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 // We need to move `tcx` while only borrowing the rest,
576 // this is kind of ugly.
577 |self_ty: Ty<'tcx>, parent_pred: &ty::Predicate<'tcx>, obligation: &str| {
578 // We don't care about regions here, so it's fine to skip the binder here.
579 if let (ty::Param(_), ty::PredicateKind::Trait(p, _)) = (
581 parent_pred.ignore_quantifiers().skip_binder().kind(),
583 if let ty::Adt(def, _) = p.trait_ref.self_ty().kind {
584 let node = def.did.as_local().map(|def_id| {
585 self.tcx.hir().get(self.tcx.hir().as_local_hir_id(def_id))
587 if let Some(hir::Node::Item(hir::Item { kind, .. })) = node {
588 if let Some(g) = kind.generics() {
589 let key = match &g.where_clause.predicates[..] {
590 [.., pred] => (pred.span().shrink_to_hi(), false),
593 .span_for_predicates_or_empty_place(),
599 .or_insert_with(FxHashSet::default)
600 .insert(obligation.to_owned());
607 let mut bound_span_label = |self_ty: Ty<'_>, obligation: &str, quiet: &str| {
609 "doesn't satisfy `{}`",
610 if obligation.len() > 50 { quiet } else { obligation }
612 match &self_ty.kind {
613 // Point at the type that couldn't satisfy the bound.
614 ty::Adt(def, _) => bound_spans.push((def_span(def.did), msg)),
615 // Point at the trait object that couldn't satisfy the bound.
616 ty::Dynamic(preds, _) => {
617 for pred in preds.skip_binder() {
619 ty::ExistentialPredicate::Trait(tr) => {
620 bound_spans.push((def_span(tr.def_id), msg.clone()))
622 ty::ExistentialPredicate::Projection(_)
623 | ty::ExistentialPredicate::AutoTrait(_) => {}
627 // Point at the closure that couldn't satisfy the bound.
628 ty::Closure(def_id, _) => bound_spans
629 .push((def_span(*def_id), format!("doesn't satisfy `{}`", quiet))),
633 let mut format_pred = |pred: ty::Predicate<'tcx>| {
634 match pred.ignore_quantifiers().skip_binder().kind() {
635 &ty::PredicateKind::Projection(pred) => {
636 let pred = ty::Binder::bind(pred);
637 // `<Foo as Iterator>::Item = String`.
639 pred.skip_binder().projection_ty.trait_ref(self.tcx);
642 .associated_item(pred.skip_binder().projection_ty.item_def_id);
643 let ty = pred.skip_binder().ty;
644 let obligation = format!("{}::{} = {}", trait_ref, assoc.ident, ty);
646 "<_ as {}>::{} = {}",
647 trait_ref.print_only_trait_path(),
651 bound_span_label(trait_ref.self_ty(), &obligation, &quiet);
652 Some((obligation, trait_ref.self_ty()))
654 &ty::PredicateKind::Trait(poly_trait_ref, _) => {
655 let poly_trait_ref = ty::Binder::bind(poly_trait_ref);
656 let p = poly_trait_ref.skip_binder().trait_ref;
657 let self_ty = p.self_ty();
658 let path = p.print_only_trait_path();
659 let obligation = format!("{}: {}", self_ty, path);
660 let quiet = format!("_: {}", path);
661 bound_span_label(self_ty, &obligation, &quiet);
662 Some((obligation, self_ty))
667 let mut bound_list = unsatisfied_predicates
669 .filter_map(|(pred, parent_pred)| {
670 format_pred(*pred).map(|(p, self_ty)| match parent_pred {
671 None => format!("`{}`", p),
672 Some(parent_pred) => match format_pred(*parent_pred) {
673 None => format!("`{}`", p),
674 Some((parent_p, _)) => {
675 collect_type_param_suggestions(self_ty, parent_pred, &p);
676 format!("`{}`\nwhich is required by `{}`", p, parent_p)
682 .collect::<Vec<(usize, String)>>();
683 for ((span, empty_where), obligations) in type_params.into_iter() {
684 restrict_type_params = true;
685 err.span_suggestion_verbose(
688 "consider restricting the type parameter{s} to satisfy the \
690 s = pluralize!(obligations.len())
694 if empty_where { " where" } else { "," },
695 obligations.into_iter().collect::<Vec<_>>().join(", ")
697 Applicability::MaybeIncorrect,
701 bound_list.sort_by(|(_, a), (_, b)| a.cmp(&b)); // Sort alphabetically.
702 bound_list.dedup_by(|(_, a), (_, b)| a == b); // #35677
703 bound_list.sort_by_key(|(pos, _)| *pos); // Keep the original predicate order.
706 for (span, msg) in bound_spans.into_iter() {
707 err.span_label(span, &msg);
709 if !bound_list.is_empty() {
710 let bound_list = bound_list
712 .map(|(_, path)| path)
716 "the method `{}` exists but the following trait bounds were not \
718 item_name, bound_list
723 if actual.is_numeric() && actual.is_fresh() || restrict_type_params {
725 self.suggest_traits_to_import(
732 &unsatisfied_predicates,
736 if actual.is_enum() {
737 let adt_def = actual.ty_adt_def().expect("enum is not an ADT");
738 if let Some(suggestion) = lev_distance::find_best_match_for_name(
739 adt_def.variants.iter().map(|s| &s.ident.name),
745 "there is a variant with a similar name",
746 suggestion.to_string(),
747 Applicability::MaybeIncorrect,
752 let mut fallback_span = true;
753 let msg = "remove this method call";
754 if item_name.name == sym::as_str && actual.peel_refs().is_str() {
755 if let SelfSource::MethodCall(expr) = source {
757 self.tcx.hir().expect_expr(self.tcx.hir().get_parent_node(expr.hir_id));
758 if let Some(span) = call_expr.span.trim_start(expr.span) {
763 Applicability::MachineApplicable,
765 fallback_span = false;
769 err.span_label(span, msg);
771 } else if let Some(lev_candidate) = lev_candidate {
772 let def_kind = lev_candidate.kind.as_def_kind();
776 "there is {} {} with a similar name",
778 def_kind.descr(lev_candidate.def_id),
780 lev_candidate.ident.to_string(),
781 Applicability::MaybeIncorrect,
788 MethodError::Ambiguity(sources) => {
789 let mut err = struct_span_err!(
793 "multiple applicable items in scope"
795 err.span_label(item_name.span, format!("multiple `{}` found", item_name));
797 report_candidates(span, &mut err, sources, sugg_span);
801 MethodError::PrivateMatch(kind, def_id, out_of_scope_traits) => {
802 let kind = kind.descr(def_id);
803 let mut err = struct_span_err!(
807 "{} `{}` is private",
811 err.span_label(item_name.span, &format!("private {}", kind));
812 self.suggest_valid_traits(&mut err, out_of_scope_traits);
816 MethodError::IllegalSizedBound(candidates, needs_mut, bound_span) => {
817 let msg = format!("the `{}` method cannot be invoked on a trait object", item_name);
818 let mut err = self.sess().struct_span_err(span, &msg);
819 err.span_label(bound_span, "this has a `Sized` requirement");
820 if !candidates.is_empty() {
822 "{an}other candidate{s} {were} found in the following trait{s}, perhaps \
823 add a `use` for {one_of_them}:",
824 an = if candidates.len() == 1 { "an" } else { "" },
825 s = pluralize!(candidates.len()),
826 were = if candidates.len() == 1 { "was" } else { "were" },
827 one_of_them = if candidates.len() == 1 { "it" } else { "one_of_them" },
829 self.suggest_use_candidates(&mut err, help, candidates);
831 if let ty::Ref(region, t_type, mutability) = rcvr_ty.kind {
833 let trait_type = self.tcx.mk_ref(
835 ty::TypeAndMut { ty: t_type, mutbl: mutability.invert() },
837 err.note(&format!("you need `{}` instead of `{}`", trait_type, rcvr_ty));
843 MethodError::BadReturnType => bug!("no return type expectations but got BadReturnType"),
848 /// Print out the type for use in value namespace.
849 fn ty_to_value_string(&self, ty: Ty<'tcx>) -> String {
851 ty::Adt(def, substs) => format!("{}", ty::Instance::new(def.did, substs)),
852 _ => self.ty_to_string(ty),
856 fn suggest_use_candidates(
858 err: &mut DiagnosticBuilder<'_>,
860 candidates: Vec<DefId>,
862 let module_did = self.tcx.parent_module(self.body_id);
863 let module_id = self.tcx.hir().as_local_hir_id(module_did);
864 let krate = self.tcx.hir().krate();
865 let (span, found_use) = UsePlacementFinder::check(self.tcx, krate, module_id);
866 if let Some(span) = span {
867 let path_strings = candidates.iter().map(|did| {
868 // Produce an additional newline to separate the new use statement
869 // from the directly following item.
870 let additional_newline = if found_use { "" } else { "\n" };
873 with_crate_prefix(|| self.tcx.def_path_str(*did)),
878 err.span_suggestions(span, &msg, path_strings, Applicability::MaybeIncorrect);
880 let limit = if candidates.len() == 5 { 5 } else { 4 };
881 for (i, trait_did) in candidates.iter().take(limit).enumerate() {
882 if candidates.len() > 1 {
883 msg.push_str(&format!(
884 "\ncandidate #{}: `use {};`",
886 with_crate_prefix(|| self.tcx.def_path_str(*trait_did))
889 msg.push_str(&format!(
891 with_crate_prefix(|| self.tcx.def_path_str(*trait_did))
895 if candidates.len() > limit {
896 msg.push_str(&format!("\nand {} others", candidates.len() - limit));
902 fn suggest_valid_traits(
904 err: &mut DiagnosticBuilder<'_>,
905 valid_out_of_scope_traits: Vec<DefId>,
907 if !valid_out_of_scope_traits.is_empty() {
908 let mut candidates = valid_out_of_scope_traits;
911 err.help("items from traits can only be used if the trait is in scope");
913 "the following {traits_are} implemented but not in scope; \
914 perhaps add a `use` for {one_of_them}:",
915 traits_are = if candidates.len() == 1 { "trait is" } else { "traits are" },
916 one_of_them = if candidates.len() == 1 { "it" } else { "one of them" },
919 self.suggest_use_candidates(err, msg, candidates);
926 fn suggest_traits_to_import<'b>(
928 err: &mut DiagnosticBuilder<'_>,
932 source: SelfSource<'b>,
933 valid_out_of_scope_traits: Vec<DefId>,
934 unsatisfied_predicates: &[(ty::Predicate<'tcx>, Option<ty::Predicate<'tcx>>)],
936 if self.suggest_valid_traits(err, valid_out_of_scope_traits) {
940 let type_is_local = self.type_derefs_to_local(span, rcvr_ty, source);
942 let mut arbitrary_rcvr = vec![];
943 // There are no traits implemented, so lets suggest some traits to
944 // implement, by finding ones that have the item name, and are
945 // legal to implement.
946 let mut candidates = all_traits(self.tcx)
948 // Don't issue suggestions for unstable traits since they're
949 // unlikely to be implementable anyway
950 .filter(|info| match self.tcx.lookup_stability(info.def_id) {
951 Some(attr) => attr.level.is_stable(),
955 // We approximate the coherence rules to only suggest
956 // traits that are legal to implement by requiring that
957 // either the type or trait is local. Multi-dispatch means
958 // this isn't perfect (that is, there are cases when
959 // implementing a trait would be legal but is rejected
961 unsatisfied_predicates.iter().all(|(p, _)| {
962 match p.ignore_quantifiers().skip_binder().kind() {
963 // Hide traits if they are present in predicates as they can be fixed without
964 // having to implement them.
965 ty::PredicateKind::Trait(t, _) => t.def_id() == info.def_id,
966 ty::PredicateKind::Projection(p) => {
967 p.projection_ty.item_def_id == info.def_id
971 }) && (type_is_local || info.def_id.is_local())
973 .associated_item(info.def_id, item_name, Namespace::ValueNS)
975 if let ty::AssocKind::Fn = item.kind {
979 .map(|def_id| self.tcx.hir().as_local_hir_id(def_id));
980 if let Some(hir::Node::TraitItem(hir::TraitItem {
981 kind: hir::TraitItemKind::Fn(fn_sig, method),
983 })) = id.map(|id| self.tcx.hir().get(id))
985 let self_first_arg = match method {
986 hir::TraitFn::Required([ident, ..]) => {
987 ident.name == kw::SelfLower
989 hir::TraitFn::Provided(body_id) => {
990 self.tcx.hir().body(*body_id).params.first().map_or(
995 hir::PatKind::Binding(_, _, ident, _)
996 if ident.name == kw::SelfLower
1004 if !fn_sig.decl.implicit_self.has_implicit_self()
1007 if let Some(ty) = fn_sig.decl.inputs.get(0) {
1008 arbitrary_rcvr.push(ty.span);
1014 // We only want to suggest public or local traits (#45781).
1015 item.vis == ty::Visibility::Public || info.def_id.is_local()
1019 .collect::<Vec<_>>();
1020 for span in &arbitrary_rcvr {
1023 "the method might not be found because of this arbitrary self type",
1027 if !candidates.is_empty() {
1028 // Sort from most relevant to least relevant.
1029 candidates.sort_by(|a, b| a.cmp(b).reverse());
1032 let param_type = match rcvr_ty.kind {
1033 ty::Param(param) => Some(param),
1034 ty::Ref(_, ty, _) => match ty.kind {
1035 ty::Param(param) => Some(param),
1040 err.help(if param_type.is_some() {
1041 "items from traits can only be used if the type parameter is bounded by the trait"
1043 "items from traits can only be used if the trait is implemented and in scope"
1045 let message = |action| {
1047 "the following {traits_define} an item `{name}`, perhaps you need to {action} \
1050 if candidates.len() == 1 { "trait defines" } else { "traits define" },
1052 one_of_them = if candidates.len() == 1 { "it" } else { "one of them" },
1056 // Obtain the span for `param` and use it for a structured suggestion.
1057 let mut suggested = false;
1058 if let (Some(ref param), Some(ref table)) =
1059 (param_type, self.in_progress_typeck_results)
1061 let table_owner = table.borrow().hir_owner;
1062 let generics = self.tcx.generics_of(table_owner.to_def_id());
1063 let type_param = generics.type_param(param, self.tcx);
1064 let hir = &self.tcx.hir();
1065 if let Some(def_id) = type_param.def_id.as_local() {
1066 let id = hir.as_local_hir_id(def_id);
1067 // Get the `hir::Param` to verify whether it already has any bounds.
1068 // We do this to avoid suggesting code that ends up as `T: FooBar`,
1069 // instead we suggest `T: Foo + Bar` in that case.
1071 Node::GenericParam(ref param) => {
1072 let mut impl_trait = false;
1074 if let hir::GenericParamKind::Type { synthetic: Some(_), .. } =
1077 // We've found `fn foo(x: impl Trait)` instead of
1078 // `fn foo<T>(x: T)`. We want to suggest the correct
1079 // `fn foo(x: impl Trait + TraitBound)` instead of
1080 // `fn foo<T: TraitBound>(x: T)`. (#63706)
1086 let sp = hir.span(id);
1087 let sp = if let Some(first_bound) = has_bounds {
1088 // `sp` only covers `T`, change it so that it covers
1089 // `T:` when appropriate
1090 sp.until(first_bound.span())
1094 let trait_def_ids: FxHashSet<DefId> = param
1097 .filter_map(|bound| Some(bound.trait_ref()?.trait_def_id()?))
1099 if !candidates.iter().any(|t| trait_def_ids.contains(&t.def_id)) {
1100 err.span_suggestions(
1103 "restrict type parameter `{}` with",
1106 candidates.iter().map(|t| {
1110 if impl_trait { " +" } else { ":" },
1111 self.tcx.def_path_str(t.def_id),
1112 if has_bounds.is_some() { " + " } else { "" },
1115 Applicability::MaybeIncorrect,
1120 Node::Item(hir::Item {
1121 kind: hir::ItemKind::Trait(.., bounds, _),
1125 let (sp, sep, article) = if bounds.is_empty() {
1126 (ident.span.shrink_to_hi(), ":", "a")
1128 (bounds.last().unwrap().span().shrink_to_hi(), " +", "another")
1130 err.span_suggestions(
1132 &message(format!("add {} supertrait for", article)),
1133 candidates.iter().map(|t| {
1134 format!("{} {}", sep, self.tcx.def_path_str(t.def_id),)
1136 Applicability::MaybeIncorrect,
1146 let action = if let Some(param) = param_type {
1147 format!("restrict type parameter `{}` with", param)
1149 // FIXME: it might only need to be imported into scope, not implemented.
1150 "implement".to_string()
1152 let mut use_note = true;
1153 if let [trait_info] = &candidates[..] {
1154 if let Some(span) = self.tcx.hir().span_if_local(trait_info.def_id) {
1156 self.tcx.sess.source_map().guess_head_span(span),
1158 "`{}` defines an item `{}`, perhaps you need to {} it",
1159 self.tcx.def_path_str(trait_info.def_id),
1168 let mut msg = message(action);
1169 for (i, trait_info) in candidates.iter().enumerate() {
1170 msg.push_str(&format!(
1171 "\ncandidate #{}: `{}`",
1173 self.tcx.def_path_str(trait_info.def_id),
1182 /// Checks whether there is a local type somewhere in the chain of
1183 /// autoderefs of `rcvr_ty`.
1184 fn type_derefs_to_local(&self, span: Span, rcvr_ty: Ty<'tcx>, source: SelfSource<'_>) -> bool {
1185 fn is_local(ty: Ty<'_>) -> bool {
1187 ty::Adt(def, _) => def.did.is_local(),
1188 ty::Foreign(did) => did.is_local(),
1190 ty::Dynamic(ref tr, ..) => {
1191 tr.principal().map(|d| d.def_id().is_local()).unwrap_or(false)
1194 ty::Param(_) => true,
1196 // Everything else (primitive types, etc.) is effectively
1197 // non-local (there are "edge" cases, e.g., `(LocalType,)`, but
1198 // the noise from these sort of types is usually just really
1199 // annoying, rather than any sort of help).
1204 // This occurs for UFCS desugaring of `T::method`, where there is no
1205 // receiver expression for the method call, and thus no autoderef.
1206 if let SelfSource::QPath(_) = source {
1207 return is_local(self.resolve_vars_with_obligations(rcvr_ty));
1210 self.autoderef(span, rcvr_ty).any(|(ty, _)| is_local(ty))
1214 #[derive(Copy, Clone)]
1215 pub enum SelfSource<'a> {
1216 QPath(&'a hir::Ty<'a>),
1217 MethodCall(&'a hir::Expr<'a> /* rcvr */),
1220 #[derive(Copy, Clone)]
1221 pub struct TraitInfo {
1225 impl PartialEq for TraitInfo {
1226 fn eq(&self, other: &TraitInfo) -> bool {
1227 self.cmp(other) == Ordering::Equal
1230 impl Eq for TraitInfo {}
1231 impl PartialOrd for TraitInfo {
1232 fn partial_cmp(&self, other: &TraitInfo) -> Option<Ordering> {
1233 Some(self.cmp(other))
1236 impl Ord for TraitInfo {
1237 fn cmp(&self, other: &TraitInfo) -> Ordering {
1238 // Local crates are more important than remote ones (local:
1239 // `cnum == 0`), and otherwise we throw in the defid for totality.
1241 let lhs = (other.def_id.krate, other.def_id);
1242 let rhs = (self.def_id.krate, self.def_id);
1247 /// Retrieves all traits in this crate and any dependent crates.
1248 pub fn all_traits(tcx: TyCtxt<'_>) -> Vec<TraitInfo> {
1249 tcx.all_traits(LOCAL_CRATE).iter().map(|&def_id| TraitInfo { def_id }).collect()
1252 /// Computes all traits in this crate and any dependent crates.
1253 fn compute_all_traits(tcx: TyCtxt<'_>) -> Vec<DefId> {
1254 use hir::itemlikevisit;
1256 let mut traits = vec![];
1260 struct Visitor<'a, 'tcx> {
1261 map: &'a hir_map::Map<'tcx>,
1262 traits: &'a mut Vec<DefId>,
1265 impl<'v, 'a, 'tcx> itemlikevisit::ItemLikeVisitor<'v> for Visitor<'a, 'tcx> {
1266 fn visit_item(&mut self, i: &'v hir::Item<'v>) {
1268 hir::ItemKind::Trait(..) | hir::ItemKind::TraitAlias(..) => {
1269 let def_id = self.map.local_def_id(i.hir_id);
1270 self.traits.push(def_id.to_def_id());
1276 fn visit_trait_item(&mut self, _trait_item: &hir::TraitItem<'_>) {}
1278 fn visit_impl_item(&mut self, _impl_item: &hir::ImplItem<'_>) {}
1281 tcx.hir().krate().visit_all_item_likes(&mut Visitor { map: &tcx.hir(), traits: &mut traits });
1285 let mut external_mods = FxHashSet::default();
1286 fn handle_external_res(
1288 traits: &mut Vec<DefId>,
1289 external_mods: &mut FxHashSet<DefId>,
1293 Res::Def(DefKind::Trait | DefKind::TraitAlias, def_id) => {
1294 traits.push(def_id);
1296 Res::Def(DefKind::Mod, def_id) => {
1297 if !external_mods.insert(def_id) {
1300 for child in tcx.item_children(def_id).iter() {
1301 handle_external_res(tcx, traits, external_mods, child.res)
1307 for &cnum in tcx.crates().iter() {
1308 let def_id = DefId { krate: cnum, index: CRATE_DEF_INDEX };
1309 handle_external_res(tcx, &mut traits, &mut external_mods, Res::Def(DefKind::Mod, def_id));
1315 pub fn provide(providers: &mut ty::query::Providers) {
1316 providers.all_traits = |tcx, cnum| {
1317 assert_eq!(cnum, LOCAL_CRATE);
1318 &tcx.arena.alloc(compute_all_traits(tcx))[..]
1322 struct UsePlacementFinder<'tcx> {
1323 target_module: hir::HirId,
1329 impl UsePlacementFinder<'tcx> {
1332 krate: &'tcx hir::Crate<'tcx>,
1333 target_module: hir::HirId,
1334 ) -> (Option<Span>, bool) {
1335 let mut finder = UsePlacementFinder { target_module, span: None, found_use: false, tcx };
1336 intravisit::walk_crate(&mut finder, krate);
1337 (finder.span, finder.found_use)
1341 impl intravisit::Visitor<'tcx> for UsePlacementFinder<'tcx> {
1342 fn visit_mod(&mut self, module: &'tcx hir::Mod<'tcx>, _: Span, hir_id: hir::HirId) {
1343 if self.span.is_some() {
1346 if hir_id != self.target_module {
1347 intravisit::walk_mod(self, module, hir_id);
1350 // Find a `use` statement.
1351 for item_id in module.item_ids {
1352 let item = self.tcx.hir().expect_item(item_id.id);
1354 hir::ItemKind::Use(..) => {
1355 // Don't suggest placing a `use` before the prelude
1356 // import or other generated ones.
1357 if !item.span.from_expansion() {
1358 self.span = Some(item.span.shrink_to_lo());
1359 self.found_use = true;
1363 // Don't place `use` before `extern crate`...
1364 hir::ItemKind::ExternCrate(_) => {}
1365 // ...but do place them before the first other item.
1367 if self.span.map_or(true, |span| item.span < span) {
1368 if !item.span.from_expansion() {
1369 // Don't insert between attributes and an item.
1370 if item.attrs.is_empty() {
1371 self.span = Some(item.span.shrink_to_lo());
1373 // Find the first attribute on the item.
1374 for attr in item.attrs {
1375 if self.span.map_or(true, |span| attr.span < span) {
1376 self.span = Some(attr.span.shrink_to_lo());
1387 type Map = intravisit::ErasedMap<'tcx>;
1389 fn nested_visit_map(&mut self) -> intravisit::NestedVisitorMap<Self::Map> {
1390 intravisit::NestedVisitorMap::None
1394 fn print_disambiguation_help(
1396 args: Option<&'tcx [hir::Expr<'tcx>]>,
1397 err: &mut DiagnosticBuilder<'_>,
1400 kind: ty::AssocKind,
1403 candidate: Option<usize>,
1404 source_map: &source_map::SourceMap,
1406 let mut applicability = Applicability::MachineApplicable;
1407 let sugg_args = if let (ty::AssocKind::Fn, Some(args)) = (kind, args) {
1410 if rcvr_ty.is_region_ptr() {
1411 if rcvr_ty.is_mutable_ptr() { "&mut " } else { "&" }
1416 .map(|arg| source_map.span_to_snippet(arg.span).unwrap_or_else(|_| {
1417 applicability = Applicability::HasPlaceholders;
1420 .collect::<Vec<_>>()
1426 let sugg = format!("{}::{}{}", trait_name, item_name, sugg_args);
1427 err.span_suggestion(
1430 "disambiguate the {} for {}",
1431 kind.as_def_kind().descr(def_id),
1432 if let Some(candidate) = candidate {
1433 format!("candidate #{}", candidate)
1435 "the candidate".to_string()