Skip to content

Commit 5788125

Browse files
committed
specify that type variable tuple should have variance
1 parent 825f144 commit 5788125

File tree

8 files changed

+198
-10
lines changed

8 files changed

+198
-10
lines changed
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
conformant = "Unsupported"
2+
conformance_automated = "Fail"
3+
errors_diff = """
4+
Line 13: Expected 1 errors
5+
Line 32: Expected 1 errors
6+
Line 39: Expected 1 errors
7+
Line 14: Unexpected errors ['generics_typevartuple_variance.py:14: error: Incompatible types in assignment (expression has type "ContravariantTypeVarTuple[object]", variable has type "ContravariantTypeVarTuple[int]") [assignment]']
8+
Line 18: Unexpected errors ['generics_typevartuple_variance.py:18: error: Missing return statement [empty-body]']
9+
Line 25: Unexpected errors ['generics_typevartuple_variance.py:25: error: Unexpected keyword argument "contravariant" for "TypeVarTuple" [misc]']
10+
Line 33: Unexpected errors ['generics_typevartuple_variance.py:33: error: Incompatible types in assignment (expression has type "ContravariantTypeVarTupleOld[object]", variable has type "ContravariantTypeVarTupleOld[int]") [assignment]']
11+
Line 35: Unexpected errors ['generics_typevartuple_variance.py:35: error: Unexpected keyword argument "covariant" for "TypeVarTuple" [misc]']
12+
Line 40: Unexpected errors ['generics_typevartuple_variance.py:40: error: Missing return statement [empty-body]']
13+
"""
14+
output = """
15+
generics_typevartuple_variance.py:14: error: Incompatible types in assignment (expression has type "ContravariantTypeVarTuple[object]", variable has type "ContravariantTypeVarTuple[int]") [assignment]
16+
generics_typevartuple_variance.py:18: error: Missing return statement [empty-body]
17+
generics_typevartuple_variance.py:21: error: Incompatible types in assignment (expression has type "CovariantTypeVarTuple[object]", variable has type "CovariantTypeVarTuple[int]") [assignment]
18+
generics_typevartuple_variance.py:25: error: Unexpected keyword argument "contravariant" for "TypeVarTuple" [misc]
19+
generics_typevartuple_variance.py:30: error: Missing return statement [empty-body]
20+
generics_typevartuple_variance.py:33: error: Incompatible types in assignment (expression has type "ContravariantTypeVarTupleOld[object]", variable has type "ContravariantTypeVarTupleOld[int]") [assignment]
21+
generics_typevartuple_variance.py:35: error: Unexpected keyword argument "covariant" for "TypeVarTuple" [misc]
22+
generics_typevartuple_variance.py:40: error: Missing return statement [empty-body]
23+
generics_typevartuple_variance.py:43: error: Incompatible types in assignment (expression has type "CovariantTypeVarTupleOld[object]", variable has type "CovariantTypeVarTupleOld[int]") [assignment]
24+
"""
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
conformant = "Unsupported"
2+
conformance_automated = "Fail"
3+
errors_diff = """
4+
Line 30: Expected 1 errors
5+
Line 39: Expected 1 errors
6+
Line 14: Unexpected errors ['`ContravariantTypeVarTuple[object]` is not assignable to `ContravariantTypeVarTuple[int]` [bad-assignment]']
7+
Line 22: Unexpected errors ['`CovariantTypeVarTuple[int]` is not assignable to `CovariantTypeVarTuple[object]` [bad-assignment]']
8+
Line 25: Unexpected errors ['Unexpected keyword argument `contravariant` to TypeVarTuple [invalid-type-var-tuple]']
9+
Line 33: Unexpected errors ['`ContravariantTypeVarTupleOld[object]` is not assignable to `ContravariantTypeVarTupleOld[int]` [bad-assignment]']
10+
Line 35: Unexpected errors ['Unexpected keyword argument `covariant` to TypeVarTuple [invalid-type-var-tuple]']
11+
Line 44: Unexpected errors ['`CovariantTypeVarTupleOld[int]` is not assignable to `CovariantTypeVarTupleOld[object]` [bad-assignment]']
12+
"""
13+
output = """
14+
ERROR generics_typevartuple_variance.py:13:45-77: `ContravariantTypeVarTuple[int]` is not assignable to `ContravariantTypeVarTuple[object]` [bad-assignment]
15+
ERROR generics_typevartuple_variance.py:14:42-77: `ContravariantTypeVarTuple[object]` is not assignable to `ContravariantTypeVarTuple[int]` [bad-assignment]
16+
ERROR generics_typevartuple_variance.py:21:39-70: `CovariantTypeVarTuple[object]` is not assignable to `CovariantTypeVarTuple[int]` [bad-assignment]
17+
ERROR generics_typevartuple_variance.py:22:42-70: `CovariantTypeVarTuple[int]` is not assignable to `CovariantTypeVarTuple[object]` [bad-assignment]
18+
ERROR generics_typevartuple_variance.py:25:29-47: Unexpected keyword argument `contravariant` to TypeVarTuple [invalid-type-var-tuple]
19+
ERROR generics_typevartuple_variance.py:32:52-87: `ContravariantTypeVarTupleOld[int]` is not assignable to `ContravariantTypeVarTupleOld[object]` [bad-assignment]
20+
ERROR generics_typevartuple_variance.py:33:49-87: `ContravariantTypeVarTupleOld[object]` is not assignable to `ContravariantTypeVarTupleOld[int]` [bad-assignment]
21+
ERROR generics_typevartuple_variance.py:35:31-45: Unexpected keyword argument `covariant` to TypeVarTuple [invalid-type-var-tuple]
22+
ERROR generics_typevartuple_variance.py:43:46-80: `CovariantTypeVarTupleOld[object]` is not assignable to `CovariantTypeVarTupleOld[int]` [bad-assignment]
23+
ERROR generics_typevartuple_variance.py:44:49-80: `CovariantTypeVarTupleOld[int]` is not assignable to `CovariantTypeVarTupleOld[object]` [bad-assignment]
24+
"""
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
conformant = "Unsupported"
2+
conformance_automated = "Fail"
3+
errors_diff = """
4+
Line 30: Expected 1 errors
5+
Line 39: Expected 1 errors
6+
Line 14: Unexpected errors ['generics_typevartuple_variance.py:14:42 - error: Type "ContravariantTypeVarTuple[object]" is not assignable to declared type "ContravariantTypeVarTuple[int]"']
7+
Line 22: Unexpected errors ['generics_typevartuple_variance.py:22:42 - error: Type "CovariantTypeVarTuple[int]" is not assignable to declared type "CovariantTypeVarTuple[object]"']
8+
Line 25: Unexpected errors ['generics_typevartuple_variance.py:25:29 - error: "contravariant" is unknown parameter to TypeVarTuple (reportGeneralTypeIssues)']
9+
Line 33: Unexpected errors ['generics_typevartuple_variance.py:33:49 - error: Type "ContravariantTypeVarTupleOld[object]" is not assignable to declared type "ContravariantTypeVarTupleOld[int]"']
10+
Line 35: Unexpected errors ['generics_typevartuple_variance.py:35:31 - error: "covariant" is unknown parameter to TypeVarTuple (reportGeneralTypeIssues)']
11+
Line 44: Unexpected errors ['generics_typevartuple_variance.py:44:49 - error: Type "CovariantTypeVarTupleOld[int]" is not assignable to declared type "CovariantTypeVarTupleOld[object]"']
12+
"""
13+
output = """
14+
generics_typevartuple_variance.py:13:45 - error: Type "ContravariantTypeVarTuple[int]" is not assignable to declared type "ContravariantTypeVarTuple[object]"
15+
  "ContravariantTypeVarTuple[int]" is not assignable to "ContravariantTypeVarTuple[object]"
16+
    Type parameter "InTs@ContravariantTypeVarTuple" is invariant, but "*tuple[int]" is not the same as "*tuple[object]" (reportAssignmentType)
17+
generics_typevartuple_variance.py:14:42 - error: Type "ContravariantTypeVarTuple[object]" is not assignable to declared type "ContravariantTypeVarTuple[int]"
18+
  "ContravariantTypeVarTuple[object]" is not assignable to "ContravariantTypeVarTuple[int]"
19+
    Type parameter "InTs@ContravariantTypeVarTuple" is invariant, but "*tuple[object]" is not the same as "*tuple[int]" (reportAssignmentType)
20+
generics_typevartuple_variance.py:21:39 - error: Type "CovariantTypeVarTuple[object]" is not assignable to declared type "CovariantTypeVarTuple[int]"
21+
  "CovariantTypeVarTuple[object]" is not assignable to "CovariantTypeVarTuple[int]"
22+
    Type parameter "OutTs@CovariantTypeVarTuple" is invariant, but "*tuple[object]" is not the same as "*tuple[int]" (reportAssignmentType)
23+
generics_typevartuple_variance.py:22:42 - error: Type "CovariantTypeVarTuple[int]" is not assignable to declared type "CovariantTypeVarTuple[object]"
24+
  "CovariantTypeVarTuple[int]" is not assignable to "CovariantTypeVarTuple[object]"
25+
    Type parameter "OutTs@CovariantTypeVarTuple" is invariant, but "*tuple[int]" is not the same as "*tuple[object]" (reportAssignmentType)
26+
generics_typevartuple_variance.py:25:29 - error: "contravariant" is unknown parameter to TypeVarTuple (reportGeneralTypeIssues)
27+
generics_typevartuple_variance.py:32:52 - error: Type "ContravariantTypeVarTupleOld[int]" is not assignable to declared type "ContravariantTypeVarTupleOld[object]"
28+
  "ContravariantTypeVarTupleOld[int]" is not assignable to "ContravariantTypeVarTupleOld[object]"
29+
    Type parameter "InTs@ContravariantTypeVarTupleOld" is invariant, but "*tuple[int]" is not the same as "*tuple[object]" (reportAssignmentType)
30+
generics_typevartuple_variance.py:33:49 - error: Type "ContravariantTypeVarTupleOld[object]" is not assignable to declared type "ContravariantTypeVarTupleOld[int]"
31+
  "ContravariantTypeVarTupleOld[object]" is not assignable to "ContravariantTypeVarTupleOld[int]"
32+
    Type parameter "InTs@ContravariantTypeVarTupleOld" is invariant, but "*tuple[object]" is not the same as "*tuple[int]" (reportAssignmentType)
33+
generics_typevartuple_variance.py:35:31 - error: "covariant" is unknown parameter to TypeVarTuple (reportGeneralTypeIssues)
34+
generics_typevartuple_variance.py:43:46 - error: Type "CovariantTypeVarTupleOld[object]" is not assignable to declared type "CovariantTypeVarTupleOld[int]"
35+
  "CovariantTypeVarTupleOld[object]" is not assignable to "CovariantTypeVarTupleOld[int]"
36+
    Type parameter "OutTs@CovariantTypeVarTupleOld" is invariant, but "*tuple[object]" is not the same as "*tuple[int]" (reportAssignmentType)
37+
generics_typevartuple_variance.py:44:49 - error: Type "CovariantTypeVarTupleOld[int]" is not assignable to declared type "CovariantTypeVarTupleOld[object]"
38+
  "CovariantTypeVarTupleOld[int]" is not assignable to "CovariantTypeVarTupleOld[object]"
39+
    Type parameter "OutTs@CovariantTypeVarTupleOld" is invariant, but "*tuple[int]" is not the same as "*tuple[object]" (reportAssignmentType)
40+
"""

