about summary refs log tree commit diff
diff options
context:
space:
mode:
authorStuart Cook <Zalathar@users.noreply.github.com>2025-04-15 15:47:30 +1000
committerGitHub <noreply@github.com>2025-04-15 15:47:30 +1000
commitb21c5cd025927113d0ed1dad349b8763e2438fac (patch)
tree7202c38507127456cd298ad14a2dc09fd93ae40d
parente8c9dcc79eca6315c8b34bd6e8c9b36f040e3574 (diff)
parent9c88eb6c4344cc2387900bb362f09291f031e9c2 (diff)
downloadrust-b21c5cd025927113d0ed1dad349b8763e2438fac.tar.gz
rust-b21c5cd025927113d0ed1dad349b8763e2438fac.zip
Rollup merge of #139798 - lcnr:where-bounds-gt-alias-bound, r=compiler-errors
normalize: prefer `ParamEnv` over `AliasBound` candidates

cc https://github.com/rust-lang/trait-system-refactor-initiative/issues/175 not the only issue affecting bevy sadly

r? ``@compiler-errors``
-rw-r--r--compiler/rustc_next_trait_solver/src/solve/assembly/mod.rs51
-rw-r--r--tests/ui/traits/winnowing/norm-where-bound-gt-alias-bound.rs29
2 files changed, 59 insertions, 21 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 384a304c4a9..ee000b11748 100644
--- a/compiler/rustc_next_trait_solver/src/solve/assembly/mod.rs
+++ b/compiler/rustc_next_trait_solver/src/solve/assembly/mod.rs
@@ -792,37 +792,46 @@ where
         };
 
         match proven_via {
-            // Even when a trait bound has been proven using a where-bound, we
-            // still need to consider alias-bounds for normalization, see
-            // tests/ui/next-solver/alias-bound-shadowed-by-env.rs.
-            //
-            // FIXME(const_trait_impl): should this behavior also be used by
-            // constness checking. Doing so is *at least theoretically* breaking,
-            // see github.com/rust-lang/rust/issues/133044#issuecomment-2500709754
             TraitGoalProvenVia::ParamEnv | TraitGoalProvenVia::AliasBound => {
-                let mut candidates_from_env_and_bounds: Vec<_> = candidates
-                    .iter()
-                    .filter(|c| {
-                        matches!(
-                            c.source,
-                            CandidateSource::AliasBound | CandidateSource::ParamEnv(_)
-                        )
-                    })
-                    .map(|c| c.result)
-                    .collect();
+                let mut considered_candidates = Vec::new();
+                considered_candidates.extend(
+                    candidates
+                        .iter()
+                        .filter(|c| matches!(c.source, CandidateSource::ParamEnv(_)))
+                        .map(|c| c.result),
+                );
+
+                // Even when a trait bound has been proven using a where-bound, we
+                // still need to consider alias-bounds for normalization, see
+                // tests/ui/next-solver/alias-bound-shadowed-by-env.rs.
+                //
+                // We still need to prefer where-bounds over alias-bounds however.
+                // See tests/ui/winnowing/norm-where-bound-gt-alias-bound.rs.
+                //
+                // FIXME(const_trait_impl): should this behavior also be used by
+                // constness checking. Doing so is *at least theoretically* breaking,
+                // see github.com/rust-lang/rust/issues/133044#issuecomment-2500709754
+                if considered_candidates.is_empty() {
+                    considered_candidates.extend(
+                        candidates
+                            .iter()
+                            .filter(|c| matches!(c.source, CandidateSource::AliasBound))
+                            .map(|c| c.result),
+                    );
+                }
 
                 // 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.
-                if candidates_from_env_and_bounds.is_empty() {
+                if considered_candidates.is_empty() {
                     if let Ok(response) = inject_normalize_to_rigid_candidate(self) {
-                        candidates_from_env_and_bounds.push(response);
+                        considered_candidates.push(response);
                     }
                 }
 
-                if let Some(response) = self.try_merge_responses(&candidates_from_env_and_bounds) {
+                if let Some(response) = self.try_merge_responses(&considered_candidates) {
                     Ok(response)
                 } else {
-                    self.flounder(&candidates_from_env_and_bounds)
+                    self.flounder(&considered_candidates)
                 }
             }
             TraitGoalProvenVia::Misc => {
diff --git a/tests/ui/traits/winnowing/norm-where-bound-gt-alias-bound.rs b/tests/ui/traits/winnowing/norm-where-bound-gt-alias-bound.rs
new file mode 100644
index 00000000000..cdfb0ee45af
--- /dev/null
+++ b/tests/ui/traits/winnowing/norm-where-bound-gt-alias-bound.rs
@@ -0,0 +1,29 @@
+//@ revisions: current next
+//@ ignore-compare-mode-next-solver (explicit revisions)
+//@[next] compile-flags: -Znext-solver
+//@ check-pass
+
+// Make sure we prefer the `I::IntoIterator: Iterator<Item = ()>`
+// where-bound over the `I::Intoiterator: Iterator<Item = I::Item>`
+// alias-bound.
+
+trait Iterator {
+    type Item;
+}
+
+trait IntoIterator {
+    type Item;
+    type IntoIter: Iterator<Item = Self::Item>;
+}
+
+fn normalize<I: Iterator<Item = ()>>() {}
+
+fn foo<I>()
+where
+    I: IntoIterator,
+    I::IntoIter: Iterator<Item = ()>,
+{
+    normalize::<I::IntoIter>();
+}
+
+fn main() {}