diff options
author | Simon Peyton Jones <simon.peytonjones@gmail.com> | 2022-12-19 22:29:19 +0000 |
---|---|---|
committer | Marge Bot <ben+marge-bot@smart-cactus.org> | 2022-12-21 14:32:30 -0500 |
commit | e193e53790dd5886feea3cf4c9c17625d188291b (patch) | |
tree | 2ce9d6b7fa4bf749fe51d4580e3e7a0300676538 /compiler | |
parent | df7bc6b36d16e91f3e9e96e9542885e544bbf4d0 (diff) | |
download | haskell-e193e53790dd5886feea3cf4c9c17625d188291b.tar.gz |
Fix shadowing lacuna in OccurAnal
Issue #22623 demonstrated another lacuna in the implementation
of wrinkle (BS3) in Note [The binder-swap substitution] in
the occurrence analyser.
I was failing to add TyVar lambda binders using
addInScope/addOneInScope and that led to a totally bogus binder-swap
transformation.
Very easy to fix.
Diffstat (limited to 'compiler')
-rw-r--r-- | compiler/GHC/Core/Opt/OccurAnal.hs | 53 | ||||
-rw-r--r-- | compiler/GHC/Core/Opt/Simplify.hs | 4 |
2 files changed, 34 insertions, 23 deletions
diff --git a/compiler/GHC/Core/Opt/OccurAnal.hs b/compiler/GHC/Core/Opt/OccurAnal.hs index 0c6f4d5413..539074e698 100644 --- a/compiler/GHC/Core/Opt/OccurAnal.hs +++ b/compiler/GHC/Core/Opt/OccurAnal.hs @@ -1820,7 +1820,8 @@ occAnalLam :: OccEnv -> CoreExpr -> (WithUsageDetails CoreExpr) occAnalLam env (Lam bndr expr) | isTyVar bndr - = let (WithUsageDetails usage expr') = occAnalLam env expr + = let env1 = addOneInScope env bndr + WithUsageDetails usage expr' = occAnalLam env1 expr in WithUsageDetails usage (Lam bndr expr') -- Important: Keep the 'env' unchanged so that with a RHS like -- \(@ x) -> K @x (f @x) @@ -2466,10 +2467,11 @@ data OccEnv -- If x :-> (y, co) is in the env, -- then please replace x by (y |> mco) -- Invariant of course: idType x = exprType (y |> mco) - , occ_bs_env :: !(VarEnv (OutId, MCoercion)) - , occ_bs_rng :: !VarSet -- Vars free in the range of occ_bs_env + , occ_bs_env :: !(IdEnv (OutId, MCoercion)) -- Domain is Global and Local Ids -- Range is just Local Ids + , occ_bs_rng :: !VarSet + -- Vars (TyVars and Ids) free in the range of occ_bs_env } @@ -2546,14 +2548,15 @@ isRhsEnv (OccEnv { occ_encl = cxt }) = case cxt of _ -> False addOneInScope :: OccEnv -> CoreBndr -> OccEnv +-- Needed for all Vars not just Ids +-- See Note [The binder-swap substitution] (BS3) addOneInScope env@(OccEnv { occ_bs_env = swap_env, occ_bs_rng = rng_vars }) bndr | bndr `elemVarSet` rng_vars = env { occ_bs_env = emptyVarEnv, occ_bs_rng = emptyVarSet } | otherwise = env { occ_bs_env = swap_env `delVarEnv` bndr } addInScope :: OccEnv -> [Var] -> OccEnv --- See Note [The binder-swap substitution] --- It's only necessary to call this on in-scope Ids, --- but harmless to include TyVars too +-- Needed for all Vars not just Ids +-- See Note [The binder-swap substitution] (BS3) addInScope env@(OccEnv { occ_bs_env = swap_env, occ_bs_rng = rng_vars }) bndrs | any (`elemVarSet` rng_vars) bndrs = env { occ_bs_env = emptyVarEnv, occ_bs_rng = emptyVarSet } | otherwise = env { occ_bs_env = swap_env `delVarEnvList` bndrs } @@ -2712,25 +2715,29 @@ Some tricky corners: (BS3) We need care when shadowing. Suppose [x :-> b] is in occ_bs_env, and we encounter: - - \x. blah - Here we want to delete the x-binding from occ_bs_env - - - \b. blah - This is harder: we really want to delete all bindings that - have 'b' free in the range. That is a bit tiresome to implement, - so we compromise. We keep occ_bs_rng, which is the set of - free vars of rng(occc_bs_env). If a binder shadows any of these - variables, we discard all of occ_bs_env. Safe, if a bit - brutal. NB, however: the simplifer de-shadows the code, so the - next time around this won't happen. + (i) \x. blah + Here we want to delete the x-binding from occ_bs_env + + (ii) \b. blah + This is harder: we really want to delete all bindings that + have 'b' free in the range. That is a bit tiresome to implement, + so we compromise. We keep occ_bs_rng, which is the set of + free vars of rng(occc_bs_env). If a binder shadows any of these + variables, we discard all of occ_bs_env. Safe, if a bit + brutal. NB, however: the simplifer de-shadows the code, so the + next time around this won't happen. These checks are implemented in addInScope. - - The occurrence analyser itself does /not/ do cloning. It could, in - principle, but it'd make it a bit more complicated and there is no - great benefit. The simplifer uses cloning to get a no-shadowing - situation, the care-when-shadowing behaviour above isn't needed for - long. + (i) is needed only for Ids, but (ii) is needed for tyvars too (#22623) + because if occ_bs_env has [x :-> ...a...] where `a` is a tyvar, we + must not replace `x` by `...a...` under /\a. ...x..., or similarly + under a case pattern match that binds `a`. + + An alternative would be for the occurrence analyser to do cloning as + it goes. In principle it could do so, but it'd make it a bit more + complicated and there is no great benefit. The simplifer uses + cloning to get a no-shadowing situation, the care-when-shadowing + behaviour above isn't needed for long. (BS4) The domain of occ_bs_env can include GlobaIds. Eg case M.foo of b { alts } diff --git a/compiler/GHC/Core/Opt/Simplify.hs b/compiler/GHC/Core/Opt/Simplify.hs index 0cc6d984e5..7b7b439e33 100644 --- a/compiler/GHC/Core/Opt/Simplify.hs +++ b/compiler/GHC/Core/Opt/Simplify.hs @@ -132,7 +132,11 @@ data SimplifyOpts = SimplifyOpts { so_dump_core_sizes :: !Bool , so_iterations :: !Int , so_mode :: !SimplMode + , so_pass_result_cfg :: !(Maybe LintPassResultConfig) + -- Nothing => Do not Lint + -- Just cfg => Lint like this + , so_hpt_rules :: !RuleBase , so_top_env_cfg :: !TopEnvConfig } |