Skip to content

Comments

[ty] Limit argument expansion size for overload call evaluation#20041

Merged
dhruvmanila merged 5 commits intomainfrom
dhruv/limit-argument-expansion-size
Aug 25, 2025
Merged

[ty] Limit argument expansion size for overload call evaluation#20041
dhruvmanila merged 5 commits intomainfrom
dhruv/limit-argument-expansion-size

Conversation

@dhruvmanila
Copy link
Member

@dhruvmanila dhruvmanila commented Aug 22, 2025

Summary

This PR limits the argument type expansion size for an overload call evaluation to 512.

The limit chosen is arbitrary but I've taken the 256 limit from Pyright into account and bumped it x2 to start with.

Initially, I actually started out by trying to refactor the entire argument type expansion to be lazy. Currently, expanding a single argument at any position eagerly creates the combination (argument lists) and returns that (Vec<CallArguments>) but I thought we could make it lazier by converting the return type of expand from Iterator<Item = Vec<CallArguments>> to Iterator<Item = Iterator<Item = CallArguments>> but that's proving to be difficult to implement mainly because we need to maintain the previous expansion to generate the next expansion which is the main reason to use std::iter::successors in the first place.

Another approach would be to eagerly expand all the argument types and then use the combinations from itertools to generate the combinations but we would need to find the "boundary" between arguments lists produced from expanding argument at position 1 and position 2 because that's important for the algorithm.

Closes: astral-sh/ty#868

Test Plan

Add test case to demonstrate the limit along with the diagnostic snapshot stating that the limit has been reached.

@dhruvmanila dhruvmanila added the ty Multi-file analysis & type inference label Aug 22, 2025
@github-actions
Copy link
Contributor

github-actions bot commented Aug 22, 2025

Diagnostic diff on typing conformance tests

No changes detected when running ty on typing conformance tests ✅

@github-actions
Copy link
Contributor

github-actions bot commented Aug 22, 2025

mypy_primer results

No ecosystem changes detected ✅
No memory usage changes detected ✅

@dhruvmanila dhruvmanila force-pushed the dhruv/limit-argument-expansion-size branch from 61c5245 to 6df342d Compare August 22, 2025 10:26
@dhruvmanila dhruvmanila marked this pull request as ready for review August 22, 2025 13:55
@carljm
Copy link
Contributor

carljm commented Aug 22, 2025

proving to be difficult to implement mainly because we need to maintain the previous expansion to generate the next expansion

I think it is good to move on from this issue now, if the limit takes care of the runaway problem on the fuzzer code sample, and we don't have reports of this in real code. But for future, I'm curious -- why is the above hard to implement? It sounds like a custom-implemented iterator that stores some state, which doesn't seem particularly unusual?

@AlexWaygood AlexWaygood removed their request for review August 25, 2025 09:19
@dhruvmanila
Copy link
Member Author

But for future, I'm curious -- why is the above hard to implement? It sounds like a custom-implemented iterator that stores some state, which doesn't seem particularly unusual?

I'll try to explain it using this example: (bool, int | str, A | B | C), assuming that we're at the final argument in the expansion process, one of the data that we'd need to maintain is all the argument lists that resulted in expanding all the previous arguments i.e., 1 and 2 in this example. This means that when the expansion is at A | B | C argument, the data would contain (True, int, ...), (False, int, ...), (True, str, ...), (False, str, ...) (4) argument lists. Imagine this at a larger scale where the previous iteration could generate 200 argument lists which needs to be kept between iteration.

One way to resolve this could be that we only maintain the expanded types and generate the combinations for each iteration manually i.e., in the above example, for the first argument, we'd generate 2 combinations by expanding bool to True and False and we'll store the expanded list. Then, for the second argument, we'll expand int | str and generate 4 combinations. In this implementation, we'd save memory but each iteration would have to generate the combinations every time.

Does this make sense?

But, now that I think this out loud, maybe the second solution isn't too bad.

@dhruvmanila dhruvmanila enabled auto-merge (squash) August 25, 2025 09:39
@dhruvmanila dhruvmanila merged commit 376e3ff into main Aug 25, 2025
37 checks passed
@dhruvmanila dhruvmanila deleted the dhruv/limit-argument-expansion-size branch August 25, 2025 09:43
second-ed pushed a commit to second-ed/ruff that referenced this pull request Sep 9, 2025
…al-sh#20041)

## Summary

This PR limits the argument type expansion size for an overload call
evaluation to 512.

The limit chosen is arbitrary but I've taken the 256 limit from Pyright
into account and bumped it x2 to start with.

Initially, I actually started out by trying to refactor the entire
argument type expansion to be lazy. Currently, expanding a single
argument at any position eagerly creates the combination (argument
lists) and returns that (`Vec<CallArguments>`) but I thought we could
make it lazier by converting the return type of `expand` from
`Iterator<Item = Vec<CallArguments>>` to `Iterator<Item = Iterator<Item
= CallArguments>>` but that's proving to be difficult to implement
mainly because we **need** to maintain the previous expansion to
generate the next expansion which is the main reason to use
`std::iter::successors` in the first place.

Another approach would be to eagerly expand all the argument types and
then use the `combinations` from `itertools` to generate the
combinations but we would need to find the "boundary" between arguments
lists produced from expanding argument at position 1 and position 2
because that's important for the algorithm.

Closes: astral-sh/ty#868

## Test Plan

Add test case to demonstrate the limit along with the diagnostic
snapshot stating that the limit has been reached.
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.

Overload argument type expansion leads to combinatoric explosion

3 participants