]> git.lizzy.rs Git - rust.git/blob - src/librustc_typeck/check/method/suggest.rs
72e6f5971596092ab92b2fa39819ee86265089eb
[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};
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.sty {
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 ambiuous 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.node {
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.sty {
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.sty {
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                     }
429                 } else {
430                     err.span_label(span, format!("{} not found in `{}`", item_kind, ty_str));
431                     self.tcx.sess.trait_methods_not_found.borrow_mut().insert(orig_span);
432                 }
433
434                 if self.is_fn_ty(&rcvr_ty, span) {
435                     macro_rules! report_function {
436                         ($span:expr, $name:expr) => {
437                             err.note(&format!("{} is a function, perhaps you wish to call it",
438                                               $name));
439                         }
440                     }
441
442                     if let SelfSource::MethodCall(expr) = source {
443                         if let Ok(expr_string) = tcx.sess.source_map().span_to_snippet(expr.span) {
444                             report_function!(expr.span, expr_string);
445                         } else if let ExprKind::Path(QPath::Resolved(_, ref path)) =
446                             expr.node
447                         {
448                             if let Some(segment) = path.segments.last() {
449                                 report_function!(expr.span, segment.ident);
450                             }
451                         }
452                     }
453                 }
454
455                 if !static_sources.is_empty() {
456                     err.note("found the following associated functions; to be used as methods, \
457                               functions must have a `self` parameter");
458                     err.span_label(span, "this is an associated function, not a method");
459                 }
460                 if static_sources.len() == 1 {
461                     if let SelfSource::MethodCall(expr) = source {
462                         err.span_suggestion(expr.span.to(span),
463                                             "use associated function syntax instead",
464                                             format!("{}::{}",
465                                                     self.ty_to_string(actual),
466                                                     item_name),
467                                             Applicability::MachineApplicable);
468                     } else {
469                         err.help(&format!("try with `{}::{}`",
470                                           self.ty_to_string(actual), item_name));
471                     }
472
473                     report_candidates(span, &mut err, static_sources);
474                 } else if static_sources.len() > 1 {
475                     report_candidates(span, &mut err, static_sources);
476                 }
477
478                 if !unsatisfied_predicates.is_empty() {
479                     let mut bound_list = unsatisfied_predicates.iter()
480                         .map(|p| format!("`{} : {}`", p.self_ty(), p))
481                         .collect::<Vec<_>>();
482                     bound_list.sort();
483                     bound_list.dedup();  // #35677
484                     let bound_list = bound_list.join("\n");
485                     err.note(&format!("the method `{}` exists but the following trait bounds \
486                                        were not satisfied:\n{}",
487                                       item_name,
488                                       bound_list));
489                 }
490
491                 if actual.is_numeric() && actual.is_fresh() {
492
493                 } else {
494                     self.suggest_traits_to_import(&mut err,
495                                                   span,
496                                                   rcvr_ty,
497                                                   item_name,
498                                                   source,
499                                                   out_of_scope_traits);
500                 }
501
502                 if actual.is_enum() {
503                     let adt_def = actual.ty_adt_def().expect("enum is not an ADT");
504                     if let Some(suggestion) = lev_distance::find_best_match_for_name(
505                         adt_def.variants.iter().map(|s| &s.ident.name),
506                         &item_name.as_str(),
507                         None,
508                     ) {
509                         err.span_suggestion(
510                             span,
511                             "there is a variant with a similar name",
512                             suggestion.to_string(),
513                             Applicability::MaybeIncorrect,
514                         );
515                     }
516                 }
517
518                 if let Some(lev_candidate) = lev_candidate {
519                     let def_kind = lev_candidate.def_kind();
520                     err.span_suggestion(
521                         span,
522                         &format!(
523                             "there is {} {} with a similar name",
524                             def_kind.article(),
525                             def_kind.descr(lev_candidate.def_id),
526                         ),
527                         lev_candidate.ident.to_string(),
528                         Applicability::MaybeIncorrect,
529                     );
530                 }
531
532                 return Some(err);
533             }
534
535             MethodError::Ambiguity(sources) => {
536                 let mut err = struct_span_err!(self.sess(),
537                                                span,
538                                                E0034,
539                                                "multiple applicable items in scope");
540                 err.span_label(span, format!("multiple `{}` found", item_name));
541
542                 report_candidates(span, &mut err, sources);
543                 err.emit();
544             }
545
546             MethodError::PrivateMatch(kind, def_id, out_of_scope_traits) => {
547                 let mut err = struct_span_err!(self.tcx.sess, span, E0624,
548                                                "{} `{}` is private", kind.descr(def_id), item_name);
549                 self.suggest_valid_traits(&mut err, out_of_scope_traits);
550                 err.emit();
551             }
552
553             MethodError::IllegalSizedBound(candidates) => {
554                 let msg = format!("the `{}` method cannot be invoked on a trait object", item_name);
555                 let mut err = self.sess().struct_span_err(span, &msg);
556                 if !candidates.is_empty() {
557                     let help = format!("{an}other candidate{s} {were} found in the following \
558                                         trait{s}, perhaps add a `use` for {one_of_them}:",
559                                     an = if candidates.len() == 1 {"an" } else { "" },
560                                     s = if candidates.len() == 1 { "" } else { "s" },
561                                     were = if candidates.len() == 1 { "was" } else { "were" },
562                                     one_of_them = if candidates.len() == 1 {
563                                         "it"
564                                     } else {
565                                         "one_of_them"
566                                     });
567                     self.suggest_use_candidates(&mut err, help, candidates);
568                 }
569                 err.emit();
570             }
571
572             MethodError::BadReturnType => {
573                 bug!("no return type expectations but got BadReturnType")
574             }
575         }
576         None
577     }
578
579     fn suggest_use_candidates(&self,
580                               err: &mut DiagnosticBuilder<'_>,
581                               mut msg: String,
582                               candidates: Vec<DefId>) {
583         let module_did = self.tcx.hir().get_module_parent(self.body_id);
584         let module_id = self.tcx.hir().as_local_hir_id(module_did).unwrap();
585         let krate = self.tcx.hir().krate();
586         let (span, found_use) = UsePlacementFinder::check(self.tcx, krate, module_id);
587         if let Some(span) = span {
588             let path_strings = candidates.iter().map(|did| {
589                 // Produce an additional newline to separate the new use statement
590                 // from the directly following item.
591                 let additional_newline = if found_use {
592                     ""
593                 } else {
594                     "\n"
595                 };
596                 format!(
597                     "use {};\n{}",
598                     with_crate_prefix(|| self.tcx.def_path_str(*did)),
599                     additional_newline
600                 )
601             });
602
603             err.span_suggestions(span, &msg, path_strings, Applicability::MaybeIncorrect);
604         } else {
605             let limit = if candidates.len() == 5 { 5 } else { 4 };
606             for (i, trait_did) in candidates.iter().take(limit).enumerate() {
607                 if candidates.len() > 1 {
608                     msg.push_str(
609                         &format!(
610                             "\ncandidate #{}: `use {};`",
611                             i + 1,
612                             with_crate_prefix(|| self.tcx.def_path_str(*trait_did))
613                         )
614                     );
615                 } else {
616                     msg.push_str(
617                         &format!(
618                             "\n`use {};`",
619                             with_crate_prefix(|| self.tcx.def_path_str(*trait_did))
620                         )
621                     );
622                 }
623             }
624             if candidates.len() > limit {
625                 msg.push_str(&format!("\nand {} others", candidates.len() - limit));
626             }
627             err.note(&msg[..]);
628         }
629     }
630
631     fn suggest_valid_traits(&self,
632                             err: &mut DiagnosticBuilder<'_>,
633                             valid_out_of_scope_traits: Vec<DefId>) -> bool {
634         if !valid_out_of_scope_traits.is_empty() {
635             let mut candidates = valid_out_of_scope_traits;
636             candidates.sort();
637             candidates.dedup();
638             err.help("items from traits can only be used if the trait is in scope");
639             let msg = format!("the following {traits_are} implemented but not in scope, \
640                                perhaps add a `use` for {one_of_them}:",
641                             traits_are = if candidates.len() == 1 {
642                                 "trait is"
643                             } else {
644                                 "traits are"
645                             },
646                             one_of_them = if candidates.len() == 1 {
647                                 "it"
648                             } else {
649                                 "one of them"
650                             });
651
652             self.suggest_use_candidates(err, msg, candidates);
653             true
654         } else {
655             false
656         }
657     }
658
659     fn suggest_traits_to_import<'b>(
660         &self,
661         err: &mut DiagnosticBuilder<'_>,
662         span: Span,
663         rcvr_ty: Ty<'tcx>,
664         item_name: ast::Ident,
665         source: SelfSource<'b>,
666         valid_out_of_scope_traits: Vec<DefId>,
667     ) {
668         if self.suggest_valid_traits(err, valid_out_of_scope_traits) {
669             return;
670         }
671
672         let type_is_local = self.type_derefs_to_local(span, rcvr_ty, source);
673
674         // There are no traits implemented, so lets suggest some traits to
675         // implement, by finding ones that have the item name, and are
676         // legal to implement.
677         let mut candidates = all_traits(self.tcx)
678             .into_iter()
679             .filter(|info| {
680                 // We approximate the coherence rules to only suggest
681                 // traits that are legal to implement by requiring that
682                 // either the type or trait is local. Multi-dispatch means
683                 // this isn't perfect (that is, there are cases when
684                 // implementing a trait would be legal but is rejected
685                 // here).
686                 (type_is_local || info.def_id.is_local()) &&
687                     self.associated_item(info.def_id, item_name, Namespace::Value)
688                         .filter(|item| {
689                             // We only want to suggest public or local traits (#45781).
690                             item.vis == ty::Visibility::Public || info.def_id.is_local()
691                         })
692                         .is_some()
693             })
694             .collect::<Vec<_>>();
695
696         if !candidates.is_empty() {
697             // Sort from most relevant to least relevant.
698             candidates.sort_by(|a, b| a.cmp(b).reverse());
699             candidates.dedup();
700
701             let param_type = match rcvr_ty.sty {
702                 ty::Param(param) => Some(param),
703                 ty::Ref(_, ty, _) => match ty.sty {
704                     ty::Param(param) => Some(param),
705                     _ => None,
706                 }
707                 _ => None,
708             };
709             err.help(if param_type.is_some() {
710                 "items from traits can only be used if the type parameter is bounded by the trait"
711             } else {
712                 "items from traits can only be used if the trait is implemented and in scope"
713             });
714             let mut msg = format!(
715                 "the following {traits_define} an item `{name}`, perhaps you need to {action} \
716                  {one_of_them}:",
717                 traits_define = if candidates.len() == 1 {
718                     "trait defines"
719                 } else {
720                     "traits define"
721                 },
722                 action = if let Some(param) = param_type {
723                     format!("restrict type parameter `{}` with", param)
724                 } else {
725                     "implement".to_string()
726                 },
727                 one_of_them = if candidates.len() == 1 {
728                     "it"
729                 } else {
730                     "one of them"
731                 },
732                 name = item_name,
733             );
734             // Obtain the span for `param` and use it for a structured suggestion.
735             let mut suggested = false;
736             if let (Some(ref param), Some(ref table)) = (param_type, self.in_progress_tables) {
737                 let table = table.borrow();
738                 if let Some(did) = table.local_id_root {
739                     let generics = self.tcx.generics_of(did);
740                     let type_param = generics.type_param(param, self.tcx);
741                     let hir = &self.tcx.hir();
742                     if let Some(id) = hir.as_local_hir_id(type_param.def_id) {
743                         // Get the `hir::Param` to verify whether it already has any bounds.
744                         // We do this to avoid suggesting code that ends up as `T: FooBar`,
745                         // instead we suggest `T: Foo + Bar` in that case.
746                         let mut has_bounds = false;
747                         let mut impl_trait = false;
748                         if let Node::GenericParam(ref param) = hir.get(id) {
749                             match param.kind {
750                                 hir::GenericParamKind::Type { synthetic: Some(_), .. } => {
751                                     // We've found `fn foo(x: impl Trait)` instead of
752                                     // `fn foo<T>(x: T)`. We want to suggest the correct
753                                     // `fn foo(x: impl Trait + TraitBound)` instead of
754                                     // `fn foo<T: TraitBound>(x: T)`. (#63706)
755                                     impl_trait = true;
756                                     has_bounds = param.bounds.len() > 1;
757                                 }
758                                 _ => {
759                                     has_bounds = !param.bounds.is_empty();
760                                 }
761                             }
762                         }
763                         let sp = hir.span(id);
764                         // `sp` only covers `T`, change it so that it covers
765                         // `T:` when appropriate
766                         let sp = if has_bounds {
767                             sp.to(self.tcx
768                                 .sess
769                                 .source_map()
770                                 .next_point(self.tcx.sess.source_map().next_point(sp)))
771                         } else {
772                             sp
773                         };
774
775                         // FIXME: contrast `t.def_id` against `param.bounds` to not suggest traits
776                         // already there. That can happen when the cause is that we're in a const
777                         // scope or associated function used as a method.
778                         err.span_suggestions(
779                             sp,
780                             &msg[..],
781                             candidates.iter().map(|t| format!(
782                                 "{}{} {}{}",
783                                 param,
784                                 if impl_trait { " +" } else { ":" },
785                                 self.tcx.def_path_str(t.def_id),
786                                 if has_bounds { " +"} else { "" },
787                             )),
788                             Applicability::MaybeIncorrect,
789                         );
790                         suggested = true;
791                     }
792                 };
793             }
794
795             if !suggested {
796                 for (i, trait_info) in candidates.iter().enumerate() {
797                     msg.push_str(&format!(
798                         "\ncandidate #{}: `{}`",
799                         i + 1,
800                         self.tcx.def_path_str(trait_info.def_id),
801                     ));
802                 }
803                 err.note(&msg[..]);
804             }
805         }
806     }
807
808     /// Checks whether there is a local type somewhere in the chain of
809     /// autoderefs of `rcvr_ty`.
810     fn type_derefs_to_local(&self,
811                             span: Span,
812                             rcvr_ty: Ty<'tcx>,
813                             source: SelfSource<'_>) -> bool {
814         fn is_local(ty: Ty<'_>) -> bool {
815             match ty.sty {
816                 ty::Adt(def, _) => def.did.is_local(),
817                 ty::Foreign(did) => did.is_local(),
818
819                 ty::Dynamic(ref tr, ..) =>
820                     tr.principal().map(|d| d.def_id().is_local()).unwrap_or(false),
821
822                 ty::Param(_) => true,
823
824                 // Everything else (primitive types, etc.) is effectively
825                 // non-local (there are "edge" cases, e.g., `(LocalType,)`, but
826                 // the noise from these sort of types is usually just really
827                 // annoying, rather than any sort of help).
828                 _ => false,
829             }
830         }
831
832         // This occurs for UFCS desugaring of `T::method`, where there is no
833         // receiver expression for the method call, and thus no autoderef.
834         if let SelfSource::QPath(_) = source {
835             return is_local(self.resolve_type_vars_with_obligations(rcvr_ty));
836         }
837
838         self.autoderef(span, rcvr_ty).any(|(ty, _)| is_local(ty))
839     }
840 }
841
842 #[derive(Copy, Clone)]
843 pub enum SelfSource<'a> {
844     QPath(&'a hir::Ty),
845     MethodCall(&'a hir::Expr /* rcvr */),
846 }
847
848 #[derive(Copy, Clone)]
849 pub struct TraitInfo {
850     pub def_id: DefId,
851 }
852
853 impl PartialEq for TraitInfo {
854     fn eq(&self, other: &TraitInfo) -> bool {
855         self.cmp(other) == Ordering::Equal
856     }
857 }
858 impl Eq for TraitInfo {}
859 impl PartialOrd for TraitInfo {
860     fn partial_cmp(&self, other: &TraitInfo) -> Option<Ordering> {
861         Some(self.cmp(other))
862     }
863 }
864 impl Ord for TraitInfo {
865     fn cmp(&self, other: &TraitInfo) -> Ordering {
866         // Local crates are more important than remote ones (local:
867         // `cnum == 0`), and otherwise we throw in the defid for totality.
868
869         let lhs = (other.def_id.krate, other.def_id);
870         let rhs = (self.def_id.krate, self.def_id);
871         lhs.cmp(&rhs)
872     }
873 }
874
875 /// Retrieves all traits in this crate and any dependent crates.
876 pub fn all_traits(tcx: TyCtxt<'_>) -> Vec<TraitInfo> {
877     tcx.all_traits(LOCAL_CRATE).iter().map(|&def_id| TraitInfo { def_id }).collect()
878 }
879
880 /// Computes all traits in this crate and any dependent crates.
881 fn compute_all_traits(tcx: TyCtxt<'_>) -> Vec<DefId> {
882     use hir::itemlikevisit;
883
884     let mut traits = vec![];
885
886     // Crate-local:
887
888     struct Visitor<'a, 'tcx> {
889         map: &'a hir_map::Map<'tcx>,
890         traits: &'a mut Vec<DefId>,
891     }
892
893     impl<'v, 'a, 'tcx> itemlikevisit::ItemLikeVisitor<'v> for Visitor<'a, 'tcx> {
894         fn visit_item(&mut self, i: &'v hir::Item) {
895             match i.node {
896                 hir::ItemKind::Trait(..) |
897                 hir::ItemKind::TraitAlias(..) => {
898                     let def_id = self.map.local_def_id(i.hir_id);
899                     self.traits.push(def_id);
900                 }
901                 _ => ()
902             }
903         }
904
905         fn visit_trait_item(&mut self, _trait_item: &hir::TraitItem) {}
906
907         fn visit_impl_item(&mut self, _impl_item: &hir::ImplItem) {}
908     }
909
910     tcx.hir().krate().visit_all_item_likes(&mut Visitor {
911         map: &tcx.hir(),
912         traits: &mut traits,
913     });
914
915     // Cross-crate:
916
917     let mut external_mods = FxHashSet::default();
918     fn handle_external_res(
919         tcx: TyCtxt<'_>,
920         traits: &mut Vec<DefId>,
921         external_mods: &mut FxHashSet<DefId>,
922         res: Res,
923     ) {
924         match res {
925             Res::Def(DefKind::Trait, def_id) |
926             Res::Def(DefKind::TraitAlias, def_id) => {
927                 traits.push(def_id);
928             }
929             Res::Def(DefKind::Mod, def_id) => {
930                 if !external_mods.insert(def_id) {
931                     return;
932                 }
933                 for child in tcx.item_children(def_id).iter() {
934                     handle_external_res(tcx, traits, external_mods, child.res)
935                 }
936             }
937             _ => {}
938         }
939     }
940     for &cnum in tcx.crates().iter() {
941         let def_id = DefId {
942             krate: cnum,
943             index: CRATE_DEF_INDEX,
944         };
945         handle_external_res(tcx, &mut traits, &mut external_mods, Res::Def(DefKind::Mod, def_id));
946     }
947
948     traits
949 }
950
951 pub fn provide(providers: &mut ty::query::Providers<'_>) {
952     providers.all_traits = |tcx, cnum| {
953         assert_eq!(cnum, LOCAL_CRATE);
954         &tcx.arena.alloc(compute_all_traits(tcx))[..]
955     }
956 }
957
958 struct UsePlacementFinder<'tcx> {
959     target_module: hir::HirId,
960     span: Option<Span>,
961     found_use: bool,
962     tcx: TyCtxt<'tcx>,
963 }
964
965 impl UsePlacementFinder<'tcx> {
966     fn check(
967         tcx: TyCtxt<'tcx>,
968         krate: &'tcx hir::Crate,
969         target_module: hir::HirId,
970     ) -> (Option<Span>, bool) {
971         let mut finder = UsePlacementFinder {
972             target_module,
973             span: None,
974             found_use: false,
975             tcx,
976         };
977         hir::intravisit::walk_crate(&mut finder, krate);
978         (finder.span, finder.found_use)
979     }
980 }
981
982 impl hir::intravisit::Visitor<'tcx> for UsePlacementFinder<'tcx> {
983     fn visit_mod(
984         &mut self,
985         module: &'tcx hir::Mod,
986         _: Span,
987         hir_id: hir::HirId,
988     ) {
989         if self.span.is_some() {
990             return;
991         }
992         if hir_id != self.target_module {
993             hir::intravisit::walk_mod(self, module, hir_id);
994             return;
995         }
996         // Find a `use` statement.
997         for item_id in &module.item_ids {
998             let item = self.tcx.hir().expect_item(item_id.id);
999             match item.node {
1000                 hir::ItemKind::Use(..) => {
1001                     // Don't suggest placing a `use` before the prelude
1002                     // import or other generated ones.
1003                     if !item.span.from_expansion() {
1004                         self.span = Some(item.span.shrink_to_lo());
1005                         self.found_use = true;
1006                         return;
1007                     }
1008                 },
1009                 // Don't place `use` before `extern crate`...
1010                 hir::ItemKind::ExternCrate(_) => {}
1011                 // ...but do place them before the first other item.
1012                 _ => if self.span.map_or(true, |span| item.span < span ) {
1013                     if !item.span.from_expansion() {
1014                         // Don't insert between attributes and an item.
1015                         if item.attrs.is_empty() {
1016                             self.span = Some(item.span.shrink_to_lo());
1017                         } else {
1018                             // Find the first attribute on the item.
1019                             for attr in &item.attrs {
1020                                 if self.span.map_or(true, |span| attr.span < span) {
1021                                     self.span = Some(attr.span.shrink_to_lo());
1022                                 }
1023                             }
1024                         }
1025                     }
1026                 },
1027             }
1028         }
1029     }
1030
1031     fn nested_visit_map<'this>(
1032         &'this mut self
1033     ) -> hir::intravisit::NestedVisitorMap<'this, 'tcx> {
1034         hir::intravisit::NestedVisitorMap::None
1035     }
1036 }