rustc_parse: migrate more to diagnostic structs
This commit is contained in:
parent
ac9c66bff5
commit
87ef37dbd7
9 changed files with 974 additions and 488 deletions
|
@ -390,3 +390,152 @@ parse_where_clause_before_tuple_struct_body = where clauses are not allowed befo
|
||||||
.name_label = while parsing this tuple struct
|
.name_label = while parsing this tuple struct
|
||||||
.body_label = the struct body
|
.body_label = the struct body
|
||||||
.suggestion = move the body before the where clause
|
.suggestion = move the body before the where clause
|
||||||
|
|
||||||
|
parse_async_fn_in_2015 = `async fn` is not permitted in Rust 2015
|
||||||
|
.label = to use `async fn`, switch to Rust 2018 or later
|
||||||
|
|
||||||
|
parse_async_block_in_2015 = `async` blocks are only allowed in Rust 2018 or later
|
||||||
|
|
||||||
|
parse_self_argument_pointer = cannot pass `self` by raw pointer
|
||||||
|
.label = cannot pass `self` by raw pointer
|
||||||
|
|
||||||
|
parse_visibility_not_followed_by_item = visibility `{$vis}` is not followed by an item
|
||||||
|
.label = the visibility
|
||||||
|
.help = you likely meant to define an item, e.g., `{$vis} fn foo() {"{}"}`
|
||||||
|
|
||||||
|
parse_default_not_followed_by_item = `default` is not followed by an item
|
||||||
|
.label = the `default` qualifier
|
||||||
|
.note = only `fn`, `const`, `type`, or `impl` items may be prefixed by `default`
|
||||||
|
|
||||||
|
parse_missing_struct_for_struct_definition = missing `struct` for struct definition
|
||||||
|
.suggestion = add `struct` here to parse `{$ident}` as a public struct
|
||||||
|
|
||||||
|
parse_missing_fn_for_function_definition = missing `fn` for function definition
|
||||||
|
.suggestion = add `fn` here to parse `{$ident}` as a public function
|
||||||
|
|
||||||
|
parse_missing_fn_for_method_definition = missing `fn` for method definition
|
||||||
|
.suggestion = add `fn` here to parse `{$ident}` as a public method
|
||||||
|
|
||||||
|
parse_ambiguous_missing_keyword_for_item_definition = missing `fn` or `struct` for function or struct definition
|
||||||
|
.suggestion = if you meant to call a macro, try
|
||||||
|
.help = if you meant to call a macro, remove the `pub` and add a trailing `!` after the identifier
|
||||||
|
|
||||||
|
parse_missing_trait_in_trait_impl = missing trait in a trait impl
|
||||||
|
.suggestion_add_trait = add a trait here
|
||||||
|
.suggestion_remove_for = for an inherent impl, drop this `for`
|
||||||
|
|
||||||
|
parse_missing_for_in_trait_impl = missing `for` in a trait impl
|
||||||
|
.suggestion = add `for` here
|
||||||
|
|
||||||
|
parse_expected_trait_in_trait_impl_found_type = expected a trait, found type
|
||||||
|
|
||||||
|
parse_non_item_in_item_list = non-item in item list
|
||||||
|
.suggestion_use_const_not_let = consider using `const` instead of `let` for associated const
|
||||||
|
.label_list_start = item list starts here
|
||||||
|
.label_non_item = non-item starts here
|
||||||
|
.label_list_end = item list ends here
|
||||||
|
.suggestion_remove_semicolon = consider removing this semicolon
|
||||||
|
|
||||||
|
parse_bounds_not_allowed_on_trait_aliases = bounds are not allowed on trait aliases
|
||||||
|
|
||||||
|
parse_trait_alias_cannot_be_auto = trait aliases cannot be `auto`
|
||||||
|
parse_trait_alias_cannot_be_unsafe = trait aliases cannot be `unsafe`
|
||||||
|
|
||||||
|
parse_associated_static_item_not_allowed = associated `static` items are not allowed
|
||||||
|
|
||||||
|
parse_extern_crate_name_with_dashes = crate name using dashes are not valid in `extern crate` statements
|
||||||
|
.label = dash-separated idents are not valid
|
||||||
|
.suggestion = if the original crate name uses dashes you need to use underscores in the code
|
||||||
|
|
||||||
|
parse_extern_item_cannot_be_const = extern items cannot be `const`
|
||||||
|
.suggestion = try using a static value
|
||||||
|
.note = for more information, visit https://doc.rust-lang.org/std/keyword.extern.html
|
||||||
|
|
||||||
|
parse_const_global_cannot_be_mutable = const globals cannot be mutable
|
||||||
|
.label = cannot be mutable
|
||||||
|
.suggestion = you might want to declare a static instead
|
||||||
|
|
||||||
|
parse_missing_const_type = missing type for `{$kind}` item
|
||||||
|
.suggestion = provide a type for the item
|
||||||
|
|
||||||
|
parse_enum_struct_mutually_exclusive = `enum` and `struct` are mutually exclusive
|
||||||
|
.suggestion = replace `enum struct` with
|
||||||
|
|
||||||
|
parse_unexpected_token_after_struct_name = expected `where`, `{"{"}`, `(`, or `;` after struct name
|
||||||
|
parse_unexpected_token_after_struct_name_found_reserved_identifier = expected `where`, `{"{"}`, `(`, or `;` after struct name, found reserved identifier `{$token}`
|
||||||
|
parse_unexpected_token_after_struct_name_found_keyword = expected `where`, `{"{"}`, `(`, or `;` after struct name, found keyword `{$token}`
|
||||||
|
parse_unexpected_token_after_struct_name_found_reserved_keyword = expected `where`, `{"{"}`, `(`, or `;` after struct name, found reserved keyword `{$token}`
|
||||||
|
parse_unexpected_token_after_struct_name_found_doc_comment = expected `where`, `{"{"}`, `(`, or `;` after struct name, found doc comment `{$token}`
|
||||||
|
parse_unexpected_token_after_struct_name_found_other = expected `where`, `{"{"}`, `(`, or `;` after struct name, found `{$token}`
|
||||||
|
|
||||||
|
parse_unexpected_self_in_generic_parameters = unexpected keyword `Self` in generic parameters
|
||||||
|
.note = you cannot use `Self` as a generic parameter because it is reserved for associated items
|
||||||
|
|
||||||
|
parse_multiple_where_clauses = cannot define duplicate `where` clauses on an item
|
||||||
|
.label = previous `where` clause starts here
|
||||||
|
.suggestion = consider joining the two `where` clauses into one
|
||||||
|
|
||||||
|
parse_nonterminal_expected_item_keyword = expected an item keyword
|
||||||
|
parse_nonterminal_expected_statement = expected a statement
|
||||||
|
parse_nonterminal_expected_ident = expected ident, found `{$token}`
|
||||||
|
parse_nonterminal_expected_lifetime = expected a lifetime, found `{$token}`
|
||||||
|
|
||||||
|
parse_or_pattern_not_allowed_in_let_binding = top-level or-patterns are not allowed in `let` bindings
|
||||||
|
parse_or_pattern_not_allowed_in_fn_parameters = top-level or-patterns are not allowed in function parameters
|
||||||
|
parse_sugg_remove_leading_vert_in_pattern = remove the `|`
|
||||||
|
parse_sugg_wrap_pattern_in_parens = wrap the pattern in parentheses
|
||||||
|
|
||||||
|
parse_note_pattern_alternatives_use_single_vert = alternatives in or-patterns are separated with `|`, not `||`
|
||||||
|
|
||||||
|
parse_unexpected_vert_vert_before_function_parameter = unexpected `||` before function parameter
|
||||||
|
.suggestion = remove the `||`
|
||||||
|
|
||||||
|
parse_label_while_parsing_or_pattern_here = while parsing this or-pattern starting here
|
||||||
|
|
||||||
|
parse_unexpected_vert_vert_in_pattern = unexpected token `||` in pattern
|
||||||
|
.suggestion = use a single `|` to separate multiple alternative patterns
|
||||||
|
|
||||||
|
parse_trailing_vert_not_allowed = a trailing `|` is not allowed in an or-pattern
|
||||||
|
.suggestion = remove the `{$token}`
|
||||||
|
|
||||||
|
parse_dotdotdot_rest_pattern = unexpected `...`
|
||||||
|
.label = not a valid pattern
|
||||||
|
.suggestion = for a rest pattern, use `..` instead of `...`
|
||||||
|
|
||||||
|
parse_pattern_on_wrong_side_of_at = pattern on wrong side of `@`
|
||||||
|
.label_pattern = pattern on the left, should be on the right
|
||||||
|
.label_binding = binding on the right, should be on the left
|
||||||
|
.suggestion = switch the order
|
||||||
|
|
||||||
|
parse_expected_binding_left_of_at = left-hand side of `@` must be a binding
|
||||||
|
.label_lhs = interpreted as a pattern, not a binding
|
||||||
|
.label_rhs = also a pattern
|
||||||
|
.note = bindings are `x`, `mut x`, `ref x`, and `ref mut x`
|
||||||
|
|
||||||
|
parse_ambiguous_range_pattern = the range pattern here has ambiguous interpretation
|
||||||
|
.suggestion = add parentheses to clarify the precedence
|
||||||
|
|
||||||
|
parse_unexpected_lifetime_in_pattern = unexpected lifetime `{$symbol}` in pattern
|
||||||
|
.suggestion = remove the lifetime
|
||||||
|
|
||||||
|
parse_ref_mut_order_incorrect = the order of `mut` and `ref` is incorrect
|
||||||
|
.suggestion = try switching the order
|
||||||
|
|
||||||
|
parse_mut_on_nested_ident_pattern = `mut` must be attached to each individual binding
|
||||||
|
.suggestion = add `mut` to each binding
|
||||||
|
parse_mut_on_non_ident_pattern = `mut` must be followed by a named binding
|
||||||
|
.suggestion = remove the `mut` prefix
|
||||||
|
parse_note_mut_pattern_usage = `mut` may be followed by `variable` and `variable @ pattern`
|
||||||
|
|
||||||
|
parse_repeated_mut_in_pattern = `mut` on a binding may not be repeated
|
||||||
|
.suggestion = remove the additional `mut`s
|
||||||
|
|
||||||
|
parse_dot_dot_dot_range_to_pattern_not_allowed = range-to patterns with `...` are not allowed
|
||||||
|
.suggestion = use `..=` instead
|
||||||
|
|
||||||
|
parse_enum_pattern_instead_of_identifier = expected identifier, found enum pattern
|
||||||
|
|
||||||
|
parse_dot_dot_dot_for_remaining_fields = expected field pattern, found `...`
|
||||||
|
.suggestion = to omit remaining fields, use one fewer `.`
|
||||||
|
|
||||||
|
parse_expected_comma_after_pattern_field = expected `,`
|
||||||
|
|
|
@ -1,6 +1,8 @@
|
||||||
use rustc_ast::token::Token;
|
use rustc_ast::token::Token;
|
||||||
use rustc_ast::Path;
|
use rustc_ast::{Path, Visibility};
|
||||||
use rustc_errors::{fluent, AddToDiagnostic, Applicability, EmissionGuarantee, IntoDiagnostic};
|
use rustc_errors::{
|
||||||
|
fluent, AddToDiagnostic, Applicability, EmissionGuarantee, HelpUseLatestEdition, IntoDiagnostic,
|
||||||
|
};
|
||||||
use rustc_macros::{Diagnostic, Subdiagnostic};
|
use rustc_macros::{Diagnostic, Subdiagnostic};
|
||||||
use rustc_session::errors::ExprParenthesesNeeded;
|
use rustc_session::errors::ExprParenthesesNeeded;
|
||||||
use rustc_span::symbol::Ident;
|
use rustc_span::symbol::Ident;
|
||||||
|
@ -1330,3 +1332,516 @@ pub(crate) struct WhereClauseBeforeTupleStructBodySugg {
|
||||||
#[suggestion_part(code = "")]
|
#[suggestion_part(code = "")]
|
||||||
pub right: Span,
|
pub right: Span,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Diagnostic)]
|
||||||
|
#[diag(parse_async_fn_in_2015, code = "E0670")]
|
||||||
|
pub(crate) struct AsyncFnIn2015 {
|
||||||
|
#[primary_span]
|
||||||
|
#[label]
|
||||||
|
pub span: Span,
|
||||||
|
#[subdiagnostic]
|
||||||
|
pub help: HelpUseLatestEdition,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Subdiagnostic)]
|
||||||
|
#[label(parse_async_block_in_2015)]
|
||||||
|
pub(crate) struct AsyncBlockIn2015 {
|
||||||
|
#[primary_span]
|
||||||
|
pub span: Span,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Diagnostic)]
|
||||||
|
#[diag(parse_self_argument_pointer)]
|
||||||
|
pub(crate) struct SelfArgumentPointer {
|
||||||
|
#[primary_span]
|
||||||
|
#[label]
|
||||||
|
pub span: Span,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Diagnostic)]
|
||||||
|
#[diag(parse_visibility_not_followed_by_item)]
|
||||||
|
#[help]
|
||||||
|
pub(crate) struct VisibilityNotFollowedByItem {
|
||||||
|
#[primary_span]
|
||||||
|
#[label]
|
||||||
|
pub span: Span,
|
||||||
|
pub vis: Visibility,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Diagnostic)]
|
||||||
|
#[diag(parse_default_not_followed_by_item)]
|
||||||
|
#[note]
|
||||||
|
pub(crate) struct DefaultNotFollowedByItem {
|
||||||
|
#[primary_span]
|
||||||
|
#[label]
|
||||||
|
pub span: Span,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Diagnostic)]
|
||||||
|
pub(crate) enum MissingKeywordForItemDefinition {
|
||||||
|
#[diag(parse_missing_struct_for_struct_definition)]
|
||||||
|
Struct {
|
||||||
|
#[primary_span]
|
||||||
|
#[suggestion(style = "short", applicability = "maybe-incorrect", code = " struct ")]
|
||||||
|
span: Span,
|
||||||
|
ident: Ident,
|
||||||
|
},
|
||||||
|
#[diag(parse_missing_fn_for_function_definition)]
|
||||||
|
Function {
|
||||||
|
#[primary_span]
|
||||||
|
#[suggestion(style = "short", applicability = "maybe-incorrect", code = " fn ")]
|
||||||
|
span: Span,
|
||||||
|
ident: Ident,
|
||||||
|
},
|
||||||
|
#[diag(parse_missing_fn_for_method_definition)]
|
||||||
|
Method {
|
||||||
|
#[primary_span]
|
||||||
|
#[suggestion(style = "short", applicability = "maybe-incorrect", code = " fn ")]
|
||||||
|
span: Span,
|
||||||
|
ident: Ident,
|
||||||
|
},
|
||||||
|
#[diag(parse_ambiguous_missing_keyword_for_item_definition)]
|
||||||
|
Ambiguous {
|
||||||
|
#[primary_span]
|
||||||
|
span: Span,
|
||||||
|
#[subdiagnostic]
|
||||||
|
subdiag: Option<AmbiguousMissingKwForItemSub>,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Subdiagnostic)]
|
||||||
|
pub(crate) enum AmbiguousMissingKwForItemSub {
|
||||||
|
#[suggestion(suggestion, applicability = "maybe-incorrect", code = "{snippet}!")]
|
||||||
|
SuggestMacro {
|
||||||
|
#[primary_span]
|
||||||
|
span: Span,
|
||||||
|
snippet: String,
|
||||||
|
},
|
||||||
|
#[help(help)]
|
||||||
|
HelpMacro,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Diagnostic)]
|
||||||
|
#[diag(parse_missing_trait_in_trait_impl)]
|
||||||
|
pub(crate) struct MissingTraitInTraitImpl {
|
||||||
|
#[primary_span]
|
||||||
|
#[suggestion(suggestion_add_trait, code = " Trait ", applicability = "has-placeholders")]
|
||||||
|
pub span: Span,
|
||||||
|
#[suggestion(suggestion_remove_for, code = "", applicability = "maybe-incorrect")]
|
||||||
|
pub for_span: Span,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Diagnostic)]
|
||||||
|
#[diag(parse_missing_for_in_trait_impl)]
|
||||||
|
pub(crate) struct MissingForInTraitImpl {
|
||||||
|
#[primary_span]
|
||||||
|
#[suggestion(style = "short", code = " for ", applicability = "machine-applicable")]
|
||||||
|
pub span: Span,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Diagnostic)]
|
||||||
|
#[diag(parse_expected_trait_in_trait_impl_found_type)]
|
||||||
|
pub(crate) struct ExpectedTraitInTraitImplFoundType {
|
||||||
|
#[primary_span]
|
||||||
|
pub span: Span,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Diagnostic)]
|
||||||
|
#[diag(parse_non_item_in_item_list)]
|
||||||
|
pub(crate) struct NonItemInItemList {
|
||||||
|
#[primary_span]
|
||||||
|
pub span: Span,
|
||||||
|
#[subdiagnostic]
|
||||||
|
pub sub: NonItemInItemListSub,
|
||||||
|
#[suggestion(suggestion_remove_semicolon, code = "", applicability = "maybe-incorrect")]
|
||||||
|
pub remove_semicolon: Option<Span>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Subdiagnostic)]
|
||||||
|
pub(crate) enum NonItemInItemListSub {
|
||||||
|
#[suggestion(
|
||||||
|
suggestion_use_const_not_let,
|
||||||
|
code = "const",
|
||||||
|
applicability = "machine-applicable"
|
||||||
|
)]
|
||||||
|
Let {
|
||||||
|
#[primary_span]
|
||||||
|
span: Span,
|
||||||
|
},
|
||||||
|
Other {
|
||||||
|
#[label(label_list_start)]
|
||||||
|
list_start: Span,
|
||||||
|
#[label(label_non_item)]
|
||||||
|
non_item: Span,
|
||||||
|
#[label(label_list_end)]
|
||||||
|
list_end: Span,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Diagnostic)]
|
||||||
|
#[diag(parse_bounds_not_allowed_on_trait_aliases)]
|
||||||
|
pub(crate) struct BoundsNotAllowedOnTraitAliases {
|
||||||
|
#[primary_span]
|
||||||
|
pub span: Span,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Diagnostic)]
|
||||||
|
#[diag(parse_trait_alias_cannot_be_auto)]
|
||||||
|
pub(crate) struct TraitAliasCannotBeAuto {
|
||||||
|
#[primary_span]
|
||||||
|
#[label(parse_trait_alias_cannot_be_auto)]
|
||||||
|
pub span: Span,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Diagnostic)]
|
||||||
|
#[diag(parse_trait_alias_cannot_be_unsafe)]
|
||||||
|
pub(crate) struct TraitAliasCannotBeUnsafe {
|
||||||
|
#[primary_span]
|
||||||
|
#[label(parse_trait_alias_cannot_be_unsafe)]
|
||||||
|
pub span: Span,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Diagnostic)]
|
||||||
|
#[diag(parse_associated_static_item_not_allowed)]
|
||||||
|
pub(crate) struct AssociatedStaticItemNotAllowed {
|
||||||
|
#[primary_span]
|
||||||
|
pub span: Span,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Diagnostic)]
|
||||||
|
#[diag(parse_extern_crate_name_with_dashes)]
|
||||||
|
pub(crate) struct ExternCrateNameWithDashes {
|
||||||
|
#[primary_span]
|
||||||
|
#[label]
|
||||||
|
pub span: Span,
|
||||||
|
#[subdiagnostic]
|
||||||
|
pub sugg: ExternCrateNameWithDashesSugg,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Subdiagnostic)]
|
||||||
|
#[multipart_suggestion(suggestion, applicability = "machine-applicable")]
|
||||||
|
pub(crate) struct ExternCrateNameWithDashesSugg {
|
||||||
|
#[suggestion_part(code = "_")]
|
||||||
|
pub dashes: Vec<Span>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Diagnostic)]
|
||||||
|
#[diag(parse_extern_item_cannot_be_const)]
|
||||||
|
#[note]
|
||||||
|
pub(crate) struct ExternItemCannotBeConst {
|
||||||
|
#[primary_span]
|
||||||
|
pub ident_span: Span,
|
||||||
|
#[suggestion(code = "static ", applicability = "machine-applicable")]
|
||||||
|
pub const_span: Span,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Diagnostic)]
|
||||||
|
#[diag(parse_const_global_cannot_be_mutable)]
|
||||||
|
pub(crate) struct ConstGlobalCannotBeMutable {
|
||||||
|
#[primary_span]
|
||||||
|
#[label]
|
||||||
|
pub ident_span: Span,
|
||||||
|
#[suggestion(code = "static", applicability = "maybe-incorrect")]
|
||||||
|
pub const_span: Span,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Diagnostic)]
|
||||||
|
#[diag(parse_missing_const_type)]
|
||||||
|
pub(crate) struct MissingConstType {
|
||||||
|
#[primary_span]
|
||||||
|
#[suggestion(code = "{colon} <type>", applicability = "has-placeholders")]
|
||||||
|
pub span: Span,
|
||||||
|
|
||||||
|
pub kind: &'static str,
|
||||||
|
pub colon: &'static str,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Diagnostic)]
|
||||||
|
#[diag(parse_enum_struct_mutually_exclusive)]
|
||||||
|
pub(crate) struct EnumStructMutuallyExclusive {
|
||||||
|
#[primary_span]
|
||||||
|
#[suggestion(code = "enum", applicability = "machine-applicable")]
|
||||||
|
pub span: Span,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Diagnostic)]
|
||||||
|
pub(crate) enum UnexpectedTokenAfterStructName {
|
||||||
|
#[diag(parse_unexpected_token_after_struct_name_found_reserved_identifier)]
|
||||||
|
ReservedIdentifier {
|
||||||
|
#[primary_span]
|
||||||
|
#[label(parse_unexpected_token_after_struct_name)]
|
||||||
|
span: Span,
|
||||||
|
token: Token,
|
||||||
|
},
|
||||||
|
#[diag(parse_unexpected_token_after_struct_name_found_keyword)]
|
||||||
|
Keyword {
|
||||||
|
#[primary_span]
|
||||||
|
#[label(parse_unexpected_token_after_struct_name)]
|
||||||
|
span: Span,
|
||||||
|
token: Token,
|
||||||
|
},
|
||||||
|
#[diag(parse_unexpected_token_after_struct_name_found_reserved_keyword)]
|
||||||
|
ReservedKeyword {
|
||||||
|
#[primary_span]
|
||||||
|
#[label(parse_unexpected_token_after_struct_name)]
|
||||||
|
span: Span,
|
||||||
|
token: Token,
|
||||||
|
},
|
||||||
|
#[diag(parse_unexpected_token_after_struct_name_found_doc_comment)]
|
||||||
|
DocComment {
|
||||||
|
#[primary_span]
|
||||||
|
#[label(parse_unexpected_token_after_struct_name)]
|
||||||
|
span: Span,
|
||||||
|
token: Token,
|
||||||
|
},
|
||||||
|
#[diag(parse_unexpected_token_after_struct_name_found_other)]
|
||||||
|
Other {
|
||||||
|
#[primary_span]
|
||||||
|
#[label(parse_unexpected_token_after_struct_name)]
|
||||||
|
span: Span,
|
||||||
|
token: Token,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
impl UnexpectedTokenAfterStructName {
|
||||||
|
pub fn new(span: Span, token: Token) -> Self {
|
||||||
|
match TokenDescription::from_token(&token) {
|
||||||
|
Some(TokenDescription::ReservedIdentifier) => Self::ReservedIdentifier { span, token },
|
||||||
|
Some(TokenDescription::Keyword) => Self::Keyword { span, token },
|
||||||
|
Some(TokenDescription::ReservedKeyword) => Self::ReservedKeyword { span, token },
|
||||||
|
Some(TokenDescription::DocComment) => Self::DocComment { span, token },
|
||||||
|
None => Self::Other { span, token },
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Diagnostic)]
|
||||||
|
#[diag(parse_unexpected_self_in_generic_parameters)]
|
||||||
|
#[note]
|
||||||
|
pub(crate) struct UnexpectedSelfInGenericParameters {
|
||||||
|
#[primary_span]
|
||||||
|
pub span: Span,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Diagnostic)]
|
||||||
|
#[diag(parse_multiple_where_clauses)]
|
||||||
|
pub(crate) struct MultipleWhereClauses {
|
||||||
|
#[primary_span]
|
||||||
|
pub span: Span,
|
||||||
|
#[label]
|
||||||
|
pub previous: Span,
|
||||||
|
#[suggestion(style = "verbose", code = ",", applicability = "maybe-incorrect")]
|
||||||
|
pub between: Span,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Diagnostic)]
|
||||||
|
pub(crate) enum UnexpectedNonterminal {
|
||||||
|
#[diag(parse_nonterminal_expected_item_keyword)]
|
||||||
|
Item(#[primary_span] Span),
|
||||||
|
#[diag(parse_nonterminal_expected_statement)]
|
||||||
|
Statement(#[primary_span] Span),
|
||||||
|
#[diag(parse_nonterminal_expected_ident)]
|
||||||
|
Ident {
|
||||||
|
#[primary_span]
|
||||||
|
span: Span,
|
||||||
|
token: Token,
|
||||||
|
},
|
||||||
|
#[diag(parse_nonterminal_expected_lifetime)]
|
||||||
|
Lifetime {
|
||||||
|
#[primary_span]
|
||||||
|
span: Span,
|
||||||
|
token: Token,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Diagnostic)]
|
||||||
|
pub(crate) enum TopLevelOrPatternNotAllowed {
|
||||||
|
#[diag(parse_or_pattern_not_allowed_in_let_binding)]
|
||||||
|
LetBinding {
|
||||||
|
#[primary_span]
|
||||||
|
span: Span,
|
||||||
|
#[subdiagnostic]
|
||||||
|
sub: Option<TopLevelOrPatternNotAllowedSugg>,
|
||||||
|
},
|
||||||
|
#[diag(parse_or_pattern_not_allowed_in_fn_parameters)]
|
||||||
|
FunctionParameter {
|
||||||
|
#[primary_span]
|
||||||
|
span: Span,
|
||||||
|
#[subdiagnostic]
|
||||||
|
sub: Option<TopLevelOrPatternNotAllowedSugg>,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Subdiagnostic)]
|
||||||
|
pub(crate) enum TopLevelOrPatternNotAllowedSugg {
|
||||||
|
#[suggestion(
|
||||||
|
parse_sugg_remove_leading_vert_in_pattern,
|
||||||
|
code = "{pat}",
|
||||||
|
applicability = "machine-applicable"
|
||||||
|
)]
|
||||||
|
RemoveLeadingVert {
|
||||||
|
#[primary_span]
|
||||||
|
span: Span,
|
||||||
|
pat: String,
|
||||||
|
},
|
||||||
|
#[suggestion(
|
||||||
|
parse_sugg_wrap_pattern_in_parens,
|
||||||
|
code = "({pat})",
|
||||||
|
applicability = "machine-applicable"
|
||||||
|
)]
|
||||||
|
WrapInParens {
|
||||||
|
#[primary_span]
|
||||||
|
span: Span,
|
||||||
|
pat: String,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Diagnostic)]
|
||||||
|
#[diag(parse_unexpected_vert_vert_before_function_parameter)]
|
||||||
|
#[note(parse_note_pattern_alternatives_use_single_vert)]
|
||||||
|
pub(crate) struct UnexpectedVertVertBeforeFunctionParam {
|
||||||
|
#[primary_span]
|
||||||
|
#[suggestion(code = "", applicability = "machine-applicable")]
|
||||||
|
pub span: Span,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Diagnostic)]
|
||||||
|
#[diag(parse_unexpected_vert_vert_in_pattern)]
|
||||||
|
pub(crate) struct UnexpectedVertVertInPattern {
|
||||||
|
#[primary_span]
|
||||||
|
#[suggestion(code = "|", applicability = "machine-applicable")]
|
||||||
|
pub span: Span,
|
||||||
|
#[label(parse_label_while_parsing_or_pattern_here)]
|
||||||
|
pub start: Option<Span>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Diagnostic)]
|
||||||
|
#[diag(parse_trailing_vert_not_allowed)]
|
||||||
|
pub(crate) struct TrailingVertNotAllowed {
|
||||||
|
#[primary_span]
|
||||||
|
#[suggestion(code = "", applicability = "machine-applicable")]
|
||||||
|
pub span: Span,
|
||||||
|
#[label(parse_label_while_parsing_or_pattern_here)]
|
||||||
|
pub start: Option<Span>,
|
||||||
|
pub token: Token,
|
||||||
|
#[note(parse_note_pattern_alternatives_use_single_vert)]
|
||||||
|
pub note_double_vert: Option<()>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Diagnostic)]
|
||||||
|
#[diag(parse_dotdotdot_rest_pattern)]
|
||||||
|
pub(crate) struct DotDotDotRestPattern {
|
||||||
|
#[primary_span]
|
||||||
|
#[suggestion(style = "short", code = "..", applicability = "machine-applicable")]
|
||||||
|
#[label]
|
||||||
|
pub span: Span,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Diagnostic)]
|
||||||
|
#[diag(parse_pattern_on_wrong_side_of_at)]
|
||||||
|
pub(crate) struct PatternOnWrongSideOfAt {
|
||||||
|
#[primary_span]
|
||||||
|
#[suggestion(code = "{whole_pat}", applicability = "machine-applicable")]
|
||||||
|
pub whole_span: Span,
|
||||||
|
pub whole_pat: String,
|
||||||
|
#[label(label_pattern)]
|
||||||
|
pub pattern: Span,
|
||||||
|
#[label(label_binding)]
|
||||||
|
pub binding: Span,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Diagnostic)]
|
||||||
|
#[diag(parse_expected_binding_left_of_at)]
|
||||||
|
#[note]
|
||||||
|
pub(crate) struct ExpectedBindingLeftOfAt {
|
||||||
|
#[primary_span]
|
||||||
|
pub whole_span: Span,
|
||||||
|
#[label(label_lhs)]
|
||||||
|
pub lhs: Span,
|
||||||
|
#[label(label_rhs)]
|
||||||
|
pub rhs: Span,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Diagnostic)]
|
||||||
|
#[diag(parse_ambiguous_range_pattern)]
|
||||||
|
pub(crate) struct AmbiguousRangePattern {
|
||||||
|
#[primary_span]
|
||||||
|
#[suggestion(code = "({pat})", applicability = "maybe-incorrect")]
|
||||||
|
pub span: Span,
|
||||||
|
pub pat: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Diagnostic)]
|
||||||
|
#[diag(parse_unexpected_lifetime_in_pattern)]
|
||||||
|
pub(crate) struct UnexpectedLifetimeInPattern {
|
||||||
|
#[primary_span]
|
||||||
|
#[suggestion(code = "", applicability = "machine-applicable")]
|
||||||
|
pub span: Span,
|
||||||
|
pub symbol: Symbol,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Diagnostic)]
|
||||||
|
#[diag(parse_ref_mut_order_incorrect)]
|
||||||
|
pub(crate) struct RefMutOrderIncorrect {
|
||||||
|
#[primary_span]
|
||||||
|
#[suggestion(code = "ref mut", applicability = "machine-applicable")]
|
||||||
|
pub span: Span,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Diagnostic)]
|
||||||
|
pub(crate) enum InvalidMutInPattern {
|
||||||
|
#[diag(parse_mut_on_nested_ident_pattern)]
|
||||||
|
#[note(parse_note_mut_pattern_usage)]
|
||||||
|
NestedIdent {
|
||||||
|
#[primary_span]
|
||||||
|
#[suggestion(code = "{pat}", applicability = "machine-applicable")]
|
||||||
|
span: Span,
|
||||||
|
pat: String,
|
||||||
|
},
|
||||||
|
#[diag(parse_mut_on_non_ident_pattern)]
|
||||||
|
#[note(parse_note_mut_pattern_usage)]
|
||||||
|
NonIdent {
|
||||||
|
#[primary_span]
|
||||||
|
#[suggestion(code = "{pat}", applicability = "machine-applicable")]
|
||||||
|
span: Span,
|
||||||
|
pat: String,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Diagnostic)]
|
||||||
|
#[diag(parse_repeated_mut_in_pattern)]
|
||||||
|
pub(crate) struct RepeatedMutInPattern {
|
||||||
|
#[primary_span]
|
||||||
|
#[suggestion(code = "", applicability = "machine-applicable")]
|
||||||
|
pub span: Span,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Diagnostic)]
|
||||||
|
#[diag(parse_dot_dot_dot_range_to_pattern_not_allowed)]
|
||||||
|
pub(crate) struct DotDotDotRangeToPatternNotAllowed {
|
||||||
|
#[primary_span]
|
||||||
|
#[suggestion(style = "short", code = "..=", applicability = "machine-applicable")]
|
||||||
|
pub span: Span,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Diagnostic)]
|
||||||
|
#[diag(parse_enum_pattern_instead_of_identifier)]
|
||||||
|
pub(crate) struct EnumPatternInsteadOfIdentifier {
|
||||||
|
#[primary_span]
|
||||||
|
pub span: Span,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Diagnostic)]
|
||||||
|
#[diag(parse_dot_dot_dot_for_remaining_fields)]
|
||||||
|
pub(crate) struct DotDotDotForRemainingFields {
|
||||||
|
#[primary_span]
|
||||||
|
#[suggestion(code = "..", applicability = "machine-applicable")]
|
||||||
|
pub span: Span,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Diagnostic)]
|
||||||
|
#[diag(parse_expected_comma_after_pattern_field)]
|
||||||
|
pub(crate) struct ExpectedCommaAfterPatternField {
|
||||||
|
#[primary_span]
|
||||||
|
pub span: Span,
|
||||||
|
}
|
||||||
|
|
|
@ -6,19 +6,19 @@ use super::{
|
||||||
SemiColonMode, SeqSep, TokenExpectType, TokenType, TrailingToken,
|
SemiColonMode, SeqSep, TokenExpectType, TokenType, TrailingToken,
|
||||||
};
|
};
|
||||||
use crate::errors::{
|
use crate::errors::{
|
||||||
ArrayBracketsInsteadOfSpaces, ArrayBracketsInsteadOfSpacesSugg, AsyncMoveOrderIncorrect,
|
ArrayBracketsInsteadOfSpaces, ArrayBracketsInsteadOfSpacesSugg, AsyncBlockIn2015,
|
||||||
BracesForStructLiteral, CatchAfterTry, CommaAfterBaseStruct, ComparisonInterpretedAsGeneric,
|
AsyncMoveOrderIncorrect, BracesForStructLiteral, CatchAfterTry, CommaAfterBaseStruct,
|
||||||
ComparisonOrShiftInterpretedAsGenericSugg, DoCatchSyntaxRemoved, DotDotDot, EqFieldInit,
|
ComparisonInterpretedAsGeneric, ComparisonOrShiftInterpretedAsGenericSugg,
|
||||||
ExpectedElseBlock, ExpectedEqForLetExpr, ExpectedExpressionFoundLet,
|
DoCatchSyntaxRemoved, DotDotDot, EqFieldInit, ExpectedElseBlock, ExpectedEqForLetExpr,
|
||||||
FieldExpressionWithGeneric, FloatLiteralRequiresIntegerPart, FoundExprWouldBeStmt,
|
ExpectedExpressionFoundLet, FieldExpressionWithGeneric, FloatLiteralRequiresIntegerPart,
|
||||||
IfExpressionLetSomeSub, IfExpressionMissingCondition, IfExpressionMissingThenBlock,
|
FoundExprWouldBeStmt, IfExpressionLetSomeSub, IfExpressionMissingCondition,
|
||||||
IfExpressionMissingThenBlockSub, InvalidBlockMacroSegment, InvalidComparisonOperator,
|
IfExpressionMissingThenBlock, IfExpressionMissingThenBlockSub, InvalidBlockMacroSegment,
|
||||||
InvalidComparisonOperatorSub, InvalidInterpolatedExpression, InvalidLiteralSuffixOnTupleIndex,
|
InvalidComparisonOperator, InvalidComparisonOperatorSub, InvalidInterpolatedExpression,
|
||||||
InvalidLogicalOperator, InvalidLogicalOperatorSub, LabeledLoopInBreak, LeadingPlusNotSupported,
|
InvalidLiteralSuffixOnTupleIndex, InvalidLogicalOperator, InvalidLogicalOperatorSub,
|
||||||
LeftArrowOperator, LifetimeInBorrowExpression, MacroInvocationWithQualifiedPath,
|
LabeledLoopInBreak, LeadingPlusNotSupported, LeftArrowOperator, LifetimeInBorrowExpression,
|
||||||
MalformedLoopLabel, MatchArmBodyWithoutBraces, MatchArmBodyWithoutBracesSugg,
|
MacroInvocationWithQualifiedPath, MalformedLoopLabel, MatchArmBodyWithoutBraces,
|
||||||
MissingCommaAfterMatchArm, MissingDotDot, MissingInInForLoop, MissingInInForLoopSub,
|
MatchArmBodyWithoutBracesSugg, MissingCommaAfterMatchArm, MissingDotDot, MissingInInForLoop,
|
||||||
MissingSemicolonBeforeArray, NoFieldsForFnCall, NotAsNegationOperator,
|
MissingInInForLoopSub, MissingSemicolonBeforeArray, NoFieldsForFnCall, NotAsNegationOperator,
|
||||||
NotAsNegationOperatorSub, OuterAttributeNotAllowedOnIfElse, ParenthesesWithStructFields,
|
NotAsNegationOperatorSub, OuterAttributeNotAllowedOnIfElse, ParenthesesWithStructFields,
|
||||||
RequireColonAfterLabeledExpression, ShiftInterpretedAsGeneric, StructLiteralNotAllowedHere,
|
RequireColonAfterLabeledExpression, ShiftInterpretedAsGeneric, StructLiteralNotAllowedHere,
|
||||||
StructLiteralNotAllowedHereSugg, TildeAsUnaryOperator, UnexpectedIfWithIf,
|
StructLiteralNotAllowedHereSugg, TildeAsUnaryOperator, UnexpectedIfWithIf,
|
||||||
|
@ -2926,7 +2926,7 @@ impl<'a> Parser<'a> {
|
||||||
|
|
||||||
let mut async_block_err = |e: &mut Diagnostic, span: Span| {
|
let mut async_block_err = |e: &mut Diagnostic, span: Span| {
|
||||||
recover_async = true;
|
recover_async = true;
|
||||||
e.span_label(span, "`async` blocks are only allowed in Rust 2018 or later");
|
AsyncBlockIn2015 { span }.add_to_diagnostic(e);
|
||||||
HelpUseLatestEdition::new().add_to_diagnostic(e);
|
HelpUseLatestEdition::new().add_to_diagnostic(e);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -1,4 +1,7 @@
|
||||||
use crate::errors::{WhereClauseBeforeTupleStructBody, WhereClauseBeforeTupleStructBodySugg};
|
use crate::errors::{
|
||||||
|
MultipleWhereClauses, UnexpectedSelfInGenericParameters, WhereClauseBeforeTupleStructBody,
|
||||||
|
WhereClauseBeforeTupleStructBodySugg,
|
||||||
|
};
|
||||||
|
|
||||||
use super::{ForceCollect, Parser, TrailingToken};
|
use super::{ForceCollect, Parser, TrailingToken};
|
||||||
|
|
||||||
|
@ -127,12 +130,9 @@ impl<'a> Parser<'a> {
|
||||||
if this.eat_keyword_noexpect(kw::SelfUpper) {
|
if this.eat_keyword_noexpect(kw::SelfUpper) {
|
||||||
// `Self` as a generic param is invalid. Here we emit the diagnostic and continue parsing
|
// `Self` as a generic param is invalid. Here we emit the diagnostic and continue parsing
|
||||||
// as if `Self` never existed.
|
// as if `Self` never existed.
|
||||||
this.struct_span_err(
|
this.sess.emit_err(UnexpectedSelfInGenericParameters {
|
||||||
this.prev_token.span,
|
span: this.prev_token.span,
|
||||||
"unexpected keyword `Self` in generic parameters",
|
});
|
||||||
)
|
|
||||||
.note("you cannot use `Self` as a generic parameter because it is reserved for associated items")
|
|
||||||
.emit();
|
|
||||||
|
|
||||||
this.eat(&token::Comma);
|
this.eat(&token::Comma);
|
||||||
}
|
}
|
||||||
|
@ -329,16 +329,11 @@ impl<'a> Parser<'a> {
|
||||||
let ate_comma = self.eat(&token::Comma);
|
let ate_comma = self.eat(&token::Comma);
|
||||||
|
|
||||||
if self.eat_keyword_noexpect(kw::Where) {
|
if self.eat_keyword_noexpect(kw::Where) {
|
||||||
let msg = "cannot define duplicate `where` clauses on an item";
|
self.sess.emit_err(MultipleWhereClauses {
|
||||||
let mut err = self.struct_span_err(self.token.span, msg);
|
span: self.token.span,
|
||||||
err.span_label(pred_lo, "previous `where` clause starts here");
|
previous: pred_lo,
|
||||||
err.span_suggestion_verbose(
|
between: prev_token.shrink_to_hi().to(self.prev_token.span),
|
||||||
prev_token.shrink_to_hi().to(self.prev_token.span),
|
});
|
||||||
"consider joining the two `where` clauses into one",
|
|
||||||
",",
|
|
||||||
Applicability::MaybeIncorrect,
|
|
||||||
);
|
|
||||||
err.emit();
|
|
||||||
} else if !ate_comma {
|
} else if !ate_comma {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,4 +1,13 @@
|
||||||
use crate::errors::{DocCommentDoesNotDocumentAnything, UseEmptyBlockNotSemi};
|
use crate::errors::{
|
||||||
|
AmbiguousMissingKwForItemSub, AssociatedStaticItemNotAllowed, AsyncFnIn2015,
|
||||||
|
BoundsNotAllowedOnTraitAliases, ConstGlobalCannotBeMutable, ConstLetMutuallyExclusive,
|
||||||
|
DefaultNotFollowedByItem, DocCommentDoesNotDocumentAnything, EnumStructMutuallyExclusive,
|
||||||
|
ExpectedTraitInTraitImplFoundType, ExternCrateNameWithDashes, ExternCrateNameWithDashesSugg,
|
||||||
|
ExternItemCannotBeConst, MissingConstType, MissingForInTraitImpl,
|
||||||
|
MissingKeywordForItemDefinition, MissingTraitInTraitImpl, NonItemInItemList,
|
||||||
|
NonItemInItemListSub, SelfArgumentPointer, TraitAliasCannotBeAuto, TraitAliasCannotBeUnsafe,
|
||||||
|
UnexpectedTokenAfterStructName, UseEmptyBlockNotSemi, VisibilityNotFollowedByItem,
|
||||||
|
};
|
||||||
|
|
||||||
use super::diagnostics::{dummy_arg, ConsumeClosingDelim};
|
use super::diagnostics::{dummy_arg, ConsumeClosingDelim};
|
||||||
use super::ty::{AllowPlus, RecoverQPath, RecoverReturnSign};
|
use super::ty::{AllowPlus, RecoverQPath, RecoverReturnSign};
|
||||||
|
@ -17,8 +26,8 @@ use rustc_ast::{FnHeader, ForeignItem, Path, PathSegment, Visibility, Visibility
|
||||||
use rustc_ast::{MacCall, MacDelimiter};
|
use rustc_ast::{MacCall, MacDelimiter};
|
||||||
use rustc_ast_pretty::pprust;
|
use rustc_ast_pretty::pprust;
|
||||||
use rustc_errors::{
|
use rustc_errors::{
|
||||||
struct_span_err, AddToDiagnostic, Applicability, HelpUseLatestEdition, IntoDiagnostic, PResult,
|
struct_span_err, Applicability, DiagnosticBuilder, ErrorGuaranteed, HelpUseLatestEdition,
|
||||||
StashKey,
|
IntoDiagnostic, PResult, StashKey,
|
||||||
};
|
};
|
||||||
use rustc_span::edition::Edition;
|
use rustc_span::edition::Edition;
|
||||||
use rustc_span::lev_distance::lev_distance;
|
use rustc_span::lev_distance::lev_distance;
|
||||||
|
@ -167,37 +176,20 @@ impl<'a> Parser<'a> {
|
||||||
}
|
}
|
||||||
|
|
||||||
// At this point, we have failed to parse an item.
|
// At this point, we have failed to parse an item.
|
||||||
self.error_on_unmatched_vis(&vis);
|
if !matches!(vis.kind, VisibilityKind::Inherited) {
|
||||||
self.error_on_unmatched_defaultness(def);
|
self.sess.emit_err(VisibilityNotFollowedByItem { span: vis.span, vis });
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Defaultness::Default(span) = def {
|
||||||
|
self.sess.emit_err(DefaultNotFollowedByItem { span });
|
||||||
|
}
|
||||||
|
|
||||||
if !attrs_allowed {
|
if !attrs_allowed {
|
||||||
self.recover_attrs_no_item(&attrs)?;
|
self.recover_attrs_no_item(&attrs)?;
|
||||||
}
|
}
|
||||||
Ok(None)
|
Ok(None)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Error in-case a non-inherited visibility was parsed but no item followed.
|
|
||||||
fn error_on_unmatched_vis(&self, vis: &Visibility) {
|
|
||||||
if let VisibilityKind::Inherited = vis.kind {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
let vs = pprust::vis_to_string(&vis);
|
|
||||||
let vs = vs.trim_end();
|
|
||||||
self.struct_span_err(vis.span, &format!("visibility `{vs}` is not followed by an item"))
|
|
||||||
.span_label(vis.span, "the visibility")
|
|
||||||
.help(&format!("you likely meant to define an item, e.g., `{vs} fn foo() {{}}`"))
|
|
||||||
.emit();
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Error in-case a `default` was parsed but no item followed.
|
|
||||||
fn error_on_unmatched_defaultness(&self, def: Defaultness) {
|
|
||||||
if let Defaultness::Default(sp) = def {
|
|
||||||
self.struct_span_err(sp, "`default` is not followed by an item")
|
|
||||||
.span_label(sp, "the `default` qualifier")
|
|
||||||
.note("only `fn`, `const`, `type`, or `impl` items may be prefixed by `default`")
|
|
||||||
.emit();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Error in-case `default` was parsed in an in-appropriate context.
|
/// Error in-case `default` was parsed in an in-appropriate context.
|
||||||
fn error_on_unconsumed_default(&self, def: Defaultness, kind: &ItemKind) {
|
fn error_on_unconsumed_default(&self, def: Defaultness, kind: &ItemKind) {
|
||||||
if let Defaultness::Default(span) = def {
|
if let Defaultness::Default(span) = def {
|
||||||
|
@ -388,86 +380,72 @@ impl<'a> Parser<'a> {
|
||||||
let sp = self.prev_token.span.between(self.token.span);
|
let sp = self.prev_token.span.between(self.token.span);
|
||||||
let full_sp = self.prev_token.span.to(self.token.span);
|
let full_sp = self.prev_token.span.to(self.token.span);
|
||||||
let ident_sp = self.token.span;
|
let ident_sp = self.token.span;
|
||||||
if self.look_ahead(1, |t| *t == token::OpenDelim(Delimiter::Brace)) {
|
|
||||||
// possible public struct definition where `struct` was forgotten
|
|
||||||
let ident = self.parse_ident().unwrap();
|
|
||||||
let msg = format!("add `struct` here to parse `{ident}` as a public struct");
|
|
||||||
let mut err = self.struct_span_err(sp, "missing `struct` for struct definition");
|
|
||||||
err.span_suggestion_short(
|
|
||||||
sp,
|
|
||||||
&msg,
|
|
||||||
" struct ",
|
|
||||||
Applicability::MaybeIncorrect, // speculative
|
|
||||||
);
|
|
||||||
Err(err)
|
|
||||||
} else if self.look_ahead(1, |t| *t == token::OpenDelim(Delimiter::Parenthesis)) {
|
|
||||||
let ident = self.parse_ident().unwrap();
|
|
||||||
self.bump(); // `(`
|
|
||||||
let kw_name = self.recover_first_param();
|
|
||||||
self.consume_block(Delimiter::Parenthesis, ConsumeClosingDelim::Yes);
|
|
||||||
let (kw, kw_name, ambiguous) = if self.check(&token::RArrow) {
|
|
||||||
self.eat_to_tokens(&[&token::OpenDelim(Delimiter::Brace)]);
|
|
||||||
self.bump(); // `{`
|
|
||||||
("fn", kw_name, false)
|
|
||||||
} else if self.check(&token::OpenDelim(Delimiter::Brace)) {
|
|
||||||
self.bump(); // `{`
|
|
||||||
("fn", kw_name, false)
|
|
||||||
} else if self.check(&token::Semi) {
|
|
||||||
let kw = "struct";
|
|
||||||
(kw, kw, false)
|
|
||||||
} else {
|
|
||||||
("fn` or `struct", "function or struct", true)
|
|
||||||
};
|
|
||||||
|
|
||||||
let msg = format!("missing `{kw}` for {kw_name} definition");
|
let ident = if self.look_ahead(1, |t| {
|
||||||
let mut err = self.struct_span_err(sp, &msg);
|
[
|
||||||
if !ambiguous {
|
token::Lt,
|
||||||
self.consume_block(Delimiter::Brace, ConsumeClosingDelim::Yes);
|
token::OpenDelim(Delimiter::Brace),
|
||||||
let suggestion =
|
token::OpenDelim(Delimiter::Parenthesis),
|
||||||
format!("add `{kw}` here to parse `{ident}` as a public {kw_name}");
|
]
|
||||||
err.span_suggestion_short(
|
.contains(&t.kind)
|
||||||
sp,
|
}) {
|
||||||
&suggestion,
|
self.parse_ident().unwrap()
|
||||||
format!(" {kw} "),
|
} else {
|
||||||
Applicability::MachineApplicable,
|
return Ok(());
|
||||||
);
|
};
|
||||||
} else if let Ok(snippet) = self.span_to_snippet(ident_sp) {
|
|
||||||
err.span_suggestion(
|
let mut found_generics = false;
|
||||||
full_sp,
|
if self.check(&token::Lt) {
|
||||||
"if you meant to call a macro, try",
|
found_generics = true;
|
||||||
format!("{}!", snippet),
|
|
||||||
// this is the `ambiguous` conditional branch
|
|
||||||
Applicability::MaybeIncorrect,
|
|
||||||
);
|
|
||||||
} else {
|
|
||||||
err.help(
|
|
||||||
"if you meant to call a macro, remove the `pub` \
|
|
||||||
and add a trailing `!` after the identifier",
|
|
||||||
);
|
|
||||||
}
|
|
||||||
Err(err)
|
|
||||||
} else if self.look_ahead(1, |t| *t == token::Lt) {
|
|
||||||
let ident = self.parse_ident().unwrap();
|
|
||||||
self.eat_to_tokens(&[&token::Gt]);
|
self.eat_to_tokens(&[&token::Gt]);
|
||||||
self.bump(); // `>`
|
self.bump(); // `>`
|
||||||
let (kw, kw_name, ambiguous) = if self.eat(&token::OpenDelim(Delimiter::Parenthesis)) {
|
}
|
||||||
("fn", self.recover_first_param(), false)
|
|
||||||
} else if self.check(&token::OpenDelim(Delimiter::Brace)) {
|
let err = if self.check(&token::OpenDelim(Delimiter::Brace)) {
|
||||||
("struct", "struct", false)
|
// possible public struct definition where `struct` was forgotten
|
||||||
|
Some(MissingKeywordForItemDefinition::Struct { span: sp, ident })
|
||||||
|
} else if self.check(&token::OpenDelim(Delimiter::Parenthesis)) {
|
||||||
|
// possible public function or tuple struct definition where `fn`/`struct` was
|
||||||
|
// forgotten
|
||||||
|
self.bump(); // `(`
|
||||||
|
let is_method = self.recover_self_param();
|
||||||
|
|
||||||
|
self.consume_block(Delimiter::Parenthesis, ConsumeClosingDelim::Yes);
|
||||||
|
|
||||||
|
let err = if self.check(&token::RArrow)
|
||||||
|
|| self.check(&token::OpenDelim(Delimiter::Brace))
|
||||||
|
{
|
||||||
|
self.eat_to_tokens(&[&token::OpenDelim(Delimiter::Brace)]);
|
||||||
|
self.bump(); // `{`
|
||||||
|
self.consume_block(Delimiter::Brace, ConsumeClosingDelim::Yes);
|
||||||
|
if is_method {
|
||||||
|
MissingKeywordForItemDefinition::Method { span: sp, ident }
|
||||||
|
} else {
|
||||||
|
MissingKeywordForItemDefinition::Function { span: sp, ident }
|
||||||
|
}
|
||||||
|
} else if self.check(&token::Semi) {
|
||||||
|
MissingKeywordForItemDefinition::Struct { span: sp, ident }
|
||||||
} else {
|
} else {
|
||||||
("fn` or `struct", "function or struct", true)
|
MissingKeywordForItemDefinition::Ambiguous {
|
||||||
|
span: sp,
|
||||||
|
subdiag: if found_generics {
|
||||||
|
None
|
||||||
|
} else if let Ok(snippet) = self.span_to_snippet(ident_sp) {
|
||||||
|
Some(AmbiguousMissingKwForItemSub::SuggestMacro { span: full_sp, snippet })
|
||||||
|
} else {
|
||||||
|
Some(AmbiguousMissingKwForItemSub::HelpMacro)
|
||||||
|
},
|
||||||
|
}
|
||||||
};
|
};
|
||||||
let msg = format!("missing `{kw}` for {kw_name} definition");
|
Some(err)
|
||||||
let mut err = self.struct_span_err(sp, &msg);
|
} else if found_generics {
|
||||||
if !ambiguous {
|
Some(MissingKeywordForItemDefinition::Ambiguous { span: sp, subdiag: None })
|
||||||
err.span_suggestion_short(
|
} else {
|
||||||
sp,
|
None
|
||||||
&format!("add `{kw}` here to parse `{ident}` as a public {kw_name}"),
|
};
|
||||||
format!(" {} ", kw),
|
|
||||||
Applicability::MachineApplicable,
|
if let Some(err) = err {
|
||||||
);
|
Err(err.into_diagnostic(&self.sess.span_diagnostic))
|
||||||
}
|
|
||||||
Err(err)
|
|
||||||
} else {
|
} else {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
@ -516,16 +494,13 @@ impl<'a> Parser<'a> {
|
||||||
let mut err = self.struct_span_err(end.span, msg);
|
let mut err = self.struct_span_err(end.span, msg);
|
||||||
if end.is_doc_comment() {
|
if end.is_doc_comment() {
|
||||||
err.span_label(end.span, "this doc comment doesn't document anything");
|
err.span_label(end.span, "this doc comment doesn't document anything");
|
||||||
}
|
} else if self.token.kind == TokenKind::Semi {
|
||||||
if end.meta_kind().is_some() {
|
err.span_suggestion_verbose(
|
||||||
if self.token.kind == TokenKind::Semi {
|
self.token.span,
|
||||||
err.span_suggestion_verbose(
|
"consider removing this semicolon",
|
||||||
self.token.span,
|
"",
|
||||||
"consider removing this semicolon",
|
Applicability::MaybeIncorrect,
|
||||||
"",
|
);
|
||||||
Applicability::MaybeIncorrect,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
if let [.., penultimate, _] = attrs {
|
if let [.., penultimate, _] = attrs {
|
||||||
err.span_label(start.span.to(penultimate.span), "other attributes here");
|
err.span_label(start.span.to(penultimate.span), "other attributes here");
|
||||||
|
@ -592,20 +567,9 @@ impl<'a> Parser<'a> {
|
||||||
let ty_first = if self.token.is_keyword(kw::For) && self.look_ahead(1, |t| t != &token::Lt)
|
let ty_first = if self.token.is_keyword(kw::For) && self.look_ahead(1, |t| t != &token::Lt)
|
||||||
{
|
{
|
||||||
let span = self.prev_token.span.between(self.token.span);
|
let span = self.prev_token.span.between(self.token.span);
|
||||||
self.struct_span_err(span, "missing trait in a trait impl")
|
self.sess
|
||||||
.span_suggestion(
|
.emit_err(MissingTraitInTraitImpl { span, for_span: span.to(self.token.span) });
|
||||||
span,
|
|
||||||
"add a trait here",
|
|
||||||
" Trait ",
|
|
||||||
Applicability::HasPlaceholders,
|
|
||||||
)
|
|
||||||
.span_suggestion(
|
|
||||||
span.to(self.token.span),
|
|
||||||
"for an inherent impl, drop this `for`",
|
|
||||||
"",
|
|
||||||
Applicability::MaybeIncorrect,
|
|
||||||
)
|
|
||||||
.emit();
|
|
||||||
P(Ty {
|
P(Ty {
|
||||||
kind: TyKind::Path(None, err_path(span)),
|
kind: TyKind::Path(None, err_path(span)),
|
||||||
span,
|
span,
|
||||||
|
@ -638,14 +602,7 @@ impl<'a> Parser<'a> {
|
||||||
Some(ty_second) => {
|
Some(ty_second) => {
|
||||||
// impl Trait for Type
|
// impl Trait for Type
|
||||||
if !has_for {
|
if !has_for {
|
||||||
self.struct_span_err(missing_for_span, "missing `for` in a trait impl")
|
self.sess.emit_err(MissingForInTraitImpl { span: missing_for_span });
|
||||||
.span_suggestion_short(
|
|
||||||
missing_for_span,
|
|
||||||
"add `for` here",
|
|
||||||
" for ",
|
|
||||||
Applicability::MachineApplicable,
|
|
||||||
)
|
|
||||||
.emit();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
let ty_first = ty_first.into_inner();
|
let ty_first = ty_first.into_inner();
|
||||||
|
@ -653,7 +610,8 @@ impl<'a> Parser<'a> {
|
||||||
// This notably includes paths passed through `ty` macro fragments (#46438).
|
// This notably includes paths passed through `ty` macro fragments (#46438).
|
||||||
TyKind::Path(None, path) => path,
|
TyKind::Path(None, path) => path,
|
||||||
_ => {
|
_ => {
|
||||||
self.struct_span_err(ty_first.span, "expected a trait, found type").emit();
|
self.sess
|
||||||
|
.emit_err(ExpectedTraitInTraitImplFoundType { span: ty_first.span });
|
||||||
err_path(ty_first.span)
|
err_path(ty_first.span)
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -745,29 +703,22 @@ impl<'a> Parser<'a> {
|
||||||
let non_item_span = self.token.span;
|
let non_item_span = self.token.span;
|
||||||
let is_let = self.token.is_keyword(kw::Let);
|
let is_let = self.token.is_keyword(kw::Let);
|
||||||
|
|
||||||
let mut err = self.struct_span_err(non_item_span, "non-item in item list");
|
|
||||||
self.consume_block(Delimiter::Brace, ConsumeClosingDelim::Yes);
|
self.consume_block(Delimiter::Brace, ConsumeClosingDelim::Yes);
|
||||||
if is_let {
|
|
||||||
err.span_suggestion(
|
self.sess.emit_err(NonItemInItemList {
|
||||||
non_item_span,
|
span: non_item_span,
|
||||||
"consider using `const` instead of `let` for associated const",
|
sub: if is_let {
|
||||||
"const",
|
NonItemInItemListSub::Let { span: non_item_span }
|
||||||
Applicability::MachineApplicable,
|
} else {
|
||||||
);
|
NonItemInItemListSub::Other {
|
||||||
} else {
|
list_start: open_brace_span,
|
||||||
err.span_label(open_brace_span, "item list starts here")
|
non_item: non_item_span,
|
||||||
.span_label(non_item_span, "non-item starts here")
|
list_end: self.prev_token.span,
|
||||||
.span_label(self.prev_token.span, "item list ends here");
|
}
|
||||||
}
|
},
|
||||||
if is_unnecessary_semicolon {
|
remove_semicolon: is_unnecessary_semicolon.then_some(semicolon_span),
|
||||||
err.span_suggestion(
|
});
|
||||||
semicolon_span,
|
|
||||||
"consider removing this semicolon",
|
|
||||||
"",
|
|
||||||
Applicability::MaybeIncorrect,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
err.emit();
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
Ok(Some(item)) => items.extend(item),
|
Ok(Some(item)) => items.extend(item),
|
||||||
|
@ -787,6 +738,7 @@ impl<'a> Parser<'a> {
|
||||||
fn recover_doc_comment_before_brace(&mut self) -> bool {
|
fn recover_doc_comment_before_brace(&mut self) -> bool {
|
||||||
if let token::DocComment(..) = self.token.kind {
|
if let token::DocComment(..) = self.token.kind {
|
||||||
if self.look_ahead(1, |tok| tok == &token::CloseDelim(Delimiter::Brace)) {
|
if self.look_ahead(1, |tok| tok == &token::CloseDelim(Delimiter::Brace)) {
|
||||||
|
// FIXME: merge with `DocCommentDoesNotDocumentAnything` (E0585)
|
||||||
struct_span_err!(
|
struct_span_err!(
|
||||||
self.diagnostic(),
|
self.diagnostic(),
|
||||||
self.token.span,
|
self.token.span,
|
||||||
|
@ -853,7 +805,7 @@ impl<'a> Parser<'a> {
|
||||||
// It's a trait alias.
|
// It's a trait alias.
|
||||||
if had_colon {
|
if had_colon {
|
||||||
let span = span_at_colon.to(span_before_eq);
|
let span = span_at_colon.to(span_before_eq);
|
||||||
self.struct_span_err(span, "bounds are not allowed on trait aliases").emit();
|
self.sess.emit_err(BoundsNotAllowedOnTraitAliases { span });
|
||||||
}
|
}
|
||||||
|
|
||||||
let bounds = self.parse_generic_bounds(None)?;
|
let bounds = self.parse_generic_bounds(None)?;
|
||||||
|
@ -862,12 +814,10 @@ impl<'a> Parser<'a> {
|
||||||
|
|
||||||
let whole_span = lo.to(self.prev_token.span);
|
let whole_span = lo.to(self.prev_token.span);
|
||||||
if is_auto == IsAuto::Yes {
|
if is_auto == IsAuto::Yes {
|
||||||
let msg = "trait aliases cannot be `auto`";
|
self.sess.emit_err(TraitAliasCannotBeAuto { span: whole_span });
|
||||||
self.struct_span_err(whole_span, msg).span_label(whole_span, msg).emit();
|
|
||||||
}
|
}
|
||||||
if let Unsafe::Yes(_) = unsafety {
|
if let Unsafe::Yes(_) = unsafety {
|
||||||
let msg = "trait aliases cannot be `unsafe`";
|
self.sess.emit_err(TraitAliasCannotBeUnsafe { span: whole_span });
|
||||||
self.struct_span_err(whole_span, msg).span_label(whole_span, msg).emit();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
self.sess.gated_spans.gate(sym::trait_alias, whole_span);
|
self.sess.gated_spans.gate(sym::trait_alias, whole_span);
|
||||||
|
@ -913,8 +863,7 @@ impl<'a> Parser<'a> {
|
||||||
Ok(kind) => kind,
|
Ok(kind) => kind,
|
||||||
Err(kind) => match kind {
|
Err(kind) => match kind {
|
||||||
ItemKind::Static(a, _, b) => {
|
ItemKind::Static(a, _, b) => {
|
||||||
self.struct_span_err(span, "associated `static` items are not allowed")
|
self.sess.emit_err(AssociatedStaticItemNotAllowed { span });
|
||||||
.emit();
|
|
||||||
AssocItemKind::Const(Defaultness::Final, a, b)
|
AssocItemKind::Const(Defaultness::Final, a, b)
|
||||||
}
|
}
|
||||||
_ => return self.error_bad_item_kind(span, &kind, "`trait`s or `impl`s"),
|
_ => return self.error_bad_item_kind(span, &kind, "`trait`s or `impl`s"),
|
||||||
|
@ -1088,41 +1037,37 @@ impl<'a> Parser<'a> {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn parse_crate_name_with_dashes(&mut self) -> PResult<'a, Ident> {
|
fn parse_crate_name_with_dashes(&mut self) -> PResult<'a, Ident> {
|
||||||
let error_msg = "crate name using dashes are not valid in `extern crate` statements";
|
let ident = if self.token.is_keyword(kw::SelfLower) {
|
||||||
let suggestion_msg = "if the original crate name uses dashes you need to use underscores \
|
|
||||||
in the code";
|
|
||||||
let mut ident = if self.token.is_keyword(kw::SelfLower) {
|
|
||||||
self.parse_path_segment_ident()
|
self.parse_path_segment_ident()
|
||||||
} else {
|
} else {
|
||||||
self.parse_ident()
|
self.parse_ident()
|
||||||
}?;
|
}?;
|
||||||
let mut idents = vec![];
|
|
||||||
let mut replacement = vec![];
|
|
||||||
let mut fixed_crate_name = false;
|
|
||||||
// Accept `extern crate name-like-this` for better diagnostics.
|
|
||||||
let dash = token::BinOp(token::BinOpToken::Minus);
|
|
||||||
if self.token == dash {
|
|
||||||
// Do not include `-` as part of the expected tokens list.
|
|
||||||
while self.eat(&dash) {
|
|
||||||
fixed_crate_name = true;
|
|
||||||
replacement.push((self.prev_token.span, "_".to_string()));
|
|
||||||
idents.push(self.parse_ident()?);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if fixed_crate_name {
|
|
||||||
let fixed_name_sp = ident.span.to(idents.last().unwrap().span);
|
|
||||||
let mut fixed_name = ident.name.to_string();
|
|
||||||
for part in idents {
|
|
||||||
write!(fixed_name, "_{}", part.name).unwrap();
|
|
||||||
}
|
|
||||||
ident = Ident::from_str_and_span(&fixed_name, fixed_name_sp);
|
|
||||||
|
|
||||||
self.struct_span_err(fixed_name_sp, error_msg)
|
let dash = token::BinOp(token::BinOpToken::Minus);
|
||||||
.span_label(fixed_name_sp, "dash-separated idents are not valid")
|
if self.token != dash {
|
||||||
.multipart_suggestion(suggestion_msg, replacement, Applicability::MachineApplicable)
|
return Ok(ident);
|
||||||
.emit();
|
|
||||||
}
|
}
|
||||||
Ok(ident)
|
|
||||||
|
// Accept `extern crate name-like-this` for better diagnostics.
|
||||||
|
let mut dashes = vec![];
|
||||||
|
let mut idents = vec![];
|
||||||
|
while self.eat(&dash) {
|
||||||
|
dashes.push(self.prev_token.span);
|
||||||
|
idents.push(self.parse_ident()?);
|
||||||
|
}
|
||||||
|
|
||||||
|
let fixed_name_sp = ident.span.to(idents.last().unwrap().span);
|
||||||
|
let mut fixed_name = ident.name.to_string();
|
||||||
|
for part in idents {
|
||||||
|
write!(fixed_name, "_{}", part.name).unwrap();
|
||||||
|
}
|
||||||
|
|
||||||
|
self.sess.emit_err(ExternCrateNameWithDashes {
|
||||||
|
span: fixed_name_sp,
|
||||||
|
sugg: ExternCrateNameWithDashesSugg { dashes },
|
||||||
|
});
|
||||||
|
|
||||||
|
Ok(Ident::from_str_and_span(&fixed_name, fixed_name_sp))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Parses `extern` for foreign ABIs modules.
|
/// Parses `extern` for foreign ABIs modules.
|
||||||
|
@ -1170,7 +1115,10 @@ impl<'a> Parser<'a> {
|
||||||
Ok(kind) => kind,
|
Ok(kind) => kind,
|
||||||
Err(kind) => match kind {
|
Err(kind) => match kind {
|
||||||
ItemKind::Const(_, a, b) => {
|
ItemKind::Const(_, a, b) => {
|
||||||
self.error_on_foreign_const(span, ident);
|
self.sess.emit_err(ExternItemCannotBeConst {
|
||||||
|
ident_span: ident.span,
|
||||||
|
const_span: span.with_hi(ident.span.lo()),
|
||||||
|
});
|
||||||
ForeignItemKind::Static(a, Mutability::Not, b)
|
ForeignItemKind::Static(a, Mutability::Not, b)
|
||||||
}
|
}
|
||||||
_ => return self.error_bad_item_kind(span, &kind, "`extern` blocks"),
|
_ => return self.error_bad_item_kind(span, &kind, "`extern` blocks"),
|
||||||
|
@ -1182,6 +1130,7 @@ impl<'a> Parser<'a> {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn error_bad_item_kind<T>(&self, span: Span, kind: &ItemKind, ctx: &str) -> Option<T> {
|
fn error_bad_item_kind<T>(&self, span: Span, kind: &ItemKind, ctx: &str) -> Option<T> {
|
||||||
|
// FIXME(#100717): needs variant for each `ItemKind` (instead of using `ItemKind::descr()`)
|
||||||
let span = self.sess.source_map().guess_head_span(span);
|
let span = self.sess.source_map().guess_head_span(span);
|
||||||
let descr = kind.descr();
|
let descr = kind.descr();
|
||||||
self.struct_span_err(span, &format!("{descr} is not supported in {ctx}"))
|
self.struct_span_err(span, &format!("{descr} is not supported in {ctx}"))
|
||||||
|
@ -1190,18 +1139,6 @@ impl<'a> Parser<'a> {
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
|
|
||||||
fn error_on_foreign_const(&self, span: Span, ident: Ident) {
|
|
||||||
self.struct_span_err(ident.span, "extern items cannot be `const`")
|
|
||||||
.span_suggestion(
|
|
||||||
span.with_hi(ident.span.lo()),
|
|
||||||
"try using a static value",
|
|
||||||
"static ",
|
|
||||||
Applicability::MachineApplicable,
|
|
||||||
)
|
|
||||||
.note("for more information, visit https://doc.rust-lang.org/std/keyword.extern.html")
|
|
||||||
.emit();
|
|
||||||
}
|
|
||||||
|
|
||||||
fn is_unsafe_foreign_mod(&self) -> bool {
|
fn is_unsafe_foreign_mod(&self) -> bool {
|
||||||
self.token.is_keyword(kw::Unsafe)
|
self.token.is_keyword(kw::Unsafe)
|
||||||
&& self.is_keyword_ahead(1, &[kw::Extern])
|
&& self.is_keyword_ahead(1, &[kw::Extern])
|
||||||
|
@ -1229,25 +1166,10 @@ impl<'a> Parser<'a> {
|
||||||
fn recover_const_mut(&mut self, const_span: Span) {
|
fn recover_const_mut(&mut self, const_span: Span) {
|
||||||
if self.eat_keyword(kw::Mut) {
|
if self.eat_keyword(kw::Mut) {
|
||||||
let span = self.prev_token.span;
|
let span = self.prev_token.span;
|
||||||
self.struct_span_err(span, "const globals cannot be mutable")
|
self.sess.emit_err(ConstGlobalCannotBeMutable { ident_span: span, const_span });
|
||||||
.span_label(span, "cannot be mutable")
|
|
||||||
.span_suggestion(
|
|
||||||
const_span,
|
|
||||||
"you might want to declare a static instead",
|
|
||||||
"static",
|
|
||||||
Applicability::MaybeIncorrect,
|
|
||||||
)
|
|
||||||
.emit();
|
|
||||||
} else if self.eat_keyword(kw::Let) {
|
} else if self.eat_keyword(kw::Let) {
|
||||||
let span = self.prev_token.span;
|
let span = self.prev_token.span;
|
||||||
self.struct_span_err(const_span.to(span), "`const` and `let` are mutually exclusive")
|
self.sess.emit_err(ConstLetMutuallyExclusive { span: const_span.to(span) });
|
||||||
.span_suggestion(
|
|
||||||
const_span.to(span),
|
|
||||||
"remove `let`",
|
|
||||||
"const",
|
|
||||||
Applicability::MaybeIncorrect,
|
|
||||||
)
|
|
||||||
.emit();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1332,13 +1254,8 @@ impl<'a> Parser<'a> {
|
||||||
};
|
};
|
||||||
|
|
||||||
let span = self.prev_token.span.shrink_to_hi();
|
let span = self.prev_token.span.shrink_to_hi();
|
||||||
let mut err = self.struct_span_err(span, &format!("missing type for `{kind}` item"));
|
let err: DiagnosticBuilder<'_, ErrorGuaranteed> =
|
||||||
err.span_suggestion(
|
MissingConstType { span, colon, kind }.into_diagnostic(&self.sess.span_diagnostic);
|
||||||
span,
|
|
||||||
"provide a type for the item",
|
|
||||||
format!("{colon} <type>"),
|
|
||||||
Applicability::HasPlaceholders,
|
|
||||||
);
|
|
||||||
err.stash(span, StashKey::ItemNoType);
|
err.stash(span, StashKey::ItemNoType);
|
||||||
|
|
||||||
// The user intended that the type be inferred,
|
// The user intended that the type be inferred,
|
||||||
|
@ -1350,18 +1267,12 @@ impl<'a> Parser<'a> {
|
||||||
fn parse_item_enum(&mut self) -> PResult<'a, ItemInfo> {
|
fn parse_item_enum(&mut self) -> PResult<'a, ItemInfo> {
|
||||||
if self.token.is_keyword(kw::Struct) {
|
if self.token.is_keyword(kw::Struct) {
|
||||||
let span = self.prev_token.span.to(self.token.span);
|
let span = self.prev_token.span.to(self.token.span);
|
||||||
let mut err = self.struct_span_err(span, "`enum` and `struct` are mutually exclusive");
|
let err = EnumStructMutuallyExclusive { span };
|
||||||
err.span_suggestion(
|
|
||||||
span,
|
|
||||||
"replace `enum struct` with",
|
|
||||||
"enum",
|
|
||||||
Applicability::MachineApplicable,
|
|
||||||
);
|
|
||||||
if self.look_ahead(1, |t| t.is_ident()) {
|
if self.look_ahead(1, |t| t.is_ident()) {
|
||||||
self.bump();
|
self.bump();
|
||||||
err.emit();
|
self.sess.emit_err(err);
|
||||||
} else {
|
} else {
|
||||||
return Err(err);
|
return Err(err.into_diagnostic(&self.sess.span_diagnostic));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1497,13 +1408,8 @@ impl<'a> Parser<'a> {
|
||||||
self.expect_semi()?;
|
self.expect_semi()?;
|
||||||
body
|
body
|
||||||
} else {
|
} else {
|
||||||
let token_str = super::token_descr(&self.token);
|
let err = UnexpectedTokenAfterStructName::new(self.token.span, self.token.clone());
|
||||||
let msg = &format!(
|
return Err(err.into_diagnostic(&self.sess.span_diagnostic));
|
||||||
"expected `where`, `{{`, `(`, or `;` after struct name, found {token_str}"
|
|
||||||
);
|
|
||||||
let mut err = self.struct_span_err(self.token.span, msg);
|
|
||||||
err.span_label(self.token.span, "expected `where`, `{`, `(`, or `;` after struct name");
|
|
||||||
return Err(err);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
Ok((class_name, ItemKind::Struct(vdata, generics)))
|
Ok((class_name, ItemKind::Struct(vdata, generics)))
|
||||||
|
@ -2334,7 +2240,9 @@ impl<'a> Parser<'a> {
|
||||||
let ext = self.parse_extern(case);
|
let ext = self.parse_extern(case);
|
||||||
|
|
||||||
if let Async::Yes { span, .. } = asyncness {
|
if let Async::Yes { span, .. } = asyncness {
|
||||||
self.ban_async_in_2015(span);
|
if span.rust_2015() {
|
||||||
|
self.sess.emit_err(AsyncFnIn2015 { span, help: HelpUseLatestEdition::new() });
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if !self.eat_keyword_case(kw::Fn, case) {
|
if !self.eat_keyword_case(kw::Fn, case) {
|
||||||
|
@ -2444,19 +2352,6 @@ impl<'a> Parser<'a> {
|
||||||
Ok(FnHeader { constness, unsafety, asyncness, ext })
|
Ok(FnHeader { constness, unsafety, asyncness, ext })
|
||||||
}
|
}
|
||||||
|
|
||||||
/// We are parsing `async fn`. If we are on Rust 2015, emit an error.
|
|
||||||
fn ban_async_in_2015(&self, span: Span) {
|
|
||||||
if span.rust_2015() {
|
|
||||||
let diag = self.diagnostic();
|
|
||||||
|
|
||||||
let mut e =
|
|
||||||
struct_span_err!(diag, span, E0670, "`async fn` is not permitted in Rust 2015");
|
|
||||||
e.span_label(span, "to use `async fn`, switch to Rust 2018 or later");
|
|
||||||
HelpUseLatestEdition::new().add_to_diagnostic(&mut e);
|
|
||||||
e.emit();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Parses the parameter list and result type of a function declaration.
|
/// Parses the parameter list and result type of a function declaration.
|
||||||
pub(super) fn parse_fn_decl(
|
pub(super) fn parse_fn_decl(
|
||||||
&mut self,
|
&mut self,
|
||||||
|
@ -2599,9 +2494,7 @@ impl<'a> Parser<'a> {
|
||||||
};
|
};
|
||||||
// Recover for the grammar `*self`, `*const self`, and `*mut self`.
|
// Recover for the grammar `*self`, `*const self`, and `*mut self`.
|
||||||
let recover_self_ptr = |this: &mut Self| {
|
let recover_self_ptr = |this: &mut Self| {
|
||||||
let msg = "cannot pass `self` by raw pointer";
|
self.sess.emit_err(SelfArgumentPointer { span: this.token.span });
|
||||||
let span = this.token.span;
|
|
||||||
this.struct_span_err(span, msg).span_label(span, msg).emit();
|
|
||||||
|
|
||||||
Ok((SelfKind::Value(Mutability::Not), expect_self_ident(this), this.prev_token.span))
|
Ok((SelfKind::Value(Mutability::Not), expect_self_ident(this), this.prev_token.span))
|
||||||
};
|
};
|
||||||
|
@ -2682,14 +2575,14 @@ impl<'a> Parser<'a> {
|
||||||
&& self.look_ahead(offset + 1, |t| t == &token::Colon)
|
&& self.look_ahead(offset + 1, |t| t == &token::Colon)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn recover_first_param(&mut self) -> &'static str {
|
fn recover_self_param(&mut self) -> bool {
|
||||||
match self
|
match self
|
||||||
.parse_outer_attributes()
|
.parse_outer_attributes()
|
||||||
.and_then(|_| self.parse_self_param())
|
.and_then(|_| self.parse_self_param())
|
||||||
.map_err(|e| e.cancel())
|
.map_err(|e| e.cancel())
|
||||||
{
|
{
|
||||||
Ok(Some(_)) => "method",
|
Ok(Some(_)) => true,
|
||||||
_ => "function",
|
_ => false,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,9 +2,11 @@ use rustc_ast::ptr::P;
|
||||||
use rustc_ast::token::{self, Delimiter, NonterminalKind, Token};
|
use rustc_ast::token::{self, Delimiter, NonterminalKind, Token};
|
||||||
use rustc_ast::HasTokens;
|
use rustc_ast::HasTokens;
|
||||||
use rustc_ast_pretty::pprust;
|
use rustc_ast_pretty::pprust;
|
||||||
|
use rustc_errors::IntoDiagnostic;
|
||||||
use rustc_errors::PResult;
|
use rustc_errors::PResult;
|
||||||
use rustc_span::symbol::{kw, Ident};
|
use rustc_span::symbol::{kw, Ident};
|
||||||
|
|
||||||
|
use crate::errors::UnexpectedNonterminal;
|
||||||
use crate::parser::pat::{CommaRecoveryMode, RecoverColon, RecoverComma};
|
use crate::parser::pat::{CommaRecoveryMode, RecoverColon, RecoverComma};
|
||||||
use crate::parser::{FollowedByType, ForceCollect, NtOrTt, Parser, PathStyle};
|
use crate::parser::{FollowedByType, ForceCollect, NtOrTt, Parser, PathStyle};
|
||||||
|
|
||||||
|
@ -113,7 +115,8 @@ impl<'a> Parser<'a> {
|
||||||
NonterminalKind::Item => match self.parse_item(ForceCollect::Yes)? {
|
NonterminalKind::Item => match self.parse_item(ForceCollect::Yes)? {
|
||||||
Some(item) => token::NtItem(item),
|
Some(item) => token::NtItem(item),
|
||||||
None => {
|
None => {
|
||||||
return Err(self.struct_span_err(self.token.span, "expected an item keyword"));
|
return Err(UnexpectedNonterminal::Item(self.token.span)
|
||||||
|
.into_diagnostic(&self.sess.span_diagnostic));
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
NonterminalKind::Block => {
|
NonterminalKind::Block => {
|
||||||
|
@ -124,7 +127,8 @@ impl<'a> Parser<'a> {
|
||||||
NonterminalKind::Stmt => match self.parse_stmt(ForceCollect::Yes)? {
|
NonterminalKind::Stmt => match self.parse_stmt(ForceCollect::Yes)? {
|
||||||
Some(s) => token::NtStmt(P(s)),
|
Some(s) => token::NtStmt(P(s)),
|
||||||
None => {
|
None => {
|
||||||
return Err(self.struct_span_err(self.token.span, "expected a statement"));
|
return Err(UnexpectedNonterminal::Statement(self.token.span)
|
||||||
|
.into_diagnostic(&self.sess.span_diagnostic));
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
NonterminalKind::PatParam { .. } | NonterminalKind::PatWithOr { .. } => {
|
NonterminalKind::PatParam { .. } | NonterminalKind::PatWithOr { .. } => {
|
||||||
|
@ -160,9 +164,10 @@ impl<'a> Parser<'a> {
|
||||||
token::NtIdent(ident, is_raw)
|
token::NtIdent(ident, is_raw)
|
||||||
}
|
}
|
||||||
NonterminalKind::Ident => {
|
NonterminalKind::Ident => {
|
||||||
let token_str = pprust::token_to_string(&self.token);
|
return Err(UnexpectedNonterminal::Ident {
|
||||||
let msg = &format!("expected ident, found {}", &token_str);
|
span: self.token.span,
|
||||||
return Err(self.struct_span_err(self.token.span, msg));
|
token: self.token.clone(),
|
||||||
|
}.into_diagnostic(&self.sess.span_diagnostic));
|
||||||
}
|
}
|
||||||
NonterminalKind::Path => token::NtPath(
|
NonterminalKind::Path => token::NtPath(
|
||||||
P(self.collect_tokens_no_attrs(|this| this.parse_path(PathStyle::Type))?),
|
P(self.collect_tokens_no_attrs(|this| this.parse_path(PathStyle::Type))?),
|
||||||
|
@ -175,9 +180,10 @@ impl<'a> Parser<'a> {
|
||||||
if self.check_lifetime() {
|
if self.check_lifetime() {
|
||||||
token::NtLifetime(self.expect_lifetime().ident)
|
token::NtLifetime(self.expect_lifetime().ident)
|
||||||
} else {
|
} else {
|
||||||
let token_str = pprust::token_to_string(&self.token);
|
return Err(UnexpectedNonterminal::Lifetime {
|
||||||
let msg = &format!("expected a lifetime, found `{}`", &token_str);
|
span: self.token.span,
|
||||||
return Err(self.struct_span_err(self.token.span, msg));
|
token: self.token.clone(),
|
||||||
|
}.into_diagnostic(&self.sess.span_diagnostic));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
|
@ -1,6 +1,12 @@
|
||||||
use super::{ForceCollect, Parser, PathStyle, TrailingToken};
|
use super::{ForceCollect, Parser, PathStyle, TrailingToken};
|
||||||
use crate::errors::{
|
use crate::errors::{
|
||||||
InclusiveRangeExtraEquals, InclusiveRangeMatchArrow, InclusiveRangeNoEnd, RemoveLet,
|
AmbiguousRangePattern, DotDotDotForRemainingFields, DotDotDotRangeToPatternNotAllowed,
|
||||||
|
DotDotDotRestPattern, EnumPatternInsteadOfIdentifier, ExpectedBindingLeftOfAt,
|
||||||
|
ExpectedCommaAfterPatternField, InclusiveRangeExtraEquals, InclusiveRangeMatchArrow,
|
||||||
|
InclusiveRangeNoEnd, InvalidMutInPattern, PatternOnWrongSideOfAt, RefMutOrderIncorrect,
|
||||||
|
RemoveLet, RepeatedMutInPattern, TopLevelOrPatternNotAllowed, TopLevelOrPatternNotAllowedSugg,
|
||||||
|
TrailingVertNotAllowed, UnexpectedLifetimeInPattern, UnexpectedVertVertBeforeFunctionParam,
|
||||||
|
UnexpectedVertVertInPattern,
|
||||||
};
|
};
|
||||||
use crate::{maybe_recover_from_interpolated_ty_qpath, maybe_whole};
|
use crate::{maybe_recover_from_interpolated_ty_qpath, maybe_whole};
|
||||||
use rustc_ast::mut_visit::{noop_visit_pat, MutVisitor};
|
use rustc_ast::mut_visit::{noop_visit_pat, MutVisitor};
|
||||||
|
@ -11,7 +17,9 @@ use rustc_ast::{
|
||||||
PatField, PatKind, Path, QSelf, RangeEnd, RangeSyntax,
|
PatField, PatKind, Path, QSelf, RangeEnd, RangeSyntax,
|
||||||
};
|
};
|
||||||
use rustc_ast_pretty::pprust;
|
use rustc_ast_pretty::pprust;
|
||||||
use rustc_errors::{Applicability, DiagnosticBuilder, ErrorGuaranteed, PResult};
|
use rustc_errors::{
|
||||||
|
fluent, Applicability, DiagnosticBuilder, ErrorGuaranteed, IntoDiagnostic, PResult,
|
||||||
|
};
|
||||||
use rustc_session::errors::ExprParenthesesNeeded;
|
use rustc_session::errors::ExprParenthesesNeeded;
|
||||||
use rustc_span::source_map::{respan, Span, Spanned};
|
use rustc_span::source_map::{respan, Span, Spanned};
|
||||||
use rustc_span::symbol::{kw, sym, Ident};
|
use rustc_span::symbol::{kw, sym, Ident};
|
||||||
|
@ -56,6 +64,12 @@ enum EatOrResult {
|
||||||
None,
|
None,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// The syntax location of a given pattern. Used for diagnostics.
|
||||||
|
pub(super) enum PatternLocation {
|
||||||
|
LetBinding,
|
||||||
|
FunctionParameter,
|
||||||
|
}
|
||||||
|
|
||||||
impl<'a> Parser<'a> {
|
impl<'a> Parser<'a> {
|
||||||
/// Parses a pattern.
|
/// Parses a pattern.
|
||||||
///
|
///
|
||||||
|
@ -170,7 +184,7 @@ impl<'a> Parser<'a> {
|
||||||
&mut self,
|
&mut self,
|
||||||
expected: Expected,
|
expected: Expected,
|
||||||
rc: RecoverComma,
|
rc: RecoverComma,
|
||||||
syntax_loc: &str,
|
syntax_loc: PatternLocation,
|
||||||
) -> PResult<'a, (P<Pat>, bool)> {
|
) -> PResult<'a, (P<Pat>, bool)> {
|
||||||
// We use `parse_pat_allow_top_alt` regardless of whether we actually want top-level
|
// We use `parse_pat_allow_top_alt` regardless of whether we actually want top-level
|
||||||
// or-patterns so that we can detect when a user tries to use it. This allows us to print a
|
// or-patterns so that we can detect when a user tries to use it. This allows us to print a
|
||||||
|
@ -184,27 +198,41 @@ impl<'a> Parser<'a> {
|
||||||
let colon = self.eat(&token::Colon);
|
let colon = self.eat(&token::Colon);
|
||||||
|
|
||||||
if let PatKind::Or(pats) = &pat.kind {
|
if let PatKind::Or(pats) = &pat.kind {
|
||||||
let msg = format!("top-level or-patterns are not allowed in {}", syntax_loc);
|
let span = pat.span;
|
||||||
let (help, fix) = if pats.len() == 1 {
|
|
||||||
// If all we have is a leading vert, then print a special message. This is the case
|
|
||||||
// if `parse_pat_allow_top_alt` returns an or-pattern with one variant.
|
|
||||||
let msg = "remove the `|`";
|
|
||||||
let fix = pprust::pat_to_string(&pat);
|
|
||||||
(msg, fix)
|
|
||||||
} else {
|
|
||||||
let msg = "wrap the pattern in parentheses";
|
|
||||||
let fix = format!("({})", pprust::pat_to_string(&pat));
|
|
||||||
(msg, fix)
|
|
||||||
};
|
|
||||||
|
|
||||||
if trailing_vert {
|
if trailing_vert {
|
||||||
// We already emitted an error and suggestion to remove the trailing vert. Don't
|
// We already emitted an error and suggestion to remove the trailing vert. Don't
|
||||||
// emit again.
|
// emit again.
|
||||||
self.sess.span_diagnostic.delay_span_bug(pat.span, &msg);
|
|
||||||
|
// FIXME(#100717): pass `TopLevelOrPatternNotAllowed::* { sub: None }` to
|
||||||
|
// `delay_span_bug()` instead of fluent message
|
||||||
|
self.sess.span_diagnostic.delay_span_bug(
|
||||||
|
span,
|
||||||
|
match syntax_loc {
|
||||||
|
PatternLocation::LetBinding => {
|
||||||
|
fluent::parse_or_pattern_not_allowed_in_let_binding
|
||||||
|
}
|
||||||
|
PatternLocation::FunctionParameter => {
|
||||||
|
fluent::parse_or_pattern_not_allowed_in_fn_parameters
|
||||||
|
}
|
||||||
|
},
|
||||||
|
);
|
||||||
} else {
|
} else {
|
||||||
self.struct_span_err(pat.span, &msg)
|
let pat = pprust::pat_to_string(&pat);
|
||||||
.span_suggestion(pat.span, help, fix, Applicability::MachineApplicable)
|
let sub = if pats.len() == 1 {
|
||||||
.emit();
|
Some(TopLevelOrPatternNotAllowedSugg::RemoveLeadingVert { span, pat })
|
||||||
|
} else {
|
||||||
|
Some(TopLevelOrPatternNotAllowedSugg::WrapInParens { span, pat })
|
||||||
|
};
|
||||||
|
|
||||||
|
self.sess.emit_err(match syntax_loc {
|
||||||
|
PatternLocation::LetBinding => {
|
||||||
|
TopLevelOrPatternNotAllowed::LetBinding { span, sub }
|
||||||
|
}
|
||||||
|
PatternLocation::FunctionParameter => {
|
||||||
|
TopLevelOrPatternNotAllowed::FunctionParameter { span, sub }
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -221,15 +249,15 @@ impl<'a> Parser<'a> {
|
||||||
// a leading `||` probably doesn't indicate an or-pattern attempt, so we handle that
|
// a leading `||` probably doesn't indicate an or-pattern attempt, so we handle that
|
||||||
// separately.
|
// separately.
|
||||||
if let token::OrOr = self.token.kind {
|
if let token::OrOr = self.token.kind {
|
||||||
let span = self.token.span;
|
self.sess.emit_err(UnexpectedVertVertBeforeFunctionParam { span: self.token.span });
|
||||||
let mut err = self.struct_span_err(span, "unexpected `||` before function parameter");
|
|
||||||
err.span_suggestion(span, "remove the `||`", "", Applicability::MachineApplicable);
|
|
||||||
err.note("alternatives in or-patterns are separated with `|`, not `||`");
|
|
||||||
err.emit();
|
|
||||||
self.bump();
|
self.bump();
|
||||||
}
|
}
|
||||||
|
|
||||||
self.parse_pat_before_ty(PARAM_EXPECTED, RecoverComma::No, "function parameters")
|
self.parse_pat_before_ty(
|
||||||
|
PARAM_EXPECTED,
|
||||||
|
RecoverComma::No,
|
||||||
|
PatternLocation::FunctionParameter,
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Eat the or-pattern `|` separator.
|
/// Eat the or-pattern `|` separator.
|
||||||
|
@ -239,7 +267,7 @@ impl<'a> Parser<'a> {
|
||||||
EatOrResult::TrailingVert
|
EatOrResult::TrailingVert
|
||||||
} else if matches!(self.token.kind, token::OrOr) {
|
} else if matches!(self.token.kind, token::OrOr) {
|
||||||
// Found `||`; Recover and pretend we parsed `|`.
|
// Found `||`; Recover and pretend we parsed `|`.
|
||||||
self.ban_unexpected_or_or(lo);
|
self.sess.emit_err(UnexpectedVertVertInPattern { span: self.token.span, start: lo });
|
||||||
self.bump();
|
self.bump();
|
||||||
EatOrResult::AteOr
|
EatOrResult::AteOr
|
||||||
} else if self.eat(&token::BinOp(token::Or)) {
|
} else if self.eat(&token::BinOp(token::Or)) {
|
||||||
|
@ -273,7 +301,13 @@ impl<'a> Parser<'a> {
|
||||||
});
|
});
|
||||||
match (is_end_ahead, &self.token.kind) {
|
match (is_end_ahead, &self.token.kind) {
|
||||||
(true, token::BinOp(token::Or) | token::OrOr) => {
|
(true, token::BinOp(token::Or) | token::OrOr) => {
|
||||||
self.ban_illegal_vert(lo, "trailing", "not allowed in an or-pattern");
|
// A `|` or possibly `||` token shouldn't be here. Ban it.
|
||||||
|
self.sess.emit_err(TrailingVertNotAllowed {
|
||||||
|
span: self.token.span,
|
||||||
|
start: lo,
|
||||||
|
token: self.token.clone(),
|
||||||
|
note_double_vert: matches!(self.token.kind, token::OrOr).then_some(()),
|
||||||
|
});
|
||||||
self.bump();
|
self.bump();
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
|
@ -281,40 +315,6 @@ impl<'a> Parser<'a> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// We have parsed `||` instead of `|`. Error and suggest `|` instead.
|
|
||||||
fn ban_unexpected_or_or(&mut self, lo: Option<Span>) {
|
|
||||||
let mut err = self.struct_span_err(self.token.span, "unexpected token `||` in pattern");
|
|
||||||
err.span_suggestion(
|
|
||||||
self.token.span,
|
|
||||||
"use a single `|` to separate multiple alternative patterns",
|
|
||||||
"|",
|
|
||||||
Applicability::MachineApplicable,
|
|
||||||
);
|
|
||||||
if let Some(lo) = lo {
|
|
||||||
err.span_label(lo, WHILE_PARSING_OR_MSG);
|
|
||||||
}
|
|
||||||
err.emit();
|
|
||||||
}
|
|
||||||
|
|
||||||
/// A `|` or possibly `||` token shouldn't be here. Ban it.
|
|
||||||
fn ban_illegal_vert(&mut self, lo: Option<Span>, pos: &str, ctx: &str) {
|
|
||||||
let span = self.token.span;
|
|
||||||
let mut err = self.struct_span_err(span, &format!("a {} `|` is {}", pos, ctx));
|
|
||||||
err.span_suggestion(
|
|
||||||
span,
|
|
||||||
&format!("remove the `{}`", pprust::token_to_string(&self.token)),
|
|
||||||
"",
|
|
||||||
Applicability::MachineApplicable,
|
|
||||||
);
|
|
||||||
if let Some(lo) = lo {
|
|
||||||
err.span_label(lo, WHILE_PARSING_OR_MSG);
|
|
||||||
}
|
|
||||||
if let token::OrOr = self.token.kind {
|
|
||||||
err.note("alternatives in or-patterns are separated with `|`, not `||`");
|
|
||||||
}
|
|
||||||
err.emit();
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Parses a pattern, with a setting whether modern range patterns (e.g., `a..=b`, `a..b` are
|
/// Parses a pattern, with a setting whether modern range patterns (e.g., `a..=b`, `a..b` are
|
||||||
/// allowed).
|
/// allowed).
|
||||||
fn parse_pat_with_range_pat(
|
fn parse_pat_with_range_pat(
|
||||||
|
@ -457,15 +457,7 @@ impl<'a> Parser<'a> {
|
||||||
self.bump(); // `...`
|
self.bump(); // `...`
|
||||||
|
|
||||||
// The user probably mistook `...` for a rest pattern `..`.
|
// The user probably mistook `...` for a rest pattern `..`.
|
||||||
self.struct_span_err(lo, "unexpected `...`")
|
self.sess.emit_err(DotDotDotRestPattern { span: lo });
|
||||||
.span_label(lo, "not a valid pattern")
|
|
||||||
.span_suggestion_short(
|
|
||||||
lo,
|
|
||||||
"for a rest pattern, use `..` instead of `...`",
|
|
||||||
"..",
|
|
||||||
Applicability::MachineApplicable,
|
|
||||||
)
|
|
||||||
.emit();
|
|
||||||
PatKind::Rest
|
PatKind::Rest
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -490,7 +482,7 @@ impl<'a> Parser<'a> {
|
||||||
// At this point we attempt to parse `@ $pat_rhs` and emit an error.
|
// At this point we attempt to parse `@ $pat_rhs` and emit an error.
|
||||||
self.bump(); // `@`
|
self.bump(); // `@`
|
||||||
let mut rhs = self.parse_pat_no_top_alt(None)?;
|
let mut rhs = self.parse_pat_no_top_alt(None)?;
|
||||||
let sp = lhs.span.to(rhs.span);
|
let whole_span = lhs.span.to(rhs.span);
|
||||||
|
|
||||||
if let PatKind::Ident(_, _, sub @ None) = &mut rhs.kind {
|
if let PatKind::Ident(_, _, sub @ None) = &mut rhs.kind {
|
||||||
// The user inverted the order, so help them fix that.
|
// The user inverted the order, so help them fix that.
|
||||||
|
@ -499,27 +491,23 @@ impl<'a> Parser<'a> {
|
||||||
// The RHS is now the full pattern.
|
// The RHS is now the full pattern.
|
||||||
*sub = Some(lhs);
|
*sub = Some(lhs);
|
||||||
|
|
||||||
self.struct_span_err(sp, "pattern on wrong side of `@`")
|
self.sess.emit_err(PatternOnWrongSideOfAt {
|
||||||
.span_label(lhs_span, "pattern on the left, should be on the right")
|
whole_span,
|
||||||
.span_label(rhs.span, "binding on the right, should be on the left")
|
whole_pat: pprust::pat_to_string(&rhs),
|
||||||
.span_suggestion(
|
pattern: lhs_span,
|
||||||
sp,
|
binding: rhs.span,
|
||||||
"switch the order",
|
});
|
||||||
pprust::pat_to_string(&rhs),
|
|
||||||
Applicability::MachineApplicable,
|
|
||||||
)
|
|
||||||
.emit();
|
|
||||||
} else {
|
} else {
|
||||||
// The special case above doesn't apply so we may have e.g. `A(x) @ B(y)`.
|
// The special case above doesn't apply so we may have e.g. `A(x) @ B(y)`.
|
||||||
rhs.kind = PatKind::Wild;
|
rhs.kind = PatKind::Wild;
|
||||||
self.struct_span_err(sp, "left-hand side of `@` must be a binding")
|
self.sess.emit_err(ExpectedBindingLeftOfAt {
|
||||||
.span_label(lhs.span, "interpreted as a pattern, not a binding")
|
whole_span,
|
||||||
.span_label(rhs.span, "also a pattern")
|
lhs: lhs.span,
|
||||||
.note("bindings are `x`, `mut x`, `ref x`, and `ref mut x`")
|
rhs: rhs.span,
|
||||||
.emit();
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
rhs.span = sp;
|
rhs.span = whole_span;
|
||||||
Ok(rhs)
|
Ok(rhs)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -534,35 +522,23 @@ impl<'a> Parser<'a> {
|
||||||
_ => return,
|
_ => return,
|
||||||
}
|
}
|
||||||
|
|
||||||
self.struct_span_err(pat.span, "the range pattern here has ambiguous interpretation")
|
self.sess
|
||||||
.span_suggestion(
|
.emit_err(AmbiguousRangePattern { span: pat.span, pat: pprust::pat_to_string(&pat) });
|
||||||
pat.span,
|
|
||||||
"add parentheses to clarify the precedence",
|
|
||||||
format!("({})", pprust::pat_to_string(&pat)),
|
|
||||||
// "ambiguous interpretation" implies that we have to be guessing
|
|
||||||
Applicability::MaybeIncorrect,
|
|
||||||
)
|
|
||||||
.emit();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Parse `&pat` / `&mut pat`.
|
/// Parse `&pat` / `&mut pat`.
|
||||||
fn parse_pat_deref(&mut self, expected: Expected) -> PResult<'a, PatKind> {
|
fn parse_pat_deref(&mut self, expected: Expected) -> PResult<'a, PatKind> {
|
||||||
self.expect_and()?;
|
self.expect_and()?;
|
||||||
self.recover_lifetime_in_deref_pat();
|
|
||||||
let mutbl = self.parse_mutability();
|
|
||||||
let subpat = self.parse_pat_with_range_pat(false, expected)?;
|
|
||||||
Ok(PatKind::Ref(subpat, mutbl))
|
|
||||||
}
|
|
||||||
|
|
||||||
fn recover_lifetime_in_deref_pat(&mut self) {
|
|
||||||
if let token::Lifetime(name) = self.token.kind {
|
if let token::Lifetime(name) = self.token.kind {
|
||||||
self.bump(); // `'a`
|
self.bump(); // `'a`
|
||||||
|
|
||||||
let span = self.prev_token.span;
|
self.sess
|
||||||
self.struct_span_err(span, &format!("unexpected lifetime `{}` in pattern", name))
|
.emit_err(UnexpectedLifetimeInPattern { span: self.prev_token.span, symbol: name });
|
||||||
.span_suggestion(span, "remove the lifetime", "", Applicability::MachineApplicable)
|
|
||||||
.emit();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let mutbl = self.parse_mutability();
|
||||||
|
let subpat = self.parse_pat_with_range_pat(false, expected)?;
|
||||||
|
Ok(PatKind::Ref(subpat, mutbl))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Parse a tuple or parenthesis pattern.
|
/// Parse a tuple or parenthesis pattern.
|
||||||
|
@ -590,7 +566,8 @@ impl<'a> Parser<'a> {
|
||||||
let mut_span = self.prev_token.span;
|
let mut_span = self.prev_token.span;
|
||||||
|
|
||||||
if self.eat_keyword(kw::Ref) {
|
if self.eat_keyword(kw::Ref) {
|
||||||
return self.recover_mut_ref_ident(mut_span);
|
self.sess.emit_err(RefMutOrderIncorrect { span: mut_span.to(self.prev_token.span) });
|
||||||
|
return self.parse_pat_ident(BindingAnnotation::REF_MUT);
|
||||||
}
|
}
|
||||||
|
|
||||||
self.recover_additional_muts();
|
self.recover_additional_muts();
|
||||||
|
@ -620,22 +597,6 @@ impl<'a> Parser<'a> {
|
||||||
Ok(pat.into_inner().kind)
|
Ok(pat.into_inner().kind)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Recover on `mut ref? ident @ pat` and suggest
|
|
||||||
/// that the order of `mut` and `ref` is incorrect.
|
|
||||||
fn recover_mut_ref_ident(&mut self, lo: Span) -> PResult<'a, PatKind> {
|
|
||||||
let mutref_span = lo.to(self.prev_token.span);
|
|
||||||
self.struct_span_err(mutref_span, "the order of `mut` and `ref` is incorrect")
|
|
||||||
.span_suggestion(
|
|
||||||
mutref_span,
|
|
||||||
"try switching the order",
|
|
||||||
"ref mut",
|
|
||||||
Applicability::MachineApplicable,
|
|
||||||
)
|
|
||||||
.emit();
|
|
||||||
|
|
||||||
self.parse_pat_ident(BindingAnnotation::REF_MUT)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Turn all by-value immutable bindings in a pattern into mutable bindings.
|
/// Turn all by-value immutable bindings in a pattern into mutable bindings.
|
||||||
/// Returns `true` if any change was made.
|
/// Returns `true` if any change was made.
|
||||||
fn make_all_value_bindings_mutable(pat: &mut P<Pat>) -> bool {
|
fn make_all_value_bindings_mutable(pat: &mut P<Pat>) -> bool {
|
||||||
|
@ -660,16 +621,13 @@ impl<'a> Parser<'a> {
|
||||||
/// Error on `mut $pat` where `$pat` is not an ident.
|
/// Error on `mut $pat` where `$pat` is not an ident.
|
||||||
fn ban_mut_general_pat(&self, lo: Span, pat: &Pat, changed_any_binding: bool) {
|
fn ban_mut_general_pat(&self, lo: Span, pat: &Pat, changed_any_binding: bool) {
|
||||||
let span = lo.to(pat.span);
|
let span = lo.to(pat.span);
|
||||||
let fix = pprust::pat_to_string(&pat);
|
let pat = pprust::pat_to_string(&pat);
|
||||||
let (problem, suggestion) = if changed_any_binding {
|
|
||||||
("`mut` must be attached to each individual binding", "add `mut` to each binding")
|
self.sess.emit_err(if changed_any_binding {
|
||||||
|
InvalidMutInPattern::NestedIdent { span, pat }
|
||||||
} else {
|
} else {
|
||||||
("`mut` must be followed by a named binding", "remove the `mut` prefix")
|
InvalidMutInPattern::NonIdent { span, pat }
|
||||||
};
|
});
|
||||||
self.struct_span_err(span, problem)
|
|
||||||
.span_suggestion(span, suggestion, fix, Applicability::MachineApplicable)
|
|
||||||
.note("`mut` may be followed by `variable` and `variable @ pattern`")
|
|
||||||
.emit();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Eat any extraneous `mut`s and error + recover if we ate any.
|
/// Eat any extraneous `mut`s and error + recover if we ate any.
|
||||||
|
@ -680,15 +638,7 @@ impl<'a> Parser<'a> {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
let span = lo.to(self.prev_token.span);
|
self.sess.emit_err(RepeatedMutInPattern { span: lo.to(self.prev_token.span) });
|
||||||
self.struct_span_err(span, "`mut` on a binding may not be repeated")
|
|
||||||
.span_suggestion(
|
|
||||||
span,
|
|
||||||
"remove the additional `mut`s",
|
|
||||||
"",
|
|
||||||
Applicability::MachineApplicable,
|
|
||||||
)
|
|
||||||
.emit();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Parse macro invocation
|
/// Parse macro invocation
|
||||||
|
@ -774,28 +724,18 @@ impl<'a> Parser<'a> {
|
||||||
let _ = self.parse_pat_range_end().map_err(|e| e.cancel());
|
let _ = self.parse_pat_range_end().map_err(|e| e.cancel());
|
||||||
}
|
}
|
||||||
|
|
||||||
self.error_inclusive_range_with_extra_equals(span_with_eq);
|
self.sess.emit_err(InclusiveRangeExtraEquals { span: span_with_eq });
|
||||||
}
|
}
|
||||||
token::Gt if no_space => {
|
token::Gt if no_space => {
|
||||||
self.error_inclusive_range_match_arrow(span);
|
let after_pat = span.with_hi(span.hi() - rustc_span::BytePos(1)).shrink_to_hi();
|
||||||
|
self.sess.emit_err(InclusiveRangeMatchArrow { span, after_pat });
|
||||||
|
}
|
||||||
|
_ => {
|
||||||
|
self.sess.emit_err(InclusiveRangeNoEnd { span });
|
||||||
}
|
}
|
||||||
_ => self.error_inclusive_range_with_no_end(span),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn error_inclusive_range_with_extra_equals(&self, span: Span) {
|
|
||||||
self.sess.emit_err(InclusiveRangeExtraEquals { span });
|
|
||||||
}
|
|
||||||
|
|
||||||
fn error_inclusive_range_match_arrow(&self, span: Span) {
|
|
||||||
let after_pat = span.with_hi(span.hi() - rustc_span::BytePos(1)).shrink_to_hi();
|
|
||||||
self.sess.emit_err(InclusiveRangeMatchArrow { span, after_pat });
|
|
||||||
}
|
|
||||||
|
|
||||||
fn error_inclusive_range_with_no_end(&self, span: Span) {
|
|
||||||
self.sess.emit_err(InclusiveRangeNoEnd { span });
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Parse a range-to pattern, `..X` or `..=X` where `X` remains to be parsed.
|
/// Parse a range-to pattern, `..X` or `..=X` where `X` remains to be parsed.
|
||||||
///
|
///
|
||||||
/// The form `...X` is prohibited to reduce confusion with the potential
|
/// The form `...X` is prohibited to reduce confusion with the potential
|
||||||
|
@ -804,14 +744,7 @@ impl<'a> Parser<'a> {
|
||||||
let end = self.parse_pat_range_end()?;
|
let end = self.parse_pat_range_end()?;
|
||||||
if let RangeEnd::Included(syn @ RangeSyntax::DotDotDot) = &mut re.node {
|
if let RangeEnd::Included(syn @ RangeSyntax::DotDotDot) = &mut re.node {
|
||||||
*syn = RangeSyntax::DotDotEq;
|
*syn = RangeSyntax::DotDotEq;
|
||||||
self.struct_span_err(re.span, "range-to patterns with `...` are not allowed")
|
self.sess.emit_err(DotDotDotRangeToPatternNotAllowed { span: re.span });
|
||||||
.span_suggestion_short(
|
|
||||||
re.span,
|
|
||||||
"use `..=` instead",
|
|
||||||
"..=",
|
|
||||||
Applicability::MachineApplicable,
|
|
||||||
)
|
|
||||||
.emit();
|
|
||||||
}
|
}
|
||||||
Ok(PatKind::Range(None, Some(end), re))
|
Ok(PatKind::Range(None, Some(end), re))
|
||||||
}
|
}
|
||||||
|
@ -887,8 +820,8 @@ impl<'a> Parser<'a> {
|
||||||
// binding mode then we do not end up here, because the lookahead
|
// binding mode then we do not end up here, because the lookahead
|
||||||
// will direct us over to `parse_enum_variant()`.
|
// will direct us over to `parse_enum_variant()`.
|
||||||
if self.token == token::OpenDelim(Delimiter::Parenthesis) {
|
if self.token == token::OpenDelim(Delimiter::Parenthesis) {
|
||||||
return Err(self
|
return Err(EnumPatternInsteadOfIdentifier { span: self.prev_token.span }
|
||||||
.struct_span_err(self.prev_token.span, "expected identifier, found enum pattern"));
|
.into_diagnostic(&self.sess.span_diagnostic));
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(PatKind::Ident(binding_annotation, ident, sub))
|
Ok(PatKind::Ident(binding_annotation, ident, sub))
|
||||||
|
@ -1005,7 +938,8 @@ impl<'a> Parser<'a> {
|
||||||
|
|
||||||
// check that a comma comes after every field
|
// check that a comma comes after every field
|
||||||
if !ate_comma {
|
if !ate_comma {
|
||||||
let err = self.struct_span_err(self.token.span, "expected `,`");
|
let err = ExpectedCommaAfterPatternField { span: self.token.span }
|
||||||
|
.into_diagnostic(&self.sess.span_diagnostic);
|
||||||
if let Some(mut delayed) = delayed_err {
|
if let Some(mut delayed) = delayed_err {
|
||||||
delayed.emit();
|
delayed.emit();
|
||||||
}
|
}
|
||||||
|
@ -1118,14 +1052,7 @@ impl<'a> Parser<'a> {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
self.struct_span_err(self.token.span, "expected field pattern, found `...`")
|
self.sess.emit_err(DotDotDotForRemainingFields { span: self.token.span });
|
||||||
.span_suggestion(
|
|
||||||
self.token.span,
|
|
||||||
"to omit remaining fields, use one fewer `.`",
|
|
||||||
"..",
|
|
||||||
Applicability::MachineApplicable,
|
|
||||||
)
|
|
||||||
.emit();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn parse_pat_field(&mut self, lo: Span, attrs: AttrVec) -> PResult<'a, PatField> {
|
fn parse_pat_field(&mut self, lo: Span, attrs: AttrVec) -> PResult<'a, PatField> {
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
use super::attr::InnerAttrForbiddenReason;
|
use super::attr::InnerAttrForbiddenReason;
|
||||||
use super::diagnostics::AttemptLocalParseRecovery;
|
use super::diagnostics::AttemptLocalParseRecovery;
|
||||||
use super::expr::LhsExpr;
|
use super::expr::LhsExpr;
|
||||||
use super::pat::RecoverComma;
|
use super::pat::{PatternLocation, RecoverComma};
|
||||||
use super::path::PathStyle;
|
use super::path::PathStyle;
|
||||||
use super::TrailingToken;
|
use super::TrailingToken;
|
||||||
use super::{
|
use super::{
|
||||||
|
@ -275,7 +275,8 @@ impl<'a> Parser<'a> {
|
||||||
}
|
}
|
||||||
|
|
||||||
self.report_invalid_identifier_error()?;
|
self.report_invalid_identifier_error()?;
|
||||||
let (pat, colon) = self.parse_pat_before_ty(None, RecoverComma::Yes, "`let` bindings")?;
|
let (pat, colon) =
|
||||||
|
self.parse_pat_before_ty(None, RecoverComma::Yes, PatternLocation::LetBinding)?;
|
||||||
|
|
||||||
let (err, ty) = if colon {
|
let (err, ty) = if colon {
|
||||||
// Save the state of the parser before parsing type normally, in case there is a `:`
|
// Save the state of the parser before parsing type normally, in case there is a `:`
|
||||||
|
|
|
@ -3,7 +3,7 @@ error: missing `struct` for struct definition
|
||||||
|
|
|
|
||||||
LL | pub onion {
|
LL | pub onion {
|
||||||
| ^
|
| ^
|
||||||
-Ztrack-diagnostics: created at compiler/rustc_parse/src/parser/diagnostics.rs:LL:CC
|
-Ztrack-diagnostics: created at compiler/rustc_parse/src/parser/item.rs:LL:CC
|
||||||
|
|
|
|
||||||
help: add `struct` here to parse `onion` as a public struct
|
help: add `struct` here to parse `onion` as a public struct
|
||||||
|
|
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue