Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[red-knot] use fixpoint iteration for all cycles #14029

Open
wants to merge 8 commits into
base: main
Choose a base branch
from
Open

Conversation

carljm
Copy link
Contributor

@carljm carljm commented Nov 1, 2024

Pulls in the latest Salsa main branch, which supports fixpoint iteration, and uses it to handle all query cycles.

With this, we no longer need to skip any corpus files to avoid panics.

Latest perf results show a 6% incremental and 1% cold-check regression. This is not a "no cycles" regression, as tomllib and typeshed do trigger some definition cycles (previously handled by our old infer_definition_types fallback to Unknown). We don't currently have a benchmark we can use to measure the pure no-cycles regression, though I expect there would still be some regression; the fixpoint iteration feature in Salsa does add some overhead even for non-cyclic queries.

I think this regression is within the reasonable range for this feature. We can do further optimization work later, but I don't think it's the top priority right now. So going ahead and acknowledging the regression on CodSpeed.

Mypy primer is happy, so this doesn't regress anything on our currently-checked projects. I expect it probably unlocks adding a number of new projects to our ecosystem check that previously would have panicked.

Fixes #13792
Fixes #14672

@carljm carljm added the red-knot Multi-file analysis & type inference label Nov 1, 2024
Copy link

codspeed-hq bot commented Nov 1, 2024

CodSpeed Performance Report

Merging #14029 will degrade performances by 6.24%

Comparing cjm/fixpoint (c7f4213) with main (0340e23)

Summary

❌ 1 (👁 1) regressions
✅ 31 untouched benchmarks

Benchmarks breakdown

Benchmark BASE HEAD Change
👁 red_knot_check_file[incremental] 4.9 ms 5.3 ms -6.24%

Copy link
Contributor

github-actions bot commented Nov 1, 2024

ruff-ecosystem results

Linter (stable)

✅ ecosystem check detected no linter changes.

Linter (preview)

✅ ecosystem check detected no linter changes.

Formatter (stable)

✅ ecosystem check detected no format changes.

Formatter (preview)

✅ ecosystem check detected no format changes.

@MichaReiser
Copy link
Member

Nice on bringing down the regression. I'm still somewhat surprised that we see an 11% perf regression and a 4 perf regression in the salsa benchmarks (that don't have any cycles).

@carljm
Copy link
Contributor Author

carljm commented Nov 15, 2024

Yeah I planned to do some more looking at profiles; thanks for doing that!

@carljm carljm force-pushed the cjm/fixpoint branch 6 times, most recently from bbd7090 to 3189bd8 Compare February 26, 2025 17:26
carljm added a commit that referenced this pull request Mar 5, 2025
This is split out of #14029, to
reduce the size of that PR, and to validate that this "fallback type"
support in `TypeInference` doesn't come with a performance cost. It also
improves the reliability and debuggability of our current (temporary)
cycle handling.

In order to recover from a cycle, we have to be able to construct a
"default" `TypeInference` where all expressions and definitions have
some "default" type. In our current cycle handling, this "default" type
is just unknown or a todo type. With fixpoint iteration, the "default"
type will be `Type::Never`, which is the "bottom" type that fixpoint
iteration starts from.

Since it would be costly (both in space and time) to actually enumerate
all expressions and definitions in a scope, just to insert the same
default type for all of them, instead we add an optional "missing type"
fallback to `TypeInference`, which (if set) is the fallback type for any
expression or definition which doesn't have an explicit type set.

With this change, cycles can no longer result in the dreaded "Missing
key" errors looking up the type of some expression.
@carljm carljm changed the title [WIP] initial fixpoint iteration [red-knot] use fixpoint iteration for all cycles Mar 12, 2025
Copy link
Contributor

mypy_primer results

No ecosystem changes detected ✅

@carljm carljm marked this pull request as ready for review March 12, 2025 05:35
@carljm carljm requested a review from MichaReiser as a code owner March 12, 2025 05:35
Copy link
Member

@MichaReiser MichaReiser left a comment

Choose a reason for hiding this comment

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

This looks good to me. Do you think it would be useful to have any documentation on when/where to add cycle fallbacks or documentation on the cycle fallback function itself?

And very impressive that this results in only a 1% perf regression in the cold case. Nice work!

("crates/ruff_linter/resources/test/fixtures/pyflakes/F401_12.py", false, true),
("crates/ruff_linter/resources/test/fixtures/pyflakes/F401_14.py", false, true),
];
const KNOWN_FAILURES: &[(&str, bool, bool)] = &[];
Copy link
Member

Choose a reason for hiding this comment

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

Should we delete this functionality now that all known failures are fixed? Do we forsee situations where it is okay for a PR to introduce a new panic case over fixing the panic?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
red-knot Multi-file analysis & type inference
Projects
None yet
2 participants