1 use crate::diagnostics
::{ImportSuggestion, LabelSuggestion, TypoSuggestion}
;
2 use crate::late
::lifetimes
::{ElisionFailureInfo, LifetimeContext}
;
3 use crate::late
::{AliasPossibility, LateResolutionVisitor, RibKind}
;
4 use crate::late
::{LifetimeBinderKind, LifetimeRibKind, LifetimeUseSet}
;
5 use crate::path_names_to_string
;
6 use crate::{Module, ModuleKind, ModuleOrUniformRoot}
;
7 use crate::{PathResult, PathSource, Segment}
;
9 use rustc_ast
::visit
::{FnCtxt, FnKind, LifetimeCtxt}
;
11 self as ast
, AssocItemKind
, Expr
, ExprKind
, GenericParam
, GenericParamKind
, Item
, ItemKind
,
12 NodeId
, Path
, Ty
, TyKind
,
14 use rustc_ast_pretty
::pprust
::path_segment_to_string
;
15 use rustc_data_structures
::fx
::{FxHashSet, FxIndexSet}
;
17 pluralize
, struct_span_err
, Applicability
, Diagnostic
, DiagnosticBuilder
, ErrorGuaranteed
,
21 use rustc_hir
::def
::Namespace
::{self, *}
;
22 use rustc_hir
::def
::{self, CtorKind, CtorOf, DefKind}
;
23 use rustc_hir
::def_id
::{DefId, LocalDefId, CRATE_DEF_ID, LOCAL_CRATE}
;
24 use rustc_hir
::PrimTy
;
25 use rustc_session
::lint
;
26 use rustc_session
::parse
::feature_err
;
27 use rustc_session
::Session
;
28 use rustc_span
::edition
::Edition
;
29 use rustc_span
::hygiene
::MacroKind
;
30 use rustc_span
::lev_distance
::find_best_match_for_name
;
31 use rustc_span
::symbol
::{kw, sym, Ident, Symbol}
;
32 use rustc_span
::{BytePos, Span, DUMMY_SP}
;
39 type Res
= def
::Res
<ast
::NodeId
>;
41 /// A field or associated item from self type suggested in case of resolution failure.
42 enum AssocSuggestion
{
50 impl AssocSuggestion
{
51 fn action(&self) -> &'
static str {
53 AssocSuggestion
::Field
=> "use the available field",
54 AssocSuggestion
::MethodWithSelf
=> "call the method with the fully-qualified path",
55 AssocSuggestion
::AssocFn
=> "call the associated function",
56 AssocSuggestion
::AssocConst
=> "use the associated `const`",
57 AssocSuggestion
::AssocType
=> "use the associated type",
62 pub(crate) enum MissingLifetimeSpot
<'tcx
> {
63 Generics(&'tcx hir
::Generics
<'tcx
>),
64 HigherRanked { span: Span, span_type: ForLifetimeSpanType }
,
68 pub(crate) enum ForLifetimeSpanType
{
75 impl ForLifetimeSpanType
{
76 pub(crate) fn descr(&self) -> &'
static str {
78 Self::BoundEmpty
| Self::BoundTail
=> "bound",
79 Self::TypeEmpty
| Self::TypeTail
=> "type",
83 pub(crate) fn suggestion(&self, sugg
: &str) -> String
{
85 Self::BoundEmpty
| Self::TypeEmpty
=> format
!("for<{}> ", sugg
),
86 Self::BoundTail
| Self::TypeTail
=> format
!(", {}", sugg
),
91 impl<'tcx
> Into
<MissingLifetimeSpot
<'tcx
>> for &&'tcx hir
::Generics
<'tcx
> {
92 fn into(self) -> MissingLifetimeSpot
<'tcx
> {
93 MissingLifetimeSpot
::Generics(self)
97 fn is_self_type(path
: &[Segment
], namespace
: Namespace
) -> bool
{
98 namespace
== TypeNS
&& path
.len() == 1 && path
[0].ident
.name
== kw
::SelfUpper
101 fn is_self_value(path
: &[Segment
], namespace
: Namespace
) -> bool
{
102 namespace
== ValueNS
&& path
.len() == 1 && path
[0].ident
.name
== kw
::SelfLower
105 /// Gets the stringified path for an enum from an `ImportSuggestion` for an enum variant.
106 fn import_candidate_to_enum_paths(suggestion
: &ImportSuggestion
) -> (String
, String
) {
107 let variant_path
= &suggestion
.path
;
108 let variant_path_string
= path_names_to_string(variant_path
);
110 let path_len
= suggestion
.path
.segments
.len();
111 let enum_path
= ast
::Path
{
112 span
: suggestion
.path
.span
,
113 segments
: suggestion
.path
.segments
[0..path_len
- 1].to_vec(),
116 let enum_path_string
= path_names_to_string(&enum_path
);
118 (variant_path_string
, enum_path_string
)
121 impl<'a
: 'ast
, 'ast
> LateResolutionVisitor
<'a
, '_
, 'ast
> {
122 fn def_span(&self, def_id
: DefId
) -> Option
<Span
> {
124 LOCAL_CRATE
=> self.r
.opt_span(def_id
),
129 .guess_head_span(self.r
.cstore().get_span_untracked(def_id
, self.r
.session
)),
134 /// Handles error reporting for `smart_resolve_path_fragment` function.
135 /// Creates base error and amends it with one short label and possibly some longer helps/notes.
136 pub(crate) fn smart_resolve_report_errors(
140 source
: PathSource
<'_
>,
142 ) -> (DiagnosticBuilder
<'a
, ErrorGuaranteed
>, Vec
<ImportSuggestion
>) {
143 let ident_span
= path
.last().map_or(span
, |ident
| ident
.ident
.span
);
144 let ns
= source
.namespace();
145 let is_expected
= &|res
| source
.is_expected(res
);
146 let is_enum_variant
= &|res
| matches
!(res
, Res
::Def(DefKind
::Variant
, _
));
148 debug
!(?res
, ?source
);
150 // Make the base error.
151 struct BaseError
<'a
> {
153 fallback_label
: String
,
156 suggestion
: Option
<(Span
, &'a
str, String
)>,
158 let mut expected
= source
.descr_expected();
159 let path_str
= Segment
::names_to_string(path
);
160 let item_str
= path
.last().unwrap().ident
;
161 let base_error
= if let Some(res
) = res
{
163 msg
: format
!("expected {}, found {} `{}`", expected
, res
.descr(), path_str
),
164 fallback_label
: format
!("not a {expected}"),
166 could_be_expr
: match res
{
167 Res
::Def(DefKind
::Fn
, _
) => {
168 // Verify whether this is a fn call or an Fn used as a type.
172 .span_to_snippet(span
)
173 .map(|snippet
| snippet
.ends_with('
)'
))
177 DefKind
::Ctor(..) | DefKind
::AssocFn
| DefKind
::Const
| DefKind
::AssocConst
,
182 | Res
::Local(_
) => true,
188 let item_span
= path
.last().unwrap().ident
.span
;
189 let (mod_prefix
, mod_str
, suggestion
) = if path
.len() == 1 {
190 debug
!(?
self.diagnostic_metadata
.current_impl_items
);
191 debug
!(?
self.diagnostic_metadata
.current_function
);
192 let suggestion
= if let Some(items
) = self.diagnostic_metadata
.current_impl_items
193 && let Some((fn_kind
, _
)) = self.diagnostic_metadata
.current_function
194 && self.current_trait_ref
.is_none()
195 && let Some(FnCtxt
::Assoc(_
)) = fn_kind
.ctxt()
196 && let Some(item
) = items
.iter().find(|i
| {
197 if let AssocItemKind
::Fn(fn_
) = &i
.kind
198 && !fn_
.sig
.decl
.has_self()
199 && i
.ident
.name
== item_str
.name
201 debug
!(?item_str
.name
);
202 debug
!(?fn_
.sig
.decl
.inputs
);
210 "consider using the associated function",
211 format
!("Self::{}", item
.ident
)
216 (String
::new(), "this scope".to_string(), suggestion
)
217 } else if path
.len() == 2 && path
[0].ident
.name
== kw
::PathRoot
{
218 if self.r
.session
.edition() > Edition
::Edition2015
{
219 // In edition 2018 onwards, the `::foo` syntax may only pull from the extern prelude
220 // which overrides all other expectations of item type
222 (String
::new(), "the list of imported crates".to_string(), None
)
224 (String
::new(), "the crate root".to_string(), None
)
226 } else if path
.len() == 2 && path
[0].ident
.name
== kw
::Crate
{
227 (String
::new(), "the crate root".to_string(), None
)
229 let mod_path
= &path
[..path
.len() - 1];
230 let mod_prefix
= match self.resolve_path(mod_path
, Some(TypeNS
), None
) {
231 PathResult
::Module(ModuleOrUniformRoot
::Module(module
)) => module
.res(),
234 .map_or_else(String
::new
, |res
| format
!("{} ", res
.descr()));
235 (mod_prefix
, format
!("`{}`", Segment
::names_to_string(mod_path
)), None
)
238 msg
: format
!("cannot find {expected} `{item_str}` in {mod_prefix}{mod_str}"),
239 fallback_label
: if path_str
== "async" && expected
.starts_with("struct") {
240 "`async` blocks are only allowed in Rust 2018 or later".to_string()
242 format
!("not found in {mod_str}")
245 could_be_expr
: false,
250 let code
= source
.error_code(res
.is_some());
252 self.r
.session
.struct_span_err_with_code(base_error
.span
, &base_error
.msg
, code
);
254 self.suggest_swapping_misplaced_self_ty_and_trait(&mut err
, source
, res
, base_error
.span
);
256 if let Some(sugg
) = base_error
.suggestion
{
257 err
.span_suggestion_verbose(sugg
.0, sugg
.1, sugg
.2, Applicability
::MaybeIncorrect
);
260 if let Some(span
) = self.diagnostic_metadata
.current_block_could_be_bare_struct_literal
{
261 err
.multipart_suggestion(
262 "you might have meant to write a `struct` literal",
264 (span
.shrink_to_lo(), "{ SomeStruct ".to_string()),
265 (span
.shrink_to_hi(), "}".to_string()),
267 Applicability
::HasPlaceholders
,
270 match (source
, self.diagnostic_metadata
.in_if_condition
) {
273 Some(Expr { span: expr_span, kind: ExprKind::Assign(lhs, _, _), .. }
),
275 // Icky heuristic so we don't suggest:
276 // `if (i + 2) = 2` => `if let (i + 2) = 2` (approximately pattern)
277 // `if 2 = i` => `if let 2 = i` (lhs needs to contain error span)
278 if lhs
.is_approximately_pattern() && lhs
.span
.contains(span
) {
279 err
.span_suggestion_verbose(
280 expr_span
.shrink_to_lo(),
281 "you might have meant to use pattern matching",
283 Applicability
::MaybeIncorrect
,
290 let is_assoc_fn
= self.self_type_is_available();
291 // Emit help message for fake-self from other languages (e.g., `this` in Javascript).
292 if ["this", "my"].contains(&item_str
.as_str()) && is_assoc_fn
{
293 err
.span_suggestion_short(
295 "you might have meant to use `self` here instead",
297 Applicability
::MaybeIncorrect
,
299 if !self.self_value_is_available(path
[0].ident
.span
) {
300 if let Some((FnKind
::Fn(_
, _
, sig
, ..), fn_span
)) =
301 &self.diagnostic_metadata
.current_function
303 let (span
, sugg
) = if let Some(param
) = sig
.decl
.inputs
.get(0) {
304 (param
.span
.shrink_to_lo(), "&self, ")
310 .span_through_char(*fn_span
, '
('
)
315 err
.span_suggestion_verbose(
317 "if you meant to use `self`, you are also missing a `self` receiver \
320 Applicability
::MaybeIncorrect
,
326 self.detect_assoct_type_constraint_meant_as_path(base_error
.span
, &mut err
);
328 // Emit special messages for unresolved `Self` and `self`.
329 if is_self_type(path
, ns
) {
330 err
.code(rustc_errors
::error_code
!(E0411
));
333 "`Self` is only available in impls, traits, and type definitions".to_string(),
335 if let Some(item_kind
) = self.diagnostic_metadata
.current_item
{
337 item_kind
.ident
.span
,
339 "`Self` not allowed in {} {}",
340 item_kind
.kind
.article(),
341 item_kind
.kind
.descr()
345 return (err
, Vec
::new());
347 if is_self_value(path
, ns
) {
348 debug
!("smart_resolve_path_fragment: E0424, source={:?}", source
);
350 err
.code(rustc_errors
::error_code
!(E0424
));
351 err
.span_label(span
, match source
{
352 PathSource
::Pat
=> "`self` value is a keyword and may not be bound to variables or shadowed"
354 _
=> "`self` value is a keyword only available in methods with a `self` parameter"
357 if let Some((fn_kind
, span
)) = &self.diagnostic_metadata
.current_function
{
358 // The current function has a `self' parameter, but we were unable to resolve
359 // a reference to `self`. This can only happen if the `self` identifier we
360 // are resolving came from a different hygiene context.
361 if fn_kind
.decl().inputs
.get(0).map_or(false, |p
| p
.is_self()) {
362 err
.span_label(*span
, "this function has a `self` parameter, but a macro invocation can only access identifiers it receives from parameters");
364 let doesnt
= if is_assoc_fn
{
365 let (span
, sugg
) = fn_kind
369 .map(|p
| (p
.span
.shrink_to_lo(), "&self, "))
371 // Try to look for the "(" after the function name, if possible.
372 // This avoids placing the suggestion into the visibility specifier.
375 .map_or(*span
, |ident
| span
.with_lo(ident
.span
.hi()));
380 .span_through_char(span
, '
('
)
385 err
.span_suggestion_verbose(
387 "add a `self` receiver parameter to make the associated `fn` a method",
389 Applicability
::MaybeIncorrect
,
395 if let Some(ident
) = fn_kind
.ident() {
398 &format
!("this function {} have a `self` parameter", doesnt
),
402 } else if let Some(item_kind
) = self.diagnostic_metadata
.current_item
{
404 item_kind
.ident
.span
,
406 "`self` not allowed in {} {}",
407 item_kind
.kind
.article(),
408 item_kind
.kind
.descr()
412 return (err
, Vec
::new());
415 // Try to lookup name in more relaxed fashion for better error reporting.
416 let ident
= path
.last().unwrap().ident
;
417 let mut candidates
= self
419 .lookup_import_candidates(ident
, ns
, &self.parent_scope
, is_expected
)
421 .filter(|ImportSuggestion { did, .. }
| {
422 match (did
, res
.and_then(|res
| res
.opt_def_id())) {
423 (Some(suggestion_did
), Some(actual_did
)) => *suggestion_did
!= actual_did
,
427 .collect
::<Vec
<_
>>();
428 let crate_def_id
= CRATE_DEF_ID
.to_def_id();
429 // Try to filter out intrinsics candidates, as long as we have
430 // some other candidates to suggest.
431 let intrinsic_candidates
: Vec
<_
> = candidates
432 .drain_filter(|sugg
| {
433 let path
= path_names_to_string(&sugg
.path
);
434 path
.starts_with("core::intrinsics::") || path
.starts_with("std::intrinsics::")
437 if candidates
.is_empty() {
438 // Put them back if we have no more candidates to suggest...
439 candidates
.extend(intrinsic_candidates
);
441 if candidates
.is_empty() && is_expected(Res
::Def(DefKind
::Enum
, crate_def_id
)) {
442 let mut enum_candidates
: Vec
<_
> = self
444 .lookup_import_candidates(ident
, ns
, &self.parent_scope
, is_enum_variant
)
446 .map(|suggestion
| import_candidate_to_enum_paths(&suggestion
))
447 .filter(|(_
, enum_ty_path
)| !enum_ty_path
.starts_with("std::prelude::"))
449 if !enum_candidates
.is_empty() {
450 if let (PathSource
::Type
, Some(span
)) =
451 (source
, self.diagnostic_metadata
.current_type_ascription
.last())
457 .type_ascription_path_suggestions
461 // Already reported this issue on the lhs of the type ascription.
463 return (err
, candidates
);
467 enum_candidates
.sort();
469 // Contextualize for E0412 "cannot find type", but don't belabor the point
470 // (that it's a variant) for E0573 "expected type, found variant".
471 let preamble
= if res
.is_none() {
472 let others
= match enum_candidates
.len() {
474 2 => " and 1 other".to_owned(),
475 n
=> format
!(" and {} others", n
),
477 format
!("there is an enum variant `{}`{}; ", enum_candidates
[0].0, others
)
481 let msg
= format
!("{}try using the variant's enum", preamble
);
483 err
.span_suggestions(
486 enum_candidates
.into_iter().map(|(_variant_path
, enum_ty_path
)| enum_ty_path
),
487 Applicability
::MachineApplicable
,
491 // Try Levenshtein algorithm.
492 let typo_sugg
= self.lookup_typo_candidate(path
, ns
, is_expected
);
493 if path
.len() == 1 && self.self_type_is_available() {
494 if let Some(candidate
) = self.lookup_assoc_candidate(ident
, ns
, is_expected
) {
495 let self_is_available
= self.self_value_is_available(path
[0].ident
.span
);
497 AssocSuggestion
::Field
=> {
498 if self_is_available
{
501 "you might have meant to use the available field",
502 format
!("self.{path_str}"),
503 Applicability
::MachineApplicable
,
506 err
.span_label(span
, "a field by this name exists in `Self`");
509 AssocSuggestion
::MethodWithSelf
if self_is_available
=> {
512 "you might have meant to call the method",
513 format
!("self.{path_str}"),
514 Applicability
::MachineApplicable
,
517 AssocSuggestion
::MethodWithSelf
518 | AssocSuggestion
::AssocFn
519 | AssocSuggestion
::AssocConst
520 | AssocSuggestion
::AssocType
=> {
523 &format
!("you might have meant to {}", candidate
.action()),
524 format
!("Self::{path_str}"),
525 Applicability
::MachineApplicable
,
529 self.r
.add_typo_suggestion(&mut err
, typo_sugg
, ident_span
);
530 return (err
, candidates
);
533 // If the first argument in call is `self` suggest calling a method.
534 if let Some((call_span
, args_span
)) = self.call_has_self_arg(source
) {
535 let mut args_snippet
= String
::new();
536 if let Some(args_span
) = args_span
{
537 if let Ok(snippet
) = self.r
.session
.source_map().span_to_snippet(args_span
) {
538 args_snippet
= snippet
;
544 &format
!("try calling `{ident}` as a method"),
545 format
!("self.{path_str}({args_snippet})"),
546 Applicability
::MachineApplicable
,
548 return (err
, candidates
);
552 // Try context-dependent help if relaxed lookup didn't work.
553 if let Some(res
) = res
{
554 if self.smart_resolve_context_dependent_help(
560 &base_error
.fallback_label
,
562 // We do this to avoid losing a secondary span when we override the main error span.
563 self.r
.add_typo_suggestion(&mut err
, typo_sugg
, ident_span
);
564 return (err
, candidates
);
569 base_error
.span
.from_expansion() && base_error
.span
.desugaring_kind().is_none();
570 if !self.type_ascription_suggestion(&mut err
, base_error
.span
) {
571 let mut fallback
= false;
573 PathSource
::Trait(AliasPossibility
::Maybe
),
574 Some(Res
::Def(DefKind
::Struct
| DefKind
::Enum
| DefKind
::Union
, _
)),
576 ) = (source
, res
, is_macro
)
578 if let Some(bounds @
[_
, .., _
]) = self.diagnostic_metadata
.current_trait_object
{
580 let spans
: Vec
<Span
> = bounds
582 .map(|bound
| bound
.span())
583 .filter(|&sp
| sp
!= base_error
.span
)
586 let start_span
= bounds
.iter().map(|bound
| bound
.span()).next().unwrap();
587 // `end_span` is the end of the poly trait ref (Foo + 'baz + Bar><)
588 let end_span
= bounds
.iter().map(|bound
| bound
.span()).last().unwrap();
589 // `last_bound_span` is the last bound of the poly trait ref (Foo + >'baz< + Bar)
590 let last_bound_span
= spans
.last().cloned().unwrap();
591 let mut multi_span
: MultiSpan
= spans
.clone().into();
593 let msg
= if sp
== last_bound_span
{
595 "...because of {these} bound{s}",
596 these
= pluralize
!("this", bounds
.len() - 1),
597 s
= pluralize
!(bounds
.len() - 1),
602 multi_span
.push_span_label(sp
, msg
);
604 multi_span
.push_span_label(
606 "expected this type to be a trait...".to_string(),
610 "`+` is used to constrain a \"trait object\" type with lifetimes or \
611 auto-traits; structs and enums can't be bound in that way",
613 if bounds
.iter().all(|bound
| match bound
{
614 ast
::GenericBound
::Outlives(_
) => true,
615 ast
::GenericBound
::Trait(tr
, _
) => tr
.span
== base_error
.span
,
617 let mut sugg
= vec
![];
618 if base_error
.span
!= start_span
{
619 sugg
.push((start_span
.until(base_error
.span
), String
::new()));
621 if base_error
.span
!= end_span
{
622 sugg
.push((base_error
.span
.shrink_to_hi().to(end_span
), String
::new()));
625 err
.multipart_suggestion(
626 "if you meant to use a type and not a trait here, remove the bounds",
628 Applicability
::MaybeIncorrect
,
634 fallback
|= self.restrict_assoc_type_in_where_clause(span
, &mut err
);
636 if !self.r
.add_typo_suggestion(&mut err
, typo_sugg
, ident_span
) {
638 match self.diagnostic_metadata
.current_let_binding
{
639 Some((pat_sp
, Some(ty_sp
), None
))
640 if ty_sp
.contains(base_error
.span
) && base_error
.could_be_expr
=>
642 err
.span_suggestion_short(
643 pat_sp
.between(ty_sp
),
644 "use `=` if you meant to assign",
646 Applicability
::MaybeIncorrect
,
652 // If the trait has a single item (which wasn't matched by Levenshtein), suggest it
653 let suggestion
= self.get_single_associated_item(&path
, &source
, is_expected
);
654 self.r
.add_typo_suggestion(&mut err
, suggestion
, ident_span
);
658 err
.span_label(base_error
.span
, base_error
.fallback_label
);
661 if let Some(err_code
) = &err
.code
{
662 if err_code
== &rustc_errors
::error_code
!(E0425
) {
663 for label_rib
in &self.label_ribs
{
664 for (label_ident
, node_id
) in &label_rib
.bindings
{
665 if format
!("'{}", ident
) == label_ident
.to_string() {
666 err
.span_label(label_ident
.span
, "a label with a similar name exists");
667 if let PathSource
::Expr(Some(Expr
{
668 kind
: ExprKind
::Break(None
, Some(_
)),
674 "use the similarly named label",
676 Applicability
::MaybeIncorrect
,
678 // Do not lint against unused label when we suggest them.
679 self.diagnostic_metadata
.unused_labels
.remove(node_id
);
684 } else if err_code
== &rustc_errors
::error_code
!(E0412
) {
685 if let Some(correct
) = Self::likely_rust_type(path
) {
688 "perhaps you intended to use this type",
690 Applicability
::MaybeIncorrect
,
699 fn detect_assoct_type_constraint_meant_as_path(&self, base_span
: Span
, err
: &mut Diagnostic
) {
700 let Some(ty
) = self.diagnostic_metadata
.current_type_path
else { return; }
;
701 let TyKind
::Path(_
, path
) = &ty
.kind
else { return; }
;
702 for segment
in &path
.segments
{
703 let Some(params
) = &segment
.args
else { continue; }
;
704 let ast
::GenericArgs
::AngleBracketed(ref params
) = params
.deref() else { continue; }
;
705 for param
in ¶ms
.args
{
706 let ast
::AngleBracketedArg
::Constraint(constraint
) = param
else { continue; }
;
707 let ast
::AssocConstraintKind
::Bound { bounds }
= &constraint
.kind
else {
710 for bound
in bounds
{
711 let ast
::GenericBound
::Trait(trait_ref
, ast
::TraitBoundModifier
::None
)
716 if base_span
== trait_ref
.span
{
717 err
.span_suggestion_verbose(
718 constraint
.ident
.span
.between(trait_ref
.span
),
719 "you might have meant to write a path instead of an associated type bound",
721 Applicability
::MachineApplicable
,
729 fn suggest_swapping_misplaced_self_ty_and_trait(
731 err
: &mut Diagnostic
,
732 source
: PathSource
<'_
>,
736 if let Some((trait_ref
, self_ty
)) =
737 self.diagnostic_metadata
.currently_processing_impl_trait
.clone()
738 && let TyKind
::Path(_
, self_ty_path
) = &self_ty
.kind
739 && let PathResult
::Module(ModuleOrUniformRoot
::Module(module
)) =
740 self.resolve_path(&Segment
::from_path(self_ty_path
), Some(TypeNS
), None
)
741 && let ModuleKind
::Def(DefKind
::Trait
, ..) = module
.kind
742 && trait_ref
.path
.span
== span
743 && let PathSource
::Trait(_
) = source
744 && let Some(Res
::Def(DefKind
::Struct
| DefKind
::Enum
| DefKind
::Union
, _
)) = res
745 && let Ok(self_ty_str
) =
746 self.r
.session
.source_map().span_to_snippet(self_ty
.span
)
747 && let Ok(trait_ref_str
) =
748 self.r
.session
.source_map().span_to_snippet(trait_ref
.path
.span
)
750 err
.multipart_suggestion(
751 "`impl` items mention the trait being implemented first and the type it is being implemented for second",
752 vec
![(trait_ref
.path
.span
, self_ty_str
), (self_ty
.span
, trait_ref_str
)],
753 Applicability
::MaybeIncorrect
,
758 fn get_single_associated_item(
761 source
: &PathSource
<'_
>,
762 filter_fn
: &impl Fn(Res
) -> bool
,
763 ) -> Option
<TypoSuggestion
> {
764 if let crate::PathSource
::TraitItem(_
) = source
{
765 let mod_path
= &path
[..path
.len() - 1];
766 if let PathResult
::Module(ModuleOrUniformRoot
::Module(module
)) =
767 self.resolve_path(mod_path
, None
, None
)
769 let resolutions
= self.r
.resolutions(module
).borrow();
770 let targets
: Vec
<_
> =
773 .filter_map(|(key
, resolution
)| {
774 resolution
.borrow().binding
.map(|binding
| binding
.res()).and_then(
775 |res
| if filter_fn(res
) { Some((key, res)) }
else { None }
,
779 if targets
.len() == 1 {
780 let target
= targets
[0];
781 return Some(TypoSuggestion
::single_item_from_res(
791 /// Given `where <T as Bar>::Baz: String`, suggest `where T: Bar<Baz = String>`.
792 fn restrict_assoc_type_in_where_clause(&mut self, span
: Span
, err
: &mut Diagnostic
) -> bool
{
793 // Detect that we are actually in a `where` predicate.
794 let (bounded_ty
, bounds
, where_span
) =
795 if let Some(ast
::WherePredicate
::BoundPredicate(ast
::WhereBoundPredicate
{
797 bound_generic_params
,
800 })) = self.diagnostic_metadata
.current_where_predicate
802 if !bound_generic_params
.is_empty() {
805 (bounded_ty
, bounds
, span
)
810 // Confirm that the target is an associated type.
811 let (ty
, position
, path
) = if let ast
::TyKind
::Path(
812 Some(ast
::QSelf { ty, position, .. }
),
816 // use this to verify that ident is a type param.
817 let Some(partial_res
) = self.r
.partial_res_map
.get(&bounded_ty
.id
) else {
821 partial_res
.base_res(),
822 hir
::def
::Res
::Def(hir
::def
::DefKind
::AssocTy
, _
)
823 ) && partial_res
.unresolved_segments() == 0)
832 let peeled_ty
= ty
.peel_refs();
833 if let ast
::TyKind
::Path(None
, type_param_path
) = &peeled_ty
.kind
{
834 // Confirm that the `SelfTy` is a type parameter.
835 let Some(partial_res
) = self.r
.partial_res_map
.get(&peeled_ty
.id
) else {
839 partial_res
.base_res(),
840 hir
::def
::Res
::Def(hir
::def
::DefKind
::TyParam
, _
)
841 ) && partial_res
.unresolved_segments() == 0)
846 [ast
::PathSegment { ident: constrain_ident, args: None, .. }
],
847 [ast
::GenericBound
::Trait(poly_trait_ref
, ast
::TraitBoundModifier
::None
)],
848 ) = (&type_param_path
.segments
[..], &bounds
[..])
850 if let [ast
::PathSegment { ident, args: None, .. }
] =
851 &poly_trait_ref
.trait_ref
.path
.segments
[..]
853 if ident
.span
== span
{
854 err
.span_suggestion_verbose(
856 &format
!("constrain the associated type to `{}`", ident
),
862 .span_to_snippet(ty
.span
) // Account for `<&'a T as Foo>::Bar`.
863 .unwrap_or_else(|_
| constrain_ident
.to_string()),
864 path
.segments
[..*position
]
866 .map(|segment
| path_segment_to_string(segment
))
869 path
.segments
[*position
..]
871 .map(|segment
| path_segment_to_string(segment
))
876 Applicability
::MaybeIncorrect
,
886 /// Check if the source is call expression and the first argument is `self`. If true,
887 /// return the span of whole call and the span for all arguments expect the first one (`self`).
888 fn call_has_self_arg(&self, source
: PathSource
<'_
>) -> Option
<(Span
, Option
<Span
>)> {
889 let mut has_self_arg
= None
;
890 if let PathSource
::Expr(Some(parent
)) = source
{
892 ExprKind
::Call(_
, args
) if !args
.is_empty() => {
893 let mut expr_kind
= &args
[0].kind
;
896 ExprKind
::Path(_
, arg_name
) if arg_name
.segments
.len() == 1 => {
897 if arg_name
.segments
[0].ident
.name
== kw
::SelfLower
{
898 let call_span
= parent
.span
;
899 let tail_args_span
= if args
.len() > 1 {
902 args
.last().unwrap().span
.hi(),
909 has_self_arg
= Some((call_span
, tail_args_span
));
913 ExprKind
::AddrOf(_
, _
, expr
) => expr_kind
= &expr
.kind
,
924 fn followed_by_brace(&self, span
: Span
) -> (bool
, Option
<Span
>) {
925 // HACK(estebank): find a better way to figure out that this was a
926 // parser issue where a struct literal is being used on an expression
927 // where a brace being opened means a block is being started. Look
928 // ahead for the next text to see if `span` is followed by a `{`.
929 let sm
= self.r
.session
.source_map();
932 sp
= sm
.next_point(sp
);
933 match sm
.span_to_snippet(sp
) {
935 if snippet
.chars().any(|c
| !c
.is_whitespace()) {
942 let followed_by_brace
= matches
!(sm
.span_to_snippet(sp
), Ok(ref snippet
) if snippet
== "{");
943 // In case this could be a struct literal that needs to be surrounded
944 // by parentheses, find the appropriate span.
946 let mut closing_brace
= None
;
948 sp
= sm
.next_point(sp
);
949 match sm
.span_to_snippet(sp
) {
952 closing_brace
= Some(span
.to(sp
));
959 // The bigger the span, the more likely we're incorrect --
960 // bound it to 100 chars long.
965 (followed_by_brace
, closing_brace
)
968 /// Provides context-dependent help for errors reported by the `smart_resolve_path_fragment`
970 /// Returns `true` if able to provide context-dependent help.
971 fn smart_resolve_context_dependent_help(
973 err
: &mut Diagnostic
,
975 source
: PathSource
<'_
>,
978 fallback_label
: &str,
980 let ns
= source
.namespace();
981 let is_expected
= &|res
| source
.is_expected(res
);
983 let path_sep
= |err
: &mut Diagnostic
, expr
: &Expr
| match expr
.kind
{
984 ExprKind
::Field(_
, ident
) => {
987 "use the path separator to refer to an item",
988 format
!("{}::{}", path_str
, ident
),
989 Applicability
::MaybeIncorrect
,
993 ExprKind
::MethodCall(ref segment
, ..) => {
994 let span
= expr
.span
.with_hi(segment
.ident
.span
.hi());
997 "use the path separator to refer to an item",
998 format
!("{}::{}", path_str
, segment
.ident
),
999 Applicability
::MaybeIncorrect
,
1006 let find_span
= |source
: &PathSource
<'_
>, err
: &mut Diagnostic
| {
1008 PathSource
::Expr(Some(Expr { span, kind: ExprKind::Call(_, _), .. }
))
1009 | PathSource
::TupleStruct(span
, _
) => {
1010 // We want the main underline to cover the suggested code as well for
1012 err
.set_span(*span
);
1019 let mut bad_struct_syntax_suggestion
= |def_id
: DefId
| {
1020 let (followed_by_brace
, closing_brace
) = self.followed_by_brace(span
);
1023 PathSource
::Expr(Some(
1024 parent @ Expr { kind: ExprKind::Field(..) | ExprKind::MethodCall(..), .. }
,
1025 )) if path_sep(err
, &parent
) => {}
1031 | ExprKind
::Binary(..)
1032 | ExprKind
::Unary(..)
1034 | ExprKind
::While(..)
1035 | ExprKind
::ForLoop(..)
1036 | ExprKind
::Match(..),
1039 ) if followed_by_brace
=> {
1040 if let Some(sp
) = closing_brace
{
1041 err
.span_label(span
, fallback_label
);
1042 err
.multipart_suggestion(
1043 "surround the struct literal with parentheses",
1045 (sp
.shrink_to_lo(), "(".to_string()),
1046 (sp
.shrink_to_hi(), ")".to_string()),
1048 Applicability
::MaybeIncorrect
,
1052 span
, // Note the parentheses surrounding the suggestion below
1054 "you might want to surround a struct literal with parentheses: \
1055 `({} {{ /* fields */ }})`?",
1061 PathSource
::Expr(_
) | PathSource
::TupleStruct(..) | PathSource
::Pat
=> {
1062 let span
= find_span(&source
, err
);
1063 if let Some(span
) = self.def_span(def_id
) {
1064 err
.span_label(span
, &format
!("`{}` defined here", path_str
));
1066 let (tail
, descr
, applicability
) = match source
{
1067 PathSource
::Pat
| PathSource
::TupleStruct(..) => {
1068 ("", "pattern", Applicability
::MachineApplicable
)
1070 _
=> (": val", "literal", Applicability
::HasPlaceholders
),
1072 let (fields
, applicability
) = match self.r
.field_names
.get(&def_id
) {
1076 .map(|f
| format
!("{}{}", f
.node
, tail
))
1077 .collect
::<Vec
<String
>>()
1081 None
=> ("/* fields */".to_string(), Applicability
::HasPlaceholders
),
1083 let pad
= match self.r
.field_names
.get(&def_id
) {
1084 Some(fields
) if fields
.is_empty() => "",
1087 err
.span_suggestion(
1089 &format
!("use struct {} syntax instead", descr
),
1090 format
!("{path_str} {{{pad}{fields}{pad}}}"),
1095 err
.span_label(span
, fallback_label
);
1100 match (res
, source
) {
1102 Res
::Def(DefKind
::Macro(MacroKind
::Bang
), _
),
1103 PathSource
::Expr(Some(Expr
{
1104 kind
: ExprKind
::Index(..) | ExprKind
::Call(..), ..
1106 | PathSource
::Struct
,
1108 err
.span_label(span
, fallback_label
);
1109 err
.span_suggestion_verbose(
1110 span
.shrink_to_hi(),
1111 "use `!` to invoke the macro",
1113 Applicability
::MaybeIncorrect
,
1115 if path_str
== "try" && span
.rust_2015() {
1116 err
.note("if you want the `try` keyword, you need Rust 2018 or later");
1119 (Res
::Def(DefKind
::Macro(MacroKind
::Bang
), _
), _
) => {
1120 err
.span_label(span
, fallback_label
);
1122 (Res
::Def(DefKind
::TyAlias
, def_id
), PathSource
::Trait(_
)) => {
1123 err
.span_label(span
, "type aliases cannot be used as traits");
1124 if self.r
.session
.is_nightly_build() {
1125 let msg
= "you might have meant to use `#![feature(trait_alias)]` instead of a \
1127 if let Some(span
) = self.def_span(def_id
) {
1128 if let Ok(snip
) = self.r
.session
.source_map().span_to_snippet(span
) {
1129 // The span contains a type alias so we should be able to
1130 // replace `type` with `trait`.
1131 let snip
= snip
.replacen("type", "trait", 1);
1132 err
.span_suggestion(span
, msg
, snip
, Applicability
::MaybeIncorrect
);
1134 err
.span_help(span
, msg
);
1141 (Res
::Def(DefKind
::Mod
, _
), PathSource
::Expr(Some(parent
))) => {
1142 if !path_sep(err
, &parent
) {
1147 Res
::Def(DefKind
::Enum
, def_id
),
1148 PathSource
::TupleStruct(..) | PathSource
::Expr(..),
1151 .diagnostic_metadata
1152 .current_type_ascription
1158 .type_ascription_path_suggestions
1164 err
.downgrade_to_delayed_bug();
1165 // We already suggested changing `:` into `::` during parsing.
1169 self.suggest_using_enum_variant(err
, source
, def_id
, span
);
1171 (Res
::Def(DefKind
::Struct
, def_id
), source
) if ns
== ValueNS
=> {
1172 let (ctor_def
, ctor_vis
, fields
) =
1173 if let Some(struct_ctor
) = self.r
.struct_constructors
.get(&def_id
).cloned() {
1174 if let PathSource
::Expr(Some(parent
)) = source
{
1175 if let ExprKind
::Field(..) | ExprKind
::MethodCall(..) = parent
.kind
{
1176 bad_struct_syntax_suggestion(def_id
);
1182 bad_struct_syntax_suggestion(def_id
);
1186 let is_accessible
= self.r
.is_accessible_from(ctor_vis
, self.parent_scope
.module
);
1187 if !is_expected(ctor_def
) || is_accessible
{
1191 let field_spans
= match source
{
1192 // e.g. `if let Enum::TupleVariant(field1, field2) = _`
1193 PathSource
::TupleStruct(_
, pattern_spans
) => {
1194 err
.set_primary_message(
1195 "cannot match against a tuple struct which contains private fields",
1198 // Use spans of the tuple struct pattern.
1199 Some(Vec
::from(pattern_spans
))
1201 // e.g. `let _ = Enum::TupleVariant(field1, field2);`
1202 _
if source
.is_call() => {
1203 err
.set_primary_message(
1204 "cannot initialize a tuple struct which contains private fields",
1207 // Use spans of the tuple struct definition.
1211 .map(|fields
| fields
.iter().map(|f
| f
.span
).collect
::<Vec
<_
>>())
1216 if let Some(spans
) =
1217 field_spans
.filter(|spans
| spans
.len() > 0 && fields
.len() == spans
.len())
1219 let non_visible_spans
: Vec
<Span
> = iter
::zip(&fields
, &spans
)
1220 .filter(|(vis
, _
)| {
1221 !self.r
.is_accessible_from(**vis
, self.parent_scope
.module
)
1223 .map(|(_
, span
)| *span
)
1226 if non_visible_spans
.len() > 0 {
1227 let mut m
: MultiSpan
= non_visible_spans
.clone().into();
1230 .for_each(|s
| m
.push_span_label(s
, "private field".to_string()));
1231 err
.span_note(m
, "constructor is not visible here due to private fields");
1239 "constructor is not visible here due to private fields".to_string(),
1244 DefKind
::Union
| DefKind
::Variant
| DefKind
::Ctor(_
, CtorKind
::Fictive
),
1248 ) if ns
== ValueNS
=> {
1249 bad_struct_syntax_suggestion(def_id
);
1251 (Res
::Def(DefKind
::Ctor(_
, CtorKind
::Const
), def_id
), _
) if ns
== ValueNS
=> {
1253 PathSource
::Expr(_
) | PathSource
::TupleStruct(..) | PathSource
::Pat
=> {
1254 let span
= find_span(&source
, err
);
1255 if let Some(span
) = self.def_span(def_id
) {
1256 err
.span_label(span
, &format
!("`{}` defined here", path_str
));
1258 err
.span_suggestion(
1260 "use this syntax instead",
1262 Applicability
::MaybeIncorrect
,
1268 (Res
::Def(DefKind
::Ctor(_
, CtorKind
::Fn
), def_id
), _
) if ns
== ValueNS
=> {
1269 if let Some(span
) = self.def_span(def_id
) {
1270 err
.span_label(span
, &format
!("`{}` defined here", path_str
));
1272 let fields
= self.r
.field_names
.get(&def_id
).map_or_else(
1273 || "/* fields */".to_string(),
1274 |fields
| vec
!["_"; fields
.len()].join(", "),
1276 err
.span_suggestion(
1278 "use the tuple variant pattern syntax instead",
1279 format
!("{}({})", path_str
, fields
),
1280 Applicability
::HasPlaceholders
,
1283 (Res
::SelfTy { .. }
, _
) if ns
== ValueNS
=> {
1284 err
.span_label(span
, fallback_label
);
1285 err
.note("can't use `Self` as a constructor, you must use the implemented struct");
1287 (Res
::Def(DefKind
::TyAlias
| DefKind
::AssocTy
, _
), _
) if ns
== ValueNS
=> {
1288 err
.note("can't use a type alias as a constructor");
1295 /// Given the target `ident` and `kind`, search for the similarly named associated item
1296 /// in `self.current_trait_ref`.
1297 pub(crate) fn find_similarly_named_assoc_item(
1300 kind
: &AssocItemKind
,
1301 ) -> Option
<Symbol
> {
1302 let (module
, _
) = self.current_trait_ref
.as_ref()?
;
1303 if ident
== kw
::Underscore
{
1304 // We do nothing for `_`.
1308 let resolutions
= self.r
.resolutions(module
);
1309 let targets
= resolutions
1312 .filter_map(|(key
, res
)| res
.borrow().binding
.map(|binding
| (key
, binding
.res())))
1313 .filter(|(_
, res
)| match (kind
, res
) {
1314 (AssocItemKind
::Const(..), Res
::Def(DefKind
::AssocConst
, _
)) => true,
1315 (AssocItemKind
::Fn(_
), Res
::Def(DefKind
::AssocFn
, _
)) => true,
1316 (AssocItemKind
::TyAlias(..), Res
::Def(DefKind
::AssocTy
, _
)) => true,
1319 .map(|(key
, _
)| key
.ident
.name
)
1320 .collect
::<Vec
<_
>>();
1322 find_best_match_for_name(&targets
, ident
, None
)
1325 fn lookup_assoc_candidate
<FilterFn
>(
1329 filter_fn
: FilterFn
,
1330 ) -> Option
<AssocSuggestion
>
1332 FilterFn
: Fn(Res
) -> bool
,
1334 fn extract_node_id(t
: &Ty
) -> Option
<NodeId
> {
1336 TyKind
::Path(None
, _
) => Some(t
.id
),
1337 TyKind
::Rptr(_
, ref mut_ty
) => extract_node_id(&mut_ty
.ty
),
1338 // This doesn't handle the remaining `Ty` variants as they are not
1339 // that commonly the self_type, it might be interesting to provide
1340 // support for those in future.
1345 // Fields are generally expected in the same contexts as locals.
1346 if filter_fn(Res
::Local(ast
::DUMMY_NODE_ID
)) {
1347 if let Some(node_id
) =
1348 self.diagnostic_metadata
.current_self_type
.as_ref().and_then(extract_node_id
)
1350 // Look for a field with the same name in the current self_type.
1351 if let Some(resolution
) = self.r
.partial_res_map
.get(&node_id
) {
1352 match resolution
.base_res() {
1353 Res
::Def(DefKind
::Struct
| DefKind
::Union
, did
)
1354 if resolution
.unresolved_segments() == 0 =>
1356 if let Some(field_names
) = self.r
.field_names
.get(&did
) {
1359 .any(|&field_name
| ident
.name
== field_name
.node
)
1361 return Some(AssocSuggestion
::Field
);
1371 if let Some(items
) = self.diagnostic_metadata
.current_trait_assoc_items
{
1372 for assoc_item
in items
{
1373 if assoc_item
.ident
== ident
{
1374 return Some(match &assoc_item
.kind
{
1375 ast
::AssocItemKind
::Const(..) => AssocSuggestion
::AssocConst
,
1376 ast
::AssocItemKind
::Fn(box ast
::Fn { sig, .. }
) if sig
.decl
.has_self() => {
1377 AssocSuggestion
::MethodWithSelf
1379 ast
::AssocItemKind
::Fn(..) => AssocSuggestion
::AssocFn
,
1380 ast
::AssocItemKind
::TyAlias(..) => AssocSuggestion
::AssocType
,
1381 ast
::AssocItemKind
::MacCall(_
) => continue,
1387 // Look for associated items in the current trait.
1388 if let Some((module
, _
)) = self.current_trait_ref
{
1389 if let Ok(binding
) = self.r
.maybe_resolve_ident_in_module(
1390 ModuleOrUniformRoot
::Module(module
),
1395 let res
= binding
.res();
1397 if self.r
.has_self
.contains(&res
.def_id()) {
1398 return Some(AssocSuggestion
::MethodWithSelf
);
1401 Res
::Def(DefKind
::AssocFn
, _
) => return Some(AssocSuggestion
::AssocFn
),
1402 Res
::Def(DefKind
::AssocConst
, _
) => {
1403 return Some(AssocSuggestion
::AssocConst
);
1405 Res
::Def(DefKind
::AssocTy
, _
) => {
1406 return Some(AssocSuggestion
::AssocType
);
1418 fn lookup_typo_candidate(
1422 filter_fn
: &impl Fn(Res
) -> bool
,
1423 ) -> Option
<TypoSuggestion
> {
1424 let mut names
= Vec
::new();
1425 if path
.len() == 1 {
1426 // Search in lexical scope.
1427 // Walk backwards up the ribs in scope and collect candidates.
1428 for rib
in self.ribs
[ns
].iter().rev() {
1429 // Locals and type parameters
1430 for (ident
, &res
) in &rib
.bindings
{
1432 names
.push(TypoSuggestion
::typo_from_res(ident
.name
, res
));
1436 if let RibKind
::ModuleRibKind(module
) = rib
.kind
{
1437 // Items from this module
1438 self.r
.add_module_candidates(module
, &mut names
, &filter_fn
);
1440 if let ModuleKind
::Block(..) = module
.kind
{
1441 // We can see through blocks
1443 // Items from the prelude
1444 if !module
.no_implicit_prelude
{
1445 let extern_prelude
= self.r
.extern_prelude
.clone();
1446 names
.extend(extern_prelude
.iter().flat_map(|(ident
, _
)| {
1447 self.r
.crate_loader
.maybe_process_path_extern(ident
.name
).and_then(
1450 Res
::Def(DefKind
::Mod
, crate_id
.as_def_id());
1452 if filter_fn(crate_mod
) {
1453 Some(TypoSuggestion
::typo_from_res(
1454 ident
.name
, crate_mod
,
1463 if let Some(prelude
) = self.r
.prelude
{
1464 self.r
.add_module_candidates(prelude
, &mut names
, &filter_fn
);
1471 // Add primitive types to the mix
1472 if filter_fn(Res
::PrimTy(PrimTy
::Bool
)) {
1473 names
.extend(PrimTy
::ALL
.iter().map(|prim_ty
| {
1474 TypoSuggestion
::typo_from_res(prim_ty
.name(), Res
::PrimTy(*prim_ty
))
1478 // Search in module.
1479 let mod_path
= &path
[..path
.len() - 1];
1480 if let PathResult
::Module(ModuleOrUniformRoot
::Module(module
)) =
1481 self.resolve_path(mod_path
, Some(TypeNS
), None
)
1483 self.r
.add_module_candidates(module
, &mut names
, &filter_fn
);
1487 let name
= path
[path
.len() - 1].ident
.name
;
1488 // Make sure error reporting is deterministic.
1489 names
.sort_by(|a
, b
| a
.candidate
.as_str().partial_cmp(b
.candidate
.as_str()).unwrap());
1491 match find_best_match_for_name(
1492 &names
.iter().map(|suggestion
| suggestion
.candidate
).collect
::<Vec
<Symbol
>>(),
1496 Some(found
) if found
!= name
=> {
1497 names
.into_iter().find(|suggestion
| suggestion
.candidate
== found
)
1503 // Returns the name of the Rust type approximately corresponding to
1504 // a type name in another programming language.
1505 fn likely_rust_type(path
: &[Segment
]) -> Option
<Symbol
> {
1506 let name
= path
[path
.len() - 1].ident
.as_str();
1507 // Common Java types
1509 "byte" => sym
::u8, // In Java, bytes are signed, but in practice one almost always wants unsigned bytes.
1510 "short" => sym
::i16,
1511 "boolean" => sym
::bool
,
1514 "float" => sym
::f32,
1515 "double" => sym
::f64,
1520 /// Only used in a specific case of type ascription suggestions
1521 fn get_colon_suggestion_span(&self, start
: Span
) -> Span
{
1522 let sm
= self.r
.session
.source_map();
1523 start
.to(sm
.next_point(start
))
1526 fn type_ascription_suggestion(&self, err
: &mut Diagnostic
, base_span
: Span
) -> bool
{
1527 let sm
= self.r
.session
.source_map();
1528 let base_snippet
= sm
.span_to_snippet(base_span
);
1529 if let Some(&sp
) = self.diagnostic_metadata
.current_type_ascription
.last() {
1530 if let Ok(snippet
) = sm
.span_to_snippet(sp
) {
1531 let len
= snippet
.trim_end().len() as u32;
1532 if snippet
.trim() == ":" {
1534 sp
.with_lo(sp
.lo() + BytePos(len
- 1)).with_hi(sp
.lo() + BytePos(len
));
1535 let mut show_label
= true;
1536 if sm
.is_multiline(sp
) {
1537 err
.span_suggestion_short(
1539 "maybe you meant to write `;` here",
1541 Applicability
::MaybeIncorrect
,
1544 let after_colon_sp
=
1545 self.get_colon_suggestion_span(colon_sp
.shrink_to_hi());
1546 if snippet
.len() == 1 {
1548 err
.span_suggestion(
1550 "maybe you meant to write a path separator here",
1552 Applicability
::MaybeIncorrect
,
1559 .type_ascription_path_suggestions
1563 err
.downgrade_to_delayed_bug();
1566 if let Ok(base_snippet
) = base_snippet
{
1567 let mut sp
= after_colon_sp
;
1569 // Try to find an assignment
1570 sp
= sm
.next_point(sp
);
1571 let snippet
= sm
.span_to_snippet(sp
.to(sm
.next_point(sp
)));
1573 Ok(ref x
) if x
.as_str() == "=" => {
1574 err
.span_suggestion(
1576 "maybe you meant to write an assignment here",
1577 format
!("let {}", base_snippet
),
1578 Applicability
::MaybeIncorrect
,
1583 Ok(ref x
) if x
.as_str() == "\n" => break,
1593 "expecting a type here because of type ascription",
1603 fn find_module(&mut self, def_id
: DefId
) -> Option
<(Module
<'a
>, ImportSuggestion
)> {
1604 let mut result
= None
;
1605 let mut seen_modules
= FxHashSet
::default();
1606 let mut worklist
= vec
![(self.r
.graph_root
, Vec
::new())];
1608 while let Some((in_module
, path_segments
)) = worklist
.pop() {
1609 // abort if the module is already found
1610 if result
.is_some() {
1614 in_module
.for_each_child(self.r
, |_
, ident
, _
, name_binding
| {
1615 // abort if the module is already found or if name_binding is private external
1616 if result
.is_some() || !name_binding
.vis
.is_visible_locally() {
1619 if let Some(module
) = name_binding
.module() {
1621 let mut path_segments
= path_segments
.clone();
1622 path_segments
.push(ast
::PathSegment
::from_ident(ident
));
1623 let module_def_id
= module
.def_id();
1624 if module_def_id
== def_id
{
1626 Path { span: name_binding.span, segments: path_segments, tokens: None }
;
1638 // add the module to the lookup
1639 if seen_modules
.insert(module_def_id
) {
1640 worklist
.push((module
, path_segments
));
1650 fn collect_enum_ctors(&mut self, def_id
: DefId
) -> Option
<Vec
<(Path
, DefId
, CtorKind
)>> {
1651 self.find_module(def_id
).map(|(enum_module
, enum_import_suggestion
)| {
1652 let mut variants
= Vec
::new();
1653 enum_module
.for_each_child(self.r
, |_
, ident
, _
, name_binding
| {
1654 if let Res
::Def(DefKind
::Ctor(CtorOf
::Variant
, kind
), def_id
) = name_binding
.res() {
1655 let mut segms
= enum_import_suggestion
.path
.segments
.clone();
1656 segms
.push(ast
::PathSegment
::from_ident(ident
));
1657 let path
= Path { span: name_binding.span, segments: segms, tokens: None }
;
1658 variants
.push((path
, def_id
, kind
));
1665 /// Adds a suggestion for using an enum's variant when an enum is used instead.
1666 fn suggest_using_enum_variant(
1668 err
: &mut Diagnostic
,
1669 source
: PathSource
<'_
>,
1673 let Some(variants
) = self.collect_enum_ctors(def_id
) else {
1674 err
.note("you might have meant to use one of the enum's variants");
1678 let suggest_only_tuple_variants
=
1679 matches
!(source
, PathSource
::TupleStruct(..)) || source
.is_call();
1680 if suggest_only_tuple_variants
{
1681 // Suggest only tuple variants regardless of whether they have fields and do not
1682 // suggest path with added parentheses.
1683 let suggestable_variants
= variants
1685 .filter(|(.., kind
)| *kind
== CtorKind
::Fn
)
1686 .map(|(variant
, ..)| path_names_to_string(variant
))
1687 .collect
::<Vec
<_
>>();
1689 let non_suggestable_variant_count
= variants
.len() - suggestable_variants
.len();
1691 let source_msg
= if source
.is_call() {
1693 } else if matches
!(source
, PathSource
::TupleStruct(..)) {
1699 if !suggestable_variants
.is_empty() {
1700 let msg
= if non_suggestable_variant_count
== 0 && suggestable_variants
.len() == 1 {
1701 format
!("try {} the enum's variant", source_msg
)
1703 format
!("try {} one of the enum's variants", source_msg
)
1706 err
.span_suggestions(
1709 suggestable_variants
.into_iter(),
1710 Applicability
::MaybeIncorrect
,
1714 // If the enum has no tuple variants..
1715 if non_suggestable_variant_count
== variants
.len() {
1716 err
.help(&format
!("the enum has no tuple variants {}", source_msg
));
1719 // If there are also non-tuple variants..
1720 if non_suggestable_variant_count
== 1 {
1722 "you might have meant {} the enum's non-tuple variant",
1725 } else if non_suggestable_variant_count
>= 1 {
1727 "you might have meant {} one of the enum's non-tuple variants",
1732 let needs_placeholder
= |def_id
: DefId
, kind
: CtorKind
| {
1733 let has_no_fields
= self.r
.field_names
.get(&def_id
).map_or(false, |f
| f
.is_empty());
1735 CtorKind
::Const
=> false,
1736 CtorKind
::Fn
| CtorKind
::Fictive
if has_no_fields
=> false,
1741 let mut suggestable_variants
= variants
1743 .filter(|(_
, def_id
, kind
)| !needs_placeholder(*def_id
, *kind
))
1744 .map(|(variant
, _
, kind
)| (path_names_to_string(variant
), kind
))
1745 .map(|(variant
, kind
)| match kind
{
1746 CtorKind
::Const
=> variant
,
1747 CtorKind
::Fn
=> format
!("({}())", variant
),
1748 CtorKind
::Fictive
=> format
!("({} {{}})", variant
),
1750 .collect
::<Vec
<_
>>();
1752 if !suggestable_variants
.is_empty() {
1753 let msg
= if suggestable_variants
.len() == 1 {
1754 "you might have meant to use the following enum variant"
1756 "you might have meant to use one of the following enum variants"
1759 err
.span_suggestions(
1762 suggestable_variants
.drain(..),
1763 Applicability
::MaybeIncorrect
,
1767 let suggestable_variants_with_placeholders
= variants
1769 .filter(|(_
, def_id
, kind
)| needs_placeholder(*def_id
, *kind
))
1770 .map(|(variant
, _
, kind
)| (path_names_to_string(variant
), kind
))
1771 .filter_map(|(variant
, kind
)| match kind
{
1772 CtorKind
::Fn
=> Some(format
!("({}(/* fields */))", variant
)),
1773 CtorKind
::Fictive
=> Some(format
!("({} {{ /* fields */ }})", variant
)),
1776 .collect
::<Vec
<_
>>();
1778 if !suggestable_variants_with_placeholders
.is_empty() {
1780 suggestable_variants
.is_empty(),
1781 suggestable_variants_with_placeholders
.len(),
1783 (true, 1) => "the following enum variant is available",
1784 (true, _
) => "the following enum variants are available",
1785 (false, 1) => "alternatively, the following enum variant is available",
1786 (false, _
) => "alternatively, the following enum variants are also available",
1789 err
.span_suggestions(
1792 suggestable_variants_with_placeholders
.into_iter(),
1793 Applicability
::HasPlaceholders
,
1798 if def_id
.is_local() {
1799 if let Some(span
) = self.def_span(def_id
) {
1800 err
.span_note(span
, "the enum is defined here");
1805 pub(crate) fn report_missing_type_error(
1808 ) -> Option
<(Span
, &'
static str, String
, Applicability
)> {
1809 let (ident
, span
) = match path
{
1810 [segment
] if !segment
.has_generic_args
&& segment
.ident
.name
!= kw
::SelfUpper
=> {
1811 (segment
.ident
.to_string(), segment
.ident
.span
)
1815 let mut iter
= ident
.chars().map(|c
| c
.is_uppercase());
1816 let single_uppercase_char
=
1817 matches
!(iter
.next(), Some(true)) && matches
!(iter
.next(), None
);
1818 if !self.diagnostic_metadata
.currently_processing_generics
&& !single_uppercase_char
{
1821 match (self.diagnostic_metadata
.current_item
, single_uppercase_char
, self.diagnostic_metadata
.currently_processing_generics
) {
1822 (Some(Item { kind: ItemKind::Fn(..), ident, .. }
), _
, _
) if ident
.name
== sym
::main
=> {
1823 // Ignore `fn main()` as we don't want to suggest `fn main<T>()`
1828 kind @ ItemKind
::Fn(..)
1829 | kind @ ItemKind
::Enum(..)
1830 | kind @ ItemKind
::Struct(..)
1831 | kind @ ItemKind
::Union(..),
1836 // Without the 2nd `true`, we'd suggest `impl <T>` for `impl T` when a type `T` isn't found
1837 | (Some(Item { kind: kind @ ItemKind::Impl(..), .. }
), true, true)
1838 | (Some(Item { kind, .. }
), false, _
) => {
1839 // Likely missing type parameter.
1840 if let Some(generics
) = kind
.generics() {
1841 if span
.overlaps(generics
.span
) {
1842 // Avoid the following:
1843 // error[E0405]: cannot find trait `A` in this scope
1844 // --> $DIR/typo-suggestion-named-underscore.rs:CC:LL
1846 // L | fn foo<T: A>(x: T) {} // Shouldn't suggest underscore
1847 // | ^- help: you might be missing a type parameter: `, A`
1849 // | not found in this scope
1852 let msg
= "you might be missing a type parameter";
1853 let (span
, sugg
) = if let [.., param
] = &generics
.params
[..] {
1854 let span
= if let [.., bound
] = ¶m
.bounds
[..] {
1856 } else if let GenericParam
{
1857 kind
: GenericParamKind
::Const { ty, kw_span: _, default }
, ..
1859 default.as_ref().map(|def
| def
.value
.span
).unwrap_or(ty
.span
)
1863 (span
, format
!(", {}", ident
))
1865 (generics
.span
, format
!("<{}>", ident
))
1867 // Do not suggest if this is coming from macro expansion.
1868 if span
.can_be_used_for_suggestions() {
1870 span
.shrink_to_hi(),
1873 Applicability
::MaybeIncorrect
,
1883 /// Given the target `label`, search the `rib_index`th label rib for similarly named labels,
1884 /// optionally returning the closest match and whether it is reachable.
1885 pub(crate) fn suggestion_for_label_in_rib(
1889 ) -> Option
<LabelSuggestion
> {
1890 // Are ribs from this `rib_index` within scope?
1891 let within_scope
= self.is_label_valid_from_rib(rib_index
);
1893 let rib
= &self.label_ribs
[rib_index
];
1897 .filter(|(id
, _
)| id
.span
.eq_ctxt(label
.span
))
1898 .map(|(id
, _
)| id
.name
)
1899 .collect
::<Vec
<Symbol
>>();
1901 find_best_match_for_name(&names
, label
.name
, None
).map(|symbol
| {
1902 // Upon finding a similar name, get the ident that it was from - the span
1903 // contained within helps make a useful diagnostic. In addition, determine
1904 // whether this candidate is within scope.
1905 let (ident
, _
) = rib
.bindings
.iter().find(|(ident
, _
)| ident
.name
== symbol
).unwrap();
1906 (*ident
, within_scope
)
1910 pub(crate) fn maybe_report_lifetime_uses(
1912 generics_span
: Span
,
1913 params
: &[ast
::GenericParam
],
1915 for (param_index
, param
) in params
.iter().enumerate() {
1916 let GenericParamKind
::Lifetime
= param
.kind
else { continue }
;
1918 let def_id
= self.r
.local_def_id(param
.id
);
1920 let use_set
= self.lifetime_uses
.remove(&def_id
);
1922 "Use set for {:?}({:?} at {:?}) is {:?}",
1923 def_id
, param
.ident
, param
.ident
.span
, use_set
1926 let deletion_span
= || {
1927 if params
.len() == 1 {
1928 // if sole lifetime, remove the entire `<>` brackets
1930 } else if param_index
== 0 {
1931 // if removing within `<>` brackets, we also want to
1932 // delete a leading or trailing comma as appropriate
1933 param
.span().to(params
[param_index
+ 1].span().shrink_to_lo())
1935 // if removing within `<>` brackets, we also want to
1936 // delete a leading or trailing comma as appropriate
1937 params
[param_index
- 1].span().shrink_to_hi().to(param
.span())
1941 Some(LifetimeUseSet
::Many
) => {}
1942 Some(LifetimeUseSet
::One { use_span, use_ctxt }
) => {
1943 debug
!(?param
.ident
, ?param
.ident
.span
, ?use_span
);
1945 let elidable
= matches
!(use_ctxt
, LifetimeCtxt
::Rptr
);
1947 let deletion_span
= deletion_span();
1948 self.r
.lint_buffer
.buffer_lint_with_diagnostic(
1949 lint
::builtin
::SINGLE_USE_LIFETIMES
,
1952 &format
!("lifetime parameter `{}` only used once", param
.ident
),
1953 lint
::BuiltinLintDiagnostics
::SingleUseLifetime
{
1954 param_span
: param
.ident
.span
,
1955 use_span
: Some((use_span
, elidable
)),
1961 debug
!(?param
.ident
, ?param
.ident
.span
);
1963 let deletion_span
= deletion_span();
1964 self.r
.lint_buffer
.buffer_lint_with_diagnostic(
1965 lint
::builtin
::UNUSED_LIFETIMES
,
1968 &format
!("lifetime parameter `{}` never used", param
.ident
),
1969 lint
::BuiltinLintDiagnostics
::SingleUseLifetime
{
1970 param_span
: param
.ident
.span
,
1980 pub(crate) fn emit_undeclared_lifetime_error(
1982 lifetime_ref
: &ast
::Lifetime
,
1983 outer_lifetime_ref
: Option
<Ident
>,
1985 debug_assert_ne
!(lifetime_ref
.ident
.name
, kw
::UnderscoreLifetime
);
1986 let mut err
= if let Some(outer
) = outer_lifetime_ref
{
1987 let mut err
= struct_span_err
!(
1989 lifetime_ref
.ident
.span
,
1991 "can't use generic parameters from outer item",
1993 err
.span_label(lifetime_ref
.ident
.span
, "use of generic parameter from outer item");
1994 err
.span_label(outer
.span
, "lifetime parameter from outer item");
1997 let mut err
= struct_span_err
!(
1999 lifetime_ref
.ident
.span
,
2001 "use of undeclared lifetime name `{}`",
2004 err
.span_label(lifetime_ref
.ident
.span
, "undeclared lifetime");
2007 let mut suggest_note
= true;
2009 for rib
in self.lifetime_ribs
.iter().rev() {
2011 LifetimeRibKind
::Generics { binder: _, span, kind }
=> {
2012 if !span
.can_be_used_for_suggestions() && suggest_note
{
2013 suggest_note
= false; // Avoid displaying the same help multiple times.
2017 "lifetime `{}` is missing in item created through this procedural macro",
2024 let higher_ranked
= matches
!(
2026 LifetimeBinderKind
::BareFnType
2027 | LifetimeBinderKind
::PolyTrait
2028 | LifetimeBinderKind
::WhereBound
2030 let (span
, sugg
) = if span
.is_empty() {
2033 if higher_ranked { "for" }
else { "" }
,
2035 if higher_ranked { " " }
else { "" }
,
2040 self.r
.session
.source_map().span_through_char(span
, '
<'
).shrink_to_hi();
2041 let sugg
= format
!("{}, ", lifetime_ref
.ident
);
2045 err
.span_suggestion(
2048 "consider making the {} lifetime-generic with a new `{}` lifetime",
2053 Applicability
::MaybeIncorrect
,
2056 "for more information on higher-ranked polymorphism, visit \
2057 https://doc.rust-lang.org/nomicon/hrtb.html",
2060 err
.span_suggestion(
2062 &format
!("consider introducing lifetime `{}` here", lifetime_ref
.ident
),
2064 Applicability
::MaybeIncorrect
,
2068 LifetimeRibKind
::Item
=> break,
2076 pub(crate) fn emit_non_static_lt_in_const_generic_error(&self, lifetime_ref
: &ast
::Lifetime
) {
2079 lifetime_ref
.ident
.span
,
2081 "use of non-static lifetime `{}` in const generic",
2085 "for more information, see issue #74052 \
2086 <https://github.com/rust-lang/rust/issues/74052>",
2091 /// Non-static lifetimes are prohibited in anonymous constants under `min_const_generics`.
2092 /// This function will emit an error if `generic_const_exprs` is not enabled, the body identified by
2093 /// `body_id` is an anonymous constant and `lifetime_ref` is non-static.
2094 pub(crate) fn maybe_emit_forbidden_non_static_lifetime_error(
2096 lifetime_ref
: &ast
::Lifetime
,
2098 let feature_active
= self.r
.session
.features_untracked().generic_const_exprs
;
2099 if !feature_active
{
2101 &self.r
.session
.parse_sess
,
2102 sym
::generic_const_exprs
,
2103 lifetime_ref
.ident
.span
,
2104 "a non-static lifetime is not allowed in a `const`",
2111 /// Report lifetime/lifetime shadowing as an error.
2112 pub fn signal_lifetime_shadowing(sess
: &Session
, orig
: Ident
, shadower
: Ident
) {
2113 let mut err
= struct_span_err
!(
2117 "lifetime name `{}` shadows a lifetime name that is already in scope",
2120 err
.span_label(orig
.span
, "first declared here");
2121 err
.span_label(shadower
.span
, format
!("lifetime `{}` already in scope", orig
.name
));
2125 /// Shadowing involving a label is only a warning for historical reasons.
2126 //FIXME: make this a proper lint.
2127 pub fn signal_label_shadowing(sess
: &Session
, orig
: Span
, shadower
: Ident
) {
2128 let name
= shadower
.name
;
2129 let shadower
= shadower
.span
;
2130 let mut err
= sess
.struct_span_warn(
2132 &format
!("label name `{}` shadows a label name that is already in scope", name
),
2134 err
.span_label(orig
, "first declared here");
2135 err
.span_label(shadower
, format
!("label `{}` already in scope", name
));
2139 impl<'tcx
> LifetimeContext
<'_
, 'tcx
> {
2140 pub(crate) fn report_missing_lifetime_specifiers(
2144 ) -> DiagnosticBuilder
<'tcx
, ErrorGuaranteed
> {
2149 "missing lifetime specifier{}",
2154 /// Returns whether to add `'static` lifetime to the suggested lifetime list.
2155 pub(crate) fn report_elision_failure(
2157 diag
: &mut Diagnostic
,
2158 params
: &[ElisionFailureInfo
],
2160 let mut m
= String
::new();
2161 let len
= params
.len();
2163 let elided_params
: Vec
<_
> =
2164 params
.iter().cloned().filter(|info
| info
.lifetime_count
> 0).collect();
2166 let elided_len
= elided_params
.len();
2168 for (i
, info
) in elided_params
.into_iter().enumerate() {
2169 let ElisionFailureInfo { parent, index, lifetime_count: n, have_bound_regions, span }
=
2172 diag
.span_label(span
, "");
2173 let help_name
= if let Some(ident
) =
2174 parent
.and_then(|body
| self.tcx
.hir().body(body
).params
[index
].pat
.simple_ident())
2176 format
!("`{}`", ident
)
2178 format
!("argument {}", index
+ 1)
2186 "one of {}'s {} {}lifetimes",
2189 if have_bound_regions { "free " }
else { "" }
2194 if elided_len
== 2 && i
== 0 {
2196 } else if i
+ 2 == elided_len
{
2197 m
.push_str(", or ");
2198 } else if i
!= elided_len
- 1 {
2205 "this function's return type contains a borrowed value, \
2206 but there is no value for it to be borrowed from",
2209 } else if elided_len
== 0 {
2211 "this function's return type contains a borrowed value with \
2212 an elided lifetime, but the lifetime cannot be derived from \
2216 } else if elided_len
== 1 {
2218 "this function's return type contains a borrowed value, \
2219 but the signature does not say which {} it is borrowed from",
2225 "this function's return type contains a borrowed value, \
2226 but the signature does not say whether it is borrowed from {}",
2233 pub(crate) fn is_trait_ref_fn_scope(
2235 trait_ref
: &'tcx hir
::PolyTraitRef
<'tcx
>,
2237 if let def
::Res
::Def(_
, did
) = trait_ref
.trait_ref
.path
.res
{
2239 self.tcx
.lang_items().fn_once_trait(),
2240 self.tcx
.lang_items().fn_trait(),
2241 self.tcx
.lang_items().fn_mut_trait(),
2243 .contains(&Some(did
))
2245 let (span
, span_type
) = if let Some(bound
) =
2246 trait_ref
.bound_generic_params
.iter().rfind(|param
| {
2249 hir
::GenericParamKind
::Lifetime
{
2250 kind
: hir
::LifetimeParamKind
::Explicit
2254 (bound
.span
.shrink_to_hi(), ForLifetimeSpanType
::BoundTail
)
2256 (trait_ref
.span
.shrink_to_lo(), ForLifetimeSpanType
::BoundEmpty
)
2258 self.missing_named_lifetime_spots
2259 .push(MissingLifetimeSpot
::HigherRanked { span, span_type }
);
2266 pub(crate) fn add_missing_lifetime_specifiers_label(
2268 err
: &mut Diagnostic
,
2269 mut spans_with_counts
: Vec
<(Span
, usize)>,
2270 in_scope_lifetimes
: FxIndexSet
<LocalDefId
>,
2271 params
: Option
<&[ElisionFailureInfo
]>,
2273 let (mut lifetime_names
, lifetime_spans
): (FxHashSet
<_
>, Vec
<_
>) = in_scope_lifetimes
2275 .filter_map(|def_id
| {
2276 let name
= self.tcx
.item_name(def_id
.to_def_id());
2277 let span
= self.tcx
.def_ident_span(def_id
.to_def_id())?
;
2280 .filter(|&(n
, _
)| n
!= kw
::UnderscoreLifetime
)
2283 if let Some(params
) = params
{
2284 // If there's no lifetime available, suggest `'static`.
2285 if self.report_elision_failure(err
, params
) && lifetime_names
.is_empty() {
2286 lifetime_names
.insert(kw
::StaticLifetime
);
2289 let params
= params
.unwrap_or(&[]);
2291 let snippets
: Vec
<Option
<String
>> = spans_with_counts
2293 .map(|(span
, _
)| self.tcx
.sess
.source_map().span_to_snippet(*span
).ok())
2296 // Empty generics are marked with a span of "<", but since from now on
2297 // that information is in the snippets it can be removed from the spans.
2298 for ((span
, _
), snippet
) in spans_with_counts
.iter_mut().zip(&snippets
) {
2299 if snippet
.as_deref() == Some("<") {
2300 *span
= span
.shrink_to_hi();
2304 for &(span
, count
) in &spans_with_counts
{
2308 "expected {} lifetime parameter{}",
2309 if count
== 1 { "named".to_string() }
else { count.to_string() }
,
2315 let suggest_existing
=
2316 |err
: &mut Diagnostic
,
2318 formatters
: Vec
<Option
<Box
<dyn Fn(&str) -> String
>>>| {
2319 if let Some(MissingLifetimeSpot
::HigherRanked { span: for_span, span_type }
) =
2320 self.missing_named_lifetime_spots
.iter().rev().next()
2322 // When we have `struct S<'a>(&'a dyn Fn(&X) -> &X);` we want to not only suggest
2323 // using `'a`, but also introduce the concept of HRLTs by suggesting
2324 // `struct S<'a>(&'a dyn for<'b> Fn(&X) -> &'b X);`. (#72404)
2325 let mut introduce_suggestion
= vec
![];
2327 let a_to_z_repeat_n
= |n
| {
2328 (b'a'
..=b'z'
).map(move |c
| {
2329 let mut s
= '
\''
.to_string();
2330 s
.extend(std
::iter
::repeat(char::from(c
)).take(n
));
2335 // If all single char lifetime names are present, we wrap around and double the chars.
2337 .flat_map(a_to_z_repeat_n
)
2338 .find(|lt
| !lifetime_names
.contains(&Symbol
::intern(<
)))
2341 "consider making the {} lifetime-generic with a new `{}` lifetime",
2346 "for more information on higher-ranked polymorphism, visit \
2347 https://doc.rust-lang.org/nomicon/hrtb.html",
2349 let for_sugg
= span_type
.suggestion(<_name
);
2350 for param
in params
{
2351 if let Ok(snippet
) = self.tcx
.sess
.source_map().span_to_snippet(param
.span
)
2353 if snippet
.starts_with('
&'
) && !snippet
.starts_with("&'") {
2354 introduce_suggestion
2355 .push((param
.span
, format
!("&{} {}", lt_name
, &snippet
[1..])));
2356 } else if let Some(stripped
) = snippet
.strip_prefix("&'_ ") {
2357 introduce_suggestion
2358 .push((param
.span
, format
!("&{} {}", lt_name
, stripped
)));
2362 introduce_suggestion
.push((*for_span
, for_sugg
));
2363 for ((span
, _
), formatter
) in spans_with_counts
.iter().zip(formatters
.iter()) {
2364 if let Some(formatter
) = formatter
{
2365 introduce_suggestion
.push((*span
, formatter(<_name
)));
2368 err
.multipart_suggestion_verbose(
2370 introduce_suggestion
,
2371 Applicability
::MaybeIncorrect
,
2375 let spans_suggs
: Vec
<_
> = formatters
2377 .zip(spans_with_counts
.iter())
2378 .filter_map(|(formatter
, (span
, _
))| {
2379 if let Some(formatter
) = formatter
{
2380 Some((*span
, formatter(name
)))
2386 if spans_suggs
.is_empty() {
2387 // If all the spans come from macros, we cannot extract snippets and then
2388 // `formatters` only contains None and `spans_suggs` is empty.
2391 err
.multipart_suggestion_verbose(
2393 "consider using the `{}` lifetime",
2394 lifetime_names
.iter().next().unwrap()
2397 Applicability
::MaybeIncorrect
,
2400 let suggest_new
= |err
: &mut Diagnostic
, suggs
: Vec
<Option
<String
>>| {
2401 for missing
in self.missing_named_lifetime_spots
.iter().rev() {
2402 let mut introduce_suggestion
= vec
![];
2405 introduce_suggestion
.push(match missing
{
2406 MissingLifetimeSpot
::Generics(generics
) => {
2407 if generics
.span
== DUMMY_SP
{
2408 // Account for malformed generics in the HIR. This shouldn't happen,
2409 // but if we make a mistake elsewhere, mainly by keeping something in
2410 // `missing_named_lifetime_spots` that we shouldn't, like associated
2411 // `const`s or making a mistake in the AST lowering we would provide
2412 // nonsensical suggestions. Guard against that by skipping these.
2416 msg
= "consider introducing a named lifetime parameter".to_string();
2417 should_break
= true;
2418 if let Some(param
) = generics
.params
.iter().find(|p
| {
2421 hir
::GenericParamKind
::Type { synthetic: true, .. }
2422 | hir
::GenericParamKind
::Lifetime
{
2423 kind
: hir
::LifetimeParamKind
::Elided
2427 (param
.span
.shrink_to_lo(), "'a, ".to_string())
2429 (generics
.span
, "<'a>".to_string())
2432 MissingLifetimeSpot
::HigherRanked { span, span_type }
=> {
2434 "consider making the {} lifetime-generic with a new `'a` lifetime",
2437 should_break
= false;
2439 "for more information on higher-ranked polymorphism, visit \
2440 https://doc.rust-lang.org/nomicon/hrtb.html",
2442 (*span
, span_type
.suggestion("'a"))
2444 MissingLifetimeSpot
::Static
=> {
2445 let mut spans_suggs
= Vec
::new();
2446 for ((span
, count
), snippet
) in
2447 spans_with_counts
.iter().copied().zip(snippets
.iter())
2449 let (span
, sugg
) = match snippet
.as_deref() {
2450 Some("&") => (span
.shrink_to_hi(), "'static ".to_owned()),
2451 Some("'_") => (span
, "'static".to_owned()),
2452 Some(snippet
) if !snippet
.ends_with('
>'
) => {
2456 std
::iter
::repeat("'static")
2458 .collect
::<Vec
<_
>>()
2461 } else if snippet
== "<" || snippet
== "(" {
2463 span
.shrink_to_hi(),
2464 std
::iter
::repeat("'static")
2466 .collect
::<Vec
<_
>>()
2471 span
.shrink_to_hi(),
2474 std
::iter
::repeat("'static")
2476 .collect
::<Vec
<_
>>()
2484 spans_suggs
.push((span
, sugg
.to_string()));
2486 err
.multipart_suggestion_verbose(
2487 "consider using the `'static` lifetime",
2489 Applicability
::MaybeIncorrect
,
2495 struct Lifetime(Span
, String
);
2497 fn is_unnamed(&self) -> bool
{
2498 self.1.starts_with('
&'
) && !self.1.starts_with("&'")
2500 fn is_underscore(&self) -> bool
{
2501 self.1.starts_with("&'_ ")
2503 fn is_named(&self) -> bool
{
2504 self.1.starts_with("&'")
2506 fn suggestion(&self, sugg
: String
) -> Option
<(Span
, String
)> {
2510 self.is_underscore(),
2512 sugg
.starts_with('
&'
),
2514 (true, _
, _
, false) => (self.span_unnamed_borrow(), sugg
),
2515 (true, _
, _
, true) => {
2516 (self.span_unnamed_borrow(), sugg
[1..].to_string())
2518 (_
, true, _
, false) => {
2519 (self.span_underscore_borrow(), sugg
.trim().to_string())
2521 (_
, true, _
, true) => {
2522 (self.span_underscore_borrow(), sugg
[1..].trim().to_string())
2524 (_
, _
, true, false) => {
2525 (self.span_named_borrow(), sugg
.trim().to_string())
2527 (_
, _
, true, true) => {
2528 (self.span_named_borrow(), sugg
[1..].trim().to_string())
2534 fn span_unnamed_borrow(&self) -> Span
{
2535 let lo
= self.0.lo() + BytePos(1);
2536 self.0.with_lo(lo
).with_hi(lo
)
2538 fn span_named_borrow(&self) -> Span
{
2539 let lo
= self.0.lo() + BytePos(1);
2542 fn span_underscore_borrow(&self) -> Span
{
2543 let lo
= self.0.lo() + BytePos(1);
2544 let hi
= lo
+ BytePos(2);
2545 self.0.with_lo(lo
).with_hi(hi
)
2549 for param
in params
{
2550 if let Ok(snippet
) = self.tcx
.sess
.source_map().span_to_snippet(param
.span
) {
2551 if let Some((span
, sugg
)) =
2552 Lifetime(param
.span
, snippet
).suggestion("'a ".to_string())
2554 introduce_suggestion
.push((span
, sugg
));
2558 for (span
, sugg
) in spans_with_counts
.iter().copied().zip(suggs
.iter()).filter_map(
2559 |((span
, _
), sugg
)| match &sugg
{
2560 Some(sugg
) => Some((span
, sugg
.to_string())),
2564 let (span
, sugg
) = self
2568 .span_to_snippet(span
)
2570 .and_then(|snippet
| Lifetime(span
, snippet
).suggestion(sugg
.clone()))
2571 .unwrap_or((span
, sugg
));
2572 introduce_suggestion
.push((span
, sugg
.to_string()));
2574 err
.multipart_suggestion_verbose(
2576 introduce_suggestion
,
2577 Applicability
::MaybeIncorrect
,
2585 let lifetime_names
: Vec
<_
> = lifetime_names
.iter().collect();
2586 match &lifetime_names
[..] {
2588 let mut suggs
: Vec
<Option
<Box
<dyn Fn(&str) -> String
>>> = Vec
::new();
2589 for (snippet
, (_
, count
)) in snippets
.iter().zip(spans_with_counts
.iter().copied())
2591 suggs
.push(match snippet
.as_deref() {
2592 Some("&") => Some(Box
::new(|name
| format
!("&{} ", name
))),
2593 Some("'_") => Some(Box
::new(|n
| n
.to_string())),
2594 Some("") => Some(Box
::new(move |n
| format
!("{}, ", n
).repeat(count
))),
2595 Some("<") => Some(Box
::new(move |n
| {
2596 std
::iter
::repeat(n
).take(count
).collect
::<Vec
<_
>>().join(", ")
2598 Some(snippet
) if !snippet
.ends_with('
>'
) => Some(Box
::new(move |name
| {
2602 std
::iter
::repeat(name
.to_string())
2604 .collect
::<Vec
<_
>>()
2611 suggest_existing(err
, name
.as_str(), suggs
);
2614 let mut suggs
= Vec
::new();
2615 for (snippet
, (_
, count
)) in
2616 snippets
.iter().cloned().zip(spans_with_counts
.iter().copied())
2618 suggs
.push(match snippet
.as_deref() {
2619 Some("&") => Some("&'a ".to_string()),
2620 Some("'_") => Some("'a".to_string()),
2622 Some(std
::iter
::repeat("'a, ").take(count
).collect
::<Vec
<_
>>().join(""))
2625 Some(std
::iter
::repeat("'a").take(count
).collect
::<Vec
<_
>>().join(", "))
2627 Some(snippet
) => Some(format
!(
2630 std
::iter
::repeat("'a").take(count
).collect
::<Vec
<_
>>().join(", "),
2635 suggest_new(err
, suggs
);
2637 lts
if lts
.len() > 1 => {
2638 err
.span_note(lifetime_spans
, "these named lifetimes are available to use");
2640 let mut spans_suggs
: Vec
<_
> = Vec
::new();
2641 for ((span
, _
), snippet
) in spans_with_counts
.iter().copied().zip(snippets
.iter()) {
2642 match snippet
.as_deref() {
2643 Some("") => spans_suggs
.push((span
, "'lifetime, ".to_string())),
2644 Some("&") => spans_suggs
2645 .push((span
.with_lo(span
.lo() + BytePos(1)), "'lifetime ".to_string())),
2650 if spans_suggs
.len() > 0 {
2651 // This happens when we have `Foo<T>` where we point at the space before `T`,
2652 // but this can be confusing so we give a suggestion with placeholders.
2653 err
.multipart_suggestion_verbose(
2654 "consider using one of the available lifetimes here",
2656 Applicability
::HasPlaceholders
,
2660 _
=> unreachable
!(),