Skip to content

Commit 29fe4b5

Browse files
committed
Stash UnexpectedExpressionInPattern
1 parent cef4655 commit 29fe4b5

File tree

8 files changed

+101
-48
lines changed

8 files changed

+101
-48
lines changed

compiler/rustc_errors/src/lib.rs

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -522,6 +522,8 @@ pub enum StashKey {
522522
/// Query cycle detected, stashing in favor of a better error.
523523
Cycle,
524524
UndeterminedMacroResolution,
525+
/// Used by `Parser::maybe_recover_trailing_expr`
526+
ExprInPat,
525527
}
526528

527529
fn default_track_diagnostic<R>(diag: DiagInner, f: &mut dyn FnMut(DiagInner) -> R) -> R {
@@ -806,6 +808,23 @@ impl DiagCtxt {
806808
Some(Diag::new_diagnostic(self, diag))
807809
}
808810

811+
/// Steals a previously stashed error with the given `Span` and
812+
/// [`StashKey`] as the key, and cancels it if found.
813+
/// Panics if the found diagnostic's level isn't `Level::Error`.
814+
pub fn steal_err(&self, span: Span, key: StashKey, _: ErrorGuaranteed) -> bool {
815+
let key = (span.with_parent(None), key);
816+
// FIXME(#120456) - is `swap_remove` correct?
817+
self.inner
818+
.borrow_mut()
819+
.stashed_diagnostics
820+
.swap_remove(&key)
821+
.inspect(|(diag, guar)| {
822+
assert_eq!(diag.level, Error);
823+
assert!(guar.is_some())
824+
})
825+
.is_some()
826+
}
827+
809828
/// Steals a previously stashed error with the given `Span` and
810829
/// [`StashKey`] as the key, modifies it, and emits it. Returns `None` if
811830
/// no matching diagnostic is found. Panics if the found diagnostic's level
@@ -1250,6 +1269,17 @@ impl DiagCtxt {
12501269
self.create_err(err).emit()
12511270
}
12521271

1272+
/// See [`DiagCtxt::stash_diagnostic`] for details.
1273+
#[track_caller]
1274+
pub fn stash_err<'a>(
1275+
&'a self,
1276+
span: Span,
1277+
key: StashKey,
1278+
err: impl Diagnostic<'a>,
1279+
) -> ErrorGuaranteed {
1280+
self.create_err(err).stash(span, key).unwrap()
1281+
}
1282+
12531283
/// Ensures that an error is printed. See `Level::DelayedBug`.
12541284
//
12551285
// No `#[rustc_lint_diagnostics]` and no `impl Into<DiagMessage>` because bug messages aren't

compiler/rustc_parse/src/parser/pat.rs

