X-Git-Url: http://git.megacz.com/?a=blobdiff_plain;f=compiler%2Fspecialise%2FSpecConstr.lhs;h=36dda5ecda896c9e2133b6f74686d45919e93fcf;hb=f4b727487a65e6b611bbaafbd2207bd63a8df706;hp=055f794d2e1f867cbc9b138971c38a1583e142eb;hpb=bbdccd19b73a05be23578169da5aca5b13b50519;p=ghc-hetmet.git diff --git a/compiler/specialise/SpecConstr.lhs b/compiler/specialise/SpecConstr.lhs index 055f794..36dda5e 100644 --- a/compiler/specialise/SpecConstr.lhs +++ b/compiler/specialise/SpecConstr.lhs @@ -11,7 +11,7 @@ -- for details module SpecConstr( - specConstrProgram + specConstrProgram, SpecConstrAnnotation(..) ) where #include "HsVersions.h" @@ -20,35 +20,44 @@ import CoreSyn import CoreSubst import CoreUtils import CoreUnfold ( couldBeSmallEnoughToInline ) -import CoreLint ( showPass, endPass ) import CoreFVs ( exprsFreeVars ) -import CoreTidy ( tidyRules ) -import PprCore ( pprRules ) +import CoreMonad +import HscTypes ( ModGuts(..) ) import WwLib ( mkWorkerArgs ) -import DataCon ( dataConRepArity, dataConUnivTyVars ) +import DataCon ( dataConTyCon, dataConRepArity, dataConUnivTyVars ) +import TyCon ( TyCon ) +import Literal ( literalType ) import Coercion +import Rules import Type hiding( substTy ) -import Id ( Id, idName, idType, isDataConWorkId_maybe, idArity, - mkUserLocal, mkSysLocal, idUnfolding, isLocalId ) +import Id +import MkId ( mkImpossibleExpr ) import Var import VarEnv import VarSet import Name -import Rules ( addIdSpecialisations, mkLocalRule, rulesOfBinds ) -import OccName ( mkSpecOcc ) -import ErrUtils ( dumpIfSet_dyn ) -import DynFlags ( DynFlags(..), DynFlag(..) ) +import DynFlags ( DynFlags(..) ) +import StaticFlags ( opt_PprStyle_Debug ) import StaticFlags ( opt_SpecInlineJoinPoints ) import BasicTypes ( Activation(..) ) import Maybes ( orElse, catMaybes, isJust, isNothing ) +import Demand +import DmdAnal ( both ) +import Serialized ( deserializeWithData ) import Util -import List ( nubBy, partition ) import UniqSupply import Outputable import FastString import UniqFM +import qualified LazyUniqFM as L import MonadUtils import Control.Monad ( zipWithM ) +import Data.List +#if __GLASGOW_HASKELL__ > 609 +import Data.Data ( Data, Typeable ) +#else +import Data.Generics ( Data, Typeable ) +#endif \end{code} ----------------------------------------------------- @@ -369,6 +378,19 @@ specialising the loops arising from stream fusion, for example in NDP where we were getting literally hundreds of (mostly unused) specialisations of a local function. +Note [Do not specialise diverging functions] +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +Specialising a function that just diverges is a waste of code. +Furthermore, it broke GHC (simpl014) thus: + {-# STR Sb #-} + f = \x. case x of (a,b) -> f x +If we specialise f we get + f = \x. case x of (a,b) -> fspec a b +But fspec doesn't have decent strictnes info. As it happened, +(f x) :: IO t, so the state hack applied and we eta expanded fspec, +and hence f. But now f's strictness is less than its arity, which +breaks an invariant. + ----------------------------------------------------- Stuff not yet handled ----------------------------------------------------- @@ -444,7 +466,19 @@ But perhaps the first one isn't good. After all, we know that tpl_B2 is a T (I# x) really, because T is strict and Int has one constructor. (We can't unbox the strict fields, becuase T is polymorphic!) +%************************************************************************ +%* * +\subsection{Annotations} +%* * +%************************************************************************ + +Annotating a type with NoSpecConstr will make SpecConstr not specialise +for arguments of that type. +\begin{code} +data SpecConstrAnnotation = NoSpecConstr | ForceSpecConstr + deriving( Data, Typeable, Eq ) +\end{code} %************************************************************************ %* * @@ -453,19 +487,14 @@ unbox the strict fields, becuase T is polymorphic!) %************************************************************************ \begin{code} -specConstrProgram :: DynFlags -> UniqSupply -> [CoreBind] -> IO [CoreBind] -specConstrProgram dflags us binds +specConstrProgram :: ModGuts -> CoreM ModGuts +specConstrProgram guts = do - showPass dflags "SpecConstr" - - let (binds', _) = initUs us (go (initScEnv dflags) binds) - - endPass dflags "SpecConstr" Opt_D_dump_spec binds' - - dumpIfSet_dyn dflags Opt_D_dump_rules "Top-level specialisations" - (pprRules (tidyRules emptyTidyEnv (rulesOfBinds binds'))) - - return binds' + dflags <- getDynFlags + us <- getUniqueSupplyM + annos <- getFirstAnnotations deserializeWithData guts + let binds' = fst $ initUs us (go (initScEnv dflags annos) (mg_binds guts)) + return (guts { mg_binds = binds' }) where go _ [] = return [] go env (bind:binds) = do (env', bind') <- scTopBind env bind @@ -491,9 +520,11 @@ data ScEnv = SCE { sc_size :: Maybe Int, -- Size threshold -- Binds interesting non-top-level variables -- Domain is OutVars (*after* applying the substitution) - sc_vals :: ValueEnv + sc_vals :: ValueEnv, -- Domain is OutIds (*after* applying the substitution) -- Used even for top-level bindings (but not imported ones) + + sc_annotations :: L.UniqFM SpecConstrAnnotation } --------------------- @@ -517,13 +548,14 @@ instance Outputable Value where ppr LambdaVal = ptext (sLit "") --------------------- -initScEnv :: DynFlags -> ScEnv -initScEnv dflags +initScEnv :: DynFlags -> L.UniqFM SpecConstrAnnotation -> ScEnv +initScEnv dflags anns = SCE { sc_size = specConstrThreshold dflags, sc_count = specConstrCount dflags, sc_subst = emptySubst, sc_how_bound = emptyVarEnv, - sc_vals = emptyVarEnv } + sc_vals = emptyVarEnv, + sc_annotations = anns } data HowBound = RecFun -- These are the recursive functions for which -- we seek interesting call patterns @@ -592,17 +624,28 @@ extendValEnv :: ScEnv -> Id -> Maybe Value -> ScEnv extendValEnv env _ Nothing = env extendValEnv env id (Just cv) = env { sc_vals = extendVarEnv (sc_vals env) id cv } -extendCaseBndrs :: ScEnv -> CoreExpr -> Id -> AltCon -> [Var] -> ScEnv +extendCaseBndrs :: ScEnv -> Id -> AltCon -> [Var] -> (ScEnv, [Var]) -- When we encounter -- case scrut of b -- C x y -> ... --- we want to bind b, and perhaps scrut too, to (C x y) --- NB: Extends only the sc_vals part of the envt -extendCaseBndrs env scrut case_bndr con alt_bndrs - = case scrut of - Var v -> extendValEnv env1 v cval - _other -> env1 +-- we want to bind b, to (C x y) +-- NB1: Extends only the sc_vals part of the envt +-- NB2: Kill the dead-ness info on the pattern binders x,y, since +-- they are potentially made alive by the [b -> C x y] binding +extendCaseBndrs env case_bndr con alt_bndrs + | isDeadBinder case_bndr + = (env, alt_bndrs) + | otherwise + = (env1, map zap alt_bndrs) + -- NB: We used to bind v too, if scrut = (Var v); but + -- the simplifer has already done this so it seems + -- redundant to do so here + -- case scrut of + -- Var v -> extendValEnv env1 v cval + -- _other -> env1 where + zap v | isTyVar v = v -- See NB2 above + | otherwise = zapIdOccInfo v env1 = extendValEnv env case_bndr cval cval = case con of DEFAULT -> Nothing @@ -611,6 +654,39 @@ extendCaseBndrs env scrut case_bndr con alt_bndrs where vanilla_args = map Type (tyConAppArgs (idType case_bndr)) ++ varsToCoreExprs alt_bndrs + +ignoreTyCon :: ScEnv -> TyCon -> Bool +ignoreTyCon env tycon + = L.lookupUFM (sc_annotations env) tycon == Just NoSpecConstr + +ignoreType :: ScEnv -> Type -> Bool +ignoreType env ty + = case splitTyConApp_maybe ty of + Just (tycon, _) -> ignoreTyCon env tycon + _ -> False + +ignoreAltCon :: ScEnv -> AltCon -> Bool +ignoreAltCon env (DataAlt dc) = ignoreTyCon env (dataConTyCon dc) +ignoreAltCon env (LitAlt lit) = ignoreType env (literalType lit) +ignoreAltCon _ DEFAULT = True + +forceSpecBndr :: ScEnv -> Var -> Bool +forceSpecBndr env var = forceSpecFunTy env . varType $ var + +forceSpecFunTy :: ScEnv -> Type -> Bool +forceSpecFunTy env = any (forceSpecArgTy env) . fst . splitFunTys + +forceSpecArgTy :: ScEnv -> Type -> Bool +forceSpecArgTy env ty + | Just ty' <- coreView ty = forceSpecArgTy env ty' + +forceSpecArgTy env ty + | Just (tycon, tys) <- splitTyConApp_maybe ty + , tycon /= funTyCon + = L.lookupUFM (sc_annotations env) tycon == Just ForceSpecConstr + || any (forceSpecArgTy env) tys + +forceSpecArgTy _ _ = False \end{code} @@ -769,7 +845,8 @@ scExpr' env (Case scrut b ty alts) where sc_con_app con args scrut' -- Known constructor; simplify = do { let (_, bs, rhs) = findAlt con alts - alt_env' = extendScSubstList env ((b,scrut') : bs `zip` trimConArgs con args) + `orElse` (DEFAULT, [], mkImpossibleExpr (coreAltsType alts)) + alt_env' = extendScSubstList env ((b,scrut') : bs `zip` trimConArgs con args) ; scExpr alt_env' rhs } sc_vanilla scrut_usg scrut' -- Normal case @@ -789,15 +866,15 @@ scExpr' env (Case scrut b ty alts) ; return (alt_usg `combineUsage` scrut_usg', Case scrut' b' (scSubstTy env ty) alts') } - sc_alt env scrut' b' (con,bs,rhs) - = do { let (env1, bs') = extendBndrsWith RecArg env bs - env2 = extendCaseBndrs env1 scrut' b' con bs' + sc_alt env _scrut' b' (con,bs,rhs) + = do { let (env1, bs1) = extendBndrsWith RecArg env bs + (env2, bs2) = extendCaseBndrs env1 b' con bs1 ; (usg,rhs') <- scExpr env2 rhs - ; let (usg', arg_occs) = lookupOccs usg bs' + ; let (usg', arg_occs) = lookupOccs usg bs2 scrut_occ = case con of DataAlt dc -> ScrutOcc (unitUFM dc arg_occs) _ -> ScrutOcc emptyUFM - ; return (usg', scrut_occ, (con,bs',rhs')) } + ; return (usg', scrut_occ, (con, bs2, rhs')) } scExpr' env (Let (NonRec bndr rhs) body) | isTyVar bndr -- Type-lets may be created by doBeta @@ -840,12 +917,14 @@ scExpr' env (Let (Rec prs) body) = do { let (bndrs,rhss) = unzip prs (rhs_env1,bndrs') = extendRecBndrs env bndrs rhs_env2 = extendHowBound rhs_env1 bndrs' RecFun + force_spec = any (forceSpecBndr env) bndrs' ; (rhs_usgs, rhs_infos) <- mapAndUnzipM (scRecRhs rhs_env2) (bndrs' `zip` rhss) ; (body_usg, body') <- scExpr rhs_env2 body -- NB: start specLoop from body_usg - ; (spec_usg, specs) <- specLoop rhs_env2 (scu_calls body_usg) rhs_infos nullUsage + ; (spec_usg, specs) <- specLoop rhs_env2 force_spec + (scu_calls body_usg) rhs_infos nullUsage [SI [] 0 (Just usg) | usg <- rhs_usgs] ; let all_usg = spec_usg `combineUsage` body_usg @@ -899,6 +978,7 @@ scApp env (other_fn, args) scTopBind :: ScEnv -> CoreBind -> UniqSM (ScEnv, CoreBind) scTopBind env (Rec prs) | Just threshold <- sc_size env + , not force_spec , not (all (couldBeSmallEnoughToInline threshold) rhss) -- No specialisation = do { let (rhs_env,bndrs') = extendRecBndrs env bndrs @@ -911,13 +991,15 @@ scTopBind env (Rec prs) ; (rhs_usgs, rhs_infos) <- mapAndUnzipM (scRecRhs rhs_env2) (bndrs' `zip` rhss) ; let rhs_usg = combineUsages rhs_usgs - ; (_, specs) <- specLoop rhs_env2 (scu_calls rhs_usg) rhs_infos nullUsage + ; (_, specs) <- specLoop rhs_env2 force_spec + (scu_calls rhs_usg) rhs_infos nullUsage [SI [] 0 Nothing | _ <- bndrs] ; return (rhs_env1, -- For the body of the letrec, delete the RecFun business Rec (concat (zipWith specInfoBinds rhs_infos specs))) } where (bndrs,rhss) = unzip prs + force_spec = any (forceSpecBndr env) bndrs scTopBind env (NonRec bndr rhs) = do { (_, rhs') <- scExpr env rhs @@ -982,12 +1064,13 @@ data OneSpec = OS CallPat -- Call pattern that generated this specialisation specLoop :: ScEnv + -> Bool -- force specialisation? -> CallEnv -> [RhsInfo] -> ScUsage -> [SpecInfo] -- One per binder; acccumulating parameter -> UniqSM (ScUsage, [SpecInfo]) -- ...ditto... -specLoop env all_calls rhs_infos usg_so_far specs_so_far - = do { specs_w_usg <- zipWithM (specialise env all_calls) rhs_infos specs_so_far +specLoop env force_spec all_calls rhs_infos usg_so_far specs_so_far + = do { specs_w_usg <- zipWithM (specialise env force_spec all_calls) rhs_infos specs_so_far ; let (new_usg_s, all_specs) = unzip specs_w_usg new_usg = combineUsages new_usg_s new_calls = scu_calls new_usg @@ -995,10 +1078,11 @@ specLoop env all_calls rhs_infos usg_so_far specs_so_far ; if isEmptyVarEnv new_calls then return (all_usg, all_specs) else - specLoop env new_calls rhs_infos all_usg all_specs } + specLoop env force_spec new_calls rhs_infos all_usg all_specs } specialise :: ScEnv + -> Bool -- force specialisation? -> CallEnv -- Info on calls -> RhsInfo -> SpecInfo -- Original RHS plus patterns dealt with @@ -1008,10 +1092,11 @@ specialise -- So when we make a specialised copy of the RHS, we're starting -- from an RHS whose nested functions have been optimised already. -specialise env bind_calls (fn, arg_bndrs, body, arg_occs) +specialise env force_spec bind_calls (fn, arg_bndrs, body, arg_occs) spec_info@(SI specs spec_count mb_unspec) - | notNull arg_bndrs, -- Only specialise functions - Just all_calls <- lookupVarEnv bind_calls fn + | not (isBottomingId fn) -- Note [Do not specialise diverging functions] + , notNull arg_bndrs -- Only specialise functions + , Just all_calls <- lookupVarEnv bind_calls fn = do { (boring_call, pats) <- callsToPats env specs arg_occs all_calls -- ; pprTrace "specialise" (vcat [ppr fn <+> ppr arg_occs, -- text "calls" <+> ppr all_calls, @@ -1022,11 +1107,15 @@ specialise env bind_calls (fn, arg_bndrs, body, arg_occs) -- Rather a hacky way to do so, but it'll do for now ; let spec_count' = length pats + spec_count ; case sc_count env of - Just max | spec_count' > max - -> pprTrace "SpecConstr: too many specialisations for one function (see -fspec-constr-count):" - (vcat [ptext (sLit "Function:") <+> ppr fn, - ptext (sLit "Specialisations:") <+> ppr (pats ++ [p | OS p _ _ _ <- specs])]) - return (nullUsage, spec_info) + Just max | not force_spec && spec_count' > max + -> WARN( True, msg ) return (nullUsage, spec_info) + where + msg = vcat [ sep [ ptext (sLit "SpecConstr: specialisation of") <+> quotes (ppr fn) + , nest 2 (ptext (sLit "limited by bound of")) <+> int max ] + , ptext (sLit "Use -fspec-constr-count=n to set the bound") + , extra ] + extra | not opt_PprStyle_Debug = ptext (sLit "Use -dppr-debug to see specialisations") + | otherwise = ptext (sLit "Specialisations:") <+> ppr (pats ++ [p | OS p _ _ _ <- specs]) _normal_case -> do { @@ -1095,12 +1184,37 @@ spec_one env fn arg_bndrs body (call_pat@(qvars, pats), rule_number) spec_occ = mkSpecOcc (nameOccName fn_name) rule_name = mkFastString ("SC:" ++ showSDoc (ppr fn <> int rule_number)) spec_rhs = mkLams spec_lam_args spec_body + spec_str = calcSpecStrictness fn spec_lam_args pats spec_id = mkUserLocal spec_occ spec_uniq (mkPiTypes spec_lam_args body_ty) fn_loc + `setIdStrictness` spec_str -- See Note [Transfer strictness] + `setIdArity` count isId spec_lam_args body_ty = exprType spec_body rule_rhs = mkVarApps (Var spec_id) spec_call_args rule = mkLocalRule rule_name specConstrActivation fn_name qvars pats rule_rhs ; return (spec_usg, OS call_pat rule spec_id spec_rhs) } +calcSpecStrictness :: Id -- The original function + -> [Var] -> [CoreExpr] -- Call pattern + -> StrictSig -- Strictness of specialised thing +-- See Note [Transfer strictness] +calcSpecStrictness fn qvars pats + = StrictSig (mkTopDmdType spec_dmds TopRes) + where + spec_dmds = [ lookupVarEnv dmd_env qv `orElse` lazyDmd | qv <- qvars, isId qv ] + StrictSig (DmdType _ dmds _) = idStrictness fn + + dmd_env = go emptyVarEnv dmds pats + + go env ds (Type {} : pats) = go env ds pats + go env (d:ds) (pat : pats) = go (go_one env d pat) ds pats + go env _ _ = env + + go_one env d (Var v) = extendVarEnv_C both env v d + go_one env (Box d) e = go_one env d e + go_one env (Eval (Prod ds)) e + | (Var _, args) <- collectArgs e = go env ds args + go_one env _ _ = env + -- In which phase should the specialise-constructor rules be active? -- Originally I made them always-active, but Manuel found that -- this defeated some clever user-written rules. So Plan B @@ -1113,6 +1227,23 @@ specConstrActivation :: Activation specConstrActivation = ActiveAfter 0 -- Baked in; see comments above \end{code} +Note [Transfer strictness] +~~~~~~~~~~~~~~~~~~~~~~~~~~ +We must transfer strictness information from the original function to +the specialised one. Suppose, for example + + f has strictness SS + and a RULE f (a:as) b = f_spec a as b + +Now we want f_spec to have strictess LLS, otherwise we'll use call-by-need +when calling f_spec instead of call-by-value. And that can result in +unbounded worsening in space (cf the classic foldl vs foldl') + +See Trac #3437 for a good example. + +The function calcSpecStrictness performs the calculation. + + %************************************************************************ %* * \subsection{Argument analysis} @@ -1152,7 +1283,7 @@ callToPats env bndr_occs (con_env, args) = return Nothing | otherwise = do { let in_scope = substInScope (sc_subst env) - ; prs <- argsToPats in_scope con_env (args `zip` bndr_occs) + ; prs <- argsToPats env in_scope con_env (args `zip` bndr_occs) ; let (interesting_s, pats) = unzip prs pat_fvs = varSetElems (exprsFreeVars pats) qvars = filterOut (`elemInScopeSet` in_scope) pat_fvs @@ -1176,7 +1307,8 @@ callToPats env bndr_occs (con_env, args) -- placeholder variables. For example: -- C a (D (f x) (g y)) ==> C p1 (D p2 p3) -argToPat :: InScopeSet -- What's in scope at the fn defn site +argToPat :: ScEnv + -> InScopeSet -- What's in scope at the fn defn site -> ValueEnv -- ValueEnv at the call site -> CoreArg -- A call arg (or component thereof) -> ArgOcc @@ -1191,11 +1323,11 @@ argToPat :: InScopeSet -- What's in scope at the fn defn site -- lvl7 --> (True, lvl7) if lvl7 is bound -- somewhere further out -argToPat _in_scope _val_env arg@(Type {}) _arg_occ +argToPat _env _in_scope _val_env arg@(Type {}) _arg_occ = return (False, arg) -argToPat in_scope val_env (Note _ arg) arg_occ - = argToPat in_scope val_env arg arg_occ +argToPat env in_scope val_env (Note _ arg) arg_occ + = argToPat env in_scope val_env arg arg_occ -- Note [Notes in call patterns] -- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -- Ignore Notes. In particular, we want to ignore any InlineMe notes @@ -1203,16 +1335,16 @@ argToPat in_scope val_env (Note _ arg) arg_occ -- ride roughshod over them all for now. --- See Note [Notes in RULE matching] in Rules -argToPat in_scope val_env (Let _ arg) arg_occ - = argToPat in_scope val_env arg arg_occ +argToPat env in_scope val_env (Let _ arg) arg_occ + = argToPat env in_scope val_env arg arg_occ -- Look through let expressions -- e.g. f (let v = rhs in \y -> ...v...) -- Here we can specialise for f (\y -> ...) -- because the rule-matcher will look through the let. -argToPat in_scope val_env (Cast arg co) arg_occ - = do { (interesting, arg') <- argToPat in_scope val_env arg arg_occ - ; let (ty1,ty2) = coercionKind co +argToPat env in_scope val_env (Cast arg co) arg_occ + | not (ignoreType env ty2) + = do { (interesting, arg') <- argToPat env in_scope val_env arg arg_occ ; if not interesting then wildCardPat ty2 else do @@ -1221,6 +1353,10 @@ argToPat in_scope val_env (Cast arg co) arg_occ ; let co_name = mkSysTvName uniq (fsLit "sg") co_var = mkCoVar co_name (mkCoKind ty1 ty2) ; return (interesting, Cast arg' (mkTyVarTy co_var)) } } + where + (ty1, ty2) = coercionKind co + + {- Disabling lambda specialisation for now It's fragile, and the spec_loop can be infinite @@ -1236,15 +1372,16 @@ argToPat in_scope val_env arg arg_occ -- Check for a constructor application -- NB: this *precedes* the Var case, so that we catch nullary constrs -argToPat in_scope val_env arg arg_occ +argToPat env in_scope val_env arg arg_occ | Just (ConVal dc args) <- isValue val_env arg + , not (ignoreAltCon env dc) , case arg_occ of ScrutOcc _ -> True -- Used only by case scrutinee BothOcc -> case arg of -- Used elsewhere App {} -> True -- see Note [Reboxing] _other -> False _other -> False -- No point; the arg is not decomposed - = do { args' <- argsToPats in_scope val_env (args `zip` conArgOccs arg_occ dc) + = do { args' <- argsToPats env in_scope val_env (args `zip` conArgOccs arg_occ dc) ; return (True, mk_con_app dc (map snd args')) } -- Check if the argument is a variable that @@ -1252,9 +1389,10 @@ argToPat in_scope val_env arg arg_occ -- It's worth specialising on this if -- (a) it's used in an interesting way in the body -- (b) we know what its value is -argToPat in_scope val_env (Var v) arg_occ +argToPat env in_scope val_env (Var v) arg_occ | case arg_occ of { UnkOcc -> False; _other -> True }, -- (a) - is_value -- (b) + is_value, -- (b) + not (ignoreType env (varType v)) = return (True, Var v) where is_value @@ -1283,7 +1421,7 @@ argToPat in_scope val_env (Var v) arg_occ -- We don't want to specialise for that *particular* x,y -- The default case: make a wild-card -argToPat _in_scope _val_env arg _arg_occ +argToPat _env _in_scope _val_env arg _arg_occ = wildCardPat (exprType arg) wildCardPat :: Type -> UniqSM (Bool, CoreArg) @@ -1291,13 +1429,13 @@ wildCardPat ty = do { uniq <- getUniqueUs ; let id = mkSysLocal (fsLit "sc") uniq ty ; return (False, Var id) } -argsToPats :: InScopeSet -> ValueEnv +argsToPats :: ScEnv -> InScopeSet -> ValueEnv -> [(CoreArg, ArgOcc)] -> UniqSM [(Bool, CoreArg)] -argsToPats in_scope val_env args +argsToPats env in_scope val_env args = mapM do_one args where - do_one (arg,occ) = argToPat in_scope val_env arg occ + do_one (arg,occ) = argToPat env in_scope val_env arg occ \end{code}