darling icon indicating copy to clipboard operation
darling copied to clipboard

Attributes containing keywords can't be parsed with 0.20

Open Florob opened this issue 2 years ago • 10 comments

The code below worked in 0.14.2. It uses type inside a derive macro attribute.

As of 0.20 this yields:

Error { kind: Custom("expected identifier, found keyword `type`"), locations: ["bar"], span: Some(Span) }
use darling::{ast, FromDeriveInput, FromField, FromMeta};
use quote::quote;
use syn::{parse_quote, DeriveInput};

#[derive(Clone, Debug, FromMeta)]
#[darling(rename_all = "snake_case")]
enum Type {
    A,
    B,
}

#[derive(Clone, Debug, FromDeriveInput)]
#[darling(attributes(myderive), supports(struct_named))]
struct MyDeriveReceiver {
    data: ast::Data<(), MyDeriveFieldReceiver>,
}

#[derive(Clone, Debug, FromField)]
#[darling(attributes(myderive))]
struct MyDeriveFieldReceiver {
    #[darling(rename = "type")]
    my_type: Option<Type>,
}

fn main() {
    let input = parse_quote! {
        #[derive(MyDerive)]
        struct Foo {
            #[myderive(type = "a")]
            bar: (),
        }
    };
    let receiver = MyDeriveReceiver::from_derive_input(&input).unwrap();
}

Florob avatar May 25 '23 00:05 Florob

Attempting to repro this, I discovered something interesting. This errors:

let _attr: syn::Attribute = syn::parse_quote!(#[type = false]);

But this doesn't:

let _attr: syn::Attribute = syn::parse_quote!(#[hello(type = false)]);

It seems like it may matter to syn whether the keyword is the outermost item, or is inside a Meta wrapper.

Alternatively, the issue is in NestedMeta, which does some custom parsing. That seems to be looking for an identifier, so I it's possible that needs to allow for keywords instead. @jonasbb is that something you'd be able to take a look at?

TedDriggs avatar May 25 '23 13:05 TedDriggs

I've filed dtolnay/syn#1458 to request that syn handle this scenario without errors.

TedDriggs avatar May 25 '23 13:05 TedDriggs

I can take another look next week, but it looks a bit like https://github.com/dtolnay/syn/issues/1414 Basically, type = false is not a valid Meta syntax in Rust and syn. I guess the DeriveInput gets recursively parsed into a Meta or NestedMeta somewhere. No chance of getting any support from syn, because of its maintainer. This is how I worked around that for serde_with: jonasbb/serde_with@c22f165 (#578), replace as with r#as such that it is valid Meta.

jonasbb avatar May 25 '23 13:05 jonasbb

As noted in #1414 it seems that keyword identifiers are fine as long as they're inside the List portion; is there a way that NestedMeta could reimplement Meta parsing to preserve that behavior?

TedDriggs avatar May 25 '23 14:05 TedDriggs

NestedMeta works.

let nm: darling::ast::NestedMeta = syn::parse_quote!(myderive(type = "a"));

You just cannot expect that the inside is a well-formed meta again. Probably from_derive_input assumes that (recursive parsing). darling has no from_tokenstream for directly parsing. syn has no type supporting keywords. Dropping Meta and doing something separate from syn would work.

jonasbb avatar May 25 '23 17:05 jonasbb

It's possible to hand-construct a syn::Meta that has an Ident in its path field which is a keyword, right? The issue is that attempting to construct it using Parse fails?

If so, then would a darling-local copy of the Meta parsing code which used a different path parsing function work?

TedDriggs avatar May 25 '23 17:05 TedDriggs

It's possible to hand-construct a syn::Meta that has an Ident in its path field which is a keyword, right?

I am not sure if that is true, but yes if it is, then copying and adapting the Meta parsing code could work. I would be a bit wary about it. dtolnay likes breaking code that works and I feel that using Meta in such a form is something that could break at any point.

Instead of using Meta it might work to rely more on syn::parse::Parse to directly process the TokenStream that is embedded in a MetaList.

jonasbb avatar May 29 '23 18:05 jonasbb

Is there a current hack to get around this issue?

wcampbell0x2a avatar Aug 01 '23 11:08 wcampbell0x2a