@@ -171,6 +171,8 @@ const collectPatternNames = (pattern: Pattern, out: Array<string> = []): Array<s
171171}
172172
173173// `var` names declared anywhere in a function body except inside nested functions, which own theirs.
174+ // Memoized per body: a function's var names never change, and hoisting runs on every call.
175+ const varNames = new WeakMap < ReadonlyArray < Statement | ModuleDeclaration > , ReadonlyArray < string > > ( )
174176const collectVarNames = (
175177 node : Statement | ModuleDeclaration | null | undefined ,
176178 out : Array < string > = [ ] ,
@@ -446,12 +448,14 @@ class Frame<R> {
446448 // Hoisted `var` bindings start undefined, or copy a same-named parameter. Function bodies hoist
447449 // into their own scope above the parameters so closures in parameter defaults keep seeing outer names.
448450 private hoistVars ( statements : ReadonlyArray < Statement | ModuleDeclaration > , parameters ?: Map < string , Binding > ) : void {
451+ const names =
452+ varNames . get ( statements ) ??
453+ statements . reduce < Array < string > > ( ( out , statement ) => collectVarNames ( statement , out ) , [ ] )
454+ varNames . set ( statements , names )
449455 const scope = this . scopes . current ( )
450- for ( const statement of statements ) {
451- for ( const name of collectVarNames ( statement ) ) {
452- if ( scope . has ( name ) ) continue
453- scope . set ( name , { mutable : true , value : parameters ?. get ( name ) ?. value , initialized : true } )
454- }
456+ for ( const name of names ) {
457+ if ( scope . has ( name ) ) continue
458+ scope . set ( name , { mutable : true , value : parameters ?. get ( name ) ?. value , initialized : true } )
455459 }
456460 }
457461
@@ -492,7 +496,9 @@ class Frame<R> {
492496 self . scopes . push ( )
493497 return yield * Effect . gen ( function * ( ) {
494498 const cases = node . cases
495- self . predeclareLexical ( cases . flatMap ( ( branch ) => branch . consequent ) )
499+ const statements = cases . flatMap ( ( branch ) => branch . consequent )
500+ self . predeclareLexical ( statements )
501+ self . hoistFunctions ( statements )
496502 let defaultIndex : number | undefined
497503 let selected : number | undefined
498504 for ( const [ index , branch ] of cases . entries ( ) ) {
@@ -1649,16 +1655,8 @@ class Frame<R> {
16491655 } )
16501656 if ( fn . generator ) return Effect . succeed ( this . createGenerator ( invocation , run , fn . async ) )
16511657 if ( ! fn . async ) return run
1652- // The initial yield assigns the promise before the body can self-resolve.
1653- const box : { promise ?: Values . Promise } = { }
1654- return Effect . map (
1655- this . createPromise (
1656- Effect . flatMap ( run , ( value ) => resolvePromiseValue ( invocation . runtime . runner , value , fn . body , box ) ) ,
1657- ) ,
1658- ( promise ) => {
1659- box . promise = promise
1660- return promise
1661- } ,
1658+ return this . runtime . promises . createWithSelf ( ( self ) =>
1659+ Effect . flatMap ( run , ( value ) => resolvePromiseValue ( invocation . runtime . runner , value , fn . body , self ) ) ,
16621660 )
16631661 }
16641662
0 commit comments