Generic types in declarative macros


#1

I was trying to write a test suite and benchmark generator for a several generic structs which share a common interface (they all implement the same trait, as a matter of fact), and got the impression that declarative macros were the right tool for this. But then I realized that there is no obvious way to use a caller-specified generic type in macros.

Basically, the problem is that I want to instantiate GenericStruct<T> for various types T, which are implementation details of the test suite, but it seems there is no way to pass “GenericStruct” to the macro (e.g. as a “ty”) and instantiate it for various type parameters on the inside. Instead, it seems I need to pass all the instantiations of GenericStruct into the macro, which undesirably leaks implementation details and makes the code more brittle in the face of test suite modifications.

Searching around the web for people who encountered similar issues, I did not find anything satisfactory.

So I have two questions:

  • Is there a way to do this (creating modules with #[test]s inside) without using at least declarative macros?
  • Is there a way to instantiate user-specified generic types in declarative macros that I missed?

If the answer to both of these questions is “no” , perhaps this would be a use case to consider for declarative macros 2.0?


#2

Can’t you pass it as an ident? (or path?)

Edit: Oh dear, it looks like path doesn’t work:

3  |         impl $path<u8> { }
   |                   ^ expected one of `!`, `+`, `for`, `where`, or `{` here

But here’s a PoC for ident:

macro_rules! foo {
    ($path:ident) => {
        impl $path<u8> { }
        impl $path<u16> { }
    }
}

mod a {
    pub struct A<T>(T);
    foo!(A);
}

Update: Somewhat astonishingly, :: works as a separator in repetitions.

macro_rules! foo {
    ($($path:ident)::+) => {
        impl $($path)::+<u8> { }
        impl $($path)::+<u16> { }
    }
}

mod a {
    pub struct A<T>(T);
}

foo!(a::A);

#3

cc https://github.com/rust-lang/rust/issues/47090


#4

In my rose-colored glasses, I’d rather see this be solved by higher ranked types.


#5

I initially tried ident, but did not get it to work at the time as I got stuck into “Use of undeclared type or module” errors that I did not understand. At the time, I hazarded a guess that this was because I was trying to shove that ident token in a place where it did not fit. But as it turns out, it was just me misunderstanding how identifier scoping works inside of macros.

With suitable modifications, I managed to get an indent-based version rolling. Thanks!