Thanks to visit codestin.com
Credit goes to github.com

Skip to content

[ty] Retain recursively-defined state in binary expressions#25277

Merged
charliermarsh merged 1 commit into
mainfrom
charlie/final-recursively
May 21, 2026
Merged

[ty] Retain recursively-defined state in binary expressions#25277
charliermarsh merged 1 commit into
mainfrom
charlie/final-recursively

Conversation

@charliermarsh

@charliermarsh charliermarsh commented May 20, 2026

Copy link
Copy Markdown
Member

Summary

Prior to this change, a recursive implicit attribute like:

from __future__ import annotations
from typing import Final

class ScopeChain:
    def __init__(self, parent: ScopeChain | None = None) -> None:
        self.depth: Final = 1 if parent is None else parent.depth + 1

...could fail to converge during type inference. We now preserve the recursive-definition marker when literal binary operations produce a new literal result, so recursive literal unions continue through the existing widening path instead of accumulating results indefinitely.

Note: in the above snippet, the bare Final exposes the issue because we infer the RHS to get the type, as opposed to relying on the annotation, but in theory it needn't be specific to Final... Codex believes this is the only way to trigger that panic as of now, though because it's the only site where we create a recursive attribute lookup and retain the exact RHS literal type (e.g., the non-Final version, self.depth = 1 if parent is None else parent.depth + 1, promotes those literals).

Closes astral-sh/ty#3499.

@charliermarsh charliermarsh added the bug Something isn't working label May 20, 2026
@astral-sh-bot astral-sh-bot Bot added the ty Multi-file analysis & type inference label May 20, 2026
@astral-sh-bot

astral-sh-bot Bot commented May 20, 2026

Copy link
Copy Markdown

Typing conformance results

No changes detected ✅

Current numbers
The percentage of diagnostics emitted that were expected errors held steady at 89.36%. The percentage of expected errors that received a diagnostic held steady at 85.49%. The number of fully passing files held steady at 88/134.

@astral-sh-bot

astral-sh-bot Bot commented May 20, 2026

Copy link
Copy Markdown

Memory usage report

Memory usage unchanged ✅

@astral-sh-bot

astral-sh-bot Bot commented May 20, 2026

Copy link
Copy Markdown

ecosystem-analyzer results

No diagnostic changes detected ✅

Full report with detailed diff (timing results)

@charliermarsh charliermarsh marked this pull request as ready for review May 20, 2026 14:23
@charliermarsh charliermarsh marked this pull request as draft May 20, 2026 14:24
@charliermarsh charliermarsh marked this pull request as ready for review May 20, 2026 14:33
@charliermarsh charliermarsh merged commit 67d8c54 into main May 21, 2026
59 checks passed
@charliermarsh charliermarsh deleted the charlie/final-recursively branch May 21, 2026 08:40
thejchap pushed a commit to thejchap/ruff that referenced this pull request May 23, 2026
…h#25277)

## Summary

Prior to this change, a recursive implicit attribute like:

```python
from __future__ import annotations
from typing import Final

class ScopeChain:
    def __init__(self, parent: ScopeChain | None = None) -> None:
        self.depth: Final = 1 if parent is None else parent.depth + 1
```

...could fail to converge during type inference. We now preserve the
recursive-definition marker when literal binary operations produce a new
literal result, so recursive literal unions continue through the
existing widening path instead of accumulating results indefinitely.

Note: in the above snippet, the bare `Final` exposes the issue because
we infer the RHS to get the type, as opposed to relying on the
annotation, but in theory it needn't be specific to `Final`... Codex
believes this is the only way to trigger that panic as of now, though
because it's the only site where we create a recursive attribute lookup
_and_ retain the exact RHS literal type (e.g., the non-`Final` version,
`self.depth = 1 if parent is None else parent.depth + 1`, promotes those
literals).

Closes astral-sh/ty#3499.
anishgirianish pushed a commit to anishgirianish/ruff that referenced this pull request May 28, 2026
…h#25277)

## Summary

Prior to this change, a recursive implicit attribute like:

```python
from __future__ import annotations
from typing import Final

class ScopeChain:
    def __init__(self, parent: ScopeChain | None = None) -> None:
        self.depth: Final = 1 if parent is None else parent.depth + 1
```

...could fail to converge during type inference. We now preserve the
recursive-definition marker when literal binary operations produce a new
literal result, so recursive literal unions continue through the
existing widening path instead of accumulating results indefinitely.

Note: in the above snippet, the bare `Final` exposes the issue because
we infer the RHS to get the type, as opposed to relying on the
annotation, but in theory it needn't be specific to `Final`... Codex
believes this is the only way to trigger that panic as of now, though
because it's the only site where we create a recursive attribute lookup
_and_ retain the exact RHS literal type (e.g., the non-`Final` version,
`self.depth = 1 if parent is None else parent.depth + 1`, promotes those
literals).

Closes astral-sh/ty#3499.
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.

[panic] infer_definition_types(Id(1412)): execute: too many cycle iterations

2 participants