diff --git a/CHANGELOG.md b/CHANGELOG.md index 870c63b415..9eedca833b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -28,6 +28,7 @@ - Better error message if platform binaries package is not found. https://github.com/rescript-lang/rescript/pull/7698 - Hint in error for string constants matching expected variant/polyvariant constructor. https://github.com/rescript-lang/rescript/pull/7711 - Polish arity mismatch error message a bit. https://github.com/rescript-lang/rescript/pull/7709 +- Improve error when a constructor expects an inline record. https://github.com/rescript-lang/rescript/pull/7713 #### :house: Internal diff --git a/compiler/ml/typecore.ml b/compiler/ml/typecore.ml index feff8336c2..060816f684 100644 --- a/compiler/ml/typecore.ml +++ b/compiler/ml/typecore.ml @@ -26,7 +26,12 @@ open Error_message_utils type error = | Polymorphic_label of Longident.t - | Constructor_arity_mismatch of Longident.t * int * int + | Constructor_arity_mismatch of { + name: Longident.t; + constuctor: constructor_description; + expected: int; + provided: int; + } | Label_mismatch of Longident.t * (type_expr * type_expr) list | Pattern_type_clash of (type_expr * type_expr) list | Or_pattern_type_clash of Ident.t * (type_expr * type_expr) list @@ -1395,7 +1400,12 @@ and type_pat_aux ~constrs ~labels ~no_existentials ~mode ~explode ~env sp ( loc, !env, Constructor_arity_mismatch - (lid.txt, constr.cstr_arity, List.length sargs) )); + { + name = lid.txt; + constuctor = constr; + expected = constr.cstr_arity; + provided = List.length sargs; + } )); let ty_args, ty_res = instance_constructor ~in_pattern:(env, get_newtype_level ()) constr in @@ -3742,7 +3752,12 @@ and type_construct ~context env loc lid sarg ty_expected attrs = ( loc, env, Constructor_arity_mismatch - (lid.txt, constr.cstr_arity, List.length sargs) )); + { + name = lid.txt; + constuctor = constr; + expected = constr.cstr_arity; + provided = List.length sargs; + } )); let separate = Env.has_local_constraints env in if separate then ( begin_def (); @@ -4245,14 +4260,24 @@ let report_error env loc ppf error = | Polymorphic_label lid -> fprintf ppf "@[The record field %a is polymorphic.@ %s@]" longident lid "You cannot instantiate it in a pattern." - | Constructor_arity_mismatch (lid, expected, provided) -> + | Constructor_arity_mismatch {name; constuctor; expected; provided} -> (* modified *) - fprintf ppf - "@[This variant constructor, %a, expects %i %s; here, we've %sfound %i.@]" - longident lid expected - (if expected == 1 then "argument" else "arguments") - (if provided < expected then "only " else "") - provided + let is_inline_record = Option.is_some constuctor.cstr_inlined in + if is_inline_record && expected = 1 then + fprintf ppf + "@[This variant constructor @{%a@} expects an inline record as \ + payload%s.@]" + longident name + (if provided = 0 then ", but it's not being passed any arguments" + else "") + else + fprintf ppf + "@[This variant constructor @{%a@} expects %i %s, but it's%s \ + being passed %i.@]" + longident name expected + (if expected == 1 then "argument" else "arguments") + (if provided < expected then " only" else "") + provided | Label_mismatch (lid, trace) -> (* modified *) super_report_unification_error ppf env trace diff --git a/compiler/ml/typecore.mli b/compiler/ml/typecore.mli index f615c226ec..d262fe4280 100644 --- a/compiler/ml/typecore.mli +++ b/compiler/ml/typecore.mli @@ -58,7 +58,12 @@ val name_pattern : string -> Typedtree.case list -> Ident.t type error = | Polymorphic_label of Longident.t - | Constructor_arity_mismatch of Longident.t * int * int + | Constructor_arity_mismatch of { + name: Longident.t; + constuctor: constructor_description; + expected: int; + provided: int; + } | Label_mismatch of Longident.t * (type_expr * type_expr) list | Pattern_type_clash of (type_expr * type_expr) list | Or_pattern_type_clash of Ident.t * (type_expr * type_expr) list diff --git a/tests/build_tests/super_errors/expected/primitives5.res.expected b/tests/build_tests/super_errors/expected/primitives5.res.expected index 31847d4b95..f0ab6795ce 100644 --- a/tests/build_tests/super_errors/expected/primitives5.res.expected +++ b/tests/build_tests/super_errors/expected/primitives5.res.expected @@ -7,4 +7,4 @@ 3 │ X(10)->ignore 4 │ - This variant constructor, X, expects 2 arguments; here, we've only found 1. \ No newline at end of file + This variant constructor X expects 2 arguments, but it's only being passed 1. \ No newline at end of file diff --git a/tests/build_tests/super_errors/expected/variant_constructor_expects_inline_record.res.expected b/tests/build_tests/super_errors/expected/variant_constructor_expects_inline_record.res.expected new file mode 100644 index 0000000000..4e235656ea --- /dev/null +++ b/tests/build_tests/super_errors/expected/variant_constructor_expects_inline_record.res.expected @@ -0,0 +1,9 @@ + + We've found a bug for you! + /.../fixtures/variant_constructor_expects_inline_record.res:2:9-11 + + 1 │ type x = One({test: bool}) + 2 │ let f = One + 3 │ + + This variant constructor One expects an inline record as payload, but it's not being passed any arguments. \ No newline at end of file diff --git a/tests/build_tests/super_errors/fixtures/variant_constructor_expects_inline_record.res b/tests/build_tests/super_errors/fixtures/variant_constructor_expects_inline_record.res new file mode 100644 index 0000000000..b5c83fe554 --- /dev/null +++ b/tests/build_tests/super_errors/fixtures/variant_constructor_expects_inline_record.res @@ -0,0 +1,2 @@ +type x = One({test: bool}) +let f = One