Skip to content

Conversation

carljm
Copy link
Contributor

@carljm carljm commented Aug 13, 2025

Summary

For PEP 695 generic functions and classes, there is an extra "type params scope" (a child of the outer scope, and wrapping the body scope) in which the type parameters are defined; class bases and function parameter/return annotations are resolved in that type-params scope.

This PR fixes some longstanding bugs in how we resolve name loads from inside these PEP 695 type parameter scopes, and also defers type inference of PEP 695 typevar bounds/constraints/default, so we can handle cycles without panicking.

We were previously treating these type-param scopes as lazy nested scopes, which is wrong. In fact they are eager nested scopes; the class C here inherits int, not str, and previously we got that wrong:

Base = int

class C[T](Base): ...

Base = str

But certain syntactic positions within type param scopes (typevar bounds/constraints/defaults) are lazy at runtime, and we should use deferred name resolution for them. This also means they can have cycles; in order to handle that without panicking in type inference, we need to actually defer their type inference until after we have constructed the TypeVarInstance.

PEP 695 does specify that typevar bounds and constraints cannot be generic, and that typevar defaults can only reference prior typevars, not later ones. This reduces the scope of (valid from the type-system perspective) cycles somewhat, although cycles are still possible (e.g. class C[T: list[C]]). And this is a type-system-only restriction; from the runtime perspective an "invalid" case like class C[T: T] actually works fine.

I debated whether to implement the PEP 695 restrictions as a way to avoid some cycles up-front, but I ended up deciding against that; I'd rather model the runtime name-resolution semantics accurately, and implement the PEP 695 restrictions as a separate diagnostic on top. (This PR doesn't yet implement those diagnostics, thus some # TODO: error in the added tests.)

Introducing the possibility of cyclic typevars made typevar display potentially stack overflow. For now I've handled this by simply removing typevar details (bounds/constraints/default) from typevar display. This impacts display of two kinds of types. If you reveal_type(T) on an unbound T you now get just typing.TypeVar instead of typing.TypeVar("T", ...) where ... is the bound/constraints/default. This matches pyright and mypy; pyrefly uses type[TypeVar[T]] which seems a bit confusing, but does include the name. (We could easily include the name without cycle issues, if there's a syntax we like for that.)

It also means that displaying a generic function type like def f[T: int](x: T) -> T: ... now displays as f[T](x: T) -> T instead of f[T: int](x: T) -> T. This matches pyright and pyrefly; mypy does include bound/constraints/defaults of typevars in function/callable type display. If we wanted to add this, we would either need to thread a visitor through all the type display code, or add a decycle type transformation that replaced recursive reoccurrence of a type with a marker.

Test Plan

Added mdtests and modified existing tests to improve their correctness.

After this PR, there's only a single remaining py-fuzzer seed in the 0-500 range that panics! (Before this PR, there were 10; the fuzzer likes to generate cyclic PEP 695 syntax.)

Ecosystem report

It's all just the changes to TypeVar display.

@carljm carljm added the ty Multi-file analysis & type inference label Aug 13, 2025
Copy link
Contributor

github-actions bot commented Aug 13, 2025

Diagnostic diff on typing conformance tests

Changes were detected when running ty on typing conformance tests
--- old-output.txt	2025-08-13 22:34:15.963392901 +0000
+++ new-output.txt	2025-08-13 22:34:16.030393914 +0000
@@ -1,5 +1,5 @@
 WARN ty is pre-release software and not ready for production use. Expect to encounter bugs, missing features, and fatal errors.
