summaryrefslogtreecommitdiffstats
path: root/compiler/rustc_trait_selection/src/traits/coherence.rs
diff options
context:
space:
mode:
Diffstat (limited to 'compiler/rustc_trait_selection/src/traits/coherence.rs')
-rw-r--r--compiler/rustc_trait_selection/src/traits/coherence.rs86
1 files changed, 55 insertions, 31 deletions
diff --git a/compiler/rustc_trait_selection/src/traits/coherence.rs b/compiler/rustc_trait_selection/src/traits/coherence.rs
index 6b688c322..20c2605f2 100644
--- a/compiler/rustc_trait_selection/src/traits/coherence.rs
+++ b/compiler/rustc_trait_selection/src/traits/coherence.rs
@@ -17,7 +17,7 @@ use crate::traits::{
use rustc_data_structures::fx::FxIndexSet;
use rustc_errors::Diagnostic;
use rustc_hir::def_id::{DefId, CRATE_DEF_ID, LOCAL_CRATE};
-use rustc_infer::infer::{DefiningAnchor, InferCtxt, TyCtxtInferExt};
+use rustc_infer::infer::{DefineOpaqueTypes, DefiningAnchor, InferCtxt, TyCtxtInferExt};
use rustc_infer::traits::util;
use rustc_middle::traits::specialization_graph::OverlapMode;
use rustc_middle::ty::fast_reject::{DeepRejectCtxt, TreatParams};
@@ -75,12 +75,13 @@ pub fn overlapping_impls(
// Before doing expensive operations like entering an inference context, do
// a quick check via fast_reject to tell if the impl headers could possibly
// unify.
- let drcx = DeepRejectCtxt { treat_obligation_params: TreatParams::AsInfer };
+ let drcx = DeepRejectCtxt { treat_obligation_params: TreatParams::AsCandidateKey };
let impl1_ref = tcx.impl_trait_ref(impl1_def_id);
let impl2_ref = tcx.impl_trait_ref(impl2_def_id);
let may_overlap = match (impl1_ref, impl2_ref) {
- (Some(a), Some(b)) => iter::zip(a.skip_binder().substs, b.skip_binder().substs)
- .all(|(arg1, arg2)| drcx.generic_args_may_unify(arg1, arg2)),
+ (Some(a), Some(b)) => {
+ drcx.substs_refs_may_unify(a.skip_binder().substs, b.skip_binder().substs)
+ }
(None, None) => {
let self_ty1 = tcx.type_of(impl1_def_id).skip_binder();
let self_ty2 = tcx.type_of(impl2_def_id).skip_binder();
@@ -95,8 +96,11 @@ pub fn overlapping_impls(
return None;
}
- let infcx =
- tcx.infer_ctxt().with_opaque_type_inference(DefiningAnchor::Bubble).intercrate().build();
+ let infcx = tcx
+ .infer_ctxt()
+ .with_opaque_type_inference(DefiningAnchor::Bubble)
+ .intercrate(true)
+ .build();
let selcx = &mut SelectionContext::new(&infcx);
let overlaps =
overlap(selcx, skip_leak_check, impl1_def_id, impl2_def_id, overlap_mode).is_some();
@@ -107,8 +111,11 @@ pub fn overlapping_impls(
// In the case where we detect an error, run the check again, but
// this time tracking intercrate ambiguity causes for better
// diagnostics. (These take time and can lead to false errors.)
- let infcx =
- tcx.infer_ctxt().with_opaque_type_inference(DefiningAnchor::Bubble).intercrate().build();
+ let infcx = tcx
+ .infer_ctxt()
+ .with_opaque_type_inference(DefiningAnchor::Bubble)
+ .intercrate(true)
+ .build();
let selcx = &mut SelectionContext::new(&infcx);
selcx.enable_tracking_intercrate_ambiguity_causes();
Some(overlap(selcx, skip_leak_check, impl1_def_id, impl2_def_id, overlap_mode).unwrap())
@@ -181,7 +188,7 @@ fn overlap_within_probe<'cx, 'tcx>(
let impl1_header = with_fresh_ty_vars(selcx, param_env, impl1_def_id);
let impl2_header = with_fresh_ty_vars(selcx, param_env, impl2_def_id);
- let obligations = equate_impl_headers(selcx, &impl1_header, &impl2_header)?;
+ let obligations = equate_impl_headers(selcx.infcx, &impl1_header, &impl2_header)?;
debug!("overlap: unification check succeeded");
if overlap_mode.use_implicit_negative() {
@@ -207,20 +214,25 @@ fn overlap_within_probe<'cx, 'tcx>(
Some(OverlapResult { impl_header, intercrate_ambiguity_causes, involves_placeholder })
}
-fn equate_impl_headers<'cx, 'tcx>(
- selcx: &mut SelectionContext<'cx, 'tcx>,
- impl1_header: &ty::ImplHeader<'tcx>,
- impl2_header: &ty::ImplHeader<'tcx>,
+#[instrument(level = "debug", skip(infcx), ret)]
+fn equate_impl_headers<'tcx>(
+ infcx: &InferCtxt<'tcx>,
+ impl1: &ty::ImplHeader<'tcx>,
+ impl2: &ty::ImplHeader<'tcx>,
) -> Option<PredicateObligations<'tcx>> {
- // Do `a` and `b` unify? If not, no overlap.
- debug!("equate_impl_headers(impl1_header={:?}, impl2_header={:?}", impl1_header, impl2_header);
- selcx
- .infcx
- .at(&ObligationCause::dummy(), ty::ParamEnv::empty())
- .define_opaque_types(true)
- .eq_impl_headers(impl1_header, impl2_header)
- .map(|infer_ok| infer_ok.obligations)
- .ok()
+ let result = match (impl1.trait_ref, impl2.trait_ref) {
+ (Some(impl1_ref), Some(impl2_ref)) => infcx
+ .at(&ObligationCause::dummy(), ty::ParamEnv::empty())
+ .eq(DefineOpaqueTypes::Yes, impl1_ref, impl2_ref),
+ (None, None) => infcx.at(&ObligationCause::dummy(), ty::ParamEnv::empty()).eq(
+ DefineOpaqueTypes::Yes,
+ impl1.self_ty,
+ impl2.self_ty,
+ ),
+ _ => bug!("mk_eq_impl_headers given mismatched impl kinds"),
+ };
+
+ result.map(|infer_ok| infer_ok.obligations).ok()
}
/// Given impl1 and impl2 check if both impls can be satisfied by a common type (including
@@ -294,7 +306,7 @@ fn negative_impl(tcx: TyCtxt<'_>, impl1_def_id: DefId, impl2_def_id: DefId) -> b
&infcx,
ObligationCause::dummy(),
impl_env,
- tcx.impl_subject(impl1_def_id),
+ tcx.impl_subject(impl1_def_id).subst_identity(),
) {
Ok(s) => s,
Err(err) => {
@@ -325,7 +337,7 @@ fn equate<'tcx>(
) -> bool {
// do the impls unify? If not, not disjoint.
let Ok(InferOk { obligations: more_obligations, .. }) =
- infcx.at(&ObligationCause::dummy(), impl_env).eq(subject1, subject2)
+ infcx.at(&ObligationCause::dummy(), impl_env).eq(DefineOpaqueTypes::No,subject1, subject2)
else {
debug!("explicit_disjoint: {:?} does not unify with {:?}", subject1, subject2);
return true;
@@ -356,8 +368,8 @@ fn negative_impl_exists<'tcx>(
}
// Try to prove a negative obligation exists for super predicates
- for o in util::elaborate_predicates(infcx.tcx, iter::once(o.predicate)) {
- if resolve_negative_obligation(infcx.fork(), &o, body_def_id) {
+ for pred in util::elaborate(infcx.tcx, iter::once(o.predicate)) {
+ if resolve_negative_obligation(infcx.fork(), &o.with(infcx.tcx, pred), body_def_id) {
return true;
}
}
@@ -378,7 +390,10 @@ fn resolve_negative_obligation<'tcx>(
};
let param_env = o.param_env;
- if !super::fully_solve_obligation(&infcx, o).is_empty() {
+ let ocx = ObligationCtxt::new(&infcx);
+ ocx.register_obligation(o);
+ let errors = ocx.select_all_or_error();
+ if !errors.is_empty() {
return false;
}
@@ -388,20 +403,29 @@ fn resolve_negative_obligation<'tcx>(
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_def_id, wf_tys),
);
-
- infcx.process_registered_region_obligations(outlives_env.region_bound_pairs(), param_env);
-
infcx.resolve_regions(&outlives_env).is_empty()
}
+/// Returns whether all impls which would apply to the `trait_ref`
+/// e.g. `Ty: Trait<Arg>` are already known in the local crate.
+///
+/// This both checks whether any downstream or sibling crates could
+/// implement it and whether an upstream crate can add this impl
+/// without breaking backwards compatibility.
#[instrument(level = "debug", skip(tcx), ret)]
pub fn trait_ref_is_knowable<'tcx>(
tcx: TyCtxt<'tcx>,
trait_ref: ty::TraitRef<'tcx>,
) -> Result<(), Conflict> {
+ if Some(trait_ref.def_id) == tcx.lang_items().fn_ptr_trait() {
+ // The only types implementing `FnPtr` are function pointers,
+ // so if there's no impl of `FnPtr` in the current crate,
+ // then such an impl will never be added in the future.
+ return Ok(());
+ }
+
if orphan_check_trait_ref(trait_ref, InCrate::Remote).is_ok() {
// A downstream or cousin crate is allowed to implement some
// substitution of this trait-ref.