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, 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(),
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 {
162 | ty::AssocKind::Type
163 | ty::AssocKind::OpaqueTy => rcvr_ty,
164 ty::AssocKind::Fn => self
170 .filter(|ty| ty.is_region_ptr() && !rcvr_ty.is_region_ptr())
174 print_disambiguation_help(
184 self.tcx.sess.source_map(),
188 CandidateSource::TraitSource(trait_did) => {
190 match self.associated_item(trait_did, item_name, Namespace::ValueNS) {
198 .guess_head_span(self.tcx.def_span(item.def_id));
199 let idx = if sources.len() > 1 {
201 "candidate #{} is defined in the trait `{}`",
203 self.tcx.def_path_str(trait_did)
205 err.span_note(item_span, msg);
209 "the candidate is defined in the trait `{}`",
210 self.tcx.def_path_str(trait_did)
212 err.span_note(item_span, msg);
215 let path = self.tcx.def_path_str(trait_did);
216 print_disambiguation_help(
226 self.tcx.sess.source_map(),
231 if sources.len() > limit {
232 err.note(&format!("and {} others", sources.len() - limit));
236 let sugg_span = if let SelfSource::MethodCall(expr) = source {
237 // Given `foo.bar(baz)`, `expr` is `bar`, but we want to point to the whole thing.
238 self.tcx.hir().expect_expr(self.tcx.hir().get_parent_node(expr.hir_id)).span
244 MethodError::NoMatch(NoMatchData {
245 static_candidates: static_sources,
246 unsatisfied_predicates,
253 let actual = self.resolve_vars_if_possible(&rcvr_ty);
254 let ty_str = self.ty_to_string(actual);
255 let is_method = mode == Mode::MethodCall;
256 let item_kind = if is_method {
258 } else if actual.is_enum() {
259 "variant or associated item"
261 match (item_name.as_str().chars().next(), actual.is_fresh_ty()) {
262 (Some(name), false) if name.is_lowercase() => "function or associated item",
263 (Some(_), false) => "associated item",
264 (Some(_), true) | (None, false) => "variant or associated item",
265 (None, true) => "variant",
268 let mut err = if !actual.references_error() {
269 // Suggest clamping down the type if the method that is being attempted to
270 // be used exists at all, and the type is an ambiguous numeric type
271 // ({integer}/{float}).
272 let mut candidates = all_traits(self.tcx).into_iter().filter_map(|info| {
273 self.associated_item(info.def_id, item_name, Namespace::ValueNS)
275 // There are methods that are defined on the primitive types and won't be
276 // found when exploring `all_traits`, but we also need them to be acurate on
277 // our suggestions (#47759).
278 let fund_assoc = |opt_def_id: Option<DefId>| {
280 .and_then(|id| self.associated_item(id, item_name, Namespace::ValueNS))
283 let lang_items = tcx.lang_items();
284 let found_candidate = candidates.next().is_some()
285 || fund_assoc(lang_items.i8_impl())
286 || fund_assoc(lang_items.i16_impl())
287 || fund_assoc(lang_items.i32_impl())
288 || fund_assoc(lang_items.i64_impl())
289 || fund_assoc(lang_items.i128_impl())
290 || fund_assoc(lang_items.u8_impl())
291 || fund_assoc(lang_items.u16_impl())
292 || fund_assoc(lang_items.u32_impl())
293 || fund_assoc(lang_items.u64_impl())
294 || fund_assoc(lang_items.u128_impl())
295 || fund_assoc(lang_items.f32_impl())
296 || fund_assoc(lang_items.f32_runtime_impl())
297 || fund_assoc(lang_items.f64_impl())
298 || fund_assoc(lang_items.f64_runtime_impl());
299 if let (true, false, SelfSource::MethodCall(expr), true) = (
301 actual.has_concrete_skeleton(),
305 let mut err = struct_span_err!(
309 "can't call {} `{}` on ambiguous numeric type `{}`",
314 let concrete_type = if actual.is_integral() { "i32" } else { "f32" };
316 ExprKind::Lit(ref lit) => {
321 .span_to_snippet(lit.span)
322 .unwrap_or_else(|_| "<numeric literal>".to_owned());
327 "you must specify a concrete type for \
328 this numeric value, like `{}`",
331 format!("{}_{}", snippet, concrete_type),
332 Applicability::MaybeIncorrect,
335 ExprKind::Path(ref qpath) => {
337 if let &QPath::Resolved(_, ref path) = &qpath {
338 if let hir::def::Res::Local(hir_id) = path.res {
339 let span = tcx.hir().span(hir_id);
340 let snippet = tcx.sess.source_map().span_to_snippet(span);
341 let filename = tcx.sess.source_map().span_to_filename(span);
343 let parent_node = self
346 .get(self.tcx.hir().get_parent_node(hir_id));
348 "you must specify a type for this binding, like `{}`",
352 match (filename, parent_node, snippet) {
355 Node::Local(hir::Local {
356 source: hir::LocalSource::Normal,
363 // account for `let x: _ = 42;`
370 format!("{}: {}", snippet, concrete_type),
371 Applicability::MaybeIncorrect,
375 err.span_label(span, msg);
386 span = item_name.span;
387 let mut err = struct_span_err!(
391 "no {} named `{}` found for {} `{}` in the current scope",
394 actual.prefix_string(),
398 tcx.sess.confused_type_with_std_module.borrow().get(&span)
400 if let Ok(snippet) = tcx.sess.source_map().span_to_snippet(*span) {
403 "you are looking for the module in `std`, \
404 not the primitive type",
405 format!("std::{}", snippet),
406 Applicability::MachineApplicable,
410 if let ty::RawPtr(_) = &actual.kind {
412 "try using `<*const T>::as_ref()` to get a reference to the \
413 type behind the pointer: https://doc.rust-lang.org/std/\
414 primitive.pointer.html#method.as_ref",
417 "using `<*const T>::as_ref()` on a pointer \
418 which is unaligned or points to invalid \
419 or uninitialized memory is undefined behavior",
425 tcx.sess.diagnostic().struct_dummy()
428 if let Some(def) = actual.ty_adt_def() {
429 if let Some(full_sp) = tcx.hir().span_if_local(def.did) {
430 let def_sp = tcx.sess.source_map().guess_head_span(full_sp);
434 "{} `{}` not found {}",
437 if def.is_enum() && !is_method { "here" } else { "for this" }
443 // If the method name is the name of a field with a function or closure type,
444 // give a helping note that it has to be called as `(x.f)(...)`.
445 if let SelfSource::MethodCall(expr) = source {
447 self.autoderef(span, rcvr_ty).find_map(|(ty, _)| match ty.kind {
448 ty::Adt(def, substs) if !def.is_enum() => {
449 let variant = &def.non_enum_variant();
450 self.tcx.find_field_index(item_name, variant).map(|index| {
451 let field = &variant.fields[index];
452 let field_ty = field.ty(tcx, substs);
459 if let Some((field, field_ty)) = field_receiver {
460 let scope = self.tcx.parent_module(self.body_id).to_def_id();
461 let is_accessible = field.vis.is_accessible_from(scope, self.tcx);
464 if self.is_fn_ty(&field_ty, span) {
465 let expr_span = expr.span.to(item_name.span);
466 err.multipart_suggestion(
468 "to call the function stored in `{}`, \
469 surround the field access with parentheses",
473 (expr_span.shrink_to_lo(), '('.to_string()),
474 (expr_span.shrink_to_hi(), ')'.to_string()),
476 Applicability::MachineApplicable,
482 .expect_expr(self.tcx.hir().get_parent_node(expr.hir_id));
484 if let Some(span) = call_expr.span.trim_start(item_name.span) {
487 "remove the arguments",
489 Applicability::MaybeIncorrect,
495 let field_kind = if is_accessible { "field" } else { "private field" };
496 err.span_label(item_name.span, format!("{}, not a method", field_kind));
497 } else if lev_candidate.is_none() && static_sources.is_empty() {
498 err.span_label(span, format!("{} not found in `{}`", item_kind, ty_str));
499 self.tcx.sess.trait_methods_not_found.borrow_mut().insert(orig_span);
502 err.span_label(span, format!("{} not found in `{}`", item_kind, ty_str));
503 self.tcx.sess.trait_methods_not_found.borrow_mut().insert(orig_span);
506 if self.is_fn_ty(&rcvr_ty, span) {
507 macro_rules! report_function {
508 ($span:expr, $name:expr) => {
510 "`{}` is a function, perhaps you wish to call it",
516 if let SelfSource::MethodCall(expr) = source {
517 if let Ok(expr_string) = tcx.sess.source_map().span_to_snippet(expr.span) {
518 report_function!(expr.span, expr_string);
519 } else if let ExprKind::Path(QPath::Resolved(_, ref path)) = expr.kind {
520 if let Some(segment) = path.segments.last() {
521 report_function!(expr.span, segment.ident);
527 if !static_sources.is_empty() {
529 "found the following associated functions; to be used as methods, \
530 functions must have a `self` parameter",
532 err.span_label(span, "this is an associated function, not a method");
534 if static_sources.len() == 1 {
535 let ty_str = if let Some(CandidateSource::ImplSource(impl_did)) =
536 static_sources.get(0)
538 // When the "method" is resolved through dereferencing, we really want the
539 // original type that has the associated function for accurate suggestions.
541 let ty = tcx.at(span).type_of(*impl_did);
542 match (&ty.peel_refs().kind, &actual.peel_refs().kind) {
543 (ty::Adt(def, _), ty::Adt(def_actual, _)) if def == def_actual => {
544 // Use `actual` as it will have more `substs` filled in.
545 self.ty_to_value_string(actual.peel_refs())
547 _ => self.ty_to_value_string(ty.peel_refs()),
550 self.ty_to_value_string(actual.peel_refs())
552 if let SelfSource::MethodCall(expr) = source {
555 "use associated function syntax instead",
556 format!("{}::{}", ty_str, item_name),
557 Applicability::MachineApplicable,
560 err.help(&format!("try with `{}::{}`", ty_str, item_name,));
563 report_candidates(span, &mut err, static_sources, sugg_span);
564 } else if static_sources.len() > 1 {
565 report_candidates(span, &mut err, static_sources, sugg_span);
568 let mut restrict_type_params = false;
569 if !unsatisfied_predicates.is_empty() {
570 let def_span = |def_id| {
571 self.tcx.sess.source_map().guess_head_span(self.tcx.def_span(def_id))
573 let mut type_params = FxHashMap::default();
574 let mut bound_spans = vec![];
575 let mut collect_type_param_suggestions =
576 |self_ty: Ty<'_>, parent_pred: &ty::Predicate<'_>, obligation: &str| {
577 if let (ty::Param(_), ty::PredicateKind::Trait(p, _)) =
578 (&self_ty.kind, parent_pred)
580 if let ty::Adt(def, _) = p.skip_binder().trait_ref.self_ty().kind {
581 let node = def.did.as_local().map(|def_id| {
582 self.tcx.hir().get(self.tcx.hir().as_local_hir_id(def_id))
584 if let Some(hir::Node::Item(hir::Item { kind, .. })) = node {
585 if let Some(g) = kind.generics() {
586 let key = match &g.where_clause.predicates[..] {
587 [.., pred] => (pred.span().shrink_to_hi(), false),
590 .span_for_predicates_or_empty_place(),
596 .or_insert_with(FxHashSet::default)
597 .insert(obligation.to_owned());
603 let mut bound_span_label = |self_ty: Ty<'_>, obligation: &str, quiet: &str| {
605 "doesn't satisfy `{}`",
606 if obligation.len() > 50 { quiet } else { obligation }
608 match &self_ty.kind {
609 // Point at the type that couldn't satisfy the bound.
610 ty::Adt(def, _) => bound_spans.push((def_span(def.did), msg)),
611 // Point at the trait object that couldn't satisfy the bound.
612 ty::Dynamic(preds, _) => {
613 for pred in *preds.skip_binder() {
615 ty::ExistentialPredicate::Trait(tr) => {
616 bound_spans.push((def_span(tr.def_id), msg.clone()))
618 ty::ExistentialPredicate::Projection(_)
619 | ty::ExistentialPredicate::AutoTrait(_) => {}
623 // Point at the closure that couldn't satisfy the bound.
624 ty::Closure(def_id, _) => bound_spans
625 .push((def_span(*def_id), format!("doesn't satisfy `{}`", quiet))),
629 let mut format_pred = |pred| {
631 ty::PredicateKind::Projection(pred) => {
632 // `<Foo as Iterator>::Item = String`.
634 pred.skip_binder().projection_ty.trait_ref(self.tcx);
637 .associated_item(pred.skip_binder().projection_ty.item_def_id);
638 let ty = pred.skip_binder().ty;
639 let obligation = format!("{}::{} = {}", trait_ref, assoc.ident, ty);
641 "<_ as {}>::{} = {}",
642 trait_ref.print_only_trait_path(),
646 bound_span_label(trait_ref.self_ty(), &obligation, &quiet);
647 Some((obligation, trait_ref.self_ty()))
649 ty::PredicateKind::Trait(poly_trait_ref, _) => {
650 let p = poly_trait_ref.skip_binder().trait_ref;
651 let self_ty = p.self_ty();
652 let path = p.print_only_trait_path();
653 let obligation = format!("{}: {}", self_ty, path);
654 let quiet = format!("_: {}", path);
655 bound_span_label(self_ty, &obligation, &quiet);
656 Some((obligation, self_ty))
661 let mut bound_list = unsatisfied_predicates
663 .filter_map(|(pred, parent_pred)| {
664 format_pred(*pred).map(|(p, self_ty)| match parent_pred {
665 None => format!("`{}`", p),
666 Some(parent_pred) => match format_pred(*parent_pred) {
667 None => format!("`{}`", p),
668 Some((parent_p, _)) => {
669 collect_type_param_suggestions(self_ty, parent_pred, &p);
670 format!("`{}`\nwhich is required by `{}`", p, parent_p)
676 .collect::<Vec<(usize, String)>>();
677 for ((span, empty_where), obligations) in type_params.into_iter() {
678 restrict_type_params = true;
679 err.span_suggestion_verbose(
682 "consider restricting the type parameter{s} to satisfy the \
684 s = pluralize!(obligations.len())
688 if empty_where { " where" } else { "," },
689 obligations.into_iter().collect::<Vec<_>>().join(", ")
691 Applicability::MaybeIncorrect,
695 bound_list.sort_by(|(_, a), (_, b)| a.cmp(&b)); // Sort alphabetically.
696 bound_list.dedup_by(|(_, a), (_, b)| a == b); // #35677
697 bound_list.sort_by_key(|(pos, _)| *pos); // Keep the original predicate order.
700 for (span, msg) in bound_spans.into_iter() {
701 err.span_label(span, &msg);
703 if !bound_list.is_empty() {
704 let bound_list = bound_list
706 .map(|(_, path)| path)
710 "the method `{}` exists but the following trait bounds were not \
712 item_name, bound_list
717 if actual.is_numeric() && actual.is_fresh() || restrict_type_params {
719 self.suggest_traits_to_import(
726 &unsatisfied_predicates,
730 if actual.is_enum() {
731 let adt_def = actual.ty_adt_def().expect("enum is not an ADT");
732 if let Some(suggestion) = lev_distance::find_best_match_for_name(
733 adt_def.variants.iter().map(|s| &s.ident.name),
739 "there is a variant with a similar name",
740 suggestion.to_string(),
741 Applicability::MaybeIncorrect,
746 let mut fallback_span = true;
747 let msg = "remove this method call";
748 if item_name.as_str() == "as_str" && actual.peel_refs().is_str() {
749 if let SelfSource::MethodCall(expr) = source {
751 self.tcx.hir().expect_expr(self.tcx.hir().get_parent_node(expr.hir_id));
752 if let Some(span) = call_expr.span.trim_start(expr.span) {
757 Applicability::MachineApplicable,
759 fallback_span = false;
763 err.span_label(span, msg);
765 } else if let Some(lev_candidate) = lev_candidate {
766 let def_kind = lev_candidate.kind.as_def_kind();
770 "there is {} {} with a similar name",
772 def_kind.descr(lev_candidate.def_id),
774 lev_candidate.ident.to_string(),
775 Applicability::MaybeIncorrect,
782 MethodError::Ambiguity(sources) => {
783 let mut err = struct_span_err!(
787 "multiple applicable items in scope"
789 err.span_label(item_name.span, format!("multiple `{}` found", item_name));
791 report_candidates(span, &mut err, sources, sugg_span);
795 MethodError::PrivateMatch(kind, def_id, out_of_scope_traits) => {
796 let kind = kind.descr(def_id);
797 let mut err = struct_span_err!(
801 "{} `{}` is private",
805 err.span_label(item_name.span, &format!("private {}", kind));
806 self.suggest_valid_traits(&mut err, out_of_scope_traits);
810 MethodError::IllegalSizedBound(candidates, needs_mut, bound_span) => {
811 let msg = format!("the `{}` method cannot be invoked on a trait object", item_name);
812 let mut err = self.sess().struct_span_err(span, &msg);
813 err.span_label(bound_span, "this has a `Sized` requirement");
814 if !candidates.is_empty() {
816 "{an}other candidate{s} {were} found in the following trait{s}, perhaps \
817 add a `use` for {one_of_them}:",
818 an = if candidates.len() == 1 { "an" } else { "" },
819 s = pluralize!(candidates.len()),
820 were = if candidates.len() == 1 { "was" } else { "were" },
821 one_of_them = if candidates.len() == 1 { "it" } else { "one_of_them" },
823 self.suggest_use_candidates(&mut err, help, candidates);
825 if let ty::Ref(region, t_type, mutability) = rcvr_ty.kind {
827 let trait_type = self.tcx.mk_ref(
829 ty::TypeAndMut { ty: t_type, mutbl: mutability.invert() },
831 err.note(&format!("you need `{}` instead of `{}`", trait_type, rcvr_ty));
837 MethodError::BadReturnType => bug!("no return type expectations but got BadReturnType"),
842 /// Print out the type for use in value namespace.
843 fn ty_to_value_string(&self, ty: Ty<'tcx>) -> String {
845 ty::Adt(def, substs) => format!("{}", ty::Instance::new(def.did, substs)),
846 _ => self.ty_to_string(ty),
850 fn suggest_use_candidates(
852 err: &mut DiagnosticBuilder<'_>,
854 candidates: Vec<DefId>,
856 let module_did = self.tcx.parent_module(self.body_id);
857 let module_id = self.tcx.hir().as_local_hir_id(module_did);
858 let krate = self.tcx.hir().krate();
859 let (span, found_use) = UsePlacementFinder::check(self.tcx, krate, module_id);
860 if let Some(span) = span {
861 let path_strings = candidates.iter().map(|did| {
862 // Produce an additional newline to separate the new use statement
863 // from the directly following item.
864 let additional_newline = if found_use { "" } else { "\n" };
867 with_crate_prefix(|| self.tcx.def_path_str(*did)),
872 err.span_suggestions(span, &msg, path_strings, Applicability::MaybeIncorrect);
874 let limit = if candidates.len() == 5 { 5 } else { 4 };
875 for (i, trait_did) in candidates.iter().take(limit).enumerate() {
876 if candidates.len() > 1 {
877 msg.push_str(&format!(
878 "\ncandidate #{}: `use {};`",
880 with_crate_prefix(|| self.tcx.def_path_str(*trait_did))
883 msg.push_str(&format!(
885 with_crate_prefix(|| self.tcx.def_path_str(*trait_did))
889 if candidates.len() > limit {
890 msg.push_str(&format!("\nand {} others", candidates.len() - limit));
896 fn suggest_valid_traits(
898 err: &mut DiagnosticBuilder<'_>,
899 valid_out_of_scope_traits: Vec<DefId>,
901 if !valid_out_of_scope_traits.is_empty() {
902 let mut candidates = valid_out_of_scope_traits;
905 err.help("items from traits can only be used if the trait is in scope");
907 "the following {traits_are} implemented but not in scope; \
908 perhaps add a `use` for {one_of_them}:",
909 traits_are = if candidates.len() == 1 { "trait is" } else { "traits are" },
910 one_of_them = if candidates.len() == 1 { "it" } else { "one of them" },
913 self.suggest_use_candidates(err, msg, candidates);
920 fn suggest_traits_to_import<'b>(
922 err: &mut DiagnosticBuilder<'_>,
926 source: SelfSource<'b>,
927 valid_out_of_scope_traits: Vec<DefId>,
928 unsatisfied_predicates: &[(ty::Predicate<'tcx>, Option<ty::Predicate<'tcx>>)],
930 if self.suggest_valid_traits(err, valid_out_of_scope_traits) {
934 let type_is_local = self.type_derefs_to_local(span, rcvr_ty, source);
936 let mut arbitrary_rcvr = vec![];
937 // There are no traits implemented, so lets suggest some traits to
938 // implement, by finding ones that have the item name, and are
939 // legal to implement.
940 let mut candidates = all_traits(self.tcx)
943 // We approximate the coherence rules to only suggest
944 // traits that are legal to implement by requiring that
945 // either the type or trait is local. Multi-dispatch means
946 // this isn't perfect (that is, there are cases when
947 // implementing a trait would be legal but is rejected
949 unsatisfied_predicates.iter().all(|(p, _)| match p {
950 // Hide traits if they are present in predicates as they can be fixed without
951 // having to implement them.
952 ty::PredicateKind::Trait(t, _) => t.def_id() == info.def_id,
953 ty::PredicateKind::Projection(p) => p.item_def_id() == info.def_id,
955 }) && (type_is_local || info.def_id.is_local())
957 .associated_item(info.def_id, item_name, Namespace::ValueNS)
959 if let ty::AssocKind::Fn = item.kind {
963 .map(|def_id| self.tcx.hir().as_local_hir_id(def_id));
964 if let Some(hir::Node::TraitItem(hir::TraitItem {
965 kind: hir::TraitItemKind::Fn(fn_sig, method),
967 })) = id.map(|id| self.tcx.hir().get(id))
969 let self_first_arg = match method {
970 hir::TraitFn::Required([ident, ..]) => {
971 ident.name == kw::SelfLower
973 hir::TraitFn::Provided(body_id) => {
974 self.tcx.hir().body(*body_id).params.first().map_or(
979 hir::PatKind::Binding(_, _, ident, _)
980 if ident.name == kw::SelfLower
988 if !fn_sig.decl.implicit_self.has_implicit_self()
991 if let Some(ty) = fn_sig.decl.inputs.get(0) {
992 arbitrary_rcvr.push(ty.span);
998 // We only want to suggest public or local traits (#45781).
999 item.vis == ty::Visibility::Public || info.def_id.is_local()
1003 .collect::<Vec<_>>();
1004 for span in &arbitrary_rcvr {
1007 "the method might not be found because of this arbitrary self type",
1011 if !candidates.is_empty() {
1012 // Sort from most relevant to least relevant.
1013 candidates.sort_by(|a, b| a.cmp(b).reverse());
1016 let param_type = match rcvr_ty.kind {
1017 ty::Param(param) => Some(param),
1018 ty::Ref(_, ty, _) => match ty.kind {
1019 ty::Param(param) => Some(param),
1024 err.help(if param_type.is_some() {
1025 "items from traits can only be used if the type parameter is bounded by the trait"
1027 "items from traits can only be used if the trait is implemented and in scope"
1029 let message = |action| {
1031 "the following {traits_define} an item `{name}`, perhaps you need to {action} \
1034 if candidates.len() == 1 { "trait defines" } else { "traits define" },
1036 one_of_them = if candidates.len() == 1 { "it" } else { "one of them" },
1040 // Obtain the span for `param` and use it for a structured suggestion.
1041 let mut suggested = false;
1042 if let (Some(ref param), Some(ref table)) = (param_type, self.in_progress_tables) {
1043 let table_owner = table.borrow().hir_owner;
1044 if let Some(table_owner) = table_owner {
1045 let generics = self.tcx.generics_of(table_owner.to_def_id());
1046 let type_param = generics.type_param(param, self.tcx);
1047 let hir = &self.tcx.hir();
1048 if let Some(def_id) = type_param.def_id.as_local() {
1049 let id = hir.as_local_hir_id(def_id);
1050 // Get the `hir::Param` to verify whether it already has any bounds.
1051 // We do this to avoid suggesting code that ends up as `T: FooBar`,
1052 // instead we suggest `T: Foo + Bar` in that case.
1054 Node::GenericParam(ref param) => {
1055 let mut impl_trait = false;
1056 let has_bounds = if let hir::GenericParamKind::Type {
1061 // We've found `fn foo(x: impl Trait)` instead of
1062 // `fn foo<T>(x: T)`. We want to suggest the correct
1063 // `fn foo(x: impl Trait + TraitBound)` instead of
1064 // `fn foo<T: TraitBound>(x: T)`. (#63706)
1070 let sp = hir.span(id);
1071 let sp = if let Some(first_bound) = has_bounds {
1072 // `sp` only covers `T`, change it so that it covers
1073 // `T:` when appropriate
1074 sp.until(first_bound.span())
1078 let trait_def_ids: FxHashSet<DefId> = param
1081 .filter_map(|bound| Some(bound.trait_ref()?.trait_def_id()?))
1083 if !candidates.iter().any(|t| trait_def_ids.contains(&t.def_id)) {
1084 err.span_suggestions(
1087 "restrict type parameter `{}` with",
1090 candidates.iter().map(|t| {
1094 if impl_trait { " +" } else { ":" },
1095 self.tcx.def_path_str(t.def_id),
1096 if has_bounds.is_some() { " + " } else { "" },
1099 Applicability::MaybeIncorrect,
1104 Node::Item(hir::Item {
1105 kind: hir::ItemKind::Trait(.., bounds, _),
1109 let (sp, sep, article) = if bounds.is_empty() {
1110 (ident.span.shrink_to_hi(), ":", "a")
1112 (bounds.last().unwrap().span().shrink_to_hi(), " +", "another")
1114 err.span_suggestions(
1116 &message(format!("add {} supertrait for", article)),
1117 candidates.iter().map(|t| {
1118 format!("{} {}", sep, self.tcx.def_path_str(t.def_id),)
1120 Applicability::MaybeIncorrect,
1131 let action = if let Some(param) = param_type {
1132 format!("restrict type parameter `{}` with", param)
1134 // FIXME: it might only need to be imported into scope, not implemented.
1135 "implement".to_string()
1137 let mut use_note = true;
1138 if let [trait_info] = &candidates[..] {
1139 if let Some(span) = self.tcx.hir().span_if_local(trait_info.def_id) {
1141 self.tcx.sess.source_map().guess_head_span(span),
1143 "`{}` defines an item `{}`, perhaps you need to {} it",
1144 self.tcx.def_path_str(trait_info.def_id),
1153 let mut msg = message(action);
1154 for (i, trait_info) in candidates.iter().enumerate() {
1155 msg.push_str(&format!(
1156 "\ncandidate #{}: `{}`",
1158 self.tcx.def_path_str(trait_info.def_id),
1167 /// Checks whether there is a local type somewhere in the chain of
1168 /// autoderefs of `rcvr_ty`.
1169 fn type_derefs_to_local(&self, span: Span, rcvr_ty: Ty<'tcx>, source: SelfSource<'_>) -> bool {
1170 fn is_local(ty: Ty<'_>) -> bool {
1172 ty::Adt(def, _) => def.did.is_local(),
1173 ty::Foreign(did) => did.is_local(),
1175 ty::Dynamic(ref tr, ..) => {
1176 tr.principal().map(|d| d.def_id().is_local()).unwrap_or(false)
1179 ty::Param(_) => true,
1181 // Everything else (primitive types, etc.) is effectively
1182 // non-local (there are "edge" cases, e.g., `(LocalType,)`, but
1183 // the noise from these sort of types is usually just really
1184 // annoying, rather than any sort of help).
1189 // This occurs for UFCS desugaring of `T::method`, where there is no
1190 // receiver expression for the method call, and thus no autoderef.
1191 if let SelfSource::QPath(_) = source {
1192 return is_local(self.resolve_vars_with_obligations(rcvr_ty));
1195 self.autoderef(span, rcvr_ty).any(|(ty, _)| is_local(ty))
1199 #[derive(Copy, Clone)]
1200 pub enum SelfSource<'a> {
1201 QPath(&'a hir::Ty<'a>),
1202 MethodCall(&'a hir::Expr<'a> /* rcvr */),
1205 #[derive(Copy, Clone)]
1206 pub struct TraitInfo {
1210 impl PartialEq for TraitInfo {
1211 fn eq(&self, other: &TraitInfo) -> bool {
1212 self.cmp(other) == Ordering::Equal
1215 impl Eq for TraitInfo {}
1216 impl PartialOrd for TraitInfo {
1217 fn partial_cmp(&self, other: &TraitInfo) -> Option<Ordering> {
1218 Some(self.cmp(other))
1221 impl Ord for TraitInfo {
1222 fn cmp(&self, other: &TraitInfo) -> Ordering {
1223 // Local crates are more important than remote ones (local:
1224 // `cnum == 0`), and otherwise we throw in the defid for totality.
1226 let lhs = (other.def_id.krate, other.def_id);
1227 let rhs = (self.def_id.krate, self.def_id);
1232 /// Retrieves all traits in this crate and any dependent crates.
1233 pub fn all_traits(tcx: TyCtxt<'_>) -> Vec<TraitInfo> {
1234 tcx.all_traits(LOCAL_CRATE).iter().map(|&def_id| TraitInfo { def_id }).collect()
1237 /// Computes all traits in this crate and any dependent crates.
1238 fn compute_all_traits(tcx: TyCtxt<'_>) -> Vec<DefId> {
1239 use hir::itemlikevisit;
1241 let mut traits = vec![];
1245 struct Visitor<'a, 'tcx> {
1246 map: &'a hir_map::Map<'tcx>,
1247 traits: &'a mut Vec<DefId>,
1250 impl<'v, 'a, 'tcx> itemlikevisit::ItemLikeVisitor<'v> for Visitor<'a, 'tcx> {
1251 fn visit_item(&mut self, i: &'v hir::Item<'v>) {
1253 hir::ItemKind::Trait(..) | hir::ItemKind::TraitAlias(..) => {
1254 let def_id = self.map.local_def_id(i.hir_id);
1255 self.traits.push(def_id.to_def_id());
1261 fn visit_trait_item(&mut self, _trait_item: &hir::TraitItem<'_>) {}
1263 fn visit_impl_item(&mut self, _impl_item: &hir::ImplItem<'_>) {}
1266 tcx.hir().krate().visit_all_item_likes(&mut Visitor { map: &tcx.hir(), traits: &mut traits });
1270 let mut external_mods = FxHashSet::default();
1271 fn handle_external_res(
1273 traits: &mut Vec<DefId>,
1274 external_mods: &mut FxHashSet<DefId>,
1278 Res::Def(DefKind::Trait | DefKind::TraitAlias, def_id) => {
1279 traits.push(def_id);
1281 Res::Def(DefKind::Mod, def_id) => {
1282 if !external_mods.insert(def_id) {
1285 for child in tcx.item_children(def_id).iter() {
1286 handle_external_res(tcx, traits, external_mods, child.res)
1292 for &cnum in tcx.crates().iter() {
1293 let def_id = DefId { krate: cnum, index: CRATE_DEF_INDEX };
1294 handle_external_res(tcx, &mut traits, &mut external_mods, Res::Def(DefKind::Mod, def_id));
1300 pub fn provide(providers: &mut ty::query::Providers<'_>) {
1301 providers.all_traits = |tcx, cnum| {
1302 assert_eq!(cnum, LOCAL_CRATE);
1303 &tcx.arena.alloc(compute_all_traits(tcx))[..]
1307 struct UsePlacementFinder<'tcx> {
1308 target_module: hir::HirId,
1314 impl UsePlacementFinder<'tcx> {
1317 krate: &'tcx hir::Crate<'tcx>,
1318 target_module: hir::HirId,
1319 ) -> (Option<Span>, bool) {
1320 let mut finder = UsePlacementFinder { target_module, span: None, found_use: false, tcx };
1321 intravisit::walk_crate(&mut finder, krate);
1322 (finder.span, finder.found_use)
1326 impl intravisit::Visitor<'tcx> for UsePlacementFinder<'tcx> {
1327 fn visit_mod(&mut self, module: &'tcx hir::Mod<'tcx>, _: Span, hir_id: hir::HirId) {
1328 if self.span.is_some() {
1331 if hir_id != self.target_module {
1332 intravisit::walk_mod(self, module, hir_id);
1335 // Find a `use` statement.
1336 for item_id in module.item_ids {
1337 let item = self.tcx.hir().expect_item(item_id.id);
1339 hir::ItemKind::Use(..) => {
1340 // Don't suggest placing a `use` before the prelude
1341 // import or other generated ones.
1342 if !item.span.from_expansion() {
1343 self.span = Some(item.span.shrink_to_lo());
1344 self.found_use = true;
1348 // Don't place `use` before `extern crate`...
1349 hir::ItemKind::ExternCrate(_) => {}
1350 // ...but do place them before the first other item.
1352 if self.span.map_or(true, |span| item.span < span) {
1353 if !item.span.from_expansion() {
1354 // Don't insert between attributes and an item.
1355 if item.attrs.is_empty() {
1356 self.span = Some(item.span.shrink_to_lo());
1358 // Find the first attribute on the item.
1359 for attr in item.attrs {
1360 if self.span.map_or(true, |span| attr.span < span) {
1361 self.span = Some(attr.span.shrink_to_lo());
1372 type Map = intravisit::ErasedMap<'tcx>;
1374 fn nested_visit_map(&mut self) -> intravisit::NestedVisitorMap<Self::Map> {
1375 intravisit::NestedVisitorMap::None
1379 fn print_disambiguation_help(
1381 args: Option<&'tcx [hir::Expr<'tcx>]>,
1382 err: &mut DiagnosticBuilder<'_>,
1385 kind: ty::AssocKind,
1388 candidate: Option<usize>,
1389 source_map: &source_map::SourceMap,
1391 let mut applicability = Applicability::MachineApplicable;
1392 let sugg_args = if let (ty::AssocKind::Fn, Some(args)) = (kind, args) {
1395 if rcvr_ty.is_region_ptr() {
1396 if rcvr_ty.is_mutable_ptr() { "&mut " } else { "&" }
1401 .map(|arg| source_map.span_to_snippet(arg.span).unwrap_or_else(|_| {
1402 applicability = Applicability::HasPlaceholders;
1405 .collect::<Vec<_>>()
1411 let sugg = format!("{}::{}{}", trait_name, item_name, sugg_args);
1412 err.span_suggestion(
1415 "disambiguate the {} for {}",
1416 kind.as_def_kind().descr(def_id),
1417 if let Some(candidate) = candidate {
1418 format!("candidate #{}", candidate)
1420 "the candidate".to_string()