Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
41 commits
Select commit Hold shift + click to select a range
62709aa
Lex tokens into a flat arena
Kobzol Aug 25, 2026
ff95782
Pass `TokenArena` to `Parser`
Kobzol Aug 25, 2026
2878ca1
Explicitly store delimited sequence end markers in the token arena
Kobzol Aug 26, 2026
c4dda06
Reimplement the parser's token cursor to work on top of the arena
Kobzol Aug 26, 2026
9f6ce4a
Push arena token trees further down the stack
Kobzol Aug 26, 2026
e1f053c
Pass `&mut TokenArena` to `lex_token_trees`
Kobzol Aug 26, 2026
7649daa
Migrate `fake_token_stream_for_file_mod` to `TokenArena`
Kobzol Aug 26, 2026
60e1ddb
Ensure that we only push tokens directly to the arena
Kobzol Sep 11, 2026
d4fcad2
Represent closing delimiters implicitly
Kobzol Sep 11, 2026
a03e8cc
Split mutable and immutable part of the arena token stream
Kobzol Sep 11, 2026
21ade1f
Store the parent of each delimited sequence explicitly
Kobzol Sep 11, 2026
d8034bf
Reduce size of `TokenCursor`
Kobzol Sep 11, 2026
c12cb9e
Store `ArenaTokenStream` in `DelimArgs`
Kobzol Sep 11, 2026
0b04f38
Add `ArenaTokenTreeIter` and use it in `MetaItemKind::list_from_tokens`
Kobzol Sep 11, 2026
75034d4
Make `DelimitedBounds` fields private
Kobzol Sep 12, 2026
c8a0973
Return `ArenaTokenStream` from `inner_tokens`
Kobzol Sep 12, 2026
e288eba
Use `ArenaTokenStream` in builtin lints
Kobzol Sep 12, 2026
6d0bf78
Use `ArenaTokenStream` in pretty printing
Kobzol Sep 12, 2026
58a995f
Use `ArenaTokenStream` in `MetaItemListParser`
Kobzol Sep 12, 2026
8d7700f
Use `ArenaTokenStream` in `new_parser_from_tts`
Kobzol Sep 12, 2026
5c01c9a
Use `ArenaTokenStream` in some parts of macro expansion
Kobzol Sep 12, 2026
925bdd2
Use `ArenaTokenStream` in more parts of macro expansion
Kobzol Sep 12, 2026
09893a1
Use `ArenaTokenStream` in derive proc macro expansion
Kobzol Sep 12, 2026
68299cc
Use `ArenaTokenStream` in `edition_2024_expr_fragment_specifier`
Kobzol Sep 12, 2026
bf2c305
Use `ArenaTokenStream` in builtin macros
Kobzol Sep 12, 2026
8e762e0
Remove `ArenaTokenStream::from_token`
Kobzol Sep 13, 2026
f0b6234
Use `ArenaTokenStream` in the proc macro server
Kobzol Sep 13, 2026
6aa7a7f
Remove the penultimate instance of `ArenaTokenStream::from_stream`
Kobzol Sep 13, 2026
eef0d2f
Remove the penultimate instance of `ArenaTokenStreamBuilder::push_tok…
Kobzol Sep 13, 2026
b7d7178
Use `ArenaTokenStreamBuilder` in macro transcription
Kobzol Sep 13, 2026
9e563a7
Harden delimited groups
Kobzol Sep 13, 2026
773d85a
Remove last usage of `push_token_tree` in macro transcription
Kobzol Sep 13, 2026
8f33269
Add `ArenaTokenStreamBuilder::push_delimited`
Kobzol Sep 13, 2026
5618c17
Fix `ArenaTokenStreamIter::peek` and remove last usage of `to_token_t…
Kobzol Sep 13, 2026
887833b
Add empty arena token stream optimization
Kobzol Sep 14, 2026
0af9c37
Implement traits for `ArenaTokenStream` manually
Kobzol Sep 14, 2026
fd5a573
Allow structurally sharing the same token tree Vec amongst multiple v…
Kobzol Sep 14, 2026
2307ca2
Slightly optimize `into_builder`
Kobzol Sep 14, 2026
ebd8ba4
Optimize remembering of glueing metadata
Kobzol Sep 14, 2026
e0cd02d
Add inline to some tiny methods
Kobzol Sep 14, 2026
85952f3
Do not store `ArenaTokenStream` in `ParseNtResult`
Kobzol Sep 14, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 7 additions & 6 deletions compiler/rustc_ast/src/ast.rs
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ use thin_vec::{ThinVec, thin_vec};
use crate::attr::data_structures::CfgEntry;
pub use crate::format::*;
use crate::token::{self, CommentKind, Delimiter};
use crate::tokenstream::{DelimSpan, LazyAttrTokenStream, TokenStream};
use crate::tokenstream::{DelimSpan, LazyAttrTokenStream};
use crate::util::parser::{ExprPrecedence, Fixity};
use crate::visit::{AssocCtxt, BoundKind, LifetimeCtxt};

