Skip to content

Commit 994b55e

Browse files
committed
Speed up Parser::expected_token_types.
The parser pushes a `TokenType` to `Parser::expected_token_types` on every call to the various `check`/`eat` methods, and clears it on every call to `bump`. Some of those `TokenType` values are full tokens that require cloning and dropping. This is a *lot* of work for something that is only used in error messages and it accounts for a significant fraction of parsing execution time. This commit overhauls `TokenType` so that `Parser::expected_token_types` can be implemented as a bitset. This requires changing `TokenType` to a C-style parameterless enum, and adding `TokenTypeSet` which uses a `u128` for the bits. (The new `TokenType` has 105 variants.) The new types `ExpTokenPair` and `ExpKeywordPair` are now arguments to the `check`/`eat` methods. This is for maximum speed. The elements in the pairs are always statically known; e.g. a `token::BinOp(token::Star)` is always paired with a `TokenType::Star`. So we now compute `TokenType`s in advance and pass them in to `check`/`eat` rather than the current approach of constructing them on insertion into `expected_token_types`. Values of these pair types can be produced by the new `exp!` macro, which is used at every `check`/`eat` call site. The macro is for convenience, allowing any pair to be generated from a single identifier. The ident/keyword filtering in `expected_one_of_not_found` is no longer necessary. It was there to account for some sloppiness in `TokenKind`/`TokenType` comparisons. The existing `TokenType` is moved to a new file `token_type.rs`, and all its new infrastructure is added to that file. There is more boilerplate code than I would like, but I can't see how to make it shorter.
1 parent aeca2c2 commit 994b55e

File tree

3 files changed

+17
-16
lines changed

3 files changed

+17
-16
lines changed

src/parse/macros/cfg_if.rs

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ use std::panic::{AssertUnwindSafe, catch_unwind};
22

33
use rustc_ast::ast;
44
use rustc_ast::token::{Delimiter, TokenKind};
5+
use rustc_parse::exp;
56
use rustc_parse::parser::ForceCollect;
67
use rustc_span::symbol::kw;
78

@@ -31,7 +32,7 @@ fn parse_cfg_if_inner<'a>(
3132

3233
while parser.token.kind != TokenKind::Eof {
3334
if process_if_cfg {
34-
if !parser.eat_keyword(kw::If) {
35+
if !parser.eat_keyword(exp!(If)) {
3536
return Err("Expected `if`");
3637
}
3738

@@ -55,7 +56,7 @@ fn parse_cfg_if_inner<'a>(
5556
})?;
5657
}
5758

58-
if !parser.eat(&TokenKind::OpenDelim(Delimiter::Brace)) {
59+
if !parser.eat(exp!(OpenBrace)) {
5960
return Err("Expected an opening brace");
6061
}
6162

@@ -78,15 +79,15 @@ fn parse_cfg_if_inner<'a>(
7879
}
7980
}
8081

81-
if !parser.eat(&TokenKind::CloseDelim(Delimiter::Brace)) {
82+
if !parser.eat(exp!(CloseBrace)) {
8283
return Err("Expected a closing brace");
8384
}
8485

85-
if parser.eat(&TokenKind::Eof) {
86+
if parser.eat(exp!(Eof)) {
8687
break;
8788
}
8889

89-
if !parser.eat_keyword(kw::Else) {
90+
if !parser.eat_keyword(exp!(Else)) {
9091
return Err("Expected `else`");
9192
}
9293

src/parse/macros/lazy_static.rs

Lines changed: 9 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,9 @@
11
use rustc_ast::ast;
22
use rustc_ast::ptr::P;
3-
use rustc_ast::token::TokenKind;
3+
use rustc_ast::token;
44
use rustc_ast::tokenstream::TokenStream;
5-
use rustc_span::symbol::{self, kw};
5+
use rustc_parse::exp;
6+
use rustc_span::symbol;
67

78
use crate::rewrite::RewriteContext;
89

@@ -31,19 +32,19 @@ pub(crate) fn parse_lazy_static(
3132
}
3233
}
3334
}
34-
while parser.token.kind != TokenKind::Eof {
35+
while parser.token.kind != token::Eof {
3536
// Parse a `lazy_static!` item.
3637
// FIXME: These `eat_*` calls should be converted to `parse_or` to avoid
3738
// silently formatting malformed lazy-statics.
3839
let vis = parse_or!(parse_visibility, rustc_parse::parser::FollowedByType::No);
39-
let _ = parser.eat_keyword(kw::Static);
40-
let _ = parser.eat_keyword(kw::Ref);
40+
let _ = parser.eat_keyword(exp!(Static));
41+
let _ = parser.eat_keyword(exp!(Ref));
4142
let id = parse_or!(parse_ident);
42-
let _ = parser.eat(&TokenKind::Colon);
43+
let _ = parser.eat(exp!(Colon));
4344
let ty = parse_or!(parse_ty);
44-
let _ = parser.eat(&TokenKind::Eq);
45+
let _ = parser.eat(exp!(Eq));
4546
let expr = parse_or!(parse_expr);
46-
let _ = parser.eat(&TokenKind::Semi);
47+
let _ = parser.eat(exp!(Semi));
4748
result.push((vis, id, ty, expr));
4849
}
4950

src/parse/parser.rs

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,10 @@
11
use std::panic::{AssertUnwindSafe, catch_unwind};
22
use std::path::{Path, PathBuf};
33

4-
use rustc_ast::token::TokenKind;
54
use rustc_ast::{ast, attr, ptr};
65
use rustc_errors::Diag;
76
use rustc_parse::parser::Parser as RawParser;
8-
use rustc_parse::{new_parser_from_file, new_parser_from_source_str, unwrap_or_emit_fatal};
7+
use rustc_parse::{exp, new_parser_from_file, new_parser_from_source_str, unwrap_or_emit_fatal};
98
use rustc_span::{Span, sym};
109
use thin_vec::ThinVec;
1110

@@ -107,7 +106,7 @@ impl<'a> Parser<'a> {
107106
let result = catch_unwind(AssertUnwindSafe(|| {
108107
let mut parser =
109108
unwrap_or_emit_fatal(new_parser_from_file(psess.inner(), path, Some(span)));
110-
match parser.parse_mod(&TokenKind::Eof) {
109+
match parser.parse_mod(exp!(Eof)) {
111110
Ok((a, i, spans)) => Some((a, i, spans.inner_span)),
112111
Err(e) => {
113112
e.emit();

0 commit comments

Comments
 (0)