[ty] Optimize protocol subtyping by removing expensive and unnecessary equivalence check from the top of Type::has_relation_to()
#19230
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Summary
A full equivalence check at the top of
Type::has_relation_to()
is unnecessary. All our mdtests, and all our property tests, pass if it is replaced with a much cheaper naive equality check. The reason for this is that equivalence is generally the same as equality for atomic types (types that cannot contain other types); and "non-atomic" types (types that can contain other types within them) all have comprehensive subtyping logic lower down in theType::has_relation_to()
method. For every non-atomic type in our model currently, our subtyping logic is sufficiently generalized to also cover equivalent types; there's no need to check for equivalence separately.Up till now, the inefficiency here hasn't mattered that much, because comparing two nominal types for equivalence is generally pretty cheap. (It is not cheap for large unions, large intersections or large tuples (or combinations of the three), but these are all somewhat rare.) Unfortunately, however, comparing two structural types for equivalence can be extremely expensive: determining whether two protocols are equivalent can necessitate a full structural check between the two underlying interfaces. That means that this PR yields a 7% speedup when checking
DateType
, which has some large protocols in it. We also see 1% speedups on a lot of other micro- and macro-benchmarks for ty, and no slowdowns: https://codspeed.io/astral-sh/ruff/branches/alex%2Fremove-equivalent-check?runnerMode=Instrumentation.Test plan
QUICKCHECK_TESTS=100000 cargo test --release -p ty_python_semantic -- --ignored types::property_tests::stable
passes