]>
Commit | Line | Data |
---|---|---|
ba9703b0 | 1 | //! Method lookup: the secret sauce of Rust. See the [rustc dev guide] for more information. |
0531ce1d | 2 | //! |
ba9703b0 | 3 | //! [rustc dev guide]: https://rustc-dev-guide.rust-lang.org/method-lookup.html |
1a4d82fc | 4 | |
0731742a | 5 | mod confirm; |
136023e0 | 6 | mod prelude2021; |
0731742a XL |
7 | pub mod probe; |
8 | mod suggest; | |
9 | ||
a2a8927a | 10 | pub use self::suggest::SelfSource; |
dfeec247 | 11 | pub use self::MethodError::*; |
0731742a | 12 | |
487cf647 | 13 | use crate::errors::OpMethodGenericParams; |
9c376795 | 14 | use crate::FnCtxt; |
dfeec247 | 15 | use rustc_data_structures::sync::Lrc; |
5e7ed085 | 16 | use rustc_errors::{Applicability, Diagnostic}; |
dfeec247 | 17 | use rustc_hir as hir; |
74b04a01 | 18 | use rustc_hir::def::{CtorOf, DefKind, Namespace}; |
dfeec247 | 19 | use rustc_hir::def_id::DefId; |
74b04a01 | 20 | use rustc_infer::infer::{self, InferOk}; |
2b03887a | 21 | use rustc_middle::traits::ObligationCause; |
ba9703b0 | 22 | use rustc_middle::ty::subst::{InternalSubsts, SubstsRef}; |
487cf647 | 23 | use rustc_middle::ty::{self, GenericParamDefKind, Ty, TypeVisitable}; |
f9f354fc | 24 | use rustc_span::symbol::Ident; |
dfeec247 | 25 | use rustc_span::Span; |
ba9703b0 | 26 | use rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt; |
487cf647 | 27 | use rustc_trait_selection::traits::{self, NormalizeExt}; |
1a4d82fc | 28 | |
3b2f2976 | 29 | use self::probe::{IsSuggestion, ProbeScope}; |
32a655c1 | 30 | |
f035d41b | 31 | pub fn provide(providers: &mut ty::query::Providers) { |
0731742a | 32 | probe::provide(providers); |
83c7162d XL |
33 | } |
34 | ||
7cac9316 XL |
35 | #[derive(Clone, Copy, Debug)] |
36 | pub struct MethodCallee<'tcx> { | |
37 | /// Impl method ID, for inherent methods, or trait method ID, otherwise. | |
38 | pub def_id: DefId, | |
532ac7d7 | 39 | pub substs: SubstsRef<'tcx>, |
7cac9316 | 40 | |
0731742a | 41 | /// Instantiated method signature, i.e., it has been |
7cac9316 XL |
42 | /// substituted, normalized, and has had late-bound |
43 | /// lifetimes replaced with inference variables. | |
44 | pub sig: ty::FnSig<'tcx>, | |
45 | } | |
46 | ||
cdc7bbd5 | 47 | #[derive(Debug)] |
62682a34 SL |
48 | pub enum MethodError<'tcx> { |
49 | // Did not find an applicable method, but we did find various near-misses that may work. | |
50 | NoMatch(NoMatchData<'tcx>), | |
1a4d82fc JJ |
51 | |
52 | // Multiple methods might apply. | |
53 | Ambiguity(Vec<CandidateSource>), | |
85aaf69f | 54 | |
48663c56 | 55 | // Found an applicable method, but it is not visible. The third argument contains a list of |
3b2f2976 | 56 | // not-in-scope traits which may work. |
48663c56 | 57 | PrivateMatch(DefKind, DefId, Vec<DefId>), |
3b2f2976 | 58 | |
487cf647 | 59 | // Found a `Self: Sized` bound where `Self` is a trait object. |
9c376795 FG |
60 | IllegalSizedBound { |
61 | candidates: Vec<DefId>, | |
62 | needs_mut: bool, | |
63 | bound_span: Span, | |
64 | self_expr: &'tcx hir::Expr<'tcx>, | |
65 | }, | |
ea8adc8c XL |
66 | |
67 | // Found a match, but the return type is wrong | |
68 | BadReturnType, | |
1a4d82fc JJ |
69 | } |
70 | ||
62682a34 SL |
71 | // Contains a list of static methods that may apply, a list of unsatisfied trait predicates which |
72 | // could lead to matches if satisfied, and a list of not-in-scope traits which may work. | |
cdc7bbd5 | 73 | #[derive(Debug)] |
62682a34 SL |
74 | pub struct NoMatchData<'tcx> { |
75 | pub static_candidates: Vec<CandidateSource>, | |
3c0e092e XL |
76 | pub unsatisfied_predicates: |
77 | Vec<(ty::Predicate<'tcx>, Option<ty::Predicate<'tcx>>, Option<ObligationCause<'tcx>>)>, | |
e9174d1e | 78 | pub out_of_scope_traits: Vec<DefId>, |
dc9dc135 | 79 | pub lev_candidate: Option<ty::AssocItem>, |
c30ab7b3 | 80 | pub mode: probe::Mode, |
62682a34 SL |
81 | } |
82 | ||
1a4d82fc JJ |
83 | // A pared down enum describing just the places from which a method |
84 | // candidate can arise. Used for error reporting only. | |
62682a34 | 85 | #[derive(Copy, Clone, Debug, Eq, Ord, PartialEq, PartialOrd)] |
1a4d82fc | 86 | pub enum CandidateSource { |
04454e1e FG |
87 | Impl(DefId), |
88 | Trait(DefId /* trait id */), | |
1a4d82fc JJ |
89 | } |
90 | ||
dc9dc135 | 91 | impl<'a, 'tcx> FnCtxt<'a, 'tcx> { |
a7813a04 | 92 | /// Determines whether the type `self_ty` supports a method name `method_name` or not. |
5869c6ff | 93 | #[instrument(level = "debug", skip(self))] |
dfeec247 XL |
94 | pub fn method_exists( |
95 | &self, | |
f9f354fc | 96 | method_name: Ident, |
dfeec247 XL |
97 | self_ty: Ty<'tcx>, |
98 | call_expr_id: hir::HirId, | |
99 | allow_private: bool, | |
9c376795 | 100 | return_type: Option<Ty<'tcx>>, |
dfeec247 | 101 | ) -> bool { |
dfeec247 | 102 | match self.probe_for_name( |
487cf647 | 103 | probe::Mode::MethodCall, |
dfeec247 | 104 | method_name, |
9c376795 | 105 | return_type, |
dfeec247 XL |
106 | IsSuggestion(false), |
107 | self_ty, | |
108 | call_expr_id, | |
109 | ProbeScope::TraitsInScope, | |
110 | ) { | |
487cf647 FG |
111 | Ok(pick) => { |
112 | pick.maybe_emit_unstable_name_collision_hint( | |
113 | self.tcx, | |
114 | method_name.span, | |
115 | call_expr_id, | |
116 | ); | |
117 | true | |
118 | } | |
a7813a04 XL |
119 | Err(NoMatch(..)) => false, |
120 | Err(Ambiguity(..)) => true, | |
a7813a04 | 121 | Err(PrivateMatch(..)) => allow_private, |
9c376795 FG |
122 | Err(IllegalSizedBound { .. }) => true, |
123 | Err(BadReturnType) => false, | |
a7813a04 | 124 | } |
1a4d82fc | 125 | } |
1a4d82fc | 126 | |
9fa01778 | 127 | /// Adds a suggestion to call the given method to the provided diagnostic. |
5869c6ff | 128 | #[instrument(level = "debug", skip(self, err, call_expr))] |
923072b8 | 129 | pub(crate) fn suggest_method_call( |
0731742a | 130 | &self, |
5e7ed085 | 131 | err: &mut Diagnostic, |
0731742a | 132 | msg: &str, |
f9f354fc | 133 | method_name: Ident, |
0731742a | 134 | self_ty: Ty<'tcx>, |
9c376795 | 135 | call_expr: &hir::Expr<'tcx>, |
c295e0f8 | 136 | span: Option<Span>, |
0731742a | 137 | ) { |
ba9703b0 | 138 | let params = self |
9c376795 | 139 | .lookup_probe_for_diagnostic( |
0731742a | 140 | method_name, |
0731742a | 141 | self_ty, |
9c376795 | 142 | call_expr, |
0731742a | 143 | ProbeScope::TraitsInScope, |
9c376795 | 144 | None, |
0731742a | 145 | ) |
ba9703b0 | 146 | .map(|pick| { |
0731742a | 147 | let sig = self.tcx.fn_sig(pick.item.def_id); |
ba9703b0 XL |
148 | sig.inputs().skip_binder().len().saturating_sub(1) |
149 | }) | |
150 | .unwrap_or(0); | |
0731742a | 151 | |
74b04a01 | 152 | // Account for `foo.bar<T>`; |
c295e0f8 | 153 | let sugg_span = span.unwrap_or(call_expr.span).shrink_to_hi(); |
ba9703b0 XL |
154 | let (suggestion, applicability) = ( |
155 | format!("({})", (0..params).map(|_| "_").collect::<Vec<_>>().join(", ")), | |
156 | if params > 0 { Applicability::HasPlaceholders } else { Applicability::MaybeIncorrect }, | |
157 | ); | |
0731742a | 158 | |
ba9703b0 | 159 | err.span_suggestion_verbose(sugg_span, msg, suggestion, applicability); |
0731742a XL |
160 | } |
161 | ||
a7813a04 XL |
162 | /// Performs method lookup. If lookup is successful, it will return the callee |
163 | /// and store an appropriate adjustment for the self-expr. In some cases it may | |
164 | /// report an error (e.g., invoking the `drop` method). | |
165 | /// | |
166 | /// # Arguments | |
167 | /// | |
136023e0 | 168 | /// Given a method call like `foo.bar::<T1,...Tn>(a, b + 1, ...)`: |
a7813a04 | 169 | /// |
ba9703b0 | 170 | /// * `self`: the surrounding `FnCtxt` (!) |
a7813a04 | 171 | /// * `self_ty`: the (unadjusted) type of the self expression (`foo`) |
ba9703b0 XL |
172 | /// * `segment`: the name and generic arguments of the method (`bar::<T1, ...Tn>`) |
173 | /// * `span`: the span for the method call | |
174 | /// * `call_expr`: the complete method call: (`foo.bar::<T1,...Tn>(...)`) | |
a7813a04 | 175 | /// * `self_expr`: the self expression (`foo`) |
136023e0 | 176 | /// * `args`: the expressions of the arguments (`a, b + 1, ...`) |
f2b60f7d | 177 | #[instrument(level = "debug", skip(self))] |
dc9dc135 XL |
178 | pub fn lookup_method( |
179 | &self, | |
180 | self_ty: Ty<'tcx>, | |
dfeec247 | 181 | segment: &hir::PathSegment<'_>, |
dc9dc135 | 182 | span: Span, |
dfeec247 XL |
183 | call_expr: &'tcx hir::Expr<'tcx>, |
184 | self_expr: &'tcx hir::Expr<'tcx>, | |
136023e0 | 185 | args: &'tcx [hir::Expr<'tcx>], |
dc9dc135 | 186 | ) -> Result<MethodCallee<'tcx>, MethodError<'tcx>> { |
dfeec247 | 187 | let pick = |
487cf647 | 188 | self.lookup_probe(segment.ident, self_ty, call_expr, ProbeScope::TraitsInScope)?; |
a7813a04 | 189 | |
136023e0 XL |
190 | self.lint_dot_call_from_2018(self_ty, segment, span, call_expr, self_expr, &pick, args); |
191 | ||
48663c56 | 192 | for import_id in &pick.import_ids { |
f035d41b | 193 | debug!("used_trait_import: {:?}", import_id); |
3dfed10e | 194 | Lrc::get_mut(&mut self.typeck_results.borrow_mut().used_trait_imports) |
dfeec247 | 195 | .unwrap() |
f035d41b | 196 | .insert(*import_id); |
1a4d82fc JJ |
197 | } |
198 | ||
17df50a5 | 199 | self.tcx.check_stability(pick.item.def_id, Some(call_expr.hir_id), span, None); |
476ff2be | 200 | |
9c376795 | 201 | let result = self.confirm_method(span, self_expr, call_expr, self_ty, &pick, segment); |
5869c6ff | 202 | debug!("result = {:?}", result); |
3b2f2976 | 203 | |
74b04a01 | 204 | if let Some(span) = result.illegal_sized_bound { |
e74abb32 | 205 | let mut needs_mut = false; |
1b1a35ee | 206 | if let ty::Ref(region, t_type, mutability) = self_ty.kind() { |
dfeec247 XL |
207 | let trait_type = self |
208 | .tcx | |
5099ac24 | 209 | .mk_ref(*region, ty::TypeAndMut { ty: *t_type, mutbl: mutability.invert() }); |
e74abb32 XL |
210 | // We probe again to see if there might be a borrow mutability discrepancy. |
211 | match self.lookup_probe( | |
e74abb32 XL |
212 | segment.ident, |
213 | trait_type, | |
214 | call_expr, | |
dfeec247 | 215 | ProbeScope::TraitsInScope, |
e74abb32 | 216 | ) { |
487cf647 | 217 | Ok(ref new_pick) if pick.differs_from(new_pick) => { |
9c376795 | 218 | needs_mut = new_pick.self_ty.ref_mutability() != self_ty.ref_mutability(); |
e74abb32 XL |
219 | } |
220 | _ => {} | |
221 | } | |
222 | } | |
223 | ||
3b2f2976 | 224 | // We probe again, taking all traits into account (not only those in scope). |
9c376795 FG |
225 | let candidates = match self.lookup_probe_for_diagnostic( |
226 | segment.ident, | |
227 | self_ty, | |
228 | call_expr, | |
229 | ProbeScope::AllTraits, | |
230 | None, | |
231 | ) { | |
232 | // If we find a different result the caller probably forgot to import a trait. | |
233 | Ok(ref new_pick) if pick.differs_from(new_pick) => { | |
234 | vec![new_pick.item.container_id(self.tcx)] | |
235 | } | |
236 | Err(Ambiguity(ref sources)) => sources | |
237 | .iter() | |
238 | .filter_map(|source| { | |
239 | match *source { | |
240 | // Note: this cannot come from an inherent impl, | |
241 | // because the first probing succeeded. | |
242 | CandidateSource::Impl(def) => self.tcx.trait_id_of_impl(def), | |
243 | CandidateSource::Trait(_) => None, | |
244 | } | |
245 | }) | |
246 | .collect(), | |
247 | _ => Vec::new(), | |
248 | }; | |
249 | ||
250 | return Err(IllegalSizedBound { candidates, needs_mut, bound_span: span, self_expr }); | |
3b2f2976 XL |
251 | } |
252 | ||
253 | Ok(result.callee) | |
254 | } | |
255 | ||
5869c6ff | 256 | #[instrument(level = "debug", skip(self, call_expr))] |
e1599b0c | 257 | pub fn lookup_probe( |
dc9dc135 | 258 | &self, |
f9f354fc | 259 | method_name: Ident, |
dc9dc135 | 260 | self_ty: Ty<'tcx>, |
9c376795 | 261 | call_expr: &hir::Expr<'_>, |
dc9dc135 XL |
262 | scope: ProbeScope, |
263 | ) -> probe::PickResult<'tcx> { | |
487cf647 FG |
264 | let pick = self.probe_for_name( |
265 | probe::Mode::MethodCall, | |
dfeec247 | 266 | method_name, |
9c376795 | 267 | None, |
dfeec247 XL |
268 | IsSuggestion(false), |
269 | self_ty, | |
270 | call_expr.hir_id, | |
271 | scope, | |
487cf647 FG |
272 | )?; |
273 | pick.maybe_emit_unstable_name_collision_hint(self.tcx, method_name.span, call_expr.hir_id); | |
274 | Ok(pick) | |
c1a9b12d | 275 | } |
1a4d82fc | 276 | |
9c376795 | 277 | pub fn lookup_probe_for_diagnostic( |
dfeec247 | 278 | &self, |
9c376795 | 279 | method_name: Ident, |
dfeec247 | 280 | self_ty: Ty<'tcx>, |
9c376795 FG |
281 | call_expr: &hir::Expr<'_>, |
282 | scope: ProbeScope, | |
283 | return_type: Option<Ty<'tcx>>, | |
284 | ) -> probe::PickResult<'tcx> { | |
285 | let pick = self.probe_for_name( | |
286 | probe::Mode::MethodCall, | |
287 | method_name, | |
288 | return_type, | |
289 | IsSuggestion(true), | |
290 | self_ty, | |
291 | call_expr.hir_id, | |
292 | scope, | |
293 | )?; | |
294 | Ok(pick) | |
c295e0f8 XL |
295 | } |
296 | ||
9c376795 | 297 | pub(super) fn obligation_for_method( |
5e7ed085 | 298 | &self, |
9c376795 | 299 | cause: ObligationCause<'tcx>, |
5e7ed085 FG |
300 | trait_def_id: DefId, |
301 | self_ty: Ty<'tcx>, | |
9c376795 | 302 | opt_input_types: Option<&[Ty<'tcx>]>, |
5e7ed085 FG |
303 | ) -> (traits::Obligation<'tcx, ty::Predicate<'tcx>>, &'tcx ty::List<ty::subst::GenericArg<'tcx>>) |
304 | { | |
305 | // Construct a trait-reference `self_ty : Trait<input_tys>` | |
306 | let substs = InternalSubsts::for_item(self.tcx, trait_def_id, |param, _| { | |
307 | match param.kind { | |
308 | GenericParamDefKind::Lifetime | GenericParamDefKind::Const { .. } => {} | |
309 | GenericParamDefKind::Type { .. } => { | |
310 | if param.index == 0 { | |
311 | return self_ty.into(); | |
9c376795 FG |
312 | } else if let Some(input_types) = opt_input_types { |
313 | return input_types[param.index as usize - 1].into(); | |
5e7ed085 FG |
314 | } |
315 | } | |
316 | } | |
9c376795 | 317 | self.var_for_def(cause.span, param) |
5e7ed085 FG |
318 | }); |
319 | ||
9c376795 | 320 | let trait_ref = self.tcx.mk_trait_ref(trait_def_id, substs); |
5e7ed085 FG |
321 | |
322 | // Construct an obligation | |
323 | let poly_trait_ref = ty::Binder::dummy(trait_ref); | |
324 | ( | |
325 | traits::Obligation::new( | |
487cf647 | 326 | self.tcx, |
9c376795 | 327 | cause, |
5e7ed085 | 328 | self.param_env, |
9c376795 | 329 | poly_trait_ref.without_const(), |
5e7ed085 FG |
330 | ), |
331 | substs, | |
332 | ) | |
333 | } | |
334 | ||
c295e0f8 XL |
335 | /// `lookup_method_in_trait` is used for overloaded operators. |
336 | /// It does a very narrow slice of what the normal probe/confirm path does. | |
337 | /// In particular, it doesn't really do any probing: it simply constructs | |
338 | /// an obligation for a particular trait with the given self type and checks | |
339 | /// whether that trait is implemented. | |
9c376795 | 340 | #[instrument(level = "debug", skip(self))] |
c295e0f8 XL |
341 | pub(super) fn lookup_method_in_trait( |
342 | &self, | |
9c376795 | 343 | cause: ObligationCause<'tcx>, |
c295e0f8 XL |
344 | m_name: Ident, |
345 | trait_def_id: DefId, | |
346 | self_ty: Ty<'tcx>, | |
347 | opt_input_types: Option<&[Ty<'tcx>]>, | |
348 | ) -> Option<InferOk<'tcx, MethodCallee<'tcx>>> { | |
c295e0f8 | 349 | let (obligation, substs) = |
9c376795 FG |
350 | self.obligation_for_method(cause, trait_def_id, self_ty, opt_input_types); |
351 | self.construct_obligation_for_trait(m_name, trait_def_id, obligation, substs) | |
5e7ed085 | 352 | } |
c295e0f8 | 353 | |
5e7ed085 FG |
354 | // FIXME(#18741): it seems likely that we can consolidate some of this |
355 | // code with the other method-lookup code. In particular, the second half | |
356 | // of this method is basically the same as confirmation. | |
357 | fn construct_obligation_for_trait( | |
358 | &self, | |
5e7ed085 FG |
359 | m_name: Ident, |
360 | trait_def_id: DefId, | |
361 | obligation: traits::PredicateObligation<'tcx>, | |
362 | substs: &'tcx ty::List<ty::subst::GenericArg<'tcx>>, | |
5e7ed085 | 363 | ) -> Option<InferOk<'tcx, MethodCallee<'tcx>>> { |
5099ac24 FG |
364 | debug!(?obligation); |
365 | ||
a7813a04 | 366 | // Now we want to know if this can be matched |
83c7162d | 367 | if !self.predicate_may_hold(&obligation) { |
a7813a04 | 368 | debug!("--> Cannot match obligation"); |
c295e0f8 XL |
369 | // Cannot be matched, no such method resolution is possible. |
370 | return None; | |
a7813a04 XL |
371 | } |
372 | ||
373 | // Trait must have a method named `m_name` and it should not have | |
374 | // type parameters or early-bound regions. | |
375 | let tcx = self.tcx; | |
5e7ed085 FG |
376 | let Some(method_item) = self.associated_value(trait_def_id, m_name) else { |
377 | tcx.sess.delay_span_bug( | |
9c376795 | 378 | obligation.cause.span, |
5e7ed085 FG |
379 | "operator trait does not have corresponding operator method", |
380 | ); | |
381 | return None; | |
a1dfa0c6 | 382 | }; |
476ff2be | 383 | let def_id = method_item.def_id; |
7cac9316 | 384 | let generics = tcx.generics_of(def_id); |
487cf647 FG |
385 | |
386 | if generics.params.len() != 0 { | |
387 | tcx.sess.emit_fatal(OpMethodGenericParams { | |
388 | span: tcx.def_span(method_item.def_id), | |
389 | method_name: m_name.to_string(), | |
390 | }); | |
391 | } | |
a7813a04 | 392 | |
476ff2be | 393 | debug!("lookup_in_trait_adjusted: method_item={:?}", method_item); |
cc61c64b | 394 | let mut obligations = vec![]; |
a7813a04 XL |
395 | |
396 | // Instantiate late-bound regions and substitute the trait | |
397 | // parameters into the method type to get the actual method type. | |
398 | // | |
9c376795 FG |
399 | // N.B., instantiate late-bound regions before normalizing the |
400 | // function signature so that normalization does not need to deal | |
401 | // with bound regions. | |
04454e1e | 402 | let fn_sig = tcx.bound_fn_sig(def_id); |
cc61c64b | 403 | let fn_sig = fn_sig.subst(self.tcx, substs); |
9c376795 FG |
404 | let fn_sig = |
405 | self.replace_bound_vars_with_fresh_vars(obligation.cause.span, infer::FnCall, fn_sig); | |
487cf647 | 406 | |
9c376795 FG |
407 | let InferOk { value, obligations: o } = |
408 | self.at(&obligation.cause, self.param_env).normalize(fn_sig); | |
ba9703b0 XL |
409 | let fn_sig = { |
410 | obligations.extend(o); | |
411 | value | |
cc61c64b | 412 | }; |
a7813a04 | 413 | |
0731742a | 414 | // Register obligations for the parameters. This will include the |
a7813a04 | 415 | // `Self` parameter, which in turn has a bound of the main trait, |
9c376795 | 416 | // so this also effectively registers `obligation` as well. (We |
a7813a04 XL |
417 | // used to register `obligation` explicitly, but that resulted in |
418 | // double error messages being reported.) | |
419 | // | |
420 | // Note that as the method comes from a trait, it should not have | |
421 | // any late-bound regions appearing in its bounds. | |
7cac9316 | 422 | let bounds = self.tcx.predicates_of(def_id).instantiate(self.tcx, substs); |
ba9703b0 | 423 | |
9c376795 FG |
424 | let InferOk { value, obligations: o } = |
425 | self.at(&obligation.cause, self.param_env).normalize(bounds); | |
ba9703b0 XL |
426 | let bounds = { |
427 | obligations.extend(o); | |
428 | value | |
cc61c64b | 429 | }; |
ba9703b0 | 430 | |
a1dfa0c6 | 431 | assert!(!bounds.has_escaping_bound_vars()); |
a7813a04 | 432 | |
9c376795 | 433 | let predicates_cause = obligation.cause.clone(); |
f2b60f7d FG |
434 | obligations.extend(traits::predicates_for_generics( |
435 | move |_, _| predicates_cause.clone(), | |
436 | self.param_env, | |
437 | bounds, | |
438 | )); | |
a7813a04 | 439 | |
cc61c64b | 440 | // Also add an obligation for the method type being well-formed. |
136023e0 | 441 | let method_ty = tcx.mk_fn_ptr(ty::Binder::dummy(fn_sig)); |
dfeec247 XL |
442 | debug!( |
443 | "lookup_in_trait_adjusted: matched method method_ty={:?} obligation={:?}", | |
444 | method_ty, obligation | |
445 | ); | |
446 | obligations.push(traits::Obligation::new( | |
487cf647 | 447 | tcx, |
9c376795 | 448 | obligation.cause, |
dfeec247 | 449 | self.param_env, |
487cf647 | 450 | ty::Binder::dummy(ty::PredicateKind::WellFormed(method_ty.into())), |
dfeec247 XL |
451 | )); |
452 | ||
c295e0f8 | 453 | let callee = MethodCallee { def_id, substs, sig: fn_sig }; |
1a4d82fc | 454 | |
a7813a04 | 455 | debug!("callee = {:?}", callee); |
1a4d82fc | 456 | |
dfeec247 | 457 | Some(InferOk { obligations, value: callee }) |
a7813a04 | 458 | } |
1a4d82fc | 459 | |
136023e0 XL |
460 | /// Performs a [full-qualified function call] (formerly "universal function call") lookup. If |
461 | /// lookup is successful, it will return the type of definition and the [`DefId`] of the found | |
462 | /// function definition. | |
463 | /// | |
464 | /// [full-qualified function call]: https://doc.rust-lang.org/reference/expressions/call-expr.html#disambiguating-function-calls | |
465 | /// | |
466 | /// # Arguments | |
467 | /// | |
468 | /// Given a function call like `Foo::bar::<T1,...Tn>(...)`: | |
469 | /// | |
470 | /// * `self`: the surrounding `FnCtxt` (!) | |
471 | /// * `span`: the span of the call, excluding arguments (`Foo::bar::<T1, ...Tn>`) | |
472 | /// * `method_name`: the identifier of the function within the container type (`bar`) | |
473 | /// * `self_ty`: the type to search within (`Foo`) | |
474 | /// * `self_ty_span` the span for the type being searched within (span of `Foo`) | |
475 | /// * `expr_id`: the [`hir::HirId`] of the expression composing the entire call | |
f2b60f7d | 476 | #[instrument(level = "debug", skip(self), ret)] |
136023e0 | 477 | pub fn resolve_fully_qualified_call( |
0731742a XL |
478 | &self, |
479 | span: Span, | |
f9f354fc | 480 | method_name: Ident, |
0731742a | 481 | self_ty: Ty<'tcx>, |
136023e0 | 482 | self_ty_span: Span, |
dfeec247 | 483 | expr_id: hir::HirId, |
48663c56 | 484 | ) -> Result<(DefKind, DefId), MethodError<'tcx>> { |
0731742a XL |
485 | let tcx = self.tcx; |
486 | ||
9fa01778 | 487 | // Check if we have an enum variant. |
487cf647 | 488 | let mut struct_variant = None; |
1b1a35ee | 489 | if let ty::Adt(adt_def, _) = self_ty.kind() { |
9fa01778 | 490 | if adt_def.is_enum() { |
dfeec247 | 491 | let variant_def = adt_def |
5e7ed085 | 492 | .variants() |
dfeec247 | 493 | .iter() |
5e7ed085 | 494 | .find(|vd| tcx.hygienic_eq(method_name, vd.ident(tcx), adt_def.did())); |
9fa01778 | 495 | if let Some(variant_def) = variant_def { |
487cf647 FG |
496 | if let Some((ctor_kind, ctor_def_id)) = variant_def.ctor { |
497 | tcx.check_stability( | |
498 | ctor_def_id, | |
499 | Some(expr_id), | |
500 | span, | |
501 | Some(method_name.span), | |
502 | ); | |
503 | return Ok((DefKind::Ctor(CtorOf::Variant, ctor_kind), ctor_def_id)); | |
504 | } else { | |
505 | struct_variant = Some((DefKind::Variant, variant_def.def_id)); | |
506 | } | |
0731742a | 507 | } |
0731742a | 508 | } |
9fa01778 | 509 | } |
476ff2be | 510 | |
dfeec247 | 511 | let pick = self.probe_for_name( |
dfeec247 XL |
512 | probe::Mode::Path, |
513 | method_name, | |
9c376795 | 514 | None, |
dfeec247 XL |
515 | IsSuggestion(false), |
516 | self_ty, | |
517 | expr_id, | |
518 | ProbeScope::TraitsInScope, | |
487cf647 FG |
519 | ); |
520 | let pick = match (pick, struct_variant) { | |
521 | // Fall back to a resolution that will produce an error later. | |
522 | (Err(_), Some(res)) => return Ok(res), | |
523 | (pick, _) => pick?, | |
524 | }; | |
525 | ||
526 | pick.maybe_emit_unstable_name_collision_hint(self.tcx, span, expr_id); | |
136023e0 XL |
527 | |
528 | self.lint_fully_qualified_call_from_2018( | |
529 | span, | |
530 | method_name, | |
531 | self_ty, | |
532 | self_ty_span, | |
533 | expr_id, | |
534 | &pick, | |
535 | ); | |
536 | ||
f2b60f7d | 537 | debug!(?pick); |
74b04a01 | 538 | { |
3dfed10e XL |
539 | let mut typeck_results = self.typeck_results.borrow_mut(); |
540 | let used_trait_imports = Lrc::get_mut(&mut typeck_results.used_trait_imports).unwrap(); | |
74b04a01 | 541 | for import_id in pick.import_ids { |
f2b60f7d | 542 | debug!(used_trait_import=?import_id); |
f035d41b | 543 | used_trait_imports.insert(import_id); |
74b04a01 | 544 | } |
0731742a | 545 | } |
9fa01778 | 546 | |
ba9703b0 | 547 | let def_kind = pick.item.kind.as_def_kind(); |
17df50a5 | 548 | tcx.check_stability(pick.item.def_id, Some(expr_id), span, Some(method_name.span)); |
48663c56 | 549 | Ok((def_kind, pick.item.def_id)) |
c1a9b12d | 550 | } |
c34b1796 | 551 | |
9fa01778 | 552 | /// Finds item with name `item_name` defined in impl/trait `def_id` |
9e0c209e | 553 | /// and return it, or `None`, if no such item was defined there. |
5099ac24 | 554 | pub fn associated_value(&self, def_id: DefId, item_name: Ident) -> Option<ty::AssocItem> { |
74b04a01 XL |
555 | self.tcx |
556 | .associated_items(def_id) | |
5099ac24 | 557 | .find_by_name_and_namespace(self.tcx, item_name, Namespace::ValueNS, def_id) |
74b04a01 | 558 | .copied() |
a7813a04 | 559 | } |
1a4d82fc | 560 | } |