X-Git-Url: http://git.megacz.com/?a=blobdiff_plain;f=ghc%2Fcompiler%2FcoreSyn%2FSubst.lhs;h=dee369ceef959bd08e37a69d1ba2883c33cf8a02;hb=d32c5227315009f38355fe3233f0f4e5b1f61dc6;hp=186695684c38da26ecaae6f1260537b46e50812b;hpb=bca9dd54c2b39638cb4638aaccf6015a104a1df5;p=ghc-hetmet.git diff --git a/ghc/compiler/coreSyn/Subst.lhs b/ghc/compiler/coreSyn/Subst.lhs index 1866956..dee369c 100644 --- a/ghc/compiler/coreSyn/Subst.lhs +++ b/ghc/compiler/coreSyn/Subst.lhs @@ -23,15 +23,15 @@ module Subst ( bindSubst, unBindSubst, bindSubstList, unBindSubstList, -- Binders - substBndr, substBndrs, substTyVar, substId, substIds, - substAndCloneId, substAndCloneIds, + simplBndr, simplBndrs, simplLetId, simplLamBndr, simplIdInfo, + substAndCloneId, substAndCloneIds, substAndCloneRecIds, -- Type stuff mkTyVarSubst, mkTopTyVarSubst, - substTy, substClasses, substTheta, + substTyWith, substTy, substTheta, deShadowTy, -- Expression stuff - substExpr, substIdInfo + substExpr, substRules ) where #include "HsVersions.h" @@ -39,30 +39,37 @@ module Subst ( import CmdLineOpts ( opt_PprStyle_Debug ) import CoreSyn ( Expr(..), Bind(..), Note(..), CoreExpr, CoreRules(..), CoreRule(..), - isEmptyCoreRules, seqRules + isEmptyCoreRules, seqRules, hasUnfolding, noUnfolding, hasSomeUnfolding, + Unfolding(..) ) -import CoreFVs ( exprFreeVars, mustHaveLocalBinding ) +import CoreFVs ( exprFreeVars ) +import CoreUtils ( exprIsTrivial ) import TypeRep ( Type(..), TyNote(..) ) -- friend -import Type ( ThetaType, PredType(..), ClassContext, - tyVarsOfType, tyVarsOfTypes, mkAppTy, mkUTy, isUTy +import Type ( ThetaType, PredType(..), + tyVarsOfType, tyVarsOfTypes, mkAppTy, ) import VarSet import VarEnv -import Var ( setVarUnique, isId ) -import Id ( idType, setIdType, idOccInfo, zapFragileIdInfo, maybeModifyIdInfo ) -import IdInfo ( IdInfo, isFragileOcc, +import Var ( setVarUnique, isId, mustHaveLocalBinding ) +import Id ( idType, idInfo, setIdInfo, setIdType, + idUnfolding, setIdUnfolding, + idOccInfo, maybeModifyIdInfo ) +import IdInfo ( IdInfo, vanillaIdInfo, + occInfo, isFragileOcc, setOccInfo, specInfo, setSpecInfo, - WorkerInfo(..), workerExists, workerInfo, setWorkerInfo, WorkerInfo, - lbvarInfo, LBVarInfo(..), setLBVarInfo + setArityInfo, unknownArity, arityInfo, + unfoldingInfo, setUnfoldingInfo, + WorkerInfo(..), workerExists, workerInfo, setWorkerInfo, WorkerInfo ) -import Unique ( Uniquable(..), deriveUnique ) +import BasicTypes ( OccInfo(..) ) +import Unique ( Unique, Uniquable(..), deriveUnique ) import UniqSet ( elemUniqSet_Directly ) -import UniqSupply ( UniqSupply, uniqFromSupply, splitUniqSupply ) +import UniqSupply ( UniqSupply, uniqFromSupply, uniqsFromSupply ) import Var ( Var, Id, TyVar, isTyVar ) import Outputable import PprCore () -- Instances import UniqFM ( ufmToList ) -- Yuk (add a new op to VarEnv) -import Util ( mapAccumL, foldl2, seqList, ($!) ) +import Util ( mapAccumL, foldl2, seqList ) import FastTypes \end{code} @@ -124,7 +131,7 @@ lookupInScope (InScope in_scope n) v uniqAway :: InScopeSet -> Var -> Var -- (uniqAway in_scope v) finds a unique that is not used in the -- in-scope set, and gives that to v. It starts with v's current unique, of course, --- in the hope that it won't have to change it, nad thereafter uses a combination +-- in the hope that it won't have to change it, and thereafter uses a combination -- of that and the hash-code found in the in-scope set uniqAway (InScope set n) var | not (var `elemVarSet` set) = var -- Nothing to do @@ -189,9 +196,7 @@ type IdSubst = Subst The general plan about the substitution and in-scope set for Ids is as follows * substId always adds new_id to the in-scope set. - new_id has a correctly-substituted type, but all its fragile IdInfo has been zapped. - That is added back in later. So new_id is the minimal thing it's - correct to substitute. + new_id has a correctly-substituted type, occ info * substId adds a binding (DoneId new_id occ) to the substitution if EITHER the Id's unique has changed @@ -244,13 +249,12 @@ substInScope (Subst in_scope _) = in_scope zapSubstEnv :: Subst -> Subst zapSubstEnv (Subst in_scope env) = Subst in_scope emptySubstEnv +-- ToDo: add an ASSERT that fvs(subst-result) is already in the in-scope set extendSubst :: Subst -> Var -> SubstResult -> Subst -extendSubst (Subst in_scope env) v r = UASSERT( case r of { DoneTy ty -> not (isUTy ty) ; _ -> True } ) - Subst in_scope (extendSubstEnv env v r) +extendSubst (Subst in_scope env) v r = Subst in_scope (extendSubstEnv env v r) extendSubstList :: Subst -> [Var] -> [SubstResult] -> Subst -extendSubstList (Subst in_scope env) v r = UASSERT( all (\ r1 -> case r1 of { DoneTy ty -> not (isUTy ty) ; _ -> True }) r ) - Subst in_scope (extendSubstEnvList env v r) +extendSubstList (Subst in_scope env) v r = Subst in_scope (extendSubstEnvList env v r) lookupSubst :: Subst -> Var -> Maybe SubstResult lookupSubst (Subst _ env) v = lookupSubstEnv env v @@ -370,30 +374,52 @@ type TyVarSubst = Subst -- TyVarSubst are expected to have range elements -- the types given; but it's just a thunk so with a bit of luck -- it'll never be evaluated mkTyVarSubst :: [TyVar] -> [Type] -> Subst -mkTyVarSubst tyvars tys = Subst (mkInScopeSet (tyVarsOfTypes tys)) (zip_ty_env tyvars tys emptySubstEnv) +mkTyVarSubst tyvars tys = Subst (mkInScopeSet (tyVarsOfTypes tys)) + (zipTyEnv tyvars tys) -- mkTopTyVarSubst is called when doing top-level substitutions. -- Here we expect that the free vars of the range of the -- substitution will be empty. mkTopTyVarSubst :: [TyVar] -> [Type] -> Subst -mkTopTyVarSubst tyvars tys = Subst emptyInScopeSet (zip_ty_env tyvars tys emptySubstEnv) +mkTopTyVarSubst tyvars tys = Subst emptyInScopeSet (zipTyEnv tyvars tys) +zipTyEnv tyvars tys +#ifdef DEBUG + | length tyvars /= length tys + = pprTrace "mkTopTyVarSubst" (ppr tyvars $$ ppr tys) emptySubstEnv + | otherwise +#endif + = zip_ty_env tyvars tys emptySubstEnv + +-- Later substitutions in the list over-ride earlier ones zip_ty_env [] [] env = env -zip_ty_env (tv:tvs) (ty:tys) env = UASSERT( not (isUTy ty) ) - zip_ty_env tvs tys (extendSubstEnv env tv (DoneTy ty)) +zip_ty_env (tv:tvs) (ty:tys) env = zip_ty_env tvs tys (extendSubstEnv env tv (DoneTy ty)) + -- There used to be a special case for when + -- ty == TyVarTy tv + -- (a not-uncommon case) in which case the substitution was dropped. + -- But the type-tidier changes the print-name of a type variable without + -- changing the unique, and that led to a bug. Why? Pre-tidying, we had + -- a type {Foo t}, where Foo is a one-method class. So Foo is really a newtype. + -- And it happened that t was the type variable of the class. Post-tiding, + -- it got turned into {Foo t2}. The ext-core printer expanded this using + -- sourceTypeRep, but that said "Oh, t == t2" because they have the same unique, + -- and so generated a rep type mentioning t not t2. + -- + -- Simplest fix is to nuke the "optimisation" \end{code} substTy works with general Substs, so that it can be called from substExpr too. \begin{code} +substTyWith :: [TyVar] -> [Type] -> Type -> Type +substTyWith tvs tys = substTy (mkTyVarSubst tvs tys) + substTy :: Subst -> Type -> Type substTy subst ty | isEmptySubst subst = ty | otherwise = subst_ty subst ty -substClasses :: TyVarSubst -> ClassContext -> ClassContext -substClasses subst theta - | isEmptySubst subst = theta - | otherwise = [(clas, map (subst_ty subst) tys) | (clas, tys) <- theta] +deShadowTy :: Type -> Type -- Remove any shadowing from the type +deShadowTy ty = subst_ty emptySubst ty substTheta :: TyVarSubst -> ThetaType -> ThetaType substTheta subst theta @@ -401,8 +427,8 @@ substTheta subst theta | otherwise = map (substPred subst) theta substPred :: TyVarSubst -> PredType -> PredType -substPred subst (Class clas tys) = Class clas (map (subst_ty subst) tys) -substPred subst (IParam n ty) = IParam n (subst_ty subst ty) +substPred subst (IParam n ty) = IParam n (subst_ty subst ty) +substPred subst (ClassP clas tys) = ClassP clas (map (subst_ty subst) tys) subst_ty subst ty = go ty @@ -410,6 +436,9 @@ subst_ty subst ty go (TyConApp tc tys) = let args = map go tys in args `seqList` TyConApp tc args + go (NewTcApp tc tys) = let args = map go tys + in args `seqList` NewTcApp tc args + go (PredTy p) = PredTy $! (substPred subst p) go (NoteTy (SynNote ty1) ty2) = NoteTy (SynNote $! (go ty1)) $! (go ty2) @@ -423,8 +452,6 @@ subst_ty subst ty go (ForAllTy tv ty) = case substTyVar subst tv of (subst', tv') -> ForAllTy tv' $! (subst_ty subst' ty) - - go (UsageTy u ty) = mkUTy (go u) $! (go ty) \end{code} Here is where we invent a new binder if necessary. @@ -508,7 +535,7 @@ substExpr subst expr go (Let (Rec pairs) body) = Let (Rec pairs') (substExpr subst' body) where - (subst', bndrs') = substBndrs subst (map fst pairs) + (subst', bndrs') = substRecBndrs subst (map fst pairs) pairs' = bndrs' `zip` rhss' rhss' = map (substExpr subst' . snd) pairs @@ -527,87 +554,175 @@ substExpr subst expr \end{code} -Substituting in binders is a rather tricky part of the whole compiler. -When we hit a binder we may need to - (a) apply the the type envt (if non-empty) to its type - (c) give it a new unique to avoid name clashes +%************************************************************************ +%* * +\section{Substituting an Id binder} +%* * +%************************************************************************ \begin{code} +-- simplBndr and simplLetId are used by the simplifier + +simplBndr :: Subst -> Var -> (Subst, Var) +-- Used for lambda and case-bound variables +-- Clone Id if necessary, substitute type +-- Return with IdInfo already substituted, but (fragile) occurrence info zapped +-- The substitution is extended only if the variable is cloned, because +-- we *don't* need to use it to track occurrence info. +simplBndr subst bndr + | isTyVar bndr = substTyVar subst bndr + | otherwise = subst_id False subst subst bndr + +simplBndrs :: Subst -> [Var] -> (Subst, [Var]) +simplBndrs subst bndrs = mapAccumL simplBndr subst bndrs + +simplLamBndr :: Subst -> Var -> (Subst, Var) +-- Used for lambda binders. These sometimes have unfoldings added by +-- the worker/wrapper pass that must be preserved, becuase they can't +-- be reconstructed from context. For example: +-- f x = case x of (a,b) -> fw a b x +-- fw a b x{=(a,b)} = ... +-- The "{=(a,b)}" is an unfolding we can't reconstruct otherwise. +simplLamBndr subst bndr + | not (isId bndr && hasSomeUnfolding old_unf) + = simplBndr subst bndr -- Normal case + | otherwise + = (subst', bndr' `setIdUnfolding` substUnfolding subst old_unf) + where + old_unf = idUnfolding bndr + (subst', bndr') = subst_id False subst subst bndr + + +simplLetId :: Subst -> Id -> (Subst, Id) +-- Clone Id if necessary +-- Substitute its type +-- Return an Id with completely zapped IdInfo +-- [A subsequent substIdInfo will restore its IdInfo] +-- Augment the subtitution +-- if the unique changed, *or* +-- if there's interesting occurrence info + +simplLetId subst@(Subst in_scope env) old_id + = (Subst (in_scope `extendInScopeSet` new_id) new_env, new_id) + where + old_info = idInfo old_id + id1 = uniqAway in_scope old_id + id2 = substIdType subst id1 + new_id = setIdInfo id2 vanillaIdInfo + + -- Extend the substitution if the unique has changed, + -- or there's some useful occurrence information + -- See the notes with substTyVar for the delSubstEnv + occ_info = occInfo old_info + new_env | new_id /= old_id || isFragileOcc occ_info + = extendSubstEnv env old_id (DoneId new_id occ_info) + | otherwise + = delSubstEnv env old_id + +simplIdInfo :: Subst -> IdInfo -> IdInfo + -- Used by the simplifier to compute new IdInfo for a let(rec) binder, + -- subsequent to simplLetId having zapped its IdInfo +simplIdInfo subst old_info + = case substIdInfo False subst old_info of + Just new_info -> new_info + Nothing -> old_info +\end{code} + +\begin{code} +-- substBndr and friends are used when doing expression substitution only +-- In this case we can *preserve* occurrence information, and indeed we *want* +-- to do so else lose useful occ info in rules. + substBndr :: Subst -> Var -> (Subst, Var) substBndr subst bndr | isTyVar bndr = substTyVar subst bndr - | otherwise = substId subst bndr + | otherwise = subst_id True {- keep fragile info -} subst subst bndr substBndrs :: Subst -> [Var] -> (Subst, [Var]) substBndrs subst bndrs = mapAccumL substBndr subst bndrs +substRecBndrs :: Subst -> [Id] -> (Subst, [Id]) +-- Substitute a mutually recursive group +substRecBndrs subst bndrs + = (new_subst, new_bndrs) + where + -- Here's the reason we need to pass rec_subst to subst_id + (new_subst, new_bndrs) = mapAccumL (subst_id True {- keep fragile info -} new_subst) + subst bndrs +\end{code} -substIds :: Subst -> [Id] -> (Subst, [Id]) -substIds subst bndrs = mapAccumL substId subst bndrs - -substId :: Subst -> Id -> (Subst, Id) - -- Returns an Id with empty IdInfo - -- See the notes with the Subst data type decl at the - -- top of this module -substId subst@(Subst in_scope env) old_id +\begin{code} +subst_id :: Bool -- True <=> keep fragile info + -> Subst -- Substitution to use for the IdInfo + -> Subst -> Id -- Substitition and Id to transform + -> (Subst, Id) -- Transformed pair + +-- Returns with: +-- * Unique changed if necessary +-- * Type substituted +-- * Unfolding zapped +-- * Rules, worker, lbvar info all substituted +-- * Occurrence info zapped if is_fragile_occ returns True +-- * The in-scope set extended with the returned Id +-- * The substitution extended with a DoneId if unique changed +-- In this case, the var in the DoneId is the same as the +-- var returned + +subst_id keep_fragile rec_subst subst@(Subst in_scope env) old_id = (Subst (in_scope `extendInScopeSet` new_id) new_env, new_id) where - id_ty = idType old_id - occ_info = idOccInfo old_id - - -- id1 has its type zapped - id1 | noTypeSubst env - || isEmptyVarSet (tyVarsOfType id_ty) = old_id - -- The tyVarsOfType is cheaper than it looks - -- because we cache the free tyvars of the type - -- in a Note in the id's type itself - | otherwise = setIdType old_id (substTy subst id_ty) - - -- id2 has its IdInfo zapped - id2 = zapFragileIdInfo id1 - - -- id3 has its LBVarInfo zapped - id3 = maybeModifyIdInfo (\ info -> go info (lbvarInfo info)) id2 - where go info (LBVarInfo u@(TyVarTy _)) = Just $ setLBVarInfo info $ - LBVarInfo (subst_ty subst u) - go info _ = Nothing - - -- new_id is cloned if necessary - new_id = uniqAway in_scope id3 - -- Extend the substitution if the unique has changed, - -- or there's some useful occurrence information + -- id1 is cloned if necessary + id1 = uniqAway in_scope old_id + + -- id2 has its type zapped + id2 = substIdType subst id1 + + -- new_id has the right IdInfo + -- The lazy-set is because we're in a loop here, with + -- rec_subst, when dealing with a mutually-recursive group + new_id = maybeModifyIdInfo (substIdInfo keep_fragile rec_subst) id2 + + -- Extend the substitution if the unique has changed -- See the notes with substTyVar for the delSubstEnv - new_env | new_id /= old_id || isFragileOcc occ_info - = extendSubstEnv env old_id (DoneId new_id occ_info) + new_env | new_id /= old_id + = extendSubstEnv env old_id (DoneId new_id (idOccInfo old_id)) | otherwise = delSubstEnv env old_id \end{code} Now a variant that unconditionally allocates a new unique. +It also unconditionally zaps the OccInfo. \begin{code} -substAndCloneIds :: Subst -> UniqSupply -> [Id] -> (Subst, UniqSupply, [Id]) -substAndCloneIds subst us [] = (subst, us, []) -substAndCloneIds subst us (b:bs) = case substAndCloneId subst us b of { (subst1, us1, b') -> - case substAndCloneIds subst1 us1 bs of { (subst2, us2, bs') -> - (subst2, us2, (b':bs')) }} - -substAndCloneId :: Subst -> UniqSupply -> Id -> (Subst, UniqSupply, Id) -substAndCloneId subst@(Subst in_scope env) us old_id - = (Subst (in_scope `extendInScopeSet` new_id) - (extendSubstEnv env old_id (DoneEx (Var new_id))), - new_us, - new_id) +subst_clone_id :: Subst -- Substitution to use (lazily) for the rules and worker + -> Subst -> (Id, Unique) -- Substitition and Id to transform + -> (Subst, Id) -- Transformed pair + +subst_clone_id rec_subst subst@(Subst in_scope env) (old_id, uniq) + = (Subst (in_scope `extendInScopeSet` new_id) new_env, new_id) where - id_ty = idType old_id - id1 | noTypeSubst env || isEmptyVarSet (tyVarsOfType id_ty) = old_id - | otherwise = setIdType old_id (substTy subst id_ty) + id1 = setVarUnique old_id uniq + id2 = substIdType subst id1 - id2 = zapFragileIdInfo id1 - new_id = setVarUnique id2 (uniqFromSupply us1) - (us1,new_us) = splitUniqSupply us + new_id = maybeModifyIdInfo (substIdInfo False rec_subst) id2 + new_env = extendSubstEnv env old_id (DoneId new_id NoOccInfo) + +substAndCloneIds :: Subst -> UniqSupply -> [Id] -> (Subst, [Id]) +substAndCloneIds subst us ids + = mapAccumL (subst_clone_id subst) subst (ids `zip` uniqsFromSupply us) + +substAndCloneRecIds :: Subst -> UniqSupply -> [Id] -> (Subst, [Id]) +substAndCloneRecIds subst us ids + = (subst', ids') + where + (subst', ids') = mapAccumL (subst_clone_id subst') subst + (ids `zip` uniqsFromSupply us) + +substAndCloneId :: Subst -> UniqSupply -> Id -> (Subst, Id) +substAndCloneId subst@(Subst in_scope env) us old_id + = subst_clone_id subst subst (old_id, uniqFromSupply us) \end{code} @@ -618,31 +733,62 @@ substAndCloneId subst@(Subst in_scope env) us old_id %************************************************************************ \begin{code} -substIdInfo :: Subst - -> IdInfo -- Get un-substituted ones from here - -> IdInfo -- Substitute it and add it to here - -> IdInfo -- To give this - -- Seq'ing on the returned IdInfo is enough to cause all the - -- substitutions to happen completely - -substIdInfo subst old_info new_info - = info2 - where - info1 | isEmptyCoreRules old_rules = new_info - | otherwise = new_info `setSpecInfo` new_rules +substIdInfo :: Bool -- True <=> keep even fragile info + -> Subst + -> IdInfo + -> Maybe IdInfo +-- The keep_fragile flag is True when we are running a simple expression +-- substitution that preserves all structure, so that arity and occurrence +-- info are unaffected. The False state is used more often. +-- +-- Substitute the +-- rules +-- worker info +-- Zap the unfolding +-- If keep_fragile then +-- keep OccInfo +-- keep Arity +-- else +-- keep only 'robust' OccInfo +-- zap Arity +-- +-- Seq'ing on the returned IdInfo is enough to cause all the +-- substitutions to happen completely + +substIdInfo keep_fragile subst info + | nothing_to_do = Nothing + | otherwise = Just (info `setOccInfo` (if keep_occ then old_occ else NoOccInfo) + `setArityInfo` (if keep_arity then old_arity else unknownArity) + `setSpecInfo` substRules subst old_rules + `setWorkerInfo` substWorker subst old_wrkr + `setUnfoldingInfo` noUnfolding) -- setSpecInfo does a seq - where - new_rules = substRules subst old_rules - - info2 | not (workerExists old_wrkr) = info1 - | otherwise = info1 `setWorkerInfo` new_wrkr -- setWorkerInfo does a seq - where - new_wrkr = substWorker subst old_wrkr - - old_rules = specInfo old_info - old_wrkr = workerInfo old_info + where + nothing_to_do = keep_occ && keep_arity && + isEmptyCoreRules old_rules && + not (workerExists old_wrkr) && + not (hasUnfolding (unfoldingInfo info)) + + keep_occ = keep_fragile || not (isFragileOcc old_occ) + keep_arity = keep_fragile || old_arity == unknownArity + old_arity = arityInfo info + old_occ = occInfo info + old_rules = specInfo info + old_wrkr = workerInfo info + +------------------ +substIdType :: Subst -> Id -> Id +substIdType subst@(Subst in_scope env) id + | noTypeSubst env || isEmptyVarSet (tyVarsOfType old_ty) = id + | otherwise = setIdType id (substTy subst old_ty) + -- The tyVarsOfType is cheaper than it looks + -- because we cache the free tyvars of the type + -- in a Note in the id's type itself + where + old_ty = idType id +------------------ substWorker :: Subst -> WorkerInfo -> WorkerInfo -- Seq'ing on the returned WorkerInfo is enough to cause all the -- substitutions to happen completely @@ -653,11 +799,20 @@ substWorker subst (HasWorker w a) = case lookupIdSubst subst w of (DoneId w1 _) -> HasWorker w1 a (DoneEx (Var w1)) -> HasWorker w1 a - (DoneEx other) -> WARN( True, text "substWorker: DoneEx" <+> ppr w ) + (DoneEx other) -> WARN( not (exprIsTrivial other), text "substWorker: DoneEx" <+> ppr w ) NoWorker -- Worker has got substituted away altogether + -- This can happen if it's trivial, + -- via postInlineUnconditionally (ContEx se1 e) -> WARN( True, text "substWorker: ContEx" <+> ppr w <+> ppr e) NoWorker -- Ditto +------------------ +substUnfolding subst NoUnfolding = NoUnfolding +substUnfolding subst (OtherCon cons) = OtherCon cons +substUnfolding subst (CompulsoryUnfolding rhs) = CompulsoryUnfolding (substExpr subst rhs) +substUnfolding subst (CoreUnfolding rhs t v w g) = CoreUnfolding (substExpr subst rhs) t v w g + +------------------ substRules :: Subst -> CoreRules -> CoreRules -- Seq'ing on the returned CoreRules is enough to cause all the -- substitutions to happen completely @@ -670,14 +825,15 @@ substRules subst (Rules rules rhs_fvs) where new_rules = Rules (map do_subst rules) (substVarSet subst rhs_fvs) - do_subst rule@(BuiltinRule _) = rule - do_subst (Rule name tpl_vars lhs_args rhs) - = Rule name tpl_vars' + do_subst rule@(BuiltinRule _ _) = rule + do_subst (Rule name act tpl_vars lhs_args rhs) + = Rule name act tpl_vars' (map (substExpr subst') lhs_args) (substExpr subst' rhs) where (subst', tpl_vars') = substBndrs subst tpl_vars +------------------ substVarSet subst fvs = foldVarSet (unionVarSet . subst_fv subst) emptyVarSet fvs where