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 changes/fold-known-some-unwrap.polish.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
- Drop `Primitive_option.some`/`valFromOption` calls when matching on `Some(x)` with `x` a variable.
6 changes: 6 additions & 0 deletions compiler/core/lam_pass_remove_alias.ml
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,12 @@ let simplify_alias (meta : Lam_stats.t) (lam : Lambda.t) : Lambda.t =
} as x -> (
match Hash_ident.find_opt meta.ident_tbl v with
| Some (OptionalBlock (l, _)) -> l
(* [v] bound to [Some(l)]: unwrapping gives back [l], whether or not
it was nested. Only substitute forms that are safe to repeat. *)
| Some (Normal_optional (Lvar _ as l)) -> l
| Some (Normal_optional (Lconst c as l))
when not (Lambda.const_is_allocating c) ->
l
| _ -> if p = Pval_from_option_not_nest then lvar else x)
| Lifthenelse (Lprim {primitive = Pis_not_none; args = [Lvar id]}, l2, l3)
-> (
Expand Down
66 changes: 66 additions & 0 deletions tests/tests/src/option_known_some_test.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
// Generated by ReScript, PLEASE EDIT WITH CARE

import * as Mocha from "mocha";
import * as Test_utils from "./test_utils.mjs";
import * as Primitive_option from "@rescript/runtime/lib/es6/Primitive_option.mjs";

function nested(y) {
if (y !== undefined) {
return y;
} else {
return 0;
}
}

function poly(y) {
return [y];
}

let calls = {
contents: 0
};

function next() {
calls.contents = calls.contents + 1 | 0;
if (calls.contents > 1) {
return calls.contents;
}
}

function effectful() {
let n = Primitive_option.some(next());
let n$1 = Primitive_option.valFromOption(n);
if (n$1 !== undefined) {
return n$1;
} else {
return 0;
}
}

Mocha.describe("Option_known_some_test", () => {
Mocha.test("nested payload", () => {
Test_utils.eq("File \"option_known_some_test.res\", line 35, characters 7-14", 0, 0);
Test_utils.eq("File \"option_known_some_test.res\", line 36, characters 7-14", 3, 3);
});
Mocha.test("polymorphic payload", () => {
Test_utils.eq("File \"option_known_some_test.res\", line 39, characters 7-14", [undefined], [undefined]);
let v = Primitive_option.some(Primitive_option.some(undefined));
Test_utils.eq("File \"option_known_some_test.res\", line 40, characters 7-14", [Primitive_option.some(undefined)], [Primitive_option.valFromOption(v)]);
Test_utils.eq("File \"option_known_some_test.res\", line 41, characters 7-14", [1], [1]);
});
Mocha.test("payload with side effects", () => {
Test_utils.eq("File \"option_known_some_test.res\", line 44, characters 7-14", 0, effectful());
Test_utils.eq("File \"option_known_some_test.res\", line 45, characters 7-14", 1, calls.contents);
Test_utils.eq("File \"option_known_some_test.res\", line 46, characters 7-14", 2, effectful());
Test_utils.eq("File \"option_known_some_test.res\", line 47, characters 7-14", 2, calls.contents);
});
});

export {
nested,
poly,
calls,
next,
effectful,
}
/* Not a pure module */
49 changes: 49 additions & 0 deletions tests/tests/src/option_known_some_test.res
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
open Mocha
open Test_utils

// Matching on [Some(x)] with [x] a variable reads [x] directly: no
// Primitive_option.some / valFromOption calls in the output.
let nested = (y: option<int>) =>
switch Some(y) {
| Some(Some(n)) => n
| Some(None) => 0
| None => -1
}

let poly = (y: 'a) =>
switch Some(y) {
| Some(v) => [v]
| None => []
}

// A payload with side effects is evaluated once.
let calls = ref(0)
let next = () => {
calls := calls.contents + 1
calls.contents > 1 ? Some(calls.contents) : None
}

let effectful = () =>
switch Some(next()) {
| Some(Some(n)) => n
| Some(None) => 0
| None => -1
}

describe(__MODULE__, () => {
test("nested payload", () => {
eq(__LOC__, 0, nested(None))
eq(__LOC__, 3, nested(Some(3)))
})
test("polymorphic payload", () => {
eq(__LOC__, [None], poly((None: option<int>)))
eq(__LOC__, [Some(None)], poly((Some(None): option<option<int>>)))
eq(__LOC__, [1], poly(1))
})
test("payload with side effects", () => {
eq(__LOC__, 0, effectful())
eq(__LOC__, 1, calls.contents)
eq(__LOC__, 2, effectful())
eq(__LOC__, 2, calls.contents)
})
})
11 changes: 3 additions & 8 deletions tests/tests/src/option_optimisation.mjs
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
// Generated by ReScript, PLEASE EDIT WITH CARE

import * as Primitive_option from "@rescript/runtime/lib/es6/Primitive_option.mjs";

function boolean(val1, val2) {
if (val2 || val1) {
Expand All @@ -11,15 +10,11 @@ function boolean(val1, val2) {
}

function $$null(val1, val2) {
let a = Primitive_option.some(val1);
let b = Primitive_option.some(val2);
let tmp = Primitive_option.valFromOption(b);
if (tmp !== null && tmp !== undefined) {
if (val2 !== null && val2 !== undefined) {
return "a";
}
tmp === null;
let tmp$1 = Primitive_option.valFromOption(a);
if (tmp$1 == null) {
val2 === null;
if (val1 == null) {
return "b";
} else {
return "a";
Expand Down
Loading