Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
46 commits
Select commit Hold shift + click to select a range
036bfcb
Lex tokens into a flat arena
Kobzol Aug 25, 2026
819bfa1
Pass `TokenArena` to `Parser`
Kobzol Aug 25, 2026
8537106
Explicitly store delimited sequence end markers in the token arena
Kobzol Aug 26, 2026
4d427da
Reimplement the parser's token cursor to work on top of the arena
Kobzol Aug 26, 2026
92648ec
Push arena token trees further down the stack
Kobzol Aug 26, 2026
dcfed69
Pass `&mut TokenArena` to `lex_token_trees`
Kobzol Aug 26, 2026
2ab9d66
Migrate `fake_token_stream_for_file_mod` to `TokenArena`
Kobzol Aug 26, 2026
604884d
Ensure that we only push tokens directly to the arena
Kobzol Sep 11, 2026
4bba119
Represent closing delimiters implicitly
Kobzol Sep 11, 2026
eac0613
Split mutable and immutable part of the arena token stream
Kobzol Sep 11, 2026
9e7edde
Store the parent of each delimited sequence explicitly
Kobzol Sep 11, 2026
110481e
Reduce size of `TokenCursor`
Kobzol Sep 11, 2026
3547295
Store `ArenaTokenStream` in `DelimArgs`
Kobzol Sep 11, 2026
8f7ca93
Add `ArenaTokenTreeIter` and use it in `MetaItemKind::list_from_tokens`
Kobzol Sep 11, 2026
b96e4a1
Make `DelimitedBounds` fields private
Kobzol Sep 12, 2026
30a2745
Return `ArenaTokenStream` from `inner_tokens`
Kobzol Sep 12, 2026
b8f4f37
Use `ArenaTokenStream` in builtin lints
Kobzol Sep 12, 2026
6c7ad7f
Use `ArenaTokenStream` in pretty printing
Kobzol Sep 12, 2026
acfdb0d
Use `ArenaTokenStream` in `MetaItemListParser`
Kobzol Sep 12, 2026
edcf17f
Use `ArenaTokenStream` in `new_parser_from_tts`
Kobzol Sep 12, 2026
60d541d
Use `ArenaTokenStream` in some parts of macro expansion
Kobzol Sep 12, 2026
e4c6c04
Use `ArenaTokenStream` in more parts of macro expansion
Kobzol Sep 12, 2026
c521c28
Use `ArenaTokenStream` in derive proc macro expansion
Kobzol Sep 12, 2026
09766f4
Use `ArenaTokenStream` in `edition_2024_expr_fragment_specifier`
Kobzol Sep 12, 2026
a6e6547
Use `ArenaTokenStream` in builtin macros
Kobzol Sep 12, 2026
264b81d
Remove `ArenaTokenStream::from_token`
Kobzol Sep 13, 2026
690ac67
Use `ArenaTokenStream` in the proc macro server
Kobzol Sep 13, 2026
5e87c61
Remove the penultimate instance of `ArenaTokenStream::from_stream`
Kobzol Sep 13, 2026
38138db
Remove the penultimate instance of `ArenaTokenStreamBuilder::push_tok…
Kobzol Sep 13, 2026
df87740
Use `ArenaTokenStreamBuilder` in macro transcription
Kobzol Sep 13, 2026
1147572
Harden delimited groups
Kobzol Sep 13, 2026
cad6e84
Remove last usage of `push_token_tree` in macro transcription
Kobzol Sep 13, 2026
4e4608c
Add `ArenaTokenStreamBuilder::push_delimited`
Kobzol Sep 13, 2026
cb7443f
Fix `ArenaTokenStreamIter::peek` and remove last usage of `to_token_t…
Kobzol Sep 13, 2026
7fbe0d1
Add empty arena token stream optimization
Kobzol Sep 14, 2026
211ae6b
Implement traits for `ArenaTokenStream` manually
Kobzol Sep 14, 2026
729b0cb
Allow structurally sharing the same token tree Vec amongst multiple v…
Kobzol Sep 14, 2026
b3c1cfb
Slightly optimize `into_builder`
Kobzol Sep 14, 2026
29be36a
Optimize remembering of glueing metadata
Kobzol Sep 14, 2026
a23bbfa
Add inline to some tiny methods
Kobzol Sep 14, 2026
44f8dd9
Do not store `ArenaTokenStream` in `ParseNtResult`
Kobzol Sep 14, 2026
621dba7
Implement `new` for `ArenaTokenStreamBuilder`
Kobzol Sep 14, 2026
a4b9bb4
Use constructors for `AbsoluteTokenTreeIndex`
Kobzol Sep 14, 2026
1598053
Rebase fallout
Kobzol Oct 7, 2026
877c0b5
Avoid double capacity reserve of tokens
Kobzol Oct 7, 2026
e5e46c5
Optimize `fill_stream`
Kobzol Oct 7, 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 @@ -4485,7 +4486,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