Skip to content

Commit 8ecccda

Browse files
ilevkivskyigvanrossum
authored andcommitted
[clean strict optional] Use dummy TypeInfo instead of None in Instance.type (and few more fixes) (#3285)
1 parent f07c8be commit 8ecccda

File tree

9 files changed

+74
-55
lines changed

9 files changed

+74
-55
lines changed

mypy/checkmember.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -451,7 +451,7 @@ class B(A): pass
451451
info = itype.type # type: TypeInfo
452452
if isinstance(t, CallableType):
453453
# TODO: Should we propagate type variable values?
454-
tvars = [TypeVarDef(n, i + 1, None, builtin_type('builtins.object'), tv.variance)
454+
tvars = [TypeVarDef(n, i + 1, [], builtin_type('builtins.object'), tv.variance)
455455
for (i, n), tv in zip(enumerate(info.type_vars), info.defn.type_vars)]
456456
if is_classmethod:
457457
t = bind_self(t, original_type)

mypy/fixup.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111
from mypy.types import (
1212
CallableType, EllipsisType, Instance, Overloaded, TupleType, TypedDictType,
1313
TypeList, TypeVarType, UnboundType, UnionType, TypeVisitor,
14-
TypeType
14+
TypeType, NOT_READY
1515
)
1616
from mypy.visitor import NodeVisitor
1717

@@ -156,7 +156,7 @@ def visit_instance(self, inst: Instance) -> None:
156156
# TODO: Is this needed or redundant?
157157
# Also fix up the bases, just in case.
158158
for base in inst.type.bases:
159-
if base.type is None:
159+
if base.type is NOT_READY:
160160
base.accept(self)
161161
for a in inst.args:
162162
a.accept(self)
@@ -233,7 +233,7 @@ def visit_type_type(self, t: TypeType) -> None:
233233

234234

235235
def lookup_qualified(modules: Dict[str, MypyFile], name: str,
236-
quick_and_dirty: bool) -> SymbolNode:
236+
quick_and_dirty: bool) -> Optional[SymbolNode]:
237237
stnode = lookup_qualified_stnode(modules, name, quick_and_dirty)
238238
if stnode is None:
239239
return None

mypy/maptype.py

Lines changed: 2 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -28,9 +28,7 @@ def map_instance_to_supertypes(instance: Instance,
2828
# FIX: Currently we should only have one supertype per interface, so no
2929
# need to return an array
3030
result = [] # type: List[Instance]
31-
typ = instance.type
32-
assert typ is not None, 'Instance.type is not fixed after deserialization'
33-
for path in class_derivation_paths(typ, supertype):
31+
for path in class_derivation_paths(instance.type, supertype):
3432
types = [instance]
3533
for sup in path:
3634
a = [] # type: List[Instance]
@@ -60,7 +58,6 @@ def class_derivation_paths(typ: TypeInfo,
6058

6159
for base in typ.bases:
6260
btype = base.type
63-
assert btype is not None, 'Instance.type is not fixed after deserialization'
6461
if btype == supertype:
6562
result.append([btype])
6663
else:
@@ -75,7 +72,6 @@ def map_instance_to_direct_supertypes(instance: Instance,
7572
supertype: TypeInfo) -> List[Instance]:
7673
# FIX: There should only be one supertypes, always.
7774
typ = instance.type
78-
assert typ is not None, 'Instance.type is not fixed after deserialization'
7975
result = [] # type: List[Instance]
8076

8177
for b in typ.bases:
@@ -103,6 +99,4 @@ def instance_to_type_environment(instance: Instance) -> Dict[TypeVarId, Type]:
10399
arguments. The type variables are mapped by their `id`.
104100
105101
"""
106-
typ = instance.type
107-
assert typ is not None, 'Instance.type is not fixed after deserialization'
108-
return {binder.id: arg for binder, arg in zip(typ.defn.type_vars, instance.args)}
102+
return {binder.id: arg for binder, arg in zip(instance.type.defn.type_vars, instance.args)}

mypy/nodes.py

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2208,6 +2208,23 @@ def deserialize(cls, data: JsonDict) -> 'TypeInfo':
22082208
return ti
22092209

22102210

2211+
class FakeInfo(TypeInfo):
2212+
# types.py defines a single instance of this class, called types.NOT_READY.
2213+
# This instance is used as a temporary placeholder in the process of de-serialization
2214+
# of 'Instance' types. The de-serialization happens in two steps: In the first step,
2215+
# Instance.type is set to NOT_READY. In the second step (in fixup.py) it is replaced by
2216+
# an actual TypeInfo. If you see the assertion error below, then most probably something
2217+
# went wrong during the second step and an 'Instance' that raised this error was not fixed.
2218+
# Note:
2219+
# 'None' is not used as a dummy value for two reasons:
2220+
# 1. This will require around 80-100 asserts to make 'mypy --strict-optional mypy'
2221+
# pass cleanly.
2222+
# 2. If NOT_READY value is accidentally used somewhere, it will be obvious where the value
2223+
# is from, whereas a 'None' value could come from anywhere.
2224+
def __getattr__(self, attr: str) -> None:
2225+
raise AssertionError('De-serialization failure: TypeInfo not fixed')
2226+
2227+
22112228
class SymbolTableNode:
22122229
# Kind of node. Possible values:
22132230
# - LDEF: local definition (of any kind)

mypy/semanal.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -182,7 +182,7 @@ class SemanticAnalyzer(NodeVisitor):
182182
# Nested block depths of scopes
183183
block_depth = None # type: List[int]
184184
# TypeInfo of directly enclosing class (or None)
185-
type = None # type: TypeInfo
185+
type = None # type: Optional[TypeInfo]
186186
# Stack of outer classes (the second tuple item contains tvars).
187187
type_stack = None # type: List[TypeInfo]
188188
# Type variables that are bound by the directly enclosing class
@@ -1745,10 +1745,10 @@ def build_newtype_typeinfo(self, name: str, old_type: Type, base_type: Instance)
17451745
info.is_newtype = True
17461746

17471747
# Add __init__ method
1748-
args = [Argument(Var('cls'), NoneTyp(), None, ARG_POS),
1748+
args = [Argument(Var('self'), NoneTyp(), None, ARG_POS),
17491749
self.make_argument('item', old_type)]
17501750
signature = CallableType(
1751-
arg_types=[cast(Type, None), old_type],
1751+
arg_types=[Instance(info, []), old_type],
17521752
arg_kinds=[arg.kind for arg in args],
17531753
arg_names=['self', 'item'],
17541754
ret_type=old_type,

mypy/subtypes.py

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -323,9 +323,11 @@ def is_callable_subtype(left: CallableType, right: CallableType,
323323

324324
if left.variables:
325325
# Apply generic type variables away in left via type inference.
326-
left = unify_generic_callable(left, right, ignore_return=ignore_return)
327-
if left is None:
326+
unified = unify_generic_callable(left, right, ignore_return=ignore_return)
327+
if unified is None:
328328
return False
329+
else:
330+
left = unified
329331

330332
# Check return types.
331333
if not ignore_return and not is_compat(left.ret_type, right.ret_type):
@@ -493,7 +495,7 @@ def are_args_compatible(
493495

494496

495497
def unify_generic_callable(type: CallableType, target: CallableType,
496-
ignore_return: bool) -> CallableType:
498+
ignore_return: bool) -> Optional[CallableType]:
497499
"""Try to unify a generic callable type with another callable type.
498500
499501
Return unified CallableType if successful; otherwise, return None.

mypy/test/testtypes.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -75,18 +75,18 @@ def test_tuple_type(self) -> None:
7575
assert_equal(str(TupleType([self.x, AnyType()], None)), 'Tuple[X?, Any]')
7676

7777
def test_type_variable_binding(self) -> None:
78-
assert_equal(str(TypeVarDef('X', 1, None, self.fx.o)), 'X')
78+
assert_equal(str(TypeVarDef('X', 1, [], self.fx.o)), 'X')
7979
assert_equal(str(TypeVarDef('X', 1, [self.x, self.y], self.fx.o)),
8080
'X in (X?, Y?)')
8181

8282
def test_generic_function_type(self) -> None:
8383
c = CallableType([self.x, self.y], [ARG_POS, ARG_POS], [None, None],
8484
self.y, self.function, name=None,
85-
variables=[TypeVarDef('X', -1, None, self.fx.o)])
85+
variables=[TypeVarDef('X', -1, [], self.fx.o)])
8686
assert_equal(str(c), 'def [X] (X?, Y?) -> Y?')
8787

88-
v = [TypeVarDef('Y', -1, None, self.fx.o),
89-
TypeVarDef('X', -2, None, self.fx.o)]
88+
v = [TypeVarDef('Y', -1, [], self.fx.o),
89+
TypeVarDef('X', -2, [], self.fx.o)]
9090
c2 = CallableType([], [], [], NoneTyp(), self.function, name=None, variables=v)
9191
assert_equal(str(c2), 'def [Y, X] ()')
9292

mypy/typefixture.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -216,7 +216,7 @@ def make_type_info(self, name: str,
216216
variance = variances[id - 1]
217217
else:
218218
variance = COVARIANT
219-
v.append(TypeVarDef(n, id, None, self.o, variance=variance))
219+
v.append(TypeVarDef(n, id, [], self.o, variance=variance))
220220
class_def.type_vars = v
221221

222222
info = TypeInfo(SymbolTable(), class_def, module_name)

0 commit comments

Comments
 (0)