-
Notifications
You must be signed in to change notification settings - Fork 13.3k
Batch proc_macro RPC for TokenStream iteration and combination operations #98186
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
7678e6a
1793ee0
2b17219
0a049fd
4d45af9
af51424
df925fd
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -277,12 +277,6 @@ impl ToInternal<rustc_errors::Level> for Level { | |
|
||
pub struct FreeFunctions; | ||
|
||
#[derive(Clone)] | ||
pub struct TokenStreamIter { | ||
cursor: tokenstream::Cursor, | ||
stack: Vec<TokenTree<Group, Punct, Ident, Literal>>, | ||
} | ||
|
||
#[derive(Clone)] | ||
pub struct Group { | ||
delimiter: Delimiter, | ||
|
@@ -382,8 +376,6 @@ impl<'a, 'b> Rustc<'a, 'b> { | |
impl server::Types for Rustc<'_, '_> { | ||
type FreeFunctions = FreeFunctions; | ||
type TokenStream = TokenStream; | ||
type TokenStreamBuilder = tokenstream::TokenStreamBuilder; | ||
type TokenStreamIter = TokenStreamIter; | ||
type Group = Group; | ||
type Punct = Punct; | ||
type Ident = Ident; | ||
|
@@ -408,9 +400,6 @@ impl server::FreeFunctions for Rustc<'_, '_> { | |
} | ||
|
||
impl server::TokenStream for Rustc<'_, '_> { | ||
fn new(&mut self) -> Self::TokenStream { | ||
TokenStream::default() | ||
} | ||
fn is_empty(&mut self, stream: &Self::TokenStream) -> bool { | ||
stream.is_empty() | ||
} | ||
|
@@ -481,53 +470,75 @@ impl server::TokenStream for Rustc<'_, '_> { | |
) -> Self::TokenStream { | ||
tree.to_internal() | ||
} | ||
fn into_iter(&mut self, stream: Self::TokenStream) -> Self::TokenStreamIter { | ||
TokenStreamIter { cursor: stream.into_trees(), stack: vec![] } | ||
} | ||
} | ||
|
||
impl server::TokenStreamBuilder for Rustc<'_, '_> { | ||
fn new(&mut self) -> Self::TokenStreamBuilder { | ||
tokenstream::TokenStreamBuilder::new() | ||
} | ||
fn push(&mut self, builder: &mut Self::TokenStreamBuilder, stream: Self::TokenStream) { | ||
builder.push(stream); | ||
fn concat_trees( | ||
&mut self, | ||
base: Option<Self::TokenStream>, | ||
trees: Vec<TokenTree<Self::Group, Self::Punct, Self::Ident, Self::Literal>>, | ||
) -> Self::TokenStream { | ||
let mut builder = tokenstream::TokenStreamBuilder::new(); | ||
if let Some(base) = base { | ||
builder.push(base); | ||
} | ||
for tree in trees { | ||
builder.push(tree.to_internal()); | ||
} | ||
builder.build() | ||
} | ||
fn build(&mut self, builder: Self::TokenStreamBuilder) -> Self::TokenStream { | ||
fn concat_streams( | ||
&mut self, | ||
base: Option<Self::TokenStream>, | ||
streams: Vec<Self::TokenStream>, | ||
) -> Self::TokenStream { | ||
let mut builder = tokenstream::TokenStreamBuilder::new(); | ||
if let Some(base) = base { | ||
builder.push(base); | ||
} | ||
for stream in streams { | ||
builder.push(stream); | ||
} | ||
builder.build() | ||
} | ||
} | ||
|
||
impl server::TokenStreamIter for Rustc<'_, '_> { | ||
fn next( | ||
fn into_trees( | ||
&mut self, | ||
iter: &mut Self::TokenStreamIter, | ||
) -> Option<TokenTree<Self::Group, Self::Punct, Self::Ident, Self::Literal>> { | ||
stream: Self::TokenStream, | ||
) -> Vec<TokenTree<Self::Group, Self::Punct, Self::Ident, Self::Literal>> { | ||
// FIXME: This is a raw port of the previous approach (which had a | ||
// `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 tree = iter.stack.pop().or_else(|| { | ||
let next = iter.cursor.next_with_spacing()?; | ||
Some(TokenTree::from_internal((next, &mut iter.stack, self))) | ||
})?; | ||
// 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 let TokenTree::Group(ref group) = tree { | ||
if group.flatten { | ||
iter.cursor.append(group.stream.clone()); | ||
continue; | ||
let next = stack.pop().or_else(|| { | ||
let next = cursor.next_with_spacing()?; | ||
Some(TokenTree::from_internal((next, &mut stack, self))) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Random note: these from/to "internal" things should probably be s/internal/rustc, for clarity. |
||
}); | ||
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 { | ||
cursor.append(group.stream); | ||
continue; | ||
} | ||
tts.push(TokenTree::Group(group)); | ||
} | ||
Some(tt) => tts.push(tt), | ||
None => return tts, | ||
} | ||
return Some(tree); | ||
} | ||
} | ||
} | ||
|
||
impl server::Group for Rustc<'_, '_> { | ||
fn new(&mut self, delimiter: Delimiter, stream: Self::TokenStream) -> Self::Group { | ||
fn new(&mut self, delimiter: Delimiter, stream: Option<Self::TokenStream>) -> Self::Group { | ||
Group { | ||
delimiter, | ||
stream, | ||
stream: stream.unwrap_or_default(), | ||
span: DelimSpan::from_single(server::Span::call_site(self)), | ||
flatten: false, | ||
} | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -178,8 +178,6 @@ define_handles! { | |
'owned: | ||
FreeFunctions, | ||
TokenStream, | ||
TokenStreamBuilder, | ||
TokenStreamIter, | ||
Group, | ||
Literal, | ||
SourceFile, | ||
|
@@ -204,12 +202,6 @@ impl Clone for TokenStream { | |
} | ||
} | ||
|
||
impl Clone for TokenStreamIter { | ||
fn clone(&self) -> Self { | ||
self.clone() | ||
} | ||
} | ||
|
||
impl Clone for Group { | ||
fn clone(&self) -> Self { | ||
self.clone() | ||
|
@@ -435,7 +427,7 @@ impl Client<crate::TokenStream, crate::TokenStream> { | |
Client { | ||
get_handle_counters: HandleCounters::get, | ||
run: super::selfless_reify::reify_to_extern_c_fn_hrt_bridge(move |bridge| { | ||
run_client(bridge, |input| f(crate::TokenStream(input)).0) | ||
run_client(bridge, |input| f(crate::TokenStream(Some(input))).0) | ||
}), | ||
_marker: PhantomData, | ||
} | ||
|
@@ -450,7 +442,7 @@ impl Client<(crate::TokenStream, crate::TokenStream), crate::TokenStream> { | |
get_handle_counters: HandleCounters::get, | ||
run: super::selfless_reify::reify_to_extern_c_fn_hrt_bridge(move |bridge| { | ||
run_client(bridge, |(input, input2)| { | ||
f(crate::TokenStream(input), crate::TokenStream(input2)).0 | ||
f(crate::TokenStream(Some(input)), crate::TokenStream(Some(input2))).0 | ||
Comment on lines
444
to
+445
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Would it make sense to pass (Also I'm imagining we might be able to get rid of the split between single-input and dual-input entry-points, and There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. We could I suppose, but it's mildly inconvenient and introduces a bunch of extra code without much benefit so I'm inclined not to for now. |
||
}) | ||
}), | ||
_marker: PhantomData, | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I was going to say that this can be
SmallVec
with an inline capacity of 2 or so, but it looks like what's actually happening isTokenTree::from_internal
could actually be returningArrayVec<_, 3>
(I suppose at that point it's not even aFromInternal
impl heh).That is, despite being ominously named "stack" (as if it's some kind of vertical tree traversal), it's a weird FILO queue of pending additional
TokenTree
s (which your implementation could consume right away with e.g. a nestedfor
loop).(you can add a comment noting this, or just ignore it as a note to self)