Skip to content

Commit

Permalink
[compiler] Outline JSX with non-jsx children
Browse files Browse the repository at this point in the history
Previously, we bailed out on outlining jsx that had children that were
not part of the outlined jsx.

Now, we add support for children by treating as attributes.

[ghstack-poisoned]
  • Loading branch information
gsathya committed Nov 1, 2024
1 parent b13a77e commit 51ff05b
Show file tree
Hide file tree
Showing 3 changed files with 136 additions and 24 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -216,13 +216,22 @@ type OutlinedJsxAttribute = {
place: Place;
};

let id = 1;
function generateName(seen: Set<string>, oldName: string): string {
let newName = oldName;
while (seen.has(newName)) {
newName = `${oldName}${id++}`;
}
seen.add(newName);
return newName;
}

function collectProps(
instructions: Array<JsxInstruction>,
): Array<OutlinedJsxAttribute> | null {
const attributes: Array<OutlinedJsxAttribute> = [];
const jsxIds = new Set(instructions.map(i => i.lvalue.identifier.id));
const seen: Set<string> = new Set();
let id = 1;

for (const instr of instructions) {
const {value} = instr;
Expand All @@ -233,25 +242,29 @@ function collectProps(
}

if (at.kind === 'JsxAttribute') {
let newName = at.name;
while (seen.has(newName)) {
newName = `${at.name}${id++}`;
}
const newName = generateName(seen, at.name);
attributes.push({
originalName: at.name,
newName,
place: at.place,
});
seen.add(newName);
}
}

// TODO(gsn): Add support for children that are not jsx expressions
if (
value.children &&
value.children.some(child => !jsxIds.has(child.identifier.id))
) {
return null;
if (value.children) {
for (const child of value.children) {
if (jsxIds.has(child.identifier.id)) {
continue;
}

promoteTemporary(child.identifier);
const newName = generateName(seen, 't');
attributes.push({
originalName: child.identifier.name!.value,
newName: newName,
place: child,
});
}
}
}
return attributes;
Expand Down Expand Up @@ -387,6 +400,7 @@ function emitUpdatedJsx(
oldToNewProps: Map<IdentifierId, OutlinedJsxAttribute>,
): Array<JsxInstruction> {
const newInstrs: Array<JsxInstruction> = [];
const jsxIds = new Set(jsx.map(i => i.lvalue.identifier.id));

for (const instr of jsx) {
const {value} = instr;
Expand All @@ -412,11 +426,30 @@ function emitUpdatedJsx(
});
}

let newChildren: Array<Place> | null = null;
if (value.children) {
newChildren = [];
for (const child of value.children) {
if (jsxIds.has(child.identifier.id)) {
newChildren.push({...child});
continue;
}

const newChild = oldToNewProps.get(child.identifier.id);
invariant(
newChild !== undefined,
`Expected a new prop for ${printIdentifier(child.identifier)}`,
);
newChildren.push({...newChild.place});
}
}

newInstrs.push({
...instr,
value: {
...value,
props: newProps,
children: newChildren,
},
});
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,12 +11,14 @@ function Component({arr}) {
return (
<Bar key={id} x={x}>
<Baz i={i}>Test</Baz>
<Foo k={i} />
</Bar>
);
})}
</>
);
}

function Bar({x, children}) {
return (
<>
Expand All @@ -26,8 +28,17 @@ function Bar({x, children}) {
);
}

function Baz({i}) {
return i;
function Baz({i, children}) {
return (
<>
{i}
{children}
</>
);
}

function Foo({k}) {
return k;
}

function useX() {
Expand All @@ -53,11 +64,11 @@ function Component(t0) {
if ($[0] !== x || $[1] !== arr) {
let t2;
if ($[3] !== x) {
t2 = (i, id) => (
<Bar key={id} x={x}>
<Baz i={i}>Test</Baz>
</Bar>
);
t2 = (i, id) => {
const t3 = "Test";
const T0 = _temp;
return <T0 i={i} t={t3} k={i} key={id} x={x} />;
};
$[3] = x;
$[4] = t2;
} else {
Expand All @@ -80,6 +91,43 @@ function Component(t0) {
}
return t2;
}
function _temp(t0) {
const $ = _c(9);
const { i: i, t: t, k: k, x: x } = t0;
let t1;
if ($[0] !== i || $[1] !== t) {
t1 = <Baz i={i}>{t}</Baz>;
$[0] = i;
$[1] = t;
$[2] = t1;
} else {
t1 = $[2];
}
let t2;
if ($[3] !== k) {
t2 = <Foo k={k} />;
$[3] = k;
$[4] = t2;
} else {
t2 = $[4];
}
let t3;
if ($[5] !== x || $[6] !== t1 || $[7] !== t2) {
t3 = (
<Bar x={x}>
{t1}
{t2}
</Bar>
);
$[5] = x;
$[6] = t1;
$[7] = t2;
$[8] = t3;
} else {
t3 = $[8];
}
return t3;
}

function Bar(t0) {
const $ = _c(3);
Expand All @@ -102,8 +150,28 @@ function Bar(t0) {
}

function Baz(t0) {
const { i } = t0;
return i;
const $ = _c(3);
const { i, children } = t0;
let t1;
if ($[0] !== i || $[1] !== children) {
t1 = (
<>
{i}
{children}
</>
);
$[0] = i;
$[1] = children;
$[2] = t1;
} else {
t1 = $[2];
}
return t1;
}

function Foo(t0) {
const { k } = t0;
return k;
}

function useX() {
Expand All @@ -118,4 +186,4 @@ export const FIXTURE_ENTRYPOINT = {
```
### Eval output
(kind: ok) xfooxbar
(kind: ok) xfooTestfooxbarTestbar
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,14 @@ function Component({arr}) {
return (
<Bar key={id} x={x}>
<Baz i={i}>Test</Baz>
<Foo k={i} />
</Bar>
);
})}
</>
);
}

function Bar({x, children}) {
return (
<>
Expand All @@ -22,8 +24,17 @@ function Bar({x, children}) {
);
}

function Baz({i}) {
return i;
function Baz({i, children}) {
return (
<>
{i}
{children}
</>
);
}

function Foo({k}) {
return k;
}

function useX() {
Expand Down

0 comments on commit 51ff05b

Please sign in to comment.