]> git.lizzy.rs Git - rust.git/blob - src/librustc_resolve/late/diagnostics.rs
9dbde5e7852902253caeea24071589adbacdc80f
[rust.git] / src / librustc_resolve / late / diagnostics.rs
1 use crate::diagnostics::{ImportSuggestion, LabelSuggestion, TypoSuggestion};
2 use crate::late::lifetimes::{ElisionFailureInfo, LifetimeContext};
3 use crate::late::{LateResolutionVisitor, RibKind};
4 use crate::path_names_to_string;
5 use crate::{CrateLint, Module, ModuleKind, ModuleOrUniformRoot};
6 use crate::{PathResult, PathSource, Segment};
7
8 use rustc_ast::ast::{self, Expr, ExprKind, Item, ItemKind, NodeId, Path, Ty, TyKind};
9 use rustc_ast::util::lev_distance::find_best_match_for_name;
10 use rustc_data_structures::fx::FxHashSet;
11 use rustc_errors::{pluralize, struct_span_err, Applicability, DiagnosticBuilder};
12 use rustc_hir as hir;
13 use rustc_hir::def::Namespace::{self, *};
14 use rustc_hir::def::{self, CtorKind, DefKind};
15 use rustc_hir::def_id::{DefId, CRATE_DEF_INDEX, LOCAL_CRATE};
16 use rustc_hir::PrimTy;
17 use rustc_session::config::nightly_options;
18 use rustc_span::hygiene::MacroKind;
19 use rustc_span::symbol::{kw, sym, Ident, Symbol};
20 use rustc_span::{BytePos, Span, DUMMY_SP};
21
22 use log::debug;
23
24 type Res = def::Res<ast::NodeId>;
25
26 /// A field or associated item from self type suggested in case of resolution failure.
27 enum AssocSuggestion {
28     Field,
29     MethodWithSelf,
30     AssocItem,
31 }
32
33 crate enum MissingLifetimeSpot<'tcx> {
34     Generics(&'tcx hir::Generics<'tcx>),
35     HigherRanked { span: Span, span_type: ForLifetimeSpanType },
36 }
37
38 crate enum ForLifetimeSpanType {
39     BoundEmpty,
40     BoundTail,
41     TypeEmpty,
42     TypeTail,
43 }
44
45 impl ForLifetimeSpanType {
46     crate fn descr(&self) -> &'static str {
47         match self {
48             Self::BoundEmpty | Self::BoundTail => "bound",
49             Self::TypeEmpty | Self::TypeTail => "type",
50         }
51     }
52
53     crate fn suggestion(&self, sugg: &str) -> String {
54         match self {
55             Self::BoundEmpty | Self::TypeEmpty => format!("for<{}> ", sugg),
56             Self::BoundTail | Self::TypeTail => format!(", {}", sugg),
57         }
58     }
59 }
60
61 impl<'tcx> Into<MissingLifetimeSpot<'tcx>> for &'tcx hir::Generics<'tcx> {
62     fn into(self) -> MissingLifetimeSpot<'tcx> {
63         MissingLifetimeSpot::Generics(self)
64     }
65 }
66
67 fn is_self_type(path: &[Segment], namespace: Namespace) -> bool {
68     namespace == TypeNS && path.len() == 1 && path[0].ident.name == kw::SelfUpper
69 }
70
71 fn is_self_value(path: &[Segment], namespace: Namespace) -> bool {
72     namespace == ValueNS && path.len() == 1 && path[0].ident.name == kw::SelfLower
73 }
74
75 /// Gets the stringified path for an enum from an `ImportSuggestion` for an enum variant.
76 fn import_candidate_to_enum_paths(suggestion: &ImportSuggestion) -> (String, String) {
77     let variant_path = &suggestion.path;
78     let variant_path_string = path_names_to_string(variant_path);
79
80     let path_len = suggestion.path.segments.len();
81     let enum_path = ast::Path {
82         span: suggestion.path.span,
83         segments: suggestion.path.segments[0..path_len - 1].to_vec(),
84     };
85     let enum_path_string = path_names_to_string(&enum_path);
86
87     (variant_path_string, enum_path_string)
88 }
89
90 impl<'a> LateResolutionVisitor<'a, '_, '_> {
91     fn def_span(&self, def_id: DefId) -> Option<Span> {
92         match def_id.krate {
93             LOCAL_CRATE => self.r.opt_span(def_id),
94             _ => Some(
95                 self.r
96                     .session
97                     .source_map()
98                     .guess_head_span(self.r.cstore().get_span_untracked(def_id, self.r.session)),
99             ),
100         }
101     }
102
103     /// Handles error reporting for `smart_resolve_path_fragment` function.
104     /// Creates base error and amends it with one short label and possibly some longer helps/notes.
105     pub(crate) fn smart_resolve_report_errors(
106         &mut self,
107         path: &[Segment],
108         span: Span,
109         source: PathSource<'_>,
110         res: Option<Res>,
111     ) -> (DiagnosticBuilder<'a>, Vec<ImportSuggestion>) {
112         let ident_span = path.last().map_or(span, |ident| ident.ident.span);
113         let ns = source.namespace();
114         let is_expected = &|res| source.is_expected(res);
115         let is_enum_variant = &|res| matches!(res, Res::Def(DefKind::Variant, _));
116
117         // Make the base error.
118         let expected = source.descr_expected();
119         let path_str = Segment::names_to_string(path);
120         let item_str = path.last().unwrap().ident;
121         let (base_msg, fallback_label, base_span, could_be_expr) = if let Some(res) = res {
122             (
123                 format!("expected {}, found {} `{}`", expected, res.descr(), path_str),
124                 format!("not a {}", expected),
125                 span,
126                 match res {
127                     Res::Def(DefKind::Fn, _) => {
128                         // Verify whether this is a fn call or an Fn used as a type.
129                         self.r
130                             .session
131                             .source_map()
132                             .span_to_snippet(span)
133                             .map(|snippet| snippet.ends_with(')'))
134                             .unwrap_or(false)
135                     }
136                     Res::Def(
137                         DefKind::Ctor(..) | DefKind::AssocFn | DefKind::Const | DefKind::AssocConst,
138                         _,
139                     )
140                     | Res::SelfCtor(_)
141                     | Res::PrimTy(_)
142                     | Res::Local(_) => true,
143                     _ => false,
144                 },
145             )
146         } else {
147             let item_span = path.last().unwrap().ident.span;
148             let (mod_prefix, mod_str) = if path.len() == 1 {
149                 (String::new(), "this scope".to_string())
150             } else if path.len() == 2 && path[0].ident.name == kw::PathRoot {
151                 (String::new(), "the crate root".to_string())
152             } else {
153                 let mod_path = &path[..path.len() - 1];
154                 let mod_prefix =
155                     match self.resolve_path(mod_path, Some(TypeNS), false, span, CrateLint::No) {
156                         PathResult::Module(ModuleOrUniformRoot::Module(module)) => module.res(),
157                         _ => None,
158                     }
159                     .map_or(String::new(), |res| format!("{} ", res.descr()));
160                 (mod_prefix, format!("`{}`", Segment::names_to_string(mod_path)))
161             };
162             (
163                 format!("cannot find {} `{}` in {}{}", expected, item_str, mod_prefix, mod_str),
164                 if path_str == "async" && expected.starts_with("struct") {
165                     "`async` blocks are only allowed in the 2018 edition".to_string()
166                 } else {
167                     format!("not found in {}", mod_str)
168                 },
169                 item_span,
170                 false,
171             )
172         };
173
174         let code = source.error_code(res.is_some());
175         let mut err = self.r.session.struct_span_err_with_code(base_span, &base_msg, code);
176
177         // Emit help message for fake-self from other languages (e.g., `this` in Javascript).
178         if ["this", "my"].contains(&&*item_str.as_str())
179             && self.self_value_is_available(path[0].ident.span, span)
180         {
181             err.span_suggestion_short(
182                 span,
183                 "you might have meant to use `self` here instead",
184                 "self".to_string(),
185                 Applicability::MaybeIncorrect,
186             );
187         }
188
189         // Emit special messages for unresolved `Self` and `self`.
190         if is_self_type(path, ns) {
191             err.code(rustc_errors::error_code!(E0411));
192             err.span_label(
193                 span,
194                 "`Self` is only available in impls, traits, and type definitions".to_string(),
195             );
196             return (err, Vec::new());
197         }
198         if is_self_value(path, ns) {
199             debug!("smart_resolve_path_fragment: E0424, source={:?}", source);
200
201             err.code(rustc_errors::error_code!(E0424));
202             err.span_label(span, match source {
203                 PathSource::Pat => "`self` value is a keyword and may not be bound to variables or shadowed"
204                                    .to_string(),
205                 _ => "`self` value is a keyword only available in methods with a `self` parameter"
206                      .to_string(),
207             });
208             if let Some((fn_kind, span)) = &self.diagnostic_metadata.current_function {
209                 // The current function has a `self' parameter, but we were unable to resolve
210                 // a reference to `self`. This can only happen if the `self` identifier we
211                 // are resolving came from a different hygiene context.
212                 if fn_kind.decl().inputs.get(0).map(|p| p.is_self()).unwrap_or(false) {
213                     err.span_label(*span, "this function has a `self` parameter, but a macro invocation can only access identifiers it receives from parameters");
214                 } else {
215                     err.span_label(*span, "this function doesn't have a `self` parameter");
216                 }
217             }
218             return (err, Vec::new());
219         }
220
221         // Try to lookup name in more relaxed fashion for better error reporting.
222         let ident = path.last().unwrap().ident;
223         let candidates = self
224             .r
225             .lookup_import_candidates(ident, ns, &self.parent_scope, is_expected)
226             .drain(..)
227             .filter(|ImportSuggestion { did, .. }| {
228                 match (did, res.and_then(|res| res.opt_def_id())) {
229                     (Some(suggestion_did), Some(actual_did)) => *suggestion_did != actual_did,
230                     _ => true,
231                 }
232             })
233             .collect::<Vec<_>>();
234         let crate_def_id = DefId::local(CRATE_DEF_INDEX);
235         if candidates.is_empty() && is_expected(Res::Def(DefKind::Enum, crate_def_id)) {
236             let enum_candidates =
237                 self.r.lookup_import_candidates(ident, ns, &self.parent_scope, is_enum_variant);
238
239             if !enum_candidates.is_empty() {
240                 if let (PathSource::Type, Some(span)) =
241                     (source, self.diagnostic_metadata.current_type_ascription.last())
242                 {
243                     if self
244                         .r
245                         .session
246                         .parse_sess
247                         .type_ascription_path_suggestions
248                         .borrow()
249                         .contains(span)
250                     {
251                         // Already reported this issue on the lhs of the type ascription.
252                         err.delay_as_bug();
253                         return (err, candidates);
254                     }
255                 }
256
257                 let mut enum_candidates = enum_candidates
258                     .iter()
259                     .map(|suggestion| import_candidate_to_enum_paths(&suggestion))
260                     .collect::<Vec<_>>();
261                 enum_candidates.sort();
262
263                 // Contextualize for E0412 "cannot find type", but don't belabor the point
264                 // (that it's a variant) for E0573 "expected type, found variant".
265                 let preamble = if res.is_none() {
266                     let others = match enum_candidates.len() {
267                         1 => String::new(),
268                         2 => " and 1 other".to_owned(),
269                         n => format!(" and {} others", n),
270                     };
271                     format!("there is an enum variant `{}`{}; ", enum_candidates[0].0, others)
272                 } else {
273                     String::new()
274                 };
275                 let msg = format!("{}try using the variant's enum", preamble);
276
277                 err.span_suggestions(
278                     span,
279                     &msg,
280                     enum_candidates
281                         .into_iter()
282                         .map(|(_variant_path, enum_ty_path)| enum_ty_path)
283                         // Variants re-exported in prelude doesn't mean `prelude::v1` is the
284                         // type name!
285                         // FIXME: is there a more principled way to do this that
286                         // would work for other re-exports?
287                         .filter(|enum_ty_path| enum_ty_path != "std::prelude::v1")
288                         // Also write `Option` rather than `std::prelude::v1::Option`.
289                         .map(|enum_ty_path| {
290                             // FIXME #56861: DRY-er prelude filtering.
291                             enum_ty_path.trim_start_matches("std::prelude::v1::").to_owned()
292                         }),
293                     Applicability::MachineApplicable,
294                 );
295             }
296         }
297         if path.len() == 1 && self.self_type_is_available(span) {
298             if let Some(candidate) = self.lookup_assoc_candidate(ident, ns, is_expected) {
299                 let self_is_available = self.self_value_is_available(path[0].ident.span, span);
300                 match candidate {
301                     AssocSuggestion::Field => {
302                         if self_is_available {
303                             err.span_suggestion(
304                                 span,
305                                 "you might have meant to use the available field",
306                                 format!("self.{}", path_str),
307                                 Applicability::MachineApplicable,
308                             );
309                         } else {
310                             err.span_label(span, "a field by this name exists in `Self`");
311                         }
312                     }
313                     AssocSuggestion::MethodWithSelf if self_is_available => {
314                         err.span_suggestion(
315                             span,
316                             "try",
317                             format!("self.{}", path_str),
318                             Applicability::MachineApplicable,
319                         );
320                     }
321                     AssocSuggestion::MethodWithSelf | AssocSuggestion::AssocItem => {
322                         err.span_suggestion(
323                             span,
324                             "try",
325                             format!("Self::{}", path_str),
326                             Applicability::MachineApplicable,
327                         );
328                     }
329                 }
330                 return (err, candidates);
331             }
332
333             // If the first argument in call is `self` suggest calling a method.
334             if let Some((call_span, args_span)) = self.call_has_self_arg(source) {
335                 let mut args_snippet = String::new();
336                 if let Some(args_span) = args_span {
337                     if let Ok(snippet) = self.r.session.source_map().span_to_snippet(args_span) {
338                         args_snippet = snippet;
339                     }
340                 }
341
342                 err.span_suggestion(
343                     call_span,
344                     &format!("try calling `{}` as a method", ident),
345                     format!("self.{}({})", path_str, args_snippet),
346                     Applicability::MachineApplicable,
347                 );
348                 return (err, candidates);
349             }
350         }
351
352         // Try Levenshtein algorithm.
353         let typo_sugg = self.lookup_typo_candidate(path, ns, is_expected, span);
354         // Try context-dependent help if relaxed lookup didn't work.
355         if let Some(res) = res {
356             if self.smart_resolve_context_dependent_help(
357                 &mut err,
358                 span,
359                 source,
360                 res,
361                 &path_str,
362                 &fallback_label,
363             ) {
364                 // We do this to avoid losing a secondary span when we override the main error span.
365                 self.r.add_typo_suggestion(&mut err, typo_sugg, ident_span);
366                 return (err, candidates);
367             }
368         }
369
370         if !self.type_ascription_suggestion(&mut err, base_span)
371             && !self.r.add_typo_suggestion(&mut err, typo_sugg, ident_span)
372         {
373             // Fallback label.
374             err.span_label(base_span, fallback_label);
375
376             match self.diagnostic_metadata.current_let_binding {
377                 Some((pat_sp, Some(ty_sp), None)) if ty_sp.contains(base_span) && could_be_expr => {
378                     err.span_suggestion_short(
379                         pat_sp.between(ty_sp),
380                         "use `=` if you meant to assign",
381                         " = ".to_string(),
382                         Applicability::MaybeIncorrect,
383                     );
384                 }
385                 _ => {}
386             }
387         }
388         (err, candidates)
389     }
390
391     /// Check if the source is call expression and the first argument is `self`. If true,
392     /// return the span of whole call and the span for all arguments expect the first one (`self`).
393     fn call_has_self_arg(&self, source: PathSource<'_>) -> Option<(Span, Option<Span>)> {
394         let mut has_self_arg = None;
395         if let PathSource::Expr(Some(parent)) = source {
396             match &parent.kind {
397                 ExprKind::Call(_, args) if !args.is_empty() => {
398                     let mut expr_kind = &args[0].kind;
399                     loop {
400                         match expr_kind {
401                             ExprKind::Path(_, arg_name) if arg_name.segments.len() == 1 => {
402                                 if arg_name.segments[0].ident.name == kw::SelfLower {
403                                     let call_span = parent.span;
404                                     let tail_args_span = if args.len() > 1 {
405                                         Some(Span::new(
406                                             args[1].span.lo(),
407                                             args.last().unwrap().span.hi(),
408                                             call_span.ctxt(),
409                                         ))
410                                     } else {
411                                         None
412                                     };
413                                     has_self_arg = Some((call_span, tail_args_span));
414                                 }
415                                 break;
416                             }
417                             ExprKind::AddrOf(_, _, expr) => expr_kind = &expr.kind,
418                             _ => break,
419                         }
420                     }
421                 }
422                 _ => (),
423             }
424         };
425         has_self_arg
426     }
427
428     fn followed_by_brace(&self, span: Span) -> (bool, Option<Span>) {
429         // HACK(estebank): find a better way to figure out that this was a
430         // parser issue where a struct literal is being used on an expression
431         // where a brace being opened means a block is being started. Look
432         // ahead for the next text to see if `span` is followed by a `{`.
433         let sm = self.r.session.source_map();
434         let mut sp = span;
435         loop {
436             sp = sm.next_point(sp);
437             match sm.span_to_snippet(sp) {
438                 Ok(ref snippet) => {
439                     if snippet.chars().any(|c| !c.is_whitespace()) {
440                         break;
441                     }
442                 }
443                 _ => break,
444             }
445         }
446         let followed_by_brace = match sm.span_to_snippet(sp) {
447             Ok(ref snippet) if snippet == "{" => true,
448             _ => false,
449         };
450         // In case this could be a struct literal that needs to be surrounded
451         // by parentheses, find the appropriate span.
452         let mut i = 0;
453         let mut closing_brace = None;
454         loop {
455             sp = sm.next_point(sp);
456             match sm.span_to_snippet(sp) {
457                 Ok(ref snippet) => {
458                     if snippet == "}" {
459                         closing_brace = Some(span.to(sp));
460                         break;
461                     }
462                 }
463                 _ => break,
464             }
465             i += 1;
466             // The bigger the span, the more likely we're incorrect --
467             // bound it to 100 chars long.
468             if i > 100 {
469                 break;
470             }
471         }
472         (followed_by_brace, closing_brace)
473     }
474
475     /// Provides context-dependent help for errors reported by the `smart_resolve_path_fragment`
476     /// function.
477     /// Returns `true` if able to provide context-dependent help.
478     fn smart_resolve_context_dependent_help(
479         &mut self,
480         err: &mut DiagnosticBuilder<'a>,
481         span: Span,
482         source: PathSource<'_>,
483         res: Res,
484         path_str: &str,
485         fallback_label: &str,
486     ) -> bool {
487         let ns = source.namespace();
488         let is_expected = &|res| source.is_expected(res);
489
490         let path_sep = |err: &mut DiagnosticBuilder<'_>, expr: &Expr| match expr.kind {
491             ExprKind::Field(_, ident) => {
492                 err.span_suggestion(
493                     expr.span,
494                     "use the path separator to refer to an item",
495                     format!("{}::{}", path_str, ident),
496                     Applicability::MaybeIncorrect,
497                 );
498                 true
499             }
500             ExprKind::MethodCall(ref segment, ..) => {
501                 let span = expr.span.with_hi(segment.ident.span.hi());
502                 err.span_suggestion(
503                     span,
504                     "use the path separator to refer to an item",
505                     format!("{}::{}", path_str, segment.ident),
506                     Applicability::MaybeIncorrect,
507                 );
508                 true
509             }
510             _ => false,
511         };
512
513         let mut bad_struct_syntax_suggestion = |def_id: DefId| {
514             let (followed_by_brace, closing_brace) = self.followed_by_brace(span);
515
516             match source {
517                 PathSource::Expr(Some(
518                     parent @ Expr { kind: ExprKind::Field(..) | ExprKind::MethodCall(..), .. },
519                 )) if path_sep(err, &parent) => {}
520                 PathSource::Expr(
521                     None
522                     | Some(Expr {
523                         kind:
524                             ExprKind::Path(..)
525                             | ExprKind::Binary(..)
526                             | ExprKind::Unary(..)
527                             | ExprKind::If(..)
528                             | ExprKind::While(..)
529                             | ExprKind::ForLoop(..)
530                             | ExprKind::Match(..),
531                         ..
532                     }),
533                 ) if followed_by_brace => {
534                     if let Some(sp) = closing_brace {
535                         err.span_label(span, fallback_label);
536                         err.multipart_suggestion(
537                             "surround the struct literal with parentheses",
538                             vec![
539                                 (sp.shrink_to_lo(), "(".to_string()),
540                                 (sp.shrink_to_hi(), ")".to_string()),
541                             ],
542                             Applicability::MaybeIncorrect,
543                         );
544                     } else {
545                         err.span_label(
546                             span, // Note the parentheses surrounding the suggestion below
547                             format!(
548                                 "you might want to surround a struct literal with parentheses: \
549                                  `({} {{ /* fields */ }})`?",
550                                 path_str
551                             ),
552                         );
553                     }
554                 }
555                 PathSource::Expr(_) | PathSource::TupleStruct(_) | PathSource::Pat => {
556                     let span = match &source {
557                         PathSource::Expr(Some(Expr {
558                             span, kind: ExprKind::Call(_, _), ..
559                         }))
560                         | PathSource::TupleStruct(span) => {
561                             // We want the main underline to cover the suggested code as well for
562                             // cleaner output.
563                             err.set_span(*span);
564                             *span
565                         }
566                         _ => span,
567                     };
568                     if let Some(span) = self.def_span(def_id) {
569                         err.span_label(span, &format!("`{}` defined here", path_str));
570                     }
571                     let (tail, descr, applicability) = match source {
572                         PathSource::Pat | PathSource::TupleStruct(_) => {
573                             ("", "pattern", Applicability::MachineApplicable)
574                         }
575                         _ => (": val", "literal", Applicability::HasPlaceholders),
576                     };
577                     let (fields, applicability) = match self.r.field_names.get(&def_id) {
578                         Some(fields) => (
579                             fields
580                                 .iter()
581                                 .map(|f| format!("{}{}", f.node, tail))
582                                 .collect::<Vec<String>>()
583                                 .join(", "),
584                             applicability,
585                         ),
586                         None => ("/* fields */".to_string(), Applicability::HasPlaceholders),
587                     };
588                     let pad = match self.r.field_names.get(&def_id) {
589                         Some(fields) if fields.is_empty() => "",
590                         _ => " ",
591                     };
592                     err.span_suggestion(
593                         span,
594                         &format!("use struct {} syntax instead", descr),
595                         format!("{} {{{pad}{}{pad}}}", path_str, fields, pad = pad),
596                         applicability,
597                     );
598                 }
599                 _ => {
600                     err.span_label(span, fallback_label);
601                 }
602             }
603         };
604
605         match (res, source) {
606             (Res::Def(DefKind::Macro(MacroKind::Bang), _), _) => {
607                 err.span_label(span, fallback_label);
608                 err.span_suggestion_verbose(
609                     span.shrink_to_hi(),
610                     "use `!` to invoke the macro",
611                     "!".to_string(),
612                     Applicability::MaybeIncorrect,
613                 );
614                 if path_str == "try" && span.rust_2015() {
615                     err.note("if you want the `try` keyword, you need to be in the 2018 edition");
616                 }
617             }
618             (Res::Def(DefKind::TyAlias, def_id), PathSource::Trait(_)) => {
619                 err.span_label(span, "type aliases cannot be used as traits");
620                 if nightly_options::is_nightly_build() {
621                     let msg = "you might have meant to use `#![feature(trait_alias)]` instead of a \
622                                `type` alias";
623                     if let Some(span) = self.def_span(def_id) {
624                         err.span_help(span, msg);
625                     } else {
626                         err.help(msg);
627                     }
628                 }
629             }
630             (Res::Def(DefKind::Mod, _), PathSource::Expr(Some(parent))) => {
631                 if !path_sep(err, &parent) {
632                     return false;
633                 }
634             }
635             (
636                 Res::Def(DefKind::Enum, def_id),
637                 PathSource::TupleStruct(_) | PathSource::Expr(..),
638             ) => {
639                 if self
640                     .diagnostic_metadata
641                     .current_type_ascription
642                     .last()
643                     .map(|sp| {
644                         self.r
645                             .session
646                             .parse_sess
647                             .type_ascription_path_suggestions
648                             .borrow()
649                             .contains(&sp)
650                     })
651                     .unwrap_or(false)
652                 {
653                     err.delay_as_bug();
654                     // We already suggested changing `:` into `::` during parsing.
655                     return false;
656                 }
657                 if let Some(variants) = self.collect_enum_variants(def_id) {
658                     if !variants.is_empty() {
659                         let msg = if variants.len() == 1 {
660                             "try using the enum's variant"
661                         } else {
662                             "try using one of the enum's variants"
663                         };
664
665                         err.span_suggestions(
666                             span,
667                             msg,
668                             variants.iter().map(path_names_to_string),
669                             Applicability::MaybeIncorrect,
670                         );
671                     }
672                 } else {
673                     err.note("you might have meant to use one of the enum's variants");
674                 }
675             }
676             (Res::Def(DefKind::Struct, def_id), _) if ns == ValueNS => {
677                 if let Some((ctor_def, ctor_vis)) = self.r.struct_constructors.get(&def_id).cloned()
678                 {
679                     let accessible_ctor =
680                         self.r.is_accessible_from(ctor_vis, self.parent_scope.module);
681                     if is_expected(ctor_def) && !accessible_ctor {
682                         err.span_label(
683                             span,
684                             "constructor is not visible here due to private fields".to_string(),
685                         );
686                     }
687                 } else {
688                     bad_struct_syntax_suggestion(def_id);
689                 }
690             }
691             (
692                 Res::Def(
693                     DefKind::Union | DefKind::Variant | DefKind::Ctor(_, CtorKind::Fictive),
694                     def_id,
695                 ),
696                 _,
697             ) if ns == ValueNS => {
698                 bad_struct_syntax_suggestion(def_id);
699             }
700             (Res::Def(DefKind::Ctor(_, CtorKind::Fn), def_id), _) if ns == ValueNS => {
701                 if let Some(span) = self.def_span(def_id) {
702                     err.span_label(span, &format!("`{}` defined here", path_str));
703                 }
704                 err.span_label(span, format!("did you mean `{}( /* fields */ )`?", path_str));
705             }
706             (Res::SelfTy(..), _) if ns == ValueNS => {
707                 err.span_label(span, fallback_label);
708                 err.note("can't use `Self` as a constructor, you must use the implemented struct");
709             }
710             (Res::Def(DefKind::TyAlias | DefKind::AssocTy, _), _) if ns == ValueNS => {
711                 err.note("can't use a type alias as a constructor");
712             }
713             _ => return false,
714         }
715         true
716     }
717
718     fn lookup_assoc_candidate<FilterFn>(
719         &mut self,
720         ident: Ident,
721         ns: Namespace,
722         filter_fn: FilterFn,
723     ) -> Option<AssocSuggestion>
724     where
725         FilterFn: Fn(Res) -> bool,
726     {
727         fn extract_node_id(t: &Ty) -> Option<NodeId> {
728             match t.kind {
729                 TyKind::Path(None, _) => Some(t.id),
730                 TyKind::Rptr(_, ref mut_ty) => extract_node_id(&mut_ty.ty),
731                 // This doesn't handle the remaining `Ty` variants as they are not
732                 // that commonly the self_type, it might be interesting to provide
733                 // support for those in future.
734                 _ => None,
735             }
736         }
737
738         // Fields are generally expected in the same contexts as locals.
739         if filter_fn(Res::Local(ast::DUMMY_NODE_ID)) {
740             if let Some(node_id) =
741                 self.diagnostic_metadata.current_self_type.as_ref().and_then(extract_node_id)
742             {
743                 // Look for a field with the same name in the current self_type.
744                 if let Some(resolution) = self.r.partial_res_map.get(&node_id) {
745                     match resolution.base_res() {
746                         Res::Def(DefKind::Struct | DefKind::Union, did)
747                             if resolution.unresolved_segments() == 0 =>
748                         {
749                             if let Some(field_names) = self.r.field_names.get(&did) {
750                                 if field_names
751                                     .iter()
752                                     .any(|&field_name| ident.name == field_name.node)
753                                 {
754                                     return Some(AssocSuggestion::Field);
755                                 }
756                             }
757                         }
758                         _ => {}
759                     }
760                 }
761             }
762         }
763
764         for assoc_type_ident in &self.diagnostic_metadata.current_trait_assoc_types {
765             if *assoc_type_ident == ident {
766                 return Some(AssocSuggestion::AssocItem);
767             }
768         }
769
770         // Look for associated items in the current trait.
771         if let Some((module, _)) = self.current_trait_ref {
772             if let Ok(binding) = self.r.resolve_ident_in_module(
773                 ModuleOrUniformRoot::Module(module),
774                 ident,
775                 ns,
776                 &self.parent_scope,
777                 false,
778                 module.span,
779             ) {
780                 let res = binding.res();
781                 if filter_fn(res) {
782                     return Some(if self.r.has_self.contains(&res.def_id()) {
783                         AssocSuggestion::MethodWithSelf
784                     } else {
785                         AssocSuggestion::AssocItem
786                     });
787                 }
788             }
789         }
790
791         None
792     }
793
794     fn lookup_typo_candidate(
795         &mut self,
796         path: &[Segment],
797         ns: Namespace,
798         filter_fn: &impl Fn(Res) -> bool,
799         span: Span,
800     ) -> Option<TypoSuggestion> {
801         let mut names = Vec::new();
802         if path.len() == 1 {
803             // Search in lexical scope.
804             // Walk backwards up the ribs in scope and collect candidates.
805             for rib in self.ribs[ns].iter().rev() {
806                 // Locals and type parameters
807                 for (ident, &res) in &rib.bindings {
808                     if filter_fn(res) {
809                         names.push(TypoSuggestion::from_res(ident.name, res));
810                     }
811                 }
812                 // Items in scope
813                 if let RibKind::ModuleRibKind(module) = rib.kind {
814                     // Items from this module
815                     self.r.add_module_candidates(module, &mut names, &filter_fn);
816
817                     if let ModuleKind::Block(..) = module.kind {
818                         // We can see through blocks
819                     } else {
820                         // Items from the prelude
821                         if !module.no_implicit_prelude {
822                             let extern_prelude = self.r.extern_prelude.clone();
823                             names.extend(extern_prelude.iter().flat_map(|(ident, _)| {
824                                 self.r.crate_loader.maybe_process_path_extern(ident.name).and_then(
825                                     |crate_id| {
826                                         let crate_mod = Res::Def(
827                                             DefKind::Mod,
828                                             DefId { krate: crate_id, index: CRATE_DEF_INDEX },
829                                         );
830
831                                         if filter_fn(crate_mod) {
832                                             Some(TypoSuggestion::from_res(ident.name, crate_mod))
833                                         } else {
834                                             None
835                                         }
836                                     },
837                                 )
838                             }));
839
840                             if let Some(prelude) = self.r.prelude {
841                                 self.r.add_module_candidates(prelude, &mut names, &filter_fn);
842                             }
843                         }
844                         break;
845                     }
846                 }
847             }
848             // Add primitive types to the mix
849             if filter_fn(Res::PrimTy(PrimTy::Bool)) {
850                 names.extend(
851                     self.r.primitive_type_table.primitive_types.iter().map(|(name, prim_ty)| {
852                         TypoSuggestion::from_res(*name, Res::PrimTy(*prim_ty))
853                     }),
854                 )
855             }
856         } else {
857             // Search in module.
858             let mod_path = &path[..path.len() - 1];
859             if let PathResult::Module(module) =
860                 self.resolve_path(mod_path, Some(TypeNS), false, span, CrateLint::No)
861             {
862                 if let ModuleOrUniformRoot::Module(module) = module {
863                     self.r.add_module_candidates(module, &mut names, &filter_fn);
864                 }
865             }
866         }
867
868         let name = path[path.len() - 1].ident.name;
869         // Make sure error reporting is deterministic.
870         names.sort_by_cached_key(|suggestion| suggestion.candidate.as_str());
871
872         match find_best_match_for_name(
873             names.iter().map(|suggestion| &suggestion.candidate),
874             name,
875             None,
876         ) {
877             Some(found) if found != name => {
878                 names.into_iter().find(|suggestion| suggestion.candidate == found)
879             }
880             _ => None,
881         }
882     }
883
884     /// Only used in a specific case of type ascription suggestions
885     fn get_colon_suggestion_span(&self, start: Span) -> Span {
886         let sm = self.r.session.source_map();
887         start.to(sm.next_point(start))
888     }
889
890     fn type_ascription_suggestion(&self, err: &mut DiagnosticBuilder<'_>, base_span: Span) -> bool {
891         let sm = self.r.session.source_map();
892         let base_snippet = sm.span_to_snippet(base_span);
893         if let Some(&sp) = self.diagnostic_metadata.current_type_ascription.last() {
894             if let Ok(snippet) = sm.span_to_snippet(sp) {
895                 let len = snippet.trim_end().len() as u32;
896                 if snippet.trim() == ":" {
897                     let colon_sp =
898                         sp.with_lo(sp.lo() + BytePos(len - 1)).with_hi(sp.lo() + BytePos(len));
899                     let mut show_label = true;
900                     if sm.is_multiline(sp) {
901                         err.span_suggestion_short(
902                             colon_sp,
903                             "maybe you meant to write `;` here",
904                             ";".to_string(),
905                             Applicability::MaybeIncorrect,
906                         );
907                     } else {
908                         let after_colon_sp =
909                             self.get_colon_suggestion_span(colon_sp.shrink_to_hi());
910                         if snippet.len() == 1 {
911                             // `foo:bar`
912                             err.span_suggestion(
913                                 colon_sp,
914                                 "maybe you meant to write a path separator here",
915                                 "::".to_string(),
916                                 Applicability::MaybeIncorrect,
917                             );
918                             show_label = false;
919                             if !self
920                                 .r
921                                 .session
922                                 .parse_sess
923                                 .type_ascription_path_suggestions
924                                 .borrow_mut()
925                                 .insert(colon_sp)
926                             {
927                                 err.delay_as_bug();
928                             }
929                         }
930                         if let Ok(base_snippet) = base_snippet {
931                             let mut sp = after_colon_sp;
932                             for _ in 0..100 {
933                                 // Try to find an assignment
934                                 sp = sm.next_point(sp);
935                                 let snippet = sm.span_to_snippet(sp.to(sm.next_point(sp)));
936                                 match snippet {
937                                     Ok(ref x) if x.as_str() == "=" => {
938                                         err.span_suggestion(
939                                             base_span,
940                                             "maybe you meant to write an assignment here",
941                                             format!("let {}", base_snippet),
942                                             Applicability::MaybeIncorrect,
943                                         );
944                                         show_label = false;
945                                         break;
946                                     }
947                                     Ok(ref x) if x.as_str() == "\n" => break,
948                                     Err(_) => break,
949                                     Ok(_) => {}
950                                 }
951                             }
952                         }
953                     }
954                     if show_label {
955                         err.span_label(
956                             base_span,
957                             "expecting a type here because of type ascription",
958                         );
959                     }
960                     return show_label;
961                 }
962             }
963         }
964         false
965     }
966
967     fn find_module(&mut self, def_id: DefId) -> Option<(Module<'a>, ImportSuggestion)> {
968         let mut result = None;
969         let mut seen_modules = FxHashSet::default();
970         let mut worklist = vec![(self.r.graph_root, Vec::new())];
971
972         while let Some((in_module, path_segments)) = worklist.pop() {
973             // abort if the module is already found
974             if result.is_some() {
975                 break;
976             }
977
978             in_module.for_each_child(self.r, |_, ident, _, name_binding| {
979                 // abort if the module is already found or if name_binding is private external
980                 if result.is_some() || !name_binding.vis.is_visible_locally() {
981                     return;
982                 }
983                 if let Some(module) = name_binding.module() {
984                     // form the path
985                     let mut path_segments = path_segments.clone();
986                     path_segments.push(ast::PathSegment::from_ident(ident));
987                     let module_def_id = module.def_id().unwrap();
988                     if module_def_id == def_id {
989                         let path = Path { span: name_binding.span, segments: path_segments };
990                         result = Some((
991                             module,
992                             ImportSuggestion {
993                                 did: Some(def_id),
994                                 descr: "module",
995                                 path,
996                                 accessible: true,
997                             },
998                         ));
999                     } else {
1000                         // add the module to the lookup
1001                         if seen_modules.insert(module_def_id) {
1002                             worklist.push((module, path_segments));
1003                         }
1004                     }
1005                 }
1006             });
1007         }
1008
1009         result
1010     }
1011
1012     fn collect_enum_variants(&mut self, def_id: DefId) -> Option<Vec<Path>> {
1013         self.find_module(def_id).map(|(enum_module, enum_import_suggestion)| {
1014             let mut variants = Vec::new();
1015             enum_module.for_each_child(self.r, |_, ident, _, name_binding| {
1016                 if let Res::Def(DefKind::Variant, _) = name_binding.res() {
1017                     let mut segms = enum_import_suggestion.path.segments.clone();
1018                     segms.push(ast::PathSegment::from_ident(ident));
1019                     variants.push(Path { span: name_binding.span, segments: segms });
1020                 }
1021             });
1022             variants
1023         })
1024     }
1025
1026     crate fn report_missing_type_error(
1027         &self,
1028         path: &[Segment],
1029     ) -> Option<(Span, &'static str, String, Applicability)> {
1030         let (ident, span) = match path {
1031             [segment] if !segment.has_generic_args => {
1032                 (segment.ident.to_string(), segment.ident.span)
1033             }
1034             _ => return None,
1035         };
1036         let mut iter = ident.chars().map(|c| c.is_uppercase());
1037         let single_uppercase_char =
1038             matches!(iter.next(), Some(true)) && matches!(iter.next(), None);
1039         if !self.diagnostic_metadata.currently_processing_generics && !single_uppercase_char {
1040             return None;
1041         }
1042         match (self.diagnostic_metadata.current_item, single_uppercase_char) {
1043             (Some(Item { kind: ItemKind::Fn(..), ident, .. }), _) if ident.name == sym::main => {
1044                 // Ignore `fn main()` as we don't want to suggest `fn main<T>()`
1045             }
1046             (
1047                 Some(Item {
1048                     kind:
1049                         kind @ ItemKind::Fn(..)
1050                         | kind @ ItemKind::Enum(..)
1051                         | kind @ ItemKind::Struct(..)
1052                         | kind @ ItemKind::Union(..),
1053                     ..
1054                 }),
1055                 true,
1056             )
1057             | (Some(Item { kind, .. }), false) => {
1058                 // Likely missing type parameter.
1059                 if let Some(generics) = kind.generics() {
1060                     if span.overlaps(generics.span) {
1061                         // Avoid the following:
1062                         // error[E0405]: cannot find trait `A` in this scope
1063                         //  --> $DIR/typo-suggestion-named-underscore.rs:CC:LL
1064                         //   |
1065                         // L | fn foo<T: A>(x: T) {} // Shouldn't suggest underscore
1066                         //   |           ^- help: you might be missing a type parameter: `, A`
1067                         //   |           |
1068                         //   |           not found in this scope
1069                         return None;
1070                     }
1071                     let msg = "you might be missing a type parameter";
1072                     let (span, sugg) = if let [.., param] = &generics.params[..] {
1073                         let span = if let [.., bound] = &param.bounds[..] {
1074                             bound.span()
1075                         } else {
1076                             param.ident.span
1077                         };
1078                         (span, format!(", {}", ident))
1079                     } else {
1080                         (generics.span, format!("<{}>", ident))
1081                     };
1082                     // Do not suggest if this is coming from macro expansion.
1083                     if !span.from_expansion() {
1084                         return Some((
1085                             span.shrink_to_hi(),
1086                             msg,
1087                             sugg,
1088                             Applicability::MaybeIncorrect,
1089                         ));
1090                     }
1091                 }
1092             }
1093             _ => {}
1094         }
1095         None
1096     }
1097
1098     /// Given the target `label`, search the `rib_index`th label rib for similarly named labels,
1099     /// optionally returning the closest match and whether it is reachable.
1100     crate fn suggestion_for_label_in_rib(
1101         &self,
1102         rib_index: usize,
1103         label: Ident,
1104     ) -> Option<LabelSuggestion> {
1105         // Are ribs from this `rib_index` within scope?
1106         let within_scope = self.is_label_valid_from_rib(rib_index);
1107
1108         let rib = &self.label_ribs[rib_index];
1109         let names = rib
1110             .bindings
1111             .iter()
1112             .filter(|(id, _)| id.span.ctxt() == label.span.ctxt())
1113             .map(|(id, _)| &id.name);
1114
1115         find_best_match_for_name(names, label.name, None).map(|symbol| {
1116             // Upon finding a similar name, get the ident that it was from - the span
1117             // contained within helps make a useful diagnostic. In addition, determine
1118             // whether this candidate is within scope.
1119             let (ident, _) = rib.bindings.iter().find(|(ident, _)| ident.name == symbol).unwrap();
1120             (*ident, within_scope)
1121         })
1122     }
1123 }
1124
1125 impl<'tcx> LifetimeContext<'_, 'tcx> {
1126     crate fn report_missing_lifetime_specifiers(
1127         &self,
1128         span: Span,
1129         count: usize,
1130     ) -> DiagnosticBuilder<'tcx> {
1131         struct_span_err!(
1132             self.tcx.sess,
1133             span,
1134             E0106,
1135             "missing lifetime specifier{}",
1136             pluralize!(count)
1137         )
1138     }
1139
1140     crate fn emit_undeclared_lifetime_error(&self, lifetime_ref: &hir::Lifetime) {
1141         let mut err = struct_span_err!(
1142             self.tcx.sess,
1143             lifetime_ref.span,
1144             E0261,
1145             "use of undeclared lifetime name `{}`",
1146             lifetime_ref
1147         );
1148         err.span_label(lifetime_ref.span, "undeclared lifetime");
1149         let mut suggests_in_band = false;
1150         for missing in &self.missing_named_lifetime_spots {
1151             match missing {
1152                 MissingLifetimeSpot::Generics(generics) => {
1153                     let (span, sugg) = if let Some(param) =
1154                         generics.params.iter().find(|p| match p.kind {
1155                             hir::GenericParamKind::Type {
1156                                 synthetic: Some(hir::SyntheticTyParamKind::ImplTrait),
1157                                 ..
1158                             } => false,
1159                             _ => true,
1160                         }) {
1161                         (param.span.shrink_to_lo(), format!("{}, ", lifetime_ref))
1162                     } else {
1163                         suggests_in_band = true;
1164                         (generics.span, format!("<{}>", lifetime_ref))
1165                     };
1166                     err.span_suggestion(
1167                         span,
1168                         &format!("consider introducing lifetime `{}` here", lifetime_ref),
1169                         sugg,
1170                         Applicability::MaybeIncorrect,
1171                     );
1172                 }
1173                 MissingLifetimeSpot::HigherRanked { span, span_type } => {
1174                     err.span_suggestion(
1175                         *span,
1176                         &format!(
1177                             "consider making the {} lifetime-generic with a new `{}` lifetime",
1178                             span_type.descr(),
1179                             lifetime_ref
1180                         ),
1181                         span_type.suggestion(&lifetime_ref.to_string()),
1182                         Applicability::MaybeIncorrect,
1183                     );
1184                     err.note(
1185                         "for more information on higher-ranked polymorphism, visit \
1186                             https://doc.rust-lang.org/nomicon/hrtb.html",
1187                     );
1188                 }
1189             }
1190         }
1191         if nightly_options::is_nightly_build()
1192             && !self.tcx.features().in_band_lifetimes
1193             && suggests_in_band
1194         {
1195             err.help(
1196                 "if you want to experiment with in-band lifetime bindings, \
1197                     add `#![feature(in_band_lifetimes)]` to the crate attributes",
1198             );
1199         }
1200         err.emit();
1201     }
1202
1203     // FIXME(const_generics): This patches over a ICE caused by non-'static lifetimes in const
1204     // generics. We are disallowing this until we can decide on how we want to handle non-'static
1205     // lifetimes in const generics. See issue #74052 for discussion.
1206     crate fn emit_non_static_lt_in_const_generic_error(&self, lifetime_ref: &hir::Lifetime) {
1207         let mut err = struct_span_err!(
1208             self.tcx.sess,
1209             lifetime_ref.span,
1210             E0771,
1211             "use of non-static lifetime `{}` in const generic",
1212             lifetime_ref
1213         );
1214         err.note(
1215             "for more information, see issue #74052 \
1216             <https://github.com/rust-lang/rust/issues/74052>",
1217         );
1218         err.emit();
1219     }
1220
1221     crate fn is_trait_ref_fn_scope(&mut self, trait_ref: &'tcx hir::PolyTraitRef<'tcx>) -> bool {
1222         if let def::Res::Def(_, did) = trait_ref.trait_ref.path.res {
1223             if [
1224                 self.tcx.lang_items().fn_once_trait(),
1225                 self.tcx.lang_items().fn_trait(),
1226                 self.tcx.lang_items().fn_mut_trait(),
1227             ]
1228             .contains(&Some(did))
1229             {
1230                 let (span, span_type) = match &trait_ref.bound_generic_params {
1231                     [] => (trait_ref.span.shrink_to_lo(), ForLifetimeSpanType::BoundEmpty),
1232                     [.., bound] => (bound.span.shrink_to_hi(), ForLifetimeSpanType::BoundTail),
1233                 };
1234                 self.missing_named_lifetime_spots
1235                     .push(MissingLifetimeSpot::HigherRanked { span, span_type });
1236                 return true;
1237             }
1238         };
1239         false
1240     }
1241
1242     crate fn add_missing_lifetime_specifiers_label(
1243         &self,
1244         err: &mut DiagnosticBuilder<'_>,
1245         span: Span,
1246         count: usize,
1247         lifetime_names: &FxHashSet<Symbol>,
1248         lifetime_spans: Vec<Span>,
1249         params: &[ElisionFailureInfo],
1250     ) {
1251         let snippet = self.tcx.sess.source_map().span_to_snippet(span).ok();
1252
1253         err.span_label(
1254             span,
1255             &format!(
1256                 "expected {} lifetime parameter{}",
1257                 if count == 1 { "named".to_string() } else { count.to_string() },
1258                 pluralize!(count)
1259             ),
1260         );
1261
1262         let suggest_existing = |err: &mut DiagnosticBuilder<'_>,
1263                                 name: &str,
1264                                 formatter: &dyn Fn(&str) -> String| {
1265             if let Some(MissingLifetimeSpot::HigherRanked { span: for_span, span_type }) =
1266                 self.missing_named_lifetime_spots.iter().rev().next()
1267             {
1268                 // When we have `struct S<'a>(&'a dyn Fn(&X) -> &X);` we want to not only suggest
1269                 // using `'a`, but also introduce the concept of HRLTs by suggesting
1270                 // `struct S<'a>(&'a dyn for<'b> Fn(&X) -> &'b X);`. (#72404)
1271                 let mut introduce_suggestion = vec![];
1272
1273                 let a_to_z_repeat_n = |n| {
1274                     (b'a'..=b'z').map(move |c| {
1275                         let mut s = '\''.to_string();
1276                         s.extend(std::iter::repeat(char::from(c)).take(n));
1277                         s
1278                     })
1279                 };
1280
1281                 // If all single char lifetime names are present, we wrap around and double the chars.
1282                 let lt_name = (1..)
1283                     .flat_map(a_to_z_repeat_n)
1284                     .find(|lt| !lifetime_names.contains(&Symbol::intern(&lt)))
1285                     .unwrap();
1286                 let msg = format!(
1287                     "consider making the {} lifetime-generic with a new `{}` lifetime",
1288                     span_type.descr(),
1289                     lt_name,
1290                 );
1291                 err.note(
1292                     "for more information on higher-ranked polymorphism, visit \
1293                     https://doc.rust-lang.org/nomicon/hrtb.html",
1294                 );
1295                 let for_sugg = span_type.suggestion(&lt_name);
1296                 for param in params {
1297                     if let Ok(snippet) = self.tcx.sess.source_map().span_to_snippet(param.span) {
1298                         if snippet.starts_with('&') && !snippet.starts_with("&'") {
1299                             introduce_suggestion
1300                                 .push((param.span, format!("&{} {}", lt_name, &snippet[1..])));
1301                         } else if snippet.starts_with("&'_ ") {
1302                             introduce_suggestion
1303                                 .push((param.span, format!("&{} {}", lt_name, &snippet[4..])));
1304                         }
1305                     }
1306                 }
1307                 introduce_suggestion.push((*for_span, for_sugg.to_string()));
1308                 introduce_suggestion.push((span, formatter(&lt_name)));
1309                 err.multipart_suggestion(&msg, introduce_suggestion, Applicability::MaybeIncorrect);
1310             }
1311
1312             err.span_suggestion_verbose(
1313                 span,
1314                 &format!("consider using the `{}` lifetime", lifetime_names.iter().next().unwrap()),
1315                 formatter(name),
1316                 Applicability::MaybeIncorrect,
1317             );
1318         };
1319         let suggest_new = |err: &mut DiagnosticBuilder<'_>, sugg: &str| {
1320             for missing in self.missing_named_lifetime_spots.iter().rev() {
1321                 let mut introduce_suggestion = vec![];
1322                 let msg;
1323                 let should_break;
1324                 introduce_suggestion.push(match missing {
1325                     MissingLifetimeSpot::Generics(generics) => {
1326                         if generics.span == DUMMY_SP {
1327                             // Account for malformed generics in the HIR. This shouldn't happen,
1328                             // but if we make a mistake elsewhere, mainly by keeping something in
1329                             // `missing_named_lifetime_spots` that we shouldn't, like associated
1330                             // `const`s or making a mistake in the AST lowering we would provide
1331                             // non-sensical suggestions. Guard against that by skipping these.
1332                             // (#74264)
1333                             continue;
1334                         }
1335                         msg = "consider introducing a named lifetime parameter".to_string();
1336                         should_break = true;
1337                         if let Some(param) = generics.params.iter().find(|p| match p.kind {
1338                             hir::GenericParamKind::Type {
1339                                 synthetic: Some(hir::SyntheticTyParamKind::ImplTrait),
1340                                 ..
1341                             } => false,
1342                             _ => true,
1343                         }) {
1344                             (param.span.shrink_to_lo(), "'a, ".to_string())
1345                         } else {
1346                             (generics.span, "<'a>".to_string())
1347                         }
1348                     }
1349                     MissingLifetimeSpot::HigherRanked { span, span_type } => {
1350                         msg = format!(
1351                             "consider making the {} lifetime-generic with a new `'a` lifetime",
1352                             span_type.descr(),
1353                         );
1354                         should_break = false;
1355                         err.note(
1356                             "for more information on higher-ranked polymorphism, visit \
1357                             https://doc.rust-lang.org/nomicon/hrtb.html",
1358                         );
1359                         (*span, span_type.suggestion("'a"))
1360                     }
1361                 });
1362                 for param in params {
1363                     if let Ok(snippet) = self.tcx.sess.source_map().span_to_snippet(param.span) {
1364                         if snippet.starts_with('&') && !snippet.starts_with("&'") {
1365                             introduce_suggestion
1366                                 .push((param.span, format!("&'a {}", &snippet[1..])));
1367                         } else if snippet.starts_with("&'_ ") {
1368                             introduce_suggestion
1369                                 .push((param.span, format!("&'a {}", &snippet[4..])));
1370                         }
1371                     }
1372                 }
1373                 introduce_suggestion.push((span, sugg.to_string()));
1374                 err.multipart_suggestion(&msg, introduce_suggestion, Applicability::MaybeIncorrect);
1375                 if should_break {
1376                     break;
1377                 }
1378             }
1379         };
1380
1381         let lifetime_names: Vec<_> = lifetime_names.into_iter().collect();
1382         match (&lifetime_names[..], snippet.as_deref()) {
1383             ([name], Some("&")) => {
1384                 suggest_existing(err, &name.as_str()[..], &|name| format!("&{} ", name));
1385             }
1386             ([name], Some("'_")) => {
1387                 suggest_existing(err, &name.as_str()[..], &|n| n.to_string());
1388             }
1389             ([name], Some("")) => {
1390                 suggest_existing(err, &name.as_str()[..], &|n| format!("{}, ", n).repeat(count));
1391             }
1392             ([name], Some(snippet)) if !snippet.ends_with('>') => {
1393                 let f = |name: &str| {
1394                     format!(
1395                         "{}<{}>",
1396                         snippet,
1397                         std::iter::repeat(name.to_string())
1398                             .take(count)
1399                             .collect::<Vec<_>>()
1400                             .join(", ")
1401                     )
1402                 };
1403                 suggest_existing(err, &name.as_str()[..], &f);
1404             }
1405             ([], Some("&")) if count == 1 => {
1406                 suggest_new(err, "&'a ");
1407             }
1408             ([], Some("'_")) if count == 1 => {
1409                 suggest_new(err, "'a");
1410             }
1411             ([], Some(snippet)) if !snippet.ends_with('>') && count == 1 => {
1412                 if snippet == "" {
1413                     // This happens when we have `type Bar<'a> = Foo<T>` where we point at the space
1414                     // before `T`. We will suggest `type Bar<'a> = Foo<'a, T>`.
1415                     suggest_new(err, "'a, ");
1416                 } else {
1417                     suggest_new(err, &format!("{}<'a>", snippet));
1418                 }
1419             }
1420             (lts, ..) if lts.len() > 1 => {
1421                 err.span_note(lifetime_spans, "these named lifetimes are available to use");
1422                 if Some("") == snippet.as_deref() {
1423                     // This happens when we have `Foo<T>` where we point at the space before `T`,
1424                     // but this can be confusing so we give a suggestion with placeholders.
1425                     err.span_suggestion_verbose(
1426                         span,
1427                         "consider using one of the available lifetimes here",
1428                         "'lifetime, ".repeat(count),
1429                         Applicability::HasPlaceholders,
1430                     );
1431                 }
1432             }
1433             _ => {}
1434         }
1435     }
1436 }