Skip to content

[ty] Avoid stack overflow when calculating inferable typevars#21971

Merged
dcreager merged 4 commits intomainfrom
dcreager/ty1874
Dec 15, 2025
Merged

[ty] Avoid stack overflow when calculating inferable typevars#21971
dcreager merged 4 commits intomainfrom
dcreager/ty1874

Conversation

@dcreager
Copy link
Member

When we calculate which typevars are inferable in a generic context, the result might include more than the typevars bound by the generic context. The canonical example is a generic method of a generic class:

class C[A]:
    def method[T](self, t: T): ...

Here, the inferable typevar set of method contains Self and T, as you'd expect. (Those are the typevars bound by the method.) But it also contains A@C, since the implicit Self typevar is defined as Self: C[A]. That means when we call method, we need to mark A@C as inferable, so that we can determine the correct mapping for A@C at the call site.

Fixes astral-sh/ty#1874

@astral-sh-bot
Copy link

astral-sh-bot bot commented Dec 14, 2025

Diagnostic diff on typing conformance tests

No changes detected when running ty on typing conformance tests ✅

Comment on lines -313 to +328
walk_bound_type_var_type(db, bound_typevar, self);
let typevar = bound_typevar.typevar(db);
if let Some(bound_or_constraints) = typevar.bound_or_constraints(db) {
walk_type_var_bounds(db, bound_or_constraints, self);
}
Copy link
Member Author

Choose a reason for hiding this comment

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

Before, we were recursing arbitrarily deep into each of the generic context's typevars — and in particular, arbitrarily deep into their bounds and constraints. There was a recursion in the example from astral-sh/ty#1874.

Really, we don't need to go more than one level deep looking for additional inferable typevars. We just need to look into the bound/constraints of the generic context's typevars. If those bounds/constraints themselves contain typevars, we mark them as inferable, but we don't need to recurse further. So we set should_visit_lazy_type_var_attributes to false to prevent the deeper recursions, and unroll the first level of recursion manually here.

@astral-sh-bot
Copy link

astral-sh-bot bot commented Dec 14, 2025

mypy_primer results

No ecosystem changes detected ✅

No memory usage changes detected ✅

@dcreager dcreager added ty Multi-file analysis & type inference ecosystem-analyzer labels Dec 14, 2025
@astral-sh-bot
Copy link

astral-sh-bot bot commented Dec 14, 2025

ecosystem-analyzer results

No diagnostic changes detected ✅
Full report with detailed diff (timing results)

@codspeed-hq
Copy link

codspeed-hq bot commented Dec 14, 2025

CodSpeed Performance Report

Merging #21971 will improve performances by 7.94%

Comparing dcreager/ty1874 (400bc25) with main (d08e414)

Summary

⚡ 1 improvement
✅ 21 untouched
⏩ 30 skipped1

Benchmarks breakdown

Mode Benchmark BASE HEAD Change
Simulation DateType 254.5 ms 235.8 ms +7.94%

Footnotes

  1. 30 benchmarks were skipped, so the baseline results were used instead. If they were deleted from the codebase, click here and archive them to remove them from the performance reports.

@dcreager dcreager marked this pull request as ready for review December 14, 2025 12:54
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! Can we add the MRE in astral-sh/ty#1874 (comment) as a regression test?

@AlexWaygood
Copy link
Member

And thank you so much for the added docs, really helpful!

@AlexWaygood AlexWaygood added the bug Something isn't working label Dec 14, 2025
* origin/main:
  Update MSRV to 1.90 (#21987)
  [ty] Improve check enforcing that an overloaded function must have an implementation (#21978)
  Update actions/checkout digest to 8e8c483 (#21982)
  [ty] Use `ParamSpec` without the attr for inferable check (#21934)
  [ty] Emit diagnostic when a type variable with a default is followed by one without a default (#21787)
  [ty] Fix callout syntax in configuration mkdocs (#1875) (#21961)
  Update debug_assert which pointed at missing method (#21969)
  [ty] Add support for `__qualname__` and other implicit class attributes (#21966)
@dcreager
Copy link
Member Author

Nice! Can we add the MRE in astral-sh/ty#1874 (comment) as a regression test?

Done

@dcreager dcreager merged commit cbfecfa into main Dec 15, 2025
42 checks passed
@dcreager dcreager deleted the dcreager/ty1874 branch December 15, 2025 15:25
dcreager added a commit that referenced this pull request Dec 15, 2025
* origin/main:
  Fluent formatting of method chains (#21369)
  [ty] Avoid stack overflow when calculating inferable typevars (#21971)
  [ty] Add "qualify ..." code fix for undefined references (#21968)
  [ty] Use jemalloc on linux (#21975)
  Update MSRV to 1.90 (#21987)
  [ty] Improve check enforcing that an overloaded function must have an implementation (#21978)
  Update actions/checkout digest to 8e8c483 (#21982)
  [ty] Use `ParamSpec` without the attr for inferable check (#21934)
  [ty] Emit diagnostic when a type variable with a default is followed by one without a default (#21787)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

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

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Stack overflow in GenericContext::inferable_typevars()

3 participants

Comments