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