1 use crate::diagnostics
::{ImportSuggestion, LabelSuggestion, TypoSuggestion}
;
2 use crate::late
::lifetimes
::{ElisionFailureInfo, LifetimeContext}
;
3 use crate::late
::{AliasPossibility, LateResolutionVisitor, RibKind}
;
4 use crate::path_names_to_string
;
5 use crate::{Finalize, Module, ModuleKind, ModuleOrUniformRoot}
;
6 use crate::{PathResult, PathSource, Segment}
;
8 use rustc_ast
::visit
::FnKind
;
10 self as ast
, AssocItemKind
, Expr
, ExprKind
, GenericParam
, GenericParamKind
, Item
, ItemKind
,
11 NodeId
, Path
, Ty
, TyKind
,
13 use rustc_ast_pretty
::pprust
::path_segment_to_string
;
14 use rustc_data_structures
::fx
::FxHashSet
;
16 pluralize
, struct_span_err
, Applicability
, Diagnostic
, DiagnosticBuilder
, ErrorGuaranteed
,
19 use rustc_hir
::def
::Namespace
::{self, *}
;
20 use rustc_hir
::def
::{self, CtorKind, CtorOf, DefKind}
;
21 use rustc_hir
::def_id
::{DefId, CRATE_DEF_INDEX, LOCAL_CRATE}
;
22 use rustc_hir
::PrimTy
;
23 use rustc_session
::parse
::feature_err
;
24 use rustc_span
::edition
::Edition
;
25 use rustc_span
::hygiene
::MacroKind
;
26 use rustc_span
::lev_distance
::find_best_match_for_name
;
27 use rustc_span
::symbol
::{kw, sym, Ident, Symbol}
;
28 use rustc_span
::{BytePos, MultiSpan, Span, DUMMY_SP}
;
35 type Res
= def
::Res
<ast
::NodeId
>;
37 /// A field or associated item from self type suggested in case of resolution failure.
38 enum AssocSuggestion
{
46 impl AssocSuggestion
{
47 fn action(&self) -> &'
static str {
49 AssocSuggestion
::Field
=> "use the available field",
50 AssocSuggestion
::MethodWithSelf
=> "call the method with the fully-qualified path",
51 AssocSuggestion
::AssocFn
=> "call the associated function",
52 AssocSuggestion
::AssocConst
=> "use the associated `const`",
53 AssocSuggestion
::AssocType
=> "use the associated type",
58 crate enum MissingLifetimeSpot
<'tcx
> {
59 Generics(&'tcx hir
::Generics
<'tcx
>),
60 HigherRanked { span: Span, span_type: ForLifetimeSpanType }
,
64 crate enum ForLifetimeSpanType
{
71 impl ForLifetimeSpanType
{
72 crate fn descr(&self) -> &'
static str {
74 Self::BoundEmpty
| Self::BoundTail
=> "bound",
75 Self::TypeEmpty
| Self::TypeTail
=> "type",
79 crate fn suggestion(&self, sugg
: &str) -> String
{
81 Self::BoundEmpty
| Self::TypeEmpty
=> format
!("for<{}> ", sugg
),
82 Self::BoundTail
| Self::TypeTail
=> format
!(", {}", sugg
),
87 impl<'tcx
> Into
<MissingLifetimeSpot
<'tcx
>> for &'tcx hir
::Generics
<'tcx
> {
88 fn into(self) -> MissingLifetimeSpot
<'tcx
> {
89 MissingLifetimeSpot
::Generics(self)
93 fn is_self_type(path
: &[Segment
], namespace
: Namespace
) -> bool
{
94 namespace
== TypeNS
&& path
.len() == 1 && path
[0].ident
.name
== kw
::SelfUpper
97 fn is_self_value(path
: &[Segment
], namespace
: Namespace
) -> bool
{
98 namespace
== ValueNS
&& path
.len() == 1 && path
[0].ident
.name
== kw
::SelfLower
101 /// Gets the stringified path for an enum from an `ImportSuggestion` for an enum variant.
102 fn import_candidate_to_enum_paths(suggestion
: &ImportSuggestion
) -> (String
, String
) {
103 let variant_path
= &suggestion
.path
;
104 let variant_path_string
= path_names_to_string(variant_path
);
106 let path_len
= suggestion
.path
.segments
.len();
107 let enum_path
= ast
::Path
{
108 span
: suggestion
.path
.span
,
109 segments
: suggestion
.path
.segments
[0..path_len
- 1].to_vec(),
112 let enum_path_string
= path_names_to_string(&enum_path
);
114 (variant_path_string
, enum_path_string
)
117 impl<'a
: 'ast
, 'ast
> LateResolutionVisitor
<'a
, '_
, 'ast
> {
118 fn def_span(&self, def_id
: DefId
) -> Option
<Span
> {
120 LOCAL_CRATE
=> self.r
.opt_span(def_id
),
125 .guess_head_span(self.r
.cstore().get_span_untracked(def_id
, self.r
.session
)),
130 /// Handles error reporting for `smart_resolve_path_fragment` function.
131 /// Creates base error and amends it with one short label and possibly some longer helps/notes.
132 pub(crate) fn smart_resolve_report_errors(
136 source
: PathSource
<'_
>,
138 ) -> (DiagnosticBuilder
<'a
, ErrorGuaranteed
>, Vec
<ImportSuggestion
>) {
139 let ident_span
= path
.last().map_or(span
, |ident
| ident
.ident
.span
);
140 let ns
= source
.namespace();
141 let is_expected
= &|res
| source
.is_expected(res
);
142 let is_enum_variant
= &|res
| matches
!(res
, Res
::Def(DefKind
::Variant
, _
));
144 // Make the base error.
145 let mut expected
= source
.descr_expected();
146 let path_str
= Segment
::names_to_string(path
);
147 let item_str
= path
.last().unwrap().ident
;
148 let (base_msg
, fallback_label
, base_span
, could_be_expr
) = if let Some(res
) = res
{
150 format
!("expected {}, found {} `{}`", expected
, res
.descr(), path_str
),
151 format
!("not a {}", expected
),
154 Res
::Def(DefKind
::Fn
, _
) => {
155 // Verify whether this is a fn call or an Fn used as a type.
159 .span_to_snippet(span
)
160 .map(|snippet
| snippet
.ends_with('
)'
))
164 DefKind
::Ctor(..) | DefKind
::AssocFn
| DefKind
::Const
| DefKind
::AssocConst
,
169 | Res
::Local(_
) => true,
174 let item_span
= path
.last().unwrap().ident
.span
;
175 let (mod_prefix
, mod_str
) = if path
.len() == 1 {
176 (String
::new(), "this scope".to_string())
177 } else if path
.len() == 2 && path
[0].ident
.name
== kw
::PathRoot
{
178 if self.r
.session
.edition() > Edition
::Edition2015
{
179 // In edition 2018 onwards, the `::foo` syntax may only pull from the extern prelude
180 // which overrides all other expectations of item type
182 (String
::new(), "the list of imported crates".to_string())
184 (String
::new(), "the crate root".to_string())
186 } else if path
.len() == 2 && path
[0].ident
.name
== kw
::Crate
{
187 (String
::new(), "the crate root".to_string())
189 let mod_path
= &path
[..path
.len() - 1];
190 let mod_prefix
= match self.resolve_path(mod_path
, Some(TypeNS
), Finalize
::No
) {
191 PathResult
::Module(ModuleOrUniformRoot
::Module(module
)) => module
.res(),
194 .map_or_else(String
::new
, |res
| format
!("{} ", res
.descr()));
195 (mod_prefix
, format
!("`{}`", Segment
::names_to_string(mod_path
)))
198 format
!("cannot find {} `{}` in {}{}", expected
, item_str
, mod_prefix
, mod_str
),
199 if path_str
== "async" && expected
.starts_with("struct") {
200 "`async` blocks are only allowed in Rust 2018 or later".to_string()
202 format
!("not found in {}", mod_str
)
209 let code
= source
.error_code(res
.is_some());
210 let mut err
= self.r
.session
.struct_span_err_with_code(base_span
, &base_msg
, code
);
212 if let Some(span
) = self.diagnostic_metadata
.current_block_could_be_bare_struct_literal
{
213 err
.multipart_suggestion(
214 "you might have meant to write a `struct` literal",
216 (span
.shrink_to_lo(), "{ SomeStruct ".to_string()),
217 (span
.shrink_to_hi(), "}".to_string()),
219 Applicability
::HasPlaceholders
,
222 match (source
, self.diagnostic_metadata
.in_if_condition
) {
223 (PathSource
::Expr(_
), Some(Expr { span, kind: ExprKind::Assign(..), .. }
)) => {
224 err
.span_suggestion_verbose(
226 "you might have meant to use pattern matching",
228 Applicability
::MaybeIncorrect
,
234 let is_assoc_fn
= self.self_type_is_available();
235 // Emit help message for fake-self from other languages (e.g., `this` in Javascript).
236 if ["this", "my"].contains(&item_str
.as_str()) && is_assoc_fn
{
237 err
.span_suggestion_short(
239 "you might have meant to use `self` here instead",
241 Applicability
::MaybeIncorrect
,
243 if !self.self_value_is_available(path
[0].ident
.span
) {
244 if let Some((FnKind
::Fn(_
, _
, sig
, ..), fn_span
)) =
245 &self.diagnostic_metadata
.current_function
247 let (span
, sugg
) = if let Some(param
) = sig
.decl
.inputs
.get(0) {
248 (param
.span
.shrink_to_lo(), "&self, ")
254 .span_through_char(*fn_span
, '
('
)
259 err
.span_suggestion_verbose(
261 "if you meant to use `self`, you are also missing a `self` receiver \
264 Applicability
::MaybeIncorrect
,
270 self.detect_assoct_type_constraint_meant_as_path(base_span
, &mut err
);
272 // Emit special messages for unresolved `Self` and `self`.
273 if is_self_type(path
, ns
) {
274 err
.code(rustc_errors
::error_code
!(E0411
));
277 "`Self` is only available in impls, traits, and type definitions".to_string(),
279 return (err
, Vec
::new());
281 if is_self_value(path
, ns
) {
282 debug
!("smart_resolve_path_fragment: E0424, source={:?}", source
);
284 err
.code(rustc_errors
::error_code
!(E0424
));
285 err
.span_label(span
, match source
{
286 PathSource
::Pat
=> "`self` value is a keyword and may not be bound to variables or shadowed"
288 _
=> "`self` value is a keyword only available in methods with a `self` parameter"
291 if let Some((fn_kind
, span
)) = &self.diagnostic_metadata
.current_function
{
292 // The current function has a `self' parameter, but we were unable to resolve
293 // a reference to `self`. This can only happen if the `self` identifier we
294 // are resolving came from a different hygiene context.
295 if fn_kind
.decl().inputs
.get(0).map_or(false, |p
| p
.is_self()) {
296 err
.span_label(*span
, "this function has a `self` parameter, but a macro invocation can only access identifiers it receives from parameters");
298 let doesnt
= if is_assoc_fn
{
299 let (span
, sugg
) = fn_kind
303 .map(|p
| (p
.span
.shrink_to_lo(), "&self, "))
305 // Try to look for the "(" after the function name, if possible.
306 // This avoids placing the suggestion into the visibility specifier.
309 .map_or(*span
, |ident
| span
.with_lo(ident
.span
.hi()));
314 .span_through_char(span
, '
('
)
319 err
.span_suggestion_verbose(
321 "add a `self` receiver parameter to make the associated `fn` a method",
323 Applicability
::MaybeIncorrect
,
329 if let Some(ident
) = fn_kind
.ident() {
332 &format
!("this function {} have a `self` parameter", doesnt
),
337 return (err
, Vec
::new());
340 // Try to lookup name in more relaxed fashion for better error reporting.
341 let ident
= path
.last().unwrap().ident
;
342 let candidates
= self
344 .lookup_import_candidates(ident
, ns
, &self.parent_scope
, is_expected
)
346 .filter(|ImportSuggestion { did, .. }
| {
347 match (did
, res
.and_then(|res
| res
.opt_def_id())) {
348 (Some(suggestion_did
), Some(actual_did
)) => *suggestion_did
!= actual_did
,
352 .collect
::<Vec
<_
>>();
353 let crate_def_id
= DefId
::local(CRATE_DEF_INDEX
);
354 if candidates
.is_empty() && is_expected(Res
::Def(DefKind
::Enum
, crate_def_id
)) {
355 let mut enum_candidates
: Vec
<_
> = self
357 .lookup_import_candidates(ident
, ns
, &self.parent_scope
, is_enum_variant
)
359 .map(|suggestion
| import_candidate_to_enum_paths(&suggestion
))
360 .filter(|(_
, enum_ty_path
)| !enum_ty_path
.starts_with("std::prelude::"))
362 if !enum_candidates
.is_empty() {
363 if let (PathSource
::Type
, Some(span
)) =
364 (source
, self.diagnostic_metadata
.current_type_ascription
.last())
370 .type_ascription_path_suggestions
374 // Already reported this issue on the lhs of the type ascription.
376 return (err
, candidates
);
380 enum_candidates
.sort();
382 // Contextualize for E0412 "cannot find type", but don't belabor the point
383 // (that it's a variant) for E0573 "expected type, found variant".
384 let preamble
= if res
.is_none() {
385 let others
= match enum_candidates
.len() {
387 2 => " and 1 other".to_owned(),
388 n
=> format
!(" and {} others", n
),
390 format
!("there is an enum variant `{}`{}; ", enum_candidates
[0].0, others
)
394 let msg
= format
!("{}try using the variant's enum", preamble
);
396 err
.span_suggestions(
399 enum_candidates
.into_iter().map(|(_variant_path
, enum_ty_path
)| enum_ty_path
),
400 Applicability
::MachineApplicable
,
404 if path
.len() == 1 && self.self_type_is_available() {
405 if let Some(candidate
) = self.lookup_assoc_candidate(ident
, ns
, is_expected
) {
406 let self_is_available
= self.self_value_is_available(path
[0].ident
.span
);
408 AssocSuggestion
::Field
=> {
409 if self_is_available
{
412 "you might have meant to use the available field",
413 format
!("self.{}", path_str
),
414 Applicability
::MachineApplicable
,
417 err
.span_label(span
, "a field by this name exists in `Self`");
420 AssocSuggestion
::MethodWithSelf
if self_is_available
=> {
423 "you might have meant to call the method",
424 format
!("self.{}", path_str
),
425 Applicability
::MachineApplicable
,
428 AssocSuggestion
::MethodWithSelf
429 | AssocSuggestion
::AssocFn
430 | AssocSuggestion
::AssocConst
431 | AssocSuggestion
::AssocType
=> {
434 &format
!("you might have meant to {}", candidate
.action()),
435 format
!("Self::{}", path_str
),
436 Applicability
::MachineApplicable
,
440 return (err
, candidates
);
443 // If the first argument in call is `self` suggest calling a method.
444 if let Some((call_span
, args_span
)) = self.call_has_self_arg(source
) {
445 let mut args_snippet
= String
::new();
446 if let Some(args_span
) = args_span
{
447 if let Ok(snippet
) = self.r
.session
.source_map().span_to_snippet(args_span
) {
448 args_snippet
= snippet
;
454 &format
!("try calling `{}` as a method", ident
),
455 format
!("self.{}({})", path_str
, args_snippet
),
456 Applicability
::MachineApplicable
,
458 return (err
, candidates
);
462 // Try Levenshtein algorithm.
463 let typo_sugg
= self.lookup_typo_candidate(path
, ns
, is_expected
);
464 // Try context-dependent help if relaxed lookup didn't work.
465 if let Some(res
) = res
{
466 if self.smart_resolve_context_dependent_help(
474 // We do this to avoid losing a secondary span when we override the main error span.
475 self.r
.add_typo_suggestion(&mut err
, typo_sugg
, ident_span
);
476 return (err
, candidates
);
480 let is_macro
= base_span
.from_expansion() && base_span
.desugaring_kind().is_none();
481 if !self.type_ascription_suggestion(&mut err
, base_span
) {
482 let mut fallback
= false;
484 PathSource
::Trait(AliasPossibility
::Maybe
),
485 Some(Res
::Def(DefKind
::Struct
| DefKind
::Enum
| DefKind
::Union
, _
)),
487 ) = (source
, res
, is_macro
)
489 if let Some(bounds @
[_
, .., _
]) = self.diagnostic_metadata
.current_trait_object
{
491 let spans
: Vec
<Span
> = bounds
493 .map(|bound
| bound
.span())
494 .filter(|&sp
| sp
!= base_span
)
497 let start_span
= bounds
.iter().map(|bound
| bound
.span()).next().unwrap();
498 // `end_span` is the end of the poly trait ref (Foo + 'baz + Bar><)
499 let end_span
= bounds
.iter().map(|bound
| bound
.span()).last().unwrap();
500 // `last_bound_span` is the last bound of the poly trait ref (Foo + >'baz< + Bar)
501 let last_bound_span
= spans
.last().cloned().unwrap();
502 let mut multi_span
: MultiSpan
= spans
.clone().into();
504 let msg
= if sp
== last_bound_span
{
506 "...because of {these} bound{s}",
507 these
= pluralize
!("this", bounds
.len() - 1),
508 s
= pluralize
!(bounds
.len() - 1),
513 multi_span
.push_span_label(sp
, msg
);
515 multi_span
.push_span_label(
517 "expected this type to be a trait...".to_string(),
521 "`+` is used to constrain a \"trait object\" type with lifetimes or \
522 auto-traits; structs and enums can't be bound in that way",
524 if bounds
.iter().all(|bound
| match bound
{
525 ast
::GenericBound
::Outlives(_
) => true,
526 ast
::GenericBound
::Trait(tr
, _
) => tr
.span
== base_span
,
528 let mut sugg
= vec
![];
529 if base_span
!= start_span
{
530 sugg
.push((start_span
.until(base_span
), String
::new()));
532 if base_span
!= end_span
{
533 sugg
.push((base_span
.shrink_to_hi().to(end_span
), String
::new()));
536 err
.multipart_suggestion(
537 "if you meant to use a type and not a trait here, remove the bounds",
539 Applicability
::MaybeIncorrect
,
545 fallback
|= self.restrict_assoc_type_in_where_clause(span
, &mut err
);
547 if !self.r
.add_typo_suggestion(&mut err
, typo_sugg
, ident_span
) {
549 match self.diagnostic_metadata
.current_let_binding
{
550 Some((pat_sp
, Some(ty_sp
), None
))
551 if ty_sp
.contains(base_span
) && could_be_expr
=>
553 err
.span_suggestion_short(
554 pat_sp
.between(ty_sp
),
555 "use `=` if you meant to assign",
557 Applicability
::MaybeIncorrect
,
563 // If the trait has a single item (which wasn't matched by Levenshtein), suggest it
564 let suggestion
= self.get_single_associated_item(&path
, &source
, is_expected
);
565 self.r
.add_typo_suggestion(&mut err
, suggestion
, ident_span
);
569 err
.span_label(base_span
, fallback_label
);
572 if let Some(err_code
) = &err
.code
{
573 if err_code
== &rustc_errors
::error_code
!(E0425
) {
574 for label_rib
in &self.label_ribs
{
575 for (label_ident
, node_id
) in &label_rib
.bindings
{
576 if format
!("'{}", ident
) == label_ident
.to_string() {
577 err
.span_label(label_ident
.span
, "a label with a similar name exists");
578 if let PathSource
::Expr(Some(Expr
{
579 kind
: ExprKind
::Break(None
, Some(_
)),
585 "use the similarly named label",
586 label_ident
.name
.to_string(),
587 Applicability
::MaybeIncorrect
,
589 // Do not lint against unused label when we suggest them.
590 self.diagnostic_metadata
.unused_labels
.remove(node_id
);
595 } else if err_code
== &rustc_errors
::error_code
!(E0412
) {
596 if let Some(correct
) = Self::likely_rust_type(path
) {
599 "perhaps you intended to use this type",
601 Applicability
::MaybeIncorrect
,
610 fn detect_assoct_type_constraint_meant_as_path(&self, base_span
: Span
, err
: &mut Diagnostic
) {
611 let Some(ty
) = self.diagnostic_metadata
.current_type_path
else { return; }
;
612 let TyKind
::Path(_
, path
) = &ty
.kind
else { return; }
;
613 for segment
in &path
.segments
{
614 let Some(params
) = &segment
.args
else { continue; }
;
615 let ast
::GenericArgs
::AngleBracketed(ref params
) = params
.deref() else { continue; }
;
616 for param
in ¶ms
.args
{
617 let ast
::AngleBracketedArg
::Constraint(constraint
) = param
else { continue; }
;
618 let ast
::AssocConstraintKind
::Bound { bounds }
= &constraint
.kind
else {
621 for bound
in bounds
{
622 let ast
::GenericBound
::Trait(trait_ref
, ast
::TraitBoundModifier
::None
)
627 if base_span
== trait_ref
.span
{
628 err
.span_suggestion_verbose(
629 constraint
.ident
.span
.between(trait_ref
.span
),
630 "you might have meant to write a path instead of an associated type bound",
632 Applicability
::MachineApplicable
,
640 fn get_single_associated_item(
643 source
: &PathSource
<'_
>,
644 filter_fn
: &impl Fn(Res
) -> bool
,
645 ) -> Option
<TypoSuggestion
> {
646 if let crate::PathSource
::TraitItem(_
) = source
{
647 let mod_path
= &path
[..path
.len() - 1];
648 if let PathResult
::Module(ModuleOrUniformRoot
::Module(module
)) =
649 self.resolve_path(mod_path
, None
, Finalize
::No
)
651 let resolutions
= self.r
.resolutions(module
).borrow();
652 let targets
: Vec
<_
> =
655 .filter_map(|(key
, resolution
)| {
656 resolution
.borrow().binding
.map(|binding
| binding
.res()).and_then(
657 |res
| if filter_fn(res
) { Some((key, res)) }
else { None }
,
661 if targets
.len() == 1 {
662 let target
= targets
[0];
663 return Some(TypoSuggestion
::single_item_from_res(
673 /// Given `where <T as Bar>::Baz: String`, suggest `where T: Bar<Baz = String>`.
674 fn restrict_assoc_type_in_where_clause(&mut self, span
: Span
, err
: &mut Diagnostic
) -> bool
{
675 // Detect that we are actually in a `where` predicate.
676 let (bounded_ty
, bounds
, where_span
) =
677 if let Some(ast
::WherePredicate
::BoundPredicate(ast
::WhereBoundPredicate
{
679 bound_generic_params
,
682 })) = self.diagnostic_metadata
.current_where_predicate
684 if !bound_generic_params
.is_empty() {
687 (bounded_ty
, bounds
, span
)
692 // Confirm that the target is an associated type.
693 let (ty
, position
, path
) = if let ast
::TyKind
::Path(
694 Some(ast
::QSelf { ty, position, .. }
),
698 // use this to verify that ident is a type param.
699 let Some(partial_res
) = self.r
.partial_res_map
.get(&bounded_ty
.id
) else {
703 partial_res
.base_res(),
704 hir
::def
::Res
::Def(hir
::def
::DefKind
::AssocTy
, _
)
705 ) && partial_res
.unresolved_segments() == 0)
714 let peeled_ty
= ty
.peel_refs();
715 if let ast
::TyKind
::Path(None
, type_param_path
) = &peeled_ty
.kind
{
716 // Confirm that the `SelfTy` is a type parameter.
717 let Some(partial_res
) = self.r
.partial_res_map
.get(&peeled_ty
.id
) else {
721 partial_res
.base_res(),
722 hir
::def
::Res
::Def(hir
::def
::DefKind
::TyParam
, _
)
723 ) && partial_res
.unresolved_segments() == 0)
728 [ast
::PathSegment { ident: constrain_ident, args: None, .. }
],
729 [ast
::GenericBound
::Trait(poly_trait_ref
, ast
::TraitBoundModifier
::None
)],
730 ) = (&type_param_path
.segments
[..], &bounds
[..])
732 if let [ast
::PathSegment { ident, args: None, .. }
] =
733 &poly_trait_ref
.trait_ref
.path
.segments
[..]
735 if ident
.span
== span
{
736 err
.span_suggestion_verbose(
738 &format
!("constrain the associated type to `{}`", ident
),
744 .span_to_snippet(ty
.span
) // Account for `<&'a T as Foo>::Bar`.
745 .unwrap_or_else(|_
| constrain_ident
.to_string()),
746 path
.segments
[..*position
]
748 .map(|segment
| path_segment_to_string(segment
))
751 path
.segments
[*position
..]
753 .map(|segment
| path_segment_to_string(segment
))
758 Applicability
::MaybeIncorrect
,
768 /// Check if the source is call expression and the first argument is `self`. If true,
769 /// return the span of whole call and the span for all arguments expect the first one (`self`).
770 fn call_has_self_arg(&self, source
: PathSource
<'_
>) -> Option
<(Span
, Option
<Span
>)> {
771 let mut has_self_arg
= None
;
772 if let PathSource
::Expr(Some(parent
)) = source
{
774 ExprKind
::Call(_
, args
) if !args
.is_empty() => {
775 let mut expr_kind
= &args
[0].kind
;
778 ExprKind
::Path(_
, arg_name
) if arg_name
.segments
.len() == 1 => {
779 if arg_name
.segments
[0].ident
.name
== kw
::SelfLower
{
780 let call_span
= parent
.span
;
781 let tail_args_span
= if args
.len() > 1 {
784 args
.last().unwrap().span
.hi(),
791 has_self_arg
= Some((call_span
, tail_args_span
));
795 ExprKind
::AddrOf(_
, _
, expr
) => expr_kind
= &expr
.kind
,
806 fn followed_by_brace(&self, span
: Span
) -> (bool
, Option
<Span
>) {
807 // HACK(estebank): find a better way to figure out that this was a
808 // parser issue where a struct literal is being used on an expression
809 // where a brace being opened means a block is being started. Look
810 // ahead for the next text to see if `span` is followed by a `{`.
811 let sm
= self.r
.session
.source_map();
814 sp
= sm
.next_point(sp
);
815 match sm
.span_to_snippet(sp
) {
817 if snippet
.chars().any(|c
| !c
.is_whitespace()) {
824 let followed_by_brace
= matches
!(sm
.span_to_snippet(sp
), Ok(ref snippet
) if snippet
== "{");
825 // In case this could be a struct literal that needs to be surrounded
826 // by parentheses, find the appropriate span.
828 let mut closing_brace
= None
;
830 sp
= sm
.next_point(sp
);
831 match sm
.span_to_snippet(sp
) {
834 closing_brace
= Some(span
.to(sp
));
841 // The bigger the span, the more likely we're incorrect --
842 // bound it to 100 chars long.
847 (followed_by_brace
, closing_brace
)
850 /// Provides context-dependent help for errors reported by the `smart_resolve_path_fragment`
852 /// Returns `true` if able to provide context-dependent help.
853 fn smart_resolve_context_dependent_help(
855 err
: &mut Diagnostic
,
857 source
: PathSource
<'_
>,
860 fallback_label
: &str,
862 let ns
= source
.namespace();
863 let is_expected
= &|res
| source
.is_expected(res
);
865 let path_sep
= |err
: &mut Diagnostic
, expr
: &Expr
| match expr
.kind
{
866 ExprKind
::Field(_
, ident
) => {
869 "use the path separator to refer to an item",
870 format
!("{}::{}", path_str
, ident
),
871 Applicability
::MaybeIncorrect
,
875 ExprKind
::MethodCall(ref segment
, ..) => {
876 let span
= expr
.span
.with_hi(segment
.ident
.span
.hi());
879 "use the path separator to refer to an item",
880 format
!("{}::{}", path_str
, segment
.ident
),
881 Applicability
::MaybeIncorrect
,
888 let find_span
= |source
: &PathSource
<'_
>, err
: &mut Diagnostic
| {
890 PathSource
::Expr(Some(Expr { span, kind: ExprKind::Call(_, _), .. }
))
891 | PathSource
::TupleStruct(span
, _
) => {
892 // We want the main underline to cover the suggested code as well for
901 let mut bad_struct_syntax_suggestion
= |def_id
: DefId
| {
902 let (followed_by_brace
, closing_brace
) = self.followed_by_brace(span
);
905 PathSource
::Expr(Some(
906 parent @ Expr { kind: ExprKind::Field(..) | ExprKind::MethodCall(..), .. }
,
907 )) if path_sep(err
, &parent
) => {}
913 | ExprKind
::Binary(..)
914 | ExprKind
::Unary(..)
916 | ExprKind
::While(..)
917 | ExprKind
::ForLoop(..)
918 | ExprKind
::Match(..),
921 ) if followed_by_brace
=> {
922 if let Some(sp
) = closing_brace
{
923 err
.span_label(span
, fallback_label
);
924 err
.multipart_suggestion(
925 "surround the struct literal with parentheses",
927 (sp
.shrink_to_lo(), "(".to_string()),
928 (sp
.shrink_to_hi(), ")".to_string()),
930 Applicability
::MaybeIncorrect
,
934 span
, // Note the parentheses surrounding the suggestion below
936 "you might want to surround a struct literal with parentheses: \
937 `({} {{ /* fields */ }})`?",
943 PathSource
::Expr(_
) | PathSource
::TupleStruct(..) | PathSource
::Pat
=> {
944 let span
= find_span(&source
, err
);
945 if let Some(span
) = self.def_span(def_id
) {
946 err
.span_label(span
, &format
!("`{}` defined here", path_str
));
948 let (tail
, descr
, applicability
) = match source
{
949 PathSource
::Pat
| PathSource
::TupleStruct(..) => {
950 ("", "pattern", Applicability
::MachineApplicable
)
952 _
=> (": val", "literal", Applicability
::HasPlaceholders
),
954 let (fields
, applicability
) = match self.r
.field_names
.get(&def_id
) {
958 .map(|f
| format
!("{}{}", f
.node
, tail
))
959 .collect
::<Vec
<String
>>()
963 None
=> ("/* fields */".to_string(), Applicability
::HasPlaceholders
),
965 let pad
= match self.r
.field_names
.get(&def_id
) {
966 Some(fields
) if fields
.is_empty() => "",
971 &format
!("use struct {} syntax instead", descr
),
972 format
!("{path_str} {{{pad}{fields}{pad}}}"),
977 err
.span_label(span
, fallback_label
);
982 match (res
, source
) {
984 Res
::Def(DefKind
::Macro(MacroKind
::Bang
), _
),
985 PathSource
::Expr(Some(Expr
{
986 kind
: ExprKind
::Index(..) | ExprKind
::Call(..), ..
988 | PathSource
::Struct
,
990 err
.span_label(span
, fallback_label
);
991 err
.span_suggestion_verbose(
993 "use `!` to invoke the macro",
995 Applicability
::MaybeIncorrect
,
997 if path_str
== "try" && span
.rust_2015() {
998 err
.note("if you want the `try` keyword, you need Rust 2018 or later");
1001 (Res
::Def(DefKind
::Macro(MacroKind
::Bang
), _
), _
) => {
1002 err
.span_label(span
, fallback_label
);
1004 (Res
::Def(DefKind
::TyAlias
, def_id
), PathSource
::Trait(_
)) => {
1005 err
.span_label(span
, "type aliases cannot be used as traits");
1006 if self.r
.session
.is_nightly_build() {
1007 let msg
= "you might have meant to use `#![feature(trait_alias)]` instead of a \
1009 if let Some(span
) = self.def_span(def_id
) {
1010 if let Ok(snip
) = self.r
.session
.source_map().span_to_snippet(span
) {
1011 // The span contains a type alias so we should be able to
1012 // replace `type` with `trait`.
1013 let snip
= snip
.replacen("type", "trait", 1);
1014 err
.span_suggestion(span
, msg
, snip
, Applicability
::MaybeIncorrect
);
1016 err
.span_help(span
, msg
);
1023 (Res
::Def(DefKind
::Mod
, _
), PathSource
::Expr(Some(parent
))) => {
1024 if !path_sep(err
, &parent
) {
1029 Res
::Def(DefKind
::Enum
, def_id
),
1030 PathSource
::TupleStruct(..) | PathSource
::Expr(..),
1033 .diagnostic_metadata
1034 .current_type_ascription
1040 .type_ascription_path_suggestions
1046 err
.downgrade_to_delayed_bug();
1047 // We already suggested changing `:` into `::` during parsing.
1051 self.suggest_using_enum_variant(err
, source
, def_id
, span
);
1053 (Res
::Def(DefKind
::Struct
, def_id
), source
) if ns
== ValueNS
=> {
1054 let (ctor_def
, ctor_vis
, fields
) =
1055 if let Some(struct_ctor
) = self.r
.struct_constructors
.get(&def_id
).cloned() {
1056 if let PathSource
::Expr(Some(parent
)) = source
{
1057 if let ExprKind
::Field(..) | ExprKind
::MethodCall(..) = parent
.kind
{
1058 bad_struct_syntax_suggestion(def_id
);
1064 bad_struct_syntax_suggestion(def_id
);
1068 let is_accessible
= self.r
.is_accessible_from(ctor_vis
, self.parent_scope
.module
);
1069 if !is_expected(ctor_def
) || is_accessible
{
1073 let field_spans
= match source
{
1074 // e.g. `if let Enum::TupleVariant(field1, field2) = _`
1075 PathSource
::TupleStruct(_
, pattern_spans
) => {
1076 err
.set_primary_message(
1077 "cannot match against a tuple struct which contains private fields",
1080 // Use spans of the tuple struct pattern.
1081 Some(Vec
::from(pattern_spans
))
1083 // e.g. `let _ = Enum::TupleVariant(field1, field2);`
1084 _
if source
.is_call() => {
1085 err
.set_primary_message(
1086 "cannot initialize a tuple struct which contains private fields",
1089 // Use spans of the tuple struct definition.
1093 .map(|fields
| fields
.iter().map(|f
| f
.span
).collect
::<Vec
<_
>>())
1098 if let Some(spans
) =
1099 field_spans
.filter(|spans
| spans
.len() > 0 && fields
.len() == spans
.len())
1101 let non_visible_spans
: Vec
<Span
> = iter
::zip(&fields
, &spans
)
1102 .filter(|(vis
, _
)| {
1103 !self.r
.is_accessible_from(**vis
, self.parent_scope
.module
)
1105 .map(|(_
, span
)| *span
)
1108 if non_visible_spans
.len() > 0 {
1109 let mut m
: rustc_span
::MultiSpan
= non_visible_spans
.clone().into();
1112 .for_each(|s
| m
.push_span_label(s
, "private field".to_string()));
1113 err
.span_note(m
, "constructor is not visible here due to private fields");
1121 "constructor is not visible here due to private fields".to_string(),
1126 DefKind
::Union
| DefKind
::Variant
| DefKind
::Ctor(_
, CtorKind
::Fictive
),
1130 ) if ns
== ValueNS
=> {
1131 bad_struct_syntax_suggestion(def_id
);
1133 (Res
::Def(DefKind
::Ctor(_
, CtorKind
::Const
), def_id
), _
) if ns
== ValueNS
=> {
1135 PathSource
::Expr(_
) | PathSource
::TupleStruct(..) | PathSource
::Pat
=> {
1136 let span
= find_span(&source
, err
);
1137 if let Some(span
) = self.def_span(def_id
) {
1138 err
.span_label(span
, &format
!("`{}` defined here", path_str
));
1140 err
.span_suggestion(
1142 &"use this syntax instead",
1143 path_str
.to_string(),
1144 Applicability
::MaybeIncorrect
,
1150 (Res
::Def(DefKind
::Ctor(_
, CtorKind
::Fn
), def_id
), _
) if ns
== ValueNS
=> {
1151 if let Some(span
) = self.def_span(def_id
) {
1152 err
.span_label(span
, &format
!("`{}` defined here", path_str
));
1154 let fields
= self.r
.field_names
.get(&def_id
).map_or_else(
1155 || "/* fields */".to_string(),
1156 |fields
| vec
!["_"; fields
.len()].join(", "),
1158 err
.span_suggestion(
1160 "use the tuple variant pattern syntax instead",
1161 format
!("{}({})", path_str
, fields
),
1162 Applicability
::HasPlaceholders
,
1165 (Res
::SelfTy { .. }
, _
) if ns
== ValueNS
=> {
1166 err
.span_label(span
, fallback_label
);
1167 err
.note("can't use `Self` as a constructor, you must use the implemented struct");
1169 (Res
::Def(DefKind
::TyAlias
| DefKind
::AssocTy
, _
), _
) if ns
== ValueNS
=> {
1170 err
.note("can't use a type alias as a constructor");
1177 /// Given the target `ident` and `kind`, search for the similarly named associated item
1178 /// in `self.current_trait_ref`.
1179 crate fn find_similarly_named_assoc_item(
1182 kind
: &AssocItemKind
,
1183 ) -> Option
<Symbol
> {
1184 let Some((module
, _
)) = &self.current_trait_ref
else {
1187 if ident
== kw
::Underscore
{
1188 // We do nothing for `_`.
1192 let resolutions
= self.r
.resolutions(module
);
1193 let targets
= resolutions
1196 .filter_map(|(key
, res
)| res
.borrow().binding
.map(|binding
| (key
, binding
.res())))
1197 .filter(|(_
, res
)| match (kind
, res
) {
1198 (AssocItemKind
::Const(..), Res
::Def(DefKind
::AssocConst
, _
)) => true,
1199 (AssocItemKind
::Fn(_
), Res
::Def(DefKind
::AssocFn
, _
)) => true,
1200 (AssocItemKind
::TyAlias(..), Res
::Def(DefKind
::AssocTy
, _
)) => true,
1203 .map(|(key
, _
)| key
.ident
.name
)
1204 .collect
::<Vec
<_
>>();
1206 find_best_match_for_name(&targets
, ident
, None
)
1209 fn lookup_assoc_candidate
<FilterFn
>(
1213 filter_fn
: FilterFn
,
1214 ) -> Option
<AssocSuggestion
>
1216 FilterFn
: Fn(Res
) -> bool
,
1218 fn extract_node_id(t
: &Ty
) -> Option
<NodeId
> {
1220 TyKind
::Path(None
, _
) => Some(t
.id
),
1221 TyKind
::Rptr(_
, ref mut_ty
) => extract_node_id(&mut_ty
.ty
),
1222 // This doesn't handle the remaining `Ty` variants as they are not
1223 // that commonly the self_type, it might be interesting to provide
1224 // support for those in future.
1229 // Fields are generally expected in the same contexts as locals.
1230 if filter_fn(Res
::Local(ast
::DUMMY_NODE_ID
)) {
1231 if let Some(node_id
) =
1232 self.diagnostic_metadata
.current_self_type
.as_ref().and_then(extract_node_id
)
1234 // Look for a field with the same name in the current self_type.
1235 if let Some(resolution
) = self.r
.partial_res_map
.get(&node_id
) {
1236 match resolution
.base_res() {
1237 Res
::Def(DefKind
::Struct
| DefKind
::Union
, did
)
1238 if resolution
.unresolved_segments() == 0 =>
1240 if let Some(field_names
) = self.r
.field_names
.get(&did
) {
1243 .any(|&field_name
| ident
.name
== field_name
.node
)
1245 return Some(AssocSuggestion
::Field
);
1255 if let Some(items
) = self.diagnostic_metadata
.current_trait_assoc_items
{
1256 for assoc_item
in items
{
1257 if assoc_item
.ident
== ident
{
1258 return Some(match &assoc_item
.kind
{
1259 ast
::AssocItemKind
::Const(..) => AssocSuggestion
::AssocConst
,
1260 ast
::AssocItemKind
::Fn(box ast
::Fn { sig, .. }
) if sig
.decl
.has_self() => {
1261 AssocSuggestion
::MethodWithSelf
1263 ast
::AssocItemKind
::Fn(..) => AssocSuggestion
::AssocFn
,
1264 ast
::AssocItemKind
::TyAlias(..) => AssocSuggestion
::AssocType
,
1265 ast
::AssocItemKind
::MacCall(_
) => continue,
1271 // Look for associated items in the current trait.
1272 if let Some((module
, _
)) = self.current_trait_ref
{
1273 if let Ok(binding
) = self.r
.resolve_ident_in_module(
1274 ModuleOrUniformRoot
::Module(module
),
1280 let res
= binding
.res();
1282 if self.r
.has_self
.contains(&res
.def_id()) {
1283 return Some(AssocSuggestion
::MethodWithSelf
);
1286 Res
::Def(DefKind
::AssocFn
, _
) => return Some(AssocSuggestion
::AssocFn
),
1287 Res
::Def(DefKind
::AssocConst
, _
) => {
1288 return Some(AssocSuggestion
::AssocConst
);
1290 Res
::Def(DefKind
::AssocTy
, _
) => {
1291 return Some(AssocSuggestion
::AssocType
);
1303 fn lookup_typo_candidate(
1307 filter_fn
: &impl Fn(Res
) -> bool
,
1308 ) -> Option
<TypoSuggestion
> {
1309 let mut names
= Vec
::new();
1310 if path
.len() == 1 {
1311 // Search in lexical scope.
1312 // Walk backwards up the ribs in scope and collect candidates.
1313 for rib
in self.ribs
[ns
].iter().rev() {
1314 // Locals and type parameters
1315 for (ident
, &res
) in &rib
.bindings
{
1317 names
.push(TypoSuggestion
::typo_from_res(ident
.name
, res
));
1321 if let RibKind
::ModuleRibKind(module
) = rib
.kind
{
1322 // Items from this module
1323 self.r
.add_module_candidates(module
, &mut names
, &filter_fn
);
1325 if let ModuleKind
::Block(..) = module
.kind
{
1326 // We can see through blocks
1328 // Items from the prelude
1329 if !module
.no_implicit_prelude
{
1330 let extern_prelude
= self.r
.extern_prelude
.clone();
1331 names
.extend(extern_prelude
.iter().flat_map(|(ident
, _
)| {
1332 self.r
.crate_loader
.maybe_process_path_extern(ident
.name
).and_then(
1334 let crate_mod
= Res
::Def(
1336 DefId { krate: crate_id, index: CRATE_DEF_INDEX }
,
1339 if filter_fn(crate_mod
) {
1340 Some(TypoSuggestion
::typo_from_res(
1341 ident
.name
, crate_mod
,
1350 if let Some(prelude
) = self.r
.prelude
{
1351 self.r
.add_module_candidates(prelude
, &mut names
, &filter_fn
);
1358 // Add primitive types to the mix
1359 if filter_fn(Res
::PrimTy(PrimTy
::Bool
)) {
1360 names
.extend(PrimTy
::ALL
.iter().map(|prim_ty
| {
1361 TypoSuggestion
::typo_from_res(prim_ty
.name(), Res
::PrimTy(*prim_ty
))
1365 // Search in module.
1366 let mod_path
= &path
[..path
.len() - 1];
1367 if let PathResult
::Module(ModuleOrUniformRoot
::Module(module
)) =
1368 self.resolve_path(mod_path
, Some(TypeNS
), Finalize
::No
)
1370 self.r
.add_module_candidates(module
, &mut names
, &filter_fn
);
1374 let name
= path
[path
.len() - 1].ident
.name
;
1375 // Make sure error reporting is deterministic.
1376 names
.sort_by(|a
, b
| a
.candidate
.as_str().partial_cmp(b
.candidate
.as_str()).unwrap());
1378 match find_best_match_for_name(
1379 &names
.iter().map(|suggestion
| suggestion
.candidate
).collect
::<Vec
<Symbol
>>(),
1383 Some(found
) if found
!= name
=> {
1384 names
.into_iter().find(|suggestion
| suggestion
.candidate
== found
)
1390 // Returns the name of the Rust type approximately corresponding to
1391 // a type name in another programming language.
1392 fn likely_rust_type(path
: &[Segment
]) -> Option
<Symbol
> {
1393 let name
= path
[path
.len() - 1].ident
.as_str();
1394 // Common Java types
1396 "byte" => sym
::u8, // In Java, bytes are signed, but in practice one almost always wants unsigned bytes.
1397 "short" => sym
::i16,
1398 "boolean" => sym
::bool
,
1401 "float" => sym
::f32,
1402 "double" => sym
::f64,
1407 /// Only used in a specific case of type ascription suggestions
1408 fn get_colon_suggestion_span(&self, start
: Span
) -> Span
{
1409 let sm
= self.r
.session
.source_map();
1410 start
.to(sm
.next_point(start
))
1413 fn type_ascription_suggestion(&self, err
: &mut Diagnostic
, base_span
: Span
) -> bool
{
1414 let sm
= self.r
.session
.source_map();
1415 let base_snippet
= sm
.span_to_snippet(base_span
);
1416 if let Some(&sp
) = self.diagnostic_metadata
.current_type_ascription
.last() {
1417 if let Ok(snippet
) = sm
.span_to_snippet(sp
) {
1418 let len
= snippet
.trim_end().len() as u32;
1419 if snippet
.trim() == ":" {
1421 sp
.with_lo(sp
.lo() + BytePos(len
- 1)).with_hi(sp
.lo() + BytePos(len
));
1422 let mut show_label
= true;
1423 if sm
.is_multiline(sp
) {
1424 err
.span_suggestion_short(
1426 "maybe you meant to write `;` here",
1428 Applicability
::MaybeIncorrect
,
1431 let after_colon_sp
=
1432 self.get_colon_suggestion_span(colon_sp
.shrink_to_hi());
1433 if snippet
.len() == 1 {
1435 err
.span_suggestion(
1437 "maybe you meant to write a path separator here",
1439 Applicability
::MaybeIncorrect
,
1446 .type_ascription_path_suggestions
1450 err
.downgrade_to_delayed_bug();
1453 if let Ok(base_snippet
) = base_snippet
{
1454 let mut sp
= after_colon_sp
;
1456 // Try to find an assignment
1457 sp
= sm
.next_point(sp
);
1458 let snippet
= sm
.span_to_snippet(sp
.to(sm
.next_point(sp
)));
1460 Ok(ref x
) if x
.as_str() == "=" => {
1461 err
.span_suggestion(
1463 "maybe you meant to write an assignment here",
1464 format
!("let {}", base_snippet
),
1465 Applicability
::MaybeIncorrect
,
1470 Ok(ref x
) if x
.as_str() == "\n" => break,
1480 "expecting a type here because of type ascription",
1490 fn find_module(&mut self, def_id
: DefId
) -> Option
<(Module
<'a
>, ImportSuggestion
)> {
1491 let mut result
= None
;
1492 let mut seen_modules
= FxHashSet
::default();
1493 let mut worklist
= vec
![(self.r
.graph_root
, Vec
::new())];
1495 while let Some((in_module
, path_segments
)) = worklist
.pop() {
1496 // abort if the module is already found
1497 if result
.is_some() {
1501 in_module
.for_each_child(self.r
, |_
, ident
, _
, name_binding
| {
1502 // abort if the module is already found or if name_binding is private external
1503 if result
.is_some() || !name_binding
.vis
.is_visible_locally() {
1506 if let Some(module
) = name_binding
.module() {
1508 let mut path_segments
= path_segments
.clone();
1509 path_segments
.push(ast
::PathSegment
::from_ident(ident
));
1510 let module_def_id
= module
.def_id();
1511 if module_def_id
== def_id
{
1513 Path { span: name_binding.span, segments: path_segments, tokens: None }
;
1525 // add the module to the lookup
1526 if seen_modules
.insert(module_def_id
) {
1527 worklist
.push((module
, path_segments
));
1537 fn collect_enum_ctors(&mut self, def_id
: DefId
) -> Option
<Vec
<(Path
, DefId
, CtorKind
)>> {
1538 self.find_module(def_id
).map(|(enum_module
, enum_import_suggestion
)| {
1539 let mut variants
= Vec
::new();
1540 enum_module
.for_each_child(self.r
, |_
, ident
, _
, name_binding
| {
1541 if let Res
::Def(DefKind
::Ctor(CtorOf
::Variant
, kind
), def_id
) = name_binding
.res() {
1542 let mut segms
= enum_import_suggestion
.path
.segments
.clone();
1543 segms
.push(ast
::PathSegment
::from_ident(ident
));
1544 let path
= Path { span: name_binding.span, segments: segms, tokens: None }
;
1545 variants
.push((path
, def_id
, kind
));
1552 /// Adds a suggestion for using an enum's variant when an enum is used instead.
1553 fn suggest_using_enum_variant(
1555 err
: &mut Diagnostic
,
1556 source
: PathSource
<'_
>,
1560 let Some(variants
) = self.collect_enum_ctors(def_id
) else {
1561 err
.note("you might have meant to use one of the enum's variants");
1565 let suggest_only_tuple_variants
=
1566 matches
!(source
, PathSource
::TupleStruct(..)) || source
.is_call();
1567 if suggest_only_tuple_variants
{
1568 // Suggest only tuple variants regardless of whether they have fields and do not
1569 // suggest path with added parentheses.
1570 let suggestable_variants
= variants
1572 .filter(|(.., kind
)| *kind
== CtorKind
::Fn
)
1573 .map(|(variant
, ..)| path_names_to_string(variant
))
1574 .collect
::<Vec
<_
>>();
1576 let non_suggestable_variant_count
= variants
.len() - suggestable_variants
.len();
1578 let source_msg
= if source
.is_call() {
1580 } else if matches
!(source
, PathSource
::TupleStruct(..)) {
1586 if !suggestable_variants
.is_empty() {
1587 let msg
= if non_suggestable_variant_count
== 0 && suggestable_variants
.len() == 1 {
1588 format
!("try {} the enum's variant", source_msg
)
1590 format
!("try {} one of the enum's variants", source_msg
)
1593 err
.span_suggestions(
1596 suggestable_variants
.into_iter(),
1597 Applicability
::MaybeIncorrect
,
1601 // If the enum has no tuple variants..
1602 if non_suggestable_variant_count
== variants
.len() {
1603 err
.help(&format
!("the enum has no tuple variants {}", source_msg
));
1606 // If there are also non-tuple variants..
1607 if non_suggestable_variant_count
== 1 {
1609 "you might have meant {} the enum's non-tuple variant",
1612 } else if non_suggestable_variant_count
>= 1 {
1614 "you might have meant {} one of the enum's non-tuple variants",
1619 let needs_placeholder
= |def_id
: DefId
, kind
: CtorKind
| {
1620 let has_no_fields
= self.r
.field_names
.get(&def_id
).map_or(false, |f
| f
.is_empty());
1622 CtorKind
::Const
=> false,
1623 CtorKind
::Fn
| CtorKind
::Fictive
if has_no_fields
=> false,
1628 let mut suggestable_variants
= variants
1630 .filter(|(_
, def_id
, kind
)| !needs_placeholder(*def_id
, *kind
))
1631 .map(|(variant
, _
, kind
)| (path_names_to_string(variant
), kind
))
1632 .map(|(variant
, kind
)| match kind
{
1633 CtorKind
::Const
=> variant
,
1634 CtorKind
::Fn
=> format
!("({}())", variant
),
1635 CtorKind
::Fictive
=> format
!("({} {{}})", variant
),
1637 .collect
::<Vec
<_
>>();
1639 if !suggestable_variants
.is_empty() {
1640 let msg
= if suggestable_variants
.len() == 1 {
1641 "you might have meant to use the following enum variant"
1643 "you might have meant to use one of the following enum variants"
1646 err
.span_suggestions(
1649 suggestable_variants
.drain(..),
1650 Applicability
::MaybeIncorrect
,
1654 let suggestable_variants_with_placeholders
= variants
1656 .filter(|(_
, def_id
, kind
)| needs_placeholder(*def_id
, *kind
))
1657 .map(|(variant
, _
, kind
)| (path_names_to_string(variant
), kind
))
1658 .filter_map(|(variant
, kind
)| match kind
{
1659 CtorKind
::Fn
=> Some(format
!("({}(/* fields */))", variant
)),
1660 CtorKind
::Fictive
=> Some(format
!("({} {{ /* fields */ }})", variant
)),
1663 .collect
::<Vec
<_
>>();
1665 if !suggestable_variants_with_placeholders
.is_empty() {
1667 suggestable_variants
.is_empty(),
1668 suggestable_variants_with_placeholders
.len(),
1670 (true, 1) => "the following enum variant is available",
1671 (true, _
) => "the following enum variants are available",
1672 (false, 1) => "alternatively, the following enum variant is available",
1673 (false, _
) => "alternatively, the following enum variants are also available",
1676 err
.span_suggestions(
1679 suggestable_variants_with_placeholders
.into_iter(),
1680 Applicability
::HasPlaceholders
,
1685 if def_id
.is_local() {
1686 if let Some(span
) = self.def_span(def_id
) {
1687 err
.span_note(span
, "the enum is defined here");
1692 crate fn report_missing_type_error(
1695 ) -> Option
<(Span
, &'
static str, String
, Applicability
)> {
1696 let (ident
, span
) = match path
{
1697 [segment
] if !segment
.has_generic_args
=> {
1698 (segment
.ident
.to_string(), segment
.ident
.span
)
1702 let mut iter
= ident
.chars().map(|c
| c
.is_uppercase());
1703 let single_uppercase_char
=
1704 matches
!(iter
.next(), Some(true)) && matches
!(iter
.next(), None
);
1705 if !self.diagnostic_metadata
.currently_processing_generics
&& !single_uppercase_char
{
1708 match (self.diagnostic_metadata
.current_item
, single_uppercase_char
, self.diagnostic_metadata
.currently_processing_generics
) {
1709 (Some(Item { kind: ItemKind::Fn(..), ident, .. }
), _
, _
) if ident
.name
== sym
::main
=> {
1710 // Ignore `fn main()` as we don't want to suggest `fn main<T>()`
1715 kind @ ItemKind
::Fn(..)
1716 | kind @ ItemKind
::Enum(..)
1717 | kind @ ItemKind
::Struct(..)
1718 | kind @ ItemKind
::Union(..),
1723 // Without the 2nd `true`, we'd suggest `impl <T>` for `impl T` when a type `T` isn't found
1724 | (Some(Item { kind: kind @ ItemKind::Impl(..), .. }
), true, true)
1725 | (Some(Item { kind, .. }
), false, _
) => {
1726 // Likely missing type parameter.
1727 if let Some(generics
) = kind
.generics() {
1728 if span
.overlaps(generics
.span
) {
1729 // Avoid the following:
1730 // error[E0405]: cannot find trait `A` in this scope
1731 // --> $DIR/typo-suggestion-named-underscore.rs:CC:LL
1733 // L | fn foo<T: A>(x: T) {} // Shouldn't suggest underscore
1734 // | ^- help: you might be missing a type parameter: `, A`
1736 // | not found in this scope
1739 let msg
= "you might be missing a type parameter";
1740 let (span
, sugg
) = if let [.., param
] = &generics
.params
[..] {
1741 let span
= if let [.., bound
] = ¶m
.bounds
[..] {
1743 } else if let GenericParam
{
1744 kind
: GenericParamKind
::Const { ty, kw_span: _, default }
, ..
1746 default.as_ref().map(|def
| def
.value
.span
).unwrap_or(ty
.span
)
1750 (span
, format
!(", {}", ident
))
1752 (generics
.span
, format
!("<{}>", ident
))
1754 // Do not suggest if this is coming from macro expansion.
1755 if span
.can_be_used_for_suggestions() {
1757 span
.shrink_to_hi(),
1760 Applicability
::MaybeIncorrect
,
1770 /// Given the target `label`, search the `rib_index`th label rib for similarly named labels,
1771 /// optionally returning the closest match and whether it is reachable.
1772 crate fn suggestion_for_label_in_rib(
1776 ) -> Option
<LabelSuggestion
> {
1777 // Are ribs from this `rib_index` within scope?
1778 let within_scope
= self.is_label_valid_from_rib(rib_index
);
1780 let rib
= &self.label_ribs
[rib_index
];
1784 .filter(|(id
, _
)| id
.span
.ctxt() == label
.span
.ctxt())
1785 .map(|(id
, _
)| id
.name
)
1786 .collect
::<Vec
<Symbol
>>();
1788 find_best_match_for_name(&names
, label
.name
, None
).map(|symbol
| {
1789 // Upon finding a similar name, get the ident that it was from - the span
1790 // contained within helps make a useful diagnostic. In addition, determine
1791 // whether this candidate is within scope.
1792 let (ident
, _
) = rib
.bindings
.iter().find(|(ident
, _
)| ident
.name
== symbol
).unwrap();
1793 (*ident
, within_scope
)
1798 impl<'tcx
> LifetimeContext
<'_
, 'tcx
> {
1799 crate fn report_missing_lifetime_specifiers(
1803 ) -> DiagnosticBuilder
<'tcx
, ErrorGuaranteed
> {
1808 "missing lifetime specifier{}",
1813 crate fn emit_undeclared_lifetime_error(&self, lifetime_ref
: &hir
::Lifetime
) {
1814 let mut err
= struct_span_err
!(
1818 "use of undeclared lifetime name `{}`",
1821 err
.span_label(lifetime_ref
.span
, "undeclared lifetime");
1822 let mut suggested_spans
= vec
![];
1823 for missing
in &self.missing_named_lifetime_spots
{
1825 MissingLifetimeSpot
::Generics(generics
) => {
1826 let (span
, sugg
) = if let Some(param
) = generics
.params
.iter().find(|p
| {
1829 hir
::GenericParamKind
::Type { synthetic: true, .. }
1830 | hir
::GenericParamKind
::Lifetime
{
1831 kind
: hir
::LifetimeParamKind
::Elided
,
1835 (param
.span
.shrink_to_lo(), format
!("{}, ", lifetime_ref
))
1837 (generics
.span
, format
!("<{}>", lifetime_ref
))
1839 if suggested_spans
.contains(&span
) {
1842 suggested_spans
.push(span
);
1843 if span
.can_be_used_for_suggestions() {
1844 err
.span_suggestion(
1846 &format
!("consider introducing lifetime `{}` here", lifetime_ref
),
1848 Applicability
::MaybeIncorrect
,
1852 MissingLifetimeSpot
::HigherRanked { span, span_type }
=> {
1853 err
.span_suggestion(
1856 "consider making the {} lifetime-generic with a new `{}` lifetime",
1860 span_type
.suggestion(&lifetime_ref
.to_string()),
1861 Applicability
::MaybeIncorrect
,
1864 "for more information on higher-ranked polymorphism, visit \
1865 https://doc.rust-lang.org/nomicon/hrtb.html",
1874 /// Returns whether to add `'static` lifetime to the suggested lifetime list.
1875 crate fn report_elision_failure(
1877 // FIXME(eddyb) rename this since it's no longer a `DiagnosticBuilder`.
1878 db
: &mut Diagnostic
,
1879 params
: &[ElisionFailureInfo
],
1881 let mut m
= String
::new();
1882 let len
= params
.len();
1884 let elided_params
: Vec
<_
> =
1885 params
.iter().cloned().filter(|info
| info
.lifetime_count
> 0).collect();
1887 let elided_len
= elided_params
.len();
1889 for (i
, info
) in elided_params
.into_iter().enumerate() {
1890 let ElisionFailureInfo { parent, index, lifetime_count: n, have_bound_regions, span }
=
1893 db
.span_label(span
, "");
1894 let help_name
= if let Some(ident
) =
1895 parent
.and_then(|body
| self.tcx
.hir().body(body
).params
[index
].pat
.simple_ident())
1897 format
!("`{}`", ident
)
1899 format
!("argument {}", index
+ 1)
1907 "one of {}'s {} {}lifetimes",
1910 if have_bound_regions { "free " }
else { "" }
1915 if elided_len
== 2 && i
== 0 {
1917 } else if i
+ 2 == elided_len
{
1918 m
.push_str(", or ");
1919 } else if i
!= elided_len
- 1 {
1926 "this function's return type contains a borrowed value, \
1927 but there is no value for it to be borrowed from",
1930 } else if elided_len
== 0 {
1932 "this function's return type contains a borrowed value with \
1933 an elided lifetime, but the lifetime cannot be derived from \
1937 } else if elided_len
== 1 {
1939 "this function's return type contains a borrowed value, \
1940 but the signature does not say which {} it is borrowed from",
1946 "this function's return type contains a borrowed value, \
1947 but the signature does not say whether it is borrowed from {}",
1954 crate fn report_elided_lifetime_in_ty(&self, lifetime_refs
: &[&hir
::Lifetime
]) {
1955 let Some(missing_lifetime
) = lifetime_refs
.iter().find(|lt
| {
1956 lt
.name
== hir
::LifetimeName
::Implicit(true)
1959 let mut spans
: Vec
<_
> = lifetime_refs
.iter().map(|lt
| lt
.span
).collect();
1961 let mut spans_dedup
= spans
.clone();
1962 spans_dedup
.dedup();
1963 let spans_with_counts
: Vec
<_
> = spans_dedup
1965 .map(|sp
| (sp
, spans
.iter().filter(|nsp
| *nsp
== &sp
).count()))
1968 self.tcx
.struct_span_lint_hir(
1969 rustc_session
::lint
::builtin
::ELIDED_LIFETIMES_IN_PATHS
,
1970 missing_lifetime
.hir_id
,
1973 let mut db
= lint
.build("hidden lifetime parameters in types are deprecated");
1974 self.add_missing_lifetime_specifiers_label(
1977 &FxHashSet
::from_iter([kw
::UnderscoreLifetime
]),
1986 // FIXME(const_generics): This patches over an ICE caused by non-'static lifetimes in const
1987 // generics. We are disallowing this until we can decide on how we want to handle non-'static
1988 // lifetimes in const generics. See issue #74052 for discussion.
1989 crate fn emit_non_static_lt_in_const_generic_error(&self, lifetime_ref
: &hir
::Lifetime
) {
1990 let mut err
= struct_span_err
!(
1994 "use of non-static lifetime `{}` in const generic",
1998 "for more information, see issue #74052 \
1999 <https://github.com/rust-lang/rust/issues/74052>",
2004 crate fn is_trait_ref_fn_scope(&mut self, trait_ref
: &'tcx hir
::PolyTraitRef
<'tcx
>) -> bool
{
2005 if let def
::Res
::Def(_
, did
) = trait_ref
.trait_ref
.path
.res
{
2007 self.tcx
.lang_items().fn_once_trait(),
2008 self.tcx
.lang_items().fn_trait(),
2009 self.tcx
.lang_items().fn_mut_trait(),
2011 .contains(&Some(did
))
2013 let (span
, span_type
) = match &trait_ref
.bound_generic_params
{
2014 [] => (trait_ref
.span
.shrink_to_lo(), ForLifetimeSpanType
::BoundEmpty
),
2015 [.., bound
] => (bound
.span
.shrink_to_hi(), ForLifetimeSpanType
::BoundTail
),
2017 self.missing_named_lifetime_spots
2018 .push(MissingLifetimeSpot
::HigherRanked { span, span_type }
);
2025 crate fn add_missing_lifetime_specifiers_label(
2027 err
: &mut Diagnostic
,
2028 mut spans_with_counts
: Vec
<(Span
, usize)>,
2029 lifetime_names
: &FxHashSet
<Symbol
>,
2030 lifetime_spans
: Vec
<Span
>,
2031 params
: &[ElisionFailureInfo
],
2033 let snippets
: Vec
<Option
<String
>> = spans_with_counts
2035 .map(|(span
, _
)| self.tcx
.sess
.source_map().span_to_snippet(*span
).ok())
2038 // Empty generics are marked with a span of "<", but since from now on
2039 // that information is in the snippets it can be removed from the spans.
2040 for ((span
, _
), snippet
) in spans_with_counts
.iter_mut().zip(&snippets
) {
2041 if snippet
.as_deref() == Some("<") {
2042 *span
= span
.shrink_to_hi();
2046 for &(span
, count
) in &spans_with_counts
{
2050 "expected {} lifetime parameter{}",
2051 if count
== 1 { "named".to_string() }
else { count.to_string() }
,
2057 let suggest_existing
=
2058 |err
: &mut Diagnostic
,
2060 formatters
: Vec
<Option
<Box
<dyn Fn(&str) -> String
>>>| {
2061 if let Some(MissingLifetimeSpot
::HigherRanked { span: for_span, span_type }
) =
2062 self.missing_named_lifetime_spots
.iter().rev().next()
2064 // When we have `struct S<'a>(&'a dyn Fn(&X) -> &X);` we want to not only suggest
2065 // using `'a`, but also introduce the concept of HRLTs by suggesting
2066 // `struct S<'a>(&'a dyn for<'b> Fn(&X) -> &'b X);`. (#72404)
2067 let mut introduce_suggestion
= vec
![];
2069 let a_to_z_repeat_n
= |n
| {
2070 (b'a'
..=b'z'
).map(move |c
| {
2071 let mut s
= '
\''
.to_string();
2072 s
.extend(std
::iter
::repeat(char::from(c
)).take(n
));
2077 // If all single char lifetime names are present, we wrap around and double the chars.
2079 .flat_map(a_to_z_repeat_n
)
2080 .find(|lt
| !lifetime_names
.contains(&Symbol
::intern(<
)))
2083 "consider making the {} lifetime-generic with a new `{}` lifetime",
2088 "for more information on higher-ranked polymorphism, visit \
2089 https://doc.rust-lang.org/nomicon/hrtb.html",
2091 let for_sugg
= span_type
.suggestion(<_name
);
2092 for param
in params
{
2093 if let Ok(snippet
) = self.tcx
.sess
.source_map().span_to_snippet(param
.span
)
2095 if snippet
.starts_with('
&'
) && !snippet
.starts_with("&'") {
2096 introduce_suggestion
2097 .push((param
.span
, format
!("&{} {}", lt_name
, &snippet
[1..])));
2098 } else if let Some(stripped
) = snippet
.strip_prefix("&'_ ") {
2099 introduce_suggestion
2100 .push((param
.span
, format
!("&{} {}", lt_name
, stripped
)));
2104 introduce_suggestion
.push((*for_span
, for_sugg
));
2105 for ((span
, _
), formatter
) in spans_with_counts
.iter().zip(formatters
.iter()) {
2106 if let Some(formatter
) = formatter
{
2107 introduce_suggestion
.push((*span
, formatter(<_name
)));
2110 err
.multipart_suggestion_verbose(
2112 introduce_suggestion
,
2113 Applicability
::MaybeIncorrect
,
2117 let spans_suggs
: Vec
<_
> = formatters
2119 .zip(spans_with_counts
.iter())
2120 .filter_map(|(formatter
, (span
, _
))| {
2121 if let Some(formatter
) = formatter
{
2122 Some((*span
, formatter(name
)))
2128 if spans_suggs
.is_empty() {
2129 // If all the spans come from macros, we cannot extract snippets and then
2130 // `formatters` only contains None and `spans_suggs` is empty.
2133 err
.multipart_suggestion_verbose(
2135 "consider using the `{}` lifetime",
2136 lifetime_names
.iter().next().unwrap()
2139 Applicability
::MaybeIncorrect
,
2142 let suggest_new
= |err
: &mut Diagnostic
, suggs
: Vec
<Option
<String
>>| {
2143 for missing
in self.missing_named_lifetime_spots
.iter().rev() {
2144 let mut introduce_suggestion
= vec
![];
2147 introduce_suggestion
.push(match missing
{
2148 MissingLifetimeSpot
::Generics(generics
) => {
2149 if generics
.span
== DUMMY_SP
{
2150 // Account for malformed generics in the HIR. This shouldn't happen,
2151 // but if we make a mistake elsewhere, mainly by keeping something in
2152 // `missing_named_lifetime_spots` that we shouldn't, like associated
2153 // `const`s or making a mistake in the AST lowering we would provide
2154 // nonsensical suggestions. Guard against that by skipping these.
2158 msg
= "consider introducing a named lifetime parameter".to_string();
2159 should_break
= true;
2160 if let Some(param
) = generics
.params
.iter().find(|p
| {
2163 hir
::GenericParamKind
::Type { synthetic: true, .. }
2164 | hir
::GenericParamKind
::Lifetime
{
2165 kind
: hir
::LifetimeParamKind
::Elided
2169 (param
.span
.shrink_to_lo(), "'a, ".to_string())
2171 (generics
.span
, "<'a>".to_string())
2174 MissingLifetimeSpot
::HigherRanked { span, span_type }
=> {
2176 "consider making the {} lifetime-generic with a new `'a` lifetime",
2179 should_break
= false;
2181 "for more information on higher-ranked polymorphism, visit \
2182 https://doc.rust-lang.org/nomicon/hrtb.html",
2184 (*span
, span_type
.suggestion("'a"))
2186 MissingLifetimeSpot
::Static
=> {
2187 let mut spans_suggs
= Vec
::new();
2188 for ((span
, count
), snippet
) in
2189 spans_with_counts
.iter().copied().zip(snippets
.iter())
2191 let (span
, sugg
) = match snippet
.as_deref() {
2192 Some("&") => (span
.shrink_to_hi(), "'static ".to_owned()),
2193 Some("'_") => (span
, "'static".to_owned()),
2194 Some(snippet
) if !snippet
.ends_with('
>'
) => {
2198 std
::iter
::repeat("'static")
2200 .collect
::<Vec
<_
>>()
2203 } else if snippet
== "<" || snippet
== "(" {
2205 span
.shrink_to_hi(),
2206 std
::iter
::repeat("'static")
2208 .collect
::<Vec
<_
>>()
2213 span
.shrink_to_hi(),
2216 std
::iter
::repeat("'static")
2218 .collect
::<Vec
<_
>>()
2226 spans_suggs
.push((span
, sugg
.to_string()));
2228 err
.multipart_suggestion_verbose(
2229 "consider using the `'static` lifetime",
2231 Applicability
::MaybeIncorrect
,
2237 struct Lifetime(Span
, String
);
2239 fn is_unnamed(&self) -> bool
{
2240 self.1.starts_with('
&'
) && !self.1.starts_with("&'")
2242 fn is_underscore(&self) -> bool
{
2243 self.1.starts_with("&'_ ")
2245 fn is_named(&self) -> bool
{
2246 self.1.starts_with("&'")
2248 fn suggestion(&self, sugg
: String
) -> Option
<(Span
, String
)> {
2252 self.is_underscore(),
2254 sugg
.starts_with('
&'
),
2256 (true, _
, _
, false) => (self.span_unnamed_borrow(), sugg
),
2257 (true, _
, _
, true) => {
2258 (self.span_unnamed_borrow(), sugg
[1..].to_string())
2260 (_
, true, _
, false) => {
2261 (self.span_underscore_borrow(), sugg
.trim().to_string())
2263 (_
, true, _
, true) => {
2264 (self.span_underscore_borrow(), sugg
[1..].trim().to_string())
2266 (_
, _
, true, false) => {
2267 (self.span_named_borrow(), sugg
.trim().to_string())
2269 (_
, _
, true, true) => {
2270 (self.span_named_borrow(), sugg
[1..].trim().to_string())
2276 fn span_unnamed_borrow(&self) -> Span
{
2277 let lo
= self.0.lo() + BytePos(1);
2278 self.0.with_lo(lo
).with_hi(lo
)
2280 fn span_named_borrow(&self) -> Span
{
2281 let lo
= self.0.lo() + BytePos(1);
2284 fn span_underscore_borrow(&self) -> Span
{
2285 let lo
= self.0.lo() + BytePos(1);
2286 let hi
= lo
+ BytePos(2);
2287 self.0.with_lo(lo
).with_hi(hi
)
2291 for param
in params
{
2292 if let Ok(snippet
) = self.tcx
.sess
.source_map().span_to_snippet(param
.span
) {
2293 if let Some((span
, sugg
)) =
2294 Lifetime(param
.span
, snippet
).suggestion("'a ".to_string())
2296 introduce_suggestion
.push((span
, sugg
));
2300 for (span
, sugg
) in spans_with_counts
.iter().copied().zip(suggs
.iter()).filter_map(
2301 |((span
, _
), sugg
)| match &sugg
{
2302 Some(sugg
) => Some((span
, sugg
.to_string())),
2306 let (span
, sugg
) = self
2310 .span_to_snippet(span
)
2312 .and_then(|snippet
| Lifetime(span
, snippet
).suggestion(sugg
.clone()))
2313 .unwrap_or((span
, sugg
));
2314 introduce_suggestion
.push((span
, sugg
.to_string()));
2316 err
.multipart_suggestion_verbose(
2318 introduce_suggestion
,
2319 Applicability
::MaybeIncorrect
,
2327 let lifetime_names
: Vec
<_
> = lifetime_names
.iter().collect();
2328 match &lifetime_names
[..] {
2330 let mut suggs
: Vec
<Option
<Box
<dyn Fn(&str) -> String
>>> = Vec
::new();
2331 for (snippet
, (_
, count
)) in snippets
.iter().zip(spans_with_counts
.iter().copied())
2333 suggs
.push(match snippet
.as_deref() {
2334 Some("&") => Some(Box
::new(|name
| format
!("&{} ", name
))),
2335 Some("'_") => Some(Box
::new(|n
| n
.to_string())),
2336 Some("") => Some(Box
::new(move |n
| format
!("{}, ", n
).repeat(count
))),
2337 Some("<") => Some(Box
::new(move |n
| {
2338 std
::iter
::repeat(n
).take(count
).collect
::<Vec
<_
>>().join(", ")
2340 Some(snippet
) if !snippet
.ends_with('
>'
) => Some(Box
::new(move |name
| {
2344 std
::iter
::repeat(name
.to_string())
2346 .collect
::<Vec
<_
>>()
2353 suggest_existing(err
, name
.as_str(), suggs
);
2356 let mut suggs
= Vec
::new();
2357 for (snippet
, (_
, count
)) in
2358 snippets
.iter().cloned().zip(spans_with_counts
.iter().copied())
2360 suggs
.push(match snippet
.as_deref() {
2361 Some("&") => Some("&'a ".to_string()),
2362 Some("'_") => Some("'a".to_string()),
2364 Some(std
::iter
::repeat("'a, ").take(count
).collect
::<Vec
<_
>>().join(""))
2367 Some(std
::iter
::repeat("'a").take(count
).collect
::<Vec
<_
>>().join(", "))
2369 Some(snippet
) => Some(format
!(
2372 std
::iter
::repeat("'a").take(count
).collect
::<Vec
<_
>>().join(", "),
2377 suggest_new(err
, suggs
);
2379 lts
if lts
.len() > 1 => {
2380 err
.span_note(lifetime_spans
, "these named lifetimes are available to use");
2382 let mut spans_suggs
: Vec
<_
> = Vec
::new();
2383 for ((span
, _
), snippet
) in spans_with_counts
.iter().copied().zip(snippets
.iter()) {
2384 match snippet
.as_deref() {
2385 Some("") => spans_suggs
.push((span
, "'lifetime, ".to_string())),
2386 Some("&") => spans_suggs
2387 .push((span
.with_lo(span
.lo() + BytePos(1)), "'lifetime ".to_string())),
2392 if spans_suggs
.len() > 0 {
2393 // This happens when we have `Foo<T>` where we point at the space before `T`,
2394 // but this can be confusing so we give a suggestion with placeholders.
2395 err
.multipart_suggestion_verbose(
2396 "consider using one of the available lifetimes here",
2398 Applicability
::HasPlaceholders
,
2402 _
=> unreachable
!(),
2406 /// Non-static lifetimes are prohibited in anonymous constants under `min_const_generics`.
2407 /// This function will emit an error if `generic_const_exprs` is not enabled, the body identified by
2408 /// `body_id` is an anonymous constant and `lifetime_ref` is non-static.
2409 crate fn maybe_emit_forbidden_non_static_lifetime_error(
2411 body_id
: hir
::BodyId
,
2412 lifetime_ref
: &'tcx hir
::Lifetime
,
2414 let is_anon_const
= matches
!(
2415 self.tcx
.def_kind(self.tcx
.hir().body_owner_def_id(body_id
)),
2416 hir
::def
::DefKind
::AnonConst
2418 let is_allowed_lifetime
= matches
!(
2420 hir
::LifetimeName
::Implicit(_
)
2421 | hir
::LifetimeName
::Static
2422 | hir
::LifetimeName
::Underscore
2425 if !self.tcx
.lazy_normalization() && is_anon_const
&& !is_allowed_lifetime
{
2427 &self.tcx
.sess
.parse_sess
,
2428 sym
::generic_const_exprs
,
2430 "a non-static lifetime is not allowed in a `const`",