[commit: ghc] master: Comments only: explain checkAxInstCo in OptCoercion (393f0bb)
git at git.haskell.org
git at git.haskell.org
Thu Sep 18 17:41:03 UTC 2014
Repository : ssh://git@git.haskell.org/ghc
On branch : master
Link : http://ghc.haskell.org/trac/ghc/changeset/393f0bbf9a36b4137457efee79e6562675cf1902/ghc
>---------------------------------------------------------------
commit 393f0bbf9a36b4137457efee79e6562675cf1902
Author: Richard Eisenberg <eir at cis.upenn.edu>
Date: Thu Sep 18 13:40:47 2014 -0400
Comments only: explain checkAxInstCo in OptCoercion
>---------------------------------------------------------------
393f0bbf9a36b4137457efee79e6562675cf1902
compiler/types/OptCoercion.lhs | 61 +++++++++++++++++++++++++++++++++---------
1 file changed, 48 insertions(+), 13 deletions(-)
diff --git a/compiler/types/OptCoercion.lhs b/compiler/types/OptCoercion.lhs
index 6eccf42..5cc2e64 100644
--- a/compiler/types/OptCoercion.lhs
+++ b/compiler/types/OptCoercion.lhs
@@ -455,6 +455,7 @@ opt_trans_rule is co1 co2
-- Push transitivity inside axioms
opt_trans_rule is co1 co2
+ -- See Note [Why call checkAxInstCo during optimisation]
-- TrPushSymAxR
| Just (sym, con, ind, cos1) <- co1_is_axiom_maybe
, Just cos2 <- matchAxiom sym con ind co2
@@ -537,13 +538,47 @@ Equal :: forall k::BOX. k -> k -> Bool
axEqual :: { forall k::BOX. forall a::k. Equal k a a ~ True
; forall k::BOX. forall a::k. forall b::k. Equal k a b ~ False }
-We wish to disallow (axEqual[1] <*> <Int> <Int). (Recall that the index is 0-based,
-so this is the second branch of the axiom.) The problem is that, on the surface, it
-seems that (axEqual[1] <*> <Int> <Int>) :: (Equal * Int Int ~ False) and that all is
-OK. But, all is not OK: we want to use the first branch of the axiom in this case,
-not the second. The problem is that the parameters of the first branch can unify with
-the supplied coercions, thus meaning that the first branch should be taken. See also
-Note [Branched instance checking] in types/FamInstEnv.lhs.
+We wish to disallow (axEqual[1] <*> <Int> <Int). (Recall that the index is
+0-based, so this is the second branch of the axiom.) The problem is that, on
+the surface, it seems that (axEqual[1] <*> <Int> <Int>) :: (Equal * Int Int ~
+False) and that all is OK. But, all is not OK: we want to use the first branch
+of the axiom in this case, not the second. The problem is that the parameters
+of the first branch can unify with the supplied coercions, thus meaning that
+the first branch should be taken. See also Note [Branched instance checking]
+in types/FamInstEnv.lhs.
+
+Note [Why call checkAxInstCo during optimisation]
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+It is possible that otherwise-good-looking optimisations meet with disaster
+in the presence of axioms with multiple equations. Consider
+
+type family Equal (a :: *) (b :: *) :: Bool where
+ Equal a a = True
+ Equal a b = False
+type family Id (a :: *) :: * where
+ Id a = a
+
+axEq :: { [a::*]. Equal a a ~ True
+ ; [a::*, b::*]. Equal a b ~ False }
+axId :: [a::*]. Id a ~ a
+
+co1 = Equal (axId[0] Int) (axId[0] Bool)
+ :: Equal (Id Int) (Id Bool) ~ Equal Int Bool
+co2 = axEq[1] <Int> <Bool>
+ :: Equal Int Bool ~ False
+
+We wish to optimise (co1 ; co2). We end up in rule TrPushAxL, noting that
+co2 is an axiom and that matchAxiom succeeds when looking at co1. But, what
+happens when we push the coercions inside? We get
+
+co3 = axEq[1] (axId[0] Int) (axId[0] Bool)
+ :: Equal (Id Int) (Id Bool) ~ False
+
+which is bogus! This is because the type system isn't smart enough to know
+that (Id Int) and (Id Bool) are Surely Apart, as they're headed by type
+families. At the time of writing, I (Richard Eisenberg) couldn't think of
+a way of detecting this any more efficient than just building the optimised
+coercion and checking.
\begin{code}
-- | Check to make sure that an AxInstCo is internally consistent.
@@ -554,12 +589,12 @@ checkAxInstCo :: Coercion -> Maybe CoAxBranch
-- If you edit this function, you may need to update the GHC formalism
-- See Note [GHC Formalism] in CoreLint
checkAxInstCo (AxiomInstCo ax ind cos)
- = let branch = coAxiomNthBranch ax ind
- tvs = coAxBranchTyVars branch
- incomps = coAxBranchIncomps branch
- tys = map (pFst . coercionKind) cos
- subst = zipOpenTvSubst tvs tys
- target = Type.substTys subst (coAxBranchLHS branch)
+ = let branch = coAxiomNthBranch ax ind
+ tvs = coAxBranchTyVars branch
+ incomps = coAxBranchIncomps branch
+ tys = map (pFst . coercionKind) cos
+ subst = zipOpenTvSubst tvs tys
+ target = Type.substTys subst (coAxBranchLHS branch)
in_scope = mkInScopeSet $
unionVarSets (map (tyVarsOfTypes . coAxBranchLHS) incomps)
flattened_target = flattenTys in_scope target in
More information about the ghc-commits
mailing list