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