about summary refs log tree commit diff
diff options
context:
space:
mode:
authorMatthias Krüger <matthias.krueger@famsik.de>2024-05-31 17:05:25 +0200
committerGitHub <noreply@github.com>2024-05-31 17:05:25 +0200
commit5109a7668a1ae051e60144d737dfbbf4e14cd956 (patch)
tree1a87d87b51cb3ba152bbf667bc6bd5b8b9c4c2a0
parent7667a917789b7a96edfeacc460c307333b32101a (diff)
parent20699fe6b23615cac13e4661b755fde2b4f36822 (diff)
downloadrust-5109a7668a1ae051e60144d737dfbbf4e14cd956.tar.gz
rust-5109a7668a1ae051e60144d737dfbbf4e14cd956.zip
Rollup merge of #125776 - compiler-errors:translate-args, r=lcnr
Stop using `translate_args` in the new solver

It was unnecessary and also sketchy, since it was doing an out-of-search-graph fulfillment loop. Added a test for the only really minor subtlety of translating args, though not sure if it was being tested before, though I wouldn't be surprised if it wasn't.

r? lcnr
-rw-r--r--compiler/rustc_trait_selection/src/solve/eval_ctxt/mod.rs11
-rw-r--r--compiler/rustc_trait_selection/src/solve/normalizes_to/mod.rs125
-rw-r--r--tests/ui/specialization/source-impl-requires-constraining-predicates-ambig.next.stderr12
-rw-r--r--tests/ui/specialization/source-impl-requires-constraining-predicates-ambig.rs29
-rw-r--r--tests/ui/specialization/source-impl-requires-constraining-predicates.current.stderr12
-rw-r--r--tests/ui/specialization/source-impl-requires-constraining-predicates.next.stderr12
-rw-r--r--tests/ui/specialization/source-impl-requires-constraining-predicates.rs24
7 files changed, 168 insertions, 57 deletions
diff --git a/compiler/rustc_trait_selection/src/solve/eval_ctxt/mod.rs b/compiler/rustc_trait_selection/src/solve/eval_ctxt/mod.rs
index b18b59d9a75..f18f1f4f8f0 100644
--- a/compiler/rustc_trait_selection/src/solve/eval_ctxt/mod.rs
+++ b/compiler/rustc_trait_selection/src/solve/eval_ctxt/mod.rs
@@ -12,7 +12,6 @@ use rustc_middle::bug;
 use rustc_middle::traits::solve::{
     inspect, CanonicalInput, CanonicalResponse, Certainty, PredefinedOpaquesData, QueryResult,
 };
-use rustc_middle::traits::specialization_graph;
 use rustc_middle::ty::AliasRelationDirection;
 use rustc_middle::ty::TypeFolder;
 use rustc_middle::ty::{
@@ -900,16 +899,6 @@ impl<'tcx> EvalCtxt<'_, InferCtxt<'tcx>> {
         args
     }
 
-    pub(super) fn translate_args(
-        &self,
-        param_env: ty::ParamEnv<'tcx>,
-        source_impl: DefId,
-        source_args: ty::GenericArgsRef<'tcx>,
-        target_node: specialization_graph::Node,
-    ) -> ty::GenericArgsRef<'tcx> {
-        crate::traits::translate_args(self.infcx, param_env, source_impl, source_args, target_node)
-    }
-
     pub(super) fn register_ty_outlives(&self, ty: Ty<'tcx>, lt: ty::Region<'tcx>) {
         self.infcx.register_region_obligation_with_cause(ty, lt, &ObligationCause::dummy());
     }
diff --git a/compiler/rustc_trait_selection/src/solve/normalizes_to/mod.rs b/compiler/rustc_trait_selection/src/solve/normalizes_to/mod.rs
index 22a77e2ecb8..8c63bd824bc 100644
--- a/compiler/rustc_trait_selection/src/solve/normalizes_to/mod.rs
+++ b/compiler/rustc_trait_selection/src/solve/normalizes_to/mod.rs
@@ -1,4 +1,4 @@
-use crate::traits::specialization_graph;
+use crate::traits::specialization_graph::{self, LeafDef, Node};
 
 use super::assembly::structural_traits::AsyncCallableRelevantTypes;
 use super::assembly::{self, structural_traits, Candidate};
