Skip to content

Commit c1b1ec7

Browse files
authoredJun 8, 2022
Suggest escaping box as identifier
1 parent 50b0025 commit c1b1ec7

File tree

3 files changed

+126
-8
lines changed

3 files changed

+126
-8
lines changed
 

Diff for: ‎compiler/rustc_parse/src/parser/pat.rs

+57-4
Original file line numberDiff line numberDiff line change
@@ -360,10 +360,7 @@ impl<'a> Parser<'a> {
360360
let mutbl = self.parse_mutability();
361361
self.parse_pat_ident(BindingMode::ByRef(mutbl))?
362362
} else if self.eat_keyword(kw::Box) {
363-
// Parse `box pat`
364-
let pat = self.parse_pat_with_range_pat(false, None)?;
365-
self.sess.gated_spans.gate(sym::box_patterns, lo.to(self.prev_token.span));
366-
PatKind::Box(pat)
363+
self.parse_pat_box()?
367364
} else if self.check_inline_const(0) {
368365
// Parse `const pat`
369366
let const_expr = self.parse_const_block(lo.to(self.token.span), true)?;
@@ -915,6 +912,62 @@ impl<'a> Parser<'a> {
915912
Ok(PatKind::TupleStruct(qself, path, fields))
916913
}
917914

915+
/// Are we sure this could not possibly be the start of a pattern?
916+
///
917+
/// Currently, this only accounts for tokens that can follow identifiers
918+
/// in patterns, but this can be extended as necessary.
919+
fn isnt_pattern_start(&self) -> bool {
920+
[
921+
token::Eq,
922+
token::Colon,
923+
token::Comma,
924+
token::Semi,
925+
token::At,
926+
token::OpenDelim(Delimiter::Brace),
927+
token::CloseDelim(Delimiter::Brace),
928+
token::CloseDelim(Delimiter::Parenthesis),
929+
]
930+
.contains(&self.token.kind)
931+
}
932+
933+
/// Parses `box pat`
934+
fn parse_pat_box(&mut self) -> PResult<'a, PatKind> {
935+
let box_span = self.prev_token.span;
936+
937+
if self.isnt_pattern_start() {
938+
self.struct_span_err(
939+
self.token.span,
940+
format!("expected pattern, found {}", super::token_descr(&self.token)),
941+
)
942+
.span_note(box_span, "`box` is a reserved keyword")
943+
.span_suggestion_verbose(
944+
box_span.shrink_to_lo(),
945+
"escape `box` to use it as an identifier",
946+
"r#",
947+
Applicability::MaybeIncorrect,
948+
)
949+
.emit();
950+
951+
// We cannot use `parse_pat_ident()` since it will complain `box`
952+
// is not an identifier.
953+
let sub = if self.eat(&token::At) {
954+
Some(self.parse_pat_no_top_alt(Some("binding pattern"))?)
955+
} else {
956+
None
957+
};
958+
959+
Ok(PatKind::Ident(
960+
BindingMode::ByValue(Mutability::Not),
961+
Ident::new(kw::Box, box_span),
962+
sub,
963+
))
964+
} else {
965+
let pat = self.parse_pat_with_range_pat(false, None)?;
966+
self.sess.gated_spans.gate(sym::box_patterns, box_span.to(self.prev_token.span));
967+
Ok(PatKind::Box(pat))
968+
}
969+
}
970+
918971
/// Parses the fields of a struct-like pattern.
919972
fn parse_pat_fields(&mut self) -> PResult<'a, (Vec<PatField>, bool)> {
920973
let mut fields = Vec::new();

Diff for: ‎src/test/ui/parser/keyword-box-as-identifier.rs

+8-1
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,10 @@
11
fn main() {
2-
let box = "foo"; //~ error: expected pattern, found `=`
2+
let box = 0;
3+
//~^ ERROR expected pattern, found `=`
4+
let box: bool;
5+
//~^ ERROR expected pattern, found `:`
6+
let mut box = 0;
7+
//~^ ERROR expected pattern, found `=`
8+
let (box,) = (0,);
9+
//~^ ERROR expected pattern, found `,`
310
}

Diff for: ‎src/test/ui/parser/keyword-box-as-identifier.stderr

+61-3
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,66 @@
11
error: expected pattern, found `=`
22
--> $DIR/keyword-box-as-identifier.rs:2:13
33
|
4-
LL | let box = "foo";
5-
| ^ expected pattern
4+
LL | let box = 0;
5+
| ^
6+
|
7+
note: `box` is a reserved keyword
8+
--> $DIR/keyword-box-as-identifier.rs:2:9
9+
|
10+
LL | let box = 0;
11+
| ^^^
12+
help: escape `box` to use it as an identifier
13+
|
14+
LL | let r#box = 0;
15+
| ++
16+
17+
error: expected pattern, found `:`
18+
--> $DIR/keyword-box-as-identifier.rs:4:12
19+
|
20+
LL | let box: bool;
21+
| ^
22+
|
23+
note: `box` is a reserved keyword
24+
--> $DIR/keyword-box-as-identifier.rs:4:9
25+
|
26+
LL | let box: bool;
27+
| ^^^
28+
help: escape `box` to use it as an identifier
29+
|
30+
LL | let r#box: bool;
31+
| ++
32+
33+
error: expected pattern, found `=`
34+
--> $DIR/keyword-box-as-identifier.rs:6:17
35+
|
36+
LL | let mut box = 0;
37+
| ^
38+
|
39+
note: `box` is a reserved keyword
40+
--> $DIR/keyword-box-as-identifier.rs:6:13
41+
|
42+
LL | let mut box = 0;
43+
| ^^^
44+
help: escape `box` to use it as an identifier
45+
|
46+
LL | let mut r#box = 0;
47+
| ++
48+
49+
error: expected pattern, found `,`
50+
--> $DIR/keyword-box-as-identifier.rs:8:13
51+
|
52+
LL | let (box,) = (0,);
53+
| ^
54+
|
55+
note: `box` is a reserved keyword
56+
--> $DIR/keyword-box-as-identifier.rs:8:10
57+
|
58+
LL | let (box,) = (0,);
59+
| ^^^
60+
help: escape `box` to use it as an identifier
61+
|
62+
LL | let (r#box,) = (0,);
63+
| ++
664

7-
error: aborting due to previous error
65+
error: aborting due to 4 previous errors
866

0 commit comments

Comments
 (0)
Please sign in to comment.