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