Macro error: variable 'param' is still repeating at this depth

Hello!

I would like to create a macro that creates functions that optionally has parameters (for example):

macro_rules! declare_function {
    ($func: ident $(, $param: ident, $param_type: ty)? ) => {
        fn $func($param: $param_type) {
            let v: Vec<$param_type> = vec![$param];
            Println!("{?}", v);
        }
        
    };
}

fn main(){
    declare_function!(foo);
    foo(); // will print empty Vec
    
    let a: i32 = 321;
    declare_function!(bar, a, i32);
    bar(a); // will print a Vec with the contents of a
}

This produces the error:

variable 'param' is still repeating at this depth

Any help?

Many thanks!

1 Like

Almost: you've forgotten to double-check whether the optional parameters have been passed or not:

macro_rules! declare_function {
    ($func: ident $(, $param: ident, $param_type: ty)? ) => {
        // first, specify the parameters only if they were passed
        fn $func( $( $param: $param_type )? ) {
            $( // second, create the vector only if there's data for it
                let v: Vec< $param_type > = vec![ $param ];
                println!("{:?}", v);
            )? 
            // the following isn't going to work, though:

            // let v $(: Vec<$param_type> )? = vec![ $($param)? ];
            // println!("{:?}", v);

            // error[E0282]: type annotations needed for `Vec<T>`
            // (Rust won't let you create a function for a vector,
            //  holding objects of a type, not known beforehand)
        }
    };
}

fn main(){
    declare_function!(foo);
    foo(); // won't print anything
    
    let a: i32 = 321;
    declare_function!(bar, a, i32);
    bar(a); // will print a Vec with the contents of a
}
3 Likes

GREAT! That was REALLY informative! Thank you.

In my real world example however, do you have any idea why It errors?

macro_rules! ffi {
    ($func: ident $(, $param: ident, $type: ty)? ) => {
        #[no_mangle]
        pub unsafe fn $func(
            $( $param: $type ,)?
            in_buf: *const u8,
            out_buf: *mut u8,
            width: usize,
            height: usize,
            num_pixel_components: usize,
        ) {
            let len = width * height * num_pixel_components;
            let in_buf = core::slice::from_raw_parts(in_buf, len);
            let out_buf = core::slice::from_raw_parts_mut(out_buf, len);

            let mut frame = kaleidoscope::VideoFrame {
                in_buf,
                out_buf,
                w: width,
                h: height,
                num_pixel_components,
            };

            frame.$func( $( $param: $type )? ); // erorr ($param): type ascription is experimental
        }
    };
}

Why are you passing the type to the function that you're calling?

Are you trying to call frame.func(par) or frame.func(par: i32)?

:man_facepalming:

you're 2 for 2! Thanks again. dumb mistake on my part, you're right, I didn't need to supply the type!

1 Like

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.