I'm new to Rust, so it's entirely possible I'm missing something obvious here, but I've run into a weird scenario where the VS Code extension (I've disabled every other extension) is reporting problems which don't exist.
I've written a macro that allows me to annotate types with an identifier, and build an enum containing variants for each of those types, as well as a 'type enumeration' enum which is identical, but without any associated data on the variants. It builds A-OK with no complaints—cargo build
works.
However, the Rust extension in VS Code reports four errors (E0428):
the name `Message1` is defined multiple times
`Message1` redefined here
note: `Message1` must be defined only once in the type namespace of this enum
the name `Message1` is defined multiple times
previous definition of the type `Message1` here
note: `Message1` must be defined only once in the type namespace of this enum
the name `Message2` is defined multiple times
`Message2` redefined here
note: `Message2` must be defined only once in the type namespace of this enum
the name `Message2` is defined multiple times
previous definition of the type `Message2` here
note: `Message2` must be defined only once in the type namespace of this enum
The actual code in question is:
#[message(Test)]
pub struct Message1 {
pub val: i32,
}
#[message(Test)]
pub struct Message2;
#[write_message_type(Test)] // Red squiggly
pub enum Test {
}
cargo expand
outputs:
pub struct Message1 {
pub val: i32,
}
pub struct Message2;
pub enum TestTypes {
Message1,
Message2,
}
pub enum Test {
Message1(Message1),
Message2(Message2),
}
Given the expansion is correct (and the crate builds and produces the expected outputs when wrapping & unwrapping messages), I'm not sure whether the macro code has much relevance, but just incase, here it is. Be forewarned, it's quick, dirty, unfinished, and my first attempt at writing a macro (without having done enough reading beforehand, frankly).
lazy_static! {
static ref MESSAGE_MAP: Mutex<HashMap<String, Vec<String>>> = Mutex::new(HashMap::new());
}
#[proc_macro_attribute]
pub fn message(attr: TokenStream, item: TokenStream) -> TokenStream {
match MESSAGE_MAP.lock() {
Ok(mut map) => map.entry(attr.to_string()).or_insert(Vec::new()).push(
syn::parse::<syn::DeriveInput>(item.clone())
.expect("Invalid target for message attr")
.ident
.to_string(),
),
Err(e) => panic!("Message map lock poisoned: '{}'.", e.to_string()),
}
item
}
#[proc_macro_attribute]
pub fn write_message_type(attr: TokenStream, _: TokenStream) -> TokenStream {
let name = attr.to_string();
match MESSAGE_MAP.lock() {
Ok(map) => match map.get(&name) {
Some(entries) => {
let message_type_enumeration_name = syn::parse_str::<syn::Ident>(&(name.clone() + "Types")).expect("Invalid message wrapper name.");
let type_entries: Vec<_>= entries.iter().map(|e| syn::parse_str::<syn::Ident>(e).expect("Something went horribly wrong enumerating the wrapped message types")).collect();
let message_wrapper_name = syn::parse_str::<syn::Variant>(&name).expect("Invalid message wrapper name.");
let wrapper_entries: Vec<_>= entries.iter().map(|e|{
let mut variant = e.clone();
variant += "(";
variant += e;
variant += ")";
syn::parse_str::<syn::Variant>(&variant).expect("Something went horribly wrong enumerating the wrapped message types")}).collect();
(quote! {
pub enum #message_type_enumeration_name {
#(#type_entries),*
}
pub enum #message_wrapper_name {
#(#wrapper_entries),*
}
})
.into()
}
None => panic!("Tried to expand message type wrappers '{}', but no message types were recorded for it!", name)
},
Err(e) => panic!("Message map lock poisoned: '{}'.", e.to_string()),
}
}
VS Code is up to date, the Rust extension is up to date, and my Win 10 installation is up to date. As I can build, it's not the end of the world, but it would be nice to not have those errors in the problem panel; if it's a problem with my code, and not the extension, my apologies.
I have had this problem many times, it has been around for a while now. In my experience rust-analyzer does not have this problem and that seems to be the language server that is being actively developed. If you're using RLS with this extension try switching to rust-analyzer, either as this extension's back-end or by using its own VS Code extension. I think rust-analyzer is eventually going to be RLS 2.0 but it is already the easier-to-use and, frankly, just plain better IDE experience.
I only use this because I use an alternative grammar (dustypomerleau.rust-syntax) that requires this extension. Using this extension with rust-analyzer required manually installing a binary, which is another problem that has persisted for months. That's why I recommend using the other extension. Despite this and RLS being the de jure defaults rust-analyzer seems to have eclipsed them.
@JKAnderson409 note that the dustypomerleau.rust-syntax
syntax was merged into rust-analyzer
recently.
@JKAnderson409 note that the
dustypomerleau.rust-syntax
syntax was merged intorust-analyzer
recently.
Yeah that was good news. I actually asked dustypomerleau to try to have it merged on the same day that I made that other comment. It's made it easier to use the nightly releases of rust-analyzer because I don't need to overwrite the grammar every day. The rust-analyzer extension is now my only Rust extension.
I'm grateful that @dustypomerleau put in the effort to go through the review process so that the rust-analyzer extension can ship with a great TextMate grammar.
Most helpful comment
Yeah that was good news. I actually asked dustypomerleau to try to have it merged on the same day that I made that other comment. It's made it easier to use the nightly releases of rust-analyzer because I don't need to overwrite the grammar every day. The rust-analyzer extension is now my only Rust extension.
I'm grateful that @dustypomerleau put in the effort to go through the review process so that the rust-analyzer extension can ship with a great TextMate grammar.