]> git.lizzy.rs Git - rust.git/blob - compiler/rustc_resolve/src/late/diagnostics.rs
suggest calling `Self::associated_function()`
[rust.git] / compiler / rustc_resolve / src / late / diagnostics.rs
1 use crate::diagnostics::{ImportSuggestion, LabelSuggestion, TypoSuggestion};
2 use crate::late::lifetimes::{ElisionFailureInfo, LifetimeContext};
3 use crate::late::{AliasPossibility, LateResolutionVisitor, RibKind};
4 use crate::late::{LifetimeBinderKind, LifetimeRibKind};
5 use crate::path_names_to_string;
6 use crate::{Finalize, Module, ModuleKind, ModuleOrUniformRoot};
7 use crate::{PathResult, PathSource, Segment};
8
9 use rustc_ast::visit::{FnCtxt, FnKind};
10 use rustc_ast::{
11     self as ast, AssocItemKind, Expr, ExprKind, GenericParam, GenericParamKind, Item, ItemKind,
12     NodeId, Path, Ty, TyKind,
13 };
14 use rustc_ast_pretty::pprust::path_segment_to_string;
15 use rustc_data_structures::fx::FxHashSet;
16 use rustc_errors::{
17     pluralize, struct_span_err, Applicability, Diagnostic, DiagnosticBuilder, ErrorGuaranteed,
18     MultiSpan,
19 };
20 use rustc_hir as hir;
21 use rustc_hir::def::Namespace::{self, *};
22 use rustc_hir::def::{self, CtorKind, CtorOf, DefKind};
23 use rustc_hir::def_id::{DefId, CRATE_DEF_ID, LOCAL_CRATE};
24 use rustc_hir::PrimTy;
25 use rustc_session::parse::feature_err;
26 use rustc_span::edition::Edition;
27 use rustc_span::hygiene::MacroKind;
28 use rustc_span::lev_distance::find_best_match_for_name;
29 use rustc_span::symbol::{kw, sym, Ident, Symbol};
30 use rustc_span::{BytePos, Span, DUMMY_SP};
31
32 use std::iter;
33 use std::ops::Deref;
34
35 use tracing::debug;
36
37 type Res = def::Res<ast::NodeId>;
38
39 /// A field or associated item from self type suggested in case of resolution failure.
40 enum AssocSuggestion {
41     Field,
42     MethodWithSelf,
43     AssocFn,
44     AssocType,
45     AssocConst,
46 }
47
48 impl AssocSuggestion {
49     fn action(&self) -> &'static str {
50         match self {
51             AssocSuggestion::Field => "use the available field",
52             AssocSuggestion::MethodWithSelf => "call the method with the fully-qualified path",
53             AssocSuggestion::AssocFn => "call the associated function",
54             AssocSuggestion::AssocConst => "use the associated `const`",
55             AssocSuggestion::AssocType => "use the associated type",
56         }
57     }
58 }
59
60 crate enum MissingLifetimeSpot<'tcx> {
61     Generics(&'tcx hir::Generics<'tcx>),
62     HigherRanked { span: Span, span_type: ForLifetimeSpanType },
63     Static,
64 }
65
66 crate enum ForLifetimeSpanType {
67     BoundEmpty,
68     BoundTail,
69     TypeEmpty,
70     TypeTail,
71 }
72
73 impl ForLifetimeSpanType {
74     crate fn descr(&self) -> &'static str {
75         match self {
76             Self::BoundEmpty | Self::BoundTail => "bound",
77             Self::TypeEmpty | Self::TypeTail => "type",
78         }
79     }
80
81     crate fn suggestion(&self, sugg: &str) -> String {
82         match self {
83             Self::BoundEmpty | Self::TypeEmpty => format!("for<{}> ", sugg),
84             Self::BoundTail | Self::TypeTail => format!(", {}", sugg),
85         }
86     }
87 }
88
89 impl<'tcx> Into<MissingLifetimeSpot<'tcx>> for &'tcx hir::Generics<'tcx> {
90     fn into(self) -> MissingLifetimeSpot<'tcx> {
91         MissingLifetimeSpot::Generics(self)
92     }
93 }
94
95 fn is_self_type(path: &[Segment], namespace: Namespace) -> bool {
96     namespace == TypeNS && path.len() == 1 && path[0].ident.name == kw::SelfUpper
97 }
98
99 fn is_self_value(path: &[Segment], namespace: Namespace) -> bool {
100     namespace == ValueNS && path.len() == 1 && path[0].ident.name == kw::SelfLower
101 }
102
103 /// Gets the stringified path for an enum from an `ImportSuggestion` for an enum variant.
104 fn import_candidate_to_enum_paths(suggestion: &ImportSuggestion) -> (String, String) {
105     let variant_path = &suggestion.path;
106     let variant_path_string = path_names_to_string(variant_path);
107
108     let path_len = suggestion.path.segments.len();
109     let enum_path = ast::Path {
110         span: suggestion.path.span,
111         segments: suggestion.path.segments[0..path_len - 1].to_vec(),
112         tokens: None,
113     };
114     let enum_path_string = path_names_to_string(&enum_path);
115
116     (variant_path_string, enum_path_string)
117 }
118
119 impl<'a: 'ast, 'ast> LateResolutionVisitor<'a, '_, 'ast> {
120     fn def_span(&self, def_id: DefId) -> Option<Span> {
121         match def_id.krate {
122             LOCAL_CRATE => self.r.opt_span(def_id),
123             _ => Some(
124                 self.r
125                     .session
126                     .source_map()
127                     .guess_head_span(self.r.cstore().get_span_untracked(def_id, self.r.session)),
128             ),
129         }
130     }
131
132     /// Handles error reporting for `smart_resolve_path_fragment` function.
133     /// Creates base error and amends it with one short label and possibly some longer helps/notes.
134     pub(crate) fn smart_resolve_report_errors(
135         &mut self,
136         path: &[Segment],
137         span: Span,
138         source: PathSource<'_>,
139         res: Option<Res>,
140     ) -> (DiagnosticBuilder<'a, ErrorGuaranteed>, Vec<ImportSuggestion>) {
141         let ident_span = path.last().map_or(span, |ident| ident.ident.span);
142         let ns = source.namespace();
143         let is_expected = &|res| source.is_expected(res);
144         let is_enum_variant = &|res| matches!(res, Res::Def(DefKind::Variant, _));
145
146         // Make the base error.
147         struct BaseError<'a> {
148             msg: String,
149             fallback_label: String,
150             span: Span,
151             could_be_expr: bool,
152             suggestion: Option<(Span, &'a str, String)>,
153         }
154         let mut expected = source.descr_expected();
155         let path_str = Segment::names_to_string(path);
156         let item_str = path.last().unwrap().ident;
157         let base_error = if let Some(res) = res {
158             BaseError {
159                 msg: format!("expected {}, found {} `{}`", expected, res.descr(), path_str),
160                 fallback_label: format!("not a {expected}"),
161                 span,
162                 could_be_expr: match res {
163                     Res::Def(DefKind::Fn, _) => {
164                         // Verify whether this is a fn call or an Fn used as a type.
165                         self.r
166                             .session
167                             .source_map()
168                             .span_to_snippet(span)
169                             .map(|snippet| snippet.ends_with(')'))
170                             .unwrap_or(false)
171                     }
172                     Res::Def(
173                         DefKind::Ctor(..) | DefKind::AssocFn | DefKind::Const | DefKind::AssocConst,
174                         _,
175                     )
176                     | Res::SelfCtor(_)
177                     | Res::PrimTy(_)
178                     | Res::Local(_) => true,
179                     _ => false,
180                 },
181                 suggestion: None,
182             }
183         } else {
184             let item_span = path.last().unwrap().ident.span;
185             let (mod_prefix, mod_str, suggestion) = if path.len() == 1 {
186                 debug!(?self.diagnostic_metadata.current_impl_items);
187                 debug!(?self.diagnostic_metadata.current_function);
188                 let suggestion = if let Some(items) = self.diagnostic_metadata.current_impl_items
189                     && let Some((fn_kind, _)) = self.diagnostic_metadata.current_function
190                     && self.current_trait_ref.is_none()
191                     && let Some(FnCtxt::Assoc(_)) = fn_kind.ctxt()
192                     && let Some(item) = items.iter().find(|i| {
193                         if let AssocItemKind::Fn(fn_) = &i.kind
194                             && !fn_.sig.decl.has_self()
195                             && i.ident.name == item_str.name
196                         {
197                             debug!(?item_str.name);
198                             debug!(?fn_.sig.decl.inputs);
199                             return true
200                         }
201                         false
202                     })
203                 {
204                     Some((
205                         item_span,
206                         "consider using the associated function",
207                         format!("Self::{}", item.ident)
208                     ))
209                 } else {
210                     None
211                 };
212                 (String::new(), "this scope".to_string(), suggestion)
213             } else if path.len() == 2 && path[0].ident.name == kw::PathRoot {
214                 if self.r.session.edition() > Edition::Edition2015 {
215                     // In edition 2018 onwards, the `::foo` syntax may only pull from the extern prelude
216                     // which overrides all other expectations of item type
217                     expected = "crate";
218                     (String::new(), "the list of imported crates".to_string(), None)
219                 } else {
220                     (String::new(), "the crate root".to_string(), None)
221                 }
222             } else if path.len() == 2 && path[0].ident.name == kw::Crate {
223                 (String::new(), "the crate root".to_string(), None)
224             } else {
225                 let mod_path = &path[..path.len() - 1];
226                 let mod_prefix = match self.resolve_path(mod_path, Some(TypeNS), Finalize::No) {
227                     PathResult::Module(ModuleOrUniformRoot::Module(module)) => module.res(),
228                     _ => None,
229                 }
230                 .map_or_else(String::new, |res| format!("{} ", res.descr()));
231                 (mod_prefix, format!("`{}`", Segment::names_to_string(mod_path)), None)
232             };
233             BaseError {
234                 msg: format!("cannot find {expected} `{item_str}` in {mod_prefix}{mod_str}"),
235                 fallback_label: if path_str == "async" && expected.starts_with("struct") {
236                     "`async` blocks are only allowed in Rust 2018 or later".to_string()
237                 } else {
238                     format!("not found in {mod_str}")
239                 },
240                 span: item_span,
241                 could_be_expr: false,
242                 suggestion,
243             }
244         };
245
246         let code = source.error_code(res.is_some());
247         let mut err =
248             self.r.session.struct_span_err_with_code(base_error.span, &base_error.msg, code);
249
250         if let Some(sugg) = base_error.suggestion {
251             err.span_suggestion_verbose(sugg.0, sugg.1, sugg.2, Applicability::MaybeIncorrect);
252         }
253
254         if let Some(span) = self.diagnostic_metadata.current_block_could_be_bare_struct_literal {
255             err.multipart_suggestion(
256                 "you might have meant to write a `struct` literal",
257                 vec![
258                     (span.shrink_to_lo(), "{ SomeStruct ".to_string()),
259                     (span.shrink_to_hi(), "}".to_string()),
260                 ],
261                 Applicability::HasPlaceholders,
262             );
263         }
264         match (source, self.diagnostic_metadata.in_if_condition) {
265             (PathSource::Expr(_), Some(Expr { span, kind: ExprKind::Assign(..), .. })) => {
266                 err.span_suggestion_verbose(
267                     span.shrink_to_lo(),
268                     "you might have meant to use pattern matching",
269                     "let ".to_string(),
270                     Applicability::MaybeIncorrect,
271                 );
272             }
273             _ => {}
274         }
275
276         let is_assoc_fn = self.self_type_is_available();
277         // Emit help message for fake-self from other languages (e.g., `this` in Javascript).
278         if ["this", "my"].contains(&item_str.as_str()) && is_assoc_fn {
279             err.span_suggestion_short(
280                 span,
281                 "you might have meant to use `self` here instead",
282                 "self".to_string(),
283                 Applicability::MaybeIncorrect,
284             );
285             if !self.self_value_is_available(path[0].ident.span) {
286                 if let Some((FnKind::Fn(_, _, sig, ..), fn_span)) =
287                     &self.diagnostic_metadata.current_function
288                 {
289                     let (span, sugg) = if let Some(param) = sig.decl.inputs.get(0) {
290                         (param.span.shrink_to_lo(), "&self, ")
291                     } else {
292                         (
293                             self.r
294                                 .session
295                                 .source_map()
296                                 .span_through_char(*fn_span, '(')
297                                 .shrink_to_hi(),
298                             "&self",
299                         )
300                     };
301                     err.span_suggestion_verbose(
302                         span,
303                         "if you meant to use `self`, you are also missing a `self` receiver \
304                          argument",
305                         sugg.to_string(),
306                         Applicability::MaybeIncorrect,
307                     );
308                 }
309             }
310         }
311
312         self.detect_assoct_type_constraint_meant_as_path(base_error.span, &mut err);
313
314         // Emit special messages for unresolved `Self` and `self`.
315         if is_self_type(path, ns) {
316             err.code(rustc_errors::error_code!(E0411));
317             err.span_label(
318                 span,
319                 "`Self` is only available in impls, traits, and type definitions".to_string(),
320             );
321             return (err, Vec::new());
322         }
323         if is_self_value(path, ns) {
324             debug!("smart_resolve_path_fragment: E0424, source={:?}", source);
325
326             err.code(rustc_errors::error_code!(E0424));
327             err.span_label(span, match source {
328                 PathSource::Pat => "`self` value is a keyword and may not be bound to variables or shadowed"
329                                    .to_string(),
330                 _ => "`self` value is a keyword only available in methods with a `self` parameter"
331                      .to_string(),
332             });
333             if let Some((fn_kind, span)) = &self.diagnostic_metadata.current_function {
334                 // The current function has a `self' parameter, but we were unable to resolve
335                 // a reference to `self`. This can only happen if the `self` identifier we
336                 // are resolving came from a different hygiene context.
337                 if fn_kind.decl().inputs.get(0).map_or(false, |p| p.is_self()) {
338                     err.span_label(*span, "this function has a `self` parameter, but a macro invocation can only access identifiers it receives from parameters");
339                 } else {
340                     let doesnt = if is_assoc_fn {
341                         let (span, sugg) = fn_kind
342                             .decl()
343                             .inputs
344                             .get(0)
345                             .map(|p| (p.span.shrink_to_lo(), "&self, "))
346                             .unwrap_or_else(|| {
347                                 // Try to look for the "(" after the function name, if possible.
348                                 // This avoids placing the suggestion into the visibility specifier.
349                                 let span = fn_kind
350                                     .ident()
351                                     .map_or(*span, |ident| span.with_lo(ident.span.hi()));
352                                 (
353                                     self.r
354                                         .session
355                                         .source_map()
356                                         .span_through_char(span, '(')
357                                         .shrink_to_hi(),
358                                     "&self",
359                                 )
360                             });
361                         err.span_suggestion_verbose(
362                             span,
363                             "add a `self` receiver parameter to make the associated `fn` a method",
364                             sugg.to_string(),
365                             Applicability::MaybeIncorrect,
366                         );
367                         "doesn't"
368                     } else {
369                         "can't"
370                     };
371                     if let Some(ident) = fn_kind.ident() {
372                         err.span_label(
373                             ident.span,
374                             &format!("this function {} have a `self` parameter", doesnt),
375                         );
376                     }
377                 }
378             }
379             return (err, Vec::new());
380         }
381
382         // Try to lookup name in more relaxed fashion for better error reporting.
383         let ident = path.last().unwrap().ident;
384         let candidates = self
385             .r
386             .lookup_import_candidates(ident, ns, &self.parent_scope, is_expected)
387             .into_iter()
388             .filter(|ImportSuggestion { did, .. }| {
389                 match (did, res.and_then(|res| res.opt_def_id())) {
390                     (Some(suggestion_did), Some(actual_did)) => *suggestion_did != actual_did,
391                     _ => true,
392                 }
393             })
394             .collect::<Vec<_>>();
395         let crate_def_id = CRATE_DEF_ID.to_def_id();
396         if candidates.is_empty() && is_expected(Res::Def(DefKind::Enum, crate_def_id)) {
397             let mut enum_candidates: Vec<_> = self
398                 .r
399                 .lookup_import_candidates(ident, ns, &self.parent_scope, is_enum_variant)
400                 .into_iter()
401                 .map(|suggestion| import_candidate_to_enum_paths(&suggestion))
402                 .filter(|(_, enum_ty_path)| !enum_ty_path.starts_with("std::prelude::"))
403                 .collect();
404             if !enum_candidates.is_empty() {
405                 if let (PathSource::Type, Some(span)) =
406                     (source, self.diagnostic_metadata.current_type_ascription.last())
407                 {
408                     if self
409                         .r
410                         .session
411                         .parse_sess
412                         .type_ascription_path_suggestions
413                         .borrow()
414                         .contains(span)
415                     {
416                         // Already reported this issue on the lhs of the type ascription.
417                         err.delay_as_bug();
418                         return (err, candidates);
419                     }
420                 }
421
422                 enum_candidates.sort();
423
424                 // Contextualize for E0412 "cannot find type", but don't belabor the point
425                 // (that it's a variant) for E0573 "expected type, found variant".
426                 let preamble = if res.is_none() {
427                     let others = match enum_candidates.len() {
428                         1 => String::new(),
429                         2 => " and 1 other".to_owned(),
430                         n => format!(" and {} others", n),
431                     };
432                     format!("there is an enum variant `{}`{}; ", enum_candidates[0].0, others)
433                 } else {
434                     String::new()
435                 };
436                 let msg = format!("{}try using the variant's enum", preamble);
437
438                 err.span_suggestions(
439                     span,
440                     &msg,
441                     enum_candidates.into_iter().map(|(_variant_path, enum_ty_path)| enum_ty_path),
442                     Applicability::MachineApplicable,
443                 );
444             }
445         }
446         if path.len() == 1 && self.self_type_is_available() {
447             if let Some(candidate) = self.lookup_assoc_candidate(ident, ns, is_expected) {
448                 let self_is_available = self.self_value_is_available(path[0].ident.span);
449                 match candidate {
450                     AssocSuggestion::Field => {
451                         if self_is_available {
452                             err.span_suggestion(
453                                 span,
454                                 "you might have meant to use the available field",
455                                 format!("self.{}", path_str),
456                                 Applicability::MachineApplicable,
457                             );
458                         } else {
459                             err.span_label(span, "a field by this name exists in `Self`");
460                         }
461                     }
462                     AssocSuggestion::MethodWithSelf if self_is_available => {
463                         err.span_suggestion(
464                             span,
465                             "you might have meant to call the method",
466                             format!("self.{}", path_str),
467                             Applicability::MachineApplicable,
468                         );
469                     }
470                     AssocSuggestion::MethodWithSelf
471                     | AssocSuggestion::AssocFn
472                     | AssocSuggestion::AssocConst
473                     | AssocSuggestion::AssocType => {
474                         err.span_suggestion(
475                             span,
476                             &format!("you might have meant to {}", candidate.action()),
477                             format!("Self::{}", path_str),
478                             Applicability::MachineApplicable,
479                         );
480                     }
481                 }
482                 return (err, candidates);
483             }
484
485             // If the first argument in call is `self` suggest calling a method.
486             if let Some((call_span, args_span)) = self.call_has_self_arg(source) {
487                 let mut args_snippet = String::new();
488                 if let Some(args_span) = args_span {
489                     if let Ok(snippet) = self.r.session.source_map().span_to_snippet(args_span) {
490                         args_snippet = snippet;
491                     }
492                 }
493
494                 err.span_suggestion(
495                     call_span,
496                     &format!("try calling `{}` as a method", ident),
497                     format!("self.{}({})", path_str, args_snippet),
498                     Applicability::MachineApplicable,
499                 );
500                 return (err, candidates);
501             }
502         }
503
504         // Try Levenshtein algorithm.
505         let typo_sugg = self.lookup_typo_candidate(path, ns, is_expected);
506         // Try context-dependent help if relaxed lookup didn't work.
507         if let Some(res) = res {
508             if self.smart_resolve_context_dependent_help(
509                 &mut err,
510                 span,
511                 source,
512                 res,
513                 &path_str,
514                 &base_error.fallback_label,
515             ) {
516                 // We do this to avoid losing a secondary span when we override the main error span.
517                 self.r.add_typo_suggestion(&mut err, typo_sugg, ident_span);
518                 return (err, candidates);
519             }
520         }
521
522         let is_macro =
523             base_error.span.from_expansion() && base_error.span.desugaring_kind().is_none();
524         if !self.type_ascription_suggestion(&mut err, base_error.span) {
525             let mut fallback = false;
526             if let (
527                 PathSource::Trait(AliasPossibility::Maybe),
528                 Some(Res::Def(DefKind::Struct | DefKind::Enum | DefKind::Union, _)),
529                 false,
530             ) = (source, res, is_macro)
531             {
532                 if let Some(bounds @ [_, .., _]) = self.diagnostic_metadata.current_trait_object {
533                     fallback = true;
534                     let spans: Vec<Span> = bounds
535                         .iter()
536                         .map(|bound| bound.span())
537                         .filter(|&sp| sp != base_error.span)
538                         .collect();
539
540                     let start_span = bounds.iter().map(|bound| bound.span()).next().unwrap();
541                     // `end_span` is the end of the poly trait ref (Foo + 'baz + Bar><)
542                     let end_span = bounds.iter().map(|bound| bound.span()).last().unwrap();
543                     // `last_bound_span` is the last bound of the poly trait ref (Foo + >'baz< + Bar)
544                     let last_bound_span = spans.last().cloned().unwrap();
545                     let mut multi_span: MultiSpan = spans.clone().into();
546                     for sp in spans {
547                         let msg = if sp == last_bound_span {
548                             format!(
549                                 "...because of {these} bound{s}",
550                                 these = pluralize!("this", bounds.len() - 1),
551                                 s = pluralize!(bounds.len() - 1),
552                             )
553                         } else {
554                             String::new()
555                         };
556                         multi_span.push_span_label(sp, msg);
557                     }
558                     multi_span.push_span_label(
559                         base_error.span,
560                         "expected this type to be a trait...".to_string(),
561                     );
562                     err.span_help(
563                         multi_span,
564                         "`+` is used to constrain a \"trait object\" type with lifetimes or \
565                          auto-traits; structs and enums can't be bound in that way",
566                     );
567                     if bounds.iter().all(|bound| match bound {
568                         ast::GenericBound::Outlives(_) => true,
569                         ast::GenericBound::Trait(tr, _) => tr.span == base_error.span,
570                     }) {
571                         let mut sugg = vec![];
572                         if base_error.span != start_span {
573                             sugg.push((start_span.until(base_error.span), String::new()));
574                         }
575                         if base_error.span != end_span {
576                             sugg.push((base_error.span.shrink_to_hi().to(end_span), String::new()));
577                         }
578
579                         err.multipart_suggestion(
580                             "if you meant to use a type and not a trait here, remove the bounds",
581                             sugg,
582                             Applicability::MaybeIncorrect,
583                         );
584                     }
585                 }
586             }
587
588             fallback |= self.restrict_assoc_type_in_where_clause(span, &mut err);
589
590             if !self.r.add_typo_suggestion(&mut err, typo_sugg, ident_span) {
591                 fallback = true;
592                 match self.diagnostic_metadata.current_let_binding {
593                     Some((pat_sp, Some(ty_sp), None))
594                         if ty_sp.contains(base_error.span) && base_error.could_be_expr =>
595                     {
596                         err.span_suggestion_short(
597                             pat_sp.between(ty_sp),
598                             "use `=` if you meant to assign",
599                             " = ".to_string(),
600                             Applicability::MaybeIncorrect,
601                         );
602                     }
603                     _ => {}
604                 }
605
606                 // If the trait has a single item (which wasn't matched by Levenshtein), suggest it
607                 let suggestion = self.get_single_associated_item(&path, &source, is_expected);
608                 self.r.add_typo_suggestion(&mut err, suggestion, ident_span);
609             }
610             if fallback {
611                 // Fallback label.
612                 err.span_label(base_error.span, base_error.fallback_label);
613             }
614         }
615         if let Some(err_code) = &err.code {
616             if err_code == &rustc_errors::error_code!(E0425) {
617                 for label_rib in &self.label_ribs {
618                     for (label_ident, node_id) in &label_rib.bindings {
619                         if format!("'{}", ident) == label_ident.to_string() {
620                             err.span_label(label_ident.span, "a label with a similar name exists");
621                             if let PathSource::Expr(Some(Expr {
622                                 kind: ExprKind::Break(None, Some(_)),
623                                 ..
624                             })) = source
625                             {
626                                 err.span_suggestion(
627                                     span,
628                                     "use the similarly named label",
629                                     label_ident.name.to_string(),
630                                     Applicability::MaybeIncorrect,
631                                 );
632                                 // Do not lint against unused label when we suggest them.
633                                 self.diagnostic_metadata.unused_labels.remove(node_id);
634                             }
635                         }
636                     }
637                 }
638             } else if err_code == &rustc_errors::error_code!(E0412) {
639                 if let Some(correct) = Self::likely_rust_type(path) {
640                     err.span_suggestion(
641                         span,
642                         "perhaps you intended to use this type",
643                         correct.to_string(),
644                         Applicability::MaybeIncorrect,
645                     );
646                 }
647             }
648         }
649
650         (err, candidates)
651     }
652
653     fn detect_assoct_type_constraint_meant_as_path(&self, base_span: Span, err: &mut Diagnostic) {
654         let Some(ty) = self.diagnostic_metadata.current_type_path else { return; };
655         let TyKind::Path(_, path) = &ty.kind else { return; };
656         for segment in &path.segments {
657             let Some(params) = &segment.args else { continue; };
658             let ast::GenericArgs::AngleBracketed(ref params) = params.deref() else { continue; };
659             for param in &params.args {
660                 let ast::AngleBracketedArg::Constraint(constraint) = param else { continue; };
661                 let ast::AssocConstraintKind::Bound { bounds } = &constraint.kind else {
662                     continue;
663                 };
664                 for bound in bounds {
665                     let ast::GenericBound::Trait(trait_ref, ast::TraitBoundModifier::None)
666                         = bound else
667                     {
668                         continue;
669                     };
670                     if base_span == trait_ref.span {
671                         err.span_suggestion_verbose(
672                             constraint.ident.span.between(trait_ref.span),
673                             "you might have meant to write a path instead of an associated type bound",
674                             "::".to_string(),
675                             Applicability::MachineApplicable,
676                         );
677                     }
678                 }
679             }
680         }
681     }
682
683     fn get_single_associated_item(
684         &mut self,
685         path: &[Segment],
686         source: &PathSource<'_>,
687         filter_fn: &impl Fn(Res) -> bool,
688     ) -> Option<TypoSuggestion> {
689         if let crate::PathSource::TraitItem(_) = source {
690             let mod_path = &path[..path.len() - 1];
691             if let PathResult::Module(ModuleOrUniformRoot::Module(module)) =
692                 self.resolve_path(mod_path, None, Finalize::No)
693             {
694                 let resolutions = self.r.resolutions(module).borrow();
695                 let targets: Vec<_> =
696                     resolutions
697                         .iter()
698                         .filter_map(|(key, resolution)| {
699                             resolution.borrow().binding.map(|binding| binding.res()).and_then(
700                                 |res| if filter_fn(res) { Some((key, res)) } else { None },
701                             )
702                         })
703                         .collect();
704                 if targets.len() == 1 {
705                     let target = targets[0];
706                     return Some(TypoSuggestion::single_item_from_res(
707                         target.0.ident.name,
708                         target.1,
709                     ));
710                 }
711             }
712         }
713         None
714     }
715
716     /// Given `where <T as Bar>::Baz: String`, suggest `where T: Bar<Baz = String>`.
717     fn restrict_assoc_type_in_where_clause(&mut self, span: Span, err: &mut Diagnostic) -> bool {
718         // Detect that we are actually in a `where` predicate.
719         let (bounded_ty, bounds, where_span) =
720             if let Some(ast::WherePredicate::BoundPredicate(ast::WhereBoundPredicate {
721                 bounded_ty,
722                 bound_generic_params,
723                 bounds,
724                 span,
725             })) = self.diagnostic_metadata.current_where_predicate
726             {
727                 if !bound_generic_params.is_empty() {
728                     return false;
729                 }
730                 (bounded_ty, bounds, span)
731             } else {
732                 return false;
733             };
734
735         // Confirm that the target is an associated type.
736         let (ty, position, path) = if let ast::TyKind::Path(
737             Some(ast::QSelf { ty, position, .. }),
738             path,
739         ) = &bounded_ty.kind
740         {
741             // use this to verify that ident is a type param.
742             let Some(partial_res) = self.r.partial_res_map.get(&bounded_ty.id) else {
743                 return false;
744             };
745             if !(matches!(
746                 partial_res.base_res(),
747                 hir::def::Res::Def(hir::def::DefKind::AssocTy, _)
748             ) && partial_res.unresolved_segments() == 0)
749             {
750                 return false;
751             }
752             (ty, position, path)
753         } else {
754             return false;
755         };
756
757         let peeled_ty = ty.peel_refs();
758         if let ast::TyKind::Path(None, type_param_path) = &peeled_ty.kind {
759             // Confirm that the `SelfTy` is a type parameter.
760             let Some(partial_res) = self.r.partial_res_map.get(&peeled_ty.id) else {
761                 return false;
762             };
763             if !(matches!(
764                 partial_res.base_res(),
765                 hir::def::Res::Def(hir::def::DefKind::TyParam, _)
766             ) && partial_res.unresolved_segments() == 0)
767             {
768                 return false;
769             }
770             if let (
771                 [ast::PathSegment { ident: constrain_ident, args: None, .. }],
772                 [ast::GenericBound::Trait(poly_trait_ref, ast::TraitBoundModifier::None)],
773             ) = (&type_param_path.segments[..], &bounds[..])
774             {
775                 if let [ast::PathSegment { ident, args: None, .. }] =
776                     &poly_trait_ref.trait_ref.path.segments[..]
777                 {
778                     if ident.span == span {
779                         err.span_suggestion_verbose(
780                             *where_span,
781                             &format!("constrain the associated type to `{}`", ident),
782                             format!(
783                                 "{}: {}<{} = {}>",
784                                 self.r
785                                     .session
786                                     .source_map()
787                                     .span_to_snippet(ty.span) // Account for `<&'a T as Foo>::Bar`.
788                                     .unwrap_or_else(|_| constrain_ident.to_string()),
789                                 path.segments[..*position]
790                                     .iter()
791                                     .map(|segment| path_segment_to_string(segment))
792                                     .collect::<Vec<_>>()
793                                     .join("::"),
794                                 path.segments[*position..]
795                                     .iter()
796                                     .map(|segment| path_segment_to_string(segment))
797                                     .collect::<Vec<_>>()
798                                     .join("::"),
799                                 ident,
800                             ),
801                             Applicability::MaybeIncorrect,
802                         );
803                     }
804                     return true;
805                 }
806             }
807         }
808         false
809     }
810
811     /// Check if the source is call expression and the first argument is `self`. If true,
812     /// return the span of whole call and the span for all arguments expect the first one (`self`).
813     fn call_has_self_arg(&self, source: PathSource<'_>) -> Option<(Span, Option<Span>)> {
814         let mut has_self_arg = None;
815         if let PathSource::Expr(Some(parent)) = source {
816             match &parent.kind {
817                 ExprKind::Call(_, args) if !args.is_empty() => {
818                     let mut expr_kind = &args[0].kind;
819                     loop {
820                         match expr_kind {
821                             ExprKind::Path(_, arg_name) if arg_name.segments.len() == 1 => {
822                                 if arg_name.segments[0].ident.name == kw::SelfLower {
823                                     let call_span = parent.span;
824                                     let tail_args_span = if args.len() > 1 {
825                                         Some(Span::new(
826                                             args[1].span.lo(),
827                                             args.last().unwrap().span.hi(),
828                                             call_span.ctxt(),
829                                             None,
830                                         ))
831                                     } else {
832                                         None
833                                     };
834                                     has_self_arg = Some((call_span, tail_args_span));
835                                 }
836                                 break;
837                             }
838                             ExprKind::AddrOf(_, _, expr) => expr_kind = &expr.kind,
839                             _ => break,
840                         }
841                     }
842                 }
843                 _ => (),
844             }
845         };
846         has_self_arg
847     }
848
849     fn followed_by_brace(&self, span: Span) -> (bool, Option<Span>) {
850         // HACK(estebank): find a better way to figure out that this was a
851         // parser issue where a struct literal is being used on an expression
852         // where a brace being opened means a block is being started. Look
853         // ahead for the next text to see if `span` is followed by a `{`.
854         let sm = self.r.session.source_map();
855         let mut sp = span;
856         loop {
857             sp = sm.next_point(sp);
858             match sm.span_to_snippet(sp) {
859                 Ok(ref snippet) => {
860                     if snippet.chars().any(|c| !c.is_whitespace()) {
861                         break;
862                     }
863                 }
864                 _ => break,
865             }
866         }
867         let followed_by_brace = matches!(sm.span_to_snippet(sp), Ok(ref snippet) if snippet == "{");
868         // In case this could be a struct literal that needs to be surrounded
869         // by parentheses, find the appropriate span.
870         let mut i = 0;
871         let mut closing_brace = None;
872         loop {
873             sp = sm.next_point(sp);
874             match sm.span_to_snippet(sp) {
875                 Ok(ref snippet) => {
876                     if snippet == "}" {
877                         closing_brace = Some(span.to(sp));
878                         break;
879                     }
880                 }
881                 _ => break,
882             }
883             i += 1;
884             // The bigger the span, the more likely we're incorrect --
885             // bound it to 100 chars long.
886             if i > 100 {
887                 break;
888             }
889         }
890         (followed_by_brace, closing_brace)
891     }
892
893     /// Provides context-dependent help for errors reported by the `smart_resolve_path_fragment`
894     /// function.
895     /// Returns `true` if able to provide context-dependent help.
896     fn smart_resolve_context_dependent_help(
897         &mut self,
898         err: &mut Diagnostic,
899         span: Span,
900         source: PathSource<'_>,
901         res: Res,
902         path_str: &str,
903         fallback_label: &str,
904     ) -> bool {
905         let ns = source.namespace();
906         let is_expected = &|res| source.is_expected(res);
907
908         let path_sep = |err: &mut Diagnostic, expr: &Expr| match expr.kind {
909             ExprKind::Field(_, ident) => {
910                 err.span_suggestion(
911                     expr.span,
912                     "use the path separator to refer to an item",
913                     format!("{}::{}", path_str, ident),
914                     Applicability::MaybeIncorrect,
915                 );
916                 true
917             }
918             ExprKind::MethodCall(ref segment, ..) => {
919                 let span = expr.span.with_hi(segment.ident.span.hi());
920                 err.span_suggestion(
921                     span,
922                     "use the path separator to refer to an item",
923                     format!("{}::{}", path_str, segment.ident),
924                     Applicability::MaybeIncorrect,
925                 );
926                 true
927             }
928             _ => false,
929         };
930
931         let find_span = |source: &PathSource<'_>, err: &mut Diagnostic| {
932             match source {
933                 PathSource::Expr(Some(Expr { span, kind: ExprKind::Call(_, _), .. }))
934                 | PathSource::TupleStruct(span, _) => {
935                     // We want the main underline to cover the suggested code as well for
936                     // cleaner output.
937                     err.set_span(*span);
938                     *span
939                 }
940                 _ => span,
941             }
942         };
943
944         let mut bad_struct_syntax_suggestion = |def_id: DefId| {
945             let (followed_by_brace, closing_brace) = self.followed_by_brace(span);
946
947             match source {
948                 PathSource::Expr(Some(
949                     parent @ Expr { kind: ExprKind::Field(..) | ExprKind::MethodCall(..), .. },
950                 )) if path_sep(err, &parent) => {}
951                 PathSource::Expr(
952                     None
953                     | Some(Expr {
954                         kind:
955                             ExprKind::Path(..)
956                             | ExprKind::Binary(..)
957                             | ExprKind::Unary(..)
958                             | ExprKind::If(..)
959                             | ExprKind::While(..)
960                             | ExprKind::ForLoop(..)
961                             | ExprKind::Match(..),
962                         ..
963                     }),
964                 ) if followed_by_brace => {
965                     if let Some(sp) = closing_brace {
966                         err.span_label(span, fallback_label);
967                         err.multipart_suggestion(
968                             "surround the struct literal with parentheses",
969                             vec![
970                                 (sp.shrink_to_lo(), "(".to_string()),
971                                 (sp.shrink_to_hi(), ")".to_string()),
972                             ],
973                             Applicability::MaybeIncorrect,
974                         );
975                     } else {
976                         err.span_label(
977                             span, // Note the parentheses surrounding the suggestion below
978                             format!(
979                                 "you might want to surround a struct literal with parentheses: \
980                                  `({} {{ /* fields */ }})`?",
981                                 path_str
982                             ),
983                         );
984                     }
985                 }
986                 PathSource::Expr(_) | PathSource::TupleStruct(..) | PathSource::Pat => {
987                     let span = find_span(&source, err);
988                     if let Some(span) = self.def_span(def_id) {
989                         err.span_label(span, &format!("`{}` defined here", path_str));
990                     }
991                     let (tail, descr, applicability) = match source {
992                         PathSource::Pat | PathSource::TupleStruct(..) => {
993                             ("", "pattern", Applicability::MachineApplicable)
994                         }
995                         _ => (": val", "literal", Applicability::HasPlaceholders),
996                     };
997                     let (fields, applicability) = match self.r.field_names.get(&def_id) {
998                         Some(fields) => (
999                             fields
1000                                 .iter()
1001                                 .map(|f| format!("{}{}", f.node, tail))
1002                                 .collect::<Vec<String>>()
1003                                 .join(", "),
1004                             applicability,
1005                         ),
1006                         None => ("/* fields */".to_string(), Applicability::HasPlaceholders),
1007                     };
1008                     let pad = match self.r.field_names.get(&def_id) {
1009                         Some(fields) if fields.is_empty() => "",
1010                         _ => " ",
1011                     };
1012                     err.span_suggestion(
1013                         span,
1014                         &format!("use struct {} syntax instead", descr),
1015                         format!("{path_str} {{{pad}{fields}{pad}}}"),
1016                         applicability,
1017                     );
1018                 }
1019                 _ => {
1020                     err.span_label(span, fallback_label);
1021                 }
1022             }
1023         };
1024
1025         match (res, source) {
1026             (
1027                 Res::Def(DefKind::Macro(MacroKind::Bang), _),
1028                 PathSource::Expr(Some(Expr {
1029                     kind: ExprKind::Index(..) | ExprKind::Call(..), ..
1030                 }))
1031                 | PathSource::Struct,
1032             ) => {
1033                 err.span_label(span, fallback_label);
1034                 err.span_suggestion_verbose(
1035                     span.shrink_to_hi(),
1036                     "use `!` to invoke the macro",
1037                     "!".to_string(),
1038                     Applicability::MaybeIncorrect,
1039                 );
1040                 if path_str == "try" && span.rust_2015() {
1041                     err.note("if you want the `try` keyword, you need Rust 2018 or later");
1042                 }
1043             }
1044             (Res::Def(DefKind::Macro(MacroKind::Bang), _), _) => {
1045                 err.span_label(span, fallback_label);
1046             }
1047             (Res::Def(DefKind::TyAlias, def_id), PathSource::Trait(_)) => {
1048                 err.span_label(span, "type aliases cannot be used as traits");
1049                 if self.r.session.is_nightly_build() {
1050                     let msg = "you might have meant to use `#![feature(trait_alias)]` instead of a \
1051                                `type` alias";
1052                     if let Some(span) = self.def_span(def_id) {
1053                         if let Ok(snip) = self.r.session.source_map().span_to_snippet(span) {
1054                             // The span contains a type alias so we should be able to
1055                             // replace `type` with `trait`.
1056                             let snip = snip.replacen("type", "trait", 1);
1057                             err.span_suggestion(span, msg, snip, Applicability::MaybeIncorrect);
1058                         } else {
1059                             err.span_help(span, msg);
1060                         }
1061                     } else {
1062                         err.help(msg);
1063                     }
1064                 }
1065             }
1066             (Res::Def(DefKind::Mod, _), PathSource::Expr(Some(parent))) => {
1067                 if !path_sep(err, &parent) {
1068                     return false;
1069                 }
1070             }
1071             (
1072                 Res::Def(DefKind::Enum, def_id),
1073                 PathSource::TupleStruct(..) | PathSource::Expr(..),
1074             ) => {
1075                 if self
1076                     .diagnostic_metadata
1077                     .current_type_ascription
1078                     .last()
1079                     .map(|sp| {
1080                         self.r
1081                             .session
1082                             .parse_sess
1083                             .type_ascription_path_suggestions
1084                             .borrow()
1085                             .contains(&sp)
1086                     })
1087                     .unwrap_or(false)
1088                 {
1089                     err.downgrade_to_delayed_bug();
1090                     // We already suggested changing `:` into `::` during parsing.
1091                     return false;
1092                 }
1093
1094                 self.suggest_using_enum_variant(err, source, def_id, span);
1095             }
1096             (Res::Def(DefKind::Struct, def_id), source) if ns == ValueNS => {
1097                 let (ctor_def, ctor_vis, fields) =
1098                     if let Some(struct_ctor) = self.r.struct_constructors.get(&def_id).cloned() {
1099                         if let PathSource::Expr(Some(parent)) = source {
1100                             if let ExprKind::Field(..) | ExprKind::MethodCall(..) = parent.kind {
1101                                 bad_struct_syntax_suggestion(def_id);
1102                                 return true;
1103                             }
1104                         }
1105                         struct_ctor
1106                     } else {
1107                         bad_struct_syntax_suggestion(def_id);
1108                         return true;
1109                     };
1110
1111                 let is_accessible = self.r.is_accessible_from(ctor_vis, self.parent_scope.module);
1112                 if !is_expected(ctor_def) || is_accessible {
1113                     return true;
1114                 }
1115
1116                 let field_spans = match source {
1117                     // e.g. `if let Enum::TupleVariant(field1, field2) = _`
1118                     PathSource::TupleStruct(_, pattern_spans) => {
1119                         err.set_primary_message(
1120                             "cannot match against a tuple struct which contains private fields",
1121                         );
1122
1123                         // Use spans of the tuple struct pattern.
1124                         Some(Vec::from(pattern_spans))
1125                     }
1126                     // e.g. `let _ = Enum::TupleVariant(field1, field2);`
1127                     _ if source.is_call() => {
1128                         err.set_primary_message(
1129                             "cannot initialize a tuple struct which contains private fields",
1130                         );
1131
1132                         // Use spans of the tuple struct definition.
1133                         self.r
1134                             .field_names
1135                             .get(&def_id)
1136                             .map(|fields| fields.iter().map(|f| f.span).collect::<Vec<_>>())
1137                     }
1138                     _ => None,
1139                 };
1140
1141                 if let Some(spans) =
1142                     field_spans.filter(|spans| spans.len() > 0 && fields.len() == spans.len())
1143                 {
1144                     let non_visible_spans: Vec<Span> = iter::zip(&fields, &spans)
1145                         .filter(|(vis, _)| {
1146                             !self.r.is_accessible_from(**vis, self.parent_scope.module)
1147                         })
1148                         .map(|(_, span)| *span)
1149                         .collect();
1150
1151                     if non_visible_spans.len() > 0 {
1152                         let mut m: MultiSpan = non_visible_spans.clone().into();
1153                         non_visible_spans
1154                             .into_iter()
1155                             .for_each(|s| m.push_span_label(s, "private field".to_string()));
1156                         err.span_note(m, "constructor is not visible here due to private fields");
1157                     }
1158
1159                     return true;
1160                 }
1161
1162                 err.span_label(
1163                     span,
1164                     "constructor is not visible here due to private fields".to_string(),
1165                 );
1166             }
1167             (
1168                 Res::Def(
1169                     DefKind::Union | DefKind::Variant | DefKind::Ctor(_, CtorKind::Fictive),
1170                     def_id,
1171                 ),
1172                 _,
1173             ) if ns == ValueNS => {
1174                 bad_struct_syntax_suggestion(def_id);
1175             }
1176             (Res::Def(DefKind::Ctor(_, CtorKind::Const), def_id), _) if ns == ValueNS => {
1177                 match source {
1178                     PathSource::Expr(_) | PathSource::TupleStruct(..) | PathSource::Pat => {
1179                         let span = find_span(&source, err);
1180                         if let Some(span) = self.def_span(def_id) {
1181                             err.span_label(span, &format!("`{}` defined here", path_str));
1182                         }
1183                         err.span_suggestion(
1184                             span,
1185                             "use this syntax instead",
1186                             path_str.to_string(),
1187                             Applicability::MaybeIncorrect,
1188                         );
1189                     }
1190                     _ => return false,
1191                 }
1192             }
1193             (Res::Def(DefKind::Ctor(_, CtorKind::Fn), def_id), _) if ns == ValueNS => {
1194                 if let Some(span) = self.def_span(def_id) {
1195                     err.span_label(span, &format!("`{}` defined here", path_str));
1196                 }
1197                 let fields = self.r.field_names.get(&def_id).map_or_else(
1198                     || "/* fields */".to_string(),
1199                     |fields| vec!["_"; fields.len()].join(", "),
1200                 );
1201                 err.span_suggestion(
1202                     span,
1203                     "use the tuple variant pattern syntax instead",
1204                     format!("{}({})", path_str, fields),
1205                     Applicability::HasPlaceholders,
1206                 );
1207             }
1208             (Res::SelfTy { .. }, _) if ns == ValueNS => {
1209                 err.span_label(span, fallback_label);
1210                 err.note("can't use `Self` as a constructor, you must use the implemented struct");
1211             }
1212             (Res::Def(DefKind::TyAlias | DefKind::AssocTy, _), _) if ns == ValueNS => {
1213                 err.note("can't use a type alias as a constructor");
1214             }
1215             _ => return false,
1216         }
1217         true
1218     }
1219
1220     /// Given the target `ident` and `kind`, search for the similarly named associated item
1221     /// in `self.current_trait_ref`.
1222     crate fn find_similarly_named_assoc_item(
1223         &mut self,
1224         ident: Symbol,
1225         kind: &AssocItemKind,
1226     ) -> Option<Symbol> {
1227         let Some((module, _)) = &self.current_trait_ref else {
1228             return None;
1229         };
1230         if ident == kw::Underscore {
1231             // We do nothing for `_`.
1232             return None;
1233         }
1234
1235         let resolutions = self.r.resolutions(module);
1236         let targets = resolutions
1237             .borrow()
1238             .iter()
1239             .filter_map(|(key, res)| res.borrow().binding.map(|binding| (key, binding.res())))
1240             .filter(|(_, res)| match (kind, res) {
1241                 (AssocItemKind::Const(..), Res::Def(DefKind::AssocConst, _)) => true,
1242                 (AssocItemKind::Fn(_), Res::Def(DefKind::AssocFn, _)) => true,
1243                 (AssocItemKind::TyAlias(..), Res::Def(DefKind::AssocTy, _)) => true,
1244                 _ => false,
1245             })
1246             .map(|(key, _)| key.ident.name)
1247             .collect::<Vec<_>>();
1248
1249         find_best_match_for_name(&targets, ident, None)
1250     }
1251
1252     fn lookup_assoc_candidate<FilterFn>(
1253         &mut self,
1254         ident: Ident,
1255         ns: Namespace,
1256         filter_fn: FilterFn,
1257     ) -> Option<AssocSuggestion>
1258     where
1259         FilterFn: Fn(Res) -> bool,
1260     {
1261         fn extract_node_id(t: &Ty) -> Option<NodeId> {
1262             match t.kind {
1263                 TyKind::Path(None, _) => Some(t.id),
1264                 TyKind::Rptr(_, ref mut_ty) => extract_node_id(&mut_ty.ty),
1265                 // This doesn't handle the remaining `Ty` variants as they are not
1266                 // that commonly the self_type, it might be interesting to provide
1267                 // support for those in future.
1268                 _ => None,
1269             }
1270         }
1271
1272         // Fields are generally expected in the same contexts as locals.
1273         if filter_fn(Res::Local(ast::DUMMY_NODE_ID)) {
1274             if let Some(node_id) =
1275                 self.diagnostic_metadata.current_self_type.as_ref().and_then(extract_node_id)
1276             {
1277                 // Look for a field with the same name in the current self_type.
1278                 if let Some(resolution) = self.r.partial_res_map.get(&node_id) {
1279                     match resolution.base_res() {
1280                         Res::Def(DefKind::Struct | DefKind::Union, did)
1281                             if resolution.unresolved_segments() == 0 =>
1282                         {
1283                             if let Some(field_names) = self.r.field_names.get(&did) {
1284                                 if field_names
1285                                     .iter()
1286                                     .any(|&field_name| ident.name == field_name.node)
1287                                 {
1288                                     return Some(AssocSuggestion::Field);
1289                                 }
1290                             }
1291                         }
1292                         _ => {}
1293                     }
1294                 }
1295             }
1296         }
1297
1298         if let Some(items) = self.diagnostic_metadata.current_trait_assoc_items {
1299             for assoc_item in items {
1300                 if assoc_item.ident == ident {
1301                     return Some(match &assoc_item.kind {
1302                         ast::AssocItemKind::Const(..) => AssocSuggestion::AssocConst,
1303                         ast::AssocItemKind::Fn(box ast::Fn { sig, .. }) if sig.decl.has_self() => {
1304                             AssocSuggestion::MethodWithSelf
1305                         }
1306                         ast::AssocItemKind::Fn(..) => AssocSuggestion::AssocFn,
1307                         ast::AssocItemKind::TyAlias(..) => AssocSuggestion::AssocType,
1308                         ast::AssocItemKind::MacCall(_) => continue,
1309                     });
1310                 }
1311             }
1312         }
1313
1314         // Look for associated items in the current trait.
1315         if let Some((module, _)) = self.current_trait_ref {
1316             if let Ok(binding) = self.r.maybe_resolve_ident_in_module(
1317                 ModuleOrUniformRoot::Module(module),
1318                 ident,
1319                 ns,
1320                 &self.parent_scope,
1321             ) {
1322                 let res = binding.res();
1323                 if filter_fn(res) {
1324                     if self.r.has_self.contains(&res.def_id()) {
1325                         return Some(AssocSuggestion::MethodWithSelf);
1326                     } else {
1327                         match res {
1328                             Res::Def(DefKind::AssocFn, _) => return Some(AssocSuggestion::AssocFn),
1329                             Res::Def(DefKind::AssocConst, _) => {
1330                                 return Some(AssocSuggestion::AssocConst);
1331                             }
1332                             Res::Def(DefKind::AssocTy, _) => {
1333                                 return Some(AssocSuggestion::AssocType);
1334                             }
1335                             _ => {}
1336                         }
1337                     }
1338                 }
1339             }
1340         }
1341
1342         None
1343     }
1344
1345     fn lookup_typo_candidate(
1346         &mut self,
1347         path: &[Segment],
1348         ns: Namespace,
1349         filter_fn: &impl Fn(Res) -> bool,
1350     ) -> Option<TypoSuggestion> {
1351         let mut names = Vec::new();
1352         if path.len() == 1 {
1353             // Search in lexical scope.
1354             // Walk backwards up the ribs in scope and collect candidates.
1355             for rib in self.ribs[ns].iter().rev() {
1356                 // Locals and type parameters
1357                 for (ident, &res) in &rib.bindings {
1358                     if filter_fn(res) {
1359                         names.push(TypoSuggestion::typo_from_res(ident.name, res));
1360                     }
1361                 }
1362                 // Items in scope
1363                 if let RibKind::ModuleRibKind(module) = rib.kind {
1364                     // Items from this module
1365                     self.r.add_module_candidates(module, &mut names, &filter_fn);
1366
1367                     if let ModuleKind::Block(..) = module.kind {
1368                         // We can see through blocks
1369                     } else {
1370                         // Items from the prelude
1371                         if !module.no_implicit_prelude {
1372                             let extern_prelude = self.r.extern_prelude.clone();
1373                             names.extend(extern_prelude.iter().flat_map(|(ident, _)| {
1374                                 self.r.crate_loader.maybe_process_path_extern(ident.name).and_then(
1375                                     |crate_id| {
1376                                         let crate_mod =
1377                                             Res::Def(DefKind::Mod, crate_id.as_def_id());
1378
1379                                         if filter_fn(crate_mod) {
1380                                             Some(TypoSuggestion::typo_from_res(
1381                                                 ident.name, crate_mod,
1382                                             ))
1383                                         } else {
1384                                             None
1385                                         }
1386                                     },
1387                                 )
1388                             }));
1389
1390                             if let Some(prelude) = self.r.prelude {
1391                                 self.r.add_module_candidates(prelude, &mut names, &filter_fn);
1392                             }
1393                         }
1394                         break;
1395                     }
1396                 }
1397             }
1398             // Add primitive types to the mix
1399             if filter_fn(Res::PrimTy(PrimTy::Bool)) {
1400                 names.extend(PrimTy::ALL.iter().map(|prim_ty| {
1401                     TypoSuggestion::typo_from_res(prim_ty.name(), Res::PrimTy(*prim_ty))
1402                 }))
1403             }
1404         } else {
1405             // Search in module.
1406             let mod_path = &path[..path.len() - 1];
1407             if let PathResult::Module(ModuleOrUniformRoot::Module(module)) =
1408                 self.resolve_path(mod_path, Some(TypeNS), Finalize::No)
1409             {
1410                 self.r.add_module_candidates(module, &mut names, &filter_fn);
1411             }
1412         }
1413
1414         let name = path[path.len() - 1].ident.name;
1415         // Make sure error reporting is deterministic.
1416         names.sort_by(|a, b| a.candidate.as_str().partial_cmp(b.candidate.as_str()).unwrap());
1417
1418         match find_best_match_for_name(
1419             &names.iter().map(|suggestion| suggestion.candidate).collect::<Vec<Symbol>>(),
1420             name,
1421             None,
1422         ) {
1423             Some(found) if found != name => {
1424                 names.into_iter().find(|suggestion| suggestion.candidate == found)
1425             }
1426             _ => None,
1427         }
1428     }
1429
1430     // Returns the name of the Rust type approximately corresponding to
1431     // a type name in another programming language.
1432     fn likely_rust_type(path: &[Segment]) -> Option<Symbol> {
1433         let name = path[path.len() - 1].ident.as_str();
1434         // Common Java types
1435         Some(match name {
1436             "byte" => sym::u8, // In Java, bytes are signed, but in practice one almost always wants unsigned bytes.
1437             "short" => sym::i16,
1438             "boolean" => sym::bool,
1439             "int" => sym::i32,
1440             "long" => sym::i64,
1441             "float" => sym::f32,
1442             "double" => sym::f64,
1443             _ => return None,
1444         })
1445     }
1446
1447     /// Only used in a specific case of type ascription suggestions
1448     fn get_colon_suggestion_span(&self, start: Span) -> Span {
1449         let sm = self.r.session.source_map();
1450         start.to(sm.next_point(start))
1451     }
1452
1453     fn type_ascription_suggestion(&self, err: &mut Diagnostic, base_span: Span) -> bool {
1454         let sm = self.r.session.source_map();
1455         let base_snippet = sm.span_to_snippet(base_span);
1456         if let Some(&sp) = self.diagnostic_metadata.current_type_ascription.last() {
1457             if let Ok(snippet) = sm.span_to_snippet(sp) {
1458                 let len = snippet.trim_end().len() as u32;
1459                 if snippet.trim() == ":" {
1460                     let colon_sp =
1461                         sp.with_lo(sp.lo() + BytePos(len - 1)).with_hi(sp.lo() + BytePos(len));
1462                     let mut show_label = true;
1463                     if sm.is_multiline(sp) {
1464                         err.span_suggestion_short(
1465                             colon_sp,
1466                             "maybe you meant to write `;` here",
1467                             ";".to_string(),
1468                             Applicability::MaybeIncorrect,
1469                         );
1470                     } else {
1471                         let after_colon_sp =
1472                             self.get_colon_suggestion_span(colon_sp.shrink_to_hi());
1473                         if snippet.len() == 1 {
1474                             // `foo:bar`
1475                             err.span_suggestion(
1476                                 colon_sp,
1477                                 "maybe you meant to write a path separator here",
1478                                 "::".to_string(),
1479                                 Applicability::MaybeIncorrect,
1480                             );
1481                             show_label = false;
1482                             if !self
1483                                 .r
1484                                 .session
1485                                 .parse_sess
1486                                 .type_ascription_path_suggestions
1487                                 .borrow_mut()
1488                                 .insert(colon_sp)
1489                             {
1490                                 err.downgrade_to_delayed_bug();
1491                             }
1492                         }
1493                         if let Ok(base_snippet) = base_snippet {
1494                             let mut sp = after_colon_sp;
1495                             for _ in 0..100 {
1496                                 // Try to find an assignment
1497                                 sp = sm.next_point(sp);
1498                                 let snippet = sm.span_to_snippet(sp.to(sm.next_point(sp)));
1499                                 match snippet {
1500                                     Ok(ref x) if x.as_str() == "=" => {
1501                                         err.span_suggestion(
1502                                             base_span,
1503                                             "maybe you meant to write an assignment here",
1504                                             format!("let {}", base_snippet),
1505                                             Applicability::MaybeIncorrect,
1506                                         );
1507                                         show_label = false;
1508                                         break;
1509                                     }
1510                                     Ok(ref x) if x.as_str() == "\n" => break,
1511                                     Err(_) => break,
1512                                     Ok(_) => {}
1513                                 }
1514                             }
1515                         }
1516                     }
1517                     if show_label {
1518                         err.span_label(
1519                             base_span,
1520                             "expecting a type here because of type ascription",
1521                         );
1522                     }
1523                     return show_label;
1524                 }
1525             }
1526         }
1527         false
1528     }
1529
1530     fn find_module(&mut self, def_id: DefId) -> Option<(Module<'a>, ImportSuggestion)> {
1531         let mut result = None;
1532         let mut seen_modules = FxHashSet::default();
1533         let mut worklist = vec![(self.r.graph_root, Vec::new())];
1534
1535         while let Some((in_module, path_segments)) = worklist.pop() {
1536             // abort if the module is already found
1537             if result.is_some() {
1538                 break;
1539             }
1540
1541             in_module.for_each_child(self.r, |_, ident, _, name_binding| {
1542                 // abort if the module is already found or if name_binding is private external
1543                 if result.is_some() || !name_binding.vis.is_visible_locally() {
1544                     return;
1545                 }
1546                 if let Some(module) = name_binding.module() {
1547                     // form the path
1548                     let mut path_segments = path_segments.clone();
1549                     path_segments.push(ast::PathSegment::from_ident(ident));
1550                     let module_def_id = module.def_id();
1551                     if module_def_id == def_id {
1552                         let path =
1553                             Path { span: name_binding.span, segments: path_segments, tokens: None };
1554                         result = Some((
1555                             module,
1556                             ImportSuggestion {
1557                                 did: Some(def_id),
1558                                 descr: "module",
1559                                 path,
1560                                 accessible: true,
1561                                 note: None,
1562                             },
1563                         ));
1564                     } else {
1565                         // add the module to the lookup
1566                         if seen_modules.insert(module_def_id) {
1567                             worklist.push((module, path_segments));
1568                         }
1569                     }
1570                 }
1571             });
1572         }
1573
1574         result
1575     }
1576
1577     fn collect_enum_ctors(&mut self, def_id: DefId) -> Option<Vec<(Path, DefId, CtorKind)>> {
1578         self.find_module(def_id).map(|(enum_module, enum_import_suggestion)| {
1579             let mut variants = Vec::new();
1580             enum_module.for_each_child(self.r, |_, ident, _, name_binding| {
1581                 if let Res::Def(DefKind::Ctor(CtorOf::Variant, kind), def_id) = name_binding.res() {
1582                     let mut segms = enum_import_suggestion.path.segments.clone();
1583                     segms.push(ast::PathSegment::from_ident(ident));
1584                     let path = Path { span: name_binding.span, segments: segms, tokens: None };
1585                     variants.push((path, def_id, kind));
1586                 }
1587             });
1588             variants
1589         })
1590     }
1591
1592     /// Adds a suggestion for using an enum's variant when an enum is used instead.
1593     fn suggest_using_enum_variant(
1594         &mut self,
1595         err: &mut Diagnostic,
1596         source: PathSource<'_>,
1597         def_id: DefId,
1598         span: Span,
1599     ) {
1600         let Some(variants) = self.collect_enum_ctors(def_id) else {
1601             err.note("you might have meant to use one of the enum's variants");
1602             return;
1603         };
1604
1605         let suggest_only_tuple_variants =
1606             matches!(source, PathSource::TupleStruct(..)) || source.is_call();
1607         if suggest_only_tuple_variants {
1608             // Suggest only tuple variants regardless of whether they have fields and do not
1609             // suggest path with added parentheses.
1610             let suggestable_variants = variants
1611                 .iter()
1612                 .filter(|(.., kind)| *kind == CtorKind::Fn)
1613                 .map(|(variant, ..)| path_names_to_string(variant))
1614                 .collect::<Vec<_>>();
1615
1616             let non_suggestable_variant_count = variants.len() - suggestable_variants.len();
1617
1618             let source_msg = if source.is_call() {
1619                 "to construct"
1620             } else if matches!(source, PathSource::TupleStruct(..)) {
1621                 "to match against"
1622             } else {
1623                 unreachable!()
1624             };
1625
1626             if !suggestable_variants.is_empty() {
1627                 let msg = if non_suggestable_variant_count == 0 && suggestable_variants.len() == 1 {
1628                     format!("try {} the enum's variant", source_msg)
1629                 } else {
1630                     format!("try {} one of the enum's variants", source_msg)
1631                 };
1632
1633                 err.span_suggestions(
1634                     span,
1635                     &msg,
1636                     suggestable_variants.into_iter(),
1637                     Applicability::MaybeIncorrect,
1638                 );
1639             }
1640
1641             // If the enum has no tuple variants..
1642             if non_suggestable_variant_count == variants.len() {
1643                 err.help(&format!("the enum has no tuple variants {}", source_msg));
1644             }
1645
1646             // If there are also non-tuple variants..
1647             if non_suggestable_variant_count == 1 {
1648                 err.help(&format!(
1649                     "you might have meant {} the enum's non-tuple variant",
1650                     source_msg
1651                 ));
1652             } else if non_suggestable_variant_count >= 1 {
1653                 err.help(&format!(
1654                     "you might have meant {} one of the enum's non-tuple variants",
1655                     source_msg
1656                 ));
1657             }
1658         } else {
1659             let needs_placeholder = |def_id: DefId, kind: CtorKind| {
1660                 let has_no_fields = self.r.field_names.get(&def_id).map_or(false, |f| f.is_empty());
1661                 match kind {
1662                     CtorKind::Const => false,
1663                     CtorKind::Fn | CtorKind::Fictive if has_no_fields => false,
1664                     _ => true,
1665                 }
1666             };
1667
1668             let mut suggestable_variants = variants
1669                 .iter()
1670                 .filter(|(_, def_id, kind)| !needs_placeholder(*def_id, *kind))
1671                 .map(|(variant, _, kind)| (path_names_to_string(variant), kind))
1672                 .map(|(variant, kind)| match kind {
1673                     CtorKind::Const => variant,
1674                     CtorKind::Fn => format!("({}())", variant),
1675                     CtorKind::Fictive => format!("({} {{}})", variant),
1676                 })
1677                 .collect::<Vec<_>>();
1678
1679             if !suggestable_variants.is_empty() {
1680                 let msg = if suggestable_variants.len() == 1 {
1681                     "you might have meant to use the following enum variant"
1682                 } else {
1683                     "you might have meant to use one of the following enum variants"
1684                 };
1685
1686                 err.span_suggestions(
1687                     span,
1688                     msg,
1689                     suggestable_variants.drain(..),
1690                     Applicability::MaybeIncorrect,
1691                 );
1692             }
1693
1694             let suggestable_variants_with_placeholders = variants
1695                 .iter()
1696                 .filter(|(_, def_id, kind)| needs_placeholder(*def_id, *kind))
1697                 .map(|(variant, _, kind)| (path_names_to_string(variant), kind))
1698                 .filter_map(|(variant, kind)| match kind {
1699                     CtorKind::Fn => Some(format!("({}(/* fields */))", variant)),
1700                     CtorKind::Fictive => Some(format!("({} {{ /* fields */ }})", variant)),
1701                     _ => None,
1702                 })
1703                 .collect::<Vec<_>>();
1704
1705             if !suggestable_variants_with_placeholders.is_empty() {
1706                 let msg = match (
1707                     suggestable_variants.is_empty(),
1708                     suggestable_variants_with_placeholders.len(),
1709                 ) {
1710                     (true, 1) => "the following enum variant is available",
1711                     (true, _) => "the following enum variants are available",
1712                     (false, 1) => "alternatively, the following enum variant is available",
1713                     (false, _) => "alternatively, the following enum variants are also available",
1714                 };
1715
1716                 err.span_suggestions(
1717                     span,
1718                     msg,
1719                     suggestable_variants_with_placeholders.into_iter(),
1720                     Applicability::HasPlaceholders,
1721                 );
1722             }
1723         };
1724
1725         if def_id.is_local() {
1726             if let Some(span) = self.def_span(def_id) {
1727                 err.span_note(span, "the enum is defined here");
1728             }
1729         }
1730     }
1731
1732     crate fn report_missing_type_error(
1733         &self,
1734         path: &[Segment],
1735     ) -> Option<(Span, &'static str, String, Applicability)> {
1736         let (ident, span) = match path {
1737             [segment] if !segment.has_generic_args => {
1738                 (segment.ident.to_string(), segment.ident.span)
1739             }
1740             _ => return None,
1741         };
1742         let mut iter = ident.chars().map(|c| c.is_uppercase());
1743         let single_uppercase_char =
1744             matches!(iter.next(), Some(true)) && matches!(iter.next(), None);
1745         if !self.diagnostic_metadata.currently_processing_generics && !single_uppercase_char {
1746             return None;
1747         }
1748         match (self.diagnostic_metadata.current_item, single_uppercase_char, self.diagnostic_metadata.currently_processing_generics) {
1749             (Some(Item { kind: ItemKind::Fn(..), ident, .. }), _, _) if ident.name == sym::main => {
1750                 // Ignore `fn main()` as we don't want to suggest `fn main<T>()`
1751             }
1752             (
1753                 Some(Item {
1754                     kind:
1755                         kind @ ItemKind::Fn(..)
1756                         | kind @ ItemKind::Enum(..)
1757                         | kind @ ItemKind::Struct(..)
1758                         | kind @ ItemKind::Union(..),
1759                     ..
1760                 }),
1761                 true, _
1762             )
1763             // Without the 2nd `true`, we'd suggest `impl <T>` for `impl T` when a type `T` isn't found
1764             | (Some(Item { kind: kind @ ItemKind::Impl(..), .. }), true, true)
1765             | (Some(Item { kind, .. }), false, _) => {
1766                 // Likely missing type parameter.
1767                 if let Some(generics) = kind.generics() {
1768                     if span.overlaps(generics.span) {
1769                         // Avoid the following:
1770                         // error[E0405]: cannot find trait `A` in this scope
1771                         //  --> $DIR/typo-suggestion-named-underscore.rs:CC:LL
1772                         //   |
1773                         // L | fn foo<T: A>(x: T) {} // Shouldn't suggest underscore
1774                         //   |           ^- help: you might be missing a type parameter: `, A`
1775                         //   |           |
1776                         //   |           not found in this scope
1777                         return None;
1778                     }
1779                     let msg = "you might be missing a type parameter";
1780                     let (span, sugg) = if let [.., param] = &generics.params[..] {
1781                         let span = if let [.., bound] = &param.bounds[..] {
1782                             bound.span()
1783                         } else if let GenericParam {
1784                             kind: GenericParamKind::Const { ty, kw_span: _, default  }, ..
1785                         } = param {
1786                             default.as_ref().map(|def| def.value.span).unwrap_or(ty.span)
1787                         } else {
1788                             param.ident.span
1789                         };
1790                         (span, format!(", {}", ident))
1791                     } else {
1792                         (generics.span, format!("<{}>", ident))
1793                     };
1794                     // Do not suggest if this is coming from macro expansion.
1795                     if span.can_be_used_for_suggestions() {
1796                         return Some((
1797                             span.shrink_to_hi(),
1798                             msg,
1799                             sugg,
1800                             Applicability::MaybeIncorrect,
1801                         ));
1802                     }
1803                 }
1804             }
1805             _ => {}
1806         }
1807         None
1808     }
1809
1810     /// Given the target `label`, search the `rib_index`th label rib for similarly named labels,
1811     /// optionally returning the closest match and whether it is reachable.
1812     crate fn suggestion_for_label_in_rib(
1813         &self,
1814         rib_index: usize,
1815         label: Ident,
1816     ) -> Option<LabelSuggestion> {
1817         // Are ribs from this `rib_index` within scope?
1818         let within_scope = self.is_label_valid_from_rib(rib_index);
1819
1820         let rib = &self.label_ribs[rib_index];
1821         let names = rib
1822             .bindings
1823             .iter()
1824             .filter(|(id, _)| id.span.ctxt() == label.span.ctxt())
1825             .map(|(id, _)| id.name)
1826             .collect::<Vec<Symbol>>();
1827
1828         find_best_match_for_name(&names, label.name, None).map(|symbol| {
1829             // Upon finding a similar name, get the ident that it was from - the span
1830             // contained within helps make a useful diagnostic. In addition, determine
1831             // whether this candidate is within scope.
1832             let (ident, _) = rib.bindings.iter().find(|(ident, _)| ident.name == symbol).unwrap();
1833             (*ident, within_scope)
1834         })
1835     }
1836
1837     crate fn emit_undeclared_lifetime_error(
1838         &self,
1839         lifetime_ref: &ast::Lifetime,
1840         outer_lifetime_ref: Option<Ident>,
1841     ) {
1842         debug_assert_ne!(lifetime_ref.ident.name, kw::UnderscoreLifetime);
1843         let mut err = if let Some(outer) = outer_lifetime_ref {
1844             let mut err = struct_span_err!(
1845                 self.r.session,
1846                 lifetime_ref.ident.span,
1847                 E0401,
1848                 "can't use generic parameters from outer item",
1849             );
1850             err.span_label(lifetime_ref.ident.span, "use of generic parameter from outer item");
1851             err.span_label(outer.span, "lifetime parameter from outer item");
1852             err
1853         } else {
1854             let mut err = struct_span_err!(
1855                 self.r.session,
1856                 lifetime_ref.ident.span,
1857                 E0261,
1858                 "use of undeclared lifetime name `{}`",
1859                 lifetime_ref.ident
1860             );
1861             err.span_label(lifetime_ref.ident.span, "undeclared lifetime");
1862             err
1863         };
1864         let mut suggest_note = true;
1865
1866         for rib in self.lifetime_ribs.iter().rev() {
1867             match rib.kind {
1868                 LifetimeRibKind::Generics { span, kind } => {
1869                     if !span.can_be_used_for_suggestions() && suggest_note {
1870                         suggest_note = false; // Avoid displaying the same help multiple times.
1871                         err.span_label(
1872                             span,
1873                             &format!(
1874                                 "lifetime `{}` is missing in item created through this procedural macro",
1875                                 lifetime_ref.ident,
1876                             ),
1877                         );
1878                         continue;
1879                     }
1880
1881                     let higher_ranked = matches!(
1882                         kind,
1883                         LifetimeBinderKind::BareFnType
1884                             | LifetimeBinderKind::PolyTrait
1885                             | LifetimeBinderKind::WhereBound
1886                     );
1887                     let (span, sugg) = if span.is_empty() {
1888                         let sugg = format!(
1889                             "{}<{}>{}",
1890                             if higher_ranked { "for" } else { "" },
1891                             lifetime_ref.ident,
1892                             if higher_ranked { " " } else { "" },
1893                         );
1894                         (span, sugg)
1895                     } else {
1896                         let span =
1897                             self.r.session.source_map().span_through_char(span, '<').shrink_to_hi();
1898                         let sugg = format!("{}, ", lifetime_ref.ident);
1899                         (span, sugg)
1900                     };
1901                     if higher_ranked {
1902                         err.span_suggestion(
1903                             span,
1904                             &format!(
1905                                 "consider making the {} lifetime-generic with a new `{}` lifetime",
1906                                 kind.descr(),
1907                                 lifetime_ref
1908                             ),
1909                             sugg,
1910                             Applicability::MaybeIncorrect,
1911                         );
1912                         err.note_once(
1913                             "for more information on higher-ranked polymorphism, visit \
1914                              https://doc.rust-lang.org/nomicon/hrtb.html",
1915                         );
1916                     } else {
1917                         err.span_suggestion(
1918                             span,
1919                             &format!("consider introducing lifetime `{}` here", lifetime_ref.ident),
1920                             sugg,
1921                             Applicability::MaybeIncorrect,
1922                         );
1923                     }
1924                 }
1925                 LifetimeRibKind::Item => break,
1926                 _ => {}
1927             }
1928         }
1929
1930         err.emit();
1931     }
1932 }
1933
1934 impl<'tcx> LifetimeContext<'_, 'tcx> {
1935     crate fn report_missing_lifetime_specifiers(
1936         &self,
1937         spans: Vec<Span>,
1938         count: usize,
1939     ) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> {
1940         struct_span_err!(
1941             self.tcx.sess,
1942             spans,
1943             E0106,
1944             "missing lifetime specifier{}",
1945             pluralize!(count)
1946         )
1947     }
1948
1949     /// Returns whether to add `'static` lifetime to the suggested lifetime list.
1950     crate fn report_elision_failure(
1951         &mut self,
1952         diag: &mut Diagnostic,
1953         params: &[ElisionFailureInfo],
1954     ) -> bool {
1955         let mut m = String::new();
1956         let len = params.len();
1957
1958         let elided_params: Vec<_> =
1959             params.iter().cloned().filter(|info| info.lifetime_count > 0).collect();
1960
1961         let elided_len = elided_params.len();
1962
1963         for (i, info) in elided_params.into_iter().enumerate() {
1964             let ElisionFailureInfo { parent, index, lifetime_count: n, have_bound_regions, span } =
1965                 info;
1966
1967             diag.span_label(span, "");
1968             let help_name = if let Some(ident) =
1969                 parent.and_then(|body| self.tcx.hir().body(body).params[index].pat.simple_ident())
1970             {
1971                 format!("`{}`", ident)
1972             } else {
1973                 format!("argument {}", index + 1)
1974             };
1975
1976             m.push_str(
1977                 &(if n == 1 {
1978                     help_name
1979                 } else {
1980                     format!(
1981                         "one of {}'s {} {}lifetimes",
1982                         help_name,
1983                         n,
1984                         if have_bound_regions { "free " } else { "" }
1985                     )
1986                 })[..],
1987             );
1988
1989             if elided_len == 2 && i == 0 {
1990                 m.push_str(" or ");
1991             } else if i + 2 == elided_len {
1992                 m.push_str(", or ");
1993             } else if i != elided_len - 1 {
1994                 m.push_str(", ");
1995             }
1996         }
1997
1998         if len == 0 {
1999             diag.help(
2000                 "this function's return type contains a borrowed value, \
2001                  but there is no value for it to be borrowed from",
2002             );
2003             true
2004         } else if elided_len == 0 {
2005             diag.help(
2006                 "this function's return type contains a borrowed value with \
2007                  an elided lifetime, but the lifetime cannot be derived from \
2008                  the arguments",
2009             );
2010             true
2011         } else if elided_len == 1 {
2012             diag.help(&format!(
2013                 "this function's return type contains a borrowed value, \
2014                  but the signature does not say which {} it is borrowed from",
2015                 m
2016             ));
2017             false
2018         } else {
2019             diag.help(&format!(
2020                 "this function's return type contains a borrowed value, \
2021                  but the signature does not say whether it is borrowed from {}",
2022                 m
2023             ));
2024             false
2025         }
2026     }
2027
2028     // FIXME(const_generics): This patches over an ICE caused by non-'static lifetimes in const
2029     // generics. We are disallowing this until we can decide on how we want to handle non-'static
2030     // lifetimes in const generics. See issue #74052 for discussion.
2031     crate fn emit_non_static_lt_in_const_generic_error(&self, lifetime_ref: &hir::Lifetime) {
2032         let mut err = struct_span_err!(
2033             self.tcx.sess,
2034             lifetime_ref.span,
2035             E0771,
2036             "use of non-static lifetime `{}` in const generic",
2037             lifetime_ref
2038         );
2039         err.note(
2040             "for more information, see issue #74052 \
2041             <https://github.com/rust-lang/rust/issues/74052>",
2042         );
2043         err.emit();
2044     }
2045
2046     crate fn is_trait_ref_fn_scope(&mut self, trait_ref: &'tcx hir::PolyTraitRef<'tcx>) -> bool {
2047         if let def::Res::Def(_, did) = trait_ref.trait_ref.path.res {
2048             if [
2049                 self.tcx.lang_items().fn_once_trait(),
2050                 self.tcx.lang_items().fn_trait(),
2051                 self.tcx.lang_items().fn_mut_trait(),
2052             ]
2053             .contains(&Some(did))
2054             {
2055                 let (span, span_type) = match &trait_ref.bound_generic_params {
2056                     [] => (trait_ref.span.shrink_to_lo(), ForLifetimeSpanType::BoundEmpty),
2057                     [.., bound] => (bound.span.shrink_to_hi(), ForLifetimeSpanType::BoundTail),
2058                 };
2059                 self.missing_named_lifetime_spots
2060                     .push(MissingLifetimeSpot::HigherRanked { span, span_type });
2061                 return true;
2062             }
2063         };
2064         false
2065     }
2066
2067     crate fn add_missing_lifetime_specifiers_label(
2068         &self,
2069         err: &mut Diagnostic,
2070         mut spans_with_counts: Vec<(Span, usize)>,
2071         lifetime_names: &FxHashSet<Symbol>,
2072         lifetime_spans: Vec<Span>,
2073         params: &[ElisionFailureInfo],
2074     ) {
2075         let snippets: Vec<Option<String>> = spans_with_counts
2076             .iter()
2077             .map(|(span, _)| self.tcx.sess.source_map().span_to_snippet(*span).ok())
2078             .collect();
2079
2080         // Empty generics are marked with a span of "<", but since from now on
2081         // that information is in the snippets it can be removed from the spans.
2082         for ((span, _), snippet) in spans_with_counts.iter_mut().zip(&snippets) {
2083             if snippet.as_deref() == Some("<") {
2084                 *span = span.shrink_to_hi();
2085             }
2086         }
2087
2088         for &(span, count) in &spans_with_counts {
2089             err.span_label(
2090                 span,
2091                 format!(
2092                     "expected {} lifetime parameter{}",
2093                     if count == 1 { "named".to_string() } else { count.to_string() },
2094                     pluralize!(count),
2095                 ),
2096             );
2097         }
2098
2099         let suggest_existing =
2100             |err: &mut Diagnostic,
2101              name: &str,
2102              formatters: Vec<Option<Box<dyn Fn(&str) -> String>>>| {
2103                 if let Some(MissingLifetimeSpot::HigherRanked { span: for_span, span_type }) =
2104                     self.missing_named_lifetime_spots.iter().rev().next()
2105                 {
2106                     // When we have `struct S<'a>(&'a dyn Fn(&X) -> &X);` we want to not only suggest
2107                     // using `'a`, but also introduce the concept of HRLTs by suggesting
2108                     // `struct S<'a>(&'a dyn for<'b> Fn(&X) -> &'b X);`. (#72404)
2109                     let mut introduce_suggestion = vec![];
2110
2111                     let a_to_z_repeat_n = |n| {
2112                         (b'a'..=b'z').map(move |c| {
2113                             let mut s = '\''.to_string();
2114                             s.extend(std::iter::repeat(char::from(c)).take(n));
2115                             s
2116                         })
2117                     };
2118
2119                     // If all single char lifetime names are present, we wrap around and double the chars.
2120                     let lt_name = (1..)
2121                         .flat_map(a_to_z_repeat_n)
2122                         .find(|lt| !lifetime_names.contains(&Symbol::intern(&lt)))
2123                         .unwrap();
2124                     let msg = format!(
2125                         "consider making the {} lifetime-generic with a new `{}` lifetime",
2126                         span_type.descr(),
2127                         lt_name,
2128                     );
2129                     err.note(
2130                         "for more information on higher-ranked polymorphism, visit \
2131                     https://doc.rust-lang.org/nomicon/hrtb.html",
2132                     );
2133                     let for_sugg = span_type.suggestion(&lt_name);
2134                     for param in params {
2135                         if let Ok(snippet) = self.tcx.sess.source_map().span_to_snippet(param.span)
2136                         {
2137                             if snippet.starts_with('&') && !snippet.starts_with("&'") {
2138                                 introduce_suggestion
2139                                     .push((param.span, format!("&{} {}", lt_name, &snippet[1..])));
2140                             } else if let Some(stripped) = snippet.strip_prefix("&'_ ") {
2141                                 introduce_suggestion
2142                                     .push((param.span, format!("&{} {}", lt_name, stripped)));
2143                             }
2144                         }
2145                     }
2146                     introduce_suggestion.push((*for_span, for_sugg));
2147                     for ((span, _), formatter) in spans_with_counts.iter().zip(formatters.iter()) {
2148                         if let Some(formatter) = formatter {
2149                             introduce_suggestion.push((*span, formatter(&lt_name)));
2150                         }
2151                     }
2152                     err.multipart_suggestion_verbose(
2153                         &msg,
2154                         introduce_suggestion,
2155                         Applicability::MaybeIncorrect,
2156                     );
2157                 }
2158
2159                 let spans_suggs: Vec<_> = formatters
2160                     .into_iter()
2161                     .zip(spans_with_counts.iter())
2162                     .filter_map(|(formatter, (span, _))| {
2163                         if let Some(formatter) = formatter {
2164                             Some((*span, formatter(name)))
2165                         } else {
2166                             None
2167                         }
2168                     })
2169                     .collect();
2170                 if spans_suggs.is_empty() {
2171                     // If all the spans come from macros, we cannot extract snippets and then
2172                     // `formatters` only contains None and `spans_suggs` is empty.
2173                     return;
2174                 }
2175                 err.multipart_suggestion_verbose(
2176                     &format!(
2177                         "consider using the `{}` lifetime",
2178                         lifetime_names.iter().next().unwrap()
2179                     ),
2180                     spans_suggs,
2181                     Applicability::MaybeIncorrect,
2182                 );
2183             };
2184         let suggest_new = |err: &mut Diagnostic, suggs: Vec<Option<String>>| {
2185             for missing in self.missing_named_lifetime_spots.iter().rev() {
2186                 let mut introduce_suggestion = vec![];
2187                 let msg;
2188                 let should_break;
2189                 introduce_suggestion.push(match missing {
2190                     MissingLifetimeSpot::Generics(generics) => {
2191                         if generics.span == DUMMY_SP {
2192                             // Account for malformed generics in the HIR. This shouldn't happen,
2193                             // but if we make a mistake elsewhere, mainly by keeping something in
2194                             // `missing_named_lifetime_spots` that we shouldn't, like associated
2195                             // `const`s or making a mistake in the AST lowering we would provide
2196                             // nonsensical suggestions. Guard against that by skipping these.
2197                             // (#74264)
2198                             continue;
2199                         }
2200                         msg = "consider introducing a named lifetime parameter".to_string();
2201                         should_break = true;
2202                         if let Some(param) = generics.params.iter().find(|p| {
2203                             !matches!(
2204                                 p.kind,
2205                                 hir::GenericParamKind::Type { synthetic: true, .. }
2206                                     | hir::GenericParamKind::Lifetime {
2207                                         kind: hir::LifetimeParamKind::Elided
2208                                     }
2209                             )
2210                         }) {
2211                             (param.span.shrink_to_lo(), "'a, ".to_string())
2212                         } else {
2213                             (generics.span, "<'a>".to_string())
2214                         }
2215                     }
2216                     MissingLifetimeSpot::HigherRanked { span, span_type } => {
2217                         msg = format!(
2218                             "consider making the {} lifetime-generic with a new `'a` lifetime",
2219                             span_type.descr(),
2220                         );
2221                         should_break = false;
2222                         err.note(
2223                             "for more information on higher-ranked polymorphism, visit \
2224                             https://doc.rust-lang.org/nomicon/hrtb.html",
2225                         );
2226                         (*span, span_type.suggestion("'a"))
2227                     }
2228                     MissingLifetimeSpot::Static => {
2229                         let mut spans_suggs = Vec::new();
2230                         for ((span, count), snippet) in
2231                             spans_with_counts.iter().copied().zip(snippets.iter())
2232                         {
2233                             let (span, sugg) = match snippet.as_deref() {
2234                                 Some("&") => (span.shrink_to_hi(), "'static ".to_owned()),
2235                                 Some("'_") => (span, "'static".to_owned()),
2236                                 Some(snippet) if !snippet.ends_with('>') => {
2237                                     if snippet == "" {
2238                                         (
2239                                             span,
2240                                             std::iter::repeat("'static")
2241                                                 .take(count)
2242                                                 .collect::<Vec<_>>()
2243                                                 .join(", "),
2244                                         )
2245                                     } else if snippet == "<" || snippet == "(" {
2246                                         (
2247                                             span.shrink_to_hi(),
2248                                             std::iter::repeat("'static")
2249                                                 .take(count)
2250                                                 .collect::<Vec<_>>()
2251                                                 .join(", "),
2252                                         )
2253                                     } else {
2254                                         (
2255                                             span.shrink_to_hi(),
2256                                             format!(
2257                                                 "<{}>",
2258                                                 std::iter::repeat("'static")
2259                                                     .take(count)
2260                                                     .collect::<Vec<_>>()
2261                                                     .join(", "),
2262                                             ),
2263                                         )
2264                                     }
2265                                 }
2266                                 _ => continue,
2267                             };
2268                             spans_suggs.push((span, sugg.to_string()));
2269                         }
2270                         err.multipart_suggestion_verbose(
2271                             "consider using the `'static` lifetime",
2272                             spans_suggs,
2273                             Applicability::MaybeIncorrect,
2274                         );
2275                         continue;
2276                     }
2277                 });
2278
2279                 struct Lifetime(Span, String);
2280                 impl Lifetime {
2281                     fn is_unnamed(&self) -> bool {
2282                         self.1.starts_with('&') && !self.1.starts_with("&'")
2283                     }
2284                     fn is_underscore(&self) -> bool {
2285                         self.1.starts_with("&'_ ")
2286                     }
2287                     fn is_named(&self) -> bool {
2288                         self.1.starts_with("&'")
2289                     }
2290                     fn suggestion(&self, sugg: String) -> Option<(Span, String)> {
2291                         Some(
2292                             match (
2293                                 self.is_unnamed(),
2294                                 self.is_underscore(),
2295                                 self.is_named(),
2296                                 sugg.starts_with('&'),
2297                             ) {
2298                                 (true, _, _, false) => (self.span_unnamed_borrow(), sugg),
2299                                 (true, _, _, true) => {
2300                                     (self.span_unnamed_borrow(), sugg[1..].to_string())
2301                                 }
2302                                 (_, true, _, false) => {
2303                                     (self.span_underscore_borrow(), sugg.trim().to_string())
2304                                 }
2305                                 (_, true, _, true) => {
2306                                     (self.span_underscore_borrow(), sugg[1..].trim().to_string())
2307                                 }
2308                                 (_, _, true, false) => {
2309                                     (self.span_named_borrow(), sugg.trim().to_string())
2310                                 }
2311                                 (_, _, true, true) => {
2312                                     (self.span_named_borrow(), sugg[1..].trim().to_string())
2313                                 }
2314                                 _ => return None,
2315                             },
2316                         )
2317                     }
2318                     fn span_unnamed_borrow(&self) -> Span {
2319                         let lo = self.0.lo() + BytePos(1);
2320                         self.0.with_lo(lo).with_hi(lo)
2321                     }
2322                     fn span_named_borrow(&self) -> Span {
2323                         let lo = self.0.lo() + BytePos(1);
2324                         self.0.with_lo(lo)
2325                     }
2326                     fn span_underscore_borrow(&self) -> Span {
2327                         let lo = self.0.lo() + BytePos(1);
2328                         let hi = lo + BytePos(2);
2329                         self.0.with_lo(lo).with_hi(hi)
2330                     }
2331                 }
2332
2333                 for param in params {
2334                     if let Ok(snippet) = self.tcx.sess.source_map().span_to_snippet(param.span) {
2335                         if let Some((span, sugg)) =
2336                             Lifetime(param.span, snippet).suggestion("'a ".to_string())
2337                         {
2338                             introduce_suggestion.push((span, sugg));
2339                         }
2340                     }
2341                 }
2342                 for (span, sugg) in spans_with_counts.iter().copied().zip(suggs.iter()).filter_map(
2343                     |((span, _), sugg)| match &sugg {
2344                         Some(sugg) => Some((span, sugg.to_string())),
2345                         _ => None,
2346                     },
2347                 ) {
2348                     let (span, sugg) = self
2349                         .tcx
2350                         .sess
2351                         .source_map()
2352                         .span_to_snippet(span)
2353                         .ok()
2354                         .and_then(|snippet| Lifetime(span, snippet).suggestion(sugg.clone()))
2355                         .unwrap_or((span, sugg));
2356                     introduce_suggestion.push((span, sugg.to_string()));
2357                 }
2358                 err.multipart_suggestion_verbose(
2359                     &msg,
2360                     introduce_suggestion,
2361                     Applicability::MaybeIncorrect,
2362                 );
2363                 if should_break {
2364                     break;
2365                 }
2366             }
2367         };
2368
2369         let lifetime_names: Vec<_> = lifetime_names.iter().collect();
2370         match &lifetime_names[..] {
2371             [name] => {
2372                 let mut suggs: Vec<Option<Box<dyn Fn(&str) -> String>>> = Vec::new();
2373                 for (snippet, (_, count)) in snippets.iter().zip(spans_with_counts.iter().copied())
2374                 {
2375                     suggs.push(match snippet.as_deref() {
2376                         Some("&") => Some(Box::new(|name| format!("&{} ", name))),
2377                         Some("'_") => Some(Box::new(|n| n.to_string())),
2378                         Some("") => Some(Box::new(move |n| format!("{}, ", n).repeat(count))),
2379                         Some("<") => Some(Box::new(move |n| {
2380                             std::iter::repeat(n).take(count).collect::<Vec<_>>().join(", ")
2381                         })),
2382                         Some(snippet) if !snippet.ends_with('>') => Some(Box::new(move |name| {
2383                             format!(
2384                                 "{}<{}>",
2385                                 snippet,
2386                                 std::iter::repeat(name.to_string())
2387                                     .take(count)
2388                                     .collect::<Vec<_>>()
2389                                     .join(", ")
2390                             )
2391                         })),
2392                         _ => None,
2393                     });
2394                 }
2395                 suggest_existing(err, name.as_str(), suggs);
2396             }
2397             [] => {
2398                 let mut suggs = Vec::new();
2399                 for (snippet, (_, count)) in
2400                     snippets.iter().cloned().zip(spans_with_counts.iter().copied())
2401                 {
2402                     suggs.push(match snippet.as_deref() {
2403                         Some("&") => Some("&'a ".to_string()),
2404                         Some("'_") => Some("'a".to_string()),
2405                         Some("") => {
2406                             Some(std::iter::repeat("'a, ").take(count).collect::<Vec<_>>().join(""))
2407                         }
2408                         Some("<") => {
2409                             Some(std::iter::repeat("'a").take(count).collect::<Vec<_>>().join(", "))
2410                         }
2411                         Some(snippet) => Some(format!(
2412                             "{}<{}>",
2413                             snippet,
2414                             std::iter::repeat("'a").take(count).collect::<Vec<_>>().join(", "),
2415                         )),
2416                         None => None,
2417                     });
2418                 }
2419                 suggest_new(err, suggs);
2420             }
2421             lts if lts.len() > 1 => {
2422                 err.span_note(lifetime_spans, "these named lifetimes are available to use");
2423
2424                 let mut spans_suggs: Vec<_> = Vec::new();
2425                 for ((span, _), snippet) in spans_with_counts.iter().copied().zip(snippets.iter()) {
2426                     match snippet.as_deref() {
2427                         Some("") => spans_suggs.push((span, "'lifetime, ".to_string())),
2428                         Some("&") => spans_suggs
2429                             .push((span.with_lo(span.lo() + BytePos(1)), "'lifetime ".to_string())),
2430                         _ => {}
2431                     }
2432                 }
2433
2434                 if spans_suggs.len() > 0 {
2435                     // This happens when we have `Foo<T>` where we point at the space before `T`,
2436                     // but this can be confusing so we give a suggestion with placeholders.
2437                     err.multipart_suggestion_verbose(
2438                         "consider using one of the available lifetimes here",
2439                         spans_suggs,
2440                         Applicability::HasPlaceholders,
2441                     );
2442                 }
2443             }
2444             _ => unreachable!(),
2445         }
2446     }
2447
2448     /// Non-static lifetimes are prohibited in anonymous constants under `min_const_generics`.
2449     /// This function will emit an error if `generic_const_exprs` is not enabled, the body identified by
2450     /// `body_id` is an anonymous constant and `lifetime_ref` is non-static.
2451     crate fn maybe_emit_forbidden_non_static_lifetime_error(
2452         &self,
2453         body_id: hir::BodyId,
2454         lifetime_ref: &'tcx hir::Lifetime,
2455     ) {
2456         let is_anon_const = matches!(
2457             self.tcx.def_kind(self.tcx.hir().body_owner_def_id(body_id)),
2458             hir::def::DefKind::AnonConst
2459         );
2460         let is_allowed_lifetime = matches!(
2461             lifetime_ref.name,
2462             hir::LifetimeName::Implicit | hir::LifetimeName::Static | hir::LifetimeName::Underscore
2463         );
2464
2465         if !self.tcx.lazy_normalization() && is_anon_const && !is_allowed_lifetime {
2466             feature_err(
2467                 &self.tcx.sess.parse_sess,
2468                 sym::generic_const_exprs,
2469                 lifetime_ref.span,
2470                 "a non-static lifetime is not allowed in a `const`",
2471             )
2472             .emit();
2473         }
2474     }
2475 }