]> git.lizzy.rs Git - rust.git/blob - src/librustc_typeck/check/method/suggest.rs
Auto merge of #58406 - Disasm:rv64-support, r=nagisa
[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_by_hir_id(
350                                         self.body_id);
351                                     if field.vis.is_accessible_from(scope, self.tcx) {
352                                         if self.is_fn_ty(&field_ty, span) {
353                                             err.help(&format!("use `({0}.{1})(...)` if you \
354                                                                meant to call the function \
355                                                                stored in the `{1}` field",
356                                                               expr_string,
357                                                               item_name));
358                                         } else {
359                                             err.help(&format!("did you mean to write `{0}.{1}` \
360                                                                instead of `{0}.{1}(...)`?",
361                                                               expr_string,
362                                                               item_name));
363                                         }
364                                         err.span_label(span, "field, not a method");
365                                     } else {
366                                         err.span_label(span, "private field, not a method");
367                                     }
368                                     break;
369                                 }
370                             }
371                         }
372                     }
373                 } else {
374                     err.span_label(span, format!("{} not found in `{}`", item_kind, ty_str));
375                 }
376
377                 if self.is_fn_ty(&rcvr_ty, span) {
378                     macro_rules! report_function {
379                         ($span:expr, $name:expr) => {
380                             err.note(&format!("{} is a function, perhaps you wish to call it",
381                                               $name));
382                         }
383                     }
384
385                     if let SelfSource::MethodCall(expr) = source {
386                         if let Ok(expr_string) = tcx.sess.source_map().span_to_snippet(expr.span) {
387                             report_function!(expr.span, expr_string);
388                         } else if let ExprKind::Path(QPath::Resolved(_, ref path)) =
389                             expr.node
390                         {
391                             if let Some(segment) = path.segments.last() {
392                                 report_function!(expr.span, segment.ident);
393                             }
394                         }
395                     }
396                 }
397
398                 if !static_sources.is_empty() {
399                     err.note("found the following associated functions; to be used as methods, \
400                               functions must have a `self` parameter");
401                     err.span_label(span, "this is an associated function, not a method");
402                 }
403                 if static_sources.len() == 1 {
404                     if let SelfSource::MethodCall(expr) = source {
405                         err.span_suggestion(expr.span.to(span),
406                                             "use associated function syntax instead",
407                                             format!("{}::{}",
408                                                     self.ty_to_string(actual),
409                                                     item_name),
410                                             Applicability::MachineApplicable);
411                     } else {
412                         err.help(&format!("try with `{}::{}`",
413                                           self.ty_to_string(actual), item_name));
414                     }
415
416                     report_candidates(&mut err, static_sources);
417                 } else if static_sources.len() > 1 {
418                     report_candidates(&mut err, static_sources);
419                 }
420
421                 if !unsatisfied_predicates.is_empty() {
422                     let mut bound_list = unsatisfied_predicates.iter()
423                         .map(|p| format!("`{} : {}`", p.self_ty(), p))
424                         .collect::<Vec<_>>();
425                     bound_list.sort();
426                     bound_list.dedup();  // #35677
427                     let bound_list = bound_list.join("\n");
428                     err.note(&format!("the method `{}` exists but the following trait bounds \
429                                        were not satisfied:\n{}",
430                                       item_name,
431                                       bound_list));
432                 }
433
434                 if actual.is_numeric() && actual.is_fresh() {
435
436                 } else {
437                     self.suggest_traits_to_import(&mut err,
438                                                   span,
439                                                   rcvr_ty,
440                                                   item_name,
441                                                   source,
442                                                   out_of_scope_traits);
443                 }
444
445                 if let Some(lev_candidate) = lev_candidate {
446                     err.span_suggestion(
447                         span,
448                         "did you mean",
449                         lev_candidate.ident.to_string(),
450                         Applicability::MaybeIncorrect,
451                     );
452                 }
453                 err.emit();
454             }
455
456             MethodError::Ambiguity(sources) => {
457                 let mut err = struct_span_err!(self.sess(),
458                                                span,
459                                                E0034,
460                                                "multiple applicable items in scope");
461                 err.span_label(span, format!("multiple `{}` found", item_name));
462
463                 report_candidates(&mut err, sources);
464                 err.emit();
465             }
466
467             MethodError::PrivateMatch(def, out_of_scope_traits) => {
468                 let mut err = struct_span_err!(self.tcx.sess, span, E0624,
469                                                "{} `{}` is private", def.kind_name(), item_name);
470                 self.suggest_valid_traits(&mut err, out_of_scope_traits);
471                 err.emit();
472             }
473
474             MethodError::IllegalSizedBound(candidates) => {
475                 let msg = format!("the `{}` method cannot be invoked on a trait object", item_name);
476                 let mut err = self.sess().struct_span_err(span, &msg);
477                 if !candidates.is_empty() {
478                     let help = format!("{an}other candidate{s} {were} found in the following \
479                                         trait{s}, perhaps add a `use` for {one_of_them}:",
480                                     an = if candidates.len() == 1 {"an" } else { "" },
481                                     s = if candidates.len() == 1 { "" } else { "s" },
482                                     were = if candidates.len() == 1 { "was" } else { "were" },
483                                     one_of_them = if candidates.len() == 1 {
484                                         "it"
485                                     } else {
486                                         "one_of_them"
487                                     });
488                     self.suggest_use_candidates(&mut err, help, candidates);
489                 }
490                 err.emit();
491             }
492
493             MethodError::BadReturnType => {
494                 bug!("no return type expectations but got BadReturnType")
495             }
496         }
497     }
498
499     fn suggest_use_candidates(&self,
500                               err: &mut DiagnosticBuilder,
501                               mut msg: String,
502                               candidates: Vec<DefId>) {
503         let module_did = self.tcx.hir().get_module_parent_by_hir_id(self.body_id);
504         let module_id = self.tcx.hir().as_local_node_id(module_did).unwrap();
505         let krate = self.tcx.hir().krate();
506         let (span, found_use) = UsePlacementFinder::check(self.tcx, krate, module_id);
507         if let Some(span) = span {
508             let path_strings = candidates.iter().map(|did| {
509                 // Produce an additional newline to separate the new use statement
510                 // from the directly following item.
511                 let additional_newline = if found_use {
512                     ""
513                 } else {
514                     "\n"
515                 };
516                 format!(
517                     "use {};\n{}",
518                     with_crate_prefix(|| self.tcx.item_path_str(*did)),
519                     additional_newline
520                 )
521             });
522
523             err.span_suggestions(span, &msg, path_strings, Applicability::MaybeIncorrect);
524         } else {
525             let limit = if candidates.len() == 5 { 5 } else { 4 };
526             for (i, trait_did) in candidates.iter().take(limit).enumerate() {
527                 if candidates.len() > 1 {
528                     msg.push_str(
529                         &format!(
530                             "\ncandidate #{}: `use {};`",
531                             i + 1,
532                             with_crate_prefix(|| self.tcx.item_path_str(*trait_did))
533                         )
534                     );
535                 } else {
536                     msg.push_str(
537                         &format!(
538                             "\n`use {};`",
539                             with_crate_prefix(|| self.tcx.item_path_str(*trait_did))
540                         )
541                     );
542                 }
543             }
544             if candidates.len() > limit {
545                 msg.push_str(&format!("\nand {} others", candidates.len() - limit));
546             }
547             err.note(&msg[..]);
548         }
549     }
550
551     fn suggest_valid_traits(&self,
552                             err: &mut DiagnosticBuilder,
553                             valid_out_of_scope_traits: Vec<DefId>) -> bool {
554         if !valid_out_of_scope_traits.is_empty() {
555             let mut candidates = valid_out_of_scope_traits;
556             candidates.sort();
557             candidates.dedup();
558             err.help("items from traits can only be used if the trait is in scope");
559             let msg = format!("the following {traits_are} implemented but not in scope, \
560                                perhaps add a `use` for {one_of_them}:",
561                             traits_are = if candidates.len() == 1 {
562                                 "trait is"
563                             } else {
564                                 "traits are"
565                             },
566                             one_of_them = if candidates.len() == 1 {
567                                 "it"
568                             } else {
569                                 "one of them"
570                             });
571
572             self.suggest_use_candidates(err, msg, candidates);
573             true
574         } else {
575             false
576         }
577     }
578
579     fn suggest_traits_to_import<'b>(&self,
580                                     err: &mut DiagnosticBuilder,
581                                     span: Span,
582                                     rcvr_ty: Ty<'tcx>,
583                                     item_name: ast::Ident,
584                                     source: SelfSource<'b>,
585                                     valid_out_of_scope_traits: Vec<DefId>) {
586         if self.suggest_valid_traits(err, valid_out_of_scope_traits) {
587             return;
588         }
589
590         let type_is_local = self.type_derefs_to_local(span, rcvr_ty, source);
591
592         // There are no traits implemented, so lets suggest some traits to
593         // implement, by finding ones that have the item name, and are
594         // legal to implement.
595         let mut candidates = all_traits(self.tcx)
596             .into_iter()
597             .filter(|info| {
598                 // We approximate the coherence rules to only suggest
599                 // traits that are legal to implement by requiring that
600                 // either the type or trait is local. Multi-dispatch means
601                 // this isn't perfect (that is, there are cases when
602                 // implementing a trait would be legal but is rejected
603                 // here).
604                 (type_is_local || info.def_id.is_local()) &&
605                     self.associated_item(info.def_id, item_name, Namespace::Value)
606                         .filter(|item| {
607                             // We only want to suggest public or local traits (#45781).
608                             item.vis == ty::Visibility::Public || info.def_id.is_local()
609                         })
610                         .is_some()
611             })
612             .collect::<Vec<_>>();
613
614         if !candidates.is_empty() {
615             // Sort from most relevant to least relevant.
616             candidates.sort_by(|a, b| a.cmp(b).reverse());
617             candidates.dedup();
618
619             // FIXME #21673: this help message could be tuned to the case
620             // of a type parameter: suggest adding a trait bound rather
621             // than implementing.
622             err.help("items from traits can only be used if the trait is implemented and in scope");
623             let mut msg = format!("the following {traits_define} an item `{name}`, \
624                                    perhaps you need to implement {one_of_them}:",
625                                   traits_define = if candidates.len() == 1 {
626                                       "trait defines"
627                                   } else {
628                                       "traits define"
629                                   },
630                                   one_of_them = if candidates.len() == 1 {
631                                       "it"
632                                   } else {
633                                       "one of them"
634                                   },
635                                   name = item_name);
636
637             for (i, trait_info) in candidates.iter().enumerate() {
638                 msg.push_str(&format!("\ncandidate #{}: `{}`",
639                                       i + 1,
640                                       self.tcx.item_path_str(trait_info.def_id)));
641             }
642             err.note(&msg[..]);
643         }
644     }
645
646     /// Checks whether there is a local type somewhere in the chain of
647     /// autoderefs of `rcvr_ty`.
648     fn type_derefs_to_local(&self,
649                             span: Span,
650                             rcvr_ty: Ty<'tcx>,
651                             source: SelfSource) -> bool {
652         fn is_local(ty: Ty) -> bool {
653             match ty.sty {
654                 ty::Adt(def, _) => def.did.is_local(),
655                 ty::Foreign(did) => did.is_local(),
656
657                 ty::Dynamic(ref tr, ..) =>
658                     tr.principal().map(|d| d.def_id().is_local()).unwrap_or(false),
659
660                 ty::Param(_) => true,
661
662                 // Everything else (primitive types, etc.) is effectively
663                 // non-local (there are "edge" cases, e.g., `(LocalType,)`, but
664                 // the noise from these sort of types is usually just really
665                 // annoying, rather than any sort of help).
666                 _ => false,
667             }
668         }
669
670         // This occurs for UFCS desugaring of `T::method`, where there is no
671         // receiver expression for the method call, and thus no autoderef.
672         if let SelfSource::QPath(_) = source {
673             return is_local(self.resolve_type_vars_with_obligations(rcvr_ty));
674         }
675
676         self.autoderef(span, rcvr_ty).any(|(ty, _)| is_local(ty))
677     }
678 }
679
680 #[derive(Copy, Clone)]
681 pub enum SelfSource<'a> {
682     QPath(&'a hir::Ty),
683     MethodCall(&'a hir::Expr /* rcvr */),
684 }
685
686 #[derive(Copy, Clone)]
687 pub struct TraitInfo {
688     pub def_id: DefId,
689 }
690
691 impl PartialEq for TraitInfo {
692     fn eq(&self, other: &TraitInfo) -> bool {
693         self.cmp(other) == Ordering::Equal
694     }
695 }
696 impl Eq for TraitInfo {}
697 impl PartialOrd for TraitInfo {
698     fn partial_cmp(&self, other: &TraitInfo) -> Option<Ordering> {
699         Some(self.cmp(other))
700     }
701 }
702 impl Ord for TraitInfo {
703     fn cmp(&self, other: &TraitInfo) -> Ordering {
704         // Local crates are more important than remote ones (local:
705         // `cnum == 0`), and otherwise we throw in the defid for totality.
706
707         let lhs = (other.def_id.krate, other.def_id);
708         let rhs = (self.def_id.krate, self.def_id);
709         lhs.cmp(&rhs)
710     }
711 }
712
713 /// Retrieves all traits in this crate and any dependent crates.
714 pub fn all_traits<'a, 'gcx, 'tcx>(tcx: TyCtxt<'a, 'gcx, 'tcx>) -> Vec<TraitInfo> {
715     tcx.all_traits(LOCAL_CRATE).iter().map(|&def_id| TraitInfo { def_id }).collect()
716 }
717
718 /// Computes all traits in this crate and any dependent crates.
719 fn compute_all_traits<'a, 'gcx, 'tcx>(tcx: TyCtxt<'a, 'gcx, 'tcx>) -> Vec<DefId> {
720     use hir::itemlikevisit;
721
722     let mut traits = vec![];
723
724     // Crate-local:
725
726     struct Visitor<'a, 'tcx: 'a> {
727         map: &'a hir_map::Map<'tcx>,
728         traits: &'a mut Vec<DefId>,
729     }
730
731     impl<'v, 'a, 'tcx> itemlikevisit::ItemLikeVisitor<'v> for Visitor<'a, 'tcx> {
732         fn visit_item(&mut self, i: &'v hir::Item) {
733             if let hir::ItemKind::Trait(..) = i.node {
734                 let def_id = self.map.local_def_id(i.id);
735                 self.traits.push(def_id);
736             }
737         }
738
739         fn visit_trait_item(&mut self, _trait_item: &hir::TraitItem) {}
740
741         fn visit_impl_item(&mut self, _impl_item: &hir::ImplItem) {}
742     }
743
744     tcx.hir().krate().visit_all_item_likes(&mut Visitor {
745         map: &tcx.hir(),
746         traits: &mut traits,
747     });
748
749     // Cross-crate:
750
751     let mut external_mods = FxHashSet::default();
752     fn handle_external_def(tcx: TyCtxt,
753                            traits: &mut Vec<DefId>,
754                            external_mods: &mut FxHashSet<DefId>,
755                            def: Def) {
756         match def {
757             Def::Trait(def_id) => {
758                 traits.push(def_id);
759             }
760             Def::Mod(def_id) => {
761                 if !external_mods.insert(def_id) {
762                     return;
763                 }
764                 for child in tcx.item_children(def_id).iter() {
765                     handle_external_def(tcx, traits, external_mods, child.def)
766                 }
767             }
768             _ => {}
769         }
770     }
771     for &cnum in tcx.crates().iter() {
772         let def_id = DefId {
773             krate: cnum,
774             index: CRATE_DEF_INDEX,
775         };
776         handle_external_def(tcx, &mut traits, &mut external_mods, Def::Mod(def_id));
777     }
778
779     traits
780 }
781
782 pub fn provide(providers: &mut ty::query::Providers) {
783     providers.all_traits = |tcx, cnum| {
784         assert_eq!(cnum, LOCAL_CRATE);
785         Lrc::new(compute_all_traits(tcx))
786     }
787 }
788
789 struct UsePlacementFinder<'a, 'tcx: 'a, 'gcx: 'tcx> {
790     target_module: ast::NodeId,
791     span: Option<Span>,
792     found_use: bool,
793     tcx: TyCtxt<'a, 'gcx, 'tcx>
794 }
795
796 impl<'a, 'tcx, 'gcx> UsePlacementFinder<'a, 'tcx, 'gcx> {
797     fn check(
798         tcx: TyCtxt<'a, 'gcx, 'tcx>,
799         krate: &'tcx hir::Crate,
800         target_module: ast::NodeId,
801     ) -> (Option<Span>, bool) {
802         let mut finder = UsePlacementFinder {
803             target_module,
804             span: None,
805             found_use: false,
806             tcx,
807         };
808         hir::intravisit::walk_crate(&mut finder, krate);
809         (finder.span, finder.found_use)
810     }
811 }
812
813 impl<'a, 'tcx, 'gcx> hir::intravisit::Visitor<'tcx> for UsePlacementFinder<'a, 'tcx, 'gcx> {
814     fn visit_mod(
815         &mut self,
816         module: &'tcx hir::Mod,
817         _: Span,
818         node_id: ast::NodeId,
819     ) {
820         if self.span.is_some() {
821             return;
822         }
823         if node_id != self.target_module {
824             hir::intravisit::walk_mod(self, module, node_id);
825             return;
826         }
827         // Find a `use` statement.
828         for item_id in &module.item_ids {
829             let item = self.tcx.hir().expect_item(item_id.id);
830             match item.node {
831                 hir::ItemKind::Use(..) => {
832                     // Don't suggest placing a `use` before the prelude
833                     // import or other generated ones.
834                     if item.span.ctxt().outer().expn_info().is_none() {
835                         self.span = Some(item.span.shrink_to_lo());
836                         self.found_use = true;
837                         return;
838                     }
839                 },
840                 // Don't place `use` before `extern crate`...
841                 hir::ItemKind::ExternCrate(_) => {}
842                 // ...but do place them before the first other item.
843                 _ => if self.span.map_or(true, |span| item.span < span ) {
844                     if item.span.ctxt().outer().expn_info().is_none() {
845                         // Don't insert between attributes and an item.
846                         if item.attrs.is_empty() {
847                             self.span = Some(item.span.shrink_to_lo());
848                         } else {
849                             // Find the first attribute on the item.
850                             for attr in &item.attrs {
851                                 if self.span.map_or(true, |span| attr.span < span) {
852                                     self.span = Some(attr.span.shrink_to_lo());
853                                 }
854                             }
855                         }
856                     }
857                 },
858             }
859         }
860     }
861
862     fn nested_visit_map<'this>(
863         &'this mut self
864     ) -> hir::intravisit::NestedVisitorMap<'this, 'tcx> {
865         hir::intravisit::NestedVisitorMap::None
866     }
867 }