|
| 1 | + |
| 2 | +## Input |
| 3 | + |
| 4 | +```javascript |
| 5 | +import {makeArray, mutate} from 'shared-runtime'; |
| 6 | + |
| 7 | +/** |
| 8 | + * Bug repro: |
| 9 | + * Found differences in evaluator results |
| 10 | + * Non-forget (expected): |
| 11 | + * (kind: ok) |
| 12 | + * {"bar":4,"x":{"foo":3,"wat0":"joe"}} |
| 13 | + * {"bar":5,"x":{"foo":3,"wat0":"joe"}} |
| 14 | + * Forget: |
| 15 | + * (kind: ok) |
| 16 | + * {"bar":4,"x":{"foo":3,"wat0":"joe"}} |
| 17 | + * {"bar":5,"x":{"foo":3,"wat0":"joe","wat1":"joe"}} |
| 18 | + * |
| 19 | + * Fork of `capturing-func-alias-captured-mutate`, but instead of directly |
| 20 | + * aliasing `y` via `[y]`, we make an opaque call. |
| 21 | + * |
| 22 | + * Note that the bug here is that we don't infer that `a = makeArray(y)` |
| 23 | + * potentially captures a context variable into a local variable. As a result, |
| 24 | + * we don't understand that `a[0].x = b` captures `x` into `y` -- instead, we're |
| 25 | + * currently inferring that this lambda captures `y` (for a potential later |
| 26 | + * mutation) and simply reads `x`. |
| 27 | + * |
| 28 | + * Concretely `InferReferenceEffects.hasContextRefOperand` is incorrectly not |
| 29 | + * used when we analyze CallExpressions. |
| 30 | + */ |
| 31 | +function Component({foo, bar}: {foo: number; bar: number}) { |
| 32 | + let x = {foo}; |
| 33 | + let y: {bar: number; x?: {foo: number}} = {bar}; |
| 34 | + const f0 = function () { |
| 35 | + let a = makeArray(y); // a = [y] |
| 36 | + let b = x; |
| 37 | + // this writes y.x = x |
| 38 | + a[0].x = b; |
| 39 | + }; |
| 40 | + f0(); |
| 41 | + mutate(y.x); |
| 42 | + return y; |
| 43 | +} |
| 44 | + |
| 45 | +export const FIXTURE_ENTRYPOINT = { |
| 46 | + fn: Component, |
| 47 | + params: [{foo: 3, bar: 4}], |
| 48 | + sequentialRenders: [ |
| 49 | + {foo: 3, bar: 4}, |
| 50 | + {foo: 3, bar: 5}, |
| 51 | + ], |
| 52 | +}; |
| 53 | + |
| 54 | +``` |
| 55 | + |
| 56 | +## Code |
| 57 | + |
| 58 | +```javascript |
| 59 | +import { c as _c } from "react/compiler-runtime"; |
| 60 | +import { makeArray, mutate } from "shared-runtime"; |
| 61 | + |
| 62 | +/** |
| 63 | + * Bug repro: |
| 64 | + * Found differences in evaluator results |
| 65 | + * Non-forget (expected): |
| 66 | + * (kind: ok) |
| 67 | + * {"bar":4,"x":{"foo":3,"wat0":"joe"}} |
| 68 | + * {"bar":5,"x":{"foo":3,"wat0":"joe"}} |
| 69 | + * Forget: |
| 70 | + * (kind: ok) |
| 71 | + * {"bar":4,"x":{"foo":3,"wat0":"joe"}} |
| 72 | + * {"bar":5,"x":{"foo":3,"wat0":"joe","wat1":"joe"}} |
| 73 | + * |
| 74 | + * Fork of `capturing-func-alias-captured-mutate`, but instead of directly |
| 75 | + * aliasing `y` via `[y]`, we make an opaque call. |
| 76 | + * |
| 77 | + * Note that the bug here is that we don't infer that `a = makeArray(y)` |
| 78 | + * potentially captures a context variable into a local variable. As a result, |
| 79 | + * we don't understand that `a[0].x = b` captures `x` into `y` -- instead, we're |
| 80 | + * currently inferring that this lambda captures `y` (for a potential later |
| 81 | + * mutation) and simply reads `x`. |
| 82 | + * |
| 83 | + * Concretely `InferReferenceEffects.hasContextRefOperand` is incorrectly not |
| 84 | + * used when we analyze CallExpressions. |
| 85 | + */ |
| 86 | +function Component(t0) { |
| 87 | + const $ = _c(5); |
| 88 | + const { foo, bar } = t0; |
| 89 | + let t1; |
| 90 | + if ($[0] !== foo) { |
| 91 | + t1 = { foo }; |
| 92 | + $[0] = foo; |
| 93 | + $[1] = t1; |
| 94 | + } else { |
| 95 | + t1 = $[1]; |
| 96 | + } |
| 97 | + const x = t1; |
| 98 | + let y; |
| 99 | + if ($[2] !== bar || $[3] !== x) { |
| 100 | + y = { bar }; |
| 101 | + const f0 = function () { |
| 102 | + const a = makeArray(y); |
| 103 | + const b = x; |
| 104 | + |
| 105 | + a[0].x = b; |
| 106 | + }; |
| 107 | + |
| 108 | + f0(); |
| 109 | + mutate(y.x); |
| 110 | + $[2] = bar; |
| 111 | + $[3] = x; |
| 112 | + $[4] = y; |
| 113 | + } else { |
| 114 | + y = $[4]; |
| 115 | + } |
| 116 | + return y; |
| 117 | +} |
| 118 | + |
| 119 | +export const FIXTURE_ENTRYPOINT = { |
| 120 | + fn: Component, |
| 121 | + params: [{ foo: 3, bar: 4 }], |
| 122 | + sequentialRenders: [ |
| 123 | + { foo: 3, bar: 4 }, |
| 124 | + { foo: 3, bar: 5 }, |
| 125 | + ], |
| 126 | +}; |
| 127 | + |
| 128 | +``` |
| 129 | + |
0 commit comments