Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Coherence negative impls implied bounds #100888

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions compiler/rustc_trait_selection/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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]
Expand Down
41 changes: 30 additions & 11 deletions compiler/rustc_trait_selection/src/traits/coherence.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,16 +6,18 @@

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;
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;
Expand Down Expand Up @@ -322,7 +324,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)
})
}

Expand All @@ -332,6 +334,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, .. }) =
Expand All @@ -342,8 +345,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);
Expand All @@ -358,14 +363,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;
}
}
Expand All @@ -377,6 +383,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;

Expand All @@ -385,12 +392,24 @@ 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;
}

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.resolve_regions(&outlives_env).is_empty()
Expand Down
1 change: 1 addition & 0 deletions compiler/rustc_trait_selection/src/traits/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
Original file line number Diff line number Diff line change
@@ -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;

Expand Down
2 changes: 1 addition & 1 deletion compiler/rustc_typeck/src/check/compare_method.rs
Original file line number Diff line number Diff line change
@@ -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;
Expand All @@ -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,
};
Expand Down
2 changes: 1 addition & 1 deletion compiler/rustc_typeck/src/check/wfcheck.rs
Original file line number Diff line number Diff line change
@@ -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};
Expand All @@ -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,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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};
Expand All @@ -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) {
Expand Down
1 change: 0 additions & 1 deletion compiler/rustc_typeck/src/outlives/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
Original file line number Diff line number Diff line change
@@ -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 {}
Expand All @@ -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() {}

This file was deleted.