@samitouri / QOS-React-2 / commits / b69d70664c

Console methods are readonly

Defines common `console` methods to tell the compiler that they take readonly args. This ensures that things like `console.log()` aren't accidentally viewed as a mutation. Previously the pattern of "build object, then log it after mutation is done" would have grouped the console.log as part of the mutation and the log only would fire if the value got reconstructed. Now we know the log isn't mutating, and the log will happen regardless of whether the value is rebuilt or cached.

Joe Savona committed Apr 27, 2023 at 10:34 UTC b69d70664cf52bac084ea092a1cf2d181239aa5e
6 files changed +147 -19
compiler/forget/src/HIR/Globals.ts
+62 -3
@@ -8,11 +8,11 @@
8 import { Effect, ValueKind } from "./HIR";
9 import { Hook } from "./Hooks";
10 import {
11 - addFunction,
12 - addObject,
13 - BuiltInArrayId,
11 BUILTIN_SHAPES,
12 + BuiltInArrayId,
13 ShapeRegistry,
14 + addFunction,
15 + addObject,
16 } from "./ObjectShape";
17 import { BuiltInType, HookType, PolyType } from "./Types";
18
@@ -128,6 +128,65 @@ const TYPED_GLOBALS: Array<[string, BuiltInType]> = [
128 ],
129 ["Infinity", { kind: "Primitive" }],
130 ["NaN", { kind: "Primitive" }],
131 + [
132 + "console",
133 + addObject(DEFAULT_SHAPES, "console", [
134 + [
135 + "error",
136 + addFunction(DEFAULT_SHAPES, [], {
137 + positionalParams: [],
138 + restParam: Effect.Read,
139 + returnType: { kind: "Primitive" },
140 + calleeEffect: Effect.Read,
141 + }),
142 + ],
143 + [
144 + "info",
145 + addFunction(DEFAULT_SHAPES, [], {
146 + positionalParams: [],
147 + restParam: Effect.Read,
148 + returnType: { kind: "Primitive" },
149 + calleeEffect: Effect.Read,
150 + }),
151 + ],
152 + [
153 + "log",
154 + addFunction(DEFAULT_SHAPES, [], {
155 + positionalParams: [],
156 + restParam: Effect.Read,
157 + returnType: { kind: "Primitive" },
158 + calleeEffect: Effect.Read,
159 + }),
160 + ],
161 + [
162 + "table",
163 + addFunction(DEFAULT_SHAPES, [], {
164 + positionalParams: [],
165 + restParam: Effect.Read,
166 + returnType: { kind: "Primitive" },
167 + calleeEffect: Effect.Read,
168 + }),
169 + ],
170 + [
171 + "trace",
172 + addFunction(DEFAULT_SHAPES, [], {
173 + positionalParams: [],
174 + restParam: Effect.Read,
175 + returnType: { kind: "Primitive" },
176 + calleeEffect: Effect.Read,
177 + }),
178 + ],
179 + [
180 + "warn",
181 + addFunction(DEFAULT_SHAPES, [], {
182 + positionalParams: [],
183 + restParam: Effect.Read,
184 + returnType: { kind: "Primitive" },
185 + calleeEffect: Effect.Read,
186 + }),
187 + ],
188 + ]),
189 + ],
190 // TODO: rest of Global objects
191 ];
192
compiler/forget/src/__tests__/fixtures/compiler/console-readonly.expect.md new
+46
@@ -0,0 +1,46 @@
1 +
2 +## Input
3 +
4 +```javascript
5 +function Component(props) {
6 + const x = makeObject(props);
7 + // These calls should view x as readonly and be grouped outside of the reactive scope for x:
8 + console.log(x);
9 + console.info(x);
10 + console.warn(x);
11 + console.error(x);
12 + console.trace(x);
13 + console.table(x);
14 + return x;
15 +}
16 +
17 +```
18 +
19 +## Code
20 +
21 +```javascript
22 +import { unstable_useMemoCache as useMemoCache } from "react";
23 +function Component(props) {
24 + const $ = useMemoCache(2);
25 + const c_0 = $[0] !== props;
26 + let t0;
27 + if (c_0) {
28 + t0 = makeObject(props);
29 + $[0] = props;
30 + $[1] = t0;
31 + } else {
32 + t0 = $[1];
33 + }
34 + const x = t0;
35 +
36 + console.log(x);
37 + console.info(x);
38 + console.warn(x);
39 + console.error(x);
40 + console.trace(x);
41 + console.table(x);
42 + return x;
43 +}
44 +
45 +```
46 +
\ No newline at end of file
compiler/forget/src/__tests__/fixtures/compiler/console-readonly.js new
+11
@@ -0,0 +1,11 @@
1 +function Component(props) {
2 + const x = makeObject(props);
3 + // These calls should view x as readonly and be grouped outside of the reactive scope for x:
4 + console.log(x);
5 + console.info(x);
6 + console.warn(x);
7 + console.error(x);
8 + console.trace(x);
9 + console.table(x);
10 + return x;
11 +}
compiler/forget/src/__tests__/fixtures/compiler/ssa-renaming-ternary-destruction.expect.md
+10 -6
@@ -19,7 +19,7 @@ function foo(props) {
19 ```javascript
20 import { unstable_useMemoCache as useMemoCache } from "react";
21 function foo(props) {
22 - const $ = useMemoCache(4);
22 + const $ = useMemoCache(5);
23 const c_0 = $[0] !== props.bar;
24 let x;
25 if (c_0) {
@@ -31,15 +31,19 @@ function foo(props) {
31 x = $[1];
32 }
33 const c_2 = $[2] !== props;
34 + let t0;
35 if (c_2) {
35 - const _ = props.cond ? (([x] = [[]]), x.push(props.foo)) : null;
36 -
37 - console.log(_);
36 + t0 = props.cond ? (([x] = [[]]), x.push(props.foo)) : null;
37 $[2] = props;
39 - $[3] = x;
38 + $[3] = t0;
39 + $[4] = x;
40 } else {
41 - x = $[3];
41 + t0 = $[3];
42 + x = $[4];
43 }
44 + const _ = t0;
45 +
46 + console.log(_);
47 return x;
48 }
49
compiler/forget/src/__tests__/fixtures/compiler/ssa-renaming-ternary.expect.md
+9 -5
@@ -17,7 +17,7 @@ function foo(props) {
17 ```javascript
18 import { unstable_useMemoCache as useMemoCache } from "react";
19 function foo(props) {
20 - const $ = useMemoCache(4);
20 + const $ = useMemoCache(5);
21 const c_0 = $[0] !== props.bar;
22 let x;
23 if (c_0) {
@@ -29,14 +29,18 @@ function foo(props) {
29 x = $[1];
30 }
31 const c_2 = $[2] !== props;
32 + let t0;
33 if (c_2) {
33 - const _ = props.cond ? ((x = []), x.push(props.foo)) : null;
34 - console.log(_);
34 + t0 = props.cond ? ((x = []), x.push(props.foo)) : null;
35 $[2] = props;
36 - $[3] = x;
36 + $[3] = t0;
37 + $[4] = x;
38 } else {
38 - x = $[3];
39 + t0 = $[3];
40 + x = $[4];
41 }
42 + const _ = t0;
43 + console.log(_);
44 return x;
45 }
46
compiler/forget/src/__tests__/fixtures/compiler/ssa-renaming-unconditional-ternary.expect.md
+9 -5
@@ -19,7 +19,7 @@ function foo(props) {
19 ```javascript
20 import { unstable_useMemoCache as useMemoCache } from "react";
21 function foo(props) {
22 - const $ = useMemoCache(4);
22 + const $ = useMemoCache(5);
23 const c_0 = $[0] !== props.bar;
24 let x;
25 if (c_0) {
@@ -31,16 +31,20 @@ function foo(props) {
31 x = $[1];
32 }
33 const c_2 = $[2] !== props;
34 + let t0;
35 if (c_2) {
35 - const _ = props.cond
36 + t0 = props.cond
37 ? ((x = []), x.push(props.foo))
38 : ((x = []), x.push(props.bar));
38 - console.log(_);
39 $[2] = props;
40 - $[3] = x;
40 + $[3] = t0;
41 + $[4] = x;
42 } else {
42 - x = $[3];
43 + t0 = $[3];
44 + x = $[4];
45 }
46 + const _ = t0;
47 + console.log(_);
48 return x;
49 }
50