@@ -903,23 +903,23 @@ def bind(cls):
903903 cls .method ("name_handle" , assign = True , is_final = True ),
904904 greedy = True ,
905905 )
906- cls .nonfinal_funcname <<= attach (
906+ cls .nonfinal_outer_setname <<= attach (
907907 cls .name_ref ,
908- cls .method ("name_handle" , assign = True , funcname = True ),
908+ cls .method ("name_handle" , assign = True , outer_setname = True ),
909909 )
910- cls .final_funcname <<= attach (
910+ cls .final_outer_setname <<= attach (
911911 cls .final_setname_ref ,
912- cls .method ("name_handle" , assign = True , funcname = True , is_final = True ),
912+ cls .method ("name_handle" , assign = True , outer_setname = True , is_final = True ),
913913 greedy = True ,
914914 )
915915 cls .nonfinal_classname <<= attach (
916916 cls .name_ref ,
917- cls .method ("name_handle" , assign = True , classname = True ),
917+ cls .method ("name_handle" , assign = True , outer_setname = True , classname = True ),
918918 greedy = True ,
919919 )
920920 cls .final_classname <<= attach (
921921 cls .final_setname_ref ,
922- cls .method ("name_handle" , assign = True , classname = True , is_final = True ),
922+ cls .method ("name_handle" , assign = True , outer_setname = True , classname = True , is_final = True ),
923923 greedy = True ,
924924 )
925925 cls .expr_setname <<= attach (
@@ -4072,7 +4072,7 @@ def ensure_module_or_create_fake(self, mod_name):
40724072 type_ignore = self .type_ignore_comment (),
40734073 )
40744074
4075- def _make_import_stmt (self , imp_from , imp , imp_as , raw = False , lazy = False ):
4075+ def make_import_stmt (self , imp_from , imp , imp_as , raw = False , lazy = False ):
40764076 """Generate an import statement."""
40774077 if not raw and imp != "*" :
40784078 module_path = (imp if imp_from is None else imp_from ).split ("." , 1 )
@@ -4089,7 +4089,7 @@ def _make_import_stmt(self, imp_from, imp, imp_as, raw=False, lazy=False):
40894089 raise _coconut.ImportError(_coconut.str(_coconut_imp_err))
40904090 """ ,
40914091 ).format (
4092- raw_import = self ._make_import_stmt (imp_from , imp , imp_as , raw = True ),
4092+ raw_import = self .make_import_stmt (imp_from , imp , imp_as , raw = True ),
40934093 imp_name = imp_as if imp_as is not None else imp ,
40944094 imp_lookup = "." .join ([existing_imp ] + module_path [1 :] + ([imp ] if imp_from is not None else [])),
40954095 )
@@ -4135,14 +4135,14 @@ def single_import(self, loc, path, imp_as, type_ignore=False, lazy=False):
41354135
41364136 if imp_as is not None and "." in imp_as :
41374137 import_as_var = self .get_temp_var ("import" , loc )
4138- out .append (self ._make_import_stmt (imp_from , imp , import_as_var , lazy = lazy ))
4138+ out .append (self .make_import_stmt (imp_from , imp , import_as_var , lazy = lazy ))
41394139 fake_mods = imp_as .split ("." )
41404140 for i in range (1 , len (fake_mods )):
41414141 mod_name = "." .join (fake_mods [:i ])
41424142 out .append (self .ensure_module_or_create_fake (mod_name ))
41434143 out .append ("." .join (fake_mods ) + " = " + import_as_var )
41444144 else :
4145- out .append (self ._make_import_stmt (imp_from , imp , imp_as , lazy = lazy ))
4145+ out .append (self .make_import_stmt (imp_from , imp , imp_as , lazy = lazy ))
41464146
41474147 if type_ignore :
41484148 for i , line in enumerate (out ):
@@ -4593,7 +4593,7 @@ def stmt_lambdef_handle(self, original, loc, tokens):
45934593
45944594 self .add_code_before [name ] = self .decoratable_funcdef_stmt_handle (original , loc , [decorators , funcdef ], is_async , is_stmt_lambda = True )
45954595
4596- return self ._handle_expr_scope_closure (name , loc )
4596+ return self .handle_expr_scope_closure (name , loc )
45974597
45984598 def match_comp_expr_handle (self , original , loc , tokens , dict_val = None ):
45994599 """Build a match comprehension by creating a temp match function.
@@ -4633,26 +4633,31 @@ def {func_name}({iter_var}):
46334633
46344634 self .add_code_before [func_name ] = self .decoratable_funcdef_stmt_handle (original , loc , [funcdef ], is_stmt_lambda = True )
46354635
4636- func_expr = self ._handle_expr_scope_closure (func_name , loc )
4636+ func_expr = self .handle_expr_scope_closure (func_name , loc )
46374637
46384638 if dict_val is not None :
46394639 return "_coconut.dict((" + func_expr + "(" + iter_var + ") for " + iter_var + " in " + iterable + "))"
46404640 else :
46414641 return func_expr + "(" + iter_var + ") for " + iter_var + " in " + iterable
46424642
4643- def _handle_expr_scope_closure (self , name , loc ):
4643+ def get_parent_expr_setnames (self ):
4644+ """Get all expr_setnames in parent contexts, but not the current context."""
4645+ expr_setname_context = self .current_parsing_context ("expr_setnames" )
4646+ parent_context = expr_setname_context ["parent" ]
4647+ parent_setnames = set ()
4648+ while parent_context :
4649+ parent_setnames |= parent_context ["new_names" ]
4650+ parent_context = parent_context ["parent" ]
4651+ return parent_setnames
4652+
4653+ def handle_expr_scope_closure (self , name , loc ):
46444654 """Extracts the definition of a name to a separate function that closes on all local expr setnames."""
46454655 expr_setname_context = self .current_parsing_context ("expr_setnames" )
46464656 if expr_setname_context is None :
46474657 return name
46484658 else :
46494659 builder_name = self .get_temp_var ("lambda_builder" , loc )
4650-
4651- parent_context = expr_setname_context ["parent" ]
4652- parent_setnames = set ()
4653- while parent_context :
4654- parent_setnames |= parent_context ["new_names" ]
4655- parent_context = parent_context ["parent" ]
4660+ parent_setnames = self .get_parent_expr_setnames ()
46564661
46574662 def stmt_lambdef_callback ():
46584663 expr_setnames = parent_setnames | expr_setname_context ["new_names" ]
@@ -5583,12 +5588,14 @@ def has_expr_setname_manage(self, original, loc, item):
55835588 ):
55845589 yield
55855590
5586- def name_handle (self , original , loc , tokens , assign = False , classname = False , funcname = False , expr_setname = False , is_final = False ):
5591+ def name_handle (self , original , loc , tokens , assign = False , outer_setname = False , expr_setname = False , classname = False , is_final = False ):
55875592 """Handle the given base name."""
5588- if classname or funcname or expr_setname :
5589- internal_assert (assign , "classname/funcname/expr_setname should always imply assign" , (classname , funcname , expr_setname , assign ))
5593+ if classname :
5594+ internal_assert (outer_setname and not expr_setname , "classname should always imply outer_setname" , tokens )
5595+ if outer_setname or expr_setname :
5596+ internal_assert (assign , "classname/funcname/expr_setname should always imply assign" , tokens )
55905597 if is_final :
5591- internal_assert (assign and not expr_setname , "only setnames should ever be final" , ( assign , is_final ) )
5598+ internal_assert (assign and not expr_setname , "only setnames should ever be final" , tokens )
55925599
55935600 name , = tokens
55945601
@@ -5609,24 +5616,6 @@ def name_handle(self, original, loc, tokens, assign=False, classname=False, func
56095616 always_wrap = is_greedy ,
56105617 )
56115618
5612- # register non-mid-expression variable assignments inside of where statements for later mangling
5613- if assign and not expr_setname :
5614- where_context = self .current_parsing_context ("where" )
5615- if where_context is not None :
5616- where_assigns = where_context ["assigns" ]
5617- if where_assigns is not None :
5618- where_assigns .add (name )
5619-
5620- if classname :
5621- cls_context = self .current_parsing_context ("class" )
5622- self .internal_assert (cls_context is not None , original , loc , "found classname outside of class" , tokens )
5623- cls_context ["name" ] = name
5624-
5625- if expr_setname :
5626- expr_setnames_context = self .current_parsing_context ("expr_setnames" )
5627- self .internal_assert (expr_setnames_context is not None , original , loc , "found expr_setname outside of has_expr_setname_manage" , tokens )
5628- expr_setnames_context ["new_names" ].add (name )
5629-
56305619 if not escaped :
56315620 typevar_info = self .current_parsing_context ("typevars" )
56325621 if typevar_info is not None :
@@ -5647,6 +5636,25 @@ def name_handle(self, original, loc, tokens, assign=False, classname=False, func
56475636 # note that this is the one case where we return early that isn't an error
56485637 return typevars [name ]
56495638
5639+ # register non-mid-expression variable assignments inside of where statements for later mangling
5640+ if assign and not expr_setname :
5641+ where_context = self .current_parsing_context ("where" )
5642+ if where_context is not None :
5643+ where_assigns = where_context ["assigns" ]
5644+ if where_assigns is not None :
5645+ where_assigns .add (name )
5646+
5647+ cls_context = self .current_parsing_context ("class" )
5648+ expr_setnames_context = self .current_parsing_context ("expr_setnames" )
5649+
5650+ if classname :
5651+ self .internal_assert (cls_context is not None , original , loc , "found classname outside of class" , tokens )
5652+ cls_context ["name" ] = name
5653+
5654+ if expr_setname :
5655+ self .internal_assert (expr_setnames_context is not None , original , loc , "found expr_setname outside of has_expr_setname_manage" , tokens )
5656+ expr_setnames_context ["new_names" ].add (name )
5657+
56505658 scope = self .current_parsing_context ("scope" )
56515659 self .internal_assert (scope is not None , original , loc , "no scope context" )
56525660
@@ -5656,12 +5664,12 @@ def name_handle(self, original, loc, tokens, assign=False, classname=False, func
56565664 is_new = loc not in self .name_info [name ]["assigned" ]
56575665 self .name_info [name ]["assigned" ].add (loc )
56585666 if (
5659- ( classname or funcname )
5667+ outer_setname
56605668 and scope ["parent" ] is not None
56615669 and scope ["parent" ]["all_vars" ] is not None
56625670 ):
56635671 scope ["parent" ]["all_vars" ].add (name )
5664- elif scope ["all_vars" ] is not None :
5672+ elif not expr_setname and scope ["all_vars" ] is not None :
56655673 scope ["all_vars" ].add (name )
56665674 else :
56675675 is_new = loc not in self .name_info [name ]["referenced" ]
@@ -5716,7 +5724,7 @@ def name_handle(self, original, loc, tokens, assign=False, classname=False, func
57165724
57175725 is_class_attr = (
57185726 assign
5719- and self . current_parsing_context ( "class" )
5727+ and cls_context
57205728 and not self .in_method
57215729 and (
57225730 # for classnames, we need special handling for nested classes
@@ -5758,7 +5766,7 @@ def name_handle(self, original, loc, tokens, assign=False, classname=False, func
57585766 # the import statement itself, not an assignment shadowing an import
57595767 if any (not same_line (original , loc , imp_loc ) for imp_loc in self .name_info [name ]["imported" ]):
57605768 err = self .strict_err_or_warn (
5761- "assignment shadows import '{name}' (use explicit '\\ {name}' syntax when purposefully redefining imported names)" .format (name = name ),
5769+ "assignment shadows imported '{name}' (use explicit '\\ {name}' syntax when purposefully redefining imported names)" .format (name = name ),
57625770 original ,
57635771 loc ,
57645772 raise_err_func = local_raise_or_wrap_error ,
@@ -5774,6 +5782,11 @@ def name_handle(self, original, loc, tokens, assign=False, classname=False, func
57745782 and not self .star_import
57755783 and scope ["all_vars" ] is not None
57765784 and name not in all_builtins
5785+ and name != wildcard
5786+ and (expr_setnames_context is None or (
5787+ name not in expr_setnames_context ["new_names" ]
5788+ and name not in self .get_parent_expr_setnames ()
5789+ ))
57775790 ):
57785791 self .final_checks .append (partial (self .check_undefined_name , original , loc , name , scope , self .outer_ln ))
57795792
@@ -5806,7 +5819,6 @@ def name_handle(self, original, loc, tokens, assign=False, classname=False, func
58065819 return "_coconut_exec"
58075820 elif not assign and name in super_names and not self .target .startswith ("3" ):
58085821 if self .in_method :
5809- cls_context = self .current_parsing_context ("class" )
58105822 enclosing_cls = cls_context ["name_prefix" ] + cls_context ["name" ]
58115823 return self .add_code_before_marker_with_replacement (name , "__class__ = " + enclosing_cls + "\n " , add_spaces = False )
58125824 else :
0 commit comments