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