summaryrefslogtreecommitdiff
path: root/compiler/iface
diff options
context:
space:
mode:
authorsimonpj@microsoft.com <unknown>2009-01-02 14:28:51 +0000
committersimonpj@microsoft.com <unknown>2009-01-02 14:28:51 +0000
commit9ffadf219cbc4f8ec57264786df936a3cee88aec (patch)
tree3749e71fbf549d19e2b47ee615ef11129d0d292a /compiler/iface
parent24a5fdb5fe20290cbb9b58b2901e8d2fd651d3f3 (diff)
downloadhaskell-9ffadf219cbc4f8ec57264786df936a3cee88aec.tar.gz
Make record selectors into ordinary functions
This biggish patch addresses Trac #2670. The main effect is to make record selectors into ordinary functions, whose unfoldings appear in interface files, in contrast to their previous existence as magic "implicit Ids". This means that the usual machinery of optimisation, analysis, and inlining applies to them, which was failing before when the selector was somewhat complicated. (Which it can be when strictness annotations, unboxing annotations, and GADTs are involved.) The change involves the following points * Changes in Var.lhs to the representation of Var. Now a LocalId can have an IdDetails as well as a GlobalId. In particular, the information that an Id is a record selector is kept in the IdDetails. While compiling the current module, the record selector *must* be a LocalId, so that it participates properly in compilation (free variables etc). This led me to change the (hidden) representation of Var, so that there is now only one constructor for Id, not two. * The IdDetails is persisted into interface files, so that an importing module can see which Ids are records selectors. * In TcTyClDecls, we generate the record-selector bindings in renamed, but not typechecked form. In this way, we can get the typechecker to add all the types and so on, which is jolly helpful especially when GADTs or type families are involved. Just like derived instance declarations. This is the big new chunk of 180 lines of code (much of which is commentary). A call to the same function, mkAuxBinds, is needed in TcInstDcls for associated types. * The typechecker therefore has to pin the correct IdDetails on to the record selector, when it typechecks it. There was a neat way to do this, by adding a new sort of signature to HsBinds.Sig, namely IdSig. This contains an Id (with the correct Name, Type, and IdDetails); the type checker uses it as the binder for the final binding. This worked out rather easily. * Record selectors are no longer "implicit ids", which entails changes to IfaceSyn.ifaceDeclSubBndrs HscTypes.implicitTyThings TidyPgm.getImplicitBinds (These three functions must agree.) * MkId.mkRecordSelectorId is deleted entirely, some 300+ lines (incl comments) of very error prone code. Happy days. * A TyCon no longer contains the list of record selectors: algTcSelIds is gone The renamer is unaffected, including the way that import and export of record selectors is handled. Other small things * IfaceSyn.ifaceDeclSubBndrs had a fragile test for whether a data constructor had a wrapper. I've replaced that with an explicit flag in the interface file. More robust I hope. * I renamed isIdVar to isId, which touched a few otherwise-unrelated files.
Diffstat (limited to 'compiler/iface')
-rw-r--r--compiler/iface/BinIface.hs45
-rw-r--r--compiler/iface/BuildTyCl.lhs41
-rw-r--r--compiler/iface/IfaceSyn.lhs63
-rw-r--r--compiler/iface/LoadIface.lhs23
-rw-r--r--compiler/iface/MkIface.lhs15
-rw-r--r--compiler/iface/TcIface.lhs140
6 files changed, 197 insertions, 130 deletions
diff --git a/compiler/iface/BinIface.hs b/compiler/iface/BinIface.hs
index 9926b95d24..7a274011b7 100644
--- a/compiler/iface/BinIface.hs
+++ b/compiler/iface/BinIface.hs
@@ -579,12 +579,9 @@ instance Binary Activation where
return (ActiveAfter ab)
instance Binary StrictnessMark where
- put_ bh MarkedStrict = do
- putByte bh 0
- put_ bh MarkedUnboxed = do
- putByte bh 1
- put_ bh NotMarkedStrict = do
- putByte bh 2
+ put_ bh MarkedStrict = putByte bh 0
+ put_ bh MarkedUnboxed = putByte bh 1
+ put_ bh NotMarkedStrict = putByte bh 2
get bh = do
h <- getByte bh
case h of
@@ -593,10 +590,8 @@ instance Binary StrictnessMark where
_ -> do return NotMarkedStrict
instance Binary Boxity where
- put_ bh Boxed = do
- putByte bh 0
- put_ bh Unboxed = do
- putByte bh 1
+ put_ bh Boxed = putByte bh 0
+ put_ bh Unboxed = putByte bh 1
get bh = do
h <- getByte bh
case h of
@@ -1096,6 +1091,18 @@ instance Binary IfaceBinding where
_ -> do ac <- get bh
return (IfaceRec ac)
+instance Binary IfaceIdDetails where
+ put_ bh IfVanillaId = putByte bh 0
+ put_ bh (IfRecSelId b) = do { putByte bh 1; put_ bh b }
+ put_ bh IfDFunId = putByte bh 2
+ get bh = do
+ h <- getByte bh
+ case h of
+ 0 -> return IfVanillaId
+ 1 -> do a <- get bh
+ return (IfRecSelId a)
+ _ -> return IfDFunId
+
instance Binary IfaceIdInfo where
put_ bh NoInfo = putByte bh 0
put_ bh (HasInfo i) = do
@@ -1174,10 +1181,11 @@ instance Binary IfaceNote where
-- when de-serialising.
instance Binary IfaceDecl where
- put_ bh (IfaceId name ty idinfo) = do
+ put_ bh (IfaceId name ty details idinfo) = do
putByte bh 0
put_ bh (occNameFS name)
put_ bh ty
+ put_ bh details
put_ bh idinfo
put_ _ (IfaceForeign _ _) =
error "Binary.put_(IfaceDecl): IfaceForeign"
@@ -1210,11 +1218,12 @@ instance Binary IfaceDecl where
get bh = do
h <- getByte bh
case h of
- 0 -> do name <- get bh
- ty <- get bh
- idinfo <- get bh
+ 0 -> do name <- get bh
+ ty <- get bh
+ details <- get bh
+ idinfo <- get bh
occ <- return $! mkOccNameFS varName name
- return (IfaceId occ ty idinfo)
+ return (IfaceId occ ty details idinfo)
1 -> error "Binary.get(TyClDecl): ForeignType"
2 -> do
a1 <- get bh
@@ -1299,7 +1308,7 @@ instance Binary IfaceConDecls where
return (IfNewTyCon aa)
instance Binary IfaceConDecl where
- put_ bh (IfCon a1 a2 a3 a4 a5 a6 a7 a8 a9) = do
+ put_ bh (IfCon a1 a2 a3 a4 a5 a6 a7 a8 a9 a10) = do
put_ bh a1
put_ bh a2
put_ bh a3
@@ -1309,6 +1318,7 @@ instance Binary IfaceConDecl where
put_ bh a7
put_ bh a8
put_ bh a9
+ put_ bh a10
get bh = do a1 <- get bh
a2 <- get bh
a3 <- get bh
@@ -1318,7 +1328,8 @@ instance Binary IfaceConDecl where
a7 <- get bh
a8 <- get bh
a9 <- get bh
- return (IfCon a1 a2 a3 a4 a5 a6 a7 a8 a9)
+ a10 <- get bh
+ return (IfCon a1 a2 a3 a4 a5 a6 a7 a8 a9 a10)
instance Binary IfaceClassOp where
put_ bh (IfaceClassOp n def ty) = do
diff --git a/compiler/iface/BuildTyCl.lhs b/compiler/iface/BuildTyCl.lhs
index b8c04d3c4c..9213afd4ce 100644
--- a/compiler/iface/BuildTyCl.lhs
+++ b/compiler/iface/BuildTyCl.lhs
@@ -79,9 +79,8 @@ buildAlgTyCon tc_name tvs stupid_theta rhs is_rec want_generics gadt_syn
; tycon <- fixM (\ tycon_rec -> do
{ parent <- mkParentInfo mb_family tc_name tvs tycon_rec
; let { tycon = mkAlgTyCon tc_name kind tvs stupid_theta rhs
- fields parent is_rec want_generics gadt_syn
- ; kind = mkArrowKinds (map tyVarKind tvs) liftedTypeKind
- ; fields = mkTyConSelIds tycon rhs
+ parent is_rec want_generics gadt_syn
+ ; kind = mkArrowKinds (map tyVarKind tvs) liftedTypeKind
}
; return tycon
})
@@ -234,14 +233,6 @@ mkDataConStupidTheta tycon arg_tys univ_tvs
arg_tyvars = tyVarsOfTypes arg_tys
in_arg_tys pred = not $ isEmptyVarSet $
tyVarsOfPred pred `intersectVarSet` arg_tyvars
-
-------------------------------------------------------
-mkTyConSelIds :: TyCon -> AlgTyConRhs -> [Id]
-mkTyConSelIds tycon rhs
- = [ mkRecordSelId tycon fld
- | fld <- nub (concatMap dataConFieldLabels (visibleDataCons rhs)) ]
- -- We'll check later that fields with the same name
- -- from different constructors have the same type.
\end{code}
@@ -269,20 +260,11 @@ buildClass no_unf class_name tvs sc_theta fds ats sig_stuff tc_isrec
let { rec_tycon = classTyCon rec_clas
; op_tys = [ty | (_,_,ty) <- sig_stuff]
+ ; op_names = [op | (op,_,_) <- sig_stuff]
; op_items = [ (mkDictSelId no_unf op_name rec_clas, dm_info)
| (op_name, dm_info, _) <- sig_stuff ] }
-- Build the selector id and default method id
- ; dict_con <- buildDataCon datacon_name
- False -- Not declared infix
- (map (const NotMarkedStrict) op_tys)
- [{- No labelled fields -}]
- tvs [{- no existentials -}]
- [{- No GADT equalities -}] sc_theta
- op_tys
- (mkTyConApp rec_tycon (mkTyVarTys tvs))
- rec_tycon
-
; let n_value_preds = count (not . isEqPred) sc_theta
all_value_preds = n_value_preds == length sc_theta
-- We only make selectors for the *value* superclasses,
@@ -307,6 +289,23 @@ buildClass no_unf class_name tvs sc_theta fds ats sig_stuff tc_isrec
-- i.e. exactly one operation or superclass taken together
-- See note [Class newtypes and equality predicates]
+ -- We play a bit fast and loose by treating the superclasses
+ -- as ordinary arguments. That means that in the case of
+ -- class C a => D a
+ -- we don't get a newtype with no arguments!
+ args = sc_sel_names ++ op_names
+ arg_tys = map mkPredTy sc_theta ++ op_tys
+
+ ; dict_con <- buildDataCon datacon_name
+ False -- Not declared infix
+ (map (const NotMarkedStrict) args)
+ [{- No fields -}]
+ tvs [{- no existentials -}]
+ [{- No GADT equalities -}] [{- No theta -}]
+ arg_tys
+ (mkTyConApp rec_tycon (mkTyVarTys tvs))
+ rec_tycon
+
; rhs <- if use_newtype
then mkNewTyConRhs tycon_name rec_tycon dict_con
else return (mkDataTyConRhs [dict_con])
diff --git a/compiler/iface/IfaceSyn.lhs b/compiler/iface/IfaceSyn.lhs
index 7ef13a37e1..78b925f9e2 100644
--- a/compiler/iface/IfaceSyn.lhs
+++ b/compiler/iface/IfaceSyn.lhs
@@ -9,7 +9,7 @@ module IfaceSyn (
IfaceDecl(..), IfaceClassOp(..), IfaceConDecl(..), IfaceConDecls(..),
IfaceExpr(..), IfaceAlt, IfaceNote(..), IfaceLetBndr(..),
- IfaceBinding(..), IfaceConAlt(..), IfaceIdInfo(..),
+ IfaceBinding(..), IfaceConAlt(..), IfaceIdInfo(..), IfaceIdDetails(..),
IfaceInfoItem(..), IfaceRule(..), IfaceAnnotation(..), IfaceAnnTarget,
IfaceInst(..), IfaceFamInst(..),
@@ -56,9 +56,10 @@ infixl 3 &&&
\begin{code}
data IfaceDecl
- = IfaceId { ifName :: OccName,
- ifType :: IfaceType,
- ifIdInfo :: IfaceIdInfo }
+ = IfaceId { ifName :: OccName,
+ ifType :: IfaceType,
+ ifIdDetails :: IfaceIdDetails,
+ ifIdInfo :: IfaceIdInfo }
| IfaceData { ifName :: OccName, -- Type constructor
ifTyVars :: [IfaceTvBndr], -- Type variables
@@ -126,6 +127,7 @@ visibleIfConDecls (IfNewTyCon c) = [c]
data IfaceConDecl
= IfCon {
ifConOcc :: OccName, -- Constructor name
+ ifConWrapper :: Bool, -- True <=> has a wrapper
ifConInfix :: Bool, -- True <=> declared infix
ifConUnivTvs :: [IfaceTvBndr], -- Universal tyvars
ifConExTvs :: [IfaceTvBndr], -- Existential tyvars
@@ -174,6 +176,16 @@ data IfaceAnnotation
type IfaceAnnTarget = AnnTarget OccName
+-- We only serialise the IdDetails of top-level Ids, and even then
+-- we only need a very limited selection. Notably, none of the
+-- implicit ones are needed here, becuase they are not put it
+-- interface files
+
+data IfaceIdDetails
+ = IfVanillaId
+ | IfRecSelId Bool
+ | IfDFunId
+
data IfaceIdInfo
= NoInfo -- When writing interface file without -O
| HasInfo [IfaceInfoItem] -- Has info, and here it is
@@ -347,28 +359,22 @@ ifaceDeclSubBndrs IfaceData {ifCons = IfAbstractTyCon} = []
-- Newtype
ifaceDeclSubBndrs (IfaceData {ifName = tc_occ,
ifCons = IfNewTyCon (
- IfCon { ifConOcc = con_occ,
- ifConFields = fields
- }),
+ IfCon { ifConOcc = con_occ }),
ifFamInst = famInst})
- = -- fields (names of selectors)
- fields ++
- -- implicit coerion and (possibly) family instance coercion
+ = -- implicit coerion and (possibly) family instance coercion
(mkNewTyCoOcc tc_occ) : (famInstCo famInst tc_occ) ++
- -- data constructor and worker (newtypes don't have a wrapper)
+ -- data constructor and worker (newtypes don't have a wrapper)
[con_occ, mkDataConWorkerOcc con_occ]
ifaceDeclSubBndrs (IfaceData {ifName = tc_occ,
ifCons = IfDataTyCon cons,
ifFamInst = famInst})
- = -- fields (names of selectors)
- nub (concatMap ifConFields cons) -- Eliminate duplicate fields
- -- (possibly) family instance coercion;
- -- there is no implicit coercion for non-newtypes
- ++ famInstCo famInst tc_occ
- -- for each data constructor in order,
- -- data constructor, worker, and (possibly) wrapper
+ = -- (possibly) family instance coercion;
+ -- there is no implicit coercion for non-newtypes
+ famInstCo famInst tc_occ
+ -- for each data constructor in order,
+ -- data constructor, worker, and (possibly) wrapper
++ concatMap dc_occs cons
where
dc_occs con_decl
@@ -379,10 +385,8 @@ ifaceDeclSubBndrs (IfaceData {ifName = tc_occ,
wrap_occ = mkDataConWrapperOcc con_occ -- Id namespace
work_occ = mkDataConWorkerOcc con_occ -- Id namespace
strs = ifConStricts con_decl
- has_wrapper = any isMarkedStrict strs -- See MkId.mkDataConIds (sigh)
- || not (null . ifConEqSpec $ con_decl)
- || isJust famInst
- -- ToDo: may miss strictness in existential dicts
+ has_wrapper = ifConWrapper con_decl -- This is the reason for
+ -- having the ifConWrapper field!
ifaceDeclSubBndrs (IfaceClass {ifCtxt = sc_ctxt, ifName = cls_occ,
ifSigs = sigs, ifATs = ats })
@@ -428,8 +432,10 @@ instance Outputable IfaceDecl where
ppr = pprIfaceDecl
pprIfaceDecl :: IfaceDecl -> SDoc
-pprIfaceDecl (IfaceId {ifName = var, ifType = ty, ifIdInfo = info})
+pprIfaceDecl (IfaceId {ifName = var, ifType = ty,
+ ifIdDetails = details, ifIdInfo = info})
= sep [ ppr var <+> dcolon <+> ppr ty,
+ nest 2 (ppr details),
nest 2 (ppr info) ]
pprIfaceDecl (IfaceForeign {ifName = tycon})
@@ -495,12 +501,13 @@ pp_condecls tc (IfDataTyCon cs) = equals <+> sep (punctuate (ptext (sLit " |"))
pprIfaceConDecl :: OccName -> IfaceConDecl -> SDoc
pprIfaceConDecl tc
- (IfCon { ifConOcc = name, ifConInfix = is_infix,
+ (IfCon { ifConOcc = name, ifConInfix = is_infix, ifConWrapper = has_wrap,
ifConUnivTvs = univ_tvs, ifConExTvs = ex_tvs,
ifConEqSpec = eq_spec, ifConCtxt = ctxt, ifConArgTys = arg_tys,
ifConStricts = strs, ifConFields = fields })
= sep [main_payload,
if is_infix then ptext (sLit "Infix") else empty,
+ if has_wrap then ptext (sLit "HasWrapper") else empty,
if null strs then empty
else nest 4 (ptext (sLit "Stricts:") <+> hsep (map ppr strs)),
if null fields then empty
@@ -641,6 +648,12 @@ instance Outputable IfaceConAlt where
-- IfaceTupleAlt is handled by the case-alternative printer
------------------
+instance Outputable IfaceIdDetails where
+ ppr IfVanillaId = empty
+ ppr (IfRecSelId b) = ptext (sLit "RecSel")
+ <> if b then ptext (sLit "<naughty>") else empty
+ ppr IfDFunId = ptext (sLit "DFunId")
+
instance Outputable IfaceIdInfo where
ppr NoInfo = empty
ppr (HasInfo is) = ptext (sLit "{-") <+> fsep (map ppr is) <+> ptext (sLit "-}")
@@ -666,7 +679,7 @@ instance Outputable IfaceInfoItem where
-- fingerprinting the instance, so DFuns are not dependencies.
freeNamesIfDecl :: IfaceDecl -> NameSet
-freeNamesIfDecl (IfaceId _s t i) =
+freeNamesIfDecl (IfaceId _s t _d i) =
freeNamesIfType t &&&
freeNamesIfIdInfo i
freeNamesIfDecl IfaceForeign{} =
diff --git a/compiler/iface/LoadIface.lhs b/compiler/iface/LoadIface.lhs
index 8cd88efa5d..27f6cdda06 100644
--- a/compiler/iface/LoadIface.lhs
+++ b/compiler/iface/LoadIface.lhs
@@ -127,7 +127,7 @@ loadInterfaceForName doc name
-- | An 'IfM' function to load the home interface for a wired-in thing,
-- so that we're sure that we see its instance declarations and rules
--- See Note [Loading instances]
+-- See Note [Loading instances for wired-in things] in TcIface
loadWiredInHomeIface :: Name -> IfM lcl ()
loadWiredInHomeIface name
= ASSERT( isWiredInName name )
@@ -153,27 +153,6 @@ loadInterfaceWithException doc mod_name where_from
Succeeded iface -> return iface }
\end{code}
-Note [Loading instances]
-~~~~~~~~~~~~~~~~~~~~~~~~
-We need to make sure that we have at least *read* the interface files
-for any module with an instance decl or RULE that we might want.
-
-* If the instance decl is an orphan, we have a whole separate mechanism
- (loadOprhanModules)
-
-* If the instance decl not an orphan, then the act of looking at the
- TyCon or Class will force in the defining module for the
- TyCon/Class, and hence the instance decl
-
-* BUT, if the TyCon is a wired-in TyCon, we don't really need its interface;
- but we must make sure we read its interface in case it has instances or
- rules. That is what LoadIface.loadWiredInHomeInterface does. It's called
- from TcIface.{tcImportDecl, checkWiredInTyCon, ifCHeckWiredInThing}
-
-All of this is done by the type checker. The renamer plays no role.
-(It used to, but no longer.)
-
-
%*********************************************************
%* *
diff --git a/compiler/iface/MkIface.lhs b/compiler/iface/MkIface.lhs
index 4976e1fc8f..22c1756e00 100644
--- a/compiler/iface/MkIface.lhs
+++ b/compiler/iface/MkIface.lhs
@@ -1271,9 +1271,10 @@ tyThingToIfaceDecl :: TyThing -> IfaceDecl
-- Reason: Iface stuff uses OccNames, and the conversion here does
-- not do tidying on the way
tyThingToIfaceDecl (AnId id)
- = IfaceId { ifName = getOccName id,
- ifType = toIfaceType (idType id),
- ifIdInfo = info }
+ = IfaceId { ifName = getOccName id,
+ ifType = toIfaceType (idType id),
+ ifIdDetails = toIfaceIdDetails (idDetails id),
+ ifIdInfo = info }
where
info = case toIfaceIdInfo (idInfo id) of
[] -> NoInfo
@@ -1351,6 +1352,7 @@ tyThingToIfaceDecl (ATyCon tycon)
ifaceConDecl data_con
= IfCon { ifConOcc = getOccName (dataConName data_con),
ifConInfix = dataConIsInfix data_con,
+ ifConWrapper = isJust (dataConWrapId_maybe data_con),
ifConUnivTvs = toIfaceTvBndrs (dataConUnivTyVars data_con),
ifConExTvs = toIfaceTvBndrs (dataConExTyVars data_con),
ifConEqSpec = to_eq_spec (dataConEqSpec data_con),
@@ -1442,6 +1444,13 @@ toIfaceLetBndr id = IfLetBndr (occNameFS (getOccName id))
| otherwise = HasInfo [HsInline inline_prag]
--------------------------
+toIfaceIdDetails :: IdDetails -> IfaceIdDetails
+toIfaceIdDetails VanillaId = IfVanillaId
+toIfaceIdDetails DFunId = IfVanillaId
+toIfaceIdDetails (RecSelId { sel_naughty = n }) = IfRecSelId n
+toIfaceIdDetails other = pprTrace "toIfaceIdDetails" (ppr other)
+ IfVanillaId -- Unexpected
+
toIfaceIdInfo :: IdInfo -> [IfaceInfoItem]
toIfaceIdInfo id_info
= catMaybes [arity_hsinfo, caf_hsinfo, strict_hsinfo,
diff --git a/compiler/iface/TcIface.lhs b/compiler/iface/TcIface.lhs
index 28b03119ac..af43f979b4 100644
--- a/compiler/iface/TcIface.lhs
+++ b/compiler/iface/TcIface.lhs
@@ -19,6 +19,7 @@ import LoadIface
import IfaceEnv
import BuildTyCl
import TcRnMonad
+import TcType ( tcSplitSigmaTy )
import Type
import TypeRep
import HscTypes
@@ -108,8 +109,9 @@ tcImportDecl :: Name -> TcM TyThing
-- Entry point for *source-code* uses of importDecl
tcImportDecl name
| Just thing <- wiredInNameTyThing_maybe name
- = do { initIfaceTcRn (loadWiredInHomeIface name)
- -- See Note [Loading instances] in LoadIface
+ = do { when (needWiredInHomeIface thing)
+ (initIfaceTcRn (loadWiredInHomeIface name))
+ -- See Note [Loading instances for wired-in things]
; return thing }
| otherwise
= do { traceIf (text "tcImportDecl" <+> ppr name)
@@ -118,26 +120,6 @@ tcImportDecl name
Succeeded thing -> return thing
Failed err -> failWithTc err }
-checkWiredInTyCon :: TyCon -> TcM ()
--- Ensure that the home module of the TyCon (and hence its instances)
--- are loaded. See See Note [Loading instances] in LoadIface
--- It might not be a wired-in tycon (see the calls in TcUnify),
--- in which case this is a no-op.
-checkWiredInTyCon tc
- | not (isWiredInName tc_name)
- = return ()
- | otherwise
- = do { mod <- getModule
- ; ASSERT( isExternalName tc_name )
- unless (mod == nameModule tc_name)
- (initIfaceTcRn (loadWiredInHomeIface tc_name))
- -- Don't look for (non-existent) Float.hi when
- -- compiling Float.lhs, which mentions Float of course
- -- A bit yukky to call initIfaceTcRn here
- }
- where
- tc_name = tyConName tc
-
importDecl :: Name -> IfM lcl (MaybeErr Message TyThing)
-- Get the TyThing for this Name from an interface file
-- It's not a wired-in thing -- the caller caught that
@@ -168,6 +150,83 @@ importDecl name
%************************************************************************
%* *
+ Checks for wired-in things
+%* *
+%************************************************************************
+
+Note [Loading instances for wired-in things]
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+We need to make sure that we have at least *read* the interface files
+for any module with an instance decl or RULE that we might want.
+
+* If the instance decl is an orphan, we have a whole separate mechanism
+ (loadOprhanModules)
+
+* If the instance decl not an orphan, then the act of looking at the
+ TyCon or Class will force in the defining module for the
+ TyCon/Class, and hence the instance decl
+
+* BUT, if the TyCon is a wired-in TyCon, we don't really need its interface;
+ but we must make sure we read its interface in case it has instances or
+ rules. That is what LoadIface.loadWiredInHomeInterface does. It's called
+ from TcIface.{tcImportDecl, checkWiredInTyCon, ifCheckWiredInThing}
+
+* HOWEVER, only do this for TyCons. There are no wired-in Classes. There
+ are some wired-in Ids, but we don't want to load their interfaces. For
+ example, Control.Exception.Base.recSelError is wired in, but that module
+ is compiled late in the base library, and we don't want to force it to
+ load before it's been compiled!
+
+All of this is done by the type checker. The renamer plays no role.
+(It used to, but no longer.)
+
+
+\begin{code}
+checkWiredInTyCon :: TyCon -> TcM ()
+-- Ensure that the home module of the TyCon (and hence its instances)
+-- are loaded. See Note [Loading instances for wired-in things]
+-- It might not be a wired-in tycon (see the calls in TcUnify),
+-- in which case this is a no-op.
+checkWiredInTyCon tc
+ | not (isWiredInName tc_name)
+ = return ()
+ | otherwise
+ = do { mod <- getModule
+ ; ASSERT( isExternalName tc_name )
+ when (mod /= nameModule tc_name)
+ (initIfaceTcRn (loadWiredInHomeIface tc_name))
+ -- Don't look for (non-existent) Float.hi when
+ -- compiling Float.lhs, which mentions Float of course
+ -- A bit yukky to call initIfaceTcRn here
+ }
+ where
+ tc_name = tyConName tc
+
+ifCheckWiredInThing :: TyThing -> IfL ()
+-- Even though we are in an interface file, we want to make
+-- sure the instances of a wired-in thing are loaded (imagine f :: Double -> Double)
+-- Ditto want to ensure that RULES are loaded too
+-- See Note [Loading instances for wired-in things]
+ifCheckWiredInThing thing
+ = do { mod <- getIfModule
+ -- Check whether we are typechecking the interface for this
+ -- very module. E.g when compiling the base library in --make mode
+ -- we may typecheck GHC.Base.hi. At that point, GHC.Base is not in
+ -- the HPT, so without the test we'll demand-load it into the PIT!
+ -- C.f. the same test in checkWiredInTyCon above
+ ; let name = getName thing
+ ; ASSERT2( isExternalName name, ppr name )
+ when (needWiredInHomeIface thing && mod /= nameModule name)
+ (loadWiredInHomeIface name) }
+
+needWiredInHomeIface :: TyThing -> Bool
+-- Only for TyCons; see Note [Loading instances for wired-in things]
+needWiredInHomeIface (ATyCon {}) = True
+needWiredInHomeIface _ = False
+\end{code}
+
+%************************************************************************
+%* *
Type-checking a complete interface
%* *
%************************************************************************
@@ -355,11 +414,13 @@ tcIfaceDecl :: Bool -- True <=> discard IdInfo on IfaceId bindings
-> IfaceDecl
-> IfL TyThing
-tcIfaceDecl ignore_prags (IfaceId {ifName = occ_name, ifType = iface_type, ifIdInfo = info})
+tcIfaceDecl ignore_prags (IfaceId {ifName = occ_name, ifType = iface_type,
+ ifIdDetails = details, ifIdInfo = info})
= do { name <- lookupIfaceTop occ_name
; ty <- tcIfaceType iface_type
+ ; details <- tcIdDetails ty details
; info <- tcIdInfo ignore_prags name ty info
- ; return (AnId (mkVanillaGlobalWithInfo name ty info)) }
+ ; return (AnId (mkGlobalId details name ty info)) }
tcIfaceDecl _ (IfaceData {ifName = occ_name,
ifTyVars = tv_bndrs,
@@ -914,6 +975,17 @@ do_one (IfaceRec pairs) thing_inside
%************************************************************************
\begin{code}
+tcIdDetails :: Type -> IfaceIdDetails -> IfL IdDetails
+tcIdDetails _ IfVanillaId = return VanillaId
+tcIdDetails _ IfDFunId = return DFunId
+tcIdDetails ty (IfRecSelId naughty)
+ = return (RecSelId { sel_tycon = tc, sel_naughty = naughty })
+ where
+ (_, _, tau) = tcSplitSigmaTy ty
+ tc = tyConAppTyCon (funArgTy tau)
+ -- A bit fragile. Relies on the selector type looking like
+ -- forall abc. (stupid-context) => T a b c -> blah
+
tcIdInfo :: Bool -> Name -> Type -> IfaceIdInfo -> IfL IdInfo
tcIdInfo ignore_prags name ty info
| ignore_prags = return vanillaIdInfo
@@ -1016,7 +1088,7 @@ tcIfaceGlobal :: Name -> IfL TyThing
tcIfaceGlobal name
| Just thing <- wiredInNameTyThing_maybe name
-- Wired-in things include TyCons, DataCons, and Ids
- = do { ifCheckWiredInThing name; return thing }
+ = do { ifCheckWiredInThing thing; return thing }
| otherwise
= do { env <- getGblEnv
; case if_rec_types env of { -- Note [Tying the knot]
@@ -1059,22 +1131,6 @@ tcIfaceGlobal name
-- Because if M.hs also has M.hs-boot, M.T will *already be* in the HPT, but in its
-- emasculated form (e.g. lacking data constructors).
-ifCheckWiredInThing :: Name -> IfL ()
--- Even though we are in an interface file, we want to make
--- sure the instances of a wired-in thing are loaded (imagine f :: Double -> Double)
--- Ditto want to ensure that RULES are loaded too
--- See Note [Loading instances] in LoadIface
-ifCheckWiredInThing name
- = do { mod <- getIfModule
- -- Check whether we are typechecking the interface for this
- -- very module. E.g when compiling the base library in --make mode
- -- we may typecheck GHC.Base.hi. At that point, GHC.Base is not in
- -- the HPT, so without the test we'll demand-load it into the PIT!
- -- C.f. the same test in checkWiredInTyCon above
- ; ASSERT2( isExternalName name, ppr name )
- unless (mod == nameModule name)
- (loadWiredInHomeIface name) }
-
tcIfaceTyCon :: IfaceTyCon -> IfL TyCon
tcIfaceTyCon IfaceIntTc = tcWiredInTyCon intTyCon
tcIfaceTyCon IfaceBoolTc = tcWiredInTyCon boolTyCon
@@ -1101,7 +1157,7 @@ tcIfaceTyCon IfaceUbxTupleKindTc = return ubxTupleKindTyCon
-- sure the instances and RULES of this tycon are loaded
-- Imagine: f :: Double -> Double
tcWiredInTyCon :: TyCon -> IfL TyCon
-tcWiredInTyCon tc = do { ifCheckWiredInThing (tyConName tc)
+tcWiredInTyCon tc = do { ifCheckWiredInThing (ATyCon tc)
; return tc }
tcIfaceClass :: Name -> IfL Class