]> git.lizzy.rs Git - rust.git/blob - src/librustc_typeck/check/method/suggest.rs
Rename resolve_type_vars_with_obligations to
[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, pluralise};
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.kind {
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 ambiguous 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.kind {
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.kind {
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.kind {
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.kind
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                     let ty_str = if let Some(CandidateSource::ImplSource(
465                         impl_did,
466                     )) = static_sources.get(0) {
467                         // When the "method" is resolved through dereferencing, we really want the
468                         // original type that has the associated function for accurate suggestions.
469                         // (#61411)
470                         let ty = self.impl_self_ty(span, *impl_did).ty;
471                         match (&ty.peel_refs().kind, &actual.peel_refs().kind) {
472                             (ty::Adt(def, _), ty::Adt(def_actual, _)) if def == def_actual => {
473                                 // Use `actual` as it will have more `substs` filled in.
474                                 self.ty_to_value_string(actual.peel_refs())
475                             }
476                             _ => self.ty_to_value_string(ty.peel_refs()),
477                         }
478                     } else {
479                         self.ty_to_value_string(actual.peel_refs())
480                     };
481                     if let SelfSource::MethodCall(expr) = source {
482                         err.span_suggestion(
483                             expr.span.to(span),
484                             "use associated function syntax instead",
485                             format!("{}::{}", ty_str, item_name),
486                             Applicability::MachineApplicable,
487                         );
488                     } else {
489                         err.help(&format!(
490                             "try with `{}::{}`",
491                             ty_str,
492                             item_name,
493                         ));
494                     }
495
496                     report_candidates(span, &mut err, static_sources);
497                 } else if static_sources.len() > 1 {
498                     report_candidates(span, &mut err, static_sources);
499                 }
500
501                 if !unsatisfied_predicates.is_empty() {
502                     let mut bound_list = unsatisfied_predicates.iter()
503                         .map(|p| format!("`{} : {}`", p.self_ty(), p))
504                         .collect::<Vec<_>>();
505                     bound_list.sort();
506                     bound_list.dedup();  // #35677
507                     let bound_list = bound_list.join("\n");
508                     err.note(&format!("the method `{}` exists but the following trait bounds \
509                                        were not satisfied:\n{}",
510                                       item_name,
511                                       bound_list));
512                 }
513
514                 if actual.is_numeric() && actual.is_fresh() {
515
516                 } else {
517                     self.suggest_traits_to_import(&mut err,
518                                                   span,
519                                                   rcvr_ty,
520                                                   item_name,
521                                                   source,
522                                                   out_of_scope_traits);
523                 }
524
525                 if actual.is_enum() {
526                     let adt_def = actual.ty_adt_def().expect("enum is not an ADT");
527                     if let Some(suggestion) = lev_distance::find_best_match_for_name(
528                         adt_def.variants.iter().map(|s| &s.ident.name),
529                         &item_name.as_str(),
530                         None,
531                     ) {
532                         err.span_suggestion(
533                             span,
534                             "there is a variant with a similar name",
535                             suggestion.to_string(),
536                             Applicability::MaybeIncorrect,
537                         );
538                     }
539                 }
540
541                 let mut fallback_span = true;
542                 let msg = "remove this method call";
543                 if item_name.as_str() == "as_str" && actual.peel_refs().is_str() {
544                     if let SelfSource::MethodCall(expr) = source {
545                         let call_expr = self.tcx.hir().expect_expr(
546                             self.tcx.hir().get_parent_node(expr.hir_id),
547                         );
548                         if let Some(span) = call_expr.span.trim_start(expr.span) {
549                             err.span_suggestion(
550                                 span,
551                                 msg,
552                                 String::new(),
553                                 Applicability::MachineApplicable,
554                             );
555                             fallback_span = false;
556                         }
557                     }
558                     if fallback_span {
559                         err.span_label(span, msg);
560                     }
561                 } else if let Some(lev_candidate) = lev_candidate {
562                     let def_kind = lev_candidate.def_kind();
563                     err.span_suggestion(
564                         span,
565                         &format!(
566                             "there is {} {} with a similar name",
567                             def_kind.article(),
568                             def_kind.descr(lev_candidate.def_id),
569                         ),
570                         lev_candidate.ident.to_string(),
571                         Applicability::MaybeIncorrect,
572                     );
573                 }
574
575                 return Some(err);
576             }
577
578             MethodError::Ambiguity(sources) => {
579                 let mut err = struct_span_err!(self.sess(),
580                                                span,
581                                                E0034,
582                                                "multiple applicable items in scope");
583                 err.span_label(span, format!("multiple `{}` found", item_name));
584
585                 report_candidates(span, &mut err, sources);
586                 err.emit();
587             }
588
589             MethodError::PrivateMatch(kind, def_id, out_of_scope_traits) => {
590                 let mut err = struct_span_err!(self.tcx.sess, span, E0624,
591                                                "{} `{}` is private", kind.descr(def_id), item_name);
592                 self.suggest_valid_traits(&mut err, out_of_scope_traits);
593                 err.emit();
594             }
595
596             MethodError::IllegalSizedBound(candidates, needs_mut) => {
597                 let msg = format!("the `{}` method cannot be invoked on a trait object", item_name);
598                 let mut err = self.sess().struct_span_err(span, &msg);
599                 if !candidates.is_empty() {
600                     let help = format!(
601                         "{an}other candidate{s} {were} found in the following trait{s}, perhaps \
602                          add a `use` for {one_of_them}:",
603                         an = if candidates.len() == 1 {"an" } else { "" },
604                         s = pluralise!(candidates.len()),
605                         were = if candidates.len() == 1 { "was" } else { "were" },
606                         one_of_them = if candidates.len() == 1 {
607                             "it"
608                         } else {
609                             "one_of_them"
610                         },
611                     );
612                     self.suggest_use_candidates(&mut err, help, candidates);
613                 }
614                 if let ty::Ref(region, t_type, mutability) = rcvr_ty.kind {
615                     if needs_mut {
616                         let trait_type = self.tcx.mk_ref(region, ty::TypeAndMut {
617                             ty: t_type,
618                             mutbl: mutability.invert(),
619                         });
620                         err.note(&format!("you need `{}` instead of `{}`", trait_type, rcvr_ty));
621                     }
622                 }
623                 err.emit();
624             }
625
626             MethodError::BadReturnType => {
627                 bug!("no return type expectations but got BadReturnType")
628             }
629         }
630         None
631     }
632
633     /// Print out the type for use in value namespace.
634     fn ty_to_value_string(&self, ty: Ty<'tcx>) -> String {
635         match ty.kind {
636             ty::Adt(def, substs) => format!("{}", ty::Instance::new(def.did, substs)),
637             _ => self.ty_to_string(ty),
638         }
639     }
640
641     fn suggest_use_candidates(&self,
642                               err: &mut DiagnosticBuilder<'_>,
643                               mut msg: String,
644                               candidates: Vec<DefId>) {
645         let module_did = self.tcx.hir().get_module_parent(self.body_id);
646         let module_id = self.tcx.hir().as_local_hir_id(module_did).unwrap();
647         let krate = self.tcx.hir().krate();
648         let (span, found_use) = UsePlacementFinder::check(self.tcx, krate, module_id);
649         if let Some(span) = span {
650             let path_strings = candidates.iter().map(|did| {
651                 // Produce an additional newline to separate the new use statement
652                 // from the directly following item.
653                 let additional_newline = if found_use {
654                     ""
655                 } else {
656                     "\n"
657                 };
658                 format!(
659                     "use {};\n{}",
660                     with_crate_prefix(|| self.tcx.def_path_str(*did)),
661                     additional_newline
662                 )
663             });
664
665             err.span_suggestions(span, &msg, path_strings, Applicability::MaybeIncorrect);
666         } else {
667             let limit = if candidates.len() == 5 { 5 } else { 4 };
668             for (i, trait_did) in candidates.iter().take(limit).enumerate() {
669                 if candidates.len() > 1 {
670                     msg.push_str(
671                         &format!(
672                             "\ncandidate #{}: `use {};`",
673                             i + 1,
674                             with_crate_prefix(|| self.tcx.def_path_str(*trait_did))
675                         )
676                     );
677                 } else {
678                     msg.push_str(
679                         &format!(
680                             "\n`use {};`",
681                             with_crate_prefix(|| self.tcx.def_path_str(*trait_did))
682                         )
683                     );
684                 }
685             }
686             if candidates.len() > limit {
687                 msg.push_str(&format!("\nand {} others", candidates.len() - limit));
688             }
689             err.note(&msg[..]);
690         }
691     }
692
693     fn suggest_valid_traits(
694         &self,
695         err: &mut DiagnosticBuilder<'_>,
696         valid_out_of_scope_traits: Vec<DefId>,
697     ) -> bool {
698         if !valid_out_of_scope_traits.is_empty() {
699             let mut candidates = valid_out_of_scope_traits;
700             candidates.sort();
701             candidates.dedup();
702             err.help("items from traits can only be used if the trait is in scope");
703             let msg = format!(
704                 "the following {traits_are} implemented but not in scope; \
705                  perhaps add a `use` for {one_of_them}:",
706                 traits_are = if candidates.len() == 1 {
707                     "trait is"
708                 } else {
709                     "traits are"
710                 },
711                 one_of_them = if candidates.len() == 1 {
712                     "it"
713                 } else {
714                     "one of them"
715                 },
716             );
717
718             self.suggest_use_candidates(err, msg, candidates);
719             true
720         } else {
721             false
722         }
723     }
724
725     fn suggest_traits_to_import<'b>(
726         &self,
727         err: &mut DiagnosticBuilder<'_>,
728         span: Span,
729         rcvr_ty: Ty<'tcx>,
730         item_name: ast::Ident,
731         source: SelfSource<'b>,
732         valid_out_of_scope_traits: Vec<DefId>,
733     ) {
734         if self.suggest_valid_traits(err, valid_out_of_scope_traits) {
735             return;
736         }
737
738         let type_is_local = self.type_derefs_to_local(span, rcvr_ty, source);
739
740         // There are no traits implemented, so lets suggest some traits to
741         // implement, by finding ones that have the item name, and are
742         // legal to implement.
743         let mut candidates = all_traits(self.tcx)
744             .into_iter()
745             .filter(|info| {
746                 // We approximate the coherence rules to only suggest
747                 // traits that are legal to implement by requiring that
748                 // either the type or trait is local. Multi-dispatch means
749                 // this isn't perfect (that is, there are cases when
750                 // implementing a trait would be legal but is rejected
751                 // here).
752                 (type_is_local || info.def_id.is_local()) &&
753                     self.associated_item(info.def_id, item_name, Namespace::Value)
754                         .filter(|item| {
755                             // We only want to suggest public or local traits (#45781).
756                             item.vis == ty::Visibility::Public || info.def_id.is_local()
757                         })
758                         .is_some()
759             })
760             .collect::<Vec<_>>();
761
762         if !candidates.is_empty() {
763             // Sort from most relevant to least relevant.
764             candidates.sort_by(|a, b| a.cmp(b).reverse());
765             candidates.dedup();
766
767             let param_type = match rcvr_ty.kind {
768                 ty::Param(param) => Some(param),
769                 ty::Ref(_, ty, _) => match ty.kind {
770                     ty::Param(param) => Some(param),
771                     _ => None,
772                 }
773                 _ => None,
774             };
775             err.help(if param_type.is_some() {
776                 "items from traits can only be used if the type parameter is bounded by the trait"
777             } else {
778                 "items from traits can only be used if the trait is implemented and in scope"
779             });
780             let message = |action| format!(
781                 "the following {traits_define} an item `{name}`, perhaps you need to {action} \
782                  {one_of_them}:",
783                 traits_define = if candidates.len() == 1 {
784                     "trait defines"
785                 } else {
786                     "traits define"
787                 },
788                 action = action,
789                 one_of_them = if candidates.len() == 1 {
790                     "it"
791                 } else {
792                     "one of them"
793                 },
794                 name = item_name,
795             );
796             // Obtain the span for `param` and use it for a structured suggestion.
797             let mut suggested = false;
798             if let (Some(ref param), Some(ref table)) = (param_type, self.in_progress_tables) {
799                 let table = table.borrow();
800                 if let Some(did) = table.local_id_root {
801                     let generics = self.tcx.generics_of(did);
802                     let type_param = generics.type_param(param, self.tcx);
803                     let hir = &self.tcx.hir();
804                     if let Some(id) = hir.as_local_hir_id(type_param.def_id) {
805                         // Get the `hir::Param` to verify whether it already has any bounds.
806                         // We do this to avoid suggesting code that ends up as `T: FooBar`,
807                         // instead we suggest `T: Foo + Bar` in that case.
808                         match hir.get(id) {
809                             Node::GenericParam(ref param) => {
810                                 let mut impl_trait = false;
811                                 let has_bounds = if let hir::GenericParamKind::Type {
812                                     synthetic: Some(_), ..
813                                 } = &param.kind {
814                                     // We've found `fn foo(x: impl Trait)` instead of
815                                     // `fn foo<T>(x: T)`. We want to suggest the correct
816                                     // `fn foo(x: impl Trait + TraitBound)` instead of
817                                     // `fn foo<T: TraitBound>(x: T)`. (#63706)
818                                     impl_trait = true;
819                                     param.bounds.get(1)
820                                 } else {
821                                     param.bounds.get(0)
822                                 };
823                                 let sp = hir.span(id);
824                                 let sp = if let Some(first_bound) = has_bounds {
825                                     // `sp` only covers `T`, change it so that it covers
826                                     // `T:` when appropriate
827                                     sp.until(first_bound.span())
828                                 } else {
829                                     sp
830                                 };
831                                 // FIXME: contrast `t.def_id` against `param.bounds` to not suggest
832                                 // traits already there. That can happen when the cause is that
833                                 // we're in a const scope or associated function used as a method.
834                                 err.span_suggestions(
835                                     sp,
836                                     &message(format!(
837                                         "restrict type parameter `{}` with",
838                                         param.name.ident().as_str(),
839                                     )),
840                                     candidates.iter().map(|t| format!(
841                                         "{}{} {}{}",
842                                         param.name.ident().as_str(),
843                                         if impl_trait { " +" } else { ":" },
844                                         self.tcx.def_path_str(t.def_id),
845                                         if has_bounds.is_some() { " + "} else { "" },
846                                     )),
847                                     Applicability::MaybeIncorrect,
848                                 );
849                                 suggested = true;
850                             }
851                             Node::Item(hir::Item {
852                                 kind: hir::ItemKind::Trait(.., bounds, _), ident, ..
853                             }) => {
854                                 let (sp, sep, article) = if bounds.is_empty() {
855                                     (ident.span.shrink_to_hi(), ":", "a")
856                                 } else {
857                                     (bounds.last().unwrap().span().shrink_to_hi(), " +", "another")
858                                 };
859                                 err.span_suggestions(
860                                     sp,
861                                     &message(format!("add {} supertrait for", article)),
862                                     candidates.iter().map(|t| format!(
863                                         "{} {}",
864                                         sep,
865                                         self.tcx.def_path_str(t.def_id),
866                                     )),
867                                     Applicability::MaybeIncorrect,
868                                 );
869                                 suggested = true;
870                             }
871                             _ => {}
872                         }
873                     }
874                 };
875             }
876
877             if !suggested {
878                 let mut msg = message(if let Some(param) = param_type {
879                     format!("restrict type parameter `{}` with", param)
880                 } else {
881                     "implement".to_string()
882                 });
883                 for (i, trait_info) in candidates.iter().enumerate() {
884                     msg.push_str(&format!(
885                         "\ncandidate #{}: `{}`",
886                         i + 1,
887                         self.tcx.def_path_str(trait_info.def_id),
888                     ));
889                 }
890                 err.note(&msg[..]);
891             }
892         }
893     }
894
895     /// Checks whether there is a local type somewhere in the chain of
896     /// autoderefs of `rcvr_ty`.
897     fn type_derefs_to_local(&self,
898                             span: Span,
899                             rcvr_ty: Ty<'tcx>,
900                             source: SelfSource<'_>) -> bool {
901         fn is_local(ty: Ty<'_>) -> bool {
902             match ty.kind {
903                 ty::Adt(def, _) => def.did.is_local(),
904                 ty::Foreign(did) => did.is_local(),
905
906                 ty::Dynamic(ref tr, ..) =>
907                     tr.principal().map(|d| d.def_id().is_local()).unwrap_or(false),
908
909                 ty::Param(_) => true,
910
911                 // Everything else (primitive types, etc.) is effectively
912                 // non-local (there are "edge" cases, e.g., `(LocalType,)`, but
913                 // the noise from these sort of types is usually just really
914                 // annoying, rather than any sort of help).
915                 _ => false,
916             }
917         }
918
919         // This occurs for UFCS desugaring of `T::method`, where there is no
920         // receiver expression for the method call, and thus no autoderef.
921         if let SelfSource::QPath(_) = source {
922             return is_local(self.resolve_vars_with_obligations(rcvr_ty));
923         }
924
925         self.autoderef(span, rcvr_ty).any(|(ty, _)| is_local(ty))
926     }
927 }
928
929 #[derive(Copy, Clone)]
930 pub enum SelfSource<'a> {
931     QPath(&'a hir::Ty),
932     MethodCall(&'a hir::Expr /* rcvr */),
933 }
934
935 #[derive(Copy, Clone)]
936 pub struct TraitInfo {
937     pub def_id: DefId,
938 }
939
940 impl PartialEq for TraitInfo {
941     fn eq(&self, other: &TraitInfo) -> bool {
942         self.cmp(other) == Ordering::Equal
943     }
944 }
945 impl Eq for TraitInfo {}
946 impl PartialOrd for TraitInfo {
947     fn partial_cmp(&self, other: &TraitInfo) -> Option<Ordering> {
948         Some(self.cmp(other))
949     }
950 }
951 impl Ord for TraitInfo {
952     fn cmp(&self, other: &TraitInfo) -> Ordering {
953         // Local crates are more important than remote ones (local:
954         // `cnum == 0`), and otherwise we throw in the defid for totality.
955
956         let lhs = (other.def_id.krate, other.def_id);
957         let rhs = (self.def_id.krate, self.def_id);
958         lhs.cmp(&rhs)
959     }
960 }
961
962 /// Retrieves all traits in this crate and any dependent crates.
963 pub fn all_traits(tcx: TyCtxt<'_>) -> Vec<TraitInfo> {
964     tcx.all_traits(LOCAL_CRATE).iter().map(|&def_id| TraitInfo { def_id }).collect()
965 }
966
967 /// Computes all traits in this crate and any dependent crates.
968 fn compute_all_traits(tcx: TyCtxt<'_>) -> Vec<DefId> {
969     use hir::itemlikevisit;
970
971     let mut traits = vec![];
972
973     // Crate-local:
974
975     struct Visitor<'a, 'tcx> {
976         map: &'a hir_map::Map<'tcx>,
977         traits: &'a mut Vec<DefId>,
978     }
979
980     impl<'v, 'a, 'tcx> itemlikevisit::ItemLikeVisitor<'v> for Visitor<'a, 'tcx> {
981         fn visit_item(&mut self, i: &'v hir::Item) {
982             match i.kind {
983                 hir::ItemKind::Trait(..) |
984                 hir::ItemKind::TraitAlias(..) => {
985                     let def_id = self.map.local_def_id(i.hir_id);
986                     self.traits.push(def_id);
987                 }
988                 _ => ()
989             }
990         }
991
992         fn visit_trait_item(&mut self, _trait_item: &hir::TraitItem) {}
993
994         fn visit_impl_item(&mut self, _impl_item: &hir::ImplItem) {}
995     }
996
997     tcx.hir().krate().visit_all_item_likes(&mut Visitor {
998         map: &tcx.hir(),
999         traits: &mut traits,
1000     });
1001
1002     // Cross-crate:
1003
1004     let mut external_mods = FxHashSet::default();
1005     fn handle_external_res(
1006         tcx: TyCtxt<'_>,
1007         traits: &mut Vec<DefId>,
1008         external_mods: &mut FxHashSet<DefId>,
1009         res: Res,
1010     ) {
1011         match res {
1012             Res::Def(DefKind::Trait, def_id) |
1013             Res::Def(DefKind::TraitAlias, def_id) => {
1014                 traits.push(def_id);
1015             }
1016             Res::Def(DefKind::Mod, def_id) => {
1017                 if !external_mods.insert(def_id) {
1018                     return;
1019                 }
1020                 for child in tcx.item_children(def_id).iter() {
1021                     handle_external_res(tcx, traits, external_mods, child.res)
1022                 }
1023             }
1024             _ => {}
1025         }
1026     }
1027     for &cnum in tcx.crates().iter() {
1028         let def_id = DefId {
1029             krate: cnum,
1030             index: CRATE_DEF_INDEX,
1031         };
1032         handle_external_res(tcx, &mut traits, &mut external_mods, Res::Def(DefKind::Mod, def_id));
1033     }
1034
1035     traits
1036 }
1037
1038 pub fn provide(providers: &mut ty::query::Providers<'_>) {
1039     providers.all_traits = |tcx, cnum| {
1040         assert_eq!(cnum, LOCAL_CRATE);
1041         &tcx.arena.alloc(compute_all_traits(tcx))[..]
1042     }
1043 }
1044
1045 struct UsePlacementFinder<'tcx> {
1046     target_module: hir::HirId,
1047     span: Option<Span>,
1048     found_use: bool,
1049     tcx: TyCtxt<'tcx>,
1050 }
1051
1052 impl UsePlacementFinder<'tcx> {
1053     fn check(
1054         tcx: TyCtxt<'tcx>,
1055         krate: &'tcx hir::Crate,
1056         target_module: hir::HirId,
1057     ) -> (Option<Span>, bool) {
1058         let mut finder = UsePlacementFinder {
1059             target_module,
1060             span: None,
1061             found_use: false,
1062             tcx,
1063         };
1064         hir::intravisit::walk_crate(&mut finder, krate);
1065         (finder.span, finder.found_use)
1066     }
1067 }
1068
1069 impl hir::intravisit::Visitor<'tcx> for UsePlacementFinder<'tcx> {
1070     fn visit_mod(
1071         &mut self,
1072         module: &'tcx hir::Mod,
1073         _: Span,
1074         hir_id: hir::HirId,
1075     ) {
1076         if self.span.is_some() {
1077             return;
1078         }
1079         if hir_id != self.target_module {
1080             hir::intravisit::walk_mod(self, module, hir_id);
1081             return;
1082         }
1083         // Find a `use` statement.
1084         for item_id in &module.item_ids {
1085             let item = self.tcx.hir().expect_item(item_id.id);
1086             match item.kind {
1087                 hir::ItemKind::Use(..) => {
1088                     // Don't suggest placing a `use` before the prelude
1089                     // import or other generated ones.
1090                     if !item.span.from_expansion() {
1091                         self.span = Some(item.span.shrink_to_lo());
1092                         self.found_use = true;
1093                         return;
1094                     }
1095                 },
1096                 // Don't place `use` before `extern crate`...
1097                 hir::ItemKind::ExternCrate(_) => {}
1098                 // ...but do place them before the first other item.
1099                 _ => if self.span.map_or(true, |span| item.span < span ) {
1100                     if !item.span.from_expansion() {
1101                         // Don't insert between attributes and an item.
1102                         if item.attrs.is_empty() {
1103                             self.span = Some(item.span.shrink_to_lo());
1104                         } else {
1105                             // Find the first attribute on the item.
1106                             for attr in &item.attrs {
1107                                 if self.span.map_or(true, |span| attr.span < span) {
1108                                     self.span = Some(attr.span.shrink_to_lo());
1109                                 }
1110                             }
1111                         }
1112                     }
1113                 },
1114             }
1115         }
1116     }
1117
1118     fn nested_visit_map<'this>(
1119         &'this mut self
1120     ) -> hir::intravisit::NestedVisitorMap<'this, 'tcx> {
1121         hir::intravisit::NestedVisitorMap::None
1122     }
1123 }