5
5
from contextlib import contextmanager
6
6
7
7
from typing import (
8
- Dict , Set , List , cast , Tuple , TypeVar , Union , Optional , NamedTuple , Iterator , Iterable , Any
8
+ Dict , Set , List , cast , Tuple , TypeVar , Union , Optional , NamedTuple , Iterator , Iterable ,
9
+ Sequence
9
10
)
10
11
11
12
from mypy .errors import Errors , report_internal_error
72
73
73
74
DEFAULT_LAST_PASS = 1 # type: Final # Pass numbers start at 0
74
75
76
+ DeferredNodeType = Union [FuncDef , LambdaExpr , OverloadedFuncDef , Decorator ]
77
+ FineGrainedDeferredNodeType = Union [FuncDef , MypyFile , OverloadedFuncDef ]
75
78
76
79
# A node which is postponed to be processed during the next pass.
77
- # This is used for both batch mode and fine-grained incremental mode.
80
+ # In normal mode one can defer functions and methods (also decorated and/or overloaded)
81
+ # and lambda expressions. Nested functions can't be deferred -- only top-level functions
82
+ # and methods of classes not defined within a function can be deferred.
78
83
DeferredNode = NamedTuple (
79
84
'DeferredNode' ,
80
85
[
81
- # In batch mode only FuncDef and LambdaExpr are supported
82
- ('node' , Union [FuncDef , LambdaExpr , MypyFile , OverloadedFuncDef ]),
86
+ ('node' , DeferredNodeType ),
83
87
('context_type_name' , Optional [str ]), # Name of the surrounding class (for error messages)
84
88
('active_typeinfo' , Optional [TypeInfo ]), # And its TypeInfo (for semantic analysis
85
89
# self type handling)
86
90
])
87
91
92
+ # Same as above, but for fine-grained mode targets. Only top-level functions/methods
93
+ # and module top levels are allowed as such.
94
+ FineGrainedDeferredNode = NamedTuple (
95
+ 'FineDeferredNode' ,
96
+ [
97
+ ('node' , FineGrainedDeferredNodeType ),
98
+ ('context_type_name' , Optional [str ]),
99
+ ('active_typeinfo' , Optional [TypeInfo ]),
100
+ ])
88
101
89
102
# Data structure returned by find_isinstance_check representing
90
103
# information learned from the truth or falsehood of a condition. The
@@ -283,7 +296,10 @@ def check_first_pass(self) -> None:
283
296
284
297
self .tscope .leave ()
285
298
286
- def check_second_pass (self , todo : Optional [List [DeferredNode ]] = None ) -> bool :
299
+ def check_second_pass (self ,
300
+ todo : Optional [Sequence [Union [DeferredNode ,
301
+ FineGrainedDeferredNode ]]] = None
302
+ ) -> bool :
287
303
"""Run second or following pass of type checking.
288
304
289
305
This goes through deferred nodes, returning True if there were any.
@@ -300,7 +316,7 @@ def check_second_pass(self, todo: Optional[List[DeferredNode]] = None) -> bool:
300
316
else :
301
317
assert not self .deferred_nodes
302
318
self .deferred_nodes = []
303
- done = set () # type: Set[Union[FuncDef, LambdaExpr, MypyFile, OverloadedFuncDef ]]
319
+ done = set () # type: Set[Union[DeferredNodeType, FineGrainedDeferredNodeType ]]
304
320
for node , type_name , active_typeinfo in todo :
305
321
if node in done :
306
322
continue
@@ -314,10 +330,7 @@ def check_second_pass(self, todo: Optional[List[DeferredNode]] = None) -> bool:
314
330
self .tscope .leave ()
315
331
return True
316
332
317
- def check_partial (self , node : Union [FuncDef ,
318
- LambdaExpr ,
319
- MypyFile ,
320
- OverloadedFuncDef ]) -> None :
333
+ def check_partial (self , node : Union [DeferredNodeType , FineGrainedDeferredNodeType ]) -> None :
321
334
if isinstance (node , MypyFile ):
322
335
self .check_top_level (node )
323
336
else :
@@ -338,20 +351,32 @@ def check_top_level(self, node: MypyFile) -> None:
338
351
assert not self .current_node_deferred
339
352
# TODO: Handle __all__
340
353
354
+ def defer_node (self , node : DeferredNodeType , enclosing_class : Optional [TypeInfo ]) -> None :
355
+ """Defer a node for processing during next type-checking pass.
356
+
357
+ Args:
358
+ node: function/method being deferred
359
+ enclosing_class: for methods, the class where the method is defined
360
+ NOTE: this can't handle nested functions/methods.
361
+ """
362
+ if self .errors .type_name :
363
+ type_name = self .errors .type_name [- 1 ]
364
+ else :
365
+ type_name = None
366
+ # We don't freeze the entire scope since only top-level functions and methods
367
+ # can be deferred. Only module/class level scope information is needed.
368
+ # Module-level scope information is preserved in the TypeChecker instance.
369
+ self .deferred_nodes .append (DeferredNode (node , type_name , enclosing_class ))
370
+
341
371
def handle_cannot_determine_type (self , name : str , context : Context ) -> None :
342
372
node = self .scope .top_non_lambda_function ()
343
373
if self .pass_num < self .last_pass and isinstance (node , FuncDef ):
344
374
# Don't report an error yet. Just defer. Note that we don't defer
345
375
# lambdas because they are coupled to the surrounding function
346
376
# through the binder and the inferred type of the lambda, so it
347
377
# would get messy.
348
- if self .errors .type_name :
349
- type_name = self .errors .type_name [- 1 ]
350
- else :
351
- type_name = None
352
- # Shouldn't we freeze the entire scope?
353
378
enclosing_class = self .scope .enclosing_class ()
354
- self .deferred_nodes . append ( DeferredNode ( node , type_name , enclosing_class ) )
379
+ self .defer_node ( node , enclosing_class )
355
380
# Set a marker so that we won't infer additional types in this
356
381
# function. Any inferred types could be bogus, because there's at
357
382
# least one type that we don't know.
@@ -1256,15 +1281,26 @@ def expand_typevars(self, defn: FuncItem,
1256
1281
else :
1257
1282
return [(defn , typ )]
1258
1283
1259
- def check_method_override (self , defn : Union [FuncBase , Decorator ]) -> None :
1260
- """Check if function definition is compatible with base classes."""
1284
+ def check_method_override (self , defn : Union [FuncDef , OverloadedFuncDef , Decorator ]) -> None :
1285
+ """Check if function definition is compatible with base classes.
1286
+
1287
+ This may defer the method if a signature is not available in at least one base class.
1288
+ """
1261
1289
# Check against definitions in base classes.
1262
1290
for base in defn .info .mro [1 :]:
1263
- self .check_method_or_accessor_override_for_base (defn , base )
1291
+ if self .check_method_or_accessor_override_for_base (defn , base ):
1292
+ # Node was deferred, we will have another attempt later.
1293
+ return
1294
+
1295
+ def check_method_or_accessor_override_for_base (self , defn : Union [FuncDef ,
1296
+ OverloadedFuncDef ,
1297
+ Decorator ],
1298
+ base : TypeInfo ) -> bool :
1299
+ """Check if method definition is compatible with a base class.
1264
1300
1265
- def check_method_or_accessor_override_for_base ( self , defn : Union [ FuncBase , Decorator ],
1266
- base : TypeInfo ) -> None :
1267
- """Check if method definition is compatible with a base class."""
1301
+ Return True if the node was deferred because one of the corresponding
1302
+ superclass nodes is not ready.
1303
+ """
1268
1304
if base :
1269
1305
name = defn .name ()
1270
1306
base_attr = base .names .get (name )
@@ -1280,19 +1316,26 @@ def check_method_or_accessor_override_for_base(self, defn: Union[FuncBase, Decor
1280
1316
if name not in ('__init__' , '__new__' , '__init_subclass__' ):
1281
1317
# Check method override
1282
1318
# (__init__, __new__, __init_subclass__ are special).
1283
- self .check_method_override_for_base_with_name (defn , name , base )
1319
+ if self .check_method_override_for_base_with_name (defn , name , base ):
1320
+ return True
1284
1321
if name in nodes .inplace_operator_methods :
1285
1322
# Figure out the name of the corresponding operator method.
1286
1323
method = '__' + name [3 :]
1287
1324
# An inplace operator method such as __iadd__ might not be
1288
1325
# always introduced safely if a base class defined __add__.
1289
1326
# TODO can't come up with an example where this is
1290
1327
# necessary; now it's "just in case"
1291
- self .check_method_override_for_base_with_name (defn , method ,
1292
- base )
1328
+ return self .check_method_override_for_base_with_name (defn , method ,
1329
+ base )
1330
+ return False
1293
1331
1294
1332
def check_method_override_for_base_with_name (
1295
- self , defn : Union [FuncBase , Decorator ], name : str , base : TypeInfo ) -> None :
1333
+ self , defn : Union [FuncDef , OverloadedFuncDef , Decorator ],
1334
+ name : str , base : TypeInfo ) -> bool :
1335
+ """Check if overriding an attribute `name` of `base` with `defn` is valid.
1336
+
1337
+ Return True if the supertype node was not analysed yet, and `defn` was deferred.
1338
+ """
1296
1339
base_attr = base .names .get (name )
1297
1340
if base_attr :
1298
1341
# The name of the method is defined in the base class.
@@ -1305,7 +1348,7 @@ def check_method_override_for_base_with_name(
1305
1348
context = defn .func
1306
1349
1307
1350
# Construct the type of the overriding method.
1308
- if isinstance (defn , FuncBase ):
1351
+ if isinstance (defn , ( FuncDef , OverloadedFuncDef ) ):
1309
1352
typ = self .function_type (defn ) # type: Type
1310
1353
override_class_or_static = defn .is_class or defn .is_static
1311
1354
else :
@@ -1320,13 +1363,18 @@ def check_method_override_for_base_with_name(
1320
1363
original_type = base_attr .type
1321
1364
original_node = base_attr .node
1322
1365
if original_type is None :
1323
- if isinstance (original_node , FuncBase ):
1366
+ if self .pass_num < self .last_pass :
1367
+ # If there are passes left, defer this node until next pass,
1368
+ # otherwise try reconstructing the method type from available information.
1369
+ self .defer_node (defn , defn .info )
1370
+ return True
1371
+ elif isinstance (original_node , (FuncDef , OverloadedFuncDef )):
1324
1372
original_type = self .function_type (original_node )
1325
1373
elif isinstance (original_node , Decorator ):
1326
1374
original_type = self .function_type (original_node .func )
1327
1375
else :
1328
1376
assert False , str (base_attr .node )
1329
- if isinstance (original_node , FuncBase ):
1377
+ if isinstance (original_node , ( FuncDef , OverloadedFuncDef ) ):
1330
1378
original_class_or_static = original_node .is_class or original_node .is_static
1331
1379
elif isinstance (original_node , Decorator ):
1332
1380
fdef = original_node .func
@@ -1362,6 +1410,7 @@ def check_method_override_for_base_with_name(
1362
1410
else :
1363
1411
self .msg .signature_incompatible_with_supertype (
1364
1412
defn .name (), name , base .name (), context )
1413
+ return False
1365
1414
1366
1415
def get_op_other_domain (self , tp : FunctionLike ) -> Optional [Type ]:
1367
1416
if isinstance (tp , CallableType ):
0 commit comments