diff --git a/compiler/rustc_expand/src/proc_macro_server.rs b/compiler/rustc_expand/src/proc_macro_server.rs index 8b6d5bcd935..cc66eefac3e 100644 --- a/compiler/rustc_expand/src/proc_macro_server.rs +++ b/compiler/rustc_expand/src/proc_macro_server.rs @@ -502,8 +502,8 @@ impl server::TokenStream for Rustc<'_, '_> { &mut self, stream: Self::TokenStream, ) -> Vec> { - // XXX: This is a raw port of the previous approach, and can probably be - // optimized. + // FIXME: This is a raw port of the previous approach, and can probably + // be optimized. let mut cursor = stream.into_trees(); let mut stack = Vec::new(); let mut tts = Vec::new(); diff --git a/library/proc_macro/src/lib.rs b/library/proc_macro/src/lib.rs index c21f365391c..6e645216c8d 100644 --- a/library/proc_macro/src/lib.rs +++ b/library/proc_macro/src/lib.rs @@ -233,14 +233,90 @@ impl From for TokenStream { } } +/// Non-generic helper for implementing `FromIterator` and +/// `Extend` with less monomorphization in calling crates. +struct ExtendStreamWithTreesHelper { + trees: Vec< + bridge::TokenTree< + bridge::client::Group, + bridge::client::Punct, + bridge::client::Ident, + bridge::client::Literal, + >, + >, +} + +impl ExtendStreamWithTreesHelper { + fn new(capacity: usize) -> Self { + ExtendStreamWithTreesHelper { trees: Vec::with_capacity(capacity) } + } + + fn push(&mut self, tree: TokenTree) { + self.trees.push(tree_to_bridge_tree(tree)); + } + + fn build(self) -> TokenStream { + if self.trees.is_empty() { + TokenStream(None) + } else { + TokenStream(Some(bridge::client::TokenStream::concat_trees(None, self.trees))) + } + } + + fn extend(self, stream: &mut TokenStream) { + if self.trees.is_empty() { + return; + } + stream.0 = Some(bridge::client::TokenStream::concat_trees(stream.0.take(), self.trees)) + } +} + +/// Non-generic helper for implementing `FromIterator` and +/// `Extend` with less monomorphization in calling crates. +struct ExtendStreamWithStreamsHelper { + streams: Vec, +} + +impl ExtendStreamWithStreamsHelper { + fn new(capacity: usize) -> Self { + ExtendStreamWithStreamsHelper { streams: Vec::with_capacity(capacity) } + } + + fn push(&mut self, stream: TokenStream) { + if let Some(stream) = stream.0 { + self.streams.push(stream); + } + } + + fn build(mut self) -> TokenStream { + if self.streams.len() <= 1 { + TokenStream(self.streams.pop()) + } else { + TokenStream(Some(bridge::client::TokenStream::concat_streams(None, self.streams))) + } + } + + fn extend(mut self, stream: &mut TokenStream) { + if self.streams.is_empty() { + return; + } + let base = stream.0.take(); + if base.is_none() && self.streams.len() == 1 { + stream.0 = self.streams.pop(); + } else { + stream.0 = Some(bridge::client::TokenStream::concat_streams(base, self.streams)); + } + } +} + /// Collects a number of token trees into a single stream. #[stable(feature = "proc_macro_lib2", since = "1.29.0")] impl iter::FromIterator for TokenStream { fn from_iter>(trees: I) -> Self { - TokenStream(Some(bridge::client::TokenStream::concat_trees( - None, - trees.into_iter().map(tree_to_bridge_tree).collect(), - ))) + let iter = trees.into_iter(); + let mut builder = ExtendStreamWithTreesHelper::new(iter.size_hint().0); + iter.for_each(|tree| builder.push(tree)); + builder.build() } } @@ -249,30 +325,30 @@ impl iter::FromIterator for TokenStream { #[stable(feature = "proc_macro_lib", since = "1.15.0")] impl iter::FromIterator for TokenStream { fn from_iter>(streams: I) -> Self { - TokenStream(Some(bridge::client::TokenStream::concat_streams( - None, - streams.into_iter().filter_map(|stream| stream.0).collect(), - ))) + let iter = streams.into_iter(); + let mut builder = ExtendStreamWithStreamsHelper::new(iter.size_hint().0); + iter.for_each(|stream| builder.push(stream)); + builder.build() } } #[stable(feature = "token_stream_extend", since = "1.30.0")] impl Extend for TokenStream { fn extend>(&mut self, trees: I) { - *self = TokenStream(Some(bridge::client::TokenStream::concat_trees( - self.0.take(), - trees.into_iter().map(|tree| tree_to_bridge_tree(tree)).collect(), - ))); + let iter = trees.into_iter(); + let mut builder = ExtendStreamWithTreesHelper::new(iter.size_hint().0); + iter.for_each(|tree| builder.push(tree)); + builder.extend(self); } } #[stable(feature = "token_stream_extend", since = "1.30.0")] impl Extend for TokenStream { fn extend>(&mut self, streams: I) { - *self = TokenStream(Some(bridge::client::TokenStream::concat_streams( - self.0.take(), - streams.into_iter().filter_map(|stream| stream.0).collect(), - ))); + let iter = streams.into_iter(); + let mut builder = ExtendStreamWithStreamsHelper::new(iter.size_hint().0); + iter.for_each(|stream| builder.push(stream)); + builder.extend(self); } }