summaryrefslogtreecommitdiff
path: root/compiler/GHC/Tc/Types/Constraint.hs
diff options
context:
space:
mode:
authorRichard Eisenberg <rae@richarde.dev>2021-01-14 22:24:19 -0500
committerMarge Bot <ben+marge-bot@smart-cactus.org>2021-04-10 05:29:21 -0400
commitcd3917564e3caf9af676817878957c3cc6688e6d (patch)
tree7d6629bc6d6c0d23fa6708be2a75e3fe407e6df6 /compiler/GHC/Tc/Types/Constraint.hs
parenta951e06921f05df1601d9c3a39efcede27f3330c (diff)
downloadhaskell-cd3917564e3caf9af676817878957c3cc6688e6d.tar.gz
Tweak kick-out condition K2b to deal with LHSs
Kick out condition K2b really only makes sense for inerts with a type variable on the left. This updates the commentary and the code to skip this check for inerts with type families on the left. Also cleans up some commentary around solver invariants and adds Note [K2b]. Close #19042. test case: typecheck/should_compile/T19042
Diffstat (limited to 'compiler/GHC/Tc/Types/Constraint.hs')
-rw-r--r--compiler/GHC/Tc/Types/Constraint.hs53
1 files changed, 52 insertions, 1 deletions
diff --git a/compiler/GHC/Tc/Types/Constraint.hs b/compiler/GHC/Tc/Types/Constraint.hs
index 03aff4fff4..27a7a3abbf 100644
--- a/compiler/GHC/Tc/Types/Constraint.hs
+++ b/compiler/GHC/Tc/Types/Constraint.hs
@@ -142,7 +142,9 @@ We thus perform an occurs-check. There is, of course, some subtlety:
already inert, with all type family redexes reduced. So a simple
syntactic check is just fine.
-The occurs check is performed in GHC.Tc.Utils.Unify.checkTypeEq.
+The occurs check is performed in GHC.Tc.Utils.Unify.checkTypeEq
+and forms condition T3 in Note [Extending the inert equalities]
+in GHC.Tc.Solver.Monad.
-}
@@ -1708,6 +1710,55 @@ I thought maybe we could never get Derived ReprEq constraints, but
we can; straight from the Wanteds during improvement. And from a Derived
ReprEq we could conceivably get a Derived NomEq improvement (by decomposing
a type constructor with Nomninal role), and hence unify.
+
+This restriction bites, in an obscure scenario:
+
+ data T a
+ type role T nominal
+
+ type family F a
+
+ g :: forall b a. (F a ~ T a, Coercible (F a) (T b)) => ()
+ g = ()
+
+ f :: forall a. (F a ~ T a) => ()
+ f = g @a
+
+The problem is in the body of f. We have
+
+ [G] F a ~N T a
+ [WD] F alpha ~N T alpha
+ [WD] F alpha ~R T a
+
+The Wanteds aren't of use, so let's just look at Deriveds:
+
+ [G] F a ~N T a
+ [D] F alpha ~N T alpha
+ [D] F alpha ~R T a
+
+As written, this makes no progress, and GHC errors. But, if we
+allowed D/N to rewrite D/R, the first D could rewrite the second:
+
+ [G] F a ~N T a
+ [D] F alpha ~N T alpha
+ [D] T alpha ~R T a
+
+Now we decompose the second D to get
+
+ [D] alpha ~N a
+
+noting the role annotation on T. This causes (alpha := a), and then
+everything else unlocks.
+
+What to do? We could "decompose" nominal equalities into nominal-only
+("NO") equalities and representational ones, where a NO equality rewrites
+only nominals. That is, when considering whether [D] F alpha ~N T alpha
+should rewrite [D] F alpha ~R T a, we could require splitting the first D
+into [D] F alpha ~NO T alpha, [D] F alpha ~R T alpha. Then, we use the R
+half of the split to rewrite the second D, and off we go. This splitting
+would allow the split-off R equality to be rewritten by other equalities,
+thus avoiding the problem in Note [Why R2?] in GHC.Tc.Solver.Monad.
+
-}
eqCanRewrite :: EqRel -> EqRel -> Bool