简体   繁体   中英

proc_macro_attribute seems to not play nicely with struct impls and traits

I'm trying to get a procedural macro to print out information about variables in my function inputs. When I test the macro in a separate crate, I get an error from the compiler that I'm not implementing the trait functions even though the trait functions are clearly implemented.

Please ignore that the attr isn't returning anything yet; I'm building it together but ran into this issue first.

The procedural macro definition:

extern crate proc_macro;
use self::proc_macro::TokenStream;
use syn::{parse_macro_input, ItemFn};

#[proc_macro_attribute]
pub fn my_macro(attr: proc_macro::TokenStream, item: proc_macro::TokenStream) -> proc_macro::TokenStream {
    println!("item: \"{}\"", item.to_string());
    let func = parse_macro_input!(item as ItemFn);
    let input_funcs = func.sig.inputs
            .iter()
            .map(|item| println!("{:?}", try_me(item)));

    //input_funcs
    attr
}

fn try_me(arg: &syn::FnArg) -> String {
    match arg {
        syn::FnArg::Receiver(_r) => "is receiver".to_string(),
        syn::FnArg::Typed(_p) => "is pattern type".to_string()
    }
}

the testing crate:

use my_macro::{my_macro};

pub trait TestTrait {
    #[my_macro]
    fn my_func(&self, x: u8, y: String) -> u32 {
        return 0;
    }
    #[my_macro]
    fn empty_func(&mut self);
}

#[cfg(test)]
mod tests {
    // Note this useful idiom: importing names from outer (for mod tests) scope.
    use super::*;
    #[derive(Default)]
    struct MyStruct{
        pub a: u8
    }
    impl TestTrait for MyStruct{
        #[my_macro]
        fn my_func(&self, _x: u8, _y: String) -> u32 {
            return 0;
        }
        #[my_macro]
        fn empty_func(&mut self) {
            self.a = 5;
        }
    }
    #[test]
    fn test_empty_func() {
        let mut struc = MyStruct::default();
        let interface = &mut struc as &mut dyn TestTrait;
        interface.empty_func();
        assert_eq!(5, contract.a);
    }

    #[test]
    fn test_macros() {
            let mut struct = MyStruct::default();
            let interface = &mut struc as &mut dyn TestTrait;
            let zero = interface.my_func(8, "hello".to_string());
    }
}

yields errors such as:

item: "fn my_func(&self, x: u8, y: String) -> u32 { return 0; }"
item: "fn my_func(&self, x: u8, y: String) -> u32 { return 0; }"
item: "fn empty_func(&mut self);"
item: "fn empty_func(&mut self);"
error: expected curly braces
  |
9 |     fn empty_func(&mut self);
  |                             ^

error: expected curly braces
  |
9 |     fn empty_func(&mut self);

and

error[E0599]: no method named `empty_func` found for mutable reference `&mut dyn TestTrait` in the current scope
   |
34 |         interface.empty_func();
   |                   ^^^^^^^^^^ method not found in `&mut dyn TestTrait`

error[E0599]: no method named `my_func` found for mutable reference `&mut dyn TestTrait` in the current scope
   |
42 |             let zero = interface.my_func(8, "hello".to_string());
   |                                  ^^^^^^^ method not found in `&mut dyn TestTrait`

If I take off the procedural macro attribute, this compiles. What is going on here and what should I do differently?

Found this out after discussion in the Rust Discord. Props to Jebrosen. The problem is that I'm returning attr and attr currently has nothing assigned to it. Thus when the compiler goes to expand the code it actually shrinks the code to...nothing. I am essentially deleting my code at compile time. Instead of doing this to test out the proc macro, I should instead use quote and quote the function as is while testing things out with printlns. Hope this helps someone in the future.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM