summaryrefslogtreecommitdiff
path: root/compiler/typecheck/TcSimplify.lhs
diff options
context:
space:
mode:
Diffstat (limited to 'compiler/typecheck/TcSimplify.lhs')
-rw-r--r--compiler/typecheck/TcSimplify.lhs403
1 files changed, 159 insertions, 244 deletions
diff --git a/compiler/typecheck/TcSimplify.lhs b/compiler/typecheck/TcSimplify.lhs
index e6da56667e..b13fdedc14 100644
--- a/compiler/typecheck/TcSimplify.lhs
+++ b/compiler/typecheck/TcSimplify.lhs
@@ -19,15 +19,15 @@ import TcMType as TcM
import TcType
import TcSMonad as TcS
import TcInteract
-import Kind ( isKind, defaultKind_maybe )
+import Kind ( isKind, isSubKind, defaultKind_maybe )
import Inst
import Type ( classifyPredType, isIPClass, PredTree(..), getClassPredTys_maybe )
import TyCon ( isSynFamilyTyCon )
import Class ( Class )
+import Id ( idType )
import Var
import Unique
import VarSet
-import VarEnv
import TcEvidence
import Name
import Bag
@@ -60,7 +60,7 @@ simplifyTop :: WantedConstraints -> TcM (Bag EvBind)
-- in a degenerate implication, so we do that here instead
simplifyTop wanteds
= do { traceTc "simplifyTop {" $ text "wanted = " <+> ppr wanteds
- ; ev_binds_var <- newTcEvBinds
+ ; ev_binds_var <- TcM.newTcEvBinds
; zonked_final_wc <- solveWantedsTcMWithEvBinds ev_binds_var wanteds simpl_top
; binds1 <- TcRnMonad.getTcEvBinds ev_binds_var
; traceTc "End simplifyTop }" empty
@@ -74,7 +74,7 @@ simplifyTop wanteds
simpl_top :: WantedConstraints -> TcS WantedConstraints
-- See Note [Top-level Defaulting Plan]
simpl_top wanteds
- = do { wc_first_go <- nestTcS (solve_wanteds_and_drop wanteds)
+ = do { wc_first_go <- nestTcS (solveWantedsAndDrop wanteds)
-- This is where the main work happens
; try_tyvar_defaulting wc_first_go }
where
@@ -93,7 +93,7 @@ simpl_top wanteds
; if meta_tvs' == meta_tvs -- No defaulting took place;
-- (defaulting returns fresh vars)
then try_class_defaulting wc
- else do { wc_residual <- nestTcS (solve_wanteds_and_drop wc)
+ else do { wc_residual <- nestTcS (solveWantedsAndDrop wc)
-- See Note [Must simplify after defaulting]
; try_class_defaulting wc_residual } }
@@ -105,7 +105,7 @@ simpl_top wanteds
= do { something_happened <- applyDefaultingRules (approximateWC wc)
-- See Note [Top-level Defaulting Plan]
; if something_happened
- then do { wc_residual <- nestTcS (solve_wanteds_and_drop wc)
+ then do { wc_residual <- nestTcS (solveWantedsAndDrop wc)
; try_class_defaulting wc_residual }
else return wc }
\end{code}
@@ -191,7 +191,7 @@ More details in Note [DefaultTyVar].
simplifyAmbiguityCheck :: Type -> WantedConstraints -> TcM ()
simplifyAmbiguityCheck ty wanteds
= do { traceTc "simplifyAmbiguityCheck {" (text "type = " <+> ppr ty $$ text "wanted = " <+> ppr wanteds)
- ; ev_binds_var <- newTcEvBinds
+ ; ev_binds_var <- TcM.newTcEvBinds
; zonked_final_wc <- solveWantedsTcMWithEvBinds ev_binds_var wanteds simpl_top
; traceTc "End simplifyAmbiguityCheck }" empty
@@ -638,7 +638,7 @@ simplifyRule name lhs_wanted rhs_wanted
(resid_wanted, _) <- solveWantedsTcM (lhs_wanted `andWC` rhs_wanted)
-- Post: these are zonked and unflattened
- ; zonked_lhs_flats <- zonkCts (wc_flat lhs_wanted)
+ ; zonked_lhs_flats <- TcM.zonkFlats (wc_flat lhs_wanted)
; let (q_cts, non_q_cts) = partitionBag quantify_me zonked_lhs_flats
quantify_me -- Note [RULE quantification over equalities]
| insolubleWC resid_wanted = quantify_insol
@@ -730,7 +730,7 @@ solveWantedsTcMWithEvBinds :: EvBindsVar
solveWantedsTcMWithEvBinds ev_binds_var wc tcs_action
= do { traceTc "solveWantedsTcMWithEvBinds" $ text "wanted=" <+> ppr wc
; wc2 <- runTcSWithEvBinds ev_binds_var (tcs_action wc)
- ; zonkWC ev_binds_var wc2 }
+ ; zonkWC wc2 }
-- See Note [Zonk after solving]
solveWantedsTcM :: WantedConstraints -> TcM (WantedConstraints, Bag EvBind)
@@ -739,22 +739,22 @@ solveWantedsTcM :: WantedConstraints -> TcM (WantedConstraints, Bag EvBind)
-- Discards all Derived stuff in result
-- Postcondition: fully zonked and unflattened constraints
solveWantedsTcM wanted
- = do { ev_binds_var <- newTcEvBinds
- ; wanteds' <- solveWantedsTcMWithEvBinds ev_binds_var wanted solve_wanteds_and_drop
+ = do { ev_binds_var <- TcM.newTcEvBinds
+ ; wanteds' <- solveWantedsTcMWithEvBinds ev_binds_var wanted solveWantedsAndDrop
; binds <- TcRnMonad.getTcEvBinds ev_binds_var
; return (wanteds', binds) }
-solve_wanteds_and_drop :: WantedConstraints -> TcS (WantedConstraints)
--- Since solve_wanteds returns the residual WantedConstraints,
+solveWantedsAndDrop :: WantedConstraints -> TcS (WantedConstraints)
+-- Since solveWanteds returns the residual WantedConstraints,
-- it should always be called within a runTcS or something similar,
-solve_wanteds_and_drop wanted = do { wc <- solve_wanteds wanted
- ; return (dropDerivedWC wc) }
+solveWantedsAndDrop wanted = do { wc <- solveWanteds wanted
+ ; return (dropDerivedWC wc) }
-solve_wanteds :: WantedConstraints -> TcS WantedConstraints
+solveWanteds :: WantedConstraints -> TcS WantedConstraints
-- so that the inert set doesn't mindlessly propagate.
-- NB: wc_flats may be wanted /or/ derived now
-solve_wanteds wanted@(WC { wc_flat = flats, wc_impl = implics, wc_insol = insols })
- = do { traceTcS "solveWanteds {" (ppr wanted)
+solveWanteds wanteds
+ = do { traceTcS "solveWanteds {" (ppr wanteds)
-- Try the flat bit, including insolubles. Solving insolubles a
-- second time round is a bit of a waste; but the code is simple
@@ -762,57 +762,63 @@ solve_wanteds wanted@(WC { wc_flat = flats, wc_impl = implics, wc_insol = insols
-- of adding Derived insolubles twice; see
-- TcSMonad Note [Do not add duplicate derived insolubles]
; traceTcS "solveFlats {" empty
- ; let all_flats = flats `unionBags` filterBag (not . isDerivedCt) insols
- -- See Note [Dropping derived constraints] in TcRnTypes for
- -- why the insolubles may have derived constraints
-
- ; impls_from_flats <- solveInteract all_flats
- ; traceTcS "solveFlats end }" (ppr impls_from_flats)
-
- -- solve_wanteds iterates when it is able to float equalities
- -- out of one or more of the implications.
- ; unsolved_implics <- simpl_loop 1 (implics `unionBags` impls_from_flats)
-
- ; (unsolved_flats, insoluble_flats) <- getInertUnsolved
+ ; solved_flats_wanteds <- solveFlats wanteds
+ ; traceTcS "solveFlats end }" (ppr solved_flats_wanteds)
- -- We used to unflatten here but now we only do it once at top-level
- -- during zonking -- see Note [Unflattening while zonking] in TcMType
- ; let wc = WC { wc_flat = unsolved_flats
- , wc_impl = unsolved_implics
- , wc_insol = insoluble_flats }
+ -- solveWanteds iterates when it is able to float equalities
+ -- equalities out of one or more of the implications.
+ ; final_wanteds <- simpl_loop 1 solved_flats_wanteds
; bb <- getTcEvBindsMap
- ; tb <- getTcSTyBindsMap
; traceTcS "solveWanteds }" $
- vcat [ text "unsolved_flats =" <+> ppr unsolved_flats
- , text "unsolved_implics =" <+> ppr unsolved_implics
- , text "current evbinds =" <+> ppr (evBindMapBinds bb)
- , text "current tybinds =" <+> vcat (map ppr (varEnvElts tb))
- , text "final wc =" <+> ppr wc ]
-
- ; return wc }
+ vcat [ text "final wc =" <+> ppr final_wanteds
+ , text "current evbinds =" <+> ppr (evBindMapBinds bb) ]
+
+ ; return final_wanteds }
+
+solveFlats :: WantedConstraints -> TcS WantedConstraints
+-- Solve the wc_flat and wc_insol components of the WantedConstraints
+-- Do not affect the inerts
+solveFlats (WC { wc_flat = flats, wc_insol = insols, wc_impl = implics })
+ = nestTcS $
+ do { let all_flats = flats `unionBags` filterBag (not . isDerivedCt) insols
+ -- See Note [Dropping derived constraints] in TcRnTypes for
+ -- why the insolubles may have derived constraints
+ ; wc <- solveFlatWanteds all_flats
+ ; return ( wc { wc_impl = implics `unionBags` wc_impl wc } ) }
simpl_loop :: Int
- -> Bag Implication
- -> TcS (Bag Implication)
-simpl_loop n implics
+ -> WantedConstraints
+ -> TcS WantedConstraints
+simpl_loop n wanteds@(WC { wc_flat = flats, wc_insol = insols, wc_impl = implics })
| n > 10
- = traceTcS "solveWanteds: loop!" empty >> return implics
+ = do { traceTcS "solveWanteds: loop!" empty
+ ; return wanteds }
+
| otherwise
= do { traceTcS "simpl_loop, iteration" (int n)
; (floated_eqs, unsolved_implics) <- solveNestedImplications implics
+
; if isEmptyBag floated_eqs
- then return unsolved_implics
+ then return (wanteds { wc_impl = unsolved_implics })
else
+
do { -- Put floated_eqs into the current inert set before looping
- (unifs_happened, impls_from_eqs) <- reportUnifications $
- solveInteract floated_eqs
- ; if -- See Note [Cutting off simpl_loop]
- isEmptyBag impls_from_eqs &&
- not unifs_happened && -- (a)
- not (anyBag isCFunEqCan floated_eqs) -- (b)
- then return unsolved_implics
- else simpl_loop (n+1) (unsolved_implics `unionBags` impls_from_eqs) } }
+ (unifs_happened, solve_flat_res)
+ <- reportUnifications $
+ solveFlats (WC { wc_flat = floated_eqs `unionBags` flats
+ -- Put floated_eqs first so they get solved first
+ , wc_insol = emptyBag, wc_impl = emptyBag })
+
+ ; let new_wanteds = solve_flat_res `andWC`
+ WC { wc_flat = emptyBag
+ , wc_insol = insols
+ , wc_impl = unsolved_implics }
+
+ ; if not unifs_happened -- See Note [Cutting off simpl_loop]
+ && isEmptyBag (wc_impl solve_flat_res)
+ then return new_wanteds
+ else simpl_loop (n+1) new_wanteds } }
solveNestedImplications :: Bag Implication
-> TcS (Cts, Bag Implication)
@@ -822,16 +828,17 @@ solveNestedImplications implics
| isEmptyBag implics
= return (emptyBag, emptyBag)
| otherwise
- = do { inerts <- getTcSInerts
- ; let thinner_inerts = prepareInertsForImplications inerts
- -- See Note [Preparing inert set for implications]
-
- ; traceTcS "solveNestedImplications starting {" $
- vcat [ text "original inerts = " <+> ppr inerts
- , text "thinner_inerts = " <+> ppr thinner_inerts ]
+ = do {
+-- inerts <- getTcSInerts
+-- ; let thinner_inerts = prepareInertsForImplications inerts
+-- -- See Note [Preparing inert set for implications]
+--
+ traceTcS "solveNestedImplications starting {" empty
+-- vcat [ text "original inerts = " <+> ppr inerts
+-- , text "thinner_inerts = " <+> ppr thinner_inerts ]
; (floated_eqs, unsolved_implics)
- <- flatMapBagPairM (solveImplication thinner_inerts) implics
+ <- flatMapBagPairM solveImplication implics
-- ... and we are back in the original TcS inerts
-- Notice that the original includes the _insoluble_flats so it was safe to ignore
@@ -842,45 +849,45 @@ solveNestedImplications implics
; return (floated_eqs, unsolved_implics) }
-solveImplication :: InertSet
- -> Implication -- Wanted
+solveImplication :: Implication -- Wanted
-> TcS (Cts, -- All wanted or derived floated equalities: var = type
Bag Implication) -- Unsolved rest (always empty or singleton)
-- Precondition: The TcS monad contains an empty worklist and given-only inerts
-- which after trying to solve this implication we must restore to their original value
-solveImplication inerts
- imp@(Implic { ic_untch = untch
- , ic_binds = ev_binds
- , ic_skols = skols
- , ic_fsks = old_fsks
- , ic_given = givens
- , ic_wanted = wanteds
- , ic_info = info
- , ic_env = env })
- = do { traceTcS "solveImplication {" (ppr imp)
+solveImplication imp@(Implic { ic_untch = untch
+ , ic_binds = ev_binds
+ , ic_skols = skols
+ , ic_given = givens
+ , ic_wanted = wanteds
+ , ic_info = info
+ , ic_env = env })
+ = do { inerts <- getTcSInerts
+ ; traceTcS "solveImplication {" (ppr imp $$ text "Inerts" <+> ppr inerts)
-- Solve the nested constraints
- ; (no_given_eqs, new_fsks, residual_wanted)
- <- nestImplicTcS ev_binds untch inerts $
- do { (no_eqs, new_fsks) <- solveInteractGiven (mkGivenLoc info env)
- old_fsks givens
+ ; (no_given_eqs, residual_wanted)
+ <- nestImplicTcS ev_binds untch $
+ do { solveFlatGivens (mkGivenLoc untch info env) givens
- ; residual_wanted <- solve_wanteds wanteds
- -- solve_wanteds, *not* solve_wanteds_and_drop, because
+ ; residual_wanted <- solveWanteds wanteds
+ -- solveWanteds, *not* solveWantedsAndDrop, because
-- we want to retain derived equalities so we can float
-- them out in floatEqualities
- ; return (no_eqs, new_fsks, residual_wanted) }
+ ; no_eqs <- getNoGivenEqs untch skols
+
+ ; return (no_eqs, residual_wanted) }
; (floated_eqs, final_wanted)
- <- floatEqualities (skols ++ new_fsks) no_given_eqs residual_wanted
+ <- floatEqualities skols no_given_eqs residual_wanted
- ; let res_implic | isEmptyWC final_wanted && no_given_eqs
+ ; let res_implic | isEmptyWC final_wanted -- && no_given_eqs
= emptyBag -- Reason for the no_given_eqs: we don't want to
-- lose the "inaccessible code" error message
+ -- BUT: final_wanted still has the derived insolubles
+ -- so it should be fine
| otherwise
- = unitBag (imp { ic_fsks = new_fsks
- , ic_no_eqs = no_given_eqs
+ = unitBag (imp { ic_no_eqs = no_given_eqs
, ic_wanted = dropDerivedWC final_wanted
, ic_insol = insolubleWC final_wanted })
@@ -888,7 +895,6 @@ solveImplication inerts
; traceTcS "solveImplication end }" $ vcat
[ text "no_given_eqs =" <+> ppr no_given_eqs
, text "floated_eqs =" <+> ppr floated_eqs
- , text "new_fsks =" <+> ppr new_fsks
, text "res_implic =" <+> ppr res_implic
, text "implication evbinds = " <+> ppr (evBindMapBinds evbinds) ]
@@ -998,7 +1004,6 @@ approximateWC wc
= emptyCts -- See Note [ApproximateWC]
where
new_trapping_tvs = trapping_tvs `extendVarSetList` ic_skols imp
- `extendVarSetList` ic_fsks imp
do_bag :: (a -> Bag c) -> Bag a -> Bag c
do_bag f = foldrBag (unionBags.f) emptyBag
\end{code}
@@ -1129,7 +1134,6 @@ beta! Concrete example is in indexed_types/should_fail/ExtraTcsUntch.hs:
data TEx where
TEx :: a -> TEx
-
f (x::beta) =
let g1 :: forall b. b -> ()
g1 _ = h [x]
@@ -1137,7 +1141,6 @@ beta! Concrete example is in indexed_types/should_fail/ExtraTcsUntch.hs:
in (g1 '3', g2 undefined)
-
Note [Solving Family Equations]
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
After we are done with simplification we may be left with constraints of the form:
@@ -1213,112 +1216,74 @@ Consequence: classes with functional dependencies don't matter (since there is
no evidence for a fundep equality), but equality superclasses do matter (since
they carry evidence).
+
\begin{code}
-floatEqualities :: [TcTyVar] -> Bool -> WantedConstraints
+floatEqualities :: [TcTyVar] -> Bool
+ -> WantedConstraints
-> TcS (Cts, WantedConstraints)
-- Main idea: see Note [Float Equalities out of Implications]
--
--- Post: The returned floated constraints (Cts) are only Wanted or Derived
--- and come from the input wanted ev vars or deriveds
+-- Precondition: the wc_flat of the incoming WantedConstraints are
+-- fully zonked, so that we can see their free variables
+--
+-- Postcondition: The returned floated constraints (Cts) are only
+-- Wanted or Derived and come from the input wanted
+-- ev vars or deriveds
+--
-- Also performs some unifications (via promoteTyVar), adding to
-- monadically-carried ty_binds. These will be used when processing
-- floated_eqs later
--
-- Subtleties: Note [Float equalities from under a skolem binding]
-- Note [Skolem escape]
-floatEqualities skols no_given_eqs wanteds@(WC { wc_flat = flats, wc_insol = insols })
+floatEqualities skols no_given_eqs wanteds@(WC { wc_flat = flats })
| not no_given_eqs -- There are some given equalities, so don't float
= return (emptyBag, wanteds) -- Note [Float Equalities out of Implications]
- | not (isEmptyBag insols)
- = return (emptyBag, wanteds) -- Note [Do not float equalities if there are insolubles]
| otherwise
- = do { let (float_eqs, remaining_flats) = partitionBag is_floatable flats
- ; untch <- TcS.getUntouchables
- ; mapM_ (promoteTyVar untch) (varSetElems (tyVarsOfCts float_eqs))
+ = do { outer_untch <- TcS.getUntouchables
+ ; mapM_ (promoteTyVar outer_untch) (varSetElems (tyVarsOfCts float_eqs))
-- See Note [Promoting unification variables]
- ; ty_binds <- getTcSTyBindsMap
; traceTcS "floatEqualities" (vcat [ text "Skols =" <+> ppr skols
, text "Flats =" <+> ppr flats
- , text "Skol set =" <+> ppr skol_set
- , text "Floated eqs =" <+> ppr float_eqs
- , text "Ty binds =" <+> ppr ty_binds])
+ , text "Floated eqs =" <+> ppr float_eqs ])
; return (float_eqs, wanteds { wc_flat = remaining_flats }) }
where
- is_floatable :: Ct -> Bool
- is_floatable ct
- = case classifyPredType (ctPred ct) of
- EqPred ty1 ty2 -> skol_set `disjointVarSet` tyVarsOfType ty1
- && skol_set `disjointVarSet` tyVarsOfType ty2
- _ -> False
-
- skol_set = fixVarSet mk_next (mkVarSet skols)
- mk_next tvs = foldr grow_one tvs flat_eqs
- flat_eqs :: [(TcTyVarSet, TcTyVarSet)]
- flat_eqs = [ (tyVarsOfType ty1, tyVarsOfType ty2)
- | EqPred ty1 ty2 <- map (classifyPredType . ctPred) (bagToList flats)]
- grow_one (tvs1,tvs2) tvs
- | intersectsVarSet tvs tvs1 = tvs `unionVarSet` tvs2
- | intersectsVarSet tvs tvs2 = tvs `unionVarSet` tvs2
- | otherwise = tvs
+ skol_set = mkVarSet skols
+ (float_eqs, remaining_flats) = partitionBag float_me flats
+
+ float_me :: Ct -> Bool
+ float_me ct -- The constraint is un-flattened and de-cannonicalised
+ | let pred = ctPred ct
+ , EqPred ty1 ty2 <- classifyPredType pred
+ , tyVarsOfType pred `disjointVarSet` skol_set
+ , useful_to_float ty1 ty2
+ = True
+ | otherwise
+ = False
+
+ -- Float out alpha ~ ty, or ty ~ alpha
+ -- which might be unified outside
+ -- See Note [Do not float kind-incompatible equalities]
+ useful_to_float ty1 ty2
+ = case (tcGetTyVar_maybe ty1, tcGetTyVar_maybe ty2) of
+ (Just tv1, _) | isMetaTyVar tv1
+ , k2 `isSubKind` k1
+ -> True
+ (_, Just tv2) | isMetaTyVar tv2
+ , k1 `isSubKind` k2
+ -> True
+ _ -> False
+ where
+ k1 = typeKind ty1
+ k2 = typeKind ty2
\end{code}
-Note [Do not float equalities if there are insolubles]
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+Note [Do not float kind-incompatible equalities]
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
If we have (t::* ~ s::*->*), we'll get a Derived insoluble equality.
If we float the equality outwards, we'll get *another* Derived
insoluble equality one level out, so the same error will be reported
-twice. However, the equality is insoluble anyway, and when there are
-any insolubles we report only them, so there is no point in floating.
-
-
-Note [When does an implication have given equalities?]
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- NB: This note is mainly referred to from TcSMonad
- but it relates to floating equalities, so I've
- left it here
-
-Consider an implication
- beta => alpha ~ Int
-where beta is a unification variable that has already been unified
-to () in an outer scope. Then we can float the (alpha ~ Int) out
-just fine. So when deciding whether the givens contain an equality,
-we should canonicalise first, rather than just looking at the original
-givens (Trac #8644).
-
-This is the entire reason for the inert_no_eqs field in InertCans.
-We initialise it to False before processing the Givens of an implication;
-and set it to True when adding an inert equality in addInertCan.
-
-However, when flattening givens, we generate given equalities like
- <F [a]> : F [a] ~ f,
-with Refl evidence, and we *don't* want those to count as an equality
-in the givens! After all, the entire flattening business is just an
-internal matter, and the evidence does not mention any of the 'givens'
-of this implication.
-
-So we set the flag to False when adding an equality
-(TcSMonad.addInertCan) whose evidence whose CtOrigin is
-FlatSkolOrigin; see TcSMonad.isFlatSkolEv. Note that we may transform
-the original flat-skol equality before adding it to the inerts, so
-it's important that the transformation preserves origin (which
-xCtEvidence and rewriteEvidence both do). Example
- instance F [a] = Maybe a
- implication: C (F [a]) => blah
- We flatten (C (F [a])) to C fsk, with <F [a]> : F [a] ~ fsk
- Then we reduce the F [a] LHS, giving
- g22 = ax7 ; <F [a]>
- g22 : Maybe a ~ fsk
- And before adding g22 we'll re-orient it to an ordinary tyvar
- equality. None of this should count as "adding a given equality".
- This really happens (Trac #8651).
-
-An alternative we considered was to
- * Accumulate the new inert equalities (in TcSMonad.addInertCan)
- * In solveInteractGiven, check whether the evidence for the new
- equalities mentions any of the ic_givens of this implication.
-This seems like the Right Thing, but it's more code, and more work
-at runtime, so we are using the FlatSkolOrigin idea intead. It's less
-obvious that it works, but I think it does, and it's simple and efficient.
+twice. So we refrain from floating such equalities
Note [Float equalities from under a skolem binding]
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
@@ -1327,72 +1292,21 @@ ones that don't mention the skolem-bound variables. But that is
over-eager. Consider
[2] forall a. F a beta[1] ~ gamma[2], G beta[1] gamma[2] ~ Int
The second constraint doesn't mention 'a'. But if we float it
-we'll promote gamma to gamma'[1]. Now suppose that we learn that
+we'll promote gamma[2] to gamma'[1]. Now suppose that we learn that
beta := Bool, and F a Bool = a, and G Bool _ = Int. Then we'll
we left with the constraint
[2] forall a. a ~ gamma'[1]
which is insoluble because gamma became untouchable.
-Solution: only promote a constraint if its free variables cannot
-possibly be connected with the skolems. Procedurally, start with
-the skolems and "grow" that set as follows:
- * For each flat equality F ts ~ s, or tv ~ s,
- if the current set intersects with the LHS of the equality,
- add the free vars of the RHS, and vice versa
-That gives us a grown skolem set. Now float an equality if its free
-vars don't intersect the grown skolem set.
-
-This seems very ad hoc (sigh). But here are some tricky edge cases:
-
-a) [2]forall a. (F a delta[1] ~ beta[2], delta[1] ~ Maybe beta[2])
-b1) [2]forall a. (F a ty ~ beta[2], G beta[2] ~ gamma[2])
-b2) [2]forall a. (a ~ beta[2], G beta[2] ~ gamma[2])
-c) [2]forall a. (F a ty ~ beta[2], delta[1] ~ Maybe beta[2])
-d) [2]forall a. (gamma[1] ~ Tree beta[2], F ty ~ beta[2])
-
-In (a) we *must* float out the second equality,
- else we can't solve at all (Trac #7804).
-
-In (b1, b2) we *must not* float out the second equality.
- It will ultimately be solved (by flattening) in situ, but if we float
- it we'll promote beta,gamma, and render the first equality insoluble.
-
- Trac #9316 was an example of (b2). You may wonder why (a ~ beta[2]) isn't
- solved; in #9316 it wasn't solved because (a:*) and (beta:kappa[1]), so the
- equality was kind-mismatched, and hence was a CIrredEvCan. There was
- another equality alongside, (kappa[1] ~ *). We must first float *that*
- one out and *then* we can solve (a ~ beta).
-
-In (c) it would be OK to float the second equality but better not to.
- If we flatten we see (delta[1] ~ Maybe (F a ty)), which is a
- skolem-escape problem. If we float the second equality we'll
- end up with (F a ty ~ beta'[1]), which is a less explicable error.
-
-In (d) we must float the first equality, so that we can unify gamma.
- But that promotes beta, so we must float the second equality too,
- Trac #7196 exhibits this case
-
-Some notes
-
-* When "growing", do not simply take the free vars of the predicate!
- Example [2]forall a. (a:* ~ beta[2]:kappa[1]), (kappa[1] ~ *)
- We must float the second, and we must not float the first.
- But the first actually looks like ((~) kappa a beta), so if we just
- look at its free variables we'll see {a,kappa,beta), and that might
- make us think kappa should be in the grown skol set.
-
- (In any case, the kind argument for a kind-mis-matched equality like
- this one doesn't really make sense anyway.)
-
- That's why we use classifyPred when growing.
-
-* Previously we tried to "grow" the skol_set with *all* the
- constraints (not just equalities), to get all the tyvars that could
- *conceivably* unify with the skolems, but that was far too
- conservative (Trac #7804). Example: this should be fine:
- f :: (forall a. a -> Proxy x -> Proxy (F x)) -> Int
- f = error "Urk" :: (forall a. a -> Proxy x -> Proxy (F x)) -> Int
+Solution: float only constraints that stand a jolly good chance of
+being soluble simply by being floated, namely ones of form
+ a ~ ty
+where 'a' is a currently-untouchable unification variable, but may
+become touchable by being floated (perhaps by more than one level).
+We had a very complicated rule previously, but this is nice and
+simple. (To see the notes, look at this Note in a version of
+TcSimplify prior to Oct 2014).
Note [Skolem escape]
~~~~~~~~~~~~~~~~~~~~
@@ -1510,15 +1424,13 @@ disambigGroup [] _grp
= return False
disambigGroup (default_ty:default_tys) group
= do { traceTcS "disambigGroup {" (ppr group $$ ppr default_ty)
- ; success <- tryTcS $ -- Why tryTcS? If this attempt fails, we want to
- -- discard all side effects from the attempt
- do { setWantedTyBind the_tv default_ty
- ; implics_from_defaulting <- solveInteract wanteds
- ; MASSERT(isEmptyBag implics_from_defaulting)
- -- I am not certain if any implications can be generated
- -- but I am letting this fail aggressively if this ever happens.
-
- ; checkAllSolved }
+ ; fake_ev_binds_var <- TcS.newTcEvBinds
+ ; given_ev_var <- TcS.newEvVar (mkTcEqPred (mkTyVarTy the_tv) default_ty)
+ ; untch <- TcS.getUntouchables
+ ; success <- nestImplicTcS fake_ev_binds_var (pushUntouchables untch) $
+ do { solveFlatGivens loc [given_ev_var]
+ ; residual_wanted <- solveFlatWanteds wanteds
+ ; return (isEmptyWC residual_wanted) }
; if success then
-- Success: record the type variable binding, and return
@@ -1532,8 +1444,11 @@ disambigGroup (default_ty:default_tys) group
(ppr default_ty)
; disambigGroup default_tys group } }
where
- ((_,_,the_tv):_) = group
wanteds = listToBag (map fstOf3 group)
+ ((_,_,the_tv):_) = group
+ loc = CtLoc { ctl_origin = GivenOrigin UnkSkol
+ , ctl_env = panic "disambigGroup:env"
+ , ctl_depth = initialSubGoalDepth }
\end{code}
Note [Avoiding spurious errors]