From e3eecdce16dd16fe2bbd572877398f8fa42ad391 Mon Sep 17 00:00:00 2001 From: Christoph Knittel Date: Tue, 30 Sep 2025 18:32:03 +0200 Subject: [PATCH 1/3] Fix parameter type / return type ambiguity error for unit case --- compiler/syntax/src/res_core.ml | 83 ++++++++++--------- .../parsing/grammar/expressions/arrow.res | 2 + .../expressions/expected/arrow.res.txt | 1 + .../data/printer/expr/expected/fun.res.txt | 2 + tests/syntax_tests/data/printer/expr/fun.res | 2 + 5 files changed, 53 insertions(+), 37 deletions(-) diff --git a/compiler/syntax/src/res_core.ml b/compiler/syntax/src/res_core.ml index 999743ac21..5cfa4b022c 100644 --- a/compiler/syntax/src/res_core.ml +++ b/compiler/syntax/src/res_core.ml @@ -2554,17 +2554,21 @@ and over_parse_constrained_or_coerced_or_arrow_expression p expr = | EqualGreater -> Parser.next p; let body = parse_expr p in - let pat = + let pat, expr_is_unit = match expr.pexp_desc with | Pexp_ident longident -> - Ast_helper.Pat.var ~loc:expr.pexp_loc - (Location.mkloc - (Longident.flatten longident.txt |> String.concat ".") - longident.loc) + ( Ast_helper.Pat.var ~loc:expr.pexp_loc + (Location.mkloc + (Longident.flatten longident.txt |> String.concat ".") + longident.loc) + , false ) + | Pexp_construct ({txt = Longident.Lident "()"} as lid, None) -> + (Ast_helper.Pat.construct ~loc:expr.pexp_loc lid None, true) (* TODO: can we convert more expressions to patterns?*) | _ -> - Ast_helper.Pat.var ~loc:expr.pexp_loc - (Location.mkloc "pattern" expr.pexp_loc) + ( Ast_helper.Pat.var ~loc:expr.pexp_loc + (Location.mkloc "pattern" expr.pexp_loc) + , false ) in let arrow1 = Ast_helper.Exp.fun_ @@ -2572,36 +2576,41 @@ and over_parse_constrained_or_coerced_or_arrow_expression p expr = ~arity:None Asttypes.Nolabel None pat (Ast_helper.Exp.constraint_ body typ) in - let arrow2 = - Ast_helper.Exp.fun_ - ~loc:(mk_loc expr.pexp_loc.loc_start body.pexp_loc.loc_end) - ~arity:None Asttypes.Nolabel None - (Ast_helper.Pat.constraint_ pat typ) - body - in - let msg = - Doc.breakable_group ~force_break:true - (Doc.concat - [ - Doc.text - "Did you mean to annotate the parameter type or the return \ - type?"; - Doc.indent - (Doc.concat - [ - Doc.line; - Doc.text "1) "; - ResPrinter.print_expression arrow1 CommentTable.empty; - Doc.line; - Doc.text "2) "; - ResPrinter.print_expression arrow2 CommentTable.empty; - ]); - ]) - |> Doc.to_string ~width:80 - in - Parser.err ~start_pos:expr.pexp_loc.loc_start - ~end_pos:body.pexp_loc.loc_end p (Diagnostics.message msg); - arrow1 + (* When the "expr" was `()`, the colon must apply to the return type, so + skip the ambiguity diagnostic and keep the parameter as unit. *) + if expr_is_unit then + arrow1 + else ( + let arrow2 = + Ast_helper.Exp.fun_ + ~loc:(mk_loc expr.pexp_loc.loc_start body.pexp_loc.loc_end) + ~arity:None Asttypes.Nolabel None + (Ast_helper.Pat.constraint_ pat typ) + body + in + let msg = + Doc.breakable_group ~force_break:true + (Doc.concat + [ + Doc.text + "Did you mean to annotate the parameter type or the return \ + type?"; + Doc.indent + (Doc.concat + [ + Doc.line; + Doc.text "1) "; + ResPrinter.print_expression arrow1 CommentTable.empty; + Doc.line; + Doc.text "2) "; + ResPrinter.print_expression arrow2 CommentTable.empty; + ]); + ]) + |> Doc.to_string ~width:80 + in + Parser.err ~start_pos:expr.pexp_loc.loc_start + ~end_pos:body.pexp_loc.loc_end p (Diagnostics.message msg); + arrow1) | _ -> let loc = mk_loc expr.pexp_loc.loc_start typ.ptyp_loc.loc_end in let expr = Ast_helper.Exp.constraint_ ~loc expr typ in diff --git a/tests/syntax_tests/data/parsing/grammar/expressions/arrow.res b/tests/syntax_tests/data/parsing/grammar/expressions/arrow.res index 9d37007aaf..e13dd438e7 100644 --- a/tests/syntax_tests/data/parsing/grammar/expressions/arrow.res +++ b/tests/syntax_tests/data/parsing/grammar/expressions/arrow.res @@ -103,6 +103,8 @@ let un = (():u) type d<'a,'b> = ('a,'b) let c = (): d<'a,'b> => (1,2) +let arr = (): array> => [] + let fn = f => f; type f = int => unit; let a = fn(_ => (): f); \ No newline at end of file diff --git a/tests/syntax_tests/data/parsing/grammar/expressions/expected/arrow.res.txt b/tests/syntax_tests/data/parsing/grammar/expressions/expected/arrow.res.txt index 8bb00c53d3..aa9afaab35 100644 --- a/tests/syntax_tests/data/parsing/grammar/expressions/expected/arrow.res.txt +++ b/tests/syntax_tests/data/parsing/grammar/expressions/expected/arrow.res.txt @@ -74,6 +74,7 @@ type nonrec u = unit let un = (() : u) type nonrec ('a, 'b) d = ('a * 'b) let c [arity:1]() = ((1, 2) : ('a, 'b) d) +let arr () = ([||] : int nullable array) let fn [arity:1]f = f type nonrec f = int -> unit (a:1) let a = fn (fun [arity:1]_ -> () : f) \ No newline at end of file diff --git a/tests/syntax_tests/data/printer/expr/expected/fun.res.txt b/tests/syntax_tests/data/printer/expr/expected/fun.res.txt index 9821a0e93d..17b75d717e 100644 --- a/tests/syntax_tests/data/printer/expr/expected/fun.res.txt +++ b/tests/syntax_tests/data/printer/expr/expected/fun.res.txt @@ -356,3 +356,5 @@ let query = (~url, ()): (unit => unit => unit => unit) => { let f = a => b => a + b let f = (a, b) => (b, c) => a + b + c + d let f = (a, b) => (b, c) => (e, f, g) => a + b + c + d + e + f + g + +let unitConstraint = (): array> => [] diff --git a/tests/syntax_tests/data/printer/expr/fun.res b/tests/syntax_tests/data/printer/expr/fun.res index 2c5c5009af..af8700a6ed 100644 --- a/tests/syntax_tests/data/printer/expr/fun.res +++ b/tests/syntax_tests/data/printer/expr/fun.res @@ -297,3 +297,5 @@ let query = (~url, ()): (unit => unit => unit => unit) => { let f = (. a) => (. b) => a + b let f = (. a, b) => (. b, c) => a + b + c + d let f = (. a, b) => (. b , c) => (. e , f, g) => a + b + c + d + e + f + g + +let unitConstraint = (): array> => [] From 307aa3b2471824b475bec5609a6ec181a644b980 Mon Sep 17 00:00:00 2001 From: Christoph Knittel Date: Tue, 30 Sep 2025 18:50:19 +0200 Subject: [PATCH 2/3] format --- compiler/syntax/src/res_core.ml | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/compiler/syntax/src/res_core.ml b/compiler/syntax/src/res_core.ml index 5cfa4b022c..ee74eae6b4 100644 --- a/compiler/syntax/src/res_core.ml +++ b/compiler/syntax/src/res_core.ml @@ -2560,15 +2560,15 @@ and over_parse_constrained_or_coerced_or_arrow_expression p expr = ( Ast_helper.Pat.var ~loc:expr.pexp_loc (Location.mkloc (Longident.flatten longident.txt |> String.concat ".") - longident.loc) - , false ) - | Pexp_construct ({txt = Longident.Lident "()"} as lid, None) -> + longident.loc), + false ) + | Pexp_construct (({txt = Longident.Lident "()"} as lid), None) -> (Ast_helper.Pat.construct ~loc:expr.pexp_loc lid None, true) (* TODO: can we convert more expressions to patterns?*) | _ -> ( Ast_helper.Pat.var ~loc:expr.pexp_loc - (Location.mkloc "pattern" expr.pexp_loc) - , false ) + (Location.mkloc "pattern" expr.pexp_loc), + false ) in let arrow1 = Ast_helper.Exp.fun_ @@ -2578,9 +2578,8 @@ and over_parse_constrained_or_coerced_or_arrow_expression p expr = in (* When the "expr" was `()`, the colon must apply to the return type, so skip the ambiguity diagnostic and keep the parameter as unit. *) - if expr_is_unit then - arrow1 - else ( + if expr_is_unit then arrow1 + else let arrow2 = Ast_helper.Exp.fun_ ~loc:(mk_loc expr.pexp_loc.loc_start body.pexp_loc.loc_end) @@ -2610,7 +2609,7 @@ and over_parse_constrained_or_coerced_or_arrow_expression p expr = in Parser.err ~start_pos:expr.pexp_loc.loc_start ~end_pos:body.pexp_loc.loc_end p (Diagnostics.message msg); - arrow1) + arrow1 | _ -> let loc = mk_loc expr.pexp_loc.loc_start typ.ptyp_loc.loc_end in let expr = Ast_helper.Exp.constraint_ ~loc expr typ in From e9416a73871c0fabb0324ae140f49d6ecd5f956b Mon Sep 17 00:00:00 2001 From: Christoph Knittel Date: Tue, 30 Sep 2025 18:50:51 +0200 Subject: [PATCH 3/3] CHANGELOG --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 491c004eb1..24b2589167 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -23,6 +23,7 @@ #### :bug: Bug fix - Prevent lockfile creation when project folder is missing. https://github.com/rescript-lang/rescript/pull/7927 +- Fix parameter type / return type ambiguity error for unit case. https://github.com/rescript-lang/rescript/pull/7930 #### :memo: Documentation