Skip to content

Commit 3fd58cf

Browse files
committed
[compiler] First functional disambiguated single line validation of no derived computations in effects
1 parent 689e3a6 commit 3fd58cf

File tree

1 file changed

+31
-33
lines changed

1 file changed

+31
-33
lines changed

compiler/packages/babel-plugin-react-compiler/src/Validation/ValidateNoDerivedComputationsInEffects.ts

Lines changed: 31 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -5,14 +5,12 @@
55
* LICENSE file in the root directory of this source tree.
66
*/
77

8-
import {effect} from 'zod';
98
import {CompilerError, Effect, ErrorSeverity, SourceLocation} from '..';
109
import {ErrorCategory} from '../CompilerError';
1110
import {
1211
ArrayExpression,
1312
BasicBlock,
1413
BlockId,
15-
Identifier,
1614
FunctionExpression,
1715
HIRFunction,
1816
IdentifierId,
@@ -21,15 +19,12 @@ import {
2119
isSetStateType,
2220
isUseEffectHookType,
2321
isUseStateType,
24-
IdentifierName,
2522
GeneratedSource,
2623
} from '../HIR';
27-
import {printInstruction} from '../HIR/PrintHIR';
2824
import {
2925
eachInstructionOperand,
3026
eachTerminalOperand,
3127
eachInstructionLValue,
32-
eachPatternOperand,
3328
} from '../HIR/visitors';
3429
import {isMutable} from '../ReactiveScopes/InferReactiveScopeVariables';
3530
import {assertExhaustive} from '../Utils/utils';
@@ -47,12 +42,10 @@ type SetStateName = string | undefined | null;
4742

4843
type DerivationMetadata = {
4944
typeOfValue: TypeOfValue;
50-
// TODO: Rename to place
51-
identifierPlace: Place;
52-
sources: Place[];
45+
place: Place;
46+
sources: Array<Place>;
5347
};
5448

55-
// TODO: This needs refining
5649
type ErrorMetadata = {
5750
errorType: TypeOfValue;
5851
invalidDepInfo: string | undefined;
@@ -72,20 +65,22 @@ function joinValue(
7265

7366
function updateDerivationMetadata(
7467
target: Place,
75-
sources: DerivationMetadata[],
68+
sources: Array<DerivationMetadata>,
7669
typeOfValue: TypeOfValue,
7770
derivedTuple: Map<IdentifierId, DerivationMetadata>,
7871
): void {
7972
let newValue: DerivationMetadata = {
80-
identifierPlace: target,
73+
place: target,
8174
sources: [],
8275
typeOfValue: typeOfValue,
8376
};
8477

8578
for (const source of sources) {
86-
// If the identifier of the source is a promoted identifier, then
87-
// we should set the target as the source.
88-
if (source.identifierPlace.identifier.name?.kind === 'promoted') {
79+
/*
80+
* If the identifier of the source is a promoted identifier, then
81+
* we should set the target as the source.
82+
*/
83+
if (source.place.identifier.name?.kind === 'promoted') {
8984
newValue.sources.push(target);
9085
} else {
9186
newValue.sources.push(...source.sources);
@@ -97,10 +92,8 @@ function updateDerivationMetadata(
9792
function parseInstr(
9893
instr: Instruction,
9994
derivedTuple: Map<IdentifierId, DerivationMetadata>,
100-
setStateCalls: Map<SetStateName, Place[]>,
101-
) {
102-
// console.log(printInstruction(instr));
103-
// console.log(instr);
95+
setStateCalls: Map<SetStateName, Array<Place>>,
96+
): void {
10497
let typeOfValue: TypeOfValue = 'ignored';
10598

10699
// TODO: Not sure if this will catch every time we create a new useState
@@ -112,7 +105,7 @@ function parseInstr(
112105
const value = instr.value.lvalue.pattern.items[0];
113106
if (value.kind === 'Identifier') {
114107
derivedTuple.set(value.identifier.id, {
115-
identifierPlace: value,
108+
place: value,
116109
sources: [value],
117110
typeOfValue: 'fromState',
118111
});
@@ -137,7 +130,7 @@ function parseInstr(
137130
}
138131
}
139132

140-
let sources: DerivationMetadata[] = [];
133+
let sources: Array<DerivationMetadata> = [];
141134
for (const operand of eachInstructionOperand(instr)) {
142135
const opSource = derivedTuple.get(operand.identifier.id);
143136
if (opSource === undefined) {
@@ -197,23 +190,23 @@ function parseInstr(
197190
function parseBlockPhi(
198191
block: BasicBlock,
199192
derivedTuple: Map<IdentifierId, DerivationMetadata>,
200-
) {
193+
): void {
201194
for (const phi of block.phis) {
202195
for (const operand of phi.operands.values()) {
203196
const source = derivedTuple.get(operand.identifier.id);
204197
if (source !== undefined && source.typeOfValue === 'fromProps') {
205198
if (
206-
source.identifierPlace.identifier.name === null ||
207-
source.identifierPlace.identifier.name?.kind === 'promoted'
199+
source.place.identifier.name === null ||
200+
source.place.identifier.name?.kind === 'promoted'
208201
) {
209202
derivedTuple.set(phi.place.identifier.id, {
210-
identifierPlace: phi.place,
203+
place: phi.place,
211204
sources: [phi.place],
212205
typeOfValue: 'fromProps',
213206
});
214207
} else {
215208
derivedTuple.set(phi.place.identifier.id, {
216-
identifierPlace: phi.place,
209+
place: phi.place,
217210
sources: source.sources,
218211
typeOfValue: 'fromProps',
219212
});
@@ -252,16 +245,16 @@ export function validateNoDerivedComputationsInEffects(fn: HIRFunction): void {
252245
const locals: Map<IdentifierId, IdentifierId> = new Map();
253246
const derivedTuple: Map<IdentifierId, DerivationMetadata> = new Map();
254247

255-
const effectSetStates: Map<SetStateName, Place[]> = new Map();
256-
const setStateCalls: Map<SetStateName, Place[]> = new Map();
248+
const effectSetStates: Map<SetStateName, Array<Place>> = new Map();
249+
const setStateCalls: Map<SetStateName, Array<Place>> = new Map();
257250

258-
const errors: ErrorMetadata[] = [];
251+
const errors: Array<ErrorMetadata> = [];
259252

260253
if (fn.fnType === 'Hook') {
261254
for (const param of fn.params) {
262255
if (param.kind === 'Identifier') {
263256
derivedTuple.set(param.identifier.id, {
264-
identifierPlace: param,
257+
place: param,
265258
sources: [param],
266259
typeOfValue: 'fromProps',
267260
});
@@ -271,7 +264,7 @@ export function validateNoDerivedComputationsInEffects(fn: HIRFunction): void {
271264
const props = fn.params[0];
272265
if (props != null && props.kind === 'Identifier') {
273266
derivedTuple.set(props.identifier.id, {
274-
identifierPlace: props,
267+
place: props,
275268
sources: [props],
276269
typeOfValue: 'fromProps',
277270
});
@@ -348,7 +341,6 @@ export function validateNoDerivedComputationsInEffects(fn: HIRFunction): void {
348341
const throwableErrors = new CompilerError();
349342
for (const error of errors) {
350343
let reason;
351-
let description = '';
352344
// TODO: Not sure if this is robust enough.
353345
/*
354346
* If we use a setState from an invalid useEffect elsewhere then we probably have to
@@ -383,8 +375,8 @@ function validateEffect(
383375
effectFunction: HIRFunction,
384376
effectDeps: Array<IdentifierId>,
385377
derivedTuple: Map<IdentifierId, DerivationMetadata>,
386-
effectSetStates: Map<SetStateName, Place[]>,
387-
errors: ErrorMetadata[],
378+
effectSetStates: Map<SetStateName, Array<Place>>,
379+
errors: Array<ErrorMetadata>,
388380
): void {
389381
/*
390382
* TODO: This makes it so we only capture single line useEffects.
@@ -554,6 +546,12 @@ function validateEffect(
554546
invalidDepInfo = sourceNames
555547
? `Invalid deps from local state: ${sourceNames}`
556548
: '';
549+
} else {
550+
sourceNames += `[${placeNames}], `;
551+
sourceNames = sourceNames.slice(0, -2);
552+
invalidDepInfo = sourceNames
553+
? `Invalid deps from both props and local state: ${sourceNames}`
554+
: '';
557555
}
558556

559557
errors.push({

0 commit comments

Comments
 (0)