1 //! Source positions and related helper functions.
3 //! Important concepts in this module include:
5 //! - the *span*, represented by [`SpanData`] and related types;
6 //! - source code as represented by a [`SourceMap`]; and
7 //! - interned strings, represented by [`Symbol`]s, with some common symbols available statically in the [`sym`] module.
9 //! Unlike most compilers, the span contains not only the position in the source code, but also various other metadata,
10 //! such as the edition and macro hygiene. This metadata is stored in [`SyntaxContext`] and [`ExpnData`].
14 //! This API is completely unstable and subject to change.
16 #![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")]
17 #![feature(array_windows)]
18 #![cfg_attr(bootstrap, feature(let_else))]
19 #![feature(if_let_guard)]
20 #![feature(negative_impls)]
21 #![feature(min_specialization)]
22 #![feature(rustc_attrs)]
23 #![deny(rustc::untranslatable_diagnostic)]
24 #![deny(rustc::diagnostic_outside_of_impl)]
27 extern crate rustc_macros
;
32 use rustc_data_structures
::AtomicRef
;
33 use rustc_macros
::HashStable_Generic
;
34 use rustc_serialize
::{Decodable, Decoder, Encodable, Encoder}
;
36 mod caching_source_map_view
;
38 pub use self::caching_source_map_view
::CachingSourceMapView
;
39 use source_map
::SourceMap
;
44 use hygiene
::Transparency
;
45 pub use hygiene
::{DesugaringKind, ExpnKind, MacroKind}
;
46 pub use hygiene
::{ExpnData, ExpnHash, ExpnId, LocalExpnId, SyntaxContext}
;
47 use rustc_data_structures
::stable_hasher
::HashingControls
;
49 use def_id
::{CrateNum, DefId, DefPathHash, LocalDefId, LOCAL_CRATE}
;
52 pub use span_encoding
::{Span, DUMMY_SP}
;
55 pub use symbol
::{sym, Symbol}
;
57 mod analyze_source_file
;
62 use rustc_data_structures
::stable_hasher
::{HashStable, StableHasher}
;
63 use rustc_data_structures
::sync
::{Lock, Lrc}
;
66 use std
::cmp
::{self, Ordering}
;
69 use std
::ops
::{Add, Range, Sub}
;
70 use std
::path
::{Path, PathBuf}
;
71 use std
::str::FromStr
;
82 // Per-session global variables: this struct is stored in thread-local storage
83 // in such a way that it is accessible without any kind of handle to all
84 // threads within the compilation session, but is not accessible outside the
86 pub struct SessionGlobals
{
87 symbol_interner
: symbol
::Interner
,
88 span_interner
: Lock
<span_encoding
::SpanInterner
>,
89 hygiene_data
: Lock
<hygiene
::HygieneData
>,
90 source_map
: Lock
<Option
<Lrc
<SourceMap
>>>,
94 pub fn new(edition
: Edition
) -> SessionGlobals
{
96 symbol_interner
: symbol
::Interner
::fresh(),
97 span_interner
: Lock
::new(span_encoding
::SpanInterner
::default()),
98 hygiene_data
: Lock
::new(hygiene
::HygieneData
::new(edition
)),
99 source_map
: Lock
::new(None
),
105 pub fn create_session_globals_then
<R
>(edition
: Edition
, f
: impl FnOnce() -> R
) -> R
{
107 !SESSION_GLOBALS
.is_set(),
108 "SESSION_GLOBALS should never be overwritten! \
109 Use another thread if you need another SessionGlobals"
111 let session_globals
= SessionGlobals
::new(edition
);
112 SESSION_GLOBALS
.set(&session_globals
, f
)
116 pub fn set_session_globals_then
<R
>(session_globals
: &SessionGlobals
, f
: impl FnOnce() -> R
) -> R
{
118 !SESSION_GLOBALS
.is_set(),
119 "SESSION_GLOBALS should never be overwritten! \
120 Use another thread if you need another SessionGlobals"
122 SESSION_GLOBALS
.set(session_globals
, f
)
126 pub fn create_default_session_if_not_set_then
<R
, F
>(f
: F
) -> R
128 F
: FnOnce(&SessionGlobals
) -> R
,
130 create_session_if_not_set_then(edition
::DEFAULT_EDITION
, f
)
134 pub fn create_session_if_not_set_then
<R
, F
>(edition
: Edition
, f
: F
) -> R
136 F
: FnOnce(&SessionGlobals
) -> R
,
138 if !SESSION_GLOBALS
.is_set() {
139 let session_globals
= SessionGlobals
::new(edition
);
140 SESSION_GLOBALS
.set(&session_globals
, || SESSION_GLOBALS
.with(f
))
142 SESSION_GLOBALS
.with(f
)
147 pub fn with_session_globals
<R
, F
>(f
: F
) -> R
149 F
: FnOnce(&SessionGlobals
) -> R
,
151 SESSION_GLOBALS
.with(f
)
155 pub fn create_default_session_globals_then
<R
>(f
: impl FnOnce() -> R
) -> R
{
156 create_session_globals_then(edition
::DEFAULT_EDITION
, f
)
159 // If this ever becomes non thread-local, `decode_syntax_context`
160 // and `decode_expn_id` will need to be updated to handle concurrent
162 scoped_tls
::scoped_thread_local
!(static SESSION_GLOBALS
: SessionGlobals
);
164 // FIXME: We should use this enum or something like it to get rid of the
165 // use of magic `/rust/1.x/...` paths across the board.
166 #[derive(Debug, Eq, PartialEq, Clone, Ord, PartialOrd)]
168 pub enum RealFileName
{
170 /// For remapped paths (namely paths into libstd that have been mapped
171 /// to the appropriate spot on the local host's file system, and local file
172 /// system paths that have been remapped with `FilePathMapping`),
174 /// `local_path` is the (host-dependent) local path to the file. This is
175 /// None if the file was imported from another crate
176 local_path
: Option
<PathBuf
>,
177 /// `virtual_name` is the stable path rustc will store internally within
179 virtual_name
: PathBuf
,
183 impl Hash
for RealFileName
{
184 fn hash
<H
: std
::hash
::Hasher
>(&self, state
: &mut H
) {
185 // To prevent #70924 from happening again we should only hash the
186 // remapped (virtualized) path if that exists. This is because
187 // virtualized paths to sysroot crates (/rust/$hash or /rust/$version)
188 // remain stable even if the corresponding local_path changes
189 self.remapped_path_if_available().hash(state
)
193 // This is functionally identical to #[derive(Encodable)], with the exception of
194 // an added assert statement
195 impl<S
: Encoder
> Encodable
<S
> for RealFileName
{
196 fn encode(&self, encoder
: &mut S
) {
198 RealFileName
::LocalPath(ref local_path
) => encoder
.emit_enum_variant(0, |encoder
| {
199 local_path
.encode(encoder
);
202 RealFileName
::Remapped { ref local_path, ref virtual_name }
=> encoder
203 .emit_enum_variant(1, |encoder
| {
204 // For privacy and build reproducibility, we must not embed host-dependant path in artifacts
205 // if they have been remapped by --remap-path-prefix
206 assert
!(local_path
.is_none());
207 local_path
.encode(encoder
);
208 virtual_name
.encode(encoder
);
215 /// Returns the path suitable for reading from the file system on the local host,
216 /// if this information exists.
217 /// Avoid embedding this in build artifacts; see `remapped_path_if_available()` for that.
218 pub fn local_path(&self) -> Option
<&Path
> {
220 RealFileName
::LocalPath(p
) => Some(p
),
221 RealFileName
::Remapped { local_path: p, virtual_name: _ }
=> {
222 p
.as_ref().map(PathBuf
::as_path
)
227 /// Returns the path suitable for reading from the file system on the local host,
228 /// if this information exists.
229 /// Avoid embedding this in build artifacts; see `remapped_path_if_available()` for that.
230 pub fn into_local_path(self) -> Option
<PathBuf
> {
232 RealFileName
::LocalPath(p
) => Some(p
),
233 RealFileName
::Remapped { local_path: p, virtual_name: _ }
=> p
,
237 /// Returns the path suitable for embedding into build artifacts. This would still
238 /// be a local path if it has not been remapped. A remapped path will not correspond
239 /// to a valid file system path: see `local_path_if_available()` for something that
240 /// is more likely to return paths into the local host file system.
241 pub fn remapped_path_if_available(&self) -> &Path
{
243 RealFileName
::LocalPath(p
)
244 | RealFileName
::Remapped { local_path: _, virtual_name: p }
=> &p
,
248 /// Returns the path suitable for reading from the file system on the local host,
249 /// if this information exists. Otherwise returns the remapped name.
250 /// Avoid embedding this in build artifacts; see `remapped_path_if_available()` for that.
251 pub fn local_path_if_available(&self) -> &Path
{
253 RealFileName
::LocalPath(path
)
254 | RealFileName
::Remapped { local_path: None, virtual_name: path }
255 | RealFileName
::Remapped { local_path: Some(path), virtual_name: _ }
=> path
,
259 pub fn to_string_lossy(&self, display_pref
: FileNameDisplayPreference
) -> Cow
<'_
, str> {
261 FileNameDisplayPreference
::Local
=> self.local_path_if_available().to_string_lossy(),
262 FileNameDisplayPreference
::Remapped
=> {
263 self.remapped_path_if_available().to_string_lossy()
269 /// Differentiates between real files and common virtual files.
270 #[derive(Debug, Eq, PartialEq, Clone, Ord, PartialOrd, Hash)]
271 #[derive(Decodable, Encodable)]
274 /// Call to `quote!`.
278 /// Hack in `src/librustc_ast/parse.rs`.
281 ProcMacroSourceCode(u64),
282 /// Strings provided as `--cfg [cfgspec]` stored in a `crate_cfg`.
284 /// Strings provided as crate attributes in the CLI.
286 /// Custom sources for explicit parser calls from plugins and drivers.
288 DocTest(PathBuf
, isize),
289 /// Post-substitution inline assembly from LLVM.
293 impl From
<PathBuf
> for FileName
{
294 fn from(p
: PathBuf
) -> Self {
295 assert
!(!p
.to_string_lossy().ends_with('
>'
));
296 FileName
::Real(RealFileName
::LocalPath(p
))
300 #[derive(Clone, Copy, Eq, PartialEq, Hash, Debug)]
301 pub enum FileNameDisplayPreference
{
306 pub struct FileNameDisplay
<'a
> {
308 display_pref
: FileNameDisplayPreference
,
311 impl fmt
::Display
for FileNameDisplay
<'_
> {
312 fn fmt(&self, fmt
: &mut std
::fmt
::Formatter
<'_
>) -> std
::fmt
::Result
{
316 write
!(fmt
, "{}", name
.to_string_lossy(self.display_pref
))
318 QuoteExpansion(_
) => write
!(fmt
, "<quote expansion>"),
319 MacroExpansion(_
) => write
!(fmt
, "<macro expansion>"),
320 Anon(_
) => write
!(fmt
, "<anon>"),
321 ProcMacroSourceCode(_
) => write
!(fmt
, "<proc-macro source code>"),
322 CfgSpec(_
) => write
!(fmt
, "<cfgspec>"),
323 CliCrateAttr(_
) => write
!(fmt
, "<crate attribute>"),
324 Custom(ref s
) => write
!(fmt
, "<{}>", s
),
325 DocTest(ref path
, _
) => write
!(fmt
, "{}", path
.display()),
326 InlineAsm(_
) => write
!(fmt
, "<inline asm>"),
331 impl<'a
> FileNameDisplay
<'a
> {
332 pub fn to_string_lossy(&self) -> Cow
<'a
, str> {
334 FileName
::Real(ref inner
) => inner
.to_string_lossy(self.display_pref
),
335 _
=> Cow
::from(self.to_string()),
341 pub fn is_real(&self) -> bool
{
347 | ProcMacroSourceCode(_
)
353 | InlineAsm(_
) => false,
357 pub fn prefer_remapped(&self) -> FileNameDisplay
<'_
> {
358 FileNameDisplay { inner: self, display_pref: FileNameDisplayPreference::Remapped }
361 // This may include transient local filesystem information.
362 // Must not be embedded in build outputs.
363 pub fn prefer_local(&self) -> FileNameDisplay
<'_
> {
364 FileNameDisplay { inner: self, display_pref: FileNameDisplayPreference::Local }
367 pub fn display(&self, display_pref
: FileNameDisplayPreference
) -> FileNameDisplay
<'_
> {
368 FileNameDisplay { inner: self, display_pref }
371 pub fn macro_expansion_source_code(src
: &str) -> FileName
{
372 let mut hasher
= StableHasher
::new();
373 src
.hash(&mut hasher
);
374 FileName
::MacroExpansion(hasher
.finish())
377 pub fn anon_source_code(src
: &str) -> FileName
{
378 let mut hasher
= StableHasher
::new();
379 src
.hash(&mut hasher
);
380 FileName
::Anon(hasher
.finish())
383 pub fn proc_macro_source_code(src
: &str) -> FileName
{
384 let mut hasher
= StableHasher
::new();
385 src
.hash(&mut hasher
);
386 FileName
::ProcMacroSourceCode(hasher
.finish())
389 pub fn cfg_spec_source_code(src
: &str) -> FileName
{
390 let mut hasher
= StableHasher
::new();
391 src
.hash(&mut hasher
);
392 FileName
::QuoteExpansion(hasher
.finish())
395 pub fn cli_crate_attr_source_code(src
: &str) -> FileName
{
396 let mut hasher
= StableHasher
::new();
397 src
.hash(&mut hasher
);
398 FileName
::CliCrateAttr(hasher
.finish())
401 pub fn doc_test_source_code(path
: PathBuf
, line
: isize) -> FileName
{
402 FileName
::DocTest(path
, line
)
405 pub fn inline_asm_source_code(src
: &str) -> FileName
{
406 let mut hasher
= StableHasher
::new();
407 src
.hash(&mut hasher
);
408 FileName
::InlineAsm(hasher
.finish())
412 /// Represents a span.
414 /// Spans represent a region of code, used for error reporting. Positions in spans
415 /// are *absolute* positions from the beginning of the [`SourceMap`], not positions
416 /// relative to [`SourceFile`]s. Methods on the `SourceMap` can be used to relate spans back
417 /// to the original source.
419 /// You must be careful if the span crosses more than one file, since you will not be
420 /// able to use many of the functions on spans in source_map and you cannot assume
421 /// that the length of the span is equal to `span.hi - span.lo`; there may be space in the
422 /// [`BytePos`] range between files.
424 /// `SpanData` is public because `Span` uses a thread-local interner and can't be
425 /// sent to other threads, but some pieces of performance infra run in a separate thread.
426 /// Using `Span` is generally preferred.
427 #[derive(Clone, Copy, Hash, PartialEq, Eq)]
428 pub struct SpanData
{
431 /// Information about where the macro came from, if this piece of
432 /// code was created by a macro expansion.
433 pub ctxt
: SyntaxContext
,
434 pub parent
: Option
<LocalDefId
>,
437 // Order spans by position in the file.
438 impl Ord
for SpanData
{
439 fn cmp(&self, other
: &Self) -> Ordering
{
444 // `LocalDefId` does not implement `Ord`.
445 // The other fields are enough to determine in-file order.
452 // `LocalDefId` does not implement `Ord`.
453 // The other fields are enough to determine in-file order.
457 (s_lo
, s_hi
, s_ctxt
).cmp(&(o_lo
, o_hi
, o_ctxt
))
461 impl PartialOrd
for SpanData
{
462 fn partial_cmp(&self, other
: &Self) -> Option
<Ordering
> {
463 Some(self.cmp(other
))
469 pub fn span(&self) -> Span
{
470 Span
::new(self.lo
, self.hi
, self.ctxt
, self.parent
)
473 pub fn with_lo(&self, lo
: BytePos
) -> Span
{
474 Span
::new(lo
, self.hi
, self.ctxt
, self.parent
)
477 pub fn with_hi(&self, hi
: BytePos
) -> Span
{
478 Span
::new(self.lo
, hi
, self.ctxt
, self.parent
)
481 pub fn with_ctxt(&self, ctxt
: SyntaxContext
) -> Span
{
482 Span
::new(self.lo
, self.hi
, ctxt
, self.parent
)
485 pub fn with_parent(&self, parent
: Option
<LocalDefId
>) -> Span
{
486 Span
::new(self.lo
, self.hi
, self.ctxt
, parent
)
488 /// Returns `true` if this is a dummy span with any hygienic context.
490 pub fn is_dummy(self) -> bool
{
491 self.lo
.0 == 0 && self.hi
.0 == 0
493 /// Returns `true` if `self` fully encloses `other`.
494 pub fn contains(self, other
: Self) -> bool
{
495 self.lo
<= other
.lo
&& other
.hi
<= self.hi
499 // The interner is pointed to by a thread local value which is only set on the main thread
500 // with parallelization is disabled. So we don't allow `Span` to transfer between threads
501 // to avoid panics and other errors, even though it would be memory safe to do so.
502 #[cfg(not(parallel_compiler))]
503 impl !Send
for Span {}
504 #[cfg(not(parallel_compiler))]
505 impl !Sync
for Span {}
507 impl PartialOrd
for Span
{
508 fn partial_cmp(&self, rhs
: &Self) -> Option
<Ordering
> {
509 PartialOrd
::partial_cmp(&self.data(), &rhs
.data())
513 fn cmp(&self, rhs
: &Self) -> Ordering
{
514 Ord
::cmp(&self.data(), &rhs
.data())
520 pub fn lo(self) -> BytePos
{
524 pub fn with_lo(self, lo
: BytePos
) -> Span
{
525 self.data().with_lo(lo
)
528 pub fn hi(self) -> BytePos
{
532 pub fn with_hi(self, hi
: BytePos
) -> Span
{
533 self.data().with_hi(hi
)
536 pub fn ctxt(self) -> SyntaxContext
{
537 self.data_untracked().ctxt
539 pub fn eq_ctxt(self, other
: Span
) -> bool
{
540 self.data_untracked().ctxt
== other
.data_untracked().ctxt
543 pub fn with_ctxt(self, ctxt
: SyntaxContext
) -> Span
{
544 self.data_untracked().with_ctxt(ctxt
)
547 pub fn parent(self) -> Option
<LocalDefId
> {
551 pub fn with_parent(self, ctxt
: Option
<LocalDefId
>) -> Span
{
552 self.data().with_parent(ctxt
)
555 /// Returns `true` if this is a dummy span with any hygienic context.
557 pub fn is_dummy(self) -> bool
{
558 self.data_untracked().is_dummy()
561 /// Returns `true` if this span comes from any kind of macro, desugaring or inlining.
563 pub fn from_expansion(self) -> bool
{
564 self.ctxt() != SyntaxContext
::root()
567 /// Returns `true` if `span` originates in a macro's expansion where debuginfo should be
569 pub fn in_macro_expansion_with_collapse_debuginfo(self) -> bool
{
570 let outer_expn
= self.ctxt().outer_expn_data();
571 matches
!(outer_expn
.kind
, ExpnKind
::Macro(..)) && outer_expn
.collapse_debuginfo
574 /// Returns `true` if this span comes from MIR inlining.
575 pub fn is_inlined(self) -> bool
{
576 let outer_expn
= self.ctxt().outer_expn_data();
577 matches
!(outer_expn
.kind
, ExpnKind
::Inlined
)
580 /// Returns `true` if `span` originates in a derive-macro's expansion.
581 pub fn in_derive_expansion(self) -> bool
{
582 matches
!(self.ctxt().outer_expn_data().kind
, ExpnKind
::Macro(MacroKind
::Derive
, _
))
585 /// Gate suggestions that would not be appropriate in a context the user didn't write.
586 pub fn can_be_used_for_suggestions(self) -> bool
{
587 !self.from_expansion()
588 // FIXME: If this span comes from a `derive` macro but it points at code the user wrote,
589 // the callsite span and the span will be pointing at different places. It also means that
590 // we can safely provide suggestions on this span.
591 || (matches
!(self.ctxt().outer_expn_data().kind
, ExpnKind
::Macro(MacroKind
::Derive
, _
))
592 && self.parent_callsite().map(|p
| (p
.lo(), p
.hi())) != Some((self.lo(), self.hi())))
596 pub fn with_root_ctxt(lo
: BytePos
, hi
: BytePos
) -> Span
{
597 Span
::new(lo
, hi
, SyntaxContext
::root(), None
)
600 /// Returns a new span representing an empty span at the beginning of this span.
602 pub fn shrink_to_lo(self) -> Span
{
603 let span
= self.data_untracked();
604 span
.with_hi(span
.lo
)
606 /// Returns a new span representing an empty span at the end of this span.
608 pub fn shrink_to_hi(self) -> Span
{
609 let span
= self.data_untracked();
610 span
.with_lo(span
.hi
)
614 /// Returns `true` if `hi == lo`.
615 pub fn is_empty(self) -> bool
{
616 let span
= self.data_untracked();
620 /// Returns `self` if `self` is not the dummy span, and `other` otherwise.
621 pub fn substitute_dummy(self, other
: Span
) -> Span
{
622 if self.is_dummy() { other }
else { self }
625 /// Returns `true` if `self` fully encloses `other`.
626 pub fn contains(self, other
: Span
) -> bool
{
627 let span
= self.data();
628 let other
= other
.data();
632 /// Returns `true` if `self` touches `other`.
633 pub fn overlaps(self, other
: Span
) -> bool
{
634 let span
= self.data();
635 let other
= other
.data();
636 span
.lo
< other
.hi
&& other
.lo
< span
.hi
639 /// Returns `true` if the spans are equal with regards to the source text.
641 /// Use this instead of `==` when either span could be generated code,
642 /// and you only care that they point to the same bytes of source text.
643 pub fn source_equal(self, other
: Span
) -> bool
{
644 let span
= self.data();
645 let other
= other
.data();
646 span
.lo
== other
.lo
&& span
.hi
== other
.hi
649 /// Returns `Some(span)`, where the start is trimmed by the end of `other`.
650 pub fn trim_start(self, other
: Span
) -> Option
<Span
> {
651 let span
= self.data();
652 let other
= other
.data();
653 if span
.hi
> other
.hi { Some(span.with_lo(cmp::max(span.lo, other.hi))) }
else { None }
656 /// Returns the source span -- this is either the supplied span, or the span for
657 /// the macro callsite that expanded to it.
658 pub fn source_callsite(self) -> Span
{
659 let expn_data
= self.ctxt().outer_expn_data();
660 if !expn_data
.is_root() { expn_data.call_site.source_callsite() }
else { self }
663 /// The `Span` for the tokens in the previous macro expansion from which `self` was generated,
665 pub fn parent_callsite(self) -> Option
<Span
> {
666 let expn_data
= self.ctxt().outer_expn_data();
667 if !expn_data
.is_root() { Some(expn_data.call_site) }
else { None }
670 /// Walk down the expansion ancestors to find a span that's contained within `outer`.
671 pub fn find_ancestor_inside(mut self, outer
: Span
) -> Option
<Span
> {
672 while !outer
.contains(self) {
673 self = self.parent_callsite()?
;
678 /// Like `find_ancestor_inside`, but specifically for when spans might not
679 /// overlaps. Take care when using this, and prefer `find_ancestor_inside`
680 /// when you know that the spans are nested (modulo macro expansion).
681 pub fn find_ancestor_in_same_ctxt(mut self, other
: Span
) -> Option
<Span
> {
682 while !Span
::eq_ctxt(self, other
) {
683 self = self.parent_callsite()?
;
688 /// Edition of the crate from which this span came.
689 pub fn edition(self) -> edition
::Edition
{
690 self.ctxt().edition()
694 pub fn rust_2015(self) -> bool
{
695 self.edition() == edition
::Edition
::Edition2015
699 pub fn rust_2018(self) -> bool
{
700 self.edition() >= edition
::Edition
::Edition2018
704 pub fn rust_2021(self) -> bool
{
705 self.edition() >= edition
::Edition
::Edition2021
709 pub fn rust_2024(self) -> bool
{
710 self.edition() >= edition
::Edition
::Edition2024
713 /// Returns the source callee.
715 /// Returns `None` if the supplied span has no expansion trace,
716 /// else returns the `ExpnData` for the macro definition
717 /// corresponding to the source callsite.
718 pub fn source_callee(self) -> Option
<ExpnData
> {
719 fn source_callee(expn_data
: ExpnData
) -> ExpnData
{
720 let next_expn_data
= expn_data
.call_site
.ctxt().outer_expn_data();
721 if !next_expn_data
.is_root() { source_callee(next_expn_data) }
else { expn_data }
723 let expn_data
= self.ctxt().outer_expn_data();
724 if !expn_data
.is_root() { Some(source_callee(expn_data)) }
else { None }
727 /// Checks if a span is "internal" to a macro in which `#[unstable]`
728 /// items can be used (that is, a macro marked with
729 /// `#[allow_internal_unstable]`).
730 pub fn allows_unstable(self, feature
: Symbol
) -> bool
{
733 .allow_internal_unstable
734 .map_or(false, |features
| features
.iter().any(|&f
| f
== feature
))
737 /// Checks if this span arises from a compiler desugaring of kind `kind`.
738 pub fn is_desugaring(self, kind
: DesugaringKind
) -> bool
{
739 match self.ctxt().outer_expn_data().kind
{
740 ExpnKind
::Desugaring(k
) => k
== kind
,
745 /// Returns the compiler desugaring that created this span, or `None`
746 /// if this span is not from a desugaring.
747 pub fn desugaring_kind(self) -> Option
<DesugaringKind
> {
748 match self.ctxt().outer_expn_data().kind
{
749 ExpnKind
::Desugaring(k
) => Some(k
),
754 /// Checks if a span is "internal" to a macro in which `unsafe`
755 /// can be used without triggering the `unsafe_code` lint.
756 // (that is, a macro marked with `#[allow_internal_unsafe]`).
757 pub fn allows_unsafe(self) -> bool
{
758 self.ctxt().outer_expn_data().allow_internal_unsafe
761 pub fn macro_backtrace(mut self) -> impl Iterator
<Item
= ExpnData
> {
762 let mut prev_span
= DUMMY_SP
;
763 std
::iter
::from_fn(move || {
765 let expn_data
= self.ctxt().outer_expn_data();
766 if expn_data
.is_root() {
770 let is_recursive
= expn_data
.call_site
.source_equal(prev_span
);
773 self = expn_data
.call_site
;
775 // Don't print recursive invocations.
777 return Some(expn_data
);
783 /// Returns a `Span` that would enclose both `self` and `end`.
787 /// self lorem ipsum end
788 /// ^^^^^^^^^^^^^^^^^^^^
790 pub fn to(self, end
: Span
) -> Span
{
791 let span_data
= self.data();
792 let end_data
= end
.data();
793 // FIXME(jseyfried): `self.ctxt` should always equal `end.ctxt` here (cf. issue #23480).
794 // Return the macro span on its own to avoid weird diagnostic output. It is preferable to
795 // have an incomplete span than a completely nonsensical one.
796 if span_data
.ctxt
!= end_data
.ctxt
{
797 if span_data
.ctxt
== SyntaxContext
::root() {
799 } else if end_data
.ctxt
== SyntaxContext
::root() {
802 // Both spans fall within a macro.
803 // FIXME(estebank): check if it is the *same* macro.
806 cmp
::min(span_data
.lo
, end_data
.lo
),
807 cmp
::max(span_data
.hi
, end_data
.hi
),
808 if span_data
.ctxt
== SyntaxContext
::root() { end_data.ctxt }
else { span_data.ctxt }
,
809 if span_data
.parent
== end_data
.parent { span_data.parent }
else { None }
,
813 /// Returns a `Span` between the end of `self` to the beginning of `end`.
817 /// self lorem ipsum end
820 pub fn between(self, end
: Span
) -> Span
{
821 let span
= self.data();
822 let end
= end
.data();
826 if end
.ctxt
== SyntaxContext
::root() { end.ctxt }
else { span.ctxt }
,
827 if span
.parent
== end
.parent { span.parent }
else { None }
,
831 /// Returns a `Span` from the beginning of `self` until the beginning of `end`.
835 /// self lorem ipsum end
836 /// ^^^^^^^^^^^^^^^^^
838 pub fn until(self, end
: Span
) -> Span
{
839 // Most of this function's body is copied from `to`.
840 // We can't just do `self.to(end.shrink_to_lo())`,
841 // because to also does some magic where it uses min/max so
842 // it can handle overlapping spans. Some advanced mis-use of
843 // `until` with different ctxts makes this visible.
844 let span_data
= self.data();
845 let end_data
= end
.data();
846 // FIXME(jseyfried): `self.ctxt` should always equal `end.ctxt` here (cf. issue #23480).
847 // Return the macro span on its own to avoid weird diagnostic output. It is preferable to
848 // have an incomplete span than a completely nonsensical one.
849 if span_data
.ctxt
!= end_data
.ctxt
{
850 if span_data
.ctxt
== SyntaxContext
::root() {
852 } else if end_data
.ctxt
== SyntaxContext
::root() {
855 // Both spans fall within a macro.
856 // FIXME(estebank): check if it is the *same* macro.
861 if end_data
.ctxt
== SyntaxContext
::root() { end_data.ctxt }
else { span_data.ctxt }
,
862 if span_data
.parent
== end_data
.parent { span_data.parent }
else { None }
,
866 pub fn from_inner(self, inner
: InnerSpan
) -> Span
{
867 let span
= self.data();
869 span
.lo
+ BytePos
::from_usize(inner
.start
),
870 span
.lo
+ BytePos
::from_usize(inner
.end
),
876 /// Equivalent of `Span::def_site` from the proc macro API,
877 /// except that the location is taken from the `self` span.
878 pub fn with_def_site_ctxt(self, expn_id
: ExpnId
) -> Span
{
879 self.with_ctxt_from_mark(expn_id
, Transparency
::Opaque
)
882 /// Equivalent of `Span::call_site` from the proc macro API,
883 /// except that the location is taken from the `self` span.
884 pub fn with_call_site_ctxt(self, expn_id
: ExpnId
) -> Span
{
885 self.with_ctxt_from_mark(expn_id
, Transparency
::Transparent
)
888 /// Equivalent of `Span::mixed_site` from the proc macro API,
889 /// except that the location is taken from the `self` span.
890 pub fn with_mixed_site_ctxt(self, expn_id
: ExpnId
) -> Span
{
891 self.with_ctxt_from_mark(expn_id
, Transparency
::SemiTransparent
)
894 /// Produces a span with the same location as `self` and context produced by a macro with the
895 /// given ID and transparency, assuming that macro was defined directly and not produced by
896 /// some other macro (which is the case for built-in and procedural macros).
897 pub fn with_ctxt_from_mark(self, expn_id
: ExpnId
, transparency
: Transparency
) -> Span
{
898 self.with_ctxt(SyntaxContext
::root().apply_mark(expn_id
, transparency
))
902 pub fn apply_mark(self, expn_id
: ExpnId
, transparency
: Transparency
) -> Span
{
903 let span
= self.data();
904 span
.with_ctxt(span
.ctxt
.apply_mark(expn_id
, transparency
))
908 pub fn remove_mark(&mut self) -> ExpnId
{
909 let mut span
= self.data();
910 let mark
= span
.ctxt
.remove_mark();
911 *self = Span
::new(span
.lo
, span
.hi
, span
.ctxt
, span
.parent
);
916 pub fn adjust(&mut self, expn_id
: ExpnId
) -> Option
<ExpnId
> {
917 let mut span
= self.data();
918 let mark
= span
.ctxt
.adjust(expn_id
);
919 *self = Span
::new(span
.lo
, span
.hi
, span
.ctxt
, span
.parent
);
924 pub fn normalize_to_macros_2_0_and_adjust(&mut self, expn_id
: ExpnId
) -> Option
<ExpnId
> {
925 let mut span
= self.data();
926 let mark
= span
.ctxt
.normalize_to_macros_2_0_and_adjust(expn_id
);
927 *self = Span
::new(span
.lo
, span
.hi
, span
.ctxt
, span
.parent
);
932 pub fn glob_adjust(&mut self, expn_id
: ExpnId
, glob_span
: Span
) -> Option
<Option
<ExpnId
>> {
933 let mut span
= self.data();
934 let mark
= span
.ctxt
.glob_adjust(expn_id
, glob_span
);
935 *self = Span
::new(span
.lo
, span
.hi
, span
.ctxt
, span
.parent
);
940 pub fn reverse_glob_adjust(
944 ) -> Option
<Option
<ExpnId
>> {
945 let mut span
= self.data();
946 let mark
= span
.ctxt
.reverse_glob_adjust(expn_id
, glob_span
);
947 *self = Span
::new(span
.lo
, span
.hi
, span
.ctxt
, span
.parent
);
952 pub fn normalize_to_macros_2_0(self) -> Span
{
953 let span
= self.data();
954 span
.with_ctxt(span
.ctxt
.normalize_to_macros_2_0())
958 pub fn normalize_to_macro_rules(self) -> Span
{
959 let span
= self.data();
960 span
.with_ctxt(span
.ctxt
.normalize_to_macro_rules())
964 impl Default
for Span
{
965 fn default() -> Self {
970 impl<E
: Encoder
> Encodable
<E
> for Span
{
971 default fn encode(&self, s
: &mut E
) {
972 let span
= self.data();
977 impl<D
: Decoder
> Decodable
<D
> for Span
{
978 default fn decode(s
: &mut D
) -> Span
{
979 let lo
= Decodable
::decode(s
);
980 let hi
= Decodable
::decode(s
);
982 Span
::new(lo
, hi
, SyntaxContext
::root(), None
)
986 /// Calls the provided closure, using the provided `SourceMap` to format
987 /// any spans that are debug-printed during the closure's execution.
989 /// Normally, the global `TyCtxt` is used to retrieve the `SourceMap`
990 /// (see `rustc_interface::callbacks::span_debug1`). However, some parts
991 /// of the compiler (e.g. `rustc_parse`) may debug-print `Span`s before
992 /// a `TyCtxt` is available. In this case, we fall back to
993 /// the `SourceMap` provided to this function. If that is not available,
994 /// we fall back to printing the raw `Span` field values.
995 pub fn with_source_map
<T
, F
: FnOnce() -> T
>(source_map
: Lrc
<SourceMap
>, f
: F
) -> T
{
996 with_session_globals(|session_globals
| {
997 *session_globals
.source_map
.borrow_mut() = Some(source_map
);
999 struct ClearSourceMap
;
1000 impl Drop
for ClearSourceMap
{
1001 fn drop(&mut self) {
1002 with_session_globals(|session_globals
| {
1003 session_globals
.source_map
.borrow_mut().take();
1008 let _guard
= ClearSourceMap
;
1012 impl fmt
::Debug
for Span
{
1013 fn fmt(&self, f
: &mut fmt
::Formatter
<'_
>) -> fmt
::Result
{
1014 with_session_globals(|session_globals
| {
1015 if let Some(source_map
) = &*session_globals
.source_map
.borrow() {
1016 write
!(f
, "{} ({:?})", source_map
.span_to_diagnostic_string(*self), self.ctxt())
1018 f
.debug_struct("Span")
1019 .field("lo", &self.lo())
1020 .field("hi", &self.hi())
1021 .field("ctxt", &self.ctxt())
1028 impl fmt
::Debug
for SpanData
{
1029 fn fmt(&self, f
: &mut fmt
::Formatter
<'_
>) -> fmt
::Result
{
1030 fmt
::Debug
::fmt(&Span
::new(self.lo
, self.hi
, self.ctxt
, self.parent
), f
)
1034 /// Identifies an offset of a multi-byte character in a `SourceFile`.
1035 #[derive(Copy, Clone, Encodable, Decodable, Eq, PartialEq, Debug)]
1036 pub struct MultiByteChar
{
1037 /// The absolute offset of the character in the `SourceMap`.
1039 /// The number of bytes, `>= 2`.
1043 /// Identifies an offset of a non-narrow character in a `SourceFile`.
1044 #[derive(Copy, Clone, Encodable, Decodable, Eq, PartialEq, Debug)]
1045 pub enum NonNarrowChar
{
1046 /// Represents a zero-width character.
1048 /// Represents a wide (full-width) character.
1050 /// Represents a tab character, represented visually with a width of 4 characters.
1054 impl NonNarrowChar
{
1055 fn new(pos
: BytePos
, width
: usize) -> Self {
1057 0 => NonNarrowChar
::ZeroWidth(pos
),
1058 2 => NonNarrowChar
::Wide(pos
),
1059 4 => NonNarrowChar
::Tab(pos
),
1060 _
=> panic
!("width {} given for non-narrow character", width
),
1064 /// Returns the absolute offset of the character in the `SourceMap`.
1065 pub fn pos(&self) -> BytePos
{
1067 NonNarrowChar
::ZeroWidth(p
) | NonNarrowChar
::Wide(p
) | NonNarrowChar
::Tab(p
) => p
,
1071 /// Returns the width of the character, 0 (zero-width) or 2 (wide).
1072 pub fn width(&self) -> usize {
1074 NonNarrowChar
::ZeroWidth(_
) => 0,
1075 NonNarrowChar
::Wide(_
) => 2,
1076 NonNarrowChar
::Tab(_
) => 4,
1081 impl Add
<BytePos
> for NonNarrowChar
{
1084 fn add(self, rhs
: BytePos
) -> Self {
1086 NonNarrowChar
::ZeroWidth(pos
) => NonNarrowChar
::ZeroWidth(pos
+ rhs
),
1087 NonNarrowChar
::Wide(pos
) => NonNarrowChar
::Wide(pos
+ rhs
),
1088 NonNarrowChar
::Tab(pos
) => NonNarrowChar
::Tab(pos
+ rhs
),
1093 impl Sub
<BytePos
> for NonNarrowChar
{
1096 fn sub(self, rhs
: BytePos
) -> Self {
1098 NonNarrowChar
::ZeroWidth(pos
) => NonNarrowChar
::ZeroWidth(pos
- rhs
),
1099 NonNarrowChar
::Wide(pos
) => NonNarrowChar
::Wide(pos
- rhs
),
1100 NonNarrowChar
::Tab(pos
) => NonNarrowChar
::Tab(pos
- rhs
),
1105 /// Identifies an offset of a character that was normalized away from `SourceFile`.
1106 #[derive(Copy, Clone, Encodable, Decodable, Eq, PartialEq, Debug)]
1107 pub struct NormalizedPos
{
1108 /// The absolute offset of the character in the `SourceMap`.
1110 /// The difference between original and normalized string at position.
1114 #[derive(PartialEq, Eq, Clone, Debug)]
1115 pub enum ExternalSource
{
1116 /// No external source has to be loaded, since the `SourceFile` represents a local crate.
1119 kind
: ExternalSourceKind
,
1120 /// Index of the file inside metadata.
1121 metadata_index
: u32,
1125 /// The state of the lazy external source loading mechanism of a `SourceFile`.
1126 #[derive(PartialEq, Eq, Clone, Debug)]
1127 pub enum ExternalSourceKind
{
1128 /// The external source has been loaded already.
1129 Present(Lrc
<String
>),
1130 /// No attempt has been made to load the external source.
1132 /// A failed attempt has been made to load the external source.
1137 impl ExternalSource
{
1138 pub fn get_source(&self) -> Option
<&Lrc
<String
>> {
1140 ExternalSource
::Foreign { kind: ExternalSourceKind::Present(ref src), .. }
=> Some(src
),
1147 pub struct OffsetOverflowError
;
1149 #[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Encodable, Decodable)]
1150 #[derive(HashStable_Generic)]
1151 pub enum SourceFileHashAlgorithm
{
1157 impl FromStr
for SourceFileHashAlgorithm
{
1160 fn from_str(s
: &str) -> Result
<SourceFileHashAlgorithm
, ()> {
1162 "md5" => Ok(SourceFileHashAlgorithm
::Md5
),
1163 "sha1" => Ok(SourceFileHashAlgorithm
::Sha1
),
1164 "sha256" => Ok(SourceFileHashAlgorithm
::Sha256
),
1170 /// The hash of the on-disk source file used for debug info.
1171 #[derive(Copy, Clone, PartialEq, Eq, Debug, Hash)]
1172 #[derive(HashStable_Generic, Encodable, Decodable)]
1173 pub struct SourceFileHash
{
1174 pub kind
: SourceFileHashAlgorithm
,
1178 impl SourceFileHash
{
1179 pub fn new(kind
: SourceFileHashAlgorithm
, src
: &str) -> SourceFileHash
{
1180 let mut hash
= SourceFileHash { kind, value: Default::default() }
;
1181 let len
= hash
.hash_len();
1182 let value
= &mut hash
.value
[..len
];
1183 let data
= src
.as_bytes();
1185 SourceFileHashAlgorithm
::Md5
=> {
1186 value
.copy_from_slice(&Md5
::digest(data
));
1188 SourceFileHashAlgorithm
::Sha1
=> {
1189 value
.copy_from_slice(&Sha1
::digest(data
));
1191 SourceFileHashAlgorithm
::Sha256
=> {
1192 value
.copy_from_slice(&Sha256
::digest(data
));
1198 /// Check if the stored hash matches the hash of the string.
1199 pub fn matches(&self, src
: &str) -> bool
{
1200 Self::new(self.kind
, src
) == *self
1203 /// The bytes of the hash.
1204 pub fn hash_bytes(&self) -> &[u8] {
1205 let len
= self.hash_len();
1209 fn hash_len(&self) -> usize {
1211 SourceFileHashAlgorithm
::Md5
=> 16,
1212 SourceFileHashAlgorithm
::Sha1
=> 20,
1213 SourceFileHashAlgorithm
::Sha256
=> 32,
1218 #[derive(HashStable_Generic)]
1219 #[derive(Copy, PartialEq, PartialOrd, Clone, Ord, Eq, Hash, Debug, Encodable, Decodable)]
1220 pub enum DebuggerVisualizerType
{
1225 /// A single debugger visualizer file.
1226 #[derive(HashStable_Generic)]
1227 #[derive(Clone, Debug, Hash, PartialEq, Eq, PartialOrd, Ord, Encodable, Decodable)]
1228 pub struct DebuggerVisualizerFile
{
1229 /// The complete debugger visualizer source.
1231 /// Indicates which visualizer type this targets.
1232 pub visualizer_type
: DebuggerVisualizerType
,
1235 impl DebuggerVisualizerFile
{
1236 pub fn new(src
: Arc
<[u8]>, visualizer_type
: DebuggerVisualizerType
) -> Self {
1237 DebuggerVisualizerFile { src, visualizer_type }
1242 pub enum SourceFileLines
{
1243 /// The source file lines, in decoded (random-access) form.
1244 Lines(Vec
<BytePos
>),
1246 /// The source file lines, in undecoded difference list form.
1247 Diffs(SourceFileDiffs
),
1250 impl SourceFileLines
{
1251 pub fn is_lines(&self) -> bool
{
1252 matches
!(self, SourceFileLines
::Lines(_
))
1256 /// The source file lines in difference list form. This matches the form
1257 /// used within metadata, which saves space by exploiting the fact that the
1258 /// lines list is sorted and individual lines are usually not that long.
1260 /// We read it directly from metadata and only decode it into `Lines` form
1261 /// when necessary. This is a significant performance win, especially for
1262 /// small crates where very little of `std`'s metadata is used.
1264 pub struct SourceFileDiffs
{
1265 /// Position of the first line. Note that this is always encoded as a
1266 /// `BytePos` because it is often much larger than any of the
1268 line_start
: BytePos
,
1270 /// Always 1, 2, or 4. Always as small as possible, while being big
1271 /// enough to hold the length of the longest line in the source file.
1272 /// The 1 case is by far the most common.
1273 bytes_per_diff
: usize,
1275 /// The number of diffs encoded in `raw_diffs`. Always one less than
1276 /// the number of lines in the source file.
1279 /// The diffs in "raw" form. Each segment of `bytes_per_diff` length
1280 /// encodes one little-endian diff. Note that they aren't LEB128
1281 /// encoded. This makes for much faster decoding. Besides, the
1282 /// bytes_per_diff==1 case is by far the most common, and LEB128
1283 /// encoding has no effect on that case.
1287 /// A single source in the [`SourceMap`].
1289 pub struct SourceFile
{
1290 /// The name of the file that the source came from. Source that doesn't
1291 /// originate from files has names between angle brackets by convention
1292 /// (e.g., `<anon>`).
1294 /// The complete source code.
1295 pub src
: Option
<Lrc
<String
>>,
1296 /// The source code's hash.
1297 pub src_hash
: SourceFileHash
,
1298 /// The external source code (used for external crates, which will have a `None`
1299 /// value as `self.src`.
1300 pub external_src
: Lock
<ExternalSource
>,
1301 /// The start position of this source in the `SourceMap`.
1302 pub start_pos
: BytePos
,
1303 /// The end position of this source in the `SourceMap`.
1304 pub end_pos
: BytePos
,
1305 /// Locations of lines beginnings in the source code.
1306 pub lines
: Lock
<SourceFileLines
>,
1307 /// Locations of multi-byte characters in the source code.
1308 pub multibyte_chars
: Vec
<MultiByteChar
>,
1309 /// Width of characters that are not narrow in the source code.
1310 pub non_narrow_chars
: Vec
<NonNarrowChar
>,
1311 /// Locations of characters removed during normalization.
1312 pub normalized_pos
: Vec
<NormalizedPos
>,
1313 /// A hash of the filename, used for speeding up hashing in incremental compilation.
1314 pub name_hash
: u128
,
1315 /// Indicates which crate this `SourceFile` was imported from.
1319 impl<S
: Encoder
> Encodable
<S
> for SourceFile
{
1320 fn encode(&self, s
: &mut S
) {
1321 self.name
.encode(s
);
1322 self.src_hash
.encode(s
);
1323 self.start_pos
.encode(s
);
1324 self.end_pos
.encode(s
);
1326 // We are always in `Lines` form by the time we reach here.
1327 assert
!(self.lines
.borrow().is_lines());
1328 self.lines(|lines
| {
1329 // Store the length.
1330 s
.emit_u32(lines
.len() as u32);
1332 // Compute and store the difference list.
1333 if lines
.len() != 0 {
1334 let max_line_length
= if lines
.len() == 1 {
1339 .map(|&[fst
, snd
]| snd
- fst
)
1340 .map(|bp
| bp
.to_usize())
1345 let bytes_per_diff
: usize = match max_line_length
{
1347 0x100..=0xFFFF => 2,
1351 // Encode the number of bytes used per diff.
1352 s
.emit_u8(bytes_per_diff
as u8);
1354 // Encode the first element.
1357 // Encode the difference list.
1358 let diff_iter
= lines
.array_windows().map(|&[fst
, snd
]| snd
- fst
);
1359 let num_diffs
= lines
.len() - 1;
1361 match bytes_per_diff
{
1363 raw_diffs
= Vec
::with_capacity(num_diffs
);
1364 for diff
in diff_iter
{
1365 raw_diffs
.push(diff
.0 as u8);
1369 raw_diffs
= Vec
::with_capacity(bytes_per_diff
* num_diffs
);
1370 for diff
in diff_iter
{
1371 raw_diffs
.extend_from_slice(&(diff
.0 as u16).to_le_bytes());
1375 raw_diffs
= Vec
::with_capacity(bytes_per_diff
* num_diffs
);
1376 for diff
in diff_iter
{
1377 raw_diffs
.extend_from_slice(&(diff
.0 as u32).to_le_bytes());
1380 _
=> unreachable
!(),
1382 s
.emit_raw_bytes(&raw_diffs
);
1386 self.multibyte_chars
.encode(s
);
1387 self.non_narrow_chars
.encode(s
);
1388 self.name_hash
.encode(s
);
1389 self.normalized_pos
.encode(s
);
1390 self.cnum
.encode(s
);
1394 impl<D
: Decoder
> Decodable
<D
> for SourceFile
{
1395 fn decode(d
: &mut D
) -> SourceFile
{
1396 let name
: FileName
= Decodable
::decode(d
);
1397 let src_hash
: SourceFileHash
= Decodable
::decode(d
);
1398 let start_pos
: BytePos
= Decodable
::decode(d
);
1399 let end_pos
: BytePos
= Decodable
::decode(d
);
1401 let num_lines
: u32 = Decodable
::decode(d
);
1403 // Read the number of bytes used per diff.
1404 let bytes_per_diff
= d
.read_u8() as usize;
1406 // Read the first element.
1407 let line_start
: BytePos
= Decodable
::decode(d
);
1409 // Read the difference list.
1410 let num_diffs
= num_lines
as usize - 1;
1411 let raw_diffs
= d
.read_raw_bytes(bytes_per_diff
* num_diffs
).to_vec();
1412 SourceFileLines
::Diffs(SourceFileDiffs
{
1419 SourceFileLines
::Lines(vec
![])
1422 let multibyte_chars
: Vec
<MultiByteChar
> = Decodable
::decode(d
);
1423 let non_narrow_chars
: Vec
<NonNarrowChar
> = Decodable
::decode(d
);
1424 let name_hash
: u128
= Decodable
::decode(d
);
1425 let normalized_pos
: Vec
<NormalizedPos
> = Decodable
::decode(d
);
1426 let cnum
: CrateNum
= Decodable
::decode(d
);
1433 // Unused - the metadata decoder will construct
1434 // a new SourceFile, filling in `external_src` properly
1435 external_src
: Lock
::new(ExternalSource
::Unneeded
),
1436 lines
: Lock
::new(lines
),
1446 impl fmt
::Debug
for SourceFile
{
1447 fn fmt(&self, fmt
: &mut fmt
::Formatter
<'_
>) -> fmt
::Result
{
1448 write
!(fmt
, "SourceFile({:?})", self.name
)
1457 hash_kind
: SourceFileHashAlgorithm
,
1459 // Compute the file hash before any normalization.
1460 let src_hash
= SourceFileHash
::new(hash_kind
, &src
);
1461 let normalized_pos
= normalize_src(&mut src
, start_pos
);
1464 let mut hasher
: StableHasher
= StableHasher
::new();
1465 name
.hash(&mut hasher
);
1466 hasher
.finish
::<u128
>()
1468 let end_pos
= start_pos
.to_usize() + src
.len();
1469 assert
!(end_pos
<= u32::MAX
as usize);
1471 let (lines
, multibyte_chars
, non_narrow_chars
) =
1472 analyze_source_file
::analyze_source_file(&src
, start_pos
);
1476 src
: Some(Lrc
::new(src
)),
1478 external_src
: Lock
::new(ExternalSource
::Unneeded
),
1480 end_pos
: Pos
::from_usize(end_pos
),
1481 lines
: Lock
::new(SourceFileLines
::Lines(lines
)),
1490 pub fn lines
<F
, R
>(&self, f
: F
) -> R
1492 F
: FnOnce(&[BytePos
]) -> R
,
1494 let mut guard
= self.lines
.borrow_mut();
1496 SourceFileLines
::Lines(lines
) => f(lines
),
1497 SourceFileLines
::Diffs(SourceFileDiffs
{
1503 // Convert from "diffs" form to "lines" form.
1504 let num_lines
= num_diffs
+ 1;
1505 let mut lines
= Vec
::with_capacity(num_lines
);
1506 lines
.push(line_start
);
1508 assert_eq
!(*num_diffs
, raw_diffs
.len() / bytes_per_diff
);
1509 match bytes_per_diff
{
1511 lines
.extend(raw_diffs
.into_iter().map(|&diff
| {
1512 line_start
= line_start
+ BytePos(diff
as u32);
1517 lines
.extend((0..*num_diffs
).map(|i
| {
1518 let pos
= bytes_per_diff
* i
;
1519 let bytes
= [raw_diffs
[pos
], raw_diffs
[pos
+ 1]];
1520 let diff
= u16::from_le_bytes(bytes
);
1521 line_start
= line_start
+ BytePos(diff
as u32);
1526 lines
.extend((0..*num_diffs
).map(|i
| {
1527 let pos
= bytes_per_diff
* i
;
1534 let diff
= u32::from_le_bytes(bytes
);
1535 line_start
= line_start
+ BytePos(diff
);
1539 _
=> unreachable
!(),
1541 let res
= f(&lines
);
1542 *guard
= SourceFileLines
::Lines(lines
);
1548 /// Returns the `BytePos` of the beginning of the current line.
1549 pub fn line_begin_pos(&self, pos
: BytePos
) -> BytePos
{
1550 let line_index
= self.lookup_line(pos
).unwrap();
1551 self.lines(|lines
| lines
[line_index
])
1554 /// Add externally loaded source.
1555 /// If the hash of the input doesn't match or no input is supplied via None,
1556 /// it is interpreted as an error and the corresponding enum variant is set.
1557 /// The return value signifies whether some kind of source is present.
1558 pub fn add_external_src
<F
>(&self, get_src
: F
) -> bool
1560 F
: FnOnce() -> Option
<String
>,
1563 *self.external_src
.borrow(),
1564 ExternalSource
::Foreign { kind: ExternalSourceKind::AbsentOk, .. }
1566 let src
= get_src();
1567 let mut external_src
= self.external_src
.borrow_mut();
1568 // Check that no-one else have provided the source while we were getting it
1569 if let ExternalSource
::Foreign
{
1570 kind
: src_kind @ ExternalSourceKind
::AbsentOk
, ..
1571 } = &mut *external_src
1573 if let Some(mut src
) = src
{
1574 // The src_hash needs to be computed on the pre-normalized src.
1575 if self.src_hash
.matches(&src
) {
1576 normalize_src(&mut src
, BytePos
::from_usize(0));
1577 *src_kind
= ExternalSourceKind
::Present(Lrc
::new(src
));
1581 *src_kind
= ExternalSourceKind
::AbsentErr
;
1586 self.src
.is_some() || external_src
.get_source().is_some()
1589 self.src
.is_some() || self.external_src
.borrow().get_source().is_some()
1593 /// Gets a line from the list of pre-computed line-beginnings.
1594 /// The line number here is 0-based.
1595 pub fn get_line(&self, line_number
: usize) -> Option
<Cow
<'_
, str>> {
1596 fn get_until_newline(src
: &str, begin
: usize) -> &str {
1597 // We can't use `lines.get(line_number+1)` because we might
1598 // be parsing when we call this function and thus the current
1599 // line is the last one we have line info for.
1600 let slice
= &src
[begin
..];
1601 match slice
.find('
\n'
) {
1602 Some(e
) => &slice
[..e
],
1608 let line
= self.lines(|lines
| lines
.get(line_number
).copied())?
;
1609 let begin
: BytePos
= line
- self.start_pos
;
1613 if let Some(ref src
) = self.src
{
1614 Some(Cow
::from(get_until_newline(src
, begin
)))
1615 } else if let Some(src
) = self.external_src
.borrow().get_source() {
1616 Some(Cow
::Owned(String
::from(get_until_newline(src
, begin
))))
1622 pub fn is_real_file(&self) -> bool
{
1627 pub fn is_imported(&self) -> bool
{
1631 pub fn count_lines(&self) -> usize {
1632 self.lines(|lines
| lines
.len())
1635 /// Finds the line containing the given position. The return value is the
1636 /// index into the `lines` array of this `SourceFile`, not the 1-based line
1637 /// number. If the source_file is empty or the position is located before the
1638 /// first line, `None` is returned.
1639 pub fn lookup_line(&self, pos
: BytePos
) -> Option
<usize> {
1640 self.lines(|lines
| match lines
.binary_search(&pos
) {
1641 Ok(idx
) => Some(idx
),
1643 Err(idx
) => Some(idx
- 1),
1647 pub fn line_bounds(&self, line_index
: usize) -> Range
<BytePos
> {
1648 if self.is_empty() {
1649 return self.start_pos
..self.end_pos
;
1652 self.lines(|lines
| {
1653 assert
!(line_index
< lines
.len());
1654 if line_index
== (lines
.len() - 1) {
1655 lines
[line_index
]..self.end_pos
1657 lines
[line_index
]..lines
[line_index
+ 1]
1662 /// Returns whether or not the file contains the given `SourceMap` byte
1663 /// position. The position one past the end of the file is considered to be
1664 /// contained by the file. This implies that files for which `is_empty`
1665 /// returns true still contain one byte position according to this function.
1667 pub fn contains(&self, byte_pos
: BytePos
) -> bool
{
1668 byte_pos
>= self.start_pos
&& byte_pos
<= self.end_pos
1672 pub fn is_empty(&self) -> bool
{
1673 self.start_pos
== self.end_pos
1676 /// Calculates the original byte position relative to the start of the file
1677 /// based on the given byte position.
1678 pub fn original_relative_byte_pos(&self, pos
: BytePos
) -> BytePos
{
1679 // Diff before any records is 0. Otherwise use the previously recorded
1680 // diff as that applies to the following characters until a new diff
1682 let diff
= match self.normalized_pos
.binary_search_by(|np
| np
.pos
.cmp(&pos
)) {
1683 Ok(i
) => self.normalized_pos
[i
].diff
,
1684 Err(i
) if i
== 0 => 0,
1685 Err(i
) => self.normalized_pos
[i
- 1].diff
,
1688 BytePos
::from_u32(pos
.0 - self.start_pos
.0 + diff
)
1691 /// Converts an absolute `BytePos` to a `CharPos` relative to the `SourceFile`.
1692 pub fn bytepos_to_file_charpos(&self, bpos
: BytePos
) -> CharPos
{
1693 // The number of extra bytes due to multibyte chars in the `SourceFile`.
1694 let mut total_extra_bytes
= 0;
1696 for mbc
in self.multibyte_chars
.iter() {
1697 debug
!("{}-byte char at {:?}", mbc
.bytes
, mbc
.pos
);
1699 // Every character is at least one byte, so we only
1700 // count the actual extra bytes.
1701 total_extra_bytes
+= mbc
.bytes
as u32 - 1;
1702 // We should never see a byte position in the middle of a
1704 assert
!(bpos
.to_u32() >= mbc
.pos
.to_u32() + mbc
.bytes
as u32);
1710 assert
!(self.start_pos
.to_u32() + total_extra_bytes
<= bpos
.to_u32());
1711 CharPos(bpos
.to_usize() - self.start_pos
.to_usize() - total_extra_bytes
as usize)
1714 /// Looks up the file's (1-based) line number and (0-based `CharPos`) column offset, for a
1715 /// given `BytePos`.
1716 pub fn lookup_file_pos(&self, pos
: BytePos
) -> (usize, CharPos
) {
1717 let chpos
= self.bytepos_to_file_charpos(pos
);
1718 match self.lookup_line(pos
) {
1720 let line
= a
+ 1; // Line numbers start at 1
1721 let linebpos
= self.lines(|lines
| lines
[a
]);
1722 let linechpos
= self.bytepos_to_file_charpos(linebpos
);
1723 let col
= chpos
- linechpos
;
1724 debug
!("byte pos {:?} is on the line at byte pos {:?}", pos
, linebpos
);
1725 debug
!("char pos {:?} is on the line at char pos {:?}", chpos
, linechpos
);
1726 debug
!("byte is on line: {}", line
);
1727 assert
!(chpos
>= linechpos
);
1734 /// Looks up the file's (1-based) line number, (0-based `CharPos`) column offset, and (0-based)
1735 /// column offset when displayed, for a given `BytePos`.
1736 pub fn lookup_file_pos_with_col_display(&self, pos
: BytePos
) -> (usize, CharPos
, usize) {
1737 let (line
, col_or_chpos
) = self.lookup_file_pos(pos
);
1739 let col
= col_or_chpos
;
1740 let linebpos
= self.lines(|lines
| lines
[line
- 1]);
1742 let start_width_idx
= self
1744 .binary_search_by_key(&linebpos
, |x
| x
.pos())
1745 .unwrap_or_else(|x
| x
);
1746 let end_width_idx
= self
1748 .binary_search_by_key(&pos
, |x
| x
.pos())
1749 .unwrap_or_else(|x
| x
);
1750 let special_chars
= end_width_idx
- start_width_idx
;
1751 let non_narrow
: usize = self.non_narrow_chars
[start_width_idx
..end_width_idx
]
1755 col
.0 - special_chars
+ non_narrow
1757 (line
, col
, col_display
)
1759 let chpos
= col_or_chpos
;
1761 let end_width_idx
= self
1763 .binary_search_by_key(&pos
, |x
| x
.pos())
1764 .unwrap_or_else(|x
| x
);
1765 let non_narrow
: usize =
1766 self.non_narrow_chars
[0..end_width_idx
].iter().map(|x
| x
.width()).sum();
1767 chpos
.0 - end_width_idx
+ non_narrow
1769 (0, chpos
, col_display
)
1774 /// Normalizes the source code and records the normalizations.
1775 fn normalize_src(src
: &mut String
, start_pos
: BytePos
) -> Vec
<NormalizedPos
> {
1776 let mut normalized_pos
= vec
![];
1777 remove_bom(src
, &mut normalized_pos
);
1778 normalize_newlines(src
, &mut normalized_pos
);
1780 // Offset all the positions by start_pos to match the final file positions.
1781 for np
in &mut normalized_pos
{
1782 np
.pos
.0 += start_pos
.0;
1788 /// Removes UTF-8 BOM, if any.
1789 fn remove_bom(src
: &mut String
, normalized_pos
: &mut Vec
<NormalizedPos
>) {
1790 if src
.starts_with('
\u{feff}'
) {
1792 normalized_pos
.push(NormalizedPos { pos: BytePos(0), diff: 3 }
);
1796 /// Replaces `\r\n` with `\n` in-place in `src`.
1798 /// Returns error if there's a lone `\r` in the string.
1799 fn normalize_newlines(src
: &mut String
, normalized_pos
: &mut Vec
<NormalizedPos
>) {
1800 if !src
.as_bytes().contains(&b'
\r'
) {
1804 // We replace `\r\n` with `\n` in-place, which doesn't break utf-8 encoding.
1805 // While we *can* call `as_mut_vec` and do surgery on the live string
1806 // directly, let's rather steal the contents of `src`. This makes the code
1807 // safe even if a panic occurs.
1809 let mut buf
= std
::mem
::replace(src
, String
::new()).into_bytes();
1810 let mut gap_len
= 0;
1811 let mut tail
= buf
.as_mut_slice();
1813 let original_gap
= normalized_pos
.last().map_or(0, |l
| l
.diff
);
1815 let idx
= match find_crlf(&tail
[gap_len
..]) {
1817 Some(idx
) => idx
+ gap_len
,
1819 tail
.copy_within(gap_len
..idx
, 0);
1820 tail
= &mut tail
[idx
- gap_len
..];
1821 if tail
.len() == gap_len
{
1824 cursor
+= idx
- gap_len
;
1826 normalized_pos
.push(NormalizedPos
{
1827 pos
: BytePos
::from_usize(cursor
+ 1),
1828 diff
: original_gap
+ gap_len
as u32,
1832 // Account for removed `\r`.
1833 // After `set_len`, `buf` is guaranteed to contain utf-8 again.
1834 let new_len
= buf
.len() - gap_len
;
1836 buf
.set_len(new_len
);
1837 *src
= String
::from_utf8_unchecked(buf
);
1840 fn find_crlf(src
: &[u8]) -> Option
<usize> {
1841 let mut search_idx
= 0;
1842 while let Some(idx
) = find_cr(&src
[search_idx
..]) {
1843 if src
[search_idx
..].get(idx
+ 1) != Some(&b'
\n'
) {
1844 search_idx
+= idx
+ 1;
1847 return Some(search_idx
+ idx
);
1852 fn find_cr(src
: &[u8]) -> Option
<usize> {
1853 src
.iter().position(|&b
| b
== b'
\r'
)
1857 // _____________________________________________________________________________
1858 // Pos, BytePos, CharPos
1862 fn from_usize(n
: usize) -> Self;
1863 fn to_usize(&self) -> usize;
1864 fn from_u32(n
: u32) -> Self;
1865 fn to_u32(&self) -> u32;
1868 macro_rules
! impl_pos
{
1872 $vis
:vis
struct $ident
:ident($inner_vis
:vis $inner_ty
:ty
);
1877 $vis
struct $
ident($inner_vis $inner_ty
);
1879 impl Pos
for $ident
{
1881 fn from_usize(n
: usize) -> $ident
{
1882 $
ident(n
as $inner_ty
)
1886 fn to_usize(&self) -> usize {
1891 fn from_u32(n
: u32) -> $ident
{
1892 $
ident(n
as $inner_ty
)
1896 fn to_u32(&self) -> u32 {
1901 impl Add
for $ident
{
1902 type Output
= $ident
;
1905 fn add(self, rhs
: $ident
) -> $ident
{
1906 $
ident(self.0 + rhs
.0)
1910 impl Sub
for $ident
{
1911 type Output
= $ident
;
1914 fn sub(self, rhs
: $ident
) -> $ident
{
1915 $
ident(self.0 - rhs
.0)
1925 /// Keep this small (currently 32-bits), as AST contains a lot of them.
1926 #[derive(Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord, Debug)]
1927 pub struct BytePos(pub u32);
1929 /// A character offset.
1931 /// Because of multibyte UTF-8 characters, a byte offset
1932 /// is not equivalent to a character offset. The [`SourceMap`] will convert [`BytePos`]
1933 /// values to `CharPos` values as necessary.
1934 #[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Debug)]
1935 pub struct CharPos(pub usize);
1938 impl<S
: Encoder
> Encodable
<S
> for BytePos
{
1939 fn encode(&self, s
: &mut S
) {
1944 impl<D
: Decoder
> Decodable
<D
> for BytePos
{
1945 fn decode(d
: &mut D
) -> BytePos
{
1946 BytePos(d
.read_u32())
1950 // _____________________________________________________________________________
1951 // Loc, SourceFileAndLine, SourceFileAndBytePos
1954 /// A source code location used for error reporting.
1955 #[derive(Debug, Clone)]
1957 /// Information about the original source.
1958 pub file
: Lrc
<SourceFile
>,
1959 /// The (1-based) line number.
1961 /// The (0-based) column offset.
1963 /// The (0-based) column offset when displayed.
1964 pub col_display
: usize,
1967 // Used to be structural records.
1969 pub struct SourceFileAndLine
{
1970 pub sf
: Lrc
<SourceFile
>,
1971 /// Index of line, starting from 0.
1975 pub struct SourceFileAndBytePos
{
1976 pub sf
: Lrc
<SourceFile
>,
1980 #[derive(Copy, Clone, Debug, PartialEq, Eq)]
1981 pub struct LineInfo
{
1982 /// Index of line, starting from 0.
1983 pub line_index
: usize,
1985 /// Column in line where span begins, starting from 0.
1986 pub start_col
: CharPos
,
1988 /// Column in line where span ends, starting from 0, exclusive.
1989 pub end_col
: CharPos
,
1992 pub struct FileLines
{
1993 pub file
: Lrc
<SourceFile
>,
1994 pub lines
: Vec
<LineInfo
>,
1997 pub static SPAN_TRACK
: AtomicRef
<fn(LocalDefId
)> = AtomicRef
::new(&((|_
| {}
) as fn(_
)));
1999 // _____________________________________________________________________________
2000 // SpanLinesError, SpanSnippetError, DistinctSources, MalformedSourceMapPositions
2003 pub type FileLinesResult
= Result
<FileLines
, SpanLinesError
>;
2005 #[derive(Clone, PartialEq, Eq, Debug)]
2006 pub enum SpanLinesError
{
2007 DistinctSources(DistinctSources
),
2010 #[derive(Clone, PartialEq, Eq, Debug)]
2011 pub enum SpanSnippetError
{
2012 IllFormedSpan(Span
),
2013 DistinctSources(DistinctSources
),
2014 MalformedForSourcemap(MalformedSourceMapPositions
),
2015 SourceNotAvailable { filename: FileName }
,
2018 #[derive(Clone, PartialEq, Eq, Debug)]
2019 pub struct DistinctSources
{
2020 pub begin
: (FileName
, BytePos
),
2021 pub end
: (FileName
, BytePos
),
2024 #[derive(Clone, PartialEq, Eq, Debug)]
2025 pub struct MalformedSourceMapPositions
{
2027 pub source_len
: usize,
2028 pub begin_pos
: BytePos
,
2029 pub end_pos
: BytePos
,
2032 /// Range inside of a `Span` used for diagnostics when we only have access to relative positions.
2033 #[derive(Copy, Clone, PartialEq, Eq, Debug)]
2034 pub struct InnerSpan
{
2040 pub fn new(start
: usize, end
: usize) -> InnerSpan
{
2041 InnerSpan { start, end }
2045 /// Requirements for a `StableHashingContext` to be used in this crate.
2047 /// This is a hack to allow using the [`HashStable_Generic`] derive macro
2048 /// instead of implementing everything in rustc_middle.
2049 pub trait HashStableContext
{
2050 fn def_path_hash(&self, def_id
: DefId
) -> DefPathHash
;
2051 fn hash_spans(&self) -> bool
;
2052 /// Accesses `sess.opts.unstable_opts.incremental_ignore_spans` since
2053 /// we don't have easy access to a `Session`
2054 fn unstable_opts_incremental_ignore_spans(&self) -> bool
;
2055 fn def_span(&self, def_id
: LocalDefId
) -> Span
;
2056 fn span_data_to_lines_and_cols(
2059 ) -> Option
<(Lrc
<SourceFile
>, usize, BytePos
, usize, BytePos
)>;
2060 fn hashing_controls(&self) -> HashingControls
;
2063 impl<CTX
> HashStable
<CTX
> for Span
2065 CTX
: HashStableContext
,
2067 /// Hashes a span in a stable way. We can't directly hash the span's `BytePos`
2068 /// fields (that would be similar to hashing pointers, since those are just
2069 /// offsets into the `SourceMap`). Instead, we hash the (file name, line, column)
2070 /// triple, which stays the same even if the containing `SourceFile` has moved
2071 /// within the `SourceMap`.
2073 /// Also note that we are hashing byte offsets for the column, not unicode
2074 /// codepoint offsets. For the purpose of the hash that's sufficient.
2075 /// Also, hashing filenames is expensive so we avoid doing it twice when the
2076 /// span starts and ends in the same file, which is almost always the case.
2077 fn hash_stable(&self, ctx
: &mut CTX
, hasher
: &mut StableHasher
) {
2078 const TAG_VALID_SPAN
: u8 = 0;
2079 const TAG_INVALID_SPAN
: u8 = 1;
2080 const TAG_RELATIVE_SPAN
: u8 = 2;
2082 if !ctx
.hash_spans() {
2086 let span
= self.data_untracked();
2087 span
.ctxt
.hash_stable(ctx
, hasher
);
2088 span
.parent
.hash_stable(ctx
, hasher
);
2090 if span
.is_dummy() {
2091 Hash
::hash(&TAG_INVALID_SPAN
, hasher
);
2095 if let Some(parent
) = span
.parent
{
2096 let def_span
= ctx
.def_span(parent
).data_untracked();
2097 if def_span
.contains(span
) {
2098 // This span is enclosed in a definition: only hash the relative position.
2099 Hash
::hash(&TAG_RELATIVE_SPAN
, hasher
);
2100 (span
.lo
- def_span
.lo
).to_u32().hash_stable(ctx
, hasher
);
2101 (span
.hi
- def_span
.lo
).to_u32().hash_stable(ctx
, hasher
);
2106 // If this is not an empty or invalid span, we want to hash the last
2107 // position that belongs to it, as opposed to hashing the first
2108 // position past it.
2109 let Some((file
, line_lo
, col_lo
, line_hi
, col_hi
)) = ctx
.span_data_to_lines_and_cols(&span
) else {
2110 Hash
::hash(&TAG_INVALID_SPAN
, hasher
);
2114 Hash
::hash(&TAG_VALID_SPAN
, hasher
);
2115 // We truncate the stable ID hash and line and column numbers. The chances
2116 // of causing a collision this way should be minimal.
2117 Hash
::hash(&(file
.name_hash
as u64), hasher
);
2119 // Hash both the length and the end location (line/column) of a span. If we
2120 // hash only the length, for example, then two otherwise equal spans with
2121 // different end locations will have the same hash. This can cause a problem
2122 // during incremental compilation wherein a previous result for a query that
2123 // depends on the end location of a span will be incorrectly reused when the
2124 // end location of the span it depends on has changed (see issue #74890). A
2125 // similar analysis applies if some query depends specifically on the length
2126 // of the span, but we only hash the end location. So hash both.
2128 let col_lo_trunc
= (col_lo
.0 as u64) & 0xFF;
2129 let line_lo_trunc
= ((line_lo
as u64) & 0xFF_FF_FF) << 8;
2130 let col_hi_trunc
= (col_hi
.0 as u64) & 0xFF << 32;
2131 let line_hi_trunc
= ((line_hi
as u64) & 0xFF_FF_FF) << 40;
2132 let col_line
= col_lo_trunc
| line_lo_trunc
| col_hi_trunc
| line_hi_trunc
;
2133 let len
= (span
.hi
- span
.lo
).0;
2134 Hash
::hash(&col_line
, hasher
);
2135 Hash
::hash(&len
, hasher
);