2 % (c) The GRASP/AQUA Project, Glasgow University, 1992-1998
4 \section[CoreUtils]{Utility functions on @Core@ syntax}
9 Subst, TvSubstEnv, IdSubstEnv, InScopeSet,
11 substTy, substExpr, substRules, substWorker,
12 lookupIdSubst, lookupTvSubst,
14 emptySubst, mkEmptySubst, mkSubst, substInScope, isEmptySubst,
15 extendIdSubst, extendIdSubstList, extendTvSubst, extendTvSubstList,
16 extendInScope, extendInScopeIds,
20 substBndr, substBndrs, substRecBndrs,
21 cloneIdBndr, cloneIdBndrs, cloneRecIdBndrs
24 #include "HsVersions.h"
26 import CoreSyn ( Expr(..), Bind(..), Note(..), CoreExpr,
27 CoreRules(..), CoreRule(..),
28 isEmptyCoreRules, seqRules, hasUnfolding, noUnfolding
30 import CoreFVs ( exprFreeVars )
31 import CoreUtils ( exprIsTrivial )
33 import qualified Type ( substTy, substTyVarBndr )
34 import Type ( Type, tyVarsOfType, TvSubstEnv, TvSubst(..), mkTyVarTy )
37 import Var ( setVarUnique, isId )
38 import Id ( idType, setIdType, maybeModifyIdInfo, isLocalId )
39 import IdInfo ( IdInfo, specInfo, setSpecInfo,
40 unfoldingInfo, setUnfoldingInfo,
41 WorkerInfo(..), workerExists, workerInfo, setWorkerInfo, WorkerInfo
43 import Unique ( Unique )
44 import UniqSupply ( UniqSupply, uniqFromSupply, uniqsFromSupply )
45 import Var ( Var, Id, TyVar, isTyVar )
46 import Maybes ( orElse )
48 import PprCore () -- Instances
49 import Util ( mapAccumL )
54 %************************************************************************
56 \subsection{Substitutions}
58 %************************************************************************
62 = Subst InScopeSet -- Variables in in scope (both Ids and TyVars)
63 IdSubstEnv -- Substitution for Ids
64 TvSubstEnv -- Substitution for TyVars
66 -- INVARIANT 1: The (domain of the) in-scope set is a superset
67 -- of the free vars of the range of the substitution
68 -- that might possibly clash with locally-bound variables
69 -- in the thing being substituted in.
70 -- This is what lets us deal with name capture properly
71 -- It's a hard invariant to check...
72 -- There are various ways of causing it to happen:
73 -- - arrange that the in-scope set really is all the things in scope
74 -- - arrange that it's the free vars of the range of the substitution
75 -- - make it empty because all the free vars of the subst are fresh,
76 -- and hence can't possibly clash.a
78 -- INVARIANT 2: The substitution is apply-once; see notes with
81 type IdSubstEnv = IdEnv CoreExpr
83 ----------------------------
84 isEmptySubst :: Subst -> Bool
85 isEmptySubst (Subst _ id_env tv_env) = isEmptyVarEnv id_env && isEmptyVarEnv tv_env
88 emptySubst = Subst emptyInScopeSet emptyVarEnv emptyVarEnv
90 mkEmptySubst :: InScopeSet -> Subst
91 mkEmptySubst in_scope = Subst in_scope emptyVarEnv emptyVarEnv
93 mkSubst :: InScopeSet -> TvSubstEnv -> IdSubstEnv -> Subst
94 mkSubst in_scope tvs ids = Subst in_scope ids tvs
96 -- getTvSubst :: Subst -> TvSubst
97 -- getTvSubst (Subst in_scope _ tv_env) = TvSubst in_scope tv_env
99 -- getTvSubstEnv :: Subst -> TvSubstEnv
100 -- getTvSubstEnv (Subst _ _ tv_env) = tv_env
102 -- setTvSubstEnv :: Subst -> TvSubstEnv -> Subst
103 -- setTvSubstEnv (Subst in_scope ids _) tvs = Subst in_scope ids tvs
105 substInScope :: Subst -> InScopeSet
106 substInScope (Subst in_scope _ _) = in_scope
108 -- zapSubstEnv :: Subst -> Subst
109 -- zapSubstEnv (Subst in_scope _ _) = Subst in_scope emptyVarEnv emptyVarEnv
111 -- ToDo: add an ASSERT that fvs(subst-result) is already in the in-scope set
112 extendIdSubst :: Subst -> Id -> CoreExpr -> Subst
113 extendIdSubst (Subst in_scope ids tvs) v r = Subst in_scope (extendVarEnv ids v r) tvs
115 extendIdSubstList :: Subst -> [(Id, CoreExpr)] -> Subst
116 extendIdSubstList (Subst in_scope ids tvs) prs = Subst in_scope (extendVarEnvList ids prs) tvs
118 extendTvSubst :: Subst -> TyVar -> Type -> Subst
119 extendTvSubst (Subst in_scope ids tvs) v r = Subst in_scope ids (extendVarEnv tvs v r)
121 extendTvSubstList :: Subst -> [(TyVar,Type)] -> Subst
122 extendTvSubstList (Subst in_scope ids tvs) prs = Subst in_scope ids (extendVarEnvList tvs prs)
124 lookupIdSubst :: Subst -> Id -> CoreExpr
125 lookupIdSubst (Subst in_scope ids tvs) v
126 | not (isLocalId v) = Var v
128 = case lookupVarEnv ids v of {
131 case lookupInScope in_scope v of {
132 -- Watch out! Must get the Id from the in-scope set,
133 -- because its type there may differ
135 Nothing -> WARN( True, ptext SLIT("CoreSubst.lookupIdSubst") <+> ppr v )
139 lookupTvSubst :: Subst -> TyVar -> Type
140 lookupTvSubst (Subst _ ids tvs) v = lookupVarEnv tvs v `orElse` mkTyVarTy v
142 ------------------------------
143 isInScope :: Var -> Subst -> Bool
144 isInScope v (Subst in_scope _ _) = v `elemInScopeSet` in_scope
146 extendInScope :: Subst -> Var -> Subst
147 extendInScope (Subst in_scope ids tvs) v
148 = Subst (in_scope `extendInScopeSet` v)
149 (ids `delVarEnv` v) (tvs `delVarEnv` v)
151 extendInScopeIds :: Subst -> [Id] -> Subst
152 extendInScopeIds (Subst in_scope ids tvs) vs
153 = Subst (in_scope `extendInScopeSetList` vs)
154 (ids `delVarEnvList` vs) tvs
157 Pretty printing, for debugging only
160 instance Outputable Subst where
161 ppr (Subst in_scope ids tvs)
162 = ptext SLIT("<InScope =") <+> braces (fsep (map ppr (varEnvElts (getInScopeVars in_scope))))
163 $$ ptext SLIT(" IdSubst =") <+> ppr ids
164 $$ ptext SLIT(" TvSubst =") <+> ppr tvs
169 %************************************************************************
171 Substituting expressions
173 %************************************************************************
176 substExpr :: Subst -> CoreExpr -> CoreExpr
180 go (Var v) = lookupIdSubst subst v
181 go (Type ty) = Type (substTy subst ty)
182 go (Lit lit) = Lit lit
183 go (App fun arg) = App (go fun) (go arg)
184 go (Note note e) = Note (go_note note) (go e)
185 go (Lam bndr body) = Lam bndr' (substExpr subst' body)
187 (subst', bndr') = substBndr subst bndr
189 go (Let (NonRec bndr rhs) body) = Let (NonRec bndr' (go rhs)) (substExpr subst' body)
191 (subst', bndr') = substBndr subst bndr
193 go (Let (Rec pairs) body) = Let (Rec pairs') (substExpr subst' body)
195 (subst', bndrs') = substRecBndrs subst (map fst pairs)
196 pairs' = bndrs' `zip` rhss'
197 rhss' = map (substExpr subst' . snd) pairs
199 go (Case scrut bndr ty alts) = Case (go scrut) bndr' (substTy subst ty) (map (go_alt subst') alts)
201 (subst', bndr') = substBndr subst bndr
203 go_alt subst (con, bndrs, rhs) = (con, bndrs', substExpr subst' rhs)
205 (subst', bndrs') = substBndrs subst bndrs
207 go_note (Coerce ty1 ty2) = Coerce (substTy subst ty1) (substTy subst ty2)
212 %************************************************************************
216 %************************************************************************
218 Remember that substBndr and friends are used when doing expression
219 substitution only. Their only business is substitution, so they
220 preserve all IdInfo (suitably substituted). For example, we *want* to
221 preserve occ info in rules.
224 substBndr :: Subst -> Var -> (Subst, Var)
226 | isTyVar bndr = substTyVarBndr subst bndr
227 | otherwise = substIdBndr subst subst bndr
229 substBndrs :: Subst -> [Var] -> (Subst, [Var])
230 substBndrs subst bndrs = mapAccumL substBndr subst bndrs
232 substRecBndrs :: Subst -> [Id] -> (Subst, [Id])
233 -- Substitute a mutually recursive group
234 substRecBndrs subst bndrs
235 = (new_subst, new_bndrs)
236 where -- Here's the reason we need to pass rec_subst to subst_id
237 (new_subst, new_bndrs) = mapAccumL (substIdBndr new_subst) subst bndrs
242 substIdBndr :: Subst -- Substitution to use for the IdInfo
243 -> Subst -> Id -- Substitition and Id to transform
244 -> (Subst, Id) -- Transformed pair
246 substIdBndr rec_subst subst@(Subst in_scope env tvs) old_id
247 = (Subst (in_scope `extendInScopeSet` new_id) new_env tvs, new_id)
249 id1 = uniqAway in_scope old_id -- id1 is cloned if necessary
250 id2 = substIdType subst id1 -- id2 has its type zapped
252 -- new_id has the right IdInfo
253 -- The lazy-set is because we're in a loop here, with
254 -- rec_subst, when dealing with a mutually-recursive group
255 new_id = maybeModifyIdInfo (substIdInfo rec_subst) id2
257 -- Extend the substitution if the unique has changed
258 -- See the notes with substTyVarBndr for the delSubstEnv
259 new_env | new_id /= old_id = extendVarEnv env old_id (Var new_id)
260 | otherwise = delVarEnv env old_id
263 Now a variant that unconditionally allocates a new unique.
264 It also unconditionally zaps the OccInfo.
267 cloneIdBndr :: Subst -> UniqSupply -> Id -> (Subst, Id)
268 cloneIdBndr subst us old_id
269 = clone_id subst subst (old_id, uniqFromSupply us)
271 cloneIdBndrs :: Subst -> UniqSupply -> [Id] -> (Subst, [Id])
272 cloneIdBndrs subst us ids
273 = mapAccumL (clone_id subst) subst (ids `zip` uniqsFromSupply us)
275 cloneRecIdBndrs :: Subst -> UniqSupply -> [Id] -> (Subst, [Id])
276 cloneRecIdBndrs subst us ids
279 (subst', ids') = mapAccumL (clone_id subst') subst
280 (ids `zip` uniqsFromSupply us)
282 -- Just like substIdBndr, except that it always makes a new unique
283 -- It is given the unique to use
284 clone_id :: Subst -- Substitution for the IdInfo
285 -> Subst -> (Id, Unique) -- Substitition and Id to transform
286 -> (Subst, Id) -- Transformed pair
288 clone_id rec_subst subst@(Subst in_scope env tvs) (old_id, uniq)
289 = (Subst (in_scope `extendInScopeSet` new_id) new_env tvs, new_id)
291 id1 = setVarUnique old_id uniq
292 id2 = substIdType subst id1
293 new_id = maybeModifyIdInfo (substIdInfo rec_subst) id2
294 new_env = extendVarEnv env old_id (Var new_id)
298 %************************************************************************
302 %************************************************************************
304 For types we just call the corresponding function in Type, but we have
305 to repackage the substitution, from a Subst to a TvSubst
308 substTyVarBndr :: Subst -> TyVar -> (Subst, TyVar)
309 substTyVarBndr (Subst in_scope id_env tv_env) tv
310 = case Type.substTyVarBndr (TvSubst in_scope tv_env) tv of
311 (TvSubst in_scope' tv_env', tv')
312 -> (Subst in_scope' id_env tv_env', tv')
314 substTy :: Subst -> Type -> Type
315 substTy (Subst in_scope id_env tv_env) ty
316 = Type.substTy (TvSubst in_scope tv_env) ty
320 %************************************************************************
322 \section{IdInfo substitution}
324 %************************************************************************
327 substIdType :: Subst -> Id -> Id
328 substIdType subst@(Subst in_scope id_env tv_env) id
329 | isEmptyVarEnv tv_env || isEmptyVarSet (tyVarsOfType old_ty) = id
330 | otherwise = setIdType id (substTy subst old_ty)
331 -- The tyVarsOfType is cheaper than it looks
332 -- because we cache the free tyvars of the type
333 -- in a Note in the id's type itself
338 substIdInfo :: Subst -> IdInfo -> Maybe IdInfo
339 -- Always zaps the unfolding, to save substitution work
340 substIdInfo subst info
341 | nothing_to_do = Nothing
342 | otherwise = Just (info `setSpecInfo` substRules subst old_rules
343 `setWorkerInfo` substWorker subst old_wrkr
344 `setUnfoldingInfo` noUnfolding)
346 old_rules = specInfo info
347 old_wrkr = workerInfo info
348 nothing_to_do = isEmptyCoreRules old_rules &&
349 not (workerExists old_wrkr) &&
350 not (hasUnfolding (unfoldingInfo info))
354 substWorker :: Subst -> WorkerInfo -> WorkerInfo
355 -- Seq'ing on the returned WorkerInfo is enough to cause all the
356 -- substitutions to happen completely
358 substWorker subst NoWorker
360 substWorker subst (HasWorker w a)
361 = case lookupIdSubst subst w of
362 Var w1 -> HasWorker w1 a
363 other -> WARN( not (exprIsTrivial other), text "CoreSubst.substWorker:" <+> ppr w )
364 NoWorker -- Worker has got substituted away altogether
365 -- (This can happen if it's trivial,
366 -- via postInlineUnconditionally, hence warning)
369 substRules :: Subst -> CoreRules -> CoreRules
371 substRules subst rules
372 | isEmptySubst subst = rules
373 substRules subst (Rules rules rhs_fvs)
374 = seqRules new_rules `seq` new_rules
376 new_rules = Rules (map do_subst rules) (substVarSet subst rhs_fvs)
378 do_subst rule@(BuiltinRule _ _) = rule
379 do_subst (Rule name act tpl_vars lhs_args rhs)
380 = Rule name act tpl_vars'
381 (map (substExpr subst') lhs_args)
382 (substExpr subst' rhs)
384 (subst', tpl_vars') = substBndrs subst tpl_vars
387 substVarSet subst fvs
388 = foldVarSet (unionVarSet . subst_fv subst) emptyVarSet fvs
391 | isId fv = exprFreeVars (lookupIdSubst subst fv)
392 | otherwise = tyVarsOfType (lookupTvSubst subst fv)