From 97cf1c87bd98c13f4de91f7afbc971dba829ac92 Mon Sep 17 00:00:00 2001
From: sjwang05 <63834813+sjwang05@users.noreply.github.com>
Date: Fri, 27 Oct 2023 15:14:55 -0700
Subject: [PATCH] Suggest `=>` --> `>=` in conditions

---
 .../rustc_parse/src/parser/diagnostics.rs     |  20 ++++
 compiler/rustc_parse/src/parser/expr.rs       |  10 ++
 tests/ui/missing/missing-block-hint.stderr    |   4 +
 tests/ui/parser/eq-gt-to-gt-eq.fixed          |  45 ++++++++
 tests/ui/parser/eq-gt-to-gt-eq.rs             |  45 ++++++++
 tests/ui/parser/eq-gt-to-gt-eq.stderr         | 106 ++++++++++++++++++
 6 files changed, 230 insertions(+)
 create mode 100644 tests/ui/parser/eq-gt-to-gt-eq.fixed
 create mode 100644 tests/ui/parser/eq-gt-to-gt-eq.rs
 create mode 100644 tests/ui/parser/eq-gt-to-gt-eq.stderr

diff --git a/compiler/rustc_parse/src/parser/diagnostics.rs b/compiler/rustc_parse/src/parser/diagnostics.rs
index 2a8eb6edd23fd..8803b243aa852 100644
--- a/compiler/rustc_parse/src/parser/diagnostics.rs
+++ b/compiler/rustc_parse/src/parser/diagnostics.rs
@@ -610,6 +610,26 @@ impl<'a> Parser<'a> {
         // FIXME: translation requires list formatting (for `expect`)
         let mut err = self.struct_span_err(self.token.span, msg_exp);
 
+        // Look for usages of '=>' where '>=' was probably intended
+        if self.token == token::FatArrow
+            && expected
+                .iter()
+                .any(|tok| matches!(tok, TokenType::Operator | TokenType::Token(TokenKind::Le)))
+            && !expected.iter().any(|tok| {
+                matches!(
+                    tok,
+                    TokenType::Token(TokenKind::FatArrow) | TokenType::Token(TokenKind::Comma)
+                )
+            })
+        {
+            err.span_suggestion(
+                self.token.span,
+                "you might have meant to write a \"greater than or equal to\" comparison",
+                ">=",
+                Applicability::MaybeIncorrect,
+            );
+        }
+
         if let TokenKind::Ident(symbol, _) = &self.prev_token.kind {
             if ["def", "fun", "func", "function"].contains(&symbol.as_str()) {
                 err.span_suggestion_short(
diff --git a/compiler/rustc_parse/src/parser/expr.rs b/compiler/rustc_parse/src/parser/expr.rs
index 235b28b6e26e2..f6678298e5de1 100644
--- a/compiler/rustc_parse/src/parser/expr.rs
+++ b/compiler/rustc_parse/src/parser/expr.rs
@@ -2432,6 +2432,7 @@ impl<'a> Parser<'a> {
             }
         } else {
             let attrs = self.parse_outer_attributes()?; // For recovery.
+            let maybe_fatarrow = self.token.clone();
             let block = if self.check(&token::OpenDelim(Delimiter::Brace)) {
                 self.parse_block()?
             } else {
@@ -2456,6 +2457,15 @@ impl<'a> Parser<'a> {
                                 "you likely meant to continue parsing the let-chain starting here",
                             );
                         } else {
+                            // Look for usages of '=>' where '>=' might be intended
+                            if maybe_fatarrow.kind == token::FatArrow {
+                                err.span_suggestion(
+                                    maybe_fatarrow.span,
+                                    "you might have meant to write a \"greater than or equal to\" comparison",
+                                    ">=",
+                                    Applicability::MaybeIncorrect,
+                                );
+                            }
                             err.span_note(
                                 cond_span,
                                 "the `if` expression is missing a block after this condition",
diff --git a/tests/ui/missing/missing-block-hint.stderr b/tests/ui/missing/missing-block-hint.stderr
index 16954223a4521..18719289abdc8 100644
--- a/tests/ui/missing/missing-block-hint.stderr
+++ b/tests/ui/missing/missing-block-hint.stderr
@@ -9,6 +9,10 @@ note: the `if` expression is missing a block after this condition
    |
 LL |         if (foo) => {}
    |            ^^^^^
+help: you might have meant to write a "greater than or equal to" comparison
+   |
+LL |         if (foo) >= {}
+   |                  ~~
 
 error: expected `{`, found `bar`
   --> $DIR/missing-block-hint.rs:7:13
diff --git a/tests/ui/parser/eq-gt-to-gt-eq.fixed b/tests/ui/parser/eq-gt-to-gt-eq.fixed
new file mode 100644
index 0000000000000..44cb464fc0c9c
--- /dev/null
+++ b/tests/ui/parser/eq-gt-to-gt-eq.fixed
@@ -0,0 +1,45 @@
+// run-rustfix
+// Check that we try to correct `=>` to `>=` in conditions.
+#![allow(unused)]
+
+fn main() {
+    let a = 0;
+    let b = 1;
+    if a >= b {} //~ERROR
+}
+
+fn foo() {
+    let a = 0;
+    if a >= 1 {} //~ERROR
+}
+
+fn a() {
+    let a = 0;
+    if 1 >= a {} //~ERROR
+}
+
+fn bar() {
+    let a = 0;
+    let b = 1;
+    if a >= b && a != b {} //~ERROR
+}
+
+fn qux() {
+    let a = 0;
+    let b = 1;
+    if a != b && a >= b {} //~ERROR
+}
+
+fn baz() {
+    let a = 0;
+    let b = 1;
+    let _ = a >= b; //~ERROR
+}
+
+fn b() {
+    let a = 0;
+    let b = 1;
+    match a >= b { //~ERROR
+        _ => todo!(),
+    }
+}
diff --git a/tests/ui/parser/eq-gt-to-gt-eq.rs b/tests/ui/parser/eq-gt-to-gt-eq.rs
new file mode 100644
index 0000000000000..dca67c89cc033
--- /dev/null
+++ b/tests/ui/parser/eq-gt-to-gt-eq.rs
@@ -0,0 +1,45 @@
+// run-rustfix
+// Check that we try to correct `=>` to `>=` in conditions.
+#![allow(unused)]
+
+fn main() {
+    let a = 0;
+    let b = 1;
+    if a => b {} //~ERROR
+}
+
+fn foo() {
+    let a = 0;
+    if a => 1 {} //~ERROR
+}
+
+fn a() {
+    let a = 0;
+    if 1 => a {} //~ERROR
+}
+
+fn bar() {
+    let a = 0;
+    let b = 1;
+    if a => b && a != b {} //~ERROR
+}
+
+fn qux() {
+    let a = 0;
+    let b = 1;
+    if a != b && a => b {} //~ERROR
+}
+
+fn baz() {
+    let a = 0;
+    let b = 1;
+    let _ = a => b; //~ERROR
+}
+
+fn b() {
+    let a = 0;
+    let b = 1;
+    match a => b { //~ERROR
+        _ => todo!(),
+    }
+}
diff --git a/tests/ui/parser/eq-gt-to-gt-eq.stderr b/tests/ui/parser/eq-gt-to-gt-eq.stderr
new file mode 100644
index 0000000000000..73f465f7b9b28
--- /dev/null
+++ b/tests/ui/parser/eq-gt-to-gt-eq.stderr
@@ -0,0 +1,106 @@
+error: expected `{`, found `=>`
+  --> $DIR/eq-gt-to-gt-eq.rs:8:10
+   |
+LL |     if a => b {}
+   |          ^^ expected `{`
+   |
+note: the `if` expression is missing a block after this condition
+  --> $DIR/eq-gt-to-gt-eq.rs:8:8
+   |
+LL |     if a => b {}
+   |        ^
+help: you might have meant to write a "greater than or equal to" comparison
+   |
+LL |     if a >= b {}
+   |          ~~
+
+error: expected `{`, found `=>`
+  --> $DIR/eq-gt-to-gt-eq.rs:13:10
+   |
+LL |     if a => 1 {}
+   |          ^^ expected `{`
+   |
+note: the `if` expression is missing a block after this condition
+  --> $DIR/eq-gt-to-gt-eq.rs:13:8
+   |
+LL |     if a => 1 {}
+   |        ^
+help: you might have meant to write a "greater than or equal to" comparison
+   |
+LL |     if a >= 1 {}
+   |          ~~
+
+error: expected `{`, found `=>`
+  --> $DIR/eq-gt-to-gt-eq.rs:18:10
+   |
+LL |     if 1 => a {}
+   |          ^^ expected `{`
+   |
+note: the `if` expression is missing a block after this condition
+  --> $DIR/eq-gt-to-gt-eq.rs:18:8
+   |
+LL |     if 1 => a {}
+   |        ^
+help: you might have meant to write a "greater than or equal to" comparison
+   |
+LL |     if 1 >= a {}
+   |          ~~
+
+error: expected `{`, found `=>`
+  --> $DIR/eq-gt-to-gt-eq.rs:24:10
+   |
+LL |     if a => b && a != b {}
+   |          ^^ expected `{`
+   |
+note: the `if` expression is missing a block after this condition
+  --> $DIR/eq-gt-to-gt-eq.rs:24:8
+   |
+LL |     if a => b && a != b {}
+   |        ^
+help: you might have meant to write a "greater than or equal to" comparison
+   |
+LL |     if a >= b && a != b {}
+   |          ~~
+
+error: expected `{`, found `=>`
+  --> $DIR/eq-gt-to-gt-eq.rs:30:20
+   |
+LL |     if a != b && a => b {}
+   |                    ^^ expected `{`
+   |
+note: the `if` expression is missing a block after this condition
+  --> $DIR/eq-gt-to-gt-eq.rs:30:8
+   |
+LL |     if a != b && a => b {}
+   |        ^^^^^^^^^^^
+help: you might have meant to write a "greater than or equal to" comparison
+   |
+LL |     if a != b && a >= b {}
+   |                    ~~
+
+error: expected one of `!`, `.`, `::`, `;`, `?`, `else`, `{`, or an operator, found `=>`
+  --> $DIR/eq-gt-to-gt-eq.rs:36:15
+   |
+LL |     let _ = a => b;
+   |               ^^ expected one of 8 possible tokens
+   |
+help: you might have meant to write a "greater than or equal to" comparison
+   |
+LL |     let _ = a >= b;
+   |               ~~
+
+error: expected one of `!`, `.`, `::`, `?`, `{`, or an operator, found `=>`
+  --> $DIR/eq-gt-to-gt-eq.rs:42:13
+   |
+LL |     match a => b {
+   |     -----   ^^ expected one of `!`, `.`, `::`, `?`, `{`, or an operator
+   |     |
+   |     while parsing this `match` expression
+   |
+help: you might have meant to write a "greater than or equal to" comparison
+   |
+LL |     match a >= b {
+   |             ~~
+
+error: aborting due to 7 previous errors
+