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