Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
#### :bug: Bug fix

- Fix compiler crash (`Fatal error: Parmatch.all_record_args`) when matching empty dict/record patterns. https://github.com/rescript-lang/rescript/pull/8246
- Fix `null` falling into the object branch instead of the wildcard when pattern matching on untagged variants with both `Object` and `null` cases. https://github.com/rescript-lang/rescript/pull/8253

#### :memo: Documentation

Expand Down
16 changes: 15 additions & 1 deletion compiler/core/lam_compile.ml
Original file line number Diff line number Diff line change
Expand Up @@ -814,6 +814,10 @@ let compile output_prefix =
| _ -> false
in
let clause_is_not_typeof (tag, _) = tag_is_not_typeof tag in
let clause_is_object_typeof = function
| Ast_untagged_variants.Untagged ObjectType, _ -> true
| _ -> false
in
let switch ?default ?declaration e clauses =
let not_typeof_clauses, typeof_clauses =
List.partition clause_is_not_typeof clauses
Expand All @@ -827,7 +831,17 @@ let compile output_prefix =
(E.emit_check (IsInstanceOf (instance_type, Expr e)))
switch_body
~else_:[build_if_chain rest]
| _ -> S.string_switch ?default ?declaration (E.typeof e) typeof_clauses
| _ ->
let typeof_switch () =
S.string_switch ?default ?declaration (E.typeof e) typeof_clauses
in
if has_null_case && List.exists clause_is_object_typeof typeof_clauses
then
match default with
| Some default_body ->
S.if_ (E.is_null e) default_body ~else_:[typeof_switch ()]
| None -> typeof_switch ()
else typeof_switch ()
in
build_if_chain not_typeof_clauses
in
Expand Down
46 changes: 33 additions & 13 deletions tests/tests/src/js_json_test.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -367,24 +367,44 @@ Mocha.describe("Js_json_test", () => {
Test_utils.eq("File \"js_json_test.res\", line 314, characters 7-14", Js_json.decodeArray({}), undefined);
Test_utils.eq("File \"js_json_test.res\", line 315, characters 7-14", Js_json.decodeArray(1.23), undefined);
});
Mocha.test("JSON Array/Object switch falls through to wildcard on null", () => {
let classifyArrayOrObject = json => {
if (Array.isArray(json)) {
return json.length;
}
if (json === null) {
return;
}
switch (typeof json) {
case "object" :
Js_dict.get(json, "x");
return 0;
default:
return;
}
};
Test_utils.eq("File \"js_json_test.res\", line 328, characters 7-14", classifyArrayOrObject(null), undefined);
Test_utils.eq("File \"js_json_test.res\", line 329, characters 7-14", classifyArrayOrObject([1]), 1);
Test_utils.eq("File \"js_json_test.res\", line 330, characters 7-14", classifyArrayOrObject({}), 0);
});
Mocha.test("JSON decodeBoolean", () => {
Test_utils.eq("File \"js_json_test.res\", line 319, characters 7-14", Js_json.decodeBoolean("test"), undefined);
Test_utils.eq("File \"js_json_test.res\", line 320, characters 7-14", Js_json.decodeBoolean(true), true);
Test_utils.eq("File \"js_json_test.res\", line 321, characters 7-14", Js_json.decodeBoolean([]), undefined);
Test_utils.eq("File \"js_json_test.res\", line 322, characters 7-14", Js_json.decodeBoolean(null), undefined);
Test_utils.eq("File \"js_json_test.res\", line 323, characters 7-14", Js_json.decodeBoolean({}), undefined);
Test_utils.eq("File \"js_json_test.res\", line 324, characters 7-14", Js_json.decodeBoolean(1.23), undefined);
Test_utils.eq("File \"js_json_test.res\", line 334, characters 7-14", Js_json.decodeBoolean("test"), undefined);
Test_utils.eq("File \"js_json_test.res\", line 335, characters 7-14", Js_json.decodeBoolean(true), true);
Test_utils.eq("File \"js_json_test.res\", line 336, characters 7-14", Js_json.decodeBoolean([]), undefined);
Test_utils.eq("File \"js_json_test.res\", line 337, characters 7-14", Js_json.decodeBoolean(null), undefined);
Test_utils.eq("File \"js_json_test.res\", line 338, characters 7-14", Js_json.decodeBoolean({}), undefined);
Test_utils.eq("File \"js_json_test.res\", line 339, characters 7-14", Js_json.decodeBoolean(1.23), undefined);
});
Mocha.test("JSON decodeNull", () => {
Test_utils.eq("File \"js_json_test.res\", line 328, characters 7-14", Js_json.decodeNull("test"), undefined);
Test_utils.eq("File \"js_json_test.res\", line 329, characters 7-14", Js_json.decodeNull(true), undefined);
Test_utils.eq("File \"js_json_test.res\", line 330, characters 7-14", Js_json.decodeNull([]), undefined);
Test_utils.eq("File \"js_json_test.res\", line 331, characters 7-14", Js_json.decodeNull(null), null);
Test_utils.eq("File \"js_json_test.res\", line 332, characters 7-14", Js_json.decodeNull({}), undefined);
Test_utils.eq("File \"js_json_test.res\", line 333, characters 7-14", Js_json.decodeNull(1.23), undefined);
Test_utils.eq("File \"js_json_test.res\", line 343, characters 7-14", Js_json.decodeNull("test"), undefined);
Test_utils.eq("File \"js_json_test.res\", line 344, characters 7-14", Js_json.decodeNull(true), undefined);
Test_utils.eq("File \"js_json_test.res\", line 345, characters 7-14", Js_json.decodeNull([]), undefined);
Test_utils.eq("File \"js_json_test.res\", line 346, characters 7-14", Js_json.decodeNull(null), null);
Test_utils.eq("File \"js_json_test.res\", line 347, characters 7-14", Js_json.decodeNull({}), undefined);
Test_utils.eq("File \"js_json_test.res\", line 348, characters 7-14", Js_json.decodeNull(1.23), undefined);
});
Mocha.test("JSON serialize/deserialize identity", () => {
let idtest = obj => Test_utils.eq("File \"js_json_test.res\", line 339, characters 27-34", obj, Js_json.deserializeUnsafe(Js_json.serializeExn(obj)));
let idtest = obj => Test_utils.eq("File \"js_json_test.res\", line 354, characters 27-34", obj, Js_json.deserializeUnsafe(Js_json.serializeExn(obj)));
idtest(undefined);
idtest({
hd: [
Expand Down
15 changes: 15 additions & 0 deletions tests/tests/src/js_json_test.res
Original file line number Diff line number Diff line change
Expand Up @@ -315,6 +315,21 @@ describe(__MODULE__, () => {
eq(__LOC__, J.decodeArray(J.number(1.23)), None)
})

test("JSON Array/Object switch falls through to wildcard on null", () => {
let classifyArrayOrObject = (json: J.t) =>
switch json {
| J.Array(items) => Some(items->Js.Array2.length)
| J.Object(dict) =>
ignore(Js.Dict.get(dict, "x"))
Some(0)
| _ => None
}

eq(__LOC__, classifyArrayOrObject(J.null), None)
eq(__LOC__, classifyArrayOrObject(J.array([J.number(1.)])), Some(1))
eq(__LOC__, classifyArrayOrObject(J.object_(Js.Dict.empty())), Some(0))
})

test("JSON decodeBoolean", () => {
eq(__LOC__, J.decodeBoolean(J.string("test")), None)
eq(__LOC__, J.decodeBoolean(J.boolean(true)), Some(true))
Expand Down
Loading