I’ve been meaning to write this up for a while now, ever since I had this proof-of-concept.
The Problem: Rust’s macro/syntax extension system has issues preventing their widespread use in 1.0. I believe this to have potentially dire consequences on Rust’s adoption as a stable language, I would rather keep using nightlies than touch manual code generation.
What are some of these issues?
- many macros are provided by the compiler
- those macros have no clear place to attach stability markers or documentation to
- bootstrapping is hard because built-in macros in the compiler cannot be changed after the fact, to adjust for later changes to libsyntax
- syntax extensions depend on the internals of the compiler (mostly libsyntax)
- there is a way to write cleaner and more implementation-detail-agnostic syntax extensions, the quasi-quoting macros, but they’re unusable within the compiler (bootstrapping) and they’re less efficient/flexible than they could/need to be (which can be fixed, but, bootstrapping makes incremental progress very difficult)
The root of all evil: so far, bootstrapping seems to be the main factor that causes or worsens these issues.
- if we can change the generated code patterns of the snapshot compiler, at the same time with the libs it compiles, that would male changes to built-in macros much less painful.
- if we can improve quasi-quoting, it can be used almost everywhere, instead of touching compiler internals directly.
- if quasi-quoting is in a library and if writing syntax extensions doesn’t require direct access to librustc or libsyntax, we could stabilize that (plugin) library prior to 1.0 without preventing changes to the compiler internals or the creation of an improved macro system.
The solution: all of that can be achieved by moving built-in macros to plugins, which are to be compiled by the (stage N-1) compiler that compiled the (stage N) compiler (which will load them in building stage N libs). Thanks to snapshot quasi-stability, stage 0 (snapshot) is usable as “stage -1”, as long as it includes the libs it was linked against.
The branch linked at the top of this post has #[deriving]
moved out to a plugin crate, as a proof of concept.
I am.unsure about feature gates turning built-in macros on. I presume rustc_diagnostic_macros
and quote_macros
can be removed.
Should macro_rules
stay and inject #[phase(plugin)] extern crate macro_rules;
?