Only register candidate if it is associated w a shallow certainty

This commit is contained in:
Michael Goulet 2024-04-28 15:35:35 -04:00
parent 7cf1c547c2
commit 2eb7c8196b
4 changed files with 32 additions and 42 deletions

View File

@ -150,6 +150,6 @@ pub enum ProbeKind<'tcx> {
/// do a probe to find out what projection type(s) may be used to prove that
/// the source type upholds all of the target type's object bounds.
UpcastProjectionCompatibility,
/// Try to unify an opaque type with an existing
OpaqueTypeStorageLookup,
/// Try to unify an opaque type with an existing key in the storage.
OpaqueTypeStorageLookup { result: QueryResult<'tcx> },
}

View File

@ -112,8 +112,8 @@ impl<'a, 'b> ProofTreeFormatter<'a, 'b> {
ProbeKind::UpcastProjectionCompatibility => {
write!(self.f, "PROBING FOR PROJECTION COMPATIBILITY FOR UPCASTING:")
}
ProbeKind::OpaqueTypeStorageLookup => {
write!(self.f, "PROBING FOR AN EXISTING OPAQUE:")
ProbeKind::OpaqueTypeStorageLookup { result } => {
write!(self.f, "PROBING FOR AN EXISTING OPAQUE: {result:?}")
}
ProbeKind::TraitCandidate { source, result } => {
write!(self.f, "CANDIDATE {source:?}: {result:?}")

View File

@ -998,8 +998,11 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
if candidate_key.def_id != key.def_id {
continue;
}
values.extend(self.probe(|_| inspect::ProbeKind::OpaqueTypeStorageLookup).enter(
|ecx| {
values.extend(
self.probe(|result| inspect::ProbeKind::OpaqueTypeStorageLookup {
result: *result,
})
.enter(|ecx| {
for (a, b) in std::iter::zip(candidate_key.args, key.args) {
ecx.eq(param_env, a, b)?;
}
@ -1011,8 +1014,8 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
candidate_ty,
);
ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
},
));
}),
);
}
values
}

View File

@ -45,7 +45,7 @@ pub struct InspectCandidate<'a, 'tcx> {
nested_goals: Vec<inspect::CanonicalState<'tcx, Goal<'tcx, ty::Predicate<'tcx>>>>,
final_state: inspect::CanonicalState<'tcx, ()>,
result: QueryResult<'tcx>,
candidate_certainty: Option<Certainty>,
shallow_certainty: Certainty,
}
impl<'a, 'tcx> InspectCandidate<'a, 'tcx> {
@ -59,15 +59,14 @@ impl<'a, 'tcx> InspectCandidate<'a, 'tcx> {
/// Certainty passed into `evaluate_added_goals_and_make_canonical_response`.
///
/// If this certainty is `Some(Yes)`, then we must be confident that the candidate
/// If this certainty is `Yes`, then we must be confident that the candidate
/// must hold iff it's nested goals hold. This is not true if the certainty is
/// `Some(Maybe)`, which suggests we forced ambiguity instead, or if it is `None`,
/// which suggests we may have not assembled any candidates at all.
/// `Maybe(..)`, which suggests we forced ambiguity instead.
///
/// This is *not* the certainty of the candidate's nested evaluation, which can be
/// accessed with [`Self::result`] instead.
pub fn candidate_certainty(&self) -> Option<Certainty> {
self.candidate_certainty
/// This is *not* the certainty of the candidate's full nested evaluation, which
/// can be accessed with [`Self::result`] instead.
pub fn shallow_certainty(&self) -> Certainty {
self.shallow_certainty
}
/// Visit all nested goals of this candidate without rolling
@ -174,9 +173,7 @@ impl<'a, 'tcx> InspectGoal<'a, 'tcx> {
nested_goals: &mut Vec<inspect::CanonicalState<'tcx, Goal<'tcx, ty::Predicate<'tcx>>>>,
probe: &inspect::Probe<'tcx>,
) {
let mut candidate_certainty = None;
let num_candidates = candidates.len();
let mut shallow_certainty = None;
for step in &probe.steps {
match step {
&inspect::ProbeStep::AddGoal(_source, goal) => nested_goals.push(goal),
@ -188,8 +185,8 @@ impl<'a, 'tcx> InspectGoal<'a, 'tcx> {
self.candidates_recur(candidates, nested_goals, probe);
nested_goals.truncate(num_goals);
}
inspect::ProbeStep::MakeCanonicalResponse { shallow_certainty } => {
assert_eq!(candidate_certainty.replace(*shallow_certainty), None);
inspect::ProbeStep::MakeCanonicalResponse { shallow_certainty: c } => {
assert_eq!(shallow_certainty.replace(*c), None);
}
inspect::ProbeStep::EvaluateGoals(_) => (),
}
@ -198,37 +195,27 @@ impl<'a, 'tcx> InspectGoal<'a, 'tcx> {
match probe.kind {
inspect::ProbeKind::NormalizedSelfTyAssembly
| inspect::ProbeKind::UnsizeAssembly
| inspect::ProbeKind::UpcastProjectionCompatibility
| inspect::ProbeKind::OpaqueTypeStorageLookup => (),
// We add a candidate for the root evaluation if there
| inspect::ProbeKind::UpcastProjectionCompatibility => (),
// We add a candidate even for the root evaluation if there
// is only one way to prove a given goal, e.g. for `WellFormed`.
//
// FIXME: This is currently wrong if we don't even try any
// candidates, e.g. for a trait goal, as in this case `candidates` is
// actually supposed to be empty.
inspect::ProbeKind::Root { result }
| inspect::ProbeKind::TryNormalizeNonRigid { result } => {
if candidates.len() == num_candidates {
| inspect::ProbeKind::TryNormalizeNonRigid { result }
| inspect::ProbeKind::TraitCandidate { source: _, result }
| inspect::ProbeKind::OpaqueTypeStorageLookup { result } => {
// We only add a candidate if `shallow_certainty` was set, which means
// that we ended up calling `evaluate_added_goals_and_make_canonical_response`.
if let Some(shallow_certainty) = shallow_certainty {
candidates.push(InspectCandidate {
goal: self,
kind: probe.kind,
nested_goals: nested_goals.clone(),
final_state: probe.final_state,
result,
candidate_certainty,
})
shallow_certainty,
});
}
}
inspect::ProbeKind::TraitCandidate { source: _, result } => {
candidates.push(InspectCandidate {
goal: self,
kind: probe.kind,
nested_goals: nested_goals.clone(),
final_state: probe.final_state,
result,
candidate_certainty,
});
}
}
}