-fatal[panic] Panicked at /home/runner/.cargo/git/checkouts/salsa-e6f3bb7c2a062968/918d35d/src/function/execute.rs:215:25 when checking `/home/runner/work/ruff/ruff/typing/conformance/tests/aliases_typealiastype.py`: `infer_definition_types(Id(104b4)): execute: too many cycle iterations`
+fatal[panic] Panicked at /home/runner/.cargo/git/checkouts/salsa-e6f3bb7c2a062968/918d35d/src/function/execute.rs:215:25 when checking `/home/runner/work/ruff/ruff/typing/conformance/tests/aliases_typealiastype.py`: `infer_definition_types(Id(bcb6)): execute: too many cycle iterations`
 _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@__add__`
@@ -68,9 +68,9 @@
 aliases_type_statement.py:48:23: error[invalid-type-form] Boolean operations are not allowed in type expressions
 aliases_type_statement.py:49:23: error[fstring-type-annotation] Type expressions cannot use f-strings
 aliases_type_statement.py:80:37: error[invalid-type-form] List literals are not allowed in this context in a type expression: Did you mean `tuple[int, str]`?
-aliases_variance.py:18:24: error[non-subscriptable] Cannot subscript object of type `<class 'ClassA[typing.TypeVar("T_co")]'>` with no `__class_getitem__` method
-aliases_variance.py:28:16: error[non-subscriptable] Cannot subscript object of type `<class 'ClassA[typing.TypeVar("T_co")]'>` with no `__class_getitem__` method
-aliases_variance.py:44:16: error[non-subscriptable] Cannot subscript object of type `<class 'ClassB[typing.TypeVar("T_co"), typing.TypeVar("T_contra")]'>` with no `__class_getitem__` method
+aliases_variance.py:18:24: error[non-subscriptable] Cannot subscript object of type `<class 'ClassA[typing.TypeVar]'>` with no `__class_getitem__` method
+aliases_variance.py:28:16: error[non-subscriptable] Cannot subscript object of type `<class 'ClassA[typing.TypeVar]'>` with no `__class_getitem__` method
+aliases_variance.py:44:16: error[non-subscriptable] Cannot subscript object of type `<class 'ClassB[typing.TypeVar, typing.TypeVar]'>` with no `__class_getitem__` method
 annotations_forward_refs.py:22:7: error[unresolved-reference] Name `ClassA` used when not defined
 annotations_forward_refs.py:23:12: error[unresolved-reference] Name `ClassA` used when not defined
 annotations_forward_refs.py:49:10: error[invalid-type-form] Variable of type `Literal[1]` is not allowed in a type expression
@@ -384,7 +384,7 @@
 generics_defaults_referential.py:95:1: error[type-assertion-failure] Argument does not have asserted type `@Todo`
 generics_defaults_specialization.py:26:5: error[type-assertion-failure] Argument does not have asserted type `SomethingWithNoDefaults[int, str]`
 generics_defaults_specialization.py:27:5: error[type-assertion-failure] Argument does not have asserted type `SomethingWithNoDefaults[int, bool]`
-generics_defaults_specialization.py:30:1: error[non-subscriptable] Cannot subscript object of type `<class 'SomethingWithNoDefaults[int, typing.TypeVar("DefaultStrT", default=str)]'>` with no `__class_getitem__` method
+generics_defaults_specialization.py:30:1: error[non-subscriptable] Cannot subscript object of type `<class 'SomethingWithNoDefaults[int, typing.TypeVar]'>` with no `__class_getitem__` method
 generics_defaults_specialization.py:45:1: error[type-assertion-failure] Argument does not have asserted type `@Todo`
 generics_paramspec_basic.py:27:38: error[invalid-return-type] Function always implicitly returns `None`, which is not assignable to return type `int`
 generics_paramspec_components.py:83:18: error[parameter-already-assigned] Multiple values provided for parameter 1 (`x`) of function `foo`
@@ -492,7 +492,6 @@
 generics_syntax_infer_variance.py:144:1: error[invalid-assignment] Object of type `ShouldBeInvariant5[int]` is not assignable to `ShouldBeInvariant5[int | float]`
 generics_syntax_infer_variance.py:155:1: error[invalid-assignment] Object of type `ShouldBeContravariant1[int]` is not assignable to `ShouldBeContravariant1[int | float]`
 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@decorator1, /) -> (...) -> R@decorator1`
 generics_syntax_scoping.py:44:17: error[unresolved-reference] Name `T` used when not defined
@@ -564,20 +563,20 @@
 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@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[typing.TypeVar("T_contra")]'>` with no `__class_getitem__` method
