Skip to content

Commit

Permalink
Filter candidates when goal and impl polarity doesn't match
Browse files Browse the repository at this point in the history
  • Loading branch information
spastorino committed Oct 20, 2021
1 parent 6ae1d68 commit 7568632
Show file tree
Hide file tree
Showing 2 changed files with 27 additions and 9 deletions.
Expand Up @@ -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
Expand All @@ -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
Expand Down Expand Up @@ -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")]
Expand Down
30 changes: 23 additions & 7 deletions compiler/rustc_trait_selection/src/traits/select/mod.rs
Expand Up @@ -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>,
Expand Down Expand Up @@ -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 {
Expand All @@ -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))
}
Expand Down

0 comments on commit 7568632

Please sign in to comment.