summaryrefslogtreecommitdiff
path: root/compiler/GHC/Tc/Solver/Dict.hs
diff options
context:
space:
mode:
Diffstat (limited to 'compiler/GHC/Tc/Solver/Dict.hs')
-rw-r--r--compiler/GHC/Tc/Solver/Dict.hs105
1 files changed, 75 insertions, 30 deletions
diff --git a/compiler/GHC/Tc/Solver/Dict.hs b/compiler/GHC/Tc/Solver/Dict.hs
index a329711cad..558ff24002 100644
--- a/compiler/GHC/Tc/Solver/Dict.hs
+++ b/compiler/GHC/Tc/Solver/Dict.hs
@@ -10,9 +10,8 @@ module GHC.Tc.Solver.Dict (
import GHC.Prelude
import GHC.Tc.Errors.Types
-import GHC.Tc.Utils.TcType
import GHC.Tc.Instance.FunDeps
-import GHC.Tc.Instance.Class( safeOverlap )
+import GHC.Tc.Instance.Class( safeOverlap, matchEqualityInst )
import GHC.Tc.Types.Evidence
import GHC.Tc.Types.Constraint
import GHC.Tc.Types.Origin
@@ -20,6 +19,8 @@ import GHC.Tc.Types.EvTerm( evCallStack )
import GHC.Tc.Solver.InertSet
import GHC.Tc.Solver.Monad
import GHC.Tc.Solver.Types
+import GHC.Tc.Utils.TcType
+import GHC.Tc.Utils.Unify( uType )
import GHC.Hs.Type( HsIPName(..) )
@@ -53,6 +54,7 @@ import GHC.Driver.Session
import qualified GHC.LanguageExtensions as LangExt
import Data.Maybe ( listToMaybe, mapMaybe, isJust )
+import Data.Void( Void )
import Control.Monad.Trans.Maybe( MaybeT, runMaybeT )
import Control.Monad.Trans.Class( lift )
@@ -65,15 +67,27 @@ import Control.Monad( mzero, when )
* *
********************************************************************* -}
-solveDictNC :: CtEvidence -> Class -> [Type] -> SolverStage ()
+{- Note [Solving equality classes]
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+We have a special solver for the "equality classes"
+ (t1 ~ t2), (t1 ~~ t2), and (Coercible t1 t2)
+
+ TODO: expand this Note
+-}
+
+solveDictNC :: CtEvidence -> Class -> [Type] -> SolverStage Void
-- NC: this comes from CNonCanonical or CIrredCan
-- Precondition: already rewritten by inert set
solveDictNC ev cls tys
+ | isEqualityClass cls
+ = solveEqualityDict ev cls tys
+
+ | otherwise
= do { simpleStage $ traceTcS "solveDictNC" (ppr (mkClassPred cls tys) $$ ppr ev)
; dict_ct <- canDictCt ev cls tys
; solveDict dict_ct }
-solveDict :: DictCt -> SolverStage ()
+solveDict :: DictCt -> SolverStage Void
-- Preconditions: `tys` are already rewritten by the inert set
solveDict dict_ct@(DictCt { di_ev = ev, di_cls = cls, di_tys = tys })
= assertPpr (ctEvRole ev == Nominal) (ppr ev $$ ppr cls $$ ppr tys) $
@@ -96,7 +110,7 @@ solveDict dict_ct@(DictCt { di_ev = ev, di_cls = cls, di_tys = tys })
updInertDicts :: DictCt -> TcS ()
updInertDicts dict_ct@(DictCt { di_cls = cls, di_ev = ev })
- = do { -- See [Kick out existing binding for implicit parameter]
+ = do { -- See Note [Shadowing of Implicit Parameters]
; when (isGiven ev && isIPClass cls) $
updInertCans (updDicts (delIPDict dict_ct))
@@ -113,19 +127,10 @@ canDictCt ev cls tys
do { dflags <- getDynFlags
; sc_cts <- mkStrictSuperClasses (givensFuel dflags) ev [] [] cls tys
-- givensFuel dflags: See Note [Expanding Recursive Superclasses and ExpansionFuel]
+ ; emitWork (listToBag sc_cts)
- -- For equality classes, /replace/ the current constraint with its
- -- superclasses, rather than /adding/ them.
- -- See (NC1) in Note [Naturally coherent classes]
- ; if isEqualityClass cls
- then case sc_cts of
- [ct] -> startAgainWith ct
- _ -> pprPanic "canDictCt" (ppr cls)
- else
-
- do { emitWork (listToBag sc_cts)
; continueWith (DictCt { di_ev = ev, di_cls = cls
- , di_tys = tys, di_pend_sc = doNotExpand }) } }
+ , di_tys = tys, di_pend_sc = doNotExpand }) }
-- doNotExpand: We have already expanded superclasses for /this/ dict
-- so set the fuel to doNotExpand to avoid repeating expansion
@@ -183,10 +188,17 @@ solveCallStack ev ev_cs
; setEvBindIfWanted ev IsCoherent ev_tm }
-{- Note [Kick out existing binding for implicit parameter]
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+{- Note [Shadowing of Implicit Parameters]
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
When we add a new /given/ implicit parameter to the inert set, it /replaces/
-any existing givens for the same implicit parameter.
+any existing givens for the same implicit parameter. This makes a difference
+in two places:
+
+* In `GHC.Tc.Solver.InertSet.solveOneFromTheOther`, be careful when we have
+ (?x :: ty) in the inert set and an identical (?x :: ty) as the work item.
+
+* In `updInertDicts` in this module, when adding [G] (?x :: ty), remove any
+ existing [G] (?x :: ty'), regardless of ty'
Example 1:
@@ -265,6 +277,37 @@ I can think of two ways to fix this:
{- ******************************************************************************
* *
+ solveEqualityDict
+* *
+****************************************************************************** -}
+
+solveEqualityDict :: CtEvidence -> Class -> [Type] -> SolverStage Void
+-- Precondition: (isEqualityClass cls) True, so cls is (~), (~~), or Coercible
+solveEqualityDict ev cls tys
+ | CtWanted { ctev_dest = dest } <- ev
+ = Stage $
+ do { let (data_con, role, t1, t2) = matchEqualityInst cls tys
+ -- Unify t1~t2, putting anything that can't be solved
+ -- immediately into the work list
+ ; (co, _, _) <- wrapUnifierTcS ev role $ \uenv ->
+ uType uenv t1 t2
+ -- Set d :: (t1~t2) = Eq# co
+ ; setWantedEvTerm dest IsCoherent $
+ evDataConApp data_con tys [Coercion co]
+ ; stopWith ev "Solved wanted lifted equality" }
+
+ | CtGiven { ctev_evar = ev_id, ctev_loc = loc } <- ev
+ , [sel_id] <- classSCSelIds cls -- Equality classes have just one superclass
+ = Stage $
+ do { let sc_pred = classMethodInstTy sel_id tys
+ ev_expr = EvExpr $ Var sel_id `mkTyApps` tys `App` evId ev_id
+ ; given_ev <- newGivenEvVar loc (sc_pred, ev_expr)
+ ; startAgainWith (mkNonCanonical given_ev) }
+ | otherwise
+ = pprPanic "solveEqualityDict" (ppr cls)
+
+{- ******************************************************************************
+* *
interactDict
* *
*********************************************************************************
@@ -770,7 +813,6 @@ matchClassInst dflags inerts clas tys loc
-- whether top level, or local quantified constraints.
-- See Note [Instance and Given overlap]
| not (xopt LangExt.IncoherentInstances dflags)
- , not (naturallyCoherentClass clas) -- See (NC3) in Note [Naturally coherent classes]
, not (noMatchableGivenDicts inerts loc clas tys)
= do { traceTcS "Delaying instance application" $
vcat [ text "Work item=" <+> pprClassPred clas tys ]
@@ -796,6 +838,7 @@ matchClassInst dflags inerts clas tys loc
where
pred = mkClassPred clas tys
+{-
-- | If a class is "naturally coherent", then we needn't worry at all, in any
-- way, about overlapping/incoherent instances. Just solve the thing!
-- See Note [Naturally coherent classes]
@@ -803,6 +846,7 @@ matchClassInst dflags inerts clas tys loc
naturallyCoherentClass :: Class -> Bool
naturallyCoherentClass cls
= isCTupleClass cls || isEqualityClass cls
+-}
isEqualityClass :: Class -> Bool
-- True of (~), (~~), and Coercible
@@ -903,14 +947,15 @@ this:
(See Note [The equality types story] in GHC.Builtin.Types.Prim.)
PS: the term "naturally coherent" doesn't really seem helpful.
-Perhaps "invertible" or something? I left it for now though.
+Perhaps "invertible" or "bidirectional" or something? I left it for
+now though.
For naturally coherent classes:
-(NC1) For Givens, when expanding superclasses, we /replace/ the constraint
- with its superclasses (which, remember, are equally powerful) rather than
- /adding/ them. This can make a huge difference. Consider T17836, which
- has a constraint like
+(NC1) For Givens, when expanding the superclasses of a naturally coherent class,
+ we can /replace/ the constraint with its superclasses (which, remember, are
+ equally powerful) rather than /adding/ them. This can make a huge difference.
+ Consider T17836, which has a constraint like
forall b,c. a ~ (b,c) =>
forall d,e. c ~ (d,e) =>
...etc...
@@ -923,7 +968,7 @@ For naturally coherent classes:
Originally I tried this for all naturally-coherent classes, including
tuples. But discarding the tuple Given (which "replacing" does) means that
we may have to reconstruct it for a recursive call, and the optimiser isn't
- quite clever enought to figure that out: see #10359 and its test case.
+ quite clever enough to figure that out: see #10359 and its test case.
This is less pressing for equality classes because they have to be unpacked
strictly, so CSE-ing away the reconstuction works fine. Hence the use
of isEqualityClass rather than naturallyCoherentClass in canDictCt.
@@ -944,7 +989,7 @@ For naturally coherent classes:
so the reduction of the [W] constraint does not risk losing any solutions.
On the other hand, it can be fatal to /fail/ to reduce such equalities
- on the grounds of Note [Instance and Given overlap], fbecause many good
+ on the grounds of Note [Instance and Given overlap], because many good
things flow from [W] t1 ~# t2.
The same reasoning applies to
@@ -1923,8 +1968,8 @@ mk_strict_superclasses fuel rec_clss ev@(CtGiven { ctev_evar = evar, ctev_loc =
| otherwise
= do { given_ev <- newGivenEvVar sc_loc $
mk_given_desc sel_id sc_pred
- ; assertFuelPrecondition fuel
- $ mk_superclasses fuel rec_clss given_ev tvs theta sc_pred }
+ ; assertFuelPrecondition fuel $
+ mk_superclasses fuel rec_clss given_ev tvs theta sc_pred }
where
sc_pred = classMethodInstTy sel_id tys
@@ -1952,7 +1997,7 @@ mk_strict_superclasses fuel rec_clss ev@(CtGiven { ctev_evar = evar, ctev_loc =
`App` (evId evar `mkVarApps` (tvs ++ dict_ids))
`mkVarApps` sc_tvs
- sc_loc | naturallyCoherentClass cls
+ sc_loc | isCTupleClass cls
= loc -- See (NC2) in Note [Naturally coherent classes]
| otherwise
= loc { ctl_origin = mk_sc_origin (ctLocOrigin loc) }