From aed48be2402bbd3aaccb71c4eb3504ee9a5b486e Mon Sep 17 00:00:00 2001 From: Lieselotte <52315535+she3py@users.noreply.github.com> Date: Sat, 9 Dec 2023 11:02:11 +0100 Subject: [PATCH] Handle methodcalls & operators in patterns --- compiler/rustc_parse/messages.ftl | 9 + compiler/rustc_parse/src/errors.rs | 37 +++ compiler/rustc_parse/src/parser/expr.rs | 9 +- compiler/rustc_parse/src/parser/pat.rs | 252 ++++++++++++++++-- .../range_pat_interactions1.rs | 7 +- .../range_pat_interactions1.stderr | 53 +++- .../range_pat_interactions2.rs | 9 +- .../range_pat_interactions2.stderr | 67 ++++- .../attribute/attr-stmt-expr-attr-bad.rs | 6 +- .../attribute/attr-stmt-expr-attr-bad.stderr | 12 +- tests/ui/parser/issues/issue-24197.rs | 2 +- tests/ui/parser/issues/issue-24197.stderr | 6 +- tests/ui/parser/issues/issue-24375.rs | 2 +- tests/ui/parser/issues/issue-24375.stderr | 6 +- tests/ui/parser/match-arm-without-body.stderr | 8 +- tests/ui/parser/pat-lt-bracket-1.rs | 2 +- tests/ui/parser/pat-lt-bracket-1.stderr | 4 +- tests/ui/parser/pat-lt-bracket-5.rs | 4 +- tests/ui/parser/pat-lt-bracket-5.stderr | 15 +- tests/ui/parser/pat-lt-bracket-6.rs | 3 +- tests/ui/parser/pat-lt-bracket-6.stderr | 30 ++- tests/ui/parser/pat-ranges-3.rs | 6 +- tests/ui/parser/pat-ranges-3.stderr | 14 +- tests/ui/parser/pat-ranges-4.rs | 6 - tests/ui/parser/pat-ranges-4.stderr | 8 - tests/ui/pattern/recover_exprs.rs | 27 ++ tests/ui/pattern/recover_exprs.stderr | 79 ++++++ tests/ui/pattern/recover_methodcalls.rs | 37 +++ tests/ui/pattern/recover_methodcalls.stderr | 35 +++ tests/ui/pattern/recover_ranges.rs | 19 ++ tests/ui/pattern/recover_ranges.stderr | 80 ++++++ tests/ui/pattern/recover_wildcards.rs | 62 +++++ tests/ui/pattern/recover_wildcards.stderr | 77 ++++++ 33 files changed, 896 insertions(+), 97 deletions(-) delete mode 100644 tests/ui/parser/pat-ranges-4.rs delete mode 100644 tests/ui/parser/pat-ranges-4.stderr create mode 100644 tests/ui/pattern/recover_exprs.rs create mode 100644 tests/ui/pattern/recover_exprs.stderr create mode 100644 tests/ui/pattern/recover_methodcalls.rs create mode 100644 tests/ui/pattern/recover_methodcalls.stderr create mode 100644 tests/ui/pattern/recover_ranges.rs create mode 100644 tests/ui/pattern/recover_ranges.stderr create mode 100644 tests/ui/pattern/recover_wildcards.rs create mode 100644 tests/ui/pattern/recover_wildcards.stderr diff --git a/compiler/rustc_parse/messages.ftl b/compiler/rustc_parse/messages.ftl index 363b8f4bfb9cc..2a96e3eb64a83 100644 --- a/compiler/rustc_parse/messages.ftl +++ b/compiler/rustc_parse/messages.ftl @@ -766,12 +766,21 @@ parse_unexpected_const_param_declaration = unexpected `const` parameter declarat parse_unexpected_default_value_for_lifetime_in_generic_parameters = unexpected default lifetime parameter .label = lifetime parameters cannot have default values +parse_unexpected_expr_in_pat = expected pattern, found expression + .label = expressions are not allowed in patterns + parse_unexpected_if_with_if = unexpected `if` in the condition expression .suggestion = remove the `if` parse_unexpected_lifetime_in_pattern = unexpected lifetime `{$symbol}` in pattern .suggestion = remove the lifetime +parse_unexpected_methodcall_in_pat = expected pattern, found method call + .label = method calls are not allowed in patterns + +parse_unexpected_paren_in_range_pat = range pattern bounds cannot have parentheses +parse_unexpected_paren_in_range_pat_sugg = remove these parentheses + parse_unexpected_parentheses_in_for_head = unexpected parentheses surrounding `for` loop head .suggestion = remove parentheses in `for` loop diff --git a/compiler/rustc_parse/src/errors.rs b/compiler/rustc_parse/src/errors.rs index bc53ab83439d1..ace86ccbb3dd1 100644 --- a/compiler/rustc_parse/src/errors.rs +++ b/compiler/rustc_parse/src/errors.rs @@ -2372,6 +2372,43 @@ pub(crate) struct ExpectedCommaAfterPatternField { pub span: Span, } +#[derive(Diagnostic)] +#[diag(parse_unexpected_methodcall_in_pat)] +pub(crate) struct MethodCallInPattern { + #[primary_span] + #[label] + pub span: Span, +} + +#[derive(Diagnostic)] +#[diag(parse_unexpected_expr_in_pat)] +pub(crate) struct ExpressionInPattern { + #[primary_span] + #[label] + pub span: Span, +} + +#[derive(Diagnostic)] +#[diag(parse_unexpected_paren_in_range_pat)] +pub(crate) struct ParenInRangePat { + #[primary_span] + pub span: Span, + #[subdiagnostic] + pub sugg: ParenInRangePatSugg, +} + +#[derive(Subdiagnostic)] +#[multipart_suggestion( + parse_unexpected_paren_in_range_pat_sugg, + applicability = "machine-applicable" +)] +pub(crate) struct ParenInRangePatSugg { + #[suggestion_part(code = "")] + pub open_span: Span, + #[suggestion_part(code = "")] + pub close_span: Span, +} + #[derive(Diagnostic)] #[diag(parse_return_types_use_thin_arrow)] pub(crate) struct ReturnTypesUseThinArrow { diff --git a/compiler/rustc_parse/src/parser/expr.rs b/compiler/rustc_parse/src/parser/expr.rs index 406a6def019ef..40a9af3c2e97f 100644 --- a/compiler/rustc_parse/src/parser/expr.rs +++ b/compiler/rustc_parse/src/parser/expr.rs @@ -2915,7 +2915,14 @@ impl<'a> Parser<'a> { let is_almost_fat_arrow = TokenKind::FatArrow .similar_tokens() .is_some_and(|similar_tokens| similar_tokens.contains(&this.token.kind)); - let mut result = if !is_fat_arrow && !is_almost_fat_arrow { + + // this avoids the compiler saying that a `,` or `}` was expected even though + // the pattern isn't a never pattern (and thus an arm body is required) + let armless = + matches!(this.token.kind, token::Comma | token::CloseDelim(Delimiter::Brace)) + || (!is_fat_arrow && !is_almost_fat_arrow && pat.could_be_never_pattern()); + + let mut result = if armless { // A pattern without a body, allowed for never patterns. arm_body = None; this.expect_one_of(&[token::Comma], &[token::CloseDelim(Delimiter::Brace)]) diff --git a/compiler/rustc_parse/src/parser/pat.rs b/compiler/rustc_parse/src/parser/pat.rs index 020b66a985a96..6b3a43ac392c0 100644 --- a/compiler/rustc_parse/src/parser/pat.rs +++ b/compiler/rustc_parse/src/parser/pat.rs @@ -1,18 +1,20 @@ use super::{ForceCollect, Parser, PathStyle, TrailingToken}; use crate::errors::{ - self, AmbiguousRangePattern, DotDotDotForRemainingFields, DotDotDotRangeToPatternNotAllowed, - DotDotDotRestPattern, EnumPatternInsteadOfIdentifier, ExpectedBindingLeftOfAt, - ExpectedCommaAfterPatternField, GenericArgsInPatRequireTurbofishSyntax, - InclusiveRangeExtraEquals, InclusiveRangeMatchArrow, InclusiveRangeNoEnd, InvalidMutInPattern, - PatternOnWrongSideOfAt, RefMutOrderIncorrect, RemoveLet, RepeatedMutInPattern, - SwitchRefBoxOrder, TopLevelOrPatternNotAllowed, TopLevelOrPatternNotAllowedSugg, - TrailingVertNotAllowed, UnexpectedLifetimeInPattern, UnexpectedVertVertBeforeFunctionParam, - UnexpectedVertVertInPattern, + AmbiguousRangePattern, BoxNotPat, DotDotDotForRemainingFields, + DotDotDotRangeToPatternNotAllowed, DotDotDotRestPattern, EnumPatternInsteadOfIdentifier, + ExpectedBindingLeftOfAt, ExpectedCommaAfterPatternField, ExpressionInPattern, + GenericArgsInPatRequireTurbofishSyntax, InclusiveRangeExtraEquals, InclusiveRangeMatchArrow, + InclusiveRangeNoEnd, InvalidMutInPattern, MethodCallInPattern, ParenInRangePat, + ParenInRangePatSugg, PatternOnWrongSideOfAt, RefMutOrderIncorrect, RemoveLet, + RepeatedMutInPattern, SwitchRefBoxOrder, TopLevelOrPatternNotAllowed, + TopLevelOrPatternNotAllowedSugg, TrailingVertNotAllowed, UnexpectedLifetimeInPattern, + UnexpectedVertVertBeforeFunctionParam, UnexpectedVertVertInPattern, }; +use crate::parser::diagnostics::SnapshotParser; use crate::{maybe_recover_from_interpolated_ty_qpath, maybe_whole}; use rustc_ast::mut_visit::{noop_visit_pat, MutVisitor}; use rustc_ast::ptr::P; -use rustc_ast::token::{self, Delimiter}; +use rustc_ast::token::{self, BinOpToken, Delimiter}; use rustc_ast::{ self as ast, AttrVec, BindingAnnotation, ByRef, Expr, ExprKind, MacCall, Mutability, Pat, PatField, PatKind, Path, QSelf, RangeEnd, RangeSyntax, @@ -334,6 +336,92 @@ impl<'a> Parser<'a> { } } + /// Ensures that the last parsed pattern is not followed by a method call or an binary operator. + /// Returns `pat` if so, else emit an error, consume the `.methodCall()` or the expression and returns [`PatKind::Wild`] + /// (thus discarding the pattern). + fn maybe_recover_methodcall_or_operator( + &mut self, + mut snapshot: SnapshotParser<'a>, + pat: PatKind, + ) -> PatKind { + if self.prev_token.is_keyword(kw::Underscore) || !self.may_recover() { + // don't recover anything after an `_` or if recovery is disabled + return pat; + } + + // `expr.span` may contains a full range, but it's the `start..` that contains an expression, so respan only until the range operator + // also stop at `Eq` so only the left hand is spanned in `let 10 + 3 = 12` + fn respan(this: &mut Parser<'_>, lo: Span, expr: P) -> Span { + fn should_stop(this: &mut Parser<'_>, expr: &P) -> bool { + // stop at `..=`, `...` or `=` + matches!(this.token.kind, token::DotDotDot | token::DotDotEq | token::Eq) || + // `..` may be a rest pattern, so don't stop for `(..`, ` [..` and `, ..` + this.token.kind == token::DotDot && !matches!(this.prev_token.kind, token::OpenDelim(Delimiter::Parenthesis | Delimiter::Bracket) | token::Comma) || + // stop at `|` as it's a new pattern + this.token.kind == token::BinOp(BinOpToken::Or) || + // we shouldn't leave the parsed expression + !expr.span.contains(this.token.span) || + // we should stop after an eof + this.token.kind == token::Eof + } + + while !should_stop(this, &expr) { + this.bump(); + } + + lo.to(this.prev_token.span) + } + + // check for `.hello()`, but allow `.Hello()` to be recovered as `, Hello()` in `parse_seq_to_before_tokens()`. + if self.check_noexpect(&token::Dot) + && self.look_ahead(1, |tok| { + tok.ident() + .and_then(|(ident, _)| ident.name.to_string().chars().next()) + .is_some_and(char::is_lowercase) + }) + && self.look_ahead(2, |tok| tok.kind == token::OpenDelim(Delimiter::Parenthesis)) + { + let span = snapshot.token.span; + + if let Ok(expr) = snapshot.parse_expr().map_err(|err| err.cancel()) { + // we could have `.hello() + something`, so let's parse only the methodcall + self.bump(); // . + self.bump(); // hello + self.parse_paren_comma_seq(|f| f.parse_expr()).unwrap(); // (arg0, arg1, ...) + + let span = span.to(self.prev_token.span); + let expr_span = respan(self, span, expr); + + if span != expr_span { + // we got something after the methodcall + self.sess.emit_err(ExpressionInPattern { span: expr_span }); + } else { + // we only have a methodcall + self.sess.emit_err(MethodCallInPattern { span }); + } + + return PatKind::Wild; + } + } + + // `|` is excluded as it be used in pattern alternatives and lambdas, + // `[` is included for indexing operations + if self.look_ahead(0, |tok| { + matches!(tok.kind, token::BinOp(op) if op != BinOpToken::Or) + || tok.kind == token::OpenDelim(Delimiter::Bracket) + }) { + let span = snapshot.token.span; + + if let Ok(expr) = snapshot.parse_expr().map_err(|err| err.cancel()) { + self.sess.emit_err(ExpressionInPattern { span: respan(self, span, expr) }); + + return PatKind::Wild; + } + } + + pat + } + /// Parses a pattern, with a setting whether modern range patterns (e.g., `a..=b`, `a..b` are /// allowed). fn parse_pat_with_range_pat( @@ -418,6 +506,8 @@ impl<'a> Parser<'a> { // they are dealt with later in resolve. self.parse_pat_ident(BindingAnnotation::NONE, syntax_loc)? } else if self.is_start_of_pat_with_path() { + let snapshot = self.create_snapshot_for_diagnostic(); + // Parse pattern starting with a path let (qself, path) = if self.eat_lt() { // Parse a qualified path @@ -439,7 +529,7 @@ impl<'a> Parser<'a> { } else if self.check(&token::OpenDelim(Delimiter::Parenthesis)) { self.parse_pat_tuple_struct(qself, path)? } else { - PatKind::Path(qself, path) + self.maybe_recover_methodcall_or_operator(snapshot, PatKind::Path(qself, path)) } } else if matches!(self.token.kind, token::Lifetime(_)) // In pattern position, we're totally fine with using "next token isn't colon" @@ -465,12 +555,25 @@ impl<'a> Parser<'a> { }); PatKind::Lit(self.mk_expr(lo, ExprKind::Lit(lit))) } else { + let snapshot = self.create_snapshot_for_diagnostic(); + // Try to parse everything else as literal with optional minus match self.parse_literal_maybe_minus() { - Ok(begin) => match self.parse_range_end() { - Some(form) => self.parse_pat_range_begin_with(begin, form)?, - None => PatKind::Lit(begin), - }, + Ok(begin) => { + // `maybe_recover_methodcall_or_operator` returns `Wild` if it has recovered, + // so just pass `Never` or any other non-`Wild` unit type to check if it has recovered + let recovered = matches!( + self.maybe_recover_methodcall_or_operator(snapshot, PatKind::Never), + PatKind::Wild + ); + + let pat = match self.parse_range_end() { + Some(form) => self.parse_pat_range_begin_with(begin, form)?, + None => PatKind::Lit(begin), + }; + + if recovered { PatKind::Wild } else { pat } + } Err(err) => return self.fatal_unexpected_non_pat(err, expected), } }; @@ -579,6 +682,8 @@ impl<'a> Parser<'a> { /// Parse a tuple or parenthesis pattern. fn parse_pat_tuple_or_parens(&mut self) -> PResult<'a, PatKind> { + let open_paren_span = self.token.span; + let (fields, trailing_comma) = self.parse_paren_comma_seq(|p| { p.parse_pat_allow_top_alt( None, @@ -591,7 +696,58 @@ impl<'a> Parser<'a> { // Here, `(pat,)` is a tuple pattern. // For backward compatibility, `(..)` is a tuple pattern as well. Ok(if fields.len() == 1 && !(trailing_comma || fields[0].is_rest()) { - PatKind::Paren(fields.into_iter().next().unwrap()) + let pat = fields.into_iter().next().unwrap(); + let close_paren_span = self.prev_token.span; + + match &pat.kind { + // recover ranges with parentheses around the `(start)..` + PatKind::Lit(begin) if let Some(form) = self.parse_range_end() => { + self.sess.emit_err(ParenInRangePat { + span: open_paren_span.to(close_paren_span), + sugg: ParenInRangePatSugg { + open_span: open_paren_span, + close_span: close_paren_span, + }, + }); + + self.parse_pat_range_begin_with(begin.clone(), form)? + } + // HACK: `self.maybe_recover_methodcall_or_operator` will recover the pat to `_` if the pat isn't valid, + // so let's just check if `_..pat` is valid + // the `recover_wildcards` test will check that `_..pat` won't actually compile + PatKind::Wild + if matches!( + self.token.kind, + token::DotDotDot | token::DotDotEq | token::DotDot + ) => + { + let form = self.parse_range_end().unwrap(); + let form = respan( + form.span, + match form.node { + // `...` is not allowed in `parse_pat_range_to` + RangeEnd::Included(_) => RangeEnd::Included(RangeSyntax::DotDotEq), + re => re, + }, + ); + self.parse_pat_range_to(form)?; + + self.sess.emit_err(ParenInRangePat { + span: open_paren_span.to(close_paren_span), + sugg: ParenInRangePatSugg { + open_span: open_paren_span, + close_span: close_paren_span, + }, + }); + + // the `start..` wasn't a valid start pat to begin with, + // so let's just return `_` (pat) as a recovery + PatKind::Paren(pat) + } + + // (pat) with optional parentheses + _ => PatKind::Paren(pat), + } } else { PatKind::Tuple(fields) }) @@ -727,18 +883,43 @@ impl<'a> Parser<'a> { begin: P, re: Spanned, ) -> PResult<'a, PatKind> { - let end = if self.is_pat_range_end_start(0) { + // recover from `(` + let paren = + matches!(self.token.kind, token::OpenDelim(Delimiter::Parenthesis)).then(|| { + self.bump(); + self.prev_token.span + }); + + let (end, snapshot) = if self.is_pat_range_end_start(0) { + let snapshot = self.create_snapshot_for_diagnostic(); + // Parsing e.g. `X..=Y`. - Some(self.parse_pat_range_end()?) + (Some(self.parse_pat_range_end()?), Some(snapshot)) } else { // Parsing e.g. `X..`. if let RangeEnd::Included(_) = re.node { // FIXME(Centril): Consider semantic errors instead in `ast_validation`. self.inclusive_range_with_incorrect_end(); } - None + (None, None) + }; + + let pat = PatKind::Range(Some(begin), end, re); + let pat = match snapshot { + Some(snapshot) => self.maybe_recover_methodcall_or_operator(snapshot, pat), + None => pat, // no need to recover unbounded ranges }; - Ok(PatKind::Range(Some(begin), end, re)) + + if let Some(span) = paren { + self.expect(&token::CloseDelim(Delimiter::Parenthesis))?; + + self.sess.emit_err(ParenInRangePat { + span: span.to(self.prev_token.span), + sugg: ParenInRangePatSugg { open_span: span, close_span: self.prev_token.span }, + }); + } + + Ok(pat) } pub(super) fn inclusive_range_with_incorrect_end(&mut self) { @@ -777,12 +958,32 @@ impl<'a> Parser<'a> { /// The form `...X` is prohibited to reduce confusion with the potential /// expression syntax `...expr` for splatting in expressions. fn parse_pat_range_to(&mut self, mut re: Spanned) -> PResult<'a, PatKind> { + // recover from `(` + let paren = + matches!(self.token.kind, token::OpenDelim(Delimiter::Parenthesis)).then(|| { + self.bump(); + self.prev_token.span + }); + + let snapshot = self.create_snapshot_for_diagnostic(); + let end = self.parse_pat_range_end()?; if let RangeEnd::Included(syn @ RangeSyntax::DotDotDot) = &mut re.node { *syn = RangeSyntax::DotDotEq; self.sess.emit_err(DotDotDotRangeToPatternNotAllowed { span: re.span }); } - Ok(PatKind::Range(None, Some(end), re)) + + if let Some(span) = paren { + self.expect(&token::CloseDelim(Delimiter::Parenthesis))?; + + self.sess.emit_err(ParenInRangePat { + span: span.to(self.prev_token.span), + sugg: ParenInRangePatSugg { open_span: span, close_span: self.prev_token.span }, + }); + } + + let pat = PatKind::Range(None, Some(end), re); + Ok(self.maybe_recover_methodcall_or_operator(snapshot, pat)) } /// Is the token `dist` away from the current suitable as the start of a range patterns end? @@ -794,6 +995,7 @@ impl<'a> Parser<'a> { || t.can_begin_literal_maybe_minus() // e.g. `42`. || t.is_whole_expr() || t.is_lifetime() // recover `'a` instead of `'a'` + || (t.kind == token::OpenDelim(Delimiter::Parenthesis) && self.is_pat_range_end_start(dist + 1)) // recover leading `(` }) } @@ -847,6 +1049,7 @@ impl<'a> Parser<'a> { binding_annotation: BindingAnnotation, syntax_loc: Option, ) -> PResult<'a, PatKind> { + let snapshot = self.create_snapshot_for_diagnostic(); let ident = self.parse_ident_common(false)?; if self.may_recover() @@ -876,7 +1079,12 @@ impl<'a> Parser<'a> { .into_diagnostic(self.diagnostic())); } - Ok(PatKind::Ident(binding_annotation, ident, sub)) + let has_subpat = sub.is_some(); + let pat = PatKind::Ident(binding_annotation, ident, sub); + + // check for methodcalls after the `ident`, + // but not `ident @ pat` as `pat` was already checked and `ident` ends with `@` + Ok(if !has_subpat { self.maybe_recover_methodcall_or_operator(snapshot, pat) } else { pat }) } /// Parse a struct ("record") pattern (e.g. `Foo { ... }` or `Foo::Bar { ... }`). @@ -940,7 +1148,7 @@ impl<'a> Parser<'a> { if self.isnt_pattern_start() { let descr = super::token_descr(&self.token); - self.sess.emit_err(errors::BoxNotPat { + self.sess.emit_err(BoxNotPat { span: self.token.span, kw: box_span, lo: box_span.shrink_to_lo(), diff --git a/tests/ui/half-open-range-patterns/range_pat_interactions1.rs b/tests/ui/half-open-range-patterns/range_pat_interactions1.rs index 9ffc2190d20d1..6e536cfe8595e 100644 --- a/tests/ui/half-open-range-patterns/range_pat_interactions1.rs +++ b/tests/ui/half-open-range-patterns/range_pat_interactions1.rs @@ -17,12 +17,17 @@ fn main() { } match x as i32 { 0..5+1 => errors_only.push(x), - //~^ error: expected one of `,`, `=>`, `if`, `|`, or `}`, found `+` + //~^ error: expected pattern, found expression 1 | -3..0 => first_or.push(x), + //~^ error: exclusive range pattern syntax is experimental y @ (0..5 | 6) => or_two.push(y), + //~^ error: exclusive range pattern syntax is experimental y @ 0..const { 5 + 1 } => assert_eq!(y, 5), + //~^ error: exclusive range pattern syntax is experimental + //~| error: inline-const in pattern position is experimental y @ -5.. => range_from.push(y), y @ ..-7 => assert_eq!(y, -8), + //~^ error: exclusive range pattern syntax is experimental y => bottom.push(y), } } 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 05235c9b92295..0c42c0cc87945 100644 --- a/tests/ui/half-open-range-patterns/range_pat_interactions1.stderr +++ b/tests/ui/half-open-range-patterns/range_pat_interactions1.stderr @@ -1,8 +1,8 @@ -error: expected one of `,`, `=>`, `if`, `|`, or `}`, found `+` - --> $DIR/range_pat_interactions1.rs:19:17 +error: expected pattern, found expression + --> $DIR/range_pat_interactions1.rs:19:16 | LL | 0..5+1 => errors_only.push(x), - | ^ expected one of `,`, `=>`, `if`, `|`, or `}` + | ^^^ expressions are not allowed in patterns error[E0408]: variable `n` is not bound in all patterns --> $DIR/range_pat_interactions1.rs:10:25 @@ -12,6 +12,15 @@ LL | if let n @ 2..3|4 = x { | | | variable not in all patterns +error[E0658]: inline-const in pattern position is experimental + --> $DIR/range_pat_interactions1.rs:25:20 + | +LL | y @ 0..const { 5 + 1 } => assert_eq!(y, 5), + | ^^^^^ + | + = note: see issue #76001 for more information + = help: add `#![feature(inline_const_pat)]` to the crate attributes to enable + error[E0658]: exclusive range pattern syntax is experimental --> $DIR/range_pat_interactions1.rs:10:20 | @@ -30,7 +39,43 @@ LL | } else if let 2..3 | 4 = x { = note: see issue #37854 for more information = help: add `#![feature(exclusive_range_pattern)]` to the crate attributes to enable -error: aborting due to 4 previous errors +error[E0658]: exclusive range pattern syntax is experimental + --> $DIR/range_pat_interactions1.rs:21:17 + | +LL | 1 | -3..0 => first_or.push(x), + | ^^^^^ + | + = note: see issue #37854 for more information + = help: add `#![feature(exclusive_range_pattern)]` to the crate attributes to enable + +error[E0658]: exclusive range pattern syntax is experimental + --> $DIR/range_pat_interactions1.rs:23:18 + | +LL | y @ (0..5 | 6) => or_two.push(y), + | ^^^^ + | + = note: see issue #37854 for more information + = help: add `#![feature(exclusive_range_pattern)]` to the crate attributes to enable + +error[E0658]: exclusive range pattern syntax is experimental + --> $DIR/range_pat_interactions1.rs:25:17 + | +LL | y @ 0..const { 5 + 1 } => assert_eq!(y, 5), + | ^^^^^^^^^^^^^^^^^^ + | + = note: see issue #37854 for more information + = help: add `#![feature(exclusive_range_pattern)]` to the crate attributes to enable + +error[E0658]: exclusive range pattern syntax is experimental + --> $DIR/range_pat_interactions1.rs:29:17 + | +LL | y @ ..-7 => assert_eq!(y, -8), + | ^^^^ + | + = note: see issue #37854 for more information + = help: add `#![feature(exclusive_range_pattern)]` to the crate attributes to enable + +error: aborting due to 9 previous errors Some errors have detailed explanations: E0408, E0658. For more information about an error, try `rustc --explain E0408`. diff --git a/tests/ui/half-open-range-patterns/range_pat_interactions2.rs b/tests/ui/half-open-range-patterns/range_pat_interactions2.rs index b212bfbe093eb..829d985b0f442 100644 --- a/tests/ui/half-open-range-patterns/range_pat_interactions2.rs +++ b/tests/ui/half-open-range-patterns/range_pat_interactions2.rs @@ -8,13 +8,18 @@ fn main() { for x in -9 + 1..=(9 - 2) { match x as i32 { 0..=(5+1) => errors_only.push(x), - //~^ error: inclusive range with no end - //~| error: expected one of `,`, `=>`, `if`, `|`, or `}`, found `(` + //~^ error: expected pattern, found expression + //~| error: range pattern bounds cannot have parentheses 1 | -3..0 => first_or.push(x), + //~^ error: exclusive range pattern syntax is experimental y @ (0..5 | 6) => or_two.push(y), + //~^ error: exclusive range pattern syntax is experimental y @ 0..const { 5 + 1 } => assert_eq!(y, 5), + //~^ error: inline-const in pattern position is experimental + //~| error: exclusive range pattern syntax is experimental y @ -5.. => range_from.push(y), y @ ..-7 => assert_eq!(y, -8), + //~^ error: exclusive range pattern syntax is experimental y => bottom.push(y), } } 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 0129f927e3464..8e72138f6fca3 100644 --- a/tests/ui/half-open-range-patterns/range_pat_interactions2.stderr +++ b/tests/ui/half-open-range-patterns/range_pat_interactions2.stderr @@ -1,17 +1,66 @@ -error[E0586]: inclusive range with no end - --> $DIR/range_pat_interactions2.rs:10:14 +error: expected pattern, found expression + --> $DIR/range_pat_interactions2.rs:10:18 | LL | 0..=(5+1) => errors_only.push(x), - | ^^^ help: use `..` instead - | - = note: inclusive ranges must be bounded at the end (`..=b` or `a..=b`) + | ^^^ expressions are not allowed in patterns -error: expected one of `,`, `=>`, `if`, `|`, or `}`, found `(` +error: range pattern bounds cannot have parentheses --> $DIR/range_pat_interactions2.rs:10:17 | LL | 0..=(5+1) => errors_only.push(x), - | ^ expected one of `,`, `=>`, `if`, `|`, or `}` + | ^^^^^ + | +help: remove these parentheses + | +LL - 0..=(5+1) => errors_only.push(x), +LL + 0..=5+1 => errors_only.push(x), + | + +error[E0658]: inline-const in pattern position is experimental + --> $DIR/range_pat_interactions2.rs:17:20 + | +LL | y @ 0..const { 5 + 1 } => assert_eq!(y, 5), + | ^^^^^ + | + = note: see issue #76001 for more information + = help: add `#![feature(inline_const_pat)]` to the crate attributes to enable + +error[E0658]: exclusive range pattern syntax is experimental + --> $DIR/range_pat_interactions2.rs:13:17 + | +LL | 1 | -3..0 => first_or.push(x), + | ^^^^^ + | + = note: see issue #37854 for more information + = help: add `#![feature(exclusive_range_pattern)]` to the crate attributes to enable + +error[E0658]: exclusive range pattern syntax is experimental + --> $DIR/range_pat_interactions2.rs:15:18 + | +LL | y @ (0..5 | 6) => or_two.push(y), + | ^^^^ + | + = note: see issue #37854 for more information + = help: add `#![feature(exclusive_range_pattern)]` to the crate attributes to enable + +error[E0658]: exclusive range pattern syntax is experimental + --> $DIR/range_pat_interactions2.rs:17:17 + | +LL | y @ 0..const { 5 + 1 } => assert_eq!(y, 5), + | ^^^^^^^^^^^^^^^^^^ + | + = note: see issue #37854 for more information + = help: add `#![feature(exclusive_range_pattern)]` to the crate attributes to enable + +error[E0658]: exclusive range pattern syntax is experimental + --> $DIR/range_pat_interactions2.rs:21:17 + | +LL | y @ ..-7 => assert_eq!(y, -8), + | ^^^^ + | + = note: see issue #37854 for more information + = help: add `#![feature(exclusive_range_pattern)]` to the crate attributes to enable -error: aborting due to 2 previous errors +error: aborting due to 7 previous errors -For more information about this error, try `rustc --explain E0586`. +For more information about this error, try `rustc --explain E0658`. diff --git a/tests/ui/parser/attribute/attr-stmt-expr-attr-bad.rs b/tests/ui/parser/attribute/attr-stmt-expr-attr-bad.rs index 2c402e4c65e23..d1950087c4c2d 100644 --- a/tests/ui/parser/attribute/attr-stmt-expr-attr-bad.rs +++ b/tests/ui/parser/attribute/attr-stmt-expr-attr-bad.rs @@ -84,15 +84,15 @@ fn main() {} #[cfg(FALSE)] fn e() { match 0 { 0..=#[attr] 10 => () } } //~^ ERROR inclusive range with no end -//~| ERROR expected one of `,`, `=>`, `if`, `|`, or `}`, found `#` +//~| ERROR expected one of `=>`, `if`, or `|`, found `#` #[cfg(FALSE)] fn e() { match 0 { 0..=#[attr] -10 => () } } //~^ ERROR inclusive range with no end -//~| ERROR expected one of `,`, `=>`, `if`, `|`, or `}`, found `#` +//~| ERROR expected one of `=>`, `if`, or `|`, found `#` #[cfg(FALSE)] fn e() { match 0 { 0..=-#[attr] 10 => () } } //~^ ERROR unexpected token: `#` #[cfg(FALSE)] fn e() { match 0 { 0..=#[attr] FOO => () } } //~^ ERROR inclusive range with no end -//~| ERROR expected one of `,`, `=>`, `if`, `|`, or `}`, found `#` +//~| ERROR expected one of `=>`, `if`, or `|`, found `#` #[cfg(FALSE)] fn e() { let _ = x.#![attr]foo(); } //~^ ERROR unexpected token: `#` diff --git a/tests/ui/parser/attribute/attr-stmt-expr-attr-bad.stderr b/tests/ui/parser/attribute/attr-stmt-expr-attr-bad.stderr index a0e95c5c1ed32..e46c591080d43 100644 --- a/tests/ui/parser/attribute/attr-stmt-expr-attr-bad.stderr +++ b/tests/ui/parser/attribute/attr-stmt-expr-attr-bad.stderr @@ -365,11 +365,11 @@ LL | #[cfg(FALSE)] fn e() { match 0 { 0..=#[attr] 10 => () } } | = note: inclusive ranges must be bounded at the end (`..=b` or `a..=b`) -error: expected one of `,`, `=>`, `if`, `|`, or `}`, found `#` +error: expected one of `=>`, `if`, or `|`, found `#` --> $DIR/attr-stmt-expr-attr-bad.rs:85:38 | LL | #[cfg(FALSE)] fn e() { match 0 { 0..=#[attr] 10 => () } } - | ^ expected one of `,`, `=>`, `if`, `|`, or `}` + | ^ expected one of `=>`, `if`, or `|` error[E0586]: inclusive range with no end --> $DIR/attr-stmt-expr-attr-bad.rs:88:35 @@ -379,11 +379,11 @@ LL | #[cfg(FALSE)] fn e() { match 0 { 0..=#[attr] -10 => () } } | = note: inclusive ranges must be bounded at the end (`..=b` or `a..=b`) -error: expected one of `,`, `=>`, `if`, `|`, or `}`, found `#` +error: expected one of `=>`, `if`, or `|`, found `#` --> $DIR/attr-stmt-expr-attr-bad.rs:88:38 | LL | #[cfg(FALSE)] fn e() { match 0 { 0..=#[attr] -10 => () } } - | ^ expected one of `,`, `=>`, `if`, `|`, or `}` + | ^ expected one of `=>`, `if`, or `|` error: unexpected token: `#` --> $DIR/attr-stmt-expr-attr-bad.rs:91:39 @@ -399,11 +399,11 @@ LL | #[cfg(FALSE)] fn e() { match 0 { 0..=#[attr] FOO => () } } | = note: inclusive ranges must be bounded at the end (`..=b` or `a..=b`) -error: expected one of `,`, `=>`, `if`, `|`, or `}`, found `#` +error: expected one of `=>`, `if`, or `|`, found `#` --> $DIR/attr-stmt-expr-attr-bad.rs:93:38 | LL | #[cfg(FALSE)] fn e() { match 0 { 0..=#[attr] FOO => () } } - | ^ expected one of `,`, `=>`, `if`, `|`, or `}` + | ^ expected one of `=>`, `if`, or `|` error: unexpected token: `#` --> $DIR/attr-stmt-expr-attr-bad.rs:97:34 diff --git a/tests/ui/parser/issues/issue-24197.rs b/tests/ui/parser/issues/issue-24197.rs index aaf5137461fa6..f59586ffdc776 100644 --- a/tests/ui/parser/issues/issue-24197.rs +++ b/tests/ui/parser/issues/issue-24197.rs @@ -1,3 +1,3 @@ fn main() { - let buf[0] = 0; //~ ERROR expected one of `:`, `;`, `=`, `@`, or `|`, found `[` + let buf[0] = 0; //~ error: expected pattern, found expression } diff --git a/tests/ui/parser/issues/issue-24197.stderr b/tests/ui/parser/issues/issue-24197.stderr index 3ef707f3953cf..d402b745c6553 100644 --- a/tests/ui/parser/issues/issue-24197.stderr +++ b/tests/ui/parser/issues/issue-24197.stderr @@ -1,8 +1,8 @@ -error: expected one of `:`, `;`, `=`, `@`, or `|`, found `[` - --> $DIR/issue-24197.rs:2:12 +error: expected pattern, found expression + --> $DIR/issue-24197.rs:2:9 | LL | let buf[0] = 0; - | ^ expected one of `:`, `;`, `=`, `@`, or `|` + | ^^^^^^ expressions are not allowed in patterns error: aborting due to 1 previous error diff --git a/tests/ui/parser/issues/issue-24375.rs b/tests/ui/parser/issues/issue-24375.rs index 8d1bc579e7b84..721ebc908942f 100644 --- a/tests/ui/parser/issues/issue-24375.rs +++ b/tests/ui/parser/issues/issue-24375.rs @@ -3,7 +3,7 @@ static tmp : [&'static str; 2] = ["hello", "he"]; fn main() { let z = "hello"; match z { - tmp[0] => {} //~ ERROR expected one of `,`, `=>`, `@`, `if`, `|`, or `}`, found `[` + tmp[0] => {} //~ error: expected pattern, found expression _ => {} } } diff --git a/tests/ui/parser/issues/issue-24375.stderr b/tests/ui/parser/issues/issue-24375.stderr index 2b980a5520fdb..ae636e5cfa277 100644 --- a/tests/ui/parser/issues/issue-24375.stderr +++ b/tests/ui/parser/issues/issue-24375.stderr @@ -1,8 +1,8 @@ -error: expected one of `,`, `=>`, `@`, `if`, `|`, or `}`, found `[` - --> $DIR/issue-24375.rs:6:12 +error: expected pattern, found expression + --> $DIR/issue-24375.rs:6:9 | LL | tmp[0] => {} - | ^ expected one of `,`, `=>`, `@`, `if`, `|`, or `}` + | ^^^^^^ expressions are not allowed in patterns error: aborting due to 1 previous error diff --git a/tests/ui/parser/match-arm-without-body.stderr b/tests/ui/parser/match-arm-without-body.stderr index 3a06ed050b562..b588cb47b6d36 100644 --- a/tests/ui/parser/match-arm-without-body.stderr +++ b/tests/ui/parser/match-arm-without-body.stderr @@ -1,8 +1,8 @@ -error: expected one of `,`, `=>`, `if`, `|`, or `}`, found reserved identifier `_` +error: expected one of `=>`, `if`, or `|`, found reserved identifier `_` --> $DIR/match-arm-without-body.rs:13:9 | LL | Some(_) - | - expected one of `,`, `=>`, `if`, `|`, or `}` + | - expected one of `=>`, `if`, or `|` LL | _ => {} | ^ unexpected token @@ -44,11 +44,11 @@ LL + LL ~ _ => {} | -error: expected one of `,`, `.`, `=>`, `?`, `}`, or an operator, found reserved identifier `_` +error: expected one of `.`, `=>`, `?`, or an operator, found reserved identifier `_` --> $DIR/match-arm-without-body.rs:36:9 | LL | Some(_) if true - | - expected one of `,`, `.`, `=>`, `?`, `}`, or an operator + | - expected one of `.`, `=>`, `?`, or an operator LL | _ => {} | ^ unexpected token diff --git a/tests/ui/parser/pat-lt-bracket-1.rs b/tests/ui/parser/pat-lt-bracket-1.rs index 33da15adb9e40..2e2001434f28c 100644 --- a/tests/ui/parser/pat-lt-bracket-1.rs +++ b/tests/ui/parser/pat-lt-bracket-1.rs @@ -1,7 +1,7 @@ fn main() { match 42 { x < 7 => (), - //~^ error: expected one of `,`, `=>`, `@`, `if`, `|`, or `}`, found `<` + //~^ error: expected one of `=>`, `@`, `if`, or `|`, found `<` _ => () } } diff --git a/tests/ui/parser/pat-lt-bracket-1.stderr b/tests/ui/parser/pat-lt-bracket-1.stderr index f39487052ade4..14e679bbee073 100644 --- a/tests/ui/parser/pat-lt-bracket-1.stderr +++ b/tests/ui/parser/pat-lt-bracket-1.stderr @@ -1,8 +1,8 @@ -error: expected one of `,`, `=>`, `@`, `if`, `|`, or `}`, found `<` +error: expected one of `=>`, `@`, `if`, or `|`, found `<` --> $DIR/pat-lt-bracket-1.rs:3:7 | LL | x < 7 => (), - | ^ expected one of `,`, `=>`, `@`, `if`, `|`, or `}` + | ^ expected one of `=>`, `@`, `if`, or `|` error: aborting due to 1 previous error diff --git a/tests/ui/parser/pat-lt-bracket-5.rs b/tests/ui/parser/pat-lt-bracket-5.rs index aaece1f6bd9cb..26e589a1fc876 100644 --- a/tests/ui/parser/pat-lt-bracket-5.rs +++ b/tests/ui/parser/pat-lt-bracket-5.rs @@ -1,3 +1,5 @@ fn main() { - let v[0] = v[1]; //~ ERROR expected one of `:`, `;`, `=`, `@`, or `|`, found `[` + let v[0] = v[1]; + //~^ error: expected pattern, found expression + //~| error: cannot find value `v` in this scope } diff --git a/tests/ui/parser/pat-lt-bracket-5.stderr b/tests/ui/parser/pat-lt-bracket-5.stderr index e556e6c0206fb..1ade6c1c68fb5 100644 --- a/tests/ui/parser/pat-lt-bracket-5.stderr +++ b/tests/ui/parser/pat-lt-bracket-5.stderr @@ -1,8 +1,15 @@ -error: expected one of `:`, `;`, `=`, `@`, or `|`, found `[` - --> $DIR/pat-lt-bracket-5.rs:2:10 +error: expected pattern, found expression + --> $DIR/pat-lt-bracket-5.rs:2:9 | LL | let v[0] = v[1]; - | ^ expected one of `:`, `;`, `=`, `@`, or `|` + | ^^^^ expressions are not allowed in patterns -error: aborting due to 1 previous error +error[E0425]: cannot find value `v` in this scope + --> $DIR/pat-lt-bracket-5.rs:2:16 + | +LL | let v[0] = v[1]; + | ^ not found in this scope + +error: aborting due to 2 previous errors +For more information about this error, try `rustc --explain E0425`. diff --git a/tests/ui/parser/pat-lt-bracket-6.rs b/tests/ui/parser/pat-lt-bracket-6.rs index 7becffa9fe2f7..8058035a31485 100644 --- a/tests/ui/parser/pat-lt-bracket-6.rs +++ b/tests/ui/parser/pat-lt-bracket-6.rs @@ -3,7 +3,8 @@ fn main() { let x = Test(&0, []); let Test(&desc[..]) = x; - //~^ ERROR: expected one of `)`, `,`, `@`, or `|`, found `[` + //~^ error: expected pattern, found expression + //~| error: this pattern has 1 field, but the corresponding tuple struct has 2 fields } const RECOVERY_WITNESS: () = 0; //~ ERROR mismatched types diff --git a/tests/ui/parser/pat-lt-bracket-6.stderr b/tests/ui/parser/pat-lt-bracket-6.stderr index 035d0dbfe06d6..304f2c1c2311d 100644 --- a/tests/ui/parser/pat-lt-bracket-6.stderr +++ b/tests/ui/parser/pat-lt-bracket-6.stderr @@ -1,18 +1,30 @@ -error: expected one of `)`, `,`, `@`, or `|`, found `[` - --> $DIR/pat-lt-bracket-6.rs:5:19 +error: expected pattern, found expression + --> $DIR/pat-lt-bracket-6.rs:5:15 | LL | let Test(&desc[..]) = x; - | ^ - | | - | expected one of `)`, `,`, `@`, or `|` - | help: missing `,` + | ^^^^^^^^ expressions are not allowed in patterns error[E0308]: mismatched types - --> $DIR/pat-lt-bracket-6.rs:9:30 + --> $DIR/pat-lt-bracket-6.rs:10:30 | LL | const RECOVERY_WITNESS: () = 0; | ^ expected `()`, found integer -error: aborting due to 2 previous errors +error[E0023]: this pattern has 1 field, but the corresponding tuple struct has 2 fields + --> $DIR/pat-lt-bracket-6.rs:5:14 + | +LL | struct Test(&'static u8, [u8; 0]); + | ----------- ------- tuple struct has 2 fields +... +LL | let Test(&desc[..]) = x; + | ^^^^^^^^^ expected 2 fields, found 1 + | +help: use `_` to explicitly ignore each field + | +LL | let Test(&desc[..], _) = x; + | +++ + +error: aborting due to 3 previous errors -For more information about this error, try `rustc --explain E0308`. +Some errors have detailed explanations: E0023, E0308. +For more information about an error, try `rustc --explain E0023`. diff --git a/tests/ui/parser/pat-ranges-3.rs b/tests/ui/parser/pat-ranges-3.rs index 8976dcf0d90f9..ad3b1dcd9061d 100644 --- a/tests/ui/parser/pat-ranges-3.rs +++ b/tests/ui/parser/pat-ranges-3.rs @@ -1,5 +1,9 @@ // Parsing of range patterns fn main() { - let 10 ..= 10 + 3 = 12; //~ expected one of `:`, `;`, `=`, or `|`, found `+` + let 10 ..= 10 + 3 = 12; + //~^ error: expected pattern, found expression + + let 10 - 3 ..= 10 = 8; + //~^ error: expected pattern, found expression } diff --git a/tests/ui/parser/pat-ranges-3.stderr b/tests/ui/parser/pat-ranges-3.stderr index 611b35a650280..25b43c260fbec 100644 --- a/tests/ui/parser/pat-ranges-3.stderr +++ b/tests/ui/parser/pat-ranges-3.stderr @@ -1,8 +1,14 @@ -error: expected one of `:`, `;`, `=`, or `|`, found `+` - --> $DIR/pat-ranges-3.rs:4:19 +error: expected pattern, found expression + --> $DIR/pat-ranges-3.rs:4:16 | LL | let 10 ..= 10 + 3 = 12; - | ^ expected one of `:`, `;`, `=`, or `|` + | ^^^^^^ expressions are not allowed in patterns -error: aborting due to 1 previous error +error: expected pattern, found expression + --> $DIR/pat-ranges-3.rs:7:9 + | +LL | let 10 - 3 ..= 10 = 8; + | ^^^^^^ expressions are not allowed in patterns + +error: aborting due to 2 previous errors diff --git a/tests/ui/parser/pat-ranges-4.rs b/tests/ui/parser/pat-ranges-4.rs deleted file mode 100644 index 61188976b028c..0000000000000 --- a/tests/ui/parser/pat-ranges-4.rs +++ /dev/null @@ -1,6 +0,0 @@ -// Parsing of range patterns - -fn main() { - let 10 - 3 ..= 10 = 8; - //~^ error: expected one of `...`, `..=`, `..`, `:`, `;`, `=`, or `|`, found `-` -} diff --git a/tests/ui/parser/pat-ranges-4.stderr b/tests/ui/parser/pat-ranges-4.stderr deleted file mode 100644 index c30160291d608..0000000000000 --- a/tests/ui/parser/pat-ranges-4.stderr +++ /dev/null @@ -1,8 +0,0 @@ -error: expected one of `...`, `..=`, `..`, `:`, `;`, `=`, or `|`, found `-` - --> $DIR/pat-ranges-4.rs:4:12 - | -LL | let 10 - 3 ..= 10 = 8; - | ^ expected one of 7 possible tokens - -error: aborting due to 1 previous error - diff --git a/tests/ui/pattern/recover_exprs.rs b/tests/ui/pattern/recover_exprs.rs new file mode 100644 index 0000000000000..84ec8d6105b84 --- /dev/null +++ b/tests/ui/pattern/recover_exprs.rs @@ -0,0 +1,27 @@ +fn main() { + match u8::MAX { + u8::MAX.abs() => (), + //~^ error: expected pattern, found method call + x.sqrt() @ .. => (), + //~^ error: expected pattern, found method call + //~| error: left-hand side of `@` must be a binding + z @ w @ v.u() => (), + //~^ error: expected pattern, found method call + y.ilog(3) => (), + //~^ error: expected pattern, found method call + n + 1 => (), + //~^ error: expected pattern, found expression + ("".f() + 14 * 8) => (), + //~^ error: expected pattern, found expression + (_ + 1) => (), + //~^ error: expected one of `)`, `,`, or `|`, found `+` + } + + let 1 + 1 = 2; + //~^ error: expected pattern, found expression + + let b = matches!(x, x * x | x.f() | x[0]); + //~^ error: expected pattern, found expression + //~| error: expected pattern, found method call + //~| error: expected pattern, found expression +} diff --git a/tests/ui/pattern/recover_exprs.stderr b/tests/ui/pattern/recover_exprs.stderr new file mode 100644 index 0000000000000..8a553a4cf6c4a --- /dev/null +++ b/tests/ui/pattern/recover_exprs.stderr @@ -0,0 +1,79 @@ +error: expected pattern, found method call + --> $DIR/recover_exprs.rs:3:9 + | +LL | u8::MAX.abs() => (), + | ^^^^^^^^^^^^^ method calls are not allowed in patterns + +error: expected pattern, found method call + --> $DIR/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/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 pattern, found method call + --> $DIR/recover_exprs.rs:8:17 + | +LL | z @ w @ v.u() => (), + | ^^^^^ method calls are not allowed in patterns + +error: expected pattern, found method call + --> $DIR/recover_exprs.rs:10:9 + | +LL | y.ilog(3) => (), + | ^^^^^^^^^ method calls are not allowed in patterns + +error: expected pattern, found expression + --> $DIR/recover_exprs.rs:12:9 + | +LL | n + 1 => (), + | ^^^^^ expressions are not allowed in patterns + +error: expected pattern, found expression + --> $DIR/recover_exprs.rs:14:10 + | +LL | ("".f() + 14 * 8) => (), + | ^^^^^^^^^^^^^^^ expressions are not allowed in patterns + +error: expected one of `)`, `,`, or `|`, found `+` + --> $DIR/recover_exprs.rs:16:12 + | +LL | (_ + 1) => (), + | ^ expected one of `)`, `,`, or `|` + +error: expected pattern, found expression + --> $DIR/recover_exprs.rs:20:9 + | +LL | let 1 + 1 = 2; + | ^^^^^ expressions are not allowed in patterns + +error: expected pattern, found expression + --> $DIR/recover_exprs.rs:23:25 + | +LL | let b = matches!(x, x * x | x.f() | x[0]); + | ^^^^^ expressions are not allowed in patterns + +error: expected pattern, found method call + --> $DIR/recover_exprs.rs:23:33 + | +LL | let b = matches!(x, x * x | x.f() | x[0]); + | ^^^^^ method calls are not allowed in patterns + +error: expected pattern, found expression + --> $DIR/recover_exprs.rs:23:41 + | +LL | let b = matches!(x, x * x | x.f() | x[0]); + | ^^^^ expressions are not allowed in patterns + +error: aborting due to 12 previous errors + diff --git a/tests/ui/pattern/recover_methodcalls.rs b/tests/ui/pattern/recover_methodcalls.rs new file mode 100644 index 0000000000000..66e42d34f6733 --- /dev/null +++ b/tests/ui/pattern/recover_methodcalls.rs @@ -0,0 +1,37 @@ +struct Foo(String); +struct Bar { baz: String } + +fn foo(foo: Foo) -> bool { + match foo { + Foo("hi".to_owned()) => true, + //~^ error: expected pattern, found method call + _ => false + } +} + +fn bar(bar: Bar) -> bool { + match bar { + Bar { baz: "hi".to_owned() } => true, + //~^ error: expected pattern, found method call + _ => false + } +} + +fn baz() { + let foo = vec!["foo".to_string()]; + + match foo.as_slice() { + &["foo".to_string()] => {} + //~^ error: expected pattern, found method call + _ => {} + }; +} + +fn main() { + if let (-1.some(4)) = (0, Some(4)) {} + //~^ error: expected pattern, found method call + + if let (-1.Some(4)) = (0, Some(4)) {} + //~^ error: expected one of `)`, `,`, `...`, `..=`, `..`, or `|`, found `.` + //~| help: missing `,` +} diff --git a/tests/ui/pattern/recover_methodcalls.stderr b/tests/ui/pattern/recover_methodcalls.stderr new file mode 100644 index 0000000000000..65d971f292e5c --- /dev/null +++ b/tests/ui/pattern/recover_methodcalls.stderr @@ -0,0 +1,35 @@ +error: expected pattern, found method call + --> $DIR/recover_methodcalls.rs:6:13 + | +LL | Foo("hi".to_owned()) => true, + | ^^^^^^^^^^^^^^^ method calls are not allowed in patterns + +error: expected pattern, found method call + --> $DIR/recover_methodcalls.rs:14:20 + | +LL | Bar { baz: "hi".to_owned() } => true, + | ^^^^^^^^^^^^^^^ method calls are not allowed in patterns + +error: expected pattern, found method call + --> $DIR/recover_methodcalls.rs:24:11 + | +LL | &["foo".to_string()] => {} + | ^^^^^^^^^^^^^^^^^ method calls are not allowed in patterns + +error: expected pattern, found method call + --> $DIR/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/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/pattern/recover_ranges.rs b/tests/ui/pattern/recover_ranges.rs new file mode 100644 index 0000000000000..4eb75685517b8 --- /dev/null +++ b/tests/ui/pattern/recover_ranges.rs @@ -0,0 +1,19 @@ +fn main() { + match -1 { + 0..=1 => (), + ..=1 + 2 => (), + //~^ error: expected pattern, found expression + 0..=(1) => (), + //~^ error: range pattern bounds cannot have parentheses + (0)..=(4) => (), + //~^ error: range pattern bounds cannot have parentheses + //~| error: range pattern bounds cannot have parentheses + (1 + 4)...1 * 2 => (), + //~^ error: expected pattern, found expression + //~| error: expected pattern, found expression + //~| error: range pattern bounds cannot have parentheses + 0.x()..="y".z() => (), + //~^ error: expected pattern, found method call + //~| error: expected pattern, found method call + }; +} diff --git a/tests/ui/pattern/recover_ranges.stderr b/tests/ui/pattern/recover_ranges.stderr new file mode 100644 index 0000000000000..b4e30cb0dd978 --- /dev/null +++ b/tests/ui/pattern/recover_ranges.stderr @@ -0,0 +1,80 @@ +error: expected pattern, found expression + --> $DIR/recover_ranges.rs:4:12 + | +LL | ..=1 + 2 => (), + | ^^^^^ expressions are not allowed in patterns + +error: range pattern bounds cannot have parentheses + --> $DIR/recover_ranges.rs:6:13 + | +LL | 0..=(1) => (), + | ^^^ + | +help: remove these parentheses + | +LL - 0..=(1) => (), +LL + 0..=1 => (), + | + +error: range pattern bounds cannot have parentheses + --> $DIR/recover_ranges.rs:8:9 + | +LL | (0)..=(4) => (), + | ^^^ + | +help: remove these parentheses + | +LL - (0)..=(4) => (), +LL + 0..=(4) => (), + | + +error: range pattern bounds cannot have parentheses + --> $DIR/recover_ranges.rs:8:15 + | +LL | (0)..=(4) => (), + | ^^^ + | +help: remove these parentheses + | +LL - (0)..=(4) => (), +LL + (0)..=4 => (), + | + +error: expected pattern, found expression + --> $DIR/recover_ranges.rs:11:10 + | +LL | (1 + 4)...1 * 2 => (), + | ^^^^^ expressions are not allowed in patterns + +error: expected pattern, found expression + --> $DIR/recover_ranges.rs:11:19 + | +LL | (1 + 4)...1 * 2 => (), + | ^^^^^ expressions are not allowed in patterns + +error: range pattern bounds cannot have parentheses + --> $DIR/recover_ranges.rs:11:9 + | +LL | (1 + 4)...1 * 2 => (), + | ^^^^^^^ + | +help: remove these parentheses + | +LL - (1 + 4)...1 * 2 => (), +LL + 1 + 4...1 * 2 => (), + | + +error: expected pattern, found method call + --> $DIR/recover_ranges.rs:15:9 + | +LL | 0.x()..="y".z() => (), + | ^^^^^ method calls are not allowed in patterns + +error: expected pattern, found method call + --> $DIR/recover_ranges.rs:15:17 + | +LL | 0.x()..="y".z() => (), + | ^^^^^^^ method calls are not allowed in patterns + +error: aborting due to 9 previous errors + diff --git a/tests/ui/pattern/recover_wildcards.rs b/tests/ui/pattern/recover_wildcards.rs new file mode 100644 index 0000000000000..121273baee959 --- /dev/null +++ b/tests/ui/pattern/recover_wildcards.rs @@ -0,0 +1,62 @@ +// recovered patterns are transformed as `_`, +// so check that we can't do funny things with them. + +fn a() { + match 1 { + _ + 1 => () //~ error: expected one of `=>`, `if`, or `|`, found `+` + } +} + +fn b() { + match 2 { + (_ % 4) => () //~ error: expected one of `)`, `,`, or `|`, found `%` + } +} + +fn c() { + match 3 { + _.x() => () //~ error: expected one of `=>`, `if`, or `|`, found `.` + } +} + +fn d() { + match 4 { + _..=4 => () //~ error: expected one of `=>`, `if`, or `|`, found `..=` + } +} + +fn e() { + match 5 { + .._ => () //~ error: expected one of `=>`, `if`, or `|`, found reserved identifier `_` + } +} + +fn f() { + match 6 { + 0..._ => () + //~^ error: inclusive range with no end + //~| error: expected one of `=>`, `if`, or `|`, found reserved identifier `_` + } +} + +fn g() { + match 7 { + (_ * 0)..5 => () //~ error: expected one of `)`, `,`, or `|`, found `*` + } +} + +fn h() { + match 8 { + ..(_) => () //~ error: expected one of `=>`, `if`, or `|`, found `(` + } +} + +fn i() { + match 9 { + 4..=(2 + _) => () + //~^ error: expected pattern, found expression + //~| error: range pattern bounds cannot have parentheses + } +} + +fn main() {} diff --git a/tests/ui/pattern/recover_wildcards.stderr b/tests/ui/pattern/recover_wildcards.stderr new file mode 100644 index 0000000000000..37bd7f20a0060 --- /dev/null +++ b/tests/ui/pattern/recover_wildcards.stderr @@ -0,0 +1,77 @@ +error: expected one of `=>`, `if`, or `|`, found `+` + --> $DIR/recover_wildcards.rs:6:11 + | +LL | _ + 1 => () + | ^ expected one of `=>`, `if`, or `|` + +error: expected one of `)`, `,`, or `|`, found `%` + --> $DIR/recover_wildcards.rs:12:12 + | +LL | (_ % 4) => () + | ^ expected one of `)`, `,`, or `|` + +error: expected one of `=>`, `if`, or `|`, found `.` + --> $DIR/recover_wildcards.rs:18:10 + | +LL | _.x() => () + | ^ expected one of `=>`, `if`, or `|` + +error: expected one of `=>`, `if`, or `|`, found `..=` + --> $DIR/recover_wildcards.rs:24:10 + | +LL | _..=4 => () + | ^^^ expected one of `=>`, `if`, or `|` + +error: expected one of `=>`, `if`, or `|`, found reserved identifier `_` + --> $DIR/recover_wildcards.rs:30:11 + | +LL | .._ => () + | ^ expected one of `=>`, `if`, or `|` + +error[E0586]: inclusive range with no end + --> $DIR/recover_wildcards.rs:36:10 + | +LL | 0..._ => () + | ^^^ help: use `..` instead + | + = note: inclusive ranges must be bounded at the end (`..=b` or `a..=b`) + +error: expected one of `=>`, `if`, or `|`, found reserved identifier `_` + --> $DIR/recover_wildcards.rs:36:13 + | +LL | 0..._ => () + | ^ expected one of `=>`, `if`, or `|` + +error: expected one of `)`, `,`, or `|`, found `*` + --> $DIR/recover_wildcards.rs:44:12 + | +LL | (_ * 0)..5 => () + | ^ expected one of `)`, `,`, or `|` + +error: expected one of `=>`, `if`, or `|`, found `(` + --> $DIR/recover_wildcards.rs:50:11 + | +LL | ..(_) => () + | ^ expected one of `=>`, `if`, or `|` + +error: expected pattern, found expression + --> $DIR/recover_wildcards.rs:56:14 + | +LL | 4..=(2 + _) => () + | ^^^^^ expressions are not allowed in patterns + +error: range pattern bounds cannot have parentheses + --> $DIR/recover_wildcards.rs:56:13 + | +LL | 4..=(2 + _) => () + | ^^^^^^^ + | +help: remove these parentheses + | +LL - 4..=(2 + _) => () +LL + 4..=2 + _ => () + | + +error: aborting due to 11 previous errors + +For more information about this error, try `rustc --explain E0586`.