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::ty::print::with_crate_prefix;
8 use rustc::ty::{self, ToPolyTraitRef, ToPredicate, Ty, TyCtxt, TypeFoldable, WithConstness};
10 use rustc_ast::util::lev_distance;
11 use rustc_data_structures::fx::{FxHashMap, FxHashSet};
12 use rustc_errors::{pluralize, struct_span_err, Applicability, DiagnosticBuilder};
14 use rustc_hir::def::{DefKind, Namespace, Res};
15 use rustc_hir::def_id::{DefId, CRATE_DEF_INDEX, LOCAL_CRATE};
16 use rustc_hir::intravisit;
17 use rustc_hir::{ExprKind, Node, QPath};
18 use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
19 use rustc_span::symbol::kw;
20 use rustc_span::{source_map, FileName, Span};
21 use rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt;
22 use rustc_trait_selection::traits::Obligation;
24 use std::cmp::Ordering;
26 use super::probe::Mode;
27 use super::{CandidateSource, MethodError, NoMatchData};
29 impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
30 fn is_fn_ty(&self, ty: Ty<'tcx>, span: Span) -> bool {
33 // Not all of these (e.g., unsafe fns) implement `FnOnce`,
34 // so we look for these beforehand.
35 ty::Closure(..) | ty::FnDef(..) | ty::FnPtr(_) => true,
36 // If it's not a simple function, look for things which implement `FnOnce`.
38 let fn_once = match tcx.lang_items().require(FnOnceTraitLangItem) {
39 Ok(fn_once) => fn_once,
40 Err(..) => return false,
43 self.autoderef(span, ty).any(|(ty, _)| {
45 let fn_once_substs = tcx.mk_substs_trait(
48 .next_ty_var(TypeVariableOrigin {
49 kind: TypeVariableOriginKind::MiscVariable,
54 let trait_ref = ty::TraitRef::new(fn_once, fn_once_substs);
55 let poly_trait_ref = trait_ref.to_poly_trait_ref();
56 let obligation = Obligation::misc(
60 poly_trait_ref.without_const().to_predicate(),
62 self.predicate_may_hold(&obligation)
69 pub fn report_method_error<'b>(
73 item_name: ast::Ident,
74 source: SelfSource<'b>,
75 error: MethodError<'tcx>,
76 args: Option<&'tcx [hir::Expr<'tcx>]>,
77 ) -> Option<DiagnosticBuilder<'_>> {
80 // Avoid suggestions when we don't know what's going on.
81 if rcvr_ty.references_error() {
85 let report_candidates = |span: Span,
86 err: &mut DiagnosticBuilder<'_>,
87 mut sources: Vec<CandidateSource>,
91 // Dynamic limit to avoid hiding just one candidate, which is silly.
92 let limit = if sources.len() == 5 { 5 } else { 4 };
94 for (idx, source) in sources.iter().take(limit).enumerate() {
96 CandidateSource::ImplSource(impl_did) => {
97 // Provide the best span we can. Use the item, if local to crate, else
98 // the impl, if local to crate (item may be defaulted), else nothing.
100 .associated_item(impl_did, item_name, Namespace::ValueNS)
102 let impl_trait_ref = self.tcx.impl_trait_ref(impl_did)?;
103 self.associated_item(
104 impl_trait_ref.def_id,
115 .span_if_local(item.def_id)
116 .or_else(|| self.tcx.hir().span_if_local(impl_did));
118 let impl_ty = self.impl_self_ty(span, impl_did).ty;
120 let insertion = match self.tcx.impl_trait_ref(impl_did) {
121 None => String::new(),
122 Some(trait_ref) => format!(
123 " of the trait `{}`",
124 self.tcx.def_path_str(trait_ref.def_id)
128 let (note_str, idx) = if sources.len() > 1 {
131 "candidate #{} is defined in an impl{} for the type `{}`",
141 "the candidate is defined in an impl{} for the type `{}`",
147 if let Some(note_span) = note_span {
148 // We have a span pointing to the method. Show note with snippet.
150 self.tcx.sess.source_map().def_span(note_span),
156 if let Some(trait_ref) = self.tcx.impl_trait_ref(impl_did) {
157 let path = self.tcx.def_path_str(trait_ref.def_id);
159 let ty = match item.kind {
161 | ty::AssocKind::Type
162 | ty::AssocKind::OpaqueTy => rcvr_ty,
163 ty::AssocKind::Method => self
169 .filter(|ty| ty.is_region_ptr() && !rcvr_ty.is_region_ptr())
173 print_disambiguation_help(
182 self.tcx.sess.source_map(),
186 CandidateSource::TraitSource(trait_did) => {
188 match self.associated_item(trait_did, item_name, Namespace::ValueNS) {
193 self.tcx.sess.source_map().def_span(self.tcx.def_span(item.def_id));
194 let idx = if sources.len() > 1 {
196 "candidate #{} is defined in the trait `{}`",
198 self.tcx.def_path_str(trait_did)
200 err.span_note(item_span, msg);
204 "the candidate is defined in the trait `{}`",
205 self.tcx.def_path_str(trait_did)
207 err.span_note(item_span, msg);
210 let path = self.tcx.def_path_str(trait_did);
211 print_disambiguation_help(
220 self.tcx.sess.source_map(),
225 if sources.len() > limit {
226 err.note(&format!("and {} others", sources.len() - limit));
230 let sugg_span = if let SelfSource::MethodCall(expr) = source {
231 // Given `foo.bar(baz)`, `expr` is `bar`, but we want to point to the whole thing.
232 self.tcx.hir().expect_expr(self.tcx.hir().get_parent_node(expr.hir_id)).span
238 MethodError::NoMatch(NoMatchData {
239 static_candidates: static_sources,
240 unsatisfied_predicates,
247 let actual = self.resolve_vars_if_possible(&rcvr_ty);
248 let ty_str = self.ty_to_string(actual);
249 let is_method = mode == Mode::MethodCall;
250 let item_kind = if is_method {
252 } else if actual.is_enum() {
253 "variant or associated item"
255 match (item_name.as_str().chars().next(), actual.is_fresh_ty()) {
256 (Some(name), false) if name.is_lowercase() => "function or associated item",
257 (Some(_), false) => "associated item",
258 (Some(_), true) | (None, false) => "variant or associated item",
259 (None, true) => "variant",
262 let mut err = if !actual.references_error() {
263 // Suggest clamping down the type if the method that is being attempted to
264 // be used exists at all, and the type is an ambiguous numeric type
265 // ({integer}/{float}).
266 let mut candidates = all_traits(self.tcx).into_iter().filter_map(|info| {
267 self.associated_item(info.def_id, item_name, Namespace::ValueNS)
269 if let (true, false, SelfSource::MethodCall(expr), Some(_)) = (
271 actual.has_concrete_skeleton(),
275 let mut err = struct_span_err!(
279 "can't call {} `{}` on ambiguous numeric type `{}`",
284 let concrete_type = if actual.is_integral() { "i32" } else { "f32" };
286 ExprKind::Lit(ref lit) => {
291 .span_to_snippet(lit.span)
292 .unwrap_or_else(|_| "<numeric literal>".to_owned());
297 "you must specify a concrete type for \
298 this numeric value, like `{}`",
301 format!("{}_{}", snippet, concrete_type),
302 Applicability::MaybeIncorrect,
305 ExprKind::Path(ref qpath) => {
307 if let &QPath::Resolved(_, ref path) = &qpath {
308 if let hir::def::Res::Local(hir_id) = path.res {
309 let span = tcx.hir().span(hir_id);
310 let snippet = tcx.sess.source_map().span_to_snippet(span);
311 let filename = tcx.sess.source_map().span_to_filename(span);
313 let parent_node = self
316 .get(self.tcx.hir().get_parent_node(hir_id));
318 "you must specify a type for this binding, like `{}`",
322 match (filename, parent_node, snippet) {
325 Node::Local(hir::Local {
326 source: hir::LocalSource::Normal,
333 // account for `let x: _ = 42;`
340 format!("{}: {}", snippet, concrete_type),
341 Applicability::MaybeIncorrect,
345 err.span_label(span, msg);
356 span = item_name.span;
357 let mut err = struct_span_err!(
361 "no {} named `{}` found for {} `{}` in the current scope",
364 actual.prefix_string(),
368 tcx.sess.confused_type_with_std_module.borrow().get(&span)
370 if let Ok(snippet) = tcx.sess.source_map().span_to_snippet(*span) {
373 "you are looking for the module in `std`, \
374 not the primitive type",
375 format!("std::{}", snippet),
376 Applicability::MachineApplicable,
380 if let ty::RawPtr(_) = &actual.kind {
382 "try using `<*const T>::as_ref()` to get a reference to the \
383 type behind the pointer: https://doc.rust-lang.org/std/\
384 primitive.pointer.html#method.as_ref",
387 "using `<*const T>::as_ref()` on a pointer \
388 which is unaligned or points to invalid \
389 or uninitialized memory is undefined behavior",
395 tcx.sess.diagnostic().struct_dummy()
398 if let Some(def) = actual.ty_adt_def() {
399 if let Some(full_sp) = tcx.hir().span_if_local(def.did) {
400 let def_sp = tcx.sess.source_map().def_span(full_sp);
404 "{} `{}` not found {}",
407 if def.is_enum() && !is_method { "here" } else { "for this" }
413 // If the method name is the name of a field with a function or closure type,
414 // give a helping note that it has to be called as `(x.f)(...)`.
415 if let SelfSource::MethodCall(expr) = source {
417 self.autoderef(span, rcvr_ty).find_map(|(ty, _)| match ty.kind {
418 ty::Adt(def, substs) if !def.is_enum() => {
419 let variant = &def.non_enum_variant();
420 self.tcx.find_field_index(item_name, variant).map(|index| {
421 let field = &variant.fields[index];
422 let field_ty = field.ty(tcx, substs);
429 if let Some((field, field_ty)) = field_receiver {
430 let scope = self.tcx.parent_module(self.body_id).to_def_id();
431 let is_accessible = field.vis.is_accessible_from(scope, self.tcx);
434 if self.is_fn_ty(&field_ty, span) {
435 let expr_span = expr.span.to(item_name.span);
436 err.multipart_suggestion(
438 "to call the function stored in `{}`, \
439 surround the field access with parentheses",
443 (expr_span.shrink_to_lo(), '('.to_string()),
444 (expr_span.shrink_to_hi(), ')'.to_string()),
446 Applicability::MachineApplicable,
452 .expect_expr(self.tcx.hir().get_parent_node(expr.hir_id));
454 if let Some(span) = call_expr.span.trim_start(item_name.span) {
457 "remove the arguments",
459 Applicability::MaybeIncorrect,
465 let field_kind = if is_accessible { "field" } else { "private field" };
466 err.span_label(item_name.span, format!("{}, not a method", field_kind));
467 } else if lev_candidate.is_none() && static_sources.is_empty() {
468 err.span_label(span, format!("{} not found in `{}`", item_kind, ty_str));
469 self.tcx.sess.trait_methods_not_found.borrow_mut().insert(orig_span);
472 err.span_label(span, format!("{} not found in `{}`", item_kind, ty_str));
473 self.tcx.sess.trait_methods_not_found.borrow_mut().insert(orig_span);
476 if self.is_fn_ty(&rcvr_ty, span) {
477 macro_rules! report_function {
478 ($span:expr, $name:expr) => {
480 "`{}` is a function, perhaps you wish to call it",
486 if let SelfSource::MethodCall(expr) = source {
487 if let Ok(expr_string) = tcx.sess.source_map().span_to_snippet(expr.span) {
488 report_function!(expr.span, expr_string);
489 } else if let ExprKind::Path(QPath::Resolved(_, ref path)) = expr.kind {
490 if let Some(segment) = path.segments.last() {
491 report_function!(expr.span, segment.ident);
497 if !static_sources.is_empty() {
499 "found the following associated functions; to be used as methods, \
500 functions must have a `self` parameter",
502 err.span_label(span, "this is an associated function, not a method");
504 if static_sources.len() == 1 {
505 let ty_str = if let Some(CandidateSource::ImplSource(impl_did)) =
506 static_sources.get(0)
508 // When the "method" is resolved through dereferencing, we really want the
509 // original type that has the associated function for accurate suggestions.
511 let ty = self.impl_self_ty(span, *impl_did).ty;
512 match (&ty.peel_refs().kind, &actual.peel_refs().kind) {
513 (ty::Adt(def, _), ty::Adt(def_actual, _)) if def == def_actual => {
514 // Use `actual` as it will have more `substs` filled in.
515 self.ty_to_value_string(actual.peel_refs())
517 _ => self.ty_to_value_string(ty.peel_refs()),
520 self.ty_to_value_string(actual.peel_refs())
522 if let SelfSource::MethodCall(expr) = source {
525 "use associated function syntax instead",
526 format!("{}::{}", ty_str, item_name),
527 Applicability::MachineApplicable,
530 err.help(&format!("try with `{}::{}`", ty_str, item_name,));
533 report_candidates(span, &mut err, static_sources, sugg_span);
534 } else if static_sources.len() > 1 {
535 report_candidates(span, &mut err, static_sources, sugg_span);
538 let mut restrict_type_params = false;
539 if !unsatisfied_predicates.is_empty() {
541 |def_id| self.tcx.sess.source_map().def_span(self.tcx.def_span(def_id));
542 let mut type_params = FxHashMap::default();
543 let mut bound_spans = vec![];
544 let mut collect_type_param_suggestions =
545 |self_ty: Ty<'_>, parent_pred: &ty::Predicate<'_>, obligation: &str| {
546 if let (ty::Param(_), ty::Predicate::Trait(p, _)) =
547 (&self_ty.kind, parent_pred)
549 if let ty::Adt(def, _) = p.skip_binder().trait_ref.self_ty().kind {
553 .as_local_hir_id(def.did)
554 .map(|id| self.tcx.hir().get(id));
556 Some(hir::Node::Item(hir::Item { kind, .. })) => {
557 if let Some(g) = kind.generics() {
558 let key = match &g.where_clause.predicates[..] {
560 (pred.span().shrink_to_hi(), false)
564 .span_for_predicates_or_empty_place(),
570 .or_insert_with(FxHashSet::default)
571 .insert(obligation.to_owned());
579 let mut bound_span_label = |self_ty: Ty<'_>, obligation: &str, quiet: &str| {
581 "doesn't satisfy `{}`",
582 if obligation.len() > 50 { quiet } else { obligation }
584 match &self_ty.kind {
585 // Point at the type that couldn't satisfy the bound.
586 ty::Adt(def, _) => bound_spans.push((def_span(def.did), msg)),
587 // Point at the trait object that couldn't satisfy the bound.
588 ty::Dynamic(preds, _) => {
589 for pred in *preds.skip_binder() {
591 ty::ExistentialPredicate::Trait(tr) => {
592 bound_spans.push((def_span(tr.def_id), msg.clone()))
594 ty::ExistentialPredicate::Projection(_)
595 | ty::ExistentialPredicate::AutoTrait(_) => {}
599 // Point at the closure that couldn't satisfy the bound.
600 ty::Closure(def_id, _) => bound_spans
601 .push((def_span(*def_id), format!("doesn't satisfy `{}`", quiet))),
605 let mut format_pred = |pred| {
607 ty::Predicate::Projection(pred) => {
608 // `<Foo as Iterator>::Item = String`.
610 pred.skip_binder().projection_ty.trait_ref(self.tcx);
613 .associated_item(pred.skip_binder().projection_ty.item_def_id);
614 let ty = pred.skip_binder().ty;
615 let obligation = format!("{}::{} = {}", trait_ref, assoc.ident, ty);
617 "<_ as {}>::{} = {}",
618 trait_ref.print_only_trait_path(),
622 bound_span_label(trait_ref.self_ty(), &obligation, &quiet);
623 Some((obligation, trait_ref.self_ty()))
625 ty::Predicate::Trait(poly_trait_ref, _) => {
626 let p = poly_trait_ref.skip_binder().trait_ref;
627 let self_ty = p.self_ty();
628 let path = p.print_only_trait_path();
629 let obligation = format!("{}: {}", self_ty, path);
630 let quiet = format!("_: {}", path);
631 bound_span_label(self_ty, &obligation, &quiet);
632 Some((obligation, self_ty))
637 let mut bound_list = unsatisfied_predicates
639 .filter_map(|(pred, parent_pred)| {
640 format_pred(*pred).map(|(p, self_ty)| match parent_pred {
641 None => format!("`{}`", p),
642 Some(parent_pred) => match format_pred(*parent_pred) {
643 None => format!("`{}`", p),
644 Some((parent_p, _)) => {
645 collect_type_param_suggestions(self_ty, parent_pred, &p);
646 format!("`{}`\nwhich is required by `{}`", p, parent_p)
652 .collect::<Vec<(usize, String)>>();
653 for ((span, empty_where), obligations) in type_params.into_iter() {
654 restrict_type_params = true;
655 err.span_suggestion_verbose(
658 "consider restricting the type parameter{s} to satisfy the \
660 s = pluralize!(obligations.len())
664 if empty_where { " where" } else { "," },
665 obligations.into_iter().collect::<Vec<_>>().join(", ")
667 Applicability::MaybeIncorrect,
671 bound_list.sort_by(|(_, a), (_, b)| a.cmp(&b)); // Sort alphabetically.
672 bound_list.dedup_by(|(_, a), (_, b)| a == b); // #35677
673 bound_list.sort_by_key(|(pos, _)| *pos); // Keep the original predicate order.
676 for (span, msg) in bound_spans.into_iter() {
677 err.span_label(span, &msg);
679 if !bound_list.is_empty() {
680 let bound_list = bound_list
682 .map(|(_, path)| path)
686 "the method `{}` exists but the following trait bounds were not \
688 item_name, bound_list
693 if actual.is_numeric() && actual.is_fresh() || restrict_type_params {
695 self.suggest_traits_to_import(
702 &unsatisfied_predicates,
706 if actual.is_enum() {
707 let adt_def = actual.ty_adt_def().expect("enum is not an ADT");
708 if let Some(suggestion) = lev_distance::find_best_match_for_name(
709 adt_def.variants.iter().map(|s| &s.ident.name),
715 "there is a variant with a similar name",
716 suggestion.to_string(),
717 Applicability::MaybeIncorrect,
722 let mut fallback_span = true;
723 let msg = "remove this method call";
724 if item_name.as_str() == "as_str" && actual.peel_refs().is_str() {
725 if let SelfSource::MethodCall(expr) = source {
727 self.tcx.hir().expect_expr(self.tcx.hir().get_parent_node(expr.hir_id));
728 if let Some(span) = call_expr.span.trim_start(expr.span) {
733 Applicability::MachineApplicable,
735 fallback_span = false;
739 err.span_label(span, msg);
741 } else if let Some(lev_candidate) = lev_candidate {
742 let def_kind = lev_candidate.def_kind();
746 "there is {} {} with a similar name",
748 def_kind.descr(lev_candidate.def_id),
750 lev_candidate.ident.to_string(),
751 Applicability::MaybeIncorrect,
758 MethodError::Ambiguity(sources) => {
759 let mut err = struct_span_err!(
763 "multiple applicable items in scope"
765 err.span_label(span, format!("multiple `{}` found", item_name));
767 report_candidates(span, &mut err, sources, sugg_span);
771 MethodError::PrivateMatch(kind, def_id, out_of_scope_traits) => {
772 let mut err = struct_span_err!(
776 "{} `{}` is private",
780 self.suggest_valid_traits(&mut err, out_of_scope_traits);
784 MethodError::IllegalSizedBound(candidates, needs_mut, bound_span) => {
785 let msg = format!("the `{}` method cannot be invoked on a trait object", item_name);
786 let mut err = self.sess().struct_span_err(span, &msg);
787 err.span_label(bound_span, "this has a `Sized` requirement");
788 if !candidates.is_empty() {
790 "{an}other candidate{s} {were} found in the following trait{s}, perhaps \
791 add a `use` for {one_of_them}:",
792 an = if candidates.len() == 1 { "an" } else { "" },
793 s = pluralize!(candidates.len()),
794 were = if candidates.len() == 1 { "was" } else { "were" },
795 one_of_them = if candidates.len() == 1 { "it" } else { "one_of_them" },
797 self.suggest_use_candidates(&mut err, help, candidates);
799 if let ty::Ref(region, t_type, mutability) = rcvr_ty.kind {
801 let trait_type = self.tcx.mk_ref(
803 ty::TypeAndMut { ty: t_type, mutbl: mutability.invert() },
805 err.note(&format!("you need `{}` instead of `{}`", trait_type, rcvr_ty));
811 MethodError::BadReturnType => bug!("no return type expectations but got BadReturnType"),
816 /// Print out the type for use in value namespace.
817 fn ty_to_value_string(&self, ty: Ty<'tcx>) -> String {
819 ty::Adt(def, substs) => format!("{}", ty::Instance::new(def.did, substs)),
820 _ => self.ty_to_string(ty),
824 fn suggest_use_candidates(
826 err: &mut DiagnosticBuilder<'_>,
828 candidates: Vec<DefId>,
830 let module_did = self.tcx.parent_module(self.body_id);
831 let module_id = self.tcx.hir().as_local_hir_id(module_did.to_def_id()).unwrap();
832 let krate = self.tcx.hir().krate();
833 let (span, found_use) = UsePlacementFinder::check(self.tcx, krate, module_id);
834 if let Some(span) = span {
835 let path_strings = candidates.iter().map(|did| {
836 // Produce an additional newline to separate the new use statement
837 // from the directly following item.
838 let additional_newline = if found_use { "" } else { "\n" };
841 with_crate_prefix(|| self.tcx.def_path_str(*did)),
846 err.span_suggestions(span, &msg, path_strings, Applicability::MaybeIncorrect);
848 let limit = if candidates.len() == 5 { 5 } else { 4 };
849 for (i, trait_did) in candidates.iter().take(limit).enumerate() {
850 if candidates.len() > 1 {
851 msg.push_str(&format!(
852 "\ncandidate #{}: `use {};`",
854 with_crate_prefix(|| self.tcx.def_path_str(*trait_did))
857 msg.push_str(&format!(
859 with_crate_prefix(|| self.tcx.def_path_str(*trait_did))
863 if candidates.len() > limit {
864 msg.push_str(&format!("\nand {} others", candidates.len() - limit));
870 fn suggest_valid_traits(
872 err: &mut DiagnosticBuilder<'_>,
873 valid_out_of_scope_traits: Vec<DefId>,
875 if !valid_out_of_scope_traits.is_empty() {
876 let mut candidates = valid_out_of_scope_traits;
879 err.help("items from traits can only be used if the trait is in scope");
881 "the following {traits_are} implemented but not in scope; \
882 perhaps add a `use` for {one_of_them}:",
883 traits_are = if candidates.len() == 1 { "trait is" } else { "traits are" },
884 one_of_them = if candidates.len() == 1 { "it" } else { "one of them" },
887 self.suggest_use_candidates(err, msg, candidates);
894 fn suggest_traits_to_import<'b>(
896 err: &mut DiagnosticBuilder<'_>,
899 item_name: ast::Ident,
900 source: SelfSource<'b>,
901 valid_out_of_scope_traits: Vec<DefId>,
902 unsatisfied_predicates: &[(ty::Predicate<'tcx>, Option<ty::Predicate<'tcx>>)],
904 if self.suggest_valid_traits(err, valid_out_of_scope_traits) {
908 let type_is_local = self.type_derefs_to_local(span, rcvr_ty, source);
910 let mut arbitrary_rcvr = vec![];
911 // There are no traits implemented, so lets suggest some traits to
912 // implement, by finding ones that have the item name, and are
913 // legal to implement.
914 let mut candidates = all_traits(self.tcx)
917 // We approximate the coherence rules to only suggest
918 // traits that are legal to implement by requiring that
919 // either the type or trait is local. Multi-dispatch means
920 // this isn't perfect (that is, there are cases when
921 // implementing a trait would be legal but is rejected
923 !unsatisfied_predicates.iter().any(|(p, _)| match p {
924 // Hide traits if they are present in predicates as they can be fixed without
925 // having to implement them.
926 ty::Predicate::Trait(t, _) => t.def_id() != info.def_id,
927 ty::Predicate::Projection(p) => p.item_def_id() != info.def_id,
929 }) && (type_is_local || info.def_id.is_local())
931 .associated_item(info.def_id, item_name, Namespace::ValueNS)
933 if let ty::AssocKind::Method = item.kind {
934 let id = self.tcx.hir().as_local_hir_id(item.def_id);
935 if let Some(hir::Node::TraitItem(hir::TraitItem {
936 kind: hir::TraitItemKind::Fn(fn_sig, method),
938 })) = id.map(|id| self.tcx.hir().get(id))
940 let self_first_arg = match method {
941 hir::TraitFn::Required([ident, ..]) => {
942 ident.name == kw::SelfLower
944 hir::TraitFn::Provided(body_id) => {
945 match &self.tcx.hir().body(*body_id).params[..] {
950 hir::PatKind::Binding(
959 }, ..] => ident.name == kw::SelfLower,
966 if !fn_sig.decl.implicit_self.has_implicit_self()
969 if let Some(ty) = fn_sig.decl.inputs.get(0) {
970 arbitrary_rcvr.push(ty.span);
976 // We only want to suggest public or local traits (#45781).
977 item.vis == ty::Visibility::Public || info.def_id.is_local()
981 .collect::<Vec<_>>();
982 for span in &arbitrary_rcvr {
985 "the method might not be found because of this arbitrary self type",
989 if !candidates.is_empty() {
990 // Sort from most relevant to least relevant.
991 candidates.sort_by(|a, b| a.cmp(b).reverse());
994 let param_type = match rcvr_ty.kind {
995 ty::Param(param) => Some(param),
996 ty::Ref(_, ty, _) => match ty.kind {
997 ty::Param(param) => Some(param),
1002 err.help(if param_type.is_some() {
1003 "items from traits can only be used if the type parameter is bounded by the trait"
1005 "items from traits can only be used if the trait is implemented and in scope"
1007 let message = |action| {
1009 "the following {traits_define} an item `{name}`, perhaps you need to {action} \
1012 if candidates.len() == 1 { "trait defines" } else { "traits define" },
1014 one_of_them = if candidates.len() == 1 { "it" } else { "one of them" },
1018 // Obtain the span for `param` and use it for a structured suggestion.
1019 let mut suggested = false;
1020 if let (Some(ref param), Some(ref table)) = (param_type, self.in_progress_tables) {
1021 let table_owner = table.borrow().hir_owner;
1022 if let Some(table_owner) = table_owner {
1023 let generics = self.tcx.generics_of(table_owner.to_def_id());
1024 let type_param = generics.type_param(param, self.tcx);
1025 let hir = &self.tcx.hir();
1026 if let Some(id) = hir.as_local_hir_id(type_param.def_id) {
1027 // Get the `hir::Param` to verify whether it already has any bounds.
1028 // We do this to avoid suggesting code that ends up as `T: FooBar`,
1029 // instead we suggest `T: Foo + Bar` in that case.
1031 Node::GenericParam(ref param) => {
1032 let mut impl_trait = false;
1033 let has_bounds = if let hir::GenericParamKind::Type {
1038 // We've found `fn foo(x: impl Trait)` instead of
1039 // `fn foo<T>(x: T)`. We want to suggest the correct
1040 // `fn foo(x: impl Trait + TraitBound)` instead of
1041 // `fn foo<T: TraitBound>(x: T)`. (#63706)
1047 let sp = hir.span(id);
1048 let sp = if let Some(first_bound) = has_bounds {
1049 // `sp` only covers `T`, change it so that it covers
1050 // `T:` when appropriate
1051 sp.until(first_bound.span())
1055 let trait_def_ids: FxHashSet<DefId> = param
1058 .filter_map(|bound| bound.trait_def_id())
1060 if !candidates.iter().any(|t| trait_def_ids.contains(&t.def_id)) {
1061 err.span_suggestions(
1064 "restrict type parameter `{}` with",
1067 candidates.iter().map(|t| {
1071 if impl_trait { " +" } else { ":" },
1072 self.tcx.def_path_str(t.def_id),
1073 if has_bounds.is_some() { " + " } else { "" },
1076 Applicability::MaybeIncorrect,
1081 Node::Item(hir::Item {
1082 kind: hir::ItemKind::Trait(.., bounds, _),
1086 let (sp, sep, article) = if bounds.is_empty() {
1087 (ident.span.shrink_to_hi(), ":", "a")
1089 (bounds.last().unwrap().span().shrink_to_hi(), " +", "another")
1091 err.span_suggestions(
1093 &message(format!("add {} supertrait for", article)),
1094 candidates.iter().map(|t| {
1095 format!("{} {}", sep, self.tcx.def_path_str(t.def_id),)
1097 Applicability::MaybeIncorrect,
1108 let action = if let Some(param) = param_type {
1109 format!("restrict type parameter `{}` with", param)
1111 // FIXME: it might only need to be imported into scope, not implemented.
1112 "implement".to_string()
1114 let mut use_note = true;
1115 if let [trait_info] = &candidates[..] {
1116 if let Some(span) = self.tcx.hir().span_if_local(trait_info.def_id) {
1118 self.tcx.sess.source_map().def_span(span),
1120 "`{}` defines an item `{}`, perhaps you need to {} it",
1121 self.tcx.def_path_str(trait_info.def_id),
1130 let mut msg = message(action);
1131 for (i, trait_info) in candidates.iter().enumerate() {
1132 msg.push_str(&format!(
1133 "\ncandidate #{}: `{}`",
1135 self.tcx.def_path_str(trait_info.def_id),
1144 /// Checks whether there is a local type somewhere in the chain of
1145 /// autoderefs of `rcvr_ty`.
1146 fn type_derefs_to_local(&self, span: Span, rcvr_ty: Ty<'tcx>, source: SelfSource<'_>) -> bool {
1147 fn is_local(ty: Ty<'_>) -> bool {
1149 ty::Adt(def, _) => def.did.is_local(),
1150 ty::Foreign(did) => did.is_local(),
1152 ty::Dynamic(ref tr, ..) => {
1153 tr.principal().map(|d| d.def_id().is_local()).unwrap_or(false)
1156 ty::Param(_) => true,
1158 // Everything else (primitive types, etc.) is effectively
1159 // non-local (there are "edge" cases, e.g., `(LocalType,)`, but
1160 // the noise from these sort of types is usually just really
1161 // annoying, rather than any sort of help).
1166 // This occurs for UFCS desugaring of `T::method`, where there is no
1167 // receiver expression for the method call, and thus no autoderef.
1168 if let SelfSource::QPath(_) = source {
1169 return is_local(self.resolve_vars_with_obligations(rcvr_ty));
1172 self.autoderef(span, rcvr_ty).any(|(ty, _)| is_local(ty))
1176 #[derive(Copy, Clone)]
1177 pub enum SelfSource<'a> {
1178 QPath(&'a hir::Ty<'a>),
1179 MethodCall(&'a hir::Expr<'a> /* rcvr */),
1182 #[derive(Copy, Clone)]
1183 pub struct TraitInfo {
1187 impl PartialEq for TraitInfo {
1188 fn eq(&self, other: &TraitInfo) -> bool {
1189 self.cmp(other) == Ordering::Equal
1192 impl Eq for TraitInfo {}
1193 impl PartialOrd for TraitInfo {
1194 fn partial_cmp(&self, other: &TraitInfo) -> Option<Ordering> {
1195 Some(self.cmp(other))
1198 impl Ord for TraitInfo {
1199 fn cmp(&self, other: &TraitInfo) -> Ordering {
1200 // Local crates are more important than remote ones (local:
1201 // `cnum == 0`), and otherwise we throw in the defid for totality.
1203 let lhs = (other.def_id.krate, other.def_id);
1204 let rhs = (self.def_id.krate, self.def_id);
1209 /// Retrieves all traits in this crate and any dependent crates.
1210 pub fn all_traits(tcx: TyCtxt<'_>) -> Vec<TraitInfo> {
1211 tcx.all_traits(LOCAL_CRATE).iter().map(|&def_id| TraitInfo { def_id }).collect()
1214 /// Computes all traits in this crate and any dependent crates.
1215 fn compute_all_traits(tcx: TyCtxt<'_>) -> Vec<DefId> {
1216 use hir::itemlikevisit;
1218 let mut traits = vec![];
1222 struct Visitor<'a, 'tcx> {
1223 map: &'a hir_map::Map<'tcx>,
1224 traits: &'a mut Vec<DefId>,
1227 impl<'v, 'a, 'tcx> itemlikevisit::ItemLikeVisitor<'v> for Visitor<'a, 'tcx> {
1228 fn visit_item(&mut self, i: &'v hir::Item<'v>) {
1230 hir::ItemKind::Trait(..) | hir::ItemKind::TraitAlias(..) => {
1231 let def_id = self.map.local_def_id(i.hir_id);
1232 self.traits.push(def_id);
1238 fn visit_trait_item(&mut self, _trait_item: &hir::TraitItem<'_>) {}
1240 fn visit_impl_item(&mut self, _impl_item: &hir::ImplItem<'_>) {}
1243 tcx.hir().krate().visit_all_item_likes(&mut Visitor { map: &tcx.hir(), traits: &mut traits });
1247 let mut external_mods = FxHashSet::default();
1248 fn handle_external_res(
1250 traits: &mut Vec<DefId>,
1251 external_mods: &mut FxHashSet<DefId>,
1255 Res::Def(DefKind::Trait, def_id) | Res::Def(DefKind::TraitAlias, def_id) => {
1256 traits.push(def_id);
1258 Res::Def(DefKind::Mod, def_id) => {
1259 if !external_mods.insert(def_id) {
1262 for child in tcx.item_children(def_id).iter() {
1263 handle_external_res(tcx, traits, external_mods, child.res)
1269 for &cnum in tcx.crates().iter() {
1270 let def_id = DefId { krate: cnum, index: CRATE_DEF_INDEX };
1271 handle_external_res(tcx, &mut traits, &mut external_mods, Res::Def(DefKind::Mod, def_id));
1277 pub fn provide(providers: &mut ty::query::Providers<'_>) {
1278 providers.all_traits = |tcx, cnum| {
1279 assert_eq!(cnum, LOCAL_CRATE);
1280 &tcx.arena.alloc(compute_all_traits(tcx))[..]
1284 struct UsePlacementFinder<'tcx> {
1285 target_module: hir::HirId,
1291 impl UsePlacementFinder<'tcx> {
1294 krate: &'tcx hir::Crate<'tcx>,
1295 target_module: hir::HirId,
1296 ) -> (Option<Span>, bool) {
1297 let mut finder = UsePlacementFinder { target_module, span: None, found_use: false, tcx };
1298 intravisit::walk_crate(&mut finder, krate);
1299 (finder.span, finder.found_use)
1303 impl intravisit::Visitor<'tcx> for UsePlacementFinder<'tcx> {
1304 fn visit_mod(&mut self, module: &'tcx hir::Mod<'tcx>, _: Span, hir_id: hir::HirId) {
1305 if self.span.is_some() {
1308 if hir_id != self.target_module {
1309 intravisit::walk_mod(self, module, hir_id);
1312 // Find a `use` statement.
1313 for item_id in module.item_ids {
1314 let item = self.tcx.hir().expect_item(item_id.id);
1316 hir::ItemKind::Use(..) => {
1317 // Don't suggest placing a `use` before the prelude
1318 // import or other generated ones.
1319 if !item.span.from_expansion() {
1320 self.span = Some(item.span.shrink_to_lo());
1321 self.found_use = true;
1325 // Don't place `use` before `extern crate`...
1326 hir::ItemKind::ExternCrate(_) => {}
1327 // ...but do place them before the first other item.
1329 if self.span.map_or(true, |span| item.span < span) {
1330 if !item.span.from_expansion() {
1331 // Don't insert between attributes and an item.
1332 if item.attrs.is_empty() {
1333 self.span = Some(item.span.shrink_to_lo());
1335 // Find the first attribute on the item.
1336 for attr in item.attrs {
1337 if self.span.map_or(true, |span| attr.span < span) {
1338 self.span = Some(attr.span.shrink_to_lo());
1349 type Map = intravisit::ErasedMap<'tcx>;
1351 fn nested_visit_map(&mut self) -> intravisit::NestedVisitorMap<Self::Map> {
1352 intravisit::NestedVisitorMap::None
1356 fn print_disambiguation_help(
1357 item_name: ast::Ident,
1358 args: Option<&'tcx [hir::Expr<'tcx>]>,
1359 err: &mut DiagnosticBuilder<'_>,
1362 kind: ty::AssocKind,
1364 candidate: Option<usize>,
1365 source_map: &source_map::SourceMap,
1367 let mut applicability = Applicability::MachineApplicable;
1368 let sugg_args = if let (ty::AssocKind::Method, Some(args)) = (kind, args) {
1371 if rcvr_ty.is_region_ptr() {
1372 if rcvr_ty.is_mutable_ptr() { "&mut " } else { "&" }
1377 .map(|arg| source_map.span_to_snippet(arg.span).unwrap_or_else(|_| {
1378 applicability = Applicability::HasPlaceholders;
1381 .collect::<Vec<_>>()
1387 let sugg = format!("{}::{}{}", trait_name, item_name, sugg_args);
1388 err.span_suggestion(
1391 "disambiguate the {} for {}",
1392 kind.suggestion_descr(),
1393 if let Some(candidate) = candidate {
1394 format!("candidate #{}", candidate)
1396 "the candidate".to_string()