Skip to main content

rustc_span/
span_encoding.rs

1use std::cmp::Ordering;
2use std::hash::Hash;
3
4use rustc_data_structures::fx::FxIndexSet;
5use rustc_data_structures::stable_hash::RawSpan;
6// This code is very hot and uses lots of arithmetic, avoid overflow checks for performance.
7// See https://github.com/rust-lang/rust/pull/119440#issuecomment-1874255727
8use rustc_serialize::int_overflow::DebugStrictAdd;
9
10use crate::def_id::{DefIndex, LocalDefId};
11use crate::hygiene::SyntaxContext;
12use crate::{BytePos, SPAN_TRACK, SpanData};
13
14/// A compressed span.
15///
16/// [`SpanData`] is 16 bytes, which is too big to stick everywhere. `Span` is
17/// only 8 bytes. A large majority of `SpanData` instances can be made to fit
18/// within those 8 bytes. Any `SpanData` whose fields don't fit into a `Span`
19/// are stored in a separate interner table, and the `Span` will index into
20/// that table.
21///
22/// An earlier version of this code used only 4 bytes for `Span`, but that was
23/// slower because many fewer spans could be stored inline and the interner was
24/// used a lot more. That version of the code also predated the storage of
25/// parents.
26///
27/// Experiments with uncompressed spans yielded worse performance in most cases
28/// because memory usage and cache miss rates are significantly higher without
29/// compression.
30///
31/// There are four different span formats and each packs data into the 8 bytes
32/// in a different way. A variable-length prefix in the high bits identifies
33/// which format is being used. It is an invariant that we always use the first
34/// listed format whose requirements are satisfied. `len` is `hi - lo`.
35///
36/// - Inline-context format (requires 15-bit length, 16-bit context, and no parent):
37///
38///     `[ prefix=0 | len:15 | ctxt:16 | lo:32 ]`
39///
40/// - Inline-parent format (requires 14-bit length, root context, and 15-bit parent):
41///
42///     `[ prefix=110 | len:14 | parent:15 | lo:32 ]`
43///
44/// - Inline-pair format (requires 24-bit lo, 7-bit length, 15-bit context, 16-bit parent):
45///
46///     `[ prefix=10 | len:7 | ctxt:15 | parent:16 | lo:24 ]`
47///
48/// - Interned format (all cases not covered above):
49///
50///     `[ prefix=111 | ctxt:29 | index:32 ]`
51///
52/// Notes about this design.
53///
54/// - This configuration was the best one found after many measurements of
55///   real-world crates, and replaced an earlier 8-byte design.
56///
57/// - The size of `lo` depends on the size of the crate and its dependencies.
58///   Crates whose `lo` size exceeds 24-bits are extremely rare.
59///
60/// - The most common numbers of bits needed for `len` are from 0 to 7,
61///   with a peak usually at 3 or 4, and then it drops off quickly from 8
62///   onwards. Lengths larger than 14 bits are rare, but many crates will have
63///   a small number of such lengths (sometimes 20+ bits).
64///
65/// - The number of bits needed for `ctxt` and `parent` values depend partly on
66///   the crate size and partly on the form of the code. For both fields,
67///   values needing more than 15 bits are very rare, and most crates won't hit
68///   these limits.
69///
70/// - The ctxt is stored inline in every format (Every ctxt must fit in
71///   29 bits; if we ever hit that we'd have many gigabytes of contexts, and
72///   certainly would have OOM'd anyway.) This means reading the ctxt never
73///   requires checking the interner. This is good because the ctxt is often
74///   consulted by itself. It also means we don't need to store the ctxt in the
75///   interner table, which we achieve by using `SpanDataNoCtxt`, which
76///   minimizes the number of unique values that need to be interned.
77///
78/// - The use of `repr(packed(4))` means `Span` has an alignment of 4 bytes,
79///   which keeps many types that contain spans (e.g. AST nodes) smaller.
80///   `repr(packed(1))` isn't worth it; it only shrinks a few types and
81///   performance is a tiny bit worse.
82///
83/// In order to reliably use parented spans in incremental compilation,
84/// accesses to `lo` and `hi` must introduce a dependency to the parent definition's span.
85/// This is performed using the callback `SPAN_TRACK` to access the query engine.
86#[derive(#[automatically_derived]
#[doc(hidden)]
unsafe impl ::core::clone::TrivialClone for Span { }
#[automatically_derived]
impl ::core::clone::Clone for Span {
    #[inline]
    fn clone(&self) -> Self {
        let _: ::core::clone::AssertParamIsClone<u64>;
        *self
    }
}Clone, #[automatically_derived]
impl ::core::marker::Copy for Span { }Copy, #[automatically_derived]
impl ::core::cmp::Eq for Span {
    #[inline]
    #[doc(hidden)]
    #[coverage(off)]
    fn assert_fields_are_eq(&self) {
        let _: ::core::cmp::AssertParamIsEq<u64>;
    }
}Eq, #[automatically_derived]
impl ::core::marker::StructuralPartialEq for Span { }
#[automatically_derived]
impl ::core::cmp::PartialEq for Span {
    #[inline]
    fn eq(&self, other: &Self) -> bool { ({ self.0 }) == ({ other.0 }) }
}PartialEq, #[automatically_derived]
impl ::core::hash::Hash for Span {
    #[inline]
    fn hash<__H: ::core::hash::Hasher>(&self, state: &mut __H) {
        ::core::hash::Hash::hash(&{ self.0 }, state)
    }
}Hash)]
87#[rustc_pass_by_value]
88#[repr(packed(4))]
89pub struct Span(u64);
90
91// `SyntaxContext` (`SpanData::ctxt`) and `LocalDefId` (within `SpanData::parent`) aren't orderable.
92// If you want to order spans just on `lo`/`hi`, use explicit comparisons involving `Span::lo_hi`.
93// Or you can wrap your span within `OrdSpan` which impls `PartialOrd`/`Ord` via `Span::lo_hi`.
94impl !PartialOrd for Span {}
95impl !Ord for Span {}
96
97/// Specifies a field within one of the span formats. Provides const operations that (a) let a span
98/// format be fully specified, and (b) check/read/write the field for/from/to a span.
99#[derive(#[automatically_derived]
impl ::core::marker::Copy for SpanField { }Copy, #[automatically_derived]
#[doc(hidden)]
unsafe impl ::core::clone::TrivialClone for SpanField { }
#[automatically_derived]
impl ::core::clone::Clone for SpanField {
    #[inline]
    fn clone(&self) -> Self {
        let _: ::core::clone::AssertParamIsClone<u32>;
        *self
    }
}Clone)]
100struct SpanField {
101    /// The field's bit position, where zero means it's in the lowest bits.
102    shift: u32,
103    /// The field's width, in bits.
104    width: u32,
105}
106
107impl SpanField {
108    /// Specifies the top field, i.e. the highest bits. Chained with `below`.
109    #[inline]
110    const fn top(width: u32) -> Self {
111        SpanField { shift: 64 - width, width }
112    }
113
114    /// Specifies a field that comes below the field in `self`. Chainable.
115    #[inline]
116    const fn below(self, width: u32) -> Self {
117        SpanField { shift: self.shift - width, width }
118    }
119
120    /// The mask for the (downshifted to 0..n) field.
121    #[inline]
122    const fn mask(self) -> u64 {
123        (1 << self.width) - 1
124    }
125
126    /// Gets the field from a span-as-`u64` as a `u32`.
127    #[inline]
128    const fn get(self, u: u64) -> u32 {
129        ((u >> self.shift) & self.mask()) as u32
130    }
131
132    /// Sets the field to `v` in an otherwise-zero span-as-`u64`.
133    #[inline]
134    const fn set(self, v: u32) -> u64 {
135        if true {
    if !(v <= self.mask() as u32) {
        ::core::panicking::panic("assertion failed: v <= self.mask() as u32")
    };
};debug_assert!(v <= self.mask() as u32);
136        (v as u64) << self.shift
137    }
138
139    /// Returns non-zero if `v` is too big to fit in the field.
140    #[inline]
141    const fn too_big(self, v: u32) -> u32 {
142        v & !(self.mask() as u32)
143    }
144
145    /// Asserts that a field uses the bottom-most bits.
146    #[inline]
147    const fn assert_is_bottom(self) {
148        if !(self.shift == 0) {
    ::core::panicking::panic("assertion failed: self.shift == 0")
};assert!(self.shift == 0);
149    }
150}
151
152// Convenience structures for all span formats.
153#[derive(#[automatically_derived]
#[doc(hidden)]
unsafe impl ::core::clone::TrivialClone for InlineCtxt { }
#[automatically_derived]
impl ::core::clone::Clone for InlineCtxt {
    #[inline]
    fn clone(&self) -> Self {
        let _: ::core::clone::AssertParamIsClone<u32>;
        *self
    }
}Clone, #[automatically_derived]
impl ::core::marker::Copy for InlineCtxt { }Copy)]
154struct InlineCtxt {
155    lo: u32,
156    len: u32,
157    ctxt: u32,
158}
159
160#[derive(#[automatically_derived]
#[doc(hidden)]
unsafe impl ::core::clone::TrivialClone for InlineParent { }
#[automatically_derived]
impl ::core::clone::Clone for InlineParent {
    #[inline]
    fn clone(&self) -> Self {
        let _: ::core::clone::AssertParamIsClone<u32>;
        *self
    }
}Clone, #[automatically_derived]
impl ::core::marker::Copy for InlineParent { }Copy)]
161struct InlineParent {
162    lo: u32,
163    len: u32,
164    parent: u32,
165}
166
167#[derive(#[automatically_derived]
#[doc(hidden)]
unsafe impl ::core::clone::TrivialClone for InlinePair { }
#[automatically_derived]
impl ::core::clone::Clone for InlinePair {
    #[inline]
    fn clone(&self) -> Self {
        let _: ::core::clone::AssertParamIsClone<u32>;
        *self
    }
}Clone, #[automatically_derived]
impl ::core::marker::Copy for InlinePair { }Copy)]
168struct InlinePair {
169    lo: u32,
170    len: u32,
171    ctxt: u32,
172    parent: u32,
173}
174
175#[derive(#[automatically_derived]
#[doc(hidden)]
unsafe impl ::core::clone::TrivialClone for Interned { }
#[automatically_derived]
impl ::core::clone::Clone for Interned {
    #[inline]
    fn clone(&self) -> Self {
        let _: ::core::clone::AssertParamIsClone<u32>;
        *self
    }
}Clone, #[automatically_derived]
impl ::core::marker::Copy for Interned { }Copy)]
176struct Interned {
177    ctxt: u32,
178    index: u32,
179}
180
181impl InlineCtxt {
182    const PREFIX_VALUE: u32 = 0b0;
183    const PREFIX: SpanField = SpanField::top(1);
184    const LEN: SpanField = Self::PREFIX.below(15);
185    const CTXT: SpanField = Self::LEN.below(16);
186    const LO: SpanField = Self::CTXT.below(32);
187
188    #[inline]
189    const fn try_new_span(lo: u32, len: u32, ctxt: u32) -> Option<Span> {
190        if Self::LEN.too_big(len) | Self::CTXT.too_big(ctxt) == 0 {
191            Some(Span(
192                Self::PREFIX.set(Self::PREFIX_VALUE)
193                    | Self::LEN.set(len)
194                    | Self::CTXT.set(ctxt)
195                    | Self::LO.set(lo),
196            ))
197        } else {
198            None
199        }
200    }
201
202    #[inline]
203    fn data(self) -> SpanData {
204        SpanData {
205            lo: BytePos(self.lo),
206            hi: BytePos(self.lo.debug_strict_add(self.len)),
207            ctxt: SyntaxContext::from_u32(self.ctxt),
208            parent: None,
209        }
210    }
211
212    #[inline]
213    fn from_span(span: Span) -> InlineCtxt {
214        let u = span.0;
215        Self { lo: Self::LO.get(u), len: Self::LEN.get(u), ctxt: Self::CTXT.get(u) }
216    }
217}
218const _: () = InlineCtxt::LO.assert_is_bottom();
219
220impl InlineParent {
221    const PREFIX_VALUE: u32 = 0b110;
222    const PREFIX: SpanField = SpanField::top(3);
223    const LEN: SpanField = Self::PREFIX.below(14);
224    const PARENT: SpanField = Self::LEN.below(15);
225    const LO: SpanField = Self::PARENT.below(32);
226
227    #[inline]
228    fn try_new_span(lo: u32, len: u32, ctxt: u32, parent: u32) -> Option<Span> {
229        if Self::LEN.too_big(len) | ctxt | Self::PARENT.too_big(parent) == 0 {
230            Some(Span(
231                Self::PREFIX.set(Self::PREFIX_VALUE)
232                    | Self::LEN.set(len)
233                    | Self::PARENT.set(parent)
234                    | Self::LO.set(lo),
235            ))
236        } else {
237            None
238        }
239    }
240
241    #[inline]
242    fn data(self) -> SpanData {
243        SpanData {
244            lo: BytePos(self.lo),
245            hi: BytePos(self.lo.debug_strict_add(self.len)),
246            ctxt: SyntaxContext::root(),
247            parent: Some(LocalDefId { local_def_index: DefIndex::from_u32(self.parent) }),
248        }
249    }
250
251    #[inline]
252    fn from_span(span: Span) -> InlineParent {
253        let u = span.0;
254        Self { lo: Self::LO.get(u), len: Self::LEN.get(u), parent: Self::PARENT.get(u) }
255    }
256}
257const _: () = InlineParent::LO.assert_is_bottom();
258
259impl InlinePair {
260    const PREFIX_VALUE: u32 = 0b10;
261    const PREFIX: SpanField = SpanField::top(2);
262    const LEN: SpanField = Self::PREFIX.below(7);
263    const CTXT: SpanField = Self::LEN.below(15);
264    const PARENT: SpanField = Self::CTXT.below(16);
265    const LO: SpanField = Self::PARENT.below(24);
266
267    #[inline]
268    fn try_new_span(lo: u32, len: u32, ctxt: u32, parent: u32) -> Option<Span> {
269        if Self::LO.too_big(lo)
270            | Self::LEN.too_big(len)
271            | Self::CTXT.too_big(ctxt)
272            | Self::PARENT.too_big(parent)
273            == 0
274        {
275            Some(Span(
276                Self::PREFIX.set(Self::PREFIX_VALUE)
277                    | Self::LEN.set(len)
278                    | Self::CTXT.set(ctxt)
279                    | Self::PARENT.set(parent)
280                    | Self::LO.set(lo),
281            ))
282        } else {
283            None
284        }
285    }
286
287    #[inline]
288    fn data(self) -> SpanData {
289        SpanData {
290            lo: BytePos(self.lo),
291            hi: BytePos(self.lo.debug_strict_add(self.len)),
292            ctxt: SyntaxContext::from_u32(self.ctxt),
293            parent: Some(LocalDefId { local_def_index: DefIndex::from_u32(self.parent) }),
294        }
295    }
296
297    #[inline]
298    fn from_span(span: Span) -> InlinePair {
299        let u = span.0;
300        Self {
301            lo: Self::LO.get(u),
302            len: Self::LEN.get(u),
303            ctxt: Self::CTXT.get(u),
304            parent: Self::PARENT.get(u),
305        }
306    }
307}
308const _: () = InlinePair::LO.assert_is_bottom();
309
310impl Interned {
311    const PREFIX_VALUE: u32 = 0b111;
312    const PREFIX: SpanField = SpanField::top(3);
313    const CTXT: SpanField = Self::PREFIX.below(29);
314    const INDEX: SpanField = Self::CTXT.below(32);
315
316    #[inline]
317    fn new_span(ctxt: u32, index: u32) -> Span {
318        Span(Self::PREFIX.set(Self::PREFIX_VALUE) | Self::CTXT.set(ctxt) | Self::INDEX.set(index))
319    }
320
321    #[inline]
322    fn data(self) -> SpanData {
323        let SpanDataNoCtxt { lo, hi, parent } =
324            with_span_interner(|interner| interner.spans[self.index as usize]);
325        SpanData { lo, hi, ctxt: SyntaxContext::from_u32(self.ctxt), parent }
326    }
327
328    #[inline]
329    fn from_span(span: Span) -> Interned {
330        let u = span.0;
331        Self { ctxt: Self::CTXT.get(u), index: Self::INDEX.get(u) }
332    }
333}
334const _: () = Interned::INDEX.assert_is_bottom();
335
336// This code is very hot, and converting span to an enum and matching on it doesn't optimize away
337// properly. So we are using a macro emulating such a match, but expand it directly to an if-else
338// chain.
339macro_rules! match_span_kind {
340    (
341        $span:expr,
342        InlineCtxt($span1:ident) => $arm1:expr,
343        InlineParent($span2:ident) => $arm2:expr,
344        InlinePair($span3:ident) => $arm3:expr,
345        Interned($span4:ident) => $arm4:expr,
346    ) => {{
347        let span64 = $span.0;
348        if InlineCtxt::PREFIX.get(span64) == InlineCtxt::PREFIX_VALUE {
349            let $span1 = InlineCtxt::from_span($span);
350            $arm1
351        } else if InlineParent::PREFIX.get(span64) == InlineParent::PREFIX_VALUE {
352            let $span2 = InlineParent::from_span($span);
353            $arm2
354        } else if InlinePair::PREFIX.get(span64) == InlinePair::PREFIX_VALUE {
355            let $span3 = InlinePair::from_span($span);
356            $arm3
357        } else {
358            let $span4 = Interned::from_span($span);
359            $arm4
360        }
361    }};
362}
363
364/// The dummy span has zero position, length, and context, and no parent.
365pub const DUMMY_SP: Span = InlineCtxt::try_new_span(0, 0, 0).unwrap();
366
367impl Span {
368    #[inline]
369    pub fn new(
370        mut lo: BytePos,
371        mut hi: BytePos,
372        ctxt: SyntaxContext,
373        parent: Option<LocalDefId>,
374    ) -> Self {
375        #[cold]
376        #[inline(never)]
377        fn interned(lo: BytePos, hi: BytePos, ctxt: u32, parent: Option<LocalDefId>) -> Span {
378            // Interned.
379            {
    match (&Interned::CTXT.too_big(ctxt), &0) {
        (left_val, right_val) => {
            if !(*left_val == *right_val) {
                let kind = ::core::panicking::AssertKind::Eq;
                ::core::panicking::assert_failed(kind, &*left_val,
                    &*right_val, ::core::option::Option::None);
            }
        }
    }
};assert_eq!(Interned::CTXT.too_big(ctxt), 0); // this is a hard limit, with no fallback
380            let index =
381                with_span_interner(|interner| interner.intern(&SpanDataNoCtxt { lo, hi, parent }));
382            Interned::new_span(ctxt, index)
383        }
384
385        if lo > hi {
386            std::mem::swap(&mut lo, &mut hi);
387        }
388
389        let lo32 = lo.0;
390        let (len, ctxt32) = (hi.0 - lo32, ctxt.as_u32());
391        if let Some(parent) = parent {
392            if let Some(span) = Span::try_new_span_with_parent(lo32, len, ctxt32, parent) {
393                // InlineParent or InlinePair.
394                return span;
395            }
396        } else if let Some(span) = InlineCtxt::try_new_span(lo32, len, ctxt32) {
397            // InlineCtxt.
398            return span;
399        }
400
401        interned(lo, hi, ctxt32, parent)
402    }
403
404    /// Tries to create an `InlineParent` or `InlinePair` format span. Returns `None` if the fields
405    /// won't fit.
406    #[inline]
407    fn try_new_span_with_parent(lo: u32, len: u32, ctxt: u32, parent: LocalDefId) -> Option<Self> {
408        let parent = parent.local_def_index.as_u32();
409        InlineParent::try_new_span(lo, len, ctxt, parent)
410            .or_else(|| InlinePair::try_new_span(lo, len, ctxt, parent))
411    }
412
413    #[inline]
414    pub fn data(self) -> SpanData {
415        let data = self.data_untracked();
416        if let Some(parent) = data.parent {
417            (*SPAN_TRACK)(parent);
418        }
419        data
420    }
421
422    /// Internal function to translate between an encoded span and the expanded representation.
423    /// This function must not be used outside the incremental engine.
424    #[inline]
425    pub fn data_untracked(self) -> SpanData {
426        {
    let span64 = self.0;
    if InlineCtxt::PREFIX.get(span64) == InlineCtxt::PREFIX_VALUE {
        let span = InlineCtxt::from_span(self);
        span.data()
    } else if InlineParent::PREFIX.get(span64) == InlineParent::PREFIX_VALUE {
        let span = InlineParent::from_span(self);
        span.data()
    } else if InlinePair::PREFIX.get(span64) == InlinePair::PREFIX_VALUE {
        let span = InlinePair::from_span(self);
        span.data()
    } else { let span = Interned::from_span(self); span.data() }
}match_span_kind! {
427            self,
428            InlineCtxt(span) => span.data(),
429            InlineParent(span) => span.data(),
430            InlinePair(span) => span.data(),
431            Interned(span) => span.data(),
432        }
433    }
434
435    /// Returns `true` if this span comes from any kind of macro, desugaring or inlining.
436    #[inline]
437    pub fn from_expansion(self) -> bool {
438        !self.ctxt().is_root()
439    }
440
441    /// Returns `true` if this is a dummy span with lo=0, hi=0. Any context value is allowed, which
442    /// means it's not the same as an equality comparison with `DUMMY_SP`.
443    #[inline]
444    pub fn is_dummy(self) -> bool {
445        {
    let span64 = self.0;
    if InlineCtxt::PREFIX.get(span64) == InlineCtxt::PREFIX_VALUE {
        let span = InlineCtxt::from_span(self);
        span.lo == 0 && span.len == 0
    } else if InlineParent::PREFIX.get(span64) == InlineParent::PREFIX_VALUE {
        let span = InlineParent::from_span(self);
        span.lo == 0 && span.len == 0
    } else if InlinePair::PREFIX.get(span64) == InlinePair::PREFIX_VALUE {
        let span = InlinePair::from_span(self);
        span.lo == 0 && span.len == 0
    } else {
        let span = Interned::from_span(self);
        {
            let data =
                with_span_interner(|interner|
                        interner.spans[span.index as usize]);
            data.lo == BytePos(0) && data.hi == BytePos(0)
        }
    }
}match_span_kind! {
446            self,
447            InlineCtxt(span) => span.lo == 0 && span.len == 0,
448            InlineParent(span) => span.lo == 0 && span.len == 0,
449            InlinePair(span) => span.lo == 0 && span.len == 0,
450            Interned(span) => {
451                let data = with_span_interner(|interner| interner.spans[span.index as usize]);
452                data.lo == BytePos(0) && data.hi == BytePos(0)
453            },
454        }
455    }
456
457    #[inline]
458    pub fn map_ctxt(self, map: impl FnOnce(SyntaxContext) -> SyntaxContext) -> Span {
459        let data = {
    let span64 = self.0;
    if InlineCtxt::PREFIX.get(span64) == InlineCtxt::PREFIX_VALUE {
        let span = InlineCtxt::from_span(self);
        {
            let new_ctxt = map(SyntaxContext::from_u32(span.ctxt));
            let new_ctxt32 = new_ctxt.as_u32();
            return if let Some(span) =
                        InlineCtxt::try_new_span(span.lo, span.len, new_ctxt32) {
                    span
                } else { span.data().with_ctxt(new_ctxt) };
        }
    } else if InlineParent::PREFIX.get(span64) == InlineParent::PREFIX_VALUE {
        let span = InlineParent::from_span(self);
        span.data()
    } else if InlinePair::PREFIX.get(span64) == InlinePair::PREFIX_VALUE {
        let span = InlinePair::from_span(self);
        span.data()
    } else { let span = Interned::from_span(self); span.data() }
}match_span_kind! {
460            self,
461            InlineCtxt(span) => {
462                // This format occurs 1-2 orders of magnitude more often than others (#125017),
463                // so it makes sense to micro-optimize it to avoid `span.data()` and `Span::new()`.
464                let new_ctxt = map(SyntaxContext::from_u32(span.ctxt));
465                let new_ctxt32 = new_ctxt.as_u32();
466                return if let Some(span) = InlineCtxt::try_new_span(span.lo, span.len, new_ctxt32) {
467                    span
468                } else {
469                    span.data().with_ctxt(new_ctxt)
470                };
471            },
472            InlineParent(span) => span.data(),
473            InlinePair(span) => span.data(),
474            Interned(span) => span.data(),
475        };
476
477        data.with_ctxt(map(data.ctxt))
478    }
479
480    /// This function is used as a fast path when decoding the full `SpanData` is not necessary.
481    /// It's a cut-down version of `data_untracked` and doesn't require taking the interner lock.
482    #[inline]
483    pub fn ctxt(self) -> SyntaxContext {
484        let ctxt32 = {
    let span64 = self.0;
    if InlineCtxt::PREFIX.get(span64) == InlineCtxt::PREFIX_VALUE {
        let span = InlineCtxt::from_span(self);
        span.ctxt
    } else if InlineParent::PREFIX.get(span64) == InlineParent::PREFIX_VALUE {
        let _span = InlineParent::from_span(self);
        return SyntaxContext::root()
    } else if InlinePair::PREFIX.get(span64) == InlinePair::PREFIX_VALUE {
        let span = InlinePair::from_span(self);
        span.ctxt
    } else { let span = Interned::from_span(self); span.ctxt }
}match_span_kind! {
485            self,
486            InlineCtxt(span) => span.ctxt,
487            InlineParent(_span) => return SyntaxContext::root(),
488            InlinePair(span) => span.ctxt,
489            Interned(span) => span.ctxt,
490        };
491        SyntaxContext::from_u32(ctxt32)
492    }
493
494    // With the pre-#163857 span representation this method was more complex and required. Now it's
495    // trivial but it hasn't been removed simply to avoid churn.
496    #[inline]
497    pub fn eq_ctxt(self, other: Span) -> bool {
498        self.ctxt() == other.ctxt()
499    }
500
501    #[inline]
502    pub fn with_parent(self, parent: Option<LocalDefId>) -> Span {
503        let data = {
    let span64 = self.0;
    if InlineCtxt::PREFIX.get(span64) == InlineCtxt::PREFIX_VALUE {
        let span = InlineCtxt::from_span(self);
        {
            match parent {
                None => return self,
                Some(parent) if
                    let Some(span) =
                        Span::try_new_span_with_parent(span.lo, span.len, span.ctxt,
                            parent) => {
                    return span;
                }
                _ => span.data(),
            }
        }
    } else if InlineParent::PREFIX.get(span64) == InlineParent::PREFIX_VALUE {
        let span = InlineParent::from_span(self);
        span.data()
    } else if InlinePair::PREFIX.get(span64) == InlinePair::PREFIX_VALUE {
        let span = InlinePair::from_span(self);
        span.data()
    } else { let span = Interned::from_span(self); span.data() }
}match_span_kind! {
504            self,
505            InlineCtxt(span) => {
506                // This format occurs 1-2 orders of magnitude more often than others (#126544),
507                // so it makes sense to micro-optimize it to avoid `span.data()`.
508                match parent {
509                    None => return self,
510                    Some(parent)
511                        if let Some(span) =
512                            Span::try_new_span_with_parent(span.lo, span.len, span.ctxt, parent) =>
513                    {
514                        return span;
515                    }
516                    _ => span.data(),
517                }
518            },
519            InlineParent(span) => span.data(),
520            InlinePair(span) => span.data(),
521            Interned(span) => span.data(),
522        };
523
524        if let Some(old_parent) = data.parent {
525            (*SPAN_TRACK)(old_parent);
526        }
527        data.with_parent(parent)
528    }
529
530    #[inline]
531    pub fn parent(self) -> Option<LocalDefId> {
532        let to_parent = |parent| Some(LocalDefId { local_def_index: DefIndex::from_u32(parent) });
533        {
    let span64 = self.0;
    if InlineCtxt::PREFIX.get(span64) == InlineCtxt::PREFIX_VALUE {
        let _span = InlineCtxt::from_span(self);
        None
    } else if InlineParent::PREFIX.get(span64) == InlineParent::PREFIX_VALUE {
        let span = InlineParent::from_span(self);
        to_parent(span.parent)
    } else if InlinePair::PREFIX.get(span64) == InlinePair::PREFIX_VALUE {
        let span = InlinePair::from_span(self);
        to_parent(span.parent)
    } else {
        let span = Interned::from_span(self);
        {
            with_span_interner(|interner|
                    interner.spans[span.index as usize].parent)
        }
    }
}match_span_kind! {
534            self,
535            InlineCtxt(_span) => None,
536            InlineParent(span) => to_parent(span.parent),
537            InlinePair(span) => to_parent(span.parent),
538            Interned(span) => {
539                with_span_interner(|interner| interner.spans[span.index as usize].parent)
540            },
541        }
542    }
543
544    #[inline]
545    pub(crate) fn to_raw_span(self) -> RawSpan {
546        RawSpan(self.0)
547    }
548
549    #[inline]
550    pub fn from_raw_span(RawSpan(a): RawSpan) -> Span {
551        Span(a)
552    }
553}
554
555/// Span wrapper that provides equality and ordering based only on the `lo`/`hi` fields. Exists
556/// because `Span` doesn't impl `PartialOrd`/`Ord` due to the `ctxt` and `parent` fields being
557/// unorderable. Useful when storing things in source code order, e.g. in a `BTreeMap<OrdSpan, T>`.
558#[derive(#[automatically_derived]
#[doc(hidden)]
unsafe impl ::core::clone::TrivialClone for OrdSpan { }
#[automatically_derived]
impl ::core::clone::Clone for OrdSpan {
    #[inline]
    fn clone(&self) -> Self {
        let _: ::core::clone::AssertParamIsClone<Span>;
        *self
    }
}Clone, #[automatically_derived]
impl ::core::marker::Copy for OrdSpan { }Copy, #[automatically_derived]
impl ::core::fmt::Debug for OrdSpan {
    #[inline]
    fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
        ::core::fmt::Formatter::debug_tuple_field1_finish(f, "OrdSpan",
            &&self.0)
    }
}Debug)]
559pub struct OrdSpan(pub Span);
560
561impl PartialEq for OrdSpan {
562    fn eq(&self, rhs: &Self) -> bool {
563        // Ignores `ctxt` and `parent` because they are unorderable.
564        self.0.lo_hi() == rhs.0.lo_hi()
565    }
566}
567
568impl Eq for OrdSpan {}
569
570impl PartialOrd for OrdSpan {
571    fn partial_cmp(&self, rhs: &Self) -> Option<Ordering> {
572        Some(self.cmp(rhs))
573    }
574}
575
576impl Ord for OrdSpan {
577    fn cmp(&self, rhs: &Self) -> Ordering {
578        // Ignores `ctxt` and `parent` because they are unorderable.
579        self.0.lo_hi().cmp(&rhs.0.lo_hi())
580    }
581}
582
583// `OrdSpan` is typically stored in types that rely on ordering, such as `BTreeMap` or `SortedMap`.
584// Hashing shouldn't be necessary.
585impl !Hash for OrdSpan {}
586
587/// `SpanData` minus the `ctxt` field. This is what we actually intern, because we can always store
588/// ctxt inline in `Span`.
589#[derive(#[automatically_derived]
#[doc(hidden)]
unsafe impl ::core::clone::TrivialClone for SpanDataNoCtxt { }
#[automatically_derived]
impl ::core::clone::Clone for SpanDataNoCtxt {
    #[inline]
    fn clone(&self) -> Self {
        let _: ::core::clone::AssertParamIsClone<BytePos>;
        let _: ::core::clone::AssertParamIsClone<Option<LocalDefId>>;
        *self
    }
}Clone, #[automatically_derived]
impl ::core::marker::Copy for SpanDataNoCtxt { }Copy, #[automatically_derived]
impl ::core::hash::Hash for SpanDataNoCtxt {
    #[inline]
    fn hash<__H: ::core::hash::Hasher>(&self, state: &mut __H) {
        ::core::hash::Hash::hash(&self.lo, state);
        ::core::hash::Hash::hash(&self.hi, state);
        ::core::hash::Hash::hash(&self.parent, state)
    }
}Hash, #[automatically_derived]
impl ::core::marker::StructuralPartialEq for SpanDataNoCtxt { }
#[automatically_derived]
impl ::core::cmp::PartialEq for SpanDataNoCtxt {
    #[inline]
    fn eq(&self, other: &Self) -> bool {
        self.lo == other.lo && self.hi == other.hi &&
            self.parent == other.parent
    }
}PartialEq, #[automatically_derived]
impl ::core::cmp::Eq for SpanDataNoCtxt {
    #[inline]
    #[doc(hidden)]
    #[coverage(off)]
    fn assert_fields_are_eq(&self) {
        let _: ::core::cmp::AssertParamIsEq<BytePos>;
        let _: ::core::cmp::AssertParamIsEq<Option<LocalDefId>>;
    }
}Eq)]
590struct SpanDataNoCtxt {
591    lo: BytePos,
592    hi: BytePos,
593    parent: Option<LocalDefId>,
594}
595
596#[derive(#[automatically_derived]
impl ::core::default::Default for SpanInterner {
    #[inline]
    fn default() -> Self {
        SpanInterner { spans: ::core::default::Default::default() }
    }
}Default)]
597pub(crate) struct SpanInterner {
598    spans: FxIndexSet<SpanDataNoCtxt>,
599}
600
601impl SpanInterner {
602    fn intern(&mut self, span_data_no_ctxt: &SpanDataNoCtxt) -> u32 {
603        let (index, _) = self.spans.insert_full(*span_data_no_ctxt);
604        index as u32
605    }
606}
607
608// If an interner exists, return it. Otherwise, prepare a fresh one.
609#[inline]
610fn with_span_interner<T, F: FnOnce(&mut SpanInterner) -> T>(f: F) -> T {
611    crate::with_session_globals(|session_globals| f(&mut session_globals.span_interner.lock()))
612}