Skip to content

Commit 309c469

Browse files
committed
Auto merge of #104875 - chenyukang:yukang/fix-104867-inc, r=estebank
Properly handle postfix inc/dec in standalone and subexpr scenarios Fixes #104867 r? `@estebank`
2 parents 918d0ac + ded10a1 commit 309c469

10 files changed

+386
-65
lines changed

compiler/rustc_parse/src/parser/diagnostics.rs

+15-35
Original file line numberDiff line numberDiff line change
@@ -159,8 +159,6 @@ enum IsStandalone {
159159
Standalone,
160160
/// It's a subexpression, i.e., *not* standalone.
161161
Subexpr,
162-
/// It's maybe standalone; we're not sure.
163-
Maybe,
164162
}
165163

166164
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
@@ -213,14 +211,8 @@ impl MultiSugg {
213211
err.multipart_suggestion(&self.msg, self.patches, self.applicability);
214212
}
215213

216-
/// Overrides individual messages and applicabilities.
217-
fn emit_many(
218-
err: &mut Diagnostic,
219-
msg: &str,
220-
applicability: Applicability,
221-
suggestions: impl Iterator<Item = Self>,
222-
) {
223-
err.multipart_suggestions(msg, suggestions.map(|s| s.patches), applicability);
214+
fn emit_verbose(self, err: &mut Diagnostic) {
215+
err.multipart_suggestion_verbose(&self.msg, self.patches, self.applicability);
224216
}
225217
}
226218

@@ -1267,26 +1259,24 @@ impl<'a> Parser<'a> {
12671259
&mut self,
12681260
operand_expr: P<Expr>,
12691261
op_span: Span,
1270-
prev_is_semi: bool,
1262+
start_stmt: bool,
12711263
) -> PResult<'a, P<Expr>> {
1272-
let standalone =
1273-
if prev_is_semi { IsStandalone::Standalone } else { IsStandalone::Subexpr };
1264+
let standalone = if start_stmt { IsStandalone::Standalone } else { IsStandalone::Subexpr };
12741265
let kind = IncDecRecovery { standalone, op: IncOrDec::Inc, fixity: UnaryFixity::Pre };
1275-
12761266
self.recover_from_inc_dec(operand_expr, kind, op_span)
12771267
}
12781268

12791269
pub(super) fn recover_from_postfix_increment(
12801270
&mut self,
12811271
operand_expr: P<Expr>,
12821272
op_span: Span,
1273+
start_stmt: bool,
12831274
) -> PResult<'a, P<Expr>> {
12841275
let kind = IncDecRecovery {
1285-
standalone: IsStandalone::Maybe,
1276+
standalone: if start_stmt { IsStandalone::Standalone } else { IsStandalone::Subexpr },
12861277
op: IncOrDec::Inc,
12871278
fixity: UnaryFixity::Post,
12881279
};
1289-
12901280
self.recover_from_inc_dec(operand_expr, kind, op_span)
12911281
}
12921282

@@ -1315,34 +1305,25 @@ impl<'a> Parser<'a> {
13151305
};
13161306

13171307
match kind.standalone {
1318-
IsStandalone::Standalone => self.inc_dec_standalone_suggest(kind, spans).emit(&mut err),
1308+
IsStandalone::Standalone => {
1309+
self.inc_dec_standalone_suggest(kind, spans).emit_verbose(&mut err)
1310+
}
13191311
IsStandalone::Subexpr => {
13201312
let Ok(base_src) = self.span_to_snippet(base.span)
1321-
else { return help_base_case(err, base) };
1313+
else { return help_base_case(err, base) };
13221314
match kind.fixity {
13231315
UnaryFixity::Pre => {
13241316
self.prefix_inc_dec_suggest(base_src, kind, spans).emit(&mut err)
13251317
}
13261318
UnaryFixity::Post => {
1327-
self.postfix_inc_dec_suggest(base_src, kind, spans).emit(&mut err)
1319+
// won't suggest since we can not handle the precedences
1320+
// for example: `a + b++` has been parsed (a + b)++ and we can not suggest here
1321+
if !matches!(base.kind, ExprKind::Binary(_, _, _)) {
1322+
self.postfix_inc_dec_suggest(base_src, kind, spans).emit(&mut err)
1323+
}
13281324
}
13291325
}
13301326
}
1331-
IsStandalone::Maybe => {
1332-
let Ok(base_src) = self.span_to_snippet(base.span)
1333-
else { return help_base_case(err, base) };
1334-
let sugg1 = match kind.fixity {
1335-
UnaryFixity::Pre => self.prefix_inc_dec_suggest(base_src, kind, spans),
1336-
UnaryFixity::Post => self.postfix_inc_dec_suggest(base_src, kind, spans),
1337-
};
1338-
let sugg2 = self.inc_dec_standalone_suggest(kind, spans);
1339-
MultiSugg::emit_many(
1340-
&mut err,
1341-
"use `+= 1` instead",
1342-
Applicability::Unspecified,
1343-
[sugg1, sugg2].into_iter(),
1344-
)
1345-
}
13461327
}
13471328
Err(err)
13481329
}
@@ -1392,7 +1373,6 @@ impl<'a> Parser<'a> {
13921373
}
13931374

