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 {