Simon Peyton Jones pushed to branch wip/T23162-part2 at Glasgow Haskell Compiler / GHC
Commits:
-
b261357e
by Simon Peyton Jones at 2025-12-02T15:46:07+00:00
6 changed files:
- compiler/GHC/Tc/Errors/Ppr.hs
- compiler/GHC/Tc/Solver/Equality.hs
- compiler/GHC/Tc/Solver/FunDeps.hs
- compiler/GHC/Tc/Solver/Monad.hs
- compiler/GHC/Tc/Solver/Rewrite.hs
- compiler/GHC/Tc/Types/CtLoc.hs
Changes:
| ... | ... | @@ -167,9 +167,11 @@ instance Diagnostic TcRnMessage where |
| 167 | 167 | -> mkSimpleDecorated $ pprSolverReportWithCtxt msg
|
| 168 | 168 | TcRnSolverDepthError ty depth -> mkSimpleDecorated msg
|
| 169 | 169 | where
|
| 170 | + pp_type_or_constraint | isConstraintLikeKind (typeKind ty) = text "constraint"
|
|
| 171 | + | otherwise = text "type"
|
|
| 170 | 172 | msg =
|
| 171 | 173 | vcat [ text "Reduction stack overflow; size =" <+> ppr depth
|
| 172 | - , hang (text "When simplifying the following type:")
|
|
| 174 | + , hang (text "When simplifying the following" <+> pp_type_or_constraint <> colon)
|
|
| 173 | 175 | 2 (ppr ty) ]
|
| 174 | 176 | TcRnRedundantConstraints redundants (info, show_info)
|
| 175 | 177 | -> mkSimpleDecorated $
|
| ... | ... | @@ -349,11 +349,11 @@ can_eq_nc True _rdr_env _envs ev ReprEq ty1 _ ty2 _ |
| 349 | 349 | can_eq_nc _rewritten rdr_env envs ev eq_rel ty1 ps_ty1 ty2 ps_ty2
|
| 350 | 350 | | ReprEq <- eq_rel
|
| 351 | 351 | , Just stuff1 <- tcTopNormaliseNewTypeTF_maybe envs rdr_env ty1
|
| 352 | - = can_eq_newtype_nc rdr_env envs ev NotSwapped ty1 stuff1 ty2 ps_ty2
|
|
| 352 | + = can_eq_newtype_nc rdr_env envs ev NotSwapped stuff1 ty2 ps_ty2
|
|
| 353 | 353 | |
| 354 | 354 | | ReprEq <- eq_rel
|
| 355 | 355 | , Just stuff2 <- tcTopNormaliseNewTypeTF_maybe envs rdr_env ty2
|
| 356 | - = can_eq_newtype_nc rdr_env envs ev IsSwapped ty2 stuff2 ty1 ps_ty1
|
|
| 356 | + = can_eq_newtype_nc rdr_env envs ev IsSwapped stuff2 ty1 ps_ty1
|
|
| 357 | 357 | |
| 358 | 358 | -- Then, get rid of casts
|
| 359 | 359 | can_eq_nc rewritten rdr_env envs ev eq_rel (CastTy ty1 co1) _ ty2 ps_ty2
|
| ... | ... | @@ -777,18 +777,17 @@ though, because we check our depth in `can_eq_newtype_nc`. |
| 777 | 777 | can_eq_newtype_nc :: GlobalRdrEnv -> FamInstEnvs
|
| 778 | 778 | -> CtEvidence -- ^ :: ty1 ~ ty2
|
| 779 | 779 | -> SwapFlag
|
| 780 | - -> TcType -- ^ ty1
|
|
| 781 | 780 | -> ((Bag GlobalRdrElt, TcCoercion), TcType) -- ^ :: ty1 ~ ty1'
|
| 782 | 781 | -> TcType -- ^ ty2
|
| 783 | 782 | -> TcType -- ^ ty2, with type synonyms
|
| 784 | 783 | -> TcS (StopOrContinue (Either IrredCt EqCt))
|
| 785 | -can_eq_newtype_nc rdr_env envs ev swapped ty1 ((gres, co1), ty1') ty2 ps_ty2
|
|
| 784 | +can_eq_newtype_nc rdr_env envs ev swapped ((gres, co1), ty1') ty2 ps_ty2
|
|
| 786 | 785 | = do { traceTcS "can_eq_newtype_nc" $
|
| 787 | 786 | vcat [ ppr ev, ppr swapped, ppr co1, ppr gres, ppr ty1', ppr ty2 ]
|
| 788 | 787 | |
| 789 | 788 | -- Check for blowing our stack, and increase the depth
|
| 790 | 789 | -- See Note [Newtypes can blow the stack]
|
| 791 | - ; loc' <- bumpReductionDepth (ctEvLoc ev) ty1
|
|
| 790 | + ; loc' <- bumpReductionDepth (ctEvLoc ev) (ctEvPred ev)
|
|
| 792 | 791 | ; let ev' = ev `setCtEvLoc` loc'
|
| 793 | 792 | |
| 794 | 793 | -- Next, we record uses of newtype constructors, since coercing
|
| ... | ... | @@ -38,6 +38,7 @@ import GHC.Utils.Panic |
| 38 | 38 | |
| 39 | 39 | import GHC.Data.Pair
|
| 40 | 40 | import Data.Maybe( isNothing, isJust, mapMaybe )
|
| 41 | +import Control.Monad( void )
|
|
| 41 | 42 | |
| 42 | 43 | |
| 43 | 44 | {- Note [Overview of functional dependencies in type inference]
|
| ... | ... | @@ -303,17 +304,20 @@ tryDictFunDeps :: DictCt -> SolverStage () |
| 303 | 304 | |
| 304 | 305 | tryDictFunDeps dict_ct
|
| 305 | 306 | = do { -- Note [Do local fundeps before top-level instances]
|
| 306 | - tryDictFunDepsLocal dict_ct
|
|
| 307 | - ; tryDictFunDepsTop dict_ct }
|
|
| 307 | + insoluble <- tryDictFunDepsLocal dict_ct
|
|
| 308 | + ; if insoluble
|
|
| 309 | + then nopStage ()
|
|
| 310 | + else tryDictFunDepsTop dict_ct }
|
|
| 308 | 311 | |
| 309 | -tryDictFunDepsLocal :: DictCt -> SolverStage ()
|
|
| 312 | +tryDictFunDepsLocal :: DictCt -> SolverStage Bool
|
|
| 310 | 313 | -- Using functional dependencies, interact the DictCt with the
|
| 311 | 314 | -- inert Givens and Wanteds, to produce new equalities
|
| 315 | +-- Returns True if the fundeps are insoluble
|
|
| 312 | 316 | tryDictFunDepsLocal dict_ct@(DictCt { di_cls = cls, di_ev = work_ev })
|
| 313 | 317 | | isGiven work_ev
|
| 314 | 318 | = -- If work_ev is Given, there could in principle be some inert Wanteds
|
| 315 | 319 | -- but in practice there never are because we solve Givens first
|
| 316 | - nopStage ()
|
|
| 320 | + nopStage False
|
|
| 317 | 321 | |
| 318 | 322 | | otherwise
|
| 319 | 323 | = Stage $
|
| ... | ... | @@ -324,14 +328,15 @@ tryDictFunDepsLocal dict_ct@(DictCt { di_cls = cls, di_ev = work_ev }) |
| 324 | 328 | ; let eqns :: [FunDepEqns]
|
| 325 | 329 | eqns = foldr ((++) . do_interaction) [] $
|
| 326 | 330 | findDictsByClass (inert_dicts inerts) cls
|
| 327 | - ; imp <- solveFunDeps work_ev eqns
|
|
| 331 | + ; (insoluble, unif_happened) <- solveFunDeps work_ev eqns
|
|
| 328 | 332 | |
| 329 | 333 | ; traceTcS "tryDictFunDepsLocal }" $
|
| 330 | - text "imp =" <+> ppr imp $$ text "eqns = " <+> ppr eqns
|
|
| 334 | + text "unif =" <+> ppr unif_happened $$ text "eqns = " <+> ppr eqns
|
|
| 331 | 335 | |
| 332 | - ; if imp then startAgainWith (CDictCan dict_ct)
|
|
| 333 | - -- See (DFL1) of Note [Do fundeps last]
|
|
| 334 | - else continueWith () }
|
|
| 336 | + -- See (DFL1) of Note [Do fundeps last]
|
|
| 337 | + ; if insoluble then continueWith True
|
|
| 338 | + else if unif_happened then startAgainWith (CDictCan dict_ct)
|
|
| 339 | + else continueWith False }
|
|
| 335 | 340 | where
|
| 336 | 341 | work_pred = ctEvPred work_ev
|
| 337 | 342 | work_is_given = isGiven work_ev
|
| ... | ... | @@ -356,11 +361,12 @@ tryDictFunDepsTop dict_ct@(DictCt { di_ev = ev, di_cls = cls, di_tys = xis }) |
| 356 | 361 | ; traceTcS "tryDictFunDepsTop {" (ppr dict_ct)
|
| 357 | 362 | ; let eqns :: [FunDepEqns]
|
| 358 | 363 | eqns = improveFromInstEnv inst_envs cls xis
|
| 359 | - ; imp <- solveFunDeps ev eqns
|
|
| 360 | - ; traceTcS "tryDictFunDepsTop }" (text "imp =" <+> ppr imp)
|
|
| 364 | + ; (insoluble, unif_happened) <- solveFunDeps ev eqns
|
|
| 365 | + ; traceTcS "tryDictFunDepsTop }" (text "unif =" <+> ppr unif_happened)
|
|
| 361 | 366 | |
| 362 | - ; if imp then startAgainWith (CDictCan dict_ct)
|
|
| 363 | - else continueWith () }
|
|
| 367 | + ; if not insoluble && unif_happened
|
|
| 368 | + then startAgainWith (CDictCan dict_ct)
|
|
| 369 | + else continueWith () }
|
|
| 364 | 370 | |
| 365 | 371 | {- Note [No Given/Given fundeps]
|
| 366 | 372 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
| ... | ... | @@ -481,12 +487,12 @@ tryFamEqFunDeps eqs_for_me fam_tc work_args |
| 481 | 487 | = if isGiven ev
|
| 482 | 488 | then tryGivenBuiltinFamEqFDs eqs_for_me fam_tc ops work_args work_item
|
| 483 | 489 | else do { -- Note [Do local fundeps before top-level instances]
|
| 484 | - tryFDEqns fam_tc work_args work_item $
|
|
| 485 | - mkLocalBuiltinFamEqFDs eqs_for_me fam_tc ops work_args work_rhs
|
|
| 490 | + insoluble <- tryFDEqns fam_tc work_args work_item $
|
|
| 491 | + mkLocalBuiltinFamEqFDs eqs_for_me fam_tc ops work_args work_rhs
|
|
| 486 | 492 | |
| 487 | - ; if hasRelevantGiven eqs_for_me work_args work_item
|
|
| 493 | + ; if insoluble || hasRelevantGiven eqs_for_me work_args work_item
|
|
| 488 | 494 | ; then nopStage ()
|
| 489 | - else tryFDEqns fam_tc work_args work_item $
|
|
| 495 | + else void $ tryFDEqns fam_tc work_args work_item $
|
|
| 490 | 496 | mkTopBuiltinFamEqFDs fam_tc ops work_args work_rhs }
|
| 491 | 497 | |
| 492 | 498 | | isGiven ev -- See (INJFAM:Given)
|
| ... | ... | @@ -496,15 +502,16 @@ tryFamEqFunDeps eqs_for_me fam_tc work_args |
| 496 | 502 | |
| 497 | 503 | | otherwise -- Wanted, user-defined type families
|
| 498 | 504 | = do { -- Note [Do local fundeps before top-level instances]
|
| 499 | - case tyConInjectivityInfo fam_tc of
|
|
| 500 | - NotInjective -> nopStage()
|
|
| 505 | + insoluble <- case tyConInjectivityInfo fam_tc of
|
|
| 506 | + NotInjective -> nopStage False
|
|
| 501 | 507 | Injective inj -> tryFDEqns fam_tc work_args work_item $
|
| 502 | 508 | mkLocalFamEqFDs eqs_for_me fam_tc inj work_args work_rhs
|
| 503 | 509 | |
| 504 | - ; if hasRelevantGiven eqs_for_me work_args work_item
|
|
| 510 | + ; if insoluble || hasRelevantGiven eqs_for_me work_args work_item
|
|
| 505 | 511 | then nopStage ()
|
| 506 | - else tryFDEqns fam_tc work_args work_item $
|
|
| 507 | - mkTopFamEqFDs fam_tc work_args work_rhs }
|
|
| 512 | + else void $ tryFDEqns fam_tc work_args work_item $
|
|
| 513 | + mkTopFamEqFDs fam_tc work_args work_rhs
|
|
| 514 | + ; nopStage () }
|
|
| 508 | 515 | |
| 509 | 516 | mkTopFamEqFDs :: TyCon -> [TcType] -> Xi -> TcS [FunDepEqns]
|
| 510 | 517 | mkTopFamEqFDs fam_tc work_args work_rhs
|
| ... | ... | @@ -526,17 +533,19 @@ mkTopFamEqFDs fam_tc work_args work_rhs |
| 526 | 533 | -- closed type families with no equations (isClosedFamilyTyCon_maybe returns Nothing)
|
| 527 | 534 | return []
|
| 528 | 535 | |
| 529 | -tryFDEqns :: TyCon -> [TcType] -> EqCt -> TcS [FunDepEqns] -> SolverStage ()
|
|
| 536 | +tryFDEqns :: TyCon -> [TcType] -> EqCt -> TcS [FunDepEqns] -> SolverStage Bool
|
|
| 537 | +-- Returns True <=> some of the fundep eqns were insoluble
|
|
| 530 | 538 | tryFDEqns fam_tc work_args work_item@(EqCt { eq_ev = ev, eq_rhs= rhs }) mk_fd_eqns
|
| 531 | 539 | = Stage $
|
| 532 | 540 | do { fd_eqns <- mk_fd_eqns
|
| 533 | 541 | ; traceTcS "tryFDEqns" (vcat [ text "lhs:" <+> ppr fam_tc <+> ppr work_args
|
| 534 | 542 | , text "rhs:" <+> ppr rhs
|
| 535 | 543 | , text "eqns:" <+> ppr fd_eqns ])
|
| 536 | - ; imp <- solveFunDeps ev fd_eqns
|
|
| 544 | + ; (insoluble, unif_happened) <- solveFunDeps ev fd_eqns
|
|
| 537 | 545 | |
| 538 | - ; if imp then startAgainWith (CEqCan work_item)
|
|
| 539 | - else continueWith () }
|
|
| 546 | + ; if insoluble then continueWith True
|
|
| 547 | + else if unif_happened then startAgainWith (CEqCan work_item)
|
|
| 548 | + else continueWith False }
|
|
| 540 | 549 | |
| 541 | 550 | -----------------------------------------
|
| 542 | 551 | -- User-defined type families
|
| ... | ... | @@ -878,7 +887,8 @@ solving. |
| 878 | 887 | |
| 879 | 888 | solveFunDeps :: CtEvidence -- The work item
|
| 880 | 889 | -> [FunDepEqns]
|
| 881 | - -> TcS Bool
|
|
| 890 | + -> TcS ( Bool -- True <=> some insoluble fundeps
|
|
| 891 | + , Bool ) -- True <=> unifications happened
|
|
| 882 | 892 | -- Solve a bunch of type-equality equations, generated by functional dependencies
|
| 883 | 893 | -- By "solve" we mean: (only) do unifications. We do not generate evidence, and
|
| 884 | 894 | -- other than unifications there should be no effects whatsoever
|
| ... | ... | @@ -888,12 +898,13 @@ solveFunDeps :: CtEvidence -- The work item |
| 888 | 898 | -- See (SOLVE-FD) in Note [Overview of functional dependencies in type inference]
|
| 889 | 899 | solveFunDeps work_ev fd_eqns
|
| 890 | 900 | | null fd_eqns
|
| 891 | - = return False -- Common case no-op
|
|
| 901 | + = return (False, False) -- Common case no-op
|
|
| 892 | 902 | |
| 893 | 903 | | otherwise
|
| 894 | - = do { loc' <- bumpReductionDepth (ctEvLoc work_ev) (ctEvPred work_ev)
|
|
| 904 | + = do { traceTcS "bumping" (ppr work_ev)
|
|
| 905 | + ; loc' <- bumpReductionDepth (ctEvLoc work_ev) (ctEvPred work_ev)
|
|
| 895 | 906 | |
| 896 | - ; (unifs, _res)
|
|
| 907 | + ; (unifs, residual)
|
|
| 897 | 908 | <- reportFineGrainUnifications $
|
| 898 | 909 | nestFunDepsTcS $
|
| 899 | 910 | TcS.pushTcLevelM_ $
|
| ... | ... | @@ -911,7 +922,7 @@ solveFunDeps work_ev fd_eqns |
| 911 | 922 | -- that were unified by the fundep
|
| 912 | 923 | ; kickOutAfterUnification unifs
|
| 913 | 924 | |
| 914 | - ; return (not (isEmptyVarSet unifs)) }
|
|
| 925 | + ; return (insolubleWC residual, not (isEmptyVarSet unifs)) }
|
|
| 915 | 926 | where
|
| 916 | 927 | do_fundeps :: UnifyEnv -> TcM ()
|
| 917 | 928 | do_fundeps env = mapM_ (do_one env) fd_eqns
|
| ... | ... | @@ -2182,7 +2182,8 @@ newWantedNC loc rewriters pty |
| 2182 | 2182 | |
| 2183 | 2183 | -- | Checks if the depth of the given location is too much. Fails if
|
| 2184 | 2184 | -- it's too big, with an appropriate error message.
|
| 2185 | -bumpReductionDepth :: CtLoc -> TcType -- ^ type being reduced
|
|
| 2185 | +bumpReductionDepth :: CtLoc
|
|
| 2186 | + -> TcType -- ^ type or constraint being reduced
|
|
| 2186 | 2187 | -> TcS CtLoc
|
| 2187 | 2188 | bumpReductionDepth loc ty
|
| 2188 | 2189 | = do { dflags <- getDynFlags
|
| ... | ... | @@ -11,7 +11,7 @@ import GHC.Tc.Types ( TcGblEnv(tcg_tc_plugin_rewriters), |
| 11 | 11 | RewriteEnv(..),
|
| 12 | 12 | runTcPluginM )
|
| 13 | 13 | import GHC.Tc.Types.Constraint
|
| 14 | -import GHC.Tc.Types.CtLoc( CtLoc )
|
|
| 14 | +import GHC.Tc.Types.CtLoc( CtLoc, resetCtLocDepth )
|
|
| 15 | 15 | import GHC.Core.Predicate
|
| 16 | 16 | import GHC.Tc.Utils.TcType
|
| 17 | 17 | import GHC.Core.Type
|
| ... | ... | @@ -90,7 +90,8 @@ runRewriteCtEv ev |
| 90 | 90 | runRewrite :: CtLoc -> CtFlavour -> EqRel -> RewriteM a -> TcS (a, CoHoleSet)
|
| 91 | 91 | runRewrite loc flav eq_rel thing_inside
|
| 92 | 92 | = do { rewriters_ref <- newTcRef emptyCoHoleSet
|
| 93 | - ; let fmode = RE { re_loc = loc
|
|
| 93 | + ; let fmode = RE { re_loc = resetCtLocDepth loc
|
|
| 94 | + -- Start reducing from zero
|
|
| 94 | 95 | , re_flavour = flav
|
| 95 | 96 | , re_eq_rel = eq_rel
|
| 96 | 97 | , re_rewriters = rewriters_ref }
|
| ... | ... | @@ -792,8 +793,7 @@ rewrite_fam_app tc tys -- Can be over-saturated |
| 792 | 793 | -- See Note [How to normalise a family application]
|
| 793 | 794 | rewrite_exact_fam_app :: TyCon -> [TcType] -> RewriteM Reduction
|
| 794 | 795 | rewrite_exact_fam_app tc tys
|
| 795 | - = bumpReductionDepthRM (mkTyConApp tc tys) $
|
|
| 796 | - do { -- Query the typechecking plugins for all their rewriting functions
|
|
| 796 | + = do { -- Query the typechecking plugins for all their rewriting functions
|
|
| 797 | 797 | -- which apply to a type family application headed by the TyCon 'tc'.
|
| 798 | 798 | ; tc_rewriters <- getTcPluginRewritersForTyCon tc
|
| 799 | 799 | |
| ... | ... | @@ -876,7 +876,8 @@ rewrite_exact_fam_app tc tys |
| 876 | 876 | -> Reduction -> RewriteM Reduction
|
| 877 | 877 | finish use_cache redn
|
| 878 | 878 | = do { -- rewrite the result: FINISH 1
|
| 879 | - final_redn <- rewrite_reduction redn
|
|
| 879 | + final_redn <- bumpReductionDepthRM (mkTyConApp tc tys) $
|
|
| 880 | + rewrite_reduction redn
|
|
| 880 | 881 | ; eq_rel <- getEqRel
|
| 881 | 882 | |
| 882 | 883 | -- extend the cache: FINISH 2
|
| ... | ... | @@ -3,7 +3,8 @@ module GHC.Tc.Types.CtLoc ( |
| 3 | 3 | -- * CtLoc
|
| 4 | 4 | CtLoc(..), ctLocSpan, ctLocEnv, ctLocLevel, ctLocOrigin,
|
| 5 | 5 | ctLocTypeOrKind_maybe, toInvisibleLoc,
|
| 6 | - ctLocDepth, bumpCtLocDepth, isGivenLoc, mkGivenLoc, mkKindEqLoc,
|
|
| 6 | + ctLocDepth, bumpCtLocDepth, resetCtLocDepth,
|
|
| 7 | + isGivenLoc, mkGivenLoc, mkKindEqLoc,
|
|
| 7 | 8 | setCtLocOrigin, updateCtLocOrigin, setCtLocEnv, setCtLocSpan,
|
| 8 | 9 | pprCtLoc, adjustCtLoc, adjustCtLocTyConBinder,
|
| 9 | 10 | |
| ... | ... | @@ -196,6 +197,9 @@ setCtLocSpan ctl@(CtLoc { ctl_env = lcl }) loc = setCtLocEnv ctl (setCtLocRealLo |
| 196 | 197 | bumpCtLocDepth :: CtLoc -> CtLoc
|
| 197 | 198 | bumpCtLocDepth loc@(CtLoc { ctl_depth = d }) = loc { ctl_depth = bumpSubGoalDepth d }
|
| 198 | 199 | |
| 200 | +resetCtLocDepth :: CtLoc -> CtLoc
|
|
| 201 | +resetCtLocDepth loc = loc { ctl_depth = initialSubGoalDepth }
|
|
| 202 | + |
|
| 199 | 203 | setCtLocOrigin :: CtLoc -> CtOrigin -> CtLoc
|
| 200 | 204 | setCtLocOrigin ctl orig = ctl { ctl_origin = orig }
|
| 201 | 205 |