conformance/results/results.html

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -468,6 +468,13 @@ <h3>Python Type System Conformance Test Results</h3>
468468
<th class="column col2 conformant">Pass</th>
469469
<th class="column col2 not-conformant">Unsupported</th>
470470
</tr>
471+
<tr><th class="column col1">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;generics_typevartuple_variance</th>
472+
<th class="column col2 not-conformant">Unsupported</th>
473+
<th class="column col2 not-conformant">Unsupported</th>
474+
<th class="column col2 not-conformant">Unsupported</th>
475+
<th class="column col2 not-conformant">Unsupported</th>
476+
<th class="column col2 not-conformant">Unsupported</th>
477+
</tr>
471478
<tr><th class="column col1">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;generics_upper_bound</th>
472479
<th class="column col2 partially-conformant"><div class="hover-text">Partial<span class="tooltip-text" id="bottom"><p>Does not reject use of type variable within an upper bound.</p></span></div></th>
473480
<th class="column col2 conformant">Pass</th>
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
conformant = "Unsupported"
2+
conformance_automated = "Fail"
3+
errors_diff = """
4+
Line 32: Expected 1 errors
5+
Line 39: Expected 1 errors
6+
Line 43: Expected 1 errors
7+
Line 14: Unexpected errors ["generics_typevartuple_variance.py:14:9: error[not-subscriptable] Cannot subscript non-generic type `<class 'ContravariantTypeVarTuple'>`", "generics_typevartuple_variance.py:14:42: error[not-subscriptable] Cannot subscript non-generic type `<class 'ContravariantTypeVarTuple'>`"]
8+
Line 18: Unexpected errors ['generics_typevartuple_variance.py:18:20: error[empty-body] Function always implicitly returns `None`, which is not assignable to return type `tuple[@Todo(TypeVarTuple), ...]`']
9+
Line 22: Unexpected errors ["generics_typevartuple_variance.py:22:10: error[not-subscriptable] Cannot subscript non-generic type `<class 'CovariantTypeVarTuple'>`", "generics_typevartuple_variance.py:22:42: error[not-subscriptable] Cannot subscript non-generic type `<class 'CovariantTypeVarTuple'>`"]
10+
Line 25: Unexpected errors ['generics_typevartuple_variance.py:25:29: error[unknown-argument] Argument `contravariant` does not match any known parameter of function `__new__`']
11+
Line 35: Unexpected errors ['generics_typevartuple_variance.py:35:31: error[unknown-argument] Argument `covariant` does not match any known parameter of function `__new__`']
12+
Line 40: Unexpected errors ['generics_typevartuple_variance.py:40:24: error[empty-body] Function always implicitly returns `None`, which is not assignable to return type `tuple[@Todo(TypeVarTuple), ...]`']
13+
"""
14+
output = """
15+
generics_typevartuple_variance.py:13:9: error[not-subscriptable] Cannot subscript non-generic type `<class 'ContravariantTypeVarTuple'>`
16+
generics_typevartuple_variance.py:13:45: error[not-subscriptable] Cannot subscript non-generic type `<class 'ContravariantTypeVarTuple'>`
17+
generics_typevartuple_variance.py:14:9: error[not-subscriptable] Cannot subscript non-generic type `<class 'ContravariantTypeVarTuple'>`
18+
generics_typevartuple_variance.py:14:42: error[not-subscriptable] Cannot subscript non-generic type `<class 'ContravariantTypeVarTuple'>`
19+
generics_typevartuple_variance.py:18:20: error[empty-body] Function always implicitly returns `None`, which is not assignable to return type `tuple[@Todo(TypeVarTuple), ...]`
20+
generics_typevartuple_variance.py:21:10: error[not-subscriptable] Cannot subscript non-generic type `<class 'CovariantTypeVarTuple'>`
21+
generics_typevartuple_variance.py:21:39: error[not-subscriptable] Cannot subscript non-generic type `<class 'CovariantTypeVarTuple'>`
22+
generics_typevartuple_variance.py:22:10: error[not-subscriptable] Cannot subscript non-generic type `<class 'CovariantTypeVarTuple'>`
23+
generics_typevartuple_variance.py:22:42: error[not-subscriptable] Cannot subscript non-generic type `<class 'CovariantTypeVarTuple'>`
24+
generics_typevartuple_variance.py:25:29: error[unknown-argument] Argument `contravariant` does not match any known parameter of function `__new__`
25+
generics_typevartuple_variance.py:30:24: error[empty-body] Function always implicitly returns `None`, which is not assignable to return type `tuple[@Todo(TypeVarTuple), ...]`
26+
generics_typevartuple_variance.py:35:31: error[unknown-argument] Argument `covariant` does not match any known parameter of function `__new__`
27+
generics_typevartuple_variance.py:40:24: error[empty-body] Function always implicitly returns `None`, which is not assignable to return type `tuple[@Todo(TypeVarTuple), ...]`
28+
"""
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
conformant = "Unsupported"
2+
conformance_automated = "Fail"
3+
errors_diff = """
4+
Line 13: Expected 1 errors
5+
Line 32: Expected 1 errors
6+
Line 39: Expected 1 errors
7+
Line 14: Unexpected errors ['generics_typevartuple_variance.py:14: error: Incompatible types in assignment (expression has type "ContravariantTypeVarTuple[object]", variable has type "ContravariantTypeVarTuple[int]") [assignment]']
8+
Line 18: Unexpected errors ['generics_typevartuple_variance.py:18: error: Missing return statement [empty-body]']
9+
Line 25: Unexpected errors ['generics_typevartuple_variance.py:25: error: Unexpected keyword argument "contravariant" for "TypeVarTuple" [call-arg]']
10+
Line 33: Unexpected errors ['generics_typevartuple_variance.py:33: error: Incompatible types in assignment (expression has type "ContravariantTypeVarTupleOld[object]", variable has type "ContravariantTypeVarTupleOld[int]") [assignment]']
11+
Line 35: Unexpected errors ['generics_typevartuple_variance.py:35: error: Unexpected keyword argument "covariant" for "TypeVarTuple" [call-arg]']
12+
Line 40: Unexpected errors ['generics_typevartuple_variance.py:40: error: Missing return statement [empty-body]']
13+
"""
14+
output = """
15+
generics_typevartuple_variance.py:14: error: Incompatible types in assignment (expression has type "ContravariantTypeVarTuple[object]", variable has type "ContravariantTypeVarTuple[int]") [assignment]
16+
generics_typevartuple_variance.py:18: error: Missing return statement [empty-body]
17+
generics_typevartuple_variance.py:21: error: Incompatible types in assignment (expression has type "CovariantTypeVarTuple[object]", variable has type "CovariantTypeVarTuple[int]") [assignment]
18+
generics_typevartuple_variance.py:25: error: Unexpected keyword argument "contravariant" for "TypeVarTuple" [call-arg]
19+
generics_typevartuple_variance.py:30: error: Missing return statement [empty-body]
20+
generics_typevartuple_variance.py:33: error: Incompatible types in assignment (expression has type "ContravariantTypeVarTupleOld[object]", variable has type "ContravariantTypeVarTupleOld[int]") [assignment]
21+
generics_typevartuple_variance.py:35: error: Unexpected keyword argument "covariant" for "TypeVarTuple" [call-arg]
22+
generics_typevartuple_variance.py:40: error: Missing return statement [empty-body]
23+
generics_typevartuple_variance.py:43: error: Incompatible types in assignment (expression has type "CovariantTypeVarTupleOld[object]", variable has type "CovariantTypeVarTupleOld[int]") [assignment]
24+
"""
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
"""
2+
Tests variance of TypeVarTuple.
3+
"""
4+
5+
# Specification: https://typing.readthedocs.io/en/latest/spec/generics.html#semantics
6+
7+
8+
from typing import Generic, TypeVarTuple
9+
10+
class ContravariantTypeVarTuple[*InTs]:
11+
def f(self, t: tuple[*InTs]): ...
12+
13+
in_obj: ContravariantTypeVarTuple[object] = ContravariantTypeVarTuple[int]() # E
14+
in_int: ContravariantTypeVarTuple[int] = ContravariantTypeVarTuple[object]() # OK
15+
16+
17+
class CovariantTypeVarTuple[*OutTs]:
18+
def f(self) -> tuple[*OutTs]: ...
19+
20+
21+
out_int: CovariantTypeVarTuple[int] = CovariantTypeVarTuple[object]() # E
22+
out_obj: CovariantTypeVarTuple[object] = CovariantTypeVarTuple[int]() # OK
23+
24+
25+
InTs = TypeVarTuple("InTs", contravariant=True)
26+
27+
28+
class ContravariantTypeVarTupleOld(Generic[*InTs]):
29+
def in_f(self, *args: *InTs) -> None: ... # OK
30+
def out_f(self) -> tuple[*InTs]: ... # E
31+
32+
in_obj_old: ContravariantTypeVarTupleOld[object] = ContravariantTypeVarTupleOld[int]() # E
33+
in_int_old: ContravariantTypeVarTupleOld[int] = ContravariantTypeVarTupleOld[object]() # OK
34+
35+
OutTs = TypeVarTuple("OutTs", covariant=True)
36+
37+
38+
class CovariantTypeVarTupleOld(Generic[*OutTs]):
39+
def in_f(self, *args: *OutTs) -> None: ... # E
40+
def out_f(self) -> tuple[*OutTs]: ... # OK
41+
42+
43+
out_int_old: CovariantTypeVarTupleOld[int] = CovariantTypeVarTupleOld[object]() # E
44+
out_obj_old: CovariantTypeVarTupleOld[object] = CovariantTypeVarTupleOld[int]() # OK

