Handle methodcalls & operators in patterns

This commit is contained in:
Lieselotte 2024-01-28 16:12:21 +01:00
parent 6351247048
commit 6f014a81b2
No known key found for this signature in database
GPG key ID: 43A6A32F83A6F9B1
29 changed files with 809 additions and 66 deletions

View file

@ -772,6 +772,20 @@ parse_unexpected_const_param_declaration = unexpected `const` parameter declarat
parse_unexpected_default_value_for_lifetime_in_generic_parameters = unexpected default lifetime parameter parse_unexpected_default_value_for_lifetime_in_generic_parameters = unexpected default lifetime parameter
.label = lifetime parameters cannot have default values .label = lifetime parameters cannot have default values
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
}
.label = {$is_method_call ->
[true] method calls
*[false] arbitrary expressions
} are not allowed in patterns
parse_unexpected_if_with_if = unexpected `if` in the condition expression parse_unexpected_if_with_if = unexpected `if` in the condition expression
.suggestion = remove the `if` .suggestion = remove the `if`

View file

@ -2415,6 +2415,18 @@ pub(crate) struct ExpectedCommaAfterPatternField {
pub span: Span, pub span: Span,
} }
#[derive(Diagnostic)]
#[diag(parse_unexpected_expr_in_pat)]
pub(crate) struct UnexpectedExpressionInPattern {
#[primary_span]
#[label]
pub span: Span,
/// Was a `RangePatternBound` expected?
pub is_bound: bool,
/// Was the unexpected expression a `MethodCallExpression`?
pub is_method_call: bool,
}
#[derive(Diagnostic)] #[derive(Diagnostic)]
#[diag(parse_unexpected_paren_in_range_pat)] #[diag(parse_unexpected_paren_in_range_pat)]
pub(crate) struct UnexpectedParenInRangePat { pub(crate) struct UnexpectedParenInRangePat {

View file

@ -444,6 +444,19 @@ impl<'a> Parser<'a> {
) if self.restrictions.contains(Restrictions::CONST_EXPR) => { ) if self.restrictions.contains(Restrictions::CONST_EXPR) => {
return None; return None;
} }
// When recovering patterns as expressions, stop parsing when encountering an assignment `=`, an alternative `|`, or a range `..`.
(
Some(
AssocOp::Assign
| AssocOp::AssignOp(_)
| AssocOp::BitOr
| AssocOp::DotDot
| AssocOp::DotDotEq,
),
_,
) if self.restrictions.contains(Restrictions::IS_PAT) => {
return None;
}
(Some(op), _) => (op, self.token.span), (Some(op), _) => (op, self.token.span),
(None, Some((Ident { name: sym::and, span }, false))) if self.may_recover() => { (None, Some((Ident { name: sym::and, span }, false))) if self.may_recover() => {
self.dcx().emit_err(errors::InvalidLogicalOperator { self.dcx().emit_err(errors::InvalidLogicalOperator {

View file

@ -53,6 +53,7 @@ bitflags::bitflags! {
const CONST_EXPR = 1 << 2; const CONST_EXPR = 1 << 2;
const ALLOW_LET = 1 << 3; const ALLOW_LET = 1 << 3;
const IN_IF_GUARD = 1 << 4; const IN_IF_GUARD = 1 << 4;
const IS_PAT = 1 << 5;
} }
} }

View file

@ -1,4 +1,4 @@
use super::{ForceCollect, Parser, PathStyle, TrailingToken}; use super::{ForceCollect, Parser, PathStyle, Restrictions, TrailingToken};
use crate::errors::{ use crate::errors::{
self, AmbiguousRangePattern, DotDotDotForRemainingFields, DotDotDotRangeToPatternNotAllowed, self, AmbiguousRangePattern, DotDotDotForRemainingFields, DotDotDotRangeToPatternNotAllowed,
DotDotDotRestPattern, EnumPatternInsteadOfIdentifier, ExpectedBindingLeftOfAt, DotDotDotRestPattern, EnumPatternInsteadOfIdentifier, ExpectedBindingLeftOfAt,
@ -6,14 +6,14 @@ use crate::errors::{
InclusiveRangeExtraEquals, InclusiveRangeMatchArrow, InclusiveRangeNoEnd, InvalidMutInPattern, InclusiveRangeExtraEquals, InclusiveRangeMatchArrow, InclusiveRangeNoEnd, InvalidMutInPattern,
PatternOnWrongSideOfAt, RefMutOrderIncorrect, RemoveLet, RepeatedMutInPattern, PatternOnWrongSideOfAt, RefMutOrderIncorrect, RemoveLet, RepeatedMutInPattern,
SwitchRefBoxOrder, TopLevelOrPatternNotAllowed, TopLevelOrPatternNotAllowedSugg, SwitchRefBoxOrder, TopLevelOrPatternNotAllowed, TopLevelOrPatternNotAllowedSugg,
TrailingVertNotAllowed, UnexpectedLifetimeInPattern, UnexpectedParenInRangePat, TrailingVertNotAllowed, UnexpectedExpressionInPattern, UnexpectedLifetimeInPattern,
UnexpectedParenInRangePatSugg, UnexpectedVertVertBeforeFunctionParam, UnexpectedParenInRangePat, UnexpectedParenInRangePatSugg,
UnexpectedVertVertInPattern, UnexpectedVertVertBeforeFunctionParam, UnexpectedVertVertInPattern,
}; };
use crate::{maybe_recover_from_interpolated_ty_qpath, maybe_whole}; use crate::{maybe_recover_from_interpolated_ty_qpath, maybe_whole};
use rustc_ast::mut_visit::{noop_visit_pat, MutVisitor}; use rustc_ast::mut_visit::{noop_visit_pat, MutVisitor};
use rustc_ast::ptr::P; use rustc_ast::ptr::P;
use rustc_ast::token::{self, Delimiter}; use rustc_ast::token::{self, BinOpToken, Delimiter, Token};
use rustc_ast::{ use rustc_ast::{
self as ast, AttrVec, BindingAnnotation, ByRef, Expr, ExprKind, MacCall, Mutability, Pat, self as ast, AttrVec, BindingAnnotation, ByRef, Expr, ExprKind, MacCall, Mutability, Pat,
PatField, PatFieldsRest, PatKind, Path, QSelf, RangeEnd, RangeSyntax, PatField, PatFieldsRest, PatKind, Path, QSelf, RangeEnd, RangeSyntax,
@ -23,7 +23,7 @@ use rustc_errors::{Applicability, DiagnosticBuilder, PResult};
use rustc_session::errors::ExprParenthesesNeeded; use rustc_session::errors::ExprParenthesesNeeded;
use rustc_span::source_map::{respan, Spanned}; use rustc_span::source_map::{respan, Spanned};
use rustc_span::symbol::{kw, sym, Ident}; use rustc_span::symbol::{kw, sym, Ident};
use rustc_span::Span; use rustc_span::{ErrorGuaranteed, Span};
use thin_vec::{thin_vec, ThinVec}; use thin_vec::{thin_vec, ThinVec};
#[derive(PartialEq, Copy, Clone)] #[derive(PartialEq, Copy, Clone)]
@ -336,6 +336,95 @@ impl<'a> Parser<'a> {
} }
} }
/// Ensures that the last parsed pattern (or pattern range bound) is not followed by a method call or an operator.
///
/// `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";
/// ```text
/// 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.
#[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<ErrorGuaranteed> {
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)
&& 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, |tok| tok.kind == token::OpenDelim(Delimiter::Parenthesis));
// 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`)
let has_trailing_operator = matches!(self.token.kind, token::BinOp(op) if op != BinOpToken::Or)
|| self.token.kind == token::Question
|| (self.token.kind == token::OpenDelim(Delimiter::Bracket)
&& self.look_ahead(1, |tok| tok.kind != token::CloseDelim(Delimiter::Bracket)));
if !has_trailing_method && !has_trailing_operator {
// Nothing to recover here.
return None;
}
// Let's try to parse an expression to emit a better diagnostic.
let mut snapshot = self.create_snapshot_for_diagnostic();
snapshot.restrictions.insert(Restrictions::IS_PAT);
// Parse `?`, `.f`, `(arg0, arg1, ...)` or `[expr]` until they've all been eaten.
if let Ok(expr) = snapshot
.parse_expr_dot_or_call_with(
self.mk_expr_err(pat_span), // equivalent to transforming the parsed pattern into an `Expr`
pat_span,
AttrVec::new(),
)
.map_err(|err| err.cancel())
{
let non_assoc_span = expr.span;
// Parse an associative expression such as `+ expr`, `% expr`, ...
// Assignements, ranges and `|` are disabled by [`Restrictions::IS_PAT`].
if let Ok(expr) =
snapshot.parse_expr_assoc_with(0, expr.into()).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.kind == 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,
}));
}
}
// We got a trailing method/operator, but we couldn't parse an expression.
None
}
/// Parses a pattern, with a setting whether modern range patterns (e.g., `a..=b`, `a..b` are /// Parses a pattern, with a setting whether modern range patterns (e.g., `a..=b`, `a..b` are
/// allowed). /// allowed).
fn parse_pat_with_range_pat( fn parse_pat_with_range_pat(
@ -441,7 +530,10 @@ impl<'a> Parser<'a> {
} else if self.check(&token::OpenDelim(Delimiter::Parenthesis)) { } else if self.check(&token::OpenDelim(Delimiter::Parenthesis)) {
self.parse_pat_tuple_struct(qself, path)? self.parse_pat_tuple_struct(qself, path)?
} else { } else {
PatKind::Path(qself, path) match self.maybe_recover_trailing_expr(span, false) {
Some(guar) => PatKind::Err(guar),
None => PatKind::Path(qself, path),
}
} }
} else if matches!(self.token.kind, token::Lifetime(_)) } else if matches!(self.token.kind, token::Lifetime(_))
// In pattern position, we're totally fine with using "next token isn't colon" // In pattern position, we're totally fine with using "next token isn't colon"
@ -470,10 +562,17 @@ impl<'a> Parser<'a> {
} else { } else {
// Try to parse everything else as literal with optional minus // Try to parse everything else as literal with optional minus
match self.parse_literal_maybe_minus() { match self.parse_literal_maybe_minus() {
Ok(begin) => match self.parse_range_end() { Ok(begin) => {
Some(form) => self.parse_pat_range_begin_with(begin, form)?, let begin = match self.maybe_recover_trailing_expr(begin.span, false) {
None => PatKind::Lit(begin), Some(_) => self.mk_expr_err(begin.span),
}, None => begin,
};
match self.parse_range_end() {
Some(form) => self.parse_pat_range_begin_with(begin, form)?,
None => PatKind::Lit(begin),
}
}
Err(err) => return self.fatal_unexpected_non_pat(err, expected), Err(err) => return self.fatal_unexpected_non_pat(err, expected),
} }
}; };
@ -615,6 +714,21 @@ 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(_)
if self.may_recover()
&& let Some(form) = self.parse_range_end() =>
{
self.dcx().emit_err(UnexpectedParenInRangePat {
span: vec![open_paren, close_paren],
sugg: UnexpectedParenInRangePatSugg {
start_span: open_paren,
end_span: close_paren,
},
});
self.parse_pat_range_begin_with(self.mk_expr(pat.span, ExprKind::Err), form)?
}
// (pat) with optional parentheses // (pat) with optional parentheses
_ => PatKind::Paren(pat), _ => PatKind::Paren(pat),
@ -853,6 +967,8 @@ impl<'a> Parser<'a> {
self.parse_literal_maybe_minus() self.parse_literal_maybe_minus()
}?; }?;
let recovered = self.maybe_recover_trailing_expr(bound.span, true);
// recover trailing `)` // recover trailing `)`
if let Some(open_paren) = open_paren { if let Some(open_paren) = open_paren {
self.expect(&token::CloseDelim(Delimiter::Parenthesis))?; self.expect(&token::CloseDelim(Delimiter::Parenthesis))?;
@ -866,7 +982,10 @@ impl<'a> Parser<'a> {
}); });
} }
Ok(bound) Ok(match recovered {
Some(_) => self.mk_expr_err(bound.span),
None => bound,
})
} }
/// Is this the start of a pattern beginning with a path? /// Is this the start of a pattern beginning with a path?
@ -929,7 +1048,17 @@ impl<'a> Parser<'a> {
.create_err(EnumPatternInsteadOfIdentifier { span: self.prev_token.span })); .create_err(EnumPatternInsteadOfIdentifier { span: self.prev_token.span }));
} }
Ok(PatKind::Ident(binding_annotation, ident, sub)) // Check for method calls after the `ident`,
// 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)
{
PatKind::Err(guar)
} else {
PatKind::Ident(binding_annotation, ident, sub)
};
Ok(pat)
} }
/// Parse a struct ("record") pattern (e.g. `Foo { ... }` or `Foo::Bar { ... }`). /// Parse a struct ("record") pattern (e.g. `Foo { ... }` or `Foo::Bar { ... }`).

