From ba843aecd9dcde3fec4872125bac04d0a20125ac Mon Sep 17 00:00:00 2001
From: clubby789 <jamie@hill-daniel.co.uk>
Date: Fri, 27 Oct 2023 20:12:45 +0000
Subject: [PATCH] Recover from missing param list in function definitions

---
 compiler/rustc_parse/messages.ftl                  |  3 +++
 compiler/rustc_parse/src/errors.rs                 |  8 ++++++++
 compiler/rustc_parse/src/parser/item.rs            | 13 +++++++++++++
 tests/ui/mismatched_types/recovered-block.rs       |  6 ------
 tests/ui/mismatched_types/recovered-block.stderr   |  8 +-------
 .../issues/issue-108109-fn-missing-params.fixed    |  9 +++++++++
 .../issues/issue-108109-fn-missing-params.rs       |  9 +++++++++
 .../issues/issue-108109-fn-missing-params.stderr   | 14 ++++++++++++++
 8 files changed, 57 insertions(+), 13 deletions(-)
 create mode 100644 tests/ui/parser/issues/issue-108109-fn-missing-params.fixed
 create mode 100644 tests/ui/parser/issues/issue-108109-fn-missing-params.rs
 create mode 100644 tests/ui/parser/issues/issue-108109-fn-missing-params.stderr

diff --git a/compiler/rustc_parse/messages.ftl b/compiler/rustc_parse/messages.ftl
index e0778f72bfe6e..6e0d44bd00e42 100644
--- a/compiler/rustc_parse/messages.ftl
+++ b/compiler/rustc_parse/messages.ftl
@@ -523,6 +523,9 @@ parse_missing_fn_for_function_definition = missing `fn` for function definition
 parse_missing_fn_for_method_definition = missing `fn` for method definition
     .suggestion = add `fn` here to parse `{$ident}` as a public method
 
+parse_missing_fn_params = missing parameters for function definition
+    .suggestion = add a parameter list
+
 parse_missing_for_in_trait_impl = missing `for` in a trait impl
     .suggestion = add `for` here
 
diff --git a/compiler/rustc_parse/src/errors.rs b/compiler/rustc_parse/src/errors.rs
index aeb4fd0a304aa..f22d70ec809f8 100644
--- a/compiler/rustc_parse/src/errors.rs
+++ b/compiler/rustc_parse/src/errors.rs
@@ -1543,6 +1543,14 @@ pub(crate) enum AmbiguousMissingKwForItemSub {
     HelpMacro,
 }
 
