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