1 use crate::diagnostics
::{ImportSuggestion, TypoSuggestion}
;
2 use crate::late
::lifetimes
::{ElisionFailureInfo, LifetimeContext}
;
3 use crate::late
::{LateResolutionVisitor, RibKind}
;
4 use crate::path_names_to_string
;
5 use crate::{CrateLint, Module, ModuleKind, ModuleOrUniformRoot}
;
6 use crate::{PathResult, PathSource, Segment}
;
8 use rustc_ast
::ast
::{self, Expr, ExprKind, Ident, Item, ItemKind, NodeId, Path, Ty, TyKind}
;
9 use rustc_ast
::util
::lev_distance
::find_best_match_for_name
;
10 use rustc_data_structures
::fx
::FxHashSet
;
11 use rustc_errors
::{pluralize, struct_span_err, Applicability, DiagnosticBuilder}
;
13 use rustc_hir
::def
::Namespace
::{self, *}
;
14 use rustc_hir
::def
::{self, CtorKind, DefKind}
;
15 use rustc_hir
::def_id
::{DefId, CRATE_DEF_INDEX}
;
16 use rustc_hir
::PrimTy
;
17 use rustc_session
::config
::nightly_options
;
18 use rustc_span
::hygiene
::MacroKind
;
19 use rustc_span
::symbol
::{kw, sym}
;
24 type Res
= def
::Res
<ast
::NodeId
>;
26 /// A field or associated item from self type suggested in case of resolution failure.
27 enum AssocSuggestion
{
33 crate enum MissingLifetimeSpot
<'tcx
> {
34 Generics(&'tcx hir
::Generics
<'tcx
>),
35 HigherRanked { span: Span, span_type: ForLifetimeSpanType }
,
38 crate enum ForLifetimeSpanType
{
45 impl ForLifetimeSpanType
{
46 crate fn descr(&self) -> &'
static str {
48 Self::BoundEmpty
| Self::BoundTail
=> "bound",
49 Self::TypeEmpty
| Self::TypeTail
=> "type",
53 crate fn suggestion(&self, sugg
: &str) -> String
{
55 Self::BoundEmpty
| Self::TypeEmpty
=> format
!("for<{}> ", sugg
),
56 Self::BoundTail
| Self::TypeTail
=> format
!(", {}", sugg
),
61 impl<'tcx
> Into
<MissingLifetimeSpot
<'tcx
>> for &'tcx hir
::Generics
<'tcx
> {
62 fn into(self) -> MissingLifetimeSpot
<'tcx
> {
63 MissingLifetimeSpot
::Generics(self)
67 fn is_self_type(path
: &[Segment
], namespace
: Namespace
) -> bool
{
68 namespace
== TypeNS
&& path
.len() == 1 && path
[0].ident
.name
== kw
::SelfUpper
71 fn is_self_value(path
: &[Segment
], namespace
: Namespace
) -> bool
{
72 namespace
== ValueNS
&& path
.len() == 1 && path
[0].ident
.name
== kw
::SelfLower
75 /// Gets the stringified path for an enum from an `ImportSuggestion` for an enum variant.
76 fn import_candidate_to_enum_paths(suggestion
: &ImportSuggestion
) -> (String
, String
) {
77 let variant_path
= &suggestion
.path
;
78 let variant_path_string
= path_names_to_string(variant_path
);
80 let path_len
= suggestion
.path
.segments
.len();
81 let enum_path
= ast
::Path
{
82 span
: suggestion
.path
.span
,
83 segments
: suggestion
.path
.segments
[0..path_len
- 1].to_vec(),
85 let enum_path_string
= path_names_to_string(&enum_path
);
87 (variant_path_string
, enum_path_string
)
90 impl<'a
> LateResolutionVisitor
<'a
, '_
, '_
> {
91 /// Handles error reporting for `smart_resolve_path_fragment` function.
92 /// Creates base error and amends it with one short label and possibly some longer helps/notes.
93 pub(crate) fn smart_resolve_report_errors(
97 source
: PathSource
<'_
>,
99 ) -> (DiagnosticBuilder
<'a
>, Vec
<ImportSuggestion
>) {
100 let ident_span
= path
.last().map_or(span
, |ident
| ident
.ident
.span
);
101 let ns
= source
.namespace();
102 let is_expected
= &|res
| source
.is_expected(res
);
103 let is_enum_variant
= &|res
| {
104 if let Res
::Def(DefKind
::Variant
, _
) = res { true }
else { false }
107 // Make the base error.
108 let expected
= source
.descr_expected();
109 let path_str
= Segment
::names_to_string(path
);
110 let item_str
= path
.last().unwrap().ident
;
111 let (base_msg
, fallback_label
, base_span
, could_be_expr
) = if let Some(res
) = res
{
113 format
!("expected {}, found {} `{}`", expected
, res
.descr(), path_str
),
114 format
!("not a {}", expected
),
117 Res
::Def(DefKind
::Fn
, _
) => {
118 // Verify whether this is a fn call or an Fn used as a type.
122 .span_to_snippet(span
)
123 .map(|snippet
| snippet
.ends_with('
)'
))
127 DefKind
::Ctor(..) | DefKind
::AssocFn
| DefKind
::Const
| DefKind
::AssocConst
,
132 | Res
::Local(_
) => true,
137 let item_span
= path
.last().unwrap().ident
.span
;
138 let (mod_prefix
, mod_str
) = if path
.len() == 1 {
139 (String
::new(), "this scope".to_string())
140 } else if path
.len() == 2 && path
[0].ident
.name
== kw
::PathRoot
{
141 (String
::new(), "the crate root".to_string())
143 let mod_path
= &path
[..path
.len() - 1];
145 match self.resolve_path(mod_path
, Some(TypeNS
), false, span
, CrateLint
::No
) {
146 PathResult
::Module(ModuleOrUniformRoot
::Module(module
)) => module
.res(),
149 .map_or(String
::new(), |res
| format
!("{} ", res
.descr()));
150 (mod_prefix
, format
!("`{}`", Segment
::names_to_string(mod_path
)))
153 format
!("cannot find {} `{}` in {}{}", expected
, item_str
, mod_prefix
, mod_str
),
154 format
!("not found in {}", mod_str
),
160 let code
= source
.error_code(res
.is_some());
161 let mut err
= self.r
.session
.struct_span_err_with_code(base_span
, &base_msg
, code
);
163 // Emit help message for fake-self from other languages (e.g., `this` in Javascript).
164 if ["this", "my"].contains(&&*item_str
.as_str())
165 && self.self_value_is_available(path
[0].ident
.span
, span
)
171 Applicability
::MaybeIncorrect
,
175 // Emit special messages for unresolved `Self` and `self`.
176 if is_self_type(path
, ns
) {
177 err
.code(rustc_errors
::error_code
!(E0411
));
180 "`Self` is only available in impls, traits, and type definitions".to_string(),
182 return (err
, Vec
::new());
184 if is_self_value(path
, ns
) {
185 debug
!("smart_resolve_path_fragment: E0424, source={:?}", source
);
187 err
.code(rustc_errors
::error_code
!(E0424
));
188 err
.span_label(span
, match source
{
189 PathSource
::Pat
=> "`self` value is a keyword and may not be bound to variables or shadowed"
191 _
=> "`self` value is a keyword only available in methods with a `self` parameter"
194 if let Some(span
) = &self.diagnostic_metadata
.current_function
{
195 err
.span_label(*span
, "this function doesn't have a `self` parameter");
197 return (err
, Vec
::new());
200 // Try to lookup name in more relaxed fashion for better error reporting.
201 let ident
= path
.last().unwrap().ident
;
202 let candidates
= self
204 .lookup_import_candidates(ident
, ns
, is_expected
)
206 .filter(|ImportSuggestion { did, .. }
| {
207 match (did
, res
.and_then(|res
| res
.opt_def_id())) {
208 (Some(suggestion_did
), Some(actual_did
)) => *suggestion_did
!= actual_did
,
212 .collect
::<Vec
<_
>>();
213 let crate_def_id
= DefId
::local(CRATE_DEF_INDEX
);
214 if candidates
.is_empty() && is_expected(Res
::Def(DefKind
::Enum
, crate_def_id
)) {
215 let enum_candidates
= self.r
.lookup_import_candidates(ident
, ns
, is_enum_variant
);
216 let mut enum_candidates
= enum_candidates
218 .map(|suggestion
| import_candidate_to_enum_paths(&suggestion
))
219 .collect
::<Vec
<_
>>();
220 enum_candidates
.sort();
222 if !enum_candidates
.is_empty() {
223 // Contextualize for E0412 "cannot find type", but don't belabor the point
224 // (that it's a variant) for E0573 "expected type, found variant".
225 let preamble
= if res
.is_none() {
226 let others
= match enum_candidates
.len() {
228 2 => " and 1 other".to_owned(),
229 n
=> format
!(" and {} others", n
),
231 format
!("there is an enum variant `{}`{}; ", enum_candidates
[0].0, others
)
235 let msg
= format
!("{}try using the variant's enum", preamble
);
237 err
.span_suggestions(
242 .map(|(_variant_path
, enum_ty_path
)| enum_ty_path
)
243 // Variants re-exported in prelude doesn't mean `prelude::v1` is the
245 // FIXME: is there a more principled way to do this that
246 // would work for other re-exports?
247 .filter(|enum_ty_path
| enum_ty_path
!= "std::prelude::v1")
248 // Also write `Option` rather than `std::prelude::v1::Option`.
249 .map(|enum_ty_path
| {
250 // FIXME #56861: DRY-er prelude filtering.
251 enum_ty_path
.trim_start_matches("std::prelude::v1::").to_owned()
253 Applicability
::MachineApplicable
,
257 if path
.len() == 1 && self.self_type_is_available(span
) {
258 if let Some(candidate
) = self.lookup_assoc_candidate(ident
, ns
, is_expected
) {
259 let self_is_available
= self.self_value_is_available(path
[0].ident
.span
, span
);
261 AssocSuggestion
::Field
=> {
262 if self_is_available
{
265 "you might have meant to use the available field",
266 format
!("self.{}", path_str
),
267 Applicability
::MachineApplicable
,
270 err
.span_label(span
, "a field by this name exists in `Self`");
273 AssocSuggestion
::MethodWithSelf
if self_is_available
=> {
277 format
!("self.{}", path_str
),
278 Applicability
::MachineApplicable
,
281 AssocSuggestion
::MethodWithSelf
| AssocSuggestion
::AssocItem
=> {
285 format
!("Self::{}", path_str
),
286 Applicability
::MachineApplicable
,
290 return (err
, candidates
);
293 // If the first argument in call is `self` suggest calling a method.
294 if let Some((call_span
, args_span
)) = self.call_has_self_arg(source
) {
295 let mut args_snippet
= String
::new();
296 if let Some(args_span
) = args_span
{
297 if let Ok(snippet
) = self.r
.session
.source_map().span_to_snippet(args_span
) {
298 args_snippet
= snippet
;
304 &format
!("try calling `{}` as a method", ident
),
305 format
!("self.{}({})", path_str
, args_snippet
),
306 Applicability
::MachineApplicable
,
308 return (err
, candidates
);
312 // Try Levenshtein algorithm.
313 let typo_sugg
= self.lookup_typo_candidate(path
, ns
, is_expected
, span
);
314 let levenshtein_worked
= self.r
.add_typo_suggestion(&mut err
, typo_sugg
, ident_span
);
316 // Try context-dependent help if relaxed lookup didn't work.
317 if let Some(res
) = res
{
318 if self.smart_resolve_context_dependent_help(
326 return (err
, candidates
);
331 if !levenshtein_worked
{
332 err
.span_label(base_span
, fallback_label
);
333 self.type_ascription_suggestion(&mut err
, base_span
);
334 match self.diagnostic_metadata
.current_let_binding
{
335 Some((pat_sp
, Some(ty_sp
), None
)) if ty_sp
.contains(base_span
) && could_be_expr
=> {
336 err
.span_suggestion_short(
337 pat_sp
.between(ty_sp
),
338 "use `=` if you meant to assign",
340 Applicability
::MaybeIncorrect
,
349 /// Check if the source is call expression and the first argument is `self`. If true,
350 /// return the span of whole call and the span for all arguments expect the first one (`self`).
351 fn call_has_self_arg(&self, source
: PathSource
<'_
>) -> Option
<(Span
, Option
<Span
>)> {
352 let mut has_self_arg
= None
;
353 if let PathSource
::Expr(parent
) = source
{
354 match &parent?
.kind
{
355 ExprKind
::Call(_
, args
) if !args
.is_empty() => {
356 let mut expr_kind
= &args
[0].kind
;
359 ExprKind
::Path(_
, arg_name
) if arg_name
.segments
.len() == 1 => {
360 if arg_name
.segments
[0].ident
.name
== kw
::SelfLower
{
361 let call_span
= parent
.unwrap().span
;
362 let tail_args_span
= if args
.len() > 1 {
365 args
.last().unwrap().span
.hi(),
371 has_self_arg
= Some((call_span
, tail_args_span
));
375 ExprKind
::AddrOf(_
, _
, expr
) => expr_kind
= &expr
.kind
,
386 fn followed_by_brace(&self, span
: Span
) -> (bool
, Option
<(Span
, String
)>) {
387 // HACK(estebank): find a better way to figure out that this was a
388 // parser issue where a struct literal is being used on an expression
389 // where a brace being opened means a block is being started. Look
390 // ahead for the next text to see if `span` is followed by a `{`.
391 let sm
= self.r
.session
.source_map();
394 sp
= sm
.next_point(sp
);
395 match sm
.span_to_snippet(sp
) {
397 if snippet
.chars().any(|c
| !c
.is_whitespace()) {
404 let followed_by_brace
= match sm
.span_to_snippet(sp
) {
405 Ok(ref snippet
) if snippet
== "{" => true,
408 // In case this could be a struct literal that needs to be surrounded
409 // by parenthesis, find the appropriate span.
411 let mut closing_brace
= None
;
413 sp
= sm
.next_point(sp
);
414 match sm
.span_to_snippet(sp
) {
417 let sp
= span
.to(sp
);
418 if let Ok(snippet
) = sm
.span_to_snippet(sp
) {
419 closing_brace
= Some((sp
, snippet
));
427 // The bigger the span, the more likely we're incorrect --
428 // bound it to 100 chars long.
433 (followed_by_brace
, closing_brace
)
436 /// Provides context-dependent help for errors reported by the `smart_resolve_path_fragment`
438 /// Returns `true` if able to provide context-dependent help.
439 fn smart_resolve_context_dependent_help(
441 err
: &mut DiagnosticBuilder
<'a
>,
443 source
: PathSource
<'_
>,
446 fallback_label
: &str,
448 let ns
= source
.namespace();
449 let is_expected
= &|res
| source
.is_expected(res
);
451 let path_sep
= |err
: &mut DiagnosticBuilder
<'_
>, expr
: &Expr
| match expr
.kind
{
452 ExprKind
::Field(_
, ident
) => {
455 "use the path separator to refer to an item",
456 format
!("{}::{}", path_str
, ident
),
457 Applicability
::MaybeIncorrect
,
461 ExprKind
::MethodCall(ref segment
, ..) => {
462 let span
= expr
.span
.with_hi(segment
.ident
.span
.hi());
465 "use the path separator to refer to an item",
466 format
!("{}::{}", path_str
, segment
.ident
),
467 Applicability
::MaybeIncorrect
,
474 let mut bad_struct_syntax_suggestion
= |def_id
: DefId
| {
475 let (followed_by_brace
, closing_brace
) = self.followed_by_brace(span
);
476 let mut suggested
= false;
478 PathSource
::Expr(Some(parent
)) => {
479 suggested
= path_sep(err
, &parent
);
481 PathSource
::Expr(None
) if followed_by_brace
=> {
482 if let Some((sp
, snippet
)) = closing_brace
{
485 "surround the struct literal with parenthesis",
486 format
!("({})", snippet
),
487 Applicability
::MaybeIncorrect
,
491 span
, // Note the parenthesis surrounding the suggestion below
492 format
!("did you mean `({} {{ /* fields */ }})`?", path_str
),
500 if let Some(span
) = self.r
.definitions
.opt_span(def_id
) {
501 err
.span_label(span
, &format
!("`{}` defined here", path_str
));
503 err
.span_label(span
, format
!("did you mean `{} {{ /* fields */ }}`?", path_str
));
507 match (res
, source
) {
508 (Res
::Def(DefKind
::Macro(MacroKind
::Bang
), _
), _
) => {
509 err
.span_suggestion_verbose(
511 "use `!` to invoke the macro",
513 Applicability
::MaybeIncorrect
,
515 if path_str
== "try" && span
.rust_2015() {
516 err
.note("if you want the `try` keyword, you need to be in the 2018 edition");
519 (Res
::Def(DefKind
::TyAlias
, _
), PathSource
::Trait(_
)) => {
520 err
.span_label(span
, "type aliases cannot be used as traits");
521 if nightly_options
::is_nightly_build() {
522 err
.note("did you mean to use a trait alias?");
525 (Res
::Def(DefKind
::Mod
, _
), PathSource
::Expr(Some(parent
))) => {
526 if !path_sep(err
, &parent
) {
530 (Res
::Def(DefKind
::Enum
, def_id
), PathSource
::TupleStruct
| PathSource
::Expr(..)) => {
531 if let Some(variants
) = self.collect_enum_variants(def_id
) {
532 if !variants
.is_empty() {
533 let msg
= if variants
.len() == 1 {
534 "try using the enum's variant"
536 "try using one of the enum's variants"
539 err
.span_suggestions(
542 variants
.iter().map(path_names_to_string
),
543 Applicability
::MaybeIncorrect
,
547 err
.note("did you mean to use one of the enum's variants?");
550 (Res
::Def(DefKind
::Struct
, def_id
), _
) if ns
== ValueNS
=> {
551 if let Some((ctor_def
, ctor_vis
)) = self.r
.struct_constructors
.get(&def_id
).cloned()
553 let accessible_ctor
=
554 self.r
.is_accessible_from(ctor_vis
, self.parent_scope
.module
);
555 if is_expected(ctor_def
) && !accessible_ctor
{
558 "constructor is not visible here due to private fields".to_string(),
562 bad_struct_syntax_suggestion(def_id
);
567 DefKind
::Union
| DefKind
::Variant
| DefKind
::Ctor(_
, CtorKind
::Fictive
),
571 ) if ns
== ValueNS
=> {
572 bad_struct_syntax_suggestion(def_id
);
574 (Res
::Def(DefKind
::Ctor(_
, CtorKind
::Fn
), def_id
), _
) if ns
== ValueNS
=> {
575 if let Some(span
) = self.r
.definitions
.opt_span(def_id
) {
576 err
.span_label(span
, &format
!("`{}` defined here", path_str
));
578 err
.span_label(span
, format
!("did you mean `{}( /* fields */ )`?", path_str
));
580 (Res
::SelfTy(..), _
) if ns
== ValueNS
=> {
581 err
.span_label(span
, fallback_label
);
582 err
.note("can't use `Self` as a constructor, you must use the implemented struct");
584 (Res
::Def(DefKind
::TyAlias
| DefKind
::AssocTy
, _
), _
) if ns
== ValueNS
=> {
585 err
.note("can't use a type alias as a constructor");
592 fn lookup_assoc_candidate
<FilterFn
>(
597 ) -> Option
<AssocSuggestion
>
599 FilterFn
: Fn(Res
) -> bool
,
601 fn extract_node_id(t
: &Ty
) -> Option
<NodeId
> {
603 TyKind
::Path(None
, _
) => Some(t
.id
),
604 TyKind
::Rptr(_
, ref mut_ty
) => extract_node_id(&mut_ty
.ty
),
605 // This doesn't handle the remaining `Ty` variants as they are not
606 // that commonly the self_type, it might be interesting to provide
607 // support for those in future.
612 // Fields are generally expected in the same contexts as locals.
613 if filter_fn(Res
::Local(ast
::DUMMY_NODE_ID
)) {
614 if let Some(node_id
) =
615 self.diagnostic_metadata
.current_self_type
.as_ref().and_then(extract_node_id
)
617 // Look for a field with the same name in the current self_type.
618 if let Some(resolution
) = self.r
.partial_res_map
.get(&node_id
) {
619 match resolution
.base_res() {
620 Res
::Def(DefKind
::Struct
| DefKind
::Union
, did
)
621 if resolution
.unresolved_segments() == 0 =>
623 if let Some(field_names
) = self.r
.field_names
.get(&did
) {
626 .any(|&field_name
| ident
.name
== field_name
.node
)
628 return Some(AssocSuggestion
::Field
);
638 for assoc_type_ident
in &self.diagnostic_metadata
.current_trait_assoc_types
{
639 if *assoc_type_ident
== ident
{
640 return Some(AssocSuggestion
::AssocItem
);
644 // Look for associated items in the current trait.
645 if let Some((module
, _
)) = self.current_trait_ref
{
646 if let Ok(binding
) = self.r
.resolve_ident_in_module(
647 ModuleOrUniformRoot
::Module(module
),
654 let res
= binding
.res();
656 return Some(if self.r
.has_self
.contains(&res
.def_id()) {
657 AssocSuggestion
::MethodWithSelf
659 AssocSuggestion
::AssocItem
668 fn lookup_typo_candidate(
672 filter_fn
: &impl Fn(Res
) -> bool
,
674 ) -> Option
<TypoSuggestion
> {
675 let mut names
= Vec
::new();
677 // Search in lexical scope.
678 // Walk backwards up the ribs in scope and collect candidates.
679 for rib
in self.ribs
[ns
].iter().rev() {
680 // Locals and type parameters
681 for (ident
, &res
) in &rib
.bindings
{
683 names
.push(TypoSuggestion
::from_res(ident
.name
, res
));
687 if let RibKind
::ModuleRibKind(module
) = rib
.kind
{
688 // Items from this module
689 self.r
.add_module_candidates(module
, &mut names
, &filter_fn
);
691 if let ModuleKind
::Block(..) = module
.kind
{
692 // We can see through blocks
694 // Items from the prelude
695 if !module
.no_implicit_prelude
{
696 let extern_prelude
= self.r
.extern_prelude
.clone();
697 names
.extend(extern_prelude
.iter().flat_map(|(ident
, _
)| {
700 .maybe_process_path_extern(ident
.name
, ident
.span
)
701 .and_then(|crate_id
| {
702 let crate_mod
= Res
::Def(
704 DefId { krate: crate_id, index: CRATE_DEF_INDEX }
,
707 if filter_fn(crate_mod
) {
708 Some(TypoSuggestion
::from_res(ident
.name
, crate_mod
))
715 if let Some(prelude
) = self.r
.prelude
{
716 self.r
.add_module_candidates(prelude
, &mut names
, &filter_fn
);
723 // Add primitive types to the mix
724 if filter_fn(Res
::PrimTy(PrimTy
::Bool
)) {
726 self.r
.primitive_type_table
.primitive_types
.iter().map(|(name
, prim_ty
)| {
727 TypoSuggestion
::from_res(*name
, Res
::PrimTy(*prim_ty
))
733 let mod_path
= &path
[..path
.len() - 1];
734 if let PathResult
::Module(module
) =
735 self.resolve_path(mod_path
, Some(TypeNS
), false, span
, CrateLint
::No
)
737 if let ModuleOrUniformRoot
::Module(module
) = module
{
738 self.r
.add_module_candidates(module
, &mut names
, &filter_fn
);
743 let name
= path
[path
.len() - 1].ident
.name
;
744 // Make sure error reporting is deterministic.
745 names
.sort_by_cached_key(|suggestion
| suggestion
.candidate
.as_str());
747 match find_best_match_for_name(
748 names
.iter().map(|suggestion
| &suggestion
.candidate
),
752 Some(found
) if found
!= name
=> {
753 names
.into_iter().find(|suggestion
| suggestion
.candidate
== found
)
759 /// Only used in a specific case of type ascription suggestions
760 fn get_colon_suggestion_span(&self, start
: Span
) -> Span
{
761 let sm
= self.r
.session
.source_map();
762 start
.to(sm
.next_point(start
))
765 fn type_ascription_suggestion(&self, err
: &mut DiagnosticBuilder
<'_
>, base_span
: Span
) {
766 let sm
= self.r
.session
.source_map();
767 let base_snippet
= sm
.span_to_snippet(base_span
);
768 if let Some(sp
) = self.diagnostic_metadata
.current_type_ascription
.last() {
771 // Try to find the `:`; bail on first non-':' / non-whitespace.
772 sp
= sm
.next_point(sp
);
773 if let Ok(snippet
) = sm
.span_to_snippet(sp
.to(sm
.next_point(sp
))) {
774 let line_sp
= sm
.lookup_char_pos(sp
.hi()).line
;
775 let line_base_sp
= sm
.lookup_char_pos(base_span
.lo()).line
;
777 let mut show_label
= true;
778 if line_sp
!= line_base_sp
{
779 err
.span_suggestion_short(
781 "did you mean to use `;` here instead?",
783 Applicability
::MaybeIncorrect
,
786 let colon_sp
= self.get_colon_suggestion_span(sp
);
788 self.get_colon_suggestion_span(colon_sp
.shrink_to_hi());
790 .span_to_snippet(after_colon_sp
)
796 "maybe you meant to write a path separator here",
798 Applicability
::MaybeIncorrect
,
802 if let Ok(base_snippet
) = base_snippet
{
803 let mut sp
= after_colon_sp
;
805 // Try to find an assignment
806 sp
= sm
.next_point(sp
);
807 let snippet
= sm
.span_to_snippet(sp
.to(sm
.next_point(sp
)));
809 Ok(ref x
) if x
.as_str() == "=" => {
812 "maybe you meant to write an assignment here",
813 format
!("let {}", base_snippet
),
814 Applicability
::MaybeIncorrect
,
819 Ok(ref x
) if x
.as_str() == "\n" => break,
829 "expecting a type here because of type ascription",
833 } else if !snippet
.trim().is_empty() {
834 debug
!("tried to find type ascription `:` token, couldn't find it");
844 fn find_module(&mut self, def_id
: DefId
) -> Option
<(Module
<'a
>, ImportSuggestion
)> {
845 let mut result
= None
;
846 let mut seen_modules
= FxHashSet
::default();
847 let mut worklist
= vec
![(self.r
.graph_root
, Vec
::new())];
849 while let Some((in_module
, path_segments
)) = worklist
.pop() {
850 // abort if the module is already found
851 if result
.is_some() {
855 in_module
.for_each_child(self.r
, |_
, ident
, _
, name_binding
| {
856 // abort if the module is already found or if name_binding is private external
857 if result
.is_some() || !name_binding
.vis
.is_visible_locally() {
860 if let Some(module
) = name_binding
.module() {
862 let mut path_segments
= path_segments
.clone();
863 path_segments
.push(ast
::PathSegment
::from_ident(ident
));
864 let module_def_id
= module
.def_id().unwrap();
865 if module_def_id
== def_id
{
866 let path
= Path { span: name_binding.span, segments: path_segments }
;
867 result
= Some((module
, ImportSuggestion { did: Some(def_id), path }
));
869 // add the module to the lookup
870 if seen_modules
.insert(module_def_id
) {
871 worklist
.push((module
, path_segments
));
881 fn collect_enum_variants(&mut self, def_id
: DefId
) -> Option
<Vec
<Path
>> {
882 self.find_module(def_id
).map(|(enum_module
, enum_import_suggestion
)| {
883 let mut variants
= Vec
::new();
884 enum_module
.for_each_child(self.r
, |_
, ident
, _
, name_binding
| {
885 if let Res
::Def(DefKind
::Variant
, _
) = name_binding
.res() {
886 let mut segms
= enum_import_suggestion
.path
.segments
.clone();
887 segms
.push(ast
::PathSegment
::from_ident(ident
));
888 variants
.push(Path { span: name_binding.span, segments: segms }
);
895 crate fn report_missing_type_error(
898 ) -> Option
<(Span
, &'
static str, String
, Applicability
)> {
899 let ident
= match path
{
900 [segment
] => segment
.ident
,
904 self.diagnostic_metadata
.current_item
,
905 self.diagnostic_metadata
.currently_processing_generics
,
907 (Some(Item { kind: ItemKind::Fn(..), ident, .. }
), true) if ident
.name
== sym
::main
=> {
908 // Ignore `fn main()` as we don't want to suggest `fn main<T>()`
910 (Some(Item { kind, .. }
), true) => {
911 // Likely missing type parameter.
912 if let Some(generics
) = kind
.generics() {
913 let msg
= "you might be missing a type parameter";
914 let (span
, sugg
) = if let [.., param
] = &generics
.params
[..] {
915 let span
= if let [.., bound
] = ¶m
.bounds
[..] {
920 (span
, format
!(", {}", ident
))
922 (generics
.span
, format
!("<{}>", ident
))
924 // Do not suggest if this is coming from macro expansion.
925 if !span
.from_expansion() {
930 Applicability
::MaybeIncorrect
,
941 impl<'tcx
> LifetimeContext
<'_
, 'tcx
> {
942 crate fn report_missing_lifetime_specifiers(
946 ) -> DiagnosticBuilder
<'tcx
> {
951 "missing lifetime specifier{}",
956 crate fn emit_undeclared_lifetime_error(&self, lifetime_ref
: &hir
::Lifetime
) {
957 let mut err
= struct_span_err
!(
961 "use of undeclared lifetime name `{}`",
964 err
.span_label(lifetime_ref
.span
, "undeclared lifetime");
965 for missing
in &self.missing_named_lifetime_spots
{
967 MissingLifetimeSpot
::Generics(generics
) => {
968 let (span
, sugg
) = if let Some(param
) =
969 generics
.params
.iter().find(|p
| match p
.kind
{
970 hir
::GenericParamKind
::Type
{
971 synthetic
: Some(hir
::SyntheticTyParamKind
::ImplTrait
),
976 (param
.span
.shrink_to_lo(), format
!("{}, ", lifetime_ref
))
978 (generics
.span
, format
!("<{}>", lifetime_ref
))
982 &format
!("consider introducing lifetime `{}` here", lifetime_ref
),
984 Applicability
::MaybeIncorrect
,
987 MissingLifetimeSpot
::HigherRanked { span, span_type }
=> {
991 "consider making the {} lifetime-generic with a new `{}` lifetime",
995 span_type
.suggestion(&lifetime_ref
.to_string()),
996 Applicability
::MaybeIncorrect
,
999 "for more information on higher-ranked polymorphism, visit \
1000 https://doc.rust-lang.org/nomicon/hrtb.html",
1008 crate fn is_trait_ref_fn_scope(&mut self, trait_ref
: &'tcx hir
::PolyTraitRef
<'tcx
>) -> bool
{
1009 if let def
::Res
::Def(_
, did
) = trait_ref
.trait_ref
.path
.res
{
1011 self.tcx
.lang_items().fn_once_trait(),
1012 self.tcx
.lang_items().fn_trait(),
1013 self.tcx
.lang_items().fn_mut_trait(),
1015 .contains(&Some(did
))
1017 let (span
, span_type
) = match &trait_ref
.bound_generic_params
{
1018 [] => (trait_ref
.span
.shrink_to_lo(), ForLifetimeSpanType
::BoundEmpty
),
1019 [.., bound
] => (bound
.span
.shrink_to_hi(), ForLifetimeSpanType
::BoundTail
),
1021 self.missing_named_lifetime_spots
1022 .push(MissingLifetimeSpot
::HigherRanked { span, span_type }
);
1029 crate fn add_missing_lifetime_specifiers_label(
1031 err
: &mut DiagnosticBuilder
<'_
>,
1034 lifetime_names
: &FxHashSet
<ast
::Ident
>,
1035 params
: &[ElisionFailureInfo
],
1038 err
.span_label(span
, format
!("expected {} lifetime parameters", count
));
1040 let snippet
= self.tcx
.sess
.source_map().span_to_snippet(span
).ok();
1041 let suggest_existing
= |err
: &mut DiagnosticBuilder
<'_
>, sugg
| {
1042 err
.span_suggestion(
1044 "consider using the named lifetime",
1046 Applicability
::MaybeIncorrect
,
1049 let suggest_new
= |err
: &mut DiagnosticBuilder
<'_
>, sugg
: &str| {
1050 err
.span_label(span
, "expected named lifetime parameter");
1052 for missing
in self.missing_named_lifetime_spots
.iter().rev() {
1053 let mut introduce_suggestion
= vec
![];
1056 introduce_suggestion
.push(match missing
{
1057 MissingLifetimeSpot
::Generics(generics
) => {
1058 msg
= "consider introducing a named lifetime parameter".to_string();
1059 should_break
= true;
1060 if let Some(param
) = generics
.params
.iter().find(|p
| match p
.kind
{
1061 hir
::GenericParamKind
::Type
{
1062 synthetic
: Some(hir
::SyntheticTyParamKind
::ImplTrait
),
1067 (param
.span
.shrink_to_lo(), "'a, ".to_string())
1069 (generics
.span
, "<'a>".to_string())
1072 MissingLifetimeSpot
::HigherRanked { span, span_type }
=> {
1074 "consider making the {} lifetime-generic with a new `'a` lifetime",
1077 should_break
= false;
1079 "for more information on higher-ranked polymorphism, visit \
1080 https://doc.rust-lang.org/nomicon/hrtb.html",
1082 (*span
, span_type
.suggestion("'a"))
1085 for param
in params
{
1086 if let Ok(snippet
) = self.tcx
.sess
.source_map().span_to_snippet(param
.span
)
1088 if snippet
.starts_with('
&'
) && !snippet
.starts_with("&'") {
1089 introduce_suggestion
1090 .push((param
.span
, format
!("&'a {}", &snippet
[1..])));
1091 } else if snippet
.starts_with("&'_ ") {
1092 introduce_suggestion
1093 .push((param
.span
, format
!("&'a {}", &snippet
[4..])));
1097 introduce_suggestion
.push((span
, sugg
.to_string()));
1098 err
.multipart_suggestion(
1100 introduce_suggestion
,
1101 Applicability
::MaybeIncorrect
,
1109 match (lifetime_names
.len(), lifetime_names
.iter().next(), snippet
.as_deref()) {
1110 (1, Some(name
), Some("&")) => {
1111 suggest_existing(err
, format
!("&{} ", name
));
1113 (1, Some(name
), Some("'_")) => {
1114 suggest_existing(err
, name
.to_string());
1116 (1, Some(name
), Some(snippet
)) if !snippet
.ends_with('
>'
) => {
1117 suggest_existing(err
, format
!("{}<{}>", snippet
, name
));
1119 (0, _
, Some("&")) => {
1120 suggest_new(err
, "&'a ");
1122 (0, _
, Some("'_")) => {
1123 suggest_new(err
, "'a");
1125 (0, _
, Some(snippet
)) if !snippet
.ends_with('
>'
) => {
1126 suggest_new(err
, &format
!("{}<'a>", snippet
));
1129 err
.span_label(span
, "expected lifetime parameter");