29
29
from mypy .types import (
30
30
Type , AnyType , CallableType , Void , FunctionLike , Overloaded , TupleType ,
31
31
Instance , NoneTyp , UnboundType , ErrorType , TypeTranslator , strip_type ,
32
- UnionType , TypeVarType ,
32
+ UnionType , TypeVarType , PartialType
33
33
)
34
34
from mypy .sametypes import is_same_type
35
35
from mypy .messages import MessageBuilder
@@ -332,7 +332,8 @@ class TypeChecker(NodeVisitor[Type]):
332
332
breaking_out = False
333
333
# Do weak type checking in this file
334
334
weak_opts = set () # type: Set[str]
335
-
335
+ # Stack of collections of variables with partial types
336
+ partial_types = None # type: List[Dict[Var, Context]]
336
337
globals = None # type: SymbolTable
337
338
locals = None # type: SymbolTable
338
339
modules = None # type: Dict[str, MypyFile]
@@ -358,6 +359,7 @@ def __init__(self, errors: Errors, modules: Dict[str, MypyFile],
358
359
self .dynamic_funcs = []
359
360
self .function_stack = []
360
361
self .weak_opts = set () # type: Set[str]
362
+ self .partial_types = []
361
363
362
364
def visit_file (self , file_node : MypyFile , path : str ) -> None :
363
365
"""Type check a mypy file with the given path."""
@@ -367,10 +369,12 @@ def visit_file(self, file_node: MypyFile, path: str) -> None:
367
369
self .globals = file_node .names
368
370
self .locals = None
369
371
self .weak_opts = file_node .weak_opts
372
+ self .enter_partial_types ()
370
373
371
374
for d in file_node .defs :
372
375
self .accept (d )
373
376
377
+ self .leave_partial_types ()
374
378
self .errors .set_ignored_lines (set ())
375
379
376
380
def accept (self , node : Node , type_context : Type = None ) -> Type :
@@ -461,6 +465,8 @@ def check_func_item(self, defn: FuncItem,
461
465
if fdef :
462
466
self .errors .push_function (fdef .name ())
463
467
468
+ self .enter_partial_types ()
469
+
464
470
typ = self .function_type (defn )
465
471
if type_override :
466
472
typ = type_override
@@ -469,6 +475,8 @@ def check_func_item(self, defn: FuncItem,
469
475
else :
470
476
raise RuntimeError ('Not supported' )
471
477
478
+ self .leave_partial_types ()
479
+
472
480
if fdef :
473
481
self .errors .pop_function ()
474
482
@@ -864,12 +872,14 @@ def visit_class_def(self, defn: ClassDef) -> Type:
864
872
"""Type check a class definition."""
865
873
typ = defn .info
866
874
self .errors .push_type (defn .name )
875
+ self .enter_partial_types ()
867
876
old_binder = self .binder
868
877
self .binder = ConditionalTypeBinder ()
869
878
self .binder .push_frame ()
870
879
self .accept (defn .defs )
871
880
self .binder = old_binder
872
881
self .check_multiple_inheritance (typ )
882
+ self .leave_partial_types ()
873
883
self .errors .pop_type ()
874
884
875
885
def check_multiple_inheritance (self , typ : TypeInfo ) -> None :
@@ -1237,11 +1247,14 @@ def infer_variable_type(self, name: Var, lvalue: Node,
1237
1247
elif isinstance (init_type , Void ):
1238
1248
self .check_not_void (init_type , context )
1239
1249
self .set_inference_error_fallback_type (name , lvalue , init_type , context )
1240
- elif not self .is_valid_inferred_type (init_type ):
1241
- # We cannot use the type of the initialization expression for type
1242
- # inference (it's not specific enough).
1243
- self .fail (messages .NEED_ANNOTATION_FOR_VAR , context )
1244
- self .set_inference_error_fallback_type (name , lvalue , init_type , context )
1250
+ elif not is_valid_inferred_type (init_type ):
1251
+ # We cannot use the type of the initialization expression for full type
1252
+ # inference (it's not specific enough), but we might be able to give
1253
+ # partial type which will be made more specific later. A partial type
1254
+ # gets generated in assignment like 'x = []' where item type is not known.
1255
+ if not self .infer_partial_type (name , lvalue , init_type ):
1256
+ self .fail (messages .NEED_ANNOTATION_FOR_VAR , context )
1257
+ self .set_inference_error_fallback_type (name , lvalue , init_type , context )
1245
1258
else :
1246
1259
# Infer type of the target.
1247
1260
@@ -1250,6 +1263,21 @@ def infer_variable_type(self, name: Var, lvalue: Node,
1250
1263
1251
1264
self .set_inferred_type (name , lvalue , init_type )
1252
1265
1266
+ def infer_partial_type (self , name : Var , lvalue : Node , init_type : Type ) -> bool :
1267
+ if not isinstance (init_type , Instance ):
1268
+ return False
1269
+ fullname = init_type .type .fullname ()
1270
+ if ((fullname == 'builtins.list' or fullname == 'builtins.set' or
1271
+ fullname == 'builtins.dict' )
1272
+ and isinstance (init_type .args [0 ], NoneTyp )
1273
+ and (fullname != 'builtins.dict' or isinstance (init_type .args [1 ], NoneTyp ))
1274
+ and isinstance (lvalue , NameExpr )):
1275
+ partial_type = PartialType (init_type .type , name )
1276
+ self .set_inferred_type (name , lvalue , partial_type )
1277
+ self .partial_types [- 1 ][name ] = lvalue
1278
+ return True
1279
+ return False
1280
+
1253
1281
def set_inferred_type (self , var : Var , lvalue : Node , type : Type ) -> None :
1254
1282
"""Store inferred variable type.
1255
1283
@@ -1275,23 +1303,6 @@ def set_inference_error_fallback_type(self, var: Var, lvalue: Node, type: Type,
1275
1303
if context .get_line () in self .errors .ignored_lines :
1276
1304
self .set_inferred_type (var , lvalue , AnyType ())
1277
1305
1278
- def is_valid_inferred_type (self , typ : Type ) -> bool :
1279
- """Is an inferred type invalid?
1280
-
1281
- Examples include the None type or a type with a None component.
1282
- """
1283
- if is_same_type (typ , NoneTyp ()):
1284
- return False
1285
- elif isinstance (typ , Instance ):
1286
- for arg in typ .args :
1287
- if not self .is_valid_inferred_type (arg ):
1288
- return False
1289
- elif isinstance (typ , TupleType ):
1290
- for item in typ .items :
1291
- if not self .is_valid_inferred_type (item ):
1292
- return False
1293
- return True
1294
-
1295
1306
def narrow_type_from_binder (self , expr : Node , known_type : Type ) -> Type :
1296
1307
if expr .literal >= LITERAL_TYPE :
1297
1308
restriction = self .binder .get (expr )
@@ -1323,6 +1334,7 @@ def check_indexed_assignment(self, lvalue: IndexExpr,
1323
1334
1324
1335
The lvalue argument is the base[index] expression.
1325
1336
"""
1337
+ self .try_infer_partial_type_from_indexed_assignment (lvalue , rvalue )
1326
1338
basetype = self .accept (lvalue .base )
1327
1339
method_type = self .expr_checker .analyze_external_member_access (
1328
1340
'__setitem__' , basetype , context )
@@ -1331,6 +1343,26 @@ def check_indexed_assignment(self, lvalue: IndexExpr,
1331
1343
[nodes .ARG_POS , nodes .ARG_POS ],
1332
1344
context )
1333
1345
1346
+ def try_infer_partial_type_from_indexed_assignment (
1347
+ self , lvalue : IndexExpr , rvalue : Node ) -> None :
1348
+ # TODO: Should we share some of this with try_infer_partial_type?
1349
+ partial_types = self .partial_types [- 1 ]
1350
+ if not partial_types :
1351
+ # Fast path leave -- no partial types in the current scope.
1352
+ return
1353
+ if isinstance (lvalue .base , RefExpr ):
1354
+ var = lvalue .base .node
1355
+ if var in partial_types :
1356
+ var = cast (Var , var )
1357
+ typename = cast (Instance , var .type ).type .fullname ()
1358
+ if typename == 'builtins.dict' :
1359
+ # TODO: Don't infer things twice.
1360
+ key_type = self .accept (lvalue .index )
1361
+ value_type = self .accept (rvalue )
1362
+ if is_valid_inferred_type (key_type ) and is_valid_inferred_type (value_type ):
1363
+ var .type = self .named_generic_type ('builtins.dict' , [key_type , value_type ])
1364
+ del partial_types [var ]
1365
+
1334
1366
def visit_expression_stmt (self , s : ExpressionStmt ) -> Type :
1335
1367
self .accept (s .expr )
1336
1368
@@ -2032,6 +2064,21 @@ def enter(self) -> None:
2032
2064
def leave (self ) -> None :
2033
2065
self .locals = None
2034
2066
2067
+ def enter_partial_types (self ) -> None :
2068
+ """Push a new scope for collecting partial types."""
2069
+ self .partial_types .append ({})
2070
+
2071
+ def leave_partial_types (self ) -> None :
2072
+ """Pop partial type scope.
2073
+
2074
+ Also report errors for variables which still have partial
2075
+ types, i.e. we couldn't infer a complete type.
2076
+ """
2077
+ partial_types = self .partial_types .pop ()
2078
+ for var , context in partial_types .items ():
2079
+ self .msg .fail (messages .NEED_ANNOTATION_FOR_VAR , context )
2080
+ var .type = AnyType ()
2081
+
2035
2082
def is_within_function (self ) -> bool :
2036
2083
"""Are we currently type checking within a function?
2037
2084
@@ -2289,3 +2336,21 @@ def infer_operator_assignment_method(type: Type, operator: str) -> str:
2289
2336
if type .type .has_readable_member (inplace ):
2290
2337
method = inplace
2291
2338
return method
2339
+
2340
+
2341
+ def is_valid_inferred_type (typ : Type ) -> bool :
2342
+ """Is an inferred type valid?
2343
+
2344
+ Examples of invalid types include the None type or a type with a None component.
2345
+ """
2346
+ if is_same_type (typ , NoneTyp ()):
2347
+ return False
2348
+ elif isinstance (typ , Instance ):
2349
+ for arg in typ .args :
2350
+ if not is_valid_inferred_type (arg ):
2351
+ return False
2352
+ elif isinstance (typ , TupleType ):
2353
+ for item in typ .items :
2354
+ if not is_valid_inferred_type (item ):
2355
+ return False
2356
+ return True
0 commit comments