diff --git a/conformance/results/mypy/generics_defaults.toml b/conformance/results/mypy/generics_defaults.toml index 5b18af90b..3c24ab357 100644 --- a/conformance/results/mypy/generics_defaults.toml +++ b/conformance/results/mypy/generics_defaults.toml @@ -10,15 +10,16 @@ generics_defaults.py:139: error: Expression is of type "tuple[*tuple[str, int], generics_defaults.py:152: error: TypeVar default must be a subtype of the bound type [misc] generics_defaults.py:159: error: TypeVar default must be one of the constraint types [misc] generics_defaults.py:177: error: Expression is of type "int", not "Any" [assert-type] -generics_defaults.py:203: error: Can only replace ParamSpec with a parameter types list or another ParamSpec, got "str" [valid-type] -generics_defaults.py:204: error: Expression is of type "tuple[Any, ...]", not "tuple[int, str]" [assert-type] -generics_defaults.py:205: error: Expression is of type "def (*Any, **Any) -> None", not "Callable[[float, bool], None]" [assert-type] +generics_defaults.py:211: error: Can only replace ParamSpec with a parameter types list or another ParamSpec, got "str" [valid-type] +generics_defaults.py:212: error: Expression is of type "tuple[Any, ...]", not "tuple[int, str]" [assert-type] +generics_defaults.py:213: error: Expression is of type "def (*Any, **Any) -> None", not "Callable[[float, bool], None]" [assert-type] """ conformance_automated = "Fail" errors_diff = """ -Line 188: Expected 1 errors +Line 189: Expected 1 errors +Line 201: Expected 1 errors Line 139: Unexpected errors ['generics_defaults.py:139: error: Expression is of type "tuple[*tuple[str, int], ...]", not "tuple[str, int]" [assert-type]'] -Line 203: Unexpected errors ['generics_defaults.py:203: error: Can only replace ParamSpec with a parameter types list or another ParamSpec, got "str" [valid-type]'] -Line 204: Unexpected errors ['generics_defaults.py:204: error: Expression is of type "tuple[Any, ...]", not "tuple[int, str]" [assert-type]'] -Line 205: Unexpected errors ['generics_defaults.py:205: error: Expression is of type "def (*Any, **Any) -> None", not "Callable[[float, bool], None]" [assert-type]'] +Line 211: Unexpected errors ['generics_defaults.py:211: error: Can only replace ParamSpec with a parameter types list or another ParamSpec, got "str" [valid-type]'] +Line 212: Unexpected errors ['generics_defaults.py:212: error: Expression is of type "tuple[Any, ...]", not "tuple[int, str]" [assert-type]'] +Line 213: Unexpected errors ['generics_defaults.py:213: error: Expression is of type "def (*Any, **Any) -> None", not "Callable[[float, bool], None]" [assert-type]'] """ diff --git a/conformance/results/pycroscope/generics_defaults.toml b/conformance/results/pycroscope/generics_defaults.toml index 93d9e5fb4..582ac9932 100644 --- a/conformance/results/pycroscope/generics_defaults.toml +++ b/conformance/results/pycroscope/generics_defaults.toml @@ -4,6 +4,7 @@ Numerous issues; does not support TypeVarTuple and ParamSpec defaults. """ conformance_automated = "Fail" errors_diff = """ +Line 201: Expected 1 errors Line 33: Unexpected errors ['./generics_defaults.py:33:16: ~DefaultStrT@./generics_defaults.py.NoNonDefaults is not equivalent to str'] Line 34: Unexpected errors ['./generics_defaults.py:34:16: ~DefaultIntT@./generics_defaults.py.NoNonDefaults is not equivalent to int'] Line 73: Unexpected errors ['./generics_defaults.py:73:16: ~T1@./generics_defaults.py.AllTheDefaults is not equivalent to Any[explicit]'] @@ -14,10 +15,10 @@ Line 77: Unexpected errors ['./generics_defaults.py:77:16: ~DefaultBoolT@./gen Line 122: Unexpected errors ['./generics_defaults.py:122:16: (**__P: **DefaultP@./generics_defaults.py.Class_ParamSpec) -> None is not equivalent to (str, int, /) -> None'] Line 124: Unexpected errors ['./generics_defaults.py:124:16: ./generics_defaults.py.Class_ParamSpec[AnySig()] is not equivalent to ./generics_defaults.py.Class_ParamSpec[tuple[bool, bool]]'] Line 144: Unexpected errors ['./generics_defaults.py:144:60: Incompatible argument type for default: expected TypeForm[object] but got Literal[typing.Unpack[DefaultTs]] [incompatible_argument]'] -Line 203: Unexpected errors ["./generics_defaults.py:203:36: Invalid type annotation [] [invalid_annotation]", './generics_defaults.py:203:17: ParamSpec specialization must use list form, Concatenate[..., P], P, or ... [invalid_annotation]'] -Line 204: Unexpected errors ['./generics_defaults.py:204:16: tuple[int] is not equivalent to tuple[int, str]'] -Line 205: Unexpected errors ['./generics_defaults.py:205:16: (...) -> None is not equivalent to (float | int, bool, /) -> None'] -Line 208: Unexpected errors ['./generics_defaults.py:208:16: (...) -> None is not equivalent to (bytes, /) -> None'] +Line 211: Unexpected errors ["./generics_defaults.py:211:38: Invalid type annotation [] [invalid_annotation]", './generics_defaults.py:211:18: ParamSpec specialization must use list form, Concatenate[..., P], P, or ... [invalid_annotation]'] +Line 212: Unexpected errors ['./generics_defaults.py:212:16: tuple[int] is not equivalent to tuple[int, str]'] +Line 213: Unexpected errors ['./generics_defaults.py:213:16: (...) -> None is not equivalent to (float | int, bool, /) -> None'] +Line 216: Unexpected errors ['./generics_defaults.py:216:16: (...) -> None is not equivalent to (bytes, /) -> None'] """ output = """ ./generics_defaults.py:24:0: non-default TypeVars cannot follow ones with defaults [invalid_type_parameter] @@ -35,10 +36,10 @@ output = """ ./generics_defaults.py:152:50: TypeVar default must be assignable to its bound [incompatible_call] ./generics_defaults.py:159:51: TypeVar default must be one of its constraints [incompatible_call] ./generics_defaults.py:176:12: Any[generic_argument] is not equivalent to int -./generics_defaults.py:188:0: TypeVars with defaults cannot follow TypeVarTuples [invalid_type_parameter] -./generics_defaults.py:203:36: Invalid type annotation [] [invalid_annotation] -./generics_defaults.py:203:17: ParamSpec specialization must use list form, Concatenate[..., P], P, or ... [invalid_annotation] -./generics_defaults.py:204:16: tuple[int] is not equivalent to tuple[int, str] -./generics_defaults.py:205:16: (...) -> None is not equivalent to (float | int, bool, /) -> None -./generics_defaults.py:208:16: (...) -> None is not equivalent to (bytes, /) -> None +./generics_defaults.py:189:0: TypeVars with defaults cannot follow TypeVarTuples [invalid_type_parameter] +./generics_defaults.py:211:38: Invalid type annotation [] [invalid_annotation] +./generics_defaults.py:211:18: ParamSpec specialization must use list form, Concatenate[..., P], P, or ... [invalid_annotation] +./generics_defaults.py:212:16: tuple[int] is not equivalent to tuple[int, str] +./generics_defaults.py:213:16: (...) -> None is not equivalent to (float | int, bool, /) -> None +./generics_defaults.py:216:16: (...) -> None is not equivalent to (bytes, /) -> None """ diff --git a/conformance/results/pyrefly/generics_defaults.toml b/conformance/results/pyrefly/generics_defaults.toml index 5570f83ca..27dc5515b 100644 --- a/conformance/results/pyrefly/generics_defaults.toml +++ b/conformance/results/pyrefly/generics_defaults.toml @@ -1,6 +1,10 @@ -conformant = "Pass" -conformance_automated = "Pass" +conformant = "Partial" +notes = """ +Does not flag a ``ParamSpec`` with a default following a ``TypeVarTuple`` without a default. +""" +conformance_automated = "Fail" errors_diff = """ +Line 201: Expected 1 errors """ output = """ ERROR generics_defaults.py:24:7-31: Type parameter `T` without a default cannot follow type parameter `DefaultStrT` with a default [invalid-type-var] @@ -8,5 +12,5 @@ ERROR generics_defaults.py:66:8-27: Expected 5 type arguments for `AllTheDefault ERROR generics_defaults.py:152:51-54: Expected default `int` of `Invalid1` to be assignable to the upper bound of `str` [invalid-type-var] ERROR generics_defaults.py:159:52-55: Expected default `int` of `Invalid2` to be one of the following constraints: `float`, `str` [invalid-type-var] ERROR generics_defaults.py:177:12-27: assert_type(int, Any) failed [assert-type] -ERROR generics_defaults.py:188:7-11: TypeVar `T5` with a default cannot follow TypeVarTuple `Ts` [invalid-type-var] +ERROR generics_defaults.py:189:7-11: TypeVar `T5` with a default cannot follow TypeVarTuple `Ts` [invalid-type-var] """ diff --git a/conformance/results/pyright/generics_defaults.toml b/conformance/results/pyright/generics_defaults.toml index d306076f2..27d620d0b 100644 --- a/conformance/results/pyright/generics_defaults.toml +++ b/conformance/results/pyright/generics_defaults.toml @@ -1,13 +1,17 @@ -conformant = "Pass" +conformant = "Partial" +notes = """ +Does not flag a ``ParamSpec`` with a default following a ``TypeVarTuple`` without a default. +""" output = """ generics_defaults.py:24:7 - error: "T" cannot appear after "DefaultStrT" in type parameter list because it has no default type (reportGeneralTypeIssues) generics_defaults.py:66:23 - error: Too few type arguments provided for "AllTheDefaults"; expected 2 but received 1 (reportInvalidTypeArguments) generics_defaults.py:152:51 - error: TypeVar default type must be a subtype of the bound type (reportGeneralTypeIssues) generics_defaults.py:159:52 - error: TypeVar default type must be one of the constrained types (reportGeneralTypeIssues) generics_defaults.py:177:13 - error: "assert_type" mismatch: expected "Any" but received "int" (reportAssertTypeFailure) -generics_defaults.py:188:7 - error: TypeVar "T5" has a default value and cannot follow TypeVarTuple "Ts" (reportGeneralTypeIssues) +generics_defaults.py:189:7 - error: TypeVar "T5" has a default value and cannot follow TypeVarTuple "Ts" (reportGeneralTypeIssues) """ -conformance_automated = "Pass" +conformance_automated = "Fail" errors_diff = """ +Line 201: Expected 1 errors """ ignore_errors = ["Access to generic instance variable through class is ambiguous"] diff --git a/conformance/results/results.html b/conformance/results/results.html index 733c4d22f..cba480c21 100644 --- a/conformance/results/results.html +++ b/conformance/results/results.html @@ -304,7 +304,7 @@

Python Type System Conformance Test Results

     generics_defaults
Partial

Does not detect a TypeVar with a default used after a TypeVarTuple.

Does not fully support defaults on TypeVarTuple and ParamSpec.

Pass -Pass +Unknown Pass
Partial

Numerous issues; does not support TypeVarTuple and ParamSpec defaults.

Partial

Does not forbid a `TypeVar` immediately following a `TypeVarTuple` in a parameter list from having a default.

Does not support `TypeVarTuple`.

diff --git a/conformance/results/ty/generics_defaults.toml b/conformance/results/ty/generics_defaults.toml index d8887a2e3..164d1ce57 100644 --- a/conformance/results/ty/generics_defaults.toml +++ b/conformance/results/ty/generics_defaults.toml @@ -5,14 +5,16 @@ Does not forbid a `TypeVar` immediately following a `TypeVarTuple` in a paramete Does not support `TypeVarTuple`. """ errors_diff = """ -Line 188: Expected 1 errors +Line 189: Expected 1 errors +Line 201: Expected 1 errors Line 139: Unexpected errors ['generics_defaults.py:139:5: error[type-assertion-failure] Type `tuple[@Todo(TypeVarTuple), ...]` does not match asserted type `tuple[str, int]`'] Line 140: Unexpected errors ['generics_defaults.py:140:5: error[type-assertion-failure] Type `Class_TypeVarTuple` does not match asserted type `@Todo`'] -Line 200: Unexpected errors ['generics_defaults.py:200:17: error[invalid-type-form] The first argument to `Callable` must be either a list of types, ParamSpec, Concatenate, or `...`'] -Line 204: Unexpected errors ['generics_defaults.py:204:5: error[type-assertion-failure] Type `@Todo` does not match asserted type `tuple[int, str]`'] -Line 205: Unexpected errors ['generics_defaults.py:205:5: error[type-assertion-failure] Type `@Todo` does not match asserted type `(int | float, bool, /) -> None`'] -Line 207: Unexpected errors ['generics_defaults.py:207:5: error[type-assertion-failure] Type `@Todo` does not match asserted type `tuple[int, str]`'] -Line 208: Unexpected errors ['generics_defaults.py:208:5: error[type-assertion-failure] Type `@Todo` does not match asserted type `(bytes, /) -> None`'] +Line 203: Unexpected errors ['generics_defaults.py:203:17: error[invalid-type-form] The first argument to `Callable` must be either a list of types, ParamSpec, Concatenate, or `...`'] +Line 208: Unexpected errors ['generics_defaults.py:208:17: error[invalid-type-form] The first argument to `Callable` must be either a list of types, ParamSpec, Concatenate, or `...`'] +Line 212: Unexpected errors ['generics_defaults.py:212:5: error[type-assertion-failure] Type `@Todo` does not match asserted type `tuple[int, str]`'] +Line 213: Unexpected errors ['generics_defaults.py:213:5: error[type-assertion-failure] Type `@Todo` does not match asserted type `(int | float, bool, /) -> None`'] +Line 215: Unexpected errors ['generics_defaults.py:215:5: error[type-assertion-failure] Type `@Todo` does not match asserted type `tuple[int, str]`'] +Line 216: Unexpected errors ['generics_defaults.py:216:5: error[type-assertion-failure] Type `@Todo` does not match asserted type `(bytes, /) -> None`'] """ output = """ generics_defaults.py:24:40: error[invalid-generic-class] Type parameter `T` without a default cannot follow earlier parameter `DefaultStrT` with a default @@ -22,9 +24,10 @@ generics_defaults.py:140:5: error[type-assertion-failure] Type `Class_TypeVarTup generics_defaults.py:152:51: error[invalid-type-variable-default] TypeVar default is not assignable to the TypeVar's upper bound generics_defaults.py:159:52: error[invalid-type-variable-default] TypeVar default is inconsistent with the TypeVar's constraints: `int` is not one of the constraints of `Invalid2` generics_defaults.py:177:1: error[type-assertion-failure] Type `int` does not match asserted type `Any` -generics_defaults.py:200:17: error[invalid-type-form] The first argument to `Callable` must be either a list of types, ParamSpec, Concatenate, or `...` -generics_defaults.py:204:5: error[type-assertion-failure] Type `@Todo` does not match asserted type `tuple[int, str]` -generics_defaults.py:205:5: error[type-assertion-failure] Type `@Todo` does not match asserted type `(int | float, bool, /) -> None` -generics_defaults.py:207:5: error[type-assertion-failure] Type `@Todo` does not match asserted type `tuple[int, str]` -generics_defaults.py:208:5: error[type-assertion-failure] Type `@Todo` does not match asserted type `(bytes, /) -> None` +generics_defaults.py:203:17: error[invalid-type-form] The first argument to `Callable` must be either a list of types, ParamSpec, Concatenate, or `...` +generics_defaults.py:208:17: error[invalid-type-form] The first argument to `Callable` must be either a list of types, ParamSpec, Concatenate, or `...` +generics_defaults.py:212:5: error[type-assertion-failure] Type `@Todo` does not match asserted type `tuple[int, str]` +generics_defaults.py:213:5: error[type-assertion-failure] Type `@Todo` does not match asserted type `(int | float, bool, /) -> None` +generics_defaults.py:215:5: error[type-assertion-failure] Type `@Todo` does not match asserted type `tuple[int, str]` +generics_defaults.py:216:5: error[type-assertion-failure] Type `@Todo` does not match asserted type `(bytes, /) -> None` """ diff --git a/conformance/results/zuban/generics_defaults.toml b/conformance/results/zuban/generics_defaults.toml index fd34b3631..5e5d39c16 100644 --- a/conformance/results/zuban/generics_defaults.toml +++ b/conformance/results/zuban/generics_defaults.toml @@ -1,5 +1,10 @@ -conformance_automated = "Pass" +conformant = "Partial" +notes = """ +Does not flag a ``ParamSpec`` with a default following a ``TypeVarTuple`` without a default. +""" +conformance_automated = "Fail" errors_diff = """ +Line 201: Expected 1 errors """ output = """ generics_defaults.py:24: error: "T" cannot appear after "DefaultStrT" in type parameter list because it has no default type [misc] @@ -7,5 +12,5 @@ generics_defaults.py:66: error: "AllTheDefaults" expects between 2 and 5 type ar generics_defaults.py:152: error: TypeVar default must be a subtype of the bound type [misc] generics_defaults.py:159: error: TypeVar default must be one of the constraint types [misc] generics_defaults.py:177: error: Expression is of type "int", not "Any" [misc] -generics_defaults.py:188: error: TypeVar defaults are ambiguous after a TypeVarTuple [misc] +generics_defaults.py:189: error: TypeVar defaults are ambiguous after a TypeVarTuple [misc] """ diff --git a/conformance/tests/generics_defaults.py b/conformance/tests/generics_defaults.py index 14eafa2bf..af40be7c5 100644 --- a/conformance/tests/generics_defaults.py +++ b/conformance/tests/generics_defaults.py @@ -183,24 +183,32 @@ def func1(x: int | set[T4]) -> T4: Ts = TypeVarTuple("Ts") T5 = TypeVar("T5", default=bool) +TsD = TypeVarTuple("TsD", default=Unpack[tuple[int, str]]) class Foo5(Generic[*Ts, T5]): ... # E # > It is allowed to have a ``ParamSpec`` with a default following a -# > ``TypeVarTuple`` with a default, as there can be no ambiguity between a +# > ``TypeVarTuple`` **with a default**, as there can be no ambiguity between a # > type argument for the ``ParamSpec`` and one for the ``TypeVarTuple``. +# > When the ``TypeVarTuple`` has no default, a ``ParamSpec`` with a default +# > following it is not allowed (same rule as for ``TypeVar``). P = ParamSpec("P", default=[float, bool]) -class Foo6(Generic[*Ts, P]): +class Foo6(Generic[*Ts, P]): # E: Ts has no default x: tuple[*Ts] y: Callable[P, None] -def test_foo6(a: Foo6[int, str], b: Foo6[int, str, [bytes]]): +class Foo6b(Generic[*TsD, P]): # OK: TsD has a default + x: tuple[*TsD] + y: Callable[P, None] + + +def test_foo6b(a: Foo6b[int, str], b: Foo6b[int, str, [bytes]]): assert_type(a.x, tuple[int, str]) assert_type(a.y, Callable[[float, bool], None]) diff --git a/docs/spec/generics.rst b/docs/spec/generics.rst index c1fa05325..f4e73b20b 100644 --- a/docs/spec/generics.rst +++ b/docs/spec/generics.rst @@ -2098,8 +2098,10 @@ should be bound to the ``TypeVarTuple`` or the defaulted ``TypeVar``. Foo[int, str, float] It is allowed to have a ``ParamSpec`` with a default following a -``TypeVarTuple`` with a default, as there can be no ambiguity between a type argument -for the ``ParamSpec`` and one for the ``TypeVarTuple``. +``TypeVarTuple`` **with a default**, as there can be no ambiguity between a +type argument for the ``ParamSpec`` and one for the ``TypeVarTuple``. +When the ``TypeVarTuple`` has no default, a ``ParamSpec`` with a default +following it is not allowed (same rule as for ``TypeVar``). :: @@ -2108,6 +2110,8 @@ for the ``ParamSpec`` and one for the ``TypeVarTuple``. Foo[int, str] # Ts = (int, str), P = [float, bool] Foo[int, str, [bytes]] # Ts = (int, str), P = [bytes] + class Bar[*Ts, **P = [float, bool]]: ... # Type checker error: Ts has no default + Binding rules """""""""""""