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![];
574 let mut collect_type_param_suggestions =
575 |self_ty: Ty<'tcx>, parent_pred: &ty::Predicate<'tcx>, obligation: &str| {
576 // We don't care about regions here, so it's fine to skip the binder here.
577 if let (ty::Param(_), ty::PredicateAtom::Trait(p, _)) =
578 (&self_ty.kind, parent_pred.skip_binders())
580 if let ty::Adt(def, _) = p.trait_ref.self_ty().kind {
581 let node = def.did.as_local().map(|def_id| {
584 .get(self.tcx.hir().local_def_id_to_hir_id(def_id))
586 if let Some(hir::Node::Item(hir::Item { kind, .. })) = node {
587 if let Some(g) = kind.generics() {
588 let key = match &g.where_clause.predicates[..] {
589 [.., pred] => (pred.span().shrink_to_hi(), false),
592 .span_for_predicates_or_empty_place(),
598 .or_insert_with(FxHashSet::default)
599 .insert(obligation.to_owned());
605 let mut bound_span_label = |self_ty: Ty<'_>, obligation: &str, quiet: &str| {
607 "doesn't satisfy `{}`",
608 if obligation.len() > 50 { quiet } else { obligation }
610 match &self_ty.kind {
611 // Point at the type that couldn't satisfy the bound.
612 ty::Adt(def, _) => bound_spans.push((def_span(def.did), msg)),
613 // Point at the trait object that couldn't satisfy the bound.
614 ty::Dynamic(preds, _) => {
615 for pred in preds.skip_binder() {
617 ty::ExistentialPredicate::Trait(tr) => {
618 bound_spans.push((def_span(tr.def_id), msg.clone()))
620 ty::ExistentialPredicate::Projection(_)
621 | ty::ExistentialPredicate::AutoTrait(_) => {}
625 // Point at the closure that couldn't satisfy the bound.
626 ty::Closure(def_id, _) => bound_spans
627 .push((def_span(*def_id), format!("doesn't satisfy `{}`", quiet))),
631 let mut format_pred = |pred: ty::Predicate<'tcx>| {
632 match pred.skip_binders() {
633 ty::PredicateAtom::Projection(pred) => {
634 let pred = ty::Binder::bind(pred);
635 // `<Foo as Iterator>::Item = String`.
637 pred.skip_binder().projection_ty.trait_ref(self.tcx);
640 .associated_item(pred.skip_binder().projection_ty.item_def_id);
641 let ty = pred.skip_binder().ty;
642 let obligation = format!("{}::{} = {}", trait_ref, assoc.ident, ty);
644 "<_ as {}>::{} = {}",
645 trait_ref.print_only_trait_path(),
649 bound_span_label(trait_ref.self_ty(), &obligation, &quiet);
650 Some((obligation, trait_ref.self_ty()))
652 ty::PredicateAtom::Trait(poly_trait_ref, _) => {
653 let poly_trait_ref = ty::Binder::bind(poly_trait_ref);
654 let p = poly_trait_ref.skip_binder().trait_ref;
655 let self_ty = p.self_ty();
656 let path = p.print_only_trait_path();
657 let obligation = format!("{}: {}", self_ty, path);
658 let quiet = format!("_: {}", path);
659 bound_span_label(self_ty, &obligation, &quiet);
660 Some((obligation, self_ty))
665 let mut bound_list = unsatisfied_predicates
667 .filter_map(|(pred, parent_pred)| {
668 format_pred(*pred).map(|(p, self_ty)| match parent_pred {
669 None => format!("`{}`", p),
670 Some(parent_pred) => match format_pred(*parent_pred) {
671 None => format!("`{}`", p),
672 Some((parent_p, _)) => {
673 collect_type_param_suggestions(self_ty, parent_pred, &p);
674 format!("`{}`\nwhich is required by `{}`", p, parent_p)
680 .collect::<Vec<(usize, String)>>();
681 for ((span, empty_where), obligations) in type_params.into_iter() {
682 restrict_type_params = true;
683 // #74886: Sort here so that the output is always the same.
684 let mut obligations = obligations.into_iter().collect::<Vec<_>>();
686 err.span_suggestion_verbose(
689 "consider restricting the type parameter{s} to satisfy the \
691 s = pluralize!(obligations.len())
695 if empty_where { " where" } else { "," },
696 obligations.join(", ")
698 Applicability::MaybeIncorrect,
702 bound_list.sort_by(|(_, a), (_, b)| a.cmp(&b)); // Sort alphabetically.
703 bound_list.dedup_by(|(_, a), (_, b)| a == b); // #35677
704 bound_list.sort_by_key(|(pos, _)| *pos); // Keep the original predicate order.
707 for (span, msg) in bound_spans.into_iter() {
708 err.span_label(span, &msg);
710 if !bound_list.is_empty() {
711 let bound_list = bound_list
713 .map(|(_, path)| path)
717 "the method `{}` exists but the following trait bounds were not \
719 item_name, bound_list
724 if actual.is_numeric() && actual.is_fresh() || restrict_type_params {
726 self.suggest_traits_to_import(
733 &unsatisfied_predicates,
737 if actual.is_enum() {
738 let adt_def = actual.ty_adt_def().expect("enum is not an ADT");
739 if let Some(suggestion) = lev_distance::find_best_match_for_name(
740 adt_def.variants.iter().map(|s| &s.ident.name),
746 "there is a variant with a similar name",
747 suggestion.to_string(),
748 Applicability::MaybeIncorrect,
753 let mut fallback_span = true;
754 let msg = "remove this method call";
755 if item_name.name == sym::as_str && actual.peel_refs().is_str() {
756 if let SelfSource::MethodCall(expr) = source {
758 self.tcx.hir().expect_expr(self.tcx.hir().get_parent_node(expr.hir_id));
759 if let Some(span) = call_expr.span.trim_start(expr.span) {
764 Applicability::MachineApplicable,
766 fallback_span = false;
770 err.span_label(span, msg);
772 } else if let Some(lev_candidate) = lev_candidate {
773 let def_kind = lev_candidate.kind.as_def_kind();
777 "there is {} {} with a similar name",
779 def_kind.descr(lev_candidate.def_id),
781 lev_candidate.ident.to_string(),
782 Applicability::MaybeIncorrect,
789 MethodError::Ambiguity(sources) => {
790 let mut err = struct_span_err!(
794 "multiple applicable items in scope"
796 err.span_label(item_name.span, format!("multiple `{}` found", item_name));
798 report_candidates(span, &mut err, sources, sugg_span);
802 MethodError::PrivateMatch(kind, def_id, out_of_scope_traits) => {
803 let kind = kind.descr(def_id);
804 let mut err = struct_span_err!(
808 "{} `{}` is private",
812 err.span_label(item_name.span, &format!("private {}", kind));
813 self.suggest_valid_traits(&mut err, out_of_scope_traits);
817 MethodError::IllegalSizedBound(candidates, needs_mut, bound_span) => {
818 let msg = format!("the `{}` method cannot be invoked on a trait object", item_name);
819 let mut err = self.sess().struct_span_err(span, &msg);
820 err.span_label(bound_span, "this has a `Sized` requirement");
821 if !candidates.is_empty() {
823 "{an}other candidate{s} {were} found in the following trait{s}, perhaps \
824 add a `use` for {one_of_them}:",
825 an = if candidates.len() == 1 { "an" } else { "" },
826 s = pluralize!(candidates.len()),
827 were = if candidates.len() == 1 { "was" } else { "were" },
828 one_of_them = if candidates.len() == 1 { "it" } else { "one_of_them" },
830 self.suggest_use_candidates(&mut err, help, candidates);
832 if let ty::Ref(region, t_type, mutability) = rcvr_ty.kind {
834 let trait_type = self.tcx.mk_ref(
836 ty::TypeAndMut { ty: t_type, mutbl: mutability.invert() },
838 err.note(&format!("you need `{}` instead of `{}`", trait_type, rcvr_ty));
844 MethodError::BadReturnType => bug!("no return type expectations but got BadReturnType"),
849 /// Print out the type for use in value namespace.
850 fn ty_to_value_string(&self, ty: Ty<'tcx>) -> String {
852 ty::Adt(def, substs) => format!("{}", ty::Instance::new(def.did, substs)),
853 _ => self.ty_to_string(ty),
857 fn suggest_use_candidates(
859 err: &mut DiagnosticBuilder<'_>,
861 candidates: Vec<DefId>,
863 let module_did = self.tcx.parent_module(self.body_id);
864 let module_id = self.tcx.hir().local_def_id_to_hir_id(module_did);
865 let krate = self.tcx.hir().krate();
866 let (span, found_use) = UsePlacementFinder::check(self.tcx, krate, module_id);
867 if let Some(span) = span {
868 let path_strings = candidates.iter().map(|did| {
869 // Produce an additional newline to separate the new use statement
870 // from the directly following item.
871 let additional_newline = if found_use { "" } else { "\n" };
874 with_crate_prefix(|| self.tcx.def_path_str(*did)),
879 err.span_suggestions(span, &msg, path_strings, Applicability::MaybeIncorrect);
881 let limit = if candidates.len() == 5 { 5 } else { 4 };
882 for (i, trait_did) in candidates.iter().take(limit).enumerate() {
883 if candidates.len() > 1 {
884 msg.push_str(&format!(
885 "\ncandidate #{}: `use {};`",
887 with_crate_prefix(|| self.tcx.def_path_str(*trait_did))
890 msg.push_str(&format!(
892 with_crate_prefix(|| self.tcx.def_path_str(*trait_did))
896 if candidates.len() > limit {
897 msg.push_str(&format!("\nand {} others", candidates.len() - limit));
903 fn suggest_valid_traits(
905 err: &mut DiagnosticBuilder<'_>,
906 valid_out_of_scope_traits: Vec<DefId>,
908 if !valid_out_of_scope_traits.is_empty() {
909 let mut candidates = valid_out_of_scope_traits;
912 err.help("items from traits can only be used if the trait is in scope");
914 "the following {traits_are} implemented but not in scope; \
915 perhaps add a `use` for {one_of_them}:",
916 traits_are = if candidates.len() == 1 { "trait is" } else { "traits are" },
917 one_of_them = if candidates.len() == 1 { "it" } else { "one of them" },
920 self.suggest_use_candidates(err, msg, candidates);
927 fn suggest_traits_to_import<'b>(
929 err: &mut DiagnosticBuilder<'_>,
933 source: SelfSource<'b>,
934 valid_out_of_scope_traits: Vec<DefId>,
935 unsatisfied_predicates: &[(ty::Predicate<'tcx>, Option<ty::Predicate<'tcx>>)],
937 if self.suggest_valid_traits(err, valid_out_of_scope_traits) {
941 let type_is_local = self.type_derefs_to_local(span, rcvr_ty, source);
943 let mut arbitrary_rcvr = vec![];
944 // There are no traits implemented, so lets suggest some traits to
945 // implement, by finding ones that have the item name, and are
946 // legal to implement.
947 let mut candidates = all_traits(self.tcx)
949 // Don't issue suggestions for unstable traits since they're
950 // unlikely to be implementable anyway
951 .filter(|info| match self.tcx.lookup_stability(info.def_id) {
952 Some(attr) => attr.level.is_stable(),
956 // We approximate the coherence rules to only suggest
957 // traits that are legal to implement by requiring that
958 // either the type or trait is local. Multi-dispatch means
959 // this isn't perfect (that is, there are cases when
960 // implementing a trait would be legal but is rejected
962 unsatisfied_predicates.iter().all(|(p, _)| {
963 match p.skip_binders() {
964 // Hide traits if they are present in predicates as they can be fixed without
965 // having to implement them.
966 ty::PredicateAtom::Trait(t, _) => t.def_id() == info.def_id,
967 ty::PredicateAtom::Projection(p) => {
968 p.projection_ty.item_def_id == info.def_id
972 }) && (type_is_local || info.def_id.is_local())
974 .associated_item(info.def_id, item_name, Namespace::ValueNS)
976 if let ty::AssocKind::Fn = item.kind {
980 .map(|def_id| self.tcx.hir().local_def_id_to_hir_id(def_id));
981 if let Some(hir::Node::TraitItem(hir::TraitItem {
982 kind: hir::TraitItemKind::Fn(fn_sig, method),
984 })) = id.map(|id| self.tcx.hir().get(id))
986 let self_first_arg = match method {
987 hir::TraitFn::Required([ident, ..]) => {
988 ident.name == kw::SelfLower
990 hir::TraitFn::Provided(body_id) => {
991 self.tcx.hir().body(*body_id).params.first().map_or(
996 hir::PatKind::Binding(_, _, ident, _)
997 if ident.name == kw::SelfLower
1005 if !fn_sig.decl.implicit_self.has_implicit_self()
1008 if let Some(ty) = fn_sig.decl.inputs.get(0) {
1009 arbitrary_rcvr.push(ty.span);
1015 // We only want to suggest public or local traits (#45781).
1016 item.vis == ty::Visibility::Public || info.def_id.is_local()
1020 .collect::<Vec<_>>();
1021 for span in &arbitrary_rcvr {
1024 "the method might not be found because of this arbitrary self type",
1028 if !candidates.is_empty() {
1029 // Sort from most relevant to least relevant.
1030 candidates.sort_by(|a, b| a.cmp(b).reverse());
1033 let param_type = match rcvr_ty.kind {
1034 ty::Param(param) => Some(param),
1035 ty::Ref(_, ty, _) => match ty.kind {
1036 ty::Param(param) => Some(param),
1041 err.help(if param_type.is_some() {
1042 "items from traits can only be used if the type parameter is bounded by the trait"
1044 "items from traits can only be used if the trait is implemented and in scope"
1046 let message = |action| {
1048 "the following {traits_define} an item `{name}`, perhaps you need to {action} \
1051 if candidates.len() == 1 { "trait defines" } else { "traits define" },
1053 one_of_them = if candidates.len() == 1 { "it" } else { "one of them" },
1057 // Obtain the span for `param` and use it for a structured suggestion.
1058 let mut suggested = false;
1059 if let (Some(ref param), Some(ref table)) =
1060 (param_type, self.in_progress_typeck_results)
1062 let table_owner = table.borrow().hir_owner;
1063 let generics = self.tcx.generics_of(table_owner.to_def_id());
1064 let type_param = generics.type_param(param, self.tcx);
1065 let hir = &self.tcx.hir();
1066 if let Some(def_id) = type_param.def_id.as_local() {
1067 let id = hir.local_def_id_to_hir_id(def_id);
1068 // Get the `hir::Param` to verify whether it already has any bounds.
1069 // We do this to avoid suggesting code that ends up as `T: FooBar`,
1070 // instead we suggest `T: Foo + Bar` in that case.
1072 Node::GenericParam(ref param) => {
1073 let mut impl_trait = false;
1075 if let hir::GenericParamKind::Type { synthetic: Some(_), .. } =
1078 // We've found `fn foo(x: impl Trait)` instead of
1079 // `fn foo<T>(x: T)`. We want to suggest the correct
1080 // `fn foo(x: impl Trait + TraitBound)` instead of
1081 // `fn foo<T: TraitBound>(x: T)`. (#63706)
1087 let sp = hir.span(id);
1088 let sp = if let Some(first_bound) = has_bounds {
1089 // `sp` only covers `T`, change it so that it covers
1090 // `T:` when appropriate
1091 sp.until(first_bound.span())
1095 let trait_def_ids: FxHashSet<DefId> = param
1098 .filter_map(|bound| Some(bound.trait_ref()?.trait_def_id()?))
1100 if !candidates.iter().any(|t| trait_def_ids.contains(&t.def_id)) {
1101 err.span_suggestions(
1104 "restrict type parameter `{}` with",
1107 candidates.iter().map(|t| {
1111 if impl_trait { " +" } else { ":" },
1112 self.tcx.def_path_str(t.def_id),
1113 if has_bounds.is_some() { " + " } else { "" },
1116 Applicability::MaybeIncorrect,
1121 Node::Item(hir::Item {
1122 kind: hir::ItemKind::Trait(.., bounds, _),
1126 let (sp, sep, article) = if bounds.is_empty() {
1127 (ident.span.shrink_to_hi(), ":", "a")
1129 (bounds.last().unwrap().span().shrink_to_hi(), " +", "another")
1131 err.span_suggestions(
1133 &message(format!("add {} supertrait for", article)),
1134 candidates.iter().map(|t| {
1135 format!("{} {}", sep, self.tcx.def_path_str(t.def_id),)
1137 Applicability::MaybeIncorrect,
1147 let action = if let Some(param) = param_type {
1148 format!("restrict type parameter `{}` with", param)
1150 // FIXME: it might only need to be imported into scope, not implemented.
1151 "implement".to_string()
1153 let mut use_note = true;
1154 if let [trait_info] = &candidates[..] {
1155 if let Some(span) = self.tcx.hir().span_if_local(trait_info.def_id) {
1157 self.tcx.sess.source_map().guess_head_span(span),
1159 "`{}` defines an item `{}`, perhaps you need to {} it",
1160 self.tcx.def_path_str(trait_info.def_id),
1169 let mut msg = message(action);
1170 for (i, trait_info) in candidates.iter().enumerate() {
1171 msg.push_str(&format!(
1172 "\ncandidate #{}: `{}`",
1174 self.tcx.def_path_str(trait_info.def_id),
1183 /// Checks whether there is a local type somewhere in the chain of
1184 /// autoderefs of `rcvr_ty`.
1185 fn type_derefs_to_local(&self, span: Span, rcvr_ty: Ty<'tcx>, source: SelfSource<'_>) -> bool {
1186 fn is_local(ty: Ty<'_>) -> bool {
1188 ty::Adt(def, _) => def.did.is_local(),
1189 ty::Foreign(did) => did.is_local(),
1191 ty::Dynamic(ref tr, ..) => {
1192 tr.principal().map(|d| d.def_id().is_local()).unwrap_or(false)
1195 ty::Param(_) => true,
1197 // Everything else (primitive types, etc.) is effectively
1198 // non-local (there are "edge" cases, e.g., `(LocalType,)`, but
1199 // the noise from these sort of types is usually just really
1200 // annoying, rather than any sort of help).
1205 // This occurs for UFCS desugaring of `T::method`, where there is no
1206 // receiver expression for the method call, and thus no autoderef.
1207 if let SelfSource::QPath(_) = source {
1208 return is_local(self.resolve_vars_with_obligations(rcvr_ty));
1211 self.autoderef(span, rcvr_ty).any(|(ty, _)| is_local(ty))
1215 #[derive(Copy, Clone)]
1216 pub enum SelfSource<'a> {
1217 QPath(&'a hir::Ty<'a>),
1218 MethodCall(&'a hir::Expr<'a> /* rcvr */),
1221 #[derive(Copy, Clone)]
1222 pub struct TraitInfo {
1226 impl PartialEq for TraitInfo {
1227 fn eq(&self, other: &TraitInfo) -> bool {
1228 self.cmp(other) == Ordering::Equal
1231 impl Eq for TraitInfo {}
1232 impl PartialOrd for TraitInfo {
1233 fn partial_cmp(&self, other: &TraitInfo) -> Option<Ordering> {
1234 Some(self.cmp(other))
1237 impl Ord for TraitInfo {
1238 fn cmp(&self, other: &TraitInfo) -> Ordering {
1239 // Local crates are more important than remote ones (local:
1240 // `cnum == 0`), and otherwise we throw in the defid for totality.
1242 let lhs = (other.def_id.krate, other.def_id);
1243 let rhs = (self.def_id.krate, self.def_id);
1248 /// Retrieves all traits in this crate and any dependent crates.
1249 pub fn all_traits(tcx: TyCtxt<'_>) -> Vec<TraitInfo> {
1250 tcx.all_traits(LOCAL_CRATE).iter().map(|&def_id| TraitInfo { def_id }).collect()
1253 /// Computes all traits in this crate and any dependent crates.
1254 fn compute_all_traits(tcx: TyCtxt<'_>) -> Vec<DefId> {
1255 use hir::itemlikevisit;
1257 let mut traits = vec![];
1261 struct Visitor<'a, 'tcx> {
1262 map: &'a hir_map::Map<'tcx>,
1263 traits: &'a mut Vec<DefId>,
1266 impl<'v, 'a, 'tcx> itemlikevisit::ItemLikeVisitor<'v> for Visitor<'a, 'tcx> {
1267 fn visit_item(&mut self, i: &'v hir::Item<'v>) {
1269 hir::ItemKind::Trait(..) | hir::ItemKind::TraitAlias(..) => {
1270 let def_id = self.map.local_def_id(i.hir_id);
1271 self.traits.push(def_id.to_def_id());
1277 fn visit_trait_item(&mut self, _trait_item: &hir::TraitItem<'_>) {}
1279 fn visit_impl_item(&mut self, _impl_item: &hir::ImplItem<'_>) {}
1282 tcx.hir().krate().visit_all_item_likes(&mut Visitor { map: &tcx.hir(), traits: &mut traits });
1286 let mut external_mods = FxHashSet::default();
1287 fn handle_external_res(
1289 traits: &mut Vec<DefId>,
1290 external_mods: &mut FxHashSet<DefId>,
1294 Res::Def(DefKind::Trait | DefKind::TraitAlias, def_id) => {
1295 traits.push(def_id);
1297 Res::Def(DefKind::Mod, def_id) => {
1298 if !external_mods.insert(def_id) {
1301 for child in tcx.item_children(def_id).iter() {
1302 handle_external_res(tcx, traits, external_mods, child.res)
1308 for &cnum in tcx.crates().iter() {
1309 let def_id = DefId { krate: cnum, index: CRATE_DEF_INDEX };
1310 handle_external_res(tcx, &mut traits, &mut external_mods, Res::Def(DefKind::Mod, def_id));
1316 pub fn provide(providers: &mut ty::query::Providers) {
1317 providers.all_traits = |tcx, cnum| {
1318 assert_eq!(cnum, LOCAL_CRATE);
1319 &tcx.arena.alloc(compute_all_traits(tcx))[..]
1323 struct UsePlacementFinder<'tcx> {
1324 target_module: hir::HirId,
1330 impl UsePlacementFinder<'tcx> {
1333 krate: &'tcx hir::Crate<'tcx>,
1334 target_module: hir::HirId,
1335 ) -> (Option<Span>, bool) {
1336 let mut finder = UsePlacementFinder { target_module, span: None, found_use: false, tcx };
1337 intravisit::walk_crate(&mut finder, krate);
1338 (finder.span, finder.found_use)
1342 impl intravisit::Visitor<'tcx> for UsePlacementFinder<'tcx> {
1343 fn visit_mod(&mut self, module: &'tcx hir::Mod<'tcx>, _: Span, hir_id: hir::HirId) {
1344 if self.span.is_some() {
1347 if hir_id != self.target_module {
1348 intravisit::walk_mod(self, module, hir_id);
1351 // Find a `use` statement.
1352 for item_id in module.item_ids {
1353 let item = self.tcx.hir().expect_item(item_id.id);
1355 hir::ItemKind::Use(..) => {
1356 // Don't suggest placing a `use` before the prelude
1357 // import or other generated ones.
1358 if !item.span.from_expansion() {
1359 self.span = Some(item.span.shrink_to_lo());
1360 self.found_use = true;
1364 // Don't place `use` before `extern crate`...
1365 hir::ItemKind::ExternCrate(_) => {}
1366 // ...but do place them before the first other item.
1368 if self.span.map_or(true, |span| item.span < span) {
1369 if !item.span.from_expansion() {
1370 // Don't insert between attributes and an item.
1371 if item.attrs.is_empty() {
1372 self.span = Some(item.span.shrink_to_lo());
1374 // Find the first attribute on the item.
1375 for attr in item.attrs {
1376 if self.span.map_or(true, |span| attr.span < span) {
1377 self.span = Some(attr.span.shrink_to_lo());
1388 type Map = intravisit::ErasedMap<'tcx>;
1390 fn nested_visit_map(&mut self) -> intravisit::NestedVisitorMap<Self::Map> {
1391 intravisit::NestedVisitorMap::None
1395 fn print_disambiguation_help(
1397 args: Option<&'tcx [hir::Expr<'tcx>]>,
1398 err: &mut DiagnosticBuilder<'_>,
1401 kind: ty::AssocKind,
1404 candidate: Option<usize>,
1405 source_map: &source_map::SourceMap,
1407 let mut applicability = Applicability::MachineApplicable;
1408 let sugg_args = if let (ty::AssocKind::Fn, Some(args)) = (kind, args) {
1411 if rcvr_ty.is_region_ptr() {
1412 if rcvr_ty.is_mutable_ptr() { "&mut " } else { "&" }
1417 .map(|arg| source_map.span_to_snippet(arg.span).unwrap_or_else(|_| {
1418 applicability = Applicability::HasPlaceholders;
1421 .collect::<Vec<_>>()
1427 let sugg = format!("{}::{}{}", trait_name, item_name, sugg_args);
1428 err.span_suggestion(
1431 "disambiguate the {} for {}",
1432 kind.as_def_kind().descr(def_id),
1433 if let Some(candidate) = candidate {
1434 format!("candidate #{}", candidate)
1436 "the candidate".to_string()