diff options
| author | bors <bors@rust-lang.org> | 2018-09-09 13:27:44 +0000 |
|---|---|---|
| committer | bors <bors@rust-lang.org> | 2018-09-09 13:27:44 +0000 |
| commit | 40fc8ba5f95125f307ef17f11ec02b3f5fdad562 (patch) | |
| tree | 4cf149c2ccf4ced464d567ef8e7f2075c51d8815 /src/libsyntax/tokenstream.rs | |
| parent | df6ba0c4acceb5f63090bb20bd23f29c4f439376 (diff) | |
| parent | 57d6ada91d7c2d9af1115ae515b000fda93b3c4e (diff) | |
| download | rust-40fc8ba5f95125f307ef17f11ec02b3f5fdad562.tar.gz rust-40fc8ba5f95125f307ef17f11ec02b3f5fdad562.zip | |
Auto merge of #53902 - dtolnay:group, r=petrochenkov
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:
```rust
mod m {
type T =
}
```
```console
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: https://github.com/dtolnay/syn/issues/476.
```diff
impl Group {
fn span(&self) -> Span;
+ fn span_open(&self) -> Span;
+ fn span_close(&self) -> Span;
}
```
Fixes #48187
r? @alexcrichton
Diffstat (limited to 'src/libsyntax/tokenstream.rs')
| -rw-r--r-- | src/libsyntax/tokenstream.rs | 79 |
1 files changed, 53 insertions, 26 deletions
diff --git a/src/libsyntax/tokenstream.rs b/src/libsyntax/tokenstream.rs index 840ee299bf3..70867f9e42f 100644 --- a/src/libsyntax/tokenstream.rs +++ b/src/libsyntax/tokenstream.rs @@ -22,7 +22,7 @@ //! and a borrowed `TokenStream` is sufficient to build an owned `TokenStream` without taking //! ownership of the original. -use syntax_pos::{BytePos, Span, DUMMY_SP}; +use syntax_pos::{BytePos, Mark, Span, DUMMY_SP}; use ext::base; use ext::tt::{macro_parser, quoted}; use parse::Directory; @@ -97,7 +97,7 @@ pub enum TokenTree { /// A single token Token(Span, token::Token), /// A delimited sequence of token trees - Delimited(Span, Delimited), + Delimited(DelimSpan, Delimited), } impl TokenTree { @@ -145,16 +145,16 @@ impl TokenTree { /// Retrieve the TokenTree's span. pub fn span(&self) -> Span { match *self { - TokenTree::Token(sp, _) | TokenTree::Delimited(sp, _) => sp, + TokenTree::Token(sp, _) => sp, + TokenTree::Delimited(sp, _) => sp.entire(), } } /// Modify the `TokenTree`'s span inplace. pub fn set_span(&mut self, span: Span) { match *self { - TokenTree::Token(ref mut sp, _) | TokenTree::Delimited(ref mut sp, _) => { - *sp = span; - } + TokenTree::Token(ref mut sp, _) => *sp = span, + TokenTree::Delimited(ref mut sp, _) => *sp = DelimSpan::from_single(span), } } @@ -192,27 +192,20 @@ impl TokenStream { let mut iter = slice.iter().enumerate().peekable(); while let Some((pos, ts)) = iter.next() { if let Some((_, next)) = iter.peek() { - match (ts, next) { - (TokenStream { - kind: TokenStreamKind::Tree(TokenTree::Token(_, token::Token::Comma)) - }, _) | - (_, TokenStream { - kind: TokenStreamKind::Tree(TokenTree::Token(_, token::Token::Comma)) - }) => {} - (TokenStream { - kind: TokenStreamKind::Tree(TokenTree::Token(sp, _)) - }, _) | - (TokenStream { - kind: TokenStreamKind::Tree(TokenTree::Delimited(sp, _)) - }, _) => { - let sp = sp.shrink_to_hi(); - let comma = TokenStream { - kind: TokenStreamKind::Tree(TokenTree::Token(sp, token::Comma)), - }; - suggestion = Some((pos, comma, sp)); + let sp = match (&ts.kind, &next.kind) { + (TokenStreamKind::Tree(TokenTree::Token(_, token::Token::Comma)), _) | + (_, TokenStreamKind::Tree(TokenTree::Token(_, token::Token::Comma))) => { + continue; } - _ => {} - } + (TokenStreamKind::Tree(TokenTree::Token(sp, _)), _) => *sp, + (TokenStreamKind::Tree(TokenTree::Delimited(sp, _)), _) => sp.entire(), + _ => continue, + }; + let sp = sp.shrink_to_hi(); + let comma = TokenStream { + kind: TokenStreamKind::Tree(TokenTree::Token(sp, token::Comma)), + }; + suggestion = Some((pos, comma, sp)); } } if let Some((pos, comma, sp)) = suggestion { @@ -718,6 +711,40 @@ impl Decodable for ThinTokenStream { } } +#[derive(Debug, Copy, Clone, PartialEq, RustcEncodable, RustcDecodable)] +pub struct DelimSpan { + pub open: Span, + pub close: Span, +} + +impl DelimSpan { + pub fn from_single(sp: Span) -> Self { + DelimSpan { + open: sp, + close: sp, + } + } + + pub fn from_pair(open: Span, close: Span) -> Self { + DelimSpan { open, close } + } + + pub fn dummy() -> Self { + Self::from_single(DUMMY_SP) + } + + pub fn entire(self) -> Span { + self.open.with_hi(self.close.hi()) + } + + pub fn apply_mark(self, mark: Mark) -> Self { + DelimSpan { + open: self.open.apply_mark(mark), + close: self.close.apply_mark(mark), + } + } +} + #[cfg(test)] mod tests { use super::*; |
