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