diff --git a/CHANGELOG.md b/CHANGELOG.md index 7b8cc95990..169b67dfad 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -24,6 +24,8 @@ #### :nail_care: Polish +- Improve default argument type mismatch errors. https://github.com/rescript-lang/rescript/pull/8389 + #### :house: Internal # 13.0.0-alpha.4 diff --git a/compiler/ml/typecore.ml b/compiler/ml/typecore.ml index 9f06915d2e..dc5c0d1d51 100644 --- a/compiler/ml/typecore.ml +++ b/compiler/ml/typecore.ml @@ -2452,6 +2452,7 @@ and type_expect_ ?deprecated_context ~context ?in_function ?(recarg = Rejected) in let smatch = Exp.match_ ~loc:sloc + ~attrs:[(mknoloc "#optional_arg_default", PStr [])] (Exp.ident ~loc (mknoloc (Longident.Lident "*opt*"))) scases in @@ -2540,13 +2541,15 @@ and type_expect_ ?deprecated_context ~context ?in_function ?(recarg = Rejected) (* Note: val_caselist = [] and exn_caselist = [], i.e. a fully empty pattern matching can be generated by Camlp4 with its revised syntax. Let's accept it for backward compatibility. *) + let has_attr name = + Ext_list.exists sexp.pexp_attributes (fun ({txt}, _) -> txt = name) + in let call_context = - if - Ext_list.exists sexp.pexp_attributes (fun ({txt}, _) -> - match txt with - | "let.unwrap" -> true - | _ -> false) - then `LetUnwrap + (* Optional-default lowering synthesizes a match expression, but from the + user's point of view this is still part of a function definition. Use + function-style diagnostics instead of reporting a phantom switch. *) + if has_attr "let.unwrap" then `LetUnwrap + else if has_attr "#optional_arg_default" then `Function else `Switch in let val_cases, partial = diff --git a/tests/build_tests/super_errors/expected/dict_show_no_coercion.res.expected b/tests/build_tests/super_errors/expected/dict_show_no_coercion.res.expected index ee47b4af0f..6cc1d70bd0 100644 --- a/tests/build_tests/super_errors/expected/dict_show_no_coercion.res.expected +++ b/tests/build_tests/super_errors/expected/dict_show_no_coercion.res.expected @@ -9,4 +9,4 @@ 3 │ This has type: float - But it's expected to have type: JSON.t (defined as JSON.t) + But it's expected to have type: JSON.t (defined as JSON.t) \ No newline at end of file diff --git a/tests/build_tests/super_errors/expected/for_await_requires_async_iterable.res.expected b/tests/build_tests/super_errors/expected/for_await_requires_async_iterable.res.expected index d189904b04..1cd513cc03 100644 --- a/tests/build_tests/super_errors/expected/for_await_requires_async_iterable.res.expected +++ b/tests/build_tests/super_errors/expected/for_await_requires_async_iterable.res.expected @@ -9,4 +9,4 @@ 7 │ } This has type: Iterable.t (defined as iterable) - But it's expected to have type: asyncIterable<'a> + But it's expected to have type: asyncIterable<'a> \ No newline at end of file diff --git a/tests/build_tests/super_errors/expected/for_of_non_array.res.expected b/tests/build_tests/super_errors/expected/for_of_non_array.res.expected index 3eb3c8871e..c33df74847 100644 --- a/tests/build_tests/super_errors/expected/for_of_non_array.res.expected +++ b/tests/build_tests/super_errors/expected/for_of_non_array.res.expected @@ -8,4 +8,4 @@ 4 │ } This has type: int - But it's expected to have type: iterable<'a> + But it's expected to have type: iterable<'a> \ No newline at end of file diff --git a/tests/build_tests/super_errors/expected/for_of_string_requires_iterable.res.expected b/tests/build_tests/super_errors/expected/for_of_string_requires_iterable.res.expected index 13b459549a..d0c248b2cc 100644 --- a/tests/build_tests/super_errors/expected/for_of_string_requires_iterable.res.expected +++ b/tests/build_tests/super_errors/expected/for_of_string_requires_iterable.res.expected @@ -9,4 +9,4 @@ 6 │ } This has type: string - But it's expected to have type: iterable<'a> + But it's expected to have type: iterable<'a> \ No newline at end of file diff --git a/tests/build_tests/super_errors/expected/for_of_type_mismatch.res.expected b/tests/build_tests/super_errors/expected/for_of_type_mismatch.res.expected index 3f29854157..5e28439cba 100644 --- a/tests/build_tests/super_errors/expected/for_of_type_mismatch.res.expected +++ b/tests/build_tests/super_errors/expected/for_of_type_mismatch.res.expected @@ -11,4 +11,4 @@ This has type: int But it's expected to have type: string - You can convert int to string with Int.toString. + You can convert int to string with Int.toString. \ No newline at end of file diff --git a/tests/build_tests/super_errors/expected/jsx_invalid_prop_ast0_conversion.res.expected b/tests/build_tests/super_errors/expected/jsx_invalid_prop_ast0_conversion.res.expected index 8b76a61c03..54417e7cc5 100644 --- a/tests/build_tests/super_errors/expected/jsx_invalid_prop_ast0_conversion.res.expected +++ b/tests/build_tests/super_errors/expected/jsx_invalid_prop_ast0_conversion.res.expected @@ -7,6 +7,4 @@ 18 │ let _ = 19 │ - The prop bar does not belong to the JSX component  - - + The prop bar does not belong to the JSX component  \ No newline at end of file diff --git a/tests/build_tests/super_errors/expected/optional_default_arg_type_mismatch.res.expected b/tests/build_tests/super_errors/expected/optional_default_arg_type_mismatch.res.expected new file mode 100644 index 0000000000..358e7a3e77 --- /dev/null +++ b/tests/build_tests/super_errors/expected/optional_default_arg_type_mismatch.res.expected @@ -0,0 +1,9 @@ + + We've found a bug for you! + /.../fixtures/optional_default_arg_type_mismatch.res:1:29-30 + + 1 │ let f = (~test: option=42) => () + 2 │ + + This has type: int + But it's expected to have type: option \ No newline at end of file diff --git a/tests/build_tests/super_errors/fixtures/optional_default_arg_type_mismatch.res b/tests/build_tests/super_errors/fixtures/optional_default_arg_type_mismatch.res new file mode 100644 index 0000000000..dde0728e85 --- /dev/null +++ b/tests/build_tests/super_errors/fixtures/optional_default_arg_type_mismatch.res @@ -0,0 +1 @@ +let f = (~test: option=42) => ()