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
8 //! in the [`sym`] module.
10 //! Unlike most compilers, the span contains not only the position in the source code, but also
11 //! various other metadata, such as the edition and macro hygiene. This metadata is stored in
12 //! [`SyntaxContext`] and [`ExpnData`].
16 //! This API is completely unstable and subject to change.
18 // tidy-alphabetical-start
19 #![allow(internal_features)]
20 #![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")]
22 #![feature(array_windows)]
23 #![feature(cfg_match)]
24 #![feature(core_io_borrowed_buf)]
25 #![feature(if_let_guard)]
26 #![feature(let_chains)]
27 #![feature(min_specialization)]
28 #![feature(negative_impls)]
29 #![feature(new_uninit)]
31 #![feature(round_char_boundary)]
32 #![feature(rustc_attrs)]
33 #![feature(rustdoc_internals)]
34 // tidy-alphabetical-end
36 extern crate self as rustc_span
;
39 extern crate rustc_macros
;
44 use rustc_data_structures
::{outline, AtomicRef}
;
45 use rustc_macros
::HashStable_Generic
;
46 use rustc_serialize
::opaque
::{FileEncoder, MemDecoder}
;
47 use rustc_serialize
::{Decodable, Decoder, Encodable, Encoder}
;
49 mod caching_source_map_view
;
51 pub use self::caching_source_map_view
::CachingSourceMapView
;
52 use source_map
::{SourceMap, SourceMapInputs}
;
57 use hygiene
::Transparency
;
58 pub use hygiene
::{DesugaringKind, ExpnKind, MacroKind}
;
59 pub use hygiene
::{ExpnData, ExpnHash, ExpnId, LocalExpnId, SyntaxContext}
;
60 use rustc_data_structures
::stable_hasher
::HashingControls
;
62 use def_id
::{CrateNum, DefId, DefIndex, DefPathHash, LocalDefId, StableCrateId, LOCAL_CRATE}
;
63 pub mod edit_distance
;
65 pub use span_encoding
::{Span, DUMMY_SP}
;
68 pub use symbol
::{sym, Symbol}
;
70 mod analyze_source_file
;
75 use rustc_data_structures
::fx
::FxHashMap
;
76 use rustc_data_structures
::stable_hasher
::{Hash128, Hash64, HashStable, StableHasher}
;
77 use rustc_data_structures
::sync
::{FreezeLock, FreezeWriteGuard, Lock, Lrc}
;
80 use std
::cmp
::{self, Ordering}
;
82 use std
::ops
::{Add, Range, Sub}
;
83 use std
::path
::{Path, PathBuf}
;
84 use std
::str::FromStr
;
95 /// Per-session global variables: this struct is stored in thread-local storage
96 /// in such a way that it is accessible without any kind of handle to all
97 /// threads within the compilation session, but is not accessible outside the
99 pub struct SessionGlobals
{
100 symbol_interner
: symbol
::Interner
,
101 span_interner
: Lock
<span_encoding
::SpanInterner
>,
102 /// Maps a macro argument token into use of the corresponding metavariable in the macro body.
103 /// Collisions are possible and processed in `maybe_use_metavar_location` on best effort basis.
104 metavar_spans
: Lock
<FxHashMap
<Span
, Span
>>,
105 hygiene_data
: Lock
<hygiene
::HygieneData
>,
107 /// The session's source map, if there is one. This field should only be
108 /// used in places where the `Session` is truly not available, such as
109 /// `<Span as Debug>::fmt`.
110 source_map
: Option
<Lrc
<SourceMap
>>,
113 impl SessionGlobals
{
114 pub fn new(edition
: Edition
, sm_inputs
: Option
<SourceMapInputs
>) -> SessionGlobals
{
116 symbol_interner
: symbol
::Interner
::fresh(),
117 span_interner
: Lock
::new(span_encoding
::SpanInterner
::default()),
118 metavar_spans
: Default
::default(),
119 hygiene_data
: Lock
::new(hygiene
::HygieneData
::new(edition
)),
120 source_map
: sm_inputs
.map(|inputs
| Lrc
::new(SourceMap
::with_inputs(inputs
))),
125 pub fn create_session_globals_then
<R
>(
127 sm_inputs
: Option
<SourceMapInputs
>,
128 f
: impl FnOnce() -> R
,
131 !SESSION_GLOBALS
.is_set(),
132 "SESSION_GLOBALS should never be overwritten! \
133 Use another thread if you need another SessionGlobals"
135 let session_globals
= SessionGlobals
::new(edition
, sm_inputs
);
136 SESSION_GLOBALS
.set(&session_globals
, f
)
139 pub fn set_session_globals_then
<R
>(session_globals
: &SessionGlobals
, f
: impl FnOnce() -> R
) -> R
{
141 !SESSION_GLOBALS
.is_set(),
142 "SESSION_GLOBALS should never be overwritten! \
143 Use another thread if you need another SessionGlobals"
145 SESSION_GLOBALS
.set(session_globals
, f
)
149 pub fn create_session_if_not_set_then
<R
, F
>(edition
: Edition
, f
: F
) -> R
151 F
: FnOnce(&SessionGlobals
) -> R
,
153 if !SESSION_GLOBALS
.is_set() {
154 let session_globals
= SessionGlobals
::new(edition
, None
);
155 SESSION_GLOBALS
.set(&session_globals
, || SESSION_GLOBALS
.with(f
))
157 SESSION_GLOBALS
.with(f
)
161 pub fn with_session_globals
<R
, F
>(f
: F
) -> R
163 F
: FnOnce(&SessionGlobals
) -> R
,
165 SESSION_GLOBALS
.with(f
)
168 /// Default edition, no source map.
169 pub fn create_default_session_globals_then
<R
>(f
: impl FnOnce() -> R
) -> R
{
170 create_session_globals_then(edition
::DEFAULT_EDITION
, None
, f
)
173 // If this ever becomes non thread-local, `decode_syntax_context`
174 // and `decode_expn_id` will need to be updated to handle concurrent
176 scoped_tls
::scoped_thread_local
!(static SESSION_GLOBALS
: SessionGlobals
);
179 pub fn with_metavar_spans
<R
>(f
: impl FnOnce(&mut FxHashMap
<Span
, Span
>) -> R
) -> R
{
180 with_session_globals(|session_globals
| f(&mut session_globals
.metavar_spans
.lock()))
183 // FIXME: We should use this enum or something like it to get rid of the
184 // use of magic `/rust/1.x/...` paths across the board.
185 #[derive(Debug, Eq, PartialEq, Clone, Ord, PartialOrd, Decodable)]
186 pub enum RealFileName
{
188 /// For remapped paths (namely paths into libstd that have been mapped
189 /// to the appropriate spot on the local host's file system, and local file
190 /// system paths that have been remapped with `FilePathMapping`),
192 /// `local_path` is the (host-dependent) local path to the file. This is
193 /// None if the file was imported from another crate
194 local_path
: Option
<PathBuf
>,
195 /// `virtual_name` is the stable path rustc will store internally within
197 virtual_name
: PathBuf
,
201 impl Hash
for RealFileName
{
202 fn hash
<H
: std
::hash
::Hasher
>(&self, state
: &mut H
) {
203 // To prevent #70924 from happening again we should only hash the
204 // remapped (virtualized) path if that exists. This is because
205 // virtualized paths to sysroot crates (/rust/$hash or /rust/$version)
206 // remain stable even if the corresponding local_path changes
207 self.remapped_path_if_available().hash(state
)
211 // This is functionally identical to #[derive(Encodable)], with the exception of
212 // an added assert statement
213 impl<S
: Encoder
> Encodable
<S
> for RealFileName
{
214 fn encode(&self, encoder
: &mut S
) {
216 RealFileName
::LocalPath(ref local_path
) => {
218 local_path
.encode(encoder
);
221 RealFileName
::Remapped { ref local_path, ref virtual_name }
=> {
223 // For privacy and build reproducibility, we must not embed host-dependant path
224 // in artifacts if they have been remapped by --remap-path-prefix
225 assert
!(local_path
.is_none());
226 local_path
.encode(encoder
);
227 virtual_name
.encode(encoder
);
234 /// Returns the path suitable for reading from the file system on the local host,
235 /// if this information exists.
236 /// Avoid embedding this in build artifacts; see `remapped_path_if_available()` for that.
237 pub fn local_path(&self) -> Option
<&Path
> {
239 RealFileName
::LocalPath(p
) => Some(p
),
240 RealFileName
::Remapped { local_path, virtual_name: _ }
=> local_path
.as_deref(),
244 /// Returns the path suitable for reading from the file system on the local host,
245 /// if this information exists.
246 /// Avoid embedding this in build artifacts; see `remapped_path_if_available()` for that.
247 pub fn into_local_path(self) -> Option
<PathBuf
> {
249 RealFileName
::LocalPath(p
) => Some(p
),
250 RealFileName
::Remapped { local_path: p, virtual_name: _ }
=> p
,
254 /// Returns the path suitable for embedding into build artifacts. This would still
255 /// be a local path if it has not been remapped. A remapped path will not correspond
256 /// to a valid file system path: see `local_path_if_available()` for something that
257 /// is more likely to return paths into the local host file system.
258 pub fn remapped_path_if_available(&self) -> &Path
{
260 RealFileName
::LocalPath(p
)
261 | RealFileName
::Remapped { local_path: _, virtual_name: p }
=> p
,
265 /// Returns the path suitable for reading from the file system on the local host,
266 /// if this information exists. Otherwise returns the remapped name.
267 /// Avoid embedding this in build artifacts; see `remapped_path_if_available()` for that.
268 pub fn local_path_if_available(&self) -> &Path
{
270 RealFileName
::LocalPath(path
)
271 | RealFileName
::Remapped { local_path: None, virtual_name: path }
272 | RealFileName
::Remapped { local_path: Some(path), virtual_name: _ }
=> path
,
276 /// Return the path remmapped or not depending on the [`FileNameDisplayPreference`].
278 /// For the purpose of this function, local and short preference are equal.
279 pub fn to_path(&self, display_pref
: FileNameDisplayPreference
) -> &Path
{
281 FileNameDisplayPreference
::Local
| FileNameDisplayPreference
::Short
=> {
282 self.local_path_if_available()
284 FileNameDisplayPreference
::Remapped
=> self.remapped_path_if_available(),
288 pub fn to_string_lossy(&self, display_pref
: FileNameDisplayPreference
) -> Cow
<'_
, str> {
290 FileNameDisplayPreference
::Local
=> self.local_path_if_available().to_string_lossy(),
291 FileNameDisplayPreference
::Remapped
=> {
292 self.remapped_path_if_available().to_string_lossy()
294 FileNameDisplayPreference
::Short
=> self
295 .local_path_if_available()
297 .map_or_else(|| "".into(), |f
| f
.to_string_lossy()),
302 /// Differentiates between real files and common virtual files.
303 #[derive(Debug, Eq, PartialEq, Clone, Ord, PartialOrd, Hash, Decodable, Encodable)]
306 /// Call to `quote!`.
307 QuoteExpansion(Hash64
),
310 /// Hack in `src/librustc_ast/parse.rs`.
312 MacroExpansion(Hash64
),
313 ProcMacroSourceCode(Hash64
),
314 /// Strings provided as crate attributes in the CLI.
315 CliCrateAttr(Hash64
),
316 /// Custom sources for explicit parser calls from plugins and drivers.
318 DocTest(PathBuf
, isize),
319 /// Post-substitution inline assembly from LLVM.
323 impl From
<PathBuf
> for FileName
{
324 fn from(p
: PathBuf
) -> Self {
325 FileName
::Real(RealFileName
::LocalPath(p
))
329 #[derive(Clone, Copy, Eq, PartialEq, Hash, Debug)]
330 pub enum FileNameDisplayPreference
{
331 /// Display the path after the application of rewrite rules provided via `--remap-path-prefix`.
332 /// This is appropriate for paths that get embedded into files produced by the compiler.
334 /// Display the path before the application of rewrite rules provided via `--remap-path-prefix`.
335 /// This is appropriate for use in user-facing output (such as diagnostics).
337 /// Display only the filename, as a way to reduce the verbosity of the output.
338 /// This is appropriate for use in user-facing output (such as diagnostics).
342 pub struct FileNameDisplay
<'a
> {
344 display_pref
: FileNameDisplayPreference
,
347 impl fmt
::Display
for FileNameDisplay
<'_
> {
348 fn fmt(&self, fmt
: &mut std
::fmt
::Formatter
<'_
>) -> std
::fmt
::Result
{
352 write
!(fmt
, "{}", name
.to_string_lossy(self.display_pref
))
354 QuoteExpansion(_
) => write
!(fmt
, "<quote expansion>"),
355 MacroExpansion(_
) => write
!(fmt
, "<macro expansion>"),
356 Anon(_
) => write
!(fmt
, "<anon>"),
357 ProcMacroSourceCode(_
) => write
!(fmt
, "<proc-macro source code>"),
358 CliCrateAttr(_
) => write
!(fmt
, "<crate attribute>"),
359 Custom(ref s
) => write
!(fmt
, "<{s}>"),
360 DocTest(ref path
, _
) => write
!(fmt
, "{}", path
.display()),
361 InlineAsm(_
) => write
!(fmt
, "<inline asm>"),
366 impl<'a
> FileNameDisplay
<'a
> {
367 pub fn to_string_lossy(&self) -> Cow
<'a
, str> {
369 FileName
::Real(ref inner
) => inner
.to_string_lossy(self.display_pref
),
370 _
=> Cow
::from(self.to_string()),
376 pub fn is_real(&self) -> bool
{
382 | ProcMacroSourceCode(_
)
387 | InlineAsm(_
) => false,
391 pub fn prefer_remapped_unconditionaly(&self) -> FileNameDisplay
<'_
> {
392 FileNameDisplay { inner: self, display_pref: FileNameDisplayPreference::Remapped }
395 /// This may include transient local filesystem information.
396 /// Must not be embedded in build outputs.
397 pub fn prefer_local(&self) -> FileNameDisplay
<'_
> {
398 FileNameDisplay { inner: self, display_pref: FileNameDisplayPreference::Local }
401 pub fn display(&self, display_pref
: FileNameDisplayPreference
) -> FileNameDisplay
<'_
> {
402 FileNameDisplay { inner: self, display_pref }
405 pub fn macro_expansion_source_code(src
: &str) -> FileName
{
406 let mut hasher
= StableHasher
::new();
407 src
.hash(&mut hasher
);
408 FileName
::MacroExpansion(hasher
.finish())
411 pub fn anon_source_code(src
: &str) -> FileName
{
412 let mut hasher
= StableHasher
::new();
413 src
.hash(&mut hasher
);
414 FileName
::Anon(hasher
.finish())
417 pub fn proc_macro_source_code(src
: &str) -> FileName
{
418 let mut hasher
= StableHasher
::new();
419 src
.hash(&mut hasher
);
420 FileName
::ProcMacroSourceCode(hasher
.finish())
423 pub fn cfg_spec_source_code(src
: &str) -> FileName
{
424 let mut hasher
= StableHasher
::new();
425 src
.hash(&mut hasher
);
426 FileName
::QuoteExpansion(hasher
.finish())
429 pub fn cli_crate_attr_source_code(src
: &str) -> FileName
{
430 let mut hasher
= StableHasher
::new();
431 src
.hash(&mut hasher
);
432 FileName
::CliCrateAttr(hasher
.finish())
435 pub fn doc_test_source_code(path
: PathBuf
, line
: isize) -> FileName
{
436 FileName
::DocTest(path
, line
)
439 pub fn inline_asm_source_code(src
: &str) -> FileName
{
440 let mut hasher
= StableHasher
::new();
441 src
.hash(&mut hasher
);
442 FileName
::InlineAsm(hasher
.finish())
445 /// Returns the path suitable for reading from the file system on the local host,
446 /// if this information exists.
447 /// Avoid embedding this in build artifacts; see `remapped_path_if_available()` for that.
448 pub fn into_local_path(self) -> Option
<PathBuf
> {
450 FileName
::Real(path
) => path
.into_local_path(),
451 FileName
::DocTest(path
, _
) => Some(path
),
457 /// Represents a span.
459 /// Spans represent a region of code, used for error reporting. Positions in spans
460 /// are *absolute* positions from the beginning of the [`SourceMap`], not positions
461 /// relative to [`SourceFile`]s. Methods on the `SourceMap` can be used to relate spans back
462 /// to the original source.
464 /// You must be careful if the span crosses more than one file, since you will not be
465 /// able to use many of the functions on spans in source_map and you cannot assume
466 /// that the length of the span is equal to `span.hi - span.lo`; there may be space in the
467 /// [`BytePos`] range between files.
469 /// `SpanData` is public because `Span` uses a thread-local interner and can't be
470 /// sent to other threads, but some pieces of performance infra run in a separate thread.
471 /// Using `Span` is generally preferred.
472 #[derive(Clone, Copy, Hash, PartialEq, Eq)]
473 pub struct SpanData
{
476 /// Information about where the macro came from, if this piece of
477 /// code was created by a macro expansion.
478 pub ctxt
: SyntaxContext
,
479 pub parent
: Option
<LocalDefId
>,
482 // Order spans by position in the file.
483 impl Ord
for SpanData
{
484 fn cmp(&self, other
: &Self) -> Ordering
{
489 // `LocalDefId` does not implement `Ord`.
490 // The other fields are enough to determine in-file order.
497 // `LocalDefId` does not implement `Ord`.
498 // The other fields are enough to determine in-file order.
502 (s_lo
, s_hi
, s_ctxt
).cmp(&(o_lo
, o_hi
, o_ctxt
))
506 impl PartialOrd
for SpanData
{
507 fn partial_cmp(&self, other
: &Self) -> Option
<Ordering
> {
508 Some(self.cmp(other
))
514 pub fn span(&self) -> Span
{
515 Span
::new(self.lo
, self.hi
, self.ctxt
, self.parent
)
518 pub fn with_lo(&self, lo
: BytePos
) -> Span
{
519 Span
::new(lo
, self.hi
, self.ctxt
, self.parent
)
522 pub fn with_hi(&self, hi
: BytePos
) -> Span
{
523 Span
::new(self.lo
, hi
, self.ctxt
, self.parent
)
526 pub fn with_ctxt(&self, ctxt
: SyntaxContext
) -> Span
{
527 Span
::new(self.lo
, self.hi
, ctxt
, self.parent
)
530 pub fn with_parent(&self, parent
: Option
<LocalDefId
>) -> Span
{
531 Span
::new(self.lo
, self.hi
, self.ctxt
, parent
)
533 /// Returns `true` if this is a dummy span with any hygienic context.
535 pub fn is_dummy(self) -> bool
{
536 self.lo
.0 == 0 && self.hi
.0 == 0
538 /// Returns `true` if `self` fully encloses `other`.
539 pub fn contains(self, other
: Self) -> bool
{
540 self.lo
<= other
.lo
&& other
.hi
<= self.hi
544 // The interner is pointed to by a thread local value which is only set on the main thread
545 // with parallelization is disabled. So we don't allow `Span` to transfer between threads
546 // to avoid panics and other errors, even though it would be memory safe to do so.
547 #[cfg(not(parallel_compiler))]
548 impl !Send
for Span {}
549 #[cfg(not(parallel_compiler))]
550 impl !Sync
for Span {}
552 impl PartialOrd
for Span
{
553 fn partial_cmp(&self, rhs
: &Self) -> Option
<Ordering
> {
554 PartialOrd
::partial_cmp(&self.data(), &rhs
.data())
558 fn cmp(&self, rhs
: &Self) -> Ordering
{
559 Ord
::cmp(&self.data(), &rhs
.data())
565 pub fn lo(self) -> BytePos
{
569 pub fn with_lo(self, lo
: BytePos
) -> Span
{
570 self.data().with_lo(lo
)
573 pub fn hi(self) -> BytePos
{
577 pub fn with_hi(self, hi
: BytePos
) -> Span
{
578 self.data().with_hi(hi
)
581 pub fn with_ctxt(self, ctxt
: SyntaxContext
) -> Span
{
582 self.data_untracked().with_ctxt(ctxt
)
585 pub fn parent(self) -> Option
<LocalDefId
> {
589 pub fn with_parent(self, ctxt
: Option
<LocalDefId
>) -> Span
{
590 self.data().with_parent(ctxt
)
594 pub fn is_visible(self, sm
: &SourceMap
) -> bool
{
595 !self.is_dummy() && sm
.is_span_accessible(self)
598 /// Returns `true` if this span comes from any kind of macro, desugaring or inlining.
600 pub fn from_expansion(self) -> bool
{
601 !self.ctxt().is_root()
604 /// Returns `true` if `span` originates in a derive-macro's expansion.
605 pub fn in_derive_expansion(self) -> bool
{
606 matches
!(self.ctxt().outer_expn_data().kind
, ExpnKind
::Macro(MacroKind
::Derive
, _
))
609 /// Gate suggestions that would not be appropriate in a context the user didn't write.
610 pub fn can_be_used_for_suggestions(self) -> bool
{
611 !self.from_expansion()
612 // FIXME: If this span comes from a `derive` macro but it points at code the user wrote,
613 // the callsite span and the span will be pointing at different places. It also means that
614 // we can safely provide suggestions on this span.
615 || (self.in_derive_expansion()
616 && self.parent_callsite().map(|p
| (p
.lo(), p
.hi())) != Some((self.lo(), self.hi())))
620 pub fn with_root_ctxt(lo
: BytePos
, hi
: BytePos
) -> Span
{
621 Span
::new(lo
, hi
, SyntaxContext
::root(), None
)
624 /// Returns a new span representing an empty span at the beginning of this span.
626 pub fn shrink_to_lo(self) -> Span
{
627 let span
= self.data_untracked();
628 span
.with_hi(span
.lo
)
630 /// Returns a new span representing an empty span at the end of this span.
632 pub fn shrink_to_hi(self) -> Span
{
633 let span
= self.data_untracked();
634 span
.with_lo(span
.hi
)
638 /// Returns `true` if `hi == lo`.
639 pub fn is_empty(self) -> bool
{
640 let span
= self.data_untracked();
644 /// Returns `self` if `self` is not the dummy span, and `other` otherwise.
645 pub fn substitute_dummy(self, other
: Span
) -> Span
{
646 if self.is_dummy() { other }
else { self }
649 /// Returns `true` if `self` fully encloses `other`.
650 pub fn contains(self, other
: Span
) -> bool
{
651 let span
= self.data();
652 let other
= other
.data();
656 /// Returns `true` if `self` touches `other`.
657 pub fn overlaps(self, other
: Span
) -> bool
{
658 let span
= self.data();
659 let other
= other
.data();
660 span
.lo
< other
.hi
&& other
.lo
< span
.hi
663 /// Returns `true` if `self` touches or adjoins `other`.
664 pub fn overlaps_or_adjacent(self, other
: Span
) -> bool
{
665 let span
= self.data();
666 let other
= other
.data();
667 span
.lo
<= other
.hi
&& other
.lo
<= span
.hi
670 /// Returns `true` if the spans are equal with regards to the source text.
672 /// Use this instead of `==` when either span could be generated code,
673 /// and you only care that they point to the same bytes of source text.
674 pub fn source_equal(self, other
: Span
) -> bool
{
675 let span
= self.data();
676 let other
= other
.data();
677 span
.lo
== other
.lo
&& span
.hi
== other
.hi
680 /// Returns `Some(span)`, where the start is trimmed by the end of `other`.
681 pub fn trim_start(self, other
: Span
) -> Option
<Span
> {
682 let span
= self.data();
683 let other
= other
.data();
684 if span
.hi
> other
.hi { Some(span.with_lo(cmp::max(span.lo, other.hi))) }
else { None }
687 /// Returns the source span -- this is either the supplied span, or the span for
688 /// the macro callsite that expanded to it.
689 pub fn source_callsite(self) -> Span
{
690 let ctxt
= self.ctxt();
691 if !ctxt
.is_root() { ctxt.outer_expn_data().call_site.source_callsite() }
else { self }
694 /// The `Span` for the tokens in the previous macro expansion from which `self` was generated,
696 pub fn parent_callsite(self) -> Option
<Span
> {
697 let ctxt
= self.ctxt();
698 (!ctxt
.is_root()).then(|| ctxt
.outer_expn_data().call_site
)
701 /// Walk down the expansion ancestors to find a span that's contained within `outer`.
703 /// The span returned by this method may have a different [`SyntaxContext`] as `outer`.
704 /// If you need to extend the span, use [`find_ancestor_inside_same_ctxt`] instead,
705 /// because joining spans with different syntax contexts can create unexpected results.
707 /// [`find_ancestor_inside_same_ctxt`]: Self::find_ancestor_inside_same_ctxt
708 pub fn find_ancestor_inside(mut self, outer
: Span
) -> Option
<Span
> {
709 while !outer
.contains(self) {
710 self = self.parent_callsite()?
;
715 /// Walk down the expansion ancestors to find a span with the same [`SyntaxContext`] as
718 /// Like [`find_ancestor_inside_same_ctxt`], but specifically for when spans might not
719 /// overlap. Take care when using this, and prefer [`find_ancestor_inside`] or
720 /// [`find_ancestor_inside_same_ctxt`] when you know that the spans are nested (modulo
721 /// macro expansion).
723 /// [`find_ancestor_inside`]: Self::find_ancestor_inside
724 /// [`find_ancestor_inside_same_ctxt`]: Self::find_ancestor_inside_same_ctxt
725 pub fn find_ancestor_in_same_ctxt(mut self, other
: Span
) -> Option
<Span
> {
726 while !self.eq_ctxt(other
) {
727 self = self.parent_callsite()?
;
732 /// Walk down the expansion ancestors to find a span that's contained within `outer` and
733 /// has the same [`SyntaxContext`] as `outer`.
735 /// This method is the combination of [`find_ancestor_inside`] and
736 /// [`find_ancestor_in_same_ctxt`] and should be preferred when extending the returned span.
737 /// If you do not need to modify the span, use [`find_ancestor_inside`] instead.
739 /// [`find_ancestor_inside`]: Self::find_ancestor_inside
740 /// [`find_ancestor_in_same_ctxt`]: Self::find_ancestor_in_same_ctxt
741 pub fn find_ancestor_inside_same_ctxt(mut self, outer
: Span
) -> Option
<Span
> {
742 while !outer
.contains(self) || !self.eq_ctxt(outer
) {
743 self = self.parent_callsite()?
;
748 /// Recursively walk down the expansion ancestors to find the oldest ancestor span with the same
749 /// [`SyntaxContext`] the initial span.
751 /// This method is suitable for peeling through *local* macro expansions to find the "innermost"
752 /// span that is still local and shares the same [`SyntaxContext`]. For example, given
754 /// ```ignore (illustrative example, contains type error)
755 /// macro_rules! outer {
761 /// macro_rules! inner {
763 /// format!("error: {}", $x)
764 /// //~^ ERROR mismatched types
768 /// fn bar(x: &str) -> Result<(), Box<dyn std::error::Error>> {
773 /// if provided the initial span of `outer!(x)` inside `bar`, this method will recurse
774 /// the parent callsites until we reach `format!("error: {}", $x)`, at which point it is the
775 /// oldest ancestor span that is both still local and shares the same [`SyntaxContext`] as the
777 pub fn find_oldest_ancestor_in_same_ctxt(self) -> Span
{
779 while cur
.eq_ctxt(self)
780 && let Some(parent_callsite
) = cur
.parent_callsite()
782 cur
= parent_callsite
;
787 /// Edition of the crate from which this span came.
788 pub fn edition(self) -> edition
::Edition
{
789 self.ctxt().edition()
792 /// Is this edition 2015?
794 pub fn is_rust_2015(self) -> bool
{
795 self.edition().is_rust_2015()
798 /// Are we allowed to use features from the Rust 2018 edition?
800 pub fn at_least_rust_2018(self) -> bool
{
801 self.edition().at_least_rust_2018()
804 /// Are we allowed to use features from the Rust 2021 edition?
806 pub fn at_least_rust_2021(self) -> bool
{
807 self.edition().at_least_rust_2021()
810 /// Are we allowed to use features from the Rust 2024 edition?
812 pub fn at_least_rust_2024(self) -> bool
{
813 self.edition().at_least_rust_2024()
816 /// Returns the source callee.
818 /// Returns `None` if the supplied span has no expansion trace,
819 /// else returns the `ExpnData` for the macro definition
820 /// corresponding to the source callsite.
821 pub fn source_callee(self) -> Option
<ExpnData
> {
822 let mut ctxt
= self.ctxt();
823 let mut opt_expn_data
= None
;
824 while !ctxt
.is_root() {
825 let expn_data
= ctxt
.outer_expn_data();
826 ctxt
= expn_data
.call_site
.ctxt();
827 opt_expn_data
= Some(expn_data
);
832 /// Checks if a span is "internal" to a macro in which `#[unstable]`
833 /// items can be used (that is, a macro marked with
834 /// `#[allow_internal_unstable]`).
835 pub fn allows_unstable(self, feature
: Symbol
) -> bool
{
838 .allow_internal_unstable
839 .is_some_and(|features
| features
.iter().any(|&f
| f
== feature
))
842 /// Checks if this span arises from a compiler desugaring of kind `kind`.
843 pub fn is_desugaring(self, kind
: DesugaringKind
) -> bool
{
844 match self.ctxt().outer_expn_data().kind
{
845 ExpnKind
::Desugaring(k
) => k
== kind
,
850 /// Returns the compiler desugaring that created this span, or `None`
851 /// if this span is not from a desugaring.
852 pub fn desugaring_kind(self) -> Option
<DesugaringKind
> {
853 match self.ctxt().outer_expn_data().kind
{
854 ExpnKind
::Desugaring(k
) => Some(k
),
859 /// Checks if a span is "internal" to a macro in which `unsafe`
860 /// can be used without triggering the `unsafe_code` lint.
861 /// (that is, a macro marked with `#[allow_internal_unsafe]`).
862 pub fn allows_unsafe(self) -> bool
{
863 self.ctxt().outer_expn_data().allow_internal_unsafe
866 pub fn macro_backtrace(mut self) -> impl Iterator
<Item
= ExpnData
> {
867 let mut prev_span
= DUMMY_SP
;
868 iter
::from_fn(move || {
870 let ctxt
= self.ctxt();
875 let expn_data
= ctxt
.outer_expn_data();
876 let is_recursive
= expn_data
.call_site
.source_equal(prev_span
);
879 self = expn_data
.call_site
;
881 // Don't print recursive invocations.
883 return Some(expn_data
);
889 /// Splits a span into two composite spans around a certain position.
890 pub fn split_at(self, pos
: u32) -> (Span
, Span
) {
891 let len
= self.hi().0 - self.lo().0;
892 debug_assert
!(pos
<= len
);
894 let split_pos
= BytePos(self.lo().0 + pos
);
896 Span
::new(self.lo(), split_pos
, self.ctxt(), self.parent()),
897 Span
::new(split_pos
, self.hi(), self.ctxt(), self.parent()),
901 /// Check if you can select metavar spans for the given spans to get matching contexts.
902 fn try_metavars(a
: SpanData
, b
: SpanData
, a_orig
: Span
, b_orig
: Span
) -> (SpanData
, SpanData
) {
903 let get
= |mspans
: &FxHashMap
<_
, _
>, s
| mspans
.get(&s
).copied();
904 match with_metavar_spans(|mspans
| (get(mspans
, a_orig
), get(mspans
, b_orig
))) {
906 (Some(meta_a
), None
) => {
907 let meta_a
= meta_a
.data();
908 if meta_a
.ctxt
== b
.ctxt
{
912 (None
, Some(meta_b
)) => {
913 let meta_b
= meta_b
.data();
914 if a
.ctxt
== meta_b
.ctxt
{
918 (Some(meta_a
), Some(meta_b
)) => {
919 let meta_b
= meta_b
.data();
920 if a
.ctxt
== meta_b
.ctxt
{
923 let meta_a
= meta_a
.data();
924 if meta_a
.ctxt
== b
.ctxt
{
926 } else if meta_a
.ctxt
== meta_b
.ctxt
{
927 return (meta_a
, meta_b
);
935 /// Prepare two spans to a combine operation like `to` or `between`.
936 fn prepare_to_combine(
939 ) -> Result
<(SpanData
, SpanData
, Option
<LocalDefId
>), Span
> {
940 let (a
, b
) = (a_orig
.data(), b_orig
.data());
941 if a
.ctxt
== b
.ctxt
{
942 return Ok((a
, b
, if a
.parent
== b
.parent { a.parent }
else { None }
));
945 let (a
, b
) = Span
::try_metavars(a
, b
, a_orig
, b_orig
);
946 if a
.ctxt
== b
.ctxt
{
947 return Ok((a
, b
, if a
.parent
== b
.parent { a.parent }
else { None }
));
950 // Context mismatches usually happen when procedural macros combine spans copied from
951 // the macro input with spans produced by the macro (`Span::*_site`).
952 // In that case we consider the combined span to be produced by the macro and return
953 // the original macro-produced span as the result.
954 // Otherwise we just fall back to returning the first span.
955 // Combining locations typically doesn't make sense in case of context mismatches.
956 // `is_root` here is a fast path optimization.
957 let a_is_callsite
= a
.ctxt
.is_root() || a
.ctxt
== b
.span().source_callsite().ctxt();
958 Err(if a_is_callsite { b_orig }
else { a_orig }
)
961 /// This span, but in a larger context, may switch to the metavariable span if suitable.
962 pub fn with_neighbor(self, neighbor
: Span
) -> Span
{
963 match Span
::prepare_to_combine(self, neighbor
) {
964 Ok((this
, ..)) => Span
::new(this
.lo
, this
.hi
, this
.ctxt
, this
.parent
),
969 /// Returns a `Span` that would enclose both `self` and `end`.
971 /// Note that this can also be used to extend the span "backwards":
972 /// `start.to(end)` and `end.to(start)` return the same `Span`.
976 /// self lorem ipsum end
977 /// ^^^^^^^^^^^^^^^^^^^^
979 pub fn to(self, end
: Span
) -> Span
{
980 match Span
::prepare_to_combine(self, end
) {
981 Ok((from
, to
, parent
)) => {
982 Span
::new(cmp
::min(from
.lo
, to
.lo
), cmp
::max(from
.hi
, to
.hi
), from
.ctxt
, parent
)
984 Err(fallback
) => fallback
,
988 /// Returns a `Span` between the end of `self` to the beginning of `end`.
992 /// self lorem ipsum end
995 pub fn between(self, end
: Span
) -> Span
{
996 match Span
::prepare_to_combine(self, end
) {
997 Ok((from
, to
, parent
)) => {
998 Span
::new(cmp
::min(from
.hi
, to
.hi
), cmp
::max(from
.lo
, to
.lo
), from
.ctxt
, parent
)
1000 Err(fallback
) => fallback
,
1004 /// Returns a `Span` from the beginning of `self` until the beginning of `end`.
1008 /// self lorem ipsum end
1009 /// ^^^^^^^^^^^^^^^^^
1011 pub fn until(self, end
: Span
) -> Span
{
1012 match Span
::prepare_to_combine(self, end
) {
1013 Ok((from
, to
, parent
)) => {
1014 Span
::new(cmp
::min(from
.lo
, to
.lo
), cmp
::max(from
.lo
, to
.lo
), from
.ctxt
, parent
)
1016 Err(fallback
) => fallback
,
1020 pub fn from_inner(self, inner
: InnerSpan
) -> Span
{
1021 let span
= self.data();
1023 span
.lo
+ BytePos
::from_usize(inner
.start
),
1024 span
.lo
+ BytePos
::from_usize(inner
.end
),
1030 /// Equivalent of `Span::def_site` from the proc macro API,
1031 /// except that the location is taken from the `self` span.
1032 pub fn with_def_site_ctxt(self, expn_id
: ExpnId
) -> Span
{
1033 self.with_ctxt_from_mark(expn_id
, Transparency
::Opaque
)
1036 /// Equivalent of `Span::call_site` from the proc macro API,
1037 /// except that the location is taken from the `self` span.
1038 pub fn with_call_site_ctxt(self, expn_id
: ExpnId
) -> Span
{
1039 self.with_ctxt_from_mark(expn_id
, Transparency
::Transparent
)
1042 /// Equivalent of `Span::mixed_site` from the proc macro API,
1043 /// except that the location is taken from the `self` span.
1044 pub fn with_mixed_site_ctxt(self, expn_id
: ExpnId
) -> Span
{
1045 self.with_ctxt_from_mark(expn_id
, Transparency
::SemiTransparent
)
1048 /// Produces a span with the same location as `self` and context produced by a macro with the
1049 /// given ID and transparency, assuming that macro was defined directly and not produced by
1050 /// some other macro (which is the case for built-in and procedural macros).
1051 fn with_ctxt_from_mark(self, expn_id
: ExpnId
, transparency
: Transparency
) -> Span
{
1052 self.with_ctxt(SyntaxContext
::root().apply_mark(expn_id
, transparency
))
1056 pub fn apply_mark(self, expn_id
: ExpnId
, transparency
: Transparency
) -> Span
{
1057 let span
= self.data();
1058 span
.with_ctxt(span
.ctxt
.apply_mark(expn_id
, transparency
))
1062 pub fn remove_mark(&mut self) -> ExpnId
{
1063 let mut span
= self.data();
1064 let mark
= span
.ctxt
.remove_mark();
1065 *self = Span
::new(span
.lo
, span
.hi
, span
.ctxt
, span
.parent
);
1070 pub fn adjust(&mut self, expn_id
: ExpnId
) -> Option
<ExpnId
> {
1071 let mut span
= self.data();
1072 let mark
= span
.ctxt
.adjust(expn_id
);
1073 *self = Span
::new(span
.lo
, span
.hi
, span
.ctxt
, span
.parent
);
1078 pub fn normalize_to_macros_2_0_and_adjust(&mut self, expn_id
: ExpnId
) -> Option
<ExpnId
> {
1079 let mut span
= self.data();
1080 let mark
= span
.ctxt
.normalize_to_macros_2_0_and_adjust(expn_id
);
1081 *self = Span
::new(span
.lo
, span
.hi
, span
.ctxt
, span
.parent
);
1086 pub fn glob_adjust(&mut self, expn_id
: ExpnId
, glob_span
: Span
) -> Option
<Option
<ExpnId
>> {
1087 let mut span
= self.data();
1088 let mark
= span
.ctxt
.glob_adjust(expn_id
, glob_span
);
1089 *self = Span
::new(span
.lo
, span
.hi
, span
.ctxt
, span
.parent
);
1094 pub fn reverse_glob_adjust(
1098 ) -> Option
<Option
<ExpnId
>> {
1099 let mut span
= self.data();
1100 let mark
= span
.ctxt
.reverse_glob_adjust(expn_id
, glob_span
);
1101 *self = Span
::new(span
.lo
, span
.hi
, span
.ctxt
, span
.parent
);
1106 pub fn normalize_to_macros_2_0(self) -> Span
{
1107 let span
= self.data();
1108 span
.with_ctxt(span
.ctxt
.normalize_to_macros_2_0())
1112 pub fn normalize_to_macro_rules(self) -> Span
{
1113 let span
= self.data();
1114 span
.with_ctxt(span
.ctxt
.normalize_to_macro_rules())
1118 impl Default
for Span
{
1119 fn default() -> Self {
1124 rustc_index
::newtype_index
! {
1126 #[debug_format = "AttrId({})"]
1127 pub struct AttrId {}
1130 /// This trait is used to allow encoder specific encodings of certain types.
1131 /// It is similar to rustc_type_ir's TyEncoder.
1132 pub trait SpanEncoder
: Encoder
{
1133 fn encode_span(&mut self, span
: Span
);
1134 fn encode_symbol(&mut self, symbol
: Symbol
);
1135 fn encode_expn_id(&mut self, expn_id
: ExpnId
);
1136 fn encode_syntax_context(&mut self, syntax_context
: SyntaxContext
);
1137 /// As a local identifier, a `CrateNum` is only meaningful within its context, e.g. within a tcx.
1138 /// Therefore, make sure to include the context when encode a `CrateNum`.
1139 fn encode_crate_num(&mut self, crate_num
: CrateNum
);
1140 fn encode_def_index(&mut self, def_index
: DefIndex
);
1141 fn encode_def_id(&mut self, def_id
: DefId
);
1144 impl SpanEncoder
for FileEncoder
{
1145 fn encode_span(&mut self, span
: Span
) {
1146 let span
= span
.data();
1147 span
.lo
.encode(self);
1148 span
.hi
.encode(self);
1151 fn encode_symbol(&mut self, symbol
: Symbol
) {
1152 self.emit_str(symbol
.as_str());
1155 fn encode_expn_id(&mut self, _expn_id
: ExpnId
) {
1156 panic
!("cannot encode `ExpnId` with `FileEncoder`");
1159 fn encode_syntax_context(&mut self, _syntax_context
: SyntaxContext
) {
1160 panic
!("cannot encode `SyntaxContext` with `FileEncoder`");
1163 fn encode_crate_num(&mut self, crate_num
: CrateNum
) {
1164 self.emit_u32(crate_num
.as_u32());
1167 fn encode_def_index(&mut self, _def_index
: DefIndex
) {
1168 panic
!("cannot encode `DefIndex` with `FileEncoder`");
1171 fn encode_def_id(&mut self, def_id
: DefId
) {
1172 def_id
.krate
.encode(self);
1173 def_id
.index
.encode(self);
1177 impl<E
: SpanEncoder
> Encodable
<E
> for Span
{
1178 fn encode(&self, s
: &mut E
) {
1179 s
.encode_span(*self);
1183 impl<E
: SpanEncoder
> Encodable
<E
> for Symbol
{
1184 fn encode(&self, s
: &mut E
) {
1185 s
.encode_symbol(*self);
1189 impl<E
: SpanEncoder
> Encodable
<E
> for ExpnId
{
1190 fn encode(&self, s
: &mut E
) {
1191 s
.encode_expn_id(*self)
1195 impl<E
: SpanEncoder
> Encodable
<E
> for SyntaxContext
{
1196 fn encode(&self, s
: &mut E
) {
1197 s
.encode_syntax_context(*self)
1201 impl<E
: SpanEncoder
> Encodable
<E
> for CrateNum
{
1202 fn encode(&self, s
: &mut E
) {
1203 s
.encode_crate_num(*self)
1207 impl<E
: SpanEncoder
> Encodable
<E
> for DefIndex
{
1208 fn encode(&self, s
: &mut E
) {
1209 s
.encode_def_index(*self)
1213 impl<E
: SpanEncoder
> Encodable
<E
> for DefId
{
1214 fn encode(&self, s
: &mut E
) {
1215 s
.encode_def_id(*self)
1219 impl<E
: SpanEncoder
> Encodable
<E
> for AttrId
{
1220 fn encode(&self, _s
: &mut E
) {
1221 // A fresh id will be generated when decoding
1225 /// This trait is used to allow decoder specific encodings of certain types.
1226 /// It is similar to rustc_type_ir's TyDecoder.
1227 pub trait SpanDecoder
: Decoder
{
1228 fn decode_span(&mut self) -> Span
;
1229 fn decode_symbol(&mut self) -> Symbol
;
1230 fn decode_expn_id(&mut self) -> ExpnId
;
1231 fn decode_syntax_context(&mut self) -> SyntaxContext
;
1232 fn decode_crate_num(&mut self) -> CrateNum
;
1233 fn decode_def_index(&mut self) -> DefIndex
;
1234 fn decode_def_id(&mut self) -> DefId
;
1235 fn decode_attr_id(&mut self) -> AttrId
;
1238 impl SpanDecoder
for MemDecoder
<'_
> {
1239 fn decode_span(&mut self) -> Span
{
1240 let lo
= Decodable
::decode(self);
1241 let hi
= Decodable
::decode(self);
1243 Span
::new(lo
, hi
, SyntaxContext
::root(), None
)
1246 fn decode_symbol(&mut self) -> Symbol
{
1247 Symbol
::intern(self.read_str())
1250 fn decode_expn_id(&mut self) -> ExpnId
{
1251 panic
!("cannot decode `ExpnId` with `MemDecoder`");
1254 fn decode_syntax_context(&mut self) -> SyntaxContext
{
1255 panic
!("cannot decode `SyntaxContext` with `MemDecoder`");
1258 fn decode_crate_num(&mut self) -> CrateNum
{
1259 CrateNum
::from_u32(self.read_u32())
1262 fn decode_def_index(&mut self) -> DefIndex
{
1263 panic
!("cannot decode `DefIndex` with `MemDecoder`");
1266 fn decode_def_id(&mut self) -> DefId
{
1267 DefId { krate: Decodable::decode(self), index: Decodable::decode(self) }
1270 fn decode_attr_id(&mut self) -> AttrId
{
1271 panic
!("cannot decode `AttrId` with `MemDecoder`");
1275 impl<D
: SpanDecoder
> Decodable
<D
> for Span
{
1276 fn decode(s
: &mut D
) -> Span
{
1281 impl<D
: SpanDecoder
> Decodable
<D
> for Symbol
{
1282 fn decode(s
: &mut D
) -> Symbol
{
1287 impl<D
: SpanDecoder
> Decodable
<D
> for ExpnId
{
1288 fn decode(s
: &mut D
) -> ExpnId
{
1293 impl<D
: SpanDecoder
> Decodable
<D
> for SyntaxContext
{
1294 fn decode(s
: &mut D
) -> SyntaxContext
{
1295 s
.decode_syntax_context()
1299 impl<D
: SpanDecoder
> Decodable
<D
> for CrateNum
{
1300 fn decode(s
: &mut D
) -> CrateNum
{
1301 s
.decode_crate_num()
1305 impl<D
: SpanDecoder
> Decodable
<D
> for DefIndex
{
1306 fn decode(s
: &mut D
) -> DefIndex
{
1307 s
.decode_def_index()
1311 impl<D
: SpanDecoder
> Decodable
<D
> for DefId
{
1312 fn decode(s
: &mut D
) -> DefId
{
1317 impl<D
: SpanDecoder
> Decodable
<D
> for AttrId
{
1318 fn decode(s
: &mut D
) -> AttrId
{
1323 impl fmt
::Debug
for Span
{
1324 fn fmt(&self, f
: &mut fmt
::Formatter
<'_
>) -> fmt
::Result
{
1325 // Use the global `SourceMap` to print the span. If that's not
1326 // available, fall back to printing the raw values.
1328 fn fallback(span
: Span
, f
: &mut fmt
::Formatter
<'_
>) -> fmt
::Result
{
1329 f
.debug_struct("Span")
1330 .field("lo", &span
.lo())
1331 .field("hi", &span
.hi())
1332 .field("ctxt", &span
.ctxt())
1336 if SESSION_GLOBALS
.is_set() {
1337 with_session_globals(|session_globals
| {
1338 if let Some(source_map
) = &session_globals
.source_map
{
1339 write
!(f
, "{} ({:?})", source_map
.span_to_diagnostic_string(*self), self.ctxt())
1350 impl fmt
::Debug
for SpanData
{
1351 fn fmt(&self, f
: &mut fmt
::Formatter
<'_
>) -> fmt
::Result
{
1352 fmt
::Debug
::fmt(&Span
::new(self.lo
, self.hi
, self.ctxt
, self.parent
), f
)
1356 /// Identifies an offset of a multi-byte character in a `SourceFile`.
1357 #[derive(Copy, Clone, Encodable, Decodable, Eq, PartialEq, Debug, HashStable_Generic)]
1358 pub struct MultiByteChar
{
1359 /// The relative offset of the character in the `SourceFile`.
1360 pub pos
: RelativeBytePos
,
1361 /// The number of bytes, `>= 2`.
1365 /// Identifies an offset of a non-narrow character in a `SourceFile`.
1366 #[derive(Copy, Clone, Encodable, Decodable, Eq, PartialEq, Debug, HashStable_Generic)]
1367 pub enum NonNarrowChar
{
1368 /// Represents a zero-width character.
1369 ZeroWidth(RelativeBytePos
),
1370 /// Represents a wide (full-width) character.
1371 Wide(RelativeBytePos
),
1372 /// Represents a tab character, represented visually with a width of 4 characters.
1373 Tab(RelativeBytePos
),
1376 impl NonNarrowChar
{
1377 fn new(pos
: RelativeBytePos
, width
: usize) -> Self {
1379 0 => NonNarrowChar
::ZeroWidth(pos
),
1380 2 => NonNarrowChar
::Wide(pos
),
1381 4 => NonNarrowChar
::Tab(pos
),
1382 _
=> panic
!("width {width} given for non-narrow character"),
1386 /// Returns the relative offset of the character in the `SourceFile`.
1387 pub fn pos(&self) -> RelativeBytePos
{
1389 NonNarrowChar
::ZeroWidth(p
) | NonNarrowChar
::Wide(p
) | NonNarrowChar
::Tab(p
) => p
,
1393 /// Returns the width of the character, 0 (zero-width) or 2 (wide).
1394 pub fn width(&self) -> usize {
1396 NonNarrowChar
::ZeroWidth(_
) => 0,
1397 NonNarrowChar
::Wide(_
) => 2,
1398 NonNarrowChar
::Tab(_
) => 4,
1403 impl Add
<RelativeBytePos
> for NonNarrowChar
{
1406 fn add(self, rhs
: RelativeBytePos
) -> Self {
1408 NonNarrowChar
::ZeroWidth(pos
) => NonNarrowChar
::ZeroWidth(pos
+ rhs
),
1409 NonNarrowChar
::Wide(pos
) => NonNarrowChar
::Wide(pos
+ rhs
),
1410 NonNarrowChar
::Tab(pos
) => NonNarrowChar
::Tab(pos
+ rhs
),
1415 impl Sub
<RelativeBytePos
> for NonNarrowChar
{
1418 fn sub(self, rhs
: RelativeBytePos
) -> Self {
1420 NonNarrowChar
::ZeroWidth(pos
) => NonNarrowChar
::ZeroWidth(pos
- rhs
),
1421 NonNarrowChar
::Wide(pos
) => NonNarrowChar
::Wide(pos
- rhs
),
1422 NonNarrowChar
::Tab(pos
) => NonNarrowChar
::Tab(pos
- rhs
),
1427 /// Identifies an offset of a character that was normalized away from `SourceFile`.
1428 #[derive(Copy, Clone, Encodable, Decodable, Eq, PartialEq, Debug, HashStable_Generic)]
1429 pub struct NormalizedPos
{
1430 /// The relative offset of the character in the `SourceFile`.
1431 pub pos
: RelativeBytePos
,
1432 /// The difference between original and normalized string at position.
1436 #[derive(PartialEq, Eq, Clone, Debug)]
1437 pub enum ExternalSource
{
1438 /// No external source has to be loaded, since the `SourceFile` represents a local crate.
1441 kind
: ExternalSourceKind
,
1442 /// Index of the file inside metadata.
1443 metadata_index
: u32,
1447 /// The state of the lazy external source loading mechanism of a `SourceFile`.
1448 #[derive(PartialEq, Eq, Clone, Debug)]
1449 pub enum ExternalSourceKind
{
1450 /// The external source has been loaded already.
1451 Present(Lrc
<String
>),
1452 /// No attempt has been made to load the external source.
1454 /// A failed attempt has been made to load the external source.
1458 impl ExternalSource
{
1459 pub fn get_source(&self) -> Option
<&Lrc
<String
>> {
1461 ExternalSource
::Foreign { kind: ExternalSourceKind::Present(ref src), .. }
=> Some(src
),
1468 pub struct OffsetOverflowError
;
1470 #[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Encodable, Decodable)]
1471 #[derive(HashStable_Generic)]
1472 pub enum SourceFileHashAlgorithm
{
1478 impl FromStr
for SourceFileHashAlgorithm
{
1481 fn from_str(s
: &str) -> Result
<SourceFileHashAlgorithm
, ()> {
1483 "md5" => Ok(SourceFileHashAlgorithm
::Md5
),
1484 "sha1" => Ok(SourceFileHashAlgorithm
::Sha1
),
1485 "sha256" => Ok(SourceFileHashAlgorithm
::Sha256
),
1491 /// The hash of the on-disk source file used for debug info.
1492 #[derive(Copy, Clone, PartialEq, Eq, Debug, Hash)]
1493 #[derive(HashStable_Generic, Encodable, Decodable)]
1494 pub struct SourceFileHash
{
1495 pub kind
: SourceFileHashAlgorithm
,
1499 impl SourceFileHash
{
1500 pub fn new(kind
: SourceFileHashAlgorithm
, src
: &str) -> SourceFileHash
{
1501 let mut hash
= SourceFileHash { kind, value: Default::default() }
;
1502 let len
= hash
.hash_len();
1503 let value
= &mut hash
.value
[..len
];
1504 let data
= src
.as_bytes();
1506 SourceFileHashAlgorithm
::Md5
=> {
1507 value
.copy_from_slice(&Md5
::digest(data
));
1509 SourceFileHashAlgorithm
::Sha1
=> {
1510 value
.copy_from_slice(&Sha1
::digest(data
));
1512 SourceFileHashAlgorithm
::Sha256
=> {
1513 value
.copy_from_slice(&Sha256
::digest(data
));
1519 /// Check if the stored hash matches the hash of the string.
1520 pub fn matches(&self, src
: &str) -> bool
{
1521 Self::new(self.kind
, src
) == *self
1524 /// The bytes of the hash.
1525 pub fn hash_bytes(&self) -> &[u8] {
1526 let len
= self.hash_len();
1530 fn hash_len(&self) -> usize {
1532 SourceFileHashAlgorithm
::Md5
=> 16,
1533 SourceFileHashAlgorithm
::Sha1
=> 20,
1534 SourceFileHashAlgorithm
::Sha256
=> 32,
1540 pub enum SourceFileLines
{
1541 /// The source file lines, in decoded (random-access) form.
1542 Lines(Vec
<RelativeBytePos
>),
1544 /// The source file lines, in undecoded difference list form.
1545 Diffs(SourceFileDiffs
),
1548 impl SourceFileLines
{
1549 pub fn is_lines(&self) -> bool
{
1550 matches
!(self, SourceFileLines
::Lines(_
))
1554 /// The source file lines in difference list form. This matches the form
1555 /// used within metadata, which saves space by exploiting the fact that the
1556 /// lines list is sorted and individual lines are usually not that long.
1558 /// We read it directly from metadata and only decode it into `Lines` form
1559 /// when necessary. This is a significant performance win, especially for
1560 /// small crates where very little of `std`'s metadata is used.
1562 pub struct SourceFileDiffs
{
1563 /// Always 1, 2, or 4. Always as small as possible, while being big
1564 /// enough to hold the length of the longest line in the source file.
1565 /// The 1 case is by far the most common.
1566 bytes_per_diff
: usize,
1568 /// The number of diffs encoded in `raw_diffs`. Always one less than
1569 /// the number of lines in the source file.
1572 /// The diffs in "raw" form. Each segment of `bytes_per_diff` length
1573 /// encodes one little-endian diff. Note that they aren't LEB128
1574 /// encoded. This makes for much faster decoding. Besides, the
1575 /// bytes_per_diff==1 case is by far the most common, and LEB128
1576 /// encoding has no effect on that case.
1580 /// A single source in the [`SourceMap`].
1581 pub struct SourceFile
{
1582 /// The name of the file that the source came from. Source that doesn't
1583 /// originate from files has names between angle brackets by convention
1584 /// (e.g., `<anon>`).
1586 /// The complete source code.
1587 pub src
: Option
<Lrc
<String
>>,
1588 /// The source code's hash.
1589 pub src_hash
: SourceFileHash
,
1590 /// The external source code (used for external crates, which will have a `None`
1591 /// value as `self.src`.
1592 pub external_src
: FreezeLock
<ExternalSource
>,
1593 /// The start position of this source in the `SourceMap`.
1594 pub start_pos
: BytePos
,
1595 /// The byte length of this source.
1596 pub source_len
: RelativeBytePos
,
1597 /// Locations of lines beginnings in the source code.
1598 pub lines
: FreezeLock
<SourceFileLines
>,
1599 /// Locations of multi-byte characters in the source code.
1600 pub multibyte_chars
: Vec
<MultiByteChar
>,
1601 /// Width of characters that are not narrow in the source code.
1602 pub non_narrow_chars
: Vec
<NonNarrowChar
>,
1603 /// Locations of characters removed during normalization.
1604 pub normalized_pos
: Vec
<NormalizedPos
>,
1605 /// A hash of the filename & crate-id, used for uniquely identifying source
1606 /// files within the crate graph and for speeding up hashing in incremental
1608 pub stable_id
: StableSourceFileId
,
1609 /// Indicates which crate this `SourceFile` was imported from.
1613 impl Clone
for SourceFile
{
1614 fn clone(&self) -> Self {
1616 name
: self.name
.clone(),
1617 src
: self.src
.clone(),
1618 src_hash
: self.src_hash
,
1619 external_src
: self.external_src
.clone(),
1620 start_pos
: self.start_pos
,
1621 source_len
: self.source_len
,
1622 lines
: self.lines
.clone(),
1623 multibyte_chars
: self.multibyte_chars
.clone(),
1624 non_narrow_chars
: self.non_narrow_chars
.clone(),
1625 normalized_pos
: self.normalized_pos
.clone(),
1626 stable_id
: self.stable_id
,
1632 impl<S
: SpanEncoder
> Encodable
<S
> for SourceFile
{
1633 fn encode(&self, s
: &mut S
) {
1634 self.name
.encode(s
);
1635 self.src_hash
.encode(s
);
1636 // Do not encode `start_pos` as it's global state for this session.
1637 self.source_len
.encode(s
);
1639 // We are always in `Lines` form by the time we reach here.
1640 assert
!(self.lines
.read().is_lines());
1641 let lines
= self.lines();
1642 // Store the length.
1643 s
.emit_u32(lines
.len() as u32);
1645 // Compute and store the difference list.
1646 if lines
.len() != 0 {
1647 let max_line_length
= if lines
.len() == 1 {
1652 .map(|&[fst
, snd
]| snd
- fst
)
1653 .map(|bp
| bp
.to_usize())
1658 let bytes_per_diff
: usize = match max_line_length
{
1660 0x100..=0xFFFF => 2,
1664 // Encode the number of bytes used per diff.
1665 s
.emit_u8(bytes_per_diff
as u8);
1667 // Encode the first element.
1668 assert_eq
!(lines
[0], RelativeBytePos(0));
1670 // Encode the difference list.
1671 let diff_iter
= lines
.array_windows().map(|&[fst
, snd
]| snd
- fst
);
1672 let num_diffs
= lines
.len() - 1;
1674 match bytes_per_diff
{
1676 raw_diffs
= Vec
::with_capacity(num_diffs
);
1677 for diff
in diff_iter
{
1678 raw_diffs
.push(diff
.0 as u8);
1682 raw_diffs
= Vec
::with_capacity(bytes_per_diff
* num_diffs
);
1683 for diff
in diff_iter
{
1684 raw_diffs
.extend_from_slice(&(diff
.0 as u16).to_le_bytes());
1688 raw_diffs
= Vec
::with_capacity(bytes_per_diff
* num_diffs
);
1689 for diff
in diff_iter
{
1690 raw_diffs
.extend_from_slice(&(diff
.0).to_le_bytes());
1693 _
=> unreachable
!(),
1695 s
.emit_raw_bytes(&raw_diffs
);
1698 self.multibyte_chars
.encode(s
);
1699 self.non_narrow_chars
.encode(s
);
1700 self.stable_id
.encode(s
);
1701 self.normalized_pos
.encode(s
);
1702 self.cnum
.encode(s
);
1706 impl<D
: SpanDecoder
> Decodable
<D
> for SourceFile
{
1707 fn decode(d
: &mut D
) -> SourceFile
{
1708 let name
: FileName
= Decodable
::decode(d
);
1709 let src_hash
: SourceFileHash
= Decodable
::decode(d
);
1710 let source_len
: RelativeBytePos
= Decodable
::decode(d
);
1712 let num_lines
: u32 = Decodable
::decode(d
);
1714 // Read the number of bytes used per diff.
1715 let bytes_per_diff
= d
.read_u8() as usize;
1717 // Read the difference list.
1718 let num_diffs
= num_lines
as usize - 1;
1719 let raw_diffs
= d
.read_raw_bytes(bytes_per_diff
* num_diffs
).to_vec();
1720 SourceFileLines
::Diffs(SourceFileDiffs { bytes_per_diff, num_diffs, raw_diffs }
)
1722 SourceFileLines
::Lines(vec
![])
1725 let multibyte_chars
: Vec
<MultiByteChar
> = Decodable
::decode(d
);
1726 let non_narrow_chars
: Vec
<NonNarrowChar
> = Decodable
::decode(d
);
1727 let stable_id
= Decodable
::decode(d
);
1728 let normalized_pos
: Vec
<NormalizedPos
> = Decodable
::decode(d
);
1729 let cnum
: CrateNum
= Decodable
::decode(d
);
1732 start_pos
: BytePos
::from_u32(0),
1736 // Unused - the metadata decoder will construct
1737 // a new SourceFile, filling in `external_src` properly
1738 external_src
: FreezeLock
::frozen(ExternalSource
::Unneeded
),
1739 lines
: FreezeLock
::new(lines
),
1749 impl fmt
::Debug
for SourceFile
{
1750 fn fmt(&self, fmt
: &mut fmt
::Formatter
<'_
>) -> fmt
::Result
{
1751 write
!(fmt
, "SourceFile({:?})", self.name
)
1755 /// This is a [SourceFile] identifier that is used to correlate source files between
1756 /// subsequent compilation sessions (which is something we need to do during
1757 /// incremental compilation).
1759 /// It is a hash value (so we can efficiently consume it when stable-hashing
1760 /// spans) that consists of the `FileName` and the `StableCrateId` of the crate
1761 /// the source file is from. The crate id is needed because sometimes the
1762 /// `FileName` is not unique within the crate graph (think `src/lib.rs`, for
1765 /// The way the crate-id part is handled is a bit special: source files of the
1766 /// local crate are hashed as `(filename, None)`, while source files from
1767 /// upstream crates have a hash of `(filename, Some(stable_crate_id))`. This
1768 /// is because SourceFiles for the local crate are allocated very early in the
1769 /// compilation process when the `StableCrateId` is not yet known. If, due to
1770 /// some refactoring of the compiler, the `StableCrateId` of the local crate
1771 /// were to become available, it would be better to uniformely make this a
1772 /// hash of `(filename, stable_crate_id)`.
1774 /// When `SourceFile`s are exported in crate metadata, the `StableSourceFileId`
1775 /// is updated to incorporate the `StableCrateId` of the exporting crate.
1790 pub struct StableSourceFileId(Hash128
);
1792 impl StableSourceFileId
{
1793 fn from_filename_in_current_crate(filename
: &FileName
) -> Self {
1794 Self::from_filename_and_stable_crate_id(filename
, None
)
1797 pub fn from_filename_for_export(
1798 filename
: &FileName
,
1799 local_crate_stable_crate_id
: StableCrateId
,
1801 Self::from_filename_and_stable_crate_id(filename
, Some(local_crate_stable_crate_id
))
1804 fn from_filename_and_stable_crate_id(
1805 filename
: &FileName
,
1806 stable_crate_id
: Option
<StableCrateId
>,
1808 let mut hasher
= StableHasher
::new();
1809 filename
.hash(&mut hasher
);
1810 stable_crate_id
.hash(&mut hasher
);
1811 StableSourceFileId(hasher
.finish())
1819 hash_kind
: SourceFileHashAlgorithm
,
1820 ) -> Result
<Self, OffsetOverflowError
> {
1821 // Compute the file hash before any normalization.
1822 let src_hash
= SourceFileHash
::new(hash_kind
, &src
);
1823 let normalized_pos
= normalize_src(&mut src
);
1825 let stable_id
= StableSourceFileId
::from_filename_in_current_crate(&name
);
1826 let source_len
= src
.len();
1827 let source_len
= u32::try_from(source_len
).map_err(|_
| OffsetOverflowError
)?
;
1829 let (lines
, multibyte_chars
, non_narrow_chars
) =
1830 analyze_source_file
::analyze_source_file(&src
);
1834 src
: Some(Lrc
::new(src
)),
1836 external_src
: FreezeLock
::frozen(ExternalSource
::Unneeded
),
1837 start_pos
: BytePos
::from_u32(0),
1838 source_len
: RelativeBytePos
::from_u32(source_len
),
1839 lines
: FreezeLock
::frozen(SourceFileLines
::Lines(lines
)),
1848 /// This converts the `lines` field to contain `SourceFileLines::Lines` if needed and freezes
1850 fn convert_diffs_to_lines_frozen(&self) {
1851 let mut guard
= if let Some(guard
) = self.lines
.try_write() { guard }
else { return }
;
1853 let SourceFileDiffs { bytes_per_diff, num_diffs, raw_diffs }
= match &*guard
{
1854 SourceFileLines
::Diffs(diffs
) => diffs
,
1855 SourceFileLines
::Lines(..) => {
1856 FreezeWriteGuard
::freeze(guard
);
1861 // Convert from "diffs" form to "lines" form.
1862 let num_lines
= num_diffs
+ 1;
1863 let mut lines
= Vec
::with_capacity(num_lines
);
1864 let mut line_start
= RelativeBytePos(0);
1865 lines
.push(line_start
);
1867 assert_eq
!(*num_diffs
, raw_diffs
.len() / bytes_per_diff
);
1868 match bytes_per_diff
{
1870 lines
.extend(raw_diffs
.into_iter().map(|&diff
| {
1871 line_start
= line_start
+ RelativeBytePos(diff
as u32);
1876 lines
.extend((0..*num_diffs
).map(|i
| {
1877 let pos
= bytes_per_diff
* i
;
1878 let bytes
= [raw_diffs
[pos
], raw_diffs
[pos
+ 1]];
1879 let diff
= u16::from_le_bytes(bytes
);
1880 line_start
= line_start
+ RelativeBytePos(diff
as u32);
1885 lines
.extend((0..*num_diffs
).map(|i
| {
1886 let pos
= bytes_per_diff
* i
;
1893 let diff
= u32::from_le_bytes(bytes
);
1894 line_start
= line_start
+ RelativeBytePos(diff
);
1898 _
=> unreachable
!(),
1901 *guard
= SourceFileLines
::Lines(lines
);
1903 FreezeWriteGuard
::freeze(guard
);
1906 pub fn lines(&self) -> &[RelativeBytePos
] {
1907 if let Some(SourceFileLines
::Lines(lines
)) = self.lines
.get() {
1912 self.convert_diffs_to_lines_frozen();
1913 if let Some(SourceFileLines
::Lines(lines
)) = self.lines
.get() {
1920 /// Returns the `BytePos` of the beginning of the current line.
1921 pub fn line_begin_pos(&self, pos
: BytePos
) -> BytePos
{
1922 let pos
= self.relative_position(pos
);
1923 let line_index
= self.lookup_line(pos
).unwrap();
1924 let line_start_pos
= self.lines()[line_index
];
1925 self.absolute_position(line_start_pos
)
1928 /// Add externally loaded source.
1929 /// If the hash of the input doesn't match or no input is supplied via None,
1930 /// it is interpreted as an error and the corresponding enum variant is set.
1931 /// The return value signifies whether some kind of source is present.
1932 pub fn add_external_src
<F
>(&self, get_src
: F
) -> bool
1934 F
: FnOnce() -> Option
<String
>,
1936 if !self.external_src
.is_frozen() {
1937 let src
= get_src();
1938 let src
= src
.and_then(|mut src
| {
1939 // The src_hash needs to be computed on the pre-normalized src.
1940 self.src_hash
.matches(&src
).then(|| {
1941 normalize_src(&mut src
);
1946 self.external_src
.try_write().map(|mut external_src
| {
1947 if let ExternalSource
::Foreign
{
1948 kind
: src_kind @ ExternalSourceKind
::AbsentOk
,
1950 } = &mut *external_src
1952 *src_kind
= if let Some(src
) = src
{
1953 ExternalSourceKind
::Present(Lrc
::new(src
))
1955 ExternalSourceKind
::AbsentErr
1958 panic
!("unexpected state {:?}", *external_src
)
1961 // Freeze this so we don't try to load the source again.
1962 FreezeWriteGuard
::freeze(external_src
)
1966 self.src
.is_some() || self.external_src
.read().get_source().is_some()
1969 /// Gets a line from the list of pre-computed line-beginnings.
1970 /// The line number here is 0-based.
1971 pub fn get_line(&self, line_number
: usize) -> Option
<Cow
<'_
, str>> {
1972 fn get_until_newline(src
: &str, begin
: usize) -> &str {
1973 // We can't use `lines.get(line_number+1)` because we might
1974 // be parsing when we call this function and thus the current
1975 // line is the last one we have line info for.
1976 let slice
= &src
[begin
..];
1977 match slice
.find('
\n'
) {
1978 Some(e
) => &slice
[..e
],
1984 let line
= self.lines().get(line_number
).copied()?
;
1988 if let Some(ref src
) = self.src
{
1989 Some(Cow
::from(get_until_newline(src
, begin
)))
1994 .map(|src
| Cow
::Owned(String
::from(get_until_newline(src
, begin
))))
1998 pub fn is_real_file(&self) -> bool
{
2003 pub fn is_imported(&self) -> bool
{
2007 pub fn count_lines(&self) -> usize {
2012 pub fn absolute_position(&self, pos
: RelativeBytePos
) -> BytePos
{
2013 BytePos
::from_u32(pos
.to_u32() + self.start_pos
.to_u32())
2017 pub fn relative_position(&self, pos
: BytePos
) -> RelativeBytePos
{
2018 RelativeBytePos
::from_u32(pos
.to_u32() - self.start_pos
.to_u32())
2022 pub fn end_position(&self) -> BytePos
{
2023 self.absolute_position(self.source_len
)
2026 /// Finds the line containing the given position. The return value is the
2027 /// index into the `lines` array of this `SourceFile`, not the 1-based line
2028 /// number. If the source_file is empty or the position is located before the
2029 /// first line, `None` is returned.
2030 pub fn lookup_line(&self, pos
: RelativeBytePos
) -> Option
<usize> {
2031 self.lines().partition_point(|x
| x
<= &pos
).checked_sub(1)
2034 pub fn line_bounds(&self, line_index
: usize) -> Range
<BytePos
> {
2035 if self.is_empty() {
2036 return self.start_pos
..self.start_pos
;
2039 let lines
= self.lines();
2040 assert
!(line_index
< lines
.len());
2041 if line_index
== (lines
.len() - 1) {
2042 self.absolute_position(lines
[line_index
])..self.end_position()
2044 self.absolute_position(lines
[line_index
])..self.absolute_position(lines
[line_index
+ 1])
2048 /// Returns whether or not the file contains the given `SourceMap` byte
2049 /// position. The position one past the end of the file is considered to be
2050 /// contained by the file. This implies that files for which `is_empty`
2051 /// returns true still contain one byte position according to this function.
2053 pub fn contains(&self, byte_pos
: BytePos
) -> bool
{
2054 byte_pos
>= self.start_pos
&& byte_pos
<= self.end_position()
2058 pub fn is_empty(&self) -> bool
{
2059 self.source_len
.to_u32() == 0
2062 /// Calculates the original byte position relative to the start of the file
2063 /// based on the given byte position.
2064 pub fn original_relative_byte_pos(&self, pos
: BytePos
) -> RelativeBytePos
{
2065 let pos
= self.relative_position(pos
);
2067 // Diff before any records is 0. Otherwise use the previously recorded
2068 // diff as that applies to the following characters until a new diff
2070 let diff
= match self.normalized_pos
.binary_search_by(|np
| np
.pos
.cmp(&pos
)) {
2071 Ok(i
) => self.normalized_pos
[i
].diff
,
2073 Err(i
) => self.normalized_pos
[i
- 1].diff
,
2076 RelativeBytePos
::from_u32(pos
.0 + diff
)
2079 /// Calculates a normalized byte position from a byte offset relative to the
2080 /// start of the file.
2082 /// When we get an inline assembler error from LLVM during codegen, we
2083 /// import the expanded assembly code as a new `SourceFile`, which can then
2084 /// be used for error reporting with spans. However the byte offsets given
2085 /// to us by LLVM are relative to the start of the original buffer, not the
2086 /// normalized one. Hence we need to convert those offsets to the normalized
2087 /// form when constructing spans.
2088 pub fn normalized_byte_pos(&self, offset
: u32) -> BytePos
{
2089 let diff
= match self
2091 .binary_search_by(|np
| (np
.pos
.0 + np
.diff
).cmp(&(self.start_pos
.0 + offset
)))
2093 Ok(i
) => self.normalized_pos
[i
].diff
,
2095 Err(i
) => self.normalized_pos
[i
- 1].diff
,
2098 BytePos
::from_u32(self.start_pos
.0 + offset
- diff
)
2101 /// Converts an relative `RelativeBytePos` to a `CharPos` relative to the `SourceFile`.
2102 fn bytepos_to_file_charpos(&self, bpos
: RelativeBytePos
) -> CharPos
{
2103 // The number of extra bytes due to multibyte chars in the `SourceFile`.
2104 let mut total_extra_bytes
= 0;
2106 for mbc
in self.multibyte_chars
.iter() {
2107 debug
!("{}-byte char at {:?}", mbc
.bytes
, mbc
.pos
);
2109 // Every character is at least one byte, so we only
2110 // count the actual extra bytes.
2111 total_extra_bytes
+= mbc
.bytes
as u32 - 1;
2112 // We should never see a byte position in the middle of a
2114 assert
!(bpos
.to_u32() >= mbc
.pos
.to_u32() + mbc
.bytes
as u32);
2120 assert
!(total_extra_bytes
<= bpos
.to_u32());
2121 CharPos(bpos
.to_usize() - total_extra_bytes
as usize)
2124 /// Looks up the file's (1-based) line number and (0-based `CharPos`) column offset, for a
2125 /// given `RelativeBytePos`.
2126 fn lookup_file_pos(&self, pos
: RelativeBytePos
) -> (usize, CharPos
) {
2127 let chpos
= self.bytepos_to_file_charpos(pos
);
2128 match self.lookup_line(pos
) {
2130 let line
= a
+ 1; // Line numbers start at 1
2131 let linebpos
= self.lines()[a
];
2132 let linechpos
= self.bytepos_to_file_charpos(linebpos
);
2133 let col
= chpos
- linechpos
;
2134 debug
!("byte pos {:?} is on the line at byte pos {:?}", pos
, linebpos
);
2135 debug
!("char pos {:?} is on the line at char pos {:?}", chpos
, linechpos
);
2136 debug
!("byte is on line: {}", line
);
2137 assert
!(chpos
>= linechpos
);
2144 /// Looks up the file's (1-based) line number, (0-based `CharPos`) column offset, and (0-based)
2145 /// column offset when displayed, for a given `BytePos`.
2146 pub fn lookup_file_pos_with_col_display(&self, pos
: BytePos
) -> (usize, CharPos
, usize) {
2147 let pos
= self.relative_position(pos
);
2148 let (line
, col_or_chpos
) = self.lookup_file_pos(pos
);
2150 let col
= col_or_chpos
;
2151 let linebpos
= self.lines()[line
- 1];
2153 let start_width_idx
= self
2155 .binary_search_by_key(&linebpos
, |x
| x
.pos())
2156 .unwrap_or_else(|x
| x
);
2157 let end_width_idx
= self
2159 .binary_search_by_key(&pos
, |x
| x
.pos())
2160 .unwrap_or_else(|x
| x
);
2161 let special_chars
= end_width_idx
- start_width_idx
;
2162 let non_narrow
: usize = self.non_narrow_chars
[start_width_idx
..end_width_idx
]
2166 col
.0 - special_chars
+ non_narrow
2168 (line
, col
, col_display
)
2170 let chpos
= col_or_chpos
;
2172 let end_width_idx
= self
2174 .binary_search_by_key(&pos
, |x
| x
.pos())
2175 .unwrap_or_else(|x
| x
);
2176 let non_narrow
: usize =
2177 self.non_narrow_chars
[0..end_width_idx
].iter().map(|x
| x
.width()).sum();
2178 chpos
.0 - end_width_idx
+ non_narrow
2180 (0, chpos
, col_display
)
2185 /// Normalizes the source code and records the normalizations.
2186 fn normalize_src(src
: &mut String
) -> Vec
<NormalizedPos
> {
2187 let mut normalized_pos
= vec
![];
2188 remove_bom(src
, &mut normalized_pos
);
2189 normalize_newlines(src
, &mut normalized_pos
);
2193 /// Removes UTF-8 BOM, if any.
2194 fn remove_bom(src
: &mut String
, normalized_pos
: &mut Vec
<NormalizedPos
>) {
2195 if src
.starts_with('
\u{feff}'
) {
2197 normalized_pos
.push(NormalizedPos { pos: RelativeBytePos(0), diff: 3 }
);
2201 /// Replaces `\r\n` with `\n` in-place in `src`.
2203 /// Leaves any occurrences of lone `\r` unchanged.
2204 fn normalize_newlines(src
: &mut String
, normalized_pos
: &mut Vec
<NormalizedPos
>) {
2205 if !src
.as_bytes().contains(&b'
\r'
) {
2209 // We replace `\r\n` with `\n` in-place, which doesn't break utf-8 encoding.
2210 // While we *can* call `as_mut_vec` and do surgery on the live string
2211 // directly, let's rather steal the contents of `src`. This makes the code
2212 // safe even if a panic occurs.
2214 let mut buf
= std
::mem
::replace(src
, String
::new()).into_bytes();
2215 let mut gap_len
= 0;
2216 let mut tail
= buf
.as_mut_slice();
2218 let original_gap
= normalized_pos
.last().map_or(0, |l
| l
.diff
);
2220 let idx
= match find_crlf(&tail
[gap_len
..]) {
2222 Some(idx
) => idx
+ gap_len
,
2224 tail
.copy_within(gap_len
..idx
, 0);
2225 tail
= &mut tail
[idx
- gap_len
..];
2226 if tail
.len() == gap_len
{
2229 cursor
+= idx
- gap_len
;
2231 normalized_pos
.push(NormalizedPos
{
2232 pos
: RelativeBytePos
::from_usize(cursor
+ 1),
2233 diff
: original_gap
+ gap_len
as u32,
2237 // Account for removed `\r`.
2238 // After `set_len`, `buf` is guaranteed to contain utf-8 again.
2239 let new_len
= buf
.len() - gap_len
;
2241 buf
.set_len(new_len
);
2242 *src
= String
::from_utf8_unchecked(buf
);
2245 fn find_crlf(src
: &[u8]) -> Option
<usize> {
2246 let mut search_idx
= 0;
2247 while let Some(idx
) = find_cr(&src
[search_idx
..]) {
2248 if src
[search_idx
..].get(idx
+ 1) != Some(&b'
\n'
) {
2249 search_idx
+= idx
+ 1;
2252 return Some(search_idx
+ idx
);
2257 fn find_cr(src
: &[u8]) -> Option
<usize> {
2258 src
.iter().position(|&b
| b
== b'
\r'
)
2262 // _____________________________________________________________________________
2263 // Pos, BytePos, CharPos
2267 fn from_usize(n
: usize) -> Self;
2268 fn to_usize(&self) -> usize;
2269 fn from_u32(n
: u32) -> Self;
2270 fn to_u32(&self) -> u32;
2273 macro_rules
! impl_pos
{
2277 $vis
:vis
struct $ident
:ident($inner_vis
:vis $inner_ty
:ty
);
2282 $vis
struct $
ident($inner_vis $inner_ty
);
2284 impl Pos
for $ident
{
2286 fn from_usize(n
: usize) -> $ident
{
2287 $
ident(n
as $inner_ty
)
2291 fn to_usize(&self) -> usize {
2296 fn from_u32(n
: u32) -> $ident
{
2297 $
ident(n
as $inner_ty
)
2301 fn to_u32(&self) -> u32 {
2306 impl Add
for $ident
{
2307 type Output
= $ident
;
2310 fn add(self, rhs
: $ident
) -> $ident
{
2311 $
ident(self.0 + rhs
.0)
2315 impl Sub
for $ident
{
2316 type Output
= $ident
;
2319 fn sub(self, rhs
: $ident
) -> $ident
{
2320 $
ident(self.0 - rhs
.0)
2330 /// Keep this small (currently 32-bits), as AST contains a lot of them.
2331 #[derive(Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord, Debug)]
2332 pub struct BytePos(pub u32);
2334 /// A byte offset relative to file beginning.
2335 #[derive(Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord, Debug)]
2336 pub struct RelativeBytePos(pub u32);
2338 /// A character offset.
2340 /// Because of multibyte UTF-8 characters, a byte offset
2341 /// is not equivalent to a character offset. The [`SourceMap`] will convert [`BytePos`]
2342 /// values to `CharPos` values as necessary.
2343 #[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Debug)]
2344 pub struct CharPos(pub usize);
2347 impl<S
: Encoder
> Encodable
<S
> for BytePos
{
2348 fn encode(&self, s
: &mut S
) {
2353 impl<D
: Decoder
> Decodable
<D
> for BytePos
{
2354 fn decode(d
: &mut D
) -> BytePos
{
2355 BytePos(d
.read_u32())
2359 impl<H
: HashStableContext
> HashStable
<H
> for RelativeBytePos
{
2360 fn hash_stable(&self, hcx
: &mut H
, hasher
: &mut StableHasher
) {
2361 self.0.hash_stable(hcx
, hasher
);
2365 impl<S
: Encoder
> Encodable
<S
> for RelativeBytePos
{
2366 fn encode(&self, s
: &mut S
) {
2371 impl<D
: Decoder
> Decodable
<D
> for RelativeBytePos
{
2372 fn decode(d
: &mut D
) -> RelativeBytePos
{
2373 RelativeBytePos(d
.read_u32())
2377 // _____________________________________________________________________________
2378 // Loc, SourceFileAndLine, SourceFileAndBytePos
2381 /// A source code location used for error reporting.
2382 #[derive(Debug, Clone)]
2384 /// Information about the original source.
2385 pub file
: Lrc
<SourceFile
>,
2386 /// The (1-based) line number.
2388 /// The (0-based) column offset.
2390 /// The (0-based) column offset when displayed.
2391 pub col_display
: usize,
2394 // Used to be structural records.
2396 pub struct SourceFileAndLine
{
2397 pub sf
: Lrc
<SourceFile
>,
2398 /// Index of line, starting from 0.
2402 pub struct SourceFileAndBytePos
{
2403 pub sf
: Lrc
<SourceFile
>,
2407 #[derive(Copy, Clone, Debug, PartialEq, Eq)]
2408 pub struct LineInfo
{
2409 /// Index of line, starting from 0.
2410 pub line_index
: usize,
2412 /// Column in line where span begins, starting from 0.
2413 pub start_col
: CharPos
,
2415 /// Column in line where span ends, starting from 0, exclusive.
2416 pub end_col
: CharPos
,
2419 pub struct FileLines
{
2420 pub file
: Lrc
<SourceFile
>,
2421 pub lines
: Vec
<LineInfo
>,
2424 pub static SPAN_TRACK
: AtomicRef
<fn(LocalDefId
)> = AtomicRef
::new(&((|_
| {}
) as fn(_
)));
2426 // _____________________________________________________________________________
2427 // SpanLinesError, SpanSnippetError, DistinctSources, MalformedSourceMapPositions
2430 pub type FileLinesResult
= Result
<FileLines
, SpanLinesError
>;
2432 #[derive(Clone, PartialEq, Eq, Debug)]
2433 pub enum SpanLinesError
{
2434 DistinctSources(Box
<DistinctSources
>),
2437 #[derive(Clone, PartialEq, Eq, Debug)]
2438 pub enum SpanSnippetError
{
2439 IllFormedSpan(Span
),
2440 DistinctSources(Box
<DistinctSources
>),
2441 MalformedForSourcemap(MalformedSourceMapPositions
),
2442 SourceNotAvailable { filename: FileName }
,
2445 #[derive(Clone, PartialEq, Eq, Debug)]
2446 pub struct DistinctSources
{
2447 pub begin
: (FileName
, BytePos
),
2448 pub end
: (FileName
, BytePos
),
2451 #[derive(Clone, PartialEq, Eq, Debug)]
2452 pub struct MalformedSourceMapPositions
{
2454 pub source_len
: usize,
2455 pub begin_pos
: BytePos
,
2456 pub end_pos
: BytePos
,
2459 /// Range inside of a `Span` used for diagnostics when we only have access to relative positions.
2460 #[derive(Copy, Clone, PartialEq, Eq, Debug)]
2461 pub struct InnerSpan
{
2467 pub fn new(start
: usize, end
: usize) -> InnerSpan
{
2468 InnerSpan { start, end }
2472 /// Requirements for a `StableHashingContext` to be used in this crate.
2474 /// This is a hack to allow using the [`HashStable_Generic`] derive macro
2475 /// instead of implementing everything in rustc_middle.
2476 pub trait HashStableContext
{
2477 fn def_path_hash(&self, def_id
: DefId
) -> DefPathHash
;
2478 fn hash_spans(&self) -> bool
;
2479 /// Accesses `sess.opts.unstable_opts.incremental_ignore_spans` since
2480 /// we don't have easy access to a `Session`
2481 fn unstable_opts_incremental_ignore_spans(&self) -> bool
;
2482 fn def_span(&self, def_id
: LocalDefId
) -> Span
;
2483 fn span_data_to_lines_and_cols(
2486 ) -> Option
<(Lrc
<SourceFile
>, usize, BytePos
, usize, BytePos
)>;
2487 fn hashing_controls(&self) -> HashingControls
;
2490 impl<CTX
> HashStable
<CTX
> for Span
2492 CTX
: HashStableContext
,
2494 /// Hashes a span in a stable way. We can't directly hash the span's `BytePos`
2495 /// fields (that would be similar to hashing pointers, since those are just
2496 /// offsets into the `SourceMap`). Instead, we hash the (file name, line, column)
2497 /// triple, which stays the same even if the containing `SourceFile` has moved
2498 /// within the `SourceMap`.
2500 /// Also note that we are hashing byte offsets for the column, not unicode
2501 /// codepoint offsets. For the purpose of the hash that's sufficient.
2502 /// Also, hashing filenames is expensive so we avoid doing it twice when the
2503 /// span starts and ends in the same file, which is almost always the case.
2504 fn hash_stable(&self, ctx
: &mut CTX
, hasher
: &mut StableHasher
) {
2505 const TAG_VALID_SPAN
: u8 = 0;
2506 const TAG_INVALID_SPAN
: u8 = 1;
2507 const TAG_RELATIVE_SPAN
: u8 = 2;
2509 if !ctx
.hash_spans() {
2513 let span
= self.data_untracked();
2514 span
.ctxt
.hash_stable(ctx
, hasher
);
2515 span
.parent
.hash_stable(ctx
, hasher
);
2517 if span
.is_dummy() {
2518 Hash
::hash(&TAG_INVALID_SPAN
, hasher
);
2522 if let Some(parent
) = span
.parent
{
2523 let def_span
= ctx
.def_span(parent
).data_untracked();
2524 if def_span
.contains(span
) {
2525 // This span is enclosed in a definition: only hash the relative position.
2526 Hash
::hash(&TAG_RELATIVE_SPAN
, hasher
);
2527 (span
.lo
- def_span
.lo
).to_u32().hash_stable(ctx
, hasher
);
2528 (span
.hi
- def_span
.lo
).to_u32().hash_stable(ctx
, hasher
);
2533 // If this is not an empty or invalid span, we want to hash the last
2534 // position that belongs to it, as opposed to hashing the first
2535 // position past it.
2536 let Some((file
, line_lo
, col_lo
, line_hi
, col_hi
)) = ctx
.span_data_to_lines_and_cols(&span
)
2538 Hash
::hash(&TAG_INVALID_SPAN
, hasher
);
2542 Hash
::hash(&TAG_VALID_SPAN
, hasher
);
2543 Hash
::hash(&file
.stable_id
, hasher
);
2545 // Hash both the length and the end location (line/column) of a span. If we
2546 // hash only the length, for example, then two otherwise equal spans with
2547 // different end locations will have the same hash. This can cause a problem
2548 // during incremental compilation wherein a previous result for a query that
2549 // depends on the end location of a span will be incorrectly reused when the
2550 // end location of the span it depends on has changed (see issue #74890). A
2551 // similar analysis applies if some query depends specifically on the length
2552 // of the span, but we only hash the end location. So hash both.
2554 let col_lo_trunc
= (col_lo
.0 as u64) & 0xFF;
2555 let line_lo_trunc
= ((line_lo
as u64) & 0xFF_FF_FF) << 8;
2556 let col_hi_trunc
= (col_hi
.0 as u64) & 0xFF << 32;
2557 let line_hi_trunc
= ((line_hi
as u64) & 0xFF_FF_FF) << 40;
2558 let col_line
= col_lo_trunc
| line_lo_trunc
| col_hi_trunc
| line_hi_trunc
;
2559 let len
= (span
.hi
- span
.lo
).0;
2560 Hash
::hash(&col_line
, hasher
);
2561 Hash
::hash(&len
, hasher
);
2565 /// Useful type to use with `Result<>` indicate that an error has already
2566 /// been reported to the user, so no need to continue checking.
2568 /// The `()` field is necessary: it is non-`pub`, which means values of this
2569 /// type cannot be constructed outside of this crate.
2570 #[derive(Clone, Copy, Debug, Hash, PartialEq, Eq, PartialOrd, Ord)]
2571 #[derive(HashStable_Generic)]
2572 pub struct ErrorGuaranteed(());
2574 impl ErrorGuaranteed
{
2575 /// Don't use this outside of `DiagCtxtInner::emit_diagnostic`!
2576 #[deprecated = "should only be used in `DiagCtxtInner::emit_diagnostic`"]
2577 pub fn unchecked_error_guaranteed() -> Self {
2582 impl<E
: rustc_serialize
::Encoder
> Encodable
<E
> for ErrorGuaranteed
{
2584 fn encode(&self, _e
: &mut E
) {
2586 "should never serialize an `ErrorGuaranteed`, as we do not write metadata or \
2587 incremental caches in case errors occurred"
2591 impl<D
: rustc_serialize
::Decoder
> Decodable
<D
> for ErrorGuaranteed
{
2593 fn decode(_d
: &mut D
) -> ErrorGuaranteed
{
2595 "`ErrorGuaranteed` should never have been serialized to metadata or incremental caches"