diff --git a/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs b/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs index b46d35f061edc..0c1c2340c71d9 100644 --- a/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs +++ b/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs @@ -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")] diff --git a/compiler/rustc_trait_selection/src/traits/select/mod.rs b/compiler/rustc_trait_selection/src/traits/select/mod.rs index 9e77364aef36a..2748dfcca6c85 100644 --- a/compiler/rustc_trait_selection/src/traits/select/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/select/mod.rs @@ -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>, + 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)) }