]> git.lizzy.rs Git - rust.git/blob - compiler/rustc_span/src/lib.rs
Rollup merge of #81465 - joshtriplett:duration-formatting-documentation, r=m-ou-se
[rust.git] / compiler / rustc_span / src / 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 in the [`sym`] module.
8 //!
9 //! Unlike most compilers, the span contains not only the position in the source code, but also various other metadata,
10 //! such as the edition and macro hygiene. This metadata is stored in [`SyntaxContext`] and [`ExpnData`].
11 //!
12 //! ## Note
13 //!
14 //! This API is completely unstable and subject to change.
15
16 #![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")]
17 #![feature(array_windows)]
18 #![feature(crate_visibility_modifier)]
19 #![feature(const_fn)]
20 #![feature(const_panic)]
21 #![feature(negative_impls)]
22 #![feature(nll)]
23 #![feature(min_specialization)]
24 #![feature(option_expect_none)]
25
26 #[macro_use]
27 extern crate rustc_macros;
28
29 use rustc_data_structures::AtomicRef;
30 use rustc_macros::HashStable_Generic;
31 use rustc_serialize::{Decodable, Decoder, Encodable, Encoder};
32
33 mod caching_source_map_view;
34 pub mod source_map;
35 pub use self::caching_source_map_view::CachingSourceMapView;
36 use source_map::SourceMap;
37
38 pub mod edition;
39 use edition::Edition;
40 pub mod hygiene;
41 pub use hygiene::SyntaxContext;
42 use hygiene::Transparency;
43 pub use hygiene::{DesugaringKind, ExpnData, ExpnId, ExpnKind, ForLoopLoc, MacroKind};
44 pub mod def_id;
45 use def_id::{CrateNum, DefId, LOCAL_CRATE};
46 pub mod lev_distance;
47 mod span_encoding;
48 pub use span_encoding::{Span, DUMMY_SP};
49
50 pub mod crate_disambiguator;
51
52 pub mod symbol;
53 pub use symbol::{sym, Symbol};
54
55 mod analyze_source_file;
56 pub mod fatal_error;
57
58 use rustc_data_structures::fingerprint::Fingerprint;
59 use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
60 use rustc_data_structures::sync::{Lock, Lrc};
61
62 use std::borrow::Cow;
63 use std::cell::RefCell;
64 use std::cmp::{self, Ordering};
65 use std::fmt;
66 use std::hash::Hash;
67 use std::ops::{Add, Range, Sub};
68 use std::path::{Path, PathBuf};
69 use std::str::FromStr;
70 use std::thread::LocalKey;
71
72 use md5::Md5;
73 use sha1::Digest;
74 use sha1::Sha1;
75 use sha2::Sha256;
76
77 use tracing::debug;
78
79 #[cfg(test)]
80 mod tests;
81
82 // Per-session global variables: this struct is stored in thread-local storage
83 // in such a way that it is accessible without any kind of handle to all
84 // threads within the compilation session, but is not accessible outside the
85 // session.
86 pub struct SessionGlobals {
87     symbol_interner: Lock<symbol::Interner>,
88     span_interner: Lock<span_encoding::SpanInterner>,
89     hygiene_data: Lock<hygiene::HygieneData>,
90     source_map: Lock<Option<Lrc<SourceMap>>>,
91 }
92
93 impl SessionGlobals {
94     pub fn new(edition: Edition) -> SessionGlobals {
95         SessionGlobals {
96             symbol_interner: Lock::new(symbol::Interner::fresh()),
97             span_interner: Lock::new(span_encoding::SpanInterner::default()),
98             hygiene_data: Lock::new(hygiene::HygieneData::new(edition)),
99             source_map: Lock::new(None),
100         }
101     }
102 }
103
104 pub fn with_session_globals<R>(edition: Edition, f: impl FnOnce() -> R) -> R {
105     let session_globals = SessionGlobals::new(edition);
106     SESSION_GLOBALS.set(&session_globals, f)
107 }
108
109 pub fn with_default_session_globals<R>(f: impl FnOnce() -> R) -> R {
110     with_session_globals(edition::DEFAULT_EDITION, f)
111 }
112
113 // If this ever becomes non thread-local, `decode_syntax_context`
114 // and `decode_expn_id` will need to be updated to handle concurrent
115 // deserialization.
116 scoped_tls::scoped_thread_local!(pub static SESSION_GLOBALS: SessionGlobals);
117
118 // FIXME: Perhaps this should not implement Rustc{Decodable, Encodable}
119 //
120 // FIXME: We should use this enum or something like it to get rid of the
121 // use of magic `/rust/1.x/...` paths across the board.
122 #[derive(Debug, Eq, PartialEq, Clone, Ord, PartialOrd, Hash)]
123 #[derive(HashStable_Generic, Decodable, Encodable)]
124 pub enum RealFileName {
125     Named(PathBuf),
126     /// For de-virtualized paths (namely paths into libstd that have been mapped
127     /// to the appropriate spot on the local host's file system),
128     Devirtualized {
129         /// `local_path` is the (host-dependent) local path to the file.
130         local_path: PathBuf,
131         /// `virtual_name` is the stable path rustc will store internally within
132         /// build artifacts.
133         virtual_name: PathBuf,
134     },
135 }
136
137 impl RealFileName {
138     /// Returns the path suitable for reading from the file system on the local host.
139     /// Avoid embedding this in build artifacts; see `stable_name()` for that.
140     pub fn local_path(&self) -> &Path {
141         match self {
142             RealFileName::Named(p)
143             | RealFileName::Devirtualized { local_path: p, virtual_name: _ } => &p,
144         }
145     }
146
147     /// Returns the path suitable for reading from the file system on the local host.
148     /// Avoid embedding this in build artifacts; see `stable_name()` for that.
149     pub fn into_local_path(self) -> PathBuf {
150         match self {
151             RealFileName::Named(p)
152             | RealFileName::Devirtualized { local_path: p, virtual_name: _ } => p,
153         }
154     }
155
156     /// Returns the path suitable for embedding into build artifacts. Note that
157     /// a virtualized path will not correspond to a valid file system path; see
158     /// `local_path()` for something that is more likely to return paths into the
159     /// local host file system.
160     pub fn stable_name(&self) -> &Path {
161         match self {
162             RealFileName::Named(p)
163             | RealFileName::Devirtualized { local_path: _, virtual_name: p } => &p,
164         }
165     }
166 }
167
168 /// Differentiates between real files and common virtual files.
169 #[derive(Debug, Eq, PartialEq, Clone, Ord, PartialOrd, Hash)]
170 #[derive(HashStable_Generic, Decodable, Encodable)]
171 pub enum FileName {
172     Real(RealFileName),
173     /// Call to `quote!`.
174     QuoteExpansion(u64),
175     /// Command line.
176     Anon(u64),
177     /// Hack in `src/librustc_ast/parse.rs`.
178     // FIXME(jseyfried)
179     MacroExpansion(u64),
180     ProcMacroSourceCode(u64),
181     /// Strings provided as `--cfg [cfgspec]` stored in a `crate_cfg`.
182     CfgSpec(u64),
183     /// Strings provided as crate attributes in the CLI.
184     CliCrateAttr(u64),
185     /// Custom sources for explicit parser calls from plugins and drivers.
186     Custom(String),
187     DocTest(PathBuf, isize),
188     /// Post-substitution inline assembly from LLVM.
189     InlineAsm(u64),
190 }
191
192 impl std::fmt::Display for FileName {
193     fn fmt(&self, fmt: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
194         use FileName::*;
195         match *self {
196             Real(RealFileName::Named(ref path)) => write!(fmt, "{}", path.display()),
197             // FIXME: might be nice to display both components of Devirtualized.
198             // But for now (to backport fix for issue #70924), best to not
199             // perturb diagnostics so its obvious test suite still works.
200             Real(RealFileName::Devirtualized { ref local_path, virtual_name: _ }) => {
201                 write!(fmt, "{}", local_path.display())
202             }
203             QuoteExpansion(_) => write!(fmt, "<quote expansion>"),
204             MacroExpansion(_) => write!(fmt, "<macro expansion>"),
205             Anon(_) => write!(fmt, "<anon>"),
206             ProcMacroSourceCode(_) => write!(fmt, "<proc-macro source code>"),
207             CfgSpec(_) => write!(fmt, "<cfgspec>"),
208             CliCrateAttr(_) => write!(fmt, "<crate attribute>"),
209             Custom(ref s) => write!(fmt, "<{}>", s),
210             DocTest(ref path, _) => write!(fmt, "{}", path.display()),
211             InlineAsm(_) => write!(fmt, "<inline asm>"),
212         }
213     }
214 }
215
216 impl From<PathBuf> for FileName {
217     fn from(p: PathBuf) -> Self {
218         assert!(!p.to_string_lossy().ends_with('>'));
219         FileName::Real(RealFileName::Named(p))
220     }
221 }
222
223 impl FileName {
224     pub fn is_real(&self) -> bool {
225         use FileName::*;
226         match *self {
227             Real(_) => true,
228             Anon(_)
229             | MacroExpansion(_)
230             | ProcMacroSourceCode(_)
231             | CfgSpec(_)
232             | CliCrateAttr(_)
233             | Custom(_)
234             | QuoteExpansion(_)
235             | DocTest(_, _)
236             | InlineAsm(_) => false,
237         }
238     }
239
240     pub fn macro_expansion_source_code(src: &str) -> FileName {
241         let mut hasher = StableHasher::new();
242         src.hash(&mut hasher);
243         FileName::MacroExpansion(hasher.finish())
244     }
245
246     pub fn anon_source_code(src: &str) -> FileName {
247         let mut hasher = StableHasher::new();
248         src.hash(&mut hasher);
249         FileName::Anon(hasher.finish())
250     }
251
252     pub fn proc_macro_source_code(src: &str) -> FileName {
253         let mut hasher = StableHasher::new();
254         src.hash(&mut hasher);
255         FileName::ProcMacroSourceCode(hasher.finish())
256     }
257
258     pub fn cfg_spec_source_code(src: &str) -> FileName {
259         let mut hasher = StableHasher::new();
260         src.hash(&mut hasher);
261         FileName::QuoteExpansion(hasher.finish())
262     }
263
264     pub fn cli_crate_attr_source_code(src: &str) -> FileName {
265         let mut hasher = StableHasher::new();
266         src.hash(&mut hasher);
267         FileName::CliCrateAttr(hasher.finish())
268     }
269
270     pub fn doc_test_source_code(path: PathBuf, line: isize) -> FileName {
271         FileName::DocTest(path, line)
272     }
273
274     pub fn inline_asm_source_code(src: &str) -> FileName {
275         let mut hasher = StableHasher::new();
276         src.hash(&mut hasher);
277         FileName::InlineAsm(hasher.finish())
278     }
279 }
280
281 /// Represents a span.
282 ///
283 /// Spans represent a region of code, used for error reporting. Positions in spans
284 /// are *absolute* positions from the beginning of the [`SourceMap`], not positions
285 /// relative to [`SourceFile`]s. Methods on the `SourceMap` can be used to relate spans back
286 /// to the original source.
287 ///
288 /// You must be careful if the span crosses more than one file, since you will not be
289 /// able to use many of the functions on spans in source_map and you cannot assume
290 /// that the length of the span is equal to `span.hi - span.lo`; there may be space in the
291 /// [`BytePos`] range between files.
292 ///
293 /// `SpanData` is public because `Span` uses a thread-local interner and can't be
294 /// sent to other threads, but some pieces of performance infra run in a separate thread.
295 /// Using `Span` is generally preferred.
296 #[derive(Clone, Copy, Hash, PartialEq, Eq, Ord, PartialOrd)]
297 pub struct SpanData {
298     pub lo: BytePos,
299     pub hi: BytePos,
300     /// Information about where the macro came from, if this piece of
301     /// code was created by a macro expansion.
302     pub ctxt: SyntaxContext,
303 }
304
305 impl SpanData {
306     #[inline]
307     pub fn span(&self) -> Span {
308         Span::new(self.lo, self.hi, self.ctxt)
309     }
310     #[inline]
311     pub fn with_lo(&self, lo: BytePos) -> Span {
312         Span::new(lo, self.hi, self.ctxt)
313     }
314     #[inline]
315     pub fn with_hi(&self, hi: BytePos) -> Span {
316         Span::new(self.lo, hi, self.ctxt)
317     }
318     #[inline]
319     pub fn with_ctxt(&self, ctxt: SyntaxContext) -> Span {
320         Span::new(self.lo, self.hi, ctxt)
321     }
322 }
323
324 // The interner is pointed to by a thread local value which is only set on the main thread
325 // with parallelization is disabled. So we don't allow `Span` to transfer between threads
326 // to avoid panics and other errors, even though it would be memory safe to do so.
327 #[cfg(not(parallel_compiler))]
328 impl !Send for Span {}
329 #[cfg(not(parallel_compiler))]
330 impl !Sync for Span {}
331
332 impl PartialOrd for Span {
333     fn partial_cmp(&self, rhs: &Self) -> Option<Ordering> {
334         PartialOrd::partial_cmp(&self.data(), &rhs.data())
335     }
336 }
337 impl Ord for Span {
338     fn cmp(&self, rhs: &Self) -> Ordering {
339         Ord::cmp(&self.data(), &rhs.data())
340     }
341 }
342
343 /// A collection of `Span`s.
344 ///
345 /// Spans have two orthogonal attributes:
346 ///
347 /// - They can be *primary spans*. In this case they are the locus of
348 ///   the error, and would be rendered with `^^^`.
349 /// - They can have a *label*. In this case, the label is written next
350 ///   to the mark in the snippet when we render.
351 #[derive(Clone, Debug, Hash, PartialEq, Eq, Encodable, Decodable)]
352 pub struct MultiSpan {
353     primary_spans: Vec<Span>,
354     span_labels: Vec<(Span, String)>,
355 }
356
357 impl Span {
358     #[inline]
359     pub fn lo(self) -> BytePos {
360         self.data().lo
361     }
362     #[inline]
363     pub fn with_lo(self, lo: BytePos) -> Span {
364         self.data().with_lo(lo)
365     }
366     #[inline]
367     pub fn hi(self) -> BytePos {
368         self.data().hi
369     }
370     #[inline]
371     pub fn with_hi(self, hi: BytePos) -> Span {
372         self.data().with_hi(hi)
373     }
374     #[inline]
375     pub fn ctxt(self) -> SyntaxContext {
376         self.data().ctxt
377     }
378     #[inline]
379     pub fn with_ctxt(self, ctxt: SyntaxContext) -> Span {
380         self.data().with_ctxt(ctxt)
381     }
382
383     /// Returns `true` if this is a dummy span with any hygienic context.
384     #[inline]
385     pub fn is_dummy(self) -> bool {
386         let span = self.data();
387         span.lo.0 == 0 && span.hi.0 == 0
388     }
389
390     /// Returns `true` if this span comes from a macro or desugaring.
391     #[inline]
392     pub fn from_expansion(self) -> bool {
393         self.ctxt() != SyntaxContext::root()
394     }
395
396     /// Returns `true` if `span` originates in a derive-macro's expansion.
397     pub fn in_derive_expansion(self) -> bool {
398         matches!(self.ctxt().outer_expn_data().kind, ExpnKind::Macro(MacroKind::Derive, _))
399     }
400
401     #[inline]
402     pub fn with_root_ctxt(lo: BytePos, hi: BytePos) -> Span {
403         Span::new(lo, hi, SyntaxContext::root())
404     }
405
406     /// Returns a new span representing an empty span at the beginning of this span.
407     #[inline]
408     pub fn shrink_to_lo(self) -> Span {
409         let span = self.data();
410         span.with_hi(span.lo)
411     }
412     /// Returns a new span representing an empty span at the end of this span.
413     #[inline]
414     pub fn shrink_to_hi(self) -> Span {
415         let span = self.data();
416         span.with_lo(span.hi)
417     }
418
419     #[inline]
420     /// Returns `true` if `hi == lo`.
421     pub fn is_empty(&self) -> bool {
422         let span = self.data();
423         span.hi == span.lo
424     }
425
426     /// Returns `self` if `self` is not the dummy span, and `other` otherwise.
427     pub fn substitute_dummy(self, other: Span) -> Span {
428         if self.is_dummy() { other } else { self }
429     }
430
431     /// Returns `true` if `self` fully encloses `other`.
432     pub fn contains(self, other: Span) -> bool {
433         let span = self.data();
434         let other = other.data();
435         span.lo <= other.lo && other.hi <= span.hi
436     }
437
438     /// Returns `true` if `self` touches `other`.
439     pub fn overlaps(self, other: Span) -> bool {
440         let span = self.data();
441         let other = other.data();
442         span.lo < other.hi && other.lo < span.hi
443     }
444
445     /// Returns `true` if the spans are equal with regards to the source text.
446     ///
447     /// Use this instead of `==` when either span could be generated code,
448     /// and you only care that they point to the same bytes of source text.
449     pub fn source_equal(&self, other: &Span) -> bool {
450         let span = self.data();
451         let other = other.data();
452         span.lo == other.lo && span.hi == other.hi
453     }
454
455     /// Returns `Some(span)`, where the start is trimmed by the end of `other`.
456     pub fn trim_start(self, other: Span) -> Option<Span> {
457         let span = self.data();
458         let other = other.data();
459         if span.hi > other.hi { Some(span.with_lo(cmp::max(span.lo, other.hi))) } else { None }
460     }
461
462     /// Returns the source span -- this is either the supplied span, or the span for
463     /// the macro callsite that expanded to it.
464     pub fn source_callsite(self) -> Span {
465         let expn_data = self.ctxt().outer_expn_data();
466         if !expn_data.is_root() { expn_data.call_site.source_callsite() } else { self }
467     }
468
469     /// The `Span` for the tokens in the previous macro expansion from which `self` was generated,
470     /// if any.
471     pub fn parent(self) -> Option<Span> {
472         let expn_data = self.ctxt().outer_expn_data();
473         if !expn_data.is_root() { Some(expn_data.call_site) } else { None }
474     }
475
476     /// Edition of the crate from which this span came.
477     pub fn edition(self) -> edition::Edition {
478         self.ctxt().edition()
479     }
480
481     #[inline]
482     pub fn rust_2015(&self) -> bool {
483         self.edition() == edition::Edition::Edition2015
484     }
485
486     #[inline]
487     pub fn rust_2018(&self) -> bool {
488         self.edition() >= edition::Edition::Edition2018
489     }
490
491     #[inline]
492     pub fn rust_2021(&self) -> bool {
493         self.edition() >= edition::Edition::Edition2021
494     }
495
496     /// Returns the source callee.
497     ///
498     /// Returns `None` if the supplied span has no expansion trace,
499     /// else returns the `ExpnData` for the macro definition
500     /// corresponding to the source callsite.
501     pub fn source_callee(self) -> Option<ExpnData> {
502         fn source_callee(expn_data: ExpnData) -> ExpnData {
503             let next_expn_data = expn_data.call_site.ctxt().outer_expn_data();
504             if !next_expn_data.is_root() { source_callee(next_expn_data) } else { expn_data }
505         }
506         let expn_data = self.ctxt().outer_expn_data();
507         if !expn_data.is_root() { Some(source_callee(expn_data)) } else { None }
508     }
509
510     /// Checks if a span is "internal" to a macro in which `#[unstable]`
511     /// items can be used (that is, a macro marked with
512     /// `#[allow_internal_unstable]`).
513     pub fn allows_unstable(&self, feature: Symbol) -> bool {
514         self.ctxt()
515             .outer_expn_data()
516             .allow_internal_unstable
517             .map_or(false, |features| features.iter().any(|&f| f == feature))
518     }
519
520     /// Checks if this span arises from a compiler desugaring of kind `kind`.
521     pub fn is_desugaring(&self, kind: DesugaringKind) -> bool {
522         match self.ctxt().outer_expn_data().kind {
523             ExpnKind::Desugaring(k) => k == kind,
524             _ => false,
525         }
526     }
527
528     /// Returns the compiler desugaring that created this span, or `None`
529     /// if this span is not from a desugaring.
530     pub fn desugaring_kind(&self) -> Option<DesugaringKind> {
531         match self.ctxt().outer_expn_data().kind {
532             ExpnKind::Desugaring(k) => Some(k),
533             _ => None,
534         }
535     }
536
537     /// Checks if a span is "internal" to a macro in which `unsafe`
538     /// can be used without triggering the `unsafe_code` lint.
539     //  (that is, a macro marked with `#[allow_internal_unsafe]`).
540     pub fn allows_unsafe(&self) -> bool {
541         self.ctxt().outer_expn_data().allow_internal_unsafe
542     }
543
544     pub fn macro_backtrace(mut self) -> impl Iterator<Item = ExpnData> {
545         let mut prev_span = DUMMY_SP;
546         std::iter::from_fn(move || {
547             loop {
548                 let expn_data = self.ctxt().outer_expn_data();
549                 if expn_data.is_root() {
550                     return None;
551                 }
552
553                 let is_recursive = expn_data.call_site.source_equal(&prev_span);
554
555                 prev_span = self;
556                 self = expn_data.call_site;
557
558                 // Don't print recursive invocations.
559                 if !is_recursive {
560                     return Some(expn_data);
561                 }
562             }
563         })
564     }
565
566     /// Returns a `Span` that would enclose both `self` and `end`.
567     ///
568     /// ```text
569     ///     ____             ___
570     ///     self lorem ipsum end
571     ///     ^^^^^^^^^^^^^^^^^^^^
572     /// ```
573     pub fn to(self, end: Span) -> Span {
574         let span_data = self.data();
575         let end_data = end.data();
576         // FIXME(jseyfried): `self.ctxt` should always equal `end.ctxt` here (cf. issue #23480).
577         // Return the macro span on its own to avoid weird diagnostic output. It is preferable to
578         // have an incomplete span than a completely nonsensical one.
579         if span_data.ctxt != end_data.ctxt {
580             if span_data.ctxt == SyntaxContext::root() {
581                 return end;
582             } else if end_data.ctxt == SyntaxContext::root() {
583                 return self;
584             }
585             // Both spans fall within a macro.
586             // FIXME(estebank): check if it is the *same* macro.
587         }
588         Span::new(
589             cmp::min(span_data.lo, end_data.lo),
590             cmp::max(span_data.hi, end_data.hi),
591             if span_data.ctxt == SyntaxContext::root() { end_data.ctxt } else { span_data.ctxt },
592         )
593     }
594
595     /// Returns a `Span` between the end of `self` to the beginning of `end`.
596     ///
597     /// ```text
598     ///     ____             ___
599     ///     self lorem ipsum end
600     ///         ^^^^^^^^^^^^^
601     /// ```
602     pub fn between(self, end: Span) -> Span {
603         let span = self.data();
604         let end = end.data();
605         Span::new(
606             span.hi,
607             end.lo,
608             if end.ctxt == SyntaxContext::root() { end.ctxt } else { span.ctxt },
609         )
610     }
611
612     /// Returns a `Span` from the beginning of `self` until the beginning of `end`.
613     ///
614     /// ```text
615     ///     ____             ___
616     ///     self lorem ipsum end
617     ///     ^^^^^^^^^^^^^^^^^
618     /// ```
619     pub fn until(self, end: Span) -> Span {
620         let span = self.data();
621         let end = end.data();
622         Span::new(
623             span.lo,
624             end.lo,
625             if end.ctxt == SyntaxContext::root() { end.ctxt } else { span.ctxt },
626         )
627     }
628
629     pub fn from_inner(self, inner: InnerSpan) -> Span {
630         let span = self.data();
631         Span::new(
632             span.lo + BytePos::from_usize(inner.start),
633             span.lo + BytePos::from_usize(inner.end),
634             span.ctxt,
635         )
636     }
637
638     /// Equivalent of `Span::def_site` from the proc macro API,
639     /// except that the location is taken from the `self` span.
640     pub fn with_def_site_ctxt(self, expn_id: ExpnId) -> Span {
641         self.with_ctxt_from_mark(expn_id, Transparency::Opaque)
642     }
643
644     /// Equivalent of `Span::call_site` from the proc macro API,
645     /// except that the location is taken from the `self` span.
646     pub fn with_call_site_ctxt(&self, expn_id: ExpnId) -> Span {
647         self.with_ctxt_from_mark(expn_id, Transparency::Transparent)
648     }
649
650     /// Equivalent of `Span::mixed_site` from the proc macro API,
651     /// except that the location is taken from the `self` span.
652     pub fn with_mixed_site_ctxt(&self, expn_id: ExpnId) -> Span {
653         self.with_ctxt_from_mark(expn_id, Transparency::SemiTransparent)
654     }
655
656     /// Produces a span with the same location as `self` and context produced by a macro with the
657     /// given ID and transparency, assuming that macro was defined directly and not produced by
658     /// some other macro (which is the case for built-in and procedural macros).
659     pub fn with_ctxt_from_mark(self, expn_id: ExpnId, transparency: Transparency) -> Span {
660         self.with_ctxt(SyntaxContext::root().apply_mark(expn_id, transparency))
661     }
662
663     #[inline]
664     pub fn apply_mark(self, expn_id: ExpnId, transparency: Transparency) -> Span {
665         let span = self.data();
666         span.with_ctxt(span.ctxt.apply_mark(expn_id, transparency))
667     }
668
669     #[inline]
670     pub fn remove_mark(&mut self) -> ExpnId {
671         let mut span = self.data();
672         let mark = span.ctxt.remove_mark();
673         *self = Span::new(span.lo, span.hi, span.ctxt);
674         mark
675     }
676
677     #[inline]
678     pub fn adjust(&mut self, expn_id: ExpnId) -> Option<ExpnId> {
679         let mut span = self.data();
680         let mark = span.ctxt.adjust(expn_id);
681         *self = Span::new(span.lo, span.hi, span.ctxt);
682         mark
683     }
684
685     #[inline]
686     pub fn normalize_to_macros_2_0_and_adjust(&mut self, expn_id: ExpnId) -> Option<ExpnId> {
687         let mut span = self.data();
688         let mark = span.ctxt.normalize_to_macros_2_0_and_adjust(expn_id);
689         *self = Span::new(span.lo, span.hi, span.ctxt);
690         mark
691     }
692
693     #[inline]
694     pub fn glob_adjust(&mut self, expn_id: ExpnId, glob_span: Span) -> Option<Option<ExpnId>> {
695         let mut span = self.data();
696         let mark = span.ctxt.glob_adjust(expn_id, glob_span);
697         *self = Span::new(span.lo, span.hi, span.ctxt);
698         mark
699     }
700
701     #[inline]
702     pub fn reverse_glob_adjust(
703         &mut self,
704         expn_id: ExpnId,
705         glob_span: Span,
706     ) -> Option<Option<ExpnId>> {
707         let mut span = self.data();
708         let mark = span.ctxt.reverse_glob_adjust(expn_id, glob_span);
709         *self = Span::new(span.lo, span.hi, span.ctxt);
710         mark
711     }
712
713     #[inline]
714     pub fn normalize_to_macros_2_0(self) -> Span {
715         let span = self.data();
716         span.with_ctxt(span.ctxt.normalize_to_macros_2_0())
717     }
718
719     #[inline]
720     pub fn normalize_to_macro_rules(self) -> Span {
721         let span = self.data();
722         span.with_ctxt(span.ctxt.normalize_to_macro_rules())
723     }
724 }
725
726 /// A span together with some additional data.
727 #[derive(Clone, Debug)]
728 pub struct SpanLabel {
729     /// The span we are going to include in the final snippet.
730     pub span: Span,
731
732     /// Is this a primary span? This is the "locus" of the message,
733     /// and is indicated with a `^^^^` underline, versus `----`.
734     pub is_primary: bool,
735
736     /// What label should we attach to this span (if any)?
737     pub label: Option<String>,
738 }
739
740 impl Default for Span {
741     fn default() -> Self {
742         DUMMY_SP
743     }
744 }
745
746 impl<E: Encoder> Encodable<E> for Span {
747     default fn encode(&self, s: &mut E) -> Result<(), E::Error> {
748         let span = self.data();
749         s.emit_struct("Span", 2, |s| {
750             s.emit_struct_field("lo", 0, |s| span.lo.encode(s))?;
751             s.emit_struct_field("hi", 1, |s| span.hi.encode(s))
752         })
753     }
754 }
755 impl<D: Decoder> Decodable<D> for Span {
756     default fn decode(s: &mut D) -> Result<Span, D::Error> {
757         s.read_struct("Span", 2, |d| {
758             let lo = d.read_struct_field("lo", 0, Decodable::decode)?;
759             let hi = d.read_struct_field("hi", 1, Decodable::decode)?;
760
761             Ok(Span::new(lo, hi, SyntaxContext::root()))
762         })
763     }
764 }
765
766 /// Calls the provided closure, using the provided `SourceMap` to format
767 /// any spans that are debug-printed during the closure's execution.
768 ///
769 /// Normally, the global `TyCtxt` is used to retrieve the `SourceMap`
770 /// (see `rustc_interface::callbacks::span_debug1`). However, some parts
771 /// of the compiler (e.g. `rustc_parse`) may debug-print `Span`s before
772 /// a `TyCtxt` is available. In this case, we fall back to
773 /// the `SourceMap` provided to this function. If that is not available,
774 /// we fall back to printing the raw `Span` field values.
775 pub fn with_source_map<T, F: FnOnce() -> T>(source_map: Lrc<SourceMap>, f: F) -> T {
776     SESSION_GLOBALS.with(|session_globals| {
777         *session_globals.source_map.borrow_mut() = Some(source_map);
778     });
779     struct ClearSourceMap;
780     impl Drop for ClearSourceMap {
781         fn drop(&mut self) {
782             SESSION_GLOBALS.with(|session_globals| {
783                 session_globals.source_map.borrow_mut().take();
784             });
785         }
786     }
787
788     let _guard = ClearSourceMap;
789     f()
790 }
791
792 pub fn debug_with_source_map(
793     span: Span,
794     f: &mut fmt::Formatter<'_>,
795     source_map: &SourceMap,
796 ) -> fmt::Result {
797     write!(f, "{} ({:?})", source_map.span_to_string(span), span.ctxt())
798 }
799
800 pub fn default_span_debug(span: Span, f: &mut fmt::Formatter<'_>) -> fmt::Result {
801     SESSION_GLOBALS.with(|session_globals| {
802         if let Some(source_map) = &*session_globals.source_map.borrow() {
803             debug_with_source_map(span, f, source_map)
804         } else {
805             f.debug_struct("Span")
806                 .field("lo", &span.lo())
807                 .field("hi", &span.hi())
808                 .field("ctxt", &span.ctxt())
809                 .finish()
810         }
811     })
812 }
813
814 impl fmt::Debug for Span {
815     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
816         (*SPAN_DEBUG)(*self, f)
817     }
818 }
819
820 impl fmt::Debug for SpanData {
821     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
822         (*SPAN_DEBUG)(Span::new(self.lo, self.hi, self.ctxt), f)
823     }
824 }
825
826 impl MultiSpan {
827     #[inline]
828     pub fn new() -> MultiSpan {
829         MultiSpan { primary_spans: vec![], span_labels: vec![] }
830     }
831
832     pub fn from_span(primary_span: Span) -> MultiSpan {
833         MultiSpan { primary_spans: vec![primary_span], span_labels: vec![] }
834     }
835
836     pub fn from_spans(mut vec: Vec<Span>) -> MultiSpan {
837         vec.sort();
838         MultiSpan { primary_spans: vec, span_labels: vec![] }
839     }
840
841     pub fn push_span_label(&mut self, span: Span, label: String) {
842         self.span_labels.push((span, label));
843     }
844
845     /// Selects the first primary span (if any).
846     pub fn primary_span(&self) -> Option<Span> {
847         self.primary_spans.first().cloned()
848     }
849
850     /// Returns all primary spans.
851     pub fn primary_spans(&self) -> &[Span] {
852         &self.primary_spans
853     }
854
855     /// Returns `true` if any of the primary spans are displayable.
856     pub fn has_primary_spans(&self) -> bool {
857         self.primary_spans.iter().any(|sp| !sp.is_dummy())
858     }
859
860     /// Returns `true` if this contains only a dummy primary span with any hygienic context.
861     pub fn is_dummy(&self) -> bool {
862         let mut is_dummy = true;
863         for span in &self.primary_spans {
864             if !span.is_dummy() {
865                 is_dummy = false;
866             }
867         }
868         is_dummy
869     }
870
871     /// Replaces all occurrences of one Span with another. Used to move `Span`s in areas that don't
872     /// display well (like std macros). Returns whether replacements occurred.
873     pub fn replace(&mut self, before: Span, after: Span) -> bool {
874         let mut replacements_occurred = false;
875         for primary_span in &mut self.primary_spans {
876             if *primary_span == before {
877                 *primary_span = after;
878                 replacements_occurred = true;
879             }
880         }
881         for span_label in &mut self.span_labels {
882             if span_label.0 == before {
883                 span_label.0 = after;
884                 replacements_occurred = true;
885             }
886         }
887         replacements_occurred
888     }
889
890     /// Returns the strings to highlight. We always ensure that there
891     /// is an entry for each of the primary spans -- for each primary
892     /// span `P`, if there is at least one label with span `P`, we return
893     /// those labels (marked as primary). But otherwise we return
894     /// `SpanLabel` instances with empty labels.
895     pub fn span_labels(&self) -> Vec<SpanLabel> {
896         let is_primary = |span| self.primary_spans.contains(&span);
897
898         let mut span_labels = self
899             .span_labels
900             .iter()
901             .map(|&(span, ref label)| SpanLabel {
902                 span,
903                 is_primary: is_primary(span),
904                 label: Some(label.clone()),
905             })
906             .collect::<Vec<_>>();
907
908         for &span in &self.primary_spans {
909             if !span_labels.iter().any(|sl| sl.span == span) {
910                 span_labels.push(SpanLabel { span, is_primary: true, label: None });
911             }
912         }
913
914         span_labels
915     }
916
917     /// Returns `true` if any of the span labels is displayable.
918     pub fn has_span_labels(&self) -> bool {
919         self.span_labels.iter().any(|(sp, _)| !sp.is_dummy())
920     }
921 }
922
923 impl From<Span> for MultiSpan {
924     fn from(span: Span) -> MultiSpan {
925         MultiSpan::from_span(span)
926     }
927 }
928
929 impl From<Vec<Span>> for MultiSpan {
930     fn from(spans: Vec<Span>) -> MultiSpan {
931         MultiSpan::from_spans(spans)
932     }
933 }
934
935 /// Identifies an offset of a multi-byte character in a `SourceFile`.
936 #[derive(Copy, Clone, Encodable, Decodable, Eq, PartialEq, Debug)]
937 pub struct MultiByteChar {
938     /// The absolute offset of the character in the `SourceMap`.
939     pub pos: BytePos,
940     /// The number of bytes, `>= 2`.
941     pub bytes: u8,
942 }
943
944 /// Identifies an offset of a non-narrow character in a `SourceFile`.
945 #[derive(Copy, Clone, Encodable, Decodable, Eq, PartialEq, Debug)]
946 pub enum NonNarrowChar {
947     /// Represents a zero-width character.
948     ZeroWidth(BytePos),
949     /// Represents a wide (full-width) character.
950     Wide(BytePos),
951     /// Represents a tab character, represented visually with a width of 4 characters.
952     Tab(BytePos),
953 }
954
955 impl NonNarrowChar {
956     fn new(pos: BytePos, width: usize) -> Self {
957         match width {
958             0 => NonNarrowChar::ZeroWidth(pos),
959             2 => NonNarrowChar::Wide(pos),
960             4 => NonNarrowChar::Tab(pos),
961             _ => panic!("width {} given for non-narrow character", width),
962         }
963     }
964
965     /// Returns the absolute offset of the character in the `SourceMap`.
966     pub fn pos(&self) -> BytePos {
967         match *self {
968             NonNarrowChar::ZeroWidth(p) | NonNarrowChar::Wide(p) | NonNarrowChar::Tab(p) => p,
969         }
970     }
971
972     /// Returns the width of the character, 0 (zero-width) or 2 (wide).
973     pub fn width(&self) -> usize {
974         match *self {
975             NonNarrowChar::ZeroWidth(_) => 0,
976             NonNarrowChar::Wide(_) => 2,
977             NonNarrowChar::Tab(_) => 4,
978         }
979     }
980 }
981
982 impl Add<BytePos> for NonNarrowChar {
983     type Output = Self;
984
985     fn add(self, rhs: BytePos) -> Self {
986         match self {
987             NonNarrowChar::ZeroWidth(pos) => NonNarrowChar::ZeroWidth(pos + rhs),
988             NonNarrowChar::Wide(pos) => NonNarrowChar::Wide(pos + rhs),
989             NonNarrowChar::Tab(pos) => NonNarrowChar::Tab(pos + rhs),
990         }
991     }
992 }
993
994 impl Sub<BytePos> for NonNarrowChar {
995     type Output = Self;
996
997     fn sub(self, rhs: BytePos) -> Self {
998         match self {
999             NonNarrowChar::ZeroWidth(pos) => NonNarrowChar::ZeroWidth(pos - rhs),
1000             NonNarrowChar::Wide(pos) => NonNarrowChar::Wide(pos - rhs),
1001             NonNarrowChar::Tab(pos) => NonNarrowChar::Tab(pos - rhs),
1002         }
1003     }
1004 }
1005
1006 /// Identifies an offset of a character that was normalized away from `SourceFile`.
1007 #[derive(Copy, Clone, Encodable, Decodable, Eq, PartialEq, Debug)]
1008 pub struct NormalizedPos {
1009     /// The absolute offset of the character in the `SourceMap`.
1010     pub pos: BytePos,
1011     /// The difference between original and normalized string at position.
1012     pub diff: u32,
1013 }
1014
1015 #[derive(PartialEq, Eq, Clone, Debug)]
1016 pub enum ExternalSource {
1017     /// No external source has to be loaded, since the `SourceFile` represents a local crate.
1018     Unneeded,
1019     Foreign {
1020         kind: ExternalSourceKind,
1021         /// This SourceFile's byte-offset within the source_map of its original crate.
1022         original_start_pos: BytePos,
1023         /// The end of this SourceFile within the source_map of its original crate.
1024         original_end_pos: BytePos,
1025     },
1026 }
1027
1028 /// The state of the lazy external source loading mechanism of a `SourceFile`.
1029 #[derive(PartialEq, Eq, Clone, Debug)]
1030 pub enum ExternalSourceKind {
1031     /// The external source has been loaded already.
1032     Present(Lrc<String>),
1033     /// No attempt has been made to load the external source.
1034     AbsentOk,
1035     /// A failed attempt has been made to load the external source.
1036     AbsentErr,
1037     Unneeded,
1038 }
1039
1040 impl ExternalSource {
1041     pub fn is_absent(&self) -> bool {
1042         !matches!(self, ExternalSource::Foreign { kind: ExternalSourceKind::Present(_), .. })
1043     }
1044
1045     pub fn get_source(&self) -> Option<&Lrc<String>> {
1046         match self {
1047             ExternalSource::Foreign { kind: ExternalSourceKind::Present(ref src), .. } => Some(src),
1048             _ => None,
1049         }
1050     }
1051 }
1052
1053 #[derive(Debug)]
1054 pub struct OffsetOverflowError;
1055
1056 #[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Encodable, Decodable)]
1057 pub enum SourceFileHashAlgorithm {
1058     Md5,
1059     Sha1,
1060     Sha256,
1061 }
1062
1063 impl FromStr for SourceFileHashAlgorithm {
1064     type Err = ();
1065
1066     fn from_str(s: &str) -> Result<SourceFileHashAlgorithm, ()> {
1067         match s {
1068             "md5" => Ok(SourceFileHashAlgorithm::Md5),
1069             "sha1" => Ok(SourceFileHashAlgorithm::Sha1),
1070             "sha256" => Ok(SourceFileHashAlgorithm::Sha256),
1071             _ => Err(()),
1072         }
1073     }
1074 }
1075
1076 rustc_data_structures::impl_stable_hash_via_hash!(SourceFileHashAlgorithm);
1077
1078 /// The hash of the on-disk source file used for debug info.
1079 #[derive(Copy, Clone, PartialEq, Eq, Debug)]
1080 #[derive(HashStable_Generic, Encodable, Decodable)]
1081 pub struct SourceFileHash {
1082     pub kind: SourceFileHashAlgorithm,
1083     value: [u8; 32],
1084 }
1085
1086 impl SourceFileHash {
1087     pub fn new(kind: SourceFileHashAlgorithm, src: &str) -> SourceFileHash {
1088         let mut hash = SourceFileHash { kind, value: Default::default() };
1089         let len = hash.hash_len();
1090         let value = &mut hash.value[..len];
1091         let data = src.as_bytes();
1092         match kind {
1093             SourceFileHashAlgorithm::Md5 => {
1094                 value.copy_from_slice(&Md5::digest(data));
1095             }
1096             SourceFileHashAlgorithm::Sha1 => {
1097                 value.copy_from_slice(&Sha1::digest(data));
1098             }
1099             SourceFileHashAlgorithm::Sha256 => {
1100                 value.copy_from_slice(&Sha256::digest(data));
1101             }
1102         }
1103         hash
1104     }
1105
1106     /// Check if the stored hash matches the hash of the string.
1107     pub fn matches(&self, src: &str) -> bool {
1108         Self::new(self.kind, src) == *self
1109     }
1110
1111     /// The bytes of the hash.
1112     pub fn hash_bytes(&self) -> &[u8] {
1113         let len = self.hash_len();
1114         &self.value[..len]
1115     }
1116
1117     fn hash_len(&self) -> usize {
1118         match self.kind {
1119             SourceFileHashAlgorithm::Md5 => 16,
1120             SourceFileHashAlgorithm::Sha1 => 20,
1121             SourceFileHashAlgorithm::Sha256 => 32,
1122         }
1123     }
1124 }
1125
1126 /// A single source in the [`SourceMap`].
1127 #[derive(Clone)]
1128 pub struct SourceFile {
1129     /// The name of the file that the source came from. Source that doesn't
1130     /// originate from files has names between angle brackets by convention
1131     /// (e.g., `<anon>`).
1132     pub name: FileName,
1133     /// `true` if the `name` field above has been modified by `--remap-path-prefix`.
1134     pub name_was_remapped: bool,
1135     /// The unmapped path of the file that the source came from.
1136     /// Set to `None` if the `SourceFile` was imported from an external crate.
1137     pub unmapped_path: Option<FileName>,
1138     /// The complete source code.
1139     pub src: Option<Lrc<String>>,
1140     /// The source code's hash.
1141     pub src_hash: SourceFileHash,
1142     /// The external source code (used for external crates, which will have a `None`
1143     /// value as `self.src`.
1144     pub external_src: Lock<ExternalSource>,
1145     /// The start position of this source in the `SourceMap`.
1146     pub start_pos: BytePos,
1147     /// The end position of this source in the `SourceMap`.
1148     pub end_pos: BytePos,
1149     /// Locations of lines beginnings in the source code.
1150     pub lines: Vec<BytePos>,
1151     /// Locations of multi-byte characters in the source code.
1152     pub multibyte_chars: Vec<MultiByteChar>,
1153     /// Width of characters that are not narrow in the source code.
1154     pub non_narrow_chars: Vec<NonNarrowChar>,
1155     /// Locations of characters removed during normalization.
1156     pub normalized_pos: Vec<NormalizedPos>,
1157     /// A hash of the filename, used for speeding up hashing in incremental compilation.
1158     pub name_hash: u128,
1159     /// Indicates which crate this `SourceFile` was imported from.
1160     pub cnum: CrateNum,
1161 }
1162
1163 impl<S: Encoder> Encodable<S> for SourceFile {
1164     fn encode(&self, s: &mut S) -> Result<(), S::Error> {
1165         s.emit_struct("SourceFile", 8, |s| {
1166             s.emit_struct_field("name", 0, |s| self.name.encode(s))?;
1167             s.emit_struct_field("name_was_remapped", 1, |s| self.name_was_remapped.encode(s))?;
1168             s.emit_struct_field("src_hash", 2, |s| self.src_hash.encode(s))?;
1169             s.emit_struct_field("start_pos", 3, |s| self.start_pos.encode(s))?;
1170             s.emit_struct_field("end_pos", 4, |s| self.end_pos.encode(s))?;
1171             s.emit_struct_field("lines", 5, |s| {
1172                 let lines = &self.lines[..];
1173                 // Store the length.
1174                 s.emit_u32(lines.len() as u32)?;
1175
1176                 if !lines.is_empty() {
1177                     // In order to preserve some space, we exploit the fact that
1178                     // the lines list is sorted and individual lines are
1179                     // probably not that long. Because of that we can store lines
1180                     // as a difference list, using as little space as possible
1181                     // for the differences.
1182                     let max_line_length = if lines.len() == 1 {
1183                         0
1184                     } else {
1185                         lines
1186                             .array_windows()
1187                             .map(|&[fst, snd]| snd - fst)
1188                             .map(|bp| bp.to_usize())
1189                             .max()
1190                             .unwrap()
1191                     };
1192
1193                     let bytes_per_diff: u8 = match max_line_length {
1194                         0..=0xFF => 1,
1195                         0x100..=0xFFFF => 2,
1196                         _ => 4,
1197                     };
1198
1199                     // Encode the number of bytes used per diff.
1200                     bytes_per_diff.encode(s)?;
1201
1202                     // Encode the first element.
1203                     lines[0].encode(s)?;
1204
1205                     let diff_iter = lines[..].array_windows().map(|&[fst, snd]| snd - fst);
1206
1207                     match bytes_per_diff {
1208                         1 => {
1209                             for diff in diff_iter {
1210                                 (diff.0 as u8).encode(s)?
1211                             }
1212                         }
1213                         2 => {
1214                             for diff in diff_iter {
1215                                 (diff.0 as u16).encode(s)?
1216                             }
1217                         }
1218                         4 => {
1219                             for diff in diff_iter {
1220                                 diff.0.encode(s)?
1221                             }
1222                         }
1223                         _ => unreachable!(),
1224                     }
1225                 }
1226
1227                 Ok(())
1228             })?;
1229             s.emit_struct_field("multibyte_chars", 6, |s| self.multibyte_chars.encode(s))?;
1230             s.emit_struct_field("non_narrow_chars", 7, |s| self.non_narrow_chars.encode(s))?;
1231             s.emit_struct_field("name_hash", 8, |s| self.name_hash.encode(s))?;
1232             s.emit_struct_field("normalized_pos", 9, |s| self.normalized_pos.encode(s))?;
1233             s.emit_struct_field("cnum", 10, |s| self.cnum.encode(s))
1234         })
1235     }
1236 }
1237
1238 impl<D: Decoder> Decodable<D> for SourceFile {
1239     fn decode(d: &mut D) -> Result<SourceFile, D::Error> {
1240         d.read_struct("SourceFile", 8, |d| {
1241             let name: FileName = d.read_struct_field("name", 0, |d| Decodable::decode(d))?;
1242             let name_was_remapped: bool =
1243                 d.read_struct_field("name_was_remapped", 1, |d| Decodable::decode(d))?;
1244             let src_hash: SourceFileHash =
1245                 d.read_struct_field("src_hash", 2, |d| Decodable::decode(d))?;
1246             let start_pos: BytePos =
1247                 d.read_struct_field("start_pos", 3, |d| Decodable::decode(d))?;
1248             let end_pos: BytePos = d.read_struct_field("end_pos", 4, |d| Decodable::decode(d))?;
1249             let lines: Vec<BytePos> = d.read_struct_field("lines", 5, |d| {
1250                 let num_lines: u32 = Decodable::decode(d)?;
1251                 let mut lines = Vec::with_capacity(num_lines as usize);
1252
1253                 if num_lines > 0 {
1254                     // Read the number of bytes used per diff.
1255                     let bytes_per_diff: u8 = Decodable::decode(d)?;
1256
1257                     // Read the first element.
1258                     let mut line_start: BytePos = Decodable::decode(d)?;
1259                     lines.push(line_start);
1260
1261                     for _ in 1..num_lines {
1262                         let diff = match bytes_per_diff {
1263                             1 => d.read_u8()? as u32,
1264                             2 => d.read_u16()? as u32,
1265                             4 => d.read_u32()?,
1266                             _ => unreachable!(),
1267                         };
1268
1269                         line_start = line_start + BytePos(diff);
1270
1271                         lines.push(line_start);
1272                     }
1273                 }
1274
1275                 Ok(lines)
1276             })?;
1277             let multibyte_chars: Vec<MultiByteChar> =
1278                 d.read_struct_field("multibyte_chars", 6, |d| Decodable::decode(d))?;
1279             let non_narrow_chars: Vec<NonNarrowChar> =
1280                 d.read_struct_field("non_narrow_chars", 7, |d| Decodable::decode(d))?;
1281             let name_hash: u128 = d.read_struct_field("name_hash", 8, |d| Decodable::decode(d))?;
1282             let normalized_pos: Vec<NormalizedPos> =
1283                 d.read_struct_field("normalized_pos", 9, |d| Decodable::decode(d))?;
1284             let cnum: CrateNum = d.read_struct_field("cnum", 10, |d| Decodable::decode(d))?;
1285             Ok(SourceFile {
1286                 name,
1287                 name_was_remapped,
1288                 unmapped_path: None,
1289                 start_pos,
1290                 end_pos,
1291                 src: None,
1292                 src_hash,
1293                 // Unused - the metadata decoder will construct
1294                 // a new SourceFile, filling in `external_src` properly
1295                 external_src: Lock::new(ExternalSource::Unneeded),
1296                 lines,
1297                 multibyte_chars,
1298                 non_narrow_chars,
1299                 normalized_pos,
1300                 name_hash,
1301                 cnum,
1302             })
1303         })
1304     }
1305 }
1306
1307 impl fmt::Debug for SourceFile {
1308     fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
1309         write!(fmt, "SourceFile({})", self.name)
1310     }
1311 }
1312
1313 impl SourceFile {
1314     pub fn new(
1315         name: FileName,
1316         name_was_remapped: bool,
1317         unmapped_path: FileName,
1318         mut src: String,
1319         start_pos: BytePos,
1320         hash_kind: SourceFileHashAlgorithm,
1321     ) -> Self {
1322         // Compute the file hash before any normalization.
1323         let src_hash = SourceFileHash::new(hash_kind, &src);
1324         let normalized_pos = normalize_src(&mut src, start_pos);
1325
1326         let name_hash = {
1327             let mut hasher: StableHasher = StableHasher::new();
1328             name.hash(&mut hasher);
1329             hasher.finish::<u128>()
1330         };
1331         let end_pos = start_pos.to_usize() + src.len();
1332         assert!(end_pos <= u32::MAX as usize);
1333
1334         let (lines, multibyte_chars, non_narrow_chars) =
1335             analyze_source_file::analyze_source_file(&src[..], start_pos);
1336
1337         SourceFile {
1338             name,
1339             name_was_remapped,
1340             unmapped_path: Some(unmapped_path),
1341             src: Some(Lrc::new(src)),
1342             src_hash,
1343             external_src: Lock::new(ExternalSource::Unneeded),
1344             start_pos,
1345             end_pos: Pos::from_usize(end_pos),
1346             lines,
1347             multibyte_chars,
1348             non_narrow_chars,
1349             normalized_pos,
1350             name_hash,
1351             cnum: LOCAL_CRATE,
1352         }
1353     }
1354
1355     /// Returns the `BytePos` of the beginning of the current line.
1356     pub fn line_begin_pos(&self, pos: BytePos) -> BytePos {
1357         let line_index = self.lookup_line(pos).unwrap();
1358         self.lines[line_index]
1359     }
1360
1361     /// Add externally loaded source.
1362     /// If the hash of the input doesn't match or no input is supplied via None,
1363     /// it is interpreted as an error and the corresponding enum variant is set.
1364     /// The return value signifies whether some kind of source is present.
1365     pub fn add_external_src<F>(&self, get_src: F) -> bool
1366     where
1367         F: FnOnce() -> Option<String>,
1368     {
1369         if matches!(
1370             *self.external_src.borrow(),
1371             ExternalSource::Foreign { kind: ExternalSourceKind::AbsentOk, .. }
1372         ) {
1373             let src = get_src();
1374             let mut external_src = self.external_src.borrow_mut();
1375             // Check that no-one else have provided the source while we were getting it
1376             if let ExternalSource::Foreign {
1377                 kind: src_kind @ ExternalSourceKind::AbsentOk, ..
1378             } = &mut *external_src
1379             {
1380                 if let Some(mut src) = src {
1381                     // The src_hash needs to be computed on the pre-normalized src.
1382                     if self.src_hash.matches(&src) {
1383                         normalize_src(&mut src, BytePos::from_usize(0));
1384                         *src_kind = ExternalSourceKind::Present(Lrc::new(src));
1385                         return true;
1386                     }
1387                 } else {
1388                     *src_kind = ExternalSourceKind::AbsentErr;
1389                 }
1390
1391                 false
1392             } else {
1393                 self.src.is_some() || external_src.get_source().is_some()
1394             }
1395         } else {
1396             self.src.is_some() || self.external_src.borrow().get_source().is_some()
1397         }
1398     }
1399
1400     /// Gets a line from the list of pre-computed line-beginnings.
1401     /// The line number here is 0-based.
1402     pub fn get_line(&self, line_number: usize) -> Option<Cow<'_, str>> {
1403         fn get_until_newline(src: &str, begin: usize) -> &str {
1404             // We can't use `lines.get(line_number+1)` because we might
1405             // be parsing when we call this function and thus the current
1406             // line is the last one we have line info for.
1407             let slice = &src[begin..];
1408             match slice.find('\n') {
1409                 Some(e) => &slice[..e],
1410                 None => slice,
1411             }
1412         }
1413
1414         let begin = {
1415             let line = self.lines.get(line_number)?;
1416             let begin: BytePos = *line - self.start_pos;
1417             begin.to_usize()
1418         };
1419
1420         if let Some(ref src) = self.src {
1421             Some(Cow::from(get_until_newline(src, begin)))
1422         } else if let Some(src) = self.external_src.borrow().get_source() {
1423             Some(Cow::Owned(String::from(get_until_newline(src, begin))))
1424         } else {
1425             None
1426         }
1427     }
1428
1429     pub fn is_real_file(&self) -> bool {
1430         self.name.is_real()
1431     }
1432
1433     pub fn is_imported(&self) -> bool {
1434         self.src.is_none()
1435     }
1436
1437     pub fn byte_length(&self) -> u32 {
1438         self.end_pos.0 - self.start_pos.0
1439     }
1440     pub fn count_lines(&self) -> usize {
1441         self.lines.len()
1442     }
1443
1444     /// Finds the line containing the given position. The return value is the
1445     /// index into the `lines` array of this `SourceFile`, not the 1-based line
1446     /// number. If the source_file is empty or the position is located before the
1447     /// first line, `None` is returned.
1448     pub fn lookup_line(&self, pos: BytePos) -> Option<usize> {
1449         if self.lines.is_empty() {
1450             return None;
1451         }
1452
1453         let line_index = lookup_line(&self.lines[..], pos);
1454         assert!(line_index < self.lines.len() as isize);
1455         if line_index >= 0 { Some(line_index as usize) } else { None }
1456     }
1457
1458     pub fn line_bounds(&self, line_index: usize) -> Range<BytePos> {
1459         if self.is_empty() {
1460             return self.start_pos..self.end_pos;
1461         }
1462
1463         assert!(line_index < self.lines.len());
1464         if line_index == (self.lines.len() - 1) {
1465             self.lines[line_index]..self.end_pos
1466         } else {
1467             self.lines[line_index]..self.lines[line_index + 1]
1468         }
1469     }
1470
1471     /// Returns whether or not the file contains the given `SourceMap` byte
1472     /// position. The position one past the end of the file is considered to be
1473     /// contained by the file. This implies that files for which `is_empty`
1474     /// returns true still contain one byte position according to this function.
1475     #[inline]
1476     pub fn contains(&self, byte_pos: BytePos) -> bool {
1477         byte_pos >= self.start_pos && byte_pos <= self.end_pos
1478     }
1479
1480     #[inline]
1481     pub fn is_empty(&self) -> bool {
1482         self.start_pos == self.end_pos
1483     }
1484
1485     /// Calculates the original byte position relative to the start of the file
1486     /// based on the given byte position.
1487     pub fn original_relative_byte_pos(&self, pos: BytePos) -> BytePos {
1488         // Diff before any records is 0. Otherwise use the previously recorded
1489         // diff as that applies to the following characters until a new diff
1490         // is recorded.
1491         let diff = match self.normalized_pos.binary_search_by(|np| np.pos.cmp(&pos)) {
1492             Ok(i) => self.normalized_pos[i].diff,
1493             Err(i) if i == 0 => 0,
1494             Err(i) => self.normalized_pos[i - 1].diff,
1495         };
1496
1497         BytePos::from_u32(pos.0 - self.start_pos.0 + diff)
1498     }
1499
1500     /// Converts an absolute `BytePos` to a `CharPos` relative to the `SourceFile`.
1501     pub fn bytepos_to_file_charpos(&self, bpos: BytePos) -> CharPos {
1502         // The number of extra bytes due to multibyte chars in the `SourceFile`.
1503         let mut total_extra_bytes = 0;
1504
1505         for mbc in self.multibyte_chars.iter() {
1506             debug!("{}-byte char at {:?}", mbc.bytes, mbc.pos);
1507             if mbc.pos < bpos {
1508                 // Every character is at least one byte, so we only
1509                 // count the actual extra bytes.
1510                 total_extra_bytes += mbc.bytes as u32 - 1;
1511                 // We should never see a byte position in the middle of a
1512                 // character.
1513                 assert!(bpos.to_u32() >= mbc.pos.to_u32() + mbc.bytes as u32);
1514             } else {
1515                 break;
1516             }
1517         }
1518
1519         assert!(self.start_pos.to_u32() + total_extra_bytes <= bpos.to_u32());
1520         CharPos(bpos.to_usize() - self.start_pos.to_usize() - total_extra_bytes as usize)
1521     }
1522
1523     /// Looks up the file's (1-based) line number and (0-based `CharPos`) column offset, for a
1524     /// given `BytePos`.
1525     pub fn lookup_file_pos(&self, pos: BytePos) -> (usize, CharPos) {
1526         let chpos = self.bytepos_to_file_charpos(pos);
1527         match self.lookup_line(pos) {
1528             Some(a) => {
1529                 let line = a + 1; // Line numbers start at 1
1530                 let linebpos = self.lines[a];
1531                 let linechpos = self.bytepos_to_file_charpos(linebpos);
1532                 let col = chpos - linechpos;
1533                 debug!("byte pos {:?} is on the line at byte pos {:?}", pos, linebpos);
1534                 debug!("char pos {:?} is on the line at char pos {:?}", chpos, linechpos);
1535                 debug!("byte is on line: {}", line);
1536                 assert!(chpos >= linechpos);
1537                 (line, col)
1538             }
1539             None => (0, chpos),
1540         }
1541     }
1542
1543     /// Looks up the file's (1-based) line number, (0-based `CharPos`) column offset, and (0-based)
1544     /// column offset when displayed, for a given `BytePos`.
1545     pub fn lookup_file_pos_with_col_display(&self, pos: BytePos) -> (usize, CharPos, usize) {
1546         let (line, col_or_chpos) = self.lookup_file_pos(pos);
1547         if line > 0 {
1548             let col = col_or_chpos;
1549             let linebpos = self.lines[line - 1];
1550             let col_display = {
1551                 let start_width_idx = self
1552                     .non_narrow_chars
1553                     .binary_search_by_key(&linebpos, |x| x.pos())
1554                     .unwrap_or_else(|x| x);
1555                 let end_width_idx = self
1556                     .non_narrow_chars
1557                     .binary_search_by_key(&pos, |x| x.pos())
1558                     .unwrap_or_else(|x| x);
1559                 let special_chars = end_width_idx - start_width_idx;
1560                 let non_narrow: usize = self.non_narrow_chars[start_width_idx..end_width_idx]
1561                     .iter()
1562                     .map(|x| x.width())
1563                     .sum();
1564                 col.0 - special_chars + non_narrow
1565             };
1566             (line, col, col_display)
1567         } else {
1568             let chpos = col_or_chpos;
1569             let col_display = {
1570                 let end_width_idx = self
1571                     .non_narrow_chars
1572                     .binary_search_by_key(&pos, |x| x.pos())
1573                     .unwrap_or_else(|x| x);
1574                 let non_narrow: usize =
1575                     self.non_narrow_chars[0..end_width_idx].iter().map(|x| x.width()).sum();
1576                 chpos.0 - end_width_idx + non_narrow
1577             };
1578             (0, chpos, col_display)
1579         }
1580     }
1581 }
1582
1583 /// Normalizes the source code and records the normalizations.
1584 fn normalize_src(src: &mut String, start_pos: BytePos) -> Vec<NormalizedPos> {
1585     let mut normalized_pos = vec![];
1586     remove_bom(src, &mut normalized_pos);
1587     normalize_newlines(src, &mut normalized_pos);
1588
1589     // Offset all the positions by start_pos to match the final file positions.
1590     for np in &mut normalized_pos {
1591         np.pos.0 += start_pos.0;
1592     }
1593
1594     normalized_pos
1595 }
1596
1597 /// Removes UTF-8 BOM, if any.
1598 fn remove_bom(src: &mut String, normalized_pos: &mut Vec<NormalizedPos>) {
1599     if src.starts_with('\u{feff}') {
1600         src.drain(..3);
1601         normalized_pos.push(NormalizedPos { pos: BytePos(0), diff: 3 });
1602     }
1603 }
1604
1605 /// Replaces `\r\n` with `\n` in-place in `src`.
1606 ///
1607 /// Returns error if there's a lone `\r` in the string.
1608 fn normalize_newlines(src: &mut String, normalized_pos: &mut Vec<NormalizedPos>) {
1609     if !src.as_bytes().contains(&b'\r') {
1610         return;
1611     }
1612
1613     // We replace `\r\n` with `\n` in-place, which doesn't break utf-8 encoding.
1614     // While we *can* call `as_mut_vec` and do surgery on the live string
1615     // directly, let's rather steal the contents of `src`. This makes the code
1616     // safe even if a panic occurs.
1617
1618     let mut buf = std::mem::replace(src, String::new()).into_bytes();
1619     let mut gap_len = 0;
1620     let mut tail = buf.as_mut_slice();
1621     let mut cursor = 0;
1622     let original_gap = normalized_pos.last().map_or(0, |l| l.diff);
1623     loop {
1624         let idx = match find_crlf(&tail[gap_len..]) {
1625             None => tail.len(),
1626             Some(idx) => idx + gap_len,
1627         };
1628         tail.copy_within(gap_len..idx, 0);
1629         tail = &mut tail[idx - gap_len..];
1630         if tail.len() == gap_len {
1631             break;
1632         }
1633         cursor += idx - gap_len;
1634         gap_len += 1;
1635         normalized_pos.push(NormalizedPos {
1636             pos: BytePos::from_usize(cursor + 1),
1637             diff: original_gap + gap_len as u32,
1638         });
1639     }
1640
1641     // Account for removed `\r`.
1642     // After `set_len`, `buf` is guaranteed to contain utf-8 again.
1643     let new_len = buf.len() - gap_len;
1644     unsafe {
1645         buf.set_len(new_len);
1646         *src = String::from_utf8_unchecked(buf);
1647     }
1648
1649     fn find_crlf(src: &[u8]) -> Option<usize> {
1650         let mut search_idx = 0;
1651         while let Some(idx) = find_cr(&src[search_idx..]) {
1652             if src[search_idx..].get(idx + 1) != Some(&b'\n') {
1653                 search_idx += idx + 1;
1654                 continue;
1655             }
1656             return Some(search_idx + idx);
1657         }
1658         None
1659     }
1660
1661     fn find_cr(src: &[u8]) -> Option<usize> {
1662         src.iter().position(|&b| b == b'\r')
1663     }
1664 }
1665
1666 // _____________________________________________________________________________
1667 // Pos, BytePos, CharPos
1668 //
1669
1670 pub trait Pos {
1671     fn from_usize(n: usize) -> Self;
1672     fn to_usize(&self) -> usize;
1673     fn from_u32(n: u32) -> Self;
1674     fn to_u32(&self) -> u32;
1675 }
1676
1677 macro_rules! impl_pos {
1678     (
1679         $(
1680             $(#[$attr:meta])*
1681             $vis:vis struct $ident:ident($inner_vis:vis $inner_ty:ty);
1682         )*
1683     ) => {
1684         $(
1685             $(#[$attr])*
1686             $vis struct $ident($inner_vis $inner_ty);
1687
1688             impl Pos for $ident {
1689                 #[inline(always)]
1690                 fn from_usize(n: usize) -> $ident {
1691                     $ident(n as $inner_ty)
1692                 }
1693
1694                 #[inline(always)]
1695                 fn to_usize(&self) -> usize {
1696                     self.0 as usize
1697                 }
1698
1699                 #[inline(always)]
1700                 fn from_u32(n: u32) -> $ident {
1701                     $ident(n as $inner_ty)
1702                 }
1703
1704                 #[inline(always)]
1705                 fn to_u32(&self) -> u32 {
1706                     self.0 as u32
1707                 }
1708             }
1709
1710             impl Add for $ident {
1711                 type Output = $ident;
1712
1713                 #[inline(always)]
1714                 fn add(self, rhs: $ident) -> $ident {
1715                     $ident(self.0 + rhs.0)
1716                 }
1717             }
1718
1719             impl Sub for $ident {
1720                 type Output = $ident;
1721
1722                 #[inline(always)]
1723                 fn sub(self, rhs: $ident) -> $ident {
1724                     $ident(self.0 - rhs.0)
1725                 }
1726             }
1727         )*
1728     };
1729 }
1730
1731 impl_pos! {
1732     /// A byte offset.
1733     ///
1734     /// Keep this small (currently 32-bits), as AST contains a lot of them.
1735     #[derive(Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord, Debug)]
1736     pub struct BytePos(pub u32);
1737
1738     /// A character offset.
1739     ///
1740     /// Because of multibyte UTF-8 characters, a byte offset
1741     /// is not equivalent to a character offset. The [`SourceMap`] will convert [`BytePos`]
1742     /// values to `CharPos` values as necessary.
1743     #[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Debug)]
1744     pub struct CharPos(pub usize);
1745 }
1746
1747 impl<S: rustc_serialize::Encoder> Encodable<S> for BytePos {
1748     fn encode(&self, s: &mut S) -> Result<(), S::Error> {
1749         s.emit_u32(self.0)
1750     }
1751 }
1752
1753 impl<D: rustc_serialize::Decoder> Decodable<D> for BytePos {
1754     fn decode(d: &mut D) -> Result<BytePos, D::Error> {
1755         Ok(BytePos(d.read_u32()?))
1756     }
1757 }
1758
1759 // _____________________________________________________________________________
1760 // Loc, SourceFileAndLine, SourceFileAndBytePos
1761 //
1762
1763 /// A source code location used for error reporting.
1764 #[derive(Debug, Clone)]
1765 pub struct Loc {
1766     /// Information about the original source.
1767     pub file: Lrc<SourceFile>,
1768     /// The (1-based) line number.
1769     pub line: usize,
1770     /// The (0-based) column offset.
1771     pub col: CharPos,
1772     /// The (0-based) column offset when displayed.
1773     pub col_display: usize,
1774 }
1775
1776 // Used to be structural records.
1777 #[derive(Debug)]
1778 pub struct SourceFileAndLine {
1779     pub sf: Lrc<SourceFile>,
1780     pub line: usize,
1781 }
1782 #[derive(Debug)]
1783 pub struct SourceFileAndBytePos {
1784     pub sf: Lrc<SourceFile>,
1785     pub pos: BytePos,
1786 }
1787
1788 #[derive(Copy, Clone, Debug, PartialEq, Eq)]
1789 pub struct LineInfo {
1790     /// Index of line, starting from 0.
1791     pub line_index: usize,
1792
1793     /// Column in line where span begins, starting from 0.
1794     pub start_col: CharPos,
1795
1796     /// Column in line where span ends, starting from 0, exclusive.
1797     pub end_col: CharPos,
1798 }
1799
1800 pub struct FileLines {
1801     pub file: Lrc<SourceFile>,
1802     pub lines: Vec<LineInfo>,
1803 }
1804
1805 pub static SPAN_DEBUG: AtomicRef<fn(Span, &mut fmt::Formatter<'_>) -> fmt::Result> =
1806     AtomicRef::new(&(default_span_debug as fn(_, &mut fmt::Formatter<'_>) -> _));
1807
1808 // _____________________________________________________________________________
1809 // SpanLinesError, SpanSnippetError, DistinctSources, MalformedSourceMapPositions
1810 //
1811
1812 pub type FileLinesResult = Result<FileLines, SpanLinesError>;
1813
1814 #[derive(Clone, PartialEq, Eq, Debug)]
1815 pub enum SpanLinesError {
1816     DistinctSources(DistinctSources),
1817 }
1818
1819 #[derive(Clone, PartialEq, Eq, Debug)]
1820 pub enum SpanSnippetError {
1821     IllFormedSpan(Span),
1822     DistinctSources(DistinctSources),
1823     MalformedForSourcemap(MalformedSourceMapPositions),
1824     SourceNotAvailable { filename: FileName },
1825 }
1826
1827 #[derive(Clone, PartialEq, Eq, Debug)]
1828 pub struct DistinctSources {
1829     pub begin: (FileName, BytePos),
1830     pub end: (FileName, BytePos),
1831 }
1832
1833 #[derive(Clone, PartialEq, Eq, Debug)]
1834 pub struct MalformedSourceMapPositions {
1835     pub name: FileName,
1836     pub source_len: usize,
1837     pub begin_pos: BytePos,
1838     pub end_pos: BytePos,
1839 }
1840
1841 /// Range inside of a `Span` used for diagnostics when we only have access to relative positions.
1842 #[derive(Copy, Clone, PartialEq, Eq, Debug)]
1843 pub struct InnerSpan {
1844     pub start: usize,
1845     pub end: usize,
1846 }
1847
1848 impl InnerSpan {
1849     pub fn new(start: usize, end: usize) -> InnerSpan {
1850         InnerSpan { start, end }
1851     }
1852 }
1853
1854 // Given a slice of line start positions and a position, returns the index of
1855 // the line the position is on. Returns -1 if the position is located before
1856 // the first line.
1857 fn lookup_line(lines: &[BytePos], pos: BytePos) -> isize {
1858     match lines.binary_search(&pos) {
1859         Ok(line) => line as isize,
1860         Err(line) => line as isize - 1,
1861     }
1862 }
1863
1864 /// Requirements for a `StableHashingContext` to be used in this crate.
1865 ///
1866 /// This is a hack to allow using the [`HashStable_Generic`] derive macro
1867 /// instead of implementing everything in rustc_middle.
1868 pub trait HashStableContext {
1869     fn hash_def_id(&mut self, _: DefId, hasher: &mut StableHasher);
1870     /// Obtains a cache for storing the `Fingerprint` of an `ExpnId`.
1871     /// This method allows us to have multiple `HashStableContext` implementations
1872     /// that hash things in a different way, without the results of one polluting
1873     /// the cache of the other.
1874     fn expn_id_cache() -> &'static LocalKey<ExpnIdCache>;
1875     fn hash_crate_num(&mut self, _: CrateNum, hasher: &mut StableHasher);
1876     fn hash_spans(&self) -> bool;
1877     fn span_data_to_lines_and_cols(
1878         &mut self,
1879         span: &SpanData,
1880     ) -> Option<(Lrc<SourceFile>, usize, BytePos, usize, BytePos)>;
1881 }
1882
1883 impl<CTX> HashStable<CTX> for Span
1884 where
1885     CTX: HashStableContext,
1886 {
1887     /// Hashes a span in a stable way. We can't directly hash the span's `BytePos`
1888     /// fields (that would be similar to hashing pointers, since those are just
1889     /// offsets into the `SourceMap`). Instead, we hash the (file name, line, column)
1890     /// triple, which stays the same even if the containing `SourceFile` has moved
1891     /// within the `SourceMap`.
1892     ///
1893     /// Also note that we are hashing byte offsets for the column, not unicode
1894     /// codepoint offsets. For the purpose of the hash that's sufficient.
1895     /// Also, hashing filenames is expensive so we avoid doing it twice when the
1896     /// span starts and ends in the same file, which is almost always the case.
1897     fn hash_stable(&self, ctx: &mut CTX, hasher: &mut StableHasher) {
1898         const TAG_VALID_SPAN: u8 = 0;
1899         const TAG_INVALID_SPAN: u8 = 1;
1900
1901         if !ctx.hash_spans() {
1902             return;
1903         }
1904
1905         self.ctxt().hash_stable(ctx, hasher);
1906
1907         if self.is_dummy() {
1908             Hash::hash(&TAG_INVALID_SPAN, hasher);
1909             return;
1910         }
1911
1912         // If this is not an empty or invalid span, we want to hash the last
1913         // position that belongs to it, as opposed to hashing the first
1914         // position past it.
1915         let span = self.data();
1916         let (file, line_lo, col_lo, line_hi, col_hi) = match ctx.span_data_to_lines_and_cols(&span)
1917         {
1918             Some(pos) => pos,
1919             None => {
1920                 Hash::hash(&TAG_INVALID_SPAN, hasher);
1921                 return;
1922             }
1923         };
1924
1925         Hash::hash(&TAG_VALID_SPAN, hasher);
1926         // We truncate the stable ID hash and line and column numbers. The chances
1927         // of causing a collision this way should be minimal.
1928         Hash::hash(&(file.name_hash as u64), hasher);
1929
1930         // Hash both the length and the end location (line/column) of a span. If we
1931         // hash only the length, for example, then two otherwise equal spans with
1932         // different end locations will have the same hash. This can cause a problem
1933         // during incremental compilation wherein a previous result for a query that
1934         // depends on the end location of a span will be incorrectly reused when the
1935         // end location of the span it depends on has changed (see issue #74890). A
1936         // similar analysis applies if some query depends specifically on the length
1937         // of the span, but we only hash the end location. So hash both.
1938
1939         let col_lo_trunc = (col_lo.0 as u64) & 0xFF;
1940         let line_lo_trunc = ((line_lo as u64) & 0xFF_FF_FF) << 8;
1941         let col_hi_trunc = (col_hi.0 as u64) & 0xFF << 32;
1942         let line_hi_trunc = ((line_hi as u64) & 0xFF_FF_FF) << 40;
1943         let col_line = col_lo_trunc | line_lo_trunc | col_hi_trunc | line_hi_trunc;
1944         let len = (span.hi - span.lo).0;
1945         Hash::hash(&col_line, hasher);
1946         Hash::hash(&len, hasher);
1947     }
1948 }
1949
1950 impl<CTX: HashStableContext> HashStable<CTX> for SyntaxContext {
1951     fn hash_stable(&self, ctx: &mut CTX, hasher: &mut StableHasher) {
1952         const TAG_EXPANSION: u8 = 0;
1953         const TAG_NO_EXPANSION: u8 = 1;
1954
1955         if *self == SyntaxContext::root() {
1956             TAG_NO_EXPANSION.hash_stable(ctx, hasher);
1957         } else {
1958             TAG_EXPANSION.hash_stable(ctx, hasher);
1959             let (expn_id, transparency) = self.outer_mark();
1960             expn_id.hash_stable(ctx, hasher);
1961             transparency.hash_stable(ctx, hasher);
1962         }
1963     }
1964 }
1965
1966 pub type ExpnIdCache = RefCell<Vec<Option<Fingerprint>>>;
1967
1968 impl<CTX: HashStableContext> HashStable<CTX> for ExpnId {
1969     fn hash_stable(&self, ctx: &mut CTX, hasher: &mut StableHasher) {
1970         const TAG_ROOT: u8 = 0;
1971         const TAG_NOT_ROOT: u8 = 1;
1972
1973         if *self == ExpnId::root() {
1974             TAG_ROOT.hash_stable(ctx, hasher);
1975             return;
1976         }
1977
1978         // Since the same expansion context is usually referenced many
1979         // times, we cache a stable hash of it and hash that instead of
1980         // recursing every time.
1981         let index = self.as_u32() as usize;
1982         let res = CTX::expn_id_cache().with(|cache| cache.borrow().get(index).copied().flatten());
1983
1984         if let Some(res) = res {
1985             res.hash_stable(ctx, hasher);
1986         } else {
1987             let new_len = index + 1;
1988
1989             let mut sub_hasher = StableHasher::new();
1990             TAG_NOT_ROOT.hash_stable(ctx, &mut sub_hasher);
1991             self.expn_data().hash_stable(ctx, &mut sub_hasher);
1992             let sub_hash: Fingerprint = sub_hasher.finish();
1993
1994             CTX::expn_id_cache().with(|cache| {
1995                 let mut cache = cache.borrow_mut();
1996                 if cache.len() < new_len {
1997                     cache.resize(new_len, None);
1998                 }
1999                 cache[index].replace(sub_hash).expect_none("Cache slot was filled");
2000             });
2001             sub_hash.hash_stable(ctx, hasher);
2002         }
2003     }
2004 }