65
65
LAST_PASS = 1 # Pass numbers start at 0
66
66
67
67
68
- # A node which is postponed to be type checked during the next pass.
68
+ # A node which is postponed to be processed during the next pass.
69
+ # This is used for both batch mode and fine-grained incremental mode.
69
70
DeferredNode = NamedTuple (
70
71
'DeferredNode' ,
71
72
[
72
- ('node' , FuncItem ),
73
+ # In batch mode only FuncDef and LambdaExpr are supported
74
+ ('node' , Union [FuncDef , LambdaExpr , MypyFile ]),
73
75
('context_type_name' , Optional [str ]), # Name of the surrounding class (for error messages)
74
- ('active_class' , Optional [Type ]), # And its type (for selftype handling)
76
+ ('active_typeinfo' , Optional [TypeInfo ]), # And its TypeInfo (for semantic analysis
77
+ # self type handling)
75
78
])
76
79
77
80
@@ -167,7 +170,7 @@ def check_first_pass(self) -> None:
167
170
168
171
Deferred functions will be processed by check_second_pass().
169
172
"""
170
- self .errors .set_file (self .path )
173
+ self .errors .set_file (self .path , self . tree . fullname () )
171
174
with self .enter_partial_types ():
172
175
with self .binder .top_frame_context ():
173
176
for d in self .tree .defs :
@@ -187,38 +190,57 @@ def check_first_pass(self) -> None:
187
190
self .fail (messages .ALL_MUST_BE_SEQ_STR .format (str_seq_s , all_s ),
188
191
all_ .node )
189
192
190
- def check_second_pass (self ) -> bool :
193
+ def check_second_pass (self , todo : List [ DeferredNode ] = None ) -> bool :
191
194
"""Run second or following pass of type checking.
192
195
193
196
This goes through deferred nodes, returning True if there were any.
194
197
"""
195
- if not self .deferred_nodes :
198
+ if not todo and not self .deferred_nodes :
196
199
return False
197
- self .errors .set_file (self .path )
200
+ self .errors .set_file (self .path , self . tree . fullname () )
198
201
self .pass_num += 1
199
- todo = self .deferred_nodes
202
+ if not todo :
203
+ todo = self .deferred_nodes
204
+ else :
205
+ assert not self .deferred_nodes
200
206
self .deferred_nodes = []
201
- done = set () # type: Set[FuncItem ]
202
- for node , type_name , active_class in todo :
207
+ done = set () # type: Set[Union[FuncDef, LambdaExpr, MypyFile] ]
208
+ for node , type_name , active_typeinfo in todo :
203
209
if node in done :
204
210
continue
205
211
# This is useful for debugging:
206
212
# print("XXX in pass %d, class %s, function %s" %
207
213
# (self.pass_num, type_name, node.fullname() or node.name()))
208
214
done .add (node )
209
215
with self .errors .enter_type (type_name ) if type_name else nothing ():
210
- with self .scope .push_class (active_class ) if active_class else nothing ():
211
- if isinstance (node , Statement ):
212
- self .accept (node )
213
- elif isinstance (node , Expression ):
214
- self .expr_checker .accept (node )
215
- else :
216
- assert False
216
+ with self .scope .push_class (active_typeinfo ) if active_typeinfo else nothing ():
217
+ self .check_partial (node )
217
218
return True
218
219
220
+ def check_partial (self , node : Union [FuncDef , LambdaExpr , MypyFile ]) -> None :
221
+ if isinstance (node , MypyFile ):
222
+ self .check_top_level (node )
223
+ elif isinstance (node , LambdaExpr ):
224
+ self .expr_checker .accept (node )
225
+ else :
226
+ self .accept (node )
227
+
228
+ def check_top_level (self , node : MypyFile ) -> None :
229
+ """Check only the top-level of a module, skipping function definitions."""
230
+ with self .enter_partial_types ():
231
+ with self .binder .top_frame_context ():
232
+ for d in node .defs :
233
+ # TODO: Type check class bodies.
234
+ if not isinstance (d , (FuncDef , ClassDef )):
235
+ d .accept (self )
236
+
237
+ assert not self .current_node_deferred
238
+ # TODO: Handle __all__
239
+
219
240
def handle_cannot_determine_type (self , name : str , context : Context ) -> None :
220
241
node = self .scope .top_function ()
221
- if self .pass_num < LAST_PASS and node is not None :
242
+ if (self .pass_num < LAST_PASS and node is not None
243
+ and isinstance (node , (FuncDef , LambdaExpr ))):
222
244
# Don't report an error yet. Just defer.
223
245
if self .errors .type_name :
224
246
type_name = self .errors .type_name [- 1 ]
@@ -635,7 +657,7 @@ def is_implicit_any(t: Type) -> bool:
635
657
for i in range (len (typ .arg_types )):
636
658
arg_type = typ .arg_types [i ]
637
659
638
- ref_type = self .scope .active_class ()
660
+ ref_type = self .scope .active_self_type () # type: Optional[Type]
639
661
if (isinstance (defn , FuncDef ) and ref_type is not None and i == 0
640
662
and not defn .is_static
641
663
and typ .arg_kinds [0 ] not in [nodes .ARG_STAR , nodes .ARG_STAR2 ]):
@@ -946,7 +968,7 @@ def check_method_override_for_base_with_name(
946
968
# The name of the method is defined in the base class.
947
969
948
970
# Construct the type of the overriding method.
949
- typ = bind_self (self .function_type (defn ), self .scope .active_class ())
971
+ typ = bind_self (self .function_type (defn ), self .scope .active_self_type ())
950
972
# Map the overridden method type to subtype context so that
951
973
# it can be checked for compatibility.
952
974
original_type = base_attr .type
@@ -959,7 +981,7 @@ def check_method_override_for_base_with_name(
959
981
assert False , str (base_attr .node )
960
982
if isinstance (original_type , FunctionLike ):
961
983
original = map_type_from_supertype (
962
- bind_self (original_type , self .scope .active_class ()),
984
+ bind_self (original_type , self .scope .active_self_type ()),
963
985
defn .info , base )
964
986
# Check that the types are compatible.
965
987
# TODO overloaded signatures
@@ -1051,7 +1073,7 @@ def visit_class_def(self, defn: ClassDef) -> None:
1051
1073
old_binder = self .binder
1052
1074
self .binder = ConditionalTypeBinder ()
1053
1075
with self .binder .top_frame_context ():
1054
- with self .scope .push_class (fill_typevars ( defn .info ) ):
1076
+ with self .scope .push_class (defn .info ):
1055
1077
self .accept (defn .defs )
1056
1078
self .binder = old_binder
1057
1079
if not defn .has_incompatible_baseclass :
@@ -1317,8 +1339,8 @@ def check_compatibility_super(self, lvalue: NameExpr, lvalue_type: Type, rvalue:
1317
1339
# Class-level function objects and classmethods become bound
1318
1340
# methods: the former to the instance, the latter to the
1319
1341
# class
1320
- base_type = bind_self (base_type , self .scope .active_class ())
1321
- compare_type = bind_self (compare_type , self .scope .active_class ())
1342
+ base_type = bind_self (base_type , self .scope .active_self_type ())
1343
+ compare_type = bind_self (compare_type , self .scope .active_self_type ())
1322
1344
1323
1345
# If we are a static method, ensure to also tell the
1324
1346
# lvalue it now contains a static method
@@ -1347,7 +1369,8 @@ def lvalue_type_from_base(self, expr_node: Var,
1347
1369
1348
1370
if base_type :
1349
1371
if not has_no_typevars (base_type ):
1350
- instance = cast (Instance , self .scope .active_class ())
1372
+ # TODO: Handle TupleType, don't cast
1373
+ instance = cast (Instance , self .scope .active_self_type ())
1351
1374
itype = map_instance_to_supertype (instance , base )
1352
1375
base_type = expand_type_by_instance (base_type , itype )
1353
1376
@@ -2996,7 +3019,7 @@ def is_node_static(node: Node) -> Optional[bool]:
2996
3019
2997
3020
class Scope :
2998
3021
# We keep two stacks combined, to maintain the relative order
2999
- stack = None # type: List[Union[Type , FuncItem, MypyFile]]
3022
+ stack = None # type: List[Union[TypeInfo , FuncItem, MypyFile]]
3000
3023
3001
3024
def __init__ (self , module : MypyFile ) -> None :
3002
3025
self .stack = [module ]
@@ -3007,20 +3030,26 @@ def top_function(self) -> Optional[FuncItem]:
3007
3030
return e
3008
3031
return None
3009
3032
3010
- def active_class (self ) -> Optional [Type ]:
3011
- if isinstance (self .stack [- 1 ], Type ):
3033
+ def active_class (self ) -> Optional [TypeInfo ]:
3034
+ if isinstance (self .stack [- 1 ], TypeInfo ):
3012
3035
return self .stack [- 1 ]
3013
3036
return None
3014
3037
3038
+ def active_self_type (self ) -> Optional [Union [Instance , TupleType ]]:
3039
+ info = self .active_class ()
3040
+ if info :
3041
+ return fill_typevars (info )
3042
+ return None
3043
+
3015
3044
@contextmanager
3016
3045
def push_function (self , item : FuncItem ) -> Iterator [None ]:
3017
3046
self .stack .append (item )
3018
3047
yield
3019
3048
self .stack .pop ()
3020
3049
3021
3050
@contextmanager
3022
- def push_class (self , t : Type ) -> Iterator [None ]:
3023
- self .stack .append (t )
3051
+ def push_class (self , info : TypeInfo ) -> Iterator [None ]:
3052
+ self .stack .append (info )
3024
3053
yield
3025
3054
self .stack .pop ()
3026
3055
0 commit comments