Auto merge of #117565 - estebank:issue-100825, r=Nilstrieb
Tweak parsing recovery of enums, for exprs and match arm patterns Tweak recovery of `for (pat in expr) {}` for more accurate spans. When encountering `match` arm `(pat if expr) => {}`, recover and suggest removing parentheses. Fix #100825. When encountering malformed enums, try more localized per-variant parse recovery. Move parser recovery tests to subdirectory.
This commit is contained in:
commit
74fccd0b50
24 changed files with 349 additions and 219 deletions
|
@ -777,6 +777,9 @@ parse_unexpected_lifetime_in_pattern = unexpected lifetime `{$symbol}` in patter
|
||||||
parse_unexpected_parentheses_in_for_head = unexpected parentheses surrounding `for` loop head
|
parse_unexpected_parentheses_in_for_head = unexpected parentheses surrounding `for` loop head
|
||||||
.suggestion = remove parentheses in `for` loop
|
.suggestion = remove parentheses in `for` loop
|
||||||
|
|
||||||
|
parse_unexpected_parentheses_in_match_arm_pattern = unexpected parentheses surrounding `match` arm pattern
|
||||||
|
.suggestion = remove parentheses surrounding the pattern
|
||||||
|
|
||||||
parse_unexpected_self_in_generic_parameters = unexpected keyword `Self` in generic parameters
|
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
|
.note = you cannot use `Self` as a generic parameter because it is reserved for associated items
|
||||||
|
|
||||||
|
|
|
@ -1275,12 +1275,28 @@ pub(crate) struct ParenthesesInForHead {
|
||||||
#[derive(Subdiagnostic)]
|
#[derive(Subdiagnostic)]
|
||||||
#[multipart_suggestion(parse_suggestion, applicability = "machine-applicable")]
|
#[multipart_suggestion(parse_suggestion, applicability = "machine-applicable")]
|
||||||
pub(crate) struct ParenthesesInForHeadSugg {
|
pub(crate) struct ParenthesesInForHeadSugg {
|
||||||
#[suggestion_part(code = "{left_snippet}")]
|
#[suggestion_part(code = " ")]
|
||||||
pub left: Span,
|
pub left: Span,
|
||||||
pub left_snippet: String,
|
#[suggestion_part(code = " ")]
|
||||||
#[suggestion_part(code = "{right_snippet}")]
|
pub right: Span,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Diagnostic)]
|
||||||
|
#[diag(parse_unexpected_parentheses_in_match_arm_pattern)]
|
||||||
|
pub(crate) struct ParenthesesInMatchPat {
|
||||||
|
#[primary_span]
|
||||||
|
pub span: Vec<Span>,
|
||||||
|
#[subdiagnostic]
|
||||||
|
pub sugg: ParenthesesInMatchPatSugg,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Subdiagnostic)]
|
||||||
|
#[multipart_suggestion(parse_suggestion, applicability = "machine-applicable")]
|
||||||
|
pub(crate) struct ParenthesesInMatchPatSugg {
|
||||||
|
#[suggestion_part(code = "")]
|
||||||
|
pub left: Span,
|
||||||
|
#[suggestion_part(code = "")]
|
||||||
pub right: Span,
|
pub right: Span,
|
||||||
pub right_snippet: String,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Diagnostic)]
|
#[derive(Diagnostic)]
|
||||||
|
|
|
@ -11,12 +11,12 @@ use crate::errors::{
|
||||||
DoubleColonInBound, ExpectedIdentifier, ExpectedSemi, ExpectedSemiSugg,
|
DoubleColonInBound, ExpectedIdentifier, ExpectedSemi, ExpectedSemiSugg,
|
||||||
GenericParamsWithoutAngleBrackets, GenericParamsWithoutAngleBracketsSugg,
|
GenericParamsWithoutAngleBrackets, GenericParamsWithoutAngleBracketsSugg,
|
||||||
HelpIdentifierStartsWithNumber, InInTypo, IncorrectAwait, IncorrectSemicolon,
|
HelpIdentifierStartsWithNumber, InInTypo, IncorrectAwait, IncorrectSemicolon,
|
||||||
IncorrectUseOfAwait, ParenthesesInForHead, ParenthesesInForHeadSugg,
|
IncorrectUseOfAwait, PatternMethodParamWithoutBody, QuestionMarkInType, QuestionMarkInTypeSugg,
|
||||||
PatternMethodParamWithoutBody, QuestionMarkInType, QuestionMarkInTypeSugg, SelfParamNotFirst,
|
SelfParamNotFirst, StructLiteralBodyWithoutPath, StructLiteralBodyWithoutPathSugg,
|
||||||
StructLiteralBodyWithoutPath, StructLiteralBodyWithoutPathSugg, StructLiteralNeedingParens,
|
StructLiteralNeedingParens, StructLiteralNeedingParensSugg, SuggAddMissingLetStmt,
|
||||||
StructLiteralNeedingParensSugg, SuggAddMissingLetStmt, SuggEscapeIdentifier, SuggRemoveComma,
|
SuggEscapeIdentifier, SuggRemoveComma, TernaryOperator, UnexpectedConstInGenericParam,
|
||||||
TernaryOperator, UnexpectedConstInGenericParam, UnexpectedConstParamDeclaration,
|
UnexpectedConstParamDeclaration, UnexpectedConstParamDeclarationSugg, UnmatchedAngleBrackets,
|
||||||
UnexpectedConstParamDeclarationSugg, UnmatchedAngleBrackets, UseEqInstead, WrapType,
|
UseEqInstead, WrapType,
|
||||||
};
|
};
|
||||||
|
|
||||||
use crate::fluent_generated as fluent;
|
use crate::fluent_generated as fluent;
|
||||||
|
@ -1994,56 +1994,6 @@ impl<'a> Parser<'a> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Recovers a situation like `for ( $pat in $expr )`
|
|
||||||
/// and suggest writing `for $pat in $expr` instead.
|
|
||||||
///
|
|
||||||
/// This should be called before parsing the `$block`.
|
|
||||||
pub(super) fn recover_parens_around_for_head(
|
|
||||||
&mut self,
|
|
||||||
pat: P<Pat>,
|
|
||||||
begin_paren: Option<Span>,
|
|
||||||
) -> P<Pat> {
|
|
||||||
match (&self.token.kind, begin_paren) {
|
|
||||||
(token::CloseDelim(Delimiter::Parenthesis), Some(begin_par_sp)) => {
|
|
||||||
self.bump();
|
|
||||||
|
|
||||||
let sm = self.sess.source_map();
|
|
||||||
let left = begin_par_sp;
|
|
||||||
let right = self.prev_token.span;
|
|
||||||
let left_snippet = if let Ok(snip) = sm.span_to_prev_source(left)
|
|
||||||
&& !snip.ends_with(' ')
|
|
||||||
{
|
|
||||||
" ".to_string()
|
|
||||||
} else {
|
|
||||||
"".to_string()
|
|
||||||
};
|
|
||||||
|
|
||||||
let right_snippet = if let Ok(snip) = sm.span_to_next_source(right)
|
|
||||||
&& !snip.starts_with(' ')
|
|
||||||
{
|
|
||||||
" ".to_string()
|
|
||||||
} else {
|
|
||||||
"".to_string()
|
|
||||||
};
|
|
||||||
|
|
||||||
self.sess.emit_err(ParenthesesInForHead {
|
|
||||||
span: vec![left, right],
|
|
||||||
// With e.g. `for (x) in y)` this would replace `(x) in y)`
|
|
||||||
// with `x) in y)` which is syntactically invalid.
|
|
||||||
// However, this is prevented before we get here.
|
|
||||||
sugg: ParenthesesInForHeadSugg { left, right, left_snippet, right_snippet },
|
|
||||||
});
|
|
||||||
|
|
||||||
// Unwrap `(pat)` into `pat` to avoid the `unused_parens` lint.
|
|
||||||
pat.and_then(|pat| match pat.kind {
|
|
||||||
PatKind::Paren(pat) => pat,
|
|
||||||
_ => P(pat),
|
|
||||||
})
|
|
||||||
}
|
|
||||||
_ => pat,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub(super) fn recover_seq_parse_error(
|
pub(super) fn recover_seq_parse_error(
|
||||||
&mut self,
|
&mut self,
|
||||||
delim: Delimiter,
|
delim: Delimiter,
|
||||||
|
|
|
@ -10,7 +10,7 @@ use super::{
|
||||||
use crate::errors;
|
use crate::errors;
|
||||||
use crate::maybe_recover_from_interpolated_ty_qpath;
|
use crate::maybe_recover_from_interpolated_ty_qpath;
|
||||||
use ast::mut_visit::{noop_visit_expr, MutVisitor};
|
use ast::mut_visit::{noop_visit_expr, MutVisitor};
|
||||||
use ast::{GenBlockKind, Path, PathSegment};
|
use ast::{GenBlockKind, Pat, Path, PathSegment};
|
||||||
use core::mem;
|
use core::mem;
|
||||||
use rustc_ast::ptr::P;
|
use rustc_ast::ptr::P;
|
||||||
use rustc_ast::token::{self, Delimiter, Token, TokenKind};
|
use rustc_ast::token::{self, Delimiter, Token, TokenKind};
|
||||||
|
@ -2609,30 +2609,72 @@ impl<'a> Parser<'a> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Parses `for <src_pat> in <src_expr> <src_loop_block>` (`for` token already eaten).
|
fn parse_for_head(&mut self) -> PResult<'a, (P<Pat>, P<Expr>)> {
|
||||||
fn parse_expr_for(&mut self, opt_label: Option<Label>, lo: Span) -> PResult<'a, P<Expr>> {
|
let begin_paren = if self.token.kind == token::OpenDelim(Delimiter::Parenthesis) {
|
||||||
// Record whether we are about to parse `for (`.
|
// Record whether we are about to parse `for (`.
|
||||||
// This is used below for recovery in case of `for ( $stuff ) $block`
|
// This is used below for recovery in case of `for ( $stuff ) $block`
|
||||||
// in which case we will suggest `for $stuff $block`.
|
// in which case we will suggest `for $stuff $block`.
|
||||||
let begin_paren = match self.token.kind {
|
let start_span = self.token.span;
|
||||||
token::OpenDelim(Delimiter::Parenthesis) => Some(self.token.span),
|
let left = self.prev_token.span.between(self.look_ahead(1, |t| t.span));
|
||||||
_ => None,
|
Some((start_span, left))
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
};
|
||||||
|
// Try to parse the pattern `for ($PAT) in $EXPR`.
|
||||||
|
let pat = match (
|
||||||
|
self.parse_pat_allow_top_alt(
|
||||||
|
None,
|
||||||
|
RecoverComma::Yes,
|
||||||
|
RecoverColon::Yes,
|
||||||
|
CommaRecoveryMode::LikelyTuple,
|
||||||
|
),
|
||||||
|
begin_paren,
|
||||||
|
) {
|
||||||
|
(Ok(pat), _) => pat, // Happy path.
|
||||||
|
(Err(err), Some((start_span, left))) if self.eat_keyword(kw::In) => {
|
||||||
|
// We know for sure we have seen `for ($SOMETHING in`. In the happy path this would
|
||||||
|
// happen right before the return of this method.
|
||||||
|
let expr = match self.parse_expr_res(Restrictions::NO_STRUCT_LITERAL, None) {
|
||||||
|
Ok(expr) => expr,
|
||||||
|
Err(expr_err) => {
|
||||||
|
// We don't know what followed the `in`, so cancel and bubble up the
|
||||||
|
// original error.
|
||||||
|
expr_err.cancel();
|
||||||
|
return Err(err);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
return if self.token.kind == token::CloseDelim(Delimiter::Parenthesis) {
|
||||||
|
// We know for sure we have seen `for ($SOMETHING in $EXPR)`, so we recover the
|
||||||
|
// parser state and emit a targetted suggestion.
|
||||||
|
let span = vec![start_span, self.token.span];
|
||||||
|
let right = self.prev_token.span.between(self.look_ahead(1, |t| t.span));
|
||||||
|
self.bump(); // )
|
||||||
|
err.cancel();
|
||||||
|
self.sess.emit_err(errors::ParenthesesInForHead {
|
||||||
|
span,
|
||||||
|
// With e.g. `for (x) in y)` this would replace `(x) in y)`
|
||||||
|
// with `x) in y)` which is syntactically invalid.
|
||||||
|
// However, this is prevented before we get here.
|
||||||
|
sugg: errors::ParenthesesInForHeadSugg { left, right },
|
||||||
|
});
|
||||||
|
Ok((self.mk_pat(start_span.to(right), ast::PatKind::Wild), expr))
|
||||||
|
} else {
|
||||||
|
Err(err) // Some other error, bubble up.
|
||||||
|
};
|
||||||
|
}
|
||||||
|
(Err(err), _) => return Err(err), // Some other error, bubble up.
|
||||||
};
|
};
|
||||||
|
|
||||||
let pat = self.parse_pat_allow_top_alt(
|
|
||||||
None,
|
|
||||||
RecoverComma::Yes,
|
|
||||||
RecoverColon::Yes,
|
|
||||||
CommaRecoveryMode::LikelyTuple,
|
|
||||||
)?;
|
|
||||||
if !self.eat_keyword(kw::In) {
|
if !self.eat_keyword(kw::In) {
|
||||||
self.error_missing_in_for_loop();
|
self.error_missing_in_for_loop();
|
||||||
}
|
}
|
||||||
self.check_for_for_in_in_typo(self.prev_token.span);
|
self.check_for_for_in_in_typo(self.prev_token.span);
|
||||||
let expr = self.parse_expr_res(Restrictions::NO_STRUCT_LITERAL, None)?;
|
let expr = self.parse_expr_res(Restrictions::NO_STRUCT_LITERAL, None)?;
|
||||||
|
Ok((pat, expr))
|
||||||
|
}
|
||||||
|
|
||||||
let pat = self.recover_parens_around_for_head(pat, begin_paren);
|
/// Parses `for <src_pat> in <src_expr> <src_loop_block>` (`for` token already eaten).
|
||||||
|
fn parse_expr_for(&mut self, opt_label: Option<Label>, lo: Span) -> PResult<'a, P<Expr>> {
|
||||||
|
let (pat, expr) = self.parse_for_head()?;
|
||||||
// Recover from missing expression in `for` loop
|
// Recover from missing expression in `for` loop
|
||||||
if matches!(expr.kind, ExprKind::Block(..))
|
if matches!(expr.kind, ExprKind::Block(..))
|
||||||
&& !matches!(self.token.kind, token::OpenDelim(Delimiter::Brace))
|
&& !matches!(self.token.kind, token::OpenDelim(Delimiter::Brace))
|
||||||
|
@ -2853,47 +2895,10 @@ impl<'a> Parser<'a> {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(super) fn parse_arm(&mut self) -> PResult<'a, Arm> {
|
pub(super) fn parse_arm(&mut self) -> PResult<'a, Arm> {
|
||||||
// Used to check the `let_chains` and `if_let_guard` features mostly by scanning
|
|
||||||
// `&&` tokens.
|
|
||||||
fn check_let_expr(expr: &Expr) -> (bool, bool) {
|
|
||||||
match &expr.kind {
|
|
||||||
ExprKind::Binary(BinOp { node: BinOpKind::And, .. }, lhs, rhs) => {
|
|
||||||
let lhs_rslt = check_let_expr(lhs);
|
|
||||||
let rhs_rslt = check_let_expr(rhs);
|
|
||||||
(lhs_rslt.0 || rhs_rslt.0, false)
|
|
||||||
}
|
|
||||||
ExprKind::Let(..) => (true, true),
|
|
||||||
_ => (false, true),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
let attrs = self.parse_outer_attributes()?;
|
let attrs = self.parse_outer_attributes()?;
|
||||||
self.collect_tokens_trailing_token(attrs, ForceCollect::No, |this, attrs| {
|
self.collect_tokens_trailing_token(attrs, ForceCollect::No, |this, attrs| {
|
||||||
let lo = this.token.span;
|
let lo = this.token.span;
|
||||||
let pat = this.parse_pat_allow_top_alt(
|
let (pat, guard) = this.parse_match_arm_pat_and_guard()?;
|
||||||
None,
|
|
||||||
RecoverComma::Yes,
|
|
||||||
RecoverColon::Yes,
|
|
||||||
CommaRecoveryMode::EitherTupleOrPipe,
|
|
||||||
)?;
|
|
||||||
let guard = if this.eat_keyword(kw::If) {
|
|
||||||
let if_span = this.prev_token.span;
|
|
||||||
let mut cond = this.parse_match_guard_condition()?;
|
|
||||||
|
|
||||||
CondChecker::new(this).visit_expr(&mut cond);
|
|
||||||
|
|
||||||
let (has_let_expr, does_not_have_bin_op) = check_let_expr(&cond);
|
|
||||||
if has_let_expr {
|
|
||||||
if does_not_have_bin_op {
|
|
||||||
// Remove the last feature gating of a `let` expression since it's stable.
|
|
||||||
this.sess.gated_spans.ungate_last(sym::let_chains, cond.span);
|
|
||||||
}
|
|
||||||
let span = if_span.to(cond.span);
|
|
||||||
this.sess.gated_spans.gate(sym::if_let_guard, span);
|
|
||||||
}
|
|
||||||
Some(cond)
|
|
||||||
} else {
|
|
||||||
None
|
|
||||||
};
|
|
||||||
let arrow_span = this.token.span;
|
let arrow_span = this.token.span;
|
||||||
if let Err(mut err) = this.expect(&token::FatArrow) {
|
if let Err(mut err) = this.expect(&token::FatArrow) {
|
||||||
// We might have a `=>` -> `=` or `->` typo (issue #89396).
|
// We might have a `=>` -> `=` or `->` typo (issue #89396).
|
||||||
|
@ -3023,6 +3028,90 @@ impl<'a> Parser<'a> {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn parse_match_arm_guard(&mut self) -> PResult<'a, Option<P<Expr>>> {
|
||||||
|
// Used to check the `let_chains` and `if_let_guard` features mostly by scanning
|
||||||
|
// `&&` tokens.
|
||||||
|
fn check_let_expr(expr: &Expr) -> (bool, bool) {
|
||||||
|
match &expr.kind {
|
||||||
|
ExprKind::Binary(BinOp { node: BinOpKind::And, .. }, lhs, rhs) => {
|
||||||
|
let lhs_rslt = check_let_expr(lhs);
|
||||||
|
let rhs_rslt = check_let_expr(rhs);
|
||||||
|
(lhs_rslt.0 || rhs_rslt.0, false)
|
||||||
|
}
|
||||||
|
ExprKind::Let(..) => (true, true),
|
||||||
|
_ => (false, true),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if !self.eat_keyword(kw::If) {
|
||||||
|
// No match arm guard present.
|
||||||
|
return Ok(None);
|
||||||
|
}
|
||||||
|
|
||||||
|
let if_span = self.prev_token.span;
|
||||||
|
let mut cond = self.parse_match_guard_condition()?;
|
||||||
|
|
||||||
|
CondChecker::new(self).visit_expr(&mut cond);
|
||||||
|
|
||||||
|
let (has_let_expr, does_not_have_bin_op) = check_let_expr(&cond);
|
||||||
|
if has_let_expr {
|
||||||
|
if does_not_have_bin_op {
|
||||||
|
// Remove the last feature gating of a `let` expression since it's stable.
|
||||||
|
self.sess.gated_spans.ungate_last(sym::let_chains, cond.span);
|
||||||
|
}
|
||||||
|
let span = if_span.to(cond.span);
|
||||||
|
self.sess.gated_spans.gate(sym::if_let_guard, span);
|
||||||
|
}
|
||||||
|
Ok(Some(cond))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn parse_match_arm_pat_and_guard(&mut self) -> PResult<'a, (P<Pat>, Option<P<Expr>>)> {
|
||||||
|
if self.token.kind == token::OpenDelim(Delimiter::Parenthesis) {
|
||||||
|
// Detect and recover from `($pat if $cond) => $arm`.
|
||||||
|
let left = self.token.span;
|
||||||
|
match self.parse_pat_allow_top_alt(
|
||||||
|
None,
|
||||||
|
RecoverComma::Yes,
|
||||||
|
RecoverColon::Yes,
|
||||||
|
CommaRecoveryMode::EitherTupleOrPipe,
|
||||||
|
) {
|
||||||
|
Ok(pat) => Ok((pat, self.parse_match_arm_guard()?)),
|
||||||
|
Err(err)
|
||||||
|
if let prev_sp = self.prev_token.span
|
||||||
|
&& let true = self.eat_keyword(kw::If) =>
|
||||||
|
{
|
||||||
|
// We know for certain we've found `($pat if` so far.
|
||||||
|
let mut cond = match self.parse_match_guard_condition() {
|
||||||
|
Ok(cond) => cond,
|
||||||
|
Err(cond_err) => {
|
||||||
|
cond_err.cancel();
|
||||||
|
return Err(err);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
err.cancel();
|
||||||
|
CondChecker::new(self).visit_expr(&mut cond);
|
||||||
|
self.eat_to_tokens(&[&token::CloseDelim(Delimiter::Parenthesis)]);
|
||||||
|
self.expect(&token::CloseDelim(Delimiter::Parenthesis))?;
|
||||||
|
let right = self.prev_token.span;
|
||||||
|
self.sess.emit_err(errors::ParenthesesInMatchPat {
|
||||||
|
span: vec![left, right],
|
||||||
|
sugg: errors::ParenthesesInMatchPatSugg { left, right },
|
||||||
|
});
|
||||||
|
Ok((self.mk_pat(left.to(prev_sp), ast::PatKind::Wild), Some(cond)))
|
||||||
|
}
|
||||||
|
Err(err) => Err(err),
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// Regular parser flow:
|
||||||
|
let pat = self.parse_pat_allow_top_alt(
|
||||||
|
None,
|
||||||
|
RecoverComma::Yes,
|
||||||
|
RecoverColon::Yes,
|
||||||
|
CommaRecoveryMode::EitherTupleOrPipe,
|
||||||
|
)?;
|
||||||
|
Ok((pat, self.parse_match_arm_guard()?))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn parse_match_guard_condition(&mut self) -> PResult<'a, P<Expr>> {
|
fn parse_match_guard_condition(&mut self) -> PResult<'a, P<Expr>> {
|
||||||
self.parse_expr_res(Restrictions::ALLOW_LET | Restrictions::IN_IF_GUARD, None).map_err(
|
self.parse_expr_res(Restrictions::ALLOW_LET | Restrictions::IN_IF_GUARD, None).map_err(
|
||||||
|mut err| {
|
|mut err| {
|
||||||
|
|
|
@ -1415,8 +1415,8 @@ impl<'a> Parser<'a> {
|
||||||
self.bump();
|
self.bump();
|
||||||
(thin_vec![], false)
|
(thin_vec![], false)
|
||||||
} else {
|
} else {
|
||||||
self.parse_delim_comma_seq(Delimiter::Brace, |p| p.parse_enum_variant()).map_err(
|
self.parse_delim_comma_seq(Delimiter::Brace, |p| p.parse_enum_variant(id.span))
|
||||||
|mut err| {
|
.map_err(|mut err| {
|
||||||
err.span_label(id.span, "while parsing this enum");
|
err.span_label(id.span, "while parsing this enum");
|
||||||
if self.token == token::Colon {
|
if self.token == token::Colon {
|
||||||
let snapshot = self.create_snapshot_for_diagnostic();
|
let snapshot = self.create_snapshot_for_diagnostic();
|
||||||
|
@ -1436,20 +1436,22 @@ impl<'a> Parser<'a> {
|
||||||
}
|
}
|
||||||
self.restore_snapshot(snapshot);
|
self.restore_snapshot(snapshot);
|
||||||
}
|
}
|
||||||
self.recover_stmt();
|
self.eat_to_tokens(&[&token::CloseDelim(Delimiter::Brace)]);
|
||||||
|
self.bump(); // }
|
||||||
err
|
err
|
||||||
},
|
})?
|
||||||
)?
|
|
||||||
};
|
};
|
||||||
|
|
||||||
let enum_definition = EnumDef { variants: variants.into_iter().flatten().collect() };
|
let enum_definition = EnumDef { variants: variants.into_iter().flatten().collect() };
|
||||||
Ok((id, ItemKind::Enum(enum_definition, generics)))
|
Ok((id, ItemKind::Enum(enum_definition, generics)))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn parse_enum_variant(&mut self) -> PResult<'a, Option<Variant>> {
|
fn parse_enum_variant(&mut self, span: Span) -> PResult<'a, Option<Variant>> {
|
||||||
self.recover_diff_marker();
|
self.recover_diff_marker();
|
||||||
let variant_attrs = self.parse_outer_attributes()?;
|
let variant_attrs = self.parse_outer_attributes()?;
|
||||||
self.recover_diff_marker();
|
self.recover_diff_marker();
|
||||||
|
let help = "enum variants can be `Variant`, `Variant = <integer>`, \
|
||||||
|
`Variant(Type, ..., TypeN)` or `Variant { fields: Types }`";
|
||||||
self.collect_tokens_trailing_token(
|
self.collect_tokens_trailing_token(
|
||||||
variant_attrs,
|
variant_attrs,
|
||||||
ForceCollect::No,
|
ForceCollect::No,
|
||||||
|
@ -1476,10 +1478,39 @@ impl<'a> Parser<'a> {
|
||||||
let struct_def = if this.check(&token::OpenDelim(Delimiter::Brace)) {
|
let struct_def = if this.check(&token::OpenDelim(Delimiter::Brace)) {
|
||||||
// Parse a struct variant.
|
// Parse a struct variant.
|
||||||
let (fields, recovered) =
|
let (fields, recovered) =
|
||||||
this.parse_record_struct_body("struct", ident.span, false)?;
|
match this.parse_record_struct_body("struct", ident.span, false) {
|
||||||
|
Ok((fields, recovered)) => (fields, recovered),
|
||||||
|
Err(mut err) => {
|
||||||
|
if this.token == token::Colon {
|
||||||
|
// We handle `enum` to `struct` suggestion in the caller.
|
||||||
|
return Err(err);
|
||||||
|
}
|
||||||
|
this.eat_to_tokens(&[&token::CloseDelim(Delimiter::Brace)]);
|
||||||
|
this.bump(); // }
|
||||||
|
err.span_label(span, "while parsing this enum");
|
||||||
|
err.help(help);
|
||||||
|
err.emit();
|
||||||
|
(thin_vec![], true)
|
||||||
|
}
|
||||||
|
};
|
||||||
VariantData::Struct(fields, recovered)
|
VariantData::Struct(fields, recovered)
|
||||||
} else if this.check(&token::OpenDelim(Delimiter::Parenthesis)) {
|
} else if this.check(&token::OpenDelim(Delimiter::Parenthesis)) {
|
||||||
VariantData::Tuple(this.parse_tuple_struct_body()?, DUMMY_NODE_ID)
|
let body = match this.parse_tuple_struct_body() {
|
||||||
|
Ok(body) => body,
|
||||||
|
Err(mut err) => {
|
||||||
|
if this.token == token::Colon {
|
||||||
|
// We handle `enum` to `struct` suggestion in the caller.
|
||||||
|
return Err(err);
|
||||||
|
}
|
||||||
|
this.eat_to_tokens(&[&token::CloseDelim(Delimiter::Parenthesis)]);
|
||||||
|
this.bump(); // )
|
||||||
|
err.span_label(span, "while parsing this enum");
|
||||||
|
err.help(help);
|
||||||
|
err.emit();
|
||||||
|
thin_vec![]
|
||||||
|
}
|
||||||
|
};
|
||||||
|
VariantData::Tuple(body, DUMMY_NODE_ID)
|
||||||
} else {
|
} else {
|
||||||
VariantData::Unit(DUMMY_NODE_ID)
|
VariantData::Unit(DUMMY_NODE_ID)
|
||||||
};
|
};
|
||||||
|
@ -1500,8 +1531,9 @@ impl<'a> Parser<'a> {
|
||||||
|
|
||||||
Ok((Some(vr), TrailingToken::MaybeComma))
|
Ok((Some(vr), TrailingToken::MaybeComma))
|
||||||
},
|
},
|
||||||
).map_err(|mut err| {
|
)
|
||||||
err.help("enum variants can be `Variant`, `Variant = <integer>`, `Variant(Type, ..., TypeN)` or `Variant { fields: Types }`");
|
.map_err(|mut err| {
|
||||||
|
err.help(help);
|
||||||
err
|
err
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
|
@ -875,6 +875,9 @@ impl<'a> Parser<'a> {
|
||||||
if self.token == token::Colon {
|
if self.token == token::Colon {
|
||||||
// we will try to recover in `maybe_recover_struct_lit_bad_delims`
|
// we will try to recover in `maybe_recover_struct_lit_bad_delims`
|
||||||
return Err(expect_err);
|
return Err(expect_err);
|
||||||
|
} else if let [token::CloseDelim(Delimiter::Parenthesis)] = kets
|
||||||
|
{
|
||||||
|
return Err(expect_err);
|
||||||
} else {
|
} else {
|
||||||
expect_err.emit();
|
expect_err.emit();
|
||||||
break;
|
break;
|
||||||
|
|
|
@ -141,7 +141,19 @@ impl<'a> Parser<'a> {
|
||||||
};
|
};
|
||||||
|
|
||||||
// Parse the first pattern (`p_0`).
|
// Parse the first pattern (`p_0`).
|
||||||
let mut first_pat = self.parse_pat_no_top_alt(expected, syntax_loc)?;
|
let mut first_pat = match self.parse_pat_no_top_alt(expected, syntax_loc) {
|
||||||
|
Ok(pat) => pat,
|
||||||
|
Err(mut err)
|
||||||
|
if self.token.is_reserved_ident()
|
||||||
|
&& !self.token.is_keyword(kw::In)
|
||||||
|
&& !self.token.is_keyword(kw::If) =>
|
||||||
|
{
|
||||||
|
err.emit();
|
||||||
|
self.bump();
|
||||||
|
self.mk_pat(self.token.span, PatKind::Wild)
|
||||||
|
}
|
||||||
|
Err(err) => return Err(err),
|
||||||
|
};
|
||||||
if rc == RecoverComma::Yes {
|
if rc == RecoverComma::Yes {
|
||||||
self.maybe_recover_unexpected_comma(
|
self.maybe_recover_unexpected_comma(
|
||||||
first_pat.span,
|
first_pat.span,
|
||||||
|
@ -379,10 +391,10 @@ impl<'a> Parser<'a> {
|
||||||
self.parse_pat_ident_mut(syntax_loc)?
|
self.parse_pat_ident_mut(syntax_loc)?
|
||||||
} else if self.eat_keyword(kw::Ref) {
|
} else if self.eat_keyword(kw::Ref) {
|
||||||
if self.check_keyword(kw::Box) {
|
if self.check_keyword(kw::Box) {
|
||||||
// Suggest `box ref` and quit parsing pattern to prevent series of
|
// Suggest `box ref`.
|
||||||
// misguided diagnostics from later stages of the compiler.
|
|
||||||
let span = self.prev_token.span.to(self.token.span);
|
let span = self.prev_token.span.to(self.token.span);
|
||||||
return Err(self.sess.create_err(SwitchRefBoxOrder { span }));
|
self.bump();
|
||||||
|
self.sess.emit_err(SwitchRefBoxOrder { span });
|
||||||
}
|
}
|
||||||
// Parse ref ident @ pat / ref mut ident @ pat
|
// Parse ref ident @ pat / ref mut ident @ pat
|
||||||
let mutbl = self.parse_mutability();
|
let mutbl = self.parse_mutability();
|
||||||
|
@ -839,7 +851,7 @@ impl<'a> Parser<'a> {
|
||||||
binding_annotation: BindingAnnotation,
|
binding_annotation: BindingAnnotation,
|
||||||
syntax_loc: Option<PatternLocation>,
|
syntax_loc: Option<PatternLocation>,
|
||||||
) -> PResult<'a, PatKind> {
|
) -> PResult<'a, PatKind> {
|
||||||
let ident = self.parse_ident()?;
|
let ident = self.parse_ident_common(false)?;
|
||||||
|
|
||||||
if self.may_recover()
|
if self.may_recover()
|
||||||
&& !matches!(syntax_loc, Some(PatternLocation::FunctionParameter))
|
&& !matches!(syntax_loc, Some(PatternLocation::FunctionParameter))
|
||||||
|
|
|
@ -24,7 +24,9 @@ error: expected identifier, found reserved identifier `_`
|
||||||
--> $DIR/issue-66706.rs:18:26
|
--> $DIR/issue-66706.rs:18:26
|
||||||
|
|
|
|
||||||
LL | [0; match [|f @ &ref _| () ] {} ]
|
LL | [0; match [|f @ &ref _| () ] {} ]
|
||||||
| ^ expected identifier, found reserved identifier
|
| ----- ^ expected identifier, found reserved identifier
|
||||||
|
| |
|
||||||
|
| while parsing this `match` expression
|
||||||
|
|
||||||
error[E0282]: type annotations needed
|
error[E0282]: type annotations needed
|
||||||
--> $DIR/issue-66706.rs:2:11
|
--> $DIR/issue-66706.rs:2:11
|
||||||
|
|
|
@ -13,6 +13,5 @@ fn main() {
|
||||||
|
|
||||||
// reported by parser
|
// reported by parser
|
||||||
for _x in 1..10 {}
|
for _x in 1..10 {}
|
||||||
//~^ ERROR expected one of
|
//~^ ERROR unexpected parentheses surrounding
|
||||||
//~| ERROR unexpected parentheses surrounding
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,11 +8,10 @@ fn main() {
|
||||||
for(_x)in 1..10 {}
|
for(_x)in 1..10 {}
|
||||||
//~^ ERROR unnecessary parentheses around pattern
|
//~^ ERROR unnecessary parentheses around pattern
|
||||||
|
|
||||||
if(2 == 1){}
|
if(2 == 1) {}
|
||||||
//~^ ERROR unnecessary parentheses around `if` condition
|
//~^ ERROR unnecessary parentheses around `if` condition
|
||||||
|
|
||||||
// reported by parser
|
// reported by parser
|
||||||
for(_x in 1..10){}
|
for(_x in 1..10) {}
|
||||||
//~^ ERROR expected one of
|
//~^ ERROR unexpected parentheses surrounding
|
||||||
//~| ERROR unexpected parentheses surrounding
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,18 +1,12 @@
|
||||||
error: expected one of `)`, `,`, `@`, or `|`, found keyword `in`
|
|
||||||
--> $DIR/issue-103435-extra-parentheses.rs:15:12
|
|
||||||
|
|
|
||||||
LL | for(_x in 1..10){}
|
|
||||||
| ^^ expected one of `)`, `,`, `@`, or `|`
|
|
||||||
|
|
||||||
error: unexpected parentheses surrounding `for` loop head
|
error: unexpected parentheses surrounding `for` loop head
|
||||||
--> $DIR/issue-103435-extra-parentheses.rs:15:8
|
--> $DIR/issue-103435-extra-parentheses.rs:15:8
|
||||||
|
|
|
|
||||||
LL | for(_x in 1..10){}
|
LL | for(_x in 1..10) {}
|
||||||
| ^ ^
|
| ^ ^
|
||||||
|
|
|
|
||||||
help: remove parentheses in `for` loop
|
help: remove parentheses in `for` loop
|
||||||
|
|
|
|
||||||
LL - for(_x in 1..10){}
|
LL - for(_x in 1..10) {}
|
||||||
LL + for _x in 1..10 {}
|
LL + for _x in 1..10 {}
|
||||||
|
|
|
|
||||||
|
|
||||||
|
@ -48,14 +42,14 @@ LL + for _x in 1..10 {}
|
||||||
error: unnecessary parentheses around `if` condition
|
error: unnecessary parentheses around `if` condition
|
||||||
--> $DIR/issue-103435-extra-parentheses.rs:11:7
|
--> $DIR/issue-103435-extra-parentheses.rs:11:7
|
||||||
|
|
|
|
||||||
LL | if(2 == 1){}
|
LL | if(2 == 1) {}
|
||||||
| ^ ^
|
| ^ ^
|
||||||
|
|
|
|
||||||
help: remove these parentheses
|
help: remove these parentheses
|
||||||
|
|
|
|
||||||
LL - if(2 == 1){}
|
LL - if(2 == 1) {}
|
||||||
LL + if 2 == 1 {}
|
LL + if 2 == 1 {}
|
||||||
|
|
|
|
||||||
|
|
||||||
error: aborting due to 5 previous errors
|
error: aborting due to 4 previous errors
|
||||||
|
|
||||||
|
|
|
@ -8,7 +8,11 @@ error: expected one of `)`, `+`, or `,`, found `a`
|
||||||
--> $DIR/issue-68890.rs:1:15
|
--> $DIR/issue-68890.rs:1:15
|
||||||
|
|
|
|
||||||
LL | enum e{A((?'a a+?+l))}
|
LL | enum e{A((?'a a+?+l))}
|
||||||
| ^ expected one of `)`, `+`, or `,`
|
| - ^ expected one of `)`, `+`, or `,`
|
||||||
|
| |
|
||||||
|
| while parsing this enum
|
||||||
|
|
|
||||||
|
= help: enum variants can be `Variant`, `Variant = <integer>`, `Variant(Type, ..., TypeN)` or `Variant { fields: Types }`
|
||||||
|
|
||||||
error: expected item, found `)`
|
error: expected item, found `)`
|
||||||
--> $DIR/issue-68890.rs:1:21
|
--> $DIR/issue-68890.rs:1:21
|
||||||
|
|
|
@ -27,7 +27,7 @@ pub fn main() {
|
||||||
struct r#yield(u8, u8);
|
struct r#yield(u8, u8);
|
||||||
let mut mut yield(become, await) = r#yield(0, 0);
|
let mut mut yield(become, await) = r#yield(0, 0);
|
||||||
//~^ ERROR `mut` on a binding may not be repeated
|
//~^ ERROR `mut` on a binding may not be repeated
|
||||||
//~| ERROR `mut` must be attached to each individual binding
|
//~| ERROR `mut` must be followed by a named binding
|
||||||
//~| ERROR expected identifier, found reserved keyword `yield`
|
//~| ERROR expected identifier, found reserved keyword `yield`
|
||||||
//~| ERROR expected identifier, found reserved keyword `become`
|
//~| ERROR expected identifier, found reserved keyword `become`
|
||||||
//~| ERROR expected identifier, found keyword `await`
|
//~| ERROR expected identifier, found keyword `await`
|
||||||
|
|
|
@ -83,11 +83,11 @@ help: escape `await` to use it as an identifier
|
||||||
LL | let mut mut yield(become, r#await) = r#yield(0, 0);
|
LL | let mut mut yield(become, r#await) = r#yield(0, 0);
|
||||||
| ++
|
| ++
|
||||||
|
|
||||||
error: `mut` must be attached to each individual binding
|
error: `mut` must be followed by a named binding
|
||||||
--> $DIR/mut-patterns.rs:28:9
|
--> $DIR/mut-patterns.rs:28:9
|
||||||
|
|
|
|
||||||
LL | let mut mut yield(become, await) = r#yield(0, 0);
|
LL | let mut mut yield(become, await) = r#yield(0, 0);
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: add `mut` to each binding: `r#yield(mut r#become, mut r#await)`
|
| ^^^^^^^^ help: remove the `mut` prefix
|
||||||
|
|
|
|
||||||
= note: `mut` may be followed by `variable` and `variable @ pattern`
|
= note: `mut` may be followed by `variable` and `variable @ pattern`
|
||||||
|
|
||||||
|
|
|
@ -8,10 +8,12 @@ fn 1234test() {
|
||||||
|
|
||||||
let 23name = 123;
|
let 23name = 123;
|
||||||
//~^ ERROR expected identifier, found `23name`
|
//~^ ERROR expected identifier, found `23name`
|
||||||
|
}
|
||||||
|
fn foo() {
|
||||||
let 2x: i32 = 123;
|
let 2x: i32 = 123;
|
||||||
//~^ ERROR expected identifier, found `2x`
|
//~^ ERROR expected identifier, found `2x`
|
||||||
|
}
|
||||||
|
fn bar() {
|
||||||
let 1x = 123;
|
let 1x = 123;
|
||||||
//~^ ERROR expected identifier, found `1x`
|
//~^ ERROR expected identifier, found `1x`
|
||||||
}
|
}
|
|
@ -1,53 +1,53 @@
|
||||||
error: expected identifier, found `1234test`
|
error: expected identifier, found `1234test`
|
||||||
--> $DIR/issue-104088.rs:1:4
|
--> $DIR/binding-name-starting-with-number.rs:1:4
|
||||||
|
|
|
|
||||||
LL | fn 1234test() {
|
LL | fn 1234test() {
|
||||||
| ^^^^^^^^ expected identifier
|
| ^^^^^^^^ expected identifier
|
||||||
|
|
|
|
||||||
help: identifiers cannot start with a number
|
help: identifiers cannot start with a number
|
||||||
--> $DIR/issue-104088.rs:1:4
|
--> $DIR/binding-name-starting-with-number.rs:1:4
|
||||||
|
|
|
|
||||||
LL | fn 1234test() {
|
LL | fn 1234test() {
|
||||||
| ^^^^
|
| ^^^^
|
||||||
|
|
||||||
error: expected identifier, found `23name`
|
error: expected identifier, found `23name`
|
||||||
--> $DIR/issue-104088.rs:9:9
|
--> $DIR/binding-name-starting-with-number.rs:9:9
|
||||||
|
|
|
|
||||||
LL | let 23name = 123;
|
LL | let 23name = 123;
|
||||||
| ^^^^^^ expected identifier
|
| ^^^^^^ expected identifier
|
||||||
|
|
|
|
||||||
help: identifiers cannot start with a number
|
help: identifiers cannot start with a number
|
||||||
--> $DIR/issue-104088.rs:9:9
|
--> $DIR/binding-name-starting-with-number.rs:9:9
|
||||||
|
|
|
|
||||||
LL | let 23name = 123;
|
LL | let 23name = 123;
|
||||||
| ^^
|
| ^^
|
||||||
|
|
||||||
error: expected identifier, found `2x`
|
error: expected identifier, found `2x`
|
||||||
--> $DIR/issue-104088.rs:12:9
|
--> $DIR/binding-name-starting-with-number.rs:13:9
|
||||||
|
|
|
|
||||||
LL | let 2x: i32 = 123;
|
LL | let 2x: i32 = 123;
|
||||||
| ^^ expected identifier
|
| ^^ expected identifier
|
||||||
|
|
|
|
||||||
help: identifiers cannot start with a number
|
help: identifiers cannot start with a number
|
||||||
--> $DIR/issue-104088.rs:12:9
|
--> $DIR/binding-name-starting-with-number.rs:13:9
|
||||||
|
|
|
|
||||||
LL | let 2x: i32 = 123;
|
LL | let 2x: i32 = 123;
|
||||||
| ^
|
| ^
|
||||||
|
|
||||||
error: expected identifier, found `1x`
|
error: expected identifier, found `1x`
|
||||||
--> $DIR/issue-104088.rs:15:9
|
--> $DIR/binding-name-starting-with-number.rs:17:9
|
||||||
|
|
|
|
||||||
LL | let 1x = 123;
|
LL | let 1x = 123;
|
||||||
| ^^ expected identifier
|
| ^^ expected identifier
|
||||||
|
|
|
|
||||||
help: identifiers cannot start with a number
|
help: identifiers cannot start with a number
|
||||||
--> $DIR/issue-104088.rs:15:9
|
--> $DIR/binding-name-starting-with-number.rs:17:9
|
||||||
|
|
|
|
||||||
LL | let 1x = 123;
|
LL | let 1x = 123;
|
||||||
| ^
|
| ^
|
||||||
|
|
||||||
error[E0308]: mismatched types
|
error[E0308]: mismatched types
|
||||||
--> $DIR/issue-104088.rs:5:12
|
--> $DIR/binding-name-starting-with-number.rs:5:12
|
||||||
|
|
|
|
||||||
LL | if let 2e1 = 123 {
|
LL | if let 2e1 = 123 {
|
||||||
| ^^^ --- this expression has type `{integer}`
|
| ^^^ --- this expression has type `{integer}`
|
|
@ -8,7 +8,7 @@ fn main() {
|
||||||
}
|
}
|
||||||
|
|
||||||
// recover...
|
// recover...
|
||||||
let a = 1;
|
let () = 1; //~ ERROR mismatched types
|
||||||
enum Test2 {
|
enum Test2 {
|
||||||
Fine,
|
Fine,
|
||||||
}
|
}
|
||||||
|
@ -24,5 +24,6 @@ fn main() {
|
||||||
enum Test4 {
|
enum Test4 {
|
||||||
Nope(i32 {}) //~ ERROR: found `{`
|
Nope(i32 {}) //~ ERROR: found `{`
|
||||||
}
|
}
|
||||||
|
let () = 1; //~ ERROR mismatched types
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,8 +9,29 @@ LL | abc: {},
|
||||||
error: expected one of `!`, `(`, `)`, `+`, `,`, `::`, or `<`, found `{`
|
error: expected one of `!`, `(`, `)`, `+`, `,`, `::`, or `<`, found `{`
|
||||||
--> $DIR/recover-enum2.rs:25:22
|
--> $DIR/recover-enum2.rs:25:22
|
||||||
|
|
|
|
||||||
|
LL | enum Test4 {
|
||||||
|
| ----- while parsing this enum
|
||||||
LL | Nope(i32 {})
|
LL | Nope(i32 {})
|
||||||
| ^ expected one of 7 possible tokens
|
| ^ expected one of 7 possible tokens
|
||||||
|
|
|
||||||
|
= help: enum variants can be `Variant`, `Variant = <integer>`, `Variant(Type, ..., TypeN)` or `Variant { fields: Types }`
|
||||||
|
|
||||||
error: aborting due to 2 previous errors
|
error[E0308]: mismatched types
|
||||||
|
--> $DIR/recover-enum2.rs:11:9
|
||||||
|
|
|
||||||
|
LL | let () = 1;
|
||||||
|
| ^^ - this expression has type `{integer}`
|
||||||
|
| |
|
||||||
|
| expected integer, found `()`
|
||||||
|
|
||||||
|
error[E0308]: mismatched types
|
||||||
|
--> $DIR/recover-enum2.rs:27:13
|
||||||
|
|
|
||||||
|
LL | let () = 1;
|
||||||
|
| ^^ - this expression has type `{integer}`
|
||||||
|
| |
|
||||||
|
| expected integer, found `()`
|
||||||
|
|
||||||
|
error: aborting due to 4 previous errors
|
||||||
|
|
||||||
|
For more information about this error, try `rustc --explain E0308`.
|
||||||
|
|
|
@ -0,0 +1,15 @@
|
||||||
|
// run-rustfix
|
||||||
|
// Here we test that the parser is able to recover in a situation like
|
||||||
|
// `for ( $pat in $expr )` since that is familiar syntax in other languages.
|
||||||
|
// Instead we suggest that the user writes `for $pat in $expr`.
|
||||||
|
|
||||||
|
#![deny(unused)] // Make sure we don't trigger `unused_parens`.
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
let vec = vec![1, 2, 3];
|
||||||
|
|
||||||
|
for _elem in vec {
|
||||||
|
//~^ ERROR unexpected parentheses surrounding `for` loop head
|
||||||
|
const _RECOVERY_WITNESS: u32 = 0u32; //~ ERROR mismatched types
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,3 +1,4 @@
|
||||||
|
// run-rustfix
|
||||||
// Here we test that the parser is able to recover in a situation like
|
// Here we test that the parser is able to recover in a situation like
|
||||||
// `for ( $pat in $expr )` since that is familiar syntax in other languages.
|
// `for ( $pat in $expr )` since that is familiar syntax in other languages.
|
||||||
// Instead we suggest that the user writes `for $pat in $expr`.
|
// Instead we suggest that the user writes `for $pat in $expr`.
|
||||||
|
@ -7,9 +8,8 @@
|
||||||
fn main() {
|
fn main() {
|
||||||
let vec = vec![1, 2, 3];
|
let vec = vec![1, 2, 3];
|
||||||
|
|
||||||
for ( elem in vec ) {
|
for ( _elem in vec ) {
|
||||||
//~^ ERROR expected one of `)`, `,`, `@`, or `|`, found keyword `in`
|
//~^ ERROR unexpected parentheses surrounding `for` loop head
|
||||||
//~| ERROR unexpected parentheses surrounding `for` loop head
|
const _RECOVERY_WITNESS: u32 = 0u8; //~ ERROR mismatched types
|
||||||
const RECOVERY_WITNESS: () = 0; //~ ERROR mismatched types
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,27 +1,26 @@
|
||||||
error: expected one of `)`, `,`, `@`, or `|`, found keyword `in`
|
|
||||||
--> $DIR/recover-for-loop-parens-around-head.rs:10:16
|
|
||||||
|
|
|
||||||
LL | for ( elem in vec ) {
|
|
||||||
| ^^ expected one of `)`, `,`, `@`, or `|`
|
|
||||||
|
|
||||||
error: unexpected parentheses surrounding `for` loop head
|
error: unexpected parentheses surrounding `for` loop head
|
||||||
--> $DIR/recover-for-loop-parens-around-head.rs:10:9
|
--> $DIR/recover-for-loop-parens-around-head.rs:11:9
|
||||||
|
|
|
|
||||||
LL | for ( elem in vec ) {
|
LL | for ( _elem in vec ) {
|
||||||
| ^ ^
|
| ^ ^
|
||||||
|
|
|
|
||||||
help: remove parentheses in `for` loop
|
help: remove parentheses in `for` loop
|
||||||
|
|
|
|
||||||
LL - for ( elem in vec ) {
|
LL - for ( _elem in vec ) {
|
||||||
LL + for elem in vec {
|
LL + for _elem in vec {
|
||||||
|
|
|
|
||||||
|
|
||||||
error[E0308]: mismatched types
|
error[E0308]: mismatched types
|
||||||
--> $DIR/recover-for-loop-parens-around-head.rs:13:38
|
--> $DIR/recover-for-loop-parens-around-head.rs:13:40
|
||||||
|
|
|
|
||||||
LL | const RECOVERY_WITNESS: () = 0;
|
LL | const _RECOVERY_WITNESS: u32 = 0u8;
|
||||||
| ^ expected `()`, found integer
|
| ^^^ expected `u32`, found `u8`
|
||||||
|
|
|
||||||
|
help: change the type of the numeric literal from `u8` to `u32`
|
||||||
|
|
|
||||||
|
LL | const _RECOVERY_WITNESS: u32 = 0u32;
|
||||||
|
| ~~~
|
||||||
|
|
||||||
error: aborting due to 3 previous errors
|
error: aborting due to 2 previous errors
|
||||||
|
|
||||||
For more information about this error, try `rustc --explain E0308`.
|
For more information about this error, try `rustc --explain E0308`.
|
||||||
|
|
|
@ -0,0 +1,12 @@
|
||||||
|
// run-rustfix
|
||||||
|
fn main() {
|
||||||
|
let val = 42;
|
||||||
|
let x = match val {
|
||||||
|
0 if true => {
|
||||||
|
//~^ ERROR unexpected parentheses surrounding `match` arm pattern
|
||||||
|
42u8
|
||||||
|
}
|
||||||
|
_ => 0u8,
|
||||||
|
};
|
||||||
|
let _y: u32 = x.into(); //~ ERROR mismatched types
|
||||||
|
}
|
|
@ -1,11 +1,9 @@
|
||||||
|
// run-rustfix
|
||||||
fn main() {
|
fn main() {
|
||||||
let val = 42;
|
let val = 42;
|
||||||
let x = match val {
|
let x = match val {
|
||||||
(0 if true) => {
|
(0 if true) => {
|
||||||
//~^ ERROR expected identifier, found keyword `if`
|
//~^ ERROR unexpected parentheses surrounding `match` arm pattern
|
||||||
//~| ERROR expected one of `)`, `,`, `...`, `..=`, `..`, or `|`, found keyword `if`
|
|
||||||
//~| ERROR expected one of `)`, `,`, `@`, or `|`, found keyword `true`
|
|
||||||
//~| ERROR mismatched types
|
|
||||||
42u8
|
42u8
|
||||||
}
|
}
|
||||||
_ => 0u8,
|
_ => 0u8,
|
||||||
|
|
|
@ -1,38 +1,17 @@
|
||||||
error: expected identifier, found keyword `if`
|
error: unexpected parentheses surrounding `match` arm pattern
|
||||||
--> $DIR/recover-parens-around-match-arm-head.rs:4:12
|
--> $DIR/recover-parens-around-match-arm-head.rs:5:9
|
||||||
|
|
|
|
||||||
LL | (0 if true) => {
|
LL | (0 if true) => {
|
||||||
| ^^ expected identifier, found keyword
|
| ^ ^
|
||||||
|
|
||||||
error: expected one of `)`, `,`, `...`, `..=`, `..`, or `|`, found keyword `if`
|
|
||||||
--> $DIR/recover-parens-around-match-arm-head.rs:4:12
|
|
||||||
|
|
|
|
||||||
LL | (0 if true) => {
|
help: remove parentheses surrounding the pattern
|
||||||
| -^^ expected one of `)`, `,`, `...`, `..=`, `..`, or `|`
|
|
|
||||||
| |
|
LL - (0 if true) => {
|
||||||
| help: missing `,`
|
LL + 0 if true => {
|
||||||
|
|
||||||
error: expected one of `)`, `,`, `@`, or `|`, found keyword `true`
|
|
||||||
--> $DIR/recover-parens-around-match-arm-head.rs:4:15
|
|
||||||
|
|
|
|
||||||
LL | (0 if true) => {
|
|
||||||
| -^^^^ expected one of `)`, `,`, `@`, or `|`
|
|
||||||
| |
|
|
||||||
| help: missing `,`
|
|
||||||
|
|
||||||
error[E0308]: mismatched types
|
error[E0308]: mismatched types
|
||||||
--> $DIR/recover-parens-around-match-arm-head.rs:4:9
|
--> $DIR/recover-parens-around-match-arm-head.rs:11:19
|
||||||
|
|
|
||||||
LL | let x = match val {
|
|
||||||
| --- this expression has type `{integer}`
|
|
||||||
LL | (0 if true) => {
|
|
||||||
| ^^^^^^^^^^^ expected integer, found `(_, _, _)`
|
|
||||||
|
|
|
||||||
= note: expected type `{integer}`
|
|
||||||
found tuple `(_, _, _)`
|
|
||||||
|
|
||||||
error[E0308]: mismatched types
|
|
||||||
--> $DIR/recover-parens-around-match-arm-head.rs:13:19
|
|
||||||
|
|
|
|
||||||
LL | let _y: u32 = x;
|
LL | let _y: u32 = x;
|
||||||
| --- ^ expected `u32`, found `u8`
|
| --- ^ expected `u32`, found `u8`
|
||||||
|
@ -44,6 +23,6 @@ help: you can convert a `u8` to a `u32`
|
||||||
LL | let _y: u32 = x.into();
|
LL | let _y: u32 = x.into();
|
||||||
| +++++++
|
| +++++++
|
||||||
|
|
||||||
error: aborting due to 5 previous errors
|
error: aborting due to 2 previous errors
|
||||||
|
|
||||||
For more information about this error, try `rustc --explain E0308`.
|
For more information about this error, try `rustc --explain E0308`.
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue