@@ -401,6 +401,63 @@ impl Span {
401401 } ) ,
402402 }
403403 }
404+
405+ // For optimization we are interested in cases in which the parent is inline and the parent
406+ // update doesn't change format. All non-inline or format changing scenarios require accessing
407+ // interner and can fall back to `Span::new`.
408+ #[ inline]
409+ pub fn with_parent ( self , parent : Option < LocalDefId > ) -> Span {
410+ let data = match_span_kind ! {
411+ self ,
412+ InlineCtxt ( span) => {
413+ // Only if the new parent is `None` the format will be preserved.
414+ if parent. is_none( ) {
415+ return self ;
416+ }
417+ span. data( )
418+ } ,
419+ InlineParent ( span) => {
420+ // Any `Some` small new parent will preserve the format.
421+ // `None` may change the format to `InlineCtxt` if ctxt and len are small enough.
422+ if let Some ( parent) = parent
423+ && let parent32 = parent. local_def_index. as_u32( )
424+ && parent32 <= MAX_CTXT {
425+ let old_parent = LocalDefId { local_def_index: DefIndex :: from_u32( span. parent as u32 ) } ;
426+ // FIXME: Is this tracking necessary?
427+ ( * SPAN_TRACK ) ( old_parent) ;
428+ return InlineParent :: span( span. lo, span. len_with_tag, parent32 as u16 ) ;
429+ }
430+ span. data( )
431+ } ,
432+ PartiallyInterned ( span) => span. data( ) ,
433+ Interned ( span) => span. data( ) ,
434+ } ;
435+
436+ // We could not keep the span in the same inline format, fall back to the complete logic.
437+ if let Some ( old_parent) = data. parent {
438+ // FIXME: Is this tracking necessary?
439+ ( * SPAN_TRACK ) ( old_parent) ;
440+ }
441+ data. with_parent ( parent)
442+ }
443+
444+ #[ inline]
445+ pub fn parent ( self ) -> Option < LocalDefId > {
446+ let interned_parent =
447+ |index : u32 | with_span_interner ( |interner| interner. spans [ index as usize ] . parent ) ;
448+ let parent = match_span_kind ! {
449+ self ,
450+ InlineCtxt ( _span) => return None ,
451+ InlineParent ( span) => Some ( LocalDefId { local_def_index: DefIndex :: from_u32( span. parent as u32 ) } ) ,
452+ PartiallyInterned ( span) => interned_parent( span. index) ,
453+ Interned ( span) => interned_parent( span. index) ,
454+ } ;
455+ if let Some ( parent) = parent {
456+ // FIXME: Is this tracking necessary?
457+ ( * SPAN_TRACK ) ( parent) ;
458+ }
459+ parent
460+ }
404461}
405462
406463#[ derive( Default ) ]
0 commit comments