about summary refs log tree commit diff
diff options
context:
space:
mode:
authorMatthew Jasper <mjjasper1@gmail.com>2023-05-05 15:50:17 +0100
committerMatthew Jasper <mjjasper1@gmail.com>2023-05-05 16:19:18 +0100
commitfafe9e71d5c949c41a5a562e44cc40d72c5f7244 (patch)
tree749a6445e601a5b8b6ee252a91dc23fa95cf0d64
parentbd928a0b5e144b0fafb2f4659a83aa362de7e3c7 (diff)
downloadrust-fafe9e71d5c949c41a5a562e44cc40d72c5f7244.tar.gz
rust-fafe9e71d5c949c41a5a562e44cc40d72c5f7244.zip
Normalize consistently for specializations
-rw-r--r--compiler/rustc_trait_selection/src/traits/specialize/mod.rs39
-rw-r--r--tests/ui/specialization/min_specialization/specialize-associated-type.rs37
-rw-r--r--tests/ui/specialization/min_specialization/specialize_on_type_error.rs33
-rw-r--r--tests/ui/specialization/min_specialization/specialize_on_type_error.stderr12
4 files changed, 104 insertions, 17 deletions
diff --git a/compiler/rustc_trait_selection/src/traits/specialize/mod.rs b/compiler/rustc_trait_selection/src/traits/specialize/mod.rs
index 233d35aed38..8bbebadb22a 100644
--- a/compiler/rustc_trait_selection/src/traits/specialize/mod.rs
+++ b/compiler/rustc_trait_selection/src/traits/specialize/mod.rs
@@ -99,14 +99,13 @@ pub fn translate_substs<'tcx>(
                 return source_substs;
             }
 
-            fulfill_implication(infcx, param_env, source_trait_ref, target_impl).unwrap_or_else(
-                |()| {
+            fulfill_implication(infcx, param_env, source_trait_ref, source_impl, target_impl)
+                .unwrap_or_else(|()| {
                     bug!(
                         "When translating substitutions from {source_impl:?} to {target_impl:?}, \
                         the expected specialization failed to hold"
                     )
-                },
-            )
+                })
         }
         specialization_graph::Node::Trait(..) => source_trait_ref.substs,
     };
@@ -153,20 +152,9 @@ pub(super) fn specializes(tcx: TyCtxt<'_>, (impl1_def_id, impl2_def_id): (DefId,
 
     // Create an infcx, taking the predicates of impl1 as assumptions:
     let infcx = tcx.infer_ctxt().build();
-    let impl1_trait_ref =
-        match traits::fully_normalize(&infcx, ObligationCause::dummy(), penv, impl1_trait_ref) {
-            Ok(impl1_trait_ref) => impl1_trait_ref,
-            Err(_errors) => {
-                tcx.sess.delay_span_bug(
-                    tcx.def_span(impl1_def_id),
-                    format!("failed to fully normalize {impl1_trait_ref}"),
-                );
-                impl1_trait_ref
-            }
-        };
 
     // Attempt to prove that impl2 applies, given all of the above.
-    fulfill_implication(&infcx, penv, impl1_trait_ref, impl2_def_id).is_ok()
+    fulfill_implication(&infcx, penv, impl1_trait_ref, impl1_def_id, impl2_def_id).is_ok()
 }
 
 /// Attempt to fulfill all obligations of `target_impl` after unification with
@@ -178,6 +166,7 @@ fn fulfill_implication<'tcx>(
     infcx: &InferCtxt<'tcx>,
     param_env: ty::ParamEnv<'tcx>,
     source_trait_ref: ty::TraitRef<'tcx>,
+    source_impl: DefId,
     target_impl: DefId,
 ) -> Result<SubstsRef<'tcx>, ()> {
     debug!(
@@ -185,6 +174,22 @@ fn fulfill_implication<'tcx>(
         param_env, source_trait_ref, target_impl
     );
 
+    let source_trait_ref = match traits::fully_normalize(
+        &infcx,
+        ObligationCause::dummy(),
+        param_env,
+        source_trait_ref,
+    ) {
+        Ok(source_trait_ref) => source_trait_ref,
+        Err(_errors) => {
+            infcx.tcx.sess.delay_span_bug(
+                infcx.tcx.def_span(source_impl),
+                format!("failed to fully normalize {source_trait_ref}"),
+            );
+            source_trait_ref
+        }
+    };
+
     let source_trait = ImplSubject::Trait(source_trait_ref);
 
     let selcx = &mut SelectionContext::new(&infcx);
@@ -194,7 +199,7 @@ fn fulfill_implication<'tcx>(
 
     // do the impls unify? If not, no specialization.
     let Ok(InferOk { obligations: more_obligations, .. }) =
-        infcx.at(&ObligationCause::dummy(), param_env, ).eq(DefineOpaqueTypes::No,source_trait, target_trait)
+        infcx.at(&ObligationCause::dummy(), param_env).eq(DefineOpaqueTypes::No, source_trait, target_trait)
     else {
         debug!(
             "fulfill_implication: {:?} does not unify with {:?}",
diff --git a/tests/ui/specialization/min_specialization/specialize-associated-type.rs b/tests/ui/specialization/min_specialization/specialize-associated-type.rs
new file mode 100644
index 00000000000..c4960b0c28e
--- /dev/null
+++ b/tests/ui/specialization/min_specialization/specialize-associated-type.rs
@@ -0,0 +1,37 @@
+// Another regression test for #109815.
+
+// check-pass
+
+#![feature(min_specialization)]
+#![feature(rustc_attrs)]
+
+#[rustc_specialization_trait]
+trait X {}
+trait Z {
+    type Assoc: X;
+}
+struct A<T>(T);
+
+impl X for () {}
+
+impl<T: X> Z for A<T> {
+    type Assoc = ();
+}
+
+trait MyFrom<T> {
+    fn from(other: T) -> Self;
+}
+
+impl<T> MyFrom<()> for T {
+    default fn from(other: ()) -> T {
+        panic!();
+    }
+}
+
+impl<T: X> MyFrom<<A<T> as Z>::Assoc> for T {
+    fn from(other: ()) -> T {
+        panic!();
+    }
+}
+
+fn main() {}
diff --git a/tests/ui/specialization/min_specialization/specialize_on_type_error.rs b/tests/ui/specialization/min_specialization/specialize_on_type_error.rs
new file mode 100644
index 00000000000..24e92a0abc3
--- /dev/null
+++ b/tests/ui/specialization/min_specialization/specialize_on_type_error.rs
@@ -0,0 +1,33 @@
+// A regression test for #109815.
+
+#![feature(min_specialization)]
+#![feature(rustc_attrs)]
+
+#[rustc_specialization_trait]
+trait X {}
+trait Y: X {}
+trait Z {
+    type Assoc: Y;
+}
+struct A<T>(T);
+
+impl<T: X> Z for A<T> {}
+//~^ ERROR not all trait items implemented
+
+trait MyFrom<T> {
+    fn from(other: T) -> Self;
+}
+
+impl<T> MyFrom<T> for T {
+    default fn from(other: T) -> T {
+        other
+    }
+}
+
+impl<T: X> MyFrom<<A<T> as Z>::Assoc> for T {
+    fn from(other: <A<T> as Z>::Assoc) -> T {
+        other
+    }
+}
+
+fn main() {}
diff --git a/tests/ui/specialization/min_specialization/specialize_on_type_error.stderr b/tests/ui/specialization/min_specialization/specialize_on_type_error.stderr
new file mode 100644
index 00000000000..cc12302bd8c
--- /dev/null
+++ b/tests/ui/specialization/min_specialization/specialize_on_type_error.stderr
@@ -0,0 +1,12 @@
+error[E0046]: not all trait items implemented, missing: `Assoc`
+  --> $DIR/specialize_on_type_error.rs:14:1
+   |
+LL |     type Assoc: Y;
+   |     ------------- `Assoc` from trait
+...
+LL | impl<T: X> Z for A<T> {}
+   | ^^^^^^^^^^^^^^^^^^^^^ missing `Assoc` in implementation
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0046`.