mirror of
https://github.com/zebrajr/react.git
synced 2025-12-06 00:20:04 +01:00
[compiler][be] Refactor similar CallExpression and MethodCall effect handling (#32696)
Simplify InferReferenceEffect function signature matching logic for next PRs in stack --- [//]: # (BEGIN SAPLING FOOTER) Stack created with [Sapling](https://sapling-scm.com). Best reviewed with [ReviewStack](https://reviewstack.dev/facebook/react/pull/32696). * #32698 * #32697 * __->__ #32696 * #32695
This commit is contained in:
parent
febc09b480
commit
45463ab3ac
|
|
@ -23,6 +23,7 @@ import {
|
|||
Phi,
|
||||
Place,
|
||||
SpreadPattern,
|
||||
TInstruction,
|
||||
Type,
|
||||
ValueKind,
|
||||
ValueReason,
|
||||
|
|
@ -1238,62 +1239,12 @@ function inferBlock(
|
|||
break;
|
||||
}
|
||||
case 'CallExpression': {
|
||||
const signature = getFunctionCallSignature(
|
||||
env,
|
||||
instrValue.callee.identifier.type,
|
||||
inferCallEffects(
|
||||
state,
|
||||
instr as TInstruction<CallExpression>,
|
||||
freezeActions,
|
||||
getFunctionCallSignature(env, instrValue.callee.identifier.type),
|
||||
);
|
||||
|
||||
const effects =
|
||||
signature !== null ? getFunctionEffects(instrValue, signature) : null;
|
||||
const returnValueKind: AbstractValue =
|
||||
signature !== null
|
||||
? {
|
||||
kind: signature.returnValueKind,
|
||||
reason: new Set([
|
||||
signature.returnValueReason ??
|
||||
ValueReason.KnownReturnSignature,
|
||||
]),
|
||||
context: new Set(),
|
||||
}
|
||||
: {
|
||||
kind: ValueKind.Mutable,
|
||||
reason: new Set([ValueReason.Other]),
|
||||
context: new Set(),
|
||||
};
|
||||
let hasCaptureArgument = false;
|
||||
for (let i = 0; i < instrValue.args.length; i++) {
|
||||
const arg = instrValue.args[i];
|
||||
const place = arg.kind === 'Identifier' ? arg : arg.place;
|
||||
state.referenceAndRecordEffects(
|
||||
freezeActions,
|
||||
place,
|
||||
getArgumentEffect(effects != null ? effects[i] : null, arg),
|
||||
ValueReason.Other,
|
||||
);
|
||||
hasCaptureArgument ||= place.effect === Effect.Capture;
|
||||
}
|
||||
if (signature !== null) {
|
||||
state.referenceAndRecordEffects(
|
||||
freezeActions,
|
||||
instrValue.callee,
|
||||
signature.calleeEffect,
|
||||
ValueReason.Other,
|
||||
);
|
||||
} else {
|
||||
state.referenceAndRecordEffects(
|
||||
freezeActions,
|
||||
instrValue.callee,
|
||||
Effect.ConditionallyMutate,
|
||||
ValueReason.Other,
|
||||
);
|
||||
}
|
||||
hasCaptureArgument ||= instrValue.callee.effect === Effect.Capture;
|
||||
|
||||
state.initialize(instrValue, returnValueKind);
|
||||
state.define(instr.lvalue, instrValue);
|
||||
instr.lvalue.effect = hasCaptureArgument
|
||||
? Effect.Store
|
||||
: Effect.ConditionallyMutate;
|
||||
continuation = {kind: 'funeffects'};
|
||||
break;
|
||||
}
|
||||
|
|
@ -1311,102 +1262,12 @@ function inferBlock(
|
|||
Effect.Read,
|
||||
ValueReason.Other,
|
||||
);
|
||||
|
||||
const signature = getFunctionCallSignature(
|
||||
env,
|
||||
instrValue.property.identifier.type,
|
||||
inferCallEffects(
|
||||
state,
|
||||
instr as TInstruction<MethodCall>,
|
||||
freezeActions,
|
||||
getFunctionCallSignature(env, instrValue.property.identifier.type),
|
||||
);
|
||||
|
||||
const returnValueKind: AbstractValue =
|
||||
signature !== null
|
||||
? {
|
||||
kind: signature.returnValueKind,
|
||||
reason: new Set([
|
||||
signature.returnValueReason ??
|
||||
ValueReason.KnownReturnSignature,
|
||||
]),
|
||||
context: new Set(),
|
||||
}
|
||||
: {
|
||||
kind: ValueKind.Mutable,
|
||||
reason: new Set([ValueReason.Other]),
|
||||
context: new Set(),
|
||||
};
|
||||
|
||||
if (
|
||||
signature !== null &&
|
||||
signature.mutableOnlyIfOperandsAreMutable &&
|
||||
areArgumentsImmutableAndNonMutating(state, instrValue.args)
|
||||
) {
|
||||
/*
|
||||
* None of the args are mutable or mutate their params, we can downgrade to
|
||||
* treating as all reads (except that the receiver may be captured)
|
||||
*/
|
||||
for (const arg of instrValue.args) {
|
||||
const place = arg.kind === 'Identifier' ? arg : arg.place;
|
||||
state.referenceAndRecordEffects(
|
||||
freezeActions,
|
||||
place,
|
||||
Effect.Read,
|
||||
ValueReason.Other,
|
||||
);
|
||||
}
|
||||
state.referenceAndRecordEffects(
|
||||
freezeActions,
|
||||
instrValue.receiver,
|
||||
Effect.Capture,
|
||||
ValueReason.Other,
|
||||
);
|
||||
state.initialize(instrValue, returnValueKind);
|
||||
state.define(instr.lvalue, instrValue);
|
||||
instr.lvalue.effect =
|
||||
instrValue.receiver.effect === Effect.Capture
|
||||
? Effect.Store
|
||||
: Effect.ConditionallyMutate;
|
||||
continuation = {kind: 'funeffects'};
|
||||
break;
|
||||
}
|
||||
|
||||
const effects =
|
||||
signature !== null ? getFunctionEffects(instrValue, signature) : null;
|
||||
let hasCaptureArgument = false;
|
||||
for (let i = 0; i < instrValue.args.length; i++) {
|
||||
const arg = instrValue.args[i];
|
||||
const place = arg.kind === 'Identifier' ? arg : arg.place;
|
||||
/*
|
||||
* If effects are inferred for an argument, we should fail invalid
|
||||
* mutating effects
|
||||
*/
|
||||
state.referenceAndRecordEffects(
|
||||
freezeActions,
|
||||
place,
|
||||
getArgumentEffect(effects != null ? effects[i] : null, arg),
|
||||
ValueReason.Other,
|
||||
);
|
||||
hasCaptureArgument ||= place.effect === Effect.Capture;
|
||||
}
|
||||
if (signature !== null) {
|
||||
state.referenceAndRecordEffects(
|
||||
freezeActions,
|
||||
instrValue.receiver,
|
||||
signature.calleeEffect,
|
||||
ValueReason.Other,
|
||||
);
|
||||
} else {
|
||||
state.referenceAndRecordEffects(
|
||||
freezeActions,
|
||||
instrValue.receiver,
|
||||
Effect.ConditionallyMutate,
|
||||
ValueReason.Other,
|
||||
);
|
||||
}
|
||||
hasCaptureArgument ||= instrValue.receiver.effect === Effect.Capture;
|
||||
|
||||
state.initialize(instrValue, returnValueKind);
|
||||
state.define(instr.lvalue, instrValue);
|
||||
instr.lvalue.effect = hasCaptureArgument
|
||||
? Effect.Store
|
||||
: Effect.ConditionallyMutate;
|
||||
continuation = {kind: 'funeffects'};
|
||||
break;
|
||||
}
|
||||
|
|
@ -2125,3 +1986,105 @@ function getArgumentEffect(
|
|||
return Effect.ConditionallyMutate;
|
||||
}
|
||||
}
|
||||
|
||||
function inferCallEffects(
|
||||
state: InferenceState,
|
||||
instr: TInstruction<CallExpression> | TInstruction<MethodCall>,
|
||||
freezeActions: Array<FreezeAction>,
|
||||
signature: FunctionSignature | null,
|
||||
): void {
|
||||
const instrValue = instr.value;
|
||||
const returnValueKind: AbstractValue =
|
||||
signature !== null
|
||||
? {
|
||||
kind: signature.returnValueKind,
|
||||
reason: new Set([
|
||||
signature.returnValueReason ?? ValueReason.KnownReturnSignature,
|
||||
]),
|
||||
context: new Set(),
|
||||
}
|
||||
: {
|
||||
kind: ValueKind.Mutable,
|
||||
reason: new Set([ValueReason.Other]),
|
||||
context: new Set(),
|
||||
};
|
||||
|
||||
if (
|
||||
instrValue.kind === 'MethodCall' &&
|
||||
signature !== null &&
|
||||
signature.mutableOnlyIfOperandsAreMutable &&
|
||||
areArgumentsImmutableAndNonMutating(state, instrValue.args)
|
||||
) {
|
||||
/*
|
||||
* None of the args are mutable or mutate their params, we can downgrade to
|
||||
* treating as all reads (except that the receiver may be captured)
|
||||
*/
|
||||
for (const arg of instrValue.args) {
|
||||
const place = arg.kind === 'Identifier' ? arg : arg.place;
|
||||
state.referenceAndRecordEffects(
|
||||
freezeActions,
|
||||
place,
|
||||
Effect.Read,
|
||||
ValueReason.Other,
|
||||
);
|
||||
}
|
||||
state.referenceAndRecordEffects(
|
||||
freezeActions,
|
||||
instrValue.receiver,
|
||||
Effect.Capture,
|
||||
ValueReason.Other,
|
||||
);
|
||||
state.initialize(instrValue, returnValueKind);
|
||||
state.define(instr.lvalue, instrValue);
|
||||
instr.lvalue.effect =
|
||||
instrValue.receiver.effect === Effect.Capture
|
||||
? Effect.Store
|
||||
: Effect.ConditionallyMutate;
|
||||
return;
|
||||
}
|
||||
|
||||
const effects =
|
||||
signature !== null ? getFunctionEffects(instrValue, signature) : null;
|
||||
let hasCaptureArgument = false;
|
||||
for (let i = 0; i < instrValue.args.length; i++) {
|
||||
const arg = instrValue.args[i];
|
||||
const place = arg.kind === 'Identifier' ? arg : arg.place;
|
||||
/*
|
||||
* If effects are inferred for an argument, we should fail invalid
|
||||
* mutating effects
|
||||
*/
|
||||
state.referenceAndRecordEffects(
|
||||
freezeActions,
|
||||
place,
|
||||
getArgumentEffect(effects != null ? effects[i] : null, arg),
|
||||
ValueReason.Other,
|
||||
);
|
||||
hasCaptureArgument ||= place.effect === Effect.Capture;
|
||||
}
|
||||
const callee =
|
||||
instrValue.kind === 'CallExpression'
|
||||
? instrValue.callee
|
||||
: instrValue.receiver;
|
||||
if (signature !== null) {
|
||||
state.referenceAndRecordEffects(
|
||||
freezeActions,
|
||||
callee,
|
||||
signature.calleeEffect,
|
||||
ValueReason.Other,
|
||||
);
|
||||
} else {
|
||||
state.referenceAndRecordEffects(
|
||||
freezeActions,
|
||||
callee,
|
||||
Effect.ConditionallyMutate,
|
||||
ValueReason.Other,
|
||||
);
|
||||
}
|
||||
hasCaptureArgument ||= callee.effect === Effect.Capture;
|
||||
|
||||
state.initialize(instrValue, returnValueKind);
|
||||
state.define(instr.lvalue, instrValue);
|
||||
instr.lvalue.effect = hasCaptureArgument
|
||||
? Effect.Store
|
||||
: Effect.ConditionallyMutate;
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user