1 //! Give useful errors and suggestions to users when an item can't be
2 //! found or is otherwise invalid.
3
4 use crate::errors;
5 use crate::errors::CandidateTraitNote;
6 use crate::errors::NoAssociatedItem;
7 use crate::Expectation;
8 use crate::FnCtxt;
9 use rustc_ast::ast::Mutability;
10 use rustc_data_structures::fx::{FxHashMap, FxHashSet};
11 use rustc_errors::StashKey;
12 use rustc_errors::{
13 pluralize, struct_span_err, Applicability, Diagnostic, DiagnosticBuilder, ErrorGuaranteed,
14 MultiSpan,
15 };
16 use rustc_hir as hir;
17 use rustc_hir::def::DefKind;
18 use rustc_hir::def_id::DefId;
19 use rustc_hir::lang_items::LangItem;
20 use rustc_hir::PatKind::Binding;
21 use rustc_hir::PathSegment;
22 use rustc_hir::{ExprKind, Node, QPath};
23 use rustc_infer::infer::{
24 type_variable::{TypeVariableOrigin, TypeVariableOriginKind},
25 RegionVariableOrigin,
26 };
27 use rustc_middle::infer::unify_key::{ConstVariableOrigin, ConstVariableOriginKind};
28 use rustc_middle::traits::util::supertraits;
29 use rustc_middle::ty::fast_reject::DeepRejectCtxt;
30 use rustc_middle::ty::fast_reject::{simplify_type, TreatParams};
31 use rustc_middle::ty::print::{with_crate_prefix, with_forced_trimmed_paths};
32 use rustc_middle::ty::IsSuggestable;
33 use rustc_middle::ty::{self, GenericArgKind, Ty, TyCtxt, TypeVisitableExt};
34 use rustc_span::symbol::{kw, sym, Ident};
35 use rustc_span::Symbol;
36 use rustc_span::{edit_distance, source_map, ExpnKind, FileName, MacroKind, Span};
37 use rustc_trait_selection::traits::error_reporting::on_unimplemented::OnUnimplementedNote;
38 use rustc_trait_selection::traits::error_reporting::on_unimplemented::TypeErrCtxtExt as _;
39 use rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt as _;
40 use rustc_trait_selection::traits::{
41 FulfillmentError, Obligation, ObligationCause, ObligationCauseCode,
42 };
43 use std::borrow::Cow;
44
45 use super::probe::{AutorefOrPtrAdjustment, IsSuggestion, Mode, ProbeScope};
46 use super::{CandidateSource, MethodError, NoMatchData};
47 use rustc_hir::intravisit::Visitor;
48 use std::cmp::{self, Ordering};
49 use std::iter;
50
51 impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
is_fn_ty(&self, ty: Ty<'tcx>, span: Span) -> bool52 fn is_fn_ty(&self, ty: Ty<'tcx>, span: Span) -> bool {
53 let tcx = self.tcx;
54 match ty.kind() {
55 // Not all of these (e.g., unsafe fns) implement `FnOnce`,
56 // so we look for these beforehand.
57 ty::Closure(..) | ty::FnDef(..) | ty::FnPtr(_) => true,
58 // If it's not a simple function, look for things which implement `FnOnce`.
59 _ => {
60 let Some(fn_once) = tcx.lang_items().fn_once_trait() else {
61 return false;
62 };
63
64 // This conditional prevents us from asking to call errors and unresolved types.
65 // It might seem that we can use `predicate_must_hold_modulo_regions`,
66 // but since a Dummy binder is used to fill in the FnOnce trait's arguments,
67 // type resolution always gives a "maybe" here.
68 if self.autoderef(span, ty).any(|(ty, _)| {
69 info!("check deref {:?} error", ty);
70 matches!(ty.kind(), ty::Error(_) | ty::Infer(_))
71 }) {
72 return false;
73 }
74
75 self.autoderef(span, ty).any(|(ty, _)| {
76 info!("check deref {:?} impl FnOnce", ty);
77 self.probe(|_| {
78 let trait_ref = ty::TraitRef::new(
79 tcx,
80 fn_once,
81 [
82 ty,
83 self.next_ty_var(TypeVariableOrigin {
84 kind: TypeVariableOriginKind::MiscVariable,
85 span,
86 }),
87 ],
88 );
89 let poly_trait_ref = ty::Binder::dummy(trait_ref);
90 let obligation = Obligation::misc(
91 tcx,
92 span,
93 self.body_id,
94 self.param_env,
95 poly_trait_ref.without_const(),
96 );
97 self.predicate_may_hold(&obligation)
98 })
99 })
100 }
101 }
102 }
103
is_slice_ty(&self, ty: Ty<'tcx>, span: Span) -> bool104 fn is_slice_ty(&self, ty: Ty<'tcx>, span: Span) -> bool {
105 self.autoderef(span, ty).any(|(ty, _)| matches!(ty.kind(), ty::Slice(..) | ty::Array(..)))
106 }
107
108 #[instrument(level = "debug", skip(self))]
report_method_error( &self, span: Span, rcvr_ty: Ty<'tcx>, item_name: Ident, source: SelfSource<'tcx>, error: MethodError<'tcx>, args: Option<(&'tcx hir::Expr<'tcx>, &'tcx [hir::Expr<'tcx>])>, expected: Expectation<'tcx>, trait_missing_method: bool, ) -> Option<DiagnosticBuilder<'_, ErrorGuaranteed>>109 pub fn report_method_error(
110 &self,
111 span: Span,
112 rcvr_ty: Ty<'tcx>,
113 item_name: Ident,
114 source: SelfSource<'tcx>,
115 error: MethodError<'tcx>,
116 args: Option<(&'tcx hir::Expr<'tcx>, &'tcx [hir::Expr<'tcx>])>,
117 expected: Expectation<'tcx>,
118 trait_missing_method: bool,
119 ) -> Option<DiagnosticBuilder<'_, ErrorGuaranteed>> {
120 // Avoid suggestions when we don't know what's going on.
121 if rcvr_ty.references_error() {
122 return None;
123 }
124
125 let sugg_span = if let SelfSource::MethodCall(expr) = source {
126 // Given `foo.bar(baz)`, `expr` is `bar`, but we want to point to the whole thing.
127 self.tcx.hir().expect_expr(self.tcx.hir().parent_id(expr.hir_id)).span
128 } else {
129 span
130 };
131
132 match error {
133 MethodError::NoMatch(mut no_match_data) => {
134 return self.report_no_match_method_error(
135 span,
136 rcvr_ty,
137 item_name,
138 source,
139 args,
140 sugg_span,
141 &mut no_match_data,
142 expected,
143 trait_missing_method,
144 );
145 }
146
147 MethodError::Ambiguity(mut sources) => {
148 let mut err = struct_span_err!(
149 self.sess(),
150 item_name.span,
151 E0034,
152 "multiple applicable items in scope"
153 );
154 err.span_label(item_name.span, format!("multiple `{}` found", item_name));
155
156 self.note_candidates_on_method_error(
157 rcvr_ty,
158 item_name,
159 args,
160 span,
161 &mut err,
162 &mut sources,
163 Some(sugg_span),
164 );
165 err.emit();
166 }
167
168 MethodError::PrivateMatch(kind, def_id, out_of_scope_traits) => {
169 let kind = self.tcx.def_kind_descr(kind, def_id);
170 let mut err = struct_span_err!(
171 self.tcx.sess,
172 item_name.span,
173 E0624,
174 "{} `{}` is private",
175 kind,
176 item_name
177 );
178 err.span_label(item_name.span, format!("private {}", kind));
179 let sp = self
180 .tcx
181 .hir()
182 .span_if_local(def_id)
183 .unwrap_or_else(|| self.tcx.def_span(def_id));
184 err.span_label(sp, format!("private {} defined here", kind));
185 self.suggest_valid_traits(&mut err, out_of_scope_traits);
186 err.emit();
187 }
188
189 MethodError::IllegalSizedBound { candidates, needs_mut, bound_span, self_expr } => {
190 let msg = if needs_mut {
191 with_forced_trimmed_paths!(format!(
192 "the `{item_name}` method cannot be invoked on `{rcvr_ty}`"
193 ))
194 } else {
195 format!("the `{item_name}` method cannot be invoked on a trait object")
196 };
197 let mut err = self.sess().struct_span_err(span, msg);
198 if !needs_mut {
199 err.span_label(bound_span, "this has a `Sized` requirement");
200 }
201 if !candidates.is_empty() {
202 let help = format!(
203 "{an}other candidate{s} {were} found in the following trait{s}, perhaps \
204 add a `use` for {one_of_them}:",
205 an = if candidates.len() == 1 { "an" } else { "" },
206 s = pluralize!(candidates.len()),
207 were = pluralize!("was", candidates.len()),
208 one_of_them = if candidates.len() == 1 { "it" } else { "one_of_them" },
209 );
210 self.suggest_use_candidates(&mut err, help, candidates);
211 }
212 if let ty::Ref(region, t_type, mutability) = rcvr_ty.kind() {
213 if needs_mut {
214 let trait_type = Ty::new_ref(
215 self.tcx,
216 *region,
217 ty::TypeAndMut { ty: *t_type, mutbl: mutability.invert() },
218 );
219 let msg = format!("you need `{}` instead of `{}`", trait_type, rcvr_ty);
220 let mut kind = &self_expr.kind;
221 while let hir::ExprKind::AddrOf(_, _, expr)
222 | hir::ExprKind::Unary(hir::UnOp::Deref, expr) = kind
223 {
224 kind = &expr.kind;
225 }
226 if let hir::ExprKind::Path(hir::QPath::Resolved(None, path)) = kind
227 && let hir::def::Res::Local(hir_id) = path.res
228 && let Some(hir::Node::Pat(b)) = self.tcx.hir().find(hir_id)
229 && let Some(hir::Node::Param(p)) = self.tcx.hir().find_parent(b.hir_id)
230 && let Some(node) = self.tcx.hir().find_parent(p.hir_id)
231 && let Some(decl) = node.fn_decl()
232 && let Some(ty) = decl.inputs.iter().find(|ty| ty.span == p.ty_span)
233 && let hir::TyKind::Ref(_, mut_ty) = &ty.kind
234 && let hir::Mutability::Not = mut_ty.mutbl
235 {
236 err.span_suggestion_verbose(
237 mut_ty.ty.span.shrink_to_lo(),
238 msg,
239 "mut ",
240 Applicability::MachineApplicable,
241 );
242 } else {
243 err.help(msg);
244 }
245 }
246 }
247 err.emit();
248 }
249
250 MethodError::BadReturnType => bug!("no return type expectations but got BadReturnType"),
251 }
252 None
253 }
254
suggest_missing_writer( &self, rcvr_ty: Ty<'tcx>, args: (&'tcx hir::Expr<'tcx>, &'tcx [hir::Expr<'tcx>]), ) -> DiagnosticBuilder<'_, ErrorGuaranteed>255 fn suggest_missing_writer(
256 &self,
257 rcvr_ty: Ty<'tcx>,
258 args: (&'tcx hir::Expr<'tcx>, &'tcx [hir::Expr<'tcx>]),
259 ) -> DiagnosticBuilder<'_, ErrorGuaranteed> {
260 let (ty_str, _ty_file) = self.tcx.short_ty_string(rcvr_ty);
261 let mut err =
262 struct_span_err!(self.tcx.sess, args.0.span, E0599, "cannot write into `{}`", ty_str);
263 err.span_note(
264 args.0.span,
265 "must implement `io::Write`, `fmt::Write`, or have a `write_fmt` method",
266 );
267 if let ExprKind::Lit(_) = args.0.kind {
268 err.span_help(
269 args.0.span.shrink_to_lo(),
270 "a writer is needed before this format string",
271 );
272 };
273
274 err
275 }
276
report_no_match_method_error( &self, mut span: Span, rcvr_ty: Ty<'tcx>, item_name: Ident, source: SelfSource<'tcx>, args: Option<(&'tcx hir::Expr<'tcx>, &'tcx [hir::Expr<'tcx>])>, sugg_span: Span, no_match_data: &mut NoMatchData<'tcx>, expected: Expectation<'tcx>, trait_missing_method: bool, ) -> Option<DiagnosticBuilder<'_, ErrorGuaranteed>>277 pub fn report_no_match_method_error(
278 &self,
279 mut span: Span,
280 rcvr_ty: Ty<'tcx>,
281 item_name: Ident,
282 source: SelfSource<'tcx>,
283 args: Option<(&'tcx hir::Expr<'tcx>, &'tcx [hir::Expr<'tcx>])>,
284 sugg_span: Span,
285 no_match_data: &mut NoMatchData<'tcx>,
286 expected: Expectation<'tcx>,
287 trait_missing_method: bool,
288 ) -> Option<DiagnosticBuilder<'_, ErrorGuaranteed>> {
289 let mode = no_match_data.mode;
290 let tcx = self.tcx;
291 let rcvr_ty = self.resolve_vars_if_possible(rcvr_ty);
292 let ((mut ty_str, ty_file), short_ty_str) = if trait_missing_method
293 && let ty::Dynamic(predicates, _, _) = rcvr_ty.kind() {
294 ((predicates.to_string(), None), with_forced_trimmed_paths!(predicates.to_string()))
295 } else {
296 (tcx.short_ty_string(rcvr_ty), with_forced_trimmed_paths!(rcvr_ty.to_string()))
297 };
298 let is_method = mode == Mode::MethodCall;
299 let unsatisfied_predicates = &no_match_data.unsatisfied_predicates;
300 let similar_candidate = no_match_data.similar_candidate;
301 let item_kind = if is_method {
302 "method"
303 } else if rcvr_ty.is_enum() {
304 "variant or associated item"
305 } else {
306 match (item_name.as_str().chars().next(), rcvr_ty.is_fresh_ty()) {
307 (Some(name), false) if name.is_lowercase() => "function or associated item",
308 (Some(_), false) => "associated item",
309 (Some(_), true) | (None, false) => "variant or associated item",
310 (None, true) => "variant",
311 }
312 };
313
314 // We could pass the file for long types into these two, but it isn't strictly necessary
315 // given how targeted they are.
316 if self.suggest_wrapping_range_with_parens(
317 tcx,
318 rcvr_ty,
319 source,
320 span,
321 item_name,
322 &short_ty_str,
323 ) || self.suggest_constraining_numerical_ty(
324 tcx,
325 rcvr_ty,
326 source,
327 span,
328 item_kind,
329 item_name,
330 &short_ty_str,
331 ) {
332 return None;
333 }
334 span = item_name.span;
335
336 // Don't show generic arguments when the method can't be found in any implementation (#81576).
337 let mut ty_str_reported = ty_str.clone();
338 if let ty::Adt(_, generics) = rcvr_ty.kind() {
339 if generics.len() > 0 {
340 let mut autoderef = self.autoderef(span, rcvr_ty);
341 let candidate_found = autoderef.any(|(ty, _)| {
342 if let ty::Adt(adt_def, _) = ty.kind() {
343 self.tcx
344 .inherent_impls(adt_def.did())
345 .iter()
346 .any(|def_id| self.associated_value(*def_id, item_name).is_some())
347 } else {
348 false
349 }
350 });
351 let has_deref = autoderef.step_count() > 0;
352 if !candidate_found && !has_deref && unsatisfied_predicates.is_empty() {
353 if let Some((path_string, _)) = ty_str.split_once('<') {
354 ty_str_reported = path_string.to_string();
355 }
356 }
357 }
358 }
359
360 let is_write = sugg_span.ctxt().outer_expn_data().macro_def_id.is_some_and(|def_id| {
361 tcx.is_diagnostic_item(sym::write_macro, def_id)
362 || tcx.is_diagnostic_item(sym::writeln_macro, def_id)
363 }) && item_name.name == Symbol::intern("write_fmt");
364 let mut err = if is_write
365 && let Some(args) = args
366 {
367 self.suggest_missing_writer(rcvr_ty, args)
368 } else {
369 tcx.sess.create_err(NoAssociatedItem {
370 span,
371 item_kind,
372 item_name,
373 ty_prefix: if trait_missing_method {
374 // FIXME(mu001999) E0599 maybe not suitable here because it is for types
375 Cow::from("trait")
376 } else {
377 rcvr_ty.prefix_string(self.tcx)
378 },
379 ty_str: ty_str_reported,
380 trait_missing_method,
381 })
382 };
383 if tcx.sess.source_map().is_multiline(sugg_span) {
384 err.span_label(sugg_span.with_hi(span.lo()), "");
385 }
386
387 if short_ty_str.len() < ty_str.len() && ty_str.len() > 10 {
388 ty_str = short_ty_str;
389 }
390
391 if let Some(file) = ty_file {
392 err.note(format!("the full type name has been written to '{}'", file.display(),));
393 }
394 if rcvr_ty.references_error() {
395 err.downgrade_to_delayed_bug();
396 }
397
398 if tcx.ty_is_opaque_future(rcvr_ty) && item_name.name == sym::poll {
399 err.help(format!(
400 "method `poll` found on `Pin<&mut {ty_str}>`, \
401 see documentation for `std::pin::Pin`"
402 ));
403 err.help("self type must be pinned to call `Future::poll`, \
404 see https://rust-lang.github.io/async-book/04_pinning/01_chapter.html#pinning-in-practice"
405 );
406 }
407
408 if let Mode::MethodCall = mode && let SelfSource::MethodCall(cal) = source {
409 self.suggest_await_before_method(
410 &mut err, item_name, rcvr_ty, cal, span, expected.only_has_type(self),
411 );
412 }
413 if let Some(span) =
414 tcx.resolutions(()).confused_type_with_std_module.get(&span.with_parent(None))
415 {
416 err.span_suggestion(
417 span.shrink_to_lo(),
418 "you are looking for the module in `std`, not the primitive type",
419 "std::",
420 Applicability::MachineApplicable,
421 );
422 }
423 if let ty::RawPtr(_) = &rcvr_ty.kind() {
424 err.note(
425 "try using `<*const T>::as_ref()` to get a reference to the \
426 type behind the pointer: https://doc.rust-lang.org/std/\
427 primitive.pointer.html#method.as_ref",
428 );
429 err.note(
430 "using `<*const T>::as_ref()` on a pointer which is unaligned or points \
431 to invalid or uninitialized memory is undefined behavior",
432 );
433 }
434
435 let ty_span = match rcvr_ty.kind() {
436 ty::Param(param_type) => {
437 Some(param_type.span_from_generics(self.tcx, self.body_id.to_def_id()))
438 }
439 ty::Adt(def, _) if def.did().is_local() => Some(tcx.def_span(def.did())),
440 _ => None,
441 };
442 if let Some(span) = ty_span {
443 err.span_label(
444 span,
445 format!(
446 "{item_kind} `{item_name}` not found for this {}",
447 rcvr_ty.prefix_string(self.tcx)
448 ),
449 );
450 }
451
452 if let SelfSource::MethodCall(rcvr_expr) = source {
453 self.suggest_fn_call(&mut err, rcvr_expr, rcvr_ty, |output_ty| {
454 let call_expr =
455 self.tcx.hir().expect_expr(self.tcx.hir().parent_id(rcvr_expr.hir_id));
456 let probe = self.lookup_probe_for_diagnostic(
457 item_name,
458 output_ty,
459 call_expr,
460 ProbeScope::AllTraits,
461 expected.only_has_type(self),
462 );
463 probe.is_ok()
464 });
465
466 self.note_internal_mutation_in_method(
467 &mut err,
468 rcvr_expr,
469 expected.to_option(&self),
470 rcvr_ty,
471 );
472 }
473
474 let mut custom_span_label = false;
475
476 let static_candidates = &mut no_match_data.static_candidates;
477
478 // `static_candidates` may have same candidates appended by
479 // inherent and extension, which may result in incorrect
480 // diagnostic.
481 static_candidates.dedup();
482
483 if !static_candidates.is_empty() {
484 err.note(
485 "found the following associated functions; to be used as methods, \
486 functions must have a `self` parameter",
487 );
488 err.span_label(span, "this is an associated function, not a method");
489 custom_span_label = true;
490 }
491 if static_candidates.len() == 1 {
492 self.suggest_associated_call_syntax(
493 &mut err,
494 &static_candidates,
495 rcvr_ty,
496 source,
497 item_name,
498 args,
499 sugg_span,
500 );
501 self.note_candidates_on_method_error(
502 rcvr_ty,
503 item_name,
504 args,
505 span,
506 &mut err,
507 static_candidates,
508 None,
509 );
510 } else if static_candidates.len() > 1 {
511 self.note_candidates_on_method_error(
512 rcvr_ty,
513 item_name,
514 args,
515 span,
516 &mut err,
517 static_candidates,
518 Some(sugg_span),
519 );
520 }
521
522 let mut bound_spans = vec![];
523 let mut restrict_type_params = false;
524 let mut unsatisfied_bounds = false;
525 if item_name.name == sym::count && self.is_slice_ty(rcvr_ty, span) {
526 let msg = "consider using `len` instead";
527 if let SelfSource::MethodCall(_expr) = source {
528 err.span_suggestion_short(span, msg, "len", Applicability::MachineApplicable);
529 } else {
530 err.span_label(span, msg);
531 }
532 if let Some(iterator_trait) = self.tcx.get_diagnostic_item(sym::Iterator) {
533 let iterator_trait = self.tcx.def_path_str(iterator_trait);
534 err.note(format!(
535 "`count` is defined on `{iterator_trait}`, which `{rcvr_ty}` does not implement"
536 ));
537 }
538 } else if !unsatisfied_predicates.is_empty() {
539 let mut type_params = FxHashMap::default();
540
541 // Pick out the list of unimplemented traits on the receiver.
542 // This is used for custom error messages with the `#[rustc_on_unimplemented]` attribute.
543 let mut unimplemented_traits = FxHashMap::default();
544 let mut unimplemented_traits_only = true;
545 for (predicate, _parent_pred, cause) in unsatisfied_predicates {
546 if let (ty::PredicateKind::Clause(ty::ClauseKind::Trait(p)), Some(cause)) =
547 (predicate.kind().skip_binder(), cause.as_ref())
548 {
549 if p.trait_ref.self_ty() != rcvr_ty {
550 // This is necessary, not just to keep the errors clean, but also
551 // because our derived obligations can wind up with a trait ref that
552 // requires a different param_env to be correctly compared.
553 continue;
554 }
555 unimplemented_traits.entry(p.trait_ref.def_id).or_insert((
556 predicate.kind().rebind(p.trait_ref),
557 Obligation {
558 cause: cause.clone(),
559 param_env: self.param_env,
560 predicate: *predicate,
561 recursion_depth: 0,
562 },
563 ));
564 }
565 }
566
567 // Make sure that, if any traits other than the found ones were involved,
568 // we don't don't report an unimplemented trait.
569 // We don't want to say that `iter::Cloned` is not an iterator, just
570 // because of some non-Clone item being iterated over.
571 for (predicate, _parent_pred, _cause) in unsatisfied_predicates {
572 match predicate.kind().skip_binder() {
573 ty::PredicateKind::Clause(ty::ClauseKind::Trait(p))
574 if unimplemented_traits.contains_key(&p.trait_ref.def_id) => {}
575 _ => {
576 unimplemented_traits_only = false;
577 break;
578 }
579 }
580 }
581
582 let mut collect_type_param_suggestions =
583 |self_ty: Ty<'tcx>, parent_pred: ty::Predicate<'tcx>, obligation: &str| {
584 // We don't care about regions here, so it's fine to skip the binder here.
585 if let (ty::Param(_), ty::PredicateKind::Clause(ty::ClauseKind::Trait(p))) =
586 (self_ty.kind(), parent_pred.kind().skip_binder())
587 {
588 let hir = self.tcx.hir();
589 let node = match p.trait_ref.self_ty().kind() {
590 ty::Param(_) => {
591 // Account for `fn` items like in `issue-35677.rs` to
592 // suggest restricting its type params.
593 Some(hir.get_by_def_id(self.body_id))
594 }
595 ty::Adt(def, _) => {
596 def.did().as_local().map(|def_id| hir.get_by_def_id(def_id))
597 }
598 _ => None,
599 };
600 if let Some(hir::Node::Item(hir::Item { kind, .. })) = node
601 && let Some(g) = kind.generics()
602 {
603 let key = (
604 g.tail_span_for_predicate_suggestion(),
605 g.add_where_or_trailing_comma(),
606 );
607 type_params
608 .entry(key)
609 .or_insert_with(FxHashSet::default)
610 .insert(obligation.to_owned());
611 return true;
612 }
613 }
614 false
615 };
616 let mut bound_span_label = |self_ty: Ty<'_>, obligation: &str, quiet: &str| {
617 let msg = format!(
618 "doesn't satisfy `{}`",
619 if obligation.len() > 50 { quiet } else { obligation }
620 );
621 match &self_ty.kind() {
622 // Point at the type that couldn't satisfy the bound.
623 ty::Adt(def, _) => bound_spans.push((self.tcx.def_span(def.did()), msg)),
624 // Point at the trait object that couldn't satisfy the bound.
625 ty::Dynamic(preds, _, _) => {
626 for pred in preds.iter() {
627 match pred.skip_binder() {
628 ty::ExistentialPredicate::Trait(tr) => {
629 bound_spans.push((self.tcx.def_span(tr.def_id), msg.clone()))
630 }
631 ty::ExistentialPredicate::Projection(_)
632 | ty::ExistentialPredicate::AutoTrait(_) => {}
633 }
634 }
635 }
636 // Point at the closure that couldn't satisfy the bound.
637 ty::Closure(def_id, _) => bound_spans
638 .push((tcx.def_span(*def_id), format!("doesn't satisfy `{}`", quiet))),
639 _ => {}
640 }
641 };
642 let mut format_pred = |pred: ty::Predicate<'tcx>| {
643 let bound_predicate = pred.kind();
644 match bound_predicate.skip_binder() {
645 ty::PredicateKind::Clause(ty::ClauseKind::Projection(pred)) => {
646 let pred = bound_predicate.rebind(pred);
647 // `<Foo as Iterator>::Item = String`.
648 let projection_ty = pred.skip_binder().projection_ty;
649
650 let substs_with_infer_self = tcx.mk_substs_from_iter(
651 iter::once(Ty::new_var(tcx, ty::TyVid::from_u32(0)).into())
652 .chain(projection_ty.substs.iter().skip(1)),
653 );
654
655 let quiet_projection_ty =
656 tcx.mk_alias_ty(projection_ty.def_id, substs_with_infer_self);
657
658 let term = pred.skip_binder().term;
659
660 let obligation = format!("{} = {}", projection_ty, term);
661 let quiet = with_forced_trimmed_paths!(format!(
662 "{} = {}",
663 quiet_projection_ty, term
664 ));
665
666 bound_span_label(projection_ty.self_ty(), &obligation, &quiet);
667 Some((obligation, projection_ty.self_ty()))
668 }
669 ty::PredicateKind::Clause(ty::ClauseKind::Trait(poly_trait_ref)) => {
670 let p = poly_trait_ref.trait_ref;
671 let self_ty = p.self_ty();
672 let path = p.print_only_trait_path();
673 let obligation = format!("{}: {}", self_ty, path);
674 let quiet = with_forced_trimmed_paths!(format!("_: {}", path));
675 bound_span_label(self_ty, &obligation, &quiet);
676 Some((obligation, self_ty))
677 }
678 _ => None,
679 }
680 };
681
682 // Find all the requirements that come from a local `impl` block.
683 let mut skip_list: FxHashSet<_> = Default::default();
684 let mut spanned_predicates = FxHashMap::default();
685 for (p, parent_p, cause) in unsatisfied_predicates {
686 // Extract the predicate span and parent def id of the cause,
687 // if we have one.
688 let (item_def_id, cause_span) = match cause.as_ref().map(|cause| cause.code()) {
689 Some(ObligationCauseCode::ImplDerivedObligation(data)) => {
690 (data.impl_or_alias_def_id, data.span)
691 }
692 Some(
693 ObligationCauseCode::ExprBindingObligation(def_id, span, _, _)
694 | ObligationCauseCode::BindingObligation(def_id, span),
695 ) => (*def_id, *span),
696 _ => continue,
697 };
698
699 // Don't point out the span of `WellFormed` predicates.
700 if !matches!(
701 p.kind().skip_binder(),
702 ty::PredicateKind::Clause(
703 ty::ClauseKind::Projection(..) | ty::ClauseKind::Trait(..)
704 )
705 ) {
706 continue;
707 };
708
709 match self.tcx.hir().get_if_local(item_def_id) {
710 // Unmet obligation comes from a `derive` macro, point at it once to
711 // avoid multiple span labels pointing at the same place.
712 Some(Node::Item(hir::Item {
713 kind: hir::ItemKind::Impl(hir::Impl { of_trait, self_ty, .. }),
714 ..
715 })) if matches!(
716 self_ty.span.ctxt().outer_expn_data().kind,
717 ExpnKind::Macro(MacroKind::Derive, _)
718 ) || matches!(
719 of_trait.as_ref().map(|t| t.path.span.ctxt().outer_expn_data().kind),
720 Some(ExpnKind::Macro(MacroKind::Derive, _))
721 ) =>
722 {
723 let span = self_ty.span.ctxt().outer_expn_data().call_site;
724 let entry = spanned_predicates.entry(span);
725 let entry = entry.or_insert_with(|| {
726 (FxHashSet::default(), FxHashSet::default(), Vec::new())
727 });
728 entry.0.insert(span);
729 entry.1.insert((
730 span,
731 "unsatisfied trait bound introduced in this `derive` macro",
732 ));
733 entry.2.push(p);
734 skip_list.insert(p);
735 }
736
737 // Unmet obligation coming from an `impl`.
738 Some(Node::Item(hir::Item {
739 kind: hir::ItemKind::Impl(hir::Impl { of_trait, self_ty, generics, .. }),
740 span: item_span,
741 ..
742 })) => {
743 let sized_pred =
744 unsatisfied_predicates.iter().any(|(pred, _, _)| {
745 match pred.kind().skip_binder() {
746 ty::PredicateKind::Clause(ty::ClauseKind::Trait(pred)) => {
747 Some(pred.def_id()) == self.tcx.lang_items().sized_trait()
748 && pred.polarity == ty::ImplPolarity::Positive
749 }
750 _ => false,
751 }
752 });
753 for param in generics.params {
754 if param.span == cause_span && sized_pred {
755 let (sp, sugg) = match param.colon_span {
756 Some(sp) => (sp.shrink_to_hi(), " ?Sized +"),
757 None => (param.span.shrink_to_hi(), ": ?Sized"),
758 };
759 err.span_suggestion_verbose(
760 sp,
761 "consider relaxing the type parameter's implicit `Sized` bound",
762 sugg,
763 Applicability::MachineApplicable,
764 );
765 }
766 }
767 if let Some(pred) = parent_p {
768 // Done to add the "doesn't satisfy" `span_label`.
769 let _ = format_pred(*pred);
770 }
771 skip_list.insert(p);
772 let entry = spanned_predicates.entry(self_ty.span);
773 let entry = entry.or_insert_with(|| {
774 (FxHashSet::default(), FxHashSet::default(), Vec::new())
775 });
776 entry.2.push(p);
777 if cause_span != *item_span {
778 entry.0.insert(cause_span);
779 entry.1.insert((cause_span, "unsatisfied trait bound introduced here"));
780 } else {
781 if let Some(trait_ref) = of_trait {
782 entry.0.insert(trait_ref.path.span);
783 }
784 entry.0.insert(self_ty.span);
785 };
786 if let Some(trait_ref) = of_trait {
787 entry.1.insert((trait_ref.path.span, ""));
788 }
789 entry.1.insert((self_ty.span, ""));
790 }
791 Some(Node::Item(hir::Item {
792 kind: hir::ItemKind::Trait(rustc_ast::ast::IsAuto::Yes, ..),
793 span: item_span,
794 ..
795 })) => {
796 tcx.sess.delay_span_bug(
797 *item_span,
798 "auto trait is invoked with no method error, but no error reported?",
799 );
800 }
801 Some(Node::Item(hir::Item {
802 ident,
803 kind: hir::ItemKind::Trait(..) | hir::ItemKind::TraitAlias(..),
804 ..
805 })) => {
806 skip_list.insert(p);
807 let entry = spanned_predicates.entry(ident.span);
808 let entry = entry.or_insert_with(|| {
809 (FxHashSet::default(), FxHashSet::default(), Vec::new())
810 });
811 entry.0.insert(cause_span);
812 entry.1.insert((ident.span, ""));
813 entry.1.insert((cause_span, "unsatisfied trait bound introduced here"));
814 entry.2.push(p);
815 }
816 Some(node) => unreachable!("encountered `{node:?}`"),
817 None => (),
818 }
819 }
820 let mut spanned_predicates: Vec<_> = spanned_predicates.into_iter().collect();
821 spanned_predicates.sort_by_key(|(span, _)| *span);
822 for (_, (primary_spans, span_labels, predicates)) in spanned_predicates {
823 let mut preds: Vec<_> = predicates
824 .iter()
825 .filter_map(|pred| format_pred(**pred))
826 .map(|(p, _)| format!("`{}`", p))
827 .collect();
828 preds.sort();
829 preds.dedup();
830 let msg = if let [pred] = &preds[..] {
831 format!("trait bound {} was not satisfied", pred)
832 } else {
833 format!("the following trait bounds were not satisfied:\n{}", preds.join("\n"),)
834 };
835 let mut span: MultiSpan = primary_spans.into_iter().collect::<Vec<_>>().into();
836 for (sp, label) in span_labels {
837 span.push_span_label(sp, label);
838 }
839 err.span_note(span, msg);
840 unsatisfied_bounds = true;
841 }
842
843 let mut suggested_bounds = FxHashSet::default();
844 // The requirements that didn't have an `impl` span to show.
845 let mut bound_list = unsatisfied_predicates
846 .iter()
847 .filter_map(|(pred, parent_pred, _cause)| {
848 let mut suggested = false;
849 format_pred(*pred).map(|(p, self_ty)| {
850 if let Some(parent) = parent_pred && suggested_bounds.contains(parent) {
851 // We don't suggest `PartialEq` when we already suggest `Eq`.
852 } else if !suggested_bounds.contains(pred) {
853 if collect_type_param_suggestions(self_ty, *pred, &p) {
854 suggested = true;
855 suggested_bounds.insert(pred);
856 }
857 }
858 (
859 match parent_pred {
860 None => format!("`{}`", &p),
861 Some(parent_pred) => match format_pred(*parent_pred) {
862 None => format!("`{}`", &p),
863 Some((parent_p, _)) => {
864 if !suggested
865 && !suggested_bounds.contains(pred)
866 && !suggested_bounds.contains(parent_pred)
867 {
868 if collect_type_param_suggestions(
869 self_ty,
870 *parent_pred,
871 &p,
872 ) {
873 suggested_bounds.insert(pred);
874 }
875 }
876 format!("`{}`\nwhich is required by `{}`", p, parent_p)
877 }
878 },
879 },
880 *pred,
881 )
882 })
883 })
884 .filter(|(_, pred)| !skip_list.contains(&pred))
885 .map(|(t, _)| t)
886 .enumerate()
887 .collect::<Vec<(usize, String)>>();
888
889 for ((span, add_where_or_comma), obligations) in type_params.into_iter() {
890 restrict_type_params = true;
891 // #74886: Sort here so that the output is always the same.
892 let mut obligations = obligations.into_iter().collect::<Vec<_>>();
893 obligations.sort();
894 err.span_suggestion_verbose(
895 span,
896 format!(
897 "consider restricting the type parameter{s} to satisfy the \
898 trait bound{s}",
899 s = pluralize!(obligations.len())
900 ),
901 format!("{} {}", add_where_or_comma, obligations.join(", ")),
902 Applicability::MaybeIncorrect,
903 );
904 }
905
906 bound_list.sort_by(|(_, a), (_, b)| a.cmp(b)); // Sort alphabetically.
907 bound_list.dedup_by(|(_, a), (_, b)| a == b); // #35677
908 bound_list.sort_by_key(|(pos, _)| *pos); // Keep the original predicate order.
909
910 if !bound_list.is_empty() || !skip_list.is_empty() {
911 let bound_list =
912 bound_list.into_iter().map(|(_, path)| path).collect::<Vec<_>>().join("\n");
913 let actual_prefix = rcvr_ty.prefix_string(self.tcx);
914 info!("unimplemented_traits.len() == {}", unimplemented_traits.len());
915 let (primary_message, label) = if unimplemented_traits.len() == 1
916 && unimplemented_traits_only
917 {
918 unimplemented_traits
919 .into_iter()
920 .next()
921 .map(|(_, (trait_ref, obligation))| {
922 if trait_ref.self_ty().references_error() || rcvr_ty.references_error()
923 {
924 // Avoid crashing.
925 return (None, None);
926 }
927 let OnUnimplementedNote { message, label, .. } =
928 self.err_ctxt().on_unimplemented_note(trait_ref, &obligation);
929 (message, label)
930 })
931 .unwrap()
932 } else {
933 (None, None)
934 };
935 let primary_message = primary_message.unwrap_or_else(|| {
936 format!(
937 "the {item_kind} `{item_name}` exists for {actual_prefix} `{ty_str}`, \
938 but its trait bounds were not satisfied"
939 )
940 });
941 err.set_primary_message(primary_message);
942 if let Some(label) = label {
943 custom_span_label = true;
944 err.span_label(span, label);
945 }
946 if !bound_list.is_empty() {
947 err.note(format!(
948 "the following trait bounds were not satisfied:\n{bound_list}"
949 ));
950 }
951 self.suggest_derive(&mut err, &unsatisfied_predicates);
952
953 unsatisfied_bounds = true;
954 }
955 }
956
957 let label_span_not_found = |err: &mut Diagnostic| {
958 if unsatisfied_predicates.is_empty() {
959 err.span_label(span, format!("{item_kind} not found in `{ty_str}`"));
960 let is_string_or_ref_str = match rcvr_ty.kind() {
961 ty::Ref(_, ty, _) => {
962 ty.is_str()
963 || matches!(
964 ty.kind(),
965 ty::Adt(adt, _) if Some(adt.did()) == self.tcx.lang_items().string()
966 )
967 }
968 ty::Adt(adt, _) => Some(adt.did()) == self.tcx.lang_items().string(),
969 _ => false,
970 };
971 if is_string_or_ref_str && item_name.name == sym::iter {
972 err.span_suggestion_verbose(
973 item_name.span,
974 "because of the in-memory representation of `&str`, to obtain \
975 an `Iterator` over each of its codepoint use method `chars`",
976 "chars",
977 Applicability::MachineApplicable,
978 );
979 }
980 if let ty::Adt(adt, _) = rcvr_ty.kind() {
981 let mut inherent_impls_candidate = self
982 .tcx
983 .inherent_impls(adt.did())
984 .iter()
985 .copied()
986 .filter(|def_id| {
987 if let Some(assoc) = self.associated_value(*def_id, item_name) {
988 // Check for both mode is the same so we avoid suggesting
989 // incorrect associated item.
990 match (mode, assoc.fn_has_self_parameter, source) {
991 (Mode::MethodCall, true, SelfSource::MethodCall(_)) => {
992 // We check that the suggest type is actually
993 // different from the received one
994 // So we avoid suggestion method with Box<Self>
995 // for instance
996 self.tcx.at(span).type_of(*def_id).subst_identity()
997 != rcvr_ty
998 && self.tcx.at(span).type_of(*def_id).subst_identity()
999 != rcvr_ty
1000 }
1001 (Mode::Path, false, _) => true,
1002 _ => false,
1003 }
1004 } else {
1005 false
1006 }
1007 })
1008 .collect::<Vec<_>>();
1009 if !inherent_impls_candidate.is_empty() {
1010 inherent_impls_candidate.sort();
1011 inherent_impls_candidate.dedup();
1012
1013 // number of type to shows at most.
1014 let limit = if inherent_impls_candidate.len() == 5 { 5 } else { 4 };
1015 let type_candidates = inherent_impls_candidate
1016 .iter()
1017 .take(limit)
1018 .map(|impl_item| {
1019 format!(
1020 "- `{}`",
1021 self.tcx.at(span).type_of(*impl_item).subst_identity()
1022 )
1023 })
1024 .collect::<Vec<_>>()
1025 .join("\n");
1026 let additional_types = if inherent_impls_candidate.len() > limit {
1027 format!("\nand {} more types", inherent_impls_candidate.len() - limit)
1028 } else {
1029 "".to_string()
1030 };
1031 err.note(format!(
1032 "the {item_kind} was found for\n{}{}",
1033 type_candidates, additional_types
1034 ));
1035 }
1036 }
1037 } else {
1038 let ty_str =
1039 if ty_str.len() > 50 { String::new() } else { format!("on `{ty_str}` ") };
1040 err.span_label(
1041 span,
1042 format!("{item_kind} cannot be called {ty_str}due to unsatisfied trait bounds"),
1043 );
1044 }
1045 };
1046
1047 // If the method name is the name of a field with a function or closure type,
1048 // give a helping note that it has to be called as `(x.f)(...)`.
1049 if let SelfSource::MethodCall(expr) = source {
1050 if !self.suggest_calling_field_as_fn(span, rcvr_ty, expr, item_name, &mut err)
1051 && similar_candidate.is_none()
1052 && !custom_span_label
1053 {
1054 label_span_not_found(&mut err);
1055 }
1056 } else if !custom_span_label {
1057 label_span_not_found(&mut err);
1058 }
1059
1060 // Don't suggest (for example) `expr.field.clone()` if `expr.clone()`
1061 // can't be called due to `typeof(expr): Clone` not holding.
1062 if unsatisfied_predicates.is_empty() {
1063 self.suggest_calling_method_on_field(
1064 &mut err,
1065 source,
1066 span,
1067 rcvr_ty,
1068 item_name,
1069 expected.only_has_type(self),
1070 );
1071 }
1072
1073 self.suggest_unwrapping_inner_self(&mut err, source, rcvr_ty, item_name);
1074
1075 bound_spans.sort();
1076 bound_spans.dedup();
1077 for (span, msg) in bound_spans.into_iter() {
1078 err.span_label(span, msg);
1079 }
1080
1081 if rcvr_ty.is_numeric() && rcvr_ty.is_fresh() || restrict_type_params {
1082 } else {
1083 self.suggest_traits_to_import(
1084 &mut err,
1085 span,
1086 rcvr_ty,
1087 item_name,
1088 args.map(|(_, args)| args.len() + 1),
1089 source,
1090 no_match_data.out_of_scope_traits.clone(),
1091 &unsatisfied_predicates,
1092 &static_candidates,
1093 unsatisfied_bounds,
1094 expected.only_has_type(self),
1095 trait_missing_method,
1096 );
1097 }
1098
1099 // Don't emit a suggestion if we found an actual method
1100 // that had unsatisfied trait bounds
1101 if unsatisfied_predicates.is_empty() && rcvr_ty.is_enum() {
1102 let adt_def = rcvr_ty.ty_adt_def().expect("enum is not an ADT");
1103 if let Some(suggestion) = edit_distance::find_best_match_for_name(
1104 &adt_def.variants().iter().map(|s| s.name).collect::<Vec<_>>(),
1105 item_name.name,
1106 None,
1107 ) {
1108 err.span_suggestion(
1109 span,
1110 "there is a variant with a similar name",
1111 suggestion,
1112 Applicability::MaybeIncorrect,
1113 );
1114 }
1115 }
1116
1117 if item_name.name == sym::as_str && rcvr_ty.peel_refs().is_str() {
1118 let msg = "remove this method call";
1119 let mut fallback_span = true;
1120 if let SelfSource::MethodCall(expr) = source {
1121 let call_expr = self.tcx.hir().expect_expr(self.tcx.hir().parent_id(expr.hir_id));
1122 if let Some(span) = call_expr.span.trim_start(expr.span) {
1123 err.span_suggestion(span, msg, "", Applicability::MachineApplicable);
1124 fallback_span = false;
1125 }
1126 }
1127 if fallback_span {
1128 err.span_label(span, msg);
1129 }
1130 } else if let Some(similar_candidate) = similar_candidate {
1131 // Don't emit a suggestion if we found an actual method
1132 // that had unsatisfied trait bounds
1133 if unsatisfied_predicates.is_empty() {
1134 let def_kind = similar_candidate.kind.as_def_kind();
1135 // Methods are defined within the context of a struct and their first parameter is always self,
1136 // which represents the instance of the struct the method is being called on
1137 // Associated functions don’t take self as a parameter and
1138 // they are not methods because they don’t have an instance of the struct to work with.
1139 if def_kind == DefKind::AssocFn && similar_candidate.fn_has_self_parameter {
1140 err.span_suggestion(
1141 span,
1142 "there is a method with a similar name",
1143 similar_candidate.name,
1144 Applicability::MaybeIncorrect,
1145 );
1146 } else {
1147 err.span_suggestion(
1148 span,
1149 format!(
1150 "there is {} {} with a similar name",
1151 self.tcx.def_kind_descr_article(def_kind, similar_candidate.def_id),
1152 self.tcx.def_kind_descr(def_kind, similar_candidate.def_id)
1153 ),
1154 similar_candidate.name,
1155 Applicability::MaybeIncorrect,
1156 );
1157 }
1158 }
1159 }
1160
1161 self.note_derefed_ty_has_method(&mut err, source, rcvr_ty, item_name, expected);
1162 return Some(err);
1163 }
1164
note_candidates_on_method_error( &self, rcvr_ty: Ty<'tcx>, item_name: Ident, args: Option<(&'tcx hir::Expr<'tcx>, &'tcx [hir::Expr<'tcx>])>, span: Span, err: &mut Diagnostic, sources: &mut Vec<CandidateSource>, sugg_span: Option<Span>, )1165 fn note_candidates_on_method_error(
1166 &self,
1167 rcvr_ty: Ty<'tcx>,
1168 item_name: Ident,
1169 args: Option<(&'tcx hir::Expr<'tcx>, &'tcx [hir::Expr<'tcx>])>,
1170 span: Span,
1171 err: &mut Diagnostic,
1172 sources: &mut Vec<CandidateSource>,
1173 sugg_span: Option<Span>,
1174 ) {
1175 sources.sort();
1176 sources.dedup();
1177 // Dynamic limit to avoid hiding just one candidate, which is silly.
1178 let limit = if sources.len() == 5 { 5 } else { 4 };
1179
1180 for (idx, source) in sources.iter().take(limit).enumerate() {
1181 match *source {
1182 CandidateSource::Impl(impl_did) => {
1183 // Provide the best span we can. Use the item, if local to crate, else
1184 // the impl, if local to crate (item may be defaulted), else nothing.
1185 let Some(item) = self.associated_value(impl_did, item_name).or_else(|| {
1186 let impl_trait_ref = self.tcx.impl_trait_ref(impl_did)?;
1187 self.associated_value(impl_trait_ref.skip_binder().def_id, item_name)
1188 }) else {
1189 continue;
1190 };
1191
1192 let note_span = if item.def_id.is_local() {
1193 Some(self.tcx.def_span(item.def_id))
1194 } else if impl_did.is_local() {
1195 Some(self.tcx.def_span(impl_did))
1196 } else {
1197 None
1198 };
1199
1200 let impl_ty = self.tcx.at(span).type_of(impl_did).subst_identity();
1201
1202 let insertion = match self.tcx.impl_trait_ref(impl_did) {
1203 None => String::new(),
1204 Some(trait_ref) => {
1205 format!(
1206 " of the trait `{}`",
1207 self.tcx.def_path_str(trait_ref.skip_binder().def_id)
1208 )
1209 }
1210 };
1211
1212 let (note_str, idx) = if sources.len() > 1 {
1213 (
1214 format!(
1215 "candidate #{} is defined in an impl{} for the type `{}`",
1216 idx + 1,
1217 insertion,
1218 impl_ty,
1219 ),
1220 Some(idx + 1),
1221 )
1222 } else {
1223 (
1224 format!(
1225 "the candidate is defined in an impl{} for the type `{}`",
1226 insertion, impl_ty,
1227 ),
1228 None,
1229 )
1230 };
1231 if let Some(note_span) = note_span {
1232 // We have a span pointing to the method. Show note with snippet.
1233 err.span_note(note_span, note_str);
1234 } else {
1235 err.note(note_str);
1236 }
1237 if let Some(sugg_span) = sugg_span
1238 && let Some(trait_ref) = self.tcx.impl_trait_ref(impl_did) {
1239 let path = self.tcx.def_path_str(trait_ref.skip_binder().def_id);
1240
1241 let ty = match item.kind {
1242 ty::AssocKind::Const | ty::AssocKind::Type => rcvr_ty,
1243 ty::AssocKind::Fn => self
1244 .tcx
1245 .fn_sig(item.def_id)
1246 .subst_identity()
1247 .inputs()
1248 .skip_binder()
1249 .get(0)
1250 .filter(|ty| ty.is_ref() && !rcvr_ty.is_ref())
1251 .copied()
1252 .unwrap_or(rcvr_ty),
1253 };
1254 print_disambiguation_help(
1255 item_name,
1256 args,
1257 err,
1258 path,
1259 ty,
1260 item.kind,
1261 self.tcx.def_kind_descr(item.kind.as_def_kind(), item.def_id),
1262 sugg_span,
1263 idx,
1264 self.tcx.sess.source_map(),
1265 item.fn_has_self_parameter,
1266 );
1267 }
1268 }
1269 CandidateSource::Trait(trait_did) => {
1270 let Some(item) = self.associated_value(trait_did, item_name) else { continue };
1271 let item_span = self.tcx.def_span(item.def_id);
1272 let idx = if sources.len() > 1 {
1273 let msg = format!(
1274 "candidate #{} is defined in the trait `{}`",
1275 idx + 1,
1276 self.tcx.def_path_str(trait_did)
1277 );
1278 err.span_note(item_span, msg);
1279 Some(idx + 1)
1280 } else {
1281 let msg = format!(
1282 "the candidate is defined in the trait `{}`",
1283 self.tcx.def_path_str(trait_did)
1284 );
1285 err.span_note(item_span, msg);
1286 None
1287 };
1288 if let Some(sugg_span) = sugg_span {
1289 let path = self.tcx.def_path_str(trait_did);
1290 print_disambiguation_help(
1291 item_name,
1292 args,
1293 err,
1294 path,
1295 rcvr_ty,
1296 item.kind,
1297 self.tcx.def_kind_descr(item.kind.as_def_kind(), item.def_id),
1298 sugg_span,
1299 idx,
1300 self.tcx.sess.source_map(),
1301 item.fn_has_self_parameter,
1302 );
1303 }
1304 }
1305 }
1306 }
1307 if sources.len() > limit {
1308 err.note(format!("and {} others", sources.len() - limit));
1309 }
1310 }
1311
1312 /// Suggest calling `Ty::method` if `.method()` isn't found because the method
1313 /// doesn't take a `self` receiver.
suggest_associated_call_syntax( &self, err: &mut Diagnostic, static_candidates: &Vec<CandidateSource>, rcvr_ty: Ty<'tcx>, source: SelfSource<'tcx>, item_name: Ident, args: Option<(&hir::Expr<'tcx>, &[hir::Expr<'tcx>])>, sugg_span: Span, )1314 fn suggest_associated_call_syntax(
1315 &self,
1316 err: &mut Diagnostic,
1317 static_candidates: &Vec<CandidateSource>,
1318 rcvr_ty: Ty<'tcx>,
1319 source: SelfSource<'tcx>,
1320 item_name: Ident,
1321 args: Option<(&hir::Expr<'tcx>, &[hir::Expr<'tcx>])>,
1322 sugg_span: Span,
1323 ) {
1324 let mut has_unsuggestable_args = false;
1325 let ty_str = if let Some(CandidateSource::Impl(impl_did)) = static_candidates.get(0) {
1326 // When the "method" is resolved through dereferencing, we really want the
1327 // original type that has the associated function for accurate suggestions.
1328 // (#61411)
1329 let impl_ty = self.tcx.type_of(*impl_did).subst_identity();
1330 let target_ty = self
1331 .autoderef(sugg_span, rcvr_ty)
1332 .find(|(rcvr_ty, _)| {
1333 DeepRejectCtxt { treat_obligation_params: TreatParams::AsCandidateKey }
1334 .types_may_unify(*rcvr_ty, impl_ty)
1335 })
1336 .map_or(impl_ty, |(ty, _)| ty)
1337 .peel_refs();
1338 if let ty::Adt(def, substs) = target_ty.kind() {
1339 // If there are any inferred arguments, (`{integer}`), we should replace
1340 // them with underscores to allow the compiler to infer them
1341 let infer_substs = self.tcx.mk_substs_from_iter(substs.into_iter().map(|arg| {
1342 if !arg.is_suggestable(self.tcx, true) {
1343 has_unsuggestable_args = true;
1344 match arg.unpack() {
1345 GenericArgKind::Lifetime(_) => self
1346 .next_region_var(RegionVariableOrigin::MiscVariable(
1347 rustc_span::DUMMY_SP,
1348 ))
1349 .into(),
1350 GenericArgKind::Type(_) => self
1351 .next_ty_var(TypeVariableOrigin {
1352 span: rustc_span::DUMMY_SP,
1353 kind: TypeVariableOriginKind::MiscVariable,
1354 })
1355 .into(),
1356 GenericArgKind::Const(arg) => self
1357 .next_const_var(
1358 arg.ty(),
1359 ConstVariableOrigin {
1360 span: rustc_span::DUMMY_SP,
1361 kind: ConstVariableOriginKind::MiscVariable,
1362 },
1363 )
1364 .into(),
1365 }
1366 } else {
1367 arg
1368 }
1369 }));
1370
1371 self.tcx.value_path_str_with_substs(def.did(), infer_substs)
1372 } else {
1373 self.ty_to_value_string(target_ty)
1374 }
1375 } else {
1376 self.ty_to_value_string(rcvr_ty.peel_refs())
1377 };
1378 if let SelfSource::MethodCall(_) = source {
1379 let first_arg = if let Some(CandidateSource::Impl(impl_did)) = static_candidates.get(0)
1380 && let Some(assoc) = self.associated_value(*impl_did, item_name)
1381 && assoc.kind == ty::AssocKind::Fn
1382 {
1383 let sig = self.tcx.fn_sig(assoc.def_id).subst_identity();
1384 sig.inputs().skip_binder().get(0).and_then(|first| if first.peel_refs() == rcvr_ty.peel_refs() {
1385 None
1386 } else {
1387 Some(first.ref_mutability().map_or("", |mutbl| mutbl.ref_prefix_str()))
1388 })
1389 } else {
1390 None
1391 };
1392 let mut applicability = Applicability::MachineApplicable;
1393 let args = if let Some((receiver, args)) = args {
1394 // The first arg is the same kind as the receiver
1395 let explicit_args = if first_arg.is_some() {
1396 std::iter::once(receiver).chain(args.iter()).collect::<Vec<_>>()
1397 } else {
1398 // There is no `Self` kind to infer the arguments from
1399 if has_unsuggestable_args {
1400 applicability = Applicability::HasPlaceholders;
1401 }
1402 args.iter().collect()
1403 };
1404 format!(
1405 "({}{})",
1406 first_arg.unwrap_or(""),
1407 explicit_args
1408 .iter()
1409 .map(|arg| self
1410 .tcx
1411 .sess
1412 .source_map()
1413 .span_to_snippet(arg.span)
1414 .unwrap_or_else(|_| {
1415 applicability = Applicability::HasPlaceholders;
1416 "_".to_owned()
1417 }))
1418 .collect::<Vec<_>>()
1419 .join(", "),
1420 )
1421 } else {
1422 applicability = Applicability::HasPlaceholders;
1423 "(...)".to_owned()
1424 };
1425 err.span_suggestion(
1426 sugg_span,
1427 "use associated function syntax instead",
1428 format!("{}::{}{}", ty_str, item_name, args),
1429 applicability,
1430 );
1431 } else {
1432 err.help(format!("try with `{}::{}`", ty_str, item_name,));
1433 }
1434 }
1435
1436 /// Suggest calling a field with a type that implements the `Fn*` traits instead of a method with
1437 /// the same name as the field i.e. `(a.my_fn_ptr)(10)` instead of `a.my_fn_ptr(10)`.
suggest_calling_field_as_fn( &self, span: Span, rcvr_ty: Ty<'tcx>, expr: &hir::Expr<'_>, item_name: Ident, err: &mut Diagnostic, ) -> bool1438 fn suggest_calling_field_as_fn(
1439 &self,
1440 span: Span,
1441 rcvr_ty: Ty<'tcx>,
1442 expr: &hir::Expr<'_>,
1443 item_name: Ident,
1444 err: &mut Diagnostic,
1445 ) -> bool {
1446 let tcx = self.tcx;
1447 let field_receiver = self.autoderef(span, rcvr_ty).find_map(|(ty, _)| match ty.kind() {
1448 ty::Adt(def, substs) if !def.is_enum() => {
1449 let variant = &def.non_enum_variant();
1450 tcx.find_field_index(item_name, variant).map(|index| {
1451 let field = &variant.fields[index];
1452 let field_ty = field.ty(tcx, substs);
1453 (field, field_ty)
1454 })
1455 }
1456 _ => None,
1457 });
1458 if let Some((field, field_ty)) = field_receiver {
1459 let scope = tcx.parent_module_from_def_id(self.body_id);
1460 let is_accessible = field.vis.is_accessible_from(scope, tcx);
1461
1462 if is_accessible {
1463 if self.is_fn_ty(field_ty, span) {
1464 let expr_span = expr.span.to(item_name.span);
1465 err.multipart_suggestion(
1466 format!(
1467 "to call the function stored in `{}`, \
1468 surround the field access with parentheses",
1469 item_name,
1470 ),
1471 vec![
1472 (expr_span.shrink_to_lo(), '('.to_string()),
1473 (expr_span.shrink_to_hi(), ')'.to_string()),
1474 ],
1475 Applicability::MachineApplicable,
1476 );
1477 } else {
1478 let call_expr = tcx.hir().expect_expr(tcx.hir().parent_id(expr.hir_id));
1479
1480 if let Some(span) = call_expr.span.trim_start(item_name.span) {
1481 err.span_suggestion(
1482 span,
1483 "remove the arguments",
1484 "",
1485 Applicability::MaybeIncorrect,
1486 );
1487 }
1488 }
1489 }
1490
1491 let field_kind = if is_accessible { "field" } else { "private field" };
1492 err.span_label(item_name.span, format!("{}, not a method", field_kind));
1493 return true;
1494 }
1495 false
1496 }
1497
1498 /// Suggest possible range with adding parentheses, for example:
1499 /// when encountering `0..1.map(|i| i + 1)` suggest `(0..1).map(|i| i + 1)`.
suggest_wrapping_range_with_parens( &self, tcx: TyCtxt<'tcx>, actual: Ty<'tcx>, source: SelfSource<'tcx>, span: Span, item_name: Ident, ty_str: &str, ) -> bool1500 fn suggest_wrapping_range_with_parens(
1501 &self,
1502 tcx: TyCtxt<'tcx>,
1503 actual: Ty<'tcx>,
1504 source: SelfSource<'tcx>,
1505 span: Span,
1506 item_name: Ident,
1507 ty_str: &str,
1508 ) -> bool {
1509 if let SelfSource::MethodCall(expr) = source {
1510 for (_, parent) in tcx.hir().parent_iter(expr.hir_id).take(5) {
1511 if let Node::Expr(parent_expr) = parent {
1512 let lang_item = match parent_expr.kind {
1513 ExprKind::Struct(ref qpath, _, _) => match **qpath {
1514 QPath::LangItem(LangItem::Range, ..) => Some(LangItem::Range),
1515 QPath::LangItem(LangItem::RangeTo, ..) => Some(LangItem::RangeTo),
1516 QPath::LangItem(LangItem::RangeToInclusive, ..) => {
1517 Some(LangItem::RangeToInclusive)
1518 }
1519 _ => None,
1520 },
1521 ExprKind::Call(ref func, _) => match func.kind {
1522 // `..=` desugars into `::std::ops::RangeInclusive::new(...)`.
1523 ExprKind::Path(QPath::LangItem(LangItem::RangeInclusiveNew, ..)) => {
1524 Some(LangItem::RangeInclusiveStruct)
1525 }
1526 _ => None,
1527 },
1528 _ => None,
1529 };
1530
1531 if lang_item.is_none() {
1532 continue;
1533 }
1534
1535 let span_included = match parent_expr.kind {
1536 hir::ExprKind::Struct(_, eps, _) => {
1537 eps.len() > 0 && eps.last().is_some_and(|ep| ep.span.contains(span))
1538 }
1539 // `..=` desugars into `::std::ops::RangeInclusive::new(...)`.
1540 hir::ExprKind::Call(ref func, ..) => func.span.contains(span),
1541 _ => false,
1542 };
1543
1544 if !span_included {
1545 continue;
1546 }
1547
1548 let range_def_id = self.tcx.require_lang_item(lang_item.unwrap(), None);
1549 let range_ty = self.tcx.type_of(range_def_id).subst(self.tcx, &[actual.into()]);
1550
1551 let pick = self.lookup_probe_for_diagnostic(
1552 item_name,
1553 range_ty,
1554 expr,
1555 ProbeScope::AllTraits,
1556 None,
1557 );
1558 if pick.is_ok() {
1559 let range_span = parent_expr.span.with_hi(expr.span.hi());
1560 tcx.sess.emit_err(errors::MissingParenthesesInRange {
1561 span,
1562 ty_str: ty_str.to_string(),
1563 method_name: item_name.as_str().to_string(),
1564 add_missing_parentheses: Some(errors::AddMissingParenthesesInRange {
1565 func_name: item_name.name.as_str().to_string(),
1566 left: range_span.shrink_to_lo(),
1567 right: range_span.shrink_to_hi(),
1568 }),
1569 });
1570 return true;
1571 }
1572 }
1573 }
1574 }
1575 false
1576 }
1577
suggest_constraining_numerical_ty( &self, tcx: TyCtxt<'tcx>, actual: Ty<'tcx>, source: SelfSource<'_>, span: Span, item_kind: &str, item_name: Ident, ty_str: &str, ) -> bool1578 fn suggest_constraining_numerical_ty(
1579 &self,
1580 tcx: TyCtxt<'tcx>,
1581 actual: Ty<'tcx>,
1582 source: SelfSource<'_>,
1583 span: Span,
1584 item_kind: &str,
1585 item_name: Ident,
1586 ty_str: &str,
1587 ) -> bool {
1588 let found_candidate = all_traits(self.tcx)
1589 .into_iter()
1590 .any(|info| self.associated_value(info.def_id, item_name).is_some());
1591 let found_assoc = |ty: Ty<'tcx>| {
1592 simplify_type(tcx, ty, TreatParams::AsCandidateKey)
1593 .and_then(|simp| {
1594 tcx.incoherent_impls(simp)
1595 .iter()
1596 .find_map(|&id| self.associated_value(id, item_name))
1597 })
1598 .is_some()
1599 };
1600 let found_candidate = found_candidate
1601 || found_assoc(tcx.types.i8)
1602 || found_assoc(tcx.types.i16)
1603 || found_assoc(tcx.types.i32)
1604 || found_assoc(tcx.types.i64)
1605 || found_assoc(tcx.types.i128)
1606 || found_assoc(tcx.types.u8)
1607 || found_assoc(tcx.types.u16)
1608 || found_assoc(tcx.types.u32)
1609 || found_assoc(tcx.types.u64)
1610 || found_assoc(tcx.types.u128)
1611 || found_assoc(tcx.types.f32)
1612 || found_assoc(tcx.types.f32);
1613 if found_candidate
1614 && actual.is_numeric()
1615 && !actual.has_concrete_skeleton()
1616 && let SelfSource::MethodCall(expr) = source
1617 {
1618 let mut err = struct_span_err!(
1619 tcx.sess,
1620 span,
1621 E0689,
1622 "can't call {} `{}` on ambiguous numeric type `{}`",
1623 item_kind,
1624 item_name,
1625 ty_str
1626 );
1627 let concrete_type = if actual.is_integral() { "i32" } else { "f32" };
1628 match expr.kind {
1629 ExprKind::Lit(ref lit) => {
1630 // numeric literal
1631 let snippet = tcx
1632 .sess
1633 .source_map()
1634 .span_to_snippet(lit.span)
1635 .unwrap_or_else(|_| "<numeric literal>".to_owned());
1636
1637 // If this is a floating point literal that ends with '.',
1638 // get rid of it to stop this from becoming a member access.
1639 let snippet = snippet.strip_suffix('.').unwrap_or(&snippet);
1640 err.span_suggestion(
1641 lit.span,
1642 format!(
1643 "you must specify a concrete type for this numeric value, \
1644 like `{}`",
1645 concrete_type
1646 ),
1647 format!("{snippet}_{concrete_type}"),
1648 Applicability::MaybeIncorrect,
1649 );
1650 }
1651 ExprKind::Path(QPath::Resolved(_, path)) => {
1652 // local binding
1653 if let hir::def::Res::Local(hir_id) = path.res {
1654 let span = tcx.hir().span(hir_id);
1655 let filename = tcx.sess.source_map().span_to_filename(span);
1656
1657 let parent_node =
1658 self.tcx.hir().get_parent(hir_id);
1659 let msg = format!(
1660 "you must specify a type for this binding, like `{}`",
1661 concrete_type,
1662 );
1663
1664 match (filename, parent_node) {
1665 (
1666 FileName::Real(_),
1667 Node::Local(hir::Local {
1668 source: hir::LocalSource::Normal,
1669 ty,
1670 ..
1671 }),
1672 ) => {
1673 let type_span = ty.map(|ty| ty.span.with_lo(span.hi())).unwrap_or(span.shrink_to_hi());
1674 err.span_suggestion(
1675 // account for `let x: _ = 42;`
1676 // ^^^
1677 type_span,
1678 msg,
1679 format!(": {concrete_type}"),
1680 Applicability::MaybeIncorrect,
1681 );
1682 }
1683 _ => {
1684 err.span_label(span, msg);
1685 }
1686 }
1687 }
1688 }
1689 _ => {}
1690 }
1691 err.emit();
1692 return true;
1693 }
1694 false
1695 }
1696
1697 /// For code `rect::area(...)`,
1698 /// if `rect` is a local variable and `area` is a valid assoc method for it,
1699 /// we try to suggest `rect.area()`
suggest_assoc_method_call(&self, segs: &[PathSegment<'_>])1700 pub(crate) fn suggest_assoc_method_call(&self, segs: &[PathSegment<'_>]) {
1701 debug!("suggest_assoc_method_call segs: {:?}", segs);
1702 let [seg1, seg2] = segs else { return; };
1703 let Some(mut diag) =
1704 self.tcx.sess.diagnostic().steal_diagnostic(seg1.ident.span, StashKey::CallAssocMethod)
1705 else { return };
1706
1707 let map = self.infcx.tcx.hir();
1708 let body_id = self.tcx.hir().body_owned_by(self.body_id);
1709 let body = map.body(body_id);
1710 struct LetVisitor<'a> {
1711 result: Option<&'a hir::Expr<'a>>,
1712 ident_name: Symbol,
1713 }
1714
1715 // FIXME: This really should be taking scoping, etc into account.
1716 impl<'v> Visitor<'v> for LetVisitor<'v> {
1717 fn visit_stmt(&mut self, ex: &'v hir::Stmt<'v>) {
1718 if let hir::StmtKind::Local(hir::Local { pat, init, .. }) = &ex.kind
1719 && let Binding(_, _, ident, ..) = pat.kind
1720 && ident.name == self.ident_name
1721 {
1722 self.result = *init;
1723 } else {
1724 hir::intravisit::walk_stmt(self, ex);
1725 }
1726 }
1727 }
1728
1729 let mut visitor = LetVisitor { result: None, ident_name: seg1.ident.name };
1730 visitor.visit_body(&body);
1731
1732 let parent = self.tcx.hir().parent_id(seg1.hir_id);
1733 if let Some(Node::Expr(call_expr)) = self.tcx.hir().find(parent)
1734 && let Some(expr) = visitor.result
1735 && let Some(self_ty) = self.node_ty_opt(expr.hir_id)
1736 {
1737 let probe = self.lookup_probe_for_diagnostic(
1738 seg2.ident,
1739 self_ty,
1740 call_expr,
1741 ProbeScope::TraitsInScope,
1742 None,
1743 );
1744 if probe.is_ok() {
1745 let sm = self.infcx.tcx.sess.source_map();
1746 diag.span_suggestion_verbose(
1747 sm.span_extend_while(seg1.ident.span.shrink_to_hi(), |c| c == ':').unwrap(),
1748 "you may have meant to call an instance method",
1749 ".".to_string(),
1750 Applicability::MaybeIncorrect,
1751 );
1752 }
1753 }
1754 diag.emit();
1755 }
1756
1757 /// Suggest calling a method on a field i.e. `a.field.bar()` instead of `a.bar()`
suggest_calling_method_on_field( &self, err: &mut Diagnostic, source: SelfSource<'tcx>, span: Span, actual: Ty<'tcx>, item_name: Ident, return_type: Option<Ty<'tcx>>, )1758 fn suggest_calling_method_on_field(
1759 &self,
1760 err: &mut Diagnostic,
1761 source: SelfSource<'tcx>,
1762 span: Span,
1763 actual: Ty<'tcx>,
1764 item_name: Ident,
1765 return_type: Option<Ty<'tcx>>,
1766 ) {
1767 if let SelfSource::MethodCall(expr) = source
1768 && let mod_id = self.tcx.parent_module(expr.hir_id).to_def_id()
1769 && let Some((fields, substs)) =
1770 self.get_field_candidates_considering_privacy(span, actual, mod_id)
1771 {
1772 let call_expr = self.tcx.hir().expect_expr(self.tcx.hir().parent_id(expr.hir_id));
1773
1774 let lang_items = self.tcx.lang_items();
1775 let never_mention_traits = [
1776 lang_items.clone_trait(),
1777 lang_items.deref_trait(),
1778 lang_items.deref_mut_trait(),
1779 self.tcx.get_diagnostic_item(sym::AsRef),
1780 self.tcx.get_diagnostic_item(sym::AsMut),
1781 self.tcx.get_diagnostic_item(sym::Borrow),
1782 self.tcx.get_diagnostic_item(sym::BorrowMut),
1783 ];
1784 let candidate_fields: Vec<_> = fields
1785 .filter_map(|candidate_field| {
1786 self.check_for_nested_field_satisfying(
1787 span,
1788 &|_, field_ty| {
1789 self.lookup_probe_for_diagnostic(
1790 item_name,
1791 field_ty,
1792 call_expr,
1793 ProbeScope::TraitsInScope,
1794 return_type,
1795 )
1796 .is_ok_and(|pick| {
1797 !never_mention_traits
1798 .iter()
1799 .flatten()
1800 .any(|def_id| self.tcx.parent(pick.item.def_id) == *def_id)
1801 })
1802 },
1803 candidate_field,
1804 substs,
1805 vec![],
1806 mod_id,
1807 )
1808 })
1809 .map(|field_path| {
1810 field_path
1811 .iter()
1812 .map(|id| id.name.to_ident_string())
1813 .collect::<Vec<String>>()
1814 .join(".")
1815 })
1816 .collect();
1817
1818 let len = candidate_fields.len();
1819 if len > 0 {
1820 err.span_suggestions(
1821 item_name.span.shrink_to_lo(),
1822 format!(
1823 "{} of the expressions' fields {} a method of the same name",
1824 if len > 1 { "some" } else { "one" },
1825 if len > 1 { "have" } else { "has" },
1826 ),
1827 candidate_fields.iter().map(|path| format!("{path}.")),
1828 Applicability::MaybeIncorrect,
1829 );
1830 }
1831 }
1832 }
1833
suggest_unwrapping_inner_self( &self, err: &mut Diagnostic, source: SelfSource<'tcx>, actual: Ty<'tcx>, item_name: Ident, )1834 fn suggest_unwrapping_inner_self(
1835 &self,
1836 err: &mut Diagnostic,
1837 source: SelfSource<'tcx>,
1838 actual: Ty<'tcx>,
1839 item_name: Ident,
1840 ) {
1841 let tcx = self.tcx;
1842 let SelfSource::MethodCall(expr) = source else { return; };
1843 let call_expr = tcx.hir().expect_expr(tcx.hir().parent_id(expr.hir_id));
1844
1845 let ty::Adt(kind, substs) = actual.kind() else { return; };
1846 match kind.adt_kind() {
1847 ty::AdtKind::Enum => {
1848 let matching_variants: Vec<_> = kind
1849 .variants()
1850 .iter()
1851 .flat_map(|variant| {
1852 let [field] = &variant.fields.raw[..] else { return None; };
1853 let field_ty = field.ty(tcx, substs);
1854
1855 // Skip `_`, since that'll just lead to ambiguity.
1856 if self.resolve_vars_if_possible(field_ty).is_ty_var() {
1857 return None;
1858 }
1859
1860 self.lookup_probe_for_diagnostic(
1861 item_name,
1862 field_ty,
1863 call_expr,
1864 ProbeScope::TraitsInScope,
1865 None,
1866 )
1867 .ok()
1868 .map(|pick| (variant, field, pick))
1869 })
1870 .collect();
1871
1872 let ret_ty_matches = |diagnostic_item| {
1873 if let Some(ret_ty) = self
1874 .ret_coercion
1875 .as_ref()
1876 .map(|c| self.resolve_vars_if_possible(c.borrow().expected_ty()))
1877 && let ty::Adt(kind, _) = ret_ty.kind()
1878 && tcx.get_diagnostic_item(diagnostic_item) == Some(kind.did())
1879 {
1880 true
1881 } else {
1882 false
1883 }
1884 };
1885
1886 match &matching_variants[..] {
1887 [(_, field, pick)] => {
1888 let self_ty = field.ty(tcx, substs);
1889 err.span_note(
1890 tcx.def_span(pick.item.def_id),
1891 format!("the method `{item_name}` exists on the type `{self_ty}`"),
1892 );
1893 let (article, kind, variant, question) =
1894 if tcx.is_diagnostic_item(sym::Result, kind.did()) {
1895 ("a", "Result", "Err", ret_ty_matches(sym::Result))
1896 } else if tcx.is_diagnostic_item(sym::Option, kind.did()) {
1897 ("an", "Option", "None", ret_ty_matches(sym::Option))
1898 } else {
1899 return;
1900 };
1901 if question {
1902 err.span_suggestion_verbose(
1903 expr.span.shrink_to_hi(),
1904 format!(
1905 "use the `?` operator to extract the `{self_ty}` value, propagating \
1906 {article} `{kind}::{variant}` value to the caller"
1907 ),
1908 "?",
1909 Applicability::MachineApplicable,
1910 );
1911 } else {
1912 err.span_suggestion_verbose(
1913 expr.span.shrink_to_hi(),
1914 format!(
1915 "consider using `{kind}::expect` to unwrap the `{self_ty}` value, \
1916 panicking if the value is {article} `{kind}::{variant}`"
1917 ),
1918 ".expect(\"REASON\")",
1919 Applicability::HasPlaceholders,
1920 );
1921 }
1922 }
1923 // FIXME(compiler-errors): Support suggestions for other matching enum variants
1924 _ => {}
1925 }
1926 }
1927 // Target wrapper types - types that wrap or pretend to wrap another type,
1928 // perhaps this inner type is meant to be called?
1929 ty::AdtKind::Struct | ty::AdtKind::Union => {
1930 let [first] = ***substs else { return; };
1931 let ty::GenericArgKind::Type(ty) = first.unpack() else { return; };
1932 let Ok(pick) = self.lookup_probe_for_diagnostic(
1933 item_name,
1934 ty,
1935 call_expr,
1936 ProbeScope::TraitsInScope,
1937 None,
1938 ) else { return; };
1939
1940 let name = self.ty_to_value_string(actual);
1941 let inner_id = kind.did();
1942 let mutable = if let Some(AutorefOrPtrAdjustment::Autoref { mutbl, .. }) =
1943 pick.autoref_or_ptr_adjustment
1944 {
1945 Some(mutbl)
1946 } else {
1947 None
1948 };
1949
1950 if tcx.is_diagnostic_item(sym::LocalKey, inner_id) {
1951 err.help("use `with` or `try_with` to access thread local storage");
1952 } else if Some(kind.did()) == tcx.lang_items().maybe_uninit() {
1953 err.help(format!(
1954 "if this `{name}` has been initialized, \
1955 use one of the `assume_init` methods to access the inner value"
1956 ));
1957 } else if tcx.is_diagnostic_item(sym::RefCell, inner_id) {
1958 let (suggestion, borrow_kind, panic_if) = match mutable {
1959 Some(Mutability::Not) => (".borrow()", "borrow", "a mutable borrow exists"),
1960 Some(Mutability::Mut) => {
1961 (".borrow_mut()", "mutably borrow", "any borrows exist")
1962 }
1963 None => return,
1964 };
1965 err.span_suggestion_verbose(
1966 expr.span.shrink_to_hi(),
1967 format!(
1968 "use `{suggestion}` to {borrow_kind} the `{ty}`, \
1969 panicking if {panic_if}"
1970 ),
1971 suggestion,
1972 Applicability::MaybeIncorrect,
1973 );
1974 } else if tcx.is_diagnostic_item(sym::Mutex, inner_id) {
1975 err.span_suggestion_verbose(
1976 expr.span.shrink_to_hi(),
1977 format!(
1978 "use `.lock().unwrap()` to borrow the `{ty}`, \
1979 blocking the current thread until it can be acquired"
1980 ),
1981 ".lock().unwrap()",
1982 Applicability::MaybeIncorrect,
1983 );
1984 } else if tcx.is_diagnostic_item(sym::RwLock, inner_id) {
1985 let (suggestion, borrow_kind) = match mutable {
1986 Some(Mutability::Not) => (".read().unwrap()", "borrow"),
1987 Some(Mutability::Mut) => (".write().unwrap()", "mutably borrow"),
1988 None => return,
1989 };
1990 err.span_suggestion_verbose(
1991 expr.span.shrink_to_hi(),
1992 format!(
1993 "use `{suggestion}` to {borrow_kind} the `{ty}`, \
1994 blocking the current thread until it can be acquired"
1995 ),
1996 suggestion,
1997 Applicability::MaybeIncorrect,
1998 );
1999 } else {
2000 return;
2001 };
2002
2003 err.span_note(
2004 tcx.def_span(pick.item.def_id),
2005 format!("the method `{item_name}` exists on the type `{ty}`"),
2006 );
2007 }
2008 }
2009 }
2010
note_unmet_impls_on_type( &self, err: &mut Diagnostic, errors: Vec<FulfillmentError<'tcx>>, )2011 pub(crate) fn note_unmet_impls_on_type(
2012 &self,
2013 err: &mut Diagnostic,
2014 errors: Vec<FulfillmentError<'tcx>>,
2015 ) {
2016 let all_local_types_needing_impls =
2017 errors.iter().all(|e| match e.obligation.predicate.kind().skip_binder() {
2018 ty::PredicateKind::Clause(ty::ClauseKind::Trait(pred)) => {
2019 match pred.self_ty().kind() {
2020 ty::Adt(def, _) => def.did().is_local(),
2021 _ => false,
2022 }
2023 }
2024 _ => false,
2025 });
2026 let mut preds: Vec<_> = errors
2027 .iter()
2028 .filter_map(|e| match e.obligation.predicate.kind().skip_binder() {
2029 ty::PredicateKind::Clause(ty::ClauseKind::Trait(pred)) => Some(pred),
2030 _ => None,
2031 })
2032 .collect();
2033 preds.sort_by_key(|pred| (pred.def_id(), pred.self_ty()));
2034 let def_ids = preds
2035 .iter()
2036 .filter_map(|pred| match pred.self_ty().kind() {
2037 ty::Adt(def, _) => Some(def.did()),
2038 _ => None,
2039 })
2040 .collect::<FxHashSet<_>>();
2041 let mut spans: MultiSpan = def_ids
2042 .iter()
2043 .filter_map(|def_id| {
2044 let span = self.tcx.def_span(*def_id);
2045 if span.is_dummy() { None } else { Some(span) }
2046 })
2047 .collect::<Vec<_>>()
2048 .into();
2049
2050 for pred in &preds {
2051 match pred.self_ty().kind() {
2052 ty::Adt(def, _) if def.did().is_local() => {
2053 spans.push_span_label(
2054 self.tcx.def_span(def.did()),
2055 format!("must implement `{}`", pred.trait_ref.print_only_trait_path()),
2056 );
2057 }
2058 _ => {}
2059 }
2060 }
2061
2062 if all_local_types_needing_impls && spans.primary_span().is_some() {
2063 let msg = if preds.len() == 1 {
2064 format!(
2065 "an implementation of `{}` might be missing for `{}`",
2066 preds[0].trait_ref.print_only_trait_path(),
2067 preds[0].self_ty()
2068 )
2069 } else {
2070 format!(
2071 "the following type{} would have to `impl` {} required trait{} for this \
2072 operation to be valid",
2073 pluralize!(def_ids.len()),
2074 if def_ids.len() == 1 { "its" } else { "their" },
2075 pluralize!(preds.len()),
2076 )
2077 };
2078 err.span_note(spans, msg);
2079 }
2080
2081 let preds: Vec<_> = errors
2082 .iter()
2083 .map(|e| (e.obligation.predicate, None, Some(e.obligation.cause.clone())))
2084 .collect();
2085 self.suggest_derive(err, &preds);
2086 }
2087
suggest_derive( &self, err: &mut Diagnostic, unsatisfied_predicates: &[( ty::Predicate<'tcx>, Option<ty::Predicate<'tcx>>, Option<ObligationCause<'tcx>>, )], )2088 pub fn suggest_derive(
2089 &self,
2090 err: &mut Diagnostic,
2091 unsatisfied_predicates: &[(
2092 ty::Predicate<'tcx>,
2093 Option<ty::Predicate<'tcx>>,
2094 Option<ObligationCause<'tcx>>,
2095 )],
2096 ) {
2097 let mut derives = Vec::<(String, Span, Symbol)>::new();
2098 let mut traits = Vec::new();
2099 for (pred, _, _) in unsatisfied_predicates {
2100 let Some(ty::PredicateKind::Clause(ty::ClauseKind::Trait(trait_pred))) =
2101 pred.kind().no_bound_vars()
2102 else {
2103 continue
2104 };
2105 let adt = match trait_pred.self_ty().ty_adt_def() {
2106 Some(adt) if adt.did().is_local() => adt,
2107 _ => continue,
2108 };
2109 if let Some(diagnostic_name) = self.tcx.get_diagnostic_name(trait_pred.def_id()) {
2110 let can_derive = match diagnostic_name {
2111 sym::Default => !adt.is_enum(),
2112 sym::Eq
2113 | sym::PartialEq
2114 | sym::Ord
2115 | sym::PartialOrd
2116 | sym::Clone
2117 | sym::Copy
2118 | sym::Hash
2119 | sym::Debug => true,
2120 _ => false,
2121 };
2122 if can_derive {
2123 let self_name = trait_pred.self_ty().to_string();
2124 let self_span = self.tcx.def_span(adt.did());
2125 for super_trait in
2126 supertraits(self.tcx, ty::Binder::dummy(trait_pred.trait_ref))
2127 {
2128 if let Some(parent_diagnostic_name) =
2129 self.tcx.get_diagnostic_name(super_trait.def_id())
2130 {
2131 derives.push((self_name.clone(), self_span, parent_diagnostic_name));
2132 }
2133 }
2134 derives.push((self_name, self_span, diagnostic_name));
2135 } else {
2136 traits.push(trait_pred.def_id());
2137 }
2138 } else {
2139 traits.push(trait_pred.def_id());
2140 }
2141 }
2142 traits.sort();
2143 traits.dedup();
2144
2145 derives.sort();
2146 derives.dedup();
2147
2148 let mut derives_grouped = Vec::<(String, Span, String)>::new();
2149 for (self_name, self_span, trait_name) in derives.into_iter() {
2150 if let Some((last_self_name, _, ref mut last_trait_names)) = derives_grouped.last_mut()
2151 {
2152 if last_self_name == &self_name {
2153 last_trait_names.push_str(format!(", {}", trait_name).as_str());
2154 continue;
2155 }
2156 }
2157 derives_grouped.push((self_name, self_span, trait_name.to_string()));
2158 }
2159
2160 let len = traits.len();
2161 if len > 0 {
2162 let span =
2163 MultiSpan::from_spans(traits.iter().map(|&did| self.tcx.def_span(did)).collect());
2164 let mut names = format!("`{}`", self.tcx.def_path_str(traits[0]));
2165 for (i, &did) in traits.iter().enumerate().skip(1) {
2166 if len > 2 {
2167 names.push_str(", ");
2168 }
2169 if i == len - 1 {
2170 names.push_str(" and ");
2171 }
2172 names.push('`');
2173 names.push_str(&self.tcx.def_path_str(did));
2174 names.push('`');
2175 }
2176 err.span_note(
2177 span,
2178 format!("the trait{} {} must be implemented", pluralize!(len), names),
2179 );
2180 }
2181
2182 for (self_name, self_span, traits) in &derives_grouped {
2183 err.span_suggestion_verbose(
2184 self_span.shrink_to_lo(),
2185 format!("consider annotating `{}` with `#[derive({})]`", self_name, traits),
2186 format!("#[derive({})]\n", traits),
2187 Applicability::MaybeIncorrect,
2188 );
2189 }
2190 }
2191
note_derefed_ty_has_method( &self, err: &mut Diagnostic, self_source: SelfSource<'tcx>, rcvr_ty: Ty<'tcx>, item_name: Ident, expected: Expectation<'tcx>, )2192 fn note_derefed_ty_has_method(
2193 &self,
2194 err: &mut Diagnostic,
2195 self_source: SelfSource<'tcx>,
2196 rcvr_ty: Ty<'tcx>,
2197 item_name: Ident,
2198 expected: Expectation<'tcx>,
2199 ) {
2200 let SelfSource::QPath(ty) = self_source else { return; };
2201 for (deref_ty, _) in self.autoderef(rustc_span::DUMMY_SP, rcvr_ty).skip(1) {
2202 if let Ok(pick) = self.probe_for_name(
2203 Mode::Path,
2204 item_name,
2205 expected.only_has_type(self),
2206 IsSuggestion(true),
2207 deref_ty,
2208 ty.hir_id,
2209 ProbeScope::TraitsInScope,
2210 ) {
2211 if deref_ty.is_suggestable(self.tcx, true)
2212 // If this method receives `&self`, then the provided
2213 // argument _should_ coerce, so it's valid to suggest
2214 // just changing the path.
2215 && pick.item.fn_has_self_parameter
2216 && let Some(self_ty) =
2217 self.tcx.fn_sig(pick.item.def_id).subst_identity().inputs().skip_binder().get(0)
2218 && self_ty.is_ref()
2219 {
2220 let suggested_path = match deref_ty.kind() {
2221 ty::Bool
2222 | ty::Char
2223 | ty::Int(_)
2224 | ty::Uint(_)
2225 | ty::Float(_)
2226 | ty::Adt(_, _)
2227 | ty::Str
2228 | ty::Alias(ty::Projection | ty::Inherent, _)
2229 | ty::Param(_) => format!("{deref_ty}"),
2230 // we need to test something like <&[_]>::len or <(&[u32])>::len
2231 // and Vec::function();
2232 // <&[_]>::len or <&[u32]>::len doesn't need an extra "<>" between
2233 // but for Adt type like Vec::function()
2234 // we would suggest <[_]>::function();
2235 _ if self.tcx.sess.source_map().span_wrapped_by_angle_or_parentheses(ty.span) => format!("{deref_ty}"),
2236 _ => format!("<{deref_ty}>"),
2237 };
2238 err.span_suggestion_verbose(
2239 ty.span,
2240 format!("the function `{item_name}` is implemented on `{deref_ty}`"),
2241 suggested_path,
2242 Applicability::MaybeIncorrect,
2243 );
2244 } else {
2245 err.span_note(
2246 ty.span,
2247 format!("the function `{item_name}` is implemented on `{deref_ty}`"),
2248 );
2249 }
2250 return;
2251 }
2252 }
2253 }
2254
2255 /// Print out the type for use in value namespace.
ty_to_value_string(&self, ty: Ty<'tcx>) -> String2256 fn ty_to_value_string(&self, ty: Ty<'tcx>) -> String {
2257 match ty.kind() {
2258 ty::Adt(def, substs) => self.tcx.def_path_str_with_substs(def.did(), substs),
2259 _ => self.ty_to_string(ty),
2260 }
2261 }
2262
suggest_await_before_method( &self, err: &mut Diagnostic, item_name: Ident, ty: Ty<'tcx>, call: &hir::Expr<'_>, span: Span, return_type: Option<Ty<'tcx>>, )2263 fn suggest_await_before_method(
2264 &self,
2265 err: &mut Diagnostic,
2266 item_name: Ident,
2267 ty: Ty<'tcx>,
2268 call: &hir::Expr<'_>,
2269 span: Span,
2270 return_type: Option<Ty<'tcx>>,
2271 ) {
2272 let output_ty = match self.get_impl_future_output_ty(ty) {
2273 Some(output_ty) => self.resolve_vars_if_possible(output_ty),
2274 _ => return,
2275 };
2276 let method_exists =
2277 self.method_exists(item_name, output_ty, call.hir_id, true, return_type);
2278 debug!("suggest_await_before_method: is_method_exist={}", method_exists);
2279 if method_exists {
2280 err.span_suggestion_verbose(
2281 span.shrink_to_lo(),
2282 "consider `await`ing on the `Future` and calling the method on its `Output`",
2283 "await.",
2284 Applicability::MaybeIncorrect,
2285 );
2286 }
2287 }
2288
suggest_use_candidates(&self, err: &mut Diagnostic, msg: String, candidates: Vec<DefId>)2289 fn suggest_use_candidates(&self, err: &mut Diagnostic, msg: String, candidates: Vec<DefId>) {
2290 let parent_map = self.tcx.visible_parent_map(());
2291
2292 // Separate out candidates that must be imported with a glob, because they are named `_`
2293 // and cannot be referred with their identifier.
2294 let (candidates, globs): (Vec<_>, Vec<_>) = candidates.into_iter().partition(|trait_did| {
2295 if let Some(parent_did) = parent_map.get(trait_did) {
2296 // If the item is re-exported as `_`, we should suggest a glob-import instead.
2297 if *parent_did != self.tcx.parent(*trait_did)
2298 && self
2299 .tcx
2300 .module_children(*parent_did)
2301 .iter()
2302 .filter(|child| child.res.opt_def_id() == Some(*trait_did))
2303 .all(|child| child.ident.name == kw::Underscore)
2304 {
2305 return false;
2306 }
2307 }
2308
2309 true
2310 });
2311
2312 let module_did = self.tcx.parent_module_from_def_id(self.body_id);
2313 let (module, _, _) = self.tcx.hir().get_module(module_did);
2314 let span = module.spans.inject_use_span;
2315
2316 let path_strings = candidates.iter().map(|trait_did| {
2317 format!("use {};\n", with_crate_prefix!(self.tcx.def_path_str(*trait_did)),)
2318 });
2319
2320 let glob_path_strings = globs.iter().map(|trait_did| {
2321 let parent_did = parent_map.get(trait_did).unwrap();
2322 format!(
2323 "use {}::*; // trait {}\n",
2324 with_crate_prefix!(self.tcx.def_path_str(*parent_did)),
2325 self.tcx.item_name(*trait_did),
2326 )
2327 });
2328
2329 err.span_suggestions(
2330 span,
2331 msg,
2332 path_strings.chain(glob_path_strings),
2333 Applicability::MaybeIncorrect,
2334 );
2335 }
2336
suggest_valid_traits( &self, err: &mut Diagnostic, valid_out_of_scope_traits: Vec<DefId>, ) -> bool2337 fn suggest_valid_traits(
2338 &self,
2339 err: &mut Diagnostic,
2340 valid_out_of_scope_traits: Vec<DefId>,
2341 ) -> bool {
2342 if !valid_out_of_scope_traits.is_empty() {
2343 let mut candidates = valid_out_of_scope_traits;
2344 candidates.sort();
2345 candidates.dedup();
2346
2347 // `TryFrom` and `FromIterator` have no methods
2348 let edition_fix = candidates
2349 .iter()
2350 .find(|did| self.tcx.is_diagnostic_item(sym::TryInto, **did))
2351 .copied();
2352
2353 err.help("items from traits can only be used if the trait is in scope");
2354 let msg = format!(
2355 "the following {traits_are} implemented but not in scope; \
2356 perhaps add a `use` for {one_of_them}:",
2357 traits_are = if candidates.len() == 1 { "trait is" } else { "traits are" },
2358 one_of_them = if candidates.len() == 1 { "it" } else { "one of them" },
2359 );
2360
2361 self.suggest_use_candidates(err, msg, candidates);
2362 if let Some(did) = edition_fix {
2363 err.note(format!(
2364 "'{}' is included in the prelude starting in Edition 2021",
2365 with_crate_prefix!(self.tcx.def_path_str(did))
2366 ));
2367 }
2368
2369 true
2370 } else {
2371 false
2372 }
2373 }
2374
suggest_traits_to_import( &self, err: &mut Diagnostic, span: Span, rcvr_ty: Ty<'tcx>, item_name: Ident, inputs_len: Option<usize>, source: SelfSource<'tcx>, valid_out_of_scope_traits: Vec<DefId>, unsatisfied_predicates: &[( ty::Predicate<'tcx>, Option<ty::Predicate<'tcx>>, Option<ObligationCause<'tcx>>, )], static_candidates: &[CandidateSource], unsatisfied_bounds: bool, return_type: Option<Ty<'tcx>>, trait_missing_method: bool, )2375 fn suggest_traits_to_import(
2376 &self,
2377 err: &mut Diagnostic,
2378 span: Span,
2379 rcvr_ty: Ty<'tcx>,
2380 item_name: Ident,
2381 inputs_len: Option<usize>,
2382 source: SelfSource<'tcx>,
2383 valid_out_of_scope_traits: Vec<DefId>,
2384 unsatisfied_predicates: &[(
2385 ty::Predicate<'tcx>,
2386 Option<ty::Predicate<'tcx>>,
2387 Option<ObligationCause<'tcx>>,
2388 )],
2389 static_candidates: &[CandidateSource],
2390 unsatisfied_bounds: bool,
2391 return_type: Option<Ty<'tcx>>,
2392 trait_missing_method: bool,
2393 ) {
2394 let mut alt_rcvr_sugg = false;
2395 if let (SelfSource::MethodCall(rcvr), false) = (source, unsatisfied_bounds) {
2396 debug!(
2397 "suggest_traits_to_import: span={:?}, item_name={:?}, rcvr_ty={:?}, rcvr={:?}",
2398 span, item_name, rcvr_ty, rcvr
2399 );
2400 let skippable = [
2401 self.tcx.lang_items().clone_trait(),
2402 self.tcx.lang_items().deref_trait(),
2403 self.tcx.lang_items().deref_mut_trait(),
2404 self.tcx.lang_items().drop_trait(),
2405 self.tcx.get_diagnostic_item(sym::AsRef),
2406 ];
2407 // Try alternative arbitrary self types that could fulfill this call.
2408 // FIXME: probe for all types that *could* be arbitrary self-types, not
2409 // just this list.
2410 for (rcvr_ty, post) in &[
2411 (rcvr_ty, ""),
2412 (Ty::new_mut_ref(self.tcx, self.tcx.lifetimes.re_erased, rcvr_ty), "&mut "),
2413 (Ty::new_imm_ref(self.tcx, self.tcx.lifetimes.re_erased, rcvr_ty), "&"),
2414 ] {
2415 match self.lookup_probe_for_diagnostic(
2416 item_name,
2417 *rcvr_ty,
2418 rcvr,
2419 ProbeScope::AllTraits,
2420 return_type,
2421 ) {
2422 Ok(pick) => {
2423 // If the method is defined for the receiver we have, it likely wasn't `use`d.
2424 // We point at the method, but we just skip the rest of the check for arbitrary
2425 // self types and rely on the suggestion to `use` the trait from
2426 // `suggest_valid_traits`.
2427 let did = Some(pick.item.container_id(self.tcx));
2428 let skip = skippable.contains(&did);
2429 if pick.autoderefs == 0 && !skip {
2430 err.span_label(
2431 pick.item.ident(self.tcx).span,
2432 format!("the method is available for `{}` here", rcvr_ty),
2433 );
2434 }
2435 break;
2436 }
2437 Err(MethodError::Ambiguity(_)) => {
2438 // If the method is defined (but ambiguous) for the receiver we have, it is also
2439 // likely we haven't `use`d it. It may be possible that if we `Box`/`Pin`/etc.
2440 // the receiver, then it might disambiguate this method, but I think these
2441 // suggestions are generally misleading (see #94218).
2442 break;
2443 }
2444 Err(_) => (),
2445 }
2446
2447 for (rcvr_ty, pre) in &[
2448 (Ty::new_lang_item(self.tcx, *rcvr_ty, LangItem::OwnedBox), "Box::new"),
2449 (Ty::new_lang_item(self.tcx, *rcvr_ty, LangItem::Pin), "Pin::new"),
2450 (Ty::new_diagnostic_item(self.tcx, *rcvr_ty, sym::Arc), "Arc::new"),
2451 (Ty::new_diagnostic_item(self.tcx, *rcvr_ty, sym::Rc), "Rc::new"),
2452 ] {
2453 if let Some(new_rcvr_t) = *rcvr_ty
2454 && let Ok(pick) = self.lookup_probe_for_diagnostic(
2455 item_name,
2456 new_rcvr_t,
2457 rcvr,
2458 ProbeScope::AllTraits,
2459 return_type,
2460 )
2461 {
2462 debug!("try_alt_rcvr: pick candidate {:?}", pick);
2463 let did = Some(pick.item.container_id(self.tcx));
2464 // We don't want to suggest a container type when the missing
2465 // method is `.clone()` or `.deref()` otherwise we'd suggest
2466 // `Arc::new(foo).clone()`, which is far from what the user wants.
2467 // Explicitly ignore the `Pin::as_ref()` method as `Pin` does not
2468 // implement the `AsRef` trait.
2469 let skip = skippable.contains(&did)
2470 || (("Pin::new" == *pre) && (sym::as_ref == item_name.name))
2471 || inputs_len.is_some_and(|inputs_len| pick.item.kind == ty::AssocKind::Fn && self.tcx.fn_sig(pick.item.def_id).skip_binder().skip_binder().inputs().len() != inputs_len);
2472 // Make sure the method is defined for the *actual* receiver: we don't
2473 // want to treat `Box<Self>` as a receiver if it only works because of
2474 // an autoderef to `&self`
2475 if pick.autoderefs == 0 && !skip {
2476 err.span_label(
2477 pick.item.ident(self.tcx).span,
2478 format!("the method is available for `{}` here", new_rcvr_t),
2479 );
2480 err.multipart_suggestion(
2481 "consider wrapping the receiver expression with the \
2482 appropriate type",
2483 vec![
2484 (rcvr.span.shrink_to_lo(), format!("{}({}", pre, post)),
2485 (rcvr.span.shrink_to_hi(), ")".to_string()),
2486 ],
2487 Applicability::MaybeIncorrect,
2488 );
2489 // We don't care about the other suggestions.
2490 alt_rcvr_sugg = true;
2491 }
2492 }
2493 }
2494 }
2495 }
2496 if self.suggest_valid_traits(err, valid_out_of_scope_traits) {
2497 return;
2498 }
2499
2500 let type_is_local = self.type_derefs_to_local(span, rcvr_ty, source);
2501
2502 let mut arbitrary_rcvr = vec![];
2503 // There are no traits implemented, so lets suggest some traits to
2504 // implement, by finding ones that have the item name, and are
2505 // legal to implement.
2506 let mut candidates = all_traits(self.tcx)
2507 .into_iter()
2508 // Don't issue suggestions for unstable traits since they're
2509 // unlikely to be implementable anyway
2510 .filter(|info| match self.tcx.lookup_stability(info.def_id) {
2511 Some(attr) => attr.level.is_stable(),
2512 None => true,
2513 })
2514 .filter(|info| {
2515 // Static candidates are already implemented, and known not to work
2516 // Do not suggest them again
2517 static_candidates.iter().all(|sc| match *sc {
2518 CandidateSource::Trait(def_id) => def_id != info.def_id,
2519 CandidateSource::Impl(def_id) => {
2520 self.tcx.trait_id_of_impl(def_id) != Some(info.def_id)
2521 }
2522 })
2523 })
2524 .filter(|info| {
2525 // We approximate the coherence rules to only suggest
2526 // traits that are legal to implement by requiring that
2527 // either the type or trait is local. Multi-dispatch means
2528 // this isn't perfect (that is, there are cases when
2529 // implementing a trait would be legal but is rejected
2530 // here).
2531 unsatisfied_predicates.iter().all(|(p, _, _)| {
2532 match p.kind().skip_binder() {
2533 // Hide traits if they are present in predicates as they can be fixed without
2534 // having to implement them.
2535 ty::PredicateKind::Clause(ty::ClauseKind::Trait(t)) => {
2536 t.def_id() == info.def_id
2537 }
2538 ty::PredicateKind::Clause(ty::ClauseKind::Projection(p)) => {
2539 p.projection_ty.def_id == info.def_id
2540 }
2541 _ => false,
2542 }
2543 }) && (type_is_local || info.def_id.is_local())
2544 && !self.tcx.trait_is_auto(info.def_id)
2545 && self
2546 .associated_value(info.def_id, item_name)
2547 .filter(|item| {
2548 if let ty::AssocKind::Fn = item.kind {
2549 let id = item
2550 .def_id
2551 .as_local()
2552 .map(|def_id| self.tcx.hir().local_def_id_to_hir_id(def_id));
2553 if let Some(hir::Node::TraitItem(hir::TraitItem {
2554 kind: hir::TraitItemKind::Fn(fn_sig, method),
2555 ..
2556 })) = id.map(|id| self.tcx.hir().get(id))
2557 {
2558 let self_first_arg = match method {
2559 hir::TraitFn::Required([ident, ..]) => {
2560 ident.name == kw::SelfLower
2561 }
2562 hir::TraitFn::Provided(body_id) => {
2563 self.tcx.hir().body(*body_id).params.first().map_or(
2564 false,
2565 |param| {
2566 matches!(
2567 param.pat.kind,
2568 hir::PatKind::Binding(_, _, ident, _)
2569 if ident.name == kw::SelfLower
2570 )
2571 },
2572 )
2573 }
2574 _ => false,
2575 };
2576
2577 if !fn_sig.decl.implicit_self.has_implicit_self()
2578 && self_first_arg
2579 {
2580 if let Some(ty) = fn_sig.decl.inputs.get(0) {
2581 arbitrary_rcvr.push(ty.span);
2582 }
2583 return false;
2584 }
2585 }
2586 }
2587 // We only want to suggest public or local traits (#45781).
2588 item.visibility(self.tcx).is_public() || info.def_id.is_local()
2589 })
2590 .is_some()
2591 })
2592 .collect::<Vec<_>>();
2593 for span in &arbitrary_rcvr {
2594 err.span_label(
2595 *span,
2596 "the method might not be found because of this arbitrary self type",
2597 );
2598 }
2599 if alt_rcvr_sugg {
2600 return;
2601 }
2602
2603 if !candidates.is_empty() {
2604 // Sort from most relevant to least relevant.
2605 candidates.sort_by_key(|&info| cmp::Reverse(info));
2606 candidates.dedup();
2607
2608 let param_type = match rcvr_ty.kind() {
2609 ty::Param(param) => Some(param),
2610 ty::Ref(_, ty, _) => match ty.kind() {
2611 ty::Param(param) => Some(param),
2612 _ => None,
2613 },
2614 _ => None,
2615 };
2616 if !trait_missing_method {
2617 err.help(if param_type.is_some() {
2618 "items from traits can only be used if the type parameter is bounded by the trait"
2619 } else {
2620 "items from traits can only be used if the trait is implemented and in scope"
2621 });
2622 }
2623
2624 let candidates_len = candidates.len();
2625 let message = |action| {
2626 format!(
2627 "the following {traits_define} an item `{name}`, perhaps you need to {action} \
2628 {one_of_them}:",
2629 traits_define =
2630 if candidates_len == 1 { "trait defines" } else { "traits define" },
2631 action = action,
2632 one_of_them = if candidates_len == 1 { "it" } else { "one of them" },
2633 name = item_name,
2634 )
2635 };
2636 // Obtain the span for `param` and use it for a structured suggestion.
2637 if let Some(param) = param_type {
2638 let generics = self.tcx.generics_of(self.body_id.to_def_id());
2639 let type_param = generics.type_param(param, self.tcx);
2640 let hir = self.tcx.hir();
2641 if let Some(def_id) = type_param.def_id.as_local() {
2642 let id = hir.local_def_id_to_hir_id(def_id);
2643 // Get the `hir::Param` to verify whether it already has any bounds.
2644 // We do this to avoid suggesting code that ends up as `T: FooBar`,
2645 // instead we suggest `T: Foo + Bar` in that case.
2646 match hir.get(id) {
2647 Node::GenericParam(param) => {
2648 enum Introducer {
2649 Plus,
2650 Colon,
2651 Nothing,
2652 }
2653 let ast_generics = hir.get_generics(id.owner.def_id).unwrap();
2654 let trait_def_ids: FxHashSet<DefId> = ast_generics
2655 .bounds_for_param(def_id)
2656 .flat_map(|bp| bp.bounds.iter())
2657 .filter_map(|bound| bound.trait_ref()?.trait_def_id())
2658 .collect();
2659 if candidates.iter().any(|t| trait_def_ids.contains(&t.def_id)) {
2660 return;
2661 }
2662 let msg = message(format!(
2663 "restrict type parameter `{}` with",
2664 param.name.ident(),
2665 ));
2666 let bounds_span = ast_generics.bounds_span_for_suggestions(def_id);
2667 if rcvr_ty.is_ref() && param.is_impl_trait() && bounds_span.is_some() {
2668 err.multipart_suggestions(
2669 msg,
2670 candidates.iter().map(|t| {
2671 vec![
2672 (param.span.shrink_to_lo(), "(".to_string()),
2673 (
2674 bounds_span.unwrap(),
2675 format!(" + {})", self.tcx.def_path_str(t.def_id)),
2676 ),
2677 ]
2678 }),
2679 Applicability::MaybeIncorrect,
2680 );
2681 return;
2682 }
2683
2684 let (sp, introducer) = if let Some(span) = bounds_span {
2685 (span, Introducer::Plus)
2686 } else if let Some(colon_span) = param.colon_span {
2687 (colon_span.shrink_to_hi(), Introducer::Nothing)
2688 } else if param.is_impl_trait() {
2689 (param.span.shrink_to_hi(), Introducer::Plus)
2690 } else {
2691 (param.span.shrink_to_hi(), Introducer::Colon)
2692 };
2693
2694 err.span_suggestions(
2695 sp,
2696 msg,
2697 candidates.iter().map(|t| {
2698 format!(
2699 "{} {}",
2700 match introducer {
2701 Introducer::Plus => " +",
2702 Introducer::Colon => ":",
2703 Introducer::Nothing => "",
2704 },
2705 self.tcx.def_path_str(t.def_id)
2706 )
2707 }),
2708 Applicability::MaybeIncorrect,
2709 );
2710 return;
2711 }
2712 Node::Item(hir::Item {
2713 kind: hir::ItemKind::Trait(.., bounds, _),
2714 ident,
2715 ..
2716 }) => {
2717 let (sp, sep, article) = if bounds.is_empty() {
2718 (ident.span.shrink_to_hi(), ":", "a")
2719 } else {
2720 (bounds.last().unwrap().span().shrink_to_hi(), " +", "another")
2721 };
2722 err.span_suggestions(
2723 sp,
2724 message(format!("add {} supertrait for", article)),
2725 candidates.iter().map(|t| {
2726 format!("{} {}", sep, self.tcx.def_path_str(t.def_id),)
2727 }),
2728 Applicability::MaybeIncorrect,
2729 );
2730 return;
2731 }
2732 _ => {}
2733 }
2734 }
2735 }
2736
2737 let (potential_candidates, explicitly_negative) = if param_type.is_some() {
2738 // FIXME: Even though negative bounds are not implemented, we could maybe handle
2739 // cases where a positive bound implies a negative impl.
2740 (candidates, Vec::new())
2741 } else if let Some(simp_rcvr_ty) =
2742 simplify_type(self.tcx, rcvr_ty, TreatParams::ForLookup)
2743 {
2744 let mut potential_candidates = Vec::new();
2745 let mut explicitly_negative = Vec::new();
2746 for candidate in candidates {
2747 // Check if there's a negative impl of `candidate` for `rcvr_ty`
2748 if self
2749 .tcx
2750 .all_impls(candidate.def_id)
2751 .filter(|imp_did| {
2752 self.tcx.impl_polarity(*imp_did) == ty::ImplPolarity::Negative
2753 })
2754 .any(|imp_did| {
2755 let imp = self.tcx.impl_trait_ref(imp_did).unwrap().subst_identity();
2756 let imp_simp =
2757 simplify_type(self.tcx, imp.self_ty(), TreatParams::ForLookup);
2758 imp_simp.is_some_and(|s| s == simp_rcvr_ty)
2759 })
2760 {
2761 explicitly_negative.push(candidate);
2762 } else {
2763 potential_candidates.push(candidate);
2764 }
2765 }
2766 (potential_candidates, explicitly_negative)
2767 } else {
2768 // We don't know enough about `recv_ty` to make proper suggestions.
2769 (candidates, Vec::new())
2770 };
2771
2772 match &potential_candidates[..] {
2773 [] => {}
2774 [trait_info] if trait_info.def_id.is_local() => {
2775 err.subdiagnostic(CandidateTraitNote {
2776 span: self.tcx.def_span(trait_info.def_id),
2777 trait_name: self.tcx.def_path_str(trait_info.def_id),
2778 item_name,
2779 action_or_ty: if trait_missing_method {
2780 "NONE".to_string()
2781 } else {
2782 param_type.map_or_else(
2783 || "implement".to_string(), // FIXME: it might only need to be imported into scope, not implemented.
2784 ToString::to_string,
2785 )
2786 },
2787 });
2788 }
2789 trait_infos => {
2790 let mut msg = message(param_type.map_or_else(
2791 || "implement".to_string(), // FIXME: it might only need to be imported into scope, not implemented.
2792 |param| format!("restrict type parameter `{}` with", param),
2793 ));
2794 for (i, trait_info) in trait_infos.iter().enumerate() {
2795 msg.push_str(&format!(
2796 "\ncandidate #{}: `{}`",
2797 i + 1,
2798 self.tcx.def_path_str(trait_info.def_id),
2799 ));
2800 }
2801 err.note(msg);
2802 }
2803 }
2804 match &explicitly_negative[..] {
2805 [] => {}
2806 [trait_info] => {
2807 let msg = format!(
2808 "the trait `{}` defines an item `{}`, but is explicitly unimplemented",
2809 self.tcx.def_path_str(trait_info.def_id),
2810 item_name
2811 );
2812 err.note(msg);
2813 }
2814 trait_infos => {
2815 let mut msg = format!(
2816 "the following traits define an item `{}`, but are explicitly unimplemented:",
2817 item_name
2818 );
2819 for trait_info in trait_infos {
2820 msg.push_str(&format!("\n{}", self.tcx.def_path_str(trait_info.def_id)));
2821 }
2822 err.note(msg);
2823 }
2824 }
2825 }
2826 }
2827
2828 /// issue #102320, for `unwrap_or` with closure as argument, suggest `unwrap_or_else`
2829 /// FIXME: currently not working for suggesting `map_or_else`, see #102408
suggest_else_fn_with_closure( &self, err: &mut Diagnostic, expr: &hir::Expr<'_>, found: Ty<'tcx>, expected: Ty<'tcx>, ) -> bool2830 pub(crate) fn suggest_else_fn_with_closure(
2831 &self,
2832 err: &mut Diagnostic,
2833 expr: &hir::Expr<'_>,
2834 found: Ty<'tcx>,
2835 expected: Ty<'tcx>,
2836 ) -> bool {
2837 let Some((_def_id_or_name, output, _inputs)) =
2838 self.extract_callable_info(found) else {
2839 return false;
2840 };
2841
2842 if !self.can_coerce(output, expected) {
2843 return false;
2844 }
2845
2846 let parent = self.tcx.hir().parent_id(expr.hir_id);
2847 if let Some(Node::Expr(call_expr)) = self.tcx.hir().find(parent) &&
2848 let hir::ExprKind::MethodCall(
2849 hir::PathSegment { ident: method_name, .. },
2850 self_expr,
2851 args,
2852 ..,
2853 ) = call_expr.kind &&
2854 let Some(self_ty) = self.typeck_results.borrow().expr_ty_opt(self_expr) {
2855 let new_name = Ident {
2856 name: Symbol::intern(&format!("{}_else", method_name.as_str())),
2857 span: method_name.span,
2858 };
2859 let probe = self.lookup_probe_for_diagnostic(
2860 new_name,
2861 self_ty,
2862 self_expr,
2863 ProbeScope::TraitsInScope,
2864 Some(expected),
2865 );
2866
2867 // check the method arguments number
2868 if let Ok(pick) = probe &&
2869 let fn_sig = self.tcx.fn_sig(pick.item.def_id) &&
2870 let fn_args = fn_sig.skip_binder().skip_binder().inputs() &&
2871 fn_args.len() == args.len() + 1 {
2872 err.span_suggestion_verbose(
2873 method_name.span.shrink_to_hi(),
2874 format!("try calling `{}` instead", new_name.name.as_str()),
2875 "_else",
2876 Applicability::MaybeIncorrect,
2877 );
2878 return true;
2879 }
2880 }
2881 false
2882 }
2883
2884 /// Checks whether there is a local type somewhere in the chain of
2885 /// autoderefs of `rcvr_ty`.
type_derefs_to_local( &self, span: Span, rcvr_ty: Ty<'tcx>, source: SelfSource<'tcx>, ) -> bool2886 fn type_derefs_to_local(
2887 &self,
2888 span: Span,
2889 rcvr_ty: Ty<'tcx>,
2890 source: SelfSource<'tcx>,
2891 ) -> bool {
2892 fn is_local(ty: Ty<'_>) -> bool {
2893 match ty.kind() {
2894 ty::Adt(def, _) => def.did().is_local(),
2895 ty::Foreign(did) => did.is_local(),
2896 ty::Dynamic(tr, ..) => tr.principal().is_some_and(|d| d.def_id().is_local()),
2897 ty::Param(_) => true,
2898
2899 // Everything else (primitive types, etc.) is effectively
2900 // non-local (there are "edge" cases, e.g., `(LocalType,)`, but
2901 // the noise from these sort of types is usually just really
2902 // annoying, rather than any sort of help).
2903 _ => false,
2904 }
2905 }
2906
2907 // This occurs for UFCS desugaring of `T::method`, where there is no
2908 // receiver expression for the method call, and thus no autoderef.
2909 if let SelfSource::QPath(_) = source {
2910 return is_local(self.resolve_vars_with_obligations(rcvr_ty));
2911 }
2912
2913 self.autoderef(span, rcvr_ty).any(|(ty, _)| is_local(ty))
2914 }
2915 }
2916
2917 #[derive(Copy, Clone, Debug)]
2918 pub enum SelfSource<'a> {
2919 QPath(&'a hir::Ty<'a>),
2920 MethodCall(&'a hir::Expr<'a> /* rcvr */),
2921 }
2922
2923 #[derive(Copy, Clone)]
2924 pub struct TraitInfo {
2925 pub def_id: DefId,
2926 }
2927
2928 impl PartialEq for TraitInfo {
eq(&self, other: &TraitInfo) -> bool2929 fn eq(&self, other: &TraitInfo) -> bool {
2930 self.cmp(other) == Ordering::Equal
2931 }
2932 }
2933 impl Eq for TraitInfo {}
2934 impl PartialOrd for TraitInfo {
partial_cmp(&self, other: &TraitInfo) -> Option<Ordering>2935 fn partial_cmp(&self, other: &TraitInfo) -> Option<Ordering> {
2936 Some(self.cmp(other))
2937 }
2938 }
2939 impl Ord for TraitInfo {
cmp(&self, other: &TraitInfo) -> Ordering2940 fn cmp(&self, other: &TraitInfo) -> Ordering {
2941 // Local crates are more important than remote ones (local:
2942 // `cnum == 0`), and otherwise we throw in the defid for totality.
2943
2944 let lhs = (other.def_id.krate, other.def_id);
2945 let rhs = (self.def_id.krate, self.def_id);
2946 lhs.cmp(&rhs)
2947 }
2948 }
2949
2950 /// Retrieves all traits in this crate and any dependent crates,
2951 /// and wraps them into `TraitInfo` for custom sorting.
all_traits(tcx: TyCtxt<'_>) -> Vec<TraitInfo>2952 pub fn all_traits(tcx: TyCtxt<'_>) -> Vec<TraitInfo> {
2953 tcx.all_traits().map(|def_id| TraitInfo { def_id }).collect()
2954 }
2955
print_disambiguation_help<'tcx>( item_name: Ident, args: Option<(&'tcx hir::Expr<'tcx>, &'tcx [hir::Expr<'tcx>])>, err: &mut Diagnostic, trait_name: String, rcvr_ty: Ty<'_>, kind: ty::AssocKind, def_kind_descr: &'static str, span: Span, candidate: Option<usize>, source_map: &source_map::SourceMap, fn_has_self_parameter: bool, )2956 fn print_disambiguation_help<'tcx>(
2957 item_name: Ident,
2958 args: Option<(&'tcx hir::Expr<'tcx>, &'tcx [hir::Expr<'tcx>])>,
2959 err: &mut Diagnostic,
2960 trait_name: String,
2961 rcvr_ty: Ty<'_>,
2962 kind: ty::AssocKind,
2963 def_kind_descr: &'static str,
2964 span: Span,
2965 candidate: Option<usize>,
2966 source_map: &source_map::SourceMap,
2967 fn_has_self_parameter: bool,
2968 ) {
2969 let mut applicability = Applicability::MachineApplicable;
2970 let (span, sugg) = if let (ty::AssocKind::Fn, Some((receiver, args))) = (kind, args) {
2971 let args = format!(
2972 "({}{})",
2973 rcvr_ty.ref_mutability().map_or("", |mutbl| mutbl.ref_prefix_str()),
2974 std::iter::once(receiver)
2975 .chain(args.iter())
2976 .map(|arg| source_map.span_to_snippet(arg.span).unwrap_or_else(|_| {
2977 applicability = Applicability::HasPlaceholders;
2978 "_".to_owned()
2979 }))
2980 .collect::<Vec<_>>()
2981 .join(", "),
2982 );
2983 let trait_name = if !fn_has_self_parameter {
2984 format!("<{} as {}>", rcvr_ty, trait_name)
2985 } else {
2986 trait_name
2987 };
2988 (span, format!("{}::{}{}", trait_name, item_name, args))
2989 } else {
2990 (span.with_hi(item_name.span.lo()), format!("<{} as {}>::", rcvr_ty, trait_name))
2991 };
2992 err.span_suggestion_verbose(
2993 span,
2994 format!(
2995 "disambiguate the {} for {}",
2996 def_kind_descr,
2997 if let Some(candidate) = candidate {
2998 format!("candidate #{}", candidate)
2999 } else {
3000 "the candidate".to_string()
3001 },
3002 ),
3003 sugg,
3004 applicability,
3005 );
3006 }
3007