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;
6 use rustc_ast::util::lev_distance;
7 use rustc_data_structures::fx::{FxHashMap, FxHashSet};
8 use rustc_errors::{pluralize, struct_span_err, Applicability, DiagnosticBuilder};
10 use rustc_hir::def::{DefKind, Namespace, Res};
11 use rustc_hir::def_id::{DefId, CRATE_DEF_INDEX, LOCAL_CRATE};
12 use rustc_hir::intravisit;
13 use rustc_hir::lang_items::FnOnceTraitLangItem;
14 use rustc_hir::{ExprKind, Node, QPath};
15 use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
16 use rustc_middle::hir::map as hir_map;
17 use rustc_middle::ty::print::with_crate_prefix;
18 use rustc_middle::ty::{
19 self, ToPolyTraitRef, ToPredicate, Ty, TyCtxt, TypeFoldable, WithConstness,
21 use rustc_span::symbol::kw;
22 use rustc_span::{source_map, FileName, Span};
23 use rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt;
24 use rustc_trait_selection::traits::Obligation;
26 use std::cmp::Ordering;
28 use super::probe::Mode;
29 use super::{CandidateSource, MethodError, NoMatchData};
31 impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
32 fn is_fn_ty(&self, ty: Ty<'tcx>, span: Span) -> bool {
35 // Not all of these (e.g., unsafe fns) implement `FnOnce`,
36 // so we look for these beforehand.
37 ty::Closure(..) | ty::FnDef(..) | ty::FnPtr(_) => true,
38 // If it's not a simple function, look for things which implement `FnOnce`.
40 let fn_once = match tcx.lang_items().require(FnOnceTraitLangItem) {
41 Ok(fn_once) => fn_once,
42 Err(..) => return false,
45 self.autoderef(span, ty).any(|(ty, _)| {
47 let fn_once_substs = tcx.mk_substs_trait(
50 .next_ty_var(TypeVariableOrigin {
51 kind: TypeVariableOriginKind::MiscVariable,
56 let trait_ref = ty::TraitRef::new(fn_once, fn_once_substs);
57 let poly_trait_ref = trait_ref.to_poly_trait_ref();
58 let obligation = Obligation::misc(
62 poly_trait_ref.without_const().to_predicate(),
64 self.predicate_may_hold(&obligation)
71 pub fn report_method_error<'b>(
75 item_name: ast::Ident,
76 source: SelfSource<'b>,
77 error: MethodError<'tcx>,
78 args: Option<&'tcx [hir::Expr<'tcx>]>,
79 ) -> Option<DiagnosticBuilder<'_>> {
82 // Avoid suggestions when we don't know what's going on.
83 if rcvr_ty.references_error() {
87 let report_candidates = |span: Span,
88 err: &mut DiagnosticBuilder<'_>,
89 mut sources: Vec<CandidateSource>,
93 // Dynamic limit to avoid hiding just one candidate, which is silly.
94 let limit = if sources.len() == 5 { 5 } else { 4 };
96 for (idx, source) in sources.iter().take(limit).enumerate() {
98 CandidateSource::ImplSource(impl_did) => {
99 // Provide the best span we can. Use the item, if local to crate, else
100 // the impl, if local to crate (item may be defaulted), else nothing.
101 let item = match self
102 .associated_item(impl_did, item_name, Namespace::ValueNS)
104 let impl_trait_ref = self.tcx.impl_trait_ref(impl_did)?;
105 self.associated_item(
106 impl_trait_ref.def_id,
117 .span_if_local(item.def_id)
118 .or_else(|| self.tcx.hir().span_if_local(impl_did));
120 let impl_ty = self.impl_self_ty(span, impl_did).ty;
122 let insertion = match self.tcx.impl_trait_ref(impl_did) {
123 None => String::new(),
124 Some(trait_ref) => format!(
125 " of the trait `{}`",
126 self.tcx.def_path_str(trait_ref.def_id)
130 let (note_str, idx) = if sources.len() > 1 {
133 "candidate #{} is defined in an impl{} for the type `{}`",
143 "the candidate is defined in an impl{} for the type `{}`",
149 if let Some(note_span) = note_span {
150 // We have a span pointing to the method. Show note with snippet.
152 self.tcx.sess.source_map().guess_head_span(note_span),
158 if let Some(trait_ref) = self.tcx.impl_trait_ref(impl_did) {
159 let path = self.tcx.def_path_str(trait_ref.def_id);
161 let ty = match item.kind {
163 | ty::AssocKind::Type
164 | ty::AssocKind::OpaqueTy => rcvr_ty,
165 ty::AssocKind::Method => self
171 .filter(|ty| ty.is_region_ptr() && !rcvr_ty.is_region_ptr())
175 print_disambiguation_help(
184 self.tcx.sess.source_map(),
188 CandidateSource::TraitSource(trait_did) => {
190 match self.associated_item(trait_did, item_name, Namespace::ValueNS) {
198 .guess_head_span(self.tcx.def_span(item.def_id));
199 let idx = if sources.len() > 1 {
201 "candidate #{} is defined in the trait `{}`",
203 self.tcx.def_path_str(trait_did)
205 err.span_note(item_span, msg);
209 "the candidate is defined in the trait `{}`",
210 self.tcx.def_path_str(trait_did)
212 err.span_note(item_span, msg);
215 let path = self.tcx.def_path_str(trait_did);
216 print_disambiguation_help(
225 self.tcx.sess.source_map(),
230 if sources.len() > limit {
231 err.note(&format!("and {} others", sources.len() - limit));
235 let sugg_span = if let SelfSource::MethodCall(expr) = source {
236 // Given `foo.bar(baz)`, `expr` is `bar`, but we want to point to the whole thing.
237 self.tcx.hir().expect_expr(self.tcx.hir().get_parent_node(expr.hir_id)).span
243 MethodError::NoMatch(NoMatchData {
244 static_candidates: static_sources,
245 unsatisfied_predicates,
252 let actual = self.resolve_vars_if_possible(&rcvr_ty);
253 let ty_str = self.ty_to_string(actual);
254 let is_method = mode == Mode::MethodCall;
255 let item_kind = if is_method {
257 } else if actual.is_enum() {
258 "variant or associated item"
260 match (item_name.as_str().chars().next(), actual.is_fresh_ty()) {
261 (Some(name), false) if name.is_lowercase() => "function or associated item",
262 (Some(_), false) => "associated item",
263 (Some(_), true) | (None, false) => "variant or associated item",
264 (None, true) => "variant",
267 let mut err = if !actual.references_error() {
268 // Suggest clamping down the type if the method that is being attempted to
269 // be used exists at all, and the type is an ambiguous numeric type
270 // ({integer}/{float}).
271 let mut candidates = all_traits(self.tcx).into_iter().filter_map(|info| {
272 self.associated_item(info.def_id, item_name, Namespace::ValueNS)
274 if let (true, false, SelfSource::MethodCall(expr), Some(_)) = (
276 actual.has_concrete_skeleton(),
280 let mut err = struct_span_err!(
284 "can't call {} `{}` on ambiguous numeric type `{}`",
289 let concrete_type = if actual.is_integral() { "i32" } else { "f32" };
291 ExprKind::Lit(ref lit) => {
296 .span_to_snippet(lit.span)
297 .unwrap_or_else(|_| "<numeric literal>".to_owned());
302 "you must specify a concrete type for \
303 this numeric value, like `{}`",
306 format!("{}_{}", snippet, concrete_type),
307 Applicability::MaybeIncorrect,
310 ExprKind::Path(ref qpath) => {
312 if let &QPath::Resolved(_, ref path) = &qpath {
313 if let hir::def::Res::Local(hir_id) = path.res {
314 let span = tcx.hir().span(hir_id);
315 let snippet = tcx.sess.source_map().span_to_snippet(span);
316 let filename = tcx.sess.source_map().span_to_filename(span);
318 let parent_node = self
321 .get(self.tcx.hir().get_parent_node(hir_id));
323 "you must specify a type for this binding, like `{}`",
327 match (filename, parent_node, snippet) {
330 Node::Local(hir::Local {
331 source: hir::LocalSource::Normal,
338 // account for `let x: _ = 42;`
345 format!("{}: {}", snippet, concrete_type),
346 Applicability::MaybeIncorrect,
350 err.span_label(span, msg);
361 span = item_name.span;
362 let mut err = struct_span_err!(
366 "no {} named `{}` found for {} `{}` in the current scope",
369 actual.prefix_string(),
373 tcx.sess.confused_type_with_std_module.borrow().get(&span)
375 if let Ok(snippet) = tcx.sess.source_map().span_to_snippet(*span) {
378 "you are looking for the module in `std`, \
379 not the primitive type",
380 format!("std::{}", snippet),
381 Applicability::MachineApplicable,
385 if let ty::RawPtr(_) = &actual.kind {
387 "try using `<*const T>::as_ref()` to get a reference to the \
388 type behind the pointer: https://doc.rust-lang.org/std/\
389 primitive.pointer.html#method.as_ref",
392 "using `<*const T>::as_ref()` on a pointer \
393 which is unaligned or points to invalid \
394 or uninitialized memory is undefined behavior",
400 tcx.sess.diagnostic().struct_dummy()
403 if let Some(def) = actual.ty_adt_def() {
404 if let Some(full_sp) = tcx.hir().span_if_local(def.did) {
405 let def_sp = tcx.sess.source_map().guess_head_span(full_sp);
409 "{} `{}` not found {}",
412 if def.is_enum() && !is_method { "here" } else { "for this" }
418 // If the method name is the name of a field with a function or closure type,
419 // give a helping note that it has to be called as `(x.f)(...)`.
420 if let SelfSource::MethodCall(expr) = source {
422 self.autoderef(span, rcvr_ty).find_map(|(ty, _)| match ty.kind {
423 ty::Adt(def, substs) if !def.is_enum() => {
424 let variant = &def.non_enum_variant();
425 self.tcx.find_field_index(item_name, variant).map(|index| {
426 let field = &variant.fields[index];
427 let field_ty = field.ty(tcx, substs);
434 if let Some((field, field_ty)) = field_receiver {
435 let scope = self.tcx.parent_module(self.body_id).to_def_id();
436 let is_accessible = field.vis.is_accessible_from(scope, self.tcx);
439 if self.is_fn_ty(&field_ty, span) {
440 let expr_span = expr.span.to(item_name.span);
441 err.multipart_suggestion(
443 "to call the function stored in `{}`, \
444 surround the field access with parentheses",
448 (expr_span.shrink_to_lo(), '('.to_string()),
449 (expr_span.shrink_to_hi(), ')'.to_string()),
451 Applicability::MachineApplicable,
457 .expect_expr(self.tcx.hir().get_parent_node(expr.hir_id));
459 if let Some(span) = call_expr.span.trim_start(item_name.span) {
462 "remove the arguments",
464 Applicability::MaybeIncorrect,
470 let field_kind = if is_accessible { "field" } else { "private field" };
471 err.span_label(item_name.span, format!("{}, not a method", field_kind));
472 } else if lev_candidate.is_none() && static_sources.is_empty() {
473 err.span_label(span, format!("{} not found in `{}`", item_kind, ty_str));
474 self.tcx.sess.trait_methods_not_found.borrow_mut().insert(orig_span);
477 err.span_label(span, format!("{} not found in `{}`", item_kind, ty_str));
478 self.tcx.sess.trait_methods_not_found.borrow_mut().insert(orig_span);
481 if self.is_fn_ty(&rcvr_ty, span) {
482 macro_rules! report_function {
483 ($span:expr, $name:expr) => {
485 "`{}` is a function, perhaps you wish to call it",
491 if let SelfSource::MethodCall(expr) = source {
492 if let Ok(expr_string) = tcx.sess.source_map().span_to_snippet(expr.span) {
493 report_function!(expr.span, expr_string);
494 } else if let ExprKind::Path(QPath::Resolved(_, ref path)) = expr.kind {
495 if let Some(segment) = path.segments.last() {
496 report_function!(expr.span, segment.ident);
502 if !static_sources.is_empty() {
504 "found the following associated functions; to be used as methods, \
505 functions must have a `self` parameter",
507 err.span_label(span, "this is an associated function, not a method");
509 if static_sources.len() == 1 {
510 let ty_str = if let Some(CandidateSource::ImplSource(impl_did)) =
511 static_sources.get(0)
513 // When the "method" is resolved through dereferencing, we really want the
514 // original type that has the associated function for accurate suggestions.
516 let ty = self.impl_self_ty(span, *impl_did).ty;
517 match (&ty.peel_refs().kind, &actual.peel_refs().kind) {
518 (ty::Adt(def, _), ty::Adt(def_actual, _)) if def == def_actual => {
519 // Use `actual` as it will have more `substs` filled in.
520 self.ty_to_value_string(actual.peel_refs())
522 _ => self.ty_to_value_string(ty.peel_refs()),
525 self.ty_to_value_string(actual.peel_refs())
527 if let SelfSource::MethodCall(expr) = source {
530 "use associated function syntax instead",
531 format!("{}::{}", ty_str, item_name),
532 Applicability::MachineApplicable,
535 err.help(&format!("try with `{}::{}`", ty_str, item_name,));
538 report_candidates(span, &mut err, static_sources, sugg_span);
539 } else if static_sources.len() > 1 {
540 report_candidates(span, &mut err, static_sources, sugg_span);
543 let mut restrict_type_params = false;
544 if !unsatisfied_predicates.is_empty() {
545 let def_span = |def_id| {
546 self.tcx.sess.source_map().guess_head_span(self.tcx.def_span(def_id))
548 let mut type_params = FxHashMap::default();
549 let mut bound_spans = vec![];
550 let mut collect_type_param_suggestions =
551 |self_ty: Ty<'_>, parent_pred: &ty::Predicate<'_>, obligation: &str| {
552 if let (ty::Param(_), ty::Predicate::Trait(p, _)) =
553 (&self_ty.kind, parent_pred)
555 if let ty::Adt(def, _) = p.skip_binder().trait_ref.self_ty().kind {
559 .as_local_hir_id(def.did)
560 .map(|id| self.tcx.hir().get(id));
561 if let Some(hir::Node::Item(hir::Item { kind, .. })) = node {
562 if let Some(g) = kind.generics() {
563 let key = match &g.where_clause.predicates[..] {
564 [.., pred] => (pred.span().shrink_to_hi(), false),
567 .span_for_predicates_or_empty_place(),
573 .or_insert_with(FxHashSet::default)
574 .insert(obligation.to_owned());
580 let mut bound_span_label = |self_ty: Ty<'_>, obligation: &str, quiet: &str| {
582 "doesn't satisfy `{}`",
583 if obligation.len() > 50 { quiet } else { obligation }
585 match &self_ty.kind {
586 // Point at the type that couldn't satisfy the bound.
587 ty::Adt(def, _) => bound_spans.push((def_span(def.did), msg)),
588 // Point at the trait object that couldn't satisfy the bound.
589 ty::Dynamic(preds, _) => {
590 for pred in *preds.skip_binder() {
592 ty::ExistentialPredicate::Trait(tr) => {
593 bound_spans.push((def_span(tr.def_id), msg.clone()))
595 ty::ExistentialPredicate::Projection(_)
596 | ty::ExistentialPredicate::AutoTrait(_) => {}
600 // Point at the closure that couldn't satisfy the bound.
601 ty::Closure(def_id, _) => bound_spans
602 .push((def_span(*def_id), format!("doesn't satisfy `{}`", quiet))),
606 let mut format_pred = |pred| {
608 ty::Predicate::Projection(pred) => {
609 // `<Foo as Iterator>::Item = String`.
611 pred.skip_binder().projection_ty.trait_ref(self.tcx);
614 .associated_item(pred.skip_binder().projection_ty.item_def_id);
615 let ty = pred.skip_binder().ty;
616 let obligation = format!("{}::{} = {}", trait_ref, assoc.ident, ty);
618 "<_ as {}>::{} = {}",
619 trait_ref.print_only_trait_path(),
623 bound_span_label(trait_ref.self_ty(), &obligation, &quiet);
624 Some((obligation, trait_ref.self_ty()))
626 ty::Predicate::Trait(poly_trait_ref, _) => {
627 let p = poly_trait_ref.skip_binder().trait_ref;
628 let self_ty = p.self_ty();
629 let path = p.print_only_trait_path();
630 let obligation = format!("{}: {}", self_ty, path);
631 let quiet = format!("_: {}", path);
632 bound_span_label(self_ty, &obligation, &quiet);
633 Some((obligation, self_ty))
638 let mut bound_list = unsatisfied_predicates
640 .filter_map(|(pred, parent_pred)| {
641 format_pred(*pred).map(|(p, self_ty)| match parent_pred {
642 None => format!("`{}`", p),
643 Some(parent_pred) => match format_pred(*parent_pred) {
644 None => format!("`{}`", p),
645 Some((parent_p, _)) => {
646 collect_type_param_suggestions(self_ty, parent_pred, &p);
647 format!("`{}`\nwhich is required by `{}`", p, parent_p)
653 .collect::<Vec<(usize, String)>>();
654 for ((span, empty_where), obligations) in type_params.into_iter() {
655 restrict_type_params = true;
656 err.span_suggestion_verbose(
659 "consider restricting the type parameter{s} to satisfy the \
661 s = pluralize!(obligations.len())
665 if empty_where { " where" } else { "," },
666 obligations.into_iter().collect::<Vec<_>>().join(", ")
668 Applicability::MaybeIncorrect,
672 bound_list.sort_by(|(_, a), (_, b)| a.cmp(&b)); // Sort alphabetically.
673 bound_list.dedup_by(|(_, a), (_, b)| a == b); // #35677
674 bound_list.sort_by_key(|(pos, _)| *pos); // Keep the original predicate order.
677 for (span, msg) in bound_spans.into_iter() {
678 err.span_label(span, &msg);
680 if !bound_list.is_empty() {
681 let bound_list = bound_list
683 .map(|(_, path)| path)
687 "the method `{}` exists but the following trait bounds were not \
689 item_name, bound_list
694 if actual.is_numeric() && actual.is_fresh() || restrict_type_params {
696 self.suggest_traits_to_import(
703 &unsatisfied_predicates,
707 if actual.is_enum() {
708 let adt_def = actual.ty_adt_def().expect("enum is not an ADT");
709 if let Some(suggestion) = lev_distance::find_best_match_for_name(
710 adt_def.variants.iter().map(|s| &s.ident.name),
716 "there is a variant with a similar name",
717 suggestion.to_string(),
718 Applicability::MaybeIncorrect,
723 let mut fallback_span = true;
724 let msg = "remove this method call";
725 if item_name.as_str() == "as_str" && actual.peel_refs().is_str() {
726 if let SelfSource::MethodCall(expr) = source {
728 self.tcx.hir().expect_expr(self.tcx.hir().get_parent_node(expr.hir_id));
729 if let Some(span) = call_expr.span.trim_start(expr.span) {
734 Applicability::MachineApplicable,
736 fallback_span = false;
740 err.span_label(span, msg);
742 } else if let Some(lev_candidate) = lev_candidate {
743 let def_kind = lev_candidate.def_kind();
747 "there is {} {} with a similar name",
749 def_kind.descr(lev_candidate.def_id),
751 lev_candidate.ident.to_string(),
752 Applicability::MaybeIncorrect,
759 MethodError::Ambiguity(sources) => {
760 let mut err = struct_span_err!(
764 "multiple applicable items in scope"
766 err.span_label(item_name.span, format!("multiple `{}` found", item_name));
768 report_candidates(span, &mut err, sources, sugg_span);
772 MethodError::PrivateMatch(kind, def_id, out_of_scope_traits) => {
773 let kind = kind.descr(def_id);
774 let mut err = struct_span_err!(
778 "{} `{}` is private",
782 err.span_label(item_name.span, &format!("private {}", kind));
783 self.suggest_valid_traits(&mut err, out_of_scope_traits);
787 MethodError::IllegalSizedBound(candidates, needs_mut, bound_span) => {
788 let msg = format!("the `{}` method cannot be invoked on a trait object", item_name);
789 let mut err = self.sess().struct_span_err(span, &msg);
790 err.span_label(bound_span, "this has a `Sized` requirement");
791 if !candidates.is_empty() {
793 "{an}other candidate{s} {were} found in the following trait{s}, perhaps \
794 add a `use` for {one_of_them}:",
795 an = if candidates.len() == 1 { "an" } else { "" },
796 s = pluralize!(candidates.len()),
797 were = if candidates.len() == 1 { "was" } else { "were" },
798 one_of_them = if candidates.len() == 1 { "it" } else { "one_of_them" },
800 self.suggest_use_candidates(&mut err, help, candidates);
802 if let ty::Ref(region, t_type, mutability) = rcvr_ty.kind {
804 let trait_type = self.tcx.mk_ref(
806 ty::TypeAndMut { ty: t_type, mutbl: mutability.invert() },
808 err.note(&format!("you need `{}` instead of `{}`", trait_type, rcvr_ty));
814 MethodError::BadReturnType => bug!("no return type expectations but got BadReturnType"),
819 /// Print out the type for use in value namespace.
820 fn ty_to_value_string(&self, ty: Ty<'tcx>) -> String {
822 ty::Adt(def, substs) => format!("{}", ty::Instance::new(def.did, substs)),
823 _ => self.ty_to_string(ty),
827 fn suggest_use_candidates(
829 err: &mut DiagnosticBuilder<'_>,
831 candidates: Vec<DefId>,
833 let module_did = self.tcx.parent_module(self.body_id);
834 let module_id = self.tcx.hir().as_local_hir_id(module_did.to_def_id()).unwrap();
835 let krate = self.tcx.hir().krate();
836 let (span, found_use) = UsePlacementFinder::check(self.tcx, krate, module_id);
837 if let Some(span) = span {
838 let path_strings = candidates.iter().map(|did| {
839 // Produce an additional newline to separate the new use statement
840 // from the directly following item.
841 let additional_newline = if found_use { "" } else { "\n" };
844 with_crate_prefix(|| self.tcx.def_path_str(*did)),
849 err.span_suggestions(span, &msg, path_strings, Applicability::MaybeIncorrect);
851 let limit = if candidates.len() == 5 { 5 } else { 4 };
852 for (i, trait_did) in candidates.iter().take(limit).enumerate() {
853 if candidates.len() > 1 {
854 msg.push_str(&format!(
855 "\ncandidate #{}: `use {};`",
857 with_crate_prefix(|| self.tcx.def_path_str(*trait_did))
860 msg.push_str(&format!(
862 with_crate_prefix(|| self.tcx.def_path_str(*trait_did))
866 if candidates.len() > limit {
867 msg.push_str(&format!("\nand {} others", candidates.len() - limit));
873 fn suggest_valid_traits(
875 err: &mut DiagnosticBuilder<'_>,
876 valid_out_of_scope_traits: Vec<DefId>,
878 if !valid_out_of_scope_traits.is_empty() {
879 let mut candidates = valid_out_of_scope_traits;
882 err.help("items from traits can only be used if the trait is in scope");
884 "the following {traits_are} implemented but not in scope; \
885 perhaps add a `use` for {one_of_them}:",
886 traits_are = if candidates.len() == 1 { "trait is" } else { "traits are" },
887 one_of_them = if candidates.len() == 1 { "it" } else { "one of them" },
890 self.suggest_use_candidates(err, msg, candidates);
897 fn suggest_traits_to_import<'b>(
899 err: &mut DiagnosticBuilder<'_>,
902 item_name: ast::Ident,
903 source: SelfSource<'b>,
904 valid_out_of_scope_traits: Vec<DefId>,
905 unsatisfied_predicates: &[(ty::Predicate<'tcx>, Option<ty::Predicate<'tcx>>)],
907 if self.suggest_valid_traits(err, valid_out_of_scope_traits) {
911 let type_is_local = self.type_derefs_to_local(span, rcvr_ty, source);
913 let mut arbitrary_rcvr = vec![];
914 // There are no traits implemented, so lets suggest some traits to
915 // implement, by finding ones that have the item name, and are
916 // legal to implement.
917 let mut candidates = all_traits(self.tcx)
920 // We approximate the coherence rules to only suggest
921 // traits that are legal to implement by requiring that
922 // either the type or trait is local. Multi-dispatch means
923 // this isn't perfect (that is, there are cases when
924 // implementing a trait would be legal but is rejected
926 !unsatisfied_predicates.iter().any(|(p, _)| match p {
927 // Hide traits if they are present in predicates as they can be fixed without
928 // having to implement them.
929 ty::Predicate::Trait(t, _) => t.def_id() != info.def_id,
930 ty::Predicate::Projection(p) => p.item_def_id() != info.def_id,
932 }) && (type_is_local || info.def_id.is_local())
934 .associated_item(info.def_id, item_name, Namespace::ValueNS)
936 if let ty::AssocKind::Method = item.kind {
937 let id = self.tcx.hir().as_local_hir_id(item.def_id);
938 if let Some(hir::Node::TraitItem(hir::TraitItem {
939 kind: hir::TraitItemKind::Fn(fn_sig, method),
941 })) = id.map(|id| self.tcx.hir().get(id))
943 let self_first_arg = match method {
944 hir::TraitFn::Required([ident, ..]) => {
945 ident.name == kw::SelfLower
947 hir::TraitFn::Provided(body_id) => {
948 match &self.tcx.hir().body(*body_id).params[..] {
953 hir::PatKind::Binding(
962 }, ..] => ident.name == kw::SelfLower,
969 if !fn_sig.decl.implicit_self.has_implicit_self()
972 if let Some(ty) = fn_sig.decl.inputs.get(0) {
973 arbitrary_rcvr.push(ty.span);
979 // We only want to suggest public or local traits (#45781).
980 item.vis == ty::Visibility::Public || info.def_id.is_local()
984 .collect::<Vec<_>>();
985 for span in &arbitrary_rcvr {
988 "the method might not be found because of this arbitrary self type",
992 if !candidates.is_empty() {
993 // Sort from most relevant to least relevant.
994 candidates.sort_by(|a, b| a.cmp(b).reverse());
997 let param_type = match rcvr_ty.kind {
998 ty::Param(param) => Some(param),
999 ty::Ref(_, ty, _) => match ty.kind {
1000 ty::Param(param) => Some(param),
1005 err.help(if param_type.is_some() {
1006 "items from traits can only be used if the type parameter is bounded by the trait"
1008 "items from traits can only be used if the trait is implemented and in scope"
1010 let message = |action| {
1012 "the following {traits_define} an item `{name}`, perhaps you need to {action} \
1015 if candidates.len() == 1 { "trait defines" } else { "traits define" },
1017 one_of_them = if candidates.len() == 1 { "it" } else { "one of them" },
1021 // Obtain the span for `param` and use it for a structured suggestion.
1022 let mut suggested = false;
1023 if let (Some(ref param), Some(ref table)) = (param_type, self.in_progress_tables) {
1024 let table_owner = table.borrow().hir_owner;
1025 if let Some(table_owner) = table_owner {
1026 let generics = self.tcx.generics_of(table_owner.to_def_id());
1027 let type_param = generics.type_param(param, self.tcx);
1028 let hir = &self.tcx.hir();
1029 if let Some(id) = hir.as_local_hir_id(type_param.def_id) {
1030 // Get the `hir::Param` to verify whether it already has any bounds.
1031 // We do this to avoid suggesting code that ends up as `T: FooBar`,
1032 // instead we suggest `T: Foo + Bar` in that case.
1034 Node::GenericParam(ref param) => {
1035 let mut impl_trait = false;
1036 let has_bounds = if let hir::GenericParamKind::Type {
1041 // We've found `fn foo(x: impl Trait)` instead of
1042 // `fn foo<T>(x: T)`. We want to suggest the correct
1043 // `fn foo(x: impl Trait + TraitBound)` instead of
1044 // `fn foo<T: TraitBound>(x: T)`. (#63706)
1050 let sp = hir.span(id);
1051 let sp = if let Some(first_bound) = has_bounds {
1052 // `sp` only covers `T`, change it so that it covers
1053 // `T:` when appropriate
1054 sp.until(first_bound.span())
1058 let trait_def_ids: FxHashSet<DefId> = param
1061 .filter_map(|bound| Some(bound.trait_ref()?.trait_def_id()?))
1063 if !candidates.iter().any(|t| trait_def_ids.contains(&t.def_id)) {
1064 err.span_suggestions(
1067 "restrict type parameter `{}` with",
1070 candidates.iter().map(|t| {
1074 if impl_trait { " +" } else { ":" },
1075 self.tcx.def_path_str(t.def_id),
1076 if has_bounds.is_some() { " + " } else { "" },
1079 Applicability::MaybeIncorrect,
1084 Node::Item(hir::Item {
1085 kind: hir::ItemKind::Trait(.., bounds, _),
1089 let (sp, sep, article) = if bounds.is_empty() {
1090 (ident.span.shrink_to_hi(), ":", "a")
1092 (bounds.last().unwrap().span().shrink_to_hi(), " +", "another")
1094 err.span_suggestions(
1096 &message(format!("add {} supertrait for", article)),
1097 candidates.iter().map(|t| {
1098 format!("{} {}", sep, self.tcx.def_path_str(t.def_id),)
1100 Applicability::MaybeIncorrect,
1111 let action = if let Some(param) = param_type {
1112 format!("restrict type parameter `{}` with", param)
1114 // FIXME: it might only need to be imported into scope, not implemented.
1115 "implement".to_string()
1117 let mut use_note = true;
1118 if let [trait_info] = &candidates[..] {
1119 if let Some(span) = self.tcx.hir().span_if_local(trait_info.def_id) {
1121 self.tcx.sess.source_map().guess_head_span(span),
1123 "`{}` defines an item `{}`, perhaps you need to {} it",
1124 self.tcx.def_path_str(trait_info.def_id),
1133 let mut msg = message(action);
1134 for (i, trait_info) in candidates.iter().enumerate() {
1135 msg.push_str(&format!(
1136 "\ncandidate #{}: `{}`",
1138 self.tcx.def_path_str(trait_info.def_id),
1147 /// Checks whether there is a local type somewhere in the chain of
1148 /// autoderefs of `rcvr_ty`.
1149 fn type_derefs_to_local(&self, span: Span, rcvr_ty: Ty<'tcx>, source: SelfSource<'_>) -> bool {
1150 fn is_local(ty: Ty<'_>) -> bool {
1152 ty::Adt(def, _) => def.did.is_local(),
1153 ty::Foreign(did) => did.is_local(),
1155 ty::Dynamic(ref tr, ..) => {
1156 tr.principal().map(|d| d.def_id().is_local()).unwrap_or(false)
1159 ty::Param(_) => true,
1161 // Everything else (primitive types, etc.) is effectively
1162 // non-local (there are "edge" cases, e.g., `(LocalType,)`, but
1163 // the noise from these sort of types is usually just really
1164 // annoying, rather than any sort of help).
1169 // This occurs for UFCS desugaring of `T::method`, where there is no
1170 // receiver expression for the method call, and thus no autoderef.
1171 if let SelfSource::QPath(_) = source {
1172 return is_local(self.resolve_vars_with_obligations(rcvr_ty));
1175 self.autoderef(span, rcvr_ty).any(|(ty, _)| is_local(ty))
1179 #[derive(Copy, Clone)]
1180 pub enum SelfSource<'a> {
1181 QPath(&'a hir::Ty<'a>),
1182 MethodCall(&'a hir::Expr<'a> /* rcvr */),
1185 #[derive(Copy, Clone)]
1186 pub struct TraitInfo {
1190 impl PartialEq for TraitInfo {
1191 fn eq(&self, other: &TraitInfo) -> bool {
1192 self.cmp(other) == Ordering::Equal
1195 impl Eq for TraitInfo {}
1196 impl PartialOrd for TraitInfo {
1197 fn partial_cmp(&self, other: &TraitInfo) -> Option<Ordering> {
1198 Some(self.cmp(other))
1201 impl Ord for TraitInfo {
1202 fn cmp(&self, other: &TraitInfo) -> Ordering {
1203 // Local crates are more important than remote ones (local:
1204 // `cnum == 0`), and otherwise we throw in the defid for totality.
1206 let lhs = (other.def_id.krate, other.def_id);
1207 let rhs = (self.def_id.krate, self.def_id);
1212 /// Retrieves all traits in this crate and any dependent crates.
1213 pub fn all_traits(tcx: TyCtxt<'_>) -> Vec<TraitInfo> {
1214 tcx.all_traits(LOCAL_CRATE).iter().map(|&def_id| TraitInfo { def_id }).collect()
1217 /// Computes all traits in this crate and any dependent crates.
1218 fn compute_all_traits(tcx: TyCtxt<'_>) -> Vec<DefId> {
1219 use hir::itemlikevisit;
1221 let mut traits = vec![];
1225 struct Visitor<'a, 'tcx> {
1226 map: &'a hir_map::Map<'tcx>,
1227 traits: &'a mut Vec<DefId>,
1230 impl<'v, 'a, 'tcx> itemlikevisit::ItemLikeVisitor<'v> for Visitor<'a, 'tcx> {
1231 fn visit_item(&mut self, i: &'v hir::Item<'v>) {
1233 hir::ItemKind::Trait(..) | hir::ItemKind::TraitAlias(..) => {
1234 let def_id = self.map.local_def_id(i.hir_id);
1235 self.traits.push(def_id);
1241 fn visit_trait_item(&mut self, _trait_item: &hir::TraitItem<'_>) {}
1243 fn visit_impl_item(&mut self, _impl_item: &hir::ImplItem<'_>) {}
1246 tcx.hir().krate().visit_all_item_likes(&mut Visitor { map: &tcx.hir(), traits: &mut traits });
1250 let mut external_mods = FxHashSet::default();
1251 fn handle_external_res(
1253 traits: &mut Vec<DefId>,
1254 external_mods: &mut FxHashSet<DefId>,
1258 Res::Def(DefKind::Trait, def_id) | Res::Def(DefKind::TraitAlias, def_id) => {
1259 traits.push(def_id);
1261 Res::Def(DefKind::Mod, def_id) => {
1262 if !external_mods.insert(def_id) {
1265 for child in tcx.item_children(def_id).iter() {
1266 handle_external_res(tcx, traits, external_mods, child.res)
1272 for &cnum in tcx.crates().iter() {
1273 let def_id = DefId { krate: cnum, index: CRATE_DEF_INDEX };
1274 handle_external_res(tcx, &mut traits, &mut external_mods, Res::Def(DefKind::Mod, def_id));
1280 pub fn provide(providers: &mut ty::query::Providers<'_>) {
1281 providers.all_traits = |tcx, cnum| {
1282 assert_eq!(cnum, LOCAL_CRATE);
1283 &tcx.arena.alloc(compute_all_traits(tcx))[..]
1287 struct UsePlacementFinder<'tcx> {
1288 target_module: hir::HirId,
1294 impl UsePlacementFinder<'tcx> {
1297 krate: &'tcx hir::Crate<'tcx>,
1298 target_module: hir::HirId,
1299 ) -> (Option<Span>, bool) {
1300 let mut finder = UsePlacementFinder { target_module, span: None, found_use: false, tcx };
1301 intravisit::walk_crate(&mut finder, krate);
1302 (finder.span, finder.found_use)
1306 impl intravisit::Visitor<'tcx> for UsePlacementFinder<'tcx> {
1307 fn visit_mod(&mut self, module: &'tcx hir::Mod<'tcx>, _: Span, hir_id: hir::HirId) {
1308 if self.span.is_some() {
1311 if hir_id != self.target_module {
1312 intravisit::walk_mod(self, module, hir_id);
1315 // Find a `use` statement.
1316 for item_id in module.item_ids {
1317 let item = self.tcx.hir().expect_item(item_id.id);
1319 hir::ItemKind::Use(..) => {
1320 // Don't suggest placing a `use` before the prelude
1321 // import or other generated ones.
1322 if !item.span.from_expansion() {
1323 self.span = Some(item.span.shrink_to_lo());
1324 self.found_use = true;
1328 // Don't place `use` before `extern crate`...
1329 hir::ItemKind::ExternCrate(_) => {}
1330 // ...but do place them before the first other item.
1332 if self.span.map_or(true, |span| item.span < span) {
1333 if !item.span.from_expansion() {
1334 // Don't insert between attributes and an item.
1335 if item.attrs.is_empty() {
1336 self.span = Some(item.span.shrink_to_lo());
1338 // Find the first attribute on the item.
1339 for attr in item.attrs {
1340 if self.span.map_or(true, |span| attr.span < span) {
1341 self.span = Some(attr.span.shrink_to_lo());
1352 type Map = intravisit::ErasedMap<'tcx>;
1354 fn nested_visit_map(&mut self) -> intravisit::NestedVisitorMap<Self::Map> {
1355 intravisit::NestedVisitorMap::None
1359 fn print_disambiguation_help(
1360 item_name: ast::Ident,
1361 args: Option<&'tcx [hir::Expr<'tcx>]>,
1362 err: &mut DiagnosticBuilder<'_>,
1365 kind: ty::AssocKind,
1367 candidate: Option<usize>,
1368 source_map: &source_map::SourceMap,
1370 let mut applicability = Applicability::MachineApplicable;
1371 let sugg_args = if let (ty::AssocKind::Method, Some(args)) = (kind, args) {
1374 if rcvr_ty.is_region_ptr() {
1375 if rcvr_ty.is_mutable_ptr() { "&mut " } else { "&" }
1380 .map(|arg| source_map.span_to_snippet(arg.span).unwrap_or_else(|_| {
1381 applicability = Applicability::HasPlaceholders;
1384 .collect::<Vec<_>>()
1390 let sugg = format!("{}::{}{}", trait_name, item_name, sugg_args);
1391 err.span_suggestion(
1394 "disambiguate the {} for {}",
1395 kind.suggestion_descr(),
1396 if let Some(candidate) = candidate {
1397 format!("candidate #{}", candidate)
1399 "the candidate".to_string()