Rollup merge of #100888 - spastorino:coherence-negative-impls-implied-bounds, r=lcnr
Coherence negative impls implied bounds
Fixes #93875
This PR is rebased on top of #100789 and it would need to include that one which is already r+ed.
r? ``@nikomatsakis``
cc ``@lcnr`` (which I've talked about 3222f420d9
, I guess after you finish your reordering of modules and work with OutlivesEnvironmentEnv this commit can just be reverted).
This commit is contained in:
commit
0fcabec620
10 changed files with 42 additions and 33 deletions
|
@ -20,6 +20,7 @@
|
||||||
#![feature(let_else)]
|
#![feature(let_else)]
|
||||||
#![feature(if_let_guard)]
|
#![feature(if_let_guard)]
|
||||||
#![feature(never_type)]
|
#![feature(never_type)]
|
||||||
|
#![feature(type_alias_impl_trait)]
|
||||||
#![recursion_limit = "512"] // For rustdoc
|
#![recursion_limit = "512"] // For rustdoc
|
||||||
|
|
||||||
#[macro_use]
|
#[macro_use]
|
||||||
|
|
|
@ -6,16 +6,18 @@
|
||||||
|
|
||||||
use crate::infer::outlives::env::OutlivesEnvironment;
|
use crate::infer::outlives::env::OutlivesEnvironment;
|
||||||
use crate::infer::{CombinedSnapshot, InferOk};
|
use crate::infer::{CombinedSnapshot, InferOk};
|
||||||
|
use crate::traits::outlives_bounds::InferCtxtExt as _;
|
||||||
use crate::traits::select::IntercrateAmbiguityCause;
|
use crate::traits::select::IntercrateAmbiguityCause;
|
||||||
use crate::traits::util::impl_subject_and_oblig;
|
use crate::traits::util::impl_subject_and_oblig;
|
||||||
use crate::traits::SkipLeakCheck;
|
use crate::traits::SkipLeakCheck;
|
||||||
use crate::traits::{
|
use crate::traits::{
|
||||||
self, Normalized, Obligation, ObligationCause, PredicateObligation, PredicateObligations,
|
self, Normalized, Obligation, ObligationCause, ObligationCtxt, PredicateObligation,
|
||||||
SelectionContext,
|
PredicateObligations, SelectionContext,
|
||||||
};
|
};
|
||||||
use rustc_data_structures::fx::FxIndexSet;
|
use rustc_data_structures::fx::FxIndexSet;
|
||||||
use rustc_errors::Diagnostic;
|
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::infer::{InferCtxt, TyCtxtInferExt};
|
||||||
use rustc_infer::traits::util;
|
use rustc_infer::traits::util;
|
||||||
use rustc_middle::traits::specialization_graph::OverlapMode;
|
use rustc_middle::traits::specialization_graph::OverlapMode;
|
||||||
|
@ -322,7 +324,7 @@ fn negative_impl<'cx, 'tcx>(
|
||||||
let (subject2, obligations) =
|
let (subject2, obligations) =
|
||||||
impl_subject_and_oblig(selcx, impl_env, impl2_def_id, impl2_substs);
|
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 +334,7 @@ fn equate<'cx, 'tcx>(
|
||||||
subject1: ImplSubject<'tcx>,
|
subject1: ImplSubject<'tcx>,
|
||||||
subject2: ImplSubject<'tcx>,
|
subject2: ImplSubject<'tcx>,
|
||||||
obligations: impl Iterator<Item = PredicateObligation<'tcx>>,
|
obligations: impl Iterator<Item = PredicateObligation<'tcx>>,
|
||||||
|
body_def_id: DefId,
|
||||||
) -> bool {
|
) -> bool {
|
||||||
// do the impls unify? If not, not disjoint.
|
// do the impls unify? If not, not disjoint.
|
||||||
let Ok(InferOk { obligations: more_obligations, .. }) =
|
let Ok(InferOk { obligations: more_obligations, .. }) =
|
||||||
|
@ -342,8 +345,10 @@ fn equate<'cx, 'tcx>(
|
||||||
};
|
};
|
||||||
|
|
||||||
let selcx = &mut SelectionContext::new(&infcx);
|
let selcx = &mut SelectionContext::new(&infcx);
|
||||||
let opt_failing_obligation =
|
let opt_failing_obligation = obligations
|
||||||
obligations.into_iter().chain(more_obligations).find(|o| negative_impl_exists(selcx, o));
|
.into_iter()
|
||||||
|
.chain(more_obligations)
|
||||||
|
.find(|o| negative_impl_exists(selcx, o, body_def_id));
|
||||||
|
|
||||||
if let Some(failing_obligation) = opt_failing_obligation {
|
if let Some(failing_obligation) = opt_failing_obligation {
|
||||||
debug!("overlap: obligation unsatisfiable {:?}", failing_obligation);
|
debug!("overlap: obligation unsatisfiable {:?}", failing_obligation);
|
||||||
|
@ -358,14 +363,15 @@ fn equate<'cx, 'tcx>(
|
||||||
fn negative_impl_exists<'cx, 'tcx>(
|
fn negative_impl_exists<'cx, 'tcx>(
|
||||||
selcx: &SelectionContext<'cx, 'tcx>,
|
selcx: &SelectionContext<'cx, 'tcx>,
|
||||||
o: &PredicateObligation<'tcx>,
|
o: &PredicateObligation<'tcx>,
|
||||||
|
body_def_id: DefId,
|
||||||
) -> bool {
|
) -> bool {
|
||||||
if resolve_negative_obligation(selcx.infcx().fork(), o) {
|
if resolve_negative_obligation(selcx.infcx().fork(), o, body_def_id) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Try to prove a negative obligation exists for super predicates
|
// Try to prove a negative obligation exists for super predicates
|
||||||
for o in util::elaborate_predicates(selcx.tcx(), iter::once(o.predicate)) {
|
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;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -377,6 +383,7 @@ fn negative_impl_exists<'cx, 'tcx>(
|
||||||
fn resolve_negative_obligation<'cx, 'tcx>(
|
fn resolve_negative_obligation<'cx, 'tcx>(
|
||||||
infcx: InferCtxt<'cx, 'tcx>,
|
infcx: InferCtxt<'cx, 'tcx>,
|
||||||
o: &PredicateObligation<'tcx>,
|
o: &PredicateObligation<'tcx>,
|
||||||
|
body_def_id: DefId,
|
||||||
) -> bool {
|
) -> bool {
|
||||||
let tcx = infcx.tcx;
|
let tcx = infcx.tcx;
|
||||||
|
|
||||||
|
@ -385,12 +392,24 @@ fn resolve_negative_obligation<'cx, 'tcx>(
|
||||||
};
|
};
|
||||||
|
|
||||||
let param_env = o.param_env;
|
let param_env = o.param_env;
|
||||||
let errors = super::fully_solve_obligation(&infcx, o);
|
if !super::fully_solve_obligation(&infcx, o).is_empty() {
|
||||||
if !errors.is_empty() {
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
let outlives_env = OutlivesEnvironment::new(param_env);
|
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 {
|
||||||
|
(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.process_registered_region_obligations(outlives_env.region_bound_pairs(), param_env);
|
||||||
|
|
||||||
infcx.resolve_regions(&outlives_env).is_empty()
|
infcx.resolve_regions(&outlives_env).is_empty()
|
||||||
|
|
|
@ -13,6 +13,7 @@ mod fulfill;
|
||||||
pub mod misc;
|
pub mod misc;
|
||||||
mod object_safety;
|
mod object_safety;
|
||||||
mod on_unimplemented;
|
mod on_unimplemented;
|
||||||
|
pub mod outlives_bounds;
|
||||||
mod project;
|
mod project;
|
||||||
pub mod query;
|
pub mod query;
|
||||||
pub(crate) mod relationships;
|
pub(crate) mod relationships;
|
||||||
|
|
|
@ -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_data_structures::fx::FxHashSet;
|
||||||
use rustc_hir as hir;
|
use rustc_hir as hir;
|
||||||
use rustc_hir::HirId;
|
use rustc_hir::HirId;
|
||||||
use rustc_middle::ty::{self, ParamEnv, Ty};
|
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;
|
pub use rustc_middle::traits::query::OutlivesBound;
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
use super::potentially_plural_count;
|
use super::potentially_plural_count;
|
||||||
use crate::errors::LifetimesOrBoundsMismatchOnTrait;
|
use crate::errors::LifetimesOrBoundsMismatchOnTrait;
|
||||||
use crate::outlives::outlives_bounds::InferCtxtExt as _;
|
|
||||||
use rustc_data_structures::fx::FxHashSet;
|
use rustc_data_structures::fx::FxHashSet;
|
||||||
use rustc_errors::{pluralize, struct_span_err, Applicability, DiagnosticId, ErrorGuaranteed};
|
use rustc_errors::{pluralize, struct_span_err, Applicability, DiagnosticId, ErrorGuaranteed};
|
||||||
use rustc_hir as hir;
|
use rustc_hir as hir;
|
||||||
|
@ -17,6 +16,7 @@ use rustc_middle::ty::{self, DefIdTree};
|
||||||
use rustc_middle::ty::{GenericParamDefKind, ToPredicate, TyCtxt};
|
use rustc_middle::ty::{GenericParamDefKind, ToPredicate, TyCtxt};
|
||||||
use rustc_span::Span;
|
use rustc_span::Span;
|
||||||
use rustc_trait_selection::traits::error_reporting::InferCtxtExt;
|
use rustc_trait_selection::traits::error_reporting::InferCtxtExt;
|
||||||
|
use rustc_trait_selection::traits::outlives_bounds::InferCtxtExt as _;
|
||||||
use rustc_trait_selection::traits::{
|
use rustc_trait_selection::traits::{
|
||||||
self, ObligationCause, ObligationCauseCode, ObligationCtxt, Reveal,
|
self, ObligationCause, ObligationCauseCode, ObligationCtxt, Reveal,
|
||||||
};
|
};
|
||||||
|
|
|
@ -1,5 +1,4 @@
|
||||||
use crate::constrained_generic_params::{identify_constrained_generic_params, Parameter};
|
use crate::constrained_generic_params::{identify_constrained_generic_params, Parameter};
|
||||||
use crate::outlives::outlives_bounds::InferCtxtExt as _;
|
|
||||||
use rustc_ast as ast;
|
use rustc_ast as ast;
|
||||||
use rustc_data_structures::fx::{FxHashMap, FxHashSet};
|
use rustc_data_structures::fx::{FxHashMap, FxHashSet};
|
||||||
use rustc_errors::{pluralize, struct_span_err, Applicability, DiagnosticBuilder, ErrorGuaranteed};
|
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_span::{Span, DUMMY_SP};
|
||||||
use rustc_trait_selection::autoderef::Autoderef;
|
use rustc_trait_selection::autoderef::Autoderef;
|
||||||
use rustc_trait_selection::traits::error_reporting::InferCtxtExt;
|
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::query::evaluate_obligation::InferCtxtExt as _;
|
||||||
use rustc_trait_selection::traits::{
|
use rustc_trait_selection::traits::{
|
||||||
self, ObligationCause, ObligationCauseCode, ObligationCtxt, WellFormedLoc,
|
self, ObligationCause, ObligationCauseCode, ObligationCtxt, WellFormedLoc,
|
||||||
|
|
|
@ -67,7 +67,6 @@
|
||||||
|
|
||||||
use crate::constrained_generic_params as cgp;
|
use crate::constrained_generic_params as cgp;
|
||||||
use crate::errors::SubstsOnOverriddenImpl;
|
use crate::errors::SubstsOnOverriddenImpl;
|
||||||
use crate::outlives::outlives_bounds::InferCtxtExt as _;
|
|
||||||
|
|
||||||
use rustc_data_structures::fx::FxHashSet;
|
use rustc_data_structures::fx::FxHashSet;
|
||||||
use rustc_hir::def_id::{DefId, LocalDefId};
|
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_middle::ty::{self, TyCtxt, TypeVisitable};
|
||||||
use rustc_span::Span;
|
use rustc_span::Span;
|
||||||
use rustc_trait_selection::traits::error_reporting::InferCtxtExt;
|
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};
|
use rustc_trait_selection::traits::{self, translate_substs, wf, ObligationCtxt};
|
||||||
|
|
||||||
pub(super) fn check_min_specialization(tcx: TyCtxt<'_>, impl_def_id: LocalDefId) {
|
pub(super) fn check_min_specialization(tcx: TyCtxt<'_>, impl_def_id: LocalDefId) {
|
||||||
|
|
|
@ -9,7 +9,6 @@ use rustc_span::Span;
|
||||||
|
|
||||||
mod explicit;
|
mod explicit;
|
||||||
mod implicit_infer;
|
mod implicit_infer;
|
||||||
pub(crate) mod outlives_bounds;
|
|
||||||
/// Code to write unit test for outlives.
|
/// Code to write unit test for outlives.
|
||||||
pub mod test;
|
pub mod test;
|
||||||
mod utils;
|
mod utils;
|
||||||
|
|
|
@ -1,9 +1,9 @@
|
||||||
// revisions: stock with_negative_coherence
|
// revisions: stock with_negative_coherence
|
||||||
|
//[with_negative_coherence] check-pass
|
||||||
|
|
||||||
#![feature(negative_impls)]
|
#![feature(negative_impls)]
|
||||||
#![cfg_attr(with_negative_coherence, feature(with_negative_coherence))]
|
#![cfg_attr(with_negative_coherence, feature(with_negative_coherence))]
|
||||||
|
|
||||||
// FIXME: this should compile
|
|
||||||
|
|
||||||
trait MyPredicate<'a> {}
|
trait MyPredicate<'a> {}
|
||||||
|
|
||||||
impl<'a, T> !MyPredicate<'a> for &'a T where T: '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: MyPredicate<'a>> MyTrait<'a> for T {}
|
||||||
impl<'a, T> MyTrait<'a> for &'a 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() {}
|
fn main() {}
|
||||||
|
|
|
@ -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`.
|
|
Loading…
Add table
Add a link
Reference in a new issue