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