]> git.proxmox.com Git - rustc.git/blame - compiler/rustc_typeck/src/check/method/suggest.rs
New upstream version 1.55.0+dfsg1
[rustc.git] / compiler / rustc_typeck / src / check / method / suggest.rs
CommitLineData
d9579d0f 1//! Give useful errors and suggestions to users when an item can't be
85aaf69f
SL
2//! found or is otherwise invalid.
3
9fa01778 4use crate::check::FnCtxt;
74b04a01 5use rustc_data_structures::fx::{FxHashMap, FxHashSet};
dfeec247
XL
6use rustc_errors::{pluralize, struct_span_err, Applicability, DiagnosticBuilder};
7use rustc_hir as hir;
74b04a01 8use rustc_hir::def::{DefKind, Namespace, Res};
17df50a5 9use rustc_hir::def_id::{DefId, CRATE_DEF_INDEX};
dfeec247 10use rustc_hir::intravisit;
3dfed10e 11use rustc_hir::lang_items::LangItem;
dfeec247 12use rustc_hir::{ExprKind, Node, QPath};
74b04a01 13use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
fc512014 14use rustc_middle::ty::fast_reject::simplify_type;
ba9703b0
XL
15use rustc_middle::ty::print::with_crate_prefix;
16use rustc_middle::ty::{
17 self, ToPolyTraitRef, ToPredicate, Ty, TyCtxt, TypeFoldable, WithConstness,
18};
fc512014 19use rustc_span::lev_distance;
3dfed10e 20use rustc_span::symbol::{kw, sym, Ident};
dfeec247 21use rustc_span::{source_map, FileName, Span};
ba9703b0
XL
22use rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt;
23use rustc_trait_selection::traits::Obligation;
85aaf69f 24
85aaf69f 25use std::cmp::Ordering;
6a06907d 26use std::iter;
85aaf69f 27
d9579d0f 28use super::probe::Mode;
dfeec247 29use super::{CandidateSource, MethodError, NoMatchData};
85aaf69f 30
dc9dc135 31impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
48663c56 32 fn is_fn_ty(&self, ty: Ty<'tcx>, span: Span) -> bool {
a7813a04 33 let tcx = self.tcx;
1b1a35ee 34 match ty.kind() {
0731742a
XL
35 // Not all of these (e.g., unsafe fns) implement `FnOnce`,
36 // so we look for these beforehand.
dfeec247 37 ty::Closure(..) | ty::FnDef(..) | ty::FnPtr(_) => true,
0731742a 38 // If it's not a simple function, look for things which implement `FnOnce`.
a7813a04 39 _ => {
3dfed10e 40 let fn_once = match tcx.lang_items().require(LangItem::FnOnce) {
3157f602 41 Ok(fn_once) => fn_once,
c30ab7b3 42 Err(..) => return false,
3157f602 43 };
a7813a04 44
c30ab7b3
SL
45 self.autoderef(span, ty).any(|(ty, _)| {
46 self.probe(|_| {
dfeec247
XL
47 let fn_once_substs = tcx.mk_substs_trait(
48 ty,
49 &[self
50 .next_ty_var(TypeVariableOrigin {
51 kind: TypeVariableOriginKind::MiscVariable,
52 span,
53 })
54 .into()],
55 );
c30ab7b3
SL
56 let trait_ref = ty::TraitRef::new(fn_once, fn_once_substs);
57 let poly_trait_ref = trait_ref.to_poly_trait_ref();
dfeec247
XL
58 let obligation = Obligation::misc(
59 span,
60 self.body_id,
61 self.param_env,
f9f354fc 62 poly_trait_ref.without_const().to_predicate(tcx),
dfeec247 63 );
83c7162d 64 self.predicate_may_hold(&obligation)
c30ab7b3
SL
65 })
66 })
54a0048b
SL
67 }
68 }
69 }
3157f602 70
cdc7bbd5 71 pub fn report_method_error(
532ac7d7
XL
72 &self,
73 span: Span,
74 rcvr_ty: Ty<'tcx>,
f9f354fc 75 item_name: Ident,
cdc7bbd5 76 source: SelfSource<'tcx>,
532ac7d7 77 error: MethodError<'tcx>,
dfeec247 78 args: Option<&'tcx [hir::Expr<'tcx>]>,
e1599b0c 79 ) -> Option<DiagnosticBuilder<'_>> {
532ac7d7
XL
80 let orig_span = span;
81 let mut span = span;
0731742a 82 // Avoid suggestions when we don't know what's going on.
a7813a04 83 if rcvr_ty.references_error() {
e1599b0c 84 return None;
a7813a04 85 }
85aaf69f 86
dfeec247
XL
87 let report_candidates = |span: Span,
88 err: &mut DiagnosticBuilder<'_>,
89 mut sources: Vec<CandidateSource>,
90 sugg_span: Span| {
a7813a04
XL
91 sources.sort();
92 sources.dedup();
93 // Dynamic limit to avoid hiding just one candidate, which is silly.
94 let limit = if sources.len() == 5 { 5 } else { 4 };
95
96 for (idx, source) in sources.iter().take(limit).enumerate() {
97 match *source {
98 CandidateSource::ImplSource(impl_did) => {
99 // Provide the best span we can. Use the item, if local to crate, else
100 // the impl, if local to crate (item may be defaulted), else nothing.
dfeec247 101 let item = match self
74b04a01 102 .associated_item(impl_did, item_name, Namespace::ValueNS)
dfeec247
XL
103 .or_else(|| {
104 let impl_trait_ref = self.tcx.impl_trait_ref(impl_did)?;
105 self.associated_item(
106 impl_trait_ref.def_id,
107 item_name,
74b04a01 108 Namespace::ValueNS,
dfeec247
XL
109 )
110 }) {
48663c56
XL
111 Some(item) => item,
112 None => continue,
113 };
dfeec247
XL
114 let note_span = self
115 .tcx
116 .hir()
117 .span_if_local(item.def_id)
118 .or_else(|| self.tcx.hir().span_if_local(impl_did));
a7813a04 119
ba9703b0 120 let impl_ty = self.tcx.at(span).type_of(impl_did);
a7813a04
XL
121
122 let insertion = match self.tcx.impl_trait_ref(impl_did) {
8faf50e0 123 None => String::new(),
dfeec247
XL
124 Some(trait_ref) => format!(
125 " of the trait `{}`",
126 self.tcx.def_path_str(trait_ref.def_id)
127 ),
a7813a04
XL
128 };
129
dfeec247
XL
130 let (note_str, idx) = if sources.len() > 1 {
131 (
132 format!(
133 "candidate #{} is defined in an impl{} for the type `{}`",
94b46f34
XL
134 idx + 1,
135 insertion,
dfeec247
XL
136 impl_ty,
137 ),
138 Some(idx + 1),
139 )
94b46f34 140 } else {
dfeec247
XL
141 (
142 format!(
143 "the candidate is defined in an impl{} for the type `{}`",
144 insertion, impl_ty,
145 ),
146 None,
147 )
94b46f34 148 };
a7813a04
XL
149 if let Some(note_span) = note_span {
150 // We have a span pointing to the method. Show note with snippet.
dfeec247 151 err.span_note(
ba9703b0 152 self.tcx.sess.source_map().guess_head_span(note_span),
dfeec247
XL
153 &note_str,
154 );
a7813a04
XL
155 } else {
156 err.note(&note_str);
157 }
416331ca 158 if let Some(trait_ref) = self.tcx.impl_trait_ref(impl_did) {
dfeec247
XL
159 let path = self.tcx.def_path_str(trait_ref.def_id);
160
161 let ty = match item.kind {
f035d41b 162 ty::AssocKind::Const | ty::AssocKind::Type => rcvr_ty,
ba9703b0 163 ty::AssocKind::Fn => self
dfeec247
XL
164 .tcx
165 .fn_sig(item.def_id)
166 .inputs()
167 .skip_binder()
168 .get(0)
169 .filter(|ty| ty.is_region_ptr() && !rcvr_ty.is_region_ptr())
74b04a01 170 .copied()
dfeec247
XL
171 .unwrap_or(rcvr_ty),
172 };
173 print_disambiguation_help(
174 item_name,
175 args,
176 err,
177 path,
178 ty,
179 item.kind,
ba9703b0 180 item.def_id,
dfeec247
XL
181 sugg_span,
182 idx,
183 self.tcx.sess.source_map(),
184 );
416331ca 185 }
a7813a04
XL
186 }
187 CandidateSource::TraitSource(trait_did) => {
dfeec247 188 let item =
74b04a01 189 match self.associated_item(trait_did, item_name, Namespace::ValueNS) {
dfeec247
XL
190 Some(item) => item,
191 None => continue,
192 };
ba9703b0
XL
193 let item_span = self
194 .tcx
195 .sess
196 .source_map()
197 .guess_head_span(self.tcx.def_span(item.def_id));
dfeec247
XL
198 let idx = if sources.len() > 1 {
199 let msg = &format!(
200 "candidate #{} is defined in the trait `{}`",
201 idx + 1,
202 self.tcx.def_path_str(trait_did)
203 );
204 err.span_note(item_span, msg);
205 Some(idx + 1)
94b46f34 206 } else {
dfeec247
XL
207 let msg = &format!(
208 "the candidate is defined in the trait `{}`",
209 self.tcx.def_path_str(trait_did)
210 );
211 err.span_note(item_span, msg);
212 None
213 };
214 let path = self.tcx.def_path_str(trait_did);
215 print_disambiguation_help(
216 item_name,
217 args,
218 err,
219 path,
220 rcvr_ty,
221 item.kind,
ba9703b0 222 item.def_id,
dfeec247
XL
223 sugg_span,
224 idx,
225 self.tcx.sess.source_map(),
226 );
9cc50fc6 227 }
54a0048b
SL
228 }
229 }
a7813a04
XL
230 if sources.len() > limit {
231 err.note(&format!("and {} others", sources.len() - limit));
232 }
233 };
62682a34 234
dfeec247
XL
235 let sugg_span = if let SelfSource::MethodCall(expr) = source {
236 // Given `foo.bar(baz)`, `expr` is `bar`, but we want to point to the whole thing.
237 self.tcx.hir().expect_expr(self.tcx.hir().get_parent_node(expr.hir_id)).span
238 } else {
239 span
240 };
241
a7813a04 242 match error {
ff7c6d11
XL
243 MethodError::NoMatch(NoMatchData {
244 static_candidates: static_sources,
245 unsatisfied_predicates,
246 out_of_scope_traits,
247 lev_candidate,
248 mode,
ff7c6d11 249 }) => {
a7813a04
XL
250 let tcx = self.tcx;
251
fc512014 252 let actual = self.resolve_vars_if_possible(rcvr_ty);
0731742a 253 let ty_str = self.ty_to_string(actual);
ff7c6d11 254 let is_method = mode == Mode::MethodCall;
94b46f34 255 let item_kind = if is_method {
ff7c6d11
XL
256 "method"
257 } else if actual.is_enum() {
48663c56 258 "variant or associated item"
ff7c6d11
XL
259 } else {
260 match (item_name.as_str().chars().next(), actual.is_fresh_ty()) {
dfeec247 261 (Some(name), false) if name.is_lowercase() => "function or associated item",
ff7c6d11 262 (Some(_), false) => "associated item",
dfeec247 263 (Some(_), true) | (None, false) => "variant or associated item",
ff7c6d11
XL
264 (None, true) => "variant",
265 }
266 };
7cac9316 267 let mut err = if !actual.references_error() {
2c00a5a8 268 // Suggest clamping down the type if the method that is being attempted to
e74abb32 269 // be used exists at all, and the type is an ambiguous numeric type
2c00a5a8 270 // ({integer}/{float}).
dfeec247 271 let mut candidates = all_traits(self.tcx).into_iter().filter_map(|info| {
74b04a01 272 self.associated_item(info.def_id, item_name, Namespace::ValueNS)
dfeec247 273 });
ba9703b0
XL
274 // There are methods that are defined on the primitive types and won't be
275 // found when exploring `all_traits`, but we also need them to be acurate on
276 // our suggestions (#47759).
277 let fund_assoc = |opt_def_id: Option<DefId>| {
278 opt_def_id
279 .and_then(|id| self.associated_item(id, item_name, Namespace::ValueNS))
280 .is_some()
281 };
282 let lang_items = tcx.lang_items();
283 let found_candidate = candidates.next().is_some()
284 || fund_assoc(lang_items.i8_impl())
285 || fund_assoc(lang_items.i16_impl())
286 || fund_assoc(lang_items.i32_impl())
287 || fund_assoc(lang_items.i64_impl())
288 || fund_assoc(lang_items.i128_impl())
289 || fund_assoc(lang_items.u8_impl())
290 || fund_assoc(lang_items.u16_impl())
291 || fund_assoc(lang_items.u32_impl())
292 || fund_assoc(lang_items.u64_impl())
293 || fund_assoc(lang_items.u128_impl())
294 || fund_assoc(lang_items.f32_impl())
295 || fund_assoc(lang_items.f32_runtime_impl())
296 || fund_assoc(lang_items.f64_impl())
297 || fund_assoc(lang_items.f64_runtime_impl());
298 if let (true, false, SelfSource::MethodCall(expr), true) = (
dfeec247
XL
299 actual.is_numeric(),
300 actual.has_concrete_skeleton(),
301 source,
ba9703b0 302 found_candidate,
dfeec247 303 ) {
2c00a5a8
XL
304 let mut err = struct_span_err!(
305 tcx.sess,
306 span,
307 E0689,
308 "can't call {} `{}` on ambiguous numeric type `{}`",
94b46f34 309 item_kind,
2c00a5a8 310 item_name,
0731742a 311 ty_str
2c00a5a8 312 );
dfeec247 313 let concrete_type = if actual.is_integral() { "i32" } else { "f32" };
e74abb32 314 match expr.kind {
0731742a
XL
315 ExprKind::Lit(ref lit) => {
316 // numeric literal
dfeec247
XL
317 let snippet = tcx
318 .sess
319 .source_map()
320 .span_to_snippet(lit.span)
0bf4aa26 321 .unwrap_or_else(|_| "<numeric literal>".to_owned());
2c00a5a8 322
9fa01778
XL
323 err.span_suggestion(
324 lit.span,
dfeec247 325 &format!(
cdc7bbd5
XL
326 "you must specify a concrete type for this numeric value, \
327 like `{}`",
dfeec247
XL
328 concrete_type
329 ),
9fa01778
XL
330 format!("{}_{}", snippet, concrete_type),
331 Applicability::MaybeIncorrect,
0bf4aa26 332 );
2c00a5a8 333 }
0731742a
XL
334 ExprKind::Path(ref qpath) => {
335 // local binding
5869c6ff 336 if let QPath::Resolved(_, path) = qpath {
48663c56 337 if let hir::def::Res::Local(hir_id) = path.res {
dc9dc135 338 let span = tcx.hir().span(hir_id);
48663c56 339 let snippet = tcx.sess.source_map().span_to_snippet(span);
b7449926 340 let filename = tcx.sess.source_map().span_to_filename(span);
8faf50e0 341
dfeec247
XL
342 let parent_node = self
343 .tcx
344 .hir()
345 .get(self.tcx.hir().get_parent_node(hir_id));
8faf50e0
XL
346 let msg = format!(
347 "you must specify a type for this binding, like `{}`",
348 concrete_type,
349 );
350
48663c56 351 match (filename, parent_node, snippet) {
dfeec247
XL
352 (
353 FileName::Real(_),
354 Node::Local(hir::Local {
355 source: hir::LocalSource::Normal,
356 ty,
357 ..
358 }),
359 Ok(ref snippet),
360 ) => {
9fa01778 361 err.span_suggestion(
8faf50e0
XL
362 // account for `let x: _ = 42;`
363 // ^^^^
dfeec247
XL
364 span.to(ty
365 .as_ref()
366 .map(|ty| ty.span)
8faf50e0
XL
367 .unwrap_or(span)),
368 &msg,
369 format!("{}: {}", snippet, concrete_type),
0bf4aa26 370 Applicability::MaybeIncorrect,
8faf50e0
XL
371 );
372 }
373 _ => {
374 err.span_label(span, msg);
375 }
376 }
2c00a5a8
XL
377 }
378 }
379 }
380 _ => {}
381 }
382 err.emit();
e1599b0c 383 return None;
2c00a5a8 384 } else {
532ac7d7 385 span = item_name.span;
17df50a5
XL
386
387 // Don't show generic arguments when the method can't be found in any implementation (#81576).
388 let mut ty_str_reported = ty_str.clone();
389 if let ty::Adt(_, ref generics) = actual.kind() {
390 if generics.len() > 0 {
391 let mut autoderef = self.autoderef(span, actual);
392 let candidate_found = autoderef.any(|(ty, _)| {
393 if let ty::Adt(ref adt_deref, _) = ty.kind() {
394 self.tcx
395 .inherent_impls(adt_deref.did)
396 .iter()
397 .filter_map(|def_id| {
398 self.associated_item(
399 *def_id,
400 item_name,
401 Namespace::ValueNS,
402 )
403 })
404 .count()
405 >= 1
406 } else {
407 false
408 }
409 });
410 let has_deref = autoderef.step_count() > 0;
411 if !candidate_found
412 && !has_deref
413 && unsatisfied_predicates.is_empty()
414 {
415 if let Some((path_string, _)) = ty_str.split_once('<') {
416 ty_str_reported = path_string.to_string();
417 }
418 }
419 }
420 }
421
0531ce1d 422 let mut err = struct_span_err!(
2c00a5a8 423 tcx.sess,
532ac7d7 424 span,
2c00a5a8 425 E0599,
dfeec247 426 "no {} named `{}` found for {} `{}` in the current scope",
94b46f34 427 item_kind,
2c00a5a8 428 item_name,
6a06907d 429 actual.prefix_string(self.tcx),
17df50a5 430 ty_str_reported,
0531ce1d 431 );
1b1a35ee
XL
432 if let Mode::MethodCall = mode {
433 if let SelfSource::MethodCall(call) = source {
434 self.suggest_await_before_method(
435 &mut err, item_name, actual, call, span,
436 );
437 }
438 }
dfeec247
XL
439 if let Some(span) =
440 tcx.sess.confused_type_with_std_module.borrow().get(&span)
48663c56
XL
441 {
442 if let Ok(snippet) = tcx.sess.source_map().span_to_snippet(*span) {
443 err.span_suggestion(
444 *span,
445 "you are looking for the module in `std`, \
446 not the primitive type",
447 format!("std::{}", snippet),
448 Applicability::MachineApplicable,
449 );
450 }
0531ce1d 451 }
1b1a35ee 452 if let ty::RawPtr(_) = &actual.kind() {
dfeec247
XL
453 err.note(
454 "try using `<*const T>::as_ref()` to get a reference to the \
dc9dc135 455 type behind the pointer: https://doc.rust-lang.org/std/\
dfeec247
XL
456 primitive.pointer.html#method.as_ref",
457 );
458 err.note(
459 "using `<*const T>::as_ref()` on a pointer \
416331ca 460 which is unaligned or points to invalid \
dfeec247
XL
461 or uninitialized memory is undefined behavior",
462 );
dc9dc135 463 }
0531ce1d 464 err
2c00a5a8 465 }
7cac9316 466 } else {
ff7c6d11 467 tcx.sess.diagnostic().struct_dummy()
7cac9316 468 };
5bcae85e 469
94b46f34 470 if let Some(def) = actual.ty_adt_def() {
0731742a 471 if let Some(full_sp) = tcx.hir().span_if_local(def.did) {
ba9703b0 472 let def_sp = tcx.sess.source_map().guess_head_span(full_sp);
dfeec247
XL
473 err.span_label(
474 def_sp,
475 format!(
476 "{} `{}` not found {}",
477 item_kind,
478 item_name,
479 if def.is_enum() && !is_method { "here" } else { "for this" }
480 ),
481 );
ff7c6d11
XL
482 }
483 }
484
5869c6ff
XL
485 let mut label_span_not_found = || {
486 if unsatisfied_predicates.is_empty() {
487 err.span_label(span, format!("{item_kind} not found in `{ty_str}`"));
17df50a5
XL
488 if let ty::Adt(ref adt, _) = rcvr_ty.kind() {
489 let mut inherent_impls_candidate = self
490 .tcx
491 .inherent_impls(adt.did)
492 .iter()
493 .copied()
494 .filter(|def_id| {
495 if let Some(assoc) =
496 self.associated_item(*def_id, item_name, Namespace::ValueNS)
497 {
498 // Check for both mode is the same so we avoid suggesting
499 // incorrect associated item.
500 match (mode, assoc.fn_has_self_parameter, source) {
501 (Mode::MethodCall, true, SelfSource::MethodCall(_)) => {
502 // We check that the suggest type is actually
503 // different from the received one
504 // So we avoid suggestion method with Box<Self>
505 // for instance
506 self.tcx.at(span).type_of(*def_id) != actual
507 && self.tcx.at(span).type_of(*def_id) != rcvr_ty
508 }
509 (Mode::Path, false, _) => true,
510 _ => false,
511 }
512 } else {
513 false
514 }
515 })
516 .collect::<Vec<_>>();
517 if inherent_impls_candidate.len() > 0 {
518 inherent_impls_candidate.sort();
519 inherent_impls_candidate.dedup();
520
521 // number of type to shows at most.
522 let limit = if inherent_impls_candidate.len() == 5 { 5 } else { 4 };
523 let type_candidates = inherent_impls_candidate
524 .iter()
525 .take(limit)
526 .map(|impl_item| {
527 format!("- `{}`", self.tcx.at(span).type_of(*impl_item))
528 })
529 .collect::<Vec<_>>()
530 .join("\n");
531 let additional_types = if inherent_impls_candidate.len() > limit {
532 format!(
533 "\nand {} more types",
534 inherent_impls_candidate.len() - limit
535 )
536 } else {
537 "".to_string()
538 };
539 err.note(&format!(
540 "the {item_kind} was found for\n{}{}",
541 type_candidates, additional_types
542 ));
543 }
544 }
5869c6ff
XL
545 } else {
546 err.span_label(span, format!("{item_kind} cannot be called on `{ty_str}` due to unsatisfied trait bounds"));
547 }
548 self.tcx.sess.trait_methods_not_found.borrow_mut().insert(orig_span);
549 };
550
5bcae85e 551 // If the method name is the name of a field with a function or closure type,
0731742a
XL
552 // give a helping note that it has to be called as `(x.f)(...)`.
553 if let SelfSource::MethodCall(expr) = source {
dfeec247 554 let field_receiver =
1b1a35ee 555 self.autoderef(span, rcvr_ty).find_map(|(ty, _)| match ty.kind() {
532ac7d7 556 ty::Adt(def, substs) if !def.is_enum() => {
83c7162d 557 let variant = &def.non_enum_variant();
532ac7d7 558 self.tcx.find_field_index(item_name, variant).map(|index| {
83c7162d 559 let field = &variant.fields[index];
9e0c209e 560 let field_ty = field.ty(tcx, substs);
532ac7d7
XL
561 (field, field_ty)
562 })
563 }
564 _ => None,
565 });
566
567 if let Some((field, field_ty)) = field_receiver {
ba9703b0 568 let scope = self.tcx.parent_module(self.body_id).to_def_id();
532ac7d7
XL
569 let is_accessible = field.vis.is_accessible_from(scope, self.tcx);
570
571 if is_accessible {
572 if self.is_fn_ty(&field_ty, span) {
573 let expr_span = expr.span.to(item_name.span);
574 err.multipart_suggestion(
575 &format!(
576 "to call the function stored in `{}`, \
577 surround the field access with parentheses",
578 item_name,
579 ),
580 vec![
581 (expr_span.shrink_to_lo(), '('.to_string()),
582 (expr_span.shrink_to_hi(), ')'.to_string()),
583 ],
584 Applicability::MachineApplicable,
585 );
586 } else {
dfeec247
XL
587 let call_expr = self
588 .tcx
589 .hir()
590 .expect_expr(self.tcx.hir().get_parent_node(expr.hir_id));
532ac7d7 591
48663c56
XL
592 if let Some(span) = call_expr.span.trim_start(item_name.span) {
593 err.span_suggestion(
594 span,
595 "remove the arguments",
596 String::new(),
597 Applicability::MaybeIncorrect,
598 );
599 }
5bcae85e 600 }
a7813a04 601 }
532ac7d7 602
dfeec247 603 let field_kind = if is_accessible { "field" } else { "private field" };
532ac7d7 604 err.span_label(item_name.span, format!("{}, not a method", field_kind));
e1599b0c 605 } else if lev_candidate.is_none() && static_sources.is_empty() {
5869c6ff 606 label_span_not_found();
54a0048b 607 }
ff7c6d11 608 } else {
5869c6ff 609 label_span_not_found();
54a0048b 610 }
92a42be0 611
a7813a04 612 if self.is_fn_ty(&rcvr_ty, span) {
6a06907d
XL
613 fn report_function<T: std::fmt::Display>(
614 err: &mut DiagnosticBuilder<'_>,
615 name: T,
616 ) {
617 err.note(
618 &format!("`{}` is a function, perhaps you wish to call it", name,),
619 );
54a0048b 620 }
a7813a04 621
0731742a 622 if let SelfSource::MethodCall(expr) = source {
b7449926 623 if let Ok(expr_string) = tcx.sess.source_map().span_to_snippet(expr.span) {
6a06907d 624 report_function(&mut err, expr_string);
dfeec247 625 } else if let ExprKind::Path(QPath::Resolved(_, ref path)) = expr.kind {
a7813a04 626 if let Some(segment) = path.segments.last() {
6a06907d 627 report_function(&mut err, segment.ident);
a7813a04 628 }
62682a34
SL
629 }
630 }
c34b1796 631 }
85aaf69f 632
a7813a04 633 if !static_sources.is_empty() {
dfeec247
XL
634 err.note(
635 "found the following associated functions; to be used as methods, \
74b04a01 636 functions must have a `self` parameter",
dfeec247 637 );
94b46f34
XL
638 err.span_label(span, "this is an associated function, not a method");
639 }
640 if static_sources.len() == 1 {
dfeec247
XL
641 let ty_str = if let Some(CandidateSource::ImplSource(impl_did)) =
642 static_sources.get(0)
643 {
e74abb32
XL
644 // When the "method" is resolved through dereferencing, we really want the
645 // original type that has the associated function for accurate suggestions.
646 // (#61411)
ba9703b0 647 let ty = tcx.at(span).type_of(*impl_did);
1b1a35ee 648 match (&ty.peel_refs().kind(), &actual.peel_refs().kind()) {
e74abb32
XL
649 (ty::Adt(def, _), ty::Adt(def_actual, _)) if def == def_actual => {
650 // Use `actual` as it will have more `substs` filled in.
651 self.ty_to_value_string(actual.peel_refs())
652 }
653 _ => self.ty_to_value_string(ty.peel_refs()),
654 }
655 } else {
656 self.ty_to_value_string(actual.peel_refs())
657 };
0731742a 658 if let SelfSource::MethodCall(expr) = source {
e74abb32
XL
659 err.span_suggestion(
660 expr.span.to(span),
661 "use associated function syntax instead",
662 format!("{}::{}", ty_str, item_name),
663 Applicability::MachineApplicable,
664 );
94b46f34 665 } else {
dfeec247 666 err.help(&format!("try with `{}::{}`", ty_str, item_name,));
94b46f34
XL
667 }
668
dfeec247 669 report_candidates(span, &mut err, static_sources, sugg_span);
94b46f34 670 } else if static_sources.len() > 1 {
dfeec247 671 report_candidates(span, &mut err, static_sources, sugg_span);
a7813a04 672 }
85aaf69f 673
74b04a01 674 let mut restrict_type_params = false;
cdc7bbd5 675 let mut unsatisfied_bounds = false;
a7813a04 676 if !unsatisfied_predicates.is_empty() {
ba9703b0
XL
677 let def_span = |def_id| {
678 self.tcx.sess.source_map().guess_head_span(self.tcx.def_span(def_id))
679 };
74b04a01
XL
680 let mut type_params = FxHashMap::default();
681 let mut bound_spans = vec![];
3dfed10e 682
74b04a01 683 let mut collect_type_param_suggestions =
3dfed10e
XL
684 |self_ty: Ty<'tcx>, parent_pred: &ty::Predicate<'tcx>, obligation: &str| {
685 // We don't care about regions here, so it's fine to skip the binder here.
5869c6ff
XL
686 if let (ty::Param(_), ty::PredicateKind::Trait(p, _)) =
687 (self_ty.kind(), parent_pred.kind().skip_binder())
74b04a01 688 {
1b1a35ee 689 if let ty::Adt(def, _) = p.trait_ref.self_ty().kind() {
f9f354fc 690 let node = def.did.as_local().map(|def_id| {
3dfed10e
XL
691 self.tcx
692 .hir()
693 .get(self.tcx.hir().local_def_id_to_hir_id(def_id))
f9f354fc 694 });
ba9703b0
XL
695 if let Some(hir::Node::Item(hir::Item { kind, .. })) = node {
696 if let Some(g) = kind.generics() {
6a06907d 697 let key = match g.where_clause.predicates {
ba9703b0
XL
698 [.., pred] => (pred.span().shrink_to_hi(), false),
699 [] => (
700 g.where_clause
701 .span_for_predicates_or_empty_place(),
702 true,
703 ),
704 };
705 type_params
706 .entry(key)
707 .or_insert_with(FxHashSet::default)
708 .insert(obligation.to_owned());
74b04a01 709 }
74b04a01
XL
710 }
711 }
712 }
713 };
714 let mut bound_span_label = |self_ty: Ty<'_>, obligation: &str, quiet: &str| {
715 let msg = format!(
716 "doesn't satisfy `{}`",
717 if obligation.len() > 50 { quiet } else { obligation }
718 );
1b1a35ee 719 match &self_ty.kind() {
74b04a01
XL
720 // Point at the type that couldn't satisfy the bound.
721 ty::Adt(def, _) => bound_spans.push((def_span(def.did), msg)),
722 // Point at the trait object that couldn't satisfy the bound.
723 ty::Dynamic(preds, _) => {
fc512014
XL
724 for pred in preds.iter() {
725 match pred.skip_binder() {
74b04a01
XL
726 ty::ExistentialPredicate::Trait(tr) => {
727 bound_spans.push((def_span(tr.def_id), msg.clone()))
728 }
729 ty::ExistentialPredicate::Projection(_)
730 | ty::ExistentialPredicate::AutoTrait(_) => {}
731 }
732 }
733 }
734 // Point at the closure that couldn't satisfy the bound.
735 ty::Closure(def_id, _) => bound_spans
736 .push((def_span(*def_id), format!("doesn't satisfy `{}`", quiet))),
737 _ => {}
738 }
739 };
f9f354fc 740 let mut format_pred = |pred: ty::Predicate<'tcx>| {
5869c6ff 741 let bound_predicate = pred.kind();
29967ef6 742 match bound_predicate.skip_binder() {
5869c6ff 743 ty::PredicateKind::Projection(pred) => {
29967ef6 744 let pred = bound_predicate.rebind(pred);
74b04a01 745 // `<Foo as Iterator>::Item = String`.
6a06907d
XL
746 let projection_ty = pred.skip_binder().projection_ty;
747
748 let substs_with_infer_self = tcx.mk_substs(
749 iter::once(tcx.mk_ty_var(ty::TyVid { index: 0 }).into())
750 .chain(projection_ty.substs.iter().skip(1)),
74b04a01 751 );
6a06907d
XL
752
753 let quiet_projection_ty = ty::ProjectionTy {
754 substs: substs_with_infer_self,
755 item_def_id: projection_ty.item_def_id,
756 };
757
758 let ty = pred.skip_binder().ty;
759
760 let obligation = format!("{} = {}", projection_ty, ty);
761 let quiet = format!("{} = {}", quiet_projection_ty, ty);
762
763 bound_span_label(projection_ty.self_ty(), &obligation, &quiet);
764 Some((obligation, projection_ty.self_ty()))
74b04a01 765 }
5869c6ff 766 ty::PredicateKind::Trait(poly_trait_ref, _) => {
29967ef6 767 let p = poly_trait_ref.trait_ref;
74b04a01
XL
768 let self_ty = p.self_ty();
769 let path = p.print_only_trait_path();
770 let obligation = format!("{}: {}", self_ty, path);
771 let quiet = format!("_: {}", path);
772 bound_span_label(self_ty, &obligation, &quiet);
773 Some((obligation, self_ty))
774 }
775 _ => None,
776 }
777 };
dfeec247
XL
778 let mut bound_list = unsatisfied_predicates
779 .iter()
74b04a01
XL
780 .filter_map(|(pred, parent_pred)| {
781 format_pred(*pred).map(|(p, self_ty)| match parent_pred {
fc512014 782 None => format!("`{}`", &p),
74b04a01 783 Some(parent_pred) => match format_pred(*parent_pred) {
fc512014 784 None => format!("`{}`", &p),
74b04a01
XL
785 Some((parent_p, _)) => {
786 collect_type_param_suggestions(self_ty, parent_pred, &p);
787 format!("`{}`\nwhich is required by `{}`", p, parent_p)
788 }
789 },
790 })
791 })
792 .enumerate()
793 .collect::<Vec<(usize, String)>>();
794 for ((span, empty_where), obligations) in type_params.into_iter() {
795 restrict_type_params = true;
3dfed10e
XL
796 // #74886: Sort here so that the output is always the same.
797 let mut obligations = obligations.into_iter().collect::<Vec<_>>();
798 obligations.sort();
74b04a01
XL
799 err.span_suggestion_verbose(
800 span,
801 &format!(
802 "consider restricting the type parameter{s} to satisfy the \
803 trait bound{s}",
804 s = pluralize!(obligations.len())
805 ),
806 format!(
807 "{} {}",
808 if empty_where { " where" } else { "," },
3dfed10e 809 obligations.join(", ")
74b04a01
XL
810 ),
811 Applicability::MaybeIncorrect,
812 );
813 }
814
815 bound_list.sort_by(|(_, a), (_, b)| a.cmp(&b)); // Sort alphabetically.
816 bound_list.dedup_by(|(_, a), (_, b)| a == b); // #35677
817 bound_list.sort_by_key(|(pos, _)| *pos); // Keep the original predicate order.
818 bound_spans.sort();
819 bound_spans.dedup();
820 for (span, msg) in bound_spans.into_iter() {
821 err.span_label(span, &msg);
822 }
823 if !bound_list.is_empty() {
824 let bound_list = bound_list
825 .into_iter()
826 .map(|(_, path)| path)
827 .collect::<Vec<_>>()
828 .join("\n");
6a06907d 829 let actual_prefix = actual.prefix_string(self.tcx);
5869c6ff
XL
830 err.set_primary_message(&format!(
831 "the {item_kind} `{item_name}` exists for {actual_prefix} `{ty_str}`, but its trait bounds were not satisfied"
832 ));
74b04a01 833 err.note(&format!(
5869c6ff 834 "the following trait bounds were not satisfied:\n{bound_list}"
74b04a01 835 ));
cdc7bbd5 836 unsatisfied_bounds = true;
74b04a01 837 }
a7813a04 838 }
62682a34 839
74b04a01 840 if actual.is_numeric() && actual.is_fresh() || restrict_type_params {
2c00a5a8 841 } else {
dfeec247
XL
842 self.suggest_traits_to_import(
843 &mut err,
844 span,
845 rcvr_ty,
846 item_name,
847 source,
848 out_of_scope_traits,
74b04a01 849 &unsatisfied_predicates,
cdc7bbd5 850 unsatisfied_bounds,
dfeec247 851 );
2c00a5a8 852 }
ea8adc8c 853
5869c6ff
XL
854 // Don't emit a suggestion if we found an actual method
855 // that had unsatisfied trait bounds
856 if unsatisfied_predicates.is_empty() && actual.is_enum() {
48663c56
XL
857 let adt_def = actual.ty_adt_def().expect("enum is not an ADT");
858 if let Some(suggestion) = lev_distance::find_best_match_for_name(
fc512014 859 &adt_def.variants.iter().map(|s| s.ident.name).collect::<Vec<_>>(),
3dfed10e 860 item_name.name,
48663c56
XL
861 None,
862 ) {
863 err.span_suggestion(
864 span,
865 "there is a variant with a similar name",
866 suggestion.to_string(),
867 Applicability::MaybeIncorrect,
868 );
869 }
870 }
871
e74abb32
XL
872 let mut fallback_span = true;
873 let msg = "remove this method call";
3dfed10e 874 if item_name.name == sym::as_str && actual.peel_refs().is_str() {
e74abb32 875 if let SelfSource::MethodCall(expr) = source {
dfeec247
XL
876 let call_expr =
877 self.tcx.hir().expect_expr(self.tcx.hir().get_parent_node(expr.hir_id));
e74abb32
XL
878 if let Some(span) = call_expr.span.trim_start(expr.span) {
879 err.span_suggestion(
880 span,
881 msg,
882 String::new(),
883 Applicability::MachineApplicable,
884 );
885 fallback_span = false;
886 }
887 }
888 if fallback_span {
889 err.span_label(span, msg);
890 }
891 } else if let Some(lev_candidate) = lev_candidate {
5869c6ff
XL
892 // Don't emit a suggestion if we found an actual method
893 // that had unsatisfied trait bounds
894 if unsatisfied_predicates.is_empty() {
895 let def_kind = lev_candidate.kind.as_def_kind();
896 err.span_suggestion(
897 span,
898 &format!(
899 "there is {} {} with a similar name",
900 def_kind.article(),
901 def_kind.descr(lev_candidate.def_id),
902 ),
903 lev_candidate.ident.to_string(),
904 Applicability::MaybeIncorrect,
905 );
906 }
ea8adc8c 907 }
48663c56 908
e1599b0c 909 return Some(err);
a7813a04 910 }
85aaf69f 911
a7813a04 912 MethodError::Ambiguity(sources) => {
dfeec247
XL
913 let mut err = struct_span_err!(
914 self.sess(),
ba9703b0 915 item_name.span,
dfeec247
XL
916 E0034,
917 "multiple applicable items in scope"
918 );
ba9703b0 919 err.span_label(item_name.span, format!("multiple `{}` found", item_name));
85aaf69f 920
dfeec247 921 report_candidates(span, &mut err, sources, sugg_span);
a7813a04
XL
922 err.emit();
923 }
85aaf69f 924
416331ca 925 MethodError::PrivateMatch(kind, def_id, out_of_scope_traits) => {
ba9703b0 926 let kind = kind.descr(def_id);
dfeec247
XL
927 let mut err = struct_span_err!(
928 self.tcx.sess,
ba9703b0 929 item_name.span,
dfeec247
XL
930 E0624,
931 "{} `{}` is private",
ba9703b0 932 kind,
dfeec247
XL
933 item_name
934 );
ba9703b0 935 err.span_label(item_name.span, &format!("private {}", kind));
136023e0
XL
936 let sp = self
937 .tcx
938 .hir()
939 .span_if_local(def_id)
940 .unwrap_or_else(|| self.tcx.def_span(def_id));
941 err.span_label(sp, &format!("private {} defined here", kind));
3b2f2976
XL
942 self.suggest_valid_traits(&mut err, out_of_scope_traits);
943 err.emit();
a7813a04 944 }
3b2f2976 945
74b04a01 946 MethodError::IllegalSizedBound(candidates, needs_mut, bound_span) => {
3b2f2976
XL
947 let msg = format!("the `{}` method cannot be invoked on a trait object", item_name);
948 let mut err = self.sess().struct_span_err(span, &msg);
74b04a01 949 err.span_label(bound_span, "this has a `Sized` requirement");
3b2f2976 950 if !candidates.is_empty() {
e74abb32
XL
951 let help = format!(
952 "{an}other candidate{s} {were} found in the following trait{s}, perhaps \
953 add a `use` for {one_of_them}:",
dfeec247 954 an = if candidates.len() == 1 { "an" } else { "" },
60c5eb7d 955 s = pluralize!(candidates.len()),
e74abb32 956 were = if candidates.len() == 1 { "was" } else { "were" },
dfeec247 957 one_of_them = if candidates.len() == 1 { "it" } else { "one_of_them" },
e74abb32 958 );
3b2f2976
XL
959 self.suggest_use_candidates(&mut err, help, candidates);
960 }
1b1a35ee 961 if let ty::Ref(region, t_type, mutability) = rcvr_ty.kind() {
e74abb32 962 if needs_mut {
dfeec247
XL
963 let trait_type = self.tcx.mk_ref(
964 region,
965 ty::TypeAndMut { ty: t_type, mutbl: mutability.invert() },
966 );
e74abb32
XL
967 err.note(&format!("you need `{}` instead of `{}`", trait_type, rcvr_ty));
968 }
969 }
3b2f2976
XL
970 err.emit();
971 }
ea8adc8c 972
dfeec247 973 MethodError::BadReturnType => bug!("no return type expectations but got BadReturnType"),
3b2f2976 974 }
e1599b0c 975 None
3b2f2976
XL
976 }
977
e74abb32
XL
978 /// Print out the type for use in value namespace.
979 fn ty_to_value_string(&self, ty: Ty<'tcx>) -> String {
1b1a35ee 980 match ty.kind() {
e74abb32
XL
981 ty::Adt(def, substs) => format!("{}", ty::Instance::new(def.did, substs)),
982 _ => self.ty_to_string(ty),
983 }
984 }
985
1b1a35ee
XL
986 fn suggest_await_before_method(
987 &self,
988 err: &mut DiagnosticBuilder<'_>,
989 item_name: Ident,
990 ty: Ty<'tcx>,
991 call: &hir::Expr<'_>,
992 span: Span,
993 ) {
29967ef6 994 let output_ty = match self.infcx.get_impl_future_output_ty(ty) {
fc512014 995 Some(output_ty) => self.resolve_vars_if_possible(output_ty),
29967ef6
XL
996 _ => return,
997 };
998 let method_exists = self.method_exists(item_name, output_ty, call.hir_id, true);
999 debug!("suggest_await_before_method: is_method_exist={}", method_exists);
1000 if method_exists {
1001 err.span_suggestion_verbose(
1002 span.shrink_to_lo(),
1003 "consider `await`ing on the `Future` and calling the method on its `Output`",
1004 "await.".to_string(),
1005 Applicability::MaybeIncorrect,
1006 );
1b1a35ee
XL
1007 }
1008 }
1009
dfeec247
XL
1010 fn suggest_use_candidates(
1011 &self,
1012 err: &mut DiagnosticBuilder<'_>,
1013 mut msg: String,
1014 candidates: Vec<DefId>,
1015 ) {
74b04a01 1016 let module_did = self.tcx.parent_module(self.body_id);
3dfed10e 1017 let module_id = self.tcx.hir().local_def_id_to_hir_id(module_did);
0731742a 1018 let krate = self.tcx.hir().krate();
ff7c6d11
XL
1019 let (span, found_use) = UsePlacementFinder::check(self.tcx, krate, module_id);
1020 if let Some(span) = span {
1021 let path_strings = candidates.iter().map(|did| {
0731742a 1022 // Produce an additional newline to separate the new use statement
ff7c6d11 1023 // from the directly following item.
dfeec247 1024 let additional_newline = if found_use { "" } else { "\n" };
0bf4aa26
XL
1025 format!(
1026 "use {};\n{}",
532ac7d7 1027 with_crate_prefix(|| self.tcx.def_path_str(*did)),
0bf4aa26
XL
1028 additional_newline
1029 )
a1dfa0c6 1030 });
ff7c6d11 1031
9fa01778 1032 err.span_suggestions(span, &msg, path_strings, Applicability::MaybeIncorrect);
ff7c6d11
XL
1033 } else {
1034 let limit = if candidates.len() == 5 { 5 } else { 4 };
1035 for (i, trait_did) in candidates.iter().take(limit).enumerate() {
94b46f34 1036 if candidates.len() > 1 {
dfeec247
XL
1037 msg.push_str(&format!(
1038 "\ncandidate #{}: `use {};`",
1039 i + 1,
1040 with_crate_prefix(|| self.tcx.def_path_str(*trait_did))
1041 ));
94b46f34 1042 } else {
dfeec247
XL
1043 msg.push_str(&format!(
1044 "\n`use {};`",
1045 with_crate_prefix(|| self.tcx.def_path_str(*trait_did))
1046 ));
94b46f34 1047 }
ff7c6d11
XL
1048 }
1049 if candidates.len() > limit {
1050 msg.push_str(&format!("\nand {} others", candidates.len() - limit));
1051 }
1052 err.note(&msg[..]);
3b2f2976 1053 }
3b2f2976
XL
1054 }
1055
e74abb32
XL
1056 fn suggest_valid_traits(
1057 &self,
1058 err: &mut DiagnosticBuilder<'_>,
1059 valid_out_of_scope_traits: Vec<DefId>,
1060 ) -> bool {
3b2f2976
XL
1061 if !valid_out_of_scope_traits.is_empty() {
1062 let mut candidates = valid_out_of_scope_traits;
1063 candidates.sort();
1064 candidates.dedup();
1065 err.help("items from traits can only be used if the trait is in scope");
e74abb32
XL
1066 let msg = format!(
1067 "the following {traits_are} implemented but not in scope; \
1068 perhaps add a `use` for {one_of_them}:",
dfeec247
XL
1069 traits_are = if candidates.len() == 1 { "trait is" } else { "traits are" },
1070 one_of_them = if candidates.len() == 1 { "it" } else { "one of them" },
e74abb32 1071 );
3b2f2976
XL
1072
1073 self.suggest_use_candidates(err, msg, candidates);
1074 true
1075 } else {
1076 false
54a0048b 1077 }
85aaf69f
SL
1078 }
1079
cdc7bbd5 1080 fn suggest_traits_to_import(
416331ca
XL
1081 &self,
1082 err: &mut DiagnosticBuilder<'_>,
1083 span: Span,
1084 rcvr_ty: Ty<'tcx>,
f9f354fc 1085 item_name: Ident,
cdc7bbd5 1086 source: SelfSource<'tcx>,
416331ca 1087 valid_out_of_scope_traits: Vec<DefId>,
74b04a01 1088 unsatisfied_predicates: &[(ty::Predicate<'tcx>, Option<ty::Predicate<'tcx>>)],
cdc7bbd5 1089 unsatisfied_bounds: bool,
416331ca 1090 ) {
cdc7bbd5
XL
1091 let mut alt_rcvr_sugg = false;
1092 if let (SelfSource::MethodCall(rcvr), false) = (source, unsatisfied_bounds) {
1093 debug!(?span, ?item_name, ?rcvr_ty, ?rcvr);
1094 let skippable = [
1095 self.tcx.lang_items().clone_trait(),
1096 self.tcx.lang_items().deref_trait(),
1097 self.tcx.lang_items().deref_mut_trait(),
1098 self.tcx.lang_items().drop_trait(),
1099 ];
1100 // Try alternative arbitrary self types that could fulfill this call.
1101 // FIXME: probe for all types that *could* be arbitrary self-types, not
1102 // just this list.
1103 for (rcvr_ty, post) in &[
1104 (rcvr_ty, ""),
1105 (self.tcx.mk_mut_ref(&ty::ReErased, rcvr_ty), "&mut "),
1106 (self.tcx.mk_imm_ref(&ty::ReErased, rcvr_ty), "&"),
1107 ] {
1108 if let Ok(pick) = self.lookup_probe(
1109 span,
1110 item_name,
1111 rcvr_ty,
1112 rcvr,
1113 crate::check::method::probe::ProbeScope::AllTraits,
1114 ) {
1115 // If the method is defined for the receiver we have, it likely wasn't `use`d.
1116 // We point at the method, but we just skip the rest of the check for arbitrary
1117 // self types and rely on the suggestion to `use` the trait from
1118 // `suggest_valid_traits`.
1119 let did = Some(pick.item.container.id());
1120 let skip = skippable.contains(&did);
1121 if pick.autoderefs == 0 && !skip {
1122 err.span_label(
1123 pick.item.ident.span,
1124 &format!("the method is available for `{}` here", rcvr_ty),
1125 );
1126 }
1127 break;
1128 }
1129 for (rcvr_ty, pre) in &[
1130 (self.tcx.mk_lang_item(rcvr_ty, LangItem::OwnedBox), "Box::new"),
1131 (self.tcx.mk_lang_item(rcvr_ty, LangItem::Pin), "Pin::new"),
1132 (self.tcx.mk_diagnostic_item(rcvr_ty, sym::Arc), "Arc::new"),
1133 (self.tcx.mk_diagnostic_item(rcvr_ty, sym::Rc), "Rc::new"),
1134 ] {
1135 if let Some(new_rcvr_t) = *rcvr_ty {
1136 if let Ok(pick) = self.lookup_probe(
1137 span,
1138 item_name,
1139 new_rcvr_t,
1140 rcvr,
1141 crate::check::method::probe::ProbeScope::AllTraits,
1142 ) {
1143 debug!("try_alt_rcvr: pick candidate {:?}", pick);
1144 let did = Some(pick.item.container.id());
1145 // We don't want to suggest a container type when the missing
1146 // method is `.clone()` or `.deref()` otherwise we'd suggest
1147 // `Arc::new(foo).clone()`, which is far from what the user wants.
1148 let skip = skippable.contains(&did);
1149 // Make sure the method is defined for the *actual* receiver: we don't
1150 // want to treat `Box<Self>` as a receiver if it only works because of
1151 // an autoderef to `&self`
1152 if pick.autoderefs == 0 && !skip {
1153 err.span_label(
1154 pick.item.ident.span,
1155 &format!("the method is available for `{}` here", new_rcvr_t),
1156 );
1157 err.multipart_suggestion(
1158 "consider wrapping the receiver expression with the \
1159 appropriate type",
1160 vec![
1161 (rcvr.span.shrink_to_lo(), format!("{}({}", pre, post)),
1162 (rcvr.span.shrink_to_hi(), ")".to_string()),
1163 ],
1164 Applicability::MaybeIncorrect,
1165 );
1166 // We don't care about the other suggestions.
1167 alt_rcvr_sugg = true;
1168 }
1169 }
1170 }
1171 }
1172 }
1173 }
3b2f2976 1174 if self.suggest_valid_traits(err, valid_out_of_scope_traits) {
c30ab7b3 1175 return;
85aaf69f 1176 }
85aaf69f 1177
0731742a 1178 let type_is_local = self.type_derefs_to_local(span, rcvr_ty, source);
a7813a04 1179
74b04a01 1180 let mut arbitrary_rcvr = vec![];
0731742a 1181 // There are no traits implemented, so lets suggest some traits to
a7813a04
XL
1182 // implement, by finding ones that have the item name, and are
1183 // legal to implement.
8bb4bdeb 1184 let mut candidates = all_traits(self.tcx)
83c7162d 1185 .into_iter()
3dfed10e
XL
1186 // Don't issue suggestions for unstable traits since they're
1187 // unlikely to be implementable anyway
1188 .filter(|info| match self.tcx.lookup_stability(info.def_id) {
1189 Some(attr) => attr.level.is_stable(),
1190 None => true,
1191 })
a7813a04 1192 .filter(|info| {
0731742a 1193 // We approximate the coherence rules to only suggest
a7813a04 1194 // traits that are legal to implement by requiring that
0731742a 1195 // either the type or trait is local. Multi-dispatch means
a7813a04
XL
1196 // this isn't perfect (that is, there are cases when
1197 // implementing a trait would be legal but is rejected
1198 // here).
3dfed10e 1199 unsatisfied_predicates.iter().all(|(p, _)| {
5869c6ff 1200 match p.kind().skip_binder() {
3dfed10e
XL
1201 // Hide traits if they are present in predicates as they can be fixed without
1202 // having to implement them.
5869c6ff
XL
1203 ty::PredicateKind::Trait(t, _) => t.def_id() == info.def_id,
1204 ty::PredicateKind::Projection(p) => {
3dfed10e
XL
1205 p.projection_ty.item_def_id == info.def_id
1206 }
1207 _ => false,
1208 }
74b04a01 1209 }) && (type_is_local || info.def_id.is_local())
dfeec247 1210 && self
74b04a01 1211 .associated_item(info.def_id, item_name, Namespace::ValueNS)
2c00a5a8 1212 .filter(|item| {
ba9703b0 1213 if let ty::AssocKind::Fn = item.kind {
f9f354fc
XL
1214 let id = item
1215 .def_id
1216 .as_local()
3dfed10e 1217 .map(|def_id| self.tcx.hir().local_def_id_to_hir_id(def_id));
74b04a01 1218 if let Some(hir::Node::TraitItem(hir::TraitItem {
ba9703b0 1219 kind: hir::TraitItemKind::Fn(fn_sig, method),
74b04a01
XL
1220 ..
1221 })) = id.map(|id| self.tcx.hir().get(id))
1222 {
1223 let self_first_arg = match method {
ba9703b0 1224 hir::TraitFn::Required([ident, ..]) => {
74b04a01
XL
1225 ident.name == kw::SelfLower
1226 }
ba9703b0 1227 hir::TraitFn::Provided(body_id) => {
f9f354fc
XL
1228 self.tcx.hir().body(*body_id).params.first().map_or(
1229 false,
1230 |param| {
1231 matches!(
1232 param.pat.kind,
1233 hir::PatKind::Binding(_, _, ident, _)
1234 if ident.name == kw::SelfLower
1235 )
1236 },
1237 )
74b04a01
XL
1238 }
1239 _ => false,
1240 };
1241
1242 if !fn_sig.decl.implicit_self.has_implicit_self()
1243 && self_first_arg
1244 {
1245 if let Some(ty) = fn_sig.decl.inputs.get(0) {
1246 arbitrary_rcvr.push(ty.span);
1247 }
1248 return false;
1249 }
1250 }
1251 }
2c00a5a8
XL
1252 // We only want to suggest public or local traits (#45781).
1253 item.vis == ty::Visibility::Public || info.def_id.is_local()
1254 })
1255 .is_some()
a7813a04
XL
1256 })
1257 .collect::<Vec<_>>();
74b04a01
XL
1258 for span in &arbitrary_rcvr {
1259 err.span_label(
1260 *span,
1261 "the method might not be found because of this arbitrary self type",
1262 );
1263 }
cdc7bbd5
XL
1264 if alt_rcvr_sugg {
1265 return;
1266 }
a7813a04
XL
1267
1268 if !candidates.is_empty() {
0731742a 1269 // Sort from most relevant to least relevant.
a7813a04
XL
1270 candidates.sort_by(|a, b| a.cmp(b).reverse());
1271 candidates.dedup();
1272
1b1a35ee 1273 let param_type = match rcvr_ty.kind() {
416331ca 1274 ty::Param(param) => Some(param),
1b1a35ee 1275 ty::Ref(_, ty, _) => match ty.kind() {
416331ca
XL
1276 ty::Param(param) => Some(param),
1277 _ => None,
dfeec247 1278 },
416331ca
XL
1279 _ => None,
1280 };
1281 err.help(if param_type.is_some() {
1282 "items from traits can only be used if the type parameter is bounded by the trait"
1283 } else {
1284 "items from traits can only be used if the trait is implemented and in scope"
1285 });
fc512014 1286 let candidates_len = candidates.len();
dfeec247
XL
1287 let message = |action| {
1288 format!(
1289 "the following {traits_define} an item `{name}`, perhaps you need to {action} \
74b04a01 1290 {one_of_them}:",
dfeec247 1291 traits_define =
fc512014 1292 if candidates_len == 1 { "trait defines" } else { "traits define" },
dfeec247 1293 action = action,
fc512014 1294 one_of_them = if candidates_len == 1 { "it" } else { "one of them" },
dfeec247
XL
1295 name = item_name,
1296 )
1297 };
416331ca 1298 // Obtain the span for `param` and use it for a structured suggestion.
3dfed10e
XL
1299 if let (Some(ref param), Some(ref table)) =
1300 (param_type, self.in_progress_typeck_results)
1301 {
ba9703b0 1302 let table_owner = table.borrow().hir_owner;
f035d41b
XL
1303 let generics = self.tcx.generics_of(table_owner.to_def_id());
1304 let type_param = generics.type_param(param, self.tcx);
1305 let hir = &self.tcx.hir();
1306 if let Some(def_id) = type_param.def_id.as_local() {
3dfed10e 1307 let id = hir.local_def_id_to_hir_id(def_id);
f035d41b
XL
1308 // Get the `hir::Param` to verify whether it already has any bounds.
1309 // We do this to avoid suggesting code that ends up as `T: FooBar`,
1310 // instead we suggest `T: Foo + Bar` in that case.
1311 match hir.get(id) {
1312 Node::GenericParam(ref param) => {
1313 let mut impl_trait = false;
1314 let has_bounds =
1315 if let hir::GenericParamKind::Type { synthetic: Some(_), .. } =
1316 &param.kind
dfeec247 1317 {
e1599b0c
XL
1318 // We've found `fn foo(x: impl Trait)` instead of
1319 // `fn foo<T>(x: T)`. We want to suggest the correct
1320 // `fn foo(x: impl Trait + TraitBound)` instead of
1321 // `fn foo<T: TraitBound>(x: T)`. (#63706)
1322 impl_trait = true;
e74abb32
XL
1323 param.bounds.get(1)
1324 } else {
1325 param.bounds.get(0)
1326 };
f035d41b
XL
1327 let sp = hir.span(id);
1328 let sp = if let Some(first_bound) = has_bounds {
1329 // `sp` only covers `T`, change it so that it covers
1330 // `T:` when appropriate
1331 sp.until(first_bound.span())
1332 } else {
1333 sp
1334 };
1335 let trait_def_ids: FxHashSet<DefId> = param
1336 .bounds
1337 .iter()
6a06907d 1338 .filter_map(|bound| bound.trait_ref()?.trait_def_id())
f035d41b
XL
1339 .collect();
1340 if !candidates.iter().any(|t| trait_def_ids.contains(&t.def_id)) {
e74abb32
XL
1341 err.span_suggestions(
1342 sp,
f035d41b
XL
1343 &message(format!(
1344 "restrict type parameter `{}` with",
1345 param.name.ident(),
1346 )),
dfeec247 1347 candidates.iter().map(|t| {
f035d41b
XL
1348 format!(
1349 "{}{} {}{}",
1350 param.name.ident(),
1351 if impl_trait { " +" } else { ":" },
1352 self.tcx.def_path_str(t.def_id),
1353 if has_bounds.is_some() { " + " } else { "" },
1354 )
dfeec247 1355 }),
e74abb32
XL
1356 Applicability::MaybeIncorrect,
1357 );
e1599b0c 1358 }
fc512014 1359 return;
f035d41b
XL
1360 }
1361 Node::Item(hir::Item {
1362 kind: hir::ItemKind::Trait(.., bounds, _),
1363 ident,
1364 ..
1365 }) => {
1366 let (sp, sep, article) = if bounds.is_empty() {
1367 (ident.span.shrink_to_hi(), ":", "a")
1368 } else {
1369 (bounds.last().unwrap().span().shrink_to_hi(), " +", "another")
1370 };
1371 err.span_suggestions(
1372 sp,
1373 &message(format!("add {} supertrait for", article)),
1374 candidates.iter().map(|t| {
1375 format!("{} {}", sep, self.tcx.def_path_str(t.def_id),)
1376 }),
1377 Applicability::MaybeIncorrect,
1378 );
fc512014 1379 return;
416331ca 1380 }
f035d41b 1381 _ => {}
416331ca 1382 }
f035d41b 1383 }
416331ca
XL
1384 }
1385
fc512014
XL
1386 let (potential_candidates, explicitly_negative) = if param_type.is_some() {
1387 // FIXME: Even though negative bounds are not implemented, we could maybe handle
1388 // cases where a positive bound implies a negative impl.
1389 (candidates, Vec::new())
1390 } else if let Some(simp_rcvr_ty) = simplify_type(self.tcx, rcvr_ty, true) {
1391 let mut potential_candidates = Vec::new();
1392 let mut explicitly_negative = Vec::new();
1393 for candidate in candidates {
1394 // Check if there's a negative impl of `candidate` for `rcvr_ty`
1395 if self
1396 .tcx
1397 .all_impls(candidate.def_id)
1398 .filter(|imp_did| {
1399 self.tcx.impl_polarity(*imp_did) == ty::ImplPolarity::Negative
1400 })
1401 .any(|imp_did| {
1402 let imp = self.tcx.impl_trait_ref(imp_did).unwrap();
1403 let imp_simp = simplify_type(self.tcx, imp.self_ty(), true);
5869c6ff 1404 imp_simp.map_or(false, |s| s == simp_rcvr_ty)
fc512014
XL
1405 })
1406 {
1407 explicitly_negative.push(candidate);
1408 } else {
1409 potential_candidates.push(candidate);
74b04a01
XL
1410 }
1411 }
fc512014
XL
1412 (potential_candidates, explicitly_negative)
1413 } else {
1414 // We don't know enough about `recv_ty` to make proper suggestions.
1415 (candidates, Vec::new())
1416 };
1417
1418 let action = if let Some(param) = param_type {
1419 format!("restrict type parameter `{}` with", param)
1420 } else {
1421 // FIXME: it might only need to be imported into scope, not implemented.
1422 "implement".to_string()
1423 };
1424 match &potential_candidates[..] {
1425 [] => {}
1426 [trait_info] if trait_info.def_id.is_local() => {
1427 let span = self.tcx.hir().span_if_local(trait_info.def_id).unwrap();
1428 err.span_note(
1429 self.tcx.sess.source_map().guess_head_span(span),
1430 &format!(
1431 "`{}` defines an item `{}`, perhaps you need to {} it",
1432 self.tcx.def_path_str(trait_info.def_id),
1433 item_name,
1434 action
1435 ),
1436 );
1437 }
1438 trait_infos => {
74b04a01 1439 let mut msg = message(action);
fc512014 1440 for (i, trait_info) in trait_infos.iter().enumerate() {
74b04a01
XL
1441 msg.push_str(&format!(
1442 "\ncandidate #{}: `{}`",
1443 i + 1,
1444 self.tcx.def_path_str(trait_info.def_id),
1445 ));
1446 }
fc512014
XL
1447 err.note(&msg);
1448 }
1449 }
1450 match &explicitly_negative[..] {
1451 [] => {}
1452 [trait_info] => {
1453 let msg = format!(
1454 "the trait `{}` defines an item `{}`, but is explicitely unimplemented",
1455 self.tcx.def_path_str(trait_info.def_id),
1456 item_name
1457 );
1458 err.note(&msg);
1459 }
1460 trait_infos => {
1461 let mut msg = format!(
1462 "the following traits define an item `{}`, but are explicitely unimplemented:",
1463 item_name
1464 );
1465 for trait_info in trait_infos {
1466 msg.push_str(&format!("\n{}", self.tcx.def_path_str(trait_info.def_id)));
1467 }
1468 err.note(&msg);
416331ca 1469 }
a7813a04 1470 }
85aaf69f 1471 }
85aaf69f
SL
1472 }
1473
a7813a04
XL
1474 /// Checks whether there is a local type somewhere in the chain of
1475 /// autoderefs of `rcvr_ty`.
cdc7bbd5
XL
1476 fn type_derefs_to_local(
1477 &self,
1478 span: Span,
1479 rcvr_ty: Ty<'tcx>,
1480 source: SelfSource<'tcx>,
1481 ) -> bool {
9fa01778 1482 fn is_local(ty: Ty<'_>) -> bool {
1b1a35ee 1483 match ty.kind() {
b7449926
XL
1484 ty::Adt(def, _) => def.did.is_local(),
1485 ty::Foreign(did) => did.is_local(),
5869c6ff 1486 ty::Dynamic(ref tr, ..) => tr.principal().map_or(false, |d| d.def_id().is_local()),
b7449926 1487 ty::Param(_) => true,
a7813a04 1488
0731742a
XL
1489 // Everything else (primitive types, etc.) is effectively
1490 // non-local (there are "edge" cases, e.g., `(LocalType,)`, but
a7813a04
XL
1491 // the noise from these sort of types is usually just really
1492 // annoying, rather than any sort of help).
c30ab7b3 1493 _ => false,
a7813a04 1494 }
85aaf69f 1495 }
85aaf69f 1496
a7813a04
XL
1497 // This occurs for UFCS desugaring of `T::method`, where there is no
1498 // receiver expression for the method call, and thus no autoderef.
0731742a 1499 if let SelfSource::QPath(_) = source {
e74abb32 1500 return is_local(self.resolve_vars_with_obligations(rcvr_ty));
c34b1796 1501 }
c34b1796 1502
3157f602 1503 self.autoderef(span, rcvr_ty).any(|(ty, _)| is_local(ty))
c34b1796 1504 }
85aaf69f
SL
1505}
1506
cdc7bbd5 1507#[derive(Copy, Clone, Debug)]
0731742a 1508pub enum SelfSource<'a> {
dfeec247
XL
1509 QPath(&'a hir::Ty<'a>),
1510 MethodCall(&'a hir::Expr<'a> /* rcvr */),
0731742a
XL
1511}
1512
c34b1796 1513#[derive(Copy, Clone)]
85aaf69f 1514pub struct TraitInfo {
e9174d1e 1515 pub def_id: DefId,
85aaf69f
SL
1516}
1517
85aaf69f
SL
1518impl PartialEq for TraitInfo {
1519 fn eq(&self, other: &TraitInfo) -> bool {
1520 self.cmp(other) == Ordering::Equal
1521 }
1522}
1523impl Eq for TraitInfo {}
1524impl PartialOrd for TraitInfo {
c30ab7b3
SL
1525 fn partial_cmp(&self, other: &TraitInfo) -> Option<Ordering> {
1526 Some(self.cmp(other))
1527 }
85aaf69f
SL
1528}
1529impl Ord for TraitInfo {
1530 fn cmp(&self, other: &TraitInfo) -> Ordering {
0731742a
XL
1531 // Local crates are more important than remote ones (local:
1532 // `cnum == 0`), and otherwise we throw in the defid for totality.
85aaf69f 1533
b039eaaf
SL
1534 let lhs = (other.def_id.krate, other.def_id);
1535 let rhs = (self.def_id.krate, self.def_id);
85aaf69f
SL
1536 lhs.cmp(&rhs)
1537 }
1538}
1539
9fa01778 1540/// Retrieves all traits in this crate and any dependent crates.
416331ca 1541pub fn all_traits(tcx: TyCtxt<'_>) -> Vec<TraitInfo> {
17df50a5 1542 tcx.all_traits(()).iter().map(|&def_id| TraitInfo { def_id }).collect()
83c7162d
XL
1543}
1544
9fa01778 1545/// Computes all traits in this crate and any dependent crates.
17df50a5 1546fn compute_all_traits(tcx: TyCtxt<'_>, (): ()) -> &[DefId] {
0731742a 1547 use hir::itemlikevisit;
85aaf69f 1548
0731742a 1549 let mut traits = vec![];
85aaf69f 1550
0731742a 1551 // Crate-local:
476ff2be 1552
6a06907d 1553 struct Visitor<'a> {
0731742a
XL
1554 traits: &'a mut Vec<DefId>,
1555 }
32a655c1 1556
6a06907d 1557 impl<'v, 'a> itemlikevisit::ItemLikeVisitor<'v> for Visitor<'a> {
dfeec247 1558 fn visit_item(&mut self, i: &'v hir::Item<'v>) {
e74abb32 1559 match i.kind {
dfeec247 1560 hir::ItemKind::Trait(..) | hir::ItemKind::TraitAlias(..) => {
6a06907d 1561 self.traits.push(i.def_id.to_def_id());
532ac7d7 1562 }
dfeec247 1563 _ => (),
476ff2be 1564 }
85aaf69f 1565 }
0731742a 1566
dfeec247 1567 fn visit_trait_item(&mut self, _trait_item: &hir::TraitItem<'_>) {}
0731742a 1568
dfeec247 1569 fn visit_impl_item(&mut self, _impl_item: &hir::ImplItem<'_>) {}
fc512014
XL
1570
1571 fn visit_foreign_item(&mut self, _foreign_item: &hir::ForeignItem<'_>) {}
0731742a
XL
1572 }
1573
6a06907d 1574 tcx.hir().krate().visit_all_item_likes(&mut Visitor { traits: &mut traits });
0731742a
XL
1575
1576 // Cross-crate:
1577
1578 let mut external_mods = FxHashSet::default();
dc9dc135
XL
1579 fn handle_external_res(
1580 tcx: TyCtxt<'_>,
1581 traits: &mut Vec<DefId>,
1582 external_mods: &mut FxHashSet<DefId>,
1583 res: Res,
1584 ) {
48663c56 1585 match res {
ba9703b0 1586 Res::Def(DefKind::Trait | DefKind::TraitAlias, def_id) => {
0731742a
XL
1587 traits.push(def_id);
1588 }
48663c56 1589 Res::Def(DefKind::Mod, def_id) => {
0731742a
XL
1590 if !external_mods.insert(def_id) {
1591 return;
85aaf69f 1592 }
0731742a 1593 for child in tcx.item_children(def_id).iter() {
48663c56 1594 handle_external_res(tcx, traits, external_mods, child.res)
85aaf69f 1595 }
85aaf69f 1596 }
0731742a 1597 _ => {}
85aaf69f 1598 }
0731742a 1599 }
136023e0 1600 for &cnum in tcx.crates(()).iter() {
dfeec247 1601 let def_id = DefId { krate: cnum, index: CRATE_DEF_INDEX };
48663c56 1602 handle_external_res(tcx, &mut traits, &mut external_mods, Res::Def(DefKind::Mod, def_id));
0731742a 1603 }
85aaf69f 1604
17df50a5 1605 tcx.arena.alloc_from_iter(traits)
85aaf69f
SL
1606}
1607
f035d41b 1608pub fn provide(providers: &mut ty::query::Providers) {
17df50a5 1609 providers.all_traits = compute_all_traits;
85aaf69f 1610}
ff7c6d11 1611
dc9dc135 1612struct UsePlacementFinder<'tcx> {
9fa01778 1613 target_module: hir::HirId,
ff7c6d11
XL
1614 span: Option<Span>,
1615 found_use: bool,
dc9dc135 1616 tcx: TyCtxt<'tcx>,
ff7c6d11
XL
1617}
1618
dc9dc135 1619impl UsePlacementFinder<'tcx> {
ff7c6d11 1620 fn check(
dc9dc135 1621 tcx: TyCtxt<'tcx>,
dfeec247 1622 krate: &'tcx hir::Crate<'tcx>,
9fa01778 1623 target_module: hir::HirId,
ff7c6d11 1624 ) -> (Option<Span>, bool) {
dfeec247
XL
1625 let mut finder = UsePlacementFinder { target_module, span: None, found_use: false, tcx };
1626 intravisit::walk_crate(&mut finder, krate);
ff7c6d11
XL
1627 (finder.span, finder.found_use)
1628 }
1629}
1630
dfeec247
XL
1631impl intravisit::Visitor<'tcx> for UsePlacementFinder<'tcx> {
1632 fn visit_mod(&mut self, module: &'tcx hir::Mod<'tcx>, _: Span, hir_id: hir::HirId) {
ff7c6d11
XL
1633 if self.span.is_some() {
1634 return;
1635 }
9fa01778 1636 if hir_id != self.target_module {
dfeec247 1637 intravisit::walk_mod(self, module, hir_id);
ff7c6d11
XL
1638 return;
1639 }
0731742a 1640 // Find a `use` statement.
6a06907d
XL
1641 for &item_id in module.item_ids {
1642 let item = self.tcx.hir().item(item_id);
e74abb32 1643 match item.kind {
8faf50e0 1644 hir::ItemKind::Use(..) => {
0731742a
XL
1645 // Don't suggest placing a `use` before the prelude
1646 // import or other generated ones.
e1599b0c 1647 if !item.span.from_expansion() {
0531ce1d 1648 self.span = Some(item.span.shrink_to_lo());
ff7c6d11
XL
1649 self.found_use = true;
1650 return;
1651 }
dfeec247 1652 }
0731742a 1653 // Don't place `use` before `extern crate`...
8faf50e0 1654 hir::ItemKind::ExternCrate(_) => {}
0731742a 1655 // ...but do place them before the first other item.
dfeec247
XL
1656 _ => {
1657 if self.span.map_or(true, |span| item.span < span) {
1658 if !item.span.from_expansion() {
136023e0 1659 self.span = Some(item.span.shrink_to_lo());
dfeec247 1660 // Don't insert between attributes and an item.
6a06907d 1661 let attrs = self.tcx.hir().attrs(item.hir_id());
136023e0
XL
1662 // Find the first attribute on the item.
1663 // FIXME: This is broken for active attributes.
1664 for attr in attrs {
1665 if !attr.span.is_dummy()
1666 && self.span.map_or(true, |span| attr.span < span)
1667 {
1668 self.span = Some(attr.span.shrink_to_lo());
ff7c6d11
XL
1669 }
1670 }
1671 }
1672 }
dfeec247 1673 }
ff7c6d11
XL
1674 }
1675 }
1676 }
0731742a 1677
ba9703b0 1678 type Map = intravisit::ErasedMap<'tcx>;
dfeec247 1679
ba9703b0 1680 fn nested_visit_map(&mut self) -> intravisit::NestedVisitorMap<Self::Map> {
dfeec247 1681 intravisit::NestedVisitorMap::None
ff7c6d11
XL
1682 }
1683}
dfeec247
XL
1684
1685fn print_disambiguation_help(
f9f354fc 1686 item_name: Ident,
dfeec247
XL
1687 args: Option<&'tcx [hir::Expr<'tcx>]>,
1688 err: &mut DiagnosticBuilder<'_>,
1689 trait_name: String,
1690 rcvr_ty: Ty<'_>,
1691 kind: ty::AssocKind,
ba9703b0 1692 def_id: DefId,
dfeec247
XL
1693 span: Span,
1694 candidate: Option<usize>,
1695 source_map: &source_map::SourceMap,
1696) {
1697 let mut applicability = Applicability::MachineApplicable;
ba9703b0 1698 let sugg_args = if let (ty::AssocKind::Fn, Some(args)) = (kind, args) {
dfeec247
XL
1699 format!(
1700 "({}{})",
1701 if rcvr_ty.is_region_ptr() {
1702 if rcvr_ty.is_mutable_ptr() { "&mut " } else { "&" }
1703 } else {
1704 ""
1705 },
1706 args.iter()
1707 .map(|arg| source_map.span_to_snippet(arg.span).unwrap_or_else(|_| {
1708 applicability = Applicability::HasPlaceholders;
1709 "_".to_owned()
1710 }))
1711 .collect::<Vec<_>>()
1712 .join(", "),
1713 )
1714 } else {
1715 String::new()
1716 };
1717 let sugg = format!("{}::{}{}", trait_name, item_name, sugg_args);
1718 err.span_suggestion(
1719 span,
1720 &format!(
1721 "disambiguate the {} for {}",
ba9703b0 1722 kind.as_def_kind().descr(def_id),
dfeec247
XL
1723 if let Some(candidate) = candidate {
1724 format!("candidate #{}", candidate)
1725 } else {
1726 "the candidate".to_string()
1727 },
1728 ),
1729 sugg,
1730 applicability,
1731 );
1732}