Parse a pattern with no arm

This commit is contained in:
Nadrieril 2023-11-27 03:15:56 +01:00
parent caa488b96e
commit 80bdcbf50a
36 changed files with 420 additions and 279 deletions

View File

@ -658,6 +658,24 @@ impl Pat {
pub fn is_rest(&self) -> bool { pub fn is_rest(&self) -> bool {
matches!(self.kind, PatKind::Rest) matches!(self.kind, PatKind::Rest)
} }
/// Could this be a never pattern? I.e. is it a never pattern modulo macro invocations that
/// might return never patterns?
pub fn could_be_never_pattern(&self) -> bool {
let mut could_be_never_pattern = false;
self.walk(&mut |pat| match &pat.kind {
PatKind::Never | PatKind::MacCall(_) => {
could_be_never_pattern = true;
false
}
PatKind::Or(s) => {
could_be_never_pattern = s.iter().all(|p| p.could_be_never_pattern());
false
}
_ => true,
});
could_be_never_pattern
}
} }
/// A single field in a struct pattern. /// A single field in a struct pattern.
@ -1080,8 +1098,8 @@ pub struct Arm {
pub pat: P<Pat>, pub pat: P<Pat>,
/// Match arm guard, e.g. `n > 10` in `match foo { n if n > 10 => {}, _ => {} }` /// Match arm guard, e.g. `n > 10` in `match foo { n if n > 10 => {}, _ => {} }`
pub guard: Option<P<Expr>>, pub guard: Option<P<Expr>>,
/// Match arm body. /// Match arm body. Omitted if the pattern is a never pattern.
pub body: P<Expr>, pub body: Option<P<Expr>>,
pub span: Span, pub span: Span,
pub id: NodeId, pub id: NodeId,
pub is_placeholder: bool, pub is_placeholder: bool,

View File

@ -453,7 +453,7 @@ pub fn noop_flat_map_arm<T: MutVisitor>(mut arm: Arm, vis: &mut T) -> SmallVec<[
vis.visit_id(id); vis.visit_id(id);
vis.visit_pat(pat); vis.visit_pat(pat);
visit_opt(guard, |guard| vis.visit_expr(guard)); visit_opt(guard, |guard| vis.visit_expr(guard));
vis.visit_expr(body); visit_opt(body, |body| vis.visit_expr(body));
vis.visit_span(span); vis.visit_span(span);
smallvec![arm] smallvec![arm]
} }

View File

@ -951,7 +951,7 @@ pub fn walk_param<'a, V: Visitor<'a>>(visitor: &mut V, param: &'a Param) {
pub fn walk_arm<'a, V: Visitor<'a>>(visitor: &mut V, arm: &'a Arm) { pub fn walk_arm<'a, V: Visitor<'a>>(visitor: &mut V, arm: &'a Arm) {
visitor.visit_pat(&arm.pat); visitor.visit_pat(&arm.pat);
walk_list!(visitor, visit_expr, &arm.guard); walk_list!(visitor, visit_expr, &arm.guard);
visitor.visit_expr(&arm.body); walk_list!(visitor, visit_expr, &arm.body);
walk_list!(visitor, visit_attribute, &arm.attrs); walk_list!(visitor, visit_attribute, &arm.attrs);
} }

View File

@ -566,13 +566,28 @@ impl<'hir> LoweringContext<'_, 'hir> {
}); });
let hir_id = self.next_id(); let hir_id = self.next_id();
self.lower_attrs(hir_id, &arm.attrs); self.lower_attrs(hir_id, &arm.attrs);
hir::Arm { let body = if let Some(body) = &arm.body {
hir_id, self.lower_expr(body)
pat, } else {
guard, // An arm without a body, meant for never patterns.
body: self.lower_expr(&arm.body), // We add a fake `loop {}` arm body so that it typecks to `!`.
span: self.lower_span(arm.span), // FIXME(never_patterns): Desugar into a call to `unreachable_unchecked`.
} let span = pat.span;
let block = self.arena.alloc(hir::Block {
stmts: &[],
expr: None,
hir_id: self.next_id(),
rules: hir::BlockCheckMode::DefaultBlock,
span,
targeted_by_break: false,
});
self.arena.alloc(hir::Expr {
hir_id: self.next_id(),
kind: hir::ExprKind::Loop(block, None, hir::LoopSource::Loop, span),
span,
})
};
hir::Arm { hir_id, pat, guard, body, span: self.lower_span(arm.span) }
} }
/// Lower an `async` construct to a coroutine that implements `Future`. /// Lower an `async` construct to a coroutine that implements `Future`.

View File

@ -631,28 +631,33 @@ impl<'a> State<'a> {
self.print_expr(e); self.print_expr(e);
self.space(); self.space();
} }
self.word_space("=>");
match &arm.body.kind { if let Some(body) = &arm.body {
ast::ExprKind::Block(blk, opt_label) => { self.word_space("=>");
if let Some(label) = opt_label {
self.print_ident(label.ident); match &body.kind {
self.word_space(":"); ast::ExprKind::Block(blk, opt_label) => {
if let Some(label) = opt_label {
self.print_ident(label.ident);
self.word_space(":");
}
// The block will close the pattern's ibox.
self.print_block_unclosed_indent(blk);
// If it is a user-provided unsafe block, print a comma after it.
if let BlockCheckMode::Unsafe(ast::UserProvided) = blk.rules {
self.word(",");
}
} }
_ => {
// The block will close the pattern's ibox. self.end(); // Close the ibox for the pattern.
self.print_block_unclosed_indent(blk); self.print_expr(body);
// If it is a user-provided unsafe block, print a comma after it.
if let BlockCheckMode::Unsafe(ast::UserProvided) = blk.rules {
self.word(","); self.word(",");
} }
} }
_ => { } else {
self.end(); // Close the ibox for the pattern. self.word(",");
self.print_expr(&arm.body);
self.word(",");
}
} }
self.end(); // Close enclosing cbox. self.end(); // Close enclosing cbox.
} }

View File

