diff --git a/compiler/forget/src/HIR/BuildHIR.ts b/compiler/forget/src/HIR/BuildHIR.ts
index 331706190f..6c5b77a0b5 100644
--- a/compiler/forget/src/HIR/BuildHIR.ts
+++ b/compiler/forget/src/HIR/BuildHIR.ts
@@ -960,8 +960,13 @@ function lowerExpression(
const place = buildTemporaryPlace(builder, loc);
const continuationBlock = builder.reserve(builder.currentBlockKind());
+ // Lower the callee in the current block: the callee is always unconditionally evaluated
+ // The test block's branch will test on this value to determine whether to evaluate the call (consequent)
+ // or evaluate to undefined (alternate)
const callee = lowerExpressionToTemporary(builder, calleePath);
+ // block to evaluate if the callee is non-null/undefined. arguments are lowered in this block to preserve
+ // the semantic of conditional evaluation depending on the callee
const consequent = builder.enter("value", () => {
const args = lowerArguments(builder, expr.get("arguments"));
const temp = buildTemporaryPlace(builder, loc);
@@ -994,6 +999,8 @@ function lowerExpression(
id: makeInstructionId(0),
};
});
+
+ // block to evaluate if the callee is null/undefined, this sets the result of the call to undefined.
const alternate = builder.enter("value", () => {
const temp = buildTemporaryPlace(builder, loc);
builder.push({
diff --git a/compiler/forget/src/__tests__/fixtures/compiler/call-with-independently-memoizable-arg.expect.md b/compiler/forget/src/__tests__/fixtures/compiler/call-with-independently-memoizable-arg.expect.md
new file mode 100644
index 0000000000..57e76125a0
--- /dev/null
+++ b/compiler/forget/src/__tests__/fixtures/compiler/call-with-independently-memoizable-arg.expect.md
@@ -0,0 +1,55 @@
+
+## Input
+
+```javascript
+function Component(props) {
+ const x = makeFunction(props);
+ const y = x(
+
+ {props.text}
+
+ );
+ return y;
+}
+
+```
+
+## Code
+
+```javascript
+function Component(props) {
+ const $ = React.unstable_useMemoCache(6);
+ const c_0 = $[0] !== props;
+ let t2;
+ if (c_0) {
+ const x = makeFunction(props);
+ const c_2 = $[2] !== props.text;
+ let t0;
+ if (c_2) {
+ t0 = {props.text};
+ $[2] = props.text;
+ $[3] = t0;
+ } else {
+ t0 = $[3];
+ }
+ const c_4 = $[4] !== t0;
+ let t1;
+ if (c_4) {
+ t1 = {t0}
;
+ $[4] = t0;
+ $[5] = t1;
+ } else {
+ t1 = $[5];
+ }
+ t2 = x(t1);
+ $[0] = props;
+ $[1] = t2;
+ } else {
+ t2 = $[1];
+ }
+ const y = t2;
+ return y;
+}
+
+```
+
\ No newline at end of file
diff --git a/compiler/forget/src/__tests__/fixtures/compiler/call-with-independently-memoizable-arg.js b/compiler/forget/src/__tests__/fixtures/compiler/call-with-independently-memoizable-arg.js
new file mode 100644
index 0000000000..0675b44287
--- /dev/null
+++ b/compiler/forget/src/__tests__/fixtures/compiler/call-with-independently-memoizable-arg.js
@@ -0,0 +1,9 @@
+function Component(props) {
+ const x = makeFunction(props);
+ const y = x(
+
+ {props.text}
+
+ );
+ return y;
+}
diff --git a/compiler/forget/src/__tests__/fixtures/compiler/optional-call-with-independently-memoizable-arg.expect.md b/compiler/forget/src/__tests__/fixtures/compiler/optional-call-with-independently-memoizable-arg.expect.md
new file mode 100644
index 0000000000..6bab00a43d
--- /dev/null
+++ b/compiler/forget/src/__tests__/fixtures/compiler/optional-call-with-independently-memoizable-arg.expect.md
@@ -0,0 +1,42 @@
+
+## Input
+
+```javascript
+function Component(props) {
+ const x = makeOptionalFunction(props);
+ // for a regular call, the JSX element could be independently memoized
+ // since it is an immutable value. however, because the call is optional,
+ // we can't extract out independent memoization for the element w/o
+ // forcing that argument to evaluate unconditionally
+ const y = x?.(
+
+ {props.text}
+
+ );
+ return y;
+}
+
+```
+
+## Code
+
+```javascript
+function Component(props) {
+ const $ = React.unstable_useMemoCache(2);
+ const c_0 = $[0] !== props;
+ let t0;
+ if (c_0) {
+ const x = makeOptionalFunction(props);
+
+ t0 = x?.({{props.text}}
);
+ $[0] = props;
+ $[1] = t0;
+ } else {
+ t0 = $[1];
+ }
+ const y = t0;
+ return y;
+}
+
+```
+
\ No newline at end of file
diff --git a/compiler/forget/src/__tests__/fixtures/compiler/optional-call-with-independently-memoizable-arg.js b/compiler/forget/src/__tests__/fixtures/compiler/optional-call-with-independently-memoizable-arg.js
new file mode 100644
index 0000000000..9d9abf887f
--- /dev/null
+++ b/compiler/forget/src/__tests__/fixtures/compiler/optional-call-with-independently-memoizable-arg.js
@@ -0,0 +1,13 @@
+function Component(props) {
+ const x = makeOptionalFunction(props);
+ // for a regular call, the JSX element could be independently memoized
+ // since it is an immutable value. however, because the call is optional,
+ // we can't extract out independent memoization for the element w/o
+ // forcing that argument to evaluate unconditionally
+ const y = x?.(
+
+ {props.text}
+
+ );
+ return y;
+}
diff --git a/compiler/forget/src/__tests__/fixtures/compiler/optional-call.expect.md b/compiler/forget/src/__tests__/fixtures/compiler/optional-call.expect.md
new file mode 100644
index 0000000000..3c30aeb83d
--- /dev/null
+++ b/compiler/forget/src/__tests__/fixtures/compiler/optional-call.expect.md
@@ -0,0 +1,35 @@
+
+## Input
+
+```javascript
+function Component(props) {
+ const x = makeOptionalFunction(props);
+ const y = makeObject(props);
+ const z = x?.(y.a, props.a, foo(y.b), bar(props.b));
+ return z;
+}
+
+```
+
+## Code
+
+```javascript
+function Component(props) {
+ const $ = React.unstable_useMemoCache(2);
+ const c_0 = $[0] !== props;
+ let t0;
+ if (c_0) {
+ const x = makeOptionalFunction(props);
+ const y = makeObject(props);
+ t0 = x?.(y.a, props.a, foo(y.b), bar(props.b));
+ $[0] = props;
+ $[1] = t0;
+ } else {
+ t0 = $[1];
+ }
+ const z = t0;
+ return z;
+}
+
+```
+
\ No newline at end of file
diff --git a/compiler/forget/src/__tests__/fixtures/compiler/optional-call.js b/compiler/forget/src/__tests__/fixtures/compiler/optional-call.js
new file mode 100644
index 0000000000..f4610a49f3
--- /dev/null
+++ b/compiler/forget/src/__tests__/fixtures/compiler/optional-call.js
@@ -0,0 +1,6 @@
+function Component(props) {
+ const x = makeOptionalFunction(props);
+ const y = makeObject(props);
+ const z = x?.(y.a, props.a, foo(y.b), bar(props.b));
+ return z;
+}