Skip to content

Commit

Permalink
[compiler] Outline jsx with duplicate attributes
Browse files Browse the repository at this point in the history
Previously, we would skip outlining jsx expressions that had duplicate
jsx attributes as we would not rename them causing incorrect
compilation.

In thir PR, we add outlining support for duplicate jsx attributes by
renaming them.

ghstack-source-id: 3777d9947304d8ebcc5617ecf1a4f26ae4701684
Pull Request resolved: facebook#31378
  • Loading branch information
gsathya committed Nov 6, 2024
1 parent fe9e9d9 commit 8161333
Show file tree
Hide file tree
Showing 9 changed files with 675 additions and 23 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -222,6 +222,8 @@ function collectProps(
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 @@ -230,21 +232,17 @@ function collectProps(
return null;
}

/*
* TODO(gsn): Handle attributes that have same value across
* the outlined jsx instructions.
*/
if (seen.has(at.name)) {
return null;
}

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

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,166 @@

## Input

```javascript
// @enableJsxOutlining
function Component({arr}) {
const x = useX();
return (
<>
{arr.map((i, id) => {
return (
<Bar key={id} x={x}>
<Baz i={i + 'i'}></Baz>
<Foo k={i + 'j'}></Foo>
</Bar>
);
})}
</>
);
}
function Bar({x, children}) {
return (
<>
{x}
{children}
</>
);
}

function Baz({i}) {
return i;
}

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

function useX() {
return 'x';
}

export const FIXTURE_ENTRYPOINT = {
fn: Component,
params: [{arr: ['foo', 'bar']}],
};

```

## Code

```javascript
import { c as _c } from "react/compiler-runtime"; // @enableJsxOutlining
function Component(t0) {
const $ = _c(7);
const { arr } = t0;
const x = useX();
let t1;
if ($[0] !== arr || $[1] !== x) {
let t2;
if ($[3] !== x) {
t2 = (i, id) => {
const T0 = _temp;
return <T0 i={i + "i"} k={i + "j"} key={id} x={x} />;
};
$[3] = x;
$[4] = t2;
} else {
t2 = $[4];
}
t1 = arr.map(t2);
$[0] = arr;
$[1] = x;
$[2] = t1;
} else {
t1 = $[2];
}
let t2;
if ($[5] !== t1) {
t2 = <>{t1}</>;
$[5] = t1;
$[6] = t2;
} else {
t2 = $[6];
}
return t2;
}
function _temp(t0) {
const $ = _c(8);
const { i: i, k: k, x: x } = t0;
let t1;
if ($[0] !== i) {
t1 = <Baz i={i} />;
$[0] = i;
$[1] = t1;
} else {
t1 = $[1];
}
let t2;
if ($[2] !== k) {
t2 = <Foo k={k} />;
$[2] = k;
$[3] = t2;
} else {
t2 = $[3];
}
let t3;
if ($[4] !== t1 || $[5] !== t2 || $[6] !== x) {
t3 = (
<Bar x={x}>
{t1}
{t2}
</Bar>
);
$[4] = t1;
$[5] = t2;
$[6] = x;
$[7] = t3;
} else {
t3 = $[7];
}
return t3;
}

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

function Baz(t0) {
const { i } = t0;
return i;
}

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

function useX() {
return "x";
}

export const FIXTURE_ENTRYPOINT = {
fn: Component,
params: [{ arr: ["foo", "bar"] }],
};

```
### Eval output
(kind: ok) xfooifoojxbaribarj
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
// @enableJsxOutlining
function Component({arr}) {
const x = useX();
return (
<>
{arr.map((i, id) => {
return (
<Bar key={id} x={x}>
<Baz i={i + 'i'}></Baz>
<Foo k={i + 'j'}></Foo>
</Bar>
);
})}
</>
);
}
function Bar({x, children}) {
return (
<>
{x}
{children}
</>
);
}

function Baz({i}) {
return i;
}

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

function useX() {
return 'x';
}

export const FIXTURE_ENTRYPOINT = {
fn: Component,
params: [{arr: ['foo', 'bar']}],
};
Loading

0 comments on commit 8161333

Please sign in to comment.