@ -136,7 +136,7 @@ fn cs_partial_cmp(
&& let Some(last) = arms.last_mut() && let Some(last) = arms.last_mut()
&& let PatKind::Wild = last.pat.kind && let PatKind::Wild = last.pat.kind
{ {
last.body = expr2; last.body = Some(expr2);
expr1 expr1
} else { } else {
let eq_arm = cx.arm( let eq_arm = cx.arm(

View File

@ -505,7 +505,7 @@ impl<'a> ExtCtxt<'a> {
attrs: AttrVec::new(), attrs: AttrVec::new(),
pat, pat,
guard: None, guard: None,
body: expr, body: Some(expr),
span, span,
id: ast::DUMMY_NODE_ID, id: ast::DUMMY_NODE_ID,
is_placeholder: false, is_placeholder: false,

View File

@ -119,7 +119,7 @@ pub fn placeholder(
}]), }]),
AstFragmentKind::Arms => AstFragment::Arms(smallvec![ast::Arm { AstFragmentKind::Arms => AstFragment::Arms(smallvec![ast::Arm {
attrs: Default::default(), attrs: Default::default(),
body: expr_placeholder(), body: Some(expr_placeholder()),
guard: None, guard: None,
id, id,
pat: pat(), pat: pat(),

View File

@ -1000,8 +1000,10 @@ impl EarlyLintPass for UnusedDocComment {
} }
fn check_arm(&mut self, cx: &EarlyContext<'_>, arm: &ast::Arm) { fn check_arm(&mut self, cx: &EarlyContext<'_>, arm: &ast::Arm) {
let arm_span = arm.pat.span.with_hi(arm.body.span.hi()); if let Some(body) = &arm.body {
warn_if_doc(cx, arm_span, "match arms", &arm.attrs); let arm_span = arm.pat.span.with_hi(body.span.hi());
warn_if_doc(cx, arm_span, "match arms", &arm.attrs);
}
} }
fn check_pat(&mut self, cx: &EarlyContext<'_>, pat: &ast::Pat) { fn check_pat(&mut self, cx: &EarlyContext<'_>, pat: &ast::Pat) {

View File

@ -1113,15 +1113,17 @@ impl EarlyLintPass for UnusedParens {
} }
ExprKind::Match(ref _expr, ref arm) => { ExprKind::Match(ref _expr, ref arm) => {
for a in arm { for a in arm {
self.check_unused_delims_expr( if let Some(body) = &a.body {
cx, self.check_unused_delims_expr(
&a.body, cx,
UnusedDelimsCtx::MatchArmExpr, body,
false, UnusedDelimsCtx::MatchArmExpr,
None, false,
None, None,
true, None,
); true,
);
}
} }
} }
_ => {} _ => {}

View File

@ -2899,127 +2899,155 @@ impl<'a> Parser<'a> {
self.collect_tokens_trailing_token(attrs, ForceCollect::No, |this, attrs| { self.collect_tokens_trailing_token(attrs, ForceCollect::No, |this, attrs| {
let lo = this.token.span; let lo = this.token.span;
let (pat, guard) = this.parse_match_arm_pat_and_guard()?; let (pat, guard) = this.parse_match_arm_pat_and_guard()?;
let arrow_span = this.token.span;
if let Err(mut err) = this.expect(&token::FatArrow) {
// We might have a `=>` -> `=` or `->` typo (issue #89396).
if TokenKind::FatArrow
.similar_tokens()
.is_some_and(|similar_tokens| similar_tokens.contains(&this.token.kind))
{
err.span_suggestion(
this.token.span,
"use a fat arrow to start a match arm",
"=>",
Applicability::MachineApplicable,
);
if matches!(
(&this.prev_token.kind, &this.token.kind),
(token::DotDotEq, token::Gt)
) {
// `error_inclusive_range_match_arrow` handles cases like `0..=> {}`,
// so we suppress the error here
err.delay_as_bug();
} else {
err.emit();
}
this.bump();
} else {
return Err(err);
}
}
let arm_start_span = this.token.span;
let expr = this.parse_expr_res(Restrictions::STMT_EXPR, None).map_err(|mut err| { let span_before_body = this.prev_token.span;
err.span_label(arrow_span, "while parsing the `match` arm starting here"); let arm_body;
err let is_fat_arrow = this.check(&token::FatArrow);
})?; let is_almost_fat_arrow = TokenKind::FatArrow
.similar_tokens()
let require_comma = classify::expr_requires_semi_to_be_stmt(&expr) .is_some_and(|similar_tokens| similar_tokens.contains(&this.token.kind));
&& this.token != token::CloseDelim(Delimiter::Brace); let mut result = if !is_fat_arrow && !is_almost_fat_arrow {
// A pattern without a body, allowed for never patterns.
let hi = this.prev_token.span; arm_body = None;
if require_comma {
let sm = this.sess.source_map();
if let Some(body) = this.parse_arm_body_missing_braces(&expr, arrow_span) {
let span = body.span;
return Ok((
ast::Arm {
attrs,
pat,
guard,
body,
span,
id: DUMMY_NODE_ID,
is_placeholder: false,
},
TrailingToken::None,
));
}
this.expect_one_of(&[token::Comma], &[token::CloseDelim(Delimiter::Brace)]) this.expect_one_of(&[token::Comma], &[token::CloseDelim(Delimiter::Brace)])
.or_else(|mut err| {
if this.token == token::FatArrow {
if let Ok(expr_lines) = sm.span_to_lines(expr.span)
&& let Ok(arm_start_lines) = sm.span_to_lines(arm_start_span)
&& arm_start_lines.lines[0].end_col == expr_lines.lines[0].end_col
&& expr_lines.lines.len() == 2
{
// We check whether there's any trailing code in the parse span,
// if there isn't, we very likely have the following:
//
// X | &Y => "y"
// | -- - missing comma
// | |
// | arrow_span
// X | &X => "x"
// | - ^^ self.token.span
// | |
// | parsed until here as `"y" & X`
err.span_suggestion_short(
arm_start_span.shrink_to_hi(),
"missing a comma here to end this `match` arm",
",",
Applicability::MachineApplicable,
);
return Err(err);
}
} else {
// FIXME(compiler-errors): We could also recover `; PAT =>` here
// Try to parse a following `PAT =>`, if successful
// then we should recover.
let mut snapshot = this.create_snapshot_for_diagnostic();
let pattern_follows = snapshot
.parse_pat_allow_top_alt(
None,
RecoverComma::Yes,
RecoverColon::Yes,
CommaRecoveryMode::EitherTupleOrPipe,
)
.map_err(|err| err.cancel())
.is_ok();
if pattern_follows && snapshot.check(&TokenKind::FatArrow) {
err.cancel();
this.sess.emit_err(errors::MissingCommaAfterMatchArm {
span: hi.shrink_to_hi(),
});
return Ok(true);
}
}
err.span_label(arrow_span, "while parsing the `match` arm starting here");
Err(err)
})?;
} else { } else {
this.eat(&token::Comma); if let Err(mut err) = this.expect(&token::FatArrow) {
// We might have a `=>` -> `=` or `->` typo (issue #89396).
if is_almost_fat_arrow {
err.span_suggestion(
this.token.span,
"use a fat arrow to start a match arm",
"=>",
Applicability::MachineApplicable,
);
if matches!(
(&this.prev_token.kind, &this.token.kind),
(token::DotDotEq, token::Gt)
) {
// `error_inclusive_range_match_arrow` handles cases like `0..=> {}`,
// so we suppress the error here
err.delay_as_bug();
} else {
err.emit();
}
this.bump();
} else {
return Err(err);
}
}
let arrow_span = this.prev_token.span;
let arm_start_span = this.token.span;
let expr =
this.parse_expr_res(Restrictions::STMT_EXPR, None).map_err(|mut err| {
err.span_label(arrow_span, "while parsing the `match` arm starting here");
err
})?;
let require_comma = classify::expr_requires_semi_to_be_stmt(&expr)
&& this.token != token::CloseDelim(Delimiter::Brace);
if !require_comma {
arm_body = Some(expr);
this.eat(&token::Comma);
Ok(false)
} else if let Some(body) = this.parse_arm_body_missing_braces(&expr, arrow_span) {
arm_body = Some(body);
Ok(true)
} else {
let expr_span = expr.span;
arm_body = Some(expr);
this.expect_one_of(&[token::Comma], &[token::CloseDelim(Delimiter::Brace)])
.map_err(|mut err| {
if this.token == token::FatArrow {
let sm = this.sess.source_map();
if let Ok(expr_lines) = sm.span_to_lines(expr_span)
&& let Ok(arm_start_lines) = sm.span_to_lines(arm_start_span)
&& arm_start_lines.lines[0].end_col
== expr_lines.lines[0].end_col
&& expr_lines.lines.len() == 2
{
// We check whether there's any trailing code in the parse span,
// if there isn't, we very likely have the following:
//
// X | &Y => "y"
// | -- - missing comma
// | |
// | arrow_span
// X | &X => "x"
// | - ^^ self.token.span
// | |
// | parsed until here as `"y" & X`
err.span_suggestion_short(
arm_start_span.shrink_to_hi(),
"missing a comma here to end this `match` arm",
",",
Applicability::MachineApplicable,
);
}
} else {
err.span_label(
arrow_span,
"while parsing the `match` arm starting here",
);
}
err
})
}
};
let hi_span = arm_body.as_ref().map_or(span_before_body, |body| body.span);
let arm_span = lo.to(hi_span);
// We want to recover:
// X | Some(_) => foo()
// | - missing comma
// X | None => "x"
// | ^^^^ self.token.span
// as well as:
// X | Some(!)
// | - missing comma
// X | None => "x"
// | ^^^^ self.token.span
// But we musn't recover
// X | pat[0] => {}
// | ^ self.token.span
let recover_missing_comma = arm_body.is_some() || pat.could_be_never_pattern();
if recover_missing_comma {
result = result.or_else(|err| {
// FIXME(compiler-errors): We could also recover `; PAT =>` here
// Try to parse a following `PAT =>`, if successful
// then we should recover.
let mut snapshot = this.create_snapshot_for_diagnostic();
let pattern_follows = snapshot
.parse_pat_allow_top_alt(
None,
RecoverComma::Yes,
RecoverColon::Yes,
CommaRecoveryMode::EitherTupleOrPipe,
)
.map_err(|err| err.cancel())
.is_ok();
if pattern_follows && snapshot.check(&TokenKind::FatArrow) {
err.cancel();
this.sess.emit_err(errors::MissingCommaAfterMatchArm {
span: arm_span.shrink_to_hi(),
});
return Ok(true);
}
Err(err)
});
} }
result?;
Ok(( Ok((
ast::Arm { ast::Arm {
attrs, attrs,
pat, pat,
guard, guard,
body: expr, body: arm_body,
span: lo.to(hi), span: arm_span,
id: DUMMY_NODE_ID, id: DUMMY_NODE_ID,
is_placeholder: false, is_placeholder: false,
}, },

View File

@ -154,7 +154,7 @@ impl<'a> Parser<'a> {
} }
Err(err) => return Err(err), Err(err) => return Err(err),
}; };
if rc == RecoverComma::Yes { if rc == RecoverComma::Yes && !first_pat.could_be_never_pattern() {
self.maybe_recover_unexpected_comma( self.maybe_recover_unexpected_comma(
first_pat.span, first_pat.span,
matches!(first_pat.kind, PatKind::MacCall(_)), matches!(first_pat.kind, PatKind::MacCall(_)),
@ -200,7 +200,7 @@ impl<'a> Parser<'a> {
err.span_label(lo, WHILE_PARSING_OR_MSG); err.span_label(lo, WHILE_PARSING_OR_MSG);
err err
})?; })?;
if rc == RecoverComma::Yes { if rc == RecoverComma::Yes && !pat.could_be_never_pattern() {
self.maybe_recover_unexpected_comma(pat.span, false, rt)?; self.maybe_recover_unexpected_comma(pat.span, false, rt)?;
} }
pats.push(pat); pats.push(pat);

View File

@ -3294,7 +3294,7 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> {
self.with_rib(ValueNS, RibKind::Normal, |this| { self.with_rib(ValueNS, RibKind::Normal, |this| {
this.resolve_pattern_top(&arm.pat, PatternSource::Match); this.resolve_pattern_top(&arm.pat, PatternSource::Match);
walk_list!(this, visit_expr, &arm.guard); walk_list!(this, visit_expr, &arm.guard);
this.visit_expr(&arm.body); walk_list!(this, visit_expr, &arm.body);
}); });
} }

View File

@ -341,7 +341,9 @@ impl<'a, 'tcx> Visitor<'tcx> for SimilarNamesLocalVisitor<'a, 'tcx> {
self.apply(|this| { self.apply(|this| {
SimilarNamesNameVisitor(this).visit_pat(&arm.pat); SimilarNamesNameVisitor(this).visit_pat(&arm.pat);
this.apply(|this| walk_expr(this, &arm.body)); if let Some(body) = &arm.body {
this.apply(|this| walk_expr(this, body));
}
}); });
self.check_single_char_names(); self.check_single_char_names();

View File

@ -105,7 +105,9 @@ impl<'ast> Visitor<'ast> for BreakVisitor {
fn visit_expr(&mut self, expr: &'ast Expr) { fn visit_expr(&mut self, expr: &'ast Expr) {
self.is_break = match expr.kind { self.is_break = match expr.kind {
ExprKind::Break(..) | ExprKind::Continue(..) | ExprKind::Ret(..) => true, ExprKind::Break(..) | ExprKind::Continue(..) | ExprKind::Ret(..) => true,
ExprKind::Match(_, ref arms) => arms.iter().all(|arm| self.check_expr(&arm.body)), ExprKind::Match(_, ref arms) => arms.iter().all(|arm|
arm.body.is_none() || arm.body.as_deref().is_some_and(|body| self.check_expr(body))
),
ExprKind::If(_, ref then, Some(ref els)) => self.check_block(then) && self.check_expr(els), ExprKind::If(_, ref then, Some(ref els)) => self.check_block(then) && self.check_expr(els),
ExprKind::If(_, _, None) ExprKind::If(_, _, None)
// ignore loops for simplicity // ignore loops for simplicity

View File

@ -236,7 +236,7 @@ pub fn eq_field(l: &ExprField, r: &ExprField) -> bool {
pub fn eq_arm(l: &Arm, r: &Arm) -> bool { pub fn eq_arm(l: &Arm, r: &Arm) -> bool {
l.is_placeholder == r.is_placeholder l.is_placeholder == r.is_placeholder
&& eq_pat(&l.pat, &r.pat) && eq_pat(&l.pat, &r.pat)
&& eq_expr(&l.body, &r.body) && eq_expr_opt(&l.body, &r.body)
&& eq_expr_opt(&l.guard, &r.guard) && eq_expr_opt(&l.guard, &r.guard)
&& over(&l.attrs, &r.attrs, eq_attr) && over(&l.attrs, &r.attrs, eq_attr)
} }

View File

@ -223,7 +223,7 @@ fn rewrite_match_arm(
) -> Option<String> { ) -> Option<String> {
let (missing_span, attrs_str) = if !arm.attrs.is_empty() { let (missing_span, attrs_str) = if !arm.attrs.is_empty() {
if contains_skip(&arm.attrs) { if contains_skip(&arm.attrs) {
let (_, body) = flatten_arm_body(context, &arm.body, None); let (_, body) = flatten_arm_body(context, arm.body.as_deref()?, None);
// `arm.span()` does not include trailing comma, add it manually. // `arm.span()` does not include trailing comma, add it manually.
return Some(format!( return Some(format!(
"{}{}", "{}{}",
@ -246,7 +246,7 @@ fn rewrite_match_arm(
}; };
// Patterns // Patterns
let pat_shape = match &arm.body.kind { let pat_shape = match &arm.body.as_ref()?.kind {
ast::ExprKind::Block(_, Some(label)) => { ast::ExprKind::Block(_, Some(label)) => {
// Some block with a label ` => 'label: {` // Some block with a label ` => 'label: {`
// 7 = ` => : {` // 7 = ` => : {`
@ -280,10 +280,10 @@ fn rewrite_match_arm(
false, false,
)?; )?;
let arrow_span = mk_sp(arm.pat.span.hi(), arm.body.span().lo()); let arrow_span = mk_sp(arm.pat.span.hi(), arm.body.as_ref()?.span().lo());
rewrite_match_body( rewrite_match_body(
context, context,
&arm.body, arm.body.as_ref()?,
&lhs_str, &lhs_str,
shape, shape,
guard_str.contains('\n'), guard_str.contains('\n'),

View File

@ -97,7 +97,12 @@ impl Spanned for ast::Arm {
} else { } else {
self.attrs[0].span.lo() self.attrs[0].span.lo()
}; };
span_with_attrs_lo_hi!(self, lo, self.body.span.hi()) let hi = if let Some(body) = &self.body {
body.span.hi()
} else {
self.pat.span.hi()
};
span_with_attrs_lo_hi!(self, lo, hi)
} }
} }

View File

@ -17,7 +17,7 @@ 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 one of `,`, `=>`, `if`, `|`, or `}`, found `+`
1 | -3..0 => first_or.push(x), 1 | -3..0 => first_or.push(x),
y @ (0..5 | 6) => or_two.push(y), y @ (0..5 | 6) => or_two.push(y),
y @ 0..const { 5 + 1 } => assert_eq!(y, 5), y @ 0..const { 5 + 1 } => assert_eq!(y, 5),

View File

@ -1,8 +1,8 @@
error: expected one of `=>`, `if`, or `|`, found `+` error: expected one of `,`, `=>`, `if`, `|`, or `}`, found `+`
--> $DIR/range_pat_interactions1.rs:19:17 --> $DIR/range_pat_interactions1.rs:19:17
| |
LL | 0..5+1 => errors_only.push(x), LL | 0..5+1 => errors_only.push(x),
| ^ expected one of `=>`, `if`, or `|` | ^ expected one of `,`, `=>`, `if`, `|`, or `}`
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

View File

@ -9,7 +9,7 @@ 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: inclusive range with no end //~^ error: inclusive range with no end
//~| error: expected one of `=>`, `if`, or `|`, found `(` //~| error: expected one of `,`, `=>`, `if`, `|`, or `}`, found `(`
1 | -3..0 => first_or.push(x), 1 | -3..0 => first_or.push(x),
y @ (0..5 | 6) => or_two.push(y), y @ (0..5 | 6) => or_two.push(y),
y @ 0..const { 5 + 1 } => assert_eq!(y, 5), y @ 0..const { 5 + 1 } => assert_eq!(y, 5),

View File

@ -6,11 +6,11 @@ LL | 0..=(5+1) => errors_only.push(x),
| |
= note: inclusive ranges must be bounded at the end (`..=b` or `a..=b`) = 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/range_pat_interactions2.rs:10:17 --> $DIR/range_pat_interactions2.rs:10:17
| |
LL | 0..=(5+1) => errors_only.push(x), LL | 0..=(5+1) => errors_only.push(x),
| ^ expected one of `=>`, `if`, or `|` | ^ expected one of `,`, `=>`, `if`, `|`, or `}`
error: aborting due to 2 previous errors error: aborting due to 2 previous errors

View File

@ -15,11 +15,12 @@ fn no_arms_or_guards(x: Void) {
None => {} None => {}
} }
match None::<Void> { match None::<Void> {
//~^ ERROR non-exhaustive
Some(!) if true, Some(!) if true,
//~^ ERROR expected one of
None => {} None => {}
} }
match None::<Void> { match None::<Void> {
//~^ ERROR non-exhaustive
Some(!) if true => {} Some(!) if true => {}
None => {} None => {}
} }

View File

@ -1,8 +1,39 @@
error: expected one of `.`, `=>`, `?`, or an operator, found `,` error[E0004]: non-exhaustive patterns: `Some(_)` not covered
--> $DIR/check.rs:18:24 --> $DIR/check.rs:17:11
|
LL | match None::<Void> {
| ^^^^^^^^^^^^ pattern `Some(_)` not covered
|
note: `Option<Void>` defined here
--> $SRC_DIR/core/src/option.rs:LL:COL
::: $SRC_DIR/core/src/option.rs:LL:COL
|
= note: not covered
= note: the matched value is of type `Option<Void>`
help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
|
LL ~ None => {},
LL + Some(_) => todo!()
| |
LL | Some(!) if true,
| ^ expected one of `.`, `=>`, `?`, or an operator
error: aborting due to 1 previous error error[E0004]: non-exhaustive patterns: `Some(_)` not covered
--> $DIR/check.rs:22:11
|
LL | match None::<Void> {
| ^^^^^^^^^^^^ pattern `Some(_)` not covered
|
note: `Option<Void>` defined here
--> $SRC_DIR/core/src/option.rs:LL:COL
::: $SRC_DIR/core/src/option.rs:LL:COL
|
= note: not covered
= note: the matched value is of type `Option<Void>`
help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
|
LL ~ None => {},
LL + Some(_) => todo!()
|
error: aborting due to 2 previous errors
For more information about this error, try `rustc --explain E0004`.

View File

@ -0,0 +1,68 @@
#![feature(never_patterns)]
#![allow(incomplete_features)]
enum Void {}
fn main() {}
macro_rules! never {
() => { ! }
}
fn parse(x: Void) {
match None::<Void> {
None => {}
Some(!),
}
match None::<Void> {
Some(!),
None => {}
}
match None::<Void> {
None => {}
Some(!)
}
match None::<Void> {
Some(!)
//~^ ERROR expected `,` following `match` arm
None => {}
}
match None::<Void> {
Some(!) if true
//~^ ERROR expected `,` following `match` arm
None => {}
}
match None::<Void> {
Some(!) if true,
None => {}
}
match None::<Void> {
Some(!) <=
//~^ ERROR expected one of
}
match x {
never!(),
}
match x {
never!() if true,
}
match x {
never!()
}
match &x {
&never!(),
}
match None::<Void> {
Some(never!()),
None => {}
}
match x { ! }
match &x { &! }
let res: Result<bool, Void> = Ok(false);
let Ok(_) = res;
let Ok(_) | Err(!) = &res; // Disallowed; see #82048.
//~^ ERROR top-level or-patterns are not allowed in `let` bindings
let (Ok(_) | Err(!)) = &res;
let (Ok(_) | Err(&!)) = res.as_ref();
}

View File

@ -0,0 +1,26 @@
error: expected `,` following `match` arm
--> $DIR/parse.rs:26:16
|
LL | Some(!)
| ^ help: missing a comma here to end this `match` arm: `,`
error: expected `,` following `match` arm
--> $DIR/parse.rs:31:24
|
LL | Some(!) if true
| ^ help: missing a comma here to end this `match` arm: `,`
error: expected one of `,`, `=>`, `if`, `|`, or `}`, found `<=`
--> $DIR/parse.rs:40:17
|
LL | Some(!) <=
| ^^ expected one of `,`, `=>`, `if`, `|`, or `}`
error: top-level or-patterns are not allowed in `let` bindings
--> $DIR/parse.rs:64:9
|
LL | let Ok(_) | Err(!) = &res; // Disallowed; see #82048.
| ^^^^^^^^^^^^^^ help: wrap the pattern in parentheses: `(Ok(_) | Err(!))`
error: aborting due to 4 previous errors

View File

@ -84,15 +84,15 @@ fn main() {}
#[cfg(FALSE)] fn e() { match 0 { 0..=#[attr] 10 => () } } #[cfg(FALSE)] fn e() { match 0 { 0..=#[attr] 10 => () } }
//~^ ERROR inclusive range with no end //~^ 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 => () } } #[cfg(FALSE)] fn e() { match 0 { 0..=#[attr] -10 => () } }
//~^ ERROR inclusive range with no end //~^ 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 => () } } #[cfg(FALSE)] fn e() { match 0 { 0..=-#[attr] 10 => () } }
//~^ ERROR unexpected token: `#` //~^ ERROR unexpected token: `#`
#[cfg(FALSE)] fn e() { match 0 { 0..=#[attr] FOO => () } } #[cfg(FALSE)] fn e() { match 0 { 0..=#[attr] FOO => () } }
//~^ ERROR inclusive range with no end //~^ 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(); } #[cfg(FALSE)] fn e() { let _ = x.#![attr]foo(); }
//~^ ERROR unexpected token: `#` //~^ ERROR unexpected token: `#`

View File

@ -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`) = 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 --> $DIR/attr-stmt-expr-attr-bad.rs:85:38
| |
LL | #[cfg(FALSE)] fn e() { match 0 { 0..=#[attr] 10 => () } } 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 error[E0586]: inclusive range with no end
--> $DIR/attr-stmt-expr-attr-bad.rs:88:35 --> $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`) = 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 --> $DIR/attr-stmt-expr-attr-bad.rs:88:38
| |
LL | #[cfg(FALSE)] fn e() { match 0 { 0..=#[attr] -10 => () } } LL | #[cfg(FALSE)] fn e() { match 0 { 0..=#[attr] -10 => () } }
| ^ expected one of `=>`, `if`, or `|` | ^ expected one of `,`, `=>`, `if`, `|`, or `}`
error: unexpected token: `#` error: unexpected token: `#`
--> $DIR/attr-stmt-expr-attr-bad.rs:91:39 --> $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`) = 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 --> $DIR/attr-stmt-expr-attr-bad.rs:93:38
| |
LL | #[cfg(FALSE)] fn e() { match 0 { 0..=#[attr] FOO => () } } LL | #[cfg(FALSE)] fn e() { match 0 { 0..=#[attr] FOO => () } }
| ^ expected one of `=>`, `if`, or `|` | ^ expected one of `,`, `=>`, `if`, `|`, or `}`
error: unexpected token: `#` error: unexpected token: `#`
--> $DIR/attr-stmt-expr-attr-bad.rs:97:34 --> $DIR/attr-stmt-expr-attr-bad.rs:97:34

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 one of `,`, `=>`, `@`, `if`, `|`, or `}`, found `[`
_ => {} _ => {}
} }
} }

View File

@ -1,8 +1,8 @@
error: expected one of `=>`, `@`, `if`, or `|`, found `[` error: expected one of `,`, `=>`, `@`, `if`, `|`, or `}`, found `[`
--> $DIR/issue-24375.rs:6:12 --> $DIR/issue-24375.rs:6:12
| |
LL | tmp[0] => {} LL | tmp[0] => {}
| ^ expected one of `=>`, `@`, `if`, or `|` | ^ expected one of `,`, `=>`, `@`, `if`, `|`, or `}`
error: aborting due to 1 previous error error: aborting due to 1 previous error

View File

@ -1,6 +1,8 @@
macro_rules! arm { macro_rules! arm {
($pattern:pat => $block:block) => { ($pattern:pat => $block:block) => {
$pattern => $block $pattern => $block
//~^ ERROR macro expansion ignores token `=>` and any following
//~| NOTE the usage of `arm!` is likely invalid in pattern context
}; };
} }
@ -9,9 +11,7 @@ fn main() {
match x { match x {
Some(1) => {}, Some(1) => {},
arm!(None => {}), arm!(None => {}),
//~^ NOTE macros cannot expand to match arms //~^ NOTE caused by the macro expansion here
//~| ERROR unexpected `,` in pattern
// doesn't recover
Some(2) => {}, Some(2) => {},
_ => {}, _ => {},
}; };

View File

@ -1,10 +1,13 @@
error: unexpected `,` in pattern error: macro expansion ignores token `=>` and any following
--> $DIR/macro-expand-to-match-arm.rs:11:25 --> $DIR/macro-expand-to-match-arm.rs:3:18
| |
LL | $pattern => $block
| ^^
...
LL | arm!(None => {}), LL | arm!(None => {}),
| ^ | ---------------- caused by the macro expansion here
| |
= note: macros cannot expand to match arms = note: the usage of `arm!` is likely invalid in pattern context
error: aborting due to 1 previous error error: aborting due to 1 previous error

View File

@ -6,7 +6,6 @@ fn main() {
match Some(false) { match Some(false) {
Some(_) Some(_)
} }
//~^ ERROR expected one of
match Some(false) { match Some(false) {
Some(_) Some(_)
_ => {} _ => {}
@ -28,7 +27,6 @@ fn main() {
match Some(false) { match Some(false) {
Some(_) if true Some(_) if true
} }
//~^ ERROR expected one of
match Some(false) { match Some(false) {
Some(_) if true Some(_) if true
_ => {} _ => {}
@ -36,33 +34,28 @@ fn main() {
} }
match Some(false) { match Some(false) {
Some(_) if true, Some(_) if true,
//~^ ERROR expected one of
} }
match Some(false) { match Some(false) {
Some(_) if true, Some(_) if true,
//~^ ERROR expected one of
_ => {} _ => {}
} }
match Some(false) { match Some(false) {
pat!() pat!()
} }
//~^ ERROR expected one of
match Some(false) { match Some(false) {
pat!(), pat!(),
//~^ ERROR unexpected `,` in pattern
} }
match Some(false) { match Some(false) {
pat!() if true, pat!() if true,
//~^ ERROR expected one of
} }
match Some(false) { match Some(false) {
pat!() pat!()
//~^ ERROR expected `,` following `match` arm
//~| HELP missing a comma here
_ => {} _ => {}
//~^ ERROR expected one of
} }
match Some(false) { match Some(false) {
pat!(), pat!(),
//~^ ERROR unexpected `,` in pattern
_ => {} _ => {}
} }
} }

View File

@ -1,21 +1,13 @@
error: expected one of `=>`, `if`, or `|`, found `}` error: expected one of `,`, `=>`, `if`, `|`, or `}`, found reserved identifier `_`
--> $DIR/match-arm-without-body.rs:8:5 --> $DIR/match-arm-without-body.rs:11:9
| |
LL | Some(_) LL | Some(_)
| - expected one of `=>`, `if`, or `|` | - expected one of `,`, `=>`, `if`, `|`, or `}`
LL | }
| ^ unexpected token
error: expected one of `=>`, `if`, or `|`, found reserved identifier `_`
--> $DIR/match-arm-without-body.rs:12:9
|
LL | Some(_)
| - expected one of `=>`, `if`, or `|`
LL | _ => {} LL | _ => {}
| ^ unexpected token | ^ unexpected token
error: unexpected `,` in pattern error: unexpected `,` in pattern
--> $DIR/match-arm-without-body.rs:16:16 --> $DIR/match-arm-without-body.rs:15:16
| |
LL | Some(_), LL | Some(_),
| ^ | ^
@ -30,7 +22,7 @@ LL | Some(_) |
| |
error: unexpected `,` in pattern error: unexpected `,` in pattern
--> $DIR/match-arm-without-body.rs:22:16 --> $DIR/match-arm-without-body.rs:21:16
| |
LL | Some(_), LL | Some(_),
| ^ | ^
@ -52,71 +44,19 @@ LL +
LL ~ _ => {} LL ~ _ => {}
| |
error: expected one of `.`, `=>`, `?`, or an operator, found `}` error: expected one of `,`, `.`, `=>`, `?`, `}`, or an operator, found reserved identifier `_`
--> $DIR/match-arm-without-body.rs:30:5 --> $DIR/match-arm-without-body.rs:32:9
| |
LL | Some(_) if true LL | Some(_) if true
| - expected one of `.`, `=>`, `?`, or an operator | - expected one of `,`, `.`, `=>`, `?`, `}`, or an operator
LL | }
| ^ unexpected token
error: expected one of `.`, `=>`, `?`, or an operator, found reserved identifier `_`
--> $DIR/match-arm-without-body.rs:34:9
|
LL | Some(_) if true
| - expected one of `.`, `=>`, `?`, or an operator
LL | _ => {} LL | _ => {}
| ^ unexpected token | ^ unexpected token
error: expected one of `.`, `=>`, `?`, or an operator, found `,` error: expected `,` following `match` arm
--> $DIR/match-arm-without-body.rs:38:24 --> $DIR/match-arm-without-body.rs:52:15
|
LL | Some(_) if true,
| ^ expected one of `.`, `=>`, `?`, or an operator
error: expected one of `.`, `=>`, `?`, or an operator, found `,`
--> $DIR/match-arm-without-body.rs:42:24
|
LL | Some(_) if true,
| ^ expected one of `.`, `=>`, `?`, or an operator
error: expected one of `=>`, `if`, or `|`, found `}`
--> $DIR/match-arm-without-body.rs:48:5
| |
LL | pat!() LL | pat!()
| - expected one of `=>`, `if`, or `|` | ^ help: missing a comma here to end this `match` arm: `,`
LL | }
| ^ unexpected token
error: unexpected `,` in pattern error: aborting due to 5 previous errors
--> $DIR/match-arm-without-body.rs:51:15
|
LL | pat!(),
| ^
|
= note: macros cannot expand to match arms
error: expected one of `.`, `=>`, `?`, or an operator, found `,`
--> $DIR/match-arm-without-body.rs:55:23
|
LL | pat!() if true,
| ^ expected one of `.`, `=>`, `?`, or an operator
error: expected one of `=>`, `if`, or `|`, found reserved identifier `_`
--> $DIR/match-arm-without-body.rs:60:9
|
LL | pat!()
| - expected one of `=>`, `if`, or `|`
LL | _ => {}
| ^ unexpected token
error: unexpected `,` in pattern
--> $DIR/match-arm-without-body.rs:64:15
|
LL | pat!(),
| ^
|
= note: macros cannot expand to match arms
error: aborting due to 13 previous errors

View File

@ -1,7 +1,7 @@
fn main() { fn main() {
match 42 { match 42 {
x < 7 => (), x < 7 => (),
//~^ error: expected one of `=>`, `@`, `if`, or `|`, found `<` //~^ error: expected one of `,`, `=>`, `@`, `if`, `|`, or `}`, found `<`
_ => () _ => ()
} }
} }

View File

@ -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 --> $DIR/pat-lt-bracket-1.rs:3:7
| |
LL | x < 7 => (), LL | x < 7 => (),
| ^ expected one of `=>`, `@`, `if`, or `|` | ^ expected one of `,`, `=>`, `@`, `if`, `|`, or `}`
error: aborting due to 1 previous error error: aborting due to 1 previous error