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
::LangItem
;
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(LangItem
::FnOnce
) {
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(),
395 if let Mode
::MethodCall
= mode
{
396 if let SelfSource
::MethodCall(call
) = source
{
397 self.suggest_await_before_method(
398 &mut err
, item_name
, actual
, call
, span
,
403 tcx
.sess
.confused_type_with_std_module
.borrow().get(&span
)
405 if let Ok(snippet
) = tcx
.sess
.source_map().span_to_snippet(*span
) {
408 "you are looking for the module in `std`, \
409 not the primitive type",
410 format
!("std::{}", snippet
),
411 Applicability
::MachineApplicable
,
415 if let ty
::RawPtr(_
) = &actual
.kind() {
417 "try using `<*const T>::as_ref()` to get a reference to the \
418 type behind the pointer: https://doc.rust-lang.org/std/\
419 primitive.pointer.html#method.as_ref",
422 "using `<*const T>::as_ref()` on a pointer \
423 which is unaligned or points to invalid \
424 or uninitialized memory is undefined behavior",
430 tcx
.sess
.diagnostic().struct_dummy()
433 if let Some(def
) = actual
.ty_adt_def() {
434 if let Some(full_sp
) = tcx
.hir().span_if_local(def
.did
) {
435 let def_sp
= tcx
.sess
.source_map().guess_head_span(full_sp
);
439 "{} `{}` not found {}",
442 if def
.is_enum() && !is_method { "here" }
else { "for this" }
448 // If the method name is the name of a field with a function or closure type,
449 // give a helping note that it has to be called as `(x.f)(...)`.
450 if let SelfSource
::MethodCall(expr
) = source
{
452 self.autoderef(span
, rcvr_ty
).find_map(|(ty
, _
)| match ty
.kind() {
453 ty
::Adt(def
, substs
) if !def
.is_enum() => {
454 let variant
= &def
.non_enum_variant();
455 self.tcx
.find_field_index(item_name
, variant
).map(|index
| {
456 let field
= &variant
.fields
[index
];
457 let field_ty
= field
.ty(tcx
, substs
);
464 if let Some((field
, field_ty
)) = field_receiver
{
465 let scope
= self.tcx
.parent_module(self.body_id
).to_def_id();
466 let is_accessible
= field
.vis
.is_accessible_from(scope
, self.tcx
);
469 if self.is_fn_ty(&field_ty
, span
) {
470 let expr_span
= expr
.span
.to(item_name
.span
);
471 err
.multipart_suggestion(
473 "to call the function stored in `{}`, \
474 surround the field access with parentheses",
478 (expr_span
.shrink_to_lo(), '
('
.to_string()),
479 (expr_span
.shrink_to_hi(), '
)'
.to_string()),
481 Applicability
::MachineApplicable
,
487 .expect_expr(self.tcx
.hir().get_parent_node(expr
.hir_id
));
489 if let Some(span
) = call_expr
.span
.trim_start(item_name
.span
) {
492 "remove the arguments",
494 Applicability
::MaybeIncorrect
,
500 let field_kind
= if is_accessible { "field" }
else { "private field" }
;
501 err
.span_label(item_name
.span
, format
!("{}, not a method", field_kind
));
502 } else if lev_candidate
.is_none() && static_sources
.is_empty() {
503 err
.span_label(span
, format
!("{} not found in `{}`", item_kind
, ty_str
));
504 self.tcx
.sess
.trait_methods_not_found
.borrow_mut().insert(orig_span
);
507 err
.span_label(span
, format
!("{} not found in `{}`", item_kind
, ty_str
));
508 self.tcx
.sess
.trait_methods_not_found
.borrow_mut().insert(orig_span
);
511 if self.is_fn_ty(&rcvr_ty
, span
) {
512 macro_rules
! report_function
{
513 ($span
:expr
, $name
:expr
) => {
515 "`{}` is a function, perhaps you wish to call it",
521 if let SelfSource
::MethodCall(expr
) = source
{
522 if let Ok(expr_string
) = tcx
.sess
.source_map().span_to_snippet(expr
.span
) {
523 report_function
!(expr
.span
, expr_string
);
524 } else if let ExprKind
::Path(QPath
::Resolved(_
, ref path
)) = expr
.kind
{
525 if let Some(segment
) = path
.segments
.last() {
526 report_function
!(expr
.span
, segment
.ident
);
532 if !static_sources
.is_empty() {
534 "found the following associated functions; to be used as methods, \
535 functions must have a `self` parameter",
537 err
.span_label(span
, "this is an associated function, not a method");
539 if static_sources
.len() == 1 {
540 let ty_str
= if let Some(CandidateSource
::ImplSource(impl_did
)) =
541 static_sources
.get(0)
543 // When the "method" is resolved through dereferencing, we really want the
544 // original type that has the associated function for accurate suggestions.
546 let ty
= tcx
.at(span
).type_of(*impl_did
);
547 match (&ty
.peel_refs().kind(), &actual
.peel_refs().kind()) {
548 (ty
::Adt(def
, _
), ty
::Adt(def_actual
, _
)) if def
== def_actual
=> {
549 // Use `actual` as it will have more `substs` filled in.
550 self.ty_to_value_string(actual
.peel_refs())
552 _
=> self.ty_to_value_string(ty
.peel_refs()),
555 self.ty_to_value_string(actual
.peel_refs())
557 if let SelfSource
::MethodCall(expr
) = source
{
560 "use associated function syntax instead",
561 format
!("{}::{}", ty_str
, item_name
),
562 Applicability
::MachineApplicable
,
565 err
.help(&format
!("try with `{}::{}`", ty_str
, item_name
,));
568 report_candidates(span
, &mut err
, static_sources
, sugg_span
);
569 } else if static_sources
.len() > 1 {
570 report_candidates(span
, &mut err
, static_sources
, sugg_span
);
573 let mut restrict_type_params
= false;
574 if !unsatisfied_predicates
.is_empty() {
575 let def_span
= |def_id
| {
576 self.tcx
.sess
.source_map().guess_head_span(self.tcx
.def_span(def_id
))
578 let mut type_params
= FxHashMap
::default();
579 let mut bound_spans
= vec
![];
581 let mut collect_type_param_suggestions
=
582 |self_ty
: Ty
<'tcx
>, parent_pred
: &ty
::Predicate
<'tcx
>, obligation
: &str| {
583 // We don't care about regions here, so it's fine to skip the binder here.
584 if let (ty
::Param(_
), ty
::PredicateAtom
::Trait(p
, _
)) =
585 (self_ty
.kind(), parent_pred
.skip_binders())
587 if let ty
::Adt(def
, _
) = p
.trait_ref
.self_ty().kind() {
588 let node
= def
.did
.as_local().map(|def_id
| {
591 .get(self.tcx
.hir().local_def_id_to_hir_id(def_id
))
593 if let Some(hir
::Node
::Item(hir
::Item { kind, .. }
)) = node
{
594 if let Some(g
) = kind
.generics() {
595 let key
= match &g
.where_clause
.predicates
[..] {
596 [.., pred
] => (pred
.span().shrink_to_hi(), false),
599 .span_for_predicates_or_empty_place(),
605 .or_insert_with(FxHashSet
::default)
606 .insert(obligation
.to_owned());
612 let mut bound_span_label
= |self_ty
: Ty
<'_
>, obligation
: &str, quiet
: &str| {
614 "doesn't satisfy `{}`",
615 if obligation
.len() > 50 { quiet }
else { obligation }
617 match &self_ty
.kind() {
618 // Point at the type that couldn't satisfy the bound.
619 ty
::Adt(def
, _
) => bound_spans
.push((def_span(def
.did
), msg
)),
620 // Point at the trait object that couldn't satisfy the bound.
621 ty
::Dynamic(preds
, _
) => {
622 for pred
in preds
.skip_binder() {
624 ty
::ExistentialPredicate
::Trait(tr
) => {
625 bound_spans
.push((def_span(tr
.def_id
), msg
.clone()))
627 ty
::ExistentialPredicate
::Projection(_
)
628 | ty
::ExistentialPredicate
::AutoTrait(_
) => {}
632 // Point at the closure that couldn't satisfy the bound.
633 ty
::Closure(def_id
, _
) => bound_spans
634 .push((def_span(*def_id
), format
!("doesn't satisfy `{}`", quiet
))),
638 let mut format_pred
= |pred
: ty
::Predicate
<'tcx
>| {
639 let bound_predicate
= pred
.bound_atom();
640 match bound_predicate
.skip_binder() {
641 ty
::PredicateAtom
::Projection(pred
) => {
642 let pred
= bound_predicate
.rebind(pred
);
643 // `<Foo as Iterator>::Item = String`.
645 pred
.skip_binder().projection_ty
.trait_ref(self.tcx
);
648 .associated_item(pred
.skip_binder().projection_ty
.item_def_id
);
649 let ty
= pred
.skip_binder().ty
;
650 let obligation
= format
!("{}::{} = {}", trait_ref
, assoc
.ident
, ty
);
652 "<_ as {}>::{} = {}",
653 trait_ref
.print_only_trait_path(),
657 bound_span_label(trait_ref
.self_ty(), &obligation
, &quiet
);
658 Some((obligation
, trait_ref
.self_ty()))
660 ty
::PredicateAtom
::Trait(poly_trait_ref
, _
) => {
661 let p
= poly_trait_ref
.trait_ref
;
662 let self_ty
= p
.self_ty();
663 let path
= p
.print_only_trait_path();
664 let obligation
= format
!("{}: {}", self_ty
, path
);
665 let quiet
= format
!("_: {}", path
);
666 bound_span_label(self_ty
, &obligation
, &quiet
);
667 Some((obligation
, self_ty
))
672 let mut bound_list
= unsatisfied_predicates
674 .filter_map(|(pred
, parent_pred
)| {
675 format_pred(*pred
).map(|(p
, self_ty
)| match parent_pred
{
676 None
=> format
!("`{}`", p
),
677 Some(parent_pred
) => match format_pred(*parent_pred
) {
678 None
=> format
!("`{}`", p
),
679 Some((parent_p
, _
)) => {
680 collect_type_param_suggestions(self_ty
, parent_pred
, &p
);
681 format
!("`{}`\nwhich is required by `{}`", p
, parent_p
)
687 .collect
::<Vec
<(usize, String
)>>();
688 for ((span
, empty_where
), obligations
) in type_params
.into_iter() {
689 restrict_type_params
= true;
690 // #74886: Sort here so that the output is always the same.
691 let mut obligations
= obligations
.into_iter().collect
::<Vec
<_
>>();
693 err
.span_suggestion_verbose(
696 "consider restricting the type parameter{s} to satisfy the \
698 s
= pluralize
!(obligations
.len())
702 if empty_where { " where" }
else { "," }
,
703 obligations
.join(", ")
705 Applicability
::MaybeIncorrect
,
709 bound_list
.sort_by(|(_
, a
), (_
, b
)| a
.cmp(&b
)); // Sort alphabetically.
710 bound_list
.dedup_by(|(_
, a
), (_
, b
)| a
== b
); // #35677
711 bound_list
.sort_by_key(|(pos
, _
)| *pos
); // Keep the original predicate order.
714 for (span
, msg
) in bound_spans
.into_iter() {
715 err
.span_label(span
, &msg
);
717 if !bound_list
.is_empty() {
718 let bound_list
= bound_list
720 .map(|(_
, path
)| path
)
724 "the method `{}` exists but the following trait bounds were not \
726 item_name
, bound_list
731 if actual
.is_numeric() && actual
.is_fresh() || restrict_type_params
{
733 self.suggest_traits_to_import(
740 &unsatisfied_predicates
,
744 if actual
.is_enum() {
745 let adt_def
= actual
.ty_adt_def().expect("enum is not an ADT");
746 if let Some(suggestion
) = lev_distance
::find_best_match_for_name(
747 adt_def
.variants
.iter().map(|s
| &s
.ident
.name
),
753 "there is a variant with a similar name",
754 suggestion
.to_string(),
755 Applicability
::MaybeIncorrect
,
760 let mut fallback_span
= true;
761 let msg
= "remove this method call";
762 if item_name
.name
== sym
::as_str
&& actual
.peel_refs().is_str() {
763 if let SelfSource
::MethodCall(expr
) = source
{
765 self.tcx
.hir().expect_expr(self.tcx
.hir().get_parent_node(expr
.hir_id
));
766 if let Some(span
) = call_expr
.span
.trim_start(expr
.span
) {
771 Applicability
::MachineApplicable
,
773 fallback_span
= false;
777 err
.span_label(span
, msg
);
779 } else if let Some(lev_candidate
) = lev_candidate
{
780 let def_kind
= lev_candidate
.kind
.as_def_kind();
784 "there is {} {} with a similar name",
786 def_kind
.descr(lev_candidate
.def_id
),
788 lev_candidate
.ident
.to_string(),
789 Applicability
::MaybeIncorrect
,
796 MethodError
::Ambiguity(sources
) => {
797 let mut err
= struct_span_err
!(
801 "multiple applicable items in scope"
803 err
.span_label(item_name
.span
, format
!("multiple `{}` found", item_name
));
805 report_candidates(span
, &mut err
, sources
, sugg_span
);
809 MethodError
::PrivateMatch(kind
, def_id
, out_of_scope_traits
) => {
810 let kind
= kind
.descr(def_id
);
811 let mut err
= struct_span_err
!(
815 "{} `{}` is private",
819 err
.span_label(item_name
.span
, &format
!("private {}", kind
));
820 self.suggest_valid_traits(&mut err
, out_of_scope_traits
);
824 MethodError
::IllegalSizedBound(candidates
, needs_mut
, bound_span
) => {
825 let msg
= format
!("the `{}` method cannot be invoked on a trait object", item_name
);
826 let mut err
= self.sess().struct_span_err(span
, &msg
);
827 err
.span_label(bound_span
, "this has a `Sized` requirement");
828 if !candidates
.is_empty() {
830 "{an}other candidate{s} {were} found in the following trait{s}, perhaps \
831 add a `use` for {one_of_them}:",
832 an
= if candidates
.len() == 1 { "an" }
else { "" }
,
833 s
= pluralize
!(candidates
.len()),
834 were
= if candidates
.len() == 1 { "was" }
else { "were" }
,
835 one_of_them
= if candidates
.len() == 1 { "it" }
else { "one_of_them" }
,
837 self.suggest_use_candidates(&mut err
, help
, candidates
);
839 if let ty
::Ref(region
, t_type
, mutability
) = rcvr_ty
.kind() {
841 let trait_type
= self.tcx
.mk_ref(
843 ty
::TypeAndMut { ty: t_type, mutbl: mutability.invert() }
,
845 err
.note(&format
!("you need `{}` instead of `{}`", trait_type
, rcvr_ty
));
851 MethodError
::BadReturnType
=> bug
!("no return type expectations but got BadReturnType"),
856 /// Print out the type for use in value namespace.
857 fn ty_to_value_string(&self, ty
: Ty
<'tcx
>) -> String
{
859 ty
::Adt(def
, substs
) => format
!("{}", ty
::Instance
::new(def
.did
, substs
)),
860 _
=> self.ty_to_string(ty
),
864 fn suggest_await_before_method(
866 err
: &mut DiagnosticBuilder
<'_
>,
869 call
: &hir
::Expr
<'_
>,
872 let output_ty
= match self.infcx
.get_impl_future_output_ty(ty
) {
873 Some(output_ty
) => self.resolve_vars_if_possible(&output_ty
),
876 let method_exists
= self.method_exists(item_name
, output_ty
, call
.hir_id
, true);
877 debug
!("suggest_await_before_method: is_method_exist={}", method_exists
);
879 err
.span_suggestion_verbose(
881 "consider `await`ing on the `Future` and calling the method on its `Output`",
882 "await.".to_string(),
883 Applicability
::MaybeIncorrect
,
888 fn suggest_use_candidates(
890 err
: &mut DiagnosticBuilder
<'_
>,
892 candidates
: Vec
<DefId
>,
894 let module_did
= self.tcx
.parent_module(self.body_id
);
895 let module_id
= self.tcx
.hir().local_def_id_to_hir_id(module_did
);
896 let krate
= self.tcx
.hir().krate();
897 let (span
, found_use
) = UsePlacementFinder
::check(self.tcx
, krate
, module_id
);
898 if let Some(span
) = span
{
899 let path_strings
= candidates
.iter().map(|did
| {
900 // Produce an additional newline to separate the new use statement
901 // from the directly following item.
902 let additional_newline
= if found_use { "" }
else { "\n" }
;
905 with_crate_prefix(|| self.tcx
.def_path_str(*did
)),
910 err
.span_suggestions(span
, &msg
, path_strings
, Applicability
::MaybeIncorrect
);
912 let limit
= if candidates
.len() == 5 { 5 }
else { 4 }
;
913 for (i
, trait_did
) in candidates
.iter().take(limit
).enumerate() {
914 if candidates
.len() > 1 {
915 msg
.push_str(&format
!(
916 "\ncandidate #{}: `use {};`",
918 with_crate_prefix(|| self.tcx
.def_path_str(*trait_did
))
921 msg
.push_str(&format
!(
923 with_crate_prefix(|| self.tcx
.def_path_str(*trait_did
))
927 if candidates
.len() > limit
{
928 msg
.push_str(&format
!("\nand {} others", candidates
.len() - limit
));
934 fn suggest_valid_traits(
936 err
: &mut DiagnosticBuilder
<'_
>,
937 valid_out_of_scope_traits
: Vec
<DefId
>,
939 if !valid_out_of_scope_traits
.is_empty() {
940 let mut candidates
= valid_out_of_scope_traits
;
943 err
.help("items from traits can only be used if the trait is in scope");
945 "the following {traits_are} implemented but not in scope; \
946 perhaps add a `use` for {one_of_them}:",
947 traits_are
= if candidates
.len() == 1 { "trait is" }
else { "traits are" }
,
948 one_of_them
= if candidates
.len() == 1 { "it" }
else { "one of them" }
,
951 self.suggest_use_candidates(err
, msg
, candidates
);
958 fn suggest_traits_to_import
<'b
>(
960 err
: &mut DiagnosticBuilder
<'_
>,
964 source
: SelfSource
<'b
>,
965 valid_out_of_scope_traits
: Vec
<DefId
>,
966 unsatisfied_predicates
: &[(ty
::Predicate
<'tcx
>, Option
<ty
::Predicate
<'tcx
>>)],
968 if self.suggest_valid_traits(err
, valid_out_of_scope_traits
) {
972 let type_is_local
= self.type_derefs_to_local(span
, rcvr_ty
, source
);
974 let mut arbitrary_rcvr
= vec
![];
975 // There are no traits implemented, so lets suggest some traits to
976 // implement, by finding ones that have the item name, and are
977 // legal to implement.
978 let mut candidates
= all_traits(self.tcx
)
980 // Don't issue suggestions for unstable traits since they're
981 // unlikely to be implementable anyway
982 .filter(|info
| match self.tcx
.lookup_stability(info
.def_id
) {
983 Some(attr
) => attr
.level
.is_stable(),
987 // We approximate the coherence rules to only suggest
988 // traits that are legal to implement by requiring that
989 // either the type or trait is local. Multi-dispatch means
990 // this isn't perfect (that is, there are cases when
991 // implementing a trait would be legal but is rejected
993 unsatisfied_predicates
.iter().all(|(p
, _
)| {
994 match p
.skip_binders() {
995 // Hide traits if they are present in predicates as they can be fixed without
996 // having to implement them.
997 ty
::PredicateAtom
::Trait(t
, _
) => t
.def_id() == info
.def_id
,
998 ty
::PredicateAtom
::Projection(p
) => {
999 p
.projection_ty
.item_def_id
== info
.def_id
1003 }) && (type_is_local
|| info
.def_id
.is_local())
1005 .associated_item(info
.def_id
, item_name
, Namespace
::ValueNS
)
1007 if let ty
::AssocKind
::Fn
= item
.kind
{
1011 .map(|def_id
| self.tcx
.hir().local_def_id_to_hir_id(def_id
));
1012 if let Some(hir
::Node
::TraitItem(hir
::TraitItem
{
1013 kind
: hir
::TraitItemKind
::Fn(fn_sig
, method
),
1015 })) = id
.map(|id
| self.tcx
.hir().get(id
))
1017 let self_first_arg
= match method
{
1018 hir
::TraitFn
::Required([ident
, ..]) => {
1019 ident
.name
== kw
::SelfLower
1021 hir
::TraitFn
::Provided(body_id
) => {
1022 self.tcx
.hir().body(*body_id
).params
.first().map_or(
1027 hir
::PatKind
::Binding(_
, _
, ident
, _
)
1028 if ident
.name
== kw
::SelfLower
1036 if !fn_sig
.decl
.implicit_self
.has_implicit_self()
1039 if let Some(ty
) = fn_sig
.decl
.inputs
.get(0) {
1040 arbitrary_rcvr
.push(ty
.span
);
1046 // We only want to suggest public or local traits (#45781).
1047 item
.vis
== ty
::Visibility
::Public
|| info
.def_id
.is_local()
1051 .collect
::<Vec
<_
>>();
1052 for span
in &arbitrary_rcvr
{
1055 "the method might not be found because of this arbitrary self type",
1059 if !candidates
.is_empty() {
1060 // Sort from most relevant to least relevant.
1061 candidates
.sort_by(|a
, b
| a
.cmp(b
).reverse());
1064 let param_type
= match rcvr_ty
.kind() {
1065 ty
::Param(param
) => Some(param
),
1066 ty
::Ref(_
, ty
, _
) => match ty
.kind() {
1067 ty
::Param(param
) => Some(param
),
1072 err
.help(if param_type
.is_some() {
1073 "items from traits can only be used if the type parameter is bounded by the trait"
1075 "items from traits can only be used if the trait is implemented and in scope"
1077 let message
= |action
| {
1079 "the following {traits_define} an item `{name}`, perhaps you need to {action} \
1082 if candidates
.len() == 1 { "trait defines" }
else { "traits define" }
,
1084 one_of_them
= if candidates
.len() == 1 { "it" }
else { "one of them" }
,
1088 // Obtain the span for `param` and use it for a structured suggestion.
1089 let mut suggested
= false;
1090 if let (Some(ref param
), Some(ref table
)) =
1091 (param_type
, self.in_progress_typeck_results
)
1093 let table_owner
= table
.borrow().hir_owner
;
1094 let generics
= self.tcx
.generics_of(table_owner
.to_def_id());
1095 let type_param
= generics
.type_param(param
, self.tcx
);
1096 let hir
= &self.tcx
.hir();
1097 if let Some(def_id
) = type_param
.def_id
.as_local() {
1098 let id
= hir
.local_def_id_to_hir_id(def_id
);
1099 // Get the `hir::Param` to verify whether it already has any bounds.
1100 // We do this to avoid suggesting code that ends up as `T: FooBar`,
1101 // instead we suggest `T: Foo + Bar` in that case.
1103 Node
::GenericParam(ref param
) => {
1104 let mut impl_trait
= false;
1106 if let hir
::GenericParamKind
::Type { synthetic: Some(_), .. }
=
1109 // We've found `fn foo(x: impl Trait)` instead of
1110 // `fn foo<T>(x: T)`. We want to suggest the correct
1111 // `fn foo(x: impl Trait + TraitBound)` instead of
1112 // `fn foo<T: TraitBound>(x: T)`. (#63706)
1118 let sp
= hir
.span(id
);
1119 let sp
= if let Some(first_bound
) = has_bounds
{
1120 // `sp` only covers `T`, change it so that it covers
1121 // `T:` when appropriate
1122 sp
.until(first_bound
.span())
1126 let trait_def_ids
: FxHashSet
<DefId
> = param
1129 .filter_map(|bound
| Some(bound
.trait_ref()?
.trait_def_id()?
))
1131 if !candidates
.iter().any(|t
| trait_def_ids
.contains(&t
.def_id
)) {
1132 err
.span_suggestions(
1135 "restrict type parameter `{}` with",
1138 candidates
.iter().map(|t
| {
1142 if impl_trait { " +" }
else { ":" }
,
1143 self.tcx
.def_path_str(t
.def_id
),
1144 if has_bounds
.is_some() { " + " }
else { "" }
,
1147 Applicability
::MaybeIncorrect
,
1152 Node
::Item(hir
::Item
{
1153 kind
: hir
::ItemKind
::Trait(.., bounds
, _
),
1157 let (sp
, sep
, article
) = if bounds
.is_empty() {
1158 (ident
.span
.shrink_to_hi(), ":", "a")
1160 (bounds
.last().unwrap().span().shrink_to_hi(), " +", "another")
1162 err
.span_suggestions(
1164 &message(format
!("add {} supertrait for", article
)),
1165 candidates
.iter().map(|t
| {
1166 format
!("{} {}", sep
, self.tcx
.def_path_str(t
.def_id
),)
1168 Applicability
::MaybeIncorrect
,
1178 let action
= if let Some(param
) = param_type
{
1179 format
!("restrict type parameter `{}` with", param
)
1181 // FIXME: it might only need to be imported into scope, not implemented.
1182 "implement".to_string()
1184 let mut use_note
= true;
1185 if let [trait_info
] = &candidates
[..] {
1186 if let Some(span
) = self.tcx
.hir().span_if_local(trait_info
.def_id
) {
1188 self.tcx
.sess
.source_map().guess_head_span(span
),
1190 "`{}` defines an item `{}`, perhaps you need to {} it",
1191 self.tcx
.def_path_str(trait_info
.def_id
),
1200 let mut msg
= message(action
);
1201 for (i
, trait_info
) in candidates
.iter().enumerate() {
1202 msg
.push_str(&format
!(
1203 "\ncandidate #{}: `{}`",
1205 self.tcx
.def_path_str(trait_info
.def_id
),
1214 /// Checks whether there is a local type somewhere in the chain of
1215 /// autoderefs of `rcvr_ty`.
1216 fn type_derefs_to_local(&self, span
: Span
, rcvr_ty
: Ty
<'tcx
>, source
: SelfSource
<'_
>) -> bool
{
1217 fn is_local(ty
: Ty
<'_
>) -> bool
{
1219 ty
::Adt(def
, _
) => def
.did
.is_local(),
1220 ty
::Foreign(did
) => did
.is_local(),
1222 ty
::Dynamic(ref tr
, ..) => {
1223 tr
.principal().map(|d
| d
.def_id().is_local()).unwrap_or(false)
1226 ty
::Param(_
) => true,
1228 // Everything else (primitive types, etc.) is effectively
1229 // non-local (there are "edge" cases, e.g., `(LocalType,)`, but
1230 // the noise from these sort of types is usually just really
1231 // annoying, rather than any sort of help).
1236 // This occurs for UFCS desugaring of `T::method`, where there is no
1237 // receiver expression for the method call, and thus no autoderef.
1238 if let SelfSource
::QPath(_
) = source
{
1239 return is_local(self.resolve_vars_with_obligations(rcvr_ty
));
1242 self.autoderef(span
, rcvr_ty
).any(|(ty
, _
)| is_local(ty
))
1246 #[derive(Copy, Clone)]
1247 pub enum SelfSource
<'a
> {
1248 QPath(&'a hir
::Ty
<'a
>),
1249 MethodCall(&'a hir
::Expr
<'a
> /* rcvr */),
1252 #[derive(Copy, Clone)]
1253 pub struct TraitInfo
{
1257 impl PartialEq
for TraitInfo
{
1258 fn eq(&self, other
: &TraitInfo
) -> bool
{
1259 self.cmp(other
) == Ordering
::Equal
1262 impl Eq
for TraitInfo {}
1263 impl PartialOrd
for TraitInfo
{
1264 fn partial_cmp(&self, other
: &TraitInfo
) -> Option
<Ordering
> {
1265 Some(self.cmp(other
))
1268 impl Ord
for TraitInfo
{
1269 fn cmp(&self, other
: &TraitInfo
) -> Ordering
{
1270 // Local crates are more important than remote ones (local:
1271 // `cnum == 0`), and otherwise we throw in the defid for totality.
1273 let lhs
= (other
.def_id
.krate
, other
.def_id
);
1274 let rhs
= (self.def_id
.krate
, self.def_id
);
1279 /// Retrieves all traits in this crate and any dependent crates.
1280 pub fn all_traits(tcx
: TyCtxt
<'_
>) -> Vec
<TraitInfo
> {
1281 tcx
.all_traits(LOCAL_CRATE
).iter().map(|&def_id
| TraitInfo { def_id }
).collect()
1284 /// Computes all traits in this crate and any dependent crates.
1285 fn compute_all_traits(tcx
: TyCtxt
<'_
>) -> Vec
<DefId
> {
1286 use hir
::itemlikevisit
;
1288 let mut traits
= vec
![];
1292 struct Visitor
<'a
, 'tcx
> {
1293 map
: &'a hir_map
::Map
<'tcx
>,
1294 traits
: &'a
mut Vec
<DefId
>,
1297 impl<'v
, 'a
, 'tcx
> itemlikevisit
::ItemLikeVisitor
<'v
> for Visitor
<'a
, 'tcx
> {
1298 fn visit_item(&mut self, i
: &'v hir
::Item
<'v
>) {
1300 hir
::ItemKind
::Trait(..) | hir
::ItemKind
::TraitAlias(..) => {
1301 let def_id
= self.map
.local_def_id(i
.hir_id
);
1302 self.traits
.push(def_id
.to_def_id());
1308 fn visit_trait_item(&mut self, _trait_item
: &hir
::TraitItem
<'_
>) {}
1310 fn visit_impl_item(&mut self, _impl_item
: &hir
::ImplItem
<'_
>) {}
1313 tcx
.hir().krate().visit_all_item_likes(&mut Visitor { map: &tcx.hir(), traits: &mut traits }
);
1317 let mut external_mods
= FxHashSet
::default();
1318 fn handle_external_res(
1320 traits
: &mut Vec
<DefId
>,
1321 external_mods
: &mut FxHashSet
<DefId
>,
1325 Res
::Def(DefKind
::Trait
| DefKind
::TraitAlias
, def_id
) => {
1326 traits
.push(def_id
);
1328 Res
::Def(DefKind
::Mod
, def_id
) => {
1329 if !external_mods
.insert(def_id
) {
1332 for child
in tcx
.item_children(def_id
).iter() {
1333 handle_external_res(tcx
, traits
, external_mods
, child
.res
)
1339 for &cnum
in tcx
.crates().iter() {
1340 let def_id
= DefId { krate: cnum, index: CRATE_DEF_INDEX }
;
1341 handle_external_res(tcx
, &mut traits
, &mut external_mods
, Res
::Def(DefKind
::Mod
, def_id
));
1347 pub fn provide(providers
: &mut ty
::query
::Providers
) {
1348 providers
.all_traits
= |tcx
, cnum
| {
1349 assert_eq
!(cnum
, LOCAL_CRATE
);
1350 &tcx
.arena
.alloc(compute_all_traits(tcx
))[..]
1354 struct UsePlacementFinder
<'tcx
> {
1355 target_module
: hir
::HirId
,
1361 impl UsePlacementFinder
<'tcx
> {
1364 krate
: &'tcx hir
::Crate
<'tcx
>,
1365 target_module
: hir
::HirId
,
1366 ) -> (Option
<Span
>, bool
) {
1367 let mut finder
= UsePlacementFinder { target_module, span: None, found_use: false, tcx }
;
1368 intravisit
::walk_crate(&mut finder
, krate
);
1369 (finder
.span
, finder
.found_use
)
1373 impl intravisit
::Visitor
<'tcx
> for UsePlacementFinder
<'tcx
> {
1374 fn visit_mod(&mut self, module
: &'tcx hir
::Mod
<'tcx
>, _
: Span
, hir_id
: hir
::HirId
) {
1375 if self.span
.is_some() {
1378 if hir_id
!= self.target_module
{
1379 intravisit
::walk_mod(self, module
, hir_id
);
1382 // Find a `use` statement.
1383 for item_id
in module
.item_ids
{
1384 let item
= self.tcx
.hir().expect_item(item_id
.id
);
1386 hir
::ItemKind
::Use(..) => {
1387 // Don't suggest placing a `use` before the prelude
1388 // import or other generated ones.
1389 if !item
.span
.from_expansion() {
1390 self.span
= Some(item
.span
.shrink_to_lo());
1391 self.found_use
= true;
1395 // Don't place `use` before `extern crate`...
1396 hir
::ItemKind
::ExternCrate(_
) => {}
1397 // ...but do place them before the first other item.
1399 if self.span
.map_or(true, |span
| item
.span
< span
) {
1400 if !item
.span
.from_expansion() {
1401 // Don't insert between attributes and an item.
1402 if item
.attrs
.is_empty() {
1403 self.span
= Some(item
.span
.shrink_to_lo());
1405 // Find the first attribute on the item.
1406 for attr
in item
.attrs
{
1407 if self.span
.map_or(true, |span
| attr
.span
< span
) {
1408 self.span
= Some(attr
.span
.shrink_to_lo());
1419 type Map
= intravisit
::ErasedMap
<'tcx
>;
1421 fn nested_visit_map(&mut self) -> intravisit
::NestedVisitorMap
<Self::Map
> {
1422 intravisit
::NestedVisitorMap
::None
1426 fn print_disambiguation_help(
1428 args
: Option
<&'tcx
[hir
::Expr
<'tcx
>]>,
1429 err
: &mut DiagnosticBuilder
<'_
>,
1432 kind
: ty
::AssocKind
,
1435 candidate
: Option
<usize>,
1436 source_map
: &source_map
::SourceMap
,
1438 let mut applicability
= Applicability
::MachineApplicable
;
1439 let sugg_args
= if let (ty
::AssocKind
::Fn
, Some(args
)) = (kind
, args
) {
1442 if rcvr_ty
.is_region_ptr() {
1443 if rcvr_ty
.is_mutable_ptr() { "&mut " }
else { "&" }
1448 .map(|arg
| source_map
.span_to_snippet(arg
.span
).unwrap_or_else(|_
| {
1449 applicability
= Applicability
::HasPlaceholders
;
1452 .collect
::<Vec
<_
>>()
1458 let sugg
= format
!("{}::{}{}", trait_name
, item_name
, sugg_args
);
1459 err
.span_suggestion(
1462 "disambiguate the {} for {}",
1463 kind
.as_def_kind().descr(def_id
),
1464 if let Some(candidate
) = candidate
{
1465 format
!("candidate #{}", candidate
)
1467 "the candidate".to_string()