For example for this code:
trait Foo {
fn foo(&self) {}
}
struct Bar;
impl Foo for Bar {}
mod test {
use super::Bar;
fn test() {
Bar.foo();
}
}
22 | Bar.foo();
| ^^^ method not found in `Bar`
|
= help: items from traits can only be used if the trait is in scope
help: the following trait is implemented but not in scope; perhaps add a `use` for it:
|
20 | use crate::Foo;
|- I'm already using 'cargo check' as my linter (rustc doesn't understand modules, seemingly).
- My setup works for JavaScript/React/Svelte, SQL, C/C++, Python, and Go.
- It can't be the case that (Neo)Vim + Ale [0] is arcane. Also the link in "Tools" from rust-lang.org goes to the rust.vim repo, which defaults to Syntastic, which I'm pretty sure has the same issue.
I don't necessarily think I should extrapolate from my experience to a broader "Rust is different for little/no gain" critique I've made in the past, but I sure want to haha. And to kind of anticipate a little, I wouldn't blame Ale here because--again--it works for everything else.
But anyway, yeah I've mostly given up on linting and I just run 'cargo check' in a terminal buffer now. It's probably something as simple as adding a command-line argument to... idk cargo or rustc to make the additional "help" format a little more amenable to Ale? Maybe I'll take a crack at it when I get some time.
I did find this blog post, which seems to suggest there may be a bit of extra config required to get rust-analyzer going with ALE: https://petermalmgren.com/rc-batch-day-9/
Good luck!
One of the things I've really enjoyed about the Free Software ecosystem is choice, like mostly before Rails the attitude was "we don't presume to know the best anything, here are some options." I'm not saying there aren't tradeoffs (complexity, bitrot, 7 half-baked options vs. 1 incredible one), only that I kind of low-key resent the "opinionated" software that's out there. I guess I don't really see it as opinionated (like I think Rails' convention over configuration was actually a pretty good idea and exemplifies the "execute" phase of the explore/execute cycle of tooling), I see it as "flashy and targets the 80% use-case to get mindshare".
To be clear, I don't think rust-analyzer is that opinionated or flashy or lazy. I think it's awesome. But Rust's linting story is essentially "why would you use anything besides rust-analyzer, language servers are awesome and have no downsides." Which like, yeah they do.
[0]: https://github.com/dense-analysis/ale/blob/master/doc/ale.tx...
And yeah rust-analyzer is definitely the happy path, but if you were trying to get by without a language server (not going to lie on a very large rust project rust-analyzer’s RAM usage can get up there), I think that `cargo check` output properly parsed and displayed in your linter would probably get you a huge portion of what you need. Between that and rustfmt, I think the only thing you’d be missing would be go to definition and that kind of thing (but you can set that up with a ctags-style thing or just replace with fuzzy grep).
In fact, before I figured out how to get rust-analyzer working in emacs, I used a setup where `cargo check` ran on save, and the output showed up in flycheck. From what you said about ALE, it sounds like you could set it up the same way. The main thing would be making sure there’s a way to get the FULL output of `cargo check`, probably not inline because there tends to be a lot of it. But e.g. with emacs I get error underlines that show the first part of the error, and then I can expand that in a popup window, or run cargo check, which opens cargo check in another buffer, with the output parsed so that if I press enter on an error, it brings me to the location in the code.
All of which is to say that it is doable! Maybe it would just take some extra ALE configuration, since the defaults are probably oriented towards people who are using rust-analyzer.
I use rust-analyzer in emacs, but it’s available in any editor that supports language servers.
With my setup, I’ll start typing a method, get a completion for the trait method I want with the trait indicated, and select the completion. The trait is then automatically imported and the method is completed.
`import Foo.Bar ()`
Which looks like it's just importing nothing at all (`()`) but is actually pulling in some traits and nothing else.
You don't see this often because "orphan instances" (instances defined in a file besides the location of the trait definition or the type definition) are discouraged, but they do occur.
I had also thought that there was a reason one could need that pattern to import instances even in the absence of orphans, but on reflection I think I was mistaken.