summaryrefslogtreecommitdiff
path: root/compiler/iface
diff options
context:
space:
mode:
authorsimonpj@microsoft.com <unknown>2010-10-25 15:28:17 +0000
committersimonpj@microsoft.com <unknown>2010-10-25 15:28:17 +0000
commit9a81ddfb43b96cfeae2236c9616ca3552250b235 (patch)
treed2bad6c510c546eeaaca50557574027da95b1f37 /compiler/iface
parent2cda6f9f6c68f5cfd202e9979fefaa40df26769e (diff)
downloadhaskell-9a81ddfb43b96cfeae2236c9616ca3552250b235.tar.gz
Serialise nested unfoldings across module boundaries
As Roman reported in #4428, nested let-bindings weren't being recorded with their unfoldings. Needless to say, fixing this had more knock-on effects than I expected.
Diffstat (limited to 'compiler/iface')
-rw-r--r--compiler/iface/BinIface.hs17
-rw-r--r--compiler/iface/IfaceSyn.lhs44
-rw-r--r--compiler/iface/IfaceType.lhs29
-rw-r--r--compiler/iface/MkIface.lhs38
-rw-r--r--compiler/iface/TcIface.lhs75
5 files changed, 108 insertions, 95 deletions
diff --git a/compiler/iface/BinIface.hs b/compiler/iface/BinIface.hs
index f7a9aa297a..7c84778d0c 100644
--- a/compiler/iface/BinIface.hs
+++ b/compiler/iface/BinIface.hs
@@ -1209,15 +1209,19 @@ instance Binary IfaceUnfolding where
put_ bh b
put_ bh c
put_ bh d
- put_ bh (IfWrapper a n) = do
+ put_ bh (IfLclWrapper a n) = do
putByte bh 2
put_ bh a
put_ bh n
- put_ bh (IfDFunUnfold as) = do
+ put_ bh (IfExtWrapper a n) = do
putByte bh 3
+ put_ bh a
+ put_ bh n
+ put_ bh (IfDFunUnfold as) = do
+ putByte bh 4
put_ bh as
put_ bh (IfCompulsory e) = do
- putByte bh 4
+ putByte bh 5
put_ bh e
get bh = do
h <- getByte bh
@@ -1232,8 +1236,11 @@ instance Binary IfaceUnfolding where
return (IfInlineRule a b c d)
2 -> do a <- get bh
n <- get bh
- return (IfWrapper a n)
- 3 -> do as <- get bh
+ return (IfLclWrapper a n)
+ 3 -> do a <- get bh
+ n <- get bh
+ return (IfExtWrapper a n)
+ 4 -> do as <- get bh
return (IfDFunUnfold as)
_ -> do e <- get bh
return (IfCompulsory e)
diff --git a/compiler/iface/IfaceSyn.lhs b/compiler/iface/IfaceSyn.lhs
index 3d40b3858e..f86f4b9558 100644
--- a/compiler/iface/IfaceSyn.lhs
+++ b/compiler/iface/IfaceSyn.lhs
@@ -137,9 +137,9 @@ data IfaceConDecl
-- or 1-1 corresp with arg tys
data IfaceInst
- = IfaceInst { ifInstCls :: Name, -- See comments with
+ = IfaceInst { ifInstCls :: IfExtName, -- See comments with
ifInstTys :: [Maybe IfaceTyCon], -- the defn of Instance
- ifDFun :: Name, -- The dfun
+ ifDFun :: IfExtName, -- The dfun
ifOFlag :: OverlapFlag, -- Overlap flag
ifInstOrph :: Maybe OccName } -- See Note [Orphans]
-- There's always a separate IfaceDecl for the DFun, which gives
@@ -150,7 +150,7 @@ data IfaceInst
-- and if the head does not change it won't be used if it wasn't before
data IfaceFamInst
- = IfaceFamInst { ifFamInstFam :: Name -- Family tycon
+ = IfaceFamInst { ifFamInstFam :: IfExtName -- Family tycon
, ifFamInstTys :: [Maybe IfaceTyCon] -- Rough match types
, ifFamInstTyCon :: IfaceTyCon -- Instance decl
}
@@ -160,7 +160,7 @@ data IfaceRule
ifRuleName :: RuleName,
ifActivation :: Activation,
ifRuleBndrs :: [IfaceBndr], -- Tyvars and term vars
- ifRuleHead :: Name, -- Head of lhs
+ ifRuleHead :: IfExtName, -- Head of lhs
ifRuleArgs :: [IfaceExpr], -- Args of LHS
ifRuleRhs :: IfaceExpr,
ifRuleAuto :: Bool,
@@ -222,20 +222,21 @@ data IfaceUnfolding
Bool -- OK to inline even if context is boring
IfaceExpr
- | IfWrapper Arity Name -- NB: we need a Name (not just OccName) because the worker
- -- can simplify to a function in another module.
+ | IfExtWrapper Arity IfExtName -- NB: sometimes we need a IfExtName (not just IfLclName)
+ | IfLclWrapper Arity IfLclName -- because the worker can simplify to a function in
+ -- another module.
| IfDFunUnfold [IfaceExpr]
--------------------------------
data IfaceExpr
- = IfaceLcl FastString
- | IfaceExt Name
+ = IfaceLcl IfLclName
+ | IfaceExt IfExtName
| IfaceType IfaceType
| IfaceTuple Boxity [IfaceExpr] -- Saturated; type arguments omitted
| IfaceLam IfaceBndr IfaceExpr
| IfaceApp IfaceExpr IfaceExpr
- | IfaceCase IfaceExpr FastString IfaceType [IfaceAlt]
+ | IfaceCase IfaceExpr IfLclName IfaceType [IfaceAlt]
| IfaceLet IfaceBinding IfaceExpr
| IfaceNote IfaceNote IfaceExpr
| IfaceCast IfaceExpr IfaceCoercion
@@ -246,13 +247,13 @@ data IfaceExpr
data IfaceNote = IfaceSCC CostCentre
| IfaceCoreNote String
-type IfaceAlt = (IfaceConAlt, [FastString], IfaceExpr)
- -- Note: FastString, not IfaceBndr (and same with the case binder)
+type IfaceAlt = (IfaceConAlt, [IfLclName], IfaceExpr)
+ -- Note: IfLclName, not IfaceBndr (and same with the case binder)
-- We reconstruct the kind/type of the thing from the context
-- thus saving bulk in interface files
data IfaceConAlt = IfaceDefault
- | IfaceDataAlt Name
+ | IfaceDataAlt IfExtName
| IfaceTupleAlt Boxity
| IfaceLitAlt Literal
@@ -263,7 +264,7 @@ data IfaceBinding
-- IfaceLetBndr is like IfaceIdBndr, but has IdInfo too
-- It's used for *non-top-level* let/rec binders
-- See Note [IdInfo on nested let-bindings]
-data IfaceLetBndr = IfLetBndr FastString IfaceType IfaceIdInfo
+data IfaceLetBndr = IfLetBndr IfLclName IfaceType IfaceIdInfo
\end{code}
Note [Expose recursive functions]
@@ -280,10 +281,8 @@ that came up was a NOINLINE pragma on a let-binding inside an INLINE
function. The user (Duncan Coutts) really wanted the NOINLINE control
to cross the separate compilation boundary.
-So a IfaceLetBndr keeps a trimmed-down list of IfaceIdInfo stuff.
-Currently we only actually retain InlinePragInfo, but in principle we could
-add strictness etc.
-
+In general we retain all info that is left by CoreTidy.tidyLetBndr, since
+that is what is seen by importing module with --make
Note [Orphans]: the ifInstOrph and ifRuleOrph fields
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
@@ -640,11 +639,11 @@ pprIfaceExpr add_par (IfaceLet (IfaceRec pairs) body)
pprIfaceExpr add_par (IfaceNote note body) = add_par (ppr note <+> pprParendIfaceExpr body)
-ppr_alt :: (IfaceConAlt, [FastString], IfaceExpr) -> SDoc
+ppr_alt :: (IfaceConAlt, [IfLclName], IfaceExpr) -> SDoc
ppr_alt (con, bs, rhs) = sep [ppr_con_bs con bs,
arrow <+> pprIfaceExpr noParens rhs]
-ppr_con_bs :: IfaceConAlt -> [FastString] -> SDoc
+ppr_con_bs :: IfaceConAlt -> [IfLclName] -> SDoc
ppr_con_bs (IfaceTupleAlt tup_con) bs = tupleParens tup_con (interpp'SP bs)
ppr_con_bs con bs = ppr con <+> hsep (map ppr bs)
@@ -695,7 +694,9 @@ instance Outputable IfaceUnfolding where
ppr (IfCoreUnfold s e) = (if s then ptext (sLit "<stable>") else empty) <+> parens (ppr e)
ppr (IfInlineRule a uok bok e) = sep [ptext (sLit "InlineRule") <+> ppr (a,uok,bok),
pprParendIfaceExpr e]
- ppr (IfWrapper a wkr) = ptext (sLit "Worker:") <+> ppr wkr
+ ppr (IfLclWrapper a wkr) = ptext (sLit "Worker(lcl):") <+> ppr wkr
+ <+> parens (ptext (sLit "arity") <+> int a)
+ ppr (IfExtWrapper a wkr) = ptext (sLit "Worker(ext0:") <+> ppr wkr
<+> parens (ptext (sLit "arity") <+> int a)
ppr (IfDFunUnfold ns) = ptext (sLit "DFun:")
<+> brackets (pprWithCommas pprParendIfaceExpr ns)
@@ -819,7 +820,8 @@ freeNamesIfUnfold :: IfaceUnfolding -> NameSet
freeNamesIfUnfold (IfCoreUnfold _ e) = freeNamesIfExpr e
freeNamesIfUnfold (IfCompulsory e) = freeNamesIfExpr e
freeNamesIfUnfold (IfInlineRule _ _ _ e) = freeNamesIfExpr e
-freeNamesIfUnfold (IfWrapper _ v) = unitNameSet v
+freeNamesIfUnfold (IfExtWrapper _ v) = unitNameSet v
+freeNamesIfUnfold (IfLclWrapper {}) = emptyNameSet
freeNamesIfUnfold (IfDFunUnfold vs) = fnList freeNamesIfExpr vs
freeNamesIfExpr :: IfaceExpr -> NameSet
diff --git a/compiler/iface/IfaceType.lhs b/compiler/iface/IfaceType.lhs
index 47772d7c46..c97e16eef2 100644
--- a/compiler/iface/IfaceType.lhs
+++ b/compiler/iface/IfaceType.lhs
@@ -7,7 +7,9 @@ This module defines interface types and binders
\begin{code}
module IfaceType (
- IfaceType(..), IfaceKind, IfacePredType(..), IfaceTyCon(..),
+ IfExtName, IfLclName,
+
+ IfaceType(..), IfaceKind, IfacePredType(..), IfaceTyCon(..),
IfaceContext, IfaceBndr(..), IfaceTvBndr, IfaceIdBndr, IfaceCoercion,
ifaceTyConName,
@@ -41,19 +43,24 @@ import FastString
%************************************************************************
\begin{code}
+type IfLclName = FastString -- A local name in iface syntax
+
+type IfExtName = Name -- An External or WiredIn Name can appear in IfaceSyn
+ -- (However Internal or System Names never should)
+
data IfaceBndr -- Local (non-top-level) binders
= IfaceIdBndr {-# UNPACK #-} !IfaceIdBndr
| IfaceTvBndr {-# UNPACK #-} !IfaceTvBndr
-type IfaceIdBndr = (FastString, IfaceType)
-type IfaceTvBndr = (FastString, IfaceKind)
+type IfaceIdBndr = (IfLclName, IfaceType)
+type IfaceTvBndr = (IfLclName, IfaceKind)
-------------------------------
type IfaceKind = IfaceType
type IfaceCoercion = IfaceType
data IfaceType
- = IfaceTyVar FastString -- Type variable only, not tycon
+ = IfaceTyVar IfLclName -- Type variable only, not tycon
| IfaceAppTy IfaceType IfaceType
| IfaceForAllTy IfaceTvBndr IfaceType
| IfacePredTy IfacePredType
@@ -62,14 +69,14 @@ data IfaceType
| IfaceFunTy IfaceType IfaceType
data IfacePredType -- NewTypes are handled as ordinary TyConApps
- = IfaceClassP Name [IfaceType]
+ = IfaceClassP IfExtName [IfaceType]
| IfaceIParam (IPName OccName) IfaceType
| IfaceEqPred IfaceType IfaceType
type IfaceContext = [IfacePredType]
data IfaceTyCon -- Abbreviations for common tycons with known names
- = IfaceTc Name -- The common case
+ = IfaceTc IfExtName -- The common case
| IfaceIntTc | IfaceBoolTc | IfaceCharTc
| IfaceListTc | IfacePArrTc
| IfaceTupTc Boxity Arity
@@ -78,7 +85,7 @@ data IfaceTyCon -- Abbreviations for common tycons with known names
| IfaceLiftedTypeKindTc | IfaceOpenTypeKindTc | IfaceUnliftedTypeKindTc
| IfaceUbxTupleKindTc | IfaceArgTypeKindTc
-ifaceTyConName :: IfaceTyCon -> Name
+ifaceTyConName :: IfaceTyCon -> IfExtName
ifaceTyConName IfaceIntTc = intTyConName
ifaceTyConName IfaceBoolTc = boolTyConName
ifaceTyConName IfaceCharTc = charTyConName
@@ -173,7 +180,7 @@ instance Outputable IfaceBndr where
pprIfaceBndrs :: [IfaceBndr] -> SDoc
pprIfaceBndrs bs = sep (map ppr bs)
-pprIfaceIdBndr :: (FastString, IfaceType) -> SDoc
+pprIfaceIdBndr :: (IfLclName, IfaceType) -> SDoc
pprIfaceIdBndr (name, ty) = hsep [ppr name, dcolon, ppr ty]
pprIfaceTvBndr :: IfaceTvBndr -> SDoc
@@ -284,11 +291,11 @@ pabrackets p = ptext (sLit "[:") <> p <> ptext (sLit ":]")
\begin{code}
----------------
-toIfaceTvBndr :: TyVar -> (FastString, IfaceType)
+toIfaceTvBndr :: TyVar -> (IfLclName, IfaceType)
toIfaceTvBndr tyvar = (occNameFS (getOccName tyvar), toIfaceKind (tyVarKind tyvar))
-toIfaceIdBndr :: Id -> (FastString, IfaceType)
+toIfaceIdBndr :: Id -> (IfLclName, IfaceType)
toIfaceIdBndr id = (occNameFS (getOccName id), toIfaceType (idType id))
-toIfaceTvBndrs :: [TyVar] -> [(FastString, IfaceType)]
+toIfaceTvBndrs :: [TyVar] -> [(IfLclName, IfaceType)]
toIfaceTvBndrs tyvars = map toIfaceTvBndr tyvars
toIfaceBndr :: Var -> IfaceBndr
diff --git a/compiler/iface/MkIface.lhs b/compiler/iface/MkIface.lhs
index a8ea826c94..0d592160ca 100644
--- a/compiler/iface/MkIface.lhs
+++ b/compiler/iface/MkIface.lhs
@@ -439,7 +439,7 @@ addFingerprints hsc_env mb_old_fingerprint iface0 new_decls
| isWiredInName name = putNameLiterally bh name
-- wired-in names don't have fingerprints
| otherwise
- = ASSERT( isExternalName name )
+ = ASSERT2( isExternalName name, ppr name )
let hash | nameModule name /= this_mod = global_hash_fn name
| otherwise =
snd (lookupOccEnv local_env (getOccName name)
@@ -1322,11 +1322,7 @@ tyThingToIfaceDecl (AnId id)
= IfaceId { ifName = getOccName id,
ifType = toIfaceType (idType id),
ifIdDetails = toIfaceIdDetails (idDetails id),
- ifIdInfo = info }
- where
- info = case toIfaceIdInfo (idInfo id) of
- [] -> NoInfo
- items -> HasInfo items
+ ifIdInfo = toIfaceIdInfo (idInfo id) }
tyThingToIfaceDecl (AClass clas)
= IfaceClass { ifCtxt = toIfaceContext sc_theta,
@@ -1482,18 +1478,9 @@ famInstToIfaceFamInst (FamInst { fi_tycon = tycon,
toIfaceLetBndr :: Id -> IfaceLetBndr
toIfaceLetBndr id = IfLetBndr (occNameFS (getOccName id))
(toIfaceType (idType id))
- prag_info
- where
- -- Stripped-down version of tcIfaceIdInfo
- -- Change this if you want to export more IdInfo for
- -- non-top-level Ids. Don't forget to change
- -- CoreTidy.tidyLetBndr too!
- --
- -- See Note [IdInfo on nested let-bindings] in IfaceSyn
- id_info = idInfo id
- inline_prag = inlinePragInfo id_info
- prag_info | isDefaultInlinePragma inline_prag = NoInfo
- | otherwise = HasInfo [HsInline inline_prag]
+ (toIfaceIdInfo (idInfo id))
+ -- Put into the interface file any IdInfo that CoreTidy.tidyLetBndr
+ -- has left on the Id. See Note [IdInfo on nested let-bindings] in IfaceSyn
--------------------------
toIfaceIdDetails :: IdDetails -> IfaceIdDetails
@@ -1504,11 +1491,13 @@ toIfaceIdDetails (RecSelId { sel_naughty = n
toIfaceIdDetails other = pprTrace "toIfaceIdDetails" (ppr other)
IfVanillaId -- Unexpected
-toIfaceIdInfo :: IdInfo -> [IfaceInfoItem]
+toIfaceIdInfo :: IdInfo -> IfaceIdInfo
toIfaceIdInfo id_info
- = catMaybes [arity_hsinfo, caf_hsinfo, strict_hsinfo,
- inline_hsinfo, unfold_hsinfo]
- -- NB: strictness must be before unfolding
+ = case catMaybes [arity_hsinfo, caf_hsinfo, strict_hsinfo,
+ inline_hsinfo, unfold_hsinfo] of
+ [] -> NoInfo
+ infos -> HasInfo infos
+ -- NB: strictness must appear in the list before unfolding
-- See TcIface.tcUnfolding
where
------------ Arity --------------
@@ -1547,7 +1536,10 @@ toIfUnfolding lb (CoreUnfolding { uf_tmpl = rhs, uf_arity = arity
-> case guidance of
UnfWhen unsat_ok boring_ok -> IfInlineRule arity unsat_ok boring_ok if_rhs
_other -> IfCoreUnfold True if_rhs
- InlineWrapper w -> IfWrapper arity (idName w)
+ InlineWrapper w | isExternalName n -> IfExtWrapper arity n
+ | otherwise -> IfLclWrapper arity (getFS n)
+ where
+ n = idName w
InlineCompulsory -> IfCompulsory if_rhs
InlineRhs -> IfCoreUnfold False if_rhs
-- Yes, even if guidance is UnfNever, expose the unfolding
diff --git a/compiler/iface/TcIface.lhs b/compiler/iface/TcIface.lhs
index ba1da6028c..c39b713f9f 100644
--- a/compiler/iface/TcIface.lhs
+++ b/compiler/iface/TcIface.lhs
@@ -39,8 +39,8 @@ import TyCon
import DataCon
import TysWiredIn
import TysPrim ( anyTyConOfKind )
-import Var ( TyVar )
-import BasicTypes ( nonRuleLoopBreaker )
+import Var ( Var, TyVar )
+import BasicTypes ( Arity, nonRuleLoopBreaker )
import qualified Var
import VarEnv
import Name
@@ -1038,8 +1038,23 @@ tcUnfolding name _ _ (IfInlineRule arity unsat_ok boring_ok if_expr)
(UnfWhen unsat_ok boring_ok))
}
-tcUnfolding name ty info (IfWrapper arity wkr)
- = do { mb_wkr_id <- forkM_maybe doc (tcIfaceExtId wkr)
+tcUnfolding name dfun_ty _ (IfDFunUnfold ops)
+ = do { mb_ops1 <- forkM_maybe doc $ mapM tcIfaceExpr ops
+ ; return (case mb_ops1 of
+ Nothing -> noUnfolding
+ Just ops1 -> mkDFunUnfolding dfun_ty ops1) }
+ where
+ doc = text "Class ops for dfun" <+> ppr name
+
+tcUnfolding name ty info (IfExtWrapper arity wkr)
+ = tcIfaceWrapper name ty info arity (tcIfaceExtId wkr)
+tcUnfolding name ty info (IfLclWrapper arity wkr)
+ = tcIfaceWrapper name ty info arity (tcIfaceLclId wkr)
+
+-------------
+tcIfaceWrapper :: Name -> Type -> IdInfo -> Arity -> IfL Id -> IfL Unfolding
+tcIfaceWrapper name ty info arity get_worker
+ = do { mb_wkr_id <- forkM_maybe doc get_worker
; us <- newUniqueSupply
; return (case mb_wkr_id of
Nothing -> noUnfolding
@@ -1056,15 +1071,7 @@ tcUnfolding name ty info (IfWrapper arity wkr)
-- before unfolding
strict_sig = case strictnessInfo info of
Just sig -> sig
- Nothing -> pprPanic "Worker info but no strictness for" (ppr wkr)
-
-tcUnfolding name dfun_ty _ (IfDFunUnfold ops)
- = do { mb_ops1 <- forkM_maybe doc $ mapM tcIfaceExpr ops
- ; return (case mb_ops1 of
- Nothing -> noUnfolding
- Just ops1 -> mkDFunUnfolding dfun_ty ops1) }
- where
- doc = text "Class ops for dfun" <+> ppr name
+ Nothing -> pprPanic "Worker info but no strictness for" (ppr name)
\end{code}
For unfoldings we try to do the job lazily, so that we never type check
@@ -1078,22 +1085,28 @@ tcPragExpr name expr
-- Check for type consistency in the unfolding
ifDOptM Opt_DoCoreLinting $ do
- in_scope <- get_in_scope_ids
+ in_scope <- get_in_scope
case lintUnfolding noSrcLoc in_scope core_expr' of
Nothing -> return ()
- Just fail_msg -> pprPanic "Iface Lint failure" (hang doc 2 fail_msg)
-
+ Just fail_msg -> do { mod <- getIfModule
+ ; pprPanic "Iface Lint failure"
+ (vcat [ ptext (sLit "In interface for") <+> ppr mod
+ , hang doc 2 fail_msg ]) }
return core_expr'
where
doc = text "Unfolding of" <+> ppr name
- get_in_scope_ids -- Urgh; but just for linting
- = setLclEnv () $
- do { env <- getGblEnv
- ; case if_rec_types env of {
- Nothing -> return [] ;
- Just (_, get_env) -> do
- { type_env <- get_env
- ; return (typeEnvIds type_env) }}}
+
+ get_in_scope :: IfL [Var] -- Totally disgusting; but just for linting
+ get_in_scope
+ = do { (gbl_env, lcl_env) <- getEnvs
+ ; setLclEnv () $ do
+ { case if_rec_types gbl_env of {
+ Nothing -> return [] ;
+ Just (_, get_env) -> do
+ { type_env <- get_env
+ ; return (varEnvElts (if_tv_env lcl_env) ++
+ varEnvElts (if_id_env lcl_env) ++
+ typeEnvIds type_env) }}}}
\end{code}
@@ -1229,17 +1242,9 @@ tcIfaceLetBndr :: IfaceLetBndr -> IfL Id
tcIfaceLetBndr (IfLetBndr fs ty info)
= do { name <- newIfaceName (mkVarOccFS fs)
; ty' <- tcIfaceType ty
- ; case info of
- NoInfo -> return (mkLocalId name ty')
- HasInfo i -> return (mkLocalIdWithInfo name ty' (tc_info i)) }
- where
- -- Similar to tcIdInfo, but much simpler
- tc_info [] = vanillaIdInfo
- tc_info (HsInline p : i) = tc_info i `setInlinePragInfo` p
- tc_info (HsArity a : i) = tc_info i `setArityInfo` a
- tc_info (HsStrictness s : i) = tc_info i `setStrictnessInfo` Just s
- tc_info (other : i) = pprTrace "tcIfaceLetBndr: discarding unexpected IdInfo"
- (ppr other) (tc_info i)
+ ; id_info <- tcIdInfo False {- Don't ignore prags; we are inside one! -}
+ name ty' info
+ ; return (mkLocalIdWithInfo name ty' id_info) }
-----------------------
newExtCoreBndr :: IfaceLetBndr -> IfL Id