Skip to content

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
To upload designs, you'll need to enable LFS and have an admin enable hashed storage. More information