From 39602ee45400e73deae2babb7d5ca50d6b64096f Mon Sep 17 00:00:00 2001 From: Shoyu Vanilla Date: Fri, 27 Mar 2026 02:22:41 +0900 Subject: [PATCH] `-Znext-solver` Remove special handling of `NormalizesTo` goal --- .../src/solve/eval_ctxt/mod.rs | 258 ++---------------- .../src/solve/eval_ctxt/probe.rs | 56 +++- .../src/solve/normalizes_to/mod.rs | 88 +++--- ...t-impl-for-trait-obj-coherence.next.stderr | 4 +- .../indirect-impl-for-trait-obj-coherence.rs | 2 +- .../occurs-check/associated-type.next.stderr | 4 +- .../coherence/occurs-check/associated-type.rs | 2 +- ...nsubstituting-in-region-112823.next.stderr | 2 +- ...-type-whensubstituting-in-region-112823.rs | 2 +- .../opaque-type-unsatisfied-bound.rs | 6 +- .../opaque-type-unsatisfied-bound.stderr | 15 +- .../opaque-type-unsatisfied-fn-bound.rs | 2 +- .../opaque-type-unsatisfied-fn-bound.stderr | 6 +- ...ojection-param-candidates-are-ambiguous.rs | 2 +- ...tion-param-candidates-are-ambiguous.stderr | 4 +- ...rivial-unsized-projection-2.bad_new.stderr | 33 ++- .../ui/traits/trivial-unsized-projection-2.rs | 4 + .../trivial-unsized-projection.bad_new.stderr | 33 ++- tests/ui/traits/trivial-unsized-projection.rs | 4 + 19 files changed, 229 insertions(+), 298 deletions(-) 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 d6ed220909732..a621f49b4f5cd 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 @@ -1,5 +1,4 @@ use std::mem; -use std::ops::ControlFlow; #[cfg(feature = "nightly")] use rustc_macros::HashStable_NoContext; @@ -11,8 +10,7 @@ use rustc_type_ir::search_graph::{CandidateHeadUsages, PathKind}; use rustc_type_ir::solve::OpaqueTypesJank; use rustc_type_ir::{ self as ty, CanonicalVarValues, InferCtxtLike, Interner, Ty, TypeFoldable, TypeFolder, - TypeSuperFoldable, TypeSuperVisitable, TypeVisitable, TypeVisitableExt, TypeVisitor, - TypingMode, + TypeSuperFoldable, TypeVisitableExt, TypingMode, }; use tracing::{debug, instrument, trace}; @@ -47,13 +45,13 @@ enum CurrentGoalKind { /// These are currently the only goals whose impl where-clauses are considered to be /// productive steps. CoinductiveTrait, - /// Unlike other goals, `NormalizesTo` goals act like functions with the expected term - /// always being fully unconstrained. This would weaken inference however, as the nested + /// When probing and selecting `NormalizesTo` goal's projection candidates, the expected + /// term is always fully unconstrained. This would weaken inference however, as the nested /// goals never get the inference constraints from the actual normalized-to type. /// - /// Because of this we return any ambiguous nested goals from `NormalizesTo` to the - /// caller when then adds these to its own context. The caller is always an `AliasRelate` - /// goal so this never leaks out of the solver. + /// Because of this we return any ambiguous nested goals from the candidate probe to the + /// root of the `NormalizesTo` goal then adds these to its own context. So this never leaks + /// out of the solver. NormalizesTo, } @@ -67,7 +65,6 @@ impl CurrentGoalKind { CurrentGoalKind::Misc } } - ty::PredicateKind::NormalizesTo(_) => CurrentGoalKind::NormalizesTo, _ => CurrentGoalKind::Misc, } } @@ -509,17 +506,6 @@ where HasChanged::No => { let mut stalled_vars = orig_values; - // Remove the unconstrained RHS arg, which is expected to have changed. - if let Some(normalizes_to) = goal.predicate.as_normalizes_to() { - let normalizes_to = normalizes_to.skip_binder(); - let rhs_arg: I::GenericArg = normalizes_to.term.into(); - let idx = stalled_vars - .iter() - .rposition(|arg| *arg == rhs_arg) - .expect("expected unconstrained arg"); - stalled_vars.swap_remove(idx); - } - // Remove the canonicalized universal vars, since we only care about stalled existentials. let mut sub_roots = Vec::new(); stalled_vars.retain(|arg| match arg.kind() { @@ -564,7 +550,12 @@ where pub(super) fn compute_goal(&mut self, goal: Goal) -> QueryResult { let Goal { param_env, predicate } = goal; let kind = predicate.kind(); - self.enter_forall(kind, |ecx, kind| match kind { + + if let Some(normalizes_to) = predicate.as_normalizes_to() { + assert!(!normalizes_to.skip_binder().has_escaping_bound_vars()); + } + + let resp = self.enter_forall(kind, |ecx, kind| match kind { ty::PredicateKind::Clause(ty::ClauseKind::Trait(predicate)) => { ecx.compute_trait_goal(Goal { param_env, predicate }).map(|(r, _via)| r) } @@ -613,7 +604,11 @@ where ty::PredicateKind::Ambiguous => { ecx.evaluate_added_goals_and_make_canonical_response(Certainty::AMBIGUOUS) } - }) + })?; + + assert!(resp.value.external_constraints.normalization_nested_goals.is_empty()); + + Ok(resp) } // Recursively evaluates all the goals added to this `EvalCtxt` to completion, returning @@ -639,7 +634,6 @@ where /// /// Goals for the next step get directly added to the nested goals of the `EvalCtxt`. fn evaluate_added_goals_step(&mut self) -> Result, NoSolution> { - let cx = self.cx(); // If this loop did not result in any progress, what's our final certainty. let mut unchanged_certainty = Some(Certainty::Yes); for (source, goal, stalled_on) in mem::take(&mut self.nested_goals) { @@ -654,92 +648,17 @@ where continue; } - // We treat normalizes-to goals specially here. In each iteration we take the - // RHS of the projection, replace it with a fresh inference variable, and only - // after evaluating that goal do we equate the fresh inference variable with the - // actual RHS of the predicate. - // - // This is both to improve caching, and to avoid using the RHS of the - // projection predicate to influence the normalizes-to candidate we select. - // - // Forgetting to replace the RHS with a fresh inference variable when we evaluate - // this goal results in an ICE. - if let Some(pred) = goal.predicate.as_normalizes_to() { - // We should never encounter higher-ranked normalizes-to goals. - let pred = pred.no_bound_vars().unwrap(); - // Replace the goal with an unconstrained infer var, so the - // RHS does not affect projection candidate assembly. - let unconstrained_rhs = self.next_term_infer_of_kind(pred.term); - let unconstrained_goal = - goal.with(cx, ty::NormalizesTo { alias: pred.alias, term: unconstrained_rhs }); - - let ( - NestedNormalizationGoals(nested_goals), - GoalEvaluation { goal, certainty, stalled_on, has_changed: _ }, - ) = self.evaluate_goal_raw(source, unconstrained_goal, stalled_on)?; - // Add the nested goals from normalization to our own nested goals. - trace!(?nested_goals); - self.nested_goals.extend(nested_goals.into_iter().map(|(s, g)| (s, g, None))); - - // Finally, equate the goal's RHS with the unconstrained var. - // - // SUBTLE: - // We structurally relate aliases here. This is necessary - // as we otherwise emit a nested `AliasRelate` goal in case the - // returned term is a rigid alias, resulting in overflow. - // - // It is correct as both `goal.predicate.term` and `unconstrained_rhs` - // start out as an unconstrained inference variable so any aliases get - // fully normalized when instantiating it. - // - // FIXME: Strictly speaking this may be incomplete if the normalized-to - // type contains an ambiguous alias referencing bound regions. We should - // consider changing this to only use "shallow structural equality". - self.eq_structurally_relating_aliases( - goal.param_env, - pred.term, - unconstrained_rhs, - )?; - - // We only look at the `projection_ty` part here rather than - // looking at the "has changed" return from evaluate_goal, - // because we expect the `unconstrained_rhs` part of the predicate - // to have changed -- that means we actually normalized successfully! - // FIXME: Do we need to eagerly resolve here? Or should we check - // if the cache key has any changed vars? - let with_resolved_vars = self.resolve_vars_if_possible(goal); - if pred.alias - != with_resolved_vars - .predicate - .as_normalizes_to() - .unwrap() - .no_bound_vars() - .unwrap() - .alias - { - unchanged_certainty = None; - } - - match certainty { - Certainty::Yes => {} - Certainty::Maybe { .. } => { - self.nested_goals.push((source, with_resolved_vars, stalled_on)); - unchanged_certainty = unchanged_certainty.map(|c| c.and(certainty)); - } - } - } else { - let GoalEvaluation { goal, certainty, has_changed, stalled_on } = - self.evaluate_goal(source, goal, stalled_on)?; - if has_changed == HasChanged::Yes { - unchanged_certainty = None; - } + let GoalEvaluation { goal, certainty, has_changed, stalled_on } = + self.evaluate_goal(source, goal, stalled_on)?; + if has_changed == HasChanged::Yes { + unchanged_certainty = None; + } - match certainty { - Certainty::Yes => {} - Certainty::Maybe { .. } => { - self.nested_goals.push((source, goal, stalled_on)); - unchanged_certainty = unchanged_certainty.map(|c| c.and(certainty)); - } + match certainty { + Certainty::Yes => {} + Certainty::Maybe { .. } => { + self.nested_goals.push((source, goal, stalled_on)); + unchanged_certainty = unchanged_certainty.map(|c| c.and(certainty)); } } } @@ -802,129 +721,6 @@ where } } - /// Is the projection predicate is of the form `exists ::Assoc = T`. - /// - /// This is the case if the `term` does not occur in any other part of the predicate - /// and is able to name all other placeholder and inference variables. - #[instrument(level = "trace", skip(self), ret)] - pub(super) fn term_is_fully_unconstrained(&self, goal: Goal>) -> bool { - let universe_of_term = match goal.predicate.term.kind() { - ty::TermKind::Ty(ty) => { - if let ty::Infer(ty::TyVar(vid)) = ty.kind() { - self.delegate.universe_of_ty(vid).unwrap() - } else { - return false; - } - } - ty::TermKind::Const(ct) => { - if let ty::ConstKind::Infer(ty::InferConst::Var(vid)) = ct.kind() { - self.delegate.universe_of_ct(vid).unwrap() - } else { - return false; - } - } - }; - - struct ContainsTermOrNotNameable<'a, D: SolverDelegate, I: Interner> { - term: I::Term, - universe_of_term: ty::UniverseIndex, - delegate: &'a D, - cache: HashSet>, - } - - impl, I: Interner> ContainsTermOrNotNameable<'_, D, I> { - fn check_nameable(&self, universe: ty::UniverseIndex) -> ControlFlow<()> { - if self.universe_of_term.can_name(universe) { - ControlFlow::Continue(()) - } else { - ControlFlow::Break(()) - } - } - } - - impl, I: Interner> TypeVisitor - for ContainsTermOrNotNameable<'_, D, I> - { - type Result = ControlFlow<()>; - fn visit_ty(&mut self, t: Ty) -> Self::Result { - if self.cache.contains(&t) { - return ControlFlow::Continue(()); - } - - match t.kind() { - ty::Infer(ty::TyVar(vid)) => { - if let ty::TermKind::Ty(term) = self.term.kind() - && let ty::Infer(ty::TyVar(term_vid)) = term.kind() - && self.delegate.root_ty_var(vid) == self.delegate.root_ty_var(term_vid) - { - return ControlFlow::Break(()); - } - - self.check_nameable(self.delegate.universe_of_ty(vid).unwrap())?; - } - ty::Placeholder(p) => self.check_nameable(p.universe())?, - _ => { - if t.has_non_region_infer() || t.has_placeholders() { - t.super_visit_with(self)? - } - } - } - - assert!(self.cache.insert(t)); - ControlFlow::Continue(()) - } - - fn visit_const(&mut self, c: I::Const) -> Self::Result { - match c.kind() { - ty::ConstKind::Infer(ty::InferConst::Var(vid)) => { - if let ty::TermKind::Const(term) = self.term.kind() - && let ty::ConstKind::Infer(ty::InferConst::Var(term_vid)) = term.kind() - && self.delegate.root_const_var(vid) - == self.delegate.root_const_var(term_vid) - { - return ControlFlow::Break(()); - } - - self.check_nameable(self.delegate.universe_of_ct(vid).unwrap()) - } - ty::ConstKind::Placeholder(p) => self.check_nameable(p.universe()), - _ => { - if c.has_non_region_infer() || c.has_placeholders() { - c.super_visit_with(self) - } else { - ControlFlow::Continue(()) - } - } - } - } - - fn visit_predicate(&mut self, p: I::Predicate) -> Self::Result { - if p.has_non_region_infer() || p.has_placeholders() { - p.super_visit_with(self) - } else { - ControlFlow::Continue(()) - } - } - - fn visit_clauses(&mut self, c: I::Clauses) -> Self::Result { - if c.has_non_region_infer() || c.has_placeholders() { - c.super_visit_with(self) - } else { - ControlFlow::Continue(()) - } - } - } - - let mut visitor = ContainsTermOrNotNameable { - delegate: self.delegate, - universe_of_term, - term: goal.predicate.term, - cache: Default::default(), - }; - goal.predicate.alias.visit_with(&mut visitor).is_continue() - && goal.param_env.visit_with(&mut visitor).is_continue() - } - pub(super) fn sub_unify_ty_vids_raw(&self, a: ty::TyVid, b: ty::TyVid) { self.delegate.sub_unify_ty_vids_raw(a, b) } diff --git a/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/probe.rs b/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/probe.rs index edf2a5d1ba8dc..5901bf0dc08ee 100644 --- a/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/probe.rs +++ b/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/probe.rs @@ -1,11 +1,15 @@ use std::marker::PhantomData; +use rustc_type_ir::inherent::*; use rustc_type_ir::search_graph::CandidateHeadUsages; -use rustc_type_ir::{InferCtxtLike, Interner}; +use rustc_type_ir::solve::{Certainty, Goal}; +use rustc_type_ir::{self as ty, InferCtxtLike, Interner}; use tracing::instrument; +use crate::canonical::instantiate_and_apply_query_response; use crate::delegate::SolverDelegate; use crate::solve::assembly::Candidate; +use crate::solve::eval_ctxt::CurrentGoalKind; use crate::solve::{ BuiltinImplSource, CandidateSource, EvalCtxt, NoSolution, QueryResult, inspect, }; @@ -135,4 +139,54 @@ where source, } } + + /// When probing candidates for the `NormalizesTo` goal, the projection term should be + /// fully unconstrained. This helps it by replacing the projection term to an unconstrained + /// inference var, probe with `CurrentGoalKind::NormalizesTo` to handle ambiguous nested + /// goals, instantiate and apply the response and then add those nested goals to the root + /// context. + pub(in crate::solve) fn probe_with_unconstrained_projection_term( + &mut self, + goal: Goal>, + f: impl FnOnce(&mut EvalCtxt<'_, D, I>, Goal>) -> QueryResult, + ) -> Result<(I::Term, Certainty), NoSolution> { + let cx = self.cx(); + let unconstrained_term = self.next_term_infer_of_kind(goal.predicate.term); + let unconstrained_goal = goal + .with(cx, ty::NormalizesTo { alias: goal.predicate.alias, term: unconstrained_term }); + let extended_var_values = cx.mk_args_from_iter( + self.var_values.var_values.iter().chain(std::iter::once(unconstrained_term.into())), + ); + let mut extended_var_kinds = self.var_kinds.to_vec(); + let extra_var_kind = match unconstrained_term.kind() { + ty::TermKind::Ty(_) => ty::CanonicalVarKind::Ty { + ui: self.max_input_universe, + sub_root: ty::BoundVar::from_usize(extended_var_kinds.len()), + }, + ty::TermKind::Const(_) => ty::CanonicalVarKind::Const(self.max_input_universe), + }; + extended_var_kinds.push(extra_var_kind); + let extended_var_kinds = cx.mk_canonical_var_kinds(&extended_var_kinds); + + let resp = self.probe(|_| inspect::ProbeKind::ShadowedEnvProbing).enter(|ecx| { + ecx.current_goal_kind = CurrentGoalKind::NormalizesTo; + ecx.var_values.var_values = extended_var_values; + ecx.var_kinds = extended_var_kinds; + f(ecx, unconstrained_goal) + })?; + + let (nested_goals, certainty) = instantiate_and_apply_query_response( + self.delegate, + goal.param_env, + extended_var_values.as_slice(), + resp, + self.origin_span, + ); + + for (source, nested_goal) in nested_goals.0 { + self.add_goal(source, nested_goal); + } + + Ok((unconstrained_term, certainty)) + } } diff --git a/compiler/rustc_next_trait_solver/src/solve/normalizes_to/mod.rs b/compiler/rustc_next_trait_solver/src/solve/normalizes_to/mod.rs index 13ed945857db2..49d4c56c5e3aa 100644 --- a/compiler/rustc_next_trait_solver/src/solve/normalizes_to/mod.rs +++ b/compiler/rustc_next_trait_solver/src/solve/normalizes_to/mod.rs @@ -29,7 +29,6 @@ where &mut self, goal: Goal>, ) -> QueryResult { - debug_assert!(self.term_is_fully_unconstrained(goal)); let cx = self.cx(); match goal.predicate.alias.kind(cx) { ty::AliasTermKind::ProjectionTy | ty::AliasTermKind::ProjectionConst => { @@ -39,49 +38,64 @@ where let trait_goal: Goal> = goal.with(cx, trait_ref); ecx.compute_trait_goal(trait_goal) })?; - self.assemble_and_merge_candidates( - proven_via, - goal, - |ecx| { - // FIXME(generic_associated_types): Addresses aggressive inference in #92917. - // - // If this type is a GAT with currently unconstrained arguments, we do not - // want to normalize it via a candidate which only applies for a specific - // instantiation. We could otherwise keep the GAT as rigid and succeed this way. - // See tests/ui/generic-associated-types/no-incomplete-gat-arg-inference.rs. - // - // This only avoids normalization if a GAT argument is fully unconstrained. - // This is quite arbitrary but fixing it causes some ambiguity, see #125196. - for arg in goal.predicate.alias.own_args(cx).iter() { - let Some(term) = arg.as_term() else { - continue; - }; - match ecx.structurally_normalize_term(goal.param_env, term) { - Ok(term) => { - if term.is_infer() { - return Some( + + let term = self.next_term_infer_of_kind(goal.predicate.term); + self.eq(goal.param_env, goal.predicate.term, term)?; + + let (probed_term, certainty) = + self.probe_with_unconstrained_projection_term(goal, |ecx, goal| { + ecx.assemble_and_merge_candidates( + proven_via, + goal, + |ecx| { + // FIXME(generic_associated_types): Addresses aggressive inference in #92917. + // + // If this type is a GAT with currently unconstrained arguments, we do not + // want to normalize it via a candidate which only applies for a specific + // instantiation. We could otherwise keep the GAT as rigid and succeed this way. + // See tests/ui/generic-associated-types/no-incomplete-gat-arg-inference.rs. + // + // This only avoids normalization if a GAT argument is fully unconstrained. + // This is quite arbitrary but fixing it causes some ambiguity, see #125196. + for arg in goal.predicate.alias.own_args(cx).iter() { + let Some(term) = arg.as_term() else { + continue; + }; + match ecx.structurally_normalize_term(goal.param_env, term) { + Ok(term) => { + if term.is_infer() { + return Some( ecx.evaluate_added_goals_and_make_canonical_response( Certainty::AMBIGUOUS, ), ); + } + } + Err(NoSolution) => return Some(Err(NoSolution)), } } - Err(NoSolution) => return Some(Err(NoSolution)), - } - } - None - }, - |ecx| { - ecx.probe(|&result| ProbeKind::RigidAlias { result }).enter(|this| { - this.structurally_instantiate_normalizes_to_term( - goal, - goal.predicate.alias, - ); - this.evaluate_added_goals_and_make_canonical_response(Certainty::Yes) - }) - }, - ) + None + }, + |ecx| { + ecx.probe(|&result| ProbeKind::RigidAlias { result }).enter( + |this| { + this.structurally_instantiate_normalizes_to_term( + goal, + goal.predicate.alias, + ); + this.evaluate_added_goals_and_make_canonical_response( + Certainty::Yes, + ) + }, + ) + }, + ) + })?; + + self.eq_structurally_relating_aliases(goal.param_env, term, probed_term)?; + + self.evaluate_added_goals_and_make_canonical_response(certainty) } ty::AliasTermKind::InherentTy | ty::AliasTermKind::InherentConst => { self.normalize_inherent_associated_term(goal) diff --git a/tests/ui/coherence/indirect-impl-for-trait-obj-coherence.next.stderr b/tests/ui/coherence/indirect-impl-for-trait-obj-coherence.next.stderr index b6636d4de86eb..120bffed7c4ec 100644 --- a/tests/ui/coherence/indirect-impl-for-trait-obj-coherence.next.stderr +++ b/tests/ui/coherence/indirect-impl-for-trait-obj-coherence.next.stderr @@ -1,8 +1,8 @@ -error[E0284]: type annotations needed: cannot normalize ` as Object>::Output` +error[E0284]: type annotations needed: cannot satisfy ` as Object>::Output normalizes-to T` --> $DIR/indirect-impl-for-trait-obj-coherence.rs:25:41 | LL | foo::, U>(x) - | ^ cannot normalize ` as Object>::Output` + | ^ cannot satisfy ` as Object>::Output normalizes-to T` error: aborting due to 1 previous error diff --git a/tests/ui/coherence/indirect-impl-for-trait-obj-coherence.rs b/tests/ui/coherence/indirect-impl-for-trait-obj-coherence.rs index abfd51c2008bb..a5c3384d0d7da 100644 --- a/tests/ui/coherence/indirect-impl-for-trait-obj-coherence.rs +++ b/tests/ui/coherence/indirect-impl-for-trait-obj-coherence.rs @@ -23,7 +23,7 @@ fn foo(x: >::Output) -> U { #[allow(dead_code)] fn transmute(x: T) -> U { foo::, U>(x) - //[next]~^ ERROR type annotations needed: cannot normalize ` as Object>::Output` + //[next]~^ ERROR type annotations needed: cannot satisfy ` as Object>::Output normalizes-to T` } fn main() {} diff --git a/tests/ui/coherence/occurs-check/associated-type.next.stderr b/tests/ui/coherence/occurs-check/associated-type.next.stderr index 381f5c60f9831..a296f95abbbd2 100644 --- a/tests/ui/coherence/occurs-check/associated-type.next.stderr +++ b/tests/ui/coherence/occurs-check/associated-type.next.stderr @@ -14,11 +14,11 @@ LL | | for<'a> *const T: ToUnit<'a>, | = note: this behavior recently changed as a result of a bug fix; see rust-lang/rust#56105 for details -error[E0284]: type annotations needed: cannot normalize ` fn(&'a (), ()) as Overlap fn(&'a (), ())>>::Assoc` +error[E0284]: type annotations needed: cannot satisfy ` fn(&'a (), ()) as Overlap fn(&'a (), ())>>::Assoc normalizes-to usize` --> $DIR/associated-type.rs:45:59 | LL | foo:: fn(&'a (), ()), for<'a> fn(&'a (), ())>(3usize); - | ^^^^^^ cannot normalize ` fn(&'a (), ()) as Overlap fn(&'a (), ())>>::Assoc` + | ^^^^^^ cannot satisfy ` fn(&'a (), ()) as Overlap fn(&'a (), ())>>::Assoc normalizes-to usize` error: aborting due to 2 previous errors diff --git a/tests/ui/coherence/occurs-check/associated-type.rs b/tests/ui/coherence/occurs-check/associated-type.rs index d56ccc5b3532d..7e8b24e3a60bc 100644 --- a/tests/ui/coherence/occurs-check/associated-type.rs +++ b/tests/ui/coherence/occurs-check/associated-type.rs @@ -43,5 +43,5 @@ fn foo, U>(x: T::Assoc) -> T::Assoc { fn main() { foo:: fn(&'a (), ()), for<'a> fn(&'a (), ())>(3usize); - //[next]~^ ERROR: cannot normalize + //[next]~^ ERROR: type annotations needed: cannot satisfy ` fn(&'a (), ()) as Overlap fn(&'a (), ())>>::Assoc normalizes-to usize` } diff --git a/tests/ui/impl-trait/ice-unexpected-param-type-whensubstituting-in-region-112823.next.stderr b/tests/ui/impl-trait/ice-unexpected-param-type-whensubstituting-in-region-112823.next.stderr index f2e249f2cbf99..9632d2ce6249a 100644 --- a/tests/ui/impl-trait/ice-unexpected-param-type-whensubstituting-in-region-112823.next.stderr +++ b/tests/ui/impl-trait/ice-unexpected-param-type-whensubstituting-in-region-112823.next.stderr @@ -25,7 +25,7 @@ LL | type LineStream<'c, 'd> = impl Stream; | = note: `LineStream` must be used in combination with a concrete type within the same impl -error[E0271]: type mismatch resolving `::LineStreamFut<'a, Repr> normalizes-to ()` +error[E0271]: type mismatch resolving `::LineStreamFut<'a, Repr> == ()` --> $DIR/ice-unexpected-param-type-whensubstituting-in-region-112823.rs:29:43 | LL | fn line_stream<'a, Repr>(&'a self) -> Self::LineStreamFut<'a, Repr> {} diff --git a/tests/ui/impl-trait/ice-unexpected-param-type-whensubstituting-in-region-112823.rs b/tests/ui/impl-trait/ice-unexpected-param-type-whensubstituting-in-region-112823.rs index 7cf155ce01ef4..0b507ed948ae1 100644 --- a/tests/ui/impl-trait/ice-unexpected-param-type-whensubstituting-in-region-112823.rs +++ b/tests/ui/impl-trait/ice-unexpected-param-type-whensubstituting-in-region-112823.rs @@ -29,7 +29,7 @@ impl X for Y { fn line_stream<'a, Repr>(&'a self) -> Self::LineStreamFut<'a, Repr> {} //~^ ERROR method `line_stream` is not a member of trait `X` //[current]~^^ ERROR `()` is not a future - //[next]~^^^ ERROR type mismatch resolving `::LineStreamFut<'a, Repr> normalizes-to ()` + //[next]~^^^ ERROR type mismatch resolving `::LineStreamFut<'a, Repr> == ()` //[next]~| ERROR type mismatch resolving `::LineStreamFut<'a, Repr> normalizes-to _` //[next]~| ERROR type mismatch resolving `::LineStreamFut<'a, Repr> normalizes-to _` } diff --git a/tests/ui/traits/negative-bounds/opaque-type-unsatisfied-bound.rs b/tests/ui/traits/negative-bounds/opaque-type-unsatisfied-bound.rs index 14f0cbcc8b77c..eef7bb0130dc6 100644 --- a/tests/ui/traits/negative-bounds/opaque-type-unsatisfied-bound.rs +++ b/tests/ui/traits/negative-bounds/opaque-type-unsatisfied-bound.rs @@ -13,9 +13,9 @@ fn main() { } fn weird0() -> impl Sized + !Sized {} -//~^ ERROR the trait bound `(): !Sized` is not satisfied +//~^ ERROR type mismatch resolving `impl !Sized + Sized == ()` fn weird1() -> impl !Sized + Sized {} -//~^ ERROR the trait bound `(): !Sized` is not satisfied +//~^ ERROR type mismatch resolving `impl !Sized + Sized == ()` fn weird2() -> impl !Sized {} -//~^ ERROR the trait bound `(): !Sized` is not satisfied +//~^ ERROR type mismatch resolving `impl !Sized == ()` //~| ERROR the size for values of type diff --git a/tests/ui/traits/negative-bounds/opaque-type-unsatisfied-bound.stderr b/tests/ui/traits/negative-bounds/opaque-type-unsatisfied-bound.stderr index 3ba3d8d8bd595..41d9e74f8076e 100644 --- a/tests/ui/traits/negative-bounds/opaque-type-unsatisfied-bound.stderr +++ b/tests/ui/traits/negative-bounds/opaque-type-unsatisfied-bound.stderr @@ -7,23 +7,23 @@ LL | fn weird2() -> impl !Sized {} = help: the trait `Sized` is not implemented for `impl !Sized` = note: the return type of a function must have a statically known size -error[E0277]: the trait bound `(): !Sized` is not satisfied +error[E0271]: type mismatch resolving `impl !Sized + Sized == ()` --> $DIR/opaque-type-unsatisfied-bound.rs:15:16 | LL | fn weird0() -> impl Sized + !Sized {} - | ^^^^^^^^^^^^^^^^^^^ the trait bound `(): !Sized` is not satisfied + | ^^^^^^^^^^^^^^^^^^^ types differ -error[E0277]: the trait bound `(): !Sized` is not satisfied +error[E0271]: type mismatch resolving `impl !Sized + Sized == ()` --> $DIR/opaque-type-unsatisfied-bound.rs:17:16 | LL | fn weird1() -> impl !Sized + Sized {} - | ^^^^^^^^^^^^^^^^^^^ the trait bound `(): !Sized` is not satisfied + | ^^^^^^^^^^^^^^^^^^^ types differ -error[E0277]: the trait bound `(): !Sized` is not satisfied +error[E0271]: type mismatch resolving `impl !Sized == ()` --> $DIR/opaque-type-unsatisfied-bound.rs:19:16 | LL | fn weird2() -> impl !Sized {} - | ^^^^^^^^^^^ the trait bound `(): !Sized` is not satisfied + | ^^^^^^^^^^^ types differ error[E0277]: the trait bound `impl !Trait: Trait` is not satisfied --> $DIR/opaque-type-unsatisfied-bound.rs:12:13 @@ -41,4 +41,5 @@ LL | fn consume(_: impl Trait) {} error: aborting due to 5 previous errors -For more information about this error, try `rustc --explain E0277`. +Some errors have detailed explanations: E0271, E0277. +For more information about an error, try `rustc --explain E0271`. diff --git a/tests/ui/traits/negative-bounds/opaque-type-unsatisfied-fn-bound.rs b/tests/ui/traits/negative-bounds/opaque-type-unsatisfied-fn-bound.rs index 39422914afcdd..9951826a8466d 100644 --- a/tests/ui/traits/negative-bounds/opaque-type-unsatisfied-fn-bound.rs +++ b/tests/ui/traits/negative-bounds/opaque-type-unsatisfied-fn-bound.rs @@ -3,6 +3,6 @@ #![feature(negative_bounds, unboxed_closures)] fn produce() -> impl !Fn<(u32,)> {} -//~^ ERROR the trait bound `(): !Fn(u32)` is not satisfied +//~^ ERROR type mismatch resolving `impl !Fn<(u32,)> == ()` fn main() {} diff --git a/tests/ui/traits/negative-bounds/opaque-type-unsatisfied-fn-bound.stderr b/tests/ui/traits/negative-bounds/opaque-type-unsatisfied-fn-bound.stderr index 760e5aa62f2c1..e1b84e0df7a54 100644 --- a/tests/ui/traits/negative-bounds/opaque-type-unsatisfied-fn-bound.stderr +++ b/tests/ui/traits/negative-bounds/opaque-type-unsatisfied-fn-bound.stderr @@ -1,9 +1,9 @@ -error[E0277]: the trait bound `(): !Fn(u32)` is not satisfied +error[E0271]: type mismatch resolving `impl !Fn<(u32,)> == ()` --> $DIR/opaque-type-unsatisfied-fn-bound.rs:5:17 | LL | fn produce() -> impl !Fn<(u32,)> {} - | ^^^^^^^^^^^^^^^^ the trait bound `(): !Fn(u32)` is not satisfied + | ^^^^^^^^^^^^^^^^ types differ error: aborting due to 1 previous error -For more information about this error, try `rustc --explain E0277`. +For more information about this error, try `rustc --explain E0271`. diff --git a/tests/ui/traits/next-solver/normalize/two-projection-param-candidates-are-ambiguous.rs b/tests/ui/traits/next-solver/normalize/two-projection-param-candidates-are-ambiguous.rs index 5239474ff44b2..cc9d9b9081026 100644 --- a/tests/ui/traits/next-solver/normalize/two-projection-param-candidates-are-ambiguous.rs +++ b/tests/ui/traits/next-solver/normalize/two-projection-param-candidates-are-ambiguous.rs @@ -24,7 +24,7 @@ fn needs_bar() {} fn foo + Foo>() { needs_bar::(); - //~^ ERROR type annotations needed: cannot normalize + //~^ ERROR type annotations needed: cannot satisfy `::Assoc normalizes-to i32` } fn main() {} diff --git a/tests/ui/traits/next-solver/normalize/two-projection-param-candidates-are-ambiguous.stderr b/tests/ui/traits/next-solver/normalize/two-projection-param-candidates-are-ambiguous.stderr index 270ad85171779..23ec9d87bcfe0 100644 --- a/tests/ui/traits/next-solver/normalize/two-projection-param-candidates-are-ambiguous.stderr +++ b/tests/ui/traits/next-solver/normalize/two-projection-param-candidates-are-ambiguous.stderr @@ -1,8 +1,8 @@ -error[E0284]: type annotations needed: cannot normalize `::Assoc` +error[E0284]: type annotations needed: cannot satisfy `::Assoc normalizes-to i32` --> $DIR/two-projection-param-candidates-are-ambiguous.rs:26:17 | LL | needs_bar::(); - | ^ cannot normalize `::Assoc` + | ^ cannot satisfy `::Assoc normalizes-to i32` | note: required for `T` to implement `Bar` --> $DIR/two-projection-param-candidates-are-ambiguous.rs:21:9 diff --git a/tests/ui/traits/trivial-unsized-projection-2.bad_new.stderr b/tests/ui/traits/trivial-unsized-projection-2.bad_new.stderr index bf8d3c40cf653..2a81d6e951589 100644 --- a/tests/ui/traits/trivial-unsized-projection-2.bad_new.stderr +++ b/tests/ui/traits/trivial-unsized-projection-2.bad_new.stderr @@ -1,3 +1,17 @@ +error[E0271]: type mismatch resolving `::Assert normalizes-to _` + --> $DIR/trivial-unsized-projection-2.rs:22:12 + | +LL | const FOO: ::Assert = todo!(); + | ^^^^^^^^^^^^^^^^^^^^^ types differ + +error[E0271]: type mismatch resolving `::Assert normalizes-to _` + --> $DIR/trivial-unsized-projection-2.rs:22:12 + | +LL | const FOO: ::Assert = todo!(); + | ^^^^^^^^^^^^^^^^^^^^^ types differ + | + = note: statics and constants must have a statically known size + error[E0277]: the size for values of type `[()]` cannot be known at compilation time --> $DIR/trivial-unsized-projection-2.rs:22:12 | @@ -49,6 +63,21 @@ help: consider relaxing the implicit `Sized` restriction LL | type Assert: ?Sized | ++++++++ -error: aborting due to 2 previous errors +error[E0271]: type mismatch resolving `::Assert normalizes-to _` + --> $DIR/trivial-unsized-projection-2.rs:22:36 + | +LL | const FOO: ::Assert = todo!(); + | ^^^^^^^ types differ + +error[E0271]: type mismatch resolving `::Assert normalizes-to _` + --> $DIR/trivial-unsized-projection-2.rs:22:36 + | +LL | const FOO: ::Assert = todo!(); + | ^^^^^^^ types differ + | + = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` + +error: aborting due to 6 previous errors -For more information about this error, try `rustc --explain E0277`. +Some errors have detailed explanations: E0271, E0277. +For more information about an error, try `rustc --explain E0271`. diff --git a/tests/ui/traits/trivial-unsized-projection-2.rs b/tests/ui/traits/trivial-unsized-projection-2.rs index af4e12f6f9008..ca9cf9a3106dc 100644 --- a/tests/ui/traits/trivial-unsized-projection-2.rs +++ b/tests/ui/traits/trivial-unsized-projection-2.rs @@ -24,6 +24,10 @@ const FOO: ::Assert = todo!(); //[bad]~| ERROR the size for values of type `[()]` cannot be known at compilation time //[bad_new]~^^^ ERROR the size for values of type `[()]` cannot be known at compilation time //[bad_new]~| ERROR the size for values of type `[()]` cannot be known at compilation time +//[bad_new]~| ERROR type mismatch resolving `::Assert normalizes-to _` +//[bad_new]~| ERROR type mismatch resolving `::Assert normalizes-to _` +//[bad_new]~| ERROR type mismatch resolving `::Assert normalizes-to _` +//[bad_new]~| ERROR type mismatch resolving `::Assert normalizes-to _` #[cfg(any(good, good_new))] // Well-formed in trivially false param-env diff --git a/tests/ui/traits/trivial-unsized-projection.bad_new.stderr b/tests/ui/traits/trivial-unsized-projection.bad_new.stderr index 4aea63329b360..886a75918d3d0 100644 --- a/tests/ui/traits/trivial-unsized-projection.bad_new.stderr +++ b/tests/ui/traits/trivial-unsized-projection.bad_new.stderr @@ -1,3 +1,17 @@ +error[E0271]: type mismatch resolving `<[()] as Bad>::Assert normalizes-to _` + --> $DIR/trivial-unsized-projection.rs:20:12 + | +LL | const FOO: <[()] as Bad>::Assert = todo!(); + | ^^^^^^^^^^^^^^^^^^^^^ types differ + +error[E0271]: type mismatch resolving `<[()] as Bad>::Assert normalizes-to _` + --> $DIR/trivial-unsized-projection.rs:20:12 + | +LL | const FOO: <[()] as Bad>::Assert = todo!(); + | ^^^^^^^^^^^^^^^^^^^^^ types differ + | + = note: statics and constants must have a statically known size + error[E0277]: the size for values of type `[()]` cannot be known at compilation time --> $DIR/trivial-unsized-projection.rs:20:12 | @@ -39,6 +53,21 @@ help: consider relaxing the implicit `Sized` restriction LL | type Assert: ?Sized | ++++++++ -error: aborting due to 2 previous errors +error[E0271]: type mismatch resolving `<[()] as Bad>::Assert normalizes-to _` + --> $DIR/trivial-unsized-projection.rs:20:36 + | +LL | const FOO: <[()] as Bad>::Assert = todo!(); + | ^^^^^^^ types differ + +error[E0271]: type mismatch resolving `<[()] as Bad>::Assert normalizes-to _` + --> $DIR/trivial-unsized-projection.rs:20:36 + | +LL | const FOO: <[()] as Bad>::Assert = todo!(); + | ^^^^^^^ types differ + | + = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` + +error: aborting due to 6 previous errors -For more information about this error, try `rustc --explain E0277`. +Some errors have detailed explanations: E0271, E0277. +For more information about an error, try `rustc --explain E0271`. diff --git a/tests/ui/traits/trivial-unsized-projection.rs b/tests/ui/traits/trivial-unsized-projection.rs index 62ff25fb7ac0a..9a730cc7da0a5 100644 --- a/tests/ui/traits/trivial-unsized-projection.rs +++ b/tests/ui/traits/trivial-unsized-projection.rs @@ -22,6 +22,10 @@ const FOO: <[()] as Bad>::Assert = todo!(); //[bad]~| ERROR the size for values of type `[()]` cannot be known at compilation time //[bad_new]~^^^ ERROR the size for values of type `[()]` cannot be known at compilation time //[bad_new]~| ERROR the size for values of type `[()]` cannot be known at compilation time +//[bad_new]~| ERROR type mismatch resolving `<[()] as Bad>::Assert normalizes-to _` +//[bad_new]~| ERROR type mismatch resolving `<[()] as Bad>::Assert normalizes-to _` +//[bad_new]~| ERROR type mismatch resolving `<[()] as Bad>::Assert normalizes-to _` +//[bad_new]~| ERROR type mismatch resolving `<[()] as Bad>::Assert normalizes-to _` #[cfg(any(good, good_new))] // Well-formed in trivially false param-env