Skip to content

Commit 7568632

Browse files
committed
Filter candidates when goal and impl polarity doesn't match
1 parent 6ae1d68 commit 7568632

File tree

2 files changed

+27
-9
lines changed

2 files changed

+27
-9
lines changed

compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs

+4-2
Original file line numberDiff line numberDiff line change
@@ -134,6 +134,8 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
134134
// candidate which assumes $0 == int, one that assumes `$0 ==
135135
// usize`, etc. This spells an ambiguity.
136136

137+
self.filter_impls(&mut candidates, stack);
138+
137139
// If there is more than one candidate, first winnow them down
138140
// by considering extra conditions (nested obligations and so
139141
// forth). We don't winnow if there is exactly one
@@ -149,7 +151,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
149151
// Instead, we select the right impl now but report "`Bar` does
150152
// not implement `Clone`".
151153
if candidates.len() == 1 {
152-
return self.filter_impls(candidates.pop().unwrap(), stack.obligation);
154+
return self.filter_reservation_impls(candidates.pop().unwrap(), stack.obligation);
153155
}
154156

155157
// Winnow, but record the exact outcome of evaluation, which
@@ -223,7 +225,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
223225
}
224226

225227
// Just one candidate left.
226-
self.filter_impls(candidates.pop().unwrap().candidate, stack.obligation)
228+
self.filter_reservation_impls(candidates.pop().unwrap().candidate, stack.obligation)
227229
}
228230

229231
#[instrument(skip(self, stack), level = "debug")]

compiler/rustc_trait_selection/src/traits/select/mod.rs

+23-7
Original file line numberDiff line numberDiff line change
@@ -1117,8 +1117,30 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
11171117
(result, dep_node)
11181118
}
11191119

1120+
/// filter_impls filters candidates that have a positive impl for a negative goal and a
1121+
/// negative impl for a positive goal
11201122
#[instrument(level = "debug", skip(self))]
11211123
fn filter_impls(
1124+
&mut self,
1125+
candidates: &mut Vec<SelectionCandidate<'tcx>>,
1126+
stack: &TraitObligationStack<'o, 'tcx>,
1127+
) {
1128+
let tcx = self.tcx();
1129+
candidates.retain(|candidate| {
1130+
if let ImplCandidate(def_id) = candidate {
1131+
ty::ImplPolarity::Reservation == tcx.impl_polarity(*def_id)
1132+
|| !self.allow_negative_impls
1133+
&& stack.obligation.predicate.skip_binder().polarity
1134+
== tcx.impl_polarity(*def_id)
1135+
} else {
1136+
true
1137+
}
1138+
});
1139+
}
1140+
1141+
/// filter_reservation_impls filter reservation impl for any goal as ambiguous
1142+
#[instrument(level = "debug", skip(self))]
1143+
fn filter_reservation_impls(
11221144
&mut self,
11231145
candidate: SelectionCandidate<'tcx>,
11241146
obligation: &TraitObligation<'tcx>,
@@ -1148,7 +1170,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
11481170
}
11491171
}
11501172
}
1151-
// Treat negative impls as unimplemented, and reservation impls as ambiguity.
1173+
// Treat reservation impls as ambiguity.
11521174
if let ImplCandidate(def_id) = candidate {
11531175
if let ty::ImplPolarity::Reservation = tcx.impl_polarity(def_id) {
11541176
if let Some(intercrate_ambiguity_clauses) = &mut self.intercrate_ambiguity_causes {
@@ -1170,12 +1192,6 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
11701192
}
11711193
return Ok(None);
11721194
}
1173-
1174-
if !self.allow_negative_impls {
1175-
if obligation.predicate.skip_binder().polarity != tcx.impl_polarity(def_id) {
1176-
return Err(Unimplemented);
1177-
}
1178-
}
11791195
}
11801196
Ok(Some(candidate))
11811197
}

0 commit comments

Comments
 (0)