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