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