From b855865850db3d77b26de9cf3ca24e7ad6fd1b87 Mon Sep 17 00:00:00 2001 From: Douglas Creager Date: Thu, 4 Jun 2026 15:01:46 -0400 Subject: [PATCH 1/2] [conformance] Add examples that require bidi inference of list literals after specialization inference --- .../results/mypy/constructors_callable.toml | 22 +++++++++-- .../pycroscope/constructors_callable.toml | 23 +++++++++-- .../pyrefly/constructors_callable.toml | 23 +++++++++-- .../pyright/constructors_callable.toml | 30 ++++++++++++--- conformance/results/results.html | 8 ++-- .../results/ty/constructors_callable.toml | 27 ++++++++++--- .../results/zuban/constructors_callable.toml | 23 +++++++++-- conformance/tests/constructors_callable.py | 38 +++++++++++++++++-- 8 files changed, 162 insertions(+), 32 deletions(-) diff --git a/conformance/results/mypy/constructors_callable.toml b/conformance/results/mypy/constructors_callable.toml index 2d788f335..e5918845b 100644 --- a/conformance/results/mypy/constructors_callable.toml +++ b/conformance/results/mypy/constructors_callable.toml @@ -15,6 +15,10 @@ Line 107: Unexpected errors ['constructors_callable.py:107: error: Expression is Line 118: Unexpected errors ['constructors_callable.py:118: error: Incompatible return type for "__new__" (returns "Class6Proxy", but must return a subtype of "Class6") [misc]'] Line 128: Unexpected errors ['constructors_callable.py:128: error: Expression is of type "Class6", not "Class6Proxy" [assert-type]', 'constructors_callable.py:128: error: Too few arguments [call-arg]'] Line 145: Unexpected errors ['constructors_callable.py:145: error: Expression is of type "Class6Any", not "Any" [assert-type]', 'constructors_callable.py:145: error: Too few arguments [call-arg]'] +Line 187: Unexpected errors ['constructors_callable.py:187: error: Expression is of type "Class8[Any]", not "Class8[int | str]" [assert-type]', 'constructors_callable.py:187: error: Cannot infer function type argument [misc]'] +Line 199: Unexpected errors ['constructors_callable.py:199: error: Cannot infer function type argument [misc]'] +Line 215: Unexpected errors ['constructors_callable.py:215: error: Expression is of type "Class10[Any]", not "Class10[int]" [assert-type]', 'constructors_callable.py:215: error: Cannot infer function type argument [misc]'] +Line 229: Unexpected errors ['constructors_callable.py:229: error: Cannot infer function type argument [misc]'] """ output = """ constructors_callable.py:36: note: Revealed type is "def (x: int) -> constructors_callable.Class1" @@ -43,7 +47,19 @@ constructors_callable.py:145: error: Expression is of type "Class6Any", not "Any constructors_callable.py:145: error: Too few arguments [call-arg] constructors_callable.py:164: note: Revealed type is "Overload(def (x: int) -> constructors_callable.Class7[int], def (x: str) -> constructors_callable.Class7[str])" constructors_callable.py:184: note: Revealed type is "def [T] (x: list[T], y: list[T]) -> constructors_callable.Class8[T]" -constructors_callable.py:186: error: Cannot infer function type argument [misc] -constructors_callable.py:195: note: Revealed type is "def [T] (x: list[T], y: list[T]) -> constructors_callable.Class9" -constructors_callable.py:197: error: Cannot infer function type argument [misc] +constructors_callable.py:185: error: Argument 2 has incompatible type "str"; expected "list[str]" [arg-type] +constructors_callable.py:187: error: Expression is of type "Class8[Any]", not "Class8[int | str]" [assert-type] +constructors_callable.py:187: error: Cannot infer function type argument [misc] +constructors_callable.py:196: note: Revealed type is "def [T] (x: list[T], y: list[T]) -> constructors_callable.Class9" +constructors_callable.py:197: error: Argument 2 has incompatible type "str"; expected "list[str]" [arg-type] +constructors_callable.py:199: error: Cannot infer function type argument [misc] +constructors_callable.py:210: note: Revealed type is "def [T_int <: int] (x: list[T_int], y: list[T_int]) -> constructors_callable.Class10[T_int]" +constructors_callable.py:211: error: Argument 2 has incompatible type "str"; expected "list[int]" [arg-type] +constructors_callable.py:212: error: Cannot infer function type argument [misc] +constructors_callable.py:215: error: Expression is of type "Class10[Any]", not "Class10[int]" [assert-type] +constructors_callable.py:215: error: Cannot infer function type argument [misc] +constructors_callable.py:224: note: Revealed type is "def [T_int <: int] (x: list[T_int], y: list[T_int]) -> constructors_callable.Class11" +constructors_callable.py:225: error: Argument 2 has incompatible type "str"; expected "list[int]" [arg-type] +constructors_callable.py:226: error: Cannot infer function type argument [misc] +constructors_callable.py:229: error: Cannot infer function type argument [misc] """ diff --git a/conformance/results/pycroscope/constructors_callable.toml b/conformance/results/pycroscope/constructors_callable.toml index 3c01c1f16..878586744 100644 --- a/conformance/results/pycroscope/constructors_callable.toml +++ b/conformance/results/pycroscope/constructors_callable.toml @@ -1,5 +1,11 @@ -conformance_automated = "Pass" +conformant = "Partial" +notes = """ +List literal arguments are inferred in isolation before specialization inference +""" +conformance_automated = "Fail" errors_diff = """ +Line 187: Unexpected errors ['./constructors_callable.py:187:12: ./constructors_callable.py.Class8[Any[error]] is not equivalent to ./constructors_callable.py.Class8[int | str]', './constructors_callable.py:187:12: Cannot resolve type variables [incompatible_call]'] +Line 199: Unexpected errors ['./constructors_callable.py:199:12: Cannot resolve type variables [incompatible_call]'] """ output = """ ./constructors_callable.py:36:12: Revealed type is '(x: int) -> ./constructors_callable.py.Class1' [reveal_type] @@ -21,7 +27,16 @@ output = """ ./constructors_callable.py:146:0: Takes 0 positional arguments but 1 were given [incompatible_call] ./constructors_callable.py:164:4: Revealed type is '(x: ~_Ctor_Class7_T) -> ./constructors_callable.py.Class7[~_Ctor_Class7_T]' [reveal_type] ./constructors_callable.py:184:12: Revealed type is '(x: list[~T@./constructors_callable.py.Class8], y: list[~T@./constructors_callable.py.Class8]) -> ./constructors_callable.py.Class8[~T@./constructors_callable.py.Class8]' [reveal_type] -./constructors_callable.py:186:0: Cannot resolve type variables [incompatible_call] -./constructors_callable.py:195:12: Revealed type is '(x: list[~T@./constructors_callable.py.Class9.__init__..__init__], y: list[~T@./constructors_callable.py.Class9.__init__..__init__]) -> ./constructors_callable.py.Class9' [reveal_type] -./constructors_callable.py:197:0: Cannot resolve type variables [incompatible_call] +./constructors_callable.py:185:9: Incompatible argument type for y: expected list[~T@./constructors_callable.py.Class8] but got Literal['not a list'] [incompatible_argument] +./constructors_callable.py:187:12: ./constructors_callable.py.Class8[Any[error]] is not equivalent to ./constructors_callable.py.Class8[int | str] +./constructors_callable.py:187:12: Cannot resolve type variables [incompatible_call] +./constructors_callable.py:196:12: Revealed type is '(x: list[~T@./constructors_callable.py.Class9.__init__..__init__], y: list[~T@./constructors_callable.py.Class9.__init__..__init__]) -> ./constructors_callable.py.Class9' [reveal_type] +./constructors_callable.py:197:9: Incompatible argument type for y: expected list[~T@./constructors_callable.py.Class9.__init__..__init__] but got Literal['not a list'] [incompatible_argument] +./constructors_callable.py:199:12: Cannot resolve type variables [incompatible_call] +./constructors_callable.py:210:12: Revealed type is '(x: list[~T_int@./constructors_callable.py.Class10], y: list[~T_int@./constructors_callable.py.Class10]) -> ./constructors_callable.py.Class10[~T_int@./constructors_callable.py.Class10]' [reveal_type] +./constructors_callable.py:211:9: Incompatible argument type for y: expected list[~T_int@./constructors_callable.py.Class10] but got Literal['not a list'] [incompatible_argument] +./constructors_callable.py:212:9: Incompatible argument type for y: expected list[~T_int@./constructors_callable.py.Class10] but got Literal[['']] [incompatible_argument] +./constructors_callable.py:224:12: Revealed type is '(x: list[~T_int@./constructors_callable.py.Class11.__init__..__init__], y: list[~T_int@./constructors_callable.py.Class11.__init__..__init__]) -> ./constructors_callable.py.Class11' [reveal_type] +./constructors_callable.py:225:9: Incompatible argument type for y: expected list[~T_int@./constructors_callable.py.Class11.__init__..__init__] but got Literal['not a list'] [incompatible_argument] +./constructors_callable.py:226:9: Incompatible argument type for y: expected list[~T_int@./constructors_callable.py.Class11.__init__..__init__] but got Literal[['']] [incompatible_argument] """ diff --git a/conformance/results/pyrefly/constructors_callable.toml b/conformance/results/pyrefly/constructors_callable.toml index 33d7b6000..8c3793108 100644 --- a/conformance/results/pyrefly/constructors_callable.toml +++ b/conformance/results/pyrefly/constructors_callable.toml @@ -4,8 +4,13 @@ Converting constructor to callable does not preserve class-scoped type params. """ conformance_automated = "Fail" errors_diff = """ -Line 186: Expected 1 errors -Line 185: Unexpected errors ['assert_type(Class8[Unknown], Class8[str]) failed [assert-type]'] +Line 212: Expected 1 errors +Line 186: Unexpected errors ['assert_type(Class8[Unknown], Class8[str]) failed [assert-type]'] +Line 187: Unexpected errors ['assert_type(Class8[Unknown], Class8[int | str]) failed [assert-type]'] +Line 199: Unexpected errors ['Argument `list[str]` is not assignable to parameter `y` with type `list[int]` [bad-argument-type]'] +Line 213: Unexpected errors ['assert_type(Class10[Unknown], Class10[int]) failed [assert-type]'] +Line 214: Unexpected errors ['assert_type(Class10[Unknown], Class10[bool]) failed [assert-type]'] +Line 215: Unexpected errors ['assert_type(Class10[Unknown], Class10[int]) failed [assert-type]'] """ output = """ ERROR constructors_callable.py:38:3-5: Missing argument `x` [missing-argument] @@ -21,6 +26,16 @@ ERROR constructors_callable.py:82:3-8: Missing argument `x` [missing-argument] ERROR constructors_callable.py:82:4-5: Unexpected keyword argument `y` [unexpected-keyword] ERROR constructors_callable.py:129:4-5: Expected 0 positional arguments, got 1 [bad-argument-count] ERROR constructors_callable.py:146:8-9: Expected 0 positional arguments, got 1 [bad-argument-count] -ERROR constructors_callable.py:185:12-41: assert_type(Class8[Unknown], Class8[str]) failed [assert-type] -ERROR constructors_callable.py:197:9-13: Argument `list[str]` is not assignable to parameter `y` with type `list[int]` [bad-argument-type] +ERROR constructors_callable.py:185:10-22: Argument `Literal['not a list']` is not assignable to parameter `y` with type `list[Unknown]` [bad-argument-type] +ERROR constructors_callable.py:186:12-41: assert_type(Class8[Unknown], Class8[str]) failed [assert-type] +ERROR constructors_callable.py:187:12-46: assert_type(Class8[Unknown], Class8[int | str]) failed [assert-type] +ERROR constructors_callable.py:197:10-22: Argument `Literal['not a list']` is not assignable to parameter `y` with type `list[str]` [bad-argument-type] +ERROR constructors_callable.py:199:21-25: Argument `list[str]` is not assignable to parameter `y` with type `list[int]` [bad-argument-type] +ERROR constructors_callable.py:211:10-22: Argument `Literal['not a list']` is not assignable to parameter `y` with type `list[Unknown]` [bad-argument-type] +ERROR constructors_callable.py:213:12-41: assert_type(Class10[Unknown], Class10[int]) failed [assert-type] +ERROR constructors_callable.py:214:12-48: assert_type(Class10[Unknown], Class10[bool]) failed [assert-type] +ERROR constructors_callable.py:215:12-44: assert_type(Class10[Unknown], Class10[int]) failed [assert-type] +ERROR constructors_callable.py:225:10-22: Argument `Literal['not a list']` is not assignable to parameter `y` with type `list[int]` [bad-argument-type] +ERROR constructors_callable.py:226:4-15: `str` is not assignable to upper bound `int` of type variable `T_int` [bad-specialization] +ERROR constructors_callable.py:226:10-14: Argument `list[str]` is not assignable to parameter `y` with type `list[int]` [bad-argument-type] """ diff --git a/conformance/results/pyright/constructors_callable.toml b/conformance/results/pyright/constructors_callable.toml index 4a9c41d59..02716dc29 100644 --- a/conformance/results/pyright/constructors_callable.toml +++ b/conformance/results/pyright/constructors_callable.toml @@ -1,6 +1,11 @@ -conformant = "Pass" -conformance_automated = "Pass" +conformant = "Partial" +notes = """ +List literal arguments are inferred in isolation before specialization inference +""" +conformance_automated = "Fail" errors_diff = """ +Line 187: Unexpected errors ['constructors_callable.py:187:13 - error: "assert_type" mismatch: expected "Class8[int | str]" but received "Class8[int]" (reportAssertTypeFailure)', 'constructors_callable.py:187:22 - error: Argument of type "list[str]" cannot be assigned to parameter "y" of type "list[T@Class8]"'] +Line 199: Unexpected errors ['constructors_callable.py:199:22 - error: Argument of type "list[str]" cannot be assigned to parameter "y" of type "list[T@__init__]"'] """ output = """ constructors_callable.py:36:13 - information: Type of "r1" is "(x: int) -> Class1" @@ -25,9 +30,24 @@ constructors_callable.py:144:13 - information: Type of "r6_any" is "() -> Any" constructors_callable.py:146:8 - error: Expected 0 positional arguments (reportCallIssue) constructors_callable.py:164:5 - information: Type of "r7" is "Overload[(x: int) -> Class7[int], (x: str) -> Class7[str]]" constructors_callable.py:184:13 - information: Type of "r8" is "(x: list[T@Class8], y: list[T@Class8]) -> Class8[T@Class8]" -constructors_callable.py:186:10 - error: Argument of type "list[str]" cannot be assigned to parameter "y" of type "list[T@Class8]" +constructors_callable.py:185:10 - error: Argument of type "Literal['not a list']" cannot be assigned to parameter "y" of type "list[T@Class8]" +  "Literal['not a list']" is not assignable to "list[str]" (reportArgumentType) +constructors_callable.py:187:13 - error: "assert_type" mismatch: expected "Class8[int | str]" but received "Class8[int]" (reportAssertTypeFailure) +constructors_callable.py:187:22 - error: Argument of type "list[str]" cannot be assigned to parameter "y" of type "list[T@Class8]" +  "Literal['']" is not assignable to "int" (reportArgumentType) +constructors_callable.py:196:13 - information: Type of "r9" is "(x: list[T@__init__], y: list[T@__init__]) -> Class9" +constructors_callable.py:197:10 - error: Argument of type "Literal['not a list']" cannot be assigned to parameter "y" of type "list[T@__init__]" +  "Literal['not a list']" is not assignable to "list[str]" (reportArgumentType) +constructors_callable.py:199:22 - error: Argument of type "list[str]" cannot be assigned to parameter "y" of type "list[T@__init__]" +  "Literal['']" is not assignable to "int" (reportArgumentType) +constructors_callable.py:210:13 - information: Type of "r10" is "(x: list[T_int@Class10], y: list[T_int@Class10]) -> Class10[T_int@Class10]" +constructors_callable.py:211:10 - error: Argument of type "Literal['not a list']" cannot be assigned to parameter "y" of type "list[T_int@Class10]" +  "Literal['not a list']" is not assignable to "list[int]" (reportArgumentType) +constructors_callable.py:212:11 - error: Argument of type "list[str]" cannot be assigned to parameter "y" of type "list[T_int@Class10]"   "Literal['']" is not assignable to "int" (reportArgumentType) -constructors_callable.py:195:13 - information: Type of "r9" is "(x: list[T@__init__], y: list[T@__init__]) -> Class9" -constructors_callable.py:197:10 - error: Argument of type "list[str]" cannot be assigned to parameter "y" of type "list[T@__init__]" +constructors_callable.py:224:13 - information: Type of "r11" is "(x: list[T_int@__init__], y: list[T_int@__init__]) -> Class11" +constructors_callable.py:225:10 - error: Argument of type "Literal['not a list']" cannot be assigned to parameter "y" of type "list[T_int@__init__]" +  "Literal['not a list']" is not assignable to "list[int]" (reportArgumentType) +constructors_callable.py:226:11 - error: Argument of type "list[str]" cannot be assigned to parameter "y" of type "list[T_int@__init__]"   "Literal['']" is not assignable to "int" (reportArgumentType) """ diff --git a/conformance/results/results.html b/conformance/results/results.html index 0edd52cc8..13b802460 100644 --- a/conformance/results/results.html +++ b/conformance/results/results.html @@ -828,11 +828,11 @@

Python Type System Conformance Test Results

     constructors_callable
Partial

Does not generate a union type for __new__ and __init__ when converting class to callable.

Does not ignore __init__ based on __new__ return type when converting class to callable.

Does not support __new__ return type that is different from class being constructed.

-Pass -Pass +
Partial

List literal arguments are inferred in isolation before specialization inference

+
Partial

List literal arguments are inferred in isolation before specialization inference

Partial

Converting constructor to callable does not preserve class-scoped type params.

-Pass -
Partial

Does not include `__init__` when `__new__` returns `Self`.

Does not respect `NoReturn` return type on metaclass `__call__`.

Does not ignore `__init__` when `__new__` returns `Any`.

Unions overload return types.

+
Partial

List literal arguments are inferred in isolation before specialization inference

+
Partial

Does not include `__init__` when `__new__` returns `Self`.

Does not respect `NoReturn` return type on metaclass `__call__`.

Does not ignore `__init__` when `__new__` returns `Any`.

Unions overload return types.

List literal arguments are inferred in isolation before specialization inference

     constructors_consistency
Pass*

Does not report inconsistency between __new__ and __init__ (optional).

diff --git a/conformance/results/ty/constructors_callable.toml b/conformance/results/ty/constructors_callable.toml index a0e0c6c35..c19cbb675 100644 --- a/conformance/results/ty/constructors_callable.toml +++ b/conformance/results/ty/constructors_callable.toml @@ -5,6 +5,7 @@ Does not include `__init__` when `__new__` returns `Self`. Does not respect `NoReturn` return type on metaclass `__call__`. Does not ignore `__init__` when `__new__` returns `Any`. Unions overload return types. +List literal arguments are inferred in isolation before specialization inference """ errors_diff = """ Line 66: Expected 1 errors @@ -16,6 +17,10 @@ Line 143: Unexpected errors ["constructors_callable.py:143:27: error[invalid-arg Line 145: Unexpected errors ['constructors_callable.py:145:1: error[type-assertion-failure] Type `Any | Class6Any` does not match asserted type `Any`'] Line 166: Unexpected errors ['constructors_callable.py:166:1: error[type-assertion-failure] Type `Class7[int] | Class7[str]` does not match asserted type `Class7[int]`'] Line 167: Unexpected errors ['constructors_callable.py:167:1: error[type-assertion-failure] Type `Class7[int] | Class7[str]` does not match asserted type `Class7[str]`'] +Line 187: Unexpected errors ['constructors_callable.py:187:16: error[invalid-argument-type] Argument is incorrect: Expected `list[int | str]`, found `list[int]`', 'constructors_callable.py:187:21: error[invalid-argument-type] Argument is incorrect: Expected `list[int | str]`, found `list[str]`'] +Line 199: Unexpected errors ['constructors_callable.py:199:16: error[invalid-argument-type] Argument is incorrect: Expected `list[int | str]`, found `list[int]`', 'constructors_callable.py:199:21: error[invalid-argument-type] Argument is incorrect: Expected `list[int | str]`, found `list[str]`'] +Line 215: Unexpected errors ['constructors_callable.py:215:22: error[invalid-argument-type] Argument is incorrect: Expected `list[int]`, found `list[bool]`'] +Line 229: Unexpected errors ['constructors_callable.py:229:22: error[invalid-argument-type] Argument is incorrect: Expected `list[int]`, found `list[bool]`'] """ output = """ constructors_callable.py:36:13: info[revealed-type] Revealed type: `(x: int) -> Class1` @@ -42,9 +47,21 @@ constructors_callable.py:164:5: info[revealed-type] Revealed type: `Overload[[T] constructors_callable.py:166:1: error[type-assertion-failure] Type `Class7[int] | Class7[str]` does not match asserted type `Class7[int]` constructors_callable.py:167:1: error[type-assertion-failure] Type `Class7[int] | Class7[str]` does not match asserted type `Class7[str]` constructors_callable.py:184:13: info[revealed-type] Revealed type: `[T](x: list[T], y: list[T]) -> Class8[T]` -constructors_callable.py:186:4: error[invalid-argument-type] Argument is incorrect: Expected `list[int | str]`, found `list[int]` -constructors_callable.py:186:9: error[invalid-argument-type] Argument is incorrect: Expected `list[int | str]`, found `list[str]` -constructors_callable.py:195:13: info[revealed-type] Revealed type: `[T](x: list[T], y: list[T]) -> Class9` -constructors_callable.py:197:4: error[invalid-argument-type] Argument is incorrect: Expected `list[int | str]`, found `list[int]` -constructors_callable.py:197:9: error[invalid-argument-type] Argument is incorrect: Expected `list[int | str]`, found `list[str]` +constructors_callable.py:185:10: error[invalid-argument-type] Argument is incorrect: Expected `list[str]`, found `Literal["not a list"]` +constructors_callable.py:187:16: error[invalid-argument-type] Argument is incorrect: Expected `list[int | str]`, found `list[int]` +constructors_callable.py:187:21: error[invalid-argument-type] Argument is incorrect: Expected `list[int | str]`, found `list[str]` +constructors_callable.py:196:13: info[revealed-type] Revealed type: `[T](x: list[T], y: list[T]) -> Class9` +constructors_callable.py:197:10: error[invalid-argument-type] Argument is incorrect: Expected `list[str]`, found `Literal["not a list"]` +constructors_callable.py:199:16: error[invalid-argument-type] Argument is incorrect: Expected `list[int | str]`, found `list[int]` +constructors_callable.py:199:21: error[invalid-argument-type] Argument is incorrect: Expected `list[int | str]`, found `list[str]` +constructors_callable.py:210:13: info[revealed-type] Revealed type: `[T_int](x: list[T_int], y: list[T_int]) -> Class10[T_int]` +constructors_callable.py:211:10: error[invalid-argument-type] Argument is incorrect: Expected `list[int]`, found `Literal["not a list"]` +constructors_callable.py:212:10: error[invalid-argument-type] Argument is incorrect: Argument type `str` does not satisfy upper bound `int` of type variable `T_int` +constructors_callable.py:212:10: error[invalid-argument-type] Argument is incorrect: Expected `list[int]`, found `list[str]` +constructors_callable.py:215:22: error[invalid-argument-type] Argument is incorrect: Expected `list[int]`, found `list[bool]` +constructors_callable.py:224:13: info[revealed-type] Revealed type: `[T_int](x: list[T_int], y: list[T_int]) -> Class11` +constructors_callable.py:225:10: error[invalid-argument-type] Argument is incorrect: Expected `list[int]`, found `Literal["not a list"]` +constructors_callable.py:226:10: error[invalid-argument-type] Argument is incorrect: Argument type `str` does not satisfy upper bound `int` of type variable `T_int` +constructors_callable.py:226:10: error[invalid-argument-type] Argument is incorrect: Expected `list[int]`, found `list[str]` +constructors_callable.py:229:22: error[invalid-argument-type] Argument is incorrect: Expected `list[int]`, found `list[bool]` """ diff --git a/conformance/results/zuban/constructors_callable.toml b/conformance/results/zuban/constructors_callable.toml index 09b2c88ee..71406d9dd 100644 --- a/conformance/results/zuban/constructors_callable.toml +++ b/conformance/results/zuban/constructors_callable.toml @@ -1,5 +1,11 @@ -conformance_automated = "Pass" +conformant = "Partial" +notes = """ +List literal arguments are inferred in isolation before specialization inference +""" +conformance_automated = "Fail" errors_diff = """ +Line 187: Unexpected errors ['constructors_callable.py:187: error: Expression is of type "Class8[Any]", not "Class8[int | str]" [misc]', 'constructors_callable.py:187: error: List item 0 has incompatible type "str"; expected "int" [list-item]'] +Line 199: Unexpected errors ['constructors_callable.py:199: error: List item 0 has incompatible type "str"; expected "int" [list-item]'] """ output = """ constructors_callable.py:36: note: Revealed type is "def (x: builtins.int) -> tests.constructors_callable.Class1" @@ -21,7 +27,16 @@ constructors_callable.py:144: note: Revealed type is "def () -> Any" constructors_callable.py:146: error: Too many arguments [call-arg] constructors_callable.py:164: note: Revealed type is "Overload(def (x: builtins.int) -> tests.constructors_callable.Class7[builtins.int], def (x: builtins.str) -> tests.constructors_callable.Class7[builtins.str])" constructors_callable.py:184: note: Revealed type is "def [T] (x: builtins.list[T], y: builtins.list[T]) -> tests.constructors_callable.Class8[T]" -constructors_callable.py:186: error: List item 0 has incompatible type "str"; expected "int" [list-item] -constructors_callable.py:195: note: Revealed type is "def [T] (x: builtins.list[T], y: builtins.list[T]) -> tests.constructors_callable.Class9" -constructors_callable.py:197: error: List item 0 has incompatible type "str"; expected "int" [list-item] +constructors_callable.py:185: error: Argument 2 has incompatible type "str"; expected "list[str]" [arg-type] +constructors_callable.py:187: error: Expression is of type "Class8[Any]", not "Class8[int | str]" [misc] +constructors_callable.py:187: error: List item 0 has incompatible type "str"; expected "int" [list-item] +constructors_callable.py:196: note: Revealed type is "def [T] (x: builtins.list[T], y: builtins.list[T]) -> tests.constructors_callable.Class9" +constructors_callable.py:197: error: Argument 2 has incompatible type "str"; expected "list[str]" [arg-type] +constructors_callable.py:199: error: List item 0 has incompatible type "str"; expected "int" [list-item] +constructors_callable.py:210: note: Revealed type is "def [T_int <: builtins.int] (x: builtins.list[T_int], y: builtins.list[T_int]) -> tests.constructors_callable.Class10[T_int]" +constructors_callable.py:211: error: Argument 2 has incompatible type "str"; expected "list[int]" [arg-type] +constructors_callable.py:212: error: List item 0 has incompatible type "str"; expected "int" [list-item] +constructors_callable.py:224: note: Revealed type is "def [T_int <: builtins.int] (x: builtins.list[T_int], y: builtins.list[T_int]) -> tests.constructors_callable.Class11" +constructors_callable.py:225: error: Argument 2 has incompatible type "str"; expected "list[int]" [arg-type] +constructors_callable.py:226: error: List item 0 has incompatible type "str"; expected "int" [list-item] """ diff --git a/conformance/tests/constructors_callable.py b/conformance/tests/constructors_callable.py index c05fee3fb..912f4ea4e 100644 --- a/conformance/tests/constructors_callable.py +++ b/conformance/tests/constructors_callable.py @@ -182,8 +182,9 @@ def __new__(cls, x: list[T], y: list[T]) -> Self: r8 = accepts_callable(Class8) reveal_type(r8) # `def [T] (x: list[T], y: list[T]) -> Class8[T]` -assert_type(r8([""], [""]), Class8[str]) -r8([1], [""]) # E +r8([""], "not a list") # E: no assignment of T makes the second argument valid +assert_type(r8([""], [""]), Class8[str]) # T = str +assert_type(r8([1], [""]), Class8[int | str]) # T = int | str class Class9: @@ -193,5 +194,36 @@ def __init__(self, x: list[T], y: list[T]) -> None: r9 = accepts_callable(Class9) reveal_type(r9) # `def [T] (x: list[T], y: list[T]) -> Class9` +r9([""], "not a list") # E: no assignment of T makes the second argument valid assert_type(r9([""], [""]), Class9) -r9([1], [""]) # E +assert_type(r9([1], [""]), Class9) + + +T_int = TypeVar("T_int", bound=int) + +class Class10(Generic[T_int]): + def __new__(cls, x: list[T_int], y: list[T_int]) -> Self: + return super().__new__(cls) + + +r10 = accepts_callable(Class10) +reveal_type(r10) # `def [T_int] (x: list[T_int], y: list[T_int]) -> Class10[T_int]` +r10([1], "not a list") # E: no assignment of T_int makes the second argument valid +r10([1], [""]) # E: no assignment of T_int makes the second argument valid +assert_type(r10([1], [1]), Class10[int]) # T = int +assert_type(r10([True], [True]), Class10[bool]) # T = bool +assert_type(r10([1], [True]), Class10[int]) # T = int | bool = int + + +class Class11: + def __init__(self, x: list[T_int], y: list[T_int]) -> None: + pass + + +r11 = accepts_callable(Class11) +reveal_type(r11) # `def [T_int] (x: list[T_int], y: list[T_int]) -> Class11` +r11([1], "not a list") # E: no assignment of T_int makes the second argument valid +r11([1], [""]) # E: no assignment of T_int makes the second argument valid +assert_type(r11([1], [1]), Class11) # T = int +assert_type(r11([True], [True]), Class11) # T = bool +assert_type(r11([1], [True]), Class11) # T = int | bool = int From 8d7100472b43eaa551e2a17bddbc36f3c89d6b44 Mon Sep 17 00:00:00 2001 From: Douglas Creager Date: Mon, 8 Jun 2026 14:35:29 -0400 Subject: [PATCH 2/2] move most of these examples to generics_basic --- .../results/mypy/constructors_callable.toml | 14 ------- conformance/results/mypy/generics_basic.toml | 7 ++++ .../pycroscope/constructors_callable.toml | 19 ++------- .../results/pycroscope/generics_basic.toml | 6 +++ .../pyrefly/constructors_callable.toml | 16 +------ .../results/pyrefly/generics_basic.toml | 7 ++++ .../pyright/constructors_callable.toml | 23 ++-------- .../results/pyright/generics_basic.toml | 16 +++++++ conformance/results/results.html | 8 ++-- .../results/ty/constructors_callable.toml | 23 ++-------- conformance/results/ty/generics_basic.toml | 10 +++++ .../results/zuban/constructors_callable.toml | 15 +------ conformance/results/zuban/generics_basic.toml | 8 ++++ conformance/tests/constructors_callable.py | 36 ++-------------- conformance/tests/generics_basic.py | 42 +++++++++++++++++++ 15 files changed, 115 insertions(+), 135 deletions(-) diff --git a/conformance/results/mypy/constructors_callable.toml b/conformance/results/mypy/constructors_callable.toml index e5918845b..af573bd2e 100644 --- a/conformance/results/mypy/constructors_callable.toml +++ b/conformance/results/mypy/constructors_callable.toml @@ -15,10 +15,6 @@ Line 107: Unexpected errors ['constructors_callable.py:107: error: Expression is Line 118: Unexpected errors ['constructors_callable.py:118: error: Incompatible return type for "__new__" (returns "Class6Proxy", but must return a subtype of "Class6") [misc]'] Line 128: Unexpected errors ['constructors_callable.py:128: error: Expression is of type "Class6", not "Class6Proxy" [assert-type]', 'constructors_callable.py:128: error: Too few arguments [call-arg]'] Line 145: Unexpected errors ['constructors_callable.py:145: error: Expression is of type "Class6Any", not "Any" [assert-type]', 'constructors_callable.py:145: error: Too few arguments [call-arg]'] -Line 187: Unexpected errors ['constructors_callable.py:187: error: Expression is of type "Class8[Any]", not "Class8[int | str]" [assert-type]', 'constructors_callable.py:187: error: Cannot infer function type argument [misc]'] -Line 199: Unexpected errors ['constructors_callable.py:199: error: Cannot infer function type argument [misc]'] -Line 215: Unexpected errors ['constructors_callable.py:215: error: Expression is of type "Class10[Any]", not "Class10[int]" [assert-type]', 'constructors_callable.py:215: error: Cannot infer function type argument [misc]'] -Line 229: Unexpected errors ['constructors_callable.py:229: error: Cannot infer function type argument [misc]'] """ output = """ constructors_callable.py:36: note: Revealed type is "def (x: int) -> constructors_callable.Class1" @@ -48,18 +44,8 @@ constructors_callable.py:145: error: Too few arguments [call-arg] constructors_callable.py:164: note: Revealed type is "Overload(def (x: int) -> constructors_callable.Class7[int], def (x: str) -> constructors_callable.Class7[str])" constructors_callable.py:184: note: Revealed type is "def [T] (x: list[T], y: list[T]) -> constructors_callable.Class8[T]" constructors_callable.py:185: error: Argument 2 has incompatible type "str"; expected "list[str]" [arg-type] -constructors_callable.py:187: error: Expression is of type "Class8[Any]", not "Class8[int | str]" [assert-type] constructors_callable.py:187: error: Cannot infer function type argument [misc] constructors_callable.py:196: note: Revealed type is "def [T] (x: list[T], y: list[T]) -> constructors_callable.Class9" constructors_callable.py:197: error: Argument 2 has incompatible type "str"; expected "list[str]" [arg-type] constructors_callable.py:199: error: Cannot infer function type argument [misc] -constructors_callable.py:210: note: Revealed type is "def [T_int <: int] (x: list[T_int], y: list[T_int]) -> constructors_callable.Class10[T_int]" -constructors_callable.py:211: error: Argument 2 has incompatible type "str"; expected "list[int]" [arg-type] -constructors_callable.py:212: error: Cannot infer function type argument [misc] -constructors_callable.py:215: error: Expression is of type "Class10[Any]", not "Class10[int]" [assert-type] -constructors_callable.py:215: error: Cannot infer function type argument [misc] -constructors_callable.py:224: note: Revealed type is "def [T_int <: int] (x: list[T_int], y: list[T_int]) -> constructors_callable.Class11" -constructors_callable.py:225: error: Argument 2 has incompatible type "str"; expected "list[int]" [arg-type] -constructors_callable.py:226: error: Cannot infer function type argument [misc] -constructors_callable.py:229: error: Cannot infer function type argument [misc] """ diff --git a/conformance/results/mypy/generics_basic.toml b/conformance/results/mypy/generics_basic.toml index 3c95445b9..f850976ed 100644 --- a/conformance/results/mypy/generics_basic.toml +++ b/conformance/results/mypy/generics_basic.toml @@ -16,6 +16,13 @@ generics_basic.py:208: error: Dynamic metaclass not supported for "GenericMetaIn generics_basic.py:208: error: Type variable "generics_basic.T" is unbound [valid-type] generics_basic.py:208: note: (Hint: Use "Generic[T]" or "Protocol[T]" base class to bind "T" inside a class) generics_basic.py:208: note: (Hint: Use "T" in function signature to bind "T" inside a function) +generics_basic.py:223: error: Argument 2 to "takes_two_lists" has incompatible type "str"; expected "list[int]" [arg-type] +generics_basic.py:225: error: Cannot infer value of type parameter "T" of "takes_two_lists" [misc] +generics_basic.py:232: error: Cannot infer value of type parameter "T" of "takes_two_lists" [misc] +generics_basic.py:240: error: Argument 2 to "takes_two_int_lists" has incompatible type "str"; expected "list[int]" [arg-type] +generics_basic.py:241: error: Cannot infer value of type parameter "T_int" of "takes_two_int_lists" [misc] +generics_basic.py:244: error: Cannot infer value of type parameter "T_int" of "takes_two_int_lists" [misc] +generics_basic.py:251: error: Cannot infer value of type parameter "T_int" of "takes_two_int_lists" [misc] """ conformance_automated = "Pass" errors_diff = """ diff --git a/conformance/results/pycroscope/constructors_callable.toml b/conformance/results/pycroscope/constructors_callable.toml index 878586744..c9dbd4a39 100644 --- a/conformance/results/pycroscope/constructors_callable.toml +++ b/conformance/results/pycroscope/constructors_callable.toml @@ -1,11 +1,5 @@ -conformant = "Partial" -notes = """ -List literal arguments are inferred in isolation before specialization inference -""" -conformance_automated = "Fail" +conformance_automated = "Pass" errors_diff = """ -Line 187: Unexpected errors ['./constructors_callable.py:187:12: ./constructors_callable.py.Class8[Any[error]] is not equivalent to ./constructors_callable.py.Class8[int | str]', './constructors_callable.py:187:12: Cannot resolve type variables [incompatible_call]'] -Line 199: Unexpected errors ['./constructors_callable.py:199:12: Cannot resolve type variables [incompatible_call]'] """ output = """ ./constructors_callable.py:36:12: Revealed type is '(x: int) -> ./constructors_callable.py.Class1' [reveal_type] @@ -28,15 +22,8 @@ output = """ ./constructors_callable.py:164:4: Revealed type is '(x: ~_Ctor_Class7_T) -> ./constructors_callable.py.Class7[~_Ctor_Class7_T]' [reveal_type] ./constructors_callable.py:184:12: Revealed type is '(x: list[~T@./constructors_callable.py.Class8], y: list[~T@./constructors_callable.py.Class8]) -> ./constructors_callable.py.Class8[~T@./constructors_callable.py.Class8]' [reveal_type] ./constructors_callable.py:185:9: Incompatible argument type for y: expected list[~T@./constructors_callable.py.Class8] but got Literal['not a list'] [incompatible_argument] -./constructors_callable.py:187:12: ./constructors_callable.py.Class8[Any[error]] is not equivalent to ./constructors_callable.py.Class8[int | str] -./constructors_callable.py:187:12: Cannot resolve type variables [incompatible_call] +./constructors_callable.py:187:0: Cannot resolve type variables [incompatible_call] ./constructors_callable.py:196:12: Revealed type is '(x: list[~T@./constructors_callable.py.Class9.__init__..__init__], y: list[~T@./constructors_callable.py.Class9.__init__..__init__]) -> ./constructors_callable.py.Class9' [reveal_type] ./constructors_callable.py:197:9: Incompatible argument type for y: expected list[~T@./constructors_callable.py.Class9.__init__..__init__] but got Literal['not a list'] [incompatible_argument] -./constructors_callable.py:199:12: Cannot resolve type variables [incompatible_call] -./constructors_callable.py:210:12: Revealed type is '(x: list[~T_int@./constructors_callable.py.Class10], y: list[~T_int@./constructors_callable.py.Class10]) -> ./constructors_callable.py.Class10[~T_int@./constructors_callable.py.Class10]' [reveal_type] -./constructors_callable.py:211:9: Incompatible argument type for y: expected list[~T_int@./constructors_callable.py.Class10] but got Literal['not a list'] [incompatible_argument] -./constructors_callable.py:212:9: Incompatible argument type for y: expected list[~T_int@./constructors_callable.py.Class10] but got Literal[['']] [incompatible_argument] -./constructors_callable.py:224:12: Revealed type is '(x: list[~T_int@./constructors_callable.py.Class11.__init__..__init__], y: list[~T_int@./constructors_callable.py.Class11.__init__..__init__]) -> ./constructors_callable.py.Class11' [reveal_type] -./constructors_callable.py:225:9: Incompatible argument type for y: expected list[~T_int@./constructors_callable.py.Class11.__init__..__init__] but got Literal['not a list'] [incompatible_argument] -./constructors_callable.py:226:9: Incompatible argument type for y: expected list[~T_int@./constructors_callable.py.Class11.__init__..__init__] but got Literal[['']] [incompatible_argument] +./constructors_callable.py:199:0: Cannot resolve type variables [incompatible_call] """ diff --git a/conformance/results/pycroscope/generics_basic.toml b/conformance/results/pycroscope/generics_basic.toml index 1876b1010..2cabd73cf 100644 --- a/conformance/results/pycroscope/generics_basic.toml +++ b/conformance/results/pycroscope/generics_basic.toml @@ -15,4 +15,10 @@ output = """ ./generics_basic.py:171:27: All type parameters for the class must appear within Generic or Protocol [invalid_base] ./generics_basic.py:172:27: All type parameters for the class must appear within Generic or Protocol [invalid_base] ./generics_basic.py:208:36: Cannot determine metaclass [invalid_metaclass] +./generics_basic.py:223:21: Incompatible argument type for y: expected list[~T@./generics_basic.py.takes_two_lists..takes_two_lists] but got Literal['not a list'] [incompatible_argument] +./generics_basic.py:225:0: Cannot resolve type variables [incompatible_call] +./generics_basic.py:232:4: Cannot resolve type variables [incompatible_call] +./generics_basic.py:240:25: Incompatible argument type for y: expected list[~T_int@./generics_basic.py.takes_two_int_lists..takes_two_int_lists] but got Literal['not a list'] [incompatible_argument] +./generics_basic.py:241:25: Incompatible argument type for y: expected list[~T_int@./generics_basic.py.takes_two_int_lists..takes_two_int_lists] but got Literal[['']] [incompatible_argument] +./generics_basic.py:251:4: Cannot resolve type variables [incompatible_call] """ diff --git a/conformance/results/pyrefly/constructors_callable.toml b/conformance/results/pyrefly/constructors_callable.toml index 8c3793108..bf88f403d 100644 --- a/conformance/results/pyrefly/constructors_callable.toml +++ b/conformance/results/pyrefly/constructors_callable.toml @@ -4,13 +4,7 @@ Converting constructor to callable does not preserve class-scoped type params. """ conformance_automated = "Fail" errors_diff = """ -Line 212: Expected 1 errors Line 186: Unexpected errors ['assert_type(Class8[Unknown], Class8[str]) failed [assert-type]'] -Line 187: Unexpected errors ['assert_type(Class8[Unknown], Class8[int | str]) failed [assert-type]'] -Line 199: Unexpected errors ['Argument `list[str]` is not assignable to parameter `y` with type `list[int]` [bad-argument-type]'] -Line 213: Unexpected errors ['assert_type(Class10[Unknown], Class10[int]) failed [assert-type]'] -Line 214: Unexpected errors ['assert_type(Class10[Unknown], Class10[bool]) failed [assert-type]'] -Line 215: Unexpected errors ['assert_type(Class10[Unknown], Class10[int]) failed [assert-type]'] """ output = """ ERROR constructors_callable.py:38:3-5: Missing argument `x` [missing-argument] @@ -28,14 +22,6 @@ ERROR constructors_callable.py:129:4-5: Expected 0 positional arguments, got 1 [ ERROR constructors_callable.py:146:8-9: Expected 0 positional arguments, got 1 [bad-argument-count] ERROR constructors_callable.py:185:10-22: Argument `Literal['not a list']` is not assignable to parameter `y` with type `list[Unknown]` [bad-argument-type] ERROR constructors_callable.py:186:12-41: assert_type(Class8[Unknown], Class8[str]) failed [assert-type] -ERROR constructors_callable.py:187:12-46: assert_type(Class8[Unknown], Class8[int | str]) failed [assert-type] ERROR constructors_callable.py:197:10-22: Argument `Literal['not a list']` is not assignable to parameter `y` with type `list[str]` [bad-argument-type] -ERROR constructors_callable.py:199:21-25: Argument `list[str]` is not assignable to parameter `y` with type `list[int]` [bad-argument-type] -ERROR constructors_callable.py:211:10-22: Argument `Literal['not a list']` is not assignable to parameter `y` with type `list[Unknown]` [bad-argument-type] -ERROR constructors_callable.py:213:12-41: assert_type(Class10[Unknown], Class10[int]) failed [assert-type] -ERROR constructors_callable.py:214:12-48: assert_type(Class10[Unknown], Class10[bool]) failed [assert-type] -ERROR constructors_callable.py:215:12-44: assert_type(Class10[Unknown], Class10[int]) failed [assert-type] -ERROR constructors_callable.py:225:10-22: Argument `Literal['not a list']` is not assignable to parameter `y` with type `list[int]` [bad-argument-type] -ERROR constructors_callable.py:226:4-15: `str` is not assignable to upper bound `int` of type variable `T_int` [bad-specialization] -ERROR constructors_callable.py:226:10-14: Argument `list[str]` is not assignable to parameter `y` with type `list[int]` [bad-argument-type] +ERROR constructors_callable.py:199:9-13: Argument `list[str]` is not assignable to parameter `y` with type `list[int]` [bad-argument-type] """ diff --git a/conformance/results/pyrefly/generics_basic.toml b/conformance/results/pyrefly/generics_basic.toml index cc8c87d4b..91d67475f 100644 --- a/conformance/results/pyrefly/generics_basic.toml +++ b/conformance/results/pyrefly/generics_basic.toml @@ -15,4 +15,11 @@ ERROR generics_basic.py:163:7-11: Expected a type variable, got `int` [invalid-t ERROR generics_basic.py:171:7-11: Class `Bad3` uses type variables not specified in `Generic` or `Protocol` base [invalid-type-var] ERROR generics_basic.py:172:7-11: Class `Bad4` uses type variables not specified in `Generic` or `Protocol` base [invalid-type-var] ERROR generics_basic.py:208:7-26: Metaclass may not be an unbound generic [invalid-inheritance] +ERROR generics_basic.py:223:22-34: Argument `Literal['not a list']` is not assignable to parameter `y` with type `list[int]` in function `takes_two_lists` [bad-argument-type] +ERROR generics_basic.py:225:22-26: Argument `list[str]` is not assignable to parameter `y` with type `list[int]` in function `takes_two_lists` [bad-argument-type] +ERROR generics_basic.py:232:24-25: Argument `list[str]` is not assignable to parameter `y` with type `list[int]` in function `takes_two_lists` [bad-argument-type] +ERROR generics_basic.py:240:26-38: Argument `Literal['not a list']` is not assignable to parameter `y` with type `list[int]` in function `takes_two_int_lists` [bad-argument-type] +ERROR generics_basic.py:241:20-31: `str` is not assignable to upper bound `int` of type variable `T_int` [bad-specialization] +ERROR generics_basic.py:241:26-30: Argument `list[str]` is not assignable to parameter `y` with type `list[int]` in function `takes_two_int_lists` [bad-argument-type] +ERROR generics_basic.py:251:28-29: Argument `list[bool]` is not assignable to parameter `y` with type `list[int]` in function `takes_two_int_lists` [bad-argument-type] """ diff --git a/conformance/results/pyright/constructors_callable.toml b/conformance/results/pyright/constructors_callable.toml index 02716dc29..901fe77b0 100644 --- a/conformance/results/pyright/constructors_callable.toml +++ b/conformance/results/pyright/constructors_callable.toml @@ -1,11 +1,5 @@ -conformant = "Partial" -notes = """ -List literal arguments are inferred in isolation before specialization inference -""" -conformance_automated = "Fail" +conformance_automated = "Pass" errors_diff = """ -Line 187: Unexpected errors ['constructors_callable.py:187:13 - error: "assert_type" mismatch: expected "Class8[int | str]" but received "Class8[int]" (reportAssertTypeFailure)', 'constructors_callable.py:187:22 - error: Argument of type "list[str]" cannot be assigned to parameter "y" of type "list[T@Class8]"'] -Line 199: Unexpected errors ['constructors_callable.py:199:22 - error: Argument of type "list[str]" cannot be assigned to parameter "y" of type "list[T@__init__]"'] """ output = """ constructors_callable.py:36:13 - information: Type of "r1" is "(x: int) -> Class1" @@ -32,22 +26,11 @@ constructors_callable.py:164:5 - information: Type of "r7" is "Overload[(x: int) constructors_callable.py:184:13 - information: Type of "r8" is "(x: list[T@Class8], y: list[T@Class8]) -> Class8[T@Class8]" constructors_callable.py:185:10 - error: Argument of type "Literal['not a list']" cannot be assigned to parameter "y" of type "list[T@Class8]"   "Literal['not a list']" is not assignable to "list[str]" (reportArgumentType) -constructors_callable.py:187:13 - error: "assert_type" mismatch: expected "Class8[int | str]" but received "Class8[int]" (reportAssertTypeFailure) -constructors_callable.py:187:22 - error: Argument of type "list[str]" cannot be assigned to parameter "y" of type "list[T@Class8]" +constructors_callable.py:187:10 - error: Argument of type "list[str]" cannot be assigned to parameter "y" of type "list[T@Class8]"   "Literal['']" is not assignable to "int" (reportArgumentType) constructors_callable.py:196:13 - information: Type of "r9" is "(x: list[T@__init__], y: list[T@__init__]) -> Class9" constructors_callable.py:197:10 - error: Argument of type "Literal['not a list']" cannot be assigned to parameter "y" of type "list[T@__init__]"   "Literal['not a list']" is not assignable to "list[str]" (reportArgumentType) -constructors_callable.py:199:22 - error: Argument of type "list[str]" cannot be assigned to parameter "y" of type "list[T@__init__]" -  "Literal['']" is not assignable to "int" (reportArgumentType) -constructors_callable.py:210:13 - information: Type of "r10" is "(x: list[T_int@Class10], y: list[T_int@Class10]) -> Class10[T_int@Class10]" -constructors_callable.py:211:10 - error: Argument of type "Literal['not a list']" cannot be assigned to parameter "y" of type "list[T_int@Class10]" -  "Literal['not a list']" is not assignable to "list[int]" (reportArgumentType) -constructors_callable.py:212:11 - error: Argument of type "list[str]" cannot be assigned to parameter "y" of type "list[T_int@Class10]" -  "Literal['']" is not assignable to "int" (reportArgumentType) -constructors_callable.py:224:13 - information: Type of "r11" is "(x: list[T_int@__init__], y: list[T_int@__init__]) -> Class11" -constructors_callable.py:225:10 - error: Argument of type "Literal['not a list']" cannot be assigned to parameter "y" of type "list[T_int@__init__]" -  "Literal['not a list']" is not assignable to "list[int]" (reportArgumentType) -constructors_callable.py:226:11 - error: Argument of type "list[str]" cannot be assigned to parameter "y" of type "list[T_int@__init__]" +constructors_callable.py:199:10 - error: Argument of type "list[str]" cannot be assigned to parameter "y" of type "list[T@__init__]"   "Literal['']" is not assignable to "int" (reportArgumentType) """ diff --git a/conformance/results/pyright/generics_basic.toml b/conformance/results/pyright/generics_basic.toml index 8b77d57f4..2fa41eea6 100644 --- a/conformance/results/pyright/generics_basic.toml +++ b/conformance/results/pyright/generics_basic.toml @@ -20,6 +20,22 @@ generics_basic.py:171:7 - error: Generic[] or Protocol[] must include all type v generics_basic.py:172:7 - error: Generic[] or Protocol[] must include all type variables   Missing type variables: "T_co" (reportGeneralTypeIssues) generics_basic.py:208:37 - error: Metaclass cannot be generic (reportGeneralTypeIssues) +generics_basic.py:223:22 - error: Argument of type "Literal['not a list']" cannot be assigned to parameter "y" of type "list[T@takes_two_lists]" in function "takes_two_lists" +  "Literal['not a list']" is not assignable to "list[int]" (reportArgumentType) +generics_basic.py:225:23 - error: Argument of type "list[str]" cannot be assigned to parameter "y" of type "list[T@takes_two_lists]" in function "takes_two_lists" +  "Literal['']" is not assignable to "int" (reportArgumentType) +generics_basic.py:232:24 - error: Argument of type "list[str]" cannot be assigned to parameter "y" of type "list[T@takes_two_lists]" in function "takes_two_lists" +  "list[str]" is not assignable to "list[int]" +    Type parameter "_T@list" is invariant, but "str" is not the same as "int" +    Consider switching from "list" to "Sequence" which is covariant (reportArgumentType) +generics_basic.py:240:26 - error: Argument of type "Literal['not a list']" cannot be assigned to parameter "y" of type "list[T_int@takes_two_int_lists]" in function "takes_two_int_lists" +  "Literal['not a list']" is not assignable to "list[int]" (reportArgumentType) +generics_basic.py:241:27 - error: Argument of type "list[str]" cannot be assigned to parameter "y" of type "list[T_int@takes_two_int_lists]" in function "takes_two_int_lists" +  "Literal['']" is not assignable to "int" (reportArgumentType) +generics_basic.py:251:28 - error: Argument of type "list[bool]" cannot be assigned to parameter "y" of type "list[T_int@takes_two_int_lists]" in function "takes_two_int_lists" +  "list[bool]" is not assignable to "list[int]" +    Type parameter "_T@list" is invariant, but "bool" is not the same as "int" +    Consider switching from "list" to "Sequence" which is covariant (reportArgumentType) """ conformance_automated = "Pass" errors_diff = """ diff --git a/conformance/results/results.html b/conformance/results/results.html index 13b802460..0edd52cc8 100644 --- a/conformance/results/results.html +++ b/conformance/results/results.html @@ -828,11 +828,11 @@

Python Type System Conformance Test Results

     constructors_callable
Partial

Does not generate a union type for __new__ and __init__ when converting class to callable.

Does not ignore __init__ based on __new__ return type when converting class to callable.

Does not support __new__ return type that is different from class being constructed.

-
Partial

List literal arguments are inferred in isolation before specialization inference

-
Partial

List literal arguments are inferred in isolation before specialization inference

+Pass +Pass
Partial

Converting constructor to callable does not preserve class-scoped type params.

-
Partial

List literal arguments are inferred in isolation before specialization inference

-
Partial

Does not include `__init__` when `__new__` returns `Self`.

Does not respect `NoReturn` return type on metaclass `__call__`.

Does not ignore `__init__` when `__new__` returns `Any`.

Unions overload return types.

List literal arguments are inferred in isolation before specialization inference

+Pass +
Partial

Does not include `__init__` when `__new__` returns `Self`.

Does not respect `NoReturn` return type on metaclass `__call__`.

Does not ignore `__init__` when `__new__` returns `Any`.

Unions overload return types.

     constructors_consistency
Pass*

Does not report inconsistency between __new__ and __init__ (optional).

diff --git a/conformance/results/ty/constructors_callable.toml b/conformance/results/ty/constructors_callable.toml index c19cbb675..8652886de 100644 --- a/conformance/results/ty/constructors_callable.toml +++ b/conformance/results/ty/constructors_callable.toml @@ -5,7 +5,6 @@ Does not include `__init__` when `__new__` returns `Self`. Does not respect `NoReturn` return type on metaclass `__call__`. Does not ignore `__init__` when `__new__` returns `Any`. Unions overload return types. -List literal arguments are inferred in isolation before specialization inference """ errors_diff = """ Line 66: Expected 1 errors @@ -17,10 +16,6 @@ Line 143: Unexpected errors ["constructors_callable.py:143:27: error[invalid-arg Line 145: Unexpected errors ['constructors_callable.py:145:1: error[type-assertion-failure] Type `Any | Class6Any` does not match asserted type `Any`'] Line 166: Unexpected errors ['constructors_callable.py:166:1: error[type-assertion-failure] Type `Class7[int] | Class7[str]` does not match asserted type `Class7[int]`'] Line 167: Unexpected errors ['constructors_callable.py:167:1: error[type-assertion-failure] Type `Class7[int] | Class7[str]` does not match asserted type `Class7[str]`'] -Line 187: Unexpected errors ['constructors_callable.py:187:16: error[invalid-argument-type] Argument is incorrect: Expected `list[int | str]`, found `list[int]`', 'constructors_callable.py:187:21: error[invalid-argument-type] Argument is incorrect: Expected `list[int | str]`, found `list[str]`'] -Line 199: Unexpected errors ['constructors_callable.py:199:16: error[invalid-argument-type] Argument is incorrect: Expected `list[int | str]`, found `list[int]`', 'constructors_callable.py:199:21: error[invalid-argument-type] Argument is incorrect: Expected `list[int | str]`, found `list[str]`'] -Line 215: Unexpected errors ['constructors_callable.py:215:22: error[invalid-argument-type] Argument is incorrect: Expected `list[int]`, found `list[bool]`'] -Line 229: Unexpected errors ['constructors_callable.py:229:22: error[invalid-argument-type] Argument is incorrect: Expected `list[int]`, found `list[bool]`'] """ output = """ constructors_callable.py:36:13: info[revealed-type] Revealed type: `(x: int) -> Class1` @@ -48,20 +43,10 @@ constructors_callable.py:166:1: error[type-assertion-failure] Type `Class7[int] constructors_callable.py:167:1: error[type-assertion-failure] Type `Class7[int] | Class7[str]` does not match asserted type `Class7[str]` constructors_callable.py:184:13: info[revealed-type] Revealed type: `[T](x: list[T], y: list[T]) -> Class8[T]` constructors_callable.py:185:10: error[invalid-argument-type] Argument is incorrect: Expected `list[str]`, found `Literal["not a list"]` -constructors_callable.py:187:16: error[invalid-argument-type] Argument is incorrect: Expected `list[int | str]`, found `list[int]` -constructors_callable.py:187:21: error[invalid-argument-type] Argument is incorrect: Expected `list[int | str]`, found `list[str]` +constructors_callable.py:187:4: error[invalid-argument-type] Argument is incorrect: Expected `list[int | str]`, found `list[int]` +constructors_callable.py:187:9: error[invalid-argument-type] Argument is incorrect: Expected `list[int | str]`, found `list[str]` constructors_callable.py:196:13: info[revealed-type] Revealed type: `[T](x: list[T], y: list[T]) -> Class9` constructors_callable.py:197:10: error[invalid-argument-type] Argument is incorrect: Expected `list[str]`, found `Literal["not a list"]` -constructors_callable.py:199:16: error[invalid-argument-type] Argument is incorrect: Expected `list[int | str]`, found `list[int]` -constructors_callable.py:199:21: error[invalid-argument-type] Argument is incorrect: Expected `list[int | str]`, found `list[str]` -constructors_callable.py:210:13: info[revealed-type] Revealed type: `[T_int](x: list[T_int], y: list[T_int]) -> Class10[T_int]` -constructors_callable.py:211:10: error[invalid-argument-type] Argument is incorrect: Expected `list[int]`, found `Literal["not a list"]` -constructors_callable.py:212:10: error[invalid-argument-type] Argument is incorrect: Argument type `str` does not satisfy upper bound `int` of type variable `T_int` -constructors_callable.py:212:10: error[invalid-argument-type] Argument is incorrect: Expected `list[int]`, found `list[str]` -constructors_callable.py:215:22: error[invalid-argument-type] Argument is incorrect: Expected `list[int]`, found `list[bool]` -constructors_callable.py:224:13: info[revealed-type] Revealed type: `[T_int](x: list[T_int], y: list[T_int]) -> Class11` -constructors_callable.py:225:10: error[invalid-argument-type] Argument is incorrect: Expected `list[int]`, found `Literal["not a list"]` -constructors_callable.py:226:10: error[invalid-argument-type] Argument is incorrect: Argument type `str` does not satisfy upper bound `int` of type variable `T_int` -constructors_callable.py:226:10: error[invalid-argument-type] Argument is incorrect: Expected `list[int]`, found `list[str]` -constructors_callable.py:229:22: error[invalid-argument-type] Argument is incorrect: Expected `list[int]`, found `list[bool]` +constructors_callable.py:199:4: error[invalid-argument-type] Argument is incorrect: Expected `list[int | str]`, found `list[int]` +constructors_callable.py:199:9: error[invalid-argument-type] Argument is incorrect: Expected `list[int | str]`, found `list[str]` """ diff --git a/conformance/results/ty/generics_basic.toml b/conformance/results/ty/generics_basic.toml index 463ed0f7d..ab12bf40e 100644 --- a/conformance/results/ty/generics_basic.toml +++ b/conformance/results/ty/generics_basic.toml @@ -19,4 +19,14 @@ generics_basic.py:163:12: error[invalid-argument-type] `` is not a generics_basic.py:171:1: error[invalid-generic-class] `Generic` base class must include all type variables used in other base classes generics_basic.py:172:1: error[invalid-generic-class] `Generic` base class must include all type variables used in other base classes generics_basic.py:208:27: error[invalid-metaclass] Generic metaclasses are not supported +generics_basic.py:223:22: error[invalid-argument-type] Argument to function `takes_two_lists` is incorrect: Expected `list[int]`, found `Literal["not a list"]` +generics_basic.py:225:17: error[invalid-argument-type] Argument to function `takes_two_lists` is incorrect: Expected `list[int | str]`, found `list[int]` +generics_basic.py:225:22: error[invalid-argument-type] Argument to function `takes_two_lists` is incorrect: Expected `list[int | str]`, found `list[str]` +generics_basic.py:232:21: error[invalid-argument-type] Argument to function `takes_two_lists` is incorrect: Expected `list[int | str]`, found `list[int]` +generics_basic.py:232:24: error[invalid-argument-type] Argument to function `takes_two_lists` is incorrect: Expected `list[int | str]`, found `list[str]` +generics_basic.py:240:26: error[invalid-argument-type] Argument to function `takes_two_int_lists` is incorrect: Expected `list[int]`, found `Literal["not a list"]` +generics_basic.py:241:26: error[invalid-argument-type] Argument to function `takes_two_int_lists` is incorrect: Argument type `str` does not satisfy upper bound `int` of type variable `T_int` +generics_basic.py:241:26: error[invalid-argument-type] Argument to function `takes_two_int_lists` is incorrect: Expected `list[int]`, found `list[str]` +generics_basic.py:244:26: error[invalid-argument-type] Argument to function `takes_two_int_lists` is incorrect: Expected `list[int]`, found `list[bool]` +generics_basic.py:251:28: error[invalid-argument-type] Argument to function `takes_two_int_lists` is incorrect: Expected `list[int]`, found `list[bool]` """ diff --git a/conformance/results/zuban/constructors_callable.toml b/conformance/results/zuban/constructors_callable.toml index 71406d9dd..569f40b9a 100644 --- a/conformance/results/zuban/constructors_callable.toml +++ b/conformance/results/zuban/constructors_callable.toml @@ -1,11 +1,5 @@ -conformant = "Partial" -notes = """ -List literal arguments are inferred in isolation before specialization inference -""" -conformance_automated = "Fail" +conformance_automated = "Pass" errors_diff = """ -Line 187: Unexpected errors ['constructors_callable.py:187: error: Expression is of type "Class8[Any]", not "Class8[int | str]" [misc]', 'constructors_callable.py:187: error: List item 0 has incompatible type "str"; expected "int" [list-item]'] -Line 199: Unexpected errors ['constructors_callable.py:199: error: List item 0 has incompatible type "str"; expected "int" [list-item]'] """ output = """ constructors_callable.py:36: note: Revealed type is "def (x: builtins.int) -> tests.constructors_callable.Class1" @@ -28,15 +22,8 @@ constructors_callable.py:146: error: Too many arguments [call-arg] constructors_callable.py:164: note: Revealed type is "Overload(def (x: builtins.int) -> tests.constructors_callable.Class7[builtins.int], def (x: builtins.str) -> tests.constructors_callable.Class7[builtins.str])" constructors_callable.py:184: note: Revealed type is "def [T] (x: builtins.list[T], y: builtins.list[T]) -> tests.constructors_callable.Class8[T]" constructors_callable.py:185: error: Argument 2 has incompatible type "str"; expected "list[str]" [arg-type] -constructors_callable.py:187: error: Expression is of type "Class8[Any]", not "Class8[int | str]" [misc] constructors_callable.py:187: error: List item 0 has incompatible type "str"; expected "int" [list-item] constructors_callable.py:196: note: Revealed type is "def [T] (x: builtins.list[T], y: builtins.list[T]) -> tests.constructors_callable.Class9" constructors_callable.py:197: error: Argument 2 has incompatible type "str"; expected "list[str]" [arg-type] constructors_callable.py:199: error: List item 0 has incompatible type "str"; expected "int" [list-item] -constructors_callable.py:210: note: Revealed type is "def [T_int <: builtins.int] (x: builtins.list[T_int], y: builtins.list[T_int]) -> tests.constructors_callable.Class10[T_int]" -constructors_callable.py:211: error: Argument 2 has incompatible type "str"; expected "list[int]" [arg-type] -constructors_callable.py:212: error: List item 0 has incompatible type "str"; expected "int" [list-item] -constructors_callable.py:224: note: Revealed type is "def [T_int <: builtins.int] (x: builtins.list[T_int], y: builtins.list[T_int]) -> tests.constructors_callable.Class11" -constructors_callable.py:225: error: Argument 2 has incompatible type "str"; expected "list[int]" [arg-type] -constructors_callable.py:226: error: List item 0 has incompatible type "str"; expected "int" [list-item] """ diff --git a/conformance/results/zuban/generics_basic.toml b/conformance/results/zuban/generics_basic.toml index 1b2260e44..8a98fe6f7 100644 --- a/conformance/results/zuban/generics_basic.toml +++ b/conformance/results/zuban/generics_basic.toml @@ -15,4 +15,12 @@ generics_basic.py:163: error: Free type variable expected in Protocol[...] [mis generics_basic.py:171: error: If Generic[...] or Protocol[...] is present it should list all type variables [misc] generics_basic.py:172: error: If Generic[...] or Protocol[...] is present it should list all type variables [misc] generics_basic.py:208: error: Invalid metaclass "GenericMeta[T]" [metaclass] +generics_basic.py:223: error: Argument 2 to "takes_two_lists" has incompatible type "str"; expected "list[int]" [arg-type] +generics_basic.py:225: error: List item 0 has incompatible type "str"; expected "int" [list-item] +generics_basic.py:232: error: Argument 2 to "takes_two_lists" has incompatible type "list[str]"; expected "list[int]" [arg-type] +generics_basic.py:240: error: Argument 2 to "takes_two_int_lists" has incompatible type "str"; expected "list[int]" [arg-type] +generics_basic.py:241: error: List item 0 has incompatible type "str"; expected "int" [list-item] +generics_basic.py:251: error: Argument 2 to "takes_two_int_lists" has incompatible type "list[bool]"; expected "list[int]" [arg-type] +generics_basic.py:251: note: "List" is invariant -- see https://mypy.readthedocs.io/en/stable/common_issues.html#variance +generics_basic.py:251: note: Consider using "Sequence" instead, which is covariant """ diff --git a/conformance/tests/constructors_callable.py b/conformance/tests/constructors_callable.py index 912f4ea4e..0ec091e2d 100644 --- a/conformance/tests/constructors_callable.py +++ b/conformance/tests/constructors_callable.py @@ -183,8 +183,8 @@ def __new__(cls, x: list[T], y: list[T]) -> Self: r8 = accepts_callable(Class8) reveal_type(r8) # `def [T] (x: list[T], y: list[T]) -> Class8[T]` r8([""], "not a list") # E: no assignment of T makes the second argument valid -assert_type(r8([""], [""]), Class8[str]) # T = str -assert_type(r8([1], [""]), Class8[int | str]) # T = int | str +assert_type(r8([""], [""]), Class8[str]) +r8([1], [""]) # E?: T = int | str is a potential solution class Class9: @@ -196,34 +196,4 @@ def __init__(self, x: list[T], y: list[T]) -> None: reveal_type(r9) # `def [T] (x: list[T], y: list[T]) -> Class9` r9([""], "not a list") # E: no assignment of T makes the second argument valid assert_type(r9([""], [""]), Class9) -assert_type(r9([1], [""]), Class9) - - -T_int = TypeVar("T_int", bound=int) - -class Class10(Generic[T_int]): - def __new__(cls, x: list[T_int], y: list[T_int]) -> Self: - return super().__new__(cls) - - -r10 = accepts_callable(Class10) -reveal_type(r10) # `def [T_int] (x: list[T_int], y: list[T_int]) -> Class10[T_int]` -r10([1], "not a list") # E: no assignment of T_int makes the second argument valid -r10([1], [""]) # E: no assignment of T_int makes the second argument valid -assert_type(r10([1], [1]), Class10[int]) # T = int -assert_type(r10([True], [True]), Class10[bool]) # T = bool -assert_type(r10([1], [True]), Class10[int]) # T = int | bool = int - - -class Class11: - def __init__(self, x: list[T_int], y: list[T_int]) -> None: - pass - - -r11 = accepts_callable(Class11) -reveal_type(r11) # `def [T_int] (x: list[T_int], y: list[T_int]) -> Class11` -r11([1], "not a list") # E: no assignment of T_int makes the second argument valid -r11([1], [""]) # E: no assignment of T_int makes the second argument valid -assert_type(r11([1], [1]), Class11) # T = int -assert_type(r11([True], [True]), Class11) # T = bool -assert_type(r11([1], [True]), Class11) # T = int | bool = int +r9([1], [""]) # E?: T = int | str is a potential solution diff --git a/conformance/tests/generics_basic.py b/conformance/tests/generics_basic.py index 179d84758..45f85f59f 100644 --- a/conformance/tests/generics_basic.py +++ b/conformance/tests/generics_basic.py @@ -207,3 +207,45 @@ class GenericMeta(type, Generic[T]): ... class GenericMetaInstance(metaclass=GenericMeta[T]): # E ... + + +# When a typevar appears in multiple parameters, we can (but are not required +# to) infer a "combined" specialization that satisfies all of the corresponding +# arguments. This is especially interesting for list literals, since `list` is +# invariant in its typevar. We can use the surrounding context of the generic +# function call to infer a wider type for the list literals that allows the call +# to succeed. + +def takes_two_lists(x: list[T], y: list[T]) -> T: + return x[0] + + +takes_two_lists([1], "not a list") # E: no assignment of T makes the second argument valid +takes_two_lists([""], [""]) # T = str or T = Literal[""] +takes_two_lists([1], [""]) # E?: T = int | str is a potential solution + +def test_specific_lists() -> None: + x: list[int] = [1] + y: list[int] = [1] + z: list[str] = [""] + assert_type(takes_two_lists(x, y), int) + takes_two_lists(x, z) # E: because lists are invariant, no assignment of T makes both arguments valid + + +T_int = TypeVar("T_int", bound=int) + +def takes_two_int_lists(x: list[T_int], y: list[T_int]) -> T_int: + return x[0] + +takes_two_int_lists([1], "not a list") # E: no assignment of T_int makes the second argument valid +takes_two_int_lists([1], [""]) # E: no assignment of T_int makes the second argument valid +takes_two_int_lists([1], [1]) # T = int or T = Literal[1] +takes_two_int_lists([True], [True]) # T = bool or T = Literal[True] +takes_two_int_lists([1], [True]) # E?: T = int | bool = int is a potential solution + +def test_specific_int_lists() -> None: + x: list[int] = [1] + y: list[int] = [1] + z: list[bool] = [True] + assert_type(takes_two_int_lists(x, y), int) + takes_two_int_lists(x, z) # E: because lists are invariant, no assignment of T makes both arguments valid