use super::Selection;
use super::SelectionResult;
use super::TraitQueryMode;
-use super::{ErrorReporting, Overflow, SelectionError, Unimplemented};
+use super::{ErrorReporting, Overflow, SelectionError};
use super::{ObligationCause, PredicateObligation, TraitObligation};
use crate::infer::{InferCtxt, InferOk, TypeFreshener};
&mut self,
obligation: &TraitObligation<'tcx>,
) -> SelectionResult<'tcx, Selection<'tcx>> {
- debug_assert!(!obligation.predicate.has_escaping_bound_vars());
-
- let pec = &ProvisionalEvaluationCache::default();
- let stack = self.push_stack(TraitObligationStackList::empty(pec), obligation);
-
- let candidate = match self.candidate_from_obligation(&stack) {
+ let candidate = match self.select_from_obligation(obligation) {
Err(SelectionError::Overflow) => {
// In standard mode, overflow must have been caught and reported
// earlier.
assert!(self.query_mode == TraitQueryMode::Canonical);
return Err(SelectionError::Overflow);
}
+ Err(SelectionError::Ambiguous(_)) => {
+ return Ok(None);
+ }
Err(e) => {
return Err(e);
}
}
}
+ crate fn select_from_obligation(
+ &mut self,
+ obligation: &TraitObligation<'tcx>,
+ ) -> SelectionResult<'tcx, SelectionCandidate<'tcx>> {
+ debug_assert!(!obligation.predicate.has_escaping_bound_vars());
+
+ let pec = &ProvisionalEvaluationCache::default();
+ let stack = self.push_stack(TraitObligationStackList::empty(pec), obligation);
+
+ self.candidate_from_obligation(&stack)
+ }
+
///////////////////////////////////////////////////////////////////////////
// EVALUATION
//
match self.candidate_from_obligation(stack) {
Ok(Some(c)) => self.evaluate_candidate(stack, &c),
+ Err(SelectionError::Ambiguous(_)) => Ok(EvaluatedToAmbig),
Ok(None) => Ok(EvaluatedToAmbig),
Err(Overflow) => Err(OverflowError::Canonical),
Err(ErrorReporting) => Err(OverflowError::ErrorReporting),
(result, dep_node)
}
- /// filter_impls filters candidates that have a positive impl for a negative goal and a
- /// negative impl for a positive goal
+ /// filter_impls filters constant trait obligations and 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>,
- ) {
+ candidates: Vec<SelectionCandidate<'tcx>>,
+ obligation: &TraitObligation<'tcx>,
+ ) -> Vec<SelectionCandidate<'tcx>> {
let tcx = self.tcx();
- candidates.retain(|candidate| {
+ let mut result = Vec::with_capacity(candidates.len());
+
+ for candidate in candidates {
+ // Respect const trait obligations
+ if self.is_trait_predicate_const(obligation.predicate.skip_binder()) {
+ match candidate {
+ // const impl
+ ImplCandidate(def_id)
+ if tcx.impl_constness(def_id) == hir::Constness::Const => {}
+ // const param
+ ParamCandidate((
+ ty::ConstnessAnd { constness: ty::BoundConstness::ConstIfConst, .. },
+ _,
+ )) => {}
+ // auto trait impl
+ AutoImplCandidate(..) => {}
+ // generator, this will raise error in other places
+ // or ignore error with const_async_blocks feature
+ GeneratorCandidate => {}
+ // FnDef where the function is const
+ FnPointerCandidate { is_const: true } => {}
+ ConstDropCandidate => {}
+ _ => {
+ // reject all other types of candidates
+ continue;
+ }
+ }
+ }
+
if let ImplCandidate(def_id) = candidate {
- ty::ImplPolarity::Reservation == tcx.impl_polarity(*def_id)
- || stack.obligation.polarity() == tcx.impl_polarity(*def_id)
+ if ty::ImplPolarity::Reservation == tcx.impl_polarity(def_id)
+ || obligation.polarity() == tcx.impl_polarity(def_id)
|| self.allow_negative_impls
+ {
+ result.push(candidate);
+ }
} else {
- true
+ result.push(candidate);
}
- });
+ }
+
+ result
}
/// filter_reservation_impls filter reservation impl for any goal as ambiguous
obligation: &TraitObligation<'tcx>,
) -> SelectionResult<'tcx, SelectionCandidate<'tcx>> {
let tcx = self.tcx();
- // Respect const trait obligations
- if self.is_trait_predicate_const(obligation.predicate.skip_binder()) {
- match candidate {
- // const impl
- ImplCandidate(def_id) if tcx.impl_constness(def_id) == hir::Constness::Const => {}
- // const param
- ParamCandidate((
- ty::ConstnessAnd { constness: ty::BoundConstness::ConstIfConst, .. },
- _,
- )) => {}
- // auto trait impl
- AutoImplCandidate(..) => {}
- // generator, this will raise error in other places
- // or ignore error with const_async_blocks feature
- GeneratorCandidate => {}
- // FnDef where the function is const
- FnPointerCandidate { is_const: true } => {}
- ConstDropCandidate => {}
- _ => {
- // reject all other types of candidates
- return Err(Unimplemented);
- }
- }
- }
// Treat reservation impls as ambiguity.
if let ImplCandidate(def_id) = candidate {
if let ty::ImplPolarity::Reservation = tcx.impl_polarity(def_id) {
let value = attr.and_then(|a| a.value_str());
if let Some(value) = value {
debug!(
- "filter_impls: \
+ "filter_reservation_impls: \
reservation impl ambiguity on {:?}",
def_id
);