-
Notifications
You must be signed in to change notification settings - Fork 1.6k
[ty] Track different uses of legacy typevars, including context when rendering typevars #19604
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
Diagnostic diff on typing conformance testsChanges were detected when running ty on typing conformance tests--- old-output.txt 2025-08-01 16:10:16.545867493 +0000
+++ new-output.txt 2025-08-01 16:10:16.607867387 +0000
@@ -1,7 +1,7 @@
WARN ty is pre-release software and not ready for production use. Expect to encounter bugs, missing features, and fatal errors.
_directives_deprecated_library.py:15:31: error[invalid-return-type] Function always implicitly returns `None`, which is not assignable to return type `int`
_directives_deprecated_library.py:30:26: error[invalid-return-type] Function always implicitly returns `None`, which is not assignable to return type `str`
-_directives_deprecated_library.py:36:41: error[invalid-return-type] Function always implicitly returns `None`, which is not assignable to return type `Self`
+_directives_deprecated_library.py:36:41: error[invalid-return-type] Function always implicitly returns `None`, which is not assignable to return type `Self@Spam`
_directives_deprecated_library.py:41:25: error[invalid-return-type] Function always implicitly returns `None`, which is not assignable to return type `int | float`
_directives_deprecated_library.py:45:24: error[invalid-return-type] Function always implicitly returns `None`, which is not assignable to return type `str`
aliases_explicit.py:41:24: error[invalid-type-form] List literals are not allowed in this context in a type expression: Did you mean `tuple[str, str]`?
@@ -149,7 +149,7 @@
callables_protocol.py:97:1: error[invalid-assignment] Object of type `def cb4_bad1(x: int) -> None` is not assignable to `Proto4`
callables_protocol.py:121:1: error[invalid-assignment] Object of type `def cb6_bad1(*vals: bytes, *, max_len: int | None = None) -> list[bytes]` is not assignable to `NotProto6`
callables_protocol.py:176:14: error[invalid-argument-type] `ParamSpec` is not a valid argument to `Protocol`
-callables_protocol.py:179:62: error[invalid-return-type] Function always implicitly returns `None`, which is not assignable to return type `R`
+callables_protocol.py:179:62: error[invalid-return-type] Function always implicitly returns `None`, which is not assignable to return type `R@__call__`
callables_subtyping.py:26:5: error[invalid-assignment] Object of type `(int, /) -> int` is not assignable to `(int | float, /) -> int | float`
callables_subtyping.py:29:5: error[invalid-assignment] Object of type `(int | float, /) -> int | float` is not assignable to `(int, /) -> int`
callables_subtyping.py:204:21: error[invalid-argument-type] `ParamSpec` is not a valid argument to `Protocol`
@@ -189,10 +189,10 @@
constructors_call_new.py:76:17: error[missing-argument] No argument provided for required parameter `x` of bound method `__init__`
constructors_call_new.py:89:1: error[type-assertion-failure] Argument does not have asserted type `int | Class6`
constructors_call_new.py:89:13: error[missing-argument] No argument provided for required parameter `x` of bound method `__init__`
-constructors_call_new.py:113:42: error[invalid-return-type] Function always implicitly returns `None`, which is not assignable to return type `Class8[list[T]]`
+constructors_call_new.py:113:42: error[invalid-return-type] Function always implicitly returns `None`, which is not assignable to return type `Class8[list[T@Class8]]`
constructors_call_new.py:116:1: error[type-assertion-failure] Argument does not have asserted type `Class8[list[int]]`
constructors_call_new.py:117:1: error[type-assertion-failure] Argument does not have asserted type `Class8[list[str]]`
-constructors_call_new.py:125:42: error[invalid-return-type] Function always implicitly returns `None`, which is not assignable to return type `Self`
+constructors_call_new.py:125:42: error[invalid-return-type] Function always implicitly returns `None`, which is not assignable to return type `Self@Class9`
constructors_call_new.py:140:47: error[invalid-return-type] Function always implicitly returns `None`, which is not assignable to return type `Class11[int]`
constructors_call_type.py:40:5: error[missing-argument] No arguments provided for required parameters `x`, `y` of function `__new__`
constructors_call_type.py:50:5: error[missing-argument] No arguments provided for required parameters `x`, `y` of bound method `__init__`
@@ -201,7 +201,7 @@
constructors_callable.py:37:1: error[type-assertion-failure] Argument does not have asserted type `Class1`
constructors_callable.py:49:13: info[revealed-type] Revealed type: `(...) -> Unknown`
constructors_callable.py:50:1: error[type-assertion-failure] Argument does not have asserted type `Class2`
-constructors_callable.py:57:42: error[invalid-return-type] Function always implicitly returns `None`, which is not assignable to return type `Self`
+constructors_callable.py:57:42: error[invalid-return-type] Function always implicitly returns `None`, which is not assignable to return type `Self@Class3`
constructors_callable.py:63:13: info[revealed-type] Revealed type: `(...) -> Unknown`
constructors_callable.py:64:1: error[type-assertion-failure] Argument does not have asserted type `Class3`
constructors_callable.py:73:33: error[invalid-return-type] Function always implicitly returns `None`, which is not assignable to return type `int`
@@ -221,7 +221,7 @@
constructors_callable.py:193:13: info[revealed-type] Revealed type: `(...) -> Unknown`
constructors_callable.py:194:1: error[type-assertion-failure] Argument does not have asserted type `Class9`
dataclasses_descriptors.py:23:62: error[invalid-return-type] Function always implicitly returns `None`, which is not assignable to return type `int | Desc1`
-dataclasses_descriptors.py:50:63: error[invalid-return-type] Function always implicitly returns `None`, which is not assignable to return type `list[T] | T`
+dataclasses_descriptors.py:50:63: error[invalid-return-type] Function always implicitly returns `None`, which is not assignable to return type `list[T@Desc2] | T@Desc2`
dataclasses_descriptors.py:66:1: error[type-assertion-failure] Argument does not have asserted type `int`
dataclasses_descriptors.py:67:1: error[type-assertion-failure] Argument does not have asserted type `str`
dataclasses_final.py:27:1: error[invalid-assignment] Cannot assign to final attribute `final_classvar` on type `<class 'D'>`
@@ -270,7 +270,7 @@
dataclasses_transform_class.py:106:24: error[unknown-argument] Argument `id` does not match any known parameter of bound method `__init__`
dataclasses_transform_class.py:119:18: error[unknown-argument] Argument `id` does not match any known parameter of bound method `__init__`
dataclasses_transform_class.py:119:24: error[unknown-argument] Argument `name` does not match any known parameter of bound method `__init__`
-dataclasses_transform_converter.py:25:6: error[invalid-return-type] Function always implicitly returns `None`, which is not assignable to return type `T`
+dataclasses_transform_converter.py:25:6: error[invalid-return-type] Function always implicitly returns `None`, which is not assignable to return type `T@model_field`
dataclasses_transform_converter.py:48:31: error[invalid-argument-type] Argument to function `model_field` is incorrect: Expected `(Unknown, /) -> Unknown`, found `def bad_converter1() -> int`
dataclasses_transform_converter.py:49:31: error[invalid-argument-type] Argument to function `model_field` is incorrect: Expected `(Unknown, /) -> Unknown`, found `def bad_converter2(*, x: int) -> int`
dataclasses_transform_converter.py:107:5: error[too-many-positional-arguments] Too many positional arguments to bound method `__init__`: expected 1, got 6
@@ -287,7 +287,7 @@
dataclasses_transform_func.py:57:1: error[invalid-assignment] Object of type `Literal[3]` is not assignable to attribute `name` of type `str`
dataclasses_transform_func.py:61:6: error[unsupported-operator] Operator `<` is not supported for types `Customer1` and `Customer1`
dataclasses_transform_func.py:65:36: error[unknown-argument] Argument `salary` does not match any known parameter
-dataclasses_transform_func.py:77:36: error[invalid-return-type] Function always implicitly returns `None`, which is not assignable to return type `T`
+dataclasses_transform_func.py:77:36: error[invalid-return-type] Function always implicitly returns `None`, which is not assignable to return type `T@create_model_frozen`
dataclasses_transform_func.py:97:1: error[invalid-assignment] Property `id` defined in `Customer3` is read-only
dataclasses_transform_meta.py:60:36: error[unknown-argument] Argument `other_name` does not match any known parameter
dataclasses_transform_meta.py:73:6: error[unsupported-operator] Operator `<` is not supported for types `Customer1` and `Customer1`
@@ -365,7 +365,7 @@
generics_base_class.py:45:5: error[type-assertion-failure] Argument does not have asserted type `Iterator[int]`
generics_base_class.py:49:22: error[too-many-positional-arguments] Too many positional arguments to class `LinkedList`: expected 1, got 2
generics_base_class.py:61:18: error[too-many-positional-arguments] Too many positional arguments to class `MyDict`: expected 1, got 2
-generics_basic.py:34:12: error[unsupported-operator] Operator `+` is unsupported between objects of type `AnyStr` and `AnyStr`
+generics_basic.py:34:12: error[unsupported-operator] Operator `+` is unsupported between objects of type `AnyStr@concat` and `AnyStr@concat`
generics_basic.py:139:5: error[type-assertion-failure] Argument does not have asserted type `int`
generics_basic.py:140:5: error[type-assertion-failure] Argument does not have asserted type `int`
generics_basic.py:157:5: error[invalid-argument-type] Method `__getitem__` of type `bound method MyMap1[str, int].__getitem__(key: str, /) -> int` cannot be called with key of type `Literal[0]` on object of type `MyMap1[str, int]`
@@ -392,7 +392,7 @@
generics_defaults.py:91:26: error[invalid-argument-type] `@Todo` is not a valid argument to `Generic`
generics_defaults.py:94:1: error[type-assertion-failure] Argument does not have asserted type `@Todo`
generics_defaults.py:95:1: error[type-assertion-failure] Argument does not have asserted type `@Todo`
-generics_defaults.py:127:32: error[invalid-return-type] Function always implicitly returns `None`, which is not assignable to return type `T4`
+generics_defaults.py:127:32: error[invalid-return-type] Function always implicitly returns `None`, which is not assignable to return type `T4@func1`
generics_defaults.py:141:12: error[invalid-argument-type] `@Todo` is not a valid argument to `Generic`
generics_defaults.py:151:12: error[invalid-argument-type] `@Todo` is not a valid argument to `Generic`
generics_defaults.py:154:49: error[invalid-type-form] List literals are not allowed in this context in a type expression: Did you mean `tuple[int | float, bool]`?
@@ -441,64 +441,64 @@
generics_scoping.py:15:1: error[type-assertion-failure] Argument does not have asserted type `str`
generics_scoping.py:42:1: error[type-assertion-failure] Argument does not have asserted type `str`
generics_scoping.py:43:1: error[type-assertion-failure] Argument does not have asserted type `bytes`
-generics_self_advanced.py:11:24: error[invalid-return-type] Function always implicitly returns `None`, which is not assignable to return type `Self`
+generics_self_advanced.py:11:24: error[invalid-return-type] Function always implicitly returns `None`, which is not assignable to return type `Self@ParentA`
generics_self_advanced.py:18:1: error[type-assertion-failure] Argument does not have asserted type `ParentA`
generics_self_advanced.py:19:1: error[type-assertion-failure] Argument does not have asserted type `ChildA`
-generics_self_advanced.py:28:25: error[invalid-return-type] Function always implicitly returns `None`, which is not assignable to return type `Self`
-generics_self_advanced.py:35:9: error[type-assertion-failure] Argument does not have asserted type `Self`
-generics_self_advanced.py:36:9: error[type-assertion-failure] Argument does not have asserted type `list[Self]`
-generics_self_advanced.py:37:9: error[type-assertion-failure] Argument does not have asserted type `Self`
-generics_self_advanced.py:38:9: error[type-assertion-failure] Argument does not have asserted type `Self`
-generics_self_advanced.py:43:9: error[type-assertion-failure] Argument does not have asserted type `list[Self]`
-generics_self_advanced.py:44:9: error[type-assertion-failure] Argument does not have asserted type `Self`
-generics_self_advanced.py:45:9: error[type-assertion-failure] Argument does not have asserted type `Self`
-generics_self_attributes.py:26:33: error[invalid-argument-type] Argument is incorrect: Expected `Self | None`, found `LinkedList[int]`
-generics_self_attributes.py:29:5: error[invalid-assignment] Object of type `OrdinalLinkedList` is not assignable to attribute `next` of type `Self | None`
-generics_self_attributes.py:32:5: error[invalid-assignment] Object of type `LinkedList[int]` is not assignable to attribute `next` of type `Self | None`
-generics_self_basic.py:14:9: error[type-assertion-failure] Argument does not have asserted type `Self`
-generics_self_basic.py:20:16: error[invalid-return-type] Return type does not match returned value: expected `Self`, found `Shape`
-generics_self_basic.py:33:16: error[invalid-return-type] Return type does not match returned value: expected `Self`, found `Shape`
+generics_self_advanced.py:28:25: error[invalid-return-type] Function always implicitly returns `None`, which is not assignable to return type `Self@ParentB`
+generics_self_advanced.py:35:9: error[type-assertion-failure] Argument does not have asserted type `Self@ChildB`
+generics_self_advanced.py:36:9: error[type-assertion-failure] Argument does not have asserted type `list[Self@ChildB]`
+generics_self_advanced.py:37:9: error[type-assertion-failure] Argument does not have asserted type `Self@ChildB`
+generics_self_advanced.py:38:9: error[type-assertion-failure] Argument does not have asserted type `Self@ChildB`
+generics_self_advanced.py:43:9: error[type-assertion-failure] Argument does not have asserted type `list[Self@ChildB]`
+generics_self_advanced.py:44:9: error[type-assertion-failure] Argument does not have asserted type `Self@ChildB`
+generics_self_advanced.py:45:9: error[type-assertion-failure] Argument does not have asserted type `Self@ChildB`
+generics_self_attributes.py:26:33: error[invalid-argument-type] Argument is incorrect: Expected `Self@LinkedList | None`, found `LinkedList[int]`
+generics_self_attributes.py:29:5: error[invalid-assignment] Object of type `OrdinalLinkedList` is not assignable to attribute `next` of type `Self@LinkedList | None`
+generics_self_attributes.py:32:5: error[invalid-assignment] Object of type `LinkedList[int]` is not assignable to attribute `next` of type `Self@LinkedList | None`
+generics_self_basic.py:14:9: error[type-assertion-failure] Argument does not have asserted type `Self@Shape`
+generics_self_basic.py:20:16: error[invalid-return-type] Return type does not match returned value: expected `Self@Shape`, found `Shape`
+generics_self_basic.py:33:16: error[invalid-return-type] Return type does not match returned value: expected `Self@Shape`, found `Shape`
generics_self_basic.py:51:1: error[type-assertion-failure] Argument does not have asserted type `Shape`
generics_self_basic.py:52:1: error[type-assertion-failure] Argument does not have asserted type `Circle`
generics_self_basic.py:54:1: error[type-assertion-failure] Argument does not have asserted type `Shape`
generics_self_basic.py:55:1: error[type-assertion-failure] Argument does not have asserted type `Circle`
-generics_self_basic.py:64:38: error[invalid-return-type] Function always implicitly returns `None`, which is not assignable to return type `Self`
+generics_self_basic.py:64:38: error[invalid-return-type] Function always implicitly returns `None`, which is not assignable to return type `Self@Container`
generics_self_basic.py:67:26: error[invalid-type-form] Special form `typing.Self` expected no type parameter
generics_self_basic.py:74:5: error[type-assertion-failure] Argument does not have asserted type `Container[int]`
generics_self_basic.py:75:5: error[type-assertion-failure] Argument does not have asserted type `Container[str]`
-generics_self_basic.py:83:5: error[type-assertion-failure] Argument does not have asserted type `Container[T]`
+generics_self_basic.py:83:5: error[type-assertion-failure] Argument does not have asserted type `Container[T@object_with_generic_type]`
generics_self_protocols.py:48:5: error[type-assertion-failure] Argument does not have asserted type `ShapeProtocol`
generics_self_usage.py:73:14: error[invalid-type-form] Variable of type `typing.Self` is not allowed in a type expression
generics_self_usage.py:73:23: error[invalid-type-form] Variable of type `typing.Self` is not allowed in a type expression
generics_self_usage.py:76:6: error[invalid-type-form] Variable of type `typing.Self` is not allowed in a type expression
-generics_self_usage.py:82:54: error[invalid-return-type] Function always implicitly returns `None`, which is not assignable to return type `Self`
-generics_self_usage.py:86:16: error[invalid-return-type] Return type does not match returned value: expected `Self`, found `Foo3`
-generics_self_usage.py:98:22: error[invalid-return-type] Function always implicitly returns `None`, which is not assignable to return type `T`
+generics_self_usage.py:82:54: error[invalid-return-type] Function always implicitly returns `None`, which is not assignable to return type `Self@Foo2`
+generics_self_usage.py:86:16: error[invalid-return-type] Return type does not match returned value: expected `Self@Foo3`, found `Foo3`
+generics_self_usage.py:98:22: error[invalid-return-type] Function always implicitly returns `None`, which is not assignable to return type `T@Bar`
generics_self_usage.py:101:15: error[invalid-type-form] Variable of type `typing.Self` is not allowed in a type expression
generics_self_usage.py:103:12: error[invalid-base] Invalid class base with type `typing.Self`
generics_self_usage.py:106:30: error[invalid-type-form] Variable of type `typing.Self` is not allowed in a type expression
-generics_self_usage.py:111:19: error[invalid-return-type] Function always implicitly returns `None`, which is not assignable to return type `Self`
-generics_self_usage.py:116:40: error[invalid-return-type] Function always implicitly returns `None`, which is not assignable to return type `Self`
-generics_self_usage.py:121:37: error[invalid-return-type] Function always implicitly returns `None`, which is not assignable to return type `Self`
-generics_self_usage.py:125:37: error[invalid-return-type] Function always implicitly returns `None`, which is not assignable to return type `list[Self]`
-generics_syntax_compatibility.py:23:38: error[invalid-return-type] Function always implicitly returns `None`, which is not assignable to return type `V | K`
-generics_syntax_compatibility.py:26:41: error[invalid-return-type] Function always implicitly returns `None`, which is not assignable to return type `M | K`
+generics_self_usage.py:111:19: error[invalid-return-type] Function always implicitly returns `None`, which is not assignable to return type `Self@Base`
+generics_self_usage.py:116:40: error[invalid-return-type] Function always implicitly returns `None`, which is not assignable to return type `Self@Base`
+generics_self_usage.py:121:37: error[invalid-return-type] Function always implicitly returns `None`, which is not assignable to return type `Self@MyMetaclass`
+generics_self_usage.py:125:37: error[invalid-return-type] Function always implicitly returns `None`, which is not assignable to return type `list[Self@MyMetaclass]`
+generics_syntax_compatibility.py:23:38: error[invalid-return-type] Function always implicitly returns `None`, which is not assignable to return type `V@ClassC | K@method1`
+generics_syntax_compatibility.py:26:41: error[invalid-return-type] Function always implicitly returns `None`, which is not assignable to return type `M@method2 | K`
generics_syntax_declarations.py:17:1: error[invalid-generic-class] Cannot both inherit from `typing.Generic` and use PEP 695 type variables
generics_syntax_declarations.py:25:20: error[invalid-generic-class] Cannot both inherit from subscripted `Protocol` and use PEP 695 type variables
-generics_syntax_declarations.py:32:9: error[unresolved-attribute] Type `T` has no attribute `is_integer`
+generics_syntax_declarations.py:32:9: error[unresolved-attribute] Type `T@ClassD` has no attribute `is_integer`
generics_syntax_declarations.py:48:17: error[invalid-type-form] List literals are not allowed in this context in a type expression: Did you mean `tuple[str, int]`?
generics_syntax_declarations.py:60:17: error[invalid-type-variable-constraints] TypeVar must have at least two constrained types
generics_syntax_declarations.py:64:17: error[invalid-type-variable-constraints] TypeVar must have at least two constrained types
generics_syntax_declarations.py:71:17: error[invalid-type-form] Variable of type `tuple[<class 'bytes'>, <class 'str'>]` is not allowed in a type expression
generics_syntax_declarations.py:75:18: error[invalid-type-form] Int literals are not allowed in this context in a type expression
generics_syntax_declarations.py:79:23: error[unresolved-reference] Name `S` used when not defined
-generics_syntax_infer_variance.py:21:42: error[invalid-return-type] Function always implicitly returns `None`, which is not assignable to return type `T`
-generics_syntax_infer_variance.py:24:27: error[invalid-return-type] Function always implicitly returns `None`, which is not assignable to return type `Iterator[T]`
+generics_syntax_infer_variance.py:21:42: error[invalid-return-type] Function always implicitly returns `None`, which is not assignable to return type `T@ShouldBeCovariant1`
+generics_syntax_infer_variance.py:24:27: error[invalid-return-type] Function always implicitly returns `None`, which is not assignable to return type `Iterator[T@ShouldBeCovariant1]`
generics_syntax_infer_variance.py:28:1: error[invalid-assignment] Object of type `ShouldBeCovariant1[int]` is not assignable to `ShouldBeCovariant1[int | float]`
generics_syntax_infer_variance.py:29:1: error[invalid-assignment] Object of type `ShouldBeCovariant1[int | float]` is not assignable to `ShouldBeCovariant1[int]`
generics_syntax_infer_variance.py:36:1: error[invalid-assignment] Object of type `ShouldBeCovariant2[int]` is not assignable to `ShouldBeCovariant2[int | float]`
generics_syntax_infer_variance.py:37:1: error[invalid-assignment] Object of type `ShouldBeCovariant2[int | float]` is not assignable to `ShouldBeCovariant2[int]`
-generics_syntax_infer_variance.py:41:26: error[invalid-return-type] Function always implicitly returns `None`, which is not assignable to return type `ShouldBeCovariant2[T]`
+generics_syntax_infer_variance.py:41:26: error[invalid-return-type] Function always implicitly returns `None`, which is not assignable to return type `ShouldBeCovariant2[T@ShouldBeCovariant3]`
generics_syntax_infer_variance.py:45:1: error[invalid-assignment] Object of type `ShouldBeCovariant3[int]` is not assignable to `ShouldBeCovariant3[int | float]`
generics_syntax_infer_variance.py:46:1: error[invalid-assignment] Object of type `ShouldBeCovariant3[int | float]` is not assignable to `ShouldBeCovariant3[int]`
generics_syntax_infer_variance.py:74:1: error[invalid-assignment] Object of type `ShouldBeCovariant5[int]` is not assignable to `ShouldBeCovariant5[int | float]`
@@ -519,9 +519,9 @@
generics_syntax_infer_variance.py:156:1: error[invalid-assignment] Object of type `ShouldBeContravariant1[int | float]` is not assignable to `ShouldBeContravariant1[int]`
generics_syntax_scoping.py:18:26: error[unresolved-reference] Name `T` used when not defined
generics_syntax_scoping.py:35:7: error[unresolved-reference] Name `T` used when not defined
-generics_syntax_scoping.py:40:23: error[invalid-return-type] Function always implicitly returns `None`, which is not assignable to return type `((...) -> R, /) -> (...) -> R`
+generics_syntax_scoping.py:40:23: error[invalid-return-type] Function always implicitly returns `None`, which is not assignable to return type `((...) -> R@decorator1, /) -> (...) -> R@decorator1`
generics_syntax_scoping.py:44:17: error[unresolved-reference] Name `T` used when not defined
-generics_syntax_scoping.py:81:35: error[invalid-return-type] Function always implicitly returns `None`, which is not assignable to return type `((...) -> R, /) -> (...) -> R`
+generics_syntax_scoping.py:81:35: error[invalid-return-type] Function always implicitly returns `None`, which is not assignable to return type `((...) -> R@decorator2, /) -> (...) -> R@decorator2`
generics_syntax_scoping.py:113:9: error[type-assertion-failure] Argument does not have asserted type `str`
generics_syntax_scoping.py:116:13: error[type-assertion-failure] Argument does not have asserted type `TypeVar`
generics_syntax_scoping.py:121:9: error[type-assertion-failure] Argument does not have asserted type `int | float | complex`
@@ -564,11 +564,11 @@
generics_typevartuple_specialization.py:93:5: error[type-assertion-failure] Argument does not have asserted type `tuple[str, int]`
generics_typevartuple_specialization.py:94:5: error[type-assertion-failure] Argument does not have asserted type `tuple[int | float]`
generics_typevartuple_specialization.py:95:5: error[type-assertion-failure] Argument does not have asserted type `tuple[Any, *tuple[Any, ...]]`
-generics_typevartuple_specialization.py:130:35: error[invalid-return-type] Function always implicitly returns `None`, which is not assignable to return type `tuple[@Todo, T1, T2]`
+generics_typevartuple_specialization.py:130:35: error[invalid-return-type] Function always implicitly returns `None`, which is not assignable to return type `tuple[@Todo, T1@func7, T2@func7]`
generics_typevartuple_specialization.py:135:5: error[type-assertion-failure] Argument does not have asserted type `tuple[tuple[()], str, bool]`
generics_typevartuple_specialization.py:136:5: error[type-assertion-failure] Argument does not have asserted type `tuple[tuple[str], bool, int | float]`
generics_typevartuple_specialization.py:137:5: error[type-assertion-failure] Argument does not have asserted type `tuple[tuple[str, bool], int | float, int]`
-generics_typevartuple_specialization.py:143:39: error[invalid-return-type] Function always implicitly returns `None`, which is not assignable to return type `tuple[@Todo, T1, T2, T3]`
+generics_typevartuple_specialization.py:143:39: error[invalid-return-type] Function always implicitly returns `None`, which is not assignable to return type `tuple[@Todo, T1@func9, T2@func9, T3@func9]`
generics_typevartuple_specialization.py:148:5: error[type-assertion-failure] Argument does not have asserted type `tuple[tuple[()], str, bool, int | float]`
generics_typevartuple_specialization.py:149:5: error[type-assertion-failure] Argument does not have asserted type `tuple[tuple[bool], str, int | float, int]`
generics_typevartuple_specialization.py:157:5: error[type-assertion-failure] Argument does not have asserted type `tuple[*tuple[int, ...], int]`
@@ -581,8 +581,8 @@
generics_upper_bound.py:51:8: error[invalid-argument-type] Argument to function `longer` is incorrect: Argument type `Literal[3]` does not satisfy upper bound of type variable `ST`
generics_upper_bound.py:51:11: error[invalid-argument-type] Argument to function `longer` is incorrect: Argument type `Literal[3]` does not satisfy upper bound of type variable `ST`
generics_variance.py:14:6: error[invalid-legacy-type-variable] A legacy `typing.TypeVar` cannot be both covariant and contravariant
-generics_variance.py:26:27: error[invalid-return-type] Function always implicitly returns `None`, which is not assignable to return type `Iterator[T_co]`
-generics_variance.py:57:28: error[invalid-return-type] Function always implicitly returns `None`, which is not assignable to return type `B_co`
+generics_variance.py:26:27: error[invalid-return-type] Function always implicitly returns `None`, which is not assignable to return type `Iterator[T_co@ImmutableList]`
+generics_variance.py:57:28: error[invalid-return-type] Function always implicitly returns `None`, which is not assignable to return type `B_co@func`
generics_variance.py:175:25: error[non-subscriptable] Cannot subscript object of type `<class 'Contra[T_contra]'>` with no `__class_getitem__` method
generics_variance.py:175:35: error[non-subscriptable] Cannot subscript object of type `<class 'Co[T_co]'>` with no `__class_getitem__` method
generics_variance.py:179:29: error[non-subscriptable] Cannot subscript object of type `<class 'Contra[T_contra]'>` with no `__class_getitem__` method
@@ -597,19 +597,19 @@
generics_variance.py:196:5: error[non-subscriptable] Cannot subscript object of type `<class 'Contra[T_contra]'>` with no `__class_getitem__` method
generics_variance.py:196:15: error[non-subscriptable] Cannot subscript object of type `<class 'Contra[T_contra]'>` with no `__class_getitem__` method
generics_variance.py:196:25: error[non-subscriptable] Cannot subscript object of type `<class 'Contra[T_contra]'>` with no `__class_getitem__` method
-generics_variance_inference.py:19:26: error[invalid-return-type] Function always implicitly returns `None`, which is not assignable to return type `T3`
+generics_variance_inference.py:19:26: error[invalid-return-type] Function always implicitly returns `None`, which is not assignable to return type `T3@ClassA`
generics_variance_inference.py:24:5: error[invalid-assignment] Object of type `ClassA[int | float, int, int]` is not assignable to `ClassA[int, int, int]`
generics_variance_inference.py:25:5: error[invalid-assignment] Object of type `ClassA[int | float, int, int]` is not assignable to `ClassA[int | float, int | float, int]`
generics_variance_inference.py:26:5: error[invalid-assignment] Object of type `ClassA[int | float, int, int]` is not assignable to `ClassA[int | float, int, int | float]`
generics_variance_inference.py:28:5: error[invalid-assignment] Object of type `ClassA[int, int | float, int | float]` is not assignable to `ClassA[int, int, int]`
generics_variance_inference.py:29:5: error[invalid-assignment] Object of type `ClassA[int, int | float, int | float]` is not assignable to `ClassA[int, int, int | float]`
-generics_variance_inference.py:33:42: error[invalid-return-type] Function always implicitly returns `None`, which is not assignable to return type `T`
-generics_variance_inference.py:36:27: error[invalid-return-type] Function always implicitly returns `None`, which is not assignable to return type `Iterator[T]`
+generics_variance_inference.py:33:42: error[invalid-return-type] Function always implicitly returns `None`, which is not assignable to return type `T@ShouldBeCovariant1`
+generics_variance_inference.py:36:27: error[invalid-return-type] Function always implicitly returns `None`, which is not assignable to return type `Iterator[T@ShouldBeCovariant1]`
generics_variance_inference.py:40:1: error[invalid-assignment] Object of type `ShouldBeCovariant1[int]` is not assignable to `ShouldBeCovariant1[int | float]`
generics_variance_inference.py:41:1: error[invalid-assignment] Object of type `ShouldBeCovariant1[int | float]` is not assignable to `ShouldBeCovariant1[int]`
generics_variance_inference.py:48:1: error[invalid-assignment] Object of type `ShouldBeCovariant2[int]` is not assignable to `ShouldBeCovariant2[int | float]`
generics_variance_inference.py:49:1: error[invalid-assignment] Object of type `ShouldBeCovariant2[int | float]` is not assignable to `ShouldBeCovariant2[int]`
-generics_variance_inference.py:53:26: error[invalid-return-type] Function always implicitly returns `None`, which is not assignable to return type `ShouldBeCovariant2[T]`
+generics_variance_inference.py:53:26: error[invalid-return-type] Function always implicitly returns `None`, which is not assignable to return type `ShouldBeCovariant2[T@ShouldBeCovariant3]`
generics_variance_inference.py:57:1: error[invalid-assignment] Object of type `ShouldBeCovariant3[int]` is not assignable to `ShouldBeCovariant3[int | float]`
generics_variance_inference.py:58:1: error[invalid-assignment] Object of type `ShouldBeCovariant3[int | float]` is not assignable to `ShouldBeCovariant3[int]`
generics_variance_inference.py:66:1: error[invalid-assignment] Object of type `ShouldBeCovariant4[int]` is not assignable to `ShouldBeCovariant4[int | float]`
@@ -638,9 +638,9 @@
literals_interactions.py:16:5: error[index-out-of-bounds] Index -5 is out of bounds for tuple `tuple[int, str, list[bool]]` with length 3
literals_interactions.py:17:5: error[index-out-of-bounds] Index 4 is out of bounds for tuple `tuple[int, str, list[bool]]` with length 3
literals_interactions.py:18:5: error[index-out-of-bounds] Index -4 is out of bounds for tuple `tuple[int, str, list[bool]]` with length 3
-literals_interactions.py:60:49: error[invalid-return-type] Function always implicitly returns `None`, which is not assignable to return type `Matrix[A, B]`
-literals_interactions.py:63:52: error[invalid-return-type] Function always implicitly returns `None`, which is not assignable to return type `Matrix[A, C]`
-literals_interactions.py:66:28: error[invalid-return-type] Function always implicitly returns `None`, which is not assignable to return type `Matrix[B, A]`
+literals_interactions.py:60:49: error[invalid-return-type] Function always implicitly returns `None`, which is not assignable to return type `Matrix[A@Matrix, B@Matrix]`
+literals_interactions.py:63:52: error[invalid-return-type] Function always implicitly returns `None`, which is not assignable to return type `Matrix[A@Matrix, C@__matmul__]`
+literals_interactions.py:66:28: error[invalid-return-type] Function always implicitly returns `None`, which is not assignable to return type `Matrix[B@Matrix, A@Matrix]`
literals_interactions.py:106:35: error[invalid-argument-type] Argument to function `expects_bad_status` is incorrect: Expected `Literal["MALFORMED", "ABORTED"]`, found `str`
literals_interactions.py:109:32: error[invalid-argument-type] Argument to function `expects_pending_status` is incorrect: Expected `Literal["PENDING"]`, found `str`
literals_literalstring.py:23:51: error[invalid-return-type] Function always implicitly returns `None`, which is not assignable to return type `LiteralString`
@@ -758,7 +758,7 @@
overloads_evaluation.py:115:5: error[no-matching-overload] No overload of function `example2` matches arguments
overloads_evaluation.py:161:5: error[type-assertion-failure] Argument does not have asserted type `Literal[0, 1]`
overloads_evaluation.py:234:5: error[type-assertion-failure] Argument does not have asserted type `int`
-overloads_evaluation.py:291:33: error[invalid-return-type] Function always implicitly returns `None`, which is not assignable to return type `T`
+overloads_evaluation.py:291:33: error[invalid-return-type] Function always implicitly returns `None`, which is not assignable to return type `T@example6`
overloads_evaluation.py:322:5: error[type-assertion-failure] Argument does not have asserted type `list[int]`
protocols_class_objects.py:30:5: error[invalid-argument-type] Argument to function `fun` is incorrect: Expected `type[Proto]`, found `<class 'Concrete'>`
protocols_class_objects.py:35:1: error[invalid-assignment] Object of type `<class 'Concrete'>` is not assignable to `type[Proto]`
@@ -781,14 +781,14 @@
protocols_modules.py:47:1: error[invalid-assignment] Object of type `<module '_protocols_modules2'>` is not assignable to `Reporter1`
protocols_modules.py:48:1: error[invalid-assignment] Object of type `<module '_protocols_modules2'>` is not assignable to `Reporter2`
protocols_modules.py:49:1: error[invalid-assignment] Object of type `<module '_protocols_modules2'>` is not assignable to `Reporter3`
-protocols_recursive.py:76:35: error[invalid-return-type] Function always implicitly returns `None`, which is not assignable to return type `T`
+protocols_recursive.py:76:35: error[invalid-return-type] Function always implicitly returns `None`, which is not assignable to return type `T@func1`
protocols_recursive.py:81:1: error[type-assertion-failure] Argument does not have asserted type `list[int]`
protocols_runtime_checkable.py:23:8: error[invalid-argument-type] Class `Proto1` cannot be used as the second argument to `isinstance`: This call will raise `TypeError` at runtime
protocols_subtyping.py:16:6: error[call-non-callable] Cannot instantiate class `Proto1`: This call will raise `TypeError` at runtime
protocols_subtyping.py:38:5: error[invalid-assignment] Object of type `Proto2` is not assignable to `Concrete2`
protocols_subtyping.py:55:5: error[invalid-assignment] Object of type `Proto2` is not assignable to `Proto3`
protocols_variance.py:84:16: error[invalid-argument-type] `ParamSpec` is not a valid argument to `Protocol`
-protocols_variance.py:85:62: error[invalid-return-type] Function always implicitly returns `None`, which is not assignable to return type `R`
+protocols_variance.py:85:62: error[invalid-return-type] Function always implicitly returns `None`, which is not assignable to return type `R@__call__`
qualifiers_annotated.py:43:17: error[invalid-type-form] List literals are not allowed in this context in a type expression: Did you mean `tuple[int, str]`?
qualifiers_annotated.py:44:17: error[invalid-type-form] Tuple literals are not allowed in this context in a type expression
qualifiers_annotated.py:44:18: error[invalid-type-form] Tuple literals are not allowed in this context in a type expression: Did you mean `tuple[int, str]`?
@@ -822,7 +822,7 @@
specialtypes_never.py:19:22: error[invalid-return-type] Function always implicitly returns `None`, which is not assignable to return type `Never`
specialtypes_never.py:32:12: error[invalid-return-type] Return type does not match returned value: expected `int`, found `Literal["whatever works"]`
specialtypes_never.py:86:5: error[invalid-assignment] Object of type `list[Never]` is not assignable to `list[int]`
-specialtypes_never.py:105:12: error[invalid-return-type] Return type does not match returned value: expected `ClassC[U]`, found `ClassC[Never]`
+specialtypes_never.py:105:12: error[invalid-return-type] Return type does not match returned value: expected `ClassC[U@func10]`, found `ClassC[Never]`
specialtypes_none.py:21:7: error[invalid-argument-type] Argument to function `func1` is incorrect: Expected `None`, found `<class 'NoneType'>`
specialtypes_none.py:27:1: error[invalid-assignment] Object of type `None` is not assignable to `Iterable[Unknown]`
specialtypes_none.py:32:1: error[missing-argument] No argument provided for required parameter `value` of function `__eq__` |
|
CodSpeed Instrumentation Performance ReportMerging #19604 will degrade performances by 8.27%Comparing Summary
Benchmarks breakdown
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I lack a bit of context on this change but I skimmed over the changes. I'm a bit concerned about the perf and memory regression (surprise surprise) this introduces but maybe this is just a bullet we need to take?
Can you provide some more context on the motivation for:
With that in place, we can now include the name of the binding context when rendering typevars (e.g. T@f instead of T)
I find the notation a bit confusing. E.g. I find it a bit strange to see it in completions. Is this essential information for users? What's the motivation for always showing it? Do you know what other type checkers do here? Feel free to ignore this part if it's obvious to everyone else working on ty's typing and it's just me being out of the loop
| /// The type var's definition (None if synthesized) | ||
| pub definition: Option<Definition<'db>>, | ||
|
|
||
| /// The definition of the generic class, function, or type alias that binds this typevar. This |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It took me a while to understand the difference between definition and binding_context. I think it could help to add an example and add some comment explaining the difference between the two.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done
|
|
||
| /// The definition of the generic class, function, or type alias that binds this typevar. This | ||
| /// is `None` for a legacy typevar outside of a context that can bind it. | ||
| binding_context: Option<Definition<'db>>, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm not very familiar with the design, and I haven't looked through all usages, so I don't feel like I've a good sense to judge whether it makes the most sense to have the binding_context here or not.
I'm also just speculating here. I haven't checked whether the number of TypeVarInstances is significantly increasing, and if that is the main cause of the perf regression.
Do you think that this new field leads to significantly less reuse of TypeVarInstances, meaning, it leads to many more interned salsa struct (which requires storing an extra name and the overhead of salsa tracking).
Would it make sense to split the struct into a TypeVarInstance and a BoundTypeVarInstance
TypeVarInstance: The same as before this PR?BoundTypeVarInstance: A regular Rust struct that wraps theTypeVarInstanceand has the extrabinding_contextfield.
I'm sure that this isn't possible because of some size constraints that we have but I thought it's worth considering as an alternative design
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Would it make sense to split the struct into a
TypeVarInstanceand aBoundTypeVarInstance
I can give that a quick try to see if that helps
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Okay this "try" has not really been "quick", but I'm willing to say that this won't work, at least without fairly invasive changes. The sticking point wasn't size constraints, but instead that we would need separate Type variants for TypeVarInstance and BoundTypeVarInstance. There genuinely are places where we need to refer to a legacy typevar that has not yet been bound — in particular, in typevar defaults:
T = TypeVar("T")
U = TypeVar("U", default=T)That reference to T is not yet bound in a generic context, and in fact needs to be rebound so that the default of U@C is T@C in the following:
class C(Generic[T, U]): ...All in all, I don't see this being tenable, at least in the current PR. (To make this work, we would need the separate types you suggest, and also a separate Type variant for each.)
Regarding the performance regression,
Do you think that this new field leads to significantly less reuse of TypeVarInstances, meaning, it leads to many more interned salsa struct (which requires storing an extra name and the overhead of salsa tracking).
Yes, that's right, and especially since the typeshed makes heavy use of legacy typevars. The MRO of list[int], for instance, contains all of the following:
list[_T = int]
MutableSequence[_T = int]
Sequence[_T_co = int]
Reversible[_T_co = int]
Collection[_T_co = int]
Iterable[_T_co = int]
Container[_T_co = int]
Before, that was two TypeVarInstances, one for _T and one for _T_co. Now its nine: the two unbound ones that are created when _T and _T_co are instantiated, and one for each class that uses the typevar in its generic context.
Given that factoring out the binding is untenable (at least in this PR), I think we have to accept the performance regression.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for looking into this. Would you mind opening an issue that documents this problem as a future performance optimisation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
|
| Lint rule | Added | Removed | Changed |
|---|---|---|---|
unresolved-attribute |
0 | 0 | 2,893 |
invalid-argument-type |
113 | 4 | 1,376 |
possibly-unbound-attribute |
0 | 0 | 512 |
invalid-return-type |
40 | 0 | 242 |
invalid-assignment |
2 | 3 | 42 |
invalid-parameter-default |
1 | 0 | 8 |
call-non-callable |
2 | 0 | 6 |
no-matching-overload |
0 | 7 | 0 |
invalid-super-argument |
0 | 0 | 6 |
type-assertion-failure |
6 | 0 | 0 |
unsupported-operator |
0 | 0 | 6 |
inconsistent-mro |
0 | 0 | 3 |
redundant-cast |
0 | 0 | 3 |
non-subscriptable |
0 | 0 | 1 |
unused-ignore-comment |
0 | 1 | 0 |
| Total | 164 | 15 | 5,098 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Very nice — thank you!
Did you look at the added diagnostics here? There are some new diagnostics like "Argument is incorrect: Expected _TSource@choose, found _TSource@mapper" or "Argument to bound method __init__ is incorrect: Expected _T_io@redirect_stdout, found None", which look concerning?
@MichaReiser this is the same notation that pyright uses (in its display to users) to disambiguate the scope to which a legacy TypeVar is bound. Mypy increments an identifier instead ( You can see their different displays here: |
* main: (24 commits) Add `Checker::context` method, deduplicate Unicode checks (#19609) [`flake8-pyi`] Preserve inline comment in ellipsis removal (`PYI013`) (#19399) [ty] Add flow diagram for import resolution [ty] Add comments to some core resolver functions [ty] Add missing ticks and use consistent quoting [ty] Reflow some long lines [ty] Unexport helper function [ty] Remove offset from `CompletionTargetTokens::Unknown` [`pyupgrade`] Fix `UP030` to avoid modifying double curly braces in format strings (#19378) [ty] fix a typo (#19621) [ty] synthesize `__replace__` for dataclasses (>=3.13) (#19545) [ty] Discard `Definition`s when normalizing `Signature`s (#19615) [ty] Fix empty spans following a line terminator and unprintable character spans in diagnostics (#19535) Add `LinterContext::settings` to avoid passing separate settings (#19608) Support `.pyi` files in ruff analyze graph (#19611) [ty] Sync vendored typeshed stubs (#19607) [ty] Bump docstring-adder pin (#19606) [`perflint`] Ignore rule if target is `global` or `nonlocal` (`PERF401`) (#19539) Add license classifier back to pyproject.toml (#19599) [ty] Add stub mapping support to signature help (#19570) ...
|
Dug into the new ecosystem diagnostics, and they have one of two causes:
This is due to the
This example is now hitting astral-sh/ty#588, since we're now trying to instantiate a class |
And for this, it's not that decorators in general are a problem — it works fine when I use a simpler decorator like def nothing[F](f: F) -> F:
return fThe issue is that the |
* main: (39 commits) [ty] Initial test suite for `TypedDict` (#19686) [ty] Improve debuggability of protocol types (#19662) [ty] Simplify lifetime requirements for `PySlice` trait (#19687) [ty] Improve `isinstance()` truthiness analysis for generic types (#19668) [`refurb`] Make example error out-of-the-box (`FURB164`) (#19673) Fix link: unused_import.rs (#19648) [ty] Remove `Specialization::display` (full) (#19682) [ty] Remove `KnownModule::is_enum` (#19681) [ty] Support `__setitem__` and improve `__getitem__` related diagnostics (#19578) [ty] Sync vendored typeshed stubs (#19676) [`flake8-use-pathlib`] Expand `PTH201` to check all `PurePath` subclasses (#19440) [`refurb`] Make example error out-of-the-box (`FURB180`) (#19672) [`pyupgrade`] Prevent infinite loop with `I002` (`UP010`, `UP035`) (#19413) [ty] Improve the `Display` for generic `type[]` types (#19667) [ty] Refactor `TypeInferenceBuilder::infer_subscript_expression_types` (#19658) Fix tests on 32-bit architectures (#19652) [ty] Move `pandas-stubs` to bad.txt (#19659) [ty] Remove special casing for string-literal-in-tuple `__contains__` (#19642) Update pre-commit's `ruff` id (#19654) Update salsa (#19449) ...
…m generic base class (#19693) This is subtle, and the root cause became more apparent with #19604, since we now have many more cases of superclasses and subclasses using different typevars. The issue is easiest to see in the following: ```py class C[T]: def __init__(self, t: T) -> None: ... class D[U](C[T]): pass reveal_type(C(1)) # revealed: C[int] reveal_type(D(1)) # should be: D[int] ``` When instantiating a generic class, the `__init__` method inherits the generic context of that class. This lets our call binding machinery infer a specialization for that context. Prior to this PR, the instantiation of `C` worked just fine. Its `__init__` method would inherit the `[T]` generic context, and we would infer `{T = int}` as the specialization based on the argument parameters. It didn't work for `D`. The issue is that the `__init__` method was inheriting the generic context of the class where `__init__` was defined (here, `C` and `[T]`). At the call site, we would then infer `{T = int}` as the specialization — but that wouldn't help us specialize `D[U]`, since `D` does not have `T` in its generic context! Instead, the `__init__` method should inherit the generic context of the class that we are performing the lookup on (here, `D` and `[U]`). That lets us correctly infer `{U = int}` as the specialization, which we can successfully apply to `D[U]`. (Note that `__init__` refers to `C`'s typevars in its signature, but that's okay; our member lookup logic already applies the `T = U` specialization when returning a member of `C` while performing a lookup on `D`, transforming its signature from `(Self, T) -> None` to `(Self, U) -> None`.) Closes astral-sh/ty#588
This PR introduces a few related changes:
We now keep track of each time a legacy typevar is bound in a different generic context (e.g. class, function), and internally create a new
TypeVarInstancefor each usage. This means the rest of the code can now assume that salsa-equivalentTypeVarInstances refer to the same typevar, even taking into account that legacy typevars can be used more than once.We also go ahead and track the binding context of PEP 695 typevars. That's much easier to track since we have the binding context right there during type inference.
With that in place, we can now include the name of the binding context when rendering typevars (e.g.
T@finstead ofT)