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