Skip to content

Commit c5a561c

Browse files
committed
proc_macro::Group::span_open and span_close
Before this addition, every delimited group like (...) [...] {...} has only a single Span that covers the full source location from opening delimiter to closing delimiter. This makes it impossible for a procedural macro to trigger an error pointing to just the opening or closing delimiter. The Rust compiler does not seem to have the same limitation: mod m { type T = } error: expected type, found `}` --> src/main.rs:3:1 | 3 | } | ^ On that same input, a procedural macro would be forced to trigger the error on the last token inside the block, on the entire block, or on the next token after the block, none of which is really what you want for an error like above. This commit adds group.span_open() and group.span_close() which access the Span associated with just the opening delimiter and just the closing delimiter of the group. Relevant to Syn as we implement real error messages for when parsing fails in a procedural macro.
1 parent 3480ac2 commit c5a561c

File tree

1 file changed

+42
-1
lines changed

1 file changed

+42
-1
lines changed

src/libproc_macro/lib.rs

+42-1
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,7 @@ use syntax::errors::DiagnosticBuilder;
6464
use syntax::parse::{self, token};
6565
use syntax::symbol::Symbol;
6666
use syntax::tokenstream;
67-
use syntax_pos::{Pos, FileName};
67+
use syntax_pos::{BytePos, Pos, FileName};
6868

6969
/// The main type provided by this crate, representing an abstract stream of
7070
/// tokens, or, more specifically, a sequence of token trees.
@@ -671,11 +671,52 @@ impl Group {
671671

672672
/// Returns the span for the delimiters of this token stream, spanning the
673673
/// entire `Group`.
674+
///
675+
/// ```text
676+
/// pub fn span(&self) -> Span {
677+
/// ^^^^^^^
678+
/// ```
674679
#[stable(feature = "proc_macro_lib2", since = "1.29.0")]
675680
pub fn span(&self) -> Span {
676681
self.span
677682
}
678683

684+
/// Returns the span pointing to the opening delimiter of this group, or the
685+
/// span of the entire group if this is a None-delimited group.
686+
///
687+
/// ```text
688+
/// pub fn span_open(&self) -> Span {
689+
/// ^
690+
/// ```
691+
#[unstable(feature = "proc_macro_span", issue = "38356")]
692+
pub fn span_open(&self) -> Span {
693+
if self.delimiter == Delimiter::None {
694+
self.span
695+
} else {
696+
let lo = self.span.0.lo();
697+
let new_hi = BytePos::from_usize(lo.to_usize() + 1);
698+
Span(self.span.0.with_hi(new_hi))
699+
}
700+
}
701+
702+
/// Returns the span pointing to the closing delimiter of this group, or the
703+
/// span of the entire group if this is a None-delimited group.
704+
///
705+
/// ```text
706+
/// pub fn span_close(&self) -> Span {
707+
/// ^
708+
/// ```
709+
#[unstable(feature = "proc_macro_span", issue = "38356")]
710+
pub fn span_close(&self) -> Span {
711+
let hi = self.span.0.hi();
712+
if self.delimiter == Delimiter::None || hi.to_usize() == 0 {
713+
self.span
714+
} else {
715+
let new_lo = BytePos::from_usize(hi.to_usize() - 1);
716+
Span(self.span.0.with_lo(new_lo))
717+
}
718+
}
719+
679720
/// Configures the span for this `Group`'s delimiters, but not its internal
680721
/// tokens.
681722
///

0 commit comments

Comments
 (0)