Hello
In general, the idea of being able to mix crates from different editions in the same project is a nice one and works great.
Except one thing I’ve noticed. There are places where code from one edition may „leak“ into a crate of other edition. This happens for example with code generated by a build.rs
script (if I use for example prost-build
, it doesn’t know what edition I’m going to include!
the resulting code into) or with macros (both procedural and macro_rules!
ones), and then compilation errors and other beasts may get unleashed (I had to deal with some when migrating to the 2018 edition and had to find hacks and workarounds).
Currently, the solution seems to be trying to produce code that compiles in both. But this doesn’t feel nice and will probably not be a reasonable strategy with more than two editions.
I haven’t seen any plans/solutions, but that might be because I didn’t search well enough. Are there any? Or was it considered unimportant?
Brainstorming ideas
I have a few ideas, I’d like to hear if they make some kind of sense and if it would be possible to do something of that (or similar) to help with the above problem. If so, what can I do to help out?
Knowing the edition
The build.rs and procedural macros could get eg. an environment variable and decide to generate either one or the other edition code.
Similarly, it would be possible to add a #[cfg(edition = "...")]
attribute. That would allow a macro/build.rs to generate both variants and let the compiler pick one accordingly.
Both these things should IMO be relatively easy to do, seem non-intrusive and make it at least possible for crate authors to deal with support of multiple simultaneous downstream editions, if not getting some kind of future-proofing.
Overriding the edition per scope
Currently, the whole crate is compiled under the same edition. This would allow to somehow mark a scope generated by a macro that it is in some (possibly) different edition, eg:
// This is generated by the macro or build.rs
#[edition = "2015"]
mod generated {
// No matter what is around, the code here gets compiled under the 2015 rules.
}
This would make it possible to „future-proof“ the generated code against crates in future yet unknown editions. But this might be hard to do inside the compiler (I don’t know) and if the macro wanted to paste some piece of code it gets from its user’s crate, it would need to switch back and it would need to know somehow from which edition the tokens come from (that could come from a property on the TokenStream/individual tokens, or maybe an automatic $edition
variable in macro_rules
, similar as there’s $crate
).
Automatic macro edition hygiene
That’s basically an automatic version of the above ‒ the code created by the macro would be compiled under the edition of the macro’s crate, but pasted tokens would preserve the edition of the crate they come from.
But honestly, this one seems a bit crazy to do even to me ‒ probably very hard to do (I imagine people who know how the compiler works inside streaming now), and harder to decide what it would mean if the tokens’ editions just mixed arbitrarily (as opposed to eg. on a scope boundary). And it would probably be backwards-incompatible change?