Note [Positional information in representation-polymorphism errors]

GHC/Tc/Types/Origin.hs:1333 compiler

Consider an invalid instantiation of the 'catch#' primop:

  catch#
    :: forall {q :: RuntimeRep} {k :: Levity} (a :: TYPE q)
              (b :: TYPE (BoxedRep k)).
       (State# RealWorld -> (# State# RealWorld, a #))
       -> (b -> State# RealWorld -> (# State# RealWorld, a #))
       -> State# RealWorld
       -> (# State# RealWorld, a #)

  boo :: forall r (a :: TYPE r). ...
  boo = catch# @a

The instantiation is invalid because we insist that the quantified RuntimeRep
type variable 'q' be instantiated to a concrete RuntimeRep, as per
Note [Representation-polymorphism checking built-ins] in GHC.Tc.Utils.Concrete.

We report this as the following error message:

  The result of the first argument of the primop ‘catch#’ does not have a fixed runtime representation.
  Its type is: (a :: TYPE r).

The positional information in this message, namely "The result of the first argument",
is produced by using the 'Position' datatype. In this case:

  pos :: Position Neg
  pos = Result (Argument Top)
  ppr pos = "result of the first argument"

Other examples:

  pos2 :: Position Neg
  pos2 = Argument (Result (Result Top))
  ppr pos2 = "3rd argument"

  pos3 :: Position Pos
  pos3 = Argument (Result (Argument (Result Top)))
  ppr pos3 = "2nd argument of the 2nd argument"

It's useful to keep track at the type-level whether we are in a positive or
negative position in the type, as for primops we can usually tolerate
representation-polymorphism in positive positions, but not in negative ones;
for example

  ($) :: forall {r} (a :: Type) (b :: TYPE r). (a -> b) -> a -> b


This positional information is (currently) used to report representation-polymorphism
errors in precisely the following two situations:

  1. Representation-polymorphic Ids with no binding, as described in
     Note [Representation-polymorphic Ids with no binding] in GHC.Tc.Utils.Concrete.

     This uses the 'FRRRepPolyId' constructor of 'FixedRuntimeRepContext'.

  2. When inserting eta-expansions for deep subsumption.
     See Wrinkle [Representation-polymorphism checking during subtyping] in
     Note [FunTy vs FunTy case in tc_sub_type_deep] in GHC.Tc.Utils.Unify.

     This uses the 'FRRDeepSubsumption' constructor of 'FixedRuntimeRepContext'.

References 3

Referenced by 2