@samitouri / QOS-React / commits / 2df8f61885

[compiler] Store original and new prop names (#31440)

Previously, we'd directly store the original attributes from the jsx expressions. But this isn't enough as we want to rename duplicate attributes. This PR refactors the prop collection logic to store both the original and new names for jsx attributes in the newly outlined jsx expression. For now, both the new and old names are the same. In the future, they will be different when we add support for outlining expressions with duplicate attribute names.

Sathya Gunasekaran committed Nov 6, 2024 at 17:44 UTC 2df8f6188537514a538741064ae83682c2bef7c1
1 file changed +49 -27
compiler/packages/babel-plugin-react-compiler/src/Optimization/OutlineJsx.ts
+49 -27
@@ -210,10 +210,16 @@ function process(
210 return {instrs: newInstrs, fn: outlinedFn};
211 }
212
213 +type OutlinedJsxAttribute = {
214 + originalName: string;
215 + newName: string;
216 + place: Place;
217 +};
218 +
219 function collectProps(
220 instructions: Array<JsxInstruction>,
215 -): Array<JsxAttribute> | null {
216 - const attributes: Array<JsxAttribute> = [];
221 +): Array<OutlinedJsxAttribute> | null {
222 + const attributes: Array<OutlinedJsxAttribute> = [];
223 const jsxIds = new Set(instructions.map(i => i.lvalue.identifier.id));
224 const seen: Set<string> = new Set();
225 for (const instr of instructions) {
@@ -234,7 +240,11 @@ function collectProps(
240
241 if (at.kind === 'JsxAttribute') {
242 seen.add(at.name);
237 - attributes.push(at);
243 + attributes.push({
244 + originalName: at.name,
245 + newName: at.name,
246 + place: at.place,
247 + });
248 }
249 }
250
@@ -252,9 +262,15 @@ function collectProps(
262 function emitOutlinedJsx(
263 env: Environment,
264 instructions: Array<Instruction>,
255 - props: Array<JsxAttribute>,
265 + outlinedProps: Array<OutlinedJsxAttribute>,
266 outlinedTag: string,
267 ): Array<Instruction> {
268 + const props: Array<JsxAttribute> = outlinedProps.map(p => ({
269 + kind: 'JsxAttribute',
270 + name: p.newName,
271 + place: p.place,
272 + }));
273 +
274 const loadJsx: Instruction = {
275 id: makeInstructionId(0),
276 loc: GeneratedSource,
@@ -290,7 +306,7 @@ function emitOutlinedJsx(
306 function emitOutlinedFn(
307 env: Environment,
308 jsx: Array<JsxInstruction>,
293 - oldProps: Array<JsxAttribute>,
309 + oldProps: Array<OutlinedJsxAttribute>,
310 globals: LoadGlobalMap,
311 ): HIRFunction | null {
312 const instructions: Array<Instruction> = [];
@@ -299,9 +315,11 @@ function emitOutlinedFn(
315 const propsObj: Place = createTemporaryPlace(env, GeneratedSource);
316 promoteTemporary(propsObj.identifier);
317
302 - const destructurePropsInstr = emitDestructureProps(env, propsObj, [
303 - ...oldToNewProps.values(),
304 - ]);
318 + const destructurePropsInstr = emitDestructureProps(
319 + env,
320 + propsObj,
321 + oldToNewProps,
322 + );
323 instructions.push(destructurePropsInstr);
324
325 const updatedJsxInstructions = emitUpdatedJsx(jsx, oldToNewProps);
@@ -368,7 +386,7 @@ function emitLoadGlobals(
386
387 function emitUpdatedJsx(
388 jsx: Array<JsxInstruction>,
371 - oldToNewProps: Map<IdentifierId, ObjectProperty>,
389 + oldToNewProps: Map<IdentifierId, OutlinedJsxAttribute>,
390 ): Array<JsxInstruction> {
391 const newInstrs: Array<JsxInstruction> = [];
392
@@ -390,7 +408,8 @@ function emitUpdatedJsx(
408 `Expected a new property for ${printIdentifier(prop.place.identifier)}`,
409 );
410 newProps.push({
393 - ...prop,
411 + kind: 'JsxAttribute',
412 + name: newProp.originalName,
413 place: newProp.place,
414 });
415 }
@@ -409,31 +428,21 @@ function emitUpdatedJsx(
428
429 function createOldToNewPropsMapping(
430 env: Environment,
412 - oldProps: Array<JsxAttribute>,
413 -): Map<IdentifierId, ObjectProperty> {
431 + oldProps: Array<OutlinedJsxAttribute>,
432 +): Map<IdentifierId, OutlinedJsxAttribute> {
433 const oldToNewProps = new Map();
434
435 for (const oldProp of oldProps) {
417 - invariant(
418 - oldProp.kind === 'JsxAttribute',
419 - `Expected only attributes but found ${oldProp.kind}`,
420 - );
421 -
436 // Do not read key prop in the outlined component
423 - if (oldProp.name === 'key') {
437 + if (oldProp.originalName === 'key') {
438 continue;
439 }
440
427 - const newProp: ObjectProperty = {
428 - kind: 'ObjectProperty',
429 - key: {
430 - kind: 'string',
431 - name: oldProp.name,
432 - },
433 - type: 'property',
441 + const newProp: OutlinedJsxAttribute = {
442 + ...oldProp,
443 place: createTemporaryPlace(env, GeneratedSource),
444 };
436 - newProp.place.identifier.name = makeIdentifierName(oldProp.name);
445 + newProp.place.identifier.name = makeIdentifierName(oldProp.newName);
446 oldToNewProps.set(oldProp.place.identifier.id, newProp);
447 }
448
@@ -443,8 +452,21 @@ function createOldToNewPropsMapping(
452 function emitDestructureProps(
453 env: Environment,
454 propsObj: Place,
446 - properties: Array<ObjectProperty>,
455 + oldToNewProps: Map<IdentifierId, OutlinedJsxAttribute>,
456 ): Instruction {
457 + const properties: Array<ObjectProperty> = [];
458 + for (const [_, prop] of oldToNewProps) {
459 + properties.push({
460 + kind: 'ObjectProperty',
461 + key: {
462 + kind: 'string',
463 + name: prop.newName,
464 + },
465 + type: 'property',
466 + place: prop.place,
467 + });
468 + }
469 +
470 const destructurePropsInstr: Instruction = {
471 id: makeInstructionId(0),
472 lvalue: createTemporaryPlace(env, GeneratedSource),