Rollup merge of #118649 - compiler-errors:coherence-ambig, r=lcnr
Make inductive cycles in coherence ambiguous always Logical conclusion of https://github.com/rust-lang/rust/issues/114040 One step after #116493 cc https://github.com/rust-lang/trait-system-refactor-initiative/issues/20 r? lcnr to kick off the FCP after review... maybe we should wait until 1.75 is landed? In that case, I'd still like to get the FCP boxes checked sooner since that'll be near the holidays which means everyone's away.
This commit is contained in:
commit
1974f5cba9
6 changed files with 27 additions and 155 deletions
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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(
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue