From 7b72b73f26e07660de719a68cab286a9acb7b98a Mon Sep 17 00:00:00 2001 From: lcnr Date: Thu, 6 Aug 2026 13:25:52 +0200 Subject: [PATCH 1/6] overflow FCW also trigger for overflow -> ambig --- .../src/solve/eval_ctxt/mod.rs | 16 ++++---- ...flow-to-ambig-with-constraints.next.stderr | 40 +++++++++++++++++++ .../fcw-overflow-to-ambig-with-constraints.rs | 36 +++++++++++++++++ 3 files changed, 84 insertions(+), 8 deletions(-) create mode 100644 tests/ui/traits/next-solver/overflow/fcw-overflow-to-ambig-with-constraints.next.stderr create mode 100644 tests/ui/traits/next-solver/overflow/fcw-overflow-to-ambig-with-constraints.rs diff --git a/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/mod.rs b/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/mod.rs index aa7e1e79b5866..0948c11aedf79 100644 --- a/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/mod.rs +++ b/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/mod.rs @@ -329,9 +329,9 @@ where } /// The old solver doesn't check depth requirement when looking up cache while the next solver -/// does so. Thus the next solver is more prone to overflow. -/// To mitigate breakages, we re-evaluate the overflowed goal with doubled recursion limit -/// and emit a FCW if it succeeds. +/// does so. Thus the next solver is more prone to overflow. To mitigate breakages, we re-evaluate +/// the overflowed goal with doubled recursion limit and emit a FCW if doing so prevents overflow. +/// /// See the doc comment on `RECURSION_DEPTH_EXCEEDING_LIMIT` and #159228 for more details. fn maybe_evaluate_root_goal_with_higher_recursion_limit( delegate: &D, @@ -358,7 +358,7 @@ fn maybe_evaluate_root_goal_with_higher_recursion_limit( ecx.evaluate_goal_no_fast_paths(GoalSource::Misc, goal) }); if let Ok(goal_evaluation) = &rerun_result - && goal_evaluation.certainty.is_yes() + && !goal_evaluation.certainty.is_overflow() { Ok(rerun_result) } else { @@ -372,9 +372,9 @@ fn maybe_evaluate_root_goal_with_higher_recursion_limit( } /// The old solver doesn't check depth requirement when looking up cache while the next solver -/// does so. Thus the next solver is more prone to overflow. -/// To mitigate breakages, we re-evaluate the overflowed goal with doubled recursion limit -/// and emit a FCW if it succeeds. +/// does so. Thus the next solver is more prone to overflow. To mitigate breakages, we re-evaluate +/// the overflowed goal with doubled recursion limit and emit a FCW if doing so prevents overflow. +/// /// See the doc comment on `RECURSION_DEPTH_EXCEEDING_LIMIT` and #159228 for more details. fn maybe_evaluate_root_goal_for_proof_tree_with_higher_recursion_limit( delegate: &D, @@ -407,7 +407,7 @@ fn maybe_evaluate_root_goal_for_proof_tree_with_higher_recursion_limit( delegate.cx().recursion_limit() * 2, ); if let Ok(response) = &new_goal_evaluation.result - && response.value.certainty.is_yes() + && !response.value.certainty.is_overflow() { Ok((new_result, new_goal_evaluation)) } else { diff --git a/tests/ui/traits/next-solver/overflow/fcw-overflow-to-ambig-with-constraints.next.stderr b/tests/ui/traits/next-solver/overflow/fcw-overflow-to-ambig-with-constraints.next.stderr new file mode 100644 index 0000000000000..e94b95c67dc65 --- /dev/null +++ b/tests/ui/traits/next-solver/overflow/fcw-overflow-to-ambig-with-constraints.next.stderr @@ -0,0 +1,40 @@ +warning: overflow evaluating the requirement `u32: Constrain<_, _, W>, _>, _>>` + --> $DIR/fcw-overflow-to-ambig-with-constraints.rs:29:5 + | +LL | fun_times(); + | ^^^^^^^^^^^ + | + = help: consider increasing the recursion limit by adding a `#![recursion_limit = "16"]` attribute to your crate (`fcw_overflow_to_ambig_with_constraints`) + = help: or consider adding a manual `impl` of auto traits like `Send` for intermediate types, if auto traits are involved + = note: this lint is attached to the whole crate and can't be disabled on a per-function basis + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #159228 + = note: `#[warn(recursion_depth_exceeding_limit)]` (part of `#[warn(future_incompatible)]`) on by default + +warning: overflow evaluating the requirement `u32: Constrain>, _>, _>>` + --> $DIR/fcw-overflow-to-ambig-with-constraints.rs:29:5 + | +LL | fun_times(); + | ^^^^^^^^^^^ + | + = help: consider increasing the recursion limit by adding a `#![recursion_limit = "16"]` attribute to your crate (`fcw_overflow_to_ambig_with_constraints`) + = help: or consider adding a manual `impl` of auto traits like `Send` for intermediate types, if auto traits are involved + = note: this lint is attached to the whole crate and can't be disabled on a per-function basis + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #159228 + +warning: overflow evaluating the requirement `u32: Constrain>, _>, _>>` + --> $DIR/fcw-overflow-to-ambig-with-constraints.rs:29:5 + | +LL | fun_times(); + | ^^^^^^^^^^^ + | + = help: consider increasing the recursion limit by adding a `#![recursion_limit = "16"]` attribute to your crate (`fcw_overflow_to_ambig_with_constraints`) + = help: or consider adding a manual `impl` of auto traits like `Send` for intermediate types, if auto traits are involved + = note: this lint is attached to the whole crate and can't be disabled on a per-function basis + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #159228 + = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` + +warning: 3 warnings emitted + diff --git a/tests/ui/traits/next-solver/overflow/fcw-overflow-to-ambig-with-constraints.rs b/tests/ui/traits/next-solver/overflow/fcw-overflow-to-ambig-with-constraints.rs new file mode 100644 index 0000000000000..9c51f3480c09b --- /dev/null +++ b/tests/ui/traits/next-solver/overflow/fcw-overflow-to-ambig-with-constraints.rs @@ -0,0 +1,36 @@ +//@ revisions: old next +//@[next] compile-flags: -Znext-solver +//@ check-pass + +// Regression test for `calimero-store` + +#![recursion_limit = "8"] +struct W(T, U); +trait Count {} +impl Count for W {} +impl Count for () {} +// Old solver is able to use cache entries from lower recursion depths, +// new one correctly tracks their required depth, so it needs more than 8 steps. +type Four = W>>>; + +trait Constrain {} +impl Constrain for u32 {} + +trait Equal {} +impl Equal for T {} + +fn fun_times() +where + u32: Constrain>>>, + T: Equal, +{} + +fn main() { + fun_times(); + //[next]~^ WARN overflow evaluating the requirement `u32: Constrain<_, _, W>, _>, _>>` + //[next]~| WARN: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + //[next]~| WARN overflow evaluating the requirement `u32: Constrain>, _>, _>>` + //[next]~| WARN: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + //[next]~| WARN overflow evaluating the requirement `u32: Constrain>, _>, _>>` + //[next]~| WARN: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! +} From 89c2f92806c798075e488d964fd784154573b11d Mon Sep 17 00:00:00 2001 From: lcnr Date: Thu, 13 Aug 2026 12:50:34 +0200 Subject: [PATCH 2/6] only emit a single `recursion_depth_exceeding_limit` --- compiler/rustc_errors/src/lib.rs | 34 +++++++++--- .../overflow-discards-constraints.stderr | 10 +--- .../overflow/fcw-on-auto-trait.next.stderr | 10 +--- .../overflow/fcw-on-normalization.next.stderr | 55 +------------------ .../overflow/fcw-on-normalization.rs | 7 --- ...flow-to-ambig-with-constraints.next.stderr | 27 +-------- .../fcw-overflow-to-ambig-with-constraints.rs | 4 -- 7 files changed, 31 insertions(+), 116 deletions(-) diff --git a/compiler/rustc_errors/src/lib.rs b/compiler/rustc_errors/src/lib.rs index 4fa104ad6dbfe..b487187842029 100644 --- a/compiler/rustc_errors/src/lib.rs +++ b/compiler/rustc_errors/src/lib.rs @@ -22,7 +22,7 @@ use std::num::NonZero; use std::ops::DerefMut; use std::path::{Path, PathBuf}; use std::thread::ThreadId; -use std::{assert_matches, fmt, panic}; +use std::{assert_matches, fmt, mem, panic}; use Level::*; // Used by external projects such as `rust-gpu`. @@ -336,6 +336,15 @@ struct DiagCtxtInner { /// twice. emitted_diagnostics: FxHashSet, + /// We only want to emit `recursion_depth_exceeding_limit` once per + /// crate. Otherwise crates like `calimero-store` emit more than + /// a thousand warnings. + /// + /// We only check this in `TRACK_DIAGNOSTIC` meaning that the diagnostics + /// still get tracked by the query system, even if they don't get emitted + /// to users. + emitted_recursion_depth_exceeding_limit: bool, + /// Stashed diagnostics emitted in one stage of the compiler that may be /// stolen and emitted/cancelled by other stages (e.g. to improve them and /// add more information). All stashed diagnostics must be emitted with @@ -527,6 +536,7 @@ impl DiagCtxt { taught_diagnostics, emitted_diagnostic_codes, emitted_diagnostics, + emitted_recursion_depth_exceeding_limit, stashed_diagnostics, future_breakage_diagnostics, fulfilled_expectations, @@ -547,6 +557,7 @@ impl DiagCtxt { *taught_diagnostics = Default::default(); *emitted_diagnostic_codes = Default::default(); *emitted_diagnostics = Default::default(); + *emitted_recursion_depth_exceeding_limit = false; *stashed_diagnostics = Default::default(); *future_breakage_diagnostics = Default::default(); *fulfilled_expectations = Default::default(); @@ -879,7 +890,7 @@ impl<'a> DiagCtxtHandle<'a> { pub fn emit_future_breakage_report(&self) { let inner = &mut *self.inner.borrow_mut(); - let diags = std::mem::take(&mut inner.future_breakage_diagnostics); + let diags = mem::take(&mut inner.future_breakage_diagnostics); if !diags.is_empty() { inner.emitter.emit_future_breakage_report(diags); } @@ -919,7 +930,7 @@ impl<'a> DiagCtxtHandle<'a> { /// [`DiagCtxtInner`] and indicate that the linked expectation has been fulfilled. #[must_use] pub fn steal_fulfilled_expectation_ids(&self) -> FxIndexSet { - std::mem::take(&mut self.inner.borrow_mut().fulfilled_expectations) + mem::take(&mut self.inner.borrow_mut().fulfilled_expectations) } /// Trigger an ICE if there are any delayed bugs and no hard errors. @@ -1195,6 +1206,7 @@ impl DiagCtxtInner { taught_diagnostics: Default::default(), emitted_diagnostic_codes: Default::default(), emitted_diagnostics: Default::default(), + emitted_recursion_depth_exceeding_limit: false, stashed_diagnostics: Default::default(), future_breakage_diagnostics: Vec::new(), fulfilled_expectations: Default::default(), @@ -1207,7 +1219,7 @@ impl DiagCtxtInner { fn emit_stashed_diagnostics(&mut self) -> Option { let mut guar = None; let has_errors = !self.err_guars.is_empty(); - for (_, stashed_diagnostics) in std::mem::take(&mut self.stashed_diagnostics).into_iter() { + for (_, stashed_diagnostics) in mem::take(&mut self.stashed_diagnostics).into_iter() { for (_, (diag, _guar, _thread)) in stashed_diagnostics { if !diag.is_error() { // Unless they're forced, don't flush stashed warnings when @@ -1334,10 +1346,19 @@ impl DiagCtxtInner { let is_error = diagnostic.is_error(); let is_lint = diagnostic.is_lint.is_some(); + // We only emit the first occurrence of `recursion_depth_exceeding_limit`. + let silence_recursion_depth_exceeded_limit = + diagnostic.is_lint.as_ref().is_some_and(|lint| { + lint.name.eq_ignore_ascii_case( + rustc_lint_defs::builtin::RECURSION_DEPTH_EXCEEDING_LIMIT.name, + ) && mem::replace(&mut self.emitted_recursion_depth_exceeding_limit, true) + }); // Only emit the diagnostic if we've been asked to deduplicate or // haven't already emitted an equivalent diagnostic. - if !(self.flags.deduplicate_diagnostics && already_emitted) { + if !silence_recursion_depth_exceeded_limit + && !(self.flags.deduplicate_diagnostics && already_emitted) + { debug!(?diagnostic); debug!(?self.emitted_diagnostics); @@ -1460,8 +1481,7 @@ impl DiagCtxtInner { return; } - let bugs: Vec<_> = - std::mem::take(&mut self.delayed_bugs).into_iter().map(|(b, _)| b).collect(); + let bugs: Vec<_> = mem::take(&mut self.delayed_bugs).into_iter().map(|(b, _)| b).collect(); let backtrace = std::env::var_os("RUST_BACKTRACE").as_deref() != Some(OsStr::new("0")); let decorate = backtrace || self.ice_file.is_none(); diff --git a/tests/ui/traits/next-solver/overflow-discards-constraints.stderr b/tests/ui/traits/next-solver/overflow-discards-constraints.stderr index eeeace3180091..26d353cfe99c4 100644 --- a/tests/ui/traits/next-solver/overflow-discards-constraints.stderr +++ b/tests/ui/traits/next-solver/overflow-discards-constraints.stderr @@ -11,13 +11,5 @@ LL | foo(); // register a `(): Trait` obligation = note: for more information, see issue #159228 = note: `#[warn(recursion_depth_exceeding_limit)]` (part of `#[warn(future_incompatible)]`) on by default -warning: overflow evaluating the requirement `(): Trait` - | - = help: consider increasing the recursion limit by adding a `#![recursion_limit = "12"]` attribute to your crate (`overflow_discards_constraints`) - = help: or consider adding a manual `impl` of auto traits like `Send` for intermediate types, if auto traits are involved - = note: this lint is attached to the whole crate and can't be disabled on a per-function basis - = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - = note: for more information, see issue #159228 - -warning: 2 warnings emitted +warning: 1 warning emitted diff --git a/tests/ui/traits/next-solver/overflow/fcw-on-auto-trait.next.stderr b/tests/ui/traits/next-solver/overflow/fcw-on-auto-trait.next.stderr index 41849b8d2f49a..bd4b8b63a990b 100644 --- a/tests/ui/traits/next-solver/overflow/fcw-on-auto-trait.next.stderr +++ b/tests/ui/traits/next-solver/overflow/fcw-on-auto-trait.next.stderr @@ -11,13 +11,5 @@ LL | require_sync::>>>>>>(); = note: for more information, see issue #159228 = note: `#[warn(recursion_depth_exceeding_limit)]` (part of `#[warn(future_incompatible)]`) on by default -warning: overflow evaluating the requirement `Foo>>>>>: Sync` - | - = help: consider increasing the recursion limit by adding a `#![recursion_limit = "16"]` attribute to your crate (`fcw_on_auto_trait`) - = help: or consider adding a manual `impl` of auto traits like `Send` for intermediate types, if auto traits are involved - = note: this lint is attached to the whole crate and can't be disabled on a per-function basis - = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - = note: for more information, see issue #159228 - -warning: 2 warnings emitted +warning: 1 warning emitted diff --git a/tests/ui/traits/next-solver/overflow/fcw-on-normalization.next.stderr b/tests/ui/traits/next-solver/overflow/fcw-on-normalization.next.stderr index 76cc281cffd57..9cc933d73711e 100644 --- a/tests/ui/traits/next-solver/overflow/fcw-on-normalization.next.stderr +++ b/tests/ui/traits/next-solver/overflow/fcw-on-normalization.next.stderr @@ -11,58 +11,5 @@ LL | let b: >>>>>>>>> as HasAssoc>::Assoc = loop {}; = note: for more information, see issue #159228 = note: `#[warn(recursion_depth_exceeding_limit)]` (part of `#[warn(future_incompatible)]`) on by default -warning: overflow evaluating the requirement `>>>>>> as HasAssoc>::Assoc == _` - --> $DIR/fcw-on-normalization.rs:45:12 - | -LL | let b: >>>>>>>>> as HasAssoc>::Assoc = loop {}; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = help: consider increasing the recursion limit by adding a `#![recursion_limit = "16"]` attribute to your crate (`fcw_on_normalization`) - = help: or consider adding a manual `impl` of auto traits like `Send` for intermediate types, if auto traits are involved - = note: this lint is attached to the whole crate and can't be disabled on a per-function basis - = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - = note: for more information, see issue #159228 - = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` - -warning: overflow evaluating the requirement `W>>>>>>>>>: HasAssoc` - --> $DIR/fcw-on-normalization.rs:45:12 - | -LL | let b: >>>>>>>>> as HasAssoc>::Assoc = loop {}; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = help: consider increasing the recursion limit by adding a `#![recursion_limit = "16"]` attribute to your crate (`fcw_on_normalization`) - = help: or consider adding a manual `impl` of auto traits like `Send` for intermediate types, if auto traits are involved - = note: this lint is attached to the whole crate and can't be disabled on a per-function basis - = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - = note: for more information, see issue #159228 - -warning: overflow evaluating the requirement `>>>>> as HasAssoc>::Assoc well-formed` - --> $DIR/fcw-on-normalization.rs:45:12 - | -LL | let b: >>>>>>>>> as HasAssoc>::Assoc = loop {}; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = help: consider increasing the recursion limit by adding a `#![recursion_limit = "16"]` attribute to your crate (`fcw_on_normalization`) - = help: or consider adding a manual `impl` of auto traits like `Send` for intermediate types, if auto traits are involved - = note: this lint is attached to the whole crate and can't be disabled on a per-function basis - = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - = note: for more information, see issue #159228 - -warning: overflow evaluating the requirement `>>>>>> as HasAssoc>::Assoc == _` - | - = help: consider increasing the recursion limit by adding a `#![recursion_limit = "16"]` attribute to your crate (`fcw_on_normalization`) - = help: or consider adding a manual `impl` of auto traits like `Send` for intermediate types, if auto traits are involved - = note: this lint is attached to the whole crate and can't be disabled on a per-function basis - = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - = note: for more information, see issue #159228 - -warning: overflow evaluating the requirement `>>>>> as HasAssoc>::Assoc well-formed` - | - = help: consider increasing the recursion limit by adding a `#![recursion_limit = "16"]` attribute to your crate (`fcw_on_normalization`) - = help: or consider adding a manual `impl` of auto traits like `Send` for intermediate types, if auto traits are involved - = note: this lint is attached to the whole crate and can't be disabled on a per-function basis - = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - = note: for more information, see issue #159228 - -warning: 6 warnings emitted +warning: 1 warning emitted diff --git a/tests/ui/traits/next-solver/overflow/fcw-on-normalization.rs b/tests/ui/traits/next-solver/overflow/fcw-on-normalization.rs index fa5d518640dfc..d8761d11ae751 100644 --- a/tests/ui/traits/next-solver/overflow/fcw-on-normalization.rs +++ b/tests/ui/traits/next-solver/overflow/fcw-on-normalization.rs @@ -45,13 +45,6 @@ fn foo() { let b: >>>>>>>>> as HasAssoc>::Assoc = loop {}; //[next]~^ WARN: overflow evaluating the requirement `>>>>>> as HasAssoc>::Assoc == _` [recursion_depth_exceeding_limit] //[next]~| WARN: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - //[next]~| WARN: overflow evaluating the requirement `>>>>>> as HasAssoc>::Assoc == _` [recursion_depth_exceeding_limit] - //[next]~| WARN: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - //[next]~| WARN: overflow evaluating the requirement `W>>>>>>>>>: HasAssoc` [recursion_depth_exceeding_limit] - //[next]~| WARN: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - //[next]~| WARN: overflow evaluating the requirement `>>>>> as HasAssoc>::Assoc well-formed` [recursion_depth_exceeding_limit] - //[next]~| WARN: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - // Force normalization when looking up methods and the self_ty is normalized to infer. b.anyone_can_call(); } diff --git a/tests/ui/traits/next-solver/overflow/fcw-overflow-to-ambig-with-constraints.next.stderr b/tests/ui/traits/next-solver/overflow/fcw-overflow-to-ambig-with-constraints.next.stderr index e94b95c67dc65..507132eface89 100644 --- a/tests/ui/traits/next-solver/overflow/fcw-overflow-to-ambig-with-constraints.next.stderr +++ b/tests/ui/traits/next-solver/overflow/fcw-overflow-to-ambig-with-constraints.next.stderr @@ -11,30 +11,5 @@ LL | fun_times(); = note: for more information, see issue #159228 = note: `#[warn(recursion_depth_exceeding_limit)]` (part of `#[warn(future_incompatible)]`) on by default -warning: overflow evaluating the requirement `u32: Constrain>, _>, _>>` - --> $DIR/fcw-overflow-to-ambig-with-constraints.rs:29:5 - | -LL | fun_times(); - | ^^^^^^^^^^^ - | - = help: consider increasing the recursion limit by adding a `#![recursion_limit = "16"]` attribute to your crate (`fcw_overflow_to_ambig_with_constraints`) - = help: or consider adding a manual `impl` of auto traits like `Send` for intermediate types, if auto traits are involved - = note: this lint is attached to the whole crate and can't be disabled on a per-function basis - = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - = note: for more information, see issue #159228 - -warning: overflow evaluating the requirement `u32: Constrain>, _>, _>>` - --> $DIR/fcw-overflow-to-ambig-with-constraints.rs:29:5 - | -LL | fun_times(); - | ^^^^^^^^^^^ - | - = help: consider increasing the recursion limit by adding a `#![recursion_limit = "16"]` attribute to your crate (`fcw_overflow_to_ambig_with_constraints`) - = help: or consider adding a manual `impl` of auto traits like `Send` for intermediate types, if auto traits are involved - = note: this lint is attached to the whole crate and can't be disabled on a per-function basis - = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - = note: for more information, see issue #159228 - = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` - -warning: 3 warnings emitted +warning: 1 warning emitted diff --git a/tests/ui/traits/next-solver/overflow/fcw-overflow-to-ambig-with-constraints.rs b/tests/ui/traits/next-solver/overflow/fcw-overflow-to-ambig-with-constraints.rs index 9c51f3480c09b..6ef671d7dd471 100644 --- a/tests/ui/traits/next-solver/overflow/fcw-overflow-to-ambig-with-constraints.rs +++ b/tests/ui/traits/next-solver/overflow/fcw-overflow-to-ambig-with-constraints.rs @@ -29,8 +29,4 @@ fn main() { fun_times(); //[next]~^ WARN overflow evaluating the requirement `u32: Constrain<_, _, W>, _>, _>>` //[next]~| WARN: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - //[next]~| WARN overflow evaluating the requirement `u32: Constrain>, _>, _>>` - //[next]~| WARN: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - //[next]~| WARN overflow evaluating the requirement `u32: Constrain>, _>, _>>` - //[next]~| WARN: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! } From d3bde3ca87d83eb32d12e008431b1ac362e475a3 Mon Sep 17 00:00:00 2001 From: lcnr Date: Thu, 13 Aug 2026 13:10:54 +0200 Subject: [PATCH 3/6] move fcw to `SolverDelegate`, resolve infer vars --- .../src/ty/context/impl_interner.rs | 43 +----------------- .../rustc_next_trait_solver/src/delegate.rs | 6 +++ .../src/solve/eval_ctxt/mod.rs | 4 +- .../src/solve/delegate.rs | 44 ++++++++++++++++++- compiler/rustc_type_ir/src/interner.rs | 2 - .../overflow-discards-constraints.rs | 2 +- .../overflow-discards-constraints.stderr | 4 +- .../overflow/fcw-on-normalization.next.stderr | 4 +- .../overflow/fcw-on-normalization.rs | 2 +- ...flow-to-ambig-with-constraints.next.stderr | 2 +- .../fcw-overflow-to-ambig-with-constraints.rs | 2 +- 11 files changed, 61 insertions(+), 54 deletions(-) diff --git a/compiler/rustc_middle/src/ty/context/impl_interner.rs b/compiler/rustc_middle/src/ty/context/impl_interner.rs index 637fc1d34b9e1..f19adb5b9d553 100644 --- a/compiler/rustc_middle/src/ty/context/impl_interner.rs +++ b/compiler/rustc_middle/src/ty/context/impl_interner.rs @@ -5,13 +5,10 @@ use std::{debug_assert_matches, fmt}; use rustc_data_structures::intern::Interned; use rustc_errors::ErrorGuaranteed; use rustc_hir as hir; -use rustc_hir::CRATE_HIR_ID; use rustc_hir::attrs::lang_items::LangItem; -use rustc_hir::def::{CtorKind, DefKind, Namespace}; -use rustc_hir::def_id::{DefId, LOCAL_CRATE, LocalDefId}; -use rustc_lint_defs::builtin::RECURSION_DEPTH_EXCEEDING_LIMIT; +use rustc_hir::def::{CtorKind, DefKind}; +use rustc_hir::def_id::{DefId, LocalDefId}; use rustc_span::{DUMMY_SP, Span, Symbol}; -use rustc_structures::Limit; use rustc_type_ir::lang_items::{SolverAdtLangItem, SolverProjectionLangItem, SolverTraitLangItem}; use rustc_type_ir::{ BoundVar, CollectAndApply, DebruijnIndex, Interner, TypeFoldable, Unnormalized, VisitorResult, @@ -24,7 +21,6 @@ use crate::traits::cache::WithDepNode; use crate::traits::solve::{ self, CanonicalInput, ExternalConstraints, ExternalConstraintsData, QueryResult, inspect, }; -use crate::ty::print::{FmtPrinter, Print}; use crate::ty::{ self, BoundRegion, Clause, Const, List, ParamTy, Pattern, PolyExistentialPredicate, Predicate, Region, RegionKind, Ty, TyCtxt, @@ -676,41 +672,6 @@ impl<'tcx> Interner for TyCtxt<'tcx> { self.evaluate_root_goal_for_proof_tree_raw((canonical_goal, root_depth)) } - fn emit_next_solver_overflow_fcw(self, predicate: ty::Predicate<'tcx>, span: Span) { - self.emit_node_span_lint( - RECURSION_DEPTH_EXCEEDING_LIMIT, - CRATE_HIR_ID, - span, - rustc_errors::DiagDecorator(|diag| { - // FIXME: share this with overflow error in fulfillment instead of duplicating. - let pred_str = { - let s = predicate.to_string(); - if s.len() > 50 { - let mut p: FmtPrinter<'_, '_> = - FmtPrinter::new_with_limit(self, Namespace::TypeNS, Limit(6)); - predicate.print(&mut p).unwrap(); - p.into_buffer() - } else { - s - } - }; - diag.primary_message(format!( - "overflow evaluating the requirement `{pred_str}`", - )); - diag.help(format!( - "consider increasing the recursion limit by adding a \ - `#![recursion_limit = \"{}\"]` attribute to your crate (`{}`)", - self.recursion_limit() * 2, - self.crate_name(LOCAL_CRATE), - )); - diag.help( - "or consider adding a manual `impl` of auto traits like `Send` for intermediate types, if auto traits are involved", - ); - diag.note("this lint is attached to the whole crate and can't be disabled on a per-function basis"); - }), - ) - } - fn item_name(self, id: DefId) -> Symbol { self.opt_item_name(id).unwrap_or_else(|| { bug!("item_name: no name for {:?}", self.def_path(id)); diff --git a/compiler/rustc_next_trait_solver/src/delegate.rs b/compiler/rustc_next_trait_solver/src/delegate.rs index 13988e2c7b918..0e414b35d769a 100644 --- a/compiler/rustc_next_trait_solver/src/delegate.rs +++ b/compiler/rustc_next_trait_solver/src/delegate.rs @@ -124,4 +124,10 @@ pub trait SolverDelegate: Deref + Sized { /// Release canonicalizer state, either by deallocating it (the default) or by clearing it and /// stashing it for later reuse. fn release_canonicalizer_state(&self, _: CanonicalizerState) {} + + fn emit_next_solver_overflow_fcw( + &self, + predicate: ::Predicate, + span: ::Span, + ); } diff --git a/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/mod.rs b/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/mod.rs index 0948c11aedf79..a4f868abfd409 100644 --- a/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/mod.rs +++ b/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/mod.rs @@ -366,7 +366,7 @@ fn maybe_evaluate_root_goal_with_higher_recursion_limit( } }); if let Ok(rerun_result) = rerun_result { - delegate.cx().emit_next_solver_overflow_fcw(predicate, span); + delegate.emit_next_solver_overflow_fcw(predicate, span); *initial_result = rerun_result; } } @@ -416,7 +416,7 @@ fn maybe_evaluate_root_goal_for_proof_tree_with_higher_recursion_limit( }); if let Ok(rerun_result) = rerun_result { let predicate: I::Predicate = goal_evaluation.uncanonicalized_goal.predicate; - delegate.cx().emit_next_solver_overflow_fcw(predicate, span); + delegate.emit_next_solver_overflow_fcw(predicate, span); *initial_result = rerun_result; } } diff --git a/compiler/rustc_trait_selection/src/solve/delegate.rs b/compiler/rustc_trait_selection/src/solve/delegate.rs index 5e3c03ba7e7ba..89e739e797850 100644 --- a/compiler/rustc_trait_selection/src/solve/delegate.rs +++ b/compiler/rustc_trait_selection/src/solve/delegate.rs @@ -4,8 +4,10 @@ use std::mem; use std::ops::Deref; use rustc_data_structures::fx::{FxHashMap, FxHashSet}; +use rustc_hir::CRATE_HIR_ID; use rustc_hir::attrs::lang_items::LangItem; -use rustc_hir::def_id::{CRATE_DEF_ID, DefId}; +use rustc_hir::def::Namespace; +use rustc_hir::def_id::{CRATE_DEF_ID, DefId, LOCAL_CRATE}; use rustc_infer::infer::canonical::query_response::make_query_region_constraints; use rustc_infer::infer::canonical::{ Canonical, CanonicalExt as _, CanonicalQueryInput, CanonicalVarKind, CanonicalVarValues, @@ -15,14 +17,17 @@ use rustc_infer::infer::{InferCtxt, RegionVariableOrigin, SubregionOrigin, TyCtx use rustc_infer::traits::solve::{ ComputeGoalFastPathOutcome, FetchEligibleAssocItemResponse, Goal, SucceededInErased, }; +use rustc_lint_defs::builtin::RECURSION_DEPTH_EXCEEDING_LIMIT; use rustc_middle::traits::query::NoSolution; use rustc_middle::traits::solve::{Certainty, MaybeInfo}; +use rustc_middle::ty::print::{FmtPrinter, Print}; use rustc_middle::ty::{ self, CanonicalizerState, MayBeErased, Ty, TyCtxt, TypeFlags, TypeFoldable, TypeSuperVisitable, TypeVisitable, TypeVisitableExt, TypeVisitor, TypingMode, }; use rustc_next_trait_solver::solve::{GoalStalledOn, GoalStalledOnOpaques, TyOrConstInferVar}; use rustc_span::{DUMMY_SP, Span}; +use rustc_structures::Limit; use thin_vec::{ThinVec, thin_vec}; use crate::traits::{EvaluateConstErr, ObligationCause, sizedness_fast_path, specialization_graph}; @@ -504,4 +509,41 @@ impl<'tcx> rustc_next_trait_solver::delegate::SolverDelegate for SolverDelegate< state.clear(); *self.canonicalizer_state.borrow_mut() = state; } + + fn emit_next_solver_overflow_fcw(&self, predicate: ty::Predicate<'tcx>, span: Span) { + let tcx = self.tcx; + let predicate = self.resolve_vars_if_possible(predicate); + tcx.emit_node_span_lint( + RECURSION_DEPTH_EXCEEDING_LIMIT, + CRATE_HIR_ID, + span, + rustc_errors::DiagDecorator(|diag| { + // FIXME: share this with overflow error in fulfillment instead of duplicating. + let pred_str = { + let s = predicate.to_string(); + if s.len() > 50 { + let mut p: FmtPrinter<'_, '_> = + FmtPrinter::new_with_limit(tcx, Namespace::TypeNS, Limit(6)); + predicate.print(&mut p).unwrap(); + p.into_buffer() + } else { + s + } + }; + diag.primary_message(format!( + "overflow evaluating the requirement `{pred_str}`", + )); + diag.help(format!( + "consider increasing the recursion limit by adding a \ + `#![recursion_limit = \"{}\"]` attribute to your crate (`{}`)", + tcx.recursion_limit() * 2, + tcx.crate_name(LOCAL_CRATE), + )); + diag.help( + "or consider adding a manual `impl` of auto traits like `Send` for intermediate types, if auto traits are involved", + ); + diag.note("this lint is attached to the whole crate and can't be disabled on a per-function basis"); + }), + ) + } } diff --git a/compiler/rustc_type_ir/src/interner.rs b/compiler/rustc_type_ir/src/interner.rs index 1113aa4f6af51..3d57648f1900e 100644 --- a/compiler/rustc_type_ir/src/interner.rs +++ b/compiler/rustc_type_ir/src/interner.rs @@ -502,8 +502,6 @@ pub trait Interner: root_depth: usize, ) -> (QueryResult, Self::Probe); - fn emit_next_solver_overflow_fcw(self, predicate: Self::Predicate, span: Self::Span); - fn item_name(self, item_index: Self::DefId) -> Self::Symbol; fn get_anon_re_bounds_lifetime(self, idx: usize, var_idx: usize) -> Option>; diff --git a/tests/ui/traits/next-solver/overflow-discards-constraints.rs b/tests/ui/traits/next-solver/overflow-discards-constraints.rs index 1516184dfde81..259875025ea7b 100644 --- a/tests/ui/traits/next-solver/overflow-discards-constraints.rs +++ b/tests/ui/traits/next-solver/overflow-discards-constraints.rs @@ -71,7 +71,7 @@ fn foo() fn main() { foo(); // register a `(): Trait` obligation - //~^ WARN: overflow evaluating the requirement `(): Trait<_>` [recursion_depth_exceeding_limit] + //~^ WARN: overflow evaluating the requirement `(): Trait` [recursion_depth_exceeding_limit] //~| WARN: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! } diff --git a/tests/ui/traits/next-solver/overflow-discards-constraints.stderr b/tests/ui/traits/next-solver/overflow-discards-constraints.stderr index 26d353cfe99c4..68c1e88181f17 100644 --- a/tests/ui/traits/next-solver/overflow-discards-constraints.stderr +++ b/tests/ui/traits/next-solver/overflow-discards-constraints.stderr @@ -1,5 +1,5 @@ -warning: overflow evaluating the requirement `(): Trait<_>` - --> $DIR/overflow-discards-constraints.rs:73:5 +warning: overflow evaluating the requirement `(): Trait` + --> $DIR/overflow-discards-constraints.rs:69:5 | LL | foo(); // register a `(): Trait` obligation | ^^^^^ diff --git a/tests/ui/traits/next-solver/overflow/fcw-on-normalization.next.stderr b/tests/ui/traits/next-solver/overflow/fcw-on-normalization.next.stderr index 9cc933d73711e..0726f81a0f7be 100644 --- a/tests/ui/traits/next-solver/overflow/fcw-on-normalization.next.stderr +++ b/tests/ui/traits/next-solver/overflow/fcw-on-normalization.next.stderr @@ -1,5 +1,5 @@ -warning: overflow evaluating the requirement `>>>>>> as HasAssoc>::Assoc == _` - --> $DIR/fcw-on-normalization.rs:45:12 +warning: overflow evaluating the requirement `>>>>>> as HasAssoc>::Assoc == ()` + --> $DIR/fcw-on-normalization.rs:40:12 | LL | let b: >>>>>>>>> as HasAssoc>::Assoc = loop {}; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/tests/ui/traits/next-solver/overflow/fcw-on-normalization.rs b/tests/ui/traits/next-solver/overflow/fcw-on-normalization.rs index d8761d11ae751..9845d38abc2c4 100644 --- a/tests/ui/traits/next-solver/overflow/fcw-on-normalization.rs +++ b/tests/ui/traits/next-solver/overflow/fcw-on-normalization.rs @@ -43,7 +43,7 @@ fn foo() { a.anyone_can_call(); let b: >>>>>>>>> as HasAssoc>::Assoc = loop {}; - //[next]~^ WARN: overflow evaluating the requirement `>>>>>> as HasAssoc>::Assoc == _` [recursion_depth_exceeding_limit] + //[next]~^ WARN: overflow evaluating the requirement `>>>>>> as HasAssoc>::Assoc == ()` [recursion_depth_exceeding_limit] //[next]~| WARN: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! // Force normalization when looking up methods and the self_ty is normalized to infer. b.anyone_can_call(); diff --git a/tests/ui/traits/next-solver/overflow/fcw-overflow-to-ambig-with-constraints.next.stderr b/tests/ui/traits/next-solver/overflow/fcw-overflow-to-ambig-with-constraints.next.stderr index 507132eface89..56d9de921a03d 100644 --- a/tests/ui/traits/next-solver/overflow/fcw-overflow-to-ambig-with-constraints.next.stderr +++ b/tests/ui/traits/next-solver/overflow/fcw-overflow-to-ambig-with-constraints.next.stderr @@ -1,4 +1,4 @@ -warning: overflow evaluating the requirement `u32: Constrain<_, _, W>, _>, _>>` +warning: overflow evaluating the requirement `u32: Constrain>, _>, _>>` --> $DIR/fcw-overflow-to-ambig-with-constraints.rs:29:5 | LL | fun_times(); diff --git a/tests/ui/traits/next-solver/overflow/fcw-overflow-to-ambig-with-constraints.rs b/tests/ui/traits/next-solver/overflow/fcw-overflow-to-ambig-with-constraints.rs index 6ef671d7dd471..440e1fd4525bd 100644 --- a/tests/ui/traits/next-solver/overflow/fcw-overflow-to-ambig-with-constraints.rs +++ b/tests/ui/traits/next-solver/overflow/fcw-overflow-to-ambig-with-constraints.rs @@ -27,6 +27,6 @@ where fn main() { fun_times(); - //[next]~^ WARN overflow evaluating the requirement `u32: Constrain<_, _, W>, _>, _>>` + //[next]~^ WARN overflow evaluating the requirement `u32: Constrain>, _>, _>>` //[next]~| WARN: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! } From c0683f6c3a35c991a232e9178f1462280484b7a1 Mon Sep 17 00:00:00 2001 From: Adwin White Date: Tue, 18 Aug 2026 10:31:51 +0800 Subject: [PATCH 4/6] add required_depth to `InspectGoal` --- compiler/rustc_middle/src/queries.rs | 4 ++-- compiler/rustc_middle/src/query/erase.rs | 2 +- .../src/ty/context/impl_interner.rs | 4 ++-- compiler/rustc_middle/src/ty/mod.rs | 1 + .../src/solve/eval_ctxt/mod.rs | 24 +++++++++++-------- compiler/rustc_trait_selection/src/solve.rs | 4 ++-- .../src/solve/inspect/analyse.rs | 19 ++++++++++++--- compiler/rustc_type_ir/src/interner.rs | 3 ++- .../src/search_graph/global_cache.rs | 10 ++++---- .../rustc_type_ir/src/search_graph/mod.rs | 17 +++++++------ .../rustc_type_ir/src/search_graph/stack.rs | 5 ++-- compiler/rustc_type_ir/src/solve/inspect.rs | 2 ++ 12 files changed, 60 insertions(+), 35 deletions(-) diff --git a/compiler/rustc_middle/src/queries.rs b/compiler/rustc_middle/src/queries.rs index ba790cadfe24f..03ff0716ad979 100644 --- a/compiler/rustc_middle/src/queries.rs +++ b/compiler/rustc_middle/src/queries.rs @@ -115,7 +115,7 @@ use crate::ty::print::PrintTraitRefExt; use crate::ty::util::AlwaysRequiresDrop; use crate::ty::{ self, CrateInherentImpls, GenericArg, GenericArgsRef, LitToConstInput, PseudoCanonicalInput, - SizedTraitKind, Ty, TyCtxt, TyCtxtFeed, + RequiredDepth, SizedTraitKind, Ty, TyCtxt, TyCtxtFeed, }; use crate::{mir, thir}; @@ -2643,7 +2643,7 @@ rustc_queries! { /// Used by `-Znext-solver` to compute proof trees. query evaluate_root_goal_for_proof_tree_raw( key: (solve::CanonicalInput<'tcx>, usize) - ) -> (solve::QueryResult<'tcx>, &'tcx solve::inspect::Probe>) { + ) -> (solve::QueryResult<'tcx>, &'tcx solve::inspect::Probe>, RequiredDepth) { no_hash desc { "computing proof tree for `{}` with depth `{}`", key.0.canonical.value.goal.predicate, key.1 } } diff --git a/compiler/rustc_middle/src/query/erase.rs b/compiler/rustc_middle/src/query/erase.rs index 7dcd364bde8bf..23c02ffcb09c4 100644 --- a/compiler/rustc_middle/src/query/erase.rs +++ b/compiler/rustc_middle/src/query/erase.rs @@ -172,7 +172,7 @@ impl_erasable_for_types_with_no_type_params! { // tidy-alphabetical-start (&'_ ty::CrateInherentImpls, Result<(), ErrorGuaranteed>), (), - (traits::solve::QueryResult<'_>, &'_ traits::solve::inspect::Probe>), + (traits::solve::QueryResult<'_>, &'_ traits::solve::inspect::Probe>, ty::RequiredDepth), Option<&'_ OsStr>, Option<&'_ [rustc_hir::PreciseCapturingArgKind]>, Option<(mir::ConstValue, Ty<'_>)>, diff --git a/compiler/rustc_middle/src/ty/context/impl_interner.rs b/compiler/rustc_middle/src/ty/context/impl_interner.rs index f19adb5b9d553..048e509ec88e0 100644 --- a/compiler/rustc_middle/src/ty/context/impl_interner.rs +++ b/compiler/rustc_middle/src/ty/context/impl_interner.rs @@ -23,7 +23,7 @@ use crate::traits::solve::{ }; use crate::ty::{ self, BoundRegion, Clause, Const, List, ParamTy, Pattern, PolyExistentialPredicate, Predicate, - Region, RegionKind, Ty, TyCtxt, + Region, RegionKind, RequiredDepth, Ty, TyCtxt, }; #[allow(rustc::usage_of_ty_tykind)] @@ -668,7 +668,7 @@ impl<'tcx> Interner for TyCtxt<'tcx> { self, canonical_goal: CanonicalInput<'tcx>, root_depth: usize, - ) -> (QueryResult<'tcx>, &'tcx inspect::Probe>) { + ) -> (QueryResult<'tcx>, &'tcx inspect::Probe>, RequiredDepth) { self.evaluate_root_goal_for_proof_tree_raw((canonical_goal, root_depth)) } diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs index 3d8e30191c700..3dec913ab9481 100644 --- a/compiler/rustc_middle/src/ty/mod.rs +++ b/compiler/rustc_middle/src/ty/mod.rs @@ -59,6 +59,7 @@ use rustc_target::callconv::FnAbi; pub use rustc_type_ir::data_structures::{DelayedMap, DelayedSet}; pub use rustc_type_ir::fast_reject::DeepRejectCtxt; pub use rustc_type_ir::relate::VarianceDiagInfo; +pub use rustc_type_ir::search_graph::RequiredDepth; pub use rustc_type_ir::solve::{CandidatePreferenceMode, SizedTraitKind, VisibleForLeakCheck}; pub use rustc_type_ir::*; use tracing::{debug, instrument}; diff --git a/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/mod.rs b/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/mod.rs index a4f868abfd409..7dc3211bfd5cf 100644 --- a/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/mod.rs +++ b/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/mod.rs @@ -8,7 +8,9 @@ use rustc_type_ir::inherent::*; use rustc_type_ir::region_constraint::{RegionConstraint, evaluate_solver_constraint}; use rustc_type_ir::relate::Relate; use rustc_type_ir::relate::solver_relating::RelateExt; -use rustc_type_ir::search_graph::{CandidateHeadUsages, LowerAvailableDepth, PathKind}; +use rustc_type_ir::search_graph::{ + CandidateHeadUsages, LowerAvailableDepth, PathKind, RequiredDepth, +}; use rustc_type_ir::solve::{ AccessedOpaques, ExternalRegionConstraints, FetchEligibleAssocItemResponse, MaybeInfo, NoSolutionOrRerunNonErased, OpaqueTypesJank, QueryResultOrRerunNonErased, RerunCondition, @@ -1832,18 +1834,19 @@ pub fn evaluate_root_goal_for_proof_tree_raw_provider< cx: I, canonical_goal: CanonicalInput, root_depth: usize, -) -> (QueryResult, I::Probe) { +) -> (QueryResult, I::Probe, RequiredDepth) { let mut inspect = inspect::ProofTreeBuilder::new(); - let (canonical_result, accessed_opaques) = SearchGraph::::evaluate_root_goal_for_proof_tree( - cx, - root_depth, - canonical_goal, - &mut inspect, - ); + let ((canonical_result, accessed_opaques), required_depth) = + SearchGraph::::evaluate_root_goal_for_proof_tree( + cx, + root_depth, + canonical_goal, + &mut inspect, + ); let final_revision = inspect.unwrap(); assert!(!accessed_opaques.might_rerun()); - (canonical_result, cx.mk_probe(final_revision)) + (canonical_result, cx.mk_probe(final_revision), required_depth) } /// Evaluate a goal to build a proof tree. @@ -1863,7 +1866,7 @@ pub(super) fn evaluate_root_goal_for_proof_tree, let (orig_values, canonical_goal) = canonicalize_goal(delegate, goal, &opaque_types, typing_mode.into()); - let (canonical_result, final_revision) = + let (canonical_result, final_revision, required_depth) = delegate.cx().evaluate_root_goal_for_proof_tree_raw(canonical_goal, root_depth); let proof_tree = inspect::GoalEvaluation { @@ -1871,6 +1874,7 @@ pub(super) fn evaluate_root_goal_for_proof_tree, orig_values, final_revision, result: canonical_result, + required_depth, }; let response = match canonical_result { diff --git a/compiler/rustc_trait_selection/src/solve.rs b/compiler/rustc_trait_selection/src/solve.rs index f6c01b12ae4c0..4766ea6f2cf6e 100644 --- a/compiler/rustc_trait_selection/src/solve.rs +++ b/compiler/rustc_trait_selection/src/solve.rs @@ -14,13 +14,13 @@ pub use normalize::{ deeply_normalize_with_skipped_universes_and_ambiguous_coroutine_goals, normalize, }; use rustc_middle::query::Providers; -use rustc_middle::ty::TyCtxt; +use rustc_middle::ty::{RequiredDepth, TyCtxt}; pub use select::InferCtxtSelectExt; fn evaluate_root_goal_for_proof_tree_raw<'tcx>( tcx: TyCtxt<'tcx>, key: (CanonicalInput>, usize), -) -> (QueryResult>, &'tcx inspect::Probe>) { +) -> (QueryResult>, &'tcx inspect::Probe>, RequiredDepth) { evaluate_root_goal_for_proof_tree_raw_provider::, TyCtxt<'tcx>>( tcx, key.0, key.1, ) diff --git a/compiler/rustc_trait_selection/src/solve/inspect/analyse.rs b/compiler/rustc_trait_selection/src/solve/inspect/analyse.rs index f7d6fe2481b2d..aaba2f86da598 100644 --- a/compiler/rustc_trait_selection/src/solve/inspect/analyse.rs +++ b/compiler/rustc_trait_selection/src/solve/inspect/analyse.rs @@ -14,7 +14,7 @@ use std::assert_matches; use rustc_infer::infer::InferCtxt; use rustc_macros::extension; use rustc_middle::traits::solve::{Certainty, Goal, GoalSource, NoSolution, QueryResult}; -use rustc_middle::ty::{TyCtxt, VisitorResult, eager_resolve_vars, try_visit}; +use rustc_middle::ty::{RequiredDepth, TyCtxt, VisitorResult, eager_resolve_vars, try_visit}; use rustc_middle::{bug, ty}; use rustc_next_trait_solver::canonical::instantiate_canonical_state; use rustc_next_trait_solver::solve::{MaybeCause, MaybeInfo, SolverDelegateEvalExt as _, inspect}; @@ -30,7 +30,10 @@ pub struct InspectConfig { pub struct InspectGoal<'a, 'tcx> { infcx: &'a SolverDelegate<'tcx>, + // Record how deep we are in nested goals from the root goal. depth: usize, + // Required depth to complete the evaluation of this goal. + required_depth: RequiredDepth, orig_values: ThinVec>, prev_universe: ty::UniverseIndex, goal: Goal<'tcx, ty::Predicate<'tcx>>, @@ -231,6 +234,10 @@ impl<'a, 'tcx> InspectGoal<'a, 'tcx> { self.depth } + pub fn required_depth(&self) -> RequiredDepth { + self.required_depth + } + pub fn orig_values(&self) -> &[ty::GenericArg<'tcx>] { &self.orig_values } @@ -338,8 +345,13 @@ impl<'a, 'tcx> InspectGoal<'a, 'tcx> { let infcx = <&SolverDelegate<'tcx>>::from(infcx); let prev_universe = infcx.universe(); - let inspect::GoalEvaluation { uncanonicalized_goal, orig_values, final_revision, result } = - root; + let inspect::GoalEvaluation { + uncanonicalized_goal, + orig_values, + final_revision, + result, + required_depth, + } = root; // If there's a normalizes-to goal, AND the evaluation result with the result of // constraining the normalizes-to RHS and computing the nested goals. let result = result.map(|ok| ok.value.certainty); @@ -353,6 +365,7 @@ impl<'a, 'tcx> InspectGoal<'a, 'tcx> { result, final_revision, source, + required_depth, } } diff --git a/compiler/rustc_type_ir/src/interner.rs b/compiler/rustc_type_ir/src/interner.rs index 3d57648f1900e..d230791304527 100644 --- a/compiler/rustc_type_ir/src/interner.rs +++ b/compiler/rustc_type_ir/src/interner.rs @@ -15,6 +15,7 @@ use crate::intern::Interned; use crate::ir_print::IrPrint; use crate::lang_items::{SolverAdtLangItem, SolverProjectionLangItem, SolverTraitLangItem}; use crate::relate::Relate; +use crate::search_graph::RequiredDepth; use crate::solve::{ AccessedOpaques, CanonicalInput, Certainty, ExternalConstraintsData, QueryResult, inspect, }; @@ -500,7 +501,7 @@ pub trait Interner: self, canonical_goal: CanonicalInput, root_depth: usize, - ) -> (QueryResult, Self::Probe); + ) -> (QueryResult, Self::Probe, RequiredDepth); fn item_name(self, item_index: Self::DefId) -> Self::Symbol; diff --git a/compiler/rustc_type_ir/src/search_graph/global_cache.rs b/compiler/rustc_type_ir/src/search_graph/global_cache.rs index fcbc8b281d132..200ded3cca761 100644 --- a/compiler/rustc_type_ir/src/search_graph/global_cache.rs +++ b/compiler/rustc_type_ir/src/search_graph/global_cache.rs @@ -1,11 +1,11 @@ use derive_where::derive_where; -use super::{AvailableDepth, Cx, NestedGoals}; +use super::{AvailableDepth, Cx, NestedGoals, RequiredDepth}; use crate::data_structures::HashMap; use crate::search_graph::EvaluationResult; struct Success { - required_depth: usize, + required_depth: RequiredDepth, nested_goals: NestedGoals, result: X::Tracked, } @@ -23,13 +23,13 @@ struct WithOverflow { #[derive_where(Default; X: Cx)] struct CacheEntry { success: Option>, - with_overflow: HashMap>, + with_overflow: HashMap>, } #[derive_where(Debug; X: Cx)] pub(super) struct CacheData<'a, X: Cx> { pub(super) result: X::Result, - pub(super) required_depth: usize, + pub(super) required_depth: RequiredDepth, pub(super) encountered_overflow: bool, pub(super) nested_goals: &'a NestedGoals, } @@ -97,7 +97,7 @@ impl GlobalCache { }); } - let additional_depth = available_depth.0; + let additional_depth = RequiredDepth(available_depth.0); if let Some(WithOverflow { nested_goals, result }) = entry.with_overflow.get(&additional_depth) && candidate_is_applicable(nested_goals) diff --git a/compiler/rustc_type_ir/src/search_graph/mod.rs b/compiler/rustc_type_ir/src/search_graph/mod.rs index b1635e7e4097c..c1cc1de08cbd8 100644 --- a/compiler/rustc_type_ir/src/search_graph/mod.rs +++ b/compiler/rustc_type_ir/src/search_graph/mod.rs @@ -311,11 +311,14 @@ impl AvailableDepth { /// Whether we're allowed to use a global cache entry which required /// the given depth. - fn cache_entry_is_applicable(self, additional_depth: usize) -> bool { - self.0 >= additional_depth + fn cache_entry_is_applicable(self, required_depth: RequiredDepth) -> bool { + self.0 >= required_depth.0 } } +#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] +pub struct RequiredDepth(pub usize); + #[derive(Clone, Copy, Debug)] struct CycleHead { paths_to_head: PathsToNested, @@ -569,7 +572,7 @@ struct ProvisionalCacheEntry { #[derive_where(Debug; X: Cx)] struct EvaluationResult { encountered_overflow: bool, - required_depth: usize, + required_depth: RequiredDepth, heads: CycleHeads, nested_goals: NestedGoals, result: X::Result, @@ -750,7 +753,7 @@ impl, X: Cx> SearchGraph { root_depth: usize, input: X::Input, inspect: &mut D::ProofTreeBuilder, - ) -> X::Result { + ) -> (X::Result, RequiredDepth) { let mut this = SearchGraph::::new(root_depth); let available_depth = AvailableDepth(root_depth); let step_kind_from_parent = PathKind::Inductive; // is never used @@ -767,7 +770,7 @@ impl, X: Cx> SearchGraph { nested_goals: Default::default(), }); let evaluation_result = this.evaluate_goal_in_task(cx, input, inspect); - evaluation_result.result + (evaluation_result.result, evaluation_result.required_depth) } /// Probably the most involved method of the whole solver. @@ -865,7 +868,7 @@ impl, X: Cx> SearchGraph { UpdateParentGoalCtxt::Ordinary { nested_goals: &evaluation_result.nested_goals, min_reachable_available_depth: AvailableDepth( - available_depth.0 - evaluation_result.required_depth, + available_depth.0 - evaluation_result.required_depth.0, ), }, ); @@ -1271,7 +1274,7 @@ impl, X: Cx> SearchGraph { UpdateParentGoalCtxt::Ordinary { nested_goals, min_reachable_available_depth: AvailableDepth( - available_depth.0 - required_depth, + available_depth.0 - required_depth.0, ), }, ); diff --git a/compiler/rustc_type_ir/src/search_graph/stack.rs b/compiler/rustc_type_ir/src/search_graph/stack.rs index 429009c46b314..5a93b941f3a64 100644 --- a/compiler/rustc_type_ir/src/search_graph/stack.rs +++ b/compiler/rustc_type_ir/src/search_graph/stack.rs @@ -5,6 +5,7 @@ use rustc_index::IndexVec; use crate::search_graph::{ AvailableDepth, CandidateHeadUsages, Cx, CycleHeads, HeadUsages, NestedGoals, PathKind, + RequiredDepth, }; rustc_index::newtype_index! { @@ -59,8 +60,8 @@ pub(super) struct StackEntry { } impl StackEntry { - pub(super) fn required_depth(&self) -> usize { - self.available_depth.0 - self.min_reached_available_depth.0 + pub(super) fn required_depth(&self) -> RequiredDepth { + RequiredDepth(self.available_depth.0 - self.min_reached_available_depth.0) } } diff --git a/compiler/rustc_type_ir/src/solve/inspect.rs b/compiler/rustc_type_ir/src/solve/inspect.rs index 783ee23fd9fbd..3f0d7f5893265 100644 --- a/compiler/rustc_type_ir/src/solve/inspect.rs +++ b/compiler/rustc_type_ir/src/solve/inspect.rs @@ -21,6 +21,7 @@ use derive_where::derive_where; use rustc_type_ir_macros::{GenericTypeVisitable, TypeFoldable_Generic, TypeVisitable_Generic}; use thin_vec::ThinVec; +use crate::search_graph::RequiredDepth; use crate::solve::{CandidateSource, Certainty, Goal, GoalSource, QueryResult}; use crate::{Canonical, CanonicalVarValues, Interner}; @@ -52,6 +53,7 @@ pub struct GoalEvaluation { pub orig_values: ThinVec, pub final_revision: I::Probe, pub result: QueryResult, + pub required_depth: RequiredDepth, } /// A self-contained computation during trait solving. This either From be2ff7e18e085547bf794e12f1763585a06e83ac Mon Sep 17 00:00:00 2001 From: Adwin White Date: Mon, 17 Aug 2026 17:45:32 +0800 Subject: [PATCH 5/6] visit nested goal with largest required depth --- compiler/rustc_infer/src/infer/at.rs | 4 +- compiler/rustc_infer/src/infer/context.rs | 2 +- compiler/rustc_infer/src/infer/mod.rs | 16 +++- .../rustc_next_trait_solver/src/delegate.rs | 2 +- .../src/solve/eval_ctxt/mod.rs | 4 +- .../src/solve/delegate.rs | 78 +++++++++++++++---- .../overflow-discards-constraints.rs | 4 - .../overflow-discards-constraints.stderr | 9 ++- .../overflow/fcw-on-auto-trait.next.stderr | 13 +++- .../next-solver/overflow/fcw-on-auto-trait.rs | 3 - .../overflow/fcw-on-normalization.next.stderr | 8 +- .../overflow/fcw-on-normalization.rs | 7 +- ...flow-to-ambig-with-constraints.next.stderr | 13 +++- .../fcw-overflow-to-ambig-with-constraints.rs | 2 +- 14 files changed, 119 insertions(+), 46 deletions(-) diff --git a/compiler/rustc_infer/src/infer/at.rs b/compiler/rustc_infer/src/infer/at.rs index bab3c207984f6..85e9e612dfc9c 100644 --- a/compiler/rustc_infer/src/infer/at.rs +++ b/compiler/rustc_infer/src/infer/at.rs @@ -85,7 +85,7 @@ impl<'tcx> InferCtxt<'tcx> { .placeholder_assumptions_for_next_solver .clone(), next_trait_solver: self.next_trait_solver, - enable_next_solver_overflow_fcw: self.enable_next_solver_overflow_fcw, + enable_next_solver_overflow_fcw: self.enable_next_solver_overflow_fcw.clone(), obligation_inspector: self.obligation_inspector.clone(), canonicalizer_state: Default::default(), } @@ -115,7 +115,7 @@ impl<'tcx> InferCtxt<'tcx> { .placeholder_assumptions_for_next_solver .clone(), next_trait_solver: self.next_trait_solver, - enable_next_solver_overflow_fcw: self.enable_next_solver_overflow_fcw, + enable_next_solver_overflow_fcw: self.enable_next_solver_overflow_fcw.clone(), obligation_inspector: self.obligation_inspector.clone(), canonicalizer_state: Default::default(), }; diff --git a/compiler/rustc_infer/src/infer/context.rs b/compiler/rustc_infer/src/infer/context.rs index 84ffccd6f2c80..5eafe73301ba7 100644 --- a/compiler/rustc_infer/src/infer/context.rs +++ b/compiler/rustc_infer/src/infer/context.rs @@ -27,7 +27,7 @@ impl<'tcx> rustc_type_ir::InferCtxtLike for InferCtxt<'tcx> { } fn enable_next_solver_overflow_fcw(&self) -> bool { - self.enable_next_solver_overflow_fcw + self.enable_next_solver_overflow_fcw.get() } fn disable_trait_solver_fast_paths(&self) -> bool { diff --git a/compiler/rustc_infer/src/infer/mod.rs b/compiler/rustc_infer/src/infer/mod.rs index 906ffe710e03a..333ed7c360080 100644 --- a/compiler/rustc_infer/src/infer/mod.rs +++ b/compiler/rustc_infer/src/infer/mod.rs @@ -345,7 +345,7 @@ pub struct InferCtxt<'tcx> { /// already used by default in some places so we know they won't have /// additional breakages. We also don't want spurious result in coherence /// checking so we disable the FCW there as well. - enable_next_solver_overflow_fcw: bool, + enable_next_solver_overflow_fcw: Cell, pub obligation_inspector: Cell>>, @@ -691,7 +691,7 @@ impl<'tcx> InferCtxtBuilder<'tcx> { universe: Cell::new(ty::UniverseIndex::ROOT), placeholder_assumptions_for_next_solver: RefCell::new(Default::default()), next_trait_solver, - enable_next_solver_overflow_fcw, + enable_next_solver_overflow_fcw: Cell::new(enable_next_solver_overflow_fcw), obligation_inspector: Cell::new(None), canonicalizer_state: Default::default(), } @@ -1556,6 +1556,18 @@ impl<'tcx> InferCtxt<'tcx> { u } + /// We need to disable the fcw if we're already in a fcw emitting to avoid + /// indefinite triggering. + pub fn enter_next_solver_overflow_fcw(&self, mut f: F) -> R + where + F: FnMut() -> R, + { + let prev = self.enable_next_solver_overflow_fcw.replace(false); + let ret = f(); + self.enable_next_solver_overflow_fcw.set(prev); + ret + } + /// Extract [`ty::TypingMode`] of this inference context to get a `TypingEnv` /// which contains the necessary information to use the trait system without /// using canonicalization or carrying this inference context around. diff --git a/compiler/rustc_next_trait_solver/src/delegate.rs b/compiler/rustc_next_trait_solver/src/delegate.rs index 0e414b35d769a..0a307f766ebb2 100644 --- a/compiler/rustc_next_trait_solver/src/delegate.rs +++ b/compiler/rustc_next_trait_solver/src/delegate.rs @@ -127,7 +127,7 @@ pub trait SolverDelegate: Deref + Sized { fn emit_next_solver_overflow_fcw( &self, - predicate: ::Predicate, + goal: Goal::Predicate>, span: ::Span, ); } diff --git a/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/mod.rs b/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/mod.rs index 7dc3211bfd5cf..d7db7d90acc38 100644 --- a/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/mod.rs +++ b/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/mod.rs @@ -368,7 +368,7 @@ fn maybe_evaluate_root_goal_with_higher_recursion_limit( } }); if let Ok(rerun_result) = rerun_result { - delegate.emit_next_solver_overflow_fcw(predicate, span); + delegate.emit_next_solver_overflow_fcw(goal.with(delegate.cx(), predicate), span); *initial_result = rerun_result; } } @@ -418,7 +418,7 @@ fn maybe_evaluate_root_goal_for_proof_tree_with_higher_recursion_limit( }); if let Ok(rerun_result) = rerun_result { let predicate: I::Predicate = goal_evaluation.uncanonicalized_goal.predicate; - delegate.emit_next_solver_overflow_fcw(predicate, span); + delegate.emit_next_solver_overflow_fcw(goal.with(delegate.cx(), predicate), span); *initial_result = rerun_result; } } diff --git a/compiler/rustc_trait_selection/src/solve/delegate.rs b/compiler/rustc_trait_selection/src/solve/delegate.rs index 89e739e797850..82dfffe4d5126 100644 --- a/compiler/rustc_trait_selection/src/solve/delegate.rs +++ b/compiler/rustc_trait_selection/src/solve/delegate.rs @@ -1,7 +1,7 @@ use std::collections::hash_map::Entry; use std::fmt::Debug; use std::mem; -use std::ops::Deref; +use std::ops::{ControlFlow, Deref}; use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc_hir::CRATE_HIR_ID; @@ -30,6 +30,8 @@ use rustc_span::{DUMMY_SP, Span}; use rustc_structures::Limit; use thin_vec::{ThinVec, thin_vec}; +use super::inspect::InferCtxtProofTreeExt; +use crate::solve::inspect::{self, InspectConfig, ProofTreeVisitor}; use crate::traits::{EvaluateConstErr, ObligationCause, sizedness_fast_path, specialization_graph}; #[repr(transparent)] @@ -510,40 +512,90 @@ impl<'tcx> rustc_next_trait_solver::delegate::SolverDelegate for SolverDelegate< *self.canonicalizer_state.borrow_mut() = state; } - fn emit_next_solver_overflow_fcw(&self, predicate: ty::Predicate<'tcx>, span: Span) { + fn emit_next_solver_overflow_fcw(&self, goal: Goal<'tcx, ty::Predicate<'tcx>>, span: Span) { let tcx = self.tcx; - let predicate = self.resolve_vars_if_possible(predicate); + let goal = self.resolve_vars_if_possible(goal); + let mut visitor = OverflowedGoalChain { + span, + predicates: vec![], + recursion_limit: usize::min(16, tcx.recursion_limit().0), + }; + let _ = self.enter_next_solver_overflow_fcw(|| self.visit_proof_tree(goal, &mut visitor)); tcx.emit_node_span_lint( RECURSION_DEPTH_EXCEEDING_LIMIT, CRATE_HIR_ID, span, rustc_errors::DiagDecorator(|diag| { // FIXME: share this with overflow error in fulfillment instead of duplicating. - let pred_str = { - let s = predicate.to_string(); - if s.len() > 50 { + let pred_str = |pred: ty::Predicate<'tcx>| { + let s = pred.to_string(); + if s.len() > 80 { let mut p: FmtPrinter<'_, '_> = - FmtPrinter::new_with_limit(tcx, Namespace::TypeNS, Limit(6)); - predicate.print(&mut p).unwrap(); + FmtPrinter::new_with_limit(tcx, Namespace::TypeNS, Limit(10)); + pred.print(&mut p).unwrap(); p.into_buffer() } else { s } }; diag.primary_message(format!( - "overflow evaluating the requirement `{pred_str}`", + "overflow evaluating the requirement `{}`", + pred_str(goal.predicate), )); + for p in visitor.predicates.into_iter().skip(1) { + diag.note(format!("which requires {}", pred_str(p))); + } + diag.help( + "consider adding a manual `impl` of auto traits like `Send` for intermediate types, if auto traits are involved", + ); diag.help(format!( - "consider increasing the recursion limit by adding a \ + "or consider increasing the recursion limit by adding a \ `#![recursion_limit = \"{}\"]` attribute to your crate (`{}`)", tcx.recursion_limit() * 2, tcx.crate_name(LOCAL_CRATE), )); - diag.help( - "or consider adding a manual `impl` of auto traits like `Send` for intermediate types, if auto traits are involved", - ); diag.note("this lint is attached to the whole crate and can't be disabled on a per-function basis"); }), ) } } + +struct OverflowedGoalChain<'tcx> { + span: Span, + predicates: Vec>, + recursion_limit: usize, +} + +impl<'tcx> ProofTreeVisitor<'tcx> for OverflowedGoalChain<'tcx> { + type Result = ControlFlow<()>; + + fn span(&self) -> Span { + self.span + } + + fn config(&self) -> InspectConfig { + InspectConfig { max_depth: self.recursion_limit } + } + + fn visit_goal(&mut self, goal: &inspect::InspectGoal<'_, 'tcx>) -> Self::Result { + self.predicates.push(goal.goal().predicate); + if let Some(cand) = goal.unique_applicable_candidate() { + goal.infcx().probe(|_| { + if let Some(nested_goal_with_largest_required_depth) = cand + .instantiate_nested_goals(self.span) + .into_iter() + .max_by_key(|g| g.required_depth()) + { + nested_goal_with_largest_required_depth.visit_with(self) + } else { + ControlFlow::Continue(()) + } + })?; + } + ControlFlow::Continue(()) + } + + fn on_recursion_limit(&mut self) -> Self::Result { + ControlFlow::Break(()) + } +} diff --git a/tests/ui/traits/next-solver/overflow-discards-constraints.rs b/tests/ui/traits/next-solver/overflow-discards-constraints.rs index 259875025ea7b..810d756625b01 100644 --- a/tests/ui/traits/next-solver/overflow-discards-constraints.rs +++ b/tests/ui/traits/next-solver/overflow-discards-constraints.rs @@ -11,10 +11,6 @@ // Setting it to 12 would make it compile. #![recursion_limit = "6"] - -//~^^^^^^^^^^^^^^ WARN: overflow evaluating the requirement `(): Trait` [recursion_depth_exceeding_limit] -//~| WARN: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - trait Trait {} struct W1(T); diff --git a/tests/ui/traits/next-solver/overflow-discards-constraints.stderr b/tests/ui/traits/next-solver/overflow-discards-constraints.stderr index 68c1e88181f17..ae2680cf6394e 100644 --- a/tests/ui/traits/next-solver/overflow-discards-constraints.stderr +++ b/tests/ui/traits/next-solver/overflow-discards-constraints.stderr @@ -4,8 +4,13 @@ warning: overflow evaluating the requirement `(): Trait` LL | foo(); // register a `(): Trait` obligation | ^^^^^ | - = help: consider increasing the recursion limit by adding a `#![recursion_limit = "12"]` attribute to your crate (`overflow_discards_constraints`) - = help: or consider adding a manual `impl` of auto traits like `Send` for intermediate types, if auto traits are involved + = note: which requires W1: Trait + = note: which requires W2: Trait + = note: which requires W3: Trait + = note: which requires W4: Trait + = note: which requires W5: Trait + = help: consider adding a manual `impl` of auto traits like `Send` for intermediate types, if auto traits are involved + = help: or consider increasing the recursion limit by adding a `#![recursion_limit = "12"]` attribute to your crate (`overflow_discards_constraints`) = note: this lint is attached to the whole crate and can't be disabled on a per-function basis = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! = note: for more information, see issue #159228 diff --git a/tests/ui/traits/next-solver/overflow/fcw-on-auto-trait.next.stderr b/tests/ui/traits/next-solver/overflow/fcw-on-auto-trait.next.stderr index bd4b8b63a990b..94c87862ae716 100644 --- a/tests/ui/traits/next-solver/overflow/fcw-on-auto-trait.next.stderr +++ b/tests/ui/traits/next-solver/overflow/fcw-on-auto-trait.next.stderr @@ -1,11 +1,18 @@ warning: overflow evaluating the requirement `Foo>>>>>: Sync` - --> $DIR/fcw-on-auto-trait.rs:25:5 + --> $DIR/fcw-on-auto-trait.rs:22:5 | LL | require_sync::>>>>>>(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | - = help: consider increasing the recursion limit by adding a `#![recursion_limit = "16"]` attribute to your crate (`fcw_on_auto_trait`) - = help: or consider adding a manual `impl` of auto traits like `Send` for intermediate types, if auto traits are involved + = note: which requires Option>>>>>: Sync + = note: which requires Foo>>>>: Sync + = note: which requires Option>>>>: Sync + = note: which requires Foo>>>: Sync + = note: which requires Option>>>: Sync + = note: which requires Foo>>: Sync + = note: which requires Option>>: Sync + = help: consider adding a manual `impl` of auto traits like `Send` for intermediate types, if auto traits are involved + = help: or consider increasing the recursion limit by adding a `#![recursion_limit = "16"]` attribute to your crate (`fcw_on_auto_trait`) = note: this lint is attached to the whole crate and can't be disabled on a per-function basis = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! = note: for more information, see issue #159228 diff --git a/tests/ui/traits/next-solver/overflow/fcw-on-auto-trait.rs b/tests/ui/traits/next-solver/overflow/fcw-on-auto-trait.rs index 9252a04b9f6ce..73c0a5c153893 100644 --- a/tests/ui/traits/next-solver/overflow/fcw-on-auto-trait.rs +++ b/tests/ui/traits/next-solver/overflow/fcw-on-auto-trait.rs @@ -7,9 +7,6 @@ // and emit an FCW for this. // See the `NEXT_TRAIT_SOLVER_OVERFLOW` FCW. -//[next]~^^^^^^^^^ WARN: overflow evaluating the requirement `Foo>>>>>: Sync` [recursion_depth_exceeding_limit] -//[next]~| WARN: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - #![recursion_limit = "8"] // The field order matters 😂 diff --git a/tests/ui/traits/next-solver/overflow/fcw-on-normalization.next.stderr b/tests/ui/traits/next-solver/overflow/fcw-on-normalization.next.stderr index 0726f81a0f7be..6c9224a7120c5 100644 --- a/tests/ui/traits/next-solver/overflow/fcw-on-normalization.next.stderr +++ b/tests/ui/traits/next-solver/overflow/fcw-on-normalization.next.stderr @@ -1,11 +1,13 @@ -warning: overflow evaluating the requirement `>>>>>> as HasAssoc>::Assoc == ()` +warning: overflow evaluating the requirement `>>>>>>>>> as HasAssoc>::Assoc == ()` --> $DIR/fcw-on-normalization.rs:40:12 | LL | let b: >>>>>>>>> as HasAssoc>::Assoc = loop {}; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | - = help: consider increasing the recursion limit by adding a `#![recursion_limit = "16"]` attribute to your crate (`fcw_on_normalization`) - = help: or consider adding a manual `impl` of auto traits like `Send` for intermediate types, if auto traits are involved + = note: which requires >>>>>>>> as HasAssoc>::Assoc == () + = note: which requires >>>>>>> as HasAssoc>::Assoc == () + = help: consider adding a manual `impl` of auto traits like `Send` for intermediate types, if auto traits are involved + = help: or consider increasing the recursion limit by adding a `#![recursion_limit = "16"]` attribute to your crate (`fcw_on_normalization`) = note: this lint is attached to the whole crate and can't be disabled on a per-function basis = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! = note: for more information, see issue #159228 diff --git a/tests/ui/traits/next-solver/overflow/fcw-on-normalization.rs b/tests/ui/traits/next-solver/overflow/fcw-on-normalization.rs index 9845d38abc2c4..c8fa0366f2944 100644 --- a/tests/ui/traits/next-solver/overflow/fcw-on-normalization.rs +++ b/tests/ui/traits/next-solver/overflow/fcw-on-normalization.rs @@ -7,11 +7,6 @@ // and emit an FCW for this. // See the `recursion_depth_exceeding_limit` FCW. -//[next]~^^^^^^^^^ WARN: overflow evaluating the requirement `>>>>>> as HasAssoc>::Assoc == _` [recursion_depth_exceeding_limit] -//[next]~| WARN: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! -//[next]~| WARN: overflow evaluating the requirement `>>>>> as HasAssoc>::Assoc well-formed` [recursion_depth_exceeding_limit] -//[next]~| WARN: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - #![recursion_limit = "8"] trait Trait { @@ -43,7 +38,7 @@ fn foo() { a.anyone_can_call(); let b: >>>>>>>>> as HasAssoc>::Assoc = loop {}; - //[next]~^ WARN: overflow evaluating the requirement `>>>>>> as HasAssoc>::Assoc == ()` [recursion_depth_exceeding_limit] + //[next]~^ WARN: overflow evaluating the requirement `>>>>>>>>> as HasAssoc>::Assoc == ()` [recursion_depth_exceeding_limit] //[next]~| WARN: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! // Force normalization when looking up methods and the self_ty is normalized to infer. b.anyone_can_call(); diff --git a/tests/ui/traits/next-solver/overflow/fcw-overflow-to-ambig-with-constraints.next.stderr b/tests/ui/traits/next-solver/overflow/fcw-overflow-to-ambig-with-constraints.next.stderr index 56d9de921a03d..92c0a480869df 100644 --- a/tests/ui/traits/next-solver/overflow/fcw-overflow-to-ambig-with-constraints.next.stderr +++ b/tests/ui/traits/next-solver/overflow/fcw-overflow-to-ambig-with-constraints.next.stderr @@ -1,11 +1,18 @@ -warning: overflow evaluating the requirement `u32: Constrain>, _>, _>>` +warning: overflow evaluating the requirement `u32: Constrain>>>, W, _>>, _>>` --> $DIR/fcw-overflow-to-ambig-with-constraints.rs:29:5 | LL | fun_times(); | ^^^^^^^^^^^ | - = help: consider increasing the recursion limit by adding a `#![recursion_limit = "16"]` attribute to your crate (`fcw_overflow_to_ambig_with_constraints`) - = help: or consider adding a manual `impl` of auto traits like `Send` for intermediate types, if auto traits are involved + = note: which requires W>>>, W>>>, _>>, _>: Count + = note: which requires W>>>, W>>>, _>>, _>: Count + = note: which requires W>>>, W>>>, _>>, _>: Count + = note: which requires W>>>, W>>>, _>>, _>: Count + = note: which requires W>>>, W>>>, W<_, _>>>: Count + = note: which requires W>>>, W>>>, W<_, _>>>: Count + = note: which requires W>>>, W>>>, W<(), _>>>: Count + = help: consider adding a manual `impl` of auto traits like `Send` for intermediate types, if auto traits are involved + = help: or consider increasing the recursion limit by adding a `#![recursion_limit = "16"]` attribute to your crate (`fcw_overflow_to_ambig_with_constraints`) = note: this lint is attached to the whole crate and can't be disabled on a per-function basis = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! = note: for more information, see issue #159228 diff --git a/tests/ui/traits/next-solver/overflow/fcw-overflow-to-ambig-with-constraints.rs b/tests/ui/traits/next-solver/overflow/fcw-overflow-to-ambig-with-constraints.rs index 440e1fd4525bd..d8606225f246f 100644 --- a/tests/ui/traits/next-solver/overflow/fcw-overflow-to-ambig-with-constraints.rs +++ b/tests/ui/traits/next-solver/overflow/fcw-overflow-to-ambig-with-constraints.rs @@ -27,6 +27,6 @@ where fn main() { fun_times(); - //[next]~^ WARN overflow evaluating the requirement `u32: Constrain>, _>, _>>` + //[next]~^ WARN: overflow evaluating the requirement `u32: Constrain>>>, W, _>>, _>>` //[next]~| WARN: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! } From 3f63986a3ab34c34cfcc3f360eca4330e2af0ce8 Mon Sep 17 00:00:00 2001 From: lcnr Date: Sat, 22 Aug 2026 19:02:14 +0200 Subject: [PATCH 6/6] apply nits --- compiler/rustc_infer/src/infer/mod.rs | 2 +- .../rustc_trait_selection/src/solve/delegate.rs | 3 ++- compiler/rustc_type_ir/src/search_graph/mod.rs | 17 +++++++++++------ 3 files changed, 14 insertions(+), 8 deletions(-) diff --git a/compiler/rustc_infer/src/infer/mod.rs b/compiler/rustc_infer/src/infer/mod.rs index 333ed7c360080..eed1e42311e65 100644 --- a/compiler/rustc_infer/src/infer/mod.rs +++ b/compiler/rustc_infer/src/infer/mod.rs @@ -1558,7 +1558,7 @@ impl<'tcx> InferCtxt<'tcx> { /// We need to disable the fcw if we're already in a fcw emitting to avoid /// indefinite triggering. - pub fn enter_next_solver_overflow_fcw(&self, mut f: F) -> R + pub fn with_disabled_next_solver_overflow_fcw(&self, mut f: F) -> R where F: FnMut() -> R, { diff --git a/compiler/rustc_trait_selection/src/solve/delegate.rs b/compiler/rustc_trait_selection/src/solve/delegate.rs index 82dfffe4d5126..3bff243427bb1 100644 --- a/compiler/rustc_trait_selection/src/solve/delegate.rs +++ b/compiler/rustc_trait_selection/src/solve/delegate.rs @@ -520,7 +520,8 @@ impl<'tcx> rustc_next_trait_solver::delegate::SolverDelegate for SolverDelegate< predicates: vec![], recursion_limit: usize::min(16, tcx.recursion_limit().0), }; - let _ = self.enter_next_solver_overflow_fcw(|| self.visit_proof_tree(goal, &mut visitor)); + let _ = self + .with_disabled_next_solver_overflow_fcw(|| self.visit_proof_tree(goal, &mut visitor)); tcx.emit_node_span_lint( RECURSION_DEPTH_EXCEEDING_LIMIT, CRATE_HIR_ID, diff --git a/compiler/rustc_type_ir/src/search_graph/mod.rs b/compiler/rustc_type_ir/src/search_graph/mod.rs index c1cc1de08cbd8..c081898f26f56 100644 --- a/compiler/rustc_type_ir/src/search_graph/mod.rs +++ b/compiler/rustc_type_ir/src/search_graph/mod.rs @@ -18,6 +18,7 @@ use std::fmt::Debug; use std::hash::Hash; use std::iter; use std::marker::PhantomData; +use std::ops::Sub; use derive_where::derive_where; #[cfg(feature = "nightly")] @@ -275,6 +276,14 @@ pub enum LowerAvailableDepth { #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)] struct AvailableDepth(usize); + +impl Sub for AvailableDepth { + type Output = AvailableDepth; + fn sub(self, rhs: RequiredDepth) -> AvailableDepth { + AvailableDepth(self.0.checked_sub(rhs.0).unwrap()) + } +} + impl AvailableDepth { /// Returns the remaining depth allowed for nested goals. /// @@ -867,9 +876,7 @@ impl, X: Cx> SearchGraph { evaluation_result.encountered_overflow, UpdateParentGoalCtxt::Ordinary { nested_goals: &evaluation_result.nested_goals, - min_reachable_available_depth: AvailableDepth( - available_depth.0 - evaluation_result.required_depth.0, - ), + min_reachable_available_depth: available_depth - evaluation_result.required_depth, }, ); let result = evaluation_result.result; @@ -1273,9 +1280,7 @@ impl, X: Cx> SearchGraph { encountered_overflow, UpdateParentGoalCtxt::Ordinary { nested_goals, - min_reachable_available_depth: AvailableDepth( - available_depth.0 - required_depth.0, - ), + min_reachable_available_depth: available_depth - required_depth, }, );