Note [Eliminate casts in function position]
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
- GHC.Core.SimpleOpt call site