From 1fa1611e9fa6315254c9202ab2874e67b65f68b1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jana=20D=C3=B6nszelmann?= Date: Mon, 23 Mar 2026 12:09:34 +0100 Subject: [PATCH 01/12] Revert "address review" This reverts commit d665c0b3718dc582189a85dc1d49e641d22e9e21. --- .../src/infer/relate/generalize.rs | 72 +++++-------------- 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, 23 insertions(+), 65 deletions(-) diff --git a/compiler/rustc_infer/src/infer/relate/generalize.rs b/compiler/rustc_infer/src/infer/relate/generalize.rs index b2d591327fea2..f3843c371e2ca 100644 --- a/compiler/rustc_infer/src/infer/relate/generalize.rs +++ b/compiler/rustc_infer/src/infer/relate/generalize.rs @@ -355,51 +355,13 @@ impl<'tcx> TypeVisitor> for MaxUniverse { } } -/// This state determines how generalization treats aliases. -/// -/// Based on which state we're in, we treat them either as rigid or normalizable, -/// which might change depending on what types the generalization visitor encounters. -/// See `handle_alias_ty` for the logic of how we change states. #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] enum GeneralizerState { /// Treat aliases as potentially normalizable. - /// - /// This is the default state that generalization starts in, unless we're - /// treating aliases as rigid. It also means we're not currently inside an - /// alias, since then we change the state to `IncompletelyRelateAliasArgs`. Default, - /// We enter this state when we're generalizing the arguments of a - /// potentially normalizeable alias. - /// - /// The behavior here is different between the old and the new solver: - /// - /// In the old solver, the difference between this and `Default` is needed to - /// correctly handle `::Assoc>::Assoc == ?0`. That - /// equality can hold by either normalizing the outer or the inner - /// associated type. In the old solver, we always structurally relate - /// aliases. If we we encounter an occurs check failure, we propagate the - /// failure to the outermost alias, for which we then emit a `Projection` - /// goal instead. - /// - /// In the new solver, we rarely get into this state. - /// When we encounter aliases we instead attempt to normalize them, and treat - /// them as rigid using `ShallowStructurallyRelate`. Only when an alias has - /// escaping bound variables do we continue with similar logic to the old - /// solver, except now we also explicitly relate the type and consts in the - /// arguments of aliases while in this mode. - /// - /// FIXME: Because we relate the type and consts in the arguments of aliases - /// while in this mode, this is incomplete. - IncompletelyRelateAliasArgs, - /// During generalization, when we encounter aliases, we will first attempt - /// to normalize them when we're using the next trait solver. We can now - /// treat the normalized alias as rigid, but only for "one layer", hence - /// shallow. New aliases encountered inside the arguments of the outer alias - /// should once again be related as normal. + IncompletelyRelateHigherRankedAlias, + /// Only one layer ShallowStructurallyRelateAliases, - /// Treat aliases as rigid when relating them. - /// - /// This corresponds to `relation.structurally_relate_aliases()`. StructurallyRelateAliases, } @@ -438,10 +400,11 @@ struct Generalizer<'me, 'tcx> { /// some other type. What will be the variance at this point? ambient_variance: ty::Variance, - /// This field keeps track of how we treat aliases during generalization. + /// This is set once we're generalizing the arguments of an alias. /// - /// Refer to [`GeneralizerState`]'s docs for more information about the - /// all the possible values this can have, and when we use which. + /// This is necessary to correctly handle + /// `::Assoc>::Assoc == ?0`. This equality can + /// hold by either normalizing the outer or the inner associated type. state: GeneralizerState, cache: SsoHashMap<(Ty<'tcx>, ty::Variance, GeneralizerState), Ty<'tcx>>, @@ -520,11 +483,11 @@ impl<'tcx> Generalizer<'_, 'tcx> { return res; } - GeneralizerState::Default | GeneralizerState::IncompletelyRelateAliasArgs => {} + GeneralizerState::Default | GeneralizerState::IncompletelyRelateHigherRankedAlias => {} } let previous_state = - mem::replace(&mut self.state, GeneralizerState::IncompletelyRelateAliasArgs); + 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 { @@ -541,7 +504,7 @@ impl<'tcx> Generalizer<'_, 'tcx> { debug!("generalization failure in alias"); Ok(self.next_ty_var_for_alias()) } - GeneralizerState::IncompletelyRelateAliasArgs => return Err(e), + GeneralizerState::IncompletelyRelateHigherRankedAlias => return Err(e), // Early return. GeneralizerState::ShallowStructurallyRelateAliases @@ -650,7 +613,6 @@ 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. @@ -670,13 +632,13 @@ impl<'tcx> TypeRelation> for Generalizer<'_, 'tcx> { && !matches!(self.infcx.typing_mode(), TypingMode::Coherence) { match self.state { - GeneralizerState::IncompletelyRelateAliasArgs => { + GeneralizerState::IncompletelyRelateHigherRankedAlias => { inner.type_variables().equate(vid, new_var_id); } - GeneralizerState::Default - | GeneralizerState::ShallowStructurallyRelateAliases - | GeneralizerState::StructurallyRelateAliases => {} } + GeneralizerState::Default + | GeneralizerState::ShallowStructurallyRelateAliases + | GeneralizerState::StructurallyRelateAliases => {} } debug!("replacing original vid={:?} with new={:?}", vid, new_var_id); @@ -803,13 +765,13 @@ impl<'tcx> TypeRelation> for Generalizer<'_, 'tcx> { && !matches!(self.infcx.typing_mode(), TypingMode::Coherence) { match self.state { - GeneralizerState::IncompletelyRelateAliasArgs => { + GeneralizerState::IncompletelyRelateHigherRankedAlias => { variable_table.union(vid, new_var_id); } - GeneralizerState::Default - | GeneralizerState::ShallowStructurallyRelateAliases - | GeneralizerState::StructurallyRelateAliases => {} } + GeneralizerState::Default + | GeneralizerState::ShallowStructurallyRelateAliases + | GeneralizerState::StructurallyRelateAliases => {} } Ok(ty::Const::new_var(self.cx(), new_var_id)) } diff --git a/compiler/rustc_middle/src/hooks/mod.rs b/compiler/rustc_middle/src/hooks/mod.rs index 1f339ea0cabf6..0caa8dcbc9c64 100644 --- a/compiler/rustc_middle/src/hooks/mod.rs +++ b/compiler/rustc_middle/src/hooks/mod.rs @@ -130,12 +130,7 @@ declare_hooks! { ) -> Ty<'tcx>; } -/// 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)` 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 c7699f31a0f95..118bd8c81b1e7 100644 --- a/compiler/rustc_trait_selection/src/solve.rs +++ b/compiler/rustc_trait_selection/src/solve.rs @@ -56,7 +56,8 @@ fn try_eagerly_normalize_alias<'a, 'tcx>( let cause = ObligationCause::dummy_with_span(span); let obligation = Obligation::new( tcx, - cause, + // we ignore the error anyway + ObligationCause::dummy_with_span(span), param_env, ty::PredicateKind::AliasRelate( alias.to_ty(tcx).into(), @@ -67,8 +68,7 @@ fn try_eagerly_normalize_alias<'a, 'tcx>( ocx.register_obligation(obligation); - // We only use this to constrain inference variables. - // We don't care if it errors. + // 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) diff --git a/tests/ui/impl-trait/unsized_coercion.rs b/tests/ui/impl-trait/unsized_coercion.rs index f77f2198be0ef..6a9a53903fed3 100644 --- a/tests/ui/impl-trait/unsized_coercion.rs +++ b/tests/ui/impl-trait/unsized_coercion.rs @@ -3,7 +3,8 @@ //@ revisions: next old //@[next] compile-flags: -Znext-solver -//@ check-pass +//@[old] check-pass +//@[next] check-pass trait Trait {} From bd781549f2583d6ae7e141cc6adeff443ec9b02d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jana=20D=C3=B6nszelmann?= Date: Mon, 23 Mar 2026 12:09:34 +0100 Subject: [PATCH 02/12] Revert "inline into" This reverts commit 9aa065bc49e5c9a0e07dbfc4bb0823821e5f130d. --- .../src/infer/relate/generalize.rs | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/compiler/rustc_infer/src/infer/relate/generalize.rs b/compiler/rustc_infer/src/infer/relate/generalize.rs index f3843c371e2ca..e1d3f4e6bd489 100644 --- a/compiler/rustc_infer/src/infer/relate/generalize.rs +++ b/compiler/rustc_infer/src/infer/relate/generalize.rs @@ -99,10 +99,7 @@ impl<'tcx> InferCtxt<'tcx> { // `?1 <: ?3`. let Generalization { value_may_be_infer: generalized_ty } = self.generalize( relation.span(), - match relation.structurally_relate_aliases() { - StructurallyRelateAliases::No => GeneralizerState::Default, - StructurallyRelateAliases::Yes => GeneralizerState::StructurallyRelateAliases, - }, + relation.structurally_relate_aliases().into(), target_vid, instantiation_variance, source_ty, @@ -239,10 +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(), - match relation.structurally_relate_aliases() { - StructurallyRelateAliases::No => GeneralizerState::Default, - StructurallyRelateAliases::Yes => GeneralizerState::StructurallyRelateAliases, - }, + relation.structurally_relate_aliases().into(), target_vid, ty::Invariant, source_ct, @@ -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 e613b82e4eaed11edddfc90024a5e51c807ece42 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jana=20D=C3=B6nszelmann?= Date: Mon, 23 Mar 2026 12:09:34 +0100 Subject: [PATCH 03/12] Revert "bless some tests" This reverts commit 6edf58fab80d713b5e017d98a57c4075c12b833e. --- .../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, 30 insertions(+), 42 deletions(-) create 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 new file mode 100644 index 0000000000000..bea5ddb0aefcc --- /dev/null +++ b/tests/ui/impl-trait/unsized_coercion.next.stderr @@ -0,0 +1,11 @@ +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 6a9a53903fed3..2cbf0d25d7ec6 100644 --- a/tests/ui/impl-trait/unsized_coercion.rs +++ b/tests/ui/impl-trait/unsized_coercion.rs @@ -4,7 +4,6 @@ //@ revisions: next old //@[next] compile-flags: -Znext-solver //@[old] check-pass -//@[next] check-pass trait Trait {} @@ -13,6 +12,7 @@ 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 db758761d7954..a480a69a38641 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:14:17 + --> $DIR/unsized_coercion3.rs:13:17 | LL | let x = hello(); | ^^^^^^^ the trait `Trait` is not implemented for `dyn Send` @@ -9,37 +9,7 @@ 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[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 +error: aborting due to 1 previous error -Some errors have detailed explanations: E0277, E0308. -For more information about an error, try `rustc --explain E0277`. +For more information about this 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 3bb9f9c209510..52a72b84a8dd6 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:16:32 + --> $DIR/unsized_coercion3.rs:15: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 c1dd5350e229a..ebfbb2955de55 100644 --- a/tests/ui/impl-trait/unsized_coercion3.rs +++ b/tests/ui/impl-trait/unsized_coercion3.rs @@ -9,7 +9,6 @@ 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 @@ -17,7 +16,6 @@ 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 4652bf5e3c586..afacb3a7d5213 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 an impl of the trait `Trait2` for the type `T` +note: candidate #2 is defined in the trait `Trait2` --> $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 1c45a2c0adb3e..ba46a447802c8 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,5 +8,6 @@ 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 a `FnMut(& as Iterator>::Item)` closure, found + //[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 } 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 36e49c20c4331..7912ed4d7071a 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,6 +12,12 @@ 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 | @@ -26,6 +32,7 @@ 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 2 previous errors +error: aborting due to 3 previous errors -For more information about this error, try `rustc --explain E0277`. +Some errors have detailed explanations: E0271, E0277. +For more information about an error, try `rustc --explain E0271`. diff --git a/tests/ui/mismatched_types/closure-arg-type-mismatch-issue-45727.rs b/tests/ui/mismatched_types/closure-arg-type-mismatch-issue-45727.rs index 20d6fed3b35b8..0fd56707763e9 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,5 +8,6 @@ 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 a `FnMut(& as Iterator>::Item)` closure, found + //[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 } From 304a197ba5d18bf837f822f8f9d7a7a3f3e3c897 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jana=20D=C3=B6nszelmann?= Date: Mon, 23 Mar 2026 12:09:34 +0100 Subject: [PATCH 04/12] Revert "fixup span in obligation cause" This reverts commit 2d411a0faad447b5bfc968b954fd3e9c10596325. --- 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 118bd8c81b1e7..cb02885139038 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_with_span(span), + ObligationCause::dummy(), param_env, ty::PredicateKind::AliasRelate( alias.to_ty(tcx).into(), From 38cb40091c08bf821745151ab65b3d51e02609b9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jana=20D=C3=B6nszelmann?= Date: Mon, 23 Mar 2026 12:09:34 +0100 Subject: [PATCH 05/12] Revert "try generalizing if normalization isn't a tyvar" This reverts commit e8e3544a71f23606c85e8586e37bd98389bc1ebe. --- .../src/infer/relate/generalize.rs | 115 +++++++++--------- 1 file changed, 56 insertions(+), 59 deletions(-) diff --git a/compiler/rustc_infer/src/infer/relate/generalize.rs b/compiler/rustc_infer/src/infer/relate/generalize.rs index e1d3f4e6bd489..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`. /// @@ -61,53 +86,31 @@ impl<'tcx> InferCtxt<'tcx> { ) -> RelateResult<'tcx, ()> { debug_assert!(self.inner.borrow_mut().type_variables().probe(target_vid).is_unknown()); - 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 - }; + 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. // @@ -236,7 +239,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().into(), + relation.structurally_relate_aliases(), target_vid, ty::Invariant, source_ct, @@ -276,7 +279,7 @@ impl<'tcx> InferCtxt<'tcx> { fn generalize> + Relate>>( &self, span: Span, - initial_state: GeneralizerState, + structurally_relate_aliases: StructurallyRelateAliases, target_vid: impl Into, ambient_variance: ty::Variance, source_term: T, @@ -300,7 +303,10 @@ impl<'tcx> InferCtxt<'tcx> { for_universe, root_term: source_term.into(), ambient_variance, - state: initial_state, + state: match structurally_relate_aliases { + StructurallyRelateAliases::No => GeneralizerState::Default, + StructurallyRelateAliases::Yes => GeneralizerState::StructurallyRelateAliases, + }, cache: Default::default(), normalize, }; @@ -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 c838deca23cca696e00dd999beca5dedccd41180 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jana=20D=C3=B6nszelmann?= Date: Mon, 23 Mar 2026 12:09:34 +0100 Subject: [PATCH 06/12] Revert "normalize at the start of generalize if we can" This reverts commit f50591fc1059d98ba57c79094f6e2d46db4b25b6. --- .../src/infer/relate/generalize.rs | 84 ++++++------------- .../src/canonical/canonicalizer.rs | 6 +- 2 files changed, 27 insertions(+), 63 deletions(-) diff --git a/compiler/rustc_infer/src/infer/relate/generalize.rs b/compiler/rustc_infer/src/infer/relate/generalize.rs index 1d4dab0016168..d5c0726ed9a88 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`. /// @@ -76,7 +51,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, @@ -86,31 +61,30 @@ 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 - } - }; + // 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); + } // Finally, relate `generalized_ty` to `source_ty`, as described in previous comment. // @@ -118,10 +92,7 @@ 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 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); - + if generalized_ty.is_ty_var() { // 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 @@ -162,9 +133,6 @@ 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 e469451da993e..ce2be24adc586 100644 --- a/compiler/rustc_next_trait_solver/src/canonical/canonicalizer.rs +++ b/compiler/rustc_next_trait_solver/src/canonical/canonicalizer.rs @@ -177,11 +177,7 @@ 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(), - "{:?}", - env_canonicalizer.sub_root_lookup_table - ); + debug_assert!(env_canonicalizer.sub_root_lookup_table.is_empty()); ( param_env, env_canonicalizer.variables, From df0f627bfc983e79a491ea6bf25d138eed668906 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jana=20D=C3=B6nszelmann?= Date: Mon, 23 Mar 2026 12:09:34 +0100 Subject: [PATCH 07/12] Revert "explicitly provide type in transmute" This reverts commit 7a123e87b21cd95fef62b80571ee6c644ac3a1c3. --- compiler/rustc_infer/src/infer/mod.rs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/compiler/rustc_infer/src/infer/mod.rs b/compiler/rustc_infer/src/infer/mod.rs index e7082f961d0b1..26b094ff8eccb 100644 --- a/compiler/rustc_infer/src/infer/mod.rs +++ b/compiler/rustc_infer/src/infer/mod.rs @@ -1535,8 +1535,7 @@ impl<'tcx> InferCtxt<'tcx> { span: Span, alias: ty::AliasTy<'tcx>, ) -> Ty<'tcx> { - let erased = - unsafe { mem::transmute::<&'a InferCtxt<'tcx>, TypeErasedInfcx<'a, 'tcx>>(self) }; + let erased = unsafe { mem::transmute::<_, TypeErasedInfcx<'a, 'tcx>>(self) }; self.tcx.try_eagerly_normalize_alias(erased, param_env, span, alias) } From e190973e4fae59ad8a851f022be45dcf3a72cce3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jana=20D=C3=B6nszelmann?= Date: Mon, 23 Mar 2026 12:09:34 +0100 Subject: [PATCH 08/12] Revert "merge generalizer state and structurally relate aliases" This reverts commit 917713b4db3c627f2a35174c09d3ca715dd814b2. --- .../src/infer/relate/generalize.rs | 123 ++++++++++-------- 1 file changed, 67 insertions(+), 56 deletions(-) diff --git a/compiler/rustc_infer/src/infer/relate/generalize.rs b/compiler/rustc_infer/src/infer/relate/generalize.rs index d5c0726ed9a88..34fd32c45bd27 100644 --- a/compiler/rustc_infer/src/infer/relate/generalize.rs +++ b/compiler/rustc_infer/src/infer/relate/generalize.rs @@ -267,14 +267,12 @@ 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: match structurally_relate_aliases { - StructurallyRelateAliases::No => GeneralizerState::Default, - StructurallyRelateAliases::Yes => GeneralizerState::StructurallyRelateAliases, - }, + state: GeneralizationState::Default, cache: Default::default(), normalize, }; @@ -324,13 +322,10 @@ impl<'tcx> TypeVisitor> for MaxUniverse { } #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] -enum GeneralizerState { - /// Treat aliases as potentially normalizable. +enum GeneralizationState { Default, - IncompletelyRelateHigherRankedAlias, - /// Only one layer - ShallowStructurallyRelateAliases, - StructurallyRelateAliases, + InAlias, + InNormalizedAlias, } /// The "generalizer" is used when handling inference variables. @@ -351,6 +346,10 @@ 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. @@ -373,9 +372,10 @@ 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. - state: GeneralizerState, + // TODO: update doc comment + state: GeneralizationState, - cache: SsoHashMap<(Ty<'tcx>, ty::Variance, GeneralizerState), 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. @@ -415,51 +415,44 @@ 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 handle_alias_ty( + fn generalize_alias_ty( &mut self, - alias_ty: Ty<'tcx>, alias: ty::AliasTy<'tcx>, ) -> Result, TypeError<'tcx>> { - 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; - } - 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; + // 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!(), } - GeneralizerState::Default | GeneralizerState::IncompletelyRelateHigherRankedAlias => {} + { + 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 previous_state = - mem::replace(&mut self.state, GeneralizerState::IncompletelyRelateHigherRankedAlias); + 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) => match previous_state { - GeneralizerState::Default => { + GeneralizationState::Default => { let mut visitor = MaxUniverse::new(); alias.visit_with(&mut visitor); let infer_replacement_is_complete = @@ -472,11 +465,11 @@ impl<'tcx> Generalizer<'_, 'tcx> { debug!("generalization failure in alias"); Ok(self.next_ty_var_for_alias()) } - GeneralizerState::IncompletelyRelateHigherRankedAlias => return Err(e), - - // Early return. - GeneralizerState::ShallowStructurallyRelateAliases - | GeneralizerState::StructurallyRelateAliases => unreachable!(), + 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.state = previous_state; @@ -600,9 +593,11 @@ impl<'tcx> TypeRelation> for Generalizer<'_, 'tcx> { && !matches!(self.infcx.typing_mode(), TypingMode::Coherence) { match self.state { - GeneralizerState::IncompletelyRelateHigherRankedAlias => { + GeneralizationState::InAlias => { inner.type_variables().equate(vid, new_var_id); } + GeneralizationState::Default + | GeneralizationState::InNormalizedAlias => {} } GeneralizerState::Default | GeneralizerState::ShallowStructurallyRelateAliases @@ -635,7 +630,21 @@ impl<'tcx> TypeRelation> for Generalizer<'_, 'tcx> { } } - ty::Alias(_, data) => self.handle_alias_ty(t, data), + 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), + }, _ => relate::structurally_relate_tys(self, t, t), }?; @@ -733,9 +742,11 @@ impl<'tcx> TypeRelation> for Generalizer<'_, 'tcx> { && !matches!(self.infcx.typing_mode(), TypingMode::Coherence) { match self.state { - GeneralizerState::IncompletelyRelateHigherRankedAlias => { + GeneralizationState::InAlias => { variable_table.union(vid, new_var_id); } + GeneralizationState::Default + | GeneralizationState::InNormalizedAlias => {} } GeneralizerState::Default | GeneralizerState::ShallowStructurallyRelateAliases From 4af62bdbac8e27f03c217175aefdd38c1d424e13 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jana=20D=C3=B6nszelmann?= Date: Mon, 23 Mar 2026 12:09:34 +0100 Subject: [PATCH 09/12] Revert "implement eager normalization in a fresh context during typeck" This reverts commit 04f2c0191ebe7a1018e00cf6db5f8394352c2da6. --- 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, 16 insertions(+), 97 deletions(-) diff --git a/compiler/rustc_infer/src/infer/at.rs b/compiler/rustc_infer/src/infer/at.rs index 3487286d58830..84ad05fa8ea23 100644 --- a/compiler/rustc_infer/src/infer/at.rs +++ b/compiler/rustc_infer/src/infer/at.rs @@ -140,9 +140,8 @@ impl<'a, 'tcx> At<'a, 'tcx> { ty::Contravariant, actual, self.cause.span, - &mut |alias| { - self.infcx.try_eagerly_normalize_alias(self.param_env, self.cause.span, alias) - }, + // TODO: should normalize + &mut |_alias| self.infcx.next_ty_var(self.cause.span), ) .map(|goals| self.goals_to_obligations(goals)) } else { @@ -176,9 +175,8 @@ impl<'a, 'tcx> At<'a, 'tcx> { ty::Covariant, actual, self.cause.span, - &mut |alias| { - self.infcx.try_eagerly_normalize_alias(self.param_env, self.cause.span, alias) - }, + // TODO: should normalize + &mut |_alias| self.infcx.next_ty_var(self.cause.span), ) .map(|goals| self.goals_to_obligations(goals)) } else { @@ -231,9 +229,8 @@ impl<'a, 'tcx> At<'a, 'tcx> { ty::Invariant, actual, self.cause.span, - &mut |alias| { - self.infcx.try_eagerly_normalize_alias(self.param_env, self.cause.span, alias) - }, + // 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/mod.rs b/compiler/rustc_infer/src/infer/mod.rs index 26b094ff8eccb..10e7b1e72f446 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, mem}; +use std::fmt; pub use at::DefineOpaqueTypes; use free_regions::RegionRelations; @@ -21,7 +21,6 @@ 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; @@ -1529,16 +1528,6 @@ 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 7e480df7dda63..2cb256b1c63c4 100644 --- a/compiler/rustc_infer/src/infer/relate/lattice.rs +++ b/compiler/rustc_infer/src/infer/relate/lattice.rs @@ -300,7 +300,8 @@ impl<'tcx> PredicateEmittingRelation> for LatticeOp<'_, 'tcx> { ))]); } - 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) + 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_interface/src/passes.rs b/compiler/rustc_interface/src/passes.rs index 28f51095966d5..6b7f31521d441 100644 --- a/compiler/rustc_interface/src/passes.rs +++ b/compiler/rustc_interface/src/passes.rs @@ -904,7 +904,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(providers); + solve::provide(&mut providers.queries); 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 0caa8dcbc9c64..691096f4e47c2 100644 --- a/compiler/rustc_middle/src/hooks/mod.rs +++ b/compiler/rustc_middle/src/hooks/mod.rs @@ -3,16 +3,14 @@ //! 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, Span}; +use rustc_span::{ExpnHash, ExpnId}; +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,24 +115,6 @@ 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 cb02885139038..5d200c4d340ba 100644 --- a/compiler/rustc_trait_selection/src/solve.rs +++ b/compiler/rustc_trait_selection/src/solve.rs @@ -1,8 +1,3 @@ -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; @@ -18,13 +13,10 @@ pub use normalize::{ deeply_normalize, deeply_normalize_with_skipped_universes, deeply_normalize_with_skipped_universes_and_ambiguous_coroutine_goals, }; -use rustc_middle::ty::{self, Ty, TyCtxt}; -use rustc_middle::util::Providers; -use rustc_span::Span; +use rustc_middle::query::Providers; +use rustc_middle::ty::TyCtxt; pub use select::InferCtxtSelectExt; -use crate::traits::ObligationCtxt; - fn evaluate_root_goal_for_proof_tree_raw<'tcx>( tcx: TyCtxt<'tcx>, canonical_input: CanonicalInput>, @@ -35,46 +27,6 @@ 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.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; + *providers = Providers { evaluate_root_goal_for_proof_tree_raw, ..*providers }; } From 632ed108384bff71b7a59883891f39b90aa7d5a2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jana=20D=C3=B6nszelmann?= Date: Mon, 23 Mar 2026 12:09:34 +0100 Subject: [PATCH 10/12] Revert "eagerly normalize during generalization" This reverts commit 5d0863b147c0a0084dfb15e6435004909363865f. --- .../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, 42 insertions(+), 179 deletions(-) diff --git a/compiler/rustc_borrowck/src/type_check/relate_tys.rs b/compiler/rustc_borrowck/src/type_check/relate_tys.rs index 152a7674490c7..e2d684e12a816 100644 --- a/compiler/rustc_borrowck/src/type_check/relate_tys.rs +++ b/compiler/rustc_borrowck/src/type_check/relate_tys.rs @@ -616,9 +616,4 @@ 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 84ad05fa8ea23..70e3d7dc9fef0 100644 --- a/compiler/rustc_infer/src/infer/at.rs +++ b/compiler/rustc_infer/src/infer/at.rs @@ -140,8 +140,6 @@ 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 { @@ -175,8 +173,6 @@ 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 { @@ -229,8 +225,6 @@ 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 34fd32c45bd27..69c090b662e54 100644 --- a/compiler/rustc_infer/src/infer/relate/generalize.rs +++ b/compiler/rustc_infer/src/infer/relate/generalize.rs @@ -76,7 +76,6 @@ 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`. @@ -211,7 +210,6 @@ 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()); @@ -251,7 +249,6 @@ 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() { @@ -272,9 +269,8 @@ impl<'tcx> InferCtxt<'tcx> { for_universe, root_term: source_term.into(), ambient_variance, - state: GeneralizationState::Default, + in_alias: false, cache: Default::default(), - normalize, }; let value_may_be_infer = generalizer.relate(source_term, source_term)?; @@ -321,13 +317,6 @@ 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 @@ -372,14 +361,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, + in_alias: bool, - 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>, + cache: SsoHashMap<(Ty<'tcx>, ty::Variance, bool), Ty<'tcx>>, } impl<'tcx> Generalizer<'_, 'tcx> { @@ -425,34 +409,17 @@ 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() - && 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; + if self.infcx.next_trait_solver() && !alias.has_escaping_bound_vars() && !self.in_alias { + return Ok(self.next_ty_var_for_alias()); } - let previous_state = mem::replace(&mut self.state, GeneralizationState::InAlias); + let is_nested_alias = mem::replace(&mut self.in_alias, true); let result = match self.relate(alias, alias) { Ok(alias) => Ok(alias.to_ty(self.cx())), - Err(e) => match previous_state { - GeneralizationState::Default => { + Err(e) => { + if is_nested_alias { + return Err(e); + } else { let mut visitor = MaxUniverse::new(); alias.visit_with(&mut visitor); let infer_replacement_is_complete = @@ -465,14 +432,9 @@ 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.state = previous_state; + self.in_alias = is_nested_alias; result } } @@ -526,7 +488,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.state)) { + if let Some(&result) = self.cache.get(&(t, self.ambient_variance, self.in_alias)) { return Ok(result); } @@ -591,17 +553,9 @@ 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 { - match self.state { - GeneralizationState::InAlias => { - inner.type_variables().equate(vid, new_var_id); - } - GeneralizationState::Default - | GeneralizationState::InNormalizedAlias => {} - } - GeneralizerState::Default - | GeneralizerState::ShallowStructurallyRelateAliases - | GeneralizerState::StructurallyRelateAliases => {} + inner.type_variables().equate(vid, new_var_id); } debug!("replacing original vid={:?} with new={:?}", vid, new_var_id); @@ -631,25 +585,14 @@ 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::No => self.generalize_alias_ty(data), StructurallyRelateAliases::Yes => relate::structurally_relate_tys(self, t, t), }, _ => relate::structurally_relate_tys(self, t, t), }?; - self.cache.insert((t, self.ambient_variance, self.state), g); + self.cache.insert((t, self.ambient_variance, self.in_alias), g); Ok(g) } @@ -740,17 +683,9 @@ 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 { - match self.state { - GeneralizationState::InAlias => { - variable_table.union(vid, new_var_id); - } - GeneralizationState::Default - | GeneralizationState::InNormalizedAlias => {} - } - GeneralizerState::Default - | GeneralizerState::ShallowStructurallyRelateAliases - | GeneralizerState::StructurallyRelateAliases => {} + variable_table.union(vid, new_var_id); } 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 2cb256b1c63c4..a05e2d40e829f 100644 --- a/compiler/rustc_infer/src/infer/relate/lattice.rs +++ b/compiler/rustc_infer/src/infer/relate/lattice.rs @@ -299,9 +299,4 @@ 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 67f9dc69a4a65..96a0375f5fba6 100644 --- a/compiler/rustc_infer/src/infer/relate/type_relating.rs +++ b/compiler/rustc_infer/src/infer/relate/type_relating.rs @@ -396,13 +396,4 @@ 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 456fe5246d801..cd74e87b670f1 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 @@ -987,12 +987,7 @@ where let replacement = self.ecx.instantiate_binder_with_infer(*replacement); self.nested.extend( self.ecx - .relate_and_get_goals( - self.param_env, - alias_term, - ty::Invariant, - replacement.projection_term, - ) + .eq_and_get_goals(self.param_env, alias_term, 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 fedb6390d9588..6841fe1c5124e 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. - pub(super) fn evaluate_goal( + fn evaluate_goal( &mut self, source: GoalSource, goal: Goal, @@ -1018,8 +1018,7 @@ where variance: ty::Variance, rhs: T, ) -> Result<(), NoSolution> { - let goals = self.relate_and_get_goals(param_env, lhs, variance, rhs)?; - + 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() { ty::PredicateKind::Subtype { .. } | ty::PredicateKind::AliasRelate(..) => { @@ -1040,37 +1039,13 @@ where /// If possible, try using `eq` instead which automatically handles nested /// goals correctly. #[instrument(level = "trace", skip(self, param_env), ret)] - pub(super) fn relate_and_get_goals>( - &mut self, + pub(super) fn eq_and_get_goals>( + &self, param_env: I::ParamEnv, lhs: T, - variance: ty::Variance, rhs: T, ) -> Result>, NoSolution> { - 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)?) + Ok(self.delegate.relate(param_env, lhs, ty::Variance::Invariant, rhs, self.origin_span)?) } 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 72d54c23733ee..64b87fac77f94 100644 --- a/compiler/rustc_type_ir/src/relate/combine.rs +++ b/compiler/rustc_type_ir/src/relate/combine.rs @@ -40,8 +40,6 @@ 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 541b2531fe749..82ee4f75fcb0a 100644 --- a/compiler/rustc_type_ir/src/relate/solver_relating.rs +++ b/compiler/rustc_type_ir/src/relate/solver_relating.rs @@ -15,7 +15,6 @@ pub trait RelateExt: InferCtxtLike { variance: ty::Variance, rhs: T, span: ::Span, - normalize: &mut dyn FnMut(ty::AliasTy) -> ::Ty, ) -> Result< Vec::Predicate>>, TypeError, @@ -33,46 +32,40 @@ pub trait RelateExt: InferCtxtLike { >; } -impl> RelateExt for Infcx { - fn relate>( +impl RelateExt for Infcx { + fn relate>( &self, - param_env: I::ParamEnv, + param_env: ::ParamEnv, lhs: T, variance: ty::Variance, rhs: T, - 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, - ); + span: ::Span, + ) -> Result< + Vec::Predicate>>, + TypeError, + > { + let mut relate = + SolverRelating::new(self, StructurallyRelateAliases::No, variance, param_env, span); relate.relate(lhs, rhs)?; Ok(relate.goals) } - fn eq_structurally_relating_aliases>( + fn eq_structurally_relating_aliases>( &self, - param_env: I::ParamEnv, + param_env: ::ParamEnv, lhs: T, rhs: T, - 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!(); - + span: ::Span, + ) -> Result< + Vec::Predicate>>, + TypeError, + > { let mut relate = SolverRelating::new( self, StructurallyRelateAliases::Yes, ty::Invariant, param_env, span, - &mut normalize_unreachable, ); relate.relate(lhs, rhs)?; Ok(relate.goals) @@ -82,14 +75,12 @@ 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 @@ -127,14 +118,12 @@ 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(), @@ -417,8 +406,4 @@ where } })]); } - - fn try_eagerly_normalize_alias(&mut self, alias: ty::AliasTy) -> I::Ty { - (self.normalize)(alias) - } } From 34a876657558c348388bc20066d32b40a393bc8e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jana=20D=C3=B6nszelmann?= Date: Mon, 23 Mar 2026 12:09:34 +0100 Subject: [PATCH 11/12] Revert "Regression test for trait-system-refactor#262" This reverts commit 244b6d5ca8fd6257df414c8b8d48c9c8d26269de. --- .../generalize/eagely-normalizing-aliases.rs | 26 ------------------- 1 file changed, 26 deletions(-) delete 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 deleted file mode 100644 index 463fe49e55315..0000000000000 --- a/tests/ui/traits/next-solver/generalize/eagely-normalizing-aliases.rs +++ /dev/null @@ -1,26 +0,0 @@ -//@ 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 e28b48565fcccc43eb6abdf93da1af449815c48f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jana=20D=C3=B6nszelmann?= Date: Mon, 23 Mar 2026 12:11:08 +0100 Subject: [PATCH 12/12] add regression test --- .../constrain-inference-during-normalize.rs | 25 +++++++++++++++++++ 1 file changed, 25 insertions(+) create mode 100644 tests/ui/traits/next-solver/generalize/constrain-inference-during-normalize.rs diff --git a/tests/ui/traits/next-solver/generalize/constrain-inference-during-normalize.rs b/tests/ui/traits/next-solver/generalize/constrain-inference-during-normalize.rs new file mode 100644 index 0000000000000..c3942b008ccbc --- /dev/null +++ b/tests/ui/traits/next-solver/generalize/constrain-inference-during-normalize.rs @@ -0,0 +1,25 @@ +// revisions: next old +//[next] compile-flags: -Znext-solver +//@ check-pass +// Regression test for https://github.com/rust-lang/rust/issues/154173. +// The ICE there was caused by a (flawed) attempt to eagerly normalize during generalization. +// The normalize would constrain other inference variables, which we couldn't deal with. + +trait Trait { + type Assoc; +} + +impl Trait for () { + type Assoc = u32; +} + +trait Eq {} +impl, T> Eq for (C, T, >::Assoc) {} +fn foo() +where + ((), A, A): Eq +{} + +fn main() { + foo::<_>(); +}