Why building a Rust LSP is hard
summary
Building a Language Server Protocol (LSP) for Rust is significantly more complex than building a compiler because it requires producing useful, real-time answers from partial, often incorrect, or incomplete code. While a compiler has a binary state of success or failure, an LSP must provide incremental value to the user immediately, necessitating sophisticated indexing strategies and a constant effort to guess user intent. The architectural differences between tools like rust-analyzer and Rust Glancer demonstrate that there is no single correct approach, but rather a series of trade-offs between memory usage, startup speed, and analysis precision.
key points
- LSPs must handle a virtual file system to synchronize editor edits with the actual disk, using source generations to avoid race conditions and parallelize read queries without blocking the user.
- Indexing for Rust occurs in layers—from parsing and item tree building to definition maps and body resolution—where the server must often use fixed loops to resolve dependencies and macros that introduce new items into the scope.
- Unlike compilers, LSPs must be resilient to broken code, utilizing Concrete Syntax Trees (CSTs) and heuristic-based guessing to provide completions and hover information even when the code is syntactically incorrect.
who should read it
Software engineers and language tool developers interested in the internal architecture of IDE tooling and the specific challenges of implementing the Language Server Protocol for a complex language like Rust.
discussion positive
consensus
Commenters generally agree that while the Language Server Protocol (LSP) introduces overhead due to IPC and JSON serialization, it is a pragmatic necessity for fault isolation and cross-editor compatibility. There is a shared recognition that LSPs must balance the tension between low-latency 'best-effort' editing help and comprehensive, high-latency semantic analysis. While some argue that in-process plugins would be more performant, the consensus leans toward separate processes to prevent buggy plugins from crashing the editor.
top insight
A language server author suggests that instead of attempting full syntax recovery for broken code, LSPs should parse documents up to the point of the error to maintain local context for autocompletion. By combining this partial parse with a cached version of the last valid document state, the server can provide high-quality suggestions even during active editing. This approach avoids the 'dead-end' of complex syntax recovery rules while remaining performant.
Generated by an LLM from the article and thread. Check the sources before relying on it.