@@ -23,7 +23,11 @@ pub use mbe::{Origin, ValueResult};
23
23
24
24
use std:: { fmt, hash:: Hash , iter, sync:: Arc } ;
25
25
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
+ } ;
27
31
use either:: Either ;
28
32
use syntax:: {
29
33
algo:: { self , skip_trivia_token} ,
@@ -79,26 +83,12 @@ impl fmt::Display for ExpandError {
79
83
/// finite (because everything bottoms out at the real `FileId`) and small
80
84
/// (`MacroCallId` uses the location interning. You can check details here:
81
85
/// <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`.
82
90
#[ 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 ) ;
102
92
103
93
#[ derive( Debug , Clone , Copy , PartialEq , Eq , Hash ) ]
104
94
pub struct MacroFile {
@@ -172,13 +162,37 @@ pub enum MacroCallKind {
172
162
} ,
173
163
}
174
164
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
+
175
186
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
+
176
190
/// For macro-expansion files, returns the file original source file the
177
191
/// expansion originated from.
178
192
pub fn original_file ( self , db : & dyn db:: AstDatabase ) -> FileId {
179
193
let mut file_id = self ;
180
194
loop {
181
- match file_id. 0 {
195
+ match file_id. repr ( ) {
182
196
HirFileIdRepr :: FileId ( id) => break id,
183
197
HirFileIdRepr :: MacroFile ( MacroFile { macro_call_id } ) => {
184
198
let loc: MacroCallLoc = db. lookup_intern_macro_call ( macro_call_id) ;
@@ -194,7 +208,7 @@ impl HirFileId {
194
208
pub fn expansion_level ( self , db : & dyn db:: AstDatabase ) -> u32 {
195
209
let mut level = 0 ;
196
210
let mut curr = self ;
197
- while let HirFileIdRepr :: MacroFile ( macro_file) = curr. 0 {
211
+ while let Some ( macro_file) = curr. macro_file ( ) {
198
212
let loc: MacroCallLoc = db. lookup_intern_macro_call ( macro_file. macro_call_id ) ;
199
213
200
214
level += 1 ;
@@ -205,25 +219,17 @@ impl HirFileId {
205
219
206
220
/// If this is a macro call, returns the syntax node of the call.
207
221
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) )
215
225
}
216
226
217
227
/// If this is a macro call, returns the syntax node of the very first macro call this file resides in.
218
228
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) ;
225
231
loop {
226
- match call. file_id . 0 {
232
+ match call. file_id . repr ( ) {
227
233
HirFileIdRepr :: FileId ( file_id) => break Some ( ( file_id, call. value ) ) ,
228
234
HirFileIdRepr :: MacroFile ( MacroFile { macro_call_id } ) => {
229
235
call = db. lookup_intern_macro_call ( macro_call_id) . kind . to_node ( db) ;
@@ -234,84 +240,74 @@ impl HirFileId {
234
240
235
241
/// Return expansion information if it is a macro-expansion file
236
242
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 ) ;
241
245
242
- let arg_tt = loc. kind . arg ( db) ?;
246
+ let arg_tt = loc. kind . arg ( db) ?;
243
247
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 ) ?;
247
251
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) )
282
271
}
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
+ } )
284
284
}
285
285
286
286
/// Indicate it is macro file generated for builtin derive
287
287
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 ( ) ) ?) )
299
295
}
300
296
301
297
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) => {
305
300
let loc: MacroCallLoc = db. lookup_intern_macro_call ( macro_file. macro_call_id ) ;
306
301
matches ! ( loc. def. kind, MacroDefKind :: ProcMacro ( _, ProcMacroKind :: CustomDerive , _) )
307
302
}
303
+ None => false ,
308
304
}
309
305
}
310
306
311
307
/// Return whether this file is an include macro
312
308
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) => {
315
311
let loc: MacroCallLoc = db. lookup_intern_macro_call ( macro_file. macro_call_id ) ;
316
312
matches ! ( loc. eager, Some ( EagerCallInfo { included_file: Some ( _) , .. } ) )
317
313
}
@@ -321,8 +317,8 @@ impl HirFileId {
321
317
322
318
/// Return whether this file is an attr macro
323
319
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) => {
326
322
let loc: MacroCallLoc = db. lookup_intern_macro_call ( macro_file. macro_call_id ) ;
327
323
matches ! ( loc. kind, MacroCallKind :: Attr { .. } )
328
324
}
@@ -333,23 +329,36 @@ impl HirFileId {
333
329
/// Return whether this file is the pseudo expansion of the derive attribute.
334
330
/// See [`crate::builtin_attr_macro::derive_attr_expand`].
335
331
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) => {
338
334
let loc: MacroCallLoc = db. lookup_intern_macro_call ( macro_file. macro_call_id ) ;
339
335
matches ! ( loc. kind, MacroCallKind :: Attr { is_derive: true , .. } )
340
336
}
341
- _ => false ,
337
+ None => false ,
342
338
}
343
339
}
344
340
341
+ #[ inline]
345
342
pub fn is_macro ( self ) -> bool {
346
- matches ! ( self . 0 , HirFileIdRepr :: MacroFile ( _ ) )
343
+ self . 0 & Self :: MACRO_FILE_TAG_MASK != 0
347
344
}
348
345
346
+ #[ inline]
349
347
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
+ } ) ,
353
362
}
354
363
}
355
364
}
@@ -442,7 +451,7 @@ impl MacroCallKind {
442
451
pub fn original_call_range_with_body ( self , db : & dyn db:: AstDatabase ) -> FileRange {
443
452
let mut kind = self ;
444
453
let file_id = loop {
445
- match kind. file_id ( ) . 0 {
454
+ match kind. file_id ( ) . repr ( ) {
446
455
HirFileIdRepr :: MacroFile ( file) => {
447
456
kind = db. lookup_intern_macro_call ( file. macro_call_id ) . kind ;
448
457
}
@@ -467,7 +476,7 @@ impl MacroCallKind {
467
476
pub fn original_call_range ( self , db : & dyn db:: AstDatabase ) -> FileRange {
468
477
let mut kind = self ;
469
478
let file_id = loop {
470
- match kind. file_id ( ) . 0 {
479
+ match kind. file_id ( ) . repr ( ) {
471
480
HirFileIdRepr :: MacroFile ( file) => {
472
481
kind = db. lookup_intern_macro_call ( file. macro_call_id ) . kind ;
473
482
}
@@ -779,7 +788,7 @@ impl<'a> InFile<&'a SyntaxNode> {
779
788
/// For attributes and derives, this will point back to the attribute only.
780
789
/// For the entire item `InFile::use original_file_range_full`.
781
790
pub fn original_file_range ( self , db : & dyn db:: AstDatabase ) -> FileRange {
782
- match self . file_id . 0 {
791
+ match self . file_id . repr ( ) {
783
792
HirFileIdRepr :: FileId ( file_id) => FileRange { file_id, range : self . value . text_range ( ) } ,
784
793
HirFileIdRepr :: MacroFile ( mac_file) => {
785
794
if let Some ( res) = self . original_file_range_opt ( db) {
@@ -846,7 +855,7 @@ impl InFile<SyntaxToken> {
846
855
847
856
/// Falls back to the macro call range if the node cannot be mapped up fully.
848
857
pub fn original_file_range ( self , db : & dyn db:: AstDatabase ) -> FileRange {
849
- match self . file_id . 0 {
858
+ match self . file_id . repr ( ) {
850
859
HirFileIdRepr :: FileId ( file_id) => FileRange { file_id, range : self . value . text_range ( ) } ,
851
860
HirFileIdRepr :: MacroFile ( mac_file) => {
852
861
if let Some ( res) = self . original_file_range_opt ( db) {
@@ -861,7 +870,7 @@ impl InFile<SyntaxToken> {
861
870
862
871
/// Attempts to map the syntax node back up its macro calls.
863
872
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 ( ) {
865
874
HirFileIdRepr :: FileId ( file_id) => {
866
875
Some ( FileRange { file_id, range : self . value . text_range ( ) } )
867
876
}
0 commit comments