about summary refs log tree commit diff
diff options
context:
space:
mode:
authorSantiago Pastorino <spastorino@gmail.com>2022-08-22 15:52:49 -0300
committerSantiago Pastorino <spastorino@gmail.com>2022-08-23 08:55:43 -0300
commitac0b6af37bc6d8ed6f4468a8c3feab31ebb9e15d (patch)
tree8a60e1480c599ec3e68930161166f3d17f793d28
parent5ff45dc89efdaabe903e5bff4dc1c170def7b325 (diff)
downloadrust-ac0b6af37bc6d8ed6f4468a8c3feab31ebb9e15d.tar.gz
rust-ac0b6af37bc6d8ed6f4468a8c3feab31ebb9e15d.zip
Permit negative impls coherence to take advantage of implied bounds
-rw-r--r--compiler/rustc_trait_selection/src/traits/coherence.rs34
-rw-r--r--src/test/ui/coherence/coherence-negative-outlives-lifetimes.rs6
-rw-r--r--src/test/ui/coherence/coherence-negative-outlives-lifetimes.with_negative_coherence.stderr11
3 files changed, 29 insertions, 22 deletions
diff --git a/compiler/rustc_trait_selection/src/traits/coherence.rs b/compiler/rustc_trait_selection/src/traits/coherence.rs
index 3bc08fba91a..fb2440ef457 100644
--- a/compiler/rustc_trait_selection/src/traits/coherence.rs
+++ b/compiler/rustc_trait_selection/src/traits/coherence.rs
@@ -6,12 +6,13 @@
 
 use crate::infer::outlives::env::OutlivesEnvironment;
 use crate::infer::{CombinedSnapshot, InferOk};
+use crate::traits::outlives_bounds::InferCtxtExt as _;
 use crate::traits::select::IntercrateAmbiguityCause;
 use crate::traits::util::impl_subject_and_oblig;
 use crate::traits::SkipLeakCheck;
 use crate::traits::{
-    self, Normalized, Obligation, ObligationCause, PredicateObligation, PredicateObligations,
-    SelectionContext,
+    self, Normalized, Obligation, ObligationCause, ObligationCtxt, PredicateObligation,
+    PredicateObligations, SelectionContext,
 };
 use rustc_data_structures::fx::FxIndexSet;
 use rustc_errors::Diagnostic;
@@ -322,7 +323,7 @@ fn negative_impl<'cx, 'tcx>(
         let (subject2, obligations) =
             impl_subject_and_oblig(selcx, impl_env, impl2_def_id, impl2_substs);
 
-        !equate(&infcx, impl_env, subject1, subject2, obligations)
+        !equate(&infcx, impl_env, subject1, subject2, obligations, impl1_def_id)
     })
 }
 
