Compare commits
3 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
9df57882bb | ||
|
|
d58c07b563 | ||
|
|
631b1cfc74 |
@@ -72,7 +72,7 @@ export function lower(
|
||||
env: Environment,
|
||||
// Bindings captured from the outer function, in case lower() is called recursively (for lambdas)
|
||||
bindings: Bindings | null = null,
|
||||
capturedRefs: Map<t.Identifier, SourceLocation> = new Map(),
|
||||
capturedRefs: Array<t.Identifier> = [],
|
||||
): Result<HIRFunction, CompilerError> {
|
||||
const builder = new HIRBuilder(env, {
|
||||
bindings,
|
||||
@@ -80,13 +80,13 @@ export function lower(
|
||||
});
|
||||
const context: HIRFunction['context'] = [];
|
||||
|
||||
for (const [ref, loc] of capturedRefs ?? []) {
|
||||
for (const ref of capturedRefs ?? []) {
|
||||
context.push({
|
||||
kind: 'Identifier',
|
||||
identifier: builder.resolveBinding(ref),
|
||||
effect: Effect.Unknown,
|
||||
reactive: false,
|
||||
loc,
|
||||
loc: ref.loc ?? GeneratedSource,
|
||||
});
|
||||
}
|
||||
|
||||
@@ -3439,12 +3439,10 @@ function lowerFunction(
|
||||
* This isn't a problem in practice because use Babel's scope analysis to
|
||||
* identify the correct references.
|
||||
*/
|
||||
const lowering = lower(
|
||||
expr,
|
||||
builder.environment,
|
||||
builder.bindings,
|
||||
new Map([...builder.context, ...capturedContext]),
|
||||
);
|
||||
const lowering = lower(expr, builder.environment, builder.bindings, [
|
||||
...builder.context,
|
||||
...capturedContext,
|
||||
]);
|
||||
let loweredFunc: HIRFunction;
|
||||
if (lowering.isErr()) {
|
||||
lowering
|
||||
@@ -4162,11 +4160,6 @@ function captureScopes({from, to}: {from: Scope; to: Scope}): Set<Scope> {
|
||||
return scopes;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a mapping of "context" identifiers — references to free variables that
|
||||
* will become part of the function expression's `context` array — along with the
|
||||
* source location of their first reference within the function.
|
||||
*/
|
||||
function gatherCapturedContext(
|
||||
fn: NodePath<
|
||||
| t.FunctionExpression
|
||||
@@ -4175,8 +4168,8 @@ function gatherCapturedContext(
|
||||
| t.ObjectMethod
|
||||
>,
|
||||
componentScope: Scope,
|
||||
): Map<t.Identifier, SourceLocation> {
|
||||
const capturedIds = new Map<t.Identifier, SourceLocation>();
|
||||
): Array<t.Identifier> {
|
||||
const capturedIds = new Set<t.Identifier>();
|
||||
|
||||
/*
|
||||
* Capture all the scopes from the parent of this function up to and including
|
||||
@@ -4219,15 +4212,8 @@ function gatherCapturedContext(
|
||||
|
||||
// Add the base identifier binding as a dependency.
|
||||
const binding = baseIdentifier.scope.getBinding(baseIdentifier.node.name);
|
||||
if (
|
||||
binding !== undefined &&
|
||||
pureScopes.has(binding.scope) &&
|
||||
!capturedIds.has(binding.identifier)
|
||||
) {
|
||||
capturedIds.set(
|
||||
binding.identifier,
|
||||
path.node.loc ?? binding.identifier.loc ?? GeneratedSource,
|
||||
);
|
||||
if (binding !== undefined && pureScopes.has(binding.scope)) {
|
||||
capturedIds.add(binding.identifier);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4264,7 +4250,7 @@ function gatherCapturedContext(
|
||||
},
|
||||
});
|
||||
|
||||
return capturedIds;
|
||||
return [...capturedIds.keys()];
|
||||
}
|
||||
|
||||
function notNull<T>(value: T | null): value is T {
|
||||
|
||||
@@ -246,7 +246,7 @@ export const EnvironmentConfigSchema = z.object({
|
||||
/**
|
||||
* Enable a new model for mutability and aliasing inference
|
||||
*/
|
||||
enableNewMutationAliasingModel: z.boolean().default(true),
|
||||
enableNewMutationAliasingModel: z.boolean().default(false),
|
||||
|
||||
/**
|
||||
* Enables inference of optional dependency chains. Without this flag
|
||||
|
||||
@@ -1388,16 +1388,6 @@ export enum ValueReason {
|
||||
*/
|
||||
JsxCaptured = 'jsx-captured',
|
||||
|
||||
/**
|
||||
* Argument to a hook
|
||||
*/
|
||||
HookCaptured = 'hook-captured',
|
||||
|
||||
/**
|
||||
* Return value of a hook
|
||||
*/
|
||||
HookReturn = 'hook-return',
|
||||
|
||||
/**
|
||||
* Passed to an effect
|
||||
*/
|
||||
|
||||
@@ -106,7 +106,7 @@ export default class HIRBuilder {
|
||||
#current: WipBlock;
|
||||
#entry: BlockId;
|
||||
#scopes: Array<Scope> = [];
|
||||
#context: Map<t.Identifier, SourceLocation>;
|
||||
#context: Array<t.Identifier>;
|
||||
#bindings: Bindings;
|
||||
#env: Environment;
|
||||
#exceptionHandlerStack: Array<BlockId> = [];
|
||||
@@ -121,7 +121,7 @@ export default class HIRBuilder {
|
||||
return this.#env.nextIdentifierId;
|
||||
}
|
||||
|
||||
get context(): Map<t.Identifier, SourceLocation> {
|
||||
get context(): Array<t.Identifier> {
|
||||
return this.#context;
|
||||
}
|
||||
|
||||
@@ -137,13 +137,13 @@ export default class HIRBuilder {
|
||||
env: Environment,
|
||||
options?: {
|
||||
bindings?: Bindings | null;
|
||||
context?: Map<t.Identifier, SourceLocation>;
|
||||
context?: Array<t.Identifier>;
|
||||
entryBlockKind?: BlockKind;
|
||||
},
|
||||
) {
|
||||
this.#env = env;
|
||||
this.#bindings = options?.bindings ?? new Map();
|
||||
this.#context = options?.context ?? new Map();
|
||||
this.#context = options?.context ?? [];
|
||||
this.#entry = makeBlockId(env.nextBlockId);
|
||||
this.#current = newBlock(this.#entry, options?.entryBlockKind ?? 'block');
|
||||
}
|
||||
|
||||
@@ -1302,34 +1302,6 @@ export const DefaultNonmutatingHook = addHook(
|
||||
calleeEffect: Effect.Read,
|
||||
hookKind: 'Custom',
|
||||
returnValueKind: ValueKind.Frozen,
|
||||
aliasing: {
|
||||
receiver: makeIdentifierId(0),
|
||||
params: [],
|
||||
rest: makeIdentifierId(1),
|
||||
returns: makeIdentifierId(2),
|
||||
temporaries: [],
|
||||
effects: [
|
||||
// Freeze the arguments
|
||||
{
|
||||
kind: 'Freeze',
|
||||
value: signatureArgument(1),
|
||||
reason: ValueReason.HookCaptured,
|
||||
},
|
||||
// Returns a frozen value
|
||||
{
|
||||
kind: 'Create',
|
||||
into: signatureArgument(2),
|
||||
value: ValueKind.Frozen,
|
||||
reason: ValueReason.HookReturn,
|
||||
},
|
||||
// May alias any arguments into the return
|
||||
{
|
||||
kind: 'Alias',
|
||||
from: signatureArgument(1),
|
||||
into: signatureArgument(2),
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
'DefaultNonmutatingHook',
|
||||
);
|
||||
|
||||
@@ -8,7 +8,6 @@
|
||||
import {CompilerErrorDetailOptions} from '../CompilerError';
|
||||
import {
|
||||
FunctionExpression,
|
||||
GeneratedSource,
|
||||
Hole,
|
||||
IdentifierId,
|
||||
ObjectMethod,
|
||||
@@ -19,7 +18,6 @@ import {
|
||||
ValueReason,
|
||||
} from '../HIR';
|
||||
import {FunctionSignature} from '../HIR/ObjectShape';
|
||||
import {printSourceLocation} from '../HIR/PrintHIR';
|
||||
|
||||
/**
|
||||
* `AliasingEffect` describes a set of "effects" that an instruction/terminal has on one or
|
||||
@@ -202,19 +200,10 @@ export function hashEffect(effect: AliasingEffect): string {
|
||||
return [effect.kind, effect.value.identifier.id, effect.reason].join(':');
|
||||
}
|
||||
case 'Impure':
|
||||
case 'Render': {
|
||||
return [effect.kind, effect.place.identifier.id].join(':');
|
||||
}
|
||||
case 'Render':
|
||||
case 'MutateFrozen':
|
||||
case 'MutateGlobal': {
|
||||
return [
|
||||
effect.kind,
|
||||
effect.place.identifier.id,
|
||||
effect.error.severity,
|
||||
effect.error.reason,
|
||||
effect.error.description,
|
||||
printSourceLocation(effect.error.loc ?? GeneratedSource),
|
||||
].join(':');
|
||||
return [effect.kind, effect.place.identifier.id].join(':');
|
||||
}
|
||||
case 'Mutate':
|
||||
case 'MutateConditionally':
|
||||
|
||||
@@ -42,16 +42,8 @@ export default function analyseFunctions(func: HIRFunction): void {
|
||||
* Reset mutable range for outer inferReferenceEffects
|
||||
*/
|
||||
for (const operand of instr.value.loweredFunc.func.context) {
|
||||
/**
|
||||
* NOTE: inferReactiveScopeVariables makes identifiers in the scope
|
||||
* point to the *same* mutableRange instance. Resetting start/end
|
||||
* here is insufficient, because a later mutation of the range
|
||||
* for any one identifier could affect the range for other identifiers.
|
||||
*/
|
||||
operand.identifier.mutableRange = {
|
||||
start: makeInstructionId(0),
|
||||
end: makeInstructionId(0),
|
||||
};
|
||||
operand.identifier.mutableRange.start = makeInstructionId(0);
|
||||
operand.identifier.mutableRange.end = makeInstructionId(0);
|
||||
operand.identifier.scope = null;
|
||||
}
|
||||
break;
|
||||
|
||||
@@ -341,10 +341,6 @@ export function getWriteErrorReason(abstractValue: AbstractValue): string {
|
||||
return "Mutating a value returned from 'useReducer()', which should not be mutated. Use the dispatch function to update instead";
|
||||
} else if (abstractValue.reason.has(ValueReason.Effect)) {
|
||||
return 'Updating a value used previously in an effect function or as an effect dependency is not allowed. Consider moving the mutation before calling useEffect()';
|
||||
} else if (abstractValue.reason.has(ValueReason.HookCaptured)) {
|
||||
return 'Updating a value previously passed as an argument to a hook is not allowed. Consider moving the mutation before calling the hook';
|
||||
} else if (abstractValue.reason.has(ValueReason.HookReturn)) {
|
||||
return 'Updating a value returned from a hook is not allowed. Consider moving the mutation into the hook where the value is constructed';
|
||||
} else {
|
||||
return 'This mutates a variable that React considers immutable';
|
||||
}
|
||||
|
||||
@@ -38,7 +38,6 @@ import {
|
||||
import {
|
||||
eachInstructionValueLValue,
|
||||
eachInstructionValueOperand,
|
||||
eachTerminalOperand,
|
||||
eachTerminalSuccessor,
|
||||
} from '../HIR/visitors';
|
||||
import {Ok, Result} from '../Utils/Result';
|
||||
@@ -50,14 +49,12 @@ import {
|
||||
} from './InferReferenceEffects';
|
||||
import {
|
||||
assertExhaustive,
|
||||
getOrInsertDefault,
|
||||
getOrInsertWith,
|
||||
Set_isSuperset,
|
||||
} from '../Utils/utils';
|
||||
import {
|
||||
printAliasingEffect,
|
||||
printAliasingSignature,
|
||||
printFunction,
|
||||
printIdentifier,
|
||||
printInstruction,
|
||||
printInstructionValue,
|
||||
@@ -197,15 +194,12 @@ export function inferMutationAliasingEffects(
|
||||
let count = 0;
|
||||
while (queuedStates.size !== 0) {
|
||||
count++;
|
||||
if (count > 100) {
|
||||
if (count > 1000) {
|
||||
console.log(
|
||||
'oops infinite loop',
|
||||
fn.id,
|
||||
typeof fn.loc !== 'symbol' ? fn.loc?.filename : null,
|
||||
);
|
||||
if (DEBUG) {
|
||||
console.log(printFunction(fn));
|
||||
}
|
||||
throw new Error('infinite loop');
|
||||
}
|
||||
for (const [blockId, block] of fn.body.blocks) {
|
||||
@@ -217,11 +211,6 @@ export function inferMutationAliasingEffects(
|
||||
|
||||
statesByBlock.set(blockId, incomingState);
|
||||
const state = incomingState.clone();
|
||||
if (DEBUG) {
|
||||
console.log('*************');
|
||||
console.log(`bb${block.id}`);
|
||||
console.log('*************');
|
||||
}
|
||||
inferBlock(context, state, block);
|
||||
|
||||
for (const nextBlockId of eachTerminalSuccessor(block.terminal)) {
|
||||
@@ -232,19 +221,8 @@ export function inferMutationAliasingEffects(
|
||||
return Ok(undefined);
|
||||
}
|
||||
|
||||
function findHoistedContextDeclarations(
|
||||
fn: HIRFunction,
|
||||
): Map<DeclarationId, Place | null> {
|
||||
const hoisted = new Map<DeclarationId, Place | null>();
|
||||
function visit(place: Place): void {
|
||||
if (
|
||||
hoisted.has(place.identifier.declarationId) &&
|
||||
hoisted.get(place.identifier.declarationId) == null
|
||||
) {
|
||||
// If this is the first load of the value, store the location
|
||||
hoisted.set(place.identifier.declarationId, place);
|
||||
}
|
||||
}
|
||||
function findHoistedContextDeclarations(fn: HIRFunction): Set<DeclarationId> {
|
||||
const hoisted = new Set<DeclarationId>();
|
||||
for (const block of fn.body.blocks.values()) {
|
||||
for (const instr of block.instructions) {
|
||||
if (instr.value.kind === 'DeclareContext') {
|
||||
@@ -254,17 +232,10 @@ function findHoistedContextDeclarations(
|
||||
kind == InstructionKind.HoistedFunction ||
|
||||
kind == InstructionKind.HoistedLet
|
||||
) {
|
||||
hoisted.set(instr.value.lvalue.place.identifier.declarationId, null);
|
||||
}
|
||||
} else {
|
||||
for (const operand of eachInstructionValueOperand(instr.value)) {
|
||||
visit(operand);
|
||||
hoisted.add(instr.value.lvalue.place.identifier.declarationId);
|
||||
}
|
||||
}
|
||||
}
|
||||
for (const operand of eachTerminalOperand(block.terminal)) {
|
||||
visit(operand);
|
||||
}
|
||||
}
|
||||
return hoisted;
|
||||
}
|
||||
@@ -274,40 +245,21 @@ class Context {
|
||||
instructionSignatureCache: Map<Instruction, InstructionSignature> = new Map();
|
||||
effectInstructionValueCache: Map<AliasingEffect, InstructionValue> =
|
||||
new Map();
|
||||
applySignatureCache: Map<
|
||||
AliasingSignature,
|
||||
Map<AliasingEffect, Array<AliasingEffect> | null>
|
||||
> = new Map();
|
||||
catchHandlers: Map<BlockId, Place> = new Map();
|
||||
functionSignatureCache: Map<FunctionExpression, AliasingSignature> =
|
||||
new Map();
|
||||
isFuctionExpression: boolean;
|
||||
fn: HIRFunction;
|
||||
hoistedContextDeclarations: Map<DeclarationId, Place | null>;
|
||||
hoistedContextDeclarations: Set<DeclarationId>;
|
||||
|
||||
constructor(
|
||||
isFunctionExpression: boolean,
|
||||
fn: HIRFunction,
|
||||
hoistedContextDeclarations: Map<DeclarationId, Place | null>,
|
||||
hoistedContextDeclarations: Set<DeclarationId>,
|
||||
) {
|
||||
this.isFuctionExpression = isFunctionExpression;
|
||||
this.fn = fn;
|
||||
this.hoistedContextDeclarations = hoistedContextDeclarations;
|
||||
}
|
||||
|
||||
cacheApplySignature(
|
||||
signature: AliasingSignature,
|
||||
effect: Extract<AliasingEffect, {kind: 'Apply'}>,
|
||||
f: () => Array<AliasingEffect> | null,
|
||||
): Array<AliasingEffect> | null {
|
||||
const inner = getOrInsertDefault(
|
||||
this.applySignatureCache,
|
||||
signature,
|
||||
new Map(),
|
||||
);
|
||||
return getOrInsertWith(inner, effect, f);
|
||||
}
|
||||
|
||||
internEffect(effect: AliasingEffect): AliasingEffect {
|
||||
const hash = hashEffect(effect);
|
||||
let interned = this.internedEffects.get(hash);
|
||||
@@ -381,13 +333,11 @@ function inferBlock(
|
||||
state.appendAlias(handlerParam, instr.lvalue);
|
||||
const kind = state.kind(instr.lvalue).kind;
|
||||
if (kind === ValueKind.Mutable || kind == ValueKind.Context) {
|
||||
effects.push(
|
||||
context.internEffect({
|
||||
kind: 'Alias',
|
||||
from: instr.lvalue,
|
||||
into: handlerParam,
|
||||
}),
|
||||
);
|
||||
effects.push({
|
||||
kind: 'Alias',
|
||||
from: instr.lvalue,
|
||||
into: handlerParam,
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -396,11 +346,11 @@ function inferBlock(
|
||||
} else if (terminal.kind === 'return') {
|
||||
if (!context.isFuctionExpression) {
|
||||
terminal.effects = [
|
||||
context.internEffect({
|
||||
{
|
||||
kind: 'Freeze',
|
||||
value: terminal.value,
|
||||
reason: ValueReason.JsxCaptured,
|
||||
}),
|
||||
},
|
||||
];
|
||||
}
|
||||
}
|
||||
@@ -577,21 +527,20 @@ function applyEffect(
|
||||
break;
|
||||
}
|
||||
case ValueKind.Frozen: {
|
||||
applyEffect(
|
||||
context,
|
||||
state,
|
||||
{
|
||||
kind: 'ImmutableCapture',
|
||||
from: effect.from,
|
||||
into: effect.into,
|
||||
},
|
||||
aliased,
|
||||
effects,
|
||||
);
|
||||
effects.push({
|
||||
kind: 'ImmutableCapture',
|
||||
from: effect.from,
|
||||
into: effect.into,
|
||||
});
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
effects.push(effect);
|
||||
effects.push({
|
||||
// OK: recording information flow
|
||||
kind: 'CreateFrom', // prev Alias
|
||||
from: effect.from,
|
||||
into: effect.into,
|
||||
});
|
||||
}
|
||||
}
|
||||
break;
|
||||
@@ -690,17 +639,11 @@ function applyEffect(
|
||||
}
|
||||
case ValueKind.Frozen: {
|
||||
isMutableReferenceType = false;
|
||||
applyEffect(
|
||||
context,
|
||||
state,
|
||||
{
|
||||
kind: 'ImmutableCapture',
|
||||
from: effect.from,
|
||||
into: effect.into,
|
||||
},
|
||||
aliased,
|
||||
effects,
|
||||
);
|
||||
effects.push({
|
||||
kind: 'ImmutableCapture',
|
||||
from: effect.from,
|
||||
into: effect.into,
|
||||
});
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
@@ -722,17 +665,11 @@ function applyEffect(
|
||||
const fromKind = fromValue.kind;
|
||||
switch (fromKind) {
|
||||
case ValueKind.Frozen: {
|
||||
applyEffect(
|
||||
context,
|
||||
state,
|
||||
{
|
||||
kind: 'ImmutableCapture',
|
||||
from: effect.from,
|
||||
into: effect.into,
|
||||
},
|
||||
aliased,
|
||||
effects,
|
||||
);
|
||||
effects.push({
|
||||
kind: 'ImmutableCapture',
|
||||
from: effect.from,
|
||||
into: effect.into,
|
||||
});
|
||||
let value = context.effectInstructionValueCache.get(effect);
|
||||
if (value == null) {
|
||||
value = {
|
||||
@@ -790,33 +727,23 @@ function applyEffect(
|
||||
* We're calling a locally declared function, we already know it's effects!
|
||||
* We just have to substitute in the args for the params
|
||||
*/
|
||||
const functionExpr = functionValues[0];
|
||||
let signature = context.functionSignatureCache.get(functionExpr);
|
||||
if (signature == null) {
|
||||
signature = buildSignatureFromFunctionExpression(
|
||||
state.env,
|
||||
functionExpr,
|
||||
);
|
||||
context.functionSignatureCache.set(functionExpr, signature);
|
||||
}
|
||||
const signature = buildSignatureFromFunctionExpression(
|
||||
state.env,
|
||||
functionValues[0],
|
||||
);
|
||||
if (DEBUG) {
|
||||
console.log(
|
||||
`constructed alias signature:\n${printAliasingSignature(signature)}`,
|
||||
);
|
||||
}
|
||||
const signatureEffects = context.cacheApplySignature(
|
||||
const signatureEffects = computeEffectsForSignature(
|
||||
state.env,
|
||||
signature,
|
||||
effect,
|
||||
() =>
|
||||
computeEffectsForSignature(
|
||||
state.env,
|
||||
signature,
|
||||
effect.into,
|
||||
effect.receiver,
|
||||
effect.args,
|
||||
functionExpr.loweredFunc.func.context,
|
||||
effect.loc,
|
||||
),
|
||||
effect.into,
|
||||
effect.receiver,
|
||||
effect.args,
|
||||
functionValues[0].loweredFunc.func.context,
|
||||
effect.loc,
|
||||
);
|
||||
if (signatureEffects != null) {
|
||||
if (DEBUG) {
|
||||
@@ -835,24 +762,18 @@ function applyEffect(
|
||||
break;
|
||||
}
|
||||
}
|
||||
let signatureEffects = null;
|
||||
if (effect.signature?.aliasing != null) {
|
||||
const signature = effect.signature.aliasing;
|
||||
signatureEffects = context.cacheApplySignature(
|
||||
effect.signature.aliasing,
|
||||
effect,
|
||||
() =>
|
||||
computeEffectsForSignature(
|
||||
const signatureEffects =
|
||||
effect.signature?.aliasing != null
|
||||
? computeEffectsForSignature(
|
||||
state.env,
|
||||
signature,
|
||||
effect.signature.aliasing,
|
||||
effect.into,
|
||||
effect.receiver,
|
||||
effect.args,
|
||||
[],
|
||||
effect.loc,
|
||||
),
|
||||
);
|
||||
}
|
||||
)
|
||||
: null;
|
||||
if (signatureEffects != null) {
|
||||
if (DEBUG) {
|
||||
console.log('apply aliasing signature effects');
|
||||
@@ -980,89 +901,27 @@ function applyEffect(
|
||||
console.log(prettyFormat(state.debugAbstractValue(value)));
|
||||
}
|
||||
|
||||
if (
|
||||
mutationKind === 'mutate-frozen' &&
|
||||
context.hoistedContextDeclarations.has(
|
||||
effect.value.identifier.declarationId,
|
||||
)
|
||||
) {
|
||||
const description =
|
||||
effect.value.identifier.name !== null &&
|
||||
effect.value.identifier.name.kind === 'named'
|
||||
? `Variable \`${effect.value.identifier.name.value}\` is accessed before it is declared`
|
||||
: null;
|
||||
const hoistedAccess = context.hoistedContextDeclarations.get(
|
||||
effect.value.identifier.declarationId,
|
||||
);
|
||||
if (hoistedAccess != null && hoistedAccess.loc != effect.value.loc) {
|
||||
applyEffect(
|
||||
context,
|
||||
state,
|
||||
{
|
||||
kind: 'MutateFrozen',
|
||||
place: effect.value,
|
||||
error: {
|
||||
severity: ErrorSeverity.InvalidReact,
|
||||
reason: `This variable is accessed before it is declared, which may prevent it from updating as the assigned value changes over time`,
|
||||
description,
|
||||
loc: hoistedAccess.loc,
|
||||
suggestions: null,
|
||||
},
|
||||
},
|
||||
aliased,
|
||||
effects,
|
||||
);
|
||||
}
|
||||
|
||||
applyEffect(
|
||||
context,
|
||||
state,
|
||||
{
|
||||
kind: 'MutateFrozen',
|
||||
place: effect.value,
|
||||
error: {
|
||||
severity: ErrorSeverity.InvalidReact,
|
||||
reason: `This variable is accessed before it is declared, which prevents the earlier access from updating when this value changes over time`,
|
||||
description,
|
||||
loc: effect.value.loc,
|
||||
suggestions: null,
|
||||
},
|
||||
},
|
||||
aliased,
|
||||
effects,
|
||||
);
|
||||
} else {
|
||||
const reason = getWriteErrorReason({
|
||||
kind: value.kind,
|
||||
reason: value.reason,
|
||||
context: new Set(),
|
||||
});
|
||||
const description =
|
||||
effect.value.identifier.name !== null &&
|
||||
effect.value.identifier.name.kind === 'named'
|
||||
? `Found mutation of \`${effect.value.identifier.name.value}\``
|
||||
: null;
|
||||
applyEffect(
|
||||
context,
|
||||
state,
|
||||
{
|
||||
kind:
|
||||
value.kind === ValueKind.Frozen
|
||||
? 'MutateFrozen'
|
||||
: 'MutateGlobal',
|
||||
place: effect.value,
|
||||
error: {
|
||||
severity: ErrorSeverity.InvalidReact,
|
||||
reason,
|
||||
description,
|
||||
loc: effect.value.loc,
|
||||
suggestions: null,
|
||||
},
|
||||
},
|
||||
aliased,
|
||||
effects,
|
||||
);
|
||||
}
|
||||
const reason = getWriteErrorReason({
|
||||
kind: value.kind,
|
||||
reason: value.reason,
|
||||
context: new Set(),
|
||||
});
|
||||
effects.push({
|
||||
kind:
|
||||
value.kind === ValueKind.Frozen ? 'MutateFrozen' : 'MutateGlobal',
|
||||
place: effect.value,
|
||||
error: {
|
||||
severity: ErrorSeverity.InvalidReact,
|
||||
reason,
|
||||
description:
|
||||
effect.value.identifier.name !== null &&
|
||||
effect.value.identifier.name.kind === 'named'
|
||||
? `Found mutation of \`${effect.value.identifier.name.value}\``
|
||||
: null,
|
||||
loc: effect.value.loc,
|
||||
suggestions: null,
|
||||
},
|
||||
});
|
||||
}
|
||||
break;
|
||||
}
|
||||
@@ -2100,17 +1959,28 @@ function computeEffectsForLegacySignature(
|
||||
break;
|
||||
}
|
||||
case Effect.ConditionallyMutateIterator: {
|
||||
const mutateIterator = conditionallyMutateIterator(place);
|
||||
if (mutateIterator != null) {
|
||||
effects.push(mutateIterator);
|
||||
// TODO: should we always push to captures?
|
||||
if (
|
||||
isArrayType(place.identifier) ||
|
||||
isSetType(place.identifier) ||
|
||||
isMapType(place.identifier)
|
||||
) {
|
||||
effects.push({
|
||||
kind: 'Capture',
|
||||
from: place,
|
||||
into: lvalue,
|
||||
});
|
||||
} else {
|
||||
effects.push({
|
||||
kind: 'Capture',
|
||||
from: place,
|
||||
into: lvalue,
|
||||
});
|
||||
captures.push(place);
|
||||
effects.push({
|
||||
kind: 'MutateTransitiveConditionally',
|
||||
value: place,
|
||||
});
|
||||
}
|
||||
effects.push({
|
||||
kind: 'Capture',
|
||||
from: place,
|
||||
into: lvalue,
|
||||
});
|
||||
break;
|
||||
}
|
||||
case Effect.Freeze: {
|
||||
@@ -2300,7 +2170,6 @@ function computeEffectsForSignature(
|
||||
return null;
|
||||
}
|
||||
// Build substitutions
|
||||
const mutableSpreads = new Set<IdentifierId>();
|
||||
const substitutions: Map<IdentifierId, Array<Place>> = new Map();
|
||||
substitutions.set(signature.receiver, [receiver]);
|
||||
substitutions.set(signature.returns, [lvalue]);
|
||||
@@ -2318,13 +2187,6 @@ function computeEffectsForSignature(
|
||||
}
|
||||
const place = arg.kind === 'Identifier' ? arg : arg.place;
|
||||
getOrInsertWith(substitutions, signature.rest, () => []).push(place);
|
||||
|
||||
if (arg.kind === 'Spread') {
|
||||
const mutateIterator = conditionallyMutateIterator(arg.place);
|
||||
if (mutateIterator != null) {
|
||||
mutableSpreads.add(arg.place.identifier.id);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
const param = params[i];
|
||||
substitutions.set(param, [arg]);
|
||||
@@ -2396,12 +2258,6 @@ function computeEffectsForSignature(
|
||||
case 'Freeze': {
|
||||
const values = substitutions.get(effect.value.identifier.id) ?? [];
|
||||
for (const value of values) {
|
||||
if (mutableSpreads.has(value.identifier.id)) {
|
||||
CompilerError.throwTodo({
|
||||
reason: 'Support spread syntax for hook arguments',
|
||||
loc: value.loc,
|
||||
});
|
||||
}
|
||||
effects.push({kind: 'Freeze', value, reason: effect.reason});
|
||||
}
|
||||
break;
|
||||
|
||||
@@ -175,14 +175,21 @@ import {
|
||||
* and mutability.
|
||||
*/
|
||||
function Component(t0) {
|
||||
const $ = _c(2);
|
||||
const $ = _c(4);
|
||||
const { prop } = t0;
|
||||
let t1;
|
||||
if ($[0] !== prop) {
|
||||
const obj = shallowCopy(prop);
|
||||
const aliasedObj = identity(obj);
|
||||
|
||||
const id = [obj.id];
|
||||
let t2;
|
||||
if ($[2] !== obj) {
|
||||
t2 = [obj.id];
|
||||
$[2] = obj;
|
||||
$[3] = t2;
|
||||
} else {
|
||||
t2 = $[3];
|
||||
}
|
||||
const id = t2;
|
||||
|
||||
mutate(aliasedObj);
|
||||
setPropertyByKey(aliasedObj, "id", prop.id + 1);
|
||||
|
||||
@@ -25,25 +25,17 @@ export const FIXTURE_ENTRYPOINT = {
|
||||
```javascript
|
||||
import { c as _c } from "react/compiler-runtime";
|
||||
function bar(a) {
|
||||
const $ = _c(4);
|
||||
let t0;
|
||||
if ($[0] !== a) {
|
||||
t0 = [a];
|
||||
$[0] = a;
|
||||
$[1] = t0;
|
||||
} else {
|
||||
t0 = $[1];
|
||||
}
|
||||
const x = t0;
|
||||
const $ = _c(2);
|
||||
let y;
|
||||
if ($[2] !== x[0][1]) {
|
||||
if ($[0] !== a) {
|
||||
const x = [a];
|
||||
y = {};
|
||||
|
||||
y = x[0][1];
|
||||
$[2] = x[0][1];
|
||||
$[3] = y;
|
||||
$[0] = a;
|
||||
$[1] = y;
|
||||
} else {
|
||||
y = $[3];
|
||||
y = $[1];
|
||||
}
|
||||
return y;
|
||||
}
|
||||
|
||||
@@ -29,29 +29,20 @@ export const FIXTURE_ENTRYPOINT = {
|
||||
```javascript
|
||||
import { c as _c } from "react/compiler-runtime";
|
||||
function bar(a, b) {
|
||||
const $ = _c(6);
|
||||
let t0;
|
||||
if ($[0] !== a || $[1] !== b) {
|
||||
t0 = [a, b];
|
||||
$[0] = a;
|
||||
$[1] = b;
|
||||
$[2] = t0;
|
||||
} else {
|
||||
t0 = $[2];
|
||||
}
|
||||
const x = t0;
|
||||
const $ = _c(3);
|
||||
let y;
|
||||
if ($[3] !== x[0][1] || $[4] !== x[1][0]) {
|
||||
if ($[0] !== a || $[1] !== b) {
|
||||
const x = [a, b];
|
||||
y = {};
|
||||
let t = {};
|
||||
|
||||
y = x[0][1];
|
||||
t = x[1][0];
|
||||
$[3] = x[0][1];
|
||||
$[4] = x[1][0];
|
||||
$[5] = y;
|
||||
$[0] = a;
|
||||
$[1] = b;
|
||||
$[2] = y;
|
||||
} else {
|
||||
y = $[5];
|
||||
y = $[2];
|
||||
}
|
||||
return y;
|
||||
}
|
||||
|
||||
@@ -25,25 +25,17 @@ export const FIXTURE_ENTRYPOINT = {
|
||||
```javascript
|
||||
import { c as _c } from "react/compiler-runtime";
|
||||
function bar(a) {
|
||||
const $ = _c(4);
|
||||
let t0;
|
||||
if ($[0] !== a) {
|
||||
t0 = [a];
|
||||
$[0] = a;
|
||||
$[1] = t0;
|
||||
} else {
|
||||
t0 = $[1];
|
||||
}
|
||||
const x = t0;
|
||||
const $ = _c(2);
|
||||
let y;
|
||||
if ($[2] !== x[0].a[1]) {
|
||||
if ($[0] !== a) {
|
||||
const x = [a];
|
||||
y = {};
|
||||
|
||||
y = x[0].a[1];
|
||||
$[2] = x[0].a[1];
|
||||
$[3] = y;
|
||||
$[0] = a;
|
||||
$[1] = y;
|
||||
} else {
|
||||
y = $[3];
|
||||
y = $[1];
|
||||
}
|
||||
return y;
|
||||
}
|
||||
|
||||
@@ -24,25 +24,17 @@ export const FIXTURE_ENTRYPOINT = {
|
||||
```javascript
|
||||
import { c as _c } from "react/compiler-runtime";
|
||||
function bar(a) {
|
||||
const $ = _c(4);
|
||||
let t0;
|
||||
if ($[0] !== a) {
|
||||
t0 = [a];
|
||||
$[0] = a;
|
||||
$[1] = t0;
|
||||
} else {
|
||||
t0 = $[1];
|
||||
}
|
||||
const x = t0;
|
||||
const $ = _c(2);
|
||||
let y;
|
||||
if ($[2] !== x[0]) {
|
||||
if ($[0] !== a) {
|
||||
const x = [a];
|
||||
y = {};
|
||||
|
||||
y = x[0];
|
||||
$[2] = x[0];
|
||||
$[3] = y;
|
||||
$[0] = a;
|
||||
$[1] = y;
|
||||
} else {
|
||||
y = $[3];
|
||||
y = $[1];
|
||||
}
|
||||
return y;
|
||||
}
|
||||
|
||||
@@ -32,7 +32,7 @@ export const FIXTURE_ENTRYPOINT = {
|
||||
11 | });
|
||||
12 |
|
||||
> 13 | x.value += count;
|
||||
| ^ InvalidReact: Updating a value previously passed as an argument to a hook is not allowed. Consider moving the mutation before calling the hook (13:13)
|
||||
| ^ InvalidReact: This mutates a variable that React considers immutable (13:13)
|
||||
14 | return <Stringify x={x} cb={cb} />;
|
||||
15 | }
|
||||
16 |
|
||||
|
||||
@@ -32,7 +32,7 @@ export const FIXTURE_ENTRYPOINT = {
|
||||
11 | });
|
||||
12 |
|
||||
> 13 | x.value += count;
|
||||
| ^ InvalidReact: Updating a value previously passed as an argument to a hook is not allowed. Consider moving the mutation before calling the hook (13:13)
|
||||
| ^ InvalidReact: This mutates a variable that React considers immutable (13:13)
|
||||
14 | return <Stringify x={x} cb={cb} />;
|
||||
15 | }
|
||||
16 |
|
||||
|
||||
@@ -38,15 +38,13 @@ export const FIXTURE_ENTRYPOINT = {
|
||||
## Error
|
||||
|
||||
```
|
||||
17 | * $2 = Function context=setState
|
||||
18 | */
|
||||
> 19 | useEffect(() => setState(2), []);
|
||||
| ^^^^^^^^ InvalidReact: This variable is accessed before it is declared, which may prevent it from updating as the assigned value changes over time. Variable `setState` is accessed before it is declared (19:19)
|
||||
|
||||
InvalidReact: This variable is accessed before it is declared, which prevents the earlier access from updating when this value changes over time. Variable `setState` is accessed before it is declared (21:21)
|
||||
19 | useEffect(() => setState(2), []);
|
||||
20 |
|
||||
21 | const [state, setState] = useState(0);
|
||||
> 21 | const [state, setState] = useState(0);
|
||||
| ^^^^^^^^ InvalidReact: Updating a value used previously in an effect function or as an effect dependency is not allowed. Consider moving the mutation before calling useEffect(). Found mutation of `setState` (21:21)
|
||||
22 | return <Stringify state={state} />;
|
||||
23 | }
|
||||
24 |
|
||||
```
|
||||
|
||||
|
||||
@@ -20,7 +20,7 @@ function Component() {
|
||||
2 |
|
||||
3 | function Component() {
|
||||
> 4 | const date = Date.now();
|
||||
| ^^^^^^^^^^ InvalidReact: Calling an impure function can produce unstable results. (https://react.dev/reference/rules/components-and-hooks-must-be-pure#components-and-hooks-must-be-idempotent). `Date.now` is an impure function whose results may change on every call (4:4)
|
||||
| ^^^^^^^^ InvalidReact: Calling an impure function can produce unstable results. (https://react.dev/reference/rules/components-and-hooks-must-be-pure#components-and-hooks-must-be-idempotent). `Date.now` is an impure function whose results may change on every call (4:4)
|
||||
|
||||
InvalidReact: Calling an impure function can produce unstable results. (https://react.dev/reference/rules/components-and-hooks-must-be-pure#components-and-hooks-must-be-idempotent). `performance.now` is an impure function whose results may change on every call (5:5)
|
||||
|
||||
|
||||
@@ -27,7 +27,7 @@ function SomeComponent() {
|
||||
9 | return (
|
||||
10 | <Button
|
||||
> 11 | onPress={() => (sharedVal.value = Math.random())}
|
||||
| ^^^^^^^^^ InvalidReact: Updating a value returned from a hook is not allowed. Consider moving the mutation into the hook where the value is constructed. Found mutation of `sharedVal` (11:11)
|
||||
| ^^^^^^^^^ InvalidReact: Mutating a value returned from a function whose return value should not be mutated. Found mutation of `sharedVal` (11:11)
|
||||
12 | title="Randomize"
|
||||
13 | />
|
||||
14 | );
|
||||
|
||||
@@ -16,8 +16,6 @@ function useHook(a, b) {
|
||||
1 | function useHook(a, b) {
|
||||
> 2 | b.test = 1;
|
||||
| ^ InvalidReact: Mutating component props or hook arguments is not allowed. Consider using a local variable instead (2:2)
|
||||
|
||||
InvalidReact: Mutating component props or hook arguments is not allowed. Consider using a local variable instead (3:3)
|
||||
3 | a.test = 2;
|
||||
4 | }
|
||||
5 |
|
||||
|
||||
@@ -21,8 +21,6 @@ function Component(props) {
|
||||
4 | foo(() => {
|
||||
> 5 | x.a = 10;
|
||||
| ^ InvalidReact: Writing to a variable defined outside a component or hook is not allowed. Consider using an effect (5:5)
|
||||
|
||||
InvalidReact: Writing to a variable defined outside a component or hook is not allowed. Consider using an effect (6:6)
|
||||
6 | x.a = 20;
|
||||
7 | });
|
||||
8 | }
|
||||
|
||||
@@ -21,8 +21,6 @@ function Component() {
|
||||
3 | // Cannot assign to globals
|
||||
> 4 | someUnknownGlobal = true;
|
||||
| ^^^^^^^^^^^^^^^^^ InvalidReact: Unexpected reassignment of a variable which was defined outside of the component. Components and hooks should be pure and side-effect free, but variable reassignment is a form of side-effect. If this variable is used in rendering, use useState instead. (https://react.dev/reference/rules/components-and-hooks-must-be-pure#side-effects-must-run-outside-of-render) (4:4)
|
||||
|
||||
InvalidReact: Unexpected reassignment of a variable which was defined outside of the component. Components and hooks should be pure and side-effect free, but variable reassignment is a form of side-effect. If this variable is used in rendering, use useState instead. (https://react.dev/reference/rules/components-and-hooks-must-be-pure#side-effects-must-run-outside-of-render) (5:5)
|
||||
5 | moduleLocal = true;
|
||||
6 | };
|
||||
7 | foo();
|
||||
|
||||
@@ -18,8 +18,6 @@ function Component() {
|
||||
2 | // Cannot assign to globals
|
||||
> 3 | someUnknownGlobal = true;
|
||||
| ^^^^^^^^^^^^^^^^^ InvalidReact: Unexpected reassignment of a variable which was defined outside of the component. Components and hooks should be pure and side-effect free, but variable reassignment is a form of side-effect. If this variable is used in rendering, use useState instead. (https://react.dev/reference/rules/components-and-hooks-must-be-pure#side-effects-must-run-outside-of-render) (3:3)
|
||||
|
||||
InvalidReact: Unexpected reassignment of a variable which was defined outside of the component. Components and hooks should be pure and side-effect free, but variable reassignment is a form of side-effect. If this variable is used in rendering, use useState instead. (https://react.dev/reference/rules/components-and-hooks-must-be-pure#side-effects-must-run-outside-of-render) (4:4)
|
||||
4 | moduleLocal = true;
|
||||
5 | }
|
||||
6 |
|
||||
|
||||
@@ -22,7 +22,7 @@ function Component(props) {
|
||||
7 | return hasErrors;
|
||||
8 | }
|
||||
> 9 | return hasErrors();
|
||||
| ^^^^^^^^^ Invariant: [InferMutationAliasingEffects] Expected value kind to be initialized. <unknown> hasErrors_0$15:TFunction (9:9)
|
||||
| ^^^^^^^^^ Invariant: [hoisting] Expected value for identifier to be initialized. hasErrors_0$15 (9:9)
|
||||
10 | }
|
||||
11 |
|
||||
```
|
||||
|
||||
@@ -34,13 +34,13 @@ export const FIXTURE_ENTRYPOINT = {
|
||||
## Error
|
||||
|
||||
```
|
||||
11 |
|
||||
12 | function foo() {
|
||||
> 13 | return bar();
|
||||
| ^^^ Todo: [PruneHoistedContexts] Rewrite hoisted function references (13:13)
|
||||
13 | return bar();
|
||||
14 | }
|
||||
15 | function bar() {
|
||||
> 15 | function bar() {
|
||||
| ^^^ Todo: [PruneHoistedContexts] Rewrite hoisted function references (15:15)
|
||||
16 | return 42;
|
||||
17 | }
|
||||
18 |
|
||||
```
|
||||
|
||||
|
||||
@@ -48,7 +48,7 @@ export const FIXTURE_ENTRYPOINT = {
|
||||
## Logs
|
||||
|
||||
```
|
||||
{"kind":"CompileError","fnLoc":{"start":{"line":5,"column":0,"index":139},"end":{"line":12,"column":1,"index":384},"filename":"mutate-after-useeffect-optional-chain.ts"},"detail":{"reason":"Updating a value used previously in an effect function or as an effect dependency is not allowed. Consider moving the mutation before calling useEffect()","description":null,"severity":"InvalidReact","suggestions":null,"loc":{"start":{"line":10,"column":2,"index":345},"end":{"line":10,"column":5,"index":348},"filename":"mutate-after-useeffect-optional-chain.ts","identifierName":"arr"}}}
|
||||
{"kind":"CompileError","fnLoc":{"start":{"line":5,"column":0,"index":139},"end":{"line":12,"column":1,"index":384},"filename":"mutate-after-useeffect-optional-chain.ts"},"detail":{"reason":"This mutates a variable that React considers immutable","description":null,"loc":{"start":{"line":10,"column":2,"index":345},"end":{"line":10,"column":5,"index":348},"filename":"mutate-after-useeffect-optional-chain.ts","identifierName":"arr"},"suggestions":null,"severity":"InvalidReact"}}
|
||||
{"kind":"AutoDepsDecorations","fnLoc":{"start":{"line":9,"column":2,"index":304},"end":{"line":9,"column":39,"index":341},"filename":"mutate-after-useeffect-optional-chain.ts"},"decorations":[{"start":{"line":9,"column":24,"index":326},"end":{"line":9,"column":27,"index":329},"filename":"mutate-after-useeffect-optional-chain.ts","identifierName":"arr"}]}
|
||||
{"kind":"CompileSuccess","fnLoc":{"start":{"line":5,"column":0,"index":139},"end":{"line":12,"column":1,"index":384},"filename":"mutate-after-useeffect-optional-chain.ts"},"fnName":"Component","memoSlots":0,"memoBlocks":0,"memoValues":0,"prunedMemoBlocks":0,"prunedMemoValues":0}
|
||||
```
|
||||
|
||||
@@ -47,7 +47,7 @@ export const FIXTURE_ENTRYPOINT = {
|
||||
## Logs
|
||||
|
||||
```
|
||||
{"kind":"CompileError","fnLoc":{"start":{"line":6,"column":0,"index":148},"end":{"line":11,"column":1,"index":311},"filename":"mutate-after-useeffect-ref-access.ts"},"detail":{"reason":"Mutating component props or hook arguments is not allowed. Consider using a local variable instead","description":null,"severity":"InvalidReact","suggestions":null,"loc":{"start":{"line":9,"column":2,"index":269},"end":{"line":9,"column":16,"index":283},"filename":"mutate-after-useeffect-ref-access.ts"}}}
|
||||
{"kind":"CompileError","fnLoc":{"start":{"line":6,"column":0,"index":148},"end":{"line":11,"column":1,"index":311},"filename":"mutate-after-useeffect-ref-access.ts"},"detail":{"reason":"Mutating component props or hook arguments is not allowed. Consider using a local variable instead","description":null,"loc":{"start":{"line":9,"column":2,"index":269},"end":{"line":9,"column":16,"index":283},"filename":"mutate-after-useeffect-ref-access.ts"},"suggestions":null,"severity":"InvalidReact"}}
|
||||
{"kind":"AutoDepsDecorations","fnLoc":{"start":{"line":8,"column":2,"index":227},"end":{"line":8,"column":40,"index":265},"filename":"mutate-after-useeffect-ref-access.ts"},"decorations":[{"start":{"line":8,"column":24,"index":249},"end":{"line":8,"column":30,"index":255},"filename":"mutate-after-useeffect-ref-access.ts","identifierName":"arrRef"}]}
|
||||
{"kind":"CompileSuccess","fnLoc":{"start":{"line":6,"column":0,"index":148},"end":{"line":11,"column":1,"index":311},"filename":"mutate-after-useeffect-ref-access.ts"},"fnName":"Component","memoSlots":0,"memoBlocks":0,"memoValues":0,"prunedMemoBlocks":0,"prunedMemoValues":0}
|
||||
```
|
||||
|
||||
@@ -47,7 +47,7 @@ export const FIXTURE_ENTRYPOINT = {
|
||||
## Logs
|
||||
|
||||
```
|
||||
{"kind":"CompileError","fnLoc":{"start":{"line":4,"column":0,"index":101},"end":{"line":11,"column":1,"index":222},"filename":"mutate-after-useeffect.ts"},"detail":{"reason":"Updating a value used previously in an effect function or as an effect dependency is not allowed. Consider moving the mutation before calling useEffect()","description":null,"severity":"InvalidReact","suggestions":null,"loc":{"start":{"line":9,"column":2,"index":194},"end":{"line":9,"column":5,"index":197},"filename":"mutate-after-useeffect.ts","identifierName":"arr"}}}
|
||||
{"kind":"CompileError","fnLoc":{"start":{"line":4,"column":0,"index":101},"end":{"line":11,"column":1,"index":222},"filename":"mutate-after-useeffect.ts"},"detail":{"reason":"This mutates a variable that React considers immutable","description":null,"loc":{"start":{"line":9,"column":2,"index":194},"end":{"line":9,"column":5,"index":197},"filename":"mutate-after-useeffect.ts","identifierName":"arr"},"suggestions":null,"severity":"InvalidReact"}}
|
||||
{"kind":"AutoDepsDecorations","fnLoc":{"start":{"line":6,"column":2,"index":149},"end":{"line":8,"column":4,"index":190},"filename":"mutate-after-useeffect.ts"},"decorations":[{"start":{"line":7,"column":4,"index":171},"end":{"line":7,"column":7,"index":174},"filename":"mutate-after-useeffect.ts","identifierName":"arr"},{"start":{"line":7,"column":4,"index":171},"end":{"line":7,"column":7,"index":174},"filename":"mutate-after-useeffect.ts","identifierName":"arr"},{"start":{"line":7,"column":13,"index":180},"end":{"line":7,"column":16,"index":183},"filename":"mutate-after-useeffect.ts","identifierName":"foo"}]}
|
||||
{"kind":"CompileSuccess","fnLoc":{"start":{"line":4,"column":0,"index":101},"end":{"line":11,"column":1,"index":222},"filename":"mutate-after-useeffect.ts"},"fnName":"Component","memoSlots":0,"memoBlocks":0,"memoValues":0,"prunedMemoBlocks":0,"prunedMemoValues":0}
|
||||
```
|
||||
|
||||
@@ -52,7 +52,7 @@ export const FIXTURE_ENTRYPOINT = {
|
||||
## Logs
|
||||
|
||||
```
|
||||
{"kind":"CompileError","fnLoc":{"start":{"line":5,"column":0,"index":163},"end":{"line":13,"column":1,"index":357},"filename":"retry-no-emit.ts"},"detail":{"reason":"Updating a value previously passed as an argument to a hook is not allowed. Consider moving the mutation before calling the hook","description":null,"severity":"InvalidReact","suggestions":null,"loc":{"start":{"line":11,"column":2,"index":320},"end":{"line":11,"column":6,"index":324},"filename":"retry-no-emit.ts","identifierName":"arr2"}}}
|
||||
{"kind":"CompileError","fnLoc":{"start":{"line":5,"column":0,"index":163},"end":{"line":13,"column":1,"index":357},"filename":"retry-no-emit.ts"},"detail":{"reason":"This mutates a variable that React considers immutable","description":null,"loc":{"start":{"line":11,"column":2,"index":320},"end":{"line":11,"column":6,"index":324},"filename":"retry-no-emit.ts","identifierName":"arr2"},"suggestions":null,"severity":"InvalidReact"}}
|
||||
{"kind":"AutoDepsDecorations","fnLoc":{"start":{"line":7,"column":2,"index":216},"end":{"line":7,"column":36,"index":250},"filename":"retry-no-emit.ts"},"decorations":[{"start":{"line":7,"column":31,"index":245},"end":{"line":7,"column":34,"index":248},"filename":"retry-no-emit.ts","identifierName":"arr"}]}
|
||||
{"kind":"AutoDepsDecorations","fnLoc":{"start":{"line":10,"column":2,"index":274},"end":{"line":10,"column":44,"index":316},"filename":"retry-no-emit.ts"},"decorations":[{"start":{"line":10,"column":25,"index":297},"end":{"line":10,"column":29,"index":301},"filename":"retry-no-emit.ts","identifierName":"arr2"},{"start":{"line":10,"column":25,"index":297},"end":{"line":10,"column":29,"index":301},"filename":"retry-no-emit.ts","identifierName":"arr2"},{"start":{"line":10,"column":35,"index":307},"end":{"line":10,"column":42,"index":314},"filename":"retry-no-emit.ts","identifierName":"propVal"}]}
|
||||
{"kind":"CompileSuccess","fnLoc":{"start":{"line":5,"column":0,"index":163},"end":{"line":13,"column":1,"index":357},"filename":"retry-no-emit.ts"},"fnName":"Foo","memoSlots":0,"memoBlocks":0,"memoValues":0,"prunedMemoBlocks":0,"prunedMemoValues":0}
|
||||
|
||||
@@ -34,28 +34,22 @@ import { print } from "shared-runtime";
|
||||
* setState types are not enough to determine to omit from deps. Must also take reactivity into account.
|
||||
*/
|
||||
function ReactiveRefInEffect(props) {
|
||||
const $ = _c(4);
|
||||
const $ = _c(2);
|
||||
const [, setState1] = useRef("initial value");
|
||||
const [, setState2] = useRef("initial value");
|
||||
let setState;
|
||||
if ($[0] !== props.foo) {
|
||||
if (props.foo) {
|
||||
setState = setState1;
|
||||
} else {
|
||||
setState = setState2;
|
||||
}
|
||||
$[0] = props.foo;
|
||||
$[1] = setState;
|
||||
if (props.foo) {
|
||||
setState = setState1;
|
||||
} else {
|
||||
setState = $[1];
|
||||
setState = setState2;
|
||||
}
|
||||
let t0;
|
||||
if ($[2] !== setState) {
|
||||
if ($[0] !== setState) {
|
||||
t0 = () => print(setState);
|
||||
$[2] = setState;
|
||||
$[3] = t0;
|
||||
$[0] = setState;
|
||||
$[1] = t0;
|
||||
} else {
|
||||
t0 = $[3];
|
||||
t0 = $[1];
|
||||
}
|
||||
useEffect(t0, [setState]);
|
||||
}
|
||||
|
||||
@@ -2,7 +2,6 @@
|
||||
## Input
|
||||
|
||||
```javascript
|
||||
// @enableNewMutationAliasingModel
|
||||
import {
|
||||
Stringify,
|
||||
mutate,
|
||||
@@ -102,7 +101,7 @@ export const FIXTURE_ENTRYPOINT = {
|
||||
## Code
|
||||
|
||||
```javascript
|
||||
import { c as _c } from "react/compiler-runtime"; // @enableNewMutationAliasingModel
|
||||
import { c as _c } from "react/compiler-runtime";
|
||||
import {
|
||||
Stringify,
|
||||
mutate,
|
||||
@@ -176,14 +175,21 @@ import {
|
||||
* and mutability.
|
||||
*/
|
||||
function Component(t0) {
|
||||
const $ = _c(2);
|
||||
const $ = _c(4);
|
||||
const { prop } = t0;
|
||||
let t1;
|
||||
if ($[0] !== prop) {
|
||||
const obj = shallowCopy(prop);
|
||||
const aliasedObj = identity(obj);
|
||||
|
||||
const id = [obj.id];
|
||||
let t2;
|
||||
if ($[2] !== obj) {
|
||||
t2 = [obj.id];
|
||||
$[2] = obj;
|
||||
$[3] = t2;
|
||||
} else {
|
||||
t2 = $[3];
|
||||
}
|
||||
const id = t2;
|
||||
|
||||
mutate(aliasedObj);
|
||||
setPropertyByKey(aliasedObj, "id", prop.id + 1);
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
// @enableNewMutationAliasingModel
|
||||
import {
|
||||
Stringify,
|
||||
mutate,
|
||||
|
||||
@@ -2,7 +2,6 @@
|
||||
## Input
|
||||
|
||||
```javascript
|
||||
// @enableNewMutationAliasingModel
|
||||
import {Stringify} from 'shared-runtime';
|
||||
|
||||
/**
|
||||
@@ -44,7 +43,7 @@ export const FIXTURE_ENTRYPOINT = {
|
||||
## Code
|
||||
|
||||
```javascript
|
||||
import { c as _c } from "react/compiler-runtime"; // @enableNewMutationAliasingModel
|
||||
import { c as _c } from "react/compiler-runtime";
|
||||
import { Stringify } from "shared-runtime";
|
||||
|
||||
/**
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
// @enableNewMutationAliasingModel
|
||||
import {Stringify} from 'shared-runtime';
|
||||
|
||||
/**
|
||||
|
||||
@@ -2,7 +2,6 @@
|
||||
## Input
|
||||
|
||||
```javascript
|
||||
// @enableNewMutationAliasingModel
|
||||
function bar(a) {
|
||||
let x = [a];
|
||||
let y = {};
|
||||
@@ -24,27 +23,19 @@ export const FIXTURE_ENTRYPOINT = {
|
||||
## Code
|
||||
|
||||
```javascript
|
||||
import { c as _c } from "react/compiler-runtime"; // @enableNewMutationAliasingModel
|
||||
import { c as _c } from "react/compiler-runtime";
|
||||
function bar(a) {
|
||||
const $ = _c(4);
|
||||
let t0;
|
||||
if ($[0] !== a) {
|
||||
t0 = [a];
|
||||
$[0] = a;
|
||||
$[1] = t0;
|
||||
} else {
|
||||
t0 = $[1];
|
||||
}
|
||||
const x = t0;
|
||||
const $ = _c(2);
|
||||
let y;
|
||||
if ($[2] !== x[0][1]) {
|
||||
if ($[0] !== a) {
|
||||
const x = [a];
|
||||
y = {};
|
||||
|
||||
y = x[0][1];
|
||||
$[2] = x[0][1];
|
||||
$[3] = y;
|
||||
$[0] = a;
|
||||
$[1] = y;
|
||||
} else {
|
||||
y = $[3];
|
||||
y = $[1];
|
||||
}
|
||||
return y;
|
||||
}
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
// @enableNewMutationAliasingModel
|
||||
function bar(a) {
|
||||
let x = [a];
|
||||
let y = {};
|
||||
|
||||
@@ -2,7 +2,6 @@
|
||||
## Input
|
||||
|
||||
```javascript
|
||||
// @enableNewMutationAliasingModel
|
||||
function bar(a, b) {
|
||||
let x = [a, b];
|
||||
let y = {};
|
||||
@@ -28,31 +27,22 @@ export const FIXTURE_ENTRYPOINT = {
|
||||
## Code
|
||||
|
||||
```javascript
|
||||
import { c as _c } from "react/compiler-runtime"; // @enableNewMutationAliasingModel
|
||||
import { c as _c } from "react/compiler-runtime";
|
||||
function bar(a, b) {
|
||||
const $ = _c(6);
|
||||
let t0;
|
||||
if ($[0] !== a || $[1] !== b) {
|
||||
t0 = [a, b];
|
||||
$[0] = a;
|
||||
$[1] = b;
|
||||
$[2] = t0;
|
||||
} else {
|
||||
t0 = $[2];
|
||||
}
|
||||
const x = t0;
|
||||
const $ = _c(3);
|
||||
let y;
|
||||
if ($[3] !== x[0][1] || $[4] !== x[1][0]) {
|
||||
if ($[0] !== a || $[1] !== b) {
|
||||
const x = [a, b];
|
||||
y = {};
|
||||
let t = {};
|
||||
|
||||
y = x[0][1];
|
||||
t = x[1][0];
|
||||
$[3] = x[0][1];
|
||||
$[4] = x[1][0];
|
||||
$[5] = y;
|
||||
$[0] = a;
|
||||
$[1] = b;
|
||||
$[2] = y;
|
||||
} else {
|
||||
y = $[5];
|
||||
y = $[2];
|
||||
}
|
||||
return y;
|
||||
}
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
// @enableNewMutationAliasingModel
|
||||
function bar(a, b) {
|
||||
let x = [a, b];
|
||||
let y = {};
|
||||
|
||||
@@ -2,7 +2,6 @@
|
||||
## Input
|
||||
|
||||
```javascript
|
||||
// @enableNewMutationAliasingModel
|
||||
function bar(a) {
|
||||
let x = [a];
|
||||
let y = {};
|
||||
@@ -24,27 +23,19 @@ export const FIXTURE_ENTRYPOINT = {
|
||||
## Code
|
||||
|
||||
```javascript
|
||||
import { c as _c } from "react/compiler-runtime"; // @enableNewMutationAliasingModel
|
||||
import { c as _c } from "react/compiler-runtime";
|
||||
function bar(a) {
|
||||
const $ = _c(4);
|
||||
let t0;
|
||||
if ($[0] !== a) {
|
||||
t0 = [a];
|
||||
$[0] = a;
|
||||
$[1] = t0;
|
||||
} else {
|
||||
t0 = $[1];
|
||||
}
|
||||
const x = t0;
|
||||
const $ = _c(2);
|
||||
let y;
|
||||
if ($[2] !== x[0].a[1]) {
|
||||
if ($[0] !== a) {
|
||||
const x = [a];
|
||||
y = {};
|
||||
|
||||
y = x[0].a[1];
|
||||
$[2] = x[0].a[1];
|
||||
$[3] = y;
|
||||
$[0] = a;
|
||||
$[1] = y;
|
||||
} else {
|
||||
y = $[3];
|
||||
y = $[1];
|
||||
}
|
||||
return y;
|
||||
}
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
// @enableNewMutationAliasingModel
|
||||
function bar(a) {
|
||||
let x = [a];
|
||||
let y = {};
|
||||
|
||||
@@ -2,7 +2,6 @@
|
||||
## Input
|
||||
|
||||
```javascript
|
||||
// @enableNewMutationAliasingModel
|
||||
function bar(a) {
|
||||
let x = [a];
|
||||
let y = {};
|
||||
@@ -23,27 +22,19 @@ export const FIXTURE_ENTRYPOINT = {
|
||||
## Code
|
||||
|
||||
```javascript
|
||||
import { c as _c } from "react/compiler-runtime"; // @enableNewMutationAliasingModel
|
||||
import { c as _c } from "react/compiler-runtime";
|
||||
function bar(a) {
|
||||
const $ = _c(4);
|
||||
let t0;
|
||||
if ($[0] !== a) {
|
||||
t0 = [a];
|
||||
$[0] = a;
|
||||
$[1] = t0;
|
||||
} else {
|
||||
t0 = $[1];
|
||||
}
|
||||
const x = t0;
|
||||
const $ = _c(2);
|
||||
let y;
|
||||
if ($[2] !== x[0]) {
|
||||
if ($[0] !== a) {
|
||||
const x = [a];
|
||||
y = {};
|
||||
|
||||
y = x[0];
|
||||
$[2] = x[0];
|
||||
$[3] = y;
|
||||
$[0] = a;
|
||||
$[1] = y;
|
||||
} else {
|
||||
y = $[3];
|
||||
y = $[1];
|
||||
}
|
||||
return y;
|
||||
}
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
// @enableNewMutationAliasingModel
|
||||
function bar(a) {
|
||||
let x = [a];
|
||||
let y = {};
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
## Input
|
||||
|
||||
```javascript
|
||||
// @validateNoImpureFunctionsInRender @enableNewMutationAliasingModel
|
||||
// @validateNoImpureFunctionsInRender
|
||||
|
||||
function Component() {
|
||||
const date = Date.now();
|
||||
@@ -20,7 +20,7 @@ function Component() {
|
||||
2 |
|
||||
3 | function Component() {
|
||||
> 4 | const date = Date.now();
|
||||
| ^^^^^^^^^^ InvalidReact: Calling an impure function can produce unstable results. (https://react.dev/reference/rules/components-and-hooks-must-be-pure#components-and-hooks-must-be-idempotent). `Date.now` is an impure function whose results may change on every call (4:4)
|
||||
| ^^^^^^^^ InvalidReact: Calling an impure function can produce unstable results. (https://react.dev/reference/rules/components-and-hooks-must-be-pure#components-and-hooks-must-be-idempotent). `Date.now` is an impure function whose results may change on every call (4:4)
|
||||
|
||||
InvalidReact: Calling an impure function can produce unstable results. (https://react.dev/reference/rules/components-and-hooks-must-be-pure#components-and-hooks-must-be-idempotent). `performance.now` is an impure function whose results may change on every call (5:5)
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// @validateNoImpureFunctionsInRender @enableNewMutationAliasingModel
|
||||
// @validateNoImpureFunctionsInRender
|
||||
|
||||
function Component() {
|
||||
const date = Date.now();
|
||||
|
||||
@@ -2,7 +2,6 @@
|
||||
## Input
|
||||
|
||||
```javascript
|
||||
// @enableNewMutationAliasingModel
|
||||
function Component() {
|
||||
let local;
|
||||
|
||||
@@ -42,13 +41,13 @@ function Component() {
|
||||
## Error
|
||||
|
||||
```
|
||||
4 |
|
||||
5 | const reassignLocal = newValue => {
|
||||
> 6 | local = newValue;
|
||||
| ^^^^^ InvalidReact: Reassigning a variable after render has completed can cause inconsistent behavior on subsequent renders. Consider using state instead. Variable `local` cannot be reassigned after render (6:6)
|
||||
7 | };
|
||||
8 |
|
||||
9 | const onClick = newValue => {
|
||||
3 |
|
||||
4 | const reassignLocal = newValue => {
|
||||
> 5 | local = newValue;
|
||||
| ^^^^^ InvalidReact: Reassigning a variable after render has completed can cause inconsistent behavior on subsequent renders. Consider using state instead. Variable `local` cannot be reassigned after render (5:5)
|
||||
6 | };
|
||||
7 |
|
||||
8 | const onClick = newValue => {
|
||||
```
|
||||
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
// @enableNewMutationAliasingModel
|
||||
function Component() {
|
||||
let local;
|
||||
|
||||
|
||||
@@ -1,45 +0,0 @@
|
||||
|
||||
## Input
|
||||
|
||||
```javascript
|
||||
//@flow @validatePreserveExistingMemoizationGuarantees @enableNewMutationAliasingModel
|
||||
|
||||
import {useCallback} from 'react';
|
||||
import {useIdentity} from 'shared-runtime';
|
||||
|
||||
function Component({content, refetch}) {
|
||||
// This callback function accesses a hoisted const as a dependency,
|
||||
// but it cannot reference it as a dependency since that would be a
|
||||
// TDZ violation!
|
||||
const onRefetch = useCallback(() => {
|
||||
refetch(data);
|
||||
}, [refetch]);
|
||||
|
||||
// The context variable gets frozen here since it's passed to a hook
|
||||
const onSubmit = useIdentity(onRefetch);
|
||||
|
||||
// This has to error: onRefetch needs to memoize with `content` as a
|
||||
// dependency, but the dependency comes later
|
||||
const {data = null} = content;
|
||||
|
||||
return <Foo data={data} onSubmit={onSubmit} />;
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
|
||||
## Error
|
||||
|
||||
```
|
||||
9 | // TDZ violation!
|
||||
10 | const onRefetch = useCallback(() => {
|
||||
> 11 | refetch(data);
|
||||
| ^^^^ InvalidReact: This variable is accessed before it is declared, which may prevent it from updating as the assigned value changes over time. Variable `data` is accessed before it is declared (11:11)
|
||||
|
||||
InvalidReact: This variable is accessed before it is declared, which prevents the earlier access from updating when this value changes over time. Variable `data` is accessed before it is declared (19:19)
|
||||
12 | }, [refetch]);
|
||||
13 |
|
||||
14 | // The context variable gets frozen here since it's passed to a hook
|
||||
```
|
||||
|
||||
|
||||
@@ -1,22 +0,0 @@
|
||||
//@flow @validatePreserveExistingMemoizationGuarantees @enableNewMutationAliasingModel
|
||||
|
||||
import {useCallback} from 'react';
|
||||
import {useIdentity} from 'shared-runtime';
|
||||
|
||||
function Component({content, refetch}) {
|
||||
// This callback function accesses a hoisted const as a dependency,
|
||||
// but it cannot reference it as a dependency since that would be a
|
||||
// TDZ violation!
|
||||
const onRefetch = useCallback(() => {
|
||||
refetch(data);
|
||||
}, [refetch]);
|
||||
|
||||
// The context variable gets frozen here since it's passed to a hook
|
||||
const onSubmit = useIdentity(onRefetch);
|
||||
|
||||
// This has to error: onRefetch needs to memoize with `content` as a
|
||||
// dependency, but the dependency comes later
|
||||
const {data = null} = content;
|
||||
|
||||
return <Foo data={data} onSubmit={onSubmit} />;
|
||||
}
|
||||
@@ -19,7 +19,7 @@ function Component({a, b}) {
|
||||
3 | const x = {a};
|
||||
4 | useFreeze(x);
|
||||
> 5 | x.y = true;
|
||||
| ^ InvalidReact: Updating a value previously passed as an argument to a hook is not allowed. Consider moving the mutation before calling the hook (5:5)
|
||||
| ^ InvalidReact: This mutates a variable that React considers immutable (5:5)
|
||||
6 | return <div>error</div>;
|
||||
7 | }
|
||||
8 |
|
||||
|
||||
@@ -2,7 +2,6 @@
|
||||
## Input
|
||||
|
||||
```javascript
|
||||
// @enableNewMutationAliasingModel
|
||||
function useHook(a, b) {
|
||||
b.test = 1;
|
||||
a.test = 2;
|
||||
@@ -14,15 +13,12 @@ function useHook(a, b) {
|
||||
## Error
|
||||
|
||||
```
|
||||
1 | // @enableNewMutationAliasingModel
|
||||
2 | function useHook(a, b) {
|
||||
> 3 | b.test = 1;
|
||||
| ^ InvalidReact: Mutating component props or hook arguments is not allowed. Consider using a local variable instead (3:3)
|
||||
|
||||
InvalidReact: Mutating component props or hook arguments is not allowed. Consider using a local variable instead (4:4)
|
||||
4 | a.test = 2;
|
||||
5 | }
|
||||
6 |
|
||||
1 | function useHook(a, b) {
|
||||
> 2 | b.test = 1;
|
||||
| ^ InvalidReact: Mutating component props or hook arguments is not allowed. Consider using a local variable instead (2:2)
|
||||
3 | a.test = 2;
|
||||
4 | }
|
||||
5 |
|
||||
```
|
||||
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
// @enableNewMutationAliasingModel
|
||||
function useHook(a, b) {
|
||||
b.test = 1;
|
||||
a.test = 2;
|
||||
|
||||
@@ -2,7 +2,6 @@
|
||||
## Input
|
||||
|
||||
```javascript
|
||||
// @enableNewMutationAliasingModel
|
||||
let x = {a: 42};
|
||||
|
||||
function Component(props) {
|
||||
@@ -18,15 +17,13 @@ function Component(props) {
|
||||
## Error
|
||||
|
||||
```
|
||||
4 | function Component(props) {
|
||||
5 | foo(() => {
|
||||
> 6 | x.a = 10;
|
||||
| ^ InvalidReact: Writing to a variable defined outside a component or hook is not allowed. Consider using an effect (6:6)
|
||||
|
||||
InvalidReact: Writing to a variable defined outside a component or hook is not allowed. Consider using an effect (7:7)
|
||||
7 | x.a = 20;
|
||||
8 | });
|
||||
9 | }
|
||||
3 | function Component(props) {
|
||||
4 | foo(() => {
|
||||
> 5 | x.a = 10;
|
||||
| ^ InvalidReact: Writing to a variable defined outside a component or hook is not allowed. Consider using an effect (5:5)
|
||||
6 | x.a = 20;
|
||||
7 | });
|
||||
8 | }
|
||||
```
|
||||
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
// @enableNewMutationAliasingModel
|
||||
let x = {a: 42};
|
||||
|
||||
function Component(props) {
|
||||
|
||||
@@ -2,7 +2,6 @@
|
||||
## Input
|
||||
|
||||
```javascript
|
||||
// @enableNewMutationAliasingModel
|
||||
function Component() {
|
||||
const foo = () => {
|
||||
// Cannot assign to globals
|
||||
@@ -18,15 +17,13 @@ function Component() {
|
||||
## Error
|
||||
|
||||
```
|
||||
3 | const foo = () => {
|
||||
4 | // Cannot assign to globals
|
||||
> 5 | someUnknownGlobal = true;
|
||||
| ^^^^^^^^^^^^^^^^^ InvalidReact: Unexpected reassignment of a variable which was defined outside of the component. Components and hooks should be pure and side-effect free, but variable reassignment is a form of side-effect. If this variable is used in rendering, use useState instead. (https://react.dev/reference/rules/components-and-hooks-must-be-pure#side-effects-must-run-outside-of-render) (5:5)
|
||||
|
||||
InvalidReact: Unexpected reassignment of a variable which was defined outside of the component. Components and hooks should be pure and side-effect free, but variable reassignment is a form of side-effect. If this variable is used in rendering, use useState instead. (https://react.dev/reference/rules/components-and-hooks-must-be-pure#side-effects-must-run-outside-of-render) (6:6)
|
||||
6 | moduleLocal = true;
|
||||
7 | };
|
||||
8 | foo();
|
||||
2 | const foo = () => {
|
||||
3 | // Cannot assign to globals
|
||||
> 4 | someUnknownGlobal = true;
|
||||
| ^^^^^^^^^^^^^^^^^ InvalidReact: Unexpected reassignment of a variable which was defined outside of the component. Components and hooks should be pure and side-effect free, but variable reassignment is a form of side-effect. If this variable is used in rendering, use useState instead. (https://react.dev/reference/rules/components-and-hooks-must-be-pure#side-effects-must-run-outside-of-render) (4:4)
|
||||
5 | moduleLocal = true;
|
||||
6 | };
|
||||
7 | foo();
|
||||
```
|
||||
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
// @enableNewMutationAliasingModel
|
||||
function Component() {
|
||||
const foo = () => {
|
||||
// Cannot assign to globals
|
||||
|
||||
@@ -2,7 +2,6 @@
|
||||
## Input
|
||||
|
||||
```javascript
|
||||
// @enableNewMutationAliasingModel
|
||||
function Component() {
|
||||
// Cannot assign to globals
|
||||
someUnknownGlobal = true;
|
||||
@@ -15,15 +14,13 @@ function Component() {
|
||||
## Error
|
||||
|
||||
```
|
||||
2 | function Component() {
|
||||
3 | // Cannot assign to globals
|
||||
> 4 | someUnknownGlobal = true;
|
||||
| ^^^^^^^^^^^^^^^^^ InvalidReact: Unexpected reassignment of a variable which was defined outside of the component. Components and hooks should be pure and side-effect free, but variable reassignment is a form of side-effect. If this variable is used in rendering, use useState instead. (https://react.dev/reference/rules/components-and-hooks-must-be-pure#side-effects-must-run-outside-of-render) (4:4)
|
||||
|
||||
InvalidReact: Unexpected reassignment of a variable which was defined outside of the component. Components and hooks should be pure and side-effect free, but variable reassignment is a form of side-effect. If this variable is used in rendering, use useState instead. (https://react.dev/reference/rules/components-and-hooks-must-be-pure#side-effects-must-run-outside-of-render) (5:5)
|
||||
5 | moduleLocal = true;
|
||||
6 | }
|
||||
7 |
|
||||
1 | function Component() {
|
||||
2 | // Cannot assign to globals
|
||||
> 3 | someUnknownGlobal = true;
|
||||
| ^^^^^^^^^^^^^^^^^ InvalidReact: Unexpected reassignment of a variable which was defined outside of the component. Components and hooks should be pure and side-effect free, but variable reassignment is a form of side-effect. If this variable is used in rendering, use useState instead. (https://react.dev/reference/rules/components-and-hooks-must-be-pure#side-effects-must-run-outside-of-render) (3:3)
|
||||
4 | moduleLocal = true;
|
||||
5 | }
|
||||
6 |
|
||||
```
|
||||
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
// @enableNewMutationAliasingModel
|
||||
function Component() {
|
||||
// Cannot assign to globals
|
||||
someUnknownGlobal = true;
|
||||
|
||||
@@ -2,7 +2,6 @@
|
||||
## Input
|
||||
|
||||
```javascript
|
||||
// @enableNewMutationAliasingModel
|
||||
function Component(props) {
|
||||
function hasErrors() {
|
||||
let hasErrors = false;
|
||||
@@ -20,12 +19,12 @@ function Component(props) {
|
||||
## Error
|
||||
|
||||
```
|
||||
8 | return hasErrors;
|
||||
9 | }
|
||||
> 10 | return hasErrors();
|
||||
| ^^^^^^^^^ Invariant: [InferMutationAliasingEffects] Expected value kind to be initialized. <unknown> hasErrors_0$15:TFunction (10:10)
|
||||
11 | }
|
||||
12 |
|
||||
7 | return hasErrors;
|
||||
8 | }
|
||||
> 9 | return hasErrors();
|
||||
| ^^^^^^^^^ Invariant: [hoisting] Expected value for identifier to be initialized. hasErrors_0$15 (9:9)
|
||||
10 | }
|
||||
11 |
|
||||
```
|
||||
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
// @enableNewMutationAliasingModel
|
||||
function Component(props) {
|
||||
function hasErrors() {
|
||||
let hasErrors = false;
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
## Input
|
||||
|
||||
```javascript
|
||||
// @inferEffectDependencies @panicThreshold:"none" @loggerTestOnly @enableNewMutationAliasingModel
|
||||
// @inferEffectDependencies @panicThreshold:"none" @loggerTestOnly
|
||||
import {useEffect} from 'react';
|
||||
import {print} from 'shared-runtime';
|
||||
|
||||
@@ -25,7 +25,7 @@ export const FIXTURE_ENTRYPOINT = {
|
||||
## Code
|
||||
|
||||
```javascript
|
||||
// @inferEffectDependencies @panicThreshold:"none" @loggerTestOnly @enableNewMutationAliasingModel
|
||||
// @inferEffectDependencies @panicThreshold:"none" @loggerTestOnly
|
||||
import { useEffect } from "react";
|
||||
import { print } from "shared-runtime";
|
||||
|
||||
@@ -48,9 +48,9 @@ export const FIXTURE_ENTRYPOINT = {
|
||||
## Logs
|
||||
|
||||
```
|
||||
{"kind":"CompileError","fnLoc":{"start":{"line":5,"column":0,"index":171},"end":{"line":12,"column":1,"index":416},"filename":"mutate-after-useeffect-optional-chain.ts"},"detail":{"reason":"Updating a value used previously in an effect function or as an effect dependency is not allowed. Consider moving the mutation before calling useEffect()","description":null,"severity":"InvalidReact","suggestions":null,"loc":{"start":{"line":10,"column":2,"index":377},"end":{"line":10,"column":5,"index":380},"filename":"mutate-after-useeffect-optional-chain.ts","identifierName":"arr"}}}
|
||||
{"kind":"AutoDepsDecorations","fnLoc":{"start":{"line":9,"column":2,"index":336},"end":{"line":9,"column":39,"index":373},"filename":"mutate-after-useeffect-optional-chain.ts"},"decorations":[{"start":{"line":9,"column":24,"index":358},"end":{"line":9,"column":27,"index":361},"filename":"mutate-after-useeffect-optional-chain.ts","identifierName":"arr"}]}
|
||||
{"kind":"CompileSuccess","fnLoc":{"start":{"line":5,"column":0,"index":171},"end":{"line":12,"column":1,"index":416},"filename":"mutate-after-useeffect-optional-chain.ts"},"fnName":"Component","memoSlots":0,"memoBlocks":0,"memoValues":0,"prunedMemoBlocks":0,"prunedMemoValues":0}
|
||||
{"kind":"CompileError","fnLoc":{"start":{"line":5,"column":0,"index":139},"end":{"line":12,"column":1,"index":384},"filename":"mutate-after-useeffect-optional-chain.ts"},"detail":{"reason":"This mutates a variable that React considers immutable","description":null,"loc":{"start":{"line":10,"column":2,"index":345},"end":{"line":10,"column":5,"index":348},"filename":"mutate-after-useeffect-optional-chain.ts","identifierName":"arr"},"suggestions":null,"severity":"InvalidReact"}}
|
||||
{"kind":"AutoDepsDecorations","fnLoc":{"start":{"line":9,"column":2,"index":304},"end":{"line":9,"column":39,"index":341},"filename":"mutate-after-useeffect-optional-chain.ts"},"decorations":[{"start":{"line":9,"column":24,"index":326},"end":{"line":9,"column":27,"index":329},"filename":"mutate-after-useeffect-optional-chain.ts","identifierName":"arr"}]}
|
||||
{"kind":"CompileSuccess","fnLoc":{"start":{"line":5,"column":0,"index":139},"end":{"line":12,"column":1,"index":384},"filename":"mutate-after-useeffect-optional-chain.ts"},"fnName":"Component","memoSlots":0,"memoBlocks":0,"memoValues":0,"prunedMemoBlocks":0,"prunedMemoValues":0}
|
||||
```
|
||||
|
||||
### Eval output
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// @inferEffectDependencies @panicThreshold:"none" @loggerTestOnly @enableNewMutationAliasingModel
|
||||
// @inferEffectDependencies @panicThreshold:"none" @loggerTestOnly
|
||||
import {useEffect} from 'react';
|
||||
import {print} from 'shared-runtime';
|
||||
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
## Input
|
||||
|
||||
```javascript
|
||||
// @inferEffectDependencies @panicThreshold:"none" @loggerTestOnly @enableNewMutationAliasingModel
|
||||
// @inferEffectDependencies @panicThreshold:"none" @loggerTestOnly
|
||||
|
||||
import {useEffect, useRef} from 'react';
|
||||
import {print} from 'shared-runtime';
|
||||
@@ -24,7 +24,7 @@ export const FIXTURE_ENTRYPOINT = {
|
||||
## Code
|
||||
|
||||
```javascript
|
||||
// @inferEffectDependencies @panicThreshold:"none" @loggerTestOnly @enableNewMutationAliasingModel
|
||||
// @inferEffectDependencies @panicThreshold:"none" @loggerTestOnly
|
||||
|
||||
import { useEffect, useRef } from "react";
|
||||
import { print } from "shared-runtime";
|
||||
@@ -47,9 +47,9 @@ export const FIXTURE_ENTRYPOINT = {
|
||||
## Logs
|
||||
|
||||
```
|
||||
{"kind":"CompileError","fnLoc":{"start":{"line":6,"column":0,"index":180},"end":{"line":11,"column":1,"index":343},"filename":"mutate-after-useeffect-ref-access.ts"},"detail":{"reason":"Mutating component props or hook arguments is not allowed. Consider using a local variable instead","description":null,"severity":"InvalidReact","suggestions":null,"loc":{"start":{"line":9,"column":2,"index":301},"end":{"line":9,"column":16,"index":315},"filename":"mutate-after-useeffect-ref-access.ts"}}}
|
||||
{"kind":"AutoDepsDecorations","fnLoc":{"start":{"line":8,"column":2,"index":259},"end":{"line":8,"column":40,"index":297},"filename":"mutate-after-useeffect-ref-access.ts"},"decorations":[{"start":{"line":8,"column":24,"index":281},"end":{"line":8,"column":30,"index":287},"filename":"mutate-after-useeffect-ref-access.ts","identifierName":"arrRef"}]}
|
||||
{"kind":"CompileSuccess","fnLoc":{"start":{"line":6,"column":0,"index":180},"end":{"line":11,"column":1,"index":343},"filename":"mutate-after-useeffect-ref-access.ts"},"fnName":"Component","memoSlots":0,"memoBlocks":0,"memoValues":0,"prunedMemoBlocks":0,"prunedMemoValues":0}
|
||||
{"kind":"CompileError","fnLoc":{"start":{"line":6,"column":0,"index":148},"end":{"line":11,"column":1,"index":311},"filename":"mutate-after-useeffect-ref-access.ts"},"detail":{"reason":"Mutating component props or hook arguments is not allowed. Consider using a local variable instead","description":null,"loc":{"start":{"line":9,"column":2,"index":269},"end":{"line":9,"column":16,"index":283},"filename":"mutate-after-useeffect-ref-access.ts"},"suggestions":null,"severity":"InvalidReact"}}
|
||||
{"kind":"AutoDepsDecorations","fnLoc":{"start":{"line":8,"column":2,"index":227},"end":{"line":8,"column":40,"index":265},"filename":"mutate-after-useeffect-ref-access.ts"},"decorations":[{"start":{"line":8,"column":24,"index":249},"end":{"line":8,"column":30,"index":255},"filename":"mutate-after-useeffect-ref-access.ts","identifierName":"arrRef"}]}
|
||||
{"kind":"CompileSuccess","fnLoc":{"start":{"line":6,"column":0,"index":148},"end":{"line":11,"column":1,"index":311},"filename":"mutate-after-useeffect-ref-access.ts"},"fnName":"Component","memoSlots":0,"memoBlocks":0,"memoValues":0,"prunedMemoBlocks":0,"prunedMemoValues":0}
|
||||
```
|
||||
|
||||
### Eval output
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// @inferEffectDependencies @panicThreshold:"none" @loggerTestOnly @enableNewMutationAliasingModel
|
||||
// @inferEffectDependencies @panicThreshold:"none" @loggerTestOnly
|
||||
|
||||
import {useEffect, useRef} from 'react';
|
||||
import {print} from 'shared-runtime';
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
## Input
|
||||
|
||||
```javascript
|
||||
// @inferEffectDependencies @panicThreshold:"none" @loggerTestOnly @enableNewMutationAliasingModel
|
||||
// @inferEffectDependencies @panicThreshold:"none" @loggerTestOnly
|
||||
import {useEffect} from 'react';
|
||||
|
||||
function Component({foo}) {
|
||||
@@ -24,7 +24,7 @@ export const FIXTURE_ENTRYPOINT = {
|
||||
## Code
|
||||
|
||||
```javascript
|
||||
// @inferEffectDependencies @panicThreshold:"none" @loggerTestOnly @enableNewMutationAliasingModel
|
||||
// @inferEffectDependencies @panicThreshold:"none" @loggerTestOnly
|
||||
import { useEffect } from "react";
|
||||
|
||||
function Component(t0) {
|
||||
@@ -47,9 +47,9 @@ export const FIXTURE_ENTRYPOINT = {
|
||||
## Logs
|
||||
|
||||
```
|
||||
{"kind":"CompileError","fnLoc":{"start":{"line":4,"column":0,"index":133},"end":{"line":11,"column":1,"index":254},"filename":"mutate-after-useeffect.ts"},"detail":{"reason":"Updating a value used previously in an effect function or as an effect dependency is not allowed. Consider moving the mutation before calling useEffect()","description":null,"severity":"InvalidReact","suggestions":null,"loc":{"start":{"line":9,"column":2,"index":226},"end":{"line":9,"column":5,"index":229},"filename":"mutate-after-useeffect.ts","identifierName":"arr"}}}
|
||||
{"kind":"AutoDepsDecorations","fnLoc":{"start":{"line":6,"column":2,"index":181},"end":{"line":8,"column":4,"index":222},"filename":"mutate-after-useeffect.ts"},"decorations":[{"start":{"line":7,"column":4,"index":203},"end":{"line":7,"column":7,"index":206},"filename":"mutate-after-useeffect.ts","identifierName":"arr"},{"start":{"line":7,"column":4,"index":203},"end":{"line":7,"column":7,"index":206},"filename":"mutate-after-useeffect.ts","identifierName":"arr"},{"start":{"line":7,"column":13,"index":212},"end":{"line":7,"column":16,"index":215},"filename":"mutate-after-useeffect.ts","identifierName":"foo"}]}
|
||||
{"kind":"CompileSuccess","fnLoc":{"start":{"line":4,"column":0,"index":133},"end":{"line":11,"column":1,"index":254},"filename":"mutate-after-useeffect.ts"},"fnName":"Component","memoSlots":0,"memoBlocks":0,"memoValues":0,"prunedMemoBlocks":0,"prunedMemoValues":0}
|
||||
{"kind":"CompileError","fnLoc":{"start":{"line":4,"column":0,"index":101},"end":{"line":11,"column":1,"index":222},"filename":"mutate-after-useeffect.ts"},"detail":{"reason":"This mutates a variable that React considers immutable","description":null,"loc":{"start":{"line":9,"column":2,"index":194},"end":{"line":9,"column":5,"index":197},"filename":"mutate-after-useeffect.ts","identifierName":"arr"},"suggestions":null,"severity":"InvalidReact"}}
|
||||
{"kind":"AutoDepsDecorations","fnLoc":{"start":{"line":6,"column":2,"index":149},"end":{"line":8,"column":4,"index":190},"filename":"mutate-after-useeffect.ts"},"decorations":[{"start":{"line":7,"column":4,"index":171},"end":{"line":7,"column":7,"index":174},"filename":"mutate-after-useeffect.ts","identifierName":"arr"},{"start":{"line":7,"column":4,"index":171},"end":{"line":7,"column":7,"index":174},"filename":"mutate-after-useeffect.ts","identifierName":"arr"},{"start":{"line":7,"column":13,"index":180},"end":{"line":7,"column":16,"index":183},"filename":"mutate-after-useeffect.ts","identifierName":"foo"}]}
|
||||
{"kind":"CompileSuccess","fnLoc":{"start":{"line":4,"column":0,"index":101},"end":{"line":11,"column":1,"index":222},"filename":"mutate-after-useeffect.ts"},"fnName":"Component","memoSlots":0,"memoBlocks":0,"memoValues":0,"prunedMemoBlocks":0,"prunedMemoValues":0}
|
||||
```
|
||||
|
||||
### Eval output
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// @inferEffectDependencies @panicThreshold:"none" @loggerTestOnly @enableNewMutationAliasingModel
|
||||
// @inferEffectDependencies @panicThreshold:"none" @loggerTestOnly
|
||||
import {useEffect} from 'react';
|
||||
|
||||
function Component({foo}) {
|
||||
|
||||
@@ -2,7 +2,6 @@
|
||||
## Input
|
||||
|
||||
```javascript
|
||||
// @enableNewMutationAliasingModel
|
||||
import {identity, mutate} from 'shared-runtime';
|
||||
|
||||
function Component(props) {
|
||||
@@ -24,22 +23,38 @@ export const FIXTURE_ENTRYPOINT = {
|
||||
## Code
|
||||
|
||||
```javascript
|
||||
import { c as _c } from "react/compiler-runtime"; // @enableNewMutationAliasingModel
|
||||
import { c as _c } from "react/compiler-runtime";
|
||||
import { identity, mutate } from "shared-runtime";
|
||||
|
||||
function Component(props) {
|
||||
const $ = _c(2);
|
||||
let context;
|
||||
if ($[0] !== props.value) {
|
||||
const key = {};
|
||||
context = { [key]: identity([props.value]) };
|
||||
|
||||
mutate(key);
|
||||
$[0] = props.value;
|
||||
$[1] = context;
|
||||
const $ = _c(5);
|
||||
let t0;
|
||||
if ($[0] === Symbol.for("react.memo_cache_sentinel")) {
|
||||
t0 = {};
|
||||
$[0] = t0;
|
||||
} else {
|
||||
context = $[1];
|
||||
t0 = $[0];
|
||||
}
|
||||
const key = t0;
|
||||
let t1;
|
||||
if ($[1] !== props.value) {
|
||||
t1 = identity([props.value]);
|
||||
$[1] = props.value;
|
||||
$[2] = t1;
|
||||
} else {
|
||||
t1 = $[2];
|
||||
}
|
||||
let t2;
|
||||
if ($[3] !== t1) {
|
||||
t2 = { [key]: t1 };
|
||||
$[3] = t1;
|
||||
$[4] = t2;
|
||||
} else {
|
||||
t2 = $[4];
|
||||
}
|
||||
const context = t2;
|
||||
|
||||
mutate(key);
|
||||
return context;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
// @enableNewMutationAliasingModel
|
||||
import {identity, mutate} from 'shared-runtime';
|
||||
|
||||
function Component(props) {
|
||||
|
||||
@@ -2,7 +2,6 @@
|
||||
## Input
|
||||
|
||||
```javascript
|
||||
// @enableNewMutationAliasingModel
|
||||
import {identity, mutate, mutateAndReturn} from 'shared-runtime';
|
||||
|
||||
function Component(props) {
|
||||
@@ -24,26 +23,15 @@ export const FIXTURE_ENTRYPOINT = {
|
||||
## Code
|
||||
|
||||
```javascript
|
||||
import { c as _c } from "react/compiler-runtime"; // @enableNewMutationAliasingModel
|
||||
import { c as _c } from "react/compiler-runtime";
|
||||
import { identity, mutate, mutateAndReturn } from "shared-runtime";
|
||||
|
||||
function Component(props) {
|
||||
const $ = _c(4);
|
||||
const $ = _c(2);
|
||||
let context;
|
||||
if ($[0] !== props.value) {
|
||||
const key = { a: "key" };
|
||||
|
||||
const t0 = key.a;
|
||||
const t1 = identity([props.value]);
|
||||
let t2;
|
||||
if ($[2] !== t1) {
|
||||
t2 = { [t0]: t1 };
|
||||
$[2] = t1;
|
||||
$[3] = t2;
|
||||
} else {
|
||||
t2 = $[3];
|
||||
}
|
||||
context = t2;
|
||||
context = { [key.a]: identity([props.value]) };
|
||||
|
||||
mutate(key);
|
||||
$[0] = props.value;
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
// @enableNewMutationAliasingModel
|
||||
import {identity, mutate, mutateAndReturn} from 'shared-runtime';
|
||||
|
||||
function Component(props) {
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
## Input
|
||||
|
||||
```javascript
|
||||
// @inferEffectDependencies @enableNewMutationAliasingModel
|
||||
// @inferEffectDependencies
|
||||
import {useEffect, useState} from 'react';
|
||||
import {print} from 'shared-runtime';
|
||||
|
||||
@@ -26,7 +26,7 @@ function ReactiveRefInEffect(props) {
|
||||
## Code
|
||||
|
||||
```javascript
|
||||
import { c as _c } from "react/compiler-runtime"; // @inferEffectDependencies @enableNewMutationAliasingModel
|
||||
import { c as _c } from "react/compiler-runtime"; // @inferEffectDependencies
|
||||
import { useEffect, useState } from "react";
|
||||
import { print } from "shared-runtime";
|
||||
|
||||
@@ -34,28 +34,22 @@ import { print } from "shared-runtime";
|
||||
* setState types are not enough to determine to omit from deps. Must also take reactivity into account.
|
||||
*/
|
||||
function ReactiveRefInEffect(props) {
|
||||
const $ = _c(4);
|
||||
const $ = _c(2);
|
||||
const [, setState1] = useRef("initial value");
|
||||
const [, setState2] = useRef("initial value");
|
||||
let setState;
|
||||
if ($[0] !== props.foo) {
|
||||
if (props.foo) {
|
||||
setState = setState1;
|
||||
} else {
|
||||
setState = setState2;
|
||||
}
|
||||
$[0] = props.foo;
|
||||
$[1] = setState;
|
||||
if (props.foo) {
|
||||
setState = setState1;
|
||||
} else {
|
||||
setState = $[1];
|
||||
setState = setState2;
|
||||
}
|
||||
let t0;
|
||||
if ($[2] !== setState) {
|
||||
if ($[0] !== setState) {
|
||||
t0 = () => print(setState);
|
||||
$[2] = setState;
|
||||
$[3] = t0;
|
||||
$[0] = setState;
|
||||
$[1] = t0;
|
||||
} else {
|
||||
t0 = $[3];
|
||||
t0 = $[1];
|
||||
}
|
||||
useEffect(t0, [setState]);
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// @inferEffectDependencies @enableNewMutationAliasingModel
|
||||
// @inferEffectDependencies
|
||||
import {useEffect, useState} from 'react';
|
||||
import {print} from 'shared-runtime';
|
||||
|
||||
|
||||
@@ -1,54 +0,0 @@
|
||||
|
||||
## Input
|
||||
|
||||
```javascript
|
||||
// @flow @enableNewMutationAliasingModel
|
||||
|
||||
import fbt from 'fbt';
|
||||
|
||||
component Component() {
|
||||
const sections = Object.keys(items);
|
||||
|
||||
for (let i = 0; i < sections.length; i += 3) {
|
||||
chunks.push(
|
||||
sections.slice(i, i + 3).map(section => {
|
||||
return <Child />;
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
return <Child />;
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
## Code
|
||||
|
||||
```javascript
|
||||
import { c as _c } from "react/compiler-runtime";
|
||||
|
||||
import fbt from "fbt";
|
||||
|
||||
function Component() {
|
||||
const $ = _c(1);
|
||||
const sections = Object.keys(items);
|
||||
for (let i = 0; i < sections.length; i = i + 3, i) {
|
||||
chunks.push(sections.slice(i, i + 3).map(_temp));
|
||||
}
|
||||
let t0;
|
||||
if ($[0] === Symbol.for("react.memo_cache_sentinel")) {
|
||||
t0 = <Child />;
|
||||
$[0] = t0;
|
||||
} else {
|
||||
t0 = $[0];
|
||||
}
|
||||
return t0;
|
||||
}
|
||||
function _temp(section) {
|
||||
return <Child />;
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
### Eval output
|
||||
(kind: exception) Fixture not implemented
|
||||
@@ -1,17 +0,0 @@
|
||||
// @flow @enableNewMutationAliasingModel
|
||||
|
||||
import fbt from 'fbt';
|
||||
|
||||
component Component() {
|
||||
const sections = Object.keys(items);
|
||||
|
||||
for (let i = 0; i < sections.length; i += 3) {
|
||||
chunks.push(
|
||||
sections.slice(i, i + 3).map(section => {
|
||||
return <Child />;
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
return <Child />;
|
||||
}
|
||||
@@ -1,80 +0,0 @@
|
||||
|
||||
## Input
|
||||
|
||||
```javascript
|
||||
//@flow @validatePreserveExistingMemoizationGuarantees @enableNewMutationAliasingModel
|
||||
component Component(
|
||||
onAsyncSubmit?: (() => void) => void,
|
||||
onClose: (isConfirmed: boolean) => void
|
||||
) {
|
||||
// When running inferReactiveScopeVariables,
|
||||
// onAsyncSubmit and onClose update to share
|
||||
// a mutableRange instance.
|
||||
const onSubmit = useCallback(() => {
|
||||
if (onAsyncSubmit) {
|
||||
onAsyncSubmit(() => {
|
||||
onClose(true);
|
||||
});
|
||||
return;
|
||||
}
|
||||
}, [onAsyncSubmit, onClose]);
|
||||
// When running inferReactiveScopeVariables here,
|
||||
// first the existing range gets updated (affecting
|
||||
// onAsyncSubmit) and then onClose gets assigned a
|
||||
// different mutable range instance, which is the
|
||||
// one reset after AnalyzeFunctions.
|
||||
// The fix is to fully reset mutable ranges *instances*
|
||||
// after AnalyzeFunctions visit a function expression
|
||||
return <Dialog onSubmit={onSubmit} onClose={() => onClose(false)} />;
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
## Code
|
||||
|
||||
```javascript
|
||||
import { c as _c } from "react/compiler-runtime";
|
||||
function Component(t0) {
|
||||
const $ = _c(8);
|
||||
const { onAsyncSubmit, onClose } = t0;
|
||||
let t1;
|
||||
if ($[0] !== onAsyncSubmit || $[1] !== onClose) {
|
||||
t1 = () => {
|
||||
if (onAsyncSubmit) {
|
||||
onAsyncSubmit(() => {
|
||||
onClose(true);
|
||||
});
|
||||
return;
|
||||
}
|
||||
};
|
||||
$[0] = onAsyncSubmit;
|
||||
$[1] = onClose;
|
||||
$[2] = t1;
|
||||
} else {
|
||||
t1 = $[2];
|
||||
}
|
||||
const onSubmit = t1;
|
||||
let t2;
|
||||
if ($[3] !== onClose) {
|
||||
t2 = () => onClose(false);
|
||||
$[3] = onClose;
|
||||
$[4] = t2;
|
||||
} else {
|
||||
t2 = $[4];
|
||||
}
|
||||
let t3;
|
||||
if ($[5] !== onSubmit || $[6] !== t2) {
|
||||
t3 = <Dialog onSubmit={onSubmit} onClose={t2} />;
|
||||
$[5] = onSubmit;
|
||||
$[6] = t2;
|
||||
$[7] = t3;
|
||||
} else {
|
||||
t3 = $[7];
|
||||
}
|
||||
return t3;
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
### Eval output
|
||||
(kind: exception) Fixture not implemented
|
||||
@@ -1,25 +0,0 @@
|
||||
//@flow @validatePreserveExistingMemoizationGuarantees @enableNewMutationAliasingModel
|
||||
component Component(
|
||||
onAsyncSubmit?: (() => void) => void,
|
||||
onClose: (isConfirmed: boolean) => void
|
||||
) {
|
||||
// When running inferReactiveScopeVariables,
|
||||
// onAsyncSubmit and onClose update to share
|
||||
// a mutableRange instance.
|
||||
const onSubmit = useCallback(() => {
|
||||
if (onAsyncSubmit) {
|
||||
onAsyncSubmit(() => {
|
||||
onClose(true);
|
||||
});
|
||||
return;
|
||||
}
|
||||
}, [onAsyncSubmit, onClose]);
|
||||
// When running inferReactiveScopeVariables here,
|
||||
// first the existing range gets updated (affecting
|
||||
// onAsyncSubmit) and then onClose gets assigned a
|
||||
// different mutable range instance, which is the
|
||||
// one reset after AnalyzeFunctions.
|
||||
// The fix is to fully reset mutable ranges *instances*
|
||||
// after AnalyzeFunctions visit a function expression
|
||||
return <Dialog onSubmit={onSubmit} onClose={() => onClose(false)} />;
|
||||
}
|
||||
@@ -1,53 +0,0 @@
|
||||
|
||||
## Input
|
||||
|
||||
```javascript
|
||||
// @flow @enableNewMutationAliasingModel
|
||||
|
||||
import {identity, Stringify, useFragment} from 'shared-runtime';
|
||||
|
||||
component Example() {
|
||||
const data = useFragment();
|
||||
|
||||
const {a, b} = identity(data);
|
||||
|
||||
const el = <Stringify tooltip={b} />;
|
||||
|
||||
identity(a.at(0));
|
||||
|
||||
return <Stringify icon={el} />;
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
## Code
|
||||
|
||||
```javascript
|
||||
import { c as _c } from "react/compiler-runtime";
|
||||
|
||||
import { identity, Stringify, useFragment } from "shared-runtime";
|
||||
|
||||
function Example() {
|
||||
const $ = _c(2);
|
||||
const data = useFragment();
|
||||
let t0;
|
||||
if ($[0] !== data) {
|
||||
const { a, b } = identity(data);
|
||||
|
||||
const el = <Stringify tooltip={b} />;
|
||||
|
||||
identity(a.at(0));
|
||||
|
||||
t0 = <Stringify icon={el} />;
|
||||
$[0] = data;
|
||||
$[1] = t0;
|
||||
} else {
|
||||
t0 = $[1];
|
||||
}
|
||||
return t0;
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
### Eval output
|
||||
(kind: exception) Fixture not implemented
|
||||
@@ -1,15 +0,0 @@
|
||||
// @flow @enableNewMutationAliasingModel
|
||||
|
||||
import {identity, Stringify, useFragment} from 'shared-runtime';
|
||||
|
||||
component Example() {
|
||||
const data = useFragment();
|
||||
|
||||
const {a, b} = identity(data);
|
||||
|
||||
const el = <Stringify tooltip={b} />;
|
||||
|
||||
identity(a.at(0));
|
||||
|
||||
return <Stringify icon={el} />;
|
||||
}
|
||||
@@ -2,7 +2,7 @@
|
||||
## Input
|
||||
|
||||
```javascript
|
||||
// @inferEffectDependencies @noEmit @panicThreshold:"none" @loggerTestOnly @enableNewMutationAliasingModel
|
||||
// @inferEffectDependencies @noEmit @panicThreshold:"none" @loggerTestOnly
|
||||
import {print} from 'shared-runtime';
|
||||
import useEffectWrapper from 'useEffectWrapper';
|
||||
|
||||
@@ -27,7 +27,7 @@ export const FIXTURE_ENTRYPOINT = {
|
||||
## Code
|
||||
|
||||
```javascript
|
||||
// @inferEffectDependencies @noEmit @panicThreshold:"none" @loggerTestOnly @enableNewMutationAliasingModel
|
||||
// @inferEffectDependencies @noEmit @panicThreshold:"none" @loggerTestOnly
|
||||
import { print } from "shared-runtime";
|
||||
import useEffectWrapper from "useEffectWrapper";
|
||||
|
||||
@@ -52,10 +52,10 @@ export const FIXTURE_ENTRYPOINT = {
|
||||
## Logs
|
||||
|
||||
```
|
||||
{"kind":"CompileError","fnLoc":{"start":{"line":5,"column":0,"index":195},"end":{"line":13,"column":1,"index":389},"filename":"retry-no-emit.ts"},"detail":{"reason":"Updating a value previously passed as an argument to a hook is not allowed. Consider moving the mutation before calling the hook","description":null,"severity":"InvalidReact","suggestions":null,"loc":{"start":{"line":11,"column":2,"index":352},"end":{"line":11,"column":6,"index":356},"filename":"retry-no-emit.ts","identifierName":"arr2"}}}
|
||||
{"kind":"AutoDepsDecorations","fnLoc":{"start":{"line":7,"column":2,"index":248},"end":{"line":7,"column":36,"index":282},"filename":"retry-no-emit.ts"},"decorations":[{"start":{"line":7,"column":31,"index":277},"end":{"line":7,"column":34,"index":280},"filename":"retry-no-emit.ts","identifierName":"arr"}]}
|
||||
{"kind":"AutoDepsDecorations","fnLoc":{"start":{"line":10,"column":2,"index":306},"end":{"line":10,"column":44,"index":348},"filename":"retry-no-emit.ts"},"decorations":[{"start":{"line":10,"column":25,"index":329},"end":{"line":10,"column":29,"index":333},"filename":"retry-no-emit.ts","identifierName":"arr2"},{"start":{"line":10,"column":25,"index":329},"end":{"line":10,"column":29,"index":333},"filename":"retry-no-emit.ts","identifierName":"arr2"},{"start":{"line":10,"column":35,"index":339},"end":{"line":10,"column":42,"index":346},"filename":"retry-no-emit.ts","identifierName":"propVal"}]}
|
||||
{"kind":"CompileSuccess","fnLoc":{"start":{"line":5,"column":0,"index":195},"end":{"line":13,"column":1,"index":389},"filename":"retry-no-emit.ts"},"fnName":"Foo","memoSlots":0,"memoBlocks":0,"memoValues":0,"prunedMemoBlocks":0,"prunedMemoValues":0}
|
||||
{"kind":"CompileError","fnLoc":{"start":{"line":5,"column":0,"index":163},"end":{"line":13,"column":1,"index":357},"filename":"retry-no-emit.ts"},"detail":{"reason":"This mutates a variable that React considers immutable","description":null,"loc":{"start":{"line":11,"column":2,"index":320},"end":{"line":11,"column":6,"index":324},"filename":"retry-no-emit.ts","identifierName":"arr2"},"suggestions":null,"severity":"InvalidReact"}}
|
||||
{"kind":"AutoDepsDecorations","fnLoc":{"start":{"line":7,"column":2,"index":216},"end":{"line":7,"column":36,"index":250},"filename":"retry-no-emit.ts"},"decorations":[{"start":{"line":7,"column":31,"index":245},"end":{"line":7,"column":34,"index":248},"filename":"retry-no-emit.ts","identifierName":"arr"}]}
|
||||
{"kind":"AutoDepsDecorations","fnLoc":{"start":{"line":10,"column":2,"index":274},"end":{"line":10,"column":44,"index":316},"filename":"retry-no-emit.ts"},"decorations":[{"start":{"line":10,"column":25,"index":297},"end":{"line":10,"column":29,"index":301},"filename":"retry-no-emit.ts","identifierName":"arr2"},{"start":{"line":10,"column":25,"index":297},"end":{"line":10,"column":29,"index":301},"filename":"retry-no-emit.ts","identifierName":"arr2"},{"start":{"line":10,"column":35,"index":307},"end":{"line":10,"column":42,"index":314},"filename":"retry-no-emit.ts","identifierName":"propVal"}]}
|
||||
{"kind":"CompileSuccess","fnLoc":{"start":{"line":5,"column":0,"index":163},"end":{"line":13,"column":1,"index":357},"filename":"retry-no-emit.ts"},"fnName":"Foo","memoSlots":0,"memoBlocks":0,"memoValues":0,"prunedMemoBlocks":0,"prunedMemoValues":0}
|
||||
```
|
||||
|
||||
### Eval output
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// @inferEffectDependencies @noEmit @panicThreshold:"none" @loggerTestOnly @enableNewMutationAliasingModel
|
||||
// @inferEffectDependencies @noEmit @panicThreshold:"none" @loggerTestOnly
|
||||
import {print} from 'shared-runtime';
|
||||
import useEffectWrapper from 'useEffectWrapper';
|
||||
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
## Input
|
||||
|
||||
```javascript
|
||||
// @enableFire @enableNewMutationAliasingModel
|
||||
// @enableFire
|
||||
import {fire} from 'react';
|
||||
|
||||
function Component({bar, baz}) {
|
||||
@@ -26,7 +26,7 @@ function Component({bar, baz}) {
|
||||
## Code
|
||||
|
||||
```javascript
|
||||
import { c as _c, useFire } from "react/compiler-runtime"; // @enableFire @enableNewMutationAliasingModel
|
||||
import { c as _c, useFire } from "react/compiler-runtime"; // @enableFire
|
||||
import { fire } from "react";
|
||||
|
||||
function Component(t0) {
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// @enableFire @enableNewMutationAliasingModel
|
||||
// @enableFire
|
||||
import {fire} from 'react';
|
||||
|
||||
function Component({bar, baz}) {
|
||||
|
||||
@@ -2,7 +2,6 @@
|
||||
## Input
|
||||
|
||||
```javascript
|
||||
// @enableNewMutationAliasingModel
|
||||
import {useCallback} from 'react';
|
||||
import {Stringify} from 'shared-runtime';
|
||||
|
||||
@@ -36,51 +35,44 @@ export const FIXTURE_ENTRYPOINT = {
|
||||
## Code
|
||||
|
||||
```javascript
|
||||
import { c as _c } from "react/compiler-runtime"; // @enableNewMutationAliasingModel
|
||||
import { c as _c } from "react/compiler-runtime";
|
||||
import { useCallback } from "react";
|
||||
import { Stringify } from "shared-runtime";
|
||||
|
||||
function Foo(t0) {
|
||||
const $ = _c(10);
|
||||
const $ = _c(8);
|
||||
const { arr1, arr2, foo } = t0;
|
||||
let t1;
|
||||
if ($[0] !== arr1) {
|
||||
t1 = [arr1];
|
||||
$[0] = arr1;
|
||||
$[1] = t1;
|
||||
} else {
|
||||
t1 = $[1];
|
||||
}
|
||||
const x = t1;
|
||||
let getVal1;
|
||||
let t2;
|
||||
if ($[2] !== arr2 || $[3] !== foo || $[4] !== x) {
|
||||
let t1;
|
||||
if ($[0] !== arr1 || $[1] !== arr2 || $[2] !== foo) {
|
||||
const x = [arr1];
|
||||
|
||||
let y = [];
|
||||
|
||||
getVal1 = _temp;
|
||||
|
||||
t2 = () => [y];
|
||||
t1 = () => [y];
|
||||
foo ? (y = x.concat(arr2)) : y;
|
||||
$[2] = arr2;
|
||||
$[3] = foo;
|
||||
$[4] = x;
|
||||
$[0] = arr1;
|
||||
$[1] = arr2;
|
||||
$[2] = foo;
|
||||
$[3] = getVal1;
|
||||
$[4] = t1;
|
||||
} else {
|
||||
getVal1 = $[3];
|
||||
t1 = $[4];
|
||||
}
|
||||
const getVal2 = t1;
|
||||
let t2;
|
||||
if ($[5] !== getVal1 || $[6] !== getVal2) {
|
||||
t2 = <Stringify val1={getVal1} val2={getVal2} shouldInvokeFns={true} />;
|
||||
$[5] = getVal1;
|
||||
$[6] = t2;
|
||||
$[6] = getVal2;
|
||||
$[7] = t2;
|
||||
} else {
|
||||
getVal1 = $[5];
|
||||
t2 = $[6];
|
||||
t2 = $[7];
|
||||
}
|
||||
const getVal2 = t2;
|
||||
let t3;
|
||||
if ($[7] !== getVal1 || $[8] !== getVal2) {
|
||||
t3 = <Stringify val1={getVal1} val2={getVal2} shouldInvokeFns={true} />;
|
||||
$[7] = getVal1;
|
||||
$[8] = getVal2;
|
||||
$[9] = t3;
|
||||
} else {
|
||||
t3 = $[9];
|
||||
}
|
||||
return t3;
|
||||
return t2;
|
||||
}
|
||||
function _temp() {
|
||||
return { x: 2 };
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
// @enableNewMutationAliasingModel
|
||||
import {useCallback} from 'react';
|
||||
import {Stringify} from 'shared-runtime';
|
||||
|
||||
|
||||
@@ -2,7 +2,6 @@
|
||||
## Input
|
||||
|
||||
```javascript
|
||||
// @enableNewMutationAliasingModel
|
||||
import {useCallback} from 'react';
|
||||
import {Stringify} from 'shared-runtime';
|
||||
|
||||
@@ -31,44 +30,37 @@ export const FIXTURE_ENTRYPOINT = {
|
||||
## Code
|
||||
|
||||
```javascript
|
||||
import { c as _c } from "react/compiler-runtime"; // @enableNewMutationAliasingModel
|
||||
import { c as _c } from "react/compiler-runtime";
|
||||
import { useCallback } from "react";
|
||||
import { Stringify } from "shared-runtime";
|
||||
|
||||
// We currently produce invalid output (incorrect scoping for `y` declaration)
|
||||
function useFoo(arr1, arr2) {
|
||||
const $ = _c(7);
|
||||
const $ = _c(5);
|
||||
let t0;
|
||||
if ($[0] !== arr1) {
|
||||
t0 = [arr1];
|
||||
$[0] = arr1;
|
||||
$[1] = t0;
|
||||
} else {
|
||||
t0 = $[1];
|
||||
}
|
||||
const x = t0;
|
||||
let t1;
|
||||
if ($[2] !== arr2 || $[3] !== x) {
|
||||
if ($[0] !== arr1 || $[1] !== arr2) {
|
||||
const x = [arr1];
|
||||
|
||||
let y;
|
||||
t1 = () => ({ y });
|
||||
t0 = () => ({ y });
|
||||
|
||||
(y = x.concat(arr2)), y;
|
||||
$[2] = arr2;
|
||||
$[3] = x;
|
||||
$[0] = arr1;
|
||||
$[1] = arr2;
|
||||
$[2] = t0;
|
||||
} else {
|
||||
t0 = $[2];
|
||||
}
|
||||
const getVal = t0;
|
||||
let t1;
|
||||
if ($[3] !== getVal) {
|
||||
t1 = <Stringify getVal={getVal} shouldInvokeFns={true} />;
|
||||
$[3] = getVal;
|
||||
$[4] = t1;
|
||||
} else {
|
||||
t1 = $[4];
|
||||
}
|
||||
const getVal = t1;
|
||||
let t2;
|
||||
if ($[5] !== getVal) {
|
||||
t2 = <Stringify getVal={getVal} shouldInvokeFns={true} />;
|
||||
$[5] = getVal;
|
||||
$[6] = t2;
|
||||
} else {
|
||||
t2 = $[6];
|
||||
}
|
||||
return t2;
|
||||
return t1;
|
||||
}
|
||||
|
||||
export const FIXTURE_ENTRYPOINT = {
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
// @enableNewMutationAliasingModel
|
||||
import {useCallback} from 'react';
|
||||
import {Stringify} from 'shared-runtime';
|
||||
|
||||
|
||||
@@ -2,7 +2,6 @@
|
||||
## Input
|
||||
|
||||
```javascript
|
||||
// @enableNewMutationAliasingModel
|
||||
import {useMemo} from 'react';
|
||||
|
||||
function useFoo(arr1, arr2) {
|
||||
@@ -27,40 +26,33 @@ export const FIXTURE_ENTRYPOINT = {
|
||||
## Code
|
||||
|
||||
```javascript
|
||||
import { c as _c } from "react/compiler-runtime"; // @enableNewMutationAliasingModel
|
||||
import { c as _c } from "react/compiler-runtime";
|
||||
import { useMemo } from "react";
|
||||
|
||||
function useFoo(arr1, arr2) {
|
||||
const $ = _c(7);
|
||||
let t0;
|
||||
if ($[0] !== arr1) {
|
||||
t0 = [arr1];
|
||||
$[0] = arr1;
|
||||
$[1] = t0;
|
||||
} else {
|
||||
t0 = $[1];
|
||||
}
|
||||
const x = t0;
|
||||
const $ = _c(5);
|
||||
let y;
|
||||
if ($[2] !== arr2 || $[3] !== x) {
|
||||
if ($[0] !== arr1 || $[1] !== arr2) {
|
||||
const x = [arr1];
|
||||
|
||||
(y = x.concat(arr2)), y;
|
||||
$[2] = arr2;
|
||||
$[3] = x;
|
||||
$[4] = y;
|
||||
$[0] = arr1;
|
||||
$[1] = arr2;
|
||||
$[2] = y;
|
||||
} else {
|
||||
y = $[4];
|
||||
y = $[2];
|
||||
}
|
||||
let t0;
|
||||
let t1;
|
||||
let t2;
|
||||
if ($[5] !== y) {
|
||||
t2 = { y };
|
||||
$[5] = y;
|
||||
$[6] = t2;
|
||||
if ($[3] !== y) {
|
||||
t1 = { y };
|
||||
$[3] = y;
|
||||
$[4] = t1;
|
||||
} else {
|
||||
t2 = $[6];
|
||||
t1 = $[4];
|
||||
}
|
||||
t1 = t2;
|
||||
return t1;
|
||||
t0 = t1;
|
||||
return t0;
|
||||
}
|
||||
|
||||
export const FIXTURE_ENTRYPOINT = {
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
// @enableNewMutationAliasingModel
|
||||
import {useMemo} from 'react';
|
||||
|
||||
function useFoo(arr1, arr2) {
|
||||
|
||||
@@ -27,18 +27,34 @@ import { c as _c } from "react/compiler-runtime";
|
||||
import { identity, mutate } from "shared-runtime";
|
||||
|
||||
function Component(props) {
|
||||
const $ = _c(2);
|
||||
let context;
|
||||
if ($[0] !== props.value) {
|
||||
const key = {};
|
||||
context = { [key]: identity([props.value]) };
|
||||
|
||||
mutate(key);
|
||||
$[0] = props.value;
|
||||
$[1] = context;
|
||||
const $ = _c(5);
|
||||
let t0;
|
||||
if ($[0] === Symbol.for("react.memo_cache_sentinel")) {
|
||||
t0 = {};
|
||||
$[0] = t0;
|
||||
} else {
|
||||
context = $[1];
|
||||
t0 = $[0];
|
||||
}
|
||||
const key = t0;
|
||||
let t1;
|
||||
if ($[1] !== props.value) {
|
||||
t1 = identity([props.value]);
|
||||
$[1] = props.value;
|
||||
$[2] = t1;
|
||||
} else {
|
||||
t1 = $[2];
|
||||
}
|
||||
let t2;
|
||||
if ($[3] !== t1) {
|
||||
t2 = { [key]: t1 };
|
||||
$[3] = t1;
|
||||
$[4] = t2;
|
||||
} else {
|
||||
t2 = $[4];
|
||||
}
|
||||
const context = t2;
|
||||
|
||||
mutate(key);
|
||||
return context;
|
||||
}
|
||||
|
||||
|
||||
@@ -27,22 +27,11 @@ import { c as _c } from "react/compiler-runtime";
|
||||
import { identity, mutate, mutateAndReturn } from "shared-runtime";
|
||||
|
||||
function Component(props) {
|
||||
const $ = _c(4);
|
||||
const $ = _c(2);
|
||||
let context;
|
||||
if ($[0] !== props.value) {
|
||||
const key = { a: "key" };
|
||||
|
||||
const t0 = key.a;
|
||||
const t1 = identity([props.value]);
|
||||
let t2;
|
||||
if ($[2] !== t1) {
|
||||
t2 = { [t0]: t1 };
|
||||
$[2] = t1;
|
||||
$[3] = t2;
|
||||
} else {
|
||||
t2 = $[3];
|
||||
}
|
||||
context = t2;
|
||||
context = { [key.a]: identity([props.value]) };
|
||||
|
||||
mutate(key);
|
||||
$[0] = props.value;
|
||||
|
||||
@@ -40,46 +40,39 @@ import { useCallback } from "react";
|
||||
import { Stringify } from "shared-runtime";
|
||||
|
||||
function Foo(t0) {
|
||||
const $ = _c(10);
|
||||
const $ = _c(8);
|
||||
const { arr1, arr2, foo } = t0;
|
||||
let t1;
|
||||
if ($[0] !== arr1) {
|
||||
t1 = [arr1];
|
||||
$[0] = arr1;
|
||||
$[1] = t1;
|
||||
} else {
|
||||
t1 = $[1];
|
||||
}
|
||||
const x = t1;
|
||||
let getVal1;
|
||||
let t2;
|
||||
if ($[2] !== arr2 || $[3] !== foo || $[4] !== x) {
|
||||
let t1;
|
||||
if ($[0] !== arr1 || $[1] !== arr2 || $[2] !== foo) {
|
||||
const x = [arr1];
|
||||
|
||||
let y = [];
|
||||
|
||||
getVal1 = _temp;
|
||||
|
||||
t2 = () => [y];
|
||||
t1 = () => [y];
|
||||
foo ? (y = x.concat(arr2)) : y;
|
||||
$[2] = arr2;
|
||||
$[3] = foo;
|
||||
$[4] = x;
|
||||
$[0] = arr1;
|
||||
$[1] = arr2;
|
||||
$[2] = foo;
|
||||
$[3] = getVal1;
|
||||
$[4] = t1;
|
||||
} else {
|
||||
getVal1 = $[3];
|
||||
t1 = $[4];
|
||||
}
|
||||
const getVal2 = t1;
|
||||
let t2;
|
||||
if ($[5] !== getVal1 || $[6] !== getVal2) {
|
||||
t2 = <Stringify val1={getVal1} val2={getVal2} shouldInvokeFns={true} />;
|
||||
$[5] = getVal1;
|
||||
$[6] = t2;
|
||||
$[6] = getVal2;
|
||||
$[7] = t2;
|
||||
} else {
|
||||
getVal1 = $[5];
|
||||
t2 = $[6];
|
||||
t2 = $[7];
|
||||
}
|
||||
const getVal2 = t2;
|
||||
let t3;
|
||||
if ($[7] !== getVal1 || $[8] !== getVal2) {
|
||||
t3 = <Stringify val1={getVal1} val2={getVal2} shouldInvokeFns={true} />;
|
||||
$[7] = getVal1;
|
||||
$[8] = getVal2;
|
||||
$[9] = t3;
|
||||
} else {
|
||||
t3 = $[9];
|
||||
}
|
||||
return t3;
|
||||
return t2;
|
||||
}
|
||||
function _temp() {
|
||||
return { x: 2 };
|
||||
|
||||
@@ -36,38 +36,31 @@ import { Stringify } from "shared-runtime";
|
||||
|
||||
// We currently produce invalid output (incorrect scoping for `y` declaration)
|
||||
function useFoo(arr1, arr2) {
|
||||
const $ = _c(7);
|
||||
const $ = _c(5);
|
||||
let t0;
|
||||
if ($[0] !== arr1) {
|
||||
t0 = [arr1];
|
||||
$[0] = arr1;
|
||||
$[1] = t0;
|
||||
} else {
|
||||
t0 = $[1];
|
||||
}
|
||||
const x = t0;
|
||||
let t1;
|
||||
if ($[2] !== arr2 || $[3] !== x) {
|
||||
if ($[0] !== arr1 || $[1] !== arr2) {
|
||||
const x = [arr1];
|
||||
|
||||
let y;
|
||||
t1 = () => ({ y });
|
||||
t0 = () => ({ y });
|
||||
|
||||
(y = x.concat(arr2)), y;
|
||||
$[2] = arr2;
|
||||
$[3] = x;
|
||||
$[0] = arr1;
|
||||
$[1] = arr2;
|
||||
$[2] = t0;
|
||||
} else {
|
||||
t0 = $[2];
|
||||
}
|
||||
const getVal = t0;
|
||||
let t1;
|
||||
if ($[3] !== getVal) {
|
||||
t1 = <Stringify getVal={getVal} shouldInvokeFns={true} />;
|
||||
$[3] = getVal;
|
||||
$[4] = t1;
|
||||
} else {
|
||||
t1 = $[4];
|
||||
}
|
||||
const getVal = t1;
|
||||
let t2;
|
||||
if ($[5] !== getVal) {
|
||||
t2 = <Stringify getVal={getVal} shouldInvokeFns={true} />;
|
||||
$[5] = getVal;
|
||||
$[6] = t2;
|
||||
} else {
|
||||
t2 = $[6];
|
||||
}
|
||||
return t2;
|
||||
return t1;
|
||||
}
|
||||
|
||||
export const FIXTURE_ENTRYPOINT = {
|
||||
|
||||
@@ -30,36 +30,29 @@ import { c as _c } from "react/compiler-runtime";
|
||||
import { useMemo } from "react";
|
||||
|
||||
function useFoo(arr1, arr2) {
|
||||
const $ = _c(7);
|
||||
let t0;
|
||||
if ($[0] !== arr1) {
|
||||
t0 = [arr1];
|
||||
$[0] = arr1;
|
||||
$[1] = t0;
|
||||
} else {
|
||||
t0 = $[1];
|
||||
}
|
||||
const x = t0;
|
||||
const $ = _c(5);
|
||||
let y;
|
||||
if ($[2] !== arr2 || $[3] !== x) {
|
||||
if ($[0] !== arr1 || $[1] !== arr2) {
|
||||
const x = [arr1];
|
||||
|
||||
(y = x.concat(arr2)), y;
|
||||
$[2] = arr2;
|
||||
$[3] = x;
|
||||
$[4] = y;
|
||||
$[0] = arr1;
|
||||
$[1] = arr2;
|
||||
$[2] = y;
|
||||
} else {
|
||||
y = $[4];
|
||||
y = $[2];
|
||||
}
|
||||
let t0;
|
||||
let t1;
|
||||
let t2;
|
||||
if ($[5] !== y) {
|
||||
t2 = { y };
|
||||
$[5] = y;
|
||||
$[6] = t2;
|
||||
if ($[3] !== y) {
|
||||
t1 = { y };
|
||||
$[3] = y;
|
||||
$[4] = t1;
|
||||
} else {
|
||||
t2 = $[6];
|
||||
t1 = $[4];
|
||||
}
|
||||
t1 = t2;
|
||||
return t1;
|
||||
t0 = t1;
|
||||
return t0;
|
||||
}
|
||||
|
||||
export const FIXTURE_ENTRYPOINT = {
|
||||
|
||||
Reference in New Issue
Block a user