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