Skip to content

Conversation

@mtshiba
Copy link
Contributor

@mtshiba mtshiba commented Oct 19, 2025

Summary

While working on #20900, I noticed that the calculation of variance for recursive type aliases was leading to a stack overflow.

This PR fixes the apply_type_mapping_impl handling of type aliases, avoiding infinite recursion.

Test Plan

New tests in generics/pep695/aliases.md and types::tests::type_alias_variance.

@github-actions
Copy link
Contributor

github-actions bot commented Oct 19, 2025

Diagnostic diff on typing conformance tests

Changes were detected when running ty on typing conformance tests
--- old-output.txt	2025-10-23 14:11:17.723331983 +0000
+++ new-output.txt	2025-10-23 14:11:20.852357773 +0000
@@ -1,5 +1,4 @@
-fatal[panic] Panicked at /home/runner/.cargo/git/checkouts/salsa-e6f3bb7c2a062968/d38145c/src/function/execute.rs:417:17 when checking `/home/runner/work/ruff/ruff/typing/conformance/tests/aliases_type_statement.py`: `PEP695TypeAliasType < 'db >::value_type_(Id(d817)): execute: too many cycle iterations`
-fatal[panic] Panicked at /home/runner/.cargo/git/checkouts/salsa-e6f3bb7c2a062968/d38145c/src/function/execute.rs:417:17 when checking `/home/runner/work/ruff/ruff/typing/conformance/tests/aliases_typealiastype.py`: `infer_definition_types(Id(18043)): execute: too many cycle iterations`
+fatal[panic] Panicked at /home/runner/.cargo/git/checkouts/salsa-e6f3bb7c2a062968/d38145c/src/function/execute.rs:417:17 when checking `/home/runner/work/ruff/ruff/typing/conformance/tests/aliases_typealiastype.py`: `infer_definition_types(Id(17843)): 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__`
@@ -50,6 +49,33 @@
 aliases_newtype.py:18:1: error[invalid-assignment] Object of type `NewType` is not assignable to `type`
 aliases_newtype.py:26:21: error[invalid-base] Invalid class base with type `NewType`
 aliases_newtype.py:63:43: error[too-many-positional-arguments] Too many positional arguments to bound method `__init__`: expected 3, got 4
+aliases_type_statement.py:10:19: error[too-many-positional-arguments] Too many positional arguments: expected 1, got 3
+aliases_type_statement.py:17:1: error[unresolved-attribute] Object of type `typing.TypeAliasType` has no attribute `bit_count`
+aliases_type_statement.py:19:1: error[call-non-callable] Object of type `TypeAliasType` is not callable
+aliases_type_statement.py:23:7: error[unresolved-attribute] Object of type `typing.TypeAliasType` has no attribute `other_attrib`
+aliases_type_statement.py:26:18: error[invalid-base] Invalid class base with type `typing.TypeAliasType`
+aliases_type_statement.py:37:22: error[invalid-type-form] Function calls are not allowed in type expressions
+aliases_type_statement.py:38:22: error[invalid-type-form] List literals are not allowed in this context in a type expression: Did you mean `tuple[int, str]`?
+aliases_type_statement.py:39:22: error[invalid-type-form] Tuple literals are not allowed in this context in a type expression
+aliases_type_statement.py:39:23: error[invalid-type-form] Tuple literals are not allowed in this context in a type expression: Did you mean `tuple[int, str]`?
+aliases_type_statement.py:40:22: error[invalid-type-form] List comprehensions are not allowed in type expressions
+aliases_type_statement.py:41:22: error[invalid-type-form] Dict literals are not allowed in type expressions
+aliases_type_statement.py:42:22: error[invalid-type-form] Function calls are not allowed in type expressions
+aliases_type_statement.py:43:28: error[invalid-type-form] Int literals are not allowed in this context in a type expression
+aliases_type_statement.py:44:22: error[invalid-type-form] `if` expressions are not allowed in type expressions
+aliases_type_statement.py:45:22: error[invalid-type-form] Variable of type `Literal[1]` is not allowed in a type expression
+aliases_type_statement.py:46:23: error[invalid-type-form] Boolean literals are not allowed in this context in a type expression
+aliases_type_statement.py:47:23: error[invalid-type-form] Int literals are not allowed in this context in a type expression
+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:75:81: error[too-many-positional-arguments] Too many positional arguments: expected 2, got 3
+aliases_type_statement.py:77:7: error[invalid-argument-type] Argument is incorrect: Expected `int`, found `str`
+aliases_type_statement.py:77:7: error[too-many-positional-arguments] Too many positional arguments: expected 2, got 3
+aliases_type_statement.py:78:7: error[too-many-positional-arguments] Too many positional arguments: expected 2, got 3
+aliases_type_statement.py:79:7: error[invalid-argument-type] Argument is incorrect: Expected `str`, found `int`
+aliases_type_statement.py:79:7: error[too-many-positional-arguments] Too many positional arguments: expected 2, got 3
+aliases_type_statement.py:80:7: error[too-many-positional-arguments] Too many positional arguments: expected 2, got 3
+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]'>` 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
@@ -922,5 +948,5 @@
 typeddicts_usage.py:28:17: error[missing-typed-dict-key] Missing required key 'name' in TypedDict `Movie` constructor
 typeddicts_usage.py:28:18: error[invalid-key] Invalid key access on TypedDict `Movie`: Unknown key "title"
 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 924 diagnostics
+Found 950 diagnostics
 WARN A fatal error occurred while checking some files. Not all project files were analyzed. See the diagnostics list above for details.

@github-actions
Copy link
Contributor

github-actions bot commented Oct 19, 2025

mypy_primer results

No ecosystem changes detected ✅
No memory usage changes detected ✅

@mtshiba mtshiba marked this pull request as ready for review October 19, 2025 13:35
@AlexWaygood AlexWaygood added bug Something isn't working ty Multi-file analysis & type inference labels Oct 19, 2025
@mtshiba mtshiba force-pushed the recursive-generic-type-alias branch 3 times, most recently from 826d382 to 63333be Compare October 21, 2025 17:21
@mtshiba mtshiba force-pushed the recursive-generic-type-alias branch from 63333be to 7011639 Compare October 21, 2025 17:35
@mtshiba mtshiba requested a review from AlexWaygood October 21, 2025 17:52
Copy link
Member

@MichaReiser MichaReiser left a comment

Choose a reason for hiding this comment

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

I've a small suggestion. I'd appreciate it if @dcreager could give a short thumbs up because I'm not very familiar with this part of the code.

Copy link
Member

@ibraheemdev ibraheemdev left a comment

Choose a reason for hiding this comment

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

It's interesting that apply_type_mapping_impl is the only method that causes a panic. I suspect we will need to generalize this to storing a lazily-applied specialization on Type::TypeAlias, but given that this seems to resolve the panics, it seems fine to merge the easier fix for now?

@AlexWaygood AlexWaygood enabled auto-merge (squash) October 23, 2025 14:13
@AlexWaygood AlexWaygood merged commit 48f1771 into astral-sh:main Oct 23, 2025
40 checks passed
@mtshiba mtshiba deleted the recursive-generic-type-alias branch October 23, 2025 14:25
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bug Something isn't working ty Multi-file analysis & type inference

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants