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