diff --git a/compiler/rustc_parse/src/parser/diagnostics.rs b/compiler/rustc_parse/src/parser/diagnostics.rs index a8a1842f377..26ca018685e 100644 --- a/compiler/rustc_parse/src/parser/diagnostics.rs +++ b/compiler/rustc_parse/src/parser/diagnostics.rs @@ -160,8 +160,10 @@ pub fn no(&self) -> bool { /// C-style `i++`, `--i`, etc. #[derive(Debug, Copy, Clone)] struct IncDecRecovery { - /// This increment/decrement is not a subexpression. - standalone: bool, + /// Is this increment/decrement its own statement? + /// + /// This is `None` when we are unsure. + standalone: Option, /// Is this an increment or decrement? op: IncOrDec, /// Is this pre- or postfix? @@ -1225,7 +1227,7 @@ pub(super) fn maybe_recover_from_prefix_increment( prev_is_semi: bool, ) -> PResult<'a, P> { let kind = IncDecRecovery { - standalone: prev_is_semi, + standalone: Some(prev_is_semi), op: IncOrDec::Inc, fixity: UnaryFixity::Pre, }; @@ -1237,13 +1239,9 @@ pub(super) fn maybe_recover_from_postfix_increment( &mut self, operand_expr: P, op_span: Span, - prev_is_semi: bool, ) -> PResult<'a, P> { - let kind = IncDecRecovery { - standalone: prev_is_semi, - op: IncOrDec::Inc, - fixity: UnaryFixity::Post, - }; + let kind = + IncDecRecovery { standalone: None, op: IncOrDec::Inc, fixity: UnaryFixity::Post }; self.recover_from_inc_dec(operand_expr, kind, op_span) } @@ -1272,25 +1270,44 @@ fn recover_from_inc_dec( UnaryFixity::Post => (base.span.shrink_to_lo(), op_span), }; - if kind.standalone { - self.inc_dec_standalone_recovery(err, kind, spans) - } else { - let Ok(base_src) = self.span_to_snippet(base.span) - else { return help_base_case(err, base) }; - match kind.fixity { - UnaryFixity::Pre => self.prefix_inc_dec_suggest(base_src, err, kind, spans), - UnaryFixity::Post => self.postfix_inc_dec_suggest(base_src, err, kind, spans), + match kind.standalone { + Some(true) => self.inc_dec_standalone_recovery(&mut err, kind, spans, false), + Some(false) => { + let Ok(base_src) = self.span_to_snippet(base.span) + else { return help_base_case(err, base) }; + match kind.fixity { + UnaryFixity::Pre => { + self.prefix_inc_dec_suggest(base_src, &mut err, kind, spans) + } + UnaryFixity::Post => { + self.postfix_inc_dec_suggest(base_src, &mut err, kind, spans) + } + } + } + None => { + let Ok(base_src) = self.span_to_snippet(base.span) + else { return help_base_case(err, base) }; + match kind.fixity { + UnaryFixity::Pre => { + self.prefix_inc_dec_suggest(base_src, &mut err, kind, spans) + } + UnaryFixity::Post => { + self.postfix_inc_dec_suggest(base_src, &mut err, kind, spans) + } + } + self.inc_dec_standalone_recovery(&mut err, kind, spans, true) } } + Err(err) } fn prefix_inc_dec_suggest( &mut self, base_src: String, - mut err: DiagnosticBuilder<'a>, + err: &mut DiagnosticBuilder<'a>, kind: IncDecRecovery, (pre_span, post_span): (Span, Span), - ) -> PResult<'a, P> { + ) { err.multipart_suggestion( &format!("use `{}= 1` instead", kind.op.chr()), vec![ @@ -1299,16 +1316,15 @@ fn prefix_inc_dec_suggest( ], Applicability::MachineApplicable, ); - Err(err) } fn postfix_inc_dec_suggest( &mut self, base_src: String, - mut err: DiagnosticBuilder<'a>, + err: &mut DiagnosticBuilder<'a>, kind: IncDecRecovery, (pre_span, post_span): (Span, Span), - ) -> PResult<'a, P> { + ) { err.multipart_suggestion( &format!("use `{}= 1` instead", kind.op.chr()), vec![ @@ -1317,21 +1333,31 @@ fn postfix_inc_dec_suggest( ], Applicability::MachineApplicable, ); - Err(err) } fn inc_dec_standalone_recovery( &mut self, - mut err: DiagnosticBuilder<'a>, + err: &mut DiagnosticBuilder<'a>, kind: IncDecRecovery, (pre_span, post_span): (Span, Span), - ) -> PResult<'a, P> { + maybe_not_standalone: bool, + ) { + let msg = if maybe_not_standalone { + "or, if you don't need to use it as an expression, change it to this".to_owned() + } else { + format!("use `{}= 1` instead", kind.op.chr()) + }; + let applicability = if maybe_not_standalone { + // FIXME: Unspecified isn't right, but it's the least wrong option + Applicability::Unspecified + } else { + Applicability::MachineApplicable + }; err.multipart_suggestion( - &format!("use `{}= 1` instead", kind.op.chr()), + &msg, vec![(pre_span, String::new()), (post_span, format!(" {}= 1", kind.op.chr()))], - Applicability::MachineApplicable, + applicability, ); - Err(err) } /// Tries to recover from associated item paths like `[T]::AssocItem` / `(T, U)::AssocItem`. diff --git a/compiler/rustc_parse/src/parser/expr.rs b/compiler/rustc_parse/src/parser/expr.rs index 34ccd167e4e..c9864fb9fa3 100644 --- a/compiler/rustc_parse/src/parser/expr.rs +++ b/compiler/rustc_parse/src/parser/expr.rs @@ -273,9 +273,7 @@ pub(super) fn parse_assoc_expr_with( let op_span = self.prev_token.span.to(self.token.span); // Eat the second `+` self.bump(); - // TODO: implement - let start_is_semi = false; - lhs = self.maybe_recover_from_postfix_increment(lhs, op_span, start_is_semi)?; + lhs = self.maybe_recover_from_postfix_increment(lhs, op_span)?; continue; } diff --git a/src/test/ui/parser/increment-autofix.stderr b/src/test/ui/parser/increment-autofix.stderr index 46ab48f3684..e5386c7bdba 100644 --- a/src/test/ui/parser/increment-autofix.stderr +++ b/src/test/ui/parser/increment-autofix.stderr @@ -8,6 +8,11 @@ help: use `+= 1` instead | LL | { let tmp = i; i += 1; tmp }; | +++++++++++ ~~~~~~~~~~~~~~~ +help: or, if you don't need to use it as an expression, change it to this + | +LL - i++; +LL + i += 1; + | error: Rust has no postfix increment operator --> $DIR/increment-autofix.rs:11:12 @@ -19,6 +24,11 @@ help: use `+= 1` instead | LL | while { let tmp = i; i += 1; tmp } < 5 { | +++++++++++ ~~~~~~~~~~~~~~~ +help: or, if you don't need to use it as an expression, change it to this + | +LL - while i++ < 5 { +LL + while i += 1 < 5 { + | error: Rust has no prefix increment operator --> $DIR/increment-autofix.rs:19:5 diff --git a/src/test/ui/parser/increment-notfixed.stderr b/src/test/ui/parser/increment-notfixed.stderr index 3110e242712..43586c4c25e 100644 --- a/src/test/ui/parser/increment-notfixed.stderr +++ b/src/test/ui/parser/increment-notfixed.stderr @@ -8,6 +8,11 @@ help: use `+= 1` instead | LL | { let tmp = foo.bar.qux; foo.bar.qux += 1; tmp }; | +++++++++++ ~~~~~~~~~~~~~~~~~~~~~~~~~ +help: or, if you don't need to use it as an expression, change it to this + | +LL - foo.bar.qux++; +LL + foo.bar.qux += 1; + | error: Rust has no prefix increment operator --> $DIR/increment-notfixed.rs:18:5