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)) =
1047 (param_type, self.in_progress_typeck_results)
1049 let table_owner = table.borrow().hir_owner;
1050 let generics = self.tcx.generics_of(table_owner.to_def_id());
1051 let type_param = generics.type_param(param, self.tcx);
1052 let hir = &self.tcx.hir();
1053 if let Some(def_id) = type_param.def_id.as_local() {
1054 let id = hir.as_local_hir_id(def_id);
1055 // Get the `hir::Param` to verify whether it already has any bounds.
1056 // We do this to avoid suggesting code that ends up as `T: FooBar`,
1057 // instead we suggest `T: Foo + Bar` in that case.
1059 Node::GenericParam(ref param) => {
1060 let mut impl_trait = false;
1062 if let hir::GenericParamKind::Type { synthetic: Some(_), .. } =
1065 // We've found `fn foo(x: impl Trait)` instead of
1066 // `fn foo<T>(x: T)`. We want to suggest the correct
1067 // `fn foo(x: impl Trait + TraitBound)` instead of
1068 // `fn foo<T: TraitBound>(x: T)`. (#63706)
1074 let sp = hir.span(id);
1075 let sp = if let Some(first_bound) = has_bounds {
1076 // `sp` only covers `T`, change it so that it covers
1077 // `T:` when appropriate
1078 sp.until(first_bound.span())
1082 let trait_def_ids: FxHashSet<DefId> = param
1085 .filter_map(|bound| Some(bound.trait_ref()?.trait_def_id()?))
1087 if !candidates.iter().any(|t| trait_def_ids.contains(&t.def_id)) {
1088 err.span_suggestions(
1091 "restrict type parameter `{}` with",
1094 candidates.iter().map(|t| {
1098 if impl_trait { " +" } else { ":" },
1099 self.tcx.def_path_str(t.def_id),
1100 if has_bounds.is_some() { " + " } else { "" },
1103 Applicability::MaybeIncorrect,
1108 Node::Item(hir::Item {
1109 kind: hir::ItemKind::Trait(.., bounds, _),
1113 let (sp, sep, article) = if bounds.is_empty() {
1114 (ident.span.shrink_to_hi(), ":", "a")
1116 (bounds.last().unwrap().span().shrink_to_hi(), " +", "another")
1118 err.span_suggestions(
1120 &message(format!("add {} supertrait for", article)),
1121 candidates.iter().map(|t| {
1122 format!("{} {}", sep, self.tcx.def_path_str(t.def_id),)
1124 Applicability::MaybeIncorrect,
1134 let action = if let Some(param) = param_type {
1135 format!("restrict type parameter `{}` with", param)
1137 // FIXME: it might only need to be imported into scope, not implemented.
1138 "implement".to_string()
1140 let mut use_note = true;
1141 if let [trait_info] = &candidates[..] {
1142 if let Some(span) = self.tcx.hir().span_if_local(trait_info.def_id) {
1144 self.tcx.sess.source_map().guess_head_span(span),
1146 "`{}` defines an item `{}`, perhaps you need to {} it",
1147 self.tcx.def_path_str(trait_info.def_id),
1156 let mut msg = message(action);
1157 for (i, trait_info) in candidates.iter().enumerate() {
1158 msg.push_str(&format!(
1159 "\ncandidate #{}: `{}`",
1161 self.tcx.def_path_str(trait_info.def_id),
1170 /// Checks whether there is a local type somewhere in the chain of
1171 /// autoderefs of `rcvr_ty`.
1172 fn type_derefs_to_local(&self, span: Span, rcvr_ty: Ty<'tcx>, source: SelfSource<'_>) -> bool {
1173 fn is_local(ty: Ty<'_>) -> bool {
1175 ty::Adt(def, _) => def.did.is_local(),
1176 ty::Foreign(did) => did.is_local(),
1178 ty::Dynamic(ref tr, ..) => {
1179 tr.principal().map(|d| d.def_id().is_local()).unwrap_or(false)
1182 ty::Param(_) => true,
1184 // Everything else (primitive types, etc.) is effectively
1185 // non-local (there are "edge" cases, e.g., `(LocalType,)`, but
1186 // the noise from these sort of types is usually just really
1187 // annoying, rather than any sort of help).
1192 // This occurs for UFCS desugaring of `T::method`, where there is no
1193 // receiver expression for the method call, and thus no autoderef.
1194 if let SelfSource::QPath(_) = source {
1195 return is_local(self.resolve_vars_with_obligations(rcvr_ty));
1198 self.autoderef(span, rcvr_ty).any(|(ty, _)| is_local(ty))
1202 #[derive(Copy, Clone)]
1203 pub enum SelfSource<'a> {
1204 QPath(&'a hir::Ty<'a>),
1205 MethodCall(&'a hir::Expr<'a> /* rcvr */),
1208 #[derive(Copy, Clone)]
1209 pub struct TraitInfo {
1213 impl PartialEq for TraitInfo {
1214 fn eq(&self, other: &TraitInfo) -> bool {
1215 self.cmp(other) == Ordering::Equal
1218 impl Eq for TraitInfo {}
1219 impl PartialOrd for TraitInfo {
1220 fn partial_cmp(&self, other: &TraitInfo) -> Option<Ordering> {
1221 Some(self.cmp(other))
1224 impl Ord for TraitInfo {
1225 fn cmp(&self, other: &TraitInfo) -> Ordering {
1226 // Local crates are more important than remote ones (local:
1227 // `cnum == 0`), and otherwise we throw in the defid for totality.
1229 let lhs = (other.def_id.krate, other.def_id);
1230 let rhs = (self.def_id.krate, self.def_id);
1235 /// Retrieves all traits in this crate and any dependent crates.
1236 pub fn all_traits(tcx: TyCtxt<'_>) -> Vec<TraitInfo> {
1237 tcx.all_traits(LOCAL_CRATE).iter().map(|&def_id| TraitInfo { def_id }).collect()
1240 /// Computes all traits in this crate and any dependent crates.
1241 fn compute_all_traits(tcx: TyCtxt<'_>) -> Vec<DefId> {
1242 use hir::itemlikevisit;
1244 let mut traits = vec![];
1248 struct Visitor<'a, 'tcx> {
1249 map: &'a hir_map::Map<'tcx>,
1250 traits: &'a mut Vec<DefId>,
1253 impl<'v, 'a, 'tcx> itemlikevisit::ItemLikeVisitor<'v> for Visitor<'a, 'tcx> {
1254 fn visit_item(&mut self, i: &'v hir::Item<'v>) {
1256 hir::ItemKind::Trait(..) | hir::ItemKind::TraitAlias(..) => {
1257 let def_id = self.map.local_def_id(i.hir_id);
1258 self.traits.push(def_id.to_def_id());
1264 fn visit_trait_item(&mut self, _trait_item: &hir::TraitItem<'_>) {}
1266 fn visit_impl_item(&mut self, _impl_item: &hir::ImplItem<'_>) {}
1269 tcx.hir().krate().visit_all_item_likes(&mut Visitor { map: &tcx.hir(), traits: &mut traits });
1273 let mut external_mods = FxHashSet::default();
1274 fn handle_external_res(
1276 traits: &mut Vec<DefId>,
1277 external_mods: &mut FxHashSet<DefId>,
1281 Res::Def(DefKind::Trait | DefKind::TraitAlias, def_id) => {
1282 traits.push(def_id);
1284 Res::Def(DefKind::Mod, def_id) => {
1285 if !external_mods.insert(def_id) {
1288 for child in tcx.item_children(def_id).iter() {
1289 handle_external_res(tcx, traits, external_mods, child.res)
1295 for &cnum in tcx.crates().iter() {
1296 let def_id = DefId { krate: cnum, index: CRATE_DEF_INDEX };
1297 handle_external_res(tcx, &mut traits, &mut external_mods, Res::Def(DefKind::Mod, def_id));
1303 pub fn provide(providers: &mut ty::query::Providers) {
1304 providers.all_traits = |tcx, cnum| {
1305 assert_eq!(cnum, LOCAL_CRATE);
1306 &tcx.arena.alloc(compute_all_traits(tcx))[..]
1310 struct UsePlacementFinder<'tcx> {
1311 target_module: hir::HirId,
1317 impl UsePlacementFinder<'tcx> {
1320 krate: &'tcx hir::Crate<'tcx>,
1321 target_module: hir::HirId,
1322 ) -> (Option<Span>, bool) {
1323 let mut finder = UsePlacementFinder { target_module, span: None, found_use: false, tcx };
1324 intravisit::walk_crate(&mut finder, krate);
1325 (finder.span, finder.found_use)
1329 impl intravisit::Visitor<'tcx> for UsePlacementFinder<'tcx> {
1330 fn visit_mod(&mut self, module: &'tcx hir::Mod<'tcx>, _: Span, hir_id: hir::HirId) {
1331 if self.span.is_some() {
1334 if hir_id != self.target_module {
1335 intravisit::walk_mod(self, module, hir_id);
1338 // Find a `use` statement.
1339 for item_id in module.item_ids {
1340 let item = self.tcx.hir().expect_item(item_id.id);
1342 hir::ItemKind::Use(..) => {
1343 // Don't suggest placing a `use` before the prelude
1344 // import or other generated ones.
1345 if !item.span.from_expansion() {
1346 self.span = Some(item.span.shrink_to_lo());
1347 self.found_use = true;
1351 // Don't place `use` before `extern crate`...
1352 hir::ItemKind::ExternCrate(_) => {}
1353 // ...but do place them before the first other item.
1355 if self.span.map_or(true, |span| item.span < span) {
1356 if !item.span.from_expansion() {
1357 // Don't insert between attributes and an item.
1358 if item.attrs.is_empty() {
1359 self.span = Some(item.span.shrink_to_lo());
1361 // Find the first attribute on the item.
1362 for attr in item.attrs {
1363 if self.span.map_or(true, |span| attr.span < span) {
1364 self.span = Some(attr.span.shrink_to_lo());
1375 type Map = intravisit::ErasedMap<'tcx>;
1377 fn nested_visit_map(&mut self) -> intravisit::NestedVisitorMap<Self::Map> {
1378 intravisit::NestedVisitorMap::None
1382 fn print_disambiguation_help(
1384 args: Option<&'tcx [hir::Expr<'tcx>]>,
1385 err: &mut DiagnosticBuilder<'_>,
1388 kind: ty::AssocKind,
1391 candidate: Option<usize>,
1392 source_map: &source_map::SourceMap,
1394 let mut applicability = Applicability::MachineApplicable;
1395 let sugg_args = if let (ty::AssocKind::Fn, Some(args)) = (kind, args) {
1398 if rcvr_ty.is_region_ptr() {
1399 if rcvr_ty.is_mutable_ptr() { "&mut " } else { "&" }
1404 .map(|arg| source_map.span_to_snippet(arg.span).unwrap_or_else(|_| {
1405 applicability = Applicability::HasPlaceholders;
1408 .collect::<Vec<_>>()
1414 let sugg = format!("{}::{}{}", trait_name, item_name, sugg_args);
1415 err.span_suggestion(
1418 "disambiguate the {} for {}",
1419 kind.as_def_kind().descr(def_id),
1420 if let Some(candidate) = candidate {
1421 format!("candidate #{}", candidate)
1423 "the candidate".to_string()