Skip to content

Commit 7a21592

Browse files
committed
specify that type variable tuple should have variance
1 parent 117964e commit 7a21592

File tree

8 files changed

+187
-10
lines changed

8 files changed

+187
-10
lines changed
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
conformant = "Unsupported"
2+
conformance_automated = "Fail"
3+
errors_diff = """
4+
Line 24: Expected 1 errors
5+
Line 35: Expected 1 errors
6+
Line 41: Expected 1 errors
7+
Line 23: Unexpected errors ['generics_typevartuple_variance.py:23: error: Incompatible types in assignment (expression has type "CovariantTypeVarTuple[[int]]", variable has type "CovariantTypeVarTuple[[object]]") [assignment]']
8+
Line 26: Unexpected errors ['generics_typevartuple_variance.py:26: error: Unexpected keyword argument "contravariant" for "TypeVarTuple" [misc]']
9+
Line 34: Unexpected errors ['generics_typevartuple_variance.py:34: error: Incompatible types in assignment (expression has type "ContravariantTypeVarTupleOld[object]", variable has type "ContravariantTypeVarTupleOld[int]") [assignment]']
10+
Line 37: Unexpected errors ['generics_typevartuple_variance.py:37: error: Unexpected keyword argument "covariant" for "TypeVarTuple" [misc]']
11+
Line 42: Unexpected errors ['generics_typevartuple_variance.py:42: error: Missing return statement [empty-body]']
12+
"""
13+
output = """
14+
generics_typevartuple_variance.py:15: error: Incompatible types in assignment (expression has type "ContravariantTypeVarTuple[[int]]", variable has type "ContravariantTypeVarTuple[[object]]") [assignment]
15+
generics_typevartuple_variance.py:23: error: Incompatible types in assignment (expression has type "CovariantTypeVarTuple[[int]]", variable has type "CovariantTypeVarTuple[[object]]") [assignment]
16+
generics_typevartuple_variance.py:26: error: Unexpected keyword argument "contravariant" for "TypeVarTuple" [misc]
17+
generics_typevartuple_variance.py:31: error: Missing return statement [empty-body]
18+
generics_typevartuple_variance.py:34: error: Incompatible types in assignment (expression has type "ContravariantTypeVarTupleOld[object]", variable has type "ContravariantTypeVarTupleOld[int]") [assignment]
19+
generics_typevartuple_variance.py:37: error: Unexpected keyword argument "covariant" for "TypeVarTuple" [misc]
20+
generics_typevartuple_variance.py:42: error: Missing return statement [empty-body]
21+
generics_typevartuple_variance.py:47: error: Incompatible types in assignment (expression has type "CovariantTypeVarTupleOld[object]", variable has type "CovariantTypeVarTupleOld[int]") [assignment]
22+
"""
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 15: Expected 1 errors
5+
Line 24: Expected 1 errors
6+
Line 31: Expected 1 errors
7+
Line 41: Expected 1 errors
8+
Line 14: Unexpected errors ['`ContravariantTypeVarTuple[[object]]` is not assignable to `ContravariantTypeVarTuple[[int]]` [bad-assignment]']
9+
Line 23: Unexpected errors ['`CovariantTypeVarTuple[[int]]` is not assignable to `CovariantTypeVarTuple[[object]]` [bad-assignment]']
10+
Line 26: Unexpected errors ['Unexpected keyword argument `contravariant` to TypeVarTuple [invalid-type-var-tuple]']
11+
Line 34: Unexpected errors ['`ContravariantTypeVarTupleOld[object]` is not assignable to `ContravariantTypeVarTupleOld[int]` [bad-assignment]']
12+
Line 37: Unexpected errors ['Unexpected keyword argument `covariant` to TypeVarTuple [invalid-type-var-tuple]']
13+
Line 46: Unexpected errors ['`CovariantTypeVarTupleOld[int]` is not assignable to `CovariantTypeVarTupleOld[object]` [bad-assignment]']
14+
"""
15+
output = """
16+
ERROR generics_typevartuple_variance.py:14:42-48: `ContravariantTypeVarTuple[[object]]` is not assignable to `ContravariantTypeVarTuple[[int]]` [bad-assignment]
17+
ERROR generics_typevartuple_variance.py:23:42-49: `CovariantTypeVarTuple[[int]]` is not assignable to `CovariantTypeVarTuple[[object]]` [bad-assignment]
18+
ERROR generics_typevartuple_variance.py:26:29-47: Unexpected keyword argument `contravariant` to TypeVarTuple [invalid-type-var-tuple]
19+
ERROR generics_typevartuple_variance.py:34:49-59: `ContravariantTypeVarTupleOld[object]` is not assignable to `ContravariantTypeVarTupleOld[int]` [bad-assignment]
20+
ERROR generics_typevartuple_variance.py:35:14-24: `ContravariantTypeVarTupleOld[int]` is not assignable to variable `in_obj_old` with type `ContravariantTypeVarTupleOld[object]` [bad-assignment]
21+
ERROR generics_typevartuple_variance.py:37:31-45: Unexpected keyword argument `covariant` to TypeVarTuple [invalid-type-var-tuple]
22+
ERROR generics_typevartuple_variance.py:46:49-60: `CovariantTypeVarTupleOld[int]` is not assignable to `CovariantTypeVarTupleOld[object]` [bad-assignment]
23+
ERROR generics_typevartuple_variance.py:47:15-26: `CovariantTypeVarTupleOld[object]` is not assignable to variable `out_int_old` with type `CovariantTypeVarTupleOld[int]` [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 31: Expected 1 errors
5+
Line 41: 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 23: Unexpected errors ['generics_typevartuple_variance.py:23:42 - error: Type "CovariantTypeVarTuple[(int)]" is not assignable to declared type "CovariantTypeVarTuple[(object)]"']
8+
Line 26: Unexpected errors ['generics_typevartuple_variance.py:26:29 - error: "contravariant" is unknown parameter to TypeVarTuple (reportGeneralTypeIssues)']
9+
Line 34: Unexpected errors ['generics_typevartuple_variance.py:34:49 - error: Type "ContravariantTypeVarTupleOld[object]" is not assignable to declared type "ContravariantTypeVarTupleOld[int]"']
10+
Line 37: Unexpected errors ['generics_typevartuple_variance.py:37:31 - error: "covariant" is unknown parameter to TypeVarTuple (reportGeneralTypeIssues)']
11+
Line 46: Unexpected errors ['generics_typevartuple_variance.py:46:49 - error: Type "CovariantTypeVarTupleOld[int]" is not assignable to declared type "CovariantTypeVarTupleOld[object]"']
12+
"""
13+
output = """
14+
generics_typevartuple_variance.py:14:42 - error: Type "ContravariantTypeVarTuple[(object)]" is not assignable to declared type "ContravariantTypeVarTuple[(int)]"
15+
  "ContravariantTypeVarTuple[(object)]" is not assignable to "ContravariantTypeVarTuple[(int)]"
16+
    Type parameter "InTs@ContravariantTypeVarTuple" is invariant, but "(object)" is not the same as "(int)" (reportAssignmentType)
17+
generics_typevartuple_variance.py:15:10 - error: Type "ContravariantTypeVarTuple[(int)]" is not assignable to declared type "ContravariantTypeVarTuple[(object)]"
18+
  "ContravariantTypeVarTuple[(int)]" is not assignable to "ContravariantTypeVarTuple[(object)]"
19+
    Type parameter "InTs@ContravariantTypeVarTuple" is invariant, but "(int)" is not the same as "(object)" (reportAssignmentType)
20+
generics_typevartuple_variance.py:23:42 - error: Type "CovariantTypeVarTuple[(int)]" is not assignable to declared type "CovariantTypeVarTuple[(object)]"
21+
  "CovariantTypeVarTuple[(int)]" is not assignable to "CovariantTypeVarTuple[(object)]"
22+
    Type parameter "OutTs@CovariantTypeVarTuple" is invariant, but "(int)" is not the same as "(object)" (reportAssignmentType)
23+
generics_typevartuple_variance.py:24:11 - error: Type "CovariantTypeVarTuple[(object)]" is not assignable to declared type "CovariantTypeVarTuple[(int)]"
24+
  "CovariantTypeVarTuple[(object)]" is not assignable to "CovariantTypeVarTuple[(int)]"
25+
    Type parameter "OutTs@CovariantTypeVarTuple" is invariant, but "(object)" is not the same as "(int)" (reportAssignmentType)
26+
generics_typevartuple_variance.py:26:29 - error: "contravariant" is unknown parameter to TypeVarTuple (reportGeneralTypeIssues)
27+
generics_typevartuple_variance.py:34:49 - error: Type "ContravariantTypeVarTupleOld[object]" is not assignable to declared type "ContravariantTypeVarTupleOld[int]"
28+
  "ContravariantTypeVarTupleOld[object]" is not assignable to "ContravariantTypeVarTupleOld[int]"
29+
    Type parameter "InTs@ContravariantTypeVarTupleOld" is invariant, but "*tuple[object]" is not the same as "*tuple[int]" (reportAssignmentType)
30+
generics_typevartuple_variance.py:35:14 - error: Type "ContravariantTypeVarTupleOld[int]" is not assignable to declared type "ContravariantTypeVarTupleOld[object]"
31+
  "ContravariantTypeVarTupleOld[int]" is not assignable to "ContravariantTypeVarTupleOld[object]"
32+
    Type parameter "InTs@ContravariantTypeVarTupleOld" is invariant, but "*tuple[int]" is not the same as "*tuple[object]" (reportAssignmentType)
33+
generics_typevartuple_variance.py:37:31 - error: "covariant" is unknown parameter to TypeVarTuple (reportGeneralTypeIssues)
34+
generics_typevartuple_variance.py:46:49 - error: Type "CovariantTypeVarTupleOld[int]" is not assignable to declared type "CovariantTypeVarTupleOld[object]"
35+
  "CovariantTypeVarTupleOld[int]" is not assignable to "CovariantTypeVarTupleOld[object]"
36+
    Type parameter "OutTs@CovariantTypeVarTupleOld" is invariant, but "*tuple[int]" is not the same as "*tuple[object]" (reportAssignmentType)
37+
generics_typevartuple_variance.py:47:15 - error: Type "CovariantTypeVarTupleOld[object]" is not assignable to declared type "CovariantTypeVarTupleOld[int]"
38+
  "CovariantTypeVarTupleOld[object]" is not assignable to "CovariantTypeVarTupleOld[int]"
39+
    Type parameter "OutTs@CovariantTypeVarTupleOld" is invariant, but "*tuple[object]" is not the same as "*tuple[int]" (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: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
conformant = "Unsupported"
2+
conformance_automated = "Fail"
3+
errors_diff = """
4+
Line 15: Expected 1 errors
5+
Line 24: Expected 1 errors
6+
Line 35: Expected 1 errors
7+
Line 41: Expected 1 errors
8+
Line 47: Expected 1 errors
9+
Line 26: Unexpected errors ['generics_typevartuple_variance.py:26:29: error[unknown-argument] Argument `contravariant` does not match any known parameter of function `__new__`']
10+
Line 37: Unexpected errors ['generics_typevartuple_variance.py:37:31: error[unknown-argument] Argument `covariant` does not match any known parameter of function `__new__`']
11+
Line 42: Unexpected errors ['generics_typevartuple_variance.py:42:24: error[empty-body] Function always implicitly returns `None`, which is not assignable to return type `tuple[@Todo(TypeVarTuple), ...]`']
12+
"""
13+
output = """
14+
generics_typevartuple_variance.py:26:29: error[unknown-argument] Argument `contravariant` does not match any known parameter of function `__new__`
15+
generics_typevartuple_variance.py:31:24: error[empty-body] Function always implicitly returns `None`, which is not assignable to return type `tuple[@Todo(TypeVarTuple), ...]`
16+
generics_typevartuple_variance.py:37:31: error[unknown-argument] Argument `covariant` does not match any known parameter of function `__new__`
17+
generics_typevartuple_variance.py:42:24: error[empty-body] Function always implicitly returns `None`, which is not assignable to return type `tuple[@Todo(TypeVarTuple), ...]`
18+
"""
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
conformant = "Unsupported"
2+
conformance_automated = "Fail"
3+
errors_diff = """
4+
Line 24: Expected 1 errors
5+
Line 35: Expected 1 errors
6+
Line 41: Expected 1 errors
7+
Line 23: Unexpected errors ['generics_typevartuple_variance.py:23: error: Incompatible types in assignment (expression has type "CovariantTypeVarTuple[[int]]", variable has type "CovariantTypeVarTuple[[object]]") [assignment]']
8+
Line 26: Unexpected errors ['generics_typevartuple_variance.py:26: error: Unexpected keyword argument "contravariant" for "TypeVarTuple" [call-arg]']
9+
Line 34: Unexpected errors ['generics_typevartuple_variance.py:34: error: Incompatible types in assignment (expression has type "ContravariantTypeVarTupleOld[object]", variable has type "ContravariantTypeVarTupleOld[int]") [assignment]']
10+
Line 37: Unexpected errors ['generics_typevartuple_variance.py:37: error: Unexpected keyword argument "covariant" for "TypeVarTuple" [call-arg]']
11+
Line 42: Unexpected errors ['generics_typevartuple_variance.py:42: error: Missing return statement [empty-body]']
12+
"""
13+
output = """
14+
generics_typevartuple_variance.py:15: error: Incompatible types in assignment (expression has type "ContravariantTypeVarTuple[[int]]", variable has type "ContravariantTypeVarTuple[[object]]") [assignment]
15+
generics_typevartuple_variance.py:23: error: Incompatible types in assignment (expression has type "CovariantTypeVarTuple[[int]]", variable has type "CovariantTypeVarTuple[[object]]") [assignment]
16+
generics_typevartuple_variance.py:26: error: Unexpected keyword argument "contravariant" for "TypeVarTuple" [call-arg]
17+
generics_typevartuple_variance.py:31: error: Missing return statement [empty-body]
18+
generics_typevartuple_variance.py:34: error: Incompatible types in assignment (expression has type "ContravariantTypeVarTupleOld[object]", variable has type "ContravariantTypeVarTupleOld[int]") [assignment]
19+
generics_typevartuple_variance.py:37: error: Unexpected keyword argument "covariant" for "TypeVarTuple" [call-arg]
20+
generics_typevartuple_variance.py:42: error: Missing return statement [empty-body]
21+
generics_typevartuple_variance.py:47: error: Incompatible types in assignment (expression has type "CovariantTypeVarTupleOld[object]", variable has type "CovariantTypeVarTupleOld[int]") [assignment]
22+
"""
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
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 Callable, Generic, TypeVarTuple
9+
10+
class ContravariantTypeVarTuple[**InTs]:
11+
def f(self, *args: InTs.args, **kwargs: InTs.kwargs): ...
12+
13+
in_obj: ContravariantTypeVarTuple[object] = ContravariantTypeVarTuple()
14+
in_int: ContravariantTypeVarTuple[int] = in_obj # OK
15+
in_obj = in_int # E
16+
17+
18+
class CovariantTypeVarTuple[**OutTs]:
19+
def f(self, fn: Callable[OutTs, None]) -> None: ...
20+
21+
22+
out_int: CovariantTypeVarTuple[int] = CovariantTypeVarTuple()
23+
out_obj: CovariantTypeVarTuple[object] = out_int # OK
24+
out_int = out_obj # E
25+
26+
InTs = TypeVarTuple("InTs", contravariant=True)
27+
28+
29+
class ContravariantTypeVarTupleOld(Generic[*InTs]):
30+
def in_f(self, *args: *InTs) -> None: ... # OK
31+
def out_f(self) -> tuple[*InTs]: ... # E
32+
33+
in_obj_old: ContravariantTypeVarTupleOld[object] = ContravariantTypeVarTupleOld()
34+
in_int_old: ContravariantTypeVarTupleOld[int] = in_obj_old # OK
35+
in_obj_old = in_int_old # E
36+
37+
OutTs = TypeVarTuple("OutTs", covariant=True)
38+
39+
40+
class CovariantTypeVarTupleOld(Generic[*OutTs]):
41+
def in_f(self, *args: *OutTs) -> None: ... # E
42+
def out_f(self) -> tuple[*OutTs]: ... # OK
43+
44+
45+
out_int_old: CovariantTypeVarTupleOld[int] = CovariantTypeVarTupleOld()
46+
out_obj_old: CovariantTypeVarTupleOld[object] = out_int_old # OK
47+
out_int_old = out_obj_old # E

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)