Files
neovim/runtime
jdrouhard e8e914e41d fix(lsp): semantic token request/response races #42356
Problem:
Semantic token request/response handling has several races:
- active_request and active_range_request were shared, mutable tables
  reused for every request. Responses compared a mutable request_id that
  had already been cleared on cancellation or completion, so a stale,
  cancelled, or superseded response could still be applied to live
  state.
- tokens_to_ranges mutated current_result.highlights in place and the
  range merge inserted incrementally while the decoder yielded. An
  overlapping range result could duplicate tokens or leave stale ones
  that the server no longer reported.
- mark_dirty cleared the document version but kept result_id, so a
  following request could be a delta built on tokens that a range
  request had already mutated.

Solution:
Make request/response handling identity-based and non-mutating:
- represent each in-flight request as an object captured by its response
  handler and compare identity instead of the mutable request_id.
- drop responses when there is no matching active request (cancelled,
  replaced, or already completed).
- make tokens_to_ranges a pure decoder that returns a new list, and
  merge range results separately with merge_highlight_ranges, which
  keeps tokens outside the requested range and substitutes the decoded
  tokens over the hole.
- re-check that the request is still current after decoding, since
  decoding may yield, via is_current().
- clear result_id in mark_dirty so the next request is a full request
  rather than a delta over range-mutated tokens.
- clear the active request field before cancelling it.

Add regression tests covering overlapping range results, cancelled and
superseded responses, and the mark_dirty full/delta selection. The tests
defer the fake server's response callback to reproduce the races.

AI-assisted
2026-10-19 11:33:14 -04:00
..
…
…
…