From b1d71e5a6a8d072c9a9bd9ae26703daffc24aa97 Mon Sep 17 00:00:00 2001 From: Adwin White Date: Mon, 24 Aug 2026 16:46:03 +0800 Subject: [PATCH 1/4] eagerly report overflow errors --- .../src/traits/query/normalize.rs | 25 ++++++++++++++++--- .../mgca/free-const-recursive.rs | 6 +++-- .../mgca/free-const-recursive.stderr | 4 +-- .../mgca/projection-const-recursive.rs | 6 +++-- .../mgca/projection-const-recursive.stderr | 4 +-- ...to-resolve-instance-ice-105488.next.stderr | 5 ++++ ...to-resolve-instance-ice-105488.old.stderr} | 2 +- .../failed-to-resolve-instance-ice-105488.rs | 8 ++++-- .../mututally-recursive-overflow.next.stderr | 5 ++++ ...> mututally-recursive-overflow.old.stderr} | 0 .../mututally-recursive-overflow.rs | 5 +++- 11 files changed, 54 insertions(+), 16 deletions(-) create mode 100644 tests/ui/impl-trait/failed-to-resolve-instance-ice-105488.next.stderr rename tests/ui/impl-trait/{failed-to-resolve-instance-ice-105488.stderr => failed-to-resolve-instance-ice-105488.old.stderr} (93%) create mode 100644 tests/ui/type-alias-impl-trait/mututally-recursive-overflow.next.stderr rename tests/ui/type-alias-impl-trait/{mututally-recursive-overflow.stderr => mututally-recursive-overflow.old.stderr} (100%) diff --git a/compiler/rustc_trait_selection/src/traits/query/normalize.rs b/compiler/rustc_trait_selection/src/traits/query/normalize.rs index 489e4f7a93d53..8ba8779a71fec 100644 --- a/compiler/rustc_trait_selection/src/traits/query/normalize.rs +++ b/compiler/rustc_trait_selection/src/traits/query/normalize.rs @@ -21,7 +21,8 @@ use crate::infer::canonical::OriginalQueryValues; use crate::infer::{InferCtxt, InferOk}; use crate::traits::normalize::needs_normalization; use crate::traits::{ - BoundVarReplacer, Normalized, ObligationCause, PlaceholderReplacer, ScrubbedTraitError, + BoundVarReplacer, FulfillmentError, FulfillmentErrorCode, Normalized, ObligationCause, + PlaceholderReplacer, }; #[extension(pub trait QueryNormalizeExt<'tcx>)] @@ -76,7 +77,7 @@ impl<'a, 'tcx> At<'a, 'tcx> { }; if self.infcx.next_trait_solver() { - match crate::solve::deeply_normalize_with_skipped_universes::<_, ScrubbedTraitError<'tcx>>( + match crate::solve::deeply_normalize_with_skipped_universes::<_, FulfillmentError<'tcx>>( self, Unnormalized::new_wip(value), universes, @@ -84,8 +85,24 @@ impl<'a, 'tcx> At<'a, 'tcx> { Ok(value) => { return Ok(Normalized { value, obligations: PredicateObligations::new() }); } - Err(_errors) => { - return Err(NoSolution); + Err(errors) => { + // We're imitating the old solver's behavior of eagerly reporting overflow + // errors here. Otherwise we might silently ignore such errors. See #161542. + if let Some((overflowed_obligation, suggest_higher_limit)) = + errors.into_iter().find_map(|e| match e.code { + FulfillmentErrorCode::Ambiguity { + overflow: Some(suggest_higher_limit), + } => Some((e.root_obligation, suggest_higher_limit)), + _ => None, + }) + { + self.infcx.err_ctxt().report_overflow_obligation( + &overflowed_obligation, + suggest_higher_limit, + ); + } else { + return Err(NoSolution); + } } } } diff --git a/tests/ui/const-generics/mgca/free-const-recursive.rs b/tests/ui/const-generics/mgca/free-const-recursive.rs index 1bbdc36e168b6..25e99645a3cd8 100644 --- a/tests/ui/const-generics/mgca/free-const-recursive.rs +++ b/tests/ui/const-generics/mgca/free-const-recursive.rs @@ -1,6 +1,8 @@ -//! Regression test for //@ check-fail -//@compile-flags: -Znext-solver=globally --emit=obj +//@ compile-flags: -Znext-solver=globally + +// Regression test for + #![feature(min_generic_const_args)] #![expect(incomplete_features)] diff --git a/tests/ui/const-generics/mgca/free-const-recursive.stderr b/tests/ui/const-generics/mgca/free-const-recursive.stderr index aeb2bd4b22ddf..c80dc2117f576 100644 --- a/tests/ui/const-generics/mgca/free-const-recursive.stderr +++ b/tests/ui/const-generics/mgca/free-const-recursive.stderr @@ -1,11 +1,11 @@ error[E0275]: overflow evaluating the requirement `A == _` - --> $DIR/free-const-recursive.rs:7:1 + --> $DIR/free-const-recursive.rs:9:1 | LL | type const A: () = A; | ^^^^^^^^^^^^^^^^ error[E0275]: overflow evaluating the requirement `the constant `A` has type `()`` - --> $DIR/free-const-recursive.rs:7:1 + --> $DIR/free-const-recursive.rs:9:1 | LL | type const A: () = A; | ^^^^^^^^^^^^^^^^ diff --git a/tests/ui/const-generics/mgca/projection-const-recursive.rs b/tests/ui/const-generics/mgca/projection-const-recursive.rs index a2f54fbfca0e3..1d06d912d1c77 100644 --- a/tests/ui/const-generics/mgca/projection-const-recursive.rs +++ b/tests/ui/const-generics/mgca/projection-const-recursive.rs @@ -1,6 +1,8 @@ -//! See also //@ check-fail -//@compile-flags: -Znext-solver=globally --emit=obj +//@ compile-flags: -Znext-solver=globally + +// Regression test for + #![feature(min_generic_const_args)] #![expect(incomplete_features)] diff --git a/tests/ui/const-generics/mgca/projection-const-recursive.stderr b/tests/ui/const-generics/mgca/projection-const-recursive.stderr index a102e82426fca..8ea50ac64f926 100644 --- a/tests/ui/const-generics/mgca/projection-const-recursive.stderr +++ b/tests/ui/const-generics/mgca/projection-const-recursive.stderr @@ -1,11 +1,11 @@ error[E0275]: overflow evaluating the requirement `<() as Trait>::A == _` - --> $DIR/projection-const-recursive.rs:12:5 + --> $DIR/projection-const-recursive.rs:14:5 | LL | type const A: () = <() as Trait>::A; | ^^^^^^^^^^^^^^^^ error[E0275]: overflow evaluating the requirement `the constant `<() as Trait>::A` has type `()`` - --> $DIR/projection-const-recursive.rs:12:5 + --> $DIR/projection-const-recursive.rs:14:5 | LL | type const A: () = <() as Trait>::A; | ^^^^^^^^^^^^^^^^ diff --git a/tests/ui/impl-trait/failed-to-resolve-instance-ice-105488.next.stderr b/tests/ui/impl-trait/failed-to-resolve-instance-ice-105488.next.stderr new file mode 100644 index 0000000000000..90bf6abcc8927 --- /dev/null +++ b/tests/ui/impl-trait/failed-to-resolve-instance-ice-105488.next.stderr @@ -0,0 +1,5 @@ +error[E0275]: overflow evaluating the requirement ` impl MyFnOnce {my_fn_2} as MyFnOnce>::Output == _` + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0275`. diff --git a/tests/ui/impl-trait/failed-to-resolve-instance-ice-105488.stderr b/tests/ui/impl-trait/failed-to-resolve-instance-ice-105488.old.stderr similarity index 93% rename from tests/ui/impl-trait/failed-to-resolve-instance-ice-105488.stderr rename to tests/ui/impl-trait/failed-to-resolve-instance-ice-105488.old.stderr index c2782b79d9021..23ee36358e63b 100644 --- a/tests/ui/impl-trait/failed-to-resolve-instance-ice-105488.stderr +++ b/tests/ui/impl-trait/failed-to-resolve-instance-ice-105488.old.stderr @@ -2,7 +2,7 @@ error[E0275]: overflow evaluating the requirement `fn() -> impl MyFnOnce {my_fn_ | = help: consider increasing the recursion limit by adding a `#![recursion_limit = "256"]` attribute to your crate (`failed_to_resolve_instance_ice_105488`) note: required for `WrapFnOnce impl MyFnOnce {my_fn_1}>` to implement `MyFnOnce` - --> $DIR/failed-to-resolve-instance-ice-105488.rs:14:37 + --> $DIR/failed-to-resolve-instance-ice-105488.rs:18:37 | LL | impl D, D: MyFnOnce> MyFnOnce for WrapFnOnce { | -------- ^^^^^^^^ ^^^^^^^^^^^^^ diff --git a/tests/ui/impl-trait/failed-to-resolve-instance-ice-105488.rs b/tests/ui/impl-trait/failed-to-resolve-instance-ice-105488.rs index 994a507394707..b2e134176a37a 100644 --- a/tests/ui/impl-trait/failed-to-resolve-instance-ice-105488.rs +++ b/tests/ui/impl-trait/failed-to-resolve-instance-ice-105488.rs @@ -1,7 +1,11 @@ +//@ revisions: next old +//@[next] compile-flags: -Znext-solver +//@ build-fail // ICE failed to resolve instance for impl MyFnOnce ... // issue: rust-lang/rust#105488 -//@ build-fail -//~^^^ ERROR overflow evaluating the requirement `fn() -> impl MyFnOnce + +//[old]~^^^^^^ ERROR overflow evaluating the requirement `fn() -> impl MyFnOnce +//[next]~^^^^^^^ ERROR: overflow evaluating the requirement ` impl MyFnOnce {my_fn_2} as MyFnOnce>::Output == _` [E0275] pub trait MyFnOnce { type Output; diff --git a/tests/ui/type-alias-impl-trait/mututally-recursive-overflow.next.stderr b/tests/ui/type-alias-impl-trait/mututally-recursive-overflow.next.stderr new file mode 100644 index 0000000000000..3ae0aa59888fe --- /dev/null +++ b/tests/ui/type-alias-impl-trait/mututally-recursive-overflow.next.stderr @@ -0,0 +1,5 @@ +error[E0275]: overflow evaluating the requirement `<() as A>::Assoc::{opaque#0} == _` + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0275`. diff --git a/tests/ui/type-alias-impl-trait/mututally-recursive-overflow.stderr b/tests/ui/type-alias-impl-trait/mututally-recursive-overflow.old.stderr similarity index 100% rename from tests/ui/type-alias-impl-trait/mututally-recursive-overflow.stderr rename to tests/ui/type-alias-impl-trait/mututally-recursive-overflow.old.stderr diff --git a/tests/ui/type-alias-impl-trait/mututally-recursive-overflow.rs b/tests/ui/type-alias-impl-trait/mututally-recursive-overflow.rs index 4eb16727ba817..1e42021b806d3 100644 --- a/tests/ui/type-alias-impl-trait/mututally-recursive-overflow.rs +++ b/tests/ui/type-alias-impl-trait/mututally-recursive-overflow.rs @@ -1,6 +1,9 @@ +//@ revisions: next old +//@[next] compile-flags: -Znext-solver //@ edition: 2021 //@ build-fail -//~^^ ERROR overflow evaluating the requirement `<() as B>::Assoc == _` +//[old]~^^^^ ERROR overflow evaluating the requirement `<() as B>::Assoc == _` +//[next]~^^^^^ ERROR: overflow evaluating the requirement `<() as A>::Assoc::{opaque#0} == _` #![feature(rustc_attrs)] #![feature(impl_trait_in_assoc_type)] From 43a8f8e16ef9e57649eebf9513a5bf5c6ec2cffa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Le=C3=B3n=20Orell=20Valerian=20Liehr?= Date: Wed, 2 Sep 2026 09:51:46 +0200 Subject: [PATCH 2/4] Method resolution: Turn `TraitPick` and `TraitCandidate` into named structs --- .../rustc_hir_typeck/src/method/confirm.rs | 4 +- compiler/rustc_hir_typeck/src/method/probe.rs | 53 +++++++++++-------- 2 files changed, 32 insertions(+), 25 deletions(-) diff --git a/compiler/rustc_hir_typeck/src/method/confirm.rs b/compiler/rustc_hir_typeck/src/method/confirm.rs index 5345e0f9e11e1..e4f6a971c4ddb 100644 --- a/compiler/rustc_hir_typeck/src/method/confirm.rs +++ b/compiler/rustc_hir_typeck/src/method/confirm.rs @@ -347,7 +347,7 @@ impl<'a, 'tcx> ConfirmContext<'a, 'tcx> { }) } - probe::TraitPick(_) => { + probe::TraitPick { .. } => { let trait_def_id = pick.item.container_id(self.tcx); // Make a trait reference `$0 : Trait<$1...$n>` @@ -756,7 +756,7 @@ impl<'a, 'tcx> ConfirmContext<'a, 'tcx> { pick: &probe::Pick<'_>, segment: &hir::PathSegment<'tcx>, ) { - if pick.kind != probe::PickKind::TraitPick(true) { + if pick.kind != (probe::PickKind::TraitPick { is_ambiguously_imported: true }) { return; } let trait_name = self.tcx.item_name(pick.item.container_id(self.tcx)); diff --git a/compiler/rustc_hir_typeck/src/method/probe.rs b/compiler/rustc_hir_typeck/src/method/probe.rs index 6e6ded6c59ea1..0868f309a8a7d 100644 --- a/compiler/rustc_hir_typeck/src/method/probe.rs +++ b/compiler/rustc_hir_typeck/src/method/probe.rs @@ -118,7 +118,7 @@ pub(crate) struct Candidate<'tcx> { pub(crate) enum CandidateKind<'tcx> { InherentImplCandidate { impl_def_id: DefId, receiver_steps: usize }, ObjectCandidate(ty::PolyTraitRef<'tcx>), - TraitCandidate(ty::PolyTraitRef<'tcx>, bool /* lint_ambiguous */), + TraitCandidate { trait_ref: ty::PolyTraitRef<'tcx>, is_ambiguously_imported: bool }, WhereClauseCandidate(ty::PolyTraitRef<'tcx>), } @@ -239,7 +239,7 @@ pub(crate) struct Pick<'tcx> { /// Only applies for inherent impls. pub receiver_steps: Option, - /// Candidates that were shadowed by supertraits. + /// Candidates that were shadowed by subtraits. pub shadowed_candidates: Vec, } @@ -247,10 +247,9 @@ pub(crate) struct Pick<'tcx> { pub(crate) enum PickKind<'tcx> { InherentImplPick, ObjectPick, - TraitPick( - // Is Ambiguously Imported - bool, - ), + TraitPick { + is_ambiguously_imported: bool, + }, WhereClausePick( // Trait ty::PolyTraitRef<'tcx>, @@ -611,10 +610,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { Candidate { item, kind: match item.container { - AssocContainer::Trait => CandidateKind::TraitCandidate( - ty::Binder::dummy(trait_ref), - false, - ), + AssocContainer::Trait => CandidateKind::TraitCandidate { + trait_ref: ty::Binder::dummy(trait_ref), + is_ambiguously_imported: false, + }, AssocContainer::InherentImpl => { CandidateKind::InherentImplCandidate { impl_def_id: self.tcx.parent(def_id), @@ -1143,7 +1142,7 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> { &mut self, import_ids: &'tcx [LocalDefId], trait_def_id: DefId, - lint_ambiguous: bool, + is_ambiguously_imported: bool, ) { let trait_args = self.fresh_args_for_item(self.span, trait_def_id); let trait_ref = ty::TraitRef::new_from_args(self.tcx, trait_def_id, trait_args); @@ -1165,7 +1164,10 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> { Candidate { item, import_ids, - kind: TraitCandidate(bound_trait_ref, lint_ambiguous), + kind: TraitCandidate { + trait_ref: bound_trait_ref, + is_ambiguously_imported, + }, }, false, ); @@ -1188,7 +1190,10 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> { Candidate { item, import_ids, - kind: TraitCandidate(ty::Binder::dummy(trait_ref), lint_ambiguous), + kind: TraitCandidate { + trait_ref: ty::Binder::dummy(trait_ref), + is_ambiguously_imported, + }, }, false, ); @@ -1958,7 +1963,7 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> { ObjectCandidate(_) | WhereClauseCandidate(_) => { CandidateSource::Trait(candidate.item.container_id(self.tcx)) } - TraitCandidate(trait_ref, _) => self.probe(|_| { + TraitCandidate { trait_ref, is_ambiguously_imported: _ } => self.probe(|_| { let trait_ref = self.instantiate_binder_with_fresh_vars( self.span, BoundRegionConversionTime::FnCall, @@ -1988,7 +1993,7 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> { fn candidate_source_from_pick(&self, pick: &Pick<'tcx>) -> CandidateSource { match pick.kind { InherentImplPick => CandidateSource::Impl(pick.item.container_id(self.tcx)), - ObjectPick | WhereClausePick(_) | TraitPick(_) => { + ObjectPick | WhereClausePick(_) | TraitPick { .. } => { CandidateSource::Trait(pick.item.container_id(self.tcx)) } } @@ -2069,7 +2074,7 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> { impl_bounds, )); } - TraitCandidate(poly_trait_ref, _) => { + TraitCandidate { trait_ref: poly_trait_ref, is_ambiguously_imported: _ } => { // Some trait methods are excluded for arrays before 2021. // (`array.into_iter()` wants a slice iterator for compatibility.) if let Some(method_name) = self.method_name { @@ -2373,8 +2378,8 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> { } // They are all the same, so if any of them is ambiguous, we report the pick as ambiguous. - let lint_ambiguous = probes.iter().any(|(p, _)| match p.kind { - TraitCandidate(_, lint) => lint, + let is_ambiguously_imported = probes.iter().any(|(p, _)| match p.kind { + TraitCandidate { is_ambiguously_imported, .. } => is_ambiguously_imported, _ => false, }); @@ -2382,7 +2387,7 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> { // If so, just use this trait and call it a day. Some(Pick { item: probes[0].0.item, - kind: TraitPick(lint_ambiguous), + kind: TraitPick { is_ambiguously_imported }, import_ids: probes[0].0.import_ids, autoderefs: 0, autoref_or_ptr_adjustment: None, @@ -2457,14 +2462,14 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> { } } - let lint_ambiguous = match child_candidate.kind { - TraitCandidate(_, lint) => lint, + let is_ambiguously_imported = match child_candidate.kind { + TraitCandidate { is_ambiguously_imported, .. } => is_ambiguously_imported, _ => false, }; Some(Pick { item: child_candidate.item, - kind: TraitPick(lint_ambiguous), + kind: TraitPick { is_ambiguously_imported }, import_ids: child_candidate.import_ids, autoderefs: 0, autoref_or_ptr_adjustment: None, @@ -2712,7 +2717,9 @@ impl<'tcx> Candidate<'tcx> { kind: match self.kind { InherentImplCandidate { .. } => InherentImplPick, ObjectCandidate(_) => ObjectPick, - TraitCandidate(_, lint_ambiguous) => TraitPick(lint_ambiguous), + TraitCandidate { is_ambiguously_imported, .. } => { + TraitPick { is_ambiguously_imported } + } WhereClauseCandidate(trait_ref) => { // Only trait derived from where-clauses should // appear here, so they should not contain any From 77c83e443c3a5a59f6aa6b8d70c89d0c17c9c162 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Le=C3=B3n=20Orell=20Valerian=20Liehr?= Date: Wed, 2 Sep 2026 09:49:56 +0200 Subject: [PATCH 3/4] Make diagnostic of lint `ambiguous_glob_imported_traits` follow our stylistic conventions Namely: > Error, Warning, Note, and Help messages start with a lowercase letter and do not end with punctuation. From: --- .../rustc_hir_typeck/src/method/confirm.rs | 4 +-- .../ambiguous-trait-and-struct-in-scope.rs | 2 +- ...ambiguous-trait-and-struct-in-scope.stderr | 4 +-- ...trait-in-scope-and-underscore.first.stderr | 4 +-- ...-trait-in-scope-and-underscore.last.stderr | 4 +-- ...ambiguous-trait-in-scope-and-underscore.rs | 2 +- tests/ui/imports/ambiguous-trait-in-scope.rs | 14 +++++----- .../imports/ambiguous-trait-in-scope.stderr | 28 +++++++++---------- .../ambiguous-glob-imported-subtrait.rs | 2 +- .../ambiguous-glob-imported-subtrait.stderr | 4 +-- 10 files changed, 34 insertions(+), 34 deletions(-) diff --git a/compiler/rustc_hir_typeck/src/method/confirm.rs b/compiler/rustc_hir_typeck/src/method/confirm.rs index e4f6a971c4ddb..02e7991b15743 100644 --- a/compiler/rustc_hir_typeck/src/method/confirm.rs +++ b/compiler/rustc_hir_typeck/src/method/confirm.rs @@ -767,11 +767,11 @@ impl<'a, 'tcx> ConfirmContext<'a, 'tcx> { segment.hir_id, rustc_errors::DiagDecorator(|diag| { diag.primary_message(format!( - "Use of ambiguously glob imported trait `{trait_name}`" + "use of ambiguously glob imported trait `{trait_name}`" )) .span(segment.ident.span) .span_label(import_span, format!("`{trait_name}` imported ambiguously here")) - .help(format!("Import `{trait_name}` explicitly")); + .help(format!("import `{trait_name}` explicitly")); }), ); } diff --git a/tests/ui/imports/ambiguous-trait-and-struct-in-scope.rs b/tests/ui/imports/ambiguous-trait-and-struct-in-scope.rs index ec1ea313302d6..dc69cbaa4af8a 100644 --- a/tests/ui/imports/ambiguous-trait-and-struct-in-scope.rs +++ b/tests/ui/imports/ambiguous-trait-and-struct-in-scope.rs @@ -28,7 +28,7 @@ mod module_3 { use super::*; use crate::module_2::*; fn weird() { - 1_i32.method(); //~ WARNING Use of ambiguously glob imported trait `Foo` [ambiguous_glob_imported_traits] + 1_i32.method(); //~ WARNING use of ambiguously glob imported trait `Foo` [ambiguous_glob_imported_traits] //~| WARNING 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/imports/ambiguous-trait-and-struct-in-scope.stderr b/tests/ui/imports/ambiguous-trait-and-struct-in-scope.stderr index 540d41fb65f22..ac9fc20abe133 100644 --- a/tests/ui/imports/ambiguous-trait-and-struct-in-scope.stderr +++ b/tests/ui/imports/ambiguous-trait-and-struct-in-scope.stderr @@ -1,4 +1,4 @@ -warning: Use of ambiguously glob imported trait `Foo` +warning: use of ambiguously glob imported trait `Foo` --> $DIR/ambiguous-trait-and-struct-in-scope.rs:31:19 | LL | use crate::module_2::*; @@ -7,7 +7,7 @@ LL | fn weird() { LL | 1_i32.method(); | ^^^^^^ | - = help: Import `Foo` explicitly + = help: import `Foo` explicitly = 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 #152822 = note: `#[warn(ambiguous_glob_imported_traits)]` (part of `#[warn(future_incompatible)]`) on by default diff --git a/tests/ui/imports/ambiguous-trait-in-scope-and-underscore.first.stderr b/tests/ui/imports/ambiguous-trait-in-scope-and-underscore.first.stderr index 09f837bb6a219..310ee22526d7a 100644 --- a/tests/ui/imports/ambiguous-trait-in-scope-and-underscore.first.stderr +++ b/tests/ui/imports/ambiguous-trait-in-scope-and-underscore.first.stderr @@ -1,4 +1,4 @@ -warning: Use of ambiguously glob imported trait `Foo` +warning: use of ambiguously glob imported trait `Foo` --> $DIR/ambiguous-trait-in-scope-and-underscore.rs:40:10 | LL | use export::*; @@ -7,7 +7,7 @@ LL | use export::*; LL | 1i32.method(); | ^^^^^^ | - = help: Import `Foo` explicitly + = help: import `Foo` explicitly = 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 #152822 = note: `#[warn(ambiguous_glob_imported_traits)]` (part of `#[warn(future_incompatible)]`) on by default diff --git a/tests/ui/imports/ambiguous-trait-in-scope-and-underscore.last.stderr b/tests/ui/imports/ambiguous-trait-in-scope-and-underscore.last.stderr index 09f837bb6a219..310ee22526d7a 100644 --- a/tests/ui/imports/ambiguous-trait-in-scope-and-underscore.last.stderr +++ b/tests/ui/imports/ambiguous-trait-in-scope-and-underscore.last.stderr @@ -1,4 +1,4 @@ -warning: Use of ambiguously glob imported trait `Foo` +warning: use of ambiguously glob imported trait `Foo` --> $DIR/ambiguous-trait-in-scope-and-underscore.rs:40:10 | LL | use export::*; @@ -7,7 +7,7 @@ LL | use export::*; LL | 1i32.method(); | ^^^^^^ | - = help: Import `Foo` explicitly + = help: import `Foo` explicitly = 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 #152822 = note: `#[warn(ambiguous_glob_imported_traits)]` (part of `#[warn(future_incompatible)]`) on by default diff --git a/tests/ui/imports/ambiguous-trait-in-scope-and-underscore.rs b/tests/ui/imports/ambiguous-trait-in-scope-and-underscore.rs index afecdfc77d52a..d27c600b0ab6f 100644 --- a/tests/ui/imports/ambiguous-trait-in-scope-and-underscore.rs +++ b/tests/ui/imports/ambiguous-trait-in-scope-and-underscore.rs @@ -38,6 +38,6 @@ use export::*; fn main() { 1i32.method(); - //~^ WARNING Use of ambiguously glob imported trait `Foo` [ambiguous_glob_imported_traits] + //~^ WARNING use of ambiguously glob imported trait `Foo` [ambiguous_glob_imported_traits] //~| WARNING 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/imports/ambiguous-trait-in-scope.rs b/tests/ui/imports/ambiguous-trait-in-scope.rs index d122762973969..240d3cea981bb 100644 --- a/tests/ui/imports/ambiguous-trait-in-scope.rs +++ b/tests/ui/imports/ambiguous-trait-in-scope.rs @@ -29,7 +29,7 @@ fn test1() { // Create an ambiguous import for `Trait` in one order use m1::*; use m2::*; - 0u8.method1(); //~ WARNING Use of ambiguously glob imported trait `Trait` [ambiguous_glob_imported_traits] + 0u8.method1(); //~ WARNING use of ambiguously glob imported trait `Trait` [ambiguous_glob_imported_traits] //~| WARNING this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! 0u8.method2(); //~ ERROR: no method named `method2` found for type `u8` in the current scope } @@ -39,21 +39,21 @@ fn test2() { use m2::*; use m1::*; 0u8.method1(); //~ ERROR: no method named `method1` found for type `u8` in the current scope - 0u8.method2(); //~ WARNING Use of ambiguously glob imported trait `Trait` [ambiguous_glob_imported_traits] + 0u8.method2(); //~ WARNING use of ambiguously glob imported trait `Trait` [ambiguous_glob_imported_traits] //~| WARNING this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! } fn test_indirect_reexport() { use m1_reexport::*; use m2_reexport::*; - 0u8.method1(); //~ WARNING Use of ambiguously glob imported trait `Trait` [ambiguous_glob_imported_traits] + 0u8.method1(); //~ WARNING use of ambiguously glob imported trait `Trait` [ambiguous_glob_imported_traits] //~| WARNING this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! 0u8.method2(); //~ ERROR: no method named `method2` found for type `u8` in the current scope } fn test_ambig_reexport() { use ambig_reexport::*; - 0u8.method1(); //~ WARNING Use of ambiguously glob imported trait `Trait` [ambiguous_glob_imported_traits] + 0u8.method1(); //~ WARNING use of ambiguously glob imported trait `Trait` [ambiguous_glob_imported_traits] //~| WARNING this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! 0u8.method2(); //~ ERROR: no method named `method2` found for type `u8` in the current scope } @@ -61,7 +61,7 @@ fn test_ambig_reexport() { fn test_external() { use external::m1::*; use external::m2::*; - 0u8.method1(); //~ WARNING Use of ambiguously glob imported trait `Trait` [ambiguous_glob_imported_traits] + 0u8.method1(); //~ WARNING use of ambiguously glob imported trait `Trait` [ambiguous_glob_imported_traits] //~| WARNING this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! 0u8.method2(); //~ ERROR: no method named `method2` found for type `u8` in the current scope } @@ -69,14 +69,14 @@ fn test_external() { fn test_external_indirect_reexport() { use external::m1_reexport::*; use external::m2_reexport::*; - 0u8.method1(); //~ WARNING Use of ambiguously glob imported trait `Trait` [ambiguous_glob_imported_traits] + 0u8.method1(); //~ WARNING use of ambiguously glob imported trait `Trait` [ambiguous_glob_imported_traits] //~| WARNING this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! 0u8.method2(); //~ ERROR: no method named `method2` found for type `u8` in the current scope } fn test_external_ambig_reexport() { use external::ambig_reexport::*; - 0u8.method1(); //~ WARNING Use of ambiguously glob imported trait `Trait` [ambiguous_glob_imported_traits] + 0u8.method1(); //~ WARNING use of ambiguously glob imported trait `Trait` [ambiguous_glob_imported_traits] //~| WARNING this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! 0u8.method2(); //~ ERROR: no method named `method2` found for type `u8` in the current scope } diff --git a/tests/ui/imports/ambiguous-trait-in-scope.stderr b/tests/ui/imports/ambiguous-trait-in-scope.stderr index 0b37ab0c9d609..ea29cf022ac88 100644 --- a/tests/ui/imports/ambiguous-trait-in-scope.stderr +++ b/tests/ui/imports/ambiguous-trait-in-scope.stderr @@ -1,4 +1,4 @@ -warning: Use of ambiguously glob imported trait `Trait` +warning: use of ambiguously glob imported trait `Trait` --> $DIR/ambiguous-trait-in-scope.rs:32:9 | LL | use m1::*; @@ -7,7 +7,7 @@ LL | use m2::*; LL | 0u8.method1(); | ^^^^^^^ | - = help: Import `Trait` explicitly + = help: import `Trait` explicitly = 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 #152822 = note: `#[warn(ambiguous_glob_imported_traits)]` (part of `#[warn(future_incompatible)]`) on by default @@ -40,7 +40,7 @@ LL + use ambiguous_trait_reexport::m1::Trait; LL + use crate::m1::Trait; | -warning: Use of ambiguously glob imported trait `Trait` +warning: use of ambiguously glob imported trait `Trait` --> $DIR/ambiguous-trait-in-scope.rs:42:9 | LL | use m2::*; @@ -49,11 +49,11 @@ LL | use m2::*; LL | 0u8.method2(); | ^^^^^^^ | - = help: Import `Trait` explicitly + = help: import `Trait` explicitly = 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 #152822 -warning: Use of ambiguously glob imported trait `Trait` +warning: use of ambiguously glob imported trait `Trait` --> $DIR/ambiguous-trait-in-scope.rs:49:9 | LL | use m1_reexport::*; @@ -62,7 +62,7 @@ LL | use m2_reexport::*; LL | 0u8.method1(); | ^^^^^^^ | - = help: Import `Trait` explicitly + = help: import `Trait` explicitly = 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 #152822 @@ -80,7 +80,7 @@ LL + use ambiguous_trait_reexport::m2::Trait; LL + use crate::m2::Trait; | -warning: Use of ambiguously glob imported trait `Trait` +warning: use of ambiguously glob imported trait `Trait` --> $DIR/ambiguous-trait-in-scope.rs:56:9 | LL | use ambig_reexport::*; @@ -88,7 +88,7 @@ LL | use ambig_reexport::*; LL | 0u8.method1(); | ^^^^^^^ | - = help: Import `Trait` explicitly + = help: import `Trait` explicitly = 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 #152822 @@ -106,7 +106,7 @@ LL + use ambiguous_trait_reexport::m2::Trait; LL + use crate::m2::Trait; | -warning: Use of ambiguously glob imported trait `Trait` +warning: use of ambiguously glob imported trait `Trait` --> $DIR/ambiguous-trait-in-scope.rs:64:9 | LL | use external::m1::*; @@ -115,7 +115,7 @@ LL | use external::m2::*; LL | 0u8.method1(); | ^^^^^^^ | - = help: Import `Trait` explicitly + = help: import `Trait` explicitly = 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 #152822 @@ -133,7 +133,7 @@ LL + use ambiguous_trait_reexport::m2::Trait; LL + use crate::m2::Trait; | -warning: Use of ambiguously glob imported trait `Trait` +warning: use of ambiguously glob imported trait `Trait` --> $DIR/ambiguous-trait-in-scope.rs:72:9 | LL | use external::m1_reexport::*; @@ -142,7 +142,7 @@ LL | use external::m2_reexport::*; LL | 0u8.method1(); | ^^^^^^^ | - = help: Import `Trait` explicitly + = help: import `Trait` explicitly = 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 #152822 @@ -160,7 +160,7 @@ LL + use ambiguous_trait_reexport::m2::Trait; LL + use crate::m2::Trait; | -warning: Use of ambiguously glob imported trait `Trait` +warning: use of ambiguously glob imported trait `Trait` --> $DIR/ambiguous-trait-in-scope.rs:79:9 | LL | use external::ambig_reexport::*; @@ -168,7 +168,7 @@ LL | use external::ambig_reexport::*; LL | 0u8.method1(); | ^^^^^^^ | - = help: Import `Trait` explicitly + = help: import `Trait` explicitly = 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 #152822 diff --git a/tests/ui/supertrait-shadowing/ambiguous-glob-imported-subtrait.rs b/tests/ui/supertrait-shadowing/ambiguous-glob-imported-subtrait.rs index 61d1c16c8305b..839768c38a317 100644 --- a/tests/ui/supertrait-shadowing/ambiguous-glob-imported-subtrait.rs +++ b/tests/ui/supertrait-shadowing/ambiguous-glob-imported-subtrait.rs @@ -31,6 +31,6 @@ use second_policy::*; fn main() { assert!(0u8.allow_action()); - //~^ ERROR Use of ambiguously glob imported trait `Role` + //~^ ERROR use of ambiguously glob imported trait `Role` //~| WARN this was previously accepted by the compiler but is being phased out } diff --git a/tests/ui/supertrait-shadowing/ambiguous-glob-imported-subtrait.stderr b/tests/ui/supertrait-shadowing/ambiguous-glob-imported-subtrait.stderr index 71d2c38c37ca6..0c5c2f52c4d24 100644 --- a/tests/ui/supertrait-shadowing/ambiguous-glob-imported-subtrait.stderr +++ b/tests/ui/supertrait-shadowing/ambiguous-glob-imported-subtrait.stderr @@ -1,4 +1,4 @@ -error: Use of ambiguously glob imported trait `Role` +error: use of ambiguously glob imported trait `Role` --> $DIR/ambiguous-glob-imported-subtrait.rs:33:17 | LL | use first_policy::*; @@ -7,7 +7,7 @@ LL | use first_policy::*; LL | assert!(0u8.allow_action()); | ^^^^^^^^^^^^ | - = help: Import `Role` explicitly + = help: import `Role` explicitly = 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 #152822 note: the lint level is defined here From 96536dddaa69977763ce1dca79d8ab504761d27e Mon Sep 17 00:00:00 2001 From: Adwin White Date: Mon, 24 Aug 2026 16:46:03 +0800 Subject: [PATCH 4/4] eagerly report overflow errors --- .../src/solve/fulfill.rs | 99 +++++-------------- .../src/solve/fulfill/derive_errors.rs | 11 --- .../coherence-fulfill-overflow.stderr | 3 + .../dont-drop-obligations-on-overflow-1.rs | 53 ++++++++++ ...dont-drop-obligations-on-overflow-1.stderr | 11 +++ .../dont-drop-obligations-on-overflow-2.rs | 27 +++++ ...dont-drop-obligations-on-overflow-2.stderr | 19 ++++ 7 files changed, 137 insertions(+), 86 deletions(-) create mode 100644 tests/ui/traits/next-solver/overflow/dont-drop-obligations-on-overflow-1.rs create mode 100644 tests/ui/traits/next-solver/overflow/dont-drop-obligations-on-overflow-1.stderr create mode 100644 tests/ui/traits/next-solver/overflow/dont-drop-obligations-on-overflow-2.rs create mode 100644 tests/ui/traits/next-solver/overflow/dont-drop-obligations-on-overflow-2.stderr diff --git a/compiler/rustc_trait_selection/src/solve/fulfill.rs b/compiler/rustc_trait_selection/src/solve/fulfill.rs index 318897c36b010..7d3c0a4a6c1f1 100644 --- a/compiler/rustc_trait_selection/src/solve/fulfill.rs +++ b/compiler/rustc_trait_selection/src/solve/fulfill.rs @@ -17,6 +17,7 @@ use tracing::instrument; use self::derive_errors::*; use super::Certainty; use super::delegate::SolverDelegate; +use crate::error_reporting::InferCtxtErrorExt; use crate::traits::{FulfillmentError, FulfillmentErrorCode, ScrubbedTraitError}; mod derive_errors; @@ -53,12 +54,6 @@ pub struct FulfillmentCtxt<'tcx, E: 'tcx> { #[derive(Default, Debug)] struct ObligationStorage<'tcx> { - /// Obligations which resulted in an overflow in fulfillment itself. - /// - /// We cannot eagerly return these as error so we instead store them here - /// to avoid recomputing them each time `try_evaluate_obligations` is called. - /// This also allows us to return the correct `FulfillmentError` for them. - overflowed: Vec>, pending: PendingObligations<'tcx>, } @@ -72,24 +67,18 @@ impl<'tcx> ObligationStorage<'tcx> { } fn has_pending_obligations(&self) -> bool { - !self.pending.is_empty() || !self.overflowed.is_empty() + !self.pending.is_empty() } fn clone_pending(&self) -> PredicateObligations<'tcx> { - let mut obligations: PredicateObligations<'tcx> = - self.pending.iter().map(|(o, _)| o.clone()).collect(); - obligations.extend(self.overflowed.iter().cloned()); - obligations + self.pending.iter().map(|(o, _)| o.clone()).collect() } fn clone_pending_filtered(&self, f: F) -> PredicateObligations<'tcx> where F: FnMut(&&(PredicateObligation<'tcx>, Option>>)) -> bool, { - let mut obligations: PredicateObligations<'tcx> = - self.pending.iter().filter(f).map(|(o, _)| o.clone()).collect(); - obligations.extend(self.overflowed.iter().cloned()); - obligations + self.pending.iter().filter(f).map(|(o, _)| o.clone()).collect() } fn drain_pending( @@ -101,29 +90,6 @@ impl<'tcx> ObligationStorage<'tcx> { self.pending = pending; unstalled } - - fn on_fulfillment_overflow(&mut self, infcx: &InferCtxt<'tcx>) { - infcx.probe(|_| { - // IMPORTANT: we must not use solve any inference variables in the obligations - // as this is all happening inside of a probe. We use a probe to make sure - // we get all obligations involved in the overflow. We pretty much check: if - // we were to do another step of `try_evaluate_obligations`, which goals would - // change. - self.overflowed.extend( - self.pending - .extract_if(.., |(o, stalled_on)| { - let goal = o.as_goal(); - let result = <&SolverDelegate<'tcx>>::from(infcx).evaluate_root_goal( - goal, - o.cause.span, - stalled_on.take(), - ); - matches!(result, Ok(GoalEvaluation { has_changed: HasChanged::Yes, .. })) - }) - .map(|(o, _)| o), - ); - }) - } } impl<'tcx, E: 'tcx> FulfillmentCtxt<'tcx, E> { @@ -186,7 +152,7 @@ where #[inline] fn collect_remaining_errors(&mut self, infcx: &InferCtxt<'tcx>) -> TraitErrors { - if self.obligations.pending.is_empty() && self.obligations.overflowed.is_empty() { + if self.obligations.pending.is_empty() { // Typically in more than 99.9% of cases this condition is true, therefore we outline // the other case. TraitErrors::NoErrors @@ -202,13 +168,8 @@ where let delegate = <&SolverDelegate<'tcx>>::from(infcx); loop { let mut any_changed = false; - let mut overflowed = false; self.obligations.pending.retain_mut(|(obligation, opt_stalled_on)| { - if overflowed { - return false; - } - // Common case: still stalled; keep the obligation. This path is extremely hot in // some cases; there can be thousands of pending obligations. if let Some(stalled_on) = opt_stalled_on @@ -239,21 +200,26 @@ where // constrained by evaluating the goal. obligation.predicate = goal.predicate; if has_changed == HasChanged::Yes { - // We increment the recursion depth here to track the number of times - // this goal has resulted in inference progress. This doesn't precisely - // model the way that we track recursion depth in the old solver due - // to the fact that we only process root obligations, but it is a good - // approximation and should only result in fulfillment overflow in - // pathological cases. - obligation.recursion_depth += 1; - if !infcx.tcx.recursion_limit().value_within_limit(obligation.recursion_depth) { - // At this point we want to stop evaluating goals. We can't break out of - // `retain_mut`, so instead we set this flag which causes all other - // elements to be skipped. - overflowed = true; - return false; + // We limit the total count of inference progress to avoid hang so we don't + // try to recover from this. + // It's more complicated to collect all overflows thus we stopped doing that. + // Eager aborting is also what the old solver does. + // + // Note: it's incredibly rare to actually encounter fulfillment overflow + // as a single obligation would have to result in different inference progress + // a `recursion_depth` number of times. This mostly happens in bugs or with + // `Subtype` obligations because we no longer use the `sub_unification_table` + // in generalization. + infcx.err_ctxt().report_overflow_obligation(obligation, true); } else { + // We increment the recursion depth here to track the number of times + // this goal has resulted in inference progress. This doesn't precisely + // model the way that we track recursion depth in the old solver due + // to the fact that we only process root obligations, but it is a good + // approximation and should only result in fulfillment overflow in + // pathological cases. + obligation.recursion_depth += 1; any_changed = true; } } @@ -288,11 +254,6 @@ where } } }); - if overflowed { - self.obligations.on_fulfillment_overflow(infcx); - // Only return true errors that we have accumulated while processing. - return errors; - } if !any_changed { break; @@ -409,12 +370,6 @@ where .filter_map(|(obligation, _)| { try_ambiguity_error_for_stalled(infcx, obligation).map(NextSolverError::Ambiguity) }) - .chain( - cx.obligations - .overflowed - .drain(..) - .map(|obligation| NextSolverError::Overflow(obligation)), - ) .map(|e| E::from_solver_error(infcx, e)) .collect() } @@ -432,7 +387,6 @@ pub struct NextSolverAmbiguityError<'tcx> { pub enum NextSolverError<'tcx> { TrueError(PredicateObligation<'tcx>), Ambiguity(NextSolverAmbiguityError<'tcx>), - Overflow(PredicateObligation<'tcx>), } impl<'tcx> FromSolverError<'tcx, NextSolverError<'tcx>> for FulfillmentError<'tcx> { @@ -444,9 +398,6 @@ impl<'tcx> FromSolverError<'tcx, NextSolverError<'tcx>> for FulfillmentError<'tc NextSolverError::Ambiguity(ambiguity) => { fulfillment_error_for_stalled(infcx, ambiguity) } - NextSolverError::Overflow(obligation) => { - fulfillment_error_for_overflow(infcx, obligation) - } } } } @@ -455,9 +406,7 @@ impl<'tcx> FromSolverError<'tcx, NextSolverError<'tcx>> for ScrubbedTraitError<' fn from_solver_error(_infcx: &InferCtxt<'tcx>, error: NextSolverError<'tcx>) -> Self { match error { NextSolverError::TrueError(_) => ScrubbedTraitError::TrueError, - NextSolverError::Ambiguity(_) | NextSolverError::Overflow(_) => { - ScrubbedTraitError::Ambiguity - } + NextSolverError::Ambiguity(_) => ScrubbedTraitError::Ambiguity, } } } diff --git a/compiler/rustc_trait_selection/src/solve/fulfill/derive_errors.rs b/compiler/rustc_trait_selection/src/solve/fulfill/derive_errors.rs index 1c7d5b742e1ac..c44809e217791 100644 --- a/compiler/rustc_trait_selection/src/solve/fulfill/derive_errors.rs +++ b/compiler/rustc_trait_selection/src/solve/fulfill/derive_errors.rs @@ -161,17 +161,6 @@ pub(super) fn try_ambiguity_error_for_stalled<'tcx>( Some(NextSolverAmbiguityError { root_obligation, code, refine_obligation }) } -pub(super) fn fulfillment_error_for_overflow<'tcx>( - infcx: &InferCtxt<'tcx>, - root_obligation: PredicateObligation<'tcx>, -) -> FulfillmentError<'tcx> { - FulfillmentError { - obligation: find_best_leaf_obligation(infcx, &root_obligation, true), - code: FulfillmentErrorCode::Ambiguity { overflow: Some(true) }, - root_obligation, - } -} - #[instrument(level = "debug", skip(infcx), ret)] fn find_best_leaf_obligation<'tcx>( infcx: &InferCtxt<'tcx>, diff --git a/tests/ui/traits/next-solver/coherence/coherence-fulfill-overflow.stderr b/tests/ui/traits/next-solver/coherence/coherence-fulfill-overflow.stderr index 1827533a84d90..a93fbc2404dad 100644 --- a/tests/ui/traits/next-solver/coherence/coherence-fulfill-overflow.stderr +++ b/tests/ui/traits/next-solver/coherence/coherence-fulfill-overflow.stderr @@ -5,6 +5,9 @@ LL | impl Trait for W {} | ---------------------------- first implementation here LL | impl Trait for T {} | ^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `W>>>>>>>>>>>>>>>>>>>>>>` + | + = note: overflow evaluating the requirement `W>>>>>>>>>>>>>>>>>>>>>>: TwoW` + = help: consider increasing the recursion limit by adding a `#![recursion_limit = "20"]` attribute to your crate (`coherence_fulfill_overflow`) error: aborting due to 1 previous error diff --git a/tests/ui/traits/next-solver/overflow/dont-drop-obligations-on-overflow-1.rs b/tests/ui/traits/next-solver/overflow/dont-drop-obligations-on-overflow-1.rs new file mode 100644 index 0000000000000..e8bf7851f4f2e --- /dev/null +++ b/tests/ui/traits/next-solver/overflow/dont-drop-obligations-on-overflow-1.rs @@ -0,0 +1,53 @@ +//@ compile-flags: -Znext-solver + +// Regression test for trait-system-refactor-initiative#294 +// We used to drop all subsequent obligations when one obligation overflows +// in fulfillment. It means we don't really prove all obligations even if +// fulfillment returns no error. +// +// We now eagerly abort on the first overflowed obligation. + +#![feature(impl_trait_in_assoc_type)] +#![forbid(unsafe_code)] + +trait Amb<'z> {} +trait Sub<'c, 'd>: Amb<'c> + Amb<'d> {} +impl<'z> Amb<'z> for i32 {} +impl<'c, 'd> Sub<'c, 'd> for i32 {} + +trait Call<'a> { + type Output; + fn call() -> Self::Output; +} + +trait Leak { + fn leak(self) -> &'static u8; +} +impl<'z, G: Call<'static, Output = R>, R: Amb<'z>> Leak for &'static u8 { + fn leak(self) -> &'static u8 { + self + } +} + +#[expect(dead_code)] +struct Foo<'c, 'd>(&'c (), &'d ()); + +impl<'a, 'c, 'd> Call<'a> for Foo<'c, 'd> +where + i32: Sub<'c, 'd>, +{ + type Output = impl Sized + use<>; + fn call() -> Self::Output { + let r = { + let local = 42_u8; + <&u8 as Leak>>::leak(&local) + //~^ ERROR: overflow evaluating the requirement `&u8: Leak>` + }; + println!("{r}"); // use-after-free + 1_i32 + } +} + +fn main() { + Foo::call(); +} diff --git a/tests/ui/traits/next-solver/overflow/dont-drop-obligations-on-overflow-1.stderr b/tests/ui/traits/next-solver/overflow/dont-drop-obligations-on-overflow-1.stderr new file mode 100644 index 0000000000000..b7f1881605f86 --- /dev/null +++ b/tests/ui/traits/next-solver/overflow/dont-drop-obligations-on-overflow-1.stderr @@ -0,0 +1,11 @@ +error[E0275]: overflow evaluating the requirement `&u8: Leak>` + --> $DIR/dont-drop-obligations-on-overflow-1.rs:43:13 + | +LL | <&u8 as Leak>>::leak(&local) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: consider increasing the recursion limit by adding a `#![recursion_limit = "256"]` attribute to your crate (`dont_drop_obligations_on_overflow_1`) + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0275`. diff --git a/tests/ui/traits/next-solver/overflow/dont-drop-obligations-on-overflow-2.rs b/tests/ui/traits/next-solver/overflow/dont-drop-obligations-on-overflow-2.rs new file mode 100644 index 0000000000000..63be17cc9a7e3 --- /dev/null +++ b/tests/ui/traits/next-solver/overflow/dont-drop-obligations-on-overflow-2.rs @@ -0,0 +1,27 @@ +//@ compile-flags: -Znext-solver + +// Regression test for trait-system-refactor-initiative#242 +// We used to drop all subsequent obligations when one obligation overflows +// in fulfillment. It means we don't really prove all obligations even if +// fulfillment returns no error. +// +// We now eagerly abort on the first overflowed obligation. +// +// FIXME: this probably should compile and we shall fix duplicate +// uses of opaques. + +#![feature(type_alias_impl_trait)] +type Tait<'a> = impl Sized; + +fn prove() +where + for<'a> Tait<'a>: Sized, +{} + +#[define_opaque(Tait)] +fn foo<'a>() -> &'a Tait<'a> { + prove(); + //~^ ERROR: overflow evaluating the requirement `for<'a> Tait<'a>: Sized` + &() +} +fn main() {} diff --git a/tests/ui/traits/next-solver/overflow/dont-drop-obligations-on-overflow-2.stderr b/tests/ui/traits/next-solver/overflow/dont-drop-obligations-on-overflow-2.stderr new file mode 100644 index 0000000000000..c8d3b877657f3 --- /dev/null +++ b/tests/ui/traits/next-solver/overflow/dont-drop-obligations-on-overflow-2.stderr @@ -0,0 +1,19 @@ +error[E0275]: overflow evaluating the requirement `for<'a> Tait<'a>: Sized` + --> $DIR/dont-drop-obligations-on-overflow-2.rs:23:5 + | +LL | prove(); + | ^^^^^^^ + | + = help: consider increasing the recursion limit by adding a `#![recursion_limit = "256"]` attribute to your crate (`dont_drop_obligations_on_overflow_2`) +note: required by a bound in `prove` + --> $DIR/dont-drop-obligations-on-overflow-2.rs:18:23 + | +LL | fn prove() + | ----- required by a bound in this function +LL | where +LL | for<'a> Tait<'a>: Sized, + | ^^^^^ required by this bound in `prove` + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0275`.