Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Conversation

@jez
Copy link
Collaborator

@jez jez commented Mar 23, 2022

Motivation

We want to be able to service certain LSP requests on stale data when the live data is currently being updated.

In those cases, the LSP's typechecker thread holds exclusive write access to the GlobalState object while it runs a slow path. The slow path is designed to throw away all the GlobalState in a program and recompupte it.

But we keep the old GlobalState around just in case we want to cancel the running slow path (e.g., we might want to do so if a subsequent edit comes along, and the combination of the previous edit + new edit is enough to take the fast path).

Importantly, it's not possible to mutate the GlobalState that we're holding on reserve for if we can cancel an edit (being able to use it to potentially cancel a slow path requires that it not be subtly changing under the hood).

Also, we don't store the result of running namer and resolver on a tree, only the result of running the index phases. I don't quite remember the historical context here, but instead for every fast path (including every LSP query run), we re-run namer and resolver over the (cached by LSP) indexed trees. So we have a unique situation—to serve stale LSP queries, we have to be able to run namer and resolver over already-indexed trees, but not mutate GlobalState.

This PR implements the first half of that picture: it runs only the parts of namer that don't mutate GlobalState. It achieves this by aggressively throwing away subtrees. Normally the SymbolDefiner portion of namer would guarantee that every definition that appears in the source code also gets a symbol in the SymbolTable. But since we're running namer and resolver on newly-indexed trees, there might be new definitions that don't yet have entries in the symbol table.

Rather than attempt to fake it, and return something like a stub symbol for which .exists() is true, we've opted to just delete the subtrees with new definitions entirely. This is very defensive, but makes it easy to ensure that invariants are upheld. For example, it means that ctx.owner (used by things like methodOwner() and enclosingClass() are still reliable. It ensures that things like the number of arguments in a method def tree matches the number of ArgInfo objects in the symbol table. Etc.

This obviously comes at the downside that if you e.g., change a class's name, this will cause a blocking, slow path edit and you won't even be able to do things like hover over constant literals inside that class def until the slow path finishes.

But it does mean that if you e.g. add a T::Struct above your class, and then you go back into your class and try to hover while the slow path edit is running, those queries will work (hypothetically—the LSP side of things will arrive in #5469).

Test plan

To test this change, we've repurposed our whole testdata suite.

The idea is basically: after indexing but before running namer, make a copy of the just-indexed tree and run the best-effort namer on it, but only for the purpose of exercising the ENFORCEs.

There will still be lots of errors, but

  • they might not be the same errors (because we might have deleted parts of the tree where those errors would have been reported)
  • we don't actually care about the errors, because LSP is only ever going to show a limited set of LSP queries, like hover, and it's going to show it with a message like "hey there, this might be wildly wrong, wait a little while and it'll fix itself"

@jez jez force-pushed the jez-name-without-stubs branch from 46bbcd2 to 874893d Compare March 24, 2022 21:39
@jez jez marked this pull request as ready for review March 25, 2022 01:30
@jez jez requested a review from a team as a code owner March 25, 2022 01:30
@jez jez requested review from froydnj and removed request for a team March 25, 2022 01:30
@jez jez merged commit d8a1aea into master Mar 25, 2022
@jez jez deleted the jez-name-without-stubs branch March 25, 2022 21:06
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants