proc_macro: stop using a remote object handle for Group

This greatly reduces round-trips to fetch relevant extra information about the
token in proc macro code, and avoids RPC messages to create Group tokens.
This commit is contained in:
Nika Layzell 2021-07-01 17:36:38 -04:00
parent 72bfe618fa
commit f28dfdf1c7
5 changed files with 204 additions and 249 deletions

View file

@ -2,7 +2,7 @@ use crate::base::ExtCtxt;
use rustc_ast as ast; use rustc_ast as ast;
use rustc_ast::token; use rustc_ast::token;
use rustc_ast::tokenstream::{self, DelimSpan, Spacing::*, TokenStream, TreeAndSpacing}; use rustc_ast::tokenstream::{self, Spacing::*, TokenStream};
use rustc_ast_pretty::pprust; use rustc_ast_pretty::pprust;
use rustc_data_structures::fx::FxHashMap; use rustc_data_structures::fx::FxHashMap;
use rustc_data_structures::sync::Lrc; use rustc_data_structures::sync::Lrc;
@ -14,7 +14,7 @@ use rustc_span::def_id::CrateNum;
use rustc_span::symbol::{self, kw, sym, Symbol}; use rustc_span::symbol::{self, kw, sym, Symbol};
use rustc_span::{BytePos, FileName, Pos, SourceFile, Span}; use rustc_span::{BytePos, FileName, Pos, SourceFile, Span};
use pm::bridge::{server, ExpnGlobals, Punct, TokenTree}; use pm::bridge::{server, DelimSpan, ExpnGlobals, Group, Punct, TokenTree};
use pm::{Delimiter, Level, LineColumn}; use pm::{Delimiter, Level, LineColumn};
use std::ops::Bound; use std::ops::Bound;
use std::{ascii, panic}; use std::{ascii, panic};
@ -49,46 +49,57 @@ impl ToInternal<token::Delimiter> for Delimiter {
} }
} }
impl FromInternal<(TreeAndSpacing, &'_ mut Vec<Self>, &mut Rustc<'_, '_>)> impl FromInternal<(TokenStream, &mut Rustc<'_, '_>)>
for TokenTree<Span, Group, Ident, Literal> for Vec<TokenTree<TokenStream, Span, Ident, Literal>>
{ {
fn from_internal( fn from_internal((stream, rustc): (TokenStream, &mut Rustc<'_, '_>)) -> Self {
((tree, spacing), stack, rustc): (TreeAndSpacing, &mut Vec<Self>, &mut Rustc<'_, '_>),
) -> Self {
use rustc_ast::token::*; use rustc_ast::token::*;
let mut cursor = stream.into_trees();
let mut trees = Vec::new();
while let Some((tree, spacing)) = cursor.next_with_spacing() {
let joint = spacing == Joint; let joint = spacing == Joint;
let Token { kind, span } = match tree { let Token { kind, span } = match tree {
tokenstream::TokenTree::Delimited(span, delim, tts) => { tokenstream::TokenTree::Delimited(span, delim, tts) => {
let delimiter = pm::Delimiter::from_internal(delim); let delimiter = pm::Delimiter::from_internal(delim);
return TokenTree::Group(Group { delimiter, stream: tts, span, flatten: false }); trees.push(TokenTree::Group(Group {
delimiter,
stream: Some(tts),
span: DelimSpan {
open: span.open,
close: span.close,
entire: span.entire(),
},
}));
continue;
} }
tokenstream::TokenTree::Token(token) => token, tokenstream::TokenTree::Token(token) => token,
}; };
macro_rules! tt { macro_rules! tt {
($ty:ident { $($field:ident $(: $value:expr)*),+ $(,)? }) => ( ($ty:ident { $($field:ident $(: $value:expr)*),+ $(,)? }) => (
TokenTree::$ty(self::$ty { trees.push(TokenTree::$ty(self::$ty {
$($field $(: $value)*,)+ $($field $(: $value)*,)+
span, span,
}) }))
); );
($ty:ident::$method:ident($($value:expr),*)) => ( ($ty:ident::$method:ident($($value:expr),*)) => (
TokenTree::$ty(self::$ty::$method($($value,)* span)) trees.push(TokenTree::$ty(self::$ty::$method($($value,)* span)))
); );
} }
macro_rules! op { macro_rules! op {
($a:expr) => { ($a:expr) => {{
tt!(Punct { ch: $a, joint }) tt!(Punct { ch: $a, joint });
}; }};
($a:expr, $b:expr) => {{ ($a:expr, $b:expr) => {{
stack.push(tt!(Punct { ch: $b, joint })); tt!(Punct { ch: $a, joint: true });
tt!(Punct { ch: $a, joint: true }) tt!(Punct { ch: $b, joint });
}}; }};
($a:expr, $b:expr, $c:expr) => {{ ($a:expr, $b:expr, $c:expr) => {{
stack.push(tt!(Punct { ch: $c, joint })); tt!(Punct { ch: $a, joint: true });
stack.push(tt!(Punct { ch: $b, joint: true })); tt!(Punct { ch: $b, joint: true });
tt!(Punct { ch: $a, joint: true }) tt!(Punct { ch: $c, joint });
}}; }};
} }
@ -145,8 +156,8 @@ impl FromInternal<(TreeAndSpacing, &'_ mut Vec<Self>, &mut Rustc<'_, '_>)>
Ident(name, is_raw) => tt!(Ident::new(rustc.sess(), name, is_raw)), Ident(name, is_raw) => tt!(Ident::new(rustc.sess(), name, is_raw)),
Lifetime(name) => { Lifetime(name) => {
let ident = symbol::Ident::new(name, span).without_first_quote(); let ident = symbol::Ident::new(name, span).without_first_quote();
stack.push(tt!(Ident::new(rustc.sess(), ident.name, false))); tt!(Punct { ch: '\'', joint: true });
tt!(Punct { ch: '\'', joint: true }) tt!(Ident::new(rustc.sess(), ident.name, false));
} }
Literal(lit) => tt!(Literal { lit }), Literal(lit) => tt!(Literal { lit }),
DocComment(_, attr_style, data) => { DocComment(_, attr_style, data) => {
@ -154,7 +165,7 @@ impl FromInternal<(TreeAndSpacing, &'_ mut Vec<Self>, &mut Rustc<'_, '_>)>
for ch in data.as_str().chars() { for ch in data.as_str().chars() {
escaped.extend(ch.escape_debug()); escaped.extend(ch.escape_debug());
} }
let stream = [ let stream = vec![
Ident(sym::doc, false), Ident(sym::doc, false),
Eq, Eq,
TokenKind::lit(token::Str, Symbol::intern(&escaped), None), TokenKind::lit(token::Str, Symbol::intern(&escaped), None),
@ -162,44 +173,54 @@ impl FromInternal<(TreeAndSpacing, &'_ mut Vec<Self>, &mut Rustc<'_, '_>)>
.into_iter() .into_iter()
.map(|kind| tokenstream::TokenTree::token(kind, span)) .map(|kind| tokenstream::TokenTree::token(kind, span))
.collect(); .collect();
stack.push(TokenTree::Group(Group { tt!(Punct { ch: '#', joint: false });
delimiter: pm::Delimiter::Bracket,
stream,
span: DelimSpan::from_single(span),
flatten: false,
}));
if attr_style == ast::AttrStyle::Inner { if attr_style == ast::AttrStyle::Inner {
stack.push(tt!(Punct { ch: '!', joint: false })); tt!(Punct { ch: '!', joint: false });
} }
tt!(Punct { ch: '#', joint: false }) trees.push(TokenTree::Group(Group {
delimiter: pm::Delimiter::Bracket,
stream: Some(stream),
span: DelimSpan::from_single(span),
}));
} }
Interpolated(nt) if let NtIdent(ident, is_raw) = *nt => { Interpolated(nt) if let NtIdent(ident, is_raw) = *nt => {
TokenTree::Ident(Ident::new(rustc.sess(), ident.name, is_raw, ident.span)) trees.push(TokenTree::Ident(Ident::new(rustc.sess(), ident.name, is_raw, ident.span)))
} }
Interpolated(nt) => { Interpolated(nt) => {
TokenTree::Group(Group { let stream = TokenStream::from_nonterminal_ast(&nt);
if crate::base::nt_pretty_printing_compatibility_hack(&nt, rustc.sess()) {
trees.extend(Self::from_internal((stream, rustc)));
} else {
trees.push(TokenTree::Group(Group {
delimiter: pm::Delimiter::None, delimiter: pm::Delimiter::None,
stream: TokenStream::from_nonterminal_ast(&nt), stream: Some(stream),
span: DelimSpan::from_single(span), span: DelimSpan::from_single(span),
flatten: crate::base::nt_pretty_printing_compatibility_hack(&nt, rustc.sess()), }))
}) }
} }
OpenDelim(..) | CloseDelim(..) => unreachable!(), OpenDelim(..) | CloseDelim(..) => unreachable!(),
Eof => unreachable!(), Eof => unreachable!(),
} }
} }
trees
}
} }
impl ToInternal<TokenStream> for TokenTree<Span, Group, Ident, Literal> { impl ToInternal<TokenStream> for TokenTree<TokenStream, Span, Ident, Literal> {
fn to_internal(self) -> TokenStream { fn to_internal(self) -> TokenStream {
use rustc_ast::token::*; use rustc_ast::token::*;
let (ch, joint, span) = match self { let (ch, joint, span) = match self {
TokenTree::Punct(Punct { ch, joint, span }) => (ch, joint, span), TokenTree::Punct(Punct { ch, joint, span }) => (ch, joint, span),
TokenTree::Group(Group { delimiter, stream, span, .. }) => { TokenTree::Group(Group { delimiter, stream, span: DelimSpan { open, close, .. } }) => {
return tokenstream::TokenTree::Delimited(span, delimiter.to_internal(), stream) return tokenstream::TokenTree::Delimited(
tokenstream::DelimSpan { open, close },
delimiter.to_internal(),
stream.unwrap_or_default(),
)
.into(); .into();
} }
TokenTree::Ident(self::Ident { sym, is_raw, span }) => { TokenTree::Ident(self::Ident { sym, is_raw, span }) => {
@ -277,17 +298,6 @@ impl ToInternal<rustc_errors::Level> for Level {
pub struct FreeFunctions; pub struct FreeFunctions;
#[derive(Clone)]
pub struct Group {
delimiter: Delimiter,
stream: TokenStream,
span: DelimSpan,
/// A hack used to pass AST fragments to attribute and derive macros
/// as a single nonterminal token instead of a token stream.
/// FIXME: It needs to be removed, but there are some compatibility issues (see #73345).
flatten: bool,
}
#[derive(Copy, Clone, PartialEq, Eq, Hash)] #[derive(Copy, Clone, PartialEq, Eq, Hash)]
pub struct Ident { pub struct Ident {
sym: Symbol, sym: Symbol,
@ -356,7 +366,6 @@ impl<'a, 'b> Rustc<'a, 'b> {
impl server::Types for Rustc<'_, '_> { impl server::Types for Rustc<'_, '_> {
type FreeFunctions = FreeFunctions; type FreeFunctions = FreeFunctions;
type TokenStream = TokenStream; type TokenStream = TokenStream;
type Group = Group;
type Ident = Ident; type Ident = Ident;
type Literal = Literal; type Literal = Literal;
type SourceFile = Lrc<SourceFile>; type SourceFile = Lrc<SourceFile>;
@ -449,7 +458,7 @@ impl server::TokenStream for Rustc<'_, '_> {
fn from_token_tree( fn from_token_tree(
&mut self, &mut self,
tree: TokenTree<Self::Span, Self::Group, Self::Ident, Self::Literal>, tree: TokenTree<Self::TokenStream, Self::Span, Self::Ident, Self::Literal>,
) -> Self::TokenStream { ) -> Self::TokenStream {
tree.to_internal() tree.to_internal()
} }
@ -457,7 +466,7 @@ impl server::TokenStream for Rustc<'_, '_> {
fn concat_trees( fn concat_trees(
&mut self, &mut self,
base: Option<Self::TokenStream>, base: Option<Self::TokenStream>,
trees: Vec<TokenTree<Self::Span, Self::Group, Self::Ident, Self::Literal>>, trees: Vec<TokenTree<Self::TokenStream, Self::Span, Self::Ident, Self::Literal>>,
) -> Self::TokenStream { ) -> Self::TokenStream {
let mut builder = tokenstream::TokenStreamBuilder::new(); let mut builder = tokenstream::TokenStreamBuilder::new();
if let Some(base) = base { if let Some(base) = base {
@ -487,71 +496,8 @@ impl server::TokenStream for Rustc<'_, '_> {
fn into_trees( fn into_trees(
&mut self, &mut self,
stream: Self::TokenStream, stream: Self::TokenStream,
) -> Vec<TokenTree<Self::Span, Self::Group, Self::Ident, Self::Literal>> { ) -> Vec<TokenTree<Self::TokenStream, Self::Span, Self::Ident, Self::Literal>> {
// FIXME: This is a raw port of the previous approach (which had a FromInternal::from_internal((stream, self))
// `TokenStreamIter` server-side object with a single `next` method),
// and can probably be optimized (for bulk conversion).
let mut cursor = stream.into_trees();
let mut stack = Vec::new();
let mut tts = Vec::new();
loop {
let next = stack.pop().or_else(|| {
let next = cursor.next_with_spacing()?;
Some(TokenTree::from_internal((next, &mut stack, self)))
});
match next {
Some(TokenTree::Group(group)) => {
// A hack used to pass AST fragments to attribute and derive
// macros as a single nonterminal token instead of a token
// stream. Such token needs to be "unwrapped" and not
// represented as a delimited group.
// FIXME: It needs to be removed, but there are some
// compatibility issues (see #73345).
if group.flatten {
tts.append(&mut self.into_trees(group.stream));
} else {
tts.push(TokenTree::Group(group));
}
}
Some(tt) => tts.push(tt),
None => return tts,
}
}
}
}
impl server::Group for Rustc<'_, '_> {
fn new(&mut self, delimiter: Delimiter, stream: Option<Self::TokenStream>) -> Self::Group {
Group {
delimiter,
stream: stream.unwrap_or_default(),
span: DelimSpan::from_single(self.call_site),
flatten: false,
}
}
fn delimiter(&mut self, group: &Self::Group) -> Delimiter {
group.delimiter
}
fn stream(&mut self, group: &Self::Group) -> Self::TokenStream {
group.stream.clone()
}
fn span(&mut self, group: &Self::Group) -> Self::Span {
group.span.entire()
}
fn span_open(&mut self, group: &Self::Group) -> Self::Span {
group.span.open
}
fn span_close(&mut self, group: &Self::Group) -> Self::Span {
group.span.close
}
fn set_span(&mut self, group: &mut Self::Group, span: Self::Span) {
group.span = DelimSpan::from_single(span);
} }
} }

View file

@ -175,7 +175,6 @@ define_handles! {
'owned: 'owned:
FreeFunctions, FreeFunctions,
TokenStream, TokenStream,
Group,
Literal, Literal,
SourceFile, SourceFile,
MultiSpan, MultiSpan,
@ -198,12 +197,6 @@ impl Clone for TokenStream {
} }
} }
impl Clone for Group {
fn clone(&self) -> Self {
self.clone()
}
}
impl Clone for Literal { impl Clone for Literal {
fn clone(&self) -> Self { fn clone(&self) -> Self {
self.clone() self.clone()

View file

@ -65,11 +65,11 @@ macro_rules! with_api {
fn from_str(src: &str) -> $S::TokenStream; fn from_str(src: &str) -> $S::TokenStream;
fn to_string($self: &$S::TokenStream) -> String; fn to_string($self: &$S::TokenStream) -> String;
fn from_token_tree( fn from_token_tree(
tree: TokenTree<$S::Span, $S::Group, $S::Ident, $S::Literal>, tree: TokenTree<$S::TokenStream, $S::Span, $S::Ident, $S::Literal>,
) -> $S::TokenStream; ) -> $S::TokenStream;
fn concat_trees( fn concat_trees(
base: Option<$S::TokenStream>, base: Option<$S::TokenStream>,
trees: Vec<TokenTree<$S::Span, $S::Group, $S::Ident, $S::Literal>>, trees: Vec<TokenTree<$S::TokenStream, $S::Span, $S::Ident, $S::Literal>>,
) -> $S::TokenStream; ) -> $S::TokenStream;
fn concat_streams( fn concat_streams(
base: Option<$S::TokenStream>, base: Option<$S::TokenStream>,
@ -77,18 +77,7 @@ macro_rules! with_api {
) -> $S::TokenStream; ) -> $S::TokenStream;
fn into_trees( fn into_trees(
$self: $S::TokenStream $self: $S::TokenStream
) -> Vec<TokenTree<$S::Span, $S::Group, $S::Ident, $S::Literal>>; ) -> Vec<TokenTree<$S::TokenStream, $S::Span, $S::Ident, $S::Literal>>;
},
Group {
fn drop($self: $S::Group);
fn clone($self: &$S::Group) -> $S::Group;
fn new(delimiter: Delimiter, stream: Option<$S::TokenStream>) -> $S::Group;
fn delimiter($self: &$S::Group) -> Delimiter;
fn stream($self: &$S::Group) -> $S::TokenStream;
fn span($self: &$S::Group) -> $S::Span;
fn span_open($self: &$S::Group) -> $S::Span;
fn span_close($self: &$S::Group) -> $S::Span;
fn set_span($self: &mut $S::Group, span: $S::Span);
}, },
Ident { Ident {
fn new(string: &str, span: $S::Span, is_raw: bool) -> $S::Ident; fn new(string: &str, span: $S::Span, is_raw: bool) -> $S::Ident;
@ -441,6 +430,30 @@ compound_traits!(
} }
); );
#[derive(Copy, Clone)]
pub struct DelimSpan<S> {
pub open: S,
pub close: S,
pub entire: S,
}
impl<S: Copy> DelimSpan<S> {
pub fn from_single(span: S) -> Self {
DelimSpan { open: span, close: span, entire: span }
}
}
compound_traits!(struct DelimSpan<Sp> { open, close, entire });
#[derive(Clone)]
pub struct Group<T, S> {
pub delimiter: Delimiter,
pub stream: Option<T>,
pub span: DelimSpan<S>,
}
compound_traits!(struct Group<T, Sp> { delimiter, stream, span });
#[derive(Clone)] #[derive(Clone)]
pub struct Punct<S> { pub struct Punct<S> {
pub ch: char, pub ch: char,
@ -451,15 +464,15 @@ pub struct Punct<S> {
compound_traits!(struct Punct<Sp> { ch, joint, span }); compound_traits!(struct Punct<Sp> { ch, joint, span });
#[derive(Clone)] #[derive(Clone)]
pub enum TokenTree<S, G, I, L> { pub enum TokenTree<T, S, I, L> {
Group(G), Group(Group<T, S>),
Punct(Punct<S>), Punct(Punct<S>),
Ident(I), Ident(I),
Literal(L), Literal(L),
} }
compound_traits!( compound_traits!(
enum TokenTree<Sp, G, I, L> { enum TokenTree<T, Sp, I, L> {
Group(tt), Group(tt),
Punct(tt), Punct(tt),
Ident(tt), Ident(tt),

View file

@ -8,7 +8,6 @@ use super::client::HandleStore;
pub trait Types { pub trait Types {
type FreeFunctions: 'static; type FreeFunctions: 'static;
type TokenStream: 'static + Clone; type TokenStream: 'static + Clone;
type Group: 'static + Clone;
type Ident: 'static + Copy + Eq + Hash; type Ident: 'static + Copy + Eq + Hash;
type Literal: 'static + Clone; type Literal: 'static + Clone;
type SourceFile: 'static + Clone; type SourceFile: 'static + Clone;

View file

@ -212,8 +212,8 @@ pub use quote::{quote, quote_span};
fn tree_to_bridge_tree( fn tree_to_bridge_tree(
tree: TokenTree, tree: TokenTree,
) -> bridge::TokenTree< ) -> bridge::TokenTree<
bridge::client::TokenStream,
bridge::client::Span, bridge::client::Span,
bridge::client::Group,
bridge::client::Ident, bridge::client::Ident,
bridge::client::Literal, bridge::client::Literal,
> { > {
@ -238,8 +238,8 @@ impl From<TokenTree> for TokenStream {
struct ConcatTreesHelper { struct ConcatTreesHelper {
trees: Vec< trees: Vec<
bridge::TokenTree< bridge::TokenTree<
bridge::client::TokenStream,
bridge::client::Span, bridge::client::Span,
bridge::client::Group,
bridge::client::Ident, bridge::client::Ident,
bridge::client::Literal, bridge::client::Literal,
>, >,
@ -365,8 +365,8 @@ pub mod token_stream {
pub struct IntoIter( pub struct IntoIter(
std::vec::IntoIter< std::vec::IntoIter<
bridge::TokenTree< bridge::TokenTree<
bridge::client::TokenStream,
bridge::client::Span, bridge::client::Span,
bridge::client::Group,
bridge::client::Ident, bridge::client::Ident,
bridge::client::Literal, bridge::client::Literal,
>, >,
@ -788,7 +788,7 @@ impl fmt::Display for TokenTree {
/// A `Group` internally contains a `TokenStream` which is surrounded by `Delimiter`s. /// A `Group` internally contains a `TokenStream` which is surrounded by `Delimiter`s.
#[derive(Clone)] #[derive(Clone)]
#[stable(feature = "proc_macro_lib2", since = "1.29.0")] #[stable(feature = "proc_macro_lib2", since = "1.29.0")]
pub struct Group(bridge::client::Group); pub struct Group(bridge::Group<bridge::client::TokenStream, bridge::client::Span>);
#[stable(feature = "proc_macro_lib2", since = "1.29.0")] #[stable(feature = "proc_macro_lib2", since = "1.29.0")]
impl !Send for Group {} impl !Send for Group {}
@ -825,13 +825,17 @@ impl Group {
/// method below. /// method below.
#[stable(feature = "proc_macro_lib2", since = "1.29.0")] #[stable(feature = "proc_macro_lib2", since = "1.29.0")]
pub fn new(delimiter: Delimiter, stream: TokenStream) -> Group { pub fn new(delimiter: Delimiter, stream: TokenStream) -> Group {
Group(bridge::client::Group::new(delimiter, stream.0)) Group(bridge::Group {
delimiter,
stream: stream.0,
span: bridge::DelimSpan::from_single(Span::call_site().0),
})
} }
/// Returns the delimiter of this `Group` /// Returns the delimiter of this `Group`
#[stable(feature = "proc_macro_lib2", since = "1.29.0")] #[stable(feature = "proc_macro_lib2", since = "1.29.0")]
pub fn delimiter(&self) -> Delimiter { pub fn delimiter(&self) -> Delimiter {
self.0.delimiter() self.0.delimiter
} }
/// Returns the `TokenStream` of tokens that are delimited in this `Group`. /// Returns the `TokenStream` of tokens that are delimited in this `Group`.
@ -840,7 +844,7 @@ impl Group {
/// returned above. /// returned above.
#[stable(feature = "proc_macro_lib2", since = "1.29.0")] #[stable(feature = "proc_macro_lib2", since = "1.29.0")]
pub fn stream(&self) -> TokenStream { pub fn stream(&self) -> TokenStream {
TokenStream(Some(self.0.stream())) TokenStream(self.0.stream.clone())
} }
/// Returns the span for the delimiters of this token stream, spanning the /// Returns the span for the delimiters of this token stream, spanning the
@ -852,7 +856,7 @@ impl Group {
/// ``` /// ```
#[stable(feature = "proc_macro_lib2", since = "1.29.0")] #[stable(feature = "proc_macro_lib2", since = "1.29.0")]
pub fn span(&self) -> Span { pub fn span(&self) -> Span {
Span(self.0.span()) Span(self.0.span.entire)
} }
/// Returns the span pointing to the opening delimiter of this group. /// Returns the span pointing to the opening delimiter of this group.
@ -863,7 +867,7 @@ impl Group {
/// ``` /// ```
#[stable(feature = "proc_macro_group_span", since = "1.55.0")] #[stable(feature = "proc_macro_group_span", since = "1.55.0")]
pub fn span_open(&self) -> Span { pub fn span_open(&self) -> Span {
Span(self.0.span_open()) Span(self.0.span.open)
} }
/// Returns the span pointing to the closing delimiter of this group. /// Returns the span pointing to the closing delimiter of this group.
@ -874,7 +878,7 @@ impl Group {
/// ``` /// ```
#[stable(feature = "proc_macro_group_span", since = "1.55.0")] #[stable(feature = "proc_macro_group_span", since = "1.55.0")]
pub fn span_close(&self) -> Span { pub fn span_close(&self) -> Span {
Span(self.0.span_close()) Span(self.0.span.close)
} }
/// Configures the span for this `Group`'s delimiters, but not its internal /// Configures the span for this `Group`'s delimiters, but not its internal
@ -885,7 +889,7 @@ impl Group {
/// tokens at the level of the `Group`. /// tokens at the level of the `Group`.
#[stable(feature = "proc_macro_lib2", since = "1.29.0")] #[stable(feature = "proc_macro_lib2", since = "1.29.0")]
pub fn set_span(&mut self, span: Span) { pub fn set_span(&mut self, span: Span) {
self.0.set_span(span.0); self.0.span = bridge::DelimSpan::from_single(span.0);
} }
} }