+#[derive(Diagnostic)]
+#[diag(parse_missing_fn_params)]
+pub(crate) struct MissingFnParams {
+    #[primary_span]
+    #[suggestion(code = "()", applicability = "machine-applicable", style = "short")]
+    pub span: Span,
+}
+
 #[derive(Diagnostic)]
 #[diag(parse_missing_trait_in_trait_impl)]
 pub(crate) struct MissingTraitInTraitImpl {
diff --git a/compiler/rustc_parse/src/parser/item.rs b/compiler/rustc_parse/src/parser/item.rs
index 982f601c0d5a2..8340dfe2de8f0 100644
--- a/compiler/rustc_parse/src/parser/item.rs
+++ b/compiler/rustc_parse/src/parser/item.rs
@@ -2492,6 +2492,19 @@ impl<'a> Parser<'a> {
     pub(super) fn parse_fn_params(&mut self, req_name: ReqName) -> PResult<'a, ThinVec<Param>> {
         let mut first_param = true;
         // Parse the arguments, starting out with `self` being allowed...
+        if self.token.kind != TokenKind::OpenDelim(Delimiter::Parenthesis) {
+            // removed syntax, handled elsewhere
+            if self.token.kind != TokenKind::Tilde
+            // might be typo'd trait impl, handled elsewhere
+            && !self.token.is_keyword(kw::For)
+            {
+                // recover from missing argument list, e.g. `fn main -> () {}`
+                self.sess.emit_err(errors::MissingFnParams {
+                    span: self.prev_token.span.shrink_to_hi(),
+                });
+                return Ok(ThinVec::new());
+            }
+        }
         let (mut params, _) = self.parse_paren_comma_seq(|p| {
             p.recover_diff_marker();
             let param = p.parse_param_general(req_name, first_param).or_else(|mut e| {
diff --git a/tests/ui/mismatched_types/recovered-block.rs b/tests/ui/mismatched_types/recovered-block.rs
index b230b47d35d37..a91bbe7083bc2 100644
--- a/tests/ui/mismatched_types/recovered-block.rs
+++ b/tests/ui/mismatched_types/recovered-block.rs
@@ -12,10 +12,4 @@ pub fn foo() -> Foo {
 }
 //~^^ ERROR missing `struct` for struct definition
 
-pub fn bar() -> Foo {
-    fn
-    Foo { text: "".to_string() }
-}
-//~^^ ERROR expected one of `(` or `<`, found `{`
-
 fn main() {}
diff --git a/tests/ui/mismatched_types/recovered-block.stderr b/tests/ui/mismatched_types/recovered-block.stderr
index f275321abe5eb..88d625456564f 100644
--- a/tests/ui/mismatched_types/recovered-block.stderr
+++ b/tests/ui/mismatched_types/recovered-block.stderr
@@ -9,11 +9,5 @@ help: add `struct` here to parse `Foo` as a public struct
 LL |     pub struct Foo { text }
    |         ++++++
 
-error: expected one of `(` or `<`, found `{`
-  --> $DIR/recovered-block.rs:17:9
-   |
-LL |     Foo { text: "".to_string() }
-   |         ^ expected one of `(` or `<`
-
-error: aborting due to 2 previous errors
+error: aborting due to previous error
 
diff --git a/tests/ui/parser/issues/issue-108109-fn-missing-params.fixed b/tests/ui/parser/issues/issue-108109-fn-missing-params.fixed
new file mode 100644
index 0000000000000..b819aa810cb77
--- /dev/null
+++ b/tests/ui/parser/issues/issue-108109-fn-missing-params.fixed
@@ -0,0 +1,9 @@
+// run-rustfix
+
+pub fn missing() -> () {}
+//~^ ERROR missing parameters for function definition
+
+pub fn missing2() {}
+//~^ ERROR missing parameters for function definition
+
+fn main() {}
diff --git a/tests/ui/parser/issues/issue-108109-fn-missing-params.rs b/tests/ui/parser/issues/issue-108109-fn-missing-params.rs
new file mode 100644
index 0000000000000..01efe728081f3
--- /dev/null
+++ b/tests/ui/parser/issues/issue-108109-fn-missing-params.rs
@@ -0,0 +1,9 @@
+// run-rustfix
+
+pub fn missing -> () {}
+//~^ ERROR missing parameters for function definition
+
+pub fn missing2 {}
+//~^ ERROR missing parameters for function definition
+
+fn main() {}
diff --git a/tests/ui/parser/issues/issue-108109-fn-missing-params.stderr b/tests/ui/parser/issues/issue-108109-fn-missing-params.stderr
new file mode 100644
index 0000000000000..86d3449cc33b6
--- /dev/null
+++ b/tests/ui/parser/issues/issue-108109-fn-missing-params.stderr
@@ -0,0 +1,14 @@
+error: missing parameters for function definition
+  --> $DIR/issue-108109-fn-missing-params.rs:3:15
+   |
+LL | pub fn missing -> () {}
+   |               ^ help: add a parameter list
+
+error: missing parameters for function definition
+  --> $DIR/issue-108109-fn-missing-params.rs:6:16
+   |
+LL | pub fn missing2 {}
+   |                ^ help: add a parameter list
+
+error: aborting due to 2 previous errors
+