]> git.lizzy.rs Git - rust.git/blob - src/librustc_typeck/check/method/suggest.rs
7ce855c73c7c0ab8673784b43f5bf61ecb4c1a95
[rust.git] / src / librustc_typeck / check / method / suggest.rs
1 //! Give useful errors and suggestions to users when an item can't be
2 //! found or is otherwise invalid.
3
4 use crate::check::FnCtxt;
5 use crate::middle::lang_items::FnOnceTraitLangItem;
6 use crate::namespace::Namespace;
7 use crate::util::nodemap::FxHashSet;
8 use errors::{Applicability, DiagnosticBuilder, pluralise};
9 use rustc::hir::{self, ExprKind, Node, QPath};
10 use rustc::hir::def::{Res, DefKind};
11 use rustc::hir::def_id::{CRATE_DEF_INDEX, LOCAL_CRATE, DefId};
12 use rustc::hir::map as hir_map;
13 use rustc::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
14 use rustc::traits::Obligation;
15 use rustc::ty::{self, Ty, TyCtxt, ToPolyTraitRef, ToPredicate, TypeFoldable};
16 use rustc::ty::print::with_crate_prefix;
17 use syntax_pos::{Span, FileName};
18 use syntax::ast;
19 use syntax::util::lev_distance;
20
21 use std::cmp::Ordering;
22
23 use super::{MethodError, NoMatchData, CandidateSource};
24 use super::probe::Mode;
25
26 impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
27     fn is_fn_ty(&self, ty: Ty<'tcx>, span: Span) -> bool {
28         let tcx = self.tcx;
29         match ty.kind {
30             // Not all of these (e.g., unsafe fns) implement `FnOnce`,
31             // so we look for these beforehand.
32             ty::Closure(..) |
33             ty::FnDef(..) |
34             ty::FnPtr(_) => true,
35             // If it's not a simple function, look for things which implement `FnOnce`.
36             _ => {
37                 let fn_once = match tcx.lang_items().require(FnOnceTraitLangItem) {
38                     Ok(fn_once) => fn_once,
39                     Err(..) => return false,
40                 };
41
42                 self.autoderef(span, ty).any(|(ty, _)| {
43                     self.probe(|_| {
44                         let fn_once_substs = tcx.mk_substs_trait(ty, &[
45                             self.next_ty_var(TypeVariableOrigin {
46                                 kind: TypeVariableOriginKind::MiscVariable,
47                                 span,
48                             }).into()
49                         ]);
50                         let trait_ref = ty::TraitRef::new(fn_once, fn_once_substs);
51                         let poly_trait_ref = trait_ref.to_poly_trait_ref();
52                         let obligation =
53                             Obligation::misc(span,
54                                              self.body_id,
55                                              self.param_env,
56                                              poly_trait_ref.to_predicate());
57                         self.predicate_may_hold(&obligation)
58                     })
59                 })
60             }
61         }
62     }
63
64     pub fn report_method_error<'b>(
65         &self,
66         span: Span,
67         rcvr_ty: Ty<'tcx>,
68         item_name: ast::Ident,
69         source: SelfSource<'b>,
70         error: MethodError<'tcx>,
71         args: Option<&'tcx [hir::Expr]>,
72     ) -> Option<DiagnosticBuilder<'_>> {
73         let orig_span = span;
74         let mut span = span;
75         // Avoid suggestions when we don't know what's going on.
76         if rcvr_ty.references_error() {
77             return None;
78         }
79
80         let print_disambiguation_help = |
81             err: &mut DiagnosticBuilder<'_>,
82             trait_name: String,
83         | {
84             err.help(&format!(
85                 "to disambiguate the method call, write `{}::{}({}{})` instead",
86                 trait_name,
87                 item_name,
88                 if rcvr_ty.is_region_ptr() && args.is_some() {
89                     if rcvr_ty.is_mutable_ptr() {
90                         "&mut "
91                     } else {
92                         "&"
93                     }
94                 } else {
95                     ""
96                 },
97                 args.map(|arg| arg
98                     .iter()
99                     .map(|arg| self.tcx.sess.source_map().span_to_snippet(arg.span)
100                         .unwrap_or_else(|_| "...".to_owned()))
101                     .collect::<Vec<_>>()
102                     .join(", ")
103                 ).unwrap_or_else(|| "...".to_owned())
104             ));
105         };
106
107         let report_candidates = |
108             span: Span,
109             err: &mut DiagnosticBuilder<'_>,
110             mut sources: Vec<CandidateSource>,
111         | {
112             sources.sort();
113             sources.dedup();
114             // Dynamic limit to avoid hiding just one candidate, which is silly.
115             let limit = if sources.len() == 5 { 5 } else { 4 };
116
117             for (idx, source) in sources.iter().take(limit).enumerate() {
118                 match *source {
119                     CandidateSource::ImplSource(impl_did) => {
120                         // Provide the best span we can. Use the item, if local to crate, else
121                         // the impl, if local to crate (item may be defaulted), else nothing.
122                         let item = match self.associated_item(
123                             impl_did,
124                             item_name,
125                             Namespace::Value,
126                         ).or_else(|| {
127                             let impl_trait_ref = self.tcx.impl_trait_ref(impl_did)?;
128                             self.associated_item(
129                                 impl_trait_ref.def_id,
130                                 item_name,
131                                 Namespace::Value,
132                             )
133                         }) {
134                             Some(item) => item,
135                             None => continue,
136                         };
137                         let note_span = self.tcx.hir().span_if_local(item.def_id).or_else(|| {
138                             self.tcx.hir().span_if_local(impl_did)
139                         });
140
141                         let impl_ty = self.impl_self_ty(span, impl_did).ty;
142
143                         let insertion = match self.tcx.impl_trait_ref(impl_did) {
144                             None => String::new(),
145                             Some(trait_ref) => {
146                                 format!(" of the trait `{}`",
147                                         self.tcx.def_path_str(trait_ref.def_id))
148                             }
149                         };
150
151                         let note_str = if sources.len() > 1 {
152                             format!("candidate #{} is defined in an impl{} for the type `{}`",
153                                     idx + 1,
154                                     insertion,
155                                     impl_ty)
156                         } else {
157                             format!("the candidate is defined in an impl{} for the type `{}`",
158                                     insertion,
159                                     impl_ty)
160                         };
161                         if let Some(note_span) = note_span {
162                             // We have a span pointing to the method. Show note with snippet.
163                             err.span_note(self.tcx.sess.source_map().def_span(note_span),
164                                           &note_str);
165                         } else {
166                             err.note(&note_str);
167                         }
168                         if let Some(trait_ref) = self.tcx.impl_trait_ref(impl_did) {
169                             print_disambiguation_help(err, self.tcx.def_path_str(trait_ref.def_id));
170                         }
171                     }
172                     CandidateSource::TraitSource(trait_did) => {
173                         let item = match self.associated_item(
174                             trait_did,
175                             item_name,
176                             Namespace::Value)
177                         {
178                             Some(item) => item,
179                             None => continue,
180                         };
181                         let item_span = self.tcx.sess.source_map()
182                             .def_span(self.tcx.def_span(item.def_id));
183                         if sources.len() > 1 {
184                             span_note!(err,
185                                        item_span,
186                                        "candidate #{} is defined in the trait `{}`",
187                                        idx + 1,
188                                        self.tcx.def_path_str(trait_did));
189                         } else {
190                             span_note!(err,
191                                        item_span,
192                                        "the candidate is defined in the trait `{}`",
193                                        self.tcx.def_path_str(trait_did));
194                         }
195                         print_disambiguation_help(err, self.tcx.def_path_str(trait_did));
196                     }
197                 }
198             }
199             if sources.len() > limit {
200                 err.note(&format!("and {} others", sources.len() - limit));
201             }
202         };
203
204         match error {
205             MethodError::NoMatch(NoMatchData {
206                 static_candidates: static_sources,
207                 unsatisfied_predicates,
208                 out_of_scope_traits,
209                 lev_candidate,
210                 mode,
211             }) => {
212                 let tcx = self.tcx;
213
214                 let actual = self.resolve_vars_if_possible(&rcvr_ty);
215                 let ty_str = self.ty_to_string(actual);
216                 let is_method = mode == Mode::MethodCall;
217                 let item_kind = if is_method {
218                     "method"
219                 } else if actual.is_enum() {
220                     "variant or associated item"
221                 } else {
222                     match (item_name.as_str().chars().next(), actual.is_fresh_ty()) {
223                         (Some(name), false) if name.is_lowercase() => {
224                             "function or associated item"
225                         }
226                         (Some(_), false) => "associated item",
227                         (Some(_), true) | (None, false) => {
228                             "variant or associated item"
229                         }
230                         (None, true) => "variant",
231                     }
232                 };
233                 let mut err = if !actual.references_error() {
234                     // Suggest clamping down the type if the method that is being attempted to
235                     // be used exists at all, and the type is an ambiguous numeric type
236                     // ({integer}/{float}).
237                     let mut candidates = all_traits(self.tcx)
238                         .into_iter()
239                         .filter_map(|info|
240                             self.associated_item(info.def_id, item_name, Namespace::Value)
241                         );
242                     if let (true, false, SelfSource::MethodCall(expr), Some(_)) =
243                            (actual.is_numeric(),
244                             actual.has_concrete_skeleton(),
245                             source,
246                             candidates.next()) {
247                         let mut err = struct_span_err!(
248                             tcx.sess,
249                             span,
250                             E0689,
251                             "can't call {} `{}` on ambiguous numeric type `{}`",
252                             item_kind,
253                             item_name,
254                             ty_str
255                         );
256                         let concrete_type = if actual.is_integral() {
257                             "i32"
258                         } else {
259                             "f32"
260                         };
261                         match expr.kind {
262                             ExprKind::Lit(ref lit) => {
263                                 // numeric literal
264                                 let snippet = tcx.sess.source_map().span_to_snippet(lit.span)
265                                     .unwrap_or_else(|_| "<numeric literal>".to_owned());
266
267                                 err.span_suggestion(
268                                     lit.span,
269                                     &format!("you must specify a concrete type for \
270                                               this numeric value, like `{}`", concrete_type),
271                                     format!("{}_{}", snippet, concrete_type),
272                                     Applicability::MaybeIncorrect,
273                                 );
274                             }
275                             ExprKind::Path(ref qpath) => {
276                                 // local binding
277                                 if let &QPath::Resolved(_, ref path) = &qpath {
278                                     if let hir::def::Res::Local(hir_id) = path.res {
279                                         let span = tcx.hir().span(hir_id);
280                                         let snippet = tcx.sess.source_map().span_to_snippet(span);
281                                         let filename = tcx.sess.source_map().span_to_filename(span);
282
283                                         let parent_node = self.tcx.hir().get(
284                                             self.tcx.hir().get_parent_node(hir_id),
285                                         );
286                                         let msg = format!(
287                                             "you must specify a type for this binding, like `{}`",
288                                             concrete_type,
289                                         );
290
291                                         match (filename, parent_node, snippet) {
292                                             (FileName::Real(_), Node::Local(hir::Local {
293                                                 source: hir::LocalSource::Normal,
294                                                 ty,
295                                                 ..
296                                             }), Ok(ref snippet)) => {
297                                                 err.span_suggestion(
298                                                     // account for `let x: _ = 42;`
299                                                     //                  ^^^^
300                                                     span.to(ty.as_ref().map(|ty| ty.span)
301                                                         .unwrap_or(span)),
302                                                     &msg,
303                                                     format!("{}: {}", snippet, concrete_type),
304                                                     Applicability::MaybeIncorrect,
305                                                 );
306                                             }
307                                             _ => {
308                                                 err.span_label(span, msg);
309                                             }
310                                         }
311                                     }
312                                 }
313                             }
314                             _ => {}
315                         }
316                         err.emit();
317                         return None;
318                     } else {
319                         span = item_name.span;
320                         let mut err = struct_span_err!(
321                             tcx.sess,
322                             span,
323                             E0599,
324                             "no {} named `{}` found for type `{}` in the current scope",
325                             item_kind,
326                             item_name,
327                             ty_str
328                         );
329                         if let Some(span) = tcx.sess.confused_type_with_std_module.borrow()
330                             .get(&span)
331                         {
332                             if let Ok(snippet) = tcx.sess.source_map().span_to_snippet(*span) {
333                                 err.span_suggestion(
334                                     *span,
335                                     "you are looking for the module in `std`, \
336                                      not the primitive type",
337                                     format!("std::{}", snippet),
338                                     Applicability::MachineApplicable,
339                                 );
340                             }
341                         }
342                         if let ty::RawPtr(_) = &actual.kind {
343                             err.note("try using `<*const T>::as_ref()` to get a reference to the \
344                                       type behind the pointer: https://doc.rust-lang.org/std/\
345                                       primitive.pointer.html#method.as_ref");
346                             err.note("using `<*const T>::as_ref()` on a pointer \
347                                       which is unaligned or points to invalid \
348                                       or uninitialized memory is undefined behavior");
349                         }
350                         err
351                     }
352                 } else {
353                     tcx.sess.diagnostic().struct_dummy()
354                 };
355
356                 if let Some(def) = actual.ty_adt_def() {
357                     if let Some(full_sp) = tcx.hir().span_if_local(def.did) {
358                         let def_sp = tcx.sess.source_map().def_span(full_sp);
359                         err.span_label(def_sp, format!("{} `{}` not found {}",
360                                                        item_kind,
361                                                        item_name,
362                                                        if def.is_enum() && !is_method {
363                                                            "here"
364                                                        } else {
365                                                            "for this"
366                                                        }));
367                     }
368                 }
369
370                 // If the method name is the name of a field with a function or closure type,
371                 // give a helping note that it has to be called as `(x.f)(...)`.
372                 if let SelfSource::MethodCall(expr) = source {
373                     let field_receiver = self
374                         .autoderef(span, rcvr_ty)
375                         .find_map(|(ty, _)| match ty.kind {
376                             ty::Adt(def, substs) if !def.is_enum() => {
377                                 let variant = &def.non_enum_variant();
378                                 self.tcx.find_field_index(item_name, variant).map(|index| {
379                                     let field = &variant.fields[index];
380                                     let field_ty = field.ty(tcx, substs);
381                                     (field, field_ty)
382                                 })
383                             }
384                             _ => None,
385                         });
386
387                     if let Some((field, field_ty)) = field_receiver {
388                         let scope = self.tcx.hir().get_module_parent(self.body_id);
389                         let is_accessible = field.vis.is_accessible_from(scope, self.tcx);
390
391                         if is_accessible {
392                             if self.is_fn_ty(&field_ty, span) {
393                                 let expr_span = expr.span.to(item_name.span);
394                                 err.multipart_suggestion(
395                                     &format!(
396                                         "to call the function stored in `{}`, \
397                                          surround the field access with parentheses",
398                                         item_name,
399                                     ),
400                                     vec![
401                                         (expr_span.shrink_to_lo(), '('.to_string()),
402                                         (expr_span.shrink_to_hi(), ')'.to_string()),
403                                     ],
404                                     Applicability::MachineApplicable,
405                                 );
406                             } else {
407                                 let call_expr = self.tcx.hir().expect_expr(
408                                     self.tcx.hir().get_parent_node(expr.hir_id),
409                                 );
410
411                                 if let Some(span) = call_expr.span.trim_start(item_name.span) {
412                                     err.span_suggestion(
413                                         span,
414                                         "remove the arguments",
415                                         String::new(),
416                                         Applicability::MaybeIncorrect,
417                                     );
418                                 }
419                             }
420                         }
421
422                         let field_kind = if is_accessible {
423                             "field"
424                         } else {
425                             "private field"
426                         };
427                         err.span_label(item_name.span, format!("{}, not a method", field_kind));
428                     } else if lev_candidate.is_none() && static_sources.is_empty() {
429                         err.span_label(span, format!("{} not found in `{}`", item_kind, ty_str));
430                         self.tcx.sess.trait_methods_not_found.borrow_mut().insert(orig_span);
431                     }
432                 } else {
433                     err.span_label(span, format!("{} not found in `{}`", item_kind, ty_str));
434                     self.tcx.sess.trait_methods_not_found.borrow_mut().insert(orig_span);
435                 }
436
437                 if self.is_fn_ty(&rcvr_ty, span) {
438                     macro_rules! report_function {
439                         ($span:expr, $name:expr) => {
440                             err.note(&format!("{} is a function, perhaps you wish to call it",
441                                               $name));
442                         }
443                     }
444
445                     if let SelfSource::MethodCall(expr) = source {
446                         if let Ok(expr_string) = tcx.sess.source_map().span_to_snippet(expr.span) {
447                             report_function!(expr.span, expr_string);
448                         } else if let ExprKind::Path(QPath::Resolved(_, ref path)) =
449                             expr.kind
450                         {
451                             if let Some(segment) = path.segments.last() {
452                                 report_function!(expr.span, segment.ident);
453                             }
454                         }
455                     }
456                 }
457
458                 if !static_sources.is_empty() {
459                     err.note("found the following associated functions; to be used as methods, \
460                               functions must have a `self` parameter");
461                     err.span_label(span, "this is an associated function, not a method");
462                 }
463                 if static_sources.len() == 1 {
464                     if let SelfSource::MethodCall(expr) = source {
465                         err.span_suggestion(
466                             expr.span.to(span),
467                             "use associated function syntax instead",
468                             format!("{}::{}", self.ty_to_value_string(actual), item_name),
469                             Applicability::MachineApplicable,
470                         );
471                     } else {
472                         err.help(&format!(
473                             "try with `{}::{}`",
474                             self.ty_to_value_string(actual),
475                             item_name,
476                         ));
477                     }
478
479                     report_candidates(span, &mut err, static_sources);
480                 } else if static_sources.len() > 1 {
481                     report_candidates(span, &mut err, static_sources);
482                 }
483
484                 if !unsatisfied_predicates.is_empty() {
485                     let mut bound_list = unsatisfied_predicates.iter()
486                         .map(|p| format!("`{} : {}`", p.self_ty(), p))
487                         .collect::<Vec<_>>();
488                     bound_list.sort();
489                     bound_list.dedup();  // #35677
490                     let bound_list = bound_list.join("\n");
491                     err.note(&format!("the method `{}` exists but the following trait bounds \
492                                        were not satisfied:\n{}",
493                                       item_name,
494                                       bound_list));
495                 }
496
497                 if actual.is_numeric() && actual.is_fresh() {
498
499                 } else {
500                     self.suggest_traits_to_import(&mut err,
501                                                   span,
502                                                   rcvr_ty,
503                                                   item_name,
504                                                   source,
505                                                   out_of_scope_traits);
506                 }
507
508                 if actual.is_enum() {
509                     let adt_def = actual.ty_adt_def().expect("enum is not an ADT");
510                     if let Some(suggestion) = lev_distance::find_best_match_for_name(
511                         adt_def.variants.iter().map(|s| &s.ident.name),
512                         &item_name.as_str(),
513                         None,
514                     ) {
515                         err.span_suggestion(
516                             span,
517                             "there is a variant with a similar name",
518                             suggestion.to_string(),
519                             Applicability::MaybeIncorrect,
520                         );
521                     }
522                 }
523
524                 if let Some(lev_candidate) = lev_candidate {
525                     let def_kind = lev_candidate.def_kind();
526                     err.span_suggestion(
527                         span,
528                         &format!(
529                             "there is {} {} with a similar name",
530                             def_kind.article(),
531                             def_kind.descr(lev_candidate.def_id),
532                         ),
533                         lev_candidate.ident.to_string(),
534                         Applicability::MaybeIncorrect,
535                     );
536                 }
537
538                 return Some(err);
539             }
540
541             MethodError::Ambiguity(sources) => {
542                 let mut err = struct_span_err!(self.sess(),
543                                                span,
544                                                E0034,
545                                                "multiple applicable items in scope");
546                 err.span_label(span, format!("multiple `{}` found", item_name));
547
548                 report_candidates(span, &mut err, sources);
549                 err.emit();
550             }
551
552             MethodError::PrivateMatch(kind, def_id, out_of_scope_traits) => {
553                 let mut err = struct_span_err!(self.tcx.sess, span, E0624,
554                                                "{} `{}` is private", kind.descr(def_id), item_name);
555                 self.suggest_valid_traits(&mut err, out_of_scope_traits);
556                 err.emit();
557             }
558
559             MethodError::IllegalSizedBound(candidates) => {
560                 let msg = format!("the `{}` method cannot be invoked on a trait object", item_name);
561                 let mut err = self.sess().struct_span_err(span, &msg);
562                 if !candidates.is_empty() {
563                     let help = format!("{an}other candidate{s} {were} found in the following \
564                                         trait{s}, perhaps add a `use` for {one_of_them}:",
565                                     an = if candidates.len() == 1 {"an" } else { "" },
566                                     s = pluralise!(candidates.len()),
567                                     were = if candidates.len() == 1 { "was" } else { "were" },
568                                     one_of_them = if candidates.len() == 1 {
569                                         "it"
570                                     } else {
571                                         "one_of_them"
572                                     });
573                     self.suggest_use_candidates(&mut err, help, candidates);
574                 }
575                 err.emit();
576             }
577
578             MethodError::BadReturnType => {
579                 bug!("no return type expectations but got BadReturnType")
580             }
581         }
582         None
583     }
584
585     /// Print out the type for use in value namespace.
586     fn ty_to_value_string(&self, ty: Ty<'tcx>) -> String {
587         match ty.kind {
588             ty::Adt(def, substs) => format!("{}", ty::Instance::new(def.did, substs)),
589             _ => self.ty_to_string(ty),
590         }
591     }
592
593     fn suggest_use_candidates(&self,
594                               err: &mut DiagnosticBuilder<'_>,
595                               mut msg: String,
596                               candidates: Vec<DefId>) {
597         let module_did = self.tcx.hir().get_module_parent(self.body_id);
598         let module_id = self.tcx.hir().as_local_hir_id(module_did).unwrap();
599         let krate = self.tcx.hir().krate();
600         let (span, found_use) = UsePlacementFinder::check(self.tcx, krate, module_id);
601         if let Some(span) = span {
602             let path_strings = candidates.iter().map(|did| {
603                 // Produce an additional newline to separate the new use statement
604                 // from the directly following item.
605                 let additional_newline = if found_use {
606                     ""
607                 } else {
608                     "\n"
609                 };
610                 format!(
611                     "use {};\n{}",
612                     with_crate_prefix(|| self.tcx.def_path_str(*did)),
613                     additional_newline
614                 )
615             });
616
617             err.span_suggestions(span, &msg, path_strings, Applicability::MaybeIncorrect);
618         } else {
619             let limit = if candidates.len() == 5 { 5 } else { 4 };
620             for (i, trait_did) in candidates.iter().take(limit).enumerate() {
621                 if candidates.len() > 1 {
622                     msg.push_str(
623                         &format!(
624                             "\ncandidate #{}: `use {};`",
625                             i + 1,
626                             with_crate_prefix(|| self.tcx.def_path_str(*trait_did))
627                         )
628                     );
629                 } else {
630                     msg.push_str(
631                         &format!(
632                             "\n`use {};`",
633                             with_crate_prefix(|| self.tcx.def_path_str(*trait_did))
634                         )
635                     );
636                 }
637             }
638             if candidates.len() > limit {
639                 msg.push_str(&format!("\nand {} others", candidates.len() - limit));
640             }
641             err.note(&msg[..]);
642         }
643     }
644
645     fn suggest_valid_traits(
646         &self,
647         err: &mut DiagnosticBuilder<'_>,
648         valid_out_of_scope_traits: Vec<DefId>,
649     ) -> bool {
650         if !valid_out_of_scope_traits.is_empty() {
651             let mut candidates = valid_out_of_scope_traits;
652             candidates.sort();
653             candidates.dedup();
654             err.help("items from traits can only be used if the trait is in scope");
655             let msg = format!(
656                 "the following {traits_are} implemented but not in scope; \
657                  perhaps add a `use` for {one_of_them}:",
658                 traits_are = if candidates.len() == 1 {
659                     "trait is"
660                 } else {
661                     "traits are"
662                 },
663                 one_of_them = if candidates.len() == 1 {
664                     "it"
665                 } else {
666                     "one of them"
667                 },
668             );
669
670             self.suggest_use_candidates(err, msg, candidates);
671             true
672         } else {
673             false
674         }
675     }
676
677     fn suggest_traits_to_import<'b>(
678         &self,
679         err: &mut DiagnosticBuilder<'_>,
680         span: Span,
681         rcvr_ty: Ty<'tcx>,
682         item_name: ast::Ident,
683         source: SelfSource<'b>,
684         valid_out_of_scope_traits: Vec<DefId>,
685     ) {
686         if self.suggest_valid_traits(err, valid_out_of_scope_traits) {
687             return;
688         }
689
690         let type_is_local = self.type_derefs_to_local(span, rcvr_ty, source);
691
692         // There are no traits implemented, so lets suggest some traits to
693         // implement, by finding ones that have the item name, and are
694         // legal to implement.
695         let mut candidates = all_traits(self.tcx)
696             .into_iter()
697             .filter(|info| {
698                 // We approximate the coherence rules to only suggest
699                 // traits that are legal to implement by requiring that
700                 // either the type or trait is local. Multi-dispatch means
701                 // this isn't perfect (that is, there are cases when
702                 // implementing a trait would be legal but is rejected
703                 // here).
704                 (type_is_local || info.def_id.is_local()) &&
705                     self.associated_item(info.def_id, item_name, Namespace::Value)
706                         .filter(|item| {
707                             // We only want to suggest public or local traits (#45781).
708                             item.vis == ty::Visibility::Public || info.def_id.is_local()
709                         })
710                         .is_some()
711             })
712             .collect::<Vec<_>>();
713
714         if !candidates.is_empty() {
715             // Sort from most relevant to least relevant.
716             candidates.sort_by(|a, b| a.cmp(b).reverse());
717             candidates.dedup();
718
719             let param_type = match rcvr_ty.kind {
720                 ty::Param(param) => Some(param),
721                 ty::Ref(_, ty, _) => match ty.kind {
722                     ty::Param(param) => Some(param),
723                     _ => None,
724                 }
725                 _ => None,
726             };
727             err.help(if param_type.is_some() {
728                 "items from traits can only be used if the type parameter is bounded by the trait"
729             } else {
730                 "items from traits can only be used if the trait is implemented and in scope"
731             });
732             let mut msg = format!(
733                 "the following {traits_define} an item `{name}`, perhaps you need to {action} \
734                  {one_of_them}:",
735                 traits_define = if candidates.len() == 1 {
736                     "trait defines"
737                 } else {
738                     "traits define"
739                 },
740                 action = if let Some(param) = param_type {
741                     format!("restrict type parameter `{}` with", param)
742                 } else {
743                     "implement".to_string()
744                 },
745                 one_of_them = if candidates.len() == 1 {
746                     "it"
747                 } else {
748                     "one of them"
749                 },
750                 name = item_name,
751             );
752             // Obtain the span for `param` and use it for a structured suggestion.
753             let mut suggested = false;
754             if let (Some(ref param), Some(ref table)) = (param_type, self.in_progress_tables) {
755                 let table = table.borrow();
756                 if let Some(did) = table.local_id_root {
757                     let generics = self.tcx.generics_of(did);
758                     let type_param = generics.type_param(param, self.tcx);
759                     let hir = &self.tcx.hir();
760                     if let Some(id) = hir.as_local_hir_id(type_param.def_id) {
761                         // Get the `hir::Param` to verify whether it already has any bounds.
762                         // We do this to avoid suggesting code that ends up as `T: FooBar`,
763                         // instead we suggest `T: Foo + Bar` in that case.
764                         let mut has_bounds = false;
765                         let mut impl_trait = false;
766                         if let Node::GenericParam(ref param) = hir.get(id) {
767                             match param.kind {
768                                 hir::GenericParamKind::Type { synthetic: Some(_), .. } => {
769                                     // We've found `fn foo(x: impl Trait)` instead of
770                                     // `fn foo<T>(x: T)`. We want to suggest the correct
771                                     // `fn foo(x: impl Trait + TraitBound)` instead of
772                                     // `fn foo<T: TraitBound>(x: T)`. (#63706)
773                                     impl_trait = true;
774                                     has_bounds = param.bounds.len() > 1;
775                                 }
776                                 _ => {
777                                     has_bounds = !param.bounds.is_empty();
778                                 }
779                             }
780                         }
781                         let sp = hir.span(id);
782                         // `sp` only covers `T`, change it so that it covers
783                         // `T:` when appropriate
784                         let sp = if has_bounds {
785                             sp.to(self.tcx
786                                 .sess
787                                 .source_map()
788                                 .next_point(self.tcx.sess.source_map().next_point(sp)))
789                         } else {
790                             sp
791                         };
792
793                         // FIXME: contrast `t.def_id` against `param.bounds` to not suggest traits
794                         // already there. That can happen when the cause is that we're in a const
795                         // scope or associated function used as a method.
796                         err.span_suggestions(
797                             sp,
798                             &msg[..],
799                             candidates.iter().map(|t| format!(
800                                 "{}{} {}{}",
801                                 param,
802                                 if impl_trait { " +" } else { ":" },
803                                 self.tcx.def_path_str(t.def_id),
804                                 if has_bounds { " +"} else { "" },
805                             )),
806                             Applicability::MaybeIncorrect,
807                         );
808                         suggested = true;
809                     }
810                 };
811             }
812
813             if !suggested {
814                 for (i, trait_info) in candidates.iter().enumerate() {
815                     msg.push_str(&format!(
816                         "\ncandidate #{}: `{}`",
817                         i + 1,
818                         self.tcx.def_path_str(trait_info.def_id),
819                     ));
820                 }
821                 err.note(&msg[..]);
822             }
823         }
824     }
825
826     /// Checks whether there is a local type somewhere in the chain of
827     /// autoderefs of `rcvr_ty`.
828     fn type_derefs_to_local(&self,
829                             span: Span,
830                             rcvr_ty: Ty<'tcx>,
831                             source: SelfSource<'_>) -> bool {
832         fn is_local(ty: Ty<'_>) -> bool {
833             match ty.kind {
834                 ty::Adt(def, _) => def.did.is_local(),
835                 ty::Foreign(did) => did.is_local(),
836
837                 ty::Dynamic(ref tr, ..) =>
838                     tr.principal().map(|d| d.def_id().is_local()).unwrap_or(false),
839
840                 ty::Param(_) => true,
841
842                 // Everything else (primitive types, etc.) is effectively
843                 // non-local (there are "edge" cases, e.g., `(LocalType,)`, but
844                 // the noise from these sort of types is usually just really
845                 // annoying, rather than any sort of help).
846                 _ => false,
847             }
848         }
849
850         // This occurs for UFCS desugaring of `T::method`, where there is no
851         // receiver expression for the method call, and thus no autoderef.
852         if let SelfSource::QPath(_) = source {
853             return is_local(self.resolve_type_vars_with_obligations(rcvr_ty));
854         }
855
856         self.autoderef(span, rcvr_ty).any(|(ty, _)| is_local(ty))
857     }
858 }
859
860 #[derive(Copy, Clone)]
861 pub enum SelfSource<'a> {
862     QPath(&'a hir::Ty),
863     MethodCall(&'a hir::Expr /* rcvr */),
864 }
865
866 #[derive(Copy, Clone)]
867 pub struct TraitInfo {
868     pub def_id: DefId,
869 }
870
871 impl PartialEq for TraitInfo {
872     fn eq(&self, other: &TraitInfo) -> bool {
873         self.cmp(other) == Ordering::Equal
874     }
875 }
876 impl Eq for TraitInfo {}
877 impl PartialOrd for TraitInfo {
878     fn partial_cmp(&self, other: &TraitInfo) -> Option<Ordering> {
879         Some(self.cmp(other))
880     }
881 }
882 impl Ord for TraitInfo {
883     fn cmp(&self, other: &TraitInfo) -> Ordering {
884         // Local crates are more important than remote ones (local:
885         // `cnum == 0`), and otherwise we throw in the defid for totality.
886
887         let lhs = (other.def_id.krate, other.def_id);
888         let rhs = (self.def_id.krate, self.def_id);
889         lhs.cmp(&rhs)
890     }
891 }
892
893 /// Retrieves all traits in this crate and any dependent crates.
894 pub fn all_traits(tcx: TyCtxt<'_>) -> Vec<TraitInfo> {
895     tcx.all_traits(LOCAL_CRATE).iter().map(|&def_id| TraitInfo { def_id }).collect()
896 }
897
898 /// Computes all traits in this crate and any dependent crates.
899 fn compute_all_traits(tcx: TyCtxt<'_>) -> Vec<DefId> {
900     use hir::itemlikevisit;
901
902     let mut traits = vec![];
903
904     // Crate-local:
905
906     struct Visitor<'a, 'tcx> {
907         map: &'a hir_map::Map<'tcx>,
908         traits: &'a mut Vec<DefId>,
909     }
910
911     impl<'v, 'a, 'tcx> itemlikevisit::ItemLikeVisitor<'v> for Visitor<'a, 'tcx> {
912         fn visit_item(&mut self, i: &'v hir::Item) {
913             match i.kind {
914                 hir::ItemKind::Trait(..) |
915                 hir::ItemKind::TraitAlias(..) => {
916                     let def_id = self.map.local_def_id(i.hir_id);
917                     self.traits.push(def_id);
918                 }
919                 _ => ()
920             }
921         }
922
923         fn visit_trait_item(&mut self, _trait_item: &hir::TraitItem) {}
924
925         fn visit_impl_item(&mut self, _impl_item: &hir::ImplItem) {}
926     }
927
928     tcx.hir().krate().visit_all_item_likes(&mut Visitor {
929         map: &tcx.hir(),
930         traits: &mut traits,
931     });
932
933     // Cross-crate:
934
935     let mut external_mods = FxHashSet::default();
936     fn handle_external_res(
937         tcx: TyCtxt<'_>,
938         traits: &mut Vec<DefId>,
939         external_mods: &mut FxHashSet<DefId>,
940         res: Res,
941     ) {
942         match res {
943             Res::Def(DefKind::Trait, def_id) |
944             Res::Def(DefKind::TraitAlias, def_id) => {
945                 traits.push(def_id);
946             }
947             Res::Def(DefKind::Mod, def_id) => {
948                 if !external_mods.insert(def_id) {
949                     return;
950                 }
951                 for child in tcx.item_children(def_id).iter() {
952                     handle_external_res(tcx, traits, external_mods, child.res)
953                 }
954             }
955             _ => {}
956         }
957     }
958     for &cnum in tcx.crates().iter() {
959         let def_id = DefId {
960             krate: cnum,
961             index: CRATE_DEF_INDEX,
962         };
963         handle_external_res(tcx, &mut traits, &mut external_mods, Res::Def(DefKind::Mod, def_id));
964     }
965
966     traits
967 }
968
969 pub fn provide(providers: &mut ty::query::Providers<'_>) {
970     providers.all_traits = |tcx, cnum| {
971         assert_eq!(cnum, LOCAL_CRATE);
972         &tcx.arena.alloc(compute_all_traits(tcx))[..]
973     }
974 }
975
976 struct UsePlacementFinder<'tcx> {
977     target_module: hir::HirId,
978     span: Option<Span>,
979     found_use: bool,
980     tcx: TyCtxt<'tcx>,
981 }
982
983 impl UsePlacementFinder<'tcx> {
984     fn check(
985         tcx: TyCtxt<'tcx>,
986         krate: &'tcx hir::Crate,
987         target_module: hir::HirId,
988     ) -> (Option<Span>, bool) {
989         let mut finder = UsePlacementFinder {
990             target_module,
991             span: None,
992             found_use: false,
993             tcx,
994         };
995         hir::intravisit::walk_crate(&mut finder, krate);
996         (finder.span, finder.found_use)
997     }
998 }
999
1000 impl hir::intravisit::Visitor<'tcx> for UsePlacementFinder<'tcx> {
1001     fn visit_mod(
1002         &mut self,
1003         module: &'tcx hir::Mod,
1004         _: Span,
1005         hir_id: hir::HirId,
1006     ) {
1007         if self.span.is_some() {
1008             return;
1009         }
1010         if hir_id != self.target_module {
1011             hir::intravisit::walk_mod(self, module, hir_id);
1012             return;
1013         }
1014         // Find a `use` statement.
1015         for item_id in &module.item_ids {
1016             let item = self.tcx.hir().expect_item(item_id.id);
1017             match item.kind {
1018                 hir::ItemKind::Use(..) => {
1019                     // Don't suggest placing a `use` before the prelude
1020                     // import or other generated ones.
1021                     if !item.span.from_expansion() {
1022                         self.span = Some(item.span.shrink_to_lo());
1023                         self.found_use = true;
1024                         return;
1025                     }
1026                 },
1027                 // Don't place `use` before `extern crate`...
1028                 hir::ItemKind::ExternCrate(_) => {}
1029                 // ...but do place them before the first other item.
1030                 _ => if self.span.map_or(true, |span| item.span < span ) {
1031                     if !item.span.from_expansion() {
1032                         // Don't insert between attributes and an item.
1033                         if item.attrs.is_empty() {
1034                             self.span = Some(item.span.shrink_to_lo());
1035                         } else {
1036                             // Find the first attribute on the item.
1037                             for attr in &item.attrs {
1038                                 if self.span.map_or(true, |span| attr.span < span) {
1039                                     self.span = Some(attr.span.shrink_to_lo());
1040                                 }
1041                             }
1042                         }
1043                     }
1044                 },
1045             }
1046         }
1047     }
1048
1049     fn nested_visit_map<'this>(
1050         &'this mut self
1051     ) -> hir::intravisit::NestedVisitorMap<'this, 'tcx> {
1052         hir::intravisit::NestedVisitorMap::None
1053     }
1054 }