@@ -257,17 +257,17 @@ impl Span {
257
257
std:: mem:: swap ( & mut lo, & mut hi) ;
258
258
}
259
259
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).
261
261
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
+ }
271
271
}
272
272
}
273
273
@@ -322,29 +322,28 @@ impl Span {
322
322
}
323
323
}
324
324
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`.
328
325
#[ 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 ! {
331
328
self ,
332
329
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 )
337
337
} else {
338
- span. data( ) . with_ctxt( SyntaxContext :: from_u32 ( updated_ctxt32 ) )
338
+ span. data( ) . with_ctxt( new_ctxt )
339
339
} ;
340
340
} ,
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
+ } ;
345
345
346
- let data = self . data_untracked ( ) ;
347
- data. with_ctxt ( update ( data. ctxt ) )
346
+ data. with_ctxt ( map ( data. ctxt ) )
348
347
}
349
348
350
349
// Returns either syntactic context, if it can be retrieved without taking the interner lock,
@@ -381,6 +380,49 @@ impl Span {
381
380
} ) ,
382
381
}
383
382
}
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
+ }
384
426
}
385
427
386
428
#[ derive( Default ) ]
0 commit comments