13941375
patches.push((post_span, format!(" {}= 1", kind.op.chr())));
1395-
13961376
MultiSugg {
13971377
msg: format!("use `{}= 1` instead", kind.op.chr()),
13981378
patches,

compiler/rustc_parse/src/parser/expr.rs

+9-6
Original file line numberDiff line numberDiff line change
@@ -83,7 +83,7 @@ macro_rules! maybe_whole_expr {
8383
pub(super) enum LhsExpr {
8484
NotYetParsed,
8585
AttributesParsed(AttrWrapper),
86-
AlreadyParsed(P<Expr>),
86+
AlreadyParsed(P<Expr>, bool), // (expr, starts_statement)
8787
}
8888

8989
impl From<Option<AttrWrapper>> for LhsExpr {
@@ -101,7 +101,7 @@ impl From<P<Expr>> for LhsExpr {
101101
///
102102
/// This conversion does not allocate.
103103
fn from(expr: P<Expr>) -> Self {
104-
LhsExpr::AlreadyParsed(expr)
104+
LhsExpr::AlreadyParsed(expr, false)
105105
}
106106
}
107107

@@ -173,7 +173,9 @@ impl<'a> Parser<'a> {
173173
min_prec: usize,
174174
lhs: LhsExpr,
175175
) -> PResult<'a, P<Expr>> {
176-
let mut lhs = if let LhsExpr::AlreadyParsed(expr) = lhs {
176+
let mut starts_stmt = false;
177+
let mut lhs = if let LhsExpr::AlreadyParsed(expr, starts_statement) = lhs {
178+
starts_stmt = starts_statement;
177179
expr
178180
} else {
179181
let attrs = match lhs {
@@ -292,7 +294,7 @@ impl<'a> Parser<'a> {
292294
let op_span = self.prev_token.span.to(self.token.span);
293295
// Eat the second `+`
294296
self.bump();
295-
lhs = self.recover_from_postfix_increment(lhs, op_span)?;
297+
lhs = self.recover_from_postfix_increment(lhs, op_span, starts_stmt)?;
296298
continue;
297299
}
298300

@@ -590,14 +592,15 @@ impl<'a> Parser<'a> {
590592
token::BinOp(token::Plus)
591593
if this.look_ahead(1, |t| *t == token::BinOp(token::Plus)) =>
592594
{
593-
let prev_is_semi = this.prev_token == token::Semi;
595+
let starts_stmt = this.prev_token == token::Semi
596+
|| this.prev_token == token::CloseDelim(Delimiter::Brace);
594597
let pre_span = this.token.span.to(this.look_ahead(1, |t| t.span));
595598
// Eat both `+`s.
596599
this.bump();
597600
this.bump();
598601

599602
let operand_expr = this.parse_dot_or_call_expr(Default::default())?;
600-
this.recover_from_prefix_increment(operand_expr, pre_span, prev_is_semi)
603+
this.recover_from_prefix_increment(operand_expr, pre_span, starts_stmt)
601604
}
602605
token::Ident(..) if this.token.is_keyword(kw::Box) => {
603606
make_it!(this, attrs, |this, _| this.parse_box_expr(lo))

compiler/rustc_parse/src/parser/stmt.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -164,7 +164,7 @@ impl<'a> Parser<'a> {
164164
// Perform this outside of the `collect_tokens_trailing_token` closure,
165165
// since our outer attributes do not apply to this part of the expression
166166
let expr = self.with_res(Restrictions::STMT_EXPR, |this| {
167-
this.parse_assoc_expr_with(0, LhsExpr::AlreadyParsed(expr))
167+
this.parse_assoc_expr_with(0, LhsExpr::AlreadyParsed(expr, true))
168168
})?;
169169
Ok(self.mk_stmt(lo.to(self.prev_token.span), StmtKind::Expr(expr)))
170170
} else {
@@ -198,7 +198,7 @@ impl<'a> Parser<'a> {
198198
let e = self.mk_expr(lo.to(hi), ExprKind::MacCall(mac));
199199
let e = self.maybe_recover_from_bad_qpath(e)?;
200200
let e = self.parse_dot_or_call_expr_with(e, lo, attrs)?;
201-
let e = self.parse_assoc_expr_with(0, LhsExpr::AlreadyParsed(e))?;
201+
let e = self.parse_assoc_expr_with(0, LhsExpr::AlreadyParsed(e, false))?;
202202
StmtKind::Expr(e)
203203
};
204204
Ok(self.mk_stmt(lo.to(hi), kind))
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
// run-rustfix
2+
3+
struct Foo {
4+
bar: Bar,
5+
}
6+
7+
struct Bar {
8+
qux: i32,
9+
}
10+
11+
pub fn post_regular() {
12+
let mut i = 0;
13+
i += 1; //~ ERROR Rust has no postfix increment operator
14+
println!("{}", i);
15+
}
16+
17+
pub fn post_while() {
18+
let mut i = 0;
19+
while { let tmp = i; i += 1; tmp } < 5 {
20+
//~^ ERROR Rust has no postfix increment operator
21+
println!("{}", i);
22+
}
23+
}
24+
25+
pub fn post_regular_tmp() {
26+
let mut tmp = 0;
27+
tmp += 1; //~ ERROR Rust has no postfix increment operator
28+
println!("{}", tmp);
29+
}
30+
31+
pub fn post_while_tmp() {
32+
let mut tmp = 0;
33+
while { let tmp_ = tmp; tmp += 1; tmp_ } < 5 {
34+
//~^ ERROR Rust has no postfix increment operator
35+
println!("{}", tmp);
36+
}
37+
}
38+
39+
pub fn post_field() {
40+
let mut foo = Foo { bar: Bar { qux: 0 } };
41+
foo.bar.qux += 1;
42+
//~^ ERROR Rust has no postfix increment operator
43+
println!("{}", foo.bar.qux);
44+
}
45+
46+
pub fn post_field_tmp() {
47+
struct S {
48+
tmp: i32
49+
}
50+
let mut s = S { tmp: 0 };
51+
s.tmp += 1;
52+
//~^ ERROR Rust has no postfix increment operator
53+
println!("{}", s.tmp);
54+
}
55+
56+
pub fn pre_field() {
57+
let mut foo = Foo { bar: Bar { qux: 0 } };
58+
foo.bar.qux += 1;
59+
//~^ ERROR Rust has no prefix increment operator
60+
println!("{}", foo.bar.qux);
61+
}
62+
63+
fn main() {}

src/test/ui/parser/increment-notfixed.rs renamed to src/test/ui/parser/increment-autofix-2.rs

+5-3
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
// run-rustfix
2+
13
struct Foo {
24
bar: Bar,
35
}
@@ -35,7 +37,7 @@ pub fn post_while_tmp() {
3537
}
3638

3739
pub fn post_field() {
38-
let foo = Foo { bar: Bar { qux: 0 } };
40+
let mut foo = Foo { bar: Bar { qux: 0 } };
3941
foo.bar.qux++;
4042
//~^ ERROR Rust has no postfix increment operator
4143
println!("{}", foo.bar.qux);
@@ -45,14 +47,14 @@ pub fn post_field_tmp() {
4547
struct S {
4648
tmp: i32
4749
}
48-
let s = S { tmp: 0 };
50+
let mut s = S { tmp: 0 };
4951
s.tmp++;
5052
//~^ ERROR Rust has no postfix increment operator
5153
println!("{}", s.tmp);
5254
}
5355

5456
pub fn pre_field() {
55-
let foo = Foo { bar: Bar { qux: 0 } };
57+
let mut foo = Foo { bar: Bar { qux: 0 } };
5658
++foo.bar.qux;
5759
//~^ ERROR Rust has no prefix increment operator
5860
println!("{}", foo.bar.qux);

src/test/ui/parser/increment-notfixed.stderr renamed to src/test/ui/parser/increment-autofix-2.stderr

+7-19
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,16 @@
11
error: Rust has no postfix increment operator
2-
--> $DIR/increment-notfixed.rs:11:6
2+
--> $DIR/increment-autofix-2.rs:13:6
33
|
44
LL | i++;
55
| ^^ not a valid postfix operator
66
|
77
help: use `+= 1` instead
88
|
9-
LL | { let tmp = i; i += 1; tmp };
10-
| +++++++++++ ~~~~~~~~~~~~~~~
119
LL | i += 1;
1210
| ~~~~
1311

1412
error: Rust has no postfix increment operator
15-
--> $DIR/increment-notfixed.rs:17:12
13+
--> $DIR/increment-autofix-2.rs:19:12
1614
|
1715
LL | while i++ < 5 {
1816
| ----- ^^ not a valid postfix operator
@@ -23,24 +21,20 @@ help: use `+= 1` instead
2321
|
2422
LL | while { let tmp = i; i += 1; tmp } < 5 {
2523
| +++++++++++ ~~~~~~~~~~~~~~~
26-
LL | while i += 1 < 5 {
27-
| ~~~~
2824

2925
error: Rust has no postfix increment operator
30-
--> $DIR/increment-notfixed.rs:25:8
26+
--> $DIR/increment-autofix-2.rs:27:8
3127
|
3228
LL | tmp++;
3329
| ^^ not a valid postfix operator
3430
|
3531
help: use `+= 1` instead
3632
|
37-
LL | { let tmp_ = tmp; tmp += 1; tmp_ };
38-
| ++++++++++++ ~~~~~~~~~~~~~~~~~~
3933
LL | tmp += 1;
4034
| ~~~~
4135

4236
error: Rust has no postfix increment operator
43-
--> $DIR/increment-notfixed.rs:31:14
37+
--> $DIR/increment-autofix-2.rs:33:14
4438
|
4539
LL | while tmp++ < 5 {
4640
| ----- ^^ not a valid postfix operator
@@ -51,37 +45,31 @@ help: use `+= 1` instead
5145
|
5246
LL | while { let tmp_ = tmp; tmp += 1; tmp_ } < 5 {
5347
| ++++++++++++ ~~~~~~~~~~~~~~~~~~
54-
LL | while tmp += 1 < 5 {
55-
| ~~~~
5648

5749
error: Rust has no postfix increment operator
58-
--> $DIR/increment-notfixed.rs:39:16
50+
--> $DIR/increment-autofix-2.rs:41:16
5951
|
6052
LL | foo.bar.qux++;
6153
| ^^ not a valid postfix operator
6254
|
6355
help: use `+= 1` instead
6456
|
65-
LL | { let tmp = foo.bar.qux; foo.bar.qux += 1; tmp };
66-
| +++++++++++ ~~~~~~~~~~~~~~~~~~~~~~~~~
6757
LL | foo.bar.qux += 1;
6858
| ~~~~
6959

7060
error: Rust has no postfix increment operator
71-
--> $DIR/increment-notfixed.rs:49:10
61+
--> $DIR/increment-autofix-2.rs:51:10
7262
|
7363
LL | s.tmp++;
7464
| ^^ not a valid postfix operator
7565
|
7666
help: use `+= 1` instead
7767
|
78-
LL | { let tmp = s.tmp; s.tmp += 1; tmp };
79-
| +++++++++++ ~~~~~~~~~~~~~~~~~~~
8068
LL | s.tmp += 1;
8169
| ~~~~
8270

8371
error: Rust has no prefix increment operator
84-
--> $DIR/increment-notfixed.rs:56:5
72+
--> $DIR/increment-autofix-2.rs:58:5
8573
|
8674
LL | ++foo.bar.qux;
8775
| ^^ not a valid prefix operator

0 commit comments

Comments
 (0)