I’m pretty excited about the libsyntax2 work. I see a lot of potential to improve features in IDEs and help the compiler towards very incremental compilation. It would be great to improve Racer with it, for one thing.
However, my impression is that libsyntax2 allows us to do more, but doesn’t help that much with the type-driven actions which the RLS currently provides. Or rather it would let us do something similar and faster, but not as accurate (without implementing all of type checking there).
The perfect end-state I envision is to have a single rust-analyzer library, which is used by both command-line compiler as well as the language server
This is pretty much my ideal end-state too. And I also worry about how to get there. In particular the worry I expressed to Niko is that we use it in the RLS, but then there isn’t the resources to use it in the compiler and we have much increased maintenance costs for the RLS.
the rust-analyzer idea, is basically moving 80-90% of the compiler into a library. Which I think is a great idea, I’m a big fan of moving stuff out of the repo. However, there are issues with doing so (e.g., linking std versions to compiler versions) and realistically, from the RLS perspective, we won’t get anything new, it’s just an implementation detail.
The second reason for this is that working on RLS itself is super hard. …
This is a bit of an exaggeration, if you pull and use that day’s nightly it will work 8 times out of 10. It’s been worse recently because of the increased rate of changes for the edition. However, I totally agree if it would be better if this didn’t happen.
Half of the commits to RLS is “update X”, and there’s also a busy-work process of updating RLS in rust-lang/rust.
This is about right and it is extremely frustrating. I think though that any solution in this space will have these problems. There’s either API compat issues or you have the harder problem of keeping up with language changes without any compiler errors. I believe we can do much better by improving the tooling here - either using a mono-repo or some kind of structured integration of changes to Rust components.
As an example, I’ve implemented “run the test under cursor” feature both …
This isn’t really a fair test. It is something that libsyntax2 should be good at, but which isn’t a goal for the RLS design.
The tests in the RLS are bad, but I think rather than being a reason to throw it all out and start again, we should just write more (and better) tests.
The fact that libsyntax2 and RLS repositories have approximately the same number of Rust source code lines, if you exclude tests and generated code, also hints that adding a line of code to RLS is very expensive
I’m not sure that is a useful metric? If you really want to compare lines of code you should include half the compiler and the RLS support crates. I won’t deny that it is relatively difficult to add features to the RLS, but I expect that two years down the line when libsyntax2 is more complete it will be a lot more expensive to add code there too.
I thought that RLS was fairly close to being a “server API” around Racer, hence its functionality is orthogonal to libsyntax2 , which is a Rust frontend.
This is pretty true, and important.
Capitalize on and improve upon existing Racer, by incrementally substituting its heuristics with precise algorithms from Code Analyzer.
This indeed sounds like a good idea. We’ve also thought about the RLS giving type information to Racer so that it can complete a lot more. It might be useful to do the same for your code analyzer?
Capitalize on existing save-analysis infrastructure by using it for dependencies .
The hard part of dealing with deps is that you have to model the Cargo project. Hopefully some Cargo refactoring will make this much easier, but you still have to deal with some issues in any case (and this is where a lot of the RLS’s nasty concurrency issues come from).
In contrast, achieving 100% feature/bug parity with libsyntax1 will require huge effort.
ISTM that we have to address this eventually whatever approach you take and it will be a huge effort
Some people think that this would be fixed by incrementally improving RLS
I’m strongly in this camp. While most of the points you make are true, none of them are really about the foundation of the RLS and I think they can mostly be addressed without throwing everything away. It is a well-known true-ism in software engineering that you can have a clean prototype, but as you add features you inevitably end up with less clean code. We’ll surely have a bunch of problems with a clean start, we’ll just have wasted a year or so before we get to that point.
The second big RLS problem is its “shared mutable state is fine” handling of concurrency
We can do much better. Fundamentally the concurrency issues are difficult due to wanting to be responsive to the user and still be as accurate as possible. Using snapshots or something like that might be a reasonable improvement.
I think it very much depends on what you want to do as to whether repeatable read is important. AFAIK, nothing in the RLS currently needs it? We might deliver slightly out of date data, but that is usually not a problem and if the user is typing, then it’s the best you can do.
The third big RLS problem is that it is deeply integrated with the build system and runs rustc to get save-analysis data.
I don’t see this as a problem. Effectively (and this will require some work in Cargo) we will ask Cargo how to build a project and then have a very quick way to query "this file has changed what should be rebuilt) and then we do it. Other build systems will use Cargo as an abstraction layer. You never have to do a full build unless you want to (or say the Cargo.toml is changed).
If you can only guess at the project layout, I don’t think you can get accurate type info.
a significant chunk of RLS is build orchestration, which could have been just cargo check otherwise
This is not quite right. The complexity comes from tracking dependencies in workspaces where there might be multiple current crates and having files in memory which have been changed. My hope is that this can be factored out of the RLS and into Cargo.
if someone writes a tool, that’s great, but they’ll just have to keep up with upstream’s pace of development themselves
this has not worked in the past. If a tool appears which make the libs de factor stable, and people use that tool then the compilers are in an awful bind and basically have to ensure back compat.
Maintenance of the RLS
My hope is that by factoring things out to Cargo, and relying on save-analysis and the proposed query system for the compiler, we can ensure that the RLS is a fairly thin intermediary which doesn’t need too much maintenance and that by maintaining the compiler and Cargo, the RLS is also mostly looked after.
In the short-term making incremental improvement to the compiler, Racer, and the RLS is something that can be reasonably done with the resources we have. Rewriting the compiler front-end would seem to need lot’s more people working for a long time