55 * LICENSE file in the root directory of this source tree.
66 */
77
8- import { effect } from 'zod' ;
98import { CompilerError , Effect , ErrorSeverity , SourceLocation } from '..' ;
109import {
1110 ArrayExpression ,
1211 BasicBlock ,
1312 BlockId ,
14- Identifier ,
1513 FunctionExpression ,
1614 HIRFunction ,
1715 IdentifierId ,
@@ -20,15 +18,12 @@ import {
2018 isSetStateType ,
2119 isUseEffectHookType ,
2220 isUseStateType ,
23- IdentifierName ,
2421 GeneratedSource ,
2522} from '../HIR' ;
26- import { printInstruction } from '../HIR/PrintHIR' ;
2723import {
2824 eachInstructionOperand ,
2925 eachTerminalOperand ,
3026 eachInstructionLValue ,
31- eachPatternOperand ,
3227} from '../HIR/visitors' ;
3328import { isMutable } from '../ReactiveScopes/InferReactiveScopeVariables' ;
3429import { assertExhaustive } from '../Utils/utils' ;
@@ -46,12 +41,10 @@ type SetStateName = string | undefined | null;
4641
4742type DerivationMetadata = {
4843 typeOfValue : TypeOfValue ;
49- // TODO: Rename to place
50- identifierPlace : Place ;
51- sources : Place [ ] ;
44+ place : Place ;
45+ sources : Array < Place > ;
5246} ;
5347
54- // TODO: This needs refining
5548type ErrorMetadata = {
5649 errorType : TypeOfValue ;
5750 invalidDepInfo : string | undefined ;
@@ -71,20 +64,22 @@ function joinValue(
7164
7265function updateDerivationMetadata (
7366 target : Place ,
74- sources : DerivationMetadata [ ] ,
67+ sources : Array < DerivationMetadata > ,
7568 typeOfValue : TypeOfValue ,
7669 derivedTuple : Map < IdentifierId , DerivationMetadata > ,
7770) : void {
7871 let newValue : DerivationMetadata = {
79- identifierPlace : target ,
72+ place : target ,
8073 sources : [ ] ,
8174 typeOfValue : typeOfValue ,
8275 } ;
8376
8477 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' ) {
8883 newValue . sources . push ( target ) ;
8984 } else {
9085 newValue . sources . push ( ...source . sources ) ;
@@ -96,10 +91,8 @@ function updateDerivationMetadata(
9691function parseInstr (
9792 instr : Instruction ,
9893 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 {
10396 let typeOfValue : TypeOfValue = 'ignored' ;
10497
10598 // TODO: Not sure if this will catch every time we create a new useState
@@ -111,7 +104,7 @@ function parseInstr(
111104 const value = instr . value . lvalue . pattern . items [ 0 ] ;
112105 if ( value . kind === 'Identifier' ) {
113106 derivedTuple . set ( value . identifier . id , {
114- identifierPlace : value ,
107+ place : value ,
115108 sources : [ value ] ,
116109 typeOfValue : 'fromState' ,
117110 } ) ;
@@ -136,7 +129,7 @@ function parseInstr(
136129 }
137130 }
138131
139- let sources : DerivationMetadata [ ] = [ ] ;
132+ let sources : Array < DerivationMetadata > = [ ] ;
140133 for ( const operand of eachInstructionOperand ( instr ) ) {
141134 const opSource = derivedTuple . get ( operand . identifier . id ) ;
142135 if ( opSource === undefined ) {
@@ -196,23 +189,23 @@ function parseInstr(
196189function parseBlockPhi (
197190 block : BasicBlock ,
198191 derivedTuple : Map < IdentifierId , DerivationMetadata > ,
199- ) {
192+ ) : void {
200193 for ( const phi of block . phis ) {
201194 for ( const operand of phi . operands . values ( ) ) {
202195 const source = derivedTuple . get ( operand . identifier . id ) ;
203196 if ( source !== undefined && source . typeOfValue === 'fromProps' ) {
204197 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'
207200 ) {
208201 derivedTuple . set ( phi . place . identifier . id , {
209- identifierPlace : phi . place ,
202+ place : phi . place ,
210203 sources : [ phi . place ] ,
211204 typeOfValue : 'fromProps' ,
212205 } ) ;
213206 } else {
214207 derivedTuple . set ( phi . place . identifier . id , {
215- identifierPlace : phi . place ,
208+ place : phi . place ,
216209 sources : source . sources ,
217210 typeOfValue : 'fromProps' ,
218211 } ) ;
@@ -251,16 +244,16 @@ export function validateNoDerivedComputationsInEffects(fn: HIRFunction): void {
251244 const locals : Map < IdentifierId , IdentifierId > = new Map ( ) ;
252245 const derivedTuple : Map < IdentifierId , DerivationMetadata > = new Map ( ) ;
253246
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 ( ) ;
256249
257- const errors : ErrorMetadata [ ] = [ ] ;
250+ const errors : Array < ErrorMetadata > = [ ] ;
258251
259252 if ( fn . fnType === 'Hook' ) {
260253 for ( const param of fn . params ) {
261254 if ( param . kind === 'Identifier' ) {
262255 derivedTuple . set ( param . identifier . id , {
263- identifierPlace : param ,
256+ place : param ,
264257 sources : [ param ] ,
265258 typeOfValue : 'fromProps' ,
266259 } ) ;
@@ -270,7 +263,7 @@ export function validateNoDerivedComputationsInEffects(fn: HIRFunction): void {
270263 const props = fn . params [ 0 ] ;
271264 if ( props != null && props . kind === 'Identifier' ) {
272265 derivedTuple . set ( props . identifier . id , {
273- identifierPlace : props ,
266+ place : props ,
274267 sources : [ props ] ,
275268 typeOfValue : 'fromProps' ,
276269 } ) ;
@@ -347,7 +340,6 @@ export function validateNoDerivedComputationsInEffects(fn: HIRFunction): void {
347340 const throwableErrors = new CompilerError ( ) ;
348341 for ( const error of errors ) {
349342 let reason ;
350- let description = '' ;
351343 // TODO: Not sure if this is robust enough.
352344 /*
353345 * If we use a setState from an invalid useEffect elsewhere then we probably have to
@@ -382,8 +374,8 @@ function validateEffect(
382374 effectFunction : HIRFunction ,
383375 effectDeps : Array < IdentifierId > ,
384376 derivedTuple : Map < IdentifierId , DerivationMetadata > ,
385- effectSetStates : Map < SetStateName , Place [ ] > ,
386- errors : ErrorMetadata [ ] ,
377+ effectSetStates : Map < SetStateName , Array < Place > > ,
378+ errors : Array < ErrorMetadata > ,
387379) : void {
388380 /*
389381 * TODO: This makes it so we only capture single line useEffects.
@@ -553,6 +545,12 @@ function validateEffect(
553545 invalidDepInfo = sourceNames
554546 ? `Invalid deps from local state: ${ sourceNames } `
555547 : '' ;
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+ : '' ;
556554 }
557555
558556 errors . push ( {
0 commit comments