From 3eeb91b777d7260a1ae6e40278dedd0b6edf74f9 Mon Sep 17 00:00:00 2001 From: lcnr Date: Sun, 17 May 2026 14:34:32 +0200 Subject: [PATCH 1/3] eagerly normalize things in solver --- compiler/rustc_infer/src/infer/mod.rs | 26 ++- .../rustc_next_trait_solver/src/normalize.rs | 97 +++++---- .../src/solve/alias_relate.rs | 4 +- .../src/solve/assembly/mod.rs | 6 +- .../src/solve/effect_goals.rs | 16 +- .../src/solve/eval_ctxt/mod.rs | 190 +++++++----------- .../rustc_next_trait_solver/src/solve/mod.rs | 4 +- .../src/solve/normalizes_to/free_alias.rs | 2 +- .../src/solve/normalizes_to/inherent.rs | 2 +- .../src/solve/normalizes_to/mod.rs | 19 +- .../src/solve/normalizes_to/opaque_types.rs | 6 +- .../src/solve/project_goals.rs | 2 +- .../src/solve/trait_goals.rs | 30 +-- .../src/solve/fulfill.rs | 13 +- .../src/solve/normalize.rs | 115 ++++++----- compiler/rustc_type_ir/src/error.rs | 8 +- ...-on-failed-eval-with-vars-fail.next.stderr | 9 +- ...ambiguous-on-failed-eval-with-vars-fail.rs | 4 +- .../negative-coherence-ice-140609.rs | 14 -- .../specialization-fuzzing-ice-133639.rs | 18 -- .../mgca/free-const-recursive.rs | 2 +- .../mgca/free-const-recursive.stderr | 6 +- .../mgca/projection-const-recursive.rs | 4 +- .../mgca/projection-const-recursive.stderr | 6 +- .../delayed-obligations-emit.next.stderr | 1 + ...-in-higher-ranked-fn-signature.next.stderr | 6 +- .../in-trait/alias-bounds-when-not-wf.rs | 1 + .../in-trait/alias-bounds-when-not-wf.stderr | 8 +- tests/ui/traits/next-solver/async.fail.stderr | 4 +- tests/ui/traits/next-solver/async.rs | 2 +- .../coercion/non-wf-in-coerce-pointers.rs | 1 + .../coercion/non-wf-in-coerce-pointers.stderr | 10 +- .../find-param-recursion-issue-152716.rs | 2 +- .../find-param-recursion-issue-152716.stderr | 2 +- .../lazy-nested-obligations-2.next.stderr | 14 +- .../traits/next-solver/more-object-bound.rs | 2 +- .../next-solver/more-object-bound.stderr | 12 +- .../normalize/normalize-param-env-2.stderr | 38 +++- .../normalize-param-env-4.next.stderr | 18 +- .../recursive-self-normalization-2.rs | 2 +- .../recursive-self-normalization-2.stderr | 6 +- ...lize-diverging-alias-in-struct.next.stderr | 7 +- .../normalize-diverging-alias-in-struct.rs | 2 +- .../solver-cycles/129541-recursive-struct.rs | 1 - .../wf/return-type-non-wf-no-ice.next.stderr | 18 +- tests/ui/wf/return-type-non-wf-no-ice.rs | 3 +- 46 files changed, 406 insertions(+), 357 deletions(-) delete mode 100644 tests/ui/const-generics/generic_const_exprs/negative-coherence-ice-140609.rs delete mode 100644 tests/ui/const-generics/generic_const_exprs/specialization-fuzzing-ice-133639.rs diff --git a/compiler/rustc_infer/src/infer/mod.rs b/compiler/rustc_infer/src/infer/mod.rs index c0029719c6e12..9b1d0abdd016f 100644 --- a/compiler/rustc_infer/src/infer/mod.rs +++ b/compiler/rustc_infer/src/infer/mod.rs @@ -28,10 +28,11 @@ use rustc_middle::traits::select; use rustc_middle::traits::solve::Goal; use rustc_middle::ty::error::{ExpectedFound, TypeError}; use rustc_middle::ty::{ - self, BoundVarReplacerDelegate, ConstVid, FloatVid, GenericArg, GenericArgKind, GenericArgs, - GenericArgsRef, GenericParamDefKind, InferConst, IntVid, OpaqueTypeKey, ProvisionalHiddenType, - PseudoCanonicalInput, Term, TermKind, Ty, TyCtxt, TyVid, TypeFoldable, TypeFolder, - TypeSuperFoldable, TypeVisitable, TypeVisitableExt, TypingEnv, TypingMode, fold_regions, + self, AliasTermKind, BoundVarReplacerDelegate, ConstVid, FloatVid, GenericArg, GenericArgKind, + GenericArgs, GenericArgsRef, GenericParamDefKind, InferConst, IntVid, OpaqueTypeKey, + ProvisionalHiddenType, PseudoCanonicalInput, Term, TermKind, Ty, TyCtxt, TyVid, TypeFoldable, + TypeFolder, TypeSuperFoldable, TypeVisitable, TypeVisitableExt, TypingEnv, TypingMode, + fold_regions, }; use rustc_span::{DUMMY_SP, Span, Symbol}; use rustc_type_ir::MayBeErased; @@ -962,6 +963,23 @@ impl<'tcx> InferCtxt<'tcx> { } } + pub fn next_term_var_for_alias( + &self, + alias: ty::AliasTerm<'tcx>, + span: Span, + ) -> ty::Term<'tcx> { + match alias.kind(self.tcx) { + AliasTermKind::ProjectionTy { .. } + | AliasTermKind::InherentTy { .. } + | AliasTermKind::OpaqueTy { .. } + | AliasTermKind::FreeTy { .. } => self.next_ty_var(span).into(), + AliasTermKind::UnevaluatedConst { .. } + | AliasTermKind::ProjectionConst { .. } + | AliasTermKind::FreeConst { .. } + | AliasTermKind::InherentConst { .. } => self.next_const_var(span).into(), + } + } + /// Return the universe that the region `r` was created in. For /// most regions (e.g., `'static`, named regions from the user, /// etc) this is the root universe U0. For inference variables or diff --git a/compiler/rustc_next_trait_solver/src/normalize.rs b/compiler/rustc_next_trait_solver/src/normalize.rs index 7506591d6fb5d..84af3e66a7a13 100644 --- a/compiler/rustc_next_trait_solver/src/normalize.rs +++ b/compiler/rustc_next_trait_solver/src/normalize.rs @@ -1,9 +1,10 @@ +use std::fmt::Debug; + use rustc_type_ir::data_structures::ensure_sufficient_stack; use rustc_type_ir::inherent::*; -use rustc_type_ir::solve::{Goal, NoSolution}; use rustc_type_ir::{ - self as ty, Binder, FallibleTypeFolder, InferConst, InferCtxtLike, InferTy, Interner, - TypeFoldable, TypeSuperFoldable, TypeSuperVisitable, TypeVisitable, TypeVisitableExt, + self as ty, AliasTerm, Binder, FallibleTypeFolder, InferConst, InferCtxtLike, InferTy, + Interner, TypeFoldable, TypeSuperFoldable, TypeSuperVisitable, TypeVisitable, TypeVisitableExt, TypeVisitor, UniverseIndex, }; use tracing::instrument; @@ -13,7 +14,7 @@ use crate::placeholder::{BoundVarReplacer, PlaceholderReplacer}; /// This folder normalizes value and collects ambiguous goals. /// /// Note that for ambiguous alias which contains escaping bound vars, -/// we just return the original alias and don't collect the ambiguous goal. +/// we just return the original alias. pub struct NormalizationFolder<'a, Infcx, I, F> where Infcx: InferCtxtLike, @@ -21,11 +22,16 @@ where { infcx: &'a Infcx, universes: Vec>, - stalled_goals: Vec>, normalize: F, } -#[derive(PartialEq, Eq)] +#[derive(PartialEq, Eq, Debug)] +pub enum NormalizationWasAmbiguous { + Yes, + No, +} + +#[derive(PartialEq, Eq, Debug)] enum HasEscapingBoundVars { Yes, No, @@ -97,34 +103,25 @@ where } } -impl<'a, Infcx, I, F> NormalizationFolder<'a, Infcx, I, F> +impl<'a, Infcx, I, F, E> NormalizationFolder<'a, Infcx, I, F> where Infcx: InferCtxtLike, I: Interner, - F: FnMut(I::Term) -> Result<(I::Term, Option>), NoSolution>, + F: FnMut(AliasTerm) -> Result<(I::Term, NormalizationWasAmbiguous), E>, { - pub fn new( - infcx: &'a Infcx, - universes: Vec>, - stalled_goals: Vec>, - normalize: F, - ) -> Self { - Self { infcx, universes, stalled_goals, normalize } - } - - pub fn stalled_goals(self) -> Vec> { - self.stalled_goals + pub fn new(infcx: &'a Infcx, universes: Vec>, normalize: F) -> Self { + Self { infcx, universes, normalize } } fn normalize_alias_term( &mut self, - alias_term: I::Term, + alias_term: AliasTerm, has_escaping: HasEscapingBoundVars, - ) -> Result { + ) -> Result { let current_universe = self.infcx.universe(); self.infcx.create_next_universe(); - let (normalized, ambig_goal) = (self.normalize)(alias_term)?; + let (normalized, normalization_was_ambiguous) = (self.normalize)(alias_term)?; // Return ambiguous higher ranked alias as is, if // - it contains escaping vars, and @@ -134,27 +131,29 @@ where // referencing the temporary placeholders. // // We can normalize the ambiguous alias again after the binder is instantiated. - if ambig_goal.is_some() && has_escaping == HasEscapingBoundVars::Yes { + if NormalizationWasAmbiguous::Yes == normalization_was_ambiguous + && has_escaping == HasEscapingBoundVars::Yes + { let mut visitor = MaxUniverse::new(self.infcx); normalized.visit_with(&mut visitor); let max_universe = visitor.max_universe(); if current_universe.cannot_name(max_universe) { - return Ok(alias_term); + return Ok(alias_term.to_term(self.infcx.cx())); } } - self.stalled_goals.extend(ambig_goal); Ok(normalized) } } -impl<'a, Infcx, I, F> FallibleTypeFolder for NormalizationFolder<'a, Infcx, I, F> +impl<'a, Infcx, I, F, E> FallibleTypeFolder for NormalizationFolder<'a, Infcx, I, F> where Infcx: InferCtxtLike, I: Interner, - F: FnMut(I::Term) -> Result<(I::Term, Option>), NoSolution>, + F: FnMut(AliasTerm) -> Result<(I::Term, NormalizationWasAmbiguous), E>, + E: Debug, { - type Error = NoSolution; + type Error = E; fn cx(&self) -> I { self.infcx.cx() @@ -180,26 +179,26 @@ where // With eager normalization, we should normalize the args of alias before // normalizing the alias itself. let ty = ty.try_super_fold_with(self)?; - let ty::Alias(..) = ty.kind() else { return Ok(ty) }; + let ty::Alias(alias_ty) = ty.kind() else { return Ok(ty) }; if ty.has_escaping_bound_vars() { - let (ty, mapped_regions, mapped_types, mapped_consts) = - BoundVarReplacer::replace_bound_vars(infcx, &mut self.universes, ty); - let result = ensure_sufficient_stack(|| { - self.normalize_alias_term(ty.into(), HasEscapingBoundVars::Yes) - })? - .expect_ty(); - Ok(PlaceholderReplacer::replace_placeholders( + let (alias_ty, mapped_regions, mapped_types, mapped_consts) = + BoundVarReplacer::replace_bound_vars(infcx, &mut self.universes, alias_ty); + let normalized_term = ensure_sufficient_stack(|| { + self.normalize_alias_term(alias_ty.into(), HasEscapingBoundVars::Yes) + })?; + let normalized_ty = PlaceholderReplacer::replace_placeholders( infcx, mapped_regions, mapped_types, mapped_consts, &self.universes, - result, - )) + normalized_term.expect_ty(), + ); + Ok(normalized_ty) } else { Ok(ensure_sufficient_stack(|| { - self.normalize_alias_term(ty.into(), HasEscapingBoundVars::No) + self.normalize_alias_term(alias_ty.into(), HasEscapingBoundVars::No) })? .expect_ty()) } @@ -215,13 +214,16 @@ where // With eager normalization, we should normalize the args of alias before // normalizing the alias itself. let ct = ct.try_super_fold_with(self)?; - let ty::ConstKind::Unevaluated(..) = ct.kind() else { return Ok(ct) }; + let ty::ConstKind::Unevaluated(uv) = ct.kind() else { return Ok(ct) }; if ct.has_escaping_bound_vars() { - let (ct, mapped_regions, mapped_types, mapped_consts) = - BoundVarReplacer::replace_bound_vars(infcx, &mut self.universes, ct); + let (uv, mapped_regions, mapped_types, mapped_consts) = + BoundVarReplacer::replace_bound_vars(infcx, &mut self.universes, uv); let result = ensure_sufficient_stack(|| { - self.normalize_alias_term(ct.into(), HasEscapingBoundVars::Yes) + self.normalize_alias_term( + AliasTerm::from_unevaluated_const(infcx.cx(), uv), + HasEscapingBoundVars::Yes, + ) })? .expect_const(); Ok(PlaceholderReplacer::replace_placeholders( @@ -234,9 +236,16 @@ where )) } else { Ok(ensure_sufficient_stack(|| { - self.normalize_alias_term(ct.into(), HasEscapingBoundVars::No) + self.normalize_alias_term( + AliasTerm::from_unevaluated_const(infcx.cx(), uv), + HasEscapingBoundVars::No, + ) })? .expect_const()) } } + + fn try_fold_predicate(&mut self, p: I::Predicate) -> Result { + if p.allow_normalization() { p.try_super_fold_with(self) } else { Ok(p) } + } } diff --git a/compiler/rustc_next_trait_solver/src/solve/alias_relate.rs b/compiler/rustc_next_trait_solver/src/solve/alias_relate.rs index 47d33985f9d36..1101c8c1b075d 100644 --- a/compiler/rustc_next_trait_solver/src/solve/alias_relate.rs +++ b/compiler/rustc_next_trait_solver/src/solve/alias_relate.rs @@ -53,7 +53,7 @@ where self.add_goal( GoalSource::TypeRelating, goal.with(cx, ty::NormalizesTo { alias, term }), - ); + )?; term } else { lhs @@ -65,7 +65,7 @@ where self.add_goal( GoalSource::TypeRelating, goal.with(cx, ty::NormalizesTo { alias, term }), - ); + )?; term } else { rhs diff --git a/compiler/rustc_next_trait_solver/src/solve/assembly/mod.rs b/compiler/rustc_next_trait_solver/src/solve/assembly/mod.rs index 7f3627c6db54e..f58e20d6cccdc 100644 --- a/compiler/rustc_next_trait_solver/src/solve/assembly/mod.rs +++ b/compiler/rustc_next_trait_solver/src/solve/assembly/mod.rs @@ -68,7 +68,7 @@ where ) -> Result, NoSolutionOrRerunNonErased> { Self::probe_and_match_goal_against_assumption(ecx, parent_source, goal, assumption, |ecx| { for (nested_source, goal) in requirements { - ecx.add_goal(nested_source, goal); + ecx.add_goal(nested_source, goal)?; } ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes) }) @@ -113,7 +113,7 @@ where bounds, ) { Ok(requirements) => { - ecx.add_goals(GoalSource::ImplWhereBound, requirements); + ecx.add_goals(GoalSource::ImplWhereBound, requirements)?; ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes) } Err(_) => { @@ -966,7 +966,7 @@ where elaborate::elaborate(cx, [predicate]) .skip(1) .map(|predicate| goal.with(cx, predicate)), - ); + )?; ecx.evaluate_added_goals_and_make_canonical_response(Certainty::AMBIGUOUS) } }) diff --git a/compiler/rustc_next_trait_solver/src/solve/effect_goals.rs b/compiler/rustc_next_trait_solver/src/solve/effect_goals.rs index 0a260f97e5164..8575302df309e 100644 --- a/compiler/rustc_next_trait_solver/src/solve/effect_goals.rs +++ b/compiler/rustc_next_trait_solver/src/solve/effect_goals.rs @@ -117,7 +117,7 @@ where .skip_norm_wip(), ) }), - ); + )?; ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes) }, )); @@ -169,7 +169,7 @@ where .iter_instantiated(cx, impl_args) .map(Unnormalized::skip_norm_wip) .map(|pred| goal.with(cx, pred)); - ecx.add_goals(GoalSource::ImplWhereBound, where_clause_bounds); + ecx.add_goals(GoalSource::ImplWhereBound, where_clause_bounds)?; // For this impl to be `const`, we need to check its `[const]` bounds too. let const_conditions = cx @@ -183,7 +183,7 @@ where .skip_norm_wip(), ) }); - ecx.add_goals(GoalSource::ImplWhereBound, const_conditions); + ecx.add_goals(GoalSource::ImplWhereBound, const_conditions)?; then(ecx, certainty) }) @@ -234,8 +234,8 @@ where // `GoalSource::ImplWhereClause` here would be incorrect, as we also // impl them, which means we're "stepping out of the impl constructor" // again. To handle this, we treat these cycles as ambiguous for now. - ecx.add_goals(GoalSource::Misc, where_clause_bounds); - ecx.add_goals(GoalSource::Misc, const_conditions); + ecx.add_goals(GoalSource::Misc, where_clause_bounds)?; + ecx.add_goals(GoalSource::Misc, const_conditions)?; ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes) }) } @@ -270,8 +270,8 @@ where ), ) }), - ); - }); + ) + })?; ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes) }) @@ -424,7 +424,7 @@ where .to_host_effect_clause(cx, goal.predicate.constness), ) }), - ); + )?; ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes) }) } 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 54d306466cf5b..3693a18f305f6 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 @@ -3,7 +3,7 @@ use std::ops::ControlFlow; #[cfg(feature = "nightly")] use rustc_macros::StableHash; -use rustc_type_ir::data_structures::{HashMap, HashSet}; +use rustc_type_ir::data_structures::HashSet; use rustc_type_ir::inherent::*; use rustc_type_ir::region_constraint::RegionConstraint; use rustc_type_ir::relate::Relate; @@ -15,9 +15,9 @@ use rustc_type_ir::solve::{ RerunNonErased, RerunReason, RerunResultExt, SmallCopyList, }; use rustc_type_ir::{ - self as ty, CanonicalVarValues, ClauseKind, InferCtxtLike, Interner, MayBeErased, - OpaqueTypeKey, PredicateKind, TypeFoldable, TypeFolder, TypeSuperFoldable, TypeSuperVisitable, - TypeVisitable, TypeVisitableExt, TypeVisitor, TypingMode, + self as ty, AliasRelationDirection, AliasTermKind, CanonicalVarValues, ClauseKind, + InferCtxtLike, Interner, MayBeErased, OpaqueTypeKey, PredicateKind, TypeFoldable, + TypeSuperVisitable, TypeVisitable, TypeVisitableExt, TypeVisitor, TypingMode, }; use tracing::{Level, debug, instrument, trace, warn}; @@ -28,6 +28,7 @@ use crate::canonical::{ }; use crate::coherence; use crate::delegate::SolverDelegate; +use crate::normalize::{NormalizationFolder, NormalizationWasAmbiguous}; use crate::placeholder::BoundVarReplacer; use crate::resolve::eager_resolve_vars; use crate::solve::search_graph::SearchGraph; @@ -1029,11 +1030,19 @@ where } #[instrument(level = "debug", skip(self))] - pub(super) fn add_goal(&mut self, source: GoalSource, mut goal: Goal) { - goal.predicate = - goal.predicate.fold_with(&mut ReplaceAliasWithInfer::new(self, source, goal.param_env)); + pub(super) fn add_goal( + &mut self, + source: GoalSource, + mut goal: Goal, + ) -> Result<(), NoSolutionOrRerunNonErased> { + goal.predicate = self.normalize( + GoalSource::NormalizeGoal(self.step_kind_for_source(source)), + goal.param_env, + goal.predicate, + )?; self.inspect.add_goal(self.delegate, self.max_input_universe, source, goal); self.nested_goals.push((source, goal, None)); + Ok(()) } #[instrument(level = "trace", skip(self, goals))] @@ -1041,10 +1050,11 @@ where &mut self, source: GoalSource, goals: impl IntoIterator>, - ) { + ) -> Result<(), NoSolutionOrRerunNonErased> { for goal in goals { - self.add_goal(source, goal); + self.add_goal(source, goal)?; } + Ok(()) } pub(super) fn next_region_var(&mut self) -> I::Region { @@ -1074,6 +1084,19 @@ where } } + pub(super) fn next_infer_for_alias(&mut self, alias: ty::AliasTerm) -> I::Term { + match alias.kind(self.cx()) { + AliasTermKind::ProjectionTy { .. } + | AliasTermKind::InherentTy { .. } + | AliasTermKind::OpaqueTy { .. } + | AliasTermKind::FreeTy { .. } => self.next_ty_infer().into(), + AliasTermKind::UnevaluatedConst { .. } + | AliasTermKind::ProjectionConst { .. } + | AliasTermKind::FreeConst { .. } + | AliasTermKind::InherentConst { .. } => self.next_const_infer().into(), + } + } + /// 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 @@ -1207,7 +1230,7 @@ where param_env: I::ParamEnv, lhs: T, rhs: T, - ) -> Result<(), NoSolution> { + ) -> Result<(), NoSolutionOrRerunNonErased> { self.relate(param_env, lhs, ty::Variance::Invariant, rhs) } @@ -1223,7 +1246,7 @@ where alias: ty::AliasTerm, variance: ty::Variance, term: I::Term, - ) -> Result<(), NoSolution> { + ) -> Result<(), NoSolutionOrRerunNonErased> { // NOTE: this check is purely an optimization, the structural eq would // always fail if the term is not an inference variable. if term.is_infer() { @@ -1248,7 +1271,7 @@ where debug_assert!(obligations.is_empty()); self.relate(param_env, alias, variance, rigid_ctor) } else { - Err(NoSolution) + Err(NoSolutionOrRerunNonErased::NoSolution(NoSolution)) } } @@ -1261,7 +1284,7 @@ where param_env: I::ParamEnv, lhs: T, rhs: T, - ) -> Result<(), NoSolution> { + ) -> Result<(), NoSolutionOrRerunNonErased> { let result = self.delegate.eq_structurally_relating_aliases( param_env, lhs, @@ -1278,7 +1301,7 @@ where param_env: I::ParamEnv, sub: T, sup: T, - ) -> Result<(), NoSolution> { + ) -> Result<(), NoSolutionOrRerunNonErased> { self.relate(param_env, sub, ty::Variance::Covariant, sup) } @@ -1289,7 +1312,7 @@ where lhs: T, variance: ty::Variance, rhs: T, - ) -> Result<(), NoSolution> { + ) -> Result<(), NoSolutionOrRerunNonErased> { let goals = self.delegate.relate(param_env, lhs, variance, rhs, self.origin_span)?; for &goal in goals.iter() { let source = match goal.predicate.kind().skip_binder() { @@ -1300,7 +1323,7 @@ where ty::PredicateKind::Clause(ty::ClauseKind::WellFormed(_)) => GoalSource::Misc, p => unreachable!("unexpected nested goal in `relate`: {p:?}"), }; - self.add_goal(source, goal); + self.add_goal(source, goal)?; } Ok(()) } @@ -1441,7 +1464,7 @@ where opaque_args: I::GenericArgs, param_env: I::ParamEnv, hidden_ty: I::Ty, - ) { + ) -> Result<(), NoSolutionOrRerunNonErased> { let mut goals = Vec::new(); self.delegate.add_item_bounds_for_hidden_type( opaque_def_id, @@ -1450,7 +1473,8 @@ where hidden_ty, &mut goals, ); - self.add_goals(GoalSource::AliasWellFormed, goals); + self.add_goals(GoalSource::AliasWellFormed, goals)?; + Ok(()) } // Try to evaluate a const, or return `None` if the const is too generic. @@ -1731,112 +1755,38 @@ where ExternalConstraintsData { region_constraints, opaque_types, normalization_nested_goals } } -} - -/// Eagerly replace aliases with inference variables, emitting `AliasRelate` -/// goals, used when adding goals to the `EvalCtxt`. We compute the -/// `AliasRelate` goals before evaluating the actual goal to get all the -/// constraints we can. -/// -/// This is a performance optimization to more eagerly detect cycles during trait -/// solving. See tests/ui/traits/next-solver/cycles/cycle-modulo-ambig-aliases.rs. -/// -/// The emitted goals get evaluated in the context of the parent goal; by -/// replacing aliases in nested goals we essentially pull the normalization out of -/// the nested goal. We want to treat the goal as if the normalization still happens -/// inside of the nested goal by inheriting the `step_kind` of the nested goal and -/// storing it in the `GoalSource` of the emitted `AliasRelate` goals. -/// This is necessary for tests/ui/sized/coinductive-1.rs to compile. -struct ReplaceAliasWithInfer<'me, 'a, D, I> -where - D: SolverDelegate, - I: Interner, -{ - ecx: &'me mut EvalCtxt<'a, D>, - param_env: I::ParamEnv, - normalization_goal_source: GoalSource, - cache: HashMap, -} -impl<'me, 'a, D, I> ReplaceAliasWithInfer<'me, 'a, D, I> -where - D: SolverDelegate, - I: Interner, -{ - fn new( - ecx: &'me mut EvalCtxt<'a, D>, - for_goal_source: GoalSource, + fn normalize>( + &mut self, + source: GoalSource, param_env: I::ParamEnv, - ) -> Self { - let step_kind = ecx.step_kind_for_source(for_goal_source); - ReplaceAliasWithInfer { - ecx, - param_env, - normalization_goal_source: GoalSource::NormalizeGoal(step_kind), - cache: Default::default(), - } - } -} - -impl TypeFolder for ReplaceAliasWithInfer<'_, '_, D, I> -where - D: SolverDelegate, - I: Interner, -{ - fn cx(&self) -> I { - self.ecx.cx() - } - - fn fold_ty(&mut self, ty: I::Ty) -> I::Ty { - match ty.kind() { - ty::Alias(..) if !ty.has_escaping_bound_vars() => { - let infer_ty = self.ecx.next_ty_infer(); - let normalizes_to = ty::PredicateKind::AliasRelate( - ty.into(), - infer_ty.into(), - ty::AliasRelationDirection::Equate, - ); - self.ecx.add_goal( - self.normalization_goal_source, - Goal::new(self.cx(), self.param_env, normalizes_to), - ); - infer_ty - } - _ => { - if !ty.has_aliases() { - ty - } else if let Some(&entry) = self.cache.get(&ty) { - return entry; - } else { - let res = ty.super_fold_with(self); - assert!(self.cache.insert(ty, res).is_none()); - res + value: T, + ) -> Result { + let value = self.delegate.resolve_vars_if_possible(value); + // To drop the mutable borrow of self early. + let infcx = self.delegate.deref(); + let mut folder = NormalizationFolder::new(infcx, vec![], |alias_term| { + let infer_term = self.next_infer_for_alias(alias_term); + let pred = ty::PredicateKind::AliasRelate( + alias_term.to_term(infcx.cx()), + infer_term.into(), + AliasRelationDirection::Equate, + ); + let goal = Goal::new(self.cx(), param_env, pred); + self.inspect.add_goal(self.delegate, self.max_input_universe, source, goal); + let GoalEvaluation { goal, certainty, has_changed: _, stalled_on } = + self.evaluate_goal(source, goal, None)?; + let normalization_was_ambiguous = match certainty { + Certainty::Yes => NormalizationWasAmbiguous::No, + Certainty::Maybe(_) => { + self.nested_goals.push((source, goal, stalled_on)); + NormalizationWasAmbiguous::Yes } - } - } - } - - fn fold_const(&mut self, ct: I::Const) -> I::Const { - match ct.kind() { - ty::ConstKind::Unevaluated(..) if !ct.has_escaping_bound_vars() => { - let infer_ct = self.ecx.next_const_infer(); - let normalizes_to = ty::PredicateKind::AliasRelate( - ct.into(), - infer_ct.into(), - ty::AliasRelationDirection::Equate, - ); - self.ecx.add_goal( - self.normalization_goal_source, - Goal::new(self.cx(), self.param_env, normalizes_to), - ); - infer_ct - } - _ => ct.super_fold_with(self), - } - } + }; - fn fold_predicate(&mut self, predicate: I::Predicate) -> I::Predicate { - if predicate.allow_normalization() { predicate.super_fold_with(self) } else { predicate } + Ok((self.resolve_vars_if_possible(infer_term), normalization_was_ambiguous)) + }); + value.try_fold_with(&mut folder) } } diff --git a/compiler/rustc_next_trait_solver/src/solve/mod.rs b/compiler/rustc_next_trait_solver/src/solve/mod.rs index fbd6bdfa0a989..ccfc16403d066 100644 --- a/compiler/rustc_next_trait_solver/src/solve/mod.rs +++ b/compiler/rustc_next_trait_solver/src/solve/mod.rs @@ -171,7 +171,7 @@ where ) -> QueryResultOrRerunNonErased { match self.well_formed_goals(goal.param_env, goal.predicate) { Some(goals) => { - self.add_goals(GoalSource::Misc, goals); + self.add_goals(GoalSource::Misc, goals)?; self.evaluate_added_goals_and_make_canonical_response(Certainty::Yes) } None => self.evaluate_added_goals_and_make_canonical_response(Certainty::AMBIGUOUS), @@ -381,7 +381,7 @@ where ); // We normalize the self type to be able to relate it with // types from candidates. - self.add_goal(GoalSource::TypeRelating, alias_relate_goal); + self.add_goal(GoalSource::TypeRelating, alias_relate_goal)?; self.try_evaluate_added_goals()?; Ok(self.resolve_vars_if_possible(normalized_term)) } else { diff --git a/compiler/rustc_next_trait_solver/src/solve/normalizes_to/free_alias.rs b/compiler/rustc_next_trait_solver/src/solve/normalizes_to/free_alias.rs index d68c7dd11d1d9..147626ec2b2c1 100644 --- a/compiler/rustc_next_trait_solver/src/solve/normalizes_to/free_alias.rs +++ b/compiler/rustc_next_trait_solver/src/solve/normalizes_to/free_alias.rs @@ -29,7 +29,7 @@ where .iter_instantiated(cx, free_alias.args) .map(Unnormalized::skip_norm_wip) .map(|pred| goal.with(cx, pred)), - ); + )?; let actual = match free_alias.kind(cx) { ty::AliasTermKind::FreeTy { def_id } => { diff --git a/compiler/rustc_next_trait_solver/src/solve/normalizes_to/inherent.rs b/compiler/rustc_next_trait_solver/src/solve/normalizes_to/inherent.rs index 2f44cc42a5d71..149b24264ce49 100644 --- a/compiler/rustc_next_trait_solver/src/solve/normalizes_to/inherent.rs +++ b/compiler/rustc_next_trait_solver/src/solve/normalizes_to/inherent.rs @@ -52,7 +52,7 @@ where .iter_instantiated(cx, inherent_args) .map(Unnormalized::skip_norm_wip) .map(|pred| goal.with(cx, pred)), - ); + )?; let normalized = match inherent.kind(cx) { ty::AliasTermKind::InherentTy { def_id } => { 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 e9a4d7e5919ad..54b71c2d8f3ae 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 @@ -202,7 +202,7 @@ where .iter_instantiated(cx, goal.predicate.alias.args) .map(Unnormalized::skip_norm_wip) .map(|pred| goal.with(cx, pred)), - ); + )?; then(ecx) } @@ -267,7 +267,7 @@ where .iter_instantiated(cx, impl_args) .map(Unnormalized::skip_norm_wip) .map(|pred| goal.with(cx, pred)); - ecx.add_goals(GoalSource::ImplWhereBound, where_clause_bounds); + ecx.add_goals(GoalSource::ImplWhereBound, where_clause_bounds)?; // Bail if the nested goals don't hold here. This is to avoid unnecessarily // computing the `type_of` query for associated types that never apply, as @@ -284,7 +284,7 @@ where .iter_instantiated(cx, goal.predicate.alias.args) .map(Unnormalized::skip_norm_wip) .map(|pred| goal.with(cx, pred)), - ); + )?; let error_response = |ecx: &mut EvalCtxt<'_, D>, guar| { let error_term = match goal.predicate.alias.kind(cx) { @@ -316,7 +316,10 @@ where // This is not the case here and we only prefer adding an ambiguous // nested goal for consistency. ty::TypingMode::Coherence => { - ecx.add_goal(GoalSource::Misc, goal.with(cx, PredicateKind::Ambiguous)); + ecx.add_goal( + GoalSource::Misc, + goal.with(cx, PredicateKind::Ambiguous), + )?; return ecx .evaluate_added_goals_and_make_canonical_response(Certainty::Yes) .map_err(Into::into); @@ -361,7 +364,7 @@ where // would be relevant if any of the nested goals refer to the `term`. // This is not the case here and we only prefer adding an ambiguous // nested goal for consistency. - ecx.add_goal(GoalSource::Misc, goal.with(cx, PredicateKind::Ambiguous)); + ecx.add_goal(GoalSource::Misc, goal.with(cx, PredicateKind::Ambiguous))?; return then(ecx, Certainty::Yes).map_err(Into::into); } else { ecx.structurally_instantiate_normalizes_to_term(goal, goal.predicate.alias); @@ -705,7 +708,7 @@ where cx.require_trait_lang_item(SolverTraitLangItem::Sized), [I::GenericArg::from(goal.predicate.self_ty())], ); - ecx.add_goal(GoalSource::Misc, goal.with(cx, sized_predicate)); + ecx.add_goal(GoalSource::Misc, goal.with(cx, sized_predicate))?; ecx.instantiate_normalizes_to_term(goal, Ty::new_unit(cx).into()); ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes) }); @@ -1047,7 +1050,7 @@ where impl_args: I::GenericArgs, impl_trait_ref: rustc_type_ir::TraitRef, target_container_def_id: I::DefId, - ) -> Result { + ) -> Result { let cx = self.cx(); Ok(if target_container_def_id == impl_trait_ref.def_id.into() { // Default value from the trait definition. No need to rebase. @@ -1072,7 +1075,7 @@ where .iter_instantiated(cx, target_args) .map(Unnormalized::skip_norm_wip) .map(|pred| goal.with(cx, pred)), - ); + )?; goal.predicate.alias.args.rebase_onto(cx, impl_trait_ref.def_id.into(), target_args) }) } diff --git a/compiler/rustc_next_trait_solver/src/solve/normalizes_to/opaque_types.rs b/compiler/rustc_next_trait_solver/src/solve/normalizes_to/opaque_types.rs index 57d10b4ac1fe1..951584d5becde 100644 --- a/compiler/rustc_next_trait_solver/src/solve/normalizes_to/opaque_types.rs +++ b/compiler/rustc_next_trait_solver/src/solve/normalizes_to/opaque_types.rs @@ -32,12 +32,12 @@ where opaque_ty.args, goal.param_env, expected, - ); + )?; // Trying to normalize an opaque type during coherence is always ambiguous. // We add a nested ambiguous goal here instead of using `Certainty::AMBIGUOUS`. // This allows us to return the nested goals to the parent `AliasRelate` goal. // This can then allow nested goals to fail after we've constrained the `term`. - self.add_goal(GoalSource::Misc, goal.with(cx, ty::PredicateKind::Ambiguous)); + self.add_goal(GoalSource::Misc, goal.with(cx, ty::PredicateKind::Ambiguous))?; self.evaluate_added_goals_and_make_canonical_response(Certainty::Yes) .map_err(Into::into) } @@ -109,7 +109,7 @@ where normalized_args, goal.param_env, expected, - ); + )?; self.evaluate_added_goals_and_make_canonical_response(Certainty::Yes) .map_err(Into::into) } diff --git a/compiler/rustc_next_trait_solver/src/solve/project_goals.rs b/compiler/rustc_next_trait_solver/src/solve/project_goals.rs index af6d0aad25597..7a70e7d29005c 100644 --- a/compiler/rustc_next_trait_solver/src/solve/project_goals.rs +++ b/compiler/rustc_next_trait_solver/src/solve/project_goals.rs @@ -26,7 +26,7 @@ where ), ); // A projection goal holds if the alias is equal to the expected term. - self.add_goal(GoalSource::TypeRelating, goal); + self.add_goal(GoalSource::TypeRelating, goal)?; self.evaluate_added_goals_and_make_canonical_response(Certainty::Yes) } } diff --git a/compiler/rustc_next_trait_solver/src/solve/trait_goals.rs b/compiler/rustc_next_trait_solver/src/solve/trait_goals.rs index f3ace5a70c69c..a9b042bae313e 100644 --- a/compiler/rustc_next_trait_solver/src/solve/trait_goals.rs +++ b/compiler/rustc_next_trait_solver/src/solve/trait_goals.rs @@ -106,7 +106,7 @@ where .iter_instantiated(cx, impl_args) .map(Unnormalized::skip_norm_wip) .map(|pred| goal.with(cx, pred)); - ecx.add_goals(GoalSource::ImplWhereBound, where_clause_bounds); + ecx.add_goals(GoalSource::ImplWhereBound, where_clause_bounds)?; // We currently elaborate all supertrait outlives obligations from impls. // This can be removed when we actually do coinduction correctly, and prove @@ -117,7 +117,7 @@ where .iter_instantiated(cx, impl_args) .map(Unnormalized::skip_norm_wip) .map(|pred| goal.with(cx, pred)), - ); + )?; then(ecx, maximal_certainty).map_err(Into::into) }) @@ -286,7 +286,7 @@ where // `GoalSource::ImplWhereClause` here would be incorrect, as we also // impl them, which means we're "stepping out of the impl constructor" // again. To handle this, we treat these cycles as ambiguous for now. - ecx.add_goals(GoalSource::Misc, nested_obligations); + ecx.add_goals(GoalSource::Misc, nested_obligations)?; ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes) }) } @@ -736,13 +736,13 @@ where tys.iter().map(|elem_ty| { goal.with(cx, ty::TraitRef::new(cx, goal.predicate.def_id(), [elem_ty])) }), - ); + )?; } ty::Array(elem_ty, _) => { ecx.add_goal( GoalSource::ImplWhereBound, goal.with(cx, ty::TraitRef::new(cx, goal.predicate.def_id(), [elem_ty])), - ); + )?; } // All other types implement `BikeshedGuaranteedNoDrop` only if @@ -783,7 +783,7 @@ where [ty], ), ), - ); + )?; } ty::Bound(..) @@ -865,6 +865,8 @@ where } } + // FIXME(field_projections): This function does some questionable incomplete stuff by + // returning `Err(NoSolution)` on ambiguity. fn consider_builtin_field_candidate( ecx: &mut EvalCtxt<'_, D>, goal: Goal, @@ -890,14 +892,14 @@ where param_env: goal.param_env, predicate: TraitRef::new(ecx.cx(), sized_trait, [base]).upcast(ecx.cx()), }, - ); + )?; ecx.add_goal( GoalSource::ImplWhereBound, Goal { param_env: goal.param_env, predicate: TraitRef::new(ecx.cx(), sized_trait, [ty]).upcast(ecx.cx()), }, - ); + )?; ecx.try_evaluate_added_goals()? == Certainty::Yes } && match base.kind() { @@ -1015,7 +1017,7 @@ where ecx.add_goals( GoalSource::ImplWhereBound, b_data.iter().map(|pred| goal.with(cx, pred.with_self_ty(cx, a_ty))), - ); + )?; // The type must be `Sized` to be unsized. ecx.add_goal( @@ -1028,10 +1030,10 @@ where [a_ty], ), ), - ); + )?; // The type must outlive the lifetime of the `dyn` we're unsizing into. - ecx.add_goal(GoalSource::Misc, goal.with(cx, ty::OutlivesPredicate(a_ty, b_region))); + ecx.add_goal(GoalSource::Misc, goal.with(cx, ty::OutlivesPredicate(a_ty, b_region)))?; ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes) }) } @@ -1151,7 +1153,7 @@ where ecx.add_goal( GoalSource::ImplWhereBound, Goal::new(ecx.cx(), param_env, ty::OutlivesPredicate(a_region, b_region)), - ); + )?; ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes).map_err(Into::into) }) @@ -1232,7 +1234,7 @@ where [a_tail_ty, b_tail_ty], ), ), - ); + )?; self.probe_builtin_trait_candidate(BuiltinImplSource::Misc) .enter(|ecx| ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)) } @@ -1372,7 +1374,7 @@ where .collect::>() }, ); - ecx.add_goals(GoalSource::ImplWhereBound, goals); + ecx.add_goals(GoalSource::ImplWhereBound, goals)?; ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes) }) } diff --git a/compiler/rustc_trait_selection/src/solve/fulfill.rs b/compiler/rustc_trait_selection/src/solve/fulfill.rs index ed345d98b5392..6f4bb4e1f1f0e 100644 --- a/compiler/rustc_trait_selection/src/solve/fulfill.rs +++ b/compiler/rustc_trait_selection/src/solve/fulfill.rs @@ -6,7 +6,7 @@ use rustc_infer::traits::query::NoSolution; use rustc_infer::traits::{ FromSolverError, PredicateObligation, PredicateObligations, TraitEngine, }; -use rustc_middle::ty::{TyCtxt, TypeVisitableExt, TypingMode}; +use rustc_middle::ty::{self, TyCtxt, TypeVisitableExt, TypingMode}; use rustc_next_trait_solver::delegate::SolverDelegate as _; use rustc_next_trait_solver::solve::{ GoalEvaluation, GoalStalledOn, HasChanged, MaybeInfo, SolverDelegateEvalExt as _, @@ -18,7 +18,7 @@ use tracing::instrument; use self::derive_errors::*; use super::Certainty; use super::delegate::SolverDelegate; -use crate::traits::{FulfillmentError, ScrubbedTraitError}; +use crate::traits::{FulfillmentError, ObligationCtxt, ScrubbedTraitError}; mod derive_errors; @@ -151,9 +151,16 @@ where fn register_predicate_obligation( &mut self, infcx: &InferCtxt<'tcx>, - obligation: PredicateObligation<'tcx>, + mut obligation: PredicateObligation<'tcx>, ) { assert_eq!(self.usable_in_snapshot, infcx.num_open_snapshots()); + let ocx = ObligationCtxt::new(infcx); + obligation.predicate = ocx.normalize( + &obligation.cause, + obligation.param_env, + ty::Unnormalized::new_wip(obligation.predicate), + ); + self.register_predicate_obligations(infcx, ocx.into_pending_obligations()); self.obligations.register(obligation, None); } diff --git a/compiler/rustc_trait_selection/src/solve/normalize.rs b/compiler/rustc_trait_selection/src/solve/normalize.rs index 7c21dc161a1ec..e25a7e8319491 100644 --- a/compiler/rustc_trait_selection/src/solve/normalize.rs +++ b/compiler/rustc_trait_selection/src/solve/normalize.rs @@ -6,11 +6,11 @@ use rustc_infer::traits::{ }; use rustc_middle::traits::ObligationCause; use rustc_middle::ty::{ - self, Binder, Flags, Ty, TyCtxt, TypeFoldable, TypeFolder, TypeSuperFoldable, TypeVisitableExt, - UniverseIndex, Unnormalized, + self, AliasTerm, Binder, Flags, Ty, TyCtxt, TypeFoldable, TypeFolder, TypeSuperFoldable, + TypeVisitableExt, UniverseIndex, Unnormalized, }; -use rustc_next_trait_solver::normalize::NormalizationFolder; -use rustc_next_trait_solver::solve::SolverDelegateEvalExt; +use rustc_next_trait_solver::normalize::{NormalizationFolder, NormalizationWasAmbiguous}; +use rustc_next_trait_solver::solve::{NoSolution, SolverDelegateEvalExt}; use super::{FulfillmentCtxt, NextSolverError}; use crate::solve::{Certainty, SolverDelegate}; @@ -43,37 +43,47 @@ where let value = value.skip_normalization(); let value = infcx.resolve_vars_if_possible(value); let original_value = value.clone(); - let mut folder = - NormalizationFolder::new(infcx, universes.clone(), Default::default(), |alias_term| { - let delegate = <&SolverDelegate<'tcx>>::from(infcx); - let infer_term = delegate.next_term_var_of_kind(alias_term, at.cause.span); - let predicate = ty::PredicateKind::AliasRelate( - alias_term.into(), - infer_term.into(), - ty::AliasRelationDirection::Equate, - ); - let goal = Goal::new(infcx.tcx, at.param_env, predicate); - let result = delegate.evaluate_root_goal(goal, at.cause.span, None)?; - let normalized = infcx.resolve_vars_if_possible(infer_term); - let stalled_goal = match result.certainty { - Certainty::Yes => None, - Certainty::Maybe { .. } => Some(infcx.resolve_vars_if_possible(result.goal)), - }; - Ok((normalized, stalled_goal)) - }); - if let Ok(value) = value.try_fold_with(&mut folder) { - let obligations = folder - .stalled_goals() - .into_iter() - .map(|goal| { - Obligation::new(infcx.tcx, at.cause.clone(), goal.param_env, goal.predicate) - }) - .collect(); - Normalized { value, obligations } - } else { - let mut replacer = ReplaceAliasWithInfer { at, obligations: Default::default(), universes }; - let value = original_value.fold_with(&mut replacer); - Normalized { value, obligations: replacer.obligations } + let mut stalled_goals = vec![]; + let mut folder = NormalizationFolder::new(infcx, universes.clone(), |alias_term| { + let delegate = <&SolverDelegate<'tcx>>::from(infcx); + let infer_term = delegate.next_term_var_for_alias(alias_term, at.cause.span); + let predicate = ty::PredicateKind::AliasRelate( + alias_term.to_term(infcx.tcx), + infer_term.into(), + ty::AliasRelationDirection::Equate, + ); + let goal = Goal::new(infcx.tcx, at.param_env, predicate); + let result = match delegate.evaluate_root_goal(goal, at.cause.span, None) { + Ok(result) => result, + Err(err) => return Err(err), + }; + let normalized = infcx.resolve_vars_if_possible(infer_term); + let normalization_was_ambiguous = match result.certainty { + Certainty::Yes => NormalizationWasAmbiguous::No, + Certainty::Maybe { .. } => { + stalled_goals.push(infcx.resolve_vars_if_possible(goal)); + NormalizationWasAmbiguous::Yes + } + }; + Ok((normalized, normalization_was_ambiguous)) + }); + + match value.try_fold_with(&mut folder) { + Ok(value) => { + let obligations = stalled_goals + .into_iter() + .map(|goal| { + Obligation::new(infcx.tcx, at.cause.clone(), goal.param_env, goal.predicate) + }) + .collect(); + Normalized { value, obligations } + } + Err(NoSolution) => { + let mut replacer = + ReplaceAliasWithInfer { at, obligations: Default::default(), universes }; + let value = original_value.fold_with(&mut replacer); + Normalized { value, obligations: replacer.obligations } + } } } @@ -84,15 +94,15 @@ struct ReplaceAliasWithInfer<'me, 'tcx> { } impl<'me, 'tcx> ReplaceAliasWithInfer<'me, 'tcx> { - fn term_to_infer(&mut self, alias_term: ty::Term<'tcx>) -> ty::Term<'tcx> { + fn alias_term_to_infer(&mut self, alias_term: ty::AliasTerm<'tcx>) -> ty::Term<'tcx> { let infcx = self.at.infcx; - let infer_term = infcx.next_term_var_of_kind(alias_term, self.at.cause.span); + let infer_term = infcx.next_term_var_for_alias(alias_term, self.at.cause.span); let obligation = Obligation::new( infcx.tcx, self.at.cause.clone(), self.at.param_env, ty::PredicateKind::AliasRelate( - alias_term.into(), + alias_term.to_term(infcx.tcx), infer_term.into(), ty::AliasRelationDirection::Equate, ), @@ -123,15 +133,14 @@ impl<'me, 'tcx> TypeFolder> for ReplaceAliasWithInfer<'me, 'tcx> { } let ty = ty.super_fold_with(self); - let ty::Alias(..) = *ty.kind() else { return ty }; - - if ty.has_escaping_bound_vars() { + let ty::Alias(alias_ty) = *ty.kind() else { return ty }; + if alias_ty.has_escaping_bound_vars() { let (replaced, ..) = - BoundVarReplacer::replace_bound_vars(self.at.infcx, &mut self.universes, ty); - let _ = self.term_to_infer(replaced.into()); + BoundVarReplacer::replace_bound_vars(self.at.infcx, &mut self.universes, alias_ty); + let _ = self.alias_term_to_infer(replaced.into()); ty } else { - self.term_to_infer(ty.into()).expect_type() + self.alias_term_to_infer(alias_ty.into()).expect_type() } } @@ -141,17 +150,23 @@ impl<'me, 'tcx> TypeFolder> for ReplaceAliasWithInfer<'me, 'tcx> { } let ct = ct.super_fold_with(self); - let ty::ConstKind::Unevaluated(..) = ct.kind() else { return ct }; + let ty::ConstKind::Unevaluated(uv) = ct.kind() else { return ct }; if ct.has_escaping_bound_vars() { let (replaced, ..) = - BoundVarReplacer::replace_bound_vars(self.at.infcx, &mut self.universes, ct); - let _ = self.term_to_infer(replaced.into()); + BoundVarReplacer::replace_bound_vars(self.at.infcx, &mut self.universes, uv); + let _ = + self.alias_term_to_infer(AliasTerm::from_unevaluated_const(self.cx(), replaced)); ct } else { - self.term_to_infer(ct.into()).expect_const() + self.alias_term_to_infer(AliasTerm::from_unevaluated_const(self.cx(), uv)) + .expect_const() } } + + fn fold_predicate(&mut self, p: ty::Predicate<'tcx>) -> ty::Predicate<'tcx> { + if p.allow_normalization() { p.super_fold_with(self) } else { p } + } } /// Deeply normalize all aliases in `value`. This does not handle inference and expects @@ -285,4 +300,8 @@ impl<'tcx> TypeFolder> for DeeplyNormalizeForDiagnosticsFolder<'_, Err(_) => ct.super_fold_with(self), } } + + fn fold_predicate(&mut self, p: ty::Predicate<'tcx>) -> ty::Predicate<'tcx> { + if p.allow_normalization() { p.super_fold_with(self) } else { p } + } } diff --git a/compiler/rustc_type_ir/src/error.rs b/compiler/rustc_type_ir/src/error.rs index 15fbd985d9630..6af014fbfb874 100644 --- a/compiler/rustc_type_ir/src/error.rs +++ b/compiler/rustc_type_ir/src/error.rs @@ -2,7 +2,7 @@ use derive_where::derive_where; use rustc_abi::ExternAbi; use rustc_type_ir_macros::{GenericTypeVisitable, TypeFoldable_Generic, TypeVisitable_Generic}; -use crate::solve::NoSolution; +use crate::solve::{NoSolution, NoSolutionOrRerunNonErased}; use crate::{self as ty, Interner}; #[derive(Clone, Copy, Debug, PartialEq, Eq)] @@ -100,3 +100,9 @@ impl From> for NoSolution { NoSolution } } + +impl From> for NoSolutionOrRerunNonErased { + fn from(_: TypeError) -> NoSolutionOrRerunNonErased { + NoSolutionOrRerunNonErased::NoSolution(NoSolution) + } +} diff --git a/tests/ui/const-generics/gca/ambiguous-on-failed-eval-with-vars-fail.next.stderr b/tests/ui/const-generics/gca/ambiguous-on-failed-eval-with-vars-fail.next.stderr index f609dcab752af..e14b7a110e436 100644 --- a/tests/ui/const-generics/gca/ambiguous-on-failed-eval-with-vars-fail.next.stderr +++ b/tests/ui/const-generics/gca/ambiguous-on-failed-eval-with-vars-fail.next.stderr @@ -14,7 +14,7 @@ help: consider giving this pattern a type, where the value of const parameter `N LL | let (mut arr, mut arr_with_weird_len): ([_; N], _) = free(); | +++++++++++++ -error[E0271]: type mismatch resolving `10 == 2` +error[E0271]: type mismatch resolving `FREE::<10> == 2` --> $DIR/ambiguous-on-failed-eval-with-vars-fail.rs:35:45 | LL | let (mut arr, mut arr_with_weird_len) = free(); @@ -36,11 +36,14 @@ help: consider giving this pattern a type, where the value of const parameter `N LL | let (mut arr, mut arr_with_weird_len): ([_; N], _) = proj(); | +++++++++++++ -error[E0271]: type mismatch resolving `10 == 2` +error[E0271]: type mismatch resolving `::PROJ::<10> == 2` --> $DIR/ambiguous-on-failed-eval-with-vars-fail.rs:52:45 | LL | let (mut arr, mut arr_with_weird_len) = proj(); - | ^^^^^^ types differ + | ^^^^^^ expected `2`, found `10` + | + = note: expected constant `2` + found constant `10` error: aborting due to 4 previous errors diff --git a/tests/ui/const-generics/gca/ambiguous-on-failed-eval-with-vars-fail.rs b/tests/ui/const-generics/gca/ambiguous-on-failed-eval-with-vars-fail.rs index 72952940b1c12..5acdd004472f7 100644 --- a/tests/ui/const-generics/gca/ambiguous-on-failed-eval-with-vars-fail.rs +++ b/tests/ui/const-generics/gca/ambiguous-on-failed-eval-with-vars-fail.rs @@ -33,7 +33,7 @@ fn test_free() { fn test_free_mismatch() { let (mut arr, mut arr_with_weird_len) = free(); - //[next]~^ ERROR type mismatch resolving `10 == 2` + //[next]~^ ERROR type mismatch resolving `FREE::<10> == 2` arr_with_weird_len = [(); 2]; arr = [(); 10]; } @@ -50,7 +50,7 @@ fn test_proj() { fn test_proj_mismatch() { let (mut arr, mut arr_with_weird_len) = proj(); - //[next]~^ ERROR type mismatch resolving `10 == 2` + //[next]~^ ERROR type mismatch resolving `::PROJ::<10> == 2` arr_with_weird_len = [(); 2]; arr = [(); 10]; } diff --git a/tests/ui/const-generics/generic_const_exprs/negative-coherence-ice-140609.rs b/tests/ui/const-generics/generic_const_exprs/negative-coherence-ice-140609.rs deleted file mode 100644 index 1b02b874ed898..0000000000000 --- a/tests/ui/const-generics/generic_const_exprs/negative-coherence-ice-140609.rs +++ /dev/null @@ -1,14 +0,0 @@ -//@ check-pass -#![feature(with_negative_coherence)] -#![feature(generic_const_exprs)] -#![allow(incomplete_features)] -#![crate_type = "lib"] -trait Trait {} -struct A; - -trait C {} - -impl Trait for E where A<{ D <= 2 }>: FnOnce(&isize) {} -struct E; - -impl Trait for E where A<{ D <= 2 }>: C {} diff --git a/tests/ui/const-generics/generic_const_exprs/specialization-fuzzing-ice-133639.rs b/tests/ui/const-generics/generic_const_exprs/specialization-fuzzing-ice-133639.rs deleted file mode 100644 index d605c83239b27..0000000000000 --- a/tests/ui/const-generics/generic_const_exprs/specialization-fuzzing-ice-133639.rs +++ /dev/null @@ -1,18 +0,0 @@ -//@ check-pass - -// Regression test for #133639. - -#![feature(with_negative_coherence)] -#![feature(min_specialization)] -#![feature(generic_const_exprs)] - -#![crate_type = "lib"] -trait Trait {} -struct A; - -trait C {} - -impl Trait for E where A<{ D <= 2 }>: C {} -struct E; - -impl Trait for E where A<{ D <= 2 }>: C {} diff --git a/tests/ui/const-generics/mgca/free-const-recursive.rs b/tests/ui/const-generics/mgca/free-const-recursive.rs index 8d75c1a941a77..0cbe848340516 100644 --- a/tests/ui/const-generics/mgca/free-const-recursive.rs +++ b/tests/ui/const-generics/mgca/free-const-recursive.rs @@ -6,7 +6,7 @@ type const A: () = A; //~^ ERROR type mismatch resolving `A normalizes-to _` -//~| ERROR the constant `A` is not of type `()` +//~| ERROR type mismatch resolving `A normalizes-to _` fn main() { A; diff --git a/tests/ui/const-generics/mgca/free-const-recursive.stderr b/tests/ui/const-generics/mgca/free-const-recursive.stderr index d0f10275b40d2..20bcd2dcc93f3 100644 --- a/tests/ui/const-generics/mgca/free-const-recursive.stderr +++ b/tests/ui/const-generics/mgca/free-const-recursive.stderr @@ -4,11 +4,13 @@ error[E0271]: type mismatch resolving `A normalizes-to _` LL | type const A: () = A; | ^^^^^^^^^^^^^^^^ types differ -error: the constant `A` is not of type `()` +error[E0271]: type mismatch resolving `A normalizes-to _` --> $DIR/free-const-recursive.rs:7:1 | LL | type const A: () = A; - | ^^^^^^^^^^^^^^^^ expected `()`, found a different `()` + | ^^^^^^^^^^^^^^^^ types differ + | + = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` error: aborting due to 2 previous errors diff --git a/tests/ui/const-generics/mgca/projection-const-recursive.rs b/tests/ui/const-generics/mgca/projection-const-recursive.rs index c9b5039b5fd0b..15112517249a8 100644 --- a/tests/ui/const-generics/mgca/projection-const-recursive.rs +++ b/tests/ui/const-generics/mgca/projection-const-recursive.rs @@ -1,6 +1,6 @@ //! See also //@ check-fail -//@compile-flags: -Znext-solver=globally --emit=obj +//@ compile-flags: -Znext-solver=globally --emit=obj #![feature(min_generic_const_args)] #![expect(incomplete_features)] @@ -11,7 +11,7 @@ trait Trait { impl Trait for () { type const A: () = <() as Trait>::A; //~^ ERROR type mismatch resolving `<() as Trait>::A normalizes-to _` - //~| ERROR the constant `<() as Trait>::A` is not of type `()` + //~| ERROR type mismatch resolving `<() as Trait>::A normalizes-to _` } fn main() { diff --git a/tests/ui/const-generics/mgca/projection-const-recursive.stderr b/tests/ui/const-generics/mgca/projection-const-recursive.stderr index d9c60102c3184..8bc5afc81f33c 100644 --- a/tests/ui/const-generics/mgca/projection-const-recursive.stderr +++ b/tests/ui/const-generics/mgca/projection-const-recursive.stderr @@ -4,11 +4,13 @@ error[E0271]: type mismatch resolving `<() as Trait>::A normalizes-to _` LL | type const A: () = <() as Trait>::A; | ^^^^^^^^^^^^^^^^ types differ -error: the constant `<() as Trait>::A` is not of type `()` +error[E0271]: type mismatch resolving `<() as Trait>::A normalizes-to _` --> $DIR/projection-const-recursive.rs:12:5 | LL | type const A: () = <() as Trait>::A; - | ^^^^^^^^^^^^^^^^ expected `()`, found a different `()` + | ^^^^^^^^^^^^^^^^ types differ + | + = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` error: aborting due to 2 previous errors diff --git a/tests/ui/coroutine/delayed-obligations-emit.next.stderr b/tests/ui/coroutine/delayed-obligations-emit.next.stderr index 3a3663398c9a7..af7dfc75963c2 100644 --- a/tests/ui/coroutine/delayed-obligations-emit.next.stderr +++ b/tests/ui/coroutine/delayed-obligations-emit.next.stderr @@ -4,6 +4,7 @@ error[E0275]: overflow evaluating the requirement `{async block@$DIR/delayed-obl 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 | diff --git a/tests/ui/higher-ranked/trait-bounds/rigid-equate-projections-in-higher-ranked-fn-signature.next.stderr b/tests/ui/higher-ranked/trait-bounds/rigid-equate-projections-in-higher-ranked-fn-signature.next.stderr index 31d74d1c022a1..26e682dfb7a7c 100644 --- a/tests/ui/higher-ranked/trait-bounds/rigid-equate-projections-in-higher-ranked-fn-signature.next.stderr +++ b/tests/ui/higher-ranked/trait-bounds/rigid-equate-projections-in-higher-ranked-fn-signature.next.stderr @@ -1,8 +1,8 @@ -error[E0284]: type annotations needed: cannot satisfy `for<'a> <_ as Trait<'a>>::Assoc normalizes-to >::Assoc` - --> $DIR/rigid-equate-projections-in-higher-ranked-fn-signature.rs:27:50 +error[E0284]: type annotations needed: cannot normalize `<_ as Trait<'a>>::Assoc` + --> $DIR/rigid-equate-projections-in-higher-ranked-fn-signature.rs:27:12 | LL | let _: for<'a> fn(<_ as Trait<'a>>::Assoc) = foo::(); - | ^^^^^^^^^^ cannot satisfy `for<'a> <_ as Trait<'a>>::Assoc normalizes-to >::Assoc` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ cannot normalize `<_ as Trait<'a>>::Assoc` error: aborting due to 1 previous error diff --git a/tests/ui/impl-trait/in-trait/alias-bounds-when-not-wf.rs b/tests/ui/impl-trait/in-trait/alias-bounds-when-not-wf.rs index c87c8e90d741b..b63e595fd5d54 100644 --- a/tests/ui/impl-trait/in-trait/alias-bounds-when-not-wf.rs +++ b/tests/ui/impl-trait/in-trait/alias-bounds-when-not-wf.rs @@ -15,4 +15,5 @@ struct W(T); fn hello(_: W>) {} //~^ ERROR: the trait bound `usize: Foo` is not satisfied //~| ERROR: the trait bound `usize: Foo` is not satisfied +//~| ERROR: the type `W>` is not well-formed fn main() {} diff --git a/tests/ui/impl-trait/in-trait/alias-bounds-when-not-wf.stderr b/tests/ui/impl-trait/in-trait/alias-bounds-when-not-wf.stderr index dec94730df615..09418b656f8ac 100644 --- a/tests/ui/impl-trait/in-trait/alias-bounds-when-not-wf.stderr +++ b/tests/ui/impl-trait/in-trait/alias-bounds-when-not-wf.stderr @@ -15,6 +15,12 @@ note: required by a bound in `A` LL | type A = T; | ^^^ required by this bound in `A` +error: the type `W>` is not well-formed + --> $DIR/alias-bounds-when-not-wf.rs:15:13 + | +LL | fn hello(_: W>) {} + | ^^^^^^^^^^^ + error[E0277]: the trait bound `usize: Foo` is not satisfied --> $DIR/alias-bounds-when-not-wf.rs:15:13 | @@ -27,6 +33,6 @@ help: this trait has no implementations, consider adding one LL | trait Foo {} | ^^^^^^^^^ -error: aborting due to 2 previous errors +error: aborting due to 3 previous errors For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/traits/next-solver/async.fail.stderr b/tests/ui/traits/next-solver/async.fail.stderr index a76a10d20ee8b..bc89842d16a14 100644 --- a/tests/ui/traits/next-solver/async.fail.stderr +++ b/tests/ui/traits/next-solver/async.fail.stderr @@ -1,8 +1,8 @@ -error[E0271]: type mismatch resolving `() == i32` +error[E0271]: expected `{async block@$DIR/async.rs:12:17: 12:22}` to be a future that resolves to `i32`, but it resolves to `()` --> $DIR/async.rs:12:17 | LL | needs_async(async {}); - | ----------- ^^^^^^^^ types differ + | ----------- ^^^^^^^^ expected `i32`, found `()` | | | required by a bound introduced by this call | diff --git a/tests/ui/traits/next-solver/async.rs b/tests/ui/traits/next-solver/async.rs index 34c0ed02eeb12..fded774354759 100644 --- a/tests/ui/traits/next-solver/async.rs +++ b/tests/ui/traits/next-solver/async.rs @@ -10,7 +10,7 @@ fn needs_async(_: impl Future) {} #[cfg(fail)] fn main() { needs_async(async {}); - //[fail]~^ ERROR type mismatch resolving `() == i32` + //[fail]~^ ERROR expected `{async block@$DIR/async.rs:12:17: 12:22}` to be a future that resolves to `i32`, but it resolves to `()` } #[cfg(pass)] diff --git a/tests/ui/traits/next-solver/coercion/non-wf-in-coerce-pointers.rs b/tests/ui/traits/next-solver/coercion/non-wf-in-coerce-pointers.rs index bd33e3c2f47ee..0b63bb3261db7 100644 --- a/tests/ui/traits/next-solver/coercion/non-wf-in-coerce-pointers.rs +++ b/tests/ui/traits/next-solver/coercion/non-wf-in-coerce-pointers.rs @@ -7,6 +7,7 @@ trait Wf { struct S { f: &'static <() as Wf>::Assoc, //~^ ERROR the trait bound `(): Wf` is not satisfied + //~| ERROR the type `&'static <() as Wf>::Assoc` is not well-formed } fn main() { diff --git a/tests/ui/traits/next-solver/coercion/non-wf-in-coerce-pointers.stderr b/tests/ui/traits/next-solver/coercion/non-wf-in-coerce-pointers.stderr index d484a0a1c4c28..2f7307eb96b77 100644 --- a/tests/ui/traits/next-solver/coercion/non-wf-in-coerce-pointers.stderr +++ b/tests/ui/traits/next-solver/coercion/non-wf-in-coerce-pointers.stderr @@ -10,8 +10,14 @@ help: this trait has no implementations, consider adding one LL | trait Wf { | ^^^^^^^^ +error: the type `&'static <() as Wf>::Assoc` is not well-formed + --> $DIR/non-wf-in-coerce-pointers.rs:8:8 + | +LL | f: &'static <() as Wf>::Assoc, + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ + error[E0277]: the trait bound `(): Wf` is not satisfied - --> $DIR/non-wf-in-coerce-pointers.rs:14:18 + --> $DIR/non-wf-in-coerce-pointers.rs:15:18 | LL | let y: &() = x.f; | ^^^ the trait `Wf` is not implemented for `()` @@ -22,6 +28,6 @@ help: this trait has no implementations, consider adding one LL | trait Wf { | ^^^^^^^^ -error: aborting due to 2 previous errors +error: aborting due to 3 previous errors For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/traits/next-solver/find-param-recursion-issue-152716.rs b/tests/ui/traits/next-solver/find-param-recursion-issue-152716.rs index 914773c82196a..d1cdb3164d428 100644 --- a/tests/ui/traits/next-solver/find-param-recursion-issue-152716.rs +++ b/tests/ui/traits/next-solver/find-param-recursion-issue-152716.rs @@ -14,7 +14,7 @@ fn foo() where T: for<'a> Proj<'a, Assoc = for<'b> fn(>::Assoc)>, (): Trait<>::Assoc> - //~^ ERROR: overflow evaluating the requirement `(): Trait<>::Assoc>` + //~^ ERROR: overflow evaluating the requirement `(): Trait fn(>::Assoc)>` { } diff --git a/tests/ui/traits/next-solver/find-param-recursion-issue-152716.stderr b/tests/ui/traits/next-solver/find-param-recursion-issue-152716.stderr index e2ee83cfadbef..405081614a565 100644 --- a/tests/ui/traits/next-solver/find-param-recursion-issue-152716.stderr +++ b/tests/ui/traits/next-solver/find-param-recursion-issue-152716.stderr @@ -1,4 +1,4 @@ -error[E0275]: overflow evaluating the requirement `(): Trait<>::Assoc>` +error[E0275]: overflow evaluating the requirement `(): Trait fn(>::Assoc)>` --> $DIR/find-param-recursion-issue-152716.rs:16:9 | LL | (): Trait<>::Assoc> diff --git a/tests/ui/traits/next-solver/lazy-nested-obligations-2.next.stderr b/tests/ui/traits/next-solver/lazy-nested-obligations-2.next.stderr index 462544b405218..cc11aa018161a 100644 --- a/tests/ui/traits/next-solver/lazy-nested-obligations-2.next.stderr +++ b/tests/ui/traits/next-solver/lazy-nested-obligations-2.next.stderr @@ -1,14 +1,20 @@ -error[E0271]: type mismatch resolving `fn(&str) == fn(&str) {f}` +error[E0271]: type mismatch resolving `::F == fn(&str) {f}` --> $DIR/lazy-nested-obligations-2.rs:20:21 | LL | let _: V = V(f); - | ^^^^ types differ + | ^^^^ expected fn item, found fn pointer + | + = note: expected fn item `for<'a> fn(&'a _) {f}` + found fn pointer `for<'a> fn(&'a _)` -error[E0271]: type mismatch resolving `fn(&str) == fn(&str) {f}` +error[E0271]: type mismatch resolving `::F == fn(&str) {f}` --> $DIR/lazy-nested-obligations-2.rs:27:22 | LL | let _: E3 = E3::Var(f); - | ^^^^^^^^^^ types differ + | ^^^^^^^^^^ expected fn item, found fn pointer + | + = note: expected fn item `for<'a> fn(&'a _) {f}` + found fn pointer `for<'a> fn(&'a _)` error: aborting due to 2 previous errors diff --git a/tests/ui/traits/next-solver/more-object-bound.rs b/tests/ui/traits/next-solver/more-object-bound.rs index 1dad1903a649d..3d3fdc926f658 100644 --- a/tests/ui/traits/next-solver/more-object-bound.rs +++ b/tests/ui/traits/next-solver/more-object-bound.rs @@ -10,7 +10,7 @@ trait Trait: SuperTrait::B> {} fn transmute(x: A) -> B { foo::>(x) - //~^ ERROR type mismatch resolving `A == B` + //~^ ERROR type mismatch resolving ` as SuperTrait>::A == B` } fn foo(x: T::A) -> B diff --git a/tests/ui/traits/next-solver/more-object-bound.stderr b/tests/ui/traits/next-solver/more-object-bound.stderr index 7d279ed64282b..ccbf19ae4d96c 100644 --- a/tests/ui/traits/next-solver/more-object-bound.stderr +++ b/tests/ui/traits/next-solver/more-object-bound.stderr @@ -1,9 +1,17 @@ -error[E0271]: type mismatch resolving `A == B` +error[E0271]: type mismatch resolving ` as SuperTrait>::A == B` --> $DIR/more-object-bound.rs:12:17 | +LL | fn transmute(x: A) -> B { + | - - expected type parameter + | | + | found type parameter LL | foo::>(x) - | ^^^^^^^^^^^^^^^^^^^^^^^ types differ + | ^^^^^^^^^^^^^^^^^^^^^^^ expected type parameter `B`, found type parameter `A` | + = note: expected type parameter `B` + found type parameter `A` + = note: a type parameter was expected, but a different one was found; you might be missing a type parameter or trait bound + = note: for more information, visit https://doc.rust-lang.org/book/ch10-02-traits.html#traits-as-parameters = note: required because it appears within the type `dyn Trait` note: required by a bound in `foo` --> $DIR/more-object-bound.rs:18:8 diff --git a/tests/ui/traits/next-solver/normalize/normalize-param-env-2.stderr b/tests/ui/traits/next-solver/normalize/normalize-param-env-2.stderr index ecd86dba97994..b166bd0ccb92d 100644 --- a/tests/ui/traits/next-solver/normalize/normalize-param-env-2.stderr +++ b/tests/ui/traits/next-solver/normalize/normalize-param-env-2.stderr @@ -45,9 +45,43 @@ LL | trait A { LL | fn f() | ^ this trait's associated function doesn't have the requirement `_: A` -error[E0275]: overflow evaluating the requirement `<() as A>::Assoc: A` +error[E0275]: overflow evaluating the requirement `<() as A>::Assoc == _` + --> $DIR/normalize-param-env-2.rs:24:22 + | +LL | Self::Assoc: A, + | ^^^^ + | +note: required by a bound in `A` + --> $DIR/normalize-param-env-2.rs:9:1 + | +LL | / trait A { +LL | | type Assoc; +LL | | +LL | | fn f() +... | +LL | | } + | |_^ required by this bound in `A` + +error[E0275]: overflow evaluating the requirement `<() as A>::Assoc == _` + --> $DIR/normalize-param-env-2.rs:24:22 + | +LL | Self::Assoc: A, + | ^^^^ + | + = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` + +error[E0283]: type annotations needed --> $DIR/normalize-param-env-2.rs:24:22 | +LL | Self::Assoc: A, + | ^^^^ cannot infer type + | +note: multiple `impl`s or `where` clauses satisfying `_: A` found + --> $DIR/normalize-param-env-2.rs:19:1 + | +LL | impl A for () { + | ^^^^^^^^^^^^^^^^^^^ +... LL | Self::Assoc: A, | ^^^^ @@ -92,7 +126,7 @@ LL | where LL | Self::Assoc: A, | ^^^^ required by this bound in `A::f` -error: aborting due to 9 previous errors +error: aborting due to 11 previous errors Some errors have detailed explanations: E0275, E0283. For more information about an error, try `rustc --explain E0275`. diff --git a/tests/ui/traits/next-solver/normalize/normalize-param-env-4.next.stderr b/tests/ui/traits/next-solver/normalize/normalize-param-env-4.next.stderr index 47d38365e970e..a6cb9e4b4dc64 100644 --- a/tests/ui/traits/next-solver/normalize/normalize-param-env-4.next.stderr +++ b/tests/ui/traits/next-solver/normalize/normalize-param-env-4.next.stderr @@ -1,4 +1,18 @@ -error[E0275]: overflow evaluating the requirement `::Assoc: Trait` +error[E0275]: overflow evaluating the requirement `::Assoc == _` + --> $DIR/normalize-param-env-4.rs:19:26 + | +LL | ::Assoc: Trait, + | ^^^^^ + | +note: required by a bound in `Trait` + --> $DIR/normalize-param-env-4.rs:7:1 + | +LL | / trait Trait { +LL | | type Assoc; +LL | | } + | |_^ required by this bound in `Trait` + +error[E0275]: overflow evaluating the requirement `::Assoc == _` --> $DIR/normalize-param-env-4.rs:19:26 | LL | ::Assoc: Trait, @@ -22,6 +36,6 @@ note: required by a bound in `impls_trait` LL | fn impls_trait() {} | ^^^^^ required by this bound in `impls_trait` -error: aborting due to 3 previous errors +error: aborting due to 4 previous errors For more information about this error, try `rustc --explain E0275`. diff --git a/tests/ui/traits/next-solver/overflow/recursive-self-normalization-2.rs b/tests/ui/traits/next-solver/overflow/recursive-self-normalization-2.rs index c61fbef05b224..8dc27c0da605a 100644 --- a/tests/ui/traits/next-solver/overflow/recursive-self-normalization-2.rs +++ b/tests/ui/traits/next-solver/overflow/recursive-self-normalization-2.rs @@ -13,7 +13,7 @@ fn needs_bar() {} fn test::Assoc2> + Foo2::Assoc1>>() { needs_bar::(); - //~^ ERROR: the trait bound `::Assoc2: Bar` is not satisfied + //~^ ERROR: the trait bound `::Assoc1: Bar` is not satisfied } fn main() {} diff --git a/tests/ui/traits/next-solver/overflow/recursive-self-normalization-2.stderr b/tests/ui/traits/next-solver/overflow/recursive-self-normalization-2.stderr index c4be47e3520da..6f5111a6193ca 100644 --- a/tests/ui/traits/next-solver/overflow/recursive-self-normalization-2.stderr +++ b/tests/ui/traits/next-solver/overflow/recursive-self-normalization-2.stderr @@ -1,8 +1,8 @@ -error[E0277]: the trait bound `::Assoc2: Bar` is not satisfied +error[E0277]: the trait bound `::Assoc1: Bar` is not satisfied --> $DIR/recursive-self-normalization-2.rs:15:17 | LL | needs_bar::(); - | ^^^^^^^^^ the trait `Bar` is not implemented for `::Assoc2` + | ^^^^^^^^^ the trait `Bar` is not implemented for `::Assoc1` | note: required by a bound in `needs_bar` --> $DIR/recursive-self-normalization-2.rs:12:17 @@ -11,7 +11,7 @@ LL | fn needs_bar() {} | ^^^ required by this bound in `needs_bar` help: consider further restricting the associated type | -LL | fn test::Assoc2> + Foo2::Assoc1>>() where ::Assoc2: Bar { +LL | fn test::Assoc2> + Foo2::Assoc1>>() where ::Assoc1: Bar { | ++++++++++++++++++++++++++++++ error: aborting due to 1 previous error diff --git a/tests/ui/traits/normalize/normalize-diverging-alias-in-struct.next.stderr b/tests/ui/traits/normalize/normalize-diverging-alias-in-struct.next.stderr index d7046d2b058ba..d109ed37eb318 100644 --- a/tests/ui/traits/normalize/normalize-diverging-alias-in-struct.next.stderr +++ b/tests/ui/traits/normalize/normalize-diverging-alias-in-struct.next.stderr @@ -4,14 +4,11 @@ error[E0271]: type mismatch resolving `::Diverges normalizes-to LL | field: Box<::Diverges>, | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ types differ -error[E0271]: type mismatch resolving `::Diverges normalizes-to _` +error: the type `Box<::Diverges>` is not well-formed --> $DIR/normalize-diverging-alias-in-struct.rs:21:12 | LL | field: Box<::Diverges>, - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ types differ - | -note: required by a bound in `Box` - --> $SRC_DIR/alloc/src/boxed.rs:LL:COL + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: aborting due to 2 previous errors diff --git a/tests/ui/traits/normalize/normalize-diverging-alias-in-struct.rs b/tests/ui/traits/normalize/normalize-diverging-alias-in-struct.rs index 45b2cb56c25f7..7a0738af6874a 100644 --- a/tests/ui/traits/normalize/normalize-diverging-alias-in-struct.rs +++ b/tests/ui/traits/normalize/normalize-diverging-alias-in-struct.rs @@ -21,7 +21,7 @@ struct Foo { field: Box<::Diverges>, //[current]~^ ERROR: overflow evaluating the requirement `::Diverges == _` //[next]~^^ ERROR: type mismatch resolving `::Diverges normalizes-to _` - //[next]~| ERROR: type mismatch resolving `::Diverges normalizes-to _` + //[next]~| ERROR: the type `Box<::Diverges>` is not well-formed } fn main() {} diff --git a/tests/ui/traits/solver-cycles/129541-recursive-struct.rs b/tests/ui/traits/solver-cycles/129541-recursive-struct.rs index bf4b4744dbd4d..c47c7d269f8c4 100644 --- a/tests/ui/traits/solver-cycles/129541-recursive-struct.rs +++ b/tests/ui/traits/solver-cycles/129541-recursive-struct.rs @@ -1,5 +1,4 @@ //~ ERROR reached the recursion limit finding the struct tail for `Hello` -// Regression test for #129541 //@ revisions: unique_curr unique_next multiple_curr multiple_next //@ ignore-compare-mode-next-solver (explicit revisions) diff --git a/tests/ui/wf/return-type-non-wf-no-ice.next.stderr b/tests/ui/wf/return-type-non-wf-no-ice.next.stderr index 888f0893ec7c4..0ee259a401407 100644 --- a/tests/ui/wf/return-type-non-wf-no-ice.next.stderr +++ b/tests/ui/wf/return-type-non-wf-no-ice.next.stderr @@ -1,22 +1,8 @@ -error[E0277]: `T` is not an iterator +error: the type `Foo` is not well-formed --> $DIR/return-type-non-wf-no-ice.rs:13:16 | LL | fn foo() -> Foo { - | ^^^^^^ `T` is not an iterator - | -note: required by a bound in `Foo` - --> $DIR/return-type-non-wf-no-ice.rs:10:8 - | -LL | pub struct Foo(T) - | --- required by a bound in this struct -LL | where -LL | T: Iterator, - | ^^^^^^^^ required by this bound in `Foo` -help: consider restricting type parameter `T` with trait `Iterator` - | -LL | fn foo() -> Foo { - | +++++++++++++++++++++ + | ^^^^^^ error: aborting due to 1 previous error -For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/wf/return-type-non-wf-no-ice.rs b/tests/ui/wf/return-type-non-wf-no-ice.rs index 915e33418d7c0..694b8194cdbb9 100644 --- a/tests/ui/wf/return-type-non-wf-no-ice.rs +++ b/tests/ui/wf/return-type-non-wf-no-ice.rs @@ -11,7 +11,8 @@ where ::Item: Default; fn foo() -> Foo { - //~^ ERROR: `T` is not an iterator + //[current]~^ ERROR `T` is not an iterator + //[next]~^^ ERROR: the type `Foo` is not well-formed loop {} } From 92d81e253444966895615e66a5e1dfc9d029831a Mon Sep 17 00:00:00 2001 From: lcnr Date: Sun, 17 May 2026 15:04:44 +0200 Subject: [PATCH 2/3] assumptions on binders ICE yeet --- compiler/rustc_infer/src/infer/context.rs | 4 +- .../assumptions_on_binders/alias_outlives.rs | 42 --------------- .../alias_outlives.stderr | 21 -------- ...higher_ranked_alias_outlives_assumption.rs | 53 ------------------- 4 files changed, 3 insertions(+), 117 deletions(-) delete mode 100644 tests/ui/assumptions_on_binders/alias_outlives.rs delete mode 100644 tests/ui/assumptions_on_binders/alias_outlives.stderr delete mode 100644 tests/ui/assumptions_on_binders/implied_higher_ranked_alias_outlives_assumption.rs diff --git a/compiler/rustc_infer/src/infer/context.rs b/compiler/rustc_infer/src/infer/context.rs index fc0c4bb0d5f5e..ffbc7ce8aa073 100644 --- a/compiler/rustc_infer/src/infer/context.rs +++ b/compiler/rustc_infer/src/infer/context.rs @@ -50,7 +50,9 @@ impl<'tcx> rustc_type_ir::InferCtxtLike for InferCtxt<'tcx> { &self, u: ty::UniverseIndex, ) -> Option>> { - self.placeholder_assumptions_for_next_solver.borrow().get(&u).unwrap().as_ref().cloned() + // FIXME(-Zassumptions_on_binders): We should actually make sure that + // we always register placeholder assumptions. + self.placeholder_assumptions_for_next_solver.borrow().get(&u)?.as_ref().cloned() } fn get_solver_region_constraint( diff --git a/tests/ui/assumptions_on_binders/alias_outlives.rs b/tests/ui/assumptions_on_binders/alias_outlives.rs deleted file mode 100644 index c234773fb10d8..0000000000000 --- a/tests/ui/assumptions_on_binders/alias_outlives.rs +++ /dev/null @@ -1,42 +0,0 @@ -//@ compile-flags: -Znext-solver -Zassumptions-on-binders - -// test that a `::Assoc: '!a_u1` constraint is considered to be satisfied -// if there's a `T::Assoc: 'static` assumption in the root universe and if not that it is -// an error :) - -#![feature(generic_const_items)] - -trait AliasHaver { - type Assoc; -} - -trait Trait<'a> {} -impl<'a, T: 'a> Trait<'a> for T {} - -struct ReqTrait Trait<'a>>(T); - -fn borrowck_env_pass<'a, T: AliasHaver>() -where - ::Assoc: 'static, -{ - let _: ReqTrait; -} - -fn borrowck_env_fail<'a, T: AliasHaver>() -//~^ ERROR: unsatisfied lifetime constraint from -Zassumptions-on-binders -where - ::Assoc: 'a, -{ - let _: ReqTrait; -} - -const REGIONCK_ENV_PASS<'a, T: AliasHaver>: ReqTrait = todo!() -where - ::Assoc: 'static; - -const REGIONCK_ENV_FAIL<'a, T: AliasHaver>: ReqTrait = todo!() -//~^ ERROR: unsatisfied lifetime constraint from -Zassumptions-on-binders -where - ::Assoc: 'a; - -fn main() {} diff --git a/tests/ui/assumptions_on_binders/alias_outlives.stderr b/tests/ui/assumptions_on_binders/alias_outlives.stderr deleted file mode 100644 index bd3819798737d..0000000000000 --- a/tests/ui/assumptions_on_binders/alias_outlives.stderr +++ /dev/null @@ -1,21 +0,0 @@ -error: unsatisfied lifetime constraint from -Zassumptions-on-binders :3 - --> $DIR/alias_outlives.rs:37:1 - | -LL | const REGIONCK_ENV_FAIL<'a, T: AliasHaver>: ReqTrait = todo!() - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = note: meoow :c - -error: unsatisfied lifetime constraint from -Zassumptions-on-binders :3 - --> $DIR/alias_outlives.rs:25:1 - | -LL | / fn borrowck_env_fail<'a, T: AliasHaver>() -LL | | -LL | | where -LL | | ::Assoc: 'a, - | |_________________________________^ - | - = note: meoow :c - -error: aborting due to 2 previous errors - diff --git a/tests/ui/assumptions_on_binders/implied_higher_ranked_alias_outlives_assumption.rs b/tests/ui/assumptions_on_binders/implied_higher_ranked_alias_outlives_assumption.rs deleted file mode 100644 index c0cb6ce416aed..0000000000000 --- a/tests/ui/assumptions_on_binders/implied_higher_ranked_alias_outlives_assumption.rs +++ /dev/null @@ -1,53 +0,0 @@ -//@ compile-flags: -Znext-solver -Zassumptions-on-binders -//@ check-pass - -#![feature(generic_const_items)] - -// sorry for writing this -// - boxy - -// for<'a> where(for<'d> ::Assoc: 'c) { -// for<'b> { -// >::Assoc: 'c -// } -// -// rewritten to: for<'b> >::Assoc: 'c -// } -// rewritten to: true (via assumption) -// rewritting to `for<'a, 'b> >::Assoc: 'c` would be wrong - -trait Trait<'a, 'b> { - type Assoc; -} - -struct ImpliedBound<'a, 'c, T: for<'b> Trait<'a, 'b>>(T, &'a (), &'c ()) -where - for<'b> >::Assoc: 'c,; - -trait InnerBinder<'a, 'b, 'c> {} -impl<'a, 'b, 'c, S> InnerBinder<'a, 'b, 'c> for S -where - S: Trait<'a, 'b>, - >::Assoc: 'c {} - -trait OuterBinder<'a, 'c, T0> {} -impl<'a, 'c, T0, S> OuterBinder<'a, 'c, T0> for S -where - for<'b> S: InnerBinder<'a, 'b, 'c>, {} - -struct ReqTrait<'c, T>(&'c (), T) -where - for<'a> T: OuterBinder<'a, 'c, ImpliedBound<'a, 'c, T>>,; - -fn borrowck_env<'c, T>() -where - T: for<'a, 'b> Trait<'a, 'b> -{ - let _: ReqTrait<'c, T>; -} - -const REGIONCK_ENV<'c, T>: ReqTrait<'c, T> = todo!() -where - T: for<'a, 'b> Trait<'a, 'b>; - -fn main() {} From 532438d6e51c40247c9401f4582ce367c2d08e45 Mon Sep 17 00:00:00 2001 From: lcnr Date: Sun, 17 May 2026 21:44:38 +0200 Subject: [PATCH 3/3] questionable --- .../rustc_next_trait_solver/src/normalize.rs | 32 +++++++++++++------ tests/ui/README.md | 4 --- ...ambiguous-on-failed-eval-with-vars-fail.rs | 2 +- 3 files changed, 23 insertions(+), 15 deletions(-) diff --git a/compiler/rustc_next_trait_solver/src/normalize.rs b/compiler/rustc_next_trait_solver/src/normalize.rs index 84af3e66a7a13..acbb33bf8f8c4 100644 --- a/compiler/rustc_next_trait_solver/src/normalize.rs +++ b/compiler/rustc_next_trait_solver/src/normalize.rs @@ -1,5 +1,6 @@ use std::fmt::Debug; +use rustc_data_structures::sso::{SsoHashMap, SsoHashSet}; use rustc_type_ir::data_structures::ensure_sufficient_stack; use rustc_type_ir::inherent::*; use rustc_type_ir::{ @@ -23,6 +24,7 @@ where infcx: &'a Infcx, universes: Vec>, normalize: F, + cache: SsoHashMap, } #[derive(PartialEq, Eq, Debug)] @@ -45,6 +47,7 @@ where { infcx: &'a Infcx, max_universe: ty::UniverseIndex, + cache: SsoHashSet, } impl<'a, Infcx, I> MaxUniverse<'a, Infcx, I> @@ -53,7 +56,7 @@ where I: Interner, { fn new(infcx: &'a Infcx) -> Self { - MaxUniverse { infcx, max_universe: ty::UniverseIndex::ROOT } + MaxUniverse { infcx, max_universe: ty::UniverseIndex::ROOT, cache: Default::default() } } fn max_universe(self) -> ty::UniverseIndex { @@ -79,7 +82,9 @@ where self.max_universe = self.max_universe.max(self.infcx.universe_of_ty(vid).unwrap()); } - t.super_visit_with(self) + if self.cache.insert(t) { + t.super_visit_with(self) + } } fn visit_const(&mut self, c: I::Const) { @@ -110,7 +115,7 @@ where F: FnMut(AliasTerm) -> Result<(I::Term, NormalizationWasAmbiguous), E>, { pub fn new(infcx: &'a Infcx, universes: Vec>, normalize: F) -> Self { - Self { infcx, universes, normalize } + Self { infcx, universes, normalize, cache: Default::default() } } fn normalize_alias_term( @@ -176,12 +181,16 @@ where return Ok(ty); } + if let Some(ty) = self.cache.get(&ty) { + return Ok(*ty); + } + // With eager normalization, we should normalize the args of alias before // normalizing the alias itself. - let ty = ty.try_super_fold_with(self)?; - let ty::Alias(alias_ty) = ty.kind() else { return Ok(ty) }; + let folded_ty = ty.try_super_fold_with(self)?; + let ty::Alias(alias_ty) = folded_ty.kind() else { return Ok(folded_ty) }; - if ty.has_escaping_bound_vars() { + let result = if folded_ty.has_escaping_bound_vars() { let (alias_ty, mapped_regions, mapped_types, mapped_consts) = BoundVarReplacer::replace_bound_vars(infcx, &mut self.universes, alias_ty); let normalized_term = ensure_sufficient_stack(|| { @@ -195,13 +204,16 @@ where &self.universes, normalized_term.expect_ty(), ); - Ok(normalized_ty) + normalized_ty } else { - Ok(ensure_sufficient_stack(|| { + ensure_sufficient_stack(|| { self.normalize_alias_term(alias_ty.into(), HasEscapingBoundVars::No) })? - .expect_ty()) - } + .expect_ty() + }; + + assert!(self.cache.insert(ty, result).is_none(), "{ty:?} {result:?} {:?}",self.cache); + Ok(result) } #[instrument(level = "trace", skip(self), ret)] diff --git a/tests/ui/README.md b/tests/ui/README.md index 39402f78bb5ec..1ab22a65ce507 100644 --- a/tests/ui/README.md +++ b/tests/ui/README.md @@ -109,10 +109,6 @@ Tests focused on associated types. If the associated type is not in a trait defi See [Associated Types | Reference](https://doc.rust-lang.org/reference/items/associated-items.html#associated-types). -## `tests/ui/assumptions_on_binders`: -Zassumptions-on-binders - -Tests focused on the -Zassumptions-on-binders flag. - ## `tests/ui/async-await`: Async/Await Tests for the async/await related features. E.g. async functions, await expressions, and their interaction with other language features. diff --git a/tests/ui/const-generics/gca/ambiguous-on-failed-eval-with-vars-fail.rs b/tests/ui/const-generics/gca/ambiguous-on-failed-eval-with-vars-fail.rs index 5acdd004472f7..12e92d5530032 100644 --- a/tests/ui/const-generics/gca/ambiguous-on-failed-eval-with-vars-fail.rs +++ b/tests/ui/const-generics/gca/ambiguous-on-failed-eval-with-vars-fail.rs @@ -33,7 +33,7 @@ fn test_free() { fn test_free_mismatch() { let (mut arr, mut arr_with_weird_len) = free(); - //[next]~^ ERROR type mismatch resolving `FREE::<10> == 2` + //[next]~^ ERROR type mismatch resolving `FREE::<10> == 2` arr_with_weird_len = [(); 2]; arr = [(); 10]; }