@@ -332,6 +333,7 @@ fn equate<'cx, 'tcx>(
     subject1: ImplSubject<'tcx>,
     subject2: ImplSubject<'tcx>,
     obligations: impl Iterator<Item = PredicateObligation<'tcx>>,
+    body_def_id: DefId,
 ) -> bool {
     // do the impls unify? If not, not disjoint.
     let Ok(InferOk { obligations: more_obligations, .. }) =
@@ -342,8 +344,10 @@ fn equate<'cx, 'tcx>(
     };
 
     let selcx = &mut SelectionContext::new(&infcx);
-    let opt_failing_obligation =
-        obligations.into_iter().chain(more_obligations).find(|o| negative_impl_exists(selcx, o));
+    let opt_failing_obligation = obligations
+        .into_iter()
+        .chain(more_obligations)
+        .find(|o| negative_impl_exists(selcx, o, body_def_id));
 
     if let Some(failing_obligation) = opt_failing_obligation {
         debug!("overlap: obligation unsatisfiable {:?}", failing_obligation);
@@ -358,14 +362,15 @@ fn equate<'cx, 'tcx>(
 fn negative_impl_exists<'cx, 'tcx>(
     selcx: &SelectionContext<'cx, 'tcx>,
     o: &PredicateObligation<'tcx>,
+    body_def_id: DefId,
 ) -> bool {
-    if resolve_negative_obligation(selcx.infcx().fork(), o) {
+    if resolve_negative_obligation(selcx.infcx().fork(), o, body_def_id) {
         return true;
     }
 
     // Try to prove a negative obligation exists for super predicates
     for o in util::elaborate_predicates(selcx.tcx(), iter::once(o.predicate)) {
-        if resolve_negative_obligation(selcx.infcx().fork(), &o) {
+        if resolve_negative_obligation(selcx.infcx().fork(), &o, body_def_id) {
             return true;
         }
     }
@@ -377,6 +382,7 @@ fn negative_impl_exists<'cx, 'tcx>(
 fn resolve_negative_obligation<'cx, 'tcx>(
     infcx: InferCtxt<'cx, 'tcx>,
     o: &PredicateObligation<'tcx>,
+    body_def_id: DefId,
 ) -> bool {
     let tcx = infcx.tcx;
 
@@ -390,7 +396,19 @@ fn resolve_negative_obligation<'cx, 'tcx>(
         return false;
     }
 
-    let outlives_env = OutlivesEnvironment::new(param_env);
+    let outlives_env = if let Some(body_def_id) = body_def_id.as_local() {
+        let body_id = tcx.hir().local_def_id_to_hir_id(body_def_id);
+        let ocx = ObligationCtxt::new(&infcx);
+        let wf_tys = ocx.assumed_wf_types(param_env, DUMMY_SP, body_def_id);
+        OutlivesEnvironment::with_bounds(
+            param_env,
+            Some(&infcx),
+            infcx.implied_bounds_tys(param_env, body_id, wf_tys),
+        )
+    } else {
+        OutlivesEnvironment::new(param_env)
+    };
+
     infcx.process_registered_region_obligations(outlives_env.region_bound_pairs(), param_env);
 
     infcx.resolve_regions(&outlives_env).is_empty()
diff --git a/src/test/ui/coherence/coherence-negative-outlives-lifetimes.rs b/src/test/ui/coherence/coherence-negative-outlives-lifetimes.rs
index 221c1bc23b3..3acf0d8d39a 100644
--- a/src/test/ui/coherence/coherence-negative-outlives-lifetimes.rs
+++ b/src/test/ui/coherence/coherence-negative-outlives-lifetimes.rs
@@ -1,9 +1,9 @@
 // revisions: stock with_negative_coherence
+//[with_negative_coherence] check-pass
+
 #![feature(negative_impls)]
 #![cfg_attr(with_negative_coherence, feature(with_negative_coherence))]
 
-// FIXME: this should compile
-
 trait MyPredicate<'a> {}
 
 impl<'a, T> !MyPredicate<'a> for &'a T where T: 'a {}
@@ -12,6 +12,6 @@ trait MyTrait<'a> {}
 
 impl<'a, T: MyPredicate<'a>> MyTrait<'a> for T {}
 impl<'a, T> MyTrait<'a> for &'a T {}
-//~^ ERROR: conflicting implementations of trait `MyTrait<'_>` for type `&_`
+//[stock]~^ ERROR: conflicting implementations of trait `MyTrait<'_>` for type `&_`
 
 fn main() {}
diff --git a/src/test/ui/coherence/coherence-negative-outlives-lifetimes.with_negative_coherence.stderr b/src/test/ui/coherence/coherence-negative-outlives-lifetimes.with_negative_coherence.stderr
deleted file mode 100644
index 097cc4e0fe3..00000000000
--- a/src/test/ui/coherence/coherence-negative-outlives-lifetimes.with_negative_coherence.stderr
+++ /dev/null
@@ -1,11 +0,0 @@
-error[E0119]: conflicting implementations of trait `MyTrait<'_>` for type `&_`
-  --> $DIR/coherence-negative-outlives-lifetimes.rs:14:1
-   |
-LL | impl<'a, T: MyPredicate<'a>> MyTrait<'a> for T {}
-   | ---------------------------------------------- first implementation here
-LL | impl<'a, T> MyTrait<'a> for &'a T {}
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `&_`
-
-error: aborting due to previous error
-
-For more information about this error, try `rustc --explain E0119`.