0

tl;dr I think I want a macro declaration to infer type (how do I create this macro?)

This macro fails to compile (rust playground)

macro_rules! debug_assert_none {
    ($($arg:tt),+) => {
        $(
            if cfg!(debug_assertions) {
                match $arg {
                    None => {}
                    Some(..) => panic!("not None")
                }
            }
        )+
    };
}

#[test]
fn test_debug_assert_none() {
    debug_assert_none!(None);
    debug_assert_none!(None, None);
}

Fails with error

error[E0282]: type annotations needed
  --> src/lib.rs:15:24
   |
15 |     debug_assert_none!(None);
   |                        ^^^^ cannot infer type of the type parameter `T` declared on the enum `Option`
   |
help: consider specifying the generic argument
   |
15 |     debug_assert_none!(None::<T>);
   |                            +++++

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

How do I satisfy the required type declaration for a presumed Option? Or is there some other problem with this code?

JamesThomasMoon
  • 6,169
  • 7
  • 37
  • 63

1 Answers1

0

How is the compiler supposed to know the size it has to reserve for a bare None? It can't because it could hold any other type. As soon as you use your macro in a real world scenario, the type should be possible to infer, but if you want to pass in a bare None, you can always specify it explicitly by just giving it a type; usually one uses unit () for unused parameters.

debug_assert_none!(None::<()>);

Of course, you could also change your macro to help type inference but that would restrict the macro to work only with values of that one type:

macro_rules! debug_assert_none {
    ($($arg:tt),+) => {
        $(
            if cfg!(debug_assertions) {
                let x: &Option<()> = &$arg;
                match $arg {
                    None => {}
                    Some(..) => panic!("not None")
                }
            }
        )+
    };
}
kelsny
  • 23,009
  • 3
  • 19
  • 48
cafce25
  • 15,907
  • 4
  • 25
  • 31
  • `let` imposes some constraints on temporaries. Better to use `match $arg { None::<()> => ... }`. – Chayim Friedman Mar 20 '23 at 05:13
  • @ChayimFriedman I can't think of any constraints this `let` imposes which aren't desired (`T` of the `Option`) or don't have to hold true anyways can you elaborate? – cafce25 Mar 20 '23 at 10:34
  • Well, not in case of `Option<()>`, but in other cases [yes](https://play.rust-lang.org/?version=stable&mode=debug&edition=2021&gist=593e3424ec7f3110f6e9ebc18ec09d0c). – Chayim Friedman Mar 20 '23 at 11:17