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

Skip to content

[ty] Normalize recursive TypeOf growth during cycle recovery#26163

Merged
charliermarsh merged 4 commits into
mainfrom
charlie/fix-typeof-self-reference
Jun 22, 2026
Merged

[ty] Normalize recursive TypeOf growth during cycle recovery#26163
charliermarsh merged 4 commits into
mainfrom
charlie/fix-typeof-self-reference

Conversation

@charliermarsh

@charliermarsh charliermarsh commented Jun 19, 2026

Copy link
Copy Markdown
Member

Summary

A TypeOf self-reference nested in a generic specialization can cause each fixed-point iteration to wrap the previous inferred result:

from ty_extensions import TypeOf

x: list[TypeOf[x]] | None
x = [1]

Prior to this change, we repeatedly inferred a deeper specialization such as list[int], list[list[int]], and so on, eventually exhausting Salsa's cycle iterations.

This detects structurally growing nominal specializations after the tainted cycle iterations, replaces the previous cycle result with the cycle's Divergent marker, and then reuses the existing recursive-type normalization to converge.

Closes astral-sh/ty#3802.

@astral-sh-bot astral-sh-bot Bot added the ty Multi-file analysis & type inference label Jun 19, 2026
@astral-sh-bot

astral-sh-bot Bot commented Jun 19, 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 94.37%. The percentage of expected errors that received a diagnostic held steady at 89.00%. The number of fully passing files held steady at 94/134.

@astral-sh-bot

astral-sh-bot Bot commented Jun 19, 2026

Copy link
Copy Markdown

Memory usage report

Summary

Project Old New Diff Outcome
flake8 30.82MB 30.82MB +0.02% (5.45kB)
sphinx 193.95MB 193.95MB +0.00% (3.94kB)
prefect 518.49MB 518.49MB -0.00% (5.55kB) ⬇️
trio 77.57MB 77.56MB -0.01% (11.61kB) ⬇️

Significant changes

Click to expand detailed breakdown

flake8

Name Old New Diff Outcome
parsed_module 9.77MB 9.77MB +0.05% (5.45kB)

sphinx

Name Old New Diff Outcome
infer_expression_types_impl 23.33MB 23.33MB +0.00% (1.16kB)
infer_definition_types 19.56MB 19.56MB +0.00% (984.00B)
parsed_module 18.37MB 18.37MB +0.00% (808.00B)
all_narrowing_constraints_for_expression 2.69MB 2.69MB +0.01% (312.00B)
TupleType<'db>::to_class_type_ 161.29kB 161.49kB +0.13% (212.00B)
infer_statement_types_impl 965.15kB 965.28kB +0.01% (132.00B)
loop_header_reachability 382.05kB 382.17kB +0.03% (120.00B)
Specialization 1.40MB 1.40MB +0.01% (112.00B)
infer_unpack_types 505.27kB 505.36kB +0.02% (84.00B)
GenericAlias 612.21kB 612.28kB +0.01% (72.00B)
infer_scope_types_impl 10.54MB 10.54MB +0.00% (12.00B)

prefect

Name Old New Diff Outcome
parsed_module 19.36MB 19.36MB -0.03% (5.55kB) ⬇️

trio

Name Old New Diff Outcome
parsed_module 15.05MB 15.04MB -0.08% (12.17kB) ⬇️
TupleType<'db>::to_class_type_ 43.46kB 43.70kB +0.56% (248.00B) ⬇️
Specialization 456.06kB 456.17kB +0.02% (112.00B) ⬇️
GenericAlias 187.31kB 187.38kB +0.04% (72.00B) ⬇️
infer_definition_types 5.60MB 5.60MB +0.00% (72.00B) ⬇️
loop_header_reachability 124.76kB 124.80kB +0.03% (36.00B) ⬇️
infer_expression_types_impl 6.57MB 6.57MB +0.00% (36.00B) ⬇️

