1 use crate::diagnostics
::{ImportSuggestion, LabelSuggestion, TypoSuggestion}
;
2 use crate::late
::{AliasPossibility, LateResolutionVisitor, RibKind}
;
3 use crate::late
::{LifetimeBinderKind, LifetimeRes, LifetimeRibKind, LifetimeUseSet}
;
4 use crate::path_names_to_string
;
5 use crate::{Module, ModuleKind, ModuleOrUniformRoot}
;
6 use crate::{PathResult, PathSource, Segment}
;
8 use rustc_ast
::visit
::{FnCtxt, FnKind, LifetimeCtxt}
;
10 self as ast
, AssocItemKind
, Expr
, ExprKind
, GenericParam
, GenericParamKind
, Item
, ItemKind
,
11 NodeId
, Path
, Ty
, TyKind
, DUMMY_NODE_ID
,
13 use rustc_ast_pretty
::pprust
::path_segment_to_string
;
14 use rustc_data_structures
::fx
::FxHashSet
;
16 pluralize
, struct_span_err
, Applicability
, Diagnostic
, DiagnosticBuilder
, ErrorGuaranteed
,
20 use rustc_hir
::def
::Namespace
::{self, *}
;
21 use rustc_hir
::def
::{self, CtorKind, CtorOf, DefKind}
;
22 use rustc_hir
::def_id
::{DefId, CRATE_DEF_ID, LOCAL_CRATE}
;
23 use rustc_hir
::PrimTy
;
24 use rustc_session
::lint
;
25 use rustc_session
::parse
::feature_err
;
26 use rustc_session
::Session
;
27 use rustc_span
::edition
::Edition
;
28 use rustc_span
::hygiene
::MacroKind
;
29 use rustc_span
::lev_distance
::find_best_match_for_name
;
30 use rustc_span
::symbol
::{kw, sym, Ident, Symbol}
;
31 use rustc_span
::{BytePos, Span}
;
36 type Res
= def
::Res
<ast
::NodeId
>;
38 /// A field or associated item from self type suggested in case of resolution failure.
39 enum AssocSuggestion
{
47 impl AssocSuggestion
{
48 fn action(&self) -> &'
static str {
50 AssocSuggestion
::Field
=> "use the available field",
51 AssocSuggestion
::MethodWithSelf
=> "call the method with the fully-qualified path",
52 AssocSuggestion
::AssocFn
=> "call the associated function",
53 AssocSuggestion
::AssocConst
=> "use the associated `const`",
54 AssocSuggestion
::AssocType
=> "use the associated type",
59 fn is_self_type(path
: &[Segment
], namespace
: Namespace
) -> bool
{
60 namespace
== TypeNS
&& path
.len() == 1 && path
[0].ident
.name
== kw
::SelfUpper
63 fn is_self_value(path
: &[Segment
], namespace
: Namespace
) -> bool
{
64 namespace
== ValueNS
&& path
.len() == 1 && path
[0].ident
.name
== kw
::SelfLower
67 /// Gets the stringified path for an enum from an `ImportSuggestion` for an enum variant.
68 fn import_candidate_to_enum_paths(suggestion
: &ImportSuggestion
) -> (String
, String
) {
69 let variant_path
= &suggestion
.path
;
70 let variant_path_string
= path_names_to_string(variant_path
);
72 let path_len
= suggestion
.path
.segments
.len();
73 let enum_path
= ast
::Path
{
74 span
: suggestion
.path
.span
,
75 segments
: suggestion
.path
.segments
[0..path_len
- 1].to_vec(),
78 let enum_path_string
= path_names_to_string(&enum_path
);
80 (variant_path_string
, enum_path_string
)
83 /// Description of an elided lifetime.
84 #[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Debug)]
85 pub(super) struct MissingLifetime
{
86 /// Used to overwrite the resolution with the suggestion, to avoid cascasing errors.
88 /// Where to suggest adding the lifetime.
90 /// How the lifetime was introduced, to have the correct space and comma.
91 pub kind
: MissingLifetimeKind
,
92 /// Number of elided lifetimes, used for elision in path.
96 #[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Debug)]
97 pub(super) enum MissingLifetimeKind
{
100 /// An elided lifetime `&' ty`.
102 /// An elided lifetime in brackets with written brackets.
104 /// An elided lifetime with elided brackets.
108 /// Description of the lifetimes appearing in a function parameter.
109 /// This is used to provide a literal explanation to the elision failure.
110 #[derive(Clone, Debug)]
111 pub(super) struct ElisionFnParameter
{
112 /// The index of the argument in the original definition.
114 /// The name of the argument if it's a simple ident.
115 pub ident
: Option
<Ident
>,
116 /// The number of lifetimes in the parameter.
117 pub lifetime_count
: usize,
118 /// The span of the parameter.
122 /// Description of lifetimes that appear as candidates for elision.
123 /// This is used to suggest introducing an explicit lifetime.
125 pub(super) enum LifetimeElisionCandidate
{
126 /// This is not a real lifetime.
128 /// There is a named lifetime, we won't suggest anything.
130 Missing(MissingLifetime
),
133 impl<'a
: 'ast
, 'ast
> LateResolutionVisitor
<'a
, '_
, 'ast
> {
134 fn def_span(&self, def_id
: DefId
) -> Option
<Span
> {
136 LOCAL_CRATE
=> self.r
.opt_span(def_id
),
137 _
=> Some(self.r
.cstore().get_span_untracked(def_id
, self.r
.session
)),
141 /// Handles error reporting for `smart_resolve_path_fragment` function.
142 /// Creates base error and amends it with one short label and possibly some longer helps/notes.
143 pub(crate) fn smart_resolve_report_errors(
147 source
: PathSource
<'_
>,
149 ) -> (DiagnosticBuilder
<'a
, ErrorGuaranteed
>, Vec
<ImportSuggestion
>) {
150 let ident_span
= path
.last().map_or(span
, |ident
| ident
.ident
.span
);
151 let ns
= source
.namespace();
152 let is_expected
= &|res
| source
.is_expected(res
);
153 let is_enum_variant
= &|res
| matches
!(res
, Res
::Def(DefKind
::Variant
, _
));
155 debug
!(?res
, ?source
);
157 // Make the base error.
158 struct BaseError
<'a
> {
160 fallback_label
: String
,
162 span_label
: Option
<(Span
, &'a
str)>,
164 suggestion
: Option
<(Span
, &'a
str, String
)>,
166 let mut expected
= source
.descr_expected();
167 let path_str
= Segment
::names_to_string(path
);
168 let item_str
= path
.last().unwrap().ident
;
169 let base_error
= if let Some(res
) = res
{
171 msg
: format
!("expected {}, found {} `{}`", expected
, res
.descr(), path_str
),
172 fallback_label
: format
!("not a {expected}"),
174 span_label
: match res
{
175 Res
::Def(kind
, def_id
) if kind
== DefKind
::TyParam
=> {
176 self.def_span(def_id
).map(|span
| (span
, "found this type parameter"))
180 could_be_expr
: match res
{
181 Res
::Def(DefKind
::Fn
, _
) => {
182 // Verify whether this is a fn call or an Fn used as a type.
186 .span_to_snippet(span
)
187 .map(|snippet
| snippet
.ends_with('
)'
))
191 DefKind
::Ctor(..) | DefKind
::AssocFn
| DefKind
::Const
| DefKind
::AssocConst
,
196 | Res
::Local(_
) => true,
202 let item_span
= path
.last().unwrap().ident
.span
;
203 let (mod_prefix
, mod_str
, suggestion
) = if path
.len() == 1 {
204 debug
!(?
self.diagnostic_metadata
.current_impl_items
);
205 debug
!(?
self.diagnostic_metadata
.current_function
);
206 let suggestion
= if let Some(items
) = self.diagnostic_metadata
.current_impl_items
207 && let Some((fn_kind
, _
)) = self.diagnostic_metadata
.current_function
208 && self.current_trait_ref
.is_none()
209 && let Some(FnCtxt
::Assoc(_
)) = fn_kind
.ctxt()
210 && let Some(item
) = items
.iter().find(|i
| {
211 if let AssocItemKind
::Fn(fn_
) = &i
.kind
212 && !fn_
.sig
.decl
.has_self()
213 && i
.ident
.name
== item_str
.name
215 debug
!(?item_str
.name
);
216 debug
!(?fn_
.sig
.decl
.inputs
);
224 "consider using the associated function",
225 format
!("Self::{}", item
.ident
)
230 (String
::new(), "this scope".to_string(), suggestion
)
231 } else if path
.len() == 2 && path
[0].ident
.name
== kw
::PathRoot
{
232 if self.r
.session
.edition() > Edition
::Edition2015
{
233 // In edition 2018 onwards, the `::foo` syntax may only pull from the extern prelude
234 // which overrides all other expectations of item type
236 (String
::new(), "the list of imported crates".to_string(), None
)
238 (String
::new(), "the crate root".to_string(), None
)
240 } else if path
.len() == 2 && path
[0].ident
.name
== kw
::Crate
{
241 (String
::new(), "the crate root".to_string(), None
)
243 let mod_path
= &path
[..path
.len() - 1];
244 let mod_prefix
= match self.resolve_path(mod_path
, Some(TypeNS
), None
) {
245 PathResult
::Module(ModuleOrUniformRoot
::Module(module
)) => module
.res(),
248 .map_or_else(String
::new
, |res
| format
!("{} ", res
.descr()));
249 (mod_prefix
, format
!("`{}`", Segment
::names_to_string(mod_path
)), None
)
252 let (fallback_label
, suggestion
) = if path_str
== "async"
253 && expected
.starts_with("struct")
255 ("`async` blocks are only allowed in Rust 2018 or later".to_string(), suggestion
)
257 // check if we are in situation of typo like `True` instead of `true`.
258 let override_suggestion
=
259 if ["true", "false"].contains(&item_str
.to_string().to_lowercase().as_str()) {
260 let item_typo
= item_str
.to_string().to_lowercase();
263 "you may want to use a bool value instead",
264 format
!("{}", item_typo
),
269 (format
!("not found in {mod_str}"), override_suggestion
)
273 msg
: format
!("cannot find {expected} `{item_str}` in {mod_prefix}{mod_str}"),
277 could_be_expr
: false,
282 let code
= source
.error_code(res
.is_some());
284 self.r
.session
.struct_span_err_with_code(base_error
.span
, &base_error
.msg
, code
);
286 self.suggest_swapping_misplaced_self_ty_and_trait(&mut err
, source
, res
, base_error
.span
);
288 if let Some((span
, label
)) = base_error
.span_label
{
289 err
.span_label(span
, label
);
292 if let Some(sugg
) = base_error
.suggestion
{
293 err
.span_suggestion_verbose(sugg
.0, sugg
.1, sugg
.2, Applicability
::MaybeIncorrect
);
296 if let Some(span
) = self.diagnostic_metadata
.current_block_could_be_bare_struct_literal
{
297 err
.multipart_suggestion(
298 "you might have meant to write a `struct` literal",
300 (span
.shrink_to_lo(), "{ SomeStruct ".to_string()),
301 (span
.shrink_to_hi(), "}".to_string()),
303 Applicability
::HasPlaceholders
,
306 match (source
, self.diagnostic_metadata
.in_if_condition
) {
309 Some(Expr { span: expr_span, kind: ExprKind::Assign(lhs, _, _), .. }
),
311 // Icky heuristic so we don't suggest:
312 // `if (i + 2) = 2` => `if let (i + 2) = 2` (approximately pattern)
313 // `if 2 = i` => `if let 2 = i` (lhs needs to contain error span)
314 if lhs
.is_approximately_pattern() && lhs
.span
.contains(span
) {
315 err
.span_suggestion_verbose(
316 expr_span
.shrink_to_lo(),
317 "you might have meant to use pattern matching",
319 Applicability
::MaybeIncorrect
,
326 let is_assoc_fn
= self.self_type_is_available();
327 // Emit help message for fake-self from other languages (e.g., `this` in Javascript).
328 if ["this", "my"].contains(&item_str
.as_str()) && is_assoc_fn
{
329 err
.span_suggestion_short(
331 "you might have meant to use `self` here instead",
333 Applicability
::MaybeIncorrect
,
335 if !self.self_value_is_available(path
[0].ident
.span
) {
336 if let Some((FnKind
::Fn(_
, _
, sig
, ..), fn_span
)) =
337 &self.diagnostic_metadata
.current_function
339 let (span
, sugg
) = if let Some(param
) = sig
.decl
.inputs
.get(0) {
340 (param
.span
.shrink_to_lo(), "&self, ")
346 .span_through_char(*fn_span
, '
('
)
351 err
.span_suggestion_verbose(
353 "if you meant to use `self`, you are also missing a `self` receiver \
356 Applicability
::MaybeIncorrect
,
362 self.detect_assoct_type_constraint_meant_as_path(base_error
.span
, &mut err
);
364 // Emit special messages for unresolved `Self` and `self`.
365 if is_self_type(path
, ns
) {
366 err
.code(rustc_errors
::error_code
!(E0411
));
369 "`Self` is only available in impls, traits, and type definitions".to_string(),
371 if let Some(item_kind
) = self.diagnostic_metadata
.current_item
{
373 item_kind
.ident
.span
,
375 "`Self` not allowed in {} {}",
376 item_kind
.kind
.article(),
377 item_kind
.kind
.descr()
381 return (err
, Vec
::new());
383 if is_self_value(path
, ns
) {
384 debug
!("smart_resolve_path_fragment: E0424, source={:?}", source
);
386 err
.code(rustc_errors
::error_code
!(E0424
));
387 err
.span_label(span
, match source
{
388 PathSource
::Pat
=> "`self` value is a keyword and may not be bound to variables or shadowed",
389 _
=> "`self` value is a keyword only available in methods with a `self` parameter",
391 if let Some((fn_kind
, span
)) = &self.diagnostic_metadata
.current_function
{
392 // The current function has a `self' parameter, but we were unable to resolve
393 // a reference to `self`. This can only happen if the `self` identifier we
394 // are resolving came from a different hygiene context.
395 if fn_kind
.decl().inputs
.get(0).map_or(false, |p
| p
.is_self()) {
396 err
.span_label(*span
, "this function has a `self` parameter, but a macro invocation can only access identifiers it receives from parameters");
398 let doesnt
= if is_assoc_fn
{
399 let (span
, sugg
) = fn_kind
403 .map(|p
| (p
.span
.shrink_to_lo(), "&self, "))
405 // Try to look for the "(" after the function name, if possible.
406 // This avoids placing the suggestion into the visibility specifier.
409 .map_or(*span
, |ident
| span
.with_lo(ident
.span
.hi()));
414 .span_through_char(span
, '
('
)
419 err
.span_suggestion_verbose(
421 "add a `self` receiver parameter to make the associated `fn` a method",
423 Applicability
::MaybeIncorrect
,
429 if let Some(ident
) = fn_kind
.ident() {
432 &format
!("this function {} have a `self` parameter", doesnt
),
436 } else if let Some(item_kind
) = self.diagnostic_metadata
.current_item
{
438 item_kind
.ident
.span
,
440 "`self` not allowed in {} {}",
441 item_kind
.kind
.article(),
442 item_kind
.kind
.descr()
446 return (err
, Vec
::new());
449 // Try to lookup name in more relaxed fashion for better error reporting.
450 let ident
= path
.last().unwrap().ident
;
451 let mut candidates
= self
453 .lookup_import_candidates(ident
, ns
, &self.parent_scope
, is_expected
)
455 .filter(|ImportSuggestion { did, .. }
| {
456 match (did
, res
.and_then(|res
| res
.opt_def_id())) {
457 (Some(suggestion_did
), Some(actual_did
)) => *suggestion_did
!= actual_did
,
461 .collect
::<Vec
<_
>>();
462 let crate_def_id
= CRATE_DEF_ID
.to_def_id();
463 // Try to filter out intrinsics candidates, as long as we have
464 // some other candidates to suggest.
465 let intrinsic_candidates
: Vec
<_
> = candidates
466 .drain_filter(|sugg
| {
467 let path
= path_names_to_string(&sugg
.path
);
468 path
.starts_with("core::intrinsics::") || path
.starts_with("std::intrinsics::")
471 if candidates
.is_empty() {
472 // Put them back if we have no more candidates to suggest...
473 candidates
.extend(intrinsic_candidates
);
475 if candidates
.is_empty() && is_expected(Res
::Def(DefKind
::Enum
, crate_def_id
)) {
476 let mut enum_candidates
: Vec
<_
> = self
478 .lookup_import_candidates(ident
, ns
, &self.parent_scope
, is_enum_variant
)
480 .map(|suggestion
| import_candidate_to_enum_paths(&suggestion
))
481 .filter(|(_
, enum_ty_path
)| !enum_ty_path
.starts_with("std::prelude::"))
483 if !enum_candidates
.is_empty() {
484 if let (PathSource
::Type
, Some(span
)) =
485 (source
, self.diagnostic_metadata
.current_type_ascription
.last())
491 .type_ascription_path_suggestions
495 // Already reported this issue on the lhs of the type ascription.
497 return (err
, candidates
);
501 enum_candidates
.sort();
503 // Contextualize for E0412 "cannot find type", but don't belabor the point
504 // (that it's a variant) for E0573 "expected type, found variant".
505 let preamble
= if res
.is_none() {
506 let others
= match enum_candidates
.len() {
508 2 => " and 1 other".to_owned(),
509 n
=> format
!(" and {} others", n
),
511 format
!("there is an enum variant `{}`{}; ", enum_candidates
[0].0, others
)
515 let msg
= format
!("{}try using the variant's enum", preamble
);
517 err
.span_suggestions(
520 enum_candidates
.into_iter().map(|(_variant_path
, enum_ty_path
)| enum_ty_path
),
521 Applicability
::MachineApplicable
,
525 // Try Levenshtein algorithm.
526 let typo_sugg
= self.lookup_typo_candidate(path
, ns
, is_expected
);
527 if path
.len() == 1 && self.self_type_is_available() {
528 if let Some(candidate
) = self.lookup_assoc_candidate(ident
, ns
, is_expected
) {
529 let self_is_available
= self.self_value_is_available(path
[0].ident
.span
);
531 AssocSuggestion
::Field
=> {
532 if self_is_available
{
535 "you might have meant to use the available field",
536 format
!("self.{path_str}"),
537 Applicability
::MachineApplicable
,
540 err
.span_label(span
, "a field by this name exists in `Self`");
543 AssocSuggestion
::MethodWithSelf
if self_is_available
=> {
546 "you might have meant to call the method",
547 format
!("self.{path_str}"),
548 Applicability
::MachineApplicable
,
551 AssocSuggestion
::MethodWithSelf
552 | AssocSuggestion
::AssocFn
553 | AssocSuggestion
::AssocConst
554 | AssocSuggestion
::AssocType
=> {
557 &format
!("you might have meant to {}", candidate
.action()),
558 format
!("Self::{path_str}"),
559 Applicability
::MachineApplicable
,
563 self.r
.add_typo_suggestion(&mut err
, typo_sugg
, ident_span
);
564 return (err
, candidates
);
567 // If the first argument in call is `self` suggest calling a method.
568 if let Some((call_span
, args_span
)) = self.call_has_self_arg(source
) {
569 let mut args_snippet
= String
::new();
570 if let Some(args_span
) = args_span
{
571 if let Ok(snippet
) = self.r
.session
.source_map().span_to_snippet(args_span
) {
572 args_snippet
= snippet
;
578 &format
!("try calling `{ident}` as a method"),
579 format
!("self.{path_str}({args_snippet})"),
580 Applicability
::MachineApplicable
,
582 return (err
, candidates
);
586 // Try context-dependent help if relaxed lookup didn't work.
587 if let Some(res
) = res
{
588 if self.smart_resolve_context_dependent_help(
594 &base_error
.fallback_label
,
596 // We do this to avoid losing a secondary span when we override the main error span.
597 self.r
.add_typo_suggestion(&mut err
, typo_sugg
, ident_span
);
598 return (err
, candidates
);
603 base_error
.span
.from_expansion() && base_error
.span
.desugaring_kind().is_none();
604 if !self.type_ascription_suggestion(&mut err
, base_error
.span
) {
605 let mut fallback
= false;
607 PathSource
::Trait(AliasPossibility
::Maybe
),
608 Some(Res
::Def(DefKind
::Struct
| DefKind
::Enum
| DefKind
::Union
, _
)),
610 ) = (source
, res
, is_macro
)
612 if let Some(bounds @
[_
, .., _
]) = self.diagnostic_metadata
.current_trait_object
{
614 let spans
: Vec
<Span
> = bounds
616 .map(|bound
| bound
.span())
617 .filter(|&sp
| sp
!= base_error
.span
)
620 let start_span
= bounds
[0].span();
621 // `end_span` is the end of the poly trait ref (Foo + 'baz + Bar><)
622 let end_span
= bounds
.last().unwrap().span();
623 // `last_bound_span` is the last bound of the poly trait ref (Foo + >'baz< + Bar)
624 let last_bound_span
= spans
.last().cloned().unwrap();
625 let mut multi_span
: MultiSpan
= spans
.clone().into();
627 let msg
= if sp
== last_bound_span
{
629 "...because of {these} bound{s}",
630 these
= pluralize
!("this", bounds
.len() - 1),
631 s
= pluralize
!(bounds
.len() - 1),
636 multi_span
.push_span_label(sp
, msg
);
639 .push_span_label(base_error
.span
, "expected this type to be a trait...");
642 "`+` is used to constrain a \"trait object\" type with lifetimes or \
643 auto-traits; structs and enums can't be bound in that way",
645 if bounds
.iter().all(|bound
| match bound
{
646 ast
::GenericBound
::Outlives(_
) => true,
647 ast
::GenericBound
::Trait(tr
, _
) => tr
.span
== base_error
.span
,
649 let mut sugg
= vec
![];
650 if base_error
.span
!= start_span
{
651 sugg
.push((start_span
.until(base_error
.span
), String
::new()));
653 if base_error
.span
!= end_span
{
654 sugg
.push((base_error
.span
.shrink_to_hi().to(end_span
), String
::new()));
657 err
.multipart_suggestion(
658 "if you meant to use a type and not a trait here, remove the bounds",
660 Applicability
::MaybeIncorrect
,
666 fallback
|= self.restrict_assoc_type_in_where_clause(span
, &mut err
);
668 if !self.r
.add_typo_suggestion(&mut err
, typo_sugg
, ident_span
) {
670 match self.diagnostic_metadata
.current_let_binding
{
671 Some((pat_sp
, Some(ty_sp
), None
))
672 if ty_sp
.contains(base_error
.span
) && base_error
.could_be_expr
=>
674 err
.span_suggestion_short(
675 pat_sp
.between(ty_sp
),
676 "use `=` if you meant to assign",
678 Applicability
::MaybeIncorrect
,
684 // If the trait has a single item (which wasn't matched by Levenshtein), suggest it
685 let suggestion
= self.get_single_associated_item(&path
, &source
, is_expected
);
686 self.r
.add_typo_suggestion(&mut err
, suggestion
, ident_span
);
690 err
.span_label(base_error
.span
, base_error
.fallback_label
);
693 if let Some(err_code
) = &err
.code
{
694 if err_code
== &rustc_errors
::error_code
!(E0425
) {
695 for label_rib
in &self.label_ribs
{
696 for (label_ident
, node_id
) in &label_rib
.bindings
{
697 if format
!("'{}", ident
) == label_ident
.to_string() {
698 err
.span_label(label_ident
.span
, "a label with a similar name exists");
699 if let PathSource
::Expr(Some(Expr
{
700 kind
: ExprKind
::Break(None
, Some(_
)),
706 "use the similarly named label",
708 Applicability
::MaybeIncorrect
,
710 // Do not lint against unused label when we suggest them.
711 self.diagnostic_metadata
.unused_labels
.remove(node_id
);
716 } else if err_code
== &rustc_errors
::error_code
!(E0412
) {
717 if let Some(correct
) = Self::likely_rust_type(path
) {
720 "perhaps you intended to use this type",
722 Applicability
::MaybeIncorrect
,
731 fn detect_assoct_type_constraint_meant_as_path(&self, base_span
: Span
, err
: &mut Diagnostic
) {
732 let Some(ty
) = self.diagnostic_metadata
.current_type_path
else { return; }
;
733 let TyKind
::Path(_
, path
) = &ty
.kind
else { return; }
;
734 for segment
in &path
.segments
{
735 let Some(params
) = &segment
.args
else { continue; }
;
736 let ast
::GenericArgs
::AngleBracketed(ref params
) = params
.deref() else { continue; }
;
737 for param
in ¶ms
.args
{
738 let ast
::AngleBracketedArg
::Constraint(constraint
) = param
else { continue; }
;
739 let ast
::AssocConstraintKind
::Bound { bounds }
= &constraint
.kind
else {
742 for bound
in bounds
{
743 let ast
::GenericBound
::Trait(trait_ref
, ast
::TraitBoundModifier
::None
)
748 if base_span
== trait_ref
.span
{
749 err
.span_suggestion_verbose(
750 constraint
.ident
.span
.between(trait_ref
.span
),
751 "you might have meant to write a path instead of an associated type bound",
753 Applicability
::MachineApplicable
,
761 fn suggest_swapping_misplaced_self_ty_and_trait(
763 err
: &mut Diagnostic
,
764 source
: PathSource
<'_
>,
768 if let Some((trait_ref
, self_ty
)) =
769 self.diagnostic_metadata
.currently_processing_impl_trait
.clone()
770 && let TyKind
::Path(_
, self_ty_path
) = &self_ty
.kind
771 && let PathResult
::Module(ModuleOrUniformRoot
::Module(module
)) =
772 self.resolve_path(&Segment
::from_path(self_ty_path
), Some(TypeNS
), None
)
773 && let ModuleKind
::Def(DefKind
::Trait
, ..) = module
.kind
774 && trait_ref
.path
.span
== span
775 && let PathSource
::Trait(_
) = source
776 && let Some(Res
::Def(DefKind
::Struct
| DefKind
::Enum
| DefKind
::Union
, _
)) = res
777 && let Ok(self_ty_str
) =
778 self.r
.session
.source_map().span_to_snippet(self_ty
.span
)
779 && let Ok(trait_ref_str
) =
780 self.r
.session
.source_map().span_to_snippet(trait_ref
.path
.span
)
782 err
.multipart_suggestion(
783 "`impl` items mention the trait being implemented first and the type it is being implemented for second",
784 vec
![(trait_ref
.path
.span
, self_ty_str
), (self_ty
.span
, trait_ref_str
)],
785 Applicability
::MaybeIncorrect
,
790 fn get_single_associated_item(
793 source
: &PathSource
<'_
>,
794 filter_fn
: &impl Fn(Res
) -> bool
,
795 ) -> Option
<TypoSuggestion
> {
796 if let crate::PathSource
::TraitItem(_
) = source
{
797 let mod_path
= &path
[..path
.len() - 1];
798 if let PathResult
::Module(ModuleOrUniformRoot
::Module(module
)) =
799 self.resolve_path(mod_path
, None
, None
)
801 let resolutions
= self.r
.resolutions(module
).borrow();
802 let targets
: Vec
<_
> =
805 .filter_map(|(key
, resolution
)| {
806 resolution
.borrow().binding
.map(|binding
| binding
.res()).and_then(
807 |res
| if filter_fn(res
) { Some((key, res)) }
else { None }
,
811 if targets
.len() == 1 {
812 let target
= targets
[0];
813 return Some(TypoSuggestion
::single_item_from_res(
823 /// Given `where <T as Bar>::Baz: String`, suggest `where T: Bar<Baz = String>`.
824 fn restrict_assoc_type_in_where_clause(&mut self, span
: Span
, err
: &mut Diagnostic
) -> bool
{
825 // Detect that we are actually in a `where` predicate.
826 let (bounded_ty
, bounds
, where_span
) =
827 if let Some(ast
::WherePredicate
::BoundPredicate(ast
::WhereBoundPredicate
{
829 bound_generic_params
,
832 })) = self.diagnostic_metadata
.current_where_predicate
834 if !bound_generic_params
.is_empty() {
837 (bounded_ty
, bounds
, span
)
842 // Confirm that the target is an associated type.
843 let (ty
, position
, path
) = if let ast
::TyKind
::Path(
844 Some(ast
::QSelf { ty, position, .. }
),
848 // use this to verify that ident is a type param.
849 let Some(partial_res
) = self.r
.partial_res_map
.get(&bounded_ty
.id
) else {
853 partial_res
.base_res(),
854 hir
::def
::Res
::Def(hir
::def
::DefKind
::AssocTy
, _
)
855 ) && partial_res
.unresolved_segments() == 0)
864 let peeled_ty
= ty
.peel_refs();
865 if let ast
::TyKind
::Path(None
, type_param_path
) = &peeled_ty
.kind
{
866 // Confirm that the `SelfTy` is a type parameter.
867 let Some(partial_res
) = self.r
.partial_res_map
.get(&peeled_ty
.id
) else {
871 partial_res
.base_res(),
872 hir
::def
::Res
::Def(hir
::def
::DefKind
::TyParam
, _
)
873 ) && partial_res
.unresolved_segments() == 0)
878 [ast
::PathSegment { ident: constrain_ident, args: None, .. }
],
879 [ast
::GenericBound
::Trait(poly_trait_ref
, ast
::TraitBoundModifier
::None
)],
880 ) = (&type_param_path
.segments
[..], &bounds
[..])
882 if let [ast
::PathSegment { ident, args: None, .. }
] =
883 &poly_trait_ref
.trait_ref
.path
.segments
[..]
885 if ident
.span
== span
{
886 err
.span_suggestion_verbose(
888 &format
!("constrain the associated type to `{}`", ident
),
894 .span_to_snippet(ty
.span
) // Account for `<&'a T as Foo>::Bar`.
895 .unwrap_or_else(|_
| constrain_ident
.to_string()),
896 path
.segments
[..*position
]
898 .map(|segment
| path_segment_to_string(segment
))
901 path
.segments
[*position
..]
903 .map(|segment
| path_segment_to_string(segment
))
908 Applicability
::MaybeIncorrect
,
918 /// Check if the source is call expression and the first argument is `self`. If true,
919 /// return the span of whole call and the span for all arguments expect the first one (`self`).
920 fn call_has_self_arg(&self, source
: PathSource
<'_
>) -> Option
<(Span
, Option
<Span
>)> {
921 let mut has_self_arg
= None
;
922 if let PathSource
::Expr(Some(parent
)) = source
{
924 ExprKind
::Call(_
, args
) if !args
.is_empty() => {
925 let mut expr_kind
= &args
[0].kind
;
928 ExprKind
::Path(_
, arg_name
) if arg_name
.segments
.len() == 1 => {
929 if arg_name
.segments
[0].ident
.name
== kw
::SelfLower
{
930 let call_span
= parent
.span
;
931 let tail_args_span
= if args
.len() > 1 {
934 args
.last().unwrap().span
.hi(),
941 has_self_arg
= Some((call_span
, tail_args_span
));
945 ExprKind
::AddrOf(_
, _
, expr
) => expr_kind
= &expr
.kind
,
956 fn followed_by_brace(&self, span
: Span
) -> (bool
, Option
<Span
>) {
957 // HACK(estebank): find a better way to figure out that this was a
958 // parser issue where a struct literal is being used on an expression
959 // where a brace being opened means a block is being started. Look
960 // ahead for the next text to see if `span` is followed by a `{`.
961 let sm
= self.r
.session
.source_map();
964 sp
= sm
.next_point(sp
);
965 match sm
.span_to_snippet(sp
) {
967 if snippet
.chars().any(|c
| !c
.is_whitespace()) {
974 let followed_by_brace
= matches
!(sm
.span_to_snippet(sp
), Ok(ref snippet
) if snippet
== "{");
975 // In case this could be a struct literal that needs to be surrounded
976 // by parentheses, find the appropriate span.
978 let mut closing_brace
= None
;
980 sp
= sm
.next_point(sp
);
981 match sm
.span_to_snippet(sp
) {
984 closing_brace
= Some(span
.to(sp
));
991 // The bigger the span, the more likely we're incorrect --
992 // bound it to 100 chars long.
997 (followed_by_brace
, closing_brace
)
1000 /// Provides context-dependent help for errors reported by the `smart_resolve_path_fragment`
1002 /// Returns `true` if able to provide context-dependent help.
1003 fn smart_resolve_context_dependent_help(
1005 err
: &mut Diagnostic
,
1007 source
: PathSource
<'_
>,
1010 fallback_label
: &str,
1012 let ns
= source
.namespace();
1013 let is_expected
= &|res
| source
.is_expected(res
);
1015 let path_sep
= |err
: &mut Diagnostic
, expr
: &Expr
, kind
: DefKind
| {
1016 const MESSAGE
: &str = "use the path separator to refer to an item";
1018 let (lhs_span
, rhs_span
) = match &expr
.kind
{
1019 ExprKind
::Field(base
, ident
) => (base
.span
, ident
.span
),
1020 ExprKind
::MethodCall(_
, args
, span
) => (args
[0].span
, *span
),
1024 if lhs_span
.eq_ctxt(rhs_span
) {
1025 err
.span_suggestion(
1026 lhs_span
.between(rhs_span
),
1029 Applicability
::MaybeIncorrect
,
1032 } else if kind
== DefKind
::Struct
1033 && let Some(lhs_source_span
) = lhs_span
.find_ancestor_inside(expr
.span
)
1034 && let Ok(snippet
) = self.r
.session
.source_map().span_to_snippet(lhs_source_span
)
1036 // The LHS is a type that originates from a macro call.
1037 // We have to add angle brackets around it.
1039 err
.span_suggestion_verbose(
1040 lhs_source_span
.until(rhs_span
),
1042 format
!("<{snippet}>::"),
1043 Applicability
::MaybeIncorrect
,
1047 // Either we were unable to obtain the source span / the snippet or
1048 // the LHS originates from a macro call and it is not a type and thus
1049 // there is no way to replace `.` with `::` and still somehow suggest
1056 let find_span
= |source
: &PathSource
<'_
>, err
: &mut Diagnostic
| {
1058 PathSource
::Expr(Some(Expr { span, kind: ExprKind::Call(_, _), .. }
))
1059 | PathSource
::TupleStruct(span
, _
) => {
1060 // We want the main underline to cover the suggested code as well for
1062 err
.set_span(*span
);
1069 let mut bad_struct_syntax_suggestion
= |def_id
: DefId
| {
1070 let (followed_by_brace
, closing_brace
) = self.followed_by_brace(span
);
1073 PathSource
::Expr(Some(
1074 parent @ Expr { kind: ExprKind::Field(..) | ExprKind::MethodCall(..), .. }
,
1075 )) if path_sep(err
, &parent
, DefKind
::Struct
) => {}
1081 | ExprKind
::Binary(..)
1082 | ExprKind
::Unary(..)
1084 | ExprKind
::While(..)
1085 | ExprKind
::ForLoop(..)
1086 | ExprKind
::Match(..),
1089 ) if followed_by_brace
=> {
1090 if let Some(sp
) = closing_brace
{
1091 err
.span_label(span
, fallback_label
);
1092 err
.multipart_suggestion(
1093 "surround the struct literal with parentheses",
1095 (sp
.shrink_to_lo(), "(".to_string()),
1096 (sp
.shrink_to_hi(), ")".to_string()),
1098 Applicability
::MaybeIncorrect
,
1102 span
, // Note the parentheses surrounding the suggestion below
1104 "you might want to surround a struct literal with parentheses: \
1105 `({} {{ /* fields */ }})`?",
1111 PathSource
::Expr(_
) | PathSource
::TupleStruct(..) | PathSource
::Pat
=> {
1112 let span
= find_span(&source
, err
);
1113 if let Some(span
) = self.def_span(def_id
) {
1114 err
.span_label(span
, &format
!("`{}` defined here", path_str
));
1116 let (tail
, descr
, applicability
) = match source
{
1117 PathSource
::Pat
| PathSource
::TupleStruct(..) => {
1118 ("", "pattern", Applicability
::MachineApplicable
)
1120 _
=> (": val", "literal", Applicability
::HasPlaceholders
),
1122 let (fields
, applicability
) = match self.r
.field_names
.get(&def_id
) {
1126 .map(|f
| format
!("{}{}", f
.node
, tail
))
1127 .collect
::<Vec
<String
>>()
1131 None
=> ("/* fields */".to_string(), Applicability
::HasPlaceholders
),
1133 let pad
= match self.r
.field_names
.get(&def_id
) {
1134 Some(fields
) if fields
.is_empty() => "",
1137 err
.span_suggestion(
1139 &format
!("use struct {} syntax instead", descr
),
1140 format
!("{path_str} {{{pad}{fields}{pad}}}"),
1145 err
.span_label(span
, fallback_label
);
1150 match (res
, source
) {
1152 Res
::Def(DefKind
::Macro(MacroKind
::Bang
), _
),
1153 PathSource
::Expr(Some(Expr
{
1154 kind
: ExprKind
::Index(..) | ExprKind
::Call(..), ..
1156 | PathSource
::Struct
,
1158 err
.span_label(span
, fallback_label
);
1159 err
.span_suggestion_verbose(
1160 span
.shrink_to_hi(),
1161 "use `!` to invoke the macro",
1163 Applicability
::MaybeIncorrect
,
1165 if path_str
== "try" && span
.rust_2015() {
1166 err
.note("if you want the `try` keyword, you need Rust 2018 or later");
1169 (Res
::Def(DefKind
::Macro(MacroKind
::Bang
), _
), _
) => {
1170 err
.span_label(span
, fallback_label
);
1172 (Res
::Def(DefKind
::TyAlias
, def_id
), PathSource
::Trait(_
)) => {
1173 err
.span_label(span
, "type aliases cannot be used as traits");
1174 if self.r
.session
.is_nightly_build() {
1175 let msg
= "you might have meant to use `#![feature(trait_alias)]` instead of a \
1177 if let Some(span
) = self.def_span(def_id
) {
1178 if let Ok(snip
) = self.r
.session
.source_map().span_to_snippet(span
) {
1179 // The span contains a type alias so we should be able to
1180 // replace `type` with `trait`.
1181 let snip
= snip
.replacen("type", "trait", 1);
1182 err
.span_suggestion(span
, msg
, snip
, Applicability
::MaybeIncorrect
);
1184 err
.span_help(span
, msg
);
1192 Res
::Def(kind @
(DefKind
::Mod
| DefKind
::Trait
), _
),
1193 PathSource
::Expr(Some(parent
)),
1195 if !path_sep(err
, &parent
, kind
) {
1200 Res
::Def(DefKind
::Enum
, def_id
),
1201 PathSource
::TupleStruct(..) | PathSource
::Expr(..),
1204 .diagnostic_metadata
1205 .current_type_ascription
1211 .type_ascription_path_suggestions
1217 err
.downgrade_to_delayed_bug();
1218 // We already suggested changing `:` into `::` during parsing.
1222 self.suggest_using_enum_variant(err
, source
, def_id
, span
);
1224 (Res
::Def(DefKind
::Struct
, def_id
), source
) if ns
== ValueNS
=> {
1225 let (ctor_def
, ctor_vis
, fields
) =
1226 if let Some(struct_ctor
) = self.r
.struct_constructors
.get(&def_id
).cloned() {
1227 if let PathSource
::Expr(Some(parent
)) = source
{
1228 if let ExprKind
::Field(..) | ExprKind
::MethodCall(..) = parent
.kind
{
1229 bad_struct_syntax_suggestion(def_id
);
1235 bad_struct_syntax_suggestion(def_id
);
1239 let is_accessible
= self.r
.is_accessible_from(ctor_vis
, self.parent_scope
.module
);
1240 if !is_expected(ctor_def
) || is_accessible
{
1244 let field_spans
= match source
{
1245 // e.g. `if let Enum::TupleVariant(field1, field2) = _`
1246 PathSource
::TupleStruct(_
, pattern_spans
) => {
1247 err
.set_primary_message(
1248 "cannot match against a tuple struct which contains private fields",
1251 // Use spans of the tuple struct pattern.
1252 Some(Vec
::from(pattern_spans
))
1254 // e.g. `let _ = Enum::TupleVariant(field1, field2);`
1255 _
if source
.is_call() => {
1256 err
.set_primary_message(
1257 "cannot initialize a tuple struct which contains private fields",
1260 // Use spans of the tuple struct definition.
1264 .map(|fields
| fields
.iter().map(|f
| f
.span
).collect
::<Vec
<_
>>())
1269 if let Some(spans
) =
1270 field_spans
.filter(|spans
| spans
.len() > 0 && fields
.len() == spans
.len())
1272 let non_visible_spans
: Vec
<Span
> = iter
::zip(&fields
, &spans
)
1273 .filter(|(vis
, _
)| {
1274 !self.r
.is_accessible_from(**vis
, self.parent_scope
.module
)
1276 .map(|(_
, span
)| *span
)
1279 if non_visible_spans
.len() > 0 {
1280 let mut m
: MultiSpan
= non_visible_spans
.clone().into();
1283 .for_each(|s
| m
.push_span_label(s
, "private field"));
1284 err
.span_note(m
, "constructor is not visible here due to private fields");
1290 err
.span_label(span
, "constructor is not visible here due to private fields");
1294 DefKind
::Union
| DefKind
::Variant
| DefKind
::Ctor(_
, CtorKind
::Fictive
),
1298 ) if ns
== ValueNS
=> {
1299 bad_struct_syntax_suggestion(def_id
);
1301 (Res
::Def(DefKind
::Ctor(_
, CtorKind
::Const
), def_id
), _
) if ns
== ValueNS
=> {
1303 PathSource
::Expr(_
) | PathSource
::TupleStruct(..) | PathSource
::Pat
=> {
1304 let span
= find_span(&source
, err
);
1305 if let Some(span
) = self.def_span(def_id
) {
1306 err
.span_label(span
, &format
!("`{}` defined here", path_str
));
1308 err
.span_suggestion(
1310 "use this syntax instead",
1312 Applicability
::MaybeIncorrect
,
1318 (Res
::Def(DefKind
::Ctor(_
, CtorKind
::Fn
), def_id
), _
) if ns
== ValueNS
=> {
1319 if let Some(span
) = self.def_span(def_id
) {
1320 err
.span_label(span
, &format
!("`{}` defined here", path_str
));
1322 let fields
= self.r
.field_names
.get(&def_id
).map_or_else(
1323 || "/* fields */".to_string(),
1324 |fields
| vec
!["_"; fields
.len()].join(", "),
1326 err
.span_suggestion(
1328 "use the tuple variant pattern syntax instead",
1329 format
!("{}({})", path_str
, fields
),
1330 Applicability
::HasPlaceholders
,
1333 (Res
::SelfTy { .. }
, _
) if ns
== ValueNS
=> {
1334 err
.span_label(span
, fallback_label
);
1335 err
.note("can't use `Self` as a constructor, you must use the implemented struct");
1337 (Res
::Def(DefKind
::TyAlias
| DefKind
::AssocTy
, _
), _
) if ns
== ValueNS
=> {
1338 err
.note("can't use a type alias as a constructor");
1345 /// Given the target `ident` and `kind`, search for the similarly named associated item
1346 /// in `self.current_trait_ref`.
1347 pub(crate) fn find_similarly_named_assoc_item(
1350 kind
: &AssocItemKind
,
1351 ) -> Option
<Symbol
> {
1352 let (module
, _
) = self.current_trait_ref
.as_ref()?
;
1353 if ident
== kw
::Underscore
{
1354 // We do nothing for `_`.
1358 let resolutions
= self.r
.resolutions(module
);
1359 let targets
= resolutions
1362 .filter_map(|(key
, res
)| res
.borrow().binding
.map(|binding
| (key
, binding
.res())))
1363 .filter(|(_
, res
)| match (kind
, res
) {
1364 (AssocItemKind
::Const(..), Res
::Def(DefKind
::AssocConst
, _
)) => true,
1365 (AssocItemKind
::Fn(_
), Res
::Def(DefKind
::AssocFn
, _
)) => true,
1366 (AssocItemKind
::TyAlias(..), Res
::Def(DefKind
::AssocTy
, _
)) => true,
1369 .map(|(key
, _
)| key
.ident
.name
)
1370 .collect
::<Vec
<_
>>();
1372 find_best_match_for_name(&targets
, ident
, None
)
1375 fn lookup_assoc_candidate
<FilterFn
>(
1379 filter_fn
: FilterFn
,
1380 ) -> Option
<AssocSuggestion
>
1382 FilterFn
: Fn(Res
) -> bool
,
1384 fn extract_node_id(t
: &Ty
) -> Option
<NodeId
> {
1386 TyKind
::Path(None
, _
) => Some(t
.id
),
1387 TyKind
::Rptr(_
, ref mut_ty
) => extract_node_id(&mut_ty
.ty
),
1388 // This doesn't handle the remaining `Ty` variants as they are not
1389 // that commonly the self_type, it might be interesting to provide
1390 // support for those in future.
1395 // Fields are generally expected in the same contexts as locals.
1396 if filter_fn(Res
::Local(ast
::DUMMY_NODE_ID
)) {
1397 if let Some(node_id
) =
1398 self.diagnostic_metadata
.current_self_type
.as_ref().and_then(extract_node_id
)
1400 // Look for a field with the same name in the current self_type.
1401 if let Some(resolution
) = self.r
.partial_res_map
.get(&node_id
) {
1402 match resolution
.base_res() {
1403 Res
::Def(DefKind
::Struct
| DefKind
::Union
, did
)
1404 if resolution
.unresolved_segments() == 0 =>
1406 if let Some(field_names
) = self.r
.field_names
.get(&did
) {
1409 .any(|&field_name
| ident
.name
== field_name
.node
)
1411 return Some(AssocSuggestion
::Field
);
1421 if let Some(items
) = self.diagnostic_metadata
.current_trait_assoc_items
{
1422 for assoc_item
in items
{
1423 if assoc_item
.ident
== ident
{
1424 return Some(match &assoc_item
.kind
{
1425 ast
::AssocItemKind
::Const(..) => AssocSuggestion
::AssocConst
,
1426 ast
::AssocItemKind
::Fn(box ast
::Fn { sig, .. }
) if sig
.decl
.has_self() => {
1427 AssocSuggestion
::MethodWithSelf
1429 ast
::AssocItemKind
::Fn(..) => AssocSuggestion
::AssocFn
,
1430 ast
::AssocItemKind
::TyAlias(..) => AssocSuggestion
::AssocType
,
1431 ast
::AssocItemKind
::MacCall(_
) => continue,
1437 // Look for associated items in the current trait.
1438 if let Some((module
, _
)) = self.current_trait_ref
{
1439 if let Ok(binding
) = self.r
.maybe_resolve_ident_in_module(
1440 ModuleOrUniformRoot
::Module(module
),
1445 let res
= binding
.res();
1447 if self.r
.has_self
.contains(&res
.def_id()) {
1448 return Some(AssocSuggestion
::MethodWithSelf
);
1451 Res
::Def(DefKind
::AssocFn
, _
) => return Some(AssocSuggestion
::AssocFn
),
1452 Res
::Def(DefKind
::AssocConst
, _
) => {
1453 return Some(AssocSuggestion
::AssocConst
);
1455 Res
::Def(DefKind
::AssocTy
, _
) => {
1456 return Some(AssocSuggestion
::AssocType
);
1468 fn lookup_typo_candidate(
1472 filter_fn
: &impl Fn(Res
) -> bool
,
1473 ) -> Option
<TypoSuggestion
> {
1474 let mut names
= Vec
::new();
1475 if path
.len() == 1 {
1476 // Search in lexical scope.
1477 // Walk backwards up the ribs in scope and collect candidates.
1478 for rib
in self.ribs
[ns
].iter().rev() {
1479 // Locals and type parameters
1480 for (ident
, &res
) in &rib
.bindings
{
1482 names
.push(TypoSuggestion
::typo_from_res(ident
.name
, res
));
1486 if let RibKind
::ModuleRibKind(module
) = rib
.kind
{
1487 // Items from this module
1488 self.r
.add_module_candidates(module
, &mut names
, &filter_fn
);
1490 if let ModuleKind
::Block
= module
.kind
{
1491 // We can see through blocks
1493 // Items from the prelude
1494 if !module
.no_implicit_prelude
{
1495 let extern_prelude
= self.r
.extern_prelude
.clone();
1496 names
.extend(extern_prelude
.iter().flat_map(|(ident
, _
)| {
1497 self.r
.crate_loader
.maybe_process_path_extern(ident
.name
).and_then(
1500 Res
::Def(DefKind
::Mod
, crate_id
.as_def_id());
1502 if filter_fn(crate_mod
) {
1503 Some(TypoSuggestion
::typo_from_res(
1504 ident
.name
, crate_mod
,
1513 if let Some(prelude
) = self.r
.prelude
{
1514 self.r
.add_module_candidates(prelude
, &mut names
, &filter_fn
);
1521 // Add primitive types to the mix
1522 if filter_fn(Res
::PrimTy(PrimTy
::Bool
)) {
1523 names
.extend(PrimTy
::ALL
.iter().map(|prim_ty
| {
1524 TypoSuggestion
::typo_from_res(prim_ty
.name(), Res
::PrimTy(*prim_ty
))
1528 // Search in module.
1529 let mod_path
= &path
[..path
.len() - 1];
1530 if let PathResult
::Module(ModuleOrUniformRoot
::Module(module
)) =
1531 self.resolve_path(mod_path
, Some(TypeNS
), None
)
1533 self.r
.add_module_candidates(module
, &mut names
, &filter_fn
);
1537 let name
= path
[path
.len() - 1].ident
.name
;
1538 // Make sure error reporting is deterministic.
1539 names
.sort_by(|a
, b
| a
.candidate
.as_str().partial_cmp(b
.candidate
.as_str()).unwrap());
1541 match find_best_match_for_name(
1542 &names
.iter().map(|suggestion
| suggestion
.candidate
).collect
::<Vec
<Symbol
>>(),
1546 Some(found
) if found
!= name
=> {
1547 names
.into_iter().find(|suggestion
| suggestion
.candidate
== found
)
1553 // Returns the name of the Rust type approximately corresponding to
1554 // a type name in another programming language.
1555 fn likely_rust_type(path
: &[Segment
]) -> Option
<Symbol
> {
1556 let name
= path
[path
.len() - 1].ident
.as_str();
1557 // Common Java types
1559 "byte" => sym
::u8, // In Java, bytes are signed, but in practice one almost always wants unsigned bytes.
1560 "short" => sym
::i16,
1561 "Bool" => sym
::bool
,
1562 "Boolean" => sym
::bool
,
1563 "boolean" => sym
::bool
,
1566 "float" => sym
::f32,
1567 "double" => sym
::f64,
1572 /// Only used in a specific case of type ascription suggestions
1573 fn get_colon_suggestion_span(&self, start
: Span
) -> Span
{
1574 let sm
= self.r
.session
.source_map();
1575 start
.to(sm
.next_point(start
))
1578 fn type_ascription_suggestion(&self, err
: &mut Diagnostic
, base_span
: Span
) -> bool
{
1579 let sm
= self.r
.session
.source_map();
1580 let base_snippet
= sm
.span_to_snippet(base_span
);
1581 if let Some(&sp
) = self.diagnostic_metadata
.current_type_ascription
.last() {
1582 if let Ok(snippet
) = sm
.span_to_snippet(sp
) {
1583 let len
= snippet
.trim_end().len() as u32;
1584 if snippet
.trim() == ":" {
1586 sp
.with_lo(sp
.lo() + BytePos(len
- 1)).with_hi(sp
.lo() + BytePos(len
));
1587 let mut show_label
= true;
1588 if sm
.is_multiline(sp
) {
1589 err
.span_suggestion_short(
1591 "maybe you meant to write `;` here",
1593 Applicability
::MaybeIncorrect
,
1596 let after_colon_sp
=
1597 self.get_colon_suggestion_span(colon_sp
.shrink_to_hi());
1598 if snippet
.len() == 1 {
1600 err
.span_suggestion(
1602 "maybe you meant to write a path separator here",
1604 Applicability
::MaybeIncorrect
,
1611 .type_ascription_path_suggestions
1615 err
.downgrade_to_delayed_bug();
1618 if let Ok(base_snippet
) = base_snippet
{
1619 let mut sp
= after_colon_sp
;
1621 // Try to find an assignment
1622 sp
= sm
.next_point(sp
);
1623 let snippet
= sm
.span_to_snippet(sp
.to(sm
.next_point(sp
)));
1625 Ok(ref x
) if x
.as_str() == "=" => {
1626 err
.span_suggestion(
1628 "maybe you meant to write an assignment here",
1629 format
!("let {}", base_snippet
),
1630 Applicability
::MaybeIncorrect
,
1635 Ok(ref x
) if x
.as_str() == "\n" => break,
1645 "expecting a type here because of type ascription",
1655 fn find_module(&mut self, def_id
: DefId
) -> Option
<(Module
<'a
>, ImportSuggestion
)> {
1656 let mut result
= None
;
1657 let mut seen_modules
= FxHashSet
::default();
1658 let mut worklist
= vec
![(self.r
.graph_root
, Vec
::new())];
1660 while let Some((in_module
, path_segments
)) = worklist
.pop() {
1661 // abort if the module is already found
1662 if result
.is_some() {
1666 in_module
.for_each_child(self.r
, |_
, ident
, _
, name_binding
| {
1667 // abort if the module is already found or if name_binding is private external
1668 if result
.is_some() || !name_binding
.vis
.is_visible_locally() {
1671 if let Some(module
) = name_binding
.module() {
1673 let mut path_segments
= path_segments
.clone();
1674 path_segments
.push(ast
::PathSegment
::from_ident(ident
));
1675 let module_def_id
= module
.def_id();
1676 if module_def_id
== def_id
{
1678 Path { span: name_binding.span, segments: path_segments, tokens: None }
;
1690 // add the module to the lookup
1691 if seen_modules
.insert(module_def_id
) {
1692 worklist
.push((module
, path_segments
));
1702 fn collect_enum_ctors(&mut self, def_id
: DefId
) -> Option
<Vec
<(Path
, DefId
, CtorKind
)>> {
1703 self.find_module(def_id
).map(|(enum_module
, enum_import_suggestion
)| {
1704 let mut variants
= Vec
::new();
1705 enum_module
.for_each_child(self.r
, |_
, ident
, _
, name_binding
| {
1706 if let Res
::Def(DefKind
::Ctor(CtorOf
::Variant
, kind
), def_id
) = name_binding
.res() {
1707 let mut segms
= enum_import_suggestion
.path
.segments
.clone();
1708 segms
.push(ast
::PathSegment
::from_ident(ident
));
1709 let path
= Path { span: name_binding.span, segments: segms, tokens: None }
;
1710 variants
.push((path
, def_id
, kind
));
1717 /// Adds a suggestion for using an enum's variant when an enum is used instead.
1718 fn suggest_using_enum_variant(
1720 err
: &mut Diagnostic
,
1721 source
: PathSource
<'_
>,
1725 let Some(variants
) = self.collect_enum_ctors(def_id
) else {
1726 err
.note("you might have meant to use one of the enum's variants");
1730 let suggest_only_tuple_variants
=
1731 matches
!(source
, PathSource
::TupleStruct(..)) || source
.is_call();
1732 if suggest_only_tuple_variants
{
1733 // Suggest only tuple variants regardless of whether they have fields and do not
1734 // suggest path with added parentheses.
1735 let suggestable_variants
= variants
1737 .filter(|(.., kind
)| *kind
== CtorKind
::Fn
)
1738 .map(|(variant
, ..)| path_names_to_string(variant
))
1739 .collect
::<Vec
<_
>>();
1741 let non_suggestable_variant_count
= variants
.len() - suggestable_variants
.len();
1743 let source_msg
= if source
.is_call() {
1745 } else if matches
!(source
, PathSource
::TupleStruct(..)) {
1751 if !suggestable_variants
.is_empty() {
1752 let msg
= if non_suggestable_variant_count
== 0 && suggestable_variants
.len() == 1 {
1753 format
!("try {} the enum's variant", source_msg
)
1755 format
!("try {} one of the enum's variants", source_msg
)
1758 err
.span_suggestions(
1761 suggestable_variants
.into_iter(),
1762 Applicability
::MaybeIncorrect
,
1766 // If the enum has no tuple variants..
1767 if non_suggestable_variant_count
== variants
.len() {
1768 err
.help(&format
!("the enum has no tuple variants {}", source_msg
));
1771 // If there are also non-tuple variants..
1772 if non_suggestable_variant_count
== 1 {
1774 "you might have meant {} the enum's non-tuple variant",
1777 } else if non_suggestable_variant_count
>= 1 {
1779 "you might have meant {} one of the enum's non-tuple variants",
1784 let needs_placeholder
= |def_id
: DefId
, kind
: CtorKind
| {
1785 let has_no_fields
= self.r
.field_names
.get(&def_id
).map_or(false, |f
| f
.is_empty());
1787 CtorKind
::Const
=> false,
1788 CtorKind
::Fn
| CtorKind
::Fictive
if has_no_fields
=> false,
1793 let suggestable_variants
= variants
1795 .filter(|(_
, def_id
, kind
)| !needs_placeholder(*def_id
, *kind
))
1796 .map(|(variant
, _
, kind
)| (path_names_to_string(variant
), kind
))
1797 .map(|(variant
, kind
)| match kind
{
1798 CtorKind
::Const
=> variant
,
1799 CtorKind
::Fn
=> format
!("({}())", variant
),
1800 CtorKind
::Fictive
=> format
!("({} {{}})", variant
),
1802 .collect
::<Vec
<_
>>();
1803 let no_suggestable_variant
= suggestable_variants
.is_empty();
1805 if !no_suggestable_variant
{
1806 let msg
= if suggestable_variants
.len() == 1 {
1807 "you might have meant to use the following enum variant"
1809 "you might have meant to use one of the following enum variants"
1812 err
.span_suggestions(
1815 suggestable_variants
.into_iter(),
1816 Applicability
::MaybeIncorrect
,
1820 let suggestable_variants_with_placeholders
= variants
1822 .filter(|(_
, def_id
, kind
)| needs_placeholder(*def_id
, *kind
))
1823 .map(|(variant
, _
, kind
)| (path_names_to_string(variant
), kind
))
1824 .filter_map(|(variant
, kind
)| match kind
{
1825 CtorKind
::Fn
=> Some(format
!("({}(/* fields */))", variant
)),
1826 CtorKind
::Fictive
=> Some(format
!("({} {{ /* fields */ }})", variant
)),
1829 .collect
::<Vec
<_
>>();
1831 if !suggestable_variants_with_placeholders
.is_empty() {
1833 match (no_suggestable_variant
, suggestable_variants_with_placeholders
.len()) {
1834 (true, 1) => "the following enum variant is available",
1835 (true, _
) => "the following enum variants are available",
1836 (false, 1) => "alternatively, the following enum variant is available",
1838 "alternatively, the following enum variants are also available"
1842 err
.span_suggestions(
1845 suggestable_variants_with_placeholders
.into_iter(),
1846 Applicability
::HasPlaceholders
,
1851 if def_id
.is_local() {
1852 if let Some(span
) = self.def_span(def_id
) {
1853 err
.span_note(span
, "the enum is defined here");
1858 pub(crate) fn report_missing_type_error(
1861 ) -> Option
<(Span
, &'
static str, String
, Applicability
)> {
1862 let (ident
, span
) = match path
{
1863 [segment
] if !segment
.has_generic_args
&& segment
.ident
.name
!= kw
::SelfUpper
=> {
1864 (segment
.ident
.to_string(), segment
.ident
.span
)
1868 let mut iter
= ident
.chars().map(|c
| c
.is_uppercase());
1869 let single_uppercase_char
=
1870 matches
!(iter
.next(), Some(true)) && matches
!(iter
.next(), None
);
1871 if !self.diagnostic_metadata
.currently_processing_generics
&& !single_uppercase_char
{
1874 match (self.diagnostic_metadata
.current_item
, single_uppercase_char
, self.diagnostic_metadata
.currently_processing_generics
) {
1875 (Some(Item { kind: ItemKind::Fn(..), ident, .. }
), _
, _
) if ident
.name
== sym
::main
=> {
1876 // Ignore `fn main()` as we don't want to suggest `fn main<T>()`
1881 kind @ ItemKind
::Fn(..)
1882 | kind @ ItemKind
::Enum(..)
1883 | kind @ ItemKind
::Struct(..)
1884 | kind @ ItemKind
::Union(..),
1889 // Without the 2nd `true`, we'd suggest `impl <T>` for `impl T` when a type `T` isn't found
1890 | (Some(Item { kind: kind @ ItemKind::Impl(..), .. }
), true, true)
1891 | (Some(Item { kind, .. }
), false, _
) => {
1892 // Likely missing type parameter.
1893 if let Some(generics
) = kind
.generics() {
1894 if span
.overlaps(generics
.span
) {
1895 // Avoid the following:
1896 // error[E0405]: cannot find trait `A` in this scope
1897 // --> $DIR/typo-suggestion-named-underscore.rs:CC:LL
1899 // L | fn foo<T: A>(x: T) {} // Shouldn't suggest underscore
1900 // | ^- help: you might be missing a type parameter: `, A`
1902 // | not found in this scope
1905 let msg
= "you might be missing a type parameter";
1906 let (span
, sugg
) = if let [.., param
] = &generics
.params
[..] {
1907 let span
= if let [.., bound
] = ¶m
.bounds
[..] {
1909 } else if let GenericParam
{
1910 kind
: GenericParamKind
::Const { ty, kw_span: _, default }
, ..
1912 default.as_ref().map(|def
| def
.value
.span
).unwrap_or(ty
.span
)
1916 (span
, format
!(", {}", ident
))
1918 (generics
.span
, format
!("<{}>", ident
))
1920 // Do not suggest if this is coming from macro expansion.
1921 if span
.can_be_used_for_suggestions() {
1923 span
.shrink_to_hi(),
1926 Applicability
::MaybeIncorrect
,
1936 /// Given the target `label`, search the `rib_index`th label rib for similarly named labels,
1937 /// optionally returning the closest match and whether it is reachable.
1938 pub(crate) fn suggestion_for_label_in_rib(
1942 ) -> Option
<LabelSuggestion
> {
1943 // Are ribs from this `rib_index` within scope?
1944 let within_scope
= self.is_label_valid_from_rib(rib_index
);
1946 let rib
= &self.label_ribs
[rib_index
];
1950 .filter(|(id
, _
)| id
.span
.eq_ctxt(label
.span
))
1951 .map(|(id
, _
)| id
.name
)
1952 .collect
::<Vec
<Symbol
>>();
1954 find_best_match_for_name(&names
, label
.name
, None
).map(|symbol
| {
1955 // Upon finding a similar name, get the ident that it was from - the span
1956 // contained within helps make a useful diagnostic. In addition, determine
1957 // whether this candidate is within scope.
1958 let (ident
, _
) = rib
.bindings
.iter().find(|(ident
, _
)| ident
.name
== symbol
).unwrap();
1959 (*ident
, within_scope
)
1963 pub(crate) fn maybe_report_lifetime_uses(
1965 generics_span
: Span
,
1966 params
: &[ast
::GenericParam
],
1968 for (param_index
, param
) in params
.iter().enumerate() {
1969 let GenericParamKind
::Lifetime
= param
.kind
else { continue }
;
1971 let def_id
= self.r
.local_def_id(param
.id
);
1973 let use_set
= self.lifetime_uses
.remove(&def_id
);
1975 "Use set for {:?}({:?} at {:?}) is {:?}",
1976 def_id
, param
.ident
, param
.ident
.span
, use_set
1979 let deletion_span
= || {
1980 if params
.len() == 1 {
1981 // if sole lifetime, remove the entire `<>` brackets
1983 } else if param_index
== 0 {
1984 // if removing within `<>` brackets, we also want to
1985 // delete a leading or trailing comma as appropriate
1986 param
.span().to(params
[param_index
+ 1].span().shrink_to_lo())
1988 // if removing within `<>` brackets, we also want to
1989 // delete a leading or trailing comma as appropriate
1990 params
[param_index
- 1].span().shrink_to_hi().to(param
.span())
1994 Some(LifetimeUseSet
::Many
) => {}
1995 Some(LifetimeUseSet
::One { use_span, use_ctxt }
) => {
1996 debug
!(?param
.ident
, ?param
.ident
.span
, ?use_span
);
1998 let elidable
= matches
!(use_ctxt
, LifetimeCtxt
::Rptr
);
2000 let deletion_span
= deletion_span();
2001 self.r
.lint_buffer
.buffer_lint_with_diagnostic(
2002 lint
::builtin
::SINGLE_USE_LIFETIMES
,
2005 &format
!("lifetime parameter `{}` only used once", param
.ident
),
2006 lint
::BuiltinLintDiagnostics
::SingleUseLifetime
{
2007 param_span
: param
.ident
.span
,
2008 use_span
: Some((use_span
, elidable
)),
2014 debug
!(?param
.ident
, ?param
.ident
.span
);
2016 let deletion_span
= deletion_span();
2017 self.r
.lint_buffer
.buffer_lint_with_diagnostic(
2018 lint
::builtin
::UNUSED_LIFETIMES
,
2021 &format
!("lifetime parameter `{}` never used", param
.ident
),
2022 lint
::BuiltinLintDiagnostics
::SingleUseLifetime
{
2023 param_span
: param
.ident
.span
,
2033 pub(crate) fn emit_undeclared_lifetime_error(
2035 lifetime_ref
: &ast
::Lifetime
,
2036 outer_lifetime_ref
: Option
<Ident
>,
2038 debug_assert_ne
!(lifetime_ref
.ident
.name
, kw
::UnderscoreLifetime
);
2039 let mut err
= if let Some(outer
) = outer_lifetime_ref
{
2040 let mut err
= struct_span_err
!(
2042 lifetime_ref
.ident
.span
,
2044 "can't use generic parameters from outer item",
2046 err
.span_label(lifetime_ref
.ident
.span
, "use of generic parameter from outer item");
2047 err
.span_label(outer
.span
, "lifetime parameter from outer item");
2050 let mut err
= struct_span_err
!(
2052 lifetime_ref
.ident
.span
,
2054 "use of undeclared lifetime name `{}`",
2057 err
.span_label(lifetime_ref
.ident
.span
, "undeclared lifetime");
2060 self.suggest_introducing_lifetime(
2062 Some(lifetime_ref
.ident
.name
.as_str()),
2063 |err
, _
, span
, message
, suggestion
| {
2064 err
.span_suggestion(span
, message
, suggestion
, Applicability
::MaybeIncorrect
);
2071 fn suggest_introducing_lifetime(
2073 err
: &mut Diagnostic
,
2075 suggest
: impl Fn(&mut Diagnostic
, bool
, Span
, &str, String
) -> bool
,
2077 let mut suggest_note
= true;
2078 for rib
in self.lifetime_ribs
.iter().rev() {
2079 let mut should_continue
= true;
2081 LifetimeRibKind
::Generics { binder: _, span, kind }
=> {
2082 if !span
.can_be_used_for_suggestions() && suggest_note
&& let Some(name
) = name
{
2083 suggest_note
= false; // Avoid displaying the same help multiple times.
2087 "lifetime `{}` is missing in item created through this procedural macro",
2094 let higher_ranked
= matches
!(
2096 LifetimeBinderKind
::BareFnType
2097 | LifetimeBinderKind
::PolyTrait
2098 | LifetimeBinderKind
::WhereBound
2100 let (span
, sugg
) = if span
.is_empty() {
2103 if higher_ranked { "for" }
else { "" }
,
2104 name
.unwrap_or("'a"),
2105 if higher_ranked { " " }
else { "" }
,
2110 self.r
.session
.source_map().span_through_char(span
, '
<'
).shrink_to_hi();
2111 let sugg
= format
!("{}, ", name
.unwrap_or("'a"));
2115 let message
= format
!(
2116 "consider making the {} lifetime-generic with a new `{}` lifetime",
2118 name
.unwrap_or("'a"),
2120 should_continue
= suggest(err
, true, span
, &message
, sugg
);
2122 "for more information on higher-ranked polymorphism, visit \
2123 https://doc.rust-lang.org/nomicon/hrtb.html",
2125 } else if let Some(name
) = name
{
2126 let message
= format
!("consider introducing lifetime `{}` here", name
);
2127 should_continue
= suggest(err
, false, span
, &message
, sugg
);
2129 let message
= format
!("consider introducing a named lifetime parameter");
2130 should_continue
= suggest(err
, false, span
, &message
, sugg
);
2133 LifetimeRibKind
::Item
=> break,
2136 if !should_continue
{
2142 pub(crate) fn emit_non_static_lt_in_const_generic_error(&self, lifetime_ref
: &ast
::Lifetime
) {
2145 lifetime_ref
.ident
.span
,
2147 "use of non-static lifetime `{}` in const generic",
2151 "for more information, see issue #74052 \
2152 <https://github.com/rust-lang/rust/issues/74052>",
2157 /// Non-static lifetimes are prohibited in anonymous constants under `min_const_generics`.
2158 /// This function will emit an error if `generic_const_exprs` is not enabled, the body identified by
2159 /// `body_id` is an anonymous constant and `lifetime_ref` is non-static.
2160 pub(crate) fn maybe_emit_forbidden_non_static_lifetime_error(
2162 lifetime_ref
: &ast
::Lifetime
,
2164 let feature_active
= self.r
.session
.features_untracked().generic_const_exprs
;
2165 if !feature_active
{
2167 &self.r
.session
.parse_sess
,
2168 sym
::generic_const_exprs
,
2169 lifetime_ref
.ident
.span
,
2170 "a non-static lifetime is not allowed in a `const`",
2176 pub(crate) fn report_missing_lifetime_specifiers(
2178 lifetime_refs
: Vec
<MissingLifetime
>,
2179 function_param_lifetimes
: Option
<(Vec
<MissingLifetime
>, Vec
<ElisionFnParameter
>)>,
2180 ) -> ErrorGuaranteed
{
2181 let num_lifetimes
: usize = lifetime_refs
.iter().map(|lt
| lt
.count
).sum();
2182 let spans
: Vec
<_
> = lifetime_refs
.iter().map(|lt
| lt
.span
).collect();
2184 let mut err
= struct_span_err
!(
2188 "missing lifetime specifier{}",
2189 pluralize
!(num_lifetimes
)
2191 self.add_missing_lifetime_specifiers_label(
2194 function_param_lifetimes
,
2199 fn add_missing_lifetime_specifiers_label(
2201 err
: &mut Diagnostic
,
2202 lifetime_refs
: Vec
<MissingLifetime
>,
2203 function_param_lifetimes
: Option
<(Vec
<MissingLifetime
>, Vec
<ElisionFnParameter
>)>,
2205 for <
in &lifetime_refs
{
2209 "expected {} lifetime parameter{}",
2210 if lt
.count
== 1 { "named".to_string() }
else { lt.count.to_string() }
,
2211 pluralize
!(lt
.count
),
2216 let mut in_scope_lifetimes
: Vec
<_
> = self
2220 .take_while(|rib
| !matches
!(rib
.kind
, LifetimeRibKind
::Item
))
2221 .flat_map(|rib
| rib
.bindings
.iter())
2222 .map(|(&ident
, &res
)| (ident
, res
))
2223 .filter(|(ident
, _
)| ident
.name
!= kw
::UnderscoreLifetime
)
2225 debug
!(?in_scope_lifetimes
);
2227 debug
!(?function_param_lifetimes
);
2228 if let Some((param_lifetimes
, params
)) = &function_param_lifetimes
{
2229 let elided_len
= param_lifetimes
.len();
2230 let num_params
= params
.len();
2232 let mut m
= String
::new();
2234 for (i
, info
) in params
.iter().enumerate() {
2235 let ElisionFnParameter { ident, index, lifetime_count, span }
= *info
;
2236 debug_assert_ne
!(lifetime_count
, 0);
2238 err
.span_label(span
, "");
2241 if i
+ 1 < num_params
{
2243 } else if num_params
== 2 {
2246 m
.push_str(", or ");
2250 let help_name
= if let Some(ident
) = ident
{
2251 format
!("`{}`", ident
)
2253 format
!("argument {}", index
+ 1)
2256 if lifetime_count
== 1 {
2257 m
.push_str(&help_name
[..])
2259 m
.push_str(&format
!("one of {}'s {} lifetimes", help_name
, lifetime_count
)[..])
2263 if num_params
== 0 {
2265 "this function's return type contains a borrowed value, \
2266 but there is no value for it to be borrowed from",
2268 if in_scope_lifetimes
.is_empty() {
2269 in_scope_lifetimes
= vec
![(
2270 Ident
::with_dummy_span(kw
::StaticLifetime
),
2271 (DUMMY_NODE_ID
, LifetimeRes
::Static
),
2274 } else if elided_len
== 0 {
2276 "this function's return type contains a borrowed value with \
2277 an elided lifetime, but the lifetime cannot be derived from \
2280 if in_scope_lifetimes
.is_empty() {
2281 in_scope_lifetimes
= vec
![(
2282 Ident
::with_dummy_span(kw
::StaticLifetime
),
2283 (DUMMY_NODE_ID
, LifetimeRes
::Static
),
2286 } else if num_params
== 1 {
2288 "this function's return type contains a borrowed value, \
2289 but the signature does not say which {} it is borrowed from",
2294 "this function's return type contains a borrowed value, \
2295 but the signature does not say whether it is borrowed from {}",
2301 let existing_name
= match &in_scope_lifetimes
[..] {
2302 [] => Symbol
::intern("'a"),
2303 [(existing
, _
)] => existing
.name
,
2304 _
=> Symbol
::intern("'lifetime"),
2307 let mut spans_suggs
: Vec
<_
> = Vec
::new();
2308 let build_sugg
= |lt
: MissingLifetime
| match lt
.kind
{
2309 MissingLifetimeKind
::Underscore
=> {
2310 debug_assert_eq
!(lt
.count
, 1);
2311 (lt
.span
, existing_name
.to_string())
2313 MissingLifetimeKind
::Ampersand
=> {
2314 debug_assert_eq
!(lt
.count
, 1);
2315 (lt
.span
.shrink_to_hi(), format
!("{} ", existing_name
))
2317 MissingLifetimeKind
::Comma
=> {
2318 let sugg
: String
= std
::iter
::repeat([existing_name
.as_str(), ", "])
2322 (lt
.span
.shrink_to_hi(), sugg
)
2324 MissingLifetimeKind
::Brackets
=> {
2325 let sugg
: String
= std
::iter
::once("<")
2327 std
::iter
::repeat(existing_name
.as_str()).take(lt
.count
).intersperse(", "),
2331 (lt
.span
.shrink_to_hi(), sugg
)
2334 for <
in &lifetime_refs
{
2335 spans_suggs
.push(build_sugg(lt
));
2337 debug
!(?spans_suggs
);
2338 match in_scope_lifetimes
.len() {
2340 if let Some((param_lifetimes
, _
)) = function_param_lifetimes
{
2341 for lt
in param_lifetimes
{
2342 spans_suggs
.push(build_sugg(lt
))
2345 self.suggest_introducing_lifetime(
2348 |err
, higher_ranked
, span
, message
, intro_sugg
| {
2349 err
.multipart_suggestion_verbose(
2351 std
::iter
::once((span
, intro_sugg
))
2352 .chain(spans_suggs
.iter().cloned())
2354 Applicability
::MaybeIncorrect
,
2361 err
.multipart_suggestion_verbose(
2362 &format
!("consider using the `{}` lifetime", existing_name
),
2364 Applicability
::MaybeIncorrect
,
2367 // Record as using the suggested resolution.
2368 let (_
, (_
, res
)) = in_scope_lifetimes
[0];
2369 for <
in &lifetime_refs
{
2370 self.r
.lifetimes_res_map
.insert(lt
.id
, res
);
2374 let lifetime_spans
: Vec
<_
> =
2375 in_scope_lifetimes
.iter().map(|(ident
, _
)| ident
.span
).collect();
2376 err
.span_note(lifetime_spans
, "these named lifetimes are available to use");
2378 if spans_suggs
.len() > 0 {
2379 // This happens when we have `Foo<T>` where we point at the space before `T`,
2380 // but this can be confusing so we give a suggestion with placeholders.
2381 err
.multipart_suggestion_verbose(
2382 "consider using one of the available lifetimes here",
2384 Applicability
::HasPlaceholders
,
2392 /// Report lifetime/lifetime shadowing as an error.
2393 pub fn signal_lifetime_shadowing(sess
: &Session
, orig
: Ident
, shadower
: Ident
) {
2394 let mut err
= struct_span_err
!(
2398 "lifetime name `{}` shadows a lifetime name that is already in scope",
2401 err
.span_label(orig
.span
, "first declared here");
2402 err
.span_label(shadower
.span
, format
!("lifetime `{}` already in scope", orig
.name
));
2406 /// Shadowing involving a label is only a warning for historical reasons.
2407 //FIXME: make this a proper lint.
2408 pub fn signal_label_shadowing(sess
: &Session
, orig
: Span
, shadower
: Ident
) {
2409 let name
= shadower
.name
;
2410 let shadower
= shadower
.span
;
2411 let mut err
= sess
.struct_span_warn(
2413 &format
!("label name `{}` shadows a label name that is already in scope", name
),
2415 err
.span_label(orig
, "first declared here");
2416 err
.span_label(shadower
, format
!("label `{}` already in scope", name
));