@@ -87,6 +87,95 @@ pub struct Span {
87
87
ctxt_or_parent_or_marker : u16 ,
88
88
}
89
89
90
+ #[ derive( Clone , Copy ) ]
91
+ struct SpanInlineCtxt {
92
+ lo : u32 ,
93
+ len : u16 ,
94
+ ctxt : u16 ,
95
+ }
96
+ #[ derive( Clone , Copy ) ]
97
+ struct SpanInlineParent {
98
+ lo : u32 ,
99
+ len_with_tag : u16 ,
100
+ parent : u16 ,
101
+ }
102
+ #[ derive( Clone , Copy ) ]
103
+ struct SpanPartiallyInterned {
104
+ index : u32 ,
105
+ _marker1 : u16 ,
106
+ ctxt : u16 ,
107
+ }
108
+ #[ derive( Clone , Copy ) ]
109
+ struct SpanInterned {
110
+ index : u32 ,
111
+ _marker1 : u16 ,
112
+ _marker2 : u16 ,
113
+ }
114
+
115
+ #[ allow( dead_code) ]
116
+ union SpanRepr {
117
+ inline_ctxt : SpanInlineCtxt ,
118
+ inline_parent : SpanInlineParent ,
119
+ partially_interned : SpanPartiallyInterned ,
120
+ interned : SpanInterned ,
121
+ }
122
+
123
+ enum Fmt < ' a > {
124
+ InlineCtxt ( & ' a mut SpanInlineCtxt ) ,
125
+ InlineParent ( & ' a mut SpanInlineParent ) ,
126
+ PartiallyInterned ( & ' a mut SpanPartiallyInterned ) ,
127
+ Interned ( & ' a mut SpanInterned ) ,
128
+ }
129
+
130
+ impl SpanInlineCtxt {
131
+ fn data ( self ) -> SpanData {
132
+ let len = self . len as u32 ;
133
+ debug_assert ! ( len <= MAX_LEN ) ;
134
+ SpanData {
135
+ lo : BytePos ( self . lo ) ,
136
+ hi : BytePos ( self . lo . debug_strict_add ( len) ) ,
137
+ ctxt : SyntaxContext :: from_u32 ( self . ctxt as u32 ) ,
138
+ parent : None ,
139
+ }
140
+ }
141
+ }
142
+ impl SpanInlineParent {
143
+ fn data ( self ) -> SpanData {
144
+ let len = ( self . len_with_tag & !PARENT_TAG ) as u32 ;
145
+ debug_assert ! ( len <= MAX_LEN ) ;
146
+ let parent = LocalDefId { local_def_index : DefIndex :: from_u32 ( self . parent as u32 ) } ;
147
+ SpanData {
148
+ lo : BytePos ( self . lo ) ,
149
+ hi : BytePos ( self . lo . debug_strict_add ( len) ) ,
150
+ ctxt : SyntaxContext :: root ( ) ,
151
+ parent : Some ( parent) ,
152
+ }
153
+ }
154
+ }
155
+ impl SpanPartiallyInterned {
156
+ fn data ( self ) -> SpanData {
157
+ SpanData {
158
+ ctxt : SyntaxContext :: from_u32 ( self . ctxt as u32 ) ,
159
+ ..with_span_interner ( |interner| interner. spans [ self . index as usize ] )
160
+ }
161
+ }
162
+ }
163
+ impl SpanInterned {
164
+ fn data ( self ) -> SpanData {
165
+ with_span_interner ( |interner| interner. spans [ self . index as usize ] )
166
+ }
167
+ }
168
+ impl Fmt < ' _ > {
169
+ fn data ( self ) -> SpanData {
170
+ match self {
171
+ Fmt :: InlineCtxt ( span) => span. data ( ) ,
172
+ Fmt :: InlineParent ( span) => span. data ( ) ,
173
+ Fmt :: PartiallyInterned ( span) => span. data ( ) ,
174
+ Fmt :: Interned ( span) => span. data ( ) ,
175
+ }
176
+ }
177
+ }
178
+
90
179
// `MAX_LEN` is chosen so that `PARENT_TAG | MAX_LEN` is distinct from
91
180
// `BASE_LEN_INTERNED_MARKER`. (If `MAX_LEN` was 1 higher, this wouldn't be true.)
92
181
const MAX_LEN : u32 = 0b0111_1111_1111_1110 ;
@@ -137,6 +226,7 @@ impl Span {
137
226
138
227
// Partially-interned or fully-interned format.
139
228
let ( ctxt_or_parent_or_marker, ctxt) = if ctxt2 <= MAX_CTXT {
229
+ // any value, should never be read
140
230
( ctxt2 as u16 , SyntaxContext :: from_u32 ( u32:: MAX ) ) // partially-interned
141
231
} else {
142
232
( CTXT_INTERNED_MARKER , ctxt) // fully-interned
@@ -162,43 +252,8 @@ impl Span {
162
252
/// Internal function to translate between an encoded span and the expanded representation.
163
253
/// This function must not be used outside the incremental engine.
164
254
#[ inline]
165
- pub fn data_untracked ( self ) -> SpanData {
166
- if self . len_with_tag_or_marker != BASE_LEN_INTERNED_MARKER {
167
- if self . len_with_tag_or_marker & PARENT_TAG == 0 {
168
- // Inline-context format.
169
- let len = self . len_with_tag_or_marker as u32 ;
170
- debug_assert ! ( len <= MAX_LEN ) ;
171
- SpanData {
172
- lo : BytePos ( self . lo_or_index ) ,
173
- hi : BytePos ( self . lo_or_index . debug_strict_add ( len) ) ,
174
- ctxt : SyntaxContext :: from_u32 ( self . ctxt_or_parent_or_marker as u32 ) ,
175
- parent : None ,
176
- }
177
- } else {
178
- // Inline-parent format.
179
- let len = ( self . len_with_tag_or_marker & !PARENT_TAG ) as u32 ;
180
- debug_assert ! ( len <= MAX_LEN ) ;
181
- let parent = LocalDefId {
182
- local_def_index : DefIndex :: from_u32 ( self . ctxt_or_parent_or_marker as u32 ) ,
183
- } ;
184
- SpanData {
185
- lo : BytePos ( self . lo_or_index ) ,
186
- hi : BytePos ( self . lo_or_index . debug_strict_add ( len) ) ,
187
- ctxt : SyntaxContext :: root ( ) ,
188
- parent : Some ( parent) ,
189
- }
190
- }
191
- } else {
192
- // Fully-interned or partially-interned format. In either case,
193
- // the interned value contains all the data, so we don't need to
194
- // distinguish them.
195
- let index = self . lo_or_index ;
196
- let mut data = with_span_interner ( |interner| interner. spans [ index as usize ] ) ;
197
- if data. ctxt . as_u32 ( ) == u32:: MAX {
198
- data. ctxt = SyntaxContext :: from_u32 ( u32:: from ( self . ctxt_or_parent_or_marker ) ) ;
199
- }
200
- data
201
- }
255
+ pub fn data_untracked ( mut self ) -> SpanData {
256
+ self . fmt ( ) . data ( )
202
257
}
203
258
204
259
/// Returns `true` if this is a dummy span with any hygienic context.
@@ -218,66 +273,77 @@ impl Span {
218
273
}
219
274
}
220
275
276
+ #[ inline]
277
+ fn fmt ( & mut self ) -> Fmt < ' _ > {
278
+ unsafe {
279
+ if self . len_with_tag_or_marker != BASE_LEN_INTERNED_MARKER {
280
+ if self . len_with_tag_or_marker & PARENT_TAG == 0 {
281
+ Fmt :: InlineCtxt ( std:: mem:: transmute ( self ) )
282
+ } else {
283
+ Fmt :: InlineParent ( std:: mem:: transmute ( self ) )
284
+ }
285
+ } else if self . ctxt_or_parent_or_marker != CTXT_INTERNED_MARKER {
286
+ Fmt :: PartiallyInterned ( std:: mem:: transmute ( self ) )
287
+ } else {
288
+ Fmt :: Interned ( std:: mem:: transmute ( self ) )
289
+ }
290
+ }
291
+ }
292
+
221
293
// Returns either syntactic context, if it can be retrieved without taking the interner lock,
222
294
// or an index into the interner if it cannot.
223
- fn inline_ctxt ( self ) -> Result < SyntaxContext , usize > {
224
- Ok ( if self . len_with_tag_or_marker != BASE_LEN_INTERNED_MARKER {
225
- if self . len_with_tag_or_marker & PARENT_TAG == 0 {
226
- // Inline-context format.
227
- SyntaxContext :: from_u32 ( self . ctxt_or_parent_or_marker as u32 )
228
- } else {
229
- // Inline-parent format. We know that the SyntaxContext is root.
230
- SyntaxContext :: root ( )
295
+ fn inline_ctxt ( mut self ) -> Result < SyntaxContext , usize > {
296
+ match self . fmt ( ) {
297
+ Fmt :: InlineCtxt ( SpanInlineCtxt { ctxt, .. } )
298
+ | Fmt :: PartiallyInterned ( SpanPartiallyInterned { ctxt, .. } ) => {
299
+ Ok ( SyntaxContext :: from_u32 ( * ctxt as u32 ) )
231
300
}
232
- } else if self . ctxt_or_parent_or_marker != CTXT_INTERNED_MARKER {
233
- // Partially-interned format. This path avoids looking up the
234
- // interned value, and is the whole point of the
235
- // partially-interned format.
236
- SyntaxContext :: from_u32 ( self . ctxt_or_parent_or_marker as u32 )
237
- } else {
238
- // Fully-interned format.
239
- return Err ( self . lo_or_index as usize ) ;
240
- } )
301
+ Fmt :: InlineParent ( _) => Ok ( SyntaxContext :: root ( ) ) ,
302
+ Fmt :: Interned ( span) => Err ( span. index as usize ) ,
303
+ }
241
304
}
242
305
243
- pub fn update_ctxt ( & mut self , update : impl FnOnce ( SyntaxContext ) -> SyntaxContext ) {
306
+ pub fn update_ctxt ( & mut self , update : impl Fn ( SyntaxContext ) -> SyntaxContext ) {
307
+ let orig_data = self . data_untracked ( ) ;
308
+
244
309
let updated_ctxt32;
245
310
let data;
246
- if self . len_with_tag_or_marker != BASE_LEN_INTERNED_MARKER {
247
- if self . len_with_tag_or_marker & PARENT_TAG == 0 {
248
- // Inline-context format.
249
- updated_ctxt32 =
250
- update ( SyntaxContext :: from_u32 ( self . ctxt_or_parent_or_marker as u32 ) ) . as_u32 ( ) ;
311
+ match self . fmt ( ) {
312
+ Fmt :: InlineCtxt ( span) => {
313
+ updated_ctxt32 = update ( SyntaxContext :: from_u32 ( span. ctxt as u32 ) ) . as_u32 ( ) ;
251
314
if updated_ctxt32 <= MAX_CTXT {
252
- self . ctxt_or_parent_or_marker = updated_ctxt32 as u16 ;
315
+ span. ctxt = updated_ctxt32 as u16 ;
316
+ assert_eq ! ( * self , orig_data. with_ctxt( update( orig_data. ctxt) ) ) ;
253
317
return ;
254
318
}
255
- } else {
256
- // Inline-parent format. We know that the SyntaxContext is root.
319
+ data = span. data ( ) ;
320
+ }
321
+ Fmt :: PartiallyInterned ( span) => {
322
+ updated_ctxt32 = update ( SyntaxContext :: from_u32 ( span. ctxt as u32 ) ) . as_u32 ( ) ;
323
+ if updated_ctxt32 <= MAX_CTXT {
324
+ span. ctxt = updated_ctxt32 as u16 ;
325
+ assert_eq ! ( * self , orig_data. with_ctxt( update( orig_data. ctxt) ) ) ;
326
+ return ;
327
+ }
328
+ data = span. data ( ) ;
329
+ }
330
+ Fmt :: InlineParent ( span) => {
257
331
updated_ctxt32 = update ( SyntaxContext :: root ( ) ) . as_u32 ( ) ;
258
332
if updated_ctxt32 == 0 {
259
333
// do nothing
334
+ assert_eq ! ( * self , orig_data. with_ctxt( update( orig_data. ctxt) ) ) ;
260
335
return ;
261
336
}
337
+ data = span. data ( ) ;
262
338
}
263
- data = self . data_untracked ( ) ;
264
- } else if self . ctxt_or_parent_or_marker != CTXT_INTERNED_MARKER {
265
- // Partially-interned format. This path avoids looking up the
266
- // interned value, and is the whole point of the
267
- // partially-interned format.
268
- updated_ctxt32 =
269
- update ( SyntaxContext :: from_u32 ( self . ctxt_or_parent_or_marker as u32 ) ) . as_u32 ( ) ;
270
- if updated_ctxt32 <= MAX_CTXT {
271
- self . ctxt_or_parent_or_marker = updated_ctxt32 as u16 ;
272
- return ;
339
+ Fmt :: Interned ( span) => {
340
+ data = span. data ( ) ;
341
+ updated_ctxt32 = update ( data. ctxt ) . as_u32 ( ) ;
273
342
}
274
- data = self . data_untracked ( ) ;
275
- } else {
276
- data = self . data_untracked ( ) ;
277
- updated_ctxt32 = update ( data. ctxt ) . as_u32 ( ) ;
278
- } ;
343
+ }
279
344
280
345
* self = data. with_ctxt ( SyntaxContext :: from_u32 ( updated_ctxt32) ) ;
346
+ assert_eq ! ( * self , orig_data. with_ctxt( update( orig_data. ctxt) ) ) ;
281
347
}
282
348
283
349
/// This function is used as a fast path when decoding the full `SpanData` is not necessary.
0 commit comments