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