@@ -9,7 +9,6 @@ use rustc_infer::infer::InferCtxt;
 use rustc_infer::traits::query::NoSolution;
 use rustc_infer::traits::solve::inspect::ProbeKind;
 use rustc_infer::traits::solve::MaybeCause;
-use rustc_infer::traits::specialization_graph::LeafDef;
 use rustc_infer::traits::Reveal;
 use rustc_middle::traits::solve::{CandidateSource, Certainty, Goal, QueryResult};
 use rustc_middle::traits::BuiltinImplSource;
@@ -189,8 +188,7 @@ impl<'tcx> assembly::GoalKind<'tcx> for NormalizesTo<'tcx> {
             // In case the associated item is hidden due to specialization, we have to
             // return ambiguity this would otherwise be incomplete, resulting in
             // unsoundness during coherence (#105782).
-            let Some(assoc_def) = fetch_eligible_assoc_item_def(
-                ecx,
+            let Some(assoc_def) = ecx.fetch_eligible_assoc_item_def(
                 goal.param_env,
                 goal_trait_ref,
                 goal.predicate.def_id(),
@@ -235,16 +233,10 @@ impl<'tcx> assembly::GoalKind<'tcx> for NormalizesTo<'tcx> {
             //
             // And then map these args to the args of the defining impl of `Assoc`, going
             // from `[u32, u64]` to `[u32, i32, u64]`.
-            let impl_args_with_gat =
-                goal.predicate.alias.args.rebase_onto(tcx, goal_trait_ref.def_id, impl_args);
-            let args = ecx.translate_args(
-                goal.param_env,
-                impl_def_id,
-                impl_args_with_gat,
-                assoc_def.defining_node,
-            );
+            let associated_item_args =
+                ecx.translate_args(&assoc_def, goal, impl_def_id, impl_args, impl_trait_ref)?;
 
-            if !tcx.check_args_compatible(assoc_def.item.def_id, args) {
+            if !tcx.check_args_compatible(assoc_def.item.def_id, associated_item_args) {
                 return error_response(
                     ecx,
                     "associated item has mismatched generic item arguments",
@@ -272,7 +264,7 @@ impl<'tcx> assembly::GoalKind<'tcx> for NormalizesTo<'tcx> {
                 ty::AssocKind::Fn => unreachable!("we should never project to a fn"),
             };
 
-            ecx.instantiate_normalizes_to_term(goal, term.instantiate(tcx, args));
+            ecx.instantiate_normalizes_to_term(goal, term.instantiate(tcx, associated_item_args));
             ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
         })
     }
@@ -889,38 +881,79 @@ impl<'tcx> assembly::GoalKind<'tcx> for NormalizesTo<'tcx> {
     }
 }
 
