+ pub(super) fn maybe_recover_from_prefix_increment(
+ &mut self,
+ operand_expr: P<Expr>,
+ op_span: Span,
+ prev_is_semi: bool,
+ ) -> PResult<'a, P<Expr>> {
+ let kind = IncDecRecovery {
+ standalone: prev_is_semi,
+ op: IncOrDec::Inc,
+ fixity: UnaryFixity::Pre,
+ };
+
+ self.recover_from_inc_dec(operand_expr, kind, op_span)
+ }
+
+ pub(super) fn maybe_recover_from_postfix_increment(
+ &mut self,
+ operand_expr: P<Expr>,
+ op_span: Span,
+ prev_is_semi: bool,
+ ) -> PResult<'a, P<Expr>> {
+ let kind = IncDecRecovery {
+ standalone: prev_is_semi,
+ op: IncOrDec::Inc,
+ fixity: UnaryFixity::Post,
+ };
+
+ self.recover_from_inc_dec(operand_expr, kind, op_span)
+ }
+
+ fn recover_from_inc_dec(
+ &mut self,
+ base: P<Expr>,
+ kind: IncDecRecovery,
+ op_span: Span,
+ ) -> PResult<'a, P<Expr>> {
+ let mut err = self.struct_span_err(
+ op_span,
+ &format!("Rust has no {} {} operator", kind.fixity, kind.op.name()),
+ );
+ err.span_label(op_span, &format!("not a valid {} operator", kind.fixity));
+
+ let help_base_case = |mut err: DiagnosticBuilder<'_>, base| {
+ err.help(&format!("use `{}= 1` instead", kind.op.chr()));
+ err.emit();
+ Ok(base)
+ };
+
+ // (pre, post)
+ let spans = match kind.fixity {
+ UnaryFixity::Pre => (op_span, base.span.shrink_to_hi()),
+ 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),
+ }
+ }
+ }
+
+ fn prefix_inc_dec_suggest(
+ &mut self,
+ base_src: String,
+ mut err: DiagnosticBuilder<'a>,
+ kind: IncDecRecovery,
+ (pre_span, post_span): (Span, Span),
+ ) -> PResult<'a, P<Expr>> {
+ err.multipart_suggestion(
+ &format!("use `{}= 1` instead", kind.op.chr()),
+ vec![
+ (pre_span, "{ ".to_string()),
+ (post_span, format!(" {}= 1; {} }}", kind.op.chr(), base_src)),
+ ],
+ Applicability::MachineApplicable,
+ );
+ Err(err)
+ }
+
+ fn postfix_inc_dec_suggest(
+ &mut self,
+ base_src: String,
+ mut err: DiagnosticBuilder<'a>,
+ kind: IncDecRecovery,
+ (pre_span, post_span): (Span, Span),
+ ) -> PResult<'a, P<Expr>> {
+ err.multipart_suggestion(
+ &format!("use `{}= 1` instead", kind.op.chr()),
+ vec![
+ (pre_span, "{ let tmp = ".to_string()),
+ (post_span, format!("; {} {}= 1; tmp }}", base_src, kind.op.chr())),
+ ],
+ Applicability::MachineApplicable,
+ );
+ Err(err)
+ }
+
+ fn inc_dec_standalone_recovery(
+ &mut self,
+ mut err: DiagnosticBuilder<'a>,
+ kind: IncDecRecovery,
+ (pre_span, post_span): (Span, Span),
+ ) -> PResult<'a, P<Expr>> {
+ err.multipart_suggestion(
+ &format!("use `{}= 1` instead", kind.op.chr()),
+ vec![(pre_span, String::new()), (post_span, format!(" {}= 1", kind.op.chr()))],
+ Applicability::MachineApplicable,
+ );
+ Err(err)
+ }
+