about summary refs log tree commit diff
diff options
context:
space:
mode:
authorlcnr <rust@lcnr.de>2025-01-20 13:09:09 +0100
committerlcnr <rust@lcnr.de>2025-01-20 18:51:45 +0100
commit09b784fac560d725ffc37b6fad1037615f63b232 (patch)
tree199e33700e1bac78f5fdf56115834dd8969c1a8d
parent7171fee4ec77eeeae6e90f5c35d33c43495a4ecd (diff)
handle global trait bounds defining assoc type
-rw-r--r--compiler/rustc_next_trait_solver/src/solve/trait_goals.rs24
-rw-r--r--tests/ui/traits/next-solver/normalization-shadowing/global-trait-with-project.rs21
2 files changed, 43 insertions, 2 deletions
diff --git a/compiler/rustc_next_trait_solver/src/solve/trait_goals.rs b/compiler/rustc_next_trait_solver/src/solve/trait_goals.rs
index f059a6fb785..513fc9355c8 100644
--- a/compiler/rustc_next_trait_solver/src/solve/trait_goals.rs
+++ b/compiler/rustc_next_trait_solver/src/solve/trait_goals.rs
@@ -1212,8 +1212,28 @@ where
         // (including global ones) over everything else.
         let has_non_global_where_bounds = candidates.iter().any(|c| match c.source {
             CandidateSource::ParamEnv(idx) => {
-                let where_bound = goal.param_env.caller_bounds().get(idx);
-                where_bound.has_bound_vars() || !where_bound.is_global()
+                let where_bound = goal.param_env.caller_bounds().get(idx).unwrap();
+                let ty::ClauseKind::Trait(trait_pred) = where_bound.kind().skip_binder() else {
+                    unreachable!("expected trait-bound: {where_bound:?}");
+                };
+
+                if trait_pred.has_bound_vars() || !trait_pred.is_global() {
+                    return true;
+                }
+
+                // We don't consider a trait-bound global if it has a projection bound.
+                //
+                // See ui/traits/next-solver/normalization-shadowing/global-trait-with-project.rs
+                // for an example where this is necessary.
+                for p in goal.param_env.caller_bounds().iter() {
+                    if let ty::ClauseKind::Projection(proj) = p.kind().skip_binder() {
+                        if proj.projection_term.trait_ref(self.cx()) == trait_pred.trait_ref {
+                            return true;
+                        }
+                    }
+                }
+
+                false
             }
             _ => false,
         });
diff --git a/tests/ui/traits/next-solver/normalization-shadowing/global-trait-with-project.rs b/tests/ui/traits/next-solver/normalization-shadowing/global-trait-with-project.rs
new file mode 100644
index 00000000000..dc96652f82f
--- /dev/null
+++ b/tests/ui/traits/next-solver/normalization-shadowing/global-trait-with-project.rs
@@ -0,0 +1,21 @@
+//@ compile-flags: -Znext-solver
+//@ check-pass
+
+// `(): Trait` is a global where-bound with a projection bound.
+// This previously resulted in ambiguity as we considered both
+// the impl and the where-bound while normalizing.
+
+trait Trait {
+    type Assoc;
+}
+impl Trait for () {
+    type Assoc = &'static ();
+}
+
+fn foo<'a>(x: <() as Trait>::Assoc)
+where
+    (): Trait<Assoc = &'a ()>,
+{
+}
+
+fn main() {}