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