View file

@ -17,12 +17,18 @@ fn main() {
} }
match x as i32 { match x as i32 {
0..5+1 => errors_only.push(x), 0..5+1 => errors_only.push(x),
//~^ error: expected one of `=>`, `if`, or `|`, found `+` //~^ error: expected a pattern range bound, found an expression
//~| error: exclusive range pattern syntax is experimental
1 | -3..0 => first_or.push(x), 1 | -3..0 => first_or.push(x),
//~^ error: exclusive range pattern syntax is experimental
y @ (0..5 | 6) => or_two.push(y), y @ (0..5 | 6) => or_two.push(y),
//~^ error: exclusive range pattern syntax is experimental
y @ 0..const { 5 + 1 } => assert_eq!(y, 5), 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 @ -5.. => range_from.push(y),
y @ ..-7 => assert_eq!(y, -8), y @ ..-7 => assert_eq!(y, -8),
//~^ error: exclusive range pattern syntax is experimental
y => bottom.push(y), y => bottom.push(y),
} }
} }

View file

@ -1,8 +1,8 @@
error: expected one of `=>`, `if`, or `|`, found `+` error: expected a pattern range bound, found an expression
--> $DIR/range_pat_interactions1.rs:19:17 --> $DIR/range_pat_interactions1.rs:19:16
| |
LL | 0..5+1 => errors_only.push(x), LL | 0..5+1 => errors_only.push(x),
| ^ expected one of `=>`, `if`, or `|` | ^^^ arbitrary expressions are not allowed in patterns
error[E0408]: variable `n` is not bound in all patterns error[E0408]: variable `n` is not bound in all patterns
--> $DIR/range_pat_interactions1.rs:10:25 --> $DIR/range_pat_interactions1.rs:10:25
@ -12,6 +12,16 @@ LL | if let n @ 2..3|4 = x {
| | | |
| variable not in all patterns | variable not in all patterns
error[E0658]: inline-const in pattern position is experimental
--> $DIR/range_pat_interactions1.rs:26:20
|
LL | y @ 0..const { 5 + 1 } => assert_eq!(y, 5),
| ^^^^^
|
= note: see issue #76001 <https://github.com/rust-lang/rust/issues/76001> for more information
= help: add `#![feature(inline_const_pat)]` to the crate attributes to enable
= note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
error[E0658]: exclusive range pattern syntax is experimental error[E0658]: exclusive range pattern syntax is experimental
--> $DIR/range_pat_interactions1.rs:10:20 --> $DIR/range_pat_interactions1.rs:10:20
| |
@ -34,7 +44,62 @@ LL | } else if let 2..3 | 4 = x {
= note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
= help: use an inclusive range pattern, like N..=M = help: use an inclusive range pattern, like N..=M
error: aborting due to 4 previous errors error[E0658]: exclusive range pattern syntax is experimental
--> $DIR/range_pat_interactions1.rs:19:13
|
LL | 0..5+1 => errors_only.push(x),
| ^^^^^^
|
= note: see issue #37854 <https://github.com/rust-lang/rust/issues/37854> for more information
= help: add `#![feature(exclusive_range_pattern)]` to the crate attributes to enable
= note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
= help: use an inclusive range pattern, like N..=M
error[E0658]: exclusive range pattern syntax is experimental
--> $DIR/range_pat_interactions1.rs:22:17
|
LL | 1 | -3..0 => first_or.push(x),
| ^^^^^
|
= note: see issue #37854 <https://github.com/rust-lang/rust/issues/37854> for more information
= help: add `#![feature(exclusive_range_pattern)]` to the crate attributes to enable
= note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
= help: use an inclusive range pattern, like N..=M
error[E0658]: exclusive range pattern syntax is experimental
--> $DIR/range_pat_interactions1.rs:24:18
|
LL | y @ (0..5 | 6) => or_two.push(y),
| ^^^^
|
= note: see issue #37854 <https://github.com/rust-lang/rust/issues/37854> for more information
= help: add `#![feature(exclusive_range_pattern)]` to the crate attributes to enable
= note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
= help: use an inclusive range pattern, like N..=M
error[E0658]: exclusive range pattern syntax is experimental
--> $DIR/range_pat_interactions1.rs:26:17
|
LL | y @ 0..const { 5 + 1 } => assert_eq!(y, 5),
| ^^^^^^^^^^^^^^^^^^
|
= note: see issue #37854 <https://github.com/rust-lang/rust/issues/37854> for more information
= help: add `#![feature(exclusive_range_pattern)]` to the crate attributes to enable
= note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
= help: use an inclusive range pattern, like N..=M
error[E0658]: exclusive range pattern syntax is experimental
--> $DIR/range_pat_interactions1.rs:30:17
|
LL | y @ ..-7 => assert_eq!(y, -8),
| ^^^^
|
= note: see issue #37854 <https://github.com/rust-lang/rust/issues/37854> for more information
= help: add `#![feature(exclusive_range_pattern)]` to the crate attributes to enable
= note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
= help: use an inclusive range pattern, like N..=M
error: aborting due to 10 previous errors
Some errors have detailed explanations: E0408, E0658. Some errors have detailed explanations: E0408, E0658.
For more information about an error, try `rustc --explain E0408`. For more information about an error, try `rustc --explain E0408`.

View file

@ -8,12 +8,18 @@ fn main() {
for x in -9 + 1..=(9 - 2) { for x in -9 + 1..=(9 - 2) {
match x as i32 { match x as i32 {
0..=(5+1) => errors_only.push(x), 0..=(5+1) => errors_only.push(x),
//~^ error: expected `)`, found `+` //~^ error: expected a pattern range bound, found an expression
//~| error: range pattern bounds cannot have parentheses
1 | -3..0 => first_or.push(x), 1 | -3..0 => first_or.push(x),
//~^ error: exclusive range pattern syntax is experimental
y @ (0..5 | 6) => or_two.push(y), y @ (0..5 | 6) => or_two.push(y),
//~^ error: exclusive range pattern syntax is experimental
y @ 0..const { 5 + 1 } => assert_eq!(y, 5), 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 @ -5.. => range_from.push(y),
y @ ..-7 => assert_eq!(y, -8), y @ ..-7 => assert_eq!(y, -8),
//~^ error: exclusive range pattern syntax is experimental
y => bottom.push(y), y => bottom.push(y),
} }
} }

View file

@ -1,8 +1,75 @@
error: expected `)`, found `+` error: expected a pattern range bound, found an expression
--> $DIR/range_pat_interactions2.rs:10:19 --> $DIR/range_pat_interactions2.rs:10:18
| |
LL | 0..=(5+1) => errors_only.push(x), LL | 0..=(5+1) => errors_only.push(x),
| ^ expected `)` | ^^^ arbitrary expressions are not allowed in patterns
error: aborting due to 1 previous error error: range pattern bounds cannot have parentheses
--> $DIR/range_pat_interactions2.rs:10:17
|
LL | 0..=(5+1) => errors_only.push(x),
| ^ ^
|
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 <https://github.com/rust-lang/rust/issues/76001> for more information
= help: add `#![feature(inline_const_pat)]` to the crate attributes to enable
= note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
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 <https://github.com/rust-lang/rust/issues/37854> for more information
= help: add `#![feature(exclusive_range_pattern)]` to the crate attributes to enable
= note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
= help: use an inclusive range pattern, like N..=M
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 <https://github.com/rust-lang/rust/issues/37854> for more information
= help: add `#![feature(exclusive_range_pattern)]` to the crate attributes to enable
= note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
= help: use an inclusive range pattern, like N..=M
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 <https://github.com/rust-lang/rust/issues/37854> for more information
= help: add `#![feature(exclusive_range_pattern)]` to the crate attributes to enable
= note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
= help: use an inclusive range pattern, like N..=M
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 <https://github.com/rust-lang/rust/issues/37854> for more information
= help: add `#![feature(exclusive_range_pattern)]` to the crate attributes to enable
= note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
= help: use an inclusive range pattern, like N..=M
error: aborting due to 7 previous errors
For more information about this error, try `rustc --explain E0658`.

View file

@ -1,3 +1,3 @@
fn main() { fn main() {
let buf[0] = 0; //~ ERROR expected one of `:`, `;`, `=`, `@`, or `|`, found `[` let buf[0] = 0; //~ error: expected a pattern, found an expression
} }

View file

@ -1,8 +1,8 @@
error: expected one of `:`, `;`, `=`, `@`, or `|`, found `[` error: expected a pattern, found an expression
--> $DIR/issue-24197.rs:2:12 --> $DIR/issue-24197.rs:2:9
| |
LL | let buf[0] = 0; LL | let buf[0] = 0;
| ^ expected one of `:`, `;`, `=`, `@`, or `|` | ^^^^^^ arbitrary expressions are not allowed in patterns
error: aborting due to 1 previous error error: aborting due to 1 previous error

View file

@ -3,7 +3,7 @@ static tmp : [&'static str; 2] = ["hello", "he"];
fn main() { fn main() {
let z = "hello"; let z = "hello";
match z { match z {
tmp[0] => {} //~ ERROR expected one of `=>`, `@`, `if`, or `|`, found `[` tmp[0] => {} //~ error: expected a pattern, found an expression
_ => {} _ => {}
} }
} }

View file

@ -1,8 +1,8 @@
error: expected one of `=>`, `@`, `if`, or `|`, found `[` error: expected a pattern, found an expression
--> $DIR/issue-24375.rs:6:12 --> $DIR/issue-24375.rs:6:9
| |
LL | tmp[0] => {} LL | tmp[0] => {}
| ^ expected one of `=>`, `@`, `if`, or `|` | ^^^^^^ arbitrary expressions are not allowed in patterns
error: aborting due to 1 previous error error: aborting due to 1 previous error

View file

@ -1,3 +1,5 @@
fn main() { fn main() {
let v[0] = v[1]; //~ ERROR expected one of `:`, `;`, `=`, `@`, or `|`, found `[` let v[0] = v[1];
//~^ error: expected a pattern, found an expression
//~| error: cannot find value `v` in this scope
} }

View file

@ -1,8 +1,15 @@
error: expected one of `:`, `;`, `=`, `@`, or `|`, found `[` error: expected a pattern, found an expression
--> $DIR/pat-lt-bracket-5.rs:2:10 --> $DIR/pat-lt-bracket-5.rs:2:9
| |
LL | let v[0] = v[1]; LL | let v[0] = v[1];
| ^ expected one of `:`, `;`, `=`, `@`, or `|` | ^^^^ arbitrary 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`.

View file

@ -3,7 +3,8 @@ fn main() {
let x = Test(&0, []); let x = Test(&0, []);
let Test(&desc[..]) = x; let Test(&desc[..]) = x;
//~^ ERROR: expected one of `)`, `,`, `@`, or `|`, found `[` //~^ error: expected a pattern, found an expression
//~| error: this pattern has 1 field, but the corresponding tuple struct has 2 fields
} }
const RECOVERY_WITNESS: () = 0; //~ ERROR mismatched types const RECOVERY_WITNESS: () = 0; //~ ERROR mismatched types

View file

@ -1,18 +1,30 @@
error: expected one of `)`, `,`, `@`, or `|`, found `[` error: expected a pattern, found an expression
--> $DIR/pat-lt-bracket-6.rs:5:19 --> $DIR/pat-lt-bracket-6.rs:5:15
| |
LL | let Test(&desc[..]) = x; LL | let Test(&desc[..]) = x;
| ^ | ^^^^^^^^ arbitrary expressions are not allowed in patterns
| |
| expected one of `)`, `,`, `@`, or `|`
| help: missing `,`
error[E0308]: mismatched types 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; LL | const RECOVERY_WITNESS: () = 0;
| ^ expected `()`, found integer | ^ 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;
| +++
For more information about this error, try `rustc --explain E0308`. error: aborting due to 3 previous errors
Some errors have detailed explanations: E0023, E0308.
For more information about an error, try `rustc --explain E0023`.

View file

@ -1,5 +1,9 @@
// Parsing of range patterns // Parsing of range patterns
fn main() { fn main() {
let 10 ..= 10 + 3 = 12; //~ expected one of `:`, `;`, `=`, or `|`, found `+` let 10 ..= 10 + 3 = 12;
//~^ error: expected a pattern range bound, found an expression
let 10 - 3 ..= 10 = 8;
//~^ error: expected a pattern range bound, found an expression
} }

View file

@ -1,8 +1,14 @@
error: expected one of `:`, `;`, `=`, or `|`, found `+` error: expected a pattern range bound, found an expression
--> $DIR/pat-ranges-3.rs:4:19 --> $DIR/pat-ranges-3.rs:4:16
| |
LL | let 10 ..= 10 + 3 = 12; LL | let 10 ..= 10 + 3 = 12;
| ^ expected one of `:`, `;`, `=`, or `|` | ^^^^^^ arbitrary expressions are not allowed in patterns
error: aborting due to 1 previous error error: expected a pattern range bound, found an expression
--> $DIR/pat-ranges-3.rs:7:9
|
LL | let 10 - 3 ..= 10 = 8;
| ^^^^^^ arbitrary expressions are not allowed in patterns
error: aborting due to 2 previous errors

View file

@ -1,6 +0,0 @@
// Parsing of range patterns
fn main() {
let 10 - 3 ..= 10 = 8;
//~^ error: expected one of `...`, `..=`, `..`, `:`, `;`, `=`, or `|`, found `-`
}

View file

@ -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

View file

@ -0,0 +1,28 @@
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 `*`
}

View file

@ -0,0 +1,76 @@
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

View file

@ -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 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 `,`
}

View file

@ -0,0 +1,35 @@
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

View file

@ -8,6 +8,22 @@ fn main() {
(0)..=(-4) => (), (0)..=(-4) => (),
//~^ error: range pattern bounds cannot have parentheses //~^ error: range pattern bounds cannot have parentheses
//~| error: range pattern bounds cannot have parentheses //~| error: range pattern bounds cannot have parentheses
..=1 + 2 => (),
//~^ error: expected a pattern range bound, found an expression
(4).. => (),
//~^ error: range pattern bounds cannot have parentheses
(-4 + 0).. => (),
//~^ error: expected a pattern range bound, found an expression
//~| error: range pattern bounds cannot have parentheses
(1 + 4)...1 * 2 => (),
//~^ error: expected a pattern range bound, found an expression
//~| error: expected a pattern range bound, found an expression
//~| error: range pattern bounds cannot have parentheses
//~| 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
}; };
} }

View file

@ -46,5 +46,87 @@ LL - (0)..=(-4) => (),
LL + (0)..=-4 => (), LL + (0)..=-4 => (),
| |
error: aborting due to 4 previous errors error: expected a pattern range bound, found an expression
--> $DIR/pat-recover-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
|
LL | (4).. => (),
| ^ ^
|
help: remove these parentheses
|
LL - (4).. => (),
LL + 4.. => (),
|
error: expected a pattern range bound, found an expression
--> $DIR/pat-recover-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
|
LL | (-4 + 0).. => (),
| ^ ^
|
help: remove these parentheses
|
LL - (-4 + 0).. => (),
LL + -4 + 0.. => (),
|
error: expected a pattern range bound, found an expression
--> $DIR/pat-recover-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
|
LL | (1 + 4)...1 * 2 => (),
| ^ ^
|
help: remove these parentheses
|
LL - (1 + 4)...1 * 2 => (),
LL + 1 + 4...1 * 2 => (),
|
error: expected a pattern range bound, found an expression
--> $DIR/pat-recover-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
|
LL | 0.x()..="y".z() => (),
| ^^^^^ method calls are not allowed in patterns
error: expected a pattern range bound, found a method call
--> $DIR/pat-recover-ranges.rs:24:17
|
LL | 0.x()..="y".z() => (),
| ^^^^^^^ method calls are not allowed in patterns
warning: `...` range patterns are deprecated
--> $DIR/pat-recover-ranges.rs:18:16
|
LL | (1 + 4)...1 * 2 => (),
| ^^^ help: use `..=` for an inclusive range
|
= warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2021!
= note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/warnings-promoted-to-error.html>
= note: `#[warn(ellipsis_inclusive_range_patterns)]` on by default
error: aborting due to 13 previous errors; 1 warning emitted

View file

@ -0,0 +1,61 @@
// check that we can't do funny things with wildcards.
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 a pattern range bound, found an expression
//~| error: range pattern bounds cannot have parentheses
}
}
fn main() {}

