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