Generic1 deriving should use more coercions
Consider
newtype Foo a = Foo (Maybe [a]) deriving (Generic1)
This produces some rather unsatisfactory Core:
-- to1 worker
Travv.$fGeneric1Foo1 :: forall a. Rep1 Foo a -> Maybe [a]
Travv.$fGeneric1Foo1
= \ (@ a_a7RL) (ds_d9dZ :: Rep1 Foo a_a7RL) ->
case ds_d9dZ `cast` <Co:103> of {
Nothing -> GHC.Maybe.Nothing @ [a_a7RL];
Just a1_a9fD -> GHC.Maybe.Just @ [a_a7RL] (a1_a9fD `cast` <Co:5>)
}
-- from1 worker
Travv.$fGeneric1Foo2 :: forall a. Foo a -> Maybe (Rec1 [] a)
Travv.$fGeneric1Foo2
= \ (@ a_a7R6) (x_a7GJ :: Foo a_a7R6) ->
case x_a7GJ `cast` <Co:2> of {
Nothing -> GHC.Maybe.Nothing @ (Rec1 [] a_a7R6);
Just a1_a9fD ->
GHC.Maybe.Just @ (Rec1 [] a_a7R6) (a1_a9fD `cast` <Co:6>)
}
Both of these functions could be implemented as safe coercions, but neither of them is! Similarly, if I define
data Bar a = Bar (Maybe [a]) deriving Generic1
I get a to1 worker that looks like
Travv.$fGeneric1Bar_$cto1 :: forall a. Rep1 Bar a -> Bar a
Travv.$fGeneric1Bar_$cto1
= \ (@ a_a7UA) (ds_d9ho :: Rep1 Bar a_a7UA) ->
Travv.Bar
@ a_a7UA
(case ds_d9ho `cast` <Co:103> of {
Nothing -> GHC.Maybe.Nothing @ [a_a7UA];
Just a1_a9iK -> GHC.Maybe.Just @ [a_a7UA] (a1_a9iK `cast` <Co:5>)
})
That case expression should really just be a cast.
I think the basic trick is probably to inspect the role of the type argument of each type in a composition, using that to work out whether to coerce that step.
Trac metadata
| Trac field | Value |
|---|---|
| Version | 8.6.2 |
| Type | Bug |
| TypeOfFailure | OtherFailure |
| Priority | normal |
| Resolution | Unresolved |
| Component | Compiler |
| Test case | |
| Differential revisions | |
| BlockedBy | |
| Related | |
| Blocking | |
| CC | RyanGlScott |
| Operating system | |
| Architecture |