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