-
Notifications
You must be signed in to change notification settings - Fork 68
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
Update dependencies to syn 0.14 and proc-macro2 0.4 #42
Conversation
NOTE: This commit makes breaking changes only on surface level and builds are not successful yet, so some in-depth changes are needed too. Expect this commit to be squashed with others to produce a working one.
This will make `darling_core` usable in projects that don't want to depend on the dynamic library libproc_macro from rustc toolchain.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
First off, thanks for making another great dependency update. I saw this come out just after I'd finished a round of changes, and I definitely had an "oh noooo" moment.
error[E0271]: type mismatch resolving `<std::collections::HashSet<&proc_macro2::Ident, std::hash::BuildHasherDefault<fnv::FnvHasher>> as std::iter::IntoIterator>::Item == proc_macro2::Ident`
--> core/src/codegen/trait_impl.rs:72:14
|
72 | hits.extend(
| ^^^^^^ expected reference, found struct `proc_macro2::Ident`
|
= note: expected type `&proc_macro2::Ident`
found type `proc_macro2::Ident`
I'm pretty sure I understand what's happening here; I was confused why this code worked before, and I think it's because Ident
implemented Copy
and I didn't know about it. I was thinking this morning about adding a new collect_cloned_type_params
method to that trait which would clone the Idents before returning; this seems to be one more reason to do that.
Implement "proc-macro" feature propagation for darling_core so that there was a way to be dependency-free from rustc-related libraries. Since darling_macro directly depends on libproc_macro and darling is just a re-export facade (and so indirectly depends on libproc_macro), they didn't get the same treatment.
I don't understand the impact of this.
- What do other users gain by removing this indirect dependency (and therefore on rustc-related libraries)?
- Do we lose anything?
Once I know that I'll be able to update the readme. I'm also wondering if it makes sense to put this feature on darling
so that people still interact with one crate, and they turn off the proc-macro feature there to avoid getting the proc macros.
core/src/options/from_variant.rs
Outdated
@@ -51,7 +51,7 @@ impl ParseAttribute for FromVariantOptions { | |||
|
|||
impl ParseData for FromVariantOptions { | |||
fn parse_field(&mut self, field: &Field) -> Result<()> { | |||
match field.ident.as_ref().map(|i| i.as_ref()) { | |||
match field.ident.as_ref().map(|i| i.to_string().as_ref()) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should this line be using as_str
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Technically it works fine but for consistency reasons, yeah, you're right.
core/src/options/mod.rs
Outdated
@@ -43,7 +44,7 @@ impl FromMeta for DefaultExpression { | |||
} | |||
|
|||
fn from_string(lit: &str) -> Result<Self> { | |||
Ok(DefaultExpression::Explicit(syn::Path::from(lit))) | |||
Ok(DefaultExpression::Explicit(syn::Path::from(syn::Ident::new(lit, Span::call_site())))) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This changes the meaning of this line; we allow path::to::function
here, but I don't think that's a valid ident.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I didn't quite get it -- does from_string
accept ::
-separated list of idents by design or by accident?
But just in case, let's see how it worked with syn
0.13:
impl<T> From<T> for Path where T: Into<PathSegment>
: https://docs.rs/syn/0.13.11/syn/struct.Path.html#impl-From%3CT%3Eimpl<T> From<T> for PathSegment where T: Into<Ident>
: https://docs.rs/syn/0.13.11/syn/struct.PathSegment.html#impl-From%3CT%3Eimpl<'a> From<&'a str> for Ident
: https://docs.rs/syn/0.13.11/syn/struct.Ident.html#impl-From%3C%26%27a%20str%3E
So Path::from(lit)
is actually Path::from(PathSegment::from(Ident::from(lit)))
which is equivalent to
Path {
leading_colon: None,
segments: FromIterator::from_iter(iter::once(PathSegment {
ident: Ident::new(lit, Span::call_site()),
arguments: PathArguments::None,
})),
}
Which means that even if from_string
was intended to accept path::to::function
(and parse it correctly), Ident::from(lit)
would just panic with such input.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That's concerning. This is supposed to have behaved like serde(default="path::to::foo")
; I wonder if it never worked. It's worth adding a test that exercises the path functionality.
These make composition easier at the expense of additional allocations
- Change codegen structs to take an ident list rather than string slices - Do horrible things to transform idents to `&str` during darling's own attribute parsing. These things involve multiple calls to as_ref and map. - Change how tests create idents
core/src/codegen/mod.rs
Outdated
let mut __fwd_attrs: ::darling::export::Vec<::syn::Attribute> = vec![]; | ||
|
||
for __attr in &#input.attrs { | ||
// Filter attributes based on name | ||
match __attr.path.segments.iter().map(|s| s.ident.as_ref()).collect::<Vec<&str>>().join("::").as_str() { | ||
match ::darling::export::ToString::to_string(&__attr.path.clone().into_token_stream()).as_str() { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@dtolnay, do you have an idea on how to efficiently match a path against other paths? Having to import quote
, write to a token stream, and convert to a string feels wasteful (or at least roundabout)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
PartialEq for Path? https://docs.rs/syn/0.14/syn/struct.Path.html#impl-PartialEq
I think it is gated behind "extra-traits"
feature.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This code is generating a match
statement over attribute paths that are taken from user strings, and the generated code is going to live in the user's crate.
Is there a good way to write a match
statement which does equality checks against paths?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There is no builtin way to compare a Path with a string directly so you will be comparing either strings with strings or paths with paths. If strings with strings, this looks fine. If paths with paths, the attr_names
need to be converted to paths with a match-guard to do the ==
comparison.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm conflicted here. Re-parsing the handled and forwarded attribute path
values every time we come through feels wasteful, but having to indirectly import quote
to tokenize the path feels very hacky.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You don't necessarily need a parser involved to construct Path
values: playground.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ooh, that's a good point here. The user input is technically passed as an IdentList
, I believe. Maybe I can do the comparisons of "segment length is 1, and first segment is in the user-specified idents"
Sorry for the late response, I forgot to tune in when notifications arrived.
Thank you too for supporting contributions and this library!
Frankly, I began tackling this PR 3 days ago, when the new
I see you've already fixed that in 28959d0.
For example, an ability to use in non-proc-macro contexts -- such a case in presented in the discussion here: dtolnay/quote#62 -- because with the "proc-macro" feature on, the library will pull in a dynamically-linked dependency and that is not desirable for binary distribution. On the other hand, is
Since the released
That should be doable too, with So I'm glad to see the builds green. Thank you for pitching in! |
Let's do that, using a feature called |
I've split the changes into 3 commits:
List of breaking changes from
proc-macro2
,quote
andsyn
.Replacing
quote::Tokens
withproc_macro2::TokenStream
+quote::TokenStreamExt
was easy.Updating to the new
Ident
was far more tricky because bothimpl AsRef<str>
andimpl Copy
are gone -- now you can't pass aroundIdent
s without thinking about ownership and comparing to strings incurs heap allocation overhead (evenimpl<T: AsRef<str> + ?Sized> PartialEq<T>
uses.to_string()
underneath).The build in this PR produces the following error message:
Output from cargo +1.18.0 build
I believe that to resolve this on my behalf I would need to dig further and make fundamental changes in the API. I'm not comfortable to do so, for being afraid to mess up the logic, though if you think that would be easy to do, I'll probably try. Also, I might be totally wrong and just overthinking the complexity of this library 😄.
"proc-macro"
feature propagation fordarling_core
so that there was a way to be dependency-free fromrustc
-related libraries. Sincedarling_macro
directly depends on libproc_macro anddarling
is just a re-export facade (and so indirectly depends on libproc_macro), they didn't get the same treatment.With that said, please make a thorough review and suggest ideas/criticize where appropriate!
Closes #38.