@charliermarsh charliermarsh force-pushed the charlie/fix-typeof-self-reference branch from dbf2027 to c8296d8 Compare June 19, 2026 21:12
@astral-sh-bot

astral-sh-bot Bot commented Jun 19, 2026

Copy link
Copy Markdown

ecosystem-analyzer results

No diagnostic changes detected ✅

Flaky changes detected. This PR summary excludes flaky changes; see the HTML report for details.

Full report with detailed diff (timing results)

@charliermarsh charliermarsh force-pushed the charlie/fix-typeof-self-reference branch from c8296d8 to 5026d67 Compare June 19, 2026 21:28
@charliermarsh charliermarsh changed the title [ty] Normalize recursive TypeOf growth during cycle recovery [ty] Normalize recursive TypeOf growth during cycle recovery Jun 19, 2026
@charliermarsh charliermarsh added the bug Something isn't working label Jun 19, 2026
@charliermarsh charliermarsh marked this pull request as ready for review June 19, 2026 21:39
@charliermarsh charliermarsh requested a review from a team as a code owner June 19, 2026 21:39
@astral-sh-bot astral-sh-bot Bot requested a review from dhruvmanila June 19, 2026 21:39
case 0:
async def name_4():
pass
```

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

The initial fix introduced a panic caught by our fuzzer; this captures it.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

It might be worth minimizing this example but if that's not possible it would be useful to expand the prose to contain the inference path / symbol name that's caused this panic.

case 0:
async def name_4():
pass
```

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

It might be worth minimizing this example but if that's not possible it would be useful to expand the prose to contain the inference path / symbol name that's caused this panic.

Comment on lines +1228 to +1230
// Only align unions when each iteration has exactly one changed arm. With multiple
// unmatched arms, pairing is ambiguous and can destabilize otherwise-convergent
// recursive cycles.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Does this mean that something like the following might still hang?

from ty_extensions import TypeOf

class Container[T]: ...

x: list[TypeOf[x]] | Container[TypeOf[x]]
x = [1]

Regardless, I don't think it's worth prioritizing given that TypeOf is internal.

@charliermarsh charliermarsh force-pushed the charlie/fix-typeof-self-reference branch from 5026d67 to 442d7cc Compare June 22, 2026 12:45
@charliermarsh charliermarsh enabled auto-merge (squash) June 22, 2026 12:45
@charliermarsh charliermarsh merged commit d238095 into main Jun 22, 2026
59 checks passed
@charliermarsh charliermarsh deleted the charlie/fix-typeof-self-reference branch June 22, 2026 12:50
charliermarsh added a commit that referenced this pull request Jun 24, 2026
Revert #26163 and the follow-up recovery and fallout fixes in #26230, #26246, #26274, #26275, and #26316.
charliermarsh added a commit that referenced this pull request Jun 24, 2026
Revert #26163 and the follow-up recovery and fallout fixes in #26230, #26246, #26274, #26275, and #26316.
charliermarsh added a commit that referenced this pull request Jun 24, 2026
## Summary

This reverts #26163 and its follow-up changes in #26230, #26246, #26274,
#26275, and #26316.

The recursive nominal-growth recovery replaces a previous cycle result
nested inside a specialization with `Divergent`. The follow-up
regressions show that this local replacement is not structurally safe:
multi-arm union recovery can lose stable arms, and variadic tuple growth
can continue after replacement. Addressing those cases required
increasingly shape-specific alignment and guards without a general way
to establish correspondence between fixed-point iterations.

This restores the cycle-recovery behavior from before #26163. The direct
self-referential `TypeOf` case and the regression coverage for
astral-sh/ty#3835 and astral-sh/ty#3838 continue to pass without the
heuristic and are retained. We remove only the cases that no longer
converge: `TypeOf` references nested in nominal specializations and the
nested-iterable case from astral-sh/ty#3827. The independent `Divergent`
constraint fixes from #26288 and #26334, including the regression
coverage for astral-sh/ty#3836, are also retained.
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.

Hang on variable declaration TypeOf itself then assignment

2 participants