SergioBenitez / proc-macro2-diagnostics

Diagnostics for stable and nightly proc-macros!
Apache License 2.0
10 stars 5 forks source link

Support emit-and-continue pattern #8

Open dhardy opened 3 months ago

dhardy commented 3 months ago

With warnings in particular (but potentially also with errors), it may be preferable to emit a diagnostic then continue generating macro output.

Until we get better support for proc-macro errors (or more general lints) in rustc, I see only two ways of achieving this:

  1. Add fn Diagnostic::emit(self) -> () which uses the nightly API if available, otherwise
    • Errors are reported as panics (not ideal since it loses the span)
    • Everything else is silently dropped (not ideal, but there isn't a better alternative)
  2. Add state to track accumulated errors (in a static var or in a user-managed DiagnosticSet), then report via the usual method of injecting compile_error into the output (assuming the output is a list of items). This is problematic, both in that a user function call must be used to generate this output (which might be forgotten) and in that the output might be an expression (could be transformed but not merely appended to).

There isn't exactly a good option, but this is an important capability to have, and (especially option 1) should ease transition to whatever custom lint system Rust eventually adopts.

SergioBenitez commented 1 month ago

At the moment if you do any emit_as() on a diagnostic, the diagnostic is emitted directly at the call site on nightly. On stable it returns the appropriate tokens to create the compile_error!(). This is to say: on nightly, it works exactly as you suggest. On stable, it does the second of the two options you suggest.

dhardy commented 1 month ago

This isn't what I want since Diagnostic::emit_as_item_tokens returns a TokenStream (as do all other emit_as_...). Well, I could use this if I then drop the result.

I mean, I could keep track of emitted_diagnostics: TokenStream myself (via a static/thread-local value or via an extra field in many different structs representing parsed input), and then fold this into the output somewhere. This is not exactly trivial, which is why I'm suggesting it be added as library functionality.

The unmaintained proc-macro-error crate supports emit_error! and emit_warning! as item statements which return no result, which is what I want. Admittedly, emit_warning! does nothing on stable, but it supports the desired usage pattern and should be fixable once macro diagnostics finally get stabilised.