mirror of
https://github.com/rust-lang/rust.git
synced 2024-11-25 08:13:41 +00:00
Migrate more diagnostics in rustc_parse to diagnostic structs
This commit is contained in:
parent
4d02892acf
commit
ab7c7dc7ce
@ -71,6 +71,8 @@ parser_field_expression_with_generic = field expressions cannot have generic arg
|
||||
parser_macro_invocation_with_qualified_path = macros cannot use qualified paths
|
||||
|
||||
parser_unexpected_token_after_label = expected `while`, `for`, `loop` or `{"{"}` after a label
|
||||
.suggestion_remove_label = consider removing the label
|
||||
.suggestion_enclose_in_block = consider enclosing expression in a block
|
||||
|
||||
parser_require_colon_after_labeled_expression = labeled expression must be followed by `:`
|
||||
.note = labels are used before loops and blocks, allowing e.g., `break 'label` to them
|
||||
@ -161,3 +163,62 @@ parser_use_eq_instead = unexpected `==`
|
||||
|
||||
parser_use_empty_block_not_semi = expected { "`{}`" }, found `;`
|
||||
.suggestion = try using { "`{}`" } instead
|
||||
|
||||
parser_comparison_interpreted_as_generic =
|
||||
`<` is interpreted as a start of generic arguments for `{$typename}`, not a comparison
|
||||
.label_args = interpreted as generic arguments
|
||||
.label_comparison = not interpreted as comparison
|
||||
.suggestion = try comparing the cast value
|
||||
|
||||
parser_shift_interpreted_as_generic =
|
||||
`<<` is interpreted as a start of generic arguments for `{$typename}`, not a shift
|
||||
.label_args = interpreted as generic arguments
|
||||
.label_comparison = not interpreted as shift
|
||||
.suggestion = try shifting the cast value
|
||||
|
||||
parser_found_expr_would_be_stmt = expected expression, found `{$token}`
|
||||
.label = expected expression
|
||||
|
||||
parser_leading_plus_not_supported = leading `+` is not supported
|
||||
.label = unexpected `+`
|
||||
.suggestion_remove_plus = try removing the `+`
|
||||
|
||||
parser_parentheses_with_struct_fields = invalid `struct` delimiters or `fn` call arguments
|
||||
.suggestion_braces_for_struct = if `{$name}` is a struct, use braces as delimiters
|
||||
.suggestion_no_fields_for_fn = if `{$name}` is a function, use the arguments directly
|
||||
|
||||
parser_labeled_loop_in_break = parentheses are required around this expression to avoid confusion with a labeled break expression
|
||||
.suggestion = wrap the expression in parentheses
|
||||
|
||||
parser_array_brackets_instead_of_braces = this is a block expression, not an array
|
||||
.suggestion = to make an array, use square brackets instead of curly braces
|
||||
|
||||
parser_match_arm_body_without_braces = `match` arm body without braces
|
||||
.label_statements = {$num_statements ->
|
||||
[one] this statement is not surrounded by a body
|
||||
*[other] these statements are not surrounded by a body
|
||||
}
|
||||
.label_arrow = while parsing the `match` arm starting here
|
||||
.suggestion_add_braces = surround the {$num_statements ->
|
||||
[one] statement
|
||||
*[other] statements
|
||||
} with a body
|
||||
.suggestion_use_comma_not_semicolon = use a comma to end a `match` arm expression
|
||||
|
||||
parser_struct_literal_not_allowed_here = struct literals are not allowed here
|
||||
.suggestion = surround the struct literal with parentheses
|
||||
|
||||
parser_invalid_interpolated_expression = invalid interpolated expression
|
||||
|
||||
parser_hexadecimal_float_literal_not_supported = hexadecimal float literal is not supported
|
||||
parser_octal_float_literal_not_supported = octal float literal is not supported
|
||||
parser_binary_float_literal_not_supported = binary float literal is not supported
|
||||
parser_not_supported = not supported
|
||||
|
||||
parser_non_string_abi_literal = non-string ABI literal
|
||||
.suggestion = specify the ABI with a string literal
|
||||
|
||||
parser_mismatched_closing_delimiter = mismatched closing delimiter: `{$delimiter}`
|
||||
.label_unmatched = mismatched closing delimiter
|
||||
.label_opening_candidate = closing delimiter possibly meant for this
|
||||
.label_unclosed = unclosed delimiter
|
||||
|
@ -21,6 +21,7 @@ use rustc_errors::{
|
||||
};
|
||||
use rustc_errors::{pluralize, struct_span_err, Diagnostic, ErrorGuaranteed};
|
||||
use rustc_macros::{Diagnostic, Subdiagnostic};
|
||||
use rustc_session::errors::ExprParenthesesNeeded;
|
||||
use rustc_span::source_map::Spanned;
|
||||
use rustc_span::symbol::{kw, sym, Ident};
|
||||
use rustc_span::{Span, SpanSnippetError, DUMMY_SP};
|
||||
@ -487,11 +488,24 @@ pub(crate) struct MacroInvocationWithQualifiedPath(#[primary_span] pub Span);
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(parser::unexpected_token_after_label)]
|
||||
pub(crate) struct UnexpectedTokenAfterLabel(
|
||||
pub(crate) struct UnexpectedTokenAfterLabel {
|
||||
#[primary_span]
|
||||
#[label(parser::unexpected_token_after_label)]
|
||||
pub Span,
|
||||
);
|
||||
pub span: Span,
|
||||
#[suggestion_verbose(parser::suggestion_remove_label, code = "")]
|
||||
pub remove_label: Option<Span>,
|
||||
#[subdiagnostic]
|
||||
pub enclose_in_block: Option<UnexpectedTokenAfterLabelSugg>,
|
||||
}
|
||||
|
||||
#[derive(Subdiagnostic)]
|
||||
#[multipart_suggestion(parser::suggestion_enclose_in_block, applicability = "machine-applicable")]
|
||||
pub(crate) struct UnexpectedTokenAfterLabelSugg {
|
||||
#[suggestion_part(code = "{{ ")]
|
||||
pub left: Span,
|
||||
#[suggestion_part(code = " }}")]
|
||||
pub right: Span,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(parser::require_colon_after_labeled_expression)]
|
||||
@ -753,6 +767,236 @@ pub(crate) struct UseEmptyBlockNotSemi {
|
||||
pub span: Span,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(parser::comparison_interpreted_as_generic)]
|
||||
pub(crate) struct ComparisonInterpretedAsGeneric {
|
||||
#[primary_span]
|
||||
#[label(parser::label_comparison)]
|
||||
pub comparison: Span,
|
||||
pub typename: String,
|
||||
#[label(parser::label_args)]
|
||||
pub args: Span,
|
||||
#[subdiagnostic]
|
||||
pub suggestion: ComparisonOrShiftInterpretedAsGenericSugg,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(parser::shift_interpreted_as_generic)]
|
||||
pub(crate) struct ShiftInterpretedAsGeneric {
|
||||
#[primary_span]
|
||||
#[label(parser::label_comparison)]
|
||||
pub shift: Span,
|
||||
pub typename: String,
|
||||
#[label(parser::label_args)]
|
||||
pub args: Span,
|
||||
#[subdiagnostic]
|
||||
pub suggestion: ComparisonOrShiftInterpretedAsGenericSugg,
|
||||
}
|
||||
|
||||
#[derive(Subdiagnostic)]
|
||||
#[multipart_suggestion(parser::suggestion, applicability = "machine-applicable")]
|
||||
pub(crate) struct ComparisonOrShiftInterpretedAsGenericSugg {
|
||||
#[suggestion_part(code = "(")]
|
||||
pub left: Span,
|
||||
#[suggestion_part(code = ")")]
|
||||
pub right: Span,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(parser::found_expr_would_be_stmt)]
|
||||
pub(crate) struct FoundExprWouldBeStmt {
|
||||
#[primary_span]
|
||||
#[label]
|
||||
pub span: Span,
|
||||
pub token: String,
|
||||
#[subdiagnostic]
|
||||
pub suggestion: ExprParenthesesNeeded,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(parser::leading_plus_not_supported)]
|
||||
pub(crate) struct LeadingPlusNotSupported {
|
||||
#[primary_span]
|
||||
#[label]
|
||||
pub span: Span,
|
||||
#[suggestion_verbose(
|
||||
parser::suggestion_remove_plus,
|
||||
code = "",
|
||||
applicability = "machine-applicable"
|
||||
)]
|
||||
pub remove_plus: Option<Span>,
|
||||
#[subdiagnostic]
|
||||
pub add_parentheses: Option<ExprParenthesesNeeded>,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(parser::parentheses_with_struct_fields)]
|
||||
pub(crate) struct ParenthesesWithStructFields {
|
||||
#[primary_span]
|
||||
pub span: Span,
|
||||
pub name: String,
|
||||
#[subdiagnostic]
|
||||
pub braces_for_struct: BracesForStructLiteral,
|
||||
#[subdiagnostic]
|
||||
pub no_fields_for_fn: NoFieldsForFnCall,
|
||||
}
|
||||
|
||||
#[derive(Subdiagnostic)]
|
||||
#[multipart_suggestion(parser::suggestion_braces_for_struct, applicability = "maybe-incorrect")]
|
||||
pub(crate) struct BracesForStructLiteral {
|
||||
#[suggestion_part(code = " {{ ")]
|
||||
pub first: Span,
|
||||
#[suggestion_part(code = " }}")]
|
||||
pub second: Span,
|
||||
}
|
||||
|
||||
#[derive(Subdiagnostic)]
|
||||
#[multipart_suggestion(parser::suggestion_no_fields_for_fn, applicability = "maybe-incorrect")]
|
||||
pub(crate) struct NoFieldsForFnCall {
|
||||
#[suggestion_part(code = "")]
|
||||
pub fields: Vec<Span>,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(parser::labeled_loop_in_break)]
|
||||
pub(crate) struct LabeledLoopInBreak {
|
||||
#[primary_span]
|
||||
pub span: Span,
|
||||
#[subdiagnostic]
|
||||
pub sub: LabeledLoopInBreakSub,
|
||||
}
|
||||
|
||||
#[derive(Subdiagnostic)]
|
||||
#[multipart_suggestion(parser::suggestion, applicability = "machine-applicable")]
|
||||
pub(crate) struct LabeledLoopInBreakSub {
|
||||
#[suggestion_part(code = "(")]
|
||||
pub first: Span,
|
||||
#[suggestion_part(code = ")")]
|
||||
pub second: Span,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(parser::array_brackets_instead_of_braces)]
|
||||
pub(crate) struct ArrayBracketsInsteadOfSpaces {
|
||||
#[primary_span]
|
||||
pub span: Span,
|
||||
#[subdiagnostic]
|
||||
pub sub: ArrayBracketsInsteadOfSpacesSugg,
|
||||
}
|
||||
|
||||
#[derive(Subdiagnostic)]
|
||||
#[multipart_suggestion(parser::suggestion, applicability = "maybe-incorrect")]
|
||||
pub(crate) struct ArrayBracketsInsteadOfSpacesSugg {
|
||||
#[suggestion_part(code = "[")]
|
||||
pub left: Span,
|
||||
#[suggestion_part(code = "]")]
|
||||
pub right: Span,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(parser::match_arm_body_without_braces)]
|
||||
pub(crate) struct MatchArmBodyWithoutBraces {
|
||||
#[primary_span]
|
||||
#[label(parser::label_statements)]
|
||||
pub statements: Span,
|
||||
#[label(parser::label_arrow)]
|
||||
pub arrow: Span,
|
||||
pub num_statements: usize,
|
||||
#[subdiagnostic]
|
||||
pub sub: MatchArmBodyWithoutBracesSugg,
|
||||
}
|
||||
|
||||
#[derive(Subdiagnostic)]
|
||||
pub(crate) enum MatchArmBodyWithoutBracesSugg {
|
||||
#[multipart_suggestion(parser::suggestion_add_braces, applicability = "machine-applicable")]
|
||||
AddBraces {
|
||||
#[suggestion_part(code = "{{ ")]
|
||||
left: Span,
|
||||
#[suggestion_part(code = " }}")]
|
||||
right: Span,
|
||||
},
|
||||
#[suggestion(
|
||||
parser::suggestion_use_comma_not_semicolon,
|
||||
code = ",",
|
||||
applicability = "machine-applicable"
|
||||
)]
|
||||
UseComma {
|
||||
#[primary_span]
|
||||
semicolon: Span,
|
||||
},
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(parser::struct_literal_not_allowed_here)]
|
||||
pub(crate) struct StructLiteralNotAllowedHere {
|
||||
#[primary_span]
|
||||
pub span: Span,
|
||||
#[subdiagnostic]
|
||||
pub sub: StructLiteralNotAllowedHereSugg,
|
||||
}
|
||||
|
||||
#[derive(Subdiagnostic)]
|
||||
#[multipart_suggestion(parser::suggestion, applicability = "machine-applicable")]
|
||||
pub(crate) struct StructLiteralNotAllowedHereSugg {
|
||||
#[suggestion_part(code = "(")]
|
||||
pub left: Span,
|
||||
#[suggestion_part(code = ")")]
|
||||
pub right: Span,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(parser::invalid_interpolated_expression)]
|
||||
pub(crate) struct InvalidInterpolatedExpression {
|
||||
#[primary_span]
|
||||
pub span: Span,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(parser::hexadecimal_float_literal_not_supported)]
|
||||
pub(crate) struct HexadecimalFloatLiteralNotSupported {
|
||||
#[primary_span]
|
||||
#[label(parser::not_supported)]
|
||||
pub span: Span,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(parser::octal_float_literal_not_supported)]
|
||||
pub(crate) struct OctalFloatLiteralNotSupported {
|
||||
#[primary_span]
|
||||
#[label(parser::not_supported)]
|
||||
pub span: Span,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(parser::binary_float_literal_not_supported)]
|
||||
pub(crate) struct BinaryFloatLiteralNotSupported {
|
||||
#[primary_span]
|
||||
#[label(parser::not_supported)]
|
||||
pub span: Span,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(parser::non_string_abi_literal)]
|
||||
pub(crate) struct NonStringAbiLiteral {
|
||||
#[primary_span]
|
||||
#[suggestion(code = "\"C\"", applicability = "maybe-incorrect")]
|
||||
pub span: Span,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(parser::mismatched_closing_delimiter)]
|
||||
pub(crate) struct MismatchedClosingDelimiter {
|
||||
#[primary_span]
|
||||
pub spans: Vec<Span>,
|
||||
pub delimiter: String,
|
||||
#[label(parser::label_unmatched)]
|
||||
pub unmatched: Span,
|
||||
#[label(parser::label_opening_candidate)]
|
||||
pub opening_candidate: Option<Span>,
|
||||
#[label(parser::label_unclosed)]
|
||||
pub unclosed: Option<Span>,
|
||||
}
|
||||
|
||||
// SnapshotParser is used to create a snapshot of the parser
|
||||
// without causing duplicate errors being emitted when the `Parser`
|
||||
// is dropped.
|
||||
|
@ -1,14 +1,19 @@
|
||||
use super::diagnostics::{
|
||||
CatchAfterTry, CommaAfterBaseStruct, DoCatchSyntaxRemoved, DotDotDot, EqFieldInit,
|
||||
ArrayBracketsInsteadOfSpaces, ArrayBracketsInsteadOfSpacesSugg, BracesForStructLiteral,
|
||||
CatchAfterTry, CommaAfterBaseStruct, ComparisonInterpretedAsGeneric,
|
||||
ComparisonOrShiftInterpretedAsGenericSugg, DoCatchSyntaxRemoved, DotDotDot, EqFieldInit,
|
||||
ExpectedElseBlock, ExpectedExpressionFoundLet, FieldExpressionWithGeneric,
|
||||
FloatLiteralRequiresIntegerPart, IfExpressionMissingCondition, IfExpressionMissingThenBlock,
|
||||
IfExpressionMissingThenBlockSub, InvalidBlockMacroSegment, InvalidComparisonOperator,
|
||||
InvalidComparisonOperatorSub, InvalidLogicalOperator, InvalidLogicalOperatorSub,
|
||||
LeftArrowOperator, LifetimeInBorrowExpression, MacroInvocationWithQualifiedPath,
|
||||
MalformedLoopLabel, MissingInInForLoop, MissingInInForLoopSub, MissingSemicolonBeforeArray,
|
||||
NotAsNegationOperator, NotAsNegationOperatorSub, OuterAttributeNotAllowedOnIfElse,
|
||||
RequireColonAfterLabeledExpression, SnapshotParser, TildeAsUnaryOperator,
|
||||
UnexpectedTokenAfterLabel,
|
||||
FloatLiteralRequiresIntegerPart, FoundExprWouldBeStmt, IfExpressionMissingCondition,
|
||||
IfExpressionMissingThenBlock, IfExpressionMissingThenBlockSub, InvalidBlockMacroSegment,
|
||||
InvalidComparisonOperator, InvalidComparisonOperatorSub, InvalidInterpolatedExpression,
|
||||
InvalidLogicalOperator, InvalidLogicalOperatorSub, LabeledLoopInBreak, LeftArrowOperator,
|
||||
LifetimeInBorrowExpression, MacroInvocationWithQualifiedPath, MalformedLoopLabel,
|
||||
MatchArmBodyWithoutBraces, MissingInInForLoop, MissingInInForLoopSub,
|
||||
MissingSemicolonBeforeArray, NoFieldsForFnCall, NotAsNegationOperator,
|
||||
NotAsNegationOperatorSub, OuterAttributeNotAllowedOnIfElse, ParenthesesWithStructFields,
|
||||
RequireColonAfterLabeledExpression, ShiftInterpretedAsGeneric, SnapshotParser,
|
||||
StructLiteralNotAllowedHere, TildeAsUnaryOperator, UnexpectedTokenAfterLabel,
|
||||
UnexpectedTokenAfterLabelSugg,
|
||||
};
|
||||
use super::pat::{CommaRecoveryMode, RecoverColon, RecoverComma, PARAM_EXPECTED};
|
||||
use super::ty::{AllowPlus, RecoverQPath, RecoverReturnSign};
|
||||
@ -18,9 +23,11 @@ use super::{
|
||||
};
|
||||
use crate::maybe_recover_from_interpolated_ty_qpath;
|
||||
use crate::parser::diagnostics::{
|
||||
IntLiteralTooLarge, InvalidFloatLiteralSuffix, InvalidFloatLiteralWidth,
|
||||
InvalidIntLiteralWidth, InvalidNumLiteralBasePrefix, InvalidNumLiteralSuffix,
|
||||
MissingCommaAfterMatchArm,
|
||||
BinaryFloatLiteralNotSupported, HexadecimalFloatLiteralNotSupported, IntLiteralTooLarge,
|
||||
InvalidFloatLiteralSuffix, InvalidFloatLiteralWidth, InvalidIntLiteralWidth,
|
||||
InvalidNumLiteralBasePrefix, InvalidNumLiteralSuffix, LabeledLoopInBreakSub,
|
||||
LeadingPlusNotSupported, MatchArmBodyWithoutBracesSugg, MissingCommaAfterMatchArm,
|
||||
OctalFloatLiteralNotSupported, StructLiteralNotAllowedHereSugg,
|
||||
};
|
||||
|
||||
use core::mem;
|
||||
@ -38,6 +45,7 @@ use rustc_ast::{ClosureBinder, StmtKind};
|
||||
use rustc_ast_pretty::pprust;
|
||||
use rustc_errors::IntoDiagnostic;
|
||||
use rustc_errors::{Applicability, Diagnostic, PResult};
|
||||
use rustc_session::errors::ExprParenthesesNeeded;
|
||||
use rustc_session::lint::builtin::BREAK_WITH_LABEL_AND_LOOP;
|
||||
use rustc_session::lint::BuiltinLintDiagnostics;
|
||||
use rustc_span::source_map::{self, Span, Spanned};
|
||||
@ -421,13 +429,12 @@ impl<'a> Parser<'a> {
|
||||
/// but the next token implies this should be parsed as an expression.
|
||||
/// For example: `if let Some(x) = x { x } else { 0 } / 2`.
|
||||
fn error_found_expr_would_be_stmt(&self, lhs: &Expr) {
|
||||
let mut err = self.struct_span_err(
|
||||
self.token.span,
|
||||
&format!("expected expression, found `{}`", pprust::token_to_string(&self.token),),
|
||||
);
|
||||
err.span_label(self.token.span, "expected expression");
|
||||
self.sess.expr_parentheses_needed(&mut err, lhs.span);
|
||||
err.emit();
|
||||
self.sess.emit_err(FoundExprWouldBeStmt {
|
||||
span: self.token.span,
|
||||
// FIXME(#100717)
|
||||
token: pprust::token_to_string(&self.token).to_string(),
|
||||
suggestion: ExprParenthesesNeeded::surrounding(lhs.span),
|
||||
});
|
||||
}
|
||||
|
||||
/// Possibly translate the current token to an associative operator.
|
||||
@ -578,21 +585,16 @@ impl<'a> Parser<'a> {
|
||||
make_it!(this, attrs, |this, _| this.parse_borrow_expr(lo))
|
||||
}
|
||||
token::BinOp(token::Plus) if this.look_ahead(1, |tok| tok.is_numeric_lit()) => {
|
||||
let mut err = this.struct_span_err(lo, "leading `+` is not supported");
|
||||
err.span_label(lo, "unexpected `+`");
|
||||
let mut err =
|
||||
LeadingPlusNotSupported { span: lo, remove_plus: None, add_parentheses: None };
|
||||
|
||||
// a block on the LHS might have been intended to be an expression instead
|
||||
if let Some(sp) = this.sess.ambiguous_block_expr_parse.borrow().get(&lo) {
|
||||
this.sess.expr_parentheses_needed(&mut err, *sp);
|
||||
err.add_parentheses = Some(ExprParenthesesNeeded::surrounding(*sp));
|
||||
} else {
|
||||
err.span_suggestion_verbose(
|
||||
lo,
|
||||
"try removing the `+`",
|
||||
"",
|
||||
Applicability::MachineApplicable,
|
||||
);
|
||||
err.remove_plus = Some(lo);
|
||||
}
|
||||
err.emit();
|
||||
this.sess.emit_err(err);
|
||||
|
||||
this.bump();
|
||||
this.parse_prefix_expr(None)
|
||||
@ -755,9 +757,33 @@ impl<'a> Parser<'a> {
|
||||
|
||||
match self.parse_path(PathStyle::Expr) {
|
||||
Ok(path) => {
|
||||
let (op_noun, op_verb) = match self.token.kind {
|
||||
token::Lt => ("comparison", "comparing"),
|
||||
token::BinOp(token::Shl) => ("shift", "shifting"),
|
||||
let typename = pprust::path_to_string(&path);
|
||||
|
||||
let span_after_type = parser_snapshot_after_type.token.span;
|
||||
let expr =
|
||||
mk_expr(self, lhs, self.mk_ty(path.span, TyKind::Path(None, path)));
|
||||
|
||||
let args_span = self.look_ahead(1, |t| t.span).to(span_after_type);
|
||||
let suggestion = ComparisonOrShiftInterpretedAsGenericSugg {
|
||||
left: expr.span.shrink_to_lo(),
|
||||
right: expr.span.shrink_to_hi(),
|
||||
};
|
||||
|
||||
match self.token.kind {
|
||||
token::Lt => self.sess.emit_err(ComparisonInterpretedAsGeneric {
|
||||
comparison: self.token.span,
|
||||
typename,
|
||||
args: args_span,
|
||||
suggestion,
|
||||
}),
|
||||
token::BinOp(token::Shl) => {
|
||||
self.sess.emit_err(ShiftInterpretedAsGeneric {
|
||||
shift: self.token.span,
|
||||
typename,
|
||||
args: args_span,
|
||||
suggestion,
|
||||
})
|
||||
}
|
||||
_ => {
|
||||
// We can end up here even without `<` being the next token, for
|
||||
// example because `parse_ty_no_plus` returns `Err` on keywords,
|
||||
@ -771,33 +797,7 @@ impl<'a> Parser<'a> {
|
||||
// Successfully parsed the type path leaving a `<` yet to parse.
|
||||
type_err.cancel();
|
||||
|
||||
// Report non-fatal diagnostics, keep `x as usize` as an expression
|
||||
// in AST and continue parsing.
|
||||
let msg = format!(
|
||||
"`<` is interpreted as a start of generic arguments for `{}`, not a {}",
|
||||
pprust::path_to_string(&path),
|
||||
op_noun,
|
||||
);
|
||||
let span_after_type = parser_snapshot_after_type.token.span;
|
||||
let expr =
|
||||
mk_expr(self, lhs, self.mk_ty(path.span, TyKind::Path(None, path)));
|
||||
|
||||
self.struct_span_err(self.token.span, &msg)
|
||||
.span_label(
|
||||
self.look_ahead(1, |t| t.span).to(span_after_type),
|
||||
"interpreted as generic arguments",
|
||||
)
|
||||
.span_label(self.token.span, format!("not interpreted as {op_noun}"))
|
||||
.multipart_suggestion(
|
||||
&format!("try {op_verb} the cast value"),
|
||||
vec![
|
||||
(expr.span.shrink_to_lo(), "(".to_string()),
|
||||
(expr.span.shrink_to_hi(), ")".to_string()),
|
||||
],
|
||||
Applicability::MachineApplicable,
|
||||
)
|
||||
.emit();
|
||||
|
||||
// Keep `x as usize` as an expression in AST and continue parsing.
|
||||
expr
|
||||
}
|
||||
Err(path_err) => {
|
||||
@ -1208,29 +1208,25 @@ impl<'a> Parser<'a> {
|
||||
let close_paren = self.prev_token.span;
|
||||
let span = lo.to(self.prev_token.span);
|
||||
if !fields.is_empty() {
|
||||
let replacement_err = self.struct_span_err(
|
||||
let mut replacement_err = ParenthesesWithStructFields {
|
||||
span,
|
||||
"invalid `struct` delimiters or `fn` call arguments",
|
||||
);
|
||||
mem::replace(err, replacement_err).cancel();
|
||||
name,
|
||||
braces_for_struct: BracesForStructLiteral {
|
||||
first: open_paren,
|
||||
second: close_paren,
|
||||
},
|
||||
no_fields_for_fn: NoFieldsForFnCall {
|
||||
fields: fields
|
||||
.into_iter()
|
||||
.map(|field| field.span.until(field.expr.span))
|
||||
.collect(),
|
||||
},
|
||||
}
|
||||
.into_diagnostic(&self.sess.span_diagnostic);
|
||||
replacement_err.emit();
|
||||
|
||||
err.multipart_suggestion(
|
||||
&format!("if `{name}` is a struct, use braces as delimiters"),
|
||||
vec![
|
||||
(open_paren, " { ".to_string()),
|
||||
(close_paren, " }".to_string()),
|
||||
],
|
||||
Applicability::MaybeIncorrect,
|
||||
);
|
||||
err.multipart_suggestion(
|
||||
&format!("if `{name}` is a function, use the arguments directly"),
|
||||
fields
|
||||
.into_iter()
|
||||
.map(|field| (field.span.until(field.expr.span), String::new()))
|
||||
.collect(),
|
||||
Applicability::MaybeIncorrect,
|
||||
);
|
||||
err.emit();
|
||||
let old_err = mem::replace(err, replacement_err);
|
||||
old_err.cancel();
|
||||
} else {
|
||||
err.emit();
|
||||
}
|
||||
@ -1537,15 +1533,19 @@ impl<'a> Parser<'a> {
|
||||
&& (self.check_noexpect(&TokenKind::Comma) || self.check_noexpect(&TokenKind::Gt))
|
||||
{
|
||||
// We're probably inside of a `Path<'a>` that needs a turbofish
|
||||
self.sess.emit_err(UnexpectedTokenAfterLabel(self.token.span));
|
||||
self.sess.emit_err(UnexpectedTokenAfterLabel {
|
||||
span: self.token.span,
|
||||
remove_label: None,
|
||||
enclose_in_block: None,
|
||||
});
|
||||
consume_colon = false;
|
||||
Ok(self.mk_expr_err(lo))
|
||||
} else {
|
||||
// FIXME: use UnexpectedTokenAfterLabel, needs multipart suggestions
|
||||
let msg = "expected `while`, `for`, `loop` or `{` after a label";
|
||||
|
||||
let mut err = self.struct_span_err(self.token.span, msg);
|
||||
err.span_label(self.token.span, msg);
|
||||
let mut err = UnexpectedTokenAfterLabel {
|
||||
span: self.token.span,
|
||||
remove_label: None,
|
||||
enclose_in_block: None,
|
||||
};
|
||||
|
||||
// Continue as an expression in an effort to recover on `'label: non_block_expr`.
|
||||
let expr = self.parse_expr().map(|expr| {
|
||||
@ -1572,28 +1572,15 @@ impl<'a> Parser<'a> {
|
||||
// If there are no breaks that may use this label, suggest removing the label and
|
||||
// recover to the unmodified expression.
|
||||
if !found_labeled_breaks {
|
||||
let msg = "consider removing the label";
|
||||
err.span_suggestion_verbose(
|
||||
lo.until(span),
|
||||
msg,
|
||||
"",
|
||||
Applicability::MachineApplicable,
|
||||
);
|
||||
err.remove_label = Some(lo.until(span));
|
||||
|
||||
return expr;
|
||||
}
|
||||
|
||||
let sugg_msg = "consider enclosing expression in a block";
|
||||
let suggestions = vec![
|
||||
(span.shrink_to_lo(), "{ ".to_owned()),
|
||||
(span.shrink_to_hi(), " }".to_owned()),
|
||||
];
|
||||
|
||||
err.multipart_suggestion_verbose(
|
||||
sugg_msg,
|
||||
suggestions,
|
||||
Applicability::MachineApplicable,
|
||||
);
|
||||
err.enclose_in_block = Some(UnexpectedTokenAfterLabelSugg {
|
||||
left: span.shrink_to_lo(),
|
||||
right: span.shrink_to_hi(),
|
||||
});
|
||||
|
||||
// Replace `'label: non_block_expr` with `'label: {non_block_expr}` in order to suppress future errors about `break 'label`.
|
||||
let stmt = self.mk_stmt(span, StmtKind::Expr(expr));
|
||||
@ -1601,7 +1588,7 @@ impl<'a> Parser<'a> {
|
||||
self.mk_expr(span, ExprKind::Block(blk, label))
|
||||
});
|
||||
|
||||
err.emit();
|
||||
self.sess.emit_err(err);
|
||||
expr
|
||||
}?;
|
||||
|
||||
@ -1672,19 +1659,13 @@ impl<'a> Parser<'a> {
|
||||
// The value expression can be a labeled loop, see issue #86948, e.g.:
|
||||
// `loop { break 'label: loop { break 'label 42; }; }`
|
||||
let lexpr = self.parse_labeled_expr(label.take().unwrap(), true)?;
|
||||
self.struct_span_err(
|
||||
lexpr.span,
|
||||
"parentheses are required around this expression to avoid confusion with a labeled break expression",
|
||||
)
|
||||
.multipart_suggestion(
|
||||
"wrap the expression in parentheses",
|
||||
vec![
|
||||
(lexpr.span.shrink_to_lo(), "(".to_string()),
|
||||
(lexpr.span.shrink_to_hi(), ")".to_string()),
|
||||
],
|
||||
Applicability::MachineApplicable,
|
||||
)
|
||||
.emit();
|
||||
self.sess.emit_err(LabeledLoopInBreak {
|
||||
span: lexpr.span,
|
||||
sub: LabeledLoopInBreakSub {
|
||||
first: lexpr.span.shrink_to_lo(),
|
||||
second: lexpr.span.shrink_to_hi(),
|
||||
},
|
||||
});
|
||||
Some(lexpr)
|
||||
} else if self.token != token::OpenDelim(Delimiter::Brace)
|
||||
|| !self.restrictions.contains(Restrictions::NO_STRUCT_LITERAL)
|
||||
@ -1756,9 +1737,8 @@ impl<'a> Parser<'a> {
|
||||
};
|
||||
if let Some(expr) = expr {
|
||||
if matches!(expr.kind, ExprKind::Err) {
|
||||
let mut err = self
|
||||
.diagnostic()
|
||||
.struct_span_err(self.token.span, "invalid interpolated expression");
|
||||
let mut err = InvalidInterpolatedExpression { span: self.token.span }
|
||||
.into_diagnostic(&self.sess.span_diagnostic);
|
||||
err.downgrade_to_delayed_bug();
|
||||
return err;
|
||||
}
|
||||
@ -1790,7 +1770,10 @@ impl<'a> Parser<'a> {
|
||||
});
|
||||
if let Some(token) = &recovered {
|
||||
self.bump();
|
||||
self.error_float_lits_must_have_int_part(&token);
|
||||
self.sess.emit_err(FloatLiteralRequiresIntegerPart {
|
||||
span: token.span,
|
||||
correct: pprust::token_to_string(token).into_owned(),
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@ -1818,13 +1801,6 @@ impl<'a> Parser<'a> {
|
||||
}
|
||||
}
|
||||
|
||||
fn error_float_lits_must_have_int_part(&self, token: &Token) {
|
||||
self.sess.emit_err(FloatLiteralRequiresIntegerPart {
|
||||
span: token.span,
|
||||
correct: pprust::token_to_string(token).into_owned(),
|
||||
});
|
||||
}
|
||||
|
||||
fn report_lit_error(&self, err: LitError, lit: token::Lit, span: Span) {
|
||||
// Checks if `s` looks like i32 or u1234 etc.
|
||||
fn looks_like_width_suffix(first_chars: &[char], s: &str) -> bool {
|
||||
@ -1883,15 +1859,12 @@ impl<'a> Parser<'a> {
|
||||
}
|
||||
}
|
||||
LitError::NonDecimalFloat(base) => {
|
||||
let descr = match base {
|
||||
16 => "hexadecimal",
|
||||
8 => "octal",
|
||||
2 => "binary",
|
||||
match base {
|
||||
16 => self.sess.emit_err(HexadecimalFloatLiteralNotSupported { span }),
|
||||
8 => self.sess.emit_err(OctalFloatLiteralNotSupported { span }),
|
||||
2 => self.sess.emit_err(BinaryFloatLiteralNotSupported { span }),
|
||||
_ => unreachable!(),
|
||||
};
|
||||
self.struct_span_err(span, &format!("{descr} float literal is not supported"))
|
||||
.span_label(span, "not supported")
|
||||
.emit();
|
||||
}
|
||||
LitError::IntTooLarge => {
|
||||
self.sess.emit_err(IntLiteralTooLarge { span });
|
||||
@ -1964,14 +1937,13 @@ impl<'a> Parser<'a> {
|
||||
let mut snapshot = self.create_snapshot_for_diagnostic();
|
||||
match snapshot.parse_array_or_repeat_expr(Delimiter::Brace) {
|
||||
Ok(arr) => {
|
||||
let hi = snapshot.prev_token.span;
|
||||
self.struct_span_err(arr.span, "this is a block expression, not an array")
|
||||
.multipart_suggestion(
|
||||
"to make an array, use square brackets instead of curly braces",
|
||||
vec![(lo, "[".to_owned()), (hi, "]".to_owned())],
|
||||
Applicability::MaybeIncorrect,
|
||||
)
|
||||
.emit();
|
||||
self.sess.emit_err(ArrayBracketsInsteadOfSpaces {
|
||||
span: arr.span,
|
||||
sub: ArrayBracketsInsteadOfSpacesSugg {
|
||||
left: lo,
|
||||
right: snapshot.prev_token.span,
|
||||
},
|
||||
});
|
||||
|
||||
self.restore_snapshot(snapshot);
|
||||
Some(self.mk_expr_err(arr.span))
|
||||
@ -2515,39 +2487,22 @@ impl<'a> Parser<'a> {
|
||||
self.bump(); // `;`
|
||||
let mut stmts =
|
||||
vec![self.mk_stmt(first_expr.span, ast::StmtKind::Expr(first_expr.clone()))];
|
||||
let err = |this: &mut Parser<'_>, stmts: Vec<ast::Stmt>| {
|
||||
let err = |this: &Parser<'_>, stmts: Vec<ast::Stmt>| {
|
||||
let span = stmts[0].span.to(stmts[stmts.len() - 1].span);
|
||||
let mut err = this.struct_span_err(span, "`match` arm body without braces");
|
||||
let (these, s, are) =
|
||||
if stmts.len() > 1 { ("these", "s", "are") } else { ("this", "", "is") };
|
||||
err.span_label(
|
||||
span,
|
||||
&format!(
|
||||
"{these} statement{s} {are} not surrounded by a body",
|
||||
these = these,
|
||||
s = s,
|
||||
are = are
|
||||
),
|
||||
);
|
||||
err.span_label(arrow_span, "while parsing the `match` arm starting here");
|
||||
if stmts.len() > 1 {
|
||||
err.multipart_suggestion(
|
||||
&format!("surround the statement{s} with a body"),
|
||||
vec![
|
||||
(span.shrink_to_lo(), "{ ".to_string()),
|
||||
(span.shrink_to_hi(), " }".to_string()),
|
||||
],
|
||||
Applicability::MachineApplicable,
|
||||
);
|
||||
} else {
|
||||
err.span_suggestion(
|
||||
semi_sp,
|
||||
"use a comma to end a `match` arm expression",
|
||||
",",
|
||||
Applicability::MachineApplicable,
|
||||
);
|
||||
}
|
||||
err.emit();
|
||||
|
||||
this.sess.emit_err(MatchArmBodyWithoutBraces {
|
||||
statements: span,
|
||||
arrow: arrow_span,
|
||||
num_statements: stmts.len(),
|
||||
sub: if stmts.len() > 1 {
|
||||
MatchArmBodyWithoutBracesSugg::AddBraces {
|
||||
left: span.shrink_to_lo(),
|
||||
right: span.shrink_to_hi(),
|
||||
}
|
||||
} else {
|
||||
MatchArmBodyWithoutBracesSugg::UseComma { semicolon: semi_sp }
|
||||
},
|
||||
});
|
||||
this.mk_expr_err(span)
|
||||
};
|
||||
// We might have either a `,` -> `;` typo, or a block without braces. We need
|
||||
@ -2836,23 +2791,19 @@ impl<'a> Parser<'a> {
|
||||
let expr = self.parse_struct_expr(qself.cloned(), path.clone(), true);
|
||||
if let (Ok(expr), false) = (&expr, struct_allowed) {
|
||||
// This is a struct literal, but we don't can't accept them here.
|
||||
self.error_struct_lit_not_allowed_here(path.span, expr.span);
|
||||
self.sess.emit_err(StructLiteralNotAllowedHere {
|
||||
span: expr.span,
|
||||
sub: StructLiteralNotAllowedHereSugg {
|
||||
left: path.span.shrink_to_lo(),
|
||||
right: expr.span.shrink_to_hi(),
|
||||
},
|
||||
});
|
||||
}
|
||||
return Some(expr);
|
||||
}
|
||||
None
|
||||
}
|
||||
|
||||
fn error_struct_lit_not_allowed_here(&self, lo: Span, sp: Span) {
|
||||
self.struct_span_err(sp, "struct literals are not allowed here")
|
||||
.multipart_suggestion(
|
||||
"surround the struct literal with parentheses",
|
||||
vec![(lo.shrink_to_lo(), "(".to_string()), (sp.shrink_to_hi(), ")".to_string())],
|
||||
Applicability::MachineApplicable,
|
||||
)
|
||||
.emit();
|
||||
}
|
||||
|
||||
pub(super) fn parse_struct_fields(
|
||||
&mut self,
|
||||
pth: ast::Path,
|
||||
|
@ -32,7 +32,8 @@ use rustc_ast_pretty::pprust;
|
||||
use rustc_data_structures::fx::FxHashMap;
|
||||
use rustc_errors::PResult;
|
||||
use rustc_errors::{
|
||||
struct_span_err, Applicability, DiagnosticBuilder, ErrorGuaranteed, FatalError, MultiSpan,
|
||||
struct_span_err, Applicability, DiagnosticBuilder, ErrorGuaranteed, FatalError, IntoDiagnostic,
|
||||
MultiSpan,
|
||||
};
|
||||
use rustc_session::parse::ParseSess;
|
||||
use rustc_span::source_map::{Span, DUMMY_SP};
|
||||
@ -41,6 +42,8 @@ use rustc_span::symbol::{kw, sym, Ident, Symbol};
|
||||
use std::ops::Range;
|
||||
use std::{cmp, mem, slice};
|
||||
|
||||
use self::diagnostics::{MismatchedClosingDelimiter, NonStringAbiLiteral};
|
||||
|
||||
bitflags::bitflags! {
|
||||
struct Restrictions: u8 {
|
||||
const STMT_EXPR = 1 << 0;
|
||||
@ -1384,14 +1387,7 @@ impl<'a> Parser<'a> {
|
||||
Err(Some(lit)) => match lit.kind {
|
||||
ast::LitKind::Err => None,
|
||||
_ => {
|
||||
self.struct_span_err(lit.span, "non-string ABI literal")
|
||||
.span_suggestion(
|
||||
lit.span,
|
||||
"specify the ABI with a string literal",
|
||||
"\"C\"",
|
||||
Applicability::MaybeIncorrect,
|
||||
)
|
||||
.emit();
|
||||
self.sess.emit_err(NonStringAbiLiteral { span: lit.span });
|
||||
None
|
||||
}
|
||||
},
|
||||
@ -1432,25 +1428,18 @@ pub(crate) fn make_unclosed_delims_error(
|
||||
// `None` here means an `Eof` was found. We already emit those errors elsewhere, we add them to
|
||||
// `unmatched_braces` only for error recovery in the `Parser`.
|
||||
let found_delim = unmatched.found_delim?;
|
||||
let span: MultiSpan = if let Some(sp) = unmatched.unclosed_span {
|
||||
vec![unmatched.found_span, sp].into()
|
||||
} else {
|
||||
unmatched.found_span.into()
|
||||
};
|
||||
let mut err = sess.span_diagnostic.struct_span_err(
|
||||
span,
|
||||
&format!(
|
||||
"mismatched closing delimiter: `{}`",
|
||||
pprust::token_kind_to_string(&token::CloseDelim(found_delim)),
|
||||
),
|
||||
);
|
||||
err.span_label(unmatched.found_span, "mismatched closing delimiter");
|
||||
if let Some(sp) = unmatched.candidate_span {
|
||||
err.span_label(sp, "closing delimiter possibly meant for this");
|
||||
}
|
||||
let mut spans = vec![unmatched.found_span];
|
||||
if let Some(sp) = unmatched.unclosed_span {
|
||||
err.span_label(sp, "unclosed delimiter");
|
||||
spans.push(sp);
|
||||
};
|
||||
let err = MismatchedClosingDelimiter {
|
||||
spans,
|
||||
delimiter: pprust::token_kind_to_string(&token::CloseDelim(found_delim)).to_string(),
|
||||
unmatched: unmatched.found_span,
|
||||
opening_candidate: unmatched.candidate_span,
|
||||
unclosed: unmatched.unclosed_span,
|
||||
}
|
||||
.into_diagnostic(&sess.span_diagnostic);
|
||||
Some(err)
|
||||
}
|
||||
|
||||
|
@ -29,7 +29,7 @@ fn main() {
|
||||
< //~ ERROR `<` is interpreted as a start of generic
|
||||
5);
|
||||
|
||||
println!("{}", a as usize << long_name); //~ ERROR `<` is interpreted as a start of generic
|
||||
println!("{}", a as usize << long_name); //~ ERROR `<<` is interpreted as a start of generic
|
||||
|
||||
println!("{}", a: &mut 4); //~ ERROR expected type, found `4`
|
||||
}
|
||||
|
@ -95,7 +95,7 @@ LL |
|
||||
LL ~ usize)
|
||||
|
|
||||
|
||||
error: `<` is interpreted as a start of generic arguments for `usize`, not a shift
|
||||
error: `<<` is interpreted as a start of generic arguments for `usize`, not a shift
|
||||
--> $DIR/issue-22644.rs:32:31
|
||||
|
|
||||
LL | println!("{}", a as usize << long_name);
|
||||
|
Loading…
Reference in New Issue
Block a user