Skip to content
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.

Commit 1361d1a

Browse files
committedJul 6, 2024··
Add suggestions for expressions in patterns
1 parent b317f9f commit 1361d1a

21 files changed

+1152
-86
lines changed
 

‎compiler/rustc_errors/src/lib.rs

+30
Original file line numberDiff line numberDiff line change
@@ -535,6 +535,8 @@ pub enum StashKey {
535535
/// Query cycle detected, stashing in favor of a better error.
536536
Cycle,
537537
UndeterminedMacroResolution,
538+
/// Used by `Parser::maybe_recover_trailing_expr`
539+
ExprInPat,
538540
}
539541

540542
fn default_track_diagnostic<R>(diag: DiagInner, f: &mut dyn FnMut(DiagInner) -> R) -> R {
@@ -837,6 +839,23 @@ impl<'a> DiagCtxtHandle<'a> {
837839
Some(Diag::new_diagnostic(self, diag))
838840
}
839841

842+
/// Steals a previously stashed error with the given `Span` and
843+
/// [`StashKey`] as the key, and cancels it if found.
844+
/// Panics if the found diagnostic's level isn't `Level::Error`.
845+
pub fn steal_err(&self, span: Span, key: StashKey, _: ErrorGuaranteed) -> bool {
846+
let key = (span.with_parent(None), key);
847+
// FIXME(#120456) - is `swap_remove` correct?
848+
self.inner
849+
.borrow_mut()
850+
.stashed_diagnostics
851+
.swap_remove(&key)
852+
.inspect(|(diag, guar)| {
853+
assert_eq!(diag.level, Error);
854+
assert!(guar.is_some())
855+
})
856+
.is_some()
857+
}
858+
840859
/// Steals a previously stashed error with the given `Span` and
841860
/// [`StashKey`] as the key, modifies it, and emits it. Returns `None` if
842861
/// no matching diagnostic is found. Panics if the found diagnostic's level
@@ -1281,6 +1300,17 @@ impl<'a> DiagCtxtHandle<'a> {
12811300
self.create_err(err).emit()
12821301
}
12831302

1303+
/// See [`DiagCtxtHandle::stash_diagnostic`] for details.
1304+
#[track_caller]
1305+
pub fn stash_err(
1306+
&'a self,
1307+
span: Span,
1308+
key: StashKey,
1309+
err: impl Diagnostic<'a>,
1310+
) -> ErrorGuaranteed {
1311+
self.create_err(err).stash(span, key).unwrap()
1312+
}
1313+
12841314
/// Ensures that an error is printed. See `Level::DelayedBug`.
12851315
//
12861316
// No `#[rustc_lint_diagnostics]` and no `impl Into<DiagMessage>` because bug messages aren't

‎compiler/rustc_parse/messages.ftl

+14
Original file line numberDiff line numberDiff line change
@@ -778,6 +778,20 @@ parse_unexpected_expr_in_pat =
778778
779779
.label = arbitrary expressions are not allowed in patterns
780780
781+
parse_unexpected_expr_in_pat_const_sugg = extract the expression into a `const` and refer to it
782+
783+
parse_unexpected_expr_in_pat_create_guard_sugg = check the value in an arm guard
784+
785+
parse_unexpected_expr_in_pat_inline_const_sugg = wrap the expression in a inline const (requires `{"#"}![feature(inline_const_pat)]`)
786+
787+
parse_unexpected_expr_in_pat_remove_let_sugg =
788+
remove the `let` if you meant to {$has_initializer ->
789+
[true] do an assignment
790+
*[false] evaluate an expression
791+
}
792+
793+
parse_unexpected_expr_in_pat_update_guard_sugg = check the value in the arm guard
794+
781795
parse_unexpected_if_with_if = unexpected `if` in the condition expression
782796
.suggestion = remove the `if`
783797

‎compiler/rustc_parse/src/errors.rs

+86
Original file line numberDiff line numberDiff line change
@@ -2424,6 +2424,92 @@ pub(crate) struct UnexpectedExpressionInPattern {
24242424
pub is_bound: bool,
24252425
}
24262426

2427+
#[derive(Subdiagnostic)]
2428+
pub(crate) enum UnexpectedExpressionInPatternSugg {
2429+
#[multipart_suggestion(
2430+
parse_unexpected_expr_in_pat_remove_let_sugg,
2431+
applicability = "maybe-incorrect",
2432+
style = "verbose"
2433+
)]
2434+
RemoveLet {
2435+
/// The span of the `let` keyword.
2436+
#[suggestion_part(code = "")]
2437+
let_span: Span,
2438+
/// The span of the type annotation.
2439+
#[suggestion_part(code = "")]
2440+
ty_span: Option<Span>,
2441+
/// `true` iff the `let` statement has an initializer.
2442+
has_initializer: bool,
2443+
},
2444+
2445+
#[multipart_suggestion(
2446+
parse_unexpected_expr_in_pat_create_guard_sugg,
2447+
applicability = "maybe-incorrect"
2448+
)]
2449+
CreateGuard {
2450+
/// The span of the `PatKind:Err` to be transformed into a `PatKind::Ident`.
2451+
#[suggestion_part(code = "{ident}")]
2452+
ident_span: Span,
2453+
/// The end of the match arm's pattern.
2454+
#[suggestion_part(code = " if {ident} == {expr}")]
2455+
pat_hi: Span,
2456+
/// The suggested identifier.
2457+
ident: String,
2458+
/// `ident_span`'s snippet.
2459+
expr: String,
2460+
},
2461+
2462+
#[multipart_suggestion(
2463+
parse_unexpected_expr_in_pat_update_guard_sugg,
2464+
applicability = "maybe-incorrect"
2465+
)]
2466+
UpdateGuard {
2467+
/// The span of the `PatKind:Err` to be transformed into a `PatKind::Ident`.
2468+
#[suggestion_part(code = "{ident}")]
2469+
ident_span: Span,
2470+
/// The beginning of the match arm guard's expression.
2471+
#[suggestion_part(code = "(")]
2472+
guard_lo: Span,
2473+
/// The end of the match arm guard's expression.
2474+
#[suggestion_part(code = ") && {ident} == {expr}")]
2475+
guard_hi: Span,
2476+
/// The suggested identifier.
2477+
ident: String,
2478+
/// `ident_span`'s snippet.
2479+
expr: String,
2480+
},
2481+
2482+
#[multipart_suggestion(
2483+
parse_unexpected_expr_in_pat_const_sugg,
2484+
applicability = "has-placeholders"
2485+
)]
2486+
Const {
2487+
/// The beginning of statement's line.
2488+
#[suggestion_part(code = "{indentation}const {ident}: _ = {expr};\n")]
2489+
stmt_lo: Span,
2490+
/// The span of the `PatKind:Err` to be transformed into a `PatKind::Ident`.
2491+
#[suggestion_part(code = "{ident}")]
2492+
ident_span: Span,
2493+
/// The suggested identifier.
2494+
ident: String,
2495+
/// `ident_span`'s snippet.
2496+
expr: String,
2497+
/// The statement's block's indentation.
2498+
indentation: String,
2499+
},
2500+
2501+
#[multipart_suggestion(
2502+
parse_unexpected_expr_in_pat_inline_const_sugg,
2503+
applicability = "maybe-incorrect"
2504+
)]
2505+
InlineConst {
2506+
#[suggestion_part(code = "const {{ ")]
2507+
start_span: Span,
2508+
#[suggestion_part(code = " }}")]
2509+
end_span: Span,
2510+
},
2511+
}
2512+
24272513
#[derive(Diagnostic)]
24282514
#[diag(parse_unexpected_paren_in_range_pat)]
24292515
pub(crate) struct UnexpectedParenInRangePat {

‎compiler/rustc_parse/src/parser/pat.rs

+215-10
Original file line numberDiff line numberDiff line change
@@ -6,21 +6,22 @@ use crate::errors::{
66
InclusiveRangeExtraEquals, InclusiveRangeMatchArrow, InclusiveRangeNoEnd, InvalidMutInPattern,
77
PatternOnWrongSideOfAt, RemoveLet, RepeatedMutInPattern, SwitchRefBoxOrder,
88
TopLevelOrPatternNotAllowed, TopLevelOrPatternNotAllowedSugg, TrailingVertNotAllowed,
9-
UnexpectedExpressionInPattern, UnexpectedLifetimeInPattern, UnexpectedParenInRangePat,
10-
UnexpectedParenInRangePatSugg, UnexpectedVertVertBeforeFunctionParam,
11-
UnexpectedVertVertInPattern,
9+
UnexpectedExpressionInPattern, UnexpectedExpressionInPatternSugg, UnexpectedLifetimeInPattern,
10+
UnexpectedParenInRangePat, UnexpectedParenInRangePatSugg,
11+
UnexpectedVertVertBeforeFunctionParam, UnexpectedVertVertInPattern,
1212
};
1313
use crate::parser::expr::{could_be_unclosed_char_literal, DestructuredFloat, LhsExpr};
1414
use crate::{maybe_recover_from_interpolated_ty_qpath, maybe_whole};
1515
use rustc_ast::mut_visit::{noop_visit_pat, MutVisitor};
1616
use rustc_ast::ptr::P;
1717
use rustc_ast::token::{self, BinOpToken, Delimiter, Token};
18+
use rustc_ast::visit::{walk_arm, walk_pat, walk_pat_field, Visitor};
1819
use rustc_ast::{
19-
self as ast, AttrVec, BindingMode, ByRef, Expr, ExprKind, MacCall, Mutability, Pat, PatField,
20-
PatFieldsRest, PatKind, Path, QSelf, RangeEnd, RangeSyntax,
20+
self as ast, Arm, AttrVec, BindingMode, ByRef, Expr, ExprKind, LocalKind, MacCall, Mutability,
21+
Pat, PatField, PatFieldsRest, PatKind, Path, QSelf, RangeEnd, RangeSyntax, Stmt, StmtKind,
2122
};
2223
use rustc_ast_pretty::pprust;
23-
use rustc_errors::{Applicability, Diag, PResult};
24+
use rustc_errors::{Applicability, Diag, PResult, StashKey};
2425
use rustc_session::errors::ExprParenthesesNeeded;
2526
use rustc_span::source_map::{respan, Spanned};
2627
use rustc_span::symbol::{kw, sym, Ident};
@@ -431,12 +432,194 @@ impl<'a> Parser<'a> {
431432
|| self.token.kind == token::CloseDelim(Delimiter::Parenthesis)
432433
&& self.look_ahead(1, Token::is_range_separator);
433434

435+
let span = expr.span;
436+
434437
Some((
435-
self.dcx().emit_err(UnexpectedExpressionInPattern { span: expr.span, is_bound }),
436-
expr.span,
438+
self.dcx().stash_err(
439+
span,
440+
StashKey::ExprInPat,
441+
UnexpectedExpressionInPattern { span, is_bound },
442+
),
443+
span,
437444
))
438445
}
439446

447+
/// Called by [`Parser::parse_stmt_without_recovery`], used to add statement-aware subdiagnostics to the errors stashed
448+
/// by [`Parser::maybe_recover_trailing_expr`].
449+
pub(super) fn maybe_emit_stashed_expr_in_pats(&mut self, stmt: &Stmt) {
450+
if self.dcx().has_errors().is_none() {
451+
// No need to walk the statement if there's no stashed errors.
452+
return;
453+
}
454+
455+
struct PatVisitor<'a> {
456+
/// `self`
457+
parser: &'a Parser<'a>,
458+
/// The freshly-parsed statement.
459+
stmt: &'a Stmt,
460+
/// The current match arm (for arm guard suggestions).
461+
arm: Option<&'a Arm>,
462+
/// The current struct field (for variable name suggestions).
463+
field: Option<&'a PatField>,
464+
}
465+
466+
impl<'a> PatVisitor<'a> {
467+
/// Looks for stashed [`StashKey::ExprInPat`] errors in `stash_span`, and emit them with suggestions.
468+
/// `stash_span` is contained in `expr_span`, the latter being larger in borrow patterns;
469+
/// ```txt
470+
/// &mut x.y
471+
/// -----^^^ `stash_span`
472+
/// |
473+
/// `expr_span`
474+
/// ```
475+
fn emit_now(&self, stash_span: Span, expr_span: Span) {
476+
self.parser.dcx().try_steal_modify_and_emit_err(
477+
stash_span,
478+
StashKey::ExprInPat,
479+
|err| {
480+
let sm = self.parser.psess.source_map();
481+
let stmt = self.stmt;
482+
let line_lo = sm.span_extend_to_line(stmt.span).shrink_to_lo();
483+
let indentation = sm.indentation_before(stmt.span).unwrap_or_default();
484+
let expr = self.parser.span_to_snippet(expr_span).unwrap();
485+
486+
// Includes pre-pats (e.g. `&mut <err>`) in the diagnostic.
487+
err.span.replace(stash_span, expr_span);
488+
489+
if let StmtKind::Let(local) = &stmt.kind {
490+
// help: remove the let
491+
492+
match &local.kind {
493+
// help: remove the `let`
494+
LocalKind::Decl | LocalKind::Init(_) => {
495+
err.subdiagnostic(
496+
UnexpectedExpressionInPatternSugg::RemoveLet {
497+
let_span: local
498+
.span
499+
.shrink_to_lo()
500+
.until(local.pat.span),
501+
ty_span: local
502+
.colon_sp
503+
.map(|sp| sp.to(local.ty.as_ref().unwrap().span)),
504+
has_initializer: !matches!(local.kind, LocalKind::Decl),
505+
},
506+
);
507+
508+
// don't suggest `let const { pat } = expr;`
509+
return;
510+
}
511+
512+
LocalKind::InitElse(_, _) => {}
513+
}
514+
}
515+
516+
// help: use an arm guard `if val == expr`
517+
if let Some(arm) = &self.arm {
518+
let (ident, ident_span) = match self.field {
519+
Some(field) => {
520+
(field.ident.to_string(), field.ident.span.to(expr_span))
521+
}
522+
None => ("val".to_owned(), expr_span),
523+
};
524+
525+
match &arm.guard {
526+
None => {
527+
err.subdiagnostic(
528+
UnexpectedExpressionInPatternSugg::CreateGuard {
529+
ident_span,
530+
pat_hi: arm.pat.span.shrink_to_hi(),
531+
ident,
532+
expr: expr.clone(),
533+
},
534+
);
535+
}
536+
Some(guard) => {
537+
err.subdiagnostic(
538+
UnexpectedExpressionInPatternSugg::UpdateGuard {
539+
ident_span,
540+
guard_lo: guard.span.shrink_to_lo(),
541+
guard_hi: guard.span.shrink_to_hi(),
542+
ident,
543+
expr: expr.clone(),
544+
},
545+
);
546+
}
547+
}
548+
}
549+
550+
// help: extract the expr into a `const VAL: _ = expr`
551+
let ident = match self.field {
552+
Some(field) => field.ident.as_str().to_uppercase(),
553+
None => "VAL".to_owned(),
554+
};
555+
err.subdiagnostic(UnexpectedExpressionInPatternSugg::Const {
556+
stmt_lo: line_lo,
557+
ident_span: expr_span,
558+
expr,
559+
ident,
560+
indentation,
561+
});
562+
563+
// help: wrap the expr in a `const { expr }`
564+
// FIXME(inline_const_pat): once stabilized, remove this check and remove the `(requires #[feature(inline_const_pat)]` note from the message
565+
if self.parser.psess.unstable_features.is_nightly_build() {
566+
err.subdiagnostic(UnexpectedExpressionInPatternSugg::InlineConst {
567+
start_span: expr_span.shrink_to_lo(),
568+
end_span: expr_span.shrink_to_hi(),
569+
});
570+
}
571+
},
572+
);
573+
}
574+
}
575+
576+
impl<'a> Visitor<'a> for PatVisitor<'a> {
577+
fn visit_arm(&mut self, a: &'a Arm) -> Self::Result {
578+
self.arm = Some(a);
579+
walk_arm(self, a);
580+
self.arm = None;
581+
}
582+
583+
fn visit_pat_field(&mut self, fp: &'a PatField) -> Self::Result {
584+
self.field = Some(fp);
585+
walk_pat_field(self, fp);
586+
self.field = None;
587+
}
588+
589+
fn visit_pat(&mut self, p: &'a Pat) -> Self::Result {
590+
match &p.kind {
591+
// Base expression
592+
PatKind::Err(_) => self.emit_now(p.span, p.span),
593+
594+
// Sub-patterns
595+
// FIXME: this doesn't work with recursive subpats (`&mut &mut <err>`)
596+
PatKind::Box(subpat) | PatKind::Ref(subpat, _)
597+
if matches!(subpat.kind, PatKind::Err(_)) =>
598+
{
599+
self.emit_now(subpat.span, p.span)
600+
}
601+
602+
// Sub-expressions
603+
PatKind::Range(start, end, _) => {
604+
if let Some(start) = start {
605+
self.emit_now(start.span, start.span);
606+
}
607+
608+
if let Some(end) = end {
609+
self.emit_now(end.span, end.span);
610+
}
611+
}
612+
613+
// Walk continuation
614+
_ => walk_pat(self, p),
615+
}
616+
}
617+
}
618+
619+
// Starts the visit.
620+
PatVisitor { parser: self, stmt, arm: None, field: None }.visit_stmt(stmt);
621+
}
622+
440623
/// Parses a pattern, with a setting whether modern range patterns (e.g., `a..=b`, `a..b` are
441624
/// allowed).
442625
fn parse_pat_with_range_pat(
@@ -586,7 +769,11 @@ impl<'a> Parser<'a> {
586769

587770
match self.parse_range_end() {
588771
Some(form) => self.parse_pat_range_begin_with(begin, form)?,
589-
None => PatKind::Lit(begin),
772+
None => match &begin.kind {
773+
// Avoid `PatKind::Lit(ExprKind::Err)`
774+
ExprKind::Err(guar) => PatKind::Err(*guar),
775+
_ => PatKind::Lit(begin),
776+
},
590777
}
591778
}
592779
Err(err) => return self.fatal_unexpected_non_pat(err, expected),
@@ -758,7 +945,25 @@ impl<'a> Parser<'a> {
758945

759946
Ok(match self.maybe_recover_trailing_expr(open_paren.to(self.prev_token.span), false) {
760947
None => pat,
761-
Some((guar, _)) => PatKind::Err(guar),
948+
Some((guar, _)) => {
949+
// We just recovered a bigger expression, so cancel its children
950+
// (e.g. `(1 + 2) * 3`, cancel “`1 + 2` is not a pattern”).
951+
match pat {
952+
PatKind::Paren(pat) => {
953+
self.dcx().steal_err(pat.span, StashKey::ExprInPat, guar);
954+
}
955+
956+
PatKind::Tuple(fields) => {
957+
for pat in fields {
958+
self.dcx().steal_err(pat.span, StashKey::ExprInPat, guar);
959+
}
960+
}
961+
962+
_ => unreachable!("{pat:?}"),
963+
}
964+
965+
PatKind::Err(guar)
966+
}
762967
})
763968
}
764969

‎compiler/rustc_parse/src/parser/stmt.rs

+8-2
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,9 @@ use thin_vec::{thin_vec, ThinVec};
3030
impl<'a> Parser<'a> {
3131
/// Parses a statement. This stops just before trailing semicolons on everything but items.
3232
/// e.g., a `StmtKind::Semi` parses to a `StmtKind::Expr`, leaving the trailing `;` unconsumed.
33+
///
34+
/// If `force_collect` is [`ForceCollect::Yes`], forces collection of tokens regardless of
35+
/// whether or not we have attributes.
3336
// Public for rustfmt usage.
3437
pub(super) fn parse_stmt(&mut self, force_collect: ForceCollect) -> PResult<'a, Option<Stmt>> {
3538
Ok(self.parse_stmt_without_recovery(false, force_collect).unwrap_or_else(|e| {
@@ -66,7 +69,7 @@ impl<'a> Parser<'a> {
6669
});
6770
}
6871

69-
Ok(Some(if self.token.is_keyword(kw::Let) {
72+
let stmt = if self.token.is_keyword(kw::Let) {
7073
self.parse_local_mk(lo, attrs, capture_semi, force_collect)?
7174
} else if self.is_kw_followed_by_ident(kw::Mut) && self.may_recover() {
7275
self.recover_stmt_local_after_let(
@@ -140,7 +143,10 @@ impl<'a> Parser<'a> {
140143
} else {
141144
self.error_outer_attrs(attrs);
142145
return Ok(None);
143-
}))
146+
};
147+
148+
self.maybe_emit_stashed_expr_in_pats(&stmt);
149+
Ok(Some(stmt))
144150
}
145151

146152
fn parse_stmt_path_start(&mut self, lo: Span, attrs: AttrWrapper) -> PResult<'a, Stmt> {

‎tests/ui/half-open-range-patterns/range_pat_interactions1.stderr

+15
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,21 @@ error: expected a pattern range bound, found an expression
33
|
44
LL | 0..5+1 => errors_only.push(x),
55
| ^^^ arbitrary expressions are not allowed in patterns
6+
|
7+
help: check the value in an arm guard
8+
|
9+
LL | 0..val if val == 5+1 => errors_only.push(x),
10+
| ~~~ +++++++++++++
11+
help: extract the expression into a `const` and refer to it
12+
|
13+
LL + const VAL: _ = 5+1;
14+
LL ~ match x as i32 {
15+
LL ~ 0..VAL => errors_only.push(x),
16+
|
17+
help: wrap the expression in a inline const (requires `#![feature(inline_const_pat)]`)
18+
|
19+
LL | 0..const { 5+1 } => errors_only.push(x),
20+
| +++++++ +
621

722
error[E0408]: variable `n` is not bound in all patterns
823
--> $DIR/range_pat_interactions1.rs:10:25

‎tests/ui/half-open-range-patterns/range_pat_interactions2.stderr

+21-6
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,3 @@
1-
error: expected a pattern range bound, found an expression
2-
--> $DIR/range_pat_interactions2.rs:10:18
3-
|
4-
LL | 0..=(5+1) => errors_only.push(x),
5-
| ^^^ arbitrary expressions are not allowed in patterns
6-
71
error: range pattern bounds cannot have parentheses
82
--> $DIR/range_pat_interactions2.rs:10:17
93
|
@@ -16,6 +10,27 @@ LL - 0..=(5+1) => errors_only.push(x),
1610
LL + 0..=5+1 => errors_only.push(x),
1711
|
1812

13+
error: expected a pattern range bound, found an expression
14+
--> $DIR/range_pat_interactions2.rs:10:18
15+
|
16+
LL | 0..=(5+1) => errors_only.push(x),
17+
| ^^^ arbitrary expressions are not allowed in patterns
18+
|
19+
help: check the value in an arm guard
20+
|
21+
LL | 0..=(val) if val == 5+1 => errors_only.push(x),
22+
| ~~~ +++++++++++++
23+
help: extract the expression into a `const` and refer to it
24+
|
25+
LL + const VAL: _ = 5+1;
26+
LL ~ match x as i32 {
27+
LL ~ 0..=(VAL) => errors_only.push(x),
28+
|
29+
help: wrap the expression in a inline const (requires `#![feature(inline_const_pat)]`)
30+
|
31+
LL | 0..=(const { 5+1 }) => errors_only.push(x),
32+
| +++++++ +
33+
1934
error[E0658]: inline-const in pattern position is experimental
2035
--> $DIR/range_pat_interactions2.rs:15:20
2136
|

‎tests/ui/parser/bad-name.stderr

+6
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,12 @@ error: expected a pattern, found an expression
99
|
1010
LL | let x.y::<isize>.z foo;
1111
| ^^^^^^^^^^^^^^ arbitrary expressions are not allowed in patterns
12+
|
13+
help: remove the `let` if you meant to evaluate an expression
14+
|
15+
LL - let x.y::<isize>.z foo;
16+
LL + x.y::<isize>.z foo;
17+
|
1218

1319
error: expected one of `(`, `.`, `::`, `:`, `;`, `=`, `?`, `|`, or an operator, found `foo`
1420
--> $DIR/bad-name.rs:2:22

‎tests/ui/parser/issues/issue-24197.stderr

+6
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,12 @@ error: expected a pattern, found an expression
33
|
44
LL | let buf[0] = 0;
55
| ^^^^^^ arbitrary expressions are not allowed in patterns
6+
|
7+
help: remove the `let` if you meant to do an assignment
8+
|
9+
LL - let buf[0] = 0;
10+
LL + buf[0] = 0;
11+
|
612

713
error: aborting due to 1 previous error
814

‎tests/ui/parser/issues/issue-24375.stderr

+15
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,21 @@ error: expected a pattern, found an expression
33
|
44
LL | tmp[0] => {}
55
| ^^^^^^ arbitrary expressions are not allowed in patterns
6+
|
7+
help: check the value in an arm guard
8+
|
9+
LL | val if val == tmp[0] => {}
10+
| ~~~ ++++++++++++++++
11+
help: extract the expression into a `const` and refer to it
12+
|
13+
LL + const VAL: _ = tmp[0];
14+
LL ~ match z {
15+
LL ~ VAL => {}
16+
|
17+
help: wrap the expression in a inline const (requires `#![feature(inline_const_pat)]`)
18+
|
19+
LL | const { tmp[0] } => {}
20+
| +++++++ +
621

722
error: aborting due to 1 previous error
823

‎tests/ui/parser/pat-lt-bracket-5.stderr

+6
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,12 @@ error: expected a pattern, found an expression
33
|
44
LL | let v[0] = v[1];
55
| ^^^^ arbitrary expressions are not allowed in patterns
6+
|
7+
help: remove the `let` if you meant to do an assignment
8+
|
9+
LL - let v[0] = v[1];
10+
LL + v[0] = v[1];
11+
|
612

713
error[E0425]: cannot find value `v` in this scope
814
--> $DIR/pat-lt-bracket-5.rs:2:16

‎tests/ui/parser/pat-lt-bracket-6.stderr

+8-2
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,14 @@
11
error: expected a pattern, found an expression
2-
--> $DIR/pat-lt-bracket-6.rs:5:15
2+
--> $DIR/pat-lt-bracket-6.rs:5:14
33
|
44
LL | let Test(&desc[..]) = x;
5-
| ^^^^^^^^ arbitrary expressions are not allowed in patterns
5+
| ^^^^^^^^^ arbitrary expressions are not allowed in patterns
6+
|
7+
help: remove the `let` if you meant to do an assignment
8+
|
9+
LL - let Test(&desc[..]) = x;
10+
LL + Test(&desc[..]) = x;
11+
|
612

713
error[E0308]: mismatched types
814
--> $DIR/pat-lt-bracket-6.rs:10:30

‎tests/ui/parser/pat-ranges-3.stderr

+12
Original file line numberDiff line numberDiff line change
@@ -3,12 +3,24 @@ error: expected a pattern range bound, found an expression
33
|
44
LL | let 10 ..= 10 + 3 = 12;
55
| ^^^^^^ arbitrary expressions are not allowed in patterns
6+
|
7+
help: remove the `let` if you meant to do an assignment
8+
|
9+
LL - let 10 ..= 10 + 3 = 12;
10+
LL + 10 ..= 10 + 3 = 12;
11+
|
612

713
error: expected a pattern range bound, found an expression
814
--> $DIR/pat-ranges-3.rs:7:9
915
|
1016
LL | let 10 - 3 ..= 10 = 8;
1117
| ^^^^^^ arbitrary expressions are not allowed in patterns
18+
|
19+
help: remove the `let` if you meant to do an assignment
20+
|
21+
LL - let 10 - 3 ..= 10 = 8;
22+
LL + 10 - 3 ..= 10 = 8;
23+
|
1224

1325
error: aborting due to 2 previous errors
1426

‎tests/ui/parser/recover/recover-pat-exprs.rs

+1-3
Original file line numberDiff line numberDiff line change
@@ -40,9 +40,7 @@ fn type_cast() {
4040
fn operator() {
4141
match 0 {
4242
1 + 1 => (), //~ error: expected a pattern, found an expression
43-
(1 + 2) * 3 => (),
44-
//~^ error: expected a pattern, found an expression
45-
//~| error: expected a pattern, found an expression
43+
(1 + 2) * 3 => (), //~ error: expected a pattern, found an expression
4644
}
4745
}
4846

‎tests/ui/parser/recover/recover-pat-exprs.stderr

+425-34
Large diffs are not rendered by default.

‎tests/ui/parser/recover/recover-pat-issues.stderr

+75
Original file line numberDiff line numberDiff line change
@@ -3,36 +3,111 @@ error: expected a pattern, found an expression
33
|
44
LL | Foo("hi".to_owned()) => true,
55
| ^^^^^^^^^^^^^^^ arbitrary expressions are not allowed in patterns
6+
|
7+
help: check the value in an arm guard
8+
|
9+
LL | Foo(val) if val == "hi".to_owned() => true,
10+
| ~~~ +++++++++++++++++++++++++
11+
help: extract the expression into a `const` and refer to it
12+
|
13+
LL + const VAL: _ = "hi".to_owned();
14+
LL ~ match foo {
15+
LL ~ Foo(VAL) => true,
16+
|
17+
help: wrap the expression in a inline const (requires `#![feature(inline_const_pat)]`)
18+
|
19+
LL | Foo(const { "hi".to_owned() }) => true,
20+
| +++++++ +
621

722
error: expected a pattern, found an expression
823
--> $DIR/recover-pat-issues.rs:14:20
924
|
1025
LL | Bar { baz: "hi".to_owned() } => true,
1126
| ^^^^^^^^^^^^^^^ arbitrary expressions are not allowed in patterns
27+
|
28+
help: check the value in an arm guard
29+
|
30+
LL | Bar { baz } if baz == "hi".to_owned() => true,
31+
| ~~~ +++++++++++++++++++++++++
32+
help: extract the expression into a `const` and refer to it
33+
|
34+
LL + const BAZ: _ = "hi".to_owned();
35+
LL ~ match bar {
36+
LL ~ Bar { baz: BAZ } => true,
37+
|
38+
help: wrap the expression in a inline const (requires `#![feature(inline_const_pat)]`)
39+
|
40+
LL | Bar { baz: const { "hi".to_owned() } } => true,
41+
| +++++++ +
1242

1343
error: expected a pattern, found an expression
1444
--> $DIR/recover-pat-issues.rs:25:11
1545
|
1646
LL | &["foo".to_string()] => {}
1747
| ^^^^^^^^^^^^^^^^^ arbitrary expressions are not allowed in patterns
48+
|
49+
help: check the value in an arm guard
50+
|
51+
LL | &[val] if val == "foo".to_string() => {}
52+
| ~~~ +++++++++++++++++++++++++++
53+
help: extract the expression into a `const` and refer to it
54+
|
55+
LL + const VAL: _ = "foo".to_string();
56+
LL ~ match foo.as_slice() {
57+
LL ~ &[VAL] => {}
58+
|
59+
help: wrap the expression in a inline const (requires `#![feature(inline_const_pat)]`)
60+
|
61+
LL | &[const { "foo".to_string() }] => {}
62+
| +++++++ +
1863

1964
error: expected a pattern, found an expression
2065
--> $DIR/recover-pat-issues.rs:36:17
2166
|
2267
LL | if let Some(MAGIC.0 as usize) = None::<usize> {}
2368
| ^^^^^^^^^^^^^^^^ arbitrary expressions are not allowed in patterns
69+
|
70+
help: extract the expression into a `const` and refer to it
71+
|
72+
LL + const VAL: _ = MAGIC.0 as usize;
73+
LL ~ if let Some(VAL) = None::<usize> {}
74+
|
75+
help: wrap the expression in a inline const (requires `#![feature(inline_const_pat)]`)
76+
|
77+
LL | if let Some(const { MAGIC.0 as usize }) = None::<usize> {}
78+
| +++++++ +
2479

2580
error: expected a pattern, found an expression
2681
--> $DIR/recover-pat-issues.rs:41:13
2782
|
2883
LL | if let (-1.some(4)) = (0, Some(4)) {}
2984
| ^^^^^^^^^^ arbitrary expressions are not allowed in patterns
85+
|
86+
help: extract the expression into a `const` and refer to it
87+
|
88+
LL + const VAL: _ = -1.some(4);
89+
LL ~ if let (VAL) = (0, Some(4)) {}
90+
|
91+
help: wrap the expression in a inline const (requires `#![feature(inline_const_pat)]`)
92+
|
93+
LL | if let (const { -1.some(4) }) = (0, Some(4)) {}
94+
| +++++++ +
3095

3196
error: expected a pattern, found an expression
3297
--> $DIR/recover-pat-issues.rs:44:13
3398
|
3499
LL | if let (-1.Some(4)) = (0, Some(4)) {}
35100
| ^^^^^^^^^^ arbitrary expressions are not allowed in patterns
101+
|
102+
help: extract the expression into a `const` and refer to it
103+
|
104+
LL + const VAL: _ = -1.Some(4);
105+
LL ~ if let (VAL) = (0, Some(4)) {}
106+
|
107+
help: wrap the expression in a inline const (requires `#![feature(inline_const_pat)]`)
108+
|
109+
LL | if let (const { -1.Some(4) }) = (0, Some(4)) {}
110+
| +++++++ +
36111

37112
error: aborting due to 6 previous errors
38113

‎tests/ui/parser/recover/recover-pat-lets.rs

+1
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ fn main() {
33

44
let x.expect("foo");
55
//~^ error: expected a pattern, found an expression
6+
//~| error: type annotations needed
67

78
let x.unwrap(): u32;
89
//~^ error: expected a pattern, found an expression

‎tests/ui/parser/recover/recover-pat-lets.stderr

+55-5
Original file line numberDiff line numberDiff line change
@@ -3,30 +3,80 @@ error: expected a pattern, found an expression
33
|
44
LL | let x.expect("foo");
55
| ^^^^^^^^^^^^^^^ arbitrary expressions are not allowed in patterns
6+
|
7+
help: remove the `let` if you meant to evaluate an expression
8+
|
9+
LL - let x.expect("foo");
10+
LL + x.expect("foo");
11+
|
612

713
error: expected a pattern, found an expression
8-
--> $DIR/recover-pat-lets.rs:7:9
14+
--> $DIR/recover-pat-lets.rs:8:9
915
|
1016
LL | let x.unwrap(): u32;
1117
| ^^^^^^^^^^ arbitrary expressions are not allowed in patterns
18+
|
19+
help: remove the `let` if you meant to evaluate an expression
20+
|
21+
LL - let x.unwrap(): u32;
22+
LL + x.unwrap();
23+
|
1224

1325
error: expected a pattern, found an expression
14-
--> $DIR/recover-pat-lets.rs:10:9
26+
--> $DIR/recover-pat-lets.rs:11:9
1527
|
1628
LL | let x[0] = 1;
1729
| ^^^^ arbitrary expressions are not allowed in patterns
30+
|
31+
help: remove the `let` if you meant to do an assignment
32+
|
33+
LL - let x[0] = 1;
34+
LL + x[0] = 1;
35+
|
1836

1937
error: expected a pattern, found an expression
20-
--> $DIR/recover-pat-lets.rs:13:14
38+
--> $DIR/recover-pat-lets.rs:14:14
2139
|
2240
LL | let Some(1 + 1) = x else {
2341
| ^^^^^ arbitrary expressions are not allowed in patterns
42+
|
43+
help: extract the expression into a `const` and refer to it
44+
|
45+
LL + const VAL: _ = 1 + 1;
46+
LL ~ let Some(VAL) = x else {
47+
|
48+
help: wrap the expression in a inline const (requires `#![feature(inline_const_pat)]`)
49+
|
50+
LL | let Some(const { 1 + 1 }) = x else {
51+
| +++++++ +
2452

2553
error: expected a pattern, found an expression
26-
--> $DIR/recover-pat-lets.rs:17:17
54+
--> $DIR/recover-pat-lets.rs:18:17
2755
|
2856
LL | if let Some(1 + 1) = x {
2957
| ^^^^^ arbitrary expressions are not allowed in patterns
58+
|
59+
help: extract the expression into a `const` and refer to it
60+
|
61+
LL + const VAL: _ = 1 + 1;
62+
LL ~ if let Some(VAL) = x {
63+
|
64+
help: wrap the expression in a inline const (requires `#![feature(inline_const_pat)]`)
65+
|
66+
LL | if let Some(const { 1 + 1 }) = x {
67+
| +++++++ +
68+
69+
error[E0282]: type annotations needed
70+
--> $DIR/recover-pat-lets.rs:4:9
71+
|
72+
LL | let x.expect("foo");
73+
| ^^^^^^^^^^^^^^^
74+
|
75+
help: consider giving this pattern a type
76+
|
77+
LL | let x.expect("foo"): /* Type */;
78+
| ++++++++++++
3079

31-
error: aborting due to 5 previous errors
80+
error: aborting due to 6 previous errors
3281

82+
For more information about this error, try `rustc --explain E0282`.

‎tests/ui/parser/recover/recover-pat-ranges.stderr

+126-18
Original file line numberDiff line numberDiff line change
@@ -46,12 +46,6 @@ LL - (0)..=(-4) => (),
4646
LL + (0)..=-4 => (),
4747
|
4848

49-
error: expected a pattern range bound, found an expression
50-
--> $DIR/recover-pat-ranges.rs:11:12
51-
|
52-
LL | ..=1 + 2 => (),
53-
| ^^^^^ arbitrary expressions are not allowed in patterns
54-
5549
error: range pattern bounds cannot have parentheses
5650
--> $DIR/recover-pat-ranges.rs:13:9
5751
|
@@ -64,12 +58,6 @@ LL - (4).. => (),
6458
LL + 4.. => (),
6559
|
6660

67-
error: expected a pattern range bound, found an expression
68-
--> $DIR/recover-pat-ranges.rs:15:10
69-
|
70-
LL | (-4 + 0).. => (),
71-
| ^^^^^^ arbitrary expressions are not allowed in patterns
72-
7361
error: range pattern bounds cannot have parentheses
7462
--> $DIR/recover-pat-ranges.rs:15:9
7563
|
@@ -82,12 +70,6 @@ LL - (-4 + 0).. => (),
8270
LL + -4 + 0.. => (),
8371
|
8472

85-
error: expected a pattern range bound, found an expression
86-
--> $DIR/recover-pat-ranges.rs:18:10
87-
|
88-
LL | (1 + 4)...1 * 2 => (),
89-
| ^^^^^ arbitrary expressions are not allowed in patterns
90-
9173
error: range pattern bounds cannot have parentheses
9274
--> $DIR/recover-pat-ranges.rs:18:9
9375
|
@@ -100,23 +82,149 @@ LL - (1 + 4)...1 * 2 => (),
10082
LL + 1 + 4...1 * 2 => (),
10183
|
10284

85+
error: expected a pattern range bound, found an expression
86+
--> $DIR/recover-pat-ranges.rs:11:12
87+
|
88+
LL | ..=1 + 2 => (),
89+
| ^^^^^ arbitrary expressions are not allowed in patterns
90+
|
91+
help: check the value in an arm guard
92+
|
93+
LL | ..=val if val == 1 + 2 => (),
94+
| ~~~ +++++++++++++++
95+
help: extract the expression into a `const` and refer to it
96+
|
97+
LL + const VAL: _ = 1 + 2;
98+
LL ~ match -1 {
99+
LL | 0..=1 => (),
100+
...
101+
LL |
102+
LL ~ ..=VAL => (),
103+
|
104+
help: wrap the expression in a inline const (requires `#![feature(inline_const_pat)]`)
105+
|
106+
LL | ..=const { 1 + 2 } => (),
107+
| +++++++ +
108+
109+
error: expected a pattern range bound, found an expression
110+
--> $DIR/recover-pat-ranges.rs:15:10
111+
|
112+
LL | (-4 + 0).. => (),
113+
| ^^^^^^ arbitrary expressions are not allowed in patterns
114+
|
115+
help: check the value in an arm guard
116+
|
117+
LL | (val).. if val == -4 + 0 => (),
118+
| ~~~ ++++++++++++++++
119+
help: extract the expression into a `const` and refer to it
120+
|
121+
LL + const VAL: _ = -4 + 0;
122+
LL ~ match -1 {
123+
LL | 0..=1 => (),
124+
...
125+
LL |
126+
LL ~ (VAL).. => (),
127+
|
128+
help: wrap the expression in a inline const (requires `#![feature(inline_const_pat)]`)
129+
|
130+
LL | (const { -4 + 0 }).. => (),
131+
| +++++++ +
132+
133+
error: expected a pattern range bound, found an expression
134+
--> $DIR/recover-pat-ranges.rs:18:10
135+
|
136+
LL | (1 + 4)...1 * 2 => (),
137+
| ^^^^^ arbitrary expressions are not allowed in patterns
138+
|
139+
help: check the value in an arm guard
140+
|
141+
LL | (val)...1 * 2 if val == 1 + 4 => (),
142+
| ~~~ +++++++++++++++
143+
help: extract the expression into a `const` and refer to it
144+
|
145+
LL + const VAL: _ = 1 + 4;
146+
LL ~ match -1 {
147+
LL | 0..=1 => (),
148+
...
149+
LL |
150+
LL ~ (VAL)...1 * 2 => (),
151+
|
152+
help: wrap the expression in a inline const (requires `#![feature(inline_const_pat)]`)
153+
|
154+
LL | (const { 1 + 4 })...1 * 2 => (),
155+
| +++++++ +
156+
103157
error: expected a pattern range bound, found an expression
104158
--> $DIR/recover-pat-ranges.rs:18:19
105159
|
106160
LL | (1 + 4)...1 * 2 => (),
107161
| ^^^^^ arbitrary expressions are not allowed in patterns
162+
|
163+
help: check the value in an arm guard
164+
|
165+
LL | (1 + 4)...val if val == 1 * 2 => (),
166+
| ~~~ +++++++++++++++
167+
help: extract the expression into a `const` and refer to it
168+
|
169+
LL + const VAL: _ = 1 * 2;
170+
LL ~ match -1 {
171+
LL | 0..=1 => (),
172+
...
173+
LL |
174+
LL ~ (1 + 4)...VAL => (),
175+
|
176+
help: wrap the expression in a inline const (requires `#![feature(inline_const_pat)]`)
177+
|
178+
LL | (1 + 4)...const { 1 * 2 } => (),
179+
| +++++++ +
108180

109181
error: expected a pattern range bound, found an expression
110182
--> $DIR/recover-pat-ranges.rs:24:9
111183
|
112184
LL | 0.x()..="y".z() => (),
113185
| ^^^^^ arbitrary expressions are not allowed in patterns
186+
|
187+
help: check the value in an arm guard
188+
|
189+
LL | val..="y".z() if val == 0.x() => (),
190+
| ~~~ +++++++++++++++
191+
help: extract the expression into a `const` and refer to it
192+
|
193+
LL + const VAL: _ = 0.x();
194+
LL ~ match -1 {
195+
LL | 0..=1 => (),
196+
...
197+
LL |
198+
LL ~ VAL..="y".z() => (),
199+
|
200+
help: wrap the expression in a inline const (requires `#![feature(inline_const_pat)]`)
201+
|
202+
LL | const { 0.x() }..="y".z() => (),
203+
| +++++++ +
114204

115205
error: expected a pattern range bound, found an expression
116206
--> $DIR/recover-pat-ranges.rs:24:17
117207
|
118208
LL | 0.x()..="y".z() => (),
119209
| ^^^^^^^ arbitrary expressions are not allowed in patterns
210+
|
211+
help: check the value in an arm guard
212+
|
213+
LL | 0.x()..=val if val == "y".z() => (),
214+
| ~~~ +++++++++++++++++
215+
help: extract the expression into a `const` and refer to it
216+
|
217+
LL + const VAL: _ = "y".z();
218+
LL ~ match -1 {
219+
LL | 0..=1 => (),
220+
...
221+
LL |
222+
LL ~ 0.x()..=VAL => (),
223+
|
224+
help: wrap the expression in a inline const (requires `#![feature(inline_const_pat)]`)
225+
|
226+
LL | 0.x()..=const { "y".z() } => (),
227+
| +++++++ +
120228

121229
warning: `...` range patterns are deprecated
122230
--> $DIR/recover-pat-ranges.rs:18:16

‎tests/ui/parser/recover/recover-pat-wildcards.stderr

+21-6
Original file line numberDiff line numberDiff line change
@@ -54,12 +54,6 @@ error: expected one of `=>`, `if`, or `|`, found `(`
5454
LL | ..(_) => ()
5555
| ^ expected one of `=>`, `if`, or `|`
5656

57-
error: expected a pattern range bound, found an expression
58-
--> $DIR/recover-pat-wildcards.rs:55:14
59-
|
60-
LL | 4..=(2 + _) => ()
61-
| ^^^^^ arbitrary expressions are not allowed in patterns
62-
6357
error: range pattern bounds cannot have parentheses
6458
--> $DIR/recover-pat-wildcards.rs:55:13
6559
|
@@ -72,6 +66,27 @@ LL - 4..=(2 + _) => ()
7266
LL + 4..=2 + _ => ()
7367
|
7468

69+
error: expected a pattern range bound, found an expression
70+
--> $DIR/recover-pat-wildcards.rs:55:14
71+
|
72+
LL | 4..=(2 + _) => ()
73+
| ^^^^^ arbitrary expressions are not allowed in patterns
74+
|
75+
help: check the value in an arm guard
76+
|
77+
LL | 4..=(val) if val == 2 + _ => ()
78+
| ~~~ +++++++++++++++
79+
help: extract the expression into a `const` and refer to it
80+
|
81+
LL + const VAL: _ = 2 + _;
82+
LL ~ match 9 {
83+
LL ~ 4..=(VAL) => ()
84+
|
85+
help: wrap the expression in a inline const (requires `#![feature(inline_const_pat)]`)
86+
|
87+
LL | 4..=(const { 2 + _ }) => ()
88+
| +++++++ +
89+
7590
error: aborting due to 11 previous errors
7691

7792
For more information about this error, try `rustc --explain E0586`.

‎tests/ui/sized/ensure-overriding-bindings-in-pattern-with-ty-err-doesnt-ice.stderr

+6
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,12 @@ error: expected a pattern, found an expression
33
|
44
LL | let str::<{fn str() { let str::T>>::as_bytes; }}, T>::as_bytes;
55
| ^^^^^^^^^^^^^^^^^^ arbitrary expressions are not allowed in patterns
6+
|
7+
help: remove the `let` if you meant to evaluate an expression
8+
|
9+
LL - let str::<{fn str() { let str::T>>::as_bytes; }}, T>::as_bytes;
10+
LL + let str::<{fn str() { str::T>>::as_bytes; }}, T>::as_bytes;
11+
|
612

713
error[E0412]: cannot find type `T` in this scope
814
--> $DIR/ensure-overriding-bindings-in-pattern-with-ty-err-doesnt-ice.rs:2:55

0 commit comments

Comments
 (0)
Please sign in to comment.