8000 Subtyping and inference of user defined variadic types by ilevkivskyi · Pull Request #16076 · python/mypy · GitHub
[go: up one dir, main page]

Skip to content

Subtyping and inference of user defined variadic types #16076

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 14 commits into from
Sep 13, 2023
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
Add (and clean-up) tests
  • Loading branch information
ilevkivskyi committed Sep 13, 2023
commit 6946a49ec0f29dcdbffba4b14eabfef3e94511fb
13 changes: 1 addition & 12 deletions mypy/test/testconstraints.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,6 @@ def test_basic_type_variable(self) -> None:
Constraint(type_var=fx.t, op=direction, target=fx.a)
]

# TODO: some tests here use non-normalized variadic forms (mostly fixed tuple unpacks).
# We may want to either replace these with normalized ones, or add matching normalized tests.
def test_basic_type_var_tuple_subtype(self) -> None:
fx = self.fx
assert infer_constraints(
Expand Down Expand Up @@ -103,16 +101,7 @@ def test_unpack_tuple_length_non_match(self) -> None:
fx = self.fx
assert set(
infer_constraints(
Instance(
fx.gv2i,
[
fx.u,
UnpackType(
TupleType([fx.t, fx.s], fallback=Instance(fx.std_tuplei, [fx.o]))
),
fx.u,
],
),
Instance(fx.gv2i, [fx.u, fx.t, fx.s, fx.u]),
Instance(fx.gv2i, [fx.a, fx.b, fx.d]),
SUPERTYPE_OF,
)
Expand Down
33 changes: 0 additions & 33 deletions mypy/test/testsubtypes.py
Original file line number Diff line number Diff line change
Expand Up @@ -198,8 +198,6 @@ def test_type_callable_subtyping(self) -> None:
self.fx.callable_type(self.fx.a, self.fx.b), self.fx.callable(self.fx.a, self.fx.b)
)

# TODO: some tests here use non-normalized variadic forms (mostly fixed tuple unpacks).
# We may want to either replace these with normalized ones, or add matching normalized tests.
def test_type_var_tuple(self) -> None:
self.assert_subtype(Instance(self.fx.gvi, []), Instance(self.fx.gvi, []))
self.assert_subtype(
Expand Down Expand Up @@ -270,37 +268,6 @@ def test_type_var_tuple_with_prefix_suffix(self) -> None:
Instance(self.fx.gvi, [self.fx.a, UnpackType(self.fx.ss), self.fx.b, self.fx.c]),
)

def test_type_var_tuple_unpacked_tuple(self) -> None:
self.assert_not_subtype(
Instance(
self.fx.gvi,
[
UnpackType(
TupleType(
[self.fx.a, self.fx.b],
fallback=Instance(self.fx.std_tuplei, [self.fx.o]),
)
)
],
),
Instance(self.fx.gvi, [self.fx.a]),
)
self.assert_not_subtype(
Instance(
self.fx.gvi,
[
UnpackType(
TupleType(
[self.fx.a, self.fx.b],
fallback=Instance(self.fx.std_tuplei, [self.fx.o]),
)
)
],
),
# Order flipped here.
Instance(self.fx.gvi, [self.fx.b, self.fx.a]),
)

def test_type_var_tuple_unpacked_variable_length_tuple(self) -> None:
self.assert_subtype(
Instance(self.fx.gvi, [self.fx.a, self.fx.a]),
Expand Down
139 changes: 139 additions & 0 deletions test-data/unit/check-typevar-tuple.test
Original file line number Diff line number Diff line change
Expand Up @@ -1257,30 +1257,45 @@ t3: Tuple[Unpack[Tuple[int, ...]], int]
t4: Tuple[int, Unpack[Tuple[int, ...]], int]
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What about Tuple[int, int, Unpack[Tuple[int, ...]] (and similarly for a suffix)?

t5: Tuple[int, ...]

tl: Tuple[int, int, Unpack[Tuple[int, ...]]]
tr: Tuple[Unpack[Tuple[int, ...]], int, int]

f1(t1)
f1(t2)
f1(t3)
f1(t4)
f1(t5)

f1(tl)
f1(tr)

f2(t1)
f2(t2)
f2(t3)
f2(t4)
f2(t5) # E: Argument 1 to "f2" has incompatible type "Tuple[int, ...]"; expected "Tuple[float, Unpack[Tuple[float, ...]]]"

f2(tl)
f2(tr)

f3(t1)
f3(t2)
f3(t3)
f3(t4)
f3(t5) # E: Argument 1 to "f3" has incompatible type "Tuple[int, ...]"; expected "Tuple[Unpack[Tuple[float, ...]], float]"

f3(tl)
f3(tr)

f4(t1)
f4(t2) # E: Argument 1 to "f4" has incompatible type "Tuple[int, Unpack[Tuple[int, ...]]]"; expected "Tuple[float, Unpack[Tuple[float, ...]], float]"
f4(t3) # E: Argument 1 to "f4" has incompatible type "Tuple[Unpack[Tuple[int, ...]], int]"; expected "Tuple[float, Unpack[Tuple[float, ...]], float]"
f4(t4)
f4(t5) # E: Argument 1 to "f4" has incompatible type "Tuple[int, ...]"; expected "Tuple[float, Unpack[Tuple[float, ...]], float]"

f4(tl)
f4(tr)

t5_verbose: Tuple[Unpack[Tuple[int, ...]]]
t5 = t5_verbose # OK
[builtins fixtures/tuple.pyi]
Expand Down Expand Up @@ -1321,6 +1336,130 @@ class Array(Generic[Unpack[Ts]]):
self._close()
[builtins fixtures/tuple.pyi]

[case testVariadicSubclassFixed]
from typing import Generic, Tuple
from typing_extensions import TypeVarTuple, Unpack

Ts = TypeVarTuple("Ts")
class B(Generic[Unpack[Ts]]): ...
class C(B[int, str]): ...
class D(B[Unpack[Tuple[int, ...]]]): ...

def fii(x: B[int, int]) -> None: ...
def fis(x: B[int, str]) -> None: ...
def fiv(x: B[Unpack[Tuple[int, ...]]]) -> None: ...

fii(C()) # E: Argument 1 to "fii" has incompatible type "C"; expected "B[int, int]"
fii(D()) # E: Argument 1 to "fii" has incompatible type "D"; expected "B[int, int]"
fis(C())
fis(D()) # E: Argument 1 to "fis" has incompatible type "D"; expected "B[int, str]"
fiv(C()) # E: Argument 1 to "fiv" has incompatible type "C"; expected "B[Unpack[Tuple[int, ...]]]"
fiv(D())
[builtins fixtures/tuple.pyi]

[case testVariadicSubclassSame]
from typing import Generic, Tuple, TypeVar
from typing_extensions import TypeVarTuple, Unpack

Ts = TypeVarTuple("Ts")
class B(Generic[Unpack[Ts]]): ...
class C(B[Unpack[Ts]]): ...

def fii(x: B[int, int]) -> None: ...
def fis(x: B[int, str]) -> None: ...
def fiv(x: B[Unpack[Tuple[int, ...]]]) -> None: ...

cii: C[int, int]
cis: C[int, str]
civ: C[Unpack[Tuple[int, ...]]]

fii(cii)
fii(cis) # E: Argument 1 to "fii" has incompatible type "C[int, str]"; expected "B[int, int]"
fii(civ) # E: Argument 1 to "fii" has incompatible type "C[Unpack[Tuple[int, ...]]]"; expected "B[int, int]"

fis(cii) # E: Argument 1 to "fis" has incompatible type "C[int, int]"; expected "B[int, str]"
fis(cis)
fis(civ) # E: Argument 1 to "fis" has incompatible type "C[Unpack[Tuple[int, ...]]]"; expected "B[int, str]"

fiv(cii)
fiv(cis) # E: Argument 1 to "fiv" has incompatible type "C[int, str]"; expected "B[Unpack[Tuple[int, ...]]]"
fiv(civ)
[builtins fixtures/tuple.pyi]

[case testVariadicSubclassExtra]
from typing import Generic, Tuple, TypeVar
from typing_extensions import TypeVarTuple, Unpack

Ts = TypeVarTuple("Ts")
class B(Generic[Unpack[Ts]]): ...

T = TypeVar("T")
class C(B[int, Unpack[Ts], T]): ...

def ff(x: B[int, int, int]) -> None: ...
def fv(x: B[Unpack[Tuple[int, ...]]]) -> None: ...

cii: C[int, int]
cis: C[int, str]
civ: C[Unpack[Tuple[int, ...]]]

ff(cii)
ff(cis) # E: Argument 1 to "ff" has incompatible type "C[int, str]"; expected "B[int, int, int]"
ff(civ) # E: Argument 1 to "ff" has incompatible type "C[Unpack[Tuple[int, ...]]]"; expected "B[int, int, int]"

fv(cii)
fv(cis) # E: Argument 1 to "fv" has incompatible type "C[int, str]"; expected "B[Unpack[Tuple[int, ...]]]"
fv(civ)
[builtins fixtures/tuple.pyi]

[case testVariadicSubclassVariadic]
from typing import Generic, Tuple, TypeVar
from typing_extensions import TypeVarTuple, Unpack

Ts = TypeVarTuple("Ts")
class B(Generic[Unpack[Ts]]): ...
T = TypeVar("T")
class C(B[Unpack[Tuple[T, ...]]]): ...

def ff(x: B[int, int]) -> None: ...
def fv(x: B[Unpack[Tuple[int, ...]]]) -> None: ...

ci: C[int]
ff(ci) # E: Argument 1 to "ff" has incompatible type "C[int]"; expected "B[int, int]"
fv(ci)
[builtins fixtures/tuple.pyi]

[case testVariadicSubclassMethodAccess]
from typing import Generic, Tuple, TypeVar
from typing_extensions import TypeVarTuple, Unpack

Ts = TypeVarTuple("Ts")
class B(Generic[Unpack[Ts]]):
def meth(self) -> Tuple[Unpack[Ts]]: ...

class C1(B[int, str]): ...
class C2(B[Unpack[Ts]]): ...
T = TypeVar("T")
class C3(B[int, Unpack[Ts], T]): ...
class C4(B[Unpack[Tuple[T, ...]]]): ...

c1: C1
reveal_type(c1.meth()) # N: Revealed type is "Tuple[builtins.int, builtins.str]"

c2f: C2[int, str]
c2v: C2[Unpack[Tuple[int, ...]]]
reveal_type(c2f.meth()) # N: Revealed type is "Tuple[builtins.int, builtins.str]"
reveal_type(c2v.meth()) # N: Revealed type is "builtins.tuple[builtins.int, ...]"

c3f: C3[int, str]
c3v: C3[Unpack[Tuple[int, ...]]]
reveal_type(c3f.meth()) # N: Revealed type is "Tuple[builtins.int, builtins.int, builtins.str]"
reveal_type(c3v.meth()) # N: Revealed type is "Tuple[builtins.int, Unpack[builtins.tuple[builtins.int, ...]], builtins.int]"

c4: C4[int]
reveal_type(c4.meth()) # N: Revealed type is "builtins.tuple[builtins.int, ...]"
[builtins fixtures/tuple.pyi]

[case testVariadicTupleAnySubtype]
from typing import Any, Generic, Tuple
from typing_extensions import TypeVarTuple, Unpack
Expand Down
0