@@ -35,6 +35,7 @@ use crate::binding::binding::KeyExpect;
35
35
use crate :: binding:: binding:: LinkedKey ;
36
36
use crate :: binding:: binding:: RaisedException ;
37
37
use crate :: binding:: bindings:: BindingsBuilder ;
38
+ use crate :: binding:: bindings:: LookupKind ;
38
39
use crate :: binding:: bindings:: MutableCaptureLookupKind ;
39
40
use crate :: binding:: expr:: Usage ;
40
41
use crate :: binding:: narrow:: NarrowOps ;
@@ -247,6 +248,25 @@ impl<'a> BindingsBuilder<'a> {
247
248
self . scopes . mark_flow_termination ( ) ;
248
249
}
249
250
251
+ fn mark_exception_name_uninitialized ( & mut self , name : & Identifier ) {
252
+ // https://docs.python.org/3/reference/compound_stmts.html#except-clause
253
+ // Mark the handler name as uninitialized, so that it can't be used.
254
+ let idx = self . lookup_name (
255
+ Hashed :: new ( & name. id ) ,
256
+ LookupKind :: Regular ,
257
+ & mut Usage :: MutableLookup ,
258
+ ) ;
259
+ if let Ok ( idx) = idx {
260
+ self . scopes . upsert_flow_info (
261
+ Hashed :: new ( & name. id ) ,
262
+ idx,
263
+ Some ( FlowStyle :: Uninitialized ) ,
264
+ ) ;
265
+ } else {
266
+ panic ! ( "Should have found the exception name `{name}` in the current scope" ) ;
267
+ }
268
+ }
269
+
250
270
/// Evaluate the statements and update the bindings.
251
271
/// Every statement should end up in the bindings, perhaps with a location that is never used.
252
272
pub fn stmt ( & mut self , x : Stmt ) {
@@ -731,8 +751,12 @@ impl<'a> BindingsBuilder<'a> {
731
751
self . scopes . swap_current_flow_with ( & mut base) ;
732
752
branches. push ( base) ;
733
753
734
- // Store the last name of the exception, so that we can mark it uninitialized in the next scope.
735
- let mut last_name: Option < Identifier > = None ;
754
+ // Store the last caught exception name, so that we can mark any
755
+ // caught exception to be uninitialized at the end of an
756
+ // `except` block, and at the beginning of the next block. This
757
+ // allows us to ensure that the caught exception name goes out
758
+ // of scope after the corresponding `except` block.
759
+ let mut last_caught_exception_name: Option < Identifier > = None ;
736
760
737
761
for h in x. handlers {
738
762
base = self . scopes . clone_current_flow ( ) ;
@@ -758,49 +782,38 @@ impl<'a> BindingsBuilder<'a> {
758
782
Binding :: ExceptionHandler ( type_, x. is_star ) ,
759
783
) ;
760
784
}
761
- if let Some ( ref name) = last_name {
785
+
786
+ if let Some ( ref name) = last_caught_exception_name {
762
787
// https://docs.python.org/3/reference/compound_stmts.html#except-clause
763
- // Mark the previous handler name as uninitialized in
764
- // the current scope, so that it can't be used.
765
- let idx = self . lookup_name ( Hashed :: new ( & name. id ) , LookupKind :: Regular ) ;
766
- if let Ok ( idx) = idx {
767
- self . scopes . upsert_flow_info (
768
- Hashed :: new ( & name. id ) ,
769
- idx,
770
- Some ( FlowStyle :: Uninitialized ) ,
771
- ) ;
772
- } else {
773
- panic ! (
774
- "Should have found the handler name {name} in the current scope"
775
- ) ;
776
- }
788
+ // Mark the previous caught exception name as
789
+ // uninitialized in the current scope, so that it can't
790
+ // be used.
791
+ self . mark_exception_name_uninitialized ( name) ;
777
792
}
778
793
self . stmts ( h. body ) ;
794
+
795
+ if let Some ( ref name) = h. name {
796
+ // Mark the current caught exception name as
797
+ // uninitialized in the current scope, so that the flow
798
+ // merges correctly.
799
+ self . mark_exception_name_uninitialized ( name) ;
800
+ }
801
+
779
802
self . scopes . swap_current_flow_with ( & mut base) ;
780
803
781
804
if let Some ( name) = h. name {
782
- last_name = Some ( name. clone ( ) ) ;
805
+ last_caught_exception_name = Some ( name. clone ( ) ) ;
783
806
} else {
784
- last_name = None ;
807
+ last_caught_exception_name = None ;
785
808
}
786
809
branches. push ( base) ;
787
810
}
788
811
789
812
self . set_current_flow_to_merged_branches ( branches, range) ;
790
- if let Some ( ref name) = last_name {
791
- // https://docs.python.org/3/reference/compound_stmts.html#except-clause
792
- // Mark the previous handler name as uninitialized in
813
+ if let Some ( ref name) = last_caught_exception_name {
814
+ // Mark the last caught exception name as uninitialized in
793
815
// the current scope, so that it can't be used.
794
- let idx = self . lookup_name ( Hashed :: new ( & name. id ) , LookupKind :: Regular ) ;
795
- if let Ok ( idx) = idx {
796
- self . scopes . upsert_flow_info (
797
- Hashed :: new ( & name. id ) ,
798
- idx,
799
- Some ( FlowStyle :: Uninitialized ) ,
800
- ) ;
801
- } else {
802
- panic ! ( "Should have found the handler name {name} in the current scope" ) ;
803
- }
816
+ self . mark_exception_name_uninitialized ( name) ;
804
817
}
805
818
self . stmts ( x. finalbody ) ;
806
819
}
0 commit comments