1 use crate::diagnostics
::{ImportSuggestion, LabelSuggestion, TypoSuggestion}
;
2 use crate::late
::lifetimes
::{ElisionFailureInfo, LifetimeContext}
;
3 use crate::late
::{AliasPossibility, LateResolutionVisitor, RibKind}
;
4 use crate::path_names_to_string
;
5 use crate::{CrateLint, Module, ModuleKind, ModuleOrUniformRoot}
;
6 use crate::{PathResult, PathSource, Segment}
;
8 use rustc_ast
::visit
::FnKind
;
9 use rustc_ast
::{self as ast, Expr, ExprKind, Item, ItemKind, NodeId, Path, Ty, TyKind}
;
10 use rustc_ast_pretty
::pprust
::path_segment_to_string
;
11 use rustc_data_structures
::fx
::FxHashSet
;
12 use rustc_errors
::{pluralize, struct_span_err, Applicability, DiagnosticBuilder}
;
14 use rustc_hir
::def
::Namespace
::{self, *}
;
15 use rustc_hir
::def
::{self, CtorKind, CtorOf, DefKind}
;
16 use rustc_hir
::def_id
::{DefId, CRATE_DEF_INDEX, LOCAL_CRATE}
;
17 use rustc_hir
::PrimTy
;
18 use rustc_session
::parse
::feature_err
;
19 use rustc_span
::hygiene
::MacroKind
;
20 use rustc_span
::lev_distance
::find_best_match_for_name
;
21 use rustc_span
::symbol
::{kw, sym, Ident, Symbol}
;
22 use rustc_span
::{BytePos, MultiSpan, Span, DUMMY_SP}
;
26 type Res
= def
::Res
<ast
::NodeId
>;
28 /// A field or associated item from self type suggested in case of resolution failure.
29 enum AssocSuggestion
{
37 impl AssocSuggestion
{
38 fn action(&self) -> &'
static str {
40 AssocSuggestion
::Field
=> "use the available field",
41 AssocSuggestion
::MethodWithSelf
=> "call the method with the fully-qualified path",
42 AssocSuggestion
::AssocFn
=> "call the associated function",
43 AssocSuggestion
::AssocConst
=> "use the associated `const`",
44 AssocSuggestion
::AssocType
=> "use the associated type",
49 crate enum MissingLifetimeSpot
<'tcx
> {
50 Generics(&'tcx hir
::Generics
<'tcx
>),
51 HigherRanked { span: Span, span_type: ForLifetimeSpanType }
,
55 crate enum ForLifetimeSpanType
{
62 impl ForLifetimeSpanType
{
63 crate fn descr(&self) -> &'
static str {
65 Self::BoundEmpty
| Self::BoundTail
=> "bound",
66 Self::TypeEmpty
| Self::TypeTail
=> "type",
70 crate fn suggestion(&self, sugg
: &str) -> String
{
72 Self::BoundEmpty
| Self::TypeEmpty
=> format
!("for<{}> ", sugg
),
73 Self::BoundTail
| Self::TypeTail
=> format
!(", {}", sugg
),
78 impl<'tcx
> Into
<MissingLifetimeSpot
<'tcx
>> for &'tcx hir
::Generics
<'tcx
> {
79 fn into(self) -> MissingLifetimeSpot
<'tcx
> {
80 MissingLifetimeSpot
::Generics(self)
84 fn is_self_type(path
: &[Segment
], namespace
: Namespace
) -> bool
{
85 namespace
== TypeNS
&& path
.len() == 1 && path
[0].ident
.name
== kw
::SelfUpper
88 fn is_self_value(path
: &[Segment
], namespace
: Namespace
) -> bool
{
89 namespace
== ValueNS
&& path
.len() == 1 && path
[0].ident
.name
== kw
::SelfLower
92 /// Gets the stringified path for an enum from an `ImportSuggestion` for an enum variant.
93 fn import_candidate_to_enum_paths(suggestion
: &ImportSuggestion
) -> (String
, String
) {
94 let variant_path
= &suggestion
.path
;
95 let variant_path_string
= path_names_to_string(variant_path
);
97 let path_len
= suggestion
.path
.segments
.len();
98 let enum_path
= ast
::Path
{
99 span
: suggestion
.path
.span
,
100 segments
: suggestion
.path
.segments
[0..path_len
- 1].to_vec(),
103 let enum_path_string
= path_names_to_string(&enum_path
);
105 (variant_path_string
, enum_path_string
)
108 impl<'a
: 'ast
, 'ast
> LateResolutionVisitor
<'a
, '_
, 'ast
> {
109 fn def_span(&self, def_id
: DefId
) -> Option
<Span
> {
111 LOCAL_CRATE
=> self.r
.opt_span(def_id
),
116 .guess_head_span(self.r
.cstore().get_span_untracked(def_id
, self.r
.session
)),
121 /// Handles error reporting for `smart_resolve_path_fragment` function.
122 /// Creates base error and amends it with one short label and possibly some longer helps/notes.
123 pub(crate) fn smart_resolve_report_errors(
127 source
: PathSource
<'_
>,
129 ) -> (DiagnosticBuilder
<'a
>, Vec
<ImportSuggestion
>) {
130 let ident_span
= path
.last().map_or(span
, |ident
| ident
.ident
.span
);
131 let ns
= source
.namespace();
132 let is_expected
= &|res
| source
.is_expected(res
);
133 let is_enum_variant
= &|res
| matches
!(res
, Res
::Def(DefKind
::Variant
, _
));
135 // Make the base error.
136 let expected
= source
.descr_expected();
137 let path_str
= Segment
::names_to_string(path
);
138 let item_str
= path
.last().unwrap().ident
;
139 let (base_msg
, fallback_label
, base_span
, could_be_expr
) = if let Some(res
) = res
{
141 format
!("expected {}, found {} `{}`", expected
, res
.descr(), path_str
),
142 format
!("not a {}", expected
),
145 Res
::Def(DefKind
::Fn
, _
) => {
146 // Verify whether this is a fn call or an Fn used as a type.
150 .span_to_snippet(span
)
151 .map(|snippet
| snippet
.ends_with('
)'
))
155 DefKind
::Ctor(..) | DefKind
::AssocFn
| DefKind
::Const
| DefKind
::AssocConst
,
160 | Res
::Local(_
) => true,
165 let item_span
= path
.last().unwrap().ident
.span
;
166 let (mod_prefix
, mod_str
) = if path
.len() == 1 {
167 (String
::new(), "this scope".to_string())
168 } else if path
.len() == 2 && path
[0].ident
.name
== kw
::PathRoot
{
169 (String
::new(), "the crate root".to_string())
171 let mod_path
= &path
[..path
.len() - 1];
173 match self.resolve_path(mod_path
, Some(TypeNS
), false, span
, CrateLint
::No
) {
174 PathResult
::Module(ModuleOrUniformRoot
::Module(module
)) => module
.res(),
177 .map_or(String
::new(), |res
| format
!("{} ", res
.descr()));
178 (mod_prefix
, format
!("`{}`", Segment
::names_to_string(mod_path
)))
181 format
!("cannot find {} `{}` in {}{}", expected
, item_str
, mod_prefix
, mod_str
),
182 if path_str
== "async" && expected
.starts_with("struct") {
183 "`async` blocks are only allowed in Rust 2018 or later".to_string()
185 format
!("not found in {}", mod_str
)
192 let code
= source
.error_code(res
.is_some());
193 let mut err
= self.r
.session
.struct_span_err_with_code(base_span
, &base_msg
, code
);
195 match (source
, self.diagnostic_metadata
.in_if_condition
) {
196 (PathSource
::Expr(_
), Some(Expr { span, kind: ExprKind::Assign(..), .. }
)) => {
197 err
.span_suggestion_verbose(
199 "you might have meant to use pattern matching",
201 Applicability
::MaybeIncorrect
,
203 self.r
.session
.if_let_suggestions
.borrow_mut().insert(*span
);
208 let is_assoc_fn
= self.self_type_is_available(span
);
209 // Emit help message for fake-self from other languages (e.g., `this` in Javascript).
210 if ["this", "my"].contains(&&*item_str
.as_str()) && is_assoc_fn
{
211 err
.span_suggestion_short(
213 "you might have meant to use `self` here instead",
215 Applicability
::MaybeIncorrect
,
217 if !self.self_value_is_available(path
[0].ident
.span
, span
) {
218 if let Some((FnKind
::Fn(_
, _
, sig
, ..), fn_span
)) =
219 &self.diagnostic_metadata
.current_function
221 let (span
, sugg
) = if let Some(param
) = sig
.decl
.inputs
.get(0) {
222 (param
.span
.shrink_to_lo(), "&self, ")
228 .span_through_char(*fn_span
, '
('
)
233 err
.span_suggestion_verbose(
235 "if you meant to use `self`, you are also missing a `self` receiver \
238 Applicability
::MaybeIncorrect
,
244 // Emit special messages for unresolved `Self` and `self`.
245 if is_self_type(path
, ns
) {
246 err
.code(rustc_errors
::error_code
!(E0411
));
249 "`Self` is only available in impls, traits, and type definitions".to_string(),
251 return (err
, Vec
::new());
253 if is_self_value(path
, ns
) {
254 debug
!("smart_resolve_path_fragment: E0424, source={:?}", source
);
256 err
.code(rustc_errors
::error_code
!(E0424
));
257 err
.span_label(span
, match source
{
258 PathSource
::Pat
=> "`self` value is a keyword and may not be bound to variables or shadowed"
260 _
=> "`self` value is a keyword only available in methods with a `self` parameter"
263 if let Some((fn_kind
, span
)) = &self.diagnostic_metadata
.current_function
{
264 // The current function has a `self' parameter, but we were unable to resolve
265 // a reference to `self`. This can only happen if the `self` identifier we
266 // are resolving came from a different hygiene context.
267 if fn_kind
.decl().inputs
.get(0).map_or(false, |p
| p
.is_self()) {
268 err
.span_label(*span
, "this function has a `self` parameter, but a macro invocation can only access identifiers it receives from parameters");
270 let doesnt
= if is_assoc_fn
{
271 let (span
, sugg
) = fn_kind
275 .map(|p
| (p
.span
.shrink_to_lo(), "&self, "))
281 .span_through_char(*span
, '
('
)
286 err
.span_suggestion_verbose(
288 "add a `self` receiver parameter to make the associated `fn` a method",
290 Applicability
::MaybeIncorrect
,
296 if let Some(ident
) = fn_kind
.ident() {
299 &format
!("this function {} have a `self` parameter", doesnt
),
304 return (err
, Vec
::new());
307 // Try to lookup name in more relaxed fashion for better error reporting.
308 let ident
= path
.last().unwrap().ident
;
309 let candidates
= self
311 .lookup_import_candidates(ident
, ns
, &self.parent_scope
, is_expected
)
313 .filter(|ImportSuggestion { did, .. }
| {
314 match (did
, res
.and_then(|res
| res
.opt_def_id())) {
315 (Some(suggestion_did
), Some(actual_did
)) => *suggestion_did
!= actual_did
,
319 .collect
::<Vec
<_
>>();
320 let crate_def_id
= DefId
::local(CRATE_DEF_INDEX
);
321 if candidates
.is_empty() && is_expected(Res
::Def(DefKind
::Enum
, crate_def_id
)) {
322 let enum_candidates
=
323 self.r
.lookup_import_candidates(ident
, ns
, &self.parent_scope
, is_enum_variant
);
325 if !enum_candidates
.is_empty() {
326 if let (PathSource
::Type
, Some(span
)) =
327 (source
, self.diagnostic_metadata
.current_type_ascription
.last())
333 .type_ascription_path_suggestions
337 // Already reported this issue on the lhs of the type ascription.
339 return (err
, candidates
);
343 let mut enum_candidates
= enum_candidates
345 .map(|suggestion
| import_candidate_to_enum_paths(&suggestion
))
346 .collect
::<Vec
<_
>>();
347 enum_candidates
.sort();
349 // Contextualize for E0412 "cannot find type", but don't belabor the point
350 // (that it's a variant) for E0573 "expected type, found variant".
351 let preamble
= if res
.is_none() {
352 let others
= match enum_candidates
.len() {
354 2 => " and 1 other".to_owned(),
355 n
=> format
!(" and {} others", n
),
357 format
!("there is an enum variant `{}`{}; ", enum_candidates
[0].0, others
)
361 let msg
= format
!("{}try using the variant's enum", preamble
);
363 err
.span_suggestions(
368 .map(|(_variant_path
, enum_ty_path
)| enum_ty_path
)
369 // Variants re-exported in prelude doesn't mean `prelude::v1` is the
371 // FIXME: is there a more principled way to do this that
372 // would work for other re-exports?
373 .filter(|enum_ty_path
| enum_ty_path
!= "std::prelude::v1")
374 // Also write `Option` rather than `std::prelude::v1::Option`.
375 .map(|enum_ty_path
| {
376 // FIXME #56861: DRY-er prelude filtering.
377 enum_ty_path
.trim_start_matches("std::prelude::v1::").to_owned()
379 Applicability
::MachineApplicable
,
383 if path
.len() == 1 && self.self_type_is_available(span
) {
384 if let Some(candidate
) = self.lookup_assoc_candidate(ident
, ns
, is_expected
) {
385 let self_is_available
= self.self_value_is_available(path
[0].ident
.span
, span
);
387 AssocSuggestion
::Field
=> {
388 if self_is_available
{
391 "you might have meant to use the available field",
392 format
!("self.{}", path_str
),
393 Applicability
::MachineApplicable
,
396 err
.span_label(span
, "a field by this name exists in `Self`");
399 AssocSuggestion
::MethodWithSelf
if self_is_available
=> {
402 "you might have meant to call the method",
403 format
!("self.{}", path_str
),
404 Applicability
::MachineApplicable
,
407 AssocSuggestion
::MethodWithSelf
408 | AssocSuggestion
::AssocFn
409 | AssocSuggestion
::AssocConst
410 | AssocSuggestion
::AssocType
=> {
413 &format
!("you might have meant to {}", candidate
.action()),
414 format
!("Self::{}", path_str
),
415 Applicability
::MachineApplicable
,
419 return (err
, candidates
);
422 // If the first argument in call is `self` suggest calling a method.
423 if let Some((call_span
, args_span
)) = self.call_has_self_arg(source
) {
424 let mut args_snippet
= String
::new();
425 if let Some(args_span
) = args_span
{
426 if let Ok(snippet
) = self.r
.session
.source_map().span_to_snippet(args_span
) {
427 args_snippet
= snippet
;
433 &format
!("try calling `{}` as a method", ident
),
434 format
!("self.{}({})", path_str
, args_snippet
),
435 Applicability
::MachineApplicable
,
437 return (err
, candidates
);
441 // Try Levenshtein algorithm.
442 let typo_sugg
= self.lookup_typo_candidate(path
, ns
, is_expected
, span
);
443 // Try context-dependent help if relaxed lookup didn't work.
444 if let Some(res
) = res
{
445 if self.smart_resolve_context_dependent_help(
453 // We do this to avoid losing a secondary span when we override the main error span.
454 self.r
.add_typo_suggestion(&mut err
, typo_sugg
, ident_span
);
455 return (err
, candidates
);
459 if !self.type_ascription_suggestion(&mut err
, base_span
) {
460 let mut fallback
= false;
462 PathSource
::Trait(AliasPossibility
::Maybe
),
463 Some(Res
::Def(DefKind
::Struct
| DefKind
::Enum
| DefKind
::Union
, _
)),
466 if let Some(bounds @
[_
, .., _
]) = self.diagnostic_metadata
.current_trait_object
{
468 let spans
: Vec
<Span
> = bounds
470 .map(|bound
| bound
.span())
471 .filter(|&sp
| sp
!= base_span
)
474 let start_span
= bounds
.iter().map(|bound
| bound
.span()).next().unwrap();
475 // `end_span` is the end of the poly trait ref (Foo + 'baz + Bar><)
476 let end_span
= bounds
.iter().map(|bound
| bound
.span()).last().unwrap();
477 // `last_bound_span` is the last bound of the poly trait ref (Foo + >'baz< + Bar)
478 let last_bound_span
= spans
.last().cloned().unwrap();
479 let mut multi_span
: MultiSpan
= spans
.clone().into();
481 let msg
= if sp
== last_bound_span
{
483 "...because of {} bound{}",
484 if bounds
.len() <= 2 { "this" }
else { "these" }
,
485 if bounds
.len() <= 2 { "" }
else { "s" }
,
490 multi_span
.push_span_label(sp
, msg
);
492 multi_span
.push_span_label(
494 "expected this type to be a trait...".to_string(),
498 "`+` is used to constrain a \"trait object\" type with lifetimes or \
499 auto-traits; structs and enums can't be bound in that way",
501 if bounds
.iter().all(|bound
| match bound
{
502 ast
::GenericBound
::Outlives(_
) => true,
503 ast
::GenericBound
::Trait(tr
, _
) => tr
.span
== base_span
,
505 let mut sugg
= vec
![];
506 if base_span
!= start_span
{
507 sugg
.push((start_span
.until(base_span
), String
::new()));
509 if base_span
!= end_span
{
510 sugg
.push((base_span
.shrink_to_hi().to(end_span
), String
::new()));
513 err
.multipart_suggestion(
514 "if you meant to use a type and not a trait here, remove the bounds",
516 Applicability
::MaybeIncorrect
,
522 fallback
|= self.restrict_assoc_type_in_where_clause(span
, &mut err
);
524 if !self.r
.add_typo_suggestion(&mut err
, typo_sugg
, ident_span
) {
526 match self.diagnostic_metadata
.current_let_binding
{
527 Some((pat_sp
, Some(ty_sp
), None
))
528 if ty_sp
.contains(base_span
) && could_be_expr
=>
530 err
.span_suggestion_short(
531 pat_sp
.between(ty_sp
),
532 "use `=` if you meant to assign",
534 Applicability
::MaybeIncorrect
,
542 err
.span_label(base_span
, fallback_label
);
545 if let Some(err_code
) = &err
.code
{
546 if err_code
== &rustc_errors
::error_code
!(E0425
) {
547 for label_rib
in &self.label_ribs
{
548 for (label_ident
, node_id
) in &label_rib
.bindings
{
549 if format
!("'{}", ident
) == label_ident
.to_string() {
550 err
.span_label(label_ident
.span
, "a label with a similar name exists");
551 if let PathSource
::Expr(Some(Expr
{
552 kind
: ExprKind
::Break(None
, Some(_
)),
558 "use the similarly named label",
559 label_ident
.name
.to_string(),
560 Applicability
::MaybeIncorrect
,
562 // Do not lint against unused label when we suggest them.
563 self.diagnostic_metadata
.unused_labels
.remove(node_id
);
574 /// Given `where <T as Bar>::Baz: String`, suggest `where T: Bar<Baz = String>`.
575 fn restrict_assoc_type_in_where_clause(
578 err
: &mut DiagnosticBuilder
<'_
>,
580 // Detect that we are actually in a `where` predicate.
581 let (bounded_ty
, bounds
, where_span
) =
582 if let Some(ast
::WherePredicate
::BoundPredicate(ast
::WhereBoundPredicate
{
584 bound_generic_params
,
587 })) = self.diagnostic_metadata
.current_where_predicate
589 if !bound_generic_params
.is_empty() {
592 (bounded_ty
, bounds
, span
)
597 // Confirm that the target is an associated type.
598 let (ty
, position
, path
) = if let ast
::TyKind
::Path(
599 Some(ast
::QSelf { ty, position, .. }
),
603 // use this to verify that ident is a type param.
604 let partial_res
= if let Ok(Some(partial_res
)) = self.resolve_qpath_anywhere(
607 &Segment
::from_path(path
),
618 partial_res
.base_res(),
619 hir
::def
::Res
::Def(hir
::def
::DefKind
::AssocTy
, _
)
620 ) && partial_res
.unresolved_segments() == 0)
629 if let ast
::TyKind
::Path(None
, type_param_path
) = &ty
.peel_refs().kind
{
630 // Confirm that the `SelfTy` is a type parameter.
631 let partial_res
= if let Ok(Some(partial_res
)) = self.resolve_qpath_anywhere(
634 &Segment
::from_path(type_param_path
),
645 partial_res
.base_res(),
646 hir
::def
::Res
::Def(hir
::def
::DefKind
::TyParam
, _
)
647 ) && partial_res
.unresolved_segments() == 0)
652 [ast
::PathSegment { ident: constrain_ident, args: None, .. }
],
653 [ast
::GenericBound
::Trait(poly_trait_ref
, ast
::TraitBoundModifier
::None
)],
654 ) = (&type_param_path
.segments
[..], &bounds
[..])
656 if let [ast
::PathSegment { ident, args: None, .. }
] =
657 &poly_trait_ref
.trait_ref
.path
.segments
[..]
659 if ident
.span
== span
{
660 err
.span_suggestion_verbose(
662 &format
!("constrain the associated type to `{}`", ident
),
668 .span_to_snippet(ty
.span
) // Account for `<&'a T as Foo>::Bar`.
669 .unwrap_or_else(|_
| constrain_ident
.to_string()),
670 path
.segments
[..*position
]
672 .map(|segment
| path_segment_to_string(segment
))
675 path
.segments
[*position
..]
677 .map(|segment
| path_segment_to_string(segment
))
682 Applicability
::MaybeIncorrect
,
692 /// Check if the source is call expression and the first argument is `self`. If true,
693 /// return the span of whole call and the span for all arguments expect the first one (`self`).
694 fn call_has_self_arg(&self, source
: PathSource
<'_
>) -> Option
<(Span
, Option
<Span
>)> {
695 let mut has_self_arg
= None
;
696 if let PathSource
::Expr(Some(parent
)) = source
{
698 ExprKind
::Call(_
, args
) if !args
.is_empty() => {
699 let mut expr_kind
= &args
[0].kind
;
702 ExprKind
::Path(_
, arg_name
) if arg_name
.segments
.len() == 1 => {
703 if arg_name
.segments
[0].ident
.name
== kw
::SelfLower
{
704 let call_span
= parent
.span
;
705 let tail_args_span
= if args
.len() > 1 {
708 args
.last().unwrap().span
.hi(),
714 has_self_arg
= Some((call_span
, tail_args_span
));
718 ExprKind
::AddrOf(_
, _
, expr
) => expr_kind
= &expr
.kind
,
729 fn followed_by_brace(&self, span
: Span
) -> (bool
, Option
<Span
>) {
730 // HACK(estebank): find a better way to figure out that this was a
731 // parser issue where a struct literal is being used on an expression
732 // where a brace being opened means a block is being started. Look
733 // ahead for the next text to see if `span` is followed by a `{`.
734 let sm
= self.r
.session
.source_map();
737 sp
= sm
.next_point(sp
);
738 match sm
.span_to_snippet(sp
) {
740 if snippet
.chars().any(|c
| !c
.is_whitespace()) {
747 let followed_by_brace
= matches
!(sm
.span_to_snippet(sp
), Ok(ref snippet
) if snippet
== "{");
748 // In case this could be a struct literal that needs to be surrounded
749 // by parentheses, find the appropriate span.
751 let mut closing_brace
= None
;
753 sp
= sm
.next_point(sp
);
754 match sm
.span_to_snippet(sp
) {
757 closing_brace
= Some(span
.to(sp
));
764 // The bigger the span, the more likely we're incorrect --
765 // bound it to 100 chars long.
770 (followed_by_brace
, closing_brace
)
773 /// Provides context-dependent help for errors reported by the `smart_resolve_path_fragment`
775 /// Returns `true` if able to provide context-dependent help.
776 fn smart_resolve_context_dependent_help(
778 err
: &mut DiagnosticBuilder
<'a
>,
780 source
: PathSource
<'_
>,
783 fallback_label
: &str,
785 let ns
= source
.namespace();
786 let is_expected
= &|res
| source
.is_expected(res
);
788 let path_sep
= |err
: &mut DiagnosticBuilder
<'_
>, expr
: &Expr
| match expr
.kind
{
789 ExprKind
::Field(_
, ident
) => {
792 "use the path separator to refer to an item",
793 format
!("{}::{}", path_str
, ident
),
794 Applicability
::MaybeIncorrect
,
798 ExprKind
::MethodCall(ref segment
, ..) => {
799 let span
= expr
.span
.with_hi(segment
.ident
.span
.hi());
802 "use the path separator to refer to an item",
803 format
!("{}::{}", path_str
, segment
.ident
),
804 Applicability
::MaybeIncorrect
,
811 let mut bad_struct_syntax_suggestion
= |def_id
: DefId
| {
812 let (followed_by_brace
, closing_brace
) = self.followed_by_brace(span
);
815 PathSource
::Expr(Some(
816 parent @ Expr { kind: ExprKind::Field(..) | ExprKind::MethodCall(..), .. }
,
817 )) if path_sep(err
, &parent
) => {}
823 | ExprKind
::Binary(..)
824 | ExprKind
::Unary(..)
826 | ExprKind
::While(..)
827 | ExprKind
::ForLoop(..)
828 | ExprKind
::Match(..),
831 ) if followed_by_brace
=> {
832 if let Some(sp
) = closing_brace
{
833 err
.span_label(span
, fallback_label
);
834 err
.multipart_suggestion(
835 "surround the struct literal with parentheses",
837 (sp
.shrink_to_lo(), "(".to_string()),
838 (sp
.shrink_to_hi(), ")".to_string()),
840 Applicability
::MaybeIncorrect
,
844 span
, // Note the parentheses surrounding the suggestion below
846 "you might want to surround a struct literal with parentheses: \
847 `({} {{ /* fields */ }})`?",
853 PathSource
::Expr(_
) | PathSource
::TupleStruct(..) | PathSource
::Pat
=> {
854 let span
= match &source
{
855 PathSource
::Expr(Some(Expr
{
856 span
, kind
: ExprKind
::Call(_
, _
), ..
858 | PathSource
::TupleStruct(span
, _
) => {
859 // We want the main underline to cover the suggested code as well for
866 if let Some(span
) = self.def_span(def_id
) {
867 err
.span_label(span
, &format
!("`{}` defined here", path_str
));
869 let (tail
, descr
, applicability
) = match source
{
870 PathSource
::Pat
| PathSource
::TupleStruct(..) => {
871 ("", "pattern", Applicability
::MachineApplicable
)
873 _
=> (": val", "literal", Applicability
::HasPlaceholders
),
875 let (fields
, applicability
) = match self.r
.field_names
.get(&def_id
) {
879 .map(|f
| format
!("{}{}", f
.node
, tail
))
880 .collect
::<Vec
<String
>>()
884 None
=> ("/* fields */".to_string(), Applicability
::HasPlaceholders
),
886 let pad
= match self.r
.field_names
.get(&def_id
) {
887 Some(fields
) if fields
.is_empty() => "",
892 &format
!("use struct {} syntax instead", descr
),
893 format
!("{path_str} {{{pad}{fields}{pad}}}"),
898 err
.span_label(span
, fallback_label
);
903 match (res
, source
) {
904 (Res
::Def(DefKind
::Macro(MacroKind
::Bang
), _
), _
) => {
905 err
.span_label(span
, fallback_label
);
906 err
.span_suggestion_verbose(
908 "use `!` to invoke the macro",
910 Applicability
::MaybeIncorrect
,
912 if path_str
== "try" && span
.rust_2015() {
913 err
.note("if you want the `try` keyword, you need Rust 2018 or later");
916 (Res
::Def(DefKind
::TyAlias
, def_id
), PathSource
::Trait(_
)) => {
917 err
.span_label(span
, "type aliases cannot be used as traits");
918 if self.r
.session
.is_nightly_build() {
919 let msg
= "you might have meant to use `#![feature(trait_alias)]` instead of a \
921 if let Some(span
) = self.def_span(def_id
) {
922 err
.span_help(span
, msg
);
928 (Res
::Def(DefKind
::Mod
, _
), PathSource
::Expr(Some(parent
))) => {
929 if !path_sep(err
, &parent
) {
934 Res
::Def(DefKind
::Enum
, def_id
),
935 PathSource
::TupleStruct(..) | PathSource
::Expr(..),
939 .current_type_ascription
945 .type_ascription_path_suggestions
952 // We already suggested changing `:` into `::` during parsing.
956 self.suggest_using_enum_variant(err
, source
, def_id
, span
);
958 (Res
::Def(DefKind
::Struct
, def_id
), _
) if ns
== ValueNS
=> {
959 let (ctor_def
, ctor_vis
, fields
) =
960 if let Some(struct_ctor
) = self.r
.struct_constructors
.get(&def_id
).cloned() {
963 bad_struct_syntax_suggestion(def_id
);
967 let is_accessible
= self.r
.is_accessible_from(ctor_vis
, self.parent_scope
.module
);
968 if !is_expected(ctor_def
) || is_accessible
{
972 let field_spans
= match source
{
973 // e.g. `if let Enum::TupleVariant(field1, field2) = _`
974 PathSource
::TupleStruct(_
, pattern_spans
) => {
975 err
.set_primary_message(
976 "cannot match against a tuple struct which contains private fields",
979 // Use spans of the tuple struct pattern.
980 Some(Vec
::from(pattern_spans
))
982 // e.g. `let _ = Enum::TupleVariant(field1, field2);`
983 _
if source
.is_call() => {
984 err
.set_primary_message(
985 "cannot initialize a tuple struct which contains private fields",
988 // Use spans of the tuple struct definition.
992 .map(|fields
| fields
.iter().map(|f
| f
.span
).collect
::<Vec
<_
>>())
998 field_spans
.filter(|spans
| spans
.len() > 0 && fields
.len() == spans
.len())
1000 let non_visible_spans
: Vec
<Span
> = fields
1003 .filter(|(vis
, _
)| {
1004 !self.r
.is_accessible_from(**vis
, self.parent_scope
.module
)
1006 .map(|(_
, span
)| *span
)
1009 if non_visible_spans
.len() > 0 {
1010 let mut m
: rustc_span
::MultiSpan
= non_visible_spans
.clone().into();
1013 .for_each(|s
| m
.push_span_label(s
, "private field".to_string()));
1014 err
.span_note(m
, "constructor is not visible here due to private fields");
1022 "constructor is not visible here due to private fields".to_string(),
1027 DefKind
::Union
| DefKind
::Variant
| DefKind
::Ctor(_
, CtorKind
::Fictive
),
1031 ) if ns
== ValueNS
=> {
1032 bad_struct_syntax_suggestion(def_id
);
1034 (Res
::Def(DefKind
::Ctor(_
, CtorKind
::Fn
), def_id
), _
) if ns
== ValueNS
=> {
1035 if let Some(span
) = self.def_span(def_id
) {
1036 err
.span_label(span
, &format
!("`{}` defined here", path_str
));
1039 self.r
.field_names
.get(&def_id
).map_or("/* fields */".to_string(), |fields
| {
1040 vec
!["_"; fields
.len()].join(", ")
1042 err
.span_suggestion(
1044 "use the tuple variant pattern syntax instead",
1045 format
!("{}({})", path_str
, fields
),
1046 Applicability
::HasPlaceholders
,
1049 (Res
::SelfTy(..), _
) if ns
== ValueNS
=> {
1050 err
.span_label(span
, fallback_label
);
1051 err
.note("can't use `Self` as a constructor, you must use the implemented struct");
1053 (Res
::Def(DefKind
::TyAlias
| DefKind
::AssocTy
, _
), _
) if ns
== ValueNS
=> {
1054 err
.note("can't use a type alias as a constructor");
1061 fn lookup_assoc_candidate
<FilterFn
>(
1065 filter_fn
: FilterFn
,
1066 ) -> Option
<AssocSuggestion
>
1068 FilterFn
: Fn(Res
) -> bool
,
1070 fn extract_node_id(t
: &Ty
) -> Option
<NodeId
> {
1072 TyKind
::Path(None
, _
) => Some(t
.id
),
1073 TyKind
::Rptr(_
, ref mut_ty
) => extract_node_id(&mut_ty
.ty
),
1074 // This doesn't handle the remaining `Ty` variants as they are not
1075 // that commonly the self_type, it might be interesting to provide
1076 // support for those in future.
1081 // Fields are generally expected in the same contexts as locals.
1082 if filter_fn(Res
::Local(ast
::DUMMY_NODE_ID
)) {
1083 if let Some(node_id
) =
1084 self.diagnostic_metadata
.current_self_type
.as_ref().and_then(extract_node_id
)
1086 // Look for a field with the same name in the current self_type.
1087 if let Some(resolution
) = self.r
.partial_res_map
.get(&node_id
) {
1088 match resolution
.base_res() {
1089 Res
::Def(DefKind
::Struct
| DefKind
::Union
, did
)
1090 if resolution
.unresolved_segments() == 0 =>
1092 if let Some(field_names
) = self.r
.field_names
.get(&did
) {
1095 .any(|&field_name
| ident
.name
== field_name
.node
)
1097 return Some(AssocSuggestion
::Field
);
1107 if let Some(items
) = self.diagnostic_metadata
.current_trait_assoc_items
{
1108 for assoc_item
in &items
[..] {
1109 if assoc_item
.ident
== ident
{
1110 return Some(match &assoc_item
.kind
{
1111 ast
::AssocItemKind
::Const(..) => AssocSuggestion
::AssocConst
,
1112 ast
::AssocItemKind
::Fn(box ast
::FnKind(_
, sig
, ..))
1113 if sig
.decl
.has_self() =>
1115 AssocSuggestion
::MethodWithSelf
1117 ast
::AssocItemKind
::Fn(..) => AssocSuggestion
::AssocFn
,
1118 ast
::AssocItemKind
::TyAlias(..) => AssocSuggestion
::AssocType
,
1119 ast
::AssocItemKind
::MacCall(_
) => continue,
1125 // Look for associated items in the current trait.
1126 if let Some((module
, _
)) = self.current_trait_ref
{
1127 if let Ok(binding
) = self.r
.resolve_ident_in_module(
1128 ModuleOrUniformRoot
::Module(module
),
1135 let res
= binding
.res();
1137 if self.r
.has_self
.contains(&res
.def_id()) {
1138 return Some(AssocSuggestion
::MethodWithSelf
);
1141 Res
::Def(DefKind
::AssocFn
, _
) => return Some(AssocSuggestion
::AssocFn
),
1142 Res
::Def(DefKind
::AssocConst
, _
) => {
1143 return Some(AssocSuggestion
::AssocConst
);
1145 Res
::Def(DefKind
::AssocTy
, _
) => {
1146 return Some(AssocSuggestion
::AssocType
);
1158 fn lookup_typo_candidate(
1162 filter_fn
: &impl Fn(Res
) -> bool
,
1164 ) -> Option
<TypoSuggestion
> {
1165 let mut names
= Vec
::new();
1166 if path
.len() == 1 {
1167 // Search in lexical scope.
1168 // Walk backwards up the ribs in scope and collect candidates.
1169 for rib
in self.ribs
[ns
].iter().rev() {
1170 // Locals and type parameters
1171 for (ident
, &res
) in &rib
.bindings
{
1173 names
.push(TypoSuggestion
::from_res(ident
.name
, res
));
1177 if let RibKind
::ModuleRibKind(module
) = rib
.kind
{
1178 // Items from this module
1179 self.r
.add_module_candidates(module
, &mut names
, &filter_fn
);
1181 if let ModuleKind
::Block(..) = module
.kind
{
1182 // We can see through blocks
1184 // Items from the prelude
1185 if !module
.no_implicit_prelude
{
1186 let extern_prelude
= self.r
.extern_prelude
.clone();
1187 names
.extend(extern_prelude
.iter().flat_map(|(ident
, _
)| {
1188 self.r
.crate_loader
.maybe_process_path_extern(ident
.name
).and_then(
1190 let crate_mod
= Res
::Def(
1192 DefId { krate: crate_id, index: CRATE_DEF_INDEX }
,
1195 if filter_fn(crate_mod
) {
1196 Some(TypoSuggestion
::from_res(ident
.name
, crate_mod
))
1204 if let Some(prelude
) = self.r
.prelude
{
1205 self.r
.add_module_candidates(prelude
, &mut names
, &filter_fn
);
1212 // Add primitive types to the mix
1213 if filter_fn(Res
::PrimTy(PrimTy
::Bool
)) {
1215 self.r
.primitive_type_table
.primitive_types
.iter().map(|(name
, prim_ty
)| {
1216 TypoSuggestion
::from_res(*name
, Res
::PrimTy(*prim_ty
))
1221 // Search in module.
1222 let mod_path
= &path
[..path
.len() - 1];
1223 if let PathResult
::Module(module
) =
1224 self.resolve_path(mod_path
, Some(TypeNS
), false, span
, CrateLint
::No
)
1226 if let ModuleOrUniformRoot
::Module(module
) = module
{
1227 self.r
.add_module_candidates(module
, &mut names
, &filter_fn
);
1232 let name
= path
[path
.len() - 1].ident
.name
;
1233 // Make sure error reporting is deterministic.
1234 names
.sort_by_cached_key(|suggestion
| suggestion
.candidate
.as_str());
1236 match find_best_match_for_name(
1237 &names
.iter().map(|suggestion
| suggestion
.candidate
).collect
::<Vec
<Symbol
>>(),
1241 Some(found
) if found
!= name
=> {
1242 names
.into_iter().find(|suggestion
| suggestion
.candidate
== found
)
1248 /// Only used in a specific case of type ascription suggestions
1249 fn get_colon_suggestion_span(&self, start
: Span
) -> Span
{
1250 let sm
= self.r
.session
.source_map();
1251 start
.to(sm
.next_point(start
))
1254 fn type_ascription_suggestion(&self, err
: &mut DiagnosticBuilder
<'_
>, base_span
: Span
) -> bool
{
1255 let sm
= self.r
.session
.source_map();
1256 let base_snippet
= sm
.span_to_snippet(base_span
);
1257 if let Some(&sp
) = self.diagnostic_metadata
.current_type_ascription
.last() {
1258 if let Ok(snippet
) = sm
.span_to_snippet(sp
) {
1259 let len
= snippet
.trim_end().len() as u32;
1260 if snippet
.trim() == ":" {
1262 sp
.with_lo(sp
.lo() + BytePos(len
- 1)).with_hi(sp
.lo() + BytePos(len
));
1263 let mut show_label
= true;
1264 if sm
.is_multiline(sp
) {
1265 err
.span_suggestion_short(
1267 "maybe you meant to write `;` here",
1269 Applicability
::MaybeIncorrect
,
1272 let after_colon_sp
=
1273 self.get_colon_suggestion_span(colon_sp
.shrink_to_hi());
1274 if snippet
.len() == 1 {
1276 err
.span_suggestion(
1278 "maybe you meant to write a path separator here",
1280 Applicability
::MaybeIncorrect
,
1287 .type_ascription_path_suggestions
1294 if let Ok(base_snippet
) = base_snippet
{
1295 let mut sp
= after_colon_sp
;
1297 // Try to find an assignment
1298 sp
= sm
.next_point(sp
);
1299 let snippet
= sm
.span_to_snippet(sp
.to(sm
.next_point(sp
)));
1301 Ok(ref x
) if x
.as_str() == "=" => {
1302 err
.span_suggestion(
1304 "maybe you meant to write an assignment here",
1305 format
!("let {}", base_snippet
),
1306 Applicability
::MaybeIncorrect
,
1311 Ok(ref x
) if x
.as_str() == "\n" => break,
1321 "expecting a type here because of type ascription",
1331 fn find_module(&mut self, def_id
: DefId
) -> Option
<(Module
<'a
>, ImportSuggestion
)> {
1332 let mut result
= None
;
1333 let mut seen_modules
= FxHashSet
::default();
1334 let mut worklist
= vec
![(self.r
.graph_root
, Vec
::new())];
1336 while let Some((in_module
, path_segments
)) = worklist
.pop() {
1337 // abort if the module is already found
1338 if result
.is_some() {
1342 in_module
.for_each_child(self.r
, |_
, ident
, _
, name_binding
| {
1343 // abort if the module is already found or if name_binding is private external
1344 if result
.is_some() || !name_binding
.vis
.is_visible_locally() {
1347 if let Some(module
) = name_binding
.module() {
1349 let mut path_segments
= path_segments
.clone();
1350 path_segments
.push(ast
::PathSegment
::from_ident(ident
));
1351 let module_def_id
= module
.def_id().unwrap();
1352 if module_def_id
== def_id
{
1354 Path { span: name_binding.span, segments: path_segments, tokens: None }
;
1365 // add the module to the lookup
1366 if seen_modules
.insert(module_def_id
) {
1367 worklist
.push((module
, path_segments
));
1377 fn collect_enum_ctors(&mut self, def_id
: DefId
) -> Option
<Vec
<(Path
, DefId
, CtorKind
)>> {
1378 self.find_module(def_id
).map(|(enum_module
, enum_import_suggestion
)| {
1379 let mut variants
= Vec
::new();
1380 enum_module
.for_each_child(self.r
, |_
, ident
, _
, name_binding
| {
1381 if let Res
::Def(DefKind
::Ctor(CtorOf
::Variant
, kind
), def_id
) = name_binding
.res() {
1382 let mut segms
= enum_import_suggestion
.path
.segments
.clone();
1383 segms
.push(ast
::PathSegment
::from_ident(ident
));
1384 let path
= Path { span: name_binding.span, segments: segms, tokens: None }
;
1385 variants
.push((path
, def_id
, kind
));
1392 /// Adds a suggestion for using an enum's variant when an enum is used instead.
1393 fn suggest_using_enum_variant(
1395 err
: &mut DiagnosticBuilder
<'a
>,
1396 source
: PathSource
<'_
>,
1400 let variants
= match self.collect_enum_ctors(def_id
) {
1401 Some(variants
) => variants
,
1403 err
.note("you might have meant to use one of the enum's variants");
1408 let suggest_only_tuple_variants
=
1409 matches
!(source
, PathSource
::TupleStruct(..)) || source
.is_call();
1410 if suggest_only_tuple_variants
{
1411 // Suggest only tuple variants regardless of whether they have fields and do not
1412 // suggest path with added parenthesis.
1413 let mut suggestable_variants
= variants
1415 .filter(|(.., kind
)| *kind
== CtorKind
::Fn
)
1416 .map(|(variant
, ..)| path_names_to_string(variant
))
1417 .collect
::<Vec
<_
>>();
1419 let non_suggestable_variant_count
= variants
.len() - suggestable_variants
.len();
1421 let source_msg
= if source
.is_call() {
1423 } else if matches
!(source
, PathSource
::TupleStruct(..)) {
1429 if !suggestable_variants
.is_empty() {
1430 let msg
= if non_suggestable_variant_count
== 0 && suggestable_variants
.len() == 1 {
1431 format
!("try {} the enum's variant", source_msg
)
1433 format
!("try {} one of the enum's variants", source_msg
)
1436 err
.span_suggestions(
1439 suggestable_variants
.drain(..),
1440 Applicability
::MaybeIncorrect
,
1444 // If the enum has no tuple variants..
1445 if non_suggestable_variant_count
== variants
.len() {
1446 err
.help(&format
!("the enum has no tuple variants {}", source_msg
));
1449 // If there are also non-tuple variants..
1450 if non_suggestable_variant_count
== 1 {
1452 "you might have meant {} the enum's non-tuple variant",
1455 } else if non_suggestable_variant_count
>= 1 {
1457 "you might have meant {} one of the enum's non-tuple variants",
1462 let needs_placeholder
= |def_id
: DefId
, kind
: CtorKind
| {
1463 let has_no_fields
= self.r
.field_names
.get(&def_id
).map_or(false, |f
| f
.is_empty());
1465 CtorKind
::Const
=> false,
1466 CtorKind
::Fn
| CtorKind
::Fictive
if has_no_fields
=> false,
1471 let mut suggestable_variants
= variants
1473 .filter(|(_
, def_id
, kind
)| !needs_placeholder(*def_id
, *kind
))
1474 .map(|(variant
, _
, kind
)| (path_names_to_string(variant
), kind
))
1475 .map(|(variant
, kind
)| match kind
{
1476 CtorKind
::Const
=> variant
,
1477 CtorKind
::Fn
=> format
!("({}())", variant
),
1478 CtorKind
::Fictive
=> format
!("({} {{}})", variant
),
1480 .collect
::<Vec
<_
>>();
1482 if !suggestable_variants
.is_empty() {
1483 let msg
= if suggestable_variants
.len() == 1 {
1484 "you might have meant to use the following enum variant"
1486 "you might have meant to use one of the following enum variants"
1489 err
.span_suggestions(
1492 suggestable_variants
.drain(..),
1493 Applicability
::MaybeIncorrect
,
1497 let mut suggestable_variants_with_placeholders
= variants
1499 .filter(|(_
, def_id
, kind
)| needs_placeholder(*def_id
, *kind
))
1500 .map(|(variant
, _
, kind
)| (path_names_to_string(variant
), kind
))
1501 .filter_map(|(variant
, kind
)| match kind
{
1502 CtorKind
::Fn
=> Some(format
!("({}(/* fields */))", variant
)),
1503 CtorKind
::Fictive
=> Some(format
!("({} {{ /* fields */ }})", variant
)),
1506 .collect
::<Vec
<_
>>();
1508 if !suggestable_variants_with_placeholders
.is_empty() {
1510 suggestable_variants
.is_empty(),
1511 suggestable_variants_with_placeholders
.len(),
1513 (true, 1) => "the following enum variant is available",
1514 (true, _
) => "the following enum variants are available",
1515 (false, 1) => "alternatively, the following enum variant is available",
1516 (false, _
) => "alternatively, the following enum variants are also available",
1519 err
.span_suggestions(
1522 suggestable_variants_with_placeholders
.drain(..),
1523 Applicability
::HasPlaceholders
,
1528 if def_id
.is_local() {
1529 if let Some(span
) = self.def_span(def_id
) {
1530 err
.span_note(span
, "the enum is defined here");
1535 crate fn report_missing_type_error(
1538 ) -> Option
<(Span
, &'
static str, String
, Applicability
)> {
1539 let (ident
, span
) = match path
{
1540 [segment
] if !segment
.has_generic_args
=> {
1541 (segment
.ident
.to_string(), segment
.ident
.span
)
1545 let mut iter
= ident
.chars().map(|c
| c
.is_uppercase());
1546 let single_uppercase_char
=
1547 matches
!(iter
.next(), Some(true)) && matches
!(iter
.next(), None
);
1548 if !self.diagnostic_metadata
.currently_processing_generics
&& !single_uppercase_char
{
1551 match (self.diagnostic_metadata
.current_item
, single_uppercase_char
) {
1552 (Some(Item { kind: ItemKind::Fn(..), ident, .. }
), _
) if ident
.name
== sym
::main
=> {
1553 // Ignore `fn main()` as we don't want to suggest `fn main<T>()`
1558 kind @ ItemKind
::Fn(..)
1559 | kind @ ItemKind
::Enum(..)
1560 | kind @ ItemKind
::Struct(..)
1561 | kind @ ItemKind
::Union(..),
1566 | (Some(Item { kind, .. }
), false) => {
1567 // Likely missing type parameter.
1568 if let Some(generics
) = kind
.generics() {
1569 if span
.overlaps(generics
.span
) {
1570 // Avoid the following:
1571 // error[E0405]: cannot find trait `A` in this scope
1572 // --> $DIR/typo-suggestion-named-underscore.rs:CC:LL
1574 // L | fn foo<T: A>(x: T) {} // Shouldn't suggest underscore
1575 // | ^- help: you might be missing a type parameter: `, A`
1577 // | not found in this scope
1580 let msg
= "you might be missing a type parameter";
1581 let (span
, sugg
) = if let [.., param
] = &generics
.params
[..] {
1582 let span
= if let [.., bound
] = ¶m
.bounds
[..] {
1587 (span
, format
!(", {}", ident
))
1589 (generics
.span
, format
!("<{}>", ident
))
1591 // Do not suggest if this is coming from macro expansion.
1592 if !span
.from_expansion() {
1594 span
.shrink_to_hi(),
1597 Applicability
::MaybeIncorrect
,
1607 /// Given the target `label`, search the `rib_index`th label rib for similarly named labels,
1608 /// optionally returning the closest match and whether it is reachable.
1609 crate fn suggestion_for_label_in_rib(
1613 ) -> Option
<LabelSuggestion
> {
1614 // Are ribs from this `rib_index` within scope?
1615 let within_scope
= self.is_label_valid_from_rib(rib_index
);
1617 let rib
= &self.label_ribs
[rib_index
];
1621 .filter(|(id
, _
)| id
.span
.ctxt() == label
.span
.ctxt())
1622 .map(|(id
, _
)| id
.name
)
1623 .collect
::<Vec
<Symbol
>>();
1625 find_best_match_for_name(&names
, label
.name
, None
).map(|symbol
| {
1626 // Upon finding a similar name, get the ident that it was from - the span
1627 // contained within helps make a useful diagnostic. In addition, determine
1628 // whether this candidate is within scope.
1629 let (ident
, _
) = rib
.bindings
.iter().find(|(ident
, _
)| ident
.name
== symbol
).unwrap();
1630 (*ident
, within_scope
)
1635 impl<'tcx
> LifetimeContext
<'_
, 'tcx
> {
1636 crate fn report_missing_lifetime_specifiers(
1640 ) -> DiagnosticBuilder
<'tcx
> {
1645 "missing lifetime specifier{}",
1650 crate fn emit_undeclared_lifetime_error(&self, lifetime_ref
: &hir
::Lifetime
) {
1651 let mut err
= struct_span_err
!(
1655 "use of undeclared lifetime name `{}`",
1658 err
.span_label(lifetime_ref
.span
, "undeclared lifetime");
1659 let mut suggests_in_band
= false;
1660 for missing
in &self.missing_named_lifetime_spots
{
1662 MissingLifetimeSpot
::Generics(generics
) => {
1663 let (span
, sugg
) = if let Some(param
) = generics
.params
.iter().find(|p
| {
1666 hir
::GenericParamKind
::Type
{
1667 synthetic
: Some(hir
::SyntheticTyParamKind
::ImplTrait
),
1669 } | hir
::GenericParamKind
::Lifetime
{
1670 kind
: hir
::LifetimeParamKind
::Elided
,
1674 (param
.span
.shrink_to_lo(), format
!("{}, ", lifetime_ref
))
1676 suggests_in_band
= true;
1677 (generics
.span
, format
!("<{}>", lifetime_ref
))
1679 err
.span_suggestion(
1681 &format
!("consider introducing lifetime `{}` here", lifetime_ref
),
1683 Applicability
::MaybeIncorrect
,
1686 MissingLifetimeSpot
::HigherRanked { span, span_type }
=> {
1687 err
.span_suggestion(
1690 "consider making the {} lifetime-generic with a new `{}` lifetime",
1694 span_type
.suggestion(&lifetime_ref
.to_string()),
1695 Applicability
::MaybeIncorrect
,
1698 "for more information on higher-ranked polymorphism, visit \
1699 https://doc.rust-lang.org/nomicon/hrtb.html",
1705 if self.tcx
.sess
.is_nightly_build()
1706 && !self.tcx
.features().in_band_lifetimes
1710 "if you want to experiment with in-band lifetime bindings, \
1711 add `#![feature(in_band_lifetimes)]` to the crate attributes",
1717 // FIXME(const_generics): This patches over a ICE caused by non-'static lifetimes in const
1718 // generics. We are disallowing this until we can decide on how we want to handle non-'static
1719 // lifetimes in const generics. See issue #74052 for discussion.
1720 crate fn emit_non_static_lt_in_const_generic_error(&self, lifetime_ref
: &hir
::Lifetime
) {
1721 let mut err
= struct_span_err
!(
1725 "use of non-static lifetime `{}` in const generic",
1729 "for more information, see issue #74052 \
1730 <https://github.com/rust-lang/rust/issues/74052>",
1735 crate fn is_trait_ref_fn_scope(&mut self, trait_ref
: &'tcx hir
::PolyTraitRef
<'tcx
>) -> bool
{
1736 if let def
::Res
::Def(_
, did
) = trait_ref
.trait_ref
.path
.res
{
1738 self.tcx
.lang_items().fn_once_trait(),
1739 self.tcx
.lang_items().fn_trait(),
1740 self.tcx
.lang_items().fn_mut_trait(),
1742 .contains(&Some(did
))
1744 let (span
, span_type
) = match &trait_ref
.bound_generic_params
{
1745 [] => (trait_ref
.span
.shrink_to_lo(), ForLifetimeSpanType
::BoundEmpty
),
1746 [.., bound
] => (bound
.span
.shrink_to_hi(), ForLifetimeSpanType
::BoundTail
),
1748 self.missing_named_lifetime_spots
1749 .push(MissingLifetimeSpot
::HigherRanked { span, span_type }
);
1756 crate fn add_missing_lifetime_specifiers_label(
1758 err
: &mut DiagnosticBuilder
<'_
>,
1761 lifetime_names
: &FxHashSet
<Symbol
>,
1762 lifetime_spans
: Vec
<Span
>,
1763 params
: &[ElisionFailureInfo
],
1765 let snippet
= self.tcx
.sess
.source_map().span_to_snippet(span
).ok();
1770 "expected {} lifetime parameter{}",
1771 if count
== 1 { "named".to_string() }
else { count.to_string() }
,
1776 let suggest_existing
= |err
: &mut DiagnosticBuilder
<'_
>,
1778 formatter
: &dyn Fn(&str) -> String
| {
1779 if let Some(MissingLifetimeSpot
::HigherRanked { span: for_span, span_type }
) =
1780 self.missing_named_lifetime_spots
.iter().rev().next()
1782 // When we have `struct S<'a>(&'a dyn Fn(&X) -> &X);` we want to not only suggest
1783 // using `'a`, but also introduce the concept of HRLTs by suggesting
1784 // `struct S<'a>(&'a dyn for<'b> Fn(&X) -> &'b X);`. (#72404)
1785 let mut introduce_suggestion
= vec
![];
1787 let a_to_z_repeat_n
= |n
| {
1788 (b'a'
..=b'z'
).map(move |c
| {
1789 let mut s
= '
\''
.to_string();
1790 s
.extend(std
::iter
::repeat(char::from(c
)).take(n
));
1795 // If all single char lifetime names are present, we wrap around and double the chars.
1797 .flat_map(a_to_z_repeat_n
)
1798 .find(|lt
| !lifetime_names
.contains(&Symbol
::intern(<
)))
1801 "consider making the {} lifetime-generic with a new `{}` lifetime",
1806 "for more information on higher-ranked polymorphism, visit \
1807 https://doc.rust-lang.org/nomicon/hrtb.html",
1809 let for_sugg
= span_type
.suggestion(<_name
);
1810 for param
in params
{
1811 if let Ok(snippet
) = self.tcx
.sess
.source_map().span_to_snippet(param
.span
) {
1812 if snippet
.starts_with('
&'
) && !snippet
.starts_with("&'") {
1813 introduce_suggestion
1814 .push((param
.span
, format
!("&{} {}", lt_name
, &snippet
[1..])));
1815 } else if let Some(stripped
) = snippet
.strip_prefix("&'_ ") {
1816 introduce_suggestion
1817 .push((param
.span
, format
!("&{} {}", lt_name
, stripped
)));
1821 introduce_suggestion
.push((*for_span
, for_sugg
));
1822 introduce_suggestion
.push((span
, formatter(<_name
)));
1823 err
.multipart_suggestion(&msg
, introduce_suggestion
, Applicability
::MaybeIncorrect
);
1826 err
.span_suggestion_verbose(
1828 &format
!("consider using the `{}` lifetime", lifetime_names
.iter().next().unwrap()),
1830 Applicability
::MaybeIncorrect
,
1833 let suggest_new
= |err
: &mut DiagnosticBuilder
<'_
>, sugg
: &str| {
1834 for missing
in self.missing_named_lifetime_spots
.iter().rev() {
1835 let mut introduce_suggestion
= vec
![];
1838 introduce_suggestion
.push(match missing
{
1839 MissingLifetimeSpot
::Generics(generics
) => {
1840 if generics
.span
== DUMMY_SP
{
1841 // Account for malformed generics in the HIR. This shouldn't happen,
1842 // but if we make a mistake elsewhere, mainly by keeping something in
1843 // `missing_named_lifetime_spots` that we shouldn't, like associated
1844 // `const`s or making a mistake in the AST lowering we would provide
1845 // non-sensical suggestions. Guard against that by skipping these.
1849 msg
= "consider introducing a named lifetime parameter".to_string();
1850 should_break
= true;
1851 if let Some(param
) = generics
.params
.iter().find(|p
| {
1854 hir
::GenericParamKind
::Type
{
1855 synthetic
: Some(hir
::SyntheticTyParamKind
::ImplTrait
),
1860 (param
.span
.shrink_to_lo(), "'a, ".to_string())
1862 (generics
.span
, "<'a>".to_string())
1865 MissingLifetimeSpot
::HigherRanked { span, span_type }
=> {
1867 "consider making the {} lifetime-generic with a new `'a` lifetime",
1870 should_break
= false;
1872 "for more information on higher-ranked polymorphism, visit \
1873 https://doc.rust-lang.org/nomicon/hrtb.html",
1875 (*span
, span_type
.suggestion("'a"))
1877 MissingLifetimeSpot
::Static
=> {
1878 let (span
, sugg
) = match snippet
.as_deref() {
1879 Some("&") => (span
.shrink_to_hi(), "'static ".to_owned()),
1880 Some("'_") => (span
, "'static".to_owned()),
1881 Some(snippet
) if !snippet
.ends_with('
>'
) => {
1885 std
::iter
::repeat("'static")
1887 .collect
::<Vec
<_
>>()
1892 span
.shrink_to_hi(),
1895 std
::iter
::repeat("'static")
1897 .collect
::<Vec
<_
>>()
1905 err
.span_suggestion_verbose(
1907 "consider using the `'static` lifetime",
1909 Applicability
::MaybeIncorrect
,
1914 for param
in params
{
1915 if let Ok(snippet
) = self.tcx
.sess
.source_map().span_to_snippet(param
.span
) {
1916 if snippet
.starts_with('
&'
) && !snippet
.starts_with("&'") {
1917 introduce_suggestion
1918 .push((param
.span
, format
!("&'a {}", &snippet
[1..])));
1919 } else if let Some(stripped
) = snippet
.strip_prefix("&'_ ") {
1920 introduce_suggestion
.push((param
.span
, format
!("&'a {}", &stripped
)));
1924 introduce_suggestion
.push((span
, sugg
.to_string()));
1925 err
.multipart_suggestion(&msg
, introduce_suggestion
, Applicability
::MaybeIncorrect
);
1932 let lifetime_names
: Vec
<_
> = lifetime_names
.iter().collect();
1933 match (&lifetime_names
[..], snippet
.as_deref()) {
1934 ([name
], Some("&")) => {
1935 suggest_existing(err
, &name
.as_str()[..], &|name
| format
!("&{} ", name
));
1937 ([name
], Some("'_")) => {
1938 suggest_existing(err
, &name
.as_str()[..], &|n
| n
.to_string());
1940 ([name
], Some("")) => {
1941 suggest_existing(err
, &name
.as_str()[..], &|n
| format
!("{}, ", n
).repeat(count
));
1943 ([name
], Some(snippet
)) if !snippet
.ends_with('
>'
) => {
1944 let f
= |name
: &str| {
1948 std
::iter
::repeat(name
.to_string())
1950 .collect
::<Vec
<_
>>()
1954 suggest_existing(err
, &name
.as_str()[..], &f
);
1956 ([], Some("&")) if count
== 1 => {
1957 suggest_new(err
, "&'a ");
1959 ([], Some("'_")) if count
== 1 => {
1960 suggest_new(err
, "'a");
1962 ([], Some(snippet
)) if !snippet
.ends_with('
>'
) => {
1964 // This happens when we have `type Bar<'a> = Foo<T>` where we point at the space
1965 // before `T`. We will suggest `type Bar<'a> = Foo<'a, T>`.
1968 &std
::iter
::repeat("'a, ").take(count
).collect
::<Vec
<_
>>().join(""),
1976 std
::iter
::repeat("'a").take(count
).collect
::<Vec
<_
>>().join(", ")
1981 (lts
, ..) if lts
.len() > 1 => {
1982 err
.span_note(lifetime_spans
, "these named lifetimes are available to use");
1983 if Some("") == snippet
.as_deref() {
1984 // This happens when we have `Foo<T>` where we point at the space before `T`,
1985 // but this can be confusing so we give a suggestion with placeholders.
1986 err
.span_suggestion_verbose(
1988 "consider using one of the available lifetimes here",
1989 "'lifetime, ".repeat(count
),
1990 Applicability
::HasPlaceholders
,
1998 /// Non-static lifetimes are prohibited in anonymous constants under `min_const_generics`.
1999 /// This function will emit an error if `const_generics` is not enabled, the body identified by
2000 /// `body_id` is an anonymous constant and `lifetime_ref` is non-static.
2001 crate fn maybe_emit_forbidden_non_static_lifetime_error(
2003 body_id
: hir
::BodyId
,
2004 lifetime_ref
: &'tcx hir
::Lifetime
,
2006 let is_anon_const
= matches
!(
2007 self.tcx
.def_kind(self.tcx
.hir().body_owner_def_id(body_id
)),
2008 hir
::def
::DefKind
::AnonConst
2010 let is_allowed_lifetime
= matches
!(
2012 hir
::LifetimeName
::Implicit
| hir
::LifetimeName
::Static
| hir
::LifetimeName
::Underscore
2015 if !self.tcx
.lazy_normalization() && is_anon_const
&& !is_allowed_lifetime
{
2017 &self.tcx
.sess
.parse_sess
,
2018 sym
::const_generics
,
2020 "a non-static lifetime is not allowed in a `const`",