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