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

[compiler] repro for type inference + control flow bug (#31570)

Repro for bug in our type inference system. We currently propagate inferred types through control flow / potential type guards. Note that this is inconsistent with both [Flow](https://flow.org/try/#1N4Igxg9gdgZglgcxALlAIwIZoKYBsD6uEEAztvhgE6UYCe+JADpdhgCYowa5kA0I2KAFcAtiRQAXSkOz9sADwxgJ+NPTbYuQ3BMnTZA+Y2yU4IwRO4A6SFBIrGVDGM7c+h46fNRLuKxJIGWh8MeT0ZfhYlCStpHzNsFBAMIQkIEQwJODAQfiEyfBE4eWw2fDgofDBMsAALfAA3KjgsXGxxZC4eAw0G-GhcWn9aY3wWZldu-g1mbGqJUoBaCRHEzrcDEgBrbAk62kXhXFxJ923d-cPRHEpTgyEoMDaqZdW7vKgoOfaSKgOKpqmDA+d4gB5fMA-P6LCCMLLQbiLOoYCqgh6-GDYRYIXYLSgkRZkCR4jpddwPfJLZjpOBkO4AX34kA0SRWxgABAAxYjsgC87OAAB0oOzReythU2Mh2YKQNyILLeMKxeymrgZNLhCIbsL6QBuYVs7DsgBCVD5AuVYolUClMpAZsoiqtorVGvZWpuSqg9OFMAeyjg0HZdTmW3lAAp5NKAPJoABWcwkAEppWZGLg4O12fJ2bSuTyhSKxSwJEJKCKAOQ2tiVvMi3MAMkbOasNb5vP5svlsoNPuFfoD8JFGQqUel8vZAB9TVReCHoHa0MRnlBUwWIJbi6K4DB2RHbGxk1uVSrd-uAIShsDh4hR5PHoun5-siS1SgQADuHuw34AotQECUBGsqysmfYvuyvrbqepblg2EFitBKpwRWOZ9vSuQgA0JgkEGUBJBk9gmCA9JAA) and [Typescript](https://www.typescriptlang.org/play/?#code/C4TwDgpgBAYg9nKBeKBvAUFLUDWBLAOwBMAuKAInjnIBpNsA3AQwBsBXCMgtgWwCMIAJ3QBfANzpQkKACEmg5GnpZ8xMuTmDayqM3aco3fkLoj0AMzYEAxsDxwCUawAsI1nFQAUADzJw+AFZuwACUZEwAzhFCwBFQ3lB4cVRK2InmUJ4AhJ4A5KpEuYmOCQBkpfEAdAXISCiUCOQhIalp2MDOgnAA7oYQvQCigl2CnuRWEN6QthBETTpmZhZWtvaOPEyEPmQpAD6y8jRODqRQfAgsEEwEYbAIrVh4GZ7WJy0Ybdgubh4IPiEST5YQQQYBsQQlQHYMxpEFgiHxCQiIA)

mofeiZ committed Nov 18, 2024 at 11:54 UTC e33b13795dd25eba780c97b17cf7deee7f21a3e5
4 files changed +158 -1
compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/bug-type-inference-control-flow.expect.md new
+114
@@ -0,0 +1,114 @@
1 +
2 +## Input
3 +
4 +```javascript
5 +import {arrayPush, CONST_NUMBER0, mutate} from 'shared-runtime';
6 +
7 +/**
8 + * Repro for bug in our type inference system. We currently propagate inferred
9 + * types through control flow / potential type guards. Note that this is
10 + * inconsistent with both Flow and Typescript.
11 + * https://flow.org/try/#1N4Igxg9gdgZglgcxALlAIwIZoKYBsD6uEEAztvhgE6UYCe+JADpdhgCYowa5kA0I2KAFcAtiRQAXSkOz9sADwxgJ+NPTbYuQ3BMnTZA+Y2yU4IwRO4A6SFBIrGVDGM7c+h46fNRLuKxJIGWh8MeT0ZfhYlCStpHzNsFBAMIQkIEQwJODAQfiEyfBE4eWw2fDgofDBMsAALfAA3KjgsXGxxZC4eAw0G-GhcWn9aY3wWZldu-g1mbGqJUoBaCRHEzrcDEgBrbAk62kXhXFxJ923d-cPRHEpTgyEoMDaqZdW7vKgoOfaSKgOKpqmDA+d4gB5fMA-P6LCCMLLQbiLOoYCqgh6-GDYRYIXYLSgkRZkCR4jpddwPfJLZjpOBkO4AX34kA0SRWxgABAAxYjsgC87OAAB0oOzReythU2Mh2YKQNyILLeMKxeymrgZNLhCIbsL6QBuYVs7DsgBCVD5AuVYolUClMpAZsoiqtorVGvZWpuSqg9OFMAeyjg0HZdTmW3lAAp5NKAPJoABWcwkAEppWZGLg4O12fJ2bSuTyhSKxSwJEJKCKAOQ2tiVvMi3MAMkbOasNb5vP5svlsoNPuFfoD8JFGQqUel8vZAB9TVReCHoHa0MRnlBUwWIJbi6K4DB2RHbGxk1uVSrd-uAIShsDh4hR5PHoun5-siS1SgQADuHuw34AotQECUBGsqysmfYvuyvrbqepblg2EFitBKpwRWOZ9vSuQgA0JgkEGUBJBk9gmCA9JAA
12 + * https://www.typescriptlang.org/play/?#code/C4TwDgpgBAYg9nKBeKBvAUFLUDWBLAOwBMAuKAInjnIBpNsA3AQwBsBXCMgtgWwCMIAJ3QBfANzpQkKACEmg5GnpZ8xMuTmDayqM3aco3fkLoj0AMzYEAxsDxwCUawAsI1nFQAUADzJw+AFZuwACUZEwAzhFCwBFQ3lB4cVRK2InmUJ4AhJ4A5KpEuYmOCQBkpfEAdAXISCiUCOQhIalp2MDOgnAA7oYQvQCigl2CnuRWEN6QthBETTpmZhZWtvaOPEyEPmQpAD6y8jRODqRQfAgsEEwEYbAIrVh4GZ7WJy0Ybdgubh4IPiEST5YQQQYBsQQlQHYMxpEFgiHxCQiIA
13 + *
14 + * Found differences in evaluator results
15 + * Non-forget (expected):
16 + * (kind: ok)
17 + * [2]
18 + * [3]
19 + * Forget:
20 + * (kind: ok)
21 + * [2]
22 + * [2,3]
23 + */
24 +function useFoo({cond, value}: {cond: boolean; value: number}) {
25 + const x = {value: cond ? CONST_NUMBER0 : []};
26 + mutate(x);
27 +
28 + const xValue = x.value;
29 + let result;
30 + if (typeof xValue === 'number') {
31 + result = xValue + 1; // (1) here we infer xValue is a primitive
32 + } else {
33 + result = arrayPush(xValue, value); // (2) and propagate it to all other xValue references
34 + }
35 +
36 + return result;
37 +}
38 +export const FIXTURE_ENTRYPOINT = {
39 + fn: useFoo,
40 + params: [{cond: true}],
41 + sequentialRenders: [
42 + {cond: false, value: 2},
43 + {cond: false, value: 3},
44 + ],
45 +};
46 +
47 +```
48 +
49 +## Code
50 +
51 +```javascript
52 +import { c as _c } from "react/compiler-runtime";
53 +import { arrayPush, CONST_NUMBER0, mutate } from "shared-runtime";
54 +
55 +/**
56 + * Repro for bug in our type inference system. We currently propagate inferred
57 + * types through control flow / potential type guards. Note that this is
58 + * inconsistent with both Flow and Typescript.
59 + * https://flow.org/try/#1N4Igxg9gdgZglgcxALlAIwIZoKYBsD6uEEAztvhgE6UYCe+JADpdhgCYowa5kA0I2KAFcAtiRQAXSkOz9sADwxgJ+NPTbYuQ3BMnTZA+Y2yU4IwRO4A6SFBIrGVDGM7c+h46fNRLuKxJIGWh8MeT0ZfhYlCStpHzNsFBAMIQkIEQwJODAQfiEyfBE4eWw2fDgofDBMsAALfAA3KjgsXGxxZC4eAw0G-GhcWn9aY3wWZldu-g1mbGqJUoBaCRHEzrcDEgBrbAk62kXhXFxJ923d-cPRHEpTgyEoMDaqZdW7vKgoOfaSKgOKpqmDA+d4gB5fMA-P6LCCMLLQbiLOoYCqgh6-GDYRYIXYLSgkRZkCR4jpddwPfJLZjpOBkO4AX34kA0SRWxgABAAxYjsgC87OAAB0oOzReythU2Mh2YKQNyILLeMKxeymrgZNLhCIbsL6QBuYVs7DsgBCVD5AuVYolUClMpAZsoiqtorVGvZWpuSqg9OFMAeyjg0HZdTmW3lAAp5NKAPJoABWcwkAEppWZGLg4O12fJ2bSuTyhSKxSwJEJKCKAOQ2tiVvMi3MAMkbOasNb5vP5svlsoNPuFfoD8JFGQqUel8vZAB9TVReCHoHa0MRnlBUwWIJbi6K4DB2RHbGxk1uVSrd-uAIShsDh4hR5PHoun5-siS1SgQADuHuw34AotQECUBGsqysmfYvuyvrbqepblg2EFitBKpwRWOZ9vSuQgA0JgkEGUBJBk9gmCA9JAA
60 + * https://www.typescriptlang.org/play/?#code/C4TwDgpgBAYg9nKBeKBvAUFLUDWBLAOwBMAuKAInjnIBpNsA3AQwBsBXCMgtgWwCMIAJ3QBfANzpQkKACEmg5GnpZ8xMuTmDayqM3aco3fkLoj0AMzYEAxsDxwCUawAsI1nFQAUADzJw+AFZuwACUZEwAzhFCwBFQ3lB4cVRK2InmUJ4AhJ4A5KpEuYmOCQBkpfEAdAXISCiUCOQhIalp2MDOgnAA7oYQvQCigl2CnuRWEN6QthBETTpmZhZWtvaOPEyEPmQpAD6y8jRODqRQfAgsEEwEYbAIrVh4GZ7WJy0Ybdgubh4IPiEST5YQQQYBsQQlQHYMxpEFgiHxCQiIA
61 + *
62 + * Found differences in evaluator results
63 + * Non-forget (expected):
64 + * (kind: ok)
65 + * [2]
66 + * [3]
67 + * Forget:
68 + * (kind: ok)
69 + * [2]
70 + * [2,3]
71 + */
72 +function useFoo(t0) {
73 + const $ = _c(5);
74 + const { cond, value } = t0;
75 + let x;
76 + if ($[0] !== cond) {
77 + x = { value: cond ? CONST_NUMBER0 : [] };
78 + mutate(x);
79 + $[0] = cond;
80 + $[1] = x;
81 + } else {
82 + x = $[1];
83 + }
84 +
85 + const xValue = x.value;
86 + let result;
87 + if (typeof xValue === "number") {
88 + result = xValue + 1;
89 + } else {
90 + let t1;
91 + if ($[2] !== value || $[3] !== xValue) {
92 + t1 = arrayPush(xValue, value);
93 + $[2] = value;
94 + $[3] = xValue;
95 + $[4] = t1;
96 + } else {
97 + t1 = $[4];
98 + }
99 + result = t1;
100 + }
101 + return result;
102 +}
103 +
104 +export const FIXTURE_ENTRYPOINT = {
105 + fn: useFoo,
106 + params: [{ cond: true }],
107 + sequentialRenders: [
108 + { cond: false, value: 2 },
109 + { cond: false, value: 3 },
110 + ],
111 +};
112 +
113 +```
114 +
\ No newline at end of file
compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/bug-type-inference-control-flow.ts new
+41
@@ -0,0 +1,41 @@
1 +import {arrayPush, CONST_NUMBER0, mutate} from 'shared-runtime';
2 +
3 +/**
4 + * Repro for bug in our type inference system. We currently propagate inferred
5 + * types through control flow / potential type guards. Note that this is
6 + * inconsistent with both Flow and Typescript.
7 + * https://flow.org/try/#1N4Igxg9gdgZglgcxALlAIwIZoKYBsD6uEEAztvhgE6UYCe+JADpdhgCYowa5kA0I2KAFcAtiRQAXSkOz9sADwxgJ+NPTbYuQ3BMnTZA+Y2yU4IwRO4A6SFBIrGVDGM7c+h46fNRLuKxJIGWh8MeT0ZfhYlCStpHzNsFBAMIQkIEQwJODAQfiEyfBE4eWw2fDgofDBMsAALfAA3KjgsXGxxZC4eAw0G-GhcWn9aY3wWZldu-g1mbGqJUoBaCRHEzrcDEgBrbAk62kXhXFxJ923d-cPRHEpTgyEoMDaqZdW7vKgoOfaSKgOKpqmDA+d4gB5fMA-P6LCCMLLQbiLOoYCqgh6-GDYRYIXYLSgkRZkCR4jpddwPfJLZjpOBkO4AX34kA0SRWxgABAAxYjsgC87OAAB0oOzReythU2Mh2YKQNyILLeMKxeymrgZNLhCIbsL6QBuYVs7DsgBCVD5AuVYolUClMpAZsoiqtorVGvZWpuSqg9OFMAeyjg0HZdTmW3lAAp5NKAPJoABWcwkAEppWZGLg4O12fJ2bSuTyhSKxSwJEJKCKAOQ2tiVvMi3MAMkbOasNb5vP5svlsoNPuFfoD8JFGQqUel8vZAB9TVReCHoHa0MRnlBUwWIJbi6K4DB2RHbGxk1uVSrd-uAIShsDh4hR5PHoun5-siS1SgQADuHuw34AotQECUBGsqysmfYvuyvrbqepblg2EFitBKpwRWOZ9vSuQgA0JgkEGUBJBk9gmCA9JAA
8 + * https://www.typescriptlang.org/play/?#code/C4TwDgpgBAYg9nKBeKBvAUFLUDWBLAOwBMAuKAInjnIBpNsA3AQwBsBXCMgtgWwCMIAJ3QBfANzpQkKACEmg5GnpZ8xMuTmDayqM3aco3fkLoj0AMzYEAxsDxwCUawAsI1nFQAUADzJw+AFZuwACUZEwAzhFCwBFQ3lB4cVRK2InmUJ4AhJ4A5KpEuYmOCQBkpfEAdAXISCiUCOQhIalp2MDOgnAA7oYQvQCigl2CnuRWEN6QthBETTpmZhZWtvaOPEyEPmQpAD6y8jRODqRQfAgsEEwEYbAIrVh4GZ7WJy0Ybdgubh4IPiEST5YQQQYBsQQlQHYMxpEFgiHxCQiIA
9 + *
10 + * Found differences in evaluator results
11 + * Non-forget (expected):
12 + * (kind: ok)
13 + * [2]
14 + * [3]
15 + * Forget:
16 + * (kind: ok)
17 + * [2]
18 + * [2,3]
19 + */
20 +function useFoo({cond, value}: {cond: boolean; value: number}) {
21 + const x = {value: cond ? CONST_NUMBER0 : []};
22 + mutate(x);
23 +
24 + const xValue = x.value;
25 + let result;
26 + if (typeof xValue === 'number') {
27 + result = xValue + 1; // (1) here we infer xValue is a primitive
28 + } else {
29 + result = arrayPush(xValue, value); // (2) and propagate it to all other xValue references
30 + }
31 +
32 + return result;
33 +}
34 +export const FIXTURE_ENTRYPOINT = {
35 + fn: useFoo,
36 + params: [{cond: true}],
37 + sequentialRenders: [
38 + {cond: false, value: 2},
39 + {cond: false, value: 3},
40 + ],
41 +};
compiler/packages/snap/src/SproutTodoFilter.ts
+1
@@ -485,6 +485,7 @@ const skipFilter = new Set([
485 'bug-aliased-capture-mutate',
486 'bug-functiondecl-hoisting',
487 'bug-try-catch-maybe-null-dependency',
488 + 'bug-type-inference-control-flow',
489 'reduce-reactive-deps/bug-infer-function-cond-access-not-hoisted',
490 'bug-invalid-phi-as-dependency',
491 'reduce-reactive-deps/bug-merge-uncond-optional-chain-and-cond',
compiler/packages/snap/src/sprout/shared-runtime.ts
+2 -1
@@ -107,8 +107,9 @@ export function setPropertyByKey<
107 return arg;
108 }
109
110 -export function arrayPush<T>(arr: Array<T>, ...values: Array<T>): void {
110 +export function arrayPush<T>(arr: Array<T>, ...values: Array<T>): Array<T> {
111 arr.push(...values);
112 + return arr;
113 }
114
115 export function graphql(value: string): string {