Compare commits
2 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
fc2c4f2f15 | ||
|
|
963970b7a2 |
@@ -20,10 +20,11 @@ import {inferReactiveScopeVariables} from '../ReactiveScopes';
|
||||
import {rewriteInstructionKindsBasedOnReassignment} from '../SSA';
|
||||
import {inferMutableRanges} from './InferMutableRanges';
|
||||
import inferReferenceEffects from './InferReferenceEffects';
|
||||
import {assertExhaustive} from '../Utils/utils';
|
||||
import {assertExhaustive, retainWhere} from '../Utils/utils';
|
||||
import {inferMutationAliasingEffects} from './InferMutationAliasingEffects';
|
||||
import {inferFunctionExpressionAliasingEffectsSignature} from './InferFunctionExpressionAliasingEffectsSignature';
|
||||
import {inferMutationAliasingRanges} from './InferMutationAliasingRanges';
|
||||
import {hashEffect} from './AliasingEffects';
|
||||
|
||||
export default function analyseFunctions(func: HIRFunction): void {
|
||||
for (const [_, block] of func.body.blocks) {
|
||||
@@ -81,6 +82,17 @@ function lowerWithMutationAliasing(fn: HIRFunction): void {
|
||||
fn.aliasingEffects ??= [];
|
||||
fn.aliasingEffects?.push(...effects);
|
||||
}
|
||||
if (fn.aliasingEffects != null) {
|
||||
const seen = new Set<string>();
|
||||
retainWhere(fn.aliasingEffects, effect => {
|
||||
const hash = hashEffect(effect);
|
||||
if (seen.has(hash)) {
|
||||
return false;
|
||||
}
|
||||
seen.add(hash);
|
||||
return true;
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Phase 2: populate the Effect of each context variable to use in inferring
|
||||
|
||||
@@ -362,6 +362,11 @@ function inferBlock(
|
||||
} else if (terminal.kind === 'maybe-throw') {
|
||||
const handlerParam = context.catchHandlers.get(terminal.handler);
|
||||
if (handlerParam != null) {
|
||||
CompilerError.invariant(state.kind(handlerParam) != null, {
|
||||
reason:
|
||||
'Expected catch binding to be intialized with a DeclareLocal Catch instruction',
|
||||
loc: terminal.loc,
|
||||
});
|
||||
const effects: Array<AliasingEffect> = [];
|
||||
for (const instr of block.instructions) {
|
||||
if (
|
||||
@@ -476,14 +481,14 @@ function applySignature(
|
||||
* Track which values we've already aliased once, so that we can switch to
|
||||
* appendAlias() for subsequent aliases into the same value
|
||||
*/
|
||||
const aliased = new Set<IdentifierId>();
|
||||
const initialized = new Set<IdentifierId>();
|
||||
|
||||
if (DEBUG) {
|
||||
console.log(printInstruction(instruction));
|
||||
}
|
||||
|
||||
for (const effect of signature.effects) {
|
||||
applyEffect(context, state, effect, aliased, effects);
|
||||
applyEffect(context, state, effect, initialized, effects);
|
||||
}
|
||||
if (DEBUG) {
|
||||
console.log(
|
||||
@@ -508,7 +513,7 @@ function applyEffect(
|
||||
context: Context,
|
||||
state: InferenceState,
|
||||
_effect: AliasingEffect,
|
||||
aliased: Set<IdentifierId>,
|
||||
initialized: Set<IdentifierId>,
|
||||
effects: Array<AliasingEffect>,
|
||||
): void {
|
||||
const effect = context.internEffect(_effect);
|
||||
@@ -524,6 +529,13 @@ function applyEffect(
|
||||
break;
|
||||
}
|
||||
case 'Create': {
|
||||
CompilerError.invariant(!initialized.has(effect.into.identifier.id), {
|
||||
reason: `Cannot re-initialize variable within an instruction`,
|
||||
description: `Re-initialized ${printPlace(effect.into)} in ${printAliasingEffect(effect)}`,
|
||||
loc: effect.into.loc,
|
||||
});
|
||||
initialized.add(effect.into.identifier.id);
|
||||
|
||||
let value = context.effectInstructionValueCache.get(effect);
|
||||
if (value == null) {
|
||||
value = {
|
||||
@@ -538,6 +550,7 @@ function applyEffect(
|
||||
reason: new Set([effect.reason]),
|
||||
});
|
||||
state.define(effect.into, value);
|
||||
effects.push(effect);
|
||||
break;
|
||||
}
|
||||
case 'ImmutableCapture': {
|
||||
@@ -555,6 +568,13 @@ function applyEffect(
|
||||
break;
|
||||
}
|
||||
case 'CreateFrom': {
|
||||
CompilerError.invariant(!initialized.has(effect.into.identifier.id), {
|
||||
reason: `Cannot re-initialize variable within an instruction`,
|
||||
description: `Re-initialized ${printPlace(effect.into)} in ${printAliasingEffect(effect)}`,
|
||||
loc: effect.into.loc,
|
||||
});
|
||||
initialized.add(effect.into.identifier.id);
|
||||
|
||||
const fromValue = state.kind(effect.from);
|
||||
let value = context.effectInstructionValueCache.get(effect);
|
||||
if (value == null) {
|
||||
@@ -573,10 +593,21 @@ function applyEffect(
|
||||
switch (fromValue.kind) {
|
||||
case ValueKind.Primitive:
|
||||
case ValueKind.Global: {
|
||||
// no need to track this data flow
|
||||
effects.push({
|
||||
kind: 'Create',
|
||||
value: fromValue.kind,
|
||||
into: effect.into,
|
||||
reason: [...fromValue.reason][0] ?? ValueReason.Other,
|
||||
});
|
||||
break;
|
||||
}
|
||||
case ValueKind.Frozen: {
|
||||
effects.push({
|
||||
kind: 'Create',
|
||||
value: fromValue.kind,
|
||||
into: effect.into,
|
||||
reason: [...fromValue.reason][0] ?? ValueReason.Other,
|
||||
});
|
||||
applyEffect(
|
||||
context,
|
||||
state,
|
||||
@@ -585,7 +616,7 @@ function applyEffect(
|
||||
from: effect.from,
|
||||
into: effect.into,
|
||||
},
|
||||
aliased,
|
||||
initialized,
|
||||
effects,
|
||||
);
|
||||
break;
|
||||
@@ -597,6 +628,13 @@ function applyEffect(
|
||||
break;
|
||||
}
|
||||
case 'CreateFunction': {
|
||||
CompilerError.invariant(!initialized.has(effect.into.identifier.id), {
|
||||
reason: `Cannot re-initialize variable within an instruction`,
|
||||
description: `Re-initialized ${printPlace(effect.into)} in ${printAliasingEffect(effect)}`,
|
||||
loc: effect.into.loc,
|
||||
});
|
||||
initialized.add(effect.into.identifier.id);
|
||||
|
||||
effects.push(effect);
|
||||
/**
|
||||
* We consider the function mutable if it has any mutable context variables or
|
||||
@@ -653,7 +691,7 @@ function applyEffect(
|
||||
from: capture,
|
||||
into: effect.into,
|
||||
},
|
||||
aliased,
|
||||
initialized,
|
||||
effects,
|
||||
);
|
||||
}
|
||||
@@ -661,6 +699,14 @@ function applyEffect(
|
||||
}
|
||||
case 'Alias':
|
||||
case 'Capture': {
|
||||
CompilerError.invariant(
|
||||
effect.kind === 'Capture' || initialized.has(effect.into.identifier.id),
|
||||
{
|
||||
reason: `Expected destination value to already be initialized within this instruction for Alias effect`,
|
||||
description: `Destination ${printPlace(effect.into)} is not initialized in this instruction`,
|
||||
loc: effect.into.loc,
|
||||
},
|
||||
);
|
||||
/*
|
||||
* Capture describes potential information flow: storing a pointer to one value
|
||||
* within another. If the destination is not mutable, or the source value has
|
||||
@@ -698,7 +744,7 @@ function applyEffect(
|
||||
from: effect.from,
|
||||
into: effect.into,
|
||||
},
|
||||
aliased,
|
||||
initialized,
|
||||
effects,
|
||||
);
|
||||
break;
|
||||
@@ -714,6 +760,13 @@ function applyEffect(
|
||||
break;
|
||||
}
|
||||
case 'Assign': {
|
||||
CompilerError.invariant(!initialized.has(effect.into.identifier.id), {
|
||||
reason: `Cannot re-initialize variable within an instruction`,
|
||||
description: `Re-initialized ${printPlace(effect.into)} in ${printAliasingEffect(effect)}`,
|
||||
loc: effect.into.loc,
|
||||
});
|
||||
initialized.add(effect.into.identifier.id);
|
||||
|
||||
/*
|
||||
* Alias represents potential pointer aliasing. If the type is a global,
|
||||
* a primitive (copy-on-write semantics) then we can prune the effect
|
||||
@@ -730,7 +783,7 @@ function applyEffect(
|
||||
from: effect.from,
|
||||
into: effect.into,
|
||||
},
|
||||
aliased,
|
||||
initialized,
|
||||
effects,
|
||||
);
|
||||
let value = context.effectInstructionValueCache.get(effect);
|
||||
@@ -768,12 +821,7 @@ function applyEffect(
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
if (aliased.has(effect.into.identifier.id)) {
|
||||
state.appendAlias(effect.into, effect.from);
|
||||
} else {
|
||||
aliased.add(effect.into.identifier.id);
|
||||
state.alias(effect.into, effect.from);
|
||||
}
|
||||
state.assign(effect.into, effect.from);
|
||||
effects.push(effect);
|
||||
break;
|
||||
}
|
||||
@@ -826,11 +874,11 @@ function applyEffect(
|
||||
context,
|
||||
state,
|
||||
{kind: 'MutateTransitiveConditionally', value: effect.function},
|
||||
aliased,
|
||||
initialized,
|
||||
effects,
|
||||
);
|
||||
for (const signatureEffect of signatureEffects) {
|
||||
applyEffect(context, state, signatureEffect, aliased, effects);
|
||||
applyEffect(context, state, signatureEffect, initialized, effects);
|
||||
}
|
||||
break;
|
||||
}
|
||||
@@ -858,7 +906,7 @@ function applyEffect(
|
||||
console.log('apply aliasing signature effects');
|
||||
}
|
||||
for (const signatureEffect of signatureEffects) {
|
||||
applyEffect(context, state, signatureEffect, aliased, effects);
|
||||
applyEffect(context, state, signatureEffect, initialized, effects);
|
||||
}
|
||||
} else if (effect.signature != null) {
|
||||
if (DEBUG) {
|
||||
@@ -873,7 +921,7 @@ function applyEffect(
|
||||
effect.loc,
|
||||
);
|
||||
for (const legacyEffect of legacyEffects) {
|
||||
applyEffect(context, state, legacyEffect, aliased, effects);
|
||||
applyEffect(context, state, legacyEffect, initialized, effects);
|
||||
}
|
||||
} else {
|
||||
if (DEBUG) {
|
||||
@@ -888,7 +936,7 @@ function applyEffect(
|
||||
value: ValueKind.Mutable,
|
||||
reason: ValueReason.Other,
|
||||
},
|
||||
aliased,
|
||||
initialized,
|
||||
effects,
|
||||
);
|
||||
/*
|
||||
@@ -911,21 +959,21 @@ function applyEffect(
|
||||
kind: 'MutateTransitiveConditionally',
|
||||
value: operand,
|
||||
},
|
||||
aliased,
|
||||
initialized,
|
||||
effects,
|
||||
);
|
||||
}
|
||||
const mutateIterator =
|
||||
arg.kind === 'Spread' ? conditionallyMutateIterator(operand) : null;
|
||||
if (mutateIterator) {
|
||||
applyEffect(context, state, mutateIterator, aliased, effects);
|
||||
applyEffect(context, state, mutateIterator, initialized, effects);
|
||||
}
|
||||
applyEffect(
|
||||
context,
|
||||
state,
|
||||
// OK: recording information flow
|
||||
{kind: 'Alias', from: operand, into: effect.into},
|
||||
aliased,
|
||||
initialized,
|
||||
effects,
|
||||
);
|
||||
for (const otherArg of [
|
||||
@@ -953,7 +1001,7 @@ function applyEffect(
|
||||
from: operand,
|
||||
into: other,
|
||||
},
|
||||
aliased,
|
||||
initialized,
|
||||
effects,
|
||||
);
|
||||
}
|
||||
@@ -1009,7 +1057,7 @@ function applyEffect(
|
||||
suggestions: null,
|
||||
},
|
||||
},
|
||||
aliased,
|
||||
initialized,
|
||||
effects,
|
||||
);
|
||||
}
|
||||
@@ -1028,7 +1076,7 @@ function applyEffect(
|
||||
suggestions: null,
|
||||
},
|
||||
},
|
||||
aliased,
|
||||
initialized,
|
||||
effects,
|
||||
);
|
||||
} else {
|
||||
@@ -1059,7 +1107,7 @@ function applyEffect(
|
||||
suggestions: null,
|
||||
},
|
||||
},
|
||||
aliased,
|
||||
initialized,
|
||||
effects,
|
||||
);
|
||||
}
|
||||
@@ -1166,7 +1214,7 @@ class InferenceState {
|
||||
}
|
||||
|
||||
// Updates the value at @param place to point to the same value as @param value.
|
||||
alias(place: Place, value: Place): void {
|
||||
assign(place: Place, value: Place): void {
|
||||
const values = this.#variables.get(value.identifier.id);
|
||||
CompilerError.invariant(values != null, {
|
||||
reason: `[InferMutationAliasingEffects] Expected value for identifier to be initialized`,
|
||||
|
||||
@@ -23,14 +23,9 @@ function Component({a, b, c}: {a: number; b: number; c: number}) {
|
||||
|
||||
return (
|
||||
<>
|
||||
<ValidateMemoization inputs={[a, b, c]} output={x} alwaysCheck={true} />;
|
||||
<ValidateMemoization inputs={[a, b, c]} output={x} />;
|
||||
{/* TODO: should only depend on c */}
|
||||
<ValidateMemoization
|
||||
inputs={[a, b, c]}
|
||||
output={x[0]}
|
||||
alwaysCheck={true}
|
||||
/>
|
||||
;
|
||||
<ValidateMemoization inputs={[a, b, c]} output={x[0]} />;
|
||||
</>
|
||||
);
|
||||
}
|
||||
@@ -98,7 +93,7 @@ function Component(t0) {
|
||||
}
|
||||
let t3;
|
||||
if ($[9] !== t2 || $[10] !== x) {
|
||||
t3 = <ValidateMemoization inputs={t2} output={x} alwaysCheck={true} />;
|
||||
t3 = <ValidateMemoization inputs={t2} output={x} />;
|
||||
$[9] = t2;
|
||||
$[10] = x;
|
||||
$[11] = t3;
|
||||
@@ -117,7 +112,7 @@ function Component(t0) {
|
||||
}
|
||||
let t5;
|
||||
if ($[16] !== t4 || $[17] !== x[0]) {
|
||||
t5 = <ValidateMemoization inputs={t4} output={x[0]} alwaysCheck={true} />;
|
||||
t5 = <ValidateMemoization inputs={t4} output={x[0]} />;
|
||||
$[16] = t4;
|
||||
$[17] = x[0];
|
||||
$[18] = t5;
|
||||
|
||||
@@ -19,14 +19,9 @@ function Component({a, b, c}: {a: number; b: number; c: number}) {
|
||||
|
||||
return (
|
||||
<>
|
||||
<ValidateMemoization inputs={[a, b, c]} output={x} alwaysCheck={true} />;
|
||||
<ValidateMemoization inputs={[a, b, c]} output={x} />;
|
||||
{/* TODO: should only depend on c */}
|
||||
<ValidateMemoization
|
||||
inputs={[a, b, c]}
|
||||
output={x[0]}
|
||||
alwaysCheck={true}
|
||||
/>
|
||||
;
|
||||
<ValidateMemoization inputs={[a, b, c]} output={x[0]} />;
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -22,7 +22,7 @@ function Component({a, b}) {
|
||||
typedMutate(z, b);
|
||||
|
||||
// TODO: this *should* only depend on `a`
|
||||
return <ValidateMemoization inputs={[a, b]} output={x} alwaysCheck={true} />;
|
||||
return <ValidateMemoization inputs={[a, b]} output={x} />;
|
||||
}
|
||||
|
||||
export const FIXTURE_ENTRYPOINT = {
|
||||
@@ -86,7 +86,7 @@ function Component(t0) {
|
||||
}
|
||||
let t3;
|
||||
if ($[7] !== t2 || $[8] !== x) {
|
||||
t3 = <ValidateMemoization inputs={t2} output={x} alwaysCheck={true} />;
|
||||
t3 = <ValidateMemoization inputs={t2} output={x} />;
|
||||
$[7] = t2;
|
||||
$[8] = x;
|
||||
$[9] = t3;
|
||||
|
||||
@@ -18,7 +18,7 @@ function Component({a, b}) {
|
||||
typedMutate(z, b);
|
||||
|
||||
// TODO: this *should* only depend on `a`
|
||||
return <ValidateMemoization inputs={[a, b]} output={x} alwaysCheck={true} />;
|
||||
return <ValidateMemoization inputs={[a, b]} output={x} />;
|
||||
}
|
||||
|
||||
export const FIXTURE_ENTRYPOINT = {
|
||||
|
||||
@@ -20,8 +20,8 @@ function Component({a, b}) {
|
||||
|
||||
return (
|
||||
<>
|
||||
<ValidateMemoization inputs={[a]} output={o} alwaysCheck={true} />;
|
||||
<ValidateMemoization inputs={[a, b]} output={x} alwaysCheck={true} />;
|
||||
<ValidateMemoization inputs={[a]} output={o} />;
|
||||
<ValidateMemoization inputs={[a, b]} output={x} />;
|
||||
</>
|
||||
);
|
||||
}
|
||||
@@ -92,7 +92,7 @@ function Component(t0) {
|
||||
}
|
||||
let t5;
|
||||
if ($[8] !== o || $[9] !== t4) {
|
||||
t5 = <ValidateMemoization inputs={t4} output={o} alwaysCheck={true} />;
|
||||
t5 = <ValidateMemoization inputs={t4} output={o} />;
|
||||
$[8] = o;
|
||||
$[9] = t4;
|
||||
$[10] = t5;
|
||||
@@ -110,7 +110,7 @@ function Component(t0) {
|
||||
}
|
||||
let t7;
|
||||
if ($[14] !== t6 || $[15] !== x) {
|
||||
t7 = <ValidateMemoization inputs={t6} output={x} alwaysCheck={true} />;
|
||||
t7 = <ValidateMemoization inputs={t6} output={x} />;
|
||||
$[14] = t6;
|
||||
$[15] = x;
|
||||
$[16] = t7;
|
||||
|
||||
@@ -16,8 +16,8 @@ function Component({a, b}) {
|
||||
|
||||
return (
|
||||
<>
|
||||
<ValidateMemoization inputs={[a]} output={o} alwaysCheck={true} />;
|
||||
<ValidateMemoization inputs={[a, b]} output={x} alwaysCheck={true} />;
|
||||
<ValidateMemoization inputs={[a]} output={o} />;
|
||||
<ValidateMemoization inputs={[a, b]} output={x} />;
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -21,7 +21,7 @@ function Component({a, b}: {a: number; b: number}) {
|
||||
// mutates x
|
||||
typedMutate(z, b);
|
||||
|
||||
return <ValidateMemoization inputs={[a, b]} output={x} alwaysCheck={true} />;
|
||||
return <ValidateMemoization inputs={[a, b]} output={x} />;
|
||||
}
|
||||
|
||||
export const FIXTURE_ENTRYPOINT = {
|
||||
@@ -85,7 +85,7 @@ function Component(t0) {
|
||||
}
|
||||
let t3;
|
||||
if ($[7] !== t2 || $[8] !== x) {
|
||||
t3 = <ValidateMemoization inputs={t2} output={x} alwaysCheck={true} />;
|
||||
t3 = <ValidateMemoization inputs={t2} output={x} />;
|
||||
$[7] = t2;
|
||||
$[8] = x;
|
||||
$[9] = t3;
|
||||
|
||||
@@ -17,7 +17,7 @@ function Component({a, b}: {a: number; b: number}) {
|
||||
// mutates x
|
||||
typedMutate(z, b);
|
||||
|
||||
return <ValidateMemoization inputs={[a, b]} output={x} alwaysCheck={true} />;
|
||||
return <ValidateMemoization inputs={[a, b]} output={x} />;
|
||||
}
|
||||
|
||||
export const FIXTURE_ENTRYPOINT = {
|
||||
|
||||
@@ -17,7 +17,7 @@ function Component({a, b}: {a: number; b: number}) {
|
||||
// mutates x
|
||||
typedMutate(z, b);
|
||||
|
||||
return <ValidateMemoization inputs={[a, b]} output={x} alwaysCheck={true} />;
|
||||
return <ValidateMemoization inputs={[a, b]} output={x} />;
|
||||
}
|
||||
|
||||
export const FIXTURE_ENTRYPOINT = {
|
||||
@@ -76,7 +76,7 @@ function Component(t0) {
|
||||
}
|
||||
let t3;
|
||||
if ($[7] !== t2 || $[8] !== x) {
|
||||
t3 = <ValidateMemoization inputs={t2} output={x} alwaysCheck={true} />;
|
||||
t3 = <ValidateMemoization inputs={t2} output={x} />;
|
||||
$[7] = t2;
|
||||
$[8] = x;
|
||||
$[9] = t3;
|
||||
|
||||
@@ -13,7 +13,7 @@ function Component({a, b}: {a: number; b: number}) {
|
||||
// mutates x
|
||||
typedMutate(z, b);
|
||||
|
||||
return <ValidateMemoization inputs={[a, b]} output={x} alwaysCheck={true} />;
|
||||
return <ValidateMemoization inputs={[a, b]} output={x} />;
|
||||
}
|
||||
|
||||
export const FIXTURE_ENTRYPOINT = {
|
||||
|
||||
@@ -17,7 +17,7 @@ function Component({a, b}) {
|
||||
// does not mutate x, so x should not depend on b
|
||||
typedMutate(z, b);
|
||||
|
||||
return <ValidateMemoization inputs={[a]} output={x} alwaysCheck={true} />;
|
||||
return <ValidateMemoization inputs={[a]} output={x} />;
|
||||
}
|
||||
|
||||
export const FIXTURE_ENTRYPOINT = {
|
||||
@@ -73,7 +73,7 @@ function Component(t0) {
|
||||
}
|
||||
let t4;
|
||||
if ($[4] !== t3 || $[5] !== x) {
|
||||
t4 = <ValidateMemoization inputs={t3} output={x} alwaysCheck={true} />;
|
||||
t4 = <ValidateMemoization inputs={t3} output={x} />;
|
||||
$[4] = t3;
|
||||
$[5] = x;
|
||||
$[6] = t4;
|
||||
|
||||
@@ -13,7 +13,7 @@ function Component({a, b}) {
|
||||
// does not mutate x, so x should not depend on b
|
||||
typedMutate(z, b);
|
||||
|
||||
return <ValidateMemoization inputs={[a]} output={x} alwaysCheck={true} />;
|
||||
return <ValidateMemoization inputs={[a]} output={x} />;
|
||||
}
|
||||
|
||||
export const FIXTURE_ENTRYPOINT = {
|
||||
|
||||
@@ -21,7 +21,7 @@ function Component({a, b}) {
|
||||
// could mutate x
|
||||
typedMutate(z, b);
|
||||
|
||||
return <ValidateMemoization inputs={[a, b]} output={x} alwaysCheck={true} />;
|
||||
return <ValidateMemoization inputs={[a, b]} output={x} />;
|
||||
}
|
||||
|
||||
export const FIXTURE_ENTRYPOINT = {
|
||||
@@ -92,7 +92,7 @@ function Component(t0) {
|
||||
}
|
||||
let t4;
|
||||
if ($[9] !== t3 || $[10] !== x) {
|
||||
t4 = <ValidateMemoization inputs={t3} output={x} alwaysCheck={true} />;
|
||||
t4 = <ValidateMemoization inputs={t3} output={x} />;
|
||||
$[9] = t3;
|
||||
$[10] = x;
|
||||
$[11] = t4;
|
||||
|
||||
@@ -17,7 +17,7 @@ function Component({a, b}) {
|
||||
// could mutate x
|
||||
typedMutate(z, b);
|
||||
|
||||
return <ValidateMemoization inputs={[a, b]} output={x} alwaysCheck={true} />;
|
||||
return <ValidateMemoization inputs={[a, b]} output={x} />;
|
||||
}
|
||||
|
||||
export const FIXTURE_ENTRYPOINT = {
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
```javascript
|
||||
// @enableNewMutationAliasingModel
|
||||
|
||||
import {useMemo} from 'react';
|
||||
import {
|
||||
identity,
|
||||
makeObject_Primitives,
|
||||
@@ -14,7 +15,7 @@ import {
|
||||
|
||||
function Component({a, b}) {
|
||||
// create a mutable value with input `a`
|
||||
const x = makeObject_Primitives(a);
|
||||
const x = useMemo(() => makeObject_Primitives(a), [a]);
|
||||
|
||||
// freeze the value
|
||||
useIdentity(x);
|
||||
@@ -49,6 +50,7 @@ export const FIXTURE_ENTRYPOINT = {
|
||||
```javascript
|
||||
import { c as _c } from "react/compiler-runtime"; // @enableNewMutationAliasingModel
|
||||
|
||||
import { useMemo } from "react";
|
||||
import {
|
||||
identity,
|
||||
makeObject_Primitives,
|
||||
@@ -61,13 +63,15 @@ function Component(t0) {
|
||||
const $ = _c(7);
|
||||
const { a, b } = t0;
|
||||
let t1;
|
||||
let t2;
|
||||
if ($[0] !== a) {
|
||||
t1 = makeObject_Primitives(a);
|
||||
t2 = makeObject_Primitives(a);
|
||||
$[0] = a;
|
||||
$[1] = t1;
|
||||
$[1] = t2;
|
||||
} else {
|
||||
t1 = $[1];
|
||||
t2 = $[1];
|
||||
}
|
||||
t1 = t2;
|
||||
const x = t1;
|
||||
|
||||
useIdentity(x);
|
||||
@@ -75,24 +79,24 @@ function Component(t0) {
|
||||
const x2 = typedIdentity(x);
|
||||
|
||||
identity(x2, b);
|
||||
let t2;
|
||||
if ($[2] !== a) {
|
||||
t2 = [a];
|
||||
$[2] = a;
|
||||
$[3] = t2;
|
||||
} else {
|
||||
t2 = $[3];
|
||||
}
|
||||
let t3;
|
||||
if ($[4] !== t2 || $[5] !== x) {
|
||||
t3 = <ValidateMemoization inputs={t2} output={x} />;
|
||||
$[4] = t2;
|
||||
$[5] = x;
|
||||
$[6] = t3;
|
||||
if ($[2] !== a) {
|
||||
t3 = [a];
|
||||
$[2] = a;
|
||||
$[3] = t3;
|
||||
} else {
|
||||
t3 = $[6];
|
||||
t3 = $[3];
|
||||
}
|
||||
return t3;
|
||||
let t4;
|
||||
if ($[4] !== t3 || $[5] !== x) {
|
||||
t4 = <ValidateMemoization inputs={t3} output={x} />;
|
||||
$[4] = t3;
|
||||
$[5] = x;
|
||||
$[6] = t4;
|
||||
} else {
|
||||
t4 = $[6];
|
||||
}
|
||||
return t4;
|
||||
}
|
||||
|
||||
export const FIXTURE_ENTRYPOINT = {
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
// @enableNewMutationAliasingModel
|
||||
|
||||
import {useMemo} from 'react';
|
||||
import {
|
||||
identity,
|
||||
makeObject_Primitives,
|
||||
@@ -10,7 +11,7 @@ import {
|
||||
|
||||
function Component({a, b}) {
|
||||
// create a mutable value with input `a`
|
||||
const x = makeObject_Primitives(a);
|
||||
const x = useMemo(() => makeObject_Primitives(a), [a]);
|
||||
|
||||
// freeze the value
|
||||
useIdentity(x);
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
## Input
|
||||
|
||||
```javascript
|
||||
import {useMemo} from 'react';
|
||||
import {ValidateMemoization} from 'shared-runtime';
|
||||
|
||||
function Component({a, b, c}) {
|
||||
@@ -13,9 +14,21 @@ function Component({a, b, c}) {
|
||||
|
||||
return (
|
||||
<>
|
||||
<ValidateMemoization inputs={[a, c]} output={map} />
|
||||
<ValidateMemoization inputs={[a, c]} output={mapAlias} />
|
||||
<ValidateMemoization inputs={[b]} output={[hasB]} />
|
||||
<ValidateMemoization
|
||||
inputs={[a, c]}
|
||||
output={map}
|
||||
onlyCheckCompiled={true}
|
||||
/>
|
||||
<ValidateMemoization
|
||||
inputs={[a, c]}
|
||||
output={mapAlias}
|
||||
onlyCheckCompiled={true}
|
||||
/>
|
||||
<ValidateMemoization
|
||||
inputs={[b]}
|
||||
output={[hasB]}
|
||||
onlyCheckCompiled={true}
|
||||
/>
|
||||
</>
|
||||
);
|
||||
}
|
||||
@@ -44,6 +57,7 @@ export const FIXTURE_ENTRYPOINT = {
|
||||
|
||||
```javascript
|
||||
import { c as _c } from "react/compiler-runtime";
|
||||
import { useMemo } from "react";
|
||||
import { ValidateMemoization } from "shared-runtime";
|
||||
|
||||
function Component(t0) {
|
||||
@@ -76,7 +90,9 @@ function Component(t0) {
|
||||
}
|
||||
let t2;
|
||||
if ($[7] !== map || $[8] !== t1) {
|
||||
t2 = <ValidateMemoization inputs={t1} output={map} />;
|
||||
t2 = (
|
||||
<ValidateMemoization inputs={t1} output={map} onlyCheckCompiled={true} />
|
||||
);
|
||||
$[7] = map;
|
||||
$[8] = t1;
|
||||
$[9] = t2;
|
||||
@@ -94,7 +110,13 @@ function Component(t0) {
|
||||
}
|
||||
let t4;
|
||||
if ($[13] !== mapAlias || $[14] !== t3) {
|
||||
t4 = <ValidateMemoization inputs={t3} output={mapAlias} />;
|
||||
t4 = (
|
||||
<ValidateMemoization
|
||||
inputs={t3}
|
||||
output={mapAlias}
|
||||
onlyCheckCompiled={true}
|
||||
/>
|
||||
);
|
||||
$[13] = mapAlias;
|
||||
$[14] = t3;
|
||||
$[15] = t4;
|
||||
@@ -119,7 +141,9 @@ function Component(t0) {
|
||||
}
|
||||
let t7;
|
||||
if ($[20] !== t5 || $[21] !== t6) {
|
||||
t7 = <ValidateMemoization inputs={t5} output={t6} />;
|
||||
t7 = (
|
||||
<ValidateMemoization inputs={t5} output={t6} onlyCheckCompiled={true} />
|
||||
);
|
||||
$[20] = t5;
|
||||
$[21] = t6;
|
||||
$[22] = t7;
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import {useMemo} from 'react';
|
||||
import {ValidateMemoization} from 'shared-runtime';
|
||||
|
||||
function Component({a, b, c}) {
|
||||
@@ -9,9 +10,21 @@ function Component({a, b, c}) {
|
||||
|
||||
return (
|
||||
<>
|
||||
<ValidateMemoization inputs={[a, c]} output={map} />
|
||||
<ValidateMemoization inputs={[a, c]} output={mapAlias} />
|
||||
<ValidateMemoization inputs={[b]} output={[hasB]} />
|
||||
<ValidateMemoization
|
||||
inputs={[a, c]}
|
||||
output={map}
|
||||
onlyCheckCompiled={true}
|
||||
/>
|
||||
<ValidateMemoization
|
||||
inputs={[a, c]}
|
||||
output={mapAlias}
|
||||
onlyCheckCompiled={true}
|
||||
/>
|
||||
<ValidateMemoization
|
||||
inputs={[b]}
|
||||
output={[hasB]}
|
||||
onlyCheckCompiled={true}
|
||||
/>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
## Input
|
||||
|
||||
```javascript
|
||||
import {useMemo} from 'react';
|
||||
import {ValidateMemoization} from 'shared-runtime';
|
||||
|
||||
function Component({a, b, c}) {
|
||||
@@ -13,9 +14,21 @@ function Component({a, b, c}) {
|
||||
|
||||
return (
|
||||
<>
|
||||
<ValidateMemoization inputs={[a, c]} output={set} />
|
||||
<ValidateMemoization inputs={[a, c]} output={setAlias} />
|
||||
<ValidateMemoization inputs={[b]} output={[hasB]} />
|
||||
<ValidateMemoization
|
||||
inputs={[a, c]}
|
||||
output={set}
|
||||
onlyCheckCompiled={true}
|
||||
/>
|
||||
<ValidateMemoization
|
||||
inputs={[a, c]}
|
||||
output={setAlias}
|
||||
onlyCheckCompiled={true}
|
||||
/>
|
||||
<ValidateMemoization
|
||||
inputs={[b]}
|
||||
output={[hasB]}
|
||||
onlyCheckCompiled={true}
|
||||
/>
|
||||
</>
|
||||
);
|
||||
}
|
||||
@@ -44,6 +57,7 @@ export const FIXTURE_ENTRYPOINT = {
|
||||
|
||||
```javascript
|
||||
import { c as _c } from "react/compiler-runtime";
|
||||
import { useMemo } from "react";
|
||||
import { ValidateMemoization } from "shared-runtime";
|
||||
|
||||
function Component(t0) {
|
||||
@@ -76,7 +90,9 @@ function Component(t0) {
|
||||
}
|
||||
let t2;
|
||||
if ($[7] !== set || $[8] !== t1) {
|
||||
t2 = <ValidateMemoization inputs={t1} output={set} />;
|
||||
t2 = (
|
||||
<ValidateMemoization inputs={t1} output={set} onlyCheckCompiled={true} />
|
||||
);
|
||||
$[7] = set;
|
||||
$[8] = t1;
|
||||
$[9] = t2;
|
||||
@@ -94,7 +110,13 @@ function Component(t0) {
|
||||
}
|
||||
let t4;
|
||||
if ($[13] !== setAlias || $[14] !== t3) {
|
||||
t4 = <ValidateMemoization inputs={t3} output={setAlias} />;
|
||||
t4 = (
|
||||
<ValidateMemoization
|
||||
inputs={t3}
|
||||
output={setAlias}
|
||||
onlyCheckCompiled={true}
|
||||
/>
|
||||
);
|
||||
$[13] = setAlias;
|
||||
$[14] = t3;
|
||||
$[15] = t4;
|
||||
@@ -119,7 +141,9 @@ function Component(t0) {
|
||||
}
|
||||
let t7;
|
||||
if ($[20] !== t5 || $[21] !== t6) {
|
||||
t7 = <ValidateMemoization inputs={t5} output={t6} />;
|
||||
t7 = (
|
||||
<ValidateMemoization inputs={t5} output={t6} onlyCheckCompiled={true} />
|
||||
);
|
||||
$[20] = t5;
|
||||
$[21] = t6;
|
||||
$[22] = t7;
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import {useMemo} from 'react';
|
||||
import {ValidateMemoization} from 'shared-runtime';
|
||||
|
||||
function Component({a, b, c}) {
|
||||
@@ -9,9 +10,21 @@ function Component({a, b, c}) {
|
||||
|
||||
return (
|
||||
<>
|
||||
<ValidateMemoization inputs={[a, c]} output={set} />
|
||||
<ValidateMemoization inputs={[a, c]} output={setAlias} />
|
||||
<ValidateMemoization inputs={[b]} output={[hasB]} />
|
||||
<ValidateMemoization
|
||||
inputs={[a, c]}
|
||||
output={set}
|
||||
onlyCheckCompiled={true}
|
||||
/>
|
||||
<ValidateMemoization
|
||||
inputs={[a, c]}
|
||||
output={setAlias}
|
||||
onlyCheckCompiled={true}
|
||||
/>
|
||||
<ValidateMemoization
|
||||
inputs={[b]}
|
||||
output={[hasB]}
|
||||
onlyCheckCompiled={true}
|
||||
/>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -269,12 +269,10 @@ export function ValidateMemoization({
|
||||
inputs,
|
||||
output: rawOutput,
|
||||
onlyCheckCompiled = false,
|
||||
alwaysCheck = false,
|
||||
}: {
|
||||
inputs: Array<any>;
|
||||
output: any;
|
||||
onlyCheckCompiled?: boolean;
|
||||
alwaysCheck?: boolean;
|
||||
}): React.ReactElement {
|
||||
'use no forget';
|
||||
// Wrap rawOutput as it might be a function, which useState would invoke.
|
||||
@@ -282,7 +280,7 @@ export function ValidateMemoization({
|
||||
const [previousInputs, setPreviousInputs] = React.useState(inputs);
|
||||
const [previousOutput, setPreviousOutput] = React.useState(output);
|
||||
if (
|
||||
alwaysCheck ||
|
||||
!onlyCheckCompiled ||
|
||||
(onlyCheckCompiled &&
|
||||
(globalThis as any).__SNAP_EVALUATOR_MODE === 'forget')
|
||||
) {
|
||||
|
||||
Reference in New Issue
Block a user