rustc_span/
lib.rs

1//! Source positions and related helper functions.
2//!
3//! Important concepts in this module include:
4//!
5//! - the *span*, represented by [`SpanData`] and related types;
6//! - source code as represented by a [`SourceMap`]; and
7//! - interned strings, represented by [`Symbol`]s, with some common symbols available statically
8//!   in the [`sym`] module.
9//!
10//! Unlike most compilers, the span contains not only the position in the source code, but also
11//! various other metadata, such as the edition and macro hygiene. This metadata is stored in
12//! [`SyntaxContext`] and [`ExpnData`].
13//!
14//! ## Note
15//!
16//! This API is completely unstable and subject to change.
17
18// tidy-alphabetical-start
19#![allow(internal_features)]
20#![cfg_attr(bootstrap, feature(cfg_match))]
21#![cfg_attr(not(bootstrap), feature(cfg_select))]
22#![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")]
23#![doc(rust_logo)]
24#![feature(array_windows)]
25#![feature(core_io_borrowed_buf)]
26#![feature(if_let_guard)]
27#![feature(map_try_insert)]
28#![feature(negative_impls)]
29#![feature(read_buf)]
30#![feature(round_char_boundary)]
31#![feature(rustc_attrs)]
32#![feature(rustdoc_internals)]
33// tidy-alphabetical-end
34
35// The code produced by the `Encodable`/`Decodable` derive macros refer to
36// `rustc_span::Span{Encoder,Decoder}`. That's fine outside this crate, but doesn't work inside
37// this crate without this line making `rustc_span` available.
38extern crate self as rustc_span;
39
40use derive_where::derive_where;
41use rustc_data_structures::{AtomicRef, outline};
42use rustc_macros::{Decodable, Encodable, HashStable_Generic};
43use rustc_serialize::opaque::{FileEncoder, MemDecoder};
44use rustc_serialize::{Decodable, Decoder, Encodable, Encoder};
45use tracing::debug;
46
47mod caching_source_map_view;
48pub mod source_map;
49use source_map::{SourceMap, SourceMapInputs};
50
51pub use self::caching_source_map_view::CachingSourceMapView;
52use crate::fatal_error::FatalError;
53
54pub mod edition;
55use edition::Edition;
56pub mod hygiene;
57use hygiene::Transparency;
58pub use hygiene::{
59    DesugaringKind, ExpnData, ExpnHash, ExpnId, ExpnKind, LocalExpnId, MacroKind, SyntaxContext,
60};
61use rustc_data_structures::stable_hasher::HashingControls;
62pub mod def_id;
63use def_id::{CrateNum, DefId, DefIndex, DefPathHash, LOCAL_CRATE, LocalDefId, StableCrateId};
64pub mod edit_distance;
65mod span_encoding;
66pub use span_encoding::{DUMMY_SP, Span};
67
68pub mod symbol;
69pub use symbol::{Ident, MacroRulesNormalizedIdent, STDLIB_STABLE_CRATES, Symbol, kw, sym};
70
71mod analyze_source_file;
72pub mod fatal_error;
73
74pub mod profiling;
75
76use std::borrow::Cow;
77use std::cmp::{self, Ordering};
78use std::fmt::Display;
79use std::hash::Hash;
80use std::io::{self, Read};
81use std::ops::{Add, Range, Sub};
82use std::path::{Path, PathBuf};
83use std::str::FromStr;
84use std::sync::Arc;
85use std::{fmt, iter};
86
87use md5::{Digest, Md5};
88use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
89use rustc_data_structures::sync::{FreezeLock, FreezeWriteGuard, Lock};
90use rustc_data_structures::unord::UnordMap;
91use rustc_hashes::{Hash64, Hash128};
92use sha1::Sha1;
93use sha2::Sha256;
94
95#[cfg(test)]
96mod tests;
97
98/// Per-session global variables: this struct is stored in thread-local storage
99/// in such a way that it is accessible without any kind of handle to all
100/// threads within the compilation session, but is not accessible outside the
101/// session.
102pub struct SessionGlobals {
103    symbol_interner: symbol::Interner,
104    span_interner: Lock<span_encoding::SpanInterner>,
105    /// Maps a macro argument token into use of the corresponding metavariable in the macro body.
106    /// Collisions are possible and processed in `maybe_use_metavar_location` on best effort basis.
107    metavar_spans: MetavarSpansMap,
108    hygiene_data: Lock<hygiene::HygieneData>,
109
110    /// The session's source map, if there is one. This field should only be
111    /// used in places where the `Session` is truly not available, such as
112    /// `<Span as Debug>::fmt`.
113    source_map: Option<Arc<SourceMap>>,
114}
115
116impl SessionGlobals {
117    pub fn new(
118        edition: Edition,
119        extra_symbols: &[&'static str],
120        sm_inputs: Option<SourceMapInputs>,
121    ) -> SessionGlobals {
122        SessionGlobals {
123            symbol_interner: symbol::Interner::with_extra_symbols(extra_symbols),
124            span_interner: Lock::new(span_encoding::SpanInterner::default()),
125            metavar_spans: Default::default(),
126            hygiene_data: Lock::new(hygiene::HygieneData::new(edition)),
127            source_map: sm_inputs.map(|inputs| Arc::new(SourceMap::with_inputs(inputs))),
128        }
129    }
130}
131
132pub fn create_session_globals_then<R>(
133    edition: Edition,
134    extra_symbols: &[&'static str],
135    sm_inputs: Option<SourceMapInputs>,
136    f: impl FnOnce() -> R,
137) -> R {
138    assert!(
139        !SESSION_GLOBALS.is_set(),
140        "SESSION_GLOBALS should never be overwritten! \
141         Use another thread if you need another SessionGlobals"
142    );
143    let session_globals = SessionGlobals::new(edition, extra_symbols, sm_inputs);
144    SESSION_GLOBALS.set(&session_globals, f)
145}
146
147pub fn set_session_globals_then<R>(session_globals: &SessionGlobals, f: impl FnOnce() -> R) -> R {
148    assert!(
149        !SESSION_GLOBALS.is_set(),
150        "SESSION_GLOBALS should never be overwritten! \
151         Use another thread if you need another SessionGlobals"
152    );
153    SESSION_GLOBALS.set(session_globals, f)
154}
155
156/// No source map.
157pub fn create_session_if_not_set_then<R, F>(edition: Edition, f: F) -> R
158where
159    F: FnOnce(&SessionGlobals) -> R,
160{
161    if !SESSION_GLOBALS.is_set() {
162        let session_globals = SessionGlobals::new(edition, &[], None);
163        SESSION_GLOBALS.set(&session_globals, || SESSION_GLOBALS.with(f))
164    } else {
165        SESSION_GLOBALS.with(f)
166    }
167}
168
169pub fn with_session_globals<R, F>(f: F) -> R
170where
171    F: FnOnce(&SessionGlobals) -> R,
172{
173    SESSION_GLOBALS.with(f)
174}
175
176/// Default edition, no source map.
177pub fn create_default_session_globals_then<R>(f: impl FnOnce() -> R) -> R {
178    create_session_globals_then(edition::DEFAULT_EDITION, &[], None, f)
179}
180
181// If this ever becomes non thread-local, `decode_syntax_context`
182// and `decode_expn_id` will need to be updated to handle concurrent
183// deserialization.
184scoped_tls::scoped_thread_local!(static SESSION_GLOBALS: SessionGlobals);
185
186#[derive(Default)]
187pub struct MetavarSpansMap(FreezeLock<UnordMap<Span, (Span, bool)>>);
188
189impl MetavarSpansMap {
190    pub fn insert(&self, span: Span, var_span: Span) -> bool {
191        match self.0.write().try_insert(span, (var_span, false)) {
192            Ok(_) => true,
193            Err(entry) => entry.entry.get().0 == var_span,
194        }
195    }
196
197    /// Read a span and record that it was read.
198    pub fn get(&self, span: Span) -> Option<Span> {
199        if let Some(mut mspans) = self.0.try_write() {
200            if let Some((var_span, read)) = mspans.get_mut(&span) {
201                *read = true;
202                Some(*var_span)
203            } else {
204                None
205            }
206        } else {
207            if let Some((span, true)) = self.0.read().get(&span) { Some(*span) } else { None }
208        }
209    }
210
211    /// Freeze the set, and return the spans which have been read.
212    ///
213    /// After this is frozen, no spans that have not been read can be read.
214    pub fn freeze_and_get_read_spans(&self) -> UnordMap<Span, Span> {
215        self.0.freeze().items().filter(|(_, (_, b))| *b).map(|(s1, (s2, _))| (*s1, *s2)).collect()
216    }
217}
218
219#[inline]
220pub fn with_metavar_spans<R>(f: impl FnOnce(&MetavarSpansMap) -> R) -> R {
221    with_session_globals(|session_globals| f(&session_globals.metavar_spans))
222}
223
224// FIXME: We should use this enum or something like it to get rid of the
225// use of magic `/rust/1.x/...` paths across the board.
226#[derive(Debug, Eq, PartialEq, Clone, Ord, PartialOrd, Decodable, Encodable)]
227pub enum RealFileName {
228    LocalPath(PathBuf),
229    /// For remapped paths (namely paths into libstd that have been mapped
230    /// to the appropriate spot on the local host's file system, and local file
231    /// system paths that have been remapped with `FilePathMapping`),
232    Remapped {
233        /// `local_path` is the (host-dependent) local path to the file. This is
234        /// None if the file was imported from another crate
235        local_path: Option<PathBuf>,
236        /// `virtual_name` is the stable path rustc will store internally within
237        /// build artifacts.
238        virtual_name: PathBuf,
239    },
240}
241
242impl Hash for RealFileName {
243    fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
244        // To prevent #70924 from happening again we should only hash the
245        // remapped (virtualized) path if that exists. This is because
246        // virtualized paths to sysroot crates (/rust/$hash or /rust/$version)
247        // remain stable even if the corresponding local_path changes
248        self.remapped_path_if_available().hash(state)
249    }
250}
251
252impl RealFileName {
253    /// Returns the path suitable for reading from the file system on the local host,
254    /// if this information exists.
255    /// Avoid embedding this in build artifacts; see `remapped_path_if_available()` for that.
256    pub fn local_path(&self) -> Option<&Path> {
257        match self {
258            RealFileName::LocalPath(p) => Some(p),
259            RealFileName::Remapped { local_path, virtual_name: _ } => local_path.as_deref(),
260        }
261    }
262
263    /// Returns the path suitable for reading from the file system on the local host,
264    /// if this information exists.
265    /// Avoid embedding this in build artifacts; see `remapped_path_if_available()` for that.
266    pub fn into_local_path(self) -> Option<PathBuf> {
267        match self {
268            RealFileName::LocalPath(p) => Some(p),
269            RealFileName::Remapped { local_path: p, virtual_name: _ } => p,
270        }
271    }
272
273    /// Returns the path suitable for embedding into build artifacts. This would still
274    /// be a local path if it has not been remapped. A remapped path will not correspond
275    /// to a valid file system path: see `local_path_if_available()` for something that
276    /// is more likely to return paths into the local host file system.
277    pub fn remapped_path_if_available(&self) -> &Path {
278        match self {
279            RealFileName::LocalPath(p)
280            | RealFileName::Remapped { local_path: _, virtual_name: p } => p,
281        }
282    }
283
284    /// Returns the path suitable for reading from the file system on the local host,
285    /// if this information exists. Otherwise returns the remapped name.
286    /// Avoid embedding this in build artifacts; see `remapped_path_if_available()` for that.
287    pub fn local_path_if_available(&self) -> &Path {
288        match self {
289            RealFileName::LocalPath(path)
290            | RealFileName::Remapped { local_path: None, virtual_name: path }
291            | RealFileName::Remapped { local_path: Some(path), virtual_name: _ } => path,
292        }
293    }
294
295    /// Return the path remapped or not depending on the [`FileNameDisplayPreference`].
296    ///
297    /// For the purpose of this function, local and short preference are equal.
298    pub fn to_path(&self, display_pref: FileNameDisplayPreference) -> &Path {
299        match display_pref {
300            FileNameDisplayPreference::Local | FileNameDisplayPreference::Short => {
301                self.local_path_if_available()
302            }
303            FileNameDisplayPreference::Remapped => self.remapped_path_if_available(),
304        }
305    }
306
307    pub fn to_string_lossy(&self, display_pref: FileNameDisplayPreference) -> Cow<'_, str> {
308        match display_pref {
309            FileNameDisplayPreference::Local => self.local_path_if_available().to_string_lossy(),
310            FileNameDisplayPreference::Remapped => {
311                self.remapped_path_if_available().to_string_lossy()
312            }
313            FileNameDisplayPreference::Short => self
314                .local_path_if_available()
315                .file_name()
316                .map_or_else(|| "".into(), |f| f.to_string_lossy()),
317        }
318    }
319}
320
321/// Differentiates between real files and common virtual files.
322#[derive(Debug, Eq, PartialEq, Clone, Ord, PartialOrd, Hash, Decodable, Encodable)]
323pub enum FileName {
324    Real(RealFileName),
325    /// Strings provided as `--cfg [cfgspec]`.
326    CfgSpec(Hash64),
327    /// Command line.
328    Anon(Hash64),
329    /// Hack in `src/librustc_ast/parse.rs`.
330    // FIXME(jseyfried)
331    MacroExpansion(Hash64),
332    ProcMacroSourceCode(Hash64),
333    /// Strings provided as crate attributes in the CLI.
334    CliCrateAttr(Hash64),
335    /// Custom sources for explicit parser calls from plugins and drivers.
336    Custom(String),
337    DocTest(PathBuf, isize),
338    /// Post-substitution inline assembly from LLVM.
339    InlineAsm(Hash64),
340}
341
342impl From<PathBuf> for FileName {
343    fn from(p: PathBuf) -> Self {
344        FileName::Real(RealFileName::LocalPath(p))
345    }
346}
347
348#[derive(Clone, Copy, Eq, PartialEq, Hash, Debug)]
349pub enum FileNameEmbeddablePreference {
350    /// If a remapped path is available, only embed the `virtual_path` and omit the `local_path`.
351    ///
352    /// Otherwise embed the local-path into the `virtual_path`.
353    RemappedOnly,
354    /// Embed the original path as well as its remapped `virtual_path` component if available.
355    LocalAndRemapped,
356}
357
358#[derive(Clone, Copy, Eq, PartialEq, Hash, Debug)]
359pub enum FileNameDisplayPreference {
360    /// Display the path after the application of rewrite rules provided via `--remap-path-prefix`.
361    /// This is appropriate for paths that get embedded into files produced by the compiler.
362    Remapped,
363    /// Display the path before the application of rewrite rules provided via `--remap-path-prefix`.
364    /// This is appropriate for use in user-facing output (such as diagnostics).
365    Local,
366    /// Display only the filename, as a way to reduce the verbosity of the output.
367    /// This is appropriate for use in user-facing output (such as diagnostics).
368    Short,
369}
370
371pub struct FileNameDisplay<'a> {
372    inner: &'a FileName,
373    display_pref: FileNameDisplayPreference,
374}
375
376impl fmt::Display for FileNameDisplay<'_> {
377    fn fmt(&self, fmt: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
378        use FileName::*;
379        match *self.inner {
380            Real(ref name) => {
381                write!(fmt, "{}", name.to_string_lossy(self.display_pref))
382            }
383            CfgSpec(_) => write!(fmt, "<cfgspec>"),
384            MacroExpansion(_) => write!(fmt, "<macro expansion>"),
385            Anon(_) => write!(fmt, "<anon>"),
386            ProcMacroSourceCode(_) => write!(fmt, "<proc-macro source code>"),
387            CliCrateAttr(_) => write!(fmt, "<crate attribute>"),
388            Custom(ref s) => write!(fmt, "<{s}>"),
389            DocTest(ref path, _) => write!(fmt, "{}", path.display()),
390            InlineAsm(_) => write!(fmt, "<inline asm>"),
391        }
392    }
393}
394
395impl<'a> FileNameDisplay<'a> {
396    pub fn to_string_lossy(&self) -> Cow<'a, str> {
397        match self.inner {
398            FileName::Real(inner) => inner.to_string_lossy(self.display_pref),
399            _ => Cow::from(self.to_string()),
400        }
401    }
402}
403
404impl FileName {
405    pub fn is_real(&self) -> bool {
406        use FileName::*;
407        match *self {
408            Real(_) => true,
409            Anon(_)
410            | MacroExpansion(_)
411            | ProcMacroSourceCode(_)
412            | CliCrateAttr(_)
413            | Custom(_)
414            | CfgSpec(_)
415            | DocTest(_, _)
416            | InlineAsm(_) => false,
417        }
418    }
419
420    pub fn prefer_remapped_unconditionaly(&self) -> FileNameDisplay<'_> {
421        FileNameDisplay { inner: self, display_pref: FileNameDisplayPreference::Remapped }
422    }
423
424    /// This may include transient local filesystem information.
425    /// Must not be embedded in build outputs.
426    pub fn prefer_local(&self) -> FileNameDisplay<'_> {
427        FileNameDisplay { inner: self, display_pref: FileNameDisplayPreference::Local }
428    }
429
430    pub fn display(&self, display_pref: FileNameDisplayPreference) -> FileNameDisplay<'_> {
431        FileNameDisplay { inner: self, display_pref }
432    }
433
434    pub fn macro_expansion_source_code(src: &str) -> FileName {
435        let mut hasher = StableHasher::new();
436        src.hash(&mut hasher);
437        FileName::MacroExpansion(hasher.finish())
438    }
439
440    pub fn anon_source_code(src: &str) -> FileName {
441        let mut hasher = StableHasher::new();
442        src.hash(&mut hasher);
443        FileName::Anon(hasher.finish())
444    }
445
446    pub fn proc_macro_source_code(src: &str) -> FileName {
447        let mut hasher = StableHasher::new();
448        src.hash(&mut hasher);
449        FileName::ProcMacroSourceCode(hasher.finish())
450    }
451
452    pub fn cfg_spec_source_code(src: &str) -> FileName {
453        let mut hasher = StableHasher::new();
454        src.hash(&mut hasher);
455        FileName::CfgSpec(hasher.finish())
456    }
457
458    pub fn cli_crate_attr_source_code(src: &str) -> FileName {
459        let mut hasher = StableHasher::new();
460        src.hash(&mut hasher);
461        FileName::CliCrateAttr(hasher.finish())
462    }
463
464    pub fn doc_test_source_code(path: PathBuf, line: isize) -> FileName {
465        FileName::DocTest(path, line)
466    }
467
468    pub fn inline_asm_source_code(src: &str) -> FileName {
469        let mut hasher = StableHasher::new();
470        src.hash(&mut hasher);
471        FileName::InlineAsm(hasher.finish())
472    }
473
474    /// Returns the path suitable for reading from the file system on the local host,
475    /// if this information exists.
476    /// Avoid embedding this in build artifacts; see `remapped_path_if_available()` for that.
477    pub fn into_local_path(self) -> Option<PathBuf> {
478        match self {
479            FileName::Real(path) => path.into_local_path(),
480            FileName::DocTest(path, _) => Some(path),
481            _ => None,
482        }
483    }
484}
485
486/// Represents a span.
487///
488/// Spans represent a region of code, used for error reporting. Positions in spans
489/// are *absolute* positions from the beginning of the [`SourceMap`], not positions
490/// relative to [`SourceFile`]s. Methods on the `SourceMap` can be used to relate spans back
491/// to the original source.
492///
493/// You must be careful if the span crosses more than one file, since you will not be
494/// able to use many of the functions on spans in source_map and you cannot assume
495/// that the length of the span is equal to `span.hi - span.lo`; there may be space in the
496/// [`BytePos`] range between files.
497///
498/// `SpanData` is public because `Span` uses a thread-local interner and can't be
499/// sent to other threads, but some pieces of performance infra run in a separate thread.
500/// Using `Span` is generally preferred.
501#[derive(Clone, Copy, Hash, PartialEq, Eq)]
502#[derive_where(PartialOrd, Ord)]
503pub struct SpanData {
504    pub lo: BytePos,
505    pub hi: BytePos,
506    /// Information about where the macro came from, if this piece of
507    /// code was created by a macro expansion.
508    #[derive_where(skip)]
509    // `SyntaxContext` does not implement `Ord`.
510    // The other fields are enough to determine in-file order.
511    pub ctxt: SyntaxContext,
512    #[derive_where(skip)]
513    // `LocalDefId` does not implement `Ord`.
514    // The other fields are enough to determine in-file order.
515    pub parent: Option<LocalDefId>,
516}
517
518impl SpanData {
519    #[inline]
520    pub fn span(&self) -> Span {
521        Span::new(self.lo, self.hi, self.ctxt, self.parent)
522    }
523    #[inline]
524    pub fn with_lo(&self, lo: BytePos) -> Span {
525        Span::new(lo, self.hi, self.ctxt, self.parent)
526    }
527    #[inline]
528    pub fn with_hi(&self, hi: BytePos) -> Span {
529        Span::new(self.lo, hi, self.ctxt, self.parent)
530    }
531    /// Avoid if possible, `Span::map_ctxt` should be preferred.
532    #[inline]
533    fn with_ctxt(&self, ctxt: SyntaxContext) -> Span {
534        Span::new(self.lo, self.hi, ctxt, self.parent)
535    }
536    /// Avoid if possible, `Span::with_parent` should be preferred.
537    #[inline]
538    fn with_parent(&self, parent: Option<LocalDefId>) -> Span {
539        Span::new(self.lo, self.hi, self.ctxt, parent)
540    }
541    /// Returns `true` if this is a dummy span with any hygienic context.
542    #[inline]
543    pub fn is_dummy(self) -> bool {
544        self.lo.0 == 0 && self.hi.0 == 0
545    }
546    /// Returns `true` if `self` fully encloses `other`.
547    pub fn contains(self, other: Self) -> bool {
548        self.lo <= other.lo && other.hi <= self.hi
549    }
550}
551
552impl Default for SpanData {
553    fn default() -> Self {
554        Self { lo: BytePos(0), hi: BytePos(0), ctxt: SyntaxContext::root(), parent: None }
555    }
556}
557
558impl PartialOrd for Span {
559    fn partial_cmp(&self, rhs: &Self) -> Option<Ordering> {
560        PartialOrd::partial_cmp(&self.data(), &rhs.data())
561    }
562}
563impl Ord for Span {
564    fn cmp(&self, rhs: &Self) -> Ordering {
565        Ord::cmp(&self.data(), &rhs.data())
566    }
567}
568
569impl Span {
570    #[inline]
571    pub fn lo(self) -> BytePos {
572        self.data().lo
573    }
574    #[inline]
575    pub fn with_lo(self, lo: BytePos) -> Span {
576        self.data().with_lo(lo)
577    }
578    #[inline]
579    pub fn hi(self) -> BytePos {
580        self.data().hi
581    }
582    #[inline]
583    pub fn with_hi(self, hi: BytePos) -> Span {
584        self.data().with_hi(hi)
585    }
586    #[inline]
587    pub fn with_ctxt(self, ctxt: SyntaxContext) -> Span {
588        self.map_ctxt(|_| ctxt)
589    }
590
591    #[inline]
592    pub fn is_visible(self, sm: &SourceMap) -> bool {
593        !self.is_dummy() && sm.is_span_accessible(self)
594    }
595
596    /// Returns whether this span originates in a foreign crate's external macro.
597    ///
598    /// This is used to test whether a lint should not even begin to figure out whether it should
599    /// be reported on the current node.
600    #[inline]
601    pub fn in_external_macro(self, sm: &SourceMap) -> bool {
602        self.ctxt().in_external_macro(sm)
603    }
604
605    /// Returns `true` if `span` originates in a derive-macro's expansion.
606    pub fn in_derive_expansion(self) -> bool {
607        matches!(self.ctxt().outer_expn_data().kind, ExpnKind::Macro(MacroKind::Derive, _))
608    }
609
610    /// Return whether `span` is generated by `async` or `await`.
611    pub fn is_from_async_await(self) -> bool {
612        matches!(
613            self.ctxt().outer_expn_data().kind,
614            ExpnKind::Desugaring(DesugaringKind::Async | DesugaringKind::Await),
615        )
616    }
617
618    /// Gate suggestions that would not be appropriate in a context the user didn't write.
619    pub fn can_be_used_for_suggestions(self) -> bool {
620        !self.from_expansion()
621        // FIXME: If this span comes from a `derive` macro but it points at code the user wrote,
622        // the callsite span and the span will be pointing at different places. It also means that
623        // we can safely provide suggestions on this span.
624            || (self.in_derive_expansion()
625                && self.parent_callsite().map(|p| (p.lo(), p.hi())) != Some((self.lo(), self.hi())))
626    }
627
628    #[inline]
629    pub fn with_root_ctxt(lo: BytePos, hi: BytePos) -> Span {
630        Span::new(lo, hi, SyntaxContext::root(), None)
631    }
632
633    /// Returns a new span representing an empty span at the beginning of this span.
634    #[inline]
635    pub fn shrink_to_lo(self) -> Span {
636        let span = self.data_untracked();
637        span.with_hi(span.lo)
638    }
639    /// Returns a new span representing an empty span at the end of this span.
640    #[inline]
641    pub fn shrink_to_hi(self) -> Span {
642        let span = self.data_untracked();
643        span.with_lo(span.hi)
644    }
645
646    #[inline]
647    /// Returns `true` if `hi == lo`.
648    pub fn is_empty(self) -> bool {
649        let span = self.data_untracked();
650        span.hi == span.lo
651    }
652
653    /// Returns `self` if `self` is not the dummy span, and `other` otherwise.
654    pub fn substitute_dummy(self, other: Span) -> Span {
655        if self.is_dummy() { other } else { self }
656    }
657
658    /// Returns `true` if `self` fully encloses `other`.
659    pub fn contains(self, other: Span) -> bool {
660        let span = self.data();
661        let other = other.data();
662        span.contains(other)
663    }
664
665    /// Returns `true` if `self` touches `other`.
666    pub fn overlaps(self, other: Span) -> bool {
667        let span = self.data();
668        let other = other.data();
669        span.lo < other.hi && other.lo < span.hi
670    }
671
672    /// Returns `true` if `self` touches or adjoins `other`.
673    pub fn overlaps_or_adjacent(self, other: Span) -> bool {
674        let span = self.data();
675        let other = other.data();
676        span.lo <= other.hi && other.lo <= span.hi
677    }
678
679    /// Returns `true` if the spans are equal with regards to the source text.
680    ///
681    /// Use this instead of `==` when either span could be generated code,
682    /// and you only care that they point to the same bytes of source text.
683    pub fn source_equal(self, other: Span) -> bool {
684        let span = self.data();
685        let other = other.data();
686        span.lo == other.lo && span.hi == other.hi
687    }
688
689    /// Returns `Some(span)`, where the start is trimmed by the end of `other`.
690    pub fn trim_start(self, other: Span) -> Option<Span> {
691        let span = self.data();
692        let other = other.data();
693        if span.hi > other.hi { Some(span.with_lo(cmp::max(span.lo, other.hi))) } else { None }
694    }
695
696    /// Returns `Some(span)`, where the end is trimmed by the start of `other`.
697    pub fn trim_end(self, other: Span) -> Option<Span> {
698        let span = self.data();
699        let other = other.data();
700        if span.lo < other.lo { Some(span.with_hi(cmp::min(span.hi, other.lo))) } else { None }
701    }
702
703    /// Returns the source span -- this is either the supplied span, or the span for
704    /// the macro callsite that expanded to it.
705    pub fn source_callsite(self) -> Span {
706        let ctxt = self.ctxt();
707        if !ctxt.is_root() { ctxt.outer_expn_data().call_site.source_callsite() } else { self }
708    }
709
710    /// The `Span` for the tokens in the previous macro expansion from which `self` was generated,
711    /// if any.
712    pub fn parent_callsite(self) -> Option<Span> {
713        let ctxt = self.ctxt();
714        (!ctxt.is_root()).then(|| ctxt.outer_expn_data().call_site)
715    }
716
717    /// Walk down the expansion ancestors to find a span that's contained within `outer`.
718    ///
719    /// The span returned by this method may have a different [`SyntaxContext`] as `outer`.
720    /// If you need to extend the span, use [`find_ancestor_inside_same_ctxt`] instead,
721    /// because joining spans with different syntax contexts can create unexpected results.
722    ///
723    /// [`find_ancestor_inside_same_ctxt`]: Self::find_ancestor_inside_same_ctxt
724    pub fn find_ancestor_inside(mut self, outer: Span) -> Option<Span> {
725        while !outer.contains(self) {
726            self = self.parent_callsite()?;
727        }
728        Some(self)
729    }
730
731    /// Walk down the expansion ancestors to find a span with the same [`SyntaxContext`] as
732    /// `other`.
733    ///
734    /// Like [`find_ancestor_inside_same_ctxt`], but specifically for when spans might not
735    /// overlap. Take care when using this, and prefer [`find_ancestor_inside`] or
736    /// [`find_ancestor_inside_same_ctxt`] when you know that the spans are nested (modulo
737    /// macro expansion).
738    ///
739    /// [`find_ancestor_inside`]: Self::find_ancestor_inside
740    /// [`find_ancestor_inside_same_ctxt`]: Self::find_ancestor_inside_same_ctxt
741    pub fn find_ancestor_in_same_ctxt(mut self, other: Span) -> Option<Span> {
742        while !self.eq_ctxt(other) {
743            self = self.parent_callsite()?;
744        }
745        Some(self)
746    }
747
748    /// Walk down the expansion ancestors to find a span that's contained within `outer` and
749    /// has the same [`SyntaxContext`] as `outer`.
750    ///
751    /// This method is the combination of [`find_ancestor_inside`] and
752    /// [`find_ancestor_in_same_ctxt`] and should be preferred when extending the returned span.
753    /// If you do not need to modify the span, use [`find_ancestor_inside`] instead.
754    ///
755    /// [`find_ancestor_inside`]: Self::find_ancestor_inside
756    /// [`find_ancestor_in_same_ctxt`]: Self::find_ancestor_in_same_ctxt
757    pub fn find_ancestor_inside_same_ctxt(mut self, outer: Span) -> Option<Span> {
758        while !outer.contains(self) || !self.eq_ctxt(outer) {
759            self = self.parent_callsite()?;
760        }
761        Some(self)
762    }
763
764    /// Recursively walk down the expansion ancestors to find the oldest ancestor span with the same
765    /// [`SyntaxContext`] the initial span.
766    ///
767    /// This method is suitable for peeling through *local* macro expansions to find the "innermost"
768    /// span that is still local and shares the same [`SyntaxContext`]. For example, given
769    ///
770    /// ```ignore (illustrative example, contains type error)
771    ///  macro_rules! outer {
772    ///      ($x: expr) => {
773    ///          inner!($x)
774    ///      }
775    ///  }
776    ///
777    ///  macro_rules! inner {
778    ///      ($x: expr) => {
779    ///          format!("error: {}", $x)
780    ///          //~^ ERROR mismatched types
781    ///      }
782    ///  }
783    ///
784    ///  fn bar(x: &str) -> Result<(), Box<dyn std::error::Error>> {
785    ///      Err(outer!(x))
786    ///  }
787    /// ```
788    ///
789    /// if provided the initial span of `outer!(x)` inside `bar`, this method will recurse
790    /// the parent callsites until we reach `format!("error: {}", $x)`, at which point it is the
791    /// oldest ancestor span that is both still local and shares the same [`SyntaxContext`] as the
792    /// initial span.
793    pub fn find_oldest_ancestor_in_same_ctxt(self) -> Span {
794        let mut cur = self;
795        while cur.eq_ctxt(self)
796            && let Some(parent_callsite) = cur.parent_callsite()
797        {
798            cur = parent_callsite;
799        }
800        cur
801    }
802
803    /// Edition of the crate from which this span came.
804    pub fn edition(self) -> edition::Edition {
805        self.ctxt().edition()
806    }
807
808    /// Is this edition 2015?
809    #[inline]
810    pub fn is_rust_2015(self) -> bool {
811        self.edition().is_rust_2015()
812    }
813
814    /// Are we allowed to use features from the Rust 2018 edition?
815    #[inline]
816    pub fn at_least_rust_2018(self) -> bool {
817        self.edition().at_least_rust_2018()
818    }
819
820    /// Are we allowed to use features from the Rust 2021 edition?
821    #[inline]
822    pub fn at_least_rust_2021(self) -> bool {
823        self.edition().at_least_rust_2021()
824    }
825
826    /// Are we allowed to use features from the Rust 2024 edition?
827    #[inline]
828    pub fn at_least_rust_2024(self) -> bool {
829        self.edition().at_least_rust_2024()
830    }
831
832    /// Returns the source callee.
833    ///
834    /// Returns `None` if the supplied span has no expansion trace,
835    /// else returns the `ExpnData` for the macro definition
836    /// corresponding to the source callsite.
837    pub fn source_callee(self) -> Option<ExpnData> {
838        let mut ctxt = self.ctxt();
839        let mut opt_expn_data = None;
840        while !ctxt.is_root() {
841            let expn_data = ctxt.outer_expn_data();
842            ctxt = expn_data.call_site.ctxt();
843            opt_expn_data = Some(expn_data);
844        }
845        opt_expn_data
846    }
847
848    /// Checks if a span is "internal" to a macro in which `#[unstable]`
849    /// items can be used (that is, a macro marked with
850    /// `#[allow_internal_unstable]`).
851    pub fn allows_unstable(self, feature: Symbol) -> bool {
852        self.ctxt()
853            .outer_expn_data()
854            .allow_internal_unstable
855            .is_some_and(|features| features.contains(&feature))
856    }
857
858    /// Checks if this span arises from a compiler desugaring of kind `kind`.
859    pub fn is_desugaring(self, kind: DesugaringKind) -> bool {
860        match self.ctxt().outer_expn_data().kind {
861            ExpnKind::Desugaring(k) => k == kind,
862            _ => false,
863        }
864    }
865
866    /// Returns the compiler desugaring that created this span, or `None`
867    /// if this span is not from a desugaring.
868    pub fn desugaring_kind(self) -> Option<DesugaringKind> {
869        match self.ctxt().outer_expn_data().kind {
870            ExpnKind::Desugaring(k) => Some(k),
871            _ => None,
872        }
873    }
874
875    /// Checks if a span is "internal" to a macro in which `unsafe`
876    /// can be used without triggering the `unsafe_code` lint.
877    /// (that is, a macro marked with `#[allow_internal_unsafe]`).
878    pub fn allows_unsafe(self) -> bool {
879        self.ctxt().outer_expn_data().allow_internal_unsafe
880    }
881
882    pub fn macro_backtrace(mut self) -> impl Iterator<Item = ExpnData> {
883        let mut prev_span = DUMMY_SP;
884        iter::from_fn(move || {
885            loop {
886                let ctxt = self.ctxt();
887                if ctxt.is_root() {
888                    return None;
889                }
890
891                let expn_data = ctxt.outer_expn_data();
892                let is_recursive = expn_data.call_site.source_equal(prev_span);
893
894                prev_span = self;
895                self = expn_data.call_site;
896
897                // Don't print recursive invocations.
898                if !is_recursive {
899                    return Some(expn_data);
900                }
901            }
902        })
903    }
904
905    /// Splits a span into two composite spans around a certain position.
906    pub fn split_at(self, pos: u32) -> (Span, Span) {
907        let len = self.hi().0 - self.lo().0;
908        debug_assert!(pos <= len);
909
910        let split_pos = BytePos(self.lo().0 + pos);
911        (
912            Span::new(self.lo(), split_pos, self.ctxt(), self.parent()),
913            Span::new(split_pos, self.hi(), self.ctxt(), self.parent()),
914        )
915    }
916
917    /// Check if you can select metavar spans for the given spans to get matching contexts.
918    fn try_metavars(a: SpanData, b: SpanData, a_orig: Span, b_orig: Span) -> (SpanData, SpanData) {
919        match with_metavar_spans(|mspans| (mspans.get(a_orig), mspans.get(b_orig))) {
920            (None, None) => {}
921            (Some(meta_a), None) => {
922                let meta_a = meta_a.data();
923                if meta_a.ctxt == b.ctxt {
924                    return (meta_a, b);
925                }
926            }
927            (None, Some(meta_b)) => {
928                let meta_b = meta_b.data();
929                if a.ctxt == meta_b.ctxt {
930                    return (a, meta_b);
931                }
932            }
933            (Some(meta_a), Some(meta_b)) => {
934                let meta_b = meta_b.data();
935                if a.ctxt == meta_b.ctxt {
936                    return (a, meta_b);
937                }
938                let meta_a = meta_a.data();
939                if meta_a.ctxt == b.ctxt {
940                    return (meta_a, b);
941                } else if meta_a.ctxt == meta_b.ctxt {
942                    return (meta_a, meta_b);
943                }
944            }
945        }
946
947        (a, b)
948    }
949
950    /// Prepare two spans to a combine operation like `to` or `between`.
951    fn prepare_to_combine(
952        a_orig: Span,
953        b_orig: Span,
954    ) -> Result<(SpanData, SpanData, Option<LocalDefId>), Span> {
955        let (a, b) = (a_orig.data(), b_orig.data());
956        if a.ctxt == b.ctxt {
957            return Ok((a, b, if a.parent == b.parent { a.parent } else { None }));
958        }
959
960        let (a, b) = Span::try_metavars(a, b, a_orig, b_orig);
961        if a.ctxt == b.ctxt {
962            return Ok((a, b, if a.parent == b.parent { a.parent } else { None }));
963        }
964
965        // Context mismatches usually happen when procedural macros combine spans copied from
966        // the macro input with spans produced by the macro (`Span::*_site`).
967        // In that case we consider the combined span to be produced by the macro and return
968        // the original macro-produced span as the result.
969        // Otherwise we just fall back to returning the first span.
970        // Combining locations typically doesn't make sense in case of context mismatches.
971        // `is_root` here is a fast path optimization.
972        let a_is_callsite = a.ctxt.is_root() || a.ctxt == b.span().source_callsite().ctxt();
973        Err(if a_is_callsite { b_orig } else { a_orig })
974    }
975
976    /// This span, but in a larger context, may switch to the metavariable span if suitable.
977    pub fn with_neighbor(self, neighbor: Span) -> Span {
978        match Span::prepare_to_combine(self, neighbor) {
979            Ok((this, ..)) => this.span(),
980            Err(_) => self,
981        }
982    }
983
984    /// Returns a `Span` that would enclose both `self` and `end`.
985    ///
986    /// Note that this can also be used to extend the span "backwards":
987    /// `start.to(end)` and `end.to(start)` return the same `Span`.
988    ///
989    /// ```text
990    ///     ____             ___
991    ///     self lorem ipsum end
992    ///     ^^^^^^^^^^^^^^^^^^^^
993    /// ```
994    pub fn to(self, end: Span) -> Span {
995        match Span::prepare_to_combine(self, end) {
996            Ok((from, to, parent)) => {
997                Span::new(cmp::min(from.lo, to.lo), cmp::max(from.hi, to.hi), from.ctxt, parent)
998            }
999            Err(fallback) => fallback,
1000        }
1001    }
1002
1003    /// Returns a `Span` between the end of `self` to the beginning of `end`.
1004    ///
1005    /// ```text
1006    ///     ____             ___
1007    ///     self lorem ipsum end
1008    ///         ^^^^^^^^^^^^^
1009    /// ```
1010    pub fn between(self, end: Span) -> Span {
1011        match Span::prepare_to_combine(self, end) {
1012            Ok((from, to, parent)) => {
1013                Span::new(cmp::min(from.hi, to.hi), cmp::max(from.lo, to.lo), from.ctxt, parent)
1014            }
1015            Err(fallback) => fallback,
1016        }
1017    }
1018
1019    /// Returns a `Span` from the beginning of `self` until the beginning of `end`.
1020    ///
1021    /// ```text
1022    ///     ____             ___
1023    ///     self lorem ipsum end
1024    ///     ^^^^^^^^^^^^^^^^^
1025    /// ```
1026    pub fn until(self, end: Span) -> Span {
1027        match Span::prepare_to_combine(self, end) {
1028            Ok((from, to, parent)) => {
1029                Span::new(cmp::min(from.lo, to.lo), cmp::max(from.lo, to.lo), from.ctxt, parent)
1030            }
1031            Err(fallback) => fallback,
1032        }
1033    }
1034
1035    /// Returns the `Span` within the syntax context of "within". This is useful when
1036    /// "self" is an expansion from a macro variable, since this can be used for
1037    /// providing extra macro expansion context for certain errors.
1038    ///
1039    /// ```text
1040    /// macro_rules! m {
1041    ///     ($ident:ident) => { ($ident,) }
1042    /// }
1043    ///
1044    /// m!(outer_ident);
1045    /// ```
1046    ///
1047    /// If "self" is the span of the outer_ident, and "within" is the span of the `($ident,)`
1048    /// expr, then this will return the span of the `$ident` macro variable.
1049    pub fn within_macro(self, within: Span, sm: &SourceMap) -> Option<Span> {
1050        match Span::prepare_to_combine(self, within) {
1051            // Only return something if it doesn't overlap with the original span,
1052            // and the span isn't "imported" (i.e. from unavailable sources).
1053            // FIXME: This does limit the usefulness of the error when the macro is
1054            // from a foreign crate; we could also take into account `-Zmacro-backtrace`,
1055            // which doesn't redact this span (but that would mean passing in even more
1056            // args to this function, lol).
1057            Ok((self_, _, parent))
1058                if self_.hi < self.lo() || self.hi() < self_.lo && !sm.is_imported(within) =>
1059            {
1060                Some(Span::new(self_.lo, self_.hi, self_.ctxt, parent))
1061            }
1062            _ => None,
1063        }
1064    }
1065
1066    pub fn from_inner(self, inner: InnerSpan) -> Span {
1067        let span = self.data();
1068        Span::new(
1069            span.lo + BytePos::from_usize(inner.start),
1070            span.lo + BytePos::from_usize(inner.end),
1071            span.ctxt,
1072            span.parent,
1073        )
1074    }
1075
1076    /// Equivalent of `Span::def_site` from the proc macro API,
1077    /// except that the location is taken from the `self` span.
1078    pub fn with_def_site_ctxt(self, expn_id: ExpnId) -> Span {
1079        self.with_ctxt_from_mark(expn_id, Transparency::Opaque)
1080    }
1081
1082    /// Equivalent of `Span::call_site` from the proc macro API,
1083    /// except that the location is taken from the `self` span.
1084    pub fn with_call_site_ctxt(self, expn_id: ExpnId) -> Span {
1085        self.with_ctxt_from_mark(expn_id, Transparency::Transparent)
1086    }
1087
1088    /// Equivalent of `Span::mixed_site` from the proc macro API,
1089    /// except that the location is taken from the `self` span.
1090    pub fn with_mixed_site_ctxt(self, expn_id: ExpnId) -> Span {
1091        self.with_ctxt_from_mark(expn_id, Transparency::SemiOpaque)
1092    }
1093
1094    /// Produces a span with the same location as `self` and context produced by a macro with the
1095    /// given ID and transparency, assuming that macro was defined directly and not produced by
1096    /// some other macro (which is the case for built-in and procedural macros).
1097    fn with_ctxt_from_mark(self, expn_id: ExpnId, transparency: Transparency) -> Span {
1098        self.with_ctxt(SyntaxContext::root().apply_mark(expn_id, transparency))
1099    }
1100
1101    #[inline]
1102    pub fn apply_mark(self, expn_id: ExpnId, transparency: Transparency) -> Span {
1103        self.map_ctxt(|ctxt| ctxt.apply_mark(expn_id, transparency))
1104    }
1105
1106    #[inline]
1107    pub fn remove_mark(&mut self) -> ExpnId {
1108        let mut mark = ExpnId::root();
1109        *self = self.map_ctxt(|mut ctxt| {
1110            mark = ctxt.remove_mark();
1111            ctxt
1112        });
1113        mark
1114    }
1115
1116    #[inline]
1117    pub fn adjust(&mut self, expn_id: ExpnId) -> Option<ExpnId> {
1118        let mut mark = None;
1119        *self = self.map_ctxt(|mut ctxt| {
1120            mark = ctxt.adjust(expn_id);
1121            ctxt
1122        });
1123        mark
1124    }
1125
1126    #[inline]
1127    pub fn normalize_to_macros_2_0_and_adjust(&mut self, expn_id: ExpnId) -> Option<ExpnId> {
1128        let mut mark = None;
1129        *self = self.map_ctxt(|mut ctxt| {
1130            mark = ctxt.normalize_to_macros_2_0_and_adjust(expn_id);
1131            ctxt
1132        });
1133        mark
1134    }
1135
1136    #[inline]
1137    pub fn glob_adjust(&mut self, expn_id: ExpnId, glob_span: Span) -> Option<Option<ExpnId>> {
1138        let mut mark = None;
1139        *self = self.map_ctxt(|mut ctxt| {
1140            mark = ctxt.glob_adjust(expn_id, glob_span);
1141            ctxt
1142        });
1143        mark
1144    }
1145
1146    #[inline]
1147    pub fn reverse_glob_adjust(
1148        &mut self,
1149        expn_id: ExpnId,
1150        glob_span: Span,
1151    ) -> Option<Option<ExpnId>> {
1152        let mut mark = None;
1153        *self = self.map_ctxt(|mut ctxt| {
1154            mark = ctxt.reverse_glob_adjust(expn_id, glob_span);
1155            ctxt
1156        });
1157        mark
1158    }
1159
1160    #[inline]
1161    pub fn normalize_to_macros_2_0(self) -> Span {
1162        self.map_ctxt(|ctxt| ctxt.normalize_to_macros_2_0())
1163    }
1164
1165    #[inline]
1166    pub fn normalize_to_macro_rules(self) -> Span {
1167        self.map_ctxt(|ctxt| ctxt.normalize_to_macro_rules())
1168    }
1169}
1170
1171impl Default for Span {
1172    fn default() -> Self {
1173        DUMMY_SP
1174    }
1175}
1176
1177rustc_index::newtype_index! {
1178    #[orderable]
1179    #[debug_format = "AttrId({})"]
1180    pub struct AttrId {}
1181}
1182
1183/// This trait is used to allow encoder specific encodings of certain types.
1184/// It is similar to rustc_type_ir's TyEncoder.
1185pub trait SpanEncoder: Encoder {
1186    fn encode_span(&mut self, span: Span);
1187    fn encode_symbol(&mut self, symbol: Symbol);
1188    fn encode_expn_id(&mut self, expn_id: ExpnId);
1189    fn encode_syntax_context(&mut self, syntax_context: SyntaxContext);
1190    /// As a local identifier, a `CrateNum` is only meaningful within its context, e.g. within a tcx.
1191    /// Therefore, make sure to include the context when encode a `CrateNum`.
1192    fn encode_crate_num(&mut self, crate_num: CrateNum);
1193    fn encode_def_index(&mut self, def_index: DefIndex);
1194    fn encode_def_id(&mut self, def_id: DefId);
1195}
1196
1197impl SpanEncoder for FileEncoder {
1198    fn encode_span(&mut self, span: Span) {
1199        let span = span.data();
1200        span.lo.encode(self);
1201        span.hi.encode(self);
1202    }
1203
1204    fn encode_symbol(&mut self, symbol: Symbol) {
1205        self.emit_str(symbol.as_str());
1206    }
1207
1208    fn encode_expn_id(&mut self, _expn_id: ExpnId) {
1209        panic!("cannot encode `ExpnId` with `FileEncoder`");
1210    }
1211
1212    fn encode_syntax_context(&mut self, _syntax_context: SyntaxContext) {
1213        panic!("cannot encode `SyntaxContext` with `FileEncoder`");
1214    }
1215
1216    fn encode_crate_num(&mut self, crate_num: CrateNum) {
1217        self.emit_u32(crate_num.as_u32());
1218    }
1219
1220    fn encode_def_index(&mut self, _def_index: DefIndex) {
1221        panic!("cannot encode `DefIndex` with `FileEncoder`");
1222    }
1223
1224    fn encode_def_id(&mut self, def_id: DefId) {
1225        def_id.krate.encode(self);
1226        def_id.index.encode(self);
1227    }
1228}
1229
1230impl<E: SpanEncoder> Encodable<E> for Span {
1231    fn encode(&self, s: &mut E) {
1232        s.encode_span(*self);
1233    }
1234}
1235
1236impl<E: SpanEncoder> Encodable<E> for Symbol {
1237    fn encode(&self, s: &mut E) {
1238        s.encode_symbol(*self);
1239    }
1240}
1241
1242impl<E: SpanEncoder> Encodable<E> for ExpnId {
1243    fn encode(&self, s: &mut E) {
1244        s.encode_expn_id(*self)
1245    }
1246}
1247
1248impl<E: SpanEncoder> Encodable<E> for SyntaxContext {
1249    fn encode(&self, s: &mut E) {
1250        s.encode_syntax_context(*self)
1251    }
1252}
1253
1254impl<E: SpanEncoder> Encodable<E> for CrateNum {
1255    fn encode(&self, s: &mut E) {
1256        s.encode_crate_num(*self)
1257    }
1258}
1259
1260impl<E: SpanEncoder> Encodable<E> for DefIndex {
1261    fn encode(&self, s: &mut E) {
1262        s.encode_def_index(*self)
1263    }
1264}
1265
1266impl<E: SpanEncoder> Encodable<E> for DefId {
1267    fn encode(&self, s: &mut E) {
1268        s.encode_def_id(*self)
1269    }
1270}
1271
1272impl<E: SpanEncoder> Encodable<E> for AttrId {
1273    fn encode(&self, _s: &mut E) {
1274        // A fresh id will be generated when decoding
1275    }
1276}
1277
1278/// This trait is used to allow decoder specific encodings of certain types.
1279/// It is similar to rustc_type_ir's TyDecoder.
1280pub trait SpanDecoder: Decoder {
1281    fn decode_span(&mut self) -> Span;
1282    fn decode_symbol(&mut self) -> Symbol;
1283    fn decode_expn_id(&mut self) -> ExpnId;
1284    fn decode_syntax_context(&mut self) -> SyntaxContext;
1285    fn decode_crate_num(&mut self) -> CrateNum;
1286    fn decode_def_index(&mut self) -> DefIndex;
1287    fn decode_def_id(&mut self) -> DefId;
1288    fn decode_attr_id(&mut self) -> AttrId;
1289}
1290
1291impl SpanDecoder for MemDecoder<'_> {
1292    fn decode_span(&mut self) -> Span {
1293        let lo = Decodable::decode(self);
1294        let hi = Decodable::decode(self);
1295
1296        Span::new(lo, hi, SyntaxContext::root(), None)
1297    }
1298
1299    fn decode_symbol(&mut self) -> Symbol {
1300        Symbol::intern(self.read_str())
1301    }
1302
1303    fn decode_expn_id(&mut self) -> ExpnId {
1304        panic!("cannot decode `ExpnId` with `MemDecoder`");
1305    }
1306
1307    fn decode_syntax_context(&mut self) -> SyntaxContext {
1308        panic!("cannot decode `SyntaxContext` with `MemDecoder`");
1309    }
1310
1311    fn decode_crate_num(&mut self) -> CrateNum {
1312        CrateNum::from_u32(self.read_u32())
1313    }
1314
1315    fn decode_def_index(&mut self) -> DefIndex {
1316        panic!("cannot decode `DefIndex` with `MemDecoder`");
1317    }
1318
1319    fn decode_def_id(&mut self) -> DefId {
1320        DefId { krate: Decodable::decode(self), index: Decodable::decode(self) }
1321    }
1322
1323    fn decode_attr_id(&mut self) -> AttrId {
1324        panic!("cannot decode `AttrId` with `MemDecoder`");
1325    }
1326}
1327
1328impl<D: SpanDecoder> Decodable<D> for Span {
1329    fn decode(s: &mut D) -> Span {
1330        s.decode_span()
1331    }
1332}
1333
1334impl<D: SpanDecoder> Decodable<D> for Symbol {
1335    fn decode(s: &mut D) -> Symbol {
1336        s.decode_symbol()
1337    }
1338}
1339
1340impl<D: SpanDecoder> Decodable<D> for ExpnId {
1341    fn decode(s: &mut D) -> ExpnId {
1342        s.decode_expn_id()
1343    }
1344}
1345
1346impl<D: SpanDecoder> Decodable<D> for SyntaxContext {
1347    fn decode(s: &mut D) -> SyntaxContext {
1348        s.decode_syntax_context()
1349    }
1350}
1351
1352impl<D: SpanDecoder> Decodable<D> for CrateNum {
1353    fn decode(s: &mut D) -> CrateNum {
1354        s.decode_crate_num()
1355    }
1356}
1357
1358impl<D: SpanDecoder> Decodable<D> for DefIndex {
1359    fn decode(s: &mut D) -> DefIndex {
1360        s.decode_def_index()
1361    }
1362}
1363
1364impl<D: SpanDecoder> Decodable<D> for DefId {
1365    fn decode(s: &mut D) -> DefId {
1366        s.decode_def_id()
1367    }
1368}
1369
1370impl<D: SpanDecoder> Decodable<D> for AttrId {
1371    fn decode(s: &mut D) -> AttrId {
1372        s.decode_attr_id()
1373    }
1374}
1375
1376impl fmt::Debug for Span {
1377    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1378        // Use the global `SourceMap` to print the span. If that's not
1379        // available, fall back to printing the raw values.
1380
1381        fn fallback(span: Span, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1382            f.debug_struct("Span")
1383                .field("lo", &span.lo())
1384                .field("hi", &span.hi())
1385                .field("ctxt", &span.ctxt())
1386                .finish()
1387        }
1388
1389        if SESSION_GLOBALS.is_set() {
1390            with_session_globals(|session_globals| {
1391                if let Some(source_map) = &session_globals.source_map {
1392                    write!(f, "{} ({:?})", source_map.span_to_diagnostic_string(*self), self.ctxt())
1393                } else {
1394                    fallback(*self, f)
1395                }
1396            })
1397        } else {
1398            fallback(*self, f)
1399        }
1400    }
1401}
1402
1403impl fmt::Debug for SpanData {
1404    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1405        fmt::Debug::fmt(&self.span(), f)
1406    }
1407}
1408
1409/// Identifies an offset of a multi-byte character in a `SourceFile`.
1410#[derive(Copy, Clone, Encodable, Decodable, Eq, PartialEq, Debug, HashStable_Generic)]
1411pub struct MultiByteChar {
1412    /// The relative offset of the character in the `SourceFile`.
1413    pub pos: RelativeBytePos,
1414    /// The number of bytes, `>= 2`.
1415    pub bytes: u8,
1416}
1417
1418/// Identifies an offset of a character that was normalized away from `SourceFile`.
1419#[derive(Copy, Clone, Encodable, Decodable, Eq, PartialEq, Debug, HashStable_Generic)]
1420pub struct NormalizedPos {
1421    /// The relative offset of the character in the `SourceFile`.
1422    pub pos: RelativeBytePos,
1423    /// The difference between original and normalized string at position.
1424    pub diff: u32,
1425}
1426
1427#[derive(PartialEq, Eq, Clone, Debug)]
1428pub enum ExternalSource {
1429    /// No external source has to be loaded, since the `SourceFile` represents a local crate.
1430    Unneeded,
1431    Foreign {
1432        kind: ExternalSourceKind,
1433        /// Index of the file inside metadata.
1434        metadata_index: u32,
1435    },
1436}
1437
1438/// The state of the lazy external source loading mechanism of a `SourceFile`.
1439#[derive(PartialEq, Eq, Clone, Debug)]
1440pub enum ExternalSourceKind {
1441    /// The external source has been loaded already.
1442    Present(Arc<String>),
1443    /// No attempt has been made to load the external source.
1444    AbsentOk,
1445    /// A failed attempt has been made to load the external source.
1446    AbsentErr,
1447}
1448
1449impl ExternalSource {
1450    pub fn get_source(&self) -> Option<&str> {
1451        match self {
1452            ExternalSource::Foreign { kind: ExternalSourceKind::Present(src), .. } => Some(src),
1453            _ => None,
1454        }
1455    }
1456}
1457
1458#[derive(Debug)]
1459pub struct OffsetOverflowError;
1460
1461#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Encodable, Decodable)]
1462#[derive(HashStable_Generic)]
1463pub enum SourceFileHashAlgorithm {
1464    Md5,
1465    Sha1,
1466    Sha256,
1467    Blake3,
1468}
1469
1470impl Display for SourceFileHashAlgorithm {
1471    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1472        f.write_str(match self {
1473            Self::Md5 => "md5",
1474            Self::Sha1 => "sha1",
1475            Self::Sha256 => "sha256",
1476            Self::Blake3 => "blake3",
1477        })
1478    }
1479}
1480
1481impl FromStr for SourceFileHashAlgorithm {
1482    type Err = ();
1483
1484    fn from_str(s: &str) -> Result<SourceFileHashAlgorithm, ()> {
1485        match s {
1486            "md5" => Ok(SourceFileHashAlgorithm::Md5),
1487            "sha1" => Ok(SourceFileHashAlgorithm::Sha1),
1488            "sha256" => Ok(SourceFileHashAlgorithm::Sha256),
1489            "blake3" => Ok(SourceFileHashAlgorithm::Blake3),
1490            _ => Err(()),
1491        }
1492    }
1493}
1494
1495/// The hash of the on-disk source file used for debug info and cargo freshness checks.
1496#[derive(Copy, Clone, PartialEq, Eq, Debug, Hash)]
1497#[derive(HashStable_Generic, Encodable, Decodable)]
1498pub struct SourceFileHash {
1499    pub kind: SourceFileHashAlgorithm,
1500    value: [u8; 32],
1501}
1502
1503impl Display for SourceFileHash {
1504    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1505        write!(f, "{}=", self.kind)?;
1506        for byte in self.value[0..self.hash_len()].into_iter() {
1507            write!(f, "{byte:02x}")?;
1508        }
1509        Ok(())
1510    }
1511}
1512
1513impl SourceFileHash {
1514    pub fn new_in_memory(kind: SourceFileHashAlgorithm, src: impl AsRef<[u8]>) -> SourceFileHash {
1515        let mut hash = SourceFileHash { kind, value: Default::default() };
1516        let len = hash.hash_len();
1517        let value = &mut hash.value[..len];
1518        let data = src.as_ref();
1519        match kind {
1520            SourceFileHashAlgorithm::Md5 => {
1521                value.copy_from_slice(&Md5::digest(data));
1522            }
1523            SourceFileHashAlgorithm::Sha1 => {
1524                value.copy_from_slice(&Sha1::digest(data));
1525            }
1526            SourceFileHashAlgorithm::Sha256 => {
1527                value.copy_from_slice(&Sha256::digest(data));
1528            }
1529            SourceFileHashAlgorithm::Blake3 => value.copy_from_slice(blake3::hash(data).as_bytes()),
1530        };
1531        hash
1532    }
1533
1534    pub fn new(kind: SourceFileHashAlgorithm, src: impl Read) -> Result<SourceFileHash, io::Error> {
1535        let mut hash = SourceFileHash { kind, value: Default::default() };
1536        let len = hash.hash_len();
1537        let value = &mut hash.value[..len];
1538        // Buffer size is the recommended amount to fully leverage SIMD instructions on AVX-512 as per
1539        // blake3 documentation.
1540        let mut buf = vec![0; 16 * 1024];
1541
1542        fn digest<T>(
1543            mut hasher: T,
1544            mut update: impl FnMut(&mut T, &[u8]),
1545            finish: impl FnOnce(T, &mut [u8]),
1546            mut src: impl Read,
1547            buf: &mut [u8],
1548            value: &mut [u8],
1549        ) -> Result<(), io::Error> {
1550            loop {
1551                let bytes_read = src.read(buf)?;
1552                if bytes_read == 0 {
1553                    break;
1554                }
1555                update(&mut hasher, &buf[0..bytes_read]);
1556            }
1557            finish(hasher, value);
1558            Ok(())
1559        }
1560
1561        match kind {
1562            SourceFileHashAlgorithm::Sha256 => {
1563                digest(
1564                    Sha256::new(),
1565                    |h, b| {
1566                        h.update(b);
1567                    },
1568                    |h, out| out.copy_from_slice(&h.finalize()),
1569                    src,
1570                    &mut buf,
1571                    value,
1572                )?;
1573            }
1574            SourceFileHashAlgorithm::Sha1 => {
1575                digest(
1576                    Sha1::new(),
1577                    |h, b| {
1578                        h.update(b);
1579                    },
1580                    |h, out| out.copy_from_slice(&h.finalize()),
1581                    src,
1582                    &mut buf,
1583                    value,
1584                )?;
1585            }
1586            SourceFileHashAlgorithm::Md5 => {
1587                digest(
1588                    Md5::new(),
1589                    |h, b| {
1590                        h.update(b);
1591                    },
1592                    |h, out| out.copy_from_slice(&h.finalize()),
1593                    src,
1594                    &mut buf,
1595                    value,
1596                )?;
1597            }
1598            SourceFileHashAlgorithm::Blake3 => {
1599                digest(
1600                    blake3::Hasher::new(),
1601                    |h, b| {
1602                        h.update(b);
1603                    },
1604                    |h, out| out.copy_from_slice(h.finalize().as_bytes()),
1605                    src,
1606                    &mut buf,
1607                    value,
1608                )?;
1609            }
1610        }
1611        Ok(hash)
1612    }
1613
1614    /// Check if the stored hash matches the hash of the string.
1615    pub fn matches(&self, src: &str) -> bool {
1616        Self::new_in_memory(self.kind, src.as_bytes()) == *self
1617    }
1618
1619    /// The bytes of the hash.
1620    pub fn hash_bytes(&self) -> &[u8] {
1621        let len = self.hash_len();
1622        &self.value[..len]
1623    }
1624
1625    fn hash_len(&self) -> usize {
1626        match self.kind {
1627            SourceFileHashAlgorithm::Md5 => 16,
1628            SourceFileHashAlgorithm::Sha1 => 20,
1629            SourceFileHashAlgorithm::Sha256 | SourceFileHashAlgorithm::Blake3 => 32,
1630        }
1631    }
1632}
1633
1634#[derive(Clone)]
1635pub enum SourceFileLines {
1636    /// The source file lines, in decoded (random-access) form.
1637    Lines(Vec<RelativeBytePos>),
1638
1639    /// The source file lines, in undecoded difference list form.
1640    Diffs(SourceFileDiffs),
1641}
1642
1643impl SourceFileLines {
1644    pub fn is_lines(&self) -> bool {
1645        matches!(self, SourceFileLines::Lines(_))
1646    }
1647}
1648
1649/// The source file lines in difference list form. This matches the form
1650/// used within metadata, which saves space by exploiting the fact that the
1651/// lines list is sorted and individual lines are usually not that long.
1652///
1653/// We read it directly from metadata and only decode it into `Lines` form
1654/// when necessary. This is a significant performance win, especially for
1655/// small crates where very little of `std`'s metadata is used.
1656#[derive(Clone)]
1657pub struct SourceFileDiffs {
1658    /// Always 1, 2, or 4. Always as small as possible, while being big
1659    /// enough to hold the length of the longest line in the source file.
1660    /// The 1 case is by far the most common.
1661    bytes_per_diff: usize,
1662
1663    /// The number of diffs encoded in `raw_diffs`. Always one less than
1664    /// the number of lines in the source file.
1665    num_diffs: usize,
1666
1667    /// The diffs in "raw" form. Each segment of `bytes_per_diff` length
1668    /// encodes one little-endian diff. Note that they aren't LEB128
1669    /// encoded. This makes for much faster decoding. Besides, the
1670    /// bytes_per_diff==1 case is by far the most common, and LEB128
1671    /// encoding has no effect on that case.
1672    raw_diffs: Vec<u8>,
1673}
1674
1675/// A single source in the [`SourceMap`].
1676pub struct SourceFile {
1677    /// The name of the file that the source came from. Source that doesn't
1678    /// originate from files has names between angle brackets by convention
1679    /// (e.g., `<anon>`).
1680    pub name: FileName,
1681    /// The complete source code.
1682    pub src: Option<Arc<String>>,
1683    /// The source code's hash.
1684    pub src_hash: SourceFileHash,
1685    /// Used to enable cargo to use checksums to check if a crate is fresh rather
1686    /// than mtimes. This might be the same as `src_hash`, and if the requested algorithm
1687    /// is identical we won't compute it twice.
1688    pub checksum_hash: Option<SourceFileHash>,
1689    /// The external source code (used for external crates, which will have a `None`
1690    /// value as `self.src`.
1691    pub external_src: FreezeLock<ExternalSource>,
1692    /// The start position of this source in the `SourceMap`.
1693    pub start_pos: BytePos,
1694    /// The byte length of this source.
1695    pub source_len: RelativeBytePos,
1696    /// Locations of lines beginnings in the source code.
1697    pub lines: FreezeLock<SourceFileLines>,
1698    /// Locations of multi-byte characters in the source code.
1699    pub multibyte_chars: Vec<MultiByteChar>,
1700    /// Locations of characters removed during normalization.
1701    pub normalized_pos: Vec<NormalizedPos>,
1702    /// A hash of the filename & crate-id, used for uniquely identifying source
1703    /// files within the crate graph and for speeding up hashing in incremental
1704    /// compilation.
1705    pub stable_id: StableSourceFileId,
1706    /// Indicates which crate this `SourceFile` was imported from.
1707    pub cnum: CrateNum,
1708}
1709
1710impl Clone for SourceFile {
1711    fn clone(&self) -> Self {
1712        Self {
1713            name: self.name.clone(),
1714            src: self.src.clone(),
1715            src_hash: self.src_hash,
1716            checksum_hash: self.checksum_hash,
1717            external_src: self.external_src.clone(),
1718            start_pos: self.start_pos,
1719            source_len: self.source_len,
1720            lines: self.lines.clone(),
1721            multibyte_chars: self.multibyte_chars.clone(),
1722            normalized_pos: self.normalized_pos.clone(),
1723            stable_id: self.stable_id,
1724            cnum: self.cnum,
1725        }
1726    }
1727}
1728
1729impl<S: SpanEncoder> Encodable<S> for SourceFile {
1730    fn encode(&self, s: &mut S) {
1731        self.name.encode(s);
1732        self.src_hash.encode(s);
1733        self.checksum_hash.encode(s);
1734        // Do not encode `start_pos` as it's global state for this session.
1735        self.source_len.encode(s);
1736
1737        // We are always in `Lines` form by the time we reach here.
1738        assert!(self.lines.read().is_lines());
1739        let lines = self.lines();
1740        // Store the length.
1741        s.emit_u32(lines.len() as u32);
1742
1743        // Compute and store the difference list.
1744        if lines.len() != 0 {
1745            let max_line_length = if lines.len() == 1 {
1746                0
1747            } else {
1748                lines
1749                    .array_windows()
1750                    .map(|&[fst, snd]| snd - fst)
1751                    .map(|bp| bp.to_usize())
1752                    .max()
1753                    .unwrap()
1754            };
1755
1756            let bytes_per_diff: usize = match max_line_length {
1757                0..=0xFF => 1,
1758                0x100..=0xFFFF => 2,
1759                _ => 4,
1760            };
1761
1762            // Encode the number of bytes used per diff.
1763            s.emit_u8(bytes_per_diff as u8);
1764
1765            // Encode the first element.
1766            assert_eq!(lines[0], RelativeBytePos(0));
1767
1768            // Encode the difference list.
1769            let diff_iter = lines.array_windows().map(|&[fst, snd]| snd - fst);
1770            let num_diffs = lines.len() - 1;
1771            let mut raw_diffs;
1772            match bytes_per_diff {
1773                1 => {
1774                    raw_diffs = Vec::with_capacity(num_diffs);
1775                    for diff in diff_iter {
1776                        raw_diffs.push(diff.0 as u8);
1777                    }
1778                }
1779                2 => {
1780                    raw_diffs = Vec::with_capacity(bytes_per_diff * num_diffs);
1781                    for diff in diff_iter {
1782                        raw_diffs.extend_from_slice(&(diff.0 as u16).to_le_bytes());
1783                    }
1784                }
1785                4 => {
1786                    raw_diffs = Vec::with_capacity(bytes_per_diff * num_diffs);
1787                    for diff in diff_iter {
1788                        raw_diffs.extend_from_slice(&(diff.0).to_le_bytes());
1789                    }
1790                }
1791                _ => unreachable!(),
1792            }
1793            s.emit_raw_bytes(&raw_diffs);
1794        }
1795
1796        self.multibyte_chars.encode(s);
1797        self.stable_id.encode(s);
1798        self.normalized_pos.encode(s);
1799        self.cnum.encode(s);
1800    }
1801}
1802
1803impl<D: SpanDecoder> Decodable<D> for SourceFile {
1804    fn decode(d: &mut D) -> SourceFile {
1805        let name: FileName = Decodable::decode(d);
1806        let src_hash: SourceFileHash = Decodable::decode(d);
1807        let checksum_hash: Option<SourceFileHash> = Decodable::decode(d);
1808        let source_len: RelativeBytePos = Decodable::decode(d);
1809        let lines = {
1810            let num_lines: u32 = Decodable::decode(d);
1811            if num_lines > 0 {
1812                // Read the number of bytes used per diff.
1813                let bytes_per_diff = d.read_u8() as usize;
1814
1815                // Read the difference list.
1816                let num_diffs = num_lines as usize - 1;
1817                let raw_diffs = d.read_raw_bytes(bytes_per_diff * num_diffs).to_vec();
1818                SourceFileLines::Diffs(SourceFileDiffs { bytes_per_diff, num_diffs, raw_diffs })
1819            } else {
1820                SourceFileLines::Lines(vec![])
1821            }
1822        };
1823        let multibyte_chars: Vec<MultiByteChar> = Decodable::decode(d);
1824        let stable_id = Decodable::decode(d);
1825        let normalized_pos: Vec<NormalizedPos> = Decodable::decode(d);
1826        let cnum: CrateNum = Decodable::decode(d);
1827        SourceFile {
1828            name,
1829            start_pos: BytePos::from_u32(0),
1830            source_len,
1831            src: None,
1832            src_hash,
1833            checksum_hash,
1834            // Unused - the metadata decoder will construct
1835            // a new SourceFile, filling in `external_src` properly
1836            external_src: FreezeLock::frozen(ExternalSource::Unneeded),
1837            lines: FreezeLock::new(lines),
1838            multibyte_chars,
1839            normalized_pos,
1840            stable_id,
1841            cnum,
1842        }
1843    }
1844}
1845
1846impl fmt::Debug for SourceFile {
1847    fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
1848        write!(fmt, "SourceFile({:?})", self.name)
1849    }
1850}
1851
1852/// This is a [SourceFile] identifier that is used to correlate source files between
1853/// subsequent compilation sessions (which is something we need to do during
1854/// incremental compilation).
1855///
1856/// It is a hash value (so we can efficiently consume it when stable-hashing
1857/// spans) that consists of the `FileName` and the `StableCrateId` of the crate
1858/// the source file is from. The crate id is needed because sometimes the
1859/// `FileName` is not unique within the crate graph (think `src/lib.rs`, for
1860/// example).
1861///
1862/// The way the crate-id part is handled is a bit special: source files of the
1863/// local crate are hashed as `(filename, None)`, while source files from
1864/// upstream crates have a hash of `(filename, Some(stable_crate_id))`. This
1865/// is because SourceFiles for the local crate are allocated very early in the
1866/// compilation process when the `StableCrateId` is not yet known. If, due to
1867/// some refactoring of the compiler, the `StableCrateId` of the local crate
1868/// were to become available, it would be better to uniformly make this a
1869/// hash of `(filename, stable_crate_id)`.
1870///
1871/// When `SourceFile`s are exported in crate metadata, the `StableSourceFileId`
1872/// is updated to incorporate the `StableCrateId` of the exporting crate.
1873#[derive(
1874    Debug,
1875    Clone,
1876    Copy,
1877    Hash,
1878    PartialEq,
1879    Eq,
1880    HashStable_Generic,
1881    Encodable,
1882    Decodable,
1883    Default,
1884    PartialOrd,
1885    Ord
1886)]
1887pub struct StableSourceFileId(Hash128);
1888
1889impl StableSourceFileId {
1890    fn from_filename_in_current_crate(filename: &FileName) -> Self {
1891        Self::from_filename_and_stable_crate_id(filename, None)
1892    }
1893
1894    pub fn from_filename_for_export(
1895        filename: &FileName,
1896        local_crate_stable_crate_id: StableCrateId,
1897    ) -> Self {
1898        Self::from_filename_and_stable_crate_id(filename, Some(local_crate_stable_crate_id))
1899    }
1900
1901    fn from_filename_and_stable_crate_id(
1902        filename: &FileName,
1903        stable_crate_id: Option<StableCrateId>,
1904    ) -> Self {
1905        let mut hasher = StableHasher::new();
1906        filename.hash(&mut hasher);
1907        stable_crate_id.hash(&mut hasher);
1908        StableSourceFileId(hasher.finish())
1909    }
1910}
1911
1912impl SourceFile {
1913    const MAX_FILE_SIZE: u32 = u32::MAX - 1;
1914
1915    pub fn new(
1916        name: FileName,
1917        mut src: String,
1918        hash_kind: SourceFileHashAlgorithm,
1919        checksum_hash_kind: Option<SourceFileHashAlgorithm>,
1920    ) -> Result<Self, OffsetOverflowError> {
1921        // Compute the file hash before any normalization.
1922        let src_hash = SourceFileHash::new_in_memory(hash_kind, src.as_bytes());
1923        let checksum_hash = checksum_hash_kind.map(|checksum_hash_kind| {
1924            if checksum_hash_kind == hash_kind {
1925                src_hash
1926            } else {
1927                SourceFileHash::new_in_memory(checksum_hash_kind, src.as_bytes())
1928            }
1929        });
1930        let normalized_pos = normalize_src(&mut src);
1931
1932        let stable_id = StableSourceFileId::from_filename_in_current_crate(&name);
1933        let source_len = src.len();
1934        let source_len = u32::try_from(source_len).map_err(|_| OffsetOverflowError)?;
1935        if source_len > Self::MAX_FILE_SIZE {
1936            return Err(OffsetOverflowError);
1937        }
1938
1939        let (lines, multibyte_chars) = analyze_source_file::analyze_source_file(&src);
1940
1941        Ok(SourceFile {
1942            name,
1943            src: Some(Arc::new(src)),
1944            src_hash,
1945            checksum_hash,
1946            external_src: FreezeLock::frozen(ExternalSource::Unneeded),
1947            start_pos: BytePos::from_u32(0),
1948            source_len: RelativeBytePos::from_u32(source_len),
1949            lines: FreezeLock::frozen(SourceFileLines::Lines(lines)),
1950            multibyte_chars,
1951            normalized_pos,
1952            stable_id,
1953            cnum: LOCAL_CRATE,
1954        })
1955    }
1956
1957    /// This converts the `lines` field to contain `SourceFileLines::Lines` if needed and freezes
1958    /// it.
1959    fn convert_diffs_to_lines_frozen(&self) {
1960        let mut guard = if let Some(guard) = self.lines.try_write() { guard } else { return };
1961
1962        let SourceFileDiffs { bytes_per_diff, num_diffs, raw_diffs } = match &*guard {
1963            SourceFileLines::Diffs(diffs) => diffs,
1964            SourceFileLines::Lines(..) => {
1965                FreezeWriteGuard::freeze(guard);
1966                return;
1967            }
1968        };
1969
1970        // Convert from "diffs" form to "lines" form.
1971        let num_lines = num_diffs + 1;
1972        let mut lines = Vec::with_capacity(num_lines);
1973        let mut line_start = RelativeBytePos(0);
1974        lines.push(line_start);
1975
1976        assert_eq!(*num_diffs, raw_diffs.len() / bytes_per_diff);
1977        match bytes_per_diff {
1978            1 => {
1979                lines.extend(raw_diffs.into_iter().map(|&diff| {
1980                    line_start = line_start + RelativeBytePos(diff as u32);
1981                    line_start
1982                }));
1983            }
1984            2 => {
1985                lines.extend((0..*num_diffs).map(|i| {
1986                    let pos = bytes_per_diff * i;
1987                    let bytes = [raw_diffs[pos], raw_diffs[pos + 1]];
1988                    let diff = u16::from_le_bytes(bytes);
1989                    line_start = line_start + RelativeBytePos(diff as u32);
1990                    line_start
1991                }));
1992            }
1993            4 => {
1994                lines.extend((0..*num_diffs).map(|i| {
1995                    let pos = bytes_per_diff * i;
1996                    let bytes = [
1997                        raw_diffs[pos],
1998                        raw_diffs[pos + 1],
1999                        raw_diffs[pos + 2],
2000                        raw_diffs[pos + 3],
2001                    ];
2002                    let diff = u32::from_le_bytes(bytes);
2003                    line_start = line_start + RelativeBytePos(diff);
2004                    line_start
2005                }));
2006            }
2007            _ => unreachable!(),
2008        }
2009
2010        *guard = SourceFileLines::Lines(lines);
2011
2012        FreezeWriteGuard::freeze(guard);
2013    }
2014
2015    pub fn lines(&self) -> &[RelativeBytePos] {
2016        if let Some(SourceFileLines::Lines(lines)) = self.lines.get() {
2017            return &lines[..];
2018        }
2019
2020        outline(|| {
2021            self.convert_diffs_to_lines_frozen();
2022            if let Some(SourceFileLines::Lines(lines)) = self.lines.get() {
2023                return &lines[..];
2024            }
2025            unreachable!()
2026        })
2027    }
2028
2029    /// Returns the `BytePos` of the beginning of the current line.
2030    pub fn line_begin_pos(&self, pos: BytePos) -> BytePos {
2031        let pos = self.relative_position(pos);
2032        let line_index = self.lookup_line(pos).unwrap();
2033        let line_start_pos = self.lines()[line_index];
2034        self.absolute_position(line_start_pos)
2035    }
2036
2037    /// Add externally loaded source.
2038    /// If the hash of the input doesn't match or no input is supplied via None,
2039    /// it is interpreted as an error and the corresponding enum variant is set.
2040    /// The return value signifies whether some kind of source is present.
2041    pub fn add_external_src<F>(&self, get_src: F) -> bool
2042    where
2043        F: FnOnce() -> Option<String>,
2044    {
2045        if !self.external_src.is_frozen() {
2046            let src = get_src();
2047            let src = src.and_then(|mut src| {
2048                // The src_hash needs to be computed on the pre-normalized src.
2049                self.src_hash.matches(&src).then(|| {
2050                    normalize_src(&mut src);
2051                    src
2052                })
2053            });
2054
2055            self.external_src.try_write().map(|mut external_src| {
2056                if let ExternalSource::Foreign {
2057                    kind: src_kind @ ExternalSourceKind::AbsentOk,
2058                    ..
2059                } = &mut *external_src
2060                {
2061                    *src_kind = if let Some(src) = src {
2062                        ExternalSourceKind::Present(Arc::new(src))
2063                    } else {
2064                        ExternalSourceKind::AbsentErr
2065                    };
2066                } else {
2067                    panic!("unexpected state {:?}", *external_src)
2068                }
2069
2070                // Freeze this so we don't try to load the source again.
2071                FreezeWriteGuard::freeze(external_src)
2072            });
2073        }
2074
2075        self.src.is_some() || self.external_src.read().get_source().is_some()
2076    }
2077
2078    /// Gets a line from the list of pre-computed line-beginnings.
2079    /// The line number here is 0-based.
2080    pub fn get_line(&self, line_number: usize) -> Option<Cow<'_, str>> {
2081        fn get_until_newline(src: &str, begin: usize) -> &str {
2082            // We can't use `lines.get(line_number+1)` because we might
2083            // be parsing when we call this function and thus the current
2084            // line is the last one we have line info for.
2085            let slice = &src[begin..];
2086            match slice.find('\n') {
2087                Some(e) => &slice[..e],
2088                None => slice,
2089            }
2090        }
2091
2092        let begin = {
2093            let line = self.lines().get(line_number).copied()?;
2094            line.to_usize()
2095        };
2096
2097        if let Some(ref src) = self.src {
2098            Some(Cow::from(get_until_newline(src, begin)))
2099        } else {
2100            self.external_src
2101                .borrow()
2102                .get_source()
2103                .map(|src| Cow::Owned(String::from(get_until_newline(src, begin))))
2104        }
2105    }
2106
2107    pub fn is_real_file(&self) -> bool {
2108        self.name.is_real()
2109    }
2110
2111    #[inline]
2112    pub fn is_imported(&self) -> bool {
2113        self.src.is_none()
2114    }
2115
2116    pub fn count_lines(&self) -> usize {
2117        self.lines().len()
2118    }
2119
2120    #[inline]
2121    pub fn absolute_position(&self, pos: RelativeBytePos) -> BytePos {
2122        BytePos::from_u32(pos.to_u32() + self.start_pos.to_u32())
2123    }
2124
2125    #[inline]
2126    pub fn relative_position(&self, pos: BytePos) -> RelativeBytePos {
2127        RelativeBytePos::from_u32(pos.to_u32() - self.start_pos.to_u32())
2128    }
2129
2130    #[inline]
2131    pub fn end_position(&self) -> BytePos {
2132        self.absolute_position(self.source_len)
2133    }
2134
2135    /// Finds the line containing the given position. The return value is the
2136    /// index into the `lines` array of this `SourceFile`, not the 1-based line
2137    /// number. If the source_file is empty or the position is located before the
2138    /// first line, `None` is returned.
2139    pub fn lookup_line(&self, pos: RelativeBytePos) -> Option<usize> {
2140        self.lines().partition_point(|x| x <= &pos).checked_sub(1)
2141    }
2142
2143    pub fn line_bounds(&self, line_index: usize) -> Range<BytePos> {
2144        if self.is_empty() {
2145            return self.start_pos..self.start_pos;
2146        }
2147
2148        let lines = self.lines();
2149        assert!(line_index < lines.len());
2150        if line_index == (lines.len() - 1) {
2151            self.absolute_position(lines[line_index])..self.end_position()
2152        } else {
2153            self.absolute_position(lines[line_index])..self.absolute_position(lines[line_index + 1])
2154        }
2155    }
2156
2157    /// Returns whether or not the file contains the given `SourceMap` byte
2158    /// position. The position one past the end of the file is considered to be
2159    /// contained by the file. This implies that files for which `is_empty`
2160    /// returns true still contain one byte position according to this function.
2161    #[inline]
2162    pub fn contains(&self, byte_pos: BytePos) -> bool {
2163        byte_pos >= self.start_pos && byte_pos <= self.end_position()
2164    }
2165
2166    #[inline]
2167    pub fn is_empty(&self) -> bool {
2168        self.source_len.to_u32() == 0
2169    }
2170
2171    /// Calculates the original byte position relative to the start of the file
2172    /// based on the given byte position.
2173    pub fn original_relative_byte_pos(&self, pos: BytePos) -> RelativeBytePos {
2174        let pos = self.relative_position(pos);
2175
2176        // Diff before any records is 0. Otherwise use the previously recorded
2177        // diff as that applies to the following characters until a new diff
2178        // is recorded.
2179        let diff = match self.normalized_pos.binary_search_by(|np| np.pos.cmp(&pos)) {
2180            Ok(i) => self.normalized_pos[i].diff,
2181            Err(0) => 0,
2182            Err(i) => self.normalized_pos[i - 1].diff,
2183        };
2184
2185        RelativeBytePos::from_u32(pos.0 + diff)
2186    }
2187
2188    /// Calculates a normalized byte position from a byte offset relative to the
2189    /// start of the file.
2190    ///
2191    /// When we get an inline assembler error from LLVM during codegen, we
2192    /// import the expanded assembly code as a new `SourceFile`, which can then
2193    /// be used for error reporting with spans. However the byte offsets given
2194    /// to us by LLVM are relative to the start of the original buffer, not the
2195    /// normalized one. Hence we need to convert those offsets to the normalized
2196    /// form when constructing spans.
2197    pub fn normalized_byte_pos(&self, offset: u32) -> BytePos {
2198        let diff = match self
2199            .normalized_pos
2200            .binary_search_by(|np| (np.pos.0 + np.diff).cmp(&(self.start_pos.0 + offset)))
2201        {
2202            Ok(i) => self.normalized_pos[i].diff,
2203            Err(0) => 0,
2204            Err(i) => self.normalized_pos[i - 1].diff,
2205        };
2206
2207        BytePos::from_u32(self.start_pos.0 + offset - diff)
2208    }
2209
2210    /// Converts an relative `RelativeBytePos` to a `CharPos` relative to the `SourceFile`.
2211    fn bytepos_to_file_charpos(&self, bpos: RelativeBytePos) -> CharPos {
2212        // The number of extra bytes due to multibyte chars in the `SourceFile`.
2213        let mut total_extra_bytes = 0;
2214
2215        for mbc in self.multibyte_chars.iter() {
2216            debug!("{}-byte char at {:?}", mbc.bytes, mbc.pos);
2217            if mbc.pos < bpos {
2218                // Every character is at least one byte, so we only
2219                // count the actual extra bytes.
2220                total_extra_bytes += mbc.bytes as u32 - 1;
2221                // We should never see a byte position in the middle of a
2222                // character.
2223                assert!(bpos.to_u32() >= mbc.pos.to_u32() + mbc.bytes as u32);
2224            } else {
2225                break;
2226            }
2227        }
2228
2229        assert!(total_extra_bytes <= bpos.to_u32());
2230        CharPos(bpos.to_usize() - total_extra_bytes as usize)
2231    }
2232
2233    /// Looks up the file's (1-based) line number and (0-based `CharPos`) column offset, for a
2234    /// given `RelativeBytePos`.
2235    fn lookup_file_pos(&self, pos: RelativeBytePos) -> (usize, CharPos) {
2236        let chpos = self.bytepos_to_file_charpos(pos);
2237        match self.lookup_line(pos) {
2238            Some(a) => {
2239                let line = a + 1; // Line numbers start at 1
2240                let linebpos = self.lines()[a];
2241                let linechpos = self.bytepos_to_file_charpos(linebpos);
2242                let col = chpos - linechpos;
2243                debug!("byte pos {:?} is on the line at byte pos {:?}", pos, linebpos);
2244                debug!("char pos {:?} is on the line at char pos {:?}", chpos, linechpos);
2245                debug!("byte is on line: {}", line);
2246                assert!(chpos >= linechpos);
2247                (line, col)
2248            }
2249            None => (0, chpos),
2250        }
2251    }
2252
2253    /// Looks up the file's (1-based) line number, (0-based `CharPos`) column offset, and (0-based)
2254    /// column offset when displayed, for a given `BytePos`.
2255    pub fn lookup_file_pos_with_col_display(&self, pos: BytePos) -> (usize, CharPos, usize) {
2256        let pos = self.relative_position(pos);
2257        let (line, col_or_chpos) = self.lookup_file_pos(pos);
2258        if line > 0 {
2259            let Some(code) = self.get_line(line - 1) else {
2260                // If we don't have the code available, it is ok as a fallback to return the bytepos
2261                // instead of the "display" column, which is only used to properly show underlines
2262                // in the terminal.
2263                // FIXME: we'll want better handling of this in the future for the sake of tools
2264                // that want to use the display col instead of byte offsets to modify Rust code, but
2265                // that is a problem for another day, the previous code was already incorrect for
2266                // both displaying *and* third party tools using the json output naïvely.
2267                tracing::info!("couldn't find line {line} {:?}", self.name);
2268                return (line, col_or_chpos, col_or_chpos.0);
2269            };
2270            let display_col = code.chars().take(col_or_chpos.0).map(|ch| char_width(ch)).sum();
2271            (line, col_or_chpos, display_col)
2272        } else {
2273            // This is never meant to happen?
2274            (0, col_or_chpos, col_or_chpos.0)
2275        }
2276    }
2277}
2278
2279pub fn char_width(ch: char) -> usize {
2280    // FIXME: `unicode_width` sometimes disagrees with terminals on how wide a `char` is. For now,
2281    // just accept that sometimes the code line will be longer than desired.
2282    match ch {
2283        '\t' => 4,
2284        // Keep the following list in sync with `rustc_errors::emitter::OUTPUT_REPLACEMENTS`. These
2285        // are control points that we replace before printing with a visible codepoint for the sake
2286        // of being able to point at them with underlines.
2287        '\u{0000}' | '\u{0001}' | '\u{0002}' | '\u{0003}' | '\u{0004}' | '\u{0005}'
2288        | '\u{0006}' | '\u{0007}' | '\u{0008}' | '\u{000B}' | '\u{000C}' | '\u{000D}'
2289        | '\u{000E}' | '\u{000F}' | '\u{0010}' | '\u{0011}' | '\u{0012}' | '\u{0013}'
2290        | '\u{0014}' | '\u{0015}' | '\u{0016}' | '\u{0017}' | '\u{0018}' | '\u{0019}'
2291        | '\u{001A}' | '\u{001B}' | '\u{001C}' | '\u{001D}' | '\u{001E}' | '\u{001F}'
2292        | '\u{007F}' | '\u{202A}' | '\u{202B}' | '\u{202D}' | '\u{202E}' | '\u{2066}'
2293        | '\u{2067}' | '\u{2068}' | '\u{202C}' | '\u{2069}' => 1,
2294        _ => unicode_width::UnicodeWidthChar::width(ch).unwrap_or(1),
2295    }
2296}
2297
2298pub fn str_width(s: &str) -> usize {
2299    s.chars().map(char_width).sum()
2300}
2301
2302/// Normalizes the source code and records the normalizations.
2303fn normalize_src(src: &mut String) -> Vec<NormalizedPos> {
2304    let mut normalized_pos = vec![];
2305    remove_bom(src, &mut normalized_pos);
2306    normalize_newlines(src, &mut normalized_pos);
2307    normalized_pos
2308}
2309
2310/// Removes UTF-8 BOM, if any.
2311fn remove_bom(src: &mut String, normalized_pos: &mut Vec<NormalizedPos>) {
2312    if src.starts_with('\u{feff}') {
2313        src.drain(..3);
2314        normalized_pos.push(NormalizedPos { pos: RelativeBytePos(0), diff: 3 });
2315    }
2316}
2317
2318/// Replaces `\r\n` with `\n` in-place in `src`.
2319///
2320/// Leaves any occurrences of lone `\r` unchanged.
2321fn normalize_newlines(src: &mut String, normalized_pos: &mut Vec<NormalizedPos>) {
2322    if !src.as_bytes().contains(&b'\r') {
2323        return;
2324    }
2325
2326    // We replace `\r\n` with `\n` in-place, which doesn't break utf-8 encoding.
2327    // While we *can* call `as_mut_vec` and do surgery on the live string
2328    // directly, let's rather steal the contents of `src`. This makes the code
2329    // safe even if a panic occurs.
2330
2331    let mut buf = std::mem::replace(src, String::new()).into_bytes();
2332    let mut gap_len = 0;
2333    let mut tail = buf.as_mut_slice();
2334    let mut cursor = 0;
2335    let original_gap = normalized_pos.last().map_or(0, |l| l.diff);
2336    loop {
2337        let idx = match find_crlf(&tail[gap_len..]) {
2338            None => tail.len(),
2339            Some(idx) => idx + gap_len,
2340        };
2341        tail.copy_within(gap_len..idx, 0);
2342        tail = &mut tail[idx - gap_len..];
2343        if tail.len() == gap_len {
2344            break;
2345        }
2346        cursor += idx - gap_len;
2347        gap_len += 1;
2348        normalized_pos.push(NormalizedPos {
2349            pos: RelativeBytePos::from_usize(cursor + 1),
2350            diff: original_gap + gap_len as u32,
2351        });
2352    }
2353
2354    // Account for removed `\r`.
2355    // After `set_len`, `buf` is guaranteed to contain utf-8 again.
2356    let new_len = buf.len() - gap_len;
2357    unsafe {
2358        buf.set_len(new_len);
2359        *src = String::from_utf8_unchecked(buf);
2360    }
2361
2362    fn find_crlf(src: &[u8]) -> Option<usize> {
2363        let mut search_idx = 0;
2364        while let Some(idx) = find_cr(&src[search_idx..]) {
2365            if src[search_idx..].get(idx + 1) != Some(&b'\n') {
2366                search_idx += idx + 1;
2367                continue;
2368            }
2369            return Some(search_idx + idx);
2370        }
2371        None
2372    }
2373
2374    fn find_cr(src: &[u8]) -> Option<usize> {
2375        src.iter().position(|&b| b == b'\r')
2376    }
2377}
2378
2379// _____________________________________________________________________________
2380// Pos, BytePos, CharPos
2381//
2382
2383pub trait Pos {
2384    fn from_usize(n: usize) -> Self;
2385    fn to_usize(&self) -> usize;
2386    fn from_u32(n: u32) -> Self;
2387    fn to_u32(&self) -> u32;
2388}
2389
2390macro_rules! impl_pos {
2391    (
2392        $(
2393            $(#[$attr:meta])*
2394            $vis:vis struct $ident:ident($inner_vis:vis $inner_ty:ty);
2395        )*
2396    ) => {
2397        $(
2398            $(#[$attr])*
2399            $vis struct $ident($inner_vis $inner_ty);
2400
2401            impl Pos for $ident {
2402                #[inline(always)]
2403                fn from_usize(n: usize) -> $ident {
2404                    $ident(n as $inner_ty)
2405                }
2406
2407                #[inline(always)]
2408                fn to_usize(&self) -> usize {
2409                    self.0 as usize
2410                }
2411
2412                #[inline(always)]
2413                fn from_u32(n: u32) -> $ident {
2414                    $ident(n as $inner_ty)
2415                }
2416
2417                #[inline(always)]
2418                fn to_u32(&self) -> u32 {
2419                    self.0 as u32
2420                }
2421            }
2422
2423            impl Add for $ident {
2424                type Output = $ident;
2425
2426                #[inline(always)]
2427                fn add(self, rhs: $ident) -> $ident {
2428                    $ident(self.0 + rhs.0)
2429                }
2430            }
2431
2432            impl Sub for $ident {
2433                type Output = $ident;
2434
2435                #[inline(always)]
2436                fn sub(self, rhs: $ident) -> $ident {
2437                    $ident(self.0 - rhs.0)
2438                }
2439            }
2440        )*
2441    };
2442}
2443
2444impl_pos! {
2445    /// A byte offset.
2446    ///
2447    /// Keep this small (currently 32-bits), as AST contains a lot of them.
2448    #[derive(Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord, Debug)]
2449    pub struct BytePos(pub u32);
2450
2451    /// A byte offset relative to file beginning.
2452    #[derive(Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord, Debug)]
2453    pub struct RelativeBytePos(pub u32);
2454
2455    /// A character offset.
2456    ///
2457    /// Because of multibyte UTF-8 characters, a byte offset
2458    /// is not equivalent to a character offset. The [`SourceMap`] will convert [`BytePos`]
2459    /// values to `CharPos` values as necessary.
2460    #[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Debug)]
2461    pub struct CharPos(pub usize);
2462}
2463
2464impl<S: Encoder> Encodable<S> for BytePos {
2465    fn encode(&self, s: &mut S) {
2466        s.emit_u32(self.0);
2467    }
2468}
2469
2470impl<D: Decoder> Decodable<D> for BytePos {
2471    fn decode(d: &mut D) -> BytePos {
2472        BytePos(d.read_u32())
2473    }
2474}
2475
2476impl<H: HashStableContext> HashStable<H> for RelativeBytePos {
2477    fn hash_stable(&self, hcx: &mut H, hasher: &mut StableHasher) {
2478        self.0.hash_stable(hcx, hasher);
2479    }
2480}
2481
2482impl<S: Encoder> Encodable<S> for RelativeBytePos {
2483    fn encode(&self, s: &mut S) {
2484        s.emit_u32(self.0);
2485    }
2486}
2487
2488impl<D: Decoder> Decodable<D> for RelativeBytePos {
2489    fn decode(d: &mut D) -> RelativeBytePos {
2490        RelativeBytePos(d.read_u32())
2491    }
2492}
2493
2494// _____________________________________________________________________________
2495// Loc, SourceFileAndLine, SourceFileAndBytePos
2496//
2497
2498/// A source code location used for error reporting.
2499#[derive(Debug, Clone)]
2500pub struct Loc {
2501    /// Information about the original source.
2502    pub file: Arc<SourceFile>,
2503    /// The (1-based) line number.
2504    pub line: usize,
2505    /// The (0-based) column offset.
2506    pub col: CharPos,
2507    /// The (0-based) column offset when displayed.
2508    pub col_display: usize,
2509}
2510
2511// Used to be structural records.
2512#[derive(Debug)]
2513pub struct SourceFileAndLine {
2514    pub sf: Arc<SourceFile>,
2515    /// Index of line, starting from 0.
2516    pub line: usize,
2517}
2518#[derive(Debug)]
2519pub struct SourceFileAndBytePos {
2520    pub sf: Arc<SourceFile>,
2521    pub pos: BytePos,
2522}
2523
2524#[derive(Copy, Clone, Debug, PartialEq, Eq)]
2525pub struct LineInfo {
2526    /// Index of line, starting from 0.
2527    pub line_index: usize,
2528
2529    /// Column in line where span begins, starting from 0.
2530    pub start_col: CharPos,
2531
2532    /// Column in line where span ends, starting from 0, exclusive.
2533    pub end_col: CharPos,
2534}
2535
2536pub struct FileLines {
2537    pub file: Arc<SourceFile>,
2538    pub lines: Vec<LineInfo>,
2539}
2540
2541pub static SPAN_TRACK: AtomicRef<fn(LocalDefId)> = AtomicRef::new(&((|_| {}) as fn(_)));
2542
2543// _____________________________________________________________________________
2544// SpanLinesError, SpanSnippetError, DistinctSources, MalformedSourceMapPositions
2545//
2546
2547pub type FileLinesResult = Result<FileLines, SpanLinesError>;
2548
2549#[derive(Clone, PartialEq, Eq, Debug)]
2550pub enum SpanLinesError {
2551    DistinctSources(Box<DistinctSources>),
2552}
2553
2554#[derive(Clone, PartialEq, Eq, Debug)]
2555pub enum SpanSnippetError {
2556    IllFormedSpan(Span),
2557    DistinctSources(Box<DistinctSources>),
2558    MalformedForSourcemap(MalformedSourceMapPositions),
2559    SourceNotAvailable { filename: FileName },
2560}
2561
2562#[derive(Clone, PartialEq, Eq, Debug)]
2563pub struct DistinctSources {
2564    pub begin: (FileName, BytePos),
2565    pub end: (FileName, BytePos),
2566}
2567
2568#[derive(Clone, PartialEq, Eq, Debug)]
2569pub struct MalformedSourceMapPositions {
2570    pub name: FileName,
2571    pub source_len: usize,
2572    pub begin_pos: BytePos,
2573    pub end_pos: BytePos,
2574}
2575
2576/// Range inside of a `Span` used for diagnostics when we only have access to relative positions.
2577#[derive(Copy, Clone, PartialEq, Eq, Debug)]
2578pub struct InnerSpan {
2579    pub start: usize,
2580    pub end: usize,
2581}
2582
2583impl InnerSpan {
2584    pub fn new(start: usize, end: usize) -> InnerSpan {
2585        InnerSpan { start, end }
2586    }
2587}
2588
2589/// Requirements for a `StableHashingContext` to be used in this crate.
2590///
2591/// This is a hack to allow using the [`HashStable_Generic`] derive macro
2592/// instead of implementing everything in rustc_middle.
2593pub trait HashStableContext {
2594    fn def_path_hash(&self, def_id: DefId) -> DefPathHash;
2595    fn hash_spans(&self) -> bool;
2596    /// Accesses `sess.opts.unstable_opts.incremental_ignore_spans` since
2597    /// we don't have easy access to a `Session`
2598    fn unstable_opts_incremental_ignore_spans(&self) -> bool;
2599    fn def_span(&self, def_id: LocalDefId) -> Span;
2600    fn span_data_to_lines_and_cols(
2601        &mut self,
2602        span: &SpanData,
2603    ) -> Option<(StableSourceFileId, usize, BytePos, usize, BytePos)>;
2604    fn hashing_controls(&self) -> HashingControls;
2605}
2606
2607impl<CTX> HashStable<CTX> for Span
2608where
2609    CTX: HashStableContext,
2610{
2611    /// Hashes a span in a stable way. We can't directly hash the span's `BytePos`
2612    /// fields (that would be similar to hashing pointers, since those are just
2613    /// offsets into the `SourceMap`). Instead, we hash the (file name, line, column)
2614    /// triple, which stays the same even if the containing `SourceFile` has moved
2615    /// within the `SourceMap`.
2616    ///
2617    /// Also note that we are hashing byte offsets for the column, not unicode
2618    /// codepoint offsets. For the purpose of the hash that's sufficient.
2619    /// Also, hashing filenames is expensive so we avoid doing it twice when the
2620    /// span starts and ends in the same file, which is almost always the case.
2621    fn hash_stable(&self, ctx: &mut CTX, hasher: &mut StableHasher) {
2622        const TAG_VALID_SPAN: u8 = 0;
2623        const TAG_INVALID_SPAN: u8 = 1;
2624        const TAG_RELATIVE_SPAN: u8 = 2;
2625
2626        if !ctx.hash_spans() {
2627            return;
2628        }
2629
2630        let span = self.data_untracked();
2631        span.ctxt.hash_stable(ctx, hasher);
2632        span.parent.hash_stable(ctx, hasher);
2633
2634        if span.is_dummy() {
2635            Hash::hash(&TAG_INVALID_SPAN, hasher);
2636            return;
2637        }
2638
2639        if let Some(parent) = span.parent {
2640            let def_span = ctx.def_span(parent).data_untracked();
2641            if def_span.contains(span) {
2642                // This span is enclosed in a definition: only hash the relative position.
2643                Hash::hash(&TAG_RELATIVE_SPAN, hasher);
2644                (span.lo - def_span.lo).to_u32().hash_stable(ctx, hasher);
2645                (span.hi - def_span.lo).to_u32().hash_stable(ctx, hasher);
2646                return;
2647            }
2648        }
2649
2650        // If this is not an empty or invalid span, we want to hash the last
2651        // position that belongs to it, as opposed to hashing the first
2652        // position past it.
2653        let Some((file, line_lo, col_lo, line_hi, col_hi)) = ctx.span_data_to_lines_and_cols(&span)
2654        else {
2655            Hash::hash(&TAG_INVALID_SPAN, hasher);
2656            return;
2657        };
2658
2659        Hash::hash(&TAG_VALID_SPAN, hasher);
2660        Hash::hash(&file, hasher);
2661
2662        // Hash both the length and the end location (line/column) of a span. If we
2663        // hash only the length, for example, then two otherwise equal spans with
2664        // different end locations will have the same hash. This can cause a problem
2665        // during incremental compilation wherein a previous result for a query that
2666        // depends on the end location of a span will be incorrectly reused when the
2667        // end location of the span it depends on has changed (see issue #74890). A
2668        // similar analysis applies if some query depends specifically on the length
2669        // of the span, but we only hash the end location. So hash both.
2670
2671        let col_lo_trunc = (col_lo.0 as u64) & 0xFF;
2672        let line_lo_trunc = ((line_lo as u64) & 0xFF_FF_FF) << 8;
2673        let col_hi_trunc = (col_hi.0 as u64) & 0xFF << 32;
2674        let line_hi_trunc = ((line_hi as u64) & 0xFF_FF_FF) << 40;
2675        let col_line = col_lo_trunc | line_lo_trunc | col_hi_trunc | line_hi_trunc;
2676        let len = (span.hi - span.lo).0;
2677        Hash::hash(&col_line, hasher);
2678        Hash::hash(&len, hasher);
2679    }
2680}
2681
2682/// Useful type to use with `Result<>` indicate that an error has already
2683/// been reported to the user, so no need to continue checking.
2684///
2685/// The `()` field is necessary: it is non-`pub`, which means values of this
2686/// type cannot be constructed outside of this crate.
2687#[derive(Clone, Copy, Debug, Hash, PartialEq, Eq, PartialOrd, Ord)]
2688#[derive(HashStable_Generic)]
2689pub struct ErrorGuaranteed(());
2690
2691impl ErrorGuaranteed {
2692    /// Don't use this outside of `DiagCtxtInner::emit_diagnostic`!
2693    #[deprecated = "should only be used in `DiagCtxtInner::emit_diagnostic`"]
2694    pub fn unchecked_error_guaranteed() -> Self {
2695        ErrorGuaranteed(())
2696    }
2697
2698    pub fn raise_fatal(self) -> ! {
2699        FatalError.raise()
2700    }
2701}
2702
2703impl<E: rustc_serialize::Encoder> Encodable<E> for ErrorGuaranteed {
2704    #[inline]
2705    fn encode(&self, _e: &mut E) {
2706        panic!(
2707            "should never serialize an `ErrorGuaranteed`, as we do not write metadata or \
2708            incremental caches in case errors occurred"
2709        )
2710    }
2711}
2712impl<D: rustc_serialize::Decoder> Decodable<D> for ErrorGuaranteed {
2713    #[inline]
2714    fn decode(_d: &mut D) -> ErrorGuaranteed {
2715        panic!(
2716            "`ErrorGuaranteed` should never have been serialized to metadata or incremental caches"
2717        )
2718    }
2719}
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy