From 2fbb75198536302356e430fdff54f8a03463c4c2 Mon Sep 17 00:00:00 2001 From: Adwin White Date: Thu, 30 Oct 2025 20:22:45 +0800 Subject: [PATCH 1/3] Un-shadow object bound candidate in `NormalizesTo` goal --- .../src/solve/assembly/mod.rs | 6 ++++++ .../use_object_if_empty_env.rs | 17 +++++++++++++++++ 2 files changed, 23 insertions(+) create mode 100644 tests/ui/traits/next-solver/normalization-shadowing/use_object_if_empty_env.rs diff --git a/compiler/rustc_next_trait_solver/src/solve/assembly/mod.rs b/compiler/rustc_next_trait_solver/src/solve/assembly/mod.rs index c9a42dddac42b..42eb804431e43 100644 --- a/compiler/rustc_next_trait_solver/src/solve/assembly/mod.rs +++ b/compiler/rustc_next_trait_solver/src/solve/assembly/mod.rs @@ -1143,6 +1143,12 @@ where // See `tests/ui/winnowing/norm-where-bound-gt-alias-bound.rs`. if candidates.iter().any(|c| matches!(c.source, CandidateSource::ParamEnv(_))) { candidates.retain(|c| matches!(c.source, CandidateSource::ParamEnv(_))); + } else if matches!(goal.predicate.self_ty().kind(), ty::Dynamic(..)) { + // Object candidate may be shadowed by where-bound for the trait goal, see + // `tests/ui/traits/next-solver/normalization-shadowing/use_object_if_empty_env.rs`. + // Trait objects always have their associated types specified so `candidates` + // won't be empty. + self.assemble_object_bound_candidates(goal, &mut candidates); } else if candidates.is_empty() { // If the trait goal has been proven by using the environment, we want to treat // aliases as rigid if there are no applicable projection bounds in the environment. diff --git a/tests/ui/traits/next-solver/normalization-shadowing/use_object_if_empty_env.rs b/tests/ui/traits/next-solver/normalization-shadowing/use_object_if_empty_env.rs new file mode 100644 index 0000000000000..ec3a94a972947 --- /dev/null +++ b/tests/ui/traits/next-solver/normalization-shadowing/use_object_if_empty_env.rs @@ -0,0 +1,17 @@ +//@ compile-flags: -Znext-solver +//@ check-pass + +trait Trait { + type Assoc; +} + +// We have param env candidate for the trait goal but not the projection. +// Under such circumstance, consider object candidate if the self_ty is trait object. +fn foo(x: as Trait>::Assoc) -> T +where + dyn Trait: Trait, +{ + x +} + +fn main() {} From e2ac9d92d9f0ce0f4a08d8376649f740c4073439 Mon Sep 17 00:00:00 2001 From: Adwin White Date: Fri, 31 Oct 2025 20:31:49 +0800 Subject: [PATCH 2/3] Apply suggestions --- .../src/solve/assembly/mod.rs | 17 ++++++++++------- .../use_object_if_empty_env.rs | 2 ++ 2 files changed, 12 insertions(+), 7 deletions(-) diff --git a/compiler/rustc_next_trait_solver/src/solve/assembly/mod.rs b/compiler/rustc_next_trait_solver/src/solve/assembly/mod.rs index 42eb804431e43..221593d6eadb5 100644 --- a/compiler/rustc_next_trait_solver/src/solve/assembly/mod.rs +++ b/compiler/rustc_next_trait_solver/src/solve/assembly/mod.rs @@ -454,7 +454,16 @@ where self.assemble_object_bound_candidates(goal, &mut candidates); } } - AssembleCandidatesFrom::EnvAndBounds => {} + AssembleCandidatesFrom::EnvAndBounds => { + // This is somewhat inconsistent and may make #57893 slightly easier to exploit. + // However, it matches the behavior of the old solver. See + // `tests/ui/traits/next-solver/normalization-shadowing/use_object_if_empty_env.rs`. + if matches!(normalized_self_ty.kind(), ty::Dynamic(..)) + && !candidates.iter().any(|c| matches!(c.source, CandidateSource::ParamEnv(_))) + { + self.assemble_object_bound_candidates(goal, &mut candidates); + } + } } (candidates, failed_candidate_info) @@ -1143,12 +1152,6 @@ where // See `tests/ui/winnowing/norm-where-bound-gt-alias-bound.rs`. if candidates.iter().any(|c| matches!(c.source, CandidateSource::ParamEnv(_))) { candidates.retain(|c| matches!(c.source, CandidateSource::ParamEnv(_))); - } else if matches!(goal.predicate.self_ty().kind(), ty::Dynamic(..)) { - // Object candidate may be shadowed by where-bound for the trait goal, see - // `tests/ui/traits/next-solver/normalization-shadowing/use_object_if_empty_env.rs`. - // Trait objects always have their associated types specified so `candidates` - // won't be empty. - self.assemble_object_bound_candidates(goal, &mut candidates); } else if candidates.is_empty() { // If the trait goal has been proven by using the environment, we want to treat // aliases as rigid if there are no applicable projection bounds in the environment. diff --git a/tests/ui/traits/next-solver/normalization-shadowing/use_object_if_empty_env.rs b/tests/ui/traits/next-solver/normalization-shadowing/use_object_if_empty_env.rs index ec3a94a972947..c0bd2b49117b0 100644 --- a/tests/ui/traits/next-solver/normalization-shadowing/use_object_if_empty_env.rs +++ b/tests/ui/traits/next-solver/normalization-shadowing/use_object_if_empty_env.rs @@ -1,6 +1,8 @@ //@ compile-flags: -Znext-solver //@ check-pass +// Regression test for trait-system-refactor-initiative#244 + trait Trait { type Assoc; } From d2cfc47ed07497d8b8e37d17b136937a8af47723 Mon Sep 17 00:00:00 2001 From: Adwin White Date: Wed, 5 Nov 2025 21:29:39 +0800 Subject: [PATCH 3/3] add test for alias self_ty --- .../use_object_if_empty_env.rs | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/tests/ui/traits/next-solver/normalization-shadowing/use_object_if_empty_env.rs b/tests/ui/traits/next-solver/normalization-shadowing/use_object_if_empty_env.rs index c0bd2b49117b0..f8f6ed9a09887 100644 --- a/tests/ui/traits/next-solver/normalization-shadowing/use_object_if_empty_env.rs +++ b/tests/ui/traits/next-solver/normalization-shadowing/use_object_if_empty_env.rs @@ -16,4 +16,21 @@ where x } +trait Id<'a> { + type This: ?Sized; +} +impl Id<'_> for T { + type This = T; +} + +// Ensure that we properly normalize alias self_ty before evaluating the goal. +fn alias_foo(x: for<'a> fn( + < as Id<'a>>::This as Trait>::Assoc +)) -> fn(T) +where + dyn Trait: Trait, +{ + x +} + fn main() {}