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