docs/spec/generics.rst

Lines changed: 7 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1189,12 +1189,11 @@ for two reasons:
11891189
* To improve readability: the star also functions as an explicit visual
11901190
indicator that the type variable tuple is not a normal type variable.
11911191

1192-
Variance, Type Constraints and Type Bounds: Not Supported
1192+
Type Constraints and Type Bounds: Not Supported
11931193
"""""""""""""""""""""""""""""""""""""""""""""""""""""""""
11941194

11951195
``TypeVarTuple`` does not currently support specification of:
11961196

1197-
* Variance (e.g. ``TypeVar('T', covariant=True)``)
11981197
* Type constraints (``TypeVar('T', int, float)``)
11991198
* Type bounds (``TypeVar('T', bound=ParentClass)``)
12001199

@@ -2712,14 +2711,12 @@ The algorithm for computing the variance of a type parameter is as follows.
27122711

27132712
For each type parameter in a generic class:
27142713

2715-
1. If the type parameter is variadic (``TypeVarTuple``) it is always
2716-
considered invariant. No further inference is needed.
2714+
1. If the type parameter comes from a traditional
2715+
``TypeVar``/``TypeVarTuple``/``ParamSpec`` declaration and is not specified
2716+
as ``infer_variance`` (see below), its variance is specified by the
2717+
constructor call. No further inference is needed.
27172718

2718-
2. If the type parameter comes from a traditional ``TypeVar``/``ParamSpec``
2719-
declaration and is not specified as ``infer_variance`` (see below), its
2720-
variance is specified by the constructor call. No further inference is needed.
2721-
2722-
3. Create two specialized versions of the class. We'll refer to these as
2719+
2. Create two specialized versions of the class. We'll refer to these as
27232720
``upper`` and ``lower`` specializations. In both of these specializations,
27242721
replace all type parameters other than the one being inferred by a dummy type
27252722
instance (a concrete anonymous class that is assumed to meet the bounds or
@@ -2729,7 +2726,7 @@ specialization ignores the type parameter's upper bound or constraints. In the
27292726
``lower`` specialized class, specialize the target type parameter with itself
27302727
(i.e. the corresponding type argument is the type parameter itself).
27312728

2732-
4. Determine whether ``lower`` can be assigned to ``upper`` using normal
2729+
3. Determine whether ``lower`` can be assigned to ``upper`` using normal
27332730
assignability rules. If so, the target type parameter is covariant. If not,
27342731
determine whether ``upper`` can be assigned to ``lower``. If so, the target
27352732
type parameter is contravariant. If neither of these combinations are

0 commit comments

Comments
 (0)