Rollup merge of #133424 - Nadrieril:guard-patterns-parsing, r=fee1-dead
Parse guard patterns This implements the parsing of [RFC3637 Guard Patterns](https://rust-lang.github.io/rfcs/3637-guard-patterns.html) (see also [tracking issue](https://github.com/rust-lang/rust/issues/129967)). This PR is extracted from https://github.com/rust-lang/rust/pull/129996 with minor modifications. cc `@max-niederman`
This commit is contained in:
commit
1868c8f66f
31 changed files with 328 additions and 81 deletions
|
@ -627,9 +627,11 @@ impl Pat {
|
||||||
| PatKind::Or(s) => s.iter().for_each(|p| p.walk(it)),
|
| PatKind::Or(s) => s.iter().for_each(|p| p.walk(it)),
|
||||||
|
|
||||||
// Trivial wrappers over inner patterns.
|
// Trivial wrappers over inner patterns.
|
||||||
PatKind::Box(s) | PatKind::Deref(s) | PatKind::Ref(s, _) | PatKind::Paren(s) => {
|
PatKind::Box(s)
|
||||||
s.walk(it)
|
| PatKind::Deref(s)
|
||||||
}
|
| PatKind::Ref(s, _)
|
||||||
|
| PatKind::Paren(s)
|
||||||
|
| PatKind::Guard(s, _) => s.walk(it),
|
||||||
|
|
||||||
// These patterns do not contain subpatterns, skip.
|
// These patterns do not contain subpatterns, skip.
|
||||||
PatKind::Wild
|
PatKind::Wild
|
||||||
|
@ -839,6 +841,9 @@ pub enum PatKind {
|
||||||
// A never pattern `!`.
|
// A never pattern `!`.
|
||||||
Never,
|
Never,
|
||||||
|
|
||||||
|
/// A guard pattern (e.g., `x if guard(x)`).
|
||||||
|
Guard(P<Pat>, P<Expr>),
|
||||||
|
|
||||||
/// Parentheses in patterns used for grouping (i.e., `(PAT)`).
|
/// Parentheses in patterns used for grouping (i.e., `(PAT)`).
|
||||||
Paren(P<Pat>),
|
Paren(P<Pat>),
|
||||||
|
|
||||||
|
|
|
@ -1525,6 +1525,10 @@ pub fn walk_pat<T: MutVisitor>(vis: &mut T, pat: &mut P<Pat>) {
|
||||||
visit_opt(e2, |e| vis.visit_expr(e));
|
visit_opt(e2, |e| vis.visit_expr(e));
|
||||||
vis.visit_span(span);
|
vis.visit_span(span);
|
||||||
}
|
}
|
||||||
|
PatKind::Guard(p, e) => {
|
||||||
|
vis.visit_pat(p);
|
||||||
|
vis.visit_expr(e);
|
||||||
|
}
|
||||||
PatKind::Tuple(elems) | PatKind::Slice(elems) | PatKind::Or(elems) => {
|
PatKind::Tuple(elems) | PatKind::Slice(elems) | PatKind::Or(elems) => {
|
||||||
visit_thin_vec(elems, |elem| vis.visit_pat(elem))
|
visit_thin_vec(elems, |elem| vis.visit_pat(elem))
|
||||||
}
|
}
|
||||||
|
|
|
@ -682,6 +682,10 @@ pub fn walk_pat<'a, V: Visitor<'a>>(visitor: &mut V, pattern: &'a Pat) -> V::Res
|
||||||
visit_opt!(visitor, visit_expr, lower_bound);
|
visit_opt!(visitor, visit_expr, lower_bound);
|
||||||
visit_opt!(visitor, visit_expr, upper_bound);
|
visit_opt!(visitor, visit_expr, upper_bound);
|
||||||
}
|
}
|
||||||
|
PatKind::Guard(subpattern, guard_condition) => {
|
||||||
|
try_visit!(visitor.visit_pat(subpattern));
|
||||||
|
try_visit!(visitor.visit_expr(guard_condition));
|
||||||
|
}
|
||||||
PatKind::Wild | PatKind::Rest | PatKind::Never => {}
|
PatKind::Wild | PatKind::Rest | PatKind::Never => {}
|
||||||
PatKind::Err(_guar) => {}
|
PatKind::Err(_guar) => {}
|
||||||
PatKind::Tuple(elems) | PatKind::Slice(elems) | PatKind::Or(elems) => {
|
PatKind::Tuple(elems) | PatKind::Slice(elems) | PatKind::Or(elems) => {
|
||||||
|
|
|
@ -114,6 +114,8 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
||||||
self.lower_range_end(end, e2.is_some()),
|
self.lower_range_end(end, e2.is_some()),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
// FIXME(guard_patterns): lower pattern guards to HIR
|
||||||
|
PatKind::Guard(inner, _) => pattern = inner,
|
||||||
PatKind::Slice(pats) => break self.lower_pat_slice(pats),
|
PatKind::Slice(pats) => break self.lower_pat_slice(pats),
|
||||||
PatKind::Rest => {
|
PatKind::Rest => {
|
||||||
// If we reach here the `..` pattern is not semantically allowed.
|
// If we reach here the `..` pattern is not semantically allowed.
|
||||||
|
|
|
@ -556,6 +556,7 @@ pub fn check_crate(krate: &ast::Crate, sess: &Session, features: &Features) {
|
||||||
gate_all!(builtin_syntax, "`builtin #` syntax is unstable");
|
gate_all!(builtin_syntax, "`builtin #` syntax is unstable");
|
||||||
gate_all!(explicit_tail_calls, "`become` expression is experimental");
|
gate_all!(explicit_tail_calls, "`become` expression is experimental");
|
||||||
gate_all!(generic_const_items, "generic const items are experimental");
|
gate_all!(generic_const_items, "generic const items are experimental");
|
||||||
|
gate_all!(guard_patterns, "guard patterns are experimental", "consider using match arm guards");
|
||||||
gate_all!(fn_delegation, "functions delegation is not yet fully implemented");
|
gate_all!(fn_delegation, "functions delegation is not yet fully implemented");
|
||||||
gate_all!(postfix_match, "postfix match is experimental");
|
gate_all!(postfix_match, "postfix match is experimental");
|
||||||
gate_all!(mut_ref, "mutable by-reference bindings are experimental");
|
gate_all!(mut_ref, "mutable by-reference bindings are experimental");
|
||||||
|
|
|
@ -1709,6 +1709,14 @@ impl<'a> State<'a> {
|
||||||
self.print_expr(e, FixupContext::default());
|
self.print_expr(e, FixupContext::default());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
PatKind::Guard(subpat, condition) => {
|
||||||
|
self.popen();
|
||||||
|
self.print_pat(subpat);
|
||||||
|
self.space();
|
||||||
|
self.word_space("if");
|
||||||
|
self.print_expr(condition, FixupContext::default());
|
||||||
|
self.pclose();
|
||||||
|
}
|
||||||
PatKind::Slice(elts) => {
|
PatKind::Slice(elts) => {
|
||||||
self.word("[");
|
self.word("[");
|
||||||
self.commasep(Inconsistent, elts, |s, p| s.print_pat(p));
|
self.commasep(Inconsistent, elts, |s, p| s.print_pat(p));
|
||||||
|
|
|
@ -990,7 +990,7 @@ pub fn parse_ast_fragment<'a>(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
AstFragmentKind::Ty => AstFragment::Ty(this.parse_ty()?),
|
AstFragmentKind::Ty => AstFragment::Ty(this.parse_ty()?),
|
||||||
AstFragmentKind::Pat => AstFragment::Pat(this.parse_pat_allow_top_alt(
|
AstFragmentKind::Pat => AstFragment::Pat(this.parse_pat_allow_top_guard(
|
||||||
None,
|
None,
|
||||||
RecoverComma::No,
|
RecoverComma::No,
|
||||||
RecoverColon::Yes,
|
RecoverColon::Yes,
|
||||||
|
|
|
@ -505,6 +505,8 @@ declare_features! (
|
||||||
(incomplete, generic_const_items, "1.73.0", Some(113521)),
|
(incomplete, generic_const_items, "1.73.0", Some(113521)),
|
||||||
/// Allows registering static items globally, possibly across crates, to iterate over at runtime.
|
/// Allows registering static items globally, possibly across crates, to iterate over at runtime.
|
||||||
(unstable, global_registration, "1.80.0", Some(125119)),
|
(unstable, global_registration, "1.80.0", Some(125119)),
|
||||||
|
/// Allows using guards in patterns.
|
||||||
|
(incomplete, guard_patterns, "CURRENT_RUSTC_VERSION", Some(129967)),
|
||||||
/// Allows using `..=X` as a patterns in slices.
|
/// Allows using `..=X` as a patterns in slices.
|
||||||
(unstable, half_open_range_patterns_in_slices, "1.66.0", Some(67264)),
|
(unstable, half_open_range_patterns_in_slices, "1.66.0", Some(67264)),
|
||||||
/// Allows `if let` guard in match arms.
|
/// Allows `if let` guard in match arms.
|
||||||
|
|
|
@ -1235,7 +1235,7 @@ impl EarlyLintPass for UnusedParens {
|
||||||
self.check_unused_parens_pat(cx, &f.pat, false, false, keep_space);
|
self.check_unused_parens_pat(cx, &f.pat, false, false, keep_space);
|
||||||
},
|
},
|
||||||
// Avoid linting on `i @ (p0 | .. | pn)` and `box (p0 | .. | pn)`, #64106.
|
// Avoid linting on `i @ (p0 | .. | pn)` and `box (p0 | .. | pn)`, #64106.
|
||||||
Ident(.., Some(p)) | Box(p) | Deref(p) => self.check_unused_parens_pat(cx, p, true, false, keep_space),
|
Ident(.., Some(p)) | Box(p) | Deref(p) | Guard(p, _) => self.check_unused_parens_pat(cx, p, true, false, keep_space),
|
||||||
// Avoid linting on `&(mut x)` as `&mut x` has a different meaning, #55342.
|
// Avoid linting on `&(mut x)` as `&mut x` has a different meaning, #55342.
|
||||||
// Also avoid linting on `& mut? (p0 | .. | pn)`, #64106.
|
// Also avoid linting on `& mut? (p0 | .. | pn)`, #64106.
|
||||||
Ref(p, m) => self.check_unused_parens_pat(cx, p, true, *m == Mutability::Not, keep_space),
|
Ref(p, m) => self.check_unused_parens_pat(cx, p, true, *m == Mutability::Not, keep_space),
|
||||||
|
|
|
@ -2631,7 +2631,7 @@ impl<'a> Parser<'a> {
|
||||||
};
|
};
|
||||||
self.bump(); // Eat `let` token
|
self.bump(); // Eat `let` token
|
||||||
let lo = self.prev_token.span;
|
let lo = self.prev_token.span;
|
||||||
let pat = self.parse_pat_allow_top_alt(
|
let pat = self.parse_pat_no_top_guard(
|
||||||
None,
|
None,
|
||||||
RecoverComma::Yes,
|
RecoverComma::Yes,
|
||||||
RecoverColon::Yes,
|
RecoverColon::Yes,
|
||||||
|
@ -2778,7 +2778,7 @@ impl<'a> Parser<'a> {
|
||||||
};
|
};
|
||||||
// Try to parse the pattern `for ($PAT) in $EXPR`.
|
// Try to parse the pattern `for ($PAT) in $EXPR`.
|
||||||
let pat = match (
|
let pat = match (
|
||||||
self.parse_pat_allow_top_alt(
|
self.parse_pat_allow_top_guard(
|
||||||
None,
|
None,
|
||||||
RecoverComma::Yes,
|
RecoverComma::Yes,
|
||||||
RecoverColon::Yes,
|
RecoverColon::Yes,
|
||||||
|
@ -3241,7 +3241,7 @@ impl<'a> Parser<'a> {
|
||||||
// then we should recover.
|
// then we should recover.
|
||||||
let mut snapshot = this.create_snapshot_for_diagnostic();
|
let mut snapshot = this.create_snapshot_for_diagnostic();
|
||||||
let pattern_follows = snapshot
|
let pattern_follows = snapshot
|
||||||
.parse_pat_allow_top_alt(
|
.parse_pat_no_top_guard(
|
||||||
None,
|
None,
|
||||||
RecoverComma::Yes,
|
RecoverComma::Yes,
|
||||||
RecoverColon::Yes,
|
RecoverColon::Yes,
|
||||||
|
@ -3315,43 +3315,37 @@ impl<'a> Parser<'a> {
|
||||||
|
|
||||||
fn parse_match_arm_pat_and_guard(&mut self) -> PResult<'a, (P<Pat>, Option<P<Expr>>)> {
|
fn parse_match_arm_pat_and_guard(&mut self) -> PResult<'a, (P<Pat>, Option<P<Expr>>)> {
|
||||||
if self.token == token::OpenDelim(Delimiter::Parenthesis) {
|
if self.token == token::OpenDelim(Delimiter::Parenthesis) {
|
||||||
// Detect and recover from `($pat if $cond) => $arm`.
|
|
||||||
let left = self.token.span;
|
let left = self.token.span;
|
||||||
match self.parse_pat_allow_top_alt(
|
let pat = self.parse_pat_no_top_guard(
|
||||||
None,
|
None,
|
||||||
RecoverComma::Yes,
|
RecoverComma::Yes,
|
||||||
RecoverColon::Yes,
|
RecoverColon::Yes,
|
||||||
CommaRecoveryMode::EitherTupleOrPipe,
|
CommaRecoveryMode::EitherTupleOrPipe,
|
||||||
) {
|
)?;
|
||||||
Ok(pat) => Ok((pat, self.parse_match_arm_guard()?)),
|
if let ast::PatKind::Paren(subpat) = &pat.kind
|
||||||
Err(err)
|
&& let ast::PatKind::Guard(..) = &subpat.kind
|
||||||
if let prev_sp = self.prev_token.span
|
{
|
||||||
&& let true = self.eat_keyword(kw::If) =>
|
// Detect and recover from `($pat if $cond) => $arm`.
|
||||||
{
|
// FIXME(guard_patterns): convert this to a normal guard instead
|
||||||
// We know for certain we've found `($pat if` so far.
|
let span = pat.span;
|
||||||
let mut cond = match self.parse_match_guard_condition() {
|
let ast::PatKind::Paren(subpat) = pat.into_inner().kind else { unreachable!() };
|
||||||
Ok(cond) => cond,
|
let ast::PatKind::Guard(_, mut cond) = subpat.into_inner().kind else {
|
||||||
Err(cond_err) => {
|
unreachable!()
|
||||||
cond_err.cancel();
|
};
|
||||||
return Err(err);
|
self.psess.gated_spans.ungate_last(sym::guard_patterns, cond.span);
|
||||||
}
|
CondChecker::new(self).visit_expr(&mut cond);
|
||||||
};
|
let right = self.prev_token.span;
|
||||||
err.cancel();
|
self.dcx().emit_err(errors::ParenthesesInMatchPat {
|
||||||
CondChecker::new(self).visit_expr(&mut cond);
|
span: vec![left, right],
|
||||||
self.eat_to_tokens(&[&token::CloseDelim(Delimiter::Parenthesis)]);
|
sugg: errors::ParenthesesInMatchPatSugg { left, right },
|
||||||
self.expect(&token::CloseDelim(Delimiter::Parenthesis))?;
|
});
|
||||||
let right = self.prev_token.span;
|
Ok((self.mk_pat(span, ast::PatKind::Wild), Some(cond)))
|
||||||
self.dcx().emit_err(errors::ParenthesesInMatchPat {
|
} else {
|
||||||
span: vec![left, right],
|
Ok((pat, self.parse_match_arm_guard()?))
|
||||||
sugg: errors::ParenthesesInMatchPatSugg { left, right },
|
|
||||||
});
|
|
||||||
Ok((self.mk_pat(left.to(prev_sp), ast::PatKind::Wild), Some(cond)))
|
|
||||||
}
|
|
||||||
Err(err) => Err(err),
|
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// Regular parser flow:
|
// Regular parser flow:
|
||||||
let pat = self.parse_pat_allow_top_alt(
|
let pat = self.parse_pat_no_top_guard(
|
||||||
None,
|
None,
|
||||||
RecoverComma::Yes,
|
RecoverComma::Yes,
|
||||||
RecoverColon::Yes,
|
RecoverColon::Yes,
|
||||||
|
|
|
@ -174,7 +174,7 @@ impl<'a> Parser<'a> {
|
||||||
NonterminalKind::Pat(pat_kind) => {
|
NonterminalKind::Pat(pat_kind) => {
|
||||||
NtPat(self.collect_tokens_no_attrs(|this| match pat_kind {
|
NtPat(self.collect_tokens_no_attrs(|this| match pat_kind {
|
||||||
PatParam { .. } => this.parse_pat_no_top_alt(None, None),
|
PatParam { .. } => this.parse_pat_no_top_alt(None, None),
|
||||||
PatWithOr => this.parse_pat_allow_top_alt(
|
PatWithOr => this.parse_pat_no_top_guard(
|
||||||
None,
|
None,
|
||||||
RecoverComma::No,
|
RecoverComma::No,
|
||||||
RecoverColon::No,
|
RecoverColon::No,
|
||||||
|
|
|
@ -99,9 +99,34 @@ pub enum PatternLocation {
|
||||||
impl<'a> Parser<'a> {
|
impl<'a> Parser<'a> {
|
||||||
/// Parses a pattern.
|
/// Parses a pattern.
|
||||||
///
|
///
|
||||||
/// Corresponds to `pat<no_top_alt>` in RFC 2535 and does not admit or-patterns
|
/// Corresponds to `Pattern` in RFC 3637 and admits guard patterns at the top level.
|
||||||
/// at the top level. Used when parsing the parameters of lambda expressions,
|
/// Used when parsing patterns in all cases where neither `PatternNoTopGuard` nor
|
||||||
/// functions, function pointers, and `pat` macro fragments.
|
/// `PatternNoTopAlt` (see below) are used.
|
||||||
|
pub fn parse_pat_allow_top_guard(
|
||||||
|
&mut self,
|
||||||
|
expected: Option<Expected>,
|
||||||
|
rc: RecoverComma,
|
||||||
|
ra: RecoverColon,
|
||||||
|
rt: CommaRecoveryMode,
|
||||||
|
) -> PResult<'a, P<Pat>> {
|
||||||
|
let pat = self.parse_pat_no_top_guard(expected, rc, ra, rt)?;
|
||||||
|
|
||||||
|
if self.eat_keyword(kw::If) {
|
||||||
|
let cond = self.parse_expr()?;
|
||||||
|
// Feature-gate guard patterns
|
||||||
|
self.psess.gated_spans.gate(sym::guard_patterns, cond.span);
|
||||||
|
let span = pat.span.to(cond.span);
|
||||||
|
Ok(self.mk_pat(span, PatKind::Guard(pat, cond)))
|
||||||
|
} else {
|
||||||
|
Ok(pat)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Parses a pattern.
|
||||||
|
///
|
||||||
|
/// Corresponds to `PatternNoTopAlt` in RFC 3637 and does not admit or-patterns
|
||||||
|
/// or guard patterns at the top level. Used when parsing the parameters of lambda
|
||||||
|
/// expressions, functions, function pointers, and `pat_param` macro fragments.
|
||||||
pub fn parse_pat_no_top_alt(
|
pub fn parse_pat_no_top_alt(
|
||||||
&mut self,
|
&mut self,
|
||||||
expected: Option<Expected>,
|
expected: Option<Expected>,
|
||||||
|
@ -112,25 +137,26 @@ impl<'a> Parser<'a> {
|
||||||
|
|
||||||
/// Parses a pattern.
|
/// Parses a pattern.
|
||||||
///
|
///
|
||||||
/// Corresponds to `top_pat` in RFC 2535 and allows or-pattern at the top level.
|
/// Corresponds to `PatternNoTopGuard` in RFC 3637 and allows or-patterns, but not
|
||||||
/// Used for parsing patterns in all cases when `pat<no_top_alt>` is not used.
|
/// guard patterns, at the top level. Used for parsing patterns in `pat` fragments (until
|
||||||
|
/// the next edition) and `let`, `if let`, and `while let` expressions.
|
||||||
///
|
///
|
||||||
/// Note that after the FCP in <https://github.com/rust-lang/rust/issues/81415>,
|
/// Note that after the FCP in <https://github.com/rust-lang/rust/issues/81415>,
|
||||||
/// a leading vert is allowed in nested or-patterns, too. This allows us to
|
/// a leading vert is allowed in nested or-patterns, too. This allows us to
|
||||||
/// simplify the grammar somewhat.
|
/// simplify the grammar somewhat.
|
||||||
pub fn parse_pat_allow_top_alt(
|
pub fn parse_pat_no_top_guard(
|
||||||
&mut self,
|
&mut self,
|
||||||
expected: Option<Expected>,
|
expected: Option<Expected>,
|
||||||
rc: RecoverComma,
|
rc: RecoverComma,
|
||||||
ra: RecoverColon,
|
ra: RecoverColon,
|
||||||
rt: CommaRecoveryMode,
|
rt: CommaRecoveryMode,
|
||||||
) -> PResult<'a, P<Pat>> {
|
) -> PResult<'a, P<Pat>> {
|
||||||
self.parse_pat_allow_top_alt_inner(expected, rc, ra, rt, None).map(|(pat, _)| pat)
|
self.parse_pat_no_top_guard_inner(expected, rc, ra, rt, None).map(|(pat, _)| pat)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns the pattern and a bool indicating whether we recovered from a trailing vert (true =
|
/// Returns the pattern and a bool indicating whether we recovered from a trailing vert (true =
|
||||||
/// recovered).
|
/// recovered).
|
||||||
fn parse_pat_allow_top_alt_inner(
|
fn parse_pat_no_top_guard_inner(
|
||||||
&mut self,
|
&mut self,
|
||||||
expected: Option<Expected>,
|
expected: Option<Expected>,
|
||||||
rc: RecoverComma,
|
rc: RecoverComma,
|
||||||
|
@ -231,7 +257,7 @@ impl<'a> Parser<'a> {
|
||||||
// We use `parse_pat_allow_top_alt` regardless of whether we actually want top-level
|
// We use `parse_pat_allow_top_alt` regardless of whether we actually want top-level
|
||||||
// or-patterns so that we can detect when a user tries to use it. This allows us to print a
|
// or-patterns so that we can detect when a user tries to use it. This allows us to print a
|
||||||
// better error message.
|
// better error message.
|
||||||
let (pat, trailing_vert) = self.parse_pat_allow_top_alt_inner(
|
let (pat, trailing_vert) = self.parse_pat_no_top_guard_inner(
|
||||||
expected,
|
expected,
|
||||||
rc,
|
rc,
|
||||||
RecoverColon::No,
|
RecoverColon::No,
|
||||||
|
@ -696,7 +722,7 @@ impl<'a> Parser<'a> {
|
||||||
} else if self.check(&token::OpenDelim(Delimiter::Bracket)) {
|
} else if self.check(&token::OpenDelim(Delimiter::Bracket)) {
|
||||||
// Parse `[pat, pat,...]` as a slice pattern.
|
// Parse `[pat, pat,...]` as a slice pattern.
|
||||||
let (pats, _) = self.parse_delim_comma_seq(Delimiter::Bracket, |p| {
|
let (pats, _) = self.parse_delim_comma_seq(Delimiter::Bracket, |p| {
|
||||||
p.parse_pat_allow_top_alt(
|
p.parse_pat_allow_top_guard(
|
||||||
None,
|
None,
|
||||||
RecoverComma::No,
|
RecoverComma::No,
|
||||||
RecoverColon::No,
|
RecoverColon::No,
|
||||||
|
@ -944,7 +970,7 @@ impl<'a> Parser<'a> {
|
||||||
let open_paren = self.token.span;
|
let open_paren = self.token.span;
|
||||||
|
|
||||||
let (fields, trailing_comma) = self.parse_paren_comma_seq(|p| {
|
let (fields, trailing_comma) = self.parse_paren_comma_seq(|p| {
|
||||||
p.parse_pat_allow_top_alt(
|
p.parse_pat_allow_top_guard(
|
||||||
None,
|
None,
|
||||||
RecoverComma::No,
|
RecoverComma::No,
|
||||||
RecoverColon::No,
|
RecoverColon::No,
|
||||||
|
@ -1361,7 +1387,7 @@ impl<'a> Parser<'a> {
|
||||||
path: Path,
|
path: Path,
|
||||||
) -> PResult<'a, PatKind> {
|
) -> PResult<'a, PatKind> {
|
||||||
let (fields, _) = self.parse_paren_comma_seq(|p| {
|
let (fields, _) = self.parse_paren_comma_seq(|p| {
|
||||||
p.parse_pat_allow_top_alt(
|
p.parse_pat_allow_top_guard(
|
||||||
None,
|
None,
|
||||||
RecoverComma::No,
|
RecoverComma::No,
|
||||||
RecoverColon::No,
|
RecoverColon::No,
|
||||||
|
@ -1396,7 +1422,7 @@ impl<'a> Parser<'a> {
|
||||||
self.parse_builtin(|self_, _lo, ident| {
|
self.parse_builtin(|self_, _lo, ident| {
|
||||||
Ok(match ident.name {
|
Ok(match ident.name {
|
||||||
// builtin#deref(PAT)
|
// builtin#deref(PAT)
|
||||||
sym::deref => Some(ast::PatKind::Deref(self_.parse_pat_allow_top_alt(
|
sym::deref => Some(ast::PatKind::Deref(self_.parse_pat_allow_top_guard(
|
||||||
None,
|
None,
|
||||||
RecoverComma::Yes,
|
RecoverComma::Yes,
|
||||||
RecoverColon::Yes,
|
RecoverColon::Yes,
|
||||||
|
@ -1671,7 +1697,7 @@ impl<'a> Parser<'a> {
|
||||||
// Parsing a pattern of the form `fieldname: pat`.
|
// Parsing a pattern of the form `fieldname: pat`.
|
||||||
let fieldname = self.parse_field_name()?;
|
let fieldname = self.parse_field_name()?;
|
||||||
self.bump();
|
self.bump();
|
||||||
let pat = self.parse_pat_allow_top_alt(
|
let pat = self.parse_pat_allow_top_guard(
|
||||||
None,
|
None,
|
||||||
RecoverComma::No,
|
RecoverComma::No,
|
||||||
RecoverColon::No,
|
RecoverColon::No,
|
||||||
|
|
|
@ -469,7 +469,7 @@ impl<'a> Parser<'a> {
|
||||||
PathStyle::Pat
|
PathStyle::Pat
|
||||||
if let Ok(_) = self
|
if let Ok(_) = self
|
||||||
.parse_paren_comma_seq(|p| {
|
.parse_paren_comma_seq(|p| {
|
||||||
p.parse_pat_allow_top_alt(
|
p.parse_pat_allow_top_guard(
|
||||||
None,
|
None,
|
||||||
RecoverComma::No,
|
RecoverComma::No,
|
||||||
RecoverColon::No,
|
RecoverColon::No,
|
||||||
|
|
|
@ -555,6 +555,7 @@ impl<'v> ast_visit::Visitor<'v> for StatCollector<'v> {
|
||||||
Slice,
|
Slice,
|
||||||
Rest,
|
Rest,
|
||||||
Never,
|
Never,
|
||||||
|
Guard,
|
||||||
Paren,
|
Paren,
|
||||||
MacCall,
|
MacCall,
|
||||||
Err
|
Err
|
||||||
|
|
|
@ -999,6 +999,7 @@ symbols! {
|
||||||
global_registration,
|
global_registration,
|
||||||
globs,
|
globs,
|
||||||
gt,
|
gt,
|
||||||
|
guard_patterns,
|
||||||
half_open_range_patterns,
|
half_open_range_patterns,
|
||||||
half_open_range_patterns_in_slices,
|
half_open_range_patterns_in_slices,
|
||||||
hash,
|
hash,
|
||||||
|
|
|
@ -234,7 +234,7 @@ fn transform_with_focus_on_idx(alternatives: &mut ThinVec<P<Pat>>, focus_idx: us
|
||||||
// In the case of only two patterns, replacement adds net characters.
|
// In the case of only two patterns, replacement adds net characters.
|
||||||
| Ref(_, Mutability::Not)
|
| Ref(_, Mutability::Not)
|
||||||
// Dealt with elsewhere.
|
// Dealt with elsewhere.
|
||||||
| Or(_) | Paren(_) | Deref(_) => false,
|
| Or(_) | Paren(_) | Deref(_) | Guard(..) => false,
|
||||||
// Transform `box x | ... | box y` into `box (x | y)`.
|
// Transform `box x | ... | box y` into `box (x | y)`.
|
||||||
//
|
//
|
||||||
// The cases below until `Slice(...)` deal with *singleton* products.
|
// The cases below until `Slice(...)` deal with *singleton* products.
|
||||||
|
|
|
@ -48,7 +48,8 @@ fn is_short_pattern_inner(pat: &ast::Pat) -> bool {
|
||||||
| ast::PatKind::MacCall(..)
|
| ast::PatKind::MacCall(..)
|
||||||
| ast::PatKind::Slice(..)
|
| ast::PatKind::Slice(..)
|
||||||
| ast::PatKind::Path(..)
|
| ast::PatKind::Path(..)
|
||||||
| ast::PatKind::Range(..) => false,
|
| ast::PatKind::Range(..)
|
||||||
|
| ast::PatKind::Guard(..) => false,
|
||||||
ast::PatKind::Tuple(ref subpats) => subpats.len() <= 1,
|
ast::PatKind::Tuple(ref subpats) => subpats.len() <= 1,
|
||||||
ast::PatKind::TupleStruct(_, ref path, ref subpats) => {
|
ast::PatKind::TupleStruct(_, ref path, ref subpats) => {
|
||||||
path.segments.len() <= 1 && subpats.len() <= 1
|
path.segments.len() <= 1 && subpats.len() <= 1
|
||||||
|
@ -338,8 +339,9 @@ impl Rewrite for Pat {
|
||||||
.max_width_error(shape.width, self.span)?,
|
.max_width_error(shape.width, self.span)?,
|
||||||
)
|
)
|
||||||
.map(|inner_pat| format!("({})", inner_pat)),
|
.map(|inner_pat| format!("({})", inner_pat)),
|
||||||
PatKind::Err(_) => Err(RewriteError::Unknown),
|
PatKind::Guard(..) => Ok(context.snippet(self.span).to_string()),
|
||||||
PatKind::Deref(_) => Err(RewriteError::Unknown),
|
PatKind::Deref(_) => Err(RewriteError::Unknown),
|
||||||
|
PatKind::Err(_) => Err(RewriteError::Unknown),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
12
src/tools/rustfmt/tests/target/guard_patterns.rs
Normal file
12
src/tools/rustfmt/tests/target/guard_patterns.rs
Normal file
|
@ -0,0 +1,12 @@
|
||||||
|
#![feature(guard_patterns)]
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
match user.subscription_plan() {
|
||||||
|
(Plan::Regular if user.credit() >= 100) | (Plan::Premium if user.credit() >= 80) => {
|
||||||
|
// Complete the transaction.
|
||||||
|
}
|
||||||
|
_ => {
|
||||||
|
// The user doesn't have enough credit, return an error message.
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
46
tests/ui/feature-gates/feature-gate-guard-patterns.rs
Normal file
46
tests/ui/feature-gates/feature-gate-guard-patterns.rs
Normal file
|
@ -0,0 +1,46 @@
|
||||||
|
fn match_guards_still_work() {
|
||||||
|
match 0 {
|
||||||
|
0 if guard(0) => {},
|
||||||
|
_ => {},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn other_guards_dont() {
|
||||||
|
match 0 {
|
||||||
|
(0 if guard(0)) => {},
|
||||||
|
//~^ ERROR unexpected parentheses surrounding `match` arm pattern
|
||||||
|
_ => {},
|
||||||
|
}
|
||||||
|
|
||||||
|
match 0 {
|
||||||
|
(0 if guard(0)) | 1 => {},
|
||||||
|
//~^ ERROR: guard patterns are experimental
|
||||||
|
_ => {},
|
||||||
|
}
|
||||||
|
|
||||||
|
let ((x if guard(x)) | x) = 0;
|
||||||
|
//~^ ERROR: guard patterns are experimental
|
||||||
|
//~| ERROR: cannot find value `x`
|
||||||
|
|
||||||
|
if let (x if guard(x)) = 0 {}
|
||||||
|
//~^ ERROR: guard patterns are experimental
|
||||||
|
//~| WARN: irrefutable
|
||||||
|
|
||||||
|
while let (x if guard(x)) = 0 {}
|
||||||
|
//~^ ERROR: guard patterns are experimental
|
||||||
|
//~| WARN: irrefutable
|
||||||
|
|
||||||
|
#[cfg(FALSE)]
|
||||||
|
while let (x if guard(x)) = 0 {}
|
||||||
|
//~^ ERROR: guard patterns are experimental
|
||||||
|
}
|
||||||
|
|
||||||
|
fn even_as_function_parameters(((x if guard(x), _) | (_, x)): (i32, i32)) {}
|
||||||
|
//~^ ERROR: guard patterns are experimental
|
||||||
|
//~| ERROR: cannot find value `x`
|
||||||
|
|
||||||
|
fn guard<T>(x: T) -> bool {
|
||||||
|
unimplemented!()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {}
|
119
tests/ui/feature-gates/feature-gate-guard-patterns.stderr
Normal file
119
tests/ui/feature-gates/feature-gate-guard-patterns.stderr
Normal file
|
@ -0,0 +1,119 @@
|
||||||
|
error: unexpected parentheses surrounding `match` arm pattern
|
||||||
|
--> $DIR/feature-gate-guard-patterns.rs:10:9
|
||||||
|
|
|
||||||
|
LL | (0 if guard(0)) => {},
|
||||||
|
| ^ ^
|
||||||
|
|
|
||||||
|
help: remove parentheses surrounding the pattern
|
||||||
|
|
|
||||||
|
LL - (0 if guard(0)) => {},
|
||||||
|
LL + 0 if guard(0) => {},
|
||||||
|
|
|
||||||
|
|
||||||
|
error[E0425]: cannot find value `x` in this scope
|
||||||
|
--> $DIR/feature-gate-guard-patterns.rs:21:22
|
||||||
|
|
|
||||||
|
LL | let ((x if guard(x)) | x) = 0;
|
||||||
|
| ^ not found in this scope
|
||||||
|
|
||||||
|
error[E0425]: cannot find value `x` in this scope
|
||||||
|
--> $DIR/feature-gate-guard-patterns.rs:38:45
|
||||||
|
|
|
||||||
|
LL | fn even_as_function_parameters(((x if guard(x), _) | (_, x)): (i32, i32)) {}
|
||||||
|
| ^
|
||||||
|
|
|
||||||
|
help: the binding `x` is available in a different scope in the same function
|
||||||
|
--> $DIR/feature-gate-guard-patterns.rs:21:11
|
||||||
|
|
|
||||||
|
LL | let ((x if guard(x)) | x) = 0;
|
||||||
|
| ^
|
||||||
|
|
||||||
|
error[E0658]: guard patterns are experimental
|
||||||
|
--> $DIR/feature-gate-guard-patterns.rs:16:15
|
||||||
|
|
|
||||||
|
LL | (0 if guard(0)) | 1 => {},
|
||||||
|
| ^^^^^^^^
|
||||||
|
|
|
||||||
|
= note: see issue #129967 <https://github.com/rust-lang/rust/issues/129967> for more information
|
||||||
|
= help: add `#![feature(guard_patterns)]` 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: consider using match arm guards
|
||||||
|
|
||||||
|
error[E0658]: guard patterns are experimental
|
||||||
|
--> $DIR/feature-gate-guard-patterns.rs:21:16
|
||||||
|
|
|
||||||
|
LL | let ((x if guard(x)) | x) = 0;
|
||||||
|
| ^^^^^^^^
|
||||||
|
|
|
||||||
|
= note: see issue #129967 <https://github.com/rust-lang/rust/issues/129967> for more information
|
||||||
|
= help: add `#![feature(guard_patterns)]` 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: consider using match arm guards
|
||||||
|
|
||||||
|
error[E0658]: guard patterns are experimental
|
||||||
|
--> $DIR/feature-gate-guard-patterns.rs:25:18
|
||||||
|
|
|
||||||
|
LL | if let (x if guard(x)) = 0 {}
|
||||||
|
| ^^^^^^^^
|
||||||
|
|
|
||||||
|
= note: see issue #129967 <https://github.com/rust-lang/rust/issues/129967> for more information
|
||||||
|
= help: add `#![feature(guard_patterns)]` 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: consider using match arm guards
|
||||||
|
|
||||||
|
error[E0658]: guard patterns are experimental
|
||||||
|
--> $DIR/feature-gate-guard-patterns.rs:29:21
|
||||||
|
|
|
||||||
|
LL | while let (x if guard(x)) = 0 {}
|
||||||
|
| ^^^^^^^^
|
||||||
|
|
|
||||||
|
= note: see issue #129967 <https://github.com/rust-lang/rust/issues/129967> for more information
|
||||||
|
= help: add `#![feature(guard_patterns)]` 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: consider using match arm guards
|
||||||
|
|
||||||
|
error[E0658]: guard patterns are experimental
|
||||||
|
--> $DIR/feature-gate-guard-patterns.rs:34:21
|
||||||
|
|
|
||||||
|
LL | while let (x if guard(x)) = 0 {}
|
||||||
|
| ^^^^^^^^
|
||||||
|
|
|
||||||
|
= note: see issue #129967 <https://github.com/rust-lang/rust/issues/129967> for more information
|
||||||
|
= help: add `#![feature(guard_patterns)]` 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: consider using match arm guards
|
||||||
|
|
||||||
|
error[E0658]: guard patterns are experimental
|
||||||
|
--> $DIR/feature-gate-guard-patterns.rs:38:39
|
||||||
|
|
|
||||||
|
LL | fn even_as_function_parameters(((x if guard(x), _) | (_, x)): (i32, i32)) {}
|
||||||
|
| ^^^^^^^^
|
||||||
|
|
|
||||||
|
= note: see issue #129967 <https://github.com/rust-lang/rust/issues/129967> for more information
|
||||||
|
= help: add `#![feature(guard_patterns)]` 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: consider using match arm guards
|
||||||
|
|
||||||
|
warning: irrefutable `if let` pattern
|
||||||
|
--> $DIR/feature-gate-guard-patterns.rs:25:8
|
||||||
|
|
|
||||||
|
LL | if let (x if guard(x)) = 0 {}
|
||||||
|
| ^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
|
||||||
|
= note: this pattern will always match, so the `if let` is useless
|
||||||
|
= help: consider replacing the `if let` with a `let`
|
||||||
|
= note: `#[warn(irrefutable_let_patterns)]` on by default
|
||||||
|
|
||||||
|
warning: irrefutable `while let` pattern
|
||||||
|
--> $DIR/feature-gate-guard-patterns.rs:29:11
|
||||||
|
|
|
||||||
|
LL | while let (x if guard(x)) = 0 {}
|
||||||
|
| ^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
|
||||||
|
= note: this pattern will always match, so the loop will never exit
|
||||||
|
= help: consider instead using a `loop { ... }` with a `let` inside it
|
||||||
|
|
||||||
|
error: aborting due to 9 previous errors; 2 warnings emitted
|
||||||
|
|
||||||
|
Some errors have detailed explanations: E0425, E0658.
|
||||||
|
For more information about an error, try `rustc --explain E0425`.
|
|
@ -3,7 +3,7 @@ fn foo(c: &[u32], n: u32) -> u32 {
|
||||||
[h, ..] if h > n => 0,
|
[h, ..] if h > n => 0,
|
||||||
[h, ..] if h == n => 1,
|
[h, ..] if h == n => 1,
|
||||||
[h, ref ts..] => foo(c, n - h) + foo(ts, n),
|
[h, ref ts..] => foo(c, n - h) + foo(ts, n),
|
||||||
//~^ ERROR expected one of `,`, `@`, `]`, or `|`, found `..`
|
//~^ ERROR expected one of `,`, `@`, `]`, `if`, or `|`, found `..`
|
||||||
[] => 0,
|
[] => 0,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
error: expected one of `,`, `@`, `]`, or `|`, found `..`
|
error: expected one of `,`, `@`, `]`, `if`, or `|`, found `..`
|
||||||
--> $DIR/issue-72373.rs:5:19
|
--> $DIR/issue-72373.rs:5:19
|
||||||
|
|
|
|
||||||
LL | [h, ref ts..] => foo(c, n - h) + foo(ts, n),
|
LL | [h, ref ts..] => foo(c, n - h) + foo(ts, n),
|
||||||
| ^^ expected one of `,`, `@`, `]`, or `|`
|
| ^^ expected one of `,`, `@`, `]`, `if`, or `|`
|
||||||
|
|
|
|
||||||
help: if you meant to bind the contents of the rest of the array pattern into `ts`, use `@`
|
help: if you meant to bind the contents of the rest of the array pattern into `ts`, use `@`
|
||||||
|
|
|
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
error: expected one of `)`, `,`, `@`, or `|`, found `list`
|
error: expected one of `)`, `,`, `@`, `if`, or `|`, found `list`
|
||||||
--> $DIR/ref.rs:4:19
|
--> $DIR/ref.rs:4:19
|
||||||
|
|
|
|
||||||
LL | Some(refe list) => println!("{list:?}"),
|
LL | Some(refe list) => println!("{list:?}"),
|
||||||
| ^^^^ expected one of `)`, `,`, `@`, or `|`
|
| ^^^^ expected one of `)`, `,`, `@`, `if`, or `|`
|
||||||
|
|
|
|
||||||
help: there is a keyword `ref` with a similar name
|
help: there is a keyword `ref` with a similar name
|
||||||
|
|
|
|
||||||
|
|
|
@ -3,7 +3,7 @@ fn main() {
|
||||||
let foo = core::iter::empty();
|
let foo = core::iter::empty();
|
||||||
|
|
||||||
for Thing(x[]) in foo {}
|
for Thing(x[]) in foo {}
|
||||||
//~^ ERROR: expected one of `)`, `,`, `@`, or `|`, found `[`
|
//~^ ERROR: expected one of `)`, `,`, `@`, `if`, or `|`, found `[`
|
||||||
}
|
}
|
||||||
|
|
||||||
const RECOVERY_WITNESS: () = 0; //~ ERROR mismatched types
|
const RECOVERY_WITNESS: () = 0; //~ ERROR mismatched types
|
||||||
|
|
|
@ -1,10 +1,10 @@
|
||||||
error: expected one of `)`, `,`, `@`, or `|`, found `[`
|
error: expected one of `)`, `,`, `@`, `if`, or `|`, found `[`
|
||||||
--> $DIR/pat-lt-bracket-7.rs:5:16
|
--> $DIR/pat-lt-bracket-7.rs:5:16
|
||||||
|
|
|
|
||||||
LL | for Thing(x[]) in foo {}
|
LL | for Thing(x[]) in foo {}
|
||||||
| ^
|
| ^
|
||||||
| |
|
| |
|
||||||
| expected one of `)`, `,`, `@`, or `|`
|
| expected one of `)`, `,`, `@`, `if`, or `|`
|
||||||
| help: missing `,`
|
| help: missing `,`
|
||||||
|
|
||||||
error[E0308]: mismatched types
|
error[E0308]: mismatched types
|
||||||
|
|
|
@ -27,7 +27,7 @@ fn array_indexing() {
|
||||||
{ let x[0, 1, 2]; } //~ error: expected one of `:`, `;`, `=`, `@`, or `|`, found `[`
|
{ let x[0, 1, 2]; } //~ error: expected one of `:`, `;`, `=`, `@`, or `|`, found `[`
|
||||||
{ let x[0; 20]; } //~ 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 `[`
|
||||||
{ let (x[]); } //~ error: expected one of `)`, `,`, `@`, or `|`, found `[`
|
{ let (x[]); } //~ error: expected one of `)`, `,`, `@`, `if`, or `|`, found `[`
|
||||||
//~^ missing `,`
|
//~^ missing `,`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -95,12 +95,12 @@ fn main() {
|
||||||
f?() => (),
|
f?() => (),
|
||||||
//~^ error: expected a pattern, found an expression
|
//~^ error: expected a pattern, found an expression
|
||||||
(_ + 1) => (),
|
(_ + 1) => (),
|
||||||
//~^ error: expected one of `)`, `,`, or `|`, found `+`
|
//~^ error: expected one of `)`, `,`, `if`, or `|`, found `+`
|
||||||
}
|
}
|
||||||
|
|
||||||
let 1 + 1 = 2;
|
let 1 + 1 = 2;
|
||||||
//~^ error: expected a pattern, found an expression
|
//~^ error: expected a pattern, found an expression
|
||||||
|
|
||||||
let b = matches!(x, (x * x | x.f()) | x[0]);
|
let b = matches!(x, (x * x | x.f()) | x[0]);
|
||||||
//~^ error: expected one of `)`, `,`, `@`, or `|`, found `*`
|
//~^ error: expected one of `)`, `,`, `@`, `if`, or `|`, found `*`
|
||||||
}
|
}
|
||||||
|
|
|
@ -213,13 +213,13 @@ error: expected one of `:`, `;`, `=`, `@`, or `|`, found `[`
|
||||||
LL | { let x[]; }
|
LL | { let x[]; }
|
||||||
| ^ expected one of `:`, `;`, `=`, `@`, or `|`
|
| ^ expected one of `:`, `;`, `=`, `@`, or `|`
|
||||||
|
|
||||||
error: expected one of `)`, `,`, `@`, or `|`, found `[`
|
error: expected one of `)`, `,`, `@`, `if`, or `|`, found `[`
|
||||||
--> $DIR/recover-pat-exprs.rs:30:13
|
--> $DIR/recover-pat-exprs.rs:30:13
|
||||||
|
|
|
|
||||||
LL | { let (x[]); }
|
LL | { let (x[]); }
|
||||||
| ^
|
| ^
|
||||||
| |
|
| |
|
||||||
| expected one of `)`, `,`, `@`, or `|`
|
| expected one of `)`, `,`, `@`, `if`, or `|`
|
||||||
| help: missing `,`
|
| help: missing `,`
|
||||||
|
|
||||||
error: expected a pattern, found an expression
|
error: expected a pattern, found an expression
|
||||||
|
@ -611,11 +611,11 @@ LL | x.sqrt() @ .. => (),
|
||||||
|
|
|
|
||||||
= note: bindings are `x`, `mut x`, `ref x`, and `ref mut x`
|
= note: bindings are `x`, `mut x`, `ref x`, and `ref mut x`
|
||||||
|
|
||||||
error: expected one of `)`, `,`, or `|`, found `+`
|
error: expected one of `)`, `,`, `if`, or `|`, found `+`
|
||||||
--> $DIR/recover-pat-exprs.rs:97:12
|
--> $DIR/recover-pat-exprs.rs:97:12
|
||||||
|
|
|
|
||||||
LL | (_ + 1) => (),
|
LL | (_ + 1) => (),
|
||||||
| ^ expected one of `)`, `,`, or `|`
|
| ^ expected one of `)`, `,`, `if`, or `|`
|
||||||
|
|
||||||
error: expected a pattern, found an expression
|
error: expected a pattern, found an expression
|
||||||
--> $DIR/recover-pat-exprs.rs:81:9
|
--> $DIR/recover-pat-exprs.rs:81:9
|
||||||
|
@ -772,11 +772,11 @@ LL | let 1 + 1 = 2;
|
||||||
|
|
|
|
||||||
= note: arbitrary expressions are not allowed in patterns: <https://doc.rust-lang.org/book/ch19-00-patterns.html>
|
= note: arbitrary expressions are not allowed in patterns: <https://doc.rust-lang.org/book/ch19-00-patterns.html>
|
||||||
|
|
||||||
error: expected one of `)`, `,`, `@`, or `|`, found `*`
|
error: expected one of `)`, `,`, `@`, `if`, or `|`, found `*`
|
||||||
--> $DIR/recover-pat-exprs.rs:104:28
|
--> $DIR/recover-pat-exprs.rs:104:28
|
||||||
|
|
|
|
||||||
LL | let b = matches!(x, (x * x | x.f()) | x[0]);
|
LL | let b = matches!(x, (x * x | x.f()) | x[0]);
|
||||||
| ^ expected one of `)`, `,`, `@`, or `|`
|
| ^ expected one of `)`, `,`, `@`, `if`, or `|`
|
||||||
--> $SRC_DIR/core/src/macros/mod.rs:LL:COL
|
--> $SRC_DIR/core/src/macros/mod.rs:LL:COL
|
||||||
|
|
|
|
||||||
= note: while parsing argument for this `pat` macro fragment
|
= note: while parsing argument for this `pat` macro fragment
|
||||||
|
|
|
@ -8,7 +8,7 @@ fn a() {
|
||||||
|
|
||||||
fn b() {
|
fn b() {
|
||||||
match 2 {
|
match 2 {
|
||||||
(_ % 4) => () //~ error: expected one of `)`, `,`, or `|`, found `%`
|
(_ % 4) => () //~ error: expected one of `)`, `,`, `if`, or `|`, found `%`
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -40,7 +40,7 @@ fn f() {
|
||||||
|
|
||||||
fn g() {
|
fn g() {
|
||||||
match 7 {
|
match 7 {
|
||||||
(_ * 0)..5 => () //~ error: expected one of `)`, `,`, or `|`, found `*`
|
(_ * 0)..5 => () //~ error: expected one of `)`, `,`, `if`, or `|`, found `*`
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -4,11 +4,11 @@ error: expected one of `=>`, `if`, or `|`, found `+`
|
||||||
LL | _ + 1 => ()
|
LL | _ + 1 => ()
|
||||||
| ^ expected one of `=>`, `if`, or `|`
|
| ^ expected one of `=>`, `if`, or `|`
|
||||||
|
|
||||||
error: expected one of `)`, `,`, or `|`, found `%`
|
error: expected one of `)`, `,`, `if`, or `|`, found `%`
|
||||||
--> $DIR/recover-pat-wildcards.rs:11:12
|
--> $DIR/recover-pat-wildcards.rs:11:12
|
||||||
|
|
|
|
||||||
LL | (_ % 4) => ()
|
LL | (_ % 4) => ()
|
||||||
| ^ expected one of `)`, `,`, or `|`
|
| ^ expected one of `)`, `,`, `if`, or `|`
|
||||||
|
|
||||||
error: expected one of `=>`, `if`, or `|`, found `.`
|
error: expected one of `=>`, `if`, or `|`, found `.`
|
||||||
--> $DIR/recover-pat-wildcards.rs:17:10
|
--> $DIR/recover-pat-wildcards.rs:17:10
|
||||||
|
@ -47,11 +47,11 @@ error: expected one of `=>`, `if`, or `|`, found reserved identifier `_`
|
||||||
LL | 0..._ => ()
|
LL | 0..._ => ()
|
||||||
| ^ expected one of `=>`, `if`, or `|`
|
| ^ expected one of `=>`, `if`, or `|`
|
||||||
|
|
||||||
error: expected one of `)`, `,`, or `|`, found `*`
|
error: expected one of `)`, `,`, `if`, or `|`, found `*`
|
||||||
--> $DIR/recover-pat-wildcards.rs:43:12
|
--> $DIR/recover-pat-wildcards.rs:43:12
|
||||||
|
|
|
|
||||||
LL | (_ * 0)..5 => ()
|
LL | (_ * 0)..5 => ()
|
||||||
| ^ expected one of `)`, `,`, or `|`
|
| ^ expected one of `)`, `,`, `if`, or `|`
|
||||||
|
|
||||||
error: expected one of `=>`, `if`, or `|`, found `(`
|
error: expected one of `=>`, `if`, or `|`, found `(`
|
||||||
--> $DIR/recover-pat-wildcards.rs:49:11
|
--> $DIR/recover-pat-wildcards.rs:49:11
|
||||||
|
|
|
@ -6,11 +6,11 @@ LL | let a: u8 @ b = 0;
|
||||||
| |
|
| |
|
||||||
| while parsing the type for `a`
|
| while parsing the type for `a`
|
||||||
|
|
||||||
error: expected one of `)`, `,`, `@`, or `|`, found `:`
|
error: expected one of `)`, `,`, `@`, `if`, or `|`, found `:`
|
||||||
--> $DIR/nested-type-ascription-syntactically-invalid.rs:24:15
|
--> $DIR/nested-type-ascription-syntactically-invalid.rs:24:15
|
||||||
|
|
|
|
||||||
LL | let a @ (b: u8);
|
LL | let a @ (b: u8);
|
||||||
| ^ expected one of `)`, `,`, `@`, or `|`
|
| ^ expected one of `)`, `,`, `@`, `if`, or `|`
|
||||||
|
|
|
|
||||||
= note: type ascription syntax has been removed, see issue #101728 <https://github.com/rust-lang/rust/issues/101728>
|
= note: type ascription syntax has been removed, see issue #101728 <https://github.com/rust-lang/rust/issues/101728>
|
||||||
|
|
||||||
|
|
20
tests/ui/pattern/rfc-3637-guard-patterns/macro-rules.rs
Normal file
20
tests/ui/pattern/rfc-3637-guard-patterns/macro-rules.rs
Normal file
|
@ -0,0 +1,20 @@
|
||||||
|
//@ run-pass
|
||||||
|
//! Tests that the addition of guard patterns does not change the behavior of the `pat` macro
|
||||||
|
//! fragment.
|
||||||
|
#![feature(guard_patterns)]
|
||||||
|
#![allow(incomplete_features)]
|
||||||
|
|
||||||
|
macro_rules! has_guard {
|
||||||
|
($p:pat) => {
|
||||||
|
false
|
||||||
|
};
|
||||||
|
($p:pat if $e:expr) => {
|
||||||
|
true
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
assert_eq!(has_guard!(Some(_)), false);
|
||||||
|
assert_eq!(has_guard!(Some(_) if true), true);
|
||||||
|
assert_eq!(has_guard!((Some(_) if true)), false);
|
||||||
|
}
|
Loading…
Add table
Add a link
Reference in a new issue