@@ -136,13 +136,13 @@ impl Span {
136136 }
137137
138138 // Partially-interned or fully-interned format.
139- let index =
140- with_span_interner ( |interner| interner. intern ( & SpanData { lo, hi, ctxt, parent } ) ) ;
141- let ctxt_or_parent_or_marker = if ctxt2 <= MAX_CTXT {
142- ctxt2 as u16 // partially-interned
139+ let ( ctxt_or_parent_or_marker, ctxt) = if ctxt2 <= MAX_CTXT {
140+ ( ctxt2 as u16 , SyntaxContext :: from_u32 ( u32:: MAX ) ) // partially-interned
143141 } else {
144- CTXT_INTERNED_MARKER // fully-interned
142+ ( CTXT_INTERNED_MARKER , ctxt ) // fully-interned
145143 } ;
144+ let index =
145+ with_span_interner ( |interner| interner. intern ( & SpanData { lo, hi, ctxt, parent } ) ) ;
146146 Span {
147147 lo_or_index : index,
148148 len_with_tag_or_marker : BASE_LEN_INTERNED_MARKER ,
@@ -193,7 +193,11 @@ impl Span {
193193 // the interned value contains all the data, so we don't need to
194194 // distinguish them.
195195 let index = self . lo_or_index ;
196- with_span_interner ( |interner| interner. spans [ index as usize ] )
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
197201 }
198202 }
199203
@@ -236,6 +240,46 @@ impl Span {
236240 } )
237241 }
238242
243+ pub fn update_ctxt ( & mut self , update : impl FnOnce ( SyntaxContext ) -> SyntaxContext ) {
244+ let updated_ctxt32;
245+ 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 ( ) ;
251+ if updated_ctxt32 <= MAX_CTXT {
252+ self . ctxt_or_parent_or_marker = updated_ctxt32 as u16 ;
253+ return ;
254+ }
255+ } else {
256+ // Inline-parent format. We know that the SyntaxContext is root.
257+ updated_ctxt32 = update ( SyntaxContext :: root ( ) ) . as_u32 ( ) ;
258+ if updated_ctxt32 == 0 {
259+ // do nothing
260+ return ;
261+ }
262+ }
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 ;
273+ }
274+ data = self . data_untracked ( ) ;
275+ } else {
276+ data = self . data_untracked ( ) ;
277+ updated_ctxt32 = update ( data. ctxt ) . as_u32 ( ) ;
278+ } ;
279+
280+ * self = data. with_ctxt ( SyntaxContext :: from_u32 ( updated_ctxt32) ) ;
281+ }
282+
239283 /// This function is used as a fast path when decoding the full `SpanData` is not necessary.
240284 /// It's a cut-down version of `data_untracked`.
241285 #[ cfg_attr( not( test) , rustc_diagnostic_item = "SpanCtxt" ) ]
0 commit comments