about summary refs log tree commit diff
diff options
context:
space:
mode:
authorSantiago Pastorino <spastorino@gmail.com>2022-03-17 22:51:45 -0300
committerSantiago Pastorino <spastorino@gmail.com>2022-03-18 14:11:04 -0300
commit89fdb62331df00cf3f0fbd064b159d49d4d0fb48 (patch)
tree350743f319277cd7f7fcdf5cc1bc87c53fac6dec
parenta8adf7685a4ddd16e985d34d9838a75a04ca4181 (diff)
downloadrust-89fdb62331df00cf3f0fbd064b159d49d4d0fb48.tar.gz
rust-89fdb62331df00cf3f0fbd064b159d49d4d0fb48.zip
Fix inherent impls on negative coherence
-rw-r--r--compiler/rustc_trait_selection/src/traits/coherence.rs110
-rw-r--r--src/test/ui/coherence/coherence-negative-inherent.rs22
2 files changed, 89 insertions, 43 deletions
diff --git a/compiler/rustc_trait_selection/src/traits/coherence.rs b/compiler/rustc_trait_selection/src/traits/coherence.rs
index 94a4001bbb9..83f54d6dc3d 100644
--- a/compiler/rustc_trait_selection/src/traits/coherence.rs
+++ b/compiler/rustc_trait_selection/src/traits/coherence.rs
@@ -300,55 +300,79 @@ fn negative_impl<'cx, 'tcx>(
     debug!("negative_impl(impl1_def_id={:?}, impl2_def_id={:?})", impl1_def_id, impl2_def_id);
     let tcx = selcx.infcx().tcx;
 
-    // create a parameter environment corresponding to a (placeholder) instantiation of impl1
-    let impl1_env = tcx.param_env(impl1_def_id);
-    let impl1_trait_ref = tcx.impl_trait_ref(impl1_def_id).unwrap();
-
     // Create an infcx, taking the predicates of impl1 as assumptions:
     tcx.infer_ctxt().enter(|infcx| {
-        // Normalize the trait reference. The WF rules ought to ensure
-        // that this always succeeds.
-        let impl1_trait_ref = match traits::fully_normalize(
-            &infcx,
-            FulfillmentContext::new(),
-            ObligationCause::dummy(),
-            impl1_env,
-            impl1_trait_ref,
-        ) {
-            Ok(impl1_trait_ref) => impl1_trait_ref,
-            Err(err) => {
-                bug!("failed to fully normalize {:?}: {:?}", impl1_trait_ref, err);
-            }
-        };
+        // create a parameter environment corresponding to a (placeholder) instantiation of impl1
+        let impl1_env = tcx.param_env(impl1_def_id);
+
+        if let Some(impl1_trait_ref) = tcx.impl_trait_ref(impl1_def_id) {
+            // Normalize the trait reference. The WF rules ought to ensure
+            // that this always succeeds.
+            let impl1_trait_ref = match traits::fully_normalize(
+                &infcx,
+                FulfillmentContext::new(),
+                ObligationCause::dummy(),
+                impl1_env,
+                impl1_trait_ref,
+            ) {
+                Ok(impl1_trait_ref) => impl1_trait_ref,
+                Err(err) => {
+                    bug!("failed to fully normalize {:?}: {:?}", impl1_trait_ref, err);
+                }
+            };
 
-        // Attempt to prove that impl2 applies, given all of the above.
-        let selcx = &mut SelectionContext::new(&infcx);
-        let impl2_substs = infcx.fresh_substs_for_item(DUMMY_SP, impl2_def_id);
-        let (impl2_trait_ref, obligations) =
-            impl_trait_ref_and_oblig(selcx, impl1_env, impl2_def_id, impl2_substs);
+            // Attempt to prove that impl2 applies, given all of the above.
+            let selcx = &mut SelectionContext::new(&infcx);
+            let impl2_substs = infcx.fresh_substs_for_item(DUMMY_SP, impl2_def_id);
+            let (impl2_trait_ref, obligations) =
+                impl_trait_ref_and_oblig(selcx, impl1_env, impl2_def_id, impl2_substs);
 
-        // do the impls unify? If not, not disjoint.
-        let Ok(InferOk { obligations: more_obligations, .. }) = infcx
+            // do the impls unify? If not, not disjoint.
+            let Ok(InferOk { obligations: more_obligations, .. }) = infcx
             .at(&ObligationCause::dummy(), impl1_env)
-            .eq(impl1_trait_ref, impl2_trait_ref)
-        else {
-            debug!(
-                "explicit_disjoint: {:?} does not unify with {:?}",
-                impl1_trait_ref, impl2_trait_ref
-            );
-            return false;
-        };
-
-        let opt_failing_obligation = obligations
-            .into_iter()
-            .chain(more_obligations)
-            .find(|o| negative_impl_exists(selcx, impl1_env, impl1_def_id, o));
-
-        if let Some(failing_obligation) = opt_failing_obligation {
-            debug!("overlap: obligation unsatisfiable {:?}", failing_obligation);
-            true
+            .eq(impl1_trait_ref, impl2_trait_ref) else {
+                debug!(
+                    "explicit_disjoint: {:?} does not unify with {:?}",
+                    impl1_trait_ref, impl2_trait_ref
+                );
+                return false;
+            };
+
+            let opt_failing_obligation = obligations
+                .into_iter()
+                .chain(more_obligations)
+                .find(|o| negative_impl_exists(selcx, impl1_env, impl1_def_id, o));
+
+            if let Some(failing_obligation) = opt_failing_obligation {
+                debug!("overlap: obligation unsatisfiable {:?}", failing_obligation);
+                true
+            } else {
+                false
+            }
         } else {
-            false
+            let ty1 = tcx.type_of(impl1_def_id);
+            let ty2 = tcx.type_of(impl2_def_id);
+
+            let Ok(InferOk { obligations, .. }) = infcx
+            .at(&ObligationCause::dummy(), impl1_env)
+            .eq(ty1, ty2) else {
+                debug!(
+                    "explicit_disjoint: {:?} does not unify with {:?}",
+                    ty1, ty2
+                );
+                return false;
+            };
+
+            let opt_failing_obligation = obligations
+                .into_iter()
+                .find(|o| negative_impl_exists(selcx, impl1_env, impl1_def_id, o));
+
+            if let Some(failing_obligation) = opt_failing_obligation {
+                debug!("overlap: obligation unsatisfiable {:?}", failing_obligation);
+                true
+            } else {
+                false
+            }
         }
     })
 }
diff --git a/src/test/ui/coherence/coherence-negative-inherent.rs b/src/test/ui/coherence/coherence-negative-inherent.rs
new file mode 100644
index 00000000000..a9e1acc8044
--- /dev/null
+++ b/src/test/ui/coherence/coherence-negative-inherent.rs
@@ -0,0 +1,22 @@
+// check-pass
+
+#![feature(negative_impls)]
+#![feature(rustc_attrs)]
+#![feature(with_negative_coherence)]
+
+#[rustc_strict_coherence]
+trait Foo {}
+
+impl !Foo for u32 {}
+
+struct MyStruct<T>(T);
+
+impl<T: Foo> MyStruct<T> {
+    fn method(&self) {}
+}
+
+impl MyStruct<u32> {
+    fn method(&self) {}
+}
+
+fn main() {}