Skip to content

Commit 0ba687a

Browse files
committed
Parse and recover from type ascription in patterns
1 parent 97872b7 commit 0ba687a

File tree

5 files changed

+164
-39
lines changed

5 files changed

+164
-39
lines changed

compiler/rustc_parse/src/parser/diagnostics.rs

+39-12
Original file line numberDiff line numberDiff line change
@@ -2405,26 +2405,42 @@ impl<'a> Parser<'a> {
24052405
if !matches!(first_pat.kind, PatKind::Ident(_, _, None) | PatKind::Path(..))
24062406
|| !self.look_ahead(1, |token| token.is_ident() && !token.is_reserved_ident())
24072407
{
2408+
let mut snapshot_type = self.create_snapshot_for_diagnostic();
2409+
snapshot_type.bump(); // `:`
2410+
match snapshot_type.parse_ty() {
2411+
Err(inner_err) => {
2412+
inner_err.cancel();
2413+
}
2414+
Ok(ty) => {
2415+
let Err(mut err) = self.expected_one_of_not_found(&[], &[]) else {
2416+
return first_pat;
2417+
};
2418+
err.span_label(ty.span, "specifying the type of a pattern isn't supported");
2419+
self.restore_snapshot(snapshot_type);
2420+
let span = first_pat.span.to(ty.span);
2421+
first_pat = self.mk_pat(span, PatKind::Wild);
2422+
err.emit();
2423+
}
2424+
}
24082425
return first_pat;
24092426
}
24102427
// The pattern looks like it might be a path with a `::` -> `:` typo:
24112428
// `match foo { bar:baz => {} }`
2412-
let span = self.token.span;
2429+
let colon_span = self.token.span;
24132430
// We only emit "unexpected `:`" error here if we can successfully parse the
24142431
// whole pattern correctly in that case.
2415-
let snapshot = self.create_snapshot_for_diagnostic();
2432+
let mut snapshot_pat = self.create_snapshot_for_diagnostic();
2433+
let mut snapshot_type = self.create_snapshot_for_diagnostic();
24162434

24172435
// Create error for "unexpected `:`".
24182436
match self.expected_one_of_not_found(&[], &[]) {
24192437
Err(mut err) => {
2420-
self.bump(); // Skip the `:`.
2421-
match self.parse_pat_no_top_alt(expected) {
2438+
// Skip the `:`.
2439+
snapshot_pat.bump();
2440+
snapshot_type.bump();
2441+
match snapshot_pat.parse_pat_no_top_alt(expected) {
24222442
Err(inner_err) => {
2423-
// Carry on as if we had not done anything, callers will emit a
2424-
// reasonable error.
24252443
inner_err.cancel();
2426-
err.cancel();
2427-
self.restore_snapshot(snapshot);
24282444
}
24292445
Ok(mut pat) => {
24302446
// We've parsed the rest of the pattern.
@@ -2488,22 +2504,33 @@ impl<'a> Parser<'a> {
24882504
_ => {}
24892505
}
24902506
if show_sugg {
2491-
err.span_suggestion(
2492-
span,
2507+
err.span_suggestion_verbose(
2508+
colon_span.until(self.look_ahead(1, |t| t.span)),
24932509
"maybe write a path separator here",
24942510
"::",
24952511
Applicability::MaybeIncorrect,
24962512
);
24972513
} else {
24982514
first_pat = self.mk_pat(new_span, PatKind::Wild);
24992515
}
2500-
err.emit();
2516+
self.restore_snapshot(snapshot_pat);
25012517
}
25022518
}
2519+
match snapshot_type.parse_ty() {
2520+
Err(inner_err) => {
2521+
inner_err.cancel();
2522+
}
2523+
Ok(ty) => {
2524+
err.span_label(ty.span, "specifying the type of a pattern isn't supported");
2525+
self.restore_snapshot(snapshot_type);
2526+
let new_span = first_pat.span.to(ty.span);
2527+
first_pat = self.mk_pat(new_span, PatKind::Wild);
2528+
}
2529+
}
2530+
err.emit();
25032531
}
25042532
_ => {
25052533
// Carry on as if we had not done anything. This should be unreachable.
2506-
self.restore_snapshot(snapshot);
25072534
}
25082535
};
25092536
first_pat

tests/ui/parser/issues/issue-87086-colon-path-sep.rs

-1
Original file line numberDiff line numberDiff line change
@@ -68,7 +68,6 @@ fn main() {
6868
Foo:Bar::Baz => {}
6969
//~^ ERROR: expected one of
7070
//~| HELP: maybe write a path separator here
71-
//~| ERROR: failed to resolve: `Bar` is a variant, not a module
7271
}
7372
match myfoo {
7473
Foo::Bar => {}

tests/ui/parser/issues/issue-87086-colon-path-sep.stderr

+55-26
Original file line numberDiff line numberDiff line change
@@ -2,89 +2,118 @@ error: expected one of `@` or `|`, found `:`
22
--> $DIR/issue-87086-colon-path-sep.rs:17:12
33
|
44
LL | Foo:Bar => {}
5-
| ^
5+
| ^--- specifying the type of a pattern isn't supported
66
| |
77
| expected one of `@` or `|`
8-
| help: maybe write a path separator here: `::`
8+
|
9+
help: maybe write a path separator here
10+
|
11+
LL | Foo::Bar => {}
12+
| ~~
913

1014
error: expected one of `!`, `(`, `...`, `..=`, `..`, `::`, `{`, or `|`, found `:`
1115
--> $DIR/issue-87086-colon-path-sep.rs:23:17
1216
|
1317
LL | qux::Foo:Bar => {}
14-
| ^
18+
| ^--- specifying the type of a pattern isn't supported
1519
| |
1620
| expected one of 8 possible tokens
17-
| help: maybe write a path separator here: `::`
21+
|
22+
help: maybe write a path separator here
23+
|
24+
LL | qux::Foo::Bar => {}
25+
| ~~
1826

1927
error: expected one of `@` or `|`, found `:`
2028
--> $DIR/issue-87086-colon-path-sep.rs:29:12
2129
|
2230
LL | qux:Foo::Baz => {}
23-
| ^
31+
| ^-------- specifying the type of a pattern isn't supported
2432
| |
2533
| expected one of `@` or `|`
26-
| help: maybe write a path separator here: `::`
34+
|
35+
help: maybe write a path separator here
36+
|
37+
LL | qux::Foo::Baz => {}
38+
| ~~
2739

2840
error: expected one of `@` or `|`, found `:`
2941
--> $DIR/issue-87086-colon-path-sep.rs:35:12
3042
|
3143
LL | qux: Foo::Baz if true => {}
32-
| ^
44+
| ^ -------- specifying the type of a pattern isn't supported
3345
| |
3446
| expected one of `@` or `|`
35-
| help: maybe write a path separator here: `::`
47+
|
48+
help: maybe write a path separator here
49+
|
50+
LL | qux::Foo::Baz if true => {}
51+
| ~~
3652

3753
error: expected one of `@` or `|`, found `:`
3854
--> $DIR/issue-87086-colon-path-sep.rs:40:15
3955
|
4056
LL | if let Foo:Bar = f() {
41-
| ^
57+
| ^--- specifying the type of a pattern isn't supported
4258
| |
4359
| expected one of `@` or `|`
44-
| help: maybe write a path separator here: `::`
60+
|
61+
help: maybe write a path separator here
62+
|
63+
LL | if let Foo::Bar = f() {
64+
| ~~
4565

4666
error: expected one of `@` or `|`, found `:`
4767
--> $DIR/issue-87086-colon-path-sep.rs:48:16
4868
|
4969
LL | ref qux: Foo::Baz => {}
50-
| ^
70+
| ^ -------- specifying the type of a pattern isn't supported
5171
| |
5272
| expected one of `@` or `|`
53-
| help: maybe write a path separator here: `::`
73+
|
74+
help: maybe write a path separator here
75+
|
76+
LL | ref qux::Foo::Baz => {}
77+
| ~~
5478

5579
error: expected one of `@` or `|`, found `:`
5680
--> $DIR/issue-87086-colon-path-sep.rs:57:16
5781
|
5882
LL | mut qux: Foo::Baz => {}
59-
| ^
83+
| ^ -------- specifying the type of a pattern isn't supported
6084
| |
6185
| expected one of `@` or `|`
62-
| help: maybe write a path separator here: `::`
86+
|
87+
help: maybe write a path separator here
88+
|
89+
LL | mut qux::Foo::Baz => {}
90+
| ~~
6391

6492
error: expected one of `@` or `|`, found `:`
6593
--> $DIR/issue-87086-colon-path-sep.rs:68:12
6694
|
6795
LL | Foo:Bar::Baz => {}
68-
| ^
96+
| ^-------- specifying the type of a pattern isn't supported
6997
| |
7098
| expected one of `@` or `|`
71-
| help: maybe write a path separator here: `::`
99+
|
100+
help: maybe write a path separator here
101+
|
102+
LL | Foo::Bar::Baz => {}
103+
| ~~
72104

73105
error: expected one of `@` or `|`, found `:`
74-
--> $DIR/issue-87086-colon-path-sep.rs:75:12
106+
--> $DIR/issue-87086-colon-path-sep.rs:74:12
75107
|
76108
LL | Foo:Bar => {}
77-
| ^
109+
| ^--- specifying the type of a pattern isn't supported
78110
| |
79111
| expected one of `@` or `|`
80-
| help: maybe write a path separator here: `::`
81-
82-
error[E0433]: failed to resolve: `Bar` is a variant, not a module
83-
--> $DIR/issue-87086-colon-path-sep.rs:68:13
84112
|
85-
LL | Foo:Bar::Baz => {}
86-
| ^^^ `Bar` is a variant, not a module
113+
help: maybe write a path separator here
114+
|
115+
LL | Foo::Bar => {}
116+
| ~~
87117

88-
error: aborting due to 10 previous errors
118+
error: aborting due to 9 previous errors
89119

90-
For more information about this error, try `rustc --explain E0433`.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
fn foo(x: bool) -> i32 {
2+
match x {
3+
x: i32 => x, //~ ERROR expected
4+
//~^ ERROR mismatched types
5+
true => 42.,
6+
false => 0.333,
7+
}
8+
}
9+
10+
fn main() {
11+
match foo(true) {
12+
42: i32 => (), //~ ERROR expected
13+
_: f64 => (), //~ ERROR expected
14+
x: i32 => (), //~ ERROR expected
15+
}
16+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
error: expected one of `@` or `|`, found `:`
2+
--> $DIR/type-ascription-in-pattern.rs:3:10
3+
|
4+
LL | x: i32 => x,
5+
| ^ --- specifying the type of a pattern isn't supported
6+
| |
7+
| expected one of `@` or `|`
8+
|
9+
help: maybe write a path separator here
10+
|
11+
LL | x::i32 => x,
12+
| ~~
13+
14+
error: expected one of `...`, `..=`, `..`, or `|`, found `:`
15+
--> $DIR/type-ascription-in-pattern.rs:12:11
16+
|
17+
LL | 42: i32 => (),
18+
| ^ --- specifying the type of a pattern isn't supported
19+
| |
20+
| expected one of `...`, `..=`, `..`, or `|`
21+
22+
error: expected `|`, found `:`
23+
--> $DIR/type-ascription-in-pattern.rs:13:10
24+
|
25+
LL | _: f64 => (),
26+
| ^ --- specifying the type of a pattern isn't supported
27+
| |
28+
| expected `|`
29+
30+
error: expected one of `@` or `|`, found `:`
31+
--> $DIR/type-ascription-in-pattern.rs:14:10
32+
|
33+
LL | x: i32 => (),
34+
| ^ --- specifying the type of a pattern isn't supported
35+
| |
36+
| expected one of `@` or `|`
37+
|
38+
help: maybe write a path separator here
39+
|
40+
LL | x::i32 => (),
41+
| ~~
42+
43+
error[E0308]: mismatched types
44+
--> $DIR/type-ascription-in-pattern.rs:3:19
45+
|
46+
LL | fn foo(x: bool) -> i32 {
47+
| --- expected `i32` because of return type
48+
LL | match x {
49+
LL | x: i32 => x,
50+
| ^ expected `i32`, found `bool`
51+
52+
error: aborting due to 5 previous errors
53+
54+
For more information about this error, try `rustc --explain E0308`.

0 commit comments

Comments
 (0)