1 //! Give useful errors and suggestions to users when an item can't be
2 //! found or is otherwise invalid.
4 use crate::check::FnCtxt;
5 use crate::middle::lang_items::FnOnceTraitLangItem;
6 use rustc::hir::map as hir_map;
7 use rustc::hir::map::Map;
8 use rustc::ty::print::with_crate_prefix;
9 use rustc::ty::{self, ToPolyTraitRef, ToPredicate, Ty, TyCtxt, TypeFoldable, WithConstness};
10 use rustc_data_structures::fx::{FxHashMap, FxHashSet};
11 use rustc_errors::{pluralize, struct_span_err, Applicability, DiagnosticBuilder};
13 use rustc_hir::def::{DefKind, Namespace, Res};
14 use rustc_hir::def_id::{DefId, CRATE_DEF_INDEX, LOCAL_CRATE};
15 use rustc_hir::intravisit;
16 use rustc_hir::{ExprKind, Node, QPath};
17 use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
18 use rustc_infer::traits::Obligation;
19 use rustc_span::{source_map, FileName, Span};
21 use syntax::util::lev_distance;
23 use std::cmp::Ordering;
25 use super::probe::Mode;
26 use super::{CandidateSource, MethodError, NoMatchData};
28 impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
29 fn is_fn_ty(&self, ty: Ty<'tcx>, span: Span) -> bool {
32 // Not all of these (e.g., unsafe fns) implement `FnOnce`,
33 // so we look for these beforehand.
34 ty::Closure(..) | ty::FnDef(..) | ty::FnPtr(_) => true,
35 // If it's not a simple function, look for things which implement `FnOnce`.
37 let fn_once = match tcx.lang_items().require(FnOnceTraitLangItem) {
38 Ok(fn_once) => fn_once,
39 Err(..) => return false,
42 self.autoderef(span, ty).any(|(ty, _)| {
44 let fn_once_substs = tcx.mk_substs_trait(
47 .next_ty_var(TypeVariableOrigin {
48 kind: TypeVariableOriginKind::MiscVariable,
53 let trait_ref = ty::TraitRef::new(fn_once, fn_once_substs);
54 let poly_trait_ref = trait_ref.to_poly_trait_ref();
55 let obligation = Obligation::misc(
59 poly_trait_ref.without_const().to_predicate(),
61 self.predicate_may_hold(&obligation)
68 pub fn report_method_error<'b>(
72 item_name: ast::Ident,
73 source: SelfSource<'b>,
74 error: MethodError<'tcx>,
75 args: Option<&'tcx [hir::Expr<'tcx>]>,
76 ) -> Option<DiagnosticBuilder<'_>> {
79 // Avoid suggestions when we don't know what's going on.
80 if rcvr_ty.references_error() {
84 let report_candidates = |span: Span,
85 err: &mut DiagnosticBuilder<'_>,
86 mut sources: Vec<CandidateSource>,
90 // Dynamic limit to avoid hiding just one candidate, which is silly.
91 let limit = if sources.len() == 5 { 5 } else { 4 };
93 for (idx, source) in sources.iter().take(limit).enumerate() {
95 CandidateSource::ImplSource(impl_did) => {
96 // Provide the best span we can. Use the item, if local to crate, else
97 // the impl, if local to crate (item may be defaulted), else nothing.
99 .associated_item(impl_did, item_name, Namespace::ValueNS)
101 let impl_trait_ref = self.tcx.impl_trait_ref(impl_did)?;
102 self.associated_item(
103 impl_trait_ref.def_id,
114 .span_if_local(item.def_id)
115 .or_else(|| self.tcx.hir().span_if_local(impl_did));
117 let impl_ty = self.impl_self_ty(span, impl_did).ty;
119 let insertion = match self.tcx.impl_trait_ref(impl_did) {
120 None => String::new(),
121 Some(trait_ref) => format!(
122 " of the trait `{}`",
123 self.tcx.def_path_str(trait_ref.def_id)
127 let (note_str, idx) = if sources.len() > 1 {
130 "candidate #{} is defined in an impl{} for the type `{}`",
140 "the candidate is defined in an impl{} for the type `{}`",
146 if let Some(note_span) = note_span {
147 // We have a span pointing to the method. Show note with snippet.
149 self.tcx.sess.source_map().def_span(note_span),
155 if let Some(trait_ref) = self.tcx.impl_trait_ref(impl_did) {
156 let path = self.tcx.def_path_str(trait_ref.def_id);
158 let ty = match item.kind {
160 | ty::AssocKind::Type
161 | ty::AssocKind::OpaqueTy => rcvr_ty,
162 ty::AssocKind::Method => self
168 .filter(|ty| ty.is_region_ptr() && !rcvr_ty.is_region_ptr())
172 print_disambiguation_help(
181 self.tcx.sess.source_map(),
185 CandidateSource::TraitSource(trait_did) => {
187 match self.associated_item(trait_did, item_name, Namespace::ValueNS) {
192 self.tcx.sess.source_map().def_span(self.tcx.def_span(item.def_id));
193 let idx = if sources.len() > 1 {
195 "candidate #{} is defined in the trait `{}`",
197 self.tcx.def_path_str(trait_did)
199 err.span_note(item_span, msg);
203 "the candidate is defined in the trait `{}`",
204 self.tcx.def_path_str(trait_did)
206 err.span_note(item_span, msg);
209 let path = self.tcx.def_path_str(trait_did);
210 print_disambiguation_help(
219 self.tcx.sess.source_map(),
224 if sources.len() > limit {
225 err.note(&format!("and {} others", sources.len() - limit));
229 let sugg_span = if let SelfSource::MethodCall(expr) = source {
230 // Given `foo.bar(baz)`, `expr` is `bar`, but we want to point to the whole thing.
231 self.tcx.hir().expect_expr(self.tcx.hir().get_parent_node(expr.hir_id)).span
237 MethodError::NoMatch(NoMatchData {
238 static_candidates: static_sources,
239 unsatisfied_predicates,
246 let actual = self.resolve_vars_if_possible(&rcvr_ty);
247 let ty_str = self.ty_to_string(actual);
248 let is_method = mode == Mode::MethodCall;
249 let item_kind = if is_method {
251 } else if actual.is_enum() {
252 "variant or associated item"
254 match (item_name.as_str().chars().next(), actual.is_fresh_ty()) {
255 (Some(name), false) if name.is_lowercase() => "function or associated item",
256 (Some(_), false) => "associated item",
257 (Some(_), true) | (None, false) => "variant or associated item",
258 (None, true) => "variant",
261 let mut err = if !actual.references_error() {
262 // Suggest clamping down the type if the method that is being attempted to
263 // be used exists at all, and the type is an ambiguous numeric type
264 // ({integer}/{float}).
265 let mut candidates = all_traits(self.tcx).into_iter().filter_map(|info| {
266 self.associated_item(info.def_id, item_name, Namespace::ValueNS)
268 if let (true, false, SelfSource::MethodCall(expr), Some(_)) = (
270 actual.has_concrete_skeleton(),
274 let mut err = struct_span_err!(
278 "can't call {} `{}` on ambiguous numeric type `{}`",
283 let concrete_type = if actual.is_integral() { "i32" } else { "f32" };
285 ExprKind::Lit(ref lit) => {
290 .span_to_snippet(lit.span)
291 .unwrap_or_else(|_| "<numeric literal>".to_owned());
296 "you must specify a concrete type for \
297 this numeric value, like `{}`",
300 format!("{}_{}", snippet, concrete_type),
301 Applicability::MaybeIncorrect,
304 ExprKind::Path(ref qpath) => {
306 if let &QPath::Resolved(_, ref path) = &qpath {
307 if let hir::def::Res::Local(hir_id) = path.res {
308 let span = tcx.hir().span(hir_id);
309 let snippet = tcx.sess.source_map().span_to_snippet(span);
310 let filename = tcx.sess.source_map().span_to_filename(span);
312 let parent_node = self
315 .get(self.tcx.hir().get_parent_node(hir_id));
317 "you must specify a type for this binding, like `{}`",
321 match (filename, parent_node, snippet) {
324 Node::Local(hir::Local {
325 source: hir::LocalSource::Normal,
332 // account for `let x: _ = 42;`
339 format!("{}: {}", snippet, concrete_type),
340 Applicability::MaybeIncorrect,
344 err.span_label(span, msg);
355 span = item_name.span;
356 let mut err = struct_span_err!(
360 "no {} named `{}` found for {} `{}` in the current scope",
363 actual.prefix_string(),
367 tcx.sess.confused_type_with_std_module.borrow().get(&span)
369 if let Ok(snippet) = tcx.sess.source_map().span_to_snippet(*span) {
372 "you are looking for the module in `std`, \
373 not the primitive type",
374 format!("std::{}", snippet),
375 Applicability::MachineApplicable,
379 if let ty::RawPtr(_) = &actual.kind {
381 "try using `<*const T>::as_ref()` to get a reference to the \
382 type behind the pointer: https://doc.rust-lang.org/std/\
383 primitive.pointer.html#method.as_ref",
386 "using `<*const T>::as_ref()` on a pointer \
387 which is unaligned or points to invalid \
388 or uninitialized memory is undefined behavior",
394 tcx.sess.diagnostic().struct_dummy()
397 if let Some(def) = actual.ty_adt_def() {
398 if let Some(full_sp) = tcx.hir().span_if_local(def.did) {
399 let def_sp = tcx.sess.source_map().def_span(full_sp);
403 "{} `{}` not found {}",
406 if def.is_enum() && !is_method { "here" } else { "for this" }
412 // If the method name is the name of a field with a function or closure type,
413 // give a helping note that it has to be called as `(x.f)(...)`.
414 if let SelfSource::MethodCall(expr) = source {
416 self.autoderef(span, rcvr_ty).find_map(|(ty, _)| match ty.kind {
417 ty::Adt(def, substs) if !def.is_enum() => {
418 let variant = &def.non_enum_variant();
419 self.tcx.find_field_index(item_name, variant).map(|index| {
420 let field = &variant.fields[index];
421 let field_ty = field.ty(tcx, substs);
428 if let Some((field, field_ty)) = field_receiver {
429 let scope = self.tcx.hir().get_module_parent(self.body_id);
430 let is_accessible = field.vis.is_accessible_from(scope, self.tcx);
433 if self.is_fn_ty(&field_ty, span) {
434 let expr_span = expr.span.to(item_name.span);
435 err.multipart_suggestion(
437 "to call the function stored in `{}`, \
438 surround the field access with parentheses",
442 (expr_span.shrink_to_lo(), '('.to_string()),
443 (expr_span.shrink_to_hi(), ')'.to_string()),
445 Applicability::MachineApplicable,
451 .expect_expr(self.tcx.hir().get_parent_node(expr.hir_id));
453 if let Some(span) = call_expr.span.trim_start(item_name.span) {
456 "remove the arguments",
458 Applicability::MaybeIncorrect,
464 let field_kind = if is_accessible { "field" } else { "private field" };
465 err.span_label(item_name.span, format!("{}, not a method", field_kind));
466 } else if lev_candidate.is_none() && static_sources.is_empty() {
467 err.span_label(span, format!("{} not found in `{}`", item_kind, ty_str));
468 self.tcx.sess.trait_methods_not_found.borrow_mut().insert(orig_span);
471 err.span_label(span, format!("{} not found in `{}`", item_kind, ty_str));
472 self.tcx.sess.trait_methods_not_found.borrow_mut().insert(orig_span);
475 if self.is_fn_ty(&rcvr_ty, span) {
476 macro_rules! report_function {
477 ($span:expr, $name:expr) => {
479 "`{}` is a function, perhaps you wish to call it",
485 if let SelfSource::MethodCall(expr) = source {
486 if let Ok(expr_string) = tcx.sess.source_map().span_to_snippet(expr.span) {
487 report_function!(expr.span, expr_string);
488 } else if let ExprKind::Path(QPath::Resolved(_, ref path)) = expr.kind {
489 if let Some(segment) = path.segments.last() {
490 report_function!(expr.span, segment.ident);
496 if !static_sources.is_empty() {
498 "found the following associated functions; to be used as methods, \
499 functions must have a `self` parameter",
501 err.span_label(span, "this is an associated function, not a method");
503 if static_sources.len() == 1 {
504 let ty_str = if let Some(CandidateSource::ImplSource(impl_did)) =
505 static_sources.get(0)
507 // When the "method" is resolved through dereferencing, we really want the
508 // original type that has the associated function for accurate suggestions.
510 let ty = self.impl_self_ty(span, *impl_did).ty;
511 match (&ty.peel_refs().kind, &actual.peel_refs().kind) {
512 (ty::Adt(def, _), ty::Adt(def_actual, _)) if def == def_actual => {
513 // Use `actual` as it will have more `substs` filled in.
514 self.ty_to_value_string(actual.peel_refs())
516 _ => self.ty_to_value_string(ty.peel_refs()),
519 self.ty_to_value_string(actual.peel_refs())
521 if let SelfSource::MethodCall(expr) = source {
524 "use associated function syntax instead",
525 format!("{}::{}", ty_str, item_name),
526 Applicability::MachineApplicable,
529 err.help(&format!("try with `{}::{}`", ty_str, item_name,));
532 report_candidates(span, &mut err, static_sources, sugg_span);
533 } else if static_sources.len() > 1 {
534 report_candidates(span, &mut err, static_sources, sugg_span);
537 if !unsatisfied_predicates.is_empty() {
539 |def_id| self.tcx.sess.source_map().def_span(self.tcx.def_span(def_id));
540 let mut type_params = FxHashMap::default();
541 let mut bound_spans = vec![];
542 let mut collect_type_param_suggestions =
543 |self_ty: Ty<'_>, parent_pred: &ty::Predicate<'_>, obligation: &str| {
544 if let (ty::Param(_), ty::Predicate::Trait(p, _)) =
545 (&self_ty.kind, parent_pred)
547 if let ty::Adt(def, _) = p.skip_binder().trait_ref.self_ty().kind {
548 let id = self.tcx.hir().as_local_hir_id(def.did).unwrap();
549 let node = self.tcx.hir().get(id);
551 hir::Node::Item(hir::Item { kind, .. }) => {
552 if let Some(g) = kind.generics() {
553 let key = match &g.where_clause.predicates[..] {
555 (pred.span().shrink_to_hi(), false)
559 .span_for_predicates_or_empty_place(),
565 .or_insert_with(FxHashSet::default)
566 .insert(obligation.to_owned());
574 let mut bound_span_label = |self_ty: Ty<'_>, obligation: &str, quiet: &str| {
576 "doesn't satisfy `{}`",
577 if obligation.len() > 50 { quiet } else { obligation }
579 match &self_ty.kind {
580 // Point at the type that couldn't satisfy the bound.
581 ty::Adt(def, _) => bound_spans.push((def_span(def.did), msg)),
582 // Point at the trait object that couldn't satisfy the bound.
583 ty::Dynamic(preds, _) => {
584 for pred in *preds.skip_binder() {
586 ty::ExistentialPredicate::Trait(tr) => {
587 bound_spans.push((def_span(tr.def_id), msg.clone()))
589 ty::ExistentialPredicate::Projection(_)
590 | ty::ExistentialPredicate::AutoTrait(_) => {}
594 // Point at the closure that couldn't satisfy the bound.
595 ty::Closure(def_id, _) => bound_spans
596 .push((def_span(*def_id), format!("doesn't satisfy `{}`", quiet))),
600 let mut format_pred = |pred| {
602 ty::Predicate::Projection(pred) => {
603 // `<Foo as Iterator>::Item = String`.
605 pred.skip_binder().projection_ty.trait_ref(self.tcx);
608 .associated_item(pred.skip_binder().projection_ty.item_def_id);
609 let ty = pred.skip_binder().ty;
610 let obligation = format!("{}::{} = {}", trait_ref, assoc.ident, ty);
612 "<_ as {}>::{} = {}",
613 trait_ref.print_only_trait_path(),
617 bound_span_label(trait_ref.self_ty(), &obligation, &quiet);
618 Some((obligation, trait_ref.self_ty()))
620 ty::Predicate::Trait(poly_trait_ref, _) => {
621 let p = poly_trait_ref.skip_binder().trait_ref;
622 let self_ty = p.self_ty();
623 let path = p.print_only_trait_path();
624 let obligation = format!("{}: {}", self_ty, path);
625 let quiet = format!("_: {}", path);
626 bound_span_label(self_ty, &obligation, &quiet);
627 Some((obligation, self_ty))
632 let mut bound_list = unsatisfied_predicates
634 .filter_map(|(pred, parent_pred)| {
635 format_pred(*pred).map(|(p, self_ty)| match parent_pred {
636 None => format!("`{}`", p),
637 Some(parent_pred) => match format_pred(*parent_pred) {
638 None => format!("`{}`", p),
639 Some((parent_p, _)) => {
640 collect_type_param_suggestions(self_ty, parent_pred, &p);
641 format!("`{}` which is required by `{}`", p, parent_p)
646 .collect::<Vec<String>>();
647 for ((span, empty_where), obligations) in type_params.into_iter() {
648 err.span_suggestion_verbose(
651 "consider restricting the type parameter{s} to satisfy the \
653 s = pluralize!(obligations.len())
657 if empty_where { " where" } else { "," },
658 obligations.into_iter().collect::<Vec<_>>().join(", ")
660 Applicability::MaybeIncorrect,
665 bound_list.dedup(); // #35677
668 for (span, msg) in bound_spans.into_iter() {
669 err.span_label(span, &msg);
671 if !bound_list.is_empty() {
672 let bound_list = bound_list.join("\n");
674 "the method `{}` exists but the following trait bounds were not \
676 item_name, bound_list
681 if actual.is_numeric() && actual.is_fresh() {
683 self.suggest_traits_to_import(
693 if actual.is_enum() {
694 let adt_def = actual.ty_adt_def().expect("enum is not an ADT");
695 if let Some(suggestion) = lev_distance::find_best_match_for_name(
696 adt_def.variants.iter().map(|s| &s.ident.name),
702 "there is a variant with a similar name",
703 suggestion.to_string(),
704 Applicability::MaybeIncorrect,
709 let mut fallback_span = true;
710 let msg = "remove this method call";
711 if item_name.as_str() == "as_str" && actual.peel_refs().is_str() {
712 if let SelfSource::MethodCall(expr) = source {
714 self.tcx.hir().expect_expr(self.tcx.hir().get_parent_node(expr.hir_id));
715 if let Some(span) = call_expr.span.trim_start(expr.span) {
720 Applicability::MachineApplicable,
722 fallback_span = false;
726 err.span_label(span, msg);
728 } else if let Some(lev_candidate) = lev_candidate {
729 let def_kind = lev_candidate.def_kind();
733 "there is {} {} with a similar name",
735 def_kind.descr(lev_candidate.def_id),
737 lev_candidate.ident.to_string(),
738 Applicability::MaybeIncorrect,
745 MethodError::Ambiguity(sources) => {
746 let mut err = struct_span_err!(
750 "multiple applicable items in scope"
752 err.span_label(span, format!("multiple `{}` found", item_name));
754 report_candidates(span, &mut err, sources, sugg_span);
758 MethodError::PrivateMatch(kind, def_id, out_of_scope_traits) => {
759 let mut err = struct_span_err!(
763 "{} `{}` is private",
767 self.suggest_valid_traits(&mut err, out_of_scope_traits);
771 MethodError::IllegalSizedBound(candidates, needs_mut, bound_span) => {
772 let msg = format!("the `{}` method cannot be invoked on a trait object", item_name);
773 let mut err = self.sess().struct_span_err(span, &msg);
774 err.span_label(bound_span, "this has a `Sized` requirement");
775 if !candidates.is_empty() {
777 "{an}other candidate{s} {were} found in the following trait{s}, perhaps \
778 add a `use` for {one_of_them}:",
779 an = if candidates.len() == 1 { "an" } else { "" },
780 s = pluralize!(candidates.len()),
781 were = if candidates.len() == 1 { "was" } else { "were" },
782 one_of_them = if candidates.len() == 1 { "it" } else { "one_of_them" },
784 self.suggest_use_candidates(&mut err, help, candidates);
786 if let ty::Ref(region, t_type, mutability) = rcvr_ty.kind {
788 let trait_type = self.tcx.mk_ref(
790 ty::TypeAndMut { ty: t_type, mutbl: mutability.invert() },
792 err.note(&format!("you need `{}` instead of `{}`", trait_type, rcvr_ty));
798 MethodError::BadReturnType => bug!("no return type expectations but got BadReturnType"),
803 /// Print out the type for use in value namespace.
804 fn ty_to_value_string(&self, ty: Ty<'tcx>) -> String {
806 ty::Adt(def, substs) => format!("{}", ty::Instance::new(def.did, substs)),
807 _ => self.ty_to_string(ty),
811 fn suggest_use_candidates(
813 err: &mut DiagnosticBuilder<'_>,
815 candidates: Vec<DefId>,
817 let module_did = self.tcx.hir().get_module_parent(self.body_id);
818 let module_id = self.tcx.hir().as_local_hir_id(module_did).unwrap();
819 let krate = self.tcx.hir().krate();
820 let (span, found_use) = UsePlacementFinder::check(self.tcx, krate, module_id);
821 if let Some(span) = span {
822 let path_strings = candidates.iter().map(|did| {
823 // Produce an additional newline to separate the new use statement
824 // from the directly following item.
825 let additional_newline = if found_use { "" } else { "\n" };
828 with_crate_prefix(|| self.tcx.def_path_str(*did)),
833 err.span_suggestions(span, &msg, path_strings, Applicability::MaybeIncorrect);
835 let limit = if candidates.len() == 5 { 5 } else { 4 };
836 for (i, trait_did) in candidates.iter().take(limit).enumerate() {
837 if candidates.len() > 1 {
838 msg.push_str(&format!(
839 "\ncandidate #{}: `use {};`",
841 with_crate_prefix(|| self.tcx.def_path_str(*trait_did))
844 msg.push_str(&format!(
846 with_crate_prefix(|| self.tcx.def_path_str(*trait_did))
850 if candidates.len() > limit {
851 msg.push_str(&format!("\nand {} others", candidates.len() - limit));
857 fn suggest_valid_traits(
859 err: &mut DiagnosticBuilder<'_>,
860 valid_out_of_scope_traits: Vec<DefId>,
862 if !valid_out_of_scope_traits.is_empty() {
863 let mut candidates = valid_out_of_scope_traits;
866 err.help("items from traits can only be used if the trait is in scope");
868 "the following {traits_are} implemented but not in scope; \
869 perhaps add a `use` for {one_of_them}:",
870 traits_are = if candidates.len() == 1 { "trait is" } else { "traits are" },
871 one_of_them = if candidates.len() == 1 { "it" } else { "one of them" },
874 self.suggest_use_candidates(err, msg, candidates);
881 fn suggest_traits_to_import<'b>(
883 err: &mut DiagnosticBuilder<'_>,
886 item_name: ast::Ident,
887 source: SelfSource<'b>,
888 valid_out_of_scope_traits: Vec<DefId>,
890 if self.suggest_valid_traits(err, valid_out_of_scope_traits) {
894 let type_is_local = self.type_derefs_to_local(span, rcvr_ty, source);
896 // There are no traits implemented, so lets suggest some traits to
897 // implement, by finding ones that have the item name, and are
898 // legal to implement.
899 let mut candidates = all_traits(self.tcx)
902 // We approximate the coherence rules to only suggest
903 // traits that are legal to implement by requiring that
904 // either the type or trait is local. Multi-dispatch means
905 // this isn't perfect (that is, there are cases when
906 // implementing a trait would be legal but is rejected
908 (type_is_local || info.def_id.is_local())
910 .associated_item(info.def_id, item_name, Namespace::ValueNS)
912 // We only want to suggest public or local traits (#45781).
913 item.vis == ty::Visibility::Public || info.def_id.is_local()
917 .collect::<Vec<_>>();
919 if !candidates.is_empty() {
920 // Sort from most relevant to least relevant.
921 candidates.sort_by(|a, b| a.cmp(b).reverse());
924 let param_type = match rcvr_ty.kind {
925 ty::Param(param) => Some(param),
926 ty::Ref(_, ty, _) => match ty.kind {
927 ty::Param(param) => Some(param),
932 err.help(if param_type.is_some() {
933 "items from traits can only be used if the type parameter is bounded by the trait"
935 "items from traits can only be used if the trait is implemented and in scope"
937 let message = |action| {
939 "the following {traits_define} an item `{name}`, perhaps you need to {action} \
942 if candidates.len() == 1 { "trait defines" } else { "traits define" },
944 one_of_them = if candidates.len() == 1 { "it" } else { "one of them" },
948 // Obtain the span for `param` and use it for a structured suggestion.
949 let mut suggested = false;
950 if let (Some(ref param), Some(ref table)) = (param_type, self.in_progress_tables) {
951 let table = table.borrow();
952 if let Some(did) = table.local_id_root {
953 let generics = self.tcx.generics_of(did);
954 let type_param = generics.type_param(param, self.tcx);
955 let hir = &self.tcx.hir();
956 if let Some(id) = hir.as_local_hir_id(type_param.def_id) {
957 // Get the `hir::Param` to verify whether it already has any bounds.
958 // We do this to avoid suggesting code that ends up as `T: FooBar`,
959 // instead we suggest `T: Foo + Bar` in that case.
961 Node::GenericParam(ref param) => {
962 let mut impl_trait = false;
963 let has_bounds = if let hir::GenericParamKind::Type {
968 // We've found `fn foo(x: impl Trait)` instead of
969 // `fn foo<T>(x: T)`. We want to suggest the correct
970 // `fn foo(x: impl Trait + TraitBound)` instead of
971 // `fn foo<T: TraitBound>(x: T)`. (#63706)
977 let sp = hir.span(id);
978 let sp = if let Some(first_bound) = has_bounds {
979 // `sp` only covers `T`, change it so that it covers
980 // `T:` when appropriate
981 sp.until(first_bound.span())
985 let trait_def_ids: FxHashSet<DefId> = param
988 .filter_map(|bound| bound.trait_def_id())
990 if !candidates.iter().any(|t| trait_def_ids.contains(&t.def_id)) {
991 err.span_suggestions(
994 "restrict type parameter `{}` with",
997 candidates.iter().map(|t| {
1001 if impl_trait { " +" } else { ":" },
1002 self.tcx.def_path_str(t.def_id),
1003 if has_bounds.is_some() { " + " } else { "" },
1006 Applicability::MaybeIncorrect,
1011 Node::Item(hir::Item {
1012 kind: hir::ItemKind::Trait(.., bounds, _),
1016 let (sp, sep, article) = if bounds.is_empty() {
1017 (ident.span.shrink_to_hi(), ":", "a")
1019 (bounds.last().unwrap().span().shrink_to_hi(), " +", "another")
1021 err.span_suggestions(
1023 &message(format!("add {} supertrait for", article)),
1024 candidates.iter().map(|t| {
1025 format!("{} {}", sep, self.tcx.def_path_str(t.def_id),)
1027 Applicability::MaybeIncorrect,
1038 let action = if let Some(param) = param_type {
1039 format!("restrict type parameter `{}` with", param)
1041 // FIXME: it might only need to be imported into scope, not implemented.
1042 "implement".to_string()
1044 let mut use_note = true;
1045 if let [trait_info] = &candidates[..] {
1046 if let Some(span) = self.tcx.hir().span_if_local(trait_info.def_id) {
1048 self.tcx.sess.source_map().def_span(span),
1050 "`{}` defines an item `{}`, perhaps you need to {} it",
1051 self.tcx.def_path_str(trait_info.def_id),
1060 let mut msg = message(action);
1061 for (i, trait_info) in candidates.iter().enumerate() {
1062 msg.push_str(&format!(
1063 "\ncandidate #{}: `{}`",
1065 self.tcx.def_path_str(trait_info.def_id),
1074 /// Checks whether there is a local type somewhere in the chain of
1075 /// autoderefs of `rcvr_ty`.
1076 fn type_derefs_to_local(&self, span: Span, rcvr_ty: Ty<'tcx>, source: SelfSource<'_>) -> bool {
1077 fn is_local(ty: Ty<'_>) -> bool {
1079 ty::Adt(def, _) => def.did.is_local(),
1080 ty::Foreign(did) => did.is_local(),
1082 ty::Dynamic(ref tr, ..) => {
1083 tr.principal().map(|d| d.def_id().is_local()).unwrap_or(false)
1086 ty::Param(_) => true,
1088 // Everything else (primitive types, etc.) is effectively
1089 // non-local (there are "edge" cases, e.g., `(LocalType,)`, but
1090 // the noise from these sort of types is usually just really
1091 // annoying, rather than any sort of help).
1096 // This occurs for UFCS desugaring of `T::method`, where there is no
1097 // receiver expression for the method call, and thus no autoderef.
1098 if let SelfSource::QPath(_) = source {
1099 return is_local(self.resolve_vars_with_obligations(rcvr_ty));
1102 self.autoderef(span, rcvr_ty).any(|(ty, _)| is_local(ty))
1106 #[derive(Copy, Clone)]
1107 pub enum SelfSource<'a> {
1108 QPath(&'a hir::Ty<'a>),
1109 MethodCall(&'a hir::Expr<'a> /* rcvr */),
1112 #[derive(Copy, Clone)]
1113 pub struct TraitInfo {
1117 impl PartialEq for TraitInfo {
1118 fn eq(&self, other: &TraitInfo) -> bool {
1119 self.cmp(other) == Ordering::Equal
1122 impl Eq for TraitInfo {}
1123 impl PartialOrd for TraitInfo {
1124 fn partial_cmp(&self, other: &TraitInfo) -> Option<Ordering> {
1125 Some(self.cmp(other))
1128 impl Ord for TraitInfo {
1129 fn cmp(&self, other: &TraitInfo) -> Ordering {
1130 // Local crates are more important than remote ones (local:
1131 // `cnum == 0`), and otherwise we throw in the defid for totality.
1133 let lhs = (other.def_id.krate, other.def_id);
1134 let rhs = (self.def_id.krate, self.def_id);
1139 /// Retrieves all traits in this crate and any dependent crates.
1140 pub fn all_traits(tcx: TyCtxt<'_>) -> Vec<TraitInfo> {
1141 tcx.all_traits(LOCAL_CRATE).iter().map(|&def_id| TraitInfo { def_id }).collect()
1144 /// Computes all traits in this crate and any dependent crates.
1145 fn compute_all_traits(tcx: TyCtxt<'_>) -> Vec<DefId> {
1146 use hir::itemlikevisit;
1148 let mut traits = vec![];
1152 struct Visitor<'a, 'tcx> {
1153 map: &'a hir_map::Map<'tcx>,
1154 traits: &'a mut Vec<DefId>,
1157 impl<'v, 'a, 'tcx> itemlikevisit::ItemLikeVisitor<'v> for Visitor<'a, 'tcx> {
1158 fn visit_item(&mut self, i: &'v hir::Item<'v>) {
1160 hir::ItemKind::Trait(..) | hir::ItemKind::TraitAlias(..) => {
1161 let def_id = self.map.local_def_id(i.hir_id);
1162 self.traits.push(def_id);
1168 fn visit_trait_item(&mut self, _trait_item: &hir::TraitItem<'_>) {}
1170 fn visit_impl_item(&mut self, _impl_item: &hir::ImplItem<'_>) {}
1173 tcx.hir().krate().visit_all_item_likes(&mut Visitor { map: &tcx.hir(), traits: &mut traits });
1177 let mut external_mods = FxHashSet::default();
1178 fn handle_external_res(
1180 traits: &mut Vec<DefId>,
1181 external_mods: &mut FxHashSet<DefId>,
1185 Res::Def(DefKind::Trait, def_id) | Res::Def(DefKind::TraitAlias, def_id) => {
1186 traits.push(def_id);
1188 Res::Def(DefKind::Mod, def_id) => {
1189 if !external_mods.insert(def_id) {
1192 for child in tcx.item_children(def_id).iter() {
1193 handle_external_res(tcx, traits, external_mods, child.res)
1199 for &cnum in tcx.crates().iter() {
1200 let def_id = DefId { krate: cnum, index: CRATE_DEF_INDEX };
1201 handle_external_res(tcx, &mut traits, &mut external_mods, Res::Def(DefKind::Mod, def_id));
1207 pub fn provide(providers: &mut ty::query::Providers<'_>) {
1208 providers.all_traits = |tcx, cnum| {
1209 assert_eq!(cnum, LOCAL_CRATE);
1210 &tcx.arena.alloc(compute_all_traits(tcx))[..]
1214 struct UsePlacementFinder<'tcx> {
1215 target_module: hir::HirId,
1221 impl UsePlacementFinder<'tcx> {
1224 krate: &'tcx hir::Crate<'tcx>,
1225 target_module: hir::HirId,
1226 ) -> (Option<Span>, bool) {
1227 let mut finder = UsePlacementFinder { target_module, span: None, found_use: false, tcx };
1228 intravisit::walk_crate(&mut finder, krate);
1229 (finder.span, finder.found_use)
1233 impl intravisit::Visitor<'tcx> for UsePlacementFinder<'tcx> {
1234 fn visit_mod(&mut self, module: &'tcx hir::Mod<'tcx>, _: Span, hir_id: hir::HirId) {
1235 if self.span.is_some() {
1238 if hir_id != self.target_module {
1239 intravisit::walk_mod(self, module, hir_id);
1242 // Find a `use` statement.
1243 for item_id in module.item_ids {
1244 let item = self.tcx.hir().expect_item(item_id.id);
1246 hir::ItemKind::Use(..) => {
1247 // Don't suggest placing a `use` before the prelude
1248 // import or other generated ones.
1249 if !item.span.from_expansion() {
1250 self.span = Some(item.span.shrink_to_lo());
1251 self.found_use = true;
1255 // Don't place `use` before `extern crate`...
1256 hir::ItemKind::ExternCrate(_) => {}
1257 // ...but do place them before the first other item.
1259 if self.span.map_or(true, |span| item.span < span) {
1260 if !item.span.from_expansion() {
1261 // Don't insert between attributes and an item.
1262 if item.attrs.is_empty() {
1263 self.span = Some(item.span.shrink_to_lo());
1265 // Find the first attribute on the item.
1266 for attr in item.attrs {
1267 if self.span.map_or(true, |span| attr.span < span) {
1268 self.span = Some(attr.span.shrink_to_lo());
1279 type Map = Map<'tcx>;
1281 fn nested_visit_map(&mut self) -> intravisit::NestedVisitorMap<'_, Self::Map> {
1282 intravisit::NestedVisitorMap::None
1286 fn print_disambiguation_help(
1287 item_name: ast::Ident,
1288 args: Option<&'tcx [hir::Expr<'tcx>]>,
1289 err: &mut DiagnosticBuilder<'_>,
1292 kind: ty::AssocKind,
1294 candidate: Option<usize>,
1295 source_map: &source_map::SourceMap,
1297 let mut applicability = Applicability::MachineApplicable;
1298 let sugg_args = if let (ty::AssocKind::Method, Some(args)) = (kind, args) {
1301 if rcvr_ty.is_region_ptr() {
1302 if rcvr_ty.is_mutable_ptr() { "&mut " } else { "&" }
1307 .map(|arg| source_map.span_to_snippet(arg.span).unwrap_or_else(|_| {
1308 applicability = Applicability::HasPlaceholders;
1311 .collect::<Vec<_>>()
1317 let sugg = format!("{}::{}{}", trait_name, item_name, sugg_args);
1318 err.span_suggestion(
1321 "disambiguate the {} for {}",
1322 kind.suggestion_descr(),
1323 if let Some(candidate) = candidate {
1324 format!("candidate #{}", candidate)
1326 "the candidate".to_string()