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