Skip to content

Commit

Permalink
Improve error message when an object is passed where a record is expe…
Browse files Browse the repository at this point in the history
…cted (#7101)

* improve error message when an object is passed where a record is expected

* changelog
  • Loading branch information
zth authored Oct 13, 2024
1 parent e1b7fb7 commit e050527
Show file tree
Hide file tree
Showing 5 changed files with 40 additions and 2 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@
- Improve error messages around JSX components. https://github.com/rescript-lang/rescript-compiler/pull/7038
- Improve output of record copying. https://github.com/rescript-lang/rescript-compiler/pull/7043
- Provide additional context in error message when `unit` is expected. https://github.com/rescript-lang/rescript-compiler/pull/7045
- Improve error message when passing an object where a record is expected. https://github.com/rescript-lang/rescript-compiler/pull/7101

#### :house: Internal

Expand Down
19 changes: 18 additions & 1 deletion compiler/ml/error_message_utils.ml
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,15 @@ let error_expected_type_text ppf type_clash_context =
fprintf ppf "But this function is expecting you to return:"
| _ -> fprintf ppf "But it's expected to have type:"

let print_extra_type_clash_help ppf trace type_clash_context =
let is_record_type ~extract_concrete_typedecl ~env ty =
try
match extract_concrete_typedecl env ty with
| _, _, {Types.type_kind = Type_record _; _} -> true
| _ -> false
with _ -> false

let print_extra_type_clash_help ~extract_concrete_typedecl ~env ppf trace
type_clash_context =
match (type_clash_context, trace) with
| Some (MathOperator {for_float; operator; is_constant}), _ -> (
let operator_for_other_type =
Expand Down Expand Up @@ -176,6 +184,15 @@ let print_extra_type_clash_help ppf trace type_clash_context =
\ - If you don't care about the result of this expression, you can \
assign it to @{<info>_@} via @{<info>let _ = ...@} or pipe it to \
@{<info>ignore@} via @{<info>expression->ignore@}\n\n"
| _, [({desc = Tobject _}, _); (({Types.desc = Tconstr _} as t1), _)]
when is_record_type ~extract_concrete_typedecl ~env t1 ->
fprintf ppf
"\n\n\
\ You're passing a @{<error>ReScript object@} where a @{<info>record@} \
is expected. \n\n\
\ - Did you mean to pass a record instead of an object? Objects are \
written with quoted keys, and records with unquoted keys. Remove the \
quotes from the object keys to pass it as a record instead of object. \n\n"
| _ -> ()

let type_clash_context_from_function sexp sfunct =
Expand Down
3 changes: 2 additions & 1 deletion compiler/ml/typecore.ml
Original file line number Diff line number Diff line change
Expand Up @@ -814,7 +814,8 @@ let print_expr_type_clash ?type_clash_context env trace ppf =
| ppf -> error_type_text ppf type_clash_context)
(function
| ppf -> error_expected_type_text ppf type_clash_context);
print_extra_type_clash_help ppf trace type_clash_context;
print_extra_type_clash_help ~extract_concrete_typedecl ~env ppf trace
type_clash_context;
show_extra_help ppf env trace

let report_arity_mismatch ~arity_a ~arity_b ppf =
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@

We've found a bug for you!
/.../fixtures/object_passed_when_record_expected.res:4:14-26

2 │ type xx = array<x>
3 │
4 │ let x: xx = [{"one": true}]
5 │

This has type: {"one": bool}
But it's expected to have type: x

You're passing a ReScript object where a record is expected.

- Did you mean to pass a record instead of an object? Objects are written with quoted keys, and records with unquoted keys. Remove the quotes from the object keys to pass it as a record instead of object.
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
type x = {one: bool}
type xx = array<x>

let x: xx = [{"one": true}]

0 comments on commit e050527

Please sign in to comment.