1#![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(hash_set_entry)]
26#![feature(if_let_guard)]
27#![feature(let_chains)]
28#![feature(map_try_insert)]
29#![feature(negative_impls)]
30#![feature(read_buf)]
31#![feature(round_char_boundary)]
32#![feature(rustc_attrs)]
33#![feature(rustdoc_internals)]
34#![feature(slice_as_chunks)]
35extern crate self as rustc_span;
41
42use derive_where::derive_where;
43use rustc_data_structures::{AtomicRef, outline};
44use rustc_macros::{Decodable, Encodable, HashStable_Generic};
45use rustc_serialize::opaque::{FileEncoder, MemDecoder};
46use rustc_serialize::{Decodable, Decoder, Encodable, Encoder};
47use tracing::debug;
48
49mod caching_source_map_view;
50pub mod source_map;
51use source_map::{SourceMap, SourceMapInputs};
52
53pub use self::caching_source_map_view::CachingSourceMapView;
54use crate::fatal_error::FatalError;
55
56pub mod edition;
57use edition::Edition;
58pub mod hygiene;
59use hygiene::Transparency;
60pub use hygiene::{
61 DesugaringKind, ExpnData, ExpnHash, ExpnId, ExpnKind, LocalExpnId, MacroKind, SyntaxContext,
62};
63use rustc_data_structures::stable_hasher::HashingControls;
64pub mod def_id;
65use def_id::{CrateNum, DefId, DefIndex, DefPathHash, LOCAL_CRATE, LocalDefId, StableCrateId};
66pub mod edit_distance;
67mod span_encoding;
68pub use span_encoding::{DUMMY_SP, Span};
69
70pub mod symbol;
71pub use symbol::{Ident, MacroRulesNormalizedIdent, STDLIB_STABLE_CRATES, Symbol, kw, sym};
72
73mod analyze_source_file;
74pub mod fatal_error;
75
76pub mod profiling;
77
78use std::borrow::Cow;
79use std::cmp::{self, Ordering};
80use std::fmt::Display;
81use std::hash::Hash;
82use std::io::{self, Read};
83use std::ops::{Add, Range, Sub};
84use std::path::{Path, PathBuf};
85use std::str::FromStr;
86use std::sync::Arc;
87use std::{fmt, iter};
88
89use md5::{Digest, Md5};
90use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
91use rustc_data_structures::sync::{FreezeLock, FreezeWriteGuard, Lock};
92use rustc_data_structures::unord::UnordMap;
93use rustc_hashes::{Hash64, Hash128};
94use sha1::Sha1;
95use sha2::Sha256;
96
97#[cfg(test)]
98mod tests;
99
100pub struct SessionGlobals {
105 symbol_interner: symbol::Interner,
106 span_interner: Lock<span_encoding::SpanInterner>,
107 metavar_spans: MetavarSpansMap,
110 hygiene_data: Lock<hygiene::HygieneData>,
111
112 source_map: Option<Arc<SourceMap>>,
116}
117
118impl SessionGlobals {
119 pub fn new(edition: Edition, sm_inputs: Option<SourceMapInputs>) -> SessionGlobals {
120 SessionGlobals {
121 symbol_interner: symbol::Interner::fresh(),
122 span_interner: Lock::new(span_encoding::SpanInterner::default()),
123 metavar_spans: Default::default(),
124 hygiene_data: Lock::new(hygiene::HygieneData::new(edition)),
125 source_map: sm_inputs.map(|inputs| Arc::new(SourceMap::with_inputs(inputs))),
126 }
127 }
128}
129
130pub fn create_session_globals_then<R>(
131 edition: Edition,
132 sm_inputs: Option<SourceMapInputs>,
133 f: impl FnOnce() -> R,
134) -> R {
135 assert!(
136 !SESSION_GLOBALS.is_set(),
137 "SESSION_GLOBALS should never be overwritten! \
138 Use another thread if you need another SessionGlobals"
139 );
140 let session_globals = SessionGlobals::new(edition, sm_inputs);
141 SESSION_GLOBALS.set(&session_globals, f)
142}
143
144pub fn set_session_globals_then<R>(session_globals: &SessionGlobals, f: impl FnOnce() -> R) -> R {
145 assert!(
146 !SESSION_GLOBALS.is_set(),
147 "SESSION_GLOBALS should never be overwritten! \
148 Use another thread if you need another SessionGlobals"
149 );
150 SESSION_GLOBALS.set(session_globals, f)
151}
152
153pub fn create_session_if_not_set_then<R, F>(edition: Edition, f: F) -> R
155where
156 F: FnOnce(&SessionGlobals) -> R,
157{
158 if !SESSION_GLOBALS.is_set() {
159 let session_globals = SessionGlobals::new(edition, None);
160 SESSION_GLOBALS.set(&session_globals, || SESSION_GLOBALS.with(f))
161 } else {
162 SESSION_GLOBALS.with(f)
163 }
164}
165
166pub fn with_session_globals<R, F>(f: F) -> R
167where
168 F: FnOnce(&SessionGlobals) -> R,
169{
170 SESSION_GLOBALS.with(f)
171}
172
173pub fn create_default_session_globals_then<R>(f: impl FnOnce() -> R) -> R {
175 create_session_globals_then(edition::DEFAULT_EDITION, None, f)
176}
177
178scoped_tls::scoped_thread_local!(static SESSION_GLOBALS: SessionGlobals);
182
183#[derive(Default)]
184pub struct MetavarSpansMap(FreezeLock<UnordMap<Span, (Span, bool)>>);
185
186impl MetavarSpansMap {
187 pub fn insert(&self, span: Span, var_span: Span) -> bool {
188 match self.0.write().try_insert(span, (var_span, false)) {
189 Ok(_) => true,
190 Err(entry) => entry.entry.get().0 == var_span,
191 }
192 }
193
194 pub fn get(&self, span: Span) -> Option<Span> {
196 if let Some(mut mspans) = self.0.try_write() {
197 if let Some((var_span, read)) = mspans.get_mut(&span) {
198 *read = true;
199 Some(*var_span)
200 } else {
201 None
202 }
203 } else {
204 if let Some((span, true)) = self.0.read().get(&span) { Some(*span) } else { None }
205 }
206 }
207
208 pub fn freeze_and_get_read_spans(&self) -> UnordMap<Span, Span> {
212 self.0.freeze().items().filter(|(_, (_, b))| *b).map(|(s1, (s2, _))| (*s1, *s2)).collect()
213 }
214}
215
216#[inline]
217pub fn with_metavar_spans<R>(f: impl FnOnce(&MetavarSpansMap) -> R) -> R {
218 with_session_globals(|session_globals| f(&session_globals.metavar_spans))
219}
220
221#[derive(Debug, Eq, PartialEq, Clone, Ord, PartialOrd, Decodable)]
224pub enum RealFileName {
225 LocalPath(PathBuf),
226 Remapped {
230 local_path: Option<PathBuf>,
233 virtual_name: PathBuf,
236 },
237}
238
239impl Hash for RealFileName {
240 fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
241 self.remapped_path_if_available().hash(state)
246 }
247}
248
249impl<S: Encoder> Encodable<S> for RealFileName {
252 fn encode(&self, encoder: &mut S) {
253 match *self {
254 RealFileName::LocalPath(ref local_path) => {
255 encoder.emit_u8(0);
256 local_path.encode(encoder);
257 }
258
259 RealFileName::Remapped { ref local_path, ref virtual_name } => {
260 encoder.emit_u8(1);
261 assert!(local_path.is_none());
264 local_path.encode(encoder);
265 virtual_name.encode(encoder);
266 }
267 }
268 }
269}
270
271impl RealFileName {
272 pub fn local_path(&self) -> Option<&Path> {
276 match self {
277 RealFileName::LocalPath(p) => Some(p),
278 RealFileName::Remapped { local_path, virtual_name: _ } => local_path.as_deref(),
279 }
280 }
281
282 pub fn into_local_path(self) -> Option<PathBuf> {
286 match self {
287 RealFileName::LocalPath(p) => Some(p),
288 RealFileName::Remapped { local_path: p, virtual_name: _ } => p,
289 }
290 }
291
292 pub fn remapped_path_if_available(&self) -> &Path {
297 match self {
298 RealFileName::LocalPath(p)
299 | RealFileName::Remapped { local_path: _, virtual_name: p } => p,
300 }
301 }
302
303 pub fn local_path_if_available(&self) -> &Path {
307 match self {
308 RealFileName::LocalPath(path)
309 | RealFileName::Remapped { local_path: None, virtual_name: path }
310 | RealFileName::Remapped { local_path: Some(path), virtual_name: _ } => path,
311 }
312 }
313
314 pub fn to_path(&self, display_pref: FileNameDisplayPreference) -> &Path {
318 match display_pref {
319 FileNameDisplayPreference::Local | FileNameDisplayPreference::Short => {
320 self.local_path_if_available()
321 }
322 FileNameDisplayPreference::Remapped => self.remapped_path_if_available(),
323 }
324 }
325
326 pub fn to_string_lossy(&self, display_pref: FileNameDisplayPreference) -> Cow<'_, str> {
327 match display_pref {
328 FileNameDisplayPreference::Local => self.local_path_if_available().to_string_lossy(),
329 FileNameDisplayPreference::Remapped => {
330 self.remapped_path_if_available().to_string_lossy()
331 }
332 FileNameDisplayPreference::Short => self
333 .local_path_if_available()
334 .file_name()
335 .map_or_else(|| "".into(), |f| f.to_string_lossy()),
336 }
337 }
338}
339
340#[derive(Debug, Eq, PartialEq, Clone, Ord, PartialOrd, Hash, Decodable, Encodable)]
342pub enum FileName {
343 Real(RealFileName),
344 CfgSpec(Hash64),
346 Anon(Hash64),
348 MacroExpansion(Hash64),
351 ProcMacroSourceCode(Hash64),
352 CliCrateAttr(Hash64),
354 Custom(String),
356 DocTest(PathBuf, isize),
357 InlineAsm(Hash64),
359}
360
361impl From<PathBuf> for FileName {
362 fn from(p: PathBuf) -> Self {
363 FileName::Real(RealFileName::LocalPath(p))
364 }
365}
366
367#[derive(Clone, Copy, Eq, PartialEq, Hash, Debug)]
368pub enum FileNameDisplayPreference {
369 Remapped,
372 Local,
375 Short,
378}
379
380pub struct FileNameDisplay<'a> {
381 inner: &'a FileName,
382 display_pref: FileNameDisplayPreference,
383}
384
385impl fmt::Display for FileNameDisplay<'_> {
386 fn fmt(&self, fmt: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
387 use FileName::*;
388 match *self.inner {
389 Real(ref name) => {
390 write!(fmt, "{}", name.to_string_lossy(self.display_pref))
391 }
392 CfgSpec(_) => write!(fmt, "<cfgspec>"),
393 MacroExpansion(_) => write!(fmt, "<macro expansion>"),
394 Anon(_) => write!(fmt, "<anon>"),
395 ProcMacroSourceCode(_) => write!(fmt, "<proc-macro source code>"),
396 CliCrateAttr(_) => write!(fmt, "<crate attribute>"),
397 Custom(ref s) => write!(fmt, "<{s}>"),
398 DocTest(ref path, _) => write!(fmt, "{}", path.display()),
399 InlineAsm(_) => write!(fmt, "<inline asm>"),
400 }
401 }
402}
403
404impl<'a> FileNameDisplay<'a> {
405 pub fn to_string_lossy(&self) -> Cow<'a, str> {
406 match self.inner {
407 FileName::Real(inner) => inner.to_string_lossy(self.display_pref),
408 _ => Cow::from(self.to_string()),
409 }
410 }
411}
412
413impl FileName {
414 pub fn is_real(&self) -> bool {
415 use FileName::*;
416 match *self {
417 Real(_) => true,
418 Anon(_)
419 | MacroExpansion(_)
420 | ProcMacroSourceCode(_)
421 | CliCrateAttr(_)
422 | Custom(_)
423 | CfgSpec(_)
424 | DocTest(_, _)
425 | InlineAsm(_) => false,
426 }
427 }
428
429 pub fn prefer_remapped_unconditionaly(&self) -> FileNameDisplay<'_> {
430 FileNameDisplay { inner: self, display_pref: FileNameDisplayPreference::Remapped }
431 }
432
433 pub fn prefer_local(&self) -> FileNameDisplay<'_> {
436 FileNameDisplay { inner: self, display_pref: FileNameDisplayPreference::Local }
437 }
438
439 pub fn display(&self, display_pref: FileNameDisplayPreference) -> FileNameDisplay<'_> {
440 FileNameDisplay { inner: self, display_pref }
441 }
442
443 pub fn macro_expansion_source_code(src: &str) -> FileName {
444 let mut hasher = StableHasher::new();
445 src.hash(&mut hasher);
446 FileName::MacroExpansion(hasher.finish())
447 }
448
449 pub fn anon_source_code(src: &str) -> FileName {
450 let mut hasher = StableHasher::new();
451 src.hash(&mut hasher);
452 FileName::Anon(hasher.finish())
453 }
454
455 pub fn proc_macro_source_code(src: &str) -> FileName {
456 let mut hasher = StableHasher::new();
457 src.hash(&mut hasher);
458 FileName::ProcMacroSourceCode(hasher.finish())
459 }
460
461 pub fn cfg_spec_source_code(src: &str) -> FileName {
462 let mut hasher = StableHasher::new();
463 src.hash(&mut hasher);
464 FileName::CfgSpec(hasher.finish())
465 }
466
467 pub fn cli_crate_attr_source_code(src: &str) -> FileName {
468 let mut hasher = StableHasher::new();
469 src.hash(&mut hasher);
470 FileName::CliCrateAttr(hasher.finish())
471 }
472
473 pub fn doc_test_source_code(path: PathBuf, line: isize) -> FileName {
474 FileName::DocTest(path, line)
475 }
476
477 pub fn inline_asm_source_code(src: &str) -> FileName {
478 let mut hasher = StableHasher::new();
479 src.hash(&mut hasher);
480 FileName::InlineAsm(hasher.finish())
481 }
482
483 pub fn into_local_path(self) -> Option<PathBuf> {
487 match self {
488 FileName::Real(path) => path.into_local_path(),
489 FileName::DocTest(path, _) => Some(path),
490 _ => None,
491 }
492 }
493}
494
495#[derive(Clone, Copy, Hash, PartialEq, Eq)]
511#[derive_where(PartialOrd, Ord)]
512pub struct SpanData {
513 pub lo: BytePos,
514 pub hi: BytePos,
515 #[derive_where(skip)]
518 pub ctxt: SyntaxContext,
521 #[derive_where(skip)]
522 pub parent: Option<LocalDefId>,
525}
526
527impl SpanData {
528 #[inline]
529 pub fn span(&self) -> Span {
530 Span::new(self.lo, self.hi, self.ctxt, self.parent)
531 }
532 #[inline]
533 pub fn with_lo(&self, lo: BytePos) -> Span {
534 Span::new(lo, self.hi, self.ctxt, self.parent)
535 }
536 #[inline]
537 pub fn with_hi(&self, hi: BytePos) -> Span {
538 Span::new(self.lo, hi, self.ctxt, self.parent)
539 }
540 #[inline]
542 fn with_ctxt(&self, ctxt: SyntaxContext) -> Span {
543 Span::new(self.lo, self.hi, ctxt, self.parent)
544 }
545 #[inline]
547 fn with_parent(&self, parent: Option<LocalDefId>) -> Span {
548 Span::new(self.lo, self.hi, self.ctxt, parent)
549 }
550 #[inline]
552 pub fn is_dummy(self) -> bool {
553 self.lo.0 == 0 && self.hi.0 == 0
554 }
555 pub fn contains(self, other: Self) -> bool {
557 self.lo <= other.lo && other.hi <= self.hi
558 }
559}
560
561impl Default for SpanData {
562 fn default() -> Self {
563 Self { lo: BytePos(0), hi: BytePos(0), ctxt: SyntaxContext::root(), parent: None }
564 }
565}
566
567impl PartialOrd for Span {
568 fn partial_cmp(&self, rhs: &Self) -> Option<Ordering> {
569 PartialOrd::partial_cmp(&self.data(), &rhs.data())
570 }
571}
572impl Ord for Span {
573 fn cmp(&self, rhs: &Self) -> Ordering {
574 Ord::cmp(&self.data(), &rhs.data())
575 }
576}
577
578impl Span {
579 #[inline]
580 pub fn lo(self) -> BytePos {
581 self.data().lo
582 }
583 #[inline]
584 pub fn with_lo(self, lo: BytePos) -> Span {
585 self.data().with_lo(lo)
586 }
587 #[inline]
588 pub fn hi(self) -> BytePos {
589 self.data().hi
590 }
591 #[inline]
592 pub fn with_hi(self, hi: BytePos) -> Span {
593 self.data().with_hi(hi)
594 }
595 #[inline]
596 pub fn with_ctxt(self, ctxt: SyntaxContext) -> Span {
597 self.map_ctxt(|_| ctxt)
598 }
599
600 #[inline]
601 pub fn is_visible(self, sm: &SourceMap) -> bool {
602 !self.is_dummy() && sm.is_span_accessible(self)
603 }
604
605 pub fn in_external_macro(self, sm: &SourceMap) -> bool {
610 let expn_data = self.ctxt().outer_expn_data();
611 match expn_data.kind {
612 ExpnKind::Root
613 | ExpnKind::Desugaring(
614 DesugaringKind::ForLoop
615 | DesugaringKind::WhileLoop
616 | DesugaringKind::OpaqueTy
617 | DesugaringKind::Async
618 | DesugaringKind::Await,
619 ) => false,
620 ExpnKind::AstPass(_) | ExpnKind::Desugaring(_) => true, ExpnKind::Macro(MacroKind::Bang, _) => {
622 expn_data.def_site.is_dummy() || sm.is_imported(expn_data.def_site)
624 }
625 ExpnKind::Macro { .. } => true, }
627 }
628
629 pub fn in_derive_expansion(self) -> bool {
631 matches!(self.ctxt().outer_expn_data().kind, ExpnKind::Macro(MacroKind::Derive, _))
632 }
633
634 pub fn is_from_async_await(self) -> bool {
636 matches!(
637 self.ctxt().outer_expn_data().kind,
638 ExpnKind::Desugaring(DesugaringKind::Async | DesugaringKind::Await),
639 )
640 }
641
642 pub fn can_be_used_for_suggestions(self) -> bool {
644 !self.from_expansion()
645 || (self.in_derive_expansion()
649 && self.parent_callsite().map(|p| (p.lo(), p.hi())) != Some((self.lo(), self.hi())))
650 }
651
652 #[inline]
653 pub fn with_root_ctxt(lo: BytePos, hi: BytePos) -> Span {
654 Span::new(lo, hi, SyntaxContext::root(), None)
655 }
656
657 #[inline]
659 pub fn shrink_to_lo(self) -> Span {
660 let span = self.data_untracked();
661 span.with_hi(span.lo)
662 }
663 #[inline]
665 pub fn shrink_to_hi(self) -> Span {
666 let span = self.data_untracked();
667 span.with_lo(span.hi)
668 }
669
670 #[inline]
671 pub fn is_empty(self) -> bool {
673 let span = self.data_untracked();
674 span.hi == span.lo
675 }
676
677 pub fn substitute_dummy(self, other: Span) -> Span {
679 if self.is_dummy() { other } else { self }
680 }
681
682 pub fn contains(self, other: Span) -> bool {
684 let span = self.data();
685 let other = other.data();
686 span.contains(other)
687 }
688
689 pub fn overlaps(self, other: Span) -> bool {
691 let span = self.data();
692 let other = other.data();
693 span.lo < other.hi && other.lo < span.hi
694 }
695
696 pub fn overlaps_or_adjacent(self, other: Span) -> bool {
698 let span = self.data();
699 let other = other.data();
700 span.lo <= other.hi && other.lo <= span.hi
701 }
702
703 pub fn source_equal(self, other: Span) -> bool {
708 let span = self.data();
709 let other = other.data();
710 span.lo == other.lo && span.hi == other.hi
711 }
712
713 pub fn trim_start(self, other: Span) -> Option<Span> {
715 let span = self.data();
716 let other = other.data();
717 if span.hi > other.hi { Some(span.with_lo(cmp::max(span.lo, other.hi))) } else { None }
718 }
719
720 pub fn trim_end(self, other: Span) -> Option<Span> {
722 let span = self.data();
723 let other = other.data();
724 if span.lo < other.lo { Some(span.with_hi(cmp::min(span.hi, other.lo))) } else { None }
725 }
726
727 pub fn source_callsite(self) -> Span {
730 let ctxt = self.ctxt();
731 if !ctxt.is_root() { ctxt.outer_expn_data().call_site.source_callsite() } else { self }
732 }
733
734 pub fn parent_callsite(self) -> Option<Span> {
737 let ctxt = self.ctxt();
738 (!ctxt.is_root()).then(|| ctxt.outer_expn_data().call_site)
739 }
740
741 pub fn find_ancestor_inside(mut self, outer: Span) -> Option<Span> {
749 while !outer.contains(self) {
750 self = self.parent_callsite()?;
751 }
752 Some(self)
753 }
754
755 pub fn find_ancestor_in_same_ctxt(mut self, other: Span) -> Option<Span> {
766 while !self.eq_ctxt(other) {
767 self = self.parent_callsite()?;
768 }
769 Some(self)
770 }
771
772 pub fn find_ancestor_inside_same_ctxt(mut self, outer: Span) -> Option<Span> {
782 while !outer.contains(self) || !self.eq_ctxt(outer) {
783 self = self.parent_callsite()?;
784 }
785 Some(self)
786 }
787
788 pub fn find_oldest_ancestor_in_same_ctxt(self) -> Span {
818 let mut cur = self;
819 while cur.eq_ctxt(self)
820 && let Some(parent_callsite) = cur.parent_callsite()
821 {
822 cur = parent_callsite;
823 }
824 cur
825 }
826
827 pub fn edition(self) -> edition::Edition {
829 self.ctxt().edition()
830 }
831
832 #[inline]
834 pub fn is_rust_2015(self) -> bool {
835 self.edition().is_rust_2015()
836 }
837
838 #[inline]
840 pub fn at_least_rust_2018(self) -> bool {
841 self.edition().at_least_rust_2018()
842 }
843
844 #[inline]
846 pub fn at_least_rust_2021(self) -> bool {
847 self.edition().at_least_rust_2021()
848 }
849
850 #[inline]
852 pub fn at_least_rust_2024(self) -> bool {
853 self.edition().at_least_rust_2024()
854 }
855
856 pub fn source_callee(self) -> Option<ExpnData> {
862 let mut ctxt = self.ctxt();
863 let mut opt_expn_data = None;
864 while !ctxt.is_root() {
865 let expn_data = ctxt.outer_expn_data();
866 ctxt = expn_data.call_site.ctxt();
867 opt_expn_data = Some(expn_data);
868 }
869 opt_expn_data
870 }
871
872 pub fn allows_unstable(self, feature: Symbol) -> bool {
876 self.ctxt()
877 .outer_expn_data()
878 .allow_internal_unstable
879 .is_some_and(|features| features.iter().any(|&f| f == feature))
880 }
881
882 pub fn is_desugaring(self, kind: DesugaringKind) -> bool {
884 match self.ctxt().outer_expn_data().kind {
885 ExpnKind::Desugaring(k) => k == kind,
886 _ => false,
887 }
888 }
889
890 pub fn desugaring_kind(self) -> Option<DesugaringKind> {
893 match self.ctxt().outer_expn_data().kind {
894 ExpnKind::Desugaring(k) => Some(k),
895 _ => None,
896 }
897 }
898
899 pub fn allows_unsafe(self) -> bool {
903 self.ctxt().outer_expn_data().allow_internal_unsafe
904 }
905
906 pub fn macro_backtrace(mut self) -> impl Iterator<Item = ExpnData> {
907 let mut prev_span = DUMMY_SP;
908 iter::from_fn(move || {
909 loop {
910 let ctxt = self.ctxt();
911 if ctxt.is_root() {
912 return None;
913 }
914
915 let expn_data = ctxt.outer_expn_data();
916 let is_recursive = expn_data.call_site.source_equal(prev_span);
917
918 prev_span = self;
919 self = expn_data.call_site;
920
921 if !is_recursive {
923 return Some(expn_data);
924 }
925 }
926 })
927 }
928
929 pub fn split_at(self, pos: u32) -> (Span, Span) {
931 let len = self.hi().0 - self.lo().0;
932 debug_assert!(pos <= len);
933
934 let split_pos = BytePos(self.lo().0 + pos);
935 (
936 Span::new(self.lo(), split_pos, self.ctxt(), self.parent()),
937 Span::new(split_pos, self.hi(), self.ctxt(), self.parent()),
938 )
939 }
940
941 fn try_metavars(a: SpanData, b: SpanData, a_orig: Span, b_orig: Span) -> (SpanData, SpanData) {
943 match with_metavar_spans(|mspans| (mspans.get(a_orig), mspans.get(b_orig))) {
944 (None, None) => {}
945 (Some(meta_a), None) => {
946 let meta_a = meta_a.data();
947 if meta_a.ctxt == b.ctxt {
948 return (meta_a, b);
949 }
950 }
951 (None, Some(meta_b)) => {
952 let meta_b = meta_b.data();
953 if a.ctxt == meta_b.ctxt {
954 return (a, meta_b);
955 }
956 }
957 (Some(meta_a), Some(meta_b)) => {
958 let meta_b = meta_b.data();
959 if a.ctxt == meta_b.ctxt {
960 return (a, meta_b);
961 }
962 let meta_a = meta_a.data();
963 if meta_a.ctxt == b.ctxt {
964 return (meta_a, b);
965 } else if meta_a.ctxt == meta_b.ctxt {
966 return (meta_a, meta_b);
967 }
968 }
969 }
970
971 (a, b)
972 }
973
974 fn prepare_to_combine(
976 a_orig: Span,
977 b_orig: Span,
978 ) -> Result<(SpanData, SpanData, Option<LocalDefId>), Span> {
979 let (a, b) = (a_orig.data(), b_orig.data());
980 if a.ctxt == b.ctxt {
981 return Ok((a, b, if a.parent == b.parent { a.parent } else { None }));
982 }
983
984 let (a, b) = Span::try_metavars(a, b, a_orig, b_orig);
985 if a.ctxt == b.ctxt {
986 return Ok((a, b, if a.parent == b.parent { a.parent } else { None }));
987 }
988
989 let a_is_callsite = a.ctxt.is_root() || a.ctxt == b.span().source_callsite().ctxt();
997 Err(if a_is_callsite { b_orig } else { a_orig })
998 }
999
1000 pub fn with_neighbor(self, neighbor: Span) -> Span {
1002 match Span::prepare_to_combine(self, neighbor) {
1003 Ok((this, ..)) => this.span(),
1004 Err(_) => self,
1005 }
1006 }
1007
1008 pub fn to(self, end: Span) -> Span {
1019 match Span::prepare_to_combine(self, end) {
1020 Ok((from, to, parent)) => {
1021 Span::new(cmp::min(from.lo, to.lo), cmp::max(from.hi, to.hi), from.ctxt, parent)
1022 }
1023 Err(fallback) => fallback,
1024 }
1025 }
1026
1027 pub fn between(self, end: Span) -> Span {
1035 match Span::prepare_to_combine(self, end) {
1036 Ok((from, to, parent)) => {
1037 Span::new(cmp::min(from.hi, to.hi), cmp::max(from.lo, to.lo), from.ctxt, parent)
1038 }
1039 Err(fallback) => fallback,
1040 }
1041 }
1042
1043 pub fn until(self, end: Span) -> Span {
1051 match Span::prepare_to_combine(self, end) {
1052 Ok((from, to, parent)) => {
1053 Span::new(cmp::min(from.lo, to.lo), cmp::max(from.lo, to.lo), from.ctxt, parent)
1054 }
1055 Err(fallback) => fallback,
1056 }
1057 }
1058
1059 pub fn within_macro(self, within: Span, sm: &SourceMap) -> Option<Span> {
1074 match Span::prepare_to_combine(self, within) {
1075 Ok((self_, _, parent))
1082 if self_.hi < self.lo() || self.hi() < self_.lo && !sm.is_imported(within) =>
1083 {
1084 Some(Span::new(self_.lo, self_.hi, self_.ctxt, parent))
1085 }
1086 _ => None,
1087 }
1088 }
1089
1090 pub fn from_inner(self, inner: InnerSpan) -> Span {
1091 let span = self.data();
1092 Span::new(
1093 span.lo + BytePos::from_usize(inner.start),
1094 span.lo + BytePos::from_usize(inner.end),
1095 span.ctxt,
1096 span.parent,
1097 )
1098 }
1099
1100 pub fn with_def_site_ctxt(self, expn_id: ExpnId) -> Span {
1103 self.with_ctxt_from_mark(expn_id, Transparency::Opaque)
1104 }
1105
1106 pub fn with_call_site_ctxt(self, expn_id: ExpnId) -> Span {
1109 self.with_ctxt_from_mark(expn_id, Transparency::Transparent)
1110 }
1111
1112 pub fn with_mixed_site_ctxt(self, expn_id: ExpnId) -> Span {
1115 self.with_ctxt_from_mark(expn_id, Transparency::SemiTransparent)
1116 }
1117
1118 fn with_ctxt_from_mark(self, expn_id: ExpnId, transparency: Transparency) -> Span {
1122 self.with_ctxt(SyntaxContext::root().apply_mark(expn_id, transparency))
1123 }
1124
1125 #[inline]
1126 pub fn apply_mark(self, expn_id: ExpnId, transparency: Transparency) -> Span {
1127 self.map_ctxt(|ctxt| ctxt.apply_mark(expn_id, transparency))
1128 }
1129
1130 #[inline]
1131 pub fn remove_mark(&mut self) -> ExpnId {
1132 let mut mark = ExpnId::root();
1133 *self = self.map_ctxt(|mut ctxt| {
1134 mark = ctxt.remove_mark();
1135 ctxt
1136 });
1137 mark
1138 }
1139
1140 #[inline]
1141 pub fn adjust(&mut self, expn_id: ExpnId) -> Option<ExpnId> {
1142 let mut mark = None;
1143 *self = self.map_ctxt(|mut ctxt| {
1144 mark = ctxt.adjust(expn_id);
1145 ctxt
1146 });
1147 mark
1148 }
1149
1150 #[inline]
1151 pub fn normalize_to_macros_2_0_and_adjust(&mut self, expn_id: ExpnId) -> Option<ExpnId> {
1152 let mut mark = None;
1153 *self = self.map_ctxt(|mut ctxt| {
1154 mark = ctxt.normalize_to_macros_2_0_and_adjust(expn_id);
1155 ctxt
1156 });
1157 mark
1158 }
1159
1160 #[inline]
1161 pub fn glob_adjust(&mut self, expn_id: ExpnId, glob_span: Span) -> Option<Option<ExpnId>> {
1162 let mut mark = None;
1163 *self = self.map_ctxt(|mut ctxt| {
1164 mark = ctxt.glob_adjust(expn_id, glob_span);
1165 ctxt
1166 });
1167 mark
1168 }
1169
1170 #[inline]
1171 pub fn reverse_glob_adjust(
1172 &mut self,
1173 expn_id: ExpnId,
1174 glob_span: Span,
1175 ) -> Option<Option<ExpnId>> {
1176 let mut mark = None;
1177 *self = self.map_ctxt(|mut ctxt| {
1178 mark = ctxt.reverse_glob_adjust(expn_id, glob_span);
1179 ctxt
1180 });
1181 mark
1182 }
1183
1184 #[inline]
1185 pub fn normalize_to_macros_2_0(self) -> Span {
1186 self.map_ctxt(|ctxt| ctxt.normalize_to_macros_2_0())
1187 }
1188
1189 #[inline]
1190 pub fn normalize_to_macro_rules(self) -> Span {
1191 self.map_ctxt(|ctxt| ctxt.normalize_to_macro_rules())
1192 }
1193}
1194
1195impl Default for Span {
1196 fn default() -> Self {
1197 DUMMY_SP
1198 }
1199}
1200
1201rustc_index::newtype_index! {
1202 #[orderable]
1203 #[debug_format = "AttrId({})"]
1204 pub struct AttrId {}
1205}
1206
1207pub trait SpanEncoder: Encoder {
1210 fn encode_span(&mut self, span: Span);
1211 fn encode_symbol(&mut self, symbol: Symbol);
1212 fn encode_expn_id(&mut self, expn_id: ExpnId);
1213 fn encode_syntax_context(&mut self, syntax_context: SyntaxContext);
1214 fn encode_crate_num(&mut self, crate_num: CrateNum);
1217 fn encode_def_index(&mut self, def_index: DefIndex);
1218 fn encode_def_id(&mut self, def_id: DefId);
1219}
1220
1221impl SpanEncoder for FileEncoder {
1222 fn encode_span(&mut self, span: Span) {
1223 let span = span.data();
1224 span.lo.encode(self);
1225 span.hi.encode(self);
1226 }
1227
1228 fn encode_symbol(&mut self, symbol: Symbol) {
1229 self.emit_str(symbol.as_str());
1230 }
1231
1232 fn encode_expn_id(&mut self, _expn_id: ExpnId) {
1233 panic!("cannot encode `ExpnId` with `FileEncoder`");
1234 }
1235
1236 fn encode_syntax_context(&mut self, _syntax_context: SyntaxContext) {
1237 panic!("cannot encode `SyntaxContext` with `FileEncoder`");
1238 }
1239
1240 fn encode_crate_num(&mut self, crate_num: CrateNum) {
1241 self.emit_u32(crate_num.as_u32());
1242 }
1243
1244 fn encode_def_index(&mut self, _def_index: DefIndex) {
1245 panic!("cannot encode `DefIndex` with `FileEncoder`");
1246 }
1247
1248 fn encode_def_id(&mut self, def_id: DefId) {
1249 def_id.krate.encode(self);
1250 def_id.index.encode(self);
1251 }
1252}
1253
1254impl<E: SpanEncoder> Encodable<E> for Span {
1255 fn encode(&self, s: &mut E) {
1256 s.encode_span(*self);
1257 }
1258}
1259
1260impl<E: SpanEncoder> Encodable<E> for Symbol {
1261 fn encode(&self, s: &mut E) {
1262 s.encode_symbol(*self);
1263 }
1264}
1265
1266impl<E: SpanEncoder> Encodable<E> for ExpnId {
1267 fn encode(&self, s: &mut E) {
1268 s.encode_expn_id(*self)
1269 }
1270}
1271
1272impl<E: SpanEncoder> Encodable<E> for SyntaxContext {
1273 fn encode(&self, s: &mut E) {
1274 s.encode_syntax_context(*self)
1275 }
1276}
1277
1278impl<E: SpanEncoder> Encodable<E> for CrateNum {
1279 fn encode(&self, s: &mut E) {
1280 s.encode_crate_num(*self)
1281 }
1282}
1283
1284impl<E: SpanEncoder> Encodable<E> for DefIndex {
1285 fn encode(&self, s: &mut E) {
1286 s.encode_def_index(*self)
1287 }
1288}
1289
1290impl<E: SpanEncoder> Encodable<E> for DefId {
1291 fn encode(&self, s: &mut E) {
1292 s.encode_def_id(*self)
1293 }
1294}
1295
1296impl<E: SpanEncoder> Encodable<E> for AttrId {
1297 fn encode(&self, _s: &mut E) {
1298 }
1300}
1301
1302pub trait SpanDecoder: Decoder {
1305 fn decode_span(&mut self) -> Span;
1306 fn decode_symbol(&mut self) -> Symbol;
1307 fn decode_expn_id(&mut self) -> ExpnId;
1308 fn decode_syntax_context(&mut self) -> SyntaxContext;
1309 fn decode_crate_num(&mut self) -> CrateNum;
1310 fn decode_def_index(&mut self) -> DefIndex;
1311 fn decode_def_id(&mut self) -> DefId;
1312 fn decode_attr_id(&mut self) -> AttrId;
1313}
1314
1315impl SpanDecoder for MemDecoder<'_> {
1316 fn decode_span(&mut self) -> Span {
1317 let lo = Decodable::decode(self);
1318 let hi = Decodable::decode(self);
1319
1320 Span::new(lo, hi, SyntaxContext::root(), None)
1321 }
1322
1323 fn decode_symbol(&mut self) -> Symbol {
1324 Symbol::intern(self.read_str())
1325 }
1326
1327 fn decode_expn_id(&mut self) -> ExpnId {
1328 panic!("cannot decode `ExpnId` with `MemDecoder`");
1329 }
1330
1331 fn decode_syntax_context(&mut self) -> SyntaxContext {
1332 panic!("cannot decode `SyntaxContext` with `MemDecoder`");
1333 }
1334
1335 fn decode_crate_num(&mut self) -> CrateNum {
1336 CrateNum::from_u32(self.read_u32())
1337 }
1338
1339 fn decode_def_index(&mut self) -> DefIndex {
1340 panic!("cannot decode `DefIndex` with `MemDecoder`");
1341 }
1342
1343 fn decode_def_id(&mut self) -> DefId {
1344 DefId { krate: Decodable::decode(self), index: Decodable::decode(self) }
1345 }
1346
1347 fn decode_attr_id(&mut self) -> AttrId {
1348 panic!("cannot decode `AttrId` with `MemDecoder`");
1349 }
1350}
1351
1352impl<D: SpanDecoder> Decodable<D> for Span {
1353 fn decode(s: &mut D) -> Span {
1354 s.decode_span()
1355 }
1356}
1357
1358impl<D: SpanDecoder> Decodable<D> for Symbol {
1359 fn decode(s: &mut D) -> Symbol {
1360 s.decode_symbol()
1361 }
1362}
1363
1364impl<D: SpanDecoder> Decodable<D> for ExpnId {
1365 fn decode(s: &mut D) -> ExpnId {
1366 s.decode_expn_id()
1367 }
1368}
1369
1370impl<D: SpanDecoder> Decodable<D> for SyntaxContext {
1371 fn decode(s: &mut D) -> SyntaxContext {
1372 s.decode_syntax_context()
1373 }
1374}
1375
1376impl<D: SpanDecoder> Decodable<D> for CrateNum {
1377 fn decode(s: &mut D) -> CrateNum {
1378 s.decode_crate_num()
1379 }
1380}
1381
1382impl<D: SpanDecoder> Decodable<D> for DefIndex {
1383 fn decode(s: &mut D) -> DefIndex {
1384 s.decode_def_index()
1385 }
1386}
1387
1388impl<D: SpanDecoder> Decodable<D> for DefId {
1389 fn decode(s: &mut D) -> DefId {
1390 s.decode_def_id()
1391 }
1392}
1393
1394impl<D: SpanDecoder> Decodable<D> for AttrId {
1395 fn decode(s: &mut D) -> AttrId {
1396 s.decode_attr_id()
1397 }
1398}
1399
1400impl fmt::Debug for Span {
1401 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1402 fn fallback(span: Span, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1406 f.debug_struct("Span")
1407 .field("lo", &span.lo())
1408 .field("hi", &span.hi())
1409 .field("ctxt", &span.ctxt())
1410 .finish()
1411 }
1412
1413 if SESSION_GLOBALS.is_set() {
1414 with_session_globals(|session_globals| {
1415 if let Some(source_map) = &session_globals.source_map {
1416 write!(f, "{} ({:?})", source_map.span_to_diagnostic_string(*self), self.ctxt())
1417 } else {
1418 fallback(*self, f)
1419 }
1420 })
1421 } else {
1422 fallback(*self, f)
1423 }
1424 }
1425}
1426
1427impl fmt::Debug for SpanData {
1428 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1429 fmt::Debug::fmt(&self.span(), f)
1430 }
1431}
1432
1433#[derive(Copy, Clone, Encodable, Decodable, Eq, PartialEq, Debug, HashStable_Generic)]
1435pub struct MultiByteChar {
1436 pub pos: RelativeBytePos,
1438 pub bytes: u8,
1440}
1441
1442#[derive(Copy, Clone, Encodable, Decodable, Eq, PartialEq, Debug, HashStable_Generic)]
1444pub struct NormalizedPos {
1445 pub pos: RelativeBytePos,
1447 pub diff: u32,
1449}
1450
1451#[derive(PartialEq, Eq, Clone, Debug)]
1452pub enum ExternalSource {
1453 Unneeded,
1455 Foreign {
1456 kind: ExternalSourceKind,
1457 metadata_index: u32,
1459 },
1460}
1461
1462#[derive(PartialEq, Eq, Clone, Debug)]
1464pub enum ExternalSourceKind {
1465 Present(Arc<String>),
1467 AbsentOk,
1469 AbsentErr,
1471}
1472
1473impl ExternalSource {
1474 pub fn get_source(&self) -> Option<&str> {
1475 match self {
1476 ExternalSource::Foreign { kind: ExternalSourceKind::Present(src), .. } => Some(src),
1477 _ => None,
1478 }
1479 }
1480}
1481
1482#[derive(Debug)]
1483pub struct OffsetOverflowError;
1484
1485#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Encodable, Decodable)]
1486#[derive(HashStable_Generic)]
1487pub enum SourceFileHashAlgorithm {
1488 Md5,
1489 Sha1,
1490 Sha256,
1491 Blake3,
1492}
1493
1494impl Display for SourceFileHashAlgorithm {
1495 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1496 f.write_str(match self {
1497 Self::Md5 => "md5",
1498 Self::Sha1 => "sha1",
1499 Self::Sha256 => "sha256",
1500 Self::Blake3 => "blake3",
1501 })
1502 }
1503}
1504
1505impl FromStr for SourceFileHashAlgorithm {
1506 type Err = ();
1507
1508 fn from_str(s: &str) -> Result<SourceFileHashAlgorithm, ()> {
1509 match s {
1510 "md5" => Ok(SourceFileHashAlgorithm::Md5),
1511 "sha1" => Ok(SourceFileHashAlgorithm::Sha1),
1512 "sha256" => Ok(SourceFileHashAlgorithm::Sha256),
1513 "blake3" => Ok(SourceFileHashAlgorithm::Blake3),
1514 _ => Err(()),
1515 }
1516 }
1517}
1518
1519#[derive(Copy, Clone, PartialEq, Eq, Debug, Hash)]
1521#[derive(HashStable_Generic, Encodable, Decodable)]
1522pub struct SourceFileHash {
1523 pub kind: SourceFileHashAlgorithm,
1524 value: [u8; 32],
1525}
1526
1527impl Display for SourceFileHash {
1528 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1529 write!(f, "{}=", self.kind)?;
1530 for byte in self.value[0..self.hash_len()].into_iter() {
1531 write!(f, "{byte:02x}")?;
1532 }
1533 Ok(())
1534 }
1535}
1536
1537impl SourceFileHash {
1538 pub fn new_in_memory(kind: SourceFileHashAlgorithm, src: impl AsRef<[u8]>) -> SourceFileHash {
1539 let mut hash = SourceFileHash { kind, value: Default::default() };
1540 let len = hash.hash_len();
1541 let value = &mut hash.value[..len];
1542 let data = src.as_ref();
1543 match kind {
1544 SourceFileHashAlgorithm::Md5 => {
1545 value.copy_from_slice(&Md5::digest(data));
1546 }
1547 SourceFileHashAlgorithm::Sha1 => {
1548 value.copy_from_slice(&Sha1::digest(data));
1549 }
1550 SourceFileHashAlgorithm::Sha256 => {
1551 value.copy_from_slice(&Sha256::digest(data));
1552 }
1553 SourceFileHashAlgorithm::Blake3 => value.copy_from_slice(blake3::hash(data).as_bytes()),
1554 };
1555 hash
1556 }
1557
1558 pub fn new(kind: SourceFileHashAlgorithm, src: impl Read) -> Result<SourceFileHash, io::Error> {
1559 let mut hash = SourceFileHash { kind, value: Default::default() };
1560 let len = hash.hash_len();
1561 let value = &mut hash.value[..len];
1562 let mut buf = vec![0; 16 * 1024];
1565
1566 fn digest<T>(
1567 mut hasher: T,
1568 mut update: impl FnMut(&mut T, &[u8]),
1569 finish: impl FnOnce(T, &mut [u8]),
1570 mut src: impl Read,
1571 buf: &mut [u8],
1572 value: &mut [u8],
1573 ) -> Result<(), io::Error> {
1574 loop {
1575 let bytes_read = src.read(buf)?;
1576 if bytes_read == 0 {
1577 break;
1578 }
1579 update(&mut hasher, &buf[0..bytes_read]);
1580 }
1581 finish(hasher, value);
1582 Ok(())
1583 }
1584
1585 match kind {
1586 SourceFileHashAlgorithm::Sha256 => {
1587 digest(
1588 Sha256::new(),
1589 |h, b| {
1590 h.update(b);
1591 },
1592 |h, out| out.copy_from_slice(&h.finalize()),
1593 src,
1594 &mut buf,
1595 value,
1596 )?;
1597 }
1598 SourceFileHashAlgorithm::Sha1 => {
1599 digest(
1600 Sha1::new(),
1601 |h, b| {
1602 h.update(b);
1603 },
1604 |h, out| out.copy_from_slice(&h.finalize()),
1605 src,
1606 &mut buf,
1607 value,
1608 )?;
1609 }
1610 SourceFileHashAlgorithm::Md5 => {
1611 digest(
1612 Md5::new(),
1613 |h, b| {
1614 h.update(b);
1615 },
1616 |h, out| out.copy_from_slice(&h.finalize()),
1617 src,
1618 &mut buf,
1619 value,
1620 )?;
1621 }
1622 SourceFileHashAlgorithm::Blake3 => {
1623 digest(
1624 blake3::Hasher::new(),
1625 |h, b| {
1626 h.update(b);
1627 },
1628 |h, out| out.copy_from_slice(h.finalize().as_bytes()),
1629 src,
1630 &mut buf,
1631 value,
1632 )?;
1633 }
1634 }
1635 Ok(hash)
1636 }
1637
1638 pub fn matches(&self, src: &str) -> bool {
1640 Self::new_in_memory(self.kind, src.as_bytes()) == *self
1641 }
1642
1643 pub fn hash_bytes(&self) -> &[u8] {
1645 let len = self.hash_len();
1646 &self.value[..len]
1647 }
1648
1649 fn hash_len(&self) -> usize {
1650 match self.kind {
1651 SourceFileHashAlgorithm::Md5 => 16,
1652 SourceFileHashAlgorithm::Sha1 => 20,
1653 SourceFileHashAlgorithm::Sha256 | SourceFileHashAlgorithm::Blake3 => 32,
1654 }
1655 }
1656}
1657
1658#[derive(Clone)]
1659pub enum SourceFileLines {
1660 Lines(Vec<RelativeBytePos>),
1662
1663 Diffs(SourceFileDiffs),
1665}
1666
1667impl SourceFileLines {
1668 pub fn is_lines(&self) -> bool {
1669 matches!(self, SourceFileLines::Lines(_))
1670 }
1671}
1672
1673#[derive(Clone)]
1681pub struct SourceFileDiffs {
1682 bytes_per_diff: usize,
1686
1687 num_diffs: usize,
1690
1691 raw_diffs: Vec<u8>,
1697}
1698
1699pub struct SourceFile {
1701 pub name: FileName,
1705 pub src: Option<Arc<String>>,
1707 pub src_hash: SourceFileHash,
1709 pub checksum_hash: Option<SourceFileHash>,
1713 pub external_src: FreezeLock<ExternalSource>,
1716 pub start_pos: BytePos,
1718 pub source_len: RelativeBytePos,
1720 pub lines: FreezeLock<SourceFileLines>,
1722 pub multibyte_chars: Vec<MultiByteChar>,
1724 pub normalized_pos: Vec<NormalizedPos>,
1726 pub stable_id: StableSourceFileId,
1730 pub cnum: CrateNum,
1732}
1733
1734impl Clone for SourceFile {
1735 fn clone(&self) -> Self {
1736 Self {
1737 name: self.name.clone(),
1738 src: self.src.clone(),
1739 src_hash: self.src_hash,
1740 checksum_hash: self.checksum_hash,
1741 external_src: self.external_src.clone(),
1742 start_pos: self.start_pos,
1743 source_len: self.source_len,
1744 lines: self.lines.clone(),
1745 multibyte_chars: self.multibyte_chars.clone(),
1746 normalized_pos: self.normalized_pos.clone(),
1747 stable_id: self.stable_id,
1748 cnum: self.cnum,
1749 }
1750 }
1751}
1752
1753impl<S: SpanEncoder> Encodable<S> for SourceFile {
1754 fn encode(&self, s: &mut S) {
1755 self.name.encode(s);
1756 self.src_hash.encode(s);
1757 self.checksum_hash.encode(s);
1758 self.source_len.encode(s);
1760
1761 assert!(self.lines.read().is_lines());
1763 let lines = self.lines();
1764 s.emit_u32(lines.len() as u32);
1766
1767 if lines.len() != 0 {
1769 let max_line_length = if lines.len() == 1 {
1770 0
1771 } else {
1772 lines
1773 .array_windows()
1774 .map(|&[fst, snd]| snd - fst)
1775 .map(|bp| bp.to_usize())
1776 .max()
1777 .unwrap()
1778 };
1779
1780 let bytes_per_diff: usize = match max_line_length {
1781 0..=0xFF => 1,
1782 0x100..=0xFFFF => 2,
1783 _ => 4,
1784 };
1785
1786 s.emit_u8(bytes_per_diff as u8);
1788
1789 assert_eq!(lines[0], RelativeBytePos(0));
1791
1792 let diff_iter = lines.array_windows().map(|&[fst, snd]| snd - fst);
1794 let num_diffs = lines.len() - 1;
1795 let mut raw_diffs;
1796 match bytes_per_diff {
1797 1 => {
1798 raw_diffs = Vec::with_capacity(num_diffs);
1799 for diff in diff_iter {
1800 raw_diffs.push(diff.0 as u8);
1801 }
1802 }
1803 2 => {
1804 raw_diffs = Vec::with_capacity(bytes_per_diff * num_diffs);
1805 for diff in diff_iter {
1806 raw_diffs.extend_from_slice(&(diff.0 as u16).to_le_bytes());
1807 }
1808 }
1809 4 => {
1810 raw_diffs = Vec::with_capacity(bytes_per_diff * num_diffs);
1811 for diff in diff_iter {
1812 raw_diffs.extend_from_slice(&(diff.0).to_le_bytes());
1813 }
1814 }
1815 _ => unreachable!(),
1816 }
1817 s.emit_raw_bytes(&raw_diffs);
1818 }
1819
1820 self.multibyte_chars.encode(s);
1821 self.stable_id.encode(s);
1822 self.normalized_pos.encode(s);
1823 self.cnum.encode(s);
1824 }
1825}
1826
1827impl<D: SpanDecoder> Decodable<D> for SourceFile {
1828 fn decode(d: &mut D) -> SourceFile {
1829 let name: FileName = Decodable::decode(d);
1830 let src_hash: SourceFileHash = Decodable::decode(d);
1831 let checksum_hash: Option<SourceFileHash> = Decodable::decode(d);
1832 let source_len: RelativeBytePos = Decodable::decode(d);
1833 let lines = {
1834 let num_lines: u32 = Decodable::decode(d);
1835 if num_lines > 0 {
1836 let bytes_per_diff = d.read_u8() as usize;
1838
1839 let num_diffs = num_lines as usize - 1;
1841 let raw_diffs = d.read_raw_bytes(bytes_per_diff * num_diffs).to_vec();
1842 SourceFileLines::Diffs(SourceFileDiffs { bytes_per_diff, num_diffs, raw_diffs })
1843 } else {
1844 SourceFileLines::Lines(vec![])
1845 }
1846 };
1847 let multibyte_chars: Vec<MultiByteChar> = Decodable::decode(d);
1848 let stable_id = Decodable::decode(d);
1849 let normalized_pos: Vec<NormalizedPos> = Decodable::decode(d);
1850 let cnum: CrateNum = Decodable::decode(d);
1851 SourceFile {
1852 name,
1853 start_pos: BytePos::from_u32(0),
1854 source_len,
1855 src: None,
1856 src_hash,
1857 checksum_hash,
1858 external_src: FreezeLock::frozen(ExternalSource::Unneeded),
1861 lines: FreezeLock::new(lines),
1862 multibyte_chars,
1863 normalized_pos,
1864 stable_id,
1865 cnum,
1866 }
1867 }
1868}
1869
1870impl fmt::Debug for SourceFile {
1871 fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
1872 write!(fmt, "SourceFile({:?})", self.name)
1873 }
1874}
1875
1876#[derive(
1898 Debug,
1899 Clone,
1900 Copy,
1901 Hash,
1902 PartialEq,
1903 Eq,
1904 HashStable_Generic,
1905 Encodable,
1906 Decodable,
1907 Default,
1908 PartialOrd,
1909 Ord
1910)]
1911pub struct StableSourceFileId(Hash128);
1912
1913impl StableSourceFileId {
1914 fn from_filename_in_current_crate(filename: &FileName) -> Self {
1915 Self::from_filename_and_stable_crate_id(filename, None)
1916 }
1917
1918 pub fn from_filename_for_export(
1919 filename: &FileName,
1920 local_crate_stable_crate_id: StableCrateId,
1921 ) -> Self {
1922 Self::from_filename_and_stable_crate_id(filename, Some(local_crate_stable_crate_id))
1923 }
1924
1925 fn from_filename_and_stable_crate_id(
1926 filename: &FileName,
1927 stable_crate_id: Option<StableCrateId>,
1928 ) -> Self {
1929 let mut hasher = StableHasher::new();
1930 filename.hash(&mut hasher);
1931 stable_crate_id.hash(&mut hasher);
1932 StableSourceFileId(hasher.finish())
1933 }
1934}
1935
1936impl SourceFile {
1937 const MAX_FILE_SIZE: u32 = u32::MAX - 1;
1938
1939 pub fn new(
1940 name: FileName,
1941 mut src: String,
1942 hash_kind: SourceFileHashAlgorithm,
1943 checksum_hash_kind: Option<SourceFileHashAlgorithm>,
1944 ) -> Result<Self, OffsetOverflowError> {
1945 let src_hash = SourceFileHash::new_in_memory(hash_kind, src.as_bytes());
1947 let checksum_hash = checksum_hash_kind.map(|checksum_hash_kind| {
1948 if checksum_hash_kind == hash_kind {
1949 src_hash
1950 } else {
1951 SourceFileHash::new_in_memory(checksum_hash_kind, src.as_bytes())
1952 }
1953 });
1954 let normalized_pos = normalize_src(&mut src);
1955
1956 let stable_id = StableSourceFileId::from_filename_in_current_crate(&name);
1957 let source_len = src.len();
1958 let source_len = u32::try_from(source_len).map_err(|_| OffsetOverflowError)?;
1959 if source_len > Self::MAX_FILE_SIZE {
1960 return Err(OffsetOverflowError);
1961 }
1962
1963 let (lines, multibyte_chars) = analyze_source_file::analyze_source_file(&src);
1964
1965 Ok(SourceFile {
1966 name,
1967 src: Some(Arc::new(src)),
1968 src_hash,
1969 checksum_hash,
1970 external_src: FreezeLock::frozen(ExternalSource::Unneeded),
1971 start_pos: BytePos::from_u32(0),
1972 source_len: RelativeBytePos::from_u32(source_len),
1973 lines: FreezeLock::frozen(SourceFileLines::Lines(lines)),
1974 multibyte_chars,
1975 normalized_pos,
1976 stable_id,
1977 cnum: LOCAL_CRATE,
1978 })
1979 }
1980
1981 fn convert_diffs_to_lines_frozen(&self) {
1984 let mut guard = if let Some(guard) = self.lines.try_write() { guard } else { return };
1985
1986 let SourceFileDiffs { bytes_per_diff, num_diffs, raw_diffs } = match &*guard {
1987 SourceFileLines::Diffs(diffs) => diffs,
1988 SourceFileLines::Lines(..) => {
1989 FreezeWriteGuard::freeze(guard);
1990 return;
1991 }
1992 };
1993
1994 let num_lines = num_diffs + 1;
1996 let mut lines = Vec::with_capacity(num_lines);
1997 let mut line_start = RelativeBytePos(0);
1998 lines.push(line_start);
1999
2000 assert_eq!(*num_diffs, raw_diffs.len() / bytes_per_diff);
2001 match bytes_per_diff {
2002 1 => {
2003 lines.extend(raw_diffs.into_iter().map(|&diff| {
2004 line_start = line_start + RelativeBytePos(diff as u32);
2005 line_start
2006 }));
2007 }
2008 2 => {
2009 lines.extend((0..*num_diffs).map(|i| {
2010 let pos = bytes_per_diff * i;
2011 let bytes = [raw_diffs[pos], raw_diffs[pos + 1]];
2012 let diff = u16::from_le_bytes(bytes);
2013 line_start = line_start + RelativeBytePos(diff as u32);
2014 line_start
2015 }));
2016 }
2017 4 => {
2018 lines.extend((0..*num_diffs).map(|i| {
2019 let pos = bytes_per_diff * i;
2020 let bytes = [
2021 raw_diffs[pos],
2022 raw_diffs[pos + 1],
2023 raw_diffs[pos + 2],
2024 raw_diffs[pos + 3],
2025 ];
2026 let diff = u32::from_le_bytes(bytes);
2027 line_start = line_start + RelativeBytePos(diff);
2028 line_start
2029 }));
2030 }
2031 _ => unreachable!(),
2032 }
2033
2034 *guard = SourceFileLines::Lines(lines);
2035
2036 FreezeWriteGuard::freeze(guard);
2037 }
2038
2039 pub fn lines(&self) -> &[RelativeBytePos] {
2040 if let Some(SourceFileLines::Lines(lines)) = self.lines.get() {
2041 return &lines[..];
2042 }
2043
2044 outline(|| {
2045 self.convert_diffs_to_lines_frozen();
2046 if let Some(SourceFileLines::Lines(lines)) = self.lines.get() {
2047 return &lines[..];
2048 }
2049 unreachable!()
2050 })
2051 }
2052
2053 pub fn line_begin_pos(&self, pos: BytePos) -> BytePos {
2055 let pos = self.relative_position(pos);
2056 let line_index = self.lookup_line(pos).unwrap();
2057 let line_start_pos = self.lines()[line_index];
2058 self.absolute_position(line_start_pos)
2059 }
2060
2061 pub fn add_external_src<F>(&self, get_src: F) -> bool
2066 where
2067 F: FnOnce() -> Option<String>,
2068 {
2069 if !self.external_src.is_frozen() {
2070 let src = get_src();
2071 let src = src.and_then(|mut src| {
2072 self.src_hash.matches(&src).then(|| {
2074 normalize_src(&mut src);
2075 src
2076 })
2077 });
2078
2079 self.external_src.try_write().map(|mut external_src| {
2080 if let ExternalSource::Foreign {
2081 kind: src_kind @ ExternalSourceKind::AbsentOk,
2082 ..
2083 } = &mut *external_src
2084 {
2085 *src_kind = if let Some(src) = src {
2086 ExternalSourceKind::Present(Arc::new(src))
2087 } else {
2088 ExternalSourceKind::AbsentErr
2089 };
2090 } else {
2091 panic!("unexpected state {:?}", *external_src)
2092 }
2093
2094 FreezeWriteGuard::freeze(external_src)
2096 });
2097 }
2098
2099 self.src.is_some() || self.external_src.read().get_source().is_some()
2100 }
2101
2102 pub fn get_line(&self, line_number: usize) -> Option<Cow<'_, str>> {
2105 fn get_until_newline(src: &str, begin: usize) -> &str {
2106 let slice = &src[begin..];
2110 match slice.find('\n') {
2111 Some(e) => &slice[..e],
2112 None => slice,
2113 }
2114 }
2115
2116 let begin = {
2117 let line = self.lines().get(line_number).copied()?;
2118 line.to_usize()
2119 };
2120
2121 if let Some(ref src) = self.src {
2122 Some(Cow::from(get_until_newline(src, begin)))
2123 } else {
2124 self.external_src
2125 .borrow()
2126 .get_source()
2127 .map(|src| Cow::Owned(String::from(get_until_newline(src, begin))))
2128 }
2129 }
2130
2131 pub fn is_real_file(&self) -> bool {
2132 self.name.is_real()
2133 }
2134
2135 #[inline]
2136 pub fn is_imported(&self) -> bool {
2137 self.src.is_none()
2138 }
2139
2140 pub fn count_lines(&self) -> usize {
2141 self.lines().len()
2142 }
2143
2144 #[inline]
2145 pub fn absolute_position(&self, pos: RelativeBytePos) -> BytePos {
2146 BytePos::from_u32(pos.to_u32() + self.start_pos.to_u32())
2147 }
2148
2149 #[inline]
2150 pub fn relative_position(&self, pos: BytePos) -> RelativeBytePos {
2151 RelativeBytePos::from_u32(pos.to_u32() - self.start_pos.to_u32())
2152 }
2153
2154 #[inline]
2155 pub fn end_position(&self) -> BytePos {
2156 self.absolute_position(self.source_len)
2157 }
2158
2159 pub fn lookup_line(&self, pos: RelativeBytePos) -> Option<usize> {
2164 self.lines().partition_point(|x| x <= &pos).checked_sub(1)
2165 }
2166
2167 pub fn line_bounds(&self, line_index: usize) -> Range<BytePos> {
2168 if self.is_empty() {
2169 return self.start_pos..self.start_pos;
2170 }
2171
2172 let lines = self.lines();
2173 assert!(line_index < lines.len());
2174 if line_index == (lines.len() - 1) {
2175 self.absolute_position(lines[line_index])..self.end_position()
2176 } else {
2177 self.absolute_position(lines[line_index])..self.absolute_position(lines[line_index + 1])
2178 }
2179 }
2180
2181 #[inline]
2186 pub fn contains(&self, byte_pos: BytePos) -> bool {
2187 byte_pos >= self.start_pos && byte_pos <= self.end_position()
2188 }
2189
2190 #[inline]
2191 pub fn is_empty(&self) -> bool {
2192 self.source_len.to_u32() == 0
2193 }
2194
2195 pub fn original_relative_byte_pos(&self, pos: BytePos) -> RelativeBytePos {
2198 let pos = self.relative_position(pos);
2199
2200 let diff = match self.normalized_pos.binary_search_by(|np| np.pos.cmp(&pos)) {
2204 Ok(i) => self.normalized_pos[i].diff,
2205 Err(0) => 0,
2206 Err(i) => self.normalized_pos[i - 1].diff,
2207 };
2208
2209 RelativeBytePos::from_u32(pos.0 + diff)
2210 }
2211
2212 pub fn normalized_byte_pos(&self, offset: u32) -> BytePos {
2222 let diff = match self
2223 .normalized_pos
2224 .binary_search_by(|np| (np.pos.0 + np.diff).cmp(&(self.start_pos.0 + offset)))
2225 {
2226 Ok(i) => self.normalized_pos[i].diff,
2227 Err(0) => 0,
2228 Err(i) => self.normalized_pos[i - 1].diff,
2229 };
2230
2231 BytePos::from_u32(self.start_pos.0 + offset - diff)
2232 }
2233
2234 fn bytepos_to_file_charpos(&self, bpos: RelativeBytePos) -> CharPos {
2236 let mut total_extra_bytes = 0;
2238
2239 for mbc in self.multibyte_chars.iter() {
2240 debug!("{}-byte char at {:?}", mbc.bytes, mbc.pos);
2241 if mbc.pos < bpos {
2242 total_extra_bytes += mbc.bytes as u32 - 1;
2245 assert!(bpos.to_u32() >= mbc.pos.to_u32() + mbc.bytes as u32);
2248 } else {
2249 break;
2250 }
2251 }
2252
2253 assert!(total_extra_bytes <= bpos.to_u32());
2254 CharPos(bpos.to_usize() - total_extra_bytes as usize)
2255 }
2256
2257 fn lookup_file_pos(&self, pos: RelativeBytePos) -> (usize, CharPos) {
2260 let chpos = self.bytepos_to_file_charpos(pos);
2261 match self.lookup_line(pos) {
2262 Some(a) => {
2263 let line = a + 1; let linebpos = self.lines()[a];
2265 let linechpos = self.bytepos_to_file_charpos(linebpos);
2266 let col = chpos - linechpos;
2267 debug!("byte pos {:?} is on the line at byte pos {:?}", pos, linebpos);
2268 debug!("char pos {:?} is on the line at char pos {:?}", chpos, linechpos);
2269 debug!("byte is on line: {}", line);
2270 assert!(chpos >= linechpos);
2271 (line, col)
2272 }
2273 None => (0, chpos),
2274 }
2275 }
2276
2277 pub fn lookup_file_pos_with_col_display(&self, pos: BytePos) -> (usize, CharPos, usize) {
2280 let pos = self.relative_position(pos);
2281 let (line, col_or_chpos) = self.lookup_file_pos(pos);
2282 if line > 0 {
2283 let Some(code) = self.get_line(line - 1) else {
2284 tracing::info!("couldn't find line {line} {:?}", self.name);
2292 return (line, col_or_chpos, col_or_chpos.0);
2293 };
2294 let display_col = code.chars().take(col_or_chpos.0).map(|ch| char_width(ch)).sum();
2295 (line, col_or_chpos, display_col)
2296 } else {
2297 (0, col_or_chpos, col_or_chpos.0)
2299 }
2300 }
2301}
2302
2303pub fn char_width(ch: char) -> usize {
2304 match ch {
2307 '\t' => 4,
2308 '\u{0000}' | '\u{0001}' | '\u{0002}' | '\u{0003}' | '\u{0004}' | '\u{0005}'
2312 | '\u{0006}' | '\u{0007}' | '\u{0008}' | '\u{000B}' | '\u{000C}' | '\u{000D}'
2313 | '\u{000E}' | '\u{000F}' | '\u{0010}' | '\u{0011}' | '\u{0012}' | '\u{0013}'
2314 | '\u{0014}' | '\u{0015}' | '\u{0016}' | '\u{0017}' | '\u{0018}' | '\u{0019}'
2315 | '\u{001A}' | '\u{001B}' | '\u{001C}' | '\u{001D}' | '\u{001E}' | '\u{001F}'
2316 | '\u{007F}' | '\u{202A}' | '\u{202B}' | '\u{202D}' | '\u{202E}' | '\u{2066}'
2317 | '\u{2067}' | '\u{2068}' | '\u{202C}' | '\u{2069}' => 1,
2318 _ => unicode_width::UnicodeWidthChar::width(ch).unwrap_or(1),
2319 }
2320}
2321
2322pub fn str_width(s: &str) -> usize {
2323 s.chars().map(char_width).sum()
2324}
2325
2326fn normalize_src(src: &mut String) -> Vec<NormalizedPos> {
2328 let mut normalized_pos = vec![];
2329 remove_bom(src, &mut normalized_pos);
2330 normalize_newlines(src, &mut normalized_pos);
2331 normalized_pos
2332}
2333
2334fn remove_bom(src: &mut String, normalized_pos: &mut Vec<NormalizedPos>) {
2336 if src.starts_with('\u{feff}') {
2337 src.drain(..3);
2338 normalized_pos.push(NormalizedPos { pos: RelativeBytePos(0), diff: 3 });
2339 }
2340}
2341
2342fn normalize_newlines(src: &mut String, normalized_pos: &mut Vec<NormalizedPos>) {
2346 if !src.as_bytes().contains(&b'\r') {
2347 return;
2348 }
2349
2350 let mut buf = std::mem::replace(src, String::new()).into_bytes();
2356 let mut gap_len = 0;
2357 let mut tail = buf.as_mut_slice();
2358 let mut cursor = 0;
2359 let original_gap = normalized_pos.last().map_or(0, |l| l.diff);
2360 loop {
2361 let idx = match find_crlf(&tail[gap_len..]) {
2362 None => tail.len(),
2363 Some(idx) => idx + gap_len,
2364 };
2365 tail.copy_within(gap_len..idx, 0);
2366 tail = &mut tail[idx - gap_len..];
2367 if tail.len() == gap_len {
2368 break;
2369 }
2370 cursor += idx - gap_len;
2371 gap_len += 1;
2372 normalized_pos.push(NormalizedPos {
2373 pos: RelativeBytePos::from_usize(cursor + 1),
2374 diff: original_gap + gap_len as u32,
2375 });
2376 }
2377
2378 let new_len = buf.len() - gap_len;
2381 unsafe {
2382 buf.set_len(new_len);
2383 *src = String::from_utf8_unchecked(buf);
2384 }
2385
2386 fn find_crlf(src: &[u8]) -> Option<usize> {
2387 let mut search_idx = 0;
2388 while let Some(idx) = find_cr(&src[search_idx..]) {
2389 if src[search_idx..].get(idx + 1) != Some(&b'\n') {
2390 search_idx += idx + 1;
2391 continue;
2392 }
2393 return Some(search_idx + idx);
2394 }
2395 None
2396 }
2397
2398 fn find_cr(src: &[u8]) -> Option<usize> {
2399 src.iter().position(|&b| b == b'\r')
2400 }
2401}
2402
2403pub trait Pos {
2408 fn from_usize(n: usize) -> Self;
2409 fn to_usize(&self) -> usize;
2410 fn from_u32(n: u32) -> Self;
2411 fn to_u32(&self) -> u32;
2412}
2413
2414macro_rules! impl_pos {
2415 (
2416 $(
2417 $(#[$attr:meta])*
2418 $vis:vis struct $ident:ident($inner_vis:vis $inner_ty:ty);
2419 )*
2420 ) => {
2421 $(
2422 $(#[$attr])*
2423 $vis struct $ident($inner_vis $inner_ty);
2424
2425 impl Pos for $ident {
2426 #[inline(always)]
2427 fn from_usize(n: usize) -> $ident {
2428 $ident(n as $inner_ty)
2429 }
2430
2431 #[inline(always)]
2432 fn to_usize(&self) -> usize {
2433 self.0 as usize
2434 }
2435
2436 #[inline(always)]
2437 fn from_u32(n: u32) -> $ident {
2438 $ident(n as $inner_ty)
2439 }
2440
2441 #[inline(always)]
2442 fn to_u32(&self) -> u32 {
2443 self.0 as u32
2444 }
2445 }
2446
2447 impl Add for $ident {
2448 type Output = $ident;
2449
2450 #[inline(always)]
2451 fn add(self, rhs: $ident) -> $ident {
2452 $ident(self.0 + rhs.0)
2453 }
2454 }
2455
2456 impl Sub for $ident {
2457 type Output = $ident;
2458
2459 #[inline(always)]
2460 fn sub(self, rhs: $ident) -> $ident {
2461 $ident(self.0 - rhs.0)
2462 }
2463 }
2464 )*
2465 };
2466}
2467
2468impl_pos! {
2469 #[derive(Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord, Debug)]
2473 pub struct BytePos(pub u32);
2474
2475 #[derive(Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord, Debug)]
2477 pub struct RelativeBytePos(pub u32);
2478
2479 #[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Debug)]
2485 pub struct CharPos(pub usize);
2486}
2487
2488impl<S: Encoder> Encodable<S> for BytePos {
2489 fn encode(&self, s: &mut S) {
2490 s.emit_u32(self.0);
2491 }
2492}
2493
2494impl<D: Decoder> Decodable<D> for BytePos {
2495 fn decode(d: &mut D) -> BytePos {
2496 BytePos(d.read_u32())
2497 }
2498}
2499
2500impl<H: HashStableContext> HashStable<H> for RelativeBytePos {
2501 fn hash_stable(&self, hcx: &mut H, hasher: &mut StableHasher) {
2502 self.0.hash_stable(hcx, hasher);
2503 }
2504}
2505
2506impl<S: Encoder> Encodable<S> for RelativeBytePos {
2507 fn encode(&self, s: &mut S) {
2508 s.emit_u32(self.0);
2509 }
2510}
2511
2512impl<D: Decoder> Decodable<D> for RelativeBytePos {
2513 fn decode(d: &mut D) -> RelativeBytePos {
2514 RelativeBytePos(d.read_u32())
2515 }
2516}
2517
2518#[derive(Debug, Clone)]
2524pub struct Loc {
2525 pub file: Arc<SourceFile>,
2527 pub line: usize,
2529 pub col: CharPos,
2531 pub col_display: usize,
2533}
2534
2535#[derive(Debug)]
2537pub struct SourceFileAndLine {
2538 pub sf: Arc<SourceFile>,
2539 pub line: usize,
2541}
2542#[derive(Debug)]
2543pub struct SourceFileAndBytePos {
2544 pub sf: Arc<SourceFile>,
2545 pub pos: BytePos,
2546}
2547
2548#[derive(Copy, Clone, Debug, PartialEq, Eq)]
2549pub struct LineInfo {
2550 pub line_index: usize,
2552
2553 pub start_col: CharPos,
2555
2556 pub end_col: CharPos,
2558}
2559
2560pub struct FileLines {
2561 pub file: Arc<SourceFile>,
2562 pub lines: Vec<LineInfo>,
2563}
2564
2565pub static SPAN_TRACK: AtomicRef<fn(LocalDefId)> = AtomicRef::new(&((|_| {}) as fn(_)));
2566
2567pub type FileLinesResult = Result<FileLines, SpanLinesError>;
2572
2573#[derive(Clone, PartialEq, Eq, Debug)]
2574pub enum SpanLinesError {
2575 DistinctSources(Box<DistinctSources>),
2576}
2577
2578#[derive(Clone, PartialEq, Eq, Debug)]
2579pub enum SpanSnippetError {
2580 IllFormedSpan(Span),
2581 DistinctSources(Box<DistinctSources>),
2582 MalformedForSourcemap(MalformedSourceMapPositions),
2583 SourceNotAvailable { filename: FileName },
2584}
2585
2586#[derive(Clone, PartialEq, Eq, Debug)]
2587pub struct DistinctSources {
2588 pub begin: (FileName, BytePos),
2589 pub end: (FileName, BytePos),
2590}
2591
2592#[derive(Clone, PartialEq, Eq, Debug)]
2593pub struct MalformedSourceMapPositions {
2594 pub name: FileName,
2595 pub source_len: usize,
2596 pub begin_pos: BytePos,
2597 pub end_pos: BytePos,
2598}
2599
2600#[derive(Copy, Clone, PartialEq, Eq, Debug)]
2602pub struct InnerSpan {
2603 pub start: usize,
2604 pub end: usize,
2605}
2606
2607impl InnerSpan {
2608 pub fn new(start: usize, end: usize) -> InnerSpan {
2609 InnerSpan { start, end }
2610 }
2611}
2612
2613pub trait HashStableContext {
2618 fn def_path_hash(&self, def_id: DefId) -> DefPathHash;
2619 fn hash_spans(&self) -> bool;
2620 fn unstable_opts_incremental_ignore_spans(&self) -> bool;
2623 fn def_span(&self, def_id: LocalDefId) -> Span;
2624 fn span_data_to_lines_and_cols(
2625 &mut self,
2626 span: &SpanData,
2627 ) -> Option<(Arc<SourceFile>, usize, BytePos, usize, BytePos)>;
2628 fn hashing_controls(&self) -> HashingControls;
2629}
2630
2631impl<CTX> HashStable<CTX> for Span
2632where
2633 CTX: HashStableContext,
2634{
2635 fn hash_stable(&self, ctx: &mut CTX, hasher: &mut StableHasher) {
2646 const TAG_VALID_SPAN: u8 = 0;
2647 const TAG_INVALID_SPAN: u8 = 1;
2648 const TAG_RELATIVE_SPAN: u8 = 2;
2649
2650 if !ctx.hash_spans() {
2651 return;
2652 }
2653
2654 let span = self.data_untracked();
2655 span.ctxt.hash_stable(ctx, hasher);
2656 span.parent.hash_stable(ctx, hasher);
2657
2658 if span.is_dummy() {
2659 Hash::hash(&TAG_INVALID_SPAN, hasher);
2660 return;
2661 }
2662
2663 if let Some(parent) = span.parent {
2664 let def_span = ctx.def_span(parent).data_untracked();
2665 if def_span.contains(span) {
2666 Hash::hash(&TAG_RELATIVE_SPAN, hasher);
2668 (span.lo - def_span.lo).to_u32().hash_stable(ctx, hasher);
2669 (span.hi - def_span.lo).to_u32().hash_stable(ctx, hasher);
2670 return;
2671 }
2672 }
2673
2674 let Some((file, line_lo, col_lo, line_hi, col_hi)) = ctx.span_data_to_lines_and_cols(&span)
2678 else {
2679 Hash::hash(&TAG_INVALID_SPAN, hasher);
2680 return;
2681 };
2682
2683 Hash::hash(&TAG_VALID_SPAN, hasher);
2684 Hash::hash(&file.stable_id, hasher);
2685
2686 let col_lo_trunc = (col_lo.0 as u64) & 0xFF;
2696 let line_lo_trunc = ((line_lo as u64) & 0xFF_FF_FF) << 8;
2697 let col_hi_trunc = (col_hi.0 as u64) & 0xFF << 32;
2698 let line_hi_trunc = ((line_hi as u64) & 0xFF_FF_FF) << 40;
2699 let col_line = col_lo_trunc | line_lo_trunc | col_hi_trunc | line_hi_trunc;
2700 let len = (span.hi - span.lo).0;
2701 Hash::hash(&col_line, hasher);
2702 Hash::hash(&len, hasher);
2703 }
2704}
2705
2706#[derive(Clone, Copy, Debug, Hash, PartialEq, Eq, PartialOrd, Ord)]
2712#[derive(HashStable_Generic)]
2713pub struct ErrorGuaranteed(());
2714
2715impl ErrorGuaranteed {
2716 #[deprecated = "should only be used in `DiagCtxtInner::emit_diagnostic`"]
2718 pub fn unchecked_error_guaranteed() -> Self {
2719 ErrorGuaranteed(())
2720 }
2721
2722 pub fn raise_fatal(self) -> ! {
2723 FatalError.raise()
2724 }
2725}
2726
2727impl<E: rustc_serialize::Encoder> Encodable<E> for ErrorGuaranteed {
2728 #[inline]
2729 fn encode(&self, _e: &mut E) {
2730 panic!(
2731 "should never serialize an `ErrorGuaranteed`, as we do not write metadata or \
2732 incremental caches in case errors occurred"
2733 )
2734 }
2735}
2736impl<D: rustc_serialize::Decoder> Decodable<D> for ErrorGuaranteed {
2737 #[inline]
2738 fn decode(_d: &mut D) -> ErrorGuaranteed {
2739 panic!(
2740 "`ErrorGuaranteed` should never have been serialized to metadata or incremental caches"
2741 )
2742 }
2743}