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