1use core::ops::ControlFlow;
7use std::borrow::Cow;
8use std::path::PathBuf;
9
10use hir::Expr;
11use rustc_ast::ast::Mutability;
12use rustc_attr_parsing::parse_confusables;
13use rustc_data_structures::fx::{FxIndexMap, FxIndexSet};
14use rustc_data_structures::sorted_map::SortedMap;
15use rustc_data_structures::unord::UnordSet;
16use rustc_errors::codes::*;
17use rustc_errors::{Applicability, Diag, MultiSpan, StashKey, pluralize, struct_span_code_err};
18use rustc_hir::def::{CtorKind, DefKind, Res};
19use rustc_hir::def_id::DefId;
20use rustc_hir::intravisit::{self, Visitor};
21use rustc_hir::lang_items::LangItem;
22use rustc_hir::{self as hir, ExprKind, HirId, Node, PathSegment, QPath};
23use rustc_infer::infer::{self, RegionVariableOrigin};
24use rustc_middle::bug;
25use rustc_middle::ty::fast_reject::{DeepRejectCtxt, TreatParams, simplify_type};
26use rustc_middle::ty::print::{
27 PrintTraitRefExt as _, with_crate_prefix, with_forced_trimmed_paths,
28};
29use rustc_middle::ty::{self, GenericArgKind, IsSuggestable, Ty, TyCtxt, TypeVisitableExt};
30use rustc_span::def_id::DefIdSet;
31use rustc_span::{
32 DUMMY_SP, ErrorGuaranteed, ExpnKind, FileName, Ident, MacroKind, Span, Symbol, edit_distance,
33 kw, sym,
34};
35use rustc_trait_selection::error_reporting::traits::DefIdOrName;
36use rustc_trait_selection::error_reporting::traits::on_unimplemented::OnUnimplementedNote;
37use rustc_trait_selection::infer::InferCtxtExt;
38use rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt as _;
39use rustc_trait_selection::traits::{
40 FulfillmentError, Obligation, ObligationCause, ObligationCauseCode, supertraits,
41};
42use tracing::{debug, info, instrument};
43
44use super::probe::{AutorefOrPtrAdjustment, IsSuggestion, Mode, ProbeScope};
45use super::{CandidateSource, MethodError, NoMatchData};
46use crate::errors::{self, CandidateTraitNote, NoAssociatedItem};
47use crate::{Expectation, FnCtxt};
48
49impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
50 fn is_slice_ty(&self, ty: Ty<'tcx>, span: Span) -> bool {
51 self.autoderef(span, ty)
52 .silence_errors()
53 .any(|(ty, _)| matches!(ty.kind(), ty::Slice(..) | ty::Array(..)))
54 }
55
56 fn impl_into_iterator_should_be_iterator(
57 &self,
58 ty: Ty<'tcx>,
59 span: Span,
60 unsatisfied_predicates: &Vec<(
61 ty::Predicate<'tcx>,
62 Option<ty::Predicate<'tcx>>,
63 Option<ObligationCause<'tcx>>,
64 )>,
65 ) -> bool {
66 fn predicate_bounds_generic_param<'tcx>(
67 predicate: ty::Predicate<'_>,
68 generics: &'tcx ty::Generics,
69 generic_param: &ty::GenericParamDef,
70 tcx: TyCtxt<'tcx>,
71 ) -> bool {
72 if let ty::PredicateKind::Clause(ty::ClauseKind::Trait(trait_pred)) =
73 predicate.kind().as_ref().skip_binder()
74 {
75 let ty::TraitPredicate { trait_ref: ty::TraitRef { args, .. }, .. } = trait_pred;
76 if args.is_empty() {
77 return false;
78 }
79 let Some(arg_ty) = args[0].as_type() else {
80 return false;
81 };
82 let ty::Param(param) = *arg_ty.kind() else {
83 return false;
84 };
85 generic_param.index == generics.type_param(param, tcx).index
87 } else {
88 false
89 }
90 }
91
92 let is_iterator_predicate = |predicate: ty::Predicate<'tcx>| -> bool {
93 if let ty::PredicateKind::Clause(ty::ClauseKind::Trait(trait_pred)) =
94 predicate.kind().as_ref().skip_binder()
95 {
96 self.tcx.is_diagnostic_item(sym::Iterator, trait_pred.trait_ref.def_id)
97 && trait_pred.trait_ref.self_ty() == ty
99 } else {
100 false
101 }
102 };
103
104 let Some(into_iterator_trait) = self.tcx.get_diagnostic_item(sym::IntoIterator) else {
106 return false;
107 };
108 let trait_ref = ty::TraitRef::new(self.tcx, into_iterator_trait, [ty]);
109 let obligation = Obligation::new(self.tcx, self.misc(span), self.param_env, trait_ref);
110 if !self.predicate_must_hold_modulo_regions(&obligation) {
111 return false;
112 }
113
114 match *ty.peel_refs().kind() {
115 ty::Param(param) => {
116 let generics = self.tcx.generics_of(self.body_id);
117 let generic_param = generics.type_param(param, self.tcx);
118 for unsatisfied in unsatisfied_predicates.iter() {
119 if predicate_bounds_generic_param(
122 unsatisfied.0,
123 generics,
124 generic_param,
125 self.tcx,
126 ) && is_iterator_predicate(unsatisfied.0)
127 {
128 return true;
129 }
130 }
131 }
132 ty::Slice(..) | ty::Adt(..) | ty::Alias(ty::Opaque, _) => {
133 for unsatisfied in unsatisfied_predicates.iter() {
134 if is_iterator_predicate(unsatisfied.0) {
135 return true;
136 }
137 }
138 }
139 _ => return false,
140 }
141 false
142 }
143
144 #[instrument(level = "debug", skip(self))]
145 pub(crate) fn report_method_error(
146 &self,
147 call_id: HirId,
148 rcvr_ty: Ty<'tcx>,
149 error: MethodError<'tcx>,
150 expected: Expectation<'tcx>,
151 trait_missing_method: bool,
152 ) -> ErrorGuaranteed {
153 for &import_id in
156 self.tcx.in_scope_traits(call_id).into_iter().flatten().flat_map(|c| &c.import_ids)
157 {
158 self.typeck_results.borrow_mut().used_trait_imports.insert(import_id);
159 }
160
161 let (span, sugg_span, source, item_name, args) = match self.tcx.hir_node(call_id) {
162 hir::Node::Expr(&hir::Expr {
163 kind: hir::ExprKind::MethodCall(segment, rcvr, args, _),
164 span,
165 ..
166 }) => {
167 (segment.ident.span, span, SelfSource::MethodCall(rcvr), segment.ident, Some(args))
168 }
169 hir::Node::Expr(&hir::Expr {
170 kind: hir::ExprKind::Path(QPath::TypeRelative(rcvr, segment)),
171 span,
172 ..
173 })
174 | hir::Node::PatExpr(&hir::PatExpr {
175 kind: hir::PatExprKind::Path(QPath::TypeRelative(rcvr, segment)),
176 span,
177 ..
178 })
179 | hir::Node::Pat(&hir::Pat {
180 kind:
181 hir::PatKind::Struct(QPath::TypeRelative(rcvr, segment), ..)
182 | hir::PatKind::TupleStruct(QPath::TypeRelative(rcvr, segment), ..),
183 span,
184 ..
185 }) => {
186 let args = match self.tcx.parent_hir_node(call_id) {
187 hir::Node::Expr(&hir::Expr {
188 kind: hir::ExprKind::Call(callee, args), ..
189 }) if callee.hir_id == call_id => Some(args),
190 _ => None,
191 };
192 (segment.ident.span, span, SelfSource::QPath(rcvr), segment.ident, args)
193 }
194 node => unreachable!("{node:?}"),
195 };
196
197 if let Err(guar) = rcvr_ty.error_reported() {
199 return guar;
200 }
201
202 match error {
203 MethodError::NoMatch(mut no_match_data) => self.report_no_match_method_error(
204 span,
205 rcvr_ty,
206 item_name,
207 call_id,
208 source,
209 args,
210 sugg_span,
211 &mut no_match_data,
212 expected,
213 trait_missing_method,
214 ),
215
216 MethodError::Ambiguity(mut sources) => {
217 let mut err = struct_span_code_err!(
218 self.dcx(),
219 item_name.span,
220 E0034,
221 "multiple applicable items in scope"
222 );
223 err.span_label(item_name.span, format!("multiple `{item_name}` found"));
224
225 self.note_candidates_on_method_error(
226 rcvr_ty,
227 item_name,
228 source,
229 args,
230 span,
231 &mut err,
232 &mut sources,
233 Some(sugg_span),
234 );
235 err.emit()
236 }
237
238 MethodError::PrivateMatch(kind, def_id, out_of_scope_traits) => {
239 let kind = self.tcx.def_kind_descr(kind, def_id);
240 let mut err = struct_span_code_err!(
241 self.dcx(),
242 item_name.span,
243 E0624,
244 "{} `{}` is private",
245 kind,
246 item_name
247 );
248 err.span_label(item_name.span, format!("private {kind}"));
249 let sp = self
250 .tcx
251 .hir()
252 .span_if_local(def_id)
253 .unwrap_or_else(|| self.tcx.def_span(def_id));
254 err.span_label(sp, format!("private {kind} defined here"));
255 self.suggest_valid_traits(&mut err, item_name, out_of_scope_traits, true);
256 err.emit()
257 }
258
259 MethodError::IllegalSizedBound { candidates, needs_mut, bound_span, self_expr } => {
260 let msg = if needs_mut {
261 with_forced_trimmed_paths!(format!(
262 "the `{item_name}` method cannot be invoked on `{rcvr_ty}`"
263 ))
264 } else {
265 format!("the `{item_name}` method cannot be invoked on a trait object")
266 };
267 let mut err = self.dcx().struct_span_err(span, msg);
268 if !needs_mut {
269 err.span_label(bound_span, "this has a `Sized` requirement");
270 }
271 if !candidates.is_empty() {
272 let help = format!(
273 "{an}other candidate{s} {were} found in the following trait{s}",
274 an = if candidates.len() == 1 { "an" } else { "" },
275 s = pluralize!(candidates.len()),
276 were = pluralize!("was", candidates.len()),
277 );
278 self.suggest_use_candidates(
279 candidates,
280 |accessible_sugg, inaccessible_sugg, span| {
281 let suggest_for_access =
282 |err: &mut Diag<'_>, mut msg: String, sugg: Vec<_>| {
283 msg += &format!(
284 ", perhaps add a `use` for {one_of_them}:",
285 one_of_them =
286 if sugg.len() == 1 { "it" } else { "one_of_them" },
287 );
288 err.span_suggestions(
289 span,
290 msg,
291 sugg,
292 Applicability::MaybeIncorrect,
293 );
294 };
295 let suggest_for_privacy =
296 |err: &mut Diag<'_>, mut msg: String, suggs: Vec<String>| {
297 if let [sugg] = suggs.as_slice() {
298 err.help(format!("\
299 trait `{}` provides `{item_name}` is implemented but not reachable",
300 sugg.trim(),
301 ));
302 } else {
303 msg += &format!(" but {} not reachable", pluralize!("is", suggs.len()));
304 err.span_suggestions(
305 span,
306 msg,
307 suggs,
308 Applicability::MaybeIncorrect,
309 );
310 }
311 };
312 if accessible_sugg.is_empty() {
313 suggest_for_privacy(&mut err, help, inaccessible_sugg);
315 } else if inaccessible_sugg.is_empty() {
316 suggest_for_access(&mut err, help, accessible_sugg);
317 } else {
318 suggest_for_access(&mut err, help.clone(), accessible_sugg);
319 suggest_for_privacy(&mut err, help, inaccessible_sugg);
320 }
321 },
322 );
323 }
324 if let ty::Ref(region, t_type, mutability) = rcvr_ty.kind() {
325 if needs_mut {
326 let trait_type =
327 Ty::new_ref(self.tcx, *region, *t_type, mutability.invert());
328 let msg = format!("you need `{trait_type}` instead of `{rcvr_ty}`");
329 let mut kind = &self_expr.kind;
330 while let hir::ExprKind::AddrOf(_, _, expr)
331 | hir::ExprKind::Unary(hir::UnOp::Deref, expr) = kind
332 {
333 kind = &expr.kind;
334 }
335 if let hir::ExprKind::Path(hir::QPath::Resolved(None, path)) = kind
336 && let hir::def::Res::Local(hir_id) = path.res
337 && let hir::Node::Pat(b) = self.tcx.hir_node(hir_id)
338 && let hir::Node::Param(p) = self.tcx.parent_hir_node(b.hir_id)
339 && let Some(decl) = self.tcx.parent_hir_node(p.hir_id).fn_decl()
340 && let Some(ty) = decl.inputs.iter().find(|ty| ty.span == p.ty_span)
341 && let hir::TyKind::Ref(_, mut_ty) = &ty.kind
342 && let hir::Mutability::Not = mut_ty.mutbl
343 {
344 err.span_suggestion_verbose(
345 mut_ty.ty.span.shrink_to_lo(),
346 msg,
347 "mut ",
348 Applicability::MachineApplicable,
349 );
350 } else {
351 err.help(msg);
352 }
353 }
354 }
355 err.emit()
356 }
357
358 MethodError::ErrorReported(guar) => guar,
359
360 MethodError::BadReturnType => bug!("no return type expectations but got BadReturnType"),
361 }
362 }
363
364 fn suggest_missing_writer(&self, rcvr_ty: Ty<'tcx>, rcvr_expr: &hir::Expr<'tcx>) -> Diag<'_> {
365 let mut file = None;
366 let mut err = struct_span_code_err!(
367 self.dcx(),
368 rcvr_expr.span,
369 E0599,
370 "cannot write into `{}`",
371 self.tcx.short_string(rcvr_ty, &mut file),
372 );
373 *err.long_ty_path() = file;
374 err.span_note(
375 rcvr_expr.span,
376 "must implement `io::Write`, `fmt::Write`, or have a `write_fmt` method",
377 );
378 if let ExprKind::Lit(_) = rcvr_expr.kind {
379 err.span_help(
380 rcvr_expr.span.shrink_to_lo(),
381 "a writer is needed before this format string",
382 );
383 };
384 err
385 }
386
387 fn suggest_use_shadowed_binding_with_method(
388 &self,
389 self_source: SelfSource<'tcx>,
390 method_name: Ident,
391 ty_str_reported: &str,
392 err: &mut Diag<'_>,
393 ) {
394 #[derive(Debug)]
395 struct LetStmt {
396 ty_hir_id_opt: Option<hir::HirId>,
397 binding_id: hir::HirId,
398 span: Span,
399 init_hir_id: hir::HirId,
400 }
401
402 struct LetVisitor<'a, 'tcx> {
412 binding_name: Symbol,
414 binding_id: hir::HirId,
415 fcx: &'a FnCtxt<'a, 'tcx>,
417 call_expr: &'tcx Expr<'tcx>,
418 method_name: Ident,
419 sugg_let: Option<LetStmt>,
421 }
422
423 impl<'a, 'tcx> LetVisitor<'a, 'tcx> {
424 fn is_sub_scope(&self, sub_id: hir::ItemLocalId, super_id: hir::ItemLocalId) -> bool {
426 let scope_tree = self.fcx.tcx.region_scope_tree(self.fcx.body_id);
427 if let Some(sub_var_scope) = scope_tree.var_scope(sub_id)
428 && let Some(super_var_scope) = scope_tree.var_scope(super_id)
429 && scope_tree.is_subscope_of(sub_var_scope, super_var_scope)
430 {
431 return true;
432 }
433 false
434 }
435
436 fn check_and_add_sugg_binding(&mut self, binding: LetStmt) -> bool {
439 if !self.is_sub_scope(self.binding_id.local_id, binding.binding_id.local_id) {
440 return false;
441 }
442
443 if let Some(ty_hir_id) = binding.ty_hir_id_opt
445 && let Some(tyck_ty) = self.fcx.node_ty_opt(ty_hir_id)
446 {
447 if self
448 .fcx
449 .lookup_probe_for_diagnostic(
450 self.method_name,
451 tyck_ty,
452 self.call_expr,
453 ProbeScope::TraitsInScope,
454 None,
455 )
456 .is_ok()
457 {
458 self.sugg_let = Some(binding);
459 return true;
460 } else {
461 return false;
462 }
463 }
464
465 if let Some(self_ty) = self.fcx.node_ty_opt(binding.init_hir_id)
470 && self
471 .fcx
472 .lookup_probe_for_diagnostic(
473 self.method_name,
474 self_ty,
475 self.call_expr,
476 ProbeScope::TraitsInScope,
477 None,
478 )
479 .is_ok()
480 {
481 self.sugg_let = Some(binding);
482 return true;
483 }
484 return false;
485 }
486 }
487
488 impl<'v> Visitor<'v> for LetVisitor<'_, '_> {
489 type Result = ControlFlow<()>;
490 fn visit_stmt(&mut self, ex: &'v hir::Stmt<'v>) -> Self::Result {
491 if let hir::StmtKind::Let(&hir::LetStmt { pat, ty, init, .. }) = ex.kind
492 && let hir::PatKind::Binding(_, binding_id, binding_name, ..) = pat.kind
493 && let Some(init) = init
494 && binding_name.name == self.binding_name
495 && binding_id != self.binding_id
496 {
497 if self.check_and_add_sugg_binding(LetStmt {
498 ty_hir_id_opt: ty.map(|ty| ty.hir_id),
499 binding_id,
500 span: pat.span,
501 init_hir_id: init.hir_id,
502 }) {
503 return ControlFlow::Break(());
504 }
505 ControlFlow::Continue(())
506 } else {
507 hir::intravisit::walk_stmt(self, ex)
508 }
509 }
510
511 fn visit_pat(&mut self, p: &'v hir::Pat<'v>) -> Self::Result {
515 match p.kind {
516 hir::PatKind::Binding(_, binding_id, binding_name, _) => {
517 if binding_name.name == self.binding_name && binding_id == self.binding_id {
518 return ControlFlow::Break(());
519 }
520 }
521 _ => {
522 intravisit::walk_pat(self, p);
523 }
524 }
525 ControlFlow::Continue(())
526 }
527 }
528
529 if let SelfSource::MethodCall(rcvr) = self_source
530 && let hir::ExprKind::Path(QPath::Resolved(_, path)) = rcvr.kind
531 && let hir::def::Res::Local(recv_id) = path.res
532 && let Some(segment) = path.segments.first()
533 {
534 let body = self.tcx.hir().body_owned_by(self.body_id);
535
536 if let Node::Expr(call_expr) = self.tcx.parent_hir_node(rcvr.hir_id) {
537 let mut let_visitor = LetVisitor {
538 fcx: self,
539 call_expr,
540 binding_name: segment.ident.name,
541 binding_id: recv_id,
542 method_name,
543 sugg_let: None,
544 };
545 let_visitor.visit_body(&body);
546 if let Some(sugg_let) = let_visitor.sugg_let
547 && let Some(self_ty) = self.node_ty_opt(sugg_let.init_hir_id)
548 {
549 let _sm = self.infcx.tcx.sess.source_map();
550 let rcvr_name = segment.ident.name;
551 let mut span = MultiSpan::from_span(sugg_let.span);
552 span.push_span_label(sugg_let.span,
553 format!("`{rcvr_name}` of type `{self_ty}` that has method `{method_name}` defined earlier here"));
554 span.push_span_label(
555 self.tcx.hir().span(recv_id),
556 format!(
557 "earlier `{rcvr_name}` shadowed here with type `{ty_str_reported}`"
558 ),
559 );
560 err.span_note(
561 span,
562 format!(
563 "there's an earlier shadowed binding `{rcvr_name}` of type `{self_ty}` \
564 that has method `{method_name}` available"
565 ),
566 );
567 }
568 }
569 }
570 }
571
572 fn report_no_match_method_error(
573 &self,
574 mut span: Span,
575 rcvr_ty: Ty<'tcx>,
576 item_name: Ident,
577 expr_id: hir::HirId,
578 source: SelfSource<'tcx>,
579 args: Option<&'tcx [hir::Expr<'tcx>]>,
580 sugg_span: Span,
581 no_match_data: &mut NoMatchData<'tcx>,
582 expected: Expectation<'tcx>,
583 trait_missing_method: bool,
584 ) -> ErrorGuaranteed {
585 let mode = no_match_data.mode;
586 let tcx = self.tcx;
587 let rcvr_ty = self.resolve_vars_if_possible(rcvr_ty);
588 let mut ty_file = None;
589 let (mut ty_str, short_ty_str) =
590 if trait_missing_method && let ty::Dynamic(predicates, _, _) = rcvr_ty.kind() {
591 (predicates.to_string(), with_forced_trimmed_paths!(predicates.to_string()))
592 } else {
593 (
594 tcx.short_string(rcvr_ty, &mut ty_file),
595 with_forced_trimmed_paths!(rcvr_ty.to_string()),
596 )
597 };
598 let is_method = mode == Mode::MethodCall;
599 let unsatisfied_predicates = &no_match_data.unsatisfied_predicates;
600 let similar_candidate = no_match_data.similar_candidate;
601 let item_kind = if is_method {
602 "method"
603 } else if rcvr_ty.is_enum() {
604 "variant or associated item"
605 } else {
606 match (item_name.as_str().chars().next(), rcvr_ty.is_fresh_ty()) {
607 (Some(name), false) if name.is_lowercase() => "function or associated item",
608 (Some(_), false) => "associated item",
609 (Some(_), true) | (None, false) => "variant or associated item",
610 (None, true) => "variant",
611 }
612 };
613
614 if let Err(guar) = self.report_failed_method_call_on_range_end(
617 tcx,
618 rcvr_ty,
619 source,
620 span,
621 item_name,
622 &short_ty_str,
623 &mut ty_file,
624 ) {
625 return guar;
626 }
627 if let Err(guar) = self.report_failed_method_call_on_numerical_infer_var(
628 tcx,
629 rcvr_ty,
630 source,
631 span,
632 item_kind,
633 item_name,
634 &short_ty_str,
635 &mut ty_file,
636 ) {
637 return guar;
638 }
639 span = item_name.span;
640
641 let mut ty_str_reported = ty_str.clone();
643 if let ty::Adt(_, generics) = rcvr_ty.kind() {
644 if generics.len() > 0 {
645 let mut autoderef = self.autoderef(span, rcvr_ty).silence_errors();
646 let candidate_found = autoderef.any(|(ty, _)| {
647 if let ty::Adt(adt_def, _) = ty.kind() {
648 self.tcx
649 .inherent_impls(adt_def.did())
650 .into_iter()
651 .any(|def_id| self.associated_value(*def_id, item_name).is_some())
652 } else {
653 false
654 }
655 });
656 let has_deref = autoderef.step_count() > 0;
657 if !candidate_found && !has_deref && unsatisfied_predicates.is_empty() {
658 if let Some((path_string, _)) = ty_str.split_once('<') {
659 ty_str_reported = path_string.to_string();
660 }
661 }
662 }
663 }
664
665 let is_write = sugg_span.ctxt().outer_expn_data().macro_def_id.is_some_and(|def_id| {
666 tcx.is_diagnostic_item(sym::write_macro, def_id)
667 || tcx.is_diagnostic_item(sym::writeln_macro, def_id)
668 }) && item_name.name == sym::write_fmt;
669 let mut err = if is_write && let SelfSource::MethodCall(rcvr_expr) = source {
670 self.suggest_missing_writer(rcvr_ty, rcvr_expr)
671 } else {
672 let mut err = self.dcx().create_err(NoAssociatedItem {
673 span,
674 item_kind,
675 item_name,
676 ty_prefix: if trait_missing_method {
677 Cow::from("trait")
679 } else {
680 rcvr_ty.prefix_string(self.tcx)
681 },
682 ty_str: ty_str_reported.clone(),
683 trait_missing_method,
684 });
685
686 if is_method {
687 self.suggest_use_shadowed_binding_with_method(
688 source,
689 item_name,
690 &ty_str_reported,
691 &mut err,
692 );
693 }
694
695 if let SelfSource::QPath(ty) = source
697 && let hir::TyKind::Path(hir::QPath::Resolved(_, path)) = ty.kind
698 && let Res::SelfTyAlias { alias_to: impl_def_id, .. } = path.res
699 && let DefKind::Impl { .. } = self.tcx.def_kind(impl_def_id)
700 && let Some(candidate) = tcx.associated_items(impl_def_id).find_by_name_and_kind(
701 self.tcx,
702 item_name,
703 ty::AssocKind::Type,
704 impl_def_id,
705 )
706 && let Some(adt_def) = tcx.type_of(candidate.def_id).skip_binder().ty_adt_def()
707 && adt_def.is_struct()
708 && adt_def.non_enum_variant().ctor_kind() == Some(CtorKind::Fn)
709 {
710 let def_path = tcx.def_path_str(adt_def.did());
711 err.span_suggestion(
712 ty.span.to(item_name.span),
713 format!("to construct a value of type `{}`, use the explicit path", def_path),
714 def_path,
715 Applicability::MachineApplicable,
716 );
717 }
718
719 err
720 };
721 if tcx.sess.source_map().is_multiline(sugg_span) {
722 err.span_label(sugg_span.with_hi(span.lo()), "");
723 }
724
725 if short_ty_str.len() < ty_str.len() && ty_str.len() > 10 {
726 ty_str = short_ty_str;
727 }
728
729 if rcvr_ty.references_error() {
730 err.downgrade_to_delayed_bug();
731 }
732
733 if matches!(source, SelfSource::QPath(_)) && args.is_some() {
734 self.find_builder_fn(&mut err, rcvr_ty, expr_id);
735 }
736
737 if tcx.ty_is_opaque_future(rcvr_ty) && item_name.name == sym::poll {
738 err.help(format!(
739 "method `poll` found on `Pin<&mut {ty_str}>`, \
740 see documentation for `std::pin::Pin`"
741 ));
742 err.help("self type must be pinned to call `Future::poll`, \
743 see https://rust-lang.github.io/async-book/04_pinning/01_chapter.html#pinning-in-practice"
744 );
745 }
746
747 if let Mode::MethodCall = mode
748 && let SelfSource::MethodCall(cal) = source
749 {
750 self.suggest_await_before_method(
751 &mut err,
752 item_name,
753 rcvr_ty,
754 cal,
755 span,
756 expected.only_has_type(self),
757 );
758 }
759 if let Some(span) =
760 tcx.resolutions(()).confused_type_with_std_module.get(&span.with_parent(None))
761 {
762 err.span_suggestion(
763 span.shrink_to_lo(),
764 "you are looking for the module in `std`, not the primitive type",
765 "std::",
766 Applicability::MachineApplicable,
767 );
768 }
769
770 if let SelfSource::MethodCall(rcvr_expr) = source
772 && let ty::RawPtr(ty, ptr_mutbl) = *rcvr_ty.kind()
773 && let Ok(pick) = self.lookup_probe_for_diagnostic(
774 item_name,
775 Ty::new_ref(tcx, ty::Region::new_error_misc(tcx), ty, ptr_mutbl),
776 self.tcx.hir().expect_expr(self.tcx.parent_hir_id(rcvr_expr.hir_id)),
777 ProbeScope::TraitsInScope,
778 None,
779 )
780 && let ty::Ref(_, _, sugg_mutbl) = *pick.self_ty.kind()
781 && (sugg_mutbl.is_not() || ptr_mutbl.is_mut())
782 {
783 let (method, method_anchor) = match sugg_mutbl {
784 Mutability::Not => {
785 let method_anchor = match ptr_mutbl {
786 Mutability::Not => "as_ref",
787 Mutability::Mut => "as_ref-1",
788 };
789 ("as_ref", method_anchor)
790 }
791 Mutability::Mut => ("as_mut", "as_mut"),
792 };
793 err.span_note(
794 tcx.def_span(pick.item.def_id),
795 format!("the method `{item_name}` exists on the type `{ty}`", ty = pick.self_ty),
796 );
797 let mut_str = ptr_mutbl.ptr_str();
798 err.note(format!(
799 "you might want to use the unsafe method `<*{mut_str} T>::{method}` to get \
800 an optional reference to the value behind the pointer"
801 ));
802 err.note(format!(
803 "read the documentation for `<*{mut_str} T>::{method}` and ensure you satisfy its \
804 safety preconditions before calling it to avoid undefined behavior: \
805 https://doc.rust-lang.org/std/primitive.pointer.html#method.{method_anchor}"
806 ));
807 }
808
809 let mut ty_span = match rcvr_ty.kind() {
810 ty::Param(param_type) => {
811 Some(param_type.span_from_generics(self.tcx, self.body_id.to_def_id()))
812 }
813 ty::Adt(def, _) if def.did().is_local() => Some(tcx.def_span(def.did())),
814 _ => None,
815 };
816
817 if let SelfSource::MethodCall(rcvr_expr) = source {
818 self.suggest_fn_call(&mut err, rcvr_expr, rcvr_ty, |output_ty| {
819 let call_expr =
820 self.tcx.hir().expect_expr(self.tcx.parent_hir_id(rcvr_expr.hir_id));
821 let probe = self.lookup_probe_for_diagnostic(
822 item_name,
823 output_ty,
824 call_expr,
825 ProbeScope::AllTraits,
826 expected.only_has_type(self),
827 );
828 probe.is_ok()
829 });
830 self.note_internal_mutation_in_method(
831 &mut err,
832 rcvr_expr,
833 expected.to_option(self),
834 rcvr_ty,
835 );
836 }
837
838 let mut custom_span_label = false;
839
840 let static_candidates = &mut no_match_data.static_candidates;
841
842 static_candidates.dedup();
846
847 if !static_candidates.is_empty() {
848 err.note(
849 "found the following associated functions; to be used as methods, \
850 functions must have a `self` parameter",
851 );
852 err.span_label(span, "this is an associated function, not a method");
853 custom_span_label = true;
854 }
855 if static_candidates.len() == 1 {
856 self.suggest_associated_call_syntax(
857 &mut err,
858 static_candidates,
859 rcvr_ty,
860 source,
861 item_name,
862 args,
863 sugg_span,
864 );
865 self.note_candidates_on_method_error(
866 rcvr_ty,
867 item_name,
868 source,
869 args,
870 span,
871 &mut err,
872 static_candidates,
873 None,
874 );
875 } else if static_candidates.len() > 1 {
876 self.note_candidates_on_method_error(
877 rcvr_ty,
878 item_name,
879 source,
880 args,
881 span,
882 &mut err,
883 static_candidates,
884 Some(sugg_span),
885 );
886 }
887
888 let mut bound_spans: SortedMap<Span, Vec<String>> = Default::default();
889 let mut restrict_type_params = false;
890 let mut suggested_derive = false;
891 let mut unsatisfied_bounds = false;
892 if item_name.name == sym::count && self.is_slice_ty(rcvr_ty, span) {
893 let msg = "consider using `len` instead";
894 if let SelfSource::MethodCall(_expr) = source {
895 err.span_suggestion_short(span, msg, "len", Applicability::MachineApplicable);
896 } else {
897 err.span_label(span, msg);
898 }
899 if let Some(iterator_trait) = self.tcx.get_diagnostic_item(sym::Iterator) {
900 let iterator_trait = self.tcx.def_path_str(iterator_trait);
901 err.note(format!(
902 "`count` is defined on `{iterator_trait}`, which `{rcvr_ty}` does not implement"
903 ));
904 }
905 } else if self.impl_into_iterator_should_be_iterator(rcvr_ty, span, unsatisfied_predicates)
906 {
907 err.span_label(span, format!("`{rcvr_ty}` is not an iterator"));
908 err.multipart_suggestion_verbose(
909 "call `.into_iter()` first",
910 vec![(span.shrink_to_lo(), format!("into_iter()."))],
911 Applicability::MaybeIncorrect,
912 );
913 return err.emit();
914 } else if !unsatisfied_predicates.is_empty() && matches!(rcvr_ty.kind(), ty::Param(_)) {
915 } else if !unsatisfied_predicates.is_empty() {
926 let mut type_params = FxIndexMap::default();
927
928 let mut unimplemented_traits = FxIndexMap::default();
931 let mut unimplemented_traits_only = true;
932 for (predicate, _parent_pred, cause) in unsatisfied_predicates {
933 if let (ty::PredicateKind::Clause(ty::ClauseKind::Trait(p)), Some(cause)) =
934 (predicate.kind().skip_binder(), cause.as_ref())
935 {
936 if p.trait_ref.self_ty() != rcvr_ty {
937 continue;
941 }
942 unimplemented_traits.entry(p.trait_ref.def_id).or_insert((
943 predicate.kind().rebind(p),
944 Obligation {
945 cause: cause.clone(),
946 param_env: self.param_env,
947 predicate: *predicate,
948 recursion_depth: 0,
949 },
950 ));
951 }
952 }
953
954 for (predicate, _parent_pred, _cause) in unsatisfied_predicates {
959 match predicate.kind().skip_binder() {
960 ty::PredicateKind::Clause(ty::ClauseKind::Trait(p))
961 if unimplemented_traits.contains_key(&p.trait_ref.def_id) => {}
962 _ => {
963 unimplemented_traits_only = false;
964 break;
965 }
966 }
967 }
968
969 let mut collect_type_param_suggestions =
970 |self_ty: Ty<'tcx>, parent_pred: ty::Predicate<'tcx>, obligation: &str| {
971 if let (ty::Param(_), ty::PredicateKind::Clause(ty::ClauseKind::Trait(p))) =
973 (self_ty.kind(), parent_pred.kind().skip_binder())
974 {
975 let node = match p.trait_ref.self_ty().kind() {
976 ty::Param(_) => {
977 Some(self.tcx.hir_node_by_def_id(self.body_id))
980 }
981 ty::Adt(def, _) => def
982 .did()
983 .as_local()
984 .map(|def_id| self.tcx.hir_node_by_def_id(def_id)),
985 _ => None,
986 };
987 if let Some(hir::Node::Item(hir::Item { kind, .. })) = node
988 && let Some(g) = kind.generics()
989 {
990 let key = (
991 g.tail_span_for_predicate_suggestion(),
992 g.add_where_or_trailing_comma(),
993 );
994 type_params
995 .entry(key)
996 .or_insert_with(UnordSet::default)
997 .insert(obligation.to_owned());
998 return true;
999 }
1000 }
1001 false
1002 };
1003 let mut bound_span_label = |self_ty: Ty<'_>, obligation: &str, quiet: &str| {
1004 let msg = format!("`{}`", if obligation.len() > 50 { quiet } else { obligation });
1005 match self_ty.kind() {
1006 ty::Adt(def, _) => {
1008 bound_spans.get_mut_or_insert_default(tcx.def_span(def.did())).push(msg)
1009 }
1010 ty::Dynamic(preds, _, _) => {
1012 for pred in preds.iter() {
1013 match pred.skip_binder() {
1014 ty::ExistentialPredicate::Trait(tr) => {
1015 bound_spans
1016 .get_mut_or_insert_default(tcx.def_span(tr.def_id))
1017 .push(msg.clone());
1018 }
1019 ty::ExistentialPredicate::Projection(_)
1020 | ty::ExistentialPredicate::AutoTrait(_) => {}
1021 }
1022 }
1023 }
1024 ty::Closure(def_id, _) => {
1026 bound_spans
1027 .get_mut_or_insert_default(tcx.def_span(*def_id))
1028 .push(format!("`{quiet}`"));
1029 }
1030 _ => {}
1031 }
1032 };
1033 let mut format_pred = |pred: ty::Predicate<'tcx>| {
1034 let bound_predicate = pred.kind();
1035 match bound_predicate.skip_binder() {
1036 ty::PredicateKind::Clause(ty::ClauseKind::Projection(pred)) => {
1037 let pred = bound_predicate.rebind(pred);
1038 let projection_term = pred.skip_binder().projection_term;
1040 let quiet_projection_term =
1041 projection_term.with_self_ty(tcx, Ty::new_var(tcx, ty::TyVid::ZERO));
1042
1043 let term = pred.skip_binder().term;
1044
1045 let obligation = format!("{projection_term} = {term}");
1046 let quiet = with_forced_trimmed_paths!(format!(
1047 "{} = {}",
1048 quiet_projection_term, term
1049 ));
1050
1051 bound_span_label(projection_term.self_ty(), &obligation, &quiet);
1052 Some((obligation, projection_term.self_ty()))
1053 }
1054 ty::PredicateKind::Clause(ty::ClauseKind::Trait(poly_trait_ref)) => {
1055 let p = poly_trait_ref.trait_ref;
1056 let self_ty = p.self_ty();
1057 let path = p.print_only_trait_path();
1058 let obligation = format!("{self_ty}: {path}");
1059 let quiet = with_forced_trimmed_paths!(format!("_: {}", path));
1060 bound_span_label(self_ty, &obligation, &quiet);
1061 Some((obligation, self_ty))
1062 }
1063 _ => None,
1064 }
1065 };
1066
1067 let mut skip_list: UnordSet<_> = Default::default();
1069 let mut spanned_predicates = FxIndexMap::default();
1070 for (p, parent_p, cause) in unsatisfied_predicates {
1071 let (item_def_id, cause_span) = match cause.as_ref().map(|cause| cause.code()) {
1074 Some(ObligationCauseCode::ImplDerived(data)) => {
1075 (data.impl_or_alias_def_id, data.span)
1076 }
1077 Some(
1078 ObligationCauseCode::WhereClauseInExpr(def_id, span, _, _)
1079 | ObligationCauseCode::WhereClause(def_id, span),
1080 ) if !span.is_dummy() => (*def_id, *span),
1081 _ => continue,
1082 };
1083
1084 if !matches!(
1086 p.kind().skip_binder(),
1087 ty::PredicateKind::Clause(
1088 ty::ClauseKind::Projection(..) | ty::ClauseKind::Trait(..)
1089 )
1090 ) {
1091 continue;
1092 }
1093
1094 match self.tcx.hir().get_if_local(item_def_id) {
1095 Some(Node::Item(hir::Item {
1098 kind: hir::ItemKind::Impl(hir::Impl { of_trait, self_ty, .. }),
1099 ..
1100 })) if matches!(
1101 self_ty.span.ctxt().outer_expn_data().kind,
1102 ExpnKind::Macro(MacroKind::Derive, _)
1103 ) || matches!(
1104 of_trait.as_ref().map(|t| t.path.span.ctxt().outer_expn_data().kind),
1105 Some(ExpnKind::Macro(MacroKind::Derive, _))
1106 ) =>
1107 {
1108 let span = self_ty.span.ctxt().outer_expn_data().call_site;
1109 let entry = spanned_predicates.entry(span);
1110 let entry = entry.or_insert_with(|| {
1111 (FxIndexSet::default(), FxIndexSet::default(), Vec::new())
1112 });
1113 entry.0.insert(span);
1114 entry.1.insert((
1115 span,
1116 "unsatisfied trait bound introduced in this `derive` macro",
1117 ));
1118 entry.2.push(p);
1119 skip_list.insert(p);
1120 }
1121
1122 Some(Node::Item(hir::Item {
1124 kind: hir::ItemKind::Impl(hir::Impl { of_trait, self_ty, generics, .. }),
1125 span: item_span,
1126 ..
1127 })) => {
1128 let sized_pred =
1129 unsatisfied_predicates.iter().any(|(pred, _, _)| {
1130 match pred.kind().skip_binder() {
1131 ty::PredicateKind::Clause(ty::ClauseKind::Trait(pred)) => {
1132 self.tcx.is_lang_item(pred.def_id(), LangItem::Sized)
1133 && pred.polarity == ty::PredicatePolarity::Positive
1134 }
1135 _ => false,
1136 }
1137 });
1138 for param in generics.params {
1139 if param.span == cause_span && sized_pred {
1140 let (sp, sugg) = match param.colon_span {
1141 Some(sp) => (sp.shrink_to_hi(), " ?Sized +"),
1142 None => (param.span.shrink_to_hi(), ": ?Sized"),
1143 };
1144 err.span_suggestion_verbose(
1145 sp,
1146 "consider relaxing the type parameter's implicit `Sized` bound",
1147 sugg,
1148 Applicability::MachineApplicable,
1149 );
1150 }
1151 }
1152 if let Some(pred) = parent_p {
1153 let _ = format_pred(*pred);
1155 }
1156 skip_list.insert(p);
1157 let entry = spanned_predicates.entry(self_ty.span);
1158 let entry = entry.or_insert_with(|| {
1159 (FxIndexSet::default(), FxIndexSet::default(), Vec::new())
1160 });
1161 entry.2.push(p);
1162 if cause_span != *item_span {
1163 entry.0.insert(cause_span);
1164 entry.1.insert((cause_span, "unsatisfied trait bound introduced here"));
1165 } else {
1166 if let Some(trait_ref) = of_trait {
1167 entry.0.insert(trait_ref.path.span);
1168 }
1169 entry.0.insert(self_ty.span);
1170 };
1171 if let Some(trait_ref) = of_trait {
1172 entry.1.insert((trait_ref.path.span, ""));
1173 }
1174 entry.1.insert((self_ty.span, ""));
1175 }
1176 Some(Node::Item(hir::Item {
1177 kind: hir::ItemKind::Trait(rustc_ast::ast::IsAuto::Yes, ..),
1178 span: item_span,
1179 ..
1180 })) => {
1181 self.dcx().span_delayed_bug(
1182 *item_span,
1183 "auto trait is invoked with no method error, but no error reported?",
1184 );
1185 }
1186 Some(
1187 Node::Item(hir::Item {
1188 ident,
1189 kind: hir::ItemKind::Trait(..) | hir::ItemKind::TraitAlias(..),
1190 ..
1191 })
1192 | Node::TraitItem(hir::TraitItem { ident, .. })
1194 | Node::ImplItem(hir::ImplItem { ident, .. }),
1195 ) => {
1196 skip_list.insert(p);
1197 let entry = spanned_predicates.entry(ident.span);
1198 let entry = entry.or_insert_with(|| {
1199 (FxIndexSet::default(), FxIndexSet::default(), Vec::new())
1200 });
1201 entry.0.insert(cause_span);
1202 entry.1.insert((ident.span, ""));
1203 entry.1.insert((cause_span, "unsatisfied trait bound introduced here"));
1204 entry.2.push(p);
1205 }
1206 _ => {
1207 }
1212 }
1213 }
1214 let mut spanned_predicates: Vec<_> = spanned_predicates.into_iter().collect();
1215 spanned_predicates.sort_by_key(|(span, _)| *span);
1216 for (_, (primary_spans, span_labels, predicates)) in spanned_predicates {
1217 let mut preds: Vec<_> = predicates
1218 .iter()
1219 .filter_map(|pred| format_pred(**pred))
1220 .map(|(p, _)| format!("`{p}`"))
1221 .collect();
1222 preds.sort();
1223 preds.dedup();
1224 let msg = if let [pred] = &preds[..] {
1225 format!("trait bound {pred} was not satisfied")
1226 } else {
1227 format!("the following trait bounds were not satisfied:\n{}", preds.join("\n"),)
1228 };
1229 let mut span: MultiSpan = primary_spans.into_iter().collect::<Vec<_>>().into();
1230 for (sp, label) in span_labels {
1231 span.push_span_label(sp, label);
1232 }
1233 err.span_note(span, msg);
1234 unsatisfied_bounds = true;
1235 }
1236
1237 let mut suggested_bounds = UnordSet::default();
1238 let mut bound_list = unsatisfied_predicates
1240 .iter()
1241 .filter_map(|(pred, parent_pred, _cause)| {
1242 let mut suggested = false;
1243 format_pred(*pred).map(|(p, self_ty)| {
1244 if let Some(parent) = parent_pred
1245 && suggested_bounds.contains(parent)
1246 {
1247 } else if !suggested_bounds.contains(pred)
1249 && collect_type_param_suggestions(self_ty, *pred, &p)
1250 {
1251 suggested = true;
1252 suggested_bounds.insert(pred);
1253 }
1254 (
1255 match parent_pred {
1256 None => format!("`{p}`"),
1257 Some(parent_pred) => match format_pred(*parent_pred) {
1258 None => format!("`{p}`"),
1259 Some((parent_p, _)) => {
1260 if !suggested
1261 && !suggested_bounds.contains(pred)
1262 && !suggested_bounds.contains(parent_pred)
1263 && collect_type_param_suggestions(
1264 self_ty,
1265 *parent_pred,
1266 &p,
1267 )
1268 {
1269 suggested_bounds.insert(pred);
1270 }
1271 format!("`{p}`\nwhich is required by `{parent_p}`")
1272 }
1273 },
1274 },
1275 *pred,
1276 )
1277 })
1278 })
1279 .filter(|(_, pred)| !skip_list.contains(&pred))
1280 .map(|(t, _)| t)
1281 .enumerate()
1282 .collect::<Vec<(usize, String)>>();
1283
1284 if !matches!(rcvr_ty.peel_refs().kind(), ty::Param(_)) {
1285 for ((span, add_where_or_comma), obligations) in type_params.into_iter() {
1286 restrict_type_params = true;
1287 let obligations = obligations.into_sorted_stable_ord();
1289 err.span_suggestion_verbose(
1290 span,
1291 format!(
1292 "consider restricting the type parameter{s} to satisfy the trait \
1293 bound{s}",
1294 s = pluralize!(obligations.len())
1295 ),
1296 format!("{} {}", add_where_or_comma, obligations.join(", ")),
1297 Applicability::MaybeIncorrect,
1298 );
1299 }
1300 }
1301
1302 bound_list.sort_by(|(_, a), (_, b)| a.cmp(b)); bound_list.dedup_by(|(_, a), (_, b)| a == b); bound_list.sort_by_key(|(pos, _)| *pos); if !bound_list.is_empty() || !skip_list.is_empty() {
1307 let bound_list =
1308 bound_list.into_iter().map(|(_, path)| path).collect::<Vec<_>>().join("\n");
1309 let actual_prefix = rcvr_ty.prefix_string(self.tcx);
1310 info!("unimplemented_traits.len() == {}", unimplemented_traits.len());
1311 let (primary_message, label, notes) = if unimplemented_traits.len() == 1
1312 && unimplemented_traits_only
1313 {
1314 unimplemented_traits
1315 .into_iter()
1316 .next()
1317 .map(|(_, (trait_ref, obligation))| {
1318 if trait_ref.self_ty().references_error() || rcvr_ty.references_error()
1319 {
1320 return (None, None, Vec::new());
1322 }
1323 let OnUnimplementedNote { message, label, notes, .. } = self
1324 .err_ctxt()
1325 .on_unimplemented_note(trait_ref, &obligation, &mut ty_file);
1326 (message, label, notes)
1327 })
1328 .unwrap()
1329 } else {
1330 (None, None, Vec::new())
1331 };
1332 let primary_message = primary_message.unwrap_or_else(|| {
1333 format!(
1334 "the {item_kind} `{item_name}` exists for {actual_prefix} `{ty_str}`, \
1335 but its trait bounds were not satisfied"
1336 )
1337 });
1338 err.primary_message(primary_message);
1339 if let Some(label) = label {
1340 custom_span_label = true;
1341 err.span_label(span, label);
1342 }
1343 if !bound_list.is_empty() {
1344 err.note(format!(
1345 "the following trait bounds were not satisfied:\n{bound_list}"
1346 ));
1347 }
1348 for note in notes {
1349 err.note(note);
1350 }
1351
1352 suggested_derive = self.suggest_derive(&mut err, unsatisfied_predicates);
1353
1354 unsatisfied_bounds = true;
1355 }
1356 } else if let ty::Adt(def, targs) = rcvr_ty.kind()
1357 && let SelfSource::MethodCall(rcvr_expr) = source
1358 {
1359 if targs.len() == 1 {
1363 let mut item_segment = hir::PathSegment::invalid();
1364 item_segment.ident = item_name;
1365 for t in [Ty::new_mut_ref, Ty::new_imm_ref, |_, _, t| t] {
1366 let new_args =
1367 tcx.mk_args_from_iter(targs.iter().map(|arg| match arg.as_type() {
1368 Some(ty) => ty::GenericArg::from(t(
1369 tcx,
1370 tcx.lifetimes.re_erased,
1371 ty.peel_refs(),
1372 )),
1373 _ => arg,
1374 }));
1375 let rcvr_ty = Ty::new_adt(tcx, *def, new_args);
1376 if let Ok(method) = self.lookup_method_for_diagnostic(
1377 rcvr_ty,
1378 &item_segment,
1379 span,
1380 tcx.parent_hir_node(rcvr_expr.hir_id).expect_expr(),
1381 rcvr_expr,
1382 ) {
1383 err.span_note(
1384 tcx.def_span(method.def_id),
1385 format!("{item_kind} is available for `{rcvr_ty}`"),
1386 );
1387 }
1388 }
1389 }
1390 }
1391
1392 let mut find_candidate_for_method = false;
1393
1394 let mut label_span_not_found = |err: &mut Diag<'_>| {
1395 if unsatisfied_predicates.is_empty() {
1396 err.span_label(span, format!("{item_kind} not found in `{ty_str}`"));
1397 let is_string_or_ref_str = match rcvr_ty.kind() {
1398 ty::Ref(_, ty, _) => {
1399 ty.is_str()
1400 || matches!(
1401 ty.kind(),
1402 ty::Adt(adt, _) if self.tcx.is_lang_item(adt.did(), LangItem::String)
1403 )
1404 }
1405 ty::Adt(adt, _) => self.tcx.is_lang_item(adt.did(), LangItem::String),
1406 _ => false,
1407 };
1408 if is_string_or_ref_str && item_name.name == sym::iter {
1409 err.span_suggestion_verbose(
1410 item_name.span,
1411 "because of the in-memory representation of `&str`, to obtain \
1412 an `Iterator` over each of its codepoint use method `chars`",
1413 "chars",
1414 Applicability::MachineApplicable,
1415 );
1416 }
1417 if let ty::Adt(adt, _) = rcvr_ty.kind() {
1418 let mut inherent_impls_candidate = self
1419 .tcx
1420 .inherent_impls(adt.did())
1421 .into_iter()
1422 .copied()
1423 .filter(|def_id| {
1424 if let Some(assoc) = self.associated_value(*def_id, item_name) {
1425 match (mode, assoc.fn_has_self_parameter, source) {
1428 (Mode::MethodCall, true, SelfSource::MethodCall(_)) => {
1429 self.tcx.at(span).type_of(*def_id).instantiate_identity()
1434 != rcvr_ty
1435 }
1436 (Mode::Path, false, _) => true,
1437 _ => false,
1438 }
1439 } else {
1440 false
1441 }
1442 })
1443 .collect::<Vec<_>>();
1444 if !inherent_impls_candidate.is_empty() {
1445 inherent_impls_candidate.sort_by_key(|id| self.tcx.def_path_str(id));
1446 inherent_impls_candidate.dedup();
1447
1448 let limit = if inherent_impls_candidate.len() == 5 { 5 } else { 4 };
1450 let type_candidates = inherent_impls_candidate
1451 .iter()
1452 .take(limit)
1453 .map(|impl_item| {
1454 format!(
1455 "- `{}`",
1456 self.tcx.at(span).type_of(*impl_item).instantiate_identity()
1457 )
1458 })
1459 .collect::<Vec<_>>()
1460 .join("\n");
1461 let additional_types = if inherent_impls_candidate.len() > limit {
1462 format!("\nand {} more types", inherent_impls_candidate.len() - limit)
1463 } else {
1464 "".to_string()
1465 };
1466 err.note(format!(
1467 "the {item_kind} was found for\n{type_candidates}{additional_types}"
1468 ));
1469 find_candidate_for_method = mode == Mode::MethodCall;
1470 }
1471 }
1472 } else {
1473 let ty_str =
1474 if ty_str.len() > 50 { String::new() } else { format!("on `{ty_str}` ") };
1475 err.span_label(
1476 span,
1477 format!("{item_kind} cannot be called {ty_str}due to unsatisfied trait bounds"),
1478 );
1479 }
1480 };
1481
1482 if let SelfSource::MethodCall(expr) = source {
1485 if !self.suggest_calling_field_as_fn(span, rcvr_ty, expr, item_name, &mut err)
1486 && similar_candidate.is_none()
1487 && !custom_span_label
1488 {
1489 label_span_not_found(&mut err);
1490 }
1491 } else if !custom_span_label {
1492 label_span_not_found(&mut err);
1493 }
1494
1495 let confusable_suggested = self.confusable_method_name(
1496 &mut err,
1497 rcvr_ty,
1498 item_name,
1499 args.map(|args| {
1500 args.iter()
1501 .map(|expr| {
1502 self.node_ty_opt(expr.hir_id).unwrap_or_else(|| self.next_ty_var(expr.span))
1503 })
1504 .collect()
1505 }),
1506 );
1507
1508 if unsatisfied_predicates.is_empty() {
1511 self.suggest_calling_method_on_field(
1512 &mut err,
1513 source,
1514 span,
1515 rcvr_ty,
1516 item_name,
1517 expected.only_has_type(self),
1518 );
1519 }
1520
1521 self.suggest_unwrapping_inner_self(&mut err, source, rcvr_ty, item_name);
1522
1523 for (span, mut bounds) in bound_spans {
1524 if !tcx.sess.source_map().is_span_accessible(span) {
1525 continue;
1526 }
1527 bounds.sort();
1528 bounds.dedup();
1529 let pre = if Some(span) == ty_span {
1530 ty_span.take();
1531 format!(
1532 "{item_kind} `{item_name}` not found for this {} because it ",
1533 rcvr_ty.prefix_string(self.tcx)
1534 )
1535 } else {
1536 String::new()
1537 };
1538 let msg = match &bounds[..] {
1539 [bound] => format!("{pre}doesn't satisfy {bound}"),
1540 bounds if bounds.len() > 4 => format!("doesn't satisfy {} bounds", bounds.len()),
1541 [bounds @ .., last] => {
1542 format!("{pre}doesn't satisfy {} or {last}", bounds.join(", "))
1543 }
1544 [] => unreachable!(),
1545 };
1546 err.span_label(span, msg);
1547 }
1548 if let Some(span) = ty_span {
1549 err.span_label(
1550 span,
1551 format!(
1552 "{item_kind} `{item_name}` not found for this {}",
1553 rcvr_ty.prefix_string(self.tcx)
1554 ),
1555 );
1556 }
1557
1558 if rcvr_ty.is_numeric() && rcvr_ty.is_fresh() || restrict_type_params || suggested_derive {
1559 } else {
1560 self.suggest_traits_to_import(
1561 &mut err,
1562 span,
1563 rcvr_ty,
1564 item_name,
1565 args.map(|args| args.len() + 1),
1566 source,
1567 no_match_data.out_of_scope_traits.clone(),
1568 static_candidates,
1569 unsatisfied_bounds,
1570 expected.only_has_type(self),
1571 trait_missing_method,
1572 );
1573 }
1574
1575 if unsatisfied_predicates.is_empty() && rcvr_ty.is_enum() {
1578 let adt_def = rcvr_ty.ty_adt_def().expect("enum is not an ADT");
1579 if let Some(var_name) = edit_distance::find_best_match_for_name(
1580 &adt_def.variants().iter().map(|s| s.name).collect::<Vec<_>>(),
1581 item_name.name,
1582 None,
1583 ) && let Some(variant) = adt_def.variants().iter().find(|s| s.name == var_name)
1584 {
1585 let mut suggestion = vec![(span, var_name.to_string())];
1586 if let SelfSource::QPath(ty) = source
1587 && let hir::Node::Expr(ref path_expr) = self.tcx.parent_hir_node(ty.hir_id)
1588 && let hir::ExprKind::Path(_) = path_expr.kind
1589 && let hir::Node::Stmt(hir::Stmt {
1590 kind: hir::StmtKind::Semi(ref parent), ..
1591 })
1592 | hir::Node::Expr(ref parent) = self.tcx.parent_hir_node(path_expr.hir_id)
1593 {
1594 let replacement_span =
1595 if let hir::ExprKind::Call(..) | hir::ExprKind::Struct(..) = parent.kind {
1596 span.with_hi(parent.span.hi())
1598 } else {
1599 span
1600 };
1601 match (variant.ctor, parent.kind) {
1602 (None, hir::ExprKind::Struct(..)) => {
1603 suggestion = vec![(span, var_name.to_string())];
1606 }
1607 (None, _) => {
1608 suggestion = vec![(
1610 replacement_span,
1611 if variant.fields.is_empty() {
1612 format!("{var_name} {{}}")
1613 } else {
1614 format!(
1615 "{var_name} {{ {} }}",
1616 variant
1617 .fields
1618 .iter()
1619 .map(|f| format!("{}: /* value */", f.name))
1620 .collect::<Vec<_>>()
1621 .join(", ")
1622 )
1623 },
1624 )];
1625 }
1626 (Some((hir::def::CtorKind::Const, _)), _) => {
1627 suggestion = vec![(replacement_span, var_name.to_string())];
1629 }
1630 (
1631 Some((hir::def::CtorKind::Fn, def_id)),
1632 hir::ExprKind::Call(rcvr, args),
1633 ) => {
1634 let fn_sig = self.tcx.fn_sig(def_id).instantiate_identity();
1635 let inputs = fn_sig.inputs().skip_binder();
1636 match (inputs, args) {
1639 (inputs, []) => {
1640 suggestion.push((
1642 rcvr.span.shrink_to_hi().with_hi(parent.span.hi()),
1643 format!(
1644 "({})",
1645 inputs
1646 .iter()
1647 .map(|i| format!("/* {i} */"))
1648 .collect::<Vec<String>>()
1649 .join(", ")
1650 ),
1651 ));
1652 }
1653 (_, [arg]) if inputs.len() != args.len() => {
1654 suggestion.push((
1656 arg.span,
1657 inputs
1658 .iter()
1659 .map(|i| format!("/* {i} */"))
1660 .collect::<Vec<String>>()
1661 .join(", "),
1662 ));
1663 }
1664 (_, [arg_start, .., arg_end]) if inputs.len() != args.len() => {
1665 suggestion.push((
1667 arg_start.span.to(arg_end.span),
1668 inputs
1669 .iter()
1670 .map(|i| format!("/* {i} */"))
1671 .collect::<Vec<String>>()
1672 .join(", "),
1673 ));
1674 }
1675 _ => {}
1677 }
1678 }
1679 (Some((hir::def::CtorKind::Fn, def_id)), _) => {
1680 let fn_sig = self.tcx.fn_sig(def_id).instantiate_identity();
1681 let inputs = fn_sig.inputs().skip_binder();
1682 suggestion = vec![(
1683 replacement_span,
1684 format!(
1685 "{var_name}({})",
1686 inputs
1687 .iter()
1688 .map(|i| format!("/* {i} */"))
1689 .collect::<Vec<String>>()
1690 .join(", ")
1691 ),
1692 )];
1693 }
1694 }
1695 }
1696 err.multipart_suggestion_verbose(
1697 "there is a variant with a similar name",
1698 suggestion,
1699 Applicability::HasPlaceholders,
1700 );
1701 }
1702 }
1703
1704 if let Some(similar_candidate) = similar_candidate {
1705 if unsatisfied_predicates.is_empty()
1708 && Some(similar_candidate.name) != confusable_suggested
1710 {
1711 self.find_likely_intended_associated_item(
1712 &mut err,
1713 similar_candidate,
1714 span,
1715 args,
1716 mode,
1717 );
1718 }
1719 }
1720
1721 if !find_candidate_for_method {
1722 self.lookup_segments_chain_for_no_match_method(
1723 &mut err,
1724 item_name,
1725 item_kind,
1726 source,
1727 no_match_data,
1728 );
1729 }
1730
1731 self.note_derefed_ty_has_method(&mut err, source, rcvr_ty, item_name, expected);
1732 err.emit()
1733 }
1734
1735 fn lookup_segments_chain_for_no_match_method(
1737 &self,
1738 err: &mut Diag<'_>,
1739 item_name: Ident,
1740 item_kind: &str,
1741 source: SelfSource<'tcx>,
1742 no_match_data: &NoMatchData<'tcx>,
1743 ) {
1744 if no_match_data.unsatisfied_predicates.is_empty()
1745 && let Mode::MethodCall = no_match_data.mode
1746 && let SelfSource::MethodCall(mut source_expr) = source
1747 {
1748 let mut stack_methods = vec![];
1749 while let hir::ExprKind::MethodCall(_path_segment, rcvr_expr, _args, method_span) =
1750 source_expr.kind
1751 {
1752 if let Some(prev_match) = stack_methods.pop() {
1754 err.span_label(
1755 method_span,
1756 format!("{item_kind} `{item_name}` is available on `{prev_match}`"),
1757 );
1758 }
1759 let rcvr_ty = self.resolve_vars_if_possible(
1760 self.typeck_results
1761 .borrow()
1762 .expr_ty_adjusted_opt(rcvr_expr)
1763 .unwrap_or(Ty::new_misc_error(self.tcx)),
1764 );
1765
1766 let Ok(candidates) = self.probe_for_name_many(
1767 Mode::MethodCall,
1768 item_name,
1769 None,
1770 IsSuggestion(true),
1771 rcvr_ty,
1772 source_expr.hir_id,
1773 ProbeScope::TraitsInScope,
1774 ) else {
1775 return;
1776 };
1777
1778 for _matched_method in candidates {
1782 stack_methods.push(rcvr_ty);
1784 }
1785 source_expr = rcvr_expr;
1786 }
1787 if let Some(prev_match) = stack_methods.pop() {
1789 err.span_label(
1790 source_expr.span,
1791 format!("{item_kind} `{item_name}` is available on `{prev_match}`"),
1792 );
1793 }
1794 }
1795 }
1796
1797 fn find_likely_intended_associated_item(
1798 &self,
1799 err: &mut Diag<'_>,
1800 similar_candidate: ty::AssocItem,
1801 span: Span,
1802 args: Option<&'tcx [hir::Expr<'tcx>]>,
1803 mode: Mode,
1804 ) {
1805 let tcx = self.tcx;
1806 let def_kind = similar_candidate.kind.as_def_kind();
1807 let an = self.tcx.def_kind_descr_article(def_kind, similar_candidate.def_id);
1808 let msg = format!(
1809 "there is {an} {} `{}` with a similar name",
1810 self.tcx.def_kind_descr(def_kind, similar_candidate.def_id),
1811 similar_candidate.name,
1812 );
1813 if def_kind == DefKind::AssocFn {
1818 let ty_args = self.infcx.fresh_args_for_item(span, similar_candidate.def_id);
1819 let fn_sig = tcx.fn_sig(similar_candidate.def_id).instantiate(tcx, ty_args);
1820 let fn_sig = self.instantiate_binder_with_fresh_vars(span, infer::FnCall, fn_sig);
1821 if similar_candidate.fn_has_self_parameter {
1822 if let Some(args) = args
1823 && fn_sig.inputs()[1..].len() == args.len()
1824 {
1825 err.span_suggestion_verbose(
1828 span,
1829 msg,
1830 similar_candidate.name,
1831 Applicability::MaybeIncorrect,
1832 );
1833 } else {
1834 err.span_help(
1837 tcx.def_span(similar_candidate.def_id),
1838 format!(
1839 "{msg}{}",
1840 if let None = args { "" } else { ", but with different arguments" },
1841 ),
1842 );
1843 }
1844 } else if let Some(args) = args
1845 && fn_sig.inputs().len() == args.len()
1846 {
1847 err.span_suggestion_verbose(
1850 span,
1851 msg,
1852 similar_candidate.name,
1853 Applicability::MaybeIncorrect,
1854 );
1855 } else {
1856 err.span_help(tcx.def_span(similar_candidate.def_id), msg);
1857 }
1858 } else if let Mode::Path = mode
1859 && args.unwrap_or(&[]).is_empty()
1860 {
1861 err.span_suggestion_verbose(
1863 span,
1864 msg,
1865 similar_candidate.name,
1866 Applicability::MaybeIncorrect,
1867 );
1868 } else {
1869 err.span_help(tcx.def_span(similar_candidate.def_id), msg);
1872 }
1873 }
1874
1875 pub(crate) fn confusable_method_name(
1876 &self,
1877 err: &mut Diag<'_>,
1878 rcvr_ty: Ty<'tcx>,
1879 item_name: Ident,
1880 call_args: Option<Vec<Ty<'tcx>>>,
1881 ) -> Option<Symbol> {
1882 if let ty::Adt(adt, adt_args) = rcvr_ty.kind() {
1883 for inherent_impl_did in self.tcx.inherent_impls(adt.did()).into_iter() {
1884 for inherent_method in
1885 self.tcx.associated_items(inherent_impl_did).in_definition_order()
1886 {
1887 if let Some(attr) =
1888 self.tcx.get_attr(inherent_method.def_id, sym::rustc_confusables)
1889 && let Some(candidates) = parse_confusables(attr)
1890 && candidates.contains(&item_name.name)
1891 && let ty::AssocKind::Fn = inherent_method.kind
1892 {
1893 let args =
1894 ty::GenericArgs::identity_for_item(self.tcx, inherent_method.def_id)
1895 .rebase_onto(
1896 self.tcx,
1897 inherent_method.container_id(self.tcx),
1898 adt_args,
1899 );
1900 let fn_sig =
1901 self.tcx.fn_sig(inherent_method.def_id).instantiate(self.tcx, args);
1902 let fn_sig = self.instantiate_binder_with_fresh_vars(
1903 item_name.span,
1904 infer::FnCall,
1905 fn_sig,
1906 );
1907 if let Some(ref args) = call_args
1908 && fn_sig.inputs()[1..]
1909 .iter()
1910 .zip(args.into_iter())
1911 .all(|(expected, found)| self.may_coerce(*expected, *found))
1912 && fn_sig.inputs()[1..].len() == args.len()
1913 {
1914 err.span_suggestion_verbose(
1915 item_name.span,
1916 format!("you might have meant to use `{}`", inherent_method.name),
1917 inherent_method.name,
1918 Applicability::MaybeIncorrect,
1919 );
1920 return Some(inherent_method.name);
1921 } else if let None = call_args {
1922 err.span_note(
1923 self.tcx.def_span(inherent_method.def_id),
1924 format!(
1925 "you might have meant to use method `{}`",
1926 inherent_method.name,
1927 ),
1928 );
1929 return Some(inherent_method.name);
1930 }
1931 }
1932 }
1933 }
1934 }
1935 None
1936 }
1937 fn note_candidates_on_method_error(
1938 &self,
1939 rcvr_ty: Ty<'tcx>,
1940 item_name: Ident,
1941 self_source: SelfSource<'tcx>,
1942 args: Option<&'tcx [hir::Expr<'tcx>]>,
1943 span: Span,
1944 err: &mut Diag<'_>,
1945 sources: &mut Vec<CandidateSource>,
1946 sugg_span: Option<Span>,
1947 ) {
1948 sources.sort_by_key(|source| match source {
1949 CandidateSource::Trait(id) => (0, self.tcx.def_path_str(id)),
1950 CandidateSource::Impl(id) => (1, self.tcx.def_path_str(id)),
1951 });
1952 sources.dedup();
1953 let limit = if sources.len() == 5 { 5 } else { 4 };
1955
1956 let mut suggs = vec![];
1957 for (idx, source) in sources.iter().take(limit).enumerate() {
1958 match *source {
1959 CandidateSource::Impl(impl_did) => {
1960 let Some(item) = self.associated_value(impl_did, item_name).or_else(|| {
1963 let impl_trait_ref = self.tcx.impl_trait_ref(impl_did)?;
1964 self.associated_value(impl_trait_ref.skip_binder().def_id, item_name)
1965 }) else {
1966 continue;
1967 };
1968
1969 let note_span = if item.def_id.is_local() {
1970 Some(self.tcx.def_span(item.def_id))
1971 } else if impl_did.is_local() {
1972 Some(self.tcx.def_span(impl_did))
1973 } else {
1974 None
1975 };
1976
1977 let impl_ty = self.tcx.at(span).type_of(impl_did).instantiate_identity();
1978
1979 let insertion = match self.tcx.impl_trait_ref(impl_did) {
1980 None => String::new(),
1981 Some(trait_ref) => {
1982 format!(
1983 " of the trait `{}`",
1984 self.tcx.def_path_str(trait_ref.skip_binder().def_id)
1985 )
1986 }
1987 };
1988
1989 let (note_str, idx) = if sources.len() > 1 {
1990 (
1991 format!(
1992 "candidate #{} is defined in an impl{} for the type `{}`",
1993 idx + 1,
1994 insertion,
1995 impl_ty,
1996 ),
1997 Some(idx + 1),
1998 )
1999 } else {
2000 (
2001 format!(
2002 "the candidate is defined in an impl{insertion} for the type `{impl_ty}`",
2003 ),
2004 None,
2005 )
2006 };
2007 if let Some(note_span) = note_span {
2008 err.span_note(note_span, note_str);
2010 } else {
2011 err.note(note_str);
2012 }
2013 if let Some(sugg_span) = sugg_span
2014 && let Some(trait_ref) = self.tcx.impl_trait_ref(impl_did)
2015 && let Some(sugg) = print_disambiguation_help(
2016 self.tcx,
2017 err,
2018 self_source,
2019 args,
2020 trait_ref
2021 .instantiate(
2022 self.tcx,
2023 self.fresh_args_for_item(sugg_span, impl_did),
2024 )
2025 .with_self_ty(self.tcx, rcvr_ty),
2026 idx,
2027 sugg_span,
2028 item,
2029 )
2030 {
2031 suggs.push(sugg);
2032 }
2033 }
2034 CandidateSource::Trait(trait_did) => {
2035 let Some(item) = self.associated_value(trait_did, item_name) else { continue };
2036 let item_span = self.tcx.def_span(item.def_id);
2037 let idx = if sources.len() > 1 {
2038 let msg = format!(
2039 "candidate #{} is defined in the trait `{}`",
2040 idx + 1,
2041 self.tcx.def_path_str(trait_did)
2042 );
2043 err.span_note(item_span, msg);
2044 Some(idx + 1)
2045 } else {
2046 let msg = format!(
2047 "the candidate is defined in the trait `{}`",
2048 self.tcx.def_path_str(trait_did)
2049 );
2050 err.span_note(item_span, msg);
2051 None
2052 };
2053 if let Some(sugg_span) = sugg_span
2054 && let Some(sugg) = print_disambiguation_help(
2055 self.tcx,
2056 err,
2057 self_source,
2058 args,
2059 ty::TraitRef::new_from_args(
2060 self.tcx,
2061 trait_did,
2062 self.fresh_args_for_item(sugg_span, trait_did),
2063 )
2064 .with_self_ty(self.tcx, rcvr_ty),
2065 idx,
2066 sugg_span,
2067 item,
2068 )
2069 {
2070 suggs.push(sugg);
2071 }
2072 }
2073 }
2074 }
2075 if !suggs.is_empty()
2076 && let Some(span) = sugg_span
2077 {
2078 suggs.sort();
2079 err.span_suggestions(
2080 span.with_hi(item_name.span.lo()),
2081 "use fully-qualified syntax to disambiguate",
2082 suggs,
2083 Applicability::MachineApplicable,
2084 );
2085 }
2086 if sources.len() > limit {
2087 err.note(format!("and {} others", sources.len() - limit));
2088 }
2089 }
2090
2091 fn find_builder_fn(&self, err: &mut Diag<'_>, rcvr_ty: Ty<'tcx>, expr_id: hir::HirId) {
2094 let ty::Adt(adt_def, _) = rcvr_ty.kind() else {
2095 return;
2096 };
2097 let mut items = self
2098 .tcx
2099 .inherent_impls(adt_def.did())
2100 .iter()
2101 .flat_map(|i| self.tcx.associated_items(i).in_definition_order())
2102 .filter(|item| {
2105 matches!(item.kind, ty::AssocKind::Fn)
2106 && !item.fn_has_self_parameter
2107 && self
2108 .probe_for_name(
2109 Mode::Path,
2110 item.ident(self.tcx),
2111 None,
2112 IsSuggestion(true),
2113 rcvr_ty,
2114 expr_id,
2115 ProbeScope::TraitsInScope,
2116 )
2117 .is_ok()
2118 })
2119 .filter_map(|item| {
2120 let ret_ty = self
2122 .tcx
2123 .fn_sig(item.def_id)
2124 .instantiate(self.tcx, self.fresh_args_for_item(DUMMY_SP, item.def_id))
2125 .output();
2126 let ret_ty = self.tcx.instantiate_bound_regions_with_erased(ret_ty);
2127 let ty::Adt(def, args) = ret_ty.kind() else {
2128 return None;
2129 };
2130 if self.can_eq(self.param_env, ret_ty, rcvr_ty) {
2132 return Some((item.def_id, ret_ty));
2133 }
2134 if ![self.tcx.lang_items().option_type(), self.tcx.get_diagnostic_item(sym::Result)]
2136 .contains(&Some(def.did()))
2137 {
2138 return None;
2139 }
2140 let arg = args.get(0)?.expect_ty();
2141 if self.can_eq(self.param_env, rcvr_ty, arg) {
2142 Some((item.def_id, ret_ty))
2143 } else {
2144 None
2145 }
2146 })
2147 .collect::<Vec<_>>();
2148 let post = if items.len() > 5 {
2149 let items_len = items.len();
2150 items.truncate(4);
2151 format!("\nand {} others", items_len - 4)
2152 } else {
2153 String::new()
2154 };
2155 match &items[..] {
2156 [] => {}
2157 [(def_id, ret_ty)] => {
2158 err.span_note(
2159 self.tcx.def_span(def_id),
2160 format!(
2161 "if you're trying to build a new `{rcvr_ty}`, consider using `{}` which \
2162 returns `{ret_ty}`",
2163 self.tcx.def_path_str(def_id),
2164 ),
2165 );
2166 }
2167 _ => {
2168 let span: MultiSpan = items
2169 .iter()
2170 .map(|(def_id, _)| self.tcx.def_span(def_id))
2171 .collect::<Vec<Span>>()
2172 .into();
2173 err.span_note(
2174 span,
2175 format!(
2176 "if you're trying to build a new `{rcvr_ty}` consider using one of the \
2177 following associated functions:\n{}{post}",
2178 items
2179 .iter()
2180 .map(|(def_id, _ret_ty)| self.tcx.def_path_str(def_id))
2181 .collect::<Vec<String>>()
2182 .join("\n")
2183 ),
2184 );
2185 }
2186 }
2187 }
2188
2189 fn suggest_associated_call_syntax(
2192 &self,
2193 err: &mut Diag<'_>,
2194 static_candidates: &Vec<CandidateSource>,
2195 rcvr_ty: Ty<'tcx>,
2196 source: SelfSource<'tcx>,
2197 item_name: Ident,
2198 args: Option<&'tcx [hir::Expr<'tcx>]>,
2199 sugg_span: Span,
2200 ) {
2201 let mut has_unsuggestable_args = false;
2202 let ty_str = if let Some(CandidateSource::Impl(impl_did)) = static_candidates.get(0) {
2203 let impl_ty = self.tcx.type_of(*impl_did).instantiate_identity();
2207 let target_ty = self
2208 .autoderef(sugg_span, rcvr_ty)
2209 .silence_errors()
2210 .find(|(rcvr_ty, _)| {
2211 DeepRejectCtxt::relate_rigid_infer(self.tcx).types_may_unify(*rcvr_ty, impl_ty)
2212 })
2213 .map_or(impl_ty, |(ty, _)| ty)
2214 .peel_refs();
2215 if let ty::Adt(def, args) = target_ty.kind() {
2216 let infer_args = self.tcx.mk_args_from_iter(args.into_iter().map(|arg| {
2219 if !arg.is_suggestable(self.tcx, true) {
2220 has_unsuggestable_args = true;
2221 match arg.unpack() {
2222 GenericArgKind::Lifetime(_) => self
2223 .next_region_var(RegionVariableOrigin::MiscVariable(DUMMY_SP))
2224 .into(),
2225 GenericArgKind::Type(_) => self.next_ty_var(DUMMY_SP).into(),
2226 GenericArgKind::Const(_) => self.next_const_var(DUMMY_SP).into(),
2227 }
2228 } else {
2229 arg
2230 }
2231 }));
2232
2233 self.tcx.value_path_str_with_args(def.did(), infer_args)
2234 } else {
2235 self.ty_to_value_string(target_ty)
2236 }
2237 } else {
2238 self.ty_to_value_string(rcvr_ty.peel_refs())
2239 };
2240 if let SelfSource::MethodCall(_) = source {
2241 let first_arg = static_candidates.get(0).and_then(|candidate_source| {
2242 let (assoc_did, self_ty) = match candidate_source {
2243 CandidateSource::Impl(impl_did) => {
2244 (*impl_did, self.tcx.type_of(*impl_did).instantiate_identity())
2245 }
2246 CandidateSource::Trait(trait_did) => (*trait_did, rcvr_ty),
2247 };
2248
2249 let assoc = self.associated_value(assoc_did, item_name)?;
2250 if assoc.kind != ty::AssocKind::Fn {
2251 return None;
2252 }
2253
2254 let sig = self.tcx.fn_sig(assoc.def_id).instantiate_identity();
2257 sig.inputs().skip_binder().get(0).and_then(|first| {
2258 let first_ty = first.peel_refs();
2260 if first_ty == self_ty || first_ty == self.tcx.types.self_param {
2261 Some(first.ref_mutability().map_or("", |mutbl| mutbl.ref_prefix_str()))
2262 } else {
2263 None
2264 }
2265 })
2266 });
2267
2268 let mut applicability = Applicability::MachineApplicable;
2269 let args = if let SelfSource::MethodCall(receiver) = source
2270 && let Some(args) = args
2271 {
2272 let explicit_args = if first_arg.is_some() {
2274 std::iter::once(receiver).chain(args.iter()).collect::<Vec<_>>()
2275 } else {
2276 if has_unsuggestable_args {
2278 applicability = Applicability::HasPlaceholders;
2279 }
2280 args.iter().collect()
2281 };
2282 format!(
2283 "({}{})",
2284 first_arg.unwrap_or(""),
2285 explicit_args
2286 .iter()
2287 .map(|arg| self
2288 .tcx
2289 .sess
2290 .source_map()
2291 .span_to_snippet(arg.span)
2292 .unwrap_or_else(|_| {
2293 applicability = Applicability::HasPlaceholders;
2294 "_".to_owned()
2295 }))
2296 .collect::<Vec<_>>()
2297 .join(", "),
2298 )
2299 } else {
2300 applicability = Applicability::HasPlaceholders;
2301 "(...)".to_owned()
2302 };
2303 err.span_suggestion(
2304 sugg_span,
2305 "use associated function syntax instead",
2306 format!("{ty_str}::{item_name}{args}"),
2307 applicability,
2308 );
2309 } else {
2310 err.help(format!("try with `{ty_str}::{item_name}`",));
2311 }
2312 }
2313
2314 fn suggest_calling_field_as_fn(
2317 &self,
2318 span: Span,
2319 rcvr_ty: Ty<'tcx>,
2320 expr: &hir::Expr<'_>,
2321 item_name: Ident,
2322 err: &mut Diag<'_>,
2323 ) -> bool {
2324 let tcx = self.tcx;
2325 let field_receiver =
2326 self.autoderef(span, rcvr_ty).silence_errors().find_map(|(ty, _)| match ty.kind() {
2327 ty::Adt(def, args) if !def.is_enum() => {
2328 let variant = &def.non_enum_variant();
2329 tcx.find_field_index(item_name, variant).map(|index| {
2330 let field = &variant.fields[index];
2331 let field_ty = field.ty(tcx, args);
2332 (field, field_ty)
2333 })
2334 }
2335 _ => None,
2336 });
2337 if let Some((field, field_ty)) = field_receiver {
2338 let scope = tcx.parent_module_from_def_id(self.body_id);
2339 let is_accessible = field.vis.is_accessible_from(scope, tcx);
2340
2341 if is_accessible {
2342 if let Some((what, _, _)) = self.extract_callable_info(field_ty) {
2343 let what = match what {
2344 DefIdOrName::DefId(def_id) => self.tcx.def_descr(def_id),
2345 DefIdOrName::Name(what) => what,
2346 };
2347 let expr_span = expr.span.to(item_name.span);
2348 err.multipart_suggestion(
2349 format!(
2350 "to call the {what} stored in `{item_name}`, \
2351 surround the field access with parentheses",
2352 ),
2353 vec![
2354 (expr_span.shrink_to_lo(), '('.to_string()),
2355 (expr_span.shrink_to_hi(), ')'.to_string()),
2356 ],
2357 Applicability::MachineApplicable,
2358 );
2359 } else {
2360 let call_expr = tcx.hir().expect_expr(tcx.parent_hir_id(expr.hir_id));
2361
2362 if let Some(span) = call_expr.span.trim_start(item_name.span) {
2363 err.span_suggestion(
2364 span,
2365 "remove the arguments",
2366 "",
2367 Applicability::MaybeIncorrect,
2368 );
2369 }
2370 }
2371 }
2372
2373 let field_kind = if is_accessible { "field" } else { "private field" };
2374 err.span_label(item_name.span, format!("{field_kind}, not a method"));
2375 return true;
2376 }
2377 false
2378 }
2379
2380 fn report_failed_method_call_on_range_end(
2383 &self,
2384 tcx: TyCtxt<'tcx>,
2385 actual: Ty<'tcx>,
2386 source: SelfSource<'tcx>,
2387 span: Span,
2388 item_name: Ident,
2389 ty_str: &str,
2390 long_ty_path: &mut Option<PathBuf>,
2391 ) -> Result<(), ErrorGuaranteed> {
2392 if let SelfSource::MethodCall(expr) = source {
2393 for (_, parent) in tcx.hir().parent_iter(expr.hir_id).take(5) {
2394 if let Node::Expr(parent_expr) = parent {
2395 let lang_item = match parent_expr.kind {
2396 ExprKind::Struct(qpath, _, _) => match *qpath {
2397 QPath::LangItem(LangItem::Range, ..) => Some(LangItem::Range),
2398 QPath::LangItem(LangItem::RangeCopy, ..) => Some(LangItem::RangeCopy),
2399 QPath::LangItem(LangItem::RangeInclusiveCopy, ..) => {
2400 Some(LangItem::RangeInclusiveCopy)
2401 }
2402 QPath::LangItem(LangItem::RangeTo, ..) => Some(LangItem::RangeTo),
2403 QPath::LangItem(LangItem::RangeToInclusive, ..) => {
2404 Some(LangItem::RangeToInclusive)
2405 }
2406 _ => None,
2407 },
2408 ExprKind::Call(func, _) => match func.kind {
2409 ExprKind::Path(QPath::LangItem(LangItem::RangeInclusiveNew, ..)) => {
2411 Some(LangItem::RangeInclusiveStruct)
2412 }
2413 _ => None,
2414 },
2415 _ => None,
2416 };
2417
2418 if lang_item.is_none() {
2419 continue;
2420 }
2421
2422 let span_included = match parent_expr.kind {
2423 hir::ExprKind::Struct(_, eps, _) => {
2424 eps.len() > 0 && eps.last().is_some_and(|ep| ep.span.contains(span))
2425 }
2426 hir::ExprKind::Call(func, ..) => func.span.contains(span),
2428 _ => false,
2429 };
2430
2431 if !span_included {
2432 continue;
2433 }
2434
2435 let Some(range_def_id) =
2436 lang_item.and_then(|lang_item| self.tcx.lang_items().get(lang_item))
2437 else {
2438 continue;
2439 };
2440 let range_ty =
2441 self.tcx.type_of(range_def_id).instantiate(self.tcx, &[actual.into()]);
2442
2443 let pick = self.lookup_probe_for_diagnostic(
2444 item_name,
2445 range_ty,
2446 expr,
2447 ProbeScope::AllTraits,
2448 None,
2449 );
2450 if pick.is_ok() {
2451 let range_span = parent_expr.span.with_hi(expr.span.hi());
2452 let mut err = self.dcx().create_err(errors::MissingParenthesesInRange {
2453 span,
2454 ty_str: ty_str.to_string(),
2455 method_name: item_name.as_str().to_string(),
2456 add_missing_parentheses: Some(errors::AddMissingParenthesesInRange {
2457 func_name: item_name.name.as_str().to_string(),
2458 left: range_span.shrink_to_lo(),
2459 right: range_span.shrink_to_hi(),
2460 }),
2461 });
2462 *err.long_ty_path() = long_ty_path.take();
2463 return Err(err.emit());
2464 }
2465 }
2466 }
2467 }
2468 Ok(())
2469 }
2470
2471 fn report_failed_method_call_on_numerical_infer_var(
2472 &self,
2473 tcx: TyCtxt<'tcx>,
2474 actual: Ty<'tcx>,
2475 source: SelfSource<'_>,
2476 span: Span,
2477 item_kind: &str,
2478 item_name: Ident,
2479 ty_str: &str,
2480 long_ty_path: &mut Option<PathBuf>,
2481 ) -> Result<(), ErrorGuaranteed> {
2482 let found_candidate = all_traits(self.tcx)
2483 .into_iter()
2484 .any(|info| self.associated_value(info.def_id, item_name).is_some());
2485 let found_assoc = |ty: Ty<'tcx>| {
2486 simplify_type(tcx, ty, TreatParams::InstantiateWithInfer)
2487 .and_then(|simp| {
2488 tcx.incoherent_impls(simp)
2489 .into_iter()
2490 .find_map(|&id| self.associated_value(id, item_name))
2491 })
2492 .is_some()
2493 };
2494 let found_candidate = found_candidate
2495 || found_assoc(tcx.types.i8)
2496 || found_assoc(tcx.types.i16)
2497 || found_assoc(tcx.types.i32)
2498 || found_assoc(tcx.types.i64)
2499 || found_assoc(tcx.types.i128)
2500 || found_assoc(tcx.types.u8)
2501 || found_assoc(tcx.types.u16)
2502 || found_assoc(tcx.types.u32)
2503 || found_assoc(tcx.types.u64)
2504 || found_assoc(tcx.types.u128)
2505 || found_assoc(tcx.types.f32)
2506 || found_assoc(tcx.types.f64);
2507 if found_candidate
2508 && actual.is_numeric()
2509 && !actual.has_concrete_skeleton()
2510 && let SelfSource::MethodCall(expr) = source
2511 {
2512 let mut err = struct_span_code_err!(
2513 self.dcx(),
2514 span,
2515 E0689,
2516 "can't call {} `{}` on ambiguous numeric type `{}`",
2517 item_kind,
2518 item_name,
2519 ty_str
2520 );
2521 *err.long_ty_path() = long_ty_path.take();
2522 let concrete_type = if actual.is_integral() { "i32" } else { "f32" };
2523 match expr.kind {
2524 ExprKind::Lit(lit) => {
2525 let snippet = tcx
2527 .sess
2528 .source_map()
2529 .span_to_snippet(lit.span)
2530 .unwrap_or_else(|_| "<numeric literal>".to_owned());
2531
2532 let snippet = snippet.strip_suffix('.').unwrap_or(&snippet);
2535 err.span_suggestion(
2536 lit.span,
2537 format!(
2538 "you must specify a concrete type for this numeric value, \
2539 like `{concrete_type}`"
2540 ),
2541 format!("{snippet}_{concrete_type}"),
2542 Applicability::MaybeIncorrect,
2543 );
2544 }
2545 ExprKind::Path(QPath::Resolved(_, path)) => {
2546 if let hir::def::Res::Local(hir_id) = path.res {
2548 let span = tcx.hir().span(hir_id);
2549 let filename = tcx.sess.source_map().span_to_filename(span);
2550
2551 let parent_node = self.tcx.parent_hir_node(hir_id);
2552 let msg = format!(
2553 "you must specify a type for this binding, like `{concrete_type}`",
2554 );
2555
2556 match (filename, parent_node) {
2557 (
2558 FileName::Real(_),
2559 Node::LetStmt(hir::LetStmt {
2560 source: hir::LocalSource::Normal,
2561 ty,
2562 ..
2563 }),
2564 ) => {
2565 let type_span = ty
2566 .map(|ty| ty.span.with_lo(span.hi()))
2567 .unwrap_or(span.shrink_to_hi());
2568 err.span_suggestion(
2569 type_span,
2572 msg,
2573 format!(": {concrete_type}"),
2574 Applicability::MaybeIncorrect,
2575 );
2576 }
2577 _ => {
2578 err.span_label(span, msg);
2579 }
2580 }
2581 }
2582 }
2583 _ => {}
2584 }
2585 return Err(err.emit());
2586 }
2587 Ok(())
2588 }
2589
2590 pub(crate) fn suggest_assoc_method_call(&self, segs: &[PathSegment<'_>]) {
2594 debug!("suggest_assoc_method_call segs: {:?}", segs);
2595 let [seg1, seg2] = segs else {
2596 return;
2597 };
2598 self.dcx().try_steal_modify_and_emit_err(
2599 seg1.ident.span,
2600 StashKey::CallAssocMethod,
2601 |err| {
2602 let body = self.tcx.hir().body_owned_by(self.body_id);
2603 struct LetVisitor {
2604 ident_name: Symbol,
2605 }
2606
2607 impl<'v> Visitor<'v> for LetVisitor {
2609 type Result = ControlFlow<Option<&'v hir::Expr<'v>>>;
2610 fn visit_stmt(&mut self, ex: &'v hir::Stmt<'v>) -> Self::Result {
2611 if let hir::StmtKind::Let(&hir::LetStmt { pat, init, .. }) = ex.kind
2612 && let hir::PatKind::Binding(_, _, ident, ..) = pat.kind
2613 && ident.name == self.ident_name
2614 {
2615 ControlFlow::Break(init)
2616 } else {
2617 hir::intravisit::walk_stmt(self, ex)
2618 }
2619 }
2620 }
2621
2622 if let Node::Expr(call_expr) = self.tcx.parent_hir_node(seg1.hir_id)
2623 && let ControlFlow::Break(Some(expr)) =
2624 (LetVisitor { ident_name: seg1.ident.name }).visit_body(&body)
2625 && let Some(self_ty) = self.node_ty_opt(expr.hir_id)
2626 {
2627 let probe = self.lookup_probe_for_diagnostic(
2628 seg2.ident,
2629 self_ty,
2630 call_expr,
2631 ProbeScope::TraitsInScope,
2632 None,
2633 );
2634 if probe.is_ok() {
2635 let sm = self.infcx.tcx.sess.source_map();
2636 err.span_suggestion_verbose(
2637 sm.span_extend_while(seg1.ident.span.shrink_to_hi(), |c| c == ':')
2638 .unwrap(),
2639 "you may have meant to call an instance method",
2640 ".",
2641 Applicability::MaybeIncorrect,
2642 );
2643 }
2644 }
2645 },
2646 );
2647 }
2648
2649 fn suggest_calling_method_on_field(
2651 &self,
2652 err: &mut Diag<'_>,
2653 source: SelfSource<'tcx>,
2654 span: Span,
2655 actual: Ty<'tcx>,
2656 item_name: Ident,
2657 return_type: Option<Ty<'tcx>>,
2658 ) {
2659 if let SelfSource::MethodCall(expr) = source {
2660 let mod_id = self.tcx.parent_module(expr.hir_id).to_def_id();
2661 for (fields, args) in self.get_field_candidates_considering_privacy_for_diag(
2662 span,
2663 actual,
2664 mod_id,
2665 expr.hir_id,
2666 ) {
2667 let call_expr = self.tcx.hir().expect_expr(self.tcx.parent_hir_id(expr.hir_id));
2668
2669 let lang_items = self.tcx.lang_items();
2670 let never_mention_traits = [
2671 lang_items.clone_trait(),
2672 lang_items.deref_trait(),
2673 lang_items.deref_mut_trait(),
2674 self.tcx.get_diagnostic_item(sym::AsRef),
2675 self.tcx.get_diagnostic_item(sym::AsMut),
2676 self.tcx.get_diagnostic_item(sym::Borrow),
2677 self.tcx.get_diagnostic_item(sym::BorrowMut),
2678 ];
2679 let mut candidate_fields: Vec<_> = fields
2680 .into_iter()
2681 .filter_map(|candidate_field| {
2682 self.check_for_nested_field_satisfying_condition_for_diag(
2683 span,
2684 &|_, field_ty| {
2685 self.lookup_probe_for_diagnostic(
2686 item_name,
2687 field_ty,
2688 call_expr,
2689 ProbeScope::TraitsInScope,
2690 return_type,
2691 )
2692 .is_ok_and(|pick| {
2693 !never_mention_traits
2694 .iter()
2695 .flatten()
2696 .any(|def_id| self.tcx.parent(pick.item.def_id) == *def_id)
2697 })
2698 },
2699 candidate_field,
2700 args,
2701 vec![],
2702 mod_id,
2703 expr.hir_id,
2704 )
2705 })
2706 .map(|field_path| {
2707 field_path
2708 .iter()
2709 .map(|id| id.to_string())
2710 .collect::<Vec<String>>()
2711 .join(".")
2712 })
2713 .collect();
2714 candidate_fields.sort();
2715
2716 let len = candidate_fields.len();
2717 if len > 0 {
2718 err.span_suggestions(
2719 item_name.span.shrink_to_lo(),
2720 format!(
2721 "{} of the expressions' fields {} a method of the same name",
2722 if len > 1 { "some" } else { "one" },
2723 if len > 1 { "have" } else { "has" },
2724 ),
2725 candidate_fields.iter().map(|path| format!("{path}.")),
2726 Applicability::MaybeIncorrect,
2727 );
2728 }
2729 }
2730 }
2731 }
2732
2733 fn suggest_unwrapping_inner_self(
2734 &self,
2735 err: &mut Diag<'_>,
2736 source: SelfSource<'tcx>,
2737 actual: Ty<'tcx>,
2738 item_name: Ident,
2739 ) {
2740 let tcx = self.tcx;
2741 let SelfSource::MethodCall(expr) = source else {
2742 return;
2743 };
2744 let call_expr = tcx.hir().expect_expr(tcx.parent_hir_id(expr.hir_id));
2745
2746 let ty::Adt(kind, args) = actual.kind() else {
2747 return;
2748 };
2749 match kind.adt_kind() {
2750 ty::AdtKind::Enum => {
2751 let matching_variants: Vec<_> = kind
2752 .variants()
2753 .iter()
2754 .flat_map(|variant| {
2755 let [field] = &variant.fields.raw[..] else {
2756 return None;
2757 };
2758 let field_ty = field.ty(tcx, args);
2759
2760 if self.resolve_vars_if_possible(field_ty).is_ty_var() {
2762 return None;
2763 }
2764
2765 self.lookup_probe_for_diagnostic(
2766 item_name,
2767 field_ty,
2768 call_expr,
2769 ProbeScope::TraitsInScope,
2770 None,
2771 )
2772 .ok()
2773 .map(|pick| (variant, field, pick))
2774 })
2775 .collect();
2776
2777 let ret_ty_matches = |diagnostic_item| {
2778 if let Some(ret_ty) = self
2779 .ret_coercion
2780 .as_ref()
2781 .map(|c| self.resolve_vars_if_possible(c.borrow().expected_ty()))
2782 && let ty::Adt(kind, _) = ret_ty.kind()
2783 && tcx.get_diagnostic_item(diagnostic_item) == Some(kind.did())
2784 {
2785 true
2786 } else {
2787 false
2788 }
2789 };
2790
2791 match &matching_variants[..] {
2792 [(_, field, pick)] => {
2793 let self_ty = field.ty(tcx, args);
2794 err.span_note(
2795 tcx.def_span(pick.item.def_id),
2796 format!("the method `{item_name}` exists on the type `{self_ty}`"),
2797 );
2798 let (article, kind, variant, question) =
2799 if tcx.is_diagnostic_item(sym::Result, kind.did()) {
2800 ("a", "Result", "Err", ret_ty_matches(sym::Result))
2801 } else if tcx.is_diagnostic_item(sym::Option, kind.did()) {
2802 ("an", "Option", "None", ret_ty_matches(sym::Option))
2803 } else {
2804 return;
2805 };
2806 if question {
2807 err.span_suggestion_verbose(
2808 expr.span.shrink_to_hi(),
2809 format!(
2810 "use the `?` operator to extract the `{self_ty}` value, propagating \
2811 {article} `{kind}::{variant}` value to the caller"
2812 ),
2813 "?",
2814 Applicability::MachineApplicable,
2815 );
2816 } else {
2817 err.span_suggestion_verbose(
2818 expr.span.shrink_to_hi(),
2819 format!(
2820 "consider using `{kind}::expect` to unwrap the `{self_ty}` value, \
2821 panicking if the value is {article} `{kind}::{variant}`"
2822 ),
2823 ".expect(\"REASON\")",
2824 Applicability::HasPlaceholders,
2825 );
2826 }
2827 }
2828 _ => {}
2830 }
2831 }
2832 ty::AdtKind::Struct | ty::AdtKind::Union => {
2835 let [first] = ***args else {
2836 return;
2837 };
2838 let ty::GenericArgKind::Type(ty) = first.unpack() else {
2839 return;
2840 };
2841 let Ok(pick) = self.lookup_probe_for_diagnostic(
2842 item_name,
2843 ty,
2844 call_expr,
2845 ProbeScope::TraitsInScope,
2846 None,
2847 ) else {
2848 return;
2849 };
2850
2851 let name = self.ty_to_value_string(actual);
2852 let inner_id = kind.did();
2853 let mutable = if let Some(AutorefOrPtrAdjustment::Autoref { mutbl, .. }) =
2854 pick.autoref_or_ptr_adjustment
2855 {
2856 Some(mutbl)
2857 } else {
2858 None
2859 };
2860
2861 if tcx.is_diagnostic_item(sym::LocalKey, inner_id) {
2862 err.help("use `with` or `try_with` to access thread local storage");
2863 } else if tcx.is_lang_item(kind.did(), LangItem::MaybeUninit) {
2864 err.help(format!(
2865 "if this `{name}` has been initialized, \
2866 use one of the `assume_init` methods to access the inner value"
2867 ));
2868 } else if tcx.is_diagnostic_item(sym::RefCell, inner_id) {
2869 let (suggestion, borrow_kind, panic_if) = match mutable {
2870 Some(Mutability::Not) => (".borrow()", "borrow", "a mutable borrow exists"),
2871 Some(Mutability::Mut) => {
2872 (".borrow_mut()", "mutably borrow", "any borrows exist")
2873 }
2874 None => return,
2875 };
2876 err.span_suggestion_verbose(
2877 expr.span.shrink_to_hi(),
2878 format!(
2879 "use `{suggestion}` to {borrow_kind} the `{ty}`, \
2880 panicking if {panic_if}"
2881 ),
2882 suggestion,
2883 Applicability::MaybeIncorrect,
2884 );
2885 } else if tcx.is_diagnostic_item(sym::Mutex, inner_id) {
2886 err.span_suggestion_verbose(
2887 expr.span.shrink_to_hi(),
2888 format!(
2889 "use `.lock().unwrap()` to borrow the `{ty}`, \
2890 blocking the current thread until it can be acquired"
2891 ),
2892 ".lock().unwrap()",
2893 Applicability::MaybeIncorrect,
2894 );
2895 } else if tcx.is_diagnostic_item(sym::RwLock, inner_id) {
2896 let (suggestion, borrow_kind) = match mutable {
2897 Some(Mutability::Not) => (".read().unwrap()", "borrow"),
2898 Some(Mutability::Mut) => (".write().unwrap()", "mutably borrow"),
2899 None => return,
2900 };
2901 err.span_suggestion_verbose(
2902 expr.span.shrink_to_hi(),
2903 format!(
2904 "use `{suggestion}` to {borrow_kind} the `{ty}`, \
2905 blocking the current thread until it can be acquired"
2906 ),
2907 suggestion,
2908 Applicability::MaybeIncorrect,
2909 );
2910 } else {
2911 return;
2912 };
2913
2914 err.span_note(
2915 tcx.def_span(pick.item.def_id),
2916 format!("the method `{item_name}` exists on the type `{ty}`"),
2917 );
2918 }
2919 }
2920 }
2921
2922 pub(crate) fn note_unmet_impls_on_type(
2923 &self,
2924 err: &mut Diag<'_>,
2925 errors: Vec<FulfillmentError<'tcx>>,
2926 suggest_derive: bool,
2927 ) {
2928 let preds: Vec<_> = errors
2929 .iter()
2930 .filter_map(|e| match e.obligation.predicate.kind().skip_binder() {
2931 ty::PredicateKind::Clause(ty::ClauseKind::Trait(pred)) => {
2932 match pred.self_ty().kind() {
2933 ty::Adt(_, _) => Some(pred),
2934 _ => None,
2935 }
2936 }
2937 _ => None,
2938 })
2939 .collect();
2940
2941 let (mut local_preds, mut foreign_preds): (Vec<_>, Vec<_>) =
2943 preds.iter().partition(|&pred| {
2944 if let ty::Adt(def, _) = pred.self_ty().kind() {
2945 def.did().is_local()
2946 } else {
2947 false
2948 }
2949 });
2950
2951 local_preds.sort_by_key(|pred: &&ty::TraitPredicate<'_>| pred.trait_ref.to_string());
2952 let local_def_ids = local_preds
2953 .iter()
2954 .filter_map(|pred| match pred.self_ty().kind() {
2955 ty::Adt(def, _) => Some(def.did()),
2956 _ => None,
2957 })
2958 .collect::<FxIndexSet<_>>();
2959 let mut local_spans: MultiSpan = local_def_ids
2960 .iter()
2961 .filter_map(|def_id| {
2962 let span = self.tcx.def_span(*def_id);
2963 if span.is_dummy() { None } else { Some(span) }
2964 })
2965 .collect::<Vec<_>>()
2966 .into();
2967 for pred in &local_preds {
2968 match pred.self_ty().kind() {
2969 ty::Adt(def, _) => {
2970 local_spans.push_span_label(
2971 self.tcx.def_span(def.did()),
2972 format!("must implement `{}`", pred.trait_ref.print_trait_sugared()),
2973 );
2974 }
2975 _ => {}
2976 }
2977 }
2978 if local_spans.primary_span().is_some() {
2979 let msg = if let [local_pred] = local_preds.as_slice() {
2980 format!(
2981 "an implementation of `{}` might be missing for `{}`",
2982 local_pred.trait_ref.print_trait_sugared(),
2983 local_pred.self_ty()
2984 )
2985 } else {
2986 format!(
2987 "the following type{} would have to `impl` {} required trait{} for this \
2988 operation to be valid",
2989 pluralize!(local_def_ids.len()),
2990 if local_def_ids.len() == 1 { "its" } else { "their" },
2991 pluralize!(local_preds.len()),
2992 )
2993 };
2994 err.span_note(local_spans, msg);
2995 }
2996
2997 foreign_preds.sort_by_key(|pred: &&ty::TraitPredicate<'_>| pred.trait_ref.to_string());
2998 let foreign_def_ids = foreign_preds
2999 .iter()
3000 .filter_map(|pred| match pred.self_ty().kind() {
3001 ty::Adt(def, _) => Some(def.did()),
3002 _ => None,
3003 })
3004 .collect::<FxIndexSet<_>>();
3005 let mut foreign_spans: MultiSpan = foreign_def_ids
3006 .iter()
3007 .filter_map(|def_id| {
3008 let span = self.tcx.def_span(*def_id);
3009 if span.is_dummy() { None } else { Some(span) }
3010 })
3011 .collect::<Vec<_>>()
3012 .into();
3013 for pred in &foreign_preds {
3014 match pred.self_ty().kind() {
3015 ty::Adt(def, _) => {
3016 foreign_spans.push_span_label(
3017 self.tcx.def_span(def.did()),
3018 format!("not implement `{}`", pred.trait_ref.print_trait_sugared()),
3019 );
3020 }
3021 _ => {}
3022 }
3023 }
3024 if foreign_spans.primary_span().is_some() {
3025 let msg = if let [foreign_pred] = foreign_preds.as_slice() {
3026 format!(
3027 "the foreign item type `{}` doesn't implement `{}`",
3028 foreign_pred.self_ty(),
3029 foreign_pred.trait_ref.print_trait_sugared()
3030 )
3031 } else {
3032 format!(
3033 "the foreign item type{} {} implement required trait{} for this \
3034 operation to be valid",
3035 pluralize!(foreign_def_ids.len()),
3036 if foreign_def_ids.len() > 1 { "don't" } else { "doesn't" },
3037 pluralize!(foreign_preds.len()),
3038 )
3039 };
3040 err.span_note(foreign_spans, msg);
3041 }
3042
3043 let preds: Vec<_> = errors
3044 .iter()
3045 .map(|e| (e.obligation.predicate, None, Some(e.obligation.cause.clone())))
3046 .collect();
3047 if suggest_derive {
3048 self.suggest_derive(err, &preds);
3049 } else {
3050 let _ = self.note_predicate_source_and_get_derives(err, &preds);
3052 }
3053 }
3054
3055 fn note_predicate_source_and_get_derives(
3056 &self,
3057 err: &mut Diag<'_>,
3058 unsatisfied_predicates: &[(
3059 ty::Predicate<'tcx>,
3060 Option<ty::Predicate<'tcx>>,
3061 Option<ObligationCause<'tcx>>,
3062 )],
3063 ) -> Vec<(String, Span, Symbol)> {
3064 let mut derives = Vec::<(String, Span, Symbol)>::new();
3065 let mut traits = Vec::new();
3066 for (pred, _, _) in unsatisfied_predicates {
3067 let Some(ty::PredicateKind::Clause(ty::ClauseKind::Trait(trait_pred))) =
3068 pred.kind().no_bound_vars()
3069 else {
3070 continue;
3071 };
3072 let adt = match trait_pred.self_ty().ty_adt_def() {
3073 Some(adt) if adt.did().is_local() => adt,
3074 _ => continue,
3075 };
3076 if let Some(diagnostic_name) = self.tcx.get_diagnostic_name(trait_pred.def_id()) {
3077 let can_derive = match diagnostic_name {
3078 sym::Default => !adt.is_enum(),
3079 sym::Eq
3080 | sym::PartialEq
3081 | sym::Ord
3082 | sym::PartialOrd
3083 | sym::Clone
3084 | sym::Copy
3085 | sym::Hash
3086 | sym::Debug => true,
3087 _ => false,
3088 };
3089 if can_derive {
3090 let self_name = trait_pred.self_ty().to_string();
3091 let self_span = self.tcx.def_span(adt.did());
3092 for super_trait in
3093 supertraits(self.tcx, ty::Binder::dummy(trait_pred.trait_ref))
3094 {
3095 if let Some(parent_diagnostic_name) =
3096 self.tcx.get_diagnostic_name(super_trait.def_id())
3097 {
3098 derives.push((self_name.clone(), self_span, parent_diagnostic_name));
3099 }
3100 }
3101 derives.push((self_name, self_span, diagnostic_name));
3102 } else {
3103 traits.push(trait_pred.def_id());
3104 }
3105 } else {
3106 traits.push(trait_pred.def_id());
3107 }
3108 }
3109 traits.sort_by_key(|id| self.tcx.def_path_str(id));
3110 traits.dedup();
3111
3112 let len = traits.len();
3113 if len > 0 {
3114 let span =
3115 MultiSpan::from_spans(traits.iter().map(|&did| self.tcx.def_span(did)).collect());
3116 let mut names = format!("`{}`", self.tcx.def_path_str(traits[0]));
3117 for (i, &did) in traits.iter().enumerate().skip(1) {
3118 if len > 2 {
3119 names.push_str(", ");
3120 }
3121 if i == len - 1 {
3122 names.push_str(" and ");
3123 }
3124 names.push('`');
3125 names.push_str(&self.tcx.def_path_str(did));
3126 names.push('`');
3127 }
3128 err.span_note(
3129 span,
3130 format!("the trait{} {} must be implemented", pluralize!(len), names),
3131 );
3132 }
3133
3134 derives
3135 }
3136
3137 pub(crate) fn suggest_derive(
3138 &self,
3139 err: &mut Diag<'_>,
3140 unsatisfied_predicates: &[(
3141 ty::Predicate<'tcx>,
3142 Option<ty::Predicate<'tcx>>,
3143 Option<ObligationCause<'tcx>>,
3144 )],
3145 ) -> bool {
3146 let mut derives = self.note_predicate_source_and_get_derives(err, unsatisfied_predicates);
3147 derives.sort();
3148 derives.dedup();
3149
3150 let mut derives_grouped = Vec::<(String, Span, String)>::new();
3151 for (self_name, self_span, trait_name) in derives.into_iter() {
3152 if let Some((last_self_name, _, ref mut last_trait_names)) = derives_grouped.last_mut()
3153 {
3154 if last_self_name == &self_name {
3155 last_trait_names.push_str(format!(", {trait_name}").as_str());
3156 continue;
3157 }
3158 }
3159 derives_grouped.push((self_name, self_span, trait_name.to_string()));
3160 }
3161
3162 for (self_name, self_span, traits) in &derives_grouped {
3163 err.span_suggestion_verbose(
3164 self_span.shrink_to_lo(),
3165 format!("consider annotating `{self_name}` with `#[derive({traits})]`"),
3166 format!("#[derive({traits})]\n"),
3167 Applicability::MaybeIncorrect,
3168 );
3169 }
3170 !derives_grouped.is_empty()
3171 }
3172
3173 fn note_derefed_ty_has_method(
3174 &self,
3175 err: &mut Diag<'_>,
3176 self_source: SelfSource<'tcx>,
3177 rcvr_ty: Ty<'tcx>,
3178 item_name: Ident,
3179 expected: Expectation<'tcx>,
3180 ) {
3181 let SelfSource::QPath(ty) = self_source else {
3182 return;
3183 };
3184 for (deref_ty, _) in self.autoderef(DUMMY_SP, rcvr_ty).silence_errors().skip(1) {
3185 if let Ok(pick) = self.probe_for_name(
3186 Mode::Path,
3187 item_name,
3188 expected.only_has_type(self),
3189 IsSuggestion(true),
3190 deref_ty,
3191 ty.hir_id,
3192 ProbeScope::TraitsInScope,
3193 ) {
3194 if deref_ty.is_suggestable(self.tcx, true)
3195 && pick.item.fn_has_self_parameter
3199 && let Some(self_ty) =
3200 self.tcx.fn_sig(pick.item.def_id).instantiate_identity().inputs().skip_binder().get(0)
3201 && self_ty.is_ref()
3202 {
3203 let suggested_path = match deref_ty.kind() {
3204 ty::Bool
3205 | ty::Char
3206 | ty::Int(_)
3207 | ty::Uint(_)
3208 | ty::Float(_)
3209 | ty::Adt(_, _)
3210 | ty::Str
3211 | ty::Alias(ty::Projection | ty::Inherent, _)
3212 | ty::Param(_) => format!("{deref_ty}"),
3213 _ if self
3219 .tcx
3220 .sess
3221 .source_map()
3222 .span_wrapped_by_angle_or_parentheses(ty.span) =>
3223 {
3224 format!("{deref_ty}")
3225 }
3226 _ => format!("<{deref_ty}>"),
3227 };
3228 err.span_suggestion_verbose(
3229 ty.span,
3230 format!("the function `{item_name}` is implemented on `{deref_ty}`"),
3231 suggested_path,
3232 Applicability::MaybeIncorrect,
3233 );
3234 } else {
3235 err.span_note(
3236 ty.span,
3237 format!("the function `{item_name}` is implemented on `{deref_ty}`"),
3238 );
3239 }
3240 return;
3241 }
3242 }
3243 }
3244
3245 fn ty_to_value_string(&self, ty: Ty<'tcx>) -> String {
3247 match ty.kind() {
3248 ty::Adt(def, args) => self.tcx.def_path_str_with_args(def.did(), args),
3249 _ => self.ty_to_string(ty),
3250 }
3251 }
3252
3253 fn suggest_await_before_method(
3254 &self,
3255 err: &mut Diag<'_>,
3256 item_name: Ident,
3257 ty: Ty<'tcx>,
3258 call: &hir::Expr<'_>,
3259 span: Span,
3260 return_type: Option<Ty<'tcx>>,
3261 ) {
3262 let output_ty = match self.err_ctxt().get_impl_future_output_ty(ty) {
3263 Some(output_ty) => self.resolve_vars_if_possible(output_ty),
3264 _ => return,
3265 };
3266 let method_exists =
3267 self.method_exists_for_diagnostic(item_name, output_ty, call.hir_id, return_type);
3268 debug!("suggest_await_before_method: is_method_exist={}", method_exists);
3269 if method_exists {
3270 err.span_suggestion_verbose(
3271 span.shrink_to_lo(),
3272 "consider `await`ing on the `Future` and calling the method on its `Output`",
3273 "await.",
3274 Applicability::MaybeIncorrect,
3275 );
3276 }
3277 }
3278
3279 fn suggest_use_candidates<F>(&self, candidates: Vec<DefId>, handle_candidates: F)
3280 where
3281 F: FnOnce(Vec<String>, Vec<String>, Span),
3282 {
3283 let parent_map = self.tcx.visible_parent_map(());
3284
3285 let scope = self.tcx.parent_module_from_def_id(self.body_id);
3286 let (accessible_candidates, inaccessible_candidates): (Vec<_>, Vec<_>) =
3287 candidates.into_iter().partition(|id| {
3288 let vis = self.tcx.visibility(*id);
3289 vis.is_accessible_from(scope, self.tcx)
3290 });
3291
3292 let sugg = |candidates: Vec<_>, visible| {
3293 let (candidates, globs): (Vec<_>, Vec<_>) =
3296 candidates.into_iter().partition(|trait_did| {
3297 if let Some(parent_did) = parent_map.get(trait_did) {
3298 if *parent_did != self.tcx.parent(*trait_did)
3300 && self
3301 .tcx
3302 .module_children(*parent_did)
3303 .iter()
3304 .filter(|child| child.res.opt_def_id() == Some(*trait_did))
3305 .all(|child| child.ident.name == kw::Underscore)
3306 {
3307 return false;
3308 }
3309 }
3310
3311 true
3312 });
3313
3314 let prefix = if visible { "use " } else { "" };
3315 let postfix = if visible { ";" } else { "" };
3316 let path_strings = candidates.iter().map(|trait_did| {
3317 format!(
3318 "{prefix}{}{postfix}\n",
3319 with_crate_prefix!(self.tcx.def_path_str(*trait_did)),
3320 )
3321 });
3322
3323 let glob_path_strings = globs.iter().map(|trait_did| {
3324 let parent_did = parent_map.get(trait_did).unwrap();
3325 format!(
3326 "{prefix}{}::*{postfix} // trait {}\n",
3327 with_crate_prefix!(self.tcx.def_path_str(*parent_did)),
3328 self.tcx.item_name(*trait_did),
3329 )
3330 });
3331 let mut sugg: Vec<_> = path_strings.chain(glob_path_strings).collect();
3332 sugg.sort();
3333 sugg
3334 };
3335
3336 let accessible_sugg = sugg(accessible_candidates, true);
3337 let inaccessible_sugg = sugg(inaccessible_candidates, false);
3338
3339 let (module, _, _) = self.tcx.hir().get_module(scope);
3340 let span = module.spans.inject_use_span;
3341 handle_candidates(accessible_sugg, inaccessible_sugg, span);
3342 }
3343
3344 fn suggest_valid_traits(
3345 &self,
3346 err: &mut Diag<'_>,
3347 item_name: Ident,
3348 valid_out_of_scope_traits: Vec<DefId>,
3349 explain: bool,
3350 ) -> bool {
3351 if !valid_out_of_scope_traits.is_empty() {
3352 let mut candidates = valid_out_of_scope_traits;
3353 candidates.sort_by_key(|id| self.tcx.def_path_str(id));
3354 candidates.dedup();
3355
3356 let edition_fix = candidates
3358 .iter()
3359 .find(|did| self.tcx.is_diagnostic_item(sym::TryInto, **did))
3360 .copied();
3361
3362 if explain {
3363 err.help("items from traits can only be used if the trait is in scope");
3364 }
3365
3366 let msg = format!(
3367 "{this_trait_is} implemented but not in scope",
3368 this_trait_is = if candidates.len() == 1 {
3369 format!(
3370 "trait `{}` which provides `{item_name}` is",
3371 self.tcx.item_name(candidates[0]),
3372 )
3373 } else {
3374 format!("the following traits which provide `{item_name}` are")
3375 }
3376 );
3377
3378 self.suggest_use_candidates(candidates, |accessible_sugg, inaccessible_sugg, span| {
3379 let suggest_for_access = |err: &mut Diag<'_>, mut msg: String, suggs: Vec<_>| {
3380 msg += &format!(
3381 "; perhaps you want to import {one_of}",
3382 one_of = if suggs.len() == 1 { "it" } else { "one of them" },
3383 );
3384 err.span_suggestions(span, msg, suggs, Applicability::MaybeIncorrect);
3385 };
3386 let suggest_for_privacy = |err: &mut Diag<'_>, suggs: Vec<String>| {
3387 let msg = format!(
3388 "{this_trait_is} implemented but not reachable",
3389 this_trait_is = if let [sugg] = suggs.as_slice() {
3390 format!("trait `{}` which provides `{item_name}` is", sugg.trim())
3391 } else {
3392 format!("the following traits which provide `{item_name}` are")
3393 }
3394 );
3395 if suggs.len() == 1 {
3396 err.help(msg);
3397 } else {
3398 err.span_suggestions(span, msg, suggs, Applicability::MaybeIncorrect);
3399 }
3400 };
3401 if accessible_sugg.is_empty() {
3402 suggest_for_privacy(err, inaccessible_sugg);
3404 } else if inaccessible_sugg.is_empty() {
3405 suggest_for_access(err, msg, accessible_sugg);
3406 } else {
3407 suggest_for_access(err, msg, accessible_sugg);
3408 suggest_for_privacy(err, inaccessible_sugg);
3409 }
3410 });
3411
3412 if let Some(did) = edition_fix {
3413 err.note(format!(
3414 "'{}' is included in the prelude starting in Edition 2021",
3415 with_crate_prefix!(self.tcx.def_path_str(did))
3416 ));
3417 }
3418
3419 true
3420 } else {
3421 false
3422 }
3423 }
3424
3425 fn suggest_traits_to_import(
3426 &self,
3427 err: &mut Diag<'_>,
3428 span: Span,
3429 rcvr_ty: Ty<'tcx>,
3430 item_name: Ident,
3431 inputs_len: Option<usize>,
3432 source: SelfSource<'tcx>,
3433 valid_out_of_scope_traits: Vec<DefId>,
3434 static_candidates: &[CandidateSource],
3435 unsatisfied_bounds: bool,
3436 return_type: Option<Ty<'tcx>>,
3437 trait_missing_method: bool,
3438 ) {
3439 let mut alt_rcvr_sugg = false;
3440 let mut trait_in_other_version_found = false;
3441 if let (SelfSource::MethodCall(rcvr), false) = (source, unsatisfied_bounds) {
3442 debug!(
3443 "suggest_traits_to_import: span={:?}, item_name={:?}, rcvr_ty={:?}, rcvr={:?}",
3444 span, item_name, rcvr_ty, rcvr
3445 );
3446 let skippable = [
3447 self.tcx.lang_items().clone_trait(),
3448 self.tcx.lang_items().deref_trait(),
3449 self.tcx.lang_items().deref_mut_trait(),
3450 self.tcx.lang_items().drop_trait(),
3451 self.tcx.get_diagnostic_item(sym::AsRef),
3452 ];
3453 for (rcvr_ty, post, pin_call) in &[
3457 (rcvr_ty, "", None),
3458 (
3459 Ty::new_mut_ref(self.tcx, self.tcx.lifetimes.re_erased, rcvr_ty),
3460 "&mut ",
3461 Some("as_mut"),
3462 ),
3463 (
3464 Ty::new_imm_ref(self.tcx, self.tcx.lifetimes.re_erased, rcvr_ty),
3465 "&",
3466 Some("as_ref"),
3467 ),
3468 ] {
3469 match self.lookup_probe_for_diagnostic(
3470 item_name,
3471 *rcvr_ty,
3472 rcvr,
3473 ProbeScope::AllTraits,
3474 return_type,
3475 ) {
3476 Ok(pick) => {
3477 let did = Some(pick.item.container_id(self.tcx));
3482 if skippable.contains(&did) {
3483 continue;
3484 }
3485 trait_in_other_version_found = self
3486 .detect_and_explain_multiple_crate_versions(
3487 err,
3488 pick.item.def_id,
3489 rcvr.hir_id,
3490 Some(*rcvr_ty),
3491 );
3492 if pick.autoderefs == 0 && !trait_in_other_version_found {
3493 err.span_label(
3494 pick.item.ident(self.tcx).span,
3495 format!("the method is available for `{rcvr_ty}` here"),
3496 );
3497 }
3498 break;
3499 }
3500 Err(MethodError::Ambiguity(_)) => {
3501 break;
3506 }
3507 Err(_) => (),
3508 }
3509
3510 let Some(unpin_trait) = self.tcx.lang_items().unpin_trait() else {
3511 return;
3512 };
3513 let pred = ty::TraitRef::new(self.tcx, unpin_trait, [*rcvr_ty]);
3514 let unpin = self.predicate_must_hold_considering_regions(&Obligation::new(
3515 self.tcx,
3516 self.misc(rcvr.span),
3517 self.param_env,
3518 pred,
3519 ));
3520 for (rcvr_ty, pre) in &[
3521 (Ty::new_lang_item(self.tcx, *rcvr_ty, LangItem::OwnedBox), "Box::new"),
3522 (Ty::new_lang_item(self.tcx, *rcvr_ty, LangItem::Pin), "Pin::new"),
3523 (Ty::new_diagnostic_item(self.tcx, *rcvr_ty, sym::Arc), "Arc::new"),
3524 (Ty::new_diagnostic_item(self.tcx, *rcvr_ty, sym::Rc), "Rc::new"),
3525 ] {
3526 if let Some(new_rcvr_t) = *rcvr_ty
3527 && let Ok(pick) = self.lookup_probe_for_diagnostic(
3528 item_name,
3529 new_rcvr_t,
3530 rcvr,
3531 ProbeScope::AllTraits,
3532 return_type,
3533 )
3534 {
3535 debug!("try_alt_rcvr: pick candidate {:?}", pick);
3536 let did = Some(pick.item.container_id(self.tcx));
3537 let skip = skippable.contains(&did)
3543 || (("Pin::new" == *pre)
3544 && ((sym::as_ref == item_name.name) || !unpin))
3545 || inputs_len.is_some_and(|inputs_len| {
3546 pick.item.kind == ty::AssocKind::Fn
3547 && self
3548 .tcx
3549 .fn_sig(pick.item.def_id)
3550 .skip_binder()
3551 .skip_binder()
3552 .inputs()
3553 .len()
3554 != inputs_len
3555 });
3556 if pick.autoderefs == 0 && !skip {
3560 err.span_label(
3561 pick.item.ident(self.tcx).span,
3562 format!("the method is available for `{new_rcvr_t}` here"),
3563 );
3564 err.multipart_suggestion(
3565 "consider wrapping the receiver expression with the \
3566 appropriate type",
3567 vec![
3568 (rcvr.span.shrink_to_lo(), format!("{pre}({post}")),
3569 (rcvr.span.shrink_to_hi(), ")".to_string()),
3570 ],
3571 Applicability::MaybeIncorrect,
3572 );
3573 alt_rcvr_sugg = true;
3575 }
3576 }
3577 }
3578 if let Some(new_rcvr_t) = Ty::new_lang_item(self.tcx, *rcvr_ty, LangItem::Pin)
3581 && !alt_rcvr_sugg
3583 && !unpin
3585 && sym::as_ref != item_name.name
3587 && let Some(pin_call) = pin_call
3589 && let Ok(pick) = self.lookup_probe_for_diagnostic(
3591 item_name,
3592 new_rcvr_t,
3593 rcvr,
3594 ProbeScope::AllTraits,
3595 return_type,
3596 )
3597 && !skippable.contains(&Some(pick.item.container_id(self.tcx)))
3600 && pick.autoderefs == 0
3602 && inputs_len.is_some_and(|inputs_len| pick.item.kind == ty::AssocKind::Fn && self.tcx.fn_sig(pick.item.def_id).skip_binder().skip_binder().inputs().len() == inputs_len)
3605 {
3606 let indent = self
3607 .tcx
3608 .sess
3609 .source_map()
3610 .indentation_before(rcvr.span)
3611 .unwrap_or_else(|| " ".to_string());
3612 let mut expr = rcvr;
3613 while let Node::Expr(call_expr) = self.tcx.parent_hir_node(expr.hir_id)
3614 && let hir::ExprKind::MethodCall(hir::PathSegment { .. }, ..) =
3615 call_expr.kind
3616 {
3617 expr = call_expr;
3618 }
3619 match self.tcx.parent_hir_node(expr.hir_id) {
3620 Node::LetStmt(stmt)
3621 if let Some(init) = stmt.init
3622 && let Ok(code) =
3623 self.tcx.sess.source_map().span_to_snippet(rcvr.span) =>
3624 {
3625 err.multipart_suggestion(
3628 "consider pinning the expression",
3629 vec![
3630 (
3631 stmt.span.shrink_to_lo(),
3632 format!(
3633 "let mut pinned = std::pin::pin!({code});\n{indent}"
3634 ),
3635 ),
3636 (
3637 init.span.until(rcvr.span.shrink_to_hi()),
3638 format!("pinned.{pin_call}()"),
3639 ),
3640 ],
3641 Applicability::MaybeIncorrect,
3642 );
3643 }
3644 Node::Block(_) | Node::Stmt(_) => {
3645 err.multipart_suggestion(
3648 "consider pinning the expression",
3649 vec![
3650 (
3651 rcvr.span.shrink_to_lo(),
3652 format!("let mut pinned = std::pin::pin!("),
3653 ),
3654 (
3655 rcvr.span.shrink_to_hi(),
3656 format!(");\n{indent}pinned.{pin_call}()"),
3657 ),
3658 ],
3659 Applicability::MaybeIncorrect,
3660 );
3661 }
3662 _ => {
3663 err.span_help(
3666 rcvr.span,
3667 "consider pinning the expression with `std::pin::pin!()` and \
3668 assigning that to a new binding",
3669 );
3670 }
3671 }
3672 alt_rcvr_sugg = true;
3674 }
3675 }
3676 }
3677
3678 if let SelfSource::QPath(ty) = source
3679 && !valid_out_of_scope_traits.is_empty()
3680 && let hir::TyKind::Path(path) = ty.kind
3681 && let hir::QPath::Resolved(..) = path
3682 && let Some(assoc) = self
3683 .tcx
3684 .associated_items(valid_out_of_scope_traits[0])
3685 .filter_by_name_unhygienic(item_name.name)
3686 .next()
3687 {
3688 let rcvr_ty = self.node_ty_opt(ty.hir_id);
3693 trait_in_other_version_found = self.detect_and_explain_multiple_crate_versions(
3694 err,
3695 assoc.def_id,
3696 ty.hir_id,
3697 rcvr_ty,
3698 );
3699 }
3700 if !trait_in_other_version_found
3701 && self.suggest_valid_traits(err, item_name, valid_out_of_scope_traits, true)
3702 {
3703 return;
3704 }
3705
3706 let type_is_local = self.type_derefs_to_local(span, rcvr_ty, source);
3707
3708 let mut arbitrary_rcvr = vec![];
3709 let mut candidates = all_traits(self.tcx)
3713 .into_iter()
3714 .filter(|info| match self.tcx.lookup_stability(info.def_id) {
3717 Some(attr) => attr.level.is_stable(),
3718 None => true,
3719 })
3720 .filter(|info| {
3721 static_candidates.iter().all(|sc| match *sc {
3724 CandidateSource::Trait(def_id) => def_id != info.def_id,
3725 CandidateSource::Impl(def_id) => {
3726 self.tcx.trait_id_of_impl(def_id) != Some(info.def_id)
3727 }
3728 })
3729 })
3730 .filter(|info| {
3731 (type_is_local || info.def_id.is_local())
3738 && !self.tcx.trait_is_auto(info.def_id)
3739 && self
3740 .associated_value(info.def_id, item_name)
3741 .filter(|item| {
3742 if let ty::AssocKind::Fn = item.kind {
3743 let id = item
3744 .def_id
3745 .as_local()
3746 .map(|def_id| self.tcx.hir_node_by_def_id(def_id));
3747 if let Some(hir::Node::TraitItem(hir::TraitItem {
3748 kind: hir::TraitItemKind::Fn(fn_sig, method),
3749 ..
3750 })) = id
3751 {
3752 let self_first_arg = match method {
3753 hir::TraitFn::Required([ident, ..]) => {
3754 ident.name == kw::SelfLower
3755 }
3756 hir::TraitFn::Provided(body_id) => self
3757 .tcx
3758 .hir()
3759 .body(*body_id)
3760 .params
3761 .first()
3762 .is_some_and(|param| {
3763 matches!(
3764 param.pat.kind,
3765 hir::PatKind::Binding(_, _, ident, _)
3766 if ident.name == kw::SelfLower
3767 )
3768 }),
3769 _ => false,
3770 };
3771
3772 if !fn_sig.decl.implicit_self.has_implicit_self()
3773 && self_first_arg
3774 {
3775 if let Some(ty) = fn_sig.decl.inputs.get(0) {
3776 arbitrary_rcvr.push(ty.span);
3777 }
3778 return false;
3779 }
3780 }
3781 }
3782 item.visibility(self.tcx).is_public() || info.def_id.is_local()
3784 })
3785 .is_some()
3786 })
3787 .collect::<Vec<_>>();
3788 for span in &arbitrary_rcvr {
3789 err.span_label(
3790 *span,
3791 "the method might not be found because of this arbitrary self type",
3792 );
3793 }
3794 if alt_rcvr_sugg {
3795 return;
3796 }
3797
3798 if !candidates.is_empty() {
3799 candidates
3801 .sort_by_key(|&info| (!info.def_id.is_local(), self.tcx.def_path_str(info.def_id)));
3802 candidates.dedup();
3803
3804 let param_type = match *rcvr_ty.kind() {
3805 ty::Param(param) => Some(param),
3806 ty::Ref(_, ty, _) => match *ty.kind() {
3807 ty::Param(param) => Some(param),
3808 _ => None,
3809 },
3810 _ => None,
3811 };
3812 if !trait_missing_method {
3813 err.help(if param_type.is_some() {
3814 "items from traits can only be used if the type parameter is bounded by the trait"
3815 } else {
3816 "items from traits can only be used if the trait is implemented and in scope"
3817 });
3818 }
3819
3820 let candidates_len = candidates.len();
3821 let message = |action| {
3822 format!(
3823 "the following {traits_define} an item `{name}`, perhaps you need to {action} \
3824 {one_of_them}:",
3825 traits_define =
3826 if candidates_len == 1 { "trait defines" } else { "traits define" },
3827 action = action,
3828 one_of_them = if candidates_len == 1 { "it" } else { "one of them" },
3829 name = item_name,
3830 )
3831 };
3832 if let Some(param) = param_type {
3834 let generics = self.tcx.generics_of(self.body_id.to_def_id());
3835 let type_param = generics.type_param(param, self.tcx);
3836 let hir = self.tcx.hir();
3837 if let Some(def_id) = type_param.def_id.as_local() {
3838 let id = self.tcx.local_def_id_to_hir_id(def_id);
3839 match self.tcx.hir_node(id) {
3843 Node::GenericParam(param) => {
3844 enum Introducer {
3845 Plus,
3846 Colon,
3847 Nothing,
3848 }
3849 let hir_generics = hir.get_generics(id.owner.def_id).unwrap();
3850 let trait_def_ids: DefIdSet = hir_generics
3851 .bounds_for_param(def_id)
3852 .flat_map(|bp| bp.bounds.iter())
3853 .filter_map(|bound| bound.trait_ref()?.trait_def_id())
3854 .collect();
3855 if candidates.iter().any(|t| trait_def_ids.contains(&t.def_id)) {
3856 return;
3857 }
3858 let msg = message(format!(
3859 "restrict type parameter `{}` with",
3860 param.name.ident(),
3861 ));
3862 let bounds_span = hir_generics.bounds_span_for_suggestions(def_id);
3863 let mut applicability = Applicability::MaybeIncorrect;
3864 let candidate_strs: Vec<_> = candidates
3867 .iter()
3868 .map(|cand| {
3869 let cand_path = self.tcx.def_path_str(cand.def_id);
3870 let cand_params = &self.tcx.generics_of(cand.def_id).own_params;
3871 let cand_args: String = cand_params
3872 .iter()
3873 .skip(1)
3874 .filter_map(|param| match param.kind {
3875 ty::GenericParamDefKind::Type {
3876 has_default: true,
3877 ..
3878 }
3879 | ty::GenericParamDefKind::Const {
3880 has_default: true,
3881 ..
3882 } => None,
3883 _ => Some(param.name.as_str()),
3884 })
3885 .intersperse(", ")
3886 .collect();
3887 if cand_args.is_empty() {
3888 cand_path
3889 } else {
3890 applicability = Applicability::HasPlaceholders;
3891 format!("{cand_path}</* {cand_args} */>")
3892 }
3893 })
3894 .collect();
3895
3896 if rcvr_ty.is_ref()
3897 && param.is_impl_trait()
3898 && let Some((bounds_span, _)) = bounds_span
3899 {
3900 err.multipart_suggestions(
3901 msg,
3902 candidate_strs.iter().map(|cand| {
3903 vec![
3904 (param.span.shrink_to_lo(), "(".to_string()),
3905 (bounds_span, format!(" + {cand})")),
3906 ]
3907 }),
3908 applicability,
3909 );
3910 return;
3911 }
3912
3913 let (sp, introducer, open_paren_sp) =
3914 if let Some((span, open_paren_sp)) = bounds_span {
3915 (span, Introducer::Plus, open_paren_sp)
3916 } else if let Some(colon_span) = param.colon_span {
3917 (colon_span.shrink_to_hi(), Introducer::Nothing, None)
3918 } else if param.is_impl_trait() {
3919 (param.span.shrink_to_hi(), Introducer::Plus, None)
3920 } else {
3921 (param.span.shrink_to_hi(), Introducer::Colon, None)
3922 };
3923
3924 let all_suggs = candidate_strs.iter().map(|cand| {
3925 let suggestion = format!(
3926 "{} {cand}",
3927 match introducer {
3928 Introducer::Plus => " +",
3929 Introducer::Colon => ":",
3930 Introducer::Nothing => "",
3931 },
3932 );
3933
3934 let mut suggs = vec![];
3935
3936 if let Some(open_paren_sp) = open_paren_sp {
3937 suggs.push((open_paren_sp, "(".to_string()));
3938 suggs.push((sp, format!("){suggestion}")));
3939 } else {
3940 suggs.push((sp, suggestion));
3941 }
3942
3943 suggs
3944 });
3945
3946 err.multipart_suggestions(msg, all_suggs, applicability);
3947
3948 return;
3949 }
3950 Node::Item(hir::Item {
3951 kind: hir::ItemKind::Trait(.., bounds, _),
3952 ident,
3953 ..
3954 }) => {
3955 let (sp, sep, article) = if bounds.is_empty() {
3956 (ident.span.shrink_to_hi(), ":", "a")
3957 } else {
3958 (bounds.last().unwrap().span().shrink_to_hi(), " +", "another")
3959 };
3960 err.span_suggestions(
3961 sp,
3962 message(format!("add {article} supertrait for")),
3963 candidates.iter().map(|t| {
3964 format!("{} {}", sep, self.tcx.def_path_str(t.def_id),)
3965 }),
3966 Applicability::MaybeIncorrect,
3967 );
3968 return;
3969 }
3970 _ => {}
3971 }
3972 }
3973 }
3974
3975 let (potential_candidates, explicitly_negative) = if param_type.is_some() {
3976 (candidates, Vec::new())
3979 } else if let Some(simp_rcvr_ty) =
3980 simplify_type(self.tcx, rcvr_ty, TreatParams::AsRigid)
3981 {
3982 let mut potential_candidates = Vec::new();
3983 let mut explicitly_negative = Vec::new();
3984 for candidate in candidates {
3985 if self
3987 .tcx
3988 .all_impls(candidate.def_id)
3989 .map(|imp_did| {
3990 self.tcx.impl_trait_header(imp_did).expect(
3991 "inherent impls can't be candidates, only trait impls can be",
3992 )
3993 })
3994 .filter(|header| header.polarity != ty::ImplPolarity::Positive)
3995 .any(|header| {
3996 let imp = header.trait_ref.instantiate_identity();
3997 let imp_simp =
3998 simplify_type(self.tcx, imp.self_ty(), TreatParams::AsRigid);
3999 imp_simp.is_some_and(|s| s == simp_rcvr_ty)
4000 })
4001 {
4002 explicitly_negative.push(candidate);
4003 } else {
4004 potential_candidates.push(candidate);
4005 }
4006 }
4007 (potential_candidates, explicitly_negative)
4008 } else {
4009 (candidates, Vec::new())
4011 };
4012
4013 let impls_trait = |def_id: DefId| {
4014 let args = ty::GenericArgs::for_item(self.tcx, def_id, |param, _| {
4015 if param.index == 0 {
4016 rcvr_ty.into()
4017 } else {
4018 self.infcx.var_for_def(span, param)
4019 }
4020 });
4021 self.infcx
4022 .type_implements_trait(def_id, args, self.param_env)
4023 .must_apply_modulo_regions()
4024 && param_type.is_none()
4025 };
4026 match &potential_candidates[..] {
4027 [] => {}
4028 [trait_info] if trait_info.def_id.is_local() => {
4029 if impls_trait(trait_info.def_id) {
4030 self.suggest_valid_traits(err, item_name, vec![trait_info.def_id], false);
4031 } else {
4032 err.subdiagnostic(CandidateTraitNote {
4033 span: self.tcx.def_span(trait_info.def_id),
4034 trait_name: self.tcx.def_path_str(trait_info.def_id),
4035 item_name,
4036 action_or_ty: if trait_missing_method {
4037 "NONE".to_string()
4038 } else {
4039 param_type.map_or_else(
4040 || "implement".to_string(), |p| p.to_string(),
4042 )
4043 },
4044 });
4045 }
4046 }
4047 trait_infos => {
4048 let mut msg = message(param_type.map_or_else(
4049 || "implement".to_string(), |param| format!("restrict type parameter `{param}` with"),
4051 ));
4052 for (i, trait_info) in trait_infos.iter().enumerate() {
4053 if impls_trait(trait_info.def_id) {
4054 self.suggest_valid_traits(
4055 err,
4056 item_name,
4057 vec![trait_info.def_id],
4058 false,
4059 );
4060 }
4061 msg.push_str(&format!(
4062 "\ncandidate #{}: `{}`",
4063 i + 1,
4064 self.tcx.def_path_str(trait_info.def_id),
4065 ));
4066 }
4067 err.note(msg);
4068 }
4069 }
4070 match &explicitly_negative[..] {
4071 [] => {}
4072 [trait_info] => {
4073 let msg = format!(
4074 "the trait `{}` defines an item `{}`, but is explicitly unimplemented",
4075 self.tcx.def_path_str(trait_info.def_id),
4076 item_name
4077 );
4078 err.note(msg);
4079 }
4080 trait_infos => {
4081 let mut msg = format!(
4082 "the following traits define an item `{item_name}`, but are explicitly unimplemented:"
4083 );
4084 for trait_info in trait_infos {
4085 msg.push_str(&format!("\n{}", self.tcx.def_path_str(trait_info.def_id)));
4086 }
4087 err.note(msg);
4088 }
4089 }
4090 }
4091 }
4092
4093 fn detect_and_explain_multiple_crate_versions(
4094 &self,
4095 err: &mut Diag<'_>,
4096 item_def_id: DefId,
4097 hir_id: hir::HirId,
4098 rcvr_ty: Option<Ty<'_>>,
4099 ) -> bool {
4100 let hir_id = self.tcx.parent_hir_id(hir_id);
4101 let Some(traits) = self.tcx.in_scope_traits(hir_id) else { return false };
4102 if traits.is_empty() {
4103 return false;
4104 }
4105 let trait_def_id = self.tcx.parent(item_def_id);
4106 let krate = self.tcx.crate_name(trait_def_id.krate);
4107 let name = self.tcx.item_name(trait_def_id);
4108 let candidates: Vec<_> = traits
4109 .iter()
4110 .filter(|c| {
4111 c.def_id.krate != trait_def_id.krate
4112 && self.tcx.crate_name(c.def_id.krate) == krate
4113 && self.tcx.item_name(c.def_id) == name
4114 })
4115 .map(|c| (c.def_id, c.import_ids.get(0).cloned()))
4116 .collect();
4117 if candidates.is_empty() {
4118 return false;
4119 }
4120 let item_span = self.tcx.def_span(item_def_id);
4121 let msg = format!(
4122 "there are multiple different versions of crate `{krate}` in the dependency graph",
4123 );
4124 let trait_span = self.tcx.def_span(trait_def_id);
4125 let mut multi_span: MultiSpan = trait_span.into();
4126 multi_span.push_span_label(trait_span, format!("this is the trait that is needed"));
4127 let descr = self.tcx.associated_item(item_def_id).descr();
4128 let rcvr_ty =
4129 rcvr_ty.map(|t| format!("`{t}`")).unwrap_or_else(|| "the receiver".to_string());
4130 multi_span
4131 .push_span_label(item_span, format!("the {descr} is available for {rcvr_ty} here"));
4132 for (def_id, import_def_id) in candidates {
4133 if let Some(import_def_id) = import_def_id {
4134 multi_span.push_span_label(
4135 self.tcx.def_span(import_def_id),
4136 format!(
4137 "`{name}` imported here doesn't correspond to the right version of crate \
4138 `{krate}`",
4139 ),
4140 );
4141 }
4142 multi_span.push_span_label(
4143 self.tcx.def_span(def_id),
4144 format!("this is the trait that was imported"),
4145 );
4146 }
4147 err.span_note(multi_span, msg);
4148 true
4149 }
4150
4151 pub(crate) fn suggest_else_fn_with_closure(
4154 &self,
4155 err: &mut Diag<'_>,
4156 expr: &hir::Expr<'_>,
4157 found: Ty<'tcx>,
4158 expected: Ty<'tcx>,
4159 ) -> bool {
4160 let Some((_def_id_or_name, output, _inputs)) = self.extract_callable_info(found) else {
4161 return false;
4162 };
4163
4164 if !self.may_coerce(output, expected) {
4165 return false;
4166 }
4167
4168 if let Node::Expr(call_expr) = self.tcx.parent_hir_node(expr.hir_id)
4169 && let hir::ExprKind::MethodCall(
4170 hir::PathSegment { ident: method_name, .. },
4171 self_expr,
4172 args,
4173 ..,
4174 ) = call_expr.kind
4175 && let Some(self_ty) = self.typeck_results.borrow().expr_ty_opt(self_expr)
4176 {
4177 let new_name = Ident {
4178 name: Symbol::intern(&format!("{}_else", method_name.as_str())),
4179 span: method_name.span,
4180 };
4181 let probe = self.lookup_probe_for_diagnostic(
4182 new_name,
4183 self_ty,
4184 self_expr,
4185 ProbeScope::TraitsInScope,
4186 Some(expected),
4187 );
4188
4189 if let Ok(pick) = probe
4191 && let fn_sig = self.tcx.fn_sig(pick.item.def_id)
4192 && let fn_args = fn_sig.skip_binder().skip_binder().inputs()
4193 && fn_args.len() == args.len() + 1
4194 {
4195 err.span_suggestion_verbose(
4196 method_name.span.shrink_to_hi(),
4197 format!("try calling `{}` instead", new_name.name.as_str()),
4198 "_else",
4199 Applicability::MaybeIncorrect,
4200 );
4201 return true;
4202 }
4203 }
4204 false
4205 }
4206
4207 fn type_derefs_to_local(
4210 &self,
4211 span: Span,
4212 rcvr_ty: Ty<'tcx>,
4213 source: SelfSource<'tcx>,
4214 ) -> bool {
4215 fn is_local(ty: Ty<'_>) -> bool {
4216 match ty.kind() {
4217 ty::Adt(def, _) => def.did().is_local(),
4218 ty::Foreign(did) => did.is_local(),
4219 ty::Dynamic(tr, ..) => tr.principal().is_some_and(|d| d.def_id().is_local()),
4220 ty::Param(_) => true,
4221
4222 _ => false,
4227 }
4228 }
4229
4230 if let SelfSource::QPath(_) = source {
4233 return is_local(rcvr_ty);
4234 }
4235
4236 self.autoderef(span, rcvr_ty).silence_errors().any(|(ty, _)| is_local(ty))
4237 }
4238}
4239
4240#[derive(Copy, Clone, Debug)]
4241enum SelfSource<'a> {
4242 QPath(&'a hir::Ty<'a>),
4243 MethodCall(&'a hir::Expr<'a> ),
4244}
4245
4246#[derive(Copy, Clone, PartialEq, Eq)]
4247pub(crate) struct TraitInfo {
4248 pub def_id: DefId,
4249}
4250
4251pub(crate) fn all_traits(tcx: TyCtxt<'_>) -> Vec<TraitInfo> {
4254 tcx.all_traits().map(|def_id| TraitInfo { def_id }).collect()
4255}
4256
4257fn print_disambiguation_help<'tcx>(
4258 tcx: TyCtxt<'tcx>,
4259 err: &mut Diag<'_>,
4260 source: SelfSource<'tcx>,
4261 args: Option<&'tcx [hir::Expr<'tcx>]>,
4262 trait_ref: ty::TraitRef<'tcx>,
4263 candidate_idx: Option<usize>,
4264 span: Span,
4265 item: ty::AssocItem,
4266) -> Option<String> {
4267 let trait_impl_type = trait_ref.self_ty().peel_refs();
4268 let trait_ref = if item.fn_has_self_parameter {
4269 trait_ref.print_only_trait_name().to_string()
4270 } else {
4271 format!("<{} as {}>", trait_ref.args[0], trait_ref.print_only_trait_name())
4272 };
4273 Some(
4274 if matches!(item.kind, ty::AssocKind::Fn)
4275 && let SelfSource::MethodCall(receiver) = source
4276 && let Some(args) = args
4277 {
4278 let def_kind_descr = tcx.def_kind_descr(item.kind.as_def_kind(), item.def_id);
4279 let item_name = item.ident(tcx);
4280 let first_input =
4281 tcx.fn_sig(item.def_id).instantiate_identity().skip_binder().inputs().get(0);
4282 let (first_arg_type, rcvr_ref) = (
4283 first_input.map(|first| first.peel_refs()),
4284 first_input
4285 .and_then(|ty| ty.ref_mutability())
4286 .map_or("", |mutbl| mutbl.ref_prefix_str()),
4287 );
4288
4289 let args = if let Some(first_arg_type) = first_arg_type
4291 && (first_arg_type == tcx.types.self_param
4292 || first_arg_type == trait_impl_type
4293 || item.fn_has_self_parameter)
4294 {
4295 Some(receiver)
4296 } else {
4297 None
4298 }
4299 .into_iter()
4300 .chain(args)
4301 .map(|arg| {
4302 tcx.sess.source_map().span_to_snippet(arg.span).unwrap_or_else(|_| "_".to_owned())
4303 })
4304 .collect::<Vec<_>>()
4305 .join(", ");
4306
4307 let args = format!("({}{})", rcvr_ref, args);
4308 err.span_suggestion_verbose(
4309 span,
4310 format!(
4311 "disambiguate the {def_kind_descr} for {}",
4312 if let Some(candidate) = candidate_idx {
4313 format!("candidate #{candidate}")
4314 } else {
4315 "the candidate".to_string()
4316 },
4317 ),
4318 format!("{trait_ref}::{item_name}{args}"),
4319 Applicability::HasPlaceholders,
4320 );
4321 return None;
4322 } else {
4323 format!("{trait_ref}::")
4324 },
4325 )
4326}