Note [Linting representation-polymorphic builtins]

GHC/Core/Lint.hs:3235 compiler

As described in Note [Representation-polymorphism checking built-ins], on
top of the two main representation-polymorphism invariants described in the
Note [Representation polymorphism invariants], we must perform additional
representation-polymorphism checks on builtin functions which don't have a
binding, for example to ensure that we don't run afoul of the
representation-polymorphism invariants when eta-expanding.

There are two situations:

  1. Builtins which have skolem type variables which must be instantiated to
     concrete types, such as the RuntimeRep type argument r to the catch# primop.

  2. Representation-polymorphic unlifted newtypes, which must always be instantiated
     at a fixed runtime representation.

For 1, consider for example 'coerce':

  coerce :: forall {r} (a :: TYPE r) (b :: TYPE r). Coercible a b => a -> b

We store in the IdDetails of the coerce Id that the first binder, r, must always
be instantiated to a concrete type. We thus check this in Core Lint: whenever we
see an application of the form

  coerce @{rep1} ...

we ensure that 'rep1' is concrete. This is done in the function "checkRepPolyBuiltinApp".
Moreover, not instantiating these type variables at all is also an error, as
we would again not be able to perform eta-expansion. (This is a bit more theoretical,
as in user programs the typechecker will insert these type applications when
instantiating, but it can still arise when constructing Core expressions).

For 2, whenever we have an unlifted newtype such as

  type RR :: Type -> RuntimeRep
  type family RR a

  type F :: forall (a :: Type) -> TYPE (RR a)
  type family F a

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

and an unsaturated occurrence

  MkN @ty -- NB: no value argument!

we check that the (instantiated) argument type has a fixed runtime representation.
This is done in the function "checkRepPolyNewtypeApp".

References 2

Referenced by 5