-
-%************************************************************************
-%* *
-\section{Substitution}
-%* *
-%************************************************************************
-
-This expression substituter deals correctly with name capture, much
-like Type.substTy.
-
-BUT NOTE that substExpr silently discards the
- unfolding, and
- spec env
-IdInfo attached to any binders in the expression. It's quite
-tricky to do them 'right' in the case of mutually recursive bindings,
-and so far has proved unnecessary.
-
-\begin{code}
-substExpr :: TyVarSubst -> IdSubst -- Substitution
- -> IdOrTyVarSet -- Superset of in-scope
- -> CoreExpr
- -> CoreExpr
-
-substExpr te ve in_scope expr = subst_expr (te, ve, in_scope) expr
-
-subst_expr env@(te, ve, in_scope) expr
- = go expr
- where
- go (Var v) = case lookupVarEnv ve v of
- Just (Done e')
- -> e'
-
- Just (SubstMe e' te' ve')
- -> subst_expr (te', ve', in_scope) e'
-
- Nothing -> case lookupVarSet in_scope v of
- Just v' -> Var v'
- Nothing -> Var v
- -- NB: we look up in the in_scope set because the variable
- -- there may have more info. In particular, when substExpr
- -- is called from the simplifier, the type inside the *occurrences*
- -- of a variable may not be right; we should replace it with the
- -- binder, from the in_scope set.
-
- go (Type ty) = Type (go_ty ty)
- go (Con con args) = Con con (map go args)
- go (App fun arg) = App (go fun) (go arg)
- go (Note note e) = Note (go_note note) (go e)
-
- go (Lam bndr body) = Lam bndr' (subst_expr env' body)
- where
- (env', bndr') = go_bndr env bndr
-
- go (Let (NonRec bndr rhs) body) = Let (NonRec bndr' (go rhs)) (subst_expr env' body)
- where
- (env', bndr') = go_bndr env bndr
-
- go (Let (Rec pairs) body) = Let (Rec pairs') (subst_expr env' body)
- where
- (ve', in_scope', _, bndrs')
- = substIds clone_fn te ve in_scope undefined (map fst pairs)
- env' = (te, ve', in_scope')
- pairs' = bndrs' `zip` rhss'
- rhss' = map (subst_expr env' . snd) pairs
-
- go (Case scrut bndr alts) = Case (go scrut) bndr' (map (go_alt env') alts)
- where
- (env', bndr') = go_bndr env bndr
-
- go_alt env (con, bndrs, rhs) = (con, bndrs', subst_expr env' rhs)
- where
- (env', bndrs') = mapAccumL go_bndr env bndrs
-
- go_note (Coerce ty1 ty2) = Coerce (go_ty ty1) (go_ty ty2)
- go_note note = note
-
- go_ty ty = fullSubstTy te in_scope ty
-
- go_bndr (te, ve, in_scope) bndr
- | isTyVar bndr
- = case substTyVar te in_scope bndr of
- (te', in_scope', bndr') -> ((te', ve, in_scope'), bndr')
-
- | otherwise
- = case substId clone_fn te ve in_scope undefined bndr of
- (ve', in_scope', _, bndr') -> ((te, ve', in_scope'), bndr')
-
-
- clone_fn in_scope _ bndr
- | bndr `elemVarSet` in_scope = Just (uniqAway in_scope bndr, undefined)
- | otherwise = Nothing
-
-\end{code}
-
-Substituting in binders is a rather tricky part of the whole compiler.
-
-\begin{code}
-substIds :: (IdOrTyVarSet -> us -> Id -> Maybe (us, Id)) -- Cloner
- -> TyVarSubst -> IdSubst -> IdOrTyVarSet -- Usual stuff
- -> us -- Unique supply
- -> [Id]
- -> (IdSubst, IdOrTyVarSet, -- New id_subst, in_scope
- us, -- New unique supply
- [Id])
-
-substIds clone_fn ty_subst id_subst in_scope us []
- = (id_subst, in_scope, us, [])
-
-substIds clone_fn ty_subst id_subst in_scope us (id:ids)
- = case (substId clone_fn ty_subst id_subst in_scope us id) of {
- (id_subst', in_scope', us', id') ->
-
- case (substIds clone_fn ty_subst id_subst' in_scope' us' ids) of {
- (id_subst'', in_scope'', us'', ids') ->
-
- (id_subst'', in_scope'', us'', id':ids')
- }}
-
-
-substId :: (IdOrTyVarSet -> us -> Id -> Maybe (us, Id)) -- Cloner
- -> TyVarSubst -> IdSubst -> IdOrTyVarSet -- Usual stuff
- -> us -- Unique supply
- -> Id
- -> (IdSubst, IdOrTyVarSet, -- New id_subst, in_scope
- us, -- New unique supply
- Id)
-
--- Returns an Id with empty unfolding and spec-env.
--- It's up to the caller to sort these out.
-
-substId clone_fn
- ty_subst id_subst in_scope
- us id
- | old_id_will_do
- -- No need to clone, but we *must* zap any current substitution
- -- for the variable. For example:
- -- (\x.e) with id_subst = [x |-> e']
- -- Here we must simply zap the substitution for x
- = (delVarEnv id_subst id, extendVarSet in_scope id, us, id)
-
- | otherwise
- = (extendVarEnv id_subst id (Done (Var new_id)),
- extendVarSet in_scope new_id,
- new_us,
- new_id)
- where
- id_ty = idType id
- old_id_will_do = old1 && old2 && old3 && {-old4 && -}not cloned
-
- -- id1 has its type zapped
- (id1,old1) | isEmptyVarEnv ty_subst
- || isEmptyVarSet (tyVarsOfType id_ty) = (id, True)
- | otherwise = (setIdType id ty', False)
-
- ty' = fullSubstTy ty_subst in_scope id_ty
-
- -- id2 has its SpecEnv zapped
- -- It's filled in later by Simplify.simplPrags
- (id2,old2) | isEmptySpecEnv spec_env = (id1, True)
- | otherwise = (setIdSpecialisation id1 emptySpecEnv, False)
- spec_env = getIdSpecialisation id
-
- -- id3 has its Unfolding zapped
- -- This is very important; occasionally a let-bound binder is used
- -- as a binder in some lambda, in which case its unfolding is utterly
- -- bogus. Also the unfolding uses old binders so if we left it we'd
- -- have to substitute it. Much better simply to give the Id a new
- -- unfolding each time, which is what the simplifier does.
- (id3,old3) | hasUnfolding (getIdUnfolding id) = (id2 `setIdUnfolding` noUnfolding, False)
- | otherwise = (id2, True)
-
- -- new_id is cloned if necessary
- (new_us, new_id, cloned) = case clone_fn in_scope us id3 of
- Nothing -> (us, id3, False)
- Just (us', id') -> (us', id', True)
-
- -- new_id_bndr has its Inline info neutered. We must forget about whether it
- -- was marked safe-to-inline, because that isn't necessarily true in
- -- the simplified expression. We do this for the *binder* which will
- -- be used at the binding site, but we *dont* do it for new_id, which
- -- is put into the in_scope env. Why not? Because the in_scope env
- -- carries down the occurrence information to usage sites!
- --
- -- Net result: post-simplification, occurrences may have over-optimistic
- -- occurrence info, but binders won't.
-{- (new_id_bndr, old4)
- = case getInlinePragma id of
- ICanSafelyBeINLINEd _ _ -> (setInlinePragma new_id NoInlinePragInfo, False)
- other -> (new_id, True)
--}
-\end{code}
-
-
-
-
-