Filter non-const impls when we expect a const one

This commit is contained in:
Deadbeef 2021-07-23 00:01:47 +08:00
parent 32390a0df6
commit 4c8b6a20a9
No known key found for this signature in database
GPG Key ID: 027DF9338862ADDD
2 changed files with 23 additions and 6 deletions

View File

@ -144,7 +144,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_negative_and_reservation_impls(candidates.pop().unwrap());
return self.filter_impls(candidates.pop().unwrap(), stack.obligation);
}
// Winnow, but record the exact outcome of evaluation, which
@ -217,7 +217,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
}
// Just one candidate left.
self.filter_negative_and_reservation_impls(candidates.pop().unwrap().candidate)
self.filter_impls(candidates.pop().unwrap().candidate, stack.obligation)
}
pub(super) fn assemble_candidates<'o>(

View File

@ -1015,13 +1015,30 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
(result, dep_node)
}
// Treat negative impls as unimplemented, and reservation impls as ambiguity.
fn filter_negative_and_reservation_impls(
fn filter_impls(
&mut self,
candidate: SelectionCandidate<'tcx>,
obligation: &TraitObligation<'tcx>,
) -> SelectionResult<'tcx, SelectionCandidate<'tcx>> {
let tcx = self.tcx();
// Respect const trait obligations
if let hir::Constness::Const = obligation.predicate.skip_binder().constness {
match candidate {
// const impl
ImplCandidate(def_id) if tcx.impl_constness(def_id) == hir::Constness::Const => {}
// const param
ParamCandidate(ty::ConstnessAnd { constness: hir::Constness::Const, .. }) => {}
// auto trait impl
AutoImplCandidate(..) => {}
// FIXME check if this is right, but this would allow Sized impls
BuiltinCandidate { .. } => {}
_ => { // reject all other types of candidates
return Err(Unimplemented)
}
}
}
// Treat negative impls as unimplemented, and reservation impls as ambiguity.
if let ImplCandidate(def_id) = candidate {
let tcx = self.tcx();
match tcx.impl_polarity(def_id) {
ty::ImplPolarity::Negative if !self.allow_negative_impls => {
return Err(Unimplemented);
@ -1035,7 +1052,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
let value = attr.and_then(|a| a.value_str());
if let Some(value) = value {
debug!(
"filter_negative_and_reservation_impls: \
"filter_impls: \
reservation impl ambiguity on {:?}",
def_id
);