From 5ff45dc89efdaabe903e5bff4dc1c170def7b325 Mon Sep 17 00:00:00 2001 From: Santiago Pastorino Date: Mon, 22 Aug 2022 16:53:34 -0300 Subject: [PATCH 1/4] Move InferCtxtExt to rustc_trait_selection --- compiler/rustc_trait_selection/src/lib.rs | 1 + compiler/rustc_trait_selection/src/traits/mod.rs | 1 + .../src/traits}/outlives_bounds.rs | 8 ++++---- compiler/rustc_typeck/src/check/compare_method.rs | 2 +- compiler/rustc_typeck/src/check/wfcheck.rs | 2 +- .../rustc_typeck/src/impl_wf_check/min_specialization.rs | 2 +- compiler/rustc_typeck/src/outlives/mod.rs | 1 - 7 files changed, 9 insertions(+), 8 deletions(-) rename compiler/{rustc_typeck/src/outlives => rustc_trait_selection/src/traits}/outlives_bounds.rs (93%) diff --git a/compiler/rustc_trait_selection/src/lib.rs b/compiler/rustc_trait_selection/src/lib.rs index 9c252fcfe1c63..ce48d4c99e9de 100644 --- a/compiler/rustc_trait_selection/src/lib.rs +++ b/compiler/rustc_trait_selection/src/lib.rs @@ -20,6 +20,7 @@ #![feature(let_else)] #![feature(if_let_guard)] #![feature(never_type)] +#![feature(type_alias_impl_trait)] #![recursion_limit = "512"] // For rustdoc #[macro_use] diff --git a/compiler/rustc_trait_selection/src/traits/mod.rs b/compiler/rustc_trait_selection/src/traits/mod.rs index 85ff6e23711ca..86471eeb070e0 100644 --- a/compiler/rustc_trait_selection/src/traits/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/mod.rs @@ -13,6 +13,7 @@ mod fulfill; pub mod misc; mod object_safety; mod on_unimplemented; +pub mod outlives_bounds; mod project; pub mod query; pub(crate) mod relationships; diff --git a/compiler/rustc_typeck/src/outlives/outlives_bounds.rs b/compiler/rustc_trait_selection/src/traits/outlives_bounds.rs similarity index 93% rename from compiler/rustc_typeck/src/outlives/outlives_bounds.rs rename to compiler/rustc_trait_selection/src/traits/outlives_bounds.rs index 024e20d92234b..a4b540182280b 100644 --- a/compiler/rustc_typeck/src/outlives/outlives_bounds.rs +++ b/compiler/rustc_trait_selection/src/traits/outlives_bounds.rs @@ -1,11 +1,11 @@ +use crate::infer::InferCtxt; +use crate::traits::query::type_op::{self, TypeOp, TypeOpOutput}; +use crate::traits::query::NoSolution; +use crate::traits::{ObligationCause, TraitEngine, TraitEngineExt}; use rustc_data_structures::fx::FxHashSet; use rustc_hir as hir; use rustc_hir::HirId; use rustc_middle::ty::{self, ParamEnv, Ty}; -use rustc_trait_selection::infer::InferCtxt; -use rustc_trait_selection::traits::query::type_op::{self, TypeOp, TypeOpOutput}; -use rustc_trait_selection::traits::query::NoSolution; -use rustc_trait_selection::traits::{ObligationCause, TraitEngine, TraitEngineExt}; pub use rustc_middle::traits::query::OutlivesBound; diff --git a/compiler/rustc_typeck/src/check/compare_method.rs b/compiler/rustc_typeck/src/check/compare_method.rs index dfef924f6993a..af5e5622fb381 100644 --- a/compiler/rustc_typeck/src/check/compare_method.rs +++ b/compiler/rustc_typeck/src/check/compare_method.rs @@ -1,6 +1,5 @@ use super::potentially_plural_count; use crate::errors::LifetimesOrBoundsMismatchOnTrait; -use crate::outlives::outlives_bounds::InferCtxtExt as _; use rustc_data_structures::fx::FxHashSet; use rustc_errors::{pluralize, struct_span_err, Applicability, DiagnosticId, ErrorGuaranteed}; use rustc_hir as hir; @@ -17,6 +16,7 @@ use rustc_middle::ty::{self, DefIdTree}; use rustc_middle::ty::{GenericParamDefKind, ToPredicate, TyCtxt}; use rustc_span::Span; use rustc_trait_selection::traits::error_reporting::InferCtxtExt; +use rustc_trait_selection::traits::outlives_bounds::InferCtxtExt as _; use rustc_trait_selection::traits::{ self, ObligationCause, ObligationCauseCode, ObligationCtxt, Reveal, }; diff --git a/compiler/rustc_typeck/src/check/wfcheck.rs b/compiler/rustc_typeck/src/check/wfcheck.rs index e8243d666b641..ce42647c837a5 100644 --- a/compiler/rustc_typeck/src/check/wfcheck.rs +++ b/compiler/rustc_typeck/src/check/wfcheck.rs @@ -1,5 +1,4 @@ use crate::constrained_generic_params::{identify_constrained_generic_params, Parameter}; -use crate::outlives::outlives_bounds::InferCtxtExt as _; use rustc_ast as ast; use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc_errors::{pluralize, struct_span_err, Applicability, DiagnosticBuilder, ErrorGuaranteed}; @@ -22,6 +21,7 @@ use rustc_span::symbol::{sym, Ident, Symbol}; use rustc_span::{Span, DUMMY_SP}; use rustc_trait_selection::autoderef::Autoderef; use rustc_trait_selection::traits::error_reporting::InferCtxtExt; +use rustc_trait_selection::traits::outlives_bounds::InferCtxtExt as _; use rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt as _; use rustc_trait_selection::traits::{ self, ObligationCause, ObligationCauseCode, ObligationCtxt, WellFormedLoc, diff --git a/compiler/rustc_typeck/src/impl_wf_check/min_specialization.rs b/compiler/rustc_typeck/src/impl_wf_check/min_specialization.rs index 6240024d49c74..2741d9f776ce2 100644 --- a/compiler/rustc_typeck/src/impl_wf_check/min_specialization.rs +++ b/compiler/rustc_typeck/src/impl_wf_check/min_specialization.rs @@ -67,7 +67,6 @@ use crate::constrained_generic_params as cgp; use crate::errors::SubstsOnOverriddenImpl; -use crate::outlives::outlives_bounds::InferCtxtExt as _; use rustc_data_structures::fx::FxHashSet; use rustc_hir::def_id::{DefId, LocalDefId}; @@ -79,6 +78,7 @@ use rustc_middle::ty::trait_def::TraitSpecializationKind; use rustc_middle::ty::{self, TyCtxt, TypeVisitable}; use rustc_span::Span; use rustc_trait_selection::traits::error_reporting::InferCtxtExt; +use rustc_trait_selection::traits::outlives_bounds::InferCtxtExt as _; use rustc_trait_selection::traits::{self, translate_substs, wf, ObligationCtxt}; pub(super) fn check_min_specialization(tcx: TyCtxt<'_>, impl_def_id: LocalDefId) { diff --git a/compiler/rustc_typeck/src/outlives/mod.rs b/compiler/rustc_typeck/src/outlives/mod.rs index 8fa65d51e3ba1..e50c267659e3f 100644 --- a/compiler/rustc_typeck/src/outlives/mod.rs +++ b/compiler/rustc_typeck/src/outlives/mod.rs @@ -9,7 +9,6 @@ use rustc_span::Span; mod explicit; mod implicit_infer; -pub(crate) mod outlives_bounds; /// Code to write unit test for outlives. pub mod test; mod utils; From ac0b6af37bc6d8ed6f4468a8c3feab31ebb9e15d Mon Sep 17 00:00:00 2001 From: Santiago Pastorino Date: Mon, 22 Aug 2022 15:52:49 -0300 Subject: [PATCH 2/4] 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 3bc08fba91a10..fb2440ef45774 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 221c1bc23b3f4..3acf0d8d39ab9 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 097cc4e0fe3e6..0000000000000 --- 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`. From 4cb492e7408c9c54fbc9e6ad5a13af650514c715 Mon Sep 17 00:00:00 2001 From: Santiago Pastorino Date: Mon, 22 Aug 2022 15:54:02 -0300 Subject: [PATCH 3/4] Do not use unneeded extra errors variable --- compiler/rustc_trait_selection/src/traits/coherence.rs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/compiler/rustc_trait_selection/src/traits/coherence.rs b/compiler/rustc_trait_selection/src/traits/coherence.rs index fb2440ef45774..f09be12b84d0c 100644 --- a/compiler/rustc_trait_selection/src/traits/coherence.rs +++ b/compiler/rustc_trait_selection/src/traits/coherence.rs @@ -391,8 +391,7 @@ fn resolve_negative_obligation<'cx, 'tcx>( }; let param_env = o.param_env; - let errors = super::fully_solve_obligation(&infcx, o); - if !errors.is_empty() { + if !super::fully_solve_obligation(&infcx, o).is_empty() { return false; } From 4da14ef50eb697298f36d41f91cb02dc800275bf Mon Sep 17 00:00:00 2001 From: Santiago Pastorino Date: Tue, 23 Aug 2022 09:08:30 -0300 Subject: [PATCH 4/4] Use CRATE_HIR_ID and CRATE_DEF_ID for obligations from foreign crates --- .../src/traits/coherence.rs | 24 ++++++++++--------- 1 file changed, 13 insertions(+), 11 deletions(-) diff --git a/compiler/rustc_trait_selection/src/traits/coherence.rs b/compiler/rustc_trait_selection/src/traits/coherence.rs index f09be12b84d0c..292787d4dbb24 100644 --- a/compiler/rustc_trait_selection/src/traits/coherence.rs +++ b/compiler/rustc_trait_selection/src/traits/coherence.rs @@ -16,7 +16,8 @@ use crate::traits::{ }; use rustc_data_structures::fx::FxIndexSet; use rustc_errors::Diagnostic; -use rustc_hir::def_id::{DefId, LOCAL_CRATE}; +use rustc_hir::def_id::{DefId, CRATE_DEF_ID, LOCAL_CRATE}; +use rustc_hir::CRATE_HIR_ID; use rustc_infer::infer::{InferCtxt, TyCtxtInferExt}; use rustc_infer::traits::util; use rustc_middle::traits::specialization_graph::OverlapMode; @@ -395,19 +396,20 @@ fn resolve_negative_obligation<'cx, 'tcx>( return false; } - 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), - ) + let (body_id, body_def_id) = if let Some(body_def_id) = body_def_id.as_local() { + (tcx.hir().local_def_id_to_hir_id(body_def_id), body_def_id) } else { - OutlivesEnvironment::new(param_env) + (CRATE_HIR_ID, CRATE_DEF_ID) }; + let ocx = ObligationCtxt::new(&infcx); + let wf_tys = ocx.assumed_wf_types(param_env, DUMMY_SP, body_def_id); + let outlives_env = OutlivesEnvironment::with_bounds( + param_env, + Some(&infcx), + infcx.implied_bounds_tys(param_env, body_id, wf_tys), + ); + infcx.process_registered_region_obligations(outlives_env.region_bound_pairs(), param_env); infcx.resolve_regions(&outlives_env).is_empty()