From 3cd76e21163edfda8b662d7071687180a4143ba2 Mon Sep 17 00:00:00 2001
From: Cristiano Calcagno <cristianoc@users.noreply.github.com>
Date: Sat, 4 Feb 2023 10:56:07 +0100
Subject: [PATCH] Fix issue with error messages for uncurried functions where
 expected and given type were swapped

The logic for unification for `Function$`, which unifies with a generic uncurried type, was swapped.
The error message for arity mismatch was also swapped, so those errors were showing correctly.
However, in the case of expected curried function, when given a curried function whose type is begin inferred, the error message was swapped.
Also added a specialized error message when the uncurried type only contains a type variable, so `$function<'a, ...>` does not leak in the output. This happens as unification failt early, and the type of the function has not been determined yet.
---
 CHANGELOG.md                                           |  1 +
 .../expected/curried_expected.res.expected             | 10 ++++++++++
 .../super_errors/fixtures/curried_expected.res         |  3 +++
 jscomp/ml/typecore.ml                                  |  2 +-
 jscomp/super_errors/super_typecore.ml                  |  9 +++++++--
 5 files changed, 22 insertions(+), 3 deletions(-)
 create mode 100644 jscomp/build_tests/super_errors/expected/curried_expected.res.expected
 create mode 100644 jscomp/build_tests/super_errors/fixtures/curried_expected.res

diff --git a/CHANGELOG.md b/CHANGELOG.md
index d200abbc6b..3bdf0eb9a4 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -54,6 +54,7 @@ These are only breaking changes for unformatted code.
 - Fix issue where error messages related to non-existent props were displayed without location information https://github.com/rescript-lang/rescript-compiler/pull/5960
 - Fix type inference issue with uncurried functions applied to a single unit argument. The issue was introduced in https://github.com/rescript-lang/rescript-compiler/pull/5907 when adding support to `foo()` when `foo` has only optional arguments. https://github.com/rescript-lang/rescript-compiler/pull/5970
 - Fix issue where uncurried functions were incorrectly converting the type of a prop given as a default value to curried https://github.com/rescript-lang/rescript-compiler/pull/5971
+- Fix issue with error messages for uncurried functions where expected and given type were swapped https://github.com/rescript-lang/rescript-compiler/pull/5973
 
 #### :nail_care: Polish
 
diff --git a/jscomp/build_tests/super_errors/expected/curried_expected.res.expected b/jscomp/build_tests/super_errors/expected/curried_expected.res.expected
new file mode 100644
index 0000000000..5b789c5abb
--- /dev/null
+++ b/jscomp/build_tests/super_errors/expected/curried_expected.res.expected
@@ -0,0 +1,10 @@
+
+  We've found a bug for you!
+  /.../fixtures/curried_expected.res:3:24-38
+
+  1 │ let expectCurried = f => f(1) + 2
+  2 │ 
+  3 │ let z1 = expectCurried((. x, y) => x+y)
+  4 │ 
+
+  This function is an uncurried function where a curried function is expected
\ No newline at end of file
diff --git a/jscomp/build_tests/super_errors/fixtures/curried_expected.res b/jscomp/build_tests/super_errors/fixtures/curried_expected.res
new file mode 100644
index 0000000000..224d432a15
--- /dev/null
+++ b/jscomp/build_tests/super_errors/fixtures/curried_expected.res
@@ -0,0 +1,3 @@
+let expectCurried = f => f(1) + 2
+
+let z1 = expectCurried((. x, y) => x+y)
diff --git a/jscomp/ml/typecore.ml b/jscomp/ml/typecore.ml
index 4dc62db56b..acdd846da4 100644
--- a/jscomp/ml/typecore.ml
+++ b/jscomp/ml/typecore.ml
@@ -2107,7 +2107,7 @@ and type_expect_ ?in_function ?(recarg=Rejected) env sexp ty_expected =
       let state = Warnings.backup () in
       let arity = Ast_uncurried.attributes_to_arity sexp.pexp_attributes in
       let uncurried_typ = Ast_uncurried.make_uncurried_type ~env ~arity (newvar()) in
-      unify_exp_types loc env ty_expected uncurried_typ;
+      unify_exp_types loc env uncurried_typ ty_expected;
       (* Disable Unerasable_optional_argument for uncurried functions *)
       let unerasable_optional_argument = Warnings.number Unerasable_optional_argument in
       Warnings.parse_options false ("-" ^ string_of_int unerasable_optional_argument);
diff --git a/jscomp/super_errors/super_typecore.ml b/jscomp/super_errors/super_typecore.ml
index cef6a7ec0a..0f99ca1f0e 100644
--- a/jscomp/super_errors/super_typecore.ml
+++ b/jscomp/super_errors/super_typecore.ml
@@ -121,9 +121,9 @@ end
 
 let reportArityMismatch ~arityA ~arityB ppf =
   fprintf ppf "This function expected @{<info>%s@} %s, but got @{<error>%s@}"
-    arityA
-    (if arityA = "1" then "argument" else "arguments")
     arityB
+    (if arityB = "1" then "argument" else "arguments")
+    arityA
 
 (* Pasted from typecore.ml. Needed for some cases in report_error below *)
 (* Records *)
@@ -169,6 +169,11 @@ let report_error env ppf = function
     (_, {desc = Tconstr (Pident {name = "function$"},_,_)}) :: _
    ) -> 
     fprintf ppf "This function is a curried function where an uncurried function is expected"
+  | Expr_type_clash ( 
+    (_, {desc = Tconstr (Pident {name = "function$"}, [{desc=Tvar _}; _],_)}) ::
+    (_, {desc = Tarrow _}) :: _
+   ) -> 
+    fprintf ppf "This function is an uncurried function where a curried function is expected"
   | Expr_type_clash (
       (_, {desc = Tconstr (Pident {name = "function$"},[_; tA],_)}) ::
       (_, {desc = Tconstr (Pident {name = "function$"},[_; tB],_)}) :: _