Note [Eliminate casts in function position]

GHC/Core/SimpleOpt.hs:633 compiler

Consider the following program:

  type R :: Type -> RuntimeRep
  type family R a where { R Float = FloatRep; R Double = DoubleRep }
  type F :: forall (a :: Type) -> TYPE (R a)
  type family F a where { F Float = Float#  ; F Double = Double# }

  type N :: forall (a :: Type) -> TYPE (R a)
  newtype N a = MkN (F a)

As MkN is a newtype, its unfolding is a lambda which wraps its argument
in a cast:

  MkN :: forall (a :: Type). F a -> N a
  MkN = /\a \(x::F a). x |> co_ax
    recall that F a :: TYPE (R a)

This is a representation-polymorphic lambda, in which the binder has an unknown
representation (R a). We can't compile such a lambda on its own, but we can
compile instantiations, such as `MkN @Float` or `MkN @Double`.

Our strategy to avoid running afoul of the representation-polymorphism
invariants of Note [Representation polymorphism invariants] in GHC.Core is thus:

  1. Give the newtype a compulsory unfolding (it has no binding, as we can't
     define lambdas with representation-polymorphic value binders in source Haskell).
  2. Rely on the optimiser to beta-reduce away any representation-polymorphic
     value binders.

For example, consider the application

    MkN @Float 34.0#

After inlining MkN we'll get

   ((/\a \(x:F a). x |> co_ax) @Float) |> co 34#

where co :: (F Float -> N Float) ~ (Float# ~ N Float)

But to actually beta-reduce that lambda, we need to push the 'co'
inside the `\x` with pushCoecionIntoLambda.  Hence the extra
equation for Cast-of-Lam in finish_app.

This is regrettably delicate.

References 1

Referenced by 1