diff --git a/compiler/rustc_parse/src/parser/diagnostics.rs b/compiler/rustc_parse/src/parser/diagnostics.rs index c316a4dd6b41a..0191ab730c812 100644 --- a/compiler/rustc_parse/src/parser/diagnostics.rs +++ b/compiler/rustc_parse/src/parser/diagnostics.rs @@ -159,8 +159,6 @@ enum IsStandalone { Standalone, /// It's a subexpression, i.e., *not* standalone. Subexpr, - /// It's maybe standalone; we're not sure. - Maybe, } #[derive(Debug, Copy, Clone, PartialEq, Eq)] @@ -213,14 +211,8 @@ impl MultiSugg { err.multipart_suggestion(&self.msg, self.patches, self.applicability); } - /// Overrides individual messages and applicabilities. - fn emit_many( - err: &mut Diagnostic, - msg: &str, - applicability: Applicability, - suggestions: impl Iterator, - ) { - err.multipart_suggestions(msg, suggestions.map(|s| s.patches), applicability); + fn emit_verbose(self, err: &mut Diagnostic) { + err.multipart_suggestion_verbose(&self.msg, self.patches, self.applicability); } } @@ -1267,12 +1259,10 @@ impl<'a> Parser<'a> { &mut self, operand_expr: P, op_span: Span, - prev_is_semi: bool, + start_stmt: bool, ) -> PResult<'a, P> { - let standalone = - if prev_is_semi { IsStandalone::Standalone } else { IsStandalone::Subexpr }; + let standalone = if start_stmt { IsStandalone::Standalone } else { IsStandalone::Subexpr }; let kind = IncDecRecovery { standalone, op: IncOrDec::Inc, fixity: UnaryFixity::Pre }; - self.recover_from_inc_dec(operand_expr, kind, op_span) } @@ -1280,13 +1270,13 @@ impl<'a> Parser<'a> { &mut self, operand_expr: P, op_span: Span, + start_stmt: bool, ) -> PResult<'a, P> { let kind = IncDecRecovery { - standalone: IsStandalone::Maybe, + standalone: if start_stmt { IsStandalone::Standalone } else { IsStandalone::Subexpr }, op: IncOrDec::Inc, fixity: UnaryFixity::Post, }; - self.recover_from_inc_dec(operand_expr, kind, op_span) } @@ -1315,34 +1305,25 @@ impl<'a> Parser<'a> { }; match kind.standalone { - IsStandalone::Standalone => self.inc_dec_standalone_suggest(kind, spans).emit(&mut err), + IsStandalone::Standalone => { + self.inc_dec_standalone_suggest(kind, spans).emit_verbose(&mut err) + } IsStandalone::Subexpr => { let Ok(base_src) = self.span_to_snippet(base.span) - else { return help_base_case(err, base) }; + else { return help_base_case(err, base) }; match kind.fixity { UnaryFixity::Pre => { self.prefix_inc_dec_suggest(base_src, kind, spans).emit(&mut err) } UnaryFixity::Post => { - self.postfix_inc_dec_suggest(base_src, kind, spans).emit(&mut err) + // won't suggest since we can not handle the precedences + // for example: `a + b++` has been parsed (a + b)++ and we can not suggest here + if !matches!(base.kind, ExprKind::Binary(_, _, _)) { + self.postfix_inc_dec_suggest(base_src, kind, spans).emit(&mut err) + } } } } - IsStandalone::Maybe => { - let Ok(base_src) = self.span_to_snippet(base.span) - else { return help_base_case(err, base) }; - let sugg1 = match kind.fixity { - UnaryFixity::Pre => self.prefix_inc_dec_suggest(base_src, kind, spans), - UnaryFixity::Post => self.postfix_inc_dec_suggest(base_src, kind, spans), - }; - let sugg2 = self.inc_dec_standalone_suggest(kind, spans); - MultiSugg::emit_many( - &mut err, - "use `+= 1` instead", - Applicability::Unspecified, - [sugg1, sugg2].into_iter(), - ) - } } Err(err) } @@ -1392,7 +1373,6 @@ impl<'a> Parser<'a> { } patches.push((post_span, format!(" {}= 1", kind.op.chr()))); - MultiSugg { msg: format!("use `{}= 1` instead", kind.op.chr()), patches, diff --git a/compiler/rustc_parse/src/parser/expr.rs b/compiler/rustc_parse/src/parser/expr.rs index 8a3545eb3be3a..c0ed450b98508 100644 --- a/compiler/rustc_parse/src/parser/expr.rs +++ b/compiler/rustc_parse/src/parser/expr.rs @@ -83,7 +83,7 @@ macro_rules! maybe_whole_expr { pub(super) enum LhsExpr { NotYetParsed, AttributesParsed(AttrWrapper), - AlreadyParsed(P), + AlreadyParsed(P, bool), // (expr, starts_statement) } impl From> for LhsExpr { @@ -101,7 +101,7 @@ impl From> for LhsExpr { /// /// This conversion does not allocate. fn from(expr: P) -> Self { - LhsExpr::AlreadyParsed(expr) + LhsExpr::AlreadyParsed(expr, false) } } @@ -173,7 +173,9 @@ impl<'a> Parser<'a> { min_prec: usize, lhs: LhsExpr, ) -> PResult<'a, P> { - let mut lhs = if let LhsExpr::AlreadyParsed(expr) = lhs { + let mut starts_stmt = false; + let mut lhs = if let LhsExpr::AlreadyParsed(expr, starts_statement) = lhs { + starts_stmt = starts_statement; expr } else { let attrs = match lhs { @@ -292,7 +294,7 @@ impl<'a> Parser<'a> { let op_span = self.prev_token.span.to(self.token.span); // Eat the second `+` self.bump(); - lhs = self.recover_from_postfix_increment(lhs, op_span)?; + lhs = self.recover_from_postfix_increment(lhs, op_span, starts_stmt)?; continue; } @@ -590,14 +592,15 @@ impl<'a> Parser<'a> { token::BinOp(token::Plus) if this.look_ahead(1, |t| *t == token::BinOp(token::Plus)) => { - let prev_is_semi = this.prev_token == token::Semi; + let starts_stmt = this.prev_token == token::Semi + || this.prev_token == token::CloseDelim(Delimiter::Brace); let pre_span = this.token.span.to(this.look_ahead(1, |t| t.span)); // Eat both `+`s. this.bump(); this.bump(); let operand_expr = this.parse_dot_or_call_expr(Default::default())?; - this.recover_from_prefix_increment(operand_expr, pre_span, prev_is_semi) + this.recover_from_prefix_increment(operand_expr, pre_span, starts_stmt) } token::Ident(..) if this.token.is_keyword(kw::Box) => { make_it!(this, attrs, |this, _| this.parse_box_expr(lo)) diff --git a/compiler/rustc_parse/src/parser/stmt.rs b/compiler/rustc_parse/src/parser/stmt.rs index 42197e6379749..bae7f2670cb11 100644 --- a/compiler/rustc_parse/src/parser/stmt.rs +++ b/compiler/rustc_parse/src/parser/stmt.rs @@ -164,7 +164,7 @@ impl<'a> Parser<'a> { // Perform this outside of the `collect_tokens_trailing_token` closure, // since our outer attributes do not apply to this part of the expression let expr = self.with_res(Restrictions::STMT_EXPR, |this| { - this.parse_assoc_expr_with(0, LhsExpr::AlreadyParsed(expr)) + this.parse_assoc_expr_with(0, LhsExpr::AlreadyParsed(expr, true)) })?; Ok(self.mk_stmt(lo.to(self.prev_token.span), StmtKind::Expr(expr))) } else { @@ -198,7 +198,7 @@ impl<'a> Parser<'a> { let e = self.mk_expr(lo.to(hi), ExprKind::MacCall(mac)); let e = self.maybe_recover_from_bad_qpath(e)?; let e = self.parse_dot_or_call_expr_with(e, lo, attrs)?; - let e = self.parse_assoc_expr_with(0, LhsExpr::AlreadyParsed(e))?; + let e = self.parse_assoc_expr_with(0, LhsExpr::AlreadyParsed(e, false))?; StmtKind::Expr(e) }; Ok(self.mk_stmt(lo.to(hi), kind)) diff --git a/src/test/ui/parser/increment-autofix-2.fixed b/src/test/ui/parser/increment-autofix-2.fixed new file mode 100644 index 0000000000000..580ebaf5dbb13 --- /dev/null +++ b/src/test/ui/parser/increment-autofix-2.fixed @@ -0,0 +1,63 @@ +// run-rustfix + +struct Foo { + bar: Bar, +} + +struct Bar { + qux: i32, +} + +pub fn post_regular() { + let mut i = 0; + i += 1; //~ ERROR Rust has no postfix increment operator + println!("{}", i); +} + +pub fn post_while() { + let mut i = 0; + while { let tmp = i; i += 1; tmp } < 5 { + //~^ ERROR Rust has no postfix increment operator + println!("{}", i); + } +} + +pub fn post_regular_tmp() { + let mut tmp = 0; + tmp += 1; //~ ERROR Rust has no postfix increment operator + println!("{}", tmp); +} + +pub fn post_while_tmp() { + let mut tmp = 0; + while { let tmp_ = tmp; tmp += 1; tmp_ } < 5 { + //~^ ERROR Rust has no postfix increment operator + println!("{}", tmp); + } +} + +pub fn post_field() { + let mut foo = Foo { bar: Bar { qux: 0 } }; + foo.bar.qux += 1; + //~^ ERROR Rust has no postfix increment operator + println!("{}", foo.bar.qux); +} + +pub fn post_field_tmp() { + struct S { + tmp: i32 + } + let mut s = S { tmp: 0 }; + s.tmp += 1; + //~^ ERROR Rust has no postfix increment operator + println!("{}", s.tmp); +} + +pub fn pre_field() { + let mut foo = Foo { bar: Bar { qux: 0 } }; + foo.bar.qux += 1; + //~^ ERROR Rust has no prefix increment operator + println!("{}", foo.bar.qux); +} + +fn main() {} diff --git a/src/test/ui/parser/increment-notfixed.rs b/src/test/ui/parser/increment-autofix-2.rs similarity index 88% rename from src/test/ui/parser/increment-notfixed.rs rename to src/test/ui/parser/increment-autofix-2.rs index 15f159e53d294..ebe5fa6ca1e76 100644 --- a/src/test/ui/parser/increment-notfixed.rs +++ b/src/test/ui/parser/increment-autofix-2.rs @@ -1,3 +1,5 @@ +// run-rustfix + struct Foo { bar: Bar, } @@ -35,7 +37,7 @@ pub fn post_while_tmp() { } pub fn post_field() { - let foo = Foo { bar: Bar { qux: 0 } }; + let mut foo = Foo { bar: Bar { qux: 0 } }; foo.bar.qux++; //~^ ERROR Rust has no postfix increment operator println!("{}", foo.bar.qux); @@ -45,14 +47,14 @@ pub fn post_field_tmp() { struct S { tmp: i32 } - let s = S { tmp: 0 }; + let mut s = S { tmp: 0 }; s.tmp++; //~^ ERROR Rust has no postfix increment operator println!("{}", s.tmp); } pub fn pre_field() { - let foo = Foo { bar: Bar { qux: 0 } }; + let mut foo = Foo { bar: Bar { qux: 0 } }; ++foo.bar.qux; //~^ ERROR Rust has no prefix increment operator println!("{}", foo.bar.qux); diff --git a/src/test/ui/parser/increment-notfixed.stderr b/src/test/ui/parser/increment-autofix-2.stderr similarity index 69% rename from src/test/ui/parser/increment-notfixed.stderr rename to src/test/ui/parser/increment-autofix-2.stderr index ae55ae0671431..11e985480d697 100644 --- a/src/test/ui/parser/increment-notfixed.stderr +++ b/src/test/ui/parser/increment-autofix-2.stderr @@ -1,18 +1,16 @@ error: Rust has no postfix increment operator - --> $DIR/increment-notfixed.rs:11:6 + --> $DIR/increment-autofix-2.rs:13:6 | LL | i++; | ^^ not a valid postfix operator | help: use `+= 1` instead | -LL | { let tmp = i; i += 1; tmp }; - | +++++++++++ ~~~~~~~~~~~~~~~ LL | i += 1; | ~~~~ error: Rust has no postfix increment operator - --> $DIR/increment-notfixed.rs:17:12 + --> $DIR/increment-autofix-2.rs:19:12 | LL | while i++ < 5 { | ----- ^^ not a valid postfix operator @@ -23,24 +21,20 @@ help: use `+= 1` instead | LL | while { let tmp = i; i += 1; tmp } < 5 { | +++++++++++ ~~~~~~~~~~~~~~~ -LL | while i += 1 < 5 { - | ~~~~ error: Rust has no postfix increment operator - --> $DIR/increment-notfixed.rs:25:8 + --> $DIR/increment-autofix-2.rs:27:8 | LL | tmp++; | ^^ not a valid postfix operator | help: use `+= 1` instead | -LL | { let tmp_ = tmp; tmp += 1; tmp_ }; - | ++++++++++++ ~~~~~~~~~~~~~~~~~~ LL | tmp += 1; | ~~~~ error: Rust has no postfix increment operator - --> $DIR/increment-notfixed.rs:31:14 + --> $DIR/increment-autofix-2.rs:33:14 | LL | while tmp++ < 5 { | ----- ^^ not a valid postfix operator @@ -51,37 +45,31 @@ help: use `+= 1` instead | LL | while { let tmp_ = tmp; tmp += 1; tmp_ } < 5 { | ++++++++++++ ~~~~~~~~~~~~~~~~~~ -LL | while tmp += 1 < 5 { - | ~~~~ error: Rust has no postfix increment operator - --> $DIR/increment-notfixed.rs:39:16 + --> $DIR/increment-autofix-2.rs:41:16 | LL | foo.bar.qux++; | ^^ not a valid postfix operator | help: use `+= 1` instead | -LL | { let tmp = foo.bar.qux; foo.bar.qux += 1; tmp }; - | +++++++++++ ~~~~~~~~~~~~~~~~~~~~~~~~~ LL | foo.bar.qux += 1; | ~~~~ error: Rust has no postfix increment operator - --> $DIR/increment-notfixed.rs:49:10 + --> $DIR/increment-autofix-2.rs:51:10 | LL | s.tmp++; | ^^ not a valid postfix operator | help: use `+= 1` instead | -LL | { let tmp = s.tmp; s.tmp += 1; tmp }; - | +++++++++++ ~~~~~~~~~~~~~~~~~~~ LL | s.tmp += 1; | ~~~~ error: Rust has no prefix increment operator - --> $DIR/increment-notfixed.rs:56:5 + --> $DIR/increment-autofix-2.rs:58:5 | LL | ++foo.bar.qux; | ^^ not a valid prefix operator diff --git a/src/test/ui/parser/issue-104867-inc-dec-2.rs b/src/test/ui/parser/issue-104867-inc-dec-2.rs new file mode 100644 index 0000000000000..a006421a975d9 --- /dev/null +++ b/src/test/ui/parser/issue-104867-inc-dec-2.rs @@ -0,0 +1,52 @@ +fn test1() { + let mut i = 0; + let _ = i + ++i; //~ ERROR Rust has no prefix increment operator +} + +fn test2() { + let mut i = 0; + let _ = ++i + i; //~ ERROR Rust has no prefix increment operator +} + +fn test3() { + let mut i = 0; + let _ = ++i + ++i; //~ ERROR Rust has no prefix increment operator +} + +fn test4() { + let mut i = 0; + let _ = i + i++; //~ ERROR Rust has no postfix increment operator + // won't suggest since we can not handle the precedences +} + +fn test5() { + let mut i = 0; + let _ = i++ + i; //~ ERROR Rust has no postfix increment operator +} + +fn test6() { + let mut i = 0; + let _ = i++ + i++; //~ ERROR Rust has no postfix increment operator +} + +fn test7() { + let mut i = 0; + let _ = ++i + i++; //~ ERROR Rust has no prefix increment operator +} + +fn test8() { + let mut i = 0; + let _ = i++ + ++i; //~ ERROR Rust has no postfix increment operator +} + +fn test9() { + let mut i = 0; + let _ = (1 + 2 + i)++; //~ ERROR Rust has no postfix increment operator +} + +fn test10() { + let mut i = 0; + let _ = (i++ + 1) + 2; //~ ERROR Rust has no postfix increment operator +} + +fn main() { } diff --git a/src/test/ui/parser/issue-104867-inc-dec-2.stderr b/src/test/ui/parser/issue-104867-inc-dec-2.stderr new file mode 100644 index 0000000000000..4e2d0546851e3 --- /dev/null +++ b/src/test/ui/parser/issue-104867-inc-dec-2.stderr @@ -0,0 +1,107 @@ +error: Rust has no prefix increment operator + --> $DIR/issue-104867-inc-dec-2.rs:3:17 + | +LL | let _ = i + ++i; + | ^^ not a valid prefix operator + | +help: use `+= 1` instead + | +LL | let _ = i + { i += 1; i }; + | ~ +++++++++ + +error: Rust has no prefix increment operator + --> $DIR/issue-104867-inc-dec-2.rs:8:13 + | +LL | let _ = ++i + i; + | ^^ not a valid prefix operator + | +help: use `+= 1` instead + | +LL | let _ = { i += 1; i } + i; + | ~ +++++++++ + +error: Rust has no prefix increment operator + --> $DIR/issue-104867-inc-dec-2.rs:13:13 + | +LL | let _ = ++i + ++i; + | ^^ not a valid prefix operator + | +help: use `+= 1` instead + | +LL | let _ = { i += 1; i } + ++i; + | ~ +++++++++ + +error: Rust has no postfix increment operator + --> $DIR/issue-104867-inc-dec-2.rs:18:18 + | +LL | let _ = i + i++; + | ^^ not a valid postfix operator + +error: Rust has no postfix increment operator + --> $DIR/issue-104867-inc-dec-2.rs:24:14 + | +LL | let _ = i++ + i; + | ^^ not a valid postfix operator + | +help: use `+= 1` instead + | +LL | let _ = { let tmp = i; i += 1; tmp } + i; + | +++++++++++ ~~~~~~~~~~~~~~~ + +error: Rust has no postfix increment operator + --> $DIR/issue-104867-inc-dec-2.rs:29:14 + | +LL | let _ = i++ + i++; + | ^^ not a valid postfix operator + | +help: use `+= 1` instead + | +LL | let _ = { let tmp = i; i += 1; tmp } + i++; + | +++++++++++ ~~~~~~~~~~~~~~~ + +error: Rust has no prefix increment operator + --> $DIR/issue-104867-inc-dec-2.rs:34:13 + | +LL | let _ = ++i + i++; + | ^^ not a valid prefix operator + | +help: use `+= 1` instead + | +LL | let _ = { i += 1; i } + i++; + | ~ +++++++++ + +error: Rust has no postfix increment operator + --> $DIR/issue-104867-inc-dec-2.rs:39:14 + | +LL | let _ = i++ + ++i; + | ^^ not a valid postfix operator + | +help: use `+= 1` instead + | +LL | let _ = { let tmp = i; i += 1; tmp } + ++i; + | +++++++++++ ~~~~~~~~~~~~~~~ + +error: Rust has no postfix increment operator + --> $DIR/issue-104867-inc-dec-2.rs:44:24 + | +LL | let _ = (1 + 2 + i)++; + | ^^ not a valid postfix operator + | +help: use `+= 1` instead + | +LL | let _ = { let tmp = (1 + 2 + i); (1 + 2 + i) += 1; tmp }; + | +++++++++++ ~~~~~~~~~~~~~~~~~~~~~~~~~ + +error: Rust has no postfix increment operator + --> $DIR/issue-104867-inc-dec-2.rs:49:15 + | +LL | let _ = (i++ + 1) + 2; + | ^^ not a valid postfix operator + | +help: use `+= 1` instead + | +LL | let _ = ({ let tmp = i; i += 1; tmp } + 1) + 2; + | +++++++++++ ~~~~~~~~~~~~~~~ + +error: aborting due to 10 previous errors + diff --git a/src/test/ui/parser/issue-104867-inc-dec.rs b/src/test/ui/parser/issue-104867-inc-dec.rs new file mode 100644 index 0000000000000..760c67b4bed70 --- /dev/null +++ b/src/test/ui/parser/issue-104867-inc-dec.rs @@ -0,0 +1,45 @@ +struct S { + x: i32, +} + +fn test1() { + let mut i = 0; + i++; //~ ERROR Rust has no postfix increment operator +} + +fn test2() { + let s = S { x: 0 }; + s.x++; //~ ERROR Rust has no postfix increment operator +} + +fn test3() { + let mut i = 0; + if i++ == 1 {} //~ ERROR Rust has no postfix increment operator +} + +fn test4() { + let mut i = 0; + ++i; //~ ERROR Rust has no prefix increment operator +} + +fn test5() { + let mut i = 0; + if ++i == 1 { } //~ ERROR Rust has no prefix increment operator +} + +fn test6() { + let mut i = 0; + loop { break; } + i++; //~ ERROR Rust has no postfix increment operator + loop { break; } + ++i; +} + +fn test7() { + let mut i = 0; + loop { break; } + ++i; //~ ERROR Rust has no prefix increment operator +} + + +fn main() {} diff --git a/src/test/ui/parser/issue-104867-inc-dec.stderr b/src/test/ui/parser/issue-104867-inc-dec.stderr new file mode 100644 index 0000000000000..78bfd3e82f0de --- /dev/null +++ b/src/test/ui/parser/issue-104867-inc-dec.stderr @@ -0,0 +1,81 @@ +error: Rust has no postfix increment operator + --> $DIR/issue-104867-inc-dec.rs:7:6 + | +LL | i++; + | ^^ not a valid postfix operator + | +help: use `+= 1` instead + | +LL | i += 1; + | ~~~~ + +error: Rust has no postfix increment operator + --> $DIR/issue-104867-inc-dec.rs:12:8 + | +LL | s.x++; + | ^^ not a valid postfix operator + | +help: use `+= 1` instead + | +LL | s.x += 1; + | ~~~~ + +error: Rust has no postfix increment operator + --> $DIR/issue-104867-inc-dec.rs:17:9 + | +LL | if i++ == 1 {} + | ^^ not a valid postfix operator + | +help: use `+= 1` instead + | +LL | if { let tmp = i; i += 1; tmp } == 1 {} + | +++++++++++ ~~~~~~~~~~~~~~~ + +error: Rust has no prefix increment operator + --> $DIR/issue-104867-inc-dec.rs:22:5 + | +LL | ++i; + | ^^ not a valid prefix operator + | +help: use `+= 1` instead + | +LL - ++i; +LL + i += 1; + | + +error: Rust has no prefix increment operator + --> $DIR/issue-104867-inc-dec.rs:27:8 + | +LL | if ++i == 1 { } + | ^^ not a valid prefix operator + | +help: use `+= 1` instead + | +LL | if { i += 1; i } == 1 { } + | ~ +++++++++ + +error: Rust has no postfix increment operator + --> $DIR/issue-104867-inc-dec.rs:33:6 + | +LL | i++; + | ^^ not a valid postfix operator + | +help: use `+= 1` instead + | +LL | i += 1; + | ~~~~ + +error: Rust has no prefix increment operator + --> $DIR/issue-104867-inc-dec.rs:41:5 + | +LL | ++i; + | ^^ not a valid prefix operator + | +help: use `+= 1` instead + | +LL - ++i; +LL + i += 1; + | + +error: aborting due to 7 previous errors +