about summary refs log tree commit diff
diff options
context:
space:
mode:
authorSantiago Pastorino <spastorino@gmail.com>2022-03-17 11:26:45 -0300
committerSantiago Pastorino <spastorino@gmail.com>2022-03-17 12:15:11 -0300
commit64dfd3b2340a42f5fda5802d50c9739d38533102 (patch)
treeaf400c4c1e7bb7983e39dfbc999c7e9f2ad07d55
parent78346489c66779d024c60af2d2f0f5d9d455f688 (diff)
downloadrust-64dfd3b2340a42f5fda5802d50c9739d38533102.tar.gz
rust-64dfd3b2340a42f5fda5802d50c9739d38533102.zip
Make negative coherence work when there's impl negative on super predicates
-rw-r--r--compiler/rustc_trait_selection/src/traits/coherence.rs24
-rw-r--r--src/test/ui/coherence/coherence-overlap-super-negative.rs18
2 files changed, 34 insertions, 8 deletions
diff --git a/compiler/rustc_trait_selection/src/traits/coherence.rs b/compiler/rustc_trait_selection/src/traits/coherence.rs
index a3d32acc6fb..72a06abd8e0 100644
--- a/compiler/rustc_trait_selection/src/traits/coherence.rs
+++ b/compiler/rustc_trait_selection/src/traits/coherence.rs
@@ -18,7 +18,7 @@ use rustc_errors::Diagnostic;
 use rustc_hir::def_id::{DefId, LOCAL_CRATE};
 use rustc_hir::CRATE_HIR_ID;
 use rustc_infer::infer::TyCtxtInferExt;
-use rustc_infer::traits::TraitEngine;
+use rustc_infer::traits::{util, TraitEngine};
 use rustc_middle::traits::specialization_graph::OverlapMode;
 use rustc_middle::ty::fast_reject::{self, TreatParams};
 use rustc_middle::ty::fold::TypeFoldable;
@@ -353,6 +353,7 @@ fn negative_impl<'cx, 'tcx>(
     })
 }
 
+#[instrument(level = "debug", skip(selcx))]
 fn negative_impl_exists<'cx, 'tcx>(
     selcx: &SelectionContext<'cx, 'tcx>,
     param_env: ty::ParamEnv<'tcx>,
@@ -361,14 +362,18 @@ fn negative_impl_exists<'cx, 'tcx>(
 ) -> bool {
     let infcx = &selcx.infcx().fork();
     let tcx = infcx.tcx;
-    o.flip_polarity(tcx)
-        .map(|o| {
+
+    let super_obligations = util::elaborate_predicates(tcx, iter::once(o.predicate));
+
+    for o in iter::once(o.clone()).chain(super_obligations) {
+        if let Some(o) = o.flip_polarity(tcx) {
             let mut fulfillment_cx = FulfillmentContext::new();
             fulfillment_cx.register_predicate_obligation(infcx, o);
 
             let errors = fulfillment_cx.select_all_or_error(infcx);
+
             if !errors.is_empty() {
-                return false;
+                continue;
             }
 
             let mut outlives_env = OutlivesEnvironment::new(param_env);
@@ -389,13 +394,16 @@ fn negative_impl_exists<'cx, 'tcx>(
 
             let errors =
                 infcx.resolve_regions(region_context, &outlives_env, RegionckMode::default());
+
             if !errors.is_empty() {
-                return false;
+                continue;
             }
 
-            true
-        })
-        .unwrap_or(false)
+            return true;
+        }
+    }
+
+    false
 }
 
 pub fn trait_ref_is_knowable<'tcx>(
diff --git a/src/test/ui/coherence/coherence-overlap-super-negative.rs b/src/test/ui/coherence/coherence-overlap-super-negative.rs
new file mode 100644
index 00000000000..d296a094a37
--- /dev/null
+++ b/src/test/ui/coherence/coherence-overlap-super-negative.rs
@@ -0,0 +1,18 @@
+// check-pass
+
+#![feature(negative_impls)]
+#![feature(rustc_attrs)]
+#![feature(with_negative_coherence)]
+
+trait Trait1: Trait2 {}
+trait Trait2 {}
+
+struct MyType {}
+impl !Trait2 for MyType {}
+
+#[rustc_strict_coherence]
+trait Foo {}
+impl<T: Trait1> Foo for T {}
+impl Foo for MyType {}
+
+fn main() {}