@@ -467,53 +467,52 @@ type TreeNode = {
467467function buildTreeNode (
468468 sourceId : IdentifierId ,
469469 context : ValidationContext ,
470- ) : TreeNode | null {
470+ visited : Set < string > = new Set ( ) ,
471+ ) : Array < TreeNode > {
471472 const sourceMetadata = context . derivationCache . cache . get ( sourceId ) ;
472473 if ( ! sourceMetadata ) {
473- return null ;
474+ return [ ] ;
474475 }
475476
476- const childSourceIds = Array . from ( sourceMetadata . sourcesIds ) . filter (
477- id => id !== sourceId ,
478- ) ;
479-
480- if ( ! isNamedIdentifier ( sourceMetadata . place ) ) {
481- const childrenMap = new Map < string , TreeNode > ( ) ;
482- for ( const childId of childSourceIds ) {
483- const childNode = buildTreeNode ( childId , context ) ;
484- if ( childNode ) {
485- if ( ! childrenMap . has ( childNode . name ) ) {
486- childrenMap . set ( childNode . name , childNode ) ;
477+ const children : Array < TreeNode > = [ ] ;
478+
479+ const namedSiblings : Set < string > = new Set ( ) ;
480+ for ( const childId of sourceMetadata . sourcesIds ) {
481+ const childNodes = buildTreeNode (
482+ childId ,
483+ context ,
484+ new Set ( [
485+ ...visited ,
486+ ...( isNamedIdentifier ( sourceMetadata . place )
487+ ? [ sourceMetadata . place . identifier . name . value ]
488+ : [ ] ) ,
489+ ] ) ,
490+ ) ;
491+ if ( childNodes ) {
492+ for ( const childNode of childNodes ) {
493+ if ( ! namedSiblings . has ( childNode . name ) ) {
494+ children . push ( childNode ) ;
495+ namedSiblings . add ( childNode . name ) ;
487496 }
488497 }
489498 }
490- const children = Array . from ( childrenMap . values ( ) ) ;
491-
492- if ( children . length === 1 ) {
493- return children [ 0 ] ;
494- } else if ( children . length > 1 ) {
495- return null ;
496- }
497- return null ;
498499 }
499500
500- const childrenMap = new Map < string , TreeNode > ( ) ;
501- for ( const childId of childSourceIds ) {
502- const childNode = buildTreeNode ( childId , context ) ;
503- if ( childNode ) {
504- if ( ! childrenMap . has ( childNode . name ) ) {
505- childrenMap . set ( childNode . name , childNode ) ;
506- }
507- }
501+ if (
502+ isNamedIdentifier ( sourceMetadata . place ) &&
503+ ! visited . has ( sourceMetadata . place . identifier . name . value )
504+ ) {
505+ return [
506+ {
507+ name : sourceMetadata . place . identifier . name . value ,
508+ typeOfValue : sourceMetadata . typeOfValue ,
509+ isSource : sourceMetadata . isStateSource ,
510+ children : children ,
511+ } ,
512+ ] ;
508513 }
509- const children = Array . from ( childrenMap . values ( ) ) ;
510514
511- return {
512- name : sourceMetadata . place . identifier . name . value ,
513- typeOfValue : sourceMetadata . typeOfValue ,
514- isSource : sourceMetadata . isStateSource ,
515- children,
516- } ;
515+ return children ;
517516}
518517
519518function renderTree (
@@ -558,6 +557,24 @@ function renderTree(
558557 return result ;
559558}
560559
560+ function getFnGlobalDeps (
561+ fn : FunctionExpression | undefined ,
562+ deps : Set < IdentifierId > ,
563+ ) : void {
564+ if ( ! fn ) {
565+ return ;
566+ }
567+
568+ console . log ( fn ) ;
569+ for ( const [ , block ] of fn . loweredFunc . func . body . blocks ) {
570+ for ( const instr of block . instructions ) {
571+ if ( instr . value . kind === 'LoadLocal' ) {
572+ deps . add ( instr . value . place . identifier . id ) ;
573+ }
574+ }
575+ }
576+ }
577+
561578function validateEffect (
562579 effectFunction : HIRFunction ,
563580 context : ValidationContext ,
@@ -576,8 +593,24 @@ function validateEffect(
576593 Set < SourceLocation >
577594 > = new Map ( ) ;
578595
596+ const cleanUpFunctionDeps : Set < IdentifierId > = new Set ( ) ;
597+
579598 const globals : Set < IdentifierId > = new Set ( ) ;
580599 for ( const block of effectFunction . body . blocks . values ( ) ) {
600+ /*
601+ * if the block is in an effect and is of type return then its an effect's cleanup function
602+ * if the cleanup function depends on a value from which effect-set state is derived then
603+ * we can't validate
604+ */
605+ if (
606+ block . terminal . kind === 'return' &&
607+ block . terminal . returnVariant === 'Explicit'
608+ ) {
609+ getFnGlobalDeps (
610+ context . functions . get ( block . terminal . value . identifier . id ) ,
611+ cleanUpFunctionDeps ,
612+ ) ;
613+ }
581614 for ( const pred of block . preds ) {
582615 if ( ! seenBlocks . has ( pred ) ) {
583616 // skip if block has a back edge
@@ -664,28 +697,35 @@ function validateEffect(
664697 effectSetStateUsages . get ( rootSetStateCall ) ! . size ===
665698 context . setStateUsages . get ( rootSetStateCall ) ! . size - 1
666699 ) {
667- const allSourceIds = Array . from ( derivedSetStateCall . sourceIds ) ;
668700 const propsSet = new Set < string > ( ) ;
669701 const stateSet = new Set < string > ( ) ;
670702
671- const treeNodesMap = new Map < string , TreeNode > ( ) ;
672- for ( const id of allSourceIds ) {
673- const node = buildTreeNode ( id , context ) ;
674- if ( node && ! treeNodesMap . has ( node . name ) ) {
675- treeNodesMap . set ( node . name , node ) ;
703+ const rootNodesMap = new Map < string , TreeNode > ( ) ;
704+ for ( const id of derivedSetStateCall . sourceIds ) {
705+ const nodes = buildTreeNode ( id , context ) ;
706+ for ( const node of nodes ) {
707+ if ( ! rootNodesMap . has ( node . name ) ) {
708+ rootNodesMap . set ( node . name , node ) ;
709+ }
676710 }
677711 }
678- const treeNodes = Array . from ( treeNodesMap . values ( ) ) ;
712+ const rootNodes = Array . from ( rootNodesMap . values ( ) ) ;
679713
680- const trees = treeNodes . map ( ( node , index ) =>
681- renderTree (
714+ const trees = rootNodes . map ( ( node , index ) => {
715+ return renderTree (
682716 node ,
683717 '' ,
684- index === treeNodes . length - 1 ,
718+ index === rootNodes . length - 1 ,
685719 propsSet ,
686720 stateSet ,
687- ) ,
688- ) ;
721+ ) ;
722+ } ) ;
723+
724+ for ( const dep of derivedSetStateCall . sourceIds ) {
725+ if ( cleanUpFunctionDeps . has ( dep ) ) {
726+ return ;
727+ }
728+ }
689729
690730 const propsArr = Array . from ( propsSet ) ;
691731 const stateArr = Array . from ( stateSet ) ;
0 commit comments