]> git.lizzy.rs Git - rust.git/blob - compiler/rustc_resolve/src/late/diagnostics.rs
Rollup merge of #96671 - mgeisler:current-exe-docstring, r=Mark-Simulacrum
[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::{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), None) {
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, None)
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 (module, _) = self.current_trait_ref.as_ref()?;
1228         if ident == kw::Underscore {
1229             // We do nothing for `_`.
1230             return None;
1231         }
1232
1233         let resolutions = self.r.resolutions(module);
1234         let targets = resolutions
1235             .borrow()
1236             .iter()
1237             .filter_map(|(key, res)| res.borrow().binding.map(|binding| (key, binding.res())))
1238             .filter(|(_, res)| match (kind, res) {
1239                 (AssocItemKind::Const(..), Res::Def(DefKind::AssocConst, _)) => true,
1240                 (AssocItemKind::Fn(_), Res::Def(DefKind::AssocFn, _)) => true,
1241                 (AssocItemKind::TyAlias(..), Res::Def(DefKind::AssocTy, _)) => true,
1242                 _ => false,
1243             })
1244             .map(|(key, _)| key.ident.name)
1245             .collect::<Vec<_>>();
1246
1247         find_best_match_for_name(&targets, ident, None)
1248     }
1249
1250     fn lookup_assoc_candidate<FilterFn>(
1251         &mut self,
1252         ident: Ident,
1253         ns: Namespace,
1254         filter_fn: FilterFn,
1255     ) -> Option<AssocSuggestion>
1256     where
1257         FilterFn: Fn(Res) -> bool,
1258     {
1259         fn extract_node_id(t: &Ty) -> Option<NodeId> {
1260             match t.kind {
1261                 TyKind::Path(None, _) => Some(t.id),
1262                 TyKind::Rptr(_, ref mut_ty) => extract_node_id(&mut_ty.ty),
1263                 // This doesn't handle the remaining `Ty` variants as they are not
1264                 // that commonly the self_type, it might be interesting to provide
1265                 // support for those in future.
1266                 _ => None,
1267             }
1268         }
1269
1270         // Fields are generally expected in the same contexts as locals.
1271         if filter_fn(Res::Local(ast::DUMMY_NODE_ID)) {
1272             if let Some(node_id) =
1273                 self.diagnostic_metadata.current_self_type.as_ref().and_then(extract_node_id)
1274             {
1275                 // Look for a field with the same name in the current self_type.
1276                 if let Some(resolution) = self.r.partial_res_map.get(&node_id) {
1277                     match resolution.base_res() {
1278                         Res::Def(DefKind::Struct | DefKind::Union, did)
1279                             if resolution.unresolved_segments() == 0 =>
1280                         {
1281                             if let Some(field_names) = self.r.field_names.get(&did) {
1282                                 if field_names
1283                                     .iter()
1284                                     .any(|&field_name| ident.name == field_name.node)
1285                                 {
1286                                     return Some(AssocSuggestion::Field);
1287                                 }
1288                             }
1289                         }
1290                         _ => {}
1291                     }
1292                 }
1293             }
1294         }
1295
1296         if let Some(items) = self.diagnostic_metadata.current_trait_assoc_items {
1297             for assoc_item in items {
1298                 if assoc_item.ident == ident {
1299                     return Some(match &assoc_item.kind {
1300                         ast::AssocItemKind::Const(..) => AssocSuggestion::AssocConst,
1301                         ast::AssocItemKind::Fn(box ast::Fn { sig, .. }) if sig.decl.has_self() => {
1302                             AssocSuggestion::MethodWithSelf
1303                         }
1304                         ast::AssocItemKind::Fn(..) => AssocSuggestion::AssocFn,
1305                         ast::AssocItemKind::TyAlias(..) => AssocSuggestion::AssocType,
1306                         ast::AssocItemKind::MacCall(_) => continue,
1307                     });
1308                 }
1309             }
1310         }
1311
1312         // Look for associated items in the current trait.
1313         if let Some((module, _)) = self.current_trait_ref {
1314             if let Ok(binding) = self.r.maybe_resolve_ident_in_module(
1315                 ModuleOrUniformRoot::Module(module),
1316                 ident,
1317                 ns,
1318                 &self.parent_scope,
1319             ) {
1320                 let res = binding.res();
1321                 if filter_fn(res) {
1322                     if self.r.has_self.contains(&res.def_id()) {
1323                         return Some(AssocSuggestion::MethodWithSelf);
1324                     } else {
1325                         match res {
1326                             Res::Def(DefKind::AssocFn, _) => return Some(AssocSuggestion::AssocFn),
1327                             Res::Def(DefKind::AssocConst, _) => {
1328                                 return Some(AssocSuggestion::AssocConst);
1329                             }
1330                             Res::Def(DefKind::AssocTy, _) => {
1331                                 return Some(AssocSuggestion::AssocType);
1332                             }
1333                             _ => {}
1334                         }
1335                     }
1336                 }
1337             }
1338         }
1339
1340         None
1341     }
1342
1343     fn lookup_typo_candidate(
1344         &mut self,
1345         path: &[Segment],
1346         ns: Namespace,
1347         filter_fn: &impl Fn(Res) -> bool,
1348     ) -> Option<TypoSuggestion> {
1349         let mut names = Vec::new();
1350         if path.len() == 1 {
1351             // Search in lexical scope.
1352             // Walk backwards up the ribs in scope and collect candidates.
1353             for rib in self.ribs[ns].iter().rev() {
1354                 // Locals and type parameters
1355                 for (ident, &res) in &rib.bindings {
1356                     if filter_fn(res) {
1357                         names.push(TypoSuggestion::typo_from_res(ident.name, res));
1358                     }
1359                 }
1360                 // Items in scope
1361                 if let RibKind::ModuleRibKind(module) = rib.kind {
1362                     // Items from this module
1363                     self.r.add_module_candidates(module, &mut names, &filter_fn);
1364
1365                     if let ModuleKind::Block(..) = module.kind {
1366                         // We can see through blocks
1367                     } else {
1368                         // Items from the prelude
1369                         if !module.no_implicit_prelude {
1370                             let extern_prelude = self.r.extern_prelude.clone();
1371                             names.extend(extern_prelude.iter().flat_map(|(ident, _)| {
1372                                 self.r.crate_loader.maybe_process_path_extern(ident.name).and_then(
1373                                     |crate_id| {
1374                                         let crate_mod =
1375                                             Res::Def(DefKind::Mod, crate_id.as_def_id());
1376
1377                                         if filter_fn(crate_mod) {
1378                                             Some(TypoSuggestion::typo_from_res(
1379                                                 ident.name, crate_mod,
1380                                             ))
1381                                         } else {
1382                                             None
1383                                         }
1384                                     },
1385                                 )
1386                             }));
1387
1388                             if let Some(prelude) = self.r.prelude {
1389                                 self.r.add_module_candidates(prelude, &mut names, &filter_fn);
1390                             }
1391                         }
1392                         break;
1393                     }
1394                 }
1395             }
1396             // Add primitive types to the mix
1397             if filter_fn(Res::PrimTy(PrimTy::Bool)) {
1398                 names.extend(PrimTy::ALL.iter().map(|prim_ty| {
1399                     TypoSuggestion::typo_from_res(prim_ty.name(), Res::PrimTy(*prim_ty))
1400                 }))
1401             }
1402         } else {
1403             // Search in module.
1404             let mod_path = &path[..path.len() - 1];
1405             if let PathResult::Module(ModuleOrUniformRoot::Module(module)) =
1406                 self.resolve_path(mod_path, Some(TypeNS), None)
1407             {
1408                 self.r.add_module_candidates(module, &mut names, &filter_fn);
1409             }
1410         }
1411
1412         let name = path[path.len() - 1].ident.name;
1413         // Make sure error reporting is deterministic.
1414         names.sort_by(|a, b| a.candidate.as_str().partial_cmp(b.candidate.as_str()).unwrap());
1415
1416         match find_best_match_for_name(
1417             &names.iter().map(|suggestion| suggestion.candidate).collect::<Vec<Symbol>>(),
1418             name,
1419             None,
1420         ) {
1421             Some(found) if found != name => {
1422                 names.into_iter().find(|suggestion| suggestion.candidate == found)
1423             }
1424             _ => None,
1425         }
1426     }
1427
1428     // Returns the name of the Rust type approximately corresponding to
1429     // a type name in another programming language.
1430     fn likely_rust_type(path: &[Segment]) -> Option<Symbol> {
1431         let name = path[path.len() - 1].ident.as_str();
1432         // Common Java types
1433         Some(match name {
1434             "byte" => sym::u8, // In Java, bytes are signed, but in practice one almost always wants unsigned bytes.
1435             "short" => sym::i16,
1436             "boolean" => sym::bool,
1437             "int" => sym::i32,
1438             "long" => sym::i64,
1439             "float" => sym::f32,
1440             "double" => sym::f64,
1441             _ => return None,
1442         })
1443     }
1444
1445     /// Only used in a specific case of type ascription suggestions
1446     fn get_colon_suggestion_span(&self, start: Span) -> Span {
1447         let sm = self.r.session.source_map();
1448         start.to(sm.next_point(start))
1449     }
1450
1451     fn type_ascription_suggestion(&self, err: &mut Diagnostic, base_span: Span) -> bool {
1452         let sm = self.r.session.source_map();
1453         let base_snippet = sm.span_to_snippet(base_span);
1454         if let Some(&sp) = self.diagnostic_metadata.current_type_ascription.last() {
1455             if let Ok(snippet) = sm.span_to_snippet(sp) {
1456                 let len = snippet.trim_end().len() as u32;
1457                 if snippet.trim() == ":" {
1458                     let colon_sp =
1459                         sp.with_lo(sp.lo() + BytePos(len - 1)).with_hi(sp.lo() + BytePos(len));
1460                     let mut show_label = true;
1461                     if sm.is_multiline(sp) {
1462                         err.span_suggestion_short(
1463                             colon_sp,
1464                             "maybe you meant to write `;` here",
1465                             ";".to_string(),
1466                             Applicability::MaybeIncorrect,
1467                         );
1468                     } else {
1469                         let after_colon_sp =
1470                             self.get_colon_suggestion_span(colon_sp.shrink_to_hi());
1471                         if snippet.len() == 1 {
1472                             // `foo:bar`
1473                             err.span_suggestion(
1474                                 colon_sp,
1475                                 "maybe you meant to write a path separator here",
1476                                 "::".to_string(),
1477                                 Applicability::MaybeIncorrect,
1478                             );
1479                             show_label = false;
1480                             if !self
1481                                 .r
1482                                 .session
1483                                 .parse_sess
1484                                 .type_ascription_path_suggestions
1485                                 .borrow_mut()
1486                                 .insert(colon_sp)
1487                             {
1488                                 err.downgrade_to_delayed_bug();
1489                             }
1490                         }
1491                         if let Ok(base_snippet) = base_snippet {
1492                             let mut sp = after_colon_sp;
1493                             for _ in 0..100 {
1494                                 // Try to find an assignment
1495                                 sp = sm.next_point(sp);
1496                                 let snippet = sm.span_to_snippet(sp.to(sm.next_point(sp)));
1497                                 match snippet {
1498                                     Ok(ref x) if x.as_str() == "=" => {
1499                                         err.span_suggestion(
1500                                             base_span,
1501                                             "maybe you meant to write an assignment here",
1502                                             format!("let {}", base_snippet),
1503                                             Applicability::MaybeIncorrect,
1504                                         );
1505                                         show_label = false;
1506                                         break;
1507                                     }
1508                                     Ok(ref x) if x.as_str() == "\n" => break,
1509                                     Err(_) => break,
1510                                     Ok(_) => {}
1511                                 }
1512                             }
1513                         }
1514                     }
1515                     if show_label {
1516                         err.span_label(
1517                             base_span,
1518                             "expecting a type here because of type ascription",
1519                         );
1520                     }
1521                     return show_label;
1522                 }
1523             }
1524         }
1525         false
1526     }
1527
1528     fn find_module(&mut self, def_id: DefId) -> Option<(Module<'a>, ImportSuggestion)> {
1529         let mut result = None;
1530         let mut seen_modules = FxHashSet::default();
1531         let mut worklist = vec![(self.r.graph_root, Vec::new())];
1532
1533         while let Some((in_module, path_segments)) = worklist.pop() {
1534             // abort if the module is already found
1535             if result.is_some() {
1536                 break;
1537             }
1538
1539             in_module.for_each_child(self.r, |_, ident, _, name_binding| {
1540                 // abort if the module is already found or if name_binding is private external
1541                 if result.is_some() || !name_binding.vis.is_visible_locally() {
1542                     return;
1543                 }
1544                 if let Some(module) = name_binding.module() {
1545                     // form the path
1546                     let mut path_segments = path_segments.clone();
1547                     path_segments.push(ast::PathSegment::from_ident(ident));
1548                     let module_def_id = module.def_id();
1549                     if module_def_id == def_id {
1550                         let path =
1551                             Path { span: name_binding.span, segments: path_segments, tokens: None };
1552                         result = Some((
1553                             module,
1554                             ImportSuggestion {
1555                                 did: Some(def_id),
1556                                 descr: "module",
1557                                 path,
1558                                 accessible: true,
1559                                 note: None,
1560                             },
1561                         ));
1562                     } else {
1563                         // add the module to the lookup
1564                         if seen_modules.insert(module_def_id) {
1565                             worklist.push((module, path_segments));
1566                         }
1567                     }
1568                 }
1569             });
1570         }
1571
1572         result
1573     }
1574
1575     fn collect_enum_ctors(&mut self, def_id: DefId) -> Option<Vec<(Path, DefId, CtorKind)>> {
1576         self.find_module(def_id).map(|(enum_module, enum_import_suggestion)| {
1577             let mut variants = Vec::new();
1578             enum_module.for_each_child(self.r, |_, ident, _, name_binding| {
1579                 if let Res::Def(DefKind::Ctor(CtorOf::Variant, kind), def_id) = name_binding.res() {
1580                     let mut segms = enum_import_suggestion.path.segments.clone();
1581                     segms.push(ast::PathSegment::from_ident(ident));
1582                     let path = Path { span: name_binding.span, segments: segms, tokens: None };
1583                     variants.push((path, def_id, kind));
1584                 }
1585             });
1586             variants
1587         })
1588     }
1589
1590     /// Adds a suggestion for using an enum's variant when an enum is used instead.
1591     fn suggest_using_enum_variant(
1592         &mut self,
1593         err: &mut Diagnostic,
1594         source: PathSource<'_>,
1595         def_id: DefId,
1596         span: Span,
1597     ) {
1598         let Some(variants) = self.collect_enum_ctors(def_id) else {
1599             err.note("you might have meant to use one of the enum's variants");
1600             return;
1601         };
1602
1603         let suggest_only_tuple_variants =
1604             matches!(source, PathSource::TupleStruct(..)) || source.is_call();
1605         if suggest_only_tuple_variants {
1606             // Suggest only tuple variants regardless of whether they have fields and do not
1607             // suggest path with added parentheses.
1608             let suggestable_variants = variants
1609                 .iter()
1610                 .filter(|(.., kind)| *kind == CtorKind::Fn)
1611                 .map(|(variant, ..)| path_names_to_string(variant))
1612                 .collect::<Vec<_>>();
1613
1614             let non_suggestable_variant_count = variants.len() - suggestable_variants.len();
1615
1616             let source_msg = if source.is_call() {
1617                 "to construct"
1618             } else if matches!(source, PathSource::TupleStruct(..)) {
1619                 "to match against"
1620             } else {
1621                 unreachable!()
1622             };
1623
1624             if !suggestable_variants.is_empty() {
1625                 let msg = if non_suggestable_variant_count == 0 && suggestable_variants.len() == 1 {
1626                     format!("try {} the enum's variant", source_msg)
1627                 } else {
1628                     format!("try {} one of the enum's variants", source_msg)
1629                 };
1630
1631                 err.span_suggestions(
1632                     span,
1633                     &msg,
1634                     suggestable_variants.into_iter(),
1635                     Applicability::MaybeIncorrect,
1636                 );
1637             }
1638
1639             // If the enum has no tuple variants..
1640             if non_suggestable_variant_count == variants.len() {
1641                 err.help(&format!("the enum has no tuple variants {}", source_msg));
1642             }
1643
1644             // If there are also non-tuple variants..
1645             if non_suggestable_variant_count == 1 {
1646                 err.help(&format!(
1647                     "you might have meant {} the enum's non-tuple variant",
1648                     source_msg
1649                 ));
1650             } else if non_suggestable_variant_count >= 1 {
1651                 err.help(&format!(
1652                     "you might have meant {} one of the enum's non-tuple variants",
1653                     source_msg
1654                 ));
1655             }
1656         } else {
1657             let needs_placeholder = |def_id: DefId, kind: CtorKind| {
1658                 let has_no_fields = self.r.field_names.get(&def_id).map_or(false, |f| f.is_empty());
1659                 match kind {
1660                     CtorKind::Const => false,
1661                     CtorKind::Fn | CtorKind::Fictive if has_no_fields => false,
1662                     _ => true,
1663                 }
1664             };
1665
1666             let mut suggestable_variants = variants
1667                 .iter()
1668                 .filter(|(_, def_id, kind)| !needs_placeholder(*def_id, *kind))
1669                 .map(|(variant, _, kind)| (path_names_to_string(variant), kind))
1670                 .map(|(variant, kind)| match kind {
1671                     CtorKind::Const => variant,
1672                     CtorKind::Fn => format!("({}())", variant),
1673                     CtorKind::Fictive => format!("({} {{}})", variant),
1674                 })
1675                 .collect::<Vec<_>>();
1676
1677             if !suggestable_variants.is_empty() {
1678                 let msg = if suggestable_variants.len() == 1 {
1679                     "you might have meant to use the following enum variant"
1680                 } else {
1681                     "you might have meant to use one of the following enum variants"
1682                 };
1683
1684                 err.span_suggestions(
1685                     span,
1686                     msg,
1687                     suggestable_variants.drain(..),
1688                     Applicability::MaybeIncorrect,
1689                 );
1690             }
1691
1692             let suggestable_variants_with_placeholders = variants
1693                 .iter()
1694                 .filter(|(_, def_id, kind)| needs_placeholder(*def_id, *kind))
1695                 .map(|(variant, _, kind)| (path_names_to_string(variant), kind))
1696                 .filter_map(|(variant, kind)| match kind {
1697                     CtorKind::Fn => Some(format!("({}(/* fields */))", variant)),
1698                     CtorKind::Fictive => Some(format!("({} {{ /* fields */ }})", variant)),
1699                     _ => None,
1700                 })
1701                 .collect::<Vec<_>>();
1702
1703             if !suggestable_variants_with_placeholders.is_empty() {
1704                 let msg = match (
1705                     suggestable_variants.is_empty(),
1706                     suggestable_variants_with_placeholders.len(),
1707                 ) {
1708                     (true, 1) => "the following enum variant is available",
1709                     (true, _) => "the following enum variants are available",
1710                     (false, 1) => "alternatively, the following enum variant is available",
1711                     (false, _) => "alternatively, the following enum variants are also available",
1712                 };
1713
1714                 err.span_suggestions(
1715                     span,
1716                     msg,
1717                     suggestable_variants_with_placeholders.into_iter(),
1718                     Applicability::HasPlaceholders,
1719                 );
1720             }
1721         };
1722
1723         if def_id.is_local() {
1724             if let Some(span) = self.def_span(def_id) {
1725                 err.span_note(span, "the enum is defined here");
1726             }
1727         }
1728     }
1729
1730     crate fn report_missing_type_error(
1731         &self,
1732         path: &[Segment],
1733     ) -> Option<(Span, &'static str, String, Applicability)> {
1734         let (ident, span) = match path {
1735             [segment] if !segment.has_generic_args => {
1736                 (segment.ident.to_string(), segment.ident.span)
1737             }
1738             _ => return None,
1739         };
1740         let mut iter = ident.chars().map(|c| c.is_uppercase());
1741         let single_uppercase_char =
1742             matches!(iter.next(), Some(true)) && matches!(iter.next(), None);
1743         if !self.diagnostic_metadata.currently_processing_generics && !single_uppercase_char {
1744             return None;
1745         }
1746         match (self.diagnostic_metadata.current_item, single_uppercase_char, self.diagnostic_metadata.currently_processing_generics) {
1747             (Some(Item { kind: ItemKind::Fn(..), ident, .. }), _, _) if ident.name == sym::main => {
1748                 // Ignore `fn main()` as we don't want to suggest `fn main<T>()`
1749             }
1750             (
1751                 Some(Item {
1752                     kind:
1753                         kind @ ItemKind::Fn(..)
1754                         | kind @ ItemKind::Enum(..)
1755                         | kind @ ItemKind::Struct(..)
1756                         | kind @ ItemKind::Union(..),
1757                     ..
1758                 }),
1759                 true, _
1760             )
1761             // Without the 2nd `true`, we'd suggest `impl <T>` for `impl T` when a type `T` isn't found
1762             | (Some(Item { kind: kind @ ItemKind::Impl(..), .. }), true, true)
1763             | (Some(Item { kind, .. }), false, _) => {
1764                 // Likely missing type parameter.
1765                 if let Some(generics) = kind.generics() {
1766                     if span.overlaps(generics.span) {
1767                         // Avoid the following:
1768                         // error[E0405]: cannot find trait `A` in this scope
1769                         //  --> $DIR/typo-suggestion-named-underscore.rs:CC:LL
1770                         //   |
1771                         // L | fn foo<T: A>(x: T) {} // Shouldn't suggest underscore
1772                         //   |           ^- help: you might be missing a type parameter: `, A`
1773                         //   |           |
1774                         //   |           not found in this scope
1775                         return None;
1776                     }
1777                     let msg = "you might be missing a type parameter";
1778                     let (span, sugg) = if let [.., param] = &generics.params[..] {
1779                         let span = if let [.., bound] = &param.bounds[..] {
1780                             bound.span()
1781                         } else if let GenericParam {
1782                             kind: GenericParamKind::Const { ty, kw_span: _, default  }, ..
1783                         } = param {
1784                             default.as_ref().map(|def| def.value.span).unwrap_or(ty.span)
1785                         } else {
1786                             param.ident.span
1787                         };
1788                         (span, format!(", {}", ident))
1789                     } else {
1790                         (generics.span, format!("<{}>", ident))
1791                     };
1792                     // Do not suggest if this is coming from macro expansion.
1793                     if span.can_be_used_for_suggestions() {
1794                         return Some((
1795                             span.shrink_to_hi(),
1796                             msg,
1797                             sugg,
1798                             Applicability::MaybeIncorrect,
1799                         ));
1800                     }
1801                 }
1802             }
1803             _ => {}
1804         }
1805         None
1806     }
1807
1808     /// Given the target `label`, search the `rib_index`th label rib for similarly named labels,
1809     /// optionally returning the closest match and whether it is reachable.
1810     crate fn suggestion_for_label_in_rib(
1811         &self,
1812         rib_index: usize,
1813         label: Ident,
1814     ) -> Option<LabelSuggestion> {
1815         // Are ribs from this `rib_index` within scope?
1816         let within_scope = self.is_label_valid_from_rib(rib_index);
1817
1818         let rib = &self.label_ribs[rib_index];
1819         let names = rib
1820             .bindings
1821             .iter()
1822             .filter(|(id, _)| id.span.ctxt() == label.span.ctxt())
1823             .map(|(id, _)| id.name)
1824             .collect::<Vec<Symbol>>();
1825
1826         find_best_match_for_name(&names, label.name, None).map(|symbol| {
1827             // Upon finding a similar name, get the ident that it was from - the span
1828             // contained within helps make a useful diagnostic. In addition, determine
1829             // whether this candidate is within scope.
1830             let (ident, _) = rib.bindings.iter().find(|(ident, _)| ident.name == symbol).unwrap();
1831             (*ident, within_scope)
1832         })
1833     }
1834
1835     crate fn emit_undeclared_lifetime_error(
1836         &self,
1837         lifetime_ref: &ast::Lifetime,
1838         outer_lifetime_ref: Option<Ident>,
1839     ) {
1840         debug_assert_ne!(lifetime_ref.ident.name, kw::UnderscoreLifetime);
1841         let mut err = if let Some(outer) = outer_lifetime_ref {
1842             let mut err = struct_span_err!(
1843                 self.r.session,
1844                 lifetime_ref.ident.span,
1845                 E0401,
1846                 "can't use generic parameters from outer item",
1847             );
1848             err.span_label(lifetime_ref.ident.span, "use of generic parameter from outer item");
1849             err.span_label(outer.span, "lifetime parameter from outer item");
1850             err
1851         } else {
1852             let mut err = struct_span_err!(
1853                 self.r.session,
1854                 lifetime_ref.ident.span,
1855                 E0261,
1856                 "use of undeclared lifetime name `{}`",
1857                 lifetime_ref.ident
1858             );
1859             err.span_label(lifetime_ref.ident.span, "undeclared lifetime");
1860             err
1861         };
1862         let mut suggest_note = true;
1863
1864         for rib in self.lifetime_ribs.iter().rev() {
1865             match rib.kind {
1866                 LifetimeRibKind::Generics { parent: _, span, kind } => {
1867                     if !span.can_be_used_for_suggestions() && suggest_note {
1868                         suggest_note = false; // Avoid displaying the same help multiple times.
1869                         err.span_label(
1870                             span,
1871                             &format!(
1872                                 "lifetime `{}` is missing in item created through this procedural macro",
1873                                 lifetime_ref.ident,
1874                             ),
1875                         );
1876                         continue;
1877                     }
1878
1879                     let higher_ranked = matches!(
1880                         kind,
1881                         LifetimeBinderKind::BareFnType
1882                             | LifetimeBinderKind::PolyTrait
1883                             | LifetimeBinderKind::WhereBound
1884                     );
1885                     let (span, sugg) = if span.is_empty() {
1886                         let sugg = format!(
1887                             "{}<{}>{}",
1888                             if higher_ranked { "for" } else { "" },
1889                             lifetime_ref.ident,
1890                             if higher_ranked { " " } else { "" },
1891                         );
1892                         (span, sugg)
1893                     } else {
1894                         let span =
1895                             self.r.session.source_map().span_through_char(span, '<').shrink_to_hi();
1896                         let sugg = format!("{}, ", lifetime_ref.ident);
1897                         (span, sugg)
1898                     };
1899                     if higher_ranked {
1900                         err.span_suggestion(
1901                             span,
1902                             &format!(
1903                                 "consider making the {} lifetime-generic with a new `{}` lifetime",
1904                                 kind.descr(),
1905                                 lifetime_ref
1906                             ),
1907                             sugg,
1908                             Applicability::MaybeIncorrect,
1909                         );
1910                         err.note_once(
1911                             "for more information on higher-ranked polymorphism, visit \
1912                              https://doc.rust-lang.org/nomicon/hrtb.html",
1913                         );
1914                     } else {
1915                         err.span_suggestion(
1916                             span,
1917                             &format!("consider introducing lifetime `{}` here", lifetime_ref.ident),
1918                             sugg,
1919                             Applicability::MaybeIncorrect,
1920                         );
1921                     }
1922                 }
1923                 LifetimeRibKind::Item => break,
1924                 _ => {}
1925             }
1926         }
1927
1928         err.emit();
1929     }
1930
1931     crate fn emit_non_static_lt_in_const_generic_error(&self, lifetime_ref: &ast::Lifetime) {
1932         struct_span_err!(
1933             self.r.session,
1934             lifetime_ref.ident.span,
1935             E0771,
1936             "use of non-static lifetime `{}` in const generic",
1937             lifetime_ref.ident
1938         )
1939         .note(
1940             "for more information, see issue #74052 \
1941             <https://github.com/rust-lang/rust/issues/74052>",
1942         )
1943         .emit();
1944     }
1945
1946     /// Non-static lifetimes are prohibited in anonymous constants under `min_const_generics`.
1947     /// This function will emit an error if `generic_const_exprs` is not enabled, the body identified by
1948     /// `body_id` is an anonymous constant and `lifetime_ref` is non-static.
1949     crate fn maybe_emit_forbidden_non_static_lifetime_error(&self, lifetime_ref: &ast::Lifetime) {
1950         let feature_active = self.r.session.features_untracked().generic_const_exprs;
1951         if !feature_active {
1952             feature_err(
1953                 &self.r.session.parse_sess,
1954                 sym::generic_const_exprs,
1955                 lifetime_ref.ident.span,
1956                 "a non-static lifetime is not allowed in a `const`",
1957             )
1958             .emit();
1959         }
1960     }
1961 }
1962
1963 impl<'tcx> LifetimeContext<'_, 'tcx> {
1964     crate fn report_missing_lifetime_specifiers(
1965         &self,
1966         spans: Vec<Span>,
1967         count: usize,
1968     ) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> {
1969         struct_span_err!(
1970             self.tcx.sess,
1971             spans,
1972             E0106,
1973             "missing lifetime specifier{}",
1974             pluralize!(count)
1975         )
1976     }
1977
1978     /// Returns whether to add `'static` lifetime to the suggested lifetime list.
1979     crate fn report_elision_failure(
1980         &mut self,
1981         diag: &mut Diagnostic,
1982         params: &[ElisionFailureInfo],
1983     ) -> bool {
1984         let mut m = String::new();
1985         let len = params.len();
1986
1987         let elided_params: Vec<_> =
1988             params.iter().cloned().filter(|info| info.lifetime_count > 0).collect();
1989
1990         let elided_len = elided_params.len();
1991
1992         for (i, info) in elided_params.into_iter().enumerate() {
1993             let ElisionFailureInfo { parent, index, lifetime_count: n, have_bound_regions, span } =
1994                 info;
1995
1996             diag.span_label(span, "");
1997             let help_name = if let Some(ident) =
1998                 parent.and_then(|body| self.tcx.hir().body(body).params[index].pat.simple_ident())
1999             {
2000                 format!("`{}`", ident)
2001             } else {
2002                 format!("argument {}", index + 1)
2003             };
2004
2005             m.push_str(
2006                 &(if n == 1 {
2007                     help_name
2008                 } else {
2009                     format!(
2010                         "one of {}'s {} {}lifetimes",
2011                         help_name,
2012                         n,
2013                         if have_bound_regions { "free " } else { "" }
2014                     )
2015                 })[..],
2016             );
2017
2018             if elided_len == 2 && i == 0 {
2019                 m.push_str(" or ");
2020             } else if i + 2 == elided_len {
2021                 m.push_str(", or ");
2022             } else if i != elided_len - 1 {
2023                 m.push_str(", ");
2024             }
2025         }
2026
2027         if len == 0 {
2028             diag.help(
2029                 "this function's return type contains a borrowed value, \
2030                  but there is no value for it to be borrowed from",
2031             );
2032             true
2033         } else if elided_len == 0 {
2034             diag.help(
2035                 "this function's return type contains a borrowed value with \
2036                  an elided lifetime, but the lifetime cannot be derived from \
2037                  the arguments",
2038             );
2039             true
2040         } else if elided_len == 1 {
2041             diag.help(&format!(
2042                 "this function's return type contains a borrowed value, \
2043                  but the signature does not say which {} it is borrowed from",
2044                 m
2045             ));
2046             false
2047         } else {
2048             diag.help(&format!(
2049                 "this function's return type contains a borrowed value, \
2050                  but the signature does not say whether it is borrowed from {}",
2051                 m
2052             ));
2053             false
2054         }
2055     }
2056
2057     crate fn is_trait_ref_fn_scope(&mut self, trait_ref: &'tcx hir::PolyTraitRef<'tcx>) -> bool {
2058         if let def::Res::Def(_, did) = trait_ref.trait_ref.path.res {
2059             if [
2060                 self.tcx.lang_items().fn_once_trait(),
2061                 self.tcx.lang_items().fn_trait(),
2062                 self.tcx.lang_items().fn_mut_trait(),
2063             ]
2064             .contains(&Some(did))
2065             {
2066                 let (span, span_type) = match &trait_ref.bound_generic_params {
2067                     [] => (trait_ref.span.shrink_to_lo(), ForLifetimeSpanType::BoundEmpty),
2068                     [.., bound] => (bound.span.shrink_to_hi(), ForLifetimeSpanType::BoundTail),
2069                 };
2070                 self.missing_named_lifetime_spots
2071                     .push(MissingLifetimeSpot::HigherRanked { span, span_type });
2072                 return true;
2073             }
2074         };
2075         false
2076     }
2077
2078     crate fn add_missing_lifetime_specifiers_label(
2079         &self,
2080         err: &mut Diagnostic,
2081         mut spans_with_counts: Vec<(Span, usize)>,
2082         lifetime_names: &FxHashSet<Symbol>,
2083         lifetime_spans: Vec<Span>,
2084         params: &[ElisionFailureInfo],
2085     ) {
2086         let snippets: Vec<Option<String>> = spans_with_counts
2087             .iter()
2088             .map(|(span, _)| self.tcx.sess.source_map().span_to_snippet(*span).ok())
2089             .collect();
2090
2091         // Empty generics are marked with a span of "<", but since from now on
2092         // that information is in the snippets it can be removed from the spans.
2093         for ((span, _), snippet) in spans_with_counts.iter_mut().zip(&snippets) {
2094             if snippet.as_deref() == Some("<") {
2095                 *span = span.shrink_to_hi();
2096             }
2097         }
2098
2099         for &(span, count) in &spans_with_counts {
2100             err.span_label(
2101                 span,
2102                 format!(
2103                     "expected {} lifetime parameter{}",
2104                     if count == 1 { "named".to_string() } else { count.to_string() },
2105                     pluralize!(count),
2106                 ),
2107             );
2108         }
2109
2110         let suggest_existing =
2111             |err: &mut Diagnostic,
2112              name: &str,
2113              formatters: Vec<Option<Box<dyn Fn(&str) -> String>>>| {
2114                 if let Some(MissingLifetimeSpot::HigherRanked { span: for_span, span_type }) =
2115                     self.missing_named_lifetime_spots.iter().rev().next()
2116                 {
2117                     // When we have `struct S<'a>(&'a dyn Fn(&X) -> &X);` we want to not only suggest
2118                     // using `'a`, but also introduce the concept of HRLTs by suggesting
2119                     // `struct S<'a>(&'a dyn for<'b> Fn(&X) -> &'b X);`. (#72404)
2120                     let mut introduce_suggestion = vec![];
2121
2122                     let a_to_z_repeat_n = |n| {
2123                         (b'a'..=b'z').map(move |c| {
2124                             let mut s = '\''.to_string();
2125                             s.extend(std::iter::repeat(char::from(c)).take(n));
2126                             s
2127                         })
2128                     };
2129
2130                     // If all single char lifetime names are present, we wrap around and double the chars.
2131                     let lt_name = (1..)
2132                         .flat_map(a_to_z_repeat_n)
2133                         .find(|lt| !lifetime_names.contains(&Symbol::intern(&lt)))
2134                         .unwrap();
2135                     let msg = format!(
2136                         "consider making the {} lifetime-generic with a new `{}` lifetime",
2137                         span_type.descr(),
2138                         lt_name,
2139                     );
2140                     err.note(
2141                         "for more information on higher-ranked polymorphism, visit \
2142                     https://doc.rust-lang.org/nomicon/hrtb.html",
2143                     );
2144                     let for_sugg = span_type.suggestion(&lt_name);
2145                     for param in params {
2146                         if let Ok(snippet) = self.tcx.sess.source_map().span_to_snippet(param.span)
2147                         {
2148                             if snippet.starts_with('&') && !snippet.starts_with("&'") {
2149                                 introduce_suggestion
2150                                     .push((param.span, format!("&{} {}", lt_name, &snippet[1..])));
2151                             } else if let Some(stripped) = snippet.strip_prefix("&'_ ") {
2152                                 introduce_suggestion
2153                                     .push((param.span, format!("&{} {}", lt_name, stripped)));
2154                             }
2155                         }
2156                     }
2157                     introduce_suggestion.push((*for_span, for_sugg));
2158                     for ((span, _), formatter) in spans_with_counts.iter().zip(formatters.iter()) {
2159                         if let Some(formatter) = formatter {
2160                             introduce_suggestion.push((*span, formatter(&lt_name)));
2161                         }
2162                     }
2163                     err.multipart_suggestion_verbose(
2164                         &msg,
2165                         introduce_suggestion,
2166                         Applicability::MaybeIncorrect,
2167                     );
2168                 }
2169
2170                 let spans_suggs: Vec<_> = formatters
2171                     .into_iter()
2172                     .zip(spans_with_counts.iter())
2173                     .filter_map(|(formatter, (span, _))| {
2174                         if let Some(formatter) = formatter {
2175                             Some((*span, formatter(name)))
2176                         } else {
2177                             None
2178                         }
2179                     })
2180                     .collect();
2181                 if spans_suggs.is_empty() {
2182                     // If all the spans come from macros, we cannot extract snippets and then
2183                     // `formatters` only contains None and `spans_suggs` is empty.
2184                     return;
2185                 }
2186                 err.multipart_suggestion_verbose(
2187                     &format!(
2188                         "consider using the `{}` lifetime",
2189                         lifetime_names.iter().next().unwrap()
2190                     ),
2191                     spans_suggs,
2192                     Applicability::MaybeIncorrect,
2193                 );
2194             };
2195         let suggest_new = |err: &mut Diagnostic, suggs: Vec<Option<String>>| {
2196             for missing in self.missing_named_lifetime_spots.iter().rev() {
2197                 let mut introduce_suggestion = vec![];
2198                 let msg;
2199                 let should_break;
2200                 introduce_suggestion.push(match missing {
2201                     MissingLifetimeSpot::Generics(generics) => {
2202                         if generics.span == DUMMY_SP {
2203                             // Account for malformed generics in the HIR. This shouldn't happen,
2204                             // but if we make a mistake elsewhere, mainly by keeping something in
2205                             // `missing_named_lifetime_spots` that we shouldn't, like associated
2206                             // `const`s or making a mistake in the AST lowering we would provide
2207                             // nonsensical suggestions. Guard against that by skipping these.
2208                             // (#74264)
2209                             continue;
2210                         }
2211                         msg = "consider introducing a named lifetime parameter".to_string();
2212                         should_break = true;
2213                         if let Some(param) = generics.params.iter().find(|p| {
2214                             !matches!(
2215                                 p.kind,
2216                                 hir::GenericParamKind::Type { synthetic: true, .. }
2217                                     | hir::GenericParamKind::Lifetime {
2218                                         kind: hir::LifetimeParamKind::Elided
2219                                     }
2220                             )
2221                         }) {
2222                             (param.span.shrink_to_lo(), "'a, ".to_string())
2223                         } else {
2224                             (generics.span, "<'a>".to_string())
2225                         }
2226                     }
2227                     MissingLifetimeSpot::HigherRanked { span, span_type } => {
2228                         msg = format!(
2229                             "consider making the {} lifetime-generic with a new `'a` lifetime",
2230                             span_type.descr(),
2231                         );
2232                         should_break = false;
2233                         err.note(
2234                             "for more information on higher-ranked polymorphism, visit \
2235                             https://doc.rust-lang.org/nomicon/hrtb.html",
2236                         );
2237                         (*span, span_type.suggestion("'a"))
2238                     }
2239                     MissingLifetimeSpot::Static => {
2240                         let mut spans_suggs = Vec::new();
2241                         for ((span, count), snippet) in
2242                             spans_with_counts.iter().copied().zip(snippets.iter())
2243                         {
2244                             let (span, sugg) = match snippet.as_deref() {
2245                                 Some("&") => (span.shrink_to_hi(), "'static ".to_owned()),
2246                                 Some("'_") => (span, "'static".to_owned()),
2247                                 Some(snippet) if !snippet.ends_with('>') => {
2248                                     if snippet == "" {
2249                                         (
2250                                             span,
2251                                             std::iter::repeat("'static")
2252                                                 .take(count)
2253                                                 .collect::<Vec<_>>()
2254                                                 .join(", "),
2255                                         )
2256                                     } else if snippet == "<" || snippet == "(" {
2257                                         (
2258                                             span.shrink_to_hi(),
2259                                             std::iter::repeat("'static")
2260                                                 .take(count)
2261                                                 .collect::<Vec<_>>()
2262                                                 .join(", "),
2263                                         )
2264                                     } else {
2265                                         (
2266                                             span.shrink_to_hi(),
2267                                             format!(
2268                                                 "<{}>",
2269                                                 std::iter::repeat("'static")
2270                                                     .take(count)
2271                                                     .collect::<Vec<_>>()
2272                                                     .join(", "),
2273                                             ),
2274                                         )
2275                                     }
2276                                 }
2277                                 _ => continue,
2278                             };
2279                             spans_suggs.push((span, sugg.to_string()));
2280                         }
2281                         err.multipart_suggestion_verbose(
2282                             "consider using the `'static` lifetime",
2283                             spans_suggs,
2284                             Applicability::MaybeIncorrect,
2285                         );
2286                         continue;
2287                     }
2288                 });
2289
2290                 struct Lifetime(Span, String);
2291                 impl Lifetime {
2292                     fn is_unnamed(&self) -> bool {
2293                         self.1.starts_with('&') && !self.1.starts_with("&'")
2294                     }
2295                     fn is_underscore(&self) -> bool {
2296                         self.1.starts_with("&'_ ")
2297                     }
2298                     fn is_named(&self) -> bool {
2299                         self.1.starts_with("&'")
2300                     }
2301                     fn suggestion(&self, sugg: String) -> Option<(Span, String)> {
2302                         Some(
2303                             match (
2304                                 self.is_unnamed(),
2305                                 self.is_underscore(),
2306                                 self.is_named(),
2307                                 sugg.starts_with('&'),
2308                             ) {
2309                                 (true, _, _, false) => (self.span_unnamed_borrow(), sugg),
2310                                 (true, _, _, true) => {
2311                                     (self.span_unnamed_borrow(), sugg[1..].to_string())
2312                                 }
2313                                 (_, true, _, false) => {
2314                                     (self.span_underscore_borrow(), sugg.trim().to_string())
2315                                 }
2316                                 (_, true, _, true) => {
2317                                     (self.span_underscore_borrow(), sugg[1..].trim().to_string())
2318                                 }
2319                                 (_, _, true, false) => {
2320                                     (self.span_named_borrow(), sugg.trim().to_string())
2321                                 }
2322                                 (_, _, true, true) => {
2323                                     (self.span_named_borrow(), sugg[1..].trim().to_string())
2324                                 }
2325                                 _ => return None,
2326                             },
2327                         )
2328                     }
2329                     fn span_unnamed_borrow(&self) -> Span {
2330                         let lo = self.0.lo() + BytePos(1);
2331                         self.0.with_lo(lo).with_hi(lo)
2332                     }
2333                     fn span_named_borrow(&self) -> Span {
2334                         let lo = self.0.lo() + BytePos(1);
2335                         self.0.with_lo(lo)
2336                     }
2337                     fn span_underscore_borrow(&self) -> Span {
2338                         let lo = self.0.lo() + BytePos(1);
2339                         let hi = lo + BytePos(2);
2340                         self.0.with_lo(lo).with_hi(hi)
2341                     }
2342                 }
2343
2344                 for param in params {
2345                     if let Ok(snippet) = self.tcx.sess.source_map().span_to_snippet(param.span) {
2346                         if let Some((span, sugg)) =
2347                             Lifetime(param.span, snippet).suggestion("'a ".to_string())
2348                         {
2349                             introduce_suggestion.push((span, sugg));
2350                         }
2351                     }
2352                 }
2353                 for (span, sugg) in spans_with_counts.iter().copied().zip(suggs.iter()).filter_map(
2354                     |((span, _), sugg)| match &sugg {
2355                         Some(sugg) => Some((span, sugg.to_string())),
2356                         _ => None,
2357                     },
2358                 ) {
2359                     let (span, sugg) = self
2360                         .tcx
2361                         .sess
2362                         .source_map()
2363                         .span_to_snippet(span)
2364                         .ok()
2365                         .and_then(|snippet| Lifetime(span, snippet).suggestion(sugg.clone()))
2366                         .unwrap_or((span, sugg));
2367                     introduce_suggestion.push((span, sugg.to_string()));
2368                 }
2369                 err.multipart_suggestion_verbose(
2370                     &msg,
2371                     introduce_suggestion,
2372                     Applicability::MaybeIncorrect,
2373                 );
2374                 if should_break {
2375                     break;
2376                 }
2377             }
2378         };
2379
2380         let lifetime_names: Vec<_> = lifetime_names.iter().collect();
2381         match &lifetime_names[..] {
2382             [name] => {
2383                 let mut suggs: Vec<Option<Box<dyn Fn(&str) -> String>>> = Vec::new();
2384                 for (snippet, (_, count)) in snippets.iter().zip(spans_with_counts.iter().copied())
2385                 {
2386                     suggs.push(match snippet.as_deref() {
2387                         Some("&") => Some(Box::new(|name| format!("&{} ", name))),
2388                         Some("'_") => Some(Box::new(|n| n.to_string())),
2389                         Some("") => Some(Box::new(move |n| format!("{}, ", n).repeat(count))),
2390                         Some("<") => Some(Box::new(move |n| {
2391                             std::iter::repeat(n).take(count).collect::<Vec<_>>().join(", ")
2392                         })),
2393                         Some(snippet) if !snippet.ends_with('>') => Some(Box::new(move |name| {
2394                             format!(
2395                                 "{}<{}>",
2396                                 snippet,
2397                                 std::iter::repeat(name.to_string())
2398                                     .take(count)
2399                                     .collect::<Vec<_>>()
2400                                     .join(", ")
2401                             )
2402                         })),
2403                         _ => None,
2404                     });
2405                 }
2406                 suggest_existing(err, name.as_str(), suggs);
2407             }
2408             [] => {
2409                 let mut suggs = Vec::new();
2410                 for (snippet, (_, count)) in
2411                     snippets.iter().cloned().zip(spans_with_counts.iter().copied())
2412                 {
2413                     suggs.push(match snippet.as_deref() {
2414                         Some("&") => Some("&'a ".to_string()),
2415                         Some("'_") => Some("'a".to_string()),
2416                         Some("") => {
2417                             Some(std::iter::repeat("'a, ").take(count).collect::<Vec<_>>().join(""))
2418                         }
2419                         Some("<") => {
2420                             Some(std::iter::repeat("'a").take(count).collect::<Vec<_>>().join(", "))
2421                         }
2422                         Some(snippet) => Some(format!(
2423                             "{}<{}>",
2424                             snippet,
2425                             std::iter::repeat("'a").take(count).collect::<Vec<_>>().join(", "),
2426                         )),
2427                         None => None,
2428                     });
2429                 }
2430                 suggest_new(err, suggs);
2431             }
2432             lts if lts.len() > 1 => {
2433                 err.span_note(lifetime_spans, "these named lifetimes are available to use");
2434
2435                 let mut spans_suggs: Vec<_> = Vec::new();
2436                 for ((span, _), snippet) in spans_with_counts.iter().copied().zip(snippets.iter()) {
2437                     match snippet.as_deref() {
2438                         Some("") => spans_suggs.push((span, "'lifetime, ".to_string())),
2439                         Some("&") => spans_suggs
2440                             .push((span.with_lo(span.lo() + BytePos(1)), "'lifetime ".to_string())),
2441                         _ => {}
2442                     }
2443                 }
2444
2445                 if spans_suggs.len() > 0 {
2446                     // This happens when we have `Foo<T>` where we point at the space before `T`,
2447                     // but this can be confusing so we give a suggestion with placeholders.
2448                     err.multipart_suggestion_verbose(
2449                         "consider using one of the available lifetimes here",
2450                         spans_suggs,
2451                         Applicability::HasPlaceholders,
2452                     );
2453                 }
2454             }
2455             _ => unreachable!(),
2456         }
2457     }
2458 }