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)
940 // Don't issue suggestions for unstable traits since they're
941 // unlikely to be implementable anyway
942 .filter(|info| match self.tcx.lookup_stability(info.def_id) {
943 Some(attr) => attr.level.is_stable(),
947 // We approximate the coherence rules to only suggest
948 // traits that are legal to implement by requiring that
949 // either the type or trait is local. Multi-dispatch means
950 // this isn't perfect (that is, there are cases when
951 // implementing a trait would be legal but is rejected
953 unsatisfied_predicates.iter().all(|(p, _)| match p.kind() {
954 // Hide traits if they are present in predicates as they can be fixed without
955 // having to implement them.
956 ty::PredicateKind::Trait(t, _) => t.def_id() == info.def_id,
957 ty::PredicateKind::Projection(p) => p.item_def_id() == info.def_id,
959 }) && (type_is_local || info.def_id.is_local())
961 .associated_item(info.def_id, item_name, Namespace::ValueNS)
963 if let ty::AssocKind::Fn = item.kind {
967 .map(|def_id| self.tcx.hir().as_local_hir_id(def_id));
968 if let Some(hir::Node::TraitItem(hir::TraitItem {
969 kind: hir::TraitItemKind::Fn(fn_sig, method),
971 })) = id.map(|id| self.tcx.hir().get(id))
973 let self_first_arg = match method {
974 hir::TraitFn::Required([ident, ..]) => {
975 ident.name == kw::SelfLower
977 hir::TraitFn::Provided(body_id) => {
978 self.tcx.hir().body(*body_id).params.first().map_or(
983 hir::PatKind::Binding(_, _, ident, _)
984 if ident.name == kw::SelfLower
992 if !fn_sig.decl.implicit_self.has_implicit_self()
995 if let Some(ty) = fn_sig.decl.inputs.get(0) {
996 arbitrary_rcvr.push(ty.span);
1002 // We only want to suggest public or local traits (#45781).
1003 item.vis == ty::Visibility::Public || info.def_id.is_local()
1007 .collect::<Vec<_>>();
1008 for span in &arbitrary_rcvr {
1011 "the method might not be found because of this arbitrary self type",
1015 if !candidates.is_empty() {
1016 // Sort from most relevant to least relevant.
1017 candidates.sort_by(|a, b| a.cmp(b).reverse());
1020 let param_type = match rcvr_ty.kind {
1021 ty::Param(param) => Some(param),
1022 ty::Ref(_, ty, _) => match ty.kind {
1023 ty::Param(param) => Some(param),
1028 err.help(if param_type.is_some() {
1029 "items from traits can only be used if the type parameter is bounded by the trait"
1031 "items from traits can only be used if the trait is implemented and in scope"
1033 let message = |action| {
1035 "the following {traits_define} an item `{name}`, perhaps you need to {action} \
1038 if candidates.len() == 1 { "trait defines" } else { "traits define" },
1040 one_of_them = if candidates.len() == 1 { "it" } else { "one of them" },
1044 // Obtain the span for `param` and use it for a structured suggestion.
1045 let mut suggested = false;
1046 if let (Some(ref param), Some(ref table)) = (param_type, self.in_progress_tables) {
1047 let table_owner = table.borrow().hir_owner;
1048 let generics = self.tcx.generics_of(table_owner.to_def_id());
1049 let type_param = generics.type_param(param, self.tcx);
1050 let hir = &self.tcx.hir();
1051 if let Some(def_id) = type_param.def_id.as_local() {
1052 let id = hir.as_local_hir_id(def_id);
1053 // Get the `hir::Param` to verify whether it already has any bounds.
1054 // We do this to avoid suggesting code that ends up as `T: FooBar`,
1055 // instead we suggest `T: Foo + Bar` in that case.
1057 Node::GenericParam(ref param) => {
1058 let mut impl_trait = false;
1060 if let hir::GenericParamKind::Type { synthetic: Some(_), .. } =
1063 // We've found `fn foo(x: impl Trait)` instead of
1064 // `fn foo<T>(x: T)`. We want to suggest the correct
1065 // `fn foo(x: impl Trait + TraitBound)` instead of
1066 // `fn foo<T: TraitBound>(x: T)`. (#63706)
1072 let sp = hir.span(id);
1073 let sp = if let Some(first_bound) = has_bounds {
1074 // `sp` only covers `T`, change it so that it covers
1075 // `T:` when appropriate
1076 sp.until(first_bound.span())
1080 let trait_def_ids: FxHashSet<DefId> = param
1083 .filter_map(|bound| Some(bound.trait_ref()?.trait_def_id()?))
1085 if !candidates.iter().any(|t| trait_def_ids.contains(&t.def_id)) {
1086 err.span_suggestions(
1089 "restrict type parameter `{}` with",
1092 candidates.iter().map(|t| {
1096 if impl_trait { " +" } else { ":" },
1097 self.tcx.def_path_str(t.def_id),
1098 if has_bounds.is_some() { " + " } else { "" },
1101 Applicability::MaybeIncorrect,
1106 Node::Item(hir::Item {
1107 kind: hir::ItemKind::Trait(.., bounds, _),
1111 let (sp, sep, article) = if bounds.is_empty() {
1112 (ident.span.shrink_to_hi(), ":", "a")
1114 (bounds.last().unwrap().span().shrink_to_hi(), " +", "another")
1116 err.span_suggestions(
1118 &message(format!("add {} supertrait for", article)),
1119 candidates.iter().map(|t| {
1120 format!("{} {}", sep, self.tcx.def_path_str(t.def_id),)
1122 Applicability::MaybeIncorrect,
1132 let action = if let Some(param) = param_type {
1133 format!("restrict type parameter `{}` with", param)
1135 // FIXME: it might only need to be imported into scope, not implemented.
1136 "implement".to_string()
1138 let mut use_note = true;
1139 if let [trait_info] = &candidates[..] {
1140 if let Some(span) = self.tcx.hir().span_if_local(trait_info.def_id) {
1142 self.tcx.sess.source_map().guess_head_span(span),
1144 "`{}` defines an item `{}`, perhaps you need to {} it",
1145 self.tcx.def_path_str(trait_info.def_id),
1154 let mut msg = message(action);
1155 for (i, trait_info) in candidates.iter().enumerate() {
1156 msg.push_str(&format!(
1157 "\ncandidate #{}: `{}`",
1159 self.tcx.def_path_str(trait_info.def_id),
1168 /// Checks whether there is a local type somewhere in the chain of
1169 /// autoderefs of `rcvr_ty`.
1170 fn type_derefs_to_local(&self, span: Span, rcvr_ty: Ty<'tcx>, source: SelfSource<'_>) -> bool {
1171 fn is_local(ty: Ty<'_>) -> bool {
1173 ty::Adt(def, _) => def.did.is_local(),
1174 ty::Foreign(did) => did.is_local(),
1176 ty::Dynamic(ref tr, ..) => {
1177 tr.principal().map(|d| d.def_id().is_local()).unwrap_or(false)
1180 ty::Param(_) => true,
1182 // Everything else (primitive types, etc.) is effectively
1183 // non-local (there are "edge" cases, e.g., `(LocalType,)`, but
1184 // the noise from these sort of types is usually just really
1185 // annoying, rather than any sort of help).
1190 // This occurs for UFCS desugaring of `T::method`, where there is no
1191 // receiver expression for the method call, and thus no autoderef.
1192 if let SelfSource::QPath(_) = source {
1193 return is_local(self.resolve_vars_with_obligations(rcvr_ty));
1196 self.autoderef(span, rcvr_ty).any(|(ty, _)| is_local(ty))
1200 #[derive(Copy, Clone)]
1201 pub enum SelfSource<'a> {
1202 QPath(&'a hir::Ty<'a>),
1203 MethodCall(&'a hir::Expr<'a> /* rcvr */),
1206 #[derive(Copy, Clone)]
1207 pub struct TraitInfo {
1211 impl PartialEq for TraitInfo {
1212 fn eq(&self, other: &TraitInfo) -> bool {
1213 self.cmp(other) == Ordering::Equal
1216 impl Eq for TraitInfo {}
1217 impl PartialOrd for TraitInfo {
1218 fn partial_cmp(&self, other: &TraitInfo) -> Option<Ordering> {
1219 Some(self.cmp(other))
1222 impl Ord for TraitInfo {
1223 fn cmp(&self, other: &TraitInfo) -> Ordering {
1224 // Local crates are more important than remote ones (local:
1225 // `cnum == 0`), and otherwise we throw in the defid for totality.
1227 let lhs = (other.def_id.krate, other.def_id);
1228 let rhs = (self.def_id.krate, self.def_id);
1233 /// Retrieves all traits in this crate and any dependent crates.
1234 pub fn all_traits(tcx: TyCtxt<'_>) -> Vec<TraitInfo> {
1235 tcx.all_traits(LOCAL_CRATE).iter().map(|&def_id| TraitInfo { def_id }).collect()
1238 /// Computes all traits in this crate and any dependent crates.
1239 fn compute_all_traits(tcx: TyCtxt<'_>) -> Vec<DefId> {
1240 use hir::itemlikevisit;
1242 let mut traits = vec![];
1246 struct Visitor<'a, 'tcx> {
1247 map: &'a hir_map::Map<'tcx>,
1248 traits: &'a mut Vec<DefId>,
1251 impl<'v, 'a, 'tcx> itemlikevisit::ItemLikeVisitor<'v> for Visitor<'a, 'tcx> {
1252 fn visit_item(&mut self, i: &'v hir::Item<'v>) {
1254 hir::ItemKind::Trait(..) | hir::ItemKind::TraitAlias(..) => {
1255 let def_id = self.map.local_def_id(i.hir_id);
1256 self.traits.push(def_id.to_def_id());
1262 fn visit_trait_item(&mut self, _trait_item: &hir::TraitItem<'_>) {}
1264 fn visit_impl_item(&mut self, _impl_item: &hir::ImplItem<'_>) {}
1267 tcx.hir().krate().visit_all_item_likes(&mut Visitor { map: &tcx.hir(), traits: &mut traits });
1271 let mut external_mods = FxHashSet::default();
1272 fn handle_external_res(
1274 traits: &mut Vec<DefId>,
1275 external_mods: &mut FxHashSet<DefId>,
1279 Res::Def(DefKind::Trait | DefKind::TraitAlias, def_id) => {
1280 traits.push(def_id);
1282 Res::Def(DefKind::Mod, def_id) => {
1283 if !external_mods.insert(def_id) {
1286 for child in tcx.item_children(def_id).iter() {
1287 handle_external_res(tcx, traits, external_mods, child.res)
1293 for &cnum in tcx.crates().iter() {
1294 let def_id = DefId { krate: cnum, index: CRATE_DEF_INDEX };
1295 handle_external_res(tcx, &mut traits, &mut external_mods, Res::Def(DefKind::Mod, def_id));
1301 pub fn provide(providers: &mut ty::query::Providers) {
1302 providers.all_traits = |tcx, cnum| {
1303 assert_eq!(cnum, LOCAL_CRATE);
1304 &tcx.arena.alloc(compute_all_traits(tcx))[..]
1308 struct UsePlacementFinder<'tcx> {
1309 target_module: hir::HirId,
1315 impl UsePlacementFinder<'tcx> {
1318 krate: &'tcx hir::Crate<'tcx>,
1319 target_module: hir::HirId,
1320 ) -> (Option<Span>, bool) {
1321 let mut finder = UsePlacementFinder { target_module, span: None, found_use: false, tcx };
1322 intravisit::walk_crate(&mut finder, krate);
1323 (finder.span, finder.found_use)
1327 impl intravisit::Visitor<'tcx> for UsePlacementFinder<'tcx> {
1328 fn visit_mod(&mut self, module: &'tcx hir::Mod<'tcx>, _: Span, hir_id: hir::HirId) {
1329 if self.span.is_some() {
1332 if hir_id != self.target_module {
1333 intravisit::walk_mod(self, module, hir_id);
1336 // Find a `use` statement.
1337 for item_id in module.item_ids {
1338 let item = self.tcx.hir().expect_item(item_id.id);
1340 hir::ItemKind::Use(..) => {
1341 // Don't suggest placing a `use` before the prelude
1342 // import or other generated ones.
1343 if !item.span.from_expansion() {
1344 self.span = Some(item.span.shrink_to_lo());
1345 self.found_use = true;
1349 // Don't place `use` before `extern crate`...
1350 hir::ItemKind::ExternCrate(_) => {}
1351 // ...but do place them before the first other item.
1353 if self.span.map_or(true, |span| item.span < span) {
1354 if !item.span.from_expansion() {
1355 // Don't insert between attributes and an item.
1356 if item.attrs.is_empty() {
1357 self.span = Some(item.span.shrink_to_lo());
1359 // Find the first attribute on the item.
1360 for attr in item.attrs {
1361 if self.span.map_or(true, |span| attr.span < span) {
1362 self.span = Some(attr.span.shrink_to_lo());
1373 type Map = intravisit::ErasedMap<'tcx>;
1375 fn nested_visit_map(&mut self) -> intravisit::NestedVisitorMap<Self::Map> {
1376 intravisit::NestedVisitorMap::None
1380 fn print_disambiguation_help(
1382 args: Option<&'tcx [hir::Expr<'tcx>]>,
1383 err: &mut DiagnosticBuilder<'_>,
1386 kind: ty::AssocKind,
1389 candidate: Option<usize>,
1390 source_map: &source_map::SourceMap,
1392 let mut applicability = Applicability::MachineApplicable;
1393 let sugg_args = if let (ty::AssocKind::Fn, Some(args)) = (kind, args) {
1396 if rcvr_ty.is_region_ptr() {
1397 if rcvr_ty.is_mutable_ptr() { "&mut " } else { "&" }
1402 .map(|arg| source_map.span_to_snippet(arg.span).unwrap_or_else(|_| {
1403 applicability = Applicability::HasPlaceholders;
1406 .collect::<Vec<_>>()
1412 let sugg = format!("{}::{}{}", trait_name, item_name, sugg_args);
1413 err.span_suggestion(
1416 "disambiguate the {} for {}",
1417 kind.as_def_kind().descr(def_id),
1418 if let Some(candidate) = candidate {
1419 format!("candidate #{}", candidate)
1421 "the candidate".to_string()