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 crate::middle::lang_items::FnOnceTraitLangItem;
6 use rustc::hir::map as hir_map;
7 use rustc::hir::map::Map;
8 use rustc::ty::print::with_crate_prefix;
9 use rustc::ty::{self, ToPolyTraitRef, ToPredicate, Ty, TyCtxt, TypeFoldable, WithConstness};
10 use rustc_data_structures::fx::{FxHashMap, FxHashSet};
11 use rustc_errors::{pluralize, struct_span_err, Applicability, DiagnosticBuilder};
13 use rustc_hir::def::{DefKind, Namespace, Res};
14 use rustc_hir::def_id::{DefId, CRATE_DEF_INDEX, LOCAL_CRATE};
15 use rustc_hir::intravisit;
16 use rustc_hir::{ExprKind, Node, QPath};
17 use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
18 use rustc_infer::traits::Obligation;
19 use rustc_span::symbol::kw;
20 use rustc_span::{source_map, FileName, Span};
22 use syntax::util::lev_distance;
24 use std::cmp::Ordering;
26 use super::probe::Mode;
27 use super::{CandidateSource, MethodError, NoMatchData};
29 impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
30 fn is_fn_ty(&self, ty: Ty<'tcx>, span: Span) -> bool {
33 // Not all of these (e.g., unsafe fns) implement `FnOnce`,
34 // so we look for these beforehand.
35 ty::Closure(..) | ty::FnDef(..) | ty::FnPtr(_) => true,
36 // If it's not a simple function, look for things which implement `FnOnce`.
38 let fn_once = match tcx.lang_items().require(FnOnceTraitLangItem) {
39 Ok(fn_once) => fn_once,
40 Err(..) => return false,
43 self.autoderef(span, ty).any(|(ty, _)| {
45 let fn_once_substs = tcx.mk_substs_trait(
48 .next_ty_var(TypeVariableOrigin {
49 kind: TypeVariableOriginKind::MiscVariable,
54 let trait_ref = ty::TraitRef::new(fn_once, fn_once_substs);
55 let poly_trait_ref = trait_ref.to_poly_trait_ref();
56 let obligation = Obligation::misc(
60 poly_trait_ref.without_const().to_predicate(),
62 self.predicate_may_hold(&obligation)
69 pub fn report_method_error<'b>(
73 item_name: ast::Ident,
74 source: SelfSource<'b>,
75 error: MethodError<'tcx>,
76 args: Option<&'tcx [hir::Expr<'tcx>]>,
77 ) -> Option<DiagnosticBuilder<'_>> {
80 // Avoid suggestions when we don't know what's going on.
81 if rcvr_ty.references_error() {
85 let report_candidates = |span: Span,
86 err: &mut DiagnosticBuilder<'_>,
87 mut sources: Vec<CandidateSource>,
91 // Dynamic limit to avoid hiding just one candidate, which is silly.
92 let limit = if sources.len() == 5 { 5 } else { 4 };
94 for (idx, source) in sources.iter().take(limit).enumerate() {
96 CandidateSource::ImplSource(impl_did) => {
97 // Provide the best span we can. Use the item, if local to crate, else
98 // the impl, if local to crate (item may be defaulted), else nothing.
100 .associated_item(impl_did, item_name, Namespace::ValueNS)
102 let impl_trait_ref = self.tcx.impl_trait_ref(impl_did)?;
103 self.associated_item(
104 impl_trait_ref.def_id,
115 .span_if_local(item.def_id)
116 .or_else(|| self.tcx.hir().span_if_local(impl_did));
118 let impl_ty = self.impl_self_ty(span, impl_did).ty;
120 let insertion = match self.tcx.impl_trait_ref(impl_did) {
121 None => String::new(),
122 Some(trait_ref) => format!(
123 " of the trait `{}`",
124 self.tcx.def_path_str(trait_ref.def_id)
128 let (note_str, idx) = if sources.len() > 1 {
131 "candidate #{} is defined in an impl{} for the type `{}`",
141 "the candidate is defined in an impl{} for the type `{}`",
147 if let Some(note_span) = note_span {
148 // We have a span pointing to the method. Show note with snippet.
150 self.tcx.sess.source_map().def_span(note_span),
156 if let Some(trait_ref) = self.tcx.impl_trait_ref(impl_did) {
157 let path = self.tcx.def_path_str(trait_ref.def_id);
159 let ty = match item.kind {
161 | ty::AssocKind::Type
162 | ty::AssocKind::OpaqueTy => rcvr_ty,
163 ty::AssocKind::Method => self
169 .filter(|ty| ty.is_region_ptr() && !rcvr_ty.is_region_ptr())
173 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) {
193 self.tcx.sess.source_map().def_span(self.tcx.def_span(item.def_id));
194 let idx = if sources.len() > 1 {
196 "candidate #{} is defined in the trait `{}`",
198 self.tcx.def_path_str(trait_did)
200 err.span_note(item_span, msg);
204 "the candidate is defined in the trait `{}`",
205 self.tcx.def_path_str(trait_did)
207 err.span_note(item_span, msg);
210 let path = self.tcx.def_path_str(trait_did);
211 print_disambiguation_help(
220 self.tcx.sess.source_map(),
225 if sources.len() > limit {
226 err.note(&format!("and {} others", sources.len() - limit));
230 let sugg_span = if let SelfSource::MethodCall(expr) = source {
231 // Given `foo.bar(baz)`, `expr` is `bar`, but we want to point to the whole thing.
232 self.tcx.hir().expect_expr(self.tcx.hir().get_parent_node(expr.hir_id)).span
238 MethodError::NoMatch(NoMatchData {
239 static_candidates: static_sources,
240 unsatisfied_predicates,
247 let actual = self.resolve_vars_if_possible(&rcvr_ty);
248 let ty_str = self.ty_to_string(actual);
249 let is_method = mode == Mode::MethodCall;
250 let item_kind = if is_method {
252 } else if actual.is_enum() {
253 "variant or associated item"
255 match (item_name.as_str().chars().next(), actual.is_fresh_ty()) {
256 (Some(name), false) if name.is_lowercase() => "function or associated item",
257 (Some(_), false) => "associated item",
258 (Some(_), true) | (None, false) => "variant or associated item",
259 (None, true) => "variant",
262 let mut err = if !actual.references_error() {
263 // Suggest clamping down the type if the method that is being attempted to
264 // be used exists at all, and the type is an ambiguous numeric type
265 // ({integer}/{float}).
266 let mut candidates = all_traits(self.tcx).into_iter().filter_map(|info| {
267 self.associated_item(info.def_id, item_name, Namespace::ValueNS)
269 if let (true, false, SelfSource::MethodCall(expr), Some(_)) = (
271 actual.has_concrete_skeleton(),
275 let mut err = struct_span_err!(
279 "can't call {} `{}` on ambiguous numeric type `{}`",
284 let concrete_type = if actual.is_integral() { "i32" } else { "f32" };
286 ExprKind::Lit(ref lit) => {
291 .span_to_snippet(lit.span)
292 .unwrap_or_else(|_| "<numeric literal>".to_owned());
297 "you must specify a concrete type for \
298 this numeric value, like `{}`",
301 format!("{}_{}", snippet, concrete_type),
302 Applicability::MaybeIncorrect,
305 ExprKind::Path(ref qpath) => {
307 if let &QPath::Resolved(_, ref path) = &qpath {
308 if let hir::def::Res::Local(hir_id) = path.res {
309 let span = tcx.hir().span(hir_id);
310 let snippet = tcx.sess.source_map().span_to_snippet(span);
311 let filename = tcx.sess.source_map().span_to_filename(span);
313 let parent_node = self
316 .get(self.tcx.hir().get_parent_node(hir_id));
318 "you must specify a type for this binding, like `{}`",
322 match (filename, parent_node, snippet) {
325 Node::Local(hir::Local {
326 source: hir::LocalSource::Normal,
333 // account for `let x: _ = 42;`
340 format!("{}: {}", snippet, concrete_type),
341 Applicability::MaybeIncorrect,
345 err.span_label(span, msg);
356 span = item_name.span;
357 let mut err = struct_span_err!(
361 "no {} named `{}` found for {} `{}` in the current scope",
364 actual.prefix_string(),
368 tcx.sess.confused_type_with_std_module.borrow().get(&span)
370 if let Ok(snippet) = tcx.sess.source_map().span_to_snippet(*span) {
373 "you are looking for the module in `std`, \
374 not the primitive type",
375 format!("std::{}", snippet),
376 Applicability::MachineApplicable,
380 if let ty::RawPtr(_) = &actual.kind {
382 "try using `<*const T>::as_ref()` to get a reference to the \
383 type behind the pointer: https://doc.rust-lang.org/std/\
384 primitive.pointer.html#method.as_ref",
387 "using `<*const T>::as_ref()` on a pointer \
388 which is unaligned or points to invalid \
389 or uninitialized memory is undefined behavior",
395 tcx.sess.diagnostic().struct_dummy()
398 if let Some(def) = actual.ty_adt_def() {
399 if let Some(full_sp) = tcx.hir().span_if_local(def.did) {
400 let def_sp = tcx.sess.source_map().def_span(full_sp);
404 "{} `{}` not found {}",
407 if def.is_enum() && !is_method { "here" } else { "for this" }
413 // If the method name is the name of a field with a function or closure type,
414 // give a helping note that it has to be called as `(x.f)(...)`.
415 if let SelfSource::MethodCall(expr) = source {
417 self.autoderef(span, rcvr_ty).find_map(|(ty, _)| match ty.kind {
418 ty::Adt(def, substs) if !def.is_enum() => {
419 let variant = &def.non_enum_variant();
420 self.tcx.find_field_index(item_name, variant).map(|index| {
421 let field = &variant.fields[index];
422 let field_ty = field.ty(tcx, substs);
429 if let Some((field, field_ty)) = field_receiver {
430 let scope = self.tcx.hir().get_module_parent(self.body_id);
431 let is_accessible = field.vis.is_accessible_from(scope, self.tcx);
434 if self.is_fn_ty(&field_ty, span) {
435 let expr_span = expr.span.to(item_name.span);
436 err.multipart_suggestion(
438 "to call the function stored in `{}`, \
439 surround the field access with parentheses",
443 (expr_span.shrink_to_lo(), '('.to_string()),
444 (expr_span.shrink_to_hi(), ')'.to_string()),
446 Applicability::MachineApplicable,
452 .expect_expr(self.tcx.hir().get_parent_node(expr.hir_id));
454 if let Some(span) = call_expr.span.trim_start(item_name.span) {
457 "remove the arguments",
459 Applicability::MaybeIncorrect,
465 let field_kind = if is_accessible { "field" } else { "private field" };
466 err.span_label(item_name.span, format!("{}, not a method", field_kind));
467 } else if lev_candidate.is_none() && static_sources.is_empty() {
468 err.span_label(span, format!("{} not found in `{}`", item_kind, ty_str));
469 self.tcx.sess.trait_methods_not_found.borrow_mut().insert(orig_span);
472 err.span_label(span, format!("{} not found in `{}`", item_kind, ty_str));
473 self.tcx.sess.trait_methods_not_found.borrow_mut().insert(orig_span);
476 if self.is_fn_ty(&rcvr_ty, span) {
477 macro_rules! report_function {
478 ($span:expr, $name:expr) => {
480 "`{}` is a function, perhaps you wish to call it",
486 if let SelfSource::MethodCall(expr) = source {
487 if let Ok(expr_string) = tcx.sess.source_map().span_to_snippet(expr.span) {
488 report_function!(expr.span, expr_string);
489 } else if let ExprKind::Path(QPath::Resolved(_, ref path)) = expr.kind {
490 if let Some(segment) = path.segments.last() {
491 report_function!(expr.span, segment.ident);
497 if !static_sources.is_empty() {
499 "found the following associated functions; to be used as methods, \
500 functions must have a `self` parameter",
502 err.span_label(span, "this is an associated function, not a method");
504 if static_sources.len() == 1 {
505 let ty_str = if let Some(CandidateSource::ImplSource(impl_did)) =
506 static_sources.get(0)
508 // When the "method" is resolved through dereferencing, we really want the
509 // original type that has the associated function for accurate suggestions.
511 let ty = self.impl_self_ty(span, *impl_did).ty;
512 match (&ty.peel_refs().kind, &actual.peel_refs().kind) {
513 (ty::Adt(def, _), ty::Adt(def_actual, _)) if def == def_actual => {
514 // Use `actual` as it will have more `substs` filled in.
515 self.ty_to_value_string(actual.peel_refs())
517 _ => self.ty_to_value_string(ty.peel_refs()),
520 self.ty_to_value_string(actual.peel_refs())
522 if let SelfSource::MethodCall(expr) = source {
525 "use associated function syntax instead",
526 format!("{}::{}", ty_str, item_name),
527 Applicability::MachineApplicable,
530 err.help(&format!("try with `{}::{}`", ty_str, item_name,));
533 report_candidates(span, &mut err, static_sources, sugg_span);
534 } else if static_sources.len() > 1 {
535 report_candidates(span, &mut err, static_sources, sugg_span);
538 if !unsatisfied_predicates.is_empty() {
540 |def_id| self.tcx.sess.source_map().def_span(self.tcx.def_span(def_id));
541 let mut type_params = FxHashMap::default();
542 let mut bound_spans = vec![];
543 let mut collect_type_param_suggestions =
544 |self_ty: Ty<'_>, parent_pred: &ty::Predicate<'_>, obligation: &str| {
545 if let (ty::Param(_), ty::Predicate::Trait(p, _)) =
546 (&self_ty.kind, parent_pred)
548 if let ty::Adt(def, _) = p.skip_binder().trait_ref.self_ty().kind {
549 let id = self.tcx.hir().as_local_hir_id(def.did).unwrap();
550 let node = self.tcx.hir().get(id);
552 hir::Node::Item(hir::Item { kind, .. }) => {
553 if let Some(g) = kind.generics() {
554 let key = match &g.where_clause.predicates[..] {
556 (pred.span().shrink_to_hi(), false)
560 .span_for_predicates_or_empty_place(),
566 .or_insert_with(FxHashSet::default)
567 .insert(obligation.to_owned());
575 let mut bound_span_label = |self_ty: Ty<'_>, obligation: &str, quiet: &str| {
577 "doesn't satisfy `{}`",
578 if obligation.len() > 50 { quiet } else { obligation }
580 match &self_ty.kind {
581 // Point at the type that couldn't satisfy the bound.
582 ty::Adt(def, _) => bound_spans.push((def_span(def.did), msg)),
583 // Point at the trait object that couldn't satisfy the bound.
584 ty::Dynamic(preds, _) => {
585 for pred in *preds.skip_binder() {
587 ty::ExistentialPredicate::Trait(tr) => {
588 bound_spans.push((def_span(tr.def_id), msg.clone()))
590 ty::ExistentialPredicate::Projection(_)
591 | ty::ExistentialPredicate::AutoTrait(_) => {}
595 // Point at the closure that couldn't satisfy the bound.
596 ty::Closure(def_id, _) => bound_spans
597 .push((def_span(*def_id), format!("doesn't satisfy `{}`", quiet))),
601 let mut format_pred = |pred| {
603 ty::Predicate::Projection(pred) => {
604 // `<Foo as Iterator>::Item = String`.
606 pred.skip_binder().projection_ty.trait_ref(self.tcx);
609 .associated_item(pred.skip_binder().projection_ty.item_def_id);
610 let ty = pred.skip_binder().ty;
611 let obligation = format!("{}::{} = {}", trait_ref, assoc.ident, ty);
613 "<_ as {}>::{} = {}",
614 trait_ref.print_only_trait_path(),
618 bound_span_label(trait_ref.self_ty(), &obligation, &quiet);
619 Some((obligation, trait_ref.self_ty()))
621 ty::Predicate::Trait(poly_trait_ref, _) => {
622 let p = poly_trait_ref.skip_binder().trait_ref;
623 let self_ty = p.self_ty();
624 let path = p.print_only_trait_path();
625 let obligation = format!("{}: {}", self_ty, path);
626 let quiet = format!("_: {}", path);
627 bound_span_label(self_ty, &obligation, &quiet);
628 Some((obligation, self_ty))
633 let mut bound_list = unsatisfied_predicates
635 .filter_map(|(pred, parent_pred)| {
636 format_pred(*pred).map(|(p, self_ty)| match parent_pred {
637 None => format!("`{}`", p),
638 Some(parent_pred) => match format_pred(*parent_pred) {
639 None => format!("`{}`", p),
640 Some((parent_p, _)) => {
641 collect_type_param_suggestions(self_ty, parent_pred, &p);
642 format!("`{}`\nwhich is required by `{}`", p, parent_p)
648 .collect::<Vec<(usize, String)>>();
649 for ((span, empty_where), obligations) in type_params.into_iter() {
650 err.span_suggestion_verbose(
653 "consider restricting the type parameter{s} to satisfy the \
655 s = pluralize!(obligations.len())
659 if empty_where { " where" } else { "," },
660 obligations.into_iter().collect::<Vec<_>>().join(", ")
662 Applicability::MaybeIncorrect,
666 bound_list.sort_by(|(_, a), (_, b)| a.cmp(&b)); // Sort alphabetically.
667 bound_list.dedup_by(|(_, a), (_, b)| a == b); // #35677
668 bound_list.sort_by_key(|(pos, _)| *pos); // Keep the original predicate order.
671 for (span, msg) in bound_spans.into_iter() {
672 err.span_label(span, &msg);
674 if !bound_list.is_empty() {
675 let bound_list = bound_list
677 .map(|(_, path)| path)
681 "the method `{}` exists but the following trait bounds were not \
683 item_name, bound_list
688 if actual.is_numeric() && actual.is_fresh() {
690 self.suggest_traits_to_import(
700 if actual.is_enum() {
701 let adt_def = actual.ty_adt_def().expect("enum is not an ADT");
702 if let Some(suggestion) = lev_distance::find_best_match_for_name(
703 adt_def.variants.iter().map(|s| &s.ident.name),
709 "there is a variant with a similar name",
710 suggestion.to_string(),
711 Applicability::MaybeIncorrect,
716 let mut fallback_span = true;
717 let msg = "remove this method call";
718 if item_name.as_str() == "as_str" && actual.peel_refs().is_str() {
719 if let SelfSource::MethodCall(expr) = source {
721 self.tcx.hir().expect_expr(self.tcx.hir().get_parent_node(expr.hir_id));
722 if let Some(span) = call_expr.span.trim_start(expr.span) {
727 Applicability::MachineApplicable,
729 fallback_span = false;
733 err.span_label(span, msg);
735 } else if let Some(lev_candidate) = lev_candidate {
736 let def_kind = lev_candidate.def_kind();
740 "there is {} {} with a similar name",
742 def_kind.descr(lev_candidate.def_id),
744 lev_candidate.ident.to_string(),
745 Applicability::MaybeIncorrect,
752 MethodError::Ambiguity(sources) => {
753 let mut err = struct_span_err!(
757 "multiple applicable items in scope"
759 err.span_label(span, format!("multiple `{}` found", item_name));
761 report_candidates(span, &mut err, sources, sugg_span);
765 MethodError::PrivateMatch(kind, def_id, out_of_scope_traits) => {
766 let mut err = struct_span_err!(
770 "{} `{}` is private",
774 self.suggest_valid_traits(&mut err, out_of_scope_traits);
778 MethodError::IllegalSizedBound(candidates, needs_mut, bound_span) => {
779 let msg = format!("the `{}` method cannot be invoked on a trait object", item_name);
780 let mut err = self.sess().struct_span_err(span, &msg);
781 err.span_label(bound_span, "this has a `Sized` requirement");
782 if !candidates.is_empty() {
784 "{an}other candidate{s} {were} found in the following trait{s}, perhaps \
785 add a `use` for {one_of_them}:",
786 an = if candidates.len() == 1 { "an" } else { "" },
787 s = pluralize!(candidates.len()),
788 were = if candidates.len() == 1 { "was" } else { "were" },
789 one_of_them = if candidates.len() == 1 { "it" } else { "one_of_them" },
791 self.suggest_use_candidates(&mut err, help, candidates);
793 if let ty::Ref(region, t_type, mutability) = rcvr_ty.kind {
795 let trait_type = self.tcx.mk_ref(
797 ty::TypeAndMut { ty: t_type, mutbl: mutability.invert() },
799 err.note(&format!("you need `{}` instead of `{}`", trait_type, rcvr_ty));
805 MethodError::BadReturnType => bug!("no return type expectations but got BadReturnType"),
810 /// Print out the type for use in value namespace.
811 fn ty_to_value_string(&self, ty: Ty<'tcx>) -> String {
813 ty::Adt(def, substs) => format!("{}", ty::Instance::new(def.did, substs)),
814 _ => self.ty_to_string(ty),
818 fn suggest_use_candidates(
820 err: &mut DiagnosticBuilder<'_>,
822 candidates: Vec<DefId>,
824 let module_did = self.tcx.hir().get_module_parent(self.body_id);
825 let module_id = self.tcx.hir().as_local_hir_id(module_did).unwrap();
826 let krate = self.tcx.hir().krate();
827 let (span, found_use) = UsePlacementFinder::check(self.tcx, krate, module_id);
828 if let Some(span) = span {
829 let path_strings = candidates.iter().map(|did| {
830 // Produce an additional newline to separate the new use statement
831 // from the directly following item.
832 let additional_newline = if found_use { "" } else { "\n" };
835 with_crate_prefix(|| self.tcx.def_path_str(*did)),
840 err.span_suggestions(span, &msg, path_strings, Applicability::MaybeIncorrect);
842 let limit = if candidates.len() == 5 { 5 } else { 4 };
843 for (i, trait_did) in candidates.iter().take(limit).enumerate() {
844 if candidates.len() > 1 {
845 msg.push_str(&format!(
846 "\ncandidate #{}: `use {};`",
848 with_crate_prefix(|| self.tcx.def_path_str(*trait_did))
851 msg.push_str(&format!(
853 with_crate_prefix(|| self.tcx.def_path_str(*trait_did))
857 if candidates.len() > limit {
858 msg.push_str(&format!("\nand {} others", candidates.len() - limit));
864 fn suggest_valid_traits(
866 err: &mut DiagnosticBuilder<'_>,
867 valid_out_of_scope_traits: Vec<DefId>,
869 if !valid_out_of_scope_traits.is_empty() {
870 let mut candidates = valid_out_of_scope_traits;
873 err.help("items from traits can only be used if the trait is in scope");
875 "the following {traits_are} implemented but not in scope; \
876 perhaps add a `use` for {one_of_them}:",
877 traits_are = if candidates.len() == 1 { "trait is" } else { "traits are" },
878 one_of_them = if candidates.len() == 1 { "it" } else { "one of them" },
881 self.suggest_use_candidates(err, msg, candidates);
888 fn suggest_traits_to_import<'b>(
890 err: &mut DiagnosticBuilder<'_>,
893 item_name: ast::Ident,
894 source: SelfSource<'b>,
895 valid_out_of_scope_traits: Vec<DefId>,
897 if self.suggest_valid_traits(err, valid_out_of_scope_traits) {
901 let type_is_local = self.type_derefs_to_local(span, rcvr_ty, source);
903 let mut arbitrary_rcvr = vec![];
904 // There are no traits implemented, so lets suggest some traits to
905 // implement, by finding ones that have the item name, and are
906 // legal to implement.
907 let mut candidates = all_traits(self.tcx)
910 // We approximate the coherence rules to only suggest
911 // traits that are legal to implement by requiring that
912 // either the type or trait is local. Multi-dispatch means
913 // this isn't perfect (that is, there are cases when
914 // implementing a trait would be legal but is rejected
916 (type_is_local || info.def_id.is_local())
918 .associated_item(info.def_id, item_name, Namespace::ValueNS)
920 if let ty::AssocKind::Method = item.kind {
921 let id = self.tcx.hir().as_local_hir_id(item.def_id);
922 if let Some(hir::Node::TraitItem(hir::TraitItem {
923 kind: hir::TraitItemKind::Method(fn_sig, method),
925 })) = id.map(|id| self.tcx.hir().get(id))
927 let self_first_arg = match method {
928 hir::TraitMethod::Required([ident, ..]) => {
929 ident.name == kw::SelfLower
931 hir::TraitMethod::Provided(body_id) => {
932 match &self.tcx.hir().body(*body_id).params[..] {
937 hir::PatKind::Binding(
946 }, ..] => ident.name == kw::SelfLower,
953 if !fn_sig.decl.implicit_self.has_implicit_self()
956 if let Some(ty) = fn_sig.decl.inputs.get(0) {
957 arbitrary_rcvr.push(ty.span);
963 // We only want to suggest public or local traits (#45781).
964 item.vis == ty::Visibility::Public || info.def_id.is_local()
968 .collect::<Vec<_>>();
969 for span in &arbitrary_rcvr {
972 "the method might not be found because of this arbitrary self type",
976 if !candidates.is_empty() {
977 // Sort from most relevant to least relevant.
978 candidates.sort_by(|a, b| a.cmp(b).reverse());
981 let param_type = match rcvr_ty.kind {
982 ty::Param(param) => Some(param),
983 ty::Ref(_, ty, _) => match ty.kind {
984 ty::Param(param) => Some(param),
989 err.help(if param_type.is_some() {
990 "items from traits can only be used if the type parameter is bounded by the trait"
992 "items from traits can only be used if the trait is implemented and in scope"
994 let message = |action| {
996 "the following {traits_define} an item `{name}`, perhaps you need to {action} \
999 if candidates.len() == 1 { "trait defines" } else { "traits define" },
1001 one_of_them = if candidates.len() == 1 { "it" } else { "one of them" },
1005 // Obtain the span for `param` and use it for a structured suggestion.
1006 let mut suggested = false;
1007 if let (Some(ref param), Some(ref table)) = (param_type, self.in_progress_tables) {
1008 let table = table.borrow();
1009 if let Some(did) = table.local_id_root {
1010 let generics = self.tcx.generics_of(did);
1011 let type_param = generics.type_param(param, self.tcx);
1012 let hir = &self.tcx.hir();
1013 if let Some(id) = hir.as_local_hir_id(type_param.def_id) {
1014 // Get the `hir::Param` to verify whether it already has any bounds.
1015 // We do this to avoid suggesting code that ends up as `T: FooBar`,
1016 // instead we suggest `T: Foo + Bar` in that case.
1018 Node::GenericParam(ref param) => {
1019 let mut impl_trait = false;
1020 let has_bounds = if let hir::GenericParamKind::Type {
1025 // We've found `fn foo(x: impl Trait)` instead of
1026 // `fn foo<T>(x: T)`. We want to suggest the correct
1027 // `fn foo(x: impl Trait + TraitBound)` instead of
1028 // `fn foo<T: TraitBound>(x: T)`. (#63706)
1034 let sp = hir.span(id);
1035 let sp = if let Some(first_bound) = has_bounds {
1036 // `sp` only covers `T`, change it so that it covers
1037 // `T:` when appropriate
1038 sp.until(first_bound.span())
1042 let trait_def_ids: FxHashSet<DefId> = param
1045 .filter_map(|bound| bound.trait_def_id())
1047 if !candidates.iter().any(|t| trait_def_ids.contains(&t.def_id)) {
1048 err.span_suggestions(
1051 "restrict type parameter `{}` with",
1054 candidates.iter().map(|t| {
1058 if impl_trait { " +" } else { ":" },
1059 self.tcx.def_path_str(t.def_id),
1060 if has_bounds.is_some() { " + " } else { "" },
1063 Applicability::MaybeIncorrect,
1068 Node::Item(hir::Item {
1069 kind: hir::ItemKind::Trait(.., bounds, _),
1073 let (sp, sep, article) = if bounds.is_empty() {
1074 (ident.span.shrink_to_hi(), ":", "a")
1076 (bounds.last().unwrap().span().shrink_to_hi(), " +", "another")
1078 err.span_suggestions(
1080 &message(format!("add {} supertrait for", article)),
1081 candidates.iter().map(|t| {
1082 format!("{} {}", sep, self.tcx.def_path_str(t.def_id),)
1084 Applicability::MaybeIncorrect,
1095 let action = if let Some(param) = param_type {
1096 format!("restrict type parameter `{}` with", param)
1098 // FIXME: it might only need to be imported into scope, not implemented.
1099 "implement".to_string()
1101 let mut use_note = true;
1102 if let [trait_info] = &candidates[..] {
1103 if let Some(span) = self.tcx.hir().span_if_local(trait_info.def_id) {
1105 self.tcx.sess.source_map().def_span(span),
1107 "`{}` defines an item `{}`, perhaps you need to {} it",
1108 self.tcx.def_path_str(trait_info.def_id),
1117 let mut msg = message(action);
1118 for (i, trait_info) in candidates.iter().enumerate() {
1119 msg.push_str(&format!(
1120 "\ncandidate #{}: `{}`",
1122 self.tcx.def_path_str(trait_info.def_id),
1131 /// Checks whether there is a local type somewhere in the chain of
1132 /// autoderefs of `rcvr_ty`.
1133 fn type_derefs_to_local(&self, span: Span, rcvr_ty: Ty<'tcx>, source: SelfSource<'_>) -> bool {
1134 fn is_local(ty: Ty<'_>) -> bool {
1136 ty::Adt(def, _) => def.did.is_local(),
1137 ty::Foreign(did) => did.is_local(),
1139 ty::Dynamic(ref tr, ..) => {
1140 tr.principal().map(|d| d.def_id().is_local()).unwrap_or(false)
1143 ty::Param(_) => true,
1145 // Everything else (primitive types, etc.) is effectively
1146 // non-local (there are "edge" cases, e.g., `(LocalType,)`, but
1147 // the noise from these sort of types is usually just really
1148 // annoying, rather than any sort of help).
1153 // This occurs for UFCS desugaring of `T::method`, where there is no
1154 // receiver expression for the method call, and thus no autoderef.
1155 if let SelfSource::QPath(_) = source {
1156 return is_local(self.resolve_vars_with_obligations(rcvr_ty));
1159 self.autoderef(span, rcvr_ty).any(|(ty, _)| is_local(ty))
1163 #[derive(Copy, Clone)]
1164 pub enum SelfSource<'a> {
1165 QPath(&'a hir::Ty<'a>),
1166 MethodCall(&'a hir::Expr<'a> /* rcvr */),
1169 #[derive(Copy, Clone)]
1170 pub struct TraitInfo {
1174 impl PartialEq for TraitInfo {
1175 fn eq(&self, other: &TraitInfo) -> bool {
1176 self.cmp(other) == Ordering::Equal
1179 impl Eq for TraitInfo {}
1180 impl PartialOrd for TraitInfo {
1181 fn partial_cmp(&self, other: &TraitInfo) -> Option<Ordering> {
1182 Some(self.cmp(other))
1185 impl Ord for TraitInfo {
1186 fn cmp(&self, other: &TraitInfo) -> Ordering {
1187 // Local crates are more important than remote ones (local:
1188 // `cnum == 0`), and otherwise we throw in the defid for totality.
1190 let lhs = (other.def_id.krate, other.def_id);
1191 let rhs = (self.def_id.krate, self.def_id);
1196 /// Retrieves all traits in this crate and any dependent crates.
1197 pub fn all_traits(tcx: TyCtxt<'_>) -> Vec<TraitInfo> {
1198 tcx.all_traits(LOCAL_CRATE).iter().map(|&def_id| TraitInfo { def_id }).collect()
1201 /// Computes all traits in this crate and any dependent crates.
1202 fn compute_all_traits(tcx: TyCtxt<'_>) -> Vec<DefId> {
1203 use hir::itemlikevisit;
1205 let mut traits = vec![];
1209 struct Visitor<'a, 'tcx> {
1210 map: &'a hir_map::Map<'tcx>,
1211 traits: &'a mut Vec<DefId>,
1214 impl<'v, 'a, 'tcx> itemlikevisit::ItemLikeVisitor<'v> for Visitor<'a, 'tcx> {
1215 fn visit_item(&mut self, i: &'v hir::Item<'v>) {
1217 hir::ItemKind::Trait(..) | hir::ItemKind::TraitAlias(..) => {
1218 let def_id = self.map.local_def_id(i.hir_id);
1219 self.traits.push(def_id);
1225 fn visit_trait_item(&mut self, _trait_item: &hir::TraitItem<'_>) {}
1227 fn visit_impl_item(&mut self, _impl_item: &hir::ImplItem<'_>) {}
1230 tcx.hir().krate().visit_all_item_likes(&mut Visitor { map: &tcx.hir(), traits: &mut traits });
1234 let mut external_mods = FxHashSet::default();
1235 fn handle_external_res(
1237 traits: &mut Vec<DefId>,
1238 external_mods: &mut FxHashSet<DefId>,
1242 Res::Def(DefKind::Trait, def_id) | Res::Def(DefKind::TraitAlias, def_id) => {
1243 traits.push(def_id);
1245 Res::Def(DefKind::Mod, def_id) => {
1246 if !external_mods.insert(def_id) {
1249 for child in tcx.item_children(def_id).iter() {
1250 handle_external_res(tcx, traits, external_mods, child.res)
1256 for &cnum in tcx.crates().iter() {
1257 let def_id = DefId { krate: cnum, index: CRATE_DEF_INDEX };
1258 handle_external_res(tcx, &mut traits, &mut external_mods, Res::Def(DefKind::Mod, def_id));
1264 pub fn provide(providers: &mut ty::query::Providers<'_>) {
1265 providers.all_traits = |tcx, cnum| {
1266 assert_eq!(cnum, LOCAL_CRATE);
1267 &tcx.arena.alloc(compute_all_traits(tcx))[..]
1271 struct UsePlacementFinder<'tcx> {
1272 target_module: hir::HirId,
1278 impl UsePlacementFinder<'tcx> {
1281 krate: &'tcx hir::Crate<'tcx>,
1282 target_module: hir::HirId,
1283 ) -> (Option<Span>, bool) {
1284 let mut finder = UsePlacementFinder { target_module, span: None, found_use: false, tcx };
1285 intravisit::walk_crate(&mut finder, krate);
1286 (finder.span, finder.found_use)
1290 impl intravisit::Visitor<'tcx> for UsePlacementFinder<'tcx> {
1291 fn visit_mod(&mut self, module: &'tcx hir::Mod<'tcx>, _: Span, hir_id: hir::HirId) {
1292 if self.span.is_some() {
1295 if hir_id != self.target_module {
1296 intravisit::walk_mod(self, module, hir_id);
1299 // Find a `use` statement.
1300 for item_id in module.item_ids {
1301 let item = self.tcx.hir().expect_item(item_id.id);
1303 hir::ItemKind::Use(..) => {
1304 // Don't suggest placing a `use` before the prelude
1305 // import or other generated ones.
1306 if !item.span.from_expansion() {
1307 self.span = Some(item.span.shrink_to_lo());
1308 self.found_use = true;
1312 // Don't place `use` before `extern crate`...
1313 hir::ItemKind::ExternCrate(_) => {}
1314 // ...but do place them before the first other item.
1316 if self.span.map_or(true, |span| item.span < span) {
1317 if !item.span.from_expansion() {
1318 // Don't insert between attributes and an item.
1319 if item.attrs.is_empty() {
1320 self.span = Some(item.span.shrink_to_lo());
1322 // Find the first attribute on the item.
1323 for attr in item.attrs {
1324 if self.span.map_or(true, |span| attr.span < span) {
1325 self.span = Some(attr.span.shrink_to_lo());
1336 type Map = Map<'tcx>;
1338 fn nested_visit_map(&mut self) -> intravisit::NestedVisitorMap<'_, Self::Map> {
1339 intravisit::NestedVisitorMap::None
1343 fn print_disambiguation_help(
1344 item_name: ast::Ident,
1345 args: Option<&'tcx [hir::Expr<'tcx>]>,
1346 err: &mut DiagnosticBuilder<'_>,
1349 kind: ty::AssocKind,
1351 candidate: Option<usize>,
1352 source_map: &source_map::SourceMap,
1354 let mut applicability = Applicability::MachineApplicable;
1355 let sugg_args = if let (ty::AssocKind::Method, Some(args)) = (kind, args) {
1358 if rcvr_ty.is_region_ptr() {
1359 if rcvr_ty.is_mutable_ptr() { "&mut " } else { "&" }
1364 .map(|arg| source_map.span_to_snippet(arg.span).unwrap_or_else(|_| {
1365 applicability = Applicability::HasPlaceholders;
1368 .collect::<Vec<_>>()
1374 let sugg = format!("{}::{}{}", trait_name, item_name, sugg_args);
1375 err.span_suggestion(
1378 "disambiguate the {} for {}",
1379 kind.suggestion_descr(),
1380 if let Some(candidate) = candidate {
1381 format!("candidate #{}", candidate)
1383 "the candidate".to_string()