@@ -200,8 +200,9 @@ function replaceFireFunctions(fn: HIRFunction, context: Context): void {
200
200
*/
201
201
if ( value . args . length === 1 && value . args [ 0 ] . kind === 'Identifier' ) {
202
202
const callee = value . args [ 0 ] ;
203
- // TODO: This value must be captured by the useEffect lambda
204
- const loadLocal = context . getLoadLocalInstr ( callee . identifier . id ) ;
203
+ const calleeId = callee . identifier . id ;
204
+
205
+ const loadLocal = context . getLoadLocalInstr ( calleeId ) ;
205
206
if ( loadLocal == null ) {
206
207
context . pushError ( {
207
208
loc : value . loc ,
@@ -213,6 +214,11 @@ function replaceFireFunctions(fn: HIRFunction, context: Context): void {
213
214
continue ;
214
215
}
215
216
217
+ context . errorIfNotCapturedFromComponentScope (
218
+ loadLocal . place . identifier . id ,
219
+ callee . loc ,
220
+ ) ;
221
+
216
222
const fireFunctionBinding = context . getOrGenerateFireFunctionBinding (
217
223
loadLocal . place ,
218
224
value . loc ,
@@ -307,13 +313,10 @@ function visitFunctionExpressionAndPropagateFireDependencies(
307
313
context : Context ,
308
314
enteringUseEffect : boolean ,
309
315
) : FireCalleesToFireFunctionBinding {
310
- let withScope = enteringUseEffect
311
- ? context . withUseEffectLambdaScope . bind ( context )
312
- : context . withFunctionScope . bind ( context ) ;
313
-
314
- const calleesCapturedByFnExpression = withScope ( ( ) =>
315
- replaceFireFunctions ( fnExpr . loweredFunc . func , context ) ,
316
- ) ;
316
+ const visitFn = ( ) : void => replaceFireFunctions ( fnExpr . loweredFunc . func , context ) ;
317
+ const calleesCapturedByFnExpression = enteringUseEffect
318
+ ? context . withUseEffectLambdaScope ( fnExpr , visitFn )
319
+ : context . withFunctionScope ( visitFn ) ;
317
320
318
321
// For each replaced callee, update the context of the function expression to track it
319
322
for (
@@ -622,6 +625,8 @@ class Context {
622
625
*/
623
626
#inUseEffectLambda = false ;
624
627
628
+ #identifierIdsCapturedByEffectLambda = new Set < IdentifierId > ( ) ;
629
+
625
630
/*
626
631
* Mapping from useEffect callee identifier ids to the instruction id of the
627
632
* load global instruction for the useEffect call. We use this to insert the
@@ -658,17 +663,23 @@ class Context {
658
663
return this . #capturedCalleeIdentifierIds;
659
664
}
660
665
661
- withUseEffectLambdaScope ( fn : ( ) => void ) : FireCalleesToFireFunctionBinding {
666
+ withUseEffectLambdaScope (
667
+ lambda : FunctionExpression ,
668
+ fn : ( ) => void ,
669
+ ) : FireCalleesToFireFunctionBinding {
662
670
const capturedCalleeIdentifierIds = this . #capturedCalleeIdentifierIds;
663
671
const inUseEffectLambda = this . #inUseEffectLambda;
664
672
665
673
this . #capturedCalleeIdentifierIds = new Map ( ) ;
666
674
this . #inUseEffectLambda = true ;
667
-
675
+ this . #identifierIdsCapturedByEffectLambda = new Set (
676
+ lambda . loweredFunc . func . context . map ( dep => dep . identifier . id ) ,
677
+ ) ;
668
678
const resultCapturedCalleeIdentifierIds = this . withFunctionScope ( fn ) ;
669
679
670
680
this . #capturedCalleeIdentifierIds = capturedCalleeIdentifierIds ;
671
681
this . #inUseEffectLambda = inUseEffectLambda ;
682
+ this . #identifierIdsCapturedByEffectLambda = new Set ( ) ;
672
683
673
684
return resultCapturedCalleeIdentifierIds ;
674
685
}
@@ -743,6 +754,22 @@ class Context {
743
754
return this . #arrayExpressions. get ( id ) ;
744
755
}
745
756
757
+ errorIfNotCapturedFromComponentScope (
758
+ id : IdentifierId ,
759
+ loc : SourceLocation ,
760
+ ) : void {
761
+ if ( ! this . #identifierIdsCapturedByEffectLambda. has ( id ) ) {
762
+ this . pushError ( {
763
+ loc,
764
+ description :
765
+ '`fire()` only accepts identifiers defined in the component/hook scope. This value was defined in the useEffect callback.' ,
766
+ severity : ErrorSeverity . InvalidReact ,
767
+ reason : CANNOT_COMPILE_FIRE ,
768
+ suggestions : null ,
769
+ } ) ;
770
+ }
771
+ }
772
+
746
773
hasErrors ( ) : boolean {
747
774
return this . #errors. hasErrors ( ) ;
748
775
}
0 commit comments