about summary refs log tree commit diff
diff options
context:
space:
mode:
authorclubby789 <jamie@hill-daniel.co.uk>2023-10-27 19:51:51 +0000
committerclubby789 <jamie@hill-daniel.co.uk>2023-11-01 15:33:46 +0000
commit904aceec7d9595d49b1ce6e9e8a04f64f6a814fd (patch)
tree7c0e33b4bc2216337c101bd7b037fec7d955ac9d
parent9d6d5d48948945debca5a693f6030246f7bb2baf (diff)
downloadrust-904aceec7d9595d49b1ce6e9e8a04f64f6a814fd.tar.gz
rust-904aceec7d9595d49b1ce6e9e8a04f64f6a814fd.zip
Give a better diagnostic for missing parens in Fn* bounds
-rw-r--r--compiler/rustc_parse/messages.ftl3
-rw-r--r--compiler/rustc_parse/src/errors.rs28
-rw-r--r--compiler/rustc_parse/src/parser/item.rs12
-rw-r--r--compiler/rustc_span/src/symbol.rs3
-rw-r--r--tests/ui/parser/issues/issue-108109-fn-trait-missing-paren.fixed8
-rw-r--r--tests/ui/parser/issues/issue-108109-fn-trait-missing-paren.rs8
-rw-r--r--tests/ui/parser/issues/issue-108109-fn-trait-missing-paren.stderr11
7 files changed, 73 insertions, 0 deletions
diff --git a/compiler/rustc_parse/messages.ftl b/compiler/rustc_parse/messages.ftl
index e0778f72bfe..8036c68f618 100644
--- a/compiler/rustc_parse/messages.ftl
+++ b/compiler/rustc_parse/messages.ftl
@@ -270,6 +270,9 @@ parse_fn_ptr_with_generics = function pointer types may not have generic paramet
         *[false] a
     } `for` parameter list
 
+parse_fn_trait_missing_paren = `Fn` bounds require arguments in parentheses
+    .add_paren = add the missing parentheses
+
 parse_forgot_paren = perhaps you forgot parentheses?
 
 parse_found_expr_would_be_stmt = expected expression, found `{$token}`
diff --git a/compiler/rustc_parse/src/errors.rs b/compiler/rustc_parse/src/errors.rs
index aeb4fd0a304..311d573d1fc 100644
--- a/compiler/rustc_parse/src/errors.rs
+++ b/compiler/rustc_parse/src/errors.rs
@@ -1370,6 +1370,34 @@ pub(crate) struct FnPtrWithGenericsSugg {
     pub for_param_list_exists: bool,
 }
 
+pub(crate) struct FnTraitMissingParen {
+    pub span: Span,
+    pub machine_applicable: bool,
+}
+
+impl AddToDiagnostic for FnTraitMissingParen {
+    fn add_to_diagnostic_with<F>(self, diag: &mut rustc_errors::Diagnostic, _: F)
+    where
+        F: Fn(
+            &mut rustc_errors::Diagnostic,
+            rustc_errors::SubdiagnosticMessage,
+        ) -> rustc_errors::SubdiagnosticMessage,
+    {
+        diag.span_label(self.span, crate::fluent_generated::parse_fn_trait_missing_paren);
+        let applicability = if self.machine_applicable {
+            Applicability::MachineApplicable
+        } else {
+            Applicability::MaybeIncorrect
+        };
+        diag.span_suggestion_short(
+            self.span.shrink_to_hi(),
+            crate::fluent_generated::parse_add_paren,
+            "()",
+            applicability,
+        );
+    }
+}
+
 #[derive(Diagnostic)]
 #[diag(parse_unexpected_if_with_if)]
 pub(crate) struct UnexpectedIfWithIf(
diff --git a/compiler/rustc_parse/src/parser/item.rs b/compiler/rustc_parse/src/parser/item.rs
index 982f601c0d5..aa06fd9df51 100644
--- a/compiler/rustc_parse/src/parser/item.rs
+++ b/compiler/rustc_parse/src/parser/item.rs
@@ -2278,6 +2278,18 @@ impl<'a> Parser<'a> {
                     err.span_label(ident.span, "while parsing this `fn`");
                     err.emit();
                 } else {
+                    // check for typo'd Fn* trait bounds such as
+                    // fn foo<F>() where F: FnOnce -> () {}
+                    if self.token.kind == token::RArrow {
+                        let machine_applicable = [sym::FnOnce, sym::FnMut, sym::Fn]
+                            .into_iter()
+                            .any(|s| self.prev_token.is_ident_named(s));
+
+                        err.subdiagnostic(errors::FnTraitMissingParen {
+                            span: self.prev_token.span,
+                            machine_applicable,
+                        });
+                    }
                     return Err(err);
                 }
             }
diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs
index 88d9dab2ba5..8b33c1b825a 100644
--- a/compiler/rustc_span/src/symbol.rs
+++ b/compiler/rustc_span/src/symbol.rs
@@ -193,6 +193,9 @@ symbols! {
         Error,
         File,
         FileType,
+        Fn,
+        FnMut,
+        FnOnce,
         FormatSpec,
         Formatter,
         From,
diff --git a/tests/ui/parser/issues/issue-108109-fn-trait-missing-paren.fixed b/tests/ui/parser/issues/issue-108109-fn-trait-missing-paren.fixed
new file mode 100644
index 00000000000..eaae288864a
--- /dev/null
+++ b/tests/ui/parser/issues/issue-108109-fn-trait-missing-paren.fixed
@@ -0,0 +1,8 @@
+// run-rustfix
+
+pub fn func<F>() where F: FnOnce() -> () {}
+//~^ ERROR expected one of
+//~| NOTE expected one of
+//~| NOTE `Fn` bounds require arguments in parentheses
+
+fn main() {}
diff --git a/tests/ui/parser/issues/issue-108109-fn-trait-missing-paren.rs b/tests/ui/parser/issues/issue-108109-fn-trait-missing-paren.rs
new file mode 100644
index 00000000000..ea5c71150e8
--- /dev/null
+++ b/tests/ui/parser/issues/issue-108109-fn-trait-missing-paren.rs
@@ -0,0 +1,8 @@
+// run-rustfix
+
+pub fn func<F>() where F: FnOnce -> () {}
+//~^ ERROR expected one of
+//~| NOTE expected one of
+//~| NOTE `Fn` bounds require arguments in parentheses
+
+fn main() {}
diff --git a/tests/ui/parser/issues/issue-108109-fn-trait-missing-paren.stderr b/tests/ui/parser/issues/issue-108109-fn-trait-missing-paren.stderr
new file mode 100644
index 00000000000..7cda667570d
--- /dev/null
+++ b/tests/ui/parser/issues/issue-108109-fn-trait-missing-paren.stderr
@@ -0,0 +1,11 @@
+error: expected one of `(`, `+`, `,`, `::`, `<`, or `{`, found `->`
+  --> $DIR/issue-108109-fn-trait-missing-paren.rs:3:34
+   |
+LL | pub fn func<F>() where F: FnOnce -> () {}
+   |                           -------^^ expected one of `(`, `+`, `,`, `::`, `<`, or `{`
+   |                           |     |
+   |                           |     help: try adding parentheses
+   |                           `Fn` bounds require arguments in parentheses
+
+error: aborting due to previous error
+