diff --git a/CHANGELOG.md b/CHANGELOG.md index bd9695b714..1d289185c4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -22,6 +22,7 @@ #### :nail_care: Polish - Better error message for when trying to await something that is not a promise. https://github.com/rescript-lang/rescript/pull/7561 +- Better error messages for object field missing and object field type mismatches. https://github.com/rescript-lang/rescript/pull/7580 #### :house: Internal diff --git a/compiler/ml/printtyp.ml b/compiler/ml/printtyp.ml index 464723da38..98142b4a93 100644 --- a/compiler/ml/printtyp.ml +++ b/compiler/ml/printtyp.ml @@ -1352,13 +1352,29 @@ let explanation unif t3 t4 ppf = fprintf ppf "@,Self type cannot be unified with a closed object type" | _, Tfield (lab, _, _, _) when lab = dummy_method -> fprintf ppf "@,Self type cannot be unified with a closed object type" - | Tfield (l, _, _, {desc = Tnil}), Tfield (l', _, _, {desc = Tnil}) + | Tfield (l, _, f1, {desc = Tnil}), Tfield (l', _, f2, {desc = Tnil}) when l = l' -> - fprintf ppf "@,Types for method %s are incompatible" l - | (Tnil | Tconstr _), Tfield (l, _, _, _) -> - fprintf ppf "@,@[The first object type has no field %s@]" l - | Tfield (l, _, _, _), (Tnil | Tconstr _) -> - fprintf ppf "@,@[The second object type has no field %s@]" l + fprintf ppf + "@,\ + @,\ + Types for field @{\"%s\"@} are incompatible:@,\ + Field @{\"%s\"@} in the passed object has type @{%a@}, but \ + is expected to have type @{%a@}." + l l type_expr f1 type_expr f2 + | (Tnil | Tconstr _), Tfield (l, _, f1, _) -> + fprintf ppf + "@,\ + @,\ + @[The first object is expected to have a field @{\"%s\"@} of type \ + @{%a@}, but it does not.@]" + l type_expr f1 + | Tfield (l, _, f1, _), (Tnil | Tconstr _) -> + fprintf ppf + "@,\ + @,\ + @[The second object is expected to have a field @{\"%s\"@} of \ + type @{%a@}, but it does not.@]" + l type_expr f1 | Tnil, Tconstr _ | Tconstr _, Tnil -> fprintf ppf "@,@[The %s object type has an abstract row, it cannot be closed@]" diff --git a/tests/build_tests/super_errors/expected/object_field_mismatch.res.expected b/tests/build_tests/super_errors/expected/object_field_mismatch.res.expected new file mode 100644 index 0000000000..1845872ad1 --- /dev/null +++ b/tests/build_tests/super_errors/expected/object_field_mismatch.res.expected @@ -0,0 +1,18 @@ + + We've found a bug for you! + /.../fixtures/object_field_mismatch.res:11:20-22 + + 9 │ } + 10 │ + 11 │ let _ = doStuff(~ctx) + 12 │ } + 13 │ + + This has type: {"multiply": (string, string) => string} + But this function argument ~ctx is expecting: + {.."multiply": (int, int) => int} + + Types for field "multiply" are incompatible: + Field "multiply" in the passed object has type (string, string) => string, but is expected to have type (int, int) => int. + + You can convert string to int with Int.fromString. \ No newline at end of file diff --git a/tests/build_tests/super_errors/expected/object_field_missing.res.expected b/tests/build_tests/super_errors/expected/object_field_missing.res.expected new file mode 100644 index 0000000000..144376cd7e --- /dev/null +++ b/tests/build_tests/super_errors/expected/object_field_missing.res.expected @@ -0,0 +1,15 @@ + + We've found a bug for you! + /.../fixtures/object_field_missing.res:11:20-22 + + 9 │ } + 10 │ + 11 │ let _ = doStuff(~ctx) + 12 │ } + 13 │ + + This has type: {"log": (string, string) => string} + But this function argument ~ctx is expecting: + {.."multiply": (int, int) => int} + + The first object is expected to have a field "multiply" of type (int, int) => int, but it does not. \ No newline at end of file diff --git a/tests/build_tests/super_errors/fixtures/object_field_mismatch.res b/tests/build_tests/super_errors/fixtures/object_field_mismatch.res new file mode 100644 index 0000000000..653991900c --- /dev/null +++ b/tests/build_tests/super_errors/fixtures/object_field_mismatch.res @@ -0,0 +1,12 @@ +let doStuff = (~ctx) => { + let multiply: (int, int) => int = ctx["multiply"] + multiply(1, 2) +} + +let main = () => { + let ctx = { + "multiply": (a, b) => a ++ b, + } + + let _ = doStuff(~ctx) +} diff --git a/tests/build_tests/super_errors/fixtures/object_field_missing.res b/tests/build_tests/super_errors/fixtures/object_field_missing.res new file mode 100644 index 0000000000..c24ac7e06a --- /dev/null +++ b/tests/build_tests/super_errors/fixtures/object_field_missing.res @@ -0,0 +1,12 @@ +let doStuff = (~ctx) => { + let multiply: (int, int) => int = ctx["multiply"] + multiply(1, 2) +} + +let main = () => { + let ctx = { + "log": (a, b) => a ++ b, + } + + let _ = doStuff(~ctx) +}