diff --git a/compiler/packages/babel-plugin-react-compiler/src/ReactiveScopes/BuildReactiveFunction.ts b/compiler/packages/babel-plugin-react-compiler/src/ReactiveScopes/BuildReactiveFunction.ts
index 2e8584050e..2574116234 100644
--- a/compiler/packages/babel-plugin-react-compiler/src/ReactiveScopes/BuildReactiveFunction.ts
+++ b/compiler/packages/babel-plugin-react-compiler/src/ReactiveScopes/BuildReactiveFunction.ts
@@ -1104,7 +1104,7 @@ class Driver {
loc,
};
return {
- block: init.fallthrough,
+ block: final.block,
value: sequence,
place: final.place,
id: final.id,
diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/chained-optionals-with-nullish-coalesce-with-method.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/chained-optionals-with-nullish-coalesce-with-method.expect.md
new file mode 100644
index 0000000000..a770e7aa9f
--- /dev/null
+++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/chained-optionals-with-nullish-coalesce-with-method.expect.md
@@ -0,0 +1,109 @@
+
+## Input
+
+```javascript
+import {Stringify} from 'shared-runtime';
+
+// Test chained optional property access with nullish coalescing and method call
+function Component(props: {obj: {a?: {b?: {getC(): string}}} | null}) {
+ 'use memo';
+ const result = props.obj?.a?.b?.getC() ?? 'default';
+ return ;
+}
+
+export const FIXTURE_ENTRYPOINT = {
+ fn: Component,
+ params: [{obj: {a: {b: {getC: () => 'deep'}}}}],
+ sequentialRenders: [
+ {obj: {a: {b: {getC: () => 'deep'}}}},
+ {obj: null},
+ {obj: {a: null}},
+ {obj: {a: {b: null}}},
+ {obj: {a: {b: {getC: () => 'other'}}}},
+ ],
+};
+
+```
+
+## Code
+
+```javascript
+import { c as _c } from "react/compiler-runtime";
+import { Stringify } from "shared-runtime";
+
+// Test chained optional property access with nullish coalescing and method call
+function Component(props) {
+ "use memo";
+ const $ = _c(4);
+ let t0;
+ if ($[0] !== props.obj?.a?.b) {
+ t0 = props.obj?.a?.b?.getC() ?? "default";
+ $[0] = props.obj?.a?.b;
+ $[1] = t0;
+ } else {
+ t0 = $[1];
+ }
+ const result = t0;
+ let t1;
+ if ($[2] !== result) {
+ t1 = ;
+ $[2] = result;
+ $[3] = t1;
+ } else {
+ t1 = $[3];
+ }
+ return t1;
+}
+
+export const FIXTURE_ENTRYPOINT = {
+ fn: Component,
+ params: [
+ {
+ obj: {
+ a: {
+ b: {
+ getC: () => {
+ return "deep";
+ },
+ },
+ },
+ },
+ },
+ ],
+ sequentialRenders: [
+ {
+ obj: {
+ a: {
+ b: {
+ getC: () => {
+ return "deep";
+ },
+ },
+ },
+ },
+ },
+ { obj: null },
+ { obj: { a: null } },
+ { obj: { a: { b: null } } },
+ {
+ obj: {
+ a: {
+ b: {
+ getC: () => {
+ return "other";
+ },
+ },
+ },
+ },
+ },
+ ],
+};
+
+```
+
+### Eval output
+(kind: ok)
{"value":"deep"}
+{"value":"default"}
+{"value":"default"}
+{"value":"default"}
+{"value":"other"}
\ No newline at end of file
diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/chained-optionals-with-nullish-coalesce-with-method.tsx b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/chained-optionals-with-nullish-coalesce-with-method.tsx
new file mode 100644
index 0000000000..9c4048e8c8
--- /dev/null
+++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/chained-optionals-with-nullish-coalesce-with-method.tsx
@@ -0,0 +1,20 @@
+import {Stringify} from 'shared-runtime';
+
+// Test chained optional property access with nullish coalescing and method call
+function Component(props: {obj: {a?: {b?: {getC(): string}}} | null}) {
+ 'use memo';
+ const result = props.obj?.a?.b?.getC() ?? 'default';
+ return ;
+}
+
+export const FIXTURE_ENTRYPOINT = {
+ fn: Component,
+ params: [{obj: {a: {b: {getC: () => 'deep'}}}}],
+ sequentialRenders: [
+ {obj: {a: {b: {getC: () => 'deep'}}}},
+ {obj: null},
+ {obj: {a: null}},
+ {obj: {a: {b: null}}},
+ {obj: {a: {b: {getC: () => 'other'}}}},
+ ],
+};
diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/chained-optionals-with-nullish-coalesce.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/chained-optionals-with-nullish-coalesce.expect.md
new file mode 100644
index 0000000000..8b8dce7597
--- /dev/null
+++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/chained-optionals-with-nullish-coalesce.expect.md
@@ -0,0 +1,53 @@
+
+## Input
+
+```javascript
+// Test chained optional property access with nullish coalescing
+function Component(props: {obj: {a?: {b?: {c: string}}} | null}) {
+ 'use memo';
+ return props.obj?.a?.b?.c ?? 'default';
+}
+
+export const FIXTURE_ENTRYPOINT = {
+ fn: Component,
+ params: [{obj: {a: {b: {c: 'deep'}}}}],
+ sequentialRenders: [
+ {obj: {a: {b: {c: 'deep'}}}},
+ {obj: null},
+ {obj: {a: null}},
+ {obj: {a: {b: null}}},
+ {obj: {a: {b: {c: 'other'}}}},
+ ],
+};
+
+```
+
+## Code
+
+```javascript
+// Test chained optional property access with nullish coalescing
+function Component(props) {
+ "use memo";
+ return props.obj?.a?.b?.c ?? "default";
+}
+
+export const FIXTURE_ENTRYPOINT = {
+ fn: Component,
+ params: [{ obj: { a: { b: { c: "deep" } } } }],
+ sequentialRenders: [
+ { obj: { a: { b: { c: "deep" } } } },
+ { obj: null },
+ { obj: { a: null } },
+ { obj: { a: { b: null } } },
+ { obj: { a: { b: { c: "other" } } } },
+ ],
+};
+
+```
+
+### Eval output
+(kind: ok) "deep"
+"default"
+"default"
+"default"
+"other"
\ No newline at end of file
diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/chained-optionals-with-nullish-coalesce.ts b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/chained-optionals-with-nullish-coalesce.ts
new file mode 100644
index 0000000000..20852905f6
--- /dev/null
+++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/chained-optionals-with-nullish-coalesce.ts
@@ -0,0 +1,17 @@
+// Test chained optional property access with nullish coalescing
+function Component(props: {obj: {a?: {b?: {c: string}}} | null}) {
+ 'use memo';
+ return props.obj?.a?.b?.c ?? 'default';
+}
+
+export const FIXTURE_ENTRYPOINT = {
+ fn: Component,
+ params: [{obj: {a: {b: {c: 'deep'}}}}],
+ sequentialRenders: [
+ {obj: {a: {b: {c: 'deep'}}}},
+ {obj: null},
+ {obj: {a: null}},
+ {obj: {a: {b: null}}},
+ {obj: {a: {b: {c: 'other'}}}},
+ ],
+};
diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/deeply-nested-optional-ternary-logical-with-method.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/deeply-nested-optional-ternary-logical-with-method.expect.md
new file mode 100644
index 0000000000..b58187a175
--- /dev/null
+++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/deeply-nested-optional-ternary-logical-with-method.expect.md
@@ -0,0 +1,135 @@
+
+## Input
+
+```javascript
+import {Stringify} from 'shared-runtime';
+
+// Test deeply nested: optional in ternary condition with logical fallback using method calls
+function Component(props: {
+ value: {getFlag(): boolean; getData(): string} | null;
+ fallback: string;
+}) {
+ 'use memo';
+ const value = props.value;
+ const result = (value?.getFlag() ? value?.getData() : null) ?? props.fallback;
+ return ;
+}
+
+export const FIXTURE_ENTRYPOINT = {
+ fn: Component,
+ params: [
+ {
+ value: {getFlag: () => true, getData: () => 'success'},
+ fallback: 'default',
+ },
+ ],
+ sequentialRenders: [
+ {
+ value: {getFlag: () => true, getData: () => 'success'},
+ fallback: 'default',
+ },
+ {
+ value: {getFlag: () => false, getData: () => 'success'},
+ fallback: 'default',
+ },
+ {value: null, fallback: 'default'},
+ {value: {getFlag: () => true, getData: () => 'other'}, fallback: 'default'},
+ ],
+};
+
+```
+
+## Code
+
+```javascript
+import { c as _c } from "react/compiler-runtime";
+import { Stringify } from "shared-runtime";
+
+// Test deeply nested: optional in ternary condition with logical fallback using method calls
+function Component(props) {
+ "use memo";
+ const $ = _c(5);
+
+ const value = props.value;
+ let t0;
+ if ($[0] !== props.fallback || $[1] !== value) {
+ t0 = (value?.getFlag() ? value?.getData() : null) ?? props.fallback;
+ $[0] = props.fallback;
+ $[1] = value;
+ $[2] = t0;
+ } else {
+ t0 = $[2];
+ }
+ const result = t0;
+ let t1;
+ if ($[3] !== result) {
+ t1 = ;
+ $[3] = result;
+ $[4] = t1;
+ } else {
+ t1 = $[4];
+ }
+ return t1;
+}
+
+export const FIXTURE_ENTRYPOINT = {
+ fn: Component,
+ params: [
+ {
+ value: {
+ getFlag: () => {
+ return true;
+ },
+ getData: () => {
+ return "success";
+ },
+ },
+ fallback: "default",
+ },
+ ],
+
+ sequentialRenders: [
+ {
+ value: {
+ getFlag: () => {
+ return true;
+ },
+ getData: () => {
+ return "success";
+ },
+ },
+ fallback: "default",
+ },
+ {
+ value: {
+ getFlag: () => {
+ return false;
+ },
+ getData: () => {
+ return "success";
+ },
+ },
+ fallback: "default",
+ },
+ { value: null, fallback: "default" },
+ {
+ value: {
+ getFlag: () => {
+ return true;
+ },
+ getData: () => {
+ return "other";
+ },
+ },
+ fallback: "default",
+ },
+ ],
+};
+
+```
+
+### Eval output
+(kind: ok) {"value":"success"}
+{"value":"default"}
+{"value":"default"}
+{"value":"other"}
\ No newline at end of file
diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/deeply-nested-optional-ternary-logical-with-method.tsx b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/deeply-nested-optional-ternary-logical-with-method.tsx
new file mode 100644
index 0000000000..64f21291ee
--- /dev/null
+++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/deeply-nested-optional-ternary-logical-with-method.tsx
@@ -0,0 +1,34 @@
+import {Stringify} from 'shared-runtime';
+
+// Test deeply nested: optional in ternary condition with logical fallback using method calls
+function Component(props: {
+ value: {getFlag(): boolean; getData(): string} | null;
+ fallback: string;
+}) {
+ 'use memo';
+ const value = props.value;
+ const result = (value?.getFlag() ? value?.getData() : null) ?? props.fallback;
+ return ;
+}
+
+export const FIXTURE_ENTRYPOINT = {
+ fn: Component,
+ params: [
+ {
+ value: {getFlag: () => true, getData: () => 'success'},
+ fallback: 'default',
+ },
+ ],
+ sequentialRenders: [
+ {
+ value: {getFlag: () => true, getData: () => 'success'},
+ fallback: 'default',
+ },
+ {
+ value: {getFlag: () => false, getData: () => 'success'},
+ fallback: 'default',
+ },
+ {value: null, fallback: 'default'},
+ {value: {getFlag: () => true, getData: () => 'other'}, fallback: 'default'},
+ ],
+};
diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/deeply-nested-optional-ternary-logical.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/deeply-nested-optional-ternary-logical.expect.md
new file mode 100644
index 0000000000..cdaaae8c64
--- /dev/null
+++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/deeply-nested-optional-ternary-logical.expect.md
@@ -0,0 +1,64 @@
+
+## Input
+
+```javascript
+// Test deeply nested: optional in ternary condition with logical fallback
+function Component(props: {
+ value: {flag: boolean; data: string} | null;
+ fallback: string;
+}) {
+ 'use memo';
+ const value = props.value;
+ return (value?.flag ? value?.data : null) ?? props.fallback;
+}
+
+export const FIXTURE_ENTRYPOINT = {
+ fn: Component,
+ params: [{value: {flag: true, data: 'success'}, fallback: 'default'}],
+ sequentialRenders: [
+ // flag true, returns data
+ {value: {flag: true, data: 'success'}, fallback: 'default'},
+ // flag false, ternary returns null, falls back
+ {value: {flag: false, data: 'success'}, fallback: 'default'},
+ // value is null, value?.flag is undefined/falsy, ternary returns null, falls back
+ {value: null, fallback: 'default'},
+ // different data value
+ {value: {flag: true, data: 'other'}, fallback: 'default'},
+ ],
+};
+
+```
+
+## Code
+
+```javascript
+// Test deeply nested: optional in ternary condition with logical fallback
+function Component(props) {
+ "use memo";
+
+ const value = props.value;
+ return (value?.flag ? value?.data : null) ?? props.fallback;
+}
+
+export const FIXTURE_ENTRYPOINT = {
+ fn: Component,
+ params: [{ value: { flag: true, data: "success" }, fallback: "default" }],
+ sequentialRenders: [
+ // flag true, returns data
+ { value: { flag: true, data: "success" }, fallback: "default" },
+ // flag false, ternary returns null, falls back
+ { value: { flag: false, data: "success" }, fallback: "default" },
+ // value is null, value?.flag is undefined/falsy, ternary returns null, falls back
+ { value: null, fallback: "default" },
+ // different data value
+ { value: { flag: true, data: "other" }, fallback: "default" },
+ ],
+};
+
+```
+
+### Eval output
+(kind: ok) "success"
+"default"
+"default"
+"other"
\ No newline at end of file
diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/deeply-nested-optional-ternary-logical.ts b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/deeply-nested-optional-ternary-logical.ts
new file mode 100644
index 0000000000..6c86f93e53
--- /dev/null
+++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/deeply-nested-optional-ternary-logical.ts
@@ -0,0 +1,24 @@
+// Test deeply nested: optional in ternary condition with logical fallback
+function Component(props: {
+ value: {flag: boolean; data: string} | null;
+ fallback: string;
+}) {
+ 'use memo';
+ const value = props.value;
+ return (value?.flag ? value?.data : null) ?? props.fallback;
+}
+
+export const FIXTURE_ENTRYPOINT = {
+ fn: Component,
+ params: [{value: {flag: true, data: 'success'}, fallback: 'default'}],
+ sequentialRenders: [
+ // flag true, returns data
+ {value: {flag: true, data: 'success'}, fallback: 'default'},
+ // flag false, ternary returns null, falls back
+ {value: {flag: false, data: 'success'}, fallback: 'default'},
+ // value is null, value?.flag is undefined/falsy, ternary returns null, falls back
+ {value: null, fallback: 'default'},
+ // different data value
+ {value: {flag: true, data: 'other'}, fallback: 'default'},
+ ],
+};
diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.todo-optional-call-chain-in-logical-expr.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.todo-optional-call-chain-in-logical-expr.expect.md
deleted file mode 100644
index 38bb5800a8..0000000000
--- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.todo-optional-call-chain-in-logical-expr.expect.md
+++ /dev/null
@@ -1,37 +0,0 @@
-
-## Input
-
-```javascript
-import {useNoAlias} from 'shared-runtime';
-
-function useFoo(props: {value: {x: string; y: string} | null}) {
- const value = props.value;
- return useNoAlias(value?.x, value?.y) ?? {};
-}
-
-export const FIXTURE_ENTRYPONT = {
- fn: useFoo,
- props: [{value: null}],
-};
-
-```
-
-
-## Error
-
-```
-Found 1 error:
-
-Todo: Unexpected terminal kind `optional` for logical test block
-
-error.todo-optional-call-chain-in-logical-expr.ts:5:30
- 3 | function useFoo(props: {value: {x: string; y: string} | null}) {
- 4 | const value = props.value;
-> 5 | return useNoAlias(value?.x, value?.y) ?? {};
- | ^^^^^^^^ Unexpected terminal kind `optional` for logical test block
- 6 | }
- 7 |
- 8 | export const FIXTURE_ENTRYPONT = {
-```
-
-
\ No newline at end of file
diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.todo-optional-call-chain-in-ternary.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.todo-optional-call-chain-in-ternary.expect.md
deleted file mode 100644
index 897b29ce6a..0000000000
--- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.todo-optional-call-chain-in-ternary.expect.md
+++ /dev/null
@@ -1,37 +0,0 @@
-
-## Input
-
-```javascript
-import {useNoAlias} from 'shared-runtime';
-
-function useFoo(props: {value: {x: string; y: string} | null}) {
- const value = props.value;
- return useNoAlias(value?.x, value?.y) ? {} : null;
-}
-
-export const FIXTURE_ENTRYPONT = {
- fn: useFoo,
- props: [{value: null}],
-};
-
-```
-
-
-## Error
-
-```
-Found 1 error:
-
-Todo: Unexpected terminal kind `optional` for ternary test block
-
-error.todo-optional-call-chain-in-ternary.ts:5:30
- 3 | function useFoo(props: {value: {x: string; y: string} | null}) {
- 4 | const value = props.value;
-> 5 | return useNoAlias(value?.x, value?.y) ? {} : null;
- | ^^^^^^^^ Unexpected terminal kind `optional` for ternary test block
- 6 | }
- 7 |
- 8 | export const FIXTURE_ENTRYPONT = {
-```
-
-
\ No newline at end of file
diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/logical-inside-optional-chain-with-method.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/logical-inside-optional-chain-with-method.expect.md
new file mode 100644
index 0000000000..f4c4f11d7a
--- /dev/null
+++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/logical-inside-optional-chain-with-method.expect.md
@@ -0,0 +1,122 @@
+
+## Input
+
+```javascript
+import {Stringify} from 'shared-runtime';
+
+// Test logical expression as part of optional chain base with method call
+function Component(props: {
+ a: {x: {getY(): string} | null} | null;
+ b: {x: {getY(): string}} | null;
+}) {
+ 'use memo';
+ const result = (props.a || props.b)?.x?.getY();
+ return ;
+}
+
+export const FIXTURE_ENTRYPOINT = {
+ fn: Component,
+ params: [{a: null, b: {x: {getY: () => 'found'}}}],
+ sequentialRenders: [
+ {a: null, b: {x: {getY: () => 'found'}}},
+ {a: {x: {getY: () => 'first'}}, b: {x: {getY: () => 'second'}}},
+ {a: null, b: null},
+ {a: {x: null}, b: {x: {getY: () => 'second'}}},
+ ],
+};
+
+```
+
+## Code
+
+```javascript
+import { c as _c } from "react/compiler-runtime";
+import { Stringify } from "shared-runtime";
+
+// Test logical expression as part of optional chain base with method call
+function Component(props) {
+ "use memo";
+ const $ = _c(5);
+ let t0;
+ if ($[0] !== props.a || $[1] !== props.b) {
+ t0 = (props.a || props.b)?.x?.getY();
+ $[0] = props.a;
+ $[1] = props.b;
+ $[2] = t0;
+ } else {
+ t0 = $[2];
+ }
+ const result = t0;
+ let t1;
+ if ($[3] !== result) {
+ t1 = ;
+ $[3] = result;
+ $[4] = t1;
+ } else {
+ t1 = $[4];
+ }
+ return t1;
+}
+
+export const FIXTURE_ENTRYPOINT = {
+ fn: Component,
+ params: [
+ {
+ a: null,
+ b: {
+ x: {
+ getY: () => {
+ return "found";
+ },
+ },
+ },
+ },
+ ],
+ sequentialRenders: [
+ {
+ a: null,
+ b: {
+ x: {
+ getY: () => {
+ return "found";
+ },
+ },
+ },
+ },
+ {
+ a: {
+ x: {
+ getY: () => {
+ return "first";
+ },
+ },
+ },
+ b: {
+ x: {
+ getY: () => {
+ return "second";
+ },
+ },
+ },
+ },
+ { a: null, b: null },
+ {
+ a: { x: null },
+ b: {
+ x: {
+ getY: () => {
+ return "second";
+ },
+ },
+ },
+ },
+ ],
+};
+
+```
+
+### Eval output
+(kind: ok) {"value":"found"}
+{"value":"first"}
+{}
+{}
\ No newline at end of file
diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/logical-inside-optional-chain-with-method.tsx b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/logical-inside-optional-chain-with-method.tsx
new file mode 100644
index 0000000000..a733574aa1
--- /dev/null
+++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/logical-inside-optional-chain-with-method.tsx
@@ -0,0 +1,22 @@
+import {Stringify} from 'shared-runtime';
+
+// Test logical expression as part of optional chain base with method call
+function Component(props: {
+ a: {x: {getY(): string} | null} | null;
+ b: {x: {getY(): string}} | null;
+}) {
+ 'use memo';
+ const result = (props.a || props.b)?.x?.getY();
+ return ;
+}
+
+export const FIXTURE_ENTRYPOINT = {
+ fn: Component,
+ params: [{a: null, b: {x: {getY: () => 'found'}}}],
+ sequentialRenders: [
+ {a: null, b: {x: {getY: () => 'found'}}},
+ {a: {x: {getY: () => 'first'}}, b: {x: {getY: () => 'second'}}},
+ {a: null, b: null},
+ {a: {x: null}, b: {x: {getY: () => 'second'}}},
+ ],
+};
diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/logical-inside-optional-chain.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/logical-inside-optional-chain.expect.md
new file mode 100644
index 0000000000..d0eed0ad01
--- /dev/null
+++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/logical-inside-optional-chain.expect.md
@@ -0,0 +1,60 @@
+
+## Input
+
+```javascript
+// Test logical expression as part of optional chain base
+function Component(props: {
+ a: {x: {y: string} | null} | null;
+ b: {x: {y: string}} | null;
+}) {
+ 'use memo';
+ return (props.a || props.b)?.x?.y;
+}
+
+export const FIXTURE_ENTRYPOINT = {
+ fn: Component,
+ params: [{a: null, b: {x: {y: 'found'}}}],
+ sequentialRenders: [
+ // a is null, uses b
+ {a: null, b: {x: {y: 'found'}}},
+ // a is truthy, uses a
+ {a: {x: {y: 'first'}}, b: {x: {y: 'second'}}},
+ // both null
+ {a: null, b: null},
+ // a is truthy but a.x is null
+ {a: {x: null}, b: {x: {y: 'second'}}},
+ ],
+};
+
+```
+
+## Code
+
+```javascript
+// Test logical expression as part of optional chain base
+function Component(props) {
+ "use memo";
+ return (props.a || props.b)?.x?.y;
+}
+
+export const FIXTURE_ENTRYPOINT = {
+ fn: Component,
+ params: [{ a: null, b: { x: { y: "found" } } }],
+ sequentialRenders: [
+ // a is null, uses b
+ { a: null, b: { x: { y: "found" } } },
+ // a is truthy, uses a
+ { a: { x: { y: "first" } }, b: { x: { y: "second" } } },
+ // both null
+ { a: null, b: null },
+ // a is truthy but a.x is null
+ { a: { x: null }, b: { x: { y: "second" } } },
+ ],
+};
+
+```
+
+### Eval output
+(kind: ok) "found"
+"first"
+
diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/logical-inside-optional-chain.ts b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/logical-inside-optional-chain.ts
new file mode 100644
index 0000000000..74a5ff88af
--- /dev/null
+++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/logical-inside-optional-chain.ts
@@ -0,0 +1,23 @@
+// Test logical expression as part of optional chain base
+function Component(props: {
+ a: {x: {y: string} | null} | null;
+ b: {x: {y: string}} | null;
+}) {
+ 'use memo';
+ return (props.a || props.b)?.x?.y;
+}
+
+export const FIXTURE_ENTRYPOINT = {
+ fn: Component,
+ params: [{a: null, b: {x: {y: 'found'}}}],
+ sequentialRenders: [
+ // a is null, uses b
+ {a: null, b: {x: {y: 'found'}}},
+ // a is truthy, uses a
+ {a: {x: {y: 'first'}}, b: {x: {y: 'second'}}},
+ // both null
+ {a: null, b: null},
+ // a is truthy but a.x is null
+ {a: {x: null}, b: {x: {y: 'second'}}},
+ ],
+};
diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/multiple-optionals-in-ternary-branches-with-method.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/multiple-optionals-in-ternary-branches-with-method.expect.md
new file mode 100644
index 0000000000..244bcb5d81
--- /dev/null
+++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/multiple-optionals-in-ternary-branches-with-method.expect.md
@@ -0,0 +1,134 @@
+
+## Input
+
+```javascript
+import {Stringify} from 'shared-runtime';
+
+// Test optional chaining with method calls in both branches of a ternary
+function Component(props: {
+ a: {getX(): string} | null;
+ b: {getY(): string} | null;
+ cond: boolean;
+}) {
+ 'use memo';
+ const result = props.cond ? props.a?.getX() : props.b?.getY();
+ return ;
+}
+
+export const FIXTURE_ENTRYPOINT = {
+ fn: Component,
+ params: [{a: {getX: () => 'hello'}, b: {getY: () => 'world'}, cond: true}],
+ sequentialRenders: [
+ {a: {getX: () => 'hello'}, b: {getY: () => 'world'}, cond: true},
+ {a: {getX: () => 'hello'}, b: {getY: () => 'world'}, cond: false},
+ {a: null, b: {getY: () => 'world'}, cond: true},
+ {a: {getX: () => 'hello'}, b: null, cond: false},
+ ],
+};
+
+```
+
+## Code
+
+```javascript
+import { c as _c } from "react/compiler-runtime";
+import { Stringify } from "shared-runtime";
+
+// Test optional chaining with method calls in both branches of a ternary
+function Component(props) {
+ "use memo";
+ const $ = _c(6);
+ let t0;
+ if ($[0] !== props.a || $[1] !== props.b || $[2] !== props.cond) {
+ t0 = props.cond ? props.a?.getX() : props.b?.getY();
+ $[0] = props.a;
+ $[1] = props.b;
+ $[2] = props.cond;
+ $[3] = t0;
+ } else {
+ t0 = $[3];
+ }
+ const result = t0;
+ let t1;
+ if ($[4] !== result) {
+ t1 = ;
+ $[4] = result;
+ $[5] = t1;
+ } else {
+ t1 = $[5];
+ }
+ return t1;
+}
+
+export const FIXTURE_ENTRYPOINT = {
+ fn: Component,
+ params: [
+ {
+ a: {
+ getX: () => {
+ return "hello";
+ },
+ },
+ b: {
+ getY: () => {
+ return "world";
+ },
+ },
+ cond: true,
+ },
+ ],
+ sequentialRenders: [
+ {
+ a: {
+ getX: () => {
+ return "hello";
+ },
+ },
+ b: {
+ getY: () => {
+ return "world";
+ },
+ },
+ cond: true,
+ },
+ {
+ a: {
+ getX: () => {
+ return "hello";
+ },
+ },
+ b: {
+ getY: () => {
+ return "world";
+ },
+ },
+ cond: false,
+ },
+ {
+ a: null,
+ b: {
+ getY: () => {
+ return "world";
+ },
+ },
+ cond: true,
+ },
+ {
+ a: {
+ getX: () => {
+ return "hello";
+ },
+ },
+ b: null,
+ cond: false,
+ },
+ ],
+};
+
+```
+
+### Eval output
+(kind: ok) {"value":"hello"}
+{"value":"world"}
+{}
+{}
\ No newline at end of file
diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/multiple-optionals-in-ternary-branches-with-method.tsx b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/multiple-optionals-in-ternary-branches-with-method.tsx
new file mode 100644
index 0000000000..e7a685cdb3
--- /dev/null
+++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/multiple-optionals-in-ternary-branches-with-method.tsx
@@ -0,0 +1,23 @@
+import {Stringify} from 'shared-runtime';
+
+// Test optional chaining with method calls in both branches of a ternary
+function Component(props: {
+ a: {getX(): string} | null;
+ b: {getY(): string} | null;
+ cond: boolean;
+}) {
+ 'use memo';
+ const result = props.cond ? props.a?.getX() : props.b?.getY();
+ return ;
+}
+
+export const FIXTURE_ENTRYPOINT = {
+ fn: Component,
+ params: [{a: {getX: () => 'hello'}, b: {getY: () => 'world'}, cond: true}],
+ sequentialRenders: [
+ {a: {getX: () => 'hello'}, b: {getY: () => 'world'}, cond: true},
+ {a: {getX: () => 'hello'}, b: {getY: () => 'world'}, cond: false},
+ {a: null, b: {getY: () => 'world'}, cond: true},
+ {a: {getX: () => 'hello'}, b: null, cond: false},
+ ],
+};
diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/multiple-optionals-in-ternary-branches.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/multiple-optionals-in-ternary-branches.expect.md
new file mode 100644
index 0000000000..44d76d3dce
--- /dev/null
+++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/multiple-optionals-in-ternary-branches.expect.md
@@ -0,0 +1,61 @@
+
+## Input
+
+```javascript
+// Test optional chaining in both branches of a ternary
+function Component(props: {
+ a: {x: string} | null;
+ b: {y: string} | null;
+ cond: boolean;
+}) {
+ 'use memo';
+ return props.cond ? props.a?.x : props.b?.y;
+}
+
+export const FIXTURE_ENTRYPOINT = {
+ fn: Component,
+ params: [{a: {x: 'hello'}, b: {y: 'world'}, cond: true}],
+ sequentialRenders: [
+ // cond=true, picks a?.x -> 'hello'
+ {a: {x: 'hello'}, b: {y: 'world'}, cond: true},
+ // cond=false, picks b?.y -> 'world'
+ {a: {x: 'hello'}, b: {y: 'world'}, cond: false},
+ // cond=true, a=null, picks a?.x -> undefined
+ {a: null, b: {y: 'world'}, cond: true},
+ // cond=false, b=null, picks b?.y -> undefined
+ {a: {x: 'hello'}, b: null, cond: false},
+ ],
+};
+
+```
+
+## Code
+
+```javascript
+// Test optional chaining in both branches of a ternary
+function Component(props) {
+ "use memo";
+ return props.cond ? props.a?.x : props.b?.y;
+}
+
+export const FIXTURE_ENTRYPOINT = {
+ fn: Component,
+ params: [{ a: { x: "hello" }, b: { y: "world" }, cond: true }],
+ sequentialRenders: [
+ // cond=true, picks a?.x -> 'hello'
+ { a: { x: "hello" }, b: { y: "world" }, cond: true },
+ // cond=false, picks b?.y -> 'world'
+ { a: { x: "hello" }, b: { y: "world" }, cond: false },
+ // cond=true, a=null, picks a?.x -> undefined
+ { a: null, b: { y: "world" }, cond: true },
+ // cond=false, b=null, picks b?.y -> undefined
+ { a: { x: "hello" }, b: null, cond: false },
+ ],
+};
+
+```
+
+### Eval output
+(kind: ok) "hello"
+"world"
+
diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/multiple-optionals-in-ternary-branches.ts b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/multiple-optionals-in-ternary-branches.ts
new file mode 100644
index 0000000000..b9d9a95a09
--- /dev/null
+++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/multiple-optionals-in-ternary-branches.ts
@@ -0,0 +1,24 @@
+// Test optional chaining in both branches of a ternary
+function Component(props: {
+ a: {x: string} | null;
+ b: {y: string} | null;
+ cond: boolean;
+}) {
+ 'use memo';
+ return props.cond ? props.a?.x : props.b?.y;
+}
+
+export const FIXTURE_ENTRYPOINT = {
+ fn: Component,
+ params: [{a: {x: 'hello'}, b: {y: 'world'}, cond: true}],
+ sequentialRenders: [
+ // cond=true, picks a?.x -> 'hello'
+ {a: {x: 'hello'}, b: {y: 'world'}, cond: true},
+ // cond=false, picks b?.y -> 'world'
+ {a: {x: 'hello'}, b: {y: 'world'}, cond: false},
+ // cond=true, a=null, picks a?.x -> undefined
+ {a: null, b: {y: 'world'}, cond: true},
+ // cond=false, b=null, picks b?.y -> undefined
+ {a: {x: 'hello'}, b: null, cond: false},
+ ],
+};
diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/optional-call-chain-in-logical-expr-with-method.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/optional-call-chain-in-logical-expr-with-method.expect.md
new file mode 100644
index 0000000000..1374cb9e64
--- /dev/null
+++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/optional-call-chain-in-logical-expr-with-method.expect.md
@@ -0,0 +1,85 @@
+
+## Input
+
+```javascript
+import {Stringify, useIdentity} from 'shared-runtime';
+
+function useFoo(props: {value: {getX(): string; getY(): string} | null}) {
+ 'use memo';
+ const value = props.value;
+ const result = useIdentity({x: value?.getX(), y: value?.getY()}) ?? {};
+ return ;
+}
+
+export const FIXTURE_ENTRYPOINT = {
+ fn: useFoo,
+ params: [{value: null}],
+ sequentialRenders: [
+ {value: null},
+ {value: {getX: () => 'x1', getY: () => 'y1'}},
+ {value: {getX: () => 'x2', getY: () => 'y2'}},
+ {value: null},
+ ],
+};
+
+```
+
+## Code
+
+```javascript
+import { c as _c } from "react/compiler-runtime";
+import { Stringify, useIdentity } from "shared-runtime";
+
+function useFoo(props) {
+ "use memo";
+ const $ = _c(2);
+
+ const value = props.value;
+ const result = useIdentity({ x: value?.getX(), y: value?.getY() }) ?? {};
+ let t0;
+ if ($[0] !== result) {
+ t0 = ;
+ $[0] = result;
+ $[1] = t0;
+ } else {
+ t0 = $[1];
+ }
+ return t0;
+}
+
+export const FIXTURE_ENTRYPOINT = {
+ fn: useFoo,
+ params: [{ value: null }],
+ sequentialRenders: [
+ { value: null },
+ {
+ value: {
+ getX: () => {
+ return "x1";
+ },
+ getY: () => {
+ return "y1";
+ },
+ },
+ },
+ {
+ value: {
+ getX: () => {
+ return "x2";
+ },
+ getY: () => {
+ return "y2";
+ },
+ },
+ },
+ { value: null },
+ ],
+};
+
+```
+
+### Eval output
+(kind: ok) {"value":{}}
+{"value":{"x":"x1","y":"y1"}}
+{"value":{"x":"x2","y":"y2"}}
+{"value":{}}
\ No newline at end of file
diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/optional-call-chain-in-logical-expr-with-method.tsx b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/optional-call-chain-in-logical-expr-with-method.tsx
new file mode 100644
index 0000000000..201e331af3
--- /dev/null
+++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/optional-call-chain-in-logical-expr-with-method.tsx
@@ -0,0 +1,19 @@
+import {Stringify, useIdentity} from 'shared-runtime';
+
+function useFoo(props: {value: {getX(): string; getY(): string} | null}) {
+ 'use memo';
+ const value = props.value;
+ const result = useIdentity({x: value?.getX(), y: value?.getY()}) ?? {};
+ return ;
+}
+
+export const FIXTURE_ENTRYPOINT = {
+ fn: useFoo,
+ params: [{value: null}],
+ sequentialRenders: [
+ {value: null},
+ {value: {getX: () => 'x1', getY: () => 'y1'}},
+ {value: {getX: () => 'x2', getY: () => 'y2'}},
+ {value: null},
+ ],
+};
diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/optional-call-chain-in-logical-expr.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/optional-call-chain-in-logical-expr.expect.md
new file mode 100644
index 0000000000..01bac6d1a0
--- /dev/null
+++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/optional-call-chain-in-logical-expr.expect.md
@@ -0,0 +1,40 @@
+
+## Input
+
+```javascript
+import {useNoAlias} from 'shared-runtime';
+
+function useFoo(props: {value: {x: string; y: string} | null}) {
+ 'use memo';
+ const value = props.value;
+ return useNoAlias(value?.x, value?.y) ?? {};
+}
+
+export const FIXTURE_ENTRYPONT = {
+ fn: useFoo,
+ props: [{value: null}],
+};
+
+```
+
+## Code
+
+```javascript
+import { useNoAlias } from "shared-runtime";
+
+function useFoo(props) {
+ "use memo";
+
+ const value = props.value;
+ return useNoAlias(value?.x, value?.y) ?? {};
+}
+
+export const FIXTURE_ENTRYPONT = {
+ fn: useFoo,
+ props: [{ value: null }],
+};
+
+```
+
+### Eval output
+(kind: exception) Fixture not implemented
\ No newline at end of file
diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.todo-optional-call-chain-in-logical-expr.ts b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/optional-call-chain-in-logical-expr.ts
similarity index 95%
rename from compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.todo-optional-call-chain-in-logical-expr.ts
rename to compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/optional-call-chain-in-logical-expr.ts
index b96f6aefad..8219fe66a8 100644
--- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.todo-optional-call-chain-in-logical-expr.ts
+++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/optional-call-chain-in-logical-expr.ts
@@ -1,6 +1,7 @@
import {useNoAlias} from 'shared-runtime';
function useFoo(props: {value: {x: string; y: string} | null}) {
+ 'use memo';
const value = props.value;
return useNoAlias(value?.x, value?.y) ?? {};
}
diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/optional-call-chain-in-ternary-with-method.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/optional-call-chain-in-ternary-with-method.expect.md
new file mode 100644
index 0000000000..ccb2150361
--- /dev/null
+++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/optional-call-chain-in-ternary-with-method.expect.md
@@ -0,0 +1,87 @@
+
+## Input
+
+```javascript
+import {Stringify, useIdentity} from 'shared-runtime';
+
+function useFoo(props: {value: {getX(): string; getY(): string} | null}) {
+ 'use memo';
+ const value = props.value;
+ const result = useIdentity({x: value?.getX(), y: value?.getY()}) ? {} : null;
+ return ;
+}
+
+export const FIXTURE_ENTRYPOINT = {
+ fn: useFoo,
+ params: [{value: null}],
+ sequentialRenders: [
+ {value: null},
+ {value: {getX: () => 'x1', getY: () => 'y1'}},
+ {value: {getX: () => 'x2', getY: () => 'y2'}},
+ {value: null},
+ ],
+};
+
+```
+
+## Code
+
+```javascript
+import { c as _c } from "react/compiler-runtime";
+import { Stringify, useIdentity } from "shared-runtime";
+
+function useFoo(props) {
+ "use memo";
+ const $ = _c(2);
+
+ const value = props.value;
+ const result = useIdentity({ x: value?.getX(), y: value?.getY() })
+ ? {}
+ : null;
+ let t0;
+ if ($[0] !== result) {
+ t0 = ;
+ $[0] = result;
+ $[1] = t0;
+ } else {
+ t0 = $[1];
+ }
+ return t0;
+}
+
+export const FIXTURE_ENTRYPOINT = {
+ fn: useFoo,
+ params: [{ value: null }],
+ sequentialRenders: [
+ { value: null },
+ {
+ value: {
+ getX: () => {
+ return "x1";
+ },
+ getY: () => {
+ return "y1";
+ },
+ },
+ },
+ {
+ value: {
+ getX: () => {
+ return "x2";
+ },
+ getY: () => {
+ return "y2";
+ },
+ },
+ },
+ { value: null },
+ ],
+};
+
+```
+
+### Eval output
+(kind: ok) {"value":{}}
+{"value":{}}
+{"value":{}}
+{"value":{}}
\ No newline at end of file
diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/optional-call-chain-in-ternary-with-method.tsx b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/optional-call-chain-in-ternary-with-method.tsx
new file mode 100644
index 0000000000..e2107ec404
--- /dev/null
+++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/optional-call-chain-in-ternary-with-method.tsx
@@ -0,0 +1,19 @@
+import {Stringify, useIdentity} from 'shared-runtime';
+
+function useFoo(props: {value: {getX(): string; getY(): string} | null}) {
+ 'use memo';
+ const value = props.value;
+ const result = useIdentity({x: value?.getX(), y: value?.getY()}) ? {} : null;
+ return ;
+}
+
+export const FIXTURE_ENTRYPOINT = {
+ fn: useFoo,
+ params: [{value: null}],
+ sequentialRenders: [
+ {value: null},
+ {value: {getX: () => 'x1', getY: () => 'y1'}},
+ {value: {getX: () => 'x2', getY: () => 'y2'}},
+ {value: null},
+ ],
+};
diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/optional-call-chain-in-ternary.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/optional-call-chain-in-ternary.expect.md
new file mode 100644
index 0000000000..e9ae4a1809
--- /dev/null
+++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/optional-call-chain-in-ternary.expect.md
@@ -0,0 +1,40 @@
+
+## Input
+
+```javascript
+import {useNoAlias} from 'shared-runtime';
+
+function useFoo(props: {value: {x: string; y: string} | null}) {
+ 'use memo';
+ const value = props.value;
+ return useNoAlias(value?.x, value?.y) ? {} : null;
+}
+
+export const FIXTURE_ENTRYPONT = {
+ fn: useFoo,
+ props: [{value: null}],
+};
+
+```
+
+## Code
+
+```javascript
+import { useNoAlias } from "shared-runtime";
+
+function useFoo(props) {
+ "use memo";
+
+ const value = props.value;
+ return useNoAlias(value?.x, value?.y) ? {} : null;
+}
+
+export const FIXTURE_ENTRYPONT = {
+ fn: useFoo,
+ props: [{ value: null }],
+};
+
+```
+
+### Eval output
+(kind: exception) Fixture not implemented
\ No newline at end of file
diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.todo-optional-call-chain-in-ternary.ts b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/optional-call-chain-in-ternary.ts
similarity index 95%
rename from compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.todo-optional-call-chain-in-ternary.ts
rename to compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/optional-call-chain-in-ternary.ts
index ac5302da00..90e2db730d 100644
--- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.todo-optional-call-chain-in-ternary.ts
+++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/optional-call-chain-in-ternary.ts
@@ -1,6 +1,7 @@
import {useNoAlias} from 'shared-runtime';
function useFoo(props: {value: {x: string; y: string} | null}) {
+ 'use memo';
const value = props.value;
return useNoAlias(value?.x, value?.y) ? {} : null;
}
diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/optional-inside-logical-and-with-method.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/optional-inside-logical-and-with-method.expect.md
new file mode 100644
index 0000000000..41b799275b
--- /dev/null
+++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/optional-inside-logical-and-with-method.expect.md
@@ -0,0 +1,108 @@
+
+## Input
+
+```javascript
+import {Stringify} from 'shared-runtime';
+
+// Test optional chaining inside logical AND (&&) with method calls
+function Component(props: {value: {getX(): string} | null; enabled: boolean}) {
+ 'use memo';
+ const value = props.value;
+ const result = props.enabled && value?.getX();
+ return ;
+}
+
+export const FIXTURE_ENTRYPOINT = {
+ fn: Component,
+ params: [{value: {getX: () => 'hello'}, enabled: true}],
+ sequentialRenders: [
+ {value: {getX: () => 'hello'}, enabled: true},
+ {value: {getX: () => 'hello'}, enabled: false},
+ {value: null, enabled: true},
+ {value: {getX: () => 'world'}, enabled: true},
+ ],
+};
+
+```
+
+## Code
+
+```javascript
+import { c as _c } from "react/compiler-runtime";
+import { Stringify } from "shared-runtime";
+
+// Test optional chaining inside logical AND (&&) with method calls
+function Component(props) {
+ "use memo";
+ const $ = _c(5);
+
+ const value = props.value;
+ let t0;
+ if ($[0] !== props.enabled || $[1] !== value) {
+ t0 = props.enabled && value?.getX();
+ $[0] = props.enabled;
+ $[1] = value;
+ $[2] = t0;
+ } else {
+ t0 = $[2];
+ }
+ const result = t0;
+ let t1;
+ if ($[3] !== result) {
+ t1 = ;
+ $[3] = result;
+ $[4] = t1;
+ } else {
+ t1 = $[4];
+ }
+ return t1;
+}
+
+export const FIXTURE_ENTRYPOINT = {
+ fn: Component,
+ params: [
+ {
+ value: {
+ getX: () => {
+ return "hello";
+ },
+ },
+ enabled: true,
+ },
+ ],
+ sequentialRenders: [
+ {
+ value: {
+ getX: () => {
+ return "hello";
+ },
+ },
+ enabled: true,
+ },
+ {
+ value: {
+ getX: () => {
+ return "hello";
+ },
+ },
+ enabled: false,
+ },
+ { value: null, enabled: true },
+ {
+ value: {
+ getX: () => {
+ return "world";
+ },
+ },
+ enabled: true,
+ },
+ ],
+};
+
+```
+
+### Eval output
+(kind: ok) {"value":"hello"}
+{"value":false}
+{}
+{"value":"world"}
\ No newline at end of file
diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/optional-inside-logical-and-with-method.tsx b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/optional-inside-logical-and-with-method.tsx
new file mode 100644
index 0000000000..689fbe8e27
--- /dev/null
+++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/optional-inside-logical-and-with-method.tsx
@@ -0,0 +1,20 @@
+import {Stringify} from 'shared-runtime';
+
+// Test optional chaining inside logical AND (&&) with method calls
+function Component(props: {value: {getX(): string} | null; enabled: boolean}) {
+ 'use memo';
+ const value = props.value;
+ const result = props.enabled && value?.getX();
+ return ;
+}
+
+export const FIXTURE_ENTRYPOINT = {
+ fn: Component,
+ params: [{value: {getX: () => 'hello'}, enabled: true}],
+ sequentialRenders: [
+ {value: {getX: () => 'hello'}, enabled: true},
+ {value: {getX: () => 'hello'}, enabled: false},
+ {value: null, enabled: true},
+ {value: {getX: () => 'world'}, enabled: true},
+ ],
+};
diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/optional-inside-logical-and.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/optional-inside-logical-and.expect.md
new file mode 100644
index 0000000000..86e478d74b
--- /dev/null
+++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/optional-inside-logical-and.expect.md
@@ -0,0 +1,53 @@
+
+## Input
+
+```javascript
+// Test optional chaining inside logical AND (&&)
+function Component(props: {value: {x: string} | null; enabled: boolean}) {
+ 'use memo';
+ const value = props.value;
+ return props.enabled && value?.x;
+}
+
+export const FIXTURE_ENTRYPOINT = {
+ fn: Component,
+ params: [{value: {x: 'hello'}, enabled: true}],
+ sequentialRenders: [
+ {value: {x: 'hello'}, enabled: true},
+ {value: {x: 'hello'}, enabled: false},
+ {value: null, enabled: true},
+ {value: {x: 'world'}, enabled: true},
+ ],
+};
+
+```
+
+## Code
+
+```javascript
+// Test optional chaining inside logical AND (&&)
+function Component(props) {
+ "use memo";
+
+ const value = props.value;
+ return props.enabled && value?.x;
+}
+
+export const FIXTURE_ENTRYPOINT = {
+ fn: Component,
+ params: [{ value: { x: "hello" }, enabled: true }],
+ sequentialRenders: [
+ { value: { x: "hello" }, enabled: true },
+ { value: { x: "hello" }, enabled: false },
+ { value: null, enabled: true },
+ { value: { x: "world" }, enabled: true },
+ ],
+};
+
+```
+
+### Eval output
+(kind: ok) "hello"
+false
+
+"world"
\ No newline at end of file
diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/optional-inside-logical-and.ts b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/optional-inside-logical-and.ts
new file mode 100644
index 0000000000..4fee7ffd96
--- /dev/null
+++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/optional-inside-logical-and.ts
@@ -0,0 +1,17 @@
+// Test optional chaining inside logical AND (&&)
+function Component(props: {value: {x: string} | null; enabled: boolean}) {
+ 'use memo';
+ const value = props.value;
+ return props.enabled && value?.x;
+}
+
+export const FIXTURE_ENTRYPOINT = {
+ fn: Component,
+ params: [{value: {x: 'hello'}, enabled: true}],
+ sequentialRenders: [
+ {value: {x: 'hello'}, enabled: true},
+ {value: {x: 'hello'}, enabled: false},
+ {value: null, enabled: true},
+ {value: {x: 'world'}, enabled: true},
+ ],
+};
diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/optional-inside-logical-or-with-method.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/optional-inside-logical-or-with-method.expect.md
new file mode 100644
index 0000000000..b0b2821c0c
--- /dev/null
+++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/optional-inside-logical-or-with-method.expect.md
@@ -0,0 +1,92 @@
+
+## Input
+
+```javascript
+import {Stringify} from 'shared-runtime';
+
+// Test optional chaining inside logical OR (||) with method calls
+function Component(props: {value: {getX(): string} | null; fallback: string}) {
+ 'use memo';
+ const value = props.value;
+ const result = value?.getX() || props.fallback;
+ return ;
+}
+
+export const FIXTURE_ENTRYPOINT = {
+ fn: Component,
+ params: [{value: null, fallback: 'default'}],
+ sequentialRenders: [
+ {value: null, fallback: 'default'},
+ {value: {getX: () => 'hello'}, fallback: 'default'},
+ {value: {getX: () => ''}, fallback: 'default'},
+ {value: null, fallback: 'other'},
+ ],
+};
+
+```
+
+## Code
+
+```javascript
+import { c as _c } from "react/compiler-runtime";
+import { Stringify } from "shared-runtime";
+
+// Test optional chaining inside logical OR (||) with method calls
+function Component(props) {
+ "use memo";
+ const $ = _c(5);
+
+ const value = props.value;
+ let t0;
+ if ($[0] !== props.fallback || $[1] !== value) {
+ t0 = value?.getX() || props.fallback;
+ $[0] = props.fallback;
+ $[1] = value;
+ $[2] = t0;
+ } else {
+ t0 = $[2];
+ }
+ const result = t0;
+ let t1;
+ if ($[3] !== result) {
+ t1 = ;
+ $[3] = result;
+ $[4] = t1;
+ } else {
+ t1 = $[4];
+ }
+ return t1;
+}
+
+export const FIXTURE_ENTRYPOINT = {
+ fn: Component,
+ params: [{ value: null, fallback: "default" }],
+ sequentialRenders: [
+ { value: null, fallback: "default" },
+ {
+ value: {
+ getX: () => {
+ return "hello";
+ },
+ },
+ fallback: "default",
+ },
+ {
+ value: {
+ getX: () => {
+ return "";
+ },
+ },
+ fallback: "default",
+ },
+ { value: null, fallback: "other" },
+ ],
+};
+
+```
+
+### Eval output
+(kind: ok) {"value":"default"}
+{"value":"hello"}
+{"value":"default"}
+{"value":"other"}
\ No newline at end of file
diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/optional-inside-logical-or-with-method.tsx b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/optional-inside-logical-or-with-method.tsx
new file mode 100644
index 0000000000..9997f2ec06
--- /dev/null
+++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/optional-inside-logical-or-with-method.tsx
@@ -0,0 +1,20 @@
+import {Stringify} from 'shared-runtime';
+
+// Test optional chaining inside logical OR (||) with method calls
+function Component(props: {value: {getX(): string} | null; fallback: string}) {
+ 'use memo';
+ const value = props.value;
+ const result = value?.getX() || props.fallback;
+ return ;
+}
+
+export const FIXTURE_ENTRYPOINT = {
+ fn: Component,
+ params: [{value: null, fallback: 'default'}],
+ sequentialRenders: [
+ {value: null, fallback: 'default'},
+ {value: {getX: () => 'hello'}, fallback: 'default'},
+ {value: {getX: () => ''}, fallback: 'default'},
+ {value: null, fallback: 'other'},
+ ],
+};
diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/optional-inside-logical-or.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/optional-inside-logical-or.expect.md
new file mode 100644
index 0000000000..c7fa6f5bbc
--- /dev/null
+++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/optional-inside-logical-or.expect.md
@@ -0,0 +1,53 @@
+
+## Input
+
+```javascript
+// Test optional chaining inside logical OR (||)
+function Component(props: {value: {x: string} | null; fallback: string}) {
+ 'use memo';
+ const value = props.value;
+ return value?.x || props.fallback;
+}
+
+export const FIXTURE_ENTRYPOINT = {
+ fn: Component,
+ params: [{value: null, fallback: 'default'}],
+ sequentialRenders: [
+ {value: null, fallback: 'default'},
+ {value: {x: 'hello'}, fallback: 'default'},
+ {value: {x: ''}, fallback: 'default'},
+ {value: null, fallback: 'other'},
+ ],
+};
+
+```
+
+## Code
+
+```javascript
+// Test optional chaining inside logical OR (||)
+function Component(props) {
+ "use memo";
+
+ const value = props.value;
+ return value?.x || props.fallback;
+}
+
+export const FIXTURE_ENTRYPOINT = {
+ fn: Component,
+ params: [{ value: null, fallback: "default" }],
+ sequentialRenders: [
+ { value: null, fallback: "default" },
+ { value: { x: "hello" }, fallback: "default" },
+ { value: { x: "" }, fallback: "default" },
+ { value: null, fallback: "other" },
+ ],
+};
+
+```
+
+### Eval output
+(kind: ok) "default"
+"hello"
+"default"
+"other"
\ No newline at end of file
diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/optional-inside-logical-or.ts b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/optional-inside-logical-or.ts
new file mode 100644
index 0000000000..0a0ede14f2
--- /dev/null
+++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/optional-inside-logical-or.ts
@@ -0,0 +1,17 @@
+// Test optional chaining inside logical OR (||)
+function Component(props: {value: {x: string} | null; fallback: string}) {
+ 'use memo';
+ const value = props.value;
+ return value?.x || props.fallback;
+}
+
+export const FIXTURE_ENTRYPOINT = {
+ fn: Component,
+ params: [{value: null, fallback: 'default'}],
+ sequentialRenders: [
+ {value: null, fallback: 'default'},
+ {value: {x: 'hello'}, fallback: 'default'},
+ {value: {x: ''}, fallback: 'default'},
+ {value: null, fallback: 'other'},
+ ],
+};
diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/ternary-inside-optional-consequent-with-method.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/ternary-inside-optional-consequent-with-method.expect.md
new file mode 100644
index 0000000000..d854b451bb
--- /dev/null
+++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/ternary-inside-optional-consequent-with-method.expect.md
@@ -0,0 +1,135 @@
+
+## Input
+
+```javascript
+import {Stringify} from 'shared-runtime';
+
+// Test ternary expression producing the value used in optional chaining with method call
+function Component(props: {
+ a: {getX(): string} | null;
+ b: {getX(): string} | null;
+ cond: boolean;
+}) {
+ 'use memo';
+ const obj = props.cond ? props.a : props.b;
+ const result = obj?.getX();
+ return ;
+}
+
+export const FIXTURE_ENTRYPOINT = {
+ fn: Component,
+ params: [{a: {getX: () => 'a'}, b: {getX: () => 'b'}, cond: true}],
+ sequentialRenders: [
+ {a: {getX: () => 'a'}, b: {getX: () => 'b'}, cond: true},
+ {a: {getX: () => 'a'}, b: {getX: () => 'b'}, cond: false},
+ {a: null, b: {getX: () => 'b'}, cond: true},
+ {a: {getX: () => 'a'}, b: null, cond: false},
+ ],
+};
+
+```
+
+## Code
+
+```javascript
+import { c as _c } from "react/compiler-runtime";
+import { Stringify } from "shared-runtime";
+
+// Test ternary expression producing the value used in optional chaining with method call
+function Component(props) {
+ "use memo";
+ const $ = _c(4);
+
+ const obj = props.cond ? props.a : props.b;
+ let t0;
+ if ($[0] !== obj) {
+ t0 = obj?.getX();
+ $[0] = obj;
+ $[1] = t0;
+ } else {
+ t0 = $[1];
+ }
+ const result = t0;
+ let t1;
+ if ($[2] !== result) {
+ t1 = ;
+ $[2] = result;
+ $[3] = t1;
+ } else {
+ t1 = $[3];
+ }
+ return t1;
+}
+
+export const FIXTURE_ENTRYPOINT = {
+ fn: Component,
+ params: [
+ {
+ a: {
+ getX: () => {
+ return "a";
+ },
+ },
+ b: {
+ getX: () => {
+ return "b";
+ },
+ },
+ cond: true,
+ },
+ ],
+ sequentialRenders: [
+ {
+ a: {
+ getX: () => {
+ return "a";
+ },
+ },
+ b: {
+ getX: () => {
+ return "b";
+ },
+ },
+ cond: true,
+ },
+ {
+ a: {
+ getX: () => {
+ return "a";
+ },
+ },
+ b: {
+ getX: () => {
+ return "b";
+ },
+ },
+ cond: false,
+ },
+ {
+ a: null,
+ b: {
+ getX: () => {
+ return "b";
+ },
+ },
+ cond: true,
+ },
+ {
+ a: {
+ getX: () => {
+ return "a";
+ },
+ },
+ b: null,
+ cond: false,
+ },
+ ],
+};
+
+```
+
+### Eval output
+(kind: ok) {"value":"a"}
+{"value":"b"}
+{}
+{}
\ No newline at end of file
diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/ternary-inside-optional-consequent-with-method.tsx b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/ternary-inside-optional-consequent-with-method.tsx
new file mode 100644
index 0000000000..de37973a58
--- /dev/null
+++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/ternary-inside-optional-consequent-with-method.tsx
@@ -0,0 +1,24 @@
+import {Stringify} from 'shared-runtime';
+
+// Test ternary expression producing the value used in optional chaining with method call
+function Component(props: {
+ a: {getX(): string} | null;
+ b: {getX(): string} | null;
+ cond: boolean;
+}) {
+ 'use memo';
+ const obj = props.cond ? props.a : props.b;
+ const result = obj?.getX();
+ return ;
+}
+
+export const FIXTURE_ENTRYPOINT = {
+ fn: Component,
+ params: [{a: {getX: () => 'a'}, b: {getX: () => 'b'}, cond: true}],
+ sequentialRenders: [
+ {a: {getX: () => 'a'}, b: {getX: () => 'b'}, cond: true},
+ {a: {getX: () => 'a'}, b: {getX: () => 'b'}, cond: false},
+ {a: null, b: {getX: () => 'b'}, cond: true},
+ {a: {getX: () => 'a'}, b: null, cond: false},
+ ],
+};
diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/ternary-inside-optional-consequent.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/ternary-inside-optional-consequent.expect.md
new file mode 100644
index 0000000000..3f302c43d1
--- /dev/null
+++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/ternary-inside-optional-consequent.expect.md
@@ -0,0 +1,56 @@
+
+## Input
+
+```javascript
+// Test ternary expression producing the value used in optional chaining
+function Component(props: {
+ a: {x: string} | null;
+ b: {x: string} | null;
+ cond: boolean;
+}) {
+ 'use memo';
+ const obj = props.cond ? props.a : props.b;
+ return obj?.x;
+}
+
+export const FIXTURE_ENTRYPOINT = {
+ fn: Component,
+ params: [{a: {x: 'a'}, b: {x: 'b'}, cond: true}],
+ sequentialRenders: [
+ {a: {x: 'a'}, b: {x: 'b'}, cond: true}, // picks a -> 'a'
+ {a: {x: 'a'}, b: {x: 'b'}, cond: false}, // picks b -> 'b'
+ {a: null, b: {x: 'b'}, cond: true}, // picks a (null) -> undefined
+ {a: {x: 'a'}, b: null, cond: false}, // picks b (null) -> undefined
+ ],
+};
+
+```
+
+## Code
+
+```javascript
+// Test ternary expression producing the value used in optional chaining
+function Component(props) {
+ "use memo";
+
+ const obj = props.cond ? props.a : props.b;
+ return obj?.x;
+}
+
+export const FIXTURE_ENTRYPOINT = {
+ fn: Component,
+ params: [{ a: { x: "a" }, b: { x: "b" }, cond: true }],
+ sequentialRenders: [
+ { a: { x: "a" }, b: { x: "b" }, cond: true }, // picks a -> 'a'
+ { a: { x: "a" }, b: { x: "b" }, cond: false }, // picks b -> 'b'
+ { a: null, b: { x: "b" }, cond: true }, // picks a (null) -> undefined
+ { a: { x: "a" }, b: null, cond: false }, // picks b (null) -> undefined
+ ],
+};
+
+```
+
+### Eval output
+(kind: ok) "a"
+"b"
+
diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/ternary-inside-optional-consequent.ts b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/ternary-inside-optional-consequent.ts
new file mode 100644
index 0000000000..1c31d8a4ef
--- /dev/null
+++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/ternary-inside-optional-consequent.ts
@@ -0,0 +1,21 @@
+// Test ternary expression producing the value used in optional chaining
+function Component(props: {
+ a: {x: string} | null;
+ b: {x: string} | null;
+ cond: boolean;
+}) {
+ 'use memo';
+ const obj = props.cond ? props.a : props.b;
+ return obj?.x;
+}
+
+export const FIXTURE_ENTRYPOINT = {
+ fn: Component,
+ params: [{a: {x: 'a'}, b: {x: 'b'}, cond: true}],
+ sequentialRenders: [
+ {a: {x: 'a'}, b: {x: 'b'}, cond: true}, // picks a -> 'a'
+ {a: {x: 'a'}, b: {x: 'b'}, cond: false}, // picks b -> 'b'
+ {a: null, b: {x: 'b'}, cond: true}, // picks a (null) -> undefined
+ {a: {x: 'a'}, b: null, cond: false}, // picks b (null) -> undefined
+ ],
+};