From ac863006d2784d697d8053e1e846cc95aa211d7e Mon Sep 17 00:00:00 2001 From: Joao Roberto Date: Thu, 30 Jul 2026 09:21:43 -0300 Subject: [PATCH 1/3] Fix rigid alias liveness matching --- .../src/traits/outlives_for_liveness.rs | 26 +++++++++++++----- tests/ui/traits/next-solver/issue-160206.rs | 27 +++++++++++++++++++ 2 files changed, 46 insertions(+), 7 deletions(-) create mode 100644 tests/ui/traits/next-solver/issue-160206.rs diff --git a/compiler/rustc_trait_selection/src/traits/outlives_for_liveness.rs b/compiler/rustc_trait_selection/src/traits/outlives_for_liveness.rs index 5cba32d742f62..2a696f9581a41 100644 --- a/compiler/rustc_trait_selection/src/traits/outlives_for_liveness.rs +++ b/compiler/rustc_trait_selection/src/traits/outlives_for_liveness.rs @@ -41,12 +41,20 @@ pub(crate) fn live_args_for_alias_from_outlives_bounds<'tcx>( tracing::debug!(?bounds); let alias_ty = Ty::new_alias( tcx, - ty::IsRigid::No, + ty::IsRigid::yes_if_next_solver(tcx), ty::AliasTy::new_from_args(tcx, kind, self_identity_args), ); let outlives_regions: Vec<_> = bounds .iter() .filter_map(|clause| { + // This liveness computation uses a syntactic matcher, not normalization. + // In the next solver, aliases that cannot normalize further are represented + // as rigid, so put item bounds in the same form before matching them. + let clause = if tcx.next_trait_solver_globally() { + ty::set_aliases_to_rigid(tcx, clause) + } else { + clause + }; let outlives = clause.as_type_outlives_clause()?; if let Some(outlives) = outlives.no_bound_vars() && outlives.0 == alias_ty @@ -56,10 +64,6 @@ pub(crate) fn live_args_for_alias_from_outlives_bounds<'tcx>( test_type_match::extract_verify_if_eq( tcx, &outlives.map_bound(|ty::OutlivesClause(ty, bound)| VerifyIfEq { ty, bound }), - // FIXME(#155345): Region handling should generally only - // deal with rigid aliases, making sure we do so correctly - // everywhere is effort, so we're just using `No` everywhere - // for now. This should change soon. alias_ty, ) } @@ -343,9 +347,17 @@ pub(crate) fn args_known_to_outlive_non_opaque_params<'tcx>( fn live_args_for_outlives_clause<'tcx>( tcx: TyCtxt<'tcx>, alias_def_id: DefId, - ty: Ty<'tcx>, - outlives: ty::Binder<'tcx, ty::TypeOutlivesClause<'tcx>>, + mut ty: Ty<'tcx>, + mut outlives: ty::Binder<'tcx, ty::TypeOutlivesClause<'tcx>>, ) -> Option>>> { + // This liveness computation uses a syntactic matcher, not normalization. + // In the next solver, aliases that cannot normalize further are represented + // as rigid, so put the clause and matched type in the same form first. + if tcx.next_trait_solver_globally() { + ty = ty::set_aliases_to_rigid(tcx, ty); + outlives = ty::set_aliases_to_rigid(tcx, outlives); + } + // N.B. it's okay to skip the binder here (and in the rest of the function), // because all variables under binders do not escape let ty::Alias(_, ty::AliasTy { kind: clause_alias_kind, args: clause_args, .. }) = diff --git a/tests/ui/traits/next-solver/issue-160206.rs b/tests/ui/traits/next-solver/issue-160206.rs new file mode 100644 index 0000000000000..4899645e10d58 --- /dev/null +++ b/tests/ui/traits/next-solver/issue-160206.rs @@ -0,0 +1,27 @@ +//@ compile-flags: -Znext-solver=globally +//@ check-pass + +trait Foo<'x> { + type Out; + fn foo(self) -> Self::Out; +} + +struct Bar; + +impl<'x> Foo<'x> for Bar { + type Out = (); + + fn foo(self) -> Self::Out { + todo!() + } +} + +fn make_static_foo<'x>(_: &'x ()) -> impl Foo<'x, Out: 'static> { + Bar +} + +fn test() { + make_static_foo(&()); +} + +fn main() {} From 1d046de76817dc5595d5deafbb3a53aee0da0e65 Mon Sep 17 00:00:00 2001 From: Joao Roberto Date: Thu, 30 Jul 2026 09:31:02 -0300 Subject: [PATCH 2/3] Rename rigid alias liveness regression --- .../{issue-160206.rs => rigid-alias-liveness-issue-160206.rs} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename tests/ui/traits/next-solver/{issue-160206.rs => rigid-alias-liveness-issue-160206.rs} (100%) diff --git a/tests/ui/traits/next-solver/issue-160206.rs b/tests/ui/traits/next-solver/rigid-alias-liveness-issue-160206.rs similarity index 100% rename from tests/ui/traits/next-solver/issue-160206.rs rename to tests/ui/traits/next-solver/rigid-alias-liveness-issue-160206.rs From 5c1eddbda5a5cce5382009329d1dd52137dceb3b Mon Sep 17 00:00:00 2001 From: Joao Roberto Date: Thu, 30 Jul 2026 15:37:25 -0300 Subject: [PATCH 3/3] Make verify-if-eq ignore alias rigidness --- .../src/infer/outlives/test_type_match.rs | 17 +++++++++++--- .../src/traits/outlives_for_liveness.rs | 22 +++---------------- 2 files changed, 17 insertions(+), 22 deletions(-) diff --git a/compiler/rustc_infer/src/infer/outlives/test_type_match.rs b/compiler/rustc_infer/src/infer/outlives/test_type_match.rs index de42736ce2b06..e6ca880bd18c6 100644 --- a/compiler/rustc_infer/src/infer/outlives/test_type_match.rs +++ b/compiler/rustc_infer/src/infer/outlives/test_type_match.rs @@ -44,9 +44,6 @@ pub fn extract_verify_if_eq<'tcx>( assert!(!verify_if_eq_b.has_escaping_bound_vars()); let mut m = MatchAgainstHigherRankedOutlives::new(tcx); let verify_if_eq = verify_if_eq_b.skip_binder(); - debug_assert!( - !tcx.next_trait_solver_globally() || !(verify_if_eq.ty, test_ty).has_non_rigid_aliases() - ); m.relate(verify_if_eq.ty, test_ty).ok()?; if let ty::RegionKind::ReBound(index_kind, br) = verify_if_eq.bound.kind() { @@ -198,6 +195,13 @@ impl<'tcx> TypeRelation> for MatchAgainstHigherRankedOutlives<'tcx> self.no_match() } else if pattern == value { Ok(pattern) + } else if let (ty::Alias(_, pattern_alias), ty::Alias(_, value_alias)) = + (*pattern.kind(), *value.kind()) + { + // Rigidness is normalization state. This matcher only needs to know + // whether both sides are the same alias shape. + self.relate(pattern_alias, value_alias)?; + Ok(pattern) } else { relate::structurally_relate_tys(self, pattern, value) } @@ -211,6 +215,13 @@ impl<'tcx> TypeRelation> for MatchAgainstHigherRankedOutlives<'tcx> ) -> RelateResult<'tcx, ty::Const<'tcx>> { if pattern == value { Ok(pattern) + } else if let ( + ty::ConstKind::Alias(_, pattern_alias), + ty::ConstKind::Alias(_, value_alias), + ) = (pattern.kind(), value.kind()) + { + self.relate(pattern_alias, value_alias)?; + Ok(pattern) } else { relate::structurally_relate_consts(self, pattern, value) } diff --git a/compiler/rustc_trait_selection/src/traits/outlives_for_liveness.rs b/compiler/rustc_trait_selection/src/traits/outlives_for_liveness.rs index 2a696f9581a41..ad80864db924a 100644 --- a/compiler/rustc_trait_selection/src/traits/outlives_for_liveness.rs +++ b/compiler/rustc_trait_selection/src/traits/outlives_for_liveness.rs @@ -41,20 +41,12 @@ pub(crate) fn live_args_for_alias_from_outlives_bounds<'tcx>( tracing::debug!(?bounds); let alias_ty = Ty::new_alias( tcx, - ty::IsRigid::yes_if_next_solver(tcx), + ty::IsRigid::No, ty::AliasTy::new_from_args(tcx, kind, self_identity_args), ); let outlives_regions: Vec<_> = bounds .iter() .filter_map(|clause| { - // This liveness computation uses a syntactic matcher, not normalization. - // In the next solver, aliases that cannot normalize further are represented - // as rigid, so put item bounds in the same form before matching them. - let clause = if tcx.next_trait_solver_globally() { - ty::set_aliases_to_rigid(tcx, clause) - } else { - clause - }; let outlives = clause.as_type_outlives_clause()?; if let Some(outlives) = outlives.no_bound_vars() && outlives.0 == alias_ty @@ -347,17 +339,9 @@ pub(crate) fn args_known_to_outlive_non_opaque_params<'tcx>( fn live_args_for_outlives_clause<'tcx>( tcx: TyCtxt<'tcx>, alias_def_id: DefId, - mut ty: Ty<'tcx>, - mut outlives: ty::Binder<'tcx, ty::TypeOutlivesClause<'tcx>>, + ty: Ty<'tcx>, + outlives: ty::Binder<'tcx, ty::TypeOutlivesClause<'tcx>>, ) -> Option>>> { - // This liveness computation uses a syntactic matcher, not normalization. - // In the next solver, aliases that cannot normalize further are represented - // as rigid, so put the clause and matched type in the same form first. - if tcx.next_trait_solver_globally() { - ty = ty::set_aliases_to_rigid(tcx, ty); - outlives = ty::set_aliases_to_rigid(tcx, outlives); - } - // N.B. it's okay to skip the binder here (and in the rest of the function), // because all variables under binders do not escape let ty::Alias(_, ty::AliasTy { kind: clause_alias_kind, args: clause_args, .. }) =