@@ -257,17 +257,17 @@ impl Span {
257257 std:: mem:: swap ( & mut lo, & mut hi) ;
258258 }
259259
260- // Small len may enable one of fully inline formats (or may not).
260+ // Small len and ctxt may enable one of fully inline formats (or may not).
261261 let ( len, ctxt32) = ( hi. 0 - lo. 0 , ctxt. as_u32 ( ) ) ;
262- if len <= MAX_LEN {
263- if ctxt32 <= MAX_CTXT && parent. is_none ( ) {
264- return InlineCtxt :: span ( lo. 0 , len as u16 , ctxt32 as u16 ) ;
265- } else if ctxt32 == 0
266- && let Some ( parent ) = parent
267- && let parent32 = parent . local_def_index . as_u32 ( )
268- && parent32 <= MAX_CTXT
269- {
270- return InlineParent :: span ( lo . 0 , len as u16 , parent32 as u16 ) ;
262+ if len <= MAX_LEN && ctxt32 <= MAX_CTXT {
263+ match parent {
264+ None => return InlineCtxt :: span ( lo. 0 , len as u16 , ctxt32 as u16 ) ,
265+ Some ( parent ) => {
266+ let parent32 = parent. local_def_index . as_u32 ( ) ;
267+ if ctxt32 == 0 && parent32 <= MAX_CTXT {
268+ return InlineParent :: span ( lo . 0 , len as u16 , parent32 as u16 ) ;
269+ }
270+ }
271271 }
272272 }
273273
@@ -322,29 +322,28 @@ impl Span {
322322 }
323323 }
324324
325- // For optimization we are interested in cases in which the context is inline and the context
326- // update doesn't change format. All non-inline or format changing scenarios require accessing
327- // interner and can fall back to `Span::new`.
328325 #[ inline]
329- pub fn map_ctxt ( self , update : impl FnOnce ( SyntaxContext ) -> SyntaxContext ) -> Span {
330- match_span_kind ! {
326+ pub fn map_ctxt ( self , map : impl FnOnce ( SyntaxContext ) -> SyntaxContext ) -> Span {
327+ let data = match_span_kind ! {
331328 self ,
332329 InlineCtxt ( span) => {
333- let updated_ctxt32 = update( SyntaxContext :: from_u16( span. ctxt) ) . as_u32( ) ;
334- // Any small new context including zero will preserve the format.
335- return if updated_ctxt32 <= MAX_CTXT {
336- InlineCtxt :: span( span. lo, span. len, updated_ctxt32 as u16 )
330+ // This format occurs 1-2 orders of magnitude more often than others (#125017),
331+ // so it makes sense to micro-optimize it to avoid `span.data()` and `Span::new()`.
332+ let new_ctxt = map( SyntaxContext :: from_u16( span. ctxt) ) ;
333+ let new_ctxt32 = new_ctxt. as_u32( ) ;
334+ return if new_ctxt32 <= MAX_CTXT {
335+ // Any small new context including zero will preserve the format.
336+ InlineCtxt :: span( span. lo, span. len, new_ctxt32 as u16 )
337337 } else {
338- span. data( ) . with_ctxt( SyntaxContext :: from_u32 ( updated_ctxt32 ) )
338+ span. data( ) . with_ctxt( new_ctxt )
339339 } ;
340340 } ,
341- InlineParent ( _span ) => { } ,
342- PartiallyInterned ( _span ) => { } ,
343- Interned ( _span ) => { } ,
344- }
341+ InlineParent ( span ) => span . data ( ) ,
342+ PartiallyInterned ( span ) => span . data ( ) ,
343+ Interned ( span ) => span . data ( ) ,
344+ } ;
345345
346- let data = self . data_untracked ( ) ;
347- data. with_ctxt ( update ( data. ctxt ) )
346+ data. with_ctxt ( map ( data. ctxt ) )
348347 }
349348
350349 // Returns either syntactic context, if it can be retrieved without taking the interner lock,
@@ -381,6 +380,49 @@ impl Span {
381380 } ) ,
382381 }
383382 }
383+
384+ #[ inline]
385+ pub fn with_parent ( self , parent : Option < LocalDefId > ) -> Span {
386+ let data = match_span_kind ! {
387+ self ,
388+ InlineCtxt ( span) => {
389+ // This format occurs 1-2 orders of magnitude more often than others (#126544),
390+ // so it makes sense to micro-optimize it to avoid `span.data()` and `Span::new()`.
391+ // Copypaste from `Span::new`, the small len & ctxt conditions are known to hold.
392+ match parent {
393+ None => return self ,
394+ Some ( parent) => {
395+ let parent32 = parent. local_def_index. as_u32( ) ;
396+ if span. ctxt == 0 && parent32 <= MAX_CTXT {
397+ return InlineParent :: span( span. lo, span. len, parent32 as u16 ) ;
398+ }
399+ }
400+ }
401+ span. data( )
402+ } ,
403+ InlineParent ( span) => span. data( ) ,
404+ PartiallyInterned ( span) => span. data( ) ,
405+ Interned ( span) => span. data( ) ,
406+ } ;
407+
408+ if let Some ( old_parent) = data. parent {
409+ ( * SPAN_TRACK ) ( old_parent) ;
410+ }
411+ data. with_parent ( parent)
412+ }
413+
414+ #[ inline]
415+ pub fn parent ( self ) -> Option < LocalDefId > {
416+ let interned_parent =
417+ |index : u32 | with_span_interner ( |interner| interner. spans [ index as usize ] . parent ) ;
418+ match_span_kind ! {
419+ self ,
420+ InlineCtxt ( _span) => None ,
421+ InlineParent ( span) => Some ( LocalDefId { local_def_index: DefIndex :: from_u16( span. parent) } ) ,
422+ PartiallyInterned ( span) => interned_parent( span. index) ,
423+ Interned ( span) => interned_parent( span. index) ,
424+ }
425+ }
384426}
385427
386428#[ derive( Default ) ]
0 commit comments