From c2047219b59ac7830c4315653858f28cf0d57b9d Mon Sep 17 00:00:00 2001 From: Lieselotte <52315535+she3py@users.noreply.github.com> Date: Thu, 4 Jul 2024 14:10:17 +0200 Subject: [PATCH 1/2] Recover more expressions in patterns --- compiler/rustc_parse/messages.ftl | 10 +- compiler/rustc_parse/src/errors.rs | 2 - compiler/rustc_parse/src/parser/expr.rs | 4 +- compiler/rustc_parse/src/parser/pat.rs | 143 ++++++---- tests/ui/parser/bad-name.rs | 5 +- tests/ui/parser/bad-name.stderr | 20 +- tests/ui/parser/pat-recover-exprs.rs | 28 -- tests/ui/parser/pat-recover-exprs.stderr | 76 ----- tests/ui/parser/pat-recover-methodcalls.rs | 37 --- .../ui/parser/pat-recover-methodcalls.stderr | 35 --- tests/ui/parser/recover/recover-pat-exprs.rs | 98 +++++++ .../parser/recover/recover-pat-exprs.stderr | 259 ++++++++++++++++++ tests/ui/parser/recover/recover-pat-issues.rs | 46 ++++ .../parser/recover/recover-pat-issues.stderr | 38 +++ tests/ui/parser/recover/recover-pat-lets.rs | 20 ++ .../ui/parser/recover/recover-pat-lets.stderr | 32 +++ .../recover-pat-ranges.rs} | 4 +- .../recover-pat-ranges.stderr} | 36 +-- .../recover-pat-wildcards.rs} | 0 .../recover-pat-wildcards.stderr} | 22 +- 20 files changed, 633 insertions(+), 282 deletions(-) delete mode 100644 tests/ui/parser/pat-recover-exprs.rs delete mode 100644 tests/ui/parser/pat-recover-exprs.stderr delete mode 100644 tests/ui/parser/pat-recover-methodcalls.rs delete mode 100644 tests/ui/parser/pat-recover-methodcalls.stderr create mode 100644 tests/ui/parser/recover/recover-pat-exprs.rs create mode 100644 tests/ui/parser/recover/recover-pat-exprs.stderr create mode 100644 tests/ui/parser/recover/recover-pat-issues.rs create mode 100644 tests/ui/parser/recover/recover-pat-issues.stderr create mode 100644 tests/ui/parser/recover/recover-pat-lets.rs create mode 100644 tests/ui/parser/recover/recover-pat-lets.stderr rename tests/ui/parser/{pat-recover-ranges.rs => recover/recover-pat-ranges.rs} (89%) rename tests/ui/parser/{pat-recover-ranges.stderr => recover/recover-pat-ranges.stderr} (77%) rename tests/ui/parser/{pat-recover-wildcards.rs => recover/recover-pat-wildcards.rs} (100%) rename tests/ui/parser/{pat-recover-wildcards.stderr => recover/recover-pat-wildcards.stderr} (80%) diff --git a/compiler/rustc_parse/messages.ftl b/compiler/rustc_parse/messages.ftl index ec9a676ea3135..3d0ce77bc47a9 100644 --- a/compiler/rustc_parse/messages.ftl +++ b/compiler/rustc_parse/messages.ftl @@ -803,15 +803,9 @@ parse_unexpected_expr_in_pat = expected {$is_bound -> [true] a pattern range bound *[false] a pattern - }, found {$is_method_call -> - [true] a method call - *[false] an expression - } + }, found an expression - .label = {$is_method_call -> - [true] method calls - *[false] arbitrary expressions - } are not allowed in patterns + .label = arbitrary expressions are not allowed in patterns parse_unexpected_if_with_if = unexpected `if` in the condition expression .suggestion = remove the `if` diff --git a/compiler/rustc_parse/src/errors.rs b/compiler/rustc_parse/src/errors.rs index da1103a4fe5dc..a91aa1f501895 100644 --- a/compiler/rustc_parse/src/errors.rs +++ b/compiler/rustc_parse/src/errors.rs @@ -2597,8 +2597,6 @@ pub(crate) struct UnexpectedExpressionInPattern { pub span: Span, /// Was a `RangePatternBound` expected? pub is_bound: bool, - /// Was the unexpected expression a `MethodCallExpression`? - pub is_method_call: bool, } #[derive(Diagnostic)] diff --git a/compiler/rustc_parse/src/parser/expr.rs b/compiler/rustc_parse/src/parser/expr.rs index 2d5a1914fa68a..f19cba4c1bf59 100644 --- a/compiler/rustc_parse/src/parser/expr.rs +++ b/compiler/rustc_parse/src/parser/expr.rs @@ -41,7 +41,7 @@ use super::{ use crate::{errors, maybe_recover_from_interpolated_ty_qpath}; #[derive(Debug)] -enum DestructuredFloat { +pub(super) enum DestructuredFloat { /// 1e2 Single(Symbol, Span), /// 1. @@ -1041,7 +1041,7 @@ impl<'a> Parser<'a> { // support pushing "future tokens" (would be also helpful to `break_and_eat`), or // we should break everything including floats into more basic proc-macro style // tokens in the lexer (probably preferable). - fn break_up_float(&self, float: Symbol, span: Span) -> DestructuredFloat { + pub(super) fn break_up_float(&self, float: Symbol, span: Span) -> DestructuredFloat { #[derive(Debug)] enum FloatComponent { IdentLike(String), diff --git a/compiler/rustc_parse/src/parser/pat.rs b/compiler/rustc_parse/src/parser/pat.rs index daced411b8fe2..94c01f7e0d4a7 100644 --- a/compiler/rustc_parse/src/parser/pat.rs +++ b/compiler/rustc_parse/src/parser/pat.rs @@ -25,7 +25,7 @@ use crate::errors::{ UnexpectedParenInRangePat, UnexpectedParenInRangePatSugg, UnexpectedVertVertBeforeFunctionParam, UnexpectedVertVertInPattern, WrapInParens, }; -use crate::parser::expr::could_be_unclosed_char_literal; +use crate::parser::expr::{could_be_unclosed_char_literal, DestructuredFloat}; use crate::{maybe_recover_from_interpolated_ty_qpath, maybe_whole}; #[derive(PartialEq, Copy, Clone)] @@ -342,7 +342,7 @@ impl<'a> Parser<'a> { } } - /// Ensures that the last parsed pattern (or pattern range bound) is not followed by a method call or an operator. + /// Ensures that the last parsed pattern (or pattern range bound) is not followed by an expression. /// /// `is_end_bound` indicates whether the last parsed thing was the end bound of a range pattern (see [`parse_pat_range_end`](Self::parse_pat_range_end)) /// in order to say "expected a pattern range bound" instead of "expected a pattern"; @@ -350,38 +350,64 @@ impl<'a> Parser<'a> { /// 0..=1 + 2 /// ^^^^^ /// ``` - /// Only the end bound is spanned, and this function have no idea if there were a `..=` before `pat_span`, hence the parameter. + /// Only the end bound is spanned in this case, and this function has no idea if there was a `..=` before `pat_span`, hence the parameter. + /// + /// This function returns `Some` if a trailing expression was recovered, and said expression's span. #[must_use = "the pattern must be discarded as `PatKind::Err` if this function returns Some"] fn maybe_recover_trailing_expr( &mut self, pat_span: Span, is_end_bound: bool, - ) -> Option { + ) -> Option<(ErrorGuaranteed, Span)> { if self.prev_token.is_keyword(kw::Underscore) || !self.may_recover() { // Don't recover anything after an `_` or if recovery is disabled. return None; } - // Check for `.hello()`, but allow `.Hello()` to be recovered as `, Hello()` in `parse_seq_to_before_tokens()`. - let has_trailing_method = self.check_noexpect(&token::Dot) + // Returns `true` iff `token` is an unsuffixed integer. + let is_one_tuple_index = |_: &Self, token: &Token| -> bool { + use token::{Lit, LitKind}; + + matches!( + token.kind, + token::Literal(Lit { kind: LitKind::Integer, symbol: _, suffix: None }) + ) + }; + + // Returns `true` iff `token` is an unsuffixed `x.y` float. + let is_two_tuple_indexes = |this: &Self, token: &Token| -> bool { + use token::{Lit, LitKind}; + + if let token::Literal(Lit { kind: LitKind::Float, symbol, suffix: None }) = token.kind + && let DestructuredFloat::MiddleDot(..) = this.break_up_float(symbol, token.span) + { + true + } else { + false + } + }; + + // Check for `.hello` or `.0`. + let has_dot_expr = self.check_noexpect(&token::Dot) // `.` && self.look_ahead(1, |tok| { - tok.ident() - .and_then(|(ident, _)| ident.name.as_str().chars().next()) - .is_some_and(char::is_lowercase) - }) - && self.look_ahead(2, |t| *t == token::OpenDelim(Delimiter::Parenthesis)); + tok.is_ident() // `hello` + || is_one_tuple_index(&self, &tok) // `0` + || is_two_tuple_indexes(&self, &tok) // `0.0` + }); // Check for operators. // `|` is excluded as it is used in pattern alternatives and lambdas, // `?` is included for error propagation, // `[` is included for indexing operations, - // `[]` is excluded as `a[]` isn't an expression and should be recovered as `a, []` (cf. `tests/ui/parser/pat-lt-bracket-7.rs`) + // `[]` is excluded as `a[]` isn't an expression and should be recovered as `a, []` (cf. `tests/ui/parser/pat-lt-bracket-7.rs`), + // `as` is included for type casts let has_trailing_operator = matches!(self.token.kind, token::BinOp(op) if op != BinOpToken::Or) || self.token == token::Question || (self.token == token::OpenDelim(Delimiter::Bracket) - && self.look_ahead(1, |t| *t != token::CloseDelim(Delimiter::Bracket))); + && self.look_ahead(1, |t| *t != token::CloseDelim(Delimiter::Bracket))) // excludes `[]` + || self.token.is_keyword(kw::As); - if !has_trailing_method && !has_trailing_operator { + if !has_dot_expr && !has_trailing_operator { // Nothing to recover here. return None; } @@ -391,44 +417,41 @@ impl<'a> Parser<'a> { snapshot.restrictions.insert(Restrictions::IS_PAT); // Parse `?`, `.f`, `(arg0, arg1, ...)` or `[expr]` until they've all been eaten. - if let Ok(expr) = snapshot + let Ok(expr) = snapshot .parse_expr_dot_or_call_with( AttrVec::new(), self.mk_expr(pat_span, ExprKind::Dummy), // equivalent to transforming the parsed pattern into an `Expr` pat_span, ) .map_err(|err| err.cancel()) - { - let non_assoc_span = expr.span; + else { + // We got a trailing method/operator, but that wasn't an expression. + return None; + }; - // Parse an associative expression such as `+ expr`, `% expr`, ... - // Assignments, ranges and `|` are disabled by [`Restrictions::IS_PAT`]. - if let Ok((expr, _)) = - snapshot.parse_expr_assoc_rest_with(0, false, expr).map_err(|err| err.cancel()) - { - // We got a valid expression. - self.restore_snapshot(snapshot); - self.restrictions.remove(Restrictions::IS_PAT); - - let is_bound = is_end_bound - // is_start_bound: either `..` or `)..` - || self.token.is_range_separator() - || self.token == token::CloseDelim(Delimiter::Parenthesis) - && self.look_ahead(1, Token::is_range_separator); - - // Check that `parse_expr_assoc_with` didn't eat a rhs. - let is_method_call = has_trailing_method && non_assoc_span == expr.span; - - return Some(self.dcx().emit_err(UnexpectedExpressionInPattern { - span: expr.span, - is_bound, - is_method_call, - })); - } - } + // Parse an associative expression such as `+ expr`, `% expr`, ... + // Assignments, ranges and `|` are disabled by [`Restrictions::IS_PAT`]. + let Ok((expr, _)) = + snapshot.parse_expr_assoc_rest_with(0, false, expr).map_err(|err| err.cancel()) + else { + // We got a trailing method/operator, but that wasn't an expression. + return None; + }; - // We got a trailing method/operator, but we couldn't parse an expression. - None + // We got a valid expression. + self.restore_snapshot(snapshot); + self.restrictions.remove(Restrictions::IS_PAT); + + let is_bound = is_end_bound + // is_start_bound: either `..` or `)..` + || self.token.is_range_separator() + || self.token == token::CloseDelim(Delimiter::Parenthesis) + && self.look_ahead(1, Token::is_range_separator); + + Some(( + self.dcx().emit_err(UnexpectedExpressionInPattern { span: expr.span, is_bound }), + expr.span, + )) } /// Parses a pattern, with a setting whether modern range patterns (e.g., `a..=b`, `a..b` are @@ -544,7 +567,7 @@ impl<'a> Parser<'a> { self.parse_pat_tuple_struct(qself, path)? } else { match self.maybe_recover_trailing_expr(span, false) { - Some(guar) => PatKind::Err(guar), + Some((guar, _)) => PatKind::Err(guar), None => PatKind::Path(qself, path), } } @@ -577,10 +600,10 @@ impl<'a> Parser<'a> { // Try to parse everything else as literal with optional minus match self.parse_literal_maybe_minus() { Ok(begin) => { - let begin = match self.maybe_recover_trailing_expr(begin.span, false) { - Some(guar) => self.mk_expr_err(begin.span, guar), - None => begin, - }; + let begin = self + .maybe_recover_trailing_expr(begin.span, false) + .map(|(guar, sp)| self.mk_expr_err(sp, guar)) + .unwrap_or(begin); match self.parse_range_end() { Some(form) => self.parse_pat_range_begin_with(begin, form)?, @@ -721,7 +744,8 @@ impl<'a> Parser<'a> { // For backward compatibility, `(..)` is a tuple pattern as well. let paren_pattern = fields.len() == 1 && !(matches!(trailing_comma, Trailing::Yes) || fields[0].is_rest()); - if paren_pattern { + + let pat = if paren_pattern { let pat = fields.into_iter().next().unwrap(); let close_paren = self.prev_token.span; @@ -739,7 +763,7 @@ impl<'a> Parser<'a> { }, }); - self.parse_pat_range_begin_with(begin.clone(), form) + self.parse_pat_range_begin_with(begin.clone(), form)? } // recover ranges with parentheses around the `(start)..` PatKind::Err(guar) @@ -754,15 +778,20 @@ impl<'a> Parser<'a> { }, }); - self.parse_pat_range_begin_with(self.mk_expr_err(pat.span, *guar), form) + self.parse_pat_range_begin_with(self.mk_expr_err(pat.span, *guar), form)? } // (pat) with optional parentheses - _ => Ok(PatKind::Paren(pat)), + _ => PatKind::Paren(pat), } } else { - Ok(PatKind::Tuple(fields)) - } + PatKind::Tuple(fields) + }; + + Ok(match self.maybe_recover_trailing_expr(open_paren.to(self.prev_token.span), false) { + None => pat, + Some((guar, _)) => PatKind::Err(guar), + }) } /// Parse a mutable binding with the `mut` token already eaten. @@ -1015,7 +1044,7 @@ impl<'a> Parser<'a> { } Ok(match recovered { - Some(guar) => self.mk_expr_err(bound.span, guar), + Some((guar, sp)) => self.mk_expr_err(sp, guar), None => bound, }) } @@ -1084,7 +1113,7 @@ impl<'a> Parser<'a> { // but not `ident @ subpat` as `subpat` was already checked and `ident` continues with `@`. let pat = if sub.is_none() - && let Some(guar) = self.maybe_recover_trailing_expr(ident.span, false) + && let Some((guar, _)) = self.maybe_recover_trailing_expr(ident.span, false) { PatKind::Err(guar) } else { diff --git a/tests/ui/parser/bad-name.rs b/tests/ui/parser/bad-name.rs index 59432a1d9a5b9..fefe9122a08fb 100644 --- a/tests/ui/parser/bad-name.rs +++ b/tests/ui/parser/bad-name.rs @@ -1,5 +1,6 @@ -//@ error-pattern: expected - fn main() { let x.y::.z foo; + //~^ error: field expressions cannot have generic arguments + //~| error: expected a pattern, found an expression + //~| error: expected one of `(`, `.`, `::`, `:`, `;`, `=`, `?`, `|`, or an operator, found `foo` } diff --git a/tests/ui/parser/bad-name.stderr b/tests/ui/parser/bad-name.stderr index e133d4e4839ce..3fc416dd5311f 100644 --- a/tests/ui/parser/bad-name.stderr +++ b/tests/ui/parser/bad-name.stderr @@ -1,8 +1,20 @@ -error: expected one of `:`, `;`, `=`, `@`, or `|`, found `.` - --> $DIR/bad-name.rs:4:8 +error: field expressions cannot have generic arguments + --> $DIR/bad-name.rs:2:12 | LL | let x.y::.z foo; - | ^ expected one of `:`, `;`, `=`, `@`, or `|` + | ^^^^^^^ -error: aborting due to 1 previous error +error: expected a pattern, found an expression + --> $DIR/bad-name.rs:2:7 + | +LL | let x.y::.z foo; + | ^^^^^^^^^^^^^^ arbitrary expressions are not allowed in patterns + +error: expected one of `(`, `.`, `::`, `:`, `;`, `=`, `?`, `|`, or an operator, found `foo` + --> $DIR/bad-name.rs:2:22 + | +LL | let x.y::.z foo; + | ^^^ expected one of 9 possible tokens + +error: aborting due to 3 previous errors diff --git a/tests/ui/parser/pat-recover-exprs.rs b/tests/ui/parser/pat-recover-exprs.rs deleted file mode 100644 index ecd471467e380..0000000000000 --- a/tests/ui/parser/pat-recover-exprs.rs +++ /dev/null @@ -1,28 +0,0 @@ -fn main() { - match u8::MAX { - u8::MAX.abs() => (), - //~^ error: expected a pattern, found a method call - x.sqrt() @ .. => (), - //~^ error: expected a pattern, found a method call - //~| error: left-hand side of `@` must be a binding - z @ w @ v.u() => (), - //~^ error: expected a pattern, found a method call - y.ilog(3) => (), - //~^ error: expected a pattern, found a method call - n + 1 => (), - //~^ error: expected a pattern, found an expression - ("".f() + 14 * 8) => (), - //~^ error: expected a pattern, found an expression - 0 | ((1) | 2) | 3 => (), - f?() => (), - //~^ error: expected a pattern, found an expression - (_ + 1) => (), - //~^ error: expected one of `)`, `,`, or `|`, found `+` - } - - let 1 + 1 = 2; - //~^ error: expected a pattern, found an expression - - let b = matches!(x, (x * x | x.f()) | x[0]); - //~^ error: expected one of `)`, `,`, `@`, or `|`, found `*` -} diff --git a/tests/ui/parser/pat-recover-exprs.stderr b/tests/ui/parser/pat-recover-exprs.stderr deleted file mode 100644 index 787fd03b0c30d..0000000000000 --- a/tests/ui/parser/pat-recover-exprs.stderr +++ /dev/null @@ -1,76 +0,0 @@ -error: expected a pattern, found a method call - --> $DIR/pat-recover-exprs.rs:3:9 - | -LL | u8::MAX.abs() => (), - | ^^^^^^^^^^^^^ method calls are not allowed in patterns - -error: expected a pattern, found a method call - --> $DIR/pat-recover-exprs.rs:5:9 - | -LL | x.sqrt() @ .. => (), - | ^^^^^^^^ method calls are not allowed in patterns - -error: left-hand side of `@` must be a binding - --> $DIR/pat-recover-exprs.rs:5:9 - | -LL | x.sqrt() @ .. => (), - | --------^^^-- - | | | - | | also a pattern - | interpreted as a pattern, not a binding - | - = note: bindings are `x`, `mut x`, `ref x`, and `ref mut x` - -error: expected a pattern, found a method call - --> $DIR/pat-recover-exprs.rs:8:17 - | -LL | z @ w @ v.u() => (), - | ^^^^^ method calls are not allowed in patterns - -error: expected a pattern, found a method call - --> $DIR/pat-recover-exprs.rs:10:9 - | -LL | y.ilog(3) => (), - | ^^^^^^^^^ method calls are not allowed in patterns - -error: expected a pattern, found an expression - --> $DIR/pat-recover-exprs.rs:12:9 - | -LL | n + 1 => (), - | ^^^^^ arbitrary expressions are not allowed in patterns - -error: expected a pattern, found an expression - --> $DIR/pat-recover-exprs.rs:14:10 - | -LL | ("".f() + 14 * 8) => (), - | ^^^^^^^^^^^^^^^ arbitrary expressions are not allowed in patterns - -error: expected a pattern, found an expression - --> $DIR/pat-recover-exprs.rs:17:9 - | -LL | f?() => (), - | ^^^^ arbitrary expressions are not allowed in patterns - -error: expected one of `)`, `,`, or `|`, found `+` - --> $DIR/pat-recover-exprs.rs:19:12 - | -LL | (_ + 1) => (), - | ^ expected one of `)`, `,`, or `|` - -error: expected a pattern, found an expression - --> $DIR/pat-recover-exprs.rs:23:9 - | -LL | let 1 + 1 = 2; - | ^^^^^ arbitrary expressions are not allowed in patterns - -error: expected one of `)`, `,`, `@`, or `|`, found `*` - --> $DIR/pat-recover-exprs.rs:26:28 - | -LL | let b = matches!(x, (x * x | x.f()) | x[0]); - | ^ expected one of `)`, `,`, `@`, or `|` - --> $SRC_DIR/core/src/macros/mod.rs:LL:COL - | - = note: while parsing argument for this `pat` macro fragment - -error: aborting due to 11 previous errors - diff --git a/tests/ui/parser/pat-recover-methodcalls.rs b/tests/ui/parser/pat-recover-methodcalls.rs deleted file mode 100644 index 54104e9a53559..0000000000000 --- a/tests/ui/parser/pat-recover-methodcalls.rs +++ /dev/null @@ -1,37 +0,0 @@ -struct Foo(String); -struct Bar { baz: String } - -fn foo(foo: Foo) -> bool { - match foo { - Foo("hi".to_owned()) => true, - //~^ error: expected a pattern, found a method call - _ => false - } -} - -fn bar(bar: Bar) -> bool { - match bar { - Bar { baz: "hi".to_owned() } => true, - //~^ error: expected a pattern, found a method call - _ => false - } -} - -fn baz() { // issue #90121 - let foo = vec!["foo".to_string()]; - - match foo.as_slice() { - &["foo".to_string()] => {} - //~^ error: expected a pattern, found a method call - _ => {} - }; -} - -fn main() { - if let (-1.some(4)) = (0, Some(4)) {} - //~^ error: expected a pattern, found a method call - - if let (-1.Some(4)) = (0, Some(4)) {} - //~^ error: expected one of `)`, `,`, `...`, `..=`, `..`, or `|`, found `.` - //~| help: missing `,` -} diff --git a/tests/ui/parser/pat-recover-methodcalls.stderr b/tests/ui/parser/pat-recover-methodcalls.stderr deleted file mode 100644 index 1f9ae81dc0c55..0000000000000 --- a/tests/ui/parser/pat-recover-methodcalls.stderr +++ /dev/null @@ -1,35 +0,0 @@ -error: expected a pattern, found a method call - --> $DIR/pat-recover-methodcalls.rs:6:13 - | -LL | Foo("hi".to_owned()) => true, - | ^^^^^^^^^^^^^^^ method calls are not allowed in patterns - -error: expected a pattern, found a method call - --> $DIR/pat-recover-methodcalls.rs:14:20 - | -LL | Bar { baz: "hi".to_owned() } => true, - | ^^^^^^^^^^^^^^^ method calls are not allowed in patterns - -error: expected a pattern, found a method call - --> $DIR/pat-recover-methodcalls.rs:24:11 - | -LL | &["foo".to_string()] => {} - | ^^^^^^^^^^^^^^^^^ method calls are not allowed in patterns - -error: expected a pattern, found a method call - --> $DIR/pat-recover-methodcalls.rs:31:13 - | -LL | if let (-1.some(4)) = (0, Some(4)) {} - | ^^^^^^^^^^ method calls are not allowed in patterns - -error: expected one of `)`, `,`, `...`, `..=`, `..`, or `|`, found `.` - --> $DIR/pat-recover-methodcalls.rs:34:15 - | -LL | if let (-1.Some(4)) = (0, Some(4)) {} - | ^ - | | - | expected one of `)`, `,`, `...`, `..=`, `..`, or `|` - | help: missing `,` - -error: aborting due to 5 previous errors - diff --git a/tests/ui/parser/recover/recover-pat-exprs.rs b/tests/ui/parser/recover/recover-pat-exprs.rs new file mode 100644 index 0000000000000..031e49cb8ebda --- /dev/null +++ b/tests/ui/parser/recover/recover-pat-exprs.rs @@ -0,0 +1,98 @@ +// FieldExpression, TupleIndexingExpression +fn field_access() { + match 0 { + x => (), + x.y => (), //~ error: expected a pattern, found an expression + x.0 => (), //~ error: expected a pattern, found an expression + x._0 => (), //~ error: expected a pattern, found an expression + x.0.1 => (), //~ error: expected a pattern, found an expression + x.4.y.17.__z => (), //~ error: expected a pattern, found an expression + } + + { let x.0e0; } //~ error: expected one of `:`, `;`, `=`, `@`, or `|`, found `.` + { let x.-0.0; } //~ error: expected one of `:`, `;`, `=`, `@`, or `|`, found `.` + { let x.-0; } //~ error: expected one of `:`, `;`, `=`, `@`, or `|`, found `.` + + { let x.0u32; } //~ error: expected one of `:`, `;`, `=`, `@`, or `|`, found `.` + { let x.0.0_f64; } //~ error: expected one of `:`, `;`, `=`, `@`, or `|`, found `.` +} + +// IndexExpression, ArrayExpression +fn array_indexing() { + match 0 { + x[0] => (), //~ error: expected a pattern, found an expression + x[..] => (), //~ error: expected a pattern, found an expression + } + + { let x[0, 1, 2]; } //~ error: expected one of `:`, `;`, `=`, `@`, or `|`, found `[` + { let x[0; 20]; } //~ error: expected one of `:`, `;`, `=`, `@`, or `|`, found `[` + { let x[]; } //~ error: expected one of `:`, `;`, `=`, `@`, or `|`, found `[` + { let (x[]); } //~ error: expected one of `)`, `,`, `@`, or `|`, found `[` + //~^ missing `,` +} + +// MethodCallExpression, CallExpression, ErrorPropagationExpression +fn method_call() { + match 0 { + x.f() => (), //~ error: expected a pattern, found an expression + x._f() => (), //~ error: expected a pattern, found an expression + x? => (), //~ error: expected a pattern, found an expression + ().f() => (), //~ error: expected a pattern, found an expression + (0, x)?.f() => (), //~ error: expected a pattern, found an expression + x.f().g() => (), //~ error: expected a pattern, found an expression + 0.f()?.g()?? => (), //~ error: expected a pattern, found an expression + } +} + +// TypeCastExpression +fn type_cast() { + match 0 { + x as usize => (), //~ error: expected a pattern, found an expression + 0 as usize => (), //~ error: expected a pattern, found an expression + x.f().0.4 as f32 => (), //~ error: expected a pattern, found an expression + } +} + +// ArithmeticOrLogicalExpression +fn operator() { + match 0 { + 1 + 1 => (), //~ error: expected a pattern, found an expression + (1 + 2) * 3 => (), + //~^ error: expected a pattern, found an expression + //~| error: expected a pattern, found an expression + } +} + +const _: u32 = match 12 { + 1 + 2 * PI.cos() => 2, //~ error: expected a pattern, found an expression + _ => 0, +}; + +fn main() { + match u8::MAX { + u8::MAX.abs() => (), + //~^ error: expected a pattern, found an expression + x.sqrt() @ .. => (), + //~^ error: expected a pattern, found an expression + //~| error: left-hand side of `@` must be a binding + z @ w @ v.u() => (), + //~^ error: expected a pattern, found an expression + y.ilog(3) => (), + //~^ error: expected a pattern, found an expression + n + 1 => (), + //~^ error: expected a pattern, found an expression + ("".f() + 14 * 8) => (), + //~^ error: expected a pattern, found an expression + 0 | ((1) | 2) | 3 => (), + f?() => (), + //~^ error: expected a pattern, found an expression + (_ + 1) => (), + //~^ error: expected one of `)`, `,`, or `|`, found `+` + } + + let 1 + 1 = 2; + //~^ error: expected a pattern, found an expression + + let b = matches!(x, (x * x | x.f()) | x[0]); + //~^ error: expected one of `)`, `,`, `@`, or `|`, found `*` +} diff --git a/tests/ui/parser/recover/recover-pat-exprs.stderr b/tests/ui/parser/recover/recover-pat-exprs.stderr new file mode 100644 index 0000000000000..ea8d1458d27c9 --- /dev/null +++ b/tests/ui/parser/recover/recover-pat-exprs.stderr @@ -0,0 +1,259 @@ +error: expected a pattern, found an expression + --> $DIR/recover-pat-exprs.rs:5:9 + | +LL | x.y => (), + | ^^^ arbitrary expressions are not allowed in patterns + +error: expected a pattern, found an expression + --> $DIR/recover-pat-exprs.rs:6:9 + | +LL | x.0 => (), + | ^^^ arbitrary expressions are not allowed in patterns + +error: expected a pattern, found an expression + --> $DIR/recover-pat-exprs.rs:7:9 + | +LL | x._0 => (), + | ^^^^ arbitrary expressions are not allowed in patterns + +error: expected a pattern, found an expression + --> $DIR/recover-pat-exprs.rs:8:9 + | +LL | x.0.1 => (), + | ^^^^^ arbitrary expressions are not allowed in patterns + +error: expected a pattern, found an expression + --> $DIR/recover-pat-exprs.rs:9:9 + | +LL | x.4.y.17.__z => (), + | ^^^^^^^^^^^^ arbitrary expressions are not allowed in patterns + +error: expected one of `:`, `;`, `=`, `@`, or `|`, found `.` + --> $DIR/recover-pat-exprs.rs:12:12 + | +LL | { let x.0e0; } + | ^ expected one of `:`, `;`, `=`, `@`, or `|` + +error: expected one of `:`, `;`, `=`, `@`, or `|`, found `.` + --> $DIR/recover-pat-exprs.rs:13:12 + | +LL | { let x.-0.0; } + | ^ expected one of `:`, `;`, `=`, `@`, or `|` + +error: expected one of `:`, `;`, `=`, `@`, or `|`, found `.` + --> $DIR/recover-pat-exprs.rs:14:12 + | +LL | { let x.-0; } + | ^ expected one of `:`, `;`, `=`, `@`, or `|` + +error: expected one of `:`, `;`, `=`, `@`, or `|`, found `.` + --> $DIR/recover-pat-exprs.rs:16:12 + | +LL | { let x.0u32; } + | ^ expected one of `:`, `;`, `=`, `@`, or `|` + +error: expected one of `:`, `;`, `=`, `@`, or `|`, found `.` + --> $DIR/recover-pat-exprs.rs:17:12 + | +LL | { let x.0.0_f64; } + | ^ expected one of `:`, `;`, `=`, `@`, or `|` + +error: expected a pattern, found an expression + --> $DIR/recover-pat-exprs.rs:23:9 + | +LL | x[0] => (), + | ^^^^ arbitrary expressions are not allowed in patterns + +error: expected a pattern, found an expression + --> $DIR/recover-pat-exprs.rs:24:9 + | +LL | x[..] => (), + | ^^^^^ arbitrary expressions are not allowed in patterns + +error: expected one of `:`, `;`, `=`, `@`, or `|`, found `[` + --> $DIR/recover-pat-exprs.rs:27:12 + | +LL | { let x[0, 1, 2]; } + | ^ expected one of `:`, `;`, `=`, `@`, or `|` + +error: expected one of `:`, `;`, `=`, `@`, or `|`, found `[` + --> $DIR/recover-pat-exprs.rs:28:12 + | +LL | { let x[0; 20]; } + | ^ expected one of `:`, `;`, `=`, `@`, or `|` + +error: expected one of `:`, `;`, `=`, `@`, or `|`, found `[` + --> $DIR/recover-pat-exprs.rs:29:12 + | +LL | { let x[]; } + | ^ expected one of `:`, `;`, `=`, `@`, or `|` + +error: expected one of `)`, `,`, `@`, or `|`, found `[` + --> $DIR/recover-pat-exprs.rs:30:13 + | +LL | { let (x[]); } + | ^ + | | + | expected one of `)`, `,`, `@`, or `|` + | help: missing `,` + +error: expected a pattern, found an expression + --> $DIR/recover-pat-exprs.rs:37:9 + | +LL | x.f() => (), + | ^^^^^ arbitrary expressions are not allowed in patterns + +error: expected a pattern, found an expression + --> $DIR/recover-pat-exprs.rs:38:9 + | +LL | x._f() => (), + | ^^^^^^ arbitrary expressions are not allowed in patterns + +error: expected a pattern, found an expression + --> $DIR/recover-pat-exprs.rs:39:9 + | +LL | x? => (), + | ^^ arbitrary expressions are not allowed in patterns + +error: expected a pattern, found an expression + --> $DIR/recover-pat-exprs.rs:40:9 + | +LL | ().f() => (), + | ^^^^^^ arbitrary expressions are not allowed in patterns + +error: expected a pattern, found an expression + --> $DIR/recover-pat-exprs.rs:41:9 + | +LL | (0, x)?.f() => (), + | ^^^^^^^^^^^ arbitrary expressions are not allowed in patterns + +error: expected a pattern, found an expression + --> $DIR/recover-pat-exprs.rs:42:9 + | +LL | x.f().g() => (), + | ^^^^^^^^^ arbitrary expressions are not allowed in patterns + +error: expected a pattern, found an expression + --> $DIR/recover-pat-exprs.rs:43:9 + | +LL | 0.f()?.g()?? => (), + | ^^^^^^^^^^^^ arbitrary expressions are not allowed in patterns + +error: expected a pattern, found an expression + --> $DIR/recover-pat-exprs.rs:50:9 + | +LL | x as usize => (), + | ^^^^^^^^^^ arbitrary expressions are not allowed in patterns + +error: expected a pattern, found an expression + --> $DIR/recover-pat-exprs.rs:51:9 + | +LL | 0 as usize => (), + | ^^^^^^^^^^ arbitrary expressions are not allowed in patterns + +error: expected a pattern, found an expression + --> $DIR/recover-pat-exprs.rs:52:9 + | +LL | x.f().0.4 as f32 => (), + | ^^^^^^^^^^^^^^^^ arbitrary expressions are not allowed in patterns + +error: expected a pattern, found an expression + --> $DIR/recover-pat-exprs.rs:59:9 + | +LL | 1 + 1 => (), + | ^^^^^ arbitrary expressions are not allowed in patterns + +error: expected a pattern, found an expression + --> $DIR/recover-pat-exprs.rs:60:10 + | +LL | (1 + 2) * 3 => (), + | ^^^^^ arbitrary expressions are not allowed in patterns + +error: expected a pattern, found an expression + --> $DIR/recover-pat-exprs.rs:60:9 + | +LL | (1 + 2) * 3 => (), + | ^^^^^^^^^^^ arbitrary expressions are not allowed in patterns + +error: expected a pattern, found an expression + --> $DIR/recover-pat-exprs.rs:67:5 + | +LL | 1 + 2 * PI.cos() => 2, + | ^^^^^^^^^^^^^^^^ arbitrary expressions are not allowed in patterns + +error: expected a pattern, found an expression + --> $DIR/recover-pat-exprs.rs:73:9 + | +LL | u8::MAX.abs() => (), + | ^^^^^^^^^^^^^ arbitrary expressions are not allowed in patterns + +error: expected a pattern, found an expression + --> $DIR/recover-pat-exprs.rs:75:9 + | +LL | x.sqrt() @ .. => (), + | ^^^^^^^^ arbitrary expressions are not allowed in patterns + +error: left-hand side of `@` must be a binding + --> $DIR/recover-pat-exprs.rs:75:9 + | +LL | x.sqrt() @ .. => (), + | --------^^^-- + | | | + | | also a pattern + | interpreted as a pattern, not a binding + | + = note: bindings are `x`, `mut x`, `ref x`, and `ref mut x` + +error: expected a pattern, found an expression + --> $DIR/recover-pat-exprs.rs:78:17 + | +LL | z @ w @ v.u() => (), + | ^^^^^ arbitrary expressions are not allowed in patterns + +error: expected a pattern, found an expression + --> $DIR/recover-pat-exprs.rs:80:9 + | +LL | y.ilog(3) => (), + | ^^^^^^^^^ arbitrary expressions are not allowed in patterns + +error: expected a pattern, found an expression + --> $DIR/recover-pat-exprs.rs:82:9 + | +LL | n + 1 => (), + | ^^^^^ arbitrary expressions are not allowed in patterns + +error: expected a pattern, found an expression + --> $DIR/recover-pat-exprs.rs:84:10 + | +LL | ("".f() + 14 * 8) => (), + | ^^^^^^^^^^^^^^^ arbitrary expressions are not allowed in patterns + +error: expected a pattern, found an expression + --> $DIR/recover-pat-exprs.rs:87:9 + | +LL | f?() => (), + | ^^^^ arbitrary expressions are not allowed in patterns + +error: expected one of `)`, `,`, or `|`, found `+` + --> $DIR/recover-pat-exprs.rs:89:12 + | +LL | (_ + 1) => (), + | ^ expected one of `)`, `,`, or `|` + +error: expected a pattern, found an expression + --> $DIR/recover-pat-exprs.rs:93:9 + | +LL | let 1 + 1 = 2; + | ^^^^^ arbitrary expressions are not allowed in patterns + +error: expected one of `)`, `,`, `@`, or `|`, found `*` + --> $DIR/recover-pat-exprs.rs:96:28 + | +LL | let b = matches!(x, (x * x | x.f()) | x[0]); + | ^ expected one of `)`, `,`, `@`, or `|` + --> $SRC_DIR/core/src/macros/mod.rs:LL:COL + | + = note: while parsing argument for this `pat` macro fragment + +error: aborting due to 41 previous errors + diff --git a/tests/ui/parser/recover/recover-pat-issues.rs b/tests/ui/parser/recover/recover-pat-issues.rs new file mode 100644 index 0000000000000..5b900fe80e516 --- /dev/null +++ b/tests/ui/parser/recover/recover-pat-issues.rs @@ -0,0 +1,46 @@ +struct Foo(String); +struct Bar { baz: String } + +fn foo(foo: Foo) -> bool { + match foo { + Foo("hi".to_owned()) => true, + //~^ error: expected a pattern, found an expression + _ => false + } +} + +fn bar(bar: Bar) -> bool { + match bar { + Bar { baz: "hi".to_owned() } => true, + //~^ error: expected a pattern, found an expression + _ => false + } +} + +/// Issue #90121 +fn baz() { + let foo = vec!["foo".to_string()]; + + match foo.as_slice() { + &["foo".to_string()] => {} + //~^ error: expected a pattern, found an expression + _ => {} + }; +} + +/// Issue #104996 +fn qux() { + struct Magic(pub u16); + const MAGIC: Magic = Magic(42); + + if let Some(MAGIC.0 as usize) = None:: {} + //~^ error: expected a pattern, found an expression +} + +fn main() { + if let (-1.some(4)) = (0, Some(4)) {} + //~^ error: expected a pattern, found an expression + + if let (-1.Some(4)) = (0, Some(4)) {} + //~^ error: expected a pattern, found an expression +} diff --git a/tests/ui/parser/recover/recover-pat-issues.stderr b/tests/ui/parser/recover/recover-pat-issues.stderr new file mode 100644 index 0000000000000..793091bb1f1c2 --- /dev/null +++ b/tests/ui/parser/recover/recover-pat-issues.stderr @@ -0,0 +1,38 @@ +error: expected a pattern, found an expression + --> $DIR/recover-pat-issues.rs:6:13 + | +LL | Foo("hi".to_owned()) => true, + | ^^^^^^^^^^^^^^^ arbitrary expressions are not allowed in patterns + +error: expected a pattern, found an expression + --> $DIR/recover-pat-issues.rs:14:20 + | +LL | Bar { baz: "hi".to_owned() } => true, + | ^^^^^^^^^^^^^^^ arbitrary expressions are not allowed in patterns + +error: expected a pattern, found an expression + --> $DIR/recover-pat-issues.rs:25:11 + | +LL | &["foo".to_string()] => {} + | ^^^^^^^^^^^^^^^^^ arbitrary expressions are not allowed in patterns + +error: expected a pattern, found an expression + --> $DIR/recover-pat-issues.rs:36:17 + | +LL | if let Some(MAGIC.0 as usize) = None:: {} + | ^^^^^^^^^^^^^^^^ arbitrary expressions are not allowed in patterns + +error: expected a pattern, found an expression + --> $DIR/recover-pat-issues.rs:41:13 + | +LL | if let (-1.some(4)) = (0, Some(4)) {} + | ^^^^^^^^^^ arbitrary expressions are not allowed in patterns + +error: expected a pattern, found an expression + --> $DIR/recover-pat-issues.rs:44:13 + | +LL | if let (-1.Some(4)) = (0, Some(4)) {} + | ^^^^^^^^^^ arbitrary expressions are not allowed in patterns + +error: aborting due to 6 previous errors + diff --git a/tests/ui/parser/recover/recover-pat-lets.rs b/tests/ui/parser/recover/recover-pat-lets.rs new file mode 100644 index 0000000000000..6681cc25db37b --- /dev/null +++ b/tests/ui/parser/recover/recover-pat-lets.rs @@ -0,0 +1,20 @@ +fn main() { + let x = Some(2); + + let x.expect("foo"); + //~^ error: expected a pattern, found an expression + + let x.unwrap(): u32; + //~^ error: expected a pattern, found an expression + + let x[0] = 1; + //~^ error: expected a pattern, found an expression + + let Some(1 + 1) = x else { //~ error: expected a pattern, found an expression + return; + }; + + if let Some(1 + 1) = x { //~ error: expected a pattern, found an expression + return; + } +} diff --git a/tests/ui/parser/recover/recover-pat-lets.stderr b/tests/ui/parser/recover/recover-pat-lets.stderr new file mode 100644 index 0000000000000..b1d2a9b96d984 --- /dev/null +++ b/tests/ui/parser/recover/recover-pat-lets.stderr @@ -0,0 +1,32 @@ +error: expected a pattern, found an expression + --> $DIR/recover-pat-lets.rs:4:9 + | +LL | let x.expect("foo"); + | ^^^^^^^^^^^^^^^ arbitrary expressions are not allowed in patterns + +error: expected a pattern, found an expression + --> $DIR/recover-pat-lets.rs:7:9 + | +LL | let x.unwrap(): u32; + | ^^^^^^^^^^ arbitrary expressions are not allowed in patterns + +error: expected a pattern, found an expression + --> $DIR/recover-pat-lets.rs:10:9 + | +LL | let x[0] = 1; + | ^^^^ arbitrary expressions are not allowed in patterns + +error: expected a pattern, found an expression + --> $DIR/recover-pat-lets.rs:13:14 + | +LL | let Some(1 + 1) = x else { + | ^^^^^ arbitrary expressions are not allowed in patterns + +error: expected a pattern, found an expression + --> $DIR/recover-pat-lets.rs:17:17 + | +LL | if let Some(1 + 1) = x { + | ^^^^^ arbitrary expressions are not allowed in patterns + +error: aborting due to 5 previous errors + diff --git a/tests/ui/parser/pat-recover-ranges.rs b/tests/ui/parser/recover/recover-pat-ranges.rs similarity index 89% rename from tests/ui/parser/pat-recover-ranges.rs rename to tests/ui/parser/recover/recover-pat-ranges.rs index 7d77e950d905a..e3f061c625d3d 100644 --- a/tests/ui/parser/pat-recover-ranges.rs +++ b/tests/ui/parser/recover/recover-pat-ranges.rs @@ -22,8 +22,8 @@ fn main() { //~| warning: `...` range patterns are deprecated //~| warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2021! 0.x()..="y".z() => (), - //~^ error: expected a pattern range bound, found a method call - //~| error: expected a pattern range bound, found a method call + //~^ error: expected a pattern range bound, found an expression + //~| error: expected a pattern range bound, found an expression }; } diff --git a/tests/ui/parser/pat-recover-ranges.stderr b/tests/ui/parser/recover/recover-pat-ranges.stderr similarity index 77% rename from tests/ui/parser/pat-recover-ranges.stderr rename to tests/ui/parser/recover/recover-pat-ranges.stderr index a7d62bd7f8ad2..62ef7a8a908c2 100644 --- a/tests/ui/parser/pat-recover-ranges.stderr +++ b/tests/ui/parser/recover/recover-pat-ranges.stderr @@ -1,5 +1,5 @@ error: range pattern bounds cannot have parentheses - --> $DIR/pat-recover-ranges.rs:4:13 + --> $DIR/recover-pat-ranges.rs:4:13 | LL | 0..=(1) => (), | ^ ^ @@ -11,7 +11,7 @@ LL + 0..=1 => (), | error: range pattern bounds cannot have parentheses - --> $DIR/pat-recover-ranges.rs:6:9 + --> $DIR/recover-pat-ranges.rs:6:9 | LL | (-12)..=4 => (), | ^ ^ @@ -23,7 +23,7 @@ LL + -12..=4 => (), | error: range pattern bounds cannot have parentheses - --> $DIR/pat-recover-ranges.rs:8:9 + --> $DIR/recover-pat-ranges.rs:8:9 | LL | (0)..=(-4) => (), | ^ ^ @@ -35,7 +35,7 @@ LL + 0..=(-4) => (), | error: range pattern bounds cannot have parentheses - --> $DIR/pat-recover-ranges.rs:8:15 + --> $DIR/recover-pat-ranges.rs:8:15 | LL | (0)..=(-4) => (), | ^ ^ @@ -47,13 +47,13 @@ LL + (0)..=-4 => (), | error: expected a pattern range bound, found an expression - --> $DIR/pat-recover-ranges.rs:11:12 + --> $DIR/recover-pat-ranges.rs:11:12 | LL | ..=1 + 2 => (), | ^^^^^ arbitrary expressions are not allowed in patterns error: range pattern bounds cannot have parentheses - --> $DIR/pat-recover-ranges.rs:13:9 + --> $DIR/recover-pat-ranges.rs:13:9 | LL | (4).. => (), | ^ ^ @@ -65,13 +65,13 @@ LL + 4.. => (), | error: expected a pattern range bound, found an expression - --> $DIR/pat-recover-ranges.rs:15:10 + --> $DIR/recover-pat-ranges.rs:15:10 | LL | (-4 + 0).. => (), | ^^^^^^ arbitrary expressions are not allowed in patterns error: range pattern bounds cannot have parentheses - --> $DIR/pat-recover-ranges.rs:15:9 + --> $DIR/recover-pat-ranges.rs:15:9 | LL | (-4 + 0).. => (), | ^ ^ @@ -83,13 +83,13 @@ LL + -4 + 0.. => (), | error: expected a pattern range bound, found an expression - --> $DIR/pat-recover-ranges.rs:18:10 + --> $DIR/recover-pat-ranges.rs:18:10 | LL | (1 + 4)...1 * 2 => (), | ^^^^^ arbitrary expressions are not allowed in patterns error: range pattern bounds cannot have parentheses - --> $DIR/pat-recover-ranges.rs:18:9 + --> $DIR/recover-pat-ranges.rs:18:9 | LL | (1 + 4)...1 * 2 => (), | ^ ^ @@ -101,25 +101,25 @@ LL + 1 + 4...1 * 2 => (), | error: expected a pattern range bound, found an expression - --> $DIR/pat-recover-ranges.rs:18:19 + --> $DIR/recover-pat-ranges.rs:18:19 | LL | (1 + 4)...1 * 2 => (), | ^^^^^ arbitrary expressions are not allowed in patterns -error: expected a pattern range bound, found a method call - --> $DIR/pat-recover-ranges.rs:24:9 +error: expected a pattern range bound, found an expression + --> $DIR/recover-pat-ranges.rs:24:9 | LL | 0.x()..="y".z() => (), - | ^^^^^ method calls are not allowed in patterns + | ^^^^^ arbitrary expressions are not allowed in patterns -error: expected a pattern range bound, found a method call - --> $DIR/pat-recover-ranges.rs:24:17 +error: expected a pattern range bound, found an expression + --> $DIR/recover-pat-ranges.rs:24:17 | LL | 0.x()..="y".z() => (), - | ^^^^^^^ method calls are not allowed in patterns + | ^^^^^^^ arbitrary expressions are not allowed in patterns warning: `...` range patterns are deprecated - --> $DIR/pat-recover-ranges.rs:18:16 + --> $DIR/recover-pat-ranges.rs:18:16 | LL | (1 + 4)...1 * 2 => (), | ^^^ help: use `..=` for an inclusive range diff --git a/tests/ui/parser/pat-recover-wildcards.rs b/tests/ui/parser/recover/recover-pat-wildcards.rs similarity index 100% rename from tests/ui/parser/pat-recover-wildcards.rs rename to tests/ui/parser/recover/recover-pat-wildcards.rs diff --git a/tests/ui/parser/pat-recover-wildcards.stderr b/tests/ui/parser/recover/recover-pat-wildcards.stderr similarity index 80% rename from tests/ui/parser/pat-recover-wildcards.stderr rename to tests/ui/parser/recover/recover-pat-wildcards.stderr index e36ff237bb00a..64d477fdeb239 100644 --- a/tests/ui/parser/pat-recover-wildcards.stderr +++ b/tests/ui/parser/recover/recover-pat-wildcards.stderr @@ -1,35 +1,35 @@ error: expected one of `=>`, `if`, or `|`, found `+` - --> $DIR/pat-recover-wildcards.rs:5:11 + --> $DIR/recover-pat-wildcards.rs:5:11 | LL | _ + 1 => () | ^ expected one of `=>`, `if`, or `|` error: expected one of `)`, `,`, or `|`, found `%` - --> $DIR/pat-recover-wildcards.rs:11:12 + --> $DIR/recover-pat-wildcards.rs:11:12 | LL | (_ % 4) => () | ^ expected one of `)`, `,`, or `|` error: expected one of `=>`, `if`, or `|`, found `.` - --> $DIR/pat-recover-wildcards.rs:17:10 + --> $DIR/recover-pat-wildcards.rs:17:10 | LL | _.x() => () | ^ expected one of `=>`, `if`, or `|` error: expected one of `=>`, `if`, or `|`, found `..=` - --> $DIR/pat-recover-wildcards.rs:23:10 + --> $DIR/recover-pat-wildcards.rs:23:10 | LL | _..=4 => () | ^^^ expected one of `=>`, `if`, or `|` error: expected one of `=>`, `if`, or `|`, found reserved identifier `_` - --> $DIR/pat-recover-wildcards.rs:29:11 + --> $DIR/recover-pat-wildcards.rs:29:11 | LL | .._ => () | ^ expected one of `=>`, `if`, or `|` error[E0586]: inclusive range with no end - --> $DIR/pat-recover-wildcards.rs:35:10 + --> $DIR/recover-pat-wildcards.rs:35:10 | LL | 0..._ => () | ^^^ @@ -42,31 +42,31 @@ LL + 0.._ => () | error: expected one of `=>`, `if`, or `|`, found reserved identifier `_` - --> $DIR/pat-recover-wildcards.rs:35:13 + --> $DIR/recover-pat-wildcards.rs:35:13 | LL | 0..._ => () | ^ expected one of `=>`, `if`, or `|` error: expected one of `)`, `,`, or `|`, found `*` - --> $DIR/pat-recover-wildcards.rs:43:12 + --> $DIR/recover-pat-wildcards.rs:43:12 | LL | (_ * 0)..5 => () | ^ expected one of `)`, `,`, or `|` error: expected one of `=>`, `if`, or `|`, found `(` - --> $DIR/pat-recover-wildcards.rs:49:11 + --> $DIR/recover-pat-wildcards.rs:49:11 | LL | ..(_) => () | ^ expected one of `=>`, `if`, or `|` error: expected a pattern range bound, found an expression - --> $DIR/pat-recover-wildcards.rs:55:14 + --> $DIR/recover-pat-wildcards.rs:55:14 | LL | 4..=(2 + _) => () | ^^^^^ arbitrary expressions are not allowed in patterns error: range pattern bounds cannot have parentheses - --> $DIR/pat-recover-wildcards.rs:55:13 + --> $DIR/recover-pat-wildcards.rs:55:13 | LL | 4..=(2 + _) => () | ^ ^ From db09345ef6e7f39110704e6196bb239d8f10fc27 Mon Sep 17 00:00:00 2001 From: Lieselotte <52315535+she3py@users.noreply.github.com> Date: Wed, 18 Sep 2024 20:38:43 +0200 Subject: [PATCH 2/2] Add suggestions for expressions in patterns --- compiler/rustc_errors/src/lib.rs | 2 + compiler/rustc_parse/messages.ftl | 8 + compiler/rustc_parse/src/errors.rs | 77 +++ compiler/rustc_parse/src/parser/pat.rs | 227 ++++++- compiler/rustc_parse/src/parser/stmt.rs | 10 +- .../range_pat_interactions1.stderr | 11 + .../range_pat_interactions2.stderr | 23 +- tests/ui/parser/issues/issue-24375.stderr | 15 + tests/ui/parser/pat-lt-bracket-6.stderr | 4 +- tests/ui/parser/recover/recover-pat-exprs.rs | 10 +- .../parser/recover/recover-pat-exprs.stderr | 569 +++++++++++++++++- .../parser/recover/recover-pat-issues.stderr | 75 +++ .../ui/parser/recover/recover-pat-lets.stderr | 20 + .../parser/recover/recover-pat-ranges.stderr | 120 +++- .../recover/recover-pat-wildcards.stderr | 23 +- 15 files changed, 1122 insertions(+), 72 deletions(-) diff --git a/compiler/rustc_errors/src/lib.rs b/compiler/rustc_errors/src/lib.rs index 094e3010471f2..59866012069ca 100644 --- a/compiler/rustc_errors/src/lib.rs +++ b/compiler/rustc_errors/src/lib.rs @@ -571,6 +571,8 @@ pub enum StashKey { /// Query cycle detected, stashing in favor of a better error. Cycle, UndeterminedMacroResolution, + /// Used by `Parser::maybe_recover_trailing_expr` + ExprInPat, } fn default_track_diagnostic(diag: DiagInner, f: &mut dyn FnMut(DiagInner) -> R) -> R { diff --git a/compiler/rustc_parse/messages.ftl b/compiler/rustc_parse/messages.ftl index 3d0ce77bc47a9..f5aa8984f51fc 100644 --- a/compiler/rustc_parse/messages.ftl +++ b/compiler/rustc_parse/messages.ftl @@ -807,6 +807,14 @@ parse_unexpected_expr_in_pat = .label = arbitrary expressions are not allowed in patterns +parse_unexpected_expr_in_pat_const_sugg = consider extracting the expression into a `const` + +parse_unexpected_expr_in_pat_create_guard_sugg = consider moving the expression to a match arm guard + +parse_unexpected_expr_in_pat_inline_const_sugg = consider wrapping the expression in an inline `const` (requires `{"#"}![feature(inline_const_pat)]`) + +parse_unexpected_expr_in_pat_update_guard_sugg = consider moving the expression to the match arm guard + parse_unexpected_if_with_if = unexpected `if` in the condition expression .suggestion = remove the `if` diff --git a/compiler/rustc_parse/src/errors.rs b/compiler/rustc_parse/src/errors.rs index a91aa1f501895..e3e7fcebaaabb 100644 --- a/compiler/rustc_parse/src/errors.rs +++ b/compiler/rustc_parse/src/errors.rs @@ -1,3 +1,5 @@ +// ignore-tidy-filelength + use std::borrow::Cow; use rustc_ast::token::Token; @@ -2592,11 +2594,86 @@ pub(crate) struct ExpectedCommaAfterPatternField { #[derive(Diagnostic)] #[diag(parse_unexpected_expr_in_pat)] pub(crate) struct UnexpectedExpressionInPattern { + /// The unexpected expr's span. #[primary_span] #[label] pub span: Span, /// Was a `RangePatternBound` expected? pub is_bound: bool, + /// The unexpected expr's precedence (used in match arm guard suggestions). + pub expr_precedence: i8, +} + +#[derive(Subdiagnostic)] +pub(crate) enum UnexpectedExpressionInPatternSugg { + #[multipart_suggestion( + parse_unexpected_expr_in_pat_create_guard_sugg, + applicability = "maybe-incorrect" + )] + CreateGuard { + /// Where to put the suggested identifier. + #[suggestion_part(code = "{ident}")] + ident_span: Span, + /// Where to put the match arm. + #[suggestion_part(code = " if {ident} == {expr}")] + pat_hi: Span, + /// The suggested identifier. + ident: String, + /// The unexpected expression. + expr: String, + }, + + #[multipart_suggestion( + parse_unexpected_expr_in_pat_update_guard_sugg, + applicability = "maybe-incorrect" + )] + UpdateGuard { + /// Where to put the suggested identifier. + #[suggestion_part(code = "{ident}")] + ident_span: Span, + /// The beginning of the match arm guard's expression (insert a `(` if `Some`). + #[suggestion_part(code = "(")] + guard_lo: Option, + /// The end of the match arm guard's expression. + #[suggestion_part(code = "{guard_hi_paren} && {ident} == {expr}")] + guard_hi: Span, + /// Either `")"` or `""`. + guard_hi_paren: &'static str, + /// The suggested identifier. + ident: String, + /// The unexpected expression. + expr: String, + }, + + #[multipart_suggestion( + parse_unexpected_expr_in_pat_const_sugg, + applicability = "has-placeholders" + )] + Const { + /// Where to put the extracted constant declaration. + #[suggestion_part(code = "{indentation}const {ident}: /* Type */ = {expr};\n")] + stmt_lo: Span, + /// Where to put the suggested identifier. + #[suggestion_part(code = "{ident}")] + ident_span: Span, + /// The suggested identifier. + ident: String, + /// The unexpected expression. + expr: String, + /// The statement's block's indentation. + indentation: String, + }, + + #[multipart_suggestion( + parse_unexpected_expr_in_pat_inline_const_sugg, + applicability = "maybe-incorrect" + )] + InlineConst { + #[suggestion_part(code = "const {{ ")] + start_span: Span, + #[suggestion_part(code = " }}")] + end_span: Span, + }, } #[derive(Diagnostic)] diff --git a/compiler/rustc_parse/src/parser/pat.rs b/compiler/rustc_parse/src/parser/pat.rs index 94c01f7e0d4a7..647df25c82ef7 100644 --- a/compiler/rustc_parse/src/parser/pat.rs +++ b/compiler/rustc_parse/src/parser/pat.rs @@ -1,12 +1,14 @@ -use rustc_ast::mut_visit::{walk_pat, MutVisitor}; +use rustc_ast::mut_visit::{self, MutVisitor}; use rustc_ast::ptr::P; use rustc_ast::token::{self, BinOpToken, Delimiter, IdentIsRaw, Token}; +use rustc_ast::visit::{self, Visitor}; use rustc_ast::{ - self as ast, AttrVec, BindingMode, ByRef, Expr, ExprKind, MacCall, Mutability, Pat, PatField, - PatFieldsRest, PatKind, Path, QSelf, RangeEnd, RangeSyntax, + self as ast, Arm, AttrVec, BinOpKind, BindingMode, ByRef, Expr, ExprKind, ExprPrecedence, + LocalKind, MacCall, Mutability, Pat, PatField, PatFieldsRest, PatKind, Path, QSelf, RangeEnd, + RangeSyntax, Stmt, StmtKind, }; use rustc_ast_pretty::pprust; -use rustc_errors::{Applicability, Diag, PResult}; +use rustc_errors::{Applicability, Diag, DiagArgValue, PResult, StashKey}; use rustc_session::errors::ExprParenthesesNeeded; use rustc_span::source_map::{respan, Spanned}; use rustc_span::symbol::{kw, sym, Ident}; @@ -21,8 +23,8 @@ use crate::errors::{ InclusiveRangeExtraEquals, InclusiveRangeMatchArrow, InclusiveRangeNoEnd, InvalidMutInPattern, ParenRangeSuggestion, PatternOnWrongSideOfAt, RemoveLet, RepeatedMutInPattern, SwitchRefBoxOrder, TopLevelOrPatternNotAllowed, TopLevelOrPatternNotAllowedSugg, - TrailingVertNotAllowed, UnexpectedExpressionInPattern, UnexpectedLifetimeInPattern, - UnexpectedParenInRangePat, UnexpectedParenInRangePatSugg, + TrailingVertNotAllowed, UnexpectedExpressionInPattern, UnexpectedExpressionInPatternSugg, + UnexpectedLifetimeInPattern, UnexpectedParenInRangePat, UnexpectedParenInRangePatSugg, UnexpectedVertVertBeforeFunctionParam, UnexpectedVertVertInPattern, WrapInParens, }; use crate::parser::expr::{could_be_unclosed_char_literal, DestructuredFloat}; @@ -448,12 +450,219 @@ impl<'a> Parser<'a> { || self.token == token::CloseDelim(Delimiter::Parenthesis) && self.look_ahead(1, Token::is_range_separator); + let span = expr.span; + Some(( - self.dcx().emit_err(UnexpectedExpressionInPattern { span: expr.span, is_bound }), - expr.span, + self.dcx() + .create_err(UnexpectedExpressionInPattern { + span, + is_bound, + expr_precedence: expr.precedence().order(), + }) + .stash(span, StashKey::ExprInPat) + .unwrap(), + span, )) } + /// Called by [`Parser::parse_stmt_without_recovery`], used to add statement-aware subdiagnostics to the errors stashed + /// by [`Parser::maybe_recover_trailing_expr`]. + pub(super) fn maybe_augment_stashed_expr_in_pats_with_suggestions(&mut self, stmt: &Stmt) { + if self.dcx().has_errors().is_none() { + // No need to walk the statement if there's no stashed errors. + return; + } + + struct PatVisitor<'a> { + /// `self` + parser: &'a Parser<'a>, + /// The freshly-parsed statement. + stmt: &'a Stmt, + /// The current match arm (for arm guard suggestions). + arm: Option<&'a Arm>, + /// The current struct field (for variable name suggestions). + field: Option<&'a PatField>, + } + + impl<'a> PatVisitor<'a> { + /// Looks for stashed [`StashKey::ExprInPat`] errors in `stash_span`, and emit them with suggestions. + /// `stash_span` is contained in `expr_span`, the latter being larger in borrow patterns; + /// ```txt + /// &mut x.y + /// -----^^^ `stash_span` + /// | + /// `expr_span` + /// ``` + /// `is_range_bound` is used to exclude arm guard suggestions in range pattern bounds. + fn maybe_add_suggestions_then_emit( + &self, + stash_span: Span, + expr_span: Span, + is_range_bound: bool, + ) { + self.parser.dcx().try_steal_modify_and_emit_err( + stash_span, + StashKey::ExprInPat, + |err| { + // Includes pre-pats (e.g. `&mut `) in the diagnostic. + err.span.replace(stash_span, expr_span); + + let sm = self.parser.psess.source_map(); + let stmt = self.stmt; + let line_lo = sm.span_extend_to_line(stmt.span).shrink_to_lo(); + let indentation = sm.indentation_before(stmt.span).unwrap_or_default(); + let Ok(expr) = self.parser.span_to_snippet(expr_span) else { + // FIXME: some suggestions don't actually need the snippet; see PR #123877's unresolved conversations. + return; + }; + + if let StmtKind::Let(local) = &stmt.kind { + match &local.kind { + LocalKind::Decl | LocalKind::Init(_) => { + // It's kinda hard to guess what the user intended, so don't make suggestions. + return; + } + + LocalKind::InitElse(_, _) => {} + } + } + + // help: use an arm guard `if val == expr` + // FIXME(guard_patterns): suggest this regardless of a match arm. + if let Some(arm) = &self.arm + && !is_range_bound + { + let (ident, ident_span) = match self.field { + Some(field) => { + (field.ident.to_string(), field.ident.span.to(expr_span)) + } + None => ("val".to_owned(), expr_span), + }; + + // Are parentheses required around `expr`? + // HACK: a neater way would be preferable. + let expr = match &err.args["expr_precedence"] { + DiagArgValue::Number(expr_precedence) => { + if *expr_precedence + <= ExprPrecedence::Binary(BinOpKind::Eq).order() as i32 + { + format!("({expr})") + } else { + format!("{expr}") + } + } + _ => unreachable!(), + }; + + match &arm.guard { + None => { + err.subdiagnostic( + UnexpectedExpressionInPatternSugg::CreateGuard { + ident_span, + pat_hi: arm.pat.span.shrink_to_hi(), + ident, + expr, + }, + ); + } + Some(guard) => { + // Are parentheses required around the old guard? + let wrap_guard = guard.precedence().order() + <= ExprPrecedence::Binary(BinOpKind::And).order(); + + err.subdiagnostic( + UnexpectedExpressionInPatternSugg::UpdateGuard { + ident_span, + guard_lo: if wrap_guard { + Some(guard.span.shrink_to_lo()) + } else { + None + }, + guard_hi: guard.span.shrink_to_hi(), + guard_hi_paren: if wrap_guard { ")" } else { "" }, + ident, + expr, + }, + ); + } + } + } + + // help: extract the expr into a `const VAL: _ = expr` + let ident = match self.field { + Some(field) => field.ident.as_str().to_uppercase(), + None => "VAL".to_owned(), + }; + err.subdiagnostic(UnexpectedExpressionInPatternSugg::Const { + stmt_lo: line_lo, + ident_span: expr_span, + expr, + ident, + indentation, + }); + + // help: wrap the expr in a `const { expr }` + // FIXME(inline_const_pat): once stabilized, remove this check and remove the `(requires #[feature(inline_const_pat)])` note from the message + if self.parser.psess.unstable_features.is_nightly_build() { + err.subdiagnostic(UnexpectedExpressionInPatternSugg::InlineConst { + start_span: expr_span.shrink_to_lo(), + end_span: expr_span.shrink_to_hi(), + }); + } + }, + ); + } + } + + impl<'a> Visitor<'a> for PatVisitor<'a> { + fn visit_arm(&mut self, a: &'a Arm) -> Self::Result { + self.arm = Some(a); + visit::walk_arm(self, a); + self.arm = None; + } + + fn visit_pat_field(&mut self, fp: &'a PatField) -> Self::Result { + self.field = Some(fp); + visit::walk_pat_field(self, fp); + self.field = None; + } + + fn visit_pat(&mut self, p: &'a Pat) -> Self::Result { + match &p.kind { + // Base expression + PatKind::Err(_) | PatKind::Lit(_) => { + self.maybe_add_suggestions_then_emit(p.span, p.span, false) + } + + // Sub-patterns + // FIXME: this doesn't work with recursive subpats (`&mut &mut `) + PatKind::Box(subpat) | PatKind::Ref(subpat, _) + if matches!(subpat.kind, PatKind::Err(_) | PatKind::Lit(_)) => + { + self.maybe_add_suggestions_then_emit(subpat.span, p.span, false) + } + + // Sub-expressions + PatKind::Range(start, end, _) => { + if let Some(start) = start { + self.maybe_add_suggestions_then_emit(start.span, start.span, true); + } + + if let Some(end) = end { + self.maybe_add_suggestions_then_emit(end.span, end.span, true); + } + } + + // Walk continuation + _ => visit::walk_pat(self, p), + } + } + } + + // Starts the visit. + PatVisitor { parser: self, stmt, arm: None, field: None }.visit_stmt(stmt); + } + /// Parses a pattern, with a setting whether modern range patterns (e.g., `a..=b`, `a..b` are /// allowed). fn parse_pat_with_range_pat( @@ -845,7 +1054,7 @@ impl<'a> Parser<'a> { self.0 = true; *m = Mutability::Mut; } - walk_pat(self, pat); + mut_visit::walk_pat(self, pat); } } diff --git a/compiler/rustc_parse/src/parser/stmt.rs b/compiler/rustc_parse/src/parser/stmt.rs index 26ad39e06cde5..92fba89d28a1f 100644 --- a/compiler/rustc_parse/src/parser/stmt.rs +++ b/compiler/rustc_parse/src/parser/stmt.rs @@ -29,6 +29,9 @@ use crate::{errors, maybe_whole}; impl<'a> Parser<'a> { /// Parses a statement. This stops just before trailing semicolons on everything but items. /// e.g., a `StmtKind::Semi` parses to a `StmtKind::Expr`, leaving the trailing `;` unconsumed. + /// + /// If `force_collect` is [`ForceCollect::Yes`], forces collection of tokens regardless of + /// whether or not we have attributes. // Public for rustfmt usage. pub(super) fn parse_stmt(&mut self, force_collect: ForceCollect) -> PResult<'a, Option> { Ok(self.parse_stmt_without_recovery(false, force_collect).unwrap_or_else(|e| { @@ -66,7 +69,7 @@ impl<'a> Parser<'a> { }); } - Ok(Some(if self.token.is_keyword(kw::Let) { + let stmt = if self.token.is_keyword(kw::Let) { self.collect_tokens(None, attrs, force_collect, |this, attrs| { this.expect_keyword(kw::Let)?; let local = this.parse_local(attrs)?; @@ -163,7 +166,10 @@ impl<'a> Parser<'a> { } else { self.error_outer_attrs(attrs); return Ok(None); - })) + }; + + self.maybe_augment_stashed_expr_in_pats_with_suggestions(&stmt); + Ok(Some(stmt)) } fn parse_stmt_path_start(&mut self, lo: Span, attrs: AttrWrapper) -> PResult<'a, Stmt> { diff --git a/tests/ui/half-open-range-patterns/range_pat_interactions1.stderr b/tests/ui/half-open-range-patterns/range_pat_interactions1.stderr index c14021e009bd1..9831348de7569 100644 --- a/tests/ui/half-open-range-patterns/range_pat_interactions1.stderr +++ b/tests/ui/half-open-range-patterns/range_pat_interactions1.stderr @@ -3,6 +3,17 @@ error: expected a pattern range bound, found an expression | LL | 0..5+1 => errors_only.push(x), | ^^^ arbitrary expressions are not allowed in patterns + | +help: consider extracting the expression into a `const` + | +LL + const VAL: /* Type */ = 5+1; +LL ~ match x as i32 { +LL ~ 0..VAL => errors_only.push(x), + | +help: consider wrapping the expression in an inline `const` (requires `#![feature(inline_const_pat)]`) + | +LL | 0..const { 5+1 } => errors_only.push(x), + | +++++++ + error[E0408]: variable `n` is not bound in all patterns --> $DIR/range_pat_interactions1.rs:10:25 diff --git a/tests/ui/half-open-range-patterns/range_pat_interactions2.stderr b/tests/ui/half-open-range-patterns/range_pat_interactions2.stderr index 136296fa5b0f0..1b5e875cccb68 100644 --- a/tests/ui/half-open-range-patterns/range_pat_interactions2.stderr +++ b/tests/ui/half-open-range-patterns/range_pat_interactions2.stderr @@ -1,9 +1,3 @@ -error: expected a pattern range bound, found an expression - --> $DIR/range_pat_interactions2.rs:10:18 - | -LL | 0..=(5+1) => errors_only.push(x), - | ^^^ arbitrary expressions are not allowed in patterns - error: range pattern bounds cannot have parentheses --> $DIR/range_pat_interactions2.rs:10:17 | @@ -16,6 +10,23 @@ LL - 0..=(5+1) => errors_only.push(x), LL + 0..=5+1 => errors_only.push(x), | +error: expected a pattern range bound, found an expression + --> $DIR/range_pat_interactions2.rs:10:18 + | +LL | 0..=(5+1) => errors_only.push(x), + | ^^^ arbitrary expressions are not allowed in patterns + | +help: consider extracting the expression into a `const` + | +LL + const VAL: /* Type */ = 5+1; +LL ~ match x as i32 { +LL ~ 0..=(VAL) => errors_only.push(x), + | +help: consider wrapping the expression in an inline `const` (requires `#![feature(inline_const_pat)]`) + | +LL | 0..=(const { 5+1 }) => errors_only.push(x), + | +++++++ + + error[E0658]: inline-const in pattern position is experimental --> $DIR/range_pat_interactions2.rs:15:20 | diff --git a/tests/ui/parser/issues/issue-24375.stderr b/tests/ui/parser/issues/issue-24375.stderr index e6ef07d13fd8d..a25c277d78a5b 100644 --- a/tests/ui/parser/issues/issue-24375.stderr +++ b/tests/ui/parser/issues/issue-24375.stderr @@ -3,6 +3,21 @@ error: expected a pattern, found an expression | LL | tmp[0] => {} | ^^^^^^ arbitrary expressions are not allowed in patterns + | +help: consider moving the expression to a match arm guard + | +LL | val if val == tmp[0] => {} + | ~~~ ++++++++++++++++ +help: consider extracting the expression into a `const` + | +LL + const VAL: /* Type */ = tmp[0]; +LL ~ match z { +LL ~ VAL => {} + | +help: consider wrapping the expression in an inline `const` (requires `#![feature(inline_const_pat)]`) + | +LL | const { tmp[0] } => {} + | +++++++ + error: aborting due to 1 previous error diff --git a/tests/ui/parser/pat-lt-bracket-6.stderr b/tests/ui/parser/pat-lt-bracket-6.stderr index 10c638a63e44c..892883c4aedca 100644 --- a/tests/ui/parser/pat-lt-bracket-6.stderr +++ b/tests/ui/parser/pat-lt-bracket-6.stderr @@ -1,8 +1,8 @@ error: expected a pattern, found an expression - --> $DIR/pat-lt-bracket-6.rs:5:15 + --> $DIR/pat-lt-bracket-6.rs:5:14 | LL | let Test(&desc[..]) = x; - | ^^^^^^^^ arbitrary expressions are not allowed in patterns + | ^^^^^^^^^ arbitrary expressions are not allowed in patterns error[E0308]: mismatched types --> $DIR/pat-lt-bracket-6.rs:10:30 diff --git a/tests/ui/parser/recover/recover-pat-exprs.rs b/tests/ui/parser/recover/recover-pat-exprs.rs index 031e49cb8ebda..e5e25df0c01cc 100644 --- a/tests/ui/parser/recover/recover-pat-exprs.rs +++ b/tests/ui/parser/recover/recover-pat-exprs.rs @@ -53,13 +53,21 @@ fn type_cast() { } } -// ArithmeticOrLogicalExpression +// ArithmeticOrLogicalExpression, also check if parentheses are added as needed fn operator() { match 0 { 1 + 1 => (), //~ error: expected a pattern, found an expression (1 + 2) * 3 => (), //~^ error: expected a pattern, found an expression //~| error: expected a pattern, found an expression + x.0 > 2 => (), //~ error: expected a pattern, found an expression + x.0 == 2 => (), //~ error: expected a pattern, found an expression + } + + // preexisting match arm guard + match (0, 0) { + (x, y.0 > 2) if x != 0 => (), //~ error: expected a pattern, found an expression + (x, y.0 > 2) if x != 0 || x != 1 => (), //~ error: expected a pattern, found an expression } } diff --git a/tests/ui/parser/recover/recover-pat-exprs.stderr b/tests/ui/parser/recover/recover-pat-exprs.stderr index ea8d1458d27c9..63956f35c079f 100644 --- a/tests/ui/parser/recover/recover-pat-exprs.stderr +++ b/tests/ui/parser/recover/recover-pat-exprs.stderr @@ -3,30 +3,117 @@ error: expected a pattern, found an expression | LL | x.y => (), | ^^^ arbitrary expressions are not allowed in patterns + | +help: consider moving the expression to a match arm guard + | +LL | val if val == x.y => (), + | ~~~ +++++++++++++ +help: consider extracting the expression into a `const` + | +LL + const VAL: /* Type */ = x.y; +LL ~ match 0 { +LL | x => (), +LL ~ VAL => (), + | +help: consider wrapping the expression in an inline `const` (requires `#![feature(inline_const_pat)]`) + | +LL | const { x.y } => (), + | +++++++ + error: expected a pattern, found an expression --> $DIR/recover-pat-exprs.rs:6:9 | LL | x.0 => (), | ^^^ arbitrary expressions are not allowed in patterns + | +help: consider moving the expression to a match arm guard + | +LL | val if val == x.0 => (), + | ~~~ +++++++++++++ +help: consider extracting the expression into a `const` + | +LL + const VAL: /* Type */ = x.0; +LL ~ match 0 { +LL | x => (), +LL | x.y => (), +LL ~ VAL => (), + | +help: consider wrapping the expression in an inline `const` (requires `#![feature(inline_const_pat)]`) + | +LL | const { x.0 } => (), + | +++++++ + error: expected a pattern, found an expression --> $DIR/recover-pat-exprs.rs:7:9 | LL | x._0 => (), | ^^^^ arbitrary expressions are not allowed in patterns + | +help: consider moving the expression to a match arm guard + | +LL | val if val == x._0 => (), + | ~~~ ++++++++++++++ +help: consider extracting the expression into a `const` + | +LL + const VAL: /* Type */ = x._0; +LL ~ match 0 { +LL | x => (), +LL | x.y => (), +LL | x.0 => (), +LL ~ VAL => (), + | +help: consider wrapping the expression in an inline `const` (requires `#![feature(inline_const_pat)]`) + | +LL | const { x._0 } => (), + | +++++++ + error: expected a pattern, found an expression --> $DIR/recover-pat-exprs.rs:8:9 | LL | x.0.1 => (), | ^^^^^ arbitrary expressions are not allowed in patterns + | +help: consider moving the expression to a match arm guard + | +LL | val if val == x.0.1 => (), + | ~~~ +++++++++++++++ +help: consider extracting the expression into a `const` + | +LL + const VAL: /* Type */ = x.0.1; +LL ~ match 0 { +LL | x => (), +... +LL | x._0 => (), +LL ~ VAL => (), + | +help: consider wrapping the expression in an inline `const` (requires `#![feature(inline_const_pat)]`) + | +LL | const { x.0.1 } => (), + | +++++++ + error: expected a pattern, found an expression --> $DIR/recover-pat-exprs.rs:9:9 | LL | x.4.y.17.__z => (), | ^^^^^^^^^^^^ arbitrary expressions are not allowed in patterns + | +help: consider moving the expression to a match arm guard + | +LL | val if val == x.4.y.17.__z => (), + | ~~~ ++++++++++++++++++++++ +help: consider extracting the expression into a `const` + | +LL + const VAL: /* Type */ = x.4.y.17.__z; +LL ~ match 0 { +LL | x => (), +... +LL | x.0.1 => (), +LL ~ VAL => (), + | +help: consider wrapping the expression in an inline `const` (requires `#![feature(inline_const_pat)]`) + | +LL | const { x.4.y.17.__z } => (), + | +++++++ + error: expected one of `:`, `;`, `=`, `@`, or `|`, found `.` --> $DIR/recover-pat-exprs.rs:12:12 @@ -63,12 +150,43 @@ error: expected a pattern, found an expression | LL | x[0] => (), | ^^^^ arbitrary expressions are not allowed in patterns + | +help: consider moving the expression to a match arm guard + | +LL | val if val == x[0] => (), + | ~~~ ++++++++++++++ +help: consider extracting the expression into a `const` + | +LL + const VAL: /* Type */ = x[0]; +LL ~ match 0 { +LL ~ VAL => (), + | +help: consider wrapping the expression in an inline `const` (requires `#![feature(inline_const_pat)]`) + | +LL | const { x[0] } => (), + | +++++++ + error: expected a pattern, found an expression --> $DIR/recover-pat-exprs.rs:24:9 | LL | x[..] => (), | ^^^^^ arbitrary expressions are not allowed in patterns + | +help: consider moving the expression to a match arm guard + | +LL | val if val == x[..] => (), + | ~~~ +++++++++++++++ +help: consider extracting the expression into a `const` + | +LL + const VAL: /* Type */ = x[..]; +LL ~ match 0 { +LL | x[0] => (), +LL ~ VAL => (), + | +help: consider wrapping the expression in an inline `const` (requires `#![feature(inline_const_pat)]`) + | +LL | const { x[..] } => (), + | +++++++ + error: expected one of `:`, `;`, `=`, `@`, or `|`, found `[` --> $DIR/recover-pat-exprs.rs:27:12 @@ -102,99 +220,365 @@ error: expected a pattern, found an expression | LL | x.f() => (), | ^^^^^ arbitrary expressions are not allowed in patterns + | +help: consider moving the expression to a match arm guard + | +LL | val if val == x.f() => (), + | ~~~ +++++++++++++++ +help: consider extracting the expression into a `const` + | +LL + const VAL: /* Type */ = x.f(); +LL ~ match 0 { +LL ~ VAL => (), + | +help: consider wrapping the expression in an inline `const` (requires `#![feature(inline_const_pat)]`) + | +LL | const { x.f() } => (), + | +++++++ + error: expected a pattern, found an expression --> $DIR/recover-pat-exprs.rs:38:9 | LL | x._f() => (), | ^^^^^^ arbitrary expressions are not allowed in patterns + | +help: consider moving the expression to a match arm guard + | +LL | val if val == x._f() => (), + | ~~~ ++++++++++++++++ +help: consider extracting the expression into a `const` + | +LL + const VAL: /* Type */ = x._f(); +LL ~ match 0 { +LL | x.f() => (), +LL ~ VAL => (), + | +help: consider wrapping the expression in an inline `const` (requires `#![feature(inline_const_pat)]`) + | +LL | const { x._f() } => (), + | +++++++ + error: expected a pattern, found an expression --> $DIR/recover-pat-exprs.rs:39:9 | LL | x? => (), | ^^ arbitrary expressions are not allowed in patterns + | +help: consider moving the expression to a match arm guard + | +LL | val if val == x? => (), + | ~~~ ++++++++++++ +help: consider extracting the expression into a `const` + | +LL + const VAL: /* Type */ = x?; +LL ~ match 0 { +LL | x.f() => (), +LL | x._f() => (), +LL ~ VAL => (), + | +help: consider wrapping the expression in an inline `const` (requires `#![feature(inline_const_pat)]`) + | +LL | const { x? } => (), + | +++++++ + error: expected a pattern, found an expression --> $DIR/recover-pat-exprs.rs:40:9 | LL | ().f() => (), | ^^^^^^ arbitrary expressions are not allowed in patterns + | +help: consider moving the expression to a match arm guard + | +LL | val if val == ().f() => (), + | ~~~ ++++++++++++++++ +help: consider extracting the expression into a `const` + | +LL + const VAL: /* Type */ = ().f(); +LL ~ match 0 { +LL | x.f() => (), +LL | x._f() => (), +LL | x? => (), +LL ~ VAL => (), + | +help: consider wrapping the expression in an inline `const` (requires `#![feature(inline_const_pat)]`) + | +LL | const { ().f() } => (), + | +++++++ + error: expected a pattern, found an expression --> $DIR/recover-pat-exprs.rs:41:9 | LL | (0, x)?.f() => (), | ^^^^^^^^^^^ arbitrary expressions are not allowed in patterns + | +help: consider moving the expression to a match arm guard + | +LL | val if val == (0, x)?.f() => (), + | ~~~ +++++++++++++++++++++ +help: consider extracting the expression into a `const` + | +LL + const VAL: /* Type */ = (0, x)?.f(); +LL ~ match 0 { +LL | x.f() => (), +... +LL | ().f() => (), +LL ~ VAL => (), + | +help: consider wrapping the expression in an inline `const` (requires `#![feature(inline_const_pat)]`) + | +LL | const { (0, x)?.f() } => (), + | +++++++ + error: expected a pattern, found an expression --> $DIR/recover-pat-exprs.rs:42:9 | LL | x.f().g() => (), | ^^^^^^^^^ arbitrary expressions are not allowed in patterns + | +help: consider moving the expression to a match arm guard + | +LL | val if val == x.f().g() => (), + | ~~~ +++++++++++++++++++ +help: consider extracting the expression into a `const` + | +LL + const VAL: /* Type */ = x.f().g(); +LL ~ match 0 { +LL | x.f() => (), +... +LL | (0, x)?.f() => (), +LL ~ VAL => (), + | +help: consider wrapping the expression in an inline `const` (requires `#![feature(inline_const_pat)]`) + | +LL | const { x.f().g() } => (), + | +++++++ + error: expected a pattern, found an expression --> $DIR/recover-pat-exprs.rs:43:9 | LL | 0.f()?.g()?? => (), | ^^^^^^^^^^^^ arbitrary expressions are not allowed in patterns + | +help: consider moving the expression to a match arm guard + | +LL | val if val == 0.f()?.g()?? => (), + | ~~~ ++++++++++++++++++++++ +help: consider extracting the expression into a `const` + | +LL + const VAL: /* Type */ = 0.f()?.g()??; +LL ~ match 0 { +LL | x.f() => (), +... +LL | x.f().g() => (), +LL ~ VAL => (), + | +help: consider wrapping the expression in an inline `const` (requires `#![feature(inline_const_pat)]`) + | +LL | const { 0.f()?.g()?? } => (), + | +++++++ + error: expected a pattern, found an expression --> $DIR/recover-pat-exprs.rs:50:9 | LL | x as usize => (), | ^^^^^^^^^^ arbitrary expressions are not allowed in patterns + | +help: consider moving the expression to a match arm guard + | +LL | val if val == x as usize => (), + | ~~~ ++++++++++++++++++++ +help: consider extracting the expression into a `const` + | +LL + const VAL: /* Type */ = x as usize; +LL ~ match 0 { +LL ~ VAL => (), + | +help: consider wrapping the expression in an inline `const` (requires `#![feature(inline_const_pat)]`) + | +LL | const { x as usize } => (), + | +++++++ + error: expected a pattern, found an expression --> $DIR/recover-pat-exprs.rs:51:9 | LL | 0 as usize => (), | ^^^^^^^^^^ arbitrary expressions are not allowed in patterns + | +help: consider moving the expression to a match arm guard + | +LL | val if val == 0 as usize => (), + | ~~~ ++++++++++++++++++++ +help: consider extracting the expression into a `const` + | +LL + const VAL: /* Type */ = 0 as usize; +LL ~ match 0 { +LL | x as usize => (), +LL ~ VAL => (), + | +help: consider wrapping the expression in an inline `const` (requires `#![feature(inline_const_pat)]`) + | +LL | const { 0 as usize } => (), + | +++++++ + error: expected a pattern, found an expression --> $DIR/recover-pat-exprs.rs:52:9 | LL | x.f().0.4 as f32 => (), | ^^^^^^^^^^^^^^^^ arbitrary expressions are not allowed in patterns + | +help: consider moving the expression to a match arm guard + | +LL | val if val == x.f().0.4 as f32 => (), + | ~~~ ++++++++++++++++++++++++++ +help: consider extracting the expression into a `const` + | +LL + const VAL: /* Type */ = x.f().0.4 as f32; +LL ~ match 0 { +LL | x as usize => (), +LL | 0 as usize => (), +LL ~ VAL => (), + | +help: consider wrapping the expression in an inline `const` (requires `#![feature(inline_const_pat)]`) + | +LL | const { x.f().0.4 as f32 } => (), + | +++++++ + error: expected a pattern, found an expression --> $DIR/recover-pat-exprs.rs:59:9 | LL | 1 + 1 => (), | ^^^^^ arbitrary expressions are not allowed in patterns - -error: expected a pattern, found an expression - --> $DIR/recover-pat-exprs.rs:60:10 | -LL | (1 + 2) * 3 => (), - | ^^^^^ arbitrary expressions are not allowed in patterns +help: consider moving the expression to a match arm guard + | +LL | val if val == 1 + 1 => (), + | ~~~ +++++++++++++++ +help: consider extracting the expression into a `const` + | +LL + const VAL: /* Type */ = 1 + 1; +LL ~ match 0 { +LL ~ VAL => (), + | +help: consider wrapping the expression in an inline `const` (requires `#![feature(inline_const_pat)]`) + | +LL | const { 1 + 1 } => (), + | +++++++ + error: expected a pattern, found an expression --> $DIR/recover-pat-exprs.rs:60:9 | LL | (1 + 2) * 3 => (), | ^^^^^^^^^^^ arbitrary expressions are not allowed in patterns + | +help: consider moving the expression to a match arm guard + | +LL | val if val == (1 + 2) * 3 => (), + | ~~~ +++++++++++++++++++++ +help: consider extracting the expression into a `const` + | +LL + const VAL: /* Type */ = (1 + 2) * 3; +LL ~ match 0 { +LL | 1 + 1 => (), +LL ~ VAL => (), + | +help: consider wrapping the expression in an inline `const` (requires `#![feature(inline_const_pat)]`) + | +LL | const { (1 + 2) * 3 } => (), + | +++++++ + error: expected a pattern, found an expression - --> $DIR/recover-pat-exprs.rs:67:5 + --> $DIR/recover-pat-exprs.rs:63:9 | -LL | 1 + 2 * PI.cos() => 2, - | ^^^^^^^^^^^^^^^^ arbitrary expressions are not allowed in patterns +LL | x.0 > 2 => (), + | ^^^^^^^ arbitrary expressions are not allowed in patterns + | +help: consider moving the expression to a match arm guard + | +LL | val if val == (x.0 > 2) => (), + | ~~~ +++++++++++++++++++ +help: consider extracting the expression into a `const` + | +LL + const VAL: /* Type */ = x.0 > 2; +LL ~ match 0 { +LL | 1 + 1 => (), +... +LL | +LL ~ VAL => (), + | +help: consider wrapping the expression in an inline `const` (requires `#![feature(inline_const_pat)]`) + | +LL | const { x.0 > 2 } => (), + | +++++++ + error: expected a pattern, found an expression - --> $DIR/recover-pat-exprs.rs:73:9 + --> $DIR/recover-pat-exprs.rs:64:9 | -LL | u8::MAX.abs() => (), - | ^^^^^^^^^^^^^ arbitrary expressions are not allowed in patterns +LL | x.0 == 2 => (), + | ^^^^^^^^ arbitrary expressions are not allowed in patterns + | +help: consider moving the expression to a match arm guard + | +LL | val if val == (x.0 == 2) => (), + | ~~~ ++++++++++++++++++++ +help: consider extracting the expression into a `const` + | +LL + const VAL: /* Type */ = x.0 == 2; +LL ~ match 0 { +LL | 1 + 1 => (), +... +LL | x.0 > 2 => (), +LL ~ VAL => (), + | +help: consider wrapping the expression in an inline `const` (requires `#![feature(inline_const_pat)]`) + | +LL | const { x.0 == 2 } => (), + | +++++++ + error: expected a pattern, found an expression - --> $DIR/recover-pat-exprs.rs:75:9 + --> $DIR/recover-pat-exprs.rs:69:13 | -LL | x.sqrt() @ .. => (), - | ^^^^^^^^ arbitrary expressions are not allowed in patterns +LL | (x, y.0 > 2) if x != 0 => (), + | ^^^^^^^ arbitrary expressions are not allowed in patterns + | +help: consider moving the expression to the match arm guard + | +LL | (x, val) if x != 0 && val == (y.0 > 2) => (), + | ~~~ +++++++++++++++++++ +help: consider extracting the expression into a `const` + | +LL + const VAL: /* Type */ = y.0 > 2; +LL ~ match (0, 0) { +LL ~ (x, VAL) if x != 0 => (), + | +help: consider wrapping the expression in an inline `const` (requires `#![feature(inline_const_pat)]`) + | +LL | (x, const { y.0 > 2 }) if x != 0 => (), + | +++++++ + + +error: expected a pattern, found an expression + --> $DIR/recover-pat-exprs.rs:70:13 + | +LL | (x, y.0 > 2) if x != 0 || x != 1 => (), + | ^^^^^^^ arbitrary expressions are not allowed in patterns + | +help: consider moving the expression to the match arm guard + | +LL | (x, val) if (x != 0 || x != 1) && val == (y.0 > 2) => (), + | ~~~ + +++++++++++++++++++++ +help: consider extracting the expression into a `const` + | +LL + const VAL: /* Type */ = y.0 > 2; +LL ~ match (0, 0) { +LL | (x, y.0 > 2) if x != 0 => (), +LL ~ (x, VAL) if x != 0 || x != 1 => (), + | +help: consider wrapping the expression in an inline `const` (requires `#![feature(inline_const_pat)]`) + | +LL | (x, const { y.0 > 2 }) if x != 0 || x != 1 => (), + | +++++++ + error: left-hand side of `@` must be a binding - --> $DIR/recover-pat-exprs.rs:75:9 + --> $DIR/recover-pat-exprs.rs:83:9 | LL | x.sqrt() @ .. => (), | --------^^^-- @@ -204,50 +588,161 @@ LL | x.sqrt() @ .. => (), | = note: bindings are `x`, `mut x`, `ref x`, and `ref mut x` +error: expected one of `)`, `,`, or `|`, found `+` + --> $DIR/recover-pat-exprs.rs:97:12 + | +LL | (_ + 1) => (), + | ^ expected one of `)`, `,`, or `|` + +error: expected a pattern, found an expression + --> $DIR/recover-pat-exprs.rs:81:9 + | +LL | u8::MAX.abs() => (), + | ^^^^^^^^^^^^^ arbitrary expressions are not allowed in patterns + | +help: consider moving the expression to a match arm guard + | +LL | val if val == u8::MAX.abs() => (), + | ~~~ +++++++++++++++++++++++ +help: consider extracting the expression into a `const` + | +LL + const VAL: /* Type */ = u8::MAX.abs(); +LL ~ match u8::MAX { +LL ~ VAL => (), + | +help: consider wrapping the expression in an inline `const` (requires `#![feature(inline_const_pat)]`) + | +LL | const { u8::MAX.abs() } => (), + | +++++++ + + error: expected a pattern, found an expression - --> $DIR/recover-pat-exprs.rs:78:17 + --> $DIR/recover-pat-exprs.rs:86:17 | LL | z @ w @ v.u() => (), | ^^^^^ arbitrary expressions are not allowed in patterns + | +help: consider moving the expression to a match arm guard + | +LL | z @ w @ val if val == v.u() => (), + | ~~~ +++++++++++++++ +help: consider extracting the expression into a `const` + | +LL + const VAL: /* Type */ = v.u(); +LL ~ match u8::MAX { +LL | u8::MAX.abs() => (), +... +LL | +LL ~ z @ w @ VAL => (), + | +help: consider wrapping the expression in an inline `const` (requires `#![feature(inline_const_pat)]`) + | +LL | z @ w @ const { v.u() } => (), + | +++++++ + error: expected a pattern, found an expression - --> $DIR/recover-pat-exprs.rs:80:9 + --> $DIR/recover-pat-exprs.rs:88:9 | LL | y.ilog(3) => (), | ^^^^^^^^^ arbitrary expressions are not allowed in patterns + | +help: consider moving the expression to a match arm guard + | +LL | val if val == y.ilog(3) => (), + | ~~~ +++++++++++++++++++ +help: consider extracting the expression into a `const` + | +LL + const VAL: /* Type */ = y.ilog(3); +LL ~ match u8::MAX { +LL | u8::MAX.abs() => (), +... +LL | +LL ~ VAL => (), + | +help: consider wrapping the expression in an inline `const` (requires `#![feature(inline_const_pat)]`) + | +LL | const { y.ilog(3) } => (), + | +++++++ + error: expected a pattern, found an expression - --> $DIR/recover-pat-exprs.rs:82:9 + --> $DIR/recover-pat-exprs.rs:90:9 | LL | n + 1 => (), | ^^^^^ arbitrary expressions are not allowed in patterns + | +help: consider moving the expression to a match arm guard + | +LL | val if val == n + 1 => (), + | ~~~ +++++++++++++++ +help: consider extracting the expression into a `const` + | +LL + const VAL: /* Type */ = n + 1; +LL ~ match u8::MAX { +LL | u8::MAX.abs() => (), +... +LL | +LL ~ VAL => (), + | +help: consider wrapping the expression in an inline `const` (requires `#![feature(inline_const_pat)]`) + | +LL | const { n + 1 } => (), + | +++++++ + error: expected a pattern, found an expression - --> $DIR/recover-pat-exprs.rs:84:10 + --> $DIR/recover-pat-exprs.rs:92:10 | LL | ("".f() + 14 * 8) => (), | ^^^^^^^^^^^^^^^ arbitrary expressions are not allowed in patterns + | +help: consider moving the expression to a match arm guard + | +LL | (val) if val == "".f() + 14 * 8 => (), + | ~~~ +++++++++++++++++++++++++ +help: consider extracting the expression into a `const` + | +LL + const VAL: /* Type */ = "".f() + 14 * 8; +LL ~ match u8::MAX { +LL | u8::MAX.abs() => (), +... +LL | +LL ~ (VAL) => (), + | +help: consider wrapping the expression in an inline `const` (requires `#![feature(inline_const_pat)]`) + | +LL | (const { "".f() + 14 * 8 }) => (), + | +++++++ + error: expected a pattern, found an expression - --> $DIR/recover-pat-exprs.rs:87:9 + --> $DIR/recover-pat-exprs.rs:95:9 | LL | f?() => (), | ^^^^ arbitrary expressions are not allowed in patterns - -error: expected one of `)`, `,`, or `|`, found `+` - --> $DIR/recover-pat-exprs.rs:89:12 | -LL | (_ + 1) => (), - | ^ expected one of `)`, `,`, or `|` +help: consider moving the expression to a match arm guard + | +LL | val if val == f?() => (), + | ~~~ ++++++++++++++ +help: consider extracting the expression into a `const` + | +LL + const VAL: /* Type */ = f?(); +LL ~ match u8::MAX { +LL | u8::MAX.abs() => (), +... +LL | 0 | ((1) | 2) | 3 => (), +LL ~ VAL => (), + | +help: consider wrapping the expression in an inline `const` (requires `#![feature(inline_const_pat)]`) + | +LL | const { f?() } => (), + | +++++++ + error: expected a pattern, found an expression - --> $DIR/recover-pat-exprs.rs:93:9 + --> $DIR/recover-pat-exprs.rs:101:9 | LL | let 1 + 1 = 2; | ^^^^^ arbitrary expressions are not allowed in patterns error: expected one of `)`, `,`, `@`, or `|`, found `*` - --> $DIR/recover-pat-exprs.rs:96:28 + --> $DIR/recover-pat-exprs.rs:104:28 | LL | let b = matches!(x, (x * x | x.f()) | x[0]); | ^ expected one of `)`, `,`, `@`, or `|` @@ -255,5 +750,23 @@ LL | let b = matches!(x, (x * x | x.f()) | x[0]); | = note: while parsing argument for this `pat` macro fragment -error: aborting due to 41 previous errors +error: expected a pattern, found an expression + --> $DIR/recover-pat-exprs.rs:60:10 + | +LL | (1 + 2) * 3 => (), + | ^^^^^ arbitrary expressions are not allowed in patterns + +error: expected a pattern, found an expression + --> $DIR/recover-pat-exprs.rs:75:5 + | +LL | 1 + 2 * PI.cos() => 2, + | ^^^^^^^^^^^^^^^^ arbitrary expressions are not allowed in patterns + +error: expected a pattern, found an expression + --> $DIR/recover-pat-exprs.rs:83:9 + | +LL | x.sqrt() @ .. => (), + | ^^^^^^^^ arbitrary expressions are not allowed in patterns + +error: aborting due to 45 previous errors diff --git a/tests/ui/parser/recover/recover-pat-issues.stderr b/tests/ui/parser/recover/recover-pat-issues.stderr index 793091bb1f1c2..596bff2139525 100644 --- a/tests/ui/parser/recover/recover-pat-issues.stderr +++ b/tests/ui/parser/recover/recover-pat-issues.stderr @@ -3,36 +3,111 @@ error: expected a pattern, found an expression | LL | Foo("hi".to_owned()) => true, | ^^^^^^^^^^^^^^^ arbitrary expressions are not allowed in patterns + | +help: consider moving the expression to a match arm guard + | +LL | Foo(val) if val == "hi".to_owned() => true, + | ~~~ +++++++++++++++++++++++++ +help: consider extracting the expression into a `const` + | +LL + const VAL: /* Type */ = "hi".to_owned(); +LL ~ match foo { +LL ~ Foo(VAL) => true, + | +help: consider wrapping the expression in an inline `const` (requires `#![feature(inline_const_pat)]`) + | +LL | Foo(const { "hi".to_owned() }) => true, + | +++++++ + error: expected a pattern, found an expression --> $DIR/recover-pat-issues.rs:14:20 | LL | Bar { baz: "hi".to_owned() } => true, | ^^^^^^^^^^^^^^^ arbitrary expressions are not allowed in patterns + | +help: consider moving the expression to a match arm guard + | +LL | Bar { baz } if baz == "hi".to_owned() => true, + | ~~~ +++++++++++++++++++++++++ +help: consider extracting the expression into a `const` + | +LL + const BAZ: /* Type */ = "hi".to_owned(); +LL ~ match bar { +LL ~ Bar { baz: BAZ } => true, + | +help: consider wrapping the expression in an inline `const` (requires `#![feature(inline_const_pat)]`) + | +LL | Bar { baz: const { "hi".to_owned() } } => true, + | +++++++ + error: expected a pattern, found an expression --> $DIR/recover-pat-issues.rs:25:11 | LL | &["foo".to_string()] => {} | ^^^^^^^^^^^^^^^^^ arbitrary expressions are not allowed in patterns + | +help: consider moving the expression to a match arm guard + | +LL | &[val] if val == "foo".to_string() => {} + | ~~~ +++++++++++++++++++++++++++ +help: consider extracting the expression into a `const` + | +LL + const VAL: /* Type */ = "foo".to_string(); +LL ~ match foo.as_slice() { +LL ~ &[VAL] => {} + | +help: consider wrapping the expression in an inline `const` (requires `#![feature(inline_const_pat)]`) + | +LL | &[const { "foo".to_string() }] => {} + | +++++++ + error: expected a pattern, found an expression --> $DIR/recover-pat-issues.rs:36:17 | LL | if let Some(MAGIC.0 as usize) = None:: {} | ^^^^^^^^^^^^^^^^ arbitrary expressions are not allowed in patterns + | +help: consider extracting the expression into a `const` + | +LL + const VAL: /* Type */ = MAGIC.0 as usize; +LL ~ if let Some(VAL) = None:: {} + | +help: consider wrapping the expression in an inline `const` (requires `#![feature(inline_const_pat)]`) + | +LL | if let Some(const { MAGIC.0 as usize }) = None:: {} + | +++++++ + error: expected a pattern, found an expression --> $DIR/recover-pat-issues.rs:41:13 | LL | if let (-1.some(4)) = (0, Some(4)) {} | ^^^^^^^^^^ arbitrary expressions are not allowed in patterns + | +help: consider extracting the expression into a `const` + | +LL + const VAL: /* Type */ = -1.some(4); +LL ~ if let (VAL) = (0, Some(4)) {} + | +help: consider wrapping the expression in an inline `const` (requires `#![feature(inline_const_pat)]`) + | +LL | if let (const { -1.some(4) }) = (0, Some(4)) {} + | +++++++ + error: expected a pattern, found an expression --> $DIR/recover-pat-issues.rs:44:13 | LL | if let (-1.Some(4)) = (0, Some(4)) {} | ^^^^^^^^^^ arbitrary expressions are not allowed in patterns + | +help: consider extracting the expression into a `const` + | +LL + const VAL: /* Type */ = -1.Some(4); +LL ~ if let (VAL) = (0, Some(4)) {} + | +help: consider wrapping the expression in an inline `const` (requires `#![feature(inline_const_pat)]`) + | +LL | if let (const { -1.Some(4) }) = (0, Some(4)) {} + | +++++++ + error: aborting due to 6 previous errors diff --git a/tests/ui/parser/recover/recover-pat-lets.stderr b/tests/ui/parser/recover/recover-pat-lets.stderr index b1d2a9b96d984..e54586b092483 100644 --- a/tests/ui/parser/recover/recover-pat-lets.stderr +++ b/tests/ui/parser/recover/recover-pat-lets.stderr @@ -21,12 +21,32 @@ error: expected a pattern, found an expression | LL | let Some(1 + 1) = x else { | ^^^^^ arbitrary expressions are not allowed in patterns + | +help: consider extracting the expression into a `const` + | +LL + const VAL: /* Type */ = 1 + 1; +LL ~ let Some(VAL) = x else { + | +help: consider wrapping the expression in an inline `const` (requires `#![feature(inline_const_pat)]`) + | +LL | let Some(const { 1 + 1 }) = x else { + | +++++++ + error: expected a pattern, found an expression --> $DIR/recover-pat-lets.rs:17:17 | LL | if let Some(1 + 1) = x { | ^^^^^ arbitrary expressions are not allowed in patterns + | +help: consider extracting the expression into a `const` + | +LL + const VAL: /* Type */ = 1 + 1; +LL ~ if let Some(VAL) = x { + | +help: consider wrapping the expression in an inline `const` (requires `#![feature(inline_const_pat)]`) + | +LL | if let Some(const { 1 + 1 }) = x { + | +++++++ + error: aborting due to 5 previous errors diff --git a/tests/ui/parser/recover/recover-pat-ranges.stderr b/tests/ui/parser/recover/recover-pat-ranges.stderr index 62ef7a8a908c2..088f83b0ccbac 100644 --- a/tests/ui/parser/recover/recover-pat-ranges.stderr +++ b/tests/ui/parser/recover/recover-pat-ranges.stderr @@ -46,12 +46,6 @@ LL - (0)..=(-4) => (), LL + (0)..=-4 => (), | -error: expected a pattern range bound, found an expression - --> $DIR/recover-pat-ranges.rs:11:12 - | -LL | ..=1 + 2 => (), - | ^^^^^ arbitrary expressions are not allowed in patterns - error: range pattern bounds cannot have parentheses --> $DIR/recover-pat-ranges.rs:13:9 | @@ -64,12 +58,6 @@ LL - (4).. => (), LL + 4.. => (), | -error: expected a pattern range bound, found an expression - --> $DIR/recover-pat-ranges.rs:15:10 - | -LL | (-4 + 0).. => (), - | ^^^^^^ arbitrary expressions are not allowed in patterns - error: range pattern bounds cannot have parentheses --> $DIR/recover-pat-ranges.rs:15:9 | @@ -82,12 +70,6 @@ LL - (-4 + 0).. => (), LL + -4 + 0.. => (), | -error: expected a pattern range bound, found an expression - --> $DIR/recover-pat-ranges.rs:18:10 - | -LL | (1 + 4)...1 * 2 => (), - | ^^^^^ arbitrary expressions are not allowed in patterns - error: range pattern bounds cannot have parentheses --> $DIR/recover-pat-ranges.rs:18:9 | @@ -100,23 +82,125 @@ LL - (1 + 4)...1 * 2 => (), LL + 1 + 4...1 * 2 => (), | +error: expected a pattern range bound, found an expression + --> $DIR/recover-pat-ranges.rs:11:12 + | +LL | ..=1 + 2 => (), + | ^^^^^ arbitrary expressions are not allowed in patterns + | +help: consider extracting the expression into a `const` + | +LL + const VAL: /* Type */ = 1 + 2; +LL ~ match -1 { +LL | 0..=1 => (), +... +LL | +LL ~ ..=VAL => (), + | +help: consider wrapping the expression in an inline `const` (requires `#![feature(inline_const_pat)]`) + | +LL | ..=const { 1 + 2 } => (), + | +++++++ + + +error: expected a pattern range bound, found an expression + --> $DIR/recover-pat-ranges.rs:15:10 + | +LL | (-4 + 0).. => (), + | ^^^^^^ arbitrary expressions are not allowed in patterns + | +help: consider extracting the expression into a `const` + | +LL + const VAL: /* Type */ = -4 + 0; +LL ~ match -1 { +LL | 0..=1 => (), +... +LL | +LL ~ (VAL).. => (), + | +help: consider wrapping the expression in an inline `const` (requires `#![feature(inline_const_pat)]`) + | +LL | (const { -4 + 0 }).. => (), + | +++++++ + + +error: expected a pattern range bound, found an expression + --> $DIR/recover-pat-ranges.rs:18:10 + | +LL | (1 + 4)...1 * 2 => (), + | ^^^^^ arbitrary expressions are not allowed in patterns + | +help: consider extracting the expression into a `const` + | +LL + const VAL: /* Type */ = 1 + 4; +LL ~ match -1 { +LL | 0..=1 => (), +... +LL | +LL ~ (VAL)...1 * 2 => (), + | +help: consider wrapping the expression in an inline `const` (requires `#![feature(inline_const_pat)]`) + | +LL | (const { 1 + 4 })...1 * 2 => (), + | +++++++ + + error: expected a pattern range bound, found an expression --> $DIR/recover-pat-ranges.rs:18:19 | LL | (1 + 4)...1 * 2 => (), | ^^^^^ arbitrary expressions are not allowed in patterns + | +help: consider extracting the expression into a `const` + | +LL + const VAL: /* Type */ = 1 * 2; +LL ~ match -1 { +LL | 0..=1 => (), +... +LL | +LL ~ (1 + 4)...VAL => (), + | +help: consider wrapping the expression in an inline `const` (requires `#![feature(inline_const_pat)]`) + | +LL | (1 + 4)...const { 1 * 2 } => (), + | +++++++ + error: expected a pattern range bound, found an expression --> $DIR/recover-pat-ranges.rs:24:9 | LL | 0.x()..="y".z() => (), | ^^^^^ arbitrary expressions are not allowed in patterns + | +help: consider extracting the expression into a `const` + | +LL + const VAL: /* Type */ = 0.x(); +LL ~ match -1 { +LL | 0..=1 => (), +... +LL | +LL ~ VAL..="y".z() => (), + | +help: consider wrapping the expression in an inline `const` (requires `#![feature(inline_const_pat)]`) + | +LL | const { 0.x() }..="y".z() => (), + | +++++++ + error: expected a pattern range bound, found an expression --> $DIR/recover-pat-ranges.rs:24:17 | LL | 0.x()..="y".z() => (), | ^^^^^^^ arbitrary expressions are not allowed in patterns + | +help: consider extracting the expression into a `const` + | +LL + const VAL: /* Type */ = "y".z(); +LL ~ match -1 { +LL | 0..=1 => (), +... +LL | +LL ~ 0.x()..=VAL => (), + | +help: consider wrapping the expression in an inline `const` (requires `#![feature(inline_const_pat)]`) + | +LL | 0.x()..=const { "y".z() } => (), + | +++++++ + warning: `...` range patterns are deprecated --> $DIR/recover-pat-ranges.rs:18:16 diff --git a/tests/ui/parser/recover/recover-pat-wildcards.stderr b/tests/ui/parser/recover/recover-pat-wildcards.stderr index 64d477fdeb239..30307726a973b 100644 --- a/tests/ui/parser/recover/recover-pat-wildcards.stderr +++ b/tests/ui/parser/recover/recover-pat-wildcards.stderr @@ -59,12 +59,6 @@ error: expected one of `=>`, `if`, or `|`, found `(` LL | ..(_) => () | ^ expected one of `=>`, `if`, or `|` -error: expected a pattern range bound, found an expression - --> $DIR/recover-pat-wildcards.rs:55:14 - | -LL | 4..=(2 + _) => () - | ^^^^^ arbitrary expressions are not allowed in patterns - error: range pattern bounds cannot have parentheses --> $DIR/recover-pat-wildcards.rs:55:13 | @@ -77,6 +71,23 @@ LL - 4..=(2 + _) => () LL + 4..=2 + _ => () | +error: expected a pattern range bound, found an expression + --> $DIR/recover-pat-wildcards.rs:55:14 + | +LL | 4..=(2 + _) => () + | ^^^^^ arbitrary expressions are not allowed in patterns + | +help: consider extracting the expression into a `const` + | +LL + const VAL: /* Type */ = 2 + _; +LL ~ match 9 { +LL ~ 4..=(VAL) => () + | +help: consider wrapping the expression in an inline `const` (requires `#![feature(inline_const_pat)]`) + | +LL | 4..=(const { 2 + _ }) => () + | +++++++ + + error: aborting due to 11 previous errors For more information about this error, try `rustc --explain E0586`.