Skip to content

Commit e8c2f72

Browse files
serhiy-storchakaMatthew Rahtz
and
Matthew Rahtz
authored
bpo-43224: Implement substitution of unpacked TypeVarTuple in C (GH-31828)
Co-authored-by: Matthew Rahtz <[email protected]>
1 parent a29aa76 commit e8c2f72

File tree

5 files changed

+152
-41
lines changed

5 files changed

+152
-41
lines changed

Include/internal/pycore_global_strings.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -202,6 +202,7 @@ struct _Py_global_strings {
202202
STRUCT_FOR_ID(__truediv__)
203203
STRUCT_FOR_ID(__trunc__)
204204
STRUCT_FOR_ID(__typing_subst__)
205+
STRUCT_FOR_ID(__typing_unpacked__)
205206
STRUCT_FOR_ID(__warningregistry__)
206207
STRUCT_FOR_ID(__weakref__)
207208
STRUCT_FOR_ID(__xor__)

Include/internal/pycore_runtime_init.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -825,6 +825,7 @@ extern "C" {
825825
INIT_ID(__truediv__), \
826826
INIT_ID(__trunc__), \
827827
INIT_ID(__typing_subst__), \
828+
INIT_ID(__typing_unpacked__), \
828829
INIT_ID(__warningregistry__), \
829830
INIT_ID(__weakref__), \
830831
INIT_ID(__xor__), \

Lib/test/test_typing.py

Lines changed: 39 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -754,89 +754,89 @@ class C(Generic[*Ts]): pass
754754
tests = [
755755
# Alias # Args # Expected result
756756
('C[*Ts]', '[()]', 'C[()]'),
757-
('tuple[*Ts]', '[()]', 'TypeError'), # Should be tuple[()]
757+
('tuple[*Ts]', '[()]', 'tuple[()]'),
758758
('Tuple[*Ts]', '[()]', 'Tuple[()]'),
759759

760760
('C[*Ts]', '[int]', 'C[int]'),
761-
('tuple[*Ts]', '[int]', 'tuple[(int,),]'), # Should be tuple[int]
761+
('tuple[*Ts]', '[int]', 'tuple[int]'),
762762
('Tuple[*Ts]', '[int]', 'Tuple[int]'),
763763

764764
('C[*Ts]', '[int, str]', 'C[int, str]'),
765-
('tuple[*Ts]', '[int, str]', 'TypeError'), # Should be tuple[int, str]
765+
('tuple[*Ts]', '[int, str]', 'tuple[int, str]'),
766766
('Tuple[*Ts]', '[int, str]', 'Tuple[int, str]'),
767767

768768
('C[*Ts]', '[*tuple_type[int]]', 'C[*tuple_type[int]]'), # Should be C[int]
769-
('tuple[*Ts]', '[*tuple_type[int]]', 'tuple[(*tuple_type[int],),]'), # Should be tuple[int]
769+
('tuple[*Ts]', '[*tuple_type[int]]', 'tuple[*tuple_type[int]]'), # Should be tuple[int]
770770
('Tuple[*Ts]', '[*tuple_type[int]]', 'Tuple[*tuple_type[int]]'), # Should be Tuple[int]
771771

772772
('C[*Ts]', '[*tuple_type[*Ts]]', 'C[*tuple_type[*Ts]]'), # Should be C[*Ts]
773-
('tuple[*Ts]', '[*tuple_type[*Ts]]', 'tuple[(*tuple_type[*Ts],),]'), # Should be tuple[*Ts]
773+
('tuple[*Ts]', '[*tuple_type[*Ts]]', 'tuple[*tuple_type[*Ts]]'), # Should be tuple[*Ts]
774774
('Tuple[*Ts]', '[*tuple_type[*Ts]]', 'Tuple[*tuple_type[*Ts]]'), # Should be Tuple[*Ts]
775775

776776
('C[*Ts]', '[*tuple_type[int, str]]', 'C[*tuple_type[int, str]]'), # Should be C[int, str]
777-
('tuple[*Ts]', '[*tuple_type[int, str]]', 'tuple[(*tuple_type[int, str],),]'), # Should be tuple[int, str]
777+
('tuple[*Ts]', '[*tuple_type[int, str]]', 'tuple[*tuple_type[int, str]]'), # Should be tuple[int, str]
778778
('Tuple[*Ts]', '[*tuple_type[int, str]]', 'Tuple[*tuple_type[int, str]]'), # Should be Tuple[int, str]
779779

780780
('C[*Ts]', '[tuple_type[int, ...]]', 'C[tuple_type[int, ...]]'),
781-
('tuple[*Ts]', '[tuple_type[int, ...]]', 'tuple[(tuple_type[int, ...],),]'), # Should be tuple[tuple_type[int, ...]]
781+
('tuple[*Ts]', '[tuple_type[int, ...]]', 'tuple[tuple_type[int, ...]]'),
782782
('Tuple[*Ts]', '[tuple_type[int, ...]]', 'Tuple[tuple_type[int, ...]]'),
783783

784784
('C[*Ts]', '[tuple_type[int, ...], tuple_type[str, ...]]', 'C[tuple_type[int, ...], tuple_type[str, ...]]'),
785-
('tuple[*Ts]', '[tuple_type[int, ...], tuple_type[str, ...]]', 'TypeError'), # Should be tuple[tuple_type[int, ...], tuple_type[str, ...]]
785+
('tuple[*Ts]', '[tuple_type[int, ...], tuple_type[str, ...]]', 'tuple[tuple_type[int, ...], tuple_type[str, ...]]'),
786786
('Tuple[*Ts]', '[tuple_type[int, ...], tuple_type[str, ...]]', 'Tuple[tuple_type[int, ...], tuple_type[str, ...]]'),
787787

788788
('C[*Ts]', '[*tuple_type[int, ...]]', 'C[*tuple_type[int, ...]]'),
789-
('tuple[*Ts]', '[*tuple_type[int, ...]]', 'tuple[(*tuple_type[int, ...],),]'), # Should be tuple[*tuple_type[int, ...]]
789+
('tuple[*Ts]', '[*tuple_type[int, ...]]', 'tuple[*tuple_type[int, ...]]'),
790790
('Tuple[*Ts]', '[*tuple_type[int, ...]]', 'Tuple[*tuple_type[int, ...]]'),
791791

792792
# Technically, multiple unpackings are forbidden by PEP 646, but we
793793
# choose to be less restrictive at runtime, to allow folks room
794794
# to experiment. So all three of these should be valid.
795795
('C[*Ts]', '[*tuple_type[int, ...], *tuple_type[str, ...]]', 'C[*tuple_type[int, ...], *tuple_type[str, ...]]'),
796-
# Should be tuple[*tuple_type[int, ...], *tuple_type[str, ...]], to match the other two.
797-
('tuple[*Ts]', '[*tuple_type[int, ...], *tuple_type[str, ...]]', 'TypeError'),
796+
('tuple[*Ts]', '[*tuple_type[int, ...], *tuple_type[str, ...]]', 'tuple[*tuple_type[int, ...], *tuple_type[str, ...]]'),
798797
('Tuple[*Ts]', '[*tuple_type[int, ...], *tuple_type[str, ...]]', 'Tuple[*tuple_type[int, ...], *tuple_type[str, ...]]'),
799798

800799
('C[*Ts]', '[*Ts]', 'C[*Ts]'),
801-
('tuple[*Ts]', '[*Ts]', 'tuple[(*Ts,),]'), # Should be tuple[*Ts]
800+
('tuple[*Ts]', '[*Ts]', 'tuple[*Ts]'),
802801
('Tuple[*Ts]', '[*Ts]', 'Tuple[*Ts]'),
803802

804803
('C[*Ts]', '[T, *Ts]', 'C[T, *Ts]'),
805-
('tuple[*Ts]', '[T, *Ts]', 'TypeError'), # Should be tuple[T, *Ts]
804+
('tuple[*Ts]', '[T, *Ts]', 'tuple[T, *Ts]'),
806805
('Tuple[*Ts]', '[T, *Ts]', 'Tuple[T, *Ts]'),
807806

808807
('C[*Ts]', '[*Ts, T]', 'C[*Ts, T]'),
809-
('tuple[*Ts]', '[*Ts, T]', 'TypeError'), # Should be tuple[*Ts, T]
808+
('tuple[*Ts]', '[*Ts, T]', 'tuple[*Ts, T]'),
810809
('Tuple[*Ts]', '[*Ts, T]', 'Tuple[*Ts, T]'),
811810

812811
('C[T, *Ts]', '[int]', 'C[int]'),
813-
('tuple[T, *Ts]', '[int]', 'TypeError'), # Should be tuple[int]
812+
('tuple[T, *Ts]', '[int]', 'tuple[int]'),
814813
('Tuple[T, *Ts]', '[int]', 'Tuple[int]'),
815814

816815
('C[T, *Ts]', '[int, str]', 'C[int, str]'),
817-
('tuple[T, *Ts]', '[int, str]', 'tuple[int, (str,)]'), # Should be tuple[int, str]
816+
('tuple[T, *Ts]', '[int, str]', 'tuple[int, str]'),
818817
('Tuple[T, *Ts]', '[int, str]', 'Tuple[int, str]'),
819818

820819
('C[T, *Ts]', '[int, str, bool]', 'C[int, str, bool]'),
821-
('tuple[T, *Ts]', '[int, str, bool]', 'TypeError'), # Should be tuple[int, str, bool]
820+
('tuple[T, *Ts]', '[int, str, bool]', 'tuple[int, str, bool]'),
822821
('Tuple[T, *Ts]', '[int, str, bool]', 'Tuple[int, str, bool]'),
823822

824823
('C[T, *Ts]', '[*tuple[int, ...]]', 'C[*tuple[int, ...]]'), # Should be C[int, *tuple[int, ...]]
825824
('C[T, *Ts]', '[*Tuple[int, ...]]', 'TypeError'), # Ditto
826-
('tuple[T, *Ts]', '[*tuple_type[int, ...]]', 'TypeError'), # Should be tuple[int, *tuple[int, ...]]
827-
('Tuple[T, *Ts]', '[*tuple[int, ...]]', 'Tuple[*tuple[int, ...]]'), # Ditto
828-
('Tuple[T, *Ts]', '[*Tuple[int, ...]]', 'TypeError'), # Ditto
825+
('tuple[T, *Ts]', '[*tuple[int, ...]]', 'tuple[*tuple[int, ...]]'), # Should be tuple[int, *tuple[int, ...]]
826+
('tuple[T, *Ts]', '[*Tuple[int, ...]]', 'TypeError'), # Should be tuple[int, *Tuple[int, ...]]
827+
('Tuple[T, *Ts]', '[*tuple[int, ...]]', 'Tuple[*tuple[int, ...]]'), # Should be Tuple[int, *tuple[int, ...]]
828+
('Tuple[T, *Ts]', '[*Tuple[int, ...]]', 'TypeError'), # Should be Tuple[int, *Tuple[int, ...]]
829829

830830
('C[*Ts, T]', '[int]', 'C[int]'),
831-
('tuple[*Ts, T]', '[int]', 'TypeError'), # Should be tuple[int]
831+
('tuple[*Ts, T]', '[int]', 'tuple[int]'),
832832
('Tuple[*Ts, T]', '[int]', 'Tuple[int]'),
833833

834834
('C[*Ts, T]', '[int, str]', 'C[int, str]'),
835-
('tuple[*Ts, T]', '[int, str]', 'tuple[(int,), str]'), # Should be tuple[int, str]
835+
('tuple[*Ts, T]', '[int, str]', 'tuple[int, str]'),
836836
('Tuple[*Ts, T]', '[int, str]', 'Tuple[int, str]'),
837837

838838
('C[*Ts, T]', '[int, str, bool]', 'C[int, str, bool]'),
839-
('tuple[*Ts, T]', '[int, str, bool]', 'TypeError'), # Should be tuple[int, str, bool]
839+
('tuple[*Ts, T]', '[int, str, bool]', 'tuple[int, str, bool]'),
840840
('Tuple[*Ts, T]', '[int, str, bool]', 'Tuple[int, str, bool]'),
841841

842842
('generic[T, *tuple_type[int, ...]]', '[str]', 'generic[str, *tuple_type[int, ...]]'),
@@ -945,7 +945,7 @@ def test_var_substitution(self):
945945
T2 = TypeVar('T2')
946946
class G(Generic[Unpack[Ts]]): pass
947947

948-
for A in G, Tuple:
948+
for A in G, Tuple, tuple:
949949
B = A[Unpack[Ts]]
950950
self.assertEqual(B[()], A[()])
951951
self.assertEqual(B[float], A[float])
@@ -984,6 +984,21 @@ def test_bad_var_substitution(self):
984984
T2 = TypeVar('T2')
985985
class G(Generic[Unpack[Ts]]): pass
986986

987+
for A in G, Tuple, tuple:
988+
B = A[Ts]
989+
with self.assertRaises(TypeError):
990+
B[int, str]
991+
992+
C = A[T, T2]
993+
with self.assertRaises(TypeError):
994+
C[Unpack[Ts]]
995+
996+
def test_repr_is_correct(self):
997+
Ts = TypeVarTuple('Ts')
998+
T = TypeVar('T')
999+
T2 = TypeVar('T2')
1000+
class G(Generic[Unpack[Ts]]): pass
1001+
9871002
for A in G, Tuple:
9881003
B = A[T, Unpack[Ts], str, T2]
9891004
with self.assertRaises(TypeError):

Lib/typing.py

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1019,7 +1019,7 @@ def __repr__(self):
10191019
return self.__name__
10201020

10211021
def __typing_subst__(self, arg):
1022-
raise AssertionError
1022+
raise TypeError("Substitution of bare TypeVarTuple is not supported")
10231023

10241024

10251025
class ParamSpecArgs(_Final, _Immutable, _root=True):
@@ -1686,11 +1686,15 @@ def __repr__(self):
16861686
return '*' + repr(self.__args__[0])
16871687

16881688
def __getitem__(self, args):
1689-
if (len(self.__parameters__) == 1 and
1690-
isinstance(self.__parameters__[0], TypeVarTuple)):
1689+
if self.__typing_unpacked__():
16911690
return args
16921691
return super().__getitem__(args)
16931692

1693+
def __typing_unpacked__(self):
1694+
# If x is Unpack[tuple[...]], __parameters__ will be empty.
1695+
return bool(self.__parameters__ and
1696+
isinstance(self.__parameters__[0], TypeVarTuple))
1697+
16941698

16951699
class Generic:
16961700
"""Abstract base class for generic types.

0 commit comments

Comments
 (0)