From ac0b6af37bc6d8ed6f4468a8c3feab31ebb9e15d Mon Sep 17 00:00:00 2001 From: Santiago Pastorino Date: Mon, 22 Aug 2022 15:52:49 -0300 Subject: [PATCH] Permit negative impls coherence to take advantage of implied bounds --- .../src/traits/coherence.rs | 34 ++++++++++++++----- .../coherence-negative-outlives-lifetimes.rs | 6 ++-- ...s-lifetimes.with_negative_coherence.stderr | 11 ------ 3 files changed, 29 insertions(+), 22 deletions(-) delete mode 100644 src/test/ui/coherence/coherence-negative-outlives-lifetimes.with_negative_coherence.stderr 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>, + 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`.