Skip to content

Commit 3a1dc4c

Browse files
authored
Remove some not needed (and dangerous) uses of get_proper_type (#15198)
This is in preparation for support of variadic type aliases. This PR should be a no-op from user perspective. Note I also added a test to prohibit new usages of `get_proper_type()` in `expand_type()`, since this can easily create unwanted recursion.
1 parent ba8ae29 commit 3a1dc4c

File tree

8 files changed

+36
-23
lines changed

8 files changed

+36
-23
lines changed

misc/proper_plugin.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,7 @@ def is_special_target(right: ProperType) -> bool:
8888
"mypy.types.UnpackType",
8989
"mypy.types.TypeVarTupleType",
9090
"mypy.types.ParamSpecType",
91+
"mypy.types.Parameters",
9192
"mypy.types.RawExpressionType",
9293
"mypy.types.EllipsisType",
9394
"mypy.types.StarType",

mypy/checkexpr.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2057,7 +2057,7 @@ def check_argument_types(
20572057
if (
20582058
isinstance(first_actual_arg_type, TupleType)
20592059
and len(first_actual_arg_type.items) == 1
2060-
and isinstance(get_proper_type(first_actual_arg_type.items[0]), UnpackType)
2060+
and isinstance(first_actual_arg_type.items[0], UnpackType)
20612061
):
20622062
# TODO: use walrus operator
20632063
actual_types = [first_actual_arg_type.items[0]] + [
@@ -2084,7 +2084,7 @@ def check_argument_types(
20842084
callee_arg_types = unpacked_type.items
20852085
callee_arg_kinds = [ARG_POS] * len(actuals)
20862086
else:
2087-
inner_unpack = get_proper_type(unpacked_type.items[inner_unpack_index])
2087+
inner_unpack = unpacked_type.items[inner_unpack_index]
20882088
assert isinstance(inner_unpack, UnpackType)
20892089
inner_unpacked_type = get_proper_type(inner_unpack.type)
20902090
# We assume heterogenous tuples are desugared earlier

mypy/constraints.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -146,7 +146,7 @@ def infer_constraints_for_callable(
146146
# not to hold we can always handle the prefixes too.
147147
inner_unpack = unpacked_type.items[0]
148148
assert isinstance(inner_unpack, UnpackType)
149-
inner_unpacked_type = get_proper_type(inner_unpack.type)
149+
inner_unpacked_type = inner_unpack.type
150150
assert isinstance(inner_unpacked_type, TypeVarTupleType)
151151
suffix_len = len(unpacked_type.items) - 1
152152
constraints.append(

mypy/expandtype.py

Lines changed: 8 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -271,10 +271,11 @@ def interpolate_args_for_unpack(
271271
star_index = t.arg_kinds.index(ARG_STAR)
272272

273273
# We have something like Unpack[Tuple[X1, X2, Unpack[Ts], Y1, Y2]]
274-
if isinstance(get_proper_type(var_arg.type), TupleType):
275-
expanded_tuple = get_proper_type(var_arg.type.accept(self))
274+
var_arg_type = get_proper_type(var_arg.type)
275+
if isinstance(var_arg_type, TupleType):
276+
expanded_tuple = var_arg_type.accept(self)
276277
# TODO: handle the case that expanded_tuple is a variable length tuple.
277-
assert isinstance(expanded_tuple, TupleType)
278+
assert isinstance(expanded_tuple, ProperType) and isinstance(expanded_tuple, TupleType)
278279
expanded_items = expanded_tuple.items
279280
else:
280281
expanded_items_res = self.expand_unpack(var_arg)
@@ -320,11 +321,11 @@ def interpolate_args_for_unpack(
320321
# homogenous tuple, then only the prefix can be represented as
321322
# positional arguments, and we pass Tuple[Unpack[Ts-1], Y1, Y2]
322323
# as the star arg, for example.
323-
expanded_unpack = get_proper_type(expanded_items[expanded_unpack_index])
324+
expanded_unpack = expanded_items[expanded_unpack_index]
324325
assert isinstance(expanded_unpack, UnpackType)
325326

326327
# Extract the typevartuple so we can get a tuple fallback from it.
327-
expanded_unpacked_tvt = get_proper_type(expanded_unpack.type)
328+
expanded_unpacked_tvt = expanded_unpack.type
328329
assert isinstance(expanded_unpacked_tvt, TypeVarTupleType)
329330

330331
prefix_len = expanded_unpack_index
@@ -450,18 +451,14 @@ def visit_tuple_type(self, t: TupleType) -> Type:
450451
items = self.expand_types_with_unpack(t.items)
451452
if isinstance(items, list):
452453
fallback = t.partial_fallback.accept(self)
453-
fallback = get_proper_type(fallback)
454-
if not isinstance(fallback, Instance):
455-
fallback = t.partial_fallback
454+
assert isinstance(fallback, ProperType) and isinstance(fallback, Instance)
456455
return t.copy_modified(items=items, fallback=fallback)
457456
else:
458457
return items
459458

460459
def visit_typeddict_type(self, t: TypedDictType) -> Type:
461460
fallback = t.fallback.accept(self)
462-
fallback = get_proper_type(fallback)
463-
if not isinstance(fallback, Instance):
464-
fallback = t.fallback
461+
assert isinstance(fallback, ProperType) and isinstance(fallback, Instance)
465462
return t.copy_modified(item_types=self.expand_types(t.items.values()), fallback=fallback)
466463

467464
def visit_literal_type(self, t: LiteralType) -> Type:

mypy/semanal.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -936,7 +936,7 @@ def analyze_func_def(self, defn: FuncDef) -> None:
936936
def remove_unpack_kwargs(self, defn: FuncDef, typ: CallableType) -> CallableType:
937937
if not typ.arg_kinds or typ.arg_kinds[-1] is not ArgKind.ARG_STAR2:
938938
return typ
939-
last_type = get_proper_type(typ.arg_types[-1])
939+
last_type = typ.arg_types[-1]
940940
if not isinstance(last_type, UnpackType):
941941
return typ
942942
last_type = get_proper_type(last_type.type)

mypy/test/testtypes.py

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,10 @@
22

33
from __future__ import annotations
44

5+
import re
6+
from unittest import TestCase, skipUnless
7+
8+
import mypy.expandtype
59
from mypy.erasetype import erase_type, remove_instance_last_known_values
610
from mypy.expandtype import expand_type
711
from mypy.indirection import TypeIndirectionVisitor
@@ -1435,3 +1439,16 @@ def make_call(*items: tuple[str, str | None]) -> CallExpr:
14351439
else:
14361440
arg_kinds.append(ARG_POS)
14371441
return CallExpr(NameExpr("f"), args, arg_kinds, arg_names)
1442+
1443+
1444+
class TestExpandTypeLimitGetProperType(TestCase):
1445+
# WARNING: do not increase this number unless absolutely necessary,
1446+
# and you understand what you are doing.
1447+
ALLOWED_GET_PROPER_TYPES = 7
1448+
1449+
@skipUnless(mypy.expandtype.__file__.endswith(".py"), "Skip for compiled mypy")
1450+
def test_count_get_proper_type(self) -> None:
1451+
with open(mypy.expandtype.__file__) as f:
1452+
code = f.read()
1453+
get_proper_type_count = len(re.findall("get_proper_type", code))
1454+
assert get_proper_type_count == self.ALLOWED_GET_PROPER_TYPES

mypy/typevartuples.py

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -11,8 +11,7 @@
1111
def find_unpack_in_list(items: Sequence[Type]) -> int | None:
1212
unpack_index: int | None = None
1313
for i, item in enumerate(items):
14-
proper_item = get_proper_type(item)
15-
if isinstance(proper_item, UnpackType):
14+
if isinstance(item, UnpackType):
1615
# We cannot fail here, so we must check this in an earlier
1716
# semanal phase.
1817
# Funky code here avoids mypyc narrowing the type of unpack_index.
@@ -181,9 +180,8 @@ def fully_split_with_mapped_and_template(
181180
def extract_unpack(types: Sequence[Type]) -> ProperType | None:
182181
"""Given a list of types, extracts either a single type from an unpack, or returns None."""
183182
if len(types) == 1:
184-
proper_type = get_proper_type(types[0])
185-
if isinstance(proper_type, UnpackType):
186-
return get_proper_type(proper_type.type)
183+
if isinstance(types[0], UnpackType):
184+
return get_proper_type(types[0].type)
187185
return None
188186

189187

test-data/unit/check-typevar-tuple.test

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -201,7 +201,7 @@ class Array(Generic[Unpack[Shape]]):
201201

202202
def get_shape(self) -> Tuple[Unpack[Shape]]:
203203
return self._shape
204-
204+
205205
def __abs__(self) -> Array[Unpack[Shape]]: ...
206206

207207
def __add__(self, other: Array[Unpack[Shape]]) -> Array[Unpack[Shape]]: ...
@@ -237,7 +237,7 @@ class Array(Generic[DType, Unpack[Shape]]):
237237

238238
def get_shape(self) -> Tuple[Unpack[Shape]]:
239239
return self._shape
240-
240+
241241
def __abs__(self) -> Array[DType, Unpack[Shape]]: ...
242242

243243
def __add__(self, other: Array[DType, Unpack[Shape]]) -> Array[DType, Unpack[Shape]]: ...
@@ -443,7 +443,7 @@ def foo(*args: Unpack[Tuple[int, ...]]) -> None:
443443

444444
foo(0, 1, 2)
445445
# TODO: this should say 'expected "int"' rather than the unpack
446-
foo(0, 1, "bar") # E: Argument 3 to "foo" has incompatible type "str"; expected "Unpack[Tuple[int, ...]]"
446+
foo(0, 1, "bar") # E: Argument 3 to "foo" has incompatible type "str"; expected "Unpack[Tuple[int, ...]]"
447447

448448

449449
def foo2(*args: Unpack[Tuple[str, Unpack[Tuple[int, ...]], bool, bool]]) -> None:

0 commit comments

Comments
 (0)