-/// This behavior is also implemented in `rustc_ty_utils` and in the old `project` code.
-///
-/// FIXME: We should merge these 3 implementations as it's likely that they otherwise
-/// diverge.
-#[instrument(level = "trace", skip(ecx, param_env), ret)]
-fn fetch_eligible_assoc_item_def<'tcx>(
-    ecx: &EvalCtxt<'_, InferCtxt<'tcx>>,
-    param_env: ty::ParamEnv<'tcx>,
-    goal_trait_ref: ty::TraitRef<'tcx>,
-    trait_assoc_def_id: DefId,
-    impl_def_id: DefId,
-) -> Result<Option<LeafDef>, NoSolution> {
-    let node_item =
-        specialization_graph::assoc_def(ecx.interner(), impl_def_id, trait_assoc_def_id)
-            .map_err(|ErrorGuaranteed { .. }| NoSolution)?;
-
-    let eligible = if node_item.is_final() {
-        // Non-specializable items are always projectable.
-        true
-    } else {
-        // Only reveal a specializable default if we're past type-checking
-        // and the obligation is monomorphic, otherwise passes such as
-        // transmute checking and polymorphic MIR optimizations could
-        // get a result which isn't correct for all monomorphizations.
-        if param_env.reveal() == Reveal::All {
-            let poly_trait_ref = ecx.resolve_vars_if_possible(goal_trait_ref);
-            !poly_trait_ref.still_further_specializable()
+impl<'tcx> EvalCtxt<'_, InferCtxt<'tcx>> {
+    fn translate_args(
+        &mut self,
+        assoc_def: &LeafDef,
+        goal: Goal<'tcx, ty::NormalizesTo<'tcx>>,
+        impl_def_id: DefId,
+        impl_args: ty::GenericArgsRef<'tcx>,
+        impl_trait_ref: rustc_type_ir::TraitRef<TyCtxt<'tcx>>,
+    ) -> Result<ty::GenericArgsRef<'tcx>, NoSolution> {
+        let tcx = self.interner();
+        Ok(match assoc_def.defining_node {
+            Node::Trait(_) => goal.predicate.alias.args,
+            Node::Impl(target_impl_def_id) => {
+                if target_impl_def_id == impl_def_id {
+                    // Same impl, no need to fully translate, just a rebase from
+                    // the trait is sufficient.
+                    goal.predicate.alias.args.rebase_onto(tcx, impl_trait_ref.def_id, impl_args)
+                } else {
+                    let target_args = self.fresh_args_for_item(target_impl_def_id);
+                    let target_trait_ref = tcx
+                        .impl_trait_ref(target_impl_def_id)
+                        .unwrap()
+                        .instantiate(tcx, target_args);
+                    // Relate source impl to target impl by equating trait refs.
+                    self.eq(goal.param_env, impl_trait_ref, target_trait_ref)?;
+                    // Also add predicates since they may be needed to constrain the
+                    // target impl's params.
+                    self.add_goals(
+                        GoalSource::Misc,
+                        tcx.predicates_of(target_impl_def_id)
+                            .instantiate(tcx, target_args)
+                            .into_iter()
+                            .map(|(pred, _)| goal.with(tcx, pred)),
+                    );
+                    goal.predicate.alias.args.rebase_onto(tcx, impl_trait_ref.def_id, target_args)
+                }
+            }
+        })
+    }
+
+    /// This behavior is also implemented in `rustc_ty_utils` and in the old `project` code.
+    ///
+    /// FIXME: We should merge these 3 implementations as it's likely that they otherwise
+    /// diverge.
+    #[instrument(level = "trace", skip(self, param_env), ret)]
+    fn fetch_eligible_assoc_item_def(
+        &self,
+        param_env: ty::ParamEnv<'tcx>,
+        goal_trait_ref: ty::TraitRef<'tcx>,
+        trait_assoc_def_id: DefId,
+        impl_def_id: DefId,
+    ) -> Result<Option<LeafDef>, NoSolution> {
+        let node_item =
+            specialization_graph::assoc_def(self.interner(), impl_def_id, trait_assoc_def_id)
+                .map_err(|ErrorGuaranteed { .. }| NoSolution)?;
+
+        let eligible = if node_item.is_final() {
+            // Non-specializable items are always projectable.
+            true
         } else {
-            trace!(?node_item.item.def_id, "not eligible due to default");
-            false
-        }
-    };
+            // Only reveal a specializable default if we're past type-checking
+            // and the obligation is monomorphic, otherwise passes such as
+            // transmute checking and polymorphic MIR optimizations could
+            // get a result which isn't correct for all monomorphizations.
+            if param_env.reveal() == Reveal::All {
+                let poly_trait_ref = self.resolve_vars_if_possible(goal_trait_ref);
+                !poly_trait_ref.still_further_specializable()
+            } else {
+                trace!(?node_item.item.def_id, "not eligible due to default");
+                false
+            }
+        };
 
-    if eligible { Ok(Some(node_item)) } else { Ok(None) }
+        if eligible { Ok(Some(node_item)) } else { Ok(None) }
+    }
 }
