@@ -1539,18 +1539,45 @@ def type_check_raise(self, e: Node, s: RaiseStmt) -> None:
1539
1539
1540
1540
def visit_try_stmt (self , s : TryStmt ) -> Type :
1541
1541
"""Type check a try statement."""
1542
+ # Our enclosing frame will get the result if the try/except falls through.
1543
+ # This one gets all possible intermediate states
1544
+ with self .binder .frame_context ():
1545
+ if s .finally_body :
1546
+ self .binder .try_frames .add (len (self .binder .frames ) - 1 )
1547
+ broken = self .visit_try_without_finally (s )
1548
+ self .binder .try_frames .remove (len (self .binder .frames ) - 1 )
1549
+ # First we check finally_body is type safe for all intermediate frames
1550
+ self .accept (s .finally_body )
1551
+ broken = broken or self .binder .breaking_out
1552
+ else :
1553
+ broken = self .visit_try_without_finally (s )
1554
+
1555
+ if not broken and s .finally_body :
1556
+ # Then we try again for the more restricted set of options that can fall through
1557
+ self .accept (s .finally_body )
1558
+ self .binder .breaking_out = broken
1559
+ return None
1560
+
1561
+ def visit_try_without_finally (self , s : TryStmt ) -> bool :
1562
+ """Type check a try statement, ignoring the finally block.
1563
+
1564
+ Return whether we are guaranteed to be breaking out.
1565
+ Otherwise, it will place the results possible frames of
1566
+ that don't break out into self.binder.frames[-2].
1567
+ """
1542
1568
broken = True
1543
1569
# This frame records the possible states that exceptions can leave variables in
1570
+ # during the try: block
1544
1571
with self .binder .frame_context ():
1545
- with self .binder .frame_context (2 ) as frame :
1572
+ with self .binder .frame_context (3 ) as frame :
1546
1573
self .binder .try_frames .add (len (self .binder .frames ) - 2 )
1547
1574
self .accept (s .body )
1548
1575
self .binder .try_frames .remove (len (self .binder .frames ) - 2 )
1549
1576
if s .else_body :
1550
1577
self .accept (s .else_body )
1551
1578
broken = broken and frame .broken
1552
1579
for i in range (len (s .handlers )):
1553
- with self .binder .frame_context (2 ) as frame :
1580
+ with self .binder .frame_context (3 ) as frame :
1554
1581
if s .types [i ]:
1555
1582
t = self .visit_except_handler_test (s .types [i ])
1556
1583
if s .vars [i ]:
@@ -1575,11 +1602,7 @@ def visit_try_stmt(self, s: TryStmt) -> Type:
1575
1602
var .type = DeletedType (source = source )
1576
1603
self .binder .cleanse (s .vars [i ])
1577
1604
broken = broken and frame .broken
1578
-
1579
- if s .finally_body :
1580
- self .accept (s .finally_body )
1581
- if broken :
1582
- self .binder .breaking_out = True
1605
+ return broken
1583
1606
1584
1607
def visit_except_handler_test (self , n : Node ) -> Type :
1585
1608
"""Type check an exception handler test clause."""
0 commit comments