Skip to content

Commit c332ea0

Browse files
ilevkivskyigvanrossum
authored andcommitted
Fix recently reported partial type crashes (#3995)
Fixes #3986 and two additional similar crashes on partial types.
1 parent 9615b9e commit c332ea0

File tree

3 files changed

+53
-8
lines changed

3 files changed

+53
-8
lines changed

mypy/applytype.py

+3-3
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ def apply_generic_arguments(callable: CallableType, orig_types: Sequence[Optiona
2323
# values and bounds. Also, promote subtype values to allowed values.
2424
types = list(orig_types)
2525
for i, type in enumerate(types):
26+
assert not isinstance(type, PartialType), "Internal error: must never apply partial type"
2627
values = callable.variables[i].values
2728
if values and type:
2829
if isinstance(type, AnyType):
@@ -34,14 +35,13 @@ def apply_generic_arguments(callable: CallableType, orig_types: Sequence[Optiona
3435
for v1 in type.values):
3536
continue
3637
for value in values:
37-
if isinstance(type, PartialType) or mypy.subtypes.is_subtype(type, value):
38+
if mypy.subtypes.is_subtype(type, value):
3839
types[i] = value
3940
break
4041
else:
4142
msg.incompatible_typevar_value(callable, type, callable.variables[i].name, context)
4243
upper_bound = callable.variables[i].upper_bound
43-
if (type and not isinstance(type, PartialType) and
44-
not mypy.subtypes.is_subtype(type, upper_bound)):
44+
if type and not mypy.subtypes.is_subtype(type, upper_bound):
4545
msg.incompatible_typevar_value(callable, type, callable.variables[i].name, context)
4646

4747
# Create a map from type variable id to target type.

mypy/checker.py

+10-5
Original file line numberDiff line numberDiff line change
@@ -110,6 +110,9 @@ class TypeChecker(NodeVisitor[None], CheckerPluginInterface):
110110
dynamic_funcs = None # type: List[bool]
111111
# Stack of collections of variables with partial types
112112
partial_types = None # type: List[Dict[Var, Context]]
113+
# Vars for which partial type errors are already reported
114+
# (to avoid logically duplicate errors with different error context).
115+
partial_reported = None # type: Set[Var]
113116
globals = None # type: SymbolTable
114117
modules = None # type: Dict[str, MypyFile]
115118
# Nodes that couldn't be checked because some types weren't available. We'll run
@@ -157,6 +160,7 @@ def __init__(self, errors: Errors, modules: Dict[str, MypyFile], options: Option
157160
self.return_types = []
158161
self.dynamic_funcs = []
159162
self.partial_types = []
163+
self.partial_reported = set()
160164
self.deferred_nodes = []
161165
self.type_map = {}
162166
self.module_refs = set()
@@ -1681,7 +1685,7 @@ def lvalue_type_for_inference(self, lvalues: List[Lvalue], rvalue_type: TupleTyp
16811685
def append_types_for_inference(lvs: List[Expression], rv_types: List[Type]) -> None:
16821686
for lv, rv_type in zip(lvs, rv_types):
16831687
sub_lvalue_type, index_expr, inferred = self.check_lvalue(lv)
1684-
if sub_lvalue_type:
1688+
if sub_lvalue_type and not isinstance(sub_lvalue_type, PartialType):
16851689
type_parameters.append(sub_lvalue_type)
16861690
else: # index lvalue
16871691
# TODO Figure out more precise type context, probably
@@ -1692,7 +1696,7 @@ def append_types_for_inference(lvs: List[Expression], rv_types: List[Type]) -> N
16921696

16931697
if star_lv:
16941698
sub_lvalue_type, index_expr, inferred = self.check_lvalue(star_lv.expr)
1695-
if sub_lvalue_type:
1699+
if sub_lvalue_type and not isinstance(sub_lvalue_type, PartialType):
16961700
type_parameters.extend([sub_lvalue_type] * len(star_rv_types))
16971701
else: # index lvalue
16981702
# TODO Figure out more precise type context, probably
@@ -1845,8 +1849,8 @@ def set_inferred_type(self, var: Var, lvalue: Lvalue, type: Type) -> None:
18451849
var.is_inferred = True
18461850
if isinstance(lvalue, MemberExpr) and self.inferred_attribute_types is not None:
18471851
# Store inferred attribute type so that we can check consistency afterwards.
1848-
assert lvalue.def_var is not None
1849-
self.inferred_attribute_types[lvalue.def_var] = type
1852+
if lvalue.def_var is not None:
1853+
self.inferred_attribute_types[lvalue.def_var] = type
18501854
self.store_type(lvalue, type)
18511855

18521856
def set_inference_error_fallback_type(self, var: Var, lvalue: Lvalue, type: Type,
@@ -2655,9 +2659,10 @@ def enter_partial_types(self) -> Iterator[None]:
26552659
if isinstance(var.type, PartialType) and var.type.type is None:
26562660
# None partial type: assume variable is intended to have type None
26572661
var.type = NoneTyp()
2658-
else:
2662+
elif var not in self.partial_reported:
26592663
self.msg.fail(messages.NEED_ANNOTATION_FOR_VAR, context)
26602664
var.type = AnyType(TypeOfAny.from_error)
2665+
self.partial_reported.add(var)
26612666

26622667
def find_partial_types(self, var: Var) -> Optional[Dict[Var, Context]]:
26632668
for partial_types in reversed(self.partial_types):

test-data/unit/check-inference.test

+40
Original file line numberDiff line numberDiff line change
@@ -1887,3 +1887,43 @@ C[0] = 0
18871887
[out]
18881888
main:4: error: Type expected within [...]
18891889
main:4: error: Unsupported target for indexed assignment
1890+
1891+
[case testNoCrashOnPartialMember]
1892+
class C:
1893+
x = None
1894+
def __init__(self) -> None:
1895+
self.x = [] # E: Need type annotation for variable
1896+
[builtins fixtures/list.pyi]
1897+
[out]
1898+
1899+
[case testNoCrashOnPartialVariable]
1900+
from typing import Tuple, TypeVar
1901+
T = TypeVar('T', bound=str)
1902+
1903+
def f(x: T) -> Tuple[T]:
1904+
...
1905+
x = None
1906+
(x,) = f('')
1907+
reveal_type(x) # E: Revealed type is 'builtins.str'
1908+
[out]
1909+
1910+
[case testNoCrashOnPartialVariable2]
1911+
from typing import Tuple, TypeVar
1912+
T = TypeVar('T', bound=str)
1913+
1914+
def f() -> Tuple[T]:
1915+
...
1916+
x = None
1917+
(x,) = f()
1918+
[out]
1919+
1920+
[case testNoCrashOnPartialVariable3]
1921+
from typing import Tuple, TypeVar
1922+
T = TypeVar('T')
1923+
1924+
def f(x: T) -> Tuple[T, T]:
1925+
...
1926+
x = None
1927+
(x, x) = f('')
1928+
reveal_type(x) # E: Revealed type is 'builtins.str'
1929+
[out]

0 commit comments

Comments
 (0)