Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
36 changes: 35 additions & 1 deletion compiler/rustc_parse/src/parser/expr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -155,7 +155,41 @@ impl<'a> Parser<'a> {
}

self.expected_token_types.insert(TokenType::Operator);
while let Some(op) = self.check_assoc_op() {
// `matches` is parsed as a "trailing let" pseudo-expression in conditions:
//
// if <expr> matches <pat> { ... }
//
// This reuses `ExprKind::Let(<pat>, <expr>, ..)`, i.e. it is equivalent to:
//
// if let <pat> = <expr> { ... }
//
// To avoid breaking valid code that uses `matches` as an identifier, we only
// treat it specially when `Restrictions::ALLOW_LET` is enabled (which is only
// the case when parsing `if`/`while` conditions via `parse_expr_cond`).
loop {
if self.restrictions.contains(Restrictions::ALLOW_LET) {
if let Some((ident, IdentIsRaw::No)) = self.token.ident()
&& ident.name.as_str() == "matches"
{
let lo = lhs.span;
self.bump(); // Eat `matches`
let pat = self.parse_pat_no_top_guard(
None,
RecoverComma::Yes,
RecoverColon::Yes,
CommaRecoveryMode::LikelyTuple,
)?;
let span = lo.to(pat.span);
lhs = self.mk_expr(span, ExprKind::Let(pat, lhs, span, Recovered::No));
parsed_something = true;
// Continue parsing, to allow `&&` let-chains etc.
continue;
}
}

let Some(op) = self.check_assoc_op() else {
break;
};
let lhs_span = self.interpolated_or_expr_span(&lhs);
let cur_op_span = self.token.span;
let restrictions = if op.node.is_assign_like() {
Expand Down
19 changes: 19 additions & 0 deletions tests/ui/parser/if-matches.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
//@ check-pass

fn main() {
let opt = Some(1);

// New "natural" matching syntax (sugar for `if let Some(x) = opt { .. }`).
if opt matches Some(x) {
let _ = x + 1;
} else {
unreachable!();
}

// Still allowed: `matches` as an identifier.
let matches = true;
if matches {
let _ = 0;
}
}