Note [EtaAppCo]
Suppose we're trying to optimize (co1a co1b ; co2a co2b). Ideally, we'd like to rewrite this to (co1a ; co2a) (co1b ; co2b). The problem is that the resultant coercions might not be well kinded. Here is an example (things labeled with x don't matter in this example): k1 :: Type k2 :: Type a :: k1 -> Type b :: k1 h :: k1 ~ k2 co1a :: x1 ~ (a |> (h -> <Type>) co1b :: x2 ~ (b |> h) co2a :: a ~ x3 co2b :: b ~ x4 First, convince yourself of the following: co1a co1b :: x1 x2 ~ (a |> (h -> <Type>)) (b |> h) co2a co2b :: a b ~ x3 x4 (a |> (h -> <Type>)) (b |> h) `eqType` a b That last fact is due to Note [Non-trivial definitional equality] in GHC.Core.TyCo.Rep, where we ignore coercions in types as long as two types' kinds are the same. In our case, we meet this last condition, because (a |> (h -> <Type>)) (b |> h) :: Type and a b :: Type So the input coercion (co1a co1b ; co2a co2b) is well-formed. But the suggested output coercions (co1a ; co2a) and (co1b ; co2b) are not -- the kinds don't match up. The solution here is to twiddle the kinds in the output coercions. First, we need to find coercions ak :: kind(a |> (h -> <Type>)) ~ kind(a) bk :: kind(b |> h) ~ kind(b) This can be done with mkKindCo and buildCoercion. The latter assumes two types are identical modulo casts and builds a coercion between them. Then, we build (co1a ; co2a |> sym ak) and (co1b ; co2b |> sym bk) as the output coercions. These are well-kinded. Also, note that all of this is done after accumulated any nested AppCo parameters. This step is to avoid quadratic behavior in calling coercionKind. The problem described here was first found in dependent/should_compile/dynamic-paper.
References 1
- Non-trivial definitional equality GHC.Core.TyCo.Rep
Referenced by 3
- GHC.Core.Coercion.Opt call site ×2
- GHC.Core.Coercion call site