diff options
author | Simon Peyton Jones <simon.peytonjones@gmail.com> | 2023-05-06 18:48:31 +0100 |
---|---|---|
committer | Simon Peyton Jones <simon.peytonjones@gmail.com> | 2023-05-06 18:48:31 +0100 |
commit | 375dde8784f3dc36cdf5eff212b856134863fa1e (patch) | |
tree | d2f51d4db1eaf4af0cdda1d56045769ef5e519c5 | |
parent | 514ed18884cf6d52ebc06a91e7c4729e6f91db7a (diff) | |
download | haskell-375dde8784f3dc36cdf5eff212b856134863fa1e.tar.gz |
Add the SolverStage monad
This refactoring makes a substantial improvement in the
structure of GHC.Tc.Solver.Equality.
I also added the new type IrredCt (akin to EqCt).
Still to come: DictCt.
-rw-r--r-- | compiler/GHC/Tc/Errors.hs | 5 | ||||
-rw-r--r-- | compiler/GHC/Tc/Solver/Canonical.hs | 31 | ||||
-rw-r--r-- | compiler/GHC/Tc/Solver/Dict.hs | 2 | ||||
-rw-r--r-- | compiler/GHC/Tc/Solver/Equality.hs | 511 | ||||
-rw-r--r-- | compiler/GHC/Tc/Solver/InertSet.hs | 94 | ||||
-rw-r--r-- | compiler/GHC/Tc/Solver/Interact.hs | 107 | ||||
-rw-r--r-- | compiler/GHC/Tc/Solver/Monad.hs | 85 | ||||
-rw-r--r-- | compiler/GHC/Tc/Solver/Rewrite.hs | 6 | ||||
-rw-r--r-- | compiler/GHC/Tc/Types/Constraint.hs | 110 | ||||
-rw-r--r-- | compiler/GHC/Tc/Utils/Monad.hs | 8 | ||||
-rw-r--r-- | compiler/GHC/Tc/Utils/TcMType.hs | 24 |
11 files changed, 536 insertions, 447 deletions
diff --git a/compiler/GHC/Tc/Errors.hs b/compiler/GHC/Tc/Errors.hs index 8998b621e6..8e839e5824 100644 --- a/compiler/GHC/Tc/Errors.hs +++ b/compiler/GHC/Tc/Errors.hs @@ -465,8 +465,9 @@ mkErrorItem ct -> do { rewriters' <- zonkRewriterSet rewriters ; return (not (isEmptyRewriterSet rewriters'), Just dest) } - ; let m_reason = case ct of CIrredCan { cc_reason = reason } -> Just reason - _ -> Nothing + ; let m_reason = case ct of + CIrredCan (IrredCt { ir_reason = reason }) -> Just reason + _ -> Nothing ; return $ Just $ EI { ei_pred = ctPred ct , ei_evdest = m_evdest diff --git a/compiler/GHC/Tc/Solver/Canonical.hs b/compiler/GHC/Tc/Solver/Canonical.hs index 49210cefa8..e8419de4ca 100644 --- a/compiler/GHC/Tc/Solver/Canonical.hs +++ b/compiler/GHC/Tc/Solver/Canonical.hs @@ -86,17 +86,17 @@ last time through, so we can skip the classification step. -- Top-level canonicalization -- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -canonicalize :: Ct -> TcS (StopOrContinue Ct) -canonicalize (CNonCanonical { cc_ev = ev }) - = {-# SCC "canNC" #-} - canNC ev +canonicalize :: Ct -> SolverStage Ct +canonicalize (CNonCanonical ev) + = canNC ev -canonicalize (CEqCan can_eq_ct) = solveCanonicalEquality can_eq_ct +canonicalize (CEqCan can_eq_ct) + = solveCanonicalEquality can_eq_ct canonicalize (CQuantCan (QCI { qci_ev = ev, qci_pend_sc = pend_sc })) - = canForAll ev pend_sc + = Stage $ canForAll ev pend_sc -canonicalize (CIrredCan { cc_ev = ev }) +canonicalize (CIrredCan (IrredCt { ir_ev = ev })) = canNC ev -- Instead of rewriting the evidence before classifying, it's possible we -- can make progress without the rewrite. Try this first. @@ -109,20 +109,15 @@ canonicalize (CIrredCan { cc_ev = ev }) canonicalize (CDictCan { cc_ev = ev, cc_class = cls , cc_tyargs = xis, cc_pend_sc = pend_sc }) = {-# SCC "canClass" #-} - canClass ev cls xis pend_sc + Stage $ canClass ev cls xis pend_sc -canNC :: CtEvidence -> TcS (StopOrContinue Ct) +canNC :: CtEvidence -> SolverStage Ct canNC ev = case classifyPredType pred of - ClassPred cls tys -> do traceTcS "canEvNC:cls" (ppr cls <+> ppr tys) - canClassNC ev cls tys - EqPred eq_rel ty1 ty2 -> do traceTcS "canEvNC:eq" (ppr ty1 $$ ppr ty2) - solveNonCanonicalEquality ev eq_rel ty1 ty2 - IrredPred {} -> do traceTcS "canEvNC:irred" (ppr pred) - canIrred ev - ForAllPred tvs th p -> do traceTcS "canEvNC:forall" (ppr pred) - canForAllNC ev tvs th p - + ClassPred cls tys -> Stage $ canClassNC ev cls tys + EqPred eq_rel ty1 ty2 -> solveNonCanonicalEquality ev eq_rel ty1 ty2 + IrredPred {} -> Stage $ canIrred ev + ForAllPred tvs th p -> Stage $ canForAllNC ev tvs th p where pred = ctEvPred ev diff --git a/compiler/GHC/Tc/Solver/Dict.hs b/compiler/GHC/Tc/Solver/Dict.hs index c0f7dc7a49..f815bbfd86 100644 --- a/compiler/GHC/Tc/Solver/Dict.hs +++ b/compiler/GHC/Tc/Solver/Dict.hs @@ -113,7 +113,7 @@ tryLastResortProhibitedSuperclass inerts tryLastResortProhibitedSuperclass _ work_item = continueWith work_item -chooseInstance :: CtEvidence -> ClsInstResult -> TcS (StopOrContinue Ct) +chooseInstance :: CtEvidence -> ClsInstResult -> TcS (StopOrContinue a) chooseInstance work_item (OneInst { cir_new_theta = theta , cir_what = what diff --git a/compiler/GHC/Tc/Solver/Equality.hs b/compiler/GHC/Tc/Solver/Equality.hs index bb2a9aa6d5..965927d6b7 100644 --- a/compiler/GHC/Tc/Solver/Equality.hs +++ b/compiler/GHC/Tc/Solver/Equality.hs @@ -100,42 +100,201 @@ It's as if we treat (->) and (=>) as different type constructors, which indeed they are! -} -solveCanonicalEquality :: EqCt -> TcS (StopOrContinue Ct) +solveCanonicalEquality :: EqCt -> SolverStage Ct solveCanonicalEquality (EqCt { eq_ev = ev, eq_eq_rel = eq_rel , eq_lhs = lhs, eq_rhs = rhs }) = solveNonCanonicalEquality ev eq_rel (canEqLHSType lhs) rhs -solveNonCanonicalEquality :: CtEvidence -> EqRel -> Type -> Type -> TcS (StopOrContinue Ct) +solveNonCanonicalEquality :: CtEvidence -> EqRel -> Type -> Type + -> SolverStage Ct solveNonCanonicalEquality ev eq_rel ty1 ty2 - = do { result <- zonk_eq_types ty1 ty2 - ; case result of - Right ty -> canEqReflexive ev eq_rel ty - Left (Pair ty1' ty2') -> can_eq_nc False ev' eq_rel ty1' ty1' ty2' ty2' - where - ev' | debugIsOn = setCtEvPredType ev $ - mkPrimEqPredRole (eqRelRole eq_rel) ty1' ty2' - | otherwise = ev + = do { Pair ty1' ty2' <- zonkEqTypes ev eq_rel ty1 ty2 + ; let ev' | debugIsOn = setCtEvPredType ev $ + mkPrimEqPredRole (eqRelRole eq_rel) ty1' ty2' + | otherwise = ev -- ev': satisfy the precondition of can_eq_nc - } -can_eq_nc - :: Bool -- True => both types are rewritten - -> CtEvidence - -> EqRel - -> Type -> Type -- LHS, after and before type-synonym expansion, resp - -> Type -> Type -- RHS, after and before type-synonym expansion, resp - -> TcS (StopOrContinue Ct) + ; mb_canon <- canonicaliseEquality ev' eq_rel ty1' ty2' + + ; case mb_canon of { + + Left irred_ct -> do { solveIrredEquality irred_ct + ; return (CIrredCan irred_ct) } ; + + Right eq_ct -> do { interactEq eq_ct + ; tryFunDeps eq_ct + ; tryQuantifiedConstraints eq_ct + ; return (CEqCan eq_ct) } } } + + + +{- ********************************************************************* +* * +* zonkEqTypes +* * +********************************************************************* -} + +--------------------------------- +-- | Compare types for equality, while zonking as necessary. Gives up +-- as soon as it finds that two types are not equal. +-- This is quite handy when some unification has made two +-- types in an inert Wanted to be equal. We can discover the equality without +-- rewriting, which is sometimes very expensive (in the case of type functions). +-- In particular, this function makes a ~20% improvement in test case +-- perf/compiler/T5030. +-- +-- Returns either the (partially zonked) types in the case of +-- inequality, or the one type in the case of equality. canEqReflexive is +-- a good next step in the 'Right' case. Returning 'Left' is always safe. +-- +-- NB: This does *not* look through type synonyms. In fact, it treats type +-- synonyms as rigid constructors. In the future, it might be convenient +-- to look at only those arguments of type synonyms that actually appear +-- in the synonym RHS. But we're not there yet. +zonkEqTypes :: CtEvidence -> EqRel -> TcType -> TcType -> SolverStage (Pair TcType) +zonkEqTypes ev eq_rel ty1 ty2 + = Stage $ do { res <- go ty1 ty2 + ; case res of + Left pair -> continueWith pair + Right ty -> canEqReflexive ev eq_rel ty } + where + go :: TcType -> TcType -> TcS (Either (Pair TcType) TcType) + go (TyVarTy tv1) (TyVarTy tv2) = tyvar_tyvar tv1 tv2 + go (TyVarTy tv1) ty2 = tyvar NotSwapped tv1 ty2 + go ty1 (TyVarTy tv2) = tyvar IsSwapped tv2 ty1 + + -- We handle FunTys explicitly here despite the fact that they could also be + -- treated as an application. Why? Well, for one it's cheaper to just look + -- at two types (the argument and result types) than four (the argument, + -- result, and their RuntimeReps). Also, we haven't completely zonked yet, + -- so we may run into an unzonked type variable while trying to compute the + -- RuntimeReps of the argument and result types. This can be observed in + -- testcase tc269. + go (FunTy af1 w1 arg1 res1) (FunTy af2 w2 arg2 res2) + | af1 == af2 + , eqType w1 w2 + = do { res_a <- go arg1 arg2 + ; res_b <- go res1 res2 + ; return $ combine_rev (FunTy af1 w1) res_b res_a } + + go ty1@(FunTy {}) ty2 = bale_out ty1 ty2 + go ty1 ty2@(FunTy {}) = bale_out ty1 ty2 + + go ty1 ty2 + | Just (tc1, tys1) <- splitTyConAppNoView_maybe ty1 + , Just (tc2, tys2) <- splitTyConAppNoView_maybe ty2 + = if tc1 == tc2 && tys1 `equalLength` tys2 + -- Crucial to check for equal-length args, because + -- we cannot assume that the two args to 'go' have + -- the same kind. E.g go (Proxy * (Maybe Int)) + -- (Proxy (*->*) Maybe) + -- We'll call (go (Maybe Int) Maybe) + -- See #13083 + then tycon tc1 tys1 tys2 + else bale_out ty1 ty2 + + go ty1 ty2 + | Just (ty1a, ty1b) <- tcSplitAppTyNoView_maybe ty1 + , Just (ty2a, ty2b) <- tcSplitAppTyNoView_maybe ty2 + = do { res_a <- go ty1a ty2a + ; res_b <- go ty1b ty2b + ; return $ combine_rev mkAppTy res_b res_a } + + go ty1@(LitTy lit1) (LitTy lit2) + | lit1 == lit2 + = return (Right ty1) + + go ty1 ty2 = bale_out ty1 ty2 + -- We don't handle more complex forms here + + bale_out ty1 ty2 = return $ Left (Pair ty1 ty2) + + tyvar :: SwapFlag -> TcTyVar -> TcType + -> TcS (Either (Pair TcType) TcType) + -- Try to do as little as possible, as anything we do here is redundant + -- with rewriting. In particular, no need to zonk kinds. That's why + -- we don't use the already-defined zonking functions + tyvar swapped tv ty + = case tcTyVarDetails tv of + MetaTv { mtv_ref = ref } + -> do { cts <- readTcRef ref + ; case cts of + Flexi -> give_up + Indirect ty' -> do { trace_indirect tv ty' + ; unSwap swapped go ty' ty } } + _ -> give_up + where + give_up = return $ Left $ unSwap swapped Pair (mkTyVarTy tv) ty + + tyvar_tyvar tv1 tv2 + | tv1 == tv2 = return (Right (mkTyVarTy tv1)) + | otherwise = do { (ty1', progress1) <- quick_zonk tv1 + ; (ty2', progress2) <- quick_zonk tv2 + ; if progress1 || progress2 + then go ty1' ty2' + else return $ Left (Pair (TyVarTy tv1) (TyVarTy tv2)) } + + trace_indirect tv ty + = traceTcS "Following filled tyvar (zonk_eq_types)" + (ppr tv <+> equals <+> ppr ty) + + quick_zonk tv = case tcTyVarDetails tv of + MetaTv { mtv_ref = ref } + -> do { cts <- readTcRef ref + ; case cts of + Flexi -> return (TyVarTy tv, False) + Indirect ty' -> do { trace_indirect tv ty' + ; return (ty', True) } } + _ -> return (TyVarTy tv, False) + + -- This happens for type families, too. But recall that failure + -- here just means to try harder, so it's OK if the type function + -- isn't injective. + tycon :: TyCon -> [TcType] -> [TcType] + -> TcS (Either (Pair TcType) TcType) + tycon tc tys1 tys2 + = do { results <- zipWithM go tys1 tys2 + ; return $ case combine_results results of + Left tys -> Left (mkTyConApp tc <$> tys) + Right tys -> Right (mkTyConApp tc tys) } + + combine_results :: [Either (Pair TcType) TcType] + -> Either (Pair [TcType]) [TcType] + combine_results = bimap (fmap reverse) reverse . + foldl' (combine_rev (:)) (Right []) + + -- combine (in reverse) a new result onto an already-combined result + combine_rev :: (a -> b -> c) + -> Either (Pair b) b + -> Either (Pair a) a + -> Either (Pair c) c + combine_rev f (Left list) (Left elt) = Left (f <$> elt <*> list) + combine_rev f (Left list) (Right ty) = Left (f <$> pure ty <*> list) + combine_rev f (Right tys) (Left elt) = Left (f <$> elt <*> pure tys) + combine_rev f (Right tys) (Right ty) = Right (f ty tys) + + +{- ********************************************************************* +* * +* canonicaliseEquality +* * +********************************************************************* -} + +canonicaliseEquality + :: CtEvidence -> EqRel + -> Type -> Type -- LHS and RHS + -> SolverStage (Either IrredCt EqCt) -- Precondition: in DEBUG mode, the `ctev_pred` of `ev` is (ps_ty1 ~# ps_ty2), -- without zonking -- This precondition is needed (only in DEBUG) to satisfy the assertions -- in mkSelCo, called in canDecomposableTyConAppOK and canDecomposableFunTy -can_eq_nc rewritten ev eq_rel ty1 ps_ty1 ty2 ps_ty2 - = do { traceTcS "can_eq_nc" $ - vcat [ ppr rewritten, ppr ev, ppr eq_rel, ppr ty1, ppr ps_ty1, ppr ty2, ppr ps_ty2 ] - ; rdr_env <- getGlobalRdrEnvTcS - ; fam_insts <- getFamInstEnvs - ; can_eq_nc' rewritten rdr_env fam_insts ev eq_rel ty1 ps_ty1 ty2 ps_ty2 } +canonicaliseEquality ev eq_rel ty1 ty2 + = Stage $ do { traceTcS "canonicaliseEquality" $ + vcat [ ppr ev, ppr eq_rel, ppr ty1, ppr ty2 ] + ; rdr_env <- getGlobalRdrEnvTcS + ; fam_insts <- getFamInstEnvs + ; can_eq_nc' False rdr_env fam_insts ev eq_rel ty1 ty1 ty2 ty2 } can_eq_nc' :: Bool -- True => both input types are rewritten @@ -145,7 +304,7 @@ can_eq_nc' -> EqRel -> Type -> Type -- LHS, after and before type-synonym expansion, resp -> Type -> Type -- RHS, after and before type-synonym expansion, resp - -> TcS (StopOrContinue Ct) + -> TcS (StopOrContinue (Either IrredCt EqCt)) -- See Note [Comparing nullary type synonyms] in GHC.Core.Type. can_eq_nc' _flat _rdr_env _envs ev eq_rel ty1@(TyConApp tc1 []) _ps_ty1 (TyConApp tc2 []) _ps_ty2 @@ -171,19 +330,19 @@ can_eq_nc' True _rdr_env _envs ev ReprEq ty1 _ ty2 _ can_eq_nc' _rewritten rdr_env envs ev eq_rel ty1 ps_ty1 ty2 ps_ty2 | ReprEq <- eq_rel , Just stuff1 <- tcTopNormaliseNewTypeTF_maybe envs rdr_env ty1 - = can_eq_newtype_nc ev NotSwapped ty1 stuff1 ty2 ps_ty2 + = can_eq_newtype_nc rdr_env envs ev NotSwapped ty1 stuff1 ty2 ps_ty2 | ReprEq <- eq_rel , Just stuff2 <- tcTopNormaliseNewTypeTF_maybe envs rdr_env ty2 - = can_eq_newtype_nc ev IsSwapped ty2 stuff2 ty1 ps_ty1 + = can_eq_newtype_nc rdr_env envs ev IsSwapped ty2 stuff2 ty1 ps_ty1 -- Then, get rid of casts -can_eq_nc' rewritten _rdr_env _envs ev eq_rel (CastTy ty1 co1) _ ty2 ps_ty2 +can_eq_nc' rewritten rdr_env envs ev eq_rel (CastTy ty1 co1) _ ty2 ps_ty2 | isNothing (canEqLHS_maybe ty2) -- See (W3) in Note [Equalities with incompatible kinds] - = canEqCast rewritten ev eq_rel NotSwapped ty1 co1 ty2 ps_ty2 -can_eq_nc' rewritten _rdr_env _envs ev eq_rel ty1 ps_ty1 (CastTy ty2 co2) _ + = canEqCast rewritten rdr_env envs ev eq_rel NotSwapped ty1 co1 ty2 ps_ty2 +can_eq_nc' rewritten rdr_env envs ev eq_rel ty1 ps_ty1 (CastTy ty2 co2) _ | isNothing (canEqLHS_maybe ty1) -- See (W3) in Note [Equalities with incompatible kinds] - = canEqCast rewritten ev eq_rel IsSwapped ty2 co2 ty1 ps_ty1 + = canEqCast rewritten rdr_env envs ev eq_rel IsSwapped ty2 co2 ty1 ps_ty1 ---------------------- -- Otherwise try to decompose @@ -276,8 +435,8 @@ can_eq_nc' True _rdr_env _envs ev eq_rel ty1 ps_ty1 ty2 ps_ty2 can_eq_nc' True _rdr_env _envs ev eq_rel _ ps_ty1 _ ps_ty2 = do { traceTcS "can_eq_nc' catch-all case" (ppr ps_ty1 $$ ppr ps_ty2) ; case eq_rel of -- See Note [Unsolved equalities] - ReprEq -> solveIrredEquality ReprEqReason ev - NomEq -> solveIrredEquality ShapeMismatchReason ev } + ReprEq -> finishCanWithIrred ReprEqReason ev + NomEq -> finishCanWithIrred ShapeMismatchReason ev } -- No need to call canEqFailure/canEqHardFailure because they -- rewrite, and the types involved here are already rewritten @@ -294,7 +453,7 @@ Missing this point is what caused #15431 --------------------------------- can_eq_nc_forall :: CtEvidence -> EqRel -> Type -> Type -- LHS and RHS - -> TcS (StopOrContinue Ct) + -> TcS (StopOrContinue (Either IrredCt EqCt)) -- (forall as. phi1) ~ (forall bs. phi2) -- Check for length match of as, bs -- Then build an implication constraint: forall as. phi1 ~ phi2[as/bs] @@ -370,139 +529,6 @@ can_eq_nc_forall ev eq_rel s1 s2 = do { (wanted, co) <- newWantedEq loc rewriters role ty1 ty2 ; return (co, unitBag (mkNonCanonical wanted)) } ---------------------------------- --- | Compare types for equality, while zonking as necessary. Gives up --- as soon as it finds that two types are not equal. --- This is quite handy when some unification has made two --- types in an inert Wanted to be equal. We can discover the equality without --- rewriting, which is sometimes very expensive (in the case of type functions). --- In particular, this function makes a ~20% improvement in test case --- perf/compiler/T5030. --- --- Returns either the (partially zonked) types in the case of --- inequality, or the one type in the case of equality. canEqReflexive is --- a good next step in the 'Right' case. Returning 'Left' is always safe. --- --- NB: This does *not* look through type synonyms. In fact, it treats type --- synonyms as rigid constructors. In the future, it might be convenient --- to look at only those arguments of type synonyms that actually appear --- in the synonym RHS. But we're not there yet. -zonk_eq_types :: TcType -> TcType -> TcS (Either (Pair TcType) TcType) -zonk_eq_types = go - where - go (TyVarTy tv1) (TyVarTy tv2) = tyvar_tyvar tv1 tv2 - go (TyVarTy tv1) ty2 = tyvar NotSwapped tv1 ty2 - go ty1 (TyVarTy tv2) = tyvar IsSwapped tv2 ty1 - - -- We handle FunTys explicitly here despite the fact that they could also be - -- treated as an application. Why? Well, for one it's cheaper to just look - -- at two types (the argument and result types) than four (the argument, - -- result, and their RuntimeReps). Also, we haven't completely zonked yet, - -- so we may run into an unzonked type variable while trying to compute the - -- RuntimeReps of the argument and result types. This can be observed in - -- testcase tc269. - go (FunTy af1 w1 arg1 res1) (FunTy af2 w2 arg2 res2) - | af1 == af2 - , eqType w1 w2 - = do { res_a <- go arg1 arg2 - ; res_b <- go res1 res2 - ; return $ combine_rev (FunTy af1 w1) res_b res_a } - - go ty1@(FunTy {}) ty2 = bale_out ty1 ty2 - go ty1 ty2@(FunTy {}) = bale_out ty1 ty2 - - go ty1 ty2 - | Just (tc1, tys1) <- splitTyConAppNoView_maybe ty1 - , Just (tc2, tys2) <- splitTyConAppNoView_maybe ty2 - = if tc1 == tc2 && tys1 `equalLength` tys2 - -- Crucial to check for equal-length args, because - -- we cannot assume that the two args to 'go' have - -- the same kind. E.g go (Proxy * (Maybe Int)) - -- (Proxy (*->*) Maybe) - -- We'll call (go (Maybe Int) Maybe) - -- See #13083 - then tycon tc1 tys1 tys2 - else bale_out ty1 ty2 - - go ty1 ty2 - | Just (ty1a, ty1b) <- tcSplitAppTyNoView_maybe ty1 - , Just (ty2a, ty2b) <- tcSplitAppTyNoView_maybe ty2 - = do { res_a <- go ty1a ty2a - ; res_b <- go ty1b ty2b - ; return $ combine_rev mkAppTy res_b res_a } - - go ty1@(LitTy lit1) (LitTy lit2) - | lit1 == lit2 - = return (Right ty1) - - go ty1 ty2 = bale_out ty1 ty2 - -- We don't handle more complex forms here - - bale_out ty1 ty2 = return $ Left (Pair ty1 ty2) - - tyvar :: SwapFlag -> TcTyVar -> TcType - -> TcS (Either (Pair TcType) TcType) - -- Try to do as little as possible, as anything we do here is redundant - -- with rewriting. In particular, no need to zonk kinds. That's why - -- we don't use the already-defined zonking functions - tyvar swapped tv ty - = case tcTyVarDetails tv of - MetaTv { mtv_ref = ref } - -> do { cts <- readTcRef ref - ; case cts of - Flexi -> give_up - Indirect ty' -> do { trace_indirect tv ty' - ; unSwap swapped go ty' ty } } - _ -> give_up - where - give_up = return $ Left $ unSwap swapped Pair (mkTyVarTy tv) ty - - tyvar_tyvar tv1 tv2 - | tv1 == tv2 = return (Right (mkTyVarTy tv1)) - | otherwise = do { (ty1', progress1) <- quick_zonk tv1 - ; (ty2', progress2) <- quick_zonk tv2 - ; if progress1 || progress2 - then go ty1' ty2' - else return $ Left (Pair (TyVarTy tv1) (TyVarTy tv2)) } - - trace_indirect tv ty - = traceTcS "Following filled tyvar (zonk_eq_types)" - (ppr tv <+> equals <+> ppr ty) - - quick_zonk tv = case tcTyVarDetails tv of - MetaTv { mtv_ref = ref } - -> do { cts <- readTcRef ref - ; case cts of - Flexi -> return (TyVarTy tv, False) - Indirect ty' -> do { trace_indirect tv ty' - ; return (ty', True) } } - _ -> return (TyVarTy tv, False) - - -- This happens for type families, too. But recall that failure - -- here just means to try harder, so it's OK if the type function - -- isn't injective. - tycon :: TyCon -> [TcType] -> [TcType] - -> TcS (Either (Pair TcType) TcType) - tycon tc tys1 tys2 - = do { results <- zipWithM go tys1 tys2 - ; return $ case combine_results results of - Left tys -> Left (mkTyConApp tc <$> tys) - Right tys -> Right (mkTyConApp tc tys) } - - combine_results :: [Either (Pair TcType) TcType] - -> Either (Pair [TcType]) [TcType] - combine_results = bimap (fmap reverse) reverse . - foldl' (combine_rev (:)) (Right []) - - -- combine (in reverse) a new result onto an already-combined result - combine_rev :: (a -> b -> c) - -> Either (Pair b) b - -> Either (Pair a) a - -> Either (Pair c) c - combine_rev f (Left list) (Left elt) = Left (f <$> elt <*> list) - combine_rev f (Left list) (Right ty) = Left (f <$> pure ty <*> list) - combine_rev f (Right tys) (Left elt) = Left (f <$> elt <*> pure tys) - combine_rev f (Right tys) (Right ty) = Right (f ty tys) {- Note [Unwrap newtypes first] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -612,14 +638,15 @@ though, because we check our depth in `can_eq_newtype_nc`. ------------------------ -- | We're able to unwrap a newtype. Update the bits accordingly. -can_eq_newtype_nc :: CtEvidence -- ^ :: ty1 ~ ty2 +can_eq_newtype_nc :: GlobalRdrEnv -> FamInstEnvs + -> CtEvidence -- ^ :: ty1 ~ ty2 -> SwapFlag -> TcType -- ^ ty1 -> ((Bag GlobalRdrElt, TcCoercion), TcType) -- ^ :: ty1 ~ ty1' -> TcType -- ^ ty2 -> TcType -- ^ ty2, with type synonyms - -> TcS (StopOrContinue Ct) -can_eq_newtype_nc ev swapped ty1 ((gres, co1), ty1') ty2 ps_ty2 + -> TcS (StopOrContinue (Either IrredCt EqCt)) +can_eq_newtype_nc rdr_env envs ev swapped ty1 ((gres, co1), ty1') ty2 ps_ty2 = do { traceTcS "can_eq_newtype_nc" $ vcat [ ppr ev, ppr swapped, ppr co1, ppr gres, ppr ty1', ppr ty2 ] @@ -638,7 +665,7 @@ can_eq_newtype_nc ev swapped ty1 ((gres, co1), ty1') ty2 ps_ty2 ; new_ev <- rewriteEqEvidence emptyRewriterSet ev' swapped redn1 (mkReflRedn Representational ps_ty2) - ; can_eq_nc False new_ev ReprEq ty1' ty1' ty2 ps_ty2 } + ; can_eq_nc' False rdr_env envs new_ev ReprEq ty1' ty1' ty2 ps_ty2 } --------- -- ^ Decompose a type application. @@ -647,7 +674,7 @@ can_eq_newtype_nc ev swapped ty1 ((gres, co1), ty1') ty2 ps_ty2 can_eq_app :: CtEvidence -- :: s1 t1 ~N s2 t2 -> Xi -> Xi -- s1 t1 -> Xi -> Xi -- s2 t2 - -> TcS (StopOrContinue Ct) + -> TcS (StopOrContinue (Either IrredCt EqCt)) -- AppTys only decompose for nominal equality, so this case just leads -- to an irreducible constraint; see typecheck/should_compile/T10494 @@ -685,7 +712,7 @@ can_eq_app ev s1 t1 s2 t2 ; evar_t <- newGivenEvVar loc ( mkTcEqPredLikeEv ev t1 t2 , evCoercion co_t ) ; emitWorkNC [evar_t] - ; solveNonCanonicalEquality evar_s NomEq s1 s2 } + ; startAgainWith (mkNonCanonical evar_s) } where loc = ctEvLoc ev @@ -701,20 +728,21 @@ can_eq_app ev s1 t1 s2 t2 -- | Break apart an equality over a casted type -- looking like (ty1 |> co1) ~ ty2 (modulo a swap-flag) canEqCast :: Bool -- are both types rewritten? + -> GlobalRdrEnv -> FamInstEnvs -> CtEvidence -> EqRel -> SwapFlag -> TcType -> Coercion -- LHS (res. RHS), ty1 |> co1 -> TcType -> TcType -- RHS (res. LHS), ty2 both normal and pretty - -> TcS (StopOrContinue Ct) -canEqCast rewritten ev eq_rel swapped ty1 co1 ty2 ps_ty2 + -> TcS (StopOrContinue (Either IrredCt EqCt)) +canEqCast rewritten rdr_env envs ev eq_rel swapped ty1 co1 ty2 ps_ty2 = do { traceTcS "Decomposing cast" (vcat [ ppr ev , ppr ty1 <+> text "|>" <+> ppr co1 , ppr ps_ty2 ]) ; new_ev <- rewriteEqEvidence emptyRewriterSet ev swapped (mkGReflLeftRedn role ty1 co1) (mkReflRedn role ps_ty2) - ; can_eq_nc rewritten new_ev eq_rel ty1 ty1 ty2 ps_ty2 } + ; can_eq_nc' rewritten rdr_env envs new_ev eq_rel ty1 ty1 ty2 ps_ty2 } where role = eqRelRole eq_rel @@ -722,7 +750,7 @@ canEqCast rewritten ev eq_rel swapped ty1 co1 ty2 ps_ty2 canTyConApp :: CtEvidence -> EqRel -> TyCon -> [TcType] -> TyCon -> [TcType] - -> TcS (StopOrContinue Ct) + -> TcS (StopOrContinue (Either IrredCt EqCt)) -- See Note [Decomposing TyConApp equalities] -- Neither tc1 nor tc2 is a saturated funTyCon, nor a type family -- But they can be data families. @@ -737,7 +765,7 @@ canTyConApp ev eq_rel tc1 tys1 tc2 tys2 -- See Note [Skolem abstract data] in GHC.Core.Tycon | tyConSkolem tc1 || tyConSkolem tc2 = do { traceTcS "canTyConApp: skolem abstract" (ppr tc1 $$ ppr tc2) - ; solveIrredEquality AbstractTyConReason ev } + ; finishCanWithIrred AbstractTyConReason ev } -- Fail straight away for better error messages -- See Note [Use canEqFailure in canDecomposableTyConApp] @@ -1203,7 +1231,7 @@ Extra points canDecomposableTyConAppOK :: CtEvidence -> EqRel -> TyCon -> [TcType] -> [TcType] - -> TcS (StopOrContinue Ct) + -> TcS (StopOrContinue a) -- Precondition: tys1 and tys2 are the same finite length, hence "OK" canDecomposableTyConAppOK ev eq_rel tc tys1 tys2 = assert (tys1 `equalLength` tys2) $ @@ -1260,7 +1288,7 @@ canDecomposableTyConAppOK ev eq_rel tc tys1 tys2 canDecomposableFunTy :: CtEvidence -> EqRel -> FunTyFlag -> (Type,Type,Type) -- (multiplicity,arg,res) -> (Type,Type,Type) -- (multiplicity,arg,res) - -> TcS (StopOrContinue Ct) + -> TcS (StopOrContinue a) canDecomposableFunTy ev eq_rel af f1@(m1,a1,r1) f2@(m2,a2,r2) = do { traceTcS "canDecomposableFunTy" (ppr ev $$ ppr eq_rel $$ ppr f1 $$ ppr f2) @@ -1293,7 +1321,7 @@ canDecomposableFunTy ev eq_rel af f1@(m1,a1,r1) f2@(m2,a2,r2) -- representational, there is some hope for the future. -- Examples in Note [Use canEqFailure in canDecomposableTyConApp] canEqFailure :: CtEvidence -> EqRel - -> TcType -> TcType -> TcS (StopOrContinue Ct) + -> TcType -> TcType -> TcS (StopOrContinue (Either IrredCt a)) canEqFailure ev NomEq ty1 ty2 = canEqHardFailure ev ty1 ty2 canEqFailure ev ReprEq ty1 ty2 @@ -1305,18 +1333,18 @@ canEqFailure ev ReprEq ty1 ty2 ; traceTcS "canEqFailure with ReprEq" $ vcat [ ppr ev, ppr redn1, ppr redn2 ] ; new_ev <- rewriteEqEvidence (rewriters1 S.<> rewriters2) ev NotSwapped redn1 redn2 - ; continueWith (mkIrredCt ReprEqReason new_ev) } + ; finishCanWithIrred ReprEqReason new_ev } -- | Call when canonicalizing an equality fails with utterly no hope. canEqHardFailure :: CtEvidence - -> TcType -> TcType -> TcS (StopOrContinue Ct) + -> TcType -> TcType -> TcS (StopOrContinue (Either IrredCt a)) -- See Note [Make sure that insolubles are fully rewritten] canEqHardFailure ev ty1 ty2 = do { traceTcS "canEqHardFailure" (ppr ty1 $$ ppr ty2) ; (redn1, rewriters1) <- rewriteForErrors ev ty1 ; (redn2, rewriters2) <- rewriteForErrors ev ty2 ; new_ev <- rewriteEqEvidence (rewriters1 S.<> rewriters2) ev NotSwapped redn1 redn2 - ; continueWith (mkIrredCt ShapeMismatchReason new_ev) } + ; finishCanWithIrred ShapeMismatchReason new_ev } {- Note [Canonicalising type applications] @@ -1436,7 +1464,7 @@ canEqCanLHS :: CtEvidence -- ev :: lhs ~ rhs -> CanEqLHS -- lhs (or, if swapped, rhs) -> TcType -- lhs: pretty lhs, already rewritten -> TcType -> TcType -- rhs: already rewritten - -> TcS (StopOrContinue Ct) + -> TcS (StopOrContinue (Either IrredCt EqCt)) canEqCanLHS ev eq_rel swapped lhs1 ps_xi1 xi2 ps_xi2 | k1 `tcEqType` k2 = canEqCanLHSHomo ev eq_rel swapped lhs1 ps_xi1 xi2 ps_xi2 @@ -1484,7 +1512,7 @@ canEqCanLHSHetero :: CtEvidence -- :: (xi1 :: ki1) ~ (xi2 :: ki2) -> TcKind -- ki1 -> TcType -> TcType -- xi2 -> TcKind -- ki2 - -> TcS (StopOrContinue Ct) + -> TcS (StopOrContinue (Either IrredCt EqCt)) canEqCanLHSHetero ev eq_rel swapped lhs1 ps_xi1 ki1 xi2 ps_xi2 ki2 -- See Note [Equalities with incompatible kinds] -- See Note [Kind Equality Orientation] @@ -1547,7 +1575,7 @@ canEqCanLHSHomo :: CtEvidence -- lhs ~ rhs -> EqRel -> SwapFlag -> CanEqLHS -> TcType -- lhs, pretty lhs -> TcType -> TcType -- rhs, pretty rhs - -> TcS (StopOrContinue Ct) + -> TcS (StopOrContinue (Either IrredCt EqCt)) -- Guaranteed that typeKind lhs == typeKind rhs canEqCanLHSHomo ev eq_rel swapped lhs1 ps_xi1 xi2 ps_xi2 | (xi2', mco) <- split_cast_ty xi2 @@ -1571,7 +1599,7 @@ canEqCanLHS2 :: CtEvidence -- lhs ~ (rhs |> mco) -> CanEqLHS -- rhs -> TcType -- pretty rhs -> MCoercion -- :: kind(rhs) ~N kind(lhs) - -> TcS (StopOrContinue Ct) + -> TcS (StopOrContinue (Either IrredCt EqCt)) canEqCanLHS2 ev eq_rel swapped lhs1 ps_xi1 lhs2 ps_xi2 mco | lhs1 `eqCanEqLHS` lhs2 -- It must be the case that mco is reflexive @@ -1696,11 +1724,11 @@ If we have a TyFamLHS on both sides, we choose how to orient it. -- want to rewrite the LHS to (as per e.g. swapOverTyVars) canEqCanLHSFinish, canEqCanLHSFinish_try_unification, canEqCanLHSFinish_no_unification - :: CtEvidence + :: CtEvidence -- (lhs ~ rhs) or if swapped (rhs ~ lhs) -> EqRel -> SwapFlag - -> CanEqLHS -- lhs (or, if swapped, rhs) - -> TcType -- rhs (or, if swapped, lhs) - -> TcS (StopOrContinue Ct) + -> CanEqLHS -- lhs + -> TcType -- rhs + -> TcS (StopOrContinue (Either IrredCt EqCt)) -- RHS is fully rewritten, but with type synonyms -- preserved as much as possible -- Guaranteed preconditions that @@ -1866,49 +1894,54 @@ canEqCanLHSFinish_no_unification ev eq_rel swapped lhs rhs -- * new_ev has reductionReducedType on the RHS -- * eq_rhs is set to reductionReducedType -- See Note [Forgetful synonyms in checkTyConApp] in GHC.Tc.Utils.Unify - ; interactEq (EqCt { eq_ev = new_ev, eq_eq_rel = eq_rel - , eq_lhs = lhs - , eq_rhs = reductionReducedType rhs_redn }) } } + ; continueWith $ Right $ + EqCt { eq_ev = new_ev, eq_eq_rel = eq_rel + , eq_lhs = lhs + , eq_rhs = reductionReducedType rhs_redn } } } ---------------------- swapAndFinish :: CtEvidence -> EqRel -> SwapFlag -> TcType -> CanEqLHS -- ty ~ F tys - -> TcS (StopOrContinue Ct) + -> TcS (StopOrContinue (Either IrredCt EqCt)) -- We have an equality alpha ~ F tys, that we can't unify e.g because 'tys' -- mentions alpha, it would not be a canonical constraint as-is. -- We want to flip it to (F tys ~ a), whereupon it is canonical swapAndFinish ev eq_rel swapped lhs_ty can_rhs - = do { new_ev <- rewriteEqEvidence emptyRewriterSet ev (flipSwap swapped) + = do { let role = eqRelRole eq_rel + ; new_ev <- rewriteEqEvidence emptyRewriterSet ev (flipSwap swapped) (mkReflRedn role (canEqLHSType can_rhs)) (mkReflRedn role lhs_ty) - ; interactEq (EqCt { eq_ev = new_ev, eq_eq_rel = eq_rel - , eq_lhs = can_rhs, eq_rhs = lhs_ty }) } - where - role = eqRelRole eq_rel + ; continueWith $ Right $ + EqCt { eq_ev = new_ev, eq_eq_rel = eq_rel + , eq_lhs = can_rhs, eq_rhs = lhs_ty } } ---------------------- tryIrredInstead :: CheckTyEqResult -> CtEvidence -> EqRel -> SwapFlag - -> CanEqLHS -> TcType -> TcS (StopOrContinue Ct) + -> CanEqLHS -> TcType -> TcS (StopOrContinue (Either IrredCt a)) -- We have a non-canonical equality -- We still swap it if 'swapped' says so, so that it is oriented --- in the direction that the error message reporting machinery +-- in the direction that the error-reporting machinery -- expects it; e.g. (m ~ t m) rather than (t m ~ m) -- This is not very important, and only affects error reporting. tryIrredInstead reason ev eq_rel swapped lhs rhs = do { traceTcS "cantMakeCanonical" (ppr reason $$ ppr lhs $$ ppr rhs) + ; let role = eqRelRole eq_rel ; new_ev <- rewriteEqEvidence emptyRewriterSet ev swapped (mkReflRedn role (canEqLHSType lhs)) (mkReflRedn role rhs) - ; solveIrredEquality (NonCanonicalReason reason) new_ev } - where - role = eqRelRole eq_rel + ; finishCanWithIrred (NonCanonicalReason reason) new_ev } + +finishCanWithIrred :: CtIrredReason -> CtEvidence + -> TcS (StopOrContinue (Either IrredCt a)) +finishCanWithIrred reason ev + = continueWith $ Left $ IrredCt { ir_ev = ev, ir_reason = reason } ----------------------- -- | Solve a reflexive equality constraint canEqReflexive :: CtEvidence -- ty ~ ty -> EqRel -> TcType -- ty - -> TcS (StopOrContinue Ct) -- always Stop + -> TcS (StopOrContinue a) -- always Stop canEqReflexive ev eq_rel ty = do { setEvBindIfWanted ev IsCoherent $ evCoercion (mkReflCo (eqRelRole eq_rel) ty) @@ -2488,10 +2521,10 @@ But it's not so simple: call to strictly_more_visible. -} -interactEq :: EqCt -> TcS (StopOrContinue Ct) -interactEq work_item@(EqCt { eq_lhs = lhs, eq_ev = ev, eq_eq_rel = eq_rel }) - - = do { inerts <- getInertCans +interactEq :: EqCt -> SolverStage () +interactEq work_item@(EqCt { eq_ev = ev, eq_eq_rel = eq_rel }) + = Stage $ + do { inerts <- getInertCans ; if | Just (ev_i, swapped) <- inertsCanDischarge inerts work_item -> do { setEvBindIfWanted ev IsCoherent $ evCoercion (maybeSymCo swapped $ @@ -2501,14 +2534,7 @@ interactEq work_item@(EqCt { eq_lhs = lhs, eq_ev = ev, eq_eq_rel = eq_rel }) ; stopWith ev "Solved from inert" } | otherwise - -> case lhs of - TyVarLHS {} -> finishEqCt work_item - TyFamLHS tc args -> do { imp1 <- improveLocalFunEqs inerts tc args work_item - ; imp2 <- improveTopFunEqs tc args work_item - ; if (imp1 || imp2) - then startAgainWith (mkNonCanonical ev) - else finishEqCt work_item } } - + -> continueWith () } inertsCanDischarge :: InertCans -> EqCt -> Maybe ( CtEvidence -- The evidence for the inert @@ -2628,6 +2654,7 @@ make the solver iterate more often. (We don't need to iterate when unifying at the ambient level because of the kick-out mechanism.) -} + {-******************************************************************** * * Final wrap-up for equalities @@ -2647,10 +2674,10 @@ See -} -------------------- -solveIrredEquality :: CtIrredReason -> CtEvidence -> TcS (StopOrContinue Ct) -solveIrredEquality reason ev +solveIrredEquality :: IrredCt -> SolverStage () +solveIrredEquality irred@(IrredCt { ir_ev = ev }) | EqPred eq_rel t1 t2 <- classifyPredType (ctEvPred ev) - = final_qci_check (mkIrredCt reason ev) eq_rel t1 t2 + = lookup_eq_in_qcis (CIrredCan irred) eq_rel t1 t2 -- If the final_qci_check fails, we'll do continueWith on an IrredCt -- That in turn will go down the Irred pipeline, so which deals with -- the case where we have [G] Coercible (m a) (m b), and [W] m a ~R# m b @@ -2664,24 +2691,25 @@ solveIrredEquality reason ev = pprPanic "solveIrredEquality" (ppr ev) -------------------- -finishEqCt :: EqCt -> TcS (StopOrContinue Ct) -finishEqCt work_item@(EqCt { eq_lhs = lhs, eq_rhs = rhs, eq_eq_rel = eq_rel }) - = final_qci_check (CEqCan work_item) eq_rel (canEqLHSType lhs) rhs +tryQuantifiedConstraints :: EqCt -> SolverStage () +tryQuantifiedConstraints work_item@(EqCt { eq_lhs = lhs, eq_rhs = rhs, eq_eq_rel = eq_rel }) + = lookup_eq_in_qcis (CEqCan work_item) eq_rel (canEqLHSType lhs) rhs -------------------- -final_qci_check :: Ct -> EqRel -> TcType -> TcType -> TcS (StopOrContinue Ct) +lookup_eq_in_qcis :: Ct -> EqRel -> TcType -> TcType -> SolverStage () -- The "final QCI check" checks to see if we have -- [W] t1 ~# t2 -- and a Given quantified contraint like (forall a b. blah => a ~ b) -- Why? See Note [Looking up primitive equalities in quantified constraints] -final_qci_check work_ct eq_rel lhs rhs - = do { ev_binds_var <- getTcEvBindsVar +lookup_eq_in_qcis work_ct eq_rel lhs rhs + = Stage $ + do { ev_binds_var <- getTcEvBindsVar ; ics <- getInertCans ; if isWanted ev -- Never look up Givens in quantified constraints && not (null (inert_insts ics)) -- Shortcut common case && not (isCoEvBindsVar ev_binds_var) -- See Note [Instances in no-evidence implications] then try_for_qci - else continueWith work_ct } + else continueWith () } where ev = ctEvidence work_ct loc = ctEvLoc ev @@ -2690,27 +2718,27 @@ final_qci_check work_ct eq_rel lhs rhs try_for_qci -- First try looking for (lhs ~ rhs) | Just (cls, tys) <- boxEqPred eq_rel lhs rhs = do { res <- matchLocalInst (mkClassPred cls tys) loc - ; traceTcS "final_qci_check:1" (ppr (mkClassPred cls tys)) + ; traceTcS "lookup_irred_in_qcis:1" (ppr (mkClassPred cls tys)) ; case res of OneInst { cir_mk_ev = mk_ev } -> chooseInstance ev (res { cir_mk_ev = mk_eq_ev cls tys mk_ev }) _ -> try_swapping } | otherwise - = continueWith work_ct + = continueWith () try_swapping -- Now try looking for (rhs ~ lhs) (see #23333) | Just (cls, tys) <- boxEqPred eq_rel rhs lhs = do { res <- matchLocalInst (mkClassPred cls tys) loc - ; traceTcS "final_qci_check:2" (ppr (mkClassPred cls tys)) + ; traceTcS "lookup_irred_in_qcis:2" (ppr (mkClassPred cls tys)) ; case res of OneInst { cir_mk_ev = mk_ev } -> do { ev' <- rewriteEqEvidence emptyRewriterSet ev IsSwapped (mkReflRedn role rhs) (mkReflRedn role lhs) ; chooseInstance ev' (res { cir_mk_ev = mk_eq_ev cls tys mk_ev }) } - _ -> do { traceTcS "final_qci_check:3" (ppr work_ct) - ; continueWith work_ct }} + _ -> do { traceTcS "lookup_irred_in_qcis:3" (ppr work_ct) + ; continueWith () }} | otherwise - = continueWith work_ct + = continueWith () mk_eq_ev cls tys mk_ev evs | sc_id : rest <- classSCSelIds cls -- Just one superclass for this @@ -2875,6 +2903,19 @@ tryFamFamInjectivity ev eq_rel fun_tc1 fun_args1 fun_tc2 fun_args2 mco = return False -------------------- +tryFunDeps :: EqCt -> SolverStage () +tryFunDeps work_item@(EqCt { eq_lhs = lhs, eq_ev = ev }) + = Stage $ + case lhs of + TyFamLHS tc args -> do { inerts <- getInertCans + ; imp1 <- improveLocalFunEqs inerts tc args work_item + ; imp2 <- improveTopFunEqs tc args work_item + ; if (imp1 || imp2) + then startAgainWith (mkNonCanonical ev) + else continueWith () } + TyVarLHS {} -> continueWith () + +-------------------- improveTopFunEqs :: TyCon -> [TcType] -> EqCt -> TcS Bool -- See Note [FunDep and implicit parameter reactions] improveTopFunEqs fam_tc args (EqCt { eq_ev = ev, eq_rhs = rhs }) diff --git a/compiler/GHC/Tc/Solver/InertSet.hs b/compiler/GHC/Tc/Solver/InertSet.hs index 042e3ff9e3..af812fe6e1 100644 --- a/compiler/GHC/Tc/Solver/InertSet.hs +++ b/compiler/GHC/Tc/Solver/InertSet.hs @@ -31,6 +31,10 @@ module GHC.Tc.Solver.InertSet ( partitionInertEqs, partitionFunEqs, foldFunEqs, + -- * Inert Irreds + InertIrreds, delIrred, extendIrreds, foldIrreds, + findMatchingIrreds, + -- * Kick-out kickOutRewritableLHS, @@ -51,6 +55,7 @@ import GHC.Tc.Utils.TcType import GHC.Types.Var import GHC.Types.Var.Env +import GHC.Types.Basic( SwapFlag(..) ) import GHC.Core.Reduction import GHC.Core.Predicate @@ -319,7 +324,7 @@ emptyInertCans , inert_dicts = emptyDictMap , inert_safehask = emptyDictMap , inert_insts = [] - , inert_irreds = emptyCts } + , inert_irreds = emptyBag } emptyInert :: InertSet emptyInert @@ -1131,7 +1136,7 @@ data InertCans -- See Note [Detailed InertCans Invariants] for more -- ^ See Note [Safe Haskell Overlapping Instances Implementation] -- in GHC.Tc.Solver - , inert_irreds :: Cts + , inert_irreds :: InertIrreds -- Irreducible predicates that cannot be made canonical, -- and which don't interact with others (e.g. (c a)) -- and insoluble predicates (e.g. Int ~ Bool, or a ~ [a]) @@ -1152,6 +1157,7 @@ data InertCans -- See Note [Detailed InertCans Invariants] for more type InertEqs = DTyVarEnv EqualCtList type InertFunEqs = FunEqMap EqualCtList +type InertIrreds = Bag IrredCt instance Outputable InertCans where ppr (IC { inert_eqs = eqs @@ -1174,7 +1180,7 @@ instance Outputable InertCans where text "Dictionaries =" <+> pprBag (dictsToBag dicts) , ppUnless (isEmptyTcAppMap safehask) $ text "Safe Haskell unsafe overlap =" <+> pprBag (dictsToBag safehask) - , ppUnless (isEmptyCts irreds) $ + , ppUnless (isEmptyBag irreds) $ text "Irreds =" <+> pprBag irreds , ppUnless (null insts) $ text "Given instances =" <+> vcat (map ppr insts) @@ -1274,6 +1280,74 @@ extendFunEqs fun_eqs eq_ct@(EqCt { eq_lhs = TyFamLHS tc args }) = addCanFunEq fun_eqs tc args eq_ct extendFunEqs _ other = pprPanic "extendFunEqs" (ppr other) + +{- ********************************************************************* +* * + Inert Irreds +* * +********************************************************************* -} + +extendIrreds :: [IrredCt] -> InertIrreds -> InertIrreds +extendIrreds extras irreds + | null extras = irreds + | otherwise = irreds `unionBags` listToBag extras + +delIrred :: InertCans -> IrredCt -> InertCans +-- Remove a particular (Given) Irred, on the instructions of a plugin +-- For some reason this is done vis the evidence Id, not the type +-- Compare delEq. I have not idea why +delIrred ics (IrredCt { ir_ev = ev }) + = ics { inert_irreds = filterBag keep (inert_irreds ics) } + where + ev_id = ctEvEvId ev + keep (IrredCt { ir_ev = ev' }) = ev_id == ctEvEvId ev' + +foldIrreds :: (IrredCt -> b -> b) -> InertIrreds -> b -> b +foldIrreds k irreds z = foldr k z irreds + +findMatchingIrreds :: InertIrreds -> CtEvidence + -> (Bag (IrredCt, SwapFlag), InertIrreds) +findMatchingIrreds irreds ev + | EqPred eq_rel1 lty1 rty1 <- classifyPredType pred + -- See Note [Solving irreducible equalities] + = partitionBagWith (match_eq eq_rel1 lty1 rty1) irreds + | otherwise + = partitionBagWith match_non_eq irreds + where + pred = ctEvPred ev + match_non_eq irred + | irredCtPred irred `tcEqTypeNoKindCheck` pred = Left (irred, NotSwapped) + | otherwise = Right irred + + match_eq eq_rel1 lty1 rty1 irred + | EqPred eq_rel2 lty2 rty2 <- classifyPredType (irredCtPred irred) + , eq_rel1 == eq_rel2 + , Just swap <- match_eq_help lty1 rty1 lty2 rty2 + = Left (irred, swap) + | otherwise + = Right irred + + match_eq_help lty1 rty1 lty2 rty2 + | lty1 `tcEqTypeNoKindCheck` lty2, rty1 `tcEqTypeNoKindCheck` rty2 + = Just NotSwapped + | lty1 `tcEqTypeNoKindCheck` rty2, rty1 `tcEqTypeNoKindCheck` lty2 + = Just IsSwapped + | otherwise + = Nothing + +{- Note [Solving irreducible equalities] +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +Consider (#14333) + [G] a b ~R# c d + [W] c d ~R# a b +Clearly we should be able to solve this! Even though the constraints are +not decomposable. We solve this when looking up the work-item in the +irreducible constraints to look for an identical one. When doing this +lookup, findMatchingIrreds spots the equality case, and matches either +way around. It has to return a swap-flag so we can generate evidence +that is the right way round too. +-} + {- ********************************************************************* * * Adding to and removing from the inert set @@ -1290,10 +1364,10 @@ addInertItem tc_lvl TyFamLHS tc tys -> ics { inert_funeqs = addCanFunEq funeqs tc tys eq_ct } TyVarLHS tv -> ics { inert_eqs = addTyEq eqs tv eq_ct } -addInertItem tc_lvl ics@(IC { inert_irreds = irreds }) item@(CIrredCan {}) - = updateGivenEqs tc_lvl item $ -- An Irred might turn out to be an +addInertItem tc_lvl ics@(IC { inert_irreds = irreds }) ct@(CIrredCan irred) + = updateGivenEqs tc_lvl ct $ -- An Irred might turn out to be an -- equality, so we play safe - ics { inert_irreds = irreds `snocBag` item } + ics { inert_irreds = irreds `snocBag` irred } addInertItem _ ics item@(CDictCan { cc_class = cls, cc_tyargs = tys }) = ics { inert_dicts = addDict (inert_dicts ics) cls tys item } @@ -1358,7 +1432,7 @@ kickOutRewritableLHS new_fr new_lhs -- constraints, which perhaps may have become soluble after new_lhs -- is substituted; ditto the dictionaries, which may include (a~b) -- or (a~~b) constraints. - kicked_out = (dicts_out `andCts` irs_out) + kicked_out = (dicts_out `andCts` fmap CIrredCan irs_out) `extendCtsList` insts_out `extendCtsList` map CEqCan tv_eqs_out `extendCtsList` map CEqCan feqs_out @@ -1366,7 +1440,7 @@ kickOutRewritableLHS new_fr new_lhs (tv_eqs_out, tv_eqs_in) = partitionInertEqs kick_out_eq tv_eqs (feqs_out, feqs_in) = partitionFunEqs kick_out_eq funeqmap (dicts_out, dicts_in) = partitionDicts kick_out_ct dictmap - (irs_out, irs_in) = partitionBag kick_out_ct irreds + (irs_out, irs_in) = partitionBag (kick_out_ct . CIrredCan) irreds -- Kick out even insolubles: See Note [Rewrite insolubles] -- Of course we must kick out irreducibles like (c a), in case -- we can rewrite 'c' to something more useful @@ -1577,8 +1651,8 @@ noGivenNewtypeReprEqs :: TyCon -> InertSet -> Bool noGivenNewtypeReprEqs tc inerts = not (anyBag might_help (inert_irreds (inert_cans inerts))) where - might_help ct - = case classifyPredType (ctPred ct) of + might_help irred + = case classifyPredType (ctEvPred (irredCtEvidence irred)) of EqPred ReprEq t1 t2 | Just (tc1,_) <- tcSplitTyConApp_maybe t1 , tc == tc1 diff --git a/compiler/GHC/Tc/Solver/Interact.hs b/compiler/GHC/Tc/Solver/Interact.hs index e40478279c..94ab1f6379 100644 --- a/compiler/GHC/Tc/Solver/Interact.hs +++ b/compiler/GHC/Tc/Solver/Interact.hs @@ -175,9 +175,9 @@ runTcPluginsGiven ; if null givens then return [] else do { p <- runTcPluginSolvers solvers (givens,[]) ; let (solved_givens, _) = pluginSolvedCts p - insols = pluginBadCts p - ; updInertCans (removeInertCts solved_givens) - ; updInertIrreds (\irreds -> extendCtsList irreds insols) + insols = map (ctIrredCt PluginReason) (pluginBadCts p) + ; updInertCans (removeInertCts solved_givens) + ; updInertIrreds (extendIrreds insols) ; return (pluginNewCts p) } } } -- | Given a bag of (rewritten, zonked) wanteds, invoke the plugins on @@ -283,11 +283,11 @@ runTcPluginSolvers solvers all_cts (xs `without` cts, ys `without` cts) without :: [Ct] -> [Ct] -> [Ct] - without = deleteFirstsBy eqCt + without = deleteFirstsBy eq_ct - eqCt :: Ct -> Ct -> Bool - eqCt c c' = ctFlavour c == ctFlavour c' - && ctPred c `tcEqType` ctPred c' + eq_ct :: Ct -> Ct -> Bool + eq_ct c c' = ctFlavour c == ctFlavour c' + && ctPred c `tcEqType` ctPred c' add :: [(EvTerm,Ct)] -> SolvedCts -> SolvedCts add xs scs = foldl' addOne scs xs @@ -298,11 +298,8 @@ runTcPluginSolvers solvers all_cts CtWanted {} -> (givens, (ev,ct):wanteds) -type WorkItem = Ct -type SimplifierStage = WorkItem -> TcS (StopOrContinue Ct) - -runSolverPipeline :: [(String,SimplifierStage)] -- The pipeline - -> WorkItem -- The work item +runSolverPipeline :: [(String, Ct -> SolverStage Ct)] -- The pipeline + -> Ct -- The work item -> TcS () -- Run this item down the pipeline, leaving behind new work and inerts runSolverPipeline full_pipeline workItem @@ -330,12 +327,12 @@ runSolverPipeline full_pipeline workItem StartAgain ct -> pprPanic "runSolverPipeline: StartAgain" (ppr ct) } where - run_pipeline :: [(String,SimplifierStage)] -> Ct -> TcS (StopOrContinue Ct) + run_pipeline :: [(String, Ct -> SolverStage Ct)] -> Ct -> TcS (StopOrContinue Ct) run_pipeline [] ct = return (ContinueWith ct) run_pipeline ((stage_name,stage):stages) ct = do { traceTcS ("runStage " ++ stage_name ++ " {") (text "workitem = " <+> ppr ct) - ; res <- stage ct + ; res <- runSolverStage (stage ct) ; traceTcS ("end stage " ++ stage_name ++ " }") (ppr res) ; case res of Stop {} -> return res @@ -367,10 +364,10 @@ React with (a ~ Int) ==> IR (ContinueWith (F Int ~ b)) True [] React with (F Int ~ b) ==> IR Stop True [] -- after substituting we re-canonicalize and get nothing -} -thePipeline :: [(String,SimplifierStage)] -thePipeline = [ ("canonicalization", GHC.Tc.Solver.Canonical.canonicalize) - , ("interact with inerts", interactWithInertsStage) - , ("top-level reactions", topReactionsStage) ] +thePipeline :: [(String, Ct -> SolverStage Ct)] +thePipeline = [ ("canonicalization", GHC.Tc.Solver.Canonical.canonicalize) + , ("interact with inerts", interactWithInertsStage) + , ("top-level reactions", topReactionsStage) ] {- ********************************************************************************* @@ -407,16 +404,17 @@ or, equivalently, -- Interaction result of WorkItem <~> Ct -interactWithInertsStage :: WorkItem -> TcS (StopOrContinue Ct) +interactWithInertsStage :: Ct -> SolverStage Ct -- Precondition: if the workitem is a CEqCan then it will not be able to -- react with anything at this stage (except, maybe, via a type family -- dependency) interactWithInertsStage wi - = do { inerts <- getTcSInerts + = Stage $ + do { inerts <- getTcSInerts ; let ics = inert_cans inerts ; case wi of - CIrredCan {} -> interactIrred ics wi + CIrredCan ir_ct -> interactIrred ics ir_ct CDictCan {} -> interactDict ics wi CEqCan {} -> continueWith wi -- "Canonicalisation" stage is -- full solver for equalities @@ -633,19 +631,20 @@ once had done). This problem can be tickled by typecheck/should_compile/holes. -- we can rewrite them. We can never improve using this: -- if we want ty1 :: Constraint and have ty2 :: Constraint it clearly does not -- mean that (ty1 ~ ty2) -interactIrred :: InertCans -> Ct -> TcS (StopOrContinue Ct) +interactIrred :: InertCans -> IrredCt -> TcS (StopOrContinue Ct) -interactIrred inerts ct_w@(CIrredCan { cc_ev = ev_w, cc_reason = reason }) +interactIrred inerts irred_w@(IrredCt { ir_ev = ev_w, ir_reason = reason }) | isInsolubleReason reason -- For insolubles, don't allow the constraint to be dropped -- which can happen with solveOneFromTheOther, so that -- we get distinct error messages with -fdefer-type-errors - = continueWith ct_w + = carry_on | let (matching_irreds, others) = findMatchingIrreds (inert_irreds inerts) ev_w - , ((ct_i, swap) : _rest) <- bagToList matching_irreds + , ((irred_i, swap) : _rest) <- bagToList matching_irreds -- See Note [Multiple matching irreds] - , let ev_i = ctEvidence ct_i + , let ev_i = irredCtEvidence irred_i + ct_i = CIrredCan irred_i = do { traceTcS "iteractIrred" $ vcat [ text "wanted:" <+> (ppr ct_w $$ ppr (ctOrigin ct_w)) , text "inert: " <+> (ppr ct_i $$ ppr (ctOrigin ct_i)) ] @@ -654,62 +653,21 @@ interactIrred inerts ct_w@(CIrredCan { cc_ev = ev_w, cc_reason = reason }) ; return (Stop ev_w (text "Irred equal:KeepInert" <+> ppr ct_w)) } KeepWork -> do { setEvBindIfWanted ev_i IsCoherent (swap_me swap ev_w) ; updInertIrreds (\_ -> others) - ; continueWith ct_w } } + ; carry_on } } | otherwise - = continueWith ct_w + = carry_on where + ct_w = CIrredCan irred_w + carry_on = continueWith ct_w + swap_me :: SwapFlag -> CtEvidence -> EvTerm swap_me swap ev = case swap of NotSwapped -> ctEvTerm ev IsSwapped -> evCoercion (mkSymCo (evTermCoercion (ctEvTerm ev))) -interactIrred _ wi = pprPanic "interactIrred" (ppr wi) - -findMatchingIrreds :: Cts -> CtEvidence -> (Bag (Ct, SwapFlag), Bag Ct) -findMatchingIrreds irreds ev - | EqPred eq_rel1 lty1 rty1 <- classifyPredType pred - -- See Note [Solving irreducible equalities] - = partitionBagWith (match_eq eq_rel1 lty1 rty1) irreds - | otherwise - = partitionBagWith match_non_eq irreds - where - pred = ctEvPred ev - match_non_eq ct - | ctPred ct `tcEqTypeNoKindCheck` pred = Left (ct, NotSwapped) - | otherwise = Right ct - - match_eq eq_rel1 lty1 rty1 ct - | EqPred eq_rel2 lty2 rty2 <- classifyPredType (ctPred ct) - , eq_rel1 == eq_rel2 - , Just swap <- match_eq_help lty1 rty1 lty2 rty2 - = Left (ct, swap) - | otherwise - = Right ct - - match_eq_help lty1 rty1 lty2 rty2 - | lty1 `tcEqTypeNoKindCheck` lty2, rty1 `tcEqTypeNoKindCheck` rty2 - = Just NotSwapped - | lty1 `tcEqTypeNoKindCheck` rty2, rty1 `tcEqTypeNoKindCheck` lty2 - = Just IsSwapped - | otherwise - = Nothing - -{- Note [Solving irreducible equalities] -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -Consider (#14333) - [G] a b ~R# c d - [W] c d ~R# a b -Clearly we should be able to solve this! Even though the constraints are -not decomposable. We solve this when looking up the work-item in the -irreducible constraints to look for an identical one. When doing this -lookup, findMatchingIrreds spots the equality case, and matches either -way around. It has to return a swap-flag so we can generate evidence -that is the right way round too. --} - {- ********************************************************************************* * * @@ -1229,11 +1187,12 @@ I can think of two ways to fix this: ********************************************************************** -} -topReactionsStage :: WorkItem -> TcS (StopOrContinue Ct) +topReactionsStage :: Ct -> SolverStage Ct -- The work item does not react with the inert set, -- so try interaction with top-level instances. topReactionsStage work_item - = do { traceTcS "doTopReact" (ppr work_item) + = Stage $ + do { traceTcS "doTopReact" (ppr work_item) ; case work_item of CDictCan {} -> diff --git a/compiler/GHC/Tc/Solver/Monad.hs b/compiler/GHC/Tc/Solver/Monad.hs index bfbba18a11..1dce35b00b 100644 --- a/compiler/GHC/Tc/Solver/Monad.hs +++ b/compiler/GHC/Tc/Solver/Monad.hs @@ -33,7 +33,7 @@ module GHC.Tc.Solver.Monad ( -- The pipeline StopOrContinue(..), continueWith, stopWith, andWhenContinue, - startAgainWith, + startAgainWith, SolverStage(Stage, runSolverStage), -- Tracing etc panicTcS, traceTcS, @@ -207,7 +207,7 @@ import GHC.Data.Graph.Directed ********************************************************************* -} data StopOrContinue a - = StartAgain a -- Constraint is not solved, but some unifications + = StartAgain Ct -- Constraint is not solved, but some unifications -- happened, so go back to the beginning of the pipeline | ContinueWith a -- The constraint was not solved, although it may have @@ -223,7 +223,23 @@ instance Outputable a => Outputable (StopOrContinue a) where ppr (ContinueWith w) = text "ContinueWith" <+> ppr w ppr (StartAgain w) = text "StartAgain" <+> ppr w -startAgainWith :: a -> TcS (StopOrContinue a) +newtype SolverStage a = Stage { runSolverStage :: TcS (StopOrContinue a) } + deriving( Functor ) + +instance Applicative SolverStage where + pure x = Stage (return (ContinueWith x)) + (<*>) = ap + +instance Monad SolverStage where + return = pure + (Stage m) >>= k = Stage $ + do { soc <- m + ; case soc of + StartAgain x -> return (StartAgain x) + Stop ev d -> return (Stop ev d) + ContinueWith x -> runSolverStage (k x) } + +startAgainWith :: Ct -> TcS (StopOrContinue a) startAgainWith ct = return (StartAgain ct) continueWith :: a -> TcS (StopOrContinue a) @@ -434,7 +450,7 @@ kickOutAfterFillingCoercionHole hole n_kicked = lengthBag kicked_out ; unless (n_kicked == 0) $ - do { updWorkListTcS (extendWorkListCts kicked_out) + do { updWorkListTcS (extendWorkListCts (fmap CIrredCan kicked_out)) ; csTraceTcS $ hang (text "Kick out, hole =" <+> ppr hole) 2 (vcat [ text "n-kicked =" <+> int n_kicked @@ -443,16 +459,16 @@ kickOutAfterFillingCoercionHole hole ; setInertCans ics' } where - kick_out :: InertCans -> (Cts, InertCans) + kick_out :: InertCans -> (Bag IrredCt, InertCans) kick_out ics@(IC { inert_irreds = irreds }) = (irreds_to_kick, ics { inert_irreds = irreds_to_keep }) where (irreds_to_kick, irreds_to_keep) = partitionBag kick_ct irreds - kick_ct :: Ct -> Bool + kick_ct :: IrredCt -> Bool -- True: kick out; False: keep. kick_ct ct - | CIrredCan { cc_ev = ev, cc_reason = reason } <- ct + | IrredCt { ir_ev = ev, ir_reason = reason } <- ct , CtWanted { ctev_rewriters = RewriterSet rewriters } <- ev , NonCanonicalReason ctyeq <- reason , ctyeq `cterHasProblem` cteCoercionHole @@ -545,7 +561,7 @@ updInertSafehask :: (DictMap Ct -> DictMap Ct) -> TcS () updInertSafehask upd_fn = updInertCans $ \ ics -> ics { inert_safehask = upd_fn (inert_safehask ics) } -updInertIrreds :: (Cts -> Cts) -> TcS () +updInertIrreds :: (Bag IrredCt -> Bag IrredCt) -> TcS () -- Modify the inert set with the supplied function updInertIrreds upd_fn = updInertCans $ \ ics -> ics { inert_irreds = upd_fn (inert_irreds ics) } @@ -572,19 +588,20 @@ getInnermostGivenEqLevel = do { inert <- getInertCans -- want to consider a pattern match that introduces insoluble Givens to be -- redundant (see Note [Pattern match warnings with insoluble Givens] in GHC.Tc.Solver). getInertInsols :: TcS Cts -getInertInsols = do { inert <- getInertCans - ; let irreds = inert_irreds inert - unsats = findDictsByTyConKey (inert_dicts inert) unsatisfiableClassNameKey - ; return $ unsats `unionBags` filterBag insolubleCt irreds } +getInertInsols + = do { inert <- getInertCans + ; let insols = filterBag insolubleIrredCt (inert_irreds inert) + unsats = findDictsByTyConKey (inert_dicts inert) unsatisfiableClassNameKey + ; return $ unsats `unionBags` fmap CIrredCan insols } getInertGivens :: TcS [Ct] -- Returns the Given constraints in the inert set getInertGivens = do { inerts <- getInertCans - ; let all_cts = foldIrreds (:) (inert_irreds inerts) - $ foldDicts (:) (inert_dicts inerts) - $ foldFunEqs ((:) . CEqCan) (inert_funeqs inerts) - $ foldTyEqs ((:) . CEqCan) (inert_eqs inerts) + ; let all_cts = foldIrreds ((:) . CIrredCan) (inert_irreds inerts) + $ foldDicts (:) (inert_dicts inerts) + $ foldFunEqs ((:) . CEqCan) (inert_funeqs inerts) + $ foldTyEqs ((:) . CEqCan) (inert_eqs inerts) $ [] ; return (filter isGivenCt all_cts) } @@ -659,10 +676,10 @@ getUnsolvedInerts ; let unsolved_tv_eqs = foldTyEqs add_if_unsolved_eq tv_eqs emptyCts unsolved_fun_eqs = foldFunEqs add_if_unsolved_eq fun_eqs emptyCts - unsolved_irreds = Bag.filterBag isWantedCt irreds + unsolved_irreds = Bag.filterBag (isWanted . irredCtEvidence) irreds unsolved_dicts = foldDicts add_if_unsolved idicts emptyCts - unsolved_others = unionManyBags [ unsolved_irreds - , unsolved_dicts ] + unsolved_others = fmap CIrredCan unsolved_irreds `unionBags` + unsolved_dicts ; implics <- getWorkListImplics @@ -684,9 +701,9 @@ getUnsolvedInerts add_if_unsolved_eq eq_ct cts | isWanted (eq_ev eq_ct) = CEqCan eq_ct `consCts` cts | otherwise = cts -getHasGivenEqs :: TcLevel -- TcLevel of this implication - -> TcS ( HasGivenEqs -- are there Given equalities? - , Cts ) -- Insoluble equalities arising from givens +getHasGivenEqs :: TcLevel -- TcLevel of this implication + -> TcS ( HasGivenEqs -- are there Given equalities? + , InertIrreds ) -- Insoluble equalities arising from givens -- See Note [Tracking Given equalities] in GHC.Tc.Solver.InertSet getHasGivenEqs tclvl = do { inerts@(IC { inert_irreds = irreds @@ -712,8 +729,9 @@ getHasGivenEqs tclvl , text "Insols:" <+> ppr given_insols] ; return (has_ge, given_insols) } where - insoluble_given_equality ct - = insolubleEqCt ct && isGivenCt ct + insoluble_given_equality :: IrredCt -> Bool + insoluble_given_equality irred + = insolubleIrredCt irred && isGiven (irredCtEvidence irred) removeInertCts :: [Ct] -> InertCans -> InertCans -- ^ Remove inert constraints from the 'InertCans', for use when a @@ -727,17 +745,11 @@ removeInertCt is ct = CDictCan { cc_class = cl, cc_tyargs = tys } -> is { inert_dicts = delDict (inert_dicts is) cl tys } - CEqCan eq_ct -> delEq is eq_ct - - CIrredCan {} -> is { inert_irreds = filterBag (not . eqCt ct) $ inert_irreds is } - + CEqCan eq_ct -> delEq is eq_ct + CIrredCan ir_ct -> delIrred is ir_ct CQuantCan {} -> panic "removeInertCt: CQuantCan" CNonCanonical {} -> panic "removeInertCt: CNonCanonical" -eqCt :: Ct -> Ct -> Bool --- Equality via ctEvId -eqCt c c' = ctEvId c == ctEvId c' - -- | Looks up a family application in the inerts. lookupFamAppInert :: (CtFlavourRole -> Bool) -- can it rewrite the target? -> TyCon -> [Type] -> TcS (Maybe (Reduction, CtFlavourRole)) @@ -820,15 +832,6 @@ dropFromFamAppCache varset check redn = not (anyFreeVarsOfCo (`elemVarSet` varset) $ reductionCoercion redn) -{- ********************************************************************* -* * - Irreds -* * -********************************************************************* -} - -foldIrreds :: (Ct -> b -> b) -> Cts -> b -> b -foldIrreds k irreds z = foldr k z irreds - {- ************************************************************************ * * diff --git a/compiler/GHC/Tc/Solver/Rewrite.hs b/compiler/GHC/Tc/Solver/Rewrite.hs index 64d590cbe9..0a30379303 100644 --- a/compiler/GHC/Tc/Solver/Rewrite.hs +++ b/compiler/GHC/Tc/Solver/Rewrite.hs @@ -92,9 +92,9 @@ runRewriteCtEv ev runRewrite :: CtLoc -> CtFlavour -> EqRel -> RewriteM a -> TcS (a, RewriterSet) runRewrite loc flav eq_rel thing_inside = do { rewriters_ref <- newTcRef emptyRewriterSet - ; let fmode = RE { re_loc = loc - , re_flavour = flav - , re_eq_rel = eq_rel + ; let fmode = RE { re_loc = loc + , re_flavour = flav + , re_eq_rel = eq_rel , re_rewriters = rewriters_ref } ; res <- runRewriteM thing_inside fmode ; rewriters <- readTcRef rewriters_ref diff --git a/compiler/GHC/Tc/Types/Constraint.hs b/compiler/GHC/Tc/Types/Constraint.hs index 9ab842df98..e43b3b16a8 100644 --- a/compiler/GHC/Tc/Types/Constraint.hs +++ b/compiler/GHC/Tc/Types/Constraint.hs @@ -18,17 +18,19 @@ module GHC.Tc.Types.Constraint ( isWantedCt, isGivenCt, isTopLevelUserTypeError, containsUserTypeError, getUserTypeErrorMsg, isUnsatisfiableCt_maybe, - ctEvidence, ctLoc, ctPred, ctFlavour, ctEqRel, ctOrigin, + ctEvidence, updCtEvidence, + ctLoc, ctPred, ctFlavour, ctEqRel, ctOrigin, ctRewriters, ctEvId, wantedEvId_maybe, mkTcEqPredLikeEv, - mkNonCanonical, mkNonCanonicalCt, mkGivens, - mkIrredCt, + mkNonCanonical, mkGivens, ctEvPred, ctEvLoc, ctEvOrigin, ctEvEqRel, ctEvExpr, ctEvTerm, ctEvCoercion, ctEvEvId, ctEvRewriters, tyCoVarsOfCt, tyCoVarsOfCts, tyCoVarsOfCtList, tyCoVarsOfCtsList, + IrredCt(..), mkIrredCt, ctIrredCt, irredCtEvidence, irredCtPred, + ExpansionFuel, doNotExpand, consumeFuel, pendingFuel, assertFuelPrecondition, assertFuelPreconditionStrict, @@ -54,8 +56,8 @@ module GHC.Tc.Types.Constraint ( isSolvedWC, andWC, unionsWC, mkSimpleWC, mkImplicWC, addInsols, dropMisleading, addSimples, addImplics, addHoles, addNotConcreteError, addDelayedErrors, - tyCoVarsOfWC, - tyCoVarsOfWCList, insolubleWantedCt, insolubleEqCt, insolubleCt, + tyCoVarsOfWC, tyCoVarsOfWCList, + insolubleWantedCt, insolubleEqCt, insolubleCt, insolubleIrredCt, insolubleImplic, nonDefaultableTyVarsOfWC, Implication(..), implicationPrototype, checkTelescopeSkol, @@ -207,30 +209,10 @@ data Ct -- (b) those superclasses are not yet explored } - | CIrredCan { -- These stand for yet-unusable predicates - cc_ev :: CtEvidence, -- See Note [Ct/evidence invariant] - cc_reason :: CtIrredReason - - -- For the might-be-soluble case, the ctev_pred of the evidence is - -- of form (tv xi1 xi2 ... xin) with a tyvar at the head - -- or (lhs1 ~ ty2) where the CEqCan kind invariant (TyEq:K) fails - -- See Note [CIrredCan constraints] - - -- The definitely-insoluble case is for things like - -- Int ~ Bool tycons don't match - -- a ~ [a] occurs check - } - - | CNonCanonical { -- See Note [NonCanonical Semantics] in GHC.Tc.Solver.Monad - cc_ev :: CtEvidence - } - - | CEqCan EqCt -- A canonical equality constraint - - | CQuantCan QCInst -- A quantified constraint - -- NB: I expect to make more of the cases in Ct - -- look like this, with the payload in an - -- auxiliary type + | CNonCanonical CtEvidence -- See Note [NonCanonical Semantics] in GHC.Tc.Solver.Monad + | CIrredCan IrredCt -- A "irreducible" constraint (non-canonical) + | CEqCan EqCt -- A canonical equality constraint + | CQuantCan QCInst -- A quantified constraint {- Note [Canonical equalities] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -308,6 +290,29 @@ instance Outputable CanEqLHS where ppr (TyFamLHS fam_tc fam_args) = ppr (mkTyConApp fam_tc fam_args) ------------ +data IrredCt -- These stand for yet-unusable predicates + -- See Note [CIrredCan constraints] + = IrredCt { ir_ev :: CtEvidence -- See Note [Ct/evidence invariant] + , ir_reason :: CtIrredReason } + +mkIrredCt :: CtIrredReason -> CtEvidence -> Ct +mkIrredCt reason ev = CIrredCan (IrredCt { ir_ev = ev, ir_reason = reason }) + +irredCtEvidence :: IrredCt -> CtEvidence +irredCtEvidence = ir_ev + +irredCtPred :: IrredCt -> PredType +irredCtPred = ctEvPred . irredCtEvidence + +ctIrredCt :: CtIrredReason -> Ct -> IrredCt +ctIrredCt _ (CIrredCan ir) = ir +ctIrredCt reason ct = IrredCt { ir_ev = ctEvidence ct + , ir_reason = reason } + +instance Outputable IrredCt where + ppr irred = ppr (CIrredCan irred) + +------------ data QCInst -- A much simplified version of ClsInst -- See Note [Quantified constraints] in GHC.Tc.Solver.Canonical = QCI { qci_ev :: CtEvidence -- Always of type forall tvs. context => ty @@ -461,12 +466,17 @@ data CtIrredReason -- in GHC.Core.TyCon. -- INVARIANT: The constraint is an equality constraint between two TyConApps + | PluginReason + -- ^ a typechecker plugin returned this in the pluginBagCts field + -- of TcPluginProgress + instance Outputable CtIrredReason where ppr IrredShapeReason = text "(irred)" ppr (NonCanonicalReason cter) = ppr cter ppr ReprEqReason = text "(repr)" ppr ShapeMismatchReason = text "(shape)" ppr AbstractTyConReason = text "(abstc)" + ppr PluginReason = text "(plugin)" -- | Are we sure that more solving will never solve this constraint? isInsolubleReason :: CtIrredReason -> Bool @@ -475,6 +485,7 @@ isInsolubleReason (NonCanonicalReason cter) = cterIsInsoluble cter isInsolubleReason ReprEqReason = False isInsolubleReason ShapeMismatchReason = True isInsolubleReason AbstractTyConReason = True +isInsolubleReason PluginReason = True ------------------------------------------------------------------------------ -- @@ -675,13 +686,7 @@ Type-level holes have no evidence at all. -} mkNonCanonical :: CtEvidence -> Ct -mkNonCanonical ev = CNonCanonical { cc_ev = ev } - -mkNonCanonicalCt :: Ct -> Ct -mkNonCanonicalCt ct = CNonCanonical { cc_ev = cc_ev ct } - -mkIrredCt :: CtIrredReason -> CtEvidence -> Ct -mkIrredCt reason ev = CIrredCan { cc_ev = ev, cc_reason = reason } +mkNonCanonical ev = CNonCanonical ev mkGivens :: CtLoc -> [EvId] -> [Ct] mkGivens loc ev_ids @@ -692,9 +697,20 @@ mkGivens loc ev_ids , ctev_loc = loc }) ctEvidence :: Ct -> CtEvidence -ctEvidence (CQuantCan (QCI { qci_ev = ev })) = ev -ctEvidence (CEqCan (EqCt { eq_ev = ev })) = ev -ctEvidence ct = cc_ev ct +ctEvidence (CQuantCan (QCI { qci_ev = ev })) = ev +ctEvidence (CEqCan (EqCt { eq_ev = ev })) = ev +ctEvidence (CIrredCan (IrredCt { ir_ev = ev })) = ev +ctEvidence (CNonCanonical ev) = ev +ctEvidence (CDictCan { cc_ev = ev }) = ev + +updCtEvidence :: (CtEvidence -> CtEvidence) -> Ct -> Ct +updCtEvidence upd ct + = case ct of + CQuantCan qci@(QCI { qci_ev = ev }) -> CQuantCan (qci { qci_ev = upd ev }) + CEqCan eq@(EqCt { eq_ev = ev }) -> CEqCan (eq { eq_ev = upd ev }) + CIrredCan ir@(IrredCt { ir_ev = ev }) -> CIrredCan (ir { ir_ev = upd ev }) + CNonCanonical ev -> CNonCanonical (upd ev) + CDictCan { cc_ev = ev } -> ct { cc_ev = upd ev } ctLoc :: Ct -> CtLoc ctLoc = ctEvLoc . ctEvidence @@ -753,7 +769,7 @@ instance Outputable Ct where CDictCan { cc_pend_sc = psc } | psc > 0 -> text "CDictCan" <> parens (text "psc" <+> ppr psc) | otherwise -> text "CDictCan" - CIrredCan { cc_reason = reason } -> text "CIrredCan" <> ppr reason + CIrredCan (IrredCt { ir_reason = reason }) -> text "CIrredCan" <> ppr reason CQuantCan (QCI { qci_pend_sc = psc }) | psc > 0 -> text "CQuantCan" <> parens (text "psc" <+> ppr psc) | otherwise -> text "CQuantCan" @@ -1168,9 +1184,9 @@ addSimples wc cts addImplics :: WantedConstraints -> Bag Implication -> WantedConstraints addImplics wc implic = wc { wc_impl = wc_impl wc `unionBags` implic } -addInsols :: WantedConstraints -> Bag Ct -> WantedConstraints -addInsols wc cts - = wc { wc_simple = wc_simple wc `unionBags` cts } +addInsols :: WantedConstraints -> Bag IrredCt -> WantedConstraints +addInsols wc insols + = wc { wc_simple = wc_simple wc `unionBags` fmap CIrredCan insols } addHoles :: WantedConstraints -> Bag Hole -> WantedConstraints addHoles wc holes @@ -1305,8 +1321,12 @@ insolubleEqCt :: Ct -> Bool -- True for Int ~ F a Int -- but False for Maybe Int ~ F a Int Int -- (where F is an arity-1 type function) -insolubleEqCt (CIrredCan { cc_reason = reason }) = isInsolubleReason reason -insolubleEqCt _ = False +insolubleEqCt (CIrredCan ir_ct) = insolubleIrredCt ir_ct +insolubleEqCt _ = False + +insolubleIrredCt :: IrredCt -> Bool +insolubleIrredCt (IrredCt { ir_reason = reason }) + = isInsolubleReason reason -- | Returns True of equality constraints that are definitely insoluble, -- as well as TypeError constraints. diff --git a/compiler/GHC/Tc/Utils/Monad.hs b/compiler/GHC/Tc/Utils/Monad.hs index 75b74cbb35..12a898ec93 100644 --- a/compiler/GHC/Tc/Utils/Monad.hs +++ b/compiler/GHC/Tc/Utils/Monad.hs @@ -105,7 +105,7 @@ module GHC.Tc.Utils.Monad( chooseUniqueOccTc, getConstraintVar, setConstraintVar, emitConstraints, emitStaticConstraints, emitSimple, emitSimples, - emitImplication, emitImplications, emitInsoluble, + emitImplication, emitImplications, emitDelayedErrors, emitHole, emitHoles, emitNotConcreteError, discardConstraints, captureConstraints, tryCaptureConstraints, pushLevelAndCaptureConstraints, @@ -1825,12 +1825,6 @@ emitImplications ct do { lie_var <- getConstraintVar ; updTcRef lie_var (`addImplics` ct) } -emitInsoluble :: Ct -> TcM () -emitInsoluble ct - = do { traceTc "emitInsoluble" (ppr ct) - ; lie_var <- getConstraintVar - ; updTcRef lie_var (`addInsols` unitBag ct) } - emitDelayedErrors :: Bag DelayedError -> TcM () emitDelayedErrors errs = do { traceTc "emitDelayedErrors" (ppr errs) diff --git a/compiler/GHC/Tc/Utils/TcMType.hs b/compiler/GHC/Tc/Utils/TcMType.hs index 7db80cfccb..4d2dcdcba8 100644 --- a/compiler/GHC/Tc/Utils/TcMType.hs +++ b/compiler/GHC/Tc/Utils/TcMType.hs @@ -2463,9 +2463,9 @@ zonkCt ct@(CDictCan { cc_ev = ev, cc_tyargs = args }) zonkCt (CEqCan (EqCt { eq_ev = ev })) = mkNonCanonical <$> zonkCtEvidence ev -zonkCt ct@(CIrredCan { cc_ev = ev }) -- Preserve the cc_reason flag +zonkCt (CIrredCan ir@(IrredCt { ir_ev = ev })) -- Preserve the cc_reason flag = do { ev' <- zonkCtEvidence ev - ; return (ct { cc_ev = ev' }) } + ; return (CIrredCan (ir { ir_ev = ev' })) } zonkCt ct = do { fl' <- zonkCtEvidence (ctEvidence ct) @@ -2694,7 +2694,7 @@ zonkTidyFRRInfos = go [] ---------------- tidyCt :: TidyEnv -> Ct -> Ct -- Used only in error reporting -tidyCt env ct = ct { cc_ev = tidyCtEvidence env (ctEvidence ct) } +tidyCt env ct = updCtEvidence (tidyCtEvidence env) ct tidyCtEvidence :: TidyEnv -> CtEvidence -> CtEvidence -- NB: we do not tidy the ctev_evar field because we don't @@ -2792,16 +2792,18 @@ naughtyQuantification orig_ty tv escapees zonkCtRewriterSet :: Ct -> TcM Ct zonkCtRewriterSet ct - | isGiven ev = return ct + | isGivenCt ct = return ct | otherwise = case ct of - CQuantCan {} -> return ct - CEqCan eq@(EqCt { eq_ev = ev }) -> do { ev' <- zonkCtEvRewriterSet ev - ; return (CEqCan (eq { eq_ev = ev' })) } - _ -> do { ev' <- zonkCtEvRewriterSet ev - ; return (ct { cc_ev = ev' }) } - where - ev = ctEvidence ct + CEqCan eq@(EqCt { eq_ev = ev }) -> do { ev' <- zonkCtEvRewriterSet ev + ; return (CEqCan (eq { eq_ev = ev' })) } + CIrredCan ir@(IrredCt { ir_ev = ev }) -> do { ev' <- zonkCtEvRewriterSet ev + ; return (CIrredCan (ir { ir_ev = ev' })) } + CNonCanonical ev -> do { ev' <- zonkCtEvRewriterSet ev + ; return (CNonCanonical ev') } + CDictCan { cc_ev = ev } -> do { ev' <- zonkCtEvRewriterSet ev + ; return (ct { cc_ev = ev' }) } + CQuantCan {} -> return ct zonkCtEvRewriterSet :: CtEvidence -> TcM CtEvidence zonkCtEvRewriterSet ev@(CtGiven {}) |