Reputation: 913
This code:
#![feature(macro_rules)]
macro_rules! new(
($my_type:ty) => ( $my_type::new() );
)
struct Foo {
blah: int
}
impl Foo {
fn new() -> Foo {
return Foo { blah: 0 }
}
}
fn main() {
let my_foo = new!(Foo);
println!("Foo's value: {}", my_foo.blah);
}
Looks good enough, but it fails with this error:
test.rs:4:25: 4:32 error: unexpected token: `Foo`
test.rs:4 ($my_type:ty) => ( $my_type::new() );
^~~~~~~
If I go into the macro and replace $my_type
with Foo
it compiles and runs just fine, so Foo
is clearly valid in that position. Unless Foo
comes from macro substitution, apparently.
If I run rustc test.rs --pretty expanded
, it doesn't show me the expanded macro. It just gives me the same error message. I suspect this means it's generating the message before it expands the macro, but it might just be that it doesn't show me anything unless the compile succeeds. Though that would severely limit the usefulness of --pretty expanded
.
Based on other experiments, I can use the macro type arguments in basically every other place one would expect a type to work. You just can't call static functions on them. This seems like a rather arbitrary restriction, and the error message is certainly not helpful.
Why does this restriction exist? And is there a way around it?
Upvotes: 4
Views: 3061
Reputation: 102006
The Foo::bar()
syntax is creating the path Foo::bar
and then calling that function, and only works with valid paths, it doesn't work with arbitrary types, e.g. (u8, i8)::bar()
doesn't work. You can use the ident
macro non-terminal, which takes a single identifier and can be used whereever an identifier is valid, including inside a path
#![feature(macro_rules)]
macro_rules! new(
($my_type: ident) => ( $my_type::new() );
)
struct Foo {
blah: int
}
impl Foo {
fn new() -> Foo {
return Foo { blah: 0 }
}
}
fn main() {
let my_foo = new!(Foo);
println!("Foo's value: {}", my_foo.blah);
}
UFCS offers calling such methods on arbitrary types, via the syntax <Type>::new()
and so, when that is implemented, replacing your current macro with
macro_rules! new(
($my_type: ty) => ( <$my_type>::new() );
)
should work too.
Upvotes: 7