1
Fork 0

Make inductive cycles in coherence ambiguous always

This commit is contained in:
Michael Goulet 2023-12-05 17:29:36 +00:00
parent 0ee9cfd54d
commit 8abf133c4b
6 changed files with 27 additions and 155 deletions

View file

@ -10,7 +10,7 @@ use crate::solve::inspect::{InspectGoal, ProofTreeInferCtxtExt, ProofTreeVisitor
use crate::solve::{deeply_normalize_for_diagnostics, inspect};
use crate::traits::engine::TraitEngineExt;
use crate::traits::query::evaluate_obligation::InferCtxtExt;
use crate::traits::select::{IntercrateAmbiguityCause, TreatInductiveCycleAs};
use crate::traits::select::IntercrateAmbiguityCause;
use crate::traits::structural_normalize::StructurallyNormalizeExt;
use crate::traits::NormalizeExt;
use crate::traits::SkipLeakCheck;
@ -31,7 +31,6 @@ use rustc_middle::traits::DefiningAnchor;
use rustc_middle::ty::fast_reject::{DeepRejectCtxt, TreatParams};
use rustc_middle::ty::visit::{TypeVisitable, TypeVisitableExt};
use rustc_middle::ty::{self, Ty, TyCtxt, TypeSuperVisitable, TypeVisitor};
use rustc_session::lint::builtin::COINDUCTIVE_OVERLAP_IN_COHERENCE;
use rustc_span::symbol::sym;
use rustc_span::DUMMY_SP;
use std::fmt::Debug;
@ -197,7 +196,7 @@ fn overlap<'tcx>(
.intercrate(true)
.with_next_trait_solver(tcx.next_trait_solver_in_coherence())
.build();
let selcx = &mut SelectionContext::new(&infcx);
let selcx = &mut SelectionContext::with_treat_inductive_cycle_as_ambig(&infcx);
if track_ambiguity_causes.is_yes() {
selcx.enable_tracking_intercrate_ambiguity_causes();
}
@ -224,61 +223,10 @@ fn overlap<'tcx>(
);
if overlap_mode.use_implicit_negative() {
for mode in [TreatInductiveCycleAs::Ambig, TreatInductiveCycleAs::Recur] {
if let Some(failing_obligation) = selcx.with_treat_inductive_cycle_as(mode, |selcx| {
impl_intersection_has_impossible_obligation(selcx, &obligations)
}) {
if matches!(mode, TreatInductiveCycleAs::Recur) {
let first_local_impl = impl1_header
.impl_def_id
.as_local()
.or(impl2_header.impl_def_id.as_local())
.expect("expected one of the impls to be local");
infcx.tcx.struct_span_lint_hir(
COINDUCTIVE_OVERLAP_IN_COHERENCE,
infcx.tcx.local_def_id_to_hir_id(first_local_impl),
infcx.tcx.def_span(first_local_impl),
format!(
"implementations {} will conflict in the future",
match impl1_header.trait_ref {
Some(trait_ref) => {
let trait_ref = infcx.resolve_vars_if_possible(trait_ref);
format!(
"of `{}` for `{}`",
trait_ref.print_trait_sugared(),
trait_ref.self_ty()
)
}
None => format!(
"for `{}`",
infcx.resolve_vars_if_possible(impl1_header.self_ty)
),
},
),
|lint| {
lint.note(
"impls that are not considered to overlap may be considered to \
overlap in the future",
)
.span_label(
infcx.tcx.def_span(impl1_header.impl_def_id),
"the first impl is here",
)
.span_label(
infcx.tcx.def_span(impl2_header.impl_def_id),
"the second impl is here",
);
lint.note(format!(
"`{}` may be considered to hold in future releases, \
causing the impls to overlap",
infcx.resolve_vars_if_possible(failing_obligation.predicate)
));
},
);
}
return None;
}
if let Some(_failing_obligation) =
impl_intersection_has_impossible_obligation(selcx, &obligations)
{
return None;
}
}

View file

@ -239,20 +239,16 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
}
}
// Sets the `TreatInductiveCycleAs` mode temporarily in the selection context
pub fn with_treat_inductive_cycle_as<T>(
&mut self,
treat_inductive_cycle: TreatInductiveCycleAs,
f: impl FnOnce(&mut Self) -> T,
) -> T {
pub fn with_treat_inductive_cycle_as_ambig(
infcx: &'cx InferCtxt<'tcx>,
) -> SelectionContext<'cx, 'tcx> {
// Should be executed in a context where caching is disabled,
// otherwise the cache is poisoned with the temporary result.
assert!(self.is_intercrate());
let treat_inductive_cycle =
std::mem::replace(&mut self.treat_inductive_cycle, treat_inductive_cycle);
let value = f(self);
self.treat_inductive_cycle = treat_inductive_cycle;
value
assert!(infcx.intercrate);
SelectionContext {
treat_inductive_cycle: TreatInductiveCycleAs::Ambig,
..SelectionContext::new(infcx)
}
}
pub fn with_query_mode(