@@ -32,6 +32,7 @@ public abstract class ScopeStatement : Statement {
3232 private List < string > _globalVars ; // global variables accessed from this scope
3333 private List < string > _cellVars ; // variables accessed from nested scopes
3434 private Dictionary < string , PythonReference > _references ; // names of all variables referenced, null after binding completes
35+ private Dictionary < string , NonlocalStatement > _nonlocalVars ; // nonlocal variables declared in this scope, null after binding completes
3536
3637 internal Dictionary < PythonVariable , MSAst . Expression > _variableMapping = new Dictionary < PythonVariable , MSAst . Expression > ( ) ;
3738 private readonly DelayedFunctionCode _funcCodeExpr = new DelayedFunctionCode ( ) ; // expression that refers to the function code for this scope
@@ -184,12 +185,20 @@ internal virtual IList<string> GetVarNames() {
184185
185186
186187 internal void AddFreeVariable ( PythonVariable variable , bool accessedInScope ) {
188+ Debug . Assert ( variable ? . Kind is VariableKind . Local or VariableKind . Parameter ) ;
189+
187190 if ( _freeVars == null ) {
188191 _freeVars = new List < PythonVariable > ( ) ;
189192 }
190193
191194 if ( ! _freeVars . Contains ( variable ) ) {
192195 _freeVars . Add ( variable ) ;
196+ if ( TryGetVariable ( variable . Name , out PythonVariable nonlocal ) &&
197+ nonlocal . Kind is VariableKind . Nonlocal &&
198+ nonlocal . MaybeDeleted ) {
199+
200+ variable . RegisterDeletion ( ) ;
201+ }
193202 }
194203 }
195204
@@ -331,6 +340,9 @@ internal virtual void Bind(PythonNameBinder binder) {
331340 if ( _references != null ) {
332341 foreach ( var reference in _references . Values ) {
333342 reference . PythonVariable = BindReference ( binder , reference ) ;
343+ if ( reference . PythonVariable is null && TryGetNonlocalStatement ( reference . Name , out NonlocalStatement node ) ) {
344+ binder . ReportSyntaxError ( $ "no binding for nonlocal '{ reference . Name } ' found", node ) ;
345+ }
334346 }
335347 }
336348 }
@@ -350,10 +362,10 @@ internal virtual void FinishBind(PythonNameBinder binder) {
350362 if ( FreeVariables != null && FreeVariables . Count > 0 ) {
351363 LocalParentTuple = Ast . Parameter ( Parent . GetClosureTupleType ( ) , "$tuple" ) ;
352364
353- foreach ( var variable in _freeVars ) {
354- var parentClosure = Parent . _closureVariables ;
355- Debug . Assert ( parentClosure != null ) ;
365+ var parentClosure = Parent . _closureVariables ;
366+ Debug . Assert ( parentClosure != null ) ;
356367
368+ foreach ( var variable in FreeVariables ) {
357369 for ( int i = 0 ; i < parentClosure . Length ; i ++ ) {
358370 if ( parentClosure [ i ] . Variable == variable ) {
359371 _variableMapping [ variable ] = new ClosureExpression ( variable , Ast . Property ( LocalParentTuple , String . Format ( "Item{0:D3}" , i ) ) , null ) ;
@@ -372,7 +384,10 @@ internal virtual void FinishBind(PythonNameBinder binder) {
372384 if ( Variables != null ) {
373385 foreach ( PythonVariable variable in Variables . Values ) {
374386 if ( ! HasClosureVariable ( closureVariables , variable ) &&
375- ! variable . IsGlobal && ( variable . AccessedInNestedScope || ExposesLocalVariable ( variable ) ) ) {
387+ ! variable . IsGlobal &&
388+ variable . Kind != VariableKind . Nonlocal &&
389+ ( variable . AccessedInNestedScope || ExposesLocalVariable ( variable ) ) ) {
390+
376391 if ( closureVariables == null ) {
377392 closureVariables = new List < ClosureInfo > ( ) ;
378393 }
@@ -397,6 +412,7 @@ internal virtual void FinishBind(PythonNameBinder binder) {
397412
398413 // no longer needed
399414 _references = null ;
415+ _nonlocalVars = null ;
400416 }
401417
402418 private static bool HasClosureVariable ( List < ClosureInfo > closureVariables , PythonVariable variable ) {
@@ -440,6 +456,15 @@ internal bool IsReferenced(string name) {
440456 return _references != null && _references . TryGetValue ( name , out reference ) ;
441457 }
442458
459+ internal bool IsFreeVariable ( PythonVariable variable ) {
460+ return FreeVariables ? . Contains ( variable ? . LimitVariable ) ?? false ;
461+ }
462+
463+ private bool TryGetNonlocalStatement ( string name , out NonlocalStatement node ) {
464+ node = null ;
465+ return _nonlocalVars ? . TryGetValue ( name , out node ) ?? false ;
466+ }
467+
443468 internal PythonVariable /*!*/ CreateVariable ( string name , VariableKind kind ) {
444469 EnsureVariables ( ) ;
445470 Debug . Assert ( ! Variables . ContainsKey ( name ) ) ;
@@ -456,6 +481,24 @@ internal bool IsReferenced(string name) {
456481 return variable ;
457482 }
458483
484+ private PythonVariable CreateNonlocalVariable ( string name ) {
485+ EnsureVariables ( ) ;
486+ Debug . Assert ( ! Variables . ContainsKey ( name ) ) ;
487+ Debug . Assert ( ! IsReferenced ( name ) ) ;
488+ PythonReference reference = Reference ( name ) ;
489+ PythonVariable variable ;
490+ Variables [ name ] = variable = new PythonReferenceVariable ( reference , this ) ;
491+ return variable ;
492+ }
493+
494+ internal void EnsureNonlocalVariable ( string name , NonlocalStatement node ) {
495+ _nonlocalVars ??= new ( ) ;
496+ if ( ! _nonlocalVars . ContainsKey ( name ) ) {
497+ CreateNonlocalVariable ( name ) ;
498+ _nonlocalVars [ name ] = node ;
499+ }
500+ }
501+
459502 internal PythonVariable DefineParameter ( string name ) {
460503 return CreateVariable ( name , VariableKind . Parameter ) ;
461504 }
@@ -656,18 +699,19 @@ private MSAst.Expression GetClosureCell(ClosureInfo variable) {
656699 }
657700
658701 internal virtual MSAst . Expression GetVariableExpression ( PythonVariable variable ) {
702+ Assert . NotNull ( variable ? . LimitVariable ) ;
659703 if ( variable . IsGlobal ) {
660704 return GlobalParent . ModuleVariables [ variable ] ;
661705 }
662706
663- Debug . Assert ( _variableMapping . ContainsKey ( variable ) ) ;
664- return _variableMapping [ variable ] ;
707+ Debug . Assert ( _variableMapping . ContainsKey ( variable . LimitVariable ) ) ;
708+ return _variableMapping [ variable . LimitVariable ] ;
665709 }
666710
667711 internal void CreateVariables ( ReadOnlyCollectionBuilder < MSAst . ParameterExpression > locals , List < MSAst . Expression > init ) {
668712 if ( Variables != null ) {
669713 foreach ( PythonVariable variable in Variables . Values ) {
670- if ( variable . Kind != VariableKind . Global ) {
714+ if ( variable . Kind is VariableKind . Local or VariableKind . Parameter ) {
671715 if ( GetVariableExpression ( variable ) is ClosureExpression closure ) {
672716 init . Add ( closure . Create ( ) ) ;
673717 locals . Add ( ( MSAst . ParameterExpression ) closure . ClosureCell ) ;
0 commit comments