summaryrefslogtreecommitdiff
path: root/compiler
diff options
context:
space:
mode:
Diffstat (limited to 'compiler')
-rw-r--r--compiler/typecheck/TcRnTypes.hs58
-rw-r--r--compiler/typecheck/TcSMonad.hs102
2 files changed, 98 insertions, 62 deletions
diff --git a/compiler/typecheck/TcRnTypes.hs b/compiler/typecheck/TcRnTypes.hs
index 0474f747e2..7d7f265b78 100644
--- a/compiler/typecheck/TcRnTypes.hs
+++ b/compiler/typecheck/TcRnTypes.hs
@@ -1793,11 +1793,10 @@ superClassesMightHelp :: Ct -> Bool
-- expose more equalities or functional dependencies) might help to
-- solve this constraint. See Note [When superclases help]
superClassesMightHelp ct
- | CDictCan { cc_class = cls } <- ct
- , cls `hasKey` ipClassKey
- = False
- | otherwise
- = True
+ = isWantedCt ct && not (is_ip ct)
+ where
+ is_ip (CDictCan { cc_class = cls }) = isIPClass cls
+ is_ip _ = False
{- Note [When superclasses help]
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
@@ -1805,26 +1804,35 @@ First read Note [The superclass story] in TcCanonical.
We expand superclasses and iterate only if there is at unsolved wanted
for which expansion of superclasses (e.g. from given constraints)
-might actually help. Usually the answer is "yes" but for implicit
-paramters it is "no". If we have [W] ?x::ty, expanding superclasses
-won't help:
- - Superclasses can't be implicit parameters
- - If we have a [G] ?x:ty2, then we'll have another unsolved
- [D] ty ~ ty2 (from the functional dependency)
- which will trigger superclass expansion.
-
-It's a bit of a special case, but it's easy to do. The runtime cost
-is low because the unsolved set is usually empty anyway (errors
-aside), and the first non-imlicit-parameter will terminate the search.
-
-The special case is worth it (Trac #11480, comment:2) because it
-applies to CallStack constraints, which aren't type errors. If we have
- f :: (C a) => blah
- f x = ...undefined...
-we'll get a CallStack constraint. If that's the only unsolved constraint
-it'll eventually be solved by defaulting. So we don't want to emit warnings
-about hitting the simplifier's iteration limit. A CallStack constraint
-really isn't an unsolved constraint; it can always be solved by defaulting.
+might actually help. The function superClassesMightHelp tells if
+doing this superclass expansion might help solve this constraint.
+Note that
+
+ * Superclasses help only for Wanted constraints. Derived constraints
+ are not really "unsolved" and we certainly don't want them to
+ trigger superclass expansion. This was a good part of the loop
+ in Trac #11523
+
+ * Even for Wanted constraints, we say "no" for implicit paramters.
+ we have [W] ?x::ty, expanding superclasses won't help:
+ - Superclasses can't be implicit parameters
+ - If we have a [G] ?x:ty2, then we'll have another unsolved
+ [D] ty ~ ty2 (from the functional dependency)
+ which will trigger superclass expansion.
+
+ It's a bit of a special case, but it's easy to do. The runtime cost
+ is low because the unsolved set is usually empty anyway (errors
+ aside), and the first non-imlicit-parameter will terminate the search.
+
+ The special case is worth it (Trac #11480, comment:2) because it
+ applies to CallStack constraints, which aren't type errors. If we have
+ f :: (C a) => blah
+ f x = ...undefined...
+ we'll get a CallStack constraint. If that's the only unsolved
+ constraint it'll eventually be solved by defaulting. So we don't
+ want to emit warnings about hitting the simplifier's iteration
+ limit. A CallStack constraint really isn't an unsolved
+ constraint; it can always be solved by defaulting.
-}
singleCt :: Ct -> Cts
diff --git a/compiler/typecheck/TcSMonad.hs b/compiler/typecheck/TcSMonad.hs
index edcedf7701..9cb2b9b955 100644
--- a/compiler/typecheck/TcSMonad.hs
+++ b/compiler/typecheck/TcSMonad.hs
@@ -554,8 +554,10 @@ Result
data InertCans -- See Note [Detailed InertCans Invariants] for more
= IC { inert_model :: InertModel
+ -- See Note [inert_model: the inert model]
, inert_eqs :: TyVarEnv EqualCtList
+ -- See Note [inert_eqs: the inert equalities]
-- All Given/Wanted CTyEqCans; index is the LHS tyvar
, inert_funeqs :: FunEqMap Ct
@@ -664,6 +666,10 @@ Note [inert_model: the inert model]
- A Derived "shadow copy" for every Given or Wanted (a ~N ty) in
inert_eqs.
+ * The model is not subject to "kicking-out". Reason: we make a Derived
+ shadow copy of any Given/Wanted (a ~ ty), and that Derived copy will
+ be fully rewritten by the model before it is added
+
* The principal reason for maintaining the model is to generate
equalities that tell us how to unify a variable: that is, what
Mark Jones calls "improvement". The same idea is sometimes also
@@ -1101,33 +1107,39 @@ Note [Adding an inert canonical constraint the InertCans]
* Adding a *nominal* CTyEqCan (a ~N ty) to the inert set (TcSMonad.addInertEq).
- * Always (G/W/D) kick out constraints that can be rewritten
- (respecting flavours) by the new constraint. This is done
- by kickOutRewritable.
+ (A) Always (G/W/D) kick out constraints that can be rewritten
+ (respecting flavours) by the new constraint. This is done
+ by kickOutRewritable.
+
+ (B) Applies only to nominal equalities: a ~ ty. Four cases:
- Then, when adding:
+ [Representational] [G/W/D] a ~R ty:
+ Just add it to inert_eqs
- * [Derived] a ~N ty
- 1. Add (a~ty) to the model
- NB: 'a' cannot be in fv(ty), because the constraint is canonical.
+ [Derived Nominal] [D] a ~N ty:
+ 1. Add (a~ty) to the model
+ NB: 'a' cannot be in fv(ty), because the constraint is canonical.
- 2. (DShadow) Do emitDerivedShadows
- For every inert G/W constraint c, st
- (a) (a~ty) can rewrite c (see Note [Emitting shadow constraints]),
- and
- (b) the model cannot rewrite c
- kick out a Derived *copy*, leaving the original unchanged.
- Reason for (b) if the model can rewrite c, then we have already
- generated a shadow copy
+ 2. (DShadow) Do emitDerivedShadows
+ For every inert G/W constraint c, st
+ (a) (a~ty) can rewrite c (see Note [Emitting shadow constraints]),
+ and
+ (b) the model cannot rewrite c
+ kick out a Derived *copy*, leaving the original unchanged.
+ Reason for (b) if the model can rewrite c, then we have already
+ generated a shadow copy
- * [Given/Wanted] a ~N ty
+ [Given/Wanted Nominal] [G/W] a ~N ty:
1. Add it to inert_eqs
2. Emit [D] a~ty
- As a result of (2), the current model will rewrite the new [D] a~ty
- during canonicalisation, and then it'll be added to the model using
- the steps of [Derived] above.
+ Step (2) is needed to allow the current model to fully
+ rewrite [D] a~ty before adding it using the [Derived Nominal]
+ steps above.
- * [Representational equalities] a ~R ty: just add it to inert_eqs
+ We must do this even for Givens, because
+ work-item [G] a ~ [b], model has [D] b ~ a.
+ We need a shadow [D] a ~ [b] in the work-list
+ When we process it, we'll rewrite to a ~ [a] and get an occurs check
* Unifying a:=ty, is like adding [G] a~ty, but we can't make a [D]
@@ -1207,21 +1219,11 @@ add_inert_eq ics@(IC { inert_count = n
| ReprEq <- eq_rel
= return new_ics
--- | isGiven ev
--- = return (new_ics { inert_model = extendVarEnv old_model tv ct }) }
--- No no! E.g.
--- work-item [G] a ~ [b], model has [D] b ~ a.
--- We must not add the given to the model as-is. Instead,
--- we put a shadow [D] a ~ [b] in the work-list
--- When we process it, we'll rewrite to a ~ [a] and get an occurs check
-
| isDerived ev
= do { emitDerivedShadows ics tv
; return (ics { inert_model = extendVarEnv old_model tv ct }) }
- -- Nominal equality (tv ~N ty), Given/Wanted
- -- See Note [Emitting shadow constraints]
- | otherwise -- modelCanRewrite old_model rw_tvs -- Shadow of new ct isn't inert; emit it
+ | otherwise -- Given/Wanted Nominal equality [W] tv ~N ty
= do { emitNewDerived loc pred
; return new_ics }
where
@@ -1722,8 +1724,10 @@ getUnsolvedInerts
, inert_dicts = idicts
, inert_insols = insols
, inert_model = model } <- getInertCans
+ ; keep_derived <- keepSolvingDeriveds
- ; let der_tv_eqs = foldVarEnv (add_der tv_eqs) emptyCts model -- Want to float these
+ ; let der_tv_eqs = foldVarEnv (add_der_eq keep_derived tv_eqs)
+ emptyCts model
unsolved_tv_eqs = foldTyEqs add_if_unsolved tv_eqs der_tv_eqs
unsolved_fun_eqs = foldFunEqs add_if_unsolved fun_eqs emptyCts
unsolved_irreds = Bag.filterBag is_unsolved irreds
@@ -1743,8 +1747,10 @@ getUnsolvedInerts
-- Keep even the given insolubles
-- so that we can report dead GADT pattern match branches
where
- add_der tv_eqs ct cts
+ add_der_eq keep_derived tv_eqs ct cts
+ -- See Note [Unsolved Derived equalities]
| CTyEqCan { cc_tyvar = tv, cc_rhs = rhs } <- ct
+ , isMetaTyVar tv || keep_derived
, not (isInInertEqs tv_eqs tv rhs) = ct `consBag` cts
| otherwise = cts
add_if_unsolved :: Ct -> Cts -> Cts
@@ -1856,7 +1862,20 @@ prohibitedSuperClassSolve from_loc solve_loc
| otherwise
= False
-{-
+{- Note [Unsolved Derived equalities]
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+In getUnsolvedInerts, we return a derived equality from the model
+for two possible reasons:
+
+ * Because it is a candidate for floating out of this implication.
+ We only float equalities with a meta-tyvar on the left, so we only
+ pull those out here.
+
+ * If we are only solving derived constraints (i.e. tcs_need_derived
+ is true; see Note [Solving for Derived constraints]), then we
+ those Derived constraints are effectively unsolved, and we need
+ them!
+
Note [When does an implication have given equalities?]
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Consider an implication
@@ -2252,6 +2271,16 @@ All you can do is
Filling in a dictionary evidence variable means to create a binding
for it, so TcS carries a mutable location where the binding can be
added. This is initialised from the innermost implication constraint.
+
+Note [Solving for Derived constraints]
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+Sometimes we invoke the solver on a bunch of Derived constraints, not to
+generate any evidence, but just to cause unification side effects or to
+produce a simpler set of constraints. If that is what we are doing, we
+should do two things differently:
+ a) Don't stop when you've solved all the Wanteds; instead keep going
+ if there are any Deriveds in the work queue.
+ b) In getInertUnsolved, include Derived ones
-}
data TcSEnv
@@ -2277,9 +2306,8 @@ data TcSEnv
-- See also Note [Tracking redundant constraints] in TcSimplify
tcs_need_deriveds :: Bool
- -- should we keep trying to solve even if all the unsolved
- -- constraints are Derived? Usually False, but used whenever
- -- toDerivedWC is used.
+ -- Keep solving, even if all the unsolved constraints are Derived
+ -- See Note [Solving for Derived constraints]
}
---------------