use rustc_errors::Applicability;
use rustc_hir as hir;
use rustc_hir::def::DefKind;
-use rustc_hir::def::Namespace;
use rustc_infer::infer::canonical::OriginalQueryValues;
use rustc_infer::infer::canonical::{Canonical, QueryResponse};
use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
use rustc_trait_selection::traits::query::CanonicalTyGoal;
use rustc_trait_selection::traits::NormalizeExt;
use rustc_trait_selection::traits::{self, ObligationCause};
+use std::cell::RefCell;
use std::cmp::max;
use std::iter;
-use std::mem;
use std::ops::Deref;
use smallvec::{smallvec, SmallVec};
/// This is the OriginalQueryValues for the steps queries
/// that are answered in steps.
- orig_steps_var_values: OriginalQueryValues<'tcx>,
+ orig_steps_var_values: &'a OriginalQueryValues<'tcx>,
steps: &'tcx [CandidateStep<'tcx>],
inherent_candidates: Vec<Candidate<'tcx>>,
extension_candidates: Vec<Candidate<'tcx>>,
impl_dups: FxHashSet<DefId>,
- /// Collects near misses when the candidate functions are missing a `self` keyword and is only
- /// used for error reporting
- static_candidates: Vec<CandidateSource>,
-
/// When probing for names, include names that are close to the
- /// requested name (by Levensthein distance)
+ /// requested name (by Levenshtein distance)
allow_similar_names: bool,
/// Some(candidate) if there is a private candidate
private_candidate: Option<(DefKind, DefId)>,
+ /// Collects near misses when the candidate functions are missing a `self` keyword and is only
+ /// used for error reporting
+ static_candidates: RefCell<Vec<CandidateSource>>,
+
/// Collects near misses when trait bounds for type parameters are unsatisfied and is only used
/// for error reporting
- unsatisfied_predicates:
+ unsatisfied_predicates: RefCell<
Vec<(ty::Predicate<'tcx>, Option<ty::Predicate<'tcx>>, Option<ObligationCause<'tcx>>)>,
+ >,
scope_expr_id: hir::HirId,
}
op: OP,
) -> Result<R, MethodError<'tcx>>
where
- OP: FnOnce(ProbeContext<'a, 'tcx>) -> Result<R, MethodError<'tcx>>,
+ OP: FnOnce(ProbeContext<'_, 'tcx>) -> Result<R, MethodError<'tcx>>,
{
let mut orig_values = OriginalQueryValues::default();
let param_env_and_self_ty = self.canonicalize_query(
mode,
method_name,
return_type,
- orig_values,
+ &orig_values,
steps.steps,
scope_expr_id,
);
mode: Mode,
method_name: Option<Ident>,
return_type: Option<Ty<'tcx>>,
- orig_steps_var_values: OriginalQueryValues<'tcx>,
+ orig_steps_var_values: &'a OriginalQueryValues<'tcx>,
steps: &'tcx [CandidateStep<'tcx>],
scope_expr_id: hir::HirId,
) -> ProbeContext<'a, 'tcx> {
impl_dups: FxHashSet::default(),
orig_steps_var_values,
steps,
- static_candidates: Vec::new(),
allow_similar_names: false,
private_candidate: None,
- unsatisfied_predicates: Vec::new(),
+ static_candidates: RefCell::new(Vec::new()),
+ unsatisfied_predicates: RefCell::new(Vec::new()),
scope_expr_id,
}
}
self.inherent_candidates.clear();
self.extension_candidates.clear();
self.impl_dups.clear();
- self.static_candidates.clear();
self.private_candidate = None;
+ self.static_candidates.borrow_mut().clear();
+ self.unsatisfied_predicates.borrow_mut().clear();
}
///////////////////////////////////////////////////////////////////////////
debug!("pick: actual search failed, assemble diagnostics");
- let static_candidates = mem::take(&mut self.static_candidates);
+ let static_candidates = std::mem::take(self.static_candidates.get_mut());
let private_candidate = self.private_candidate.take();
- let unsatisfied_predicates = mem::take(&mut self.unsatisfied_predicates);
+ let unsatisfied_predicates = std::mem::take(self.unsatisfied_predicates.get_mut());
// things failed, so lets look at all traits, for diagnostic purposes now:
self.reset();
}))
}
- fn pick_core(&mut self) -> Option<PickResult<'tcx>> {
+ fn pick_core(&self) -> Option<PickResult<'tcx>> {
let pick = self.pick_all_method(Some(&mut vec![]));
// In this case unstable picking is done by `pick_method`.
}
fn pick_all_method(
- &mut self,
+ &self,
mut unstable_candidates: Option<&mut Vec<(Candidate<'tcx>, Symbol)>>,
) -> Option<PickResult<'tcx>> {
- let steps = self.steps.clone();
- steps
+ self.steps
.iter()
.filter(|step| {
debug!("pick_all_method: step={:?}", step);
/// to transparently pass `&mut` pointers, in particular, without consuming
/// them for their entire lifetime.
fn pick_by_value_method(
- &mut self,
+ &self,
step: &CandidateStep<'tcx>,
self_ty: Ty<'tcx>,
unstable_candidates: Option<&mut Vec<(Candidate<'tcx>, Symbol)>>,
}
fn pick_autorefd_method(
- &mut self,
+ &self,
step: &CandidateStep<'tcx>,
self_ty: Ty<'tcx>,
mutbl: hir::Mutability,
/// special case for this is because going from `*mut T` to `*const T` with autoderefs and
/// autorefs would require dereferencing the pointer, which is not safe.
fn pick_const_ptr_method(
- &mut self,
+ &self,
step: &CandidateStep<'tcx>,
self_ty: Ty<'tcx>,
unstable_candidates: Option<&mut Vec<(Candidate<'tcx>, Symbol)>>,
})
}
- fn pick_method_with_unstable(&mut self, self_ty: Ty<'tcx>) -> Option<PickResult<'tcx>> {
+ fn pick_method_with_unstable(&self, self_ty: Ty<'tcx>) -> Option<PickResult<'tcx>> {
debug!("pick_method_with_unstable(self_ty={})", self.ty_to_string(self_ty));
let mut possibly_unsatisfied_predicates = Vec::new();
debug!("searching {} candidates", kind);
let res = self.consider_candidates(
self_ty,
- candidates.iter(),
+ candidates,
&mut possibly_unsatisfied_predicates,
Some(&mut vec![]),
);
}
}
- debug!("searching unstable candidates");
- let res = self.consider_candidates(
- self_ty,
- self.inherent_candidates.iter().chain(&self.extension_candidates),
- &mut possibly_unsatisfied_predicates,
- None,
- );
- if res.is_none() {
- self.unsatisfied_predicates.extend(possibly_unsatisfied_predicates);
+ for (kind, candidates) in
+ &[("inherent", &self.inherent_candidates), ("extension", &self.extension_candidates)]
+ {
+ debug!("searching unstable {kind} candidates");
+ let res = self.consider_candidates(
+ self_ty,
+ candidates,
+ &mut possibly_unsatisfied_predicates,
+ None,
+ );
+ if res.is_some() {
+ return res;
+ }
}
- res
+
+ self.unsatisfied_predicates.borrow_mut().extend(possibly_unsatisfied_predicates);
+ None
}
fn pick_method(
- &mut self,
+ &self,
self_ty: Ty<'tcx>,
mut unstable_candidates: Option<&mut Vec<(Candidate<'tcx>, Symbol)>>,
) -> Option<PickResult<'tcx>> {
debug!("searching {} candidates", kind);
let res = self.consider_candidates(
self_ty,
- candidates.iter(),
+ candidates,
&mut possibly_unsatisfied_predicates,
unstable_candidates.as_deref_mut(),
);
// `pick_method` may be called twice for the same self_ty if no stable methods
// match. Only extend once.
if unstable_candidates.is_some() {
- self.unsatisfied_predicates.extend(possibly_unsatisfied_predicates);
+ self.unsatisfied_predicates.borrow_mut().extend(possibly_unsatisfied_predicates);
}
None
}
- fn consider_candidates<'b, ProbesIter>(
+ fn consider_candidates(
&self,
self_ty: Ty<'tcx>,
- probes: ProbesIter,
+ candidates: &[Candidate<'tcx>],
possibly_unsatisfied_predicates: &mut Vec<(
ty::Predicate<'tcx>,
Option<ty::Predicate<'tcx>>,
Option<ObligationCause<'tcx>>,
)>,
mut unstable_candidates: Option<&mut Vec<(Candidate<'tcx>, Symbol)>>,
- ) -> Option<PickResult<'tcx>>
- where
- ProbesIter: Iterator<Item = &'b Candidate<'tcx>> + Clone,
- 'tcx: 'b,
- {
- let mut applicable_candidates: Vec<_> = probes
- .clone()
+ ) -> Option<PickResult<'tcx>> {
+ let mut applicable_candidates: Vec<_> = candidates
+ .iter()
.map(|probe| {
(probe, self.consider_probe(self_ty, probe, possibly_unsatisfied_predicates))
})
}
if let Some(uc) = &mut unstable_candidates {
- applicable_candidates.retain(|&(p, _)| {
+ applicable_candidates.retain(|&(candidate, _)| {
if let stability::EvalResult::Deny { feature, .. } =
- self.tcx.eval_stability(p.item.def_id, None, self.span, None)
+ self.tcx.eval_stability(candidate.item.def_id, None, self.span, None)
{
- uc.push((p.clone(), feature));
+ uc.push((candidate.clone(), feature));
return false;
}
true
}
if applicable_candidates.len() > 1 {
- let sources = probes.map(|p| self.candidate_source(p, self_ty)).collect();
+ let sources = candidates.iter().map(|p| self.candidate_source(p, self_ty)).collect();
return Some(Err(MethodError::Ambiguity(sources)));
}
self.mode,
self.method_name,
self.return_type,
- self.orig_steps_var_values.clone(),
+ &self.orig_steps_var_values,
steps,
self.scope_expr_id,
);
// -- but this could be overcome.
}
- fn record_static_candidate(&mut self, source: CandidateSource) {
- self.static_candidates.push(source);
+ fn record_static_candidate(&self, source: CandidateSource) {
+ self.static_candidates.borrow_mut().push(source);
}
#[instrument(level = "debug", skip(self))]
self.tcx.erase_late_bound_regions(value)
}
+ /// Determine if the given associated item type is relevant in the current context.
+ fn is_relevant_kind_for_mode(&self, kind: ty::AssocKind) -> bool {
+ match (self.mode, kind) {
+ (Mode::MethodCall, ty::AssocKind::Fn) => true,
+ (Mode::Path, ty::AssocKind::Const | ty::AssocKind::Fn) => true,
+ _ => false,
+ }
+ }
+
/// Finds the method with the appropriate name (or return type, as the case may be). If
/// `allow_similar_names` is set, find methods with close-matching names.
// The length of the returned iterator is nearly always 0 or 1 and this
.associated_items(def_id)
.in_definition_order()
.filter(|x| {
- if x.kind.namespace() != Namespace::ValueNS {
+ if !self.is_relevant_kind_for_mode(x.kind) {
return false;
}
match lev_distance_with_substrings(name.as_str(), x.name.as_str(), max_dist)
} else {
self.fcx
.associated_value(def_id, name)
+ .filter(|x| self.is_relevant_kind_for_mode(x.kind))
.map_or_else(SmallVec::new, |x| SmallVec::from_buf([x]))
}
} else {
- self.tcx.associated_items(def_id).in_definition_order().copied().collect()
+ self.tcx
+ .associated_items(def_id)
+ .in_definition_order()
+ .filter(|x| self.is_relevant_kind_for_mode(x.kind))
+ .copied()
+ .collect()
}
}
}