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