From 476223f7a656b998a21f89c05382bb80980c4a04 Mon Sep 17 00:00:00 2001 From: Baraich Date: Fri, 19 Sep 2025 16:04:29 +0530 Subject: [PATCH 01/10] Fixes #4984 --- compiler-core/src/parse.rs | 117 +++++++++++++++++++++---------------- 1 file changed, 67 insertions(+), 50 deletions(-) diff --git a/compiler-core/src/parse.rs b/compiler-core/src/parse.rs index a67c334a6bc..33cee76a345 100644 --- a/compiler-core/src/parse.rs +++ b/compiler-core/src/parse.rs @@ -2117,59 +2117,76 @@ where )?; let (_, rpar_e) = self.expect_one_following_series(&Token::RightParen, "a function parameter")?; - let return_annotation = self.parse_type_annotation(&Token::RArrow)?; - - let (body_start, body, end, end_position) = match self.maybe_one(&Token::LeftBrace) { - Some((left_brace_start, _)) => { - let some_body = self.parse_statement_seq()?; - let (_, right_brace_end) = self.expect_one(&Token::RightBrace)?; - let end = return_annotation - .as_ref() - .map(|l| l.location().end) - .unwrap_or(rpar_e); - let body = match some_body { - None => vec![Statement::Expression(UntypedExpr::Todo { - kind: TodoKind::EmptyFunction { - function_location: SrcSpan { start, end }, - }, - location: SrcSpan { - start: left_brace_start + 1, - end: right_brace_end, - }, - message: None, - })], - Some((body, _)) => body.to_vec(), - }; - (Some(left_brace_start), body, end, right_brace_end) - } + // Check for TypeScript-style return type annotation (:) instead of arrow (->) + match self.maybe_one(&Token::Colon) { + Some((colon_start, colon_end)) => Err(ParseError { + error: ParseErrorType::UnexpectedToken { + token: Token::Colon, + expected: vec!["->".into()], + hint: Some("Maybe you meant to write return value type annotation?\nReturn type annotations are written using `->`, not `:`".into()), + }, + location: SrcSpan { + start: colon_start, + end: colon_end, + }, + }), + None => { + let return_annotation = self.parse_type_annotation(&Token::RArrow)?; + + let (body_start, body, end, end_position) = match self.maybe_one(&Token::LeftBrace) { + Some((left_brace_start, _)) => { + let some_body = self.parse_statement_seq()?; + let (_, right_brace_end) = self.expect_one(&Token::RightBrace)?; + let end = return_annotation + .as_ref() + .map(|l| l.location().end) + .unwrap_or(rpar_e); + let body = match some_body { + None => vec![Statement::Expression(UntypedExpr::Todo { + kind: TodoKind::EmptyFunction { + function_location: SrcSpan { start, end }, + }, + location: SrcSpan { + start: left_brace_start + 1, + end: right_brace_end, + }, + message: None, + })], + Some((body, _)) => body.to_vec(), + }; - None => (None, vec![], rpar_e, rpar_e), - }; + (Some(left_brace_start), body, end, right_brace_end) + } - Ok(Some(Definition::Function(Function { - documentation, - location: SrcSpan { start, end }, - end_position, - body_start, - publicity: self.publicity(public, attributes.internal)?, - name, - arguments, - body, - return_type: (), - return_annotation, - deprecation: std::mem::take(&mut attributes.deprecated), - external_erlang: attributes.external_erlang.take(), - external_javascript: attributes.external_javascript.take(), - implementations: Implementations { - gleam: true, - can_run_on_erlang: true, - can_run_on_javascript: true, - uses_erlang_externals: false, - uses_javascript_externals: false, - }, - purity: Purity::Pure, - }))) + None => (None, vec![], rpar_e, rpar_e), + }; + + Ok(Some(Definition::Function(Function { + documentation, + location: SrcSpan { start, end }, + end_position, + body_start, + publicity: self.publicity(public, attributes.internal)?, + name, + arguments, + body, + return_type: (), + return_annotation, + deprecation: std::mem::take(&mut attributes.deprecated), + external_erlang: attributes.external_erlang.take(), + external_javascript: attributes.external_javascript.take(), + implementations: Implementations { + gleam: true, + can_run_on_erlang: true, + can_run_on_javascript: true, + uses_erlang_externals: false, + uses_javascript_externals: false, + }, + purity: Purity::Pure, + }))) + } + } } fn add_anon_function_hint(&self, mut err: ParseError) -> ParseError { From 4990ba9d8be1971739615859e0b6a20ff2fcb28c Mon Sep 17 00:00:00 2001 From: Baraich Date: Fri, 19 Sep 2025 17:32:17 +0530 Subject: [PATCH 02/10] update the code to use early return --- compiler-core/src/parse.rs | 111 ++++++++++++++++++------------------- 1 file changed, 55 insertions(+), 56 deletions(-) diff --git a/compiler-core/src/parse.rs b/compiler-core/src/parse.rs index 33cee76a345..07b51494182 100644 --- a/compiler-core/src/parse.rs +++ b/compiler-core/src/parse.rs @@ -2119,8 +2119,8 @@ where self.expect_one_following_series(&Token::RightParen, "a function parameter")?; // Check for TypeScript-style return type annotation (:) instead of arrow (->) - match self.maybe_one(&Token::Colon) { - Some((colon_start, colon_end)) => Err(ParseError { + if let Some((colon_start, colon_end)) = self.maybe_one(&Token::Colon) { + return Err(ParseError { error: ParseErrorType::UnexpectedToken { token: Token::Colon, expected: vec!["->".into()], @@ -2130,63 +2130,62 @@ where start: colon_start, end: colon_end, }, - }), - None => { - let return_annotation = self.parse_type_annotation(&Token::RArrow)?; - - let (body_start, body, end, end_position) = match self.maybe_one(&Token::LeftBrace) { - Some((left_brace_start, _)) => { - let some_body = self.parse_statement_seq()?; - let (_, right_brace_end) = self.expect_one(&Token::RightBrace)?; - let end = return_annotation - .as_ref() - .map(|l| l.location().end) - .unwrap_or(rpar_e); - let body = match some_body { - None => vec![Statement::Expression(UntypedExpr::Todo { - kind: TodoKind::EmptyFunction { - function_location: SrcSpan { start, end }, - }, - location: SrcSpan { - start: left_brace_start + 1, - end: right_brace_end, - }, - message: None, - })], - Some((body, _)) => body.to_vec(), - }; - - (Some(left_brace_start), body, end, right_brace_end) - } + }); + }; - None => (None, vec![], rpar_e, rpar_e), + let return_annotation = self.parse_type_annotation(&Token::RArrow)?; + + let (body_start, body, end, end_position) = match self.maybe_one(&Token::LeftBrace) { + Some((left_brace_start, _)) => { + let some_body = self.parse_statement_seq()?; + let (_, right_brace_end) = self.expect_one(&Token::RightBrace)?; + let end = return_annotation + .as_ref() + .map(|l| l.location().end) + .unwrap_or(rpar_e); + let body = match some_body { + None => vec![Statement::Expression(UntypedExpr::Todo { + kind: TodoKind::EmptyFunction { + function_location: SrcSpan { start, end }, + }, + location: SrcSpan { + start: left_brace_start + 1, + end: right_brace_end, + }, + message: None, + })], + Some((body, _)) => body.to_vec(), }; - Ok(Some(Definition::Function(Function { - documentation, - location: SrcSpan { start, end }, - end_position, - body_start, - publicity: self.publicity(public, attributes.internal)?, - name, - arguments, - body, - return_type: (), - return_annotation, - deprecation: std::mem::take(&mut attributes.deprecated), - external_erlang: attributes.external_erlang.take(), - external_javascript: attributes.external_javascript.take(), - implementations: Implementations { - gleam: true, - can_run_on_erlang: true, - can_run_on_javascript: true, - uses_erlang_externals: false, - uses_javascript_externals: false, - }, - purity: Purity::Pure, - }))) - } - } + (Some(left_brace_start), body, end, right_brace_end) + } + + None => (None, vec![], rpar_e, rpar_e), + }; + + Ok(Some(Definition::Function(Function { + documentation, + location: SrcSpan { start, end }, + end_position, + body_start, + publicity: self.publicity(public, attributes.internal)?, + name, + arguments, + body, + return_type: (), + return_annotation, + deprecation: std::mem::take(&mut attributes.deprecated), + external_erlang: attributes.external_erlang.take(), + external_javascript: attributes.external_javascript.take(), + implementations: Implementations { + gleam: true, + can_run_on_erlang: true, + can_run_on_javascript: true, + uses_erlang_externals: false, + uses_javascript_externals: false, + }, + purity: Purity::Pure, + }))) } fn add_anon_function_hint(&self, mut err: ParseError) -> ParseError { From 387bc095976d41c44351cd0a07e94f48edf31b88 Mon Sep 17 00:00:00 2001 From: Baraich Date: Fri, 19 Sep 2025 18:27:00 +0530 Subject: [PATCH 03/10] added tests for #4984 --- ...on_using_colon_instead_of_right_arrow.snap | 20 +++++++++++++++++++ compiler-core/src/parse/tests.rs | 9 +++++++++ 2 files changed, 29 insertions(+) create mode 100644 compiler-core/src/parse/snapshots/gleam_core__parse__tests__wrong_function_return_type_declaration_using_colon_instead_of_right_arrow.snap diff --git a/compiler-core/src/parse/snapshots/gleam_core__parse__tests__wrong_function_return_type_declaration_using_colon_instead_of_right_arrow.snap b/compiler-core/src/parse/snapshots/gleam_core__parse__tests__wrong_function_return_type_declaration_using_colon_instead_of_right_arrow.snap new file mode 100644 index 00000000000..ca678f21e61 --- /dev/null +++ b/compiler-core/src/parse/snapshots/gleam_core__parse__tests__wrong_function_return_type_declaration_using_colon_instead_of_right_arrow.snap @@ -0,0 +1,20 @@ +--- +source: compiler-core/src/parse/tests.rs +expression: "\npub fn main(): Nil {}\n " +--- +----- SOURCE CODE + +pub fn main(): Nil {} + + +----- ERROR +error: Syntax error + ┌─ /src/parse/error.gleam:2:14 + │ +2 │ pub fn main(): Nil {} + │ ^ I was not expecting this + +Found `:`, expected one of: +- -> +Hint: Maybe you meant to write return value type annotation? +Return type annotations are written using `->`, not `:` diff --git a/compiler-core/src/parse/tests.rs b/compiler-core/src/parse/tests.rs index 23e41843456..f9072bb9787 100644 --- a/compiler-core/src/parse/tests.rs +++ b/compiler-core/src/parse/tests.rs @@ -1992,3 +1992,12 @@ pub fn main() { "# ); } + +#[test] +fn wrong_function_return_type_declaration_using_colon_instead_of_right_arrow() { + assert_module_error!( + r#" +pub fn main(): Nil {} + "# + ); +} From 6058b4fb6f742ce66d5bfffc0f230089e9cdcfd6 Mon Sep 17 00:00:00 2001 From: Baraich Date: Sun, 21 Sep 2025 15:00:01 +0530 Subject: [PATCH 04/10] wrapping operators in backticks --- compiler-core/src/parse.rs | 2 +- ...urn_type_declaration_using_colon_instead_of_right_arrow.snap | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/compiler-core/src/parse.rs b/compiler-core/src/parse.rs index 07b51494182..ee2daf0b5c4 100644 --- a/compiler-core/src/parse.rs +++ b/compiler-core/src/parse.rs @@ -2123,7 +2123,7 @@ where return Err(ParseError { error: ParseErrorType::UnexpectedToken { token: Token::Colon, - expected: vec!["->".into()], + expected: vec!["`->`".into()], hint: Some("Maybe you meant to write return value type annotation?\nReturn type annotations are written using `->`, not `:`".into()), }, location: SrcSpan { diff --git a/compiler-core/src/parse/snapshots/gleam_core__parse__tests__wrong_function_return_type_declaration_using_colon_instead_of_right_arrow.snap b/compiler-core/src/parse/snapshots/gleam_core__parse__tests__wrong_function_return_type_declaration_using_colon_instead_of_right_arrow.snap index ca678f21e61..5dbbe5191af 100644 --- a/compiler-core/src/parse/snapshots/gleam_core__parse__tests__wrong_function_return_type_declaration_using_colon_instead_of_right_arrow.snap +++ b/compiler-core/src/parse/snapshots/gleam_core__parse__tests__wrong_function_return_type_declaration_using_colon_instead_of_right_arrow.snap @@ -15,6 +15,6 @@ error: Syntax error │ ^ I was not expecting this Found `:`, expected one of: -- -> +- `->` Hint: Maybe you meant to write return value type annotation? Return type annotations are written using `->`, not `:` From 766fb3043f4d665b7b72233f131e248d3536776d Mon Sep 17 00:00:00 2001 From: Baraich Date: Fri, 19 Sep 2025 17:32:17 +0530 Subject: [PATCH 05/10] update the code to use early return --- compiler-core/src/parse.rs | 111 ++++++++++++++++++------------------- 1 file changed, 55 insertions(+), 56 deletions(-) diff --git a/compiler-core/src/parse.rs b/compiler-core/src/parse.rs index 33cee76a345..07b51494182 100644 --- a/compiler-core/src/parse.rs +++ b/compiler-core/src/parse.rs @@ -2119,8 +2119,8 @@ where self.expect_one_following_series(&Token::RightParen, "a function parameter")?; // Check for TypeScript-style return type annotation (:) instead of arrow (->) - match self.maybe_one(&Token::Colon) { - Some((colon_start, colon_end)) => Err(ParseError { + if let Some((colon_start, colon_end)) = self.maybe_one(&Token::Colon) { + return Err(ParseError { error: ParseErrorType::UnexpectedToken { token: Token::Colon, expected: vec!["->".into()], @@ -2130,63 +2130,62 @@ where start: colon_start, end: colon_end, }, - }), - None => { - let return_annotation = self.parse_type_annotation(&Token::RArrow)?; - - let (body_start, body, end, end_position) = match self.maybe_one(&Token::LeftBrace) { - Some((left_brace_start, _)) => { - let some_body = self.parse_statement_seq()?; - let (_, right_brace_end) = self.expect_one(&Token::RightBrace)?; - let end = return_annotation - .as_ref() - .map(|l| l.location().end) - .unwrap_or(rpar_e); - let body = match some_body { - None => vec![Statement::Expression(UntypedExpr::Todo { - kind: TodoKind::EmptyFunction { - function_location: SrcSpan { start, end }, - }, - location: SrcSpan { - start: left_brace_start + 1, - end: right_brace_end, - }, - message: None, - })], - Some((body, _)) => body.to_vec(), - }; - - (Some(left_brace_start), body, end, right_brace_end) - } + }); + }; - None => (None, vec![], rpar_e, rpar_e), + let return_annotation = self.parse_type_annotation(&Token::RArrow)?; + + let (body_start, body, end, end_position) = match self.maybe_one(&Token::LeftBrace) { + Some((left_brace_start, _)) => { + let some_body = self.parse_statement_seq()?; + let (_, right_brace_end) = self.expect_one(&Token::RightBrace)?; + let end = return_annotation + .as_ref() + .map(|l| l.location().end) + .unwrap_or(rpar_e); + let body = match some_body { + None => vec![Statement::Expression(UntypedExpr::Todo { + kind: TodoKind::EmptyFunction { + function_location: SrcSpan { start, end }, + }, + location: SrcSpan { + start: left_brace_start + 1, + end: right_brace_end, + }, + message: None, + })], + Some((body, _)) => body.to_vec(), }; - Ok(Some(Definition::Function(Function { - documentation, - location: SrcSpan { start, end }, - end_position, - body_start, - publicity: self.publicity(public, attributes.internal)?, - name, - arguments, - body, - return_type: (), - return_annotation, - deprecation: std::mem::take(&mut attributes.deprecated), - external_erlang: attributes.external_erlang.take(), - external_javascript: attributes.external_javascript.take(), - implementations: Implementations { - gleam: true, - can_run_on_erlang: true, - can_run_on_javascript: true, - uses_erlang_externals: false, - uses_javascript_externals: false, - }, - purity: Purity::Pure, - }))) - } - } + (Some(left_brace_start), body, end, right_brace_end) + } + + None => (None, vec![], rpar_e, rpar_e), + }; + + Ok(Some(Definition::Function(Function { + documentation, + location: SrcSpan { start, end }, + end_position, + body_start, + publicity: self.publicity(public, attributes.internal)?, + name, + arguments, + body, + return_type: (), + return_annotation, + deprecation: std::mem::take(&mut attributes.deprecated), + external_erlang: attributes.external_erlang.take(), + external_javascript: attributes.external_javascript.take(), + implementations: Implementations { + gleam: true, + can_run_on_erlang: true, + can_run_on_javascript: true, + uses_erlang_externals: false, + uses_javascript_externals: false, + }, + purity: Purity::Pure, + }))) } fn add_anon_function_hint(&self, mut err: ParseError) -> ParseError { From 3d5fb4f03da7826ee9a11df9f7f6e058745d0dfb Mon Sep 17 00:00:00 2001 From: Baraich Date: Fri, 19 Sep 2025 18:27:00 +0530 Subject: [PATCH 06/10] added tests for #4984 --- ...on_using_colon_instead_of_right_arrow.snap | 20 +++++++++++++++++++ compiler-core/src/parse/tests.rs | 9 +++++++++ 2 files changed, 29 insertions(+) create mode 100644 compiler-core/src/parse/snapshots/gleam_core__parse__tests__wrong_function_return_type_declaration_using_colon_instead_of_right_arrow.snap diff --git a/compiler-core/src/parse/snapshots/gleam_core__parse__tests__wrong_function_return_type_declaration_using_colon_instead_of_right_arrow.snap b/compiler-core/src/parse/snapshots/gleam_core__parse__tests__wrong_function_return_type_declaration_using_colon_instead_of_right_arrow.snap new file mode 100644 index 00000000000..ca678f21e61 --- /dev/null +++ b/compiler-core/src/parse/snapshots/gleam_core__parse__tests__wrong_function_return_type_declaration_using_colon_instead_of_right_arrow.snap @@ -0,0 +1,20 @@ +--- +source: compiler-core/src/parse/tests.rs +expression: "\npub fn main(): Nil {}\n " +--- +----- SOURCE CODE + +pub fn main(): Nil {} + + +----- ERROR +error: Syntax error + ┌─ /src/parse/error.gleam:2:14 + │ +2 │ pub fn main(): Nil {} + │ ^ I was not expecting this + +Found `:`, expected one of: +- -> +Hint: Maybe you meant to write return value type annotation? +Return type annotations are written using `->`, not `:` diff --git a/compiler-core/src/parse/tests.rs b/compiler-core/src/parse/tests.rs index 23e41843456..f9072bb9787 100644 --- a/compiler-core/src/parse/tests.rs +++ b/compiler-core/src/parse/tests.rs @@ -1992,3 +1992,12 @@ pub fn main() { "# ); } + +#[test] +fn wrong_function_return_type_declaration_using_colon_instead_of_right_arrow() { + assert_module_error!( + r#" +pub fn main(): Nil {} + "# + ); +} From c10bbfc06f537f9916aa3f577f7994d8219d7fd8 Mon Sep 17 00:00:00 2001 From: Baraich Date: Sun, 21 Sep 2025 15:00:01 +0530 Subject: [PATCH 07/10] wrapping operators in backticks --- compiler-core/src/parse.rs | 2 +- ...urn_type_declaration_using_colon_instead_of_right_arrow.snap | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/compiler-core/src/parse.rs b/compiler-core/src/parse.rs index 07b51494182..ee2daf0b5c4 100644 --- a/compiler-core/src/parse.rs +++ b/compiler-core/src/parse.rs @@ -2123,7 +2123,7 @@ where return Err(ParseError { error: ParseErrorType::UnexpectedToken { token: Token::Colon, - expected: vec!["->".into()], + expected: vec!["`->`".into()], hint: Some("Maybe you meant to write return value type annotation?\nReturn type annotations are written using `->`, not `:`".into()), }, location: SrcSpan { diff --git a/compiler-core/src/parse/snapshots/gleam_core__parse__tests__wrong_function_return_type_declaration_using_colon_instead_of_right_arrow.snap b/compiler-core/src/parse/snapshots/gleam_core__parse__tests__wrong_function_return_type_declaration_using_colon_instead_of_right_arrow.snap index ca678f21e61..5dbbe5191af 100644 --- a/compiler-core/src/parse/snapshots/gleam_core__parse__tests__wrong_function_return_type_declaration_using_colon_instead_of_right_arrow.snap +++ b/compiler-core/src/parse/snapshots/gleam_core__parse__tests__wrong_function_return_type_declaration_using_colon_instead_of_right_arrow.snap @@ -15,6 +15,6 @@ error: Syntax error │ ^ I was not expecting this Found `:`, expected one of: -- -> +- `->` Hint: Maybe you meant to write return value type annotation? Return type annotations are written using `->`, not `:` From 7f58949e02fab443ff580e101d7d3b5e1d2517ac Mon Sep 17 00:00:00 2001 From: Baraich Date: Tue, 23 Sep 2025 12:06:24 +0530 Subject: [PATCH 08/10] updated CHANGELOG.md file with change description --- CHANGELOG.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index a3c1834ddf7..d0fec342e12 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -758,3 +758,8 @@ - Fixed a bug where the compiler would produce wrong JavaScript code for binary pattern matching expressions using literal strings and byte segments. ([Giacomo Cavalieri](https://github.com/giacomocavalieri)) + +- The compiler now provides a clearer error message when a function's return type + is mistakenly declared using `:` instead of `->`. + ([Gurvir Singh](https://github.com/baraich)) +>>>>>>> Stashed changes From 9830e02b36cbf4b773f7e32082ab46486dd70a1b Mon Sep 17 00:00:00 2001 From: Baraich Date: Tue, 23 Sep 2025 12:08:44 +0530 Subject: [PATCH 09/10] update the hint message --- compiler-core/src/parse.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler-core/src/parse.rs b/compiler-core/src/parse.rs index ee2daf0b5c4..8f4467c84d9 100644 --- a/compiler-core/src/parse.rs +++ b/compiler-core/src/parse.rs @@ -2124,7 +2124,7 @@ where error: ParseErrorType::UnexpectedToken { token: Token::Colon, expected: vec!["`->`".into()], - hint: Some("Maybe you meant to write return value type annotation?\nReturn type annotations are written using `->`, not `:`".into()), + hint: Some("Return type annotations are written using `->`, not `:`".into()), }, location: SrcSpan { start: colon_start, From 68a84e481b93bbe81f8516477c13fa8a016a18a0 Mon Sep 17 00:00:00 2001 From: Baraich Date: Tue, 23 Sep 2025 12:11:45 +0530 Subject: [PATCH 10/10] update the snapshot --- ...rn_type_declaration_using_colon_instead_of_right_arrow.snap | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/compiler-core/src/parse/snapshots/gleam_core__parse__tests__wrong_function_return_type_declaration_using_colon_instead_of_right_arrow.snap b/compiler-core/src/parse/snapshots/gleam_core__parse__tests__wrong_function_return_type_declaration_using_colon_instead_of_right_arrow.snap index 5dbbe5191af..f194b3e6773 100644 --- a/compiler-core/src/parse/snapshots/gleam_core__parse__tests__wrong_function_return_type_declaration_using_colon_instead_of_right_arrow.snap +++ b/compiler-core/src/parse/snapshots/gleam_core__parse__tests__wrong_function_return_type_declaration_using_colon_instead_of_right_arrow.snap @@ -16,5 +16,4 @@ error: Syntax error Found `:`, expected one of: - `->` -Hint: Maybe you meant to write return value type annotation? -Return type annotations are written using `->`, not `:` +Hint: Return type annotations are written using `->`, not `:`