summaryrefslogtreecommitdiff
path: root/compiler/specialise/Rules.lhs
diff options
context:
space:
mode:
authorsimonpj@microsoft.com <unknown>2006-06-24 16:04:21 +0000
committersimonpj@microsoft.com <unknown>2006-06-24 16:04:21 +0000
commit7d44782fdfab8c280ae8de1846cb40a78b6edb95 (patch)
tree78de30fa4dc288860e2d8f996730e32b0dfb4b06 /compiler/specialise/Rules.lhs
parentc21d7cede2478d147340cd1ebdb26875d3ba333b (diff)
downloadhaskell-7d44782fdfab8c280ae8de1846cb40a78b6edb95.tar.gz
Improve RULE matching a bit more
Consider this example (provided by Roman) foo :: Int -> Maybe Int -> Int foo 0 (Just n) = n foo m (Just n) = foo (m-n) (Just n) SpecConstr sees this fragment: case w_smT of wild_Xf [Just A] { Data.Maybe.Nothing -> lvl_smf; Data.Maybe.Just n_acT [Just S(L)] -> case n_acT of wild1_ams [Just A] { GHC.Base.I# y_amr [Just L] -> $wfoo_smW (GHC.Prim.-# ds_Xmb y_amr) wild_Xf }}; and correctly generates the rule RULES: "SC:$wfoo1" [0] __forall {y_amr [Just L] :: GHC.Prim.Int# sc_snn :: GHC.Prim.Int#} $wfoo_smW sc_snn (Data.Maybe.Just @ GHC.Base.Int (GHC.Base.I# y_amr)) = $s$wfoo_sno y_amr sc_snn ;] BUT we must ensure that this rule matches in the original function! Note that the call to $wfoo is $wfoo_smW (GHC.Prim.-# ds_Xmb y_amr) wild_Xf During matching we expand wild_Xf to (Just n_acT). But then we must also expand n_acT to (I# y_amr). And we can only do that if we look up n_acT in the in-scope set, because in wild_Xf's unfolding it won't have an unfolding at all. Happily, fixing the bug is easy: add a call to 'lookupRnInScope' in the (Var v2) case of 'match'.
Diffstat (limited to 'compiler/specialise/Rules.lhs')
-rw-r--r--compiler/specialise/Rules.lhs52
1 files changed, 48 insertions, 4 deletions
diff --git a/compiler/specialise/Rules.lhs b/compiler/specialise/Rules.lhs
index f70266e8aa..4a87560616 100644
--- a/compiler/specialise/Rules.lhs
+++ b/compiler/specialise/Rules.lhs
@@ -34,7 +34,7 @@ import VarEnv ( IdEnv, InScopeSet, emptyTidyEnv,
emptyVarEnv, lookupVarEnv, extendVarEnv,
nukeRnEnvL, mkRnEnv2, rnOccR, rnOccL, inRnEnvR,
rnBndrR, rnBndr2, rnBndrL, rnBndrs2,
- rnInScope, extendRnInScopeList )
+ rnInScope, extendRnInScopeList, lookupRnInScope )
import VarSet
import Name ( Name, NamedThing(..), nameOccName )
import NameEnv
@@ -414,10 +414,18 @@ match menv subst (Var v1) e2
-- (Its occurrence information is not necessarily up to date,
-- so we don't use it.)
match menv subst e1 (Var v2)
- | isCheapUnfolding unfolding
+ | not (inRnEnvR rn_env v2),
+ -- If v2 is in the RnEnvR, then it's locally bound and can't
+ -- have an unfolding. We must make this check because if it
+ -- is locally bound we must not look it up in the in-scope set
+ -- E.g. (\x->x) where x is already in scope
+ isCheapUnfolding unfolding
= match menv subst e1 (unfoldingTemplate unfolding)
where
- unfolding = idUnfolding v2
+ rn_env = me_env menv
+ unfolding = idUnfolding (lookupRnInScope rn_env v2)
+ -- Notice that we look up v2 in the in-scope set
+ -- See Note [Lookup in-scope]
match menv subst (Lit lit1) (Lit lit2)
| lit1 == lit2
@@ -534,7 +542,7 @@ match_var menv subst@(tv_subst, id_subst, binds) v1 e2
-> Nothing -- Occurs check failure
-- e.g. match forall a. (\x-> a x) against (\y. y y)
- | otherwise
+ | otherwise -- No renaming to do on e2
-> Just (tv_subst, extendVarEnv id_subst v1 e2, binds)
Just e2' | tcEqExprX (nukeRnEnvL rn_env) e2' e2
@@ -591,6 +599,42 @@ match_ty menv (tv_subst, id_subst, binds) ty1 ty2
\end{code}
+Note [Lookup in-scope]
+~~~~~~~~~~~~~~~~~~~~~~
+Consider this example
+ foo :: Int -> Maybe Int -> Int
+ foo 0 (Just n) = n
+ foo m (Just n) = foo (m-n) (Just n)
+
+SpecConstr sees this fragment:
+
+ case w_smT of wild_Xf [Just A] {
+ Data.Maybe.Nothing -> lvl_smf;
+ Data.Maybe.Just n_acT [Just S(L)] ->
+ case n_acT of wild1_ams [Just A] { GHC.Base.I# y_amr [Just L] ->
+ $wfoo_smW (GHC.Prim.-# ds_Xmb y_amr) wild_Xf
+ }};
+
+and correctly generates the rule
+
+ RULES: "SC:$wfoo1" [0] __forall {y_amr [Just L] :: GHC.Prim.Int#
+ sc_snn :: GHC.Prim.Int#}
+ $wfoo_smW sc_snn (Data.Maybe.Just @ GHC.Base.Int (GHC.Base.I# y_amr))
+ = $s$wfoo_sno y_amr sc_snn ;]
+
+BUT we must ensure that this rule matches in the original function!
+Note that the call to $wfoo is
+ $wfoo_smW (GHC.Prim.-# ds_Xmb y_amr) wild_Xf
+
+During matching we expand wild_Xf to (Just n_acT). But then we must also
+expand n_acT to (I# y_amr). And we can only do that if we look up n_acT
+in the in-scope set, because in wild_Xf's unfolding it won't have an unfolding
+at all.
+
+That is why the 'lookupRnInScope' call in the (Var v2) case of 'match'
+is so important.
+
+
%************************************************************************
%* *
\subsection{Checking a program for failing rule applications}