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