Simon Peyton Jones pushed to branch wip/T23162-part2 at Glasgow Haskell Compiler / GHC
Commits:
-
4475b266
by Simon Peyton Jones at 2025-12-10T13:01:13+00:00
5 changed files:
- compiler/GHC/Tc/Errors.hs
- compiler/GHC/Tc/Errors/Types.hs
- compiler/GHC/Tc/Solver.hs
- compiler/GHC/Tc/Solver/Monad.hs
- compiler/GHC/Tc/Utils/Monad.hs
Changes:
| ... | ... | @@ -87,7 +87,7 @@ import qualified GHC.Data.Strict as Strict |
| 87 | 87 | |
| 88 | 88 | import Language.Haskell.Syntax.Basic (FieldLabelString(..))
|
| 89 | 89 | |
| 90 | -import Control.Monad ( unless, when, foldM, forM_ )
|
|
| 90 | +import Control.Monad ( when, foldM, forM_ )
|
|
| 91 | 91 | import Data.Bifunctor ( bimap )
|
| 92 | 92 | import Data.Foldable ( toList )
|
| 93 | 93 | import Data.Function ( on )
|
| ... | ... | @@ -482,12 +482,15 @@ mkErrorItem ct |
| 482 | 482 | CIrredCan (IrredCt { ir_reason = reason }) -> Just reason
|
| 483 | 483 | _ -> Nothing
|
| 484 | 484 | |
| 485 | - ; return $ Just $ EI { ei_pred = ctPred ct
|
|
| 486 | - , ei_evdest = m_evdest
|
|
| 487 | - , ei_flavour = flav
|
|
| 488 | - , ei_loc = loc
|
|
| 489 | - , ei_m_reason = m_reason
|
|
| 490 | - , ei_suppress = suppress }}
|
|
| 485 | + insoluble_ct = insolubleCt ct
|
|
| 486 | + |
|
| 487 | + ; return $ Just $ EI { ei_pred = ctPred ct
|
|
| 488 | + , ei_evdest = m_evdest
|
|
| 489 | + , ei_flavour = flav
|
|
| 490 | + , ei_loc = loc
|
|
| 491 | + , ei_m_reason = m_reason
|
|
| 492 | + , ei_insoluble = insoluble_ct
|
|
| 493 | + , ei_suppress = suppress }}
|
|
| 491 | 494 | |
| 492 | 495 | -- | Actually report this 'ErrorItem'.
|
| 493 | 496 | unsuppressErrorItem :: ErrorItem -> ErrorItem
|
| ... | ... | @@ -648,7 +651,7 @@ reportWanteds ctxt tc_lvl wc@(WC { wc_simple = simples, wc_impl = implics |
| 648 | 651 | , ("Homo eqs", is_homo_equality, True, mkGroupReporter mkEqErr)
|
| 649 | 652 | , ("Other eqs", is_equality, True, mkGroupReporter mkEqErr)
|
| 650 | 653 | |
| 651 | - , ("Insoluble fundeps", is_insoluble_fundep, True, mkGroupReporter mkDictErr)
|
|
| 654 | + , ("Insoluble fundeps", is_insoluble, True, mkGroupReporter mkDictErr)
|
|
| 652 | 655 | ]
|
| 653 | 656 | |
| 654 | 657 | -- report2: we suppress these if there are insolubles elsewhere in the tree
|
| ... | ... | @@ -666,9 +669,7 @@ reportWanteds ctxt tc_lvl wc@(WC { wc_simple = simples, wc_impl = implics |
| 666 | 669 | -- I think all given residuals are equalities
|
| 667 | 670 | |
| 668 | 671 | -- Constraints that have insoluble functional dependencies
|
| 669 | - is_insoluble_fundep item _ = case ei_m_reason item of
|
|
| 670 | - Just InsolubleFunDepReason -> True
|
|
| 671 | - _ -> False
|
|
| 672 | + is_insoluble item _ = ei_insoluble item
|
|
| 672 | 673 | |
| 673 | 674 | -- Things like (Int ~N Bool)
|
| 674 | 675 | utterly_wrong _ (EqPred NomEq ty1 ty2) = isRigidTy ty1 && isRigidTy ty2
|
| ... | ... | @@ -1305,18 +1306,30 @@ maybeReportError :: SolverReportErrCtxt |
| 1305 | 1306 | maybeReportError ctxt items@(item1:|_) (SolverReport { sr_important_msg = important
|
| 1306 | 1307 | , sr_supplementary = supp
|
| 1307 | 1308 | , sr_hints = hints })
|
| 1308 | - = unless (cec_suppress ctxt -- Some worse error has occurred, so suppress this diagnostic
|
|
| 1309 | - || all ei_suppress items) $
|
|
| 1310 | - -- if they're all to be suppressed, report nothing
|
|
| 1311 | - -- if at least one is not suppressed, do report:
|
|
| 1312 | - -- the function that generates the error message
|
|
| 1313 | - -- should look for an unsuppressed error item
|
|
| 1314 | - do let reason | any (nonDeferrableOrigin . errorItemOrigin) items = ErrorWithoutFlag
|
|
| 1315 | - | otherwise = cec_defer_type_errors ctxt
|
|
| 1316 | - -- See Note [No deferring for multiplicity errors]
|
|
| 1317 | - diag = TcRnSolverReport important reason
|
|
| 1318 | - msg <- mkErrorReport (ctLocEnv (errorItemCtLoc item1)) diag (Just ctxt) supp hints
|
|
| 1319 | - reportDiagnostic msg
|
|
| 1309 | + | suppress_group = return ()
|
|
| 1310 | + | otherwise = do { msg <- mkErrorReport loc_env diag (Just ctxt) supp hints
|
|
| 1311 | + ; reportDiagnostic msg }
|
|
| 1312 | + where
|
|
| 1313 | + reason | any (nonDeferrableOrigin . errorItemOrigin) items = ErrorWithoutFlag
|
|
| 1314 | + | otherwise = cec_defer_type_errors ctxt
|
|
| 1315 | + -- See Note [No deferring for multiplicity errors]
|
|
| 1316 | + diag = TcRnSolverReport important reason
|
|
| 1317 | + loc_env = ctLocEnv (errorItemCtLoc item1)
|
|
| 1318 | + |
|
| 1319 | + suppress_group
|
|
| 1320 | + | all ei_suppress items
|
|
| 1321 | + = True -- If they are all suppressed (notably, have been rewritten by another unsolved wanted)
|
|
| 1322 | + -- report nothing. (If at least one is not suppressed, do report: the function that
|
|
| 1323 | + -- generates the error message should look for an unsuppressed error item.)
|
|
| 1324 | + |
|
| 1325 | + | any ei_insoluble items
|
|
| 1326 | + = False -- Don't suppress insolubles even if cec_suppress is True
|
|
| 1327 | + |
|
| 1328 | + | cec_suppress ctxt
|
|
| 1329 | + = True -- Some earlier error has occurred, so suppress this diagnostic
|
|
| 1330 | + |
|
| 1331 | + | otherwise
|
|
| 1332 | + = False
|
|
| 1320 | 1333 | |
| 1321 | 1334 | addSolverDeferredBinding :: SolverReport -> ErrorItem -> TcM ()
|
| 1322 | 1335 | addSolverDeferredBinding err item =
|
| ... | ... | @@ -2089,7 +2102,7 @@ misMatchOrCND :: SolverReportErrCtxt -> ErrorItem |
| 2089 | 2102 | -> TcType -> TcType -> TcM MismatchMsg
|
| 2090 | 2103 | -- If oriented then ty1 is actual, ty2 is expected
|
| 2091 | 2104 | misMatchOrCND ctxt item ty1 ty2
|
| 2092 | - | insoluble_item -- See Note [Insoluble mis-match]
|
|
| 2105 | + | ei_insoluble item -- See Note [Insoluble mis-match]
|
|
| 2093 | 2106 | || (isRigidTy ty1 && isRigidTy ty2)
|
| 2094 | 2107 | || (ei_flavour item == Given)
|
| 2095 | 2108 | || null givens
|
| ... | ... | @@ -2101,10 +2114,6 @@ misMatchOrCND ctxt item ty1 ty2 |
| 2101 | 2114 | = mkCouldNotDeduceErr givens (item :| []) (Just $ CND_ExpectedActual level ty1 ty2)
|
| 2102 | 2115 | |
| 2103 | 2116 | where
|
| 2104 | - insoluble_item = case ei_m_reason item of
|
|
| 2105 | - Nothing -> False
|
|
| 2106 | - Just r -> isInsolubleReason r
|
|
| 2107 | - |
|
| 2108 | 2117 | level = ctLocTypeOrKind_maybe (errorItemCtLoc item) `orElse` TypeLevel
|
| 2109 | 2118 | givens = [ given | given <- getUserGivens ctxt, ic_given_eqs given /= NoGivenEqs ]
|
| 2110 | 2119 | -- Keep only UserGivens that have some equalities.
|
| ... | ... | @@ -5438,7 +5438,10 @@ data ErrorItem |
| 5438 | 5438 | , ei_loc :: CtLoc
|
| 5439 | 5439 | , ei_m_reason :: Maybe CtIrredReason -- If this ErrorItem was made from a
|
| 5440 | 5440 | -- CtIrred, this stores the reason
|
| 5441 | - , ei_suppress :: Bool -- Suppress because of
|
|
| 5441 | + , ei_insoluble :: Bool -- True if the constraint is defdinitely insoluble
|
|
| 5442 | + -- Cache of `insolubleCt`
|
|
| 5443 | + |
|
| 5444 | + , ei_suppress :: Bool -- Suppress because of
|
|
| 5442 | 5445 | -- Note [Wanteds rewrite Wanteds: rewriter-sets]
|
| 5443 | 5446 | -- in GHC.Tc.Constraint
|
| 5444 | 5447 | }
|
| ... | ... | @@ -723,28 +723,46 @@ they can still be solved: |
| 723 | 723 | -}
|
| 724 | 724 | |
| 725 | 725 | tcCheckGivens :: InertSet -> Bag EvVar -> TcM (Maybe InertSet)
|
| 726 | --- ^ Return (Just new_inerts) if the Givens are satisfiable, Nothing if definitely
|
|
| 727 | --- contradictory.
|
|
| 726 | +-- ^ Return (Just new_inerts) if the Givens are satisfiable,
|
|
| 727 | +-- Nothing if definitely contradictory.
|
|
| 728 | +-- So Nothing says something definite; if in doubt return Just
|
|
| 728 | 729 | --
|
| 729 | 730 | -- See Note [Pattern match warnings with insoluble Givens] above.
|
| 730 | -tcCheckGivens inerts given_ids = do
|
|
| 731 | - mb_res <- tryM $ runTcSInerts inerts $ do
|
|
| 732 | - traceTcS "checkGivens {" (ppr inerts <+> ppr given_ids)
|
|
| 733 | - lcl_env <- TcS.getLclEnv
|
|
| 734 | - let given_loc = mkGivenLoc topTcLevel (getSkolemInfo unkSkol) (mkCtLocEnv lcl_env)
|
|
| 735 | - let given_cts = mkGivens given_loc (bagToList given_ids)
|
|
| 736 | - -- See Note [Superclasses and satisfiability]
|
|
| 737 | - solveSimpleGivens given_cts
|
|
| 738 | - insols <- getInertInsols
|
|
| 739 | - insols <- try_harder insols
|
|
| 740 | - traceTcS "checkGivens }" (ppr insols)
|
|
| 741 | - return (isEmptyBag insols)
|
|
| 742 | - case mb_res of
|
|
| 743 | - Left _ -> return (Just inerts)
|
|
| 744 | - Right (sat, new_inerts)
|
|
| 745 | - | sat -> return (Just new_inerts)
|
|
| 746 | - | otherwise -> return Nothing -- Definitely unsatisfiable
|
|
| 731 | +tcCheckGivens inerts given_ids
|
|
| 732 | + = do { traceTc "checkGivens {" (ppr inerts <+> ppr given_ids)
|
|
| 733 | + |
|
| 734 | + ; lcl_env <- TcM.getLclEnv
|
|
| 735 | + ; let given_loc = mkGivenLoc topTcLevel (getSkolemInfo unkSkol) (mkCtLocEnv lcl_env)
|
|
| 736 | + given_cts = mkGivens given_loc (bagToList given_ids)
|
|
| 737 | + -- See Note [Superclasses and satisfiability]
|
|
| 738 | + |
|
| 739 | + ; mb_res <- tryM $ -- try_to_solve may throw an exception;
|
|
| 740 | + -- e.g. reduction stack overflow
|
|
| 741 | + discardErrs $ -- An exception id not an error;
|
|
| 742 | + -- just means "not definitely unsat"
|
|
| 743 | + runTcSInerts inerts $
|
|
| 744 | + try_to_solve given_cts
|
|
| 745 | + |
|
| 746 | + -- If mb_res = Left err, solving threw an exception, e.g. reduction stack
|
|
| 747 | + -- overflow. So return the original incoming inerts to say "not definitely
|
|
| 748 | + -- unsatisfiable".
|
|
| 749 | + ; let res = case mb_res of
|
|
| 750 | + Right res -> res
|
|
| 751 | + Left {} -> Just inerts
|
|
| 752 | + |
|
| 753 | + ; traceTc "checkGivens }" (ppr res)
|
|
| 754 | + ; return res }
|
|
| 755 | + |
|
| 747 | 756 | where
|
| 757 | + try_to_solve :: [Ct] -> TcS (Maybe InertSet)
|
|
| 758 | + try_to_solve given_cts
|
|
| 759 | + = do { solveSimpleGivens given_cts
|
|
| 760 | + ; insols <- getInertInsols
|
|
| 761 | + ; insols <- try_harder insols
|
|
| 762 | + ; if isEmptyBag insols
|
|
| 763 | + then do { new_inerts <- getInertSet; return (Just new_inerts) }
|
|
| 764 | + else return Nothing } -- Definitely unsatisfiable
|
|
| 765 | + |
|
| 748 | 766 | try_harder :: Cts -> TcS Cts
|
| 749 | 767 | -- Maybe we have to search up the superclass chain to find
|
| 750 | 768 | -- an unsatisfiable constraint. Example: pmcheck/T3927b.
|
| ... | ... | @@ -760,27 +778,25 @@ tcCheckGivens inerts given_ids = do |
| 760 | 778 | |
| 761 | 779 | tcCheckWanteds :: InertSet -> ThetaType -> TcM Bool
|
| 762 | 780 | -- ^ Return True if the Wanteds are soluble, False if not
|
| 763 | -tcCheckWanteds inerts wanteds = do
|
|
| 764 | - cts <- newWanteds PatCheckOrigin wanteds
|
|
| 765 | - (sat, _new_inerts) <- runTcSInerts inerts $ do
|
|
| 766 | - traceTcS "checkWanteds {" (ppr inerts <+> ppr wanteds)
|
|
| 767 | - -- See Note [Superclasses and satisfiability]
|
|
| 768 | - wcs <- solveWanteds (mkSimpleWC cts)
|
|
| 769 | - traceTcS "checkWanteds }" (ppr wcs)
|
|
| 770 | - return (isSolvedWC wcs)
|
|
| 771 | - return sat
|
|
| 781 | +tcCheckWanteds inerts wanteds
|
|
| 782 | + = do { cts <- newWanteds PatCheckOrigin wanteds
|
|
| 783 | + ; runTcSInerts inerts $
|
|
| 784 | + do { traceTcS "checkWanteds {" (ppr inerts <+> ppr wanteds)
|
|
| 785 | + -- See Note [Superclasses and satisfiability]
|
|
| 786 | + ; wcs <- solveWanteds (mkSimpleWC cts)
|
|
| 787 | + ; traceTcS "checkWanteds }" (ppr wcs)
|
|
| 788 | + ; return (isSolvedWC wcs) } }
|
|
| 772 | 789 | |
| 773 | 790 | -- | Normalise a type as much as possible using the given constraints.
|
| 774 | 791 | -- See @Note [tcNormalise]@.
|
| 775 | 792 | tcNormalise :: InertSet -> Type -> TcM Type
|
| 776 | 793 | tcNormalise inerts ty
|
| 777 | 794 | = do { norm_loc <- getCtLocM PatCheckOrigin Nothing
|
| 778 | - ; (res, _new_inerts) <- runTcSInerts inerts $
|
|
| 779 | - do { traceTcS "tcNormalise {" (ppr inerts)
|
|
| 780 | - ; ty' <- rewriteType norm_loc ty
|
|
| 781 | - ; traceTcS "tcNormalise }" (ppr ty')
|
|
| 782 | - ; pure ty' }
|
|
| 783 | - ; return res }
|
|
| 795 | + ; runTcSInerts inerts $
|
|
| 796 | + do { traceTcS "tcNormalise {" (ppr inerts)
|
|
| 797 | + ; ty' <- rewriteType norm_loc ty
|
|
| 798 | + ; traceTcS "tcNormalise }" (ppr ty')
|
|
| 799 | + ; pure ty' } }
|
|
| 784 | 800 | |
| 785 | 801 | {- Note [Superclasses and satisfiability]
|
| 786 | 802 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
| ... | ... | @@ -1170,15 +1170,12 @@ runTcSEqualities thing_inside |
| 1170 | 1170 | |
| 1171 | 1171 | -- | A variant of 'runTcS' that takes and returns an 'InertSet' for
|
| 1172 | 1172 | -- later resumption of the 'TcS' session.
|
| 1173 | -runTcSInerts :: InertSet -> TcS a -> TcM (a, InertSet)
|
|
| 1174 | -runTcSInerts inerts tcs
|
|
| 1173 | +runTcSInerts :: InertSet -> TcS a -> TcM a
|
|
| 1174 | +runTcSInerts inerts thing_inside
|
|
| 1175 | 1175 | = do { ev_binds_var <- TcM.newTcEvBinds
|
| 1176 | 1176 | ; runTcSWithEvBinds' (vanillaTcSMode { tcsmResumable = True })
|
| 1177 | 1177 | ev_binds_var $
|
| 1178 | - do { setInertSet inerts
|
|
| 1179 | - ; a <- tcs
|
|
| 1180 | - ; new_inerts <- getInertSet
|
|
| 1181 | - ; return (a, new_inerts) } }
|
|
| 1178 | + do { setInertSet inerts; thing_inside } }
|
|
| 1182 | 1179 | |
| 1183 | 1180 | runTcSWithEvBinds :: EvBindsVar
|
| 1184 | 1181 | -> TcS a
|
| ... | ... | @@ -11,7 +11,7 @@ |
| 11 | 11 | -- getters...).
|
| 12 | 12 | module GHC.Tc.Utils.Monad(
|
| 13 | 13 | -- * Initialisation
|
| 14 | - initTc, initTcWithGbl, initTcInteractive, initTcRnIf,
|
|
| 14 | + initTc, initTcInteractive, initTcRnIf,
|
|
| 15 | 15 | |
| 16 | 16 | -- * Simple accessors
|
| 17 | 17 | discardResult,
|