Note [Generating a correctly typed Rep instance]
tc_mkRepTy derives the RHS of the Rep(1) type family instance when deriving
Generic(1). For example, given the following data declaration:
data Foo a = MkFoo a
deriving stock Generic
tc_mkRepTy would generate the `Rec0 a` portion of this instance:
instance Generic (Foo a) where
type Rep (Foo a) = Rec0 a
...
(The full `Rep` instance is more complicated than this, but we have simplified
it for presentation purposes.)
`tc_mkRepTy` figures out the field types to use in the RHS by inspecting a
DerivInstTys, which contains the instantiated field types for each data
constructor. (See Note [Instantiating field types in stock deriving] for a
description of how this works.) As a result, `tc_mkRepTy` "just works" even
when dealing with StandaloneDeriving, such as in this example:
deriving stock instance Generic (Foo Int)
===>
instance Generic (Foo Int) where
type Rep (Foo Int) = Rec0 Int -- The `a` has been instantiated here
A wrinkle in all of this: what happens when deriving a Generic1 instance where
the last type variable appears in a type synonym that discards it? That is,
what should happen in this example (taken from #15012)?
type FakeOut a = Int
data T a = MkT (FakeOut a)
deriving Generic1
MkT is a particularly wily data constructor. Although the last type variable
`a` technically appears in `FakeOut a`, it's just a smokescreen, as `FakeOut a`
simply expands to `Int`. As a result, `MkT` doesn't really *use* the last type
variable. Therefore, T's `Rep` instance would use Rec0 to represent MkT's
field. But we must be careful not to produce code like this:
instance Generic1 T where
type Rep1 T = Rec0 (FakeOut a)
...
Oh no! Now we have `a` on the RHS, but it's completely unbound. This can cause
issues like what was observed in #15012. To avoid this, we ensure that `a` is
instantiated to Any:
instance Generic1 T where
type Rep1 T = Rec0 (FakeOut Any)
...
And now all is good.
Alternatively, we could have avoided this problem by expanding all type
synonyms on the RHSes of Rep1 instances. But we might blow up the size of
these types even further by doing this, so we choose not to do so. References 1
- Instantiating field types in stock deriving GHC.Tc.Deriv.Generate
Referenced by 1
- GHC.Tc.Deriv.Generics call site