@@ -226,8 +226,10 @@ def accept(self, node: Node, type_context: Type = None) -> Type:
226226 else :
227227 return typ
228228
229- def accept_loop (self , body : Node , else_body : Node = None ) -> Type :
229+ def accept_loop (self , body : Node , else_body : Node = None , * ,
230+ exit_condition : Node = None ) -> Type :
230231 """Repeatedly type check a loop body until the frame doesn't change.
232+ If exit_condition is set, assume it must be False on exit from the loop.
231233
232234 Then check the else_body.
233235 """
@@ -240,6 +242,13 @@ def accept_loop(self, body: Node, else_body: Node = None) -> Type:
240242 if not self .binder .last_pop_changed :
241243 break
242244 self .binder .pop_loop_frame ()
245+ if exit_condition :
246+ _ , else_map = find_isinstance_check (
247+ exit_condition , self .type_map , self .typing_mode_weak ()
248+ )
249+ if else_map :
250+ for var , type in else_map .items ():
251+ self .binder .push (var , type )
243252 if else_body :
244253 self .accept (else_body )
245254
@@ -1465,7 +1474,8 @@ def visit_if_stmt(self, s: IfStmt) -> Type:
14651474
14661475 def visit_while_stmt (self , s : WhileStmt ) -> Type :
14671476 """Type check a while statement."""
1468- self .accept_loop (IfStmt ([s .expr ], [s .body ], None ), s .else_body )
1477+ self .accept_loop (IfStmt ([s .expr ], [s .body ], None ), s .else_body ,
1478+ exit_condition = s .expr )
14691479
14701480 def visit_operator_assignment_stmt (self ,
14711481 s : OperatorAssignmentStmt ) -> Type :
0 commit comments