diesel-rs/diesel

Option field check in diesel_derives in incomplete

stormshield-kg opened this issue · 0 comments

Problem Description

The following code fails to compile:

diesel::table! {
    test_table (id) {
        id -> Int8,
        test -> Text,
    }
}

macro_rules! define {
    ($field_ty:ty) => {
        // Compilation error for S1
        #[derive(diesel::AsChangeset)]
        #[diesel(table_name = test_table)]
        pub struct S1 {
            pub test: $field_ty,
        }

        // Compilation is fine for S2
        #[derive(diesel::AsChangeset)]
        #[diesel(table_name = test_table)]
        pub struct S2 {
            pub test: Option<String>,
        }
    };
}

define!(Option<String>);

Playground link: https://www.rustexplorer.com/b/he8xgp

This is because the check for an Option field type in the proc-macro doesn't take into account the invisible delimiter introduced by the declarative macro:

fn option_ty_arg(ty: &Type) -> Option<&Type> {
use syn::PathArguments::AngleBracketed;
match *ty {
Type::Path(ref ty) => {
let last_segment = ty.path.segments.iter().last().unwrap();
match last_segment.arguments {
AngleBracketed(ref args) if last_segment.ident == "Option" => {
match args.args.iter().last() {
Some(GenericArgument::Type(ty)) => Some(ty),
_ => None,
}
}
_ => None,
}
}
_ => None,
}
}