diff --git a/crates/hir-def/src/nameres/collector.rs b/crates/hir-def/src/nameres/collector.rs
index fb6fd867a1..49d59cf9ad 100644
--- a/crates/hir-def/src/nameres/collector.rs
+++ b/crates/hir-def/src/nameres/collector.rs
@@ -2125,7 +2125,7 @@ impl ModCollector<'_, '_> {
let is_export = export_attr.exists();
let local_inner = if is_export {
- export_attr.tt_values().flat_map(|it| &it.token_trees).any(|it| match it {
+ export_attr.tt_values().flat_map(|it| it.token_trees.iter()).any(|it| match it {
tt::TokenTree::Leaf(tt::Leaf::Ident(ident)) => {
ident.text.contains("local_inner_macros")
}
diff --git a/crates/hir-expand/src/attrs.rs b/crates/hir-expand/src/attrs.rs
index c20c1639e1..1c92dea38e 100644
--- a/crates/hir-expand/src/attrs.rs
+++ b/crates/hir-expand/src/attrs.rs
@@ -123,7 +123,7 @@ impl RawAttrs {
.filter_map(|(idx, attr)| Attr::from_tt(db, attr, index.with_cfg_attr(idx)));
let cfg_options = &crate_graph[krate].cfg_options;
- let cfg = Subtree { delimiter: subtree.delimiter, token_trees: cfg.to_vec() };
+ let cfg = Subtree { delimiter: subtree.delimiter, token_trees: Box::from(cfg) };
let cfg = CfgExpr::parse(&cfg);
if cfg_options.check(&cfg) == Some(false) {
smallvec![]
diff --git a/crates/hir-expand/src/builtin_attr_macro.rs b/crates/hir-expand/src/builtin_attr_macro.rs
index dd2aa94ad0..903b0d4807 100644
--- a/crates/hir-expand/src/builtin_attr_macro.rs
+++ b/crates/hir-expand/src/builtin_attr_macro.rs
@@ -137,5 +137,8 @@ pub fn pseudo_derive_attr_expansion(
token_trees.extend(tt.iter().cloned());
token_trees.push(mk_leaf(']'));
}
- ExpandResult::ok(tt::Subtree { delimiter: tt.delimiter, token_trees })
+ ExpandResult::ok(tt::Subtree {
+ delimiter: tt.delimiter,
+ token_trees: token_trees.into_boxed_slice(),
+ })
}
diff --git a/crates/hir-expand/src/builtin_fn_macro.rs b/crates/hir-expand/src/builtin_fn_macro.rs
index 29d389f656..c2f6a8396d 100644
--- a/crates/hir-expand/src/builtin_fn_macro.rs
+++ b/crates/hir-expand/src/builtin_fn_macro.rs
@@ -155,10 +155,10 @@ fn line_expand(
// not incremental
ExpandResult::ok(tt::Subtree {
delimiter: tt::Delimiter::invisible_spanned(span),
- token_trees: vec![tt::TokenTree::Leaf(tt::Leaf::Literal(tt::Literal {
+ token_trees: Box::new([tt::TokenTree::Leaf(tt::Leaf::Literal(tt::Literal {
text: "0u32".into(),
span,
- }))],
+ }))]),
})
}
@@ -208,11 +208,11 @@ fn assert_expand(
[cond, panic_args @ ..] => {
let comma = tt::Subtree {
delimiter: tt::Delimiter::invisible_spanned(call_site_span),
- token_trees: vec![tt::TokenTree::Leaf(tt::Leaf::Punct(tt::Punct {
+ token_trees: Box::new([tt::TokenTree::Leaf(tt::Leaf::Punct(tt::Punct {
char: ',',
spacing: tt::Spacing::Alone,
span: call_site_span,
- }))],
+ }))]),
};
let cond = cond.clone();
let panic_args = itertools::Itertools::intersperse(panic_args.iter().cloned(), comma);
@@ -359,7 +359,12 @@ fn panic_expand(
close: call_site_span,
kind: tt::DelimiterKind::Parenthesis,
};
- call.token_trees.push(tt::TokenTree::Subtree(subtree));
+
+ // FIXME(slow): quote! have a way to expand to builder to make this a vec!
+ let mut mutable_trees = std::mem::take(&mut call.token_trees).into_vec();
+ mutable_trees.push(tt::TokenTree::Subtree(subtree));
+ call.token_trees = mutable_trees.into_boxed_slice();
+
ExpandResult::ok(call)
}
@@ -388,7 +393,12 @@ fn unreachable_expand(
close: call_site_span,
kind: tt::DelimiterKind::Parenthesis,
};
- call.token_trees.push(tt::TokenTree::Subtree(subtree));
+
+ // FIXME(slow): quote! have a way to expand to builder to make this a vec!
+ let mut mutable_trees = std::mem::take(&mut call.token_trees).into_vec();
+ mutable_trees.push(tt::TokenTree::Subtree(subtree));
+ call.token_trees = mutable_trees.into_boxed_slice();
+
ExpandResult::ok(call)
}
@@ -675,10 +685,10 @@ fn include_bytes_expand(
// FIXME: actually read the file here if the user asked for macro expansion
let res = tt::Subtree {
delimiter: tt::Delimiter::invisible_spanned(span),
- token_trees: vec![tt::TokenTree::Leaf(tt::Leaf::Literal(tt::Literal {
+ token_trees: Box::new([tt::TokenTree::Leaf(tt::Leaf::Literal(tt::Literal {
text: r#"b"""#.into(),
span,
- }))],
+ }))]),
};
ExpandResult::ok(res)
}
diff --git a/crates/hir-expand/src/db.rs b/crates/hir-expand/src/db.rs
index f220284fae..d5a1a14099 100644
--- a/crates/hir-expand/src/db.rs
+++ b/crates/hir-expand/src/db.rs
@@ -524,7 +524,7 @@ fn macro_expand(
return ExpandResult {
value: CowArc::Owned(tt::Subtree {
delimiter: tt::Delimiter::invisible_spanned(loc.call_site),
- token_trees: Vec::new(),
+ token_trees: Box::new([]),
}),
// FIXME: We should make sure to enforce an invariant that invalid macro
// calls do not reach this call path!
@@ -586,7 +586,7 @@ fn macro_expand(
return value.map(|()| {
CowArc::Owned(tt::Subtree {
delimiter: tt::Delimiter::invisible_spanned(loc.call_site),
- token_trees: vec![],
+ token_trees: Box::new([]),
})
});
}
@@ -601,7 +601,7 @@ fn expand_proc_macro(db: &dyn ExpandDatabase, id: MacroCallId) -> ExpandResult ExpandResult bool {
a.delimiter.kind == b.delimiter.kind
&& a.token_trees.len() == b.token_trees.len()
- && a.token_trees.iter().zip(&b.token_trees).all(|(a, b)| check_tt_eq(a, b))
+ && a.token_trees.iter().zip(b.token_trees.iter()).all(|(a, b)| check_tt_eq(a, b))
}
fn check_tt_eq(a: &tt::TokenTree, b: &tt::TokenTree) -> bool {
diff --git a/crates/hir-expand/src/lib.rs b/crates/hir-expand/src/lib.rs
index bd25052490..2d29af287f 100644
--- a/crates/hir-expand/src/lib.rs
+++ b/crates/hir-expand/src/lib.rs
@@ -66,6 +66,7 @@ pub mod tt {
pub type Delimiter = ::tt::Delimiter;
pub type DelimSpan = ::tt::DelimSpan;
pub type Subtree = ::tt::Subtree;
+ pub type SubtreeBuilder = ::tt::SubtreeBuilder;
pub type Leaf = ::tt::Leaf;
pub type Literal = ::tt::Literal;
pub type Punct = ::tt::Punct;
@@ -760,7 +761,7 @@ impl ExpansionInfo {
(
Arc::new(tt::Subtree {
delimiter: tt::Delimiter::invisible_spanned(loc.call_site),
- token_trees: Vec::new(),
+ token_trees: Box::new([]),
}),
SyntaxFixupUndoInfo::NONE,
)
diff --git a/crates/hir-expand/src/quote.rs b/crates/hir-expand/src/quote.rs
index 824f3c3e8f..c1930c94f5 100644
--- a/crates/hir-expand/src/quote.rs
+++ b/crates/hir-expand/src/quote.rs
@@ -31,7 +31,7 @@ macro_rules! __quote {
open: $span,
close: $span,
},
- token_trees: $crate::quote::IntoTt::to_tokens(children),
+ token_trees: $crate::quote::IntoTt::to_tokens(children).into_boxed_slice(),
}
}
};
@@ -146,7 +146,7 @@ impl IntoTt for Vec {
fn to_subtree(self, span: Span) -> crate::tt::Subtree {
crate::tt::Subtree {
delimiter: crate::tt::Delimiter::invisible_spanned(span),
- token_trees: self,
+ token_trees: self.into_boxed_slice(),
}
}
@@ -296,8 +296,9 @@ mod tests {
// }
let struct_name = mk_ident("Foo");
let fields = [mk_ident("name"), mk_ident("id")];
- let fields =
- fields.iter().flat_map(|it| quote!(DUMMY =>#it: self.#it.clone(), ).token_trees);
+ let fields = fields
+ .iter()
+ .flat_map(|it| quote!(DUMMY =>#it: self.#it.clone(), ).token_trees.into_vec());
let list = crate::tt::Subtree {
delimiter: crate::tt::Delimiter {
diff --git a/crates/mbe/src/benchmark.rs b/crates/mbe/src/benchmark.rs
index 6c3917b37f..d946ecc1ca 100644
--- a/crates/mbe/src/benchmark.rs
+++ b/crates/mbe/src/benchmark.rs
@@ -100,17 +100,19 @@ fn invocation_fixtures(
// So we just skip any error cases and try again
let mut try_cnt = 0;
loop {
- let mut subtree = tt::Subtree {
+ let mut token_trees = Vec::new();
+ for op in rule.lhs.iter() {
+ collect_from_op(op, &mut token_trees, &mut seed);
+ }
+
+ let subtree = tt::Subtree {
delimiter: tt::Delimiter {
open: DUMMY,
close: DUMMY,
kind: tt::DelimiterKind::Invisible,
},
- token_trees: vec![],
+ token_trees: token_trees.into_boxed_slice(),
};
- for op in rule.lhs.iter() {
- collect_from_op(op, &mut subtree, &mut seed);
- }
if it.expand(&subtree, |_| (), true, DUMMY).err.is_none() {
res.push((name.clone(), subtree));
break;
@@ -127,45 +129,45 @@ fn invocation_fixtures(
fn collect_from_op(
op: &Op,
- parent: &mut tt::Subtree,
+ token_trees: &mut Vec>,
seed: &mut usize,
) {
return match op {
Op::Var { kind, .. } => match kind.as_ref() {
- Some(MetaVarKind::Ident) => parent.token_trees.push(make_ident("foo")),
- Some(MetaVarKind::Ty) => parent.token_trees.push(make_ident("Foo")),
- Some(MetaVarKind::Tt) => parent.token_trees.push(make_ident("foo")),
- Some(MetaVarKind::Vis) => parent.token_trees.push(make_ident("pub")),
- Some(MetaVarKind::Pat) => parent.token_trees.push(make_ident("foo")),
- Some(MetaVarKind::Path) => parent.token_trees.push(make_ident("foo")),
- Some(MetaVarKind::Literal) => parent.token_trees.push(make_literal("1")),
- Some(MetaVarKind::Expr) => parent.token_trees.push(make_ident("foo")),
+ Some(MetaVarKind::Ident) => token_trees.push(make_ident("foo")),
+ Some(MetaVarKind::Ty) => token_trees.push(make_ident("Foo")),
+ Some(MetaVarKind::Tt) => token_trees.push(make_ident("foo")),
+ Some(MetaVarKind::Vis) => token_trees.push(make_ident("pub")),
+ Some(MetaVarKind::Pat) => token_trees.push(make_ident("foo")),
+ Some(MetaVarKind::Path) => token_trees.push(make_ident("foo")),
+ Some(MetaVarKind::Literal) => token_trees.push(make_literal("1")),
+ Some(MetaVarKind::Expr) => token_trees.push(make_ident("foo")),
Some(MetaVarKind::Lifetime) => {
- parent.token_trees.push(make_punct('\''));
- parent.token_trees.push(make_ident("a"));
+ token_trees.push(make_punct('\''));
+ token_trees.push(make_ident("a"));
}
Some(MetaVarKind::Block) => {
- parent.token_trees.push(make_subtree(tt::DelimiterKind::Brace, None))
+ token_trees.push(make_subtree(tt::DelimiterKind::Brace, None))
}
Some(MetaVarKind::Item) => {
- parent.token_trees.push(make_ident("fn"));
- parent.token_trees.push(make_ident("foo"));
- parent.token_trees.push(make_subtree(tt::DelimiterKind::Parenthesis, None));
- parent.token_trees.push(make_subtree(tt::DelimiterKind::Brace, None));
+ token_trees.push(make_ident("fn"));
+ token_trees.push(make_ident("foo"));
+ token_trees.push(make_subtree(tt::DelimiterKind::Parenthesis, None));
+ token_trees.push(make_subtree(tt::DelimiterKind::Brace, None));
}
Some(MetaVarKind::Meta) => {
- parent.token_trees.push(make_ident("foo"));
- parent.token_trees.push(make_subtree(tt::DelimiterKind::Parenthesis, None));
+ token_trees.push(make_ident("foo"));
+ token_trees.push(make_subtree(tt::DelimiterKind::Parenthesis, None));
}
None => (),
Some(kind) => panic!("Unhandled kind {kind:?}"),
},
- Op::Literal(it) => parent.token_trees.push(tt::Leaf::from(it.clone()).into()),
- Op::Ident(it) => parent.token_trees.push(tt::Leaf::from(it.clone()).into()),
+ Op::Literal(it) => token_trees.push(tt::Leaf::from(it.clone()).into()),
+ Op::Ident(it) => token_trees.push(tt::Leaf::from(it.clone()).into()),
Op::Punct(puncts) => {
for punct in puncts {
- parent.token_trees.push(tt::Leaf::from(*punct).into());
+ token_trees.push(tt::Leaf::from(*punct).into());
}
}
Op::Repeat { tokens, kind, separator } => {
@@ -177,20 +179,20 @@ fn invocation_fixtures(
};
for i in 0..cnt {
for it in tokens.iter() {
- collect_from_op(it, parent, seed);
+ collect_from_op(it, token_trees, seed);
}
if i + 1 != cnt {
if let Some(sep) = separator {
match sep {
Separator::Literal(it) => {
- parent.token_trees.push(tt::Leaf::Literal(it.clone()).into())
+ token_trees.push(tt::Leaf::Literal(it.clone()).into())
}
Separator::Ident(it) => {
- parent.token_trees.push(tt::Leaf::Ident(it.clone()).into())
+ token_trees.push(tt::Leaf::Ident(it.clone()).into())
}
Separator::Puncts(puncts) => {
for it in puncts {
- parent.token_trees.push(tt::Leaf::Punct(*it).into())
+ token_trees.push(tt::Leaf::Punct(*it).into())
}
}
};
@@ -199,11 +201,15 @@ fn invocation_fixtures(
}
}
Op::Subtree { tokens, delimiter } => {
- let mut subtree = tt::Subtree { delimiter: *delimiter, token_trees: Vec::new() };
+ let mut subtree = Vec::new();
tokens.iter().for_each(|it| {
collect_from_op(it, &mut subtree, seed);
});
- parent.token_trees.push(subtree.into());
+
+ let subtree =
+ tt::Subtree { delimiter: *delimiter, token_trees: subtree.into_boxed_slice() };
+
+ token_trees.push(subtree.into());
}
Op::Ignore { .. } | Op::Index { .. } | Op::Count { .. } | Op::Length { .. } => {}
};
@@ -230,7 +236,7 @@ fn invocation_fixtures(
) -> tt::TokenTree {
tt::Subtree {
delimiter: tt::Delimiter { open: DUMMY, close: DUMMY, kind },
- token_trees: token_trees.unwrap_or_default(),
+ token_trees: token_trees.map(Vec::into_boxed_slice).unwrap_or_default(),
}
.into()
}
diff --git a/crates/mbe/src/expander.rs b/crates/mbe/src/expander.rs
index 60483809dc..9366048fd9 100644
--- a/crates/mbe/src/expander.rs
+++ b/crates/mbe/src/expander.rs
@@ -58,7 +58,7 @@ pub(crate) fn expand_rules(
ExpandResult::new(
tt::Subtree {
delimiter: tt::Delimiter::invisible_spanned(call_site),
- token_trees: vec![],
+ token_trees: Box::new([]),
},
ExpandError::NoMatchingRule,
)
diff --git a/crates/mbe/src/expander/matcher.rs b/crates/mbe/src/expander/matcher.rs
index 40b4c7cdd6..eea92cfba4 100644
--- a/crates/mbe/src/expander/matcher.rs
+++ b/crates/mbe/src/expander/matcher.rs
@@ -798,7 +798,7 @@ fn match_meta_var(
tt.map(|tt| match tt {
tt::TokenTree::Leaf(leaf) => tt::Subtree {
delimiter: tt::Delimiter::invisible_spanned(*leaf.span()),
- token_trees: vec![leaf.into()],
+ token_trees: Box::new([leaf.into()]),
},
tt::TokenTree::Subtree(mut s) => {
if s.delimiter.kind == tt::DelimiterKind::Invisible {
@@ -832,7 +832,7 @@ fn match_meta_var(
None => lit.into(),
Some(neg) => tt::TokenTree::Subtree(tt::Subtree {
delimiter: tt::Delimiter::invisible_spanned(*literal.span()),
- token_trees: vec![neg, lit.into()],
+ token_trees: Box::new([neg, lit.into()]),
}),
}
})
@@ -989,10 +989,10 @@ impl TtIter<'_, S> {
close: ident.span,
kind: tt::DelimiterKind::Invisible,
},
- token_trees: vec![
+ token_trees: Box::new([
tt::Leaf::Punct(*punct).into(),
tt::Leaf::Ident(ident.clone()).into(),
- ],
+ ]),
}
.into())
}
diff --git a/crates/mbe/src/expander/transcriber.rs b/crates/mbe/src/expander/transcriber.rs
index 800bc994ad..9291f799cc 100644
--- a/crates/mbe/src/expander/transcriber.rs
+++ b/crates/mbe/src/expander/transcriber.rs
@@ -83,7 +83,7 @@ impl Bindings {
close: span,
kind: tt::DelimiterKind::Brace,
},
- token_trees: vec![],
+ token_trees: Box::new([]),
})),
// FIXME: Meta and Item should get proper defaults
MetaVarKind::Meta | MetaVarKind::Item | MetaVarKind::Tt | MetaVarKind::Vis => {
@@ -349,11 +349,11 @@ fn expand_var(
// We just treat it a normal tokens
let tt = tt::Subtree {
delimiter: tt::Delimiter::invisible_spanned(id),
- token_trees: vec![
+ token_trees: Box::new([
tt::Leaf::from(tt::Punct { char: '$', spacing: tt::Spacing::Alone, span: id })
.into(),
tt::Leaf::from(tt::Ident { text: v.clone(), span: id }).into(),
- ],
+ ]),
}
.into();
ExpandResult::ok(Fragment::Tokens(tt))
@@ -406,7 +406,7 @@ fn expand_repeat(
value: Fragment::Tokens(
tt::Subtree {
delimiter: tt::Delimiter::invisible_spanned(ctx.call_site),
- token_trees: vec![],
+ token_trees: Box::new([]),
}
.into(),
),
@@ -455,7 +455,7 @@ fn expand_repeat(
// e.g {Delimiter:None> ['>'] /Delimiter:None>}
let tt = tt::Subtree {
delimiter: tt::Delimiter::invisible_spanned(ctx.call_site),
- token_trees: buf,
+ token_trees: buf.into_boxed_slice(),
}
.into();
@@ -486,7 +486,7 @@ fn push_fragment(
fn push_subtree(buf: &mut Vec>, tt: tt::Subtree) {
match tt.delimiter.kind {
- tt::DelimiterKind::Invisible => buf.extend(tt.token_trees),
+ tt::DelimiterKind::Invisible => buf.extend(Vec::from(tt.token_trees)),
_ => buf.push(tt.into()),
}
}
@@ -504,7 +504,7 @@ fn fix_up_and_push_path_tt(
// Note that we only need to fix up the top-level `TokenTree`s because the
// context of the paths in the descendant `Subtree`s won't be changed by the
// mbe transcription.
- for tt in subtree.token_trees {
+ for tt in Vec::from(subtree.token_trees) {
if prev_was_ident {
// Pedantically, `(T) -> U` in `FnOnce(T) -> U` is treated as a generic
// argument list and thus needs `::` between it and `FnOnce`. However in
diff --git a/crates/mbe/src/syntax_bridge.rs b/crates/mbe/src/syntax_bridge.rs
index d6c3bd1892..b1c83cf422 100644
--- a/crates/mbe/src/syntax_bridge.rs
+++ b/crates/mbe/src/syntax_bridge.rs
@@ -130,7 +130,7 @@ where
tt::Subtree {
delimiter: tt::Delimiter { kind: tt::DelimiterKind::Invisible, .. },
token_trees,
- } => TokenBuffer::from_tokens(token_trees.as_slice()),
+ } => TokenBuffer::from_tokens(token_trees),
_ => TokenBuffer::from_subtree(tt),
};
let parser_input = to_parser_input(&buffer);
@@ -227,14 +227,14 @@ where
C: TokenConverter,
S: Span,
{
- let entry = tt::Subtree {
+ let entry = tt::SubtreeBuilder {
delimiter: tt::Delimiter::invisible_spanned(conv.call_site()),
token_trees: vec![],
};
let mut stack = NonEmptyVec::new(entry);
while let Some((token, abs_range)) = conv.bump() {
- let tt::Subtree { delimiter, token_trees } = stack.last_mut();
+ let tt::SubtreeBuilder { delimiter, token_trees } = stack.last_mut();
let tt = match token.as_leaf() {
Some(leaf) => tt::TokenTree::Leaf(leaf.clone()),
@@ -260,7 +260,7 @@ where
if matches!(expected, Some(expected) if expected == kind) {
if let Some(mut subtree) = stack.pop() {
subtree.delimiter.close = conv.span_for(abs_range);
- stack.last_mut().token_trees.push(subtree.into());
+ stack.last_mut().token_trees.push(subtree.build().into());
}
continue;
}
@@ -275,7 +275,7 @@ where
// Start a new subtree
if let Some(kind) = delim {
let open = conv.span_for(abs_range);
- stack.push(tt::Subtree {
+ stack.push(tt::SubtreeBuilder {
delimiter: tt::Delimiter {
open,
// will be overwritten on subtree close above
@@ -361,7 +361,7 @@ where
parent.token_trees.extend(entry.token_trees);
}
- let subtree = stack.into_last();
+ let subtree = stack.into_last().build();
if let [tt::TokenTree::Subtree(first)] = &*subtree.token_trees {
first.clone()
} else {
@@ -454,7 +454,7 @@ fn convert_doc_comment(
};
// Make `doc="\" Comments\""
- let meta_tkns = vec![mk_ident("doc"), mk_punct('='), mk_doc_literal(&comment)];
+ let meta_tkns = Box::new([mk_ident("doc"), mk_punct('='), mk_doc_literal(&comment)]);
// Make `#![]`
let mut token_trees = Vec::with_capacity(3);
diff --git a/crates/mbe/src/tt_iter.rs b/crates/mbe/src/tt_iter.rs
index 71513ef439..f9913cb6f9 100644
--- a/crates/mbe/src/tt_iter.rs
+++ b/crates/mbe/src/tt_iter.rs
@@ -180,7 +180,7 @@ impl<'a, S: Span> TtIter<'a, S> {
[] | [_] => res.pop(),
[first, ..] => Some(tt::TokenTree::Subtree(tt::Subtree {
delimiter: tt::Delimiter::invisible_spanned(first.first_span()),
- token_trees: res,
+ token_trees: res.into_boxed_slice(),
})),
};
ExpandResult { value: res, err }
diff --git a/crates/proc-macro-api/src/msg.rs b/crates/proc-macro-api/src/msg.rs
index e28fe387b8..aa5aff455f 100644
--- a/crates/proc-macro-api/src/msg.rs
+++ b/crates/proc-macro-api/src/msg.rs
@@ -187,7 +187,67 @@ mod tests {
file_id: FileId::from_raw(0),
ast_id: ErasedFileAstId::from_raw(RawIdx::from(0)),
};
- let mut subtree = Subtree {
+
+ let token_trees = Box::new([
+ TokenTree::Leaf(
+ Ident {
+ text: "struct".into(),
+ span: Span {
+ range: TextRange::at(TextSize::new(0), TextSize::of("struct")),
+ anchor,
+ ctx: SyntaxContextId::ROOT,
+ },
+ }
+ .into(),
+ ),
+ TokenTree::Leaf(
+ Ident {
+ text: "Foo".into(),
+ span: Span {
+ range: TextRange::at(TextSize::new(5), TextSize::of("Foo")),
+ anchor,
+ ctx: SyntaxContextId::ROOT,
+ },
+ }
+ .into(),
+ ),
+ TokenTree::Leaf(Leaf::Literal(Literal {
+ text: "Foo".into(),
+
+ span: Span {
+ range: TextRange::at(TextSize::new(8), TextSize::of("Foo")),
+ anchor,
+ ctx: SyntaxContextId::ROOT,
+ },
+ })),
+ TokenTree::Leaf(Leaf::Punct(Punct {
+ char: '@',
+ span: Span {
+ range: TextRange::at(TextSize::new(11), TextSize::of('@')),
+ anchor,
+ ctx: SyntaxContextId::ROOT,
+ },
+ spacing: Spacing::Joint,
+ })),
+ TokenTree::Subtree(Subtree {
+ delimiter: Delimiter {
+ open: Span {
+ range: TextRange::at(TextSize::new(12), TextSize::of('{')),
+ anchor,
+ ctx: SyntaxContextId::ROOT,
+ },
+ close: Span {
+ range: TextRange::at(TextSize::new(13), TextSize::of('}')),
+ anchor,
+ ctx: SyntaxContextId::ROOT,
+ },
+ kind: DelimiterKind::Brace,
+ },
+ token_trees: Box::new([]),
+ }),
+ ]);
+
+ Subtree {
delimiter: Delimiter {
open: Span {
range: TextRange::empty(TextSize::new(0)),
@@ -201,65 +261,8 @@ mod tests {
},
kind: DelimiterKind::Invisible,
},
- token_trees: Vec::new(),
- };
- subtree.token_trees.push(TokenTree::Leaf(
- Ident {
- text: "struct".into(),
- span: Span {
- range: TextRange::at(TextSize::new(0), TextSize::of("struct")),
- anchor,
- ctx: SyntaxContextId::ROOT,
- },
- }
- .into(),
- ));
- subtree.token_trees.push(TokenTree::Leaf(
- Ident {
- text: "Foo".into(),
- span: Span {
- range: TextRange::at(TextSize::new(5), TextSize::of("Foo")),
- anchor,
- ctx: SyntaxContextId::ROOT,
- },
- }
- .into(),
- ));
- subtree.token_trees.push(TokenTree::Leaf(Leaf::Literal(Literal {
- text: "Foo".into(),
-
- span: Span {
- range: TextRange::at(TextSize::new(8), TextSize::of("Foo")),
- anchor,
- ctx: SyntaxContextId::ROOT,
- },
- })));
- subtree.token_trees.push(TokenTree::Leaf(Leaf::Punct(Punct {
- char: '@',
- span: Span {
- range: TextRange::at(TextSize::new(11), TextSize::of('@')),
- anchor,
- ctx: SyntaxContextId::ROOT,
- },
- spacing: Spacing::Joint,
- })));
- subtree.token_trees.push(TokenTree::Subtree(Subtree {
- delimiter: Delimiter {
- open: Span {
- range: TextRange::at(TextSize::new(12), TextSize::of('{')),
- anchor,
- ctx: SyntaxContextId::ROOT,
- },
- close: Span {
- range: TextRange::at(TextSize::new(13), TextSize::of('}')),
- anchor,
- ctx: SyntaxContextId::ROOT,
- },
- kind: DelimiterKind::Brace,
- },
- token_trees: vec![],
- }));
- subtree
+ token_trees,
+ }
}
#[test]
diff --git a/crates/proc-macro-api/src/msg/flat.rs b/crates/proc-macro-api/src/msg/flat.rs
index 8dfaba5262..f2b2114679 100644
--- a/crates/proc-macro-api/src/msg/flat.rs
+++ b/crates/proc-macro-api/src/msg/flat.rs
@@ -370,7 +370,7 @@ impl<'a, 'span, S: InternableSpan> Writer<'a, 'span, S> {
self.subtree[idx].tt = [first_tt as u32, (first_tt + n_tt) as u32];
- for child in &subtree.token_trees {
+ for child in subtree.token_trees.iter() {
let idx_tag = match child {
tt::TokenTree::Subtree(it) => {
let idx = self.enqueue(it);
diff --git a/crates/proc-macro-srv/src/server/rust_analyzer_span.rs b/crates/proc-macro-srv/src/server/rust_analyzer_span.rs
index b864a5e4fd..c7c7bea994 100644
--- a/crates/proc-macro-srv/src/server/rust_analyzer_span.rs
+++ b/crates/proc-macro-srv/src/server/rust_analyzer_span.rs
@@ -104,7 +104,7 @@ impl server::TokenStream for RaSpanServer {
delimiter: delim_to_internal(group.delimiter, group.span),
token_trees: match group.stream {
Some(stream) => stream.into_iter().collect(),
- None => Vec::new(),
+ None => Box::new([]),
},
};
let tree = tt::TokenTree::from(group);
@@ -221,7 +221,7 @@ impl server::TokenStream for RaSpanServer {
stream: if subtree.token_trees.is_empty() {
None
} else {
- Some(subtree.token_trees.into_iter().collect())
+ Some(subtree.token_trees.into_vec().into_iter().collect())
},
span: bridge::DelimSpan::from_single(subtree.delimiter.open),
}),
diff --git a/crates/proc-macro-srv/src/server/token_id.rs b/crates/proc-macro-srv/src/server/token_id.rs
index c83e09af0d..edbdc67b48 100644
--- a/crates/proc-macro-srv/src/server/token_id.rs
+++ b/crates/proc-macro-srv/src/server/token_id.rs
@@ -94,7 +94,7 @@ impl server::TokenStream for TokenIdServer {
delimiter: delim_to_internal(group.delimiter, group.span),
token_trees: match group.stream {
Some(stream) => stream.into_iter().collect(),
- None => Vec::new(),
+ None => Box::new([]),
},
};
let tree = TokenTree::from(group);
@@ -206,7 +206,7 @@ impl server::TokenStream for TokenIdServer {
stream: if subtree.token_trees.is_empty() {
None
} else {
- Some(TokenStream { token_trees: subtree.token_trees })
+ Some(TokenStream { token_trees: subtree.token_trees.into_vec() })
},
span: bridge::DelimSpan::from_single(subtree.delimiter.open),
}),
@@ -338,7 +338,7 @@ mod tests {
close: tt::TokenId(0),
kind: tt::DelimiterKind::Brace,
},
- token_trees: vec![],
+ token_trees: Box::new([]),
}),
],
};
@@ -354,10 +354,10 @@ mod tests {
close: tt::TokenId(0),
kind: tt::DelimiterKind::Parenthesis,
},
- token_trees: vec![tt::TokenTree::Leaf(tt::Leaf::Ident(tt::Ident {
+ token_trees: Box::new([tt::TokenTree::Leaf(tt::Leaf::Ident(tt::Ident {
text: "a".into(),
span: tt::TokenId(0),
- }))],
+ }))]),
});
let t1 = TokenStream::from_str("(a)", tt::TokenId(0)).unwrap();
diff --git a/crates/proc-macro-srv/src/server/token_stream.rs b/crates/proc-macro-srv/src/server/token_stream.rs
index 8f669a3049..5edaa720fc 100644
--- a/crates/proc-macro-srv/src/server/token_stream.rs
+++ b/crates/proc-macro-srv/src/server/token_stream.rs
@@ -15,14 +15,14 @@ impl Default for TokenStream {
impl TokenStream {
pub(crate) fn new() -> Self {
- TokenStream { token_trees: vec![] }
+ TokenStream::default()
}
pub(crate) fn with_subtree(subtree: tt::Subtree) -> Self {
if subtree.delimiter.kind != tt::DelimiterKind::Invisible {
TokenStream { token_trees: vec![TokenTree::Subtree(subtree)] }
} else {
- TokenStream { token_trees: subtree.token_trees }
+ TokenStream { token_trees: subtree.token_trees.into_vec() }
}
}
@@ -36,7 +36,7 @@ impl TokenStream {
close: call_site,
kind: tt::DelimiterKind::Invisible,
},
- token_trees: self.token_trees,
+ token_trees: self.token_trees.into_boxed_slice(),
}
}
@@ -83,7 +83,7 @@ impl Extend> for TokenStream {
tt::TokenTree::Subtree(subtree)
if subtree.delimiter.kind == tt::DelimiterKind::Invisible =>
{
- self.token_trees.extend(subtree.token_trees);
+ self.token_trees.extend(subtree.token_trees.into_vec().into_iter());
}
_ => {
self.token_trees.push(tkn);
diff --git a/crates/test-fixture/src/lib.rs b/crates/test-fixture/src/lib.rs
index b5ff7a1bf5..cb8c36b680 100644
--- a/crates/test-fixture/src/lib.rs
+++ b/crates/test-fixture/src/lib.rs
@@ -598,7 +598,7 @@ impl ProcMacroExpander for MirrorProcMacroExpander {
};
token_trees.push(tt);
}
- Subtree { delimiter: input.delimiter, token_trees }
+ Subtree { delimiter: input.delimiter, token_trees: token_trees.into_boxed_slice() }
}
Ok(traverse(input))
}
diff --git a/crates/tt/src/buffer.rs b/crates/tt/src/buffer.rs
index cade2e9f67..cd41af03c6 100644
--- a/crates/tt/src/buffer.rs
+++ b/crates/tt/src/buffer.rs
@@ -106,7 +106,7 @@ impl<'t, Span> TokenBuffer<'t, Span> {
for (child_idx, (subtree, tt)) in children {
let idx = TokenBuffer::new_inner(
- subtree.token_trees.as_slice(),
+ &*subtree.token_trees,
buffers,
Some(EntryPtr(EntryId(res), child_idx + 1)),
);
diff --git a/crates/tt/src/lib.rs b/crates/tt/src/lib.rs
index b3b0eeda75..462cae6de3 100644
--- a/crates/tt/src/lib.rs
+++ b/crates/tt/src/lib.rs
@@ -23,10 +23,10 @@ pub enum TokenTree {
}
impl_from!(Leaf, Subtree for TokenTree);
impl TokenTree {
- pub const fn empty(span: S) -> Self {
+ pub fn empty(span: S) -> Self {
Self::Subtree(Subtree {
delimiter: Delimiter::invisible_spanned(span),
- token_trees: vec![],
+ token_trees: Box::new([]),
})
}
@@ -34,7 +34,7 @@ impl TokenTree {
match self {
TokenTree::Leaf(_) => Subtree {
delimiter: Delimiter::invisible_delim_spanned(span),
- token_trees: vec![self],
+ token_trees: Box::new([self]),
},
TokenTree::Subtree(s) => s,
}
@@ -69,12 +69,12 @@ impl_from!(Literal, Punct, Ident for Leaf);
#[derive(Clone, PartialEq, Eq, Hash)]
pub struct Subtree {
pub delimiter: Delimiter,
- pub token_trees: Vec>,
+ pub token_trees: Box<[TokenTree]>,
}
impl Subtree {
- pub const fn empty(span: DelimSpan) -> Self {
- Subtree { delimiter: Delimiter::invisible_delim_spanned(span), token_trees: vec![] }
+ pub fn empty(span: DelimSpan) -> Self {
+ Subtree { delimiter: Delimiter::invisible_delim_spanned(span), token_trees: Box::new([]) }
}
pub fn visit_ids(&mut self, f: &mut impl FnMut(S) -> S) {
@@ -91,6 +91,18 @@ impl Subtree {
}
}
+#[derive(Clone, PartialEq, Eq, Hash)]
+pub struct SubtreeBuilder {
+ pub delimiter: Delimiter,
+ pub token_trees: Vec>,
+}
+
+impl SubtreeBuilder {
+ pub fn build(self) -> Subtree {
+ Subtree { delimiter: self.delimiter, token_trees: self.token_trees.into_boxed_slice() }
+ }
+}
+
#[derive(Debug, Copy, Clone, PartialEq)]
pub struct DelimSpan {
pub open: S,
@@ -241,7 +253,7 @@ impl fmt::Display for Subtree {
};
f.write_str(l)?;
let mut needs_space = false;
- for tt in &self.token_trees {
+ for tt in self.token_trees.iter() {
if needs_space {
f.write_str(" ")?;
}
@@ -316,7 +328,7 @@ impl Subtree {
let mut res = String::new();
res.push_str(delim.0);
let mut last = None;
- for child in &self.token_trees {
+ for child in self.token_trees.iter() {
let s = match child {
TokenTree::Leaf(it) => {
let s = match it {