import CoreUtils ( tcEqExprX )
import PprCore ( pprRules )
import Type ( TvSubstEnv )
+import Coercion ( coercionKind )
import TcType ( tcSplitTyConApp_maybe )
import CoreTidy ( tidyRules )
import Id ( Id, idUnfolding, isLocalId, isGlobalId, idName,
import Maybes ( isJust, orElse )
import OrdList
import Bag
-import Util ( singleton, mapAccumL )
+import Util ( singleton )
import List ( isPrefixOf )
\end{code}
\begin{code}
lookupRule :: (Activation -> Bool) -> InScopeSet
-> RuleBase -- Imported rules
- -> Id -> [CoreExpr] -> Maybe (RuleName, CoreExpr)
+ -> Id -> [CoreExpr] -> Maybe (CoreRule, CoreExpr)
lookupRule is_active in_scope rule_base fn args
= matchRules is_active in_scope fn args rules
where
matchRules :: (Activation -> Bool) -> InScopeSet
-> Id -> [CoreExpr]
- -> [CoreRule] -> Maybe (RuleName, CoreExpr)
+ -> [CoreRule] -> Maybe (CoreRule, CoreExpr)
-- See comments on matchRule
matchRules is_active in_scope fn args rules
- = case go [] rules of
+ = -- pprTrace "matchRules" (ppr fn <+> ppr rules) $
+ case go [] rules of
[] -> Nothing
- (m:ms) -> Just (case findBest (fn,args) m ms of
- (rule, ans) -> (ru_name rule, ans))
+ (m:ms) -> Just (findBest (fn,args) m ms)
where
rough_args = map roughTopName args
go ms [] = ms
go ms (r:rs) = case (matchRule is_active in_scope args rough_args r) of
Just e -> go ((r,e):ms) rs
- Nothing -> go ms rs
+ Nothing -> -- pprTrace "match failed" (ppr r $$ ppr args $$
+ -- ppr [(arg_id, unfoldingTemplate unf) | Var arg_id <- args, let unf = idUnfolding arg_id, isCheapUnfolding unf] )
+ go ms rs
findBest :: (Id, [CoreExpr])
-> (CoreRule,CoreExpr) -> [(CoreRule,CoreExpr)] -> (CoreRule,CoreExpr)
| ruleCantMatch tpl_tops rough_args = Nothing
| otherwise
= case matchN in_scope tpl_vars tpl_args args of
- Nothing -> Nothing
- Just (binds, tpl_vals, leftovers) -> Just (mkLets binds $
- rule_fn
- `mkApps` tpl_vals
- `mkApps` leftovers)
+ Nothing -> Nothing
+ Just (binds, tpl_vals) -> Just (mkLets binds $
+ rule_fn `mkApps` tpl_vals)
where
rule_fn = occurAnalyseExpr (mkLams tpl_vars rhs)
-- We could do this when putting things into the rulebase, I guess
-> [CoreExpr] -- Template
-> [CoreExpr] -- Target; can have more elts than template
-> Maybe ([CoreBind], -- Bindings to wrap around the entire result
- [CoreExpr], -- What is substituted for each template var
- [CoreExpr]) -- Leftover target exprs
+ [CoreExpr]) -- What is substituted for each template var
matchN in_scope tmpl_vars tmpl_es target_es
- = do { ((tv_subst, id_subst, binds), leftover_es)
+ = do { (tv_subst, id_subst, binds)
<- go init_menv emptySubstEnv tmpl_es target_es
; return (fromOL binds,
- map (lookup_tmpl tv_subst id_subst) tmpl_vars,
- leftover_es) }
+ map (lookup_tmpl tv_subst id_subst) tmpl_vars) }
where
init_menv = ME { me_tmpls = mkVarSet tmpl_vars, me_env = init_rn_env }
init_rn_env = mkRnEnv2 (extendInScopeSetList in_scope tmpl_vars)
- go menv subst [] es = Just (subst, es)
+ go menv subst [] es = Just subst
go menv subst ts [] = Nothing -- Fail if too few actual args
go menv subst (t:ts) (e:es) = do { subst1 <- match menv subst t e
; go menv subst1 ts es }
-- Notice that we look up v2 in the in-scope set
-- See Note [Lookup in-scope]
+-- Matching a let-expression. Consider
+-- RULE forall x. f (g x) = <rhs>
+-- and target expression
+-- f (let { w=R } in g E))
+-- Then we'd like the rule to match, to generate
+-- let { w=R } in (\x. <rhs>) E
+-- In effect, we want to float the let-binding outward, to enable
+-- the match to happen. This is the WHOLE REASON for accumulating
+-- bindings in the SubstEnv
+--
+-- We can only do this if
+-- (a) Widening the scope of w does not capture any variables
+-- We use a conservative test: w is not already in scope
+-- (b) The free variables of R are not bound by the part of the
+-- target expression outside the let binding; e.g.
+-- f (\v. let w = v+1 in g E)
+-- Here we obviously cannot float the let-binding for w.
+
+match menv subst@(tv_subst, id_subst, binds) e1 (Let bind e2)
+ | all freshly_bound bndrs,
+ not (any locally_bound bind_fvs)
+ = match (menv { me_env = rn_env' })
+ (tv_subst, id_subst, binds `snocOL` bind)
+ e1 e2
+ where
+ rn_env = me_env menv
+ bndrs = bindersOf bind
+ bind_fvs = varSetElems (bindFreeVars bind)
+ freshly_bound x = not (x `rnInScope` rn_env)
+ locally_bound x = inRnEnvR rn_env x
+ rn_env' = extendRnInScopeList rn_env bndrs
+
match menv subst (Lit lit1) (Lit lit2)
| lit1 == lit2
= Just subst
-- This rule does eta expansion
-- (\x.M) ~ N iff M ~ N x
+-- It's important that this is *after* the let rule,
+-- so that (\x.M) ~ (let y = e in \y.N)
+-- does the let thing, and then gets the lam/lam rule above
match menv subst (Lam x1 e1) e2
= match menv' subst e1 (App e2 (varToCoreExpr new_x))
where
match menv subst (Type ty1) (Type ty2)
= match_ty menv subst ty1 ty2
-match menv subst (Note (Coerce to1 from1) e1) (Note (Coerce to2 from2) e2)
+match menv subst (Cast e1 co1) (Cast e2 co2)
+ | (from1, to1) <- coercionKind co1
+ , (from2, to2) <- coercionKind co2
= do { subst1 <- match_ty menv subst to1 to2
; subst2 <- match_ty menv subst1 from1 from2
; match menv subst2 e1 e2 }
--- Matching a let-expression. Consider
--- RULE forall x. f (g x) = <rhs>
--- and target expression
--- f (let { w=R } in g E))
--- Then we'd like the rule to match, to generate
--- let { w=R } in (\x. <rhs>) E
--- In effect, we want to float the let-binding outward, to enable
--- the match to happen. This is the WHOLE REASON for accumulating
--- bindings in the SubstEnv
---
--- We can only do this if
--- (a) Widening the scope of w does not capture any variables
--- We use a conservative test: w is not already in scope
--- (b) The free variables of R are not bound by the part of the
--- target expression outside the let binding; e.g.
--- f (\v. let w = v+1 in g E)
--- Here we obviously cannot float the let-binding for w.
-
-match menv subst@(tv_subst, id_subst, binds) e1 (Let bind e2)
- | all freshly_bound bndrs,
- not (any locally_bound bind_fvs)
- = match (menv { me_env = rn_env' })
- (tv_subst, id_subst, binds `snocOL` bind)
- e1 e2
- where
- rn_env = me_env menv
- bndrs = bindersOf bind
- bind_fvs = varSetElems (bindFreeVars bind)
- freshly_bound x = not (x `rnInScope` rn_env)
- locally_bound x = inRnEnvR rn_env x
- rn_env' = extendRnInScopeList rn_env bndrs
-
+{- REMOVING OLD CODE: I think that the above handling for let is
+ better than the stuff here, which looks
+ pretty suspicious to me. SLPJ Sept 06
-- This is an interesting rule: we simply ignore lets in the
-- term being matched against! The unfolding inside it is (by assumption)
-- already inside any occurrences of the bound variables, so we'll expand
-- We must not get success with x->y! So we record that y is
-- locally bound (with rnBndrR), and proceed. The Var case
-- will fail when trying to bind x->y
- --
+-}
-- Everything else fails
-match menv subst e1 e2 = Nothing
+match menv subst e1 e2 = -- pprTrace "Failing at" ((text "e1:" <+> ppr e1) $$ (text "e2:" <+> ppr e2)) $
+ Nothing
------------------------------------------
match_var :: MatchEnv
ruleCheck env (Type ty) = emptyBag
ruleCheck env (App f a) = ruleCheckApp env (App f a) []
ruleCheck env (Note n e) = ruleCheck env e
+ruleCheck env (Cast e co) = ruleCheck env e
ruleCheck env (Let bd e) = ruleCheckBind env bd `unionBags` ruleCheck env e
ruleCheck env (Lam b e) = ruleCheck env e
ruleCheck env (Case e _ _ as) = ruleCheck env e `unionBags`