rustrust-macrosrust-decl-macros

How do I early return in declarative macros and infer the return type?


I have a macro, which just generates an instance of a struct, as below:

macro_rules! foo {
    () => {{
        let baz_val = baz();
        
        let bar_val = match bar() {
            Ok(val) => val,
            Err(err) => {
                return Err(err);
            }
        };
        
        Ok(Foo(baz_val, bar_val))
    }};
}

As you can see, I do an early return in macro depending on bar() function's result. That's, however, resolves as an error, saying:

   Compiling playground v0.0.1 (/playground)
error[E0308]: mismatched types
  --> src/main.rs:23:24
   |
23 |                 return Err(err);
   |                        ^^^^^^^^ expected `()`, found enum `Result`
...
32 |     let foo_val = foo!();
   |                   ------ in this macro invocation
   |
   = note: expected unit type `()`
                   found enum `Result<_, String>`
   = note: this error originates in the macro `foo` (in Nightly builds, run with -Z macro-backtrace for more info)

For more information about this error, try `rustc --explain E0308`.

Here's also the permalink to the playground that has full minimum reproducible sample.

I think the problem here is type inference. I'd like to return an instance of FooResult in the sample, but the macro cannot infer it.

So, how do I early return and infer/define the return type in the declarative macros?


Environment


Solution

  • return is used in functions not in macros. For the expected behaviour you can wrap the macro into a closure and call it inmediatly:

    macro_rules! foo {
        () => {{
            (|| {
            let baz_val = baz();
    
            let bar_val = match bar() {
                Ok(val) => val,
                Err(err) => {
                    return Err(err);
                }
            };
    
            Ok(Foo(baz_val, bar_val))
            })()
    
        }};
    }
    

    Playground