-
Notifications
You must be signed in to change notification settings - Fork 13k
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
Tracking issue for error messages from proc-macro implementations #50054
Comments
Note to self: the master tracking issue for proc-macros is #38356. |
While experimenting with this, I discovered another major usability issue: testing. There's no way to write unit tests against I think that moving error emission to the return value would be ideal. I think I would design the API as follows:
|
Sorry, I just came across this issue. I think this is largely a documentation issue. Let me try to address your points one by one:
Indeed. In Rocket, we have a
This is true, but you don't need to type PResult<T> = ::std::result::Result<T, Diagnostic>;
fn real_derive(input: TokenStream) -> PResult<TokenStream> {
// return early if an error occurs
return Err(span.error("foo"));
}
#[proc_macro_derive(Trait)]
pub fn derive(input: TokenStream) -> TokenStream {
real_derive(input).unwrap_or_else(|diag| {
diag.emit();
TokenStream::new()
})
} There's nothing wrong with emitting an empty One thought that @alexcrichton and I have kicked around is to allow the following signature for derives directly: #[proc_macro_derive(Trait)]
pub fn derive(input: TokenStream) -> Result<TokenStream, Diagnostic> { } But this is just sugar for what I wrote before. The primary concern is that this might incentivize users to bail on the first error as opposed to trying to make as much progress as possible to emit as many errors as possible at once. It could be that this doesn't actually matter in practice, however.
Indeed. But all of this is very unstable without RFC or clear stabilization paths. This is something I will look into personally somewhat soon.
It should be inspectable, but I don't think this will be of much value for testing. You should really use
This is akin to returning an empty |
The syn side of this has been addressed as of 0.15.0: https://github.com/dtolnay/syn/releases/tag/0.15.0 |
A kind soul recently updated gnome-class to use syn 0.15.3, and I am incredibly, nicely impressed. The new parser code is much more legible! I tried adding a few deliberate syntax errors inside macro invocation, and the results are pretty spectacular. Translating a chain of
I'm so happy to see this work! Excellent, excellent job! 👍 👍 👍 👍 👍 👍 💯 |
I think with |
Currently, presenting good error messages from a proc-macro implementation — the user calls the macro and has a syntax or semantic error in the contents of the macro invocation — is very tricky. I.e.
There are some things that make it hard to present good error messages. Assuming that one uses
syn
for the parsing stage:syn
code flow bubblesPResult
upstream, but syn'sparse_error()
does not include an error message nor a span - it's just an empty struct.proc_macro::Diagnostic
:(quote! {()}).to_tokens(tokens);
, or the compiler will think that the proc-macro emitted nothing.Diagnostic
to emulate the various suggestions and annotations that rustc presesnts with its normal messages.After the parsing stage, the proc-macro may encounter semantic errors. In that case, the implementation needs to return a TokenStream with spans with errors. Again, the disparity in carrying errors as a Result, versus emitting spans with errors, makes this tricky. It's also not clear whether it's up to the implementor to aggregate errors in a Vec or something, and then later emit a bunch of error spans for them somehow (instead of just stopping after the first one, for example).
The text was updated successfully, but these errors were encountered: