From a183ac6f90dc43a550a8afa5c01fdc797cf3d1d4 Mon Sep 17 00:00:00 2001
From: Zachary Mayhew <mayhew.zachary2003@gmail.com>
Date: Thu, 4 May 2023 23:31:04 -0400
Subject: [PATCH] add hint for =< as <=

---
 compiler/rustc_parse/src/parser/expr.rs   | 13 ++++++++-
 tests/ui/parser/eq-less-to-less-eq.rs     | 33 ++++++++++++++++++++++
 tests/ui/parser/eq-less-to-less-eq.stderr | 34 +++++++++++++++++++++++
 3 files changed, 79 insertions(+), 1 deletion(-)
 create mode 100644 tests/ui/parser/eq-less-to-less-eq.rs
 create mode 100644 tests/ui/parser/eq-less-to-less-eq.stderr

diff --git a/compiler/rustc_parse/src/parser/expr.rs b/compiler/rustc_parse/src/parser/expr.rs
index f58f8919e5c..dd1b0ddc025 100644
--- a/compiler/rustc_parse/src/parser/expr.rs
+++ b/compiler/rustc_parse/src/parser/expr.rs
@@ -1448,8 +1448,19 @@ impl<'a> Parser<'a> {
     }
 
     fn parse_expr_path_start(&mut self) -> PResult<'a, P<Expr>> {
+        let maybe_eq_tok = self.prev_token.clone();
         let (qself, path) = if self.eat_lt() {
-            let (qself, path) = self.parse_qpath(PathStyle::Expr)?;
+            let lt_span = self.prev_token.span;
+            let (qself, path) = self.parse_qpath(PathStyle::Expr).map_err(|mut err| {
+                // Suggests using '<=' if there is an error parsing qpath when the previous token
+                // is an '=' token. Only emits suggestion if the '<' token and '=' token are
+                // directly adjacent (i.e. '=<')
+                if maybe_eq_tok.kind == TokenKind::Eq && maybe_eq_tok.span.hi() == lt_span.lo() {
+                    let eq_lt = maybe_eq_tok.span.to(lt_span);
+                    err.span_suggestion(eq_lt, "did you mean", "<=", Applicability::Unspecified);
+                }
+                err
+            })?;
             (Some(qself), path)
         } else {
             (None, self.parse_path(PathStyle::Expr)?)
diff --git a/tests/ui/parser/eq-less-to-less-eq.rs b/tests/ui/parser/eq-less-to-less-eq.rs
new file mode 100644
index 00000000000..23c6c59d7a6
--- /dev/null
+++ b/tests/ui/parser/eq-less-to-less-eq.rs
@@ -0,0 +1,33 @@
+fn foo() {
+    let a = 0;
+    let b = 4;
+    if a =< b { //~ERROR
+        println!("yay!");
+    }
+}
+
+fn bar() {
+    let a = 0;
+    let b = 4;
+    if a = <b { //~ERROR
+        println!("yay!");
+    }
+}
+
+fn baz() {
+    let a = 0;
+    let b = 4;
+    if a = < b { //~ERROR
+        println!("yay!");
+    }
+}
+
+fn qux() {
+    let a = 0;
+    let b = 4;
+    if a =< i32>::abs(-4) { //~ERROR: mismatched types
+        println!("yay!");
+    }
+}
+
+fn main() {}
diff --git a/tests/ui/parser/eq-less-to-less-eq.stderr b/tests/ui/parser/eq-less-to-less-eq.stderr
new file mode 100644
index 00000000000..4717d8287ff
--- /dev/null
+++ b/tests/ui/parser/eq-less-to-less-eq.stderr
@@ -0,0 +1,34 @@
+error: expected one of `!`, `(`, `+`, `::`, `<`, `>`, or `as`, found `{`
+  --> $DIR/eq-less-to-less-eq.rs:4:15
+   |
+LL |     if a =< b {
+   |          --   ^ expected one of 7 possible tokens
+   |          |
+   |          help: did you mean: `<=`
+
+error: expected one of `!`, `(`, `+`, `::`, `<`, `>`, or `as`, found `{`
+  --> $DIR/eq-less-to-less-eq.rs:12:15
+   |
+LL |     if a = <b {
+   |               ^ expected one of 7 possible tokens
+
+error: expected one of `!`, `(`, `+`, `::`, `<`, `>`, or `as`, found `{`
+  --> $DIR/eq-less-to-less-eq.rs:20:16
+   |
+LL |     if a = < b {
+   |                ^ expected one of 7 possible tokens
+
+error[E0308]: mismatched types
+  --> $DIR/eq-less-to-less-eq.rs:28:8
+   |
+LL |     if a =< i32>::abs(-4) {
+   |        ^^^^^^^^^^^^^^^^^^ expected `bool`, found `()`
+   |
+help: you might have meant to compare for equality
+   |
+LL |     if a ==< i32>::abs(-4) {
+   |           +
+
+error: aborting due to 4 previous errors
+
+For more information about this error, try `rustc --explain E0308`.