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