5
5
* LICENSE file in the root directory of this source tree.
6
6
*/
7
7
8
- import { effect } from 'zod' ;
9
8
import { CompilerError , Effect , ErrorSeverity , SourceLocation } from '..' ;
10
9
import {
11
10
ArrayExpression ,
12
11
BasicBlock ,
13
12
BlockId ,
14
- Identifier ,
15
13
FunctionExpression ,
16
14
HIRFunction ,
17
15
IdentifierId ,
@@ -20,15 +18,12 @@ import {
20
18
isSetStateType ,
21
19
isUseEffectHookType ,
22
20
isUseStateType ,
23
- IdentifierName ,
24
21
GeneratedSource ,
25
22
} from '../HIR' ;
26
- import { printInstruction } from '../HIR/PrintHIR' ;
27
23
import {
28
24
eachInstructionOperand ,
29
25
eachTerminalOperand ,
30
26
eachInstructionLValue ,
31
- eachPatternOperand ,
32
27
} from '../HIR/visitors' ;
33
28
import { isMutable } from '../ReactiveScopes/InferReactiveScopeVariables' ;
34
29
import { assertExhaustive } from '../Utils/utils' ;
@@ -46,12 +41,10 @@ type SetStateName = string | undefined | null;
46
41
47
42
type DerivationMetadata = {
48
43
typeOfValue : TypeOfValue ;
49
- // TODO: Rename to place
50
- identifierPlace : Place ;
51
- sources : Place [ ] ;
44
+ place : Place ;
45
+ sources : Array < Place > ;
52
46
} ;
53
47
54
- // TODO: This needs refining
55
48
type ErrorMetadata = {
56
49
errorType : TypeOfValue ;
57
50
invalidDepInfo : string | undefined ;
@@ -71,20 +64,22 @@ function joinValue(
71
64
72
65
function updateDerivationMetadata (
73
66
target : Place ,
74
- sources : DerivationMetadata [ ] ,
67
+ sources : Array < DerivationMetadata > ,
75
68
typeOfValue : TypeOfValue ,
76
69
derivedTuple : Map < IdentifierId , DerivationMetadata > ,
77
70
) : void {
78
71
let newValue : DerivationMetadata = {
79
- identifierPlace : target ,
72
+ place : target ,
80
73
sources : [ ] ,
81
74
typeOfValue : typeOfValue ,
82
75
} ;
83
76
84
77
for ( const source of sources ) {
85
- // If the identifier of the source is a promoted identifier, then
86
- // we should set the target as the source.
87
- if ( source . identifierPlace . identifier . name ?. kind === 'promoted' ) {
78
+ /*
79
+ * If the identifier of the source is a promoted identifier, then
80
+ * we should set the target as the source.
81
+ */
82
+ if ( source . place . identifier . name ?. kind === 'promoted' ) {
88
83
newValue . sources . push ( target ) ;
89
84
} else {
90
85
newValue . sources . push ( ...source . sources ) ;
@@ -96,10 +91,8 @@ function updateDerivationMetadata(
96
91
function parseInstr (
97
92
instr : Instruction ,
98
93
derivedTuple : Map < IdentifierId , DerivationMetadata > ,
99
- setStateCalls : Map < SetStateName , Place [ ] > ,
100
- ) {
101
- // console.log(printInstruction(instr));
102
- // console.log(instr);
94
+ setStateCalls : Map < SetStateName , Array < Place > > ,
95
+ ) : void {
103
96
let typeOfValue : TypeOfValue = 'ignored' ;
104
97
105
98
// TODO: Not sure if this will catch every time we create a new useState
@@ -111,7 +104,7 @@ function parseInstr(
111
104
const value = instr . value . lvalue . pattern . items [ 0 ] ;
112
105
if ( value . kind === 'Identifier' ) {
113
106
derivedTuple . set ( value . identifier . id , {
114
- identifierPlace : value ,
107
+ place : value ,
115
108
sources : [ value ] ,
116
109
typeOfValue : 'fromState' ,
117
110
} ) ;
@@ -136,7 +129,7 @@ function parseInstr(
136
129
}
137
130
}
138
131
139
- let sources : DerivationMetadata [ ] = [ ] ;
132
+ let sources : Array < DerivationMetadata > = [ ] ;
140
133
for ( const operand of eachInstructionOperand ( instr ) ) {
141
134
const opSource = derivedTuple . get ( operand . identifier . id ) ;
142
135
if ( opSource === undefined ) {
@@ -196,23 +189,23 @@ function parseInstr(
196
189
function parseBlockPhi (
197
190
block : BasicBlock ,
198
191
derivedTuple : Map < IdentifierId , DerivationMetadata > ,
199
- ) {
192
+ ) : void {
200
193
for ( const phi of block . phis ) {
201
194
for ( const operand of phi . operands . values ( ) ) {
202
195
const source = derivedTuple . get ( operand . identifier . id ) ;
203
196
if ( source !== undefined && source . typeOfValue === 'fromProps' ) {
204
197
if (
205
- source . identifierPlace . identifier . name === null ||
206
- source . identifierPlace . identifier . name ?. kind === 'promoted'
198
+ source . place . identifier . name === null ||
199
+ source . place . identifier . name ?. kind === 'promoted'
207
200
) {
208
201
derivedTuple . set ( phi . place . identifier . id , {
209
- identifierPlace : phi . place ,
202
+ place : phi . place ,
210
203
sources : [ phi . place ] ,
211
204
typeOfValue : 'fromProps' ,
212
205
} ) ;
213
206
} else {
214
207
derivedTuple . set ( phi . place . identifier . id , {
215
- identifierPlace : phi . place ,
208
+ place : phi . place ,
216
209
sources : source . sources ,
217
210
typeOfValue : 'fromProps' ,
218
211
} ) ;
@@ -251,16 +244,16 @@ export function validateNoDerivedComputationsInEffects(fn: HIRFunction): void {
251
244
const locals : Map < IdentifierId , IdentifierId > = new Map ( ) ;
252
245
const derivedTuple : Map < IdentifierId , DerivationMetadata > = new Map ( ) ;
253
246
254
- const effectSetStates : Map < SetStateName , Place [ ] > = new Map ( ) ;
255
- const setStateCalls : Map < SetStateName , Place [ ] > = new Map ( ) ;
247
+ const effectSetStates : Map < SetStateName , Array < Place > > = new Map ( ) ;
248
+ const setStateCalls : Map < SetStateName , Array < Place > > = new Map ( ) ;
256
249
257
- const errors : ErrorMetadata [ ] = [ ] ;
250
+ const errors : Array < ErrorMetadata > = [ ] ;
258
251
259
252
if ( fn . fnType === 'Hook' ) {
260
253
for ( const param of fn . params ) {
261
254
if ( param . kind === 'Identifier' ) {
262
255
derivedTuple . set ( param . identifier . id , {
263
- identifierPlace : param ,
256
+ place : param ,
264
257
sources : [ param ] ,
265
258
typeOfValue : 'fromProps' ,
266
259
} ) ;
@@ -270,7 +263,7 @@ export function validateNoDerivedComputationsInEffects(fn: HIRFunction): void {
270
263
const props = fn . params [ 0 ] ;
271
264
if ( props != null && props . kind === 'Identifier' ) {
272
265
derivedTuple . set ( props . identifier . id , {
273
- identifierPlace : props ,
266
+ place : props ,
274
267
sources : [ props ] ,
275
268
typeOfValue : 'fromProps' ,
276
269
} ) ;
@@ -347,7 +340,6 @@ export function validateNoDerivedComputationsInEffects(fn: HIRFunction): void {
347
340
const throwableErrors = new CompilerError ( ) ;
348
341
for ( const error of errors ) {
349
342
let reason ;
350
- let description = '' ;
351
343
// TODO: Not sure if this is robust enough.
352
344
/*
353
345
* If we use a setState from an invalid useEffect elsewhere then we probably have to
@@ -382,8 +374,8 @@ function validateEffect(
382
374
effectFunction : HIRFunction ,
383
375
effectDeps : Array < IdentifierId > ,
384
376
derivedTuple : Map < IdentifierId , DerivationMetadata > ,
385
- effectSetStates : Map < SetStateName , Place [ ] > ,
386
- errors : ErrorMetadata [ ] ,
377
+ effectSetStates : Map < SetStateName , Array < Place > > ,
378
+ errors : Array < ErrorMetadata > ,
387
379
) : void {
388
380
/*
389
381
* TODO: This makes it so we only capture single line useEffects.
@@ -553,6 +545,12 @@ function validateEffect(
553
545
invalidDepInfo = sourceNames
554
546
? `Invalid deps from local state: ${ sourceNames } `
555
547
: '' ;
548
+ } else {
549
+ sourceNames += `[${ placeNames } ], ` ;
550
+ sourceNames = sourceNames . slice ( 0 , - 2 ) ;
551
+ invalidDepInfo = sourceNames
552
+ ? `Invalid deps from both props and local state: ${ sourceNames } `
553
+ : '' ;
556
554
}
557
555
558
556
errors . push ( {
0 commit comments