mirror of
https://github.com/rust-lang/rust.git
synced 2025-02-08 04:56:58 +00:00
Filter candidates when goal and impl polarity doesn't match
This commit is contained in:
parent
6ae1d68e16
commit
7568632513
@ -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")]
|
||||
|
@ -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))
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user