1 //! Give useful errors and suggestions to users when an item can't be
2 //! found or is otherwise invalid.
6 use rustc_ast::ast::Mutability;
7 use rustc_data_structures::fx::{FxHashMap, FxHashSet};
8 use rustc_errors::StashKey;
10 pluralize, struct_span_err, Applicability, Diagnostic, DiagnosticBuilder, ErrorGuaranteed,
14 use rustc_hir::def::DefKind;
15 use rustc_hir::def_id::DefId;
16 use rustc_hir::lang_items::LangItem;
17 use rustc_hir::PatKind::Binding;
18 use rustc_hir::PathSegment;
19 use rustc_hir::{ExprKind, Node, QPath};
20 use rustc_infer::infer::{
21 type_variable::{TypeVariableOrigin, TypeVariableOriginKind},
24 use rustc_middle::infer::unify_key::{ConstVariableOrigin, ConstVariableOriginKind};
25 use rustc_middle::traits::util::supertraits;
26 use rustc_middle::ty::fast_reject::DeepRejectCtxt;
27 use rustc_middle::ty::fast_reject::{simplify_type, TreatParams};
28 use rustc_middle::ty::print::{with_crate_prefix, with_forced_trimmed_paths};
29 use rustc_middle::ty::{self, DefIdTree, GenericArgKind, Ty, TyCtxt, TypeVisitable};
30 use rustc_middle::ty::{IsSuggestable, ToPolyTraitRef};
31 use rustc_span::symbol::{kw, sym, Ident};
32 use rustc_span::Symbol;
33 use rustc_span::{lev_distance, source_map, ExpnKind, FileName, MacroKind, Span};
34 use rustc_trait_selection::traits::error_reporting::on_unimplemented::OnUnimplementedNote;
35 use rustc_trait_selection::traits::error_reporting::on_unimplemented::TypeErrCtxtExt as _;
36 use rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt as _;
37 use rustc_trait_selection::traits::{
38 FulfillmentError, Obligation, ObligationCause, ObligationCauseCode,
41 use super::probe::{AutorefOrPtrAdjustment, IsSuggestion, Mode, ProbeScope};
42 use super::{CandidateSource, MethodError, NoMatchData};
43 use rustc_hir::intravisit::Visitor;
44 use std::cmp::Ordering;
47 impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
48 fn is_fn_ty(&self, ty: Ty<'tcx>, span: Span) -> bool {
51 // Not all of these (e.g., unsafe fns) implement `FnOnce`,
52 // so we look for these beforehand.
53 ty::Closure(..) | ty::FnDef(..) | ty::FnPtr(_) => true,
54 // If it's not a simple function, look for things which implement `FnOnce`.
56 let Some(fn_once) = tcx.lang_items().fn_once_trait() else {
60 // This conditional prevents us from asking to call errors and unresolved types.
61 // It might seem that we can use `predicate_must_hold_modulo_regions`,
62 // but since a Dummy binder is used to fill in the FnOnce trait's arguments,
63 // type resolution always gives a "maybe" here.
64 if self.autoderef(span, ty).any(|(ty, _)| {
65 info!("check deref {:?} error", ty);
66 matches!(ty.kind(), ty::Error(_) | ty::Infer(_))
71 self.autoderef(span, ty).any(|(ty, _)| {
72 info!("check deref {:?} impl FnOnce", ty);
74 let trait_ref = tcx.mk_trait_ref(
78 self.next_ty_var(TypeVariableOrigin {
79 kind: TypeVariableOriginKind::MiscVariable,
84 let poly_trait_ref = ty::Binder::dummy(trait_ref);
85 let obligation = Obligation::misc(
90 poly_trait_ref.without_const(),
92 self.predicate_may_hold(&obligation)
99 fn is_slice_ty(&self, ty: Ty<'tcx>, span: Span) -> bool {
100 self.autoderef(span, ty).any(|(ty, _)| matches!(ty.kind(), ty::Slice(..) | ty::Array(..)))
103 pub fn report_method_error(
108 source: SelfSource<'tcx>,
109 error: MethodError<'tcx>,
110 args: Option<(&'tcx hir::Expr<'tcx>, &'tcx [hir::Expr<'tcx>])>,
111 ) -> Option<DiagnosticBuilder<'_, ErrorGuaranteed>> {
112 // Avoid suggestions when we don't know what's going on.
113 if rcvr_ty.references_error() {
117 let sugg_span = if let SelfSource::MethodCall(expr) = source {
118 // Given `foo.bar(baz)`, `expr` is `bar`, but we want to point to the whole thing.
119 self.tcx.hir().expect_expr(self.tcx.hir().parent_id(expr.hir_id)).span
125 MethodError::NoMatch(mut no_match_data) => {
126 return self.report_no_match_method_error(
137 MethodError::Ambiguity(mut sources) => {
138 let mut err = struct_span_err!(
142 "multiple applicable items in scope"
144 err.span_label(item_name.span, format!("multiple `{}` found", item_name));
146 self.note_candidates_on_method_error(
158 MethodError::PrivateMatch(kind, def_id, out_of_scope_traits) => {
159 let kind = kind.descr(def_id);
160 let mut err = struct_span_err!(
164 "{} `{}` is private",
168 err.span_label(item_name.span, &format!("private {}", kind));
172 .span_if_local(def_id)
173 .unwrap_or_else(|| self.tcx.def_span(def_id));
174 err.span_label(sp, &format!("private {} defined here", kind));
175 self.suggest_valid_traits(&mut err, out_of_scope_traits);
179 MethodError::IllegalSizedBound(candidates, needs_mut, bound_span) => {
180 let msg = format!("the `{}` method cannot be invoked on a trait object", item_name);
181 let mut err = self.sess().struct_span_err(span, &msg);
182 err.span_label(bound_span, "this has a `Sized` requirement");
183 if !candidates.is_empty() {
185 "{an}other candidate{s} {were} found in the following trait{s}, perhaps \
186 add a `use` for {one_of_them}:",
187 an = if candidates.len() == 1 { "an" } else { "" },
188 s = pluralize!(candidates.len()),
189 were = pluralize!("was", candidates.len()),
190 one_of_them = if candidates.len() == 1 { "it" } else { "one_of_them" },
192 self.suggest_use_candidates(&mut err, help, candidates);
194 if let ty::Ref(region, t_type, mutability) = rcvr_ty.kind() {
196 let trait_type = self.tcx.mk_ref(
198 ty::TypeAndMut { ty: *t_type, mutbl: mutability.invert() },
200 err.note(&format!("you need `{}` instead of `{}`", trait_type, rcvr_ty));
206 MethodError::BadReturnType => bug!("no return type expectations but got BadReturnType"),
211 pub fn report_no_match_method_error(
216 source: SelfSource<'tcx>,
217 args: Option<(&'tcx hir::Expr<'tcx>, &'tcx [hir::Expr<'tcx>])>,
219 no_match_data: &mut NoMatchData<'tcx>,
220 ) -> Option<DiagnosticBuilder<'_, ErrorGuaranteed>> {
221 let mode = no_match_data.mode;
223 let rcvr_ty = self.resolve_vars_if_possible(rcvr_ty);
224 let ty_str = with_forced_trimmed_paths!(self.ty_to_string(rcvr_ty));
225 let is_method = mode == Mode::MethodCall;
226 let unsatisfied_predicates = &no_match_data.unsatisfied_predicates;
227 let lev_candidate = no_match_data.lev_candidate;
228 let item_kind = if is_method {
230 } else if rcvr_ty.is_enum() {
231 "variant or associated item"
233 match (item_name.as_str().chars().next(), rcvr_ty.is_fresh_ty()) {
234 (Some(name), false) if name.is_lowercase() => "function or associated item",
235 (Some(_), false) => "associated item",
236 (Some(_), true) | (None, false) => "variant or associated item",
237 (None, true) => "variant",
241 if self.suggest_wrapping_range_with_parens(tcx, rcvr_ty, source, span, item_name, &ty_str)
242 || self.suggest_constraining_numerical_ty(
243 tcx, rcvr_ty, source, span, item_kind, item_name, &ty_str,
248 span = item_name.span;
250 // Don't show generic arguments when the method can't be found in any implementation (#81576).
251 let mut ty_str_reported = ty_str.clone();
252 if let ty::Adt(_, generics) = rcvr_ty.kind() {
253 if generics.len() > 0 {
254 let mut autoderef = self.autoderef(span, rcvr_ty);
255 let candidate_found = autoderef.any(|(ty, _)| {
256 if let ty::Adt(adt_def, _) = ty.kind() {
258 .inherent_impls(adt_def.did())
260 .any(|def_id| self.associated_value(*def_id, item_name).is_some())
265 let has_deref = autoderef.step_count() > 0;
266 if !candidate_found && !has_deref && unsatisfied_predicates.is_empty() {
267 if let Some((path_string, _)) = ty_str.split_once('<') {
268 ty_str_reported = path_string.to_string();
274 let mut err = struct_span_err!(
278 "no {} named `{}` found for {} `{}` in the current scope",
281 rcvr_ty.prefix_string(self.tcx),
284 if rcvr_ty.references_error() {
285 err.downgrade_to_delayed_bug();
288 if let Mode::MethodCall = mode && let SelfSource::MethodCall(cal) = source {
289 self.suggest_await_before_method(
290 &mut err, item_name, rcvr_ty, cal, span,
294 tcx.resolutions(()).confused_type_with_std_module.get(&span.with_parent(None))
298 "you are looking for the module in `std`, not the primitive type",
300 Applicability::MachineApplicable,
303 if let ty::RawPtr(_) = &rcvr_ty.kind() {
305 "try using `<*const T>::as_ref()` to get a reference to the \
306 type behind the pointer: https://doc.rust-lang.org/std/\
307 primitive.pointer.html#method.as_ref",
310 "using `<*const T>::as_ref()` on a pointer which is unaligned or points \
311 to invalid or uninitialized memory is undefined behavior",
315 let ty_span = match rcvr_ty.kind() {
316 ty::Param(param_type) => {
317 Some(param_type.span_from_generics(self.tcx, self.body_id.owner.to_def_id()))
319 ty::Adt(def, _) if def.did().is_local() => Some(tcx.def_span(def.did())),
322 if let Some(span) = ty_span {
326 "{item_kind} `{item_name}` not found for this {}",
327 rcvr_ty.prefix_string(self.tcx)
332 if let SelfSource::MethodCall(rcvr_expr) = source {
333 self.suggest_fn_call(&mut err, rcvr_expr, rcvr_ty, |output_ty| {
335 self.tcx.hir().expect_expr(self.tcx.hir().parent_id(rcvr_expr.hir_id));
337 self.lookup_probe(item_name, output_ty, call_expr, ProbeScope::AllTraits);
342 let mut custom_span_label = false;
344 let static_candidates = &mut no_match_data.static_candidates;
345 if !static_candidates.is_empty() {
347 "found the following associated functions; to be used as methods, \
348 functions must have a `self` parameter",
350 err.span_label(span, "this is an associated function, not a method");
351 custom_span_label = true;
353 if static_candidates.len() == 1 {
354 self.suggest_associated_call_syntax(
364 self.note_candidates_on_method_error(
373 } else if static_candidates.len() > 1 {
374 self.note_candidates_on_method_error(
385 let mut bound_spans = vec![];
386 let mut restrict_type_params = false;
387 let mut unsatisfied_bounds = false;
388 if item_name.name == sym::count && self.is_slice_ty(rcvr_ty, span) {
389 let msg = "consider using `len` instead";
390 if let SelfSource::MethodCall(_expr) = source {
391 err.span_suggestion_short(span, msg, "len", Applicability::MachineApplicable);
393 err.span_label(span, msg);
395 if let Some(iterator_trait) = self.tcx.get_diagnostic_item(sym::Iterator) {
396 let iterator_trait = self.tcx.def_path_str(iterator_trait);
398 "`count` is defined on `{iterator_trait}`, which `{rcvr_ty}` does not implement"
401 } else if !unsatisfied_predicates.is_empty() {
402 let mut type_params = FxHashMap::default();
404 // Pick out the list of unimplemented traits on the receiver.
405 // This is used for custom error messages with the `#[rustc_on_unimplemented]` attribute.
406 let mut unimplemented_traits = FxHashMap::default();
407 let mut unimplemented_traits_only = true;
408 for (predicate, _parent_pred, cause) in unsatisfied_predicates {
409 if let (ty::PredicateKind::Clause(ty::Clause::Trait(p)), Some(cause)) =
410 (predicate.kind().skip_binder(), cause.as_ref())
412 if p.trait_ref.self_ty() != rcvr_ty {
413 // This is necessary, not just to keep the errors clean, but also
414 // because our derived obligations can wind up with a trait ref that
415 // requires a different param_env to be correctly compared.
418 unimplemented_traits.entry(p.trait_ref.def_id).or_insert((
419 predicate.kind().rebind(p.trait_ref),
421 cause: cause.clone(),
422 param_env: self.param_env,
423 predicate: *predicate,
430 // Make sure that, if any traits other than the found ones were involved,
431 // we don't don't report an unimplemented trait.
432 // We don't want to say that `iter::Cloned` is not an iterator, just
433 // because of some non-Clone item being iterated over.
434 for (predicate, _parent_pred, _cause) in unsatisfied_predicates {
435 match predicate.kind().skip_binder() {
436 ty::PredicateKind::Clause(ty::Clause::Trait(p))
437 if unimplemented_traits.contains_key(&p.trait_ref.def_id) => {}
439 unimplemented_traits_only = false;
445 let mut collect_type_param_suggestions =
446 |self_ty: Ty<'tcx>, parent_pred: ty::Predicate<'tcx>, obligation: &str| {
447 // We don't care about regions here, so it's fine to skip the binder here.
448 if let (ty::Param(_), ty::PredicateKind::Clause(ty::Clause::Trait(p))) =
449 (self_ty.kind(), parent_pred.kind().skip_binder())
451 let hir = self.tcx.hir();
452 let node = match p.trait_ref.self_ty().kind() {
454 // Account for `fn` items like in `issue-35677.rs` to
455 // suggest restricting its type params.
457 hir.body_owner(hir::BodyId { hir_id: self.body_id });
458 Some(hir.get(parent_body))
461 def.did().as_local().map(|def_id| hir.get_by_def_id(def_id))
465 if let Some(hir::Node::Item(hir::Item { kind, .. })) = node {
466 if let Some(g) = kind.generics() {
468 g.tail_span_for_predicate_suggestion(),
469 g.add_where_or_trailing_comma(),
473 .or_insert_with(FxHashSet::default)
474 .insert(obligation.to_owned());
479 let mut bound_span_label = |self_ty: Ty<'_>, obligation: &str, quiet: &str| {
481 "doesn't satisfy `{}`",
482 if obligation.len() > 50 { quiet } else { obligation }
484 match &self_ty.kind() {
485 // Point at the type that couldn't satisfy the bound.
486 ty::Adt(def, _) => bound_spans.push((self.tcx.def_span(def.did()), msg)),
487 // Point at the trait object that couldn't satisfy the bound.
488 ty::Dynamic(preds, _, _) => {
489 for pred in preds.iter() {
490 match pred.skip_binder() {
491 ty::ExistentialPredicate::Trait(tr) => {
492 bound_spans.push((self.tcx.def_span(tr.def_id), msg.clone()))
494 ty::ExistentialPredicate::Projection(_)
495 | ty::ExistentialPredicate::AutoTrait(_) => {}
499 // Point at the closure that couldn't satisfy the bound.
500 ty::Closure(def_id, _) => bound_spans
501 .push((tcx.def_span(*def_id), format!("doesn't satisfy `{}`", quiet))),
505 let mut format_pred = |pred: ty::Predicate<'tcx>| {
506 let bound_predicate = pred.kind();
507 match bound_predicate.skip_binder() {
508 ty::PredicateKind::Clause(ty::Clause::Projection(pred)) => {
509 let pred = bound_predicate.rebind(pred);
510 // `<Foo as Iterator>::Item = String`.
511 let projection_ty = pred.skip_binder().projection_ty;
513 let substs_with_infer_self = tcx.mk_substs(
514 iter::once(tcx.mk_ty_var(ty::TyVid::from_u32(0)).into())
515 .chain(projection_ty.substs.iter().skip(1)),
518 let quiet_projection_ty =
519 tcx.mk_alias_ty(projection_ty.def_id, substs_with_infer_self);
521 let term = pred.skip_binder().term;
523 let obligation = format!("{} = {}", projection_ty, term);
524 let quiet = with_forced_trimmed_paths!(format!(
526 quiet_projection_ty, term
529 bound_span_label(projection_ty.self_ty(), &obligation, &quiet);
530 Some((obligation, projection_ty.self_ty()))
532 ty::PredicateKind::Clause(ty::Clause::Trait(poly_trait_ref)) => {
533 let p = poly_trait_ref.trait_ref;
534 let self_ty = p.self_ty();
535 let path = p.print_only_trait_path();
536 let obligation = format!("{}: {}", self_ty, path);
537 let quiet = with_forced_trimmed_paths!(format!("_: {}", path));
538 bound_span_label(self_ty, &obligation, &quiet);
539 Some((obligation, self_ty))
545 // Find all the requirements that come from a local `impl` block.
546 let mut skip_list: FxHashSet<_> = Default::default();
547 let mut spanned_predicates: FxHashMap<MultiSpan, _> = Default::default();
548 for (data, p, parent_p, impl_def_id, cause) in unsatisfied_predicates
550 .filter_map(|(p, parent, c)| c.as_ref().map(|c| (p, parent, c)))
551 .filter_map(|(p, parent, c)| match c.code() {
552 ObligationCauseCode::ImplDerivedObligation(data) => {
553 Some((&data.derived, p, parent, data.impl_def_id, data))
558 let parent_trait_ref = data.parent_trait_pred;
559 let path = parent_trait_ref.print_modifiers_and_trait_path();
560 let tr_self_ty = parent_trait_ref.skip_binder().self_ty();
561 let unsatisfied_msg = "unsatisfied trait bound introduced here";
562 let derive_msg = "unsatisfied trait bound introduced in this `derive` macro";
563 match self.tcx.hir().get_if_local(impl_def_id) {
564 // Unmet obligation comes from a `derive` macro, point at it once to
565 // avoid multiple span labels pointing at the same place.
566 Some(Node::Item(hir::Item {
567 kind: hir::ItemKind::Impl(hir::Impl { of_trait, self_ty, .. }),
570 self_ty.span.ctxt().outer_expn_data().kind,
571 ExpnKind::Macro(MacroKind::Derive, _)
573 of_trait.as_ref().map(|t| t.path.span.ctxt().outer_expn_data().kind),
574 Some(ExpnKind::Macro(MacroKind::Derive, _))
577 let span = self_ty.span.ctxt().outer_expn_data().call_site;
578 let mut spans: MultiSpan = span.into();
579 spans.push_span_label(span, derive_msg);
580 let entry = spanned_predicates.entry(spans);
581 entry.or_insert_with(|| (path, tr_self_ty, Vec::new())).2.push(p);
584 // Unmet obligation coming from an `impl`.
585 Some(Node::Item(hir::Item {
586 kind: hir::ItemKind::Impl(hir::Impl { of_trait, self_ty, generics, .. }),
591 unsatisfied_predicates.iter().any(|(pred, _, _)| {
592 match pred.kind().skip_binder() {
593 ty::PredicateKind::Clause(ty::Clause::Trait(pred)) => {
594 Some(pred.def_id()) == self.tcx.lang_items().sized_trait()
595 && pred.polarity == ty::ImplPolarity::Positive
600 for param in generics.params {
601 if param.span == cause.span && sized_pred {
602 let (sp, sugg) = match param.colon_span {
603 Some(sp) => (sp.shrink_to_hi(), " ?Sized +"),
604 None => (param.span.shrink_to_hi(), ": ?Sized"),
606 err.span_suggestion_verbose(
608 "consider relaxing the type parameter's implicit \
611 Applicability::MachineApplicable,
615 if let Some(pred) = parent_p {
616 // Done to add the "doesn't satisfy" `span_label`.
617 let _ = format_pred(*pred);
620 let mut spans = if cause.span != *item_span {
621 let mut spans: MultiSpan = cause.span.into();
622 spans.push_span_label(cause.span, unsatisfied_msg);
625 let mut spans = Vec::with_capacity(2);
626 if let Some(trait_ref) = of_trait {
627 spans.push(trait_ref.path.span);
629 spans.push(self_ty.span);
632 if let Some(trait_ref) = of_trait {
633 spans.push_span_label(trait_ref.path.span, "");
635 spans.push_span_label(self_ty.span, "");
637 let entry = spanned_predicates.entry(spans);
638 entry.or_insert_with(|| (path, tr_self_ty, Vec::new())).2.push(p);
640 Some(Node::Item(hir::Item {
641 kind: hir::ItemKind::Trait(rustc_ast::ast::IsAuto::Yes, ..),
645 tcx.sess.delay_span_bug(
647 "auto trait is invoked with no method error, but no error reported?",
650 Some(_) => unreachable!(),
654 let mut spanned_predicates: Vec<_> = spanned_predicates.into_iter().collect();
655 spanned_predicates.sort_by_key(|(span, (_, _, _))| span.primary_span());
656 for (span, (_path, _self_ty, preds)) in spanned_predicates {
657 let mut preds: Vec<_> = preds
659 .filter_map(|pred| format_pred(*pred))
660 .map(|(p, _)| format!("`{}`", p))
664 let msg = if let [pred] = &preds[..] {
665 format!("trait bound {} was not satisfied", pred)
667 format!("the following trait bounds were not satisfied:\n{}", preds.join("\n"),)
669 err.span_note(span, &msg);
670 unsatisfied_bounds = true;
673 // The requirements that didn't have an `impl` span to show.
674 let mut bound_list = unsatisfied_predicates
676 .filter_map(|(pred, parent_pred, _cause)| {
677 format_pred(*pred).map(|(p, self_ty)| {
678 collect_type_param_suggestions(self_ty, *pred, &p);
681 None => format!("`{}`", &p),
682 Some(parent_pred) => match format_pred(*parent_pred) {
683 None => format!("`{}`", &p),
684 Some((parent_p, _)) => {
685 collect_type_param_suggestions(self_ty, *parent_pred, &p);
686 format!("`{}`\nwhich is required by `{}`", p, parent_p)
694 .filter(|(_, pred)| !skip_list.contains(&pred))
697 .collect::<Vec<(usize, String)>>();
699 for ((span, add_where_or_comma), obligations) in type_params.into_iter() {
700 restrict_type_params = true;
701 // #74886: Sort here so that the output is always the same.
702 let mut obligations = obligations.into_iter().collect::<Vec<_>>();
704 err.span_suggestion_verbose(
707 "consider restricting the type parameter{s} to satisfy the \
709 s = pluralize!(obligations.len())
711 format!("{} {}", add_where_or_comma, obligations.join(", ")),
712 Applicability::MaybeIncorrect,
716 bound_list.sort_by(|(_, a), (_, b)| a.cmp(b)); // Sort alphabetically.
717 bound_list.dedup_by(|(_, a), (_, b)| a == b); // #35677
718 bound_list.sort_by_key(|(pos, _)| *pos); // Keep the original predicate order.
720 if !bound_list.is_empty() || !skip_list.is_empty() {
722 bound_list.into_iter().map(|(_, path)| path).collect::<Vec<_>>().join("\n");
723 let actual_prefix = rcvr_ty.prefix_string(self.tcx);
724 info!("unimplemented_traits.len() == {}", unimplemented_traits.len());
725 let (primary_message, label) = if unimplemented_traits.len() == 1
726 && unimplemented_traits_only
731 .map(|(_, (trait_ref, obligation))| {
732 if trait_ref.self_ty().references_error() || rcvr_ty.references_error()
737 let OnUnimplementedNote { message, label, .. } =
738 self.err_ctxt().on_unimplemented_note(trait_ref, &obligation);
745 let primary_message = primary_message.unwrap_or_else(|| {
747 "the {item_kind} `{item_name}` exists for {actual_prefix} `{ty_str}`, \
748 but its trait bounds were not satisfied"
751 err.set_primary_message(&primary_message);
752 if let Some(label) = label {
753 custom_span_label = true;
754 err.span_label(span, label);
756 if !bound_list.is_empty() {
758 "the following trait bounds were not satisfied:\n{bound_list}"
761 self.suggest_derive(&mut err, &unsatisfied_predicates);
763 unsatisfied_bounds = true;
767 let label_span_not_found = |err: &mut Diagnostic| {
768 if unsatisfied_predicates.is_empty() {
769 err.span_label(span, format!("{item_kind} not found in `{ty_str}`"));
770 let is_string_or_ref_str = match rcvr_ty.kind() {
771 ty::Ref(_, ty, _) => {
775 ty::Adt(adt, _) if Some(adt.did()) == self.tcx.lang_items().string()
778 ty::Adt(adt, _) => Some(adt.did()) == self.tcx.lang_items().string(),
781 if is_string_or_ref_str && item_name.name == sym::iter {
782 err.span_suggestion_verbose(
784 "because of the in-memory representation of `&str`, to obtain \
785 an `Iterator` over each of its codepoint use method `chars`",
787 Applicability::MachineApplicable,
790 if let ty::Adt(adt, _) = rcvr_ty.kind() {
791 let mut inherent_impls_candidate = self
793 .inherent_impls(adt.did())
797 if let Some(assoc) = self.associated_value(*def_id, item_name) {
798 // Check for both mode is the same so we avoid suggesting
799 // incorrect associated item.
800 match (mode, assoc.fn_has_self_parameter, source) {
801 (Mode::MethodCall, true, SelfSource::MethodCall(_)) => {
802 // We check that the suggest type is actually
803 // different from the received one
804 // So we avoid suggestion method with Box<Self>
806 self.tcx.at(span).type_of(*def_id) != rcvr_ty
807 && self.tcx.at(span).type_of(*def_id) != rcvr_ty
809 (Mode::Path, false, _) => true,
816 .collect::<Vec<_>>();
817 if !inherent_impls_candidate.is_empty() {
818 inherent_impls_candidate.sort();
819 inherent_impls_candidate.dedup();
821 // number of type to shows at most.
822 let limit = if inherent_impls_candidate.len() == 5 { 5 } else { 4 };
823 let type_candidates = inherent_impls_candidate
827 format!("- `{}`", self.tcx.at(span).type_of(*impl_item))
831 let additional_types = if inherent_impls_candidate.len() > limit {
832 format!("\nand {} more types", inherent_impls_candidate.len() - limit)
837 "the {item_kind} was found for\n{}{}",
838 type_candidates, additional_types
844 if ty_str.len() > 50 { String::new() } else { format!("on `{ty_str}` ") };
847 format!("{item_kind} cannot be called {ty_str}due to unsatisfied trait bounds"),
852 // If the method name is the name of a field with a function or closure type,
853 // give a helping note that it has to be called as `(x.f)(...)`.
854 if let SelfSource::MethodCall(expr) = source {
855 if !self.suggest_calling_field_as_fn(span, rcvr_ty, expr, item_name, &mut err)
856 && lev_candidate.is_none()
857 && !custom_span_label
859 label_span_not_found(&mut err);
861 } else if !custom_span_label {
862 label_span_not_found(&mut err);
865 // Don't suggest (for example) `expr.field.clone()` if `expr.clone()`
866 // can't be called due to `typeof(expr): Clone` not holding.
867 if unsatisfied_predicates.is_empty() {
868 self.suggest_calling_method_on_field(&mut err, source, span, rcvr_ty, item_name);
871 self.check_for_inner_self(&mut err, source, rcvr_ty, item_name);
875 for (span, msg) in bound_spans.into_iter() {
876 err.span_label(span, &msg);
879 if rcvr_ty.is_numeric() && rcvr_ty.is_fresh() || restrict_type_params {
881 self.suggest_traits_to_import(
886 args.map(|(_, args)| args.len() + 1),
888 no_match_data.out_of_scope_traits.clone(),
889 &unsatisfied_predicates,
895 // Don't emit a suggestion if we found an actual method
896 // that had unsatisfied trait bounds
897 if unsatisfied_predicates.is_empty() && rcvr_ty.is_enum() {
898 let adt_def = rcvr_ty.ty_adt_def().expect("enum is not an ADT");
899 if let Some(suggestion) = lev_distance::find_best_match_for_name(
900 &adt_def.variants().iter().map(|s| s.name).collect::<Vec<_>>(),
906 "there is a variant with a similar name",
908 Applicability::MaybeIncorrect,
913 if item_name.name == sym::as_str && rcvr_ty.peel_refs().is_str() {
914 let msg = "remove this method call";
915 let mut fallback_span = true;
916 if let SelfSource::MethodCall(expr) = source {
917 let call_expr = self.tcx.hir().expect_expr(self.tcx.hir().parent_id(expr.hir_id));
918 if let Some(span) = call_expr.span.trim_start(expr.span) {
919 err.span_suggestion(span, msg, "", Applicability::MachineApplicable);
920 fallback_span = false;
924 err.span_label(span, msg);
926 } else if let Some(lev_candidate) = lev_candidate {
927 // Don't emit a suggestion if we found an actual method
928 // that had unsatisfied trait bounds
929 if unsatisfied_predicates.is_empty() {
930 let def_kind = lev_candidate.kind.as_def_kind();
931 // Methods are defined within the context of a struct and their first parameter is always self,
932 // which represents the instance of the struct the method is being called on
933 // Associated functions don’t take self as a parameter and
934 // they are not methods because they don’t have an instance of the struct to work with.
935 if def_kind == DefKind::AssocFn && lev_candidate.fn_has_self_parameter {
938 "there is a method with a similar name",
940 Applicability::MaybeIncorrect,
946 "there is {} {} with a similar name",
948 def_kind.descr(lev_candidate.def_id),
951 Applicability::MaybeIncorrect,
957 self.check_for_deref_method(&mut err, source, rcvr_ty, item_name);
961 fn note_candidates_on_method_error(
965 args: Option<(&'tcx hir::Expr<'tcx>, &'tcx [hir::Expr<'tcx>])>,
967 err: &mut Diagnostic,
968 sources: &mut Vec<CandidateSource>,
969 sugg_span: Option<Span>,
973 // Dynamic limit to avoid hiding just one candidate, which is silly.
974 let limit = if sources.len() == 5 { 5 } else { 4 };
976 for (idx, source) in sources.iter().take(limit).enumerate() {
978 CandidateSource::Impl(impl_did) => {
979 // Provide the best span we can. Use the item, if local to crate, else
980 // the impl, if local to crate (item may be defaulted), else nothing.
981 let Some(item) = self.associated_value(impl_did, item_name).or_else(|| {
982 let impl_trait_ref = self.tcx.impl_trait_ref(impl_did)?;
983 self.associated_value(impl_trait_ref.def_id, item_name)
988 let note_span = if item.def_id.is_local() {
989 Some(self.tcx.def_span(item.def_id))
990 } else if impl_did.is_local() {
991 Some(self.tcx.def_span(impl_did))
996 let impl_ty = self.tcx.at(span).type_of(impl_did);
998 let insertion = match self.tcx.impl_trait_ref(impl_did) {
999 None => String::new(),
1000 Some(trait_ref) => {
1001 format!(" of the trait `{}`", self.tcx.def_path_str(trait_ref.def_id))
1005 let (note_str, idx) = if sources.len() > 1 {
1008 "candidate #{} is defined in an impl{} for the type `{}`",
1018 "the candidate is defined in an impl{} for the type `{}`",
1024 if let Some(note_span) = note_span {
1025 // We have a span pointing to the method. Show note with snippet.
1026 err.span_note(note_span, ¬e_str);
1028 err.note(¬e_str);
1030 if let Some(sugg_span) = sugg_span
1031 && let Some(trait_ref) = self.tcx.impl_trait_ref(impl_did) {
1032 let path = self.tcx.def_path_str(trait_ref.def_id);
1034 let ty = match item.kind {
1035 ty::AssocKind::Const | ty::AssocKind::Type => rcvr_ty,
1036 ty::AssocKind::Fn => self
1038 .fn_sig(item.def_id)
1042 .filter(|ty| ty.is_region_ptr() && !rcvr_ty.is_region_ptr())
1044 .unwrap_or(rcvr_ty),
1046 print_disambiguation_help(
1056 self.tcx.sess.source_map(),
1057 item.fn_has_self_parameter,
1061 CandidateSource::Trait(trait_did) => {
1062 let Some(item) = self.associated_value(trait_did, item_name) else { continue };
1063 let item_span = self.tcx.def_span(item.def_id);
1064 let idx = if sources.len() > 1 {
1066 "candidate #{} is defined in the trait `{}`",
1068 self.tcx.def_path_str(trait_did)
1070 err.span_note(item_span, msg);
1074 "the candidate is defined in the trait `{}`",
1075 self.tcx.def_path_str(trait_did)
1077 err.span_note(item_span, msg);
1080 if let Some(sugg_span) = sugg_span {
1081 let path = self.tcx.def_path_str(trait_did);
1082 print_disambiguation_help(
1092 self.tcx.sess.source_map(),
1093 item.fn_has_self_parameter,
1099 if sources.len() > limit {
1100 err.note(&format!("and {} others", sources.len() - limit));
1104 /// Suggest calling `Ty::method` if `.method()` isn't found because the method
1105 /// doesn't take a `self` receiver.
1106 fn suggest_associated_call_syntax(
1108 err: &mut Diagnostic,
1109 static_candidates: &Vec<CandidateSource>,
1111 source: SelfSource<'tcx>,
1113 args: Option<(&hir::Expr<'tcx>, &[hir::Expr<'tcx>])>,
1116 let mut has_unsuggestable_args = false;
1117 let ty_str = if let Some(CandidateSource::Impl(impl_did)) = static_candidates.get(0) {
1118 // When the "method" is resolved through dereferencing, we really want the
1119 // original type that has the associated function for accurate suggestions.
1121 let impl_ty = self.tcx.type_of(*impl_did);
1122 let target_ty = self
1123 .autoderef(sugg_span, rcvr_ty)
1124 .find(|(rcvr_ty, _)| {
1125 DeepRejectCtxt { treat_obligation_params: TreatParams::AsInfer }
1126 .types_may_unify(*rcvr_ty, impl_ty)
1128 .map_or(impl_ty, |(ty, _)| ty)
1130 if let ty::Adt(def, substs) = target_ty.kind() {
1131 // If there are any inferred arguments, (`{integer}`), we should replace
1132 // them with underscores to allow the compiler to infer them
1133 let infer_substs = self.tcx.mk_substs(substs.into_iter().map(|arg| {
1134 if !arg.is_suggestable(self.tcx, true) {
1135 has_unsuggestable_args = true;
1136 match arg.unpack() {
1137 GenericArgKind::Lifetime(_) => self
1138 .next_region_var(RegionVariableOrigin::MiscVariable(
1139 rustc_span::DUMMY_SP,
1142 GenericArgKind::Type(_) => self
1143 .next_ty_var(TypeVariableOrigin {
1144 span: rustc_span::DUMMY_SP,
1145 kind: TypeVariableOriginKind::MiscVariable,
1148 GenericArgKind::Const(arg) => self
1151 ConstVariableOrigin {
1152 span: rustc_span::DUMMY_SP,
1153 kind: ConstVariableOriginKind::MiscVariable,
1163 self.tcx.value_path_str_with_substs(def.did(), infer_substs)
1165 self.ty_to_value_string(target_ty)
1168 self.ty_to_value_string(rcvr_ty.peel_refs())
1170 if let SelfSource::MethodCall(_) = source {
1171 let first_arg = if let Some(CandidateSource::Impl(impl_did)) = static_candidates.get(0)
1172 && let Some(assoc) = self.associated_value(*impl_did, item_name)
1173 && assoc.kind == ty::AssocKind::Fn
1175 let sig = self.tcx.fn_sig(assoc.def_id);
1176 sig.inputs().skip_binder().get(0).and_then(|first| if first.peel_refs() == rcvr_ty.peel_refs() {
1179 Some(first.ref_mutability().map_or("", |mutbl| mutbl.ref_prefix_str()))
1184 let mut applicability = Applicability::MachineApplicable;
1185 let args = if let Some((receiver, args)) = args {
1186 // The first arg is the same kind as the receiver
1187 let explicit_args = if first_arg.is_some() {
1188 std::iter::once(receiver).chain(args.iter()).collect::<Vec<_>>()
1190 // There is no `Self` kind to infer the arguments from
1191 if has_unsuggestable_args {
1192 applicability = Applicability::HasPlaceholders;
1194 args.iter().collect()
1198 first_arg.unwrap_or(""),
1205 .span_to_snippet(arg.span)
1206 .unwrap_or_else(|_| {
1207 applicability = Applicability::HasPlaceholders;
1210 .collect::<Vec<_>>()
1214 applicability = Applicability::HasPlaceholders;
1217 err.span_suggestion(
1219 "use associated function syntax instead",
1220 format!("{}::{}{}", ty_str, item_name, args),
1224 err.help(&format!("try with `{}::{}`", ty_str, item_name,));
1228 /// Suggest calling a field with a type that implements the `Fn*` traits instead of a method with
1229 /// the same name as the field i.e. `(a.my_fn_ptr)(10)` instead of `a.my_fn_ptr(10)`.
1230 fn suggest_calling_field_as_fn(
1234 expr: &hir::Expr<'_>,
1236 err: &mut Diagnostic,
1239 let field_receiver = self.autoderef(span, rcvr_ty).find_map(|(ty, _)| match ty.kind() {
1240 ty::Adt(def, substs) if !def.is_enum() => {
1241 let variant = &def.non_enum_variant();
1242 tcx.find_field_index(item_name, variant).map(|index| {
1243 let field = &variant.fields[index];
1244 let field_ty = field.ty(tcx, substs);
1250 if let Some((field, field_ty)) = field_receiver {
1251 let scope = tcx.parent_module(self.body_id);
1252 let is_accessible = field.vis.is_accessible_from(scope, tcx);
1255 if self.is_fn_ty(field_ty, span) {
1256 let expr_span = expr.span.to(item_name.span);
1257 err.multipart_suggestion(
1259 "to call the function stored in `{}`, \
1260 surround the field access with parentheses",
1264 (expr_span.shrink_to_lo(), '('.to_string()),
1265 (expr_span.shrink_to_hi(), ')'.to_string()),
1267 Applicability::MachineApplicable,
1270 let call_expr = tcx.hir().expect_expr(tcx.hir().parent_id(expr.hir_id));
1272 if let Some(span) = call_expr.span.trim_start(item_name.span) {
1273 err.span_suggestion(
1275 "remove the arguments",
1277 Applicability::MaybeIncorrect,
1283 let field_kind = if is_accessible { "field" } else { "private field" };
1284 err.span_label(item_name.span, format!("{}, not a method", field_kind));
1290 /// Suggest possible range with adding parentheses, for example:
1291 /// when encountering `0..1.map(|i| i + 1)` suggest `(0..1).map(|i| i + 1)`.
1292 fn suggest_wrapping_range_with_parens(
1296 source: SelfSource<'tcx>,
1301 if let SelfSource::MethodCall(expr) = source {
1302 for (_, parent) in tcx.hir().parent_iter(expr.hir_id).take(5) {
1303 if let Node::Expr(parent_expr) = parent {
1304 let lang_item = match parent_expr.kind {
1305 ExprKind::Struct(ref qpath, _, _) => match **qpath {
1306 QPath::LangItem(LangItem::Range, ..) => Some(LangItem::Range),
1307 QPath::LangItem(LangItem::RangeTo, ..) => Some(LangItem::RangeTo),
1308 QPath::LangItem(LangItem::RangeToInclusive, ..) => {
1309 Some(LangItem::RangeToInclusive)
1313 ExprKind::Call(ref func, _) => match func.kind {
1314 // `..=` desugars into `::std::ops::RangeInclusive::new(...)`.
1315 ExprKind::Path(QPath::LangItem(LangItem::RangeInclusiveNew, ..)) => {
1316 Some(LangItem::RangeInclusiveStruct)
1323 if lang_item.is_none() {
1327 let span_included = match parent_expr.kind {
1328 hir::ExprKind::Struct(_, eps, _) => {
1329 eps.len() > 0 && eps.last().map_or(false, |ep| ep.span.contains(span))
1331 // `..=` desugars into `::std::ops::RangeInclusive::new(...)`.
1332 hir::ExprKind::Call(ref func, ..) => func.span.contains(span),
1340 let range_def_id = self.tcx.require_lang_item(lang_item.unwrap(), None);
1342 self.tcx.bound_type_of(range_def_id).subst(self.tcx, &[actual.into()]);
1344 let pick = self.probe_for_name(
1350 ProbeScope::AllTraits,
1353 let range_span = parent_expr.span.with_hi(expr.span.hi());
1354 tcx.sess.emit_err(errors::MissingParentheseInRange {
1356 ty_str: ty_str.to_string(),
1357 method_name: item_name.as_str().to_string(),
1358 add_missing_parentheses: Some(errors::AddMissingParenthesesInRange {
1359 func_name: item_name.name.as_str().to_string(),
1360 left: range_span.shrink_to_lo(),
1361 right: range_span.shrink_to_hi(),
1372 fn suggest_constraining_numerical_ty(
1376 source: SelfSource<'_>,
1382 let found_candidate = all_traits(self.tcx)
1384 .any(|info| self.associated_value(info.def_id, item_name).is_some());
1385 let found_assoc = |ty: Ty<'tcx>| {
1386 simplify_type(tcx, ty, TreatParams::AsInfer)
1388 tcx.incoherent_impls(simp)
1390 .find_map(|&id| self.associated_value(id, item_name))
1394 let found_candidate = found_candidate
1395 || found_assoc(tcx.types.i8)
1396 || found_assoc(tcx.types.i16)
1397 || found_assoc(tcx.types.i32)
1398 || found_assoc(tcx.types.i64)
1399 || found_assoc(tcx.types.i128)
1400 || found_assoc(tcx.types.u8)
1401 || found_assoc(tcx.types.u16)
1402 || found_assoc(tcx.types.u32)
1403 || found_assoc(tcx.types.u64)
1404 || found_assoc(tcx.types.u128)
1405 || found_assoc(tcx.types.f32)
1406 || found_assoc(tcx.types.f32);
1408 && actual.is_numeric()
1409 && !actual.has_concrete_skeleton()
1410 && let SelfSource::MethodCall(expr) = source
1412 let mut err = struct_span_err!(
1416 "can't call {} `{}` on ambiguous numeric type `{}`",
1421 let concrete_type = if actual.is_integral() { "i32" } else { "f32" };
1423 ExprKind::Lit(ref lit) => {
1428 .span_to_snippet(lit.span)
1429 .unwrap_or_else(|_| "<numeric literal>".to_owned());
1431 // If this is a floating point literal that ends with '.',
1432 // get rid of it to stop this from becoming a member access.
1433 let snippet = snippet.strip_suffix('.').unwrap_or(&snippet);
1434 err.span_suggestion(
1437 "you must specify a concrete type for this numeric value, \
1441 format!("{snippet}_{concrete_type}"),
1442 Applicability::MaybeIncorrect,
1445 ExprKind::Path(QPath::Resolved(_, path)) => {
1447 if let hir::def::Res::Local(hir_id) = path.res {
1448 let span = tcx.hir().span(hir_id);
1449 let filename = tcx.sess.source_map().span_to_filename(span);
1452 self.tcx.hir().get_parent(hir_id);
1454 "you must specify a type for this binding, like `{}`",
1458 match (filename, parent_node) {
1461 Node::Local(hir::Local {
1462 source: hir::LocalSource::Normal,
1467 let type_span = ty.map(|ty| ty.span.with_lo(span.hi())).unwrap_or(span.shrink_to_hi());
1468 err.span_suggestion(
1469 // account for `let x: _ = 42;`
1473 format!(": {concrete_type}"),
1474 Applicability::MaybeIncorrect,
1478 err.span_label(span, msg);
1491 /// For code `rect::area(...)`,
1492 /// if `rect` is a local variable and `area` is a valid assoc method for it,
1493 /// we try to suggest `rect.area()`
1494 pub(crate) fn suggest_assoc_method_call(&self, segs: &[PathSegment<'_>]) {
1495 debug!("suggest_assoc_method_call segs: {:?}", segs);
1496 let [seg1, seg2] = segs else { return; };
1497 let Some(mut diag) =
1498 self.tcx.sess.diagnostic().steal_diagnostic(seg1.ident.span, StashKey::CallAssocMethod)
1501 let map = self.infcx.tcx.hir();
1502 let body = map.body(rustc_hir::BodyId { hir_id: self.body_id });
1503 struct LetVisitor<'a> {
1504 result: Option<&'a hir::Expr<'a>>,
1508 // FIXME: This really should be taking scoping, etc into account.
1509 impl<'v> Visitor<'v> for LetVisitor<'v> {
1510 fn visit_stmt(&mut self, ex: &'v hir::Stmt<'v>) {
1511 if let hir::StmtKind::Local(hir::Local { pat, init, .. }) = &ex.kind
1512 && let Binding(_, _, ident, ..) = pat.kind
1513 && ident.name == self.ident_name
1515 self.result = *init;
1517 hir::intravisit::walk_stmt(self, ex);
1522 let mut visitor = LetVisitor { result: None, ident_name: seg1.ident.name };
1523 visitor.visit_body(&body);
1525 let parent = self.tcx.hir().parent_id(seg1.hir_id);
1526 if let Some(Node::Expr(call_expr)) = self.tcx.hir().find(parent)
1527 && let Some(expr) = visitor.result
1528 && let Some(self_ty) = self.node_ty_opt(expr.hir_id)
1530 let probe = self.lookup_probe(
1534 ProbeScope::TraitsInScope,
1537 let sm = self.infcx.tcx.sess.source_map();
1538 diag.span_suggestion_verbose(
1539 sm.span_extend_while(seg1.ident.span.shrink_to_hi(), |c| c == ':').unwrap(),
1540 "you may have meant to call an instance method",
1542 Applicability::MaybeIncorrect,
1549 /// Suggest calling a method on a field i.e. `a.field.bar()` instead of `a.bar()`
1550 fn suggest_calling_method_on_field(
1552 err: &mut Diagnostic,
1553 source: SelfSource<'tcx>,
1558 if let SelfSource::MethodCall(expr) = source
1559 && let mod_id = self.tcx.parent_module(expr.hir_id).to_def_id()
1560 && let Some((fields, substs)) =
1561 self.get_field_candidates_considering_privacy(span, actual, mod_id)
1563 let call_expr = self.tcx.hir().expect_expr(self.tcx.hir().parent_id(expr.hir_id));
1565 let lang_items = self.tcx.lang_items();
1566 let never_mention_traits = [
1567 lang_items.clone_trait(),
1568 lang_items.deref_trait(),
1569 lang_items.deref_mut_trait(),
1570 self.tcx.get_diagnostic_item(sym::AsRef),
1571 self.tcx.get_diagnostic_item(sym::AsMut),
1572 self.tcx.get_diagnostic_item(sym::Borrow),
1573 self.tcx.get_diagnostic_item(sym::BorrowMut),
1575 let candidate_fields: Vec<_> = fields
1576 .filter_map(|candidate_field| {
1577 self.check_for_nested_field_satisfying(
1584 ProbeScope::TraitsInScope,
1586 .map_or(false, |pick| {
1587 !never_mention_traits
1590 .any(|def_id| self.tcx.parent(pick.item.def_id) == *def_id)
1602 .map(|id| id.name.to_ident_string())
1603 .collect::<Vec<String>>()
1608 let len = candidate_fields.len();
1610 err.span_suggestions(
1611 item_name.span.shrink_to_lo(),
1613 "{} of the expressions' fields {} a method of the same name",
1614 if len > 1 { "some" } else { "one" },
1615 if len > 1 { "have" } else { "has" },
1617 candidate_fields.iter().map(|path| format!("{path}.")),
1618 Applicability::MaybeIncorrect,
1624 fn check_for_inner_self(
1626 err: &mut Diagnostic,
1627 source: SelfSource<'tcx>,
1632 let SelfSource::MethodCall(expr) = source else { return; };
1633 let call_expr = tcx.hir().expect_expr(tcx.hir().parent_id(expr.hir_id));
1635 let ty::Adt(kind, substs) = actual.kind() else { return; };
1636 match kind.adt_kind() {
1637 ty::AdtKind::Enum => {
1638 let matching_variants: Vec<_> = kind
1641 .flat_map(|variant| {
1642 let [field] = &variant.fields[..] else { return None; };
1643 let field_ty = field.ty(tcx, substs);
1645 // Skip `_`, since that'll just lead to ambiguity.
1646 if self.resolve_vars_if_possible(field_ty).is_ty_var() {
1650 self.lookup_probe(item_name, field_ty, call_expr, ProbeScope::TraitsInScope)
1652 .map(|pick| (variant, field, pick))
1656 let ret_ty_matches = |diagnostic_item| {
1657 if let Some(ret_ty) = self
1660 .map(|c| self.resolve_vars_if_possible(c.borrow().expected_ty()))
1661 && let ty::Adt(kind, _) = ret_ty.kind()
1662 && tcx.get_diagnostic_item(diagnostic_item) == Some(kind.did())
1670 match &matching_variants[..] {
1671 [(_, field, pick)] => {
1672 let self_ty = field.ty(tcx, substs);
1674 tcx.def_span(pick.item.def_id),
1675 &format!("the method `{item_name}` exists on the type `{self_ty}`"),
1677 let (article, kind, variant, question) =
1678 if tcx.is_diagnostic_item(sym::Result, kind.did()) {
1679 ("a", "Result", "Err", ret_ty_matches(sym::Result))
1680 } else if tcx.is_diagnostic_item(sym::Option, kind.did()) {
1681 ("an", "Option", "None", ret_ty_matches(sym::Option))
1686 err.span_suggestion_verbose(
1687 expr.span.shrink_to_hi(),
1689 "use the `?` operator to extract the `{self_ty}` value, propagating \
1690 {article} `{kind}::{variant}` value to the caller"
1693 Applicability::MachineApplicable,
1696 err.span_suggestion_verbose(
1697 expr.span.shrink_to_hi(),
1699 "consider using `{kind}::expect` to unwrap the `{self_ty}` value, \
1700 panicking if the value is {article} `{kind}::{variant}`"
1702 ".expect(\"REASON\")",
1703 Applicability::HasPlaceholders,
1707 // FIXME(compiler-errors): Support suggestions for other matching enum variants
1711 // Target wrapper types - types that wrap or pretend to wrap another type,
1712 // perhaps this inner type is meant to be called?
1713 ty::AdtKind::Struct | ty::AdtKind::Union => {
1714 let [first] = ***substs else { return; };
1715 let ty::GenericArgKind::Type(ty) = first.unpack() else { return; };
1716 let Ok(pick) = self.lookup_probe(
1720 ProbeScope::TraitsInScope,
1723 let name = self.ty_to_value_string(actual);
1724 let inner_id = kind.did();
1725 let mutable = if let Some(AutorefOrPtrAdjustment::Autoref { mutbl, .. }) =
1726 pick.autoref_or_ptr_adjustment
1733 if tcx.is_diagnostic_item(sym::LocalKey, inner_id) {
1734 err.help("use `with` or `try_with` to access thread local storage");
1735 } else if Some(kind.did()) == tcx.lang_items().maybe_uninit() {
1737 "if this `{name}` has been initialized, \
1738 use one of the `assume_init` methods to access the inner value"
1740 } else if tcx.is_diagnostic_item(sym::RefCell, inner_id) {
1741 let (suggestion, borrow_kind, panic_if) = match mutable {
1742 Some(Mutability::Not) => (".borrow()", "borrow", "a mutable borrow exists"),
1743 Some(Mutability::Mut) => {
1744 (".borrow_mut()", "mutably borrow", "any borrows exist")
1748 err.span_suggestion_verbose(
1749 expr.span.shrink_to_hi(),
1751 "use `{suggestion}` to {borrow_kind} the `{ty}`, \
1752 panicking if {panic_if}"
1755 Applicability::MaybeIncorrect,
1757 } else if tcx.is_diagnostic_item(sym::Mutex, inner_id) {
1758 err.span_suggestion_verbose(
1759 expr.span.shrink_to_hi(),
1761 "use `.lock().unwrap()` to borrow the `{ty}`, \
1762 blocking the current thread until it can be acquired"
1765 Applicability::MaybeIncorrect,
1767 } else if tcx.is_diagnostic_item(sym::RwLock, inner_id) {
1768 let (suggestion, borrow_kind) = match mutable {
1769 Some(Mutability::Not) => (".read().unwrap()", "borrow"),
1770 Some(Mutability::Mut) => (".write().unwrap()", "mutably borrow"),
1773 err.span_suggestion_verbose(
1774 expr.span.shrink_to_hi(),
1776 "use `{suggestion}` to {borrow_kind} the `{ty}`, \
1777 blocking the current thread until it can be acquired"
1780 Applicability::MaybeIncorrect,
1787 tcx.def_span(pick.item.def_id),
1788 &format!("the method `{item_name}` exists on the type `{ty}`"),
1794 pub(crate) fn note_unmet_impls_on_type(
1796 err: &mut Diagnostic,
1797 errors: Vec<FulfillmentError<'tcx>>,
1799 let all_local_types_needing_impls =
1800 errors.iter().all(|e| match e.obligation.predicate.kind().skip_binder() {
1801 ty::PredicateKind::Clause(ty::Clause::Trait(pred)) => match pred.self_ty().kind() {
1802 ty::Adt(def, _) => def.did().is_local(),
1807 let mut preds: Vec<_> = errors
1809 .filter_map(|e| match e.obligation.predicate.kind().skip_binder() {
1810 ty::PredicateKind::Clause(ty::Clause::Trait(pred)) => Some(pred),
1814 preds.sort_by_key(|pred| (pred.def_id(), pred.self_ty()));
1817 .filter_map(|pred| match pred.self_ty().kind() {
1818 ty::Adt(def, _) => Some(def.did()),
1821 .collect::<FxHashSet<_>>();
1822 let mut spans: MultiSpan = def_ids
1824 .filter_map(|def_id| {
1825 let span = self.tcx.def_span(*def_id);
1826 if span.is_dummy() { None } else { Some(span) }
1828 .collect::<Vec<_>>()
1831 for pred in &preds {
1832 match pred.self_ty().kind() {
1833 ty::Adt(def, _) if def.did().is_local() => {
1834 spans.push_span_label(
1835 self.tcx.def_span(def.did()),
1836 format!("must implement `{}`", pred.trait_ref.print_only_trait_path()),
1843 if all_local_types_needing_impls && spans.primary_span().is_some() {
1844 let msg = if preds.len() == 1 {
1846 "an implementation of `{}` might be missing for `{}`",
1847 preds[0].trait_ref.print_only_trait_path(),
1852 "the following type{} would have to `impl` {} required trait{} for this \
1853 operation to be valid",
1854 pluralize!(def_ids.len()),
1855 if def_ids.len() == 1 { "its" } else { "their" },
1856 pluralize!(preds.len()),
1859 err.span_note(spans, &msg);
1862 let preds: Vec<_> = errors
1864 .map(|e| (e.obligation.predicate, None, Some(e.obligation.cause.clone())))
1866 self.suggest_derive(err, &preds);
1869 pub fn suggest_derive(
1871 err: &mut Diagnostic,
1872 unsatisfied_predicates: &[(
1873 ty::Predicate<'tcx>,
1874 Option<ty::Predicate<'tcx>>,
1875 Option<ObligationCause<'tcx>>,
1878 let mut derives = Vec::<(String, Span, Symbol)>::new();
1879 let mut traits = Vec::new();
1880 for (pred, _, _) in unsatisfied_predicates {
1881 let ty::PredicateKind::Clause(ty::Clause::Trait(trait_pred)) = pred.kind().skip_binder() else { continue };
1882 let adt = match trait_pred.self_ty().ty_adt_def() {
1883 Some(adt) if adt.did().is_local() => adt,
1886 if let Some(diagnostic_name) = self.tcx.get_diagnostic_name(trait_pred.def_id()) {
1887 let can_derive = match diagnostic_name {
1888 sym::Default => !adt.is_enum(),
1896 | sym::Debug => true,
1900 let self_name = trait_pred.self_ty().to_string();
1901 let self_span = self.tcx.def_span(adt.did());
1902 if let Some(poly_trait_ref) = pred.to_opt_poly_trait_pred() {
1903 for super_trait in supertraits(self.tcx, poly_trait_ref.to_poly_trait_ref())
1905 if let Some(parent_diagnostic_name) =
1906 self.tcx.get_diagnostic_name(super_trait.def_id())
1911 parent_diagnostic_name,
1916 derives.push((self_name, self_span, diagnostic_name));
1918 traits.push(trait_pred.def_id());
1921 traits.push(trait_pred.def_id());
1930 let mut derives_grouped = Vec::<(String, Span, String)>::new();
1931 for (self_name, self_span, trait_name) in derives.into_iter() {
1932 if let Some((last_self_name, _, ref mut last_trait_names)) = derives_grouped.last_mut()
1934 if last_self_name == &self_name {
1935 last_trait_names.push_str(format!(", {}", trait_name).as_str());
1939 derives_grouped.push((self_name, self_span, trait_name.to_string()));
1942 let len = traits.len();
1945 MultiSpan::from_spans(traits.iter().map(|&did| self.tcx.def_span(did)).collect());
1946 let mut names = format!("`{}`", self.tcx.def_path_str(traits[0]));
1947 for (i, &did) in traits.iter().enumerate().skip(1) {
1949 names.push_str(", ");
1952 names.push_str(" and ");
1955 names.push_str(&self.tcx.def_path_str(did));
1960 &format!("the trait{} {} must be implemented", pluralize!(len), names),
1964 for (self_name, self_span, traits) in &derives_grouped {
1965 err.span_suggestion_verbose(
1966 self_span.shrink_to_lo(),
1967 &format!("consider annotating `{}` with `#[derive({})]`", self_name, traits),
1968 format!("#[derive({})]\n", traits),
1969 Applicability::MaybeIncorrect,
1974 fn check_for_deref_method(
1976 err: &mut Diagnostic,
1977 self_source: SelfSource<'tcx>,
1981 let SelfSource::QPath(ty) = self_source else { return; };
1982 for (deref_ty, _) in self.autoderef(rustc_span::DUMMY_SP, rcvr_ty).skip(1) {
1983 if let Ok(pick) = self.probe_for_name(
1989 ProbeScope::TraitsInScope,
1991 if deref_ty.is_suggestable(self.tcx, true)
1992 // If this method receives `&self`, then the provided
1993 // argument _should_ coerce, so it's valid to suggest
1994 // just changing the path.
1995 && pick.item.fn_has_self_parameter
1996 && let Some(self_ty) =
1997 self.tcx.fn_sig(pick.item.def_id).inputs().skip_binder().get(0)
2000 let suggested_path = match deref_ty.kind() {
2008 | ty::Alias(ty::Projection, _)
2009 | ty::Param(_) => format!("{deref_ty}"),
2010 // we need to test something like <&[_]>::len or <(&[u32])>::len
2011 // and Vec::function();
2012 // <&[_]>::len or <&[u32]>::len doesn't need an extra "<>" between
2013 // but for Adt type like Vec::function()
2014 // we would suggest <[_]>::function();
2015 _ if self.tcx.sess.source_map().span_wrapped_by_angle_or_parentheses(ty.span) => format!("{deref_ty}"),
2016 _ => format!("<{deref_ty}>"),
2018 err.span_suggestion_verbose(
2020 format!("the function `{item_name}` is implemented on `{deref_ty}`"),
2022 Applicability::MaybeIncorrect,
2027 format!("the function `{item_name}` is implemented on `{deref_ty}`"),
2035 /// Print out the type for use in value namespace.
2036 fn ty_to_value_string(&self, ty: Ty<'tcx>) -> String {
2038 ty::Adt(def, substs) => self.tcx.def_path_str_with_substs(def.did(), substs),
2039 _ => self.ty_to_string(ty),
2043 fn suggest_await_before_method(
2045 err: &mut Diagnostic,
2048 call: &hir::Expr<'_>,
2051 let output_ty = match self.get_impl_future_output_ty(ty) {
2052 Some(output_ty) => self.resolve_vars_if_possible(output_ty),
2055 let method_exists = self.method_exists(item_name, output_ty, call.hir_id, true);
2056 debug!("suggest_await_before_method: is_method_exist={}", method_exists);
2058 err.span_suggestion_verbose(
2059 span.shrink_to_lo(),
2060 "consider `await`ing on the `Future` and calling the method on its `Output`",
2062 Applicability::MaybeIncorrect,
2067 fn suggest_use_candidates(&self, err: &mut Diagnostic, msg: String, candidates: Vec<DefId>) {
2068 let parent_map = self.tcx.visible_parent_map(());
2070 // Separate out candidates that must be imported with a glob, because they are named `_`
2071 // and cannot be referred with their identifier.
2072 let (candidates, globs): (Vec<_>, Vec<_>) = candidates.into_iter().partition(|trait_did| {
2073 if let Some(parent_did) = parent_map.get(trait_did) {
2074 // If the item is re-exported as `_`, we should suggest a glob-import instead.
2075 if *parent_did != self.tcx.parent(*trait_did)
2078 .module_children(*parent_did)
2080 .filter(|child| child.res.opt_def_id() == Some(*trait_did))
2081 .all(|child| child.ident.name == kw::Underscore)
2090 let module_did = self.tcx.parent_module(self.body_id);
2091 let (module, _, _) = self.tcx.hir().get_module(module_did);
2092 let span = module.spans.inject_use_span;
2094 let path_strings = candidates.iter().map(|trait_did| {
2095 format!("use {};\n", with_crate_prefix!(self.tcx.def_path_str(*trait_did)),)
2098 let glob_path_strings = globs.iter().map(|trait_did| {
2099 let parent_did = parent_map.get(trait_did).unwrap();
2101 "use {}::*; // trait {}\n",
2102 with_crate_prefix!(self.tcx.def_path_str(*parent_did)),
2103 self.tcx.item_name(*trait_did),
2107 err.span_suggestions(
2110 path_strings.chain(glob_path_strings),
2111 Applicability::MaybeIncorrect,
2115 fn suggest_valid_traits(
2117 err: &mut Diagnostic,
2118 valid_out_of_scope_traits: Vec<DefId>,
2120 if !valid_out_of_scope_traits.is_empty() {
2121 let mut candidates = valid_out_of_scope_traits;
2125 // `TryFrom` and `FromIterator` have no methods
2126 let edition_fix = candidates
2128 .find(|did| self.tcx.is_diagnostic_item(sym::TryInto, **did))
2131 err.help("items from traits can only be used if the trait is in scope");
2133 "the following {traits_are} implemented but not in scope; \
2134 perhaps add a `use` for {one_of_them}:",
2135 traits_are = if candidates.len() == 1 { "trait is" } else { "traits are" },
2136 one_of_them = if candidates.len() == 1 { "it" } else { "one of them" },
2139 self.suggest_use_candidates(err, msg, candidates);
2140 if let Some(did) = edition_fix {
2142 "'{}' is included in the prelude starting in Edition 2021",
2143 with_crate_prefix!(self.tcx.def_path_str(did))
2153 fn suggest_traits_to_import(
2155 err: &mut Diagnostic,
2159 inputs_len: Option<usize>,
2160 source: SelfSource<'tcx>,
2161 valid_out_of_scope_traits: Vec<DefId>,
2162 unsatisfied_predicates: &[(
2163 ty::Predicate<'tcx>,
2164 Option<ty::Predicate<'tcx>>,
2165 Option<ObligationCause<'tcx>>,
2167 static_candidates: &[CandidateSource],
2168 unsatisfied_bounds: bool,
2170 let mut alt_rcvr_sugg = false;
2171 if let (SelfSource::MethodCall(rcvr), false) = (source, unsatisfied_bounds) {
2173 "suggest_traits_to_import: span={:?}, item_name={:?}, rcvr_ty={:?}, rcvr={:?}",
2174 span, item_name, rcvr_ty, rcvr
2177 self.tcx.lang_items().clone_trait(),
2178 self.tcx.lang_items().deref_trait(),
2179 self.tcx.lang_items().deref_mut_trait(),
2180 self.tcx.lang_items().drop_trait(),
2181 self.tcx.get_diagnostic_item(sym::AsRef),
2183 // Try alternative arbitrary self types that could fulfill this call.
2184 // FIXME: probe for all types that *could* be arbitrary self-types, not
2186 for (rcvr_ty, post) in &[
2188 (self.tcx.mk_mut_ref(self.tcx.lifetimes.re_erased, rcvr_ty), "&mut "),
2189 (self.tcx.mk_imm_ref(self.tcx.lifetimes.re_erased, rcvr_ty), "&"),
2191 match self.lookup_probe(item_name, *rcvr_ty, rcvr, ProbeScope::AllTraits) {
2193 // If the method is defined for the receiver we have, it likely wasn't `use`d.
2194 // We point at the method, but we just skip the rest of the check for arbitrary
2195 // self types and rely on the suggestion to `use` the trait from
2196 // `suggest_valid_traits`.
2197 let did = Some(pick.item.container_id(self.tcx));
2198 let skip = skippable.contains(&did);
2199 if pick.autoderefs == 0 && !skip {
2201 pick.item.ident(self.tcx).span,
2202 &format!("the method is available for `{}` here", rcvr_ty),
2207 Err(MethodError::Ambiguity(_)) => {
2208 // If the method is defined (but ambiguous) for the receiver we have, it is also
2209 // likely we haven't `use`d it. It may be possible that if we `Box`/`Pin`/etc.
2210 // the receiver, then it might disambiguate this method, but I think these
2211 // suggestions are generally misleading (see #94218).
2217 for (rcvr_ty, pre) in &[
2218 (self.tcx.mk_lang_item(*rcvr_ty, LangItem::OwnedBox), "Box::new"),
2219 (self.tcx.mk_lang_item(*rcvr_ty, LangItem::Pin), "Pin::new"),
2220 (self.tcx.mk_diagnostic_item(*rcvr_ty, sym::Arc), "Arc::new"),
2221 (self.tcx.mk_diagnostic_item(*rcvr_ty, sym::Rc), "Rc::new"),
2223 if let Some(new_rcvr_t) = *rcvr_ty
2224 && let Ok(pick) = self.lookup_probe(
2228 ProbeScope::AllTraits,
2231 debug!("try_alt_rcvr: pick candidate {:?}", pick);
2232 let did = Some(pick.item.container_id(self.tcx));
2233 // We don't want to suggest a container type when the missing
2234 // method is `.clone()` or `.deref()` otherwise we'd suggest
2235 // `Arc::new(foo).clone()`, which is far from what the user wants.
2236 // Explicitly ignore the `Pin::as_ref()` method as `Pin` does not
2237 // implement the `AsRef` trait.
2238 let skip = skippable.contains(&did)
2239 || (("Pin::new" == *pre) && (sym::as_ref == item_name.name))
2240 || inputs_len.map_or(false, |inputs_len| pick.item.kind == ty::AssocKind::Fn && self.tcx.fn_sig(pick.item.def_id).skip_binder().inputs().len() != inputs_len);
2241 // Make sure the method is defined for the *actual* receiver: we don't
2242 // want to treat `Box<Self>` as a receiver if it only works because of
2243 // an autoderef to `&self`
2244 if pick.autoderefs == 0 && !skip {
2246 pick.item.ident(self.tcx).span,
2247 &format!("the method is available for `{}` here", new_rcvr_t),
2249 err.multipart_suggestion(
2250 "consider wrapping the receiver expression with the \
2253 (rcvr.span.shrink_to_lo(), format!("{}({}", pre, post)),
2254 (rcvr.span.shrink_to_hi(), ")".to_string()),
2256 Applicability::MaybeIncorrect,
2258 // We don't care about the other suggestions.
2259 alt_rcvr_sugg = true;
2265 if self.suggest_valid_traits(err, valid_out_of_scope_traits) {
2269 let type_is_local = self.type_derefs_to_local(span, rcvr_ty, source);
2271 let mut arbitrary_rcvr = vec![];
2272 // There are no traits implemented, so lets suggest some traits to
2273 // implement, by finding ones that have the item name, and are
2274 // legal to implement.
2275 let mut candidates = all_traits(self.tcx)
2277 // Don't issue suggestions for unstable traits since they're
2278 // unlikely to be implementable anyway
2279 .filter(|info| match self.tcx.lookup_stability(info.def_id) {
2280 Some(attr) => attr.level.is_stable(),
2284 // Static candidates are already implemented, and known not to work
2285 // Do not suggest them again
2286 static_candidates.iter().all(|sc| match *sc {
2287 CandidateSource::Trait(def_id) => def_id != info.def_id,
2288 CandidateSource::Impl(def_id) => {
2289 self.tcx.trait_id_of_impl(def_id) != Some(info.def_id)
2294 // We approximate the coherence rules to only suggest
2295 // traits that are legal to implement by requiring that
2296 // either the type or trait is local. Multi-dispatch means
2297 // this isn't perfect (that is, there are cases when
2298 // implementing a trait would be legal but is rejected
2300 unsatisfied_predicates.iter().all(|(p, _, _)| {
2301 match p.kind().skip_binder() {
2302 // Hide traits if they are present in predicates as they can be fixed without
2303 // having to implement them.
2304 ty::PredicateKind::Clause(ty::Clause::Trait(t)) => {
2305 t.def_id() == info.def_id
2307 ty::PredicateKind::Clause(ty::Clause::Projection(p)) => {
2308 p.projection_ty.def_id == info.def_id
2312 }) && (type_is_local || info.def_id.is_local())
2313 && !self.tcx.trait_is_auto(info.def_id)
2315 .associated_value(info.def_id, item_name)
2317 if let ty::AssocKind::Fn = item.kind {
2321 .map(|def_id| self.tcx.hir().local_def_id_to_hir_id(def_id));
2322 if let Some(hir::Node::TraitItem(hir::TraitItem {
2323 kind: hir::TraitItemKind::Fn(fn_sig, method),
2325 })) = id.map(|id| self.tcx.hir().get(id))
2327 let self_first_arg = match method {
2328 hir::TraitFn::Required([ident, ..]) => {
2329 ident.name == kw::SelfLower
2331 hir::TraitFn::Provided(body_id) => {
2332 self.tcx.hir().body(*body_id).params.first().map_or(
2337 hir::PatKind::Binding(_, _, ident, _)
2338 if ident.name == kw::SelfLower
2346 if !fn_sig.decl.implicit_self.has_implicit_self()
2349 if let Some(ty) = fn_sig.decl.inputs.get(0) {
2350 arbitrary_rcvr.push(ty.span);
2356 // We only want to suggest public or local traits (#45781).
2357 item.visibility(self.tcx).is_public() || info.def_id.is_local()
2361 .collect::<Vec<_>>();
2362 for span in &arbitrary_rcvr {
2365 "the method might not be found because of this arbitrary self type",
2372 if !candidates.is_empty() {
2373 // Sort from most relevant to least relevant.
2374 candidates.sort_by(|a, b| a.cmp(b).reverse());
2377 let param_type = match rcvr_ty.kind() {
2378 ty::Param(param) => Some(param),
2379 ty::Ref(_, ty, _) => match ty.kind() {
2380 ty::Param(param) => Some(param),
2385 err.help(if param_type.is_some() {
2386 "items from traits can only be used if the type parameter is bounded by the trait"
2388 "items from traits can only be used if the trait is implemented and in scope"
2390 let candidates_len = candidates.len();
2391 let message = |action| {
2393 "the following {traits_define} an item `{name}`, perhaps you need to {action} \
2396 if candidates_len == 1 { "trait defines" } else { "traits define" },
2398 one_of_them = if candidates_len == 1 { "it" } else { "one of them" },
2402 // Obtain the span for `param` and use it for a structured suggestion.
2403 if let Some(param) = param_type {
2404 let generics = self.tcx.generics_of(self.body_id.owner.to_def_id());
2405 let type_param = generics.type_param(param, self.tcx);
2406 let hir = self.tcx.hir();
2407 if let Some(def_id) = type_param.def_id.as_local() {
2408 let id = hir.local_def_id_to_hir_id(def_id);
2409 // Get the `hir::Param` to verify whether it already has any bounds.
2410 // We do this to avoid suggesting code that ends up as `T: FooBar`,
2411 // instead we suggest `T: Foo + Bar` in that case.
2413 Node::GenericParam(param) => {
2419 let ast_generics = hir.get_generics(id.owner.def_id).unwrap();
2420 let (sp, mut introducer) = if let Some(span) =
2421 ast_generics.bounds_span_for_suggestions(def_id)
2423 (span, Introducer::Plus)
2424 } else if let Some(colon_span) = param.colon_span {
2425 (colon_span.shrink_to_hi(), Introducer::Nothing)
2427 (param.span.shrink_to_hi(), Introducer::Colon)
2431 hir::GenericParamKind::Type { synthetic: true, .. },
2433 introducer = Introducer::Plus
2435 let trait_def_ids: FxHashSet<DefId> = ast_generics
2436 .bounds_for_param(def_id)
2437 .flat_map(|bp| bp.bounds.iter())
2438 .filter_map(|bound| bound.trait_ref()?.trait_def_id())
2440 if !candidates.iter().any(|t| trait_def_ids.contains(&t.def_id)) {
2441 err.span_suggestions(
2444 "restrict type parameter `{}` with",
2447 candidates.iter().map(|t| {
2451 Introducer::Plus => " +",
2452 Introducer::Colon => ":",
2453 Introducer::Nothing => "",
2455 self.tcx.def_path_str(t.def_id),
2458 Applicability::MaybeIncorrect,
2463 Node::Item(hir::Item {
2464 kind: hir::ItemKind::Trait(.., bounds, _),
2468 let (sp, sep, article) = if bounds.is_empty() {
2469 (ident.span.shrink_to_hi(), ":", "a")
2471 (bounds.last().unwrap().span().shrink_to_hi(), " +", "another")
2473 err.span_suggestions(
2475 &message(format!("add {} supertrait for", article)),
2476 candidates.iter().map(|t| {
2477 format!("{} {}", sep, self.tcx.def_path_str(t.def_id),)
2479 Applicability::MaybeIncorrect,
2488 let (potential_candidates, explicitly_negative) = if param_type.is_some() {
2489 // FIXME: Even though negative bounds are not implemented, we could maybe handle
2490 // cases where a positive bound implies a negative impl.
2491 (candidates, Vec::new())
2492 } else if let Some(simp_rcvr_ty) =
2493 simplify_type(self.tcx, rcvr_ty, TreatParams::AsPlaceholder)
2495 let mut potential_candidates = Vec::new();
2496 let mut explicitly_negative = Vec::new();
2497 for candidate in candidates {
2498 // Check if there's a negative impl of `candidate` for `rcvr_ty`
2501 .all_impls(candidate.def_id)
2503 self.tcx.impl_polarity(*imp_did) == ty::ImplPolarity::Negative
2506 let imp = self.tcx.impl_trait_ref(imp_did).unwrap();
2508 simplify_type(self.tcx, imp.self_ty(), TreatParams::AsPlaceholder);
2509 imp_simp.map_or(false, |s| s == simp_rcvr_ty)
2512 explicitly_negative.push(candidate);
2514 potential_candidates.push(candidate);
2517 (potential_candidates, explicitly_negative)
2519 // We don't know enough about `recv_ty` to make proper suggestions.
2520 (candidates, Vec::new())
2523 let action = if let Some(param) = param_type {
2524 format!("restrict type parameter `{}` with", param)
2526 // FIXME: it might only need to be imported into scope, not implemented.
2527 "implement".to_string()
2529 match &potential_candidates[..] {
2531 [trait_info] if trait_info.def_id.is_local() => {
2533 self.tcx.def_span(trait_info.def_id),
2535 "`{}` defines an item `{}`, perhaps you need to {} it",
2536 self.tcx.def_path_str(trait_info.def_id),
2543 let mut msg = message(action);
2544 for (i, trait_info) in trait_infos.iter().enumerate() {
2545 msg.push_str(&format!(
2546 "\ncandidate #{}: `{}`",
2548 self.tcx.def_path_str(trait_info.def_id),
2554 match &explicitly_negative[..] {
2558 "the trait `{}` defines an item `{}`, but is explicitly unimplemented",
2559 self.tcx.def_path_str(trait_info.def_id),
2565 let mut msg = format!(
2566 "the following traits define an item `{}`, but are explicitly unimplemented:",
2569 for trait_info in trait_infos {
2570 msg.push_str(&format!("\n{}", self.tcx.def_path_str(trait_info.def_id)));
2578 /// issue #102320, for `unwrap_or` with closure as argument, suggest `unwrap_or_else`
2579 /// FIXME: currently not working for suggesting `map_or_else`, see #102408
2580 pub(crate) fn suggest_else_fn_with_closure(
2582 err: &mut Diagnostic,
2583 expr: &hir::Expr<'_>,
2587 let Some((_def_id_or_name, output, _inputs)) = self.extract_callable_info(expr, found)
2588 else { return false; };
2590 if !self.can_coerce(output, expected) {
2594 let parent = self.tcx.hir().parent_id(expr.hir_id);
2595 if let Some(Node::Expr(call_expr)) = self.tcx.hir().find(parent) &&
2596 let hir::ExprKind::MethodCall(
2597 hir::PathSegment { ident: method_name, .. },
2601 ) = call_expr.kind &&
2602 let Some(self_ty) = self.typeck_results.borrow().expr_ty_opt(self_expr) {
2603 let new_name = Ident {
2604 name: Symbol::intern(&format!("{}_else", method_name.as_str())),
2605 span: method_name.span,
2607 let probe = self.lookup_probe(
2611 ProbeScope::TraitsInScope,
2614 // check the method arguments number
2615 if let Ok(pick) = probe &&
2616 let fn_sig = self.tcx.fn_sig(pick.item.def_id) &&
2617 let fn_args = fn_sig.skip_binder().inputs() &&
2618 fn_args.len() == args.len() + 1 {
2619 err.span_suggestion_verbose(
2620 method_name.span.shrink_to_hi(),
2621 &format!("try calling `{}` instead", new_name.name.as_str()),
2623 Applicability::MaybeIncorrect,
2631 /// Checks whether there is a local type somewhere in the chain of
2632 /// autoderefs of `rcvr_ty`.
2633 fn type_derefs_to_local(
2637 source: SelfSource<'tcx>,
2639 fn is_local(ty: Ty<'_>) -> bool {
2641 ty::Adt(def, _) => def.did().is_local(),
2642 ty::Foreign(did) => did.is_local(),
2643 ty::Dynamic(tr, ..) => tr.principal().map_or(false, |d| d.def_id().is_local()),
2644 ty::Param(_) => true,
2646 // Everything else (primitive types, etc.) is effectively
2647 // non-local (there are "edge" cases, e.g., `(LocalType,)`, but
2648 // the noise from these sort of types is usually just really
2649 // annoying, rather than any sort of help).
2654 // This occurs for UFCS desugaring of `T::method`, where there is no
2655 // receiver expression for the method call, and thus no autoderef.
2656 if let SelfSource::QPath(_) = source {
2657 return is_local(self.resolve_vars_with_obligations(rcvr_ty));
2660 self.autoderef(span, rcvr_ty).any(|(ty, _)| is_local(ty))
2664 #[derive(Copy, Clone, Debug)]
2665 pub enum SelfSource<'a> {
2666 QPath(&'a hir::Ty<'a>),
2667 MethodCall(&'a hir::Expr<'a> /* rcvr */),
2670 #[derive(Copy, Clone)]
2671 pub struct TraitInfo {
2675 impl PartialEq for TraitInfo {
2676 fn eq(&self, other: &TraitInfo) -> bool {
2677 self.cmp(other) == Ordering::Equal
2680 impl Eq for TraitInfo {}
2681 impl PartialOrd for TraitInfo {
2682 fn partial_cmp(&self, other: &TraitInfo) -> Option<Ordering> {
2683 Some(self.cmp(other))
2686 impl Ord for TraitInfo {
2687 fn cmp(&self, other: &TraitInfo) -> Ordering {
2688 // Local crates are more important than remote ones (local:
2689 // `cnum == 0`), and otherwise we throw in the defid for totality.
2691 let lhs = (other.def_id.krate, other.def_id);
2692 let rhs = (self.def_id.krate, self.def_id);
2697 /// Retrieves all traits in this crate and any dependent crates,
2698 /// and wraps them into `TraitInfo` for custom sorting.
2699 pub fn all_traits(tcx: TyCtxt<'_>) -> Vec<TraitInfo> {
2700 tcx.all_traits().map(|def_id| TraitInfo { def_id }).collect()
2703 fn print_disambiguation_help<'tcx>(
2705 args: Option<(&'tcx hir::Expr<'tcx>, &'tcx [hir::Expr<'tcx>])>,
2706 err: &mut Diagnostic,
2709 kind: ty::AssocKind,
2712 candidate: Option<usize>,
2713 source_map: &source_map::SourceMap,
2714 fn_has_self_parameter: bool,
2716 let mut applicability = Applicability::MachineApplicable;
2717 let (span, sugg) = if let (ty::AssocKind::Fn, Some((receiver, args))) = (kind, args) {
2720 rcvr_ty.ref_mutability().map_or("", |mutbl| mutbl.ref_prefix_str()),
2721 std::iter::once(receiver)
2723 .map(|arg| source_map.span_to_snippet(arg.span).unwrap_or_else(|_| {
2724 applicability = Applicability::HasPlaceholders;
2727 .collect::<Vec<_>>()
2730 let trait_name = if !fn_has_self_parameter {
2731 format!("<{} as {}>", rcvr_ty, trait_name)
2735 (span, format!("{}::{}{}", trait_name, item_name, args))
2737 (span.with_hi(item_name.span.lo()), format!("<{} as {}>::", rcvr_ty, trait_name))
2739 err.span_suggestion_verbose(
2742 "disambiguate the {} for {}",
2743 kind.as_def_kind().descr(def_id),
2744 if let Some(candidate) = candidate {
2745 format!("candidate #{}", candidate)
2747 "the candidate".to_string()