diff options
| author | bors <bors@rust-lang.org> | 2023-11-30 02:14:01 +0000 |
|---|---|---|
| committer | bors <bors@rust-lang.org> | 2023-11-30 02:14:01 +0000 |
| commit | 74fccd0b50485d70680156c66229cf0949d08d2c (patch) | |
| tree | b0e074f75a6c77f47f1e7e86b3d9abe6983aa155 | |
| parent | c9c760fc206345d0d7b7b4d989e2d95cd63ce9c0 (diff) | |
| parent | 88453aaccfe308a30a30dc4dee95fe51edc367e0 (diff) | |
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.
24 files changed, 348 insertions, 218 deletions
diff --git a/compiler/rustc_parse/messages.ftl b/compiler/rustc_parse/messages.ftl index eadd2892d93..1c3c433d8b7 100644 --- a/compiler/rustc_parse/messages.ftl +++ b/compiler/rustc_parse/messages.ftl @@ -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 .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 .note = you cannot use `Self` as a generic parameter because it is reserved for associated items diff --git a/compiler/rustc_parse/src/errors.rs b/compiler/rustc_parse/src/errors.rs index e5d4cb6f4da..03e047b297d 100644 --- a/compiler/rustc_parse/src/errors.rs +++ b/compiler/rustc_parse/src/errors.rs @@ -1275,12 +1275,28 @@ pub(crate) struct ParenthesesInForHead { #[derive(Subdiagnostic)] #[multipart_suggestion(parse_suggestion, applicability = "machine-applicable")] pub(crate) struct ParenthesesInForHeadSugg { - #[suggestion_part(code = "{left_snippet}")] + #[suggestion_part(code = " ")] + pub left: Span, + #[suggestion_part(code = " ")] + 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, - pub left_snippet: String, - #[suggestion_part(code = "{right_snippet}")] + #[suggestion_part(code = "")] pub right: Span, - pub right_snippet: String, } #[derive(Diagnostic)] diff --git a/compiler/rustc_parse/src/parser/diagnostics.rs b/compiler/rustc_parse/src/parser/diagnostics.rs index ecb840f067e..8921c1c6a03 100644 --- a/compiler/rustc_parse/src/parser/diagnostics.rs +++ b/compiler/rustc_parse/src/parser/diagnostics.rs @@ -11,12 +11,12 @@ use crate::errors::{ DoubleColonInBound, ExpectedIdentifier, ExpectedSemi, ExpectedSemiSugg, GenericParamsWithoutAngleBrackets, GenericParamsWithoutAngleBracketsSugg, HelpIdentifierStartsWithNumber, InInTypo, IncorrectAwait, IncorrectSemicolon, - IncorrectUseOfAwait, ParenthesesInForHead, ParenthesesInForHeadSugg, - PatternMethodParamWithoutBody, QuestionMarkInType, QuestionMarkInTypeSugg, SelfParamNotFirst, - StructLiteralBodyWithoutPath, StructLiteralBodyWithoutPathSugg, StructLiteralNeedingParens, - StructLiteralNeedingParensSugg, SuggAddMissingLetStmt, SuggEscapeIdentifier, SuggRemoveComma, - TernaryOperator, UnexpectedConstInGenericParam, UnexpectedConstParamDeclaration, - UnexpectedConstParamDeclarationSugg, UnmatchedAngleBrackets, UseEqInstead, WrapType, + IncorrectUseOfAwait, PatternMethodParamWithoutBody, QuestionMarkInType, QuestionMarkInTypeSugg, + SelfParamNotFirst, StructLiteralBodyWithoutPath, StructLiteralBodyWithoutPathSugg, + StructLiteralNeedingParens, StructLiteralNeedingParensSugg, SuggAddMissingLetStmt, + SuggEscapeIdentifier, SuggRemoveComma, TernaryOperator, UnexpectedConstInGenericParam, + UnexpectedConstParamDeclaration, UnexpectedConstParamDeclarationSugg, UnmatchedAngleBrackets, + UseEqInstead, WrapType, }; 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( &mut self, delim: Delimiter, diff --git a/compiler/rustc_parse/src/parser/expr.rs b/compiler/rustc_parse/src/parser/expr.rs index e334837c1d4..b1b77305e4f 100644 --- a/compiler/rustc_parse/src/parser/expr.rs +++ b/compiler/rustc_parse/src/parser/expr.rs @@ -10,7 +10,7 @@ use super::{ use crate::errors; use crate::maybe_recover_from_interpolated_ty_qpath; use ast::mut_visit::{noop_visit_expr, MutVisitor}; -use ast::{GenBlockKind, Path, PathSegment}; +use ast::{GenBlockKind, Pat, Path, PathSegment}; use core::mem; use rustc_ast::ptr::P; 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_expr_for(&mut self, opt_label: Option<Label>, lo: Span) -> PResult<'a, P<Expr>> { - // Record whether we are about to parse `for (`. - // This is used below for recovery in case of `for ( $stuff ) $block` - // in which case we will suggest `for $stuff $block`. - let begin_paren = match self.token.kind { - token::OpenDelim(Delimiter::Parenthesis) => Some(self.token.span), - _ => None, + fn parse_for_head(&mut self) -> PResult<'a, (P<Pat>, P<Expr>)> { + let begin_paren = if self.token.kind == token::OpenDelim(Delimiter::Parenthesis) { + // Record whether we are about to parse `for (`. + // This is used below for recovery in case of `for ( $stuff ) $block` + // in which case we will suggest `for $stuff $block`. + let start_span = self.token.span; + let left = self.prev_token.span.between(self.look_ahead(1, |t| t.span)); + 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) { self.error_missing_in_for_loop(); } self.check_for_for_in_in_typo(self.prev_token.span); 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 if matches!(expr.kind, ExprKind::Block(..)) && !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> { - // 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()?; self.collect_tokens_trailing_token(attrs, ForceCollect::No, |this, attrs| { let lo = this.token.span; - let pat = this.parse_pat_allow_top_alt( - 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 (pat, guard) = this.parse_match_arm_pat_and_guard()?; let arrow_span = this.token.span; if let Err(mut err) = this.expect(&token::FatArrow) { // 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>> { self.parse_expr_res(Restrictions::ALLOW_LET | Restrictions::IN_IF_GUARD, None).map_err( |mut err| { diff --git a/compiler/rustc_parse/src/parser/item.rs b/compiler/rustc_parse/src/parser/item.rs index 23886b1208b..ab18e40482e 100644 --- a/compiler/rustc_parse/src/parser/item.rs +++ b/compiler/rustc_parse/src/parser/item.rs @@ -1415,8 +1415,8 @@ impl<'a> Parser<'a> { self.bump(); (thin_vec![], false) } else { - self.parse_delim_comma_seq(Delimiter::Brace, |p| p.parse_enum_variant()).map_err( - |mut err| { + self.parse_delim_comma_seq(Delimiter::Brace, |p| p.parse_enum_variant(id.span)) + .map_err(|mut err| { err.span_label(id.span, "while parsing this enum"); if self.token == token::Colon { let snapshot = self.create_snapshot_for_diagnostic(); @@ -1436,20 +1436,22 @@ impl<'a> Parser<'a> { } self.restore_snapshot(snapshot); } - self.recover_stmt(); + self.eat_to_tokens(&[&token::CloseDelim(Delimiter::Brace)]); + self.bump(); // } err - }, - )? + })? }; let enum_definition = EnumDef { variants: variants.into_iter().flatten().collect() }; 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(); let variant_attrs = self.parse_outer_attributes()?; 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( variant_attrs, ForceCollect::No, @@ -1476,10 +1478,39 @@ impl<'a> Parser<'a> { let struct_def = if this.check(&token::OpenDelim(Delimiter::Brace)) { // Parse a struct variant. 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) } 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 { VariantData::Unit(DUMMY_NODE_ID) }; @@ -1500,8 +1531,9 @@ impl<'a> Parser<'a> { 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 }) } diff --git a/compiler/rustc_parse/src/parser/mod.rs b/compiler/rustc_parse/src/parser/mod.rs index 9bd436f01ac..c680a950584 100644 --- a/compiler/rustc_parse/src/parser/mod.rs +++ b/compiler/rustc_parse/src/parser/mod.rs @@ -875,6 +875,9 @@ impl<'a> Parser<'a> { if self.token == token::Colon { // we will try to recover in `maybe_recover_struct_lit_bad_delims` return Err(expect_err); + } else if let [token::CloseDelim(Delimiter::Parenthesis)] = kets + { + return Err(expect_err); } else { expect_err.emit(); break; diff --git a/compiler/rustc_parse/src/parser/pat.rs b/compiler/rustc_parse/src/parser/pat.rs index b05868e235a..3d1d1ec8108 100644 --- a/compiler/rustc_parse/src/parser/pat.rs +++ b/compiler/rustc_parse/src/parser/pat.rs @@ -141,7 +141,19 @@ impl<'a> Parser<'a> { }; // 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 { self.maybe_recover_unexpected_comma( first_pat.span, @@ -379,10 +391,10 @@ impl<'a> Parser<'a> { self.parse_pat_ident_mut(syntax_loc)? } else if self.eat_keyword(kw::Ref) { if self.check_keyword(kw::Box) { - // Suggest `box ref` and quit parsing pattern to prevent series of - // misguided diagnostics from later stages of the compiler. + // Suggest `box ref`. 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 let mutbl = self.parse_mutability(); @@ -839,7 +851,7 @@ impl<'a> Parser<'a> { binding_annotation: BindingAnnotation, syntax_loc: Option<PatternLocation>, ) -> PResult<'a, PatKind> { - let ident = self.parse_ident()?; + let ident = self.parse_ident_common(false)?; if self.may_recover() && !matches!(syntax_loc, Some(PatternLocation::FunctionParameter)) diff --git a/tests/ui/issues/issue-66706.stderr b/tests/ui/issues/issue-66706.stderr index 8a30c0cad39..ffdd61e7723 100644 --- a/tests/ui/issues/issue-66706.stderr +++ b/tests/ui/issues/issue-66706.stderr @@ -24,7 +24,9 @@ error: expected identifier, found reserved identifier `_` --> $DIR/issue-66706.rs:18:26 | 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 --> $DIR/issue-66706.rs:2:11 diff --git a/tests/ui/lint/issue-103435-extra-parentheses.fixed b/tests/ui/lint/issue-103435-extra-parentheses.fixed index 2b01b414baa..74b5aa06e35 100644 --- a/tests/ui/lint/issue-103435-extra-parentheses.fixed +++ b/tests/ui/lint/issue-103435-extra-parentheses.fixed @@ -13,6 +13,5 @@ fn main() { // reported by parser for _x in 1..10 {} - //~^ ERROR expected one of - //~| ERROR unexpected parentheses surrounding + //~^ ERROR unexpected parentheses surrounding } diff --git a/tests/ui/lint/issue-103435-extra-parentheses.rs b/tests/ui/lint/issue-103435-extra-parentheses.rs index 8261610cf56..cc81a64f217 100644 --- a/tests/ui/lint/issue-103435-extra-parentheses.rs +++ b/tests/ui/lint/issue-103435-extra-parentheses.rs @@ -8,11 +8,10 @@ fn main() { for(_x)in 1..10 {} //~^ ERROR unnecessary parentheses around pattern - if(2 == 1){} + if(2 == 1) {} //~^ ERROR unnecessary parentheses around `if` condition // reported by parser - for(_x in 1..10){} - //~^ ERROR expected one of - //~| ERROR unexpected parentheses surrounding + for(_x in 1..10) {} + //~^ ERROR unexpected parentheses surrounding } diff --git a/tests/ui/lint/issue-103435-extra-parentheses.stderr b/tests/ui/lint/issue-103435-extra-parentheses.stderr index 29c41c91050..5a166eb5008 100644 --- a/tests/ui/lint/issue-103435-extra-parentheses.stderr +++ b/tests/ui/lint/issue-103435-extra-parentheses.stderr @@ -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 --> $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 | -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 --> $DIR/issue-103435-extra-parentheses.rs:11:7 | -LL | if(2 == 1){} +LL | if(2 == 1) {} | ^ ^ | help: remove these parentheses | -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 diff --git a/tests/ui/parser/issues/issue-68890.stderr b/tests/ui/parser/issues/issue-68890.stderr index 0d7b53a67c5..43ed69dcf24 100644 --- a/tests/ui/parser/issues/issue-68890.stderr +++ b/tests/ui/parser/issues/issue-68890.stderr @@ -8,7 +8,11 @@ error: expected one of `)`, `+`, or `,`, found `a` --> $DIR/issue-68890.rs:1:15 | 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 `)` --> $DIR/issue-68890.rs:1:21 diff --git a/tests/ui/parser/mut-patterns.rs b/tests/ui/parser/mut-patterns.rs index 8b83d6ab2f8..f2d2df0af29 100644 --- a/tests/ui/parser/mut-patterns.rs +++ b/tests/ui/parser/mut-patterns.rs @@ -27,7 +27,7 @@ pub fn main() { struct r#yield(u8, u8); let mut mut yield(become, await) = r#yield(0, 0); //~^ 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 `become` //~| ERROR expected identifier, found keyword `await` diff --git a/tests/ui/parser/mut-patterns.stderr b/tests/ui/parser/mut-patterns.stderr index 66985c9f5e4..6559cf09cdf 100644 --- a/tests/ui/parser/mut-patterns.stderr +++ b/tests/ui/parser/mut-patterns.stderr @@ -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); | ++ -error: `mut` must be attached to each individual binding +error: `mut` must be followed by a named binding --> $DIR/mut-patterns.rs:28:9 | 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` diff --git a/tests/ui/parser/issues/issue-104088.rs b/tests/ui/parser/recover/binding-name-starting-with-number.rs index 3dc636b6a33..6b279c5539e 100644 --- a/tests/ui/parser/issues/issue-104088.rs +++ b/tests/ui/parser/recover/binding-name-starting-with-number.rs @@ -8,10 +8,12 @@ fn 1234test() { let 23name = 123; //~^ ERROR expected identifier, found `23name` - +} +fn foo() { let 2x: i32 = 123; //~^ ERROR expected identifier, found `2x` - +} +fn bar() { let 1x = 123; //~^ ERROR expected identifier, found `1x` } diff --git a/tests/ui/parser/issues/issue-104088.stderr b/tests/ui/parser/recover/binding-name-starting-with-number.stderr index 8b751759d69..de59a7de043 100644 --- a/tests/ui/parser/issues/issue-104088.stderr +++ b/tests/ui/parser/recover/binding-name-starting-with-number.stderr @@ -1,53 +1,53 @@ error: expected identifier, found `1234test` - --> $DIR/issue-104088.rs:1:4 + --> $DIR/binding-name-starting-with-number.rs:1:4 | LL | fn 1234test() { | ^^^^^^^^ expected identifier | 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() { | ^^^^ error: expected identifier, found `23name` - --> $DIR/issue-104088.rs:9:9 + --> $DIR/binding-name-starting-with-number.rs:9:9 | LL | let 23name = 123; | ^^^^^^ expected identifier | 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; | ^^ 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; | ^^ expected identifier | 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; | ^ error: expected identifier, found `1x` - --> $DIR/issue-104088.rs:15:9 + --> $DIR/binding-name-starting-with-number.rs:17:9 | LL | let 1x = 123; | ^^ expected identifier | 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; | ^ error[E0308]: mismatched types - --> $DIR/issue-104088.rs:5:12 + --> $DIR/binding-name-starting-with-number.rs:5:12 | LL | if let 2e1 = 123 { | ^^^ --- this expression has type `{integer}` diff --git a/tests/ui/parser/recover/recover-enum2.rs b/tests/ui/parser/recover/recover-enum2.rs index 0c942088955..56b57f625ba 100644 --- a/tests/ui/parser/recover/recover-enum2.rs +++ b/tests/ui/parser/recover/recover-enum2.rs @@ -8,7 +8,7 @@ fn main() { } // recover... - let a = 1; + let () = 1; //~ ERROR mismatched types enum Test2 { Fine, } @@ -24,5 +24,6 @@ fn main() { enum Test4 { Nope(i32 {}) //~ ERROR: found `{` } + let () = 1; //~ ERROR mismatched types } } diff --git a/tests/ui/parser/recover/recover-enum2.stderr b/tests/ui/parser/recover/recover-enum2.stderr index 7634bca921c..132f84cc76b 100644 --- a/tests/ui/parser/recover/recover-enum2.stderr +++ b/tests/ui/parser/recover/recover-enum2.stderr @@ -9,8 +9,29 @@ LL | abc: {}, error: expected one of `!`, `(`, `)`, `+`, `,`, `::`, or `<`, found `{` --> $DIR/recover-enum2.rs:25:22 | +LL | enum Test4 { + | ----- while parsing this enum LL | Nope(i32 {}) | ^ expected one of 7 possible tokens + | + = help: enum variants can be `Variant`, `Variant = <integer>`, `Variant(Type, ..., TypeN)` or `Variant { fields: Types }` + +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 2 previous errors +error: aborting due to 4 previous errors +For more information about this error, try `rustc --explain E0308`. diff --git a/tests/ui/parser/recover/recover-for-loop-parens-around-head.fixed b/tests/ui/parser/recover/recover-for-loop-parens-around-head.fixed new file mode 100644 index 00000000000..6afc2d99355 --- /dev/null +++ b/tests/ui/parser/recover/recover-for-loop-parens-around-head.fixed @@ -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 + } +} diff --git a/tests/ui/parser/recover/recover-for-loop-parens-around-head.rs b/tests/ui/parser/recover/recover-for-loop-parens-around-head.rs index 053b428bd12..b1716900c49 100644 --- a/tests/ui/parser/recover/recover-for-loop-parens-around-head.rs +++ b/tests/ui/parser/recover/recover-for-loop-parens-around-head.rs @@ -1,3 +1,4 @@ +// 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`. @@ -7,9 +8,8 @@ fn main() { let vec = vec![1, 2, 3]; - for ( elem in vec ) { - //~^ ERROR expected one of `)`, `,`, `@`, or `|`, found keyword `in` - //~| ERROR unexpected parentheses surrounding `for` loop head - const RECOVERY_WITNESS: () = 0; //~ ERROR mismatched types + for ( _elem in vec ) { + //~^ ERROR unexpected parentheses surrounding `for` loop head + const _RECOVERY_WITNESS: u32 = 0u8; //~ ERROR mismatched types } } diff --git a/tests/ui/parser/recover/recover-for-loop-parens-around-head.stderr b/tests/ui/parser/recover/recover-for-loop-parens-around-head.stderr index 3bad29f20af..beaa346e76c 100644 --- a/tests/ui/parser/recover/recover-for-loop-parens-around-head.stderr +++ b/tests/ui/parser/recover/recover-for-loop-parens-around-head.stderr @@ -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 - --> $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 | -LL - for ( elem in vec ) { -LL + for elem in vec { +LL - for ( _elem in vec ) { +LL + for _elem in vec { | 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: u32 = 0u8; + | ^^^ expected `u32`, found `u8` + | +help: change the type of the numeric literal from `u8` to `u32` | -LL | const RECOVERY_WITNESS: () = 0; - | ^ expected `()`, found integer +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`. diff --git a/tests/ui/parser/recover/recover-parens-around-match-arm-head.fixed b/tests/ui/parser/recover/recover-parens-around-match-arm-head.fixed new file mode 100644 index 00000000000..6b9b7fa882a --- /dev/null +++ b/tests/ui/parser/recover/recover-parens-around-match-arm-head.fixed @@ -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 +} diff --git a/tests/ui/parser/recover/recover-parens-around-match-arm-head.rs b/tests/ui/parser/recover/recover-parens-around-match-arm-head.rs index 9ed733bf079..f523581e2da 100644 --- a/tests/ui/parser/recover/recover-parens-around-match-arm-head.rs +++ b/tests/ui/parser/recover/recover-parens-around-match-arm-head.rs @@ -1,11 +1,9 @@ +// run-rustfix fn main() { let val = 42; let x = match val { (0 if true) => { - //~^ ERROR expected identifier, found keyword `if` - //~| ERROR expected one of `)`, `,`, `...`, `..=`, `..`, or `|`, found keyword `if` - //~| ERROR expected one of `)`, `,`, `@`, or `|`, found keyword `true` - //~| ERROR mismatched types + //~^ ERROR unexpected parentheses surrounding `match` arm pattern 42u8 } _ => 0u8, diff --git a/tests/ui/parser/recover/recover-parens-around-match-arm-head.stderr b/tests/ui/parser/recover/recover-parens-around-match-arm-head.stderr index 6542f440e4b..bad4d7d2f19 100644 --- a/tests/ui/parser/recover/recover-parens-around-match-arm-head.stderr +++ b/tests/ui/parser/recover/recover-parens-around-match-arm-head.stderr @@ -1,38 +1,17 @@ -error: expected identifier, found keyword `if` - --> $DIR/recover-parens-around-match-arm-head.rs:4:12 +error: unexpected parentheses surrounding `match` arm pattern + --> $DIR/recover-parens-around-match-arm-head.rs:5:9 | 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) => { - | -^^ expected one of `)`, `,`, `...`, `..=`, `..`, or `|` - | | - | help: missing `,` - -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 - --> $DIR/recover-parens-around-match-arm-head.rs:4:9 +help: remove parentheses surrounding the pattern | -LL | let x = match val { - | --- this expression has type `{integer}` -LL | (0 if true) => { - | ^^^^^^^^^^^ expected integer, found `(_, _, _)` +LL - (0 if true) => { +LL + 0 if true => { | - = note: expected type `{integer}` - found tuple `(_, _, _)` error[E0308]: mismatched types - --> $DIR/recover-parens-around-match-arm-head.rs:13:19 + --> $DIR/recover-parens-around-match-arm-head.rs:11:19 | LL | let _y: u32 = x; | --- ^ expected `u32`, found `u8` @@ -44,6 +23,6 @@ help: you can convert a `u8` to a `u32` 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`. |
