Reputation: 2305
I'm working through rust's macro system attempting to make an ORM wrapper over Diesel. Working through the belongs to, I found that rust is sending a rather unexpected error. Please consider the following code:
macro_rules! klass {
(
$name:ident,
fields => ($(
$field:ident : $type:ty = $default:expr,
)*),
belongs_to => ($(
$belong_field:ident : $temp:ty [ $key:expr ],
)*)
) => {
struct $name {
$( $field: $type, )*
}
impl Default for $name {
fn default() -> $name {
$name {
$(
$field : $default,
)*
}
}
}
impl $name {
$(
fn $belong_field(&self) -> $temp {
let key = $key;
$temp { ..Default::default() }
}
)*
}
}
}
klass! ( Neat,
fields => (
id: i32 = 0,
name: String = String::from(""),
),
belongs_to => ()
);
klass!( Bob,
fields => (
id: i32 = 0,
neat_id: i32 = 0,
),
belongs_to => (
neat: Neat [ "neat_id" ],
)
);
fn main()
{
let b = Bob { ..Default::default() };
let mut n = b.neat();
}
This code will yield the following result:
error: expected expression, found `Neat`
--> macro.rs:27:31
|
27 | $temp { ..Default::default() }
|
Why does rust say it wants an expression instead of Neat? I can change this code to the following and everything in this example compiles and runs:
Neat { ..Default::default() }
Is this a compiler error given when "Neat" is inserted the program runs as expected? Thanks, apologizes for this mostly being code.
Upvotes: 2
Views: 915
Reputation: 3861
$temp
occurs in different contexts in macro expansion. As a type in fn $belong_field(&self) -> $temp
and as a structure constructor in $temp { ..Default::default() }
.
You've marked $temp
as a type, it prevents second usage.
Replacing the line
$belong_field:ident : $temp:ty [ $key:expr ],
with
$belong_field:ident : $temp:ident [ $key:expr ],
allows the code to compile.
Upvotes: 4