Filter candidates when goal and impl polarity doesn't match
This commit is contained in:
parent
6ae1d68e16
commit
7568632513
2 changed files with 27 additions and 9 deletions
|
@ -134,6 +134,8 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
||||||
// candidate which assumes $0 == int, one that assumes `$0 ==
|
// candidate which assumes $0 == int, one that assumes `$0 ==
|
||||||
// usize`, etc. This spells an ambiguity.
|
// usize`, etc. This spells an ambiguity.
|
||||||
|
|
||||||
|
self.filter_impls(&mut candidates, stack);
|
||||||
|
|
||||||
// If there is more than one candidate, first winnow them down
|
// If there is more than one candidate, first winnow them down
|
||||||
// by considering extra conditions (nested obligations and so
|
// by considering extra conditions (nested obligations and so
|
||||||
// forth). We don't winnow if there is exactly one
|
// 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
|
// Instead, we select the right impl now but report "`Bar` does
|
||||||
// not implement `Clone`".
|
// not implement `Clone`".
|
||||||
if candidates.len() == 1 {
|
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
|
// Winnow, but record the exact outcome of evaluation, which
|
||||||
|
@ -223,7 +225,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Just one candidate left.
|
// 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")]
|
#[instrument(skip(self, stack), level = "debug")]
|
||||||
|
|
|
@ -1117,8 +1117,30 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
||||||
(result, dep_node)
|
(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))]
|
#[instrument(level = "debug", skip(self))]
|
||||||
fn filter_impls(
|
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,
|
&mut self,
|
||||||
candidate: SelectionCandidate<'tcx>,
|
candidate: SelectionCandidate<'tcx>,
|
||||||
obligation: &TraitObligation<'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 ImplCandidate(def_id) = candidate {
|
||||||
if let ty::ImplPolarity::Reservation = tcx.impl_polarity(def_id) {
|
if let ty::ImplPolarity::Reservation = tcx.impl_polarity(def_id) {
|
||||||
if let Some(intercrate_ambiguity_clauses) = &mut self.intercrate_ambiguity_causes {
|
if let Some(intercrate_ambiguity_clauses) = &mut self.intercrate_ambiguity_causes {
|
||||||
|
@ -1170,12 +1192,6 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
||||||
}
|
}
|
||||||
return Ok(None);
|
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))
|
Ok(Some(candidate))
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue