@@ -358,6 +358,7 @@ class Context {
358
358
359
359
#temporaries: ReadonlyMap < IdentifierId , ReactiveScopeDependency > ;
360
360
#temporariesUsedOutsideScope: ReadonlySet < DeclarationId > ;
361
+ #processedInstrsInOptional: ReadonlySet < Instruction | Terminal > ;
361
362
362
363
/**
363
364
* Tracks the traversal state. See Context.declare for explanation of why this
@@ -368,9 +369,11 @@ class Context {
368
369
constructor (
369
370
temporariesUsedOutsideScope : ReadonlySet < DeclarationId > ,
370
371
temporaries : ReadonlyMap < IdentifierId , ReactiveScopeDependency > ,
372
+ processedInstrsInOptional : ReadonlySet < Instruction | Terminal > ,
371
373
) {
372
374
this . #temporariesUsedOutsideScope = temporariesUsedOutsideScope ;
373
375
this . #temporaries = temporaries ;
376
+ this . #processedInstrsInOptional = processedInstrsInOptional ;
374
377
}
375
378
376
379
enterScope ( scope : ReactiveScope ) : void {
@@ -574,22 +577,49 @@ class Context {
574
577
currentScope . reassignments . add ( place . identifier ) ;
575
578
}
576
579
}
580
+ enterInnerFn < T > ( cb : ( ) => T ) : T {
581
+ const wasInInnerFn = this . inInnerFn ;
582
+ this . inInnerFn = true ;
583
+ const result = cb ( ) ;
584
+ this . inInnerFn = wasInInnerFn ;
585
+ return result ;
586
+ }
587
+
588
+ /**
589
+ * Skip dependencies that are subexpressions of other dependencies. e.g. if a
590
+ * dependency is tracked in the temporaries sidemap, it can be added at
591
+ * site-of-use
592
+ */
593
+ isDeferredDependency (
594
+ instr :
595
+ | { kind : HIRValue . Instruction ; value : Instruction }
596
+ | { kind : HIRValue . Terminal ; value : Terminal } ,
597
+ ) : boolean {
598
+ return (
599
+ this . #processedInstrsInOptional. has ( instr . value ) ||
600
+ ( instr . kind === HIRValue . Instruction &&
601
+ this . #temporaries. has ( instr . value . lvalue . identifier . id ) )
602
+ ) ;
603
+ }
604
+ }
605
+ enum HIRValue {
606
+ Instruction = 1 ,
607
+ Terminal ,
577
608
}
578
609
579
610
function handleInstruction ( instr : Instruction , context : Context ) : void {
580
611
const { id, value, lvalue} = instr ;
581
- if ( value . kind === 'LoadLocal' ) {
582
- if (
583
- value . place . identifier . name === null ||
584
- lvalue . identifier . name !== null ||
585
- context . isUsedOutsideDeclaringScope ( lvalue )
586
- ) {
587
- context . visitOperand ( value . place ) ;
588
- }
589
- } else if ( value . kind === 'PropertyLoad' ) {
590
- if ( context . isUsedOutsideDeclaringScope ( lvalue ) ) {
591
- context . visitProperty ( value . object , value . property , false ) ;
592
- }
612
+ context . declare ( lvalue . identifier , {
613
+ id,
614
+ scope : context . currentScope ,
615
+ } ) ;
616
+ if (
617
+ context . isDeferredDependency ( { kind : HIRValue . Instruction , value : instr } )
618
+ ) {
619
+ return ;
620
+ }
621
+ if ( value . kind === 'PropertyLoad' ) {
622
+ context . visitProperty ( value . object , value . property , false ) ;
593
623
} else if ( value . kind === 'StoreLocal' ) {
594
624
context . visitOperand ( value . value ) ;
595
625
if ( value . lvalue . kind === InstructionKind . Reassign ) {
@@ -632,11 +662,6 @@ function handleInstruction(instr: Instruction, context: Context): void {
632
662
context . visitOperand ( operand ) ;
633
663
}
634
664
}
635
-
636
- context . declare ( lvalue . identifier , {
637
- id,
638
- scope : context . currentScope ,
639
- } ) ;
640
665
}
641
666
642
667
function collectDependencies (
@@ -645,7 +670,11 @@ function collectDependencies(
645
670
temporaries : ReadonlyMap < IdentifierId , ReactiveScopeDependency > ,
646
671
processedInstrsInOptional : ReadonlySet < Instruction | Terminal > ,
647
672
) : Map < ReactiveScope , Array < ReactiveScopeDependency > > {
648
- const context = new Context ( usedOutsideDeclaringScope , temporaries ) ;
673
+ const context = new Context (
674
+ usedOutsideDeclaringScope ,
675
+ temporaries ,
676
+ processedInstrsInOptional ,
677
+ ) ;
649
678
650
679
for ( const param of fn . params ) {
651
680
if ( param . kind === 'Identifier' ) {
@@ -694,16 +723,21 @@ function collectDependencies(
694
723
/**
695
724
* Recursively visit the inner function to extract dependencies there
696
725
*/
697
- const wasInInnerFn = context . inInnerFn ;
698
- context . inInnerFn = true ;
699
- handleFunction ( instr . value . loweredFunc . func ) ;
700
- context . inInnerFn = wasInInnerFn ;
701
- } else if ( ! processedInstrsInOptional . has ( instr ) ) {
726
+ const innerFn = instr . value . loweredFunc . func ;
727
+ context . enterInnerFn ( ( ) => {
728
+ handleFunction ( innerFn ) ;
729
+ } ) ;
730
+ } else {
702
731
handleInstruction ( instr , context ) ;
703
732
}
704
733
}
705
734
706
- if ( ! processedInstrsInOptional . has ( block . terminal ) ) {
735
+ if (
736
+ ! context . isDeferredDependency ( {
737
+ kind : HIRValue . Terminal ,
738
+ value : block . terminal ,
739
+ } )
740
+ ) {
707
741
for ( const place of eachTerminalOperand ( block . terminal ) ) {
708
742
context . visitOperand ( place ) ;
709
743
}
0 commit comments