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