dtolnay / request-for-implementation

Crates that don't exist, but should
613 stars 6 forks source link

Library for parsing function signature without parsing function body #16

Closed dtolnay closed 5 years ago

dtolnay commented 5 years ago

The Syn crate has fairly coarse compile-time control over the set of available syntax tree types. There is default-features = false mode where only the parsing API is provided with no syntax tree types at all, there is features = ["derive"] which is the default and supports structs and enums, and there is features = ["full"] which supports all possible Rust syntax.

Sometimes Rust macros, especially attribute macros, need to parse just slightly more than what is exposed by the default feature set. For example wasm-bindgen wants to parse function signatures but not their bodies. That means there should be no need for any of the expression-parsing logic enabled by features = ["full"]. They could save compile time by using features = ["derive"] in combination with a library that just parses function signatures.

pub struct Function {
    /* ... */
}

pub fn parse_signature_only(function: TokenStream) -> syn::Result<Function>;

The return struct would look like pretty much like syn::ItemFn except where the function body is kept as an unparsed TokenStream instead of a fully parsed syn::Block.

taiki-e commented 5 years ago

I implemented this: https://github.com/taiki-e/syn-mid

dtolnay commented 5 years ago

Note that if you use syn with "full" feature and use syn-mid without "full" feature at the same time, errors due to type mismatch may occur.

This seems bad. It makes the crate impossible to use correctly as a private dependency. Is there a way that you could do this differently?

The scenario to consider is:

To pull in B and C, crate A would need to add a dependency on the same version of syn-mid used by crate B in order to set its full feature. But this makes it a breaking change for B to upgrade its private syn-mid dependency to 0.n+1.

taiki-e commented 5 years ago

This seems bad. It makes the crate impossible to use correctly as a private dependency. Is there a way that you could do this differently?

You are right. I encountered an error derived from this... I decided to remove the "full" feature (taiki-e/syn-mid#1).

dtolnay commented 5 years ago

Sounds good.

I would recommend minimizing further. You can remove PatBox, PatLit, PatMacro, PatRange, PatVerbatim, RangeLimits, QSelf, and the subpat field of PatIdent since none of those ever appear in a function signature. Also I would remove the clone-impls and extra-traits features. I would remove support for inner attributes since those are never used inside functions in real code.

taiki-e commented 5 years ago

Thanks for the great feedback!

For clone-impls, it is #[cfg_attr(feature = "clone-impls", derive(Clone))] only, so I will leave this (but I will change it to "disabled by default"). And I will remove other items (taiki-e/syn-mid#2).

dtolnay commented 5 years ago

Okay, clone-impls disabled by default is a good idea.

More things to remove:

dtolnay commented 5 years ago
dtolnay commented 5 years ago

More to remove:

Altogether you should end up with less than half as much code as you started with in 0.1.0.

dtolnay commented 5 years ago

Also since this is a new crate it should be fine to require a relatively new compiler version and reduce the clippy exclusions to #![allow(clippy::large_enum_variant)].

taiki-e commented 5 years ago

Thanks! I added these to the task list of taiki-e/syn-mid#2.

  • Reduce Pat::Tuple to just paren_token and elements: Punctuated<Pat, Token![,]> -- nobody would use .. syntax in a function argument.

PatTuple is used in PatTupleStruct, so I will leave this.

  • The Pat::Slice type; I don't recall ever seeing that in function signatures.

Probably fixed size array + #![feature(slice_patterns)].

Also since this is a new crate it should be fine to require a relatively new compiler version and reduce the clippy exclusions to #![allow(clippy::large_enum_variant)].

That makes sense. I will bump the minimum required version to Rust 1.30 because proc_macro_attribute becomes available.

Altogether you should end up with less than half as much code as you started with in 0.1.0.

It's amazing, thanks!

dtolnay commented 5 years ago

PatTuple is used in PatTupleStruct

It is, but nobody writes signatures like fn f(TupleStruct(a, .., b): TupleStruct) either. For a library that exists for the sole purpose of not compiling support for unneeded syntax, I would expect unused syntax to be cut out quite aggressively.

Probably fixed size array + #![feature(slice_patterns)].

Unless you find an occurrence of this in real code, I would remove it.

taiki-e commented 5 years ago

For a library that exists for the sole purpose of not compiling support for unneeded syntax, I would expect unused syntax to be cut out quite aggressively.

That makes sense.

Probably fixed size array + #![feature(slice_patterns)].

Unless you find an occurrence of this in real code, I would remove it.

I could not find it, so I will remove it.

taiki-e commented 5 years ago

Cleanup was ended up, thank you for all your help!

dtolnay commented 5 years ago

Nicely done. Once you publish to crates.io I will close out this issue.

taiki-e commented 5 years ago

Done: https://crates.io/crates/syn-mid

dtolnay commented 5 years ago

Thanks. I added a link to your crate in the readme.