Store and check deferred nodes by containing file #27378
Merged
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.
Fixes #26680
During checking, we collect deferred nodes which we do not want to perform analysis on until later. These nodes may not actually be in the file being checked (the only time we care about deferred nodes), since a type in one file can pull on an expression in another. In an extreme case, a single deferred node in one file can pull on literally every other type in the program in a deferred fashion - causing us to check all of those nodes when checking the original file. Add in a bit of mutual recursion, and you have a situation where we end up rechecking the same deferred nodes at the end of every file (or even just a subset, which is still quite bad), because every file "depends" on them. To avoid these redundant checks, I now store all deferrals onto a list unique to the source file the node is contained within, provided that file hasn't been checked yet. (If it has, the node should have already been checked in a deferred way and there's nothing to do.)
As this is a perf issue, I don't really have a regression test for this (testing perf issues that aren't an OOM are not something we're equipped for), but here are some charts:
Before:

After:

This is to say, this reduced the error update for the active file in the editor for this repro down from almost two seconds (sluggish, effectively a whole program check just to get updated errors for one file) to around a quarter second (where message serialization time takes a bit of overhead).