data instance Crate Bool = CrateBool Bool
data instance Crate [a] = CrateList [a]
+-- Exercises the data-family rep-tyvar substitution: a polymorphic
+-- instance whose head mentions @Crate [a]@. After typechecking GHC
+-- represents the head as the synthetic rep TyCon @R:CrateList a@; the
+-- viewer should rewrite that back to the abstract @Crate [a]@ form
+-- with @a@ properly bound to the instance's tyvar (NOT leak the rep
+-- TyCon's internal tyvar as @OtherArg "a"@).
+class CrateBound a where
+ cbDescribe :: proxy a -> String
+
+instance CrateBound (Crate [a]) where
+ cbDescribe _ = "list crate"
+
-- A class parameterised by a /promoted-list/ kind. Demonstrates that
-- the viewer renders `'[Int, Bool]` as `[Int, Bool]`, not the
-- nested-cons `(: Int (: Bool []))` shape.
, isLitTy
, splitTyConApp_maybe
, splitVisibleFunTy_maybe
+ , substTys
+ , zipTvSubst
)
import GHC.Hs.Doc (Docs (..), HsDoc, hsDocString)
import GHC.Hs.DocString (renderHsDocString)
-- finding the matching @data instance@ row and connecting
-- it to any class instance of e.g. @NoThunks (Foo Args)@.
| Just (parent, parentArgs) <- tyConFamInst_maybe tc ->
- FamilyApp (qualName (tyConName parent))
- (map (typeArg boundTvs) parentArgs)
+ -- @parentArgs@ are the abstract data-instance LHS args
+ -- (e.g. @[ShelleyBlock <reptv1> <reptv2>]@), referencing
+ -- the *rep TyCon's* type variables — NOT the use-site
+ -- args. Without substitution those rep tyvars leak into
+ -- the rendered form as @OtherArg "<reptv1>"@ because
+ -- they're not in the caller's @boundTvs@. Build a
+ -- Subst from the rep's tyvars to the actual use-site
+ -- args and apply it before recursing.
+ let repTvs = tyConTyVars tc
+ sub = zipTvSubst repTvs args
+ instantiated = substTys sub parentArgs
+ in FamilyApp (qualName (tyConName parent))
+ (map (typeArg boundTvs) instantiated)
| otherwise ->
let visArgs = visibleArgs tc args
kids = map (typeArg boundTvs) visArgs