Description
The issue with checking all crates
Currently when rust-analyzer runs a flycheck it always runs on the entire workspace. In large workspaces (or in my case a large rust-project.json project) running a check build on many crates can significantly increase the time it takes to get results for the current crate. This is especially an issue in build systems that don't support cargo's functionality of streaming diagnostics over stdout as it goes, so if 1 crate in the workspace takes on the order of minutes to run a check build and the rest take milliseconds, you end up having to wait minutes every time a transitive dependency of that long-check-time crate changes to get diagnostics in your editor. Even if you do have streaming diagnostics, not knowing which crate has been modified means the build system can't schedule the check builds to prioritize the one you're actually editing, which causes the same problem of waiting for lots of other crates to check and harming your time-to-first-diagnostic.
Potential solution
As I understand it rust-analyzer has the required info (the path of the modified file) to only run a check build on the single crate that changed. In the case of a cargo command it could do this automatically by mapping the changed file to the changed crate and passing -p crate_name
rather than --workspace
to the flycheck subcommand invocation. For rust-project.json based build systems, if checkOnSave.overrideCommand
were to expose some sort of variable expansions like $crate_name
, $source_root
, and/or $changed_file
then it would be possible for GN/Bazel/Buck/etc. to use that info to only perform a check build on the modified crate.
Example: fuchsia's codebase
In fuchsia's codebase (where we use rust-project.json with GN) we already have support for this "map $changed_file
to the changed target and only run a check build on that crate" functionality, but it can't be used from the editor because there's no way for rust-analyzer to pass the path of the modified file through to our check build wrapper script. Passing that info along makes the difference between "check on save" being viable or not for our developers due to the latency of checking potentially thousands of crates (including outliers that take minutes to check) vs just one.
Config/UI concerns
I realize that the vast majority of cargo workspaces aren't large enough that this is an issue, and it's possible that people have come to expect seeing errors in downstream crates from the same workspace when editing a dependency, so I think it'd make sense to still default to the "check all crates" behavior. For huge workspaces and monorepos like ours however, getting diagnostics on save just for the current crate, and having the ability to manually trigger workspace-wide checks in the editor (#12870) would be a preferable workflow.
The least intrusive way I can think of to add the functionality would be to introduce a boolean flag like checkOnSave.onlyCurrentCrate
which makes cargo based flychecks automatically use -p crate_name
instead of --workspace
, and enables the expansion of those variables for checkOnSave.overrideCommand
. Alternatively, if we're pretty confident that noone's overrideCommand contains the strings that we choose for variable expansion, we could just enable the expansion by default in that case.
I'd love some guidance on whether this is actually a good idea or if there are issues with trying to unambiguously map source files to crate roots/names, or other issues with how LSP diagnostics requests work. Also if there are complications with getting cargo commands to work with this functionality I'd be fine putting off that work and just implementing support for rust-project.json + custom flycheck commands, both because that's what we'd need for fuchsia and because rust-project.json based projects tend to be more monorepo-y so they'd care about this feature more.
I also haven't considered the non-flycheck diagnostics that rust-analyzer provides itself. Do those checks also currently run on the entire workspace (and if so is this affected by cachePriming.enable
)? Would it make sense to tie the two such that checkOnSave.onlyCurrentCrate
applies to both the flycheck and native rust-analyzer diagnostics?