@@ -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,85 @@ 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 '{var}'" ,
2003+ ) ) ) ) ;
2004+ }
2005+ } ;
2006+
2007+ let parent_code = self . code_stack . last ( ) . unwrap ( ) ;
2008+ let vars = match symbol. scope {
2009+ SymbolScope :: Free => & parent_code. metadata . freevars ,
2010+ SymbolScope :: Cell => & parent_code. metadata . cellvars ,
2011+ SymbolScope :: TypeParams => & parent_code. metadata . cellvars ,
2012+ _ if symbol. flags . contains ( SymbolFlags :: FREE_CLASS ) => {
2013+ & parent_code. metadata . freevars
2014+ }
2015+ _ => {
2016+ return Err ( self . error ( CodegenErrorType :: SyntaxError ( format ! (
2017+ "compiler_make_closure: invalid scope for '{var}'" ,
2018+ ) ) ) ) ;
2019+ }
2020+ } ;
2021+
2022+ let idx = match vars. get_index_of ( var) {
2023+ Some ( i) => i,
2024+ None => {
2025+ return Err ( self . error ( CodegenErrorType :: SyntaxError ( format ! (
2026+ "compiler_make_closure: cannot find '{var}' in parent vars" ,
2027+ ) ) ) ) ;
2028+ }
2029+ } ;
2030+
2031+ let mut idx = idx;
2032+ if let SymbolScope :: Free = symbol. scope {
2033+ idx += parent_code. metadata . cellvars . len ( ) ;
20152034 }
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 ( ) ;
2035+
2036+ emit ! ( self , Instruction :: LoadClosure ( idx. to_u32( ) ) ) ;
20242037 }
2025- emit ! ( self , Instruction :: LoadClosure ( idx. to_u32( ) ) )
2038+
2039+ // Build tuple of closure variables
2040+ emit ! (
2041+ self ,
2042+ Instruction :: BuildTuple {
2043+ size: code. freevars. len( ) . to_u32( ) ,
2044+ }
2045+ ) ;
2046+
2047+ flags |= bytecode:: MakeFunctionFlags :: CLOSURE ;
20262048 }
2027- emit ! (
2028- self ,
2029- Instruction :: BuildTuple {
2030- size: code. freevars. len( ) . to_u32( ) ,
2031- }
2032- ) ;
2033- true
2049+
2050+ // Load code object
2051+ self . emit_load_const ( ConstantData :: Code {
2052+ code : Box :: new ( code) ,
2053+ } ) ;
2054+
2055+ // Load qualified name
2056+ self . emit_load_const ( ConstantData :: Str {
2057+ value : qualname. into ( ) ,
2058+ } ) ;
2059+
2060+ // Make function with proper flags
2061+ emit ! ( self , Instruction :: MakeFunction ( flags) ) ;
2062+
2063+ Ok ( ( ) )
20342064 }
20352065
20362066 // Python/compile.c find_ann
@@ -2230,15 +2260,8 @@ impl Compiler<'_> {
22302260 emit ! ( self , Instruction :: LoadNameAny ( dot_type_params) ) ;
22312261 func_flags |= bytecode:: MakeFunctionFlags :: TYPE_PARAMS ;
22322262
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) ) ;
2263+ // Create class function with closure
2264+ self . make_closure ( class_code, name, func_flags) ?;
22422265 self . emit_load_const ( ConstantData :: Str { value : name. into ( ) } ) ;
22432266
22442267 // Compile original bases
@@ -2287,34 +2310,19 @@ impl Compiler<'_> {
22872310 let type_params_code = self . exit_scope ( ) ;
22882311
22892312 // 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- ) ;
2313+ let type_params_name = format ! ( "<generic parameters of {name}>" ) ;
2314+ self . make_closure (
2315+ type_params_code,
2316+ & type_params_name,
2317+ bytecode:: MakeFunctionFlags :: empty ( ) ,
2318+ ) ?;
23032319 emit ! ( self , Instruction :: CallFunctionPositional { nargs: 0 } ) ;
23042320 } else {
23052321 // Non-generic class: standard path
23062322 emit ! ( self , Instruction :: LoadBuildClass ) ;
23072323
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) ) ;
2324+ // Create class function with closure
2325+ self . make_closure ( class_code, name, bytecode:: MakeFunctionFlags :: empty ( ) ) ?;
23182326 self . emit_load_const ( ConstantData :: Str { value : name. into ( ) } ) ;
23192327
23202328 let call = if let Some ( arguments) = arguments {
@@ -4026,7 +4034,7 @@ impl Compiler<'_> {
40264034 let prev_ctx = self . ctx ;
40274035
40284036 let name = "<lambda>" . to_owned ( ) ;
4029- let mut func_flags = self
4037+ let func_flags = self
40304038 . enter_function ( & name, parameters. as_deref ( ) . unwrap_or ( & Default :: default ( ) ) ) ?;
40314039
40324040 // Set qualname for lambda
@@ -4046,15 +4054,9 @@ impl Compiler<'_> {
40464054 self . compile_expression ( body) ?;
40474055 self . emit_return_value ( ) ;
40484056 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) ) ;
4057+
4058+ // Create lambda function with closure
4059+ self . make_closure ( code, & name, func_flags) ?;
40584060
40594061 self . ctx = prev_ctx;
40604062 }
@@ -4598,21 +4600,8 @@ impl Compiler<'_> {
45984600
45994601 self . ctx = prev_ctx;
46004602
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) ) ;
4603+ // Create comprehension function with closure
4604+ self . make_closure ( code, name, bytecode:: MakeFunctionFlags :: empty ( ) ) ?;
46164605
46174606 // Evaluate iterated item:
46184607 self . compile_expression ( & generators[ 0 ] . iter ) ?;
0 commit comments