1#![allow(internal_features)]
20#![cfg_attr(bootstrap, feature(cfg_match))]
21#![cfg_attr(not(bootstrap), feature(cfg_select))]
22#![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")]
23#![doc(rust_logo)]
24#![feature(array_windows)]
25#![feature(core_io_borrowed_buf)]
26#![feature(hash_set_entry)]
27#![feature(if_let_guard)]
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)]
34extern crate self as rustc_span;
40
41use derive_where::derive_where;
42use rustc_data_structures::{AtomicRef, outline};
43use rustc_macros::{Decodable, Encodable, HashStable_Generic};
44use rustc_serialize::opaque::{FileEncoder, MemDecoder};
45use rustc_serialize::{Decodable, Decoder, Encodable, Encoder};
46use tracing::debug;
47
48mod caching_source_map_view;
49pub mod source_map;
50use source_map::{SourceMap, SourceMapInputs};
51
52pub use self::caching_source_map_view::CachingSourceMapView;
53use crate::fatal_error::FatalError;
54
55pub mod edition;
56use edition::Edition;
57pub mod hygiene;
58use hygiene::Transparency;
59pub use hygiene::{
60 DesugaringKind, ExpnData, ExpnHash, ExpnId, ExpnKind, LocalExpnId, MacroKind, SyntaxContext,
61};
62use rustc_data_structures::stable_hasher::HashingControls;
63pub mod def_id;
64use def_id::{CrateNum, DefId, DefIndex, DefPathHash, LOCAL_CRATE, LocalDefId, StableCrateId};
65pub mod edit_distance;
66mod span_encoding;
67pub use span_encoding::{DUMMY_SP, Span};
68
69pub mod symbol;
70pub use symbol::{Ident, MacroRulesNormalizedIdent, STDLIB_STABLE_CRATES, Symbol, kw, sym};
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_unconditionaly(&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, symbol: Symbol);
1189 fn encode_expn_id(&mut self, expn_id: ExpnId);
1190 fn encode_syntax_context(&mut self, syntax_context: SyntaxContext);
1191 fn encode_crate_num(&mut self, crate_num: CrateNum);
1194 fn encode_def_index(&mut self, def_index: DefIndex);
1195 fn encode_def_id(&mut self, def_id: DefId);
1196}
1197
1198impl SpanEncoder for FileEncoder {
1199 fn encode_span(&mut self, span: Span) {
1200 let span = span.data();
1201 span.lo.encode(self);
1202 span.hi.encode(self);
1203 }
1204
1205 fn encode_symbol(&mut self, symbol: Symbol) {
1206 self.emit_str(symbol.as_str());
1207 }
1208
1209 fn encode_expn_id(&mut self, _expn_id: ExpnId) {
1210 panic!("cannot encode `ExpnId` with `FileEncoder`");
1211 }
1212
1213 fn encode_syntax_context(&mut self, _syntax_context: SyntaxContext) {
1214 panic!("cannot encode `SyntaxContext` with `FileEncoder`");
1215 }
1216
1217 fn encode_crate_num(&mut self, crate_num: CrateNum) {
1218 self.emit_u32(crate_num.as_u32());
1219 }
1220
1221 fn encode_def_index(&mut self, _def_index: DefIndex) {
1222 panic!("cannot encode `DefIndex` with `FileEncoder`");
1223 }
1224
1225 fn encode_def_id(&mut self, def_id: DefId) {
1226 def_id.krate.encode(self);
1227 def_id.index.encode(self);
1228 }
1229}
1230
1231impl<E: SpanEncoder> Encodable<E> for Span {
1232 fn encode(&self, s: &mut E) {
1233 s.encode_span(*self);
1234 }
1235}
1236
1237impl<E: SpanEncoder> Encodable<E> for Symbol {
1238 fn encode(&self, s: &mut E) {
1239 s.encode_symbol(*self);
1240 }
1241}
1242
1243impl<E: SpanEncoder> Encodable<E> for ExpnId {
1244 fn encode(&self, s: &mut E) {
1245 s.encode_expn_id(*self)
1246 }
1247}
1248
1249impl<E: SpanEncoder> Encodable<E> for SyntaxContext {
1250 fn encode(&self, s: &mut E) {
1251 s.encode_syntax_context(*self)
1252 }
1253}
1254
1255impl<E: SpanEncoder> Encodable<E> for CrateNum {
1256 fn encode(&self, s: &mut E) {
1257 s.encode_crate_num(*self)
1258 }
1259}
1260
1261impl<E: SpanEncoder> Encodable<E> for DefIndex {
1262 fn encode(&self, s: &mut E) {
1263 s.encode_def_index(*self)
1264 }
1265}
1266
1267impl<E: SpanEncoder> Encodable<E> for DefId {
1268 fn encode(&self, s: &mut E) {
1269 s.encode_def_id(*self)
1270 }
1271}
1272
1273impl<E: SpanEncoder> Encodable<E> for AttrId {
1274 fn encode(&self, _s: &mut E) {
1275 }
1277}
1278
1279pub trait SpanDecoder: Decoder {
1282 fn decode_span(&mut self) -> Span;
1283 fn decode_symbol(&mut self) -> Symbol;
1284 fn decode_expn_id(&mut self) -> ExpnId;
1285 fn decode_syntax_context(&mut self) -> SyntaxContext;
1286 fn decode_crate_num(&mut self) -> CrateNum;
1287 fn decode_def_index(&mut self) -> DefIndex;
1288 fn decode_def_id(&mut self) -> DefId;
1289 fn decode_attr_id(&mut self) -> AttrId;
1290}
1291
1292impl SpanDecoder for MemDecoder<'_> {
1293 fn decode_span(&mut self) -> Span {
1294 let lo = Decodable::decode(self);
1295 let hi = Decodable::decode(self);
1296
1297 Span::new(lo, hi, SyntaxContext::root(), None)
1298 }
1299
1300 fn decode_symbol(&mut self) -> Symbol {
1301 Symbol::intern(self.read_str())
1302 }
1303
1304 fn decode_expn_id(&mut self) -> ExpnId {
1305 panic!("cannot decode `ExpnId` with `MemDecoder`");
1306 }
1307
1308 fn decode_syntax_context(&mut self) -> SyntaxContext {
1309 panic!("cannot decode `SyntaxContext` with `MemDecoder`");
1310 }
1311
1312 fn decode_crate_num(&mut self) -> CrateNum {
1313 CrateNum::from_u32(self.read_u32())
1314 }
1315
1316 fn decode_def_index(&mut self) -> DefIndex {
1317 panic!("cannot decode `DefIndex` with `MemDecoder`");
1318 }
1319
1320 fn decode_def_id(&mut self) -> DefId {
1321 DefId { krate: Decodable::decode(self), index: Decodable::decode(self) }
1322 }
1323
1324 fn decode_attr_id(&mut self) -> AttrId {
1325 panic!("cannot decode `AttrId` with `MemDecoder`");
1326 }
1327}
1328
1329impl<D: SpanDecoder> Decodable<D> for Span {
1330 fn decode(s: &mut D) -> Span {
1331 s.decode_span()
1332 }
1333}
1334
1335impl<D: SpanDecoder> Decodable<D> for Symbol {
1336 fn decode(s: &mut D) -> Symbol {
1337 s.decode_symbol()
1338 }
1339}
1340
1341impl<D: SpanDecoder> Decodable<D> for ExpnId {
1342 fn decode(s: &mut D) -> ExpnId {
1343 s.decode_expn_id()
1344 }
1345}
1346
1347impl<D: SpanDecoder> Decodable<D> for SyntaxContext {
1348 fn decode(s: &mut D) -> SyntaxContext {
1349 s.decode_syntax_context()
1350 }
1351}
1352
1353impl<D: SpanDecoder> Decodable<D> for CrateNum {
1354 fn decode(s: &mut D) -> CrateNum {
1355 s.decode_crate_num()
1356 }
1357}
1358
1359impl<D: SpanDecoder> Decodable<D> for DefIndex {
1360 fn decode(s: &mut D) -> DefIndex {
1361 s.decode_def_index()
1362 }
1363}
1364
1365impl<D: SpanDecoder> Decodable<D> for DefId {
1366 fn decode(s: &mut D) -> DefId {
1367 s.decode_def_id()
1368 }
1369}
1370
1371impl<D: SpanDecoder> Decodable<D> for AttrId {
1372 fn decode(s: &mut D) -> AttrId {
1373 s.decode_attr_id()
1374 }
1375}
1376
1377impl fmt::Debug for Span {
1378 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1379 fn fallback(span: Span, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1383 f.debug_struct("Span")
1384 .field("lo", &span.lo())
1385 .field("hi", &span.hi())
1386 .field("ctxt", &span.ctxt())
1387 .finish()
1388 }
1389
1390 if SESSION_GLOBALS.is_set() {
1391 with_session_globals(|session_globals| {
1392 if let Some(source_map) = &session_globals.source_map {
1393 write!(f, "{} ({:?})", source_map.span_to_diagnostic_string(*self), self.ctxt())
1394 } else {
1395 fallback(*self, f)
1396 }
1397 })
1398 } else {
1399 fallback(*self, f)
1400 }
1401 }
1402}
1403
1404impl fmt::Debug for SpanData {
1405 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1406 fmt::Debug::fmt(&self.span(), f)
1407 }
1408}
1409
1410#[derive(Copy, Clone, Encodable, Decodable, Eq, PartialEq, Debug, HashStable_Generic)]
1412pub struct MultiByteChar {
1413 pub pos: RelativeBytePos,
1415 pub bytes: u8,
1417}
1418
1419#[derive(Copy, Clone, Encodable, Decodable, Eq, PartialEq, Debug, HashStable_Generic)]
1421pub struct NormalizedPos {
1422 pub pos: RelativeBytePos,
1424 pub diff: u32,
1426}
1427
1428#[derive(PartialEq, Eq, Clone, Debug)]
1429pub enum ExternalSource {
1430 Unneeded,
1432 Foreign {
1433 kind: ExternalSourceKind,
1434 metadata_index: u32,
1436 },
1437}
1438
1439#[derive(PartialEq, Eq, Clone, Debug)]
1441pub enum ExternalSourceKind {
1442 Present(Arc<String>),
1444 AbsentOk,
1446 AbsentErr,
1448}
1449
1450impl ExternalSource {
1451 pub fn get_source(&self) -> Option<&str> {
1452 match self {
1453 ExternalSource::Foreign { kind: ExternalSourceKind::Present(src), .. } => Some(src),
1454 _ => None,
1455 }
1456 }
1457}
1458
1459#[derive(Debug)]
1460pub struct OffsetOverflowError;
1461
1462#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Encodable, Decodable)]
1463#[derive(HashStable_Generic)]
1464pub enum SourceFileHashAlgorithm {
1465 Md5,
1466 Sha1,
1467 Sha256,
1468 Blake3,
1469}
1470
1471impl Display for SourceFileHashAlgorithm {
1472 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1473 f.write_str(match self {
1474 Self::Md5 => "md5",
1475 Self::Sha1 => "sha1",
1476 Self::Sha256 => "sha256",
1477 Self::Blake3 => "blake3",
1478 })
1479 }
1480}
1481
1482impl FromStr for SourceFileHashAlgorithm {
1483 type Err = ();
1484
1485 fn from_str(s: &str) -> Result<SourceFileHashAlgorithm, ()> {
1486 match s {
1487 "md5" => Ok(SourceFileHashAlgorithm::Md5),
1488 "sha1" => Ok(SourceFileHashAlgorithm::Sha1),
1489 "sha256" => Ok(SourceFileHashAlgorithm::Sha256),
1490 "blake3" => Ok(SourceFileHashAlgorithm::Blake3),
1491 _ => Err(()),
1492 }
1493 }
1494}
1495
1496#[derive(Copy, Clone, PartialEq, Eq, Debug, Hash)]
1498#[derive(HashStable_Generic, Encodable, Decodable)]
1499pub struct SourceFileHash {
1500 pub kind: SourceFileHashAlgorithm,
1501 value: [u8; 32],
1502}
1503
1504impl Display for SourceFileHash {
1505 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1506 write!(f, "{}=", self.kind)?;
1507 for byte in self.value[0..self.hash_len()].into_iter() {
1508 write!(f, "{byte:02x}")?;
1509 }
1510 Ok(())
1511 }
1512}
1513
1514impl SourceFileHash {
1515 pub fn new_in_memory(kind: SourceFileHashAlgorithm, src: impl AsRef<[u8]>) -> SourceFileHash {
1516 let mut hash = SourceFileHash { kind, value: Default::default() };
1517 let len = hash.hash_len();
1518 let value = &mut hash.value[..len];
1519 let data = src.as_ref();
1520 match kind {
1521 SourceFileHashAlgorithm::Md5 => {
1522 value.copy_from_slice(&Md5::digest(data));
1523 }
1524 SourceFileHashAlgorithm::Sha1 => {
1525 value.copy_from_slice(&Sha1::digest(data));
1526 }
1527 SourceFileHashAlgorithm::Sha256 => {
1528 value.copy_from_slice(&Sha256::digest(data));
1529 }
1530 SourceFileHashAlgorithm::Blake3 => value.copy_from_slice(blake3::hash(data).as_bytes()),
1531 };
1532 hash
1533 }
1534
1535 pub fn new(kind: SourceFileHashAlgorithm, src: impl Read) -> Result<SourceFileHash, io::Error> {
1536 let mut hash = SourceFileHash { kind, value: Default::default() };
1537 let len = hash.hash_len();
1538 let value = &mut hash.value[..len];
1539 let mut buf = vec![0; 16 * 1024];
1542
1543 fn digest<T>(
1544 mut hasher: T,
1545 mut update: impl FnMut(&mut T, &[u8]),
1546 finish: impl FnOnce(T, &mut [u8]),
1547 mut src: impl Read,
1548 buf: &mut [u8],
1549 value: &mut [u8],
1550 ) -> Result<(), io::Error> {
1551 loop {
1552 let bytes_read = src.read(buf)?;
1553 if bytes_read == 0 {
1554 break;
1555 }
1556 update(&mut hasher, &buf[0..bytes_read]);
1557 }
1558 finish(hasher, value);
1559 Ok(())
1560 }
1561
1562 match kind {
1563 SourceFileHashAlgorithm::Sha256 => {
1564 digest(
1565 Sha256::new(),
1566 |h, b| {
1567 h.update(b);
1568 },
1569 |h, out| out.copy_from_slice(&h.finalize()),
1570 src,
1571 &mut buf,
1572 value,
1573 )?;
1574 }
1575 SourceFileHashAlgorithm::Sha1 => {
1576 digest(
1577 Sha1::new(),
1578 |h, b| {
1579 h.update(b);
1580 },
1581 |h, out| out.copy_from_slice(&h.finalize()),
1582 src,
1583 &mut buf,
1584 value,
1585 )?;
1586 }
1587 SourceFileHashAlgorithm::Md5 => {
1588 digest(
1589 Md5::new(),
1590 |h, b| {
1591 h.update(b);
1592 },
1593 |h, out| out.copy_from_slice(&h.finalize()),
1594 src,
1595 &mut buf,
1596 value,
1597 )?;
1598 }
1599 SourceFileHashAlgorithm::Blake3 => {
1600 digest(
1601 blake3::Hasher::new(),
1602 |h, b| {
1603 h.update(b);
1604 },
1605 |h, out| out.copy_from_slice(h.finalize().as_bytes()),
1606 src,
1607 &mut buf,
1608 value,
1609 )?;
1610 }
1611 }
1612 Ok(hash)
1613 }
1614
1615 pub fn matches(&self, src: &str) -> bool {
1617 Self::new_in_memory(self.kind, src.as_bytes()) == *self
1618 }
1619
1620 pub fn hash_bytes(&self) -> &[u8] {
1622 let len = self.hash_len();
1623 &self.value[..len]
1624 }
1625
1626 fn hash_len(&self) -> usize {
1627 match self.kind {
1628 SourceFileHashAlgorithm::Md5 => 16,
1629 SourceFileHashAlgorithm::Sha1 => 20,
1630 SourceFileHashAlgorithm::Sha256 | SourceFileHashAlgorithm::Blake3 => 32,
1631 }
1632 }
1633}
1634
1635#[derive(Clone)]
1636pub enum SourceFileLines {
1637 Lines(Vec<RelativeBytePos>),
1639
1640 Diffs(SourceFileDiffs),
1642}
1643
1644impl SourceFileLines {
1645 pub fn is_lines(&self) -> bool {
1646 matches!(self, SourceFileLines::Lines(_))
1647 }
1648}
1649
1650#[derive(Clone)]
1658pub struct SourceFileDiffs {
1659 bytes_per_diff: usize,
1663
1664 num_diffs: usize,
1667
1668 raw_diffs: Vec<u8>,
1674}
1675
1676pub struct SourceFile {
1678 pub name: FileName,
1682 pub src: Option<Arc<String>>,
1684 pub src_hash: SourceFileHash,
1686 pub checksum_hash: Option<SourceFileHash>,
1690 pub external_src: FreezeLock<ExternalSource>,
1693 pub start_pos: BytePos,
1695 pub source_len: RelativeBytePos,
1697 pub lines: FreezeLock<SourceFileLines>,
1699 pub multibyte_chars: Vec<MultiByteChar>,
1701 pub normalized_pos: Vec<NormalizedPos>,
1703 pub stable_id: StableSourceFileId,
1707 pub cnum: CrateNum,
1709}
1710
1711impl Clone for SourceFile {
1712 fn clone(&self) -> Self {
1713 Self {
1714 name: self.name.clone(),
1715 src: self.src.clone(),
1716 src_hash: self.src_hash,
1717 checksum_hash: self.checksum_hash,
1718 external_src: self.external_src.clone(),
1719 start_pos: self.start_pos,
1720 source_len: self.source_len,
1721 lines: self.lines.clone(),
1722 multibyte_chars: self.multibyte_chars.clone(),
1723 normalized_pos: self.normalized_pos.clone(),
1724 stable_id: self.stable_id,
1725 cnum: self.cnum,
1726 }
1727 }
1728}
1729
1730impl<S: SpanEncoder> Encodable<S> for SourceFile {
1731 fn encode(&self, s: &mut S) {
1732 self.name.encode(s);
1733 self.src_hash.encode(s);
1734 self.checksum_hash.encode(s);
1735 self.source_len.encode(s);
1737
1738 assert!(self.lines.read().is_lines());
1740 let lines = self.lines();
1741 s.emit_u32(lines.len() as u32);
1743
1744 if lines.len() != 0 {
1746 let max_line_length = if lines.len() == 1 {
1747 0
1748 } else {
1749 lines
1750 .array_windows()
1751 .map(|&[fst, snd]| snd - fst)
1752 .map(|bp| bp.to_usize())
1753 .max()
1754 .unwrap()
1755 };
1756
1757 let bytes_per_diff: usize = match max_line_length {
1758 0..=0xFF => 1,
1759 0x100..=0xFFFF => 2,
1760 _ => 4,
1761 };
1762
1763 s.emit_u8(bytes_per_diff as u8);
1765
1766 assert_eq!(lines[0], RelativeBytePos(0));
1768
1769 let diff_iter = lines.array_windows().map(|&[fst, snd]| snd - fst);
1771 let num_diffs = lines.len() - 1;
1772 let mut raw_diffs;
1773 match bytes_per_diff {
1774 1 => {
1775 raw_diffs = Vec::with_capacity(num_diffs);
1776 for diff in diff_iter {
1777 raw_diffs.push(diff.0 as u8);
1778 }
1779 }
1780 2 => {
1781 raw_diffs = Vec::with_capacity(bytes_per_diff * num_diffs);
1782 for diff in diff_iter {
1783 raw_diffs.extend_from_slice(&(diff.0 as u16).to_le_bytes());
1784 }
1785 }
1786 4 => {
1787 raw_diffs = Vec::with_capacity(bytes_per_diff * num_diffs);
1788 for diff in diff_iter {
1789 raw_diffs.extend_from_slice(&(diff.0).to_le_bytes());
1790 }
1791 }
1792 _ => unreachable!(),
1793 }
1794 s.emit_raw_bytes(&raw_diffs);
1795 }
1796
1797 self.multibyte_chars.encode(s);
1798 self.stable_id.encode(s);
1799 self.normalized_pos.encode(s);
1800 self.cnum.encode(s);
1801 }
1802}
1803
1804impl<D: SpanDecoder> Decodable<D> for SourceFile {
1805 fn decode(d: &mut D) -> SourceFile {
1806 let name: FileName = Decodable::decode(d);
1807 let src_hash: SourceFileHash = Decodable::decode(d);
1808 let checksum_hash: Option<SourceFileHash> = Decodable::decode(d);
1809 let source_len: RelativeBytePos = Decodable::decode(d);
1810 let lines = {
1811 let num_lines: u32 = Decodable::decode(d);
1812 if num_lines > 0 {
1813 let bytes_per_diff = d.read_u8() as usize;
1815
1816 let num_diffs = num_lines as usize - 1;
1818 let raw_diffs = d.read_raw_bytes(bytes_per_diff * num_diffs).to_vec();
1819 SourceFileLines::Diffs(SourceFileDiffs { bytes_per_diff, num_diffs, raw_diffs })
1820 } else {
1821 SourceFileLines::Lines(vec![])
1822 }
1823 };
1824 let multibyte_chars: Vec<MultiByteChar> = Decodable::decode(d);
1825 let stable_id = Decodable::decode(d);
1826 let normalized_pos: Vec<NormalizedPos> = Decodable::decode(d);
1827 let cnum: CrateNum = Decodable::decode(d);
1828 SourceFile {
1829 name,
1830 start_pos: BytePos::from_u32(0),
1831 source_len,
1832 src: None,
1833 src_hash,
1834 checksum_hash,
1835 external_src: FreezeLock::frozen(ExternalSource::Unneeded),
1838 lines: FreezeLock::new(lines),
1839 multibyte_chars,
1840 normalized_pos,
1841 stable_id,
1842 cnum,
1843 }
1844 }
1845}
1846
1847impl fmt::Debug for SourceFile {
1848 fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
1849 write!(fmt, "SourceFile({:?})", self.name)
1850 }
1851}
1852
1853#[derive(
1875 Debug,
1876 Clone,
1877 Copy,
1878 Hash,
1879 PartialEq,
1880 Eq,
1881 HashStable_Generic,
1882 Encodable,
1883 Decodable,
1884 Default,
1885 PartialOrd,
1886 Ord
1887)]
1888pub struct StableSourceFileId(Hash128);
1889
1890impl StableSourceFileId {
1891 fn from_filename_in_current_crate(filename: &FileName) -> Self {
1892 Self::from_filename_and_stable_crate_id(filename, None)
1893 }
1894
1895 pub fn from_filename_for_export(
1896 filename: &FileName,
1897 local_crate_stable_crate_id: StableCrateId,
1898 ) -> Self {
1899 Self::from_filename_and_stable_crate_id(filename, Some(local_crate_stable_crate_id))
1900 }
1901
1902 fn from_filename_and_stable_crate_id(
1903 filename: &FileName,
1904 stable_crate_id: Option<StableCrateId>,
1905 ) -> Self {
1906 let mut hasher = StableHasher::new();
1907 filename.hash(&mut hasher);
1908 stable_crate_id.hash(&mut hasher);
1909 StableSourceFileId(hasher.finish())
1910 }
1911}
1912
1913impl SourceFile {
1914 const MAX_FILE_SIZE: u32 = u32::MAX - 1;
1915
1916 pub fn new(
1917 name: FileName,
1918 mut src: String,
1919 hash_kind: SourceFileHashAlgorithm,
1920 checksum_hash_kind: Option<SourceFileHashAlgorithm>,
1921 ) -> Result<Self, OffsetOverflowError> {
1922 let src_hash = SourceFileHash::new_in_memory(hash_kind, src.as_bytes());
1924 let checksum_hash = checksum_hash_kind.map(|checksum_hash_kind| {
1925 if checksum_hash_kind == hash_kind {
1926 src_hash
1927 } else {
1928 SourceFileHash::new_in_memory(checksum_hash_kind, src.as_bytes())
1929 }
1930 });
1931 let normalized_pos = normalize_src(&mut src);
1932
1933 let stable_id = StableSourceFileId::from_filename_in_current_crate(&name);
1934 let source_len = src.len();
1935 let source_len = u32::try_from(source_len).map_err(|_| OffsetOverflowError)?;
1936 if source_len > Self::MAX_FILE_SIZE {
1937 return Err(OffsetOverflowError);
1938 }
1939
1940 let (lines, multibyte_chars) = analyze_source_file::analyze_source_file(&src);
1941
1942 Ok(SourceFile {
1943 name,
1944 src: Some(Arc::new(src)),
1945 src_hash,
1946 checksum_hash,
1947 external_src: FreezeLock::frozen(ExternalSource::Unneeded),
1948 start_pos: BytePos::from_u32(0),
1949 source_len: RelativeBytePos::from_u32(source_len),
1950 lines: FreezeLock::frozen(SourceFileLines::Lines(lines)),
1951 multibyte_chars,
1952 normalized_pos,
1953 stable_id,
1954 cnum: LOCAL_CRATE,
1955 })
1956 }
1957
1958 fn convert_diffs_to_lines_frozen(&self) {
1961 let mut guard = if let Some(guard) = self.lines.try_write() { guard } else { return };
1962
1963 let SourceFileDiffs { bytes_per_diff, num_diffs, raw_diffs } = match &*guard {
1964 SourceFileLines::Diffs(diffs) => diffs,
1965 SourceFileLines::Lines(..) => {
1966 FreezeWriteGuard::freeze(guard);
1967 return;
1968 }
1969 };
1970
1971 let num_lines = num_diffs + 1;
1973 let mut lines = Vec::with_capacity(num_lines);
1974 let mut line_start = RelativeBytePos(0);
1975 lines.push(line_start);
1976
1977 assert_eq!(*num_diffs, raw_diffs.len() / bytes_per_diff);
1978 match bytes_per_diff {
1979 1 => {
1980 lines.extend(raw_diffs.into_iter().map(|&diff| {
1981 line_start = line_start + RelativeBytePos(diff as u32);
1982 line_start
1983 }));
1984 }
1985 2 => {
1986 lines.extend((0..*num_diffs).map(|i| {
1987 let pos = bytes_per_diff * i;
1988 let bytes = [raw_diffs[pos], raw_diffs[pos + 1]];
1989 let diff = u16::from_le_bytes(bytes);
1990 line_start = line_start + RelativeBytePos(diff as u32);
1991 line_start
1992 }));
1993 }
1994 4 => {
1995 lines.extend((0..*num_diffs).map(|i| {
1996 let pos = bytes_per_diff * i;
1997 let bytes = [
1998 raw_diffs[pos],
1999 raw_diffs[pos + 1],
2000 raw_diffs[pos + 2],
2001 raw_diffs[pos + 3],
2002 ];
2003 let diff = u32::from_le_bytes(bytes);
2004 line_start = line_start + RelativeBytePos(diff);
2005 line_start
2006 }));
2007 }
2008 _ => unreachable!(),
2009 }
2010
2011 *guard = SourceFileLines::Lines(lines);
2012
2013 FreezeWriteGuard::freeze(guard);
2014 }
2015
2016 pub fn lines(&self) -> &[RelativeBytePos] {
2017 if let Some(SourceFileLines::Lines(lines)) = self.lines.get() {
2018 return &lines[..];
2019 }
2020
2021 outline(|| {
2022 self.convert_diffs_to_lines_frozen();
2023 if let Some(SourceFileLines::Lines(lines)) = self.lines.get() {
2024 return &lines[..];
2025 }
2026 unreachable!()
2027 })
2028 }
2029
2030 pub fn line_begin_pos(&self, pos: BytePos) -> BytePos {
2032 let pos = self.relative_position(pos);
2033 let line_index = self.lookup_line(pos).unwrap();
2034 let line_start_pos = self.lines()[line_index];
2035 self.absolute_position(line_start_pos)
2036 }
2037
2038 pub fn add_external_src<F>(&self, get_src: F) -> bool
2043 where
2044 F: FnOnce() -> Option<String>,
2045 {
2046 if !self.external_src.is_frozen() {
2047 let src = get_src();
2048 let src = src.and_then(|mut src| {
2049 self.src_hash.matches(&src).then(|| {
2051 normalize_src(&mut src);
2052 src
2053 })
2054 });
2055
2056 self.external_src.try_write().map(|mut external_src| {
2057 if let ExternalSource::Foreign {
2058 kind: src_kind @ ExternalSourceKind::AbsentOk,
2059 ..
2060 } = &mut *external_src
2061 {
2062 *src_kind = if let Some(src) = src {
2063 ExternalSourceKind::Present(Arc::new(src))
2064 } else {
2065 ExternalSourceKind::AbsentErr
2066 };
2067 } else {
2068 panic!("unexpected state {:?}", *external_src)
2069 }
2070
2071 FreezeWriteGuard::freeze(external_src)
2073 });
2074 }
2075
2076 self.src.is_some() || self.external_src.read().get_source().is_some()
2077 }
2078
2079 pub fn get_line(&self, line_number: usize) -> Option<Cow<'_, str>> {
2082 fn get_until_newline(src: &str, begin: usize) -> &str {
2083 let slice = &src[begin..];
2087 match slice.find('\n') {
2088 Some(e) => &slice[..e],
2089 None => slice,
2090 }
2091 }
2092
2093 let begin = {
2094 let line = self.lines().get(line_number).copied()?;
2095 line.to_usize()
2096 };
2097
2098 if let Some(ref src) = self.src {
2099 Some(Cow::from(get_until_newline(src, begin)))
2100 } else {
2101 self.external_src
2102 .borrow()
2103 .get_source()
2104 .map(|src| Cow::Owned(String::from(get_until_newline(src, begin))))
2105 }
2106 }
2107
2108 pub fn is_real_file(&self) -> bool {
2109 self.name.is_real()
2110 }
2111
2112 #[inline]
2113 pub fn is_imported(&self) -> bool {
2114 self.src.is_none()
2115 }
2116
2117 pub fn count_lines(&self) -> usize {
2118 self.lines().len()
2119 }
2120
2121 #[inline]
2122 pub fn absolute_position(&self, pos: RelativeBytePos) -> BytePos {
2123 BytePos::from_u32(pos.to_u32() + self.start_pos.to_u32())
2124 }
2125
2126 #[inline]
2127 pub fn relative_position(&self, pos: BytePos) -> RelativeBytePos {
2128 RelativeBytePos::from_u32(pos.to_u32() - self.start_pos.to_u32())
2129 }
2130
2131 #[inline]
2132 pub fn end_position(&self) -> BytePos {
2133 self.absolute_position(self.source_len)
2134 }
2135
2136 pub fn lookup_line(&self, pos: RelativeBytePos) -> Option<usize> {
2141 self.lines().partition_point(|x| x <= &pos).checked_sub(1)
2142 }
2143
2144 pub fn line_bounds(&self, line_index: usize) -> Range<BytePos> {
2145 if self.is_empty() {
2146 return self.start_pos..self.start_pos;
2147 }
2148
2149 let lines = self.lines();
2150 assert!(line_index < lines.len());
2151 if line_index == (lines.len() - 1) {
2152 self.absolute_position(lines[line_index])..self.end_position()
2153 } else {
2154 self.absolute_position(lines[line_index])..self.absolute_position(lines[line_index + 1])
2155 }
2156 }
2157
2158 #[inline]
2163 pub fn contains(&self, byte_pos: BytePos) -> bool {
2164 byte_pos >= self.start_pos && byte_pos <= self.end_position()
2165 }
2166
2167 #[inline]
2168 pub fn is_empty(&self) -> bool {
2169 self.source_len.to_u32() == 0
2170 }
2171
2172 pub fn original_relative_byte_pos(&self, pos: BytePos) -> RelativeBytePos {
2175 let pos = self.relative_position(pos);
2176
2177 let diff = match self.normalized_pos.binary_search_by(|np| np.pos.cmp(&pos)) {
2181 Ok(i) => self.normalized_pos[i].diff,
2182 Err(0) => 0,
2183 Err(i) => self.normalized_pos[i - 1].diff,
2184 };
2185
2186 RelativeBytePos::from_u32(pos.0 + diff)
2187 }
2188
2189 pub fn normalized_byte_pos(&self, offset: u32) -> BytePos {
2199 let diff = match self
2200 .normalized_pos
2201 .binary_search_by(|np| (np.pos.0 + np.diff).cmp(&(self.start_pos.0 + offset)))
2202 {
2203 Ok(i) => self.normalized_pos[i].diff,
2204 Err(0) => 0,
2205 Err(i) => self.normalized_pos[i - 1].diff,
2206 };
2207
2208 BytePos::from_u32(self.start_pos.0 + offset - diff)
2209 }
2210
2211 fn bytepos_to_file_charpos(&self, bpos: RelativeBytePos) -> CharPos {
2213 let mut total_extra_bytes = 0;
2215
2216 for mbc in self.multibyte_chars.iter() {
2217 debug!("{}-byte char at {:?}", mbc.bytes, mbc.pos);
2218 if mbc.pos < bpos {
2219 total_extra_bytes += mbc.bytes as u32 - 1;
2222 assert!(bpos.to_u32() >= mbc.pos.to_u32() + mbc.bytes as u32);
2225 } else {
2226 break;
2227 }
2228 }
2229
2230 assert!(total_extra_bytes <= bpos.to_u32());
2231 CharPos(bpos.to_usize() - total_extra_bytes as usize)
2232 }
2233
2234 fn lookup_file_pos(&self, pos: RelativeBytePos) -> (usize, CharPos) {
2237 let chpos = self.bytepos_to_file_charpos(pos);
2238 match self.lookup_line(pos) {
2239 Some(a) => {
2240 let line = a + 1; let linebpos = self.lines()[a];
2242 let linechpos = self.bytepos_to_file_charpos(linebpos);
2243 let col = chpos - linechpos;
2244 debug!("byte pos {:?} is on the line at byte pos {:?}", pos, linebpos);
2245 debug!("char pos {:?} is on the line at char pos {:?}", chpos, linechpos);
2246 debug!("byte is on line: {}", line);
2247 assert!(chpos >= linechpos);
2248 (line, col)
2249 }
2250 None => (0, chpos),
2251 }
2252 }
2253
2254 pub fn lookup_file_pos_with_col_display(&self, pos: BytePos) -> (usize, CharPos, usize) {
2257 let pos = self.relative_position(pos);
2258 let (line, col_or_chpos) = self.lookup_file_pos(pos);
2259 if line > 0 {
2260 let Some(code) = self.get_line(line - 1) else {
2261 tracing::info!("couldn't find line {line} {:?}", self.name);
2269 return (line, col_or_chpos, col_or_chpos.0);
2270 };
2271 let display_col = code.chars().take(col_or_chpos.0).map(|ch| char_width(ch)).sum();
2272 (line, col_or_chpos, display_col)
2273 } else {
2274 (0, col_or_chpos, col_or_chpos.0)
2276 }
2277 }
2278}
2279
2280pub fn char_width(ch: char) -> usize {
2281 match ch {
2284 '\t' => 4,
2285 '\u{0000}' | '\u{0001}' | '\u{0002}' | '\u{0003}' | '\u{0004}' | '\u{0005}'
2289 | '\u{0006}' | '\u{0007}' | '\u{0008}' | '\u{000B}' | '\u{000C}' | '\u{000D}'
2290 | '\u{000E}' | '\u{000F}' | '\u{0010}' | '\u{0011}' | '\u{0012}' | '\u{0013}'
2291 | '\u{0014}' | '\u{0015}' | '\u{0016}' | '\u{0017}' | '\u{0018}' | '\u{0019}'
2292 | '\u{001A}' | '\u{001B}' | '\u{001C}' | '\u{001D}' | '\u{001E}' | '\u{001F}'
2293 | '\u{007F}' | '\u{202A}' | '\u{202B}' | '\u{202D}' | '\u{202E}' | '\u{2066}'
2294 | '\u{2067}' | '\u{2068}' | '\u{202C}' | '\u{2069}' => 1,
2295 _ => unicode_width::UnicodeWidthChar::width(ch).unwrap_or(1),
2296 }
2297}
2298
2299pub fn str_width(s: &str) -> usize {
2300 s.chars().map(char_width).sum()
2301}
2302
2303fn normalize_src(src: &mut String) -> Vec<NormalizedPos> {
2305 let mut normalized_pos = vec![];
2306 remove_bom(src, &mut normalized_pos);
2307 normalize_newlines(src, &mut normalized_pos);
2308 normalized_pos
2309}
2310
2311fn remove_bom(src: &mut String, normalized_pos: &mut Vec<NormalizedPos>) {
2313 if src.starts_with('\u{feff}') {
2314 src.drain(..3);
2315 normalized_pos.push(NormalizedPos { pos: RelativeBytePos(0), diff: 3 });
2316 }
2317}
2318
2319fn normalize_newlines(src: &mut String, normalized_pos: &mut Vec<NormalizedPos>) {
2323 if !src.as_bytes().contains(&b'\r') {
2324 return;
2325 }
2326
2327 let mut buf = std::mem::replace(src, String::new()).into_bytes();
2333 let mut gap_len = 0;
2334 let mut tail = buf.as_mut_slice();
2335 let mut cursor = 0;
2336 let original_gap = normalized_pos.last().map_or(0, |l| l.diff);
2337 loop {
2338 let idx = match find_crlf(&tail[gap_len..]) {
2339 None => tail.len(),
2340 Some(idx) => idx + gap_len,
2341 };
2342 tail.copy_within(gap_len..idx, 0);
2343 tail = &mut tail[idx - gap_len..];
2344 if tail.len() == gap_len {
2345 break;
2346 }
2347 cursor += idx - gap_len;
2348 gap_len += 1;
2349 normalized_pos.push(NormalizedPos {
2350 pos: RelativeBytePos::from_usize(cursor + 1),
2351 diff: original_gap + gap_len as u32,
2352 });
2353 }
2354
2355 let new_len = buf.len() - gap_len;
2358 unsafe {
2359 buf.set_len(new_len);
2360 *src = String::from_utf8_unchecked(buf);
2361 }
2362
2363 fn find_crlf(src: &[u8]) -> Option<usize> {
2364 let mut search_idx = 0;
2365 while let Some(idx) = find_cr(&src[search_idx..]) {
2366 if src[search_idx..].get(idx + 1) != Some(&b'\n') {
2367 search_idx += idx + 1;
2368 continue;
2369 }
2370 return Some(search_idx + idx);
2371 }
2372 None
2373 }
2374
2375 fn find_cr(src: &[u8]) -> Option<usize> {
2376 src.iter().position(|&b| b == b'\r')
2377 }
2378}
2379
2380pub trait Pos {
2385 fn from_usize(n: usize) -> Self;
2386 fn to_usize(&self) -> usize;
2387 fn from_u32(n: u32) -> Self;
2388 fn to_u32(&self) -> u32;
2389}
2390
2391macro_rules! impl_pos {
2392 (
2393 $(
2394 $(#[$attr:meta])*
2395 $vis:vis struct $ident:ident($inner_vis:vis $inner_ty:ty);
2396 )*
2397 ) => {
2398 $(
2399 $(#[$attr])*
2400 $vis struct $ident($inner_vis $inner_ty);
2401
2402 impl Pos for $ident {
2403 #[inline(always)]
2404 fn from_usize(n: usize) -> $ident {
2405 $ident(n as $inner_ty)
2406 }
2407
2408 #[inline(always)]
2409 fn to_usize(&self) -> usize {
2410 self.0 as usize
2411 }
2412
2413 #[inline(always)]
2414 fn from_u32(n: u32) -> $ident {
2415 $ident(n as $inner_ty)
2416 }
2417
2418 #[inline(always)]
2419 fn to_u32(&self) -> u32 {
2420 self.0 as u32
2421 }
2422 }
2423
2424 impl Add for $ident {
2425 type Output = $ident;
2426
2427 #[inline(always)]
2428 fn add(self, rhs: $ident) -> $ident {
2429 $ident(self.0 + rhs.0)
2430 }
2431 }
2432
2433 impl Sub for $ident {
2434 type Output = $ident;
2435
2436 #[inline(always)]
2437 fn sub(self, rhs: $ident) -> $ident {
2438 $ident(self.0 - rhs.0)
2439 }
2440 }
2441 )*
2442 };
2443}
2444
2445impl_pos! {
2446 #[derive(Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord, Debug)]
2450 pub struct BytePos(pub u32);
2451
2452 #[derive(Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord, Debug)]
2454 pub struct RelativeBytePos(pub u32);
2455
2456 #[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Debug)]
2462 pub struct CharPos(pub usize);
2463}
2464
2465impl<S: Encoder> Encodable<S> for BytePos {
2466 fn encode(&self, s: &mut S) {
2467 s.emit_u32(self.0);
2468 }
2469}
2470
2471impl<D: Decoder> Decodable<D> for BytePos {
2472 fn decode(d: &mut D) -> BytePos {
2473 BytePos(d.read_u32())
2474 }
2475}
2476
2477impl<H: HashStableContext> HashStable<H> for RelativeBytePos {
2478 fn hash_stable(&self, hcx: &mut H, hasher: &mut StableHasher) {
2479 self.0.hash_stable(hcx, hasher);
2480 }
2481}
2482
2483impl<S: Encoder> Encodable<S> for RelativeBytePos {
2484 fn encode(&self, s: &mut S) {
2485 s.emit_u32(self.0);
2486 }
2487}
2488
2489impl<D: Decoder> Decodable<D> for RelativeBytePos {
2490 fn decode(d: &mut D) -> RelativeBytePos {
2491 RelativeBytePos(d.read_u32())
2492 }
2493}
2494
2495#[derive(Debug, Clone)]
2501pub struct Loc {
2502 pub file: Arc<SourceFile>,
2504 pub line: usize,
2506 pub col: CharPos,
2508 pub col_display: usize,
2510}
2511
2512#[derive(Debug)]
2514pub struct SourceFileAndLine {
2515 pub sf: Arc<SourceFile>,
2516 pub line: usize,
2518}
2519#[derive(Debug)]
2520pub struct SourceFileAndBytePos {
2521 pub sf: Arc<SourceFile>,
2522 pub pos: BytePos,
2523}
2524
2525#[derive(Copy, Clone, Debug, PartialEq, Eq)]
2526pub struct LineInfo {
2527 pub line_index: usize,
2529
2530 pub start_col: CharPos,
2532
2533 pub end_col: CharPos,
2535}
2536
2537pub struct FileLines {
2538 pub file: Arc<SourceFile>,
2539 pub lines: Vec<LineInfo>,
2540}
2541
2542pub static SPAN_TRACK: AtomicRef<fn(LocalDefId)> = AtomicRef::new(&((|_| {}) as fn(_)));
2543
2544pub type FileLinesResult = Result<FileLines, SpanLinesError>;
2549
2550#[derive(Clone, PartialEq, Eq, Debug)]
2551pub enum SpanLinesError {
2552 DistinctSources(Box<DistinctSources>),
2553}
2554
2555#[derive(Clone, PartialEq, Eq, Debug)]
2556pub enum SpanSnippetError {
2557 IllFormedSpan(Span),
2558 DistinctSources(Box<DistinctSources>),
2559 MalformedForSourcemap(MalformedSourceMapPositions),
2560 SourceNotAvailable { filename: FileName },
2561}
2562
2563#[derive(Clone, PartialEq, Eq, Debug)]
2564pub struct DistinctSources {
2565 pub begin: (FileName, BytePos),
2566 pub end: (FileName, BytePos),
2567}
2568
2569#[derive(Clone, PartialEq, Eq, Debug)]
2570pub struct MalformedSourceMapPositions {
2571 pub name: FileName,
2572 pub source_len: usize,
2573 pub begin_pos: BytePos,
2574 pub end_pos: BytePos,
2575}
2576
2577#[derive(Copy, Clone, PartialEq, Eq, Debug)]
2579pub struct InnerSpan {
2580 pub start: usize,
2581 pub end: usize,
2582}
2583
2584impl InnerSpan {
2585 pub fn new(start: usize, end: usize) -> InnerSpan {
2586 InnerSpan { start, end }
2587 }
2588}
2589
2590pub trait HashStableContext {
2595 fn def_path_hash(&self, def_id: DefId) -> DefPathHash;
2596 fn hash_spans(&self) -> bool;
2597 fn unstable_opts_incremental_ignore_spans(&self) -> bool;
2600 fn def_span(&self, def_id: LocalDefId) -> Span;
2601 fn span_data_to_lines_and_cols(
2602 &mut self,
2603 span: &SpanData,
2604 ) -> Option<(Arc<SourceFile>, usize, BytePos, usize, BytePos)>;
2605 fn hashing_controls(&self) -> HashingControls;
2606}
2607
2608impl<CTX> HashStable<CTX> for Span
2609where
2610 CTX: HashStableContext,
2611{
2612 fn hash_stable(&self, ctx: &mut CTX, hasher: &mut StableHasher) {
2623 const TAG_VALID_SPAN: u8 = 0;
2624 const TAG_INVALID_SPAN: u8 = 1;
2625 const TAG_RELATIVE_SPAN: u8 = 2;
2626
2627 if !ctx.hash_spans() {
2628 return;
2629 }
2630
2631 let span = self.data_untracked();
2632 span.ctxt.hash_stable(ctx, hasher);
2633 span.parent.hash_stable(ctx, hasher);
2634
2635 if span.is_dummy() {
2636 Hash::hash(&TAG_INVALID_SPAN, hasher);
2637 return;
2638 }
2639
2640 if let Some(parent) = span.parent {
2641 let def_span = ctx.def_span(parent).data_untracked();
2642 if def_span.contains(span) {
2643 Hash::hash(&TAG_RELATIVE_SPAN, hasher);
2645 (span.lo - def_span.lo).to_u32().hash_stable(ctx, hasher);
2646 (span.hi - def_span.lo).to_u32().hash_stable(ctx, hasher);
2647 return;
2648 }
2649 }
2650
2651 let Some((file, line_lo, col_lo, line_hi, col_hi)) = ctx.span_data_to_lines_and_cols(&span)
2655 else {
2656 Hash::hash(&TAG_INVALID_SPAN, hasher);
2657 return;
2658 };
2659
2660 Hash::hash(&TAG_VALID_SPAN, hasher);
2661 Hash::hash(&file.stable_id, hasher);
2662
2663 let col_lo_trunc = (col_lo.0 as u64) & 0xFF;
2673 let line_lo_trunc = ((line_lo as u64) & 0xFF_FF_FF) << 8;
2674 let col_hi_trunc = (col_hi.0 as u64) & 0xFF << 32;
2675 let line_hi_trunc = ((line_hi as u64) & 0xFF_FF_FF) << 40;
2676 let col_line = col_lo_trunc | line_lo_trunc | col_hi_trunc | line_hi_trunc;
2677 let len = (span.hi - span.lo).0;
2678 Hash::hash(&col_line, hasher);
2679 Hash::hash(&len, hasher);
2680 }
2681}
2682
2683#[derive(Clone, Copy, Debug, Hash, PartialEq, Eq, PartialOrd, Ord)]
2689#[derive(HashStable_Generic)]
2690pub struct ErrorGuaranteed(());
2691
2692impl ErrorGuaranteed {
2693 #[deprecated = "should only be used in `DiagCtxtInner::emit_diagnostic`"]
2695 pub fn unchecked_error_guaranteed() -> Self {
2696 ErrorGuaranteed(())
2697 }
2698
2699 pub fn raise_fatal(self) -> ! {
2700 FatalError.raise()
2701 }
2702}
2703
2704impl<E: rustc_serialize::Encoder> Encodable<E> for ErrorGuaranteed {
2705 #[inline]
2706 fn encode(&self, _e: &mut E) {
2707 panic!(
2708 "should never serialize an `ErrorGuaranteed`, as we do not write metadata or \
2709 incremental caches in case errors occurred"
2710 )
2711 }
2712}
2713impl<D: rustc_serialize::Decoder> Decodable<D> for ErrorGuaranteed {
2714 #[inline]
2715 fn decode(_d: &mut D) -> ErrorGuaranteed {
2716 panic!(
2717 "`ErrorGuaranteed` should never have been serialized to metadata or incremental caches"
2718 )
2719 }
2720}