View file

@ -0,0 +1,77 @@
error: expected one of `=>`, `if`, or `|`, found `+`
--> $DIR/pat-recover-wildcards.rs:5:11
|
LL | _ + 1 => ()
| ^ expected one of `=>`, `if`, or `|`
error: expected one of `)`, `,`, or `|`, found `%`
--> $DIR/pat-recover-wildcards.rs:11:12
|
LL | (_ % 4) => ()
| ^ expected one of `)`, `,`, or `|`
error: expected one of `=>`, `if`, or `|`, found `.`
--> $DIR/pat-recover-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
|
LL | _..=4 => ()
| ^^^ expected one of `=>`, `if`, or `|`
error: expected one of `=>`, `if`, or `|`, found reserved identifier `_`
--> $DIR/pat-recover-wildcards.rs:29:11
|
LL | .._ => ()
| ^ expected one of `=>`, `if`, or `|`
error[E0586]: inclusive range with no end
--> $DIR/pat-recover-wildcards.rs:35: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/pat-recover-wildcards.rs:35:13
|
LL | 0..._ => ()
| ^ expected one of `=>`, `if`, or `|`
error: expected one of `)`, `,`, or `|`, found `*`
--> $DIR/pat-recover-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
|
LL | ..(_) => ()
| ^ expected one of `=>`, `if`, or `|`
error: expected a pattern range bound, found an expression
--> $DIR/pat-recover-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
|
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`.