Expand Down Expand Up @@ -378,6 +378,7 @@ impl ParenthesizedArgs {
}

pub use crate::node_id::{CRATE_NODE_ID, DUMMY_NODE_ID, NodeId};
use crate::tokenarena::ArenaTokenStream;

/// Modifiers on a trait bound like `[const]`, `?` and `!`.
#[derive(Copy, Clone, PartialEq, Eq, Encodable, Decodable, Debug, Walkable)]
Expand Down Expand Up @@ -2090,11 +2091,11 @@ impl AttrArgs {

/// Tokens inside the delimiters or after `=`.
/// Proc macros see these tokens, for example.
pub fn inner_tokens(&self) -> TokenStream {
pub fn inner_tokens(&self) -> ArenaTokenStream {
match self {
AttrArgs::Empty => TokenStream::default(),
AttrArgs::Empty => ArenaTokenStream::default(),
AttrArgs::Delimited(args) => args.tokens.clone(),
AttrArgs::Eq { expr, .. } => TokenStream::from_ast(expr),
AttrArgs::Eq { expr, .. } => ArenaTokenStream::from_ast(expr),
}
}
}
Expand All @@ -2104,7 +2105,7 @@ impl AttrArgs {
pub struct DelimArgs {
pub dspan: DelimSpan,
pub delim: Delimiter, // Note: `Delimiter::Invisible` never occurs
pub tokens: TokenStream,
pub tokens: ArenaTokenStream,
}

impl DelimArgs {
Expand Down Expand Up @@ -4494,7 +4495,7 @@ mod size_asserts {
static_assert_size!(MetaItem, 80);
static_assert_size!(MetaItemKind, 40);
static_assert_size!(MetaItemLit, 40);
static_assert_size!(NormalAttr, 80);
static_assert_size!(NormalAttr, 96);
static_assert_size!(Param, 40);
static_assert_size!(Pat, 64);
static_assert_size!(PatKind, 48);
Expand Down
117 changes: 79 additions & 38 deletions compiler/rustc_ast/src/attr/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,9 +19,12 @@ use crate::ast::{
use crate::token::{
self, CommentKind, Delimiter, DocFragmentKind, InvisibleOrigin, MetaVarKind, Token,
};
use crate::tokenarena::{
ArenaTokenStream, ArenaTokenStreamBuilder, ArenaTokenTree, ArenaTokenTreeIter, DelimitedData,
};
use crate::tokenstream::{
AttrTokenStream, AttrTokenTree, DelimSpacing, DelimSpan, LazyAttrTokenStream, Spacing,
TokenStream, TokenStreamIter, TokenTree,
TokenTree,
};
use crate::util::comments;
use crate::util::literal::escape_string_symbol;
Expand Down Expand Up @@ -308,6 +311,25 @@ impl Attribute {
}
}

pub fn push_token_trees(&self, builder: &mut ArenaTokenStreamBuilder) {
match self.kind {
AttrKind::Normal(ref normal) => {
normal
.tokens
.as_ref()
.unwrap_or_else(|| panic!("attribute is missing tokens: {self:?}"))
.to_attr_token_stream()
.push_token_trees(builder);
}
// Empty tokens here ensures synthetic attributes are invisible to proc macros.
AttrKind::Synthetic(..) => {}
AttrKind::DocComment(comment_kind, data) => builder.push_token_alone(Token::new(
token::DocComment(comment_kind, self.style, data),
self.span,
)),
}
}

pub fn deprecation_note(&self) -> Option<Ident> {
match &self.kind {
AttrKind::Normal(normal) if normal.item.path == sym::deprecated => {
Expand Down Expand Up @@ -345,7 +367,7 @@ impl AttrItem {
pub fn meta_item_list(&self) -> Option<ThinVec<MetaItemInner>> {
match &self.args {
AttrArgs::Delimited(args) if args.delim == Delimiter::Parenthesis => {
MetaItemKind::list_from_tokens(args.tokens.clone())
MetaItemKind::list_from_tokens(&args.tokens)
}
AttrArgs::Delimited(_) | AttrArgs::Eq { .. } | AttrArgs::Empty => None,
}
Expand Down Expand Up @@ -475,16 +497,16 @@ impl MetaItem {
}
}

fn from_tokens(iter: &mut TokenStreamIter<'_>) -> Option<MetaItem> {
fn from_tokens(iter: &mut ArenaTokenTreeIter<'_>) -> Option<MetaItem> {
// FIXME: Share code with `parse_path`.
let tt = iter.next().map(|tt| TokenTree::uninterpolate(tt));
let tt = iter.next().map(|tt| ArenaTokenTree::uninterpolate(tt));
let path = match tt.as_deref() {
Some(&TokenTree::Token(
Some(&ArenaTokenTree::Token(
Token { kind: ref kind @ (token::Ident(..) | token::PathSep), span },
_,
)) => 'arm: {
let mut segments = if let &token::Ident(name, _) = kind {
if let Some(TokenTree::Token(Token { kind: token::PathSep, .. }, _)) =
if let Some(ArenaTokenTree::Token(Token { kind: token::PathSep, .. }, _)) =
iter.peek()
{
iter.next();
Expand All @@ -496,13 +518,16 @@ impl MetaItem {
thin_vec![PathSegment::path_root(span)]
};
loop {
let Some(&TokenTree::Token(Token { kind: token::Ident(name, _), span }, _)) =
iter.next().map(|tt| TokenTree::uninterpolate(tt)).as_deref()
let Some(&ArenaTokenTree::Token(
Token { kind: token::Ident(name, _), span },
_,
)) = iter.next().map(|tt| ArenaTokenTree::uninterpolate(tt)).as_deref()
else {
return None;
};
segments.push(PathSegment::from_ident(Ident::new(name, span)));
let Some(TokenTree::Token(Token { kind: token::PathSep, .. }, _)) = iter.peek()
let Some(ArenaTokenTree::Token(Token { kind: token::PathSep, .. }, _)) =
iter.peek()
else {
break;
};
Expand All @@ -511,18 +536,21 @@ impl MetaItem {
let span = span.with_hi(segments.last().unwrap().ident.span.hi());
Path { span, segments }
}
Some(TokenTree::Delimited(
_span,
_spacing,
Delimiter::Invisible(InvisibleOrigin::MetaVar(
MetaVarKind::Meta { .. } | MetaVarKind::Path,
)),
_stream,
Some(ArenaTokenTree::DelimitedStart(
_,
DelimitedData {
delimiter:
Delimiter::Invisible(InvisibleOrigin::MetaVar(
MetaVarKind::Meta { .. } | MetaVarKind::Path,
)),
span: _,
spacing: _,
},
)) => {
// This path is currently unreachable in the test suite.
unreachable!()
}
Some(TokenTree::Token(Token { kind, .. }, _)) if kind.is_delim() => {
Some(ArenaTokenTree::Token(Token { kind, .. }, _)) if kind.is_delim() => {
panic!("Should be `AttrTokenTree::Delimited`, not delim tokens: {:?}", tt);
}
_ => return None,
Expand All @@ -544,41 +572,50 @@ impl MetaItem {

impl MetaItemKind {
// public because it can be called in the hir
pub fn list_from_tokens(tokens: TokenStream) -> Option<ThinVec<MetaItemInner>> {
let mut iter = tokens.iter();
pub fn list_from_tokens(tokens: &ArenaTokenStream) -> Option<ThinVec<MetaItemInner>> {
let mut iter = tokens.iter_top_level_trees();
let mut result = ThinVec::new();
while iter.peek().is_some() {
let item = MetaItemInner::from_tokens(&mut iter)?;
result.push(item);
match iter.next() {
None | Some(TokenTree::Token(Token { kind: token::Comma, .. }, _)) => {}
None | Some(ArenaTokenTree::Token(Token { kind: token::Comma, .. }, _)) => {}
_ => return None,
}
}
Some(result)
}

fn name_value_from_tokens(iter: &mut TokenStreamIter<'_>) -> Option<MetaItemKind> {
fn name_value_from_tokens(iter: &mut ArenaTokenTreeIter<'_>) -> Option<MetaItemKind> {
match iter.next() {
Some(TokenTree::Delimited(.., Delimiter::Invisible(_), inner_tokens)) => {
MetaItemKind::name_value_from_tokens(&mut inner_tokens.iter())
}
Some(TokenTree::Token(token, _)) => {
Some(ArenaTokenTree::DelimitedStart(
bounds,
DelimitedData { delimiter: Delimiter::Invisible(_), .. },
)) => MetaItemKind::name_value_from_tokens(
&mut iter.stream().iter_delimited_contents(bounds),
),
Some(ArenaTokenTree::Token(token, _)) => {
MetaItemLit::from_token(token).map(MetaItemKind::NameValue)
}
_ => None,
}
}

fn from_tokens(iter: &mut TokenStreamIter<'_>) -> Option<MetaItemKind> {
fn from_tokens(iter: &mut ArenaTokenTreeIter<'_>) -> Option<MetaItemKind> {
match iter.peek() {
Some(TokenTree::Delimited(.., Delimiter::Parenthesis, inner_tokens)) => {
let inner_tokens = inner_tokens.clone();
Some(ArenaTokenTree::DelimitedStart(
bounds,
DelimitedData { delimiter: Delimiter::Parenthesis, .. },
)) => {
iter.next();
MetaItemKind::list_from_tokens(inner_tokens).map(MetaItemKind::List)
MetaItemKind::list_from_tokens(&ArenaTokenStream::separate_delimited_inner(
*bounds,
iter.stream(),
))
.map(MetaItemKind::List)
}
Some(TokenTree::Delimited(..)) => None,
Some(TokenTree::Token(Token { kind: token::Eq, .. }, _)) => {
Some(ArenaTokenTree::DelimitedStart(..)) => None,
Some(ArenaTokenTree::Token(Token { kind: token::Eq, .. }, _)) => {
iter.next();
MetaItemKind::name_value_from_tokens(iter)
}
Expand All @@ -590,7 +627,7 @@ impl MetaItemKind {
match args {
AttrArgs::Empty => Some(MetaItemKind::Word),
AttrArgs::Delimited(DelimArgs { dspan: _, delim: Delimiter::Parenthesis, tokens }) => {
MetaItemKind::list_from_tokens(tokens.clone()).map(MetaItemKind::List)
MetaItemKind::list_from_tokens(tokens).map(MetaItemKind::List)
}
AttrArgs::Delimited(..) => None,
AttrArgs::Eq { expr, .. } => match expr.kind {
Expand Down Expand Up @@ -705,15 +742,19 @@ impl MetaItemInner {
self.meta_item().is_some()
}

fn from_tokens(iter: &mut TokenStreamIter<'_>) -> Option<MetaItemInner> {
fn from_tokens(iter: &mut ArenaTokenTreeIter<'_>) -> Option<MetaItemInner> {
match iter.peek() {
Some(TokenTree::Token(token, _)) if let Some(lit) = MetaItemLit::from_token(token) => {
Some(ArenaTokenTree::Token(token, _))
if let Some(lit) = MetaItemLit::from_token(token) =>
{
iter.next();
return Some(MetaItemInner::Lit(lit));
}
Some(TokenTree::Delimited(.., Delimiter::Invisible(_), inner_tokens)) => {
Some(ArenaTokenTree::DelimitedStart(bounds, _)) => {
iter.next();
return MetaItemInner::from_tokens(&mut inner_tokens.iter());
return MetaItemInner::from_tokens(
&mut iter.stream().iter_delimited_contents(bounds),
);
}
_ => {}
}
Expand Down Expand Up @@ -803,10 +844,10 @@ pub fn mk_attr_nested_word(
inner: Symbol,
span: Span,
) -> Attribute {
let inner_tokens = TokenStream::new(vec![TokenTree::Token(
let inner_tokens = ArenaTokenStream::from_token_iter(std::iter::once((
Token::from_ast_ident(Ident::new(inner, span)),
Spacing::Alone,
)]);
)));
let outer_ident = Ident::new(outer, span);
let path = Path::from_ident(outer_ident);
let attr_args = AttrArgs::Delimited(DelimArgs {
Expand Down
1 change: 1 addition & 0 deletions compiler/rustc_ast/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ pub mod format;
pub mod mut_visit;
pub mod node_id;
pub mod token;
pub mod tokenarena;
pub mod tokenstream;
pub mod visit;

Expand Down
Loading
Loading