1
- from typing import Dict , List
1
+ from contextlib import contextmanager
2
+ from typing import Dict , Iterator , List
2
3
from typing_extensions import Final
3
4
4
5
from mypy .nodes import (
@@ -74,61 +75,47 @@ def visit_mypy_file(self, file_node: MypyFile) -> None:
74
75
This is the main entry point to this class.
75
76
"""
76
77
self .clear ()
77
- self .enter_scope (FILE )
78
- self .enter_block ()
79
-
80
- for d in file_node .defs :
81
- d .accept (self )
82
-
83
- self .leave_block ()
84
- self .leave_scope ()
78
+ with self .enter_scope (FILE ), self .enter_block ():
79
+ for d in file_node .defs :
80
+ d .accept (self )
85
81
86
82
def visit_func_def (self , fdef : FuncDef ) -> None :
87
83
# Conservatively do not allow variable defined before a function to
88
84
# be redefined later, since function could refer to either definition.
89
85
self .reject_redefinition_of_vars_in_scope ()
90
86
91
- self .enter_scope (FUNCTION )
92
- self .enter_block ()
93
-
94
- for arg in fdef .arguments :
95
- name = arg .variable .name
96
- # 'self' can't be redefined since it's special as it allows definition of
97
- # attributes. 'cls' can't be used to define attributes so we can ignore it.
98
- can_be_redefined = name != 'self' # TODO: Proper check
99
- self .record_assignment (arg .variable .name , can_be_redefined )
100
- self .handle_arg (name )
87
+ with self .enter_scope (FUNCTION ), self .enter_block ():
88
+ for arg in fdef .arguments :
89
+ name = arg .variable .name
90
+ # 'self' can't be redefined since it's special as it allows definition of
91
+ # attributes. 'cls' can't be used to define attributes so we can ignore it.
92
+ can_be_redefined = name != 'self' # TODO: Proper check
93
+ self .record_assignment (arg .variable .name , can_be_redefined )
94
+ self .handle_arg (name )
101
95
102
- for stmt in fdef .body .body :
103
- stmt .accept (self )
104
-
105
- self .leave_block ()
106
- self .leave_scope ()
96
+ for stmt in fdef .body .body :
97
+ stmt .accept (self )
107
98
108
99
def visit_class_def (self , cdef : ClassDef ) -> None :
109
100
self .reject_redefinition_of_vars_in_scope ()
110
- self .enter_scope (CLASS )
111
- super ().visit_class_def (cdef )
112
- self .leave_scope ()
101
+ with self .enter_scope (CLASS ):
102
+ super ().visit_class_def (cdef )
113
103
114
104
def visit_block (self , block : Block ) -> None :
115
- self .enter_block ()
116
- super ().visit_block (block )
117
- self .leave_block ()
105
+ with self .enter_block ():
106
+ super ().visit_block (block )
118
107
119
108
def visit_while_stmt (self , stmt : WhileStmt ) -> None :
120
- self .enter_loop ()
121
- super ().visit_while_stmt (stmt )
122
- self .leave_loop ()
109
+ with self .enter_loop ():
110
+ super ().visit_while_stmt (stmt )
123
111
124
112
def visit_for_stmt (self , stmt : ForStmt ) -> None :
125
113
stmt .expr .accept (self )
126
114
self .analyze_lvalue (stmt .index , True )
127
115
# Also analyze as non-lvalue so that every for loop index variable is assumed to be read.
128
116
stmt .index .accept (self )
129
- self .enter_loop ()
130
- stmt .body .accept (self )
131
- self .leave_loop ()
117
+ with self .enter_loop ():
118
+ stmt .body .accept (self )
132
119
if stmt .else_body :
133
120
stmt .else_body .accept (self )
134
121
@@ -142,9 +129,8 @@ def visit_try_stmt(self, stmt: TryStmt) -> None:
142
129
# Variables defined by a try statement get special treatment in the
143
130
# type checker which allows them to be always redefined, so no need to
144
131
# do renaming here.
145
- self .enter_try ()
146
- super ().visit_try_stmt (stmt )
147
- self .leave_try ()
132
+ with self .enter_try ():
133
+ super ().visit_try_stmt (stmt )
148
134
149
135
def visit_with_stmt (self , stmt : WithStmt ) -> None :
150
136
for expr in stmt .expr :
@@ -275,40 +261,48 @@ def clear(self) -> None:
275
261
self .blocks = []
276
262
self .var_blocks = []
277
263
278
- def enter_block (self ) -> None :
264
+ @contextmanager
265
+ def enter_block (self ) -> Iterator [None ]:
279
266
self .block_id += 1
280
267
self .blocks .append (self .block_id )
281
268
self .block_loop_depth [self .block_id ] = self .loop_depth
269
+ try :
270
+ yield
271
+ finally :
272
+ self .blocks .pop ()
282
273
283
- def leave_block (self ) -> None :
284
- self .blocks .pop ()
285
-
286
- def enter_try (self ) -> None :
274
+ @contextmanager
275
+ def enter_try (self ) -> Iterator [None ]:
287
276
self .disallow_redef_depth += 1
277
+ try :
278
+ yield
279
+ finally :
280
+ self .disallow_redef_depth -= 1
288
281
289
- def leave_try (self ) -> None :
290
- self .disallow_redef_depth -= 1
291
-
292
- def enter_loop (self ) -> None :
282
+ @contextmanager
283
+ def enter_loop (self ) -> Iterator [None ]:
293
284
self .loop_depth += 1
294
-
295
- def leave_loop (self ) -> None :
296
- self .loop_depth -= 1
285
+ try :
286
+ yield
287
+ finally :
288
+ self .loop_depth -= 1
297
289
298
290
def current_block (self ) -> int :
299
291
return self .blocks [- 1 ]
300
292
301
- def enter_scope (self , kind : int ) -> None :
293
+ @contextmanager
294
+ def enter_scope (self , kind : int ) -> Iterator [None ]:
302
295
self .var_blocks .append ({})
303
296
self .refs .append ({})
304
297
self .num_reads .append ({})
305
298
self .scope_kinds .append (kind )
306
-
307
- def leave_scope (self ) -> None :
308
- self .flush_refs ()
309
- self .var_blocks .pop ()
310
- self .num_reads .pop ()
311
- self .scope_kinds .pop ()
299
+ try :
300
+ yield
301
+ finally :
302
+ self .flush_refs ()
303
+ self .var_blocks .pop ()
304
+ self .num_reads .pop ()
305
+ self .scope_kinds .pop ()
312
306
313
307
def is_nested (self ) -> int :
314
308
return len (self .var_blocks ) > 1
0 commit comments