@@ -17,7 +17,6 @@ import {
1717 ExternalFunction ,
1818 ReactFunctionType ,
1919 MINIMAL_RETRY_CONFIG ,
20- tryParseExternalFunction ,
2120} from '../HIR/Environment' ;
2221import { CodegenFunction } from '../ReactiveScopes' ;
2322import { isComponentDeclaration } from '../Utils/ComponentDeclaration' ;
@@ -541,30 +540,26 @@ export function compileProgram(
541540 if ( moduleScopeOptOutDirectives . length > 0 ) {
542541 return ;
543542 }
544-
543+ let gating : null | {
544+ gatingFn : ExternalFunction ;
545+ referencedBeforeDeclared : Set < CompileResult > ;
546+ } = null ;
545547 if ( pass . opts . gating != null ) {
546- const error = checkFunctionReferencedBeforeDeclarationAtTopLevel (
547- program ,
548- compiledFns . map ( result => {
549- return result . originalFn ;
550- } ) ,
551- ) ;
552- if ( error ) {
553- handleError ( error , pass , null ) ;
554- return ;
555- }
548+ gating = {
549+ gatingFn : pass . opts . gating ,
550+ referencedBeforeDeclared :
551+ getFunctionReferencedBeforeDeclarationAtTopLevel ( program , compiledFns ) ,
552+ } ;
556553 }
557554
558555 const hasLoweredContextAccess = compiledFns . some (
559556 c => c . compiledFn . hasLoweredContextAccess ,
560557 ) ;
561558 const externalFunctions : Array < ExternalFunction > = [ ] ;
562- let gating : null | ExternalFunction = null ;
563559 try {
564560 // TODO: check for duplicate import specifiers
565- if ( pass . opts . gating != null ) {
566- gating = tryParseExternalFunction ( pass . opts . gating ) ;
567- externalFunctions . push ( gating ) ;
561+ if ( gating != null ) {
562+ externalFunctions . push ( gating . gatingFn ) ;
568563 }
569564
570565 const lowerContextAccess = environment . lowerContextAccess ;
@@ -613,7 +608,12 @@ export function compileProgram(
613608 const transformedFn = createNewFunctionNode ( originalFn , compiledFn ) ;
614609
615610 if ( gating != null && kind === 'original' ) {
616- insertGatedFunctionDeclaration ( originalFn , transformedFn , gating ) ;
611+ insertGatedFunctionDeclaration (
612+ originalFn ,
613+ transformedFn ,
614+ gating . gatingFn ,
615+ gating . referencedBeforeDeclared . has ( result ) ,
616+ ) ;
617617 } else {
618618 originalFn . replaceWith ( transformedFn ) ;
619619 }
@@ -1093,20 +1093,23 @@ function getFunctionName(
10931093 }
10941094}
10951095
1096- function checkFunctionReferencedBeforeDeclarationAtTopLevel (
1096+ function getFunctionReferencedBeforeDeclarationAtTopLevel (
10971097 program : NodePath < t . Program > ,
1098- fns : Array < BabelFn > ,
1099- ) : CompilerError | null {
1100- const fnIds = new Set (
1098+ fns : Array < CompileResult > ,
1099+ ) : Set < CompileResult > {
1100+ const fnNames = new Map < string , { id : t . Identifier ; fn : CompileResult } > (
11011101 fns
1102- . map ( fn => getFunctionName ( fn ) )
1102+ . map < [ NodePath < t . Expression > | null , CompileResult ] > ( fn => [
1103+ getFunctionName ( fn . originalFn ) ,
1104+ fn ,
1105+ ] )
11031106 . filter (
1104- ( name ) : name is NodePath < t . Identifier > => ! ! name && name . isIdentifier ( ) ,
1107+ ( entry ) : entry is [ NodePath < t . Identifier > , CompileResult ] =>
1108+ ! ! entry [ 0 ] && entry [ 0 ] . isIdentifier ( ) ,
11051109 )
1106- . map ( name => name . node ) ,
1110+ . map ( entry => [ entry [ 0 ] . node . name , { id : entry [ 0 ] . node , fn : entry [ 1 ] } ] ) ,
11071111 ) ;
1108- const fnNames = new Map ( [ ...fnIds ] . map ( id => [ id . name , id ] ) ) ;
1109- const errors = new CompilerError ( ) ;
1112+ const referencedBeforeDeclaration = new Set < CompileResult > ( ) ;
11101113
11111114 program . traverse ( {
11121115 TypeAnnotation ( path ) {
@@ -1132,8 +1135,7 @@ function checkFunctionReferencedBeforeDeclarationAtTopLevel(
11321135 * We've reached the declaration, hoisting is no longer possible, stop
11331136 * checking for this component name.
11341137 */
1135- if ( fnIds . has ( id . node ) ) {
1136- fnIds . delete ( id . node ) ;
1138+ if ( id . node === fn . id ) {
11371139 fnNames . delete ( id . node . name ) ;
11381140 return ;
11391141 }
@@ -1144,20 +1146,12 @@ function checkFunctionReferencedBeforeDeclarationAtTopLevel(
11441146 * top level scope.
11451147 */
11461148 if ( scope === null && id . isReferencedIdentifier ( ) ) {
1147- errors . pushErrorDetail (
1148- new CompilerErrorDetail ( {
1149- reason : `Encountered a function used before its declaration, which breaks Forget's gating codegen due to hoisting` ,
1150- description : `Rewrite the reference to ${ fn . name } to not rely on hoisting to fix this issue` ,
1151- loc : fn . loc ?? null ,
1152- suggestions : null ,
1153- severity : ErrorSeverity . Invariant ,
1154- } ) ,
1155- ) ;
1149+ referencedBeforeDeclaration . add ( fn . fn ) ;
11561150 }
11571151 } ,
11581152 } ) ;
11591153
1160- return errors . details . length > 0 ? errors : null ;
1154+ return referencedBeforeDeclaration ;
11611155}
11621156
11631157function getReactCompilerRuntimeModule ( opts : PluginOptions ) : string {
0 commit comments