Open andrewthad opened 6 years ago
This is not simple to fix. The problem is that raise#
is defined in GHC.Prim
, which involves a fair amount of magic. In particular, GHC wires in extra typing information for a good number of functions defined in GHC.Prim
, which means that even though the type signature that Haddock sees for raise#
is a -> o
(as evidenced here), in reality, GHC sneaks in some extra levity polymorphism under the hood.
I don't know a simple way to work around this.
Note: this is fixed in the Hi Haddock branch:
Wow! Out of curiosity, how does Hi Haddock figure out what the correct type for raise#
is?
Wow! Out of curiosity, how does Hi Haddock figure out what the correct type for raise# is?
That's the type that GHC uses internally, no? Hi Haddock gets its types by querying GHC (instead of by looking at surface syntax in the initial source file, as today's Haddock does). Even TH can figure out the right type for raise#
:
{-# LANGUAGE TemplateHaskell #-}
import Language.Haskell.TH.Syntax
import Language.Haskell.TH.Ppr
import GHC.Prim
main = putStrLn $(qReify (mkName "raise#") >>= lift . pprint)
-- GHC.Prim.raise# :: forall (b_0 :: *) (q_1 :: GHC.Types.RuntimeRep) (a_2 :: GHC.Prim.TYPE q_1) .
-- b_0 -> a_2
I think the story for Haddock getting an incorrect type today is more interesting. Judging from https://ghc.haskell.org/trac/ghc/wiki/Commentary/PrimOps, looks like today's Haddock decides on the types of things in GHC.Prim
by getting tricked into parsing an auto-generated file. In that file, one finds nonsense like:
raise# :: b -> o
raise# = raise#
This makes me think:
genprimopcode
Also, I'm not sure how I feel levity polymorphism now showing up in the prelude:
On one hand, I like how honest these types are. But are they really what we want beginners to see?
Hi Haddock gets its types by querying GHC (instead of by looking at surface syntax in the initial source file, as today's Haddock does).
That's wonderful! I've always been slightly annoyed by the fact that Haddock didn't do this before, so this addresses one of its major shortcomings (IMO). Great work.
we should probably stop generating that file once Hi Haddock is merged (or at least update the commentary/comments indicating that the generated file is not used at all)
That would be an interesting idea. According to the comment at the top of GHC.Prim
:
{-
This is a generated file (generated by genprimopcode).
It is not code to actually be used. Its only purpose is to be
consumed by haddock.
-}
I wonder what would happen if we did remove GHC.Prim
entirely. Obviously, several libraries would break, since they (foolishly) import from GHC.Prim
directly. But assuming they all migrated to importing GHC.Exts
instead, would anything else break? I can't say with 100% that the answer to that question is "no", but I'm optimistic.
Also, I'm not sure how I feel levity polymorphism now showing up in the prelude:
Yes, now that Haddock is honest about type signatures, I suppose we have to address this problem too. GHC handles this issue with the -fprint-explicit-runtime-reps
flag (off by default), which controls whether the defaultRuntimeRepVars
function is called or not. defaultRuntimeRepVars
works over IfaceType
s, but you may find a similar trick useful for Haddock's purposes as well.
Wow, the hi haddock stuff looks really neat. I share your concerns about the levity-polymorphic type signature for $
. To my understanding, the implementers of levity polymorphism worked hard to make sure that things like :t ($)
in ghci do not show the levity polymorphic signature. I feel that haddock should probably take a similar approach.
I wonder what would happen if we did remove GHC.Prim entirely. Obviously, several libraries would break, since they (foolishly) import from GHC.Prim directly. But assuming they all migrated to importing GHC.Exts instead, would anything else break? I can't say with 100% that the answer to that question is "no", but I'm optimistic.
Doesn't GHC do something special when it sees GHC.Prim
being imported? I'm almost certain it doesn't consult the generated file (since then programs would be working off of bugs types like raise# :: b -> o
).
Yes, now that Haddock is honest about type signatures, I suppose we have to address this problem too. GHC handles this issue with the
-fprint-explicit-runtime-reps
flag (off by default), which controls whether thedefaultRuntimeRepVars
function is called or not.defaultRuntimeRepVars
works overIfaceTypes
, but you may find a similar trick useful for Haddock's purposes as well.
Perfect! I'll take a look at this. I suspect I'll end up porting this logic into the whole synifyType
pipeline.
For the sake of posterity, I'd like to amend something I said earlier:
This makes me think:
- we should probably stop generating that file once Hi Haddock is merged (or at least update the commentary/comments indicating that the generated file is not used at all)
- if someone really wants to fix this bug before Hi Haddock gets merged, it should be doable via some monkeying about in
genprimopcode
While it is true that the Hi Haddock work will mean that Haddock is no longer going to be using directly the type signatures of the things in the generated Haskell source for GHC.Prim
(it instead queries GHC directly for type signatures of things), it does not mean that this generated source is no longer used.
The generated source has been, and continues to be, a vessel for:
If we ever do want to avoid generating this Haskell source, we'd probably want to have ghcPrimIface :: ModIface
be fully formed (ie. have docstrings and whatever other Haddock stuff). That would likely involve adding more functions like primOpFixity
, allThePrimOps
, and so on - except this time for getting things like docstrings.
The original discussion of this issue is on trac issue 15181. At GHCi, we can inspect the type of
GHC.Exts.raise#
:However, the type of
raise#
given in the haddocks is missing the levity polymorphic kinds: