summaryrefslogtreecommitdiffstats
path: root/compiler/rustc_hir_typeck/src/method/probe.rs
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-17 12:18:21 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-17 12:18:21 +0000
commit4e8199b572f2035b7749cba276ece3a26630d23e (patch)
treef09feeed6a0fe39d027b1908aa63ea6b35e4b631 /compiler/rustc_hir_typeck/src/method/probe.rs
parentAdding upstream version 1.66.0+dfsg1. (diff)
downloadrustc-4e8199b572f2035b7749cba276ece3a26630d23e.tar.xz
rustc-4e8199b572f2035b7749cba276ece3a26630d23e.zip
Adding upstream version 1.67.1+dfsg1.upstream/1.67.1+dfsg1
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'compiler/rustc_hir_typeck/src/method/probe.rs')
-rw-r--r--compiler/rustc_hir_typeck/src/method/probe.rs210
1 files changed, 122 insertions, 88 deletions
diff --git a/compiler/rustc_hir_typeck/src/method/probe.rs b/compiler/rustc_hir_typeck/src/method/probe.rs
index 28aa2302f..ae299cc9d 100644
--- a/compiler/rustc_hir_typeck/src/method/probe.rs
+++ b/compiler/rustc_hir_typeck/src/method/probe.rs
@@ -9,7 +9,6 @@ use rustc_data_structures::fx::FxHashSet;
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};
@@ -17,8 +16,10 @@ 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::{self, ParamEnvAnd, ToPredicate, Ty, TyCtxt, TypeFoldable, TypeVisitable};
+use rustc_middle::ty::ToPredicate;
+use rustc_middle::ty::{self, ParamEnvAnd, Ty, TyCtxt, TypeFoldable, TypeVisitable};
use rustc_middle::ty::{InternalSubsts, SubstsRef};
use rustc_session::lint;
use rustc_span::def_id::DefId;
@@ -35,6 +36,7 @@ use rustc_trait_selection::traits::query::method_autoderef::{
CandidateStep, MethodAutoderefStepsResult,
};
use rustc_trait_selection::traits::query::CanonicalTyGoal;
+use rustc_trait_selection::traits::NormalizeExt;
use rustc_trait_selection::traits::{self, ObligationCause};
use std::cmp::max;
use std::iter;
@@ -83,8 +85,6 @@ struct ProbeContext<'a, 'tcx> {
unsatisfied_predicates:
Vec<(ty::Predicate<'tcx>, Option<ty::Predicate<'tcx>>, Option<ObligationCause<'tcx>>)>,
- is_suggestion: IsSuggestion,
-
scope_expr_id: hir::HirId,
}
@@ -193,7 +193,7 @@ impl AutorefOrPtrAdjustment {
}
}
-#[derive(Debug, PartialEq, Clone)]
+#[derive(Debug, Clone)]
pub struct Pick<'tcx> {
pub item: ty::AssocItem,
pub kind: PickKind<'tcx>,
@@ -209,6 +209,9 @@ pub struct Pick<'tcx> {
/// `*mut T`, convert it to `*const T`.
pub autoref_or_ptr_adjustment: Option<AutorefOrPtrAdjustment>,
pub self_ty: Ty<'tcx>,
+
+ /// Unstable candidates alongside the stable ones.
+ unstable_candidates: Vec<(Candidate<'tcx>, Symbol)>,
}
#[derive(Clone, Debug, PartialEq, Eq)]
@@ -298,7 +301,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
#[instrument(level = "debug", skip(self))]
pub fn probe_for_name(
&self,
- span: Span,
mode: Mode,
item_name: Ident,
is_suggestion: IsSuggestion,
@@ -307,7 +309,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
scope: ProbeScope,
) -> PickResult<'tcx> {
self.probe_op(
- span,
+ item_name.span,
mode,
Some(item_name),
None,
@@ -340,10 +342,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
&mut orig_values,
);
- let steps = if mode == Mode::MethodCall {
- self.tcx.method_autoderef_steps(param_env_and_self_ty)
- } else {
- self.probe(|_| {
+ let steps = match mode {
+ Mode::MethodCall => self.tcx.method_autoderef_steps(param_env_and_self_ty),
+ Mode::Path => self.probe(|_| {
// Mode::Path - the deref steps is "trivial". This turns
// our CanonicalQuery into a "trivial" QueryResponse. This
// is a bit inefficient, but I don't think that writing
@@ -372,7 +373,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
opt_bad_ty: None,
reached_recursion_limit: false,
}
- })
+ }),
};
// If our autoderef loop had reached the recursion limit,
@@ -446,7 +447,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
return_type,
orig_values,
steps.steps,
- is_suggestion,
scope_expr_id,
);
@@ -475,10 +475,9 @@ 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, DUMMY_SP)
- .include_raw_pointers()
- .silence_errors();
+ let mut autoderef = Autoderef::new(infcx, param_env, hir::CRATE_HIR_ID, DUMMY_SP, self_ty)
+ .include_raw_pointers()
+ .silence_errors();
let mut reached_raw_pointer = false;
let mut steps: Vec<_> = autoderef
.by_ref()
@@ -542,7 +541,6 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
return_type: Option<Ty<'tcx>>,
orig_steps_var_values: OriginalQueryValues<'tcx>,
steps: &'tcx [CandidateStep<'tcx>],
- is_suggestion: IsSuggestion,
scope_expr_id: hir::HirId,
) -> ProbeContext<'a, 'tcx> {
ProbeContext {
@@ -560,7 +558,6 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
allow_similar_names: false,
private_candidate: None,
unsatisfied_predicates: Vec::new(),
- is_suggestion,
scope_expr_id,
}
}
@@ -718,9 +715,9 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
// maybe shouldn't include `Param`s, but rather fresh variables or be canonicalized,
// see issue #89650
let cause = traits::ObligationCause::misc(self.span, self.body_id);
- let selcx = &mut traits::SelectionContext::new(self.fcx);
- let traits::Normalized { value: xform_self_ty, obligations } =
- traits::normalize(selcx, self.param_env, cause, xform_self_ty);
+ let InferOk { value: xform_self_ty, obligations } =
+ self.fcx.at(&cause, self.param_env).normalize(xform_self_ty);
+
debug!(
"assemble_inherent_impl_probe after normalization: xform_self_ty = {:?}/{:?}",
xform_self_ty, xform_ret_ty
@@ -787,7 +784,7 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
let bounds = self.param_env.caller_bounds().iter().filter_map(|predicate| {
let bound_predicate = predicate.kind();
match bound_predicate.skip_binder() {
- ty::PredicateKind::Trait(trait_predicate) => {
+ ty::PredicateKind::Clause(ty::Clause::Trait(trait_predicate)) => {
match *trait_predicate.trait_ref.self_ty().kind() {
ty::Param(p) if p == param_ty => {
Some(bound_predicate.rebind(trait_predicate.trait_ref))
@@ -797,14 +794,15 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
}
ty::PredicateKind::Subtype(..)
| ty::PredicateKind::Coerce(..)
- | ty::PredicateKind::Projection(..)
- | ty::PredicateKind::RegionOutlives(..)
+ | ty::PredicateKind::Clause(ty::Clause::Projection(..))
+ | ty::PredicateKind::Clause(ty::Clause::RegionOutlives(..))
| ty::PredicateKind::WellFormed(..)
| ty::PredicateKind::ObjectSafe(..)
| ty::PredicateKind::ClosureKind(..)
- | ty::PredicateKind::TypeOutlives(..)
+ | ty::PredicateKind::Clause(ty::Clause::TypeOutlives(..))
| ty::PredicateKind::ConstEvaluatable(..)
| ty::PredicateKind::ConstEquate(..)
+ | ty::PredicateKind::Ambiguous
| ty::PredicateKind::TypeWellFormedFromEnv(..) => None,
}
});
@@ -882,7 +880,7 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
}
}
- pub fn matches_return_type(
+ fn matches_return_type(
&self,
method: &ty::AssocItem,
self_ty: Option<Ty<'tcx>>,
@@ -1019,7 +1017,6 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
let out_of_scope_traits = match self.pick_core() {
Some(Ok(p)) => vec![p.item.container_id(self.tcx)],
- //Some(Ok(p)) => p.iter().map(|p| p.item.container().id()).collect(),
Some(Err(MethodError::Ambiguity(v))) => v
.into_iter()
.map(|source| match source {
@@ -1054,26 +1051,17 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
}
fn pick_core(&mut self) -> Option<PickResult<'tcx>> {
- let mut unstable_candidates = Vec::new();
- let pick = self.pick_all_method(Some(&mut unstable_candidates));
+ 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;
}
- match pick {
- // Emit a lint if there are unstable candidates alongside the stable ones.
- //
- // We suppress warning if we're picking the method only because it is a
- // suggestion.
- Some(Ok(ref p)) if !self.is_suggestion.0 && !unstable_candidates.is_empty() => {
- self.emit_unstable_name_collision_hint(p, &unstable_candidates);
- pick
- }
- Some(_) => pick,
- None => self.pick_all_method(None),
+ if pick.is_none() {
+ return self.pick_all_method(None);
}
+ pick
}
fn pick_all_method(
@@ -1218,7 +1206,6 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
debug!("pick_method_with_unstable(self_ty={})", self.ty_to_string(self_ty));
let mut possibly_unsatisfied_predicates = Vec::new();
- let mut unstable_candidates = Vec::new();
for (kind, candidates) in
&[("inherent", &self.inherent_candidates), ("extension", &self.extension_candidates)]
@@ -1228,26 +1215,17 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
self_ty,
candidates.iter(),
&mut possibly_unsatisfied_predicates,
- Some(&mut unstable_candidates),
+ Some(&mut vec![]),
);
- if let Some(pick) = res {
- if !self.is_suggestion.0 && !unstable_candidates.is_empty() {
- if let Ok(p) = &pick {
- // Emit a lint if there are unstable candidates alongside the stable ones.
- //
- // We suppress warning if we're picking the method only because it is a
- // suggestion.
- self.emit_unstable_name_collision_hint(p, &unstable_candidates);
- }
- }
- return Some(pick);
+ if res.is_some() {
+ return res;
}
}
debug!("searching unstable candidates");
let res = self.consider_candidates(
self_ty,
- unstable_candidates.iter().map(|(c, _)| c),
+ self.inherent_candidates.iter().chain(&self.extension_candidates),
&mut possibly_unsatisfied_predicates,
None,
);
@@ -1302,7 +1280,7 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
Option<ty::Predicate<'tcx>>,
Option<ObligationCause<'tcx>>,
)>,
- unstable_candidates: Option<&mut Vec<(Candidate<'tcx>, Symbol)>>,
+ mut unstable_candidates: Option<&mut Vec<(Candidate<'tcx>, Symbol)>>,
) -> Option<PickResult<'tcx>>
where
ProbesIter: Iterator<Item = &'b Candidate<'tcx>> + Clone,
@@ -1326,7 +1304,7 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
}
}
- if let Some(uc) = unstable_candidates {
+ if let Some(uc) = &mut unstable_candidates {
applicable_candidates.retain(|&(p, _)| {
if let stability::EvalResult::Deny { feature, .. } =
self.tcx.eval_stability(p.item.def_id, None, self.span, None)
@@ -1345,30 +1323,63 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
applicable_candidates.pop().map(|(probe, status)| {
if status == ProbeResult::Match {
- Ok(probe.to_unadjusted_pick(self_ty))
+ Ok(probe
+ .to_unadjusted_pick(self_ty, unstable_candidates.cloned().unwrap_or_default()))
} else {
Err(MethodError::BadReturnType)
}
})
}
+}
+
+impl<'tcx> Pick<'tcx> {
+ /// In case there were unstable name collisions, emit them as a lint.
+ /// Checks whether two picks do not refer to the same trait item for the same `Self` type.
+ /// Only useful for comparisons of picks in order to improve diagnostics.
+ /// Do not use for type checking.
+ pub fn differs_from(&self, other: &Self) -> bool {
+ let Self {
+ item:
+ AssocItem {
+ def_id,
+ name: _,
+ kind: _,
+ container: _,
+ trait_item_def_id: _,
+ fn_has_self_parameter: _,
+ },
+ kind: _,
+ import_ids: _,
+ autoderefs: _,
+ autoref_or_ptr_adjustment: _,
+ self_ty,
+ unstable_candidates: _,
+ } = *self;
+ self_ty != other.self_ty || def_id != other.item.def_id
+ }
- fn emit_unstable_name_collision_hint(
+ /// In case there were unstable name collisions, emit them as a lint.
+ pub fn maybe_emit_unstable_name_collision_hint(
&self,
- stable_pick: &Pick<'_>,
- unstable_candidates: &[(Candidate<'tcx>, Symbol)],
+ tcx: TyCtxt<'tcx>,
+ span: Span,
+ scope_expr_id: hir::HirId,
) {
- let def_kind = stable_pick.item.kind.as_def_kind();
- self.tcx.struct_span_lint_hir(
+ if self.unstable_candidates.is_empty() {
+ return;
+ }
+ let def_kind = self.item.kind.as_def_kind();
+ tcx.struct_span_lint_hir(
lint::builtin::UNSTABLE_NAME_COLLISIONS,
- self.scope_expr_id,
- self.span,
+ scope_expr_id,
+ span,
format!(
"{} {} with this name may be added to the standard library in the future",
def_kind.article(),
- def_kind.descr(stable_pick.item.def_id),
+ def_kind.descr(self.item.def_id),
),
|lint| {
- match (stable_pick.item.kind, stable_pick.item.container) {
+ match (self.item.kind, self.item.container) {
(ty::AssocKind::Fn, _) => {
// FIXME: This should be a `span_suggestion` instead of `help`
// However `self.span` only
@@ -1377,31 +1388,31 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
lint.help(&format!(
"call with fully qualified syntax `{}(...)` to keep using the current \
method",
- self.tcx.def_path_str(stable_pick.item.def_id),
+ tcx.def_path_str(self.item.def_id),
));
}
(ty::AssocKind::Const, ty::AssocItemContainer::TraitContainer) => {
- let def_id = stable_pick.item.container_id(self.tcx);
+ let def_id = self.item.container_id(tcx);
lint.span_suggestion(
- self.span,
+ span,
"use the fully qualified path to the associated const",
format!(
"<{} as {}>::{}",
- stable_pick.self_ty,
- self.tcx.def_path_str(def_id),
- stable_pick.item.name
+ self.self_ty,
+ tcx.def_path_str(def_id),
+ self.item.name
),
Applicability::MachineApplicable,
);
}
_ => {}
}
- if self.tcx.sess.is_nightly_build() {
- for (candidate, feature) in unstable_candidates {
+ if tcx.sess.is_nightly_build() {
+ for (candidate, feature) in &self.unstable_candidates {
lint.help(&format!(
"add `#![feature({})]` to the crate attributes to enable `{}`",
feature,
- self.tcx.def_path_str(candidate.item.def_id),
+ tcx.def_path_str(candidate.item.def_id),
));
}
}
@@ -1410,14 +1421,16 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
},
);
}
+}
+impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
fn select_trait_candidate(
&self,
trait_ref: ty::TraitRef<'tcx>,
) -> traits::SelectionResult<'tcx, traits::Selection<'tcx>> {
let cause = traits::ObligationCause::misc(self.span, self.body_id);
- let predicate = ty::Binder::dummy(trait_ref).to_poly_trait_predicate();
- let obligation = traits::Obligation::new(cause, self.param_env, predicate);
+ let predicate = ty::Binder::dummy(trait_ref);
+ let obligation = traits::Obligation::new(self.tcx, cause, self.param_env, predicate);
traits::SelectionContext::new(self).select(&obligation)
}
@@ -1476,7 +1489,6 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
let mut xform_ret_ty = probe.xform_ret_ty;
debug!(?xform_ret_ty);
- let selcx = &mut traits::SelectionContext::new(self);
let cause = traits::ObligationCause::misc(self.span, self.body_id);
let mut parent_pred = None;
@@ -1490,10 +1502,10 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
// `xform_ret_ty` hasn't been normalized yet, only `xform_self_ty`,
// see the reasons mentioned in the comments in `assemble_inherent_impl_probe`
// for why this is necessary
- let traits::Normalized {
+ let InferOk {
value: normalized_xform_ret_ty,
obligations: normalization_obligations,
- } = traits::normalize(selcx, self.param_env, cause.clone(), probe.xform_ret_ty);
+ } = self.fcx.at(&cause, self.param_env).normalize(probe.xform_ret_ty);
xform_ret_ty = normalized_xform_ret_ty;
debug!("xform_ret_ty after normalization: {:?}", xform_ret_ty);
@@ -1501,8 +1513,9 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
let impl_def_id = probe.item.container_id(self.tcx);
let impl_bounds = self.tcx.predicates_of(impl_def_id);
let impl_bounds = impl_bounds.instantiate(self.tcx, substs);
- let traits::Normalized { value: impl_bounds, obligations: norm_obligations } =
- traits::normalize(selcx, self.param_env, cause.clone(), impl_bounds);
+
+ let InferOk { value: impl_bounds, obligations: norm_obligations } =
+ self.fcx.at(&cause, self.param_env).normalize(impl_bounds);
// Convert the bounds into obligations.
let impl_obligations = traits::predicates_for_generics(
@@ -1548,7 +1561,8 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
let predicate =
ty::Binder::dummy(trait_ref).without_const().to_predicate(self.tcx);
parent_pred = Some(predicate);
- let obligation = traits::Obligation::new(cause, self.param_env, predicate);
+ let obligation =
+ traits::Obligation::new(self.tcx, cause, self.param_env, predicate);
if !self.predicate_may_hold(&obligation) {
result = ProbeResult::NoMatch;
if self.probe(|_| {
@@ -1669,6 +1683,7 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
autoderefs: 0,
autoref_or_ptr_adjustment: None,
self_ty,
+ unstable_candidates: vec![],
})
}
@@ -1688,7 +1703,6 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
self.return_type,
self.orig_steps_var_values.clone(),
steps,
- IsSuggestion(true),
self.scope_expr_id,
);
pcx.allow_similar_names = true;
@@ -1861,6 +1875,15 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
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
@@ -1873,7 +1896,7 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
.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)
@@ -1887,16 +1910,26 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
} 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()
}
}
}
impl<'tcx> Candidate<'tcx> {
- fn to_unadjusted_pick(&self, self_ty: Ty<'tcx>) -> Pick<'tcx> {
+ fn to_unadjusted_pick(
+ &self,
+ self_ty: Ty<'tcx>,
+ unstable_candidates: Vec<(Candidate<'tcx>, Symbol)>,
+ ) -> Pick<'tcx> {
Pick {
item: self.item,
kind: match self.kind {
@@ -1921,6 +1954,7 @@ impl<'tcx> Candidate<'tcx> {
autoderefs: 0,
autoref_or_ptr_adjustment: None,
self_ty,
+ unstable_candidates,
}
}
}