From eea7880a3f8aed10414e937dda39eaec41507605 Mon Sep 17 00:00:00 2001 From: Shoyu Vanilla Date: Thu, 15 Oct 2026 15:12:15 +0000 Subject: [PATCH] `-Znext-solver` filter out some uninteresting opaques while canonicalization --- .../src/canonical/canonicalizer.rs | 273 ++++++++++++++++-- .../src/canonical/mod.rs | 30 +- .../rustc_next_trait_solver/src/normalize.rs | 1 + .../src/solve/eval_ctxt/mod.rs | 28 +- ...se-placeholder-assumptions-issue-159889.rs | 2 +- ...laceholder-assumptions-issue-159889.stderr | 8 +- .../delayed-obligations-emit.next.stderr | 16 - .../ui/coroutine/delayed-obligations-emit.rs | 3 +- .../opaques/too-many-opaques-hangs.rs | 25 ++ .../opaques/too-many-opaques-hangs.stderr | 24 ++ .../dont-drop-obligations-on-overflow-2.rs | 2 +- ...dont-drop-obligations-on-overflow-2.stderr | 15 +- 12 files changed, 341 insertions(+), 86 deletions(-) delete mode 100644 tests/ui/coroutine/delayed-obligations-emit.next.stderr create mode 100644 tests/ui/traits/next-solver/opaques/too-many-opaques-hangs.rs create mode 100644 tests/ui/traits/next-solver/opaques/too-many-opaques-hangs.stderr diff --git a/compiler/rustc_next_trait_solver/src/canonical/canonicalizer.rs b/compiler/rustc_next_trait_solver/src/canonical/canonicalizer.rs index 3899397e6d8c3..89e1bcb2cdc01 100644 --- a/compiler/rustc_next_trait_solver/src/canonical/canonicalizer.rs +++ b/compiler/rustc_next_trait_solver/src/canonical/canonicalizer.rs @@ -1,14 +1,18 @@ use std::collections::hash_map::Entry; use std::mem; +use std::ops::ControlFlow; use rustc_type_ir::inherent::*; -use rustc_type_ir::solve::{Goal, QueryInput}; +use rustc_type_ir::solve::inspect::State; +use rustc_type_ir::solve::{Certainty, ExternalConstraintsData, Goal, QueryInput, Response}; use rustc_type_ir::{ self as ty, Canonical, CanonicalParamEnvCacheEntry, CanonicalVarKind, CanonicalizerState, Const, Flags, InferCtxtLike, Interner, PlaceholderConst, PlaceholderType, PredicateProxy, - Region, TypeFlags, TypeFoldable, TypeFolder, TypeSuperFoldable, TypeVisitableExt, + Region, TypeFlags, TypeFoldable, TypeFolder, TypeSuperFoldable, TypeSuperVisitable, + TypeVisitable, TypeVisitableExt, TypeVisitor, }; use thin_vec::ThinVec; +use tracing::trace; use crate::delegate::SolverDelegate; @@ -81,18 +85,53 @@ impl<'a, D: SolverDelegate, I: Interner> Canonicalizer<'a, D, I> { Canonicalizer { delegate, canonicalize_mode, state: delegate.obtain_canonicalizer_state() } } - pub(super) fn canonicalize_response>( + pub(super) fn canonicalize_inspect_state>( delegate: &'a D, max_input_universe: ty::UniverseIndex, - value: T, - ) -> ty::Canonical { + value: State, + ) -> ty::Canonical> { let mut canonicalizer = Canonicalizer::new(delegate, CanonicalizeMode::Response { max_input_universe }); - let value = if value.has_type_flags(NEEDS_CANONICAL) { - value.fold_with(&mut canonicalizer) - } else { - value + let value = canonicalizer.canonicalize_value(value); + debug_assert!(!value.has_infer(), "unexpected infer in {value:?}"); + debug_assert!(!value.has_placeholders(), "unexpected placeholders in {value:?}"); + let (max_universe, _variables, var_kinds) = canonicalizer.finalize(); + + Canonical { max_universe, var_kinds, value } + } + + pub(super) fn canonicalize_query_response( + delegate: &'a D, + max_input_universe: ty::UniverseIndex, + var_values: I::GenericArgs, + certainty: Certainty, + external_constraints: ExternalConstraintsData, + ) -> ty::Canonical> { + let mut canonicalizer = + Canonicalizer::new(delegate, CanonicalizeMode::Response { max_input_universe }); + + let var_values = canonicalizer.canonicalize_value(var_values); + + let ExternalConstraintsData { + region_constraints, + opaque_types, + normalization_nested_goals, + } = external_constraints; + let region_constraints = canonicalizer.canonicalize_value(region_constraints); + let normalization_nested_goals = + canonicalizer.canonicalize_value(normalization_nested_goals); + let opaque_types = canonicalizer.filter_and_canonicalize_opaque_types(opaque_types); + + let value = Response { + certainty, + var_values, + external_constraints: delegate.cx().mk_external_constraints(ExternalConstraintsData { + region_constraints, + opaque_types, + normalization_nested_goals, + }), }; + debug_assert!(!value.has_infer(), "unexpected infer in {value:?}"); debug_assert!(!value.has_placeholders(), "unexpected placeholders in {value:?}"); let (max_universe, _variables, var_kinds) = canonicalizer.finalize(); @@ -203,24 +242,20 @@ impl<'a, D: SolverDelegate, I: Interner> Canonicalizer<'a, D, I> { /// variable in the future by changing the way we detect global where-bounds. pub(super) fn canonicalize_input>( delegate: &'a D, - input: QueryInput, + Goal { param_env, predicate }: Goal, + predefined_opaques_in_body: Vec<(ty::OpaqueTypeKey, I::Ty)>, ) -> (ThinVec, ty::Canonical>) { // First canonicalize the `param_env` while keeping `'static`. This produces a // canonicalizer that can canonicalize the rest of the input without keeping `'static`. - let (param_env, mut rest_canonicalizer) = - Self::canonicalize_param_env(delegate, input.goal.param_env); + let (param_env, mut rest_canonicalizer) = Self::canonicalize_param_env(delegate, param_env); - let predicate = input.goal.predicate; let predicate = predicate.fold_with(&mut rest_canonicalizer); let goal = Goal { param_env, predicate }; - let predefined_opaques_in_body = input.predefined_opaques_in_body; let predefined_opaques_in_body = - if predefined_opaques_in_body.has_type_flags(NEEDS_CANONICAL) { - predefined_opaques_in_body.fold_with(&mut rest_canonicalizer) - } else { - predefined_opaques_in_body - }; + rest_canonicalizer.filter_and_canonicalize_opaque_types(predefined_opaques_in_body); + let predefined_opaques_in_body = + delegate.cx().mk_predefined_opaques_in_body(&predefined_opaques_in_body); let value = QueryInput { goal, predefined_opaques_in_body }; @@ -230,6 +265,10 @@ impl<'a, D: SolverDelegate, I: Interner> Canonicalizer<'a, D, I> { (variables, Canonical { max_universe, var_kinds, value }) } + fn canonicalize_value>(&mut self, value: T) -> T { + if value.has_type_flags(NEEDS_CANONICAL) { value.fold_with(self) } else { value } + } + fn get_or_insert_bound_var( &mut self, arg: impl Into, @@ -412,6 +451,202 @@ impl<'a, D: SolverDelegate, I: Interner> Canonicalizer<'a, D, I> { Ty::new_canonical_bound(self.cx(), var) } + + /// Filter out not-so-useful opaque types, i.e. whose hidden type is not + /// mentioned in `variables` so far and has any var within opaque type key + /// that is not mentioned in the same manner. This helps the perf by avoiding + /// having many inputs/outputs differing only on some not interesting opaques + /// and even saves us from overflowing due to having too many opaques. + fn filter_and_canonicalize_opaque_types( + &mut self, + mut opaque_types: Vec<(ty::OpaqueTypeKey, I::Ty)>, + ) -> Vec<(ty::OpaqueTypeKey, I::Ty)> { + struct HasUnmentionedVarVisitor<'a, D: SolverDelegate, I: Interner> { + canonicalizer: &'a Canonicalizer<'a, D, I>, + } + + impl<'a, D: SolverDelegate, I: Interner> HasUnmentionedVarVisitor<'a, D, I> { + fn arg_is_mentioned(&self, arg: impl Into) -> bool { + let arg = arg.into(); + if self.canonicalizer.state.variable_lookup_table.is_empty() { + self.canonicalizer.state.variables.iter().any(|a| *a == arg) + } else { + self.canonicalizer.state.variable_lookup_table.contains_key(&arg) + } + } + } + + // This should be synced with `Canonicalizer`'s `TypeFolder` implementation. + impl<'a, D: SolverDelegate, I: Interner> TypeVisitor + for HasUnmentionedVarVisitor<'a, D, I> + { + type Result = ControlFlow<()>; + + fn visit_ty(&mut self, t: I::Ty) -> Self::Result { + if !t.flags().intersects(NEEDS_CANONICAL) { + return ControlFlow::Continue(()); + } + + match t.kind() { + ty::Infer(ty::TyVar(ty_vid)) => { + if self.canonicalizer.state.sub_root_lookup_table.contains_key( + &self.canonicalizer.delegate.sub_unification_table_root_var(ty_vid), + ) { + ControlFlow::Continue(()) + } else { + ControlFlow::Break(()) + } + } + ty::Infer(_) | ty::Placeholder(_) | ty::Param(_) => { + if self.arg_is_mentioned(t) { + ControlFlow::Continue(()) + } else { + ControlFlow::Break(()) + } + } + + ty::Bool + | ty::Char + | ty::Int(_) + | ty::Uint(_) + | ty::Float(_) + | ty::Adt(_, _) + | ty::Foreign(_) + | ty::Str + | ty::Array(_, _) + | ty::Pat(_, _) + | ty::Slice(_) + | ty::RawPtr(_, _) + | ty::Ref(_, _, _) + | ty::FnDef(_, _) + | ty::FnPtr(_, _) + | ty::UnsafeBinder(_) + | ty::Dynamic(_, _) + | ty::Closure(_, _) + | ty::CoroutineClosure(_, _) + | ty::Coroutine(_, _) + | ty::CoroutineWitness(_, _) + | ty::Never + | ty::Tuple(_) + | ty::Alias(_, _) + | ty::Bound(_, _) + | ty::Error(_) => t.super_visit_with(self), + } + } + + fn visit_region(&mut self, r: Region) -> Self::Result { + match r.kind() { + ty::ReBound(_, _) => ControlFlow::Continue(()), + + ty::ReStatic => match self.canonicalizer.canonicalize_mode { + CanonicalizeMode::Input(CanonicalizeInputKind::Predicate) => { + if self.arg_is_mentioned(r) { + ControlFlow::Continue(()) + } else { + ControlFlow::Break(()) + } + } + CanonicalizeMode::Input(CanonicalizeInputKind::ParamEnv) + | CanonicalizeMode::Response { .. } => ControlFlow::Continue(()), + }, + + ty::ReErased | ty::ReError(_) => match self.canonicalizer.canonicalize_mode { + CanonicalizeMode::Input(_) => { + if self.arg_is_mentioned(r) { + ControlFlow::Continue(()) + } else { + ControlFlow::Break(()) + } + } + CanonicalizeMode::Response { .. } => ControlFlow::Continue(()), + }, + + ty::ReEarlyParam(_) + | ty::ReLateParam(_) + | ty::ReVar(_) + | ty::RePlaceholder(_) => { + if self.arg_is_mentioned(r) { + ControlFlow::Continue(()) + } else { + ControlFlow::Break(()) + } + } + } + } + + fn visit_const(&mut self, c: Const) -> Self::Result { + if !c.flags().intersects(NEEDS_CANONICAL) { + return ControlFlow::Continue(()); + } + + match c.kind() { + ty::ConstKind::Param(_) + | ty::ConstKind::Infer(_) + | ty::ConstKind::Placeholder(_) => { + if self.arg_is_mentioned(c) { + ControlFlow::Continue(()) + } else { + ControlFlow::Break(()) + } + } + + ty::ConstKind::Bound(_, _) + | ty::ConstKind::Alias(_, _) + | ty::ConstKind::Value(_) + | ty::ConstKind::Error(_) + | ty::ConstKind::Expr(_) => c.super_visit_with(self), + } + } + } + + let mut res = vec![]; + + // This should be through fixed-point iterations as opaque types can + // mention each other. For example, if we have + // [ + // (OpaqueTypeKey#0 { args: [] }, ?x), + // (OpaqueTypeKey#1 { args: [?x] }, ?mentioned_var), + // ], + // just iterating through them once in order will filter out the first item + // even though it is relevant with the second item, which is relevant with + // the mentioned var. + while !opaque_types.is_empty() { + let len = res.len(); + opaque_types.retain(|&(key, hidden_ty)| { + let hidden_ty_is_mentioned = if let ty::Infer(ty::TyVar(vid)) = hidden_ty.kind() { + self.state + .sub_root_lookup_table + .contains_key(&self.delegate.sub_unification_table_root_var(vid)) + } else { + false + }; + + if !hidden_ty_is_mentioned + && key + .visit_with(&mut HasUnmentionedVarVisitor { canonicalizer: self }) + .is_break() + { + true + } else { + res.push(self.canonicalize_value((key, hidden_ty))); + false + } + }); + if res.len() == len { + break; + } + } + + if !opaque_types.is_empty() { + trace!( + ?self.state.variables, + ?self.state.sub_root_lookup_table, + "filtering out excessive opaques: {opaque_types:?}", + ); + } + + res + } } impl, I: Interner> TypeFolder for Canonicalizer<'_, D, I> { diff --git a/compiler/rustc_next_trait_solver/src/canonical/mod.rs b/compiler/rustc_next_trait_solver/src/canonical/mod.rs index 45587d717b418..6f180368bc664 100644 --- a/compiler/rustc_next_trait_solver/src/canonical/mod.rs +++ b/compiler/rustc_next_trait_solver/src/canonical/mod.rs @@ -27,7 +27,7 @@ use tracing::instrument; use crate::delegate::SolverDelegate; use crate::solve::{ CanonicalResponse, Certainty, ExternalConstraintsData, ExternalRegionConstraints, Goal, - NestedNormalizationGoals, QueryInput, Response, VisibleForLeakCheck, inspect, + NestedNormalizationGoals, Response, VisibleForLeakCheck, inspect, }; pub mod canonicalizer; @@ -62,13 +62,8 @@ where D: SolverDelegate, I: Interner, { - let (orig_values, canonical) = Canonicalizer::canonicalize_input( - delegate, - QueryInput { - goal, - predefined_opaques_in_body: delegate.cx().mk_predefined_opaques_in_body(opaque_types), - }, - ); + let (orig_values, canonical) = + Canonicalizer::canonicalize_input(delegate, goal, opaque_types.to_vec()); let query_input = delegate.cx().mk_canonical_input(ty::CanonicalQueryInput { canonical, @@ -77,17 +72,24 @@ where (orig_values, query_input) } -pub(super) fn canonicalize_response( +pub(super) fn canonicalize_response( delegate: &D, max_input_universe: ty::UniverseIndex, - value: T, -) -> ty::Canonical + var_values: I::GenericArgs, + certainty: Certainty, + external_constraints: ExternalConstraintsData, +) -> ty::Canonical> where D: SolverDelegate, I: Interner, - T: TypeFoldable, { - Canonicalizer::canonicalize_response(delegate, max_input_universe, value) + Canonicalizer::canonicalize_query_response( + delegate, + max_input_universe, + var_values, + certainty, + external_constraints, + ) } /// After calling a canonical query, we apply the constraints returned @@ -571,7 +573,7 @@ where let var_values = delegate.cx().mk_args(var_values); let state = inspect::State { var_values, data }; let state = delegate.deeply_resolve_via_unification_table(state); - Canonicalizer::canonicalize_response(delegate, max_input_universe, state) + Canonicalizer::canonicalize_inspect_state(delegate, max_input_universe, state) } // FIXME: needs to be pub to be accessed by downstream diff --git a/compiler/rustc_next_trait_solver/src/normalize.rs b/compiler/rustc_next_trait_solver/src/normalize.rs index c7d8d2919089b..47eefe0fd6d91 100644 --- a/compiler/rustc_next_trait_solver/src/normalize.rs +++ b/compiler/rustc_next_trait_solver/src/normalize.rs @@ -120,6 +120,7 @@ where let Some(result) = self.normalize_alias_term(alias_ty.into(), HasEscapingBoundVars::Yes)? else { + tracing::debug!("NOSOL: {ty:?}"); return Ok(ty); }; 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 3b372876f574b..d751e3a66ecb0 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 @@ -44,7 +44,7 @@ use crate::solve::ty::may_use_unstable_feature; use crate::solve::{ CanonicalResponse, Certainty, ExternalConstraintsData, FIXPOINT_STEP_LIMIT, Goal, GoalEvaluation, GoalSource, GoalStalledOn, GoalStalledOnOpaques, HasChanged, MaybeCause, - NestedNormalizationGoals, NoSolution, QueryInput, QueryResult, Response, SucceededInErased, + NestedNormalizationGoals, NoSolution, QueryInput, QueryResult, SucceededInErased, VisibleForLeakCheck, inspect, }; @@ -770,7 +770,7 @@ where ) .entered(); - let (result, orig_values, canonical_goal, succeeded_in_erased) = 'retry_canonicalize: { + let (result, orig_values, succeeded_in_erased, num_opaques_in_storage) = 'retry_canonicalize: { let skip_erased_attempt = match typing_mode { TypingMode::Reflection | TypingMode::Coherence => true, TypingMode::Typeck { .. } @@ -831,8 +831,8 @@ where break 'retry_canonicalize ( canonical_result, orig_values, - canonical_goal, SucceededInErased::Yes { accessed_opaques }, + 0, ); } RerunDecision::EagerlyPropagateToParent => { @@ -840,10 +840,10 @@ where break 'retry_canonicalize ( canonical_result, orig_values, - canonical_goal, // If we're propagating up, we should never retry the goal. // That means `No` is fine to return, it doesn't really matter. SucceededInErased::No, + 0, ); } } @@ -859,7 +859,7 @@ where "we run without TypingMode::ErasedNotCoherence, so opaques are available, and we don't retry if the outer typing mode is ErasedNotCoherence: {accessed_opaques:?} after {goal:?}" ); - (canonical_result, orig_values, canonical_goal, SucceededInErased::No) + (canonical_result, orig_values, SucceededInErased::No, opaque_types.len()) }; debug!(?result); @@ -905,7 +905,7 @@ where // to recompute this goal. HasChanged::Yes => None, HasChanged::No => Some(self.build_stalled_on( - canonical_goal, + num_opaques_in_storage, maybe_info, orig_values, succeeded_in_erased, @@ -921,7 +921,7 @@ where fn build_stalled_on( &self, - canonical_goal: I::CanonicalInput, + num_opaques_in_storage: usize, maybe_info: MaybeInfo, stalled_vars: ThinVec, previously_succeeded_in_erased: SucceededInErased, @@ -958,11 +958,7 @@ where sub_roots, stalled_maybe_info: maybe_info, opaques: GoalStalledOnOpaques::Yes { - num_opaques_in_storage: canonical_goal - .canonical - .value - .predefined_opaques_in_body - .len(), + num_opaques_in_storage, previously_succeeded_in_erased, }, } @@ -1714,11 +1710,9 @@ where let canonical = canonicalize_response( self.delegate, self.max_input_universe, - Response { - var_values, - certainty, - external_constraints: self.cx().mk_external_constraints(external_constraints), - }, + var_values, + certainty, + external_constraints, ); Ok(canonical) diff --git a/tests/ui/assumptions_on_binders/canonical-response-placeholder-assumptions-issue-159889.rs b/tests/ui/assumptions_on_binders/canonical-response-placeholder-assumptions-issue-159889.rs index 29c4d8a6a02a3..31ddfca39ea00 100644 --- a/tests/ui/assumptions_on_binders/canonical-response-placeholder-assumptions-issue-159889.rs +++ b/tests/ui/assumptions_on_binders/canonical-response-placeholder-assumptions-issue-159889.rs @@ -19,6 +19,6 @@ impl Trait for () { #[define_opaque(Foo)] fn foo() -> Foo {} -//~^ ERROR item does not constrain `Foo::{opaque#0}` +//~^ ERROR item does not constrain `FooAssoc::{opaque#0}` fn main() {} diff --git a/tests/ui/assumptions_on_binders/canonical-response-placeholder-assumptions-issue-159889.stderr b/tests/ui/assumptions_on_binders/canonical-response-placeholder-assumptions-issue-159889.stderr index 87b225e58c06b..772209ec31bcd 100644 --- a/tests/ui/assumptions_on_binders/canonical-response-placeholder-assumptions-issue-159889.stderr +++ b/tests/ui/assumptions_on_binders/canonical-response-placeholder-assumptions-issue-159889.stderr @@ -1,4 +1,4 @@ -error: item does not constrain `Foo::{opaque#0}` +error: item does not constrain `FooAssoc::{opaque#0}` --> $DIR/canonical-response-placeholder-assumptions-issue-159889.rs:21:4 | LL | fn foo() -> Foo {} @@ -6,10 +6,10 @@ LL | fn foo() -> Foo {} | = note: consider removing `#[define_opaque]` or adding an empty `#[define_opaque()]` note: this opaque type is supposed to be constrained - --> $DIR/canonical-response-placeholder-assumptions-issue-159889.rs:13:12 + --> $DIR/canonical-response-placeholder-assumptions-issue-159889.rs:14:21 | -LL | type Foo = impl for<'a> Trait = FooAssoc<'a>>; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | type FooAssoc<'a> = impl ?Sized; + | ^^^^^^^^^^^ error: aborting due to 1 previous error diff --git a/tests/ui/coroutine/delayed-obligations-emit.next.stderr b/tests/ui/coroutine/delayed-obligations-emit.next.stderr deleted file mode 100644 index af7dfc75963c2..0000000000000 --- a/tests/ui/coroutine/delayed-obligations-emit.next.stderr +++ /dev/null @@ -1,16 +0,0 @@ -error[E0275]: overflow evaluating the requirement `{async block@$DIR/delayed-obligations-emit.rs:17:11: 17:16}: Send` - --> $DIR/delayed-obligations-emit.rs:17:5 - | -LL | spawn(async { build_dependencies().await }); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = help: consider increasing the recursion limit by adding a `#![recursion_limit = "256"]` attribute to your crate (`delayed_obligations_emit`) -note: required by a bound in `spawn` - --> $DIR/delayed-obligations-emit.rs:31:13 - | -LL | fn spawn(_: F) {} - | ^^^^ required by this bound in `spawn` - -error: aborting due to 1 previous error - -For more information about this error, try `rustc --explain E0275`. diff --git a/tests/ui/coroutine/delayed-obligations-emit.rs b/tests/ui/coroutine/delayed-obligations-emit.rs index 6334f29fcb22c..8eaa29752f28a 100644 --- a/tests/ui/coroutine/delayed-obligations-emit.rs +++ b/tests/ui/coroutine/delayed-obligations-emit.rs @@ -2,7 +2,7 @@ //@ ignore-compare-mode-next-solver (explicit revisions) //@[next] compile-flags: -Znext-solver //@ edition: 2024 -//@[current] check-pass +//@ check-pass // This previously caused an ICE with the new solver. // The delayed coroutine obligations were checked with the @@ -15,7 +15,6 @@ fn build_multiple<'a>() -> impl Sized { spawn(async { build_dependencies().await }); - //[next]~^ ERROR overflow evaluating the requirement } // Adding an explicit `Send` bound fixes it. diff --git a/tests/ui/traits/next-solver/opaques/too-many-opaques-hangs.rs b/tests/ui/traits/next-solver/opaques/too-many-opaques-hangs.rs new file mode 100644 index 0000000000000..3d89abc9eb660 --- /dev/null +++ b/tests/ui/traits/next-solver/opaques/too-many-opaques-hangs.rs @@ -0,0 +1,25 @@ +//@ compile-flags: -Znext-solver + +// Regression test for . +// This used to hang due to excessive opaques being registered endlessly. + +//~^^^^^ ERROR: overflow evaluating the requirement `::Iter == {type error}` + +#![feature(impl_trait_in_assoc_type)] +trait UnwrapItemsExt { + type Iter; +} + +trait MyTrait<'a> {} + +impl<'a> MyTrait<'a> for <() as UnwrapItemsExt>::Iter {} + +impl<'a, I> UnwrapItemsExt for I { + //~^ ERROR: the lifetime parameter `'a` is not constrained + type Iter = impl MyTrait<'a>; + fn unwrap_items() -> Self::Iter {} + //~^ ERROR: overflow evaluating the requirement `::Iter == ()` + //~| ERROR: method `unwrap_items` is not a member of trait `UnwrapItemsExt` +} + +fn main() {} diff --git a/tests/ui/traits/next-solver/opaques/too-many-opaques-hangs.stderr b/tests/ui/traits/next-solver/opaques/too-many-opaques-hangs.stderr new file mode 100644 index 0000000000000..824ba09ffc317 --- /dev/null +++ b/tests/ui/traits/next-solver/opaques/too-many-opaques-hangs.stderr @@ -0,0 +1,24 @@ +error[E0407]: method `unwrap_items` is not a member of trait `UnwrapItemsExt` + --> $DIR/too-many-opaques-hangs.rs:20:5 + | +LL | fn unwrap_items() -> Self::Iter {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ not a member of trait `UnwrapItemsExt` + +error[E0207]: the lifetime parameter `'a` is not constrained by the impl trait, self type, or predicates + --> $DIR/too-many-opaques-hangs.rs:17:6 + | +LL | impl<'a, I> UnwrapItemsExt for I { + | ^^ unconstrained lifetime parameter + +error[E0275]: overflow evaluating the requirement `::Iter == ()` + --> $DIR/too-many-opaques-hangs.rs:20:26 + | +LL | fn unwrap_items() -> Self::Iter {} + | ^^^^^^^^^^ + +error[E0275]: overflow evaluating the requirement `::Iter == {type error}` + +error: aborting due to 4 previous errors + +Some errors have detailed explanations: E0207, E0275, E0407. +For more information about an error, try `rustc --explain E0207`. 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 index 63be17cc9a7e3..64524c8c63ce5 100644 --- 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 @@ -21,7 +21,7 @@ where #[define_opaque(Tait)] fn foo<'a>() -> &'a Tait<'a> { prove(); - //~^ ERROR: overflow evaluating the requirement `for<'a> Tait<'a>: Sized` + //~^ ERROR: type annotations needed &() } 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 index 684ad98bc3f38..9b6dcfaec2688 100644 --- 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 @@ -1,18 +1,9 @@ -error[E0275]: overflow evaluating the requirement `for<'a> Tait<'a>: Sized` +error[E0282]: type annotations needed --> $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() -LL | where -LL | for<'a> Tait<'a>: Sized, - | ^^^^^ required by this bound in `prove` + | ^^^^^^^ cannot infer type for type alias `Tait<'a>` error: aborting due to 1 previous error -For more information about this error, try `rustc --explain E0275`. +For more information about this error, try `rustc --explain E0282`.