]>
Commit | Line | Data |
---|---|---|
dfeec247 | 1 | use super::suggest; |
04454e1e | 2 | use super::CandidateSource; |
c34b1796 | 3 | use super::MethodError; |
62682a34 | 4 | use super::NoMatchData; |
1a4d82fc | 5 | |
1b1a35ee | 6 | use crate::errors::MethodCallOnUnknownType; |
2b03887a | 7 | use crate::FnCtxt; |
dfeec247 | 8 | use rustc_data_structures::fx::FxHashSet; |
6a06907d | 9 | use rustc_errors::Applicability; |
dfeec247 | 10 | use rustc_hir as hir; |
2b03887a | 11 | use rustc_hir::def::DefKind; |
9c376795 | 12 | use rustc_hir_analysis::autoderef::{self, Autoderef}; |
74b04a01 XL |
13 | use rustc_infer::infer::canonical::OriginalQueryValues; |
14 | use rustc_infer::infer::canonical::{Canonical, QueryResponse}; | |
15 | use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind}; | |
74b04a01 | 16 | use rustc_infer::infer::{self, InferOk, TyCtxtInferExt}; |
5e7ed085 | 17 | use rustc_middle::infer::unify_key::{ConstVariableOrigin, ConstVariableOriginKind}; |
ba9703b0 | 18 | use rustc_middle::middle::stability; |
5e7ed085 | 19 | use rustc_middle::ty::fast_reject::{simplify_type, TreatParams}; |
487cf647 | 20 | use rustc_middle::ty::AssocItem; |
ba9703b0 | 21 | use rustc_middle::ty::GenericParamDefKind; |
487cf647 FG |
22 | use rustc_middle::ty::ToPredicate; |
23 | use rustc_middle::ty::{self, ParamEnvAnd, Ty, TyCtxt, TypeFoldable, TypeVisitable}; | |
2b03887a | 24 | use rustc_middle::ty::{InternalSubsts, SubstsRef}; |
ba9703b0 | 25 | use rustc_session::lint; |
2b03887a | 26 | use rustc_span::def_id::DefId; |
f035d41b | 27 | use rustc_span::def_id::LocalDefId; |
04454e1e FG |
28 | use rustc_span::lev_distance::{ |
29 | find_best_match_for_name_with_substrings, lev_distance_with_substrings, | |
30 | }; | |
31 | use rustc_span::symbol::sym; | |
f9f354fc | 32 | use rustc_span::{symbol::Ident, Span, Symbol, DUMMY_SP}; |
ba9703b0 XL |
33 | use rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt; |
34 | use rustc_trait_selection::traits::query::method_autoderef::MethodAutoderefBadTy; | |
35 | use rustc_trait_selection::traits::query::method_autoderef::{ | |
36 | CandidateStep, MethodAutoderefStepsResult, | |
37 | }; | |
38 | use rustc_trait_selection::traits::query::CanonicalTyGoal; | |
487cf647 | 39 | use rustc_trait_selection::traits::NormalizeExt; |
ba9703b0 | 40 | use rustc_trait_selection::traits::{self, ObligationCause}; |
9c376795 | 41 | use std::cell::RefCell; |
dfeec247 | 42 | use std::cmp::max; |
a1dfa0c6 | 43 | use std::iter; |
a7813a04 | 44 | use std::ops::Deref; |
60c5eb7d | 45 | |
48663c56 XL |
46 | use smallvec::{smallvec, SmallVec}; |
47 | ||
1a4d82fc | 48 | use self::CandidateKind::*; |
1a4d82fc JJ |
49 | pub use self::PickKind::*; |
50 | ||
32a655c1 | 51 | /// Boolean flag used to indicate if this search is for a suggestion |
0731742a | 52 | /// or not. If true, we can allow ambiguity and so forth. |
5869c6ff | 53 | #[derive(Clone, Copy, Debug)] |
32a655c1 SL |
54 | pub struct IsSuggestion(pub bool); |
55 | ||
dc9dc135 XL |
56 | struct ProbeContext<'a, 'tcx> { |
57 | fcx: &'a FnCtxt<'a, 'tcx>, | |
1a4d82fc | 58 | span: Span, |
c34b1796 | 59 | mode: Mode, |
f9f354fc | 60 | method_name: Option<Ident>, |
ea8adc8c | 61 | return_type: Option<Ty<'tcx>>, |
0731742a XL |
62 | |
63 | /// This is the OriginalQueryValues for the steps queries | |
64 | /// that are answered in steps. | |
9c376795 | 65 | orig_steps_var_values: &'a OriginalQueryValues<'tcx>, |
5099ac24 | 66 | steps: &'tcx [CandidateStep<'tcx>], |
0731742a | 67 | |
1a4d82fc JJ |
68 | inherent_candidates: Vec<Candidate<'tcx>>, |
69 | extension_candidates: Vec<Candidate<'tcx>>, | |
476ff2be | 70 | impl_dups: FxHashSet<DefId>, |
62682a34 | 71 | |
ea8adc8c | 72 | /// When probing for names, include names that are close to the |
9c376795 | 73 | /// requested name (by Levenshtein distance) |
ea8adc8c XL |
74 | allow_similar_names: bool, |
75 | ||
54a0048b | 76 | /// Some(candidate) if there is a private candidate |
48663c56 | 77 | private_candidate: Option<(DefKind, DefId)>, |
54a0048b | 78 | |
9c376795 FG |
79 | /// Collects near misses when the candidate functions are missing a `self` keyword and is only |
80 | /// used for error reporting | |
81 | static_candidates: RefCell<Vec<CandidateSource>>, | |
82 | ||
62682a34 SL |
83 | /// Collects near misses when trait bounds for type parameters are unsatisfied and is only used |
84 | /// for error reporting | |
9c376795 | 85 | unsatisfied_predicates: RefCell< |
3c0e092e | 86 | Vec<(ty::Predicate<'tcx>, Option<ty::Predicate<'tcx>>, Option<ObligationCause<'tcx>>)>, |
9c376795 | 87 | >, |
0531ce1d | 88 | |
cdc7bbd5 | 89 | scope_expr_id: hir::HirId, |
1a4d82fc JJ |
90 | } |
91 | ||
dc9dc135 XL |
92 | impl<'a, 'tcx> Deref for ProbeContext<'a, 'tcx> { |
93 | type Target = FnCtxt<'a, 'tcx>; | |
a7813a04 | 94 | fn deref(&self) -> &Self::Target { |
c295e0f8 | 95 | self.fcx |
a7813a04 XL |
96 | } |
97 | } | |
98 | ||
3c0e092e | 99 | #[derive(Debug, Clone)] |
9c376795 | 100 | pub(crate) struct Candidate<'tcx> { |
0731742a | 101 | // Candidates are (I'm not quite sure, but they are mostly) basically |
dc9dc135 | 102 | // some metadata on top of a `ty::AssocItem` (without substs). |
0731742a XL |
103 | // |
104 | // However, method probing wants to be able to evaluate the predicates | |
105 | // for a function with the substs applied - for example, if a function | |
106 | // has `where Self: Sized`, we don't want to consider it unless `Self` | |
107 | // is actually `Sized`, and similarly, return-type suggestions want | |
108 | // to consider the "actual" return type. | |
109 | // | |
110 | // The way this is handled is through `xform_self_ty`. It contains | |
111 | // the receiver type of this candidate, but `xform_self_ty`, | |
112 | // `xform_ret_ty` and `kind` (which contains the predicates) have the | |
113 | // generic parameters of this candidate substituted with the *same set* | |
114 | // of inference variables, which acts as some weird sort of "query". | |
115 | // | |
116 | // When we check out a candidate, we require `xform_self_ty` to be | |
117 | // a subtype of the passed-in self-type, and this equates the type | |
118 | // variables in the rest of the fields. | |
119 | // | |
120 | // For example, if we have this candidate: | |
121 | // ``` | |
122 | // trait Foo { | |
123 | // fn foo(&self) where Self: Sized; | |
124 | // } | |
125 | // ``` | |
126 | // | |
127 | // Then `xform_self_ty` will be `&'erased ?X` and `kind` will contain | |
128 | // the predicate `?X: Sized`, so if we are evaluating `Foo` for a | |
129 | // the receiver `&T`, we'll do the subtyping which will make `?X` | |
130 | // get the right value, then when we evaluate the predicate we'll check | |
131 | // if `T: Sized`. | |
1a4d82fc | 132 | xform_self_ty: Ty<'tcx>, |
ea8adc8c | 133 | xform_ret_ty: Option<Ty<'tcx>>, |
9c376795 FG |
134 | pub(crate) item: ty::AssocItem, |
135 | pub(crate) kind: CandidateKind<'tcx>, | |
136 | pub(crate) import_ids: SmallVec<[LocalDefId; 1]>, | |
1a4d82fc JJ |
137 | } |
138 | ||
3c0e092e | 139 | #[derive(Debug, Clone)] |
9c376795 | 140 | pub(crate) enum CandidateKind<'tcx> { |
dfeec247 XL |
141 | InherentImplCandidate( |
142 | SubstsRef<'tcx>, | |
143 | // Normalize obligations | |
144 | Vec<traits::PredicateObligation<'tcx>>, | |
145 | ), | |
c1a9b12d | 146 | ObjectCandidate, |
ea8adc8c | 147 | TraitCandidate(ty::TraitRef<'tcx>), |
dfeec247 XL |
148 | WhereClauseCandidate( |
149 | // Trait | |
150 | ty::PolyTraitRef<'tcx>, | |
151 | ), | |
1a4d82fc JJ |
152 | } |
153 | ||
ea8adc8c XL |
154 | #[derive(Debug, PartialEq, Eq, Copy, Clone)] |
155 | enum ProbeResult { | |
156 | NoMatch, | |
157 | BadReturnType, | |
158 | Match, | |
159 | } | |
160 | ||
6a06907d XL |
161 | /// When adjusting a receiver we often want to do one of |
162 | /// | |
cdc7bbd5 | 163 | /// - Add a `&` (or `&mut`), converting the receiver from `T` to `&T` (or `&mut T`) |
6a06907d XL |
164 | /// - If the receiver has type `*mut T`, convert it to `*const T` |
165 | /// | |
166 | /// This type tells us which one to do. | |
167 | /// | |
168 | /// Note that in principle we could do both at the same time. For example, when the receiver has | |
169 | /// type `T`, we could autoref it to `&T`, then convert to `*const T`. Or, when it has type `*mut | |
170 | /// T`, we could convert it to `*const T`, then autoref to `&*const T`. However, currently we do | |
171 | /// (at most) one of these. Either the receiver has type `T` and we convert it to `&T` (or with | |
172 | /// `mut`), or it has type `*mut T` and we convert it to `*const T`. | |
5099ac24 FG |
173 | #[derive(Debug, PartialEq, Copy, Clone)] |
174 | pub enum AutorefOrPtrAdjustment { | |
6a06907d XL |
175 | /// Receiver has type `T`, add `&` or `&mut` (it `T` is `mut`), and maybe also "unsize" it. |
176 | /// Unsizing is used to convert a `[T; N]` to `[T]`, which only makes sense when autorefing. | |
177 | Autoref { | |
178 | mutbl: hir::Mutability, | |
179 | ||
5099ac24 FG |
180 | /// Indicates that the source expression should be "unsized" to a target type. |
181 | /// This is special-cased for just arrays unsizing to slices. | |
182 | unsize: bool, | |
6a06907d XL |
183 | }, |
184 | /// Receiver has type `*mut T`, convert to `*const T` | |
185 | ToConstPtr, | |
186 | } | |
187 | ||
5099ac24 FG |
188 | impl AutorefOrPtrAdjustment { |
189 | fn get_unsize(&self) -> bool { | |
6a06907d | 190 | match self { |
c295e0f8 | 191 | AutorefOrPtrAdjustment::Autoref { mutbl: _, unsize } => *unsize, |
5099ac24 | 192 | AutorefOrPtrAdjustment::ToConstPtr => false, |
6a06907d XL |
193 | } |
194 | } | |
195 | } | |
196 | ||
487cf647 | 197 | #[derive(Debug, Clone)] |
1a4d82fc | 198 | pub struct Pick<'tcx> { |
dc9dc135 | 199 | pub item: ty::AssocItem, |
1a4d82fc | 200 | pub kind: PickKind<'tcx>, |
f035d41b | 201 | pub import_ids: SmallVec<[LocalDefId; 1]>, |
9346a6ac | 202 | |
6a06907d | 203 | /// Indicates that the source expression should be autoderef'd N times |
04454e1e FG |
204 | /// ```ignore (not-rust) |
205 | /// A = expr | *expr | **expr | ... | |
206 | /// ``` | |
9346a6ac AL |
207 | pub autoderefs: usize, |
208 | ||
6a06907d XL |
209 | /// Indicates that we want to add an autoref (and maybe also unsize it), or if the receiver is |
210 | /// `*mut T`, convert it to `*const T`. | |
5099ac24 | 211 | pub autoref_or_ptr_adjustment: Option<AutorefOrPtrAdjustment>, |
3c0e092e | 212 | pub self_ty: Ty<'tcx>, |
487cf647 FG |
213 | |
214 | /// Unstable candidates alongside the stable ones. | |
215 | unstable_candidates: Vec<(Candidate<'tcx>, Symbol)>, | |
1a4d82fc JJ |
216 | } |
217 | ||
3b2f2976 | 218 | #[derive(Clone, Debug, PartialEq, Eq)] |
1a4d82fc | 219 | pub enum PickKind<'tcx> { |
c1a9b12d | 220 | InherentImplPick, |
c1a9b12d SL |
221 | ObjectPick, |
222 | TraitPick, | |
dfeec247 XL |
223 | WhereClausePick( |
224 | // Trait | |
225 | ty::PolyTraitRef<'tcx>, | |
226 | ), | |
1a4d82fc JJ |
227 | } |
228 | ||
62682a34 | 229 | pub type PickResult<'tcx> = Result<Pick<'tcx>, MethodError<'tcx>>; |
1a4d82fc | 230 | |
d9579d0f | 231 | #[derive(PartialEq, Eq, Copy, Clone, Debug)] |
c34b1796 AL |
232 | pub enum Mode { |
233 | // An expression of the form `receiver.method_name(...)`. | |
234 | // Autoderefs are performed on `receiver`, lookup is done based on the | |
9c376795 | 235 | // `self` argument of the method, and static methods aren't considered. |
c34b1796 | 236 | MethodCall, |
d9579d0f | 237 | // An expression of the form `Type::item` or `<T>::item`. |
c34b1796 AL |
238 | // No autoderefs are performed, lookup is done based on the type each |
239 | // implementation is for, and static methods are included. | |
c30ab7b3 | 240 | Path, |
c34b1796 AL |
241 | } |
242 | ||
3b2f2976 XL |
243 | #[derive(PartialEq, Eq, Copy, Clone, Debug)] |
244 | pub enum ProbeScope { | |
245 | // Assemble candidates coming only from traits in scope. | |
246 | TraitsInScope, | |
247 | ||
248 | // Assemble candidates coming from all traits. | |
249 | AllTraits, | |
250 | } | |
251 | ||
dc9dc135 | 252 | impl<'a, 'tcx> FnCtxt<'a, 'tcx> { |
32a655c1 SL |
253 | /// This is used to offer suggestions to users. It returns methods |
254 | /// that could have been called which have the desired return | |
255 | /// type. Some effort is made to rule out methods that, if called, | |
256 | /// would result in an error (basically, the same criteria we | |
257 | /// would use to decide if a method is a plausible fit for | |
258 | /// ambiguity purposes). | |
2b03887a | 259 | #[instrument(level = "debug", skip(self, candidate_filter))] |
dfeec247 XL |
260 | pub fn probe_for_return_type( |
261 | &self, | |
262 | span: Span, | |
263 | mode: Mode, | |
264 | return_type: Ty<'tcx>, | |
265 | self_ty: Ty<'tcx>, | |
266 | scope_expr_id: hir::HirId, | |
2b03887a | 267 | candidate_filter: impl Fn(&ty::AssocItem) -> bool, |
dfeec247 | 268 | ) -> Vec<ty::AssocItem> { |
dfeec247 XL |
269 | let method_names = self |
270 | .probe_op( | |
271 | span, | |
272 | mode, | |
273 | None, | |
274 | Some(return_type), | |
275 | IsSuggestion(true), | |
276 | self_ty, | |
277 | scope_expr_id, | |
278 | ProbeScope::AllTraits, | |
2b03887a | 279 | |probe_cx| Ok(probe_cx.candidate_method_names(candidate_filter)), |
dfeec247 | 280 | ) |
29967ef6 | 281 | .unwrap_or_default(); |
dfeec247 XL |
282 | method_names |
283 | .iter() | |
284 | .flat_map(|&method_name| { | |
285 | self.probe_op( | |
286 | span, | |
287 | mode, | |
288 | Some(method_name), | |
289 | Some(return_type), | |
290 | IsSuggestion(true), | |
291 | self_ty, | |
292 | scope_expr_id, | |
293 | ProbeScope::AllTraits, | |
294 | |probe_cx| probe_cx.pick(), | |
295 | ) | |
296 | .ok() | |
297 | .map(|pick| pick.item) | |
298 | }) | |
32a655c1 SL |
299 | .collect() |
300 | } | |
301 | ||
f2b60f7d | 302 | #[instrument(level = "debug", skip(self))] |
dfeec247 XL |
303 | pub fn probe_for_name( |
304 | &self, | |
dfeec247 | 305 | mode: Mode, |
f9f354fc | 306 | item_name: Ident, |
9c376795 | 307 | return_type: Option<Ty<'tcx>>, |
dfeec247 XL |
308 | is_suggestion: IsSuggestion, |
309 | self_ty: Ty<'tcx>, | |
310 | scope_expr_id: hir::HirId, | |
311 | scope: ProbeScope, | |
312 | ) -> PickResult<'tcx> { | |
dfeec247 | 313 | self.probe_op( |
487cf647 | 314 | item_name.span, |
dfeec247 XL |
315 | mode, |
316 | Some(item_name), | |
9c376795 | 317 | return_type, |
dfeec247 XL |
318 | is_suggestion, |
319 | self_ty, | |
320 | scope_expr_id, | |
321 | scope, | |
322 | |probe_cx| probe_cx.pick(), | |
323 | ) | |
32a655c1 | 324 | } |
a7813a04 | 325 | |
9c376795 FG |
326 | #[instrument(level = "debug", skip(self))] |
327 | pub(crate) fn probe_for_name_many( | |
328 | &self, | |
329 | mode: Mode, | |
330 | item_name: Ident, | |
331 | return_type: Option<Ty<'tcx>>, | |
332 | is_suggestion: IsSuggestion, | |
333 | self_ty: Ty<'tcx>, | |
334 | scope_expr_id: hir::HirId, | |
335 | scope: ProbeScope, | |
336 | ) -> Vec<Candidate<'tcx>> { | |
337 | self.probe_op( | |
338 | item_name.span, | |
339 | mode, | |
340 | Some(item_name), | |
341 | return_type, | |
342 | is_suggestion, | |
343 | self_ty, | |
344 | scope_expr_id, | |
345 | scope, | |
346 | |probe_cx| { | |
347 | Ok(probe_cx | |
348 | .inherent_candidates | |
349 | .into_iter() | |
350 | .chain(probe_cx.extension_candidates) | |
351 | .collect()) | |
352 | }, | |
353 | ) | |
354 | .unwrap() | |
355 | } | |
356 | ||
dc9dc135 XL |
357 | fn probe_op<OP, R>( |
358 | &'a self, | |
359 | span: Span, | |
360 | mode: Mode, | |
f9f354fc | 361 | method_name: Option<Ident>, |
dc9dc135 XL |
362 | return_type: Option<Ty<'tcx>>, |
363 | is_suggestion: IsSuggestion, | |
364 | self_ty: Ty<'tcx>, | |
365 | scope_expr_id: hir::HirId, | |
366 | scope: ProbeScope, | |
367 | op: OP, | |
368 | ) -> Result<R, MethodError<'tcx>> | |
369 | where | |
9c376795 | 370 | OP: FnOnce(ProbeContext<'_, 'tcx>) -> Result<R, MethodError<'tcx>>, |
32a655c1 | 371 | { |
0731742a | 372 | let mut orig_values = OriginalQueryValues::default(); |
064997fb | 373 | let param_env_and_self_ty = self.canonicalize_query( |
fc512014 | 374 | ParamEnvAnd { param_env: self.param_env, value: self_ty }, |
dfeec247 XL |
375 | &mut orig_values, |
376 | ); | |
0731742a | 377 | |
487cf647 FG |
378 | let steps = match mode { |
379 | Mode::MethodCall => self.tcx.method_autoderef_steps(param_env_and_self_ty), | |
380 | Mode::Path => self.probe(|_| { | |
0731742a XL |
381 | // Mode::Path - the deref steps is "trivial". This turns |
382 | // our CanonicalQuery into a "trivial" QueryResponse. This | |
383 | // is a bit inefficient, but I don't think that writing | |
384 | // special handling for this "trivial case" is a good idea. | |
385 | ||
386 | let infcx = &self.infcx; | |
dfeec247 | 387 | let (ParamEnvAnd { param_env: _, value: self_ty }, canonical_inference_vars) = |
0731742a | 388 | infcx.instantiate_canonical_with_fresh_inference_vars( |
dfeec247 XL |
389 | span, |
390 | ¶m_env_and_self_ty, | |
391 | ); | |
392 | debug!( | |
393 | "probe_op: Mode::Path, param_env_and_self_ty={:?} self_ty={:?}", | |
394 | param_env_and_self_ty, self_ty | |
395 | ); | |
0731742a | 396 | MethodAutoderefStepsResult { |
5099ac24 | 397 | steps: infcx.tcx.arena.alloc_from_iter([CandidateStep { |
0731742a | 398 | self_ty: self.make_query_response_ignoring_pending_obligations( |
dfeec247 XL |
399 | canonical_inference_vars, |
400 | self_ty, | |
401 | ), | |
0731742a XL |
402 | autoderefs: 0, |
403 | from_unsafe_deref: false, | |
404 | unsize: false, | |
405 | }]), | |
406 | opt_bad_ty: None, | |
dfeec247 | 407 | reached_recursion_limit: false, |
0731742a | 408 | } |
487cf647 | 409 | }), |
1a4d82fc JJ |
410 | }; |
411 | ||
0731742a XL |
412 | // If our autoderef loop had reached the recursion limit, |
413 | // report an overflow error, but continue going on with | |
414 | // the truncated autoderef list. | |
415 | if steps.reached_recursion_limit { | |
416 | self.probe(|_| { | |
dfeec247 XL |
417 | let ty = &steps |
418 | .steps | |
419 | .last() | |
420 | .unwrap_or_else(|| span_bug!(span, "reached the recursion limit in 0 steps?")) | |
421 | .self_ty; | |
422 | let ty = self | |
423 | .probe_instantiate_query_response(span, &orig_values, ty) | |
0731742a | 424 | .unwrap_or_else(|_| span_bug!(span, "instantiating {:?} failed?", ty)); |
dfeec247 | 425 | autoderef::report_autoderef_recursion_limit_error(self.tcx, span, ty.value); |
0731742a XL |
426 | }); |
427 | } | |
428 | ||
0731742a XL |
429 | // If we encountered an `_` type or an error type during autoderef, this is |
430 | // ambiguous. | |
431 | if let Some(bad_ty) = &steps.opt_bad_ty { | |
432 | if is_suggestion.0 { | |
433 | // Ambiguity was encountered during a suggestion. Just keep going. | |
434 | debug!("ProbeContext: encountered ambiguity in suggestion"); | |
435 | } else if bad_ty.reached_raw_pointer && !self.tcx.features().arbitrary_self_types { | |
436 | // this case used to be allowed by the compiler, | |
437 | // so we do a future-compat lint here for the 2015 edition | |
438 | // (see https://github.com/rust-lang/rust/issues/46906) | |
439 | if self.tcx.sess.rust_2018() { | |
1b1a35ee | 440 | self.tcx.sess.emit_err(MethodCallOnUnknownType { span }); |
0731742a | 441 | } else { |
74b04a01 | 442 | self.tcx.struct_span_lint_hir( |
0731742a XL |
443 | lint::builtin::TYVAR_BEHIND_RAW_POINTER, |
444 | scope_expr_id, | |
445 | span, | |
2b03887a FG |
446 | "type annotations needed", |
447 | |lint| lint, | |
dfeec247 | 448 | ); |
0731742a XL |
449 | } |
450 | } else { | |
451 | // Encountered a real ambiguity, so abort the lookup. If `ty` is not | |
452 | // an `Err`, report the right "type annotations needed" error pointing | |
453 | // to it. | |
454 | let ty = &bad_ty.ty; | |
dfeec247 XL |
455 | let ty = self |
456 | .probe_instantiate_query_response(span, &orig_values, ty) | |
0731742a XL |
457 | .unwrap_or_else(|_| span_bug!(span, "instantiating {:?} failed?", ty)); |
458 | let ty = self.structurally_resolved_type(span, ty.value); | |
1b1a35ee | 459 | assert!(matches!(ty.kind(), ty::Error(_))); |
5e7ed085 FG |
460 | return Err(MethodError::NoMatch(NoMatchData { |
461 | static_candidates: Vec::new(), | |
462 | unsatisfied_predicates: Vec::new(), | |
463 | out_of_scope_traits: Vec::new(), | |
464 | lev_candidate: None, | |
dfeec247 | 465 | mode, |
5e7ed085 | 466 | })); |
0731742a XL |
467 | } |
468 | } | |
469 | ||
dfeec247 | 470 | debug!("ProbeContext: steps for self_ty={:?} are {:?}", self_ty, steps); |
0731742a | 471 | |
a7813a04 XL |
472 | // this creates one big transaction so that all type variables etc |
473 | // that we create during the probe process are removed later | |
474 | self.probe(|_| { | |
0531ce1d | 475 | let mut probe_cx = ProbeContext::new( |
dfeec247 XL |
476 | self, |
477 | span, | |
478 | mode, | |
479 | method_name, | |
480 | return_type, | |
9c376795 | 481 | &orig_values, |
dfeec247 | 482 | steps.steps, |
cdc7bbd5 | 483 | scope_expr_id, |
0531ce1d | 484 | ); |
3b2f2976 | 485 | |
a7813a04 | 486 | probe_cx.assemble_inherent_candidates(); |
3b2f2976 | 487 | match scope { |
dfeec247 | 488 | ProbeScope::TraitsInScope => { |
9c376795 | 489 | probe_cx.assemble_extension_candidates_for_traits_in_scope() |
dfeec247 | 490 | } |
5869c6ff | 491 | ProbeScope::AllTraits => probe_cx.assemble_extension_candidates_for_all_traits(), |
3b2f2976 | 492 | }; |
32a655c1 | 493 | op(probe_cx) |
a7813a04 XL |
494 | }) |
495 | } | |
0731742a XL |
496 | } |
497 | ||
f035d41b | 498 | pub fn provide(providers: &mut ty::query::Providers) { |
0731742a XL |
499 | providers.method_autoderef_steps = method_autoderef_steps; |
500 | } | |
501 | ||
dc9dc135 XL |
502 | fn method_autoderef_steps<'tcx>( |
503 | tcx: TyCtxt<'tcx>, | |
504 | goal: CanonicalTyGoal<'tcx>, | |
505 | ) -> MethodAutoderefStepsResult<'tcx> { | |
0731742a | 506 | debug!("method_autoderef_steps({:?})", goal); |
85aaf69f | 507 | |
2b03887a FG |
508 | let (ref infcx, goal, inference_vars) = tcx.infer_ctxt().build_with_canonical(DUMMY_SP, &goal); |
509 | let ParamEnvAnd { param_env, value: self_ty } = goal; | |
510 | ||
487cf647 FG |
511 | let mut autoderef = Autoderef::new(infcx, param_env, hir::CRATE_HIR_ID, DUMMY_SP, self_ty) |
512 | .include_raw_pointers() | |
513 | .silence_errors(); | |
2b03887a FG |
514 | let mut reached_raw_pointer = false; |
515 | let mut steps: Vec<_> = autoderef | |
516 | .by_ref() | |
517 | .map(|(ty, d)| { | |
518 | let step = CandidateStep { | |
519 | self_ty: infcx | |
520 | .make_query_response_ignoring_pending_obligations(inference_vars.clone(), ty), | |
521 | autoderefs: d, | |
522 | from_unsafe_deref: reached_raw_pointer, | |
523 | unsize: false, | |
524 | }; | |
525 | if let ty::RawPtr(_) = ty.kind() { | |
526 | // all the subsequent steps will be from_unsafe_deref | |
527 | reached_raw_pointer = true; | |
a7813a04 | 528 | } |
2b03887a FG |
529 | step |
530 | }) | |
531 | .collect(); | |
532 | ||
533 | let final_ty = autoderef.final_ty(true); | |
534 | let opt_bad_ty = match final_ty.kind() { | |
535 | ty::Infer(ty::TyVar(_)) | ty::Error(_) => Some(MethodAutoderefBadTy { | |
536 | reached_raw_pointer, | |
537 | ty: infcx.make_query_response_ignoring_pending_obligations(inference_vars, final_ty), | |
538 | }), | |
539 | ty::Array(elem_ty, _) => { | |
540 | let dereferences = steps.len() - 1; | |
541 | ||
542 | steps.push(CandidateStep { | |
543 | self_ty: infcx.make_query_response_ignoring_pending_obligations( | |
544 | inference_vars, | |
545 | infcx.tcx.mk_slice(*elem_ty), | |
546 | ), | |
547 | autoderefs: dereferences, | |
548 | // this could be from an unsafe deref if we had | |
549 | // a *mut/const [T; N] | |
550 | from_unsafe_deref: reached_raw_pointer, | |
551 | unsize: true, | |
552 | }); | |
3157f602 | 553 | |
2b03887a | 554 | None |
0731742a | 555 | } |
2b03887a FG |
556 | _ => None, |
557 | }; | |
558 | ||
559 | debug!("method_autoderef_steps: steps={:?} opt_bad_ty={:?}", steps, opt_bad_ty); | |
560 | ||
561 | MethodAutoderefStepsResult { | |
562 | steps: tcx.arena.alloc_from_iter(steps), | |
563 | opt_bad_ty: opt_bad_ty.map(|ty| &*tcx.arena.alloc(ty)), | |
564 | reached_recursion_limit: autoderef.reached_recursion_limit(), | |
565 | } | |
1a4d82fc JJ |
566 | } |
567 | ||
dc9dc135 XL |
568 | impl<'a, 'tcx> ProbeContext<'a, 'tcx> { |
569 | fn new( | |
570 | fcx: &'a FnCtxt<'a, 'tcx>, | |
571 | span: Span, | |
572 | mode: Mode, | |
f9f354fc | 573 | method_name: Option<Ident>, |
dc9dc135 | 574 | return_type: Option<Ty<'tcx>>, |
9c376795 | 575 | orig_steps_var_values: &'a OriginalQueryValues<'tcx>, |
5099ac24 | 576 | steps: &'tcx [CandidateStep<'tcx>], |
cdc7bbd5 | 577 | scope_expr_id: hir::HirId, |
dc9dc135 | 578 | ) -> ProbeContext<'a, 'tcx> { |
1a4d82fc | 579 | ProbeContext { |
3b2f2976 XL |
580 | fcx, |
581 | span, | |
582 | mode, | |
ea8adc8c XL |
583 | method_name, |
584 | return_type, | |
1a4d82fc JJ |
585 | inherent_candidates: Vec::new(), |
586 | extension_candidates: Vec::new(), | |
0bf4aa26 | 587 | impl_dups: FxHashSet::default(), |
0731742a XL |
588 | orig_steps_var_values, |
589 | steps, | |
ea8adc8c | 590 | allow_similar_names: false, |
54a0048b | 591 | private_candidate: None, |
9c376795 FG |
592 | static_candidates: RefCell::new(Vec::new()), |
593 | unsatisfied_predicates: RefCell::new(Vec::new()), | |
cdc7bbd5 | 594 | scope_expr_id, |
1a4d82fc JJ |
595 | } |
596 | } | |
597 | ||
85aaf69f SL |
598 | fn reset(&mut self) { |
599 | self.inherent_candidates.clear(); | |
600 | self.extension_candidates.clear(); | |
601 | self.impl_dups.clear(); | |
54a0048b | 602 | self.private_candidate = None; |
9c376795 FG |
603 | self.static_candidates.borrow_mut().clear(); |
604 | self.unsatisfied_predicates.borrow_mut().clear(); | |
85aaf69f SL |
605 | } |
606 | ||
1a4d82fc JJ |
607 | /////////////////////////////////////////////////////////////////////////// |
608 | // CANDIDATE ASSEMBLY | |
609 | ||
dfeec247 | 610 | fn push_candidate(&mut self, candidate: Candidate<'tcx>, is_inherent: bool) { |
ea8adc8c XL |
611 | let is_accessible = if let Some(name) = self.method_name { |
612 | let item = candidate.item; | |
064997fb FG |
613 | let def_scope = self |
614 | .tcx | |
615 | .adjust_ident_and_get_scope(name, item.container_id(self.tcx), self.body_id) | |
616 | .1; | |
617 | item.visibility(self.tcx).is_accessible_from(def_scope, self.tcx) | |
7cac9316 XL |
618 | } else { |
619 | true | |
620 | }; | |
621 | if is_accessible { | |
ea8adc8c XL |
622 | if is_inherent { |
623 | self.inherent_candidates.push(candidate); | |
624 | } else { | |
625 | self.extension_candidates.push(candidate); | |
626 | } | |
7cac9316 | 627 | } else if self.private_candidate.is_none() { |
ba9703b0 XL |
628 | self.private_candidate = |
629 | Some((candidate.item.kind.as_def_kind(), candidate.item.def_id)); | |
7cac9316 XL |
630 | } |
631 | } | |
632 | ||
1a4d82fc | 633 | fn assemble_inherent_candidates(&mut self) { |
5099ac24 | 634 | for step in self.steps.iter() { |
0731742a | 635 | self.assemble_probe(&step.self_ty); |
1a4d82fc JJ |
636 | } |
637 | } | |
638 | ||
dc9dc135 | 639 | fn assemble_probe(&mut self, self_ty: &Canonical<'tcx, QueryResponse<'tcx, Ty<'tcx>>>) { |
c30ab7b3 | 640 | debug!("assemble_probe: self_ty={:?}", self_ty); |
5e7ed085 FG |
641 | let raw_self_ty = self_ty.value.value; |
642 | match *raw_self_ty.kind() { | |
c295e0f8 | 643 | ty::Dynamic(data, ..) if let Some(p) = data.principal() => { |
94222f64 XL |
644 | // Subtle: we can't use `instantiate_query_response` here: using it will |
645 | // commit to all of the type equalities assumed by inference going through | |
646 | // autoderef (see the `method-probe-no-guessing` test). | |
647 | // | |
648 | // However, in this code, it is OK if we end up with an object type that is | |
649 | // "more general" than the object type that we are evaluating. For *every* | |
650 | // object type `MY_OBJECT`, a function call that goes through a trait-ref | |
651 | // of the form `<MY_OBJECT as SuperTraitOf(MY_OBJECT)>::func` is a valid | |
652 | // `ObjectCandidate`, and it should be discoverable "exactly" through one | |
653 | // of the iterations in the autoderef loop, so there is no problem with it | |
654 | // being discoverable in another one of these iterations. | |
655 | // | |
656 | // Using `instantiate_canonical_with_fresh_inference_vars` on our | |
657 | // `Canonical<QueryResponse<Ty<'tcx>>>` and then *throwing away* the | |
658 | // `CanonicalVarValues` will exactly give us such a generalization - it | |
659 | // will still match the original object type, but it won't pollute our | |
660 | // type variables in any form, so just do that! | |
661 | let (QueryResponse { value: generalized_self_ty, .. }, _ignored_var_values) = | |
662 | self.fcx | |
c295e0f8 | 663 | .instantiate_canonical_with_fresh_inference_vars(self.span, self_ty); |
94222f64 XL |
664 | |
665 | self.assemble_inherent_candidates_from_object(generalized_self_ty); | |
666 | self.assemble_inherent_impl_candidates_for_type(p.def_id()); | |
04454e1e FG |
667 | if self.tcx.has_attr(p.def_id(), sym::rustc_has_incoherent_inherent_impls) { |
668 | self.assemble_inherent_candidates_for_incoherent_ty(raw_self_ty); | |
669 | } | |
1a4d82fc | 670 | } |
b7449926 | 671 | ty::Adt(def, _) => { |
04454e1e FG |
672 | let def_id = def.did(); |
673 | self.assemble_inherent_impl_candidates_for_type(def_id); | |
674 | if self.tcx.has_attr(def_id, sym::rustc_has_incoherent_inherent_impls) { | |
675 | self.assemble_inherent_candidates_for_incoherent_ty(raw_self_ty); | |
676 | } | |
1a4d82fc | 677 | } |
b7449926 | 678 | ty::Foreign(did) => { |
abe05a73 | 679 | self.assemble_inherent_impl_candidates_for_type(did); |
04454e1e FG |
680 | if self.tcx.has_attr(did, sym::rustc_has_incoherent_inherent_impls) { |
681 | self.assemble_inherent_candidates_for_incoherent_ty(raw_self_ty); | |
682 | } | |
abe05a73 | 683 | } |
b7449926 | 684 | ty::Param(p) => { |
0731742a | 685 | self.assemble_inherent_candidates_from_param(p); |
1a4d82fc | 686 | } |
5e7ed085 FG |
687 | ty::Bool |
688 | | ty::Char | |
689 | | ty::Int(_) | |
690 | | ty::Uint(_) | |
691 | | ty::Float(_) | |
692 | | ty::Str | |
693 | | ty::Array(..) | |
694 | | ty::Slice(_) | |
695 | | ty::RawPtr(_) | |
696 | | ty::Ref(..) | |
697 | | ty::Never | |
698 | | ty::Tuple(..) => self.assemble_inherent_candidates_for_incoherent_ty(raw_self_ty), | |
c30ab7b3 | 699 | _ => {} |
1a4d82fc JJ |
700 | } |
701 | } | |
702 | ||
5e7ed085 | 703 | fn assemble_inherent_candidates_for_incoherent_ty(&mut self, self_ty: Ty<'tcx>) { |
923072b8 | 704 | let Some(simp) = simplify_type(self.tcx, self_ty, TreatParams::AsInfer) else { |
5e7ed085 FG |
705 | bug!("unexpected incoherent type: {:?}", self_ty) |
706 | }; | |
707 | for &impl_def_id in self.tcx.incoherent_impls(simp) { | |
c34b1796 AL |
708 | self.assemble_inherent_impl_probe(impl_def_id); |
709 | } | |
710 | } | |
711 | ||
e9174d1e | 712 | fn assemble_inherent_impl_candidates_for_type(&mut self, def_id: DefId) { |
7cac9316 | 713 | let impl_def_ids = self.tcx.at(self.span).inherent_impls(def_id); |
cc61c64b XL |
714 | for &impl_def_id in impl_def_ids.iter() { |
715 | self.assemble_inherent_impl_probe(impl_def_id); | |
1a4d82fc JJ |
716 | } |
717 | } | |
718 | ||
e9174d1e | 719 | fn assemble_inherent_impl_probe(&mut self, impl_def_id: DefId) { |
1a4d82fc JJ |
720 | if !self.impl_dups.insert(impl_def_id) { |
721 | return; // already visited | |
722 | } | |
723 | ||
724 | debug!("assemble_inherent_impl_probe {:?}", impl_def_id); | |
725 | ||
32a655c1 SL |
726 | for item in self.impl_or_trait_item(impl_def_id) { |
727 | if !self.has_applicable_self(&item) { | |
728 | // No receiver declared. Not a candidate. | |
04454e1e | 729 | self.record_static_candidate(CandidateSource::Impl(impl_def_id)); |
dfeec247 | 730 | continue; |
32a655c1 | 731 | } |
1a4d82fc | 732 | |
32a655c1 | 733 | let (impl_ty, impl_substs) = self.impl_ty_and_substs(impl_def_id); |
064997fb | 734 | let impl_ty = impl_ty.subst(self.tcx, impl_substs); |
54a0048b | 735 | |
c295e0f8 XL |
736 | debug!("impl_ty: {:?}", impl_ty); |
737 | ||
32a655c1 | 738 | // Determine the receiver type that the method itself expects. |
c295e0f8 XL |
739 | let (xform_self_ty, xform_ret_ty) = self.xform_self_ty(&item, impl_ty, impl_substs); |
740 | debug!("xform_self_ty: {:?}, xform_ret_ty: {:?}", xform_self_ty, xform_ret_ty); | |
32a655c1 SL |
741 | |
742 | // We can't use normalize_associated_types_in as it will pollute the | |
743 | // fcx's fulfillment context after this probe is over. | |
c295e0f8 XL |
744 | // Note: we only normalize `xform_self_ty` here since the normalization |
745 | // of the return type can lead to inference results that prohibit | |
5e7ed085 | 746 | // valid candidates from being found, see issue #85671 |
c295e0f8 XL |
747 | // FIXME Postponing the normalization of the return type likely only hides a deeper bug, |
748 | // which might be caused by the `param_env` itself. The clauses of the `param_env` | |
749 | // maybe shouldn't include `Param`s, but rather fresh variables or be canonicalized, | |
5e7ed085 | 750 | // see issue #89650 |
32a655c1 | 751 | let cause = traits::ObligationCause::misc(self.span, self.body_id); |
487cf647 FG |
752 | let InferOk { value: xform_self_ty, obligations } = |
753 | self.fcx.at(&cause, self.param_env).normalize(xform_self_ty); | |
754 | ||
dfeec247 | 755 | debug!( |
c295e0f8 | 756 | "assemble_inherent_impl_probe after normalization: xform_self_ty = {:?}/{:?}", |
dfeec247 XL |
757 | xform_self_ty, xform_ret_ty |
758 | ); | |
759 | ||
760 | self.push_candidate( | |
761 | Candidate { | |
762 | xform_self_ty, | |
763 | xform_ret_ty, | |
764 | item, | |
765 | kind: InherentImplCandidate(impl_substs, obligations), | |
766 | import_ids: smallvec![], | |
767 | }, | |
768 | true, | |
769 | ); | |
32a655c1 | 770 | } |
1a4d82fc JJ |
771 | } |
772 | ||
dfeec247 XL |
773 | fn assemble_inherent_candidates_from_object(&mut self, self_ty: Ty<'tcx>) { |
774 | debug!("assemble_inherent_candidates_from_object(self_ty={:?})", self_ty); | |
1a4d82fc | 775 | |
1b1a35ee | 776 | let principal = match self_ty.kind() { |
0731742a | 777 | ty::Dynamic(ref data, ..) => Some(data), |
dfeec247 XL |
778 | _ => None, |
779 | } | |
780 | .and_then(|data| data.principal()) | |
781 | .unwrap_or_else(|| { | |
782 | span_bug!( | |
783 | self.span, | |
784 | "non-object {:?} in assemble_inherent_candidates_from_object", | |
785 | self_ty | |
786 | ) | |
0731742a XL |
787 | }); |
788 | ||
fc512014 XL |
789 | // It is illegal to invoke a method on a trait instance that refers to |
790 | // the `Self` type. An [`ObjectSafetyViolation::SupertraitSelf`] error | |
791 | // will be reported by `object_safety.rs` if the method refers to the | |
792 | // `Self` type anywhere other than the receiver. Here, we use a | |
793 | // substitution that replaces `Self` with the object type itself. Hence, | |
5869c6ff | 794 | // a `&self` method will wind up with an argument type like `&dyn Trait`. |
9e0c209e | 795 | let trait_ref = principal.with_self_ty(self.tcx, self_ty); |
a1dfa0c6 | 796 | self.elaborate_bounds(iter::once(trait_ref), |this, new_trait_ref, item| { |
fc512014 | 797 | let new_trait_ref = this.erase_late_bound_regions(new_trait_ref); |
1a4d82fc | 798 | |
ea8adc8c | 799 | let (xform_self_ty, xform_ret_ty) = |
c30ab7b3 | 800 | this.xform_self_ty(&item, new_trait_ref.self_ty(), new_trait_ref.substs); |
dfeec247 XL |
801 | this.push_candidate( |
802 | Candidate { | |
803 | xform_self_ty, | |
804 | xform_ret_ty, | |
805 | item, | |
806 | kind: ObjectCandidate, | |
807 | import_ids: smallvec![], | |
808 | }, | |
809 | true, | |
810 | ); | |
1a4d82fc JJ |
811 | }); |
812 | } | |
813 | ||
48663c56 | 814 | fn assemble_inherent_candidates_from_param(&mut self, param_ty: ty::ParamTy) { |
dc9dc135 | 815 | // FIXME: do we want to commit to this behavior for param bounds? |
f035d41b | 816 | debug!("assemble_inherent_candidates_from_param(param_ty={:?})", param_ty); |
1a4d82fc | 817 | |
29967ef6 | 818 | let bounds = self.param_env.caller_bounds().iter().filter_map(|predicate| { |
5869c6ff | 819 | let bound_predicate = predicate.kind(); |
29967ef6 | 820 | match bound_predicate.skip_binder() { |
487cf647 | 821 | ty::PredicateKind::Clause(ty::Clause::Trait(trait_predicate)) => { |
29967ef6 XL |
822 | match *trait_predicate.trait_ref.self_ty().kind() { |
823 | ty::Param(p) if p == param_ty => { | |
824 | Some(bound_predicate.rebind(trait_predicate.trait_ref)) | |
3dfed10e | 825 | } |
29967ef6 | 826 | _ => None, |
3dfed10e | 827 | } |
29967ef6 | 828 | } |
5869c6ff | 829 | ty::PredicateKind::Subtype(..) |
94222f64 | 830 | | ty::PredicateKind::Coerce(..) |
487cf647 FG |
831 | | ty::PredicateKind::Clause(ty::Clause::Projection(..)) |
832 | | ty::PredicateKind::Clause(ty::Clause::RegionOutlives(..)) | |
5869c6ff XL |
833 | | ty::PredicateKind::WellFormed(..) |
834 | | ty::PredicateKind::ObjectSafe(..) | |
835 | | ty::PredicateKind::ClosureKind(..) | |
487cf647 | 836 | | ty::PredicateKind::Clause(ty::Clause::TypeOutlives(..)) |
5869c6ff XL |
837 | | ty::PredicateKind::ConstEvaluatable(..) |
838 | | ty::PredicateKind::ConstEquate(..) | |
487cf647 | 839 | | ty::PredicateKind::Ambiguous |
5869c6ff | 840 | | ty::PredicateKind::TypeWellFormedFromEnv(..) => None, |
29967ef6 XL |
841 | } |
842 | }); | |
1a4d82fc | 843 | |
a1dfa0c6 | 844 | self.elaborate_bounds(bounds, |this, poly_trait_ref, item| { |
fc512014 | 845 | let trait_ref = this.erase_late_bound_regions(poly_trait_ref); |
1a4d82fc | 846 | |
ea8adc8c XL |
847 | let (xform_self_ty, xform_ret_ty) = |
848 | this.xform_self_ty(&item, trait_ref.self_ty(), trait_ref.substs); | |
1a4d82fc | 849 | |
1a4d82fc JJ |
850 | // Because this trait derives from a where-clause, it |
851 | // should not contain any inference variables or other | |
852 | // artifacts. This means it is safe to put into the | |
853 | // `WhereClauseCandidate` and (eventually) into the | |
854 | // `WhereClausePick`. | |
9e0c209e | 855 | assert!(!trait_ref.substs.needs_infer()); |
1a4d82fc | 856 | |
dfeec247 XL |
857 | this.push_candidate( |
858 | Candidate { | |
859 | xform_self_ty, | |
860 | xform_ret_ty, | |
861 | item, | |
862 | kind: WhereClauseCandidate(poly_trait_ref), | |
863 | import_ids: smallvec![], | |
864 | }, | |
865 | true, | |
866 | ); | |
1a4d82fc JJ |
867 | }); |
868 | } | |
869 | ||
870 | // Do a search through a list of bounds, using a callback to actually | |
871 | // create the candidates. | |
dc9dc135 XL |
872 | fn elaborate_bounds<F>( |
873 | &mut self, | |
874 | bounds: impl Iterator<Item = ty::PolyTraitRef<'tcx>>, | |
875 | mut mk_cand: F, | |
876 | ) where | |
877 | F: for<'b> FnMut(&mut ProbeContext<'b, 'tcx>, ty::PolyTraitRef<'tcx>, ty::AssocItem), | |
1a4d82fc | 878 | { |
a7813a04 | 879 | let tcx = self.tcx; |
1a4d82fc | 880 | for bound_trait_ref in traits::transitive_bounds(tcx, bounds) { |
a1dfa0c6 | 881 | debug!("elaborate_bounds(bound_trait_ref={:?})", bound_trait_ref); |
32a655c1 SL |
882 | for item in self.impl_or_trait_item(bound_trait_ref.def_id()) { |
883 | if !self.has_applicable_self(&item) { | |
04454e1e | 884 | self.record_static_candidate(CandidateSource::Trait(bound_trait_ref.def_id())); |
32a655c1 SL |
885 | } else { |
886 | mk_cand(self, bound_trait_ref, item); | |
c30ab7b3 | 887 | } |
1a4d82fc JJ |
888 | } |
889 | } | |
890 | } | |
891 | ||
9c376795 | 892 | fn assemble_extension_candidates_for_traits_in_scope(&mut self) { |
0bf4aa26 | 893 | let mut duplicates = FxHashSet::default(); |
9c376795 | 894 | let opt_applicable_traits = self.tcx.in_scope_traits(self.scope_expr_id); |
85aaf69f | 895 | if let Some(applicable_traits) = opt_applicable_traits { |
ea8adc8c | 896 | for trait_candidate in applicable_traits.iter() { |
a7813a04 | 897 | let trait_did = trait_candidate.def_id; |
1a4d82fc | 898 | if duplicates.insert(trait_did) { |
5869c6ff | 899 | self.assemble_extension_candidates_for_trait( |
74b04a01 XL |
900 | &trait_candidate.import_ids, |
901 | trait_did, | |
902 | ); | |
1a4d82fc JJ |
903 | } |
904 | } | |
905 | } | |
85aaf69f SL |
906 | } |
907 | ||
5869c6ff | 908 | fn assemble_extension_candidates_for_all_traits(&mut self) { |
0bf4aa26 | 909 | let mut duplicates = FxHashSet::default(); |
8bb4bdeb | 910 | for trait_info in suggest::all_traits(self.tcx) { |
85aaf69f | 911 | if duplicates.insert(trait_info.def_id) { |
5869c6ff | 912 | self.assemble_extension_candidates_for_trait(&smallvec![], trait_info.def_id); |
85aaf69f SL |
913 | } |
914 | } | |
1a4d82fc JJ |
915 | } |
916 | ||
487cf647 | 917 | fn matches_return_type( |
dfeec247 XL |
918 | &self, |
919 | method: &ty::AssocItem, | |
920 | self_ty: Option<Ty<'tcx>>, | |
921 | expected: Ty<'tcx>, | |
922 | ) -> bool { | |
48663c56 | 923 | match method.kind { |
ba9703b0 | 924 | ty::AssocKind::Fn => { |
04454e1e | 925 | let fty = self.tcx.bound_fn_sig(method.def_id); |
32a655c1 SL |
926 | self.probe(|_| { |
927 | let substs = self.fresh_substs_for_item(self.span, method.def_id); | |
ea8adc8c | 928 | let fty = fty.subst(self.tcx, substs); |
923072b8 | 929 | let fty = |
fc512014 | 930 | self.replace_bound_vars_with_fresh_vars(self.span, infer::FnCall, fty); |
ea8adc8c XL |
931 | |
932 | if let Some(self_ty) = self_ty { | |
dfeec247 XL |
933 | if self |
934 | .at(&ObligationCause::dummy(), self.param_env) | |
935 | .sup(fty.inputs()[0], self_ty) | |
936 | .is_err() | |
ea8adc8c | 937 | { |
dfeec247 | 938 | return false; |
ea8adc8c XL |
939 | } |
940 | } | |
941 | self.can_sub(self.param_env, fty.output(), expected).is_ok() | |
32a655c1 SL |
942 | }) |
943 | } | |
944 | _ => false, | |
945 | } | |
946 | } | |
947 | ||
dfeec247 XL |
948 | fn assemble_extension_candidates_for_trait( |
949 | &mut self, | |
f035d41b | 950 | import_ids: &SmallVec<[LocalDefId; 1]>, |
dfeec247 | 951 | trait_def_id: DefId, |
5869c6ff | 952 | ) { |
dfeec247 | 953 | debug!("assemble_extension_candidates_for_trait(trait_def_id={:?})", trait_def_id); |
ea8adc8c | 954 | let trait_substs = self.fresh_item_substs(trait_def_id); |
9c376795 | 955 | let trait_ref = self.tcx.mk_trait_ref(trait_def_id, trait_substs); |
1a4d82fc | 956 | |
532ac7d7 | 957 | if self.tcx.is_trait_alias(trait_def_id) { |
c295e0f8 XL |
958 | // For trait aliases, assume all supertraits are relevant. |
959 | let bounds = iter::once(ty::Binder::dummy(trait_ref)); | |
532ac7d7 | 960 | self.elaborate_bounds(bounds, |this, new_trait_ref, item| { |
fc512014 | 961 | let new_trait_ref = this.erase_late_bound_regions(new_trait_ref); |
532ac7d7 XL |
962 | |
963 | let (xform_self_ty, xform_ret_ty) = | |
964 | this.xform_self_ty(&item, new_trait_ref.self_ty(), new_trait_ref.substs); | |
dfeec247 XL |
965 | this.push_candidate( |
966 | Candidate { | |
967 | xform_self_ty, | |
968 | xform_ret_ty, | |
969 | item, | |
970 | import_ids: import_ids.clone(), | |
971 | kind: TraitCandidate(new_trait_ref), | |
972 | }, | |
f035d41b | 973 | false, |
dfeec247 | 974 | ); |
532ac7d7 XL |
975 | }); |
976 | } else { | |
977 | debug_assert!(self.tcx.is_trait(trait_def_id)); | |
9c376795 FG |
978 | if self.tcx.trait_is_auto(trait_def_id) { |
979 | return; | |
980 | } | |
532ac7d7 XL |
981 | for item in self.impl_or_trait_item(trait_def_id) { |
982 | // Check whether `trait_def_id` defines a method with suitable name. | |
983 | if !self.has_applicable_self(&item) { | |
984 | debug!("method has inapplicable self"); | |
04454e1e | 985 | self.record_static_candidate(CandidateSource::Trait(trait_def_id)); |
532ac7d7 XL |
986 | continue; |
987 | } | |
1a4d82fc | 988 | |
532ac7d7 XL |
989 | let (xform_self_ty, xform_ret_ty) = |
990 | self.xform_self_ty(&item, trait_ref.self_ty(), trait_substs); | |
dfeec247 XL |
991 | self.push_candidate( |
992 | Candidate { | |
993 | xform_self_ty, | |
994 | xform_ret_ty, | |
995 | item, | |
996 | import_ids: import_ids.clone(), | |
997 | kind: TraitCandidate(trait_ref), | |
998 | }, | |
999 | false, | |
1000 | ); | |
532ac7d7 | 1001 | } |
32a655c1 | 1002 | } |
1a4d82fc JJ |
1003 | } |
1004 | ||
2b03887a FG |
1005 | fn candidate_method_names( |
1006 | &self, | |
1007 | candidate_filter: impl Fn(&ty::AssocItem) -> bool, | |
1008 | ) -> Vec<Ident> { | |
0bf4aa26 | 1009 | let mut set = FxHashSet::default(); |
dfeec247 XL |
1010 | let mut names: Vec<_> = self |
1011 | .inherent_candidates | |
ea8adc8c XL |
1012 | .iter() |
1013 | .chain(&self.extension_candidates) | |
2b03887a | 1014 | .filter(|candidate| candidate_filter(&candidate.item)) |
ea8adc8c XL |
1015 | .filter(|candidate| { |
1016 | if let Some(return_ty) = self.return_type { | |
1017 | self.matches_return_type(&candidate.item, None, return_ty) | |
1018 | } else { | |
1019 | true | |
1020 | } | |
1021 | }) | |
5099ac24 | 1022 | .map(|candidate| candidate.item.ident(self.tcx)) |
ea8adc8c XL |
1023 | .filter(|&name| set.insert(name)) |
1024 | .collect(); | |
32a655c1 | 1025 | |
532ac7d7 | 1026 | // Sort them by the name so we have a stable result. |
a2a8927a | 1027 | names.sort_by(|a, b| a.as_str().partial_cmp(b.as_str()).unwrap()); |
32a655c1 SL |
1028 | names |
1029 | } | |
1030 | ||
1a4d82fc JJ |
1031 | /////////////////////////////////////////////////////////////////////////// |
1032 | // THE ACTUAL SEARCH | |
1033 | ||
1034 | fn pick(mut self) -> PickResult<'tcx> { | |
ea8adc8c | 1035 | assert!(self.method_name.is_some()); |
32a655c1 | 1036 | |
3157f602 XL |
1037 | if let Some(r) = self.pick_core() { |
1038 | return r; | |
85aaf69f | 1039 | } |
1a4d82fc | 1040 | |
74b04a01 | 1041 | debug!("pick: actual search failed, assemble diagnostics"); |
532ac7d7 | 1042 | |
9c376795 | 1043 | let static_candidates = std::mem::take(self.static_candidates.get_mut()); |
a1dfa0c6 | 1044 | let private_candidate = self.private_candidate.take(); |
9c376795 | 1045 | let unsatisfied_predicates = std::mem::take(self.unsatisfied_predicates.get_mut()); |
85aaf69f SL |
1046 | |
1047 | // things failed, so lets look at all traits, for diagnostic purposes now: | |
1048 | self.reset(); | |
1049 | ||
1050 | let span = self.span; | |
a7813a04 | 1051 | let tcx = self.tcx; |
85aaf69f | 1052 | |
5869c6ff | 1053 | self.assemble_extension_candidates_for_all_traits(); |
85aaf69f SL |
1054 | |
1055 | let out_of_scope_traits = match self.pick_core() { | |
064997fb | 1056 | Some(Ok(p)) => vec![p.item.container_id(self.tcx)], |
dfeec247 XL |
1057 | Some(Err(MethodError::Ambiguity(v))) => v |
1058 | .into_iter() | |
1059 | .map(|source| match source { | |
04454e1e FG |
1060 | CandidateSource::Trait(id) => id, |
1061 | CandidateSource::Impl(impl_id) => match tcx.trait_id_of_impl(impl_id) { | |
dfeec247 XL |
1062 | Some(id) => id, |
1063 | None => span_bug!(span, "found inherent method when looking at traits"), | |
1064 | }, | |
1065 | }) | |
1066 | .collect(), | |
1067 | Some(Err(MethodError::NoMatch(NoMatchData { | |
1068 | out_of_scope_traits: others, .. | |
1069 | }))) => { | |
85aaf69f SL |
1070 | assert!(others.is_empty()); |
1071 | vec![] | |
1a4d82fc | 1072 | } |
54a0048b | 1073 | _ => vec![], |
85aaf69f SL |
1074 | }; |
1075 | ||
48663c56 XL |
1076 | if let Some((kind, def_id)) = private_candidate { |
1077 | return Err(MethodError::PrivateMatch(kind, def_id, out_of_scope_traits)); | |
54a0048b | 1078 | } |
ea8adc8c | 1079 | let lev_candidate = self.probe_for_lev_candidate()?; |
54a0048b | 1080 | |
5e7ed085 | 1081 | Err(MethodError::NoMatch(NoMatchData { |
dfeec247 XL |
1082 | static_candidates, |
1083 | unsatisfied_predicates, | |
1084 | out_of_scope_traits, | |
1085 | lev_candidate, | |
5e7ed085 FG |
1086 | mode: self.mode, |
1087 | })) | |
85aaf69f SL |
1088 | } |
1089 | ||
9c376795 | 1090 | fn pick_core(&self) -> Option<PickResult<'tcx>> { |
487cf647 | 1091 | let pick = self.pick_all_method(Some(&mut vec![])); |
3c0e092e XL |
1092 | |
1093 | // In this case unstable picking is done by `pick_method`. | |
064997fb | 1094 | if !self.tcx.sess.opts.unstable_opts.pick_stable_methods_before_any_unstable { |
3c0e092e XL |
1095 | return pick; |
1096 | } | |
1a4d82fc | 1097 | |
487cf647 FG |
1098 | if pick.is_none() { |
1099 | return self.pick_all_method(None); | |
3c0e092e | 1100 | } |
487cf647 | 1101 | pick |
3c0e092e XL |
1102 | } |
1103 | ||
1104 | fn pick_all_method( | |
9c376795 | 1105 | &self, |
3c0e092e XL |
1106 | mut unstable_candidates: Option<&mut Vec<(Candidate<'tcx>, Symbol)>>, |
1107 | ) -> Option<PickResult<'tcx>> { | |
9c376795 | 1108 | self.steps |
ea8adc8c XL |
1109 | .iter() |
1110 | .filter(|step| { | |
3c0e092e | 1111 | debug!("pick_all_method: step={:?}", step); |
ff7c6d11 XL |
1112 | // skip types that are from a type error or that would require dereferencing |
1113 | // a raw pointer | |
1114 | !step.self_ty.references_error() && !step.from_unsafe_deref | |
dfeec247 | 1115 | }) |
9c376795 | 1116 | .find_map(|step| { |
dfeec247 XL |
1117 | let InferOk { value: self_ty, obligations: _ } = self |
1118 | .fcx | |
1119 | .probe_instantiate_query_response( | |
1120 | self.span, | |
1121 | &self.orig_steps_var_values, | |
1122 | &step.self_ty, | |
1123 | ) | |
1124 | .unwrap_or_else(|_| { | |
0731742a XL |
1125 | span_bug!(self.span, "{:?} was applicable but now isn't?", step.self_ty) |
1126 | }); | |
3c0e092e XL |
1127 | self.pick_by_value_method(step, self_ty, unstable_candidates.as_deref_mut()) |
1128 | .or_else(|| { | |
1129 | self.pick_autorefd_method( | |
1130 | step, | |
1131 | self_ty, | |
1132 | hir::Mutability::Not, | |
1133 | unstable_candidates.as_deref_mut(), | |
1134 | ) | |
1135 | .or_else(|| { | |
1136 | self.pick_autorefd_method( | |
1137 | step, | |
1138 | self_ty, | |
1139 | hir::Mutability::Mut, | |
1140 | unstable_candidates.as_deref_mut(), | |
1141 | ) | |
1142 | }) | |
1143 | .or_else(|| { | |
1144 | self.pick_const_ptr_method( | |
1145 | step, | |
1146 | self_ty, | |
1147 | unstable_candidates.as_deref_mut(), | |
1148 | ) | |
1149 | }) | |
1150 | }) | |
dfeec247 | 1151 | }) |
1a4d82fc JJ |
1152 | } |
1153 | ||
6a06907d XL |
1154 | /// For each type `T` in the step list, this attempts to find a method where |
1155 | /// the (transformed) self type is exactly `T`. We do however do one | |
1156 | /// transformation on the adjustment: if we are passing a region pointer in, | |
1157 | /// we will potentially *reborrow* it to a shorter lifetime. This allows us | |
1158 | /// to transparently pass `&mut` pointers, in particular, without consuming | |
1159 | /// them for their entire lifetime. | |
dc9dc135 | 1160 | fn pick_by_value_method( |
9c376795 | 1161 | &self, |
dc9dc135 XL |
1162 | step: &CandidateStep<'tcx>, |
1163 | self_ty: Ty<'tcx>, | |
3c0e092e | 1164 | unstable_candidates: Option<&mut Vec<(Candidate<'tcx>, Symbol)>>, |
dc9dc135 | 1165 | ) -> Option<PickResult<'tcx>> { |
9346a6ac AL |
1166 | if step.unsize { |
1167 | return None; | |
1168 | } | |
1a4d82fc | 1169 | |
3c0e092e | 1170 | self.pick_method(self_ty, unstable_candidates).map(|r| { |
c30ab7b3 SL |
1171 | r.map(|mut pick| { |
1172 | pick.autoderefs = step.autoderefs; | |
1a4d82fc | 1173 | |
c30ab7b3 | 1174 | // Insert a `&*` or `&mut *` if this is a reference type: |
1b1a35ee | 1175 | if let ty::Ref(_, _, mutbl) = *step.self_ty.value.value.kind() { |
c30ab7b3 | 1176 | pick.autoderefs += 1; |
6a06907d XL |
1177 | pick.autoref_or_ptr_adjustment = Some(AutorefOrPtrAdjustment::Autoref { |
1178 | mutbl, | |
5099ac24 | 1179 | unsize: pick.autoref_or_ptr_adjustment.map_or(false, |a| a.get_unsize()), |
6a06907d | 1180 | }) |
c30ab7b3 | 1181 | } |
9346a6ac | 1182 | |
c30ab7b3 SL |
1183 | pick |
1184 | }) | |
1185 | }) | |
1a4d82fc JJ |
1186 | } |
1187 | ||
dc9dc135 | 1188 | fn pick_autorefd_method( |
9c376795 | 1189 | &self, |
dc9dc135 XL |
1190 | step: &CandidateStep<'tcx>, |
1191 | self_ty: Ty<'tcx>, | |
1192 | mutbl: hir::Mutability, | |
3c0e092e | 1193 | unstable_candidates: Option<&mut Vec<(Candidate<'tcx>, Symbol)>>, |
dc9dc135 | 1194 | ) -> Option<PickResult<'tcx>> { |
a7813a04 | 1195 | let tcx = self.tcx; |
1a4d82fc | 1196 | |
ba9703b0 | 1197 | // In general, during probing we erase regions. |
48663c56 | 1198 | let region = tcx.lifetimes.re_erased; |
1a4d82fc | 1199 | |
dfeec247 | 1200 | let autoref_ty = tcx.mk_ref(region, ty::TypeAndMut { ty: self_ty, mutbl }); |
3c0e092e | 1201 | self.pick_method(autoref_ty, unstable_candidates).map(|r| { |
ea8adc8c XL |
1202 | r.map(|mut pick| { |
1203 | pick.autoderefs = step.autoderefs; | |
5099ac24 FG |
1204 | pick.autoref_or_ptr_adjustment = |
1205 | Some(AutorefOrPtrAdjustment::Autoref { mutbl, unsize: step.unsize }); | |
6a06907d XL |
1206 | pick |
1207 | }) | |
1208 | }) | |
1209 | } | |
1210 | ||
1211 | /// If `self_ty` is `*mut T` then this picks `*const T` methods. The reason why we have a | |
1212 | /// special case for this is because going from `*mut T` to `*const T` with autoderefs and | |
1213 | /// autorefs would require dereferencing the pointer, which is not safe. | |
1214 | fn pick_const_ptr_method( | |
9c376795 | 1215 | &self, |
6a06907d XL |
1216 | step: &CandidateStep<'tcx>, |
1217 | self_ty: Ty<'tcx>, | |
3c0e092e | 1218 | unstable_candidates: Option<&mut Vec<(Candidate<'tcx>, Symbol)>>, |
6a06907d XL |
1219 | ) -> Option<PickResult<'tcx>> { |
1220 | // Don't convert an unsized reference to ptr | |
1221 | if step.unsize { | |
1222 | return None; | |
1223 | } | |
1224 | ||
5e7ed085 FG |
1225 | let &ty::RawPtr(ty::TypeAndMut { ty, mutbl: hir::Mutability::Mut }) = self_ty.kind() else { |
1226 | return None; | |
6a06907d XL |
1227 | }; |
1228 | ||
1229 | let const_self_ty = ty::TypeAndMut { ty, mutbl: hir::Mutability::Not }; | |
1230 | let const_ptr_ty = self.tcx.mk_ptr(const_self_ty); | |
3c0e092e | 1231 | self.pick_method(const_ptr_ty, unstable_candidates).map(|r| { |
6a06907d XL |
1232 | r.map(|mut pick| { |
1233 | pick.autoderefs = step.autoderefs; | |
1234 | pick.autoref_or_ptr_adjustment = Some(AutorefOrPtrAdjustment::ToConstPtr); | |
ea8adc8c | 1235 | pick |
c30ab7b3 | 1236 | }) |
ea8adc8c | 1237 | }) |
1a4d82fc JJ |
1238 | } |
1239 | ||
9c376795 | 1240 | fn pick_method_with_unstable(&self, self_ty: Ty<'tcx>) -> Option<PickResult<'tcx>> { |
3c0e092e | 1241 | debug!("pick_method_with_unstable(self_ty={})", self.ty_to_string(self_ty)); |
1a4d82fc | 1242 | |
62682a34 | 1243 | let mut possibly_unsatisfied_predicates = Vec::new(); |
0531ce1d | 1244 | |
dfeec247 XL |
1245 | for (kind, candidates) in |
1246 | &[("inherent", &self.inherent_candidates), ("extension", &self.extension_candidates)] | |
1247 | { | |
0531ce1d XL |
1248 | debug!("searching {} candidates", kind); |
1249 | let res = self.consider_candidates( | |
1250 | self_ty, | |
9c376795 | 1251 | candidates, |
0531ce1d | 1252 | &mut possibly_unsatisfied_predicates, |
487cf647 | 1253 | Some(&mut vec![]), |
0531ce1d | 1254 | ); |
487cf647 FG |
1255 | if res.is_some() { |
1256 | return res; | |
0531ce1d | 1257 | } |
1a4d82fc JJ |
1258 | } |
1259 | ||
9c376795 FG |
1260 | for (kind, candidates) in |
1261 | &[("inherent", &self.inherent_candidates), ("extension", &self.extension_candidates)] | |
1262 | { | |
1263 | debug!("searching unstable {kind} candidates"); | |
1264 | let res = self.consider_candidates( | |
1265 | self_ty, | |
1266 | candidates, | |
1267 | &mut possibly_unsatisfied_predicates, | |
1268 | None, | |
1269 | ); | |
1270 | if res.is_some() { | |
1271 | return res; | |
1272 | } | |
62682a34 | 1273 | } |
9c376795 FG |
1274 | |
1275 | self.unsatisfied_predicates.borrow_mut().extend(possibly_unsatisfied_predicates); | |
1276 | None | |
1a4d82fc JJ |
1277 | } |
1278 | ||
3c0e092e | 1279 | fn pick_method( |
9c376795 | 1280 | &self, |
3c0e092e XL |
1281 | self_ty: Ty<'tcx>, |
1282 | mut unstable_candidates: Option<&mut Vec<(Candidate<'tcx>, Symbol)>>, | |
1283 | ) -> Option<PickResult<'tcx>> { | |
064997fb | 1284 | if !self.tcx.sess.opts.unstable_opts.pick_stable_methods_before_any_unstable { |
3c0e092e XL |
1285 | return self.pick_method_with_unstable(self_ty); |
1286 | } | |
1287 | ||
1288 | debug!("pick_method(self_ty={})", self.ty_to_string(self_ty)); | |
1289 | ||
1290 | let mut possibly_unsatisfied_predicates = Vec::new(); | |
1291 | ||
1292 | for (kind, candidates) in | |
1293 | &[("inherent", &self.inherent_candidates), ("extension", &self.extension_candidates)] | |
1294 | { | |
1295 | debug!("searching {} candidates", kind); | |
1296 | let res = self.consider_candidates( | |
1297 | self_ty, | |
9c376795 | 1298 | candidates, |
3c0e092e XL |
1299 | &mut possibly_unsatisfied_predicates, |
1300 | unstable_candidates.as_deref_mut(), | |
1301 | ); | |
1302 | if let Some(pick) = res { | |
1303 | return Some(pick); | |
1304 | } | |
1305 | } | |
1306 | ||
1307 | // `pick_method` may be called twice for the same self_ty if no stable methods | |
1308 | // match. Only extend once. | |
1309 | if unstable_candidates.is_some() { | |
9c376795 | 1310 | self.unsatisfied_predicates.borrow_mut().extend(possibly_unsatisfied_predicates); |
3c0e092e XL |
1311 | } |
1312 | None | |
1313 | } | |
1314 | ||
9c376795 | 1315 | fn consider_candidates( |
0531ce1d XL |
1316 | &self, |
1317 | self_ty: Ty<'tcx>, | |
9c376795 | 1318 | candidates: &[Candidate<'tcx>], |
74b04a01 XL |
1319 | possibly_unsatisfied_predicates: &mut Vec<( |
1320 | ty::Predicate<'tcx>, | |
1321 | Option<ty::Predicate<'tcx>>, | |
3c0e092e | 1322 | Option<ObligationCause<'tcx>>, |
74b04a01 | 1323 | )>, |
487cf647 | 1324 | mut unstable_candidates: Option<&mut Vec<(Candidate<'tcx>, Symbol)>>, |
9c376795 FG |
1325 | ) -> Option<PickResult<'tcx>> { |
1326 | let mut applicable_candidates: Vec<_> = candidates | |
1327 | .iter() | |
ea8adc8c XL |
1328 | .map(|probe| { |
1329 | (probe, self.consider_probe(self_ty, probe, possibly_unsatisfied_predicates)) | |
1330 | }) | |
1331 | .filter(|&(_, status)| status != ProbeResult::NoMatch) | |
c30ab7b3 | 1332 | .collect(); |
1a4d82fc | 1333 | |
62682a34 | 1334 | debug!("applicable_candidates: {:?}", applicable_candidates); |
1a4d82fc JJ |
1335 | |
1336 | if applicable_candidates.len() > 1 { | |
3c0e092e | 1337 | if let Some(pick) = |
a2a8927a | 1338 | self.collapse_candidates_to_trait_pick(self_ty, &applicable_candidates) |
3c0e092e | 1339 | { |
ea8adc8c | 1340 | return Some(Ok(pick)); |
1a4d82fc JJ |
1341 | } |
1342 | } | |
1343 | ||
487cf647 | 1344 | if let Some(uc) = &mut unstable_candidates { |
9c376795 | 1345 | applicable_candidates.retain(|&(candidate, _)| { |
0531ce1d | 1346 | if let stability::EvalResult::Deny { feature, .. } = |
9c376795 | 1347 | self.tcx.eval_stability(candidate.item.def_id, None, self.span, None) |
0531ce1d | 1348 | { |
9c376795 | 1349 | uc.push((candidate.clone(), feature)); |
0531ce1d XL |
1350 | return false; |
1351 | } | |
1352 | true | |
1353 | }); | |
1354 | } | |
1355 | ||
1a4d82fc | 1356 | if applicable_candidates.len() > 1 { |
9c376795 | 1357 | let sources = candidates.iter().map(|p| self.candidate_source(p, self_ty)).collect(); |
85aaf69f | 1358 | return Some(Err(MethodError::Ambiguity(sources))); |
1a4d82fc JJ |
1359 | } |
1360 | ||
ea8adc8c XL |
1361 | applicable_candidates.pop().map(|(probe, status)| { |
1362 | if status == ProbeResult::Match { | |
487cf647 FG |
1363 | Ok(probe |
1364 | .to_unadjusted_pick(self_ty, unstable_candidates.cloned().unwrap_or_default())) | |
ea8adc8c XL |
1365 | } else { |
1366 | Err(MethodError::BadReturnType) | |
1367 | } | |
1368 | }) | |
1369 | } | |
487cf647 FG |
1370 | } |
1371 | ||
1372 | impl<'tcx> Pick<'tcx> { | |
1373 | /// In case there were unstable name collisions, emit them as a lint. | |
1374 | /// Checks whether two picks do not refer to the same trait item for the same `Self` type. | |
1375 | /// Only useful for comparisons of picks in order to improve diagnostics. | |
1376 | /// Do not use for type checking. | |
1377 | pub fn differs_from(&self, other: &Self) -> bool { | |
1378 | let Self { | |
1379 | item: | |
1380 | AssocItem { | |
1381 | def_id, | |
1382 | name: _, | |
1383 | kind: _, | |
1384 | container: _, | |
1385 | trait_item_def_id: _, | |
1386 | fn_has_self_parameter: _, | |
1387 | }, | |
1388 | kind: _, | |
1389 | import_ids: _, | |
1390 | autoderefs: _, | |
1391 | autoref_or_ptr_adjustment: _, | |
1392 | self_ty, | |
1393 | unstable_candidates: _, | |
1394 | } = *self; | |
1395 | self_ty != other.self_ty || def_id != other.item.def_id | |
1396 | } | |
ea8adc8c | 1397 | |
487cf647 FG |
1398 | /// In case there were unstable name collisions, emit them as a lint. |
1399 | pub fn maybe_emit_unstable_name_collision_hint( | |
0531ce1d | 1400 | &self, |
487cf647 FG |
1401 | tcx: TyCtxt<'tcx>, |
1402 | span: Span, | |
1403 | scope_expr_id: hir::HirId, | |
0531ce1d | 1404 | ) { |
487cf647 FG |
1405 | if self.unstable_candidates.is_empty() { |
1406 | return; | |
1407 | } | |
1408 | let def_kind = self.item.kind.as_def_kind(); | |
1409 | tcx.struct_span_lint_hir( | |
83c7162d | 1410 | lint::builtin::UNSTABLE_NAME_COLLISIONS, |
487cf647 FG |
1411 | scope_expr_id, |
1412 | span, | |
2b03887a FG |
1413 | format!( |
1414 | "{} {} with this name may be added to the standard library in the future", | |
1415 | def_kind.article(), | |
487cf647 | 1416 | def_kind.descr(self.item.def_id), |
2b03887a | 1417 | ), |
74b04a01 | 1418 | |lint| { |
487cf647 | 1419 | match (self.item.kind, self.item.container) { |
6a06907d XL |
1420 | (ty::AssocKind::Fn, _) => { |
1421 | // FIXME: This should be a `span_suggestion` instead of `help` | |
1422 | // However `self.span` only | |
1423 | // highlights the method name, so we can't use it. Also consider reusing | |
1424 | // the code from `report_method_error()`. | |
2b03887a | 1425 | lint.help(&format!( |
6a06907d XL |
1426 | "call with fully qualified syntax `{}(...)` to keep using the current \ |
1427 | method", | |
487cf647 | 1428 | tcx.def_path_str(self.item.def_id), |
6a06907d XL |
1429 | )); |
1430 | } | |
064997fb | 1431 | (ty::AssocKind::Const, ty::AssocItemContainer::TraitContainer) => { |
487cf647 | 1432 | let def_id = self.item.container_id(tcx); |
2b03887a | 1433 | lint.span_suggestion( |
487cf647 | 1434 | span, |
6a06907d XL |
1435 | "use the fully qualified path to the associated const", |
1436 | format!( | |
1437 | "<{} as {}>::{}", | |
487cf647 FG |
1438 | self.self_ty, |
1439 | tcx.def_path_str(def_id), | |
1440 | self.item.name | |
6a06907d XL |
1441 | ), |
1442 | Applicability::MachineApplicable, | |
1443 | ); | |
1444 | } | |
1445 | _ => {} | |
1446 | } | |
487cf647 FG |
1447 | if tcx.sess.is_nightly_build() { |
1448 | for (candidate, feature) in &self.unstable_candidates { | |
2b03887a | 1449 | lint.help(&format!( |
74b04a01 XL |
1450 | "add `#![feature({})]` to the crate attributes to enable `{}`", |
1451 | feature, | |
487cf647 | 1452 | tcx.def_path_str(candidate.item.def_id), |
74b04a01 XL |
1453 | )); |
1454 | } | |
1455 | } | |
1456 | ||
2b03887a | 1457 | lint |
74b04a01 XL |
1458 | }, |
1459 | ); | |
0531ce1d | 1460 | } |
487cf647 | 1461 | } |
0531ce1d | 1462 | |
487cf647 | 1463 | impl<'a, 'tcx> ProbeContext<'a, 'tcx> { |
dfeec247 XL |
1464 | fn select_trait_candidate( |
1465 | &self, | |
1466 | trait_ref: ty::TraitRef<'tcx>, | |
1467 | ) -> traits::SelectionResult<'tcx, traits::Selection<'tcx>> { | |
ea8adc8c | 1468 | let cause = traits::ObligationCause::misc(self.span, self.body_id); |
487cf647 FG |
1469 | let predicate = ty::Binder::dummy(trait_ref); |
1470 | let obligation = traits::Obligation::new(self.tcx, cause, self.param_env, predicate); | |
ea8adc8c XL |
1471 | traits::SelectionContext::new(self).select(&obligation) |
1472 | } | |
1473 | ||
dfeec247 | 1474 | fn candidate_source(&self, candidate: &Candidate<'tcx>, self_ty: Ty<'tcx>) -> CandidateSource { |
ea8adc8c | 1475 | match candidate.kind { |
064997fb FG |
1476 | InherentImplCandidate(..) => { |
1477 | CandidateSource::Impl(candidate.item.container_id(self.tcx)) | |
1478 | } | |
04454e1e | 1479 | ObjectCandidate | WhereClauseCandidate(_) => { |
064997fb | 1480 | CandidateSource::Trait(candidate.item.container_id(self.tcx)) |
04454e1e | 1481 | } |
ea8adc8c | 1482 | TraitCandidate(trait_ref) => self.probe(|_| { |
dfeec247 XL |
1483 | let _ = self |
1484 | .at(&ObligationCause::dummy(), self.param_env) | |
5e7ed085 | 1485 | .define_opaque_types(false) |
ea8adc8c XL |
1486 | .sup(candidate.xform_self_ty, self_ty); |
1487 | match self.select_trait_candidate(trait_ref) { | |
1b1a35ee | 1488 | Ok(Some(traits::ImplSource::UserDefined(ref impl_data))) => { |
ea8adc8c XL |
1489 | // If only a single impl matches, make the error message point |
1490 | // to that impl. | |
04454e1e | 1491 | CandidateSource::Impl(impl_data.impl_def_id) |
ea8adc8c | 1492 | } |
064997fb | 1493 | _ => CandidateSource::Trait(candidate.item.container_id(self.tcx)), |
ea8adc8c | 1494 | } |
dfeec247 | 1495 | }), |
ea8adc8c | 1496 | } |
1a4d82fc JJ |
1497 | } |
1498 | ||
dfeec247 XL |
1499 | fn consider_probe( |
1500 | &self, | |
1501 | self_ty: Ty<'tcx>, | |
1502 | probe: &Candidate<'tcx>, | |
74b04a01 XL |
1503 | possibly_unsatisfied_predicates: &mut Vec<( |
1504 | ty::Predicate<'tcx>, | |
1505 | Option<ty::Predicate<'tcx>>, | |
3c0e092e | 1506 | Option<ObligationCause<'tcx>>, |
74b04a01 | 1507 | )>, |
dfeec247 | 1508 | ) -> ProbeResult { |
c30ab7b3 | 1509 | debug!("consider_probe: self_ty={:?} probe={:?}", self_ty, probe); |
1a4d82fc | 1510 | |
a7813a04 | 1511 | self.probe(|_| { |
1a4d82fc | 1512 | // First check that the self type can be related. |
dfeec247 XL |
1513 | let sub_obligations = match self |
1514 | .at(&ObligationCause::dummy(), self.param_env) | |
5e7ed085 | 1515 | .define_opaque_types(false) |
dfeec247 XL |
1516 | .sup(probe.xform_self_ty, self_ty) |
1517 | { | |
cc61c64b | 1518 | Ok(InferOk { obligations, value: () }) => obligations, |
3c0e092e XL |
1519 | Err(err) => { |
1520 | debug!("--> cannot relate self-types {:?}", err); | |
ea8adc8c | 1521 | return ProbeResult::NoMatch; |
1a4d82fc | 1522 | } |
cc61c64b | 1523 | }; |
1a4d82fc | 1524 | |
ea8adc8c | 1525 | let mut result = ProbeResult::Match; |
c295e0f8 XL |
1526 | let mut xform_ret_ty = probe.xform_ret_ty; |
1527 | debug!(?xform_ret_ty); | |
1528 | ||
ea8adc8c XL |
1529 | let cause = traits::ObligationCause::misc(self.span, self.body_id); |
1530 | ||
5e7ed085 FG |
1531 | let mut parent_pred = None; |
1532 | ||
1a4d82fc JJ |
1533 | // If so, impls may carry other conditions (e.g., where |
1534 | // clauses) that must be considered. Make sure that those | |
1535 | // match as well (or at least may match, sometimes we | |
1536 | // don't have enough information to fully evaluate). | |
ba9703b0 | 1537 | match probe.kind { |
c1a9b12d | 1538 | InherentImplCandidate(ref substs, ref ref_obligations) => { |
c295e0f8 XL |
1539 | // `xform_ret_ty` hasn't been normalized yet, only `xform_self_ty`, |
1540 | // see the reasons mentioned in the comments in `assemble_inherent_impl_probe` | |
1541 | // for why this is necessary | |
487cf647 | 1542 | let InferOk { |
c295e0f8 XL |
1543 | value: normalized_xform_ret_ty, |
1544 | obligations: normalization_obligations, | |
9c376795 | 1545 | } = self.fcx.at(&cause, self.param_env).normalize(xform_ret_ty); |
c295e0f8 XL |
1546 | xform_ret_ty = normalized_xform_ret_ty; |
1547 | debug!("xform_ret_ty after normalization: {:?}", xform_ret_ty); | |
1548 | ||
ea8adc8c | 1549 | // Check whether the impl imposes obligations we have to worry about. |
064997fb | 1550 | let impl_def_id = probe.item.container_id(self.tcx); |
ea8adc8c XL |
1551 | let impl_bounds = self.tcx.predicates_of(impl_def_id); |
1552 | let impl_bounds = impl_bounds.instantiate(self.tcx, substs); | |
487cf647 FG |
1553 | |
1554 | let InferOk { value: impl_bounds, obligations: norm_obligations } = | |
1555 | self.fcx.at(&cause, self.param_env).normalize(impl_bounds); | |
ea8adc8c XL |
1556 | |
1557 | // Convert the bounds into obligations. | |
f2b60f7d | 1558 | let impl_obligations = traits::predicates_for_generics( |
9c376795 FG |
1559 | |_idx, span| { |
1560 | let misc = traits::ObligationCause::misc(span, self.body_id); | |
1561 | let parent_trait_pred = ty::Binder::dummy(ty::TraitPredicate { | |
1562 | trait_ref: ty::TraitRef::from_method(self.tcx, impl_def_id, substs), | |
1563 | constness: ty::BoundConstness::NotConst, | |
1564 | polarity: ty::ImplPolarity::Positive, | |
1565 | }); | |
1566 | misc.derived_cause(parent_trait_pred, |derived| { | |
1567 | traits::ImplDerivedObligation(Box::new( | |
1568 | traits::ImplDerivedObligationCause { | |
1569 | derived, | |
1570 | impl_def_id, | |
1571 | span, | |
1572 | }, | |
1573 | )) | |
1574 | }) | |
1575 | }, | |
f2b60f7d FG |
1576 | self.param_env, |
1577 | impl_bounds, | |
1578 | ); | |
ea8adc8c | 1579 | |
ba9703b0 | 1580 | let candidate_obligations = impl_obligations |
ea8adc8c | 1581 | .chain(norm_obligations.into_iter()) |
c295e0f8 XL |
1582 | .chain(ref_obligations.iter().cloned()) |
1583 | .chain(normalization_obligations.into_iter()); | |
1584 | ||
ba9703b0 XL |
1585 | // Evaluate those obligations to see if they might possibly hold. |
1586 | for o in candidate_obligations { | |
fc512014 | 1587 | let o = self.resolve_vars_if_possible(o); |
ba9703b0 XL |
1588 | if !self.predicate_may_hold(&o) { |
1589 | result = ProbeResult::NoMatch; | |
9c376795 FG |
1590 | let parent_o = o.clone(); |
1591 | let implied_obligations = | |
1592 | traits::elaborate_obligations(self.tcx, vec![o]); | |
1593 | for o in implied_obligations { | |
1594 | let parent = if o == parent_o { | |
1595 | None | |
1596 | } else { | |
1597 | if o.predicate.to_opt_poly_trait_pred().map(|p| p.def_id()) | |
1598 | == self.tcx.lang_items().sized_trait() | |
1599 | { | |
1600 | // We don't care to talk about implicit `Sized` bounds. | |
1601 | continue; | |
1602 | } | |
1603 | Some(parent_o.predicate) | |
1604 | }; | |
1605 | if !self.predicate_may_hold(&o) { | |
1606 | possibly_unsatisfied_predicates.push(( | |
1607 | o.predicate, | |
1608 | parent, | |
1609 | Some(o.cause), | |
1610 | )); | |
1611 | } | |
1612 | } | |
ba9703b0 XL |
1613 | } |
1614 | } | |
1a4d82fc JJ |
1615 | } |
1616 | ||
dfeec247 | 1617 | ObjectCandidate | WhereClauseCandidate(..) => { |
1a4d82fc | 1618 | // These have no additional conditions to check. |
c1a9b12d | 1619 | } |
c1a9b12d | 1620 | |
ea8adc8c | 1621 | TraitCandidate(trait_ref) => { |
cdc7bbd5 XL |
1622 | if let Some(method_name) = self.method_name { |
1623 | // Some trait methods are excluded for arrays before 2021. | |
1624 | // (`array.into_iter()` wants a slice iterator for compatibility.) | |
1625 | if self_ty.is_array() && !method_name.span.rust_2021() { | |
1626 | let trait_def = self.tcx.trait_def(trait_ref.def_id); | |
1627 | if trait_def.skip_array_during_method_dispatch { | |
1628 | return ProbeResult::NoMatch; | |
1629 | } | |
1630 | } | |
1631 | } | |
c295e0f8 XL |
1632 | let predicate = |
1633 | ty::Binder::dummy(trait_ref).without_const().to_predicate(self.tcx); | |
5e7ed085 | 1634 | parent_pred = Some(predicate); |
487cf647 | 1635 | let obligation = |
9c376795 | 1636 | traits::Obligation::new(self.tcx, cause.clone(), self.param_env, predicate); |
83c7162d | 1637 | if !self.predicate_may_hold(&obligation) { |
74b04a01 XL |
1638 | result = ProbeResult::NoMatch; |
1639 | if self.probe(|_| { | |
1640 | match self.select_trait_candidate(trait_ref) { | |
1641 | Err(_) => return true, | |
f035d41b XL |
1642 | Ok(Some(impl_source)) |
1643 | if !impl_source.borrow_nested_obligations().is_empty() => | |
74b04a01 | 1644 | { |
f035d41b | 1645 | for obligation in impl_source.borrow_nested_obligations() { |
74b04a01 XL |
1646 | // Determine exactly which obligation wasn't met, so |
1647 | // that we can give more context in the error. | |
fc512014 XL |
1648 | if !self.predicate_may_hold(obligation) { |
1649 | let nested_predicate = | |
1650 | self.resolve_vars_if_possible(obligation.predicate); | |
74b04a01 | 1651 | let predicate = |
fc512014 XL |
1652 | self.resolve_vars_if_possible(predicate); |
1653 | let p = if predicate == nested_predicate { | |
74b04a01 XL |
1654 | // Avoid "`MyStruct: Foo` which is required by |
1655 | // `MyStruct: Foo`" in E0599. | |
1656 | None | |
1657 | } else { | |
1658 | Some(predicate) | |
1659 | }; | |
3c0e092e XL |
1660 | possibly_unsatisfied_predicates.push(( |
1661 | nested_predicate, | |
1662 | p, | |
1663 | Some(obligation.cause.clone()), | |
1664 | )); | |
74b04a01 XL |
1665 | } |
1666 | } | |
1667 | } | |
1668 | _ => { | |
1669 | // Some nested subobligation of this predicate | |
1670 | // failed. | |
fc512014 | 1671 | let predicate = self.resolve_vars_if_possible(predicate); |
3c0e092e | 1672 | possibly_unsatisfied_predicates.push((predicate, None, None)); |
74b04a01 XL |
1673 | } |
1674 | } | |
1675 | false | |
1676 | }) { | |
ea8adc8c XL |
1677 | // This candidate's primary obligation doesn't even |
1678 | // select - don't bother registering anything in | |
1679 | // `potentially_unsatisfied_predicates`. | |
1680 | return ProbeResult::NoMatch; | |
ea8adc8c XL |
1681 | } |
1682 | } | |
ea8adc8c | 1683 | } |
ba9703b0 | 1684 | } |
c1a9b12d SL |
1685 | |
1686 | // Evaluate those obligations to see if they might possibly hold. | |
ba9703b0 | 1687 | for o in sub_obligations { |
fc512014 | 1688 | let o = self.resolve_vars_if_possible(o); |
83c7162d | 1689 | if !self.predicate_may_hold(&o) { |
ea8adc8c | 1690 | result = ProbeResult::NoMatch; |
5e7ed085 | 1691 | possibly_unsatisfied_predicates.push((o.predicate, parent_pred, Some(o.cause))); |
1a4d82fc JJ |
1692 | } |
1693 | } | |
ea8adc8c | 1694 | |
9c376795 FG |
1695 | if let ProbeResult::Match = result |
1696 | && let Some(return_ty) = self.return_type | |
1697 | && let Some(mut xform_ret_ty) = xform_ret_ty | |
1698 | { | |
1699 | // `xform_ret_ty` has only been normalized for `InherentImplCandidate`. | |
1700 | // We don't normalize the other candidates for perf/backwards-compat reasons... | |
1701 | // but `self.return_type` is only set on the diagnostic-path, so we | |
1702 | // should be okay doing it here. | |
1703 | if !matches!(probe.kind, InherentImplCandidate(..)) { | |
1704 | let InferOk { | |
1705 | value: normalized_xform_ret_ty, | |
1706 | obligations: normalization_obligations, | |
1707 | } = self.fcx.at(&cause, self.param_env).normalize(xform_ret_ty); | |
1708 | xform_ret_ty = normalized_xform_ret_ty; | |
1709 | debug!("xform_ret_ty after normalization: {:?}", xform_ret_ty); | |
1710 | // Evaluate those obligations to see if they might possibly hold. | |
1711 | for o in normalization_obligations { | |
1712 | let o = self.resolve_vars_if_possible(o); | |
1713 | if !self.predicate_may_hold(&o) { | |
1714 | result = ProbeResult::NoMatch; | |
1715 | possibly_unsatisfied_predicates.push(( | |
1716 | o.predicate, | |
1717 | None, | |
1718 | Some(o.cause), | |
1719 | )); | |
1720 | } | |
ea8adc8c XL |
1721 | } |
1722 | } | |
9c376795 FG |
1723 | |
1724 | debug!( | |
1725 | "comparing return_ty {:?} with xform ret ty {:?}", | |
1726 | return_ty, xform_ret_ty | |
1727 | ); | |
1728 | if let ProbeResult::Match = result | |
1729 | && self | |
1730 | .at(&ObligationCause::dummy(), self.param_env) | |
1731 | .define_opaque_types(false) | |
1732 | .sup(return_ty, xform_ret_ty) | |
1733 | .is_err() | |
1734 | { | |
1735 | result = ProbeResult::BadReturnType; | |
1736 | } | |
ea8adc8c XL |
1737 | } |
1738 | ||
1739 | result | |
1a4d82fc JJ |
1740 | }) |
1741 | } | |
1742 | ||
1743 | /// Sometimes we get in a situation where we have multiple probes that are all impls of the | |
1744 | /// same trait, but we don't know which impl to use. In this case, since in all cases the | |
1745 | /// external interface of the method can be determined from the trait, it's ok not to decide. | |
1746 | /// We can basically just collapse all of the probes for various impls into one where-clause | |
1747 | /// probe. This will result in a pending obligation so when more type-info is available we can | |
1748 | /// make the final decision. | |
1749 | /// | |
9c376795 | 1750 | /// Example (`tests/ui/method-two-trait-defer-resolution-1.rs`): |
1a4d82fc | 1751 | /// |
04454e1e | 1752 | /// ```ignore (illustrative) |
1a4d82fc | 1753 | /// trait Foo { ... } |
f035d41b | 1754 | /// impl Foo for Vec<i32> { ... } |
c34b1796 | 1755 | /// impl Foo for Vec<usize> { ... } |
1a4d82fc JJ |
1756 | /// ``` |
1757 | /// | |
1758 | /// Now imagine the receiver is `Vec<_>`. It doesn't really matter at this time which impl we | |
1759 | /// use, so it's ok to just commit to "using the method from the trait Foo". | |
dfeec247 XL |
1760 | fn collapse_candidates_to_trait_pick( |
1761 | &self, | |
3c0e092e | 1762 | self_ty: Ty<'tcx>, |
dfeec247 XL |
1763 | probes: &[(&Candidate<'tcx>, ProbeResult)], |
1764 | ) -> Option<Pick<'tcx>> { | |
1a4d82fc | 1765 | // Do all probes correspond to the same trait? |
064997fb FG |
1766 | let container = probes[0].0.item.trait_container(self.tcx)?; |
1767 | for (p, _) in &probes[1..] { | |
1768 | let p_container = p.item.trait_container(self.tcx)?; | |
1769 | if p_container != container { | |
1770 | return None; | |
1771 | } | |
1a4d82fc JJ |
1772 | } |
1773 | ||
ea8adc8c | 1774 | // FIXME: check the return type here somehow. |
1a4d82fc | 1775 | // If so, just use this trait and call it a day. |
1a4d82fc | 1776 | Some(Pick { |
dfeec247 | 1777 | item: probes[0].0.item, |
c1a9b12d | 1778 | kind: TraitPick, |
48663c56 | 1779 | import_ids: probes[0].0.import_ids.clone(), |
9346a6ac | 1780 | autoderefs: 0, |
6a06907d | 1781 | autoref_or_ptr_adjustment: None, |
3c0e092e | 1782 | self_ty, |
487cf647 | 1783 | unstable_candidates: vec![], |
1a4d82fc JJ |
1784 | }) |
1785 | } | |
1786 | ||
ea8adc8c | 1787 | /// Similarly to `probe_for_return_type`, this method attempts to find the best matching |
5e7ed085 | 1788 | /// candidate method where the method name may have been misspelled. Similarly to other |
ea8adc8c | 1789 | /// Levenshtein based suggestions, we provide at most one such suggestion. |
dc9dc135 | 1790 | fn probe_for_lev_candidate(&mut self) -> Result<Option<ty::AssocItem>, MethodError<'tcx>> { |
dfeec247 | 1791 | debug!("probing for method names similar to {:?}", self.method_name); |
ea8adc8c XL |
1792 | |
1793 | let steps = self.steps.clone(); | |
1794 | self.probe(|_| { | |
dfeec247 XL |
1795 | let mut pcx = ProbeContext::new( |
1796 | self.fcx, | |
1797 | self.span, | |
1798 | self.mode, | |
1799 | self.method_name, | |
1800 | self.return_type, | |
9c376795 | 1801 | &self.orig_steps_var_values, |
dfeec247 | 1802 | steps, |
cdc7bbd5 | 1803 | self.scope_expr_id, |
dfeec247 | 1804 | ); |
ea8adc8c XL |
1805 | pcx.allow_similar_names = true; |
1806 | pcx.assemble_inherent_candidates(); | |
ea8adc8c | 1807 | |
2b03887a | 1808 | let method_names = pcx.candidate_method_names(|_| true); |
ea8adc8c | 1809 | pcx.allow_similar_names = false; |
74b04a01 XL |
1810 | let applicable_close_candidates: Vec<ty::AssocItem> = method_names |
1811 | .iter() | |
1812 | .filter_map(|&method_name| { | |
1813 | pcx.reset(); | |
1814 | pcx.method_name = Some(method_name); | |
1815 | pcx.assemble_inherent_candidates(); | |
ba9703b0 | 1816 | pcx.pick_core().and_then(|pick| pick.ok()).map(|pick| pick.item) |
74b04a01 XL |
1817 | }) |
1818 | .collect(); | |
ea8adc8c XL |
1819 | |
1820 | if applicable_close_candidates.is_empty() { | |
1821 | Ok(None) | |
1822 | } else { | |
1823 | let best_name = { | |
fc512014 XL |
1824 | let names = applicable_close_candidates |
1825 | .iter() | |
5099ac24 | 1826 | .map(|cand| cand.name) |
fc512014 | 1827 | .collect::<Vec<Symbol>>(); |
04454e1e FG |
1828 | find_best_match_for_name_with_substrings( |
1829 | &names, | |
1830 | self.method_name.unwrap().name, | |
1831 | None, | |
1832 | ) | |
dfeec247 XL |
1833 | } |
1834 | .unwrap(); | |
5099ac24 | 1835 | Ok(applicable_close_candidates.into_iter().find(|method| method.name == best_name)) |
ea8adc8c XL |
1836 | } |
1837 | }) | |
1838 | } | |
1839 | ||
1a4d82fc JJ |
1840 | /////////////////////////////////////////////////////////////////////////// |
1841 | // MISCELLANY | |
dc9dc135 | 1842 | fn has_applicable_self(&self, item: &ty::AssocItem) -> bool { |
476ff2be SL |
1843 | // "Fast track" -- check for usage of sugar when in method call |
1844 | // mode. | |
1845 | // | |
1846 | // In Path mode (i.e., resolving a value like `T::next`), consider any | |
1847 | // associated value (i.e., methods, constants) but not types. | |
1848 | match self.mode { | |
ba9703b0 | 1849 | Mode::MethodCall => item.fn_has_self_parameter, |
476ff2be | 1850 | Mode::Path => match item.kind { |
f035d41b | 1851 | ty::AssocKind::Type => false, |
ba9703b0 | 1852 | ty::AssocKind::Fn | ty::AssocKind::Const => true, |
476ff2be | 1853 | }, |
1a4d82fc | 1854 | } |
1a4d82fc JJ |
1855 | // FIXME -- check for types that deref to `Self`, |
1856 | // like `Rc<Self>` and so on. | |
1857 | // | |
1858 | // Note also that the current code will break if this type | |
1859 | // includes any of the type parameters defined on the method | |
1860 | // -- but this could be overcome. | |
1a4d82fc JJ |
1861 | } |
1862 | ||
9c376795 FG |
1863 | fn record_static_candidate(&self, source: CandidateSource) { |
1864 | self.static_candidates.borrow_mut().push(source); | |
1a4d82fc JJ |
1865 | } |
1866 | ||
c295e0f8 | 1867 | #[instrument(level = "debug", skip(self))] |
dfeec247 XL |
1868 | fn xform_self_ty( |
1869 | &self, | |
1870 | item: &ty::AssocItem, | |
1871 | impl_ty: Ty<'tcx>, | |
1872 | substs: SubstsRef<'tcx>, | |
1873 | ) -> (Ty<'tcx>, Option<Ty<'tcx>>) { | |
ba9703b0 | 1874 | if item.kind == ty::AssocKind::Fn && self.mode == Mode::MethodCall { |
ea8adc8c XL |
1875 | let sig = self.xform_method_sig(item.def_id, substs); |
1876 | (sig.inputs()[0], Some(sig.output())) | |
476ff2be | 1877 | } else { |
ea8adc8c | 1878 | (impl_ty, None) |
d9579d0f AL |
1879 | } |
1880 | } | |
1881 | ||
c295e0f8 | 1882 | #[instrument(level = "debug", skip(self))] |
dfeec247 | 1883 | fn xform_method_sig(&self, method: DefId, substs: SubstsRef<'tcx>) -> ty::FnSig<'tcx> { |
04454e1e | 1884 | let fn_sig = self.tcx.bound_fn_sig(method); |
c295e0f8 | 1885 | debug!(?fn_sig); |
1a4d82fc | 1886 | |
a1dfa0c6 | 1887 | assert!(!substs.has_escaping_bound_vars()); |
1a4d82fc JJ |
1888 | |
1889 | // It is possible for type parameters or early-bound lifetimes | |
1890 | // to appear in the signature of `self`. The substitutions we | |
1891 | // are given do not include type/lifetime parameters for the | |
1892 | // method yet. So create fresh variables here for those too, | |
1893 | // if there are any. | |
7cac9316 | 1894 | let generics = self.tcx.generics_of(method); |
94b46f34 | 1895 | assert_eq!(substs.len(), generics.parent_count as usize); |
c34b1796 | 1896 | |
04454e1e FG |
1897 | let xform_fn_sig = if generics.params.is_empty() { |
1898 | fn_sig.subst(self.tcx, substs) | |
9e0c209e | 1899 | } else { |
532ac7d7 | 1900 | let substs = InternalSubsts::for_item(self.tcx, method, |param, _| { |
94b46f34 | 1901 | let i = param.index as usize; |
8bb4bdeb | 1902 | if i < substs.len() { |
94b46f34 | 1903 | substs[i] |
9e0c209e | 1904 | } else { |
94b46f34 XL |
1905 | match param.kind { |
1906 | GenericParamDefKind::Lifetime => { | |
ba9703b0 | 1907 | // In general, during probe we erase regions. |
48663c56 | 1908 | self.tcx.lifetimes.re_erased.into() |
94b46f34 | 1909 | } |
cdc7bbd5 | 1910 | GenericParamDefKind::Type { .. } | GenericParamDefKind::Const { .. } => { |
532ac7d7 XL |
1911 | self.var_for_def(self.span, param) |
1912 | } | |
94b46f34 | 1913 | } |
9e0c209e SL |
1914 | } |
1915 | }); | |
04454e1e FG |
1916 | fn_sig.subst(self.tcx, substs) |
1917 | }; | |
1918 | ||
1919 | self.erase_late_bound_regions(xform_fn_sig) | |
1a4d82fc JJ |
1920 | } |
1921 | ||
064997fb FG |
1922 | /// Gets the type of an impl and generate substitutions with inference vars. |
1923 | fn impl_ty_and_substs( | |
1924 | &self, | |
1925 | impl_def_id: DefId, | |
1926 | ) -> (ty::EarlyBinder<Ty<'tcx>>, SubstsRef<'tcx>) { | |
1927 | (self.tcx.bound_type_of(impl_def_id), self.fresh_item_substs(impl_def_id)) | |
ea8adc8c | 1928 | } |
1a4d82fc | 1929 | |
532ac7d7 | 1930 | fn fresh_item_substs(&self, def_id: DefId) -> SubstsRef<'tcx> { |
dfeec247 XL |
1931 | InternalSubsts::for_item(self.tcx, def_id, |param, _| match param.kind { |
1932 | GenericParamDefKind::Lifetime => self.tcx.lifetimes.re_erased.into(), | |
1933 | GenericParamDefKind::Type { .. } => self | |
1934 | .next_ty_var(TypeVariableOrigin { | |
1935 | kind: TypeVariableOriginKind::SubstitutionPlaceholder, | |
1936 | span: self.tcx.def_span(def_id), | |
1937 | }) | |
1938 | .into(), | |
1939 | GenericParamDefKind::Const { .. } => { | |
1940 | let span = self.tcx.def_span(def_id); | |
1941 | let origin = ConstVariableOrigin { | |
1942 | kind: ConstVariableOriginKind::SubstitutionPlaceholder, | |
1943 | span, | |
1944 | }; | |
1945 | self.next_const_var(self.tcx.type_of(param.def_id), origin).into() | |
94b46f34 XL |
1946 | } |
1947 | }) | |
1a4d82fc JJ |
1948 | } |
1949 | ||
9fa01778 | 1950 | /// Replaces late-bound-regions bound by `value` with `'static` using |
1a4d82fc JJ |
1951 | /// `ty::erase_late_bound_regions`. |
1952 | /// | |
1953 | /// This is only a reasonable thing to do during the *probe* phase, not the *confirm* phase, of | |
1954 | /// method matching. It is reasonable during the probe phase because we don't consider region | |
1955 | /// relationships at all. Therefore, we can just replace all the region variables with 'static | |
1956 | /// rather than creating fresh region variables. This is nice for two reasons: | |
1957 | /// | |
1958 | /// 1. Because the numbers of the region variables would otherwise be fairly unique to this | |
1959 | /// particular method call, it winds up creating fewer types overall, which helps for memory | |
a1dfa0c6 | 1960 | /// usage. (Admittedly, this is a rather small effect, though measurable.) |
1a4d82fc JJ |
1961 | /// |
1962 | /// 2. It makes it easier to deal with higher-ranked trait bounds, because we can replace any | |
1963 | /// late-bound regions with 'static. Otherwise, if we were going to replace late-bound | |
1964 | /// regions with actual region variables as is proper, we'd have to ensure that the same | |
1965 | /// region got replaced with the same variable, which requires a bit more coordination | |
1966 | /// and/or tracking the substitution and | |
1967 | /// so forth. | |
cdc7bbd5 | 1968 | fn erase_late_bound_regions<T>(&self, value: ty::Binder<'tcx, T>) -> T |
dfeec247 XL |
1969 | where |
1970 | T: TypeFoldable<'tcx>, | |
1a4d82fc | 1971 | { |
a7813a04 | 1972 | self.tcx.erase_late_bound_regions(value) |
1a4d82fc | 1973 | } |
1a4d82fc | 1974 | |
487cf647 FG |
1975 | /// Determine if the given associated item type is relevant in the current context. |
1976 | fn is_relevant_kind_for_mode(&self, kind: ty::AssocKind) -> bool { | |
1977 | match (self.mode, kind) { | |
1978 | (Mode::MethodCall, ty::AssocKind::Fn) => true, | |
1979 | (Mode::Path, ty::AssocKind::Const | ty::AssocKind::Fn) => true, | |
1980 | _ => false, | |
1981 | } | |
1982 | } | |
1983 | ||
9fa01778 | 1984 | /// Finds the method with the appropriate name (or return type, as the case may be). If |
ea8adc8c | 1985 | /// `allow_similar_names` is set, find methods with close-matching names. |
cdc7bbd5 XL |
1986 | // The length of the returned iterator is nearly always 0 or 1 and this |
1987 | // method is fairly hot. | |
1988 | fn impl_or_trait_item(&self, def_id: DefId) -> SmallVec<[ty::AssocItem; 1]> { | |
ea8adc8c XL |
1989 | if let Some(name) = self.method_name { |
1990 | if self.allow_similar_names { | |
1991 | let max_dist = max(name.as_str().len(), 3) / 3; | |
dfeec247 XL |
1992 | self.tcx |
1993 | .associated_items(def_id) | |
74b04a01 | 1994 | .in_definition_order() |
ea8adc8c | 1995 | .filter(|x| { |
487cf647 | 1996 | if !self.is_relevant_kind_for_mode(x.kind) { |
5099ac24 FG |
1997 | return false; |
1998 | } | |
04454e1e FG |
1999 | match lev_distance_with_substrings(name.as_str(), x.name.as_str(), max_dist) |
2000 | { | |
5099ac24 FG |
2001 | Some(d) => d > 0, |
2002 | None => false, | |
2003 | } | |
ea8adc8c | 2004 | }) |
74b04a01 | 2005 | .copied() |
32a655c1 | 2006 | .collect() |
ea8adc8c | 2007 | } else { |
abe05a73 | 2008 | self.fcx |
5099ac24 | 2009 | .associated_value(def_id, name) |
487cf647 | 2010 | .filter(|x| self.is_relevant_kind_for_mode(x.kind)) |
cdc7bbd5 | 2011 | .map_or_else(SmallVec::new, |x| SmallVec::from_buf([x])) |
32a655c1 | 2012 | } |
ea8adc8c | 2013 | } else { |
487cf647 FG |
2014 | self.tcx |
2015 | .associated_items(def_id) | |
2016 | .in_definition_order() | |
2017 | .filter(|x| self.is_relevant_kind_for_mode(x.kind)) | |
2018 | .copied() | |
2019 | .collect() | |
32a655c1 | 2020 | } |
a7813a04 | 2021 | } |
1a4d82fc JJ |
2022 | } |
2023 | ||
2024 | impl<'tcx> Candidate<'tcx> { | |
487cf647 FG |
2025 | fn to_unadjusted_pick( |
2026 | &self, | |
2027 | self_ty: Ty<'tcx>, | |
2028 | unstable_candidates: Vec<(Candidate<'tcx>, Symbol)>, | |
2029 | ) -> Pick<'tcx> { | |
1a4d82fc | 2030 | Pick { |
dfeec247 | 2031 | item: self.item, |
1a4d82fc | 2032 | kind: match self.kind { |
9e0c209e | 2033 | InherentImplCandidate(..) => InherentImplPick, |
c1a9b12d | 2034 | ObjectCandidate => ObjectPick, |
ea8adc8c | 2035 | TraitCandidate(_) => TraitPick, |
c1a9b12d | 2036 | WhereClauseCandidate(ref trait_ref) => { |
1a4d82fc JJ |
2037 | // Only trait derived from where-clauses should |
2038 | // appear here, so they should not contain any | |
2039 | // inference variables or other artifacts. This | |
2040 | // means they are safe to put into the | |
2041 | // `WhereClausePick`. | |
83c7162d XL |
2042 | assert!( |
2043 | !trait_ref.skip_binder().substs.needs_infer() | |
a1dfa0c6 | 2044 | && !trait_ref.skip_binder().substs.has_placeholders() |
83c7162d | 2045 | ); |
1a4d82fc | 2046 | |
dfeec247 | 2047 | WhereClausePick(*trait_ref) |
1a4d82fc | 2048 | } |
9346a6ac | 2049 | }, |
48663c56 | 2050 | import_ids: self.import_ids.clone(), |
9346a6ac | 2051 | autoderefs: 0, |
6a06907d | 2052 | autoref_or_ptr_adjustment: None, |
3c0e092e | 2053 | self_ty, |
487cf647 | 2054 | unstable_candidates, |
1a4d82fc JJ |
2055 | } |
2056 | } | |
1a4d82fc | 2057 | } |