Lines changed: 35 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ use rustc_ast::{
2020
PatFieldsRest, PatKind, Path, QSelf, RangeEnd, RangeSyntax,
2121
};
2222
use rustc_ast_pretty::pprust;
23-
use rustc_errors::{Applicability, Diag, PResult};
23+
use rustc_errors::{Applicability, Diag, PResult, StashKey};
2424
use rustc_session::errors::ExprParenthesesNeeded;
2525
use rustc_span::source_map::{respan, Spanned};
2626
use rustc_span::symbol::{kw, sym, Ident};
@@ -351,7 +351,7 @@ impl<'a> Parser<'a> {
351351
&mut self,
352352
pat_span: Span,
353353
is_end_bound: bool,
354-
) -> Option<ErrorGuaranteed> {
354+
) -> Option<(ErrorGuaranteed, Span)> {
355355
if self.prev_token.is_keyword(kw::Underscore) || !self.may_recover() {
356356
// Don't recover anything after an `_` or if recovery is disabled.
357357
return None;
@@ -429,11 +429,16 @@ impl<'a> Parser<'a> {
429429
// Check that `parse_expr_assoc_with` didn't eat a rhs.
430430
let is_method_call = false && non_assoc_span == expr.span;
431431

432-
return Some(self.dcx().emit_err(UnexpectedExpressionInPattern {
433-
span: expr.span,
434-
is_bound,
435-
is_method_call,
436-
}));
432+
let span = expr.span;
433+
434+
return Some((
435+
self.dcx().stash_err(
436+
span,
437+
StashKey::ExprInPat,
438+
UnexpectedExpressionInPattern { span, is_bound, is_method_call },
439+
),
440+
span,
441+
));
437442
}
438443
}
439444

@@ -550,7 +555,7 @@ impl<'a> Parser<'a> {
550555
self.parse_pat_tuple_struct(qself, path)?
551556
} else {
552557
match self.maybe_recover_trailing_expr(span, false) {
553-
Some(guar) => PatKind::Err(guar),
558+
Some((guar, _)) => PatKind::Err(guar),
554559
None => PatKind::Path(qself, path),
555560
}
556561
}
@@ -584,7 +589,7 @@ impl<'a> Parser<'a> {
584589
match self.parse_literal_maybe_minus() {
585590
Ok(begin) => {
586591
let begin = match self.maybe_recover_trailing_expr(begin.span, false) {
587-
Some(guar) => self.mk_expr_err(begin.span, guar),
592+
Some((guar, sp)) => self.mk_expr_err(sp, guar),
588593
None => begin,
589594
};
590595

@@ -762,7 +767,25 @@ impl<'a> Parser<'a> {
762767

763768
Ok(match self.maybe_recover_trailing_expr(open_paren.to(self.prev_token.span), false) {
764769
None => pat,
765-
Some(guar) => PatKind::Err(guar)
770+
Some((guar, _)) => {
771+
// We just recovered a bigger expression, so cancel its children
772+
// (e.g. `(1 + 2) * 3`, cancel “`1 + 2` is not a pattern”).
773+
match pat {
774+
PatKind::Paren(pat) => {
775+
self.dcx().steal_err(pat.span, StashKey::ExprInPat, guar);
776+
}
777+
778+
PatKind::Tuple(fields) => {
779+
for pat in fields {
780+
self.dcx().steal_err(pat.span, StashKey::ExprInPat, guar);
781+
}
782+
}
783+
784+
_ => unreachable!(),
785+
}
786+
787+
PatKind::Err(guar)
788+
}
766789
})
767790
}
768791

@@ -1012,7 +1035,7 @@ impl<'a> Parser<'a> {
10121035
}
10131036

10141037
Ok(match recovered {
1015-
Some(guar) => self.mk_expr_err(bound.span, guar),
1038+
Some((guar, sp)) => self.mk_expr_err(sp, guar),
10161039
None => bound,
10171040
})
10181041
}
@@ -1081,7 +1104,7 @@ impl<'a> Parser<'a> {
10811104
// but not `ident @ subpat` as `subpat` was already checked and `ident` continues with `@`.
10821105

10831106
let pat = if sub.is_none()
1084-
&& let Some(guar) = self.maybe_recover_trailing_expr(ident.span, false)
1107+
&& let Some((guar, _)) = self.maybe_recover_trailing_expr(ident.span, false)
10851108
{
10861109
PatKind::Err(guar)
10871110
} else {

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

Lines changed: 6 additions & 6 deletions
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_interactions1.rs:19:16
3-
|
4-
LL | 0..5+1 => errors_only.push(x),
5-
| ^^^ arbitrary expressions are not allowed in patterns
6-
71
error[E0408]: variable `n` is not bound in all patterns
82
--> $DIR/range_pat_interactions1.rs:10:25
93
|
@@ -99,6 +93,12 @@ LL | y @ ..-7 => assert_eq!(y, -8),
9993
= note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
10094
= help: use an inclusive range pattern, like N..=M
10195

96+
error: expected a pattern range bound, found an expression
97+
--> $DIR/range_pat_interactions1.rs:19:16
98+
|
99+
LL | 0..5+1 => errors_only.push(x),
100+
| ^^^ arbitrary expressions are not allowed in patterns
101+
102102
error: aborting due to 10 previous errors
103103

104104
Some errors have detailed explanations: E0408, E0658.

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

Lines changed: 6 additions & 6 deletions
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
|
@@ -70,6 +64,12 @@ LL | y @ ..-7 => assert_eq!(y, -8),
7064
= note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
7165
= help: use an inclusive range pattern, like N..=M
7266

67+
error: expected a pattern range bound, found an expression
68+
--> $DIR/range_pat_interactions2.rs:10:18
69+
|
70+
LL | 0..=(5+1) => errors_only.push(x),
71+
| ^^^ arbitrary expressions are not allowed in patterns
72+
7373
error: aborting due to 7 previous errors
7474

7575
For more information about this error, try `rustc --explain E0658`.

tests/ui/parser/bad-name.stderr

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -4,17 +4,17 @@ error: field expressions cannot have generic arguments
44
LL | let x.y::<isize>.z foo;
55
| ^^^^^^^
66

7-
error: expected a pattern, found an expression
8-
--> $DIR/bad-name.rs:4:7
9-
|
10-
LL | let x.y::<isize>.z foo;
11-
| ^^^^^^^^^^^^^^ arbitrary expressions are not allowed in patterns
12-
137
error: expected one of `(`, `.`, `::`, `:`, `;`, `=`, `?`, `|`, or an operator, found `foo`
148
--> $DIR/bad-name.rs:4:22
159
|
1610
LL | let x.y::<isize>.z foo;
1711
| ^^^ expected one of 9 possible tokens
1812

13+
error: expected a pattern, found an expression
14+
--> $DIR/bad-name.rs:4:7
15+
|
16+
LL | let x.y::<isize>.z foo;
17+
| ^^^^^^^^^^^^^^ arbitrary expressions are not allowed in patterns
18+
1919
error: aborting due to 3 previous errors
2020

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,15 @@
1-
error: expected a pattern, found an expression
2-
--> $DIR/pat-lt-bracket-5.rs:2:9
3-
|
4-
LL | let v[0] = v[1];
5-
| ^^^^ arbitrary expressions are not allowed in patterns
6-
71
error[E0425]: cannot find value `v` in this scope
82
--> $DIR/pat-lt-bracket-5.rs:2:16
93
|
104
LL | let v[0] = v[1];
115
| ^ not found in this scope
126

7+
error: expected a pattern, found an expression
8+
--> $DIR/pat-lt-bracket-5.rs:2:9
9+
|
10+
LL | let v[0] = v[1];
11+
| ^^^^ arbitrary expressions are not allowed in patterns
12+
1313
error: aborting due to 2 previous errors
1414

1515
For more information about this error, try `rustc --explain E0425`.

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

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,3 @@
1-
error: expected a pattern, found an expression
2-
--> $DIR/pat-lt-bracket-6.rs:5:15
3-
|
4-
LL | let Test(&desc[..]) = x;
5-
| ^^^^^^^^ arbitrary expressions are not allowed in patterns
6-
71
error[E0308]: mismatched types
82
--> $DIR/pat-lt-bracket-6.rs:10:30
93
|
@@ -24,6 +18,12 @@ help: use `_` to explicitly ignore each field
2418
LL | let Test(&desc[..], _) = x;
2519
| +++
2620

21+
error: expected a pattern, found an expression
22+
--> $DIR/pat-lt-bracket-6.rs:5:15
23+
|
24+
LL | let Test(&desc[..]) = x;
25+
| ^^^^^^^^ arbitrary expressions are not allowed in patterns
26+
2727
error: aborting due to 3 previous errors
2828

2929
Some errors have detailed explanations: E0023, E0308.

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

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,3 @@
1-
error: expected a pattern, found an expression
2-
--> $DIR/ensure-overriding-bindings-in-pattern-with-ty-err-doesnt-ice.rs:2:31
3-
|
4-
LL | let str::<{fn str() { let str::T>>::as_bytes; }}, T>::as_bytes;
5-
| ^^^^^^^^^^^^^^^^^^ arbitrary expressions are not allowed in patterns
6-
71
error[E0412]: cannot find type `T` in this scope
82
--> $DIR/ensure-overriding-bindings-in-pattern-with-ty-err-doesnt-ice.rs:2:55
93
|
@@ -32,6 +26,12 @@ error[E0533]: expected unit struct, unit variant or constant, found associated f
3226
LL | let str::<{fn str() { let str::T>>::as_bytes; }}, T>::as_bytes;
3327
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ not a unit struct, unit variant or constant
3428

29+
error: expected a pattern, found an expression
30+
--> $DIR/ensure-overriding-bindings-in-pattern-with-ty-err-doesnt-ice.rs:2:31
31+
|
32+
LL | let str::<{fn str() { let str::T>>::as_bytes; }}, T>::as_bytes;
33+
| ^^^^^^^^^^^^^^^^^^ arbitrary expressions are not allowed in patterns
34+
3535
error: aborting due to 4 previous errors
3636

3737
Some errors have detailed explanations: E0109, E0412, E0533.

0 commit comments

Comments
 (0)