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 rustc_ast::util::lev_distance;
6 use rustc_data_structures::fx::{FxHashMap, FxHashSet};
7 use rustc_errors::{pluralize, struct_span_err, Applicability, DiagnosticBuilder};
9 use rustc_hir::def::{DefKind, Namespace, Res};
10 use rustc_hir::def_id::{DefId, CRATE_DEF_INDEX, LOCAL_CRATE};
11 use rustc_hir::intravisit;
12 use rustc_hir::lang_items::FnOnceTraitLangItem;
13 use rustc_hir::{ExprKind, Node, QPath};
14 use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
15 use rustc_middle::hir::map as hir_map;
16 use rustc_middle::ty::print::with_crate_prefix;
17 use rustc_middle::ty::{
18 self, ToPolyTraitRef, ToPredicate, Ty, TyCtxt, TypeFoldable, WithConstness,
20 use rustc_span::symbol::{kw, sym, Ident};
21 use rustc_span::{source_map, FileName, Span};
22 use rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt;
23 use rustc_trait_selection::traits::Obligation;
25 use std::cmp::Ordering;
27 use super::probe::Mode;
28 use super::{CandidateSource, MethodError, NoMatchData};
30 impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
31 fn is_fn_ty(&self, ty: Ty<'tcx>, span: Span) -> bool {
34 // Not all of these (e.g., unsafe fns) implement `FnOnce`,
35 // so we look for these beforehand.
36 ty::Closure(..) | ty::FnDef(..) | ty::FnPtr(_) => true,
37 // If it's not a simple function, look for things which implement `FnOnce`.
39 let fn_once = match tcx.lang_items().require(FnOnceTraitLangItem) {
40 Ok(fn_once) => fn_once,
41 Err(..) => return false,
44 self.autoderef(span, ty).any(|(ty, _)| {
46 let fn_once_substs = tcx.mk_substs_trait(
49 .next_ty_var(TypeVariableOrigin {
50 kind: TypeVariableOriginKind::MiscVariable,
55 let trait_ref = ty::TraitRef::new(fn_once, fn_once_substs);
56 let poly_trait_ref = trait_ref.to_poly_trait_ref();
57 let obligation = Obligation::misc(
61 poly_trait_ref.without_const().to_predicate(tcx),
63 self.predicate_may_hold(&obligation)
70 pub fn report_method_error<'b>(
75 source: SelfSource<'b>,
76 error: MethodError<'tcx>,
77 args: Option<&'tcx [hir::Expr<'tcx>]>,
78 ) -> Option<DiagnosticBuilder<'_>> {
81 // Avoid suggestions when we don't know what's going on.
82 if rcvr_ty.references_error() {
86 let report_candidates = |span: Span,
87 err: &mut DiagnosticBuilder<'_>,
88 mut sources: Vec<CandidateSource>,
92 // Dynamic limit to avoid hiding just one candidate, which is silly.
93 let limit = if sources.len() == 5 { 5 } else { 4 };
95 for (idx, source) in sources.iter().take(limit).enumerate() {
97 CandidateSource::ImplSource(impl_did) => {
98 // Provide the best span we can. Use the item, if local to crate, else
99 // the impl, if local to crate (item may be defaulted), else nothing.
100 let item = match self
101 .associated_item(impl_did, item_name, Namespace::ValueNS)
103 let impl_trait_ref = self.tcx.impl_trait_ref(impl_did)?;
104 self.associated_item(
105 impl_trait_ref.def_id,
116 .span_if_local(item.def_id)
117 .or_else(|| self.tcx.hir().span_if_local(impl_did));
119 let impl_ty = self.tcx.at(span).type_of(impl_did);
121 let insertion = match self.tcx.impl_trait_ref(impl_did) {
122 None => String::new(),
123 Some(trait_ref) => format!(
124 " of the trait `{}`",
125 self.tcx.def_path_str(trait_ref.def_id)
129 let (note_str, idx) = if sources.len() > 1 {
132 "candidate #{} is defined in an impl{} for the type `{}`",
142 "the candidate is defined in an impl{} for the type `{}`",
148 if let Some(note_span) = note_span {
149 // We have a span pointing to the method. Show note with snippet.
151 self.tcx.sess.source_map().guess_head_span(note_span),
157 if let Some(trait_ref) = self.tcx.impl_trait_ref(impl_did) {
158 let path = self.tcx.def_path_str(trait_ref.def_id);
160 let ty = match item.kind {
161 ty::AssocKind::Const | ty::AssocKind::Type => rcvr_ty,
162 ty::AssocKind::Fn => self
168 .filter(|ty| ty.is_region_ptr() && !rcvr_ty.is_region_ptr())
172 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) {
196 .guess_head_span(self.tcx.def_span(item.def_id));
197 let idx = if sources.len() > 1 {
199 "candidate #{} is defined in the trait `{}`",
201 self.tcx.def_path_str(trait_did)
203 err.span_note(item_span, msg);
207 "the candidate is defined in the trait `{}`",
208 self.tcx.def_path_str(trait_did)
210 err.span_note(item_span, msg);
213 let path = self.tcx.def_path_str(trait_did);
214 print_disambiguation_help(
224 self.tcx.sess.source_map(),
229 if sources.len() > limit {
230 err.note(&format!("and {} others", sources.len() - limit));
234 let sugg_span = if let SelfSource::MethodCall(expr) = source {
235 // Given `foo.bar(baz)`, `expr` is `bar`, but we want to point to the whole thing.
236 self.tcx.hir().expect_expr(self.tcx.hir().get_parent_node(expr.hir_id)).span
242 MethodError::NoMatch(NoMatchData {
243 static_candidates: static_sources,
244 unsatisfied_predicates,
251 let actual = self.resolve_vars_if_possible(&rcvr_ty);
252 let ty_str = self.ty_to_string(actual);
253 let is_method = mode == Mode::MethodCall;
254 let item_kind = if is_method {
256 } else if actual.is_enum() {
257 "variant or associated item"
259 match (item_name.as_str().chars().next(), actual.is_fresh_ty()) {
260 (Some(name), false) if name.is_lowercase() => "function or associated item",
261 (Some(_), false) => "associated item",
262 (Some(_), true) | (None, false) => "variant or associated item",
263 (None, true) => "variant",
266 let mut err = if !actual.references_error() {
267 // Suggest clamping down the type if the method that is being attempted to
268 // be used exists at all, and the type is an ambiguous numeric type
269 // ({integer}/{float}).
270 let mut candidates = all_traits(self.tcx).into_iter().filter_map(|info| {
271 self.associated_item(info.def_id, item_name, Namespace::ValueNS)
273 // There are methods that are defined on the primitive types and won't be
274 // found when exploring `all_traits`, but we also need them to be acurate on
275 // our suggestions (#47759).
276 let fund_assoc = |opt_def_id: Option<DefId>| {
278 .and_then(|id| self.associated_item(id, item_name, Namespace::ValueNS))
281 let lang_items = tcx.lang_items();
282 let found_candidate = candidates.next().is_some()
283 || fund_assoc(lang_items.i8_impl())
284 || fund_assoc(lang_items.i16_impl())
285 || fund_assoc(lang_items.i32_impl())
286 || fund_assoc(lang_items.i64_impl())
287 || fund_assoc(lang_items.i128_impl())
288 || fund_assoc(lang_items.u8_impl())
289 || fund_assoc(lang_items.u16_impl())
290 || fund_assoc(lang_items.u32_impl())
291 || fund_assoc(lang_items.u64_impl())
292 || fund_assoc(lang_items.u128_impl())
293 || fund_assoc(lang_items.f32_impl())
294 || fund_assoc(lang_items.f32_runtime_impl())
295 || fund_assoc(lang_items.f64_impl())
296 || fund_assoc(lang_items.f64_runtime_impl());
297 if let (true, false, SelfSource::MethodCall(expr), true) = (
299 actual.has_concrete_skeleton(),
303 let mut err = struct_span_err!(
307 "can't call {} `{}` on ambiguous numeric type `{}`",
312 let concrete_type = if actual.is_integral() { "i32" } else { "f32" };
314 ExprKind::Lit(ref lit) => {
319 .span_to_snippet(lit.span)
320 .unwrap_or_else(|_| "<numeric literal>".to_owned());
325 "you must specify a concrete type for \
326 this numeric value, like `{}`",
329 format!("{}_{}", snippet, concrete_type),
330 Applicability::MaybeIncorrect,
333 ExprKind::Path(ref qpath) => {
335 if let &QPath::Resolved(_, ref path) = &qpath {
336 if let hir::def::Res::Local(hir_id) = path.res {
337 let span = tcx.hir().span(hir_id);
338 let snippet = tcx.sess.source_map().span_to_snippet(span);
339 let filename = tcx.sess.source_map().span_to_filename(span);
341 let parent_node = self
344 .get(self.tcx.hir().get_parent_node(hir_id));
346 "you must specify a type for this binding, like `{}`",
350 match (filename, parent_node, snippet) {
353 Node::Local(hir::Local {
354 source: hir::LocalSource::Normal,
361 // account for `let x: _ = 42;`
368 format!("{}: {}", snippet, concrete_type),
369 Applicability::MaybeIncorrect,
373 err.span_label(span, msg);
384 span = item_name.span;
385 let mut err = struct_span_err!(
389 "no {} named `{}` found for {} `{}` in the current scope",
392 actual.prefix_string(),
396 tcx.sess.confused_type_with_std_module.borrow().get(&span)
398 if let Ok(snippet) = tcx.sess.source_map().span_to_snippet(*span) {
401 "you are looking for the module in `std`, \
402 not the primitive type",
403 format!("std::{}", snippet),
404 Applicability::MachineApplicable,
408 if let ty::RawPtr(_) = &actual.kind {
410 "try using `<*const T>::as_ref()` to get a reference to the \
411 type behind the pointer: https://doc.rust-lang.org/std/\
412 primitive.pointer.html#method.as_ref",
415 "using `<*const T>::as_ref()` on a pointer \
416 which is unaligned or points to invalid \
417 or uninitialized memory is undefined behavior",
423 tcx.sess.diagnostic().struct_dummy()
426 if let Some(def) = actual.ty_adt_def() {
427 if let Some(full_sp) = tcx.hir().span_if_local(def.did) {
428 let def_sp = tcx.sess.source_map().guess_head_span(full_sp);
432 "{} `{}` not found {}",
435 if def.is_enum() && !is_method { "here" } else { "for this" }
441 // If the method name is the name of a field with a function or closure type,
442 // give a helping note that it has to be called as `(x.f)(...)`.
443 if let SelfSource::MethodCall(expr) = source {
445 self.autoderef(span, rcvr_ty).find_map(|(ty, _)| match ty.kind {
446 ty::Adt(def, substs) if !def.is_enum() => {
447 let variant = &def.non_enum_variant();
448 self.tcx.find_field_index(item_name, variant).map(|index| {
449 let field = &variant.fields[index];
450 let field_ty = field.ty(tcx, substs);
457 if let Some((field, field_ty)) = field_receiver {
458 let scope = self.tcx.parent_module(self.body_id).to_def_id();
459 let is_accessible = field.vis.is_accessible_from(scope, self.tcx);
462 if self.is_fn_ty(&field_ty, span) {
463 let expr_span = expr.span.to(item_name.span);
464 err.multipart_suggestion(
466 "to call the function stored in `{}`, \
467 surround the field access with parentheses",
471 (expr_span.shrink_to_lo(), '('.to_string()),
472 (expr_span.shrink_to_hi(), ')'.to_string()),
474 Applicability::MachineApplicable,
480 .expect_expr(self.tcx.hir().get_parent_node(expr.hir_id));
482 if let Some(span) = call_expr.span.trim_start(item_name.span) {
485 "remove the arguments",
487 Applicability::MaybeIncorrect,
493 let field_kind = if is_accessible { "field" } else { "private field" };
494 err.span_label(item_name.span, format!("{}, not a method", field_kind));
495 } else if lev_candidate.is_none() && static_sources.is_empty() {
496 err.span_label(span, format!("{} not found in `{}`", item_kind, ty_str));
497 self.tcx.sess.trait_methods_not_found.borrow_mut().insert(orig_span);
500 err.span_label(span, format!("{} not found in `{}`", item_kind, ty_str));
501 self.tcx.sess.trait_methods_not_found.borrow_mut().insert(orig_span);
504 if self.is_fn_ty(&rcvr_ty, span) {
505 macro_rules! report_function {
506 ($span:expr, $name:expr) => {
508 "`{}` is a function, perhaps you wish to call it",
514 if let SelfSource::MethodCall(expr) = source {
515 if let Ok(expr_string) = tcx.sess.source_map().span_to_snippet(expr.span) {
516 report_function!(expr.span, expr_string);
517 } else if let ExprKind::Path(QPath::Resolved(_, ref path)) = expr.kind {
518 if let Some(segment) = path.segments.last() {
519 report_function!(expr.span, segment.ident);
525 if !static_sources.is_empty() {
527 "found the following associated functions; to be used as methods, \
528 functions must have a `self` parameter",
530 err.span_label(span, "this is an associated function, not a method");
532 if static_sources.len() == 1 {
533 let ty_str = if let Some(CandidateSource::ImplSource(impl_did)) =
534 static_sources.get(0)
536 // When the "method" is resolved through dereferencing, we really want the
537 // original type that has the associated function for accurate suggestions.
539 let ty = tcx.at(span).type_of(*impl_did);
540 match (&ty.peel_refs().kind, &actual.peel_refs().kind) {
541 (ty::Adt(def, _), ty::Adt(def_actual, _)) if def == def_actual => {
542 // Use `actual` as it will have more `substs` filled in.
543 self.ty_to_value_string(actual.peel_refs())
545 _ => self.ty_to_value_string(ty.peel_refs()),
548 self.ty_to_value_string(actual.peel_refs())
550 if let SelfSource::MethodCall(expr) = source {
553 "use associated function syntax instead",
554 format!("{}::{}", ty_str, item_name),
555 Applicability::MachineApplicable,
558 err.help(&format!("try with `{}::{}`", ty_str, item_name,));
561 report_candidates(span, &mut err, static_sources, sugg_span);
562 } else if static_sources.len() > 1 {
563 report_candidates(span, &mut err, static_sources, sugg_span);
566 let mut restrict_type_params = false;
567 if !unsatisfied_predicates.is_empty() {
568 let def_span = |def_id| {
569 self.tcx.sess.source_map().guess_head_span(self.tcx.def_span(def_id))
571 let mut type_params = FxHashMap::default();
572 let mut bound_spans = vec![];
573 let mut collect_type_param_suggestions =
574 |self_ty: Ty<'_>, parent_pred: &ty::Predicate<'_>, obligation: &str| {
575 if let (ty::Param(_), ty::PredicateKind::Trait(p, _)) =
576 (&self_ty.kind, parent_pred.kind())
578 if let ty::Adt(def, _) = p.skip_binder().trait_ref.self_ty().kind {
579 let node = def.did.as_local().map(|def_id| {
580 self.tcx.hir().get(self.tcx.hir().as_local_hir_id(def_id))
582 if let Some(hir::Node::Item(hir::Item { kind, .. })) = node {
583 if let Some(g) = kind.generics() {
584 let key = match &g.where_clause.predicates[..] {
585 [.., pred] => (pred.span().shrink_to_hi(), false),
588 .span_for_predicates_or_empty_place(),
594 .or_insert_with(FxHashSet::default)
595 .insert(obligation.to_owned());
601 let mut bound_span_label = |self_ty: Ty<'_>, obligation: &str, quiet: &str| {
603 "doesn't satisfy `{}`",
604 if obligation.len() > 50 { quiet } else { obligation }
606 match &self_ty.kind {
607 // Point at the type that couldn't satisfy the bound.
608 ty::Adt(def, _) => bound_spans.push((def_span(def.did), msg)),
609 // Point at the trait object that couldn't satisfy the bound.
610 ty::Dynamic(preds, _) => {
611 for pred in preds.skip_binder() {
613 ty::ExistentialPredicate::Trait(tr) => {
614 bound_spans.push((def_span(tr.def_id), msg.clone()))
616 ty::ExistentialPredicate::Projection(_)
617 | ty::ExistentialPredicate::AutoTrait(_) => {}
621 // Point at the closure that couldn't satisfy the bound.
622 ty::Closure(def_id, _) => bound_spans
623 .push((def_span(*def_id), format!("doesn't satisfy `{}`", quiet))),
627 let mut format_pred = |pred: ty::Predicate<'tcx>| {
629 ty::PredicateKind::Projection(pred) => {
630 // `<Foo as Iterator>::Item = String`.
632 pred.skip_binder().projection_ty.trait_ref(self.tcx);
635 .associated_item(pred.skip_binder().projection_ty.item_def_id);
636 let ty = pred.skip_binder().ty;
637 let obligation = format!("{}::{} = {}", trait_ref, assoc.ident, ty);
639 "<_ as {}>::{} = {}",
640 trait_ref.print_only_trait_path(),
644 bound_span_label(trait_ref.self_ty(), &obligation, &quiet);
645 Some((obligation, trait_ref.self_ty()))
647 ty::PredicateKind::Trait(poly_trait_ref, _) => {
648 let p = poly_trait_ref.skip_binder().trait_ref;
649 let self_ty = p.self_ty();
650 let path = p.print_only_trait_path();
651 let obligation = format!("{}: {}", self_ty, path);
652 let quiet = format!("_: {}", path);
653 bound_span_label(self_ty, &obligation, &quiet);
654 Some((obligation, self_ty))
659 let mut bound_list = unsatisfied_predicates
661 .filter_map(|(pred, parent_pred)| {
662 format_pred(*pred).map(|(p, self_ty)| match parent_pred {
663 None => format!("`{}`", p),
664 Some(parent_pred) => match format_pred(*parent_pred) {
665 None => format!("`{}`", p),
666 Some((parent_p, _)) => {
667 collect_type_param_suggestions(self_ty, parent_pred, &p);
668 format!("`{}`\nwhich is required by `{}`", p, parent_p)
674 .collect::<Vec<(usize, String)>>();
675 for ((span, empty_where), obligations) in type_params.into_iter() {
676 restrict_type_params = true;
677 err.span_suggestion_verbose(
680 "consider restricting the type parameter{s} to satisfy the \
682 s = pluralize!(obligations.len())
686 if empty_where { " where" } else { "," },
687 obligations.into_iter().collect::<Vec<_>>().join(", ")
689 Applicability::MaybeIncorrect,
693 bound_list.sort_by(|(_, a), (_, b)| a.cmp(&b)); // Sort alphabetically.
694 bound_list.dedup_by(|(_, a), (_, b)| a == b); // #35677
695 bound_list.sort_by_key(|(pos, _)| *pos); // Keep the original predicate order.
698 for (span, msg) in bound_spans.into_iter() {
699 err.span_label(span, &msg);
701 if !bound_list.is_empty() {
702 let bound_list = bound_list
704 .map(|(_, path)| path)
708 "the method `{}` exists but the following trait bounds were not \
710 item_name, bound_list
715 if actual.is_numeric() && actual.is_fresh() || restrict_type_params {
717 self.suggest_traits_to_import(
724 &unsatisfied_predicates,
728 if actual.is_enum() {
729 let adt_def = actual.ty_adt_def().expect("enum is not an ADT");
730 if let Some(suggestion) = lev_distance::find_best_match_for_name(
731 adt_def.variants.iter().map(|s| &s.ident.name),
737 "there is a variant with a similar name",
738 suggestion.to_string(),
739 Applicability::MaybeIncorrect,
744 let mut fallback_span = true;
745 let msg = "remove this method call";
746 if item_name.name == sym::as_str && actual.peel_refs().is_str() {
747 if let SelfSource::MethodCall(expr) = source {
749 self.tcx.hir().expect_expr(self.tcx.hir().get_parent_node(expr.hir_id));
750 if let Some(span) = call_expr.span.trim_start(expr.span) {
755 Applicability::MachineApplicable,
757 fallback_span = false;
761 err.span_label(span, msg);
763 } else if let Some(lev_candidate) = lev_candidate {
764 let def_kind = lev_candidate.kind.as_def_kind();
768 "there is {} {} with a similar name",
770 def_kind.descr(lev_candidate.def_id),
772 lev_candidate.ident.to_string(),
773 Applicability::MaybeIncorrect,
780 MethodError::Ambiguity(sources) => {
781 let mut err = struct_span_err!(
785 "multiple applicable items in scope"
787 err.span_label(item_name.span, format!("multiple `{}` found", item_name));
789 report_candidates(span, &mut err, sources, sugg_span);
793 MethodError::PrivateMatch(kind, def_id, out_of_scope_traits) => {
794 let kind = kind.descr(def_id);
795 let mut err = struct_span_err!(
799 "{} `{}` is private",
803 err.span_label(item_name.span, &format!("private {}", kind));
804 self.suggest_valid_traits(&mut err, out_of_scope_traits);
808 MethodError::IllegalSizedBound(candidates, needs_mut, bound_span) => {
809 let msg = format!("the `{}` method cannot be invoked on a trait object", item_name);
810 let mut err = self.sess().struct_span_err(span, &msg);
811 err.span_label(bound_span, "this has a `Sized` requirement");
812 if !candidates.is_empty() {
814 "{an}other candidate{s} {were} found in the following trait{s}, perhaps \
815 add a `use` for {one_of_them}:",
816 an = if candidates.len() == 1 { "an" } else { "" },
817 s = pluralize!(candidates.len()),
818 were = if candidates.len() == 1 { "was" } else { "were" },
819 one_of_them = if candidates.len() == 1 { "it" } else { "one_of_them" },
821 self.suggest_use_candidates(&mut err, help, candidates);
823 if let ty::Ref(region, t_type, mutability) = rcvr_ty.kind {
825 let trait_type = self.tcx.mk_ref(
827 ty::TypeAndMut { ty: t_type, mutbl: mutability.invert() },
829 err.note(&format!("you need `{}` instead of `{}`", trait_type, rcvr_ty));
835 MethodError::BadReturnType => bug!("no return type expectations but got BadReturnType"),
840 /// Print out the type for use in value namespace.
841 fn ty_to_value_string(&self, ty: Ty<'tcx>) -> String {
843 ty::Adt(def, substs) => format!("{}", ty::Instance::new(def.did, substs)),
844 _ => self.ty_to_string(ty),
848 fn suggest_use_candidates(
850 err: &mut DiagnosticBuilder<'_>,
852 candidates: Vec<DefId>,
854 let module_did = self.tcx.parent_module(self.body_id);
855 let module_id = self.tcx.hir().as_local_hir_id(module_did);
856 let krate = self.tcx.hir().krate();
857 let (span, found_use) = UsePlacementFinder::check(self.tcx, krate, module_id);
858 if let Some(span) = span {
859 let path_strings = candidates.iter().map(|did| {
860 // Produce an additional newline to separate the new use statement
861 // from the directly following item.
862 let additional_newline = if found_use { "" } else { "\n" };
865 with_crate_prefix(|| self.tcx.def_path_str(*did)),
870 err.span_suggestions(span, &msg, path_strings, Applicability::MaybeIncorrect);
872 let limit = if candidates.len() == 5 { 5 } else { 4 };
873 for (i, trait_did) in candidates.iter().take(limit).enumerate() {
874 if candidates.len() > 1 {
875 msg.push_str(&format!(
876 "\ncandidate #{}: `use {};`",
878 with_crate_prefix(|| self.tcx.def_path_str(*trait_did))
881 msg.push_str(&format!(
883 with_crate_prefix(|| self.tcx.def_path_str(*trait_did))
887 if candidates.len() > limit {
888 msg.push_str(&format!("\nand {} others", candidates.len() - limit));
894 fn suggest_valid_traits(
896 err: &mut DiagnosticBuilder<'_>,
897 valid_out_of_scope_traits: Vec<DefId>,
899 if !valid_out_of_scope_traits.is_empty() {
900 let mut candidates = valid_out_of_scope_traits;
903 err.help("items from traits can only be used if the trait is in scope");
905 "the following {traits_are} implemented but not in scope; \
906 perhaps add a `use` for {one_of_them}:",
907 traits_are = if candidates.len() == 1 { "trait is" } else { "traits are" },
908 one_of_them = if candidates.len() == 1 { "it" } else { "one of them" },
911 self.suggest_use_candidates(err, msg, candidates);
918 fn suggest_traits_to_import<'b>(
920 err: &mut DiagnosticBuilder<'_>,
924 source: SelfSource<'b>,
925 valid_out_of_scope_traits: Vec<DefId>,
926 unsatisfied_predicates: &[(ty::Predicate<'tcx>, Option<ty::Predicate<'tcx>>)],
928 if self.suggest_valid_traits(err, valid_out_of_scope_traits) {
932 let type_is_local = self.type_derefs_to_local(span, rcvr_ty, source);
934 let mut arbitrary_rcvr = vec![];
935 // There are no traits implemented, so lets suggest some traits to
936 // implement, by finding ones that have the item name, and are
937 // legal to implement.
938 let mut candidates = all_traits(self.tcx)
941 // We approximate the coherence rules to only suggest
942 // traits that are legal to implement by requiring that
943 // either the type or trait is local. Multi-dispatch means
944 // this isn't perfect (that is, there are cases when
945 // implementing a trait would be legal but is rejected
947 unsatisfied_predicates.iter().all(|(p, _)| match p.kind() {
948 // Hide traits if they are present in predicates as they can be fixed without
949 // having to implement them.
950 ty::PredicateKind::Trait(t, _) => t.def_id() == info.def_id,
951 ty::PredicateKind::Projection(p) => p.item_def_id() == info.def_id,
953 }) && (type_is_local || info.def_id.is_local())
955 .associated_item(info.def_id, item_name, Namespace::ValueNS)
957 if let ty::AssocKind::Fn = item.kind {
961 .map(|def_id| self.tcx.hir().as_local_hir_id(def_id));
962 if let Some(hir::Node::TraitItem(hir::TraitItem {
963 kind: hir::TraitItemKind::Fn(fn_sig, method),
965 })) = id.map(|id| self.tcx.hir().get(id))
967 let self_first_arg = match method {
968 hir::TraitFn::Required([ident, ..]) => {
969 ident.name == kw::SelfLower
971 hir::TraitFn::Provided(body_id) => {
972 self.tcx.hir().body(*body_id).params.first().map_or(
977 hir::PatKind::Binding(_, _, ident, _)
978 if ident.name == kw::SelfLower
986 if !fn_sig.decl.implicit_self.has_implicit_self()
989 if let Some(ty) = fn_sig.decl.inputs.get(0) {
990 arbitrary_rcvr.push(ty.span);
996 // We only want to suggest public or local traits (#45781).
997 item.vis == ty::Visibility::Public || info.def_id.is_local()
1001 .collect::<Vec<_>>();
1002 for span in &arbitrary_rcvr {
1005 "the method might not be found because of this arbitrary self type",
1009 if !candidates.is_empty() {
1010 // Sort from most relevant to least relevant.
1011 candidates.sort_by(|a, b| a.cmp(b).reverse());
1014 let param_type = match rcvr_ty.kind {
1015 ty::Param(param) => Some(param),
1016 ty::Ref(_, ty, _) => match ty.kind {
1017 ty::Param(param) => Some(param),
1022 err.help(if param_type.is_some() {
1023 "items from traits can only be used if the type parameter is bounded by the trait"
1025 "items from traits can only be used if the trait is implemented and in scope"
1027 let message = |action| {
1029 "the following {traits_define} an item `{name}`, perhaps you need to {action} \
1032 if candidates.len() == 1 { "trait defines" } else { "traits define" },
1034 one_of_them = if candidates.len() == 1 { "it" } else { "one of them" },
1038 // Obtain the span for `param` and use it for a structured suggestion.
1039 let mut suggested = false;
1040 if let (Some(ref param), Some(ref table)) = (param_type, self.in_progress_tables) {
1041 let table_owner = table.borrow().hir_owner;
1042 let generics = self.tcx.generics_of(table_owner.to_def_id());
1043 let type_param = generics.type_param(param, self.tcx);
1044 let hir = &self.tcx.hir();
1045 if let Some(def_id) = type_param.def_id.as_local() {
1046 let id = hir.as_local_hir_id(def_id);
1047 // Get the `hir::Param` to verify whether it already has any bounds.
1048 // We do this to avoid suggesting code that ends up as `T: FooBar`,
1049 // instead we suggest `T: Foo + Bar` in that case.
1051 Node::GenericParam(ref param) => {
1052 let mut impl_trait = false;
1054 if let hir::GenericParamKind::Type { synthetic: Some(_), .. } =
1057 // We've found `fn foo(x: impl Trait)` instead of
1058 // `fn foo<T>(x: T)`. We want to suggest the correct
1059 // `fn foo(x: impl Trait + TraitBound)` instead of
1060 // `fn foo<T: TraitBound>(x: T)`. (#63706)
1066 let sp = hir.span(id);
1067 let sp = if let Some(first_bound) = has_bounds {
1068 // `sp` only covers `T`, change it so that it covers
1069 // `T:` when appropriate
1070 sp.until(first_bound.span())
1074 let trait_def_ids: FxHashSet<DefId> = param
1077 .filter_map(|bound| Some(bound.trait_ref()?.trait_def_id()?))
1079 if !candidates.iter().any(|t| trait_def_ids.contains(&t.def_id)) {
1080 err.span_suggestions(
1083 "restrict type parameter `{}` with",
1086 candidates.iter().map(|t| {
1090 if impl_trait { " +" } else { ":" },
1091 self.tcx.def_path_str(t.def_id),
1092 if has_bounds.is_some() { " + " } else { "" },
1095 Applicability::MaybeIncorrect,
1100 Node::Item(hir::Item {
1101 kind: hir::ItemKind::Trait(.., bounds, _),
1105 let (sp, sep, article) = if bounds.is_empty() {
1106 (ident.span.shrink_to_hi(), ":", "a")
1108 (bounds.last().unwrap().span().shrink_to_hi(), " +", "another")
1110 err.span_suggestions(
1112 &message(format!("add {} supertrait for", article)),
1113 candidates.iter().map(|t| {
1114 format!("{} {}", sep, self.tcx.def_path_str(t.def_id),)
1116 Applicability::MaybeIncorrect,
1126 let action = if let Some(param) = param_type {
1127 format!("restrict type parameter `{}` with", param)
1129 // FIXME: it might only need to be imported into scope, not implemented.
1130 "implement".to_string()
1132 let mut use_note = true;
1133 if let [trait_info] = &candidates[..] {
1134 if let Some(span) = self.tcx.hir().span_if_local(trait_info.def_id) {
1136 self.tcx.sess.source_map().guess_head_span(span),
1138 "`{}` defines an item `{}`, perhaps you need to {} it",
1139 self.tcx.def_path_str(trait_info.def_id),
1148 let mut msg = message(action);
1149 for (i, trait_info) in candidates.iter().enumerate() {
1150 msg.push_str(&format!(
1151 "\ncandidate #{}: `{}`",
1153 self.tcx.def_path_str(trait_info.def_id),
1162 /// Checks whether there is a local type somewhere in the chain of
1163 /// autoderefs of `rcvr_ty`.
1164 fn type_derefs_to_local(&self, span: Span, rcvr_ty: Ty<'tcx>, source: SelfSource<'_>) -> bool {
1165 fn is_local(ty: Ty<'_>) -> bool {
1167 ty::Adt(def, _) => def.did.is_local(),
1168 ty::Foreign(did) => did.is_local(),
1170 ty::Dynamic(ref tr, ..) => {
1171 tr.principal().map(|d| d.def_id().is_local()).unwrap_or(false)
1174 ty::Param(_) => true,
1176 // Everything else (primitive types, etc.) is effectively
1177 // non-local (there are "edge" cases, e.g., `(LocalType,)`, but
1178 // the noise from these sort of types is usually just really
1179 // annoying, rather than any sort of help).
1184 // This occurs for UFCS desugaring of `T::method`, where there is no
1185 // receiver expression for the method call, and thus no autoderef.
1186 if let SelfSource::QPath(_) = source {
1187 return is_local(self.resolve_vars_with_obligations(rcvr_ty));
1190 self.autoderef(span, rcvr_ty).any(|(ty, _)| is_local(ty))
1194 #[derive(Copy, Clone)]
1195 pub enum SelfSource<'a> {
1196 QPath(&'a hir::Ty<'a>),
1197 MethodCall(&'a hir::Expr<'a> /* rcvr */),
1200 #[derive(Copy, Clone)]
1201 pub struct TraitInfo {
1205 impl PartialEq for TraitInfo {
1206 fn eq(&self, other: &TraitInfo) -> bool {
1207 self.cmp(other) == Ordering::Equal
1210 impl Eq for TraitInfo {}
1211 impl PartialOrd for TraitInfo {
1212 fn partial_cmp(&self, other: &TraitInfo) -> Option<Ordering> {
1213 Some(self.cmp(other))
1216 impl Ord for TraitInfo {
1217 fn cmp(&self, other: &TraitInfo) -> Ordering {
1218 // Local crates are more important than remote ones (local:
1219 // `cnum == 0`), and otherwise we throw in the defid for totality.
1221 let lhs = (other.def_id.krate, other.def_id);
1222 let rhs = (self.def_id.krate, self.def_id);
1227 /// Retrieves all traits in this crate and any dependent crates.
1228 pub fn all_traits(tcx: TyCtxt<'_>) -> Vec<TraitInfo> {
1229 tcx.all_traits(LOCAL_CRATE).iter().map(|&def_id| TraitInfo { def_id }).collect()
1232 /// Computes all traits in this crate and any dependent crates.
1233 fn compute_all_traits(tcx: TyCtxt<'_>) -> Vec<DefId> {
1234 use hir::itemlikevisit;
1236 let mut traits = vec![];
1240 struct Visitor<'a, 'tcx> {
1241 map: &'a hir_map::Map<'tcx>,
1242 traits: &'a mut Vec<DefId>,
1245 impl<'v, 'a, 'tcx> itemlikevisit::ItemLikeVisitor<'v> for Visitor<'a, 'tcx> {
1246 fn visit_item(&mut self, i: &'v hir::Item<'v>) {
1248 hir::ItemKind::Trait(..) | hir::ItemKind::TraitAlias(..) => {
1249 let def_id = self.map.local_def_id(i.hir_id);
1250 self.traits.push(def_id.to_def_id());
1256 fn visit_trait_item(&mut self, _trait_item: &hir::TraitItem<'_>) {}
1258 fn visit_impl_item(&mut self, _impl_item: &hir::ImplItem<'_>) {}
1261 tcx.hir().krate().visit_all_item_likes(&mut Visitor { map: &tcx.hir(), traits: &mut traits });
1265 let mut external_mods = FxHashSet::default();
1266 fn handle_external_res(
1268 traits: &mut Vec<DefId>,
1269 external_mods: &mut FxHashSet<DefId>,
1273 Res::Def(DefKind::Trait | DefKind::TraitAlias, def_id) => {
1274 traits.push(def_id);
1276 Res::Def(DefKind::Mod, def_id) => {
1277 if !external_mods.insert(def_id) {
1280 for child in tcx.item_children(def_id).iter() {
1281 handle_external_res(tcx, traits, external_mods, child.res)
1287 for &cnum in tcx.crates().iter() {
1288 let def_id = DefId { krate: cnum, index: CRATE_DEF_INDEX };
1289 handle_external_res(tcx, &mut traits, &mut external_mods, Res::Def(DefKind::Mod, def_id));
1295 pub fn provide(providers: &mut ty::query::Providers) {
1296 providers.all_traits = |tcx, cnum| {
1297 assert_eq!(cnum, LOCAL_CRATE);
1298 &tcx.arena.alloc(compute_all_traits(tcx))[..]
1302 struct UsePlacementFinder<'tcx> {
1303 target_module: hir::HirId,
1309 impl UsePlacementFinder<'tcx> {
1312 krate: &'tcx hir::Crate<'tcx>,
1313 target_module: hir::HirId,
1314 ) -> (Option<Span>, bool) {
1315 let mut finder = UsePlacementFinder { target_module, span: None, found_use: false, tcx };
1316 intravisit::walk_crate(&mut finder, krate);
1317 (finder.span, finder.found_use)
1321 impl intravisit::Visitor<'tcx> for UsePlacementFinder<'tcx> {
1322 fn visit_mod(&mut self, module: &'tcx hir::Mod<'tcx>, _: Span, hir_id: hir::HirId) {
1323 if self.span.is_some() {
1326 if hir_id != self.target_module {
1327 intravisit::walk_mod(self, module, hir_id);
1330 // Find a `use` statement.
1331 for item_id in module.item_ids {
1332 let item = self.tcx.hir().expect_item(item_id.id);
1334 hir::ItemKind::Use(..) => {
1335 // Don't suggest placing a `use` before the prelude
1336 // import or other generated ones.
1337 if !item.span.from_expansion() {
1338 self.span = Some(item.span.shrink_to_lo());
1339 self.found_use = true;
1343 // Don't place `use` before `extern crate`...
1344 hir::ItemKind::ExternCrate(_) => {}
1345 // ...but do place them before the first other item.
1347 if self.span.map_or(true, |span| item.span < span) {
1348 if !item.span.from_expansion() {
1349 // Don't insert between attributes and an item.
1350 if item.attrs.is_empty() {
1351 self.span = Some(item.span.shrink_to_lo());
1353 // Find the first attribute on the item.
1354 for attr in item.attrs {
1355 if self.span.map_or(true, |span| attr.span < span) {
1356 self.span = Some(attr.span.shrink_to_lo());
1367 type Map = intravisit::ErasedMap<'tcx>;
1369 fn nested_visit_map(&mut self) -> intravisit::NestedVisitorMap<Self::Map> {
1370 intravisit::NestedVisitorMap::None
1374 fn print_disambiguation_help(
1376 args: Option<&'tcx [hir::Expr<'tcx>]>,
1377 err: &mut DiagnosticBuilder<'_>,
1380 kind: ty::AssocKind,
1383 candidate: Option<usize>,
1384 source_map: &source_map::SourceMap,
1386 let mut applicability = Applicability::MachineApplicable;
1387 let sugg_args = if let (ty::AssocKind::Fn, Some(args)) = (kind, args) {
1390 if rcvr_ty.is_region_ptr() {
1391 if rcvr_ty.is_mutable_ptr() { "&mut " } else { "&" }
1396 .map(|arg| source_map.span_to_snippet(arg.span).unwrap_or_else(|_| {
1397 applicability = Applicability::HasPlaceholders;
1400 .collect::<Vec<_>>()
1406 let sugg = format!("{}::{}{}", trait_name, item_name, sugg_args);
1407 err.span_suggestion(
1410 "disambiguate the {} for {}",
1411 kind.as_def_kind().descr(def_id),
1412 if let Some(candidate) = candidate {
1413 format!("candidate #{}", candidate)
1415 "the candidate".to_string()