about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--compiler/rustc_error_messages/locales/en-US/parse.ftl3
-rw-r--r--compiler/rustc_parse/src/errors.rs8
-rw-r--r--compiler/rustc_parse/src/parser/item.rs20
-rw-r--r--src/test/ui/parser/issue-105366.fixed12
-rw-r--r--src/test/ui/parser/issue-105366.rs12
-rw-r--r--src/test/ui/parser/issue-105366.stderr13
6 files changed, 66 insertions, 2 deletions
diff --git a/compiler/rustc_error_messages/locales/en-US/parse.ftl b/compiler/rustc_error_messages/locales/en-US/parse.ftl
index 114b7ec1628..b53550e5fd5 100644
--- a/compiler/rustc_error_messages/locales/en-US/parse.ftl
+++ b/compiler/rustc_error_messages/locales/en-US/parse.ftl
@@ -362,3 +362,6 @@ parse_fn_ptr_with_generics = function pointer types may not have generic paramet
 
 parse_invalid_identifier_with_leading_number = expected identifier, found number literal
     .label = identifiers cannot start with a number
+
+parse_maybe_fn_typo_with_impl = you might have meant to write `impl` instead of `fn`
+    .suggestion = replace `fn` with `impl` here
diff --git a/compiler/rustc_parse/src/errors.rs b/compiler/rustc_parse/src/errors.rs
index 9875cde4a05..18a0bee9c2e 100644
--- a/compiler/rustc_parse/src/errors.rs
+++ b/compiler/rustc_parse/src/errors.rs
@@ -1221,3 +1221,11 @@ pub(crate) struct UnexpectedIfWithIf(
     #[suggestion(applicability = "machine-applicable", code = " ", style = "verbose")]
     pub Span,
 );
+
+#[derive(Diagnostic)]
+#[diag(parse_maybe_fn_typo_with_impl)]
+pub(crate) struct FnTypoWithImpl {
+    #[primary_span]
+    #[suggestion(applicability = "maybe-incorrect", code = "impl", style = "verbose")]
+    pub fn_span: Span,
+}
diff --git a/compiler/rustc_parse/src/parser/item.rs b/compiler/rustc_parse/src/parser/item.rs
index beb9d55d454..7c2d01509de 100644
--- a/compiler/rustc_parse/src/parser/item.rs
+++ b/compiler/rustc_parse/src/parser/item.rs
@@ -3,6 +3,7 @@ use crate::errors::{DocCommentDoesNotDocumentAnything, UseEmptyBlockNotSemi};
 use super::diagnostics::{dummy_arg, ConsumeClosingDelim};
 use super::ty::{AllowPlus, RecoverQPath, RecoverReturnSign};
 use super::{AttrWrapper, FollowedByType, ForceCollect, Parser, PathStyle, TrailingToken};
+use crate::errors::FnTypoWithImpl;
 use rustc_ast::ast::*;
 use rustc_ast::ptr::P;
 use rustc_ast::token::{self, Delimiter, TokenKind};
@@ -2131,11 +2132,26 @@ impl<'a> Parser<'a> {
         vis: &Visibility,
         case: Case,
     ) -> PResult<'a, (Ident, FnSig, Generics, Option<P<Block>>)> {
+        let fn_span = self.token.span;
         let header = self.parse_fn_front_matter(vis, case)?; // `const ... fn`
         let ident = self.parse_ident()?; // `foo`
         let mut generics = self.parse_generics()?; // `<'a, T, ...>`
-        let decl =
-            self.parse_fn_decl(fn_parse_mode.req_name, AllowPlus::Yes, RecoverReturnSign::Yes)?; // `(p: u8, ...)`
+        let decl = match self.parse_fn_decl(
+            fn_parse_mode.req_name,
+            AllowPlus::Yes,
+            RecoverReturnSign::Yes,
+        ) {
+            Ok(decl) => decl,
+            Err(old_err) => {
+                // If we see `for Ty ...` then user probably meant `impl` item.
+                if self.token.is_keyword(kw::For) {
+                    old_err.cancel();
+                    return Err(self.sess.create_err(FnTypoWithImpl { fn_span }));
+                } else {
+                    return Err(old_err);
+                }
+            }
+        };
         generics.where_clause = self.parse_where_clause()?; // `where T: Ord`
 
         let mut sig_hi = self.prev_token.span;
diff --git a/src/test/ui/parser/issue-105366.fixed b/src/test/ui/parser/issue-105366.fixed
new file mode 100644
index 00000000000..ad26643c327
--- /dev/null
+++ b/src/test/ui/parser/issue-105366.fixed
@@ -0,0 +1,12 @@
+// run-rustfix
+
+struct Foo;
+
+impl From<i32> for Foo {
+    //~^ ERROR you might have meant to write `impl` instead of `fn`
+    fn from(_a: i32) -> Self {
+        Foo
+    }
+}
+
+fn main() {}
diff --git a/src/test/ui/parser/issue-105366.rs b/src/test/ui/parser/issue-105366.rs
new file mode 100644
index 00000000000..311b6a60f1a
--- /dev/null
+++ b/src/test/ui/parser/issue-105366.rs
@@ -0,0 +1,12 @@
+// run-rustfix
+
+struct Foo;
+
+fn From<i32> for Foo {
+    //~^ ERROR you might have meant to write `impl` instead of `fn`
+    fn from(_a: i32) -> Self {
+        Foo
+    }
+}
+
+fn main() {}
diff --git a/src/test/ui/parser/issue-105366.stderr b/src/test/ui/parser/issue-105366.stderr
new file mode 100644
index 00000000000..0a7408e2c17
--- /dev/null
+++ b/src/test/ui/parser/issue-105366.stderr
@@ -0,0 +1,13 @@
+error: you might have meant to write `impl` instead of `fn`
+  --> $DIR/issue-105366.rs:5:1
+   |
+LL | fn From<i32> for Foo {
+   | ^^
+   |
+help: replace `fn` with `impl` here
+   |
+LL | impl From<i32> for Foo {
+   | ~~~~
+
+error: aborting due to previous error
+