summaryrefslogtreecommitdiff
path: root/compiler/coreSyn
diff options
context:
space:
mode:
authorSimon Peyton Jones <simonpj@microsoft.com>2017-03-29 09:00:02 +0100
committerSimon Peyton Jones <simonpj@microsoft.com>2017-03-29 09:02:53 +0100
commit8674883c137401873fd53a6963acd33af651c2af (patch)
treee95de3232b884fe9a7cdc973c0d07cce13e2e1a5 /compiler/coreSyn
parente07211f752b9b98e2bd6957f126bd537d178041a (diff)
downloadhaskell-8674883c137401873fd53a6963acd33af651c2af.tar.gz
Allow unbound Refl binders in a RULE
Trac #13410 was failing because we had a RULE with a binder (c :: t~t) and the /occurrences/ of c on the LHS were being optimised to Refl, leaving a binder that would not be filled in by matching the LHS of the rule. I flirted with trying to ensure that occurrences (c :: t~t) are not optimised to Relf, but that turned out to be fragile; it was being done, for good reasons, in multiple places, including - TyCoRep.substCoVarBndr - Simplify.simplCast - Corecion.mkCoVarCo So I fixed it in one place by making Rules.matchN deal happily with an unbound binder (c :: t~t). Quite easy. See "Coercion variables" in Note [Unbound RULE binders] in Rules. In addition, I needed to make CoreLint be happy with an bound RULE binder that is a Relf coercion variable In debugging this, I was perplexed that occurrences of a variable (c :: t~t) mysteriously turned into Refl. I found out how it was happening, and decided to move it: * In TyCoRep.substCoVarBndr, do not substitute Refl for a binder (c :: t~t). * In mkCoVarCo do not optimise (c :: t~t) to Refl. Instead, we do this optimisation in optCoercion (specifically opt_co4) where, surprisingly, the optimisation was /not/ being done. This has no effect on what programs compile; it just moves a relatively-expensive optimisation to optCoercion, where it seems more properly to belong. It's actually not clear to me which is really "better", but this way round is less surprising. One small simplifying refactoring * Eliminate TyCoRep.substCoVarBndrCallback, which was only called locally.
Diffstat (limited to 'compiler/coreSyn')
-rw-r--r--compiler/coreSyn/CoreLint.hs18
1 files changed, 13 insertions, 5 deletions
diff --git a/compiler/coreSyn/CoreLint.hs b/compiler/coreSyn/CoreLint.hs
index 089a2250af..4c3da4332c 100644
--- a/compiler/coreSyn/CoreLint.hs
+++ b/compiler/coreSyn/CoreLint.hs
@@ -1425,16 +1425,14 @@ lintCoreRule fun fun_ty rule@(Rule { ru_name = name, ru_bndrs = bndrs
; rhs_ty <- case isJoinId_maybe fun of
Just join_arity
-> do { checkL (args `lengthIs` join_arity) $
- mkBadJoinPointRuleMsg fun join_arity rule
+ mkBadJoinPointRuleMsg fun join_arity rule
-- See Note [Rules for join points]
; lintCoreExpr rhs }
_ -> markAllJoinsBad $ lintCoreExpr rhs
; ensureEqTys lhs_ty rhs_ty $
(rule_doc <+> vcat [ text "lhs type:" <+> ppr lhs_ty
, text "rhs type:" <+> ppr rhs_ty ])
- ; let bad_bndrs = filterOut (`elemVarSet` exprsFreeVars args) $
- filter (`elemVarSet` exprFreeVars rhs) $
- bndrs
+ ; let bad_bndrs = filter is_bad_bndr bndrs
; checkL (null bad_bndrs)
(rule_doc <+> text "unbound" <+> ppr bad_bndrs)
@@ -1443,6 +1441,16 @@ lintCoreRule fun fun_ty rule@(Rule { ru_name = name, ru_bndrs = bndrs
where
rule_doc = text "Rule" <+> doubleQuotes (ftext name) <> colon
+ lhs_fvs = exprsFreeVars args
+ rhs_fvs = exprFreeVars rhs
+
+ is_bad_bndr :: Var -> Bool
+ -- See Note [Unbound RULE binders] in Rules
+ is_bad_bndr bndr = not (bndr `elemVarSet` lhs_fvs)
+ && bndr `elemVarSet` rhs_fvs
+ && isNothing (isReflCoVar_maybe bndr)
+
+
{- Note [Linting rules]
~~~~~~~~~~~~~~~~~~~~~~~
It's very bad if simplifying a rule means that one of the template
@@ -1462,7 +1470,7 @@ this check will nail it.
NB (Trac #11643): it's possible that a variable listed in the
binders becomes not-mentioned on both LHS and RHS. Here's a silly
example:
- RULE forall x y. f (g x y) = g (x+1 (y-1)
+ RULE forall x y. f (g x y) = g (x+1) (y-1)
And suppose worker/wrapper decides that 'x' is Absent. Then
we'll end up with
RULE forall x y. f ($gw y) = $gw (x+1)