@@ -40,6 +40,31 @@ impl CodeInfo {
4040 code. cellvars . extend ( cellvar_cache) ;
4141 code. freevars . extend ( freevar_cache) ;
4242
43+ if !code. cellvars . is_empty ( ) {
44+ let total_args = code. arg_count
45+ + code. kwonlyarg_count
46+ + code. flags . contains ( bytecode:: CodeFlags :: HAS_VARARGS ) as usize
47+ + code. flags . contains ( bytecode:: CodeFlags :: HAS_VARKEYWORDS ) as usize ;
48+ let all_args = & code. varnames [ ..total_args] ;
49+ let mut found_cellarg = false ;
50+ let cell2arg = code
51+ . cellvars
52+ . iter ( )
53+ . map ( |var| {
54+ for ( i, arg) in all_args. iter ( ) . enumerate ( ) {
55+ if var == arg {
56+ found_cellarg = true ;
57+ return i as isize ;
58+ }
59+ }
60+ -1
61+ } )
62+ . collect :: < Box < [ _ ] > > ( ) ;
63+ if found_cellarg {
64+ code. cell2arg = Some ( cell2arg) ;
65+ }
66+ }
67+
4368 for instruction in & mut code. instructions {
4469 use Instruction :: * ;
4570 // this is a little bit hacky, as until now the data stored inside Labels in
@@ -64,7 +89,7 @@ impl CodeInfo {
6489 }
6590
6691 #[ rustfmt:: skip]
67- Import { .. } | ImportStar | ImportFrom { .. } | LoadFast ( _) | LoadLocal ( _)
92+ Import { .. } | ImportStar | ImportFrom { .. } | LoadFast ( _) | LoadNameAny ( _)
6893 | LoadGlobal ( _) | LoadDeref ( _) | LoadClassDeref ( _) | StoreFast ( _) | StoreLocal ( _)
6994 | StoreGlobal ( _) | StoreDeref ( _) | DeleteFast ( _) | DeleteLocal ( _) | DeleteGlobal ( _)
7095 | DeleteDeref ( _) | LoadClosure ( _) | Subscript | StoreSubscript | DeleteSubscript
@@ -114,14 +139,14 @@ impl Default for CompileOpts {
114139 }
115140}
116141
117- #[ derive( Clone , Copy ) ]
142+ #[ derive( Debug , Clone , Copy ) ]
118143struct CompileContext {
119144 in_loop : bool ,
120145 in_class : bool ,
121146 func : FunctionContext ,
122147}
123148
124- #[ derive( Clone , Copy , PartialEq ) ]
149+ #[ derive( Debug , Clone , Copy , PartialEq ) ]
125150enum FunctionContext {
126151 NoFunction ,
127152 Function ,
@@ -130,7 +155,7 @@ enum FunctionContext {
130155
131156impl CompileContext {
132157 fn in_func ( self ) -> bool {
133- ! matches ! ( self . func, FunctionContext :: NoFunction )
158+ self . func != FunctionContext :: NoFunction
134159 }
135160}
136161
@@ -408,9 +433,8 @@ impl Compiler {
408433 cache = & mut info. varname_cache ;
409434 NameOpType :: Fast
410435 }
411- SymbolScope :: Local => NameOpType :: Local ,
412436 SymbolScope :: GlobalImplicit if self . ctx . in_func ( ) => NameOpType :: Global ,
413- SymbolScope :: GlobalImplicit => NameOpType :: Local ,
437+ SymbolScope :: Local | SymbolScope :: GlobalImplicit => NameOpType :: Local ,
414438 SymbolScope :: GlobalExplicit => NameOpType :: Global ,
415439 SymbolScope :: Free => {
416440 cache = & mut info. freevar_cache ;
@@ -423,9 +447,12 @@ impl Compiler {
423447 // TODO: is this right?
424448 SymbolScope :: Unknown => NameOpType :: Global ,
425449 } ;
426- let idx = cache
450+ let mut idx = cache
427451 . get_index_of ( name)
428452 . unwrap_or_else ( || cache. insert_full ( name. to_owned ( ) ) . 0 ) ;
453+ if let SymbolScope :: Free = symbol. scope {
454+ idx += info. cellvar_cache . len ( ) ;
455+ }
429456 let op = match op_typ {
430457 NameOpType :: Fast => match usage {
431458 NameUsage :: Load => Instruction :: LoadFast ,
@@ -438,12 +465,15 @@ impl Compiler {
438465 NameUsage :: Delete => Instruction :: DeleteGlobal ,
439466 } ,
440467 NameOpType :: Deref => match usage {
468+ NameUsage :: Load if !self . ctx . in_func ( ) && self . ctx . in_class => {
469+ Instruction :: LoadClassDeref
470+ }
441471 NameUsage :: Load => Instruction :: LoadDeref ,
442472 NameUsage :: Store => Instruction :: StoreDeref ,
443473 NameUsage :: Delete => Instruction :: DeleteDeref ,
444474 } ,
445475 NameOpType :: Local => match usage {
446- NameUsage :: Load => Instruction :: LoadLocal ,
476+ NameUsage :: Load => Instruction :: LoadNameAny ,
447477 NameUsage :: Store => Instruction :: StoreLocal ,
448478 NameUsage :: Delete => Instruction :: DeleteLocal ,
449479 } ,
@@ -844,17 +874,17 @@ impl Compiler {
844874 ) ) ;
845875
846876 for name in & args. args {
847- self . name ( & name. arg ) ;
877+ self . varname ( & name. arg ) ;
848878 }
849879 for name in & args. kwonlyargs {
850- self . name ( & name. arg ) ;
880+ self . varname ( & name. arg ) ;
851881 }
852882
853883 let mut compile_varargs = |va : & ast:: Varargs , flag| match va {
854884 ast:: Varargs :: None | ast:: Varargs :: Unnamed => { }
855885 ast:: Varargs :: Named ( name) => {
856886 self . current_code ( ) . flags |= flag;
857- self . name ( & name. arg ) ;
887+ self . varname ( & name. arg ) ;
858888 }
859889 } ;
860890
@@ -1002,6 +1032,10 @@ impl Compiler {
10021032 is_async : bool ,
10031033 ) -> CompileResult < ( ) > {
10041034 // Create bytecode for this function:
1035+
1036+ self . prepare_decorators ( decorator_list) ?;
1037+ self . enter_function ( name, args) ?;
1038+
10051039 // remember to restore self.ctx.in_loop to the original after the function is compiled
10061040 let prev_ctx = self . ctx ;
10071041
@@ -1019,10 +1053,6 @@ impl Compiler {
10191053 let old_qualified_path = self . current_qualified_path . take ( ) ;
10201054 self . current_qualified_path = Some ( self . create_qualified_name ( name, ".<locals>" ) ) ;
10211055
1022- self . prepare_decorators ( decorator_list) ?;
1023-
1024- self . enter_function ( name, args) ?;
1025-
10261056 let ( body, doc_str) = get_doc ( body) ;
10271057
10281058 self . compile_statements ( body) ?;
@@ -1090,26 +1120,7 @@ impl Compiler {
10901120 code. flags |= bytecode:: CodeFlags :: IS_COROUTINE ;
10911121 }
10921122
1093- if !code. freevars . is_empty ( ) {
1094- for var in & code. freevars {
1095- let symbol = self . symbol_table_stack . last ( ) . unwrap ( ) . lookup ( var) . unwrap ( ) ;
1096- let parent_code = self . code_stack . last ( ) . unwrap ( ) ;
1097- let vars = match symbol. scope {
1098- SymbolScope :: Free => & parent_code. freevar_cache ,
1099- SymbolScope :: Cell => & parent_code. cellvar_cache ,
1100- _ => unreachable ! ( ) ,
1101- } ;
1102- let mut idx = vars. get_index_of ( var) . unwrap ( ) ;
1103- if let SymbolScope :: Free = symbol. scope {
1104- idx += parent_code. cellvar_cache . len ( ) ;
1105- }
1106- self . emit ( Instruction :: LoadClosure ( idx) )
1107- }
1108- self . emit ( Instruction :: BuildTuple {
1109- size : code. freevars . len ( ) ,
1110- unpack : false ,
1111- } )
1112- }
1123+ self . build_closure ( & code) ;
11131124
11141125 self . emit_constant ( bytecode:: ConstantData :: Code {
11151126 code : Box :: new ( code) ,
@@ -1126,15 +1137,40 @@ impl Compiler {
11261137 self . emit ( Instruction :: Rotate { amount : 2 } ) ;
11271138 let doc = self . name ( "__doc__" ) ;
11281139 self . emit ( Instruction :: StoreAttr { idx : doc } ) ;
1140+
1141+ self . current_qualified_path = old_qualified_path;
1142+ self . ctx = prev_ctx;
1143+
11291144 self . apply_decorators ( decorator_list) ;
11301145
11311146 self . store_name ( name) ;
11321147
1133- self . current_qualified_path = old_qualified_path;
1134- self . ctx = prev_ctx;
11351148 Ok ( ( ) )
11361149 }
11371150
1151+ fn build_closure ( & mut self , code : & CodeObject ) {
1152+ if !code. freevars . is_empty ( ) {
1153+ for var in & code. freevars {
1154+ let symbol = self . symbol_table_stack . last ( ) . unwrap ( ) . lookup ( var) . unwrap ( ) ;
1155+ let parent_code = self . code_stack . last ( ) . unwrap ( ) ;
1156+ let vars = match symbol. scope {
1157+ SymbolScope :: Free => & parent_code. freevar_cache ,
1158+ SymbolScope :: Cell => & parent_code. cellvar_cache ,
1159+ _ => unreachable ! ( ) ,
1160+ } ;
1161+ let mut idx = vars. get_index_of ( var) . unwrap ( ) ;
1162+ if let SymbolScope :: Free = symbol. scope {
1163+ idx += parent_code. cellvar_cache . len ( ) ;
1164+ }
1165+ self . emit ( Instruction :: LoadClosure ( idx) )
1166+ }
1167+ self . emit ( Instruction :: BuildTuple {
1168+ size : code. freevars . len ( ) ,
1169+ unpack : false ,
1170+ } )
1171+ }
1172+ }
1173+
11381174 fn find_ann ( & self , body : & [ ast:: Statement ] ) -> bool {
11391175 use ast:: StatementType :: * ;
11401176 let option_stmt_to_bool = |suit : & Option < ast:: Suite > | -> bool {
@@ -1243,11 +1279,30 @@ impl Compiler {
12431279 self . emit ( Instruction :: SetupAnnotation ) ;
12441280 }
12451281 self . compile_statements ( new_body) ?;
1246- self . emit_constant ( bytecode:: ConstantData :: None ) ;
1282+
1283+ let classcell_idx = self
1284+ . code_stack
1285+ . last_mut ( )
1286+ . unwrap ( )
1287+ . cellvar_cache
1288+ . iter ( )
1289+ . position ( |var| * var == "__class__" ) ;
1290+
1291+ if let Some ( classcell_idx) = classcell_idx {
1292+ self . emit ( Instruction :: LoadClosure ( classcell_idx) ) ;
1293+ self . emit ( Instruction :: Duplicate ) ;
1294+ let classcell = self . name ( "__classcell__" ) ;
1295+ self . emit ( Instruction :: StoreLocal ( classcell) ) ;
1296+ } else {
1297+ self . emit_constant ( bytecode:: ConstantData :: None ) ;
1298+ }
1299+
12471300 self . emit ( Instruction :: ReturnValue ) ;
12481301
12491302 let code = self . pop_code_object ( ) ;
12501303
1304+ self . build_closure ( & code) ;
1305+
12511306 self . emit_constant ( bytecode:: ConstantData :: Code {
12521307 code : Box :: new ( code) ,
12531308 } ) ;
@@ -1526,7 +1581,7 @@ impl Compiler {
15261581 // Store as dict entry in __annotations__ dict:
15271582 if !self . ctx . in_func ( ) {
15281583 let annotations = self . name ( "__annotations__" ) ;
1529- self . emit ( Instruction :: LoadLocal ( annotations) ) ;
1584+ self . emit ( Instruction :: LoadNameAny ( annotations) ) ;
15301585 self . emit_constant ( bytecode:: ConstantData :: Str {
15311586 value : name. to_owned ( ) ,
15321587 } ) ;
@@ -1942,6 +1997,7 @@ impl Compiler {
19421997 self . compile_expression ( body) ?;
19431998 self . emit ( Instruction :: ReturnValue ) ;
19441999 let code = self . pop_code_object ( ) ;
2000+ self . build_closure ( & code) ;
19452001 self . emit_constant ( bytecode:: ConstantData :: Code {
19462002 code : Box :: new ( code) ,
19472003 } ) ;
@@ -2109,6 +2165,14 @@ impl Compiler {
21092165 kind : & ast:: ComprehensionKind ,
21102166 generators : & [ ast:: Comprehension ] ,
21112167 ) -> CompileResult < ( ) > {
2168+ let prev_ctx = self . ctx ;
2169+
2170+ self . ctx = CompileContext {
2171+ in_loop : false ,
2172+ in_class : prev_ctx. in_class ,
2173+ func : FunctionContext :: Function ,
2174+ } ;
2175+
21122176 // We must have at least one generator:
21132177 assert ! ( !generators. is_empty( ) ) ;
21142178
@@ -2252,6 +2316,10 @@ impl Compiler {
22522316 // Fetch code for listcomp function:
22532317 let code = self . pop_code_object ( ) ;
22542318
2319+ self . ctx = prev_ctx;
2320+
2321+ self . build_closure ( & code) ;
2322+
22552323 // List comprehension code:
22562324 self . emit_constant ( bytecode:: ConstantData :: Code {
22572325 code : Box :: new ( code) ,
0 commit comments