Skip to content

Commit 40fc8ba

Browse files
committed
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: dtolnay/syn#476. ```diff impl Group { fn span(&self) -> Span; + fn span_open(&self) -> Span; + fn span_close(&self) -> Span; } ``` Fixes #48187 r? @alexcrichton
2 parents df6ba0c + 57d6ada commit 40fc8ba

File tree

17 files changed

+191
-113
lines changed

17 files changed

+191
-113
lines changed

src/libproc_macro/lib.rs

+32-5
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,7 @@ use std::str::FromStr;
6363
use syntax::errors::DiagnosticBuilder;
6464
use syntax::parse::{self, token};
6565
use syntax::symbol::Symbol;
66-
use syntax::tokenstream;
66+
use syntax::tokenstream::{self, DelimSpan};
6767
use syntax_pos::{Pos, FileName};
6868

6969
/// The main type provided by this crate, representing an abstract stream of
@@ -609,7 +609,7 @@ impl fmt::Display for TokenTree {
609609
pub struct Group {
610610
delimiter: Delimiter,
611611
stream: TokenStream,
612-
span: Span,
612+
span: DelimSpan,
613613
}
614614

615615
#[stable(feature = "proc_macro_lib2", since = "1.29.0")]
@@ -650,7 +650,7 @@ impl Group {
650650
Group {
651651
delimiter: delimiter,
652652
stream: stream,
653-
span: Span::call_site(),
653+
span: DelimSpan::from_single(Span::call_site().0),
654654
}
655655
}
656656

@@ -671,9 +671,36 @@ 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 {
676-
self.span
681+
Span(self.span.entire())
682+
}
683+
684+
/// Returns the span pointing to the opening delimiter of this group.
685+
///
686+
/// ```text
687+
/// pub fn span_open(&self) -> Span {
688+
/// ^
689+
/// ```
690+
#[unstable(feature = "proc_macro_span", issue = "38356")]
691+
pub fn span_open(&self) -> Span {
692+
Span(self.span.open)
693+
}
694+
695+
/// Returns the span pointing to the closing delimiter of this group.
696+
///
697+
/// ```text
698+
/// pub fn span_close(&self) -> Span {
699+
/// ^
700+
/// ```
701+
#[unstable(feature = "proc_macro_span", issue = "38356")]
702+
pub fn span_close(&self) -> Span {
703+
Span(self.span.close)
677704
}
678705

679706
/// Configures the span for this `Group`'s delimiters, but not its internal
@@ -684,7 +711,7 @@ impl Group {
684711
/// tokens at the level of the `Group`.
685712
#[stable(feature = "proc_macro_lib2", since = "1.29.0")]
686713
pub fn set_span(&mut self, span: Span) {
687-
self.span = span;
714+
self.span = DelimSpan::from_single(span.0);
688715
}
689716
}
690717

src/libproc_macro/rustc.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,7 @@ impl TokenTree {
6464
tokenstream::TokenTree::Delimited(span, delimed) => {
6565
let delimiter = Delimiter::from_internal(delimed.delim);
6666
let mut g = Group::new(delimiter, ::TokenStream(delimed.tts.into()));
67-
g.set_span(Span(span));
67+
g.span = span;
6868
return g.into();
6969
}
7070
};
@@ -192,7 +192,7 @@ impl TokenTree {
192192
self::TokenTree::Punct(tt) => (tt.as_char(), tt.spacing(), tt.span()),
193193
self::TokenTree::Group(tt) => {
194194
return TokenTree::Delimited(
195-
tt.span.0,
195+
tt.span,
196196
Delimited {
197197
delim: tt.delimiter.to_internal(),
198198
tts: tt.stream.0.into(),

src/librustc/ich/hcx.rs

+12
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ use syntax::ast;
2727
use syntax::source_map::SourceMap;
2828
use syntax::ext::hygiene::SyntaxContext;
2929
use syntax::symbol::Symbol;
30+
use syntax::tokenstream::DelimSpan;
3031
use syntax_pos::{Span, DUMMY_SP};
3132
use syntax_pos::hygiene;
3233

@@ -392,6 +393,17 @@ impl<'a> HashStable<StableHashingContext<'a>> for Span {
392393
}
393394
}
394395

396+
impl<'a> HashStable<StableHashingContext<'a>> for DelimSpan {
397+
fn hash_stable<W: StableHasherResult>(
398+
&self,
399+
hcx: &mut StableHashingContext<'a>,
400+
hasher: &mut StableHasher<W>,
401+
) {
402+
self.open.hash_stable(hcx, hasher);
403+
self.close.hash_stable(hcx, hasher);
404+
}
405+
}
406+
395407
pub fn hash_stable_trait_impls<'a, 'gcx, W, R>(
396408
hcx: &mut StableHashingContext<'a>,
397409
hasher: &mut StableHasher<W>,

src/librustc_resolve/macros.rs

+3-2
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ use syntax::parse::parser::PathStyle;
3535
use syntax::parse::token::{self, Token};
3636
use syntax::ptr::P;
3737
use syntax::symbol::{Symbol, keywords};
38-
use syntax::tokenstream::{TokenStream, TokenTree, Delimited};
38+
use syntax::tokenstream::{TokenStream, TokenTree, Delimited, DelimSpan};
3939
use syntax::util::lev_distance::find_best_match_for_name;
4040
use syntax_pos::{Span, DUMMY_SP};
4141
use errors::Applicability;
@@ -296,7 +296,8 @@ impl<'a, 'crateloader: 'a> base::Resolver for Resolver<'a, 'crateloader> {
296296
tokens.push(TokenTree::Token(path.span, tok).into());
297297
}
298298
}
299-
attrs[i].tokens = TokenTree::Delimited(attrs[i].span, Delimited {
299+
let delim_span = DelimSpan::from_single(attrs[i].span);
300+
attrs[i].tokens = TokenTree::Delimited(delim_span, Delimited {
300301
delim: token::Paren,
301302
tts: TokenStream::concat(tokens).into(),
302303
}).into();

src/libsyntax/attr/mod.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ use parse::token::{self, Token};
3434
use ptr::P;
3535
use symbol::Symbol;
3636
use ThinVec;
37-
use tokenstream::{TokenStream, TokenTree, Delimited};
37+
use tokenstream::{TokenStream, TokenTree, Delimited, DelimSpan};
3838
use GLOBALS;
3939

4040
use std::iter;
@@ -535,7 +535,7 @@ impl MetaItemKind {
535535
}
536536
tokens.push(item.node.tokens());
537537
}
538-
TokenTree::Delimited(span, Delimited {
538+
TokenTree::Delimited(DelimSpan::from_single(span), Delimited {
539539
delim: token::Paren,
540540
tts: TokenStream::concat(tokens).into(),
541541
}).into()

src/libsyntax/ext/quote.rs

+13-9
Original file line numberDiff line numberDiff line change
@@ -10,14 +10,14 @@
1010

1111
use ast::{self, Arg, Arm, Block, Expr, Item, Pat, Stmt, Ty};
1212
use source_map::respan;
13-
use syntax_pos::Span;
13+
use syntax_pos::{Span, DUMMY_SP};
1414
use ext::base::ExtCtxt;
1515
use ext::base;
1616
use ext::build::AstBuilder;
1717
use parse::parser::{Parser, PathStyle};
1818
use parse::token;
1919
use ptr::P;
20-
use tokenstream::{TokenStream, TokenTree};
20+
use tokenstream::{DelimSpan, TokenStream, TokenTree};
2121

2222
/// Quasiquoting works via token trees.
2323
///
@@ -36,7 +36,7 @@ pub mod rt {
3636
use symbol::Symbol;
3737
use ThinVec;
3838

39-
use tokenstream::{self, TokenTree, TokenStream};
39+
use tokenstream::{self, DelimSpan, TokenTree, TokenStream};
4040

4141
pub use parse::new_parser_from_tts;
4242
pub use syntax_pos::{BytePos, Span, DUMMY_SP, FileName};
@@ -245,7 +245,8 @@ pub mod rt {
245245
}
246246
inner.push(self.tokens.clone());
247247

248-
r.push(TokenTree::Delimited(self.span, tokenstream::Delimited {
248+
let delim_span = DelimSpan::from_single(self.span);
249+
r.push(TokenTree::Delimited(delim_span, tokenstream::Delimited {
249250
delim: token::Bracket, tts: TokenStream::concat(inner).into()
250251
}));
251252
r
@@ -261,7 +262,7 @@ pub mod rt {
261262

262263
impl ToTokens for () {
263264
fn to_tokens(&self, _cx: &ExtCtxt) -> Vec<TokenTree> {
264-
vec![TokenTree::Delimited(DUMMY_SP, tokenstream::Delimited {
265+
vec![TokenTree::Delimited(DelimSpan::dummy(), tokenstream::Delimited {
265266
delim: token::Paren,
266267
tts: TokenStream::empty().into(),
267268
})]
@@ -385,13 +386,16 @@ pub fn unflatten(tts: Vec<TokenTree>) -> Vec<TokenTree> {
385386

386387
let mut results = Vec::new();
387388
let mut result = Vec::new();
389+
let mut open_span = DUMMY_SP;
388390
for tree in tts {
389391
match tree {
390-
TokenTree::Token(_, token::OpenDelim(..)) => {
392+
TokenTree::Token(span, token::OpenDelim(..)) => {
393+
open_span = span;
391394
results.push(::std::mem::replace(&mut result, Vec::new()));
392395
}
393396
TokenTree::Token(span, token::CloseDelim(delim)) => {
394-
let tree = TokenTree::Delimited(span, Delimited {
397+
let delim_span = DelimSpan::from_pair(open_span, span);
398+
let tree = TokenTree::Delimited(delim_span, Delimited {
395399
delim,
396400
tts: result.into_iter().map(TokenStream::from).collect::<TokenStream>().into(),
397401
});
@@ -756,9 +760,9 @@ fn statements_mk_tt(cx: &ExtCtxt, tt: &TokenTree, quoted: bool) -> Vec<ast::Stmt
756760
vec![cx.stmt_expr(e_push)]
757761
},
758762
TokenTree::Delimited(span, ref delimed) => {
759-
let mut stmts = statements_mk_tt(cx, &delimed.open_tt(span), false);
763+
let mut stmts = statements_mk_tt(cx, &delimed.open_tt(span.open), false);
760764
stmts.extend(statements_mk_tts(cx, delimed.stream()));
761-
stmts.extend(statements_mk_tt(cx, &delimed.close_tt(span), false));
765+
stmts.extend(statements_mk_tt(cx, &delimed.close_tt(span.close), false));
762766
stmts
763767
}
764768
}

src/libsyntax/ext/tt/macro_parser.rs

+14-14
Original file line numberDiff line numberDiff line change
@@ -85,7 +85,7 @@ pub use self::ParseResult::*;
8585
use self::TokenTreeOrTokenTreeSlice::*;
8686

8787
use ast::Ident;
88-
use syntax_pos::{self, BytePos, Span};
88+
use syntax_pos::{self, Span};
8989
use errors::FatalError;
9090
use ext::tt::quoted::{self, TokenTree};
9191
use parse::{Directory, ParseSess};
@@ -94,7 +94,7 @@ use parse::token::{self, DocComment, Nonterminal, Token};
9494
use print::pprust;
9595
use OneVector;
9696
use symbol::keywords;
97-
use tokenstream::TokenStream;
97+
use tokenstream::{DelimSpan, TokenStream};
9898

9999
use rustc_data_structures::fx::FxHashMap;
100100
use std::collections::hash_map::Entry::{Occupied, Vacant};
@@ -151,10 +151,10 @@ struct MatcherPos<'a> {
151151
top_elts: TokenTreeOrTokenTreeSlice<'a>,
152152
/// The position of the "dot" in this matcher
153153
idx: usize,
154-
/// The beginning position in the source that the beginning of this matcher corresponds to. In
155-
/// other words, the token in the source at `sp_lo` is matched against the first token of the
156-
/// matcher.
157-
sp_lo: BytePos,
154+
/// The first span of source source that the beginning of this matcher corresponds to. In other
155+
/// words, the token in the source whose span is `sp_open` is matched against the first token of
156+
/// the matcher.
157+
sp_open: Span,
158158

159159
/// For each named metavar in the matcher, we keep track of token trees matched against the
160160
/// metavar by the black box parser. In particular, there may be more than one match per
@@ -284,17 +284,17 @@ fn create_matches(len: usize) -> Vec<Rc<Vec<NamedMatch>>> {
284284
}
285285

286286
/// Generate the top-level matcher position in which the "dot" is before the first token of the
287-
/// matcher `ms` and we are going to start matching at position `lo` in the source.
288-
fn initial_matcher_pos(ms: &[TokenTree], lo: BytePos) -> MatcherPos {
287+
/// matcher `ms` and we are going to start matching at the span `open` in the source.
288+
fn initial_matcher_pos(ms: &[TokenTree], open: Span) -> MatcherPos {
289289
let match_idx_hi = count_names(ms);
290290
let matches = create_matches(match_idx_hi);
291291
MatcherPos {
292292
// Start with the top level matcher given to us
293293
top_elts: TtSeq(ms), // "elts" is an abbr. for "elements"
294294
// The "dot" is before the first token of the matcher
295295
idx: 0,
296-
// We start matching with byte `lo` in the source code
297-
sp_lo: lo,
296+
// We start matching at the span `open` in the source code
297+
sp_open: open,
298298

299299
// Initialize `matches` to a bunch of empty `Vec`s -- one for each metavar in `top_elts`.
300300
// `match_lo` for `top_elts` is 0 and `match_hi` is `matches.len()`. `match_cur` is 0 since
@@ -332,7 +332,7 @@ fn initial_matcher_pos(ms: &[TokenTree], lo: BytePos) -> MatcherPos {
332332
/// token tree it was derived from.
333333
#[derive(Debug, Clone)]
334334
pub enum NamedMatch {
335-
MatchedSeq(Rc<Vec<NamedMatch>>, syntax_pos::Span),
335+
MatchedSeq(Rc<Vec<NamedMatch>>, DelimSpan),
336336
MatchedNonterminal(Rc<Nonterminal>),
337337
}
338338

@@ -488,7 +488,7 @@ fn inner_parse_loop<'a>(
488488
// Add matches from this repetition to the `matches` of `up`
489489
for idx in item.match_lo..item.match_hi {
490490
let sub = item.matches[idx].clone();
491-
let span = span.with_lo(item.sp_lo);
491+
let span = DelimSpan::from_pair(item.sp_open, span);
492492
new_pos.push_match(idx, MatchedSeq(sub, span));
493493
}
494494

@@ -556,7 +556,7 @@ fn inner_parse_loop<'a>(
556556
match_cur: item.match_cur,
557557
match_hi: item.match_cur + seq.num_captures,
558558
up: Some(item),
559-
sp_lo: sp.lo(),
559+
sp_open: sp.open,
560560
top_elts: Tt(TokenTree::Sequence(sp, seq)),
561561
})));
562562
}
@@ -643,7 +643,7 @@ pub fn parse(
643643
//
644644
// This MatcherPos instance is allocated on the stack. All others -- and
645645
// there are frequently *no* others! -- are allocated on the heap.
646-
let mut initial = initial_matcher_pos(ms, parser.span.lo());
646+
let mut initial = initial_matcher_pos(ms, parser.span);
647647
let mut cur_items = smallvec![MatcherPosHandle::Ref(&mut initial)];
648648
let mut next_items = Vec::new();
649649

0 commit comments

Comments
 (0)