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 <[_]>::into_vec(::alloc::boxed::box_new([(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 = <[_]>::into_vec(::alloc::boxed::box_new([(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 = <[_]>::into_vec(::alloc::boxed::box_new([(span, var_name.to_string())]))vec![(span, var_name.to_string())];
1497 }
1498 (None, _) => {
1499 suggestion = <[_]>::into_vec(::alloc::boxed::box_new([(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 = <[_]>::into_vec(::alloc::boxed::box_new([(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 = <[_]>::into_vec(::alloc::boxed::box_new([(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 for (p, parent_p, cause) in unsatisfied_predicates {
1752 let (item_def_id, cause_span) = match cause.as_ref().map(|cause| cause.code()) {
1755 Some(ObligationCauseCode::ImplDerived(data)) => {
1756 (data.impl_or_alias_def_id, data.span)
1757 }
1758 Some(
1759 ObligationCauseCode::WhereClauseInExpr(def_id, span, _, _)
1760 | ObligationCauseCode::WhereClause(def_id, span),
1761 ) if !span.is_dummy() => (*def_id, *span),
1762 _ => continue,
1763 };
1764
1765 if !#[allow(non_exhaustive_omitted_patterns)] match p.kind().skip_binder() {
ty::PredicateKind::Clause(ty::ClauseKind::Projection(..) |
ty::ClauseKind::Trait(..)) => true,
_ => false,
}matches!(
1767 p.kind().skip_binder(),
1768 ty::PredicateKind::Clause(
1769 ty::ClauseKind::Projection(..) | ty::ClauseKind::Trait(..)
1770 )
1771 ) {
1772 continue;
1773 }
1774
1775 match self.tcx.hir_get_if_local(item_def_id) {
1776 Some(Node::Item(hir::Item {
1779 kind: hir::ItemKind::Impl(hir::Impl { of_trait, self_ty, .. }),
1780 ..
1781 })) if #[allow(non_exhaustive_omitted_patterns)] match self_ty.span.ctxt().outer_expn_data().kind
{
ExpnKind::Macro(MacroKind::Derive, _) => true,
_ => false,
}matches!(
1782 self_ty.span.ctxt().outer_expn_data().kind,
1783 ExpnKind::Macro(MacroKind::Derive, _)
1784 ) || #[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!(
1785 of_trait.map(|t| t.trait_ref.path.span.ctxt().outer_expn_data().kind),
1786 Some(ExpnKind::Macro(MacroKind::Derive, _))
1787 ) =>
1788 {
1789 let span = self_ty.span.ctxt().outer_expn_data().call_site;
1790 let entry = spanned_predicates.entry(span);
1791 let entry = entry.or_insert_with(|| {
1792 (FxIndexSet::default(), FxIndexSet::default(), Vec::new())
1793 });
1794 entry.0.insert(span);
1795 entry.1.insert((
1796 span,
1797 "unsatisfied trait bound introduced in this `derive` macro",
1798 ));
1799 entry.2.push(p);
1800 skip_list.insert(p);
1801 }
1802
1803 Some(Node::Item(hir::Item {
1805 kind: hir::ItemKind::Impl(hir::Impl { of_trait, self_ty, generics, .. }),
1806 span: item_span,
1807 ..
1808 })) => {
1809 let sized_pred =
1810 unsatisfied_predicates.iter().any(|(pred, _, _)| {
1811 match pred.kind().skip_binder() {
1812 ty::PredicateKind::Clause(ty::ClauseKind::Trait(pred)) => {
1813 self.tcx.is_lang_item(pred.def_id(), LangItem::Sized)
1814 && pred.polarity == ty::PredicatePolarity::Positive
1815 }
1816 _ => false,
1817 }
1818 });
1819 for param in generics.params {
1820 if param.span == cause_span && sized_pred {
1821 let (sp, sugg) = match param.colon_span {
1822 Some(sp) => (sp.shrink_to_hi(), " ?Sized +"),
1823 None => (param.span.shrink_to_hi(), ": ?Sized"),
1824 };
1825 err.span_suggestion_verbose(
1826 sp,
1827 "consider relaxing the type parameter's implicit `Sized` bound",
1828 sugg,
1829 Applicability::MachineApplicable,
1830 );
1831 }
1832 }
1833 if let Some(pred) = parent_p {
1834 let _ = format_pred(*pred);
1836 }
1837 skip_list.insert(p);
1838 let entry = spanned_predicates.entry(self_ty.span);
1839 let entry = entry.or_insert_with(|| {
1840 (FxIndexSet::default(), FxIndexSet::default(), Vec::new())
1841 });
1842 entry.2.push(p);
1843 if cause_span != *item_span {
1844 entry.0.insert(cause_span);
1845 entry.1.insert((cause_span, "unsatisfied trait bound introduced here"));
1846 } else {
1847 if let Some(of_trait) = of_trait {
1848 entry.0.insert(of_trait.trait_ref.path.span);
1849 }
1850 entry.0.insert(self_ty.span);
1851 };
1852 if let Some(of_trait) = of_trait {
1853 entry.1.insert((of_trait.trait_ref.path.span, ""));
1854 }
1855 entry.1.insert((self_ty.span, ""));
1856 }
1857 Some(Node::Item(hir::Item {
1858 kind: hir::ItemKind::Trait(_, rustc_ast::ast::IsAuto::Yes, ..),
1859 span: item_span,
1860 ..
1861 })) => {
1862 self.dcx().span_delayed_bug(
1863 *item_span,
1864 "auto trait is invoked with no method error, but no error reported?",
1865 );
1866 }
1867 Some(
1868 Node::Item(hir::Item {
1869 kind:
1870 hir::ItemKind::Trait(_, _, _, ident, ..)
1871 | hir::ItemKind::TraitAlias(_, ident, ..),
1872 ..
1873 })
1874 | Node::TraitItem(hir::TraitItem { ident, .. })
1876 | Node::ImplItem(hir::ImplItem { ident, .. })
1877 ) => {
1878 skip_list.insert(p);
1879 let entry = spanned_predicates.entry(ident.span);
1880 let entry = entry.or_insert_with(|| {
1881 (FxIndexSet::default(), FxIndexSet::default(), Vec::new())
1882 });
1883 entry.0.insert(cause_span);
1884 entry.1.insert((ident.span, ""));
1885 entry.1.insert((cause_span, "unsatisfied trait bound introduced here"));
1886 entry.2.push(p);
1887 }
1888 _ => {
1889 }
1894 }
1895 }
1896 let mut spanned_predicates: Vec<_> = spanned_predicates.into_iter().collect();
1897 spanned_predicates.sort_by_key(|(span, _)| *span);
1898 for (_, (primary_spans, span_labels, predicates)) in spanned_predicates {
1899 let mut tracker = TraitBoundDuplicateTracker::new();
1900 let mut all_trait_bounds_for_rcvr = true;
1901 for pred in &predicates {
1902 match pred.kind().skip_binder() {
1903 ty::PredicateKind::Clause(ty::ClauseKind::Trait(pred)) => {
1904 let self_ty = pred.trait_ref.self_ty();
1905 if self_ty.peel_refs() != rcvr_ty {
1906 all_trait_bounds_for_rcvr = false;
1907 break;
1908 }
1909 let is_ref = #[allow(non_exhaustive_omitted_patterns)] match self_ty.kind() {
ty::Ref(..) => true,
_ => false,
}matches!(self_ty.kind(), ty::Ref(..));
1910 tracker.track(pred.trait_ref.def_id, is_ref);
1911 }
1912 _ => {
1913 all_trait_bounds_for_rcvr = false;
1914 break;
1915 }
1916 }
1917 }
1918 let has_ref_dupes = tracker.has_ref_dupes();
1919 let trait_def_ids = tracker.into_trait_def_ids();
1920 let mut preds: Vec<_> = predicates
1921 .iter()
1922 .filter_map(|pred| format_pred(**pred))
1923 .map(|(p, _)| ::alloc::__export::must_use({
::alloc::fmt::format(format_args!("`{0}`", p))
})format!("`{p}`"))
1924 .collect();
1925 preds.sort();
1926 preds.dedup();
1927 let availability_note = if all_trait_bounds_for_rcvr
1928 && has_ref_dupes
1929 && trait_def_ids.len() > 1
1930 && #[allow(non_exhaustive_omitted_patterns)] match rcvr_ty.kind() {
ty::Adt(..) => true,
_ => false,
}matches!(rcvr_ty.kind(), ty::Adt(..))
1931 {
1932 let mut trait_names = trait_def_ids
1933 .into_iter()
1934 .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)))
1935 .collect::<Vec<_>>();
1936 trait_names.sort();
1937 listify(&trait_names, |name| name.to_string()).map(|traits| {
1938 ::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!(
1939 "for `{item_ident}` to be available, `{rcvr_ty_str}` must implement {traits}"
1940 )
1941 })
1942 } else {
1943 None
1944 };
1945 let msg = if let Some(availability_note) = availability_note {
1946 availability_note
1947 } else if let [pred] = &preds[..] {
1948 ::alloc::__export::must_use({
::alloc::fmt::format(format_args!("trait bound {0} was not satisfied",
pred))
})format!("trait bound {pred} was not satisfied")
1949 } else {
1950 ::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"),)
1951 };
1952 let mut span: MultiSpan = primary_spans.into_iter().collect::<Vec<_>>().into();
1953 for (sp, label) in span_labels {
1954 span.push_span_label(sp, label);
1955 }
1956 err.span_note(span, msg);
1957 *unsatisfied_bounds = true;
1958 }
1959
1960 let mut suggested_bounds = UnordSet::default();
1961 let mut bound_list = unsatisfied_predicates
1963 .iter()
1964 .filter_map(|(pred, parent_pred, _cause)| {
1965 let mut suggested = false;
1966 format_pred(*pred).map(|(p, self_ty)| {
1967 if let Some(parent) = parent_pred
1968 && suggested_bounds.contains(parent)
1969 {
1970 } else if !suggested_bounds.contains(pred)
1972 && collect_type_param_suggestions(self_ty, *pred, &p)
1973 {
1974 suggested = true;
1975 suggested_bounds.insert(pred);
1976 }
1977 (
1978 match parent_pred {
1979 None => ::alloc::__export::must_use({
::alloc::fmt::format(format_args!("`{0}`", p))
})format!("`{p}`"),
1980 Some(parent_pred) => match format_pred(*parent_pred) {
1981 None => ::alloc::__export::must_use({
::alloc::fmt::format(format_args!("`{0}`", p))
})format!("`{p}`"),
1982 Some((parent_p, _)) => {
1983 if !suggested
1984 && !suggested_bounds.contains(pred)
1985 && !suggested_bounds.contains(parent_pred)
1986 && collect_type_param_suggestions(self_ty, *parent_pred, &p)
1987 {
1988 suggested_bounds.insert(pred);
1989 }
1990 ::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}`")
1991 }
1992 },
1993 },
1994 *pred,
1995 )
1996 })
1997 })
1998 .filter(|(_, pred)| !skip_list.contains(&pred))
1999 .map(|(t, _)| t)
2000 .enumerate()
2001 .collect::<Vec<(usize, String)>>();
2002
2003 if !#[allow(non_exhaustive_omitted_patterns)] match rcvr_ty.peel_refs().kind() {
ty::Param(_) => true,
_ => false,
}matches!(rcvr_ty.peel_refs().kind(), ty::Param(_)) {
2004 for ((span, add_where_or_comma), obligations) in type_params.into_iter() {
2005 *restrict_type_params = true;
2006 let obligations = obligations.into_sorted_stable_ord();
2008 err.span_suggestion_verbose(
2009 span,
2010 ::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!(
2011 "consider restricting the type parameter{s} to satisfy the trait \
2012 bound{s}",
2013 s = pluralize!(obligations.len())
2014 ),
2015 ::alloc::__export::must_use({
::alloc::fmt::format(format_args!("{0} {1}", add_where_or_comma,
obligations.join(", ")))
})format!("{} {}", add_where_or_comma, obligations.join(", ")),
2016 Applicability::MaybeIncorrect,
2017 );
2018 }
2019 }
2020
2021 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() {
2026 let bound_list =
2027 bound_list.into_iter().map(|(_, path)| path).collect::<Vec<_>>().join("\n");
2028 let actual_prefix = rcvr_ty.prefix_string(self.tcx);
2029 {
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:2029",
"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(2029u32),
::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());
2030 let (primary_message, label, notes) = if unimplemented_traits.len() == 1
2031 && unimplemented_traits_only
2032 {
2033 unimplemented_traits
2034 .into_iter()
2035 .next()
2036 .map(|(_, (trait_ref, obligation))| {
2037 if trait_ref.self_ty().references_error() || rcvr_ty.references_error() {
2038 return (None, None, Vec::new());
2040 }
2041 let OnUnimplementedNote { message, label, notes, .. } = self
2042 .err_ctxt()
2043 .on_unimplemented_note(trait_ref, &obligation, err.long_ty_path());
2044 (message, label, notes)
2045 })
2046 .unwrap()
2047 } else {
2048 (None, None, Vec::new())
2049 };
2050 let primary_message = primary_message.unwrap_or_else(|| {
2051 let ty_str = self.tcx.short_string(rcvr_ty, err.long_ty_path());
2052 ::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!(
2053 "the {item_kind} `{item_ident}` exists for {actual_prefix} `{ty_str}`, \
2054 but its trait bounds were not satisfied"
2055 )
2056 });
2057 err.primary_message(primary_message);
2058 if let Some(label) = label {
2059 *custom_span_label = true;
2060 err.span_label(span, label);
2061 }
2062 if !bound_list.is_empty() {
2063 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}"));
2064 }
2065 for note in notes {
2066 err.note(note);
2067 }
2068
2069 if let ty::Adt(adt_def, _) = rcvr_ty.kind() {
2070 unsatisfied_predicates.iter().find(|(pred, _parent, _cause)| {
2071 if let ty::PredicateKind::Clause(ty::ClauseKind::Trait(pred)) =
2072 pred.kind().skip_binder()
2073 {
2074 self.suggest_hashmap_on_unsatisfied_hashset_buildhasher(
2075 err, &pred, *adt_def,
2076 )
2077 } else {
2078 false
2079 }
2080 });
2081 }
2082
2083 *suggested_derive = self.suggest_derive(err, unsatisfied_predicates);
2084 *unsatisfied_bounds = true;
2085 }
2086 }
2087
2088 fn lookup_segments_chain_for_no_match_method(
2090 &self,
2091 err: &mut Diag<'_>,
2092 item_name: Ident,
2093 item_kind: &str,
2094 source: SelfSource<'tcx>,
2095 no_match_data: &NoMatchData<'tcx>,
2096 ) {
2097 if no_match_data.unsatisfied_predicates.is_empty()
2098 && let Mode::MethodCall = no_match_data.mode
2099 && let SelfSource::MethodCall(mut source_expr) = source
2100 {
2101 let mut stack_methods = ::alloc::vec::Vec::new()vec![];
2102 while let hir::ExprKind::MethodCall(_path_segment, rcvr_expr, _args, method_span) =
2103 source_expr.kind
2104 {
2105 if let Some(prev_match) = stack_methods.pop() {
2107 err.span_label(
2108 method_span,
2109 ::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}`"),
2110 );
2111 }
2112 let rcvr_ty = self.resolve_vars_if_possible(
2113 self.typeck_results
2114 .borrow()
2115 .expr_ty_adjusted_opt(rcvr_expr)
2116 .unwrap_or(Ty::new_misc_error(self.tcx)),
2117 );
2118
2119 let Ok(candidates) = self.probe_for_name_many(
2120 Mode::MethodCall,
2121 item_name,
2122 None,
2123 IsSuggestion(true),
2124 rcvr_ty,
2125 source_expr.hir_id,
2126 ProbeScope::TraitsInScope,
2127 ) else {
2128 return;
2129 };
2130
2131 for _matched_method in candidates {
2135 stack_methods.push(rcvr_ty);
2137 }
2138 source_expr = rcvr_expr;
2139 }
2140 if let Some(prev_match) = stack_methods.pop() {
2142 err.span_label(
2143 source_expr.span,
2144 ::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}`"),
2145 );
2146 }
2147 }
2148 }
2149
2150 fn find_likely_intended_associated_item(
2151 &self,
2152 err: &mut Diag<'_>,
2153 similar_candidate: ty::AssocItem,
2154 span: Span,
2155 args: Option<&'tcx [hir::Expr<'tcx>]>,
2156 mode: Mode,
2157 ) {
2158 let tcx = self.tcx;
2159 let def_kind = similar_candidate.as_def_kind();
2160 let an = self.tcx.def_kind_descr_article(def_kind, similar_candidate.def_id);
2161 let similar_candidate_name = similar_candidate.name();
2162 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!(
2163 "there is {an} {} `{}` with a similar name",
2164 self.tcx.def_kind_descr(def_kind, similar_candidate.def_id),
2165 similar_candidate_name,
2166 );
2167 if def_kind == DefKind::AssocFn {
2172 let ty_args = self.infcx.fresh_args_for_item(span, similar_candidate.def_id);
2173 let fn_sig = tcx.fn_sig(similar_candidate.def_id).instantiate(tcx, ty_args);
2174 let fn_sig = self.instantiate_binder_with_fresh_vars(
2175 span,
2176 BoundRegionConversionTime::FnCall,
2177 fn_sig,
2178 );
2179 if similar_candidate.is_method() {
2180 if let Some(args) = args
2181 && fn_sig.inputs()[1..].len() == args.len()
2182 {
2183 err.span_suggestion_verbose(
2186 span,
2187 msg,
2188 similar_candidate_name,
2189 Applicability::MaybeIncorrect,
2190 );
2191 } else {
2192 err.span_help(
2195 tcx.def_span(similar_candidate.def_id),
2196 ::alloc::__export::must_use({
::alloc::fmt::format(format_args!("{1}{0}",
if let None = args {
""
} else { ", but with different arguments" }, msg))
})format!(
2197 "{msg}{}",
2198 if let None = args { "" } else { ", but with different arguments" },
2199 ),
2200 );
2201 }
2202 } else if let Some(args) = args
2203 && fn_sig.inputs().len() == args.len()
2204 {
2205 err.span_suggestion_verbose(
2208 span,
2209 msg,
2210 similar_candidate_name,
2211 Applicability::MaybeIncorrect,
2212 );
2213 } else {
2214 err.span_help(tcx.def_span(similar_candidate.def_id), msg);
2215 }
2216 } else if let Mode::Path = mode
2217 && args.unwrap_or(&[]).is_empty()
2218 {
2219 err.span_suggestion_verbose(
2221 span,
2222 msg,
2223 similar_candidate_name,
2224 Applicability::MaybeIncorrect,
2225 );
2226 } else {
2227 err.span_help(tcx.def_span(similar_candidate.def_id), msg);
2230 }
2231 }
2232
2233 pub(crate) fn confusable_method_name(
2234 &self,
2235 err: &mut Diag<'_>,
2236 rcvr_ty: Ty<'tcx>,
2237 item_name: Ident,
2238 call_args: Option<Vec<Ty<'tcx>>>,
2239 ) -> Option<Symbol> {
2240 if let ty::Adt(adt, adt_args) = rcvr_ty.kind() {
2241 for inherent_impl_did in self.tcx.inherent_impls(adt.did()).into_iter() {
2242 for inherent_method in
2243 self.tcx.associated_items(inherent_impl_did).in_definition_order()
2244 {
2245 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)
2246 && candidates.contains(&item_name.name)
2247 && inherent_method.is_fn()
2248 {
2249 let args =
2250 ty::GenericArgs::identity_for_item(self.tcx, inherent_method.def_id)
2251 .rebase_onto(
2252 self.tcx,
2253 inherent_method.container_id(self.tcx),
2254 adt_args,
2255 );
2256 let fn_sig =
2257 self.tcx.fn_sig(inherent_method.def_id).instantiate(self.tcx, args);
2258 let fn_sig = self.instantiate_binder_with_fresh_vars(
2259 item_name.span,
2260 BoundRegionConversionTime::FnCall,
2261 fn_sig,
2262 );
2263 let name = inherent_method.name();
2264 if let Some(ref args) = call_args
2265 && fn_sig.inputs()[1..]
2266 .iter()
2267 .eq_by(args, |expected, found| self.may_coerce(*expected, *found))
2268 {
2269 err.span_suggestion_verbose(
2270 item_name.span,
2271 ::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),
2272 name,
2273 Applicability::MaybeIncorrect,
2274 );
2275 return Some(name);
2276 } else if let None = call_args {
2277 err.span_note(
2278 self.tcx.def_span(inherent_method.def_id),
2279 ::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),
2280 );
2281 return Some(name);
2282 }
2283 }
2284 }
2285 }
2286 }
2287 None
2288 }
2289 fn note_candidates_on_method_error(
2290 &self,
2291 rcvr_ty: Ty<'tcx>,
2292 item_name: Ident,
2293 self_source: SelfSource<'tcx>,
2294 args: Option<&'tcx [hir::Expr<'tcx>]>,
2295 span: Span,
2296 err: &mut Diag<'_>,
2297 sources: &mut Vec<CandidateSource>,
2298 sugg_span: Option<Span>,
2299 ) {
2300 sources.sort_by_key(|source| match source {
2301 CandidateSource::Trait(id) => (0, self.tcx.def_path_str(id)),
2302 CandidateSource::Impl(id) => (1, self.tcx.def_path_str(id)),
2303 });
2304 sources.dedup();
2305 let limit = if sources.len() == 5 { 5 } else { 4 };
2307
2308 let mut suggs = ::alloc::vec::Vec::new()vec![];
2309 for (idx, source) in sources.iter().take(limit).enumerate() {
2310 match *source {
2311 CandidateSource::Impl(impl_did) => {
2312 let Some(item) = self.associated_value(impl_did, item_name).or_else(|| {
2315 let impl_trait_id = self.tcx.impl_opt_trait_id(impl_did)?;
2316 self.associated_value(impl_trait_id, item_name)
2317 }) else {
2318 continue;
2319 };
2320
2321 let note_span = if item.def_id.is_local() {
2322 Some(self.tcx.def_span(item.def_id))
2323 } else if impl_did.is_local() {
2324 Some(self.tcx.def_span(impl_did))
2325 } else {
2326 None
2327 };
2328
2329 let impl_ty = self.tcx.at(span).type_of(impl_did).instantiate_identity();
2330
2331 let insertion = match self.tcx.impl_opt_trait_ref(impl_did) {
2332 None => String::new(),
2333 Some(trait_ref) => {
2334 ::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!(
2335 " of the trait `{}`",
2336 self.tcx.def_path_str(trait_ref.skip_binder().def_id)
2337 )
2338 }
2339 };
2340
2341 let (note_str, idx) = if sources.len() > 1 {
2342 (
2343 ::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!(
2344 "candidate #{} is defined in an impl{} for the type `{}`",
2345 idx + 1,
2346 insertion,
2347 impl_ty,
2348 ),
2349 Some(idx + 1),
2350 )
2351 } else {
2352 (
2353 ::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!(
2354 "the candidate is defined in an impl{insertion} for the type `{impl_ty}`",
2355 ),
2356 None,
2357 )
2358 };
2359 if let Some(note_span) = note_span {
2360 err.span_note(note_span, note_str);
2362 } else {
2363 err.note(note_str);
2364 }
2365 if let Some(sugg_span) = sugg_span
2366 && let Some(trait_ref) = self.tcx.impl_opt_trait_ref(impl_did)
2367 && let Some(sugg) = print_disambiguation_help(
2368 self.tcx,
2369 err,
2370 self_source,
2371 args,
2372 trait_ref
2373 .instantiate(
2374 self.tcx,
2375 self.fresh_args_for_item(sugg_span, impl_did),
2376 )
2377 .with_replaced_self_ty(self.tcx, rcvr_ty),
2378 idx,
2379 sugg_span,
2380 item,
2381 )
2382 {
2383 suggs.push(sugg);
2384 }
2385 }
2386 CandidateSource::Trait(trait_did) => {
2387 let Some(item) = self.associated_value(trait_did, item_name) else { continue };
2388 let item_span = self.tcx.def_span(item.def_id);
2389 let idx = if sources.len() > 1 {
2390 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!(
2391 "candidate #{} is defined in the trait `{}`",
2392 idx + 1,
2393 self.tcx.def_path_str(trait_did)
2394 );
2395 err.span_note(item_span, msg);
2396 Some(idx + 1)
2397 } else {
2398 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!(
2399 "the candidate is defined in the trait `{}`",
2400 self.tcx.def_path_str(trait_did)
2401 );
2402 err.span_note(item_span, msg);
2403 None
2404 };
2405 if let Some(sugg_span) = sugg_span
2406 && let Some(sugg) = print_disambiguation_help(
2407 self.tcx,
2408 err,
2409 self_source,
2410 args,
2411 ty::TraitRef::new_from_args(
2412 self.tcx,
2413 trait_did,
2414 self.fresh_args_for_item(sugg_span, trait_did),
2415 )
2416 .with_replaced_self_ty(self.tcx, rcvr_ty),
2417 idx,
2418 sugg_span,
2419 item,
2420 )
2421 {
2422 suggs.push(sugg);
2423 }
2424 }
2425 }
2426 }
2427 if !suggs.is_empty()
2428 && let Some(span) = sugg_span
2429 {
2430 suggs.sort();
2431 err.span_suggestions(
2432 span.with_hi(item_name.span.lo()),
2433 "use fully-qualified syntax to disambiguate",
2434 suggs,
2435 Applicability::MachineApplicable,
2436 );
2437 }
2438 if sources.len() > limit {
2439 err.note(::alloc::__export::must_use({
::alloc::fmt::format(format_args!("and {0} others",
sources.len() - limit))
})format!("and {} others", sources.len() - limit));
2440 }
2441 }
2442
2443 fn find_builder_fn(&self, err: &mut Diag<'_>, rcvr_ty: Ty<'tcx>, expr_id: hir::HirId) {
2446 let ty::Adt(adt_def, _) = rcvr_ty.kind() else {
2447 return;
2448 };
2449 let mut items = self
2450 .tcx
2451 .inherent_impls(adt_def.did())
2452 .iter()
2453 .flat_map(|i| self.tcx.associated_items(i).in_definition_order())
2454 .filter(|item| {
2457 #[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, .. })
2458 && self
2459 .probe_for_name(
2460 Mode::Path,
2461 item.ident(self.tcx),
2462 None,
2463 IsSuggestion(true),
2464 rcvr_ty,
2465 expr_id,
2466 ProbeScope::TraitsInScope,
2467 )
2468 .is_ok()
2469 })
2470 .filter_map(|item| {
2471 let ret_ty = self
2473 .tcx
2474 .fn_sig(item.def_id)
2475 .instantiate(self.tcx, self.fresh_args_for_item(DUMMY_SP, item.def_id))
2476 .output();
2477 let ret_ty = self.tcx.instantiate_bound_regions_with_erased(ret_ty);
2478 let ty::Adt(def, args) = ret_ty.kind() else {
2479 return None;
2480 };
2481 if self.can_eq(self.param_env, ret_ty, rcvr_ty) {
2483 return Some((item.def_id, ret_ty));
2484 }
2485 if ![self.tcx.lang_items().option_type(), self.tcx.get_diagnostic_item(sym::Result)]
2487 .contains(&Some(def.did()))
2488 {
2489 return None;
2490 }
2491 let arg = args.get(0)?.expect_ty();
2492 if self.can_eq(self.param_env, rcvr_ty, arg) {
2493 Some((item.def_id, ret_ty))
2494 } else {
2495 None
2496 }
2497 })
2498 .collect::<Vec<_>>();
2499 let post = if items.len() > 5 {
2500 let items_len = items.len();
2501 items.truncate(4);
2502 ::alloc::__export::must_use({
::alloc::fmt::format(format_args!("\nand {0} others", items_len - 4))
})format!("\nand {} others", items_len - 4)
2503 } else {
2504 String::new()
2505 };
2506 match &items[..] {
2507 [] => {}
2508 [(def_id, ret_ty)] => {
2509 err.span_note(
2510 self.tcx.def_span(def_id),
2511 ::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!(
2512 "if you're trying to build a new `{rcvr_ty}`, consider using `{}` which \
2513 returns `{ret_ty}`",
2514 self.tcx.def_path_str(def_id),
2515 ),
2516 );
2517 }
2518 _ => {
2519 let span: MultiSpan = items
2520 .iter()
2521 .map(|(def_id, _)| self.tcx.def_span(def_id))
2522 .collect::<Vec<Span>>()
2523 .into();
2524 err.span_note(
2525 span,
2526 ::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!(
2527 "if you're trying to build a new `{rcvr_ty}` consider using one of the \
2528 following associated functions:\n{}{post}",
2529 items
2530 .iter()
2531 .map(|(def_id, _ret_ty)| self.tcx.def_path_str(def_id))
2532 .collect::<Vec<String>>()
2533 .join("\n")
2534 ),
2535 );
2536 }
2537 }
2538 }
2539
2540 fn suggest_associated_call_syntax(
2543 &self,
2544 err: &mut Diag<'_>,
2545 static_candidates: &[CandidateSource],
2546 rcvr_ty: Ty<'tcx>,
2547 source: SelfSource<'tcx>,
2548 item_name: Ident,
2549 args: Option<&'tcx [hir::Expr<'tcx>]>,
2550 sugg_span: Span,
2551 ) {
2552 let mut has_unsuggestable_args = false;
2553 let ty_str = if let Some(CandidateSource::Impl(impl_did)) = static_candidates.get(0) {
2554 let impl_ty = self.tcx.type_of(*impl_did).instantiate_identity();
2558 let target_ty = self
2559 .autoderef(sugg_span, rcvr_ty)
2560 .silence_errors()
2561 .find(|(rcvr_ty, _)| {
2562 DeepRejectCtxt::relate_rigid_infer(self.tcx).types_may_unify(*rcvr_ty, impl_ty)
2563 })
2564 .map_or(impl_ty, |(ty, _)| ty)
2565 .peel_refs();
2566 if let ty::Adt(def, args) = target_ty.kind() {
2567 let infer_args = self.tcx.mk_args_from_iter(args.into_iter().map(|arg| {
2570 if !arg.is_suggestable(self.tcx, true) {
2571 has_unsuggestable_args = true;
2572 match arg.kind() {
2573 GenericArgKind::Lifetime(_) => {
2574 self.next_region_var(RegionVariableOrigin::Misc(DUMMY_SP)).into()
2575 }
2576 GenericArgKind::Type(_) => self.next_ty_var(DUMMY_SP).into(),
2577 GenericArgKind::Const(_) => self.next_const_var(DUMMY_SP).into(),
2578 }
2579 } else {
2580 arg
2581 }
2582 }));
2583
2584 self.tcx.value_path_str_with_args(def.did(), infer_args)
2585 } else {
2586 self.ty_to_value_string(target_ty)
2587 }
2588 } else {
2589 self.ty_to_value_string(rcvr_ty.peel_refs())
2590 };
2591 if let SelfSource::MethodCall(_) = source {
2592 let first_arg = static_candidates.get(0).and_then(|candidate_source| {
2593 let (assoc_did, self_ty) = match candidate_source {
2594 CandidateSource::Impl(impl_did) => {
2595 (*impl_did, self.tcx.type_of(*impl_did).instantiate_identity())
2596 }
2597 CandidateSource::Trait(trait_did) => (*trait_did, rcvr_ty),
2598 };
2599
2600 let assoc = self.associated_value(assoc_did, item_name)?;
2601 if !assoc.is_fn() {
2602 return None;
2603 }
2604
2605 let sig = self.tcx.fn_sig(assoc.def_id).instantiate_identity();
2608 sig.inputs().skip_binder().get(0).and_then(|first| {
2609 let first_ty = first.peel_refs();
2611 if first_ty == self_ty || first_ty == self.tcx.types.self_param {
2612 Some(first.ref_mutability().map_or("", |mutbl| mutbl.ref_prefix_str()))
2613 } else {
2614 None
2615 }
2616 })
2617 });
2618
2619 let mut applicability = Applicability::MachineApplicable;
2620 let args = if let SelfSource::MethodCall(receiver) = source
2621 && let Some(args) = args
2622 {
2623 let explicit_args = if first_arg.is_some() {
2625 std::iter::once(receiver).chain(args.iter()).collect::<Vec<_>>()
2626 } else {
2627 if has_unsuggestable_args {
2629 applicability = Applicability::HasPlaceholders;
2630 }
2631 args.iter().collect()
2632 };
2633 ::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!(
2634 "({}{})",
2635 first_arg.unwrap_or(""),
2636 explicit_args
2637 .iter()
2638 .map(|arg| self
2639 .tcx
2640 .sess
2641 .source_map()
2642 .span_to_snippet(arg.span)
2643 .unwrap_or_else(|_| {
2644 applicability = Applicability::HasPlaceholders;
2645 "_".to_owned()
2646 }))
2647 .collect::<Vec<_>>()
2648 .join(", "),
2649 )
2650 } else {
2651 applicability = Applicability::HasPlaceholders;
2652 "(...)".to_owned()
2653 };
2654 err.span_suggestion_verbose(
2655 sugg_span,
2656 "use associated function syntax instead",
2657 ::alloc::__export::must_use({
::alloc::fmt::format(format_args!("{0}::{1}{2}", ty_str, item_name,
args))
})format!("{ty_str}::{item_name}{args}"),
2658 applicability,
2659 );
2660 } else {
2661 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}`",));
2662 }
2663 }
2664
2665 fn suggest_calling_field_as_fn(
2668 &self,
2669 span: Span,
2670 rcvr_ty: Ty<'tcx>,
2671 expr: &hir::Expr<'_>,
2672 item_name: Ident,
2673 err: &mut Diag<'_>,
2674 ) -> bool {
2675 let tcx = self.tcx;
2676 let field_receiver =
2677 self.autoderef(span, rcvr_ty).silence_errors().find_map(|(ty, _)| match ty.kind() {
2678 ty::Adt(def, args) if !def.is_enum() => {
2679 let variant = &def.non_enum_variant();
2680 tcx.find_field_index(item_name, variant).map(|index| {
2681 let field = &variant.fields[index];
2682 let field_ty = field.ty(tcx, args);
2683 (field, field_ty)
2684 })
2685 }
2686 _ => None,
2687 });
2688 if let Some((field, field_ty)) = field_receiver {
2689 let scope = tcx.parent_module_from_def_id(self.body_id);
2690 let is_accessible = field.vis.is_accessible_from(scope, tcx);
2691
2692 if is_accessible {
2693 if let Some((what, _, _)) = self.extract_callable_info(field_ty) {
2694 let what = match what {
2695 DefIdOrName::DefId(def_id) => self.tcx.def_descr(def_id),
2696 DefIdOrName::Name(what) => what,
2697 };
2698 let expr_span = expr.span.to(item_name.span);
2699 err.multipart_suggestion(
2700 ::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!(
2701 "to call the {what} stored in `{item_name}`, \
2702 surround the field access with parentheses",
2703 ),
2704 <[_]>::into_vec(::alloc::boxed::box_new([(expr_span.shrink_to_lo(),
'('.to_string()),
(expr_span.shrink_to_hi(), ')'.to_string())]))vec![
2705 (expr_span.shrink_to_lo(), '('.to_string()),
2706 (expr_span.shrink_to_hi(), ')'.to_string()),
2707 ],
2708 Applicability::MachineApplicable,
2709 );
2710 } else {
2711 let call_expr = tcx.hir_expect_expr(tcx.parent_hir_id(expr.hir_id));
2712
2713 if let Some(span) = call_expr.span.trim_start(item_name.span) {
2714 err.span_suggestion(
2715 span,
2716 "remove the arguments",
2717 "",
2718 Applicability::MaybeIncorrect,
2719 );
2720 }
2721 }
2722 }
2723
2724 let field_kind = if is_accessible { "field" } else { "private field" };
2725 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"));
2726 return true;
2727 }
2728 false
2729 }
2730
2731 fn report_failed_method_call_on_range_end(
2734 &self,
2735 tcx: TyCtxt<'tcx>,
2736 actual: Ty<'tcx>,
2737 source: SelfSource<'tcx>,
2738 span: Span,
2739 item_name: Ident,
2740 ) -> Result<(), ErrorGuaranteed> {
2741 if let SelfSource::MethodCall(expr) = source {
2742 for (_, parent) in tcx.hir_parent_iter(expr.hir_id).take(5) {
2743 if let Node::Expr(parent_expr) = parent {
2744 if !is_range_literal(parent_expr) {
2745 continue;
2746 }
2747 let lang_item = match parent_expr.kind {
2748 ExprKind::Struct(qpath, _, _) => match tcx.qpath_lang_item(*qpath) {
2749 Some(
2750 lang_item @ (LangItem::Range
2751 | LangItem::RangeCopy
2752 | LangItem::RangeInclusiveCopy
2753 | LangItem::RangeTo
2754 | LangItem::RangeToInclusive),
2755 ) => Some(lang_item),
2756 _ => None,
2757 },
2758 ExprKind::Call(func, _) => match func.kind {
2759 ExprKind::Path(qpath)
2761 if tcx.qpath_is_lang_item(qpath, LangItem::RangeInclusiveNew) =>
2762 {
2763 Some(LangItem::RangeInclusiveStruct)
2764 }
2765 _ => None,
2766 },
2767 _ => None,
2768 };
2769
2770 if lang_item.is_none() {
2771 continue;
2772 }
2773
2774 let span_included = match parent_expr.kind {
2775 hir::ExprKind::Struct(_, eps, _) => {
2776 eps.last().is_some_and(|ep| ep.span.contains(span))
2777 }
2778 hir::ExprKind::Call(func, ..) => func.span.contains(span),
2780 _ => false,
2781 };
2782
2783 if !span_included {
2784 continue;
2785 }
2786
2787 let Some(range_def_id) =
2788 lang_item.and_then(|lang_item| self.tcx.lang_items().get(lang_item))
2789 else {
2790 continue;
2791 };
2792 let range_ty =
2793 self.tcx.type_of(range_def_id).instantiate(self.tcx, &[actual.into()]);
2794
2795 let pick = self.lookup_probe_for_diagnostic(
2796 item_name,
2797 range_ty,
2798 expr,
2799 ProbeScope::AllTraits,
2800 None,
2801 );
2802 if pick.is_ok() {
2803 let range_span = parent_expr.span.with_hi(expr.span.hi());
2804 return Err(self.dcx().emit_err(errors::MissingParenthesesInRange {
2805 span,
2806 ty: actual,
2807 method_name: item_name.as_str().to_string(),
2808 add_missing_parentheses: Some(errors::AddMissingParenthesesInRange {
2809 func_name: item_name.name.as_str().to_string(),
2810 left: range_span.shrink_to_lo(),
2811 right: range_span.shrink_to_hi(),
2812 }),
2813 }));
2814 }
2815 }
2816 }
2817 }
2818 Ok(())
2819 }
2820
2821 fn report_failed_method_call_on_numerical_infer_var(
2822 &self,
2823 tcx: TyCtxt<'tcx>,
2824 actual: Ty<'tcx>,
2825 source: SelfSource<'_>,
2826 span: Span,
2827 item_kind: &str,
2828 item_name: Ident,
2829 long_ty_path: &mut Option<PathBuf>,
2830 ) -> Result<(), ErrorGuaranteed> {
2831 let found_candidate = all_traits(self.tcx)
2832 .into_iter()
2833 .any(|info| self.associated_value(info.def_id, item_name).is_some());
2834 let found_assoc = |ty: Ty<'tcx>| {
2835 simplify_type(tcx, ty, TreatParams::InstantiateWithInfer)
2836 .and_then(|simp| {
2837 tcx.incoherent_impls(simp)
2838 .iter()
2839 .find_map(|&id| self.associated_value(id, item_name))
2840 })
2841 .is_some()
2842 };
2843 let found_candidate = found_candidate
2844 || found_assoc(tcx.types.i8)
2845 || found_assoc(tcx.types.i16)
2846 || found_assoc(tcx.types.i32)
2847 || found_assoc(tcx.types.i64)
2848 || found_assoc(tcx.types.i128)
2849 || found_assoc(tcx.types.u8)
2850 || found_assoc(tcx.types.u16)
2851 || found_assoc(tcx.types.u32)
2852 || found_assoc(tcx.types.u64)
2853 || found_assoc(tcx.types.u128)
2854 || found_assoc(tcx.types.f32)
2855 || found_assoc(tcx.types.f64);
2856 if found_candidate
2857 && actual.is_numeric()
2858 && !actual.has_concrete_skeleton()
2859 && let SelfSource::MethodCall(expr) = source
2860 {
2861 let ty_str = self.tcx.short_string(actual, long_ty_path);
2862 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!(
2863 self.dcx(),
2864 span,
2865 E0689,
2866 "can't call {item_kind} `{item_name}` on ambiguous numeric type `{ty_str}`"
2867 );
2868 *err.long_ty_path() = long_ty_path.take();
2869 let concrete_type = if actual.is_integral() { "i32" } else { "f32" };
2870 match expr.kind {
2871 ExprKind::Lit(lit) => {
2872 let snippet = tcx
2874 .sess
2875 .source_map()
2876 .span_to_snippet(lit.span)
2877 .unwrap_or_else(|_| "<numeric literal>".to_owned());
2878
2879 let snippet = snippet.trim_suffix('.');
2882 err.span_suggestion(
2883 lit.span,
2884 ::alloc::__export::must_use({
::alloc::fmt::format(format_args!("you must specify a concrete type for this numeric value, like `{0}`",
concrete_type))
})format!(
2885 "you must specify a concrete type for this numeric value, \
2886 like `{concrete_type}`"
2887 ),
2888 ::alloc::__export::must_use({
::alloc::fmt::format(format_args!("{0}_{1}", snippet, concrete_type))
})format!("{snippet}_{concrete_type}"),
2889 Applicability::MaybeIncorrect,
2890 );
2891 }
2892 ExprKind::Path(QPath::Resolved(_, path)) => {
2893 if let hir::def::Res::Local(hir_id) = path.res {
2895 let span = tcx.hir_span(hir_id);
2896 let filename = tcx.sess.source_map().span_to_filename(span);
2897
2898 let parent_node = self.tcx.parent_hir_node(hir_id);
2899 let msg = ::alloc::__export::must_use({
::alloc::fmt::format(format_args!("you must specify a type for this binding, like `{0}`",
concrete_type))
})format!(
2900 "you must specify a type for this binding, like `{concrete_type}`",
2901 );
2902
2903 match (filename, parent_node) {
2906 (
2907 FileName::Real(_),
2908 Node::LetStmt(hir::LetStmt {
2909 source: hir::LocalSource::Normal,
2910 ty,
2911 ..
2912 }),
2913 ) => {
2914 let type_span = ty
2915 .map(|ty| ty.span.with_lo(span.hi()))
2916 .unwrap_or(span.shrink_to_hi());
2917 err.span_suggestion(
2918 type_span,
2921 msg,
2922 ::alloc::__export::must_use({
::alloc::fmt::format(format_args!(": {0}", concrete_type))
})format!(": {concrete_type}"),
2923 Applicability::MaybeIncorrect,
2924 );
2925 }
2926 (FileName::Real(_), Node::Pat(pat))
2929 if let Node::Pat(binding_pat) = self.tcx.hir_node(hir_id)
2930 && let hir::PatKind::Binding(..) = binding_pat.kind
2931 && let Node::Pat(parent_pat) = parent_node
2932 && #[allow(non_exhaustive_omitted_patterns)] match parent_pat.kind {
hir::PatKind::Ref(..) => true,
_ => false,
}matches!(parent_pat.kind, hir::PatKind::Ref(..)) =>
2933 {
2934 err.span_label(span, "you must specify a type for this binding");
2935
2936 let mut ref_muts = Vec::new();
2937 let mut current_node = parent_node;
2938
2939 while let Node::Pat(parent_pat) = current_node {
2940 if let hir::PatKind::Ref(_, _, mutability) = parent_pat.kind {
2941 ref_muts.push(mutability);
2942 current_node = self.tcx.parent_hir_node(parent_pat.hir_id);
2943 } else {
2944 break;
2945 }
2946 }
2947
2948 let mut type_annotation = String::new();
2949 for mutability in ref_muts.iter().rev() {
2950 match mutability {
2951 hir::Mutability::Mut => type_annotation.push_str("&mut "),
2952 hir::Mutability::Not => type_annotation.push('&'),
2953 }
2954 }
2955 type_annotation.push_str(&concrete_type);
2956
2957 err.span_suggestion_verbose(
2958 pat.span.shrink_to_hi(),
2959 "specify the type in the closure argument list",
2960 ::alloc::__export::must_use({
::alloc::fmt::format(format_args!(": {0}", type_annotation))
})format!(": {type_annotation}"),
2961 Applicability::MaybeIncorrect,
2962 );
2963 }
2964 _ => {
2965 err.span_label(span, msg);
2966 }
2967 }
2968 }
2969 }
2970 _ => {}
2971 }
2972 return Err(err.emit());
2973 }
2974 Ok(())
2975 }
2976
2977 pub(crate) fn suggest_assoc_method_call(&self, segs: &[PathSegment<'_>]) {
2981 {
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:2981",
"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(2981u32),
::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);
2982 let [seg1, seg2] = segs else {
2983 return;
2984 };
2985 self.dcx().try_steal_modify_and_emit_err(
2986 seg1.ident.span,
2987 StashKey::CallAssocMethod,
2988 |err| {
2989 let body = self.tcx.hir_body_owned_by(self.body_id);
2990 struct LetVisitor {
2991 ident_name: Symbol,
2992 }
2993
2994 impl<'v> Visitor<'v> for LetVisitor {
2996 type Result = ControlFlow<Option<&'v hir::Expr<'v>>>;
2997 fn visit_stmt(&mut self, ex: &'v hir::Stmt<'v>) -> Self::Result {
2998 if let hir::StmtKind::Let(&hir::LetStmt { pat, init, .. }) = ex.kind
2999 && let hir::PatKind::Binding(_, _, ident, ..) = pat.kind
3000 && ident.name == self.ident_name
3001 {
3002 ControlFlow::Break(init)
3003 } else {
3004 hir::intravisit::walk_stmt(self, ex)
3005 }
3006 }
3007 }
3008
3009 if let Node::Expr(call_expr) = self.tcx.parent_hir_node(seg1.hir_id)
3010 && let ControlFlow::Break(Some(expr)) =
3011 (LetVisitor { ident_name: seg1.ident.name }).visit_body(body)
3012 && let Some(self_ty) = self.node_ty_opt(expr.hir_id)
3013 {
3014 let probe = self.lookup_probe_for_diagnostic(
3015 seg2.ident,
3016 self_ty,
3017 call_expr,
3018 ProbeScope::TraitsInScope,
3019 None,
3020 );
3021 if probe.is_ok() {
3022 let sm = self.infcx.tcx.sess.source_map();
3023 err.span_suggestion_verbose(
3024 sm.span_extend_while(seg1.ident.span.shrink_to_hi(), |c| c == ':')
3025 .unwrap(),
3026 "you may have meant to call an instance method",
3027 ".",
3028 Applicability::MaybeIncorrect,
3029 );
3030 }
3031 }
3032 },
3033 );
3034 }
3035
3036 fn suggest_calling_method_on_field(
3038 &self,
3039 err: &mut Diag<'_>,
3040 source: SelfSource<'tcx>,
3041 span: Span,
3042 actual: Ty<'tcx>,
3043 item_name: Ident,
3044 return_type: Option<Ty<'tcx>>,
3045 ) {
3046 if let SelfSource::MethodCall(expr) = source {
3047 let mod_id = self.tcx.parent_module(expr.hir_id).to_def_id();
3048 for fields in self.get_field_candidates_considering_privacy_for_diag(
3049 span,
3050 actual,
3051 mod_id,
3052 expr.hir_id,
3053 ) {
3054 let call_expr = self.tcx.hir_expect_expr(self.tcx.parent_hir_id(expr.hir_id));
3055
3056 let lang_items = self.tcx.lang_items();
3057 let never_mention_traits = [
3058 lang_items.clone_trait(),
3059 lang_items.deref_trait(),
3060 lang_items.deref_mut_trait(),
3061 self.tcx.get_diagnostic_item(sym::AsRef),
3062 self.tcx.get_diagnostic_item(sym::AsMut),
3063 self.tcx.get_diagnostic_item(sym::Borrow),
3064 self.tcx.get_diagnostic_item(sym::BorrowMut),
3065 ];
3066 let mut candidate_fields: Vec<_> = fields
3067 .into_iter()
3068 .filter_map(|candidate_field| {
3069 self.check_for_nested_field_satisfying_condition_for_diag(
3070 span,
3071 &|_, field_ty| {
3072 self.lookup_probe_for_diagnostic(
3073 item_name,
3074 field_ty,
3075 call_expr,
3076 ProbeScope::TraitsInScope,
3077 return_type,
3078 )
3079 .is_ok_and(|pick| {
3080 !never_mention_traits
3081 .iter()
3082 .flatten()
3083 .any(|def_id| self.tcx.parent(pick.item.def_id) == *def_id)
3084 })
3085 },
3086 candidate_field,
3087 ::alloc::vec::Vec::new()vec![],
3088 mod_id,
3089 expr.hir_id,
3090 )
3091 })
3092 .map(|field_path| {
3093 field_path
3094 .iter()
3095 .map(|id| id.to_string())
3096 .collect::<Vec<String>>()
3097 .join(".")
3098 })
3099 .collect();
3100 candidate_fields.sort();
3101
3102 let len = candidate_fields.len();
3103 if len > 0 {
3104 err.span_suggestions(
3105 item_name.span.shrink_to_lo(),
3106 ::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!(
3107 "{} of the expressions' fields {} a method of the same name",
3108 if len > 1 { "some" } else { "one" },
3109 if len > 1 { "have" } else { "has" },
3110 ),
3111 candidate_fields.iter().map(|path| ::alloc::__export::must_use({
::alloc::fmt::format(format_args!("{0}.", path))
})format!("{path}.")),
3112 Applicability::MaybeIncorrect,
3113 );
3114 }
3115 }
3116 }
3117 }
3118
3119 fn suggest_unwrapping_inner_self(
3120 &self,
3121 err: &mut Diag<'_>,
3122 source: SelfSource<'tcx>,
3123 actual: Ty<'tcx>,
3124 item_name: Ident,
3125 ) {
3126 let tcx = self.tcx;
3127 let SelfSource::MethodCall(expr) = source else {
3128 return;
3129 };
3130 let call_expr = tcx.hir_expect_expr(tcx.parent_hir_id(expr.hir_id));
3131
3132 let ty::Adt(kind, args) = actual.kind() else {
3133 return;
3134 };
3135 match kind.adt_kind() {
3136 ty::AdtKind::Enum => {
3137 let matching_variants: Vec<_> = kind
3138 .variants()
3139 .iter()
3140 .flat_map(|variant| {
3141 let [field] = &variant.fields.raw[..] else {
3142 return None;
3143 };
3144 let field_ty = field.ty(tcx, args);
3145
3146 if self.resolve_vars_if_possible(field_ty).is_ty_var() {
3148 return None;
3149 }
3150
3151 self.lookup_probe_for_diagnostic(
3152 item_name,
3153 field_ty,
3154 call_expr,
3155 ProbeScope::TraitsInScope,
3156 None,
3157 )
3158 .ok()
3159 .map(|pick| (variant, field, pick))
3160 })
3161 .collect();
3162
3163 let ret_ty_matches = |diagnostic_item| {
3164 if let Some(ret_ty) = self
3165 .ret_coercion
3166 .as_ref()
3167 .map(|c| self.resolve_vars_if_possible(c.borrow().expected_ty()))
3168 && let ty::Adt(kind, _) = ret_ty.kind()
3169 && tcx.get_diagnostic_item(diagnostic_item) == Some(kind.did())
3170 {
3171 true
3172 } else {
3173 false
3174 }
3175 };
3176
3177 match &matching_variants[..] {
3178 [(_, field, pick)] => {
3179 let self_ty = field.ty(tcx, args);
3180 err.span_note(
3181 tcx.def_span(pick.item.def_id),
3182 ::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}`"),
3183 );
3184 let (article, kind, variant, question) = if tcx.is_diagnostic_item(sym::Result, kind.did())
3185 && !tcx.hir_is_inside_const_context(expr.hir_id)
3187 {
3188 ("a", "Result", "Err", ret_ty_matches(sym::Result))
3189 } else if tcx.is_diagnostic_item(sym::Option, kind.did()) {
3190 ("an", "Option", "None", ret_ty_matches(sym::Option))
3191 } else {
3192 return;
3193 };
3194 if question {
3195 err.span_suggestion_verbose(
3196 expr.span.shrink_to_hi(),
3197 ::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!(
3198 "use the `?` operator to extract the `{self_ty}` value, propagating \
3199 {article} `{kind}::{variant}` value to the caller"
3200 ),
3201 "?",
3202 Applicability::MachineApplicable,
3203 );
3204 } else {
3205 err.span_suggestion_verbose(
3206 expr.span.shrink_to_hi(),
3207 ::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!(
3208 "consider using `{kind}::expect` to unwrap the `{self_ty}` value, \
3209 panicking if the value is {article} `{kind}::{variant}`"
3210 ),
3211 ".expect(\"REASON\")",
3212 Applicability::HasPlaceholders,
3213 );
3214 }
3215 }
3216 _ => {}
3218 }
3219 }
3220 ty::AdtKind::Struct | ty::AdtKind::Union => {
3223 let [first] = ***args else {
3224 return;
3225 };
3226 let ty::GenericArgKind::Type(ty) = first.kind() else {
3227 return;
3228 };
3229 let Ok(pick) = self.lookup_probe_for_diagnostic(
3230 item_name,
3231 ty,
3232 call_expr,
3233 ProbeScope::TraitsInScope,
3234 None,
3235 ) else {
3236 return;
3237 };
3238
3239 let name = self.ty_to_value_string(actual);
3240 let inner_id = kind.did();
3241 let mutable = if let Some(AutorefOrPtrAdjustment::Autoref { mutbl, .. }) =
3242 pick.autoref_or_ptr_adjustment
3243 {
3244 Some(mutbl)
3245 } else {
3246 None
3247 };
3248
3249 if tcx.is_diagnostic_item(sym::LocalKey, inner_id) {
3250 err.help("use `with` or `try_with` to access thread local storage");
3251 } else if tcx.is_lang_item(kind.did(), LangItem::MaybeUninit) {
3252 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!(
3253 "if this `{name}` has been initialized, \
3254 use one of the `assume_init` methods to access the inner value"
3255 ));
3256 } else if tcx.is_diagnostic_item(sym::RefCell, inner_id) {
3257 let (suggestion, borrow_kind, panic_if) = match mutable {
3258 Some(Mutability::Not) => (".borrow()", "borrow", "a mutable borrow exists"),
3259 Some(Mutability::Mut) => {
3260 (".borrow_mut()", "mutably borrow", "any borrows exist")
3261 }
3262 None => return,
3263 };
3264 err.span_suggestion_verbose(
3265 expr.span.shrink_to_hi(),
3266 ::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!(
3267 "use `{suggestion}` to {borrow_kind} the `{ty}`, \
3268 panicking if {panic_if}"
3269 ),
3270 suggestion,
3271 Applicability::MaybeIncorrect,
3272 );
3273 } else if tcx.is_diagnostic_item(sym::Mutex, inner_id) {
3274 err.span_suggestion_verbose(
3275 expr.span.shrink_to_hi(),
3276 ::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!(
3277 "use `.lock().unwrap()` to borrow the `{ty}`, \
3278 blocking the current thread until it can be acquired"
3279 ),
3280 ".lock().unwrap()",
3281 Applicability::MaybeIncorrect,
3282 );
3283 } else if tcx.is_diagnostic_item(sym::RwLock, inner_id) {
3284 let (suggestion, borrow_kind) = match mutable {
3285 Some(Mutability::Not) => (".read().unwrap()", "borrow"),
3286 Some(Mutability::Mut) => (".write().unwrap()", "mutably borrow"),
3287 None => return,
3288 };
3289 err.span_suggestion_verbose(
3290 expr.span.shrink_to_hi(),
3291 ::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!(
3292 "use `{suggestion}` to {borrow_kind} the `{ty}`, \
3293 blocking the current thread until it can be acquired"
3294 ),
3295 suggestion,
3296 Applicability::MaybeIncorrect,
3297 );
3298 } else {
3299 return;
3300 };
3301
3302 err.span_note(
3303 tcx.def_span(pick.item.def_id),
3304 ::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}`"),
3305 );
3306 }
3307 }
3308 }
3309
3310 pub(crate) fn note_unmet_impls_on_type(
3311 &self,
3312 err: &mut Diag<'_>,
3313 errors: &[FulfillmentError<'tcx>],
3314 suggest_derive: bool,
3315 ) {
3316 let preds: Vec<_> = errors
3317 .iter()
3318 .filter_map(|e| match e.obligation.predicate.kind().skip_binder() {
3319 ty::PredicateKind::Clause(ty::ClauseKind::Trait(pred)) => {
3320 match pred.self_ty().kind() {
3321 ty::Adt(_, _) => Some((e.root_obligation.predicate, pred)),
3322 _ => None,
3323 }
3324 }
3325 _ => None,
3326 })
3327 .collect();
3328
3329 let (mut local_preds, mut foreign_preds): (Vec<_>, Vec<_>) =
3331 preds.iter().partition(|&(_, pred)| {
3332 if let ty::Adt(def, _) = pred.self_ty().kind() {
3333 def.did().is_local()
3334 } else {
3335 false
3336 }
3337 });
3338
3339 local_preds.sort_by_key(|(_, pred)| pred.trait_ref.to_string());
3340 let local_def_ids = local_preds
3341 .iter()
3342 .filter_map(|(_, pred)| match pred.self_ty().kind() {
3343 ty::Adt(def, _) => Some(def.did()),
3344 _ => None,
3345 })
3346 .collect::<FxIndexSet<_>>();
3347 let mut local_spans: MultiSpan = local_def_ids
3348 .iter()
3349 .filter_map(|def_id| {
3350 let span = self.tcx.def_span(*def_id);
3351 if span.is_dummy() { None } else { Some(span) }
3352 })
3353 .collect::<Vec<_>>()
3354 .into();
3355 for (_, pred) in &local_preds {
3356 if let ty::Adt(def, _) = pred.self_ty().kind() {
3357 local_spans.push_span_label(
3358 self.tcx.def_span(def.did()),
3359 ::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()),
3360 );
3361 }
3362 }
3363 if local_spans.primary_span().is_some() {
3364 let msg = if let [(_, local_pred)] = local_preds.as_slice() {
3365 ::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!(
3366 "an implementation of `{}` might be missing for `{}`",
3367 local_pred.trait_ref.print_trait_sugared(),
3368 local_pred.self_ty()
3369 )
3370 } else {
3371 ::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!(
3372 "the following type{} would have to `impl` {} required trait{} for this \
3373 operation to be valid",
3374 pluralize!(local_def_ids.len()),
3375 if local_def_ids.len() == 1 { "its" } else { "their" },
3376 pluralize!(local_preds.len()),
3377 )
3378 };
3379 err.span_note(local_spans, msg);
3380 }
3381
3382 foreign_preds
3383 .sort_by_key(|(_, pred): &(_, ty::TraitPredicate<'_>)| pred.trait_ref.to_string());
3384
3385 for (_, pred) in &foreign_preds {
3386 let ty = pred.self_ty();
3387 let ty::Adt(def, _) = ty.kind() else { continue };
3388 let span = self.tcx.def_span(def.did());
3389 if span.is_dummy() {
3390 continue;
3391 }
3392 let mut mspan: MultiSpan = span.into();
3393 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"));
3394 err.span_note(
3395 mspan,
3396 ::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()),
3397 );
3398
3399 foreign_preds.iter().find(|&(root_pred, pred)| {
3400 if let ty::PredicateKind::Clause(ty::ClauseKind::Trait(root_pred)) =
3401 root_pred.kind().skip_binder()
3402 && let Some(root_adt) = root_pred.self_ty().ty_adt_def()
3403 {
3404 self.suggest_hashmap_on_unsatisfied_hashset_buildhasher(err, pred, root_adt)
3405 } else {
3406 false
3407 }
3408 });
3409 }
3410
3411 let preds: Vec<_> = errors
3412 .iter()
3413 .map(|e| (e.obligation.predicate, None, Some(e.obligation.cause.clone())))
3414 .collect();
3415 if suggest_derive {
3416 self.suggest_derive(err, &preds);
3417 } else {
3418 let _ = self.note_predicate_source_and_get_derives(err, &preds);
3420 }
3421 }
3422
3423 fn consider_suggesting_derives_for_ty(
3426 &self,
3427 trait_pred: ty::TraitPredicate<'tcx>,
3428 adt: ty::AdtDef<'tcx>,
3429 ) -> Option<Vec<(String, Span, Symbol)>> {
3430 let diagnostic_name = self.tcx.get_diagnostic_name(trait_pred.def_id())?;
3431
3432 let can_derive = match diagnostic_name {
3433 sym::Default
3434 | sym::Eq
3435 | sym::PartialEq
3436 | sym::Ord
3437 | sym::PartialOrd
3438 | sym::Clone
3439 | sym::Copy
3440 | sym::Hash
3441 | sym::Debug => true,
3442 _ => false,
3443 };
3444
3445 if !can_derive {
3446 return None;
3447 }
3448
3449 let trait_def_id = trait_pred.def_id();
3450 let self_ty = trait_pred.self_ty();
3451
3452 if self.tcx.non_blanket_impls_for_ty(trait_def_id, self_ty).any(|impl_def_id| {
3455 self.tcx
3456 .type_of(impl_def_id)
3457 .instantiate_identity()
3458 .ty_adt_def()
3459 .is_some_and(|def| def.did() == adt.did())
3460 }) {
3461 return None;
3462 }
3463
3464 let mut derives = Vec::new();
3465 let self_name = self_ty.to_string();
3466 let self_span = self.tcx.def_span(adt.did());
3467
3468 for super_trait in supertraits(self.tcx, ty::Binder::dummy(trait_pred.trait_ref)) {
3469 if let Some(parent_diagnostic_name) = self.tcx.get_diagnostic_name(super_trait.def_id())
3470 {
3471 derives.push((self_name.clone(), self_span, parent_diagnostic_name));
3472 }
3473 }
3474
3475 derives.push((self_name, self_span, diagnostic_name));
3476
3477 Some(derives)
3478 }
3479
3480 fn note_predicate_source_and_get_derives(
3481 &self,
3482 err: &mut Diag<'_>,
3483 unsatisfied_predicates: &UnsatisfiedPredicates<'tcx>,
3484 ) -> Vec<(String, Span, Symbol)> {
3485 let mut derives = Vec::new();
3486 let mut traits = Vec::new();
3487 for (pred, _, _) in unsatisfied_predicates {
3488 let Some(ty::PredicateKind::Clause(ty::ClauseKind::Trait(trait_pred))) =
3489 pred.kind().no_bound_vars()
3490 else {
3491 continue;
3492 };
3493 let adt = match trait_pred.self_ty().ty_adt_def() {
3494 Some(adt) if adt.did().is_local() => adt,
3495 _ => continue,
3496 };
3497 if let Some(new_derives) = self.consider_suggesting_derives_for_ty(trait_pred, adt) {
3498 derives.extend(new_derives);
3499 } else {
3500 traits.push(trait_pred.def_id());
3501 }
3502 }
3503 traits.sort_by_key(|id| self.tcx.def_path_str(id));
3504 traits.dedup();
3505
3506 let len = traits.len();
3507 if len > 0 {
3508 let span =
3509 MultiSpan::from_spans(traits.iter().map(|&did| self.tcx.def_span(did)).collect());
3510 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]));
3511 for (i, &did) in traits.iter().enumerate().skip(1) {
3512 if len > 2 {
3513 names.push_str(", ");
3514 }
3515 if i == len - 1 {
3516 names.push_str(" and ");
3517 }
3518 names.push('`');
3519 names.push_str(&self.tcx.def_path_str(did));
3520 names.push('`');
3521 }
3522 err.span_note(
3523 span,
3524 ::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),
3525 );
3526 }
3527
3528 derives
3529 }
3530
3531 pub(crate) fn suggest_derive(
3532 &self,
3533 err: &mut Diag<'_>,
3534 unsatisfied_predicates: &UnsatisfiedPredicates<'tcx>,
3535 ) -> bool {
3536 let mut derives = self.note_predicate_source_and_get_derives(err, unsatisfied_predicates);
3537 derives.sort();
3538 derives.dedup();
3539
3540 let mut derives_grouped = Vec::<(String, Span, String)>::new();
3541 for (self_name, self_span, trait_name) in derives.into_iter() {
3542 if let Some((last_self_name, _, last_trait_names)) = derives_grouped.last_mut() {
3543 if last_self_name == &self_name {
3544 last_trait_names.push_str(::alloc::__export::must_use({
::alloc::fmt::format(format_args!(", {0}", trait_name))
})format!(", {trait_name}").as_str());
3545 continue;
3546 }
3547 }
3548 derives_grouped.push((self_name, self_span, trait_name.to_string()));
3549 }
3550
3551 for (self_name, self_span, traits) in &derives_grouped {
3552 err.span_suggestion_verbose(
3553 self_span.shrink_to_lo(),
3554 ::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})]`"),
3555 ::alloc::__export::must_use({
::alloc::fmt::format(format_args!("#[derive({0})]\n", traits))
})format!("#[derive({traits})]\n"),
3556 Applicability::MaybeIncorrect,
3557 );
3558 }
3559 !derives_grouped.is_empty()
3560 }
3561
3562 fn note_derefed_ty_has_method(
3563 &self,
3564 err: &mut Diag<'_>,
3565 self_source: SelfSource<'tcx>,
3566 rcvr_ty: Ty<'tcx>,
3567 item_name: Ident,
3568 expected: Expectation<'tcx>,
3569 ) {
3570 let SelfSource::QPath(ty) = self_source else {
3571 return;
3572 };
3573 for (deref_ty, _) in self.autoderef(DUMMY_SP, rcvr_ty).silence_errors().skip(1) {
3574 if let Ok(pick) = self.probe_for_name(
3575 Mode::Path,
3576 item_name,
3577 expected.only_has_type(self),
3578 IsSuggestion(true),
3579 deref_ty,
3580 ty.hir_id,
3581 ProbeScope::TraitsInScope,
3582 ) {
3583 if deref_ty.is_suggestable(self.tcx, true)
3584 && pick.item.is_method()
3588 && let Some(self_ty) =
3589 self.tcx.fn_sig(pick.item.def_id).instantiate_identity().inputs().skip_binder().get(0)
3590 && self_ty.is_ref()
3591 {
3592 let suggested_path = match deref_ty.kind() {
3593 ty::Bool
3594 | ty::Char
3595 | ty::Int(_)
3596 | ty::Uint(_)
3597 | ty::Float(_)
3598 | ty::Adt(_, _)
3599 | ty::Str
3600 | ty::Alias(ty::Projection | ty::Inherent, _)
3601 | ty::Param(_) => ::alloc::__export::must_use({
::alloc::fmt::format(format_args!("{0}", deref_ty))
})format!("{deref_ty}"),
3602 _ if self
3608 .tcx
3609 .sess
3610 .source_map()
3611 .span_wrapped_by_angle_or_parentheses(ty.span) =>
3612 {
3613 ::alloc::__export::must_use({
::alloc::fmt::format(format_args!("{0}", deref_ty))
})format!("{deref_ty}")
3614 }
3615 _ => ::alloc::__export::must_use({
::alloc::fmt::format(format_args!("<{0}>", deref_ty))
})format!("<{deref_ty}>"),
3616 };
3617 err.span_suggestion_verbose(
3618 ty.span,
3619 ::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}`"),
3620 suggested_path,
3621 Applicability::MaybeIncorrect,
3622 );
3623 } else {
3624 err.span_note(
3625 ty.span,
3626 ::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}`"),
3627 );
3628 }
3629 return;
3630 }
3631 }
3632 }
3633
3634 fn suggest_bounds_for_range_to_method(
3635 &self,
3636 err: &mut Diag<'_>,
3637 source: SelfSource<'tcx>,
3638 item_ident: Ident,
3639 ) {
3640 let SelfSource::MethodCall(rcvr_expr) = source else { return };
3641 let hir::ExprKind::Struct(qpath, fields, _) = rcvr_expr.kind else { return };
3642 let Some(lang_item) = self.tcx.qpath_lang_item(*qpath) else {
3643 return;
3644 };
3645 let is_inclusive = match lang_item {
3646 hir::LangItem::RangeTo => false,
3647 hir::LangItem::RangeToInclusive | hir::LangItem::RangeInclusiveCopy => true,
3648 _ => return,
3649 };
3650
3651 let Some(iterator_trait) = self.tcx.get_diagnostic_item(sym::Iterator) else { return };
3652 let Some(_) = self
3653 .tcx
3654 .associated_items(iterator_trait)
3655 .filter_by_name_unhygienic(item_ident.name)
3656 .next()
3657 else {
3658 return;
3659 };
3660
3661 let source_map = self.tcx.sess.source_map();
3662 let range_type = if is_inclusive { "RangeInclusive" } else { "Range" };
3663 let Some(end_field) = fields.iter().find(|f| f.ident.name == rustc_span::sym::end) else {
3664 return;
3665 };
3666
3667 let element_ty = self.typeck_results.borrow().expr_ty_opt(end_field.expr);
3668 let is_integral = element_ty.is_some_and(|ty| ty.is_integral());
3669 let end_is_negative = is_integral
3670 && #[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, _));
3671
3672 let Ok(snippet) = source_map.span_to_snippet(rcvr_expr.span) else { return };
3673
3674 let offset = snippet
3675 .chars()
3676 .take_while(|&c| c == '(' || c.is_whitespace())
3677 .map(|c| c.len_utf8())
3678 .sum::<usize>();
3679
3680 let insert_span = rcvr_expr
3681 .span
3682 .with_lo(rcvr_expr.span.lo() + rustc_span::BytePos(offset as u32))
3683 .shrink_to_lo();
3684
3685 let (value, appl) = if is_integral && !end_is_negative {
3686 ("0", Applicability::MachineApplicable)
3687 } else {
3688 ("/* start */", Applicability::HasPlaceholders)
3689 };
3690
3691 err.span_suggestion_verbose(
3692 insert_span,
3693 ::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"),
3694 value,
3695 appl,
3696 );
3697 }
3698
3699 fn ty_to_value_string(&self, ty: Ty<'tcx>) -> String {
3701 match ty.kind() {
3702 ty::Adt(def, args) => self.tcx.def_path_str_with_args(def.did(), args),
3703 _ => self.ty_to_string(ty),
3704 }
3705 }
3706
3707 fn suggest_await_before_method(
3708 &self,
3709 err: &mut Diag<'_>,
3710 item_name: Ident,
3711 ty: Ty<'tcx>,
3712 call: &hir::Expr<'_>,
3713 span: Span,
3714 return_type: Option<Ty<'tcx>>,
3715 ) {
3716 let Some(output_ty) = self.err_ctxt().get_impl_future_output_ty(ty) else { return };
3717 let output_ty = self.resolve_vars_if_possible(output_ty);
3718 let method_exists =
3719 self.method_exists_for_diagnostic(item_name, output_ty, call.hir_id, return_type);
3720 {
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:3720",
"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(3720u32),
::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);
3721 if method_exists {
3722 err.span_suggestion_verbose(
3723 span.shrink_to_lo(),
3724 "consider `await`ing on the `Future` and calling the method on its `Output`",
3725 "await.",
3726 Applicability::MaybeIncorrect,
3727 );
3728 }
3729 }
3730
3731 fn set_label_for_method_error(
3732 &self,
3733 err: &mut Diag<'_>,
3734 source: SelfSource<'tcx>,
3735 rcvr_ty: Ty<'tcx>,
3736 item_ident: Ident,
3737 expr_id: hir::HirId,
3738 span: Span,
3739 sugg_span: Span,
3740 within_macro_span: Option<Span>,
3741 args: Option<&'tcx [hir::Expr<'tcx>]>,
3742 ) {
3743 let tcx = self.tcx;
3744 if tcx.sess.source_map().is_multiline(sugg_span) {
3745 err.span_label(sugg_span.with_hi(span.lo()), "");
3746 }
3747 if let Some(within_macro_span) = within_macro_span {
3748 err.span_label(within_macro_span, "due to this macro variable");
3749 }
3750
3751 if #[allow(non_exhaustive_omitted_patterns)] match source {
SelfSource::QPath(_) => true,
_ => false,
}matches!(source, SelfSource::QPath(_)) && args.is_some() {
3752 self.find_builder_fn(err, rcvr_ty, expr_id);
3753 }
3754
3755 if tcx.ty_is_opaque_future(rcvr_ty) && item_ident.name == sym::poll {
3756 let ty_str = self.tcx.short_string(rcvr_ty, err.long_ty_path());
3757 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!(
3758 "method `poll` found on `Pin<&mut {ty_str}>`, \
3759 see documentation for `std::pin::Pin`"
3760 ));
3761 err.help("self type must be pinned to call `Future::poll`, \
3762 see https://rust-lang.github.io/async-book/04_pinning/01_chapter.html#pinning-in-practice"
3763 );
3764 }
3765
3766 if let Some(span) =
3767 tcx.resolutions(()).confused_type_with_std_module.get(&span.with_parent(None))
3768 {
3769 err.span_suggestion(
3770 span.shrink_to_lo(),
3771 "you are looking for the module in `std`, not the primitive type",
3772 "std::",
3773 Applicability::MachineApplicable,
3774 );
3775 }
3776 }
3777
3778 fn suggest_on_pointer_type(
3779 &self,
3780 err: &mut Diag<'_>,
3781 source: SelfSource<'tcx>,
3782 rcvr_ty: Ty<'tcx>,
3783 item_ident: Ident,
3784 ) {
3785 let tcx = self.tcx;
3786 if let SelfSource::MethodCall(rcvr_expr) = source
3788 && let ty::RawPtr(ty, ptr_mutbl) = *rcvr_ty.kind()
3789 && let Ok(pick) = self.lookup_probe_for_diagnostic(
3790 item_ident,
3791 Ty::new_ref(tcx, ty::Region::new_error_misc(tcx), ty, ptr_mutbl),
3792 self.tcx.hir_expect_expr(self.tcx.parent_hir_id(rcvr_expr.hir_id)),
3793 ProbeScope::TraitsInScope,
3794 None,
3795 )
3796 && let ty::Ref(_, _, sugg_mutbl) = *pick.self_ty.kind()
3797 && (sugg_mutbl.is_not() || ptr_mutbl.is_mut())
3798 {
3799 let (method, method_anchor) = match sugg_mutbl {
3800 Mutability::Not => {
3801 let method_anchor = match ptr_mutbl {
3802 Mutability::Not => "as_ref",
3803 Mutability::Mut => "as_ref-1",
3804 };
3805 ("as_ref", method_anchor)
3806 }
3807 Mutability::Mut => ("as_mut", "as_mut"),
3808 };
3809 err.span_note(
3810 tcx.def_span(pick.item.def_id),
3811 ::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),
3812 );
3813 let mut_str = ptr_mutbl.ptr_str();
3814 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!(
3815 "you might want to use the unsafe method `<*{mut_str} T>::{method}` to get \
3816 an optional reference to the value behind the pointer"
3817 ));
3818 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!(
3819 "read the documentation for `<*{mut_str} T>::{method}` and ensure you satisfy its \
3820 safety preconditions before calling it to avoid undefined behavior: \
3821 https://doc.rust-lang.org/std/primitive.pointer.html#method.{method_anchor}"
3822 ));
3823 }
3824 }
3825
3826 fn suggest_use_candidates<F>(&self, candidates: Vec<DefId>, handle_candidates: F)
3827 where
3828 F: FnOnce(Vec<String>, Vec<String>, Span),
3829 {
3830 let parent_map = self.tcx.visible_parent_map(());
3831
3832 let scope = self.tcx.parent_module_from_def_id(self.body_id);
3833 let (accessible_candidates, inaccessible_candidates): (Vec<_>, Vec<_>) =
3834 candidates.into_iter().partition(|id| {
3835 let vis = self.tcx.visibility(*id);
3836 vis.is_accessible_from(scope, self.tcx)
3837 });
3838
3839 let sugg = |candidates: Vec<_>, visible| {
3840 let (candidates, globs): (Vec<_>, Vec<_>) =
3843 candidates.into_iter().partition(|trait_did| {
3844 if let Some(parent_did) = parent_map.get(trait_did) {
3845 if *parent_did != self.tcx.parent(*trait_did)
3847 && self
3848 .tcx
3849 .module_children(*parent_did)
3850 .iter()
3851 .filter(|child| child.res.opt_def_id() == Some(*trait_did))
3852 .all(|child| child.ident.name == kw::Underscore)
3853 {
3854 return false;
3855 }
3856 }
3857
3858 true
3859 });
3860
3861 let prefix = if visible { "use " } else { "" };
3862 let postfix = if visible { ";" } else { "" };
3863 let path_strings = candidates.iter().map(|trait_did| {
3864 ::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!(
3865 "{prefix}{}{postfix}\n",
3866 with_no_visible_paths_if_doc_hidden!(with_crate_prefix!(
3867 self.tcx.def_path_str(*trait_did)
3868 )),
3869 )
3870 });
3871
3872 let glob_path_strings = globs.iter().map(|trait_did| {
3873 let parent_did = parent_map.get(trait_did).unwrap();
3874 ::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!(
3875 "{prefix}{}::*{postfix} // trait {}\n",
3876 with_no_visible_paths_if_doc_hidden!(with_crate_prefix!(
3877 self.tcx.def_path_str(*parent_did)
3878 )),
3879 self.tcx.item_name(*trait_did),
3880 )
3881 });
3882 let mut sugg: Vec<_> = path_strings.chain(glob_path_strings).collect();
3883 sugg.sort();
3884 sugg
3885 };
3886
3887 let accessible_sugg = sugg(accessible_candidates, true);
3888 let inaccessible_sugg = sugg(inaccessible_candidates, false);
3889
3890 let (module, _, _) = self.tcx.hir_get_module(scope);
3891 let span = module.spans.inject_use_span;
3892 handle_candidates(accessible_sugg, inaccessible_sugg, span);
3893 }
3894
3895 fn suggest_valid_traits(
3896 &self,
3897 err: &mut Diag<'_>,
3898 item_name: Ident,
3899 mut valid_out_of_scope_traits: Vec<DefId>,
3900 explain: bool,
3901 ) -> bool {
3902 valid_out_of_scope_traits.retain(|id| self.tcx.is_user_visible_dep(id.krate));
3903 if !valid_out_of_scope_traits.is_empty() {
3904 let mut candidates = valid_out_of_scope_traits;
3905 candidates.sort_by_key(|id| self.tcx.def_path_str(id));
3906 candidates.dedup();
3907
3908 let edition_fix = candidates
3910 .iter()
3911 .find(|did| self.tcx.is_diagnostic_item(sym::TryInto, **did))
3912 .copied();
3913
3914 if explain {
3915 err.help("items from traits can only be used if the trait is in scope");
3916 }
3917
3918 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!(
3919 "{this_trait_is} implemented but not in scope",
3920 this_trait_is = if candidates.len() == 1 {
3921 format!(
3922 "trait `{}` which provides `{item_name}` is",
3923 self.tcx.item_name(candidates[0]),
3924 )
3925 } else {
3926 format!("the following traits which provide `{item_name}` are")
3927 }
3928 );
3929
3930 self.suggest_use_candidates(candidates, |accessible_sugg, inaccessible_sugg, span| {
3931 let suggest_for_access = |err: &mut Diag<'_>, mut msg: String, suggs: Vec<_>| {
3932 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!(
3933 "; perhaps you want to import {one_of}",
3934 one_of = if suggs.len() == 1 { "it" } else { "one of them" },
3935 );
3936 err.span_suggestions(span, msg, suggs, Applicability::MaybeIncorrect);
3937 };
3938 let suggest_for_privacy = |err: &mut Diag<'_>, suggs: Vec<String>| {
3939 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!(
3940 "{this_trait_is} implemented but not reachable",
3941 this_trait_is = if let [sugg] = suggs.as_slice() {
3942 format!("trait `{}` which provides `{item_name}` is", sugg.trim())
3943 } else {
3944 format!("the following traits which provide `{item_name}` are")
3945 }
3946 );
3947 if suggs.len() == 1 {
3948 err.help(msg);
3949 } else {
3950 err.span_suggestions(span, msg, suggs, Applicability::MaybeIncorrect);
3951 }
3952 };
3953 if accessible_sugg.is_empty() {
3954 suggest_for_privacy(err, inaccessible_sugg);
3956 } else if inaccessible_sugg.is_empty() {
3957 suggest_for_access(err, msg, accessible_sugg);
3958 } else {
3959 suggest_for_access(err, msg, accessible_sugg);
3960 suggest_for_privacy(err, inaccessible_sugg);
3961 }
3962 });
3963
3964 if let Some(did) = edition_fix {
3965 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!(
3966 "'{}' is included in the prelude starting in Edition 2021",
3967 with_crate_prefix!(self.tcx.def_path_str(did))
3968 ));
3969 }
3970
3971 true
3972 } else {
3973 false
3974 }
3975 }
3976
3977 fn suggest_traits_to_import(
3978 &self,
3979 err: &mut Diag<'_>,
3980 span: Span,
3981 rcvr_ty: Ty<'tcx>,
3982 item_name: Ident,
3983 inputs_len: Option<usize>,
3984 source: SelfSource<'tcx>,
3985 valid_out_of_scope_traits: Vec<DefId>,
3986 static_candidates: &[CandidateSource],
3987 unsatisfied_bounds: bool,
3988 return_type: Option<Ty<'tcx>>,
3989 trait_missing_method: bool,
3990 ) {
3991 let mut alt_rcvr_sugg = false;
3992 let mut trait_in_other_version_found = false;
3993 if let (SelfSource::MethodCall(rcvr), false) = (source, unsatisfied_bounds) {
3994 {
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:3994",
"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(3994u32),
::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!(
3995 "suggest_traits_to_import: span={:?}, item_name={:?}, rcvr_ty={:?}, rcvr={:?}",
3996 span, item_name, rcvr_ty, rcvr
3997 );
3998 let skippable = [
3999 self.tcx.lang_items().clone_trait(),
4000 self.tcx.lang_items().deref_trait(),
4001 self.tcx.lang_items().deref_mut_trait(),
4002 self.tcx.lang_items().drop_trait(),
4003 self.tcx.get_diagnostic_item(sym::AsRef),
4004 ];
4005 for (rcvr_ty, post, pin_call) in &[
4009 (rcvr_ty, "", None),
4010 (
4011 Ty::new_mut_ref(self.tcx, self.tcx.lifetimes.re_erased, rcvr_ty),
4012 "&mut ",
4013 Some("as_mut"),
4014 ),
4015 (
4016 Ty::new_imm_ref(self.tcx, self.tcx.lifetimes.re_erased, rcvr_ty),
4017 "&",
4018 Some("as_ref"),
4019 ),
4020 ] {
4021 match self.lookup_probe_for_diagnostic(
4022 item_name,
4023 *rcvr_ty,
4024 rcvr,
4025 ProbeScope::AllTraits,
4026 return_type,
4027 ) {
4028 Ok(pick) => {
4029 let did = Some(pick.item.container_id(self.tcx));
4034 if skippable.contains(&did) {
4035 continue;
4036 }
4037 trait_in_other_version_found = self
4038 .detect_and_explain_multiple_crate_versions_of_trait_item(
4039 err,
4040 pick.item.def_id,
4041 rcvr.hir_id,
4042 Some(*rcvr_ty),
4043 );
4044 if pick.autoderefs == 0 && !trait_in_other_version_found {
4045 err.span_label(
4046 pick.item.ident(self.tcx).span,
4047 ::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"),
4048 );
4049 }
4050 break;
4051 }
4052 Err(MethodError::Ambiguity(_)) => {
4053 break;
4058 }
4059 Err(_) => (),
4060 }
4061
4062 let Some(unpin_trait) = self.tcx.lang_items().unpin_trait() else {
4063 return;
4064 };
4065 let pred = ty::TraitRef::new(self.tcx, unpin_trait, [*rcvr_ty]);
4066 let unpin = self.predicate_must_hold_considering_regions(&Obligation::new(
4067 self.tcx,
4068 self.misc(rcvr.span),
4069 self.param_env,
4070 pred,
4071 ));
4072 for (rcvr_ty, pre) in &[
4073 (Ty::new_lang_item(self.tcx, *rcvr_ty, LangItem::OwnedBox), "Box::new"),
4074 (Ty::new_lang_item(self.tcx, *rcvr_ty, LangItem::Pin), "Pin::new"),
4075 (Ty::new_diagnostic_item(self.tcx, *rcvr_ty, sym::Arc), "Arc::new"),
4076 (Ty::new_diagnostic_item(self.tcx, *rcvr_ty, sym::Rc), "Rc::new"),
4077 ] {
4078 if let Some(new_rcvr_t) = *rcvr_ty
4079 && let Ok(pick) = self.lookup_probe_for_diagnostic(
4080 item_name,
4081 new_rcvr_t,
4082 rcvr,
4083 ProbeScope::AllTraits,
4084 return_type,
4085 )
4086 {
4087 {
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:4087",
"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(4087u32),
::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);
4088 let did = pick.item.trait_container(self.tcx);
4089 let skip = skippable.contains(&did)
4095 || (("Pin::new" == *pre)
4096 && ((sym::as_ref == item_name.name) || !unpin))
4097 || inputs_len.is_some_and(|inputs_len| {
4098 pick.item.is_fn()
4099 && self
4100 .tcx
4101 .fn_sig(pick.item.def_id)
4102 .skip_binder()
4103 .skip_binder()
4104 .inputs()
4105 .len()
4106 != inputs_len
4107 });
4108 if pick.autoderefs == 0 && !skip {
4112 err.span_label(
4113 pick.item.ident(self.tcx).span,
4114 ::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"),
4115 );
4116 err.multipart_suggestion(
4117 "consider wrapping the receiver expression with the \
4118 appropriate type",
4119 <[_]>::into_vec(::alloc::boxed::box_new([(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![
4120 (rcvr.span.shrink_to_lo(), format!("{pre}({post}")),
4121 (rcvr.span.shrink_to_hi(), ")".to_string()),
4122 ],
4123 Applicability::MaybeIncorrect,
4124 );
4125 alt_rcvr_sugg = true;
4127 }
4128 }
4129 }
4130 if let Some(new_rcvr_t) = Ty::new_lang_item(self.tcx, *rcvr_ty, LangItem::Pin)
4133 && !alt_rcvr_sugg
4135 && !unpin
4137 && let Some(pin_call) = pin_call
4139 && let Ok(pick) = self.lookup_probe_for_diagnostic(
4141 item_name,
4142 new_rcvr_t,
4143 rcvr,
4144 ProbeScope::AllTraits,
4145 return_type,
4146 )
4147 && !skippable.contains(&Some(pick.item.container_id(self.tcx)))
4150 && pick.item.impl_container(self.tcx).is_none_or(|did| {
4152 match self.tcx.type_of(did).skip_binder().kind() {
4153 ty::Adt(def, _) => Some(def.did()) != self.tcx.lang_items().pin_type(),
4154 _ => true,
4155 }
4156 })
4157 && pick.autoderefs == 0
4159 && 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)
4162 {
4163 let indent = self
4164 .tcx
4165 .sess
4166 .source_map()
4167 .indentation_before(rcvr.span)
4168 .unwrap_or_else(|| " ".to_string());
4169 let mut expr = rcvr;
4170 while let Node::Expr(call_expr) = self.tcx.parent_hir_node(expr.hir_id)
4171 && let hir::ExprKind::MethodCall(hir::PathSegment { .. }, ..) =
4172 call_expr.kind
4173 {
4174 expr = call_expr;
4175 }
4176 match self.tcx.parent_hir_node(expr.hir_id) {
4177 Node::LetStmt(stmt)
4178 if let Some(init) = stmt.init
4179 && let Ok(code) =
4180 self.tcx.sess.source_map().span_to_snippet(rcvr.span) =>
4181 {
4182 err.multipart_suggestion(
4185 "consider pinning the expression",
4186 <[_]>::into_vec(::alloc::boxed::box_new([(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![
4187 (
4188 stmt.span.shrink_to_lo(),
4189 format!(
4190 "let mut pinned = std::pin::pin!({code});\n{indent}"
4191 ),
4192 ),
4193 (
4194 init.span.until(rcvr.span.shrink_to_hi()),
4195 format!("pinned.{pin_call}()"),
4196 ),
4197 ],
4198 Applicability::MaybeIncorrect,
4199 );
4200 }
4201 Node::Block(_) | Node::Stmt(_) => {
4202 err.multipart_suggestion(
4205 "consider pinning the expression",
4206 <[_]>::into_vec(::alloc::boxed::box_new([(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![
4207 (
4208 rcvr.span.shrink_to_lo(),
4209 "let mut pinned = std::pin::pin!(".to_string(),
4210 ),
4211 (
4212 rcvr.span.shrink_to_hi(),
4213 format!(");\n{indent}pinned.{pin_call}()"),
4214 ),
4215 ],
4216 Applicability::MaybeIncorrect,
4217 );
4218 }
4219 _ => {
4220 err.span_help(
4223 rcvr.span,
4224 "consider pinning the expression with `std::pin::pin!()` and \
4225 assigning that to a new binding",
4226 );
4227 }
4228 }
4229 alt_rcvr_sugg = true;
4231 }
4232 }
4233 }
4234
4235 if let SelfSource::QPath(ty) = source
4236 && !valid_out_of_scope_traits.is_empty()
4237 && let hir::TyKind::Path(path) = ty.kind
4238 && let hir::QPath::Resolved(..) = path
4239 && let Some(assoc) = self
4240 .tcx
4241 .associated_items(valid_out_of_scope_traits[0])
4242 .filter_by_name_unhygienic(item_name.name)
4243 .next()
4244 {
4245 let rcvr_ty = self.node_ty_opt(ty.hir_id);
4250 trait_in_other_version_found = self
4251 .detect_and_explain_multiple_crate_versions_of_trait_item(
4252 err,
4253 assoc.def_id,
4254 ty.hir_id,
4255 rcvr_ty,
4256 );
4257 }
4258 if !trait_in_other_version_found
4259 && self.suggest_valid_traits(err, item_name, valid_out_of_scope_traits, true)
4260 {
4261 return;
4262 }
4263
4264 let type_is_local = self.type_derefs_to_local(span, rcvr_ty, source);
4265
4266 let mut arbitrary_rcvr = ::alloc::vec::Vec::new()vec![];
4267 let mut candidates = all_traits(self.tcx)
4271 .into_iter()
4272 .filter(|info| match self.tcx.lookup_stability(info.def_id) {
4275 Some(attr) => attr.level.is_stable(),
4276 None => true,
4277 })
4278 .filter(|info| {
4279 static_candidates.iter().all(|sc| match *sc {
4282 CandidateSource::Trait(def_id) => def_id != info.def_id,
4283 CandidateSource::Impl(def_id) => {
4284 self.tcx.impl_opt_trait_id(def_id) != Some(info.def_id)
4285 }
4286 })
4287 })
4288 .filter(|info| {
4289 (type_is_local || info.def_id.is_local())
4296 && !self.tcx.trait_is_auto(info.def_id)
4297 && self
4298 .associated_value(info.def_id, item_name)
4299 .filter(|item| {
4300 if item.is_fn() {
4301 let id = item
4302 .def_id
4303 .as_local()
4304 .map(|def_id| self.tcx.hir_node_by_def_id(def_id));
4305 if let Some(hir::Node::TraitItem(hir::TraitItem {
4306 kind: hir::TraitItemKind::Fn(fn_sig, method),
4307 ..
4308 })) = id
4309 {
4310 let self_first_arg = match method {
4311 hir::TraitFn::Required([ident, ..]) => {
4312 #[allow(non_exhaustive_omitted_patterns)] match ident {
Some(Ident { name: kw::SelfLower, .. }) => true,
_ => false,
}matches!(ident, Some(Ident { name: kw::SelfLower, .. }))
4313 }
4314 hir::TraitFn::Provided(body_id) => {
4315 self.tcx.hir_body(*body_id).params.first().is_some_and(
4316 |param| {
4317 #[allow(non_exhaustive_omitted_patterns)] match param.pat.kind {
hir::PatKind::Binding(_, _, ident, _) if ident.name == kw::SelfLower =>
true,
_ => false,
}matches!(
4318 param.pat.kind,
4319 hir::PatKind::Binding(_, _, ident, _)
4320 if ident.name == kw::SelfLower
4321 )
4322 },
4323 )
4324 }
4325 _ => false,
4326 };
4327
4328 if !fn_sig.decl.implicit_self.has_implicit_self()
4329 && self_first_arg
4330 {
4331 if let Some(ty) = fn_sig.decl.inputs.get(0) {
4332 arbitrary_rcvr.push(ty.span);
4333 }
4334 return false;
4335 }
4336 }
4337 }
4338 item.visibility(self.tcx).is_public() || info.def_id.is_local()
4340 })
4341 .is_some()
4342 })
4343 .collect::<Vec<_>>();
4344 for span in &arbitrary_rcvr {
4345 err.span_label(
4346 *span,
4347 "the method might not be found because of this arbitrary self type",
4348 );
4349 }
4350 if alt_rcvr_sugg {
4351 return;
4352 }
4353
4354 if !candidates.is_empty() {
4355 candidates
4357 .sort_by_key(|&info| (!info.def_id.is_local(), self.tcx.def_path_str(info.def_id)));
4358 candidates.dedup();
4359
4360 let param_type = match *rcvr_ty.kind() {
4361 ty::Param(param) => Some(param),
4362 ty::Ref(_, ty, _) => match *ty.kind() {
4363 ty::Param(param) => Some(param),
4364 _ => None,
4365 },
4366 _ => None,
4367 };
4368 if !trait_missing_method {
4369 err.help(if param_type.is_some() {
4370 "items from traits can only be used if the type parameter is bounded by the trait"
4371 } else {
4372 "items from traits can only be used if the trait is implemented and in scope"
4373 });
4374 }
4375
4376 let candidates_len = candidates.len();
4377 let message = |action| {
4378 ::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!(
4379 "the following {traits_define} an item `{name}`, perhaps you need to {action} \
4380 {one_of_them}:",
4381 traits_define =
4382 if candidates_len == 1 { "trait defines" } else { "traits define" },
4383 action = action,
4384 one_of_them = if candidates_len == 1 { "it" } else { "one of them" },
4385 name = item_name,
4386 )
4387 };
4388 if let Some(param) = param_type {
4390 let generics = self.tcx.generics_of(self.body_id.to_def_id());
4391 let type_param = generics.type_param(param, self.tcx);
4392 let tcx = self.tcx;
4393 if let Some(def_id) = type_param.def_id.as_local() {
4394 let id = tcx.local_def_id_to_hir_id(def_id);
4395 match tcx.hir_node(id) {
4399 Node::GenericParam(param) => {
4400 enum Introducer {
4401 Plus,
4402 Colon,
4403 Nothing,
4404 }
4405 let hir_generics = tcx.hir_get_generics(id.owner.def_id).unwrap();
4406 let trait_def_ids: DefIdSet = hir_generics
4407 .bounds_for_param(def_id)
4408 .flat_map(|bp| bp.bounds.iter())
4409 .filter_map(|bound| bound.trait_ref()?.trait_def_id())
4410 .collect();
4411 if candidates.iter().any(|t| trait_def_ids.contains(&t.def_id)) {
4412 return;
4413 }
4414 let msg = message(::alloc::__export::must_use({
::alloc::fmt::format(format_args!("restrict type parameter `{0}` with",
param.name.ident()))
})format!(
4415 "restrict type parameter `{}` with",
4416 param.name.ident(),
4417 ));
4418 let bounds_span = hir_generics.bounds_span_for_suggestions(def_id);
4419 let mut applicability = Applicability::MaybeIncorrect;
4420 let candidate_strs: Vec<_> = candidates
4423 .iter()
4424 .map(|cand| {
4425 let cand_path = tcx.def_path_str(cand.def_id);
4426 let cand_params = &tcx.generics_of(cand.def_id).own_params;
4427 let cand_args: String = cand_params
4428 .iter()
4429 .skip(1)
4430 .filter_map(|param| match param.kind {
4431 ty::GenericParamDefKind::Type {
4432 has_default: true,
4433 ..
4434 }
4435 | ty::GenericParamDefKind::Const {
4436 has_default: true,
4437 ..
4438 } => None,
4439 _ => Some(param.name.as_str()),
4440 })
4441 .intersperse(", ")
4442 .collect();
4443 if cand_args.is_empty() {
4444 cand_path
4445 } else {
4446 applicability = Applicability::HasPlaceholders;
4447 ::alloc::__export::must_use({
::alloc::fmt::format(format_args!("{0}</* {1} */>", cand_path,
cand_args))
})format!("{cand_path}</* {cand_args} */>")
4448 }
4449 })
4450 .collect();
4451
4452 if rcvr_ty.is_ref()
4453 && param.is_impl_trait()
4454 && let Some((bounds_span, _)) = bounds_span
4455 {
4456 err.multipart_suggestions(
4457 msg,
4458 candidate_strs.iter().map(|cand| {
4459 <[_]>::into_vec(::alloc::boxed::box_new([(param.span.shrink_to_lo(),
"(".to_string()),
(bounds_span,
::alloc::__export::must_use({
::alloc::fmt::format(format_args!(" + {0})", cand))
}))]))vec![
4460 (param.span.shrink_to_lo(), "(".to_string()),
4461 (bounds_span, format!(" + {cand})")),
4462 ]
4463 }),
4464 applicability,
4465 );
4466 return;
4467 }
4468
4469 let (sp, introducer, open_paren_sp) =
4470 if let Some((span, open_paren_sp)) = bounds_span {
4471 (span, Introducer::Plus, open_paren_sp)
4472 } else if let Some(colon_span) = param.colon_span {
4473 (colon_span.shrink_to_hi(), Introducer::Nothing, None)
4474 } else if param.is_impl_trait() {
4475 (param.span.shrink_to_hi(), Introducer::Plus, None)
4476 } else {
4477 (param.span.shrink_to_hi(), Introducer::Colon, None)
4478 };
4479
4480 let all_suggs = candidate_strs.iter().map(|cand| {
4481 let suggestion = ::alloc::__export::must_use({
::alloc::fmt::format(format_args!("{0} {1}",
match introducer {
Introducer::Plus => " +",
Introducer::Colon => ":",
Introducer::Nothing => "",
}, cand))
})format!(
4482 "{} {cand}",
4483 match introducer {
4484 Introducer::Plus => " +",
4485 Introducer::Colon => ":",
4486 Introducer::Nothing => "",
4487 },
4488 );
4489
4490 let mut suggs = ::alloc::vec::Vec::new()vec![];
4491
4492 if let Some(open_paren_sp) = open_paren_sp {
4493 suggs.push((open_paren_sp, "(".to_string()));
4494 suggs.push((sp, ::alloc::__export::must_use({
::alloc::fmt::format(format_args!("){0}", suggestion))
})format!("){suggestion}")));
4495 } else {
4496 suggs.push((sp, suggestion));
4497 }
4498
4499 suggs
4500 });
4501
4502 err.multipart_suggestions(msg, all_suggs, applicability);
4503
4504 return;
4505 }
4506 Node::Item(hir::Item {
4507 kind: hir::ItemKind::Trait(_, _, _, ident, _, bounds, _),
4508 ..
4509 }) => {
4510 let (sp, sep, article) = if bounds.is_empty() {
4511 (ident.span.shrink_to_hi(), ":", "a")
4512 } else {
4513 (bounds.last().unwrap().span().shrink_to_hi(), " +", "another")
4514 };
4515 err.span_suggestions(
4516 sp,
4517 message(::alloc::__export::must_use({
::alloc::fmt::format(format_args!("add {0} supertrait for", article))
})format!("add {article} supertrait for")),
4518 candidates
4519 .iter()
4520 .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),)),
4521 Applicability::MaybeIncorrect,
4522 );
4523 return;
4524 }
4525 _ => {}
4526 }
4527 }
4528 }
4529
4530 let (potential_candidates, explicitly_negative) = if param_type.is_some() {
4531 (candidates, Vec::new())
4534 } else if let Some(simp_rcvr_ty) =
4535 simplify_type(self.tcx, rcvr_ty, TreatParams::AsRigid)
4536 {
4537 let mut potential_candidates = Vec::new();
4538 let mut explicitly_negative = Vec::new();
4539 for candidate in candidates {
4540 if self
4542 .tcx
4543 .all_impls(candidate.def_id)
4544 .map(|imp_did| self.tcx.impl_trait_header(imp_did))
4545 .filter(|header| header.polarity != ty::ImplPolarity::Positive)
4546 .any(|header| {
4547 let imp = header.trait_ref.instantiate_identity();
4548 let imp_simp =
4549 simplify_type(self.tcx, imp.self_ty(), TreatParams::AsRigid);
4550 imp_simp.is_some_and(|s| s == simp_rcvr_ty)
4551 })
4552 {
4553 explicitly_negative.push(candidate);
4554 } else {
4555 potential_candidates.push(candidate);
4556 }
4557 }
4558 (potential_candidates, explicitly_negative)
4559 } else {
4560 (candidates, Vec::new())
4562 };
4563
4564 let impls_trait = |def_id: DefId| {
4565 let args = ty::GenericArgs::for_item(self.tcx, def_id, |param, _| {
4566 if param.index == 0 {
4567 rcvr_ty.into()
4568 } else {
4569 self.infcx.var_for_def(span, param)
4570 }
4571 });
4572 self.infcx
4573 .type_implements_trait(def_id, args, self.param_env)
4574 .must_apply_modulo_regions()
4575 && param_type.is_none()
4576 };
4577 match &potential_candidates[..] {
4578 [] => {}
4579 [trait_info] if trait_info.def_id.is_local() => {
4580 if impls_trait(trait_info.def_id) {
4581 self.suggest_valid_traits(err, item_name, <[_]>::into_vec(::alloc::boxed::box_new([trait_info.def_id]))vec![trait_info.def_id], false);
4582 } else {
4583 err.subdiagnostic(CandidateTraitNote {
4584 span: self.tcx.def_span(trait_info.def_id),
4585 trait_name: self.tcx.def_path_str(trait_info.def_id),
4586 item_name,
4587 action_or_ty: if trait_missing_method {
4588 "NONE".to_string()
4589 } else {
4590 param_type.map_or_else(
4591 || "implement".to_string(), |p| p.to_string(),
4593 )
4594 },
4595 });
4596 }
4597 }
4598 trait_infos => {
4599 let mut msg = message(param_type.map_or_else(
4600 || "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"),
4602 ));
4603 for (i, trait_info) in trait_infos.iter().enumerate() {
4604 if impls_trait(trait_info.def_id) {
4605 self.suggest_valid_traits(
4606 err,
4607 item_name,
4608 <[_]>::into_vec(::alloc::boxed::box_new([trait_info.def_id]))vec![trait_info.def_id],
4609 false,
4610 );
4611 }
4612 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!(
4613 "\ncandidate #{}: `{}`",
4614 i + 1,
4615 self.tcx.def_path_str(trait_info.def_id),
4616 ));
4617 }
4618 err.note(msg);
4619 }
4620 }
4621 match &explicitly_negative[..] {
4622 [] => {}
4623 [trait_info] => {
4624 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!(
4625 "the trait `{}` defines an item `{}`, but is explicitly unimplemented",
4626 self.tcx.def_path_str(trait_info.def_id),
4627 item_name
4628 );
4629 err.note(msg);
4630 }
4631 trait_infos => {
4632 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!(
4633 "the following traits define an item `{item_name}`, but are explicitly unimplemented:"
4634 );
4635 for trait_info in trait_infos {
4636 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)));
4637 }
4638 err.note(msg);
4639 }
4640 }
4641 }
4642 }
4643
4644 fn detect_and_explain_multiple_crate_versions_of_trait_item(
4645 &self,
4646 err: &mut Diag<'_>,
4647 item_def_id: DefId,
4648 hir_id: hir::HirId,
4649 rcvr_ty: Option<Ty<'tcx>>,
4650 ) -> bool {
4651 let hir_id = self.tcx.parent_hir_id(hir_id);
4652 let Some(traits) = self.tcx.in_scope_traits(hir_id) else { return false };
4653 if traits.is_empty() {
4654 return false;
4655 }
4656 let trait_def_id = self.tcx.parent(item_def_id);
4657 if !self.tcx.is_trait(trait_def_id) {
4658 return false;
4659 }
4660 let hir::Node::Expr(rcvr) = self.tcx.hir_node(hir_id) else {
4661 return false;
4662 };
4663 let trait_ref = ty::TraitRef::new(self.tcx, trait_def_id, rcvr_ty.into_iter());
4664 let trait_pred = ty::Binder::dummy(ty::TraitPredicate {
4665 trait_ref,
4666 polarity: ty::PredicatePolarity::Positive,
4667 });
4668 let obligation = Obligation::new(self.tcx, self.misc(rcvr.span), self.param_env, trait_ref);
4669 self.err_ctxt().note_different_trait_with_same_name(err, &obligation, trait_pred)
4670 }
4671
4672 pub(crate) fn suggest_else_fn_with_closure(
4675 &self,
4676 err: &mut Diag<'_>,
4677 expr: &hir::Expr<'_>,
4678 found: Ty<'tcx>,
4679 expected: Ty<'tcx>,
4680 ) -> bool {
4681 let Some((_def_id_or_name, output, _inputs)) = self.extract_callable_info(found) else {
4682 return false;
4683 };
4684
4685 if !self.may_coerce(output, expected) {
4686 return false;
4687 }
4688
4689 if let Node::Expr(call_expr) = self.tcx.parent_hir_node(expr.hir_id)
4690 && let hir::ExprKind::MethodCall(
4691 hir::PathSegment { ident: method_name, .. },
4692 self_expr,
4693 args,
4694 ..,
4695 ) = call_expr.kind
4696 && let Some(self_ty) = self.typeck_results.borrow().expr_ty_opt(self_expr)
4697 {
4698 let new_name = Ident {
4699 name: Symbol::intern(&::alloc::__export::must_use({
::alloc::fmt::format(format_args!("{0}_else", method_name.as_str()))
})format!("{}_else", method_name.as_str())),
4700 span: method_name.span,
4701 };
4702 let probe = self.lookup_probe_for_diagnostic(
4703 new_name,
4704 self_ty,
4705 self_expr,
4706 ProbeScope::TraitsInScope,
4707 Some(expected),
4708 );
4709
4710 if let Ok(pick) = probe
4712 && let fn_sig = self.tcx.fn_sig(pick.item.def_id)
4713 && let fn_args = fn_sig.skip_binder().skip_binder().inputs()
4714 && fn_args.len() == args.len() + 1
4715 {
4716 err.span_suggestion_verbose(
4717 method_name.span.shrink_to_hi(),
4718 ::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()),
4719 "_else",
4720 Applicability::MaybeIncorrect,
4721 );
4722 return true;
4723 }
4724 }
4725 false
4726 }
4727
4728 fn type_derefs_to_local(
4731 &self,
4732 span: Span,
4733 rcvr_ty: Ty<'tcx>,
4734 source: SelfSource<'tcx>,
4735 ) -> bool {
4736 fn is_local(ty: Ty<'_>) -> bool {
4737 match ty.kind() {
4738 ty::Adt(def, _) => def.did().is_local(),
4739 ty::Foreign(did) => did.is_local(),
4740 ty::Dynamic(tr, ..) => tr.principal().is_some_and(|d| d.def_id().is_local()),
4741 ty::Param(_) => true,
4742
4743 _ => false,
4748 }
4749 }
4750
4751 if let SelfSource::QPath(_) = source {
4754 return is_local(rcvr_ty);
4755 }
4756
4757 self.autoderef(span, rcvr_ty).silence_errors().any(|(ty, _)| is_local(ty))
4758 }
4759
4760 fn suggest_hashmap_on_unsatisfied_hashset_buildhasher(
4761 &self,
4762 err: &mut Diag<'_>,
4763 pred: &ty::TraitPredicate<'_>,
4764 adt: ty::AdtDef<'_>,
4765 ) -> bool {
4766 if self.tcx.is_diagnostic_item(sym::HashSet, adt.did())
4767 && self.tcx.is_diagnostic_item(sym::BuildHasher, pred.def_id())
4768 {
4769 err.help("you might have intended to use a HashMap instead");
4770 true
4771 } else {
4772 false
4773 }
4774 }
4775}
4776
4777#[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)]
4778enum SelfSource<'a> {
4779 QPath(&'a hir::Ty<'a>),
4780 MethodCall(&'a hir::Expr<'a> ),
4781}
4782
4783#[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)]
4784pub(crate) struct TraitInfo {
4785 pub def_id: DefId,
4786}
4787
4788pub(crate) fn all_traits(tcx: TyCtxt<'_>) -> Vec<TraitInfo> {
4791 tcx.all_traits_including_private().map(|def_id| TraitInfo { def_id }).collect()
4792}
4793
4794fn print_disambiguation_help<'tcx>(
4795 tcx: TyCtxt<'tcx>,
4796 err: &mut Diag<'_>,
4797 source: SelfSource<'tcx>,
4798 args: Option<&'tcx [hir::Expr<'tcx>]>,
4799 trait_ref: ty::TraitRef<'tcx>,
4800 candidate_idx: Option<usize>,
4801 span: Span,
4802 item: ty::AssocItem,
4803) -> Option<String> {
4804 let trait_impl_type = trait_ref.self_ty().peel_refs();
4805 let trait_ref = if item.is_method() {
4806 trait_ref.print_only_trait_name().to_string()
4807 } else {
4808 ::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())
4809 };
4810 Some(
4811 if item.is_fn()
4812 && let SelfSource::MethodCall(receiver) = source
4813 && let Some(args) = args
4814 {
4815 let def_kind_descr = tcx.def_kind_descr(item.as_def_kind(), item.def_id);
4816 let item_name = item.ident(tcx);
4817 let first_input =
4818 tcx.fn_sig(item.def_id).instantiate_identity().skip_binder().inputs().get(0);
4819 let (first_arg_type, rcvr_ref) = (
4820 first_input.map(|first| first.peel_refs()),
4821 first_input
4822 .and_then(|ty| ty.ref_mutability())
4823 .map_or("", |mutbl| mutbl.ref_prefix_str()),
4824 );
4825
4826 let args = if let Some(first_arg_type) = first_arg_type
4828 && (first_arg_type == tcx.types.self_param
4829 || first_arg_type == trait_impl_type
4830 || item.is_method())
4831 {
4832 Some(receiver)
4833 } else {
4834 None
4835 }
4836 .into_iter()
4837 .chain(args)
4838 .map(|arg| {
4839 tcx.sess.source_map().span_to_snippet(arg.span).unwrap_or_else(|_| "_".to_owned())
4840 })
4841 .collect::<Vec<_>>()
4842 .join(", ");
4843
4844 let args = ::alloc::__export::must_use({
::alloc::fmt::format(format_args!("({0}{1})", rcvr_ref, args))
})format!("({}{})", rcvr_ref, args);
4845 err.span_suggestion_verbose(
4846 span,
4847 ::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!(
4848 "disambiguate the {def_kind_descr} for {}",
4849 if let Some(candidate) = candidate_idx {
4850 format!("candidate #{candidate}")
4851 } else {
4852 "the candidate".to_string()
4853 },
4854 ),
4855 ::alloc::__export::must_use({
::alloc::fmt::format(format_args!("{0}::{1}{2}", trait_ref, item_name,
args))
})format!("{trait_ref}::{item_name}{args}"),
4856 Applicability::HasPlaceholders,
4857 );
4858 return None;
4859 } else {
4860 ::alloc::__export::must_use({
::alloc::fmt::format(format_args!("{0}::", trait_ref))
})format!("{trait_ref}::")
4861 },
4862 )
4863}