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