Filter candidates when goal and impl polarity doesn't match

This commit is contained in:
Santiago Pastorino 2021-10-20 10:54:48 -03:00
parent 6ae1d68e16
commit 7568632513
No known key found for this signature in database
GPG Key ID: 8131A24E0C79EFAF
2 changed files with 27 additions and 9 deletions

View File

@ -134,6 +134,8 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
// candidate which assumes $0 == int, one that assumes `$0 ==
// usize`, etc. This spells an ambiguity.
self.filter_impls(&mut candidates, stack);
// If there is more than one candidate, first winnow them down
// by considering extra conditions (nested obligations and so
// forth). We don't winnow if there is exactly one
@ -149,7 +151,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
// Instead, we select the right impl now but report "`Bar` does
// not implement `Clone`".
if candidates.len() == 1 {
return self.filter_impls(candidates.pop().unwrap(), stack.obligation);
return self.filter_reservation_impls(candidates.pop().unwrap(), stack.obligation);
}
// Winnow, but record the exact outcome of evaluation, which
@ -223,7 +225,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
}
// Just one candidate left.
self.filter_impls(candidates.pop().unwrap().candidate, stack.obligation)
self.filter_reservation_impls(candidates.pop().unwrap().candidate, stack.obligation)
}
#[instrument(skip(self, stack), level = "debug")]

View File

@ -1117,8 +1117,30 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
(result, dep_node)
}
/// filter_impls filters candidates that have a positive impl for a negative goal and a
/// negative impl for a positive goal
#[instrument(level = "debug", skip(self))]
fn filter_impls(
&mut self,
candidates: &mut Vec<SelectionCandidate<'tcx>>,
stack: &TraitObligationStack<'o, 'tcx>,
) {
let tcx = self.tcx();
candidates.retain(|candidate| {
if let ImplCandidate(def_id) = candidate {
ty::ImplPolarity::Reservation == tcx.impl_polarity(*def_id)
|| !self.allow_negative_impls
&& stack.obligation.predicate.skip_binder().polarity
== tcx.impl_polarity(*def_id)
} else {
true
}
});
}
/// filter_reservation_impls filter reservation impl for any goal as ambiguous
#[instrument(level = "debug", skip(self))]
fn filter_reservation_impls(
&mut self,
candidate: SelectionCandidate<'tcx>,
obligation: &TraitObligation<'tcx>,
@ -1148,7 +1170,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
}
}
}
// Treat negative impls as unimplemented, and reservation impls as ambiguity.
// Treat reservation impls as ambiguity.
if let ImplCandidate(def_id) = candidate {
if let ty::ImplPolarity::Reservation = tcx.impl_polarity(def_id) {
if let Some(intercrate_ambiguity_clauses) = &mut self.intercrate_ambiguity_causes {
@ -1170,12 +1192,6 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
}
return Ok(None);
}
if !self.allow_negative_impls {
if obligation.predicate.skip_binder().polarity != tcx.impl_polarity(def_id) {
return Err(Unimplemented);
}
}
}
Ok(Some(candidate))
}