@@ -23,7 +23,11 @@ pub use mbe::{Origin, ValueResult};
2323
2424use 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+ } ;
2731use either:: Either ;
2832use 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 ) ]
10494pub 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+
175186impl 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