@@ -1959,24 +1959,13 @@ impl Compiler<'_> {
19591959 ) ;
19601960 }
19611961
1962- if self . build_closure ( & code) {
1963- func_flags |= bytecode:: MakeFunctionFlags :: CLOSURE ;
1964- }
1965-
19661962 // Pop the special type params symbol table
19671963 if type_params. is_some ( ) {
19681964 self . pop_symbol_table ( ) ;
19691965 }
19701966
1971- self . emit_load_const ( ConstantData :: Code {
1972- code : Box :: new ( code) ,
1973- } ) ;
1974- self . emit_load_const ( ConstantData :: Str {
1975- value : qualname. into ( ) ,
1976- } ) ;
1977-
1978- // Turn code object into function object:
1979- emit ! ( self , Instruction :: MakeFunction ( func_flags) ) ;
1967+ // Create function with closure
1968+ self . make_closure ( code, & qualname, func_flags) ?;
19801969
19811970 if let Some ( value) = doc_str {
19821971 emit ! ( self , Instruction :: Duplicate ) ;
@@ -1993,44 +1982,88 @@ impl Compiler<'_> {
19931982 self . store_name ( name)
19941983 }
19951984
1996- fn build_closure ( & mut self , code : & CodeObject ) -> bool {
1997- if code. freevars . is_empty ( ) {
1998- return false ;
1999- }
2000- for var in & * code. freevars {
2001- let table = self . symbol_table_stack . last ( ) . unwrap ( ) ;
2002- let symbol = unwrap_internal (
2003- self ,
2004- table
2005- . lookup ( var)
2006- . ok_or_else ( || InternalError :: MissingSymbol ( var. to_owned ( ) ) ) ,
2007- ) ;
2008- let parent_code = self . code_stack . last ( ) . unwrap ( ) ;
2009- let vars = match symbol. scope {
2010- SymbolScope :: Free => & parent_code. metadata . freevars ,
2011- SymbolScope :: Cell => & parent_code. metadata . cellvars ,
2012- SymbolScope :: TypeParams => & parent_code. metadata . cellvars ,
2013- _ if symbol. flags . contains ( SymbolFlags :: FREE_CLASS ) => {
2014- & parent_code. metadata . freevars
1985+ /// Implementation of CPython's compiler_make_closure
1986+ /// Loads closure variables if needed and creates a function object
1987+ fn make_closure (
1988+ & mut self ,
1989+ code : CodeObject ,
1990+ qualname : & str ,
1991+ mut flags : bytecode:: MakeFunctionFlags ,
1992+ ) -> CompileResult < ( ) > {
1993+ // Handle free variables (closure)
1994+ if !code. freevars . is_empty ( ) {
1995+ // Build closure tuple by loading free variables
1996+ for var in & * code. freevars {
1997+ let table = self . symbol_table_stack . last ( ) . unwrap ( ) ;
1998+ let symbol = match table. lookup ( var) {
1999+ Some ( s) => s,
2000+ None => {
2001+ return Err ( self . error ( CodegenErrorType :: SyntaxError ( format ! (
2002+ "compiler_make_closure: cannot find symbol '{}'" ,
2003+ var
2004+ ) ) ) ) ;
2005+ }
2006+ } ;
2007+
2008+ let parent_code = self . code_stack . last ( ) . unwrap ( ) ;
2009+ let vars = match symbol. scope {
2010+ SymbolScope :: Free => & parent_code. metadata . freevars ,
2011+ SymbolScope :: Cell => & parent_code. metadata . cellvars ,
2012+ SymbolScope :: TypeParams => & parent_code. metadata . cellvars ,
2013+ _ if symbol. flags . contains ( SymbolFlags :: FREE_CLASS ) => {
2014+ & parent_code. metadata . freevars
2015+ }
2016+ _ => {
2017+ return Err ( self . error ( CodegenErrorType :: SyntaxError ( format ! (
2018+ "compiler_make_closure: invalid scope for '{}'" ,
2019+ var
2020+ ) ) ) ) ;
2021+ }
2022+ } ;
2023+
2024+ let idx = match vars. get_index_of ( var) {
2025+ Some ( i) => i,
2026+ None => {
2027+ return Err ( self . error ( CodegenErrorType :: SyntaxError ( format ! (
2028+ "compiler_make_closure: cannot find '{}' in parent vars" ,
2029+ var
2030+ ) ) ) ) ;
2031+ }
2032+ } ;
2033+
2034+ let mut idx = idx;
2035+ if let SymbolScope :: Free = symbol. scope {
2036+ idx += parent_code. metadata . cellvars . len ( ) ;
20152037 }
2016- x => unreachable ! (
2017- "var {} in a {:?} should be free or cell but it's {:?}" ,
2018- var, table. typ, x
2019- ) ,
2020- } ;
2021- let mut idx = vars. get_index_of ( var) . unwrap ( ) ;
2022- if let SymbolScope :: Free = symbol. scope {
2023- idx += parent_code. metadata . cellvars . len ( ) ;
2038+
2039+ emit ! ( self , Instruction :: LoadClosure ( idx. to_u32( ) ) ) ;
20242040 }
2025- emit ! ( self , Instruction :: LoadClosure ( idx. to_u32( ) ) )
2041+
2042+ // Build tuple of closure variables
2043+ emit ! (
2044+ self ,
2045+ Instruction :: BuildTuple {
2046+ size: code. freevars. len( ) . to_u32( ) ,
2047+ }
2048+ ) ;
2049+
2050+ flags |= bytecode:: MakeFunctionFlags :: CLOSURE ;
20262051 }
2027- emit ! (
2028- self ,
2029- Instruction :: BuildTuple {
2030- size: code. freevars. len( ) . to_u32( ) ,
2031- }
2032- ) ;
2033- true
2052+
2053+ // Load code object
2054+ self . emit_load_const ( ConstantData :: Code {
2055+ code : Box :: new ( code) ,
2056+ } ) ;
2057+
2058+ // Load qualified name
2059+ self . emit_load_const ( ConstantData :: Str {
2060+ value : qualname. into ( ) ,
2061+ } ) ;
2062+
2063+ // Make function with proper flags
2064+ emit ! ( self , Instruction :: MakeFunction ( flags) ) ;
2065+
2066+ Ok ( ( ) )
20342067 }
20352068
20362069 // Python/compile.c find_ann
@@ -2230,15 +2263,8 @@ impl Compiler<'_> {
22302263 emit ! ( self , Instruction :: LoadNameAny ( dot_type_params) ) ;
22312264 func_flags |= bytecode:: MakeFunctionFlags :: TYPE_PARAMS ;
22322265
2233- if self . build_closure ( & class_code) {
2234- func_flags |= bytecode:: MakeFunctionFlags :: CLOSURE ;
2235- }
2236-
2237- self . emit_load_const ( ConstantData :: Code {
2238- code : Box :: new ( class_code) ,
2239- } ) ;
2240- self . emit_load_const ( ConstantData :: Str { value : name. into ( ) } ) ;
2241- emit ! ( self , Instruction :: MakeFunction ( func_flags) ) ;
2266+ // Create class function with closure
2267+ self . make_closure ( class_code, name, func_flags) ?;
22422268 self . emit_load_const ( ConstantData :: Str { value : name. into ( ) } ) ;
22432269
22442270 // Compile original bases
@@ -2287,34 +2313,19 @@ impl Compiler<'_> {
22872313 let type_params_code = self . exit_scope ( ) ;
22882314
22892315 // Execute the type params function
2290- if self . build_closure ( & type_params_code) {
2291- // Should not need closure
2292- }
2293- self . emit_load_const ( ConstantData :: Code {
2294- code : Box :: new ( type_params_code) ,
2295- } ) ;
2296- self . emit_load_const ( ConstantData :: Str {
2297- value : format ! ( "<generic parameters of {name}>" ) . into ( ) ,
2298- } ) ;
2299- emit ! (
2300- self ,
2301- Instruction :: MakeFunction ( bytecode:: MakeFunctionFlags :: empty( ) )
2302- ) ;
2316+ let type_params_name = format ! ( "<generic parameters of {name}>" ) ;
2317+ self . make_closure (
2318+ type_params_code,
2319+ & type_params_name,
2320+ bytecode:: MakeFunctionFlags :: empty ( ) ,
2321+ ) ?;
23032322 emit ! ( self , Instruction :: CallFunctionPositional { nargs: 0 } ) ;
23042323 } else {
23052324 // Non-generic class: standard path
23062325 emit ! ( self , Instruction :: LoadBuildClass ) ;
23072326
2308- let mut func_flags = bytecode:: MakeFunctionFlags :: empty ( ) ;
2309- if self . build_closure ( & class_code) {
2310- func_flags |= bytecode:: MakeFunctionFlags :: CLOSURE ;
2311- }
2312-
2313- self . emit_load_const ( ConstantData :: Code {
2314- code : Box :: new ( class_code) ,
2315- } ) ;
2316- self . emit_load_const ( ConstantData :: Str { value : name. into ( ) } ) ;
2317- emit ! ( self , Instruction :: MakeFunction ( func_flags) ) ;
2327+ // Create class function with closure
2328+ self . make_closure ( class_code, name, bytecode:: MakeFunctionFlags :: empty ( ) ) ?;
23182329 self . emit_load_const ( ConstantData :: Str { value : name. into ( ) } ) ;
23192330
23202331 let call = if let Some ( arguments) = arguments {
@@ -4026,7 +4037,7 @@ impl Compiler<'_> {
40264037 let prev_ctx = self . ctx ;
40274038
40284039 let name = "<lambda>" . to_owned ( ) ;
4029- let mut func_flags = self
4040+ let func_flags = self
40304041 . enter_function ( & name, parameters. as_deref ( ) . unwrap_or ( & Default :: default ( ) ) ) ?;
40314042
40324043 // Set qualname for lambda
@@ -4046,15 +4057,9 @@ impl Compiler<'_> {
40464057 self . compile_expression ( body) ?;
40474058 self . emit_return_value ( ) ;
40484059 let code = self . exit_scope ( ) ;
4049- if self . build_closure ( & code) {
4050- func_flags |= bytecode:: MakeFunctionFlags :: CLOSURE ;
4051- }
4052- self . emit_load_const ( ConstantData :: Code {
4053- code : Box :: new ( code) ,
4054- } ) ;
4055- self . emit_load_const ( ConstantData :: Str { value : name. into ( ) } ) ;
4056- // Turn code object into function object:
4057- emit ! ( self , Instruction :: MakeFunction ( func_flags) ) ;
4060+
4061+ // Create lambda function with closure
4062+ self . make_closure ( code, & name, func_flags) ?;
40584063
40594064 self . ctx = prev_ctx;
40604065 }
@@ -4598,21 +4603,8 @@ impl Compiler<'_> {
45984603
45994604 self . ctx = prev_ctx;
46004605
4601- let mut func_flags = bytecode:: MakeFunctionFlags :: empty ( ) ;
4602- if self . build_closure ( & code) {
4603- func_flags |= bytecode:: MakeFunctionFlags :: CLOSURE ;
4604- }
4605-
4606- // List comprehension code:
4607- self . emit_load_const ( ConstantData :: Code {
4608- code : Box :: new ( code) ,
4609- } ) ;
4610-
4611- // List comprehension function name:
4612- self . emit_load_const ( ConstantData :: Str { value : name. into ( ) } ) ;
4613-
4614- // Turn code object into function object:
4615- emit ! ( self , Instruction :: MakeFunction ( func_flags) ) ;
4606+ // Create comprehension function with closure
4607+ self . make_closure ( code, & name, bytecode:: MakeFunctionFlags :: empty ( ) ) ?;
46164608
46174609 // Evaluate iterated item:
46184610 self . compile_expression ( & generators[ 0 ] . iter ) ?;
0 commit comments