| //! Candidate assembly and selection in method resolution - where we enumerate all candidates |
| //! and choose the best one (or, in some IDE scenarios, just enumerate them all). |
| |
| use std::{cell::RefCell, convert::Infallible, ops::ControlFlow}; |
| |
| use hir_def::{ |
| AssocItemId, FunctionId, GenericParamId, ImplId, ItemContainerId, TraitId, |
| signatures::TraitFlags, |
| }; |
| use hir_expand::name::Name; |
| use rustc_ast_ir::Mutability; |
| use rustc_hash::{FxHashMap, FxHashSet}; |
| use rustc_type_ir::{ |
| InferTy, TypeVisitableExt, Upcast, Variance, |
| elaborate::{self, supertrait_def_ids}, |
| fast_reject::{DeepRejectCtxt, TreatParams, simplify_type}, |
| inherent::{AdtDef as _, BoundExistentialPredicates as _, IntoKind, SliceLike, Ty as _}, |
| }; |
| use smallvec::{SmallVec, smallvec}; |
| use tracing::{debug, instrument}; |
| |
| use self::CandidateKind::*; |
| pub(super) use self::PickKind::*; |
| use crate::{ |
| autoderef::Autoderef, |
| db::HirDatabase, |
| lower::GenericPredicates, |
| method_resolution::{ |
| CandidateId, CandidateSource, InherentImpls, MethodError, MethodResolutionContext, |
| incoherent_inherent_impls, simplified_type_module, |
| }, |
| next_solver::{ |
| Binder, Canonical, ClauseKind, DbInterner, FnSig, GenericArg, GenericArgs, Goal, ParamEnv, |
| PolyTraitRef, Predicate, Region, SimplifiedType, TraitRef, Ty, TyKind, |
| infer::{ |
| BoundRegionConversionTime, InferCtxt, InferOk, |
| canonical::{QueryResponse, canonicalizer::OriginalQueryValues}, |
| select::{ImplSource, Selection, SelectionResult}, |
| traits::{Obligation, ObligationCause, PredicateObligation}, |
| }, |
| obligation_ctxt::ObligationCtxt, |
| util::clauses_as_obligations, |
| }, |
| }; |
| |
| struct ProbeContext<'a, 'db, Choice> { |
| ctx: &'a MethodResolutionContext<'a, 'db>, |
| mode: Mode, |
| |
| /// This is the OriginalQueryValues for the steps queries |
| /// that are answered in steps. |
| orig_steps_var_values: &'a OriginalQueryValues<'db>, |
| steps: &'a [CandidateStep<'db>], |
| |
| inherent_candidates: Vec<Candidate<'db>>, |
| extension_candidates: Vec<Candidate<'db>>, |
| impl_dups: FxHashSet<ImplId>, |
| |
| /// List of potential private candidates. Will be trimmed to ones that |
| /// actually apply and then the result inserted into `private_candidate` |
| private_candidates: Vec<Candidate<'db>>, |
| |
| /// Collects near misses when the candidate functions are missing a `self` keyword and is only |
| /// used for error reporting |
| static_candidates: Vec<CandidateSource>, |
| |
| choice: Choice, |
| } |
| |
| #[derive(Debug)] |
| pub struct CandidateWithPrivate<'db> { |
| pub candidate: Candidate<'db>, |
| pub is_visible: bool, |
| } |
| |
| #[derive(Debug, Clone)] |
| pub struct Candidate<'db> { |
| pub item: CandidateId, |
| pub kind: CandidateKind<'db>, |
| } |
| |
| #[derive(Debug, Clone)] |
| pub enum CandidateKind<'db> { |
| InherentImplCandidate { impl_def_id: ImplId, receiver_steps: usize }, |
| ObjectCandidate(PolyTraitRef<'db>), |
| TraitCandidate(PolyTraitRef<'db>), |
| WhereClauseCandidate(PolyTraitRef<'db>), |
| } |
| |
| #[derive(Debug, PartialEq, Eq, Copy, Clone)] |
| enum ProbeResult { |
| NoMatch, |
| Match, |
| } |
| |
| /// When adjusting a receiver we often want to do one of |
| /// |
| /// - Add a `&` (or `&mut`), converting the receiver from `T` to `&T` (or `&mut T`) |
| /// - If the receiver has type `*mut T`, convert it to `*const T` |
| /// |
| /// This type tells us which one to do. |
| /// |
| /// Note that in principle we could do both at the same time. For example, when the receiver has |
| /// type `T`, we could autoref it to `&T`, then convert to `*const T`. Or, when it has type `*mut |
| /// T`, we could convert it to `*const T`, then autoref to `&*const T`. However, currently we do |
| /// (at most) one of these. Either the receiver has type `T` and we convert it to `&T` (or with |
| /// `mut`), or it has type `*mut T` and we convert it to `*const T`. |
| #[derive(Debug, PartialEq, Copy, Clone)] |
| pub enum AutorefOrPtrAdjustment { |
| /// Receiver has type `T`, add `&` or `&mut` (if `T` is `mut`), and maybe also "unsize" it. |
| /// Unsizing is used to convert a `[T; N]` to `[T]`, which only makes sense when autorefing. |
| Autoref { |
| mutbl: Mutability, |
| |
| /// Indicates that the source expression should be "unsized" to a target type. |
| /// This is special-cased for just arrays unsizing to slices. |
| unsize: bool, |
| }, |
| /// Receiver has type `*mut T`, convert to `*const T` |
| ToConstPtr, |
| } |
| |
| impl AutorefOrPtrAdjustment { |
| fn get_unsize(&self) -> bool { |
| match self { |
| AutorefOrPtrAdjustment::Autoref { mutbl: _, unsize } => *unsize, |
| AutorefOrPtrAdjustment::ToConstPtr => false, |
| } |
| } |
| } |
| |
| /// Criteria to apply when searching for a given Pick. This is used during |
| /// the search for potentially shadowed methods to ensure we don't search |
| /// more candidates than strictly necessary. |
| #[derive(Debug)] |
| struct PickConstraintsForShadowed { |
| autoderefs: usize, |
| receiver_steps: Option<usize>, |
| def_id: CandidateId, |
| } |
| |
| impl PickConstraintsForShadowed { |
| fn may_shadow_based_on_autoderefs(&self, autoderefs: usize) -> bool { |
| autoderefs == self.autoderefs |
| } |
| |
| fn candidate_may_shadow(&self, candidate: &Candidate<'_>) -> bool { |
| // An item never shadows itself |
| candidate.item != self.def_id |
| // and we're only concerned about inherent impls doing the shadowing. |
| // Shadowing can only occur if the shadowed is further along |
| // the Receiver dereferencing chain than the shadowed. |
| && match candidate.kind { |
| CandidateKind::InherentImplCandidate { receiver_steps, .. } => match self.receiver_steps { |
| Some(shadowed_receiver_steps) => receiver_steps > shadowed_receiver_steps, |
| _ => false |
| }, |
| _ => false |
| } |
| } |
| } |
| |
| #[derive(Debug, Clone)] |
| pub struct Pick<'db> { |
| pub item: CandidateId, |
| pub kind: PickKind<'db>, |
| |
| /// Indicates that the source expression should be autoderef'd N times |
| /// ```ignore (not-rust) |
| /// A = expr | *expr | **expr | ... |
| /// ``` |
| pub autoderefs: usize, |
| |
| /// Indicates that we want to add an autoref (and maybe also unsize it), or if the receiver is |
| /// `*mut T`, convert it to `*const T`. |
| pub autoref_or_ptr_adjustment: Option<AutorefOrPtrAdjustment>, |
| pub self_ty: Ty<'db>, |
| |
| /// Number of jumps along the `Receiver::Target` chain we followed |
| /// to identify this method. Used only for deshadowing errors. |
| /// Only applies for inherent impls. |
| pub receiver_steps: Option<usize>, |
| |
| /// Candidates that were shadowed by supertraits. |
| pub shadowed_candidates: Vec<CandidateId>, |
| } |
| |
| #[derive(Clone, Debug, PartialEq, Eq)] |
| pub enum PickKind<'db> { |
| InherentImplPick(ImplId), |
| ObjectPick(TraitId), |
| TraitPick(TraitId), |
| WhereClausePick( |
| // Trait |
| PolyTraitRef<'db>, |
| ), |
| } |
| |
| pub(crate) type PickResult<'db> = Result<Pick<'db>, MethodError<'db>>; |
| |
| #[derive(PartialEq, Eq, Copy, Clone, Debug)] |
| pub enum Mode { |
| // An expression of the form `receiver.method_name(...)`. |
| // Autoderefs are performed on `receiver`, lookup is done based on the |
| // `self` argument of the method, and static methods aren't considered. |
| MethodCall, |
| // An expression of the form `Type::item` or `<T>::item`. |
| // No autoderefs are performed, lookup is done based on the type each |
| // implementation is for, and static methods are included. |
| Path, |
| } |
| |
| #[derive(Debug, Clone)] |
| pub struct CandidateStep<'db> { |
| pub self_ty: Canonical<'db, QueryResponse<'db, Ty<'db>>>, |
| pub self_ty_is_opaque: bool, |
| pub autoderefs: usize, |
| /// `true` if the type results from a dereference of a raw pointer. |
| /// when assembling candidates, we include these steps, but not when |
| /// picking methods. This so that if we have `foo: *const Foo` and `Foo` has methods |
| /// `fn by_raw_ptr(self: *const Self)` and `fn by_ref(&self)`, then |
| /// `foo.by_raw_ptr()` will work and `foo.by_ref()` won't. |
| pub from_unsafe_deref: bool, |
| pub unsize: bool, |
| /// We will generate CandidateSteps which are reachable via a chain |
| /// of following `Receiver`. The first 'n' of those will be reachable |
| /// by following a chain of 'Deref' instead (since there's a blanket |
| /// implementation of Receiver for Deref). |
| /// We use the entire set of steps when identifying method candidates |
| /// (e.g. identifying relevant `impl` blocks) but only those that are |
| /// reachable via Deref when examining what the receiver type can |
| /// be converted into by autodereffing. |
| pub reachable_via_deref: bool, |
| } |
| |
| #[derive(Clone, Debug)] |
| struct MethodAutoderefStepsResult<'db> { |
| /// The valid autoderef steps that could be found by following a chain |
| /// of `Receiver<Target=T>` or `Deref<Target=T>` trait implementations. |
| pub steps: SmallVec<[CandidateStep<'db>; 3]>, |
| /// If Some(T), a type autoderef reported an error on. |
| pub opt_bad_ty: Option<MethodAutoderefBadTy<'db>>, |
| /// If `true`, `steps` has been truncated due to reaching the |
| /// recursion limit. |
| pub reached_recursion_limit: bool, |
| } |
| |
| #[derive(Debug, Clone)] |
| struct MethodAutoderefBadTy<'db> { |
| pub reached_raw_pointer: bool, |
| pub ty: Canonical<'db, QueryResponse<'db, Ty<'db>>>, |
| } |
| |
| impl<'a, 'db> MethodResolutionContext<'a, 'db> { |
| #[instrument(level = "debug", skip(self))] |
| pub fn probe_for_name(&self, mode: Mode, item_name: Name, self_ty: Ty<'db>) -> PickResult<'db> { |
| self.probe_op(mode, self_ty, ProbeForNameChoice { private_candidate: None, item_name }) |
| } |
| |
| #[instrument(level = "debug", skip(self))] |
| pub fn probe_all( |
| &self, |
| mode: Mode, |
| self_ty: Ty<'db>, |
| ) -> impl Iterator<Item = CandidateWithPrivate<'db>> { |
| self.probe_op(mode, self_ty, ProbeAllChoice::new()).candidates.into_inner().into_values() |
| } |
| |
| fn probe_op<Choice: ProbeChoice<'db>>( |
| &self, |
| mode: Mode, |
| self_ty: Ty<'db>, |
| choice: Choice, |
| ) -> Choice::FinalChoice { |
| let mut orig_values = OriginalQueryValues::default(); |
| let query_input = self.infcx.canonicalize_query(self_ty, &mut orig_values); |
| let steps = match mode { |
| Mode::MethodCall => self.method_autoderef_steps(&query_input), |
| Mode::Path => self.infcx.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 |
| // special handling for this "trivial case" is a good idea. |
| |
| let infcx = self.infcx; |
| let (self_ty, var_values) = infcx.instantiate_canonical(&query_input); |
| debug!(?self_ty, ?query_input, "probe_op: Mode::Path"); |
| MethodAutoderefStepsResult { |
| steps: smallvec![CandidateStep { |
| self_ty: self |
| .infcx |
| .make_query_response_ignoring_pending_obligations(var_values, self_ty), |
| self_ty_is_opaque: false, |
| autoderefs: 0, |
| from_unsafe_deref: false, |
| unsize: false, |
| reachable_via_deref: true, |
| }], |
| opt_bad_ty: None, |
| reached_recursion_limit: false, |
| } |
| }), |
| }; |
| |
| if steps.reached_recursion_limit { |
| // FIXME: Report an error. |
| } |
| |
| // If we encountered an `_` type or an error type during autoderef, this is |
| // ambiguous. |
| if let Some(bad_ty) = &steps.opt_bad_ty { |
| if bad_ty.reached_raw_pointer |
| && !self.unstable_features.arbitrary_self_types_pointers |
| && self.edition.at_least_2018() |
| { |
| // this case used to be allowed by the compiler, |
| // so we do a future-compat lint here for the 2015 edition |
| // (see https://github.com/rust-lang/rust/issues/46906) |
| // FIXME: Emit the lint. |
| // self.tcx.node_span_lint( |
| // lint::builtin::TYVAR_BEHIND_RAW_POINTER, |
| // scope_expr_id, |
| // span, |
| // |lint| { |
| // lint.primary_message("type annotations needed"); |
| // }, |
| // ); |
| } else { |
| // Ended up encountering a type variable when doing autoderef, |
| // but it may not be a type variable after processing obligations |
| // in our local `FnCtxt`, so don't call `structurally_resolve_type`. |
| let ty = &bad_ty.ty; |
| let ty = self |
| .infcx |
| .instantiate_query_response_and_region_obligations( |
| &ObligationCause::new(), |
| self.env.env, |
| &orig_values, |
| ty, |
| ) |
| .unwrap_or_else(|_| panic!("instantiating {:?} failed?", ty)); |
| let ty = self.infcx.resolve_vars_if_possible(ty.value); |
| match ty.kind() { |
| TyKind::Infer(InferTy::TyVar(_)) => { |
| // FIXME: Report "type annotations needed" error. |
| } |
| TyKind::Error(_) => {} |
| _ => panic!("unexpected bad final type in method autoderef"), |
| }; |
| return Choice::final_choice_from_err(MethodError::ErrorReported); |
| } |
| } |
| |
| debug!("ProbeContext: steps for self_ty={:?} are {:?}", self_ty, steps); |
| |
| // this creates one big transaction so that all type variables etc |
| // that we create during the probe process are removed later |
| self.infcx.probe(|_| { |
| let mut probe_cx = ProbeContext::new(self, mode, &orig_values, &steps.steps, choice); |
| |
| probe_cx.assemble_inherent_candidates(); |
| probe_cx.assemble_extension_candidates_for_traits_in_scope(); |
| Choice::choose(probe_cx) |
| }) |
| } |
| |
| fn method_autoderef_steps( |
| &self, |
| self_ty: &Canonical<'db, Ty<'db>>, |
| ) -> MethodAutoderefStepsResult<'db> { |
| self.infcx.probe(|_| { |
| debug!("method_autoderef_steps({:?})", self_ty); |
| |
| // We accept not-yet-defined opaque types in the autoderef |
| // chain to support recursive calls. We do error if the final |
| // infer var is not an opaque. |
| let infcx = self.infcx; |
| let (self_ty, inference_vars) = infcx.instantiate_canonical(self_ty); |
| let self_ty_is_opaque = |ty: Ty<'_>| { |
| if let TyKind::Infer(InferTy::TyVar(vid)) = ty.kind() { |
| infcx.has_opaques_with_sub_unified_hidden_type(vid) |
| } else { |
| false |
| } |
| }; |
| |
| // If arbitrary self types is not enabled, we follow the chain of |
| // `Deref<Target=T>`. If arbitrary self types is enabled, we instead |
| // follow the chain of `Receiver<Target=T>`, but we also record whether |
| // such types are reachable by following the (potentially shorter) |
| // chain of `Deref<Target=T>`. We will use the first list when finding |
| // potentially relevant function implementations (e.g. relevant impl blocks) |
| // but the second list when determining types that the receiver may be |
| // converted to, in order to find out which of those methods might actually |
| // be callable. |
| let mut autoderef_via_deref = |
| Autoderef::new(infcx, self.env, self_ty).include_raw_pointers(); |
| |
| let mut reached_raw_pointer = false; |
| let arbitrary_self_types_enabled = self.unstable_features.arbitrary_self_types |
| || self.unstable_features.arbitrary_self_types_pointers; |
| let (mut steps, reached_recursion_limit) = if arbitrary_self_types_enabled { |
| let reachable_via_deref = |
| autoderef_via_deref.by_ref().map(|_| true).chain(std::iter::repeat(false)); |
| |
| let mut autoderef_via_receiver = Autoderef::new(infcx, self.env, self_ty) |
| .include_raw_pointers() |
| .use_receiver_trait(); |
| let steps = autoderef_via_receiver |
| .by_ref() |
| .zip(reachable_via_deref) |
| .map(|((ty, d), reachable_via_deref)| { |
| let step = CandidateStep { |
| self_ty: infcx.make_query_response_ignoring_pending_obligations( |
| inference_vars, |
| ty, |
| ), |
| self_ty_is_opaque: self_ty_is_opaque(ty), |
| autoderefs: d, |
| from_unsafe_deref: reached_raw_pointer, |
| unsize: false, |
| reachable_via_deref, |
| }; |
| if ty.is_raw_ptr() { |
| // all the subsequent steps will be from_unsafe_deref |
| reached_raw_pointer = true; |
| } |
| step |
| }) |
| .collect::<SmallVec<[_; _]>>(); |
| (steps, autoderef_via_receiver.reached_recursion_limit()) |
| } else { |
| let steps = autoderef_via_deref |
| .by_ref() |
| .map(|(ty, d)| { |
| let step = CandidateStep { |
| self_ty: infcx.make_query_response_ignoring_pending_obligations( |
| inference_vars, |
| ty, |
| ), |
| self_ty_is_opaque: self_ty_is_opaque(ty), |
| autoderefs: d, |
| from_unsafe_deref: reached_raw_pointer, |
| unsize: false, |
| reachable_via_deref: true, |
| }; |
| if ty.is_raw_ptr() { |
| // all the subsequent steps will be from_unsafe_deref |
| reached_raw_pointer = true; |
| } |
| step |
| }) |
| .collect(); |
| (steps, autoderef_via_deref.reached_recursion_limit()) |
| }; |
| let final_ty = autoderef_via_deref.final_ty(); |
| let opt_bad_ty = match final_ty.kind() { |
| TyKind::Infer(InferTy::TyVar(_)) if !self_ty_is_opaque(final_ty) => { |
| Some(MethodAutoderefBadTy { |
| reached_raw_pointer, |
| ty: infcx.make_query_response_ignoring_pending_obligations( |
| inference_vars, |
| final_ty, |
| ), |
| }) |
| } |
| TyKind::Error(_) => Some(MethodAutoderefBadTy { |
| reached_raw_pointer, |
| ty: infcx |
| .make_query_response_ignoring_pending_obligations(inference_vars, final_ty), |
| }), |
| TyKind::Array(elem_ty, _) => { |
| let autoderefs = steps.iter().filter(|s| s.reachable_via_deref).count() - 1; |
| steps.push(CandidateStep { |
| self_ty: infcx.make_query_response_ignoring_pending_obligations( |
| inference_vars, |
| Ty::new_slice(infcx.interner, elem_ty), |
| ), |
| self_ty_is_opaque: false, |
| autoderefs, |
| // this could be from an unsafe deref if we had |
| // a *mut/const [T; N] |
| from_unsafe_deref: reached_raw_pointer, |
| unsize: true, |
| reachable_via_deref: true, // this is always the final type from |
| // autoderef_via_deref |
| }); |
| |
| None |
| } |
| _ => None, |
| }; |
| |
| debug!("method_autoderef_steps: steps={:?} opt_bad_ty={:?}", steps, opt_bad_ty); |
| MethodAutoderefStepsResult { steps, opt_bad_ty, reached_recursion_limit } |
| }) |
| } |
| } |
| |
| trait ProbeChoice<'db>: Sized { |
| type Choice; |
| type FinalChoice; |
| |
| /// Finds the method with the appropriate name (or return type, as the case may be). |
| // The length of the returned iterator is nearly always 0 or 1 and this |
| // method is fairly hot. |
| fn with_impl_or_trait_item<'a>( |
| this: &mut ProbeContext<'a, 'db, Self>, |
| items: &[(Name, AssocItemId)], |
| callback: impl FnMut(&mut ProbeContext<'a, 'db, Self>, CandidateId), |
| ); |
| |
| fn consider_candidates( |
| this: &ProbeContext<'_, 'db, Self>, |
| self_ty: Ty<'db>, |
| candidates: Vec<&Candidate<'db>>, |
| ) -> ControlFlow<Self::Choice>; |
| |
| fn consider_private_candidates( |
| this: &mut ProbeContext<'_, 'db, Self>, |
| self_ty: Ty<'db>, |
| instantiate_self_ty_obligations: &[PredicateObligation<'db>], |
| ); |
| |
| fn map_choice_pick( |
| choice: Self::Choice, |
| f: impl FnOnce(Pick<'db>) -> Pick<'db>, |
| ) -> Self::Choice; |
| |
| fn check_by_value_method_shadowing( |
| this: &mut ProbeContext<'_, 'db, Self>, |
| by_value_pick: &Self::Choice, |
| step: &CandidateStep<'db>, |
| self_ty: Ty<'db>, |
| instantiate_self_ty_obligations: &[PredicateObligation<'db>], |
| ) -> ControlFlow<Self::Choice>; |
| |
| fn check_autorefed_method_shadowing( |
| this: &mut ProbeContext<'_, 'db, Self>, |
| autoref_pick: &Self::Choice, |
| step: &CandidateStep<'db>, |
| self_ty: Ty<'db>, |
| instantiate_self_ty_obligations: &[PredicateObligation<'db>], |
| ) -> ControlFlow<Self::Choice>; |
| |
| fn final_choice_from_err(err: MethodError<'db>) -> Self::FinalChoice; |
| |
| fn choose(this: ProbeContext<'_, 'db, Self>) -> Self::FinalChoice; |
| } |
| |
| #[derive(Debug)] |
| struct ProbeForNameChoice<'db> { |
| item_name: Name, |
| |
| /// Some(candidate) if there is a private candidate |
| private_candidate: Option<Pick<'db>>, |
| } |
| |
| impl<'db> ProbeChoice<'db> for ProbeForNameChoice<'db> { |
| type Choice = PickResult<'db>; |
| type FinalChoice = PickResult<'db>; |
| |
| fn with_impl_or_trait_item<'a>( |
| this: &mut ProbeContext<'a, 'db, Self>, |
| items: &[(Name, AssocItemId)], |
| mut callback: impl FnMut(&mut ProbeContext<'a, 'db, Self>, CandidateId), |
| ) { |
| let item = items |
| .iter() |
| .filter_map(|(name, id)| { |
| let id = match *id { |
| AssocItemId::FunctionId(id) => id.into(), |
| AssocItemId::ConstId(id) => id.into(), |
| AssocItemId::TypeAliasId(_) => return None, |
| }; |
| Some((name, id)) |
| }) |
| .find(|(name, _)| **name == this.choice.item_name) |
| .map(|(_, id)| id) |
| .filter(|id| this.mode == Mode::Path || matches!(id, CandidateId::FunctionId(_))); |
| if let Some(item) = item { |
| callback(this, item); |
| } |
| } |
| |
| fn consider_candidates( |
| this: &ProbeContext<'_, 'db, Self>, |
| self_ty: Ty<'db>, |
| mut applicable_candidates: Vec<&Candidate<'db>>, |
| ) -> ControlFlow<Self::Choice> { |
| if applicable_candidates.len() > 1 |
| && let Some(pick) = |
| this.collapse_candidates_to_trait_pick(self_ty, &applicable_candidates) |
| { |
| return ControlFlow::Break(Ok(pick)); |
| } |
| |
| if applicable_candidates.len() > 1 { |
| // We collapse to a subtrait pick *after* filtering unstable candidates |
| // to make sure we don't prefer a unstable subtrait method over a stable |
| // supertrait method. |
| if this.ctx.unstable_features.supertrait_item_shadowing |
| && let Some(pick) = |
| this.collapse_candidates_to_subtrait_pick(self_ty, &applicable_candidates) |
| { |
| return ControlFlow::Break(Ok(pick)); |
| } |
| |
| let sources = |
| applicable_candidates.iter().map(|p| this.candidate_source(p, self_ty)).collect(); |
| return ControlFlow::Break(Err(MethodError::Ambiguity(sources))); |
| } |
| |
| match applicable_candidates.pop() { |
| Some(probe) => ControlFlow::Break(Ok(probe.to_unadjusted_pick(self_ty))), |
| None => ControlFlow::Continue(()), |
| } |
| } |
| |
| fn consider_private_candidates( |
| this: &mut ProbeContext<'_, 'db, Self>, |
| self_ty: Ty<'db>, |
| instantiate_self_ty_obligations: &[PredicateObligation<'db>], |
| ) { |
| if this.choice.private_candidate.is_none() |
| && let ControlFlow::Break(Ok(pick)) = this.consider_candidates( |
| self_ty, |
| instantiate_self_ty_obligations, |
| &this.private_candidates, |
| None, |
| ) |
| { |
| this.choice.private_candidate = Some(pick); |
| } |
| } |
| |
| fn map_choice_pick( |
| choice: Self::Choice, |
| f: impl FnOnce(Pick<'db>) -> Pick<'db>, |
| ) -> Self::Choice { |
| choice.map(f) |
| } |
| |
| fn check_by_value_method_shadowing( |
| this: &mut ProbeContext<'_, 'db, Self>, |
| by_value_pick: &Self::Choice, |
| step: &CandidateStep<'db>, |
| self_ty: Ty<'db>, |
| instantiate_self_ty_obligations: &[PredicateObligation<'db>], |
| ) -> ControlFlow<Self::Choice> { |
| if let Ok(by_value_pick) = by_value_pick |
| && matches!(by_value_pick.kind, PickKind::InherentImplPick(_)) |
| { |
| for mutbl in [Mutability::Not, Mutability::Mut] { |
| if let Err(e) = this.check_for_shadowed_autorefd_method( |
| by_value_pick, |
| step, |
| self_ty, |
| instantiate_self_ty_obligations, |
| mutbl, |
| ) { |
| return ControlFlow::Break(Err(e)); |
| } |
| } |
| } |
| ControlFlow::Continue(()) |
| } |
| |
| fn check_autorefed_method_shadowing( |
| this: &mut ProbeContext<'_, 'db, Self>, |
| autoref_pick: &Self::Choice, |
| step: &CandidateStep<'db>, |
| self_ty: Ty<'db>, |
| instantiate_self_ty_obligations: &[PredicateObligation<'db>], |
| ) -> ControlFlow<Self::Choice> { |
| if let Ok(autoref_pick) = autoref_pick.as_ref() { |
| // Check we're not shadowing others |
| if matches!(autoref_pick.kind, PickKind::InherentImplPick(_)) |
| && let Err(e) = this.check_for_shadowed_autorefd_method( |
| autoref_pick, |
| step, |
| self_ty, |
| instantiate_self_ty_obligations, |
| Mutability::Mut, |
| ) |
| { |
| return ControlFlow::Break(Err(e)); |
| } |
| } |
| ControlFlow::Continue(()) |
| } |
| |
| fn final_choice_from_err(err: MethodError<'db>) -> Self::FinalChoice { |
| Err(err) |
| } |
| |
| fn choose(this: ProbeContext<'_, 'db, Self>) -> Self::FinalChoice { |
| this.pick() |
| } |
| } |
| |
| #[derive(Debug)] |
| struct ProbeAllChoice<'db> { |
| candidates: RefCell<FxHashMap<CandidateId, CandidateWithPrivate<'db>>>, |
| considering_visible_candidates: bool, |
| } |
| |
| impl ProbeAllChoice<'_> { |
| fn new() -> Self { |
| Self { candidates: RefCell::default(), considering_visible_candidates: true } |
| } |
| } |
| |
| impl<'db> ProbeChoice<'db> for ProbeAllChoice<'db> { |
| type Choice = Infallible; |
| type FinalChoice = Self; |
| |
| fn with_impl_or_trait_item<'a>( |
| this: &mut ProbeContext<'a, 'db, Self>, |
| items: &[(Name, AssocItemId)], |
| mut callback: impl FnMut(&mut ProbeContext<'a, 'db, Self>, CandidateId), |
| ) { |
| let mode = this.mode; |
| items |
| .iter() |
| .filter_map(|(_, id)| is_relevant_kind_for_mode(mode, *id)) |
| .for_each(|id| callback(this, id)); |
| } |
| |
| fn consider_candidates( |
| this: &ProbeContext<'_, 'db, Self>, |
| _self_ty: Ty<'db>, |
| candidates: Vec<&Candidate<'db>>, |
| ) -> ControlFlow<Self::Choice> { |
| let is_visible = this.choice.considering_visible_candidates; |
| let mut all_candidates = this.choice.candidates.borrow_mut(); |
| for candidate in candidates { |
| // We should not override existing entries, because inherent methods of trait objects (from the principal) |
| // are also visited as trait methods, and we want to consider them inherent. |
| all_candidates |
| .entry(candidate.item) |
| .or_insert(CandidateWithPrivate { candidate: candidate.clone(), is_visible }); |
| } |
| ControlFlow::Continue(()) |
| } |
| |
| fn consider_private_candidates( |
| this: &mut ProbeContext<'_, 'db, Self>, |
| self_ty: Ty<'db>, |
| instantiate_self_ty_obligations: &[PredicateObligation<'db>], |
| ) { |
| this.choice.considering_visible_candidates = false; |
| let ControlFlow::Continue(()) = this.consider_candidates( |
| self_ty, |
| instantiate_self_ty_obligations, |
| &this.private_candidates, |
| None, |
| ); |
| this.choice.considering_visible_candidates = true; |
| } |
| |
| fn map_choice_pick( |
| choice: Self::Choice, |
| _f: impl FnOnce(Pick<'db>) -> Pick<'db>, |
| ) -> Self::Choice { |
| choice |
| } |
| |
| fn check_by_value_method_shadowing( |
| _this: &mut ProbeContext<'_, 'db, Self>, |
| _by_value_pick: &Self::Choice, |
| _step: &CandidateStep<'db>, |
| _self_ty: Ty<'db>, |
| _instantiate_self_ty_obligations: &[PredicateObligation<'db>], |
| ) -> ControlFlow<Self::Choice> { |
| ControlFlow::Continue(()) |
| } |
| |
| fn check_autorefed_method_shadowing( |
| _this: &mut ProbeContext<'_, 'db, Self>, |
| _autoref_pick: &Self::Choice, |
| _step: &CandidateStep<'db>, |
| _self_ty: Ty<'db>, |
| _instantiate_self_ty_obligations: &[PredicateObligation<'db>], |
| ) -> ControlFlow<Self::Choice> { |
| ControlFlow::Continue(()) |
| } |
| |
| fn final_choice_from_err(_err: MethodError<'db>) -> Self::FinalChoice { |
| Self::new() |
| } |
| |
| fn choose(mut this: ProbeContext<'_, 'db, Self>) -> Self::FinalChoice { |
| let ControlFlow::Continue(()) = this.pick_all_method(); |
| this.choice |
| } |
| } |
| |
| impl<'a, 'db, Choice: ProbeChoice<'db>> ProbeContext<'a, 'db, Choice> { |
| fn new( |
| ctx: &'a MethodResolutionContext<'a, 'db>, |
| mode: Mode, |
| orig_steps_var_values: &'a OriginalQueryValues<'db>, |
| steps: &'a [CandidateStep<'db>], |
| choice: Choice, |
| ) -> ProbeContext<'a, 'db, Choice> { |
| ProbeContext { |
| ctx, |
| mode, |
| inherent_candidates: Vec::new(), |
| extension_candidates: Vec::new(), |
| impl_dups: FxHashSet::default(), |
| orig_steps_var_values, |
| steps, |
| private_candidates: Vec::new(), |
| static_candidates: Vec::new(), |
| choice, |
| } |
| } |
| |
| #[inline] |
| fn db(&self) -> &'db dyn HirDatabase { |
| self.ctx.infcx.interner.db |
| } |
| |
| #[inline] |
| fn interner(&self) -> DbInterner<'db> { |
| self.ctx.infcx.interner |
| } |
| |
| #[inline] |
| fn infcx(&self) -> &'a InferCtxt<'db> { |
| self.ctx.infcx |
| } |
| |
| #[inline] |
| fn param_env(&self) -> ParamEnv<'db> { |
| self.ctx.env.env |
| } |
| |
| /// When we're looking up a method by path (UFCS), we relate the receiver |
| /// types invariantly. When we are looking up a method by the `.` operator, |
| /// we relate them covariantly. |
| fn variance(&self) -> Variance { |
| match self.mode { |
| Mode::MethodCall => Variance::Covariant, |
| Mode::Path => Variance::Invariant, |
| } |
| } |
| |
| /////////////////////////////////////////////////////////////////////////// |
| // CANDIDATE ASSEMBLY |
| |
| fn push_candidate(&mut self, candidate: Candidate<'db>, is_inherent: bool) { |
| let is_accessible = if is_inherent { |
| let candidate_id = match candidate.item { |
| CandidateId::FunctionId(id) => id.into(), |
| CandidateId::ConstId(id) => id.into(), |
| }; |
| let visibility = self.db().assoc_visibility(candidate_id); |
| self.ctx.resolver.is_visible(self.db(), visibility) |
| } else { |
| true |
| }; |
| if is_accessible { |
| if is_inherent { |
| self.inherent_candidates.push(candidate); |
| } else { |
| self.extension_candidates.push(candidate); |
| } |
| } else { |
| self.private_candidates.push(candidate); |
| } |
| } |
| |
| fn assemble_inherent_candidates(&mut self) { |
| for step in self.steps.iter() { |
| self.assemble_probe(&step.self_ty, step.autoderefs); |
| } |
| } |
| |
| #[instrument(level = "debug", skip(self))] |
| fn assemble_probe( |
| &mut self, |
| self_ty: &Canonical<'db, QueryResponse<'db, Ty<'db>>>, |
| receiver_steps: usize, |
| ) { |
| let raw_self_ty = self_ty.value.value; |
| match raw_self_ty.kind() { |
| TyKind::Dynamic(data, ..) => { |
| if let Some(p) = data.principal() { |
| // Subtle: we can't use `instantiate_query_response` here: using it will |
| // commit to all of the type equalities assumed by inference going through |
| // autoderef (see the `method-probe-no-guessing` test). |
| // |
| // However, in this code, it is OK if we end up with an object type that is |
| // "more general" than the object type that we are evaluating. For *every* |
| // object type `MY_OBJECT`, a function call that goes through a trait-ref |
| // of the form `<MY_OBJECT as SuperTraitOf(MY_OBJECT)>::func` is a valid |
| // `ObjectCandidate`, and it should be discoverable "exactly" through one |
| // of the iterations in the autoderef loop, so there is no problem with it |
| // being discoverable in another one of these iterations. |
| // |
| // Using `instantiate_canonical` on our |
| // `Canonical<QueryResponse<Ty<'db>>>` and then *throwing away* the |
| // `CanonicalVarValues` will exactly give us such a generalization - it |
| // will still match the original object type, but it won't pollute our |
| // type variables in any form, so just do that! |
| let (QueryResponse { value: generalized_self_ty, .. }, _ignored_var_values) = |
| self.infcx().instantiate_canonical(self_ty); |
| |
| self.assemble_inherent_candidates_from_object(generalized_self_ty); |
| self.assemble_inherent_impl_candidates_for_type( |
| &SimplifiedType::Trait(p.def_id().0.into()), |
| receiver_steps, |
| ); |
| self.assemble_inherent_candidates_for_incoherent_ty( |
| raw_self_ty, |
| receiver_steps, |
| ); |
| } |
| } |
| TyKind::Adt(def, _) => { |
| let def_id = def.def_id().0; |
| self.assemble_inherent_impl_candidates_for_type( |
| &SimplifiedType::Adt(def_id.into()), |
| receiver_steps, |
| ); |
| self.assemble_inherent_candidates_for_incoherent_ty(raw_self_ty, receiver_steps); |
| } |
| TyKind::Foreign(did) => { |
| self.assemble_inherent_impl_candidates_for_type( |
| &SimplifiedType::Foreign(did.0.into()), |
| receiver_steps, |
| ); |
| self.assemble_inherent_candidates_for_incoherent_ty(raw_self_ty, receiver_steps); |
| } |
| TyKind::Param(_) => { |
| self.assemble_inherent_candidates_from_param(raw_self_ty); |
| } |
| TyKind::Bool |
| | TyKind::Char |
| | TyKind::Int(_) |
| | TyKind::Uint(_) |
| | TyKind::Float(_) |
| | TyKind::Str |
| | TyKind::Array(..) |
| | TyKind::Slice(_) |
| | TyKind::RawPtr(_, _) |
| | TyKind::Ref(..) |
| | TyKind::Never |
| | TyKind::Tuple(..) => { |
| self.assemble_inherent_candidates_for_incoherent_ty(raw_self_ty, receiver_steps) |
| } |
| _ => {} |
| } |
| } |
| |
| fn assemble_inherent_candidates_for_incoherent_ty( |
| &mut self, |
| self_ty: Ty<'db>, |
| receiver_steps: usize, |
| ) { |
| let Some(simp) = simplify_type(self.interner(), self_ty, TreatParams::InstantiateWithInfer) |
| else { |
| panic!("unexpected incoherent type: {:?}", self_ty) |
| }; |
| for &impl_def_id in incoherent_inherent_impls(self.db(), simp) { |
| self.assemble_inherent_impl_probe(impl_def_id, receiver_steps); |
| } |
| } |
| |
| fn assemble_inherent_impl_candidates_for_type( |
| &mut self, |
| self_ty: &SimplifiedType, |
| receiver_steps: usize, |
| ) { |
| let Some(module) = simplified_type_module(self.db(), self_ty) else { |
| return; |
| }; |
| InherentImpls::for_each_crate_and_block( |
| self.db(), |
| module.krate(), |
| module.containing_block(), |
| &mut |impls| { |
| for &impl_def_id in impls.for_self_ty(self_ty) { |
| self.assemble_inherent_impl_probe(impl_def_id, receiver_steps); |
| } |
| }, |
| ); |
| } |
| |
| #[instrument(level = "debug", skip(self))] |
| fn assemble_inherent_impl_probe(&mut self, impl_def_id: ImplId, receiver_steps: usize) { |
| if !self.impl_dups.insert(impl_def_id) { |
| return; // already visited |
| } |
| |
| self.with_impl_item(impl_def_id, |this, item| { |
| if !this.has_applicable_self(item) { |
| // No receiver declared. Not a candidate. |
| this.record_static_candidate(CandidateSource::Impl(impl_def_id)); |
| return; |
| } |
| this.push_candidate( |
| Candidate { item, kind: InherentImplCandidate { impl_def_id, receiver_steps } }, |
| true, |
| ); |
| }); |
| } |
| |
| #[instrument(level = "debug", skip(self))] |
| fn assemble_inherent_candidates_from_object(&mut self, self_ty: Ty<'db>) { |
| let principal = match self_ty.kind() { |
| TyKind::Dynamic(data, ..) => Some(data), |
| _ => None, |
| } |
| .and_then(|data| data.principal()) |
| .unwrap_or_else(|| { |
| panic!("non-object {:?} in assemble_inherent_candidates_from_object", self_ty) |
| }); |
| |
| // It is illegal to invoke a method on a trait instance that refers to |
| // the `Self` type. An [`DynCompatibilityViolation::SupertraitSelf`] error |
| // will be reported by `dyn_compatibility.rs` if the method refers to the |
| // `Self` type anywhere other than the receiver. Here, we use a |
| // instantiation that replaces `Self` with the object type itself. Hence, |
| // a `&self` method will wind up with an argument type like `&dyn Trait`. |
| let trait_ref = principal.with_self_ty(self.interner(), self_ty); |
| self.assemble_candidates_for_bounds( |
| elaborate::supertraits(self.interner(), trait_ref), |
| |this, new_trait_ref, item| { |
| this.push_candidate(Candidate { item, kind: ObjectCandidate(new_trait_ref) }, true); |
| }, |
| ); |
| } |
| |
| #[instrument(level = "debug", skip(self))] |
| fn assemble_inherent_candidates_from_param(&mut self, param_ty: Ty<'db>) { |
| debug_assert!(matches!(param_ty.kind(), TyKind::Param(_))); |
| |
| let interner = self.interner(); |
| |
| // We use `DeepRejectCtxt` here which may return false positive on where clauses |
| // with alias self types. We need to later on reject these as inherent candidates |
| // in `consider_probe`. |
| let bounds = self.param_env().clauses.iter().filter_map(|predicate| { |
| let bound_predicate = predicate.kind(); |
| match bound_predicate.skip_binder() { |
| ClauseKind::Trait(trait_predicate) => DeepRejectCtxt::relate_rigid_rigid(interner) |
| .types_may_unify(param_ty, trait_predicate.trait_ref.self_ty()) |
| .then(|| bound_predicate.rebind(trait_predicate.trait_ref)), |
| ClauseKind::RegionOutlives(_) |
| | ClauseKind::TypeOutlives(_) |
| | ClauseKind::Projection(_) |
| | ClauseKind::ConstArgHasType(_, _) |
| | ClauseKind::WellFormed(_) |
| | ClauseKind::ConstEvaluatable(_) |
| | ClauseKind::UnstableFeature(_) |
| | ClauseKind::HostEffect(..) => None, |
| } |
| }); |
| |
| self.assemble_candidates_for_bounds(bounds, |this, poly_trait_ref, item| { |
| this.push_candidate( |
| Candidate { item, kind: WhereClauseCandidate(poly_trait_ref) }, |
| true, |
| ); |
| }); |
| } |
| |
| // Do a search through a list of bounds, using a callback to actually |
| // create the candidates. |
| fn assemble_candidates_for_bounds<F>( |
| &mut self, |
| bounds: impl Iterator<Item = PolyTraitRef<'db>>, |
| mut mk_cand: F, |
| ) where |
| F: for<'b> FnMut(&mut ProbeContext<'b, 'db, Choice>, PolyTraitRef<'db>, CandidateId), |
| { |
| for bound_trait_ref in bounds { |
| debug!("elaborate_bounds(bound_trait_ref={:?})", bound_trait_ref); |
| self.with_trait_item(bound_trait_ref.def_id().0, |this, item| { |
| if !this.has_applicable_self(item) { |
| this.record_static_candidate(CandidateSource::Trait( |
| bound_trait_ref.def_id().0, |
| )); |
| } else { |
| mk_cand(this, bound_trait_ref, item); |
| } |
| }); |
| } |
| } |
| |
| #[instrument(level = "debug", skip(self))] |
| fn assemble_extension_candidates_for_traits_in_scope(&mut self) { |
| for &trait_did in self.ctx.traits_in_scope { |
| self.assemble_extension_candidates_for_trait(trait_did); |
| } |
| } |
| |
| #[instrument(level = "debug", skip(self))] |
| fn assemble_extension_candidates_for_trait(&mut self, trait_def_id: TraitId) { |
| let trait_args = self.infcx().fresh_args_for_item(trait_def_id.into()); |
| let trait_ref = TraitRef::new_from_args(self.interner(), trait_def_id.into(), trait_args); |
| |
| self.with_trait_item(trait_def_id, |this, item| { |
| // Check whether `trait_def_id` defines a method with suitable name. |
| if !this.has_applicable_self(item) { |
| debug!("method has inapplicable self"); |
| this.record_static_candidate(CandidateSource::Trait(trait_def_id)); |
| return; |
| } |
| this.push_candidate( |
| Candidate { item, kind: TraitCandidate(Binder::dummy(trait_ref)) }, |
| false, |
| ); |
| }); |
| } |
| } |
| |
| /////////////////////////////////////////////////////////////////////////// |
| // THE ACTUAL SEARCH |
| impl<'a, 'db> ProbeContext<'a, 'db, ProbeForNameChoice<'db>> { |
| #[instrument(level = "debug", skip(self))] |
| fn pick(mut self) -> PickResult<'db> { |
| if let Some(r) = self.pick_core() { |
| return r; |
| } |
| |
| debug!("pick: actual search failed, assemble diagnostics"); |
| |
| if let Some(candidate) = self.choice.private_candidate { |
| return Err(MethodError::PrivateMatch(candidate)); |
| } |
| |
| Err(MethodError::NoMatch) |
| } |
| |
| fn pick_core(&mut self) -> Option<PickResult<'db>> { |
| self.pick_all_method().break_value() |
| } |
| |
| /// Check for cases where arbitrary self types allows shadowing |
| /// of methods that might be a compatibility break. Specifically, |
| /// we have something like: |
| /// ```ignore (illustrative) |
| /// struct A; |
| /// impl A { |
| /// fn foo(self: &NonNull<A>) {} |
| /// // note this is by reference |
| /// } |
| /// ``` |
| /// then we've come along and added this method to `NonNull`: |
| /// ```ignore (illustrative) |
| /// fn foo(self) // note this is by value |
| /// ``` |
| /// Report an error in this case. |
| fn check_for_shadowed_autorefd_method( |
| &mut self, |
| possible_shadower: &Pick<'db>, |
| step: &CandidateStep<'db>, |
| self_ty: Ty<'db>, |
| instantiate_self_ty_obligations: &[PredicateObligation<'db>], |
| mutbl: Mutability, |
| ) -> Result<(), MethodError<'db>> { |
| // The errors emitted by this function are part of |
| // the arbitrary self types work, and should not impact |
| // other users. |
| if !self.ctx.unstable_features.arbitrary_self_types |
| && !self.ctx.unstable_features.arbitrary_self_types_pointers |
| { |
| return Ok(()); |
| } |
| |
| // Set criteria for how we find methods possibly shadowed by 'possible_shadower' |
| let pick_constraints = PickConstraintsForShadowed { |
| // It's the same `self` type... |
| autoderefs: possible_shadower.autoderefs, |
| // ... but the method was found in an impl block determined |
| // by searching further along the Receiver chain than the other, |
| // showing that it's a smart pointer type causing the problem... |
| receiver_steps: possible_shadower.receiver_steps, |
| // ... and they don't end up pointing to the same item in the |
| // first place (could happen with things like blanket impls for T) |
| def_id: possible_shadower.item, |
| }; |
| // A note on the autoderefs above. Within pick_by_value_method, an extra |
| // autoderef may be applied in order to reborrow a reference with |
| // a different lifetime. That seems as though it would break the |
| // logic of these constraints, since the number of autoderefs could |
| // no longer be used to identify the fundamental type of the receiver. |
| // However, this extra autoderef is applied only to by-value calls |
| // where the receiver is already a reference. So this situation would |
| // only occur in cases where the shadowing looks like this: |
| // ``` |
| // struct A; |
| // impl A { |
| // fn foo(self: &&NonNull<A>) {} |
| // // note this is by DOUBLE reference |
| // } |
| // ``` |
| // then we've come along and added this method to `NonNull`: |
| // ``` |
| // fn foo(&self) // note this is by single reference |
| // ``` |
| // and the call is: |
| // ``` |
| // let bar = NonNull<Foo>; |
| // let bar = &foo; |
| // bar.foo(); |
| // ``` |
| // In these circumstances, the logic is wrong, and we wouldn't spot |
| // the shadowing, because the autoderef-based maths wouldn't line up. |
| // This is a niche case and we can live without generating an error |
| // in the case of such shadowing. |
| let potentially_shadowed_pick = self.pick_autorefd_method( |
| step, |
| self_ty, |
| instantiate_self_ty_obligations, |
| mutbl, |
| Some(&pick_constraints), |
| ); |
| // Look for actual pairs of shadower/shadowed which are |
| // the sort of shadowing case we want to avoid. Specifically... |
| if let ControlFlow::Break(Ok(possible_shadowed)) = &potentially_shadowed_pick { |
| let sources = [possible_shadower, possible_shadowed] |
| .into_iter() |
| .map(|p| self.candidate_source_from_pick(p)) |
| .collect(); |
| return Err(MethodError::Ambiguity(sources)); |
| } |
| Ok(()) |
| } |
| } |
| |
| impl<'a, 'db, Choice: ProbeChoice<'db>> ProbeContext<'a, 'db, Choice> { |
| fn pick_all_method(&mut self) -> ControlFlow<Choice::Choice> { |
| self.steps |
| .iter() |
| // At this point we're considering the types to which the receiver can be converted, |
| // so we want to follow the `Deref` chain not the `Receiver` chain. Filter out |
| // steps which can only be reached by following the (longer) `Receiver` chain. |
| .filter(|step| step.reachable_via_deref) |
| .filter(|step| { |
| debug!("pick_all_method: step={:?}", step); |
| // skip types that are from a type error or that would require dereferencing |
| // a raw pointer |
| !step.self_ty.value.value.references_non_lt_error() && !step.from_unsafe_deref |
| }) |
| .try_for_each(|step| { |
| let InferOk { value: self_ty, obligations: instantiate_self_ty_obligations } = self |
| .infcx() |
| .instantiate_query_response_and_region_obligations( |
| &ObligationCause::new(), |
| self.param_env(), |
| self.orig_steps_var_values, |
| &step.self_ty, |
| ) |
| .unwrap_or_else(|_| panic!("{:?} was applicable but now isn't?", step.self_ty)); |
| |
| let by_value_pick = |
| self.pick_by_value_method(step, self_ty, &instantiate_self_ty_obligations); |
| |
| // Check for shadowing of a by-reference method by a by-value method (see comments on check_for_shadowing) |
| if let ControlFlow::Break(by_value_pick) = by_value_pick { |
| Choice::check_by_value_method_shadowing( |
| self, |
| &by_value_pick, |
| step, |
| self_ty, |
| &instantiate_self_ty_obligations, |
| )?; |
| return ControlFlow::Break(by_value_pick); |
| } |
| |
| let autoref_pick = self.pick_autorefd_method( |
| step, |
| self_ty, |
| &instantiate_self_ty_obligations, |
| Mutability::Not, |
| None, |
| ); |
| // Check for shadowing of a by-mut-ref method by a by-reference method (see comments on check_for_shadowing) |
| if let ControlFlow::Break(autoref_pick) = autoref_pick { |
| Choice::check_autorefed_method_shadowing( |
| self, |
| &autoref_pick, |
| step, |
| self_ty, |
| &instantiate_self_ty_obligations, |
| )?; |
| return ControlFlow::Break(autoref_pick); |
| } |
| |
| // Note that no shadowing errors are produced from here on, |
| // as we consider const ptr methods. |
| // We allow new methods that take *mut T to shadow |
| // methods which took *const T, so there is no entry in |
| // this list for the results of `pick_const_ptr_method`. |
| // The reason is that the standard pointer cast method |
| // (on a mutable pointer) always already shadows the |
| // cast method (on a const pointer). So, if we added |
| // `pick_const_ptr_method` to this method, the anti- |
| // shadowing algorithm would always complain about |
| // the conflict between *const::cast and *mut::cast. |
| // In practice therefore this does constrain us: |
| // we cannot add new |
| // self: *mut Self |
| // methods to types such as NonNull or anything else |
| // which implements Receiver, because this might in future |
| // shadow existing methods taking |
| // self: *const NonNull<Self> |
| // in the pointee. In practice, methods taking raw pointers |
| // are rare, and it seems that it should be easily possible |
| // to avoid such compatibility breaks. |
| // We also don't check for reborrowed pin methods which |
| // may be shadowed; these also seem unlikely to occur. |
| self.pick_autorefd_method( |
| step, |
| self_ty, |
| &instantiate_self_ty_obligations, |
| Mutability::Mut, |
| None, |
| )?; |
| self.pick_const_ptr_method(step, self_ty, &instantiate_self_ty_obligations) |
| }) |
| } |
| |
| /// For each type `T` in the step list, this attempts to find a method where |
| /// the (transformed) self type is exactly `T`. We do however do one |
| /// transformation on the adjustment: if we are passing a region pointer in, |
| /// we will potentially *reborrow* it to a shorter lifetime. This allows us |
| /// to transparently pass `&mut` pointers, in particular, without consuming |
| /// them for their entire lifetime. |
| fn pick_by_value_method( |
| &mut self, |
| step: &CandidateStep<'db>, |
| self_ty: Ty<'db>, |
| instantiate_self_ty_obligations: &[PredicateObligation<'db>], |
| ) -> ControlFlow<Choice::Choice> { |
| if step.unsize { |
| return ControlFlow::Continue(()); |
| } |
| |
| self.pick_method(self_ty, instantiate_self_ty_obligations, None).map_break(|r| { |
| Choice::map_choice_pick(r, |mut pick| { |
| pick.autoderefs = step.autoderefs; |
| |
| match step.self_ty.value.value.kind() { |
| // Insert a `&*` or `&mut *` if this is a reference type: |
| TyKind::Ref(_, _, mutbl) => { |
| pick.autoderefs += 1; |
| pick.autoref_or_ptr_adjustment = Some(AutorefOrPtrAdjustment::Autoref { |
| mutbl, |
| unsize: pick.autoref_or_ptr_adjustment.is_some_and(|a| a.get_unsize()), |
| }) |
| } |
| |
| _ => (), |
| } |
| |
| pick |
| }) |
| }) |
| } |
| |
| fn pick_autorefd_method( |
| &mut self, |
| step: &CandidateStep<'db>, |
| self_ty: Ty<'db>, |
| instantiate_self_ty_obligations: &[PredicateObligation<'db>], |
| mutbl: Mutability, |
| pick_constraints: Option<&PickConstraintsForShadowed>, |
| ) -> ControlFlow<Choice::Choice> { |
| let interner = self.interner(); |
| |
| if let Some(pick_constraints) = pick_constraints |
| && !pick_constraints.may_shadow_based_on_autoderefs(step.autoderefs) |
| { |
| return ControlFlow::Continue(()); |
| } |
| |
| // In general, during probing we erase regions. |
| let region = Region::new_erased(interner); |
| |
| let autoref_ty = Ty::new_ref(interner, region, self_ty, mutbl); |
| self.pick_method(autoref_ty, instantiate_self_ty_obligations, pick_constraints).map_break( |
| |r| { |
| Choice::map_choice_pick(r, |mut pick| { |
| pick.autoderefs = step.autoderefs; |
| pick.autoref_or_ptr_adjustment = |
| Some(AutorefOrPtrAdjustment::Autoref { mutbl, unsize: step.unsize }); |
| pick |
| }) |
| }, |
| ) |
| } |
| |
| /// If `self_ty` is `*mut T` then this picks `*const T` methods. The reason why we have a |
| /// 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, |
| step: &CandidateStep<'db>, |
| self_ty: Ty<'db>, |
| instantiate_self_ty_obligations: &[PredicateObligation<'db>], |
| ) -> ControlFlow<Choice::Choice> { |
| // Don't convert an unsized reference to ptr |
| if step.unsize { |
| return ControlFlow::Continue(()); |
| } |
| |
| let TyKind::RawPtr(ty, Mutability::Mut) = self_ty.kind() else { |
| return ControlFlow::Continue(()); |
| }; |
| |
| let const_ptr_ty = Ty::new_ptr(self.interner(), ty, Mutability::Not); |
| self.pick_method(const_ptr_ty, instantiate_self_ty_obligations, None).map_break(|r| { |
| Choice::map_choice_pick(r, |mut pick| { |
| pick.autoderefs = step.autoderefs; |
| pick.autoref_or_ptr_adjustment = Some(AutorefOrPtrAdjustment::ToConstPtr); |
| pick |
| }) |
| }) |
| } |
| |
| fn pick_method( |
| &mut self, |
| self_ty: Ty<'db>, |
| instantiate_self_ty_obligations: &[PredicateObligation<'db>], |
| pick_constraints: Option<&PickConstraintsForShadowed>, |
| ) -> ControlFlow<Choice::Choice> { |
| debug!("pick_method(self_ty={:?})", self_ty); |
| |
| for (kind, candidates) in |
| [("inherent", &self.inherent_candidates), ("extension", &self.extension_candidates)] |
| { |
| debug!("searching {} candidates", kind); |
| self.consider_candidates( |
| self_ty, |
| instantiate_self_ty_obligations, |
| candidates, |
| pick_constraints, |
| )?; |
| } |
| |
| Choice::consider_private_candidates(self, self_ty, instantiate_self_ty_obligations); |
| |
| ControlFlow::Continue(()) |
| } |
| |
| fn consider_candidates( |
| &self, |
| self_ty: Ty<'db>, |
| instantiate_self_ty_obligations: &[PredicateObligation<'db>], |
| candidates: &[Candidate<'db>], |
| pick_constraints: Option<&PickConstraintsForShadowed>, |
| ) -> ControlFlow<Choice::Choice> { |
| let applicable_candidates: Vec<_> = candidates |
| .iter() |
| .filter(|candidate| { |
| pick_constraints |
| .map(|pick_constraints| pick_constraints.candidate_may_shadow(candidate)) |
| .unwrap_or(true) |
| }) |
| .filter(|probe| { |
| self.consider_probe(self_ty, instantiate_self_ty_obligations, probe) |
| != ProbeResult::NoMatch |
| }) |
| .collect(); |
| |
| debug!("applicable_candidates: {:?}", applicable_candidates); |
| |
| Choice::consider_candidates(self, self_ty, applicable_candidates) |
| } |
| |
| fn select_trait_candidate( |
| &self, |
| trait_ref: TraitRef<'db>, |
| ) -> SelectionResult<'db, Selection<'db>> { |
| let obligation = |
| Obligation::new(self.interner(), ObligationCause::new(), self.param_env(), trait_ref); |
| self.infcx().select(&obligation) |
| } |
| |
| /// Used for ambiguous method call error reporting. Uses probing that throws away the result internally, |
| /// so do not use to make a decision that may lead to a successful compilation. |
| fn candidate_source(&self, candidate: &Candidate<'db>, self_ty: Ty<'db>) -> CandidateSource { |
| match candidate.kind { |
| InherentImplCandidate { impl_def_id, .. } => CandidateSource::Impl(impl_def_id), |
| ObjectCandidate(trait_ref) | WhereClauseCandidate(trait_ref) => { |
| CandidateSource::Trait(trait_ref.def_id().0) |
| } |
| TraitCandidate(trait_ref) => self.infcx().probe(|_| { |
| let trait_ref = self.infcx().instantiate_binder_with_fresh_vars( |
| BoundRegionConversionTime::FnCall, |
| trait_ref, |
| ); |
| let (xform_self_ty, _) = self.xform_self_ty( |
| candidate.item, |
| trait_ref.self_ty(), |
| trait_ref.args.as_slice(), |
| ); |
| // Guide the trait selection to show impls that have methods whose type matches |
| // up with the `self` parameter of the method. |
| let _ = self |
| .infcx() |
| .at(&ObligationCause::dummy(), self.param_env()) |
| .sup(xform_self_ty, self_ty); |
| match self.select_trait_candidate(trait_ref) { |
| Ok(Some(ImplSource::UserDefined(ref impl_data))) => { |
| // If only a single impl matches, make the error message point |
| // to that impl. |
| CandidateSource::Impl(impl_data.impl_def_id) |
| } |
| _ => CandidateSource::Trait(trait_ref.def_id.0), |
| } |
| }), |
| } |
| } |
| |
| fn candidate_source_from_pick(&self, pick: &Pick<'db>) -> CandidateSource { |
| match pick.kind { |
| InherentImplPick(impl_) => CandidateSource::Impl(impl_), |
| ObjectPick(trait_) | TraitPick(trait_) => CandidateSource::Trait(trait_), |
| WhereClausePick(trait_ref) => CandidateSource::Trait(trait_ref.skip_binder().def_id.0), |
| } |
| } |
| |
| #[instrument(level = "debug", skip(self), ret)] |
| fn consider_probe( |
| &self, |
| self_ty: Ty<'db>, |
| instantiate_self_ty_obligations: &[PredicateObligation<'db>], |
| probe: &Candidate<'db>, |
| ) -> ProbeResult { |
| self.infcx().probe(|_| { |
| let mut result = ProbeResult::Match; |
| let cause = &ObligationCause::new(); |
| let mut ocx = ObligationCtxt::new(self.infcx()); |
| |
| // Subtle: we're not *really* instantiating the current self type while |
| // probing, but instead fully recompute the autoderef steps once we've got |
| // a final `Pick`. We can't nicely handle these obligations outside of a probe. |
| // |
| // We simply handle them for each candidate here for now. That's kinda scuffed |
| // and ideally we just put them into the `FnCtxt` right away. We need to consider |
| // them to deal with defining uses in `method_autoderef_steps`. |
| ocx.register_obligations(instantiate_self_ty_obligations.iter().cloned()); |
| let errors = ocx.try_evaluate_obligations(); |
| if !errors.is_empty() { |
| unreachable!("unexpected autoderef error {errors:?}"); |
| } |
| |
| let mut trait_predicate = None; |
| let (xform_self_ty, xform_ret_ty); |
| |
| match probe.kind { |
| InherentImplCandidate { impl_def_id, .. } => { |
| let impl_args = self.infcx().fresh_args_for_item(impl_def_id.into()); |
| let impl_ty = |
| self.db().impl_self_ty(impl_def_id).instantiate(self.interner(), impl_args); |
| (xform_self_ty, xform_ret_ty) = |
| self.xform_self_ty(probe.item, impl_ty, impl_args.as_slice()); |
| match ocx.relate( |
| cause, |
| self.param_env(), |
| self.variance(), |
| self_ty, |
| xform_self_ty, |
| ) { |
| Ok(()) => {} |
| Err(err) => { |
| debug!("--> cannot relate self-types {:?}", err); |
| return ProbeResult::NoMatch; |
| } |
| } |
| // Check whether the impl imposes obligations we have to worry about. |
| let impl_bounds = GenericPredicates::query_all(self.db(), impl_def_id.into()); |
| let impl_bounds = clauses_as_obligations( |
| impl_bounds.iter_instantiated_copied(self.interner(), impl_args.as_slice()), |
| ObligationCause::new(), |
| self.param_env(), |
| ); |
| // Convert the bounds into obligations. |
| ocx.register_obligations(impl_bounds); |
| } |
| TraitCandidate(poly_trait_ref) => { |
| // Some trait methods are excluded for arrays before 2021. |
| // (`array.into_iter()` wants a slice iterator for compatibility.) |
| if self_ty.is_array() && !self.ctx.edition.at_least_2021() { |
| let trait_signature = self.db().trait_signature(poly_trait_ref.def_id().0); |
| if trait_signature |
| .flags |
| .contains(TraitFlags::SKIP_ARRAY_DURING_METHOD_DISPATCH) |
| { |
| return ProbeResult::NoMatch; |
| } |
| } |
| |
| // Some trait methods are excluded for boxed slices before 2024. |
| // (`boxed_slice.into_iter()` wants a slice iterator for compatibility.) |
| if self_ty.boxed_ty().is_some_and(Ty::is_slice) |
| && !self.ctx.edition.at_least_2024() |
| { |
| let trait_signature = self.db().trait_signature(poly_trait_ref.def_id().0); |
| if trait_signature |
| .flags |
| .contains(TraitFlags::SKIP_BOXED_SLICE_DURING_METHOD_DISPATCH) |
| { |
| return ProbeResult::NoMatch; |
| } |
| } |
| |
| let trait_ref = self.infcx().instantiate_binder_with_fresh_vars( |
| BoundRegionConversionTime::FnCall, |
| poly_trait_ref, |
| ); |
| (xform_self_ty, xform_ret_ty) = self.xform_self_ty( |
| probe.item, |
| trait_ref.self_ty(), |
| trait_ref.args.as_slice(), |
| ); |
| match ocx.relate( |
| cause, |
| self.param_env(), |
| self.variance(), |
| self_ty, |
| xform_self_ty, |
| ) { |
| Ok(()) => {} |
| Err(err) => { |
| debug!("--> cannot relate self-types {:?}", err); |
| return ProbeResult::NoMatch; |
| } |
| } |
| let obligation = Obligation::new( |
| self.interner(), |
| cause.clone(), |
| self.param_env(), |
| Binder::dummy(trait_ref), |
| ); |
| |
| // We only need this hack to deal with fatal overflow in the old solver. |
| ocx.register_obligation(obligation); |
| |
| trait_predicate = Some(trait_ref.upcast(self.interner())); |
| } |
| ObjectCandidate(poly_trait_ref) | WhereClauseCandidate(poly_trait_ref) => { |
| let trait_ref = self.infcx().instantiate_binder_with_fresh_vars( |
| BoundRegionConversionTime::FnCall, |
| poly_trait_ref, |
| ); |
| (xform_self_ty, xform_ret_ty) = self.xform_self_ty( |
| probe.item, |
| trait_ref.self_ty(), |
| trait_ref.args.as_slice(), |
| ); |
| |
| if matches!(probe.kind, WhereClauseCandidate(_)) { |
| // `WhereClauseCandidate` requires that the self type is a param, |
| // because it has special behavior with candidate preference as an |
| // inherent pick. |
| match ocx.structurally_normalize_ty( |
| cause, |
| self.param_env(), |
| trait_ref.self_ty(), |
| ) { |
| Ok(ty) => { |
| if !matches!(ty.kind(), TyKind::Param(_)) { |
| debug!("--> not a param ty: {xform_self_ty:?}"); |
| return ProbeResult::NoMatch; |
| } |
| } |
| Err(errors) => { |
| debug!("--> cannot relate self-types {:?}", errors); |
| return ProbeResult::NoMatch; |
| } |
| } |
| } |
| |
| match ocx.relate( |
| cause, |
| self.param_env(), |
| self.variance(), |
| self_ty, |
| xform_self_ty, |
| ) { |
| Ok(()) => {} |
| Err(err) => { |
| debug!("--> cannot relate self-types {:?}", err); |
| return ProbeResult::NoMatch; |
| } |
| } |
| } |
| } |
| |
| // See <https://github.com/rust-lang/trait-system-refactor-initiative/issues/134>. |
| // |
| // In the new solver, check the well-formedness of the return type. |
| // This emulates, in a way, the predicates that fall out of |
| // normalizing the return type in the old solver. |
| // |
| // FIXME(-Znext-solver): We alternatively could check the predicates of |
| // the method itself hold, but we intentionally do not do this in the old |
| // solver b/c of cycles, and doing it in the new solver would be stronger. |
| // This should be fixed in the future, since it likely leads to much better |
| // method winnowing. |
| if let Some(xform_ret_ty) = xform_ret_ty { |
| ocx.register_obligation(Obligation::new( |
| self.interner(), |
| cause.clone(), |
| self.param_env(), |
| ClauseKind::WellFormed(xform_ret_ty.into()), |
| )); |
| } |
| |
| if !ocx.try_evaluate_obligations().is_empty() { |
| result = ProbeResult::NoMatch; |
| } |
| |
| if self.should_reject_candidate_due_to_opaque_treated_as_rigid(trait_predicate) { |
| result = ProbeResult::NoMatch; |
| } |
| |
| // FIXME: Need to leak-check here. |
| // if let Err(_) = self.leak_check(outer_universe, Some(snapshot)) { |
| // result = ProbeResult::NoMatch; |
| // } |
| |
| result |
| }) |
| } |
| |
| /// Trait candidates for not-yet-defined opaque types are a somewhat hacky. |
| /// |
| /// We want to only accept trait methods if they were hold even if the |
| /// opaque types were rigid. To handle this, we both check that for trait |
| /// candidates the goal were to hold even when treating opaques as rigid, |
| /// see [OpaqueTypesJank](rustc_trait_selection::solve::OpaqueTypesJank). |
| /// |
| /// We also check that all opaque types encountered as self types in the |
| /// autoderef chain don't get constrained when applying the candidate. |
| /// Importantly, this also handles calling methods taking `&self` on |
| /// `impl Trait` to reject the "by-self" candidate. |
| /// |
| /// This needs to happen at the end of `consider_probe` as we need to take |
| /// all the constraints from that into account. |
| #[instrument(level = "debug", skip(self), ret)] |
| fn should_reject_candidate_due_to_opaque_treated_as_rigid( |
| &self, |
| trait_predicate: Option<Predicate<'db>>, |
| ) -> bool { |
| // This function is what hacky and doesn't perfectly do what we want it to. |
| // It's not soundness critical and we should be able to freely improve this |
| // in the future. |
| // |
| // Some concrete edge cases include the fact that `goal_may_hold_opaque_types_jank` |
| // also fails if there are any constraints opaques which are never used as a self |
| // type. We also allow where-bounds which are currently ambiguous but end up |
| // constraining an opaque later on. |
| |
| // Check whether the trait candidate would not be applicable if the |
| // opaque type were rigid. |
| if let Some(predicate) = trait_predicate { |
| let goal = Goal { param_env: self.param_env(), predicate }; |
| if !self.infcx().goal_may_hold_opaque_types_jank(goal) { |
| return true; |
| } |
| } |
| |
| // Check whether any opaque types in the autoderef chain have been |
| // constrained. |
| for step in self.steps { |
| if step.self_ty_is_opaque { |
| debug!(?step.autoderefs, ?step.self_ty, "self_type_is_opaque"); |
| let constrained_opaque = self.infcx().probe(|_| { |
| // If we fail to instantiate the self type of this |
| // step, this part of the deref-chain is no longer |
| // reachable. In this case we don't care about opaque |
| // types there. |
| let Ok(ok) = self.infcx().instantiate_query_response_and_region_obligations( |
| &ObligationCause::new(), |
| self.param_env(), |
| self.orig_steps_var_values, |
| &step.self_ty, |
| ) else { |
| debug!("failed to instantiate self_ty"); |
| return false; |
| }; |
| let mut ocx = ObligationCtxt::new(self.infcx()); |
| let self_ty = ocx.register_infer_ok_obligations(ok); |
| if !ocx.try_evaluate_obligations().is_empty() { |
| debug!("failed to prove instantiate self_ty obligations"); |
| return false; |
| } |
| |
| !self.infcx().resolve_vars_if_possible(self_ty).is_ty_var() |
| }); |
| if constrained_opaque { |
| debug!("opaque type has been constrained"); |
| return true; |
| } |
| } |
| } |
| |
| false |
| } |
| |
| /// Sometimes we get in a situation where we have multiple probes that are all impls of the |
| /// same trait, but we don't know which impl to use. In this case, since in all cases the |
| /// external interface of the method can be determined from the trait, it's ok not to decide. |
| /// We can basically just collapse all of the probes for various impls into one where-clause |
| /// probe. This will result in a pending obligation so when more type-info is available we can |
| /// make the final decision. |
| /// |
| /// Example (`tests/ui/methods/method-two-trait-defer-resolution-1.rs`): |
| /// |
| /// ```ignore (illustrative) |
| /// trait Foo { ... } |
| /// impl Foo for Vec<i32> { ... } |
| /// impl Foo for Vec<usize> { ... } |
| /// ``` |
| /// |
| /// Now imagine the receiver is `Vec<_>`. It doesn't really matter at this time which impl we |
| /// use, so it's ok to just commit to "using the method from the trait Foo". |
| fn collapse_candidates_to_trait_pick( |
| &self, |
| self_ty: Ty<'db>, |
| probes: &[&Candidate<'db>], |
| ) -> Option<Pick<'db>> { |
| // Do all probes correspond to the same trait? |
| let ItemContainerId::TraitId(container) = probes[0].item.container(self.db()) else { |
| return None; |
| }; |
| for p in &probes[1..] { |
| let ItemContainerId::TraitId(p_container) = p.item.container(self.db()) else { |
| return None; |
| }; |
| if p_container != container { |
| return None; |
| } |
| } |
| |
| // FIXME: check the return type here somehow. |
| // If so, just use this trait and call it a day. |
| Some(Pick { |
| item: probes[0].item, |
| kind: TraitPick(container), |
| autoderefs: 0, |
| autoref_or_ptr_adjustment: None, |
| self_ty, |
| receiver_steps: None, |
| shadowed_candidates: vec![], |
| }) |
| } |
| |
| /// Much like `collapse_candidates_to_trait_pick`, this method allows us to collapse |
| /// multiple conflicting picks if there is one pick whose trait container is a subtrait |
| /// of the trait containers of all of the other picks. |
| /// |
| /// This implements RFC #3624. |
| fn collapse_candidates_to_subtrait_pick( |
| &self, |
| self_ty: Ty<'db>, |
| probes: &[&Candidate<'db>], |
| ) -> Option<Pick<'db>> { |
| let mut child_candidate = probes[0]; |
| let ItemContainerId::TraitId(mut child_trait) = child_candidate.item.container(self.db()) |
| else { |
| return None; |
| }; |
| let mut supertraits: FxHashSet<_> = |
| supertrait_def_ids(self.interner(), child_trait.into()).collect(); |
| |
| let mut remaining_candidates: Vec<_> = probes[1..].to_vec(); |
| while !remaining_candidates.is_empty() { |
| let mut made_progress = false; |
| let mut next_round = vec![]; |
| |
| for remaining_candidate in remaining_candidates { |
| let ItemContainerId::TraitId(remaining_trait) = |
| remaining_candidate.item.container(self.db()) |
| else { |
| return None; |
| }; |
| if supertraits.contains(&remaining_trait.into()) { |
| made_progress = true; |
| continue; |
| } |
| |
| // This pick is not a supertrait of the `child_pick`. |
| // Check if it's a subtrait of the `child_pick`, instead. |
| // If it is, then it must have been a subtrait of every |
| // other pick we've eliminated at this point. It will |
| // take over at this point. |
| let remaining_trait_supertraits: FxHashSet<_> = |
| supertrait_def_ids(self.interner(), remaining_trait.into()).collect(); |
| if remaining_trait_supertraits.contains(&child_trait.into()) { |
| child_candidate = remaining_candidate; |
| child_trait = remaining_trait; |
| supertraits = remaining_trait_supertraits; |
| made_progress = true; |
| continue; |
| } |
| |
| // `child_pick` is not a supertrait of this pick. |
| // Don't bail here, since we may be comparing two supertraits |
| // of a common subtrait. These two supertraits won't be related |
| // at all, but we will pick them up next round when we find their |
| // child as we continue iterating in this round. |
| next_round.push(remaining_candidate); |
| } |
| |
| if made_progress { |
| // If we've made progress, iterate again. |
| remaining_candidates = next_round; |
| } else { |
| // Otherwise, we must have at least two candidates which |
| // are not related to each other at all. |
| return None; |
| } |
| } |
| |
| Some(Pick { |
| item: child_candidate.item, |
| kind: TraitPick(child_trait), |
| autoderefs: 0, |
| autoref_or_ptr_adjustment: None, |
| self_ty, |
| shadowed_candidates: probes |
| .iter() |
| .map(|c| c.item) |
| .filter(|item| *item != child_candidate.item) |
| .collect(), |
| receiver_steps: None, |
| }) |
| } |
| |
| /////////////////////////////////////////////////////////////////////////// |
| // MISCELLANY |
| fn has_applicable_self(&self, item: CandidateId) -> bool { |
| // "Fast track" -- check for usage of sugar when in method call |
| // mode. |
| // |
| // In Path mode (i.e., resolving a value like `T::next`), consider any |
| // associated value (i.e., methods, constants). |
| match item { |
| CandidateId::FunctionId(id) if self.mode == Mode::MethodCall => { |
| self.db().function_signature(id).has_self_param() |
| } |
| _ => true, |
| } |
| // FIXME -- check for types that deref to `Self`, |
| // like `Rc<Self>` and so on. |
| // |
| // Note also that the current code will break if this type |
| // includes any of the type parameters defined on the method |
| // -- but this could be overcome. |
| } |
| |
| fn record_static_candidate(&mut self, source: CandidateSource) { |
| self.static_candidates.push(source); |
| } |
| |
| #[instrument(level = "debug", skip(self))] |
| fn xform_self_ty( |
| &self, |
| item: CandidateId, |
| impl_ty: Ty<'db>, |
| args: &[GenericArg<'db>], |
| ) -> (Ty<'db>, Option<Ty<'db>>) { |
| if let CandidateId::FunctionId(item) = item |
| && self.mode == Mode::MethodCall |
| { |
| let sig = self.xform_method_sig(item, args); |
| (sig.inputs().as_slice()[0], Some(sig.output())) |
| } else { |
| (impl_ty, None) |
| } |
| } |
| |
| #[instrument(level = "debug", skip(self))] |
| fn xform_method_sig(&self, method: FunctionId, args: &[GenericArg<'db>]) -> FnSig<'db> { |
| let fn_sig = self.db().callable_item_signature(method.into()); |
| debug!(?fn_sig); |
| |
| assert!(!args.has_escaping_bound_vars()); |
| |
| // It is possible for type parameters or early-bound lifetimes |
| // to appear in the signature of `self`. The generic parameters |
| // we are given do not include type/lifetime parameters for the |
| // method yet. So create fresh variables here for those too, |
| // if there are any. |
| let generics = self.db().generic_params(method.into()); |
| |
| let xform_fn_sig = if generics.is_empty() { |
| fn_sig.instantiate(self.interner(), args) |
| } else { |
| let args = GenericArgs::for_item( |
| self.interner(), |
| method.into(), |
| |param_index, param_id, _| { |
| let i = param_index as usize; |
| if i < args.len() { |
| args[i] |
| } else { |
| match param_id { |
| GenericParamId::LifetimeParamId(_) => { |
| // In general, during probe we erase regions. |
| Region::new_erased(self.interner()).into() |
| } |
| GenericParamId::TypeParamId(_) => self.infcx().next_ty_var().into(), |
| GenericParamId::ConstParamId(_) => self.infcx().next_const_var().into(), |
| } |
| } |
| }, |
| ); |
| fn_sig.instantiate(self.interner(), args) |
| }; |
| |
| self.interner().instantiate_bound_regions_with_erased(xform_fn_sig) |
| } |
| |
| fn with_impl_item(&mut self, def_id: ImplId, callback: impl FnMut(&mut Self, CandidateId)) { |
| Choice::with_impl_or_trait_item(self, &def_id.impl_items(self.db()).items, callback) |
| } |
| |
| fn with_trait_item(&mut self, def_id: TraitId, callback: impl FnMut(&mut Self, CandidateId)) { |
| Choice::with_impl_or_trait_item(self, &def_id.trait_items(self.db()).items, callback) |
| } |
| } |
| |
| /// Determine if the given associated item type is relevant in the current context. |
| fn is_relevant_kind_for_mode(mode: Mode, kind: AssocItemId) -> Option<CandidateId> { |
| Some(match (mode, kind) { |
| (Mode::MethodCall, AssocItemId::FunctionId(id)) => id.into(), |
| (Mode::Path, AssocItemId::ConstId(id)) => id.into(), |
| (Mode::Path, AssocItemId::FunctionId(id)) => id.into(), |
| _ => return None, |
| }) |
| } |
| |
| impl<'db> Candidate<'db> { |
| fn to_unadjusted_pick(&self, self_ty: Ty<'db>) -> Pick<'db> { |
| Pick { |
| item: self.item, |
| kind: match self.kind { |
| InherentImplCandidate { impl_def_id, .. } => InherentImplPick(impl_def_id), |
| ObjectCandidate(trait_ref) => ObjectPick(trait_ref.skip_binder().def_id.0), |
| TraitCandidate(trait_ref) => TraitPick(trait_ref.skip_binder().def_id.0), |
| WhereClauseCandidate(trait_ref) => { |
| // Only trait derived from where-clauses should |
| // appear here, so they should not contain any |
| // inference variables or other artifacts. This |
| // means they are safe to put into the |
| // `WhereClausePick`. |
| assert!( |
| !trait_ref.skip_binder().args.has_infer() |
| && !trait_ref.skip_binder().args.has_placeholders() |
| ); |
| |
| WhereClausePick(trait_ref) |
| } |
| }, |
| autoderefs: 0, |
| autoref_or_ptr_adjustment: None, |
| self_ty, |
| receiver_steps: match self.kind { |
| InherentImplCandidate { receiver_steps, .. } => Some(receiver_steps), |
| _ => None, |
| }, |
| shadowed_candidates: vec![], |
| } |
| } |
| } |