@@ -87,6 +87,95 @@ pub struct Span {
8787 ctxt_or_parent_or_marker : u16 ,
8888}
8989
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+
90179// `MAX_LEN` is chosen so that `PARENT_TAG | MAX_LEN` is distinct from
91180// `BASE_LEN_INTERNED_MARKER`. (If `MAX_LEN` was 1 higher, this wouldn't be true.)
92181const MAX_LEN : u32 = 0b0111_1111_1111_1110 ;
@@ -137,6 +226,7 @@ impl Span {
137226
138227 // Partially-interned or fully-interned format.
139228 let ( ctxt_or_parent_or_marker, ctxt) = if ctxt2 <= MAX_CTXT {
229+ // any value, should never be read
140230 ( ctxt2 as u16 , SyntaxContext :: from_u32 ( u32:: MAX ) ) // partially-interned
141231 } else {
142232 ( CTXT_INTERNED_MARKER , ctxt) // fully-interned
@@ -162,43 +252,8 @@ impl Span {
162252 /// Internal function to translate between an encoded span and the expanded representation.
163253 /// This function must not be used outside the incremental engine.
164254 #[ 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 ( )
202257 }
203258
204259 /// Returns `true` if this is a dummy span with any hygienic context.
@@ -218,66 +273,77 @@ impl Span {
218273 }
219274 }
220275
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+
221293 // Returns either syntactic context, if it can be retrieved without taking the interner lock,
222294 // 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 ) )
231300 }
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+ }
241304 }
242305
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+
244309 let updated_ctxt32;
245310 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 ( ) ;
251314 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) ) ) ;
253317 return ;
254318 }
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) => {
257331 updated_ctxt32 = update ( SyntaxContext :: root ( ) ) . as_u32 ( ) ;
258332 if updated_ctxt32 == 0 {
259333 // do nothing
334+ assert_eq ! ( * self , orig_data. with_ctxt( update( orig_data. ctxt) ) ) ;
260335 return ;
261336 }
337+ data = span. data ( ) ;
262338 }
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 ( ) ;
273342 }
274- data = self . data_untracked ( ) ;
275- } else {
276- data = self . data_untracked ( ) ;
277- updated_ctxt32 = update ( data. ctxt ) . as_u32 ( ) ;
278- } ;
343+ }
279344
280345 * self = data. with_ctxt ( SyntaxContext :: from_u32 ( updated_ctxt32) ) ;
346+ assert_eq ! ( * self , orig_data. with_ctxt( update( orig_data. ctxt) ) ) ;
281347 }
282348
283349 /// This function is used as a fast path when decoding the full `SpanData` is not necessary.
0 commit comments