diff --git a/tests/ui/specialization/source-impl-requires-constraining-predicates-ambig.next.stderr b/tests/ui/specialization/source-impl-requires-constraining-predicates-ambig.next.stderr
new file mode 100644
index 00000000000..17918a77821
--- /dev/null
+++ b/tests/ui/specialization/source-impl-requires-constraining-predicates-ambig.next.stderr
@@ -0,0 +1,12 @@
+warning: the feature `specialization` is incomplete and may not be safe to use and/or cause compiler crashes
+  --> $DIR/source-impl-requires-constraining-predicates-ambig.rs:14:12
+   |
+LL | #![feature(specialization)]
+   |            ^^^^^^^^^^^^^^
+   |
+   = note: see issue #31844 <https://github.com/rust-lang/rust/issues/31844> for more information
+   = help: consider using `min_specialization` instead, which is more stable and complete
+   = note: `#[warn(incomplete_features)]` on by default
+
+warning: 1 warning emitted
+
diff --git a/tests/ui/specialization/source-impl-requires-constraining-predicates-ambig.rs b/tests/ui/specialization/source-impl-requires-constraining-predicates-ambig.rs
new file mode 100644
index 00000000000..977493c885b
--- /dev/null
+++ b/tests/ui/specialization/source-impl-requires-constraining-predicates-ambig.rs
@@ -0,0 +1,29 @@
+//@ revisions: current next
+//@ ignore-compare-mode-next-solver (explicit revisions)
+//@[next] compile-flags: -Znext-solver
+//@[next] check-pass
+//@[current] known-bug: unknown
+//@[current] failure-status: 101
+//@[current] dont-check-compiler-stderr
+
+// Tests that rebasing from the concrete impl to the default impl also processes the
+// `[u32; 0]: IntoIterator<Item = ?U>` predicate to constrain the `?U` impl arg.
+// This test also makes sure that we don't do anything weird when rebasing the args
+// is ambiguous.
+
+#![feature(specialization)]
+//[next]~^ WARN the feature `specialization` is incomplete
+
+trait Spec {
+    type Assoc;
+}
+
+default impl<T, U> Spec for T where T: IntoIterator<Item = U> {
+    type Assoc = U;
+}
+
+impl<T> Spec for [T; 0] {}
+
+fn main() {
+    let x: <[_; 0] as Spec>::Assoc = 1;
+}
diff --git a/tests/ui/specialization/source-impl-requires-constraining-predicates.current.stderr b/tests/ui/specialization/source-impl-requires-constraining-predicates.current.stderr
new file mode 100644
index 00000000000..3442e5b5ca6
--- /dev/null
+++ b/tests/ui/specialization/source-impl-requires-constraining-predicates.current.stderr
@@ -0,0 +1,12 @@
+warning: the feature `specialization` is incomplete and may not be safe to use and/or cause compiler crashes
+  --> $DIR/source-impl-requires-constraining-predicates.rs:9:12
+   |
+LL | #![feature(specialization)]
+   |            ^^^^^^^^^^^^^^
+   |
+   = note: see issue #31844 <https://github.com/rust-lang/rust/issues/31844> for more information
+   = help: consider using `min_specialization` instead, which is more stable and complete
+   = note: `#[warn(incomplete_features)]` on by default
+
+warning: 1 warning emitted
+
diff --git a/tests/ui/specialization/source-impl-requires-constraining-predicates.next.stderr b/tests/ui/specialization/source-impl-requires-constraining-predicates.next.stderr
new file mode 100644
index 00000000000..3442e5b5ca6
--- /dev/null
+++ b/tests/ui/specialization/source-impl-requires-constraining-predicates.next.stderr
@@ -0,0 +1,12 @@
+warning: the feature `specialization` is incomplete and may not be safe to use and/or cause compiler crashes
+  --> $DIR/source-impl-requires-constraining-predicates.rs:9:12
+   |
+LL | #![feature(specialization)]
+   |            ^^^^^^^^^^^^^^
+   |
+   = note: see issue #31844 <https://github.com/rust-lang/rust/issues/31844> for more information
+   = help: consider using `min_specialization` instead, which is more stable and complete
+   = note: `#[warn(incomplete_features)]` on by default
+
+warning: 1 warning emitted
+
diff --git a/tests/ui/specialization/source-impl-requires-constraining-predicates.rs b/tests/ui/specialization/source-impl-requires-constraining-predicates.rs
new file mode 100644
index 00000000000..532fc367640
--- /dev/null
+++ b/tests/ui/specialization/source-impl-requires-constraining-predicates.rs
@@ -0,0 +1,24 @@
+//@ check-pass
+//@ revisions: current next
+//@ ignore-compare-mode-next-solver (explicit revisions)
+//@[next] compile-flags: -Znext-solver
+
+// Tests that rebasing from the concrete impl to the default impl also processes the
+// `[u32; 0]: IntoIterator<Item = ?U>` predicate to constrain the `?U` impl arg.
+
+#![feature(specialization)]
+//~^ WARN the feature `specialization` is incomplete
+
+trait Spec {
+    type Assoc;
+}
+
+default impl<T, U> Spec for T where T: IntoIterator<Item = U> {
+    type Assoc = U;
+}
+
+impl<T> Spec for [T; 0] {}
+
+fn main() {
+    let x: <[u32; 0] as Spec>::Assoc = 1;
+}