This commit is contained in:
lcnr 2023-09-21 08:56:23 +02:00
parent 8167a25e4e
commit 614760f612

View File

@ -214,76 +214,69 @@ fn overlap<'tcx>(
let mut obligations = equate_impl_headers(selcx.infcx, &impl1_header, &impl2_header)?; let mut obligations = equate_impl_headers(selcx.infcx, &impl1_header, &impl2_header)?;
debug!("overlap: unification check succeeded"); debug!("overlap: unification check succeeded");
if !overlap_mode.use_implicit_negative() {
let impl_header = selcx.infcx.resolve_vars_if_possible(impl1_header);
return Some(OverlapResult {
impl_header,
intercrate_ambiguity_causes: Default::default(),
involves_placeholder: false,
});
};
obligations.extend( obligations.extend(
[&impl1_header.predicates, &impl2_header.predicates].into_iter().flatten().map( [&impl1_header.predicates, &impl2_header.predicates].into_iter().flatten().map(
|&predicate| Obligation::new(infcx.tcx, ObligationCause::dummy(), param_env, predicate), |&predicate| Obligation::new(infcx.tcx, ObligationCause::dummy(), param_env, predicate),
), ),
); );
for mode in [TreatInductiveCycleAs::Ambig, TreatInductiveCycleAs::Recur] { if overlap_mode.use_implicit_negative() {
if let Some(failing_obligation) = selcx.with_treat_inductive_cycle_as(mode, |selcx| { for mode in [TreatInductiveCycleAs::Ambig, TreatInductiveCycleAs::Recur] {
impl_intersection_has_impossible_obligation(selcx, &obligations) 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 if matches!(mode, TreatInductiveCycleAs::Recur) {
.impl_def_id let first_local_impl = impl1_header
.as_local() .impl_def_id
.or(impl2_header.impl_def_id.as_local()) .as_local()
.expect("expected one of the impls to be local"); .or(impl2_header.impl_def_id.as_local())
infcx.tcx.struct_span_lint_hir( .expect("expected one of the impls to be local");
COINDUCTIVE_OVERLAP_IN_COHERENCE, infcx.tcx.struct_span_lint_hir(
infcx.tcx.local_def_id_to_hir_id(first_local_impl), COINDUCTIVE_OVERLAP_IN_COHERENCE,
infcx.tcx.def_span(first_local_impl), infcx.tcx.local_def_id_to_hir_id(first_local_impl),
format!( infcx.tcx.def_span(first_local_impl),
"implementations {} will conflict in the future", format!(
match impl1_header.trait_ref { "implementations {} will conflict in the future",
Some(trait_ref) => { match impl1_header.trait_ref {
let trait_ref = infcx.resolve_vars_if_possible(trait_ref); Some(trait_ref) => {
format!( let trait_ref = infcx.resolve_vars_if_possible(trait_ref);
"of `{}` for `{}`", format!(
trait_ref.print_only_trait_path(), "of `{}` for `{}`",
trait_ref.self_ty() trait_ref.print_only_trait_path(),
) trait_ref.self_ty()
} )
None => format!( }
"for `{}`", None => format!(
infcx.resolve_vars_if_possible(impl1_header.self_ty) "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)
));
lint
}, },
), );
|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)
));
lint
},
);
}
return None; return None;
}
} }
} }
@ -294,7 +287,9 @@ fn overlap<'tcx>(
return None; return None;
} }
let intercrate_ambiguity_causes = if infcx.next_trait_solver() { let intercrate_ambiguity_causes = if !overlap_mode.use_implicit_negative() {
Default::default()
} else if infcx.next_trait_solver() {
compute_intercrate_ambiguity_causes(&infcx, &obligations) compute_intercrate_ambiguity_causes(&infcx, &obligations)
} else { } else {
selcx.take_intercrate_ambiguity_causes() selcx.take_intercrate_ambiguity_causes()
@ -932,6 +927,8 @@ fn visit_goal(&mut self, goal: &InspectGoal<'_, 'tcx>) -> ControlFlow<Self::Brea
let Goal { param_env, predicate } = goal.goal(); let Goal { param_env, predicate } = goal.goal();
// For bound predicates we simply call `infcx.replace_bound_vars_with_placeholders`
// and then prove the resulting predicate as a nested goal.
let trait_ref = match predicate.kind().no_bound_vars() { let trait_ref = match predicate.kind().no_bound_vars() {
Some(ty::PredicateKind::Clause(ty::ClauseKind::Trait(tr))) => tr.trait_ref, Some(ty::PredicateKind::Clause(ty::ClauseKind::Trait(tr))) => tr.trait_ref,
Some(ty::PredicateKind::Clause(ty::ClauseKind::Projection(proj))) => { Some(ty::PredicateKind::Clause(ty::ClauseKind::Projection(proj))) => {
@ -942,21 +939,6 @@ fn visit_goal(&mut self, goal: &InspectGoal<'_, 'tcx>) -> ControlFlow<Self::Brea
let mut ambiguity_cause = None; let mut ambiguity_cause = None;
for cand in goal.candidates() { for cand in goal.candidates() {
match cand.result() {
Ok(Certainty::Maybe(_)) => {}
// We only add intercrate ambiguity causes if the goal would
// otherwise result in an error.
//
// FIXME: this isn't quite right. Changing a goal from YES with
// inference contraints to AMBIGUOUS can also cause a goal to not
// fail.
Ok(Certainty::Yes) => {
ambiguity_cause = None;
break;
}
Err(NoSolution) => continue,
}
// FIXME: boiiii, using string comparisions here sure is scuffed. // FIXME: boiiii, using string comparisions here sure is scuffed.
if let inspect::ProbeKind::MiscCandidate { name: "coherence unknowable", result: _ } = if let inspect::ProbeKind::MiscCandidate { name: "coherence unknowable", result: _ } =
cand.kind() cand.kind()
@ -1011,6 +993,21 @@ fn visit_goal(&mut self, goal: &InspectGoal<'_, 'tcx>) -> ControlFlow<Self::Brea
} }
} }
}) })
} else {
match cand.result() {
// We only add an ambiguity cause if the goal would otherwise
// result in an error.
//
// FIXME: While this matches the behavior of the
// old solver, it is not the only way in which the unknowable
// candidates *weaken* coherence, they can also force otherwise
// sucessful normalization to be ambiguous.
Ok(Certainty::Maybe(_) | Certainty::Yes) => {
ambiguity_cause = None;
break;
}
Err(NoSolution) => continue,
}
} }
} }