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