@@ -911,9 +911,9 @@ def visit_block(self, b: Block) -> Type:
911
911
if b .is_unreachable :
912
912
return None
913
913
for s in b .body :
914
- self .accept (s )
915
- if self .binder .breaking_out :
914
+ if self .binder .is_unreachable ():
916
915
break
916
+ self .accept (s )
917
917
918
918
def visit_assignment_stmt (self , s : AssignmentStmt ) -> Type :
919
919
"""Type check an assignment statement.
@@ -1354,7 +1354,10 @@ def visit_expression_stmt(self, s: ExpressionStmt) -> Type:
1354
1354
1355
1355
def visit_return_stmt (self , s : ReturnStmt ) -> Type :
1356
1356
"""Type check a return statement."""
1357
- self .binder .breaking_out = True
1357
+ self .check_return_stmt (s )
1358
+ self .binder .unreachable ()
1359
+
1360
+ def check_return_stmt (self , s : ReturnStmt ) -> None :
1358
1361
if self .is_within_function ():
1359
1362
if self .function_stack [- 1 ].is_generator :
1360
1363
return_type = self .get_generator_return_type (self .return_types [- 1 ])
@@ -1422,7 +1425,6 @@ def count_nested_types(self, typ: Instance, check_type: str) -> int:
1422
1425
1423
1426
def visit_if_stmt (self , s : IfStmt ) -> Type :
1424
1427
"""Type check an if statement."""
1425
- breaking_out = True
1426
1428
# This frame records the knowledge from previous if/elif clauses not being taken.
1427
1429
with self .binder .frame_context ():
1428
1430
for e , b in zip (s .expr , s .body ):
@@ -1444,7 +1446,6 @@ def visit_if_stmt(self, s: IfStmt) -> Type:
1444
1446
self .binder .push (var , type )
1445
1447
1446
1448
self .accept (b )
1447
- breaking_out = breaking_out and self .binder .last_pop_breaking_out
1448
1449
1449
1450
if else_map :
1450
1451
for var , type in else_map .items ():
@@ -1460,9 +1461,6 @@ def visit_if_stmt(self, s: IfStmt) -> Type:
1460
1461
with self .binder .frame_context (2 ):
1461
1462
if s .else_body :
1462
1463
self .accept (s .else_body )
1463
- breaking_out = breaking_out and self .binder .last_pop_breaking_out
1464
- if breaking_out :
1465
- self .binder .breaking_out = True
1466
1464
return None
1467
1465
1468
1466
def visit_while_stmt (self , s : WhileStmt ) -> Type :
@@ -1498,11 +1496,11 @@ def visit_assert_stmt(self, s: AssertStmt) -> Type:
1498
1496
1499
1497
def visit_raise_stmt (self , s : RaiseStmt ) -> Type :
1500
1498
"""Type check a raise statement."""
1501
- self .binder .breaking_out = True
1502
1499
if s .expr :
1503
1500
self .type_check_raise (s .expr , s )
1504
1501
if s .from_expr :
1505
1502
self .type_check_raise (s .from_expr , s )
1503
+ self .binder .unreachable ()
1506
1504
1507
1505
def type_check_raise (self , e : Node , s : RaiseStmt ) -> None :
1508
1506
typ = self .accept (e )
@@ -1535,28 +1533,26 @@ def visit_try_stmt(self, s: TryStmt) -> Type:
1535
1533
with self .binder .frame_context ():
1536
1534
if s .finally_body :
1537
1535
self .binder .try_frames .add (len (self .binder .frames ) - 1 )
1538
- breaking_out = self .visit_try_without_finally (s )
1536
+ self .visit_try_without_finally (s )
1539
1537
self .binder .try_frames .remove (len (self .binder .frames ) - 1 )
1540
1538
# First we check finally_body is type safe for all intermediate frames
1541
1539
self .accept (s .finally_body )
1542
- breaking_out = breaking_out or self .binder .breaking_out
1543
1540
else :
1544
- breaking_out = self .visit_try_without_finally (s )
1541
+ self .visit_try_without_finally (s )
1545
1542
1546
- if not breaking_out and s .finally_body :
1543
+ if s .finally_body :
1547
1544
# Then we try again for the more restricted set of options that can fall through
1548
1545
self .accept (s .finally_body )
1549
- self . binder . breaking_out = breaking_out
1546
+
1550
1547
return None
1551
1548
1552
- def visit_try_without_finally (self , s : TryStmt ) -> bool :
1549
+ def visit_try_without_finally (self , s : TryStmt ) -> None :
1553
1550
"""Type check a try statement, ignoring the finally block.
1554
1551
1555
1552
Return whether we are guaranteed to be breaking out.
1556
1553
Otherwise, it will place the results possible frames of
1557
1554
that don't break out into self.binder.frames[-2].
1558
1555
"""
1559
- breaking_out = True
1560
1556
# This frame records the possible states that exceptions can leave variables in
1561
1557
# during the try: block
1562
1558
with self .binder .frame_context ():
@@ -1566,7 +1562,6 @@ def visit_try_without_finally(self, s: TryStmt) -> bool:
1566
1562
self .binder .try_frames .remove (len (self .binder .frames ) - 2 )
1567
1563
if s .else_body :
1568
1564
self .accept (s .else_body )
1569
- breaking_out = breaking_out and self .binder .last_pop_breaking_out
1570
1565
for i in range (len (s .handlers )):
1571
1566
with self .binder .frame_context (3 ):
1572
1567
if s .types [i ]:
@@ -1592,8 +1587,6 @@ def visit_try_without_finally(self, s: TryStmt) -> bool:
1592
1587
var = cast (Var , s .vars [i ].node )
1593
1588
var .type = DeletedType (source = source )
1594
1589
self .binder .cleanse (s .vars [i ])
1595
- breaking_out = breaking_out and self .binder .last_pop_breaking_out
1596
- return breaking_out
1597
1590
1598
1591
def visit_except_handler_test (self , n : Node ) -> Type :
1599
1592
"""Type check an exception handler test clause."""
@@ -1811,13 +1804,13 @@ def visit_member_expr(self, e: MemberExpr) -> Type:
1811
1804
return self .expr_checker .visit_member_expr (e )
1812
1805
1813
1806
def visit_break_stmt (self , s : BreakStmt ) -> Type :
1814
- self .binder .breaking_out = True
1815
1807
self .binder .allow_jump (self .binder .loop_frames [- 1 ] - 1 )
1808
+ self .binder .unreachable ()
1816
1809
return None
1817
1810
1818
1811
def visit_continue_stmt (self , s : ContinueStmt ) -> Type :
1819
- self .binder .breaking_out = True
1820
1812
self .binder .allow_jump (self .binder .loop_frames [- 1 ])
1813
+ self .binder .unreachable ()
1821
1814
return None
1822
1815
1823
1816
def visit_int_expr (self , e : IntExpr ) -> Type :
0 commit comments