32
32
from mypy .types import (
33
33
Type , AnyType , CallableType , Void , FunctionLike , Overloaded , TupleType ,
34
34
Instance , NoneTyp , ErrorType , strip_type ,
35
- UnionType , TypeVarType , PartialType , DeletedType
35
+ UnionType , TypeVarType , PartialType , DeletedType , UninhabitedType
36
36
)
37
37
from mypy .sametypes import is_same_type
38
38
from mypy .messages import MessageBuilder
53
53
from mypy .treetransform import TransformVisitor
54
54
from mypy .meet import meet_simple , nearest_builtin_ancestor , is_overlapping_types
55
55
56
+ from mypy import experiments
57
+
56
58
57
59
T = TypeVar ('T' )
58
60
@@ -223,14 +225,14 @@ def get_declaration(self, expr: Any) -> Type:
223
225
else :
224
226
return self .frames [0 ].get (expr .literal_hash )
225
227
226
- def assign_type (self , expr : Node , type : Type ,
228
+ def assign_type (self , expr : Node ,
229
+ type : Type ,
230
+ declared_type : Type ,
227
231
restrict_any : bool = False ) -> None :
228
232
if not expr .literal :
229
233
return
230
234
self .invalidate_dependencies (expr )
231
235
232
- declared_type = self .get_declaration (expr )
233
-
234
236
if declared_type is None :
235
237
# Not sure why this happens. It seems to mainly happen in
236
238
# member initialization.
@@ -1200,18 +1202,31 @@ def check_assignment(self, lvalue: Node, rvalue: Node, infer_lvalue_type: bool =
1200
1202
partial_types = self .find_partial_types (var )
1201
1203
if partial_types is not None :
1202
1204
if not self .current_node_deferred :
1203
- var .type = rvalue_type
1205
+ if experiments .STRICT_OPTIONAL :
1206
+ var .type = UnionType .make_simplified_union (
1207
+ [rvalue_type , NoneTyp ()])
1208
+ else :
1209
+ var .type = rvalue_type
1204
1210
else :
1205
1211
var .type = None
1206
1212
del partial_types [var ]
1207
1213
# Try to infer a partial type. No need to check the return value, as
1208
1214
# an error will be reported elsewhere.
1209
1215
self .infer_partial_type (lvalue_type .var , lvalue , rvalue_type )
1210
1216
return
1211
- rvalue_type = self .check_simple_assignment (lvalue_type , rvalue , lvalue )
1217
+ if (is_literal_none (rvalue ) and
1218
+ isinstance (lvalue , NameExpr ) and
1219
+ isinstance (lvalue .node , Var ) and
1220
+ lvalue .node .is_initialized_in_class ):
1221
+ # Allow None's to be assigned to class variables with non-Optional types.
1222
+ rvalue_type = lvalue_type
1223
+ else :
1224
+ rvalue_type = self .check_simple_assignment (lvalue_type , rvalue , lvalue )
1212
1225
1213
1226
if rvalue_type and infer_lvalue_type :
1214
- self .binder .assign_type (lvalue , rvalue_type ,
1227
+ self .binder .assign_type (lvalue ,
1228
+ rvalue_type ,
1229
+ lvalue_type ,
1215
1230
self .typing_mode_weak ())
1216
1231
elif index_lvalue :
1217
1232
self .check_indexed_assignment (index_lvalue , rvalue , rvalue )
@@ -1444,7 +1459,7 @@ def infer_variable_type(self, name: Var, lvalue: Node,
1444
1459
"""Infer the type of initialized variables from initializer type."""
1445
1460
if self .typing_mode_weak ():
1446
1461
self .set_inferred_type (name , lvalue , AnyType ())
1447
- self .binder .assign_type (lvalue , init_type , True )
1462
+ self .binder .assign_type (lvalue , init_type , self . binder . get_declaration ( lvalue ), True )
1448
1463
elif isinstance (init_type , Void ):
1449
1464
self .check_not_void (init_type , context )
1450
1465
self .set_inference_error_fallback_type (name , lvalue , init_type , context )
@@ -1467,16 +1482,16 @@ def infer_variable_type(self, name: Var, lvalue: Node,
1467
1482
self .set_inferred_type (name , lvalue , init_type )
1468
1483
1469
1484
def infer_partial_type (self , name : Var , lvalue : Node , init_type : Type ) -> bool :
1470
- if isinstance (init_type , NoneTyp ):
1471
- partial_type = PartialType (None , name )
1485
+ if isinstance (init_type , ( NoneTyp , UninhabitedType ) ):
1486
+ partial_type = PartialType (None , name , [ init_type ] )
1472
1487
elif isinstance (init_type , Instance ):
1473
1488
fullname = init_type .type .fullname ()
1474
- if (( fullname == 'builtins.list' or fullname == 'builtins.set' or
1475
- fullname == 'builtins.dict' )
1476
- and isinstance ( init_type . args [ 0 ], NoneTyp )
1477
- and ( fullname != 'builtins.dict' or isinstance ( init_type . args [ 1 ], NoneTyp ))
1478
- and isinstance (lvalue , NameExpr )):
1479
- partial_type = PartialType (init_type .type , name )
1489
+ if (isinstance ( lvalue , NameExpr ) and
1490
+ ( fullname == 'builtins.list' or
1491
+ fullname == 'builtins.set' or
1492
+ fullname == 'builtins.dict' ) and
1493
+ all ( isinstance (t , ( NoneTyp , UninhabitedType )) for t in init_type . args )):
1494
+ partial_type = PartialType (init_type .type , name , init_type . args )
1480
1495
else :
1481
1496
return False
1482
1497
else :
@@ -1559,8 +1574,8 @@ def try_infer_partial_type_from_indexed_assignment(
1559
1574
self , lvalue : IndexExpr , rvalue : Node ) -> None :
1560
1575
# TODO: Should we share some of this with try_infer_partial_type?
1561
1576
if isinstance (lvalue .base , RefExpr ) and isinstance (lvalue .base .node , Var ):
1562
- var = cast ( Var , lvalue .base .node )
1563
- if var is not None and isinstance (var .type , PartialType ):
1577
+ var = lvalue .base .node
1578
+ if isinstance (var .type , PartialType ):
1564
1579
type_type = var .type .type
1565
1580
if type_type is None :
1566
1581
return # The partial type is None.
@@ -1572,10 +1587,15 @@ def try_infer_partial_type_from_indexed_assignment(
1572
1587
# TODO: Don't infer things twice.
1573
1588
key_type = self .accept (lvalue .index )
1574
1589
value_type = self .accept (rvalue )
1575
- if is_valid_inferred_type (key_type ) and is_valid_inferred_type (value_type ):
1590
+ full_key_type = UnionType .make_simplified_union (
1591
+ [key_type , var .type .inner_types [0 ]])
1592
+ full_value_type = UnionType .make_simplified_union (
1593
+ [value_type , var .type .inner_types [1 ]])
1594
+ if (is_valid_inferred_type (full_key_type ) and
1595
+ is_valid_inferred_type (full_value_type )):
1576
1596
if not self .current_node_deferred :
1577
1597
var .type = self .named_generic_type ('builtins.dict' ,
1578
- [key_type , value_type ])
1598
+ [full_key_type , full_value_type ])
1579
1599
del partial_types [var ]
1580
1600
1581
1601
def visit_expression_stmt (self , s : ExpressionStmt ) -> Type :
@@ -1881,7 +1901,10 @@ def analyze_iterable_item_type(self, expr: Node) -> Type:
1881
1901
1882
1902
self .check_not_void (iterable , expr )
1883
1903
if isinstance (iterable , TupleType ):
1884
- joined = NoneTyp () # type: Type
1904
+ if experiments .STRICT_OPTIONAL :
1905
+ joined = UninhabitedType () # type: Type
1906
+ else :
1907
+ joined = NoneTyp ()
1885
1908
for item in iterable .items :
1886
1909
joined = join_types (joined , item )
1887
1910
if isinstance (joined , ErrorType ):
@@ -1932,7 +1955,9 @@ def flatten(t: Node) -> List[Node]:
1932
1955
s .expr .accept (self )
1933
1956
for elt in flatten (s .expr ):
1934
1957
if isinstance (elt , NameExpr ):
1935
- self .binder .assign_type (elt , DeletedType (source = elt .name ),
1958
+ self .binder .assign_type (elt ,
1959
+ DeletedType (source = elt .name ),
1960
+ self .binder .get_declaration (elt ),
1936
1961
self .typing_mode_weak ())
1937
1962
return None
1938
1963
@@ -2311,8 +2336,12 @@ def leave_partial_types(self) -> None:
2311
2336
partial_types = self .partial_types .pop ()
2312
2337
if not self .current_node_deferred :
2313
2338
for var , context in partial_types .items ():
2314
- self .msg .fail (messages .NEED_ANNOTATION_FOR_VAR , context )
2315
- var .type = AnyType ()
2339
+ if experiments .STRICT_OPTIONAL and cast (PartialType , var .type ).type is None :
2340
+ # None partial type: assume variable is intended to have type None
2341
+ var .type = NoneTyp ()
2342
+ else :
2343
+ self .msg .fail (messages .NEED_ANNOTATION_FOR_VAR , context )
2344
+ var .type = AnyType ()
2316
2345
2317
2346
def find_partial_types (self , var : Var ) -> Optional [Dict [Var , Context ]]:
2318
2347
for partial_types in reversed (self .partial_types ):
@@ -2356,11 +2385,48 @@ def method_type(self, func: FuncBase) -> FunctionLike:
2356
2385
return method_type_with_fallback (func , self .named_type ('builtins.function' ))
2357
2386
2358
2387
2388
+ def conditional_type_map (expr : Node ,
2389
+ current_type : Optional [Type ],
2390
+ proposed_type : Optional [Type ],
2391
+ * ,
2392
+ weak : bool = False
2393
+ ) -> Tuple [Optional [Dict [Node , Type ]], Optional [Dict [Node , Type ]]]:
2394
+ """Takes in an expression, the current type of the expression, and a
2395
+ proposed type of that expression.
2396
+
2397
+ Returns a 2-tuple: The first element is a map from the expression to
2398
+ the proposed type, if the expression can be the proposed type. The
2399
+ second element is a map from the expression to the type it would hold
2400
+ if it was not the proposed type, if any."""
2401
+ if proposed_type :
2402
+ if current_type :
2403
+ if is_proper_subtype (current_type , proposed_type ):
2404
+ return {expr : proposed_type }, None
2405
+ elif not is_overlapping_types (current_type , proposed_type ):
2406
+ return None , {expr : current_type }
2407
+ else :
2408
+ remaining_type = restrict_subtype_away (current_type , proposed_type )
2409
+ return {expr : proposed_type }, {expr : remaining_type }
2410
+ else :
2411
+ return {expr : proposed_type }, {}
2412
+ else :
2413
+ # An isinstance check, but we don't understand the type
2414
+ if weak :
2415
+ return {expr : AnyType ()}, {expr : current_type }
2416
+ else :
2417
+ return {}, {}
2418
+
2419
+
2420
+ def is_literal_none (n : Node ) -> bool :
2421
+ return isinstance (n , NameExpr ) and n .fullname == 'builtins.None'
2422
+
2423
+
2359
2424
def find_isinstance_check (node : Node ,
2360
2425
type_map : Dict [Node , Type ],
2361
- weak : bool = False ) \
2362
- -> Tuple [Optional [Dict [Node , Type ]], Optional [Dict [Node , Type ]]]:
2363
- """Find any isinstance checks (within a chain of ands).
2426
+ weak : bool = False
2427
+ ) -> Tuple [Optional [Dict [Node , Type ]], Optional [Dict [Node , Type ]]]:
2428
+ """Find any isinstance checks (within a chain of ands). Includes
2429
+ implicit and explicit checks for None.
2364
2430
2365
2431
Return value is a map of variables to their types if the condition
2366
2432
is true and a map of variables to their types if the condition is false.
@@ -2376,20 +2442,31 @@ def find_isinstance_check(node: Node,
2376
2442
if expr .literal == LITERAL_TYPE :
2377
2443
vartype = type_map [expr ]
2378
2444
type = get_isinstance_type (node .args [1 ], type_map )
2379
- if type :
2380
- elsetype = vartype
2381
- if vartype :
2382
- if is_proper_subtype (vartype , type ):
2383
- return {expr : type }, None
2384
- elif not is_overlapping_types (vartype , type ):
2385
- return None , {expr : elsetype }
2386
- else :
2387
- elsetype = restrict_subtype_away (vartype , type )
2388
- return {expr : type }, {expr : elsetype }
2389
- else :
2390
- # An isinstance check, but we don't understand the type
2391
- if weak :
2392
- return {expr : AnyType ()}, {expr : vartype }
2445
+ return conditional_type_map (expr , vartype , type , weak = weak )
2446
+ elif (isinstance (node , ComparisonExpr ) and any (is_literal_none (n ) for n in node .operands ) and
2447
+ experiments .STRICT_OPTIONAL ):
2448
+ # Check for `x is None` and `x is not None`.
2449
+ is_not = node .operators == ['is not' ]
2450
+ if is_not or node .operators == ['is' ]:
2451
+ if_vars = {} # type: Dict[Node, Type]
2452
+ else_vars = {} # type: Dict[Node, Type]
2453
+ for expr in node .operands :
2454
+ if expr .literal == LITERAL_TYPE and not is_literal_none (expr ) and expr in type_map :
2455
+ # This should only be true at most once: there should be
2456
+ # two elements in node.operands, and at least one of them
2457
+ # should represent a None.
2458
+ vartype = type_map [expr ]
2459
+ if_vars , else_vars = conditional_type_map (expr , vartype , NoneTyp (), weak = weak )
2460
+ break
2461
+
2462
+ if is_not :
2463
+ if_vars , else_vars = else_vars , if_vars
2464
+ return if_vars , else_vars
2465
+ elif isinstance (node , RefExpr ) and experiments .STRICT_OPTIONAL :
2466
+ # The type could be falsy, so we can't deduce anything new about the else branch
2467
+ vartype = type_map [node ]
2468
+ _ , if_vars = conditional_type_map (node , vartype , NoneTyp (), weak = weak )
2469
+ return if_vars , {}
2393
2470
elif isinstance (node , OpExpr ) and node .op == 'and' :
2394
2471
left_if_vars , right_else_vars = find_isinstance_check (
2395
2472
node .left ,
@@ -2571,6 +2648,12 @@ def is_valid_inferred_type(typ: Type) -> bool:
2571
2648
Examples of invalid types include the None type or a type with a None component.
2572
2649
"""
2573
2650
if is_same_type (typ , NoneTyp ()):
2651
+ # With strict Optional checking, we *may* eventually infer NoneTyp, but
2652
+ # we only do that if we can't infer a specific Optional type. This
2653
+ # resolution happens in leave_partial_types when we pop a partial types
2654
+ # scope.
2655
+ return False
2656
+ if is_same_type (typ , UninhabitedType ()):
2574
2657
return False
2575
2658
elif isinstance (typ , Instance ):
2576
2659
for arg in typ .args :
0 commit comments