Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Unresolved type errors inside macro invocation #125

Closed
kangalio opened this issue Mar 31, 2021 · 7 comments
Closed

Unresolved type errors inside macro invocation #125

kangalio opened this issue Mar 31, 2021 · 7 comments
Labels

Comments

@kangalio
Copy link
Contributor

It seems that Darling's macros refer to items of syn (and potentially other dependencies) with a path of the form syn::_. In macros, it is advisable to use absolute paths ::syn::_ instead, as they don't clash with local items called "syn".

I encountered this issue just now, when trying out Darling for the first time. In my code, I have a custom syn prelude module to shorten paths:

// Custom prelude
mod syn {
    pub use syn::{
        parse::{Error as ParseError, Parse, ParseStream},
        parse_macro_input, parse_quote,
        punctuated::Punctuated,
        spanned::Spanned,
        Attribute, Error, Expr, ExprArray, ExprAssign, ExprLit, ExprPath, FnArg, ItemFn, Lit,
        NestedMeta, PatType, Token, Type, TypeReference,
    };
}

Darling's generated code proceeded to access an item called NestedMeta from "syn", which, due to not being an absolute path, was misinterpreted as the module.

@TedDriggs
Copy link
Owner

As far as I can tell, every reference to NestedMeta in darling_core::codegen is already using ::syn::NestedMeta (1, 2).

Can you run cargo expand and share where the generated code is referencing it without the leading :: please?

@kangalio
Copy link
Contributor Author

kangalio commented Apr 1, 2021

Hmm, I actually cannot find any non-absolute reference to syn::NestedMeta in the cargo expand-expanded code.

The compiler still complains though:

mod syn {}

#[derive(darling::FromMeta)]
struct Args {}

Compiler output with RUSTFLAGS="-Z macro-backtrace" cargo check: https://pastebin.com/uddbbrn2
cargo expand output: https://pastebin.com/9TwLhe4v

Funnily enough, if the cargo expand output is pasted back into the Rust file and then compiled (after removing the const _: () = { ... } block), the errors disappear.

Schrödinger's error; it only appears when you can't look under the hood 🤔

@kangalio
Copy link
Contributor Author

kangalio commented Apr 1, 2021

Ohhhhhh I think I know the issue.

Quoting the Rust reference on path qualifiers:

Edition Differences: In the 2015 Edition, the crate root contains a variety of different items, including external crates, default crates such as std or core, and items in the top level of the crate (including use imports).

Beginning with the 2018 Edition, paths starting with :: can only reference crates in the extern prelude.

Darling uses Rust 2015, which means that its proc-macro generated code adheres to the Rust 2015 rules, which also means that ::syn can point to "items in the top level of the crate", i.e. my custom syn module.

Only when pasting the cargo expand output back into my Rust 2018 crate, the new hygiene rules kick in and ::syn begins to function properly. That's why the error disappeared when pasting the cargo expand output into the lib.rs.

@TedDriggs
Copy link
Owner

If this works properly in 2018 or in the absence of a redeclared root syn, I'm inclined not to change darling's generated code. There don't appear to be many items that darling references in its emitted output; can you add those to your custom syn prelude as a workaround?

@kangalio
Copy link
Contributor Author

kangalio commented Apr 1, 2021

If this works properly in 2018 or in the absence of a redeclared root syn, I'm inclined not to change darling's generated code.

To be clear, Darling's generated code is perfectly fine and can't meaningfully be "fixed" as far as I can tell; the unresolved type error comes from a combination of Darling itself using Rust 2015 and the dependent crate having an item called syn in the crate root.

Tweaking the syn module in my code to make it work is not a problem at all.

Maybe it would also be cool to port Darling to Rust 2018, to get rid of old language edge cases like this one and also because it's just nice to be up to date ^.^

Anyways, thank you for your time, I think this issue can be closed since a fix has been found

@kangalio kangalio closed this as completed Apr 1, 2021
@kangalio kangalio changed the title Use absolute syn paths in generated code Unresolved type errors inside macro invocation Apr 1, 2021
@TedDriggs
Copy link
Owner

Maybe it would also be cool to port Darling to Rust 2018, to get rid of old language edge cases like this one and also because it's just nice to be up to date ^.^

I wish I could. My understanding is that proc macros inherit the edition of their call site, so I can't move darling to 2018 without all its consumers moving too. I suspect that would wreak havoc for people since the resulting errors would be unpredictable and have bad messages.

@kangalio
Copy link
Contributor Author

kangalio commented Apr 2, 2021

My understanding is that proc macros inherit the edition of their call site

I could not find any official resources on this question, but according to some testing done by Yandros in the Rust community discord server, proc macros use the edition of the definition site.

This also matches the behavior I described above: the Darling-generated code adheres to Rust 2015 rules, even when the derive macro is invoked in a Rust 2018 crate.

As far as I can tell from all of this, no user code should break when moving Darling to Rust 2018.

@TedDriggs TedDriggs mentioned this issue Apr 8, 2021
3 tasks
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

2 participants