Skip to content

Commit d2281f0

Browse files
committed
Auto merge of rust-lang#13678 - Veykril:hir-file-encode, r=Veykril
Encode the variants of `HirFileId` in a u32 with MSB as the tag This saves 10mb on `self` analysis, while this does limit us to 2billion real files and 2 billion macro expansions, I doubt we will ever hit that limit :) `HirFileId` is used a lot, so going from 8 bytes to 4 is a decent win.
2 parents b651646 + 7bf2a25 commit d2281f0

File tree

4 files changed

+145
-226
lines changed

4 files changed

+145
-226
lines changed

crates/hir-expand/src/db.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -240,7 +240,7 @@ fn ast_id_map(db: &dyn AstDatabase, file_id: HirFileId) -> Arc<AstIdMap> {
240240
}
241241

242242
fn parse_or_expand(db: &dyn AstDatabase, file_id: HirFileId) -> Option<SyntaxNode> {
243-
match file_id.0 {
243+
match file_id.repr() {
244244
HirFileIdRepr::FileId(file_id) => Some(db.parse(file_id).tree().syntax().clone()),
245245
HirFileIdRepr::MacroFile(macro_file) => {
246246
// FIXME: Note how we convert from `Parse` to `SyntaxNode` here,

crates/hir-expand/src/hygiene.rs

+4-4
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ use crate::{
1717
db::{self, AstDatabase},
1818
fixup,
1919
name::{AsName, Name},
20-
HirFileId, HirFileIdRepr, InFile, MacroCallKind, MacroCallLoc, MacroDefKind, MacroFile,
20+
HirFileId, InFile, MacroCallKind, MacroCallLoc, MacroDefKind, MacroFile,
2121
};
2222

2323
#[derive(Clone, Debug)]
@@ -216,9 +216,9 @@ fn make_hygiene_info(
216216

217217
impl HygieneFrame {
218218
pub(crate) fn new(db: &dyn AstDatabase, file_id: HirFileId) -> HygieneFrame {
219-
let (info, krate, local_inner) = match file_id.0 {
220-
HirFileIdRepr::FileId(_) => (None, None, false),
221-
HirFileIdRepr::MacroFile(macro_file) => {
219+
let (info, krate, local_inner) = match file_id.macro_file() {
220+
None => (None, None, false),
221+
Some(macro_file) => {
222222
let loc = db.lookup_intern_macro_call(macro_file.macro_call_id);
223223
let info =
224224
make_hygiene_info(db, macro_file, &loc).map(|info| (loc.kind.file_id(), info));

crates/hir-expand/src/lib.rs

+118-109
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,11 @@ pub use mbe::{Origin, ValueResult};
2323

2424
use std::{fmt, hash::Hash, iter, sync::Arc};
2525

26-
use base_db::{impl_intern_key, salsa, CrateId, FileId, FileRange, ProcMacroKind};
26+
use base_db::{
27+
impl_intern_key,
28+
salsa::{self, InternId},
29+
CrateId, FileId, FileRange, ProcMacroKind,
30+
};
2731
use either::Either;
2832
use syntax::{
2933
algo::{self, skip_trivia_token},
@@ -79,26 +83,12 @@ impl fmt::Display for ExpandError {
7983
/// finite (because everything bottoms out at the real `FileId`) and small
8084
/// (`MacroCallId` uses the location interning. You can check details here:
8185
/// <https://en.wikipedia.org/wiki/String_interning>).
86+
///
87+
/// The two variants are encoded in a single u32 which are differentiated by the MSB.
88+
/// If the MSB is 0, the value represents a `FileId`, otherwise the remaining 31 bits represent a
89+
/// `MacroCallId`.
8290
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
83-
pub struct HirFileId(HirFileIdRepr);
84-
85-
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
86-
enum HirFileIdRepr {
87-
FileId(FileId),
88-
MacroFile(MacroFile),
89-
}
90-
91-
impl From<FileId> for HirFileId {
92-
fn from(id: FileId) -> Self {
93-
HirFileId(HirFileIdRepr::FileId(id))
94-
}
95-
}
96-
97-
impl From<MacroFile> for HirFileId {
98-
fn from(id: MacroFile) -> Self {
99-
HirFileId(HirFileIdRepr::MacroFile(id))
100-
}
101-
}
91+
pub struct HirFileId(u32);
10292

10393
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
10494
pub struct MacroFile {
@@ -172,13 +162,37 @@ pub enum MacroCallKind {
172162
},
173163
}
174164

165+
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
166+
enum HirFileIdRepr {
167+
FileId(FileId),
168+
MacroFile(MacroFile),
169+
}
170+
171+
impl From<FileId> for HirFileId {
172+
fn from(FileId(id): FileId) -> Self {
173+
assert!(id < Self::MAX_FILE_ID);
174+
HirFileId(id)
175+
}
176+
}
177+
178+
impl From<MacroFile> for HirFileId {
179+
fn from(MacroFile { macro_call_id: MacroCallId(id) }: MacroFile) -> Self {
180+
let id = id.as_u32();
181+
assert!(id < Self::MAX_FILE_ID);
182+
HirFileId(id | Self::MACRO_FILE_TAG_MASK)
183+
}
184+
}
185+
175186
impl HirFileId {
187+
const MAX_FILE_ID: u32 = u32::MAX ^ Self::MACRO_FILE_TAG_MASK;
188+
const MACRO_FILE_TAG_MASK: u32 = 1 << 31;
189+
176190
/// For macro-expansion files, returns the file original source file the
177191
/// expansion originated from.
178192
pub fn original_file(self, db: &dyn db::AstDatabase) -> FileId {
179193
let mut file_id = self;
180194
loop {
181-
match file_id.0 {
195+
match file_id.repr() {
182196
HirFileIdRepr::FileId(id) => break id,
183197
HirFileIdRepr::MacroFile(MacroFile { macro_call_id }) => {
184198
let loc: MacroCallLoc = db.lookup_intern_macro_call(macro_call_id);
@@ -194,7 +208,7 @@ impl HirFileId {
194208
pub fn expansion_level(self, db: &dyn db::AstDatabase) -> u32 {
195209
let mut level = 0;
196210
let mut curr = self;
197-
while let HirFileIdRepr::MacroFile(macro_file) = curr.0 {
211+
while let Some(macro_file) = curr.macro_file() {
198212
let loc: MacroCallLoc = db.lookup_intern_macro_call(macro_file.macro_call_id);
199213

200214
level += 1;
@@ -205,25 +219,17 @@ impl HirFileId {
205219

206220
/// If this is a macro call, returns the syntax node of the call.
207221
pub fn call_node(self, db: &dyn db::AstDatabase) -> Option<InFile<SyntaxNode>> {
208-
match self.0 {
209-
HirFileIdRepr::FileId(_) => None,
210-
HirFileIdRepr::MacroFile(macro_file) => {
211-
let loc: MacroCallLoc = db.lookup_intern_macro_call(macro_file.macro_call_id);
212-
Some(loc.kind.to_node(db))
213-
}
214-
}
222+
let macro_file = self.macro_file()?;
223+
let loc: MacroCallLoc = db.lookup_intern_macro_call(macro_file.macro_call_id);
224+
Some(loc.kind.to_node(db))
215225
}
216226

217227
/// If this is a macro call, returns the syntax node of the very first macro call this file resides in.
218228
pub fn original_call_node(self, db: &dyn db::AstDatabase) -> Option<(FileId, SyntaxNode)> {
219-
let mut call = match self.0 {
220-
HirFileIdRepr::FileId(_) => return None,
221-
HirFileIdRepr::MacroFile(MacroFile { macro_call_id }) => {
222-
db.lookup_intern_macro_call(macro_call_id).kind.to_node(db)
223-
}
224-
};
229+
let mut call =
230+
db.lookup_intern_macro_call(self.macro_file()?.macro_call_id).kind.to_node(db);
225231
loop {
226-
match call.file_id.0 {
232+
match call.file_id.repr() {
227233
HirFileIdRepr::FileId(file_id) => break Some((file_id, call.value)),
228234
HirFileIdRepr::MacroFile(MacroFile { macro_call_id }) => {
229235
call = db.lookup_intern_macro_call(macro_call_id).kind.to_node(db);
@@ -234,84 +240,74 @@ impl HirFileId {
234240

235241
/// Return expansion information if it is a macro-expansion file
236242
pub fn expansion_info(self, db: &dyn db::AstDatabase) -> Option<ExpansionInfo> {
237-
match self.0 {
238-
HirFileIdRepr::FileId(_) => None,
239-
HirFileIdRepr::MacroFile(macro_file) => {
240-
let loc: MacroCallLoc = db.lookup_intern_macro_call(macro_file.macro_call_id);
243+
let macro_file = self.macro_file()?;
244+
let loc: MacroCallLoc = db.lookup_intern_macro_call(macro_file.macro_call_id);
241245

242-
let arg_tt = loc.kind.arg(db)?;
246+
let arg_tt = loc.kind.arg(db)?;
243247

244-
let macro_def = db.macro_def(loc.def).ok()?;
245-
let (parse, exp_map) = db.parse_macro_expansion(macro_file).value?;
246-
let macro_arg = db.macro_arg(macro_file.macro_call_id)?;
248+
let macro_def = db.macro_def(loc.def).ok()?;
249+
let (parse, exp_map) = db.parse_macro_expansion(macro_file).value?;
250+
let macro_arg = db.macro_arg(macro_file.macro_call_id)?;
247251

248-
let def = loc.def.ast_id().left().and_then(|id| {
249-
let def_tt = match id.to_node(db) {
250-
ast::Macro::MacroRules(mac) => mac.token_tree()?,
251-
ast::Macro::MacroDef(_)
252-
if matches!(*macro_def, TokenExpander::BuiltinAttr(_)) =>
253-
{
254-
return None
255-
}
256-
ast::Macro::MacroDef(mac) => mac.body()?,
257-
};
258-
Some(InFile::new(id.file_id, def_tt))
259-
});
260-
let attr_input_or_mac_def = def.or_else(|| match loc.kind {
261-
MacroCallKind::Attr { ast_id, invoc_attr_index, .. } => {
262-
let tt = ast_id
263-
.to_node(db)
264-
.doc_comments_and_attrs()
265-
.nth(invoc_attr_index as usize)
266-
.and_then(Either::left)?
267-
.token_tree()?;
268-
Some(InFile::new(ast_id.file_id, tt))
269-
}
270-
_ => None,
271-
});
272-
273-
Some(ExpansionInfo {
274-
expanded: InFile::new(self, parse.syntax_node()),
275-
arg: InFile::new(loc.kind.file_id(), arg_tt),
276-
attr_input_or_mac_def,
277-
macro_arg_shift: mbe::Shift::new(&macro_arg.0),
278-
macro_arg,
279-
macro_def,
280-
exp_map,
281-
})
252+
let def = loc.def.ast_id().left().and_then(|id| {
253+
let def_tt = match id.to_node(db) {
254+
ast::Macro::MacroRules(mac) => mac.token_tree()?,
255+
ast::Macro::MacroDef(_) if matches!(*macro_def, TokenExpander::BuiltinAttr(_)) => {
256+
return None
257+
}
258+
ast::Macro::MacroDef(mac) => mac.body()?,
259+
};
260+
Some(InFile::new(id.file_id, def_tt))
261+
});
262+
let attr_input_or_mac_def = def.or_else(|| match loc.kind {
263+
MacroCallKind::Attr { ast_id, invoc_attr_index, .. } => {
264+
let tt = ast_id
265+
.to_node(db)
266+
.doc_comments_and_attrs()
267+
.nth(invoc_attr_index as usize)
268+
.and_then(Either::left)?
269+
.token_tree()?;
270+
Some(InFile::new(ast_id.file_id, tt))
282271
}
283-
}
272+
_ => None,
273+
});
274+
275+
Some(ExpansionInfo {
276+
expanded: InFile::new(self, parse.syntax_node()),
277+
arg: InFile::new(loc.kind.file_id(), arg_tt),
278+
attr_input_or_mac_def,
279+
macro_arg_shift: mbe::Shift::new(&macro_arg.0),
280+
macro_arg,
281+
macro_def,
282+
exp_map,
283+
})
284284
}
285285

286286
/// Indicate it is macro file generated for builtin derive
287287
pub fn is_builtin_derive(&self, db: &dyn db::AstDatabase) -> Option<InFile<ast::Attr>> {
288-
match self.0 {
289-
HirFileIdRepr::FileId(_) => None,
290-
HirFileIdRepr::MacroFile(macro_file) => {
291-
let loc: MacroCallLoc = db.lookup_intern_macro_call(macro_file.macro_call_id);
292-
let attr = match loc.def.kind {
293-
MacroDefKind::BuiltInDerive(..) => loc.kind.to_node(db),
294-
_ => return None,
295-
};
296-
Some(attr.with_value(ast::Attr::cast(attr.value.clone())?))
297-
}
298-
}
288+
let macro_file = self.macro_file()?;
289+
let loc: MacroCallLoc = db.lookup_intern_macro_call(macro_file.macro_call_id);
290+
let attr = match loc.def.kind {
291+
MacroDefKind::BuiltInDerive(..) => loc.kind.to_node(db),
292+
_ => return None,
293+
};
294+
Some(attr.with_value(ast::Attr::cast(attr.value.clone())?))
299295
}
300296

301297
pub fn is_custom_derive(&self, db: &dyn db::AstDatabase) -> bool {
302-
match self.0 {
303-
HirFileIdRepr::FileId(_) => false,
304-
HirFileIdRepr::MacroFile(macro_file) => {
298+
match self.macro_file() {
299+
Some(macro_file) => {
305300
let loc: MacroCallLoc = db.lookup_intern_macro_call(macro_file.macro_call_id);
306301
matches!(loc.def.kind, MacroDefKind::ProcMacro(_, ProcMacroKind::CustomDerive, _))
307302
}
303+
None => false,
308304
}
309305
}
310306

311307
/// Return whether this file is an include macro
312308
pub fn is_include_macro(&self, db: &dyn db::AstDatabase) -> bool {
313-
match self.0 {
314-
HirFileIdRepr::MacroFile(macro_file) => {
309+
match self.macro_file() {
310+
Some(macro_file) => {
315311
let loc: MacroCallLoc = db.lookup_intern_macro_call(macro_file.macro_call_id);
316312
matches!(loc.eager, Some(EagerCallInfo { included_file: Some(_), .. }))
317313
}
@@ -321,8 +317,8 @@ impl HirFileId {
321317

322318
/// Return whether this file is an attr macro
323319
pub fn is_attr_macro(&self, db: &dyn db::AstDatabase) -> bool {
324-
match self.0 {
325-
HirFileIdRepr::MacroFile(macro_file) => {
320+
match self.macro_file() {
321+
Some(macro_file) => {
326322
let loc: MacroCallLoc = db.lookup_intern_macro_call(macro_file.macro_call_id);
327323
matches!(loc.kind, MacroCallKind::Attr { .. })
328324
}
@@ -333,23 +329,36 @@ impl HirFileId {
333329
/// Return whether this file is the pseudo expansion of the derive attribute.
334330
/// See [`crate::builtin_attr_macro::derive_attr_expand`].
335331
pub fn is_derive_attr_pseudo_expansion(&self, db: &dyn db::AstDatabase) -> bool {
336-
match self.0 {
337-
HirFileIdRepr::MacroFile(macro_file) => {
332+
match self.macro_file() {
333+
Some(macro_file) => {
338334
let loc: MacroCallLoc = db.lookup_intern_macro_call(macro_file.macro_call_id);
339335
matches!(loc.kind, MacroCallKind::Attr { is_derive: true, .. })
340336
}
341-
_ => false,
337+
None => false,
342338
}
343339
}
344340

341+
#[inline]
345342
pub fn is_macro(self) -> bool {
346-
matches!(self.0, HirFileIdRepr::MacroFile(_))
343+
self.0 & Self::MACRO_FILE_TAG_MASK != 0
347344
}
348345

346+
#[inline]
349347
pub fn macro_file(self) -> Option<MacroFile> {
350-
match self.0 {
351-
HirFileIdRepr::FileId(_) => None,
352-
HirFileIdRepr::MacroFile(m) => Some(m),
348+
match self.0 & Self::MACRO_FILE_TAG_MASK {
349+
0 => None,
350+
_ => Some(MacroFile {
351+
macro_call_id: MacroCallId(InternId::from(self.0 ^ Self::MACRO_FILE_TAG_MASK)),
352+
}),
353+
}
354+
}
355+
356+
fn repr(self) -> HirFileIdRepr {
357+
match self.0 & Self::MACRO_FILE_TAG_MASK {
358+
0 => HirFileIdRepr::FileId(FileId(self.0)),
359+
_ => HirFileIdRepr::MacroFile(MacroFile {
360+
macro_call_id: MacroCallId(InternId::from(self.0 ^ Self::MACRO_FILE_TAG_MASK)),
361+
}),
353362
}
354363
}
355364
}
@@ -442,7 +451,7 @@ impl MacroCallKind {
442451
pub fn original_call_range_with_body(self, db: &dyn db::AstDatabase) -> FileRange {
443452
let mut kind = self;
444453
let file_id = loop {
445-
match kind.file_id().0 {
454+
match kind.file_id().repr() {
446455
HirFileIdRepr::MacroFile(file) => {
447456
kind = db.lookup_intern_macro_call(file.macro_call_id).kind;
448457
}
@@ -467,7 +476,7 @@ impl MacroCallKind {
467476
pub fn original_call_range(self, db: &dyn db::AstDatabase) -> FileRange {
468477
let mut kind = self;
469478
let file_id = loop {
470-
match kind.file_id().0 {
479+
match kind.file_id().repr() {
471480
HirFileIdRepr::MacroFile(file) => {
472481
kind = db.lookup_intern_macro_call(file.macro_call_id).kind;
473482
}
@@ -779,7 +788,7 @@ impl<'a> InFile<&'a SyntaxNode> {
779788
/// For attributes and derives, this will point back to the attribute only.
780789
/// For the entire item `InFile::use original_file_range_full`.
781790
pub fn original_file_range(self, db: &dyn db::AstDatabase) -> FileRange {
782-
match self.file_id.0 {
791+
match self.file_id.repr() {
783792
HirFileIdRepr::FileId(file_id) => FileRange { file_id, range: self.value.text_range() },
784793
HirFileIdRepr::MacroFile(mac_file) => {
785794
if let Some(res) = self.original_file_range_opt(db) {
@@ -846,7 +855,7 @@ impl InFile<SyntaxToken> {
846855

847856
/// Falls back to the macro call range if the node cannot be mapped up fully.
848857
pub fn original_file_range(self, db: &dyn db::AstDatabase) -> FileRange {
849-
match self.file_id.0 {
858+
match self.file_id.repr() {
850859
HirFileIdRepr::FileId(file_id) => FileRange { file_id, range: self.value.text_range() },
851860
HirFileIdRepr::MacroFile(mac_file) => {
852861
if let Some(res) = self.original_file_range_opt(db) {
@@ -861,7 +870,7 @@ impl InFile<SyntaxToken> {
861870

862871
/// Attempts to map the syntax node back up its macro calls.
863872
pub fn original_file_range_opt(self, db: &dyn db::AstDatabase) -> Option<FileRange> {
864-
match self.file_id.0 {
873+
match self.file_id.repr() {
865874
HirFileIdRepr::FileId(file_id) => {
866875
Some(FileRange { file_id, range: self.value.text_range() })
867876
}

0 commit comments

Comments
 (0)