Opened 16 months ago

Closed 16 months ago

Last modified 16 months ago

#15181 closed bug (duplicate)

Levity Polymorphic type signatures in GHC.Prim

Reported by: andrewthad Owned by:
Priority: normal Milestone: 8.6.1
Component: Compiler Version: 8.2.2
Keywords: LevityPolymorphism Cc:
Operating System: Unknown/Multiple Architecture: Unknown/Multiple
Type of failure: None/Unknown Test Case:
Blocked By: Blocking:
Related Tickets: #11786 Differential Rev(s):
Wiki Page:


Some of the type signatures in the haddocks for GHC.Prim are misleading. Here are a few:

unsafeCoerce# :: a -> b
mkWeak# :: o -> b -> (State# RealWorld -> (#State# RealWorld, c#)) -> State# RealWorld -> (#State# RealWorld, Weak# b#)
raise# :: b -> o

The type signatures for these lead one to believe that all of the arguments must be lifted types, but this is not actually the case. For example, raise# is levity polymorphic in its returned value and should actually have the type:

raise# :: forall (r :: RuntimeRep) (o :: TYPE r). b -> o

It's not just the haddocks that show an inaccurate type. Even in GHCi, we get this:

>>> :set -XMagicHash
>>> :set -fprint-explicit-kinds
>>> :set -fprint-explicit-runtime-reps
>>> import GHC.Exts
>>> :t raise#
raise# :: b -> a

Similarly, unsafeCoerce# is levity polymorphic in both types. Unfortunately, mkWeak# is more difficult to assign a correct type to. It should be possible for it to be broken into two separate functions (which each do the exact same thing), one of which operates on values of type LiftedRep and other on UnliftedRep. But this would be a breaking change, and it may not be worth the breakage it would introduce.

At the very least, I feel like fixing raise# is worthwhile, since it wouldn't break anything.

Change History (7)

comment:1 Changed 16 months ago by andrewthad

Keywords: LevityPolymorphism added

comment:2 Changed 16 months ago by RyanGlScott

Resolution: duplicate
Status: newclosed

Indeed. Note that the correct type signatures are actually displayed with :info:

λ> :info raise#
raise# ::
  forall b (q :: GHC.Types.RuntimeRep) (a :: TYPE q). b -> a
        -- Defined in ‘GHC.Prim’
λ> :info unsafeCoerce#
unsafeCoerce# ::
  forall (k0 :: GHC.Types.RuntimeRep) (k1 :: GHC.Types.RuntimeRep) (a :: TYPE
                                                                           k0) (b :: TYPE k1).
  a -> b
        -- Defined in ‘GHC.Prim’
λ> :info mkWeak#
mkWeak# ::
  forall (q :: GHC.Types.RuntimeRep) (a :: TYPE q) b c.
  -> b
  -> (State# RealWorld -> (# State# RealWorld, c #))
  -> State# RealWorld
  -> (# State# RealWorld, Weak# b #)
        -- Defined in ‘GHC.Prim’

However, :type does not show the same thing with -fprint-explicit-runtime-reps enabled. In short, this is a pretty-printing issue with :type, the subject of #11786. I'll close this ticket in favor of that one.

comment:3 Changed 16 months ago by andrewthad

The haddocks are also inaccurate for these functions, which #11786 does not address.

comment:4 Changed 16 months ago by RyanGlScott

True, but that's a Haddock problem, not a GHC one. I'd encourage opening an instance at

comment:5 Changed 16 months ago by andrewthad

I'll do that. Do you happen to you where in the GHC source the real type signatures of these are found? In primops.txt,, which is where I had always assumed the type signatures came from, the types in the signature for raise# do not mention their true kinds.

comment:7 Changed 16 months ago by RyanGlScott

I'm not intimately familiar with the specifics, but I do know that GHC.Prim (and other code which adds magical properties to functions defined therein) is generated through the genprimopcode utility. genprimopcode has a convention that any type variable named o is levity polymorphic, so that's why a -> o gets a wired-in levity polymorphic type.

Note: See TracTickets for help on using tickets.