@samitouri / QOS-React / commits / be7f98d584

Scaffolding for rest params

Updates HIR to represent rest element function parameters. We don't construct these yet.

Joe Savona committed Sep 27, 2023 at 14:04 UTC be7f98d5841d16dc553eeb58f372be9cb6e3a05a
10 files changed +92 -26
compiler/packages/babel-plugin-react-forget/src/HIR/HIR.ts
+2 -2
@@ -48,7 +48,7 @@ export type SourceLocation = t.SourceLocation | typeof GeneratedSource;
48 export type ReactiveFunction = {
49 loc: SourceLocation;
50 id: string | null;
51 - params: Array<Place>;
51 + params: Array<Place | SpreadPattern>;
52 generator: boolean;
53 async: boolean;
54 body: ReactiveBlock;
@@ -232,7 +232,7 @@ export type HIRFunction = {
232 loc: SourceLocation;
233 id: string | null;
234 env: Environment;
235 - params: Array<Place>;
235 + params: Array<Place | SpreadPattern>;
236 context: Array<Place>;
237 body: HIR;
238 generator: boolean;
compiler/packages/babel-plugin-react-forget/src/Inference/InferReferenceEffects.ts
+18 -6
@@ -110,13 +110,25 @@ export default function inferReferenceEffects(
110 ? ValueKind.Mutable
111 : ValueKind.Frozen;
112 for (const param of fn.params) {
113 - const value: InstructionValue = {
114 - kind: "Primitive",
115 - loc: param.loc,
116 - value: undefined,
117 - };
113 + let value: InstructionValue;
114 + let place: Place;
115 + if (param.kind === "Identifier") {
116 + place = param;
117 + value = {
118 + kind: "Primitive",
119 + loc: param.loc,
120 + value: undefined,
121 + };
122 + } else {
123 + place = param.place;
124 + value = {
125 + kind: "Primitive",
126 + loc: param.place.loc,
127 + value: undefined,
128 + };
129 + }
130 initialState.initialize(value, paramKind);
119 - initialState.define(param, value);
131 + initialState.define(place, value);
132 }
133
134 // Map of blocks to the last (merged) incoming state that was processed
compiler/packages/babel-plugin-react-forget/src/ReactiveScopes/CodegenReactiveFunction.ts
+16 -2
@@ -54,10 +54,14 @@ export function codegenReactiveFunction(
54 ): Result<CodegenFunction, CompilerError> {
55 const cx = new Context(fn.env, fn.id ?? "[[ anonymous ]]");
56 for (const param of fn.params) {
57 - cx.temp.set(param.identifier.id, null);
57 + if (param.kind === "Identifier") {
58 + cx.temp.set(param.identifier.id, null);
59 + } else {
60 + cx.temp.set(param.place.identifier.id, null);
61 + }
62 }
63
60 - const params = fn.params.map((param) => convertIdentifier(param.identifier));
64 + const params = fn.params.map((param) => convertParameter(param));
65 const body = codegenBlock(cx, fn.body);
66 const statements = body.body;
67 if (statements.length !== 0) {
@@ -97,6 +101,16 @@ export function codegenReactiveFunction(
101 });
102 }
103
104 +function convertParameter(
105 + param: Place | SpreadPattern
106 +): t.Identifier | t.RestElement {
107 + if (param.kind === "Identifier") {
108 + return convertIdentifier(param.identifier);
109 + } else {
110 + return t.restElement(convertIdentifier(param.place.identifier));
111 + }
112 +}
113 +
114 class Context {
115 env: Environment;
116 fnName: string;
compiler/packages/babel-plugin-react-forget/src/ReactiveScopes/InferReactiveIdentifiers.ts
+5 -1
@@ -188,7 +188,11 @@ export function inferReactiveIdentifiers(
188 const visitor = new Visitor();
189 const state = new State(fn.env);
190 for (const param of fn.params) {
191 - state.reactivityMap.set(param.identifier.id, true);
191 + if (param.kind === "Identifier") {
192 + state.reactivityMap.set(param.identifier.id, true);
193 + } else {
194 + state.reactivityMap.set(param.place.identifier.id, true);
195 + }
196 }
197 visitReactiveFunction(fn, visitor, state);
198
compiler/packages/babel-plugin-react-forget/src/ReactiveScopes/PrintReactiveFunction.ts
+5 -1
@@ -27,7 +27,11 @@ export function printReactiveFunction(fn: ReactiveFunction): string {
27 writer.writeLine(`function ${fn.id !== null ? fn.id : "<unknown>"}(`);
28 writer.indented(() => {
29 for (const param of fn.params) {
30 - writer.writeLine(`${printPlace(param)},`);
30 + if (param.kind === "Identifier") {
31 + writer.writeLine(`${printPlace(param)},`);
32 + } else {
33 + writer.writeLine(`...${printPlace(param.place)},`);
34 + }
35 }
36 });
37 writer.writeLine(") {");
compiler/packages/babel-plugin-react-forget/src/ReactiveScopes/PropagateScopeDependencies.ts
+11 -4
@@ -50,10 +50,17 @@ export function propagateScopeDependencies(fn: ReactiveFunction): void {
50
51 const context = new Context(escapingTemporaries.usedOutsideDeclaringScope);
52 for (const param of fn.params) {
53 - context.declare(param.identifier, {
54 - id: makeInstructionId(0),
55 - scope: empty(),
56 - });
53 + if (param.kind === "Identifier") {
54 + context.declare(param.identifier, {
55 + id: makeInstructionId(0),
56 + scope: empty(),
57 + });
58 + } else {
59 + context.declare(param.place.identifier, {
60 + id: makeInstructionId(0),
61 + scope: empty(),
62 + });
63 + }
64 }
65 visitReactiveFunction(fn, new PropagationVisitor(), context);
66 }
compiler/packages/babel-plugin-react-forget/src/ReactiveScopes/PruneNonEscapingScopes.ts
+5 -1
@@ -117,7 +117,11 @@ export function pruneNonEscapingScopes(
117 // and which values are returned.
118 const state = new State(fn.env);
119 for (const param of fn.params) {
120 - state.declare(param.identifier.id);
120 + if (param.kind === "Identifier") {
121 + state.declare(param.identifier.id);
122 + } else {
123 + state.declare(param.place.identifier.id);
124 + }
125 }
126 visitReactiveFunction(
127 fn,
compiler/packages/babel-plugin-react-forget/src/ReactiveScopes/RenameVariables.ts
+5 -1
@@ -34,7 +34,11 @@ export function renameVariables(fn: ReactiveFunction): void {
34 const scopes = new Scopes();
35 scopes.enter(() => {
36 for (const param of fn.params) {
37 - scopes.visit(param.identifier);
37 + if (param.kind === "Identifier") {
38 + scopes.visit(param.identifier);
39 + } else {
40 + scopes.visit(param.place.identifier);
41 + }
42 }
43 visitReactiveFunction(fn, new Visitor(), scopes);
44 });
compiler/packages/babel-plugin-react-forget/src/SSA/EnterSSA.ts
+20 -4
@@ -259,7 +259,16 @@ function enterSSAImpl(
259 loc: func.loc,
260 suggestions: null,
261 });
262 - func.params = func.params.map((p) => builder.definePlace(p));
262 + func.params = func.params.map((param) => {
263 + if (param.kind === "Identifier") {
264 + return builder.definePlace(param);
265 + } else {
266 + return {
267 + kind: "Spread",
268 + place: builder.definePlace(param.place),
269 + };
270 + }
271 + });
272 }
273
274 for (const instr of block.instructions) {
@@ -282,9 +291,16 @@ function enterSSAImpl(
291 loweredFunc.context = loweredFunc.context.map((p) =>
292 builder.getPlace(p)
293 );
285 - loweredFunc.params = loweredFunc.params.map((p) =>
286 - builder.definePlace(p)
287 - );
294 + loweredFunc.params = loweredFunc.params.map((param) => {
295 + if (param.kind === "Identifier") {
296 + return builder.definePlace(param);
297 + } else {
298 + return {
299 + kind: "Spread",
300 + place: builder.definePlace(param.place),
301 + };
302 + }
303 + });
304 enterSSAImpl(loweredFunc, builder, rootEntry);
305 });
306 entry.preds.clear();
compiler/packages/babel-plugin-react-forget/src/SSA/LeaveSSA.ts
+5 -4
@@ -100,13 +100,14 @@ export function leaveSSA(fn: HIRFunction): void {
100 > = new Map();
101
102 for (const param of fn.params) {
103 - if (param.identifier.name !== null) {
104 - declarations.set(param.identifier.name, {
103 + let place: Place = param.kind === "Identifier" ? param : param.place;
104 + if (place.identifier.name !== null) {
105 + declarations.set(place.identifier.name, {
106 lvalue: {
107 kind: InstructionKind.Let,
107 - place: param,
108 + place,
109 },
109 - place: param,
110 + place,
111 });
112 }
113 }