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