From f0336511fa7bc27e05fbab5c851b8cf592844132 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jana=20D=C3=B6nszelmann?= Date: Tue, 27 Jan 2026 16:09:52 +0100 Subject: [PATCH 01/12] remove debug requirement from hooks --- compiler/rustc_middle/src/hooks/mod.rs | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/compiler/rustc_middle/src/hooks/mod.rs b/compiler/rustc_middle/src/hooks/mod.rs index 0ddcdac817b80..1a7a8f5cae60d 100644 --- a/compiler/rustc_middle/src/hooks/mod.rs +++ b/compiler/rustc_middle/src/hooks/mod.rs @@ -35,8 +35,10 @@ macro_rules! declare_hooks { impl Default for Providers { fn default() -> Self { + #[allow(unused)] Providers { - $($name: |_, $($arg,)*| default_hook(stringify!($name), &($($arg,)*))),* + $($name: + |_, $($arg,)*| default_hook(stringify!($name))),* } } } @@ -118,8 +120,6 @@ declare_hooks! { } #[cold] -fn default_hook(name: &str, args: &dyn std::fmt::Debug) -> ! { - bug!( - "`tcx.{name}{args:?}` cannot be called as `{name}` was never assigned to a provider function" - ) +fn default_hook(name: &str) -> ! { + bug!("`tcx.{name}` cannot be called as `{name}` was never assigned to a provider function") } From 244b6d5ca8fd6257df414c8b8d48c9c8d26269de Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jana=20D=C3=B6nszelmann?= Date: Tue, 27 Jan 2026 15:00:36 +0100 Subject: [PATCH 02/12] Regression test for trait-system-refactor#262 --- .../generalize/eagely-normalizing-aliases.rs | 26 +++++++++++++++++++ 1 file changed, 26 insertions(+) create mode 100644 tests/ui/traits/next-solver/generalize/eagely-normalizing-aliases.rs diff --git a/tests/ui/traits/next-solver/generalize/eagely-normalizing-aliases.rs b/tests/ui/traits/next-solver/generalize/eagely-normalizing-aliases.rs new file mode 100644 index 0000000000000..463fe49e55315 --- /dev/null +++ b/tests/ui/traits/next-solver/generalize/eagely-normalizing-aliases.rs @@ -0,0 +1,26 @@ +//@ revisions: old next +//@[next] compile-flags: -Znext-solver +//@ ignore-compare-mode-next-solver (explicit revisions) +//@ check-pass +// Regression test for trait-system-refactor-initiative#262 + +trait View {} +trait HasAssoc { + type Assoc; +} + +struct StableVec(T); +impl View for StableVec {} + +fn assert_view(f: F) -> F { f } + + +fn store(x: StableVec) +where + T: HasAssoc, + StableVec: View, +{ + let _: StableVec = assert_view(x); +} + +fn main() {} From 5d0863b147c0a0084dfb15e6435004909363865f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jana=20D=C3=B6nszelmann?= Date: Tue, 27 Jan 2026 15:00:36 +0100 Subject: [PATCH 03/12] eagerly normalize during generalization --- .../src/type_check/relate_tys.rs | 5 + compiler/rustc_infer/src/infer/at.rs | 6 + .../src/infer/relate/generalize.rs | 103 ++++++++++++++---- .../rustc_infer/src/infer/relate/lattice.rs | 5 + .../src/infer/relate/type_relating.rs | 9 ++ .../src/solve/assembly/structural_traits.rs | 7 +- .../src/solve/eval_ctxt/mod.rs | 35 +++++- compiler/rustc_type_ir/src/relate/combine.rs | 2 + .../src/relate/solver_relating.rs | 49 ++++++--- 9 files changed, 179 insertions(+), 42 deletions(-) diff --git a/compiler/rustc_borrowck/src/type_check/relate_tys.rs b/compiler/rustc_borrowck/src/type_check/relate_tys.rs index e2d684e12a816..152a7674490c7 100644 --- a/compiler/rustc_borrowck/src/type_check/relate_tys.rs +++ b/compiler/rustc_borrowck/src/type_check/relate_tys.rs @@ -616,4 +616,9 @@ impl<'b, 'tcx> PredicateEmittingRelation> for NllTypeRelating<'_ } })]); } + + fn try_eagerly_normalize_alias(&mut self, _alias: ty::AliasTy<'tcx>) -> Ty<'tcx> { + // Past hir typeck, so we don't have to worry about type inference anymore. + self.type_checker.infcx.next_ty_var(self.span()) + } } diff --git a/compiler/rustc_infer/src/infer/at.rs b/compiler/rustc_infer/src/infer/at.rs index 70e3d7dc9fef0..84ad05fa8ea23 100644 --- a/compiler/rustc_infer/src/infer/at.rs +++ b/compiler/rustc_infer/src/infer/at.rs @@ -140,6 +140,8 @@ impl<'a, 'tcx> At<'a, 'tcx> { ty::Contravariant, actual, self.cause.span, + // TODO: should normalize + &mut |_alias| self.infcx.next_ty_var(self.cause.span), ) .map(|goals| self.goals_to_obligations(goals)) } else { @@ -173,6 +175,8 @@ impl<'a, 'tcx> At<'a, 'tcx> { ty::Covariant, actual, self.cause.span, + // TODO: should normalize + &mut |_alias| self.infcx.next_ty_var(self.cause.span), ) .map(|goals| self.goals_to_obligations(goals)) } else { @@ -225,6 +229,8 @@ impl<'a, 'tcx> At<'a, 'tcx> { ty::Invariant, actual, self.cause.span, + // TODO: should normalize + &mut |_alias| self.infcx.next_ty_var(self.cause.span), ) .map(|goals| self.goals_to_obligations(goals)) } else { diff --git a/compiler/rustc_infer/src/infer/relate/generalize.rs b/compiler/rustc_infer/src/infer/relate/generalize.rs index 69c090b662e54..34fd32c45bd27 100644 --- a/compiler/rustc_infer/src/infer/relate/generalize.rs +++ b/compiler/rustc_infer/src/infer/relate/generalize.rs @@ -76,6 +76,7 @@ impl<'tcx> InferCtxt<'tcx> { target_vid, instantiation_variance, source_ty, + &mut |alias| relation.try_eagerly_normalize_alias(alias), )?; // Constrain `b_vid` to the generalized type `generalized_ty`. @@ -210,6 +211,7 @@ impl<'tcx> InferCtxt<'tcx> { target_vid, ty::Invariant, source_ct, + &mut |alias| relation.try_eagerly_normalize_alias(alias), )?; debug_assert!(!generalized_ct.is_ct_infer()); @@ -249,6 +251,7 @@ impl<'tcx> InferCtxt<'tcx> { target_vid: impl Into, ambient_variance: ty::Variance, source_term: T, + normalize: &mut dyn FnMut(ty::AliasTy<'tcx>) -> Ty<'tcx>, ) -> RelateResult<'tcx, Generalization> { assert!(!source_term.has_escaping_bound_vars()); let (for_universe, root_vid) = match target_vid.into() { @@ -269,8 +272,9 @@ impl<'tcx> InferCtxt<'tcx> { for_universe, root_term: source_term.into(), ambient_variance, - in_alias: false, + state: GeneralizationState::Default, cache: Default::default(), + normalize, }; let value_may_be_infer = generalizer.relate(source_term, source_term)?; @@ -317,6 +321,13 @@ impl<'tcx> TypeVisitor> for MaxUniverse { } } +#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] +enum GeneralizationState { + Default, + InAlias, + InNormalizedAlias, +} + /// The "generalizer" is used when handling inference variables. /// /// The basic strategy for handling a constraint like `?A <: B` is to @@ -361,9 +372,14 @@ struct Generalizer<'me, 'tcx> { /// This is necessary to correctly handle /// `::Assoc>::Assoc == ?0`. This equality can /// hold by either normalizing the outer or the inner associated type. - in_alias: bool, + // TODO: update doc comment + state: GeneralizationState, - cache: SsoHashMap<(Ty<'tcx>, ty::Variance, bool), Ty<'tcx>>, + cache: SsoHashMap<(Ty<'tcx>, ty::Variance, GeneralizationState), Ty<'tcx>>, + + /// Normalize an alias in the trait solver. + /// If normalization fails, a fresh infer var is returned. + normalize: &'me mut dyn FnMut(ty::AliasTy<'tcx>) -> Ty<'tcx>, } impl<'tcx> Generalizer<'_, 'tcx> { @@ -409,17 +425,34 @@ impl<'tcx> Generalizer<'_, 'tcx> { // with inference variables can cause incorrect ambiguity. // // cc trait-system-refactor-initiative#110 - if self.infcx.next_trait_solver() && !alias.has_escaping_bound_vars() && !self.in_alias { - return Ok(self.next_ty_var_for_alias()); + if self.infcx.next_trait_solver() + && !alias.has_escaping_bound_vars() + && match self.state { + GeneralizationState::Default => true, + GeneralizationState::InAlias => false, + // When generalizing an alias after normalizing, + // the outer alias should be treated as rigid and we shouldn't try generalizing it again. + // If we recursively find more aliases, the state should have been set back to InAlias. + GeneralizationState::InNormalizedAlias => unreachable!(), + } + { + let normalized_alias = (self.normalize)(alias); + + self.state = GeneralizationState::InNormalizedAlias; + // recursively generalize, treat the outer alias as rigid to avoid infinite recursion + let res = self.relate(normalized_alias, normalized_alias); + + // only one way to get here + self.state = GeneralizationState::Default; + + return res; } - let is_nested_alias = mem::replace(&mut self.in_alias, true); + let previous_state = mem::replace(&mut self.state, GeneralizationState::InAlias); let result = match self.relate(alias, alias) { Ok(alias) => Ok(alias.to_ty(self.cx())), - Err(e) => { - if is_nested_alias { - return Err(e); - } else { + Err(e) => match previous_state { + GeneralizationState::Default => { let mut visitor = MaxUniverse::new(); alias.visit_with(&mut visitor); let infer_replacement_is_complete = @@ -432,9 +465,14 @@ impl<'tcx> Generalizer<'_, 'tcx> { debug!("generalization failure in alias"); Ok(self.next_ty_var_for_alias()) } - } + GeneralizationState::InAlias => return Err(e), + // When generalizing an alias after normalizing, + // the outer alias should be treated as rigid and we shouldn't try generalizing it again. + // If we recursively find more aliases, the state should have been set back to InAlias. + GeneralizationState::InNormalizedAlias => unreachable!(), + }, }; - self.in_alias = is_nested_alias; + self.state = previous_state; result } } @@ -488,7 +526,7 @@ impl<'tcx> TypeRelation> for Generalizer<'_, 'tcx> { fn tys(&mut self, t: Ty<'tcx>, t2: Ty<'tcx>) -> RelateResult<'tcx, Ty<'tcx>> { assert_eq!(t, t2); // we are misusing TypeRelation here; both LHS and RHS ought to be == - if let Some(&result) = self.cache.get(&(t, self.ambient_variance, self.in_alias)) { + if let Some(&result) = self.cache.get(&(t, self.ambient_variance, self.state)) { return Ok(result); } @@ -553,9 +591,17 @@ impl<'tcx> TypeRelation> for Generalizer<'_, 'tcx> { // cc trait-system-refactor-initiative#108 if self.infcx.next_trait_solver() && !matches!(self.infcx.typing_mode(), TypingMode::Coherence) - && self.in_alias { - inner.type_variables().equate(vid, new_var_id); + match self.state { + GeneralizationState::InAlias => { + inner.type_variables().equate(vid, new_var_id); + } + GeneralizationState::Default + | GeneralizationState::InNormalizedAlias => {} + } + GeneralizerState::Default + | GeneralizerState::ShallowStructurallyRelateAliases + | GeneralizerState::StructurallyRelateAliases => {} } debug!("replacing original vid={:?} with new={:?}", vid, new_var_id); @@ -585,14 +631,25 @@ impl<'tcx> TypeRelation> for Generalizer<'_, 'tcx> { } ty::Alias(_, data) => match self.structurally_relate_aliases { - StructurallyRelateAliases::No => self.generalize_alias_ty(data), + StructurallyRelateAliases::No => match self.state { + GeneralizationState::Default | GeneralizationState::InAlias => { + self.generalize_alias_ty(data) + } + GeneralizationState::InNormalizedAlias => { + // We can switch back to default, we've treated one layer as rigid by doing this operation. + self.state = GeneralizationState::Default; + let res = relate::structurally_relate_tys(self, t, t); + self.state = GeneralizationState::InNormalizedAlias; + res + } + }, StructurallyRelateAliases::Yes => relate::structurally_relate_tys(self, t, t), }, _ => relate::structurally_relate_tys(self, t, t), }?; - self.cache.insert((t, self.ambient_variance, self.in_alias), g); + self.cache.insert((t, self.ambient_variance, self.state), g); Ok(g) } @@ -683,9 +740,17 @@ impl<'tcx> TypeRelation> for Generalizer<'_, 'tcx> { // for more details. if self.infcx.next_trait_solver() && !matches!(self.infcx.typing_mode(), TypingMode::Coherence) - && self.in_alias { - variable_table.union(vid, new_var_id); + match self.state { + GeneralizationState::InAlias => { + variable_table.union(vid, new_var_id); + } + GeneralizationState::Default + | GeneralizationState::InNormalizedAlias => {} + } + GeneralizerState::Default + | GeneralizerState::ShallowStructurallyRelateAliases + | GeneralizerState::StructurallyRelateAliases => {} } Ok(ty::Const::new_var(self.cx(), new_var_id)) } diff --git a/compiler/rustc_infer/src/infer/relate/lattice.rs b/compiler/rustc_infer/src/infer/relate/lattice.rs index a05e2d40e829f..2cb256b1c63c4 100644 --- a/compiler/rustc_infer/src/infer/relate/lattice.rs +++ b/compiler/rustc_infer/src/infer/relate/lattice.rs @@ -299,4 +299,9 @@ impl<'tcx> PredicateEmittingRelation> for LatticeOp<'_, 'tcx> { ty::AliasRelationDirection::Equate, ))]); } + + fn try_eagerly_normalize_alias(&mut self, _alias: ty::AliasTy<'tcx>) -> Ty<'tcx> { + // TODO: this should actually normalize + self.infcx.next_ty_var(self.span()) + } } diff --git a/compiler/rustc_infer/src/infer/relate/type_relating.rs b/compiler/rustc_infer/src/infer/relate/type_relating.rs index 96a0375f5fba6..67f9dc69a4a65 100644 --- a/compiler/rustc_infer/src/infer/relate/type_relating.rs +++ b/compiler/rustc_infer/src/infer/relate/type_relating.rs @@ -396,4 +396,13 @@ impl<'tcx> PredicateEmittingRelation> for TypeRelating<'_, 'tcx> } })]); } + + fn try_eagerly_normalize_alias( + &mut self, + _alias: rustc_type_ir::AliasTy< as rustc_type_ir::InferCtxtLike>::Interner>, + ) -> < as rustc_type_ir::InferCtxtLike>::Interner as rustc_type_ir::Interner>::Ty + { + // We only try to eagerly normalize aliases if we're using the new solver. + unreachable!() + } } diff --git a/compiler/rustc_next_trait_solver/src/solve/assembly/structural_traits.rs b/compiler/rustc_next_trait_solver/src/solve/assembly/structural_traits.rs index 05ea217c1de08..f94b0f0c30ed3 100644 --- a/compiler/rustc_next_trait_solver/src/solve/assembly/structural_traits.rs +++ b/compiler/rustc_next_trait_solver/src/solve/assembly/structural_traits.rs @@ -976,7 +976,12 @@ where let replacement = self.ecx.instantiate_binder_with_infer(*replacement); self.nested.extend( self.ecx - .eq_and_get_goals(self.param_env, alias_term, replacement.projection_term) + .relate_and_get_goals( + self.param_env, + alias_term, + ty::Invariant, + replacement.projection_term, + ) .expect("expected to be able to unify goal projection with dyn's projection"), ); 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 6841fe1c5124e..fedb6390d9588 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 @@ -408,7 +408,7 @@ where /// Recursively evaluates `goal`, returning whether any inference vars have /// been constrained and the certainty of the result. - fn evaluate_goal( + pub(super) fn evaluate_goal( &mut self, source: GoalSource, goal: Goal, @@ -1018,7 +1018,8 @@ where variance: ty::Variance, rhs: T, ) -> Result<(), NoSolution> { - let goals = self.delegate.relate(param_env, lhs, variance, rhs, self.origin_span)?; + let goals = self.relate_and_get_goals(param_env, lhs, variance, rhs)?; + for &goal in goals.iter() { let source = match goal.predicate.kind().skip_binder() { ty::PredicateKind::Subtype { .. } | ty::PredicateKind::AliasRelate(..) => { @@ -1039,13 +1040,37 @@ where /// If possible, try using `eq` instead which automatically handles nested /// goals correctly. #[instrument(level = "trace", skip(self, param_env), ret)] - pub(super) fn eq_and_get_goals>( - &self, + pub(super) fn relate_and_get_goals>( + &mut self, param_env: I::ParamEnv, lhs: T, + variance: ty::Variance, rhs: T, ) -> Result>, NoSolution> { - Ok(self.delegate.relate(param_env, lhs, ty::Variance::Invariant, rhs, self.origin_span)?) + let cx = self.cx(); + let delegate = self.delegate; + let origin_span = self.origin_span; + + let mut normalize = |alias: ty::AliasTy| { + let inference_var = self.next_ty_infer(); + + let goal = Goal::new( + cx, + param_env, + ty::PredicateKind::AliasRelate( + alias.to_ty(cx).into(), + inference_var.into(), + ty::AliasRelationDirection::Equate, + ), + ); + + // Ignore the result. If we can't eagerly normalize, returning the inference variable is enough. + let _ = self.evaluate_goal(GoalSource::TypeRelating, goal, None); + + self.resolve_vars_if_possible(inference_var) + }; + + Ok(delegate.relate(param_env, lhs, variance, rhs, origin_span, &mut normalize)?) } pub(super) fn instantiate_binder_with_infer + Copy>( diff --git a/compiler/rustc_type_ir/src/relate/combine.rs b/compiler/rustc_type_ir/src/relate/combine.rs index 64b87fac77f94..72d54c23733ee 100644 --- a/compiler/rustc_type_ir/src/relate/combine.rs +++ b/compiler/rustc_type_ir/src/relate/combine.rs @@ -40,6 +40,8 @@ where /// Register `AliasRelate` obligation(s) that both types must be related to each other. fn register_alias_relate_predicate(&mut self, a: I::Ty, b: I::Ty); + + fn try_eagerly_normalize_alias(&mut self, alias: ty::AliasTy) -> I::Ty; } pub fn super_combine_tys( diff --git a/compiler/rustc_type_ir/src/relate/solver_relating.rs b/compiler/rustc_type_ir/src/relate/solver_relating.rs index 82ee4f75fcb0a..541b2531fe749 100644 --- a/compiler/rustc_type_ir/src/relate/solver_relating.rs +++ b/compiler/rustc_type_ir/src/relate/solver_relating.rs @@ -15,6 +15,7 @@ pub trait RelateExt: InferCtxtLike { variance: ty::Variance, rhs: T, span: ::Span, + normalize: &mut dyn FnMut(ty::AliasTy) -> ::Ty, ) -> Result< Vec::Predicate>>, TypeError, @@ -32,40 +33,46 @@ pub trait RelateExt: InferCtxtLike { >; } -impl RelateExt for Infcx { - fn relate>( +impl> RelateExt for Infcx { + fn relate>( &self, - param_env: ::ParamEnv, + param_env: I::ParamEnv, lhs: T, variance: ty::Variance, rhs: T, - span: ::Span, - ) -> Result< - Vec::Predicate>>, - TypeError, - > { - let mut relate = - SolverRelating::new(self, StructurallyRelateAliases::No, variance, param_env, span); + span: I::Span, + normalize: &mut dyn FnMut(ty::AliasTy) -> I::Ty, + ) -> Result>, TypeError> { + let mut relate = SolverRelating::new( + self, + StructurallyRelateAliases::No, + variance, + param_env, + span, + normalize, + ); relate.relate(lhs, rhs)?; Ok(relate.goals) } - fn eq_structurally_relating_aliases>( + fn eq_structurally_relating_aliases>( &self, - param_env: ::ParamEnv, + param_env: I::ParamEnv, lhs: T, rhs: T, - span: ::Span, - ) -> Result< - Vec::Predicate>>, - TypeError, - > { + span: I::Span, + ) -> Result>, TypeError> { + // Structurally relating, we treat aliases as rigid, + // so we shouldn't ever try to normalize them. + let mut normalize_unreachable = |_alias| unreachable!(); + let mut relate = SolverRelating::new( self, StructurallyRelateAliases::Yes, ty::Invariant, param_env, span, + &mut normalize_unreachable, ); relate.relate(lhs, rhs)?; Ok(relate.goals) @@ -75,12 +82,14 @@ impl RelateExt for Infcx { /// Enforce that `a` is equal to or a subtype of `b`. pub struct SolverRelating<'infcx, Infcx, I: Interner> { infcx: &'infcx Infcx, + // Immutable fields. structurally_relate_aliases: StructurallyRelateAliases, param_env: I::ParamEnv, span: I::Span, // Mutable fields. ambient_variance: ty::Variance, + normalize: &'infcx mut dyn FnMut(ty::AliasTy) -> I::Ty, goals: Vec>, /// The cache only tracks the `ambient_variance` as it's the /// only field which is mutable and which meaningfully changes @@ -118,12 +127,14 @@ where ambient_variance: ty::Variance, param_env: I::ParamEnv, span: I::Span, + normalize: &'infcx mut dyn FnMut(ty::AliasTy) -> I::Ty, ) -> Self { SolverRelating { infcx, structurally_relate_aliases, span, ambient_variance, + normalize, param_env, goals: vec![], cache: Default::default(), @@ -406,4 +417,8 @@ where } })]); } + + fn try_eagerly_normalize_alias(&mut self, alias: ty::AliasTy) -> I::Ty { + (self.normalize)(alias) + } } From 04f2c0191ebe7a1018e00cf6db5f8394352c2da6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jana=20D=C3=B6nszelmann?= Date: Tue, 27 Jan 2026 15:46:09 +0100 Subject: [PATCH 04/12] implement eager normalization in a fresh context during typeck --- compiler/rustc_infer/src/infer/at.rs | 15 +++--- compiler/rustc_infer/src/infer/mod.rs | 13 ++++- .../rustc_infer/src/infer/relate/lattice.rs | 5 +- compiler/rustc_interface/src/passes.rs | 2 +- compiler/rustc_middle/src/hooks/mod.rs | 24 ++++++++- compiler/rustc_trait_selection/src/solve.rs | 54 +++++++++++++++++-- 6 files changed, 97 insertions(+), 16 deletions(-) diff --git a/compiler/rustc_infer/src/infer/at.rs b/compiler/rustc_infer/src/infer/at.rs index 84ad05fa8ea23..3487286d58830 100644 --- a/compiler/rustc_infer/src/infer/at.rs +++ b/compiler/rustc_infer/src/infer/at.rs @@ -140,8 +140,9 @@ impl<'a, 'tcx> At<'a, 'tcx> { ty::Contravariant, actual, self.cause.span, - // TODO: should normalize - &mut |_alias| self.infcx.next_ty_var(self.cause.span), + &mut |alias| { + self.infcx.try_eagerly_normalize_alias(self.param_env, self.cause.span, alias) + }, ) .map(|goals| self.goals_to_obligations(goals)) } else { @@ -175,8 +176,9 @@ impl<'a, 'tcx> At<'a, 'tcx> { ty::Covariant, actual, self.cause.span, - // TODO: should normalize - &mut |_alias| self.infcx.next_ty_var(self.cause.span), + &mut |alias| { + self.infcx.try_eagerly_normalize_alias(self.param_env, self.cause.span, alias) + }, ) .map(|goals| self.goals_to_obligations(goals)) } else { @@ -229,8 +231,9 @@ impl<'a, 'tcx> At<'a, 'tcx> { ty::Invariant, actual, self.cause.span, - // TODO: should normalize - &mut |_alias| self.infcx.next_ty_var(self.cause.span), + &mut |alias| { + self.infcx.try_eagerly_normalize_alias(self.param_env, self.cause.span, alias) + }, ) .map(|goals| self.goals_to_obligations(goals)) } else { diff --git a/compiler/rustc_infer/src/infer/mod.rs b/compiler/rustc_infer/src/infer/mod.rs index b573065362601..2a2ac7c159243 100644 --- a/compiler/rustc_infer/src/infer/mod.rs +++ b/compiler/rustc_infer/src/infer/mod.rs @@ -1,5 +1,5 @@ use std::cell::{Cell, RefCell}; -use std::fmt; +use std::{fmt, mem}; pub use at::DefineOpaqueTypes; use free_regions::RegionRelations; @@ -21,6 +21,7 @@ use rustc_hir::def_id::{DefId, LocalDefId}; use rustc_macros::extension; pub use rustc_macros::{TypeFoldable, TypeVisitable}; use rustc_middle::bug; +use rustc_middle::hooks::TypeErasedInfcx; use rustc_middle::infer::canonical::{CanonicalQueryInput, CanonicalVarValues}; use rustc_middle::mir::ConstraintCategory; use rustc_middle::traits::select; @@ -1498,6 +1499,16 @@ impl<'tcx> InferCtxt<'tcx> { } } + pub fn try_eagerly_normalize_alias<'a>( + &'a self, + param_env: ty::ParamEnv<'tcx>, + span: Span, + alias: ty::AliasTy<'tcx>, + ) -> Ty<'tcx> { + let erased = unsafe { mem::transmute::<_, TypeErasedInfcx<'a, 'tcx>>(self) }; + self.tcx.try_eagerly_normalize_alias(erased, param_env, span, alias) + } + /// Attach a callback to be invoked on each root obligation evaluated in the new trait solver. pub fn attach_obligation_inspector(&self, inspector: ObligationInspector<'tcx>) { debug_assert!( diff --git a/compiler/rustc_infer/src/infer/relate/lattice.rs b/compiler/rustc_infer/src/infer/relate/lattice.rs index 2cb256b1c63c4..7e480df7dda63 100644 --- a/compiler/rustc_infer/src/infer/relate/lattice.rs +++ b/compiler/rustc_infer/src/infer/relate/lattice.rs @@ -300,8 +300,7 @@ impl<'tcx> PredicateEmittingRelation> for LatticeOp<'_, 'tcx> { ))]); } - fn try_eagerly_normalize_alias(&mut self, _alias: ty::AliasTy<'tcx>) -> Ty<'tcx> { - // TODO: this should actually normalize - self.infcx.next_ty_var(self.span()) + fn try_eagerly_normalize_alias(&mut self, alias: ty::AliasTy<'tcx>) -> Ty<'tcx> { + self.infcx.try_eagerly_normalize_alias(self.param_env(), self.span(), alias) } } diff --git a/compiler/rustc_interface/src/passes.rs b/compiler/rustc_interface/src/passes.rs index 15addd2407857..225fff380ef52 100644 --- a/compiler/rustc_interface/src/passes.rs +++ b/compiler/rustc_interface/src/passes.rs @@ -900,7 +900,7 @@ pub static DEFAULT_QUERY_PROVIDERS: LazyLock = LazyLock::new(|| { rustc_hir_typeck::provide(&mut providers.queries); ty::provide(&mut providers.queries); traits::provide(&mut providers.queries); - solve::provide(&mut providers.queries); + solve::provide(providers); rustc_passes::provide(&mut providers.queries); rustc_traits::provide(&mut providers.queries); rustc_ty_utils::provide(&mut providers.queries); diff --git a/compiler/rustc_middle/src/hooks/mod.rs b/compiler/rustc_middle/src/hooks/mod.rs index 1a7a8f5cae60d..c09d9fc2d468d 100644 --- a/compiler/rustc_middle/src/hooks/mod.rs +++ b/compiler/rustc_middle/src/hooks/mod.rs @@ -3,14 +3,16 @@ //! similar to queries, but queries come with a lot of machinery for caching and incremental //! compilation, whereas hooks are just plain function pointers without any of the query magic. +use std::marker::PhantomData; + use rustc_hir::def_id::{DefId, DefPathHash}; use rustc_session::StableCrateId; use rustc_span::def_id::{CrateNum, LocalDefId}; -use rustc_span::{ExpnHash, ExpnId}; +use rustc_span::{ExpnHash, ExpnId, Span}; -use crate::mir; use crate::query::on_disk_cache::{CacheEncoder, EncodedDepNodeIndex}; use crate::ty::{Ty, TyCtxt}; +use crate::{mir, ty}; macro_rules! declare_hooks { ($($(#[$attr:meta])*hook $name:ident($($arg:ident: $K:ty),*) -> $V:ty;)*) => { @@ -117,6 +119,24 @@ declare_hooks! { encoder: &mut CacheEncoder<'_, 'tcx>, query_result_index: &mut EncodedDepNodeIndex ) -> (); + + /// Tries to normalize an alias, ignoring any errors. + /// + /// Generalization with the new trait solver calls into this, + /// when generalizing outside of the trait solver in `hir_typeck`. + hook try_eagerly_normalize_alias( + type_erased_infcx: TypeErasedInfcx<'_, 'tcx>, + param_env: ty::ParamEnv<'tcx>, + span: Span, + alias: ty::AliasTy<'tcx> + ) -> Ty<'tcx>; +} + +// `repr(transparent)` so we can transmute a `&'a Infcx<'tcx>` to this struct. +#[repr(transparent)] +pub struct TypeErasedInfcx<'a, 'tcx> { + _infcx: *const (), + phantom: PhantomData<&'a mut &'tcx ()>, } #[cold] diff --git a/compiler/rustc_trait_selection/src/solve.rs b/compiler/rustc_trait_selection/src/solve.rs index 5d200c4d340ba..cb02885139038 100644 --- a/compiler/rustc_trait_selection/src/solve.rs +++ b/compiler/rustc_trait_selection/src/solve.rs @@ -1,3 +1,8 @@ +use std::mem; + +use rustc_infer::infer::InferCtxt; +use rustc_infer::traits::{Obligation, ObligationCause}; +use rustc_middle::hooks::TypeErasedInfcx; pub use rustc_next_trait_solver::solve::*; mod delegate; @@ -13,10 +18,13 @@ pub use normalize::{ deeply_normalize, deeply_normalize_with_skipped_universes, deeply_normalize_with_skipped_universes_and_ambiguous_coroutine_goals, }; -use rustc_middle::query::Providers; -use rustc_middle::ty::TyCtxt; +use rustc_middle::ty::{self, Ty, TyCtxt}; +use rustc_middle::util::Providers; +use rustc_span::Span; pub use select::InferCtxtSelectExt; +use crate::traits::ObligationCtxt; + fn evaluate_root_goal_for_proof_tree_raw<'tcx>( tcx: TyCtxt<'tcx>, canonical_input: CanonicalInput>, @@ -27,6 +35,46 @@ fn evaluate_root_goal_for_proof_tree_raw<'tcx>( ) } +fn try_eagerly_normalize_alias<'a, 'tcx>( + tcx: TyCtxt<'tcx>, + type_erased_infcx: TypeErasedInfcx<'a, 'tcx>, + param_env: ty::ParamEnv<'tcx>, + span: Span, + alias: ty::AliasTy<'tcx>, +) -> Ty<'tcx> { + let infcx = unsafe { + mem::transmute::, &'a InferCtxt<'tcx>>(type_erased_infcx) + }; + + let ocx = ObligationCtxt::new(infcx); + + let infer_term = infcx.next_ty_var(span); + + // Dummy because we ignore the error anyway. + // We do provide a span, because this span is used when registering opaque types. + // For example, if we don't provide a span here, some diagnostics talking about TAIT will refer to a dummy span. + let cause = ObligationCause::dummy_with_span(span); + let obligation = Obligation::new( + tcx, + // we ignore the error anyway + ObligationCause::dummy(), + param_env, + ty::PredicateKind::AliasRelate( + alias.to_ty(tcx).into(), + infer_term.into(), + ty::AliasRelationDirection::Equate, + ), + ); + + ocx.register_obligation(obligation); + + // This only tries to eagerly resolve, if it errors we don't care. + let _ = ocx.try_evaluate_obligations(); + + infcx.resolve_vars_if_possible(infer_term) +} + pub fn provide(providers: &mut Providers) { - *providers = Providers { evaluate_root_goal_for_proof_tree_raw, ..*providers }; + providers.hooks.try_eagerly_normalize_alias = try_eagerly_normalize_alias; + providers.queries.evaluate_root_goal_for_proof_tree_raw = evaluate_root_goal_for_proof_tree_raw; } From 917713b4db3c627f2a35174c09d3ca715dd814b2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jana=20D=C3=B6nszelmann?= Date: Tue, 27 Jan 2026 16:03:10 +0100 Subject: [PATCH 05/12] merge generalizer state and structurally relate aliases --- .../src/infer/relate/generalize.rs | 123 ++++++++---------- 1 file changed, 56 insertions(+), 67 deletions(-) diff --git a/compiler/rustc_infer/src/infer/relate/generalize.rs b/compiler/rustc_infer/src/infer/relate/generalize.rs index 34fd32c45bd27..d5c0726ed9a88 100644 --- a/compiler/rustc_infer/src/infer/relate/generalize.rs +++ b/compiler/rustc_infer/src/infer/relate/generalize.rs @@ -267,12 +267,14 @@ impl<'tcx> InferCtxt<'tcx> { let mut generalizer = Generalizer { infcx: self, span, - structurally_relate_aliases, root_vid, for_universe, root_term: source_term.into(), ambient_variance, - state: GeneralizationState::Default, + state: match structurally_relate_aliases { + StructurallyRelateAliases::No => GeneralizerState::Default, + StructurallyRelateAliases::Yes => GeneralizerState::StructurallyRelateAliases, + }, cache: Default::default(), normalize, }; @@ -322,10 +324,13 @@ impl<'tcx> TypeVisitor> for MaxUniverse { } #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] -enum GeneralizationState { +enum GeneralizerState { + /// Treat aliases as potentially normalizable. Default, - InAlias, - InNormalizedAlias, + IncompletelyRelateHigherRankedAlias, + /// Only one layer + ShallowStructurallyRelateAliases, + StructurallyRelateAliases, } /// The "generalizer" is used when handling inference variables. @@ -346,10 +351,6 @@ struct Generalizer<'me, 'tcx> { span: Span, - /// Whether aliases should be related structurally. If not, we have to - /// be careful when generalizing aliases. - structurally_relate_aliases: StructurallyRelateAliases, - /// The vid of the type variable that is in the process of being /// instantiated. If we find this within the value we are folding, /// that means we would have created a cyclic value. @@ -372,10 +373,9 @@ struct Generalizer<'me, 'tcx> { /// This is necessary to correctly handle /// `::Assoc>::Assoc == ?0`. This equality can /// hold by either normalizing the outer or the inner associated type. - // TODO: update doc comment - state: GeneralizationState, + state: GeneralizerState, - cache: SsoHashMap<(Ty<'tcx>, ty::Variance, GeneralizationState), Ty<'tcx>>, + cache: SsoHashMap<(Ty<'tcx>, ty::Variance, GeneralizerState), Ty<'tcx>>, /// Normalize an alias in the trait solver. /// If normalization fails, a fresh infer var is returned. @@ -415,44 +415,51 @@ impl<'tcx> Generalizer<'_, 'tcx> { /// continue generalizing the alias. This ends up pulling down the universe of the /// inference variable and is incomplete in case the alias would normalize to a type /// which does not mention that inference variable. - fn generalize_alias_ty( + fn handle_alias_ty( &mut self, + alias_ty: Ty<'tcx>, alias: ty::AliasTy<'tcx>, ) -> Result, TypeError<'tcx>> { - // We do not eagerly replace aliases with inference variables if they have - // escaping bound vars, see the method comment for details. However, when we - // are inside of an alias with escaping bound vars replacing nested aliases - // with inference variables can cause incorrect ambiguity. - // - // cc trait-system-refactor-initiative#110 - if self.infcx.next_trait_solver() - && !alias.has_escaping_bound_vars() - && match self.state { - GeneralizationState::Default => true, - GeneralizationState::InAlias => false, - // When generalizing an alias after normalizing, - // the outer alias should be treated as rigid and we shouldn't try generalizing it again. - // If we recursively find more aliases, the state should have been set back to InAlias. - GeneralizationState::InNormalizedAlias => unreachable!(), + match self.state { + GeneralizerState::ShallowStructurallyRelateAliases => { + // We can switch back to default, we've treated one layer as rigid by doing this operation. + self.state = GeneralizerState::Default; + let res = relate::structurally_relate_tys(self, alias_ty, alias_ty); + self.state = GeneralizerState::ShallowStructurallyRelateAliases; + return res; } - { - let normalized_alias = (self.normalize)(alias); - - self.state = GeneralizationState::InNormalizedAlias; - // recursively generalize, treat the outer alias as rigid to avoid infinite recursion - let res = self.relate(normalized_alias, normalized_alias); - - // only one way to get here - self.state = GeneralizationState::Default; - - return res; + GeneralizerState::StructurallyRelateAliases => { + return relate::structurally_relate_tys(self, alias_ty, alias_ty); + } + GeneralizerState::Default + if self.infcx.next_trait_solver() && !alias.has_escaping_bound_vars() => + { + // We do not eagerly replace aliases with inference variables if they have + // escaping bound vars, see the method comment for details. However, when we + // are inside of an alias with escaping bound vars replacing nested aliases + // with inference variables can cause incorrect ambiguity. + // + // cc trait-system-refactor-initiative#110 + let normalized_alias = (self.normalize)(alias); + + self.state = GeneralizerState::ShallowStructurallyRelateAliases; + // recursively generalize, treat the outer alias as rigid to avoid infinite recursion + let res = self.relate(normalized_alias, normalized_alias); + + // only one way to get here + self.state = GeneralizerState::Default; + + return res; + } + GeneralizerState::Default | GeneralizerState::IncompletelyRelateHigherRankedAlias => {} } - let previous_state = mem::replace(&mut self.state, GeneralizationState::InAlias); + let previous_state = + mem::replace(&mut self.state, GeneralizerState::IncompletelyRelateHigherRankedAlias); let result = match self.relate(alias, alias) { Ok(alias) => Ok(alias.to_ty(self.cx())), Err(e) => match previous_state { - GeneralizationState::Default => { + GeneralizerState::Default => { let mut visitor = MaxUniverse::new(); alias.visit_with(&mut visitor); let infer_replacement_is_complete = @@ -465,11 +472,11 @@ impl<'tcx> Generalizer<'_, 'tcx> { debug!("generalization failure in alias"); Ok(self.next_ty_var_for_alias()) } - GeneralizationState::InAlias => return Err(e), - // When generalizing an alias after normalizing, - // the outer alias should be treated as rigid and we shouldn't try generalizing it again. - // If we recursively find more aliases, the state should have been set back to InAlias. - GeneralizationState::InNormalizedAlias => unreachable!(), + GeneralizerState::IncompletelyRelateHigherRankedAlias => return Err(e), + + // Early return. + GeneralizerState::ShallowStructurallyRelateAliases + | GeneralizerState::StructurallyRelateAliases => unreachable!(), }, }; self.state = previous_state; @@ -593,11 +600,9 @@ impl<'tcx> TypeRelation> for Generalizer<'_, 'tcx> { && !matches!(self.infcx.typing_mode(), TypingMode::Coherence) { match self.state { - GeneralizationState::InAlias => { + GeneralizerState::IncompletelyRelateHigherRankedAlias => { inner.type_variables().equate(vid, new_var_id); } - GeneralizationState::Default - | GeneralizationState::InNormalizedAlias => {} } GeneralizerState::Default | GeneralizerState::ShallowStructurallyRelateAliases @@ -630,21 +635,7 @@ impl<'tcx> TypeRelation> for Generalizer<'_, 'tcx> { } } - ty::Alias(_, data) => match self.structurally_relate_aliases { - StructurallyRelateAliases::No => match self.state { - GeneralizationState::Default | GeneralizationState::InAlias => { - self.generalize_alias_ty(data) - } - GeneralizationState::InNormalizedAlias => { - // We can switch back to default, we've treated one layer as rigid by doing this operation. - self.state = GeneralizationState::Default; - let res = relate::structurally_relate_tys(self, t, t); - self.state = GeneralizationState::InNormalizedAlias; - res - } - }, - StructurallyRelateAliases::Yes => relate::structurally_relate_tys(self, t, t), - }, + ty::Alias(_, data) => self.handle_alias_ty(t, data), _ => relate::structurally_relate_tys(self, t, t), }?; @@ -742,11 +733,9 @@ impl<'tcx> TypeRelation> for Generalizer<'_, 'tcx> { && !matches!(self.infcx.typing_mode(), TypingMode::Coherence) { match self.state { - GeneralizationState::InAlias => { + GeneralizerState::IncompletelyRelateHigherRankedAlias => { variable_table.union(vid, new_var_id); } - GeneralizationState::Default - | GeneralizationState::InNormalizedAlias => {} } GeneralizerState::Default | GeneralizerState::ShallowStructurallyRelateAliases From 7a123e87b21cd95fef62b80571ee6c644ac3a1c3 Mon Sep 17 00:00:00 2001 From: lcnr Date: Thu, 29 Jan 2026 18:49:58 +0100 Subject: [PATCH 06/12] explicitly provide type in transmute --- compiler/rustc_infer/src/infer/mod.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/compiler/rustc_infer/src/infer/mod.rs b/compiler/rustc_infer/src/infer/mod.rs index 2a2ac7c159243..351d0001c677d 100644 --- a/compiler/rustc_infer/src/infer/mod.rs +++ b/compiler/rustc_infer/src/infer/mod.rs @@ -1505,7 +1505,8 @@ impl<'tcx> InferCtxt<'tcx> { span: Span, alias: ty::AliasTy<'tcx>, ) -> Ty<'tcx> { - let erased = unsafe { mem::transmute::<_, TypeErasedInfcx<'a, 'tcx>>(self) }; + let erased = + unsafe { mem::transmute::<&'a InferCtxt<'tcx>, TypeErasedInfcx<'a, 'tcx>>(self) }; self.tcx.try_eagerly_normalize_alias(erased, param_env, span, alias) } From f50591fc1059d98ba57c79094f6e2d46db4b25b6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jana=20D=C3=B6nszelmann?= Date: Fri, 30 Jan 2026 19:00:20 +0100 Subject: [PATCH 07/12] normalize at the start of generalize if we can --- .../src/infer/relate/generalize.rs | 84 +++++++++++++------ .../src/canonical/canonicalizer.rs | 6 +- 2 files changed, 63 insertions(+), 27 deletions(-) diff --git a/compiler/rustc_infer/src/infer/relate/generalize.rs b/compiler/rustc_infer/src/infer/relate/generalize.rs index d5c0726ed9a88..1d4dab0016168 100644 --- a/compiler/rustc_infer/src/infer/relate/generalize.rs +++ b/compiler/rustc_infer/src/infer/relate/generalize.rs @@ -38,6 +38,31 @@ impl From for TermVid { } impl<'tcx> InferCtxt<'tcx> { + fn check_generalized_alias_normalizes_to_tyvar>( + &self, + relation: &mut R, + source_ty: Ty<'tcx>, + ) -> Option> { + if !self.next_trait_solver() + || matches!(relation.structurally_relate_aliases(), StructurallyRelateAliases::Yes) + { + return None; + } + + // If we get an alias + let ty::Alias(_, alias) = source_ty.kind() else { + return None; + }; + + if alias.has_escaping_bound_vars() { + return None; + } + + let normalized_alias = relation.try_eagerly_normalize_alias(*alias); + + normalized_alias.is_ty_var().then_some(normalized_alias) + } + /// The idea is that we should ensure that the type variable `target_vid` /// is equal to, a subtype of, or a supertype of `source_ty`. /// @@ -51,7 +76,7 @@ impl<'tcx> InferCtxt<'tcx> { /// `TypeRelation`. Do not use this, and instead please use `At::eq`, for all /// other usecases (i.e. setting the value of a type var). #[instrument(level = "debug", skip(self, relation))] - pub fn instantiate_ty_var>>( + pub fn instantiate_ty_var>( &self, relation: &mut R, target_is_expected: bool, @@ -61,30 +86,31 @@ impl<'tcx> InferCtxt<'tcx> { ) -> RelateResult<'tcx, ()> { debug_assert!(self.inner.borrow_mut().type_variables().probe(target_vid).is_unknown()); - // Generalize `source_ty` depending on the current variance. As an example, assume - // `?target <: &'x ?1`, where `'x` is some free region and `?1` is an inference - // variable. - // - // Then the `generalized_ty` would be `&'?2 ?3`, where `'?2` and `?3` are fresh - // region/type inference variables. - // - // We then relate `generalized_ty <: source_ty`, adding constraints like `'x: '?2` and - // `?1 <: ?3`. - let Generalization { value_may_be_infer: generalized_ty } = self.generalize( - relation.span(), - relation.structurally_relate_aliases(), - target_vid, - instantiation_variance, - source_ty, - &mut |alias| relation.try_eagerly_normalize_alias(alias), - )?; - - // Constrain `b_vid` to the generalized type `generalized_ty`. - if let &ty::Infer(ty::TyVar(generalized_vid)) = generalized_ty.kind() { - self.inner.borrow_mut().type_variables().equate(target_vid, generalized_vid); - } else { - self.inner.borrow_mut().type_variables().instantiate(target_vid, generalized_ty); - } + let generalized_ty = + match self.check_generalized_alias_normalizes_to_tyvar(relation, source_ty) { + Some(tyvar) => tyvar, + None => { + // Generalize `source_ty` depending on the current variance. As an example, assume + // `?target <: &'x ?1`, where `'x` is some free region and `?1` is an inference + // variable. + // + // Then the `generalized_ty` would be `&'?2 ?3`, where `'?2` and `?3` are fresh + // region/type inference variables. + // + // We then relate `generalized_ty <: source_ty`, adding constraints like `'x: '?2` and + // `?1 <: ?3`. + let generalizer = self.generalize( + relation.span(), + relation.structurally_relate_aliases(), + target_vid, + instantiation_variance, + source_ty, + &mut |alias| relation.try_eagerly_normalize_alias(alias), + )?; + + generalizer.value_may_be_infer + } + }; // Finally, relate `generalized_ty` to `source_ty`, as described in previous comment. // @@ -92,7 +118,10 @@ impl<'tcx> InferCtxt<'tcx> { // relations wind up attributed to the same spans. We need // to associate causes/spans with each of the relations in // the stack to get this right. - if generalized_ty.is_ty_var() { + if let &ty::Infer(ty::TyVar(generalized_vid)) = generalized_ty.kind() { + // Constrain `b_vid` to the generalized type variable. + self.inner.borrow_mut().type_variables().equate(target_vid, generalized_vid); + // This happens for cases like `::Assoc == ?0`. // We can't instantiate `?0` here as that would result in a // cyclic type. We instead delay the unification in case @@ -133,6 +162,9 @@ impl<'tcx> InferCtxt<'tcx> { } } } else { + // Constrain `b_vid` to the generalized type `generalized_ty`. + self.inner.borrow_mut().type_variables().instantiate(target_vid, generalized_ty); + // NOTE: The `instantiation_variance` is not the same variance as // used by the relation. When instantiating `b`, `target_is_expected` // is flipped and the `instantiation_variance` is also flipped. To diff --git a/compiler/rustc_next_trait_solver/src/canonical/canonicalizer.rs b/compiler/rustc_next_trait_solver/src/canonical/canonicalizer.rs index ce2be24adc586..e469451da993e 100644 --- a/compiler/rustc_next_trait_solver/src/canonical/canonicalizer.rs +++ b/compiler/rustc_next_trait_solver/src/canonical/canonicalizer.rs @@ -177,7 +177,11 @@ impl<'a, D: SolverDelegate, I: Interner> Canonicalizer<'a, D, I> { cache: Default::default(), }; let param_env = param_env.fold_with(&mut env_canonicalizer); - debug_assert!(env_canonicalizer.sub_root_lookup_table.is_empty()); + debug_assert!( + env_canonicalizer.sub_root_lookup_table.is_empty(), + "{:?}", + env_canonicalizer.sub_root_lookup_table + ); ( param_env, env_canonicalizer.variables, From e8e3544a71f23606c85e8586e37bd98389bc1ebe Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jana=20D=C3=B6nszelmann?= Date: Tue, 3 Feb 2026 15:14:44 +0100 Subject: [PATCH 08/12] try generalizing if normalization isn't a tyvar --- .../src/infer/relate/generalize.rs | 115 +++++++++--------- 1 file changed, 59 insertions(+), 56 deletions(-) diff --git a/compiler/rustc_infer/src/infer/relate/generalize.rs b/compiler/rustc_infer/src/infer/relate/generalize.rs index 1d4dab0016168..e1d3f4e6bd489 100644 --- a/compiler/rustc_infer/src/infer/relate/generalize.rs +++ b/compiler/rustc_infer/src/infer/relate/generalize.rs @@ -38,31 +38,6 @@ impl From for TermVid { } impl<'tcx> InferCtxt<'tcx> { - fn check_generalized_alias_normalizes_to_tyvar>( - &self, - relation: &mut R, - source_ty: Ty<'tcx>, - ) -> Option> { - if !self.next_trait_solver() - || matches!(relation.structurally_relate_aliases(), StructurallyRelateAliases::Yes) - { - return None; - } - - // If we get an alias - let ty::Alias(_, alias) = source_ty.kind() else { - return None; - }; - - if alias.has_escaping_bound_vars() { - return None; - } - - let normalized_alias = relation.try_eagerly_normalize_alias(*alias); - - normalized_alias.is_ty_var().then_some(normalized_alias) - } - /// The idea is that we should ensure that the type variable `target_vid` /// is equal to, a subtype of, or a supertype of `source_ty`. /// @@ -86,31 +61,53 @@ impl<'tcx> InferCtxt<'tcx> { ) -> RelateResult<'tcx, ()> { debug_assert!(self.inner.borrow_mut().type_variables().probe(target_vid).is_unknown()); - let generalized_ty = - match self.check_generalized_alias_normalizes_to_tyvar(relation, source_ty) { - Some(tyvar) => tyvar, - None => { - // Generalize `source_ty` depending on the current variance. As an example, assume - // `?target <: &'x ?1`, where `'x` is some free region and `?1` is an inference - // variable. - // - // Then the `generalized_ty` would be `&'?2 ?3`, where `'?2` and `?3` are fresh - // region/type inference variables. - // - // We then relate `generalized_ty <: source_ty`, adding constraints like `'x: '?2` and - // `?1 <: ?3`. - let generalizer = self.generalize( - relation.span(), - relation.structurally_relate_aliases(), - target_vid, - instantiation_variance, - source_ty, - &mut |alias| relation.try_eagerly_normalize_alias(alias), - )?; - - generalizer.value_may_be_infer - } - }; + let generalized_ty = if self.next_trait_solver() + && matches!(relation.structurally_relate_aliases(), StructurallyRelateAliases::No) + && let ty::Alias(_, alias) = source_ty.kind() + { + let normalized_alias = relation.try_eagerly_normalize_alias(*alias); + + if normalized_alias.is_ty_var() { + normalized_alias + } else { + let Generalization { value_may_be_infer: generalized_ty } = self.generalize( + relation.span(), + GeneralizerState::ShallowStructurallyRelateAliases, + target_vid, + instantiation_variance, + normalized_alias, + &mut |alias| relation.try_eagerly_normalize_alias(alias), + )?; + + // The only way to get a tyvar back is if the outermost type is an alias. + // However, here, though we know it *is* an alias, we initialize the generalizer + // with `ShallowStructurallyRelateAliases` so we treat the outermost alias as rigid, + // ensuring this is never a tyvar. + assert!(!generalized_ty.is_ty_var()); + + generalized_ty + } + } else { + // Generalize `source_ty` depending on the current variance. As an example, assume + // `?target <: &'x ?1`, where `'x` is some free region and `?1` is an inference + // variable. + // + // Then the `generalized_ty` would be `&'?2 ?3`, where `'?2` and `?3` are fresh + // region/type inference variables. + // + // We then relate `generalized_ty <: source_ty`, adding constraints like `'x: '?2` and + // `?1 <: ?3`. + let Generalization { value_may_be_infer: generalized_ty } = self.generalize( + relation.span(), + relation.structurally_relate_aliases().into(), + target_vid, + instantiation_variance, + source_ty, + &mut |alias| relation.try_eagerly_normalize_alias(alias), + )?; + + generalized_ty + }; // Finally, relate `generalized_ty` to `source_ty`, as described in previous comment. // @@ -239,7 +236,7 @@ impl<'tcx> InferCtxt<'tcx> { // constants and generic expressions are not yet handled correctly. let Generalization { value_may_be_infer: generalized_ct } = self.generalize( relation.span(), - relation.structurally_relate_aliases(), + relation.structurally_relate_aliases().into(), target_vid, ty::Invariant, source_ct, @@ -279,7 +276,7 @@ impl<'tcx> InferCtxt<'tcx> { fn generalize> + Relate>>( &self, span: Span, - structurally_relate_aliases: StructurallyRelateAliases, + initial_state: GeneralizerState, target_vid: impl Into, ambient_variance: ty::Variance, source_term: T, @@ -303,10 +300,7 @@ impl<'tcx> InferCtxt<'tcx> { for_universe, root_term: source_term.into(), ambient_variance, - state: match structurally_relate_aliases { - StructurallyRelateAliases::No => GeneralizerState::Default, - StructurallyRelateAliases::Yes => GeneralizerState::StructurallyRelateAliases, - }, + state: initial_state, cache: Default::default(), normalize, }; @@ -365,6 +359,15 @@ enum GeneralizerState { StructurallyRelateAliases, } +impl From for GeneralizerState { + fn from(structurally_relate_aliases: StructurallyRelateAliases) -> Self { + match structurally_relate_aliases { + StructurallyRelateAliases::No => GeneralizerState::Default, + StructurallyRelateAliases::Yes => GeneralizerState::StructurallyRelateAliases, + } + } +} + /// The "generalizer" is used when handling inference variables. /// /// The basic strategy for handling a constraint like `?A <: B` is to From 2d411a0faad447b5bfc968b954fd3e9c10596325 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jana=20D=C3=B6nszelmann?= Date: Thu, 5 Feb 2026 11:35:47 +0100 Subject: [PATCH 09/12] fixup span in obligation cause --- compiler/rustc_trait_selection/src/solve.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/rustc_trait_selection/src/solve.rs b/compiler/rustc_trait_selection/src/solve.rs index cb02885139038..118bd8c81b1e7 100644 --- a/compiler/rustc_trait_selection/src/solve.rs +++ b/compiler/rustc_trait_selection/src/solve.rs @@ -57,7 +57,7 @@ fn try_eagerly_normalize_alias<'a, 'tcx>( let obligation = Obligation::new( tcx, // we ignore the error anyway - ObligationCause::dummy(), + ObligationCause::dummy_with_span(span), param_env, ty::PredicateKind::AliasRelate( alias.to_ty(tcx).into(), From 6edf58fab80d713b5e017d98a57c4075c12b833e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jana=20D=C3=B6nszelmann?= Date: Mon, 2 Feb 2026 19:31:10 +0100 Subject: [PATCH 10/12] bless some tests --- .../impl-trait/unsized_coercion.next.stderr | 11 ------ tests/ui/impl-trait/unsized_coercion.rs | 2 +- .../impl-trait/unsized_coercion3.next.stderr | 36 +++++++++++++++++-- .../impl-trait/unsized_coercion3.old.stderr | 2 +- tests/ui/impl-trait/unsized_coercion3.rs | 2 ++ ...id-alias-bound-is-not-inherent.next.stderr | 2 +- ...rg-type-mismatch-issue-45727.current.fixed | 3 +- ...-arg-type-mismatch-issue-45727.next.stderr | 11 ++---- .../closure-arg-type-mismatch-issue-45727.rs | 3 +- 9 files changed, 42 insertions(+), 30 deletions(-) delete mode 100644 tests/ui/impl-trait/unsized_coercion.next.stderr diff --git a/tests/ui/impl-trait/unsized_coercion.next.stderr b/tests/ui/impl-trait/unsized_coercion.next.stderr deleted file mode 100644 index bea5ddb0aefcc..0000000000000 --- a/tests/ui/impl-trait/unsized_coercion.next.stderr +++ /dev/null @@ -1,11 +0,0 @@ -error[E0277]: the size for values of type `dyn Trait` cannot be known at compilation time - --> $DIR/unsized_coercion.rs:14:17 - | -LL | let x = hello(); - | ^^^^^^^ doesn't have a size known at compile-time - | - = help: the trait `Sized` is not implemented for `dyn Trait` - -error: aborting due to 1 previous error - -For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/impl-trait/unsized_coercion.rs b/tests/ui/impl-trait/unsized_coercion.rs index 2cbf0d25d7ec6..6a9a53903fed3 100644 --- a/tests/ui/impl-trait/unsized_coercion.rs +++ b/tests/ui/impl-trait/unsized_coercion.rs @@ -4,6 +4,7 @@ //@ revisions: next old //@[next] compile-flags: -Znext-solver //@[old] check-pass +//@[next] check-pass trait Trait {} @@ -12,7 +13,6 @@ impl Trait for u32 {} fn hello() -> Box { if true { let x = hello(); - //[next]~^ ERROR: the size for values of type `dyn Trait` cannot be known at compilation time let y: Box = x; } Box::new(1u32) diff --git a/tests/ui/impl-trait/unsized_coercion3.next.stderr b/tests/ui/impl-trait/unsized_coercion3.next.stderr index a480a69a38641..db758761d7954 100644 --- a/tests/ui/impl-trait/unsized_coercion3.next.stderr +++ b/tests/ui/impl-trait/unsized_coercion3.next.stderr @@ -1,5 +1,5 @@ error[E0277]: the trait bound `dyn Send: Trait` is not satisfied - --> $DIR/unsized_coercion3.rs:13:17 + --> $DIR/unsized_coercion3.rs:14:17 | LL | let x = hello(); | ^^^^^^^ the trait `Trait` is not implemented for `dyn Send` @@ -9,7 +9,37 @@ help: the trait `Trait` is implemented for `u32` | LL | impl Trait for u32 {} | ^^^^^^^^^^^^^^^^^^ +note: required by a bound in `Box` + --> $SRC_DIR/alloc/src/boxed.rs:LL:COL -error: aborting due to 1 previous error +error[E0308]: mismatched types + --> $DIR/unsized_coercion3.rs:19:5 + | +LL | fn hello() -> Box { + | ------------------------ + | | | + | | the expected opaque type + | expected `Box` because of return type +... +LL | Box::new(1u32) + | ^^^^^^^^^^^^^^ types differ + | + = note: expected struct `Box` + found struct `Box` + +error[E0277]: the trait bound `dyn Send: Trait` is not satisfied + --> $DIR/unsized_coercion3.rs:11:1 + | +LL | fn hello() -> Box { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Trait` is not implemented for `dyn Send` + | +help: the trait `Trait` is implemented for `u32` + --> $DIR/unsized_coercion3.rs:9:1 + | +LL | impl Trait for u32 {} + | ^^^^^^^^^^^^^^^^^^ + +error: aborting due to 3 previous errors -For more information about this error, try `rustc --explain E0277`. +Some errors have detailed explanations: E0277, E0308. +For more information about an error, try `rustc --explain E0277`. diff --git a/tests/ui/impl-trait/unsized_coercion3.old.stderr b/tests/ui/impl-trait/unsized_coercion3.old.stderr index 52a72b84a8dd6..3bb9f9c209510 100644 --- a/tests/ui/impl-trait/unsized_coercion3.old.stderr +++ b/tests/ui/impl-trait/unsized_coercion3.old.stderr @@ -1,5 +1,5 @@ error[E0277]: the size for values of type `impl Trait + ?Sized` cannot be known at compilation time - --> $DIR/unsized_coercion3.rs:15:32 + --> $DIR/unsized_coercion3.rs:16:32 | LL | let y: Box = x; | ^ doesn't have a size known at compile-time diff --git a/tests/ui/impl-trait/unsized_coercion3.rs b/tests/ui/impl-trait/unsized_coercion3.rs index ebfbb2955de55..c1dd5350e229a 100644 --- a/tests/ui/impl-trait/unsized_coercion3.rs +++ b/tests/ui/impl-trait/unsized_coercion3.rs @@ -9,6 +9,7 @@ trait Trait {} impl Trait for u32 {} fn hello() -> Box { + //[next]~^ ERROR: the trait bound `dyn Send: Trait` is not satisfied if true { let x = hello(); //[next]~^ ERROR: the trait bound `dyn Send: Trait` is not satisfied @@ -16,6 +17,7 @@ fn hello() -> Box { //[old]~^ ERROR: the size for values of type `impl Trait + ?Sized` cannot be know } Box::new(1u32) + //[next]~^ ERROR: mismatched types } fn main() {} diff --git a/tests/ui/methods/rigid-alias-bound-is-not-inherent.next.stderr b/tests/ui/methods/rigid-alias-bound-is-not-inherent.next.stderr index afacb3a7d5213..4652bf5e3c586 100644 --- a/tests/ui/methods/rigid-alias-bound-is-not-inherent.next.stderr +++ b/tests/ui/methods/rigid-alias-bound-is-not-inherent.next.stderr @@ -9,7 +9,7 @@ note: candidate #1 is defined in the trait `Trait1` | LL | fn method(&self) { | ^^^^^^^^^^^^^^^^ -note: candidate #2 is defined in the trait `Trait2` +note: candidate #2 is defined in an impl of the trait `Trait2` for the type `T` --> $DIR/rigid-alias-bound-is-not-inherent.rs:27:5 | LL | fn method(&self) { diff --git a/tests/ui/mismatched_types/closure-arg-type-mismatch-issue-45727.current.fixed b/tests/ui/mismatched_types/closure-arg-type-mismatch-issue-45727.current.fixed index ba46a447802c8..1c45a2c0adb3e 100644 --- a/tests/ui/mismatched_types/closure-arg-type-mismatch-issue-45727.current.fixed +++ b/tests/ui/mismatched_types/closure-arg-type-mismatch-issue-45727.current.fixed @@ -8,6 +8,5 @@ fn main() { //[next]~^^ ERROR expected a `FnMut(& as Iterator>::Item)` closure, found let _ = (-10..=10).find(|x: &i32| x.signum() == 0); //[current]~^ ERROR type mismatch in closure arguments - //[next]~^^ ERROR expected `RangeInclusive<{integer}>` to be an iterator that yields `&&i32`, but it yields `{integer}` - //[next]~| ERROR expected a `FnMut(& as Iterator>::Item)` closure, found + //[next]~^^ ERROR expected a `FnMut(& as Iterator>::Item)` closure, found } diff --git a/tests/ui/mismatched_types/closure-arg-type-mismatch-issue-45727.next.stderr b/tests/ui/mismatched_types/closure-arg-type-mismatch-issue-45727.next.stderr index 7912ed4d7071a..36e49c20c4331 100644 --- a/tests/ui/mismatched_types/closure-arg-type-mismatch-issue-45727.next.stderr +++ b/tests/ui/mismatched_types/closure-arg-type-mismatch-issue-45727.next.stderr @@ -12,12 +12,6 @@ LL | let _ = (-10..=10).find(|x: i32| x.signum() == 0); note: required by a bound in `find` --> $SRC_DIR/core/src/iter/traits/iterator.rs:LL:COL -error[E0271]: expected `RangeInclusive<{integer}>` to be an iterator that yields `&&i32`, but it yields `{integer}` - --> $DIR/closure-arg-type-mismatch-issue-45727.rs:9:24 - | -LL | let _ = (-10..=10).find(|x: &&&i32| x.signum() == 0); - | ^^^^ expected `&&i32`, found integer - error[E0277]: expected a `FnMut(& as Iterator>::Item)` closure, found `{closure@$DIR/closure-arg-type-mismatch-issue-45727.rs:9:29: 9:40}` --> $DIR/closure-arg-type-mismatch-issue-45727.rs:9:29 | @@ -32,7 +26,6 @@ LL | let _ = (-10..=10).find(|x: &&&i32| x.signum() == 0); note: required by a bound in `find` --> $SRC_DIR/core/src/iter/traits/iterator.rs:LL:COL -error: aborting due to 3 previous errors +error: aborting due to 2 previous errors -Some errors have detailed explanations: E0271, E0277. -For more information about an error, try `rustc --explain E0271`. +For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/mismatched_types/closure-arg-type-mismatch-issue-45727.rs b/tests/ui/mismatched_types/closure-arg-type-mismatch-issue-45727.rs index 0fd56707763e9..20d6fed3b35b8 100644 --- a/tests/ui/mismatched_types/closure-arg-type-mismatch-issue-45727.rs +++ b/tests/ui/mismatched_types/closure-arg-type-mismatch-issue-45727.rs @@ -8,6 +8,5 @@ fn main() { //[next]~^^ ERROR expected a `FnMut(& as Iterator>::Item)` closure, found let _ = (-10..=10).find(|x: &&&i32| x.signum() == 0); //[current]~^ ERROR type mismatch in closure arguments - //[next]~^^ ERROR expected `RangeInclusive<{integer}>` to be an iterator that yields `&&i32`, but it yields `{integer}` - //[next]~| ERROR expected a `FnMut(& as Iterator>::Item)` closure, found + //[next]~^^ ERROR expected a `FnMut(& as Iterator>::Item)` closure, found } From 9aa065bc49e5c9a0e07dbfc4bb0823821e5f130d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jana=20D=C3=B6nszelmann?= Date: Mon, 9 Feb 2026 12:31:37 +0100 Subject: [PATCH 11/12] inline into --- .../src/infer/relate/generalize.rs | 19 ++++++++----------- 1 file changed, 8 insertions(+), 11 deletions(-) diff --git a/compiler/rustc_infer/src/infer/relate/generalize.rs b/compiler/rustc_infer/src/infer/relate/generalize.rs index e1d3f4e6bd489..f3843c371e2ca 100644 --- a/compiler/rustc_infer/src/infer/relate/generalize.rs +++ b/compiler/rustc_infer/src/infer/relate/generalize.rs @@ -99,7 +99,10 @@ impl<'tcx> InferCtxt<'tcx> { // `?1 <: ?3`. let Generalization { value_may_be_infer: generalized_ty } = self.generalize( relation.span(), - relation.structurally_relate_aliases().into(), + match relation.structurally_relate_aliases() { + StructurallyRelateAliases::No => GeneralizerState::Default, + StructurallyRelateAliases::Yes => GeneralizerState::StructurallyRelateAliases, + }, target_vid, instantiation_variance, source_ty, @@ -236,7 +239,10 @@ impl<'tcx> InferCtxt<'tcx> { // constants and generic expressions are not yet handled correctly. let Generalization { value_may_be_infer: generalized_ct } = self.generalize( relation.span(), - relation.structurally_relate_aliases().into(), + match relation.structurally_relate_aliases() { + StructurallyRelateAliases::No => GeneralizerState::Default, + StructurallyRelateAliases::Yes => GeneralizerState::StructurallyRelateAliases, + }, target_vid, ty::Invariant, source_ct, @@ -359,15 +365,6 @@ enum GeneralizerState { StructurallyRelateAliases, } -impl From for GeneralizerState { - fn from(structurally_relate_aliases: StructurallyRelateAliases) -> Self { - match structurally_relate_aliases { - StructurallyRelateAliases::No => GeneralizerState::Default, - StructurallyRelateAliases::Yes => GeneralizerState::StructurallyRelateAliases, - } - } -} - /// The "generalizer" is used when handling inference variables. /// /// The basic strategy for handling a constraint like `?A <: B` is to From 1adea683d64928ee6668d0306c8ab0fdb2884fed Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jana=20D=C3=B6nszelmann?= Date: Mon, 9 Feb 2026 12:44:14 +0100 Subject: [PATCH 12/12] address review --- .../src/infer/relate/generalize.rs | 61 +++++++++++-------- compiler/rustc_middle/src/hooks/mod.rs | 7 ++- compiler/rustc_trait_selection/src/solve.rs | 6 +- tests/ui/impl-trait/unsized_coercion.rs | 3 +- 4 files changed, 44 insertions(+), 33 deletions(-) diff --git a/compiler/rustc_infer/src/infer/relate/generalize.rs b/compiler/rustc_infer/src/infer/relate/generalize.rs index f3843c371e2ca..82a91538c4dae 100644 --- a/compiler/rustc_infer/src/infer/relate/generalize.rs +++ b/compiler/rustc_infer/src/infer/relate/generalize.rs @@ -613,26 +613,30 @@ impl<'tcx> TypeRelation> for Generalizer<'_, 'tcx> { // of each other. This is currently only used for diagnostics. // To see why, see the docs in the `type_variables` module. inner.type_variables().sub_unify(vid, new_var_id); - // If we're in the new solver and create a new inference - // variable inside of an alias we eagerly constrain that - // inference variable to prevent unexpected ambiguity errors. - // - // This is incomplete as it pulls down the universe of the - // original inference variable, even though the alias could - // normalize to a type which does not refer to that type at - // all. I don't expect this to cause unexpected errors in - // practice. - // - // We only need to do so for type and const variables, as - // region variables do not impact normalization, and will get - // correctly constrained by `AliasRelate` later on. - // - // cc trait-system-refactor-initiative#108 - if self.infcx.next_trait_solver() - && !matches!(self.infcx.typing_mode(), TypingMode::Coherence) - { - match self.state { - GeneralizerState::IncompletelyRelateHigherRankedAlias => { + + match self.state { + GeneralizerState::IncompletelyRelateHigherRankedAlias => { + if self.infcx.next_trait_solver() + && !matches!( + self.infcx.typing_mode(), + TypingMode::Coherence + ) + { + // If we're in the new solver and create a new inference + // variable inside of an alias we eagerly constrain that + // inference variable to prevent unexpected ambiguity errors. + // + // This is incomplete as it pulls down the universe of the + // original inference variable, even though the alias could + // normalize to a type which does not refer to that type at + // all. I don't expect this to cause unexpected errors in + // practice. + // + // We only need to do so for type and const variables, as + // region variables do not impact normalization, and will get + // correctly constrained by `AliasRelate` later on. + // + // cc trait-system-refactor-initiative#108 inner.type_variables().equate(vid, new_var_id); } } @@ -759,13 +763,16 @@ impl<'tcx> TypeRelation> for Generalizer<'_, 'tcx> { }) .vid; - // See the comment for type inference variables - // for more details. - if self.infcx.next_trait_solver() - && !matches!(self.infcx.typing_mode(), TypingMode::Coherence) - { - match self.state { - GeneralizerState::IncompletelyRelateHigherRankedAlias => { + match self.state { + GeneralizerState::IncompletelyRelateHigherRankedAlias => { + // See the comment for type inference variables + // for more details. + if self.infcx.next_trait_solver() + && !matches!( + self.infcx.typing_mode(), + TypingMode::Coherence + ) + { variable_table.union(vid, new_var_id); } } diff --git a/compiler/rustc_middle/src/hooks/mod.rs b/compiler/rustc_middle/src/hooks/mod.rs index c09d9fc2d468d..044a9c3ef165f 100644 --- a/compiler/rustc_middle/src/hooks/mod.rs +++ b/compiler/rustc_middle/src/hooks/mod.rs @@ -132,7 +132,12 @@ declare_hooks! { ) -> Ty<'tcx>; } -// `repr(transparent)` so we can transmute a `&'a Infcx<'tcx>` to this struct. +/// The `try_eagerly_normalize_alias` hook passes an `Infcx` from where it's called (in `rustc_infer`) +/// to where it's provided (in `rustc_trait_selection`). +/// Both of those crates have that type available, but `rustc_middle` does not. +/// Instead we pass this type-erased `Infcx` and transmute on both sides. +/// +/// Has to be `repr(transparent)` so we can transmute a `&'a Infcx<'tcx>` to this struct. #[repr(transparent)] pub struct TypeErasedInfcx<'a, 'tcx> { _infcx: *const (), diff --git a/compiler/rustc_trait_selection/src/solve.rs b/compiler/rustc_trait_selection/src/solve.rs index 118bd8c81b1e7..c7699f31a0f95 100644 --- a/compiler/rustc_trait_selection/src/solve.rs +++ b/compiler/rustc_trait_selection/src/solve.rs @@ -56,8 +56,7 @@ fn try_eagerly_normalize_alias<'a, 'tcx>( let cause = ObligationCause::dummy_with_span(span); let obligation = Obligation::new( tcx, - // we ignore the error anyway - ObligationCause::dummy_with_span(span), + cause, param_env, ty::PredicateKind::AliasRelate( alias.to_ty(tcx).into(), @@ -68,7 +67,8 @@ fn try_eagerly_normalize_alias<'a, 'tcx>( ocx.register_obligation(obligation); - // This only tries to eagerly resolve, if it errors we don't care. + // We only use this to constrain inference variables. + // We don't care if it errors. let _ = ocx.try_evaluate_obligations(); infcx.resolve_vars_if_possible(infer_term) diff --git a/tests/ui/impl-trait/unsized_coercion.rs b/tests/ui/impl-trait/unsized_coercion.rs index 6a9a53903fed3..f77f2198be0ef 100644 --- a/tests/ui/impl-trait/unsized_coercion.rs +++ b/tests/ui/impl-trait/unsized_coercion.rs @@ -3,8 +3,7 @@ //@ revisions: next old //@[next] compile-flags: -Znext-solver -//@[old] check-pass -//@[next] check-pass +//@ check-pass trait Trait {}