Skip to content

Commit acbf480

Browse files
authored
Clarify that a TypeVarTuple default always has to be unpacked (#1971)
* Clarify that a TypeVarTuple default always has to be unpacked. The spec says that: 1. The default of a TypeVarTuple can be another TypeVarTuple 2. TypeVarTuples are always unpacked. Together, these suggest that the default of a TypeVarTuple has to be an *unpacked* TypeVarTuple, and indeed [pyright](https://pyright-play.net/?pyrightVersion=1.1.386&code=GYJw9gtgBALgngBwJYDsDmUkQWEMoAqiApgGoCGIBArggDbEA0UAqiguQMYDWAUAQGcAjFAC8hEhSq0GACgDkgofICU-AQCYxEhGUo16xBYI3zmAE2LBy1OjFFK1ggMzaiuqQbmKBzs1EtrW3s2Dh4AbSUAXRUgA) and [mypy](https://mypy-play.net/?mypy=latest&python=3.12&gist=b6b01c533c7930e1e520765b773d1fe1) both agree. This PR makes that clear and adds a corresponding conformance test. I don't think this needs a discussion + Typing Council approval, since it's just a clarification of an existing rule, but happy to go through the full process if anyone disagrees.
1 parent 3149e8c commit acbf480

File tree

7 files changed

+90
-80
lines changed

7 files changed

+90
-80
lines changed

conformance/results/mypy/generics_defaults.toml

Lines changed: 14 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -12,19 +12,19 @@ generics_defaults.py:55: error: Expression is of type "type[AllTheDefaults[int,
1212
generics_defaults.py:59: error: Expression is of type "type[AllTheDefaults[int, complex, str, int, DefaultBoolT]]", not "type[AllTheDefaults[int, complex, str, int, bool]]" [assert-type]
1313
generics_defaults.py:79: error: Expression is of type "type[Class_ParamSpec[DefaultP]]", not "type[Class_ParamSpec[[str, int]]]" [assert-type]
1414
generics_defaults.py:94: error: Expression is of type "type[Class_TypeVarTuple[*DefaultTs]]", not "type[Class_TypeVarTuple[str, int]]" [assert-type]
15-
generics_defaults.py:104: error: TypeVar default must be a subtype of the bound type [misc]
16-
generics_defaults.py:111: error: TypeVar default must be one of the constraint types [misc]
17-
generics_defaults.py:151: error: Expression is of type "type[Foo6[*tuple[Any, ...], Any]]", not "type[Foo6[int, str, [float, bool]]]" [assert-type]
18-
generics_defaults.py:151: error: Can only replace ParamSpec with a parameter types list or another ParamSpec, got "str" [misc]
19-
generics_defaults.py:152: error: Expression is of type "type[Foo6[*tuple[Any, ...], Any]]", not "type[Foo6[int, str, [bytes]]]" [assert-type]
20-
generics_defaults.py:152: error: Can only replace ParamSpec with a parameter types list or another ParamSpec, got "str" [misc]
21-
generics_defaults.py:166: error: Expression is of type "Callable[[Self], Self]", not "Callable[[Foo7[int]], Foo7[int]]" [assert-type]
22-
generics_defaults.py:167: error: Expression is of type "Any", not "int" [assert-type]
23-
generics_defaults.py:167: error: Access to generic instance variables via class is ambiguous [misc]
15+
generics_defaults.py:107: error: TypeVar default must be a subtype of the bound type [misc]
16+
generics_defaults.py:114: error: TypeVar default must be one of the constraint types [misc]
17+
generics_defaults.py:154: error: Expression is of type "type[Foo6[*tuple[Any, ...], Any]]", not "type[Foo6[int, str, [float, bool]]]" [assert-type]
18+
generics_defaults.py:154: error: Can only replace ParamSpec with a parameter types list or another ParamSpec, got "str" [misc]
19+
generics_defaults.py:155: error: Expression is of type "type[Foo6[*tuple[Any, ...], Any]]", not "type[Foo6[int, str, [bytes]]]" [assert-type]
20+
generics_defaults.py:155: error: Can only replace ParamSpec with a parameter types list or another ParamSpec, got "str" [misc]
21+
generics_defaults.py:169: error: Expression is of type "Callable[[Self], Self]", not "Callable[[Foo7[int]], Foo7[int]]" [assert-type]
22+
generics_defaults.py:170: error: Expression is of type "Any", not "int" [assert-type]
23+
generics_defaults.py:170: error: Access to generic instance variables via class is ambiguous [misc]
2424
"""
2525
conformance_automated = "Fail"
2626
errors_diff = """
27-
Line 138: Expected 1 errors
27+
Line 141: Expected 1 errors
2828
Line 30: Unexpected errors ['generics_defaults.py:30: error: Expression is of type "type[NoNonDefaults[DefaultStrT, DefaultIntT]]", not "type[NoNonDefaults[str, int]]" [assert-type]']
2929
Line 31: Unexpected errors ['generics_defaults.py:31: error: Expression is of type "type[NoNonDefaults[str, DefaultIntT]]", not "type[NoNonDefaults[str, int]]" [assert-type]']
3030
Line 38: Unexpected errors ['generics_defaults.py:38: error: Expression is of type "type[OneDefault[float, DefaultBoolT]]", not "type[OneDefault[float, bool]]" [assert-type]']
@@ -35,8 +35,8 @@ Line 55: Unexpected errors ['generics_defaults.py:55: error: Expression is of ty
3535
Line 59: Unexpected errors ['generics_defaults.py:59: error: Expression is of type "type[AllTheDefaults[int, complex, str, int, DefaultBoolT]]", not "type[AllTheDefaults[int, complex, str, int, bool]]" [assert-type]']
3636
Line 79: Unexpected errors ['generics_defaults.py:79: error: Expression is of type "type[Class_ParamSpec[DefaultP]]", not "type[Class_ParamSpec[[str, int]]]" [assert-type]']
3737
Line 94: Unexpected errors ['generics_defaults.py:94: error: Expression is of type "type[Class_TypeVarTuple[*DefaultTs]]", not "type[Class_TypeVarTuple[str, int]]" [assert-type]']
38-
Line 151: Unexpected errors ['generics_defaults.py:151: error: Expression is of type "type[Foo6[*tuple[Any, ...], Any]]", not "type[Foo6[int, str, [float, bool]]]" [assert-type]', 'generics_defaults.py:151: error: Can only replace ParamSpec with a parameter types list or another ParamSpec, got "str" [misc]']
39-
Line 152: Unexpected errors ['generics_defaults.py:152: error: Expression is of type "type[Foo6[*tuple[Any, ...], Any]]", not "type[Foo6[int, str, [bytes]]]" [assert-type]', 'generics_defaults.py:152: error: Can only replace ParamSpec with a parameter types list or another ParamSpec, got "str" [misc]']
40-
Line 166: Unexpected errors ['generics_defaults.py:166: error: Expression is of type "Callable[[Self], Self]", not "Callable[[Foo7[int]], Foo7[int]]" [assert-type]']
41-
Line 167: Unexpected errors ['generics_defaults.py:167: error: Expression is of type "Any", not "int" [assert-type]', 'generics_defaults.py:167: error: Access to generic instance variables via class is ambiguous [misc]']
38+
Line 154: Unexpected errors ['generics_defaults.py:154: error: Expression is of type "type[Foo6[*tuple[Any, ...], Any]]", not "type[Foo6[int, str, [float, bool]]]" [assert-type]', 'generics_defaults.py:154: error: Can only replace ParamSpec with a parameter types list or another ParamSpec, got "str" [misc]']
39+
Line 155: Unexpected errors ['generics_defaults.py:155: error: Expression is of type "type[Foo6[*tuple[Any, ...], Any]]", not "type[Foo6[int, str, [bytes]]]" [assert-type]', 'generics_defaults.py:155: error: Can only replace ParamSpec with a parameter types list or another ParamSpec, got "str" [misc]']
40+
Line 169: Unexpected errors ['generics_defaults.py:169: error: Expression is of type "Callable[[Self], Self]", not "Callable[[Foo7[int]], Foo7[int]]" [assert-type]']
41+
Line 170: Unexpected errors ['generics_defaults.py:170: error: Expression is of type "Any", not "int" [assert-type]', 'generics_defaults.py:170: error: Access to generic instance variables via class is ambiguous [misc]']
4242
"""

conformance/results/pyre/generics_defaults.toml

Lines changed: 25 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -50,26 +50,27 @@ generics_defaults.py:95:34 Invalid type parameters [24]: Non-generic type `Class
5050
generics_defaults.py:96:0 Assert type [70]: Expected `Class_TypeVarTuple[]` but got `typing.Any`.
5151
generics_defaults.py:96:12 Undefined attribute [16]: `Class_TypeVarTuple` has no attribute `__getitem__`.
5252
generics_defaults.py:96:45 Invalid type parameters [24]: Non-generic type `Class_TypeVarTuple` cannot take parameters.
53-
generics_defaults.py:124:13 Undefined or invalid type [11]: Annotation `T4` is not defined as a type.
54-
generics_defaults.py:127:0 Assert type [70]: Expected `int` but got `unknown`.
55-
generics_defaults.py:138:11 Invalid type variable [34]: The current class isn't generic with respect to the type variable `Ts`.
56-
generics_defaults.py:138:11 Undefined or invalid type [11]: Annotation `T5` is not defined as a type.
57-
generics_defaults.py:148:11 Invalid type variable [34]: The current class isn't generic with respect to the type variable `Ts`.
58-
generics_defaults.py:148:11 Undefined or invalid type [11]: Annotation `P` is not defined as a type.
59-
generics_defaults.py:151:0 Assert type [70]: Expected `Type[Foo6[]]` but got `typing.Any`.
60-
generics_defaults.py:151:12 Undefined attribute [16]: `Foo6` has no attribute `__getitem__`.
61-
generics_defaults.py:151:28 Invalid type parameters [24]: Non-generic type `Foo6` cannot take parameters.
62-
generics_defaults.py:152:0 Assert type [70]: Expected `Type[Foo6[]]` but got `typing.Any`.
63-
generics_defaults.py:152:37 Invalid type parameters [24]: Non-generic type `Foo6` cannot take parameters.
64-
generics_defaults.py:166:0 Assert type [70]: Expected `typing.Callable[[Foo7[]], Foo7[]]` but got `typing.Callable(Foo7.meth)[[Variable[_Self_generics_defaults_Foo7__ (bound to Foo7)]], Variable[_Self_generics_defaults_Foo7__ (bound to Foo7)]]`.
65-
generics_defaults.py:166:23 Invalid type parameters [24]: Non-generic type `Foo7` cannot take parameters.
66-
generics_defaults.py:167:0 Assert type [70]: Expected `int` but got `unknown`.
53+
generics_defaults.py:99:67 Incompatible parameter type [6]: In call `typing.GenericMeta.__getitem__`, for 1st positional argument, expected `Type[Variable[_T]]` but got `TypeVarTuple`.
54+
generics_defaults.py:127:13 Undefined or invalid type [11]: Annotation `T4` is not defined as a type.
55+
generics_defaults.py:130:0 Assert type [70]: Expected `int` but got `unknown`.
56+
generics_defaults.py:141:11 Invalid type variable [34]: The current class isn't generic with respect to the type variable `Ts`.
57+
generics_defaults.py:141:11 Undefined or invalid type [11]: Annotation `T5` is not defined as a type.
58+
generics_defaults.py:151:11 Invalid type variable [34]: The current class isn't generic with respect to the type variable `Ts`.
59+
generics_defaults.py:151:11 Undefined or invalid type [11]: Annotation `P` is not defined as a type.
60+
generics_defaults.py:154:0 Assert type [70]: Expected `Type[Foo6[]]` but got `typing.Any`.
61+
generics_defaults.py:154:12 Undefined attribute [16]: `Foo6` has no attribute `__getitem__`.
62+
generics_defaults.py:154:28 Invalid type parameters [24]: Non-generic type `Foo6` cannot take parameters.
63+
generics_defaults.py:155:0 Assert type [70]: Expected `Type[Foo6[]]` but got `typing.Any`.
64+
generics_defaults.py:155:37 Invalid type parameters [24]: Non-generic type `Foo6` cannot take parameters.
65+
generics_defaults.py:169:0 Assert type [70]: Expected `typing.Callable[[Foo7[]], Foo7[]]` but got `typing.Callable(Foo7.meth)[[Variable[_Self_generics_defaults_Foo7__ (bound to Foo7)]], Variable[_Self_generics_defaults_Foo7__ (bound to Foo7)]]`.
66+
generics_defaults.py:169:23 Invalid type parameters [24]: Non-generic type `Foo7` cannot take parameters.
67+
generics_defaults.py:170:0 Assert type [70]: Expected `int` but got `unknown`.
6768
"""
6869
conformance_automated = "Fail"
6970
errors_diff = """
7071
Line 50: Expected 1 errors
71-
Line 104: Expected 1 errors
72-
Line 111: Expected 1 errors
72+
Line 107: Expected 1 errors
73+
Line 114: Expected 1 errors
7374
Line 27: Unexpected errors ['generics_defaults.py:27:20 Undefined or invalid type [11]: Annotation `DefaultIntT` is not defined as a type.']
7475
Line 30: Unexpected errors ['generics_defaults.py:30:0 Assert type [70]: Expected `Type[NoNonDefaults[]]` but got `Type[NoNonDefaults]`.', 'generics_defaults.py:30:27 Invalid type parameters [24]: Non-generic type `NoNonDefaults` cannot take parameters.']
7576
Line 31: Unexpected errors ['generics_defaults.py:31:0 Assert type [70]: Expected `Type[NoNonDefaults[]]` but got `typing.Any`.', 'generics_defaults.py:31:12 Undefined attribute [16]: `NoNonDefaults` has no attribute `__getitem__`.', 'generics_defaults.py:31:32 Invalid type parameters [24]: Non-generic type `NoNonDefaults` cannot take parameters.']
@@ -97,11 +98,12 @@ Line 91: Unexpected errors ['generics_defaults.py:91:25 Undefined or invalid typ
9798
Line 94: Unexpected errors ['generics_defaults.py:94:0 Assert type [70]: Expected `Type[Class_TypeVarTuple[]]` but got `Type[Class_TypeVarTuple]`.', 'generics_defaults.py:94:32 Invalid type parameters [24]: Non-generic type `Class_TypeVarTuple` cannot take parameters.']
9899
Line 95: Unexpected errors ['generics_defaults.py:95:0 Assert type [70]: Expected `Class_TypeVarTuple[]` but got `Class_TypeVarTuple`.', 'generics_defaults.py:95:34 Invalid type parameters [24]: Non-generic type `Class_TypeVarTuple` cannot take parameters.']
99100
Line 96: Unexpected errors ['generics_defaults.py:96:0 Assert type [70]: Expected `Class_TypeVarTuple[]` but got `typing.Any`.', 'generics_defaults.py:96:12 Undefined attribute [16]: `Class_TypeVarTuple` has no attribute `__getitem__`.', 'generics_defaults.py:96:45 Invalid type parameters [24]: Non-generic type `Class_TypeVarTuple` cannot take parameters.']
100-
Line 124: Unexpected errors ['generics_defaults.py:124:13 Undefined or invalid type [11]: Annotation `T4` is not defined as a type.']
101-
Line 127: Unexpected errors ['generics_defaults.py:127:0 Assert type [70]: Expected `int` but got `unknown`.']
102-
Line 148: Unexpected errors ["generics_defaults.py:148:11 Invalid type variable [34]: The current class isn't generic with respect to the type variable `Ts`.", 'generics_defaults.py:148:11 Undefined or invalid type [11]: Annotation `P` is not defined as a type.']
103-
Line 151: Unexpected errors ['generics_defaults.py:151:0 Assert type [70]: Expected `Type[Foo6[]]` but got `typing.Any`.', 'generics_defaults.py:151:12 Undefined attribute [16]: `Foo6` has no attribute `__getitem__`.', 'generics_defaults.py:151:28 Invalid type parameters [24]: Non-generic type `Foo6` cannot take parameters.']
104-
Line 152: Unexpected errors ['generics_defaults.py:152:0 Assert type [70]: Expected `Type[Foo6[]]` but got `typing.Any`.', 'generics_defaults.py:152:37 Invalid type parameters [24]: Non-generic type `Foo6` cannot take parameters.']
105-
Line 166: Unexpected errors ['generics_defaults.py:166:0 Assert type [70]: Expected `typing.Callable[[Foo7[]], Foo7[]]` but got `typing.Callable(Foo7.meth)[[Variable[_Self_generics_defaults_Foo7__ (bound to Foo7)]], Variable[_Self_generics_defaults_Foo7__ (bound to Foo7)]]`.', 'generics_defaults.py:166:23 Invalid type parameters [24]: Non-generic type `Foo7` cannot take parameters.']
106-
Line 167: Unexpected errors ['generics_defaults.py:167:0 Assert type [70]: Expected `int` but got `unknown`.']
101+
Line 99: Unexpected errors ['generics_defaults.py:99:67 Incompatible parameter type [6]: In call `typing.GenericMeta.__getitem__`, for 1st positional argument, expected `Type[Variable[_T]]` but got `TypeVarTuple`.']
102+
Line 127: Unexpected errors ['generics_defaults.py:127:13 Undefined or invalid type [11]: Annotation `T4` is not defined as a type.']
103+
Line 130: Unexpected errors ['generics_defaults.py:130:0 Assert type [70]: Expected `int` but got `unknown`.']
104+
Line 151: Unexpected errors ["generics_defaults.py:151:11 Invalid type variable [34]: The current class isn't generic with respect to the type variable `Ts`.", 'generics_defaults.py:151:11 Undefined or invalid type [11]: Annotation `P` is not defined as a type.']
105+
Line 154: Unexpected errors ['generics_defaults.py:154:0 Assert type [70]: Expected `Type[Foo6[]]` but got `typing.Any`.', 'generics_defaults.py:154:12 Undefined attribute [16]: `Foo6` has no attribute `__getitem__`.', 'generics_defaults.py:154:28 Invalid type parameters [24]: Non-generic type `Foo6` cannot take parameters.']
106+
Line 155: Unexpected errors ['generics_defaults.py:155:0 Assert type [70]: Expected `Type[Foo6[]]` but got `typing.Any`.', 'generics_defaults.py:155:37 Invalid type parameters [24]: Non-generic type `Foo6` cannot take parameters.']
107+
Line 169: Unexpected errors ['generics_defaults.py:169:0 Assert type [70]: Expected `typing.Callable[[Foo7[]], Foo7[]]` but got `typing.Callable(Foo7.meth)[[Variable[_Self_generics_defaults_Foo7__ (bound to Foo7)]], Variable[_Self_generics_defaults_Foo7__ (bound to Foo7)]]`.', 'generics_defaults.py:169:23 Invalid type parameters [24]: Non-generic type `Foo7` cannot take parameters.']
108+
Line 170: Unexpected errors ['generics_defaults.py:170:0 Assert type [70]: Expected `int` but got `unknown`.']
107109
"""

conformance/results/pyright/generics_defaults.toml

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,10 @@ conformant = "Pass"
22
output = """
33
generics_defaults.py:24:7 - error: "T" cannot appear after "DefaultStrT" in type parameter list because it has no default type (reportGeneralTypeIssues)
44
generics_defaults.py:50:16 - error: Too few type arguments provided for "AllTheDefaults"; expected 2 but received 1 (reportInvalidTypeArguments)
5-
generics_defaults.py:104:51 - error: TypeVar default type must be a subtype of the bound type (reportGeneralTypeIssues)
6-
generics_defaults.py:111:52 - error: TypeVar default type must be one of the constrained types (reportGeneralTypeIssues)
7-
generics_defaults.py:138:7 - error: TypeVar "T5" has a default value and cannot follow TypeVarTuple "Ts" (reportGeneralTypeIssues)
8-
generics_defaults.py:167:18 - error: Access to generic instance variable through class is ambiguous (reportGeneralTypeIssues)
5+
generics_defaults.py:107:51 - error: TypeVar default type must be a subtype of the bound type (reportGeneralTypeIssues)
6+
generics_defaults.py:114:52 - error: TypeVar default type must be one of the constrained types (reportGeneralTypeIssues)
7+
generics_defaults.py:141:7 - error: TypeVar "T5" has a default value and cannot follow TypeVarTuple "Ts" (reportGeneralTypeIssues)
8+
generics_defaults.py:170:18 - error: Access to generic instance variable through class is ambiguous (reportGeneralTypeIssues)
99
"""
1010
conformance_automated = "Pass"
1111
errors_diff = """

0 commit comments

Comments
 (0)