-generics_variance.py:175:35: error[non-subscriptable] Cannot subscript object of type `<class 'Co[typing.TypeVar("T_co")]'>` with no `__class_getitem__` method
-generics_variance.py:179:29: error[non-subscriptable] Cannot subscript object of type `<class 'Contra[typing.TypeVar("T_contra")]'>` with no `__class_getitem__` method
-generics_variance.py:179:39: error[non-subscriptable] Cannot subscript object of type `<class 'Contra[typing.TypeVar("T_contra")]'>` with no `__class_getitem__` method
-generics_variance.py:183:21: error[non-subscriptable] Cannot subscript object of type `<class 'Co[typing.TypeVar("T_co")]'>` with no `__class_getitem__` method
-generics_variance.py:183:27: error[non-subscriptable] Cannot subscript object of type `<class 'Co[typing.TypeVar("T_co")]'>` with no `__class_getitem__` method
-generics_variance.py:187:25: error[non-subscriptable] Cannot subscript object of type `<class 'Co[typing.TypeVar("T_co")]'>` with no `__class_getitem__` method
-generics_variance.py:187:31: error[non-subscriptable] Cannot subscript object of type `<class 'Contra[typing.TypeVar("T_contra")]'>` with no `__class_getitem__` method
-generics_variance.py:191:33: error[non-subscriptable] Cannot subscript object of type `<class 'Contra[typing.TypeVar("T_contra")]'>` with no `__class_getitem__` method
-generics_variance.py:191:43: error[non-subscriptable] Cannot subscript object of type `<class 'Co[typing.TypeVar("T_co")]'>` with no `__class_getitem__` method
-generics_variance.py:191:49: error[non-subscriptable] Cannot subscript object of type `<class 'Contra[typing.TypeVar("T_contra")]'>` with no `__class_getitem__` method
-generics_variance.py:196:5: error[non-subscriptable] Cannot subscript object of type `<class 'Contra[typing.TypeVar("T_contra")]'>` with no `__class_getitem__` method
-generics_variance.py:196:15: error[non-subscriptable] Cannot subscript object of type `<class 'Contra[typing.TypeVar("T_contra")]'>` with no `__class_getitem__` method
-generics_variance.py:196:25: error[non-subscriptable] Cannot subscript object of type `<class 'Contra[typing.TypeVar("T_contra")]'>` with no `__class_getitem__` method
+generics_variance.py:175:25: error[non-subscriptable] Cannot subscript object of type `<class 'Contra[typing.TypeVar]'>` with no `__class_getitem__` method
+generics_variance.py:175:35: error[non-subscriptable] Cannot subscript object of type `<class 'Co[typing.TypeVar]'>` with no `__class_getitem__` method
+generics_variance.py:179:29: error[non-subscriptable] Cannot subscript object of type `<class 'Contra[typing.TypeVar]'>` with no `__class_getitem__` method
+generics_variance.py:179:39: error[non-subscriptable] Cannot subscript object of type `<class 'Contra[typing.TypeVar]'>` with no `__class_getitem__` method
+generics_variance.py:183:21: error[non-subscriptable] Cannot subscript object of type `<class 'Co[typing.TypeVar]'>` with no `__class_getitem__` method
+generics_variance.py:183:27: error[non-subscriptable] Cannot subscript object of type `<class 'Co[typing.TypeVar]'>` with no `__class_getitem__` method
+generics_variance.py:187:25: error[non-subscriptable] Cannot subscript object of type `<class 'Co[typing.TypeVar]'>` with no `__class_getitem__` method
+generics_variance.py:187:31: error[non-subscriptable] Cannot subscript object of type `<class 'Contra[typing.TypeVar]'>` with no `__class_getitem__` method
+generics_variance.py:191:33: error[non-subscriptable] Cannot subscript object of type `<class 'Contra[typing.TypeVar]'>` with no `__class_getitem__` method
+generics_variance.py:191:43: error[non-subscriptable] Cannot subscript object of type `<class 'Co[typing.TypeVar]'>` with no `__class_getitem__` method
+generics_variance.py:191:49: error[non-subscriptable] Cannot subscript object of type `<class 'Contra[typing.TypeVar]'>` with no `__class_getitem__` method
+generics_variance.py:196:5: error[non-subscriptable] Cannot subscript object of type `<class 'Contra[typing.TypeVar]'>` with no `__class_getitem__` method
+generics_variance.py:196:15: error[non-subscriptable] Cannot subscript object of type `<class 'Contra[typing.TypeVar]'>` with no `__class_getitem__` method
+generics_variance.py:196:25: error[non-subscriptable] Cannot subscript object of type `<class 'Contra[typing.TypeVar]'>` 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@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]`
@@ -860,5 +859,5 @@
 typeddicts_operations.py:60:1: error[type-assertion-failure] Argument does not have asserted type `str | None`
 typeddicts_type_consistency.py:101:1: error[invalid-assignment] Object of type `Unknown | None` is not assignable to `str`
 typeddicts_usage.py:40:24: error[invalid-type-form] The special form `typing.TypedDict` is not allowed in type expressions. Did you mean to use a concrete TypedDict or `collections.abc.Mapping[str, object]` instead?
-Found 861 diagnostics
+Found 860 diagnostics
 WARN A fatal error occurred while checking some files. Not all project files were analyzed. See the diagnostics list above for details.

Copy link
Contributor

github-actions bot commented Aug 13, 2025

mypy_primer results

Changes were detected when running on open source projects
bidict (https://github.com/jab/bidict)
- bidict/_typing.py:40:39: error[non-subscriptable] Cannot subscript object of type `<class 'Iterable[tuple[typing.TypeVar("KT"), typing.TypeVar("VT")]]'>` with no `__class_getitem__` method
+ bidict/_typing.py:40:39: error[non-subscriptable] Cannot subscript object of type `<class 'Iterable[tuple[typing.TypeVar, typing.TypeVar]]'>` with no `__class_getitem__` method

Expression (https://github.com/cognitedata/Expression)
- expression/collections/maptree.py:47:18: error[invalid-argument-type] Argument to class `MapTreeLeaf` is incorrect: Expected `SupportsLessThan`, found `typing.TypeVar("Key", bound=SupportsLessThan)`
+ expression/collections/maptree.py:47:18: error[invalid-argument-type] Argument to class `MapTreeLeaf` is incorrect: Expected `SupportsLessThan`, found `typing.TypeVar`
- tests/test_map.py:49:19: error[invalid-argument-type] Argument to function `pipe` is incorrect: Expected `(Map[str, int], /) -> Unknown`, found `def to_seq[_Key: SupportsLessThan, _Value](table: Map[_Key@to_seq, _Value@to_seq]) -> Iterable[tuple[_Key@to_seq, _Value@to_seq]]`
+ tests/test_map.py:49:19: error[invalid-argument-type] Argument to function `pipe` is incorrect: Expected `(Map[str, int], /) -> Unknown`, found `def to_seq[_Key, _Value](table: Map[_Key@to_seq, _Value@to_seq]) -> Iterable[tuple[_Key@to_seq, _Value@to_seq]]`

black (https://github.com/psf/black)
- src/black/rusty.py:28:23: error[invalid-argument-type] Argument to class `Err` is incorrect: Expected `Exception`, found `typing.TypeVar("E", bound=Exception)`
+ src/black/rusty.py:28:23: error[invalid-argument-type] Argument to class `Err` is incorrect: Expected `Exception`, found `typing.TypeVar`

mongo-python-driver (https://github.com/mongodb/mongo-python-driver)
- pymongo/asynchronous/collection.py:104:5: error[invalid-argument-type] Argument to class `InsertOne` is incorrect: Expected `Mapping[str, Any]`, found `typing.TypeVar("_DocumentType", bound=Mapping[str, Any])`
+ pymongo/asynchronous/collection.py:104:5: error[invalid-argument-type] Argument to class `InsertOne` is incorrect: Expected `Mapping[str, Any]`, found `typing.TypeVar`
- pymongo/asynchronous/collection.py:107:5: error[invalid-argument-type] Argument to class `ReplaceOne` is incorrect: Expected `Mapping[str, Any]`, found `typing.TypeVar("_DocumentType", bound=Mapping[str, Any])`
+ pymongo/asynchronous/collection.py:107:5: error[invalid-argument-type] Argument to class `ReplaceOne` is incorrect: Expected `Mapping[str, Any]`, found `typing.TypeVar`
- pymongo/synchronous/collection.py:103:5: error[invalid-argument-type] Argument to class `InsertOne` is incorrect: Expected `Mapping[str, Any]`, found `typing.TypeVar("_DocumentType", bound=Mapping[str, Any])`
+ pymongo/synchronous/collection.py:103:5: error[invalid-argument-type] Argument to class `InsertOne` is incorrect: Expected `Mapping[str, Any]`, found `typing.TypeVar`
- pymongo/synchronous/collection.py:106:5: error[invalid-argument-type] Argument to class `ReplaceOne` is incorrect: Expected `Mapping[str, Any]`, found `typing.TypeVar("_DocumentType", bound=Mapping[str, Any])`
+ pymongo/synchronous/collection.py:106:5: error[invalid-argument-type] Argument to class `ReplaceOne` is incorrect: Expected `Mapping[str, Any]`, found `typing.TypeVar`

schemathesis (https://github.com/schemathesis/schemathesis)
- src/schemathesis/core/result.py:27:23: error[invalid-argument-type] Argument to class `Err` is incorrect: Expected `Exception`, found `typing.TypeVar("E", bound=Exception)`
+ src/schemathesis/core/result.py:27:23: error[invalid-argument-type] Argument to class `Err` is incorrect: Expected `Exception`, found `typing.TypeVar`

pytest (https://github.com/pytest-dev/pytest)
- src/_pytest/raises.py:1004:33: error[invalid-argument-type] Argument to class `RaisesExc` is incorrect: Expected `BaseException`, found `typing.TypeVar("BaseExcT_co", bound=BaseException)`
+ src/_pytest/raises.py:1004:33: error[invalid-argument-type] Argument to class `RaisesExc` is incorrect: Expected `BaseException`, found `typing.TypeVar`

discord.py (https://github.com/Rapptz/discord.py)
- discord/app_commands/commands.py:111:64: error[non-subscriptable] Cannot subscript object of type `<class 'Coroutine[Any, Any, typing.TypeVar("T")]'>` with no `__class_getitem__` method
+ discord/app_commands/commands.py:111:64: error[non-subscriptable] Cannot subscript object of type `<class 'Coroutine[Any, Any, typing.TypeVar]'>` with no `__class_getitem__` method
- discord/app_commands/commands.py:113:61: error[non-subscriptable] Cannot subscript object of type `<class 'Coroutine[Any, Any, typing.TypeVar("T")]'>` with no `__class_getitem__` method
+ discord/app_commands/commands.py:113:61: error[non-subscriptable] Cannot subscript object of type `<class 'Coroutine[Any, Any, typing.TypeVar]'>` with no `__class_getitem__` method
- discord/app_commands/commands.py:116:52: error[non-subscriptable] Cannot subscript object of type `<class 'Coroutine[Any, Any, typing.TypeVar("T")]'>` with no `__class_getitem__` method
+ discord/app_commands/commands.py:116:52: error[non-subscriptable] Cannot subscript object of type `<class 'Coroutine[Any, Any, typing.TypeVar]'>` with no `__class_getitem__` method
- discord/app_commands/commands.py:122:62: error[non-subscriptable] Cannot subscript object of type `<class 'Coroutine[Any, Any, typing.TypeVar("T")]'>` with no `__class_getitem__` method
+ discord/app_commands/commands.py:122:62: error[non-subscriptable] Cannot subscript object of type `<class 'Coroutine[Any, Any, typing.TypeVar]'>` with no `__class_getitem__` method
- discord/app_commands/commands.py:123:54: error[non-subscriptable] Cannot subscript object of type `<class 'Coroutine[Any, Any, typing.TypeVar("T")]'>` with no `__class_getitem__` method
+ discord/app_commands/commands.py:123:54: error[non-subscriptable] Cannot subscript object of type `<class 'Coroutine[Any, Any, typing.TypeVar]'>` with no `__class_getitem__` method
- discord/app_commands/commands.py:132:48: error[non-subscriptable] Cannot subscript object of type `<class 'Coroutine[Any, Any, typing.TypeVar("T")]'>` with no `__class_getitem__` method
+ discord/app_commands/commands.py:132:48: error[non-subscriptable] Cannot subscript object of type `<class 'Coroutine[Any, Any, typing.TypeVar]'>` with no `__class_getitem__` method
- discord/app_commands/commands.py:133:46: error[non-subscriptable] Cannot subscript object of type `<class 'Coroutine[Any, Any, typing.TypeVar("T")]'>` with no `__class_getitem__` method
+ discord/app_commands/commands.py:133:46: error[non-subscriptable] Cannot subscript object of type `<class 'Coroutine[Any, Any, typing.TypeVar]'>` with no `__class_getitem__` method
- discord/app_commands/commands.py:134:49: error[non-subscriptable] Cannot subscript object of type `<class 'Coroutine[Any, Any, typing.TypeVar("T")]'>` with no `__class_getitem__` method
+ discord/app_commands/commands.py:134:49: error[non-subscriptable] Cannot subscript object of type `<class 'Coroutine[Any, Any, typing.TypeVar]'>` with no `__class_getitem__` method
- discord/app_commands/commands.py:135:61: error[non-subscriptable] Cannot subscript object of type `<class 'Coroutine[Any, Any, typing.TypeVar("T")]'>` with no `__class_getitem__` method
+ discord/app_commands/commands.py:135:61: error[non-subscriptable] Cannot subscript object of type `<class 'Coroutine[Any, Any, typing.TypeVar]'>` with no `__class_getitem__` method
- discord/app_commands/commands.py:139:53: error[non-subscriptable] Cannot subscript object of type `<class 'Coroutine[Any, Any, typing.TypeVar("T")]'>` with no `__class_getitem__` method
+ discord/app_commands/commands.py:139:53: error[non-subscriptable] Cannot subscript object of type `<class 'Coroutine[Any, Any, typing.TypeVar]'>` with no `__class_getitem__` method
- discord/app_commands/commands.py:139:63: error[invalid-argument-type] Argument to class `Choice` is incorrect: Expected `str | int | float`, found `typing.TypeVar("ChoiceT", str, int, int | float, str | int | float)`
+ discord/app_commands/commands.py:139:63: error[invalid-argument-type] Argument to class `Choice` is incorrect: Expected `str | int | float`, found `typing.TypeVar`
- discord/app_commands/commands.py:140:45: error[non-subscriptable] Cannot subscript object of type `<class 'Coroutine[Any, Any, typing.TypeVar("T")]'>` with no `__class_getitem__` method
+ discord/app_commands/commands.py:140:45: error[non-subscriptable] Cannot subscript object of type `<class 'Coroutine[Any, Any, typing.TypeVar]'>` with no `__class_getitem__` method
- discord/app_commands/commands.py:140:55: error[invalid-argument-type] Argument to class `Choice` is incorrect: Expected `str | int | float`, found `typing.TypeVar("ChoiceT", str, int, int | float, str | int | float)`
+ discord/app_commands/commands.py:140:55: error[invalid-argument-type] Argument to class `Choice` is incorrect: Expected `str | int | float`, found `typing.TypeVar`
- discord/app_commands/tree.py:76:10: error[invalid-argument-type] Argument to class `Interaction` is incorrect: Expected `Client`, found `typing.TypeVar("ClientT", bound=Client, default=Client)`
+ discord/app_commands/tree.py:76:10: error[invalid-argument-type] Argument to class `Interaction` is incorrect: Expected `Client`, found `typing.TypeVar`
- discord/ext/commands/_types.py:47:26: error[non-subscriptable] Cannot subscript object of type `<class 'Coroutine[Any, Any, typing.TypeVar("T")]'>` with no `__class_getitem__` method
+ discord/ext/commands/_types.py:47:26: error[non-subscriptable] Cannot subscript object of type `<class 'Coroutine[Any, Any, typing.TypeVar]'>` with no `__class_getitem__` method
- discord/ext/commands/_types.py:48:22: error[non-subscriptable] Cannot subscript object of type `<class 'Coroutine[Any, Any, typing.TypeVar("T")]'>` with no `__class_getitem__` method
+ discord/ext/commands/_types.py:48:22: error[non-subscriptable] Cannot subscript object of type `<class 'Coroutine[Any, Any, typing.TypeVar]'>` with no `__class_getitem__` method
- discord/ext/commands/_types.py:53:45: error[non-subscriptable] Cannot subscript object of type `<class 'Coroutine[Any, Any, typing.TypeVar("T")]'>` with no `__class_getitem__` method
+ discord/ext/commands/_types.py:53:45: error[non-subscriptable] Cannot subscript object of type `<class 'Coroutine[Any, Any, typing.TypeVar]'>` with no `__class_getitem__` method
- discord/ext/commands/_types.py:53:80: error[non-subscriptable] Cannot subscript object of type `<class 'Coroutine[Any, Any, typing.TypeVar("T")]'>` with no `__class_getitem__` method
+ discord/ext/commands/_types.py:53:80: error[non-subscriptable] Cannot subscript object of type `<class 'Coroutine[Any, Any, typing.TypeVar]'>` with no `__class_getitem__` method
- discord/ext/commands/_types.py:54:62: error[non-subscriptable] Cannot subscript object of type `<class 'Coroutine[Any, Any, typing.TypeVar("T")]'>` with no `__class_getitem__` method
+ discord/ext/commands/_types.py:54:62: error[non-subscriptable] Cannot subscript object of type `<class 'Coroutine[Any, Any, typing.TypeVar]'>` with no `__class_getitem__` method
- discord/ext/commands/_types.py:54:113: error[non-subscriptable] Cannot subscript object of type `<class 'Coroutine[Any, Any, typing.TypeVar("T")]'>` with no `__class_getitem__` method
+ discord/ext/commands/_types.py:54:113: error[non-subscriptable] Cannot subscript object of type `<class 'Coroutine[Any, Any, typing.TypeVar]'>` with no `__class_getitem__` method
- discord/ext/commands/hybrid.py:85:50: error[non-subscriptable] Cannot subscript object of type `<class 'Coroutine[Any, Any, typing.TypeVar("T")]'>` with no `__class_getitem__` method
+ discord/ext/commands/hybrid.py:85:50: error[non-subscriptable] Cannot subscript object of type `<class 'Coroutine[Any, Any, typing.TypeVar]'>` with no `__class_getitem__` method
- discord/ext/commands/hybrid.py:86:44: error[non-subscriptable] Cannot subscript object of type `<class 'Coroutine[Any, Any, typing.TypeVar("T")]'>` with no `__class_getitem__` method
+ discord/ext/commands/hybrid.py:86:44: error[non-subscriptable] Cannot subscript object of type `<class 'Coroutine[Any, Any, typing.TypeVar]'>` with no `__class_getitem__` method

cwltool (https://github.com/common-workflow-language/cwltool)
- cwltool/process.py:1182:5: error[invalid-parameter-default] Default value of type `def urljoin[AnyStr: (str, bytes)](base: AnyStr@urljoin, url: AnyStr@urljoin | None, allow_fragments: bool = Literal[True]) -> AnyStr@urljoin` is not assignable to annotated parameter type `(str, str, /) -> str`
+ cwltool/process.py:1182:5: error[invalid-parameter-default] Default value of type `def urljoin[AnyStr](base: AnyStr@urljoin, url: AnyStr@urljoin | None, allow_fragments: bool = Literal[True]) -> AnyStr@urljoin` is not assignable to annotated parameter type `(str, str, /) -> str`

django-stubs (https://github.com/typeddjango/django-stubs)
- django-stubs/contrib/admin/options.pyi:148:66: error[invalid-argument-type] Argument to class `QuerySet` is incorrect: Expected `Model`, found `typing.TypeVar("_ModelT", bound=Model)`
+ django-stubs/contrib/admin/options.pyi:148:66: error[invalid-argument-type] Argument to class `QuerySet` is incorrect: Expected `Model`, found `typing.TypeVar`
- django-stubs/contrib/auth/forms.pyi:115:1: error[inconsistent-mro] Cannot create a consistent method resolution order (MRO) for class `SetPasswordForm` with bases list `[typing.Generic[_UserType: AbstractBaseUser], <class 'SetPasswordMixin'>, <class 'Form'>]`
+ django-stubs/contrib/auth/forms.pyi:115:1: error[inconsistent-mro] Cannot create a consistent method resolution order (MRO) for class `SetPasswordForm` with bases list `[typing.Generic[_UserType], <class 'SetPasswordMixin'>, <class 'Form'>]`
- django-stubs/forms/formsets.pyi:28:1: error[inconsistent-mro] Cannot create a consistent method resolution order (MRO) for class `BaseFormSet` with bases list `[typing.Generic[_F: BaseForm], <class 'Sized'>, <class 'RenderableFormMixin'>]`
+ django-stubs/forms/formsets.pyi:28:1: error[inconsistent-mro] Cannot create a consistent method resolution order (MRO) for class `BaseFormSet` with bases list `[typing.Generic[_F], <class 'Sized'>, <class 'RenderableFormMixin'>]`
- ext/django_stubs_ext/annotations.py:18:33: error[invalid-argument-type] Argument to class `Annotations` is incorrect: Expected `Mapping[str, Any]`, found `typing.TypeVar("_Annotations", bound=Mapping[str, Any])`
+ ext/django_stubs_ext/annotations.py:18:33: error[invalid-argument-type] Argument to class `Annotations` is incorrect: Expected `Mapping[str, Any]`, found `typing.TypeVar`

meson (https://github.com/mesonbuild/meson)
- unittests/helpers.py:228:16: error[invalid-return-type] Return type does not match returned value: expected `((...) -> R@xfail_if_jobname, /) -> (...) -> R@xfail_if_jobname`, found `def expectedFailure[_FT: (...) -> Any](test_item: _FT@expectedFailure) -> _FT@expectedFailure`
+ unittests/helpers.py:228:16: error[invalid-return-type] Return type does not match returned value: expected `((...) -> R@xfail_if_jobname, /) -> (...) -> R@xfail_if_jobname`, found `def expectedFailure[_FT](test_item: _FT@expectedFailure) -> _FT@expectedFailure`
- unittests/linuxliketests.py:712:48: error[invalid-argument-type] Argument to function `copytree` is incorrect: Expected `(str, str, /) -> object`, found `def copyfile[_StrOrBytesPathT: @Todo(Support for `typing.TypeAlias`)](src: @Todo(Support for `typing.TypeAlias`), dst: _StrOrBytesPathT@copyfile, *, follow_symlinks: bool = Literal[True]) -> _StrOrBytesPathT@copyfile`
+ unittests/linuxliketests.py:712:48: error[invalid-argument-type] Argument to function `copytree` is incorrect: Expected `(str, str, /) -> object`, found `def copyfile[_StrOrBytesPathT](src: @Todo(Support for `typing.TypeAlias`), dst: _StrOrBytesPathT@copyfile, *, follow_symlinks: bool = Literal[True]) -> _StrOrBytesPathT@copyfile`

static-frame (https://github.com/static-frame/static-frame)
- static_frame/test/property/strategies.py:927:17: error[invalid-argument-type] Argument to function `get_index_hierarchy` is incorrect: Expected `(...) -> IndexHierarchy`, found `(bound method type[Index[Any]].from_labels[I: Index[Any]](labels: Iterable[Unknown], *, /, name: Unknown = None) -> I@from_labels) | (bound method <class 'Index'>.from_labels[I: Index[Any]](labels: Iterable[Unknown], *, /, name: Unknown = None) -> I@from_labels)`
+ static_frame/test/property/strategies.py:927:17: error[invalid-argument-type] Argument to function `get_index_hierarchy` is incorrect: Expected `(...) -> IndexHierarchy`, found `(bound method type[Index[Any]].from_labels[I](labels: Iterable[Unknown], *, /, name: Unknown = None) -> I@from_labels) | (bound method <class 'Index'>.from_labels[I](labels: Iterable[Unknown], *, /, name: Unknown = None) -> I@from_labels)`
- static_frame/test/unit/test_type_clinic.py:2878:9: error[invalid-argument-type] Argument to class `Index` is incorrect: Expected `generic[Any]`, found `typing.TypeVar("T", bound=generic[Any])`
+ static_frame/test/unit/test_type_clinic.py:2878:9: error[invalid-argument-type] Argument to class `Index` is incorrect: Expected `generic[Any]`, found `typing.TypeVar`
- static_frame/test/unit/test_type_clinic.py:2879:9: error[invalid-argument-type] Argument to class `Index` is incorrect: Expected `generic[Any]`, found `typing.TypeVar("T", bound=generic[Any])`
+ static_frame/test/unit/test_type_clinic.py:2879:9: error[invalid-argument-type] Argument to class `Index` is incorrect: Expected `generic[Any]`, found `typing.TypeVar`
- static_frame/test/unit/test_type_clinic.py:2902:9: error[invalid-argument-type] Argument to class `Index` is incorrect: Expected `generic[Any]`, found `typing.TypeVar("T", signedinteger[_64Bit], float64)`
+ static_frame/test/unit/test_type_clinic.py:2902:9: error[invalid-argument-type] Argument to class `Index` is incorrect: Expected `generic[Any]`, found `typing.TypeVar`
- static_frame/test/unit/test_type_clinic.py:2903:9: error[invalid-argument-type] Argument to class `Index` is incorrect: Expected `generic[Any]`, found `typing.TypeVar("T", signedinteger[_64Bit], float64)`
+ static_frame/test/unit/test_type_clinic.py:2903:9: error[invalid-argument-type] Argument to class `Index` is incorrect: Expected `generic[Any]`, found `typing.TypeVar`
- static_frame/test/unit/test_type_clinic.py:2922:9: error[invalid-argument-type] Argument to class `Index` is incorrect: Expected `generic[Any]`, found `typing.TypeVar("T", signedinteger[_64Bit], float64)`
+ static_frame/test/unit/test_type_clinic.py:2922:9: error[invalid-argument-type] Argument to class `Index` is incorrect: Expected `generic[Any]`, found `typing.TypeVar`
- static_frame/test/unit/test_type_clinic.py:2923:9: error[invalid-argument-type] Argument to class `Index` is incorrect: Expected `generic[Any]`, found `typing.TypeVar("T", signedinteger[_64Bit], float64)`
+ static_frame/test/unit/test_type_clinic.py:2923:9: error[invalid-argument-type] Argument to class `Index` is incorrect: Expected `generic[Any]`, found `typing.TypeVar`
- static_frame/test/unit/test_type_clinic.py:2947:9: error[invalid-argument-type] Argument to class `Index` is incorrect: Expected `generic[Any]`, found `typing.TypeVar("T")`
+ static_frame/test/unit/test_type_clinic.py:2947:9: error[invalid-argument-type] Argument to class `Index` is incorrect: Expected `generic[Any]`, found `typing.TypeVar`
- static_frame/test/unit/test_type_clinic.py:2948:9: error[invalid-argument-type] Argument to class `Index` is incorrect: Expected `generic[Any]`, found `typing.TypeVar("T")`
+ static_frame/test/unit/test_type_clinic.py:2948:9: error[invalid-argument-type] Argument to class `Index` is incorrect: Expected `generic[Any]`, found `typing.TypeVar`

zulip (https://github.com/zulip/zulip)
- zerver/lib/rest.py:189:40: error[invalid-argument-type] Argument is incorrect: Expected `typing.TypeVar("_F", bound=(...) -> Any)`, found `(...) -> HttpResponse`
+ zerver/lib/rest.py:189:40: error[invalid-argument-type] Argument is incorrect: Expected `typing.TypeVar`, found `(...) -> HttpResponse`
- zerver/lib/rest.py:205:40: error[invalid-argument-type] Argument is incorrect: Expected `typing.TypeVar("_F", bound=(...) -> Any)`, found `(...) -> HttpResponse`
+ zerver/lib/rest.py:205:40: error[invalid-argument-type] Argument is incorrect: Expected `typing.TypeVar`, found `(...) -> HttpResponse`
- zerver/lib/rest.py:215:43: error[invalid-argument-type] Argument to function `process_as_post` is incorrect: Expected `(...) -> HttpResponse`, found `((...) -> HttpResponse) | typing.TypeVar("_F", bound=(...) -> Any)`
+ zerver/lib/rest.py:215:43: error[invalid-argument-type] Argument to function `process_as_post` is incorrect: Expected `(...) -> HttpResponse`, found `((...) -> HttpResponse) | typing.TypeVar`
- zerver/views/auth.py:1178:1: error[invalid-argument-type] Argument is incorrect: Expected `typing.TypeVar("_F", bound=(...) -> Any)`, found `def api_get_server_settings(request: HttpRequest) -> HttpResponse`
+ zerver/views/auth.py:1178:1: error[invalid-argument-type] Argument is incorrect: Expected `typing.TypeVar`, found `def api_get_server_settings(request: HttpRequest) -> HttpResponse`
- zerver/views/development/email_log.py:52:1: error[invalid-argument-type] Argument is incorrect: Expected `typing.TypeVar("_F", bound=(...) -> Any)`, found `def generate_all_emails(request: HttpRequest) -> HttpResponse`
+ zerver/views/development/email_log.py:52:1: error[invalid-argument-type] Argument is incorrect: Expected `typing.TypeVar`, found `def generate_all_emails(request: HttpRequest) -> HttpResponse`
- zerver/views/realm.py:579:1: error[invalid-argument-type] Argument is incorrect: Expected `typing.TypeVar("_F", bound=(...) -> Any)`, found `def check_subdomain_available(request: HttpRequest, subdomain: str) -> HttpResponse`
+ zerver/views/realm.py:579:1: error[invalid-argument-type] Argument is incorrect: Expected `typing.TypeVar`, found `def check_subdomain_available(request: HttpRequest, subdomain: str) -> HttpResponse`
- zerver/views/report.py:13:1: error[invalid-argument-type] Argument to function `csrf_exempt` is incorrect: Argument type `typing.TypeVar("_F", bound=(...) -> Any)` does not satisfy upper bound of type variable `_F`
+ zerver/views/report.py:13:1: error[invalid-argument-type] Argument to function `csrf_exempt` is incorrect: Argument type `typing.TypeVar` does not satisfy upper bound of type variable `_F`
- zerver/views/report.py:14:1: error[invalid-argument-type] Argument is incorrect: Expected `typing.TypeVar("_F", bound=(...) -> Any)`, found `(...) -> Unknown`
+ zerver/views/report.py:14:1: error[invalid-argument-type] Argument is incorrect: Expected `typing.TypeVar`, found `(...) -> Unknown`
- zerver/views/video_calls.py:297:1: error[invalid-argument-type] Argument to function `csrf_exempt` is incorrect: Argument type `typing.TypeVar("_F", bound=(...) -> Any)` does not satisfy upper bound of type variable `_F`
+ zerver/views/video_calls.py:297:1: error[invalid-argument-type] Argument to function `csrf_exempt` is incorrect: Argument type `typing.TypeVar` does not satisfy upper bound of type variable `_F`
- zerver/views/video_calls.py:298:1: error[invalid-argument-type] Argument is incorrect: Expected `typing.TypeVar("_F", bound=(...) -> Any)`, found `(...) -> Unknown`
+ zerver/views/video_calls.py:298:1: error[invalid-argument-type] Argument is incorrect: Expected `typing.TypeVar`, found `(...) -> Unknown`

sympy (https://github.com/sympy/sympy)
- sympy/polys/series/ring.py:49:19: error[invalid-argument-type] Argument to class `PowerSeriesRingProto` is incorrect: Expected `RingElement`, found `typing.TypeVar("Er", bound=RingElement)`
+ sympy/polys/series/ring.py:49:19: error[invalid-argument-type] Argument to class `PowerSeriesRingProto` is incorrect: Expected `RingElement`, found `typing.TypeVar`
- sympy/polys/series/ring.py:49:40: error[invalid-argument-type] Argument to class `TSeries` is incorrect: Expected `RingElement`, found `typing.TypeVar("Er", bound=RingElement)`
+ sympy/polys/series/ring.py:49:40: error[invalid-argument-type] Argument to class `TSeries` is incorrect: Expected `RingElement`, found `typing.TypeVar`
No memory usage changes detected ✅

@carljm carljm marked this pull request as ready for review August 13, 2025 21:24
* main:
  [ty] Add some additional type safety to `CycleDetector` (#19903)
Copy link
Member

@dcreager dcreager left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good!

info: Attempted to call union type `(def f1() -> int) | (def f2(name: str) -> int) | (def f3(a: int, b: int) -> int) | (def f4[T: str](x: T@f4) -> int) | Literal[5] | (Overload[() -> None, (x: str) -> str]) | (Overload[() -> None, (x: str, y: str) -> str]) | PossiblyNotCallable`
info: Attempted to call union type `(def f1() -> int) | (def f2(name: str) -> int) | (def f3(a: int, b: int) -> int) | (def f4[T](x: T@f4) -> int) | Literal[5] | (Overload[() -> None, (x: str) -> str]) | (Overload[() -> None, (x: str, y: str) -> str]) | PossiblyNotCallable`
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is the place where I'm most leery of not including bounds/constraints/defaults in the rendering of a typevar. Though pyright also does not include them here, so your argument still holds!

Copy link
Contributor Author

@carljm carljm Aug 13, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, agreed. Pyrefly and pyright both do not include typevar details here, mypy does.

We can add them back in future. I'm not opposed to that at all, it's just gonna require some extra cycle-handling machinery for type display that I don't think is top priority right now.

Copy link
Member

@AlexWaygood AlexWaygood left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice!! Two minor nits about docs/naming; nothing blocking:

@carljm carljm merged commit 5a570c8 into main Aug 13, 2025
38 checks passed
@carljm carljm deleted the cjm/fix-pep695 branch August 13, 2025 22:52
dcreager added a commit that referenced this pull request Aug 14, 2025
* main:
  Feature/build riscv64 bin (#19819)
  [ty] Add caching to `CodeGeneratorKind::matches()` (#19912)
  [ty] Rename `functionArgumentNames` to `callArgumentNames` inlay hint setting (#19911)
  [ty] Default `ty.inlayHints.*` server settings to true (#19910)
  [ty] Remove py-fuzzer skips for seeds that are no longer slow (#19906)
  [ty] fix deferred name loading in PEP695 generic classes/functions (#19888)
  [ty] Add some additional type safety to `CycleDetector` (#19903)
  [`flake8-blind-except`] Fix `BLE001` false-positive on `raise ... from None` (#19755)
  [ty] resolve docstrings for modules (#19898)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
ty Multi-file analysis & type inference
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants