From 6d85bb953521039350a915a73033a2e46e1a8665 Mon Sep 17 00:00:00 2001
From: Takayuki Maeda <takoyaki0316@gmail.com>
Date: Wed, 10 Aug 2022 02:29:28 +0900
Subject: [PATCH] suggest a missing semicolon before an array

---
 compiler/rustc_parse/src/parser/expr.rs       | 42 +++++++++++++++++++
 ...-suggest-suggest-semicolon-before-array.rs |  8 ++++
 ...gest-suggest-semicolon-before-array.stderr | 10 +++++
 ...ggest-suggest-semicolon-before-array.fixed | 11 +++++
 .../suggest-suggest-semicolon-before-array.rs | 11 +++++
 ...gest-suggest-semicolon-before-array.stderr | 13 ++++++
 6 files changed, 95 insertions(+)
 create mode 100644 src/test/ui/parser/do-not-suggest-suggest-semicolon-before-array.rs
 create mode 100644 src/test/ui/parser/do-not-suggest-suggest-semicolon-before-array.stderr
 create mode 100644 src/test/ui/parser/suggest-suggest-semicolon-before-array.fixed
 create mode 100644 src/test/ui/parser/suggest-suggest-semicolon-before-array.rs
 create mode 100644 src/test/ui/parser/suggest-suggest-semicolon-before-array.stderr

diff --git a/compiler/rustc_parse/src/parser/expr.rs b/compiler/rustc_parse/src/parser/expr.rs
index e473f4d30cf..b8bd960a5b3 100644
--- a/compiler/rustc_parse/src/parser/expr.rs
+++ b/compiler/rustc_parse/src/parser/expr.rs
@@ -1258,8 +1258,11 @@ fn maybe_recover_struct_lit_bad_delims(
 
     /// Parse an indexing expression `expr[...]`.
     fn parse_index_expr(&mut self, lo: Span, base: P<Expr>) -> PResult<'a, P<Expr>> {
+        let prev_span = self.prev_token.span;
+        let open_delim_span = self.token.span;
         self.bump(); // `[`
         let index = self.parse_expr()?;
+        self.suggest_missing_semicolon_before_array(prev_span, open_delim_span)?;
         self.expect(&token::CloseDelim(Delimiter::Bracket))?;
         Ok(self.mk_expr(lo.to(self.prev_token.span), self.mk_index(base, index), AttrVec::new()))
     }
@@ -2056,6 +2059,45 @@ fn maybe_suggest_brackets_instead_of_braces(
         }
     }
 
+    fn suggest_missing_semicolon_before_array(
+        &self,
+        prev_span: Span,
+        open_delim_span: Span,
+    ) -> PResult<'a, ()> {
+        if self.token.kind == token::Comma {
+            let mut snapshot = self.create_snapshot_for_diagnostic();
+            snapshot.bump();
+            match snapshot.parse_seq_to_before_end(
+                &token::CloseDelim(Delimiter::Bracket),
+                SeqSep::trailing_allowed(token::Comma),
+                |p| p.parse_expr(),
+            ) {
+                Ok(_)
+                    // When the close delim is `)`, `token.kind` is expected to be `token::CloseDelim(Delimiter::Parenthesis)`,
+                    // but the actual `token.kind` is `token::CloseDelim(Delimiter::Bracket)`.
+                    // This is because the `token.kind` of the close delim is treated as the same as
+                    // that of the open delim in `TokenTreesReader::parse_token_tree`, even if the delimiters of them are different.
+                    // Therefore, `token.kind` should not be compared here.
+                    if snapshot
+                        .span_to_snippet(snapshot.token.span)
+                        .map_or(false, |snippet| snippet == "]") =>
+                {
+                    let mut err = self.struct_span_err(open_delim_span, "expected `;`, found `[`");
+                    err.span_suggestion_verbose(
+                        prev_span.shrink_to_hi(),
+                        "consider adding `;` here",
+                        ';',
+                        Applicability::MaybeIncorrect,
+                    );
+                    return Err(err);
+                }
+                Ok(_) => (),
+                Err(err) => err.cancel(),
+            }
+        }
+        Ok(())
+    }
+
     /// Parses a block or unsafe block.
     pub(super) fn parse_block_expr(
         &mut self,
diff --git a/src/test/ui/parser/do-not-suggest-suggest-semicolon-before-array.rs b/src/test/ui/parser/do-not-suggest-suggest-semicolon-before-array.rs
new file mode 100644
index 00000000000..7ebf3f6b0d8
--- /dev/null
+++ b/src/test/ui/parser/do-not-suggest-suggest-semicolon-before-array.rs
@@ -0,0 +1,8 @@
+fn foo() {}
+
+fn bar() -> [u8; 2] {
+    foo()
+    [1, 3) //~ ERROR expected one of `.`, `?`, `]`, or an operator, found `,`
+}
+
+fn main() {}
diff --git a/src/test/ui/parser/do-not-suggest-suggest-semicolon-before-array.stderr b/src/test/ui/parser/do-not-suggest-suggest-semicolon-before-array.stderr
new file mode 100644
index 00000000000..d6e8db80329
--- /dev/null
+++ b/src/test/ui/parser/do-not-suggest-suggest-semicolon-before-array.stderr
@@ -0,0 +1,10 @@
+error: expected one of `.`, `?`, `]`, or an operator, found `,`
+  --> $DIR/do-not-suggest-suggest-semicolon-before-array.rs:5:5
+   |
+LL |     [1, 3)
+   |     ^ ^ help: `]` may belong here
+   |     |
+   |     unclosed delimiter
+
+error: aborting due to previous error
+
diff --git a/src/test/ui/parser/suggest-suggest-semicolon-before-array.fixed b/src/test/ui/parser/suggest-suggest-semicolon-before-array.fixed
new file mode 100644
index 00000000000..a06b58b2740
--- /dev/null
+++ b/src/test/ui/parser/suggest-suggest-semicolon-before-array.fixed
@@ -0,0 +1,11 @@
+// run-rustfix
+#![allow(dead_code)]
+
+fn foo() {}
+
+fn bar() -> [u8; 2] {
+    foo();
+    [1, 3] //~ ERROR expected `;`, found `[`
+}
+
+fn main() {}
diff --git a/src/test/ui/parser/suggest-suggest-semicolon-before-array.rs b/src/test/ui/parser/suggest-suggest-semicolon-before-array.rs
new file mode 100644
index 00000000000..f601ca2aef5
--- /dev/null
+++ b/src/test/ui/parser/suggest-suggest-semicolon-before-array.rs
@@ -0,0 +1,11 @@
+// run-rustfix
+#![allow(dead_code)]
+
+fn foo() {}
+
+fn bar() -> [u8; 2] {
+    foo()
+    [1, 3] //~ ERROR expected `;`, found `[`
+}
+
+fn main() {}
diff --git a/src/test/ui/parser/suggest-suggest-semicolon-before-array.stderr b/src/test/ui/parser/suggest-suggest-semicolon-before-array.stderr
new file mode 100644
index 00000000000..bf86b43554d
--- /dev/null
+++ b/src/test/ui/parser/suggest-suggest-semicolon-before-array.stderr
@@ -0,0 +1,13 @@
+error: expected `;`, found `[`
+  --> $DIR/suggest-suggest-semicolon-before-array.rs:8:5
+   |
+LL |     [1, 3]
+   |     ^
+   |
+help: consider adding `;` here
+   |
+LL |     foo();
+   |          +
+
+error: aborting due to previous error
+