4
4
// The encoding format for inline spans were obtained by optimizing over crates in rustc/libstd.
5
5
// See https://internals.rust-lang.org/t/rfc-compiler-refactoring-spans/1357/28
6
6
7
- use crate :: def_id:: LocalDefId ;
7
+ use crate :: def_id:: { DefIndex , LocalDefId } ;
8
8
use crate :: hygiene:: SyntaxContext ;
9
9
use crate :: SPAN_TRACK ;
10
10
use crate :: { BytePos , SpanData } ;
@@ -13,8 +13,8 @@ use rustc_data_structures::fx::FxIndexSet;
13
13
14
14
/// A compressed span.
15
15
///
16
- /// Whereas [`SpanData`] is 12 bytes, which is a bit too big to stick everywhere, `Span`
17
- /// is a form that only takes up 8 bytes, with less space for the length and
16
+ /// Whereas [`SpanData`] is 16 bytes, which is a bit too big to stick everywhere, `Span`
17
+ /// is a form that only takes up 8 bytes, with less space for the length, parent and
18
18
/// context. The vast majority (99.9%+) of `SpanData` instances will fit within
19
19
/// those 8 bytes; any `SpanData` whose fields don't fit into a `Span` are
20
20
/// stored in a separate interner table, and the `Span` will index into that
@@ -25,7 +25,7 @@ use rustc_data_structures::fx::FxIndexSet;
25
25
/// slower because only 80--90% of spans could be stored inline (even less in
26
26
/// very large crates) and so the interner was used a lot more.
27
27
///
28
- /// Inline (compressed) format:
28
+ /// Inline (compressed) format with no parent :
29
29
/// - `span.base_or_index == span_data.lo`
30
30
/// - `span.len_or_tag == len == span_data.hi - span_data.lo` (must be `<= MAX_LEN`)
31
31
/// - `span.ctxt_or_tag == span_data.ctxt` (must be `<= MAX_CTXT`)
@@ -35,6 +35,12 @@ use rustc_data_structures::fx::FxIndexSet;
35
35
/// - `span.len_or_tag == LEN_TAG` (high bit set, all other bits are zero)
36
36
/// - `span.ctxt_or_tag == span_data.ctxt` (must be `<= MAX_CTXT`)
37
37
///
38
+ /// Inline (compressed) format with root context:
39
+ /// - `span.base_or_index == span_data.lo`
40
+ /// - `span.len_or_tag == len == span_data.hi - span_data.lo` (must be `<= MAX_LEN`)
41
+ /// - `span.len_or_tag` has top bit (`PARENT_MASK`) set
42
+ /// - `span.ctxt == span_data.parent` (must be `<= MAX_CTXT`)
43
+ ///
38
44
/// Interned format:
39
45
/// - `span.base_or_index == index` (indexes into the interner table)
40
46
/// - `span.len_or_tag == LEN_TAG` (high bit set, all other bits are zero)
@@ -73,7 +79,8 @@ pub struct Span {
73
79
ctxt_or_tag : u16 ,
74
80
}
75
81
76
- const LEN_TAG : u16 = 0b1000_0000_0000_0000 ;
82
+ const LEN_TAG : u16 = 0b1111_1111_1111_1111 ;
83
+ const PARENT_MASK : u16 = 0b1000_0000_0000_0000 ;
77
84
const MAX_LEN : u32 = 0b0111_1111_1111_1111 ;
78
85
const CTXT_TAG : u32 = 0b1111_1111_1111_1111 ;
79
86
const MAX_CTXT : u32 = CTXT_TAG - 1 ;
@@ -95,16 +102,32 @@ impl Span {
95
102
96
103
let ( base, len, ctxt2) = ( lo. 0 , hi. 0 - lo. 0 , ctxt. as_u32 ( ) ) ;
97
104
98
- if len <= MAX_LEN && ctxt2 <= MAX_CTXT && parent. is_none ( ) {
99
- // Inline format.
100
- Span { base_or_index : base, len_or_tag : len as u16 , ctxt_or_tag : ctxt2 as u16 }
101
- } else {
102
- // Interned format.
103
- let index =
104
- with_span_interner ( |interner| interner. intern ( & SpanData { lo, hi, ctxt, parent } ) ) ;
105
- let ctxt_or_tag = if ctxt2 <= MAX_CTXT { ctxt2 } else { CTXT_TAG } as u16 ;
106
- Span { base_or_index : index, len_or_tag : LEN_TAG , ctxt_or_tag }
105
+ if len <= MAX_LEN && ctxt2 <= MAX_CTXT {
106
+ let len_or_tag = len as u16 ;
107
+ debug_assert_eq ! ( len_or_tag & PARENT_MASK , 0 ) ;
108
+
109
+ if let Some ( parent) = parent {
110
+ // Inline format with parent.
111
+ let len_or_tag = len_or_tag | PARENT_MASK ;
112
+ let parent2 = parent. local_def_index . as_u32 ( ) ;
113
+ if ctxt2 == SyntaxContext :: root ( ) . as_u32 ( ) && parent2 <= MAX_CTXT {
114
+ return Span { base_or_index : base, len_or_tag, ctxt_or_tag : parent2 as u16 } ;
115
+ }
116
+ } else {
117
+ // Inline format with ctxt.
118
+ return Span {
119
+ base_or_index : base,
120
+ len_or_tag : len as u16 ,
121
+ ctxt_or_tag : ctxt2 as u16 ,
122
+ } ;
123
+ }
107
124
}
125
+
126
+ // Interned format.
127
+ let index =
128
+ with_span_interner ( |interner| interner. intern ( & SpanData { lo, hi, ctxt, parent } ) ) ;
129
+ let ctxt_or_tag = if ctxt2 <= MAX_CTXT { ctxt2 } else { CTXT_TAG } as u16 ;
130
+ Span { base_or_index : index, len_or_tag : LEN_TAG , ctxt_or_tag }
108
131
}
109
132
110
133
#[ inline]
@@ -122,12 +145,25 @@ impl Span {
122
145
pub fn data_untracked ( self ) -> SpanData {
123
146
if self . len_or_tag != LEN_TAG {
124
147
// Inline format.
125
- debug_assert ! ( self . len_or_tag as u32 <= MAX_LEN ) ;
126
- SpanData {
127
- lo : BytePos ( self . base_or_index ) ,
128
- hi : BytePos ( self . base_or_index + self . len_or_tag as u32 ) ,
129
- ctxt : SyntaxContext :: from_u32 ( self . ctxt_or_tag as u32 ) ,
130
- parent : None ,
148
+ if self . len_or_tag & PARENT_MASK == 0 {
149
+ debug_assert ! ( self . len_or_tag as u32 <= MAX_LEN ) ;
150
+ SpanData {
151
+ lo : BytePos ( self . base_or_index ) ,
152
+ hi : BytePos ( self . base_or_index + self . len_or_tag as u32 ) ,
153
+ ctxt : SyntaxContext :: from_u32 ( self . ctxt_or_tag as u32 ) ,
154
+ parent : None ,
155
+ }
156
+ } else {
157
+ let len = self . len_or_tag & !PARENT_MASK ;
158
+ debug_assert ! ( len as u32 <= MAX_LEN ) ;
159
+ let parent =
160
+ LocalDefId { local_def_index : DefIndex :: from_u32 ( self . ctxt_or_tag as u32 ) } ;
161
+ SpanData {
162
+ lo : BytePos ( self . base_or_index ) ,
163
+ hi : BytePos ( self . base_or_index + len as u32 ) ,
164
+ ctxt : SyntaxContext :: root ( ) ,
165
+ parent : Some ( parent) ,
166
+ }
131
167
}
132
168
} else {
133
169
// Interned format.
@@ -141,8 +177,14 @@ impl Span {
141
177
pub fn ctxt ( self ) -> SyntaxContext {
142
178
let ctxt_or_tag = self . ctxt_or_tag as u32 ;
143
179
if ctxt_or_tag <= MAX_CTXT {
144
- // Inline format or interned format with inline ctxt.
145
- SyntaxContext :: from_u32 ( ctxt_or_tag)
180
+ if self . len_or_tag == LEN_TAG || self . len_or_tag & PARENT_MASK == 0 {
181
+ // Inline format or interned format with inline ctxt.
182
+ SyntaxContext :: from_u32 ( ctxt_or_tag)
183
+ } else {
184
+ // Inline format or interned format with inline parent.
185
+ // We know that the SyntaxContext is root.
186
+ SyntaxContext :: root ( )
187
+ }
146
188
} else {
147
189
// Interned format.
148
190
let index = self . base_or_index ;
0 commit comments