Commit 321b420f authored by Simon Peyton Jones's avatar Simon Peyton Jones
Browse files

Tidy up of wired-in names

Two things here:

* While debugging Trac #14561 I found it hard to understand
  ghcPrimIds and magicIds in MkId.  This patch adds more
  structure and comments.

* I also discovered that ($) no longer needs to be a wiredInId
  because we now have levity polymorphism.  So I took dollarId
  out of MkId; and gave it a levity-polymorphic type in GHC.Base
parent e40db7b1
......@@ -88,59 +88,75 @@ import Data.Maybe ( maybeToList )
Note [Wired-in Ids]
~~~~~~~~~~~~~~~~~~~
A "wired-in" Id can be referred to directly in GHC (e.g. 'voidPrimId')
rather than by looking it up its name in some environment or fetching
it from an interface file.
There are several reasons why an Id might appear in the wiredInIds:
(1) The ghcPrimIds are wired in because they can't be defined in
Haskell at all, although the can be defined in Core. They have
compulsory unfoldings, so they are always inlined and they have
no definition site. Their home module is GHC.Prim, so they
also have a description in primops.txt.pp, where they are called
'pseudoops'.
* ghcPrimIds: see Note [ghcPrimIds (aka pseudoops)]
* magicIds: see Note [magicIds]
* errorIds, defined in coreSyn/MkCore.hs.
These error functions (e.g. rUNTIME_ERROR_ID) are wired in
becuase the desugarer generates code that mentions them directly
In all cases except ghcPrimIds, there is a definition site in a
library module, which may be called (e.g. in higher order situations);
but the wired-in version means that the details are never read from
that module's interface file; instead, the full definition is right
here.
Note [ghcPrimIds (aka pseudoops)]
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
The ghcPrimIds
(2) The 'error' function, eRROR_ID, is wired in because we don't yet have
a way to express in an interface file that the result type variable
is 'open'; that is can be unified with an unboxed type
* Are exported from GHC.Prim
[The interface file format now carry such information, but there's
no way yet of expressing at the definition site for these
error-reporting functions that they have an 'open'
result type. -- sof 1/99]
* Can't be defined in Haskell, and hence no Haskell binding site,
but have perfectly reasonable unfoldings in Core
(3) Other error functions (rUNTIME_ERROR_ID) are wired in (a) because
the desugarer generates code that mentions them directly, and
(b) for the same reason as eRROR_ID
* Either have a CompulsoryUnfolding (hence always inlined), or
of an EvaldUnfolding and void representation (e.g. void#)
(4) lazyId is wired in because the wired-in version overrides the
strictness of the version defined in GHC.Base
* Are (or should be) defined in primops.txt.pp as 'pseudoop'
Reason: that's how we generate documentation for them
(5) noinlineId is wired in because when we serialize to interfaces
we may insert noinline statements.
Note [magicIds]
~~~~~~~~~~~~~~~
The magicIds
In cases (2-4), the function has a definition in a library module, and
can be called; but the wired-in version means that the details are
never read from that module's interface file; instead, the full definition
is right here.
* Are expotted from GHC.Maic
* Can be defined in Haskell (and are, in ghc-prim:GHC/Magic.hs).
This definition at least generates Haddock documentation for them.
* May or may not have a CompulsoryUnfolding.
* But have some special behaviour that can't be done via an
unfolding from an interface file
-}
wiredInIds :: [Id]
wiredInIds
= [lazyId, dollarId, oneShotId, runRWId, noinlineId]
++ errorIds -- Defined in MkCore
= magicIds
++ ghcPrimIds
++ errorIds -- Defined in MkCore
magicIds :: [Id] -- See Note [magicIds]
magicIds = [lazyId, oneShotId, runRWId, noinlineId]
-- These Ids are exported from GHC.Prim
ghcPrimIds :: [Id]
ghcPrimIds :: [Id] -- See Note [ghcPrimIds (aka pseudoops)]
ghcPrimIds
= [ -- These can't be defined in Haskell, but they have
-- perfectly reasonable unfoldings in Core
realWorldPrimId,
voidPrimId,
unsafeCoerceId,
nullAddrId,
seqId,
magicDictId,
coerceId,
proxyHashId
= [ realWorldPrimId
, voidPrimId
, unsafeCoerceId
, nullAddrId
, seqId
, magicDictId
, coerceId
, proxyHashId
]
{-
......@@ -1158,37 +1174,25 @@ they can unify with both unlifted and lifted types. Hence we provide
another gun with which to shoot yourself in the foot.
-}
lazyIdName, unsafeCoerceName, nullAddrName, seqName,
unsafeCoerceName, nullAddrName, seqName,
realWorldName, voidPrimIdName, coercionTokenName,
magicDictName, coerceName, proxyName, dollarName, oneShotName,
runRWName, noinlineIdName :: Name
magicDictName, coerceName, proxyName :: Name
unsafeCoerceName = mkWiredInIdName gHC_PRIM (fsLit "unsafeCoerce#") unsafeCoerceIdKey unsafeCoerceId
nullAddrName = mkWiredInIdName gHC_PRIM (fsLit "nullAddr#") nullAddrIdKey nullAddrId
seqName = mkWiredInIdName gHC_PRIM (fsLit "seq") seqIdKey seqId
realWorldName = mkWiredInIdName gHC_PRIM (fsLit "realWorld#") realWorldPrimIdKey realWorldPrimId
voidPrimIdName = mkWiredInIdName gHC_PRIM (fsLit "void#") voidPrimIdKey voidPrimId
lazyIdName = mkWiredInIdName gHC_MAGIC (fsLit "lazy") lazyIdKey lazyId
coercionTokenName = mkWiredInIdName gHC_PRIM (fsLit "coercionToken#") coercionTokenIdKey coercionTokenId
magicDictName = mkWiredInIdName gHC_PRIM (fsLit "magicDict") magicDictKey magicDictId
coerceName = mkWiredInIdName gHC_PRIM (fsLit "coerce") coerceKey coerceId
proxyName = mkWiredInIdName gHC_PRIM (fsLit "proxy#") proxyHashKey proxyHashId
dollarName = mkWiredInIdName gHC_BASE (fsLit "$") dollarIdKey dollarId
lazyIdName, oneShotName, runRWName, noinlineIdName :: Name
lazyIdName = mkWiredInIdName gHC_MAGIC (fsLit "lazy") lazyIdKey lazyId
oneShotName = mkWiredInIdName gHC_MAGIC (fsLit "oneShot") oneShotKey oneShotId
runRWName = mkWiredInIdName gHC_MAGIC (fsLit "runRW#") runRWKey runRWId
noinlineIdName = mkWiredInIdName gHC_MAGIC (fsLit "noinline") noinlineIdKey noinlineId
dollarId :: Id -- Note [dollarId magic]
dollarId = pcMiscPrelId dollarName ty
(noCafIdInfo `setUnfoldingInfo` unf)
where
fun_ty = mkFunTy alphaTy openBetaTy
ty = mkSpecForAllTys [runtimeRep2TyVar, alphaTyVar, openBetaTyVar] $
mkFunTy fun_ty fun_ty
unf = mkInlineUnfoldingWithArity 2 rhs
[f,x] = mkTemplateLocals [fun_ty, alphaTy]
rhs = mkLams [runtimeRep2TyVar, alphaTyVar, openBetaTyVar, f, x] $
App (Var f) (Var x)
------------------------------------------------
proxyHashId :: Id
proxyHashId
......@@ -1279,7 +1283,7 @@ oneShotId = pcMiscPrelId oneShotName ty info
(mkFunTy fun_ty fun_ty)
fun_ty = mkFunTy openAlphaTy openBetaTy
[body, x] = mkTemplateLocals [fun_ty, openAlphaTy]
x' = setOneShotLambda x
x' = setOneShotLambda x -- Here is the magic bit!
rhs = mkLams [ runtimeRep1TyVar, runtimeRep2TyVar
, openAlphaTyVar, openBetaTyVar
, body, x'] $
......@@ -1336,20 +1340,6 @@ coerceId = pcMiscPrelId coerceName ty info
[(DataAlt coercibleDataCon, [eq], Cast (Var x) (mkCoVarCo eq))]
{-
Note [dollarId magic]
~~~~~~~~~~~~~~~~~~~~~
The only reason that ($) is wired in is so that its type can be
forall (a:*, b:Open). (a->b) -> a -> b
That is, the return type can be unboxed. E.g. this is OK
foo $ True where foo :: Bool -> Int#
because ($) doesn't inspect or move the result of the call to foo.
See Trac #8739.
There is a special typing rule for ($) in TcExpr, so the type of ($)
isn't looked at there, BUT Lint subsequently (and rightly) complains
if sees ($) applied to Int# (say), unless we give it a wired-in type
as we do here.
Note [Unsafe coerce magic]
~~~~~~~~~~~~~~~~~~~~~~~~~~
We define a *primitive*
......@@ -1520,11 +1510,11 @@ and Note [Left folds via right fold]) it was determined that it would be useful
if library authors could explicitly tell the compiler that a certain lambda is
called at most once. The oneShot function allows that.
'oneShot' is open kinded, i.e. the type variables can refer to unlifted
'oneShot' is levity-polymorphic, i.e. the type variables can refer to unlifted
types as well (Trac #10744); e.g.
oneShot (\x:Int# -> x +# 1#)
Like most magic functions it has a compulsary unfolding, so there is no need
Like most magic functions it has a compulsory unfolding, so there is no need
for a real definition somewhere. We have one in GHC.Magic for the convenience
of putting the documentation there.
......
......@@ -83,7 +83,6 @@ This is accomplished through a combination of mechanisms:
Note [Infinite families of known-key names]
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Infinite families of known-key things (e.g. tuples and sums) pose a tricky
problem: we can't add them to the knownKeyNames finite map which we use to
ensure that, e.g., a reference to (,) gets assigned the right unique (if this
......@@ -185,7 +184,7 @@ names with uniques. These ones are the *non* wired-in ones. The
wired in ones are defined in TysWiredIn etc.
-}
basicKnownKeyNames :: [Name]
basicKnownKeyNames :: [Name] -- See Note [Known-key names]
basicKnownKeyNames
= genericTyConNames
++ [ -- Classes. *Must* include:
......@@ -335,6 +334,7 @@ basicKnownKeyNames
breakpointAutoName, opaqueTyConName,
assertErrorName, traceName,
printName, fstName, sndName,
dollarName,
-- Integer
integerTyConName, mkIntegerName,
......@@ -1060,8 +1060,8 @@ groupWithName = varQual gHC_EXTS (fsLit "groupWith") groupWithIdKey
fromStringName, otherwiseIdName, foldrName, buildName, augmentName,
mapName, appendName, assertName,
breakpointName, breakpointCondName, breakpointAutoName,
opaqueTyConName :: Name
fromStringName = varQual dATA_STRING (fsLit "fromString") fromStringClassOpKey
opaqueTyConName, dollarName :: Name
dollarName = varQual gHC_BASE (fsLit "$") dollarIdKey
otherwiseIdName = varQual gHC_BASE (fsLit "otherwise") otherwiseIdKey
foldrName = varQual gHC_BASE (fsLit "foldr") foldrIdKey
buildName = varQual gHC_BASE (fsLit "build") buildIdKey
......@@ -1073,6 +1073,7 @@ breakpointName = varQual gHC_BASE (fsLit "breakpoint") breakpointIdKey
breakpointCondName= varQual gHC_BASE (fsLit "breakpointCond") breakpointCondIdKey
breakpointAutoName= varQual gHC_BASE (fsLit "breakpointAuto") breakpointAutoIdKey
opaqueTyConName = tcQual gHC_BASE (fsLit "Opaque") opaqueTyConKey
fromStringName = varQual dATA_STRING (fsLit "fromString") fromStringClassOpKey
breakpointJumpName :: Name
breakpointJumpName
......
......@@ -83,6 +83,7 @@ Other Prelude modules are much easier with fewer complex dependencies.
, UnboxedTuples
, ExistentialQuantification
, RankNTypes
, KindSignatures
#-}
-- -Wno-orphans is needed for things like:
-- Orphan rule: "x# -# x#" ALWAYS forall x# :: Int# -# x# x# = 0
......@@ -1287,9 +1288,13 @@ flip f x y = f y x
--
-- It is also useful in higher-order situations, such as @'map' ('$' 0) xs@,
-- or @'Data.List.zipWith' ('$') fs xs@.
--
-- Note that @($)@ is levity-polymorphic in its result type, so that
-- foo $ True where foo :: Bool -> Int#
-- is well-typed
{-# INLINE ($) #-}
($) :: (a -> b) -> a -> b
f $ x = f x
($) :: forall r a (b :: TYPE r). (a -> b) -> a -> b
f $ x = f x
-- | Strict (call-by-value) application operator. It takes a function and an
-- argument, evaluates the argument to weak head normal form (WHNF), then calls
......
......@@ -25,6 +25,10 @@
module GHC.Magic ( inline, noinline, lazy, oneShot, runRW# ) where
--------------------------------------------------
-- See Note [magicIds] in MkId.hs
--------------------------------------------------
import GHC.Prim
import GHC.CString ()
import GHC.Types (RuntimeRep, TYPE)
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment