summaryrefslogtreecommitdiffstats
path: root/compiler/rustc_hir_typeck/src/method/probe.rs
diff options
context:
space:
mode:
Diffstat (limited to 'compiler/rustc_hir_typeck/src/method/probe.rs')
-rw-r--r--compiler/rustc_hir_typeck/src/method/probe.rs282
1 files changed, 129 insertions, 153 deletions
diff --git a/compiler/rustc_hir_typeck/src/method/probe.rs b/compiler/rustc_hir_typeck/src/method/probe.rs
index a24814313..3bef5cfcd 100644
--- a/compiler/rustc_hir_typeck/src/method/probe.rs
+++ b/compiler/rustc_hir_typeck/src/method/probe.rs
@@ -9,24 +9,23 @@ use rustc_data_structures::fx::FxHashSet;
use rustc_errors::Applicability;
use rustc_hir as hir;
use rustc_hir::def::DefKind;
+use rustc_hir_analysis::astconv::InferCtxtExt as _;
use rustc_hir_analysis::autoderef::{self, Autoderef};
use rustc_infer::infer::canonical::OriginalQueryValues;
use rustc_infer::infer::canonical::{Canonical, QueryResponse};
-use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
use rustc_infer::infer::{self, InferOk, TyCtxtInferExt};
-use rustc_middle::infer::unify_key::{ConstVariableOrigin, ConstVariableOriginKind};
use rustc_middle::middle::stability;
use rustc_middle::ty::fast_reject::{simplify_type, TreatParams};
use rustc_middle::ty::AssocItem;
use rustc_middle::ty::GenericParamDefKind;
use rustc_middle::ty::ToPredicate;
-use rustc_middle::ty::{self, ParamEnvAnd, Ty, TyCtxt, TypeFoldable, TypeVisitable};
+use rustc_middle::ty::{self, ParamEnvAnd, Ty, TyCtxt, TypeFoldable, TypeVisitableExt};
use rustc_middle::ty::{InternalSubsts, SubstsRef};
use rustc_session::lint;
use rustc_span::def_id::DefId;
use rustc_span::def_id::LocalDefId;
-use rustc_span::lev_distance::{
- find_best_match_for_name_with_substrings, lev_distance_with_substrings,
+use rustc_span::edit_distance::{
+ edit_distance_with_substrings, find_best_match_for_name_with_substrings,
};
use rustc_span::symbol::sym;
use rustc_span::{symbol::Ident, Span, Symbol, DUMMY_SP};
@@ -70,7 +69,7 @@ struct ProbeContext<'a, 'tcx> {
impl_dups: FxHashSet<DefId>,
/// When probing for names, include names that are close to the
- /// requested name (by Levenshtein distance)
+ /// requested name (by edit distance)
allow_similar_names: bool,
/// Some(candidate) if there is a private candidate
@@ -461,7 +460,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
static_candidates: Vec::new(),
unsatisfied_predicates: Vec::new(),
out_of_scope_traits: Vec::new(),
- lev_candidate: None,
+ similar_candidate: None,
mode,
}));
}
@@ -508,16 +507,16 @@ fn method_autoderef_steps<'tcx>(
let (ref infcx, goal, inference_vars) = tcx.infer_ctxt().build_with_canonical(DUMMY_SP, &goal);
let ParamEnvAnd { param_env, value: self_ty } = goal;
- let mut autoderef = Autoderef::new(infcx, param_env, hir::CRATE_HIR_ID, DUMMY_SP, self_ty)
- .include_raw_pointers()
- .silence_errors();
+ let mut autoderef =
+ Autoderef::new(infcx, param_env, hir::def_id::CRATE_DEF_ID, DUMMY_SP, self_ty)
+ .include_raw_pointers()
+ .silence_errors();
let mut reached_raw_pointer = false;
let mut steps: Vec<_> = autoderef
.by_ref()
.map(|(ty, d)| {
let step = CandidateStep {
- self_ty: infcx
- .make_query_response_ignoring_pending_obligations(inference_vars.clone(), ty),
+ self_ty: infcx.make_query_response_ignoring_pending_obligations(inference_vars, ty),
autoderefs: d,
from_unsafe_deref: reached_raw_pointer,
unsize: false,
@@ -610,10 +609,9 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
fn push_candidate(&mut self, candidate: Candidate<'tcx>, is_inherent: bool) {
let is_accessible = if let Some(name) = self.method_name {
let item = candidate.item;
- let def_scope = self
- .tcx
- .adjust_ident_and_get_scope(name, item.container_id(self.tcx), self.body_id)
- .1;
+ let hir_id = self.tcx.hir().local_def_id_to_hir_id(self.body_id);
+ let def_scope =
+ self.tcx.adjust_ident_and_get_scope(name, item.container_id(self.tcx), hir_id).1;
item.visibility(self.tcx).is_accessible_from(def_scope, self.tcx)
} else {
true
@@ -736,7 +734,7 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
debug!("impl_ty: {:?}", impl_ty);
// Determine the receiver type that the method itself expects.
- let (xform_self_ty, xform_ret_ty) = self.xform_self_ty(&item, impl_ty, impl_substs);
+ let (xform_self_ty, xform_ret_ty) = self.xform_self_ty(item, impl_ty, impl_substs);
debug!("xform_self_ty: {:?}, xform_ret_ty: {:?}", xform_self_ty, xform_ret_ty);
// We can't use normalize_associated_types_in as it will pollute the
@@ -797,7 +795,7 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
let new_trait_ref = this.erase_late_bound_regions(new_trait_ref);
let (xform_self_ty, xform_ret_ty) =
- this.xform_self_ty(&item, new_trait_ref.self_ty(), new_trait_ref.substs);
+ this.xform_self_ty(item, new_trait_ref.self_ty(), new_trait_ref.substs);
this.push_candidate(
Candidate {
xform_self_ty,
@@ -827,6 +825,7 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
}
}
ty::PredicateKind::Subtype(..)
+ | ty::PredicateKind::Clause(ty::Clause::ConstArgHasType(..))
| ty::PredicateKind::Coerce(..)
| ty::PredicateKind::Clause(ty::Clause::Projection(..))
| ty::PredicateKind::Clause(ty::Clause::RegionOutlives(..))
@@ -837,6 +836,7 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
| ty::PredicateKind::ConstEvaluatable(..)
| ty::PredicateKind::ConstEquate(..)
| ty::PredicateKind::Ambiguous
+ | ty::PredicateKind::AliasEq(..)
| ty::PredicateKind::TypeWellFormedFromEnv(..) => None,
}
});
@@ -845,7 +845,7 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
let trait_ref = this.erase_late_bound_regions(poly_trait_ref);
let (xform_self_ty, xform_ret_ty) =
- this.xform_self_ty(&item, trait_ref.self_ty(), trait_ref.substs);
+ this.xform_self_ty(item, trait_ref.self_ty(), trait_ref.substs);
// Because this trait derives from a where-clause, it
// should not contain any inference variables or other
@@ -916,31 +916,27 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
fn matches_return_type(
&self,
- method: &ty::AssocItem,
+ method: ty::AssocItem,
self_ty: Option<Ty<'tcx>>,
expected: Ty<'tcx>,
) -> bool {
match method.kind {
- ty::AssocKind::Fn => {
- let fty = self.tcx.bound_fn_sig(method.def_id);
- self.probe(|_| {
- let substs = self.fresh_substs_for_item(self.span, method.def_id);
- let fty = fty.subst(self.tcx, substs);
- let fty =
- self.replace_bound_vars_with_fresh_vars(self.span, infer::FnCall, fty);
-
- if let Some(self_ty) = self_ty {
- if self
- .at(&ObligationCause::dummy(), self.param_env)
- .sup(fty.inputs()[0], self_ty)
- .is_err()
- {
- return false;
- }
+ ty::AssocKind::Fn => self.probe(|_| {
+ let substs = self.fresh_substs_for_item(self.span, method.def_id);
+ let fty = self.tcx.fn_sig(method.def_id).subst(self.tcx, substs);
+ let fty = self.instantiate_binder_with_fresh_vars(self.span, infer::FnCall, fty);
+
+ if let Some(self_ty) = self_ty {
+ if self
+ .at(&ObligationCause::dummy(), self.param_env)
+ .sup(fty.inputs()[0], self_ty)
+ .is_err()
+ {
+ return false;
}
- self.can_sub(self.param_env, fty.output(), expected).is_ok()
- })
- }
+ }
+ self.can_sub(self.param_env, fty.output(), expected)
+ }),
_ => false,
}
}
@@ -955,24 +951,35 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
let trait_ref = self.tcx.mk_trait_ref(trait_def_id, trait_substs);
if self.tcx.is_trait_alias(trait_def_id) {
- // For trait aliases, assume all supertraits are relevant.
- let bounds = iter::once(ty::Binder::dummy(trait_ref));
- self.elaborate_bounds(bounds, |this, new_trait_ref, item| {
- let new_trait_ref = this.erase_late_bound_regions(new_trait_ref);
-
- let (xform_self_ty, xform_ret_ty) =
- this.xform_self_ty(&item, new_trait_ref.self_ty(), new_trait_ref.substs);
- this.push_candidate(
- Candidate {
- xform_self_ty,
- xform_ret_ty,
- item,
- import_ids: import_ids.clone(),
- kind: TraitCandidate(new_trait_ref),
- },
- false,
- );
- });
+ // For trait aliases, recursively assume all explicitly named traits are relevant
+ for expansion in traits::expand_trait_aliases(
+ self.tcx,
+ iter::once((ty::Binder::dummy(trait_ref), self.span)),
+ ) {
+ let bound_trait_ref = expansion.trait_ref();
+ for item in self.impl_or_trait_item(bound_trait_ref.def_id()) {
+ if !self.has_applicable_self(&item) {
+ self.record_static_candidate(CandidateSource::Trait(
+ bound_trait_ref.def_id(),
+ ));
+ } else {
+ let new_trait_ref = self.erase_late_bound_regions(bound_trait_ref);
+
+ let (xform_self_ty, xform_ret_ty) =
+ self.xform_self_ty(item, new_trait_ref.self_ty(), new_trait_ref.substs);
+ self.push_candidate(
+ Candidate {
+ xform_self_ty,
+ xform_ret_ty,
+ item,
+ import_ids: import_ids.clone(),
+ kind: TraitCandidate(new_trait_ref),
+ },
+ false,
+ );
+ }
+ }
+ }
} else {
debug_assert!(self.tcx.is_trait(trait_def_id));
if self.tcx.trait_is_auto(trait_def_id) {
@@ -987,7 +994,7 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
}
let (xform_self_ty, xform_ret_ty) =
- self.xform_self_ty(&item, trait_ref.self_ty(), trait_substs);
+ self.xform_self_ty(item, trait_ref.self_ty(), trait_substs);
self.push_candidate(
Candidate {
xform_self_ty,
@@ -1014,7 +1021,7 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
.filter(|candidate| candidate_filter(&candidate.item))
.filter(|candidate| {
if let Some(return_ty) = self.return_type {
- self.matches_return_type(&candidate.item, None, return_ty)
+ self.matches_return_type(candidate.item, None, return_ty)
} else {
true
}
@@ -1076,29 +1083,20 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
if let Some((kind, def_id)) = private_candidate {
return Err(MethodError::PrivateMatch(kind, def_id, out_of_scope_traits));
}
- let lev_candidate = self.probe_for_lev_candidate()?;
+ let similar_candidate = self.probe_for_similar_candidate()?;
Err(MethodError::NoMatch(NoMatchData {
static_candidates,
unsatisfied_predicates,
out_of_scope_traits,
- lev_candidate,
+ similar_candidate,
mode: self.mode,
}))
}
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`.
- if !self.tcx.sess.opts.unstable_opts.pick_stable_methods_before_any_unstable {
- return pick;
- }
-
- if pick.is_none() {
- return self.pick_all_method(None);
- }
- pick
+ // Pick stable methods only first, and consider unstable candidates if not found.
+ self.pick_all_method(Some(&mut vec![])).or_else(|| self.pick_all_method(None))
}
fn pick_all_method(
@@ -1237,54 +1235,11 @@ impl<'a, 'tcx> ProbeContext<'a, '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();
-
- for (kind, candidates) in
- &[("inherent", &self.inherent_candidates), ("extension", &self.extension_candidates)]
- {
- debug!("searching {} candidates", kind);
- let res = self.consider_candidates(
- self_ty,
- candidates,
- &mut possibly_unsatisfied_predicates,
- Some(&mut vec![]),
- );
- if res.is_some() {
- return res;
- }
- }
-
- 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;
- }
- }
-
- self.unsatisfied_predicates.borrow_mut().extend(possibly_unsatisfied_predicates);
- None
- }
-
fn pick_method(
&self,
self_ty: Ty<'tcx>,
mut unstable_candidates: Option<&mut Vec<(Candidate<'tcx>, Symbol)>>,
) -> Option<PickResult<'tcx>> {
- if !self.tcx.sess.opts.unstable_opts.pick_stable_methods_before_any_unstable {
- return self.pick_method_with_unstable(self_ty);
- }
-
debug!("pick_method(self_ty={})", self.ty_to_string(self_ty));
let mut possibly_unsatisfied_predicates = Vec::new();
@@ -1358,13 +1313,12 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
return Some(Err(MethodError::Ambiguity(sources)));
}
- applicable_candidates.pop().map(|(probe, status)| {
- if status == ProbeResult::Match {
+ applicable_candidates.pop().map(|(probe, status)| match status {
+ ProbeResult::Match => {
Ok(probe
.to_unadjusted_pick(self_ty, unstable_candidates.cloned().unwrap_or_default()))
- } else {
- Err(MethodError::BadReturnType)
}
+ ProbeResult::NoMatch | ProbeResult::BadReturnType => Err(MethodError::BadReturnType),
})
}
}
@@ -1412,8 +1366,8 @@ impl<'tcx> Pick<'tcx> {
span,
format!(
"{} {} with this name may be added to the standard library in the future",
- def_kind.article(),
- def_kind.descr(self.item.def_id),
+ tcx.def_kind_descr_article(def_kind, self.item.def_id),
+ tcx.def_kind_descr(def_kind, self.item.def_id),
),
|lint| {
match (self.item.kind, self.item.container) {
@@ -1482,7 +1436,6 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
TraitCandidate(trait_ref) => self.probe(|_| {
let _ = self
.at(&ObligationCause::dummy(), self.param_env)
- .define_opaque_types(false)
.sup(candidate.xform_self_ty, self_ty);
match self.select_trait_candidate(trait_ref) {
Ok(Some(traits::ImplSource::UserDefined(ref impl_data))) => {
@@ -1512,7 +1465,6 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
// First check that the self type can be related.
let sub_obligations = match self
.at(&ObligationCause::dummy(), self.param_env)
- .define_opaque_types(false)
.sup(probe.xform_self_ty, self_ty)
{
Ok(InferOk { obligations, value: () }) => obligations,
@@ -1567,7 +1519,8 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
traits::ImplDerivedObligation(Box::new(
traits::ImplDerivedObligationCause {
derived,
- impl_def_id,
+ impl_or_alias_def_id: impl_def_id,
+ impl_def_predicate_index: None,
span,
},
))
@@ -1728,7 +1681,6 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
if let ProbeResult::Match = result
&& self
.at(&ObligationCause::dummy(), self.param_env)
- .define_opaque_types(false)
.sup(return_ty, xform_ret_ty)
.is_err()
{
@@ -1786,8 +1738,8 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
/// Similarly to `probe_for_return_type`, this method attempts to find the best matching
/// candidate method where the method name may have been misspelled. Similarly to other
- /// Levenshtein based suggestions, we provide at most one such suggestion.
- fn probe_for_lev_candidate(&mut self) -> Result<Option<ty::AssocItem>, MethodError<'tcx>> {
+ /// edit distance based suggestions, we provide at most one such suggestion.
+ fn probe_for_similar_candidate(&mut self) -> Result<Option<ty::AssocItem>, MethodError<'tcx>> {
debug!("probing for method names similar to {:?}", self.method_name);
let steps = self.steps.clone();
@@ -1831,6 +1783,12 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
None,
)
}
+ .or_else(|| {
+ applicable_close_candidates
+ .iter()
+ .find(|cand| self.matches_by_doc_alias(cand.def_id))
+ .map(|cand| cand.name)
+ })
.unwrap();
Ok(applicable_close_candidates.into_iter().find(|method| method.name == best_name))
}
@@ -1867,7 +1825,7 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
#[instrument(level = "debug", skip(self))]
fn xform_self_ty(
&self,
- item: &ty::AssocItem,
+ item: ty::AssocItem,
impl_ty: Ty<'tcx>,
substs: SubstsRef<'tcx>,
) -> (Ty<'tcx>, Option<Ty<'tcx>>) {
@@ -1881,7 +1839,7 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
#[instrument(level = "debug", skip(self))]
fn xform_method_sig(&self, method: DefId, substs: SubstsRef<'tcx>) -> ty::FnSig<'tcx> {
- let fn_sig = self.tcx.bound_fn_sig(method);
+ let fn_sig = self.tcx.fn_sig(method);
debug!(?fn_sig);
assert!(!substs.has_escaping_bound_vars());
@@ -1924,27 +1882,7 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
&self,
impl_def_id: DefId,
) -> (ty::EarlyBinder<Ty<'tcx>>, SubstsRef<'tcx>) {
- (self.tcx.bound_type_of(impl_def_id), self.fresh_item_substs(impl_def_id))
- }
-
- fn fresh_item_substs(&self, def_id: DefId) -> SubstsRef<'tcx> {
- InternalSubsts::for_item(self.tcx, def_id, |param, _| match param.kind {
- GenericParamDefKind::Lifetime => self.tcx.lifetimes.re_erased.into(),
- GenericParamDefKind::Type { .. } => self
- .next_ty_var(TypeVariableOrigin {
- kind: TypeVariableOriginKind::SubstitutionPlaceholder,
- span: self.tcx.def_span(def_id),
- })
- .into(),
- GenericParamDefKind::Const { .. } => {
- let span = self.tcx.def_span(def_id);
- let origin = ConstVariableOrigin {
- kind: ConstVariableOriginKind::SubstitutionPlaceholder,
- span,
- };
- self.next_const_var(self.tcx.type_of(param.def_id), origin).into()
- }
- })
+ (self.tcx.type_of(impl_def_id), self.fresh_item_substs(impl_def_id))
}
/// Replaces late-bound-regions bound by `value` with `'static` using
@@ -1967,7 +1905,7 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
/// so forth.
fn erase_late_bound_regions<T>(&self, value: ty::Binder<'tcx, T>) -> T
where
- T: TypeFoldable<'tcx>,
+ T: TypeFoldable<TyCtxt<'tcx>>,
{
self.tcx.erase_late_bound_regions(value)
}
@@ -1981,6 +1919,38 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
}
}
+ /// Determine if the associated item withe the given DefId matches
+ /// the desired name via a doc alias.
+ fn matches_by_doc_alias(&self, def_id: DefId) -> bool {
+ let Some(name) = self.method_name else { return false; };
+ let Some(local_def_id) = def_id.as_local() else { return false; };
+ let hir_id = self.fcx.tcx.hir().local_def_id_to_hir_id(local_def_id);
+ let attrs = self.fcx.tcx.hir().attrs(hir_id);
+ for attr in attrs {
+ let sym::doc = attr.name_or_empty() else { continue; };
+ let Some(values) = attr.meta_item_list() else { continue; };
+ for v in values {
+ if v.name_or_empty() != sym::alias {
+ continue;
+ }
+ if let Some(nested) = v.meta_item_list() {
+ // #[doc(alias("foo", "bar"))]
+ for n in nested {
+ if let Some(lit) = n.lit() && name.as_str() == lit.symbol.as_str() {
+ return true;
+ }
+ }
+ } else if let Some(meta) = v.meta_item()
+ && let Some(lit) = meta.name_value_literal()
+ && name.as_str() == lit.symbol.as_str() {
+ // #[doc(alias = "foo")]
+ return 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
@@ -1996,8 +1966,14 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
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)
- {
+ if self.matches_by_doc_alias(x.def_id) {
+ return true;
+ }
+ match edit_distance_with_substrings(
+ name.as_str(),
+ x.name.as_str(),
+ max_dist,
+ ) {
Some(d) => d > 0,
None => false,
}