Proposal
Problem statement
proc_macro::Group represents a delimited group of tokens. This group has two important spans: the span of the opening token, and the span of the closing token. In early Rust, this was exposed with only a single span for both tokens.
Then in rust-lang/rust#53902 (and stabilized in rust-lang/rust#86136 in 1.55) two new methods were added to Group: span_open and span_close, representing the separate spans for the two.
This allows macros to use those separate Group spans to map spans more precisely, resulting in better error messages.
One thing that these methods do not allow is creating new Groups with those different spans, as the only way to set the span of group delimiters is using Group::set_span, which sets it for both. This means that functions like syn::token::Brace::surround cannot produce accurate spans, resulting in worse error messages.
In the case of attribute macros, having the exact same spans before and after expansion is especially important to avoid duplicate diagnostics, but in all cases better spans will result in better error messages.
Motivating examples or use cases
When using Brace::surround in tracing::instrument to re-build the body (tokio-rs/tracing#3557), the error message span is worse.
Expected:
error: expected type, found `}`
--> src/main.rs:4:1
|
3 | let x:
| - while parsing the type for `x`
4 | }
| ^ expected type
Actual:
error: expected type, found `}`
--> src/main.rs:2:11
|
2 | fn main() {
| ___________^
3 | | let x:
| | - while parsing the type for `x`
4 | | }
| |_^ expected type
Solution sketch
// proc_macro
impl Group {
/// Configures the span for this `Group`'s opening delimiter.
///
/// ```text
/// pub fn span_open(&self) -> Span {
/// ^
/// ```
pub fn set_span_open(&mut self, span: Span);
/// Configures the span for this `Group`'s closing delimiter.
///
/// ```text
/// pub fn span_close(&self) -> Span {
/// ^
/// ```
pub fn set_span_close(&mut self, span: Span);
}
I have branches with draft implementations:
Alternatives
Proc-macros can sometimes do less manipulation of the token trees and preserve the originals to avoid needing this. But that will neither be easy nor desirable in all cases.
Links and related work
I could not find any mention of such APIs on the original tracking issue rust-lang/rust#54725, which might in part be because that tracking issue is a complete mess.
What happens now?
This issue contains an API change proposal (or ACP) and is part of the libs-api team feature lifecycle. Once this issue is filed, the libs-api team will review open proposals as capability becomes available. Current response times do not have a clear estimate, but may be up to several months.
Possible responses
The libs team may respond in various different ways. First, the team will consider the problem (this doesn't require any concrete solution or alternatives to have been proposed):
- We think this problem seems worth solving, and the standard library might be the right place to solve it.
- We think that this probably doesn't belong in the standard library.
Second, if there's a concrete solution:
- We think this specific solution looks roughly right, approved, you or someone else should implement this. (Further review will still happen on the subsequent implementation PR.)
- We're not sure this is the right solution, and the alternatives or other materials don't give us enough information to be sure about that. Here are some questions we have that aren't answered, or rough ideas about alternatives we'd want to see discussed.
Proposal
Problem statement
proc_macro::Grouprepresents a delimited group of tokens. This group has two important spans: the span of the opening token, and the span of the closing token. In early Rust, this was exposed with only a single span for both tokens.Then in rust-lang/rust#53902 (and stabilized in rust-lang/rust#86136 in 1.55) two new methods were added to
Group:span_openandspan_close, representing the separate spans for the two.This allows macros to use those separate
Groupspans to map spans more precisely, resulting in better error messages.One thing that these methods do not allow is creating new
Groups with those different spans, as the only way to set the span of group delimiters is usingGroup::set_span, which sets it for both. This means that functions likesyn::token::Brace::surroundcannot produce accurate spans, resulting in worse error messages.In the case of attribute macros, having the exact same spans before and after expansion is especially important to avoid duplicate diagnostics, but in all cases better spans will result in better error messages.
Motivating examples or use cases
When using
Brace::surroundintracing::instrumentto re-build the body (tokio-rs/tracing#3557), the error message span is worse.Expected:
Actual:
Solution sketch
I have branches with draft implementations:
Alternatives
Proc-macros can sometimes do less manipulation of the token trees and preserve the originals to avoid needing this. But that will neither be easy nor desirable in all cases.
Links and related work
I could not find any mention of such APIs on the original tracking issue rust-lang/rust#54725, which might in part be because that tracking issue is a complete mess.
What happens now?
This issue contains an API change proposal (or ACP) and is part of the libs-api team feature lifecycle. Once this issue is filed, the libs-api team will review open proposals as capability becomes available. Current response times do not have a clear estimate, but may be up to several months.
Possible responses
The libs team may respond in various different ways. First, the team will consider the problem (this doesn't require any concrete solution or alternatives to have been proposed):
Second, if there's a concrete solution: