]> git.proxmox.com Git - rustc.git/blame - compiler/rustc_span/src/lib.rs
New upstream version 1.70.0+dfsg1
[rustc.git] / compiler / rustc_span / src / lib.rs
CommitLineData
5869c6ff
XL
1//! Source positions and related helper functions.
2//!
3//! Important concepts in this module include:
4//!
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.
8//!
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`].
3157f602 11//!
0731742a 12//! ## Note
3157f602
XL
13//!
14//! This API is completely unstable and subject to change.
15
1b1a35ee
XL
16#![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")]
17#![feature(array_windows)]
94222f64 18#![feature(if_let_guard)]
f9f354fc 19#![feature(negative_impls)]
f9f354fc 20#![feature(min_specialization)]
5e7ed085 21#![feature(rustc_attrs)]
9ffffee4 22#![feature(let_chains)]
353b0b11 23#![feature(round_char_boundary)]
f2b60f7d
FG
24#![deny(rustc::untranslatable_diagnostic)]
25#![deny(rustc::diagnostic_outside_of_impl)]
f9f354fc 26
3dfed10e 27#[macro_use]
f9f354fc 28extern crate rustc_macros;
3157f602 29
c295e0f8
XL
30#[macro_use]
31extern crate tracing;
32
dfeec247 33use rustc_data_structures::AtomicRef;
60c5eb7d 34use rustc_macros::HashStable_Generic;
dfeec247 35use rustc_serialize::{Decodable, Decoder, Encodable, Encoder};
60c5eb7d 36
60c5eb7d 37mod caching_source_map_view;
dfeec247 38pub mod source_map;
60c5eb7d 39pub use self::caching_source_map_view::CachingSourceMapView;
f035d41b 40use source_map::SourceMap;
3157f602 41
94b46f34 42pub mod edition;
dc9dc135 43use edition::Edition;
cc61c64b 44pub mod hygiene;
e1599b0c 45use hygiene::Transparency;
3c0e092e 46pub use hygiene::{DesugaringKind, ExpnKind, MacroKind};
136023e0 47pub use hygiene::{ExpnData, ExpnHash, ExpnId, LocalExpnId, SyntaxContext};
5099ac24 48use rustc_data_structures::stable_hasher::HashingControls;
74b04a01 49pub mod def_id;
c295e0f8 50use def_id::{CrateNum, DefId, DefPathHash, LocalDefId, LOCAL_CRATE};
9ffffee4 51pub mod edit_distance;
ea8adc8c
XL
52mod span_encoding;
53pub use span_encoding::{Span, DUMMY_SP};
54
cc61c64b 55pub mod symbol;
dfeec247 56pub use symbol::{sym, Symbol};
cc61c64b 57
b7449926 58mod analyze_source_file;
60c5eb7d 59pub mod fatal_error;
8faf50e0 60
04454e1e
FG
61pub mod profiling;
62
dfeec247
XL
63use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
64use rustc_data_structures::sync::{Lock, Lrc};
0731742a
XL
65
66use std::borrow::Cow;
0731742a
XL
67use std::cmp::{self, Ordering};
68use std::fmt;
ba9703b0 69use std::hash::Hash;
29967ef6 70use std::ops::{Add, Range, Sub};
ba9703b0
XL
71use std::path::{Path, PathBuf};
72use std::str::FromStr;
04454e1e 73use std::sync::Arc;
ba9703b0 74
5099ac24 75use md5::Digest;
ba9703b0 76use md5::Md5;
ba9703b0 77use sha1::Sha1;
29967ef6
XL
78use sha2::Sha256;
79
416331ca
XL
80#[cfg(test)]
81mod tests;
82
487cf647
FG
83/// Per-session global variables: this struct is stored in thread-local storage
84/// in such a way that it is accessible without any kind of handle to all
85/// threads within the compilation session, but is not accessible outside the
86/// session.
f035d41b 87pub struct SessionGlobals {
c295e0f8 88 symbol_interner: symbol::Interner,
0531ce1d
XL
89 span_interner: Lock<span_encoding::SpanInterner>,
90 hygiene_data: Lock<hygiene::HygieneData>,
353b0b11
FG
91
92 /// A reference to the source map in the `Session`. It's an `Option`
93 /// because it can't be initialized until `Session` is created, which
94 /// happens after `SessionGlobals`. `set_source_map` does the
95 /// initialization.
96 ///
97 /// This field should only be used in places where the `Session` is truly
98 /// not available, such as `<Span as Debug>::fmt`.
f035d41b 99 source_map: Lock<Option<Lrc<SourceMap>>>,
0531ce1d
XL
100}
101
f035d41b
XL
102impl SessionGlobals {
103 pub fn new(edition: Edition) -> SessionGlobals {
104 SessionGlobals {
c295e0f8 105 symbol_interner: symbol::Interner::fresh(),
0531ce1d 106 span_interner: Lock::new(span_encoding::SpanInterner::default()),
416331ca 107 hygiene_data: Lock::new(hygiene::HygieneData::new(edition)),
f035d41b 108 source_map: Lock::new(None),
0531ce1d
XL
109 }
110 }
111}
112
136023e0
XL
113#[inline]
114pub fn create_session_globals_then<R>(edition: Edition, f: impl FnOnce() -> R) -> R {
115 assert!(
116 !SESSION_GLOBALS.is_set(),
117 "SESSION_GLOBALS should never be overwritten! \
118 Use another thread if you need another SessionGlobals"
119 );
3dfed10e
XL
120 let session_globals = SessionGlobals::new(edition);
121 SESSION_GLOBALS.set(&session_globals, f)
122}
123
136023e0
XL
124#[inline]
125pub fn set_session_globals_then<R>(session_globals: &SessionGlobals, f: impl FnOnce() -> R) -> R {
126 assert!(
127 !SESSION_GLOBALS.is_set(),
128 "SESSION_GLOBALS should never be overwritten! \
129 Use another thread if you need another SessionGlobals"
130 );
131 SESSION_GLOBALS.set(session_globals, f)
132}
133
134#[inline]
135pub fn create_default_session_if_not_set_then<R, F>(f: F) -> R
136where
137 F: FnOnce(&SessionGlobals) -> R,
138{
139 create_session_if_not_set_then(edition::DEFAULT_EDITION, f)
140}
141
142#[inline]
143pub fn create_session_if_not_set_then<R, F>(edition: Edition, f: F) -> R
144where
145 F: FnOnce(&SessionGlobals) -> R,
146{
147 if !SESSION_GLOBALS.is_set() {
148 let session_globals = SessionGlobals::new(edition);
149 SESSION_GLOBALS.set(&session_globals, || SESSION_GLOBALS.with(f))
150 } else {
151 SESSION_GLOBALS.with(f)
152 }
153}
154
155#[inline]
156pub fn with_session_globals<R, F>(f: F) -> R
157where
158 F: FnOnce(&SessionGlobals) -> R,
159{
160 SESSION_GLOBALS.with(f)
161}
162
163#[inline]
164pub fn create_default_session_globals_then<R>(f: impl FnOnce() -> R) -> R {
165 create_session_globals_then(edition::DEFAULT_EDITION, f)
3dfed10e
XL
166}
167
168// If this ever becomes non thread-local, `decode_syntax_context`
169// and `decode_expn_id` will need to be updated to handle concurrent
170// deserialization.
136023e0 171scoped_tls::scoped_thread_local!(static SESSION_GLOBALS: SessionGlobals);
0531ce1d 172
ba9703b0
XL
173// FIXME: We should use this enum or something like it to get rid of the
174// use of magic `/rust/1.x/...` paths across the board.
17df50a5 175#[derive(Debug, Eq, PartialEq, Clone, Ord, PartialOrd)]
94222f64 176#[derive(Decodable)]
ba9703b0 177pub enum RealFileName {
17df50a5
XL
178 LocalPath(PathBuf),
179 /// For remapped paths (namely paths into libstd that have been mapped
180 /// to the appropriate spot on the local host's file system, and local file
181 /// system paths that have been remapped with `FilePathMapping`),
182 Remapped {
183 /// `local_path` is the (host-dependent) local path to the file. This is
184 /// None if the file was imported from another crate
185 local_path: Option<PathBuf>,
ba9703b0
XL
186 /// `virtual_name` is the stable path rustc will store internally within
187 /// build artifacts.
188 virtual_name: PathBuf,
189 },
190}
191
17df50a5
XL
192impl Hash for RealFileName {
193 fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
194 // To prevent #70924 from happening again we should only hash the
195 // remapped (virtualized) path if that exists. This is because
196 // virtualized paths to sysroot crates (/rust/$hash or /rust/$version)
197 // remain stable even if the corresponding local_path changes
198 self.remapped_path_if_available().hash(state)
199 }
200}
201
202// This is functionally identical to #[derive(Encodable)], with the exception of
203// an added assert statement
204impl<S: Encoder> Encodable<S> for RealFileName {
923072b8
FG
205 fn encode(&self, encoder: &mut S) {
206 match *self {
207 RealFileName::LocalPath(ref local_path) => encoder.emit_enum_variant(0, |encoder| {
208 local_path.encode(encoder);
209 }),
17df50a5
XL
210
211 RealFileName::Remapped { ref local_path, ref virtual_name } => encoder
923072b8 212 .emit_enum_variant(1, |encoder| {
17df50a5
XL
213 // For privacy and build reproducibility, we must not embed host-dependant path in artifacts
214 // if they have been remapped by --remap-path-prefix
215 assert!(local_path.is_none());
923072b8
FG
216 local_path.encode(encoder);
217 virtual_name.encode(encoder);
17df50a5 218 }),
923072b8 219 }
17df50a5
XL
220 }
221}
222
ba9703b0 223impl RealFileName {
17df50a5
XL
224 /// Returns the path suitable for reading from the file system on the local host,
225 /// if this information exists.
226 /// Avoid embedding this in build artifacts; see `remapped_path_if_available()` for that.
227 pub fn local_path(&self) -> Option<&Path> {
ba9703b0 228 match self {
17df50a5 229 RealFileName::LocalPath(p) => Some(p),
487cf647 230 RealFileName::Remapped { local_path, virtual_name: _ } => local_path.as_deref(),
ba9703b0
XL
231 }
232 }
233
17df50a5
XL
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 into_local_path(self) -> Option<PathBuf> {
ba9703b0 238 match self {
17df50a5
XL
239 RealFileName::LocalPath(p) => Some(p),
240 RealFileName::Remapped { local_path: p, virtual_name: _ } => p,
ba9703b0
XL
241 }
242 }
243
17df50a5
XL
244 /// Returns the path suitable for embedding into build artifacts. This would still
245 /// be a local path if it has not been remapped. A remapped path will not correspond
246 /// to a valid file system path: see `local_path_if_available()` for something that
247 /// is more likely to return paths into the local host file system.
248 pub fn remapped_path_if_available(&self) -> &Path {
ba9703b0 249 match self {
17df50a5 250 RealFileName::LocalPath(p)
487cf647 251 | RealFileName::Remapped { local_path: _, virtual_name: p } => p,
17df50a5
XL
252 }
253 }
254
255 /// Returns the path suitable for reading from the file system on the local host,
256 /// if this information exists. Otherwise returns the remapped name.
257 /// Avoid embedding this in build artifacts; see `remapped_path_if_available()` for that.
258 pub fn local_path_if_available(&self) -> &Path {
259 match self {
260 RealFileName::LocalPath(path)
261 | RealFileName::Remapped { local_path: None, virtual_name: path }
262 | RealFileName::Remapped { local_path: Some(path), virtual_name: _ } => path,
263 }
264 }
265
94222f64
XL
266 pub fn to_string_lossy(&self, display_pref: FileNameDisplayPreference) -> Cow<'_, str> {
267 match display_pref {
268 FileNameDisplayPreference::Local => self.local_path_if_available().to_string_lossy(),
269 FileNameDisplayPreference::Remapped => {
270 self.remapped_path_if_available().to_string_lossy()
271 }
9c376795
FG
272 FileNameDisplayPreference::Short => self
273 .local_path_if_available()
274 .file_name()
275 .map_or_else(|| "".into(), |f| f.to_string_lossy()),
ba9703b0
XL
276 }
277 }
278}
279
0731742a 280/// Differentiates between real files and common virtual files.
3dfed10e 281#[derive(Debug, Eq, PartialEq, Clone, Ord, PartialOrd, Hash)]
94222f64 282#[derive(Decodable, Encodable)]
ff7c6d11 283pub enum FileName {
ba9703b0 284 Real(RealFileName),
0731742a
XL
285 /// Call to `quote!`.
286 QuoteExpansion(u64),
287 /// Command line.
288 Anon(u64),
74b04a01 289 /// Hack in `src/librustc_ast/parse.rs`.
0731742a
XL
290 // FIXME(jseyfried)
291 MacroExpansion(u64),
292 ProcMacroSourceCode(u64),
293 /// Strings provided as `--cfg [cfgspec]` stored in a `crate_cfg`.
294 CfgSpec(u64),
295 /// Strings provided as crate attributes in the CLI.
296 CliCrateAttr(u64),
297 /// Custom sources for explicit parser calls from plugins and drivers.
ff7c6d11 298 Custom(String),
0731742a 299 DocTest(PathBuf, isize),
5869c6ff 300 /// Post-substitution inline assembly from LLVM.
f9f354fc 301 InlineAsm(u64),
ff7c6d11
XL
302}
303
17df50a5
XL
304impl From<PathBuf> for FileName {
305 fn from(p: PathBuf) -> Self {
306 assert!(!p.to_string_lossy().ends_with('>'));
307 FileName::Real(RealFileName::LocalPath(p))
308 }
309}
310
94222f64
XL
311#[derive(Clone, Copy, Eq, PartialEq, Hash, Debug)]
312pub enum FileNameDisplayPreference {
2b03887a
FG
313 /// Display the path after the application of rewrite rules provided via `--remap-path-prefix`.
314 /// This is appropriate for paths that get embedded into files produced by the compiler.
94222f64 315 Remapped,
2b03887a
FG
316 /// Display the path before the application of rewrite rules provided via `--remap-path-prefix`.
317 /// This is appropriate for use in user-facing output (such as diagnostics).
94222f64 318 Local,
9c376795
FG
319 /// Display only the filename, as a way to reduce the verbosity of the output.
320 /// This is appropriate for use in user-facing output (such as diagnostics).
321 Short,
94222f64
XL
322}
323
17df50a5
XL
324pub struct FileNameDisplay<'a> {
325 inner: &'a FileName,
94222f64 326 display_pref: FileNameDisplayPreference,
17df50a5
XL
327}
328
329impl fmt::Display for FileNameDisplay<'_> {
9fa01778
XL
330 fn fmt(&self, fmt: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
331 use FileName::*;
17df50a5
XL
332 match *self.inner {
333 Real(ref name) => {
94222f64 334 write!(fmt, "{}", name.to_string_lossy(self.display_pref))
ba9703b0 335 }
0731742a
XL
336 QuoteExpansion(_) => write!(fmt, "<quote expansion>"),
337 MacroExpansion(_) => write!(fmt, "<macro expansion>"),
338 Anon(_) => write!(fmt, "<anon>"),
dfeec247 339 ProcMacroSourceCode(_) => write!(fmt, "<proc-macro source code>"),
0731742a
XL
340 CfgSpec(_) => write!(fmt, "<cfgspec>"),
341 CliCrateAttr(_) => write!(fmt, "<crate attribute>"),
9c376795 342 Custom(ref s) => write!(fmt, "<{s}>"),
0731742a 343 DocTest(ref path, _) => write!(fmt, "{}", path.display()),
f9f354fc 344 InlineAsm(_) => write!(fmt, "<inline asm>"),
ff7c6d11
XL
345 }
346 }
347}
348
923072b8
FG
349impl<'a> FileNameDisplay<'a> {
350 pub fn to_string_lossy(&self) -> Cow<'a, str> {
17df50a5 351 match self.inner {
94222f64 352 FileName::Real(ref inner) => inner.to_string_lossy(self.display_pref),
923072b8 353 _ => Cow::from(self.to_string()),
17df50a5 354 }
ff7c6d11
XL
355 }
356}
357
358impl FileName {
359 pub fn is_real(&self) -> bool {
9fa01778 360 use FileName::*;
ff7c6d11
XL
361 match *self {
362 Real(_) => true,
ba9703b0 363 Anon(_)
dfeec247
XL
364 | MacroExpansion(_)
365 | ProcMacroSourceCode(_)
366 | CfgSpec(_)
367 | CliCrateAttr(_)
368 | Custom(_)
369 | QuoteExpansion(_)
f9f354fc
XL
370 | DocTest(_, _)
371 | InlineAsm(_) => false,
ff7c6d11
XL
372 }
373 }
374
17df50a5 375 pub fn prefer_remapped(&self) -> FileNameDisplay<'_> {
94222f64 376 FileNameDisplay { inner: self, display_pref: FileNameDisplayPreference::Remapped }
17df50a5
XL
377 }
378
487cf647
FG
379 /// This may include transient local filesystem information.
380 /// Must not be embedded in build outputs.
17df50a5 381 pub fn prefer_local(&self) -> FileNameDisplay<'_> {
94222f64
XL
382 FileNameDisplay { inner: self, display_pref: FileNameDisplayPreference::Local }
383 }
384
385 pub fn display(&self, display_pref: FileNameDisplayPreference) -> FileNameDisplay<'_> {
386 FileNameDisplay { inner: self, display_pref }
17df50a5
XL
387 }
388
0731742a
XL
389 pub fn macro_expansion_source_code(src: &str) -> FileName {
390 let mut hasher = StableHasher::new();
391 src.hash(&mut hasher);
392 FileName::MacroExpansion(hasher.finish())
393 }
394
395 pub fn anon_source_code(src: &str) -> FileName {
396 let mut hasher = StableHasher::new();
397 src.hash(&mut hasher);
398 FileName::Anon(hasher.finish())
399 }
400
401 pub fn proc_macro_source_code(src: &str) -> FileName {
402 let mut hasher = StableHasher::new();
403 src.hash(&mut hasher);
404 FileName::ProcMacroSourceCode(hasher.finish())
405 }
406
407 pub fn cfg_spec_source_code(src: &str) -> FileName {
408 let mut hasher = StableHasher::new();
409 src.hash(&mut hasher);
410 FileName::QuoteExpansion(hasher.finish())
411 }
412
413 pub fn cli_crate_attr_source_code(src: &str) -> FileName {
414 let mut hasher = StableHasher::new();
415 src.hash(&mut hasher);
416 FileName::CliCrateAttr(hasher.finish())
417 }
418
dfeec247 419 pub fn doc_test_source_code(path: PathBuf, line: isize) -> FileName {
0731742a
XL
420 FileName::DocTest(path, line)
421 }
f9f354fc
XL
422
423 pub fn inline_asm_source_code(src: &str) -> FileName {
424 let mut hasher = StableHasher::new();
425 src.hash(&mut hasher);
426 FileName::InlineAsm(hasher.finish())
427 }
ff7c6d11 428}
3157f602 429
5869c6ff
XL
430/// Represents a span.
431///
3157f602 432/// Spans represent a region of code, used for error reporting. Positions in spans
5869c6ff
XL
433/// are *absolute* positions from the beginning of the [`SourceMap`], not positions
434/// relative to [`SourceFile`]s. Methods on the `SourceMap` can be used to relate spans back
3157f602 435/// to the original source.
5869c6ff
XL
436///
437/// You must be careful if the span crosses more than one file, since you will not be
b7449926 438/// able to use many of the functions on spans in source_map and you cannot assume
5869c6ff
XL
439/// that the length of the span is equal to `span.hi - span.lo`; there may be space in the
440/// [`BytePos`] range between files.
ea8adc8c
XL
441///
442/// `SpanData` is public because `Span` uses a thread-local interner and can't be
443/// sent to other threads, but some pieces of performance infra run in a separate thread.
444/// Using `Span` is generally preferred.
a2a8927a 445#[derive(Clone, Copy, Hash, PartialEq, Eq)]
ea8adc8c 446pub struct SpanData {
3157f602
XL
447 pub lo: BytePos,
448 pub hi: BytePos,
449 /// Information about where the macro came from, if this piece of
450 /// code was created by a macro expansion.
cc61c64b 451 pub ctxt: SyntaxContext,
c295e0f8 452 pub parent: Option<LocalDefId>,
3157f602
XL
453}
454
a2a8927a
XL
455// Order spans by position in the file.
456impl Ord for SpanData {
457 fn cmp(&self, other: &Self) -> Ordering {
458 let SpanData {
459 lo: s_lo,
460 hi: s_hi,
461 ctxt: s_ctxt,
462 // `LocalDefId` does not implement `Ord`.
463 // The other fields are enough to determine in-file order.
464 parent: _,
465 } = self;
466 let SpanData {
467 lo: o_lo,
468 hi: o_hi,
469 ctxt: o_ctxt,
470 // `LocalDefId` does not implement `Ord`.
471 // The other fields are enough to determine in-file order.
472 parent: _,
473 } = other;
474
475 (s_lo, s_hi, s_ctxt).cmp(&(o_lo, o_hi, o_ctxt))
476 }
477}
478
479impl PartialOrd for SpanData {
480 fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
481 Some(self.cmp(other))
482 }
483}
484
abe05a73 485impl SpanData {
5869c6ff
XL
486 #[inline]
487 pub fn span(&self) -> Span {
c295e0f8 488 Span::new(self.lo, self.hi, self.ctxt, self.parent)
5869c6ff 489 }
abe05a73
XL
490 #[inline]
491 pub fn with_lo(&self, lo: BytePos) -> Span {
c295e0f8 492 Span::new(lo, self.hi, self.ctxt, self.parent)
abe05a73
XL
493 }
494 #[inline]
495 pub fn with_hi(&self, hi: BytePos) -> Span {
c295e0f8 496 Span::new(self.lo, hi, self.ctxt, self.parent)
abe05a73
XL
497 }
498 #[inline]
499 pub fn with_ctxt(&self, ctxt: SyntaxContext) -> Span {
c295e0f8
XL
500 Span::new(self.lo, self.hi, ctxt, self.parent)
501 }
502 #[inline]
503 pub fn with_parent(&self, parent: Option<LocalDefId>) -> Span {
504 Span::new(self.lo, self.hi, self.ctxt, parent)
505 }
506 /// Returns `true` if this is a dummy span with any hygienic context.
507 #[inline]
508 pub fn is_dummy(self) -> bool {
509 self.lo.0 == 0 && self.hi.0 == 0
510 }
9c376795
FG
511 #[inline]
512 pub fn is_visible(self, sm: &SourceMap) -> bool {
513 !self.is_dummy() && sm.is_span_accessible(self.span())
514 }
c295e0f8
XL
515 /// Returns `true` if `self` fully encloses `other`.
516 pub fn contains(self, other: Self) -> bool {
517 self.lo <= other.lo && other.hi <= self.hi
abe05a73
XL
518 }
519}
520
0531ce1d 521// The interner is pointed to by a thread local value which is only set on the main thread
0731742a 522// with parallelization is disabled. So we don't allow `Span` to transfer between threads
0531ce1d 523// to avoid panics and other errors, even though it would be memory safe to do so.
9fa01778 524#[cfg(not(parallel_compiler))]
ea8adc8c 525impl !Send for Span {}
9fa01778 526#[cfg(not(parallel_compiler))]
ea8adc8c
XL
527impl !Sync for Span {}
528
529impl PartialOrd for Span {
530 fn partial_cmp(&self, rhs: &Self) -> Option<Ordering> {
531 PartialOrd::partial_cmp(&self.data(), &rhs.data())
532 }
533}
534impl Ord for Span {
535 fn cmp(&self, rhs: &Self) -> Ordering {
536 Ord::cmp(&self.data(), &rhs.data())
537 }
538}
539
3157f602 540impl Span {
ea8adc8c
XL
541 #[inline]
542 pub fn lo(self) -> BytePos {
543 self.data().lo
544 }
545 #[inline]
546 pub fn with_lo(self, lo: BytePos) -> Span {
abe05a73 547 self.data().with_lo(lo)
ea8adc8c
XL
548 }
549 #[inline]
550 pub fn hi(self) -> BytePos {
551 self.data().hi
552 }
553 #[inline]
554 pub fn with_hi(self, hi: BytePos) -> Span {
abe05a73 555 self.data().with_hi(hi)
ea8adc8c
XL
556 }
557 #[inline]
923072b8
FG
558 pub fn eq_ctxt(self, other: Span) -> bool {
559 self.data_untracked().ctxt == other.data_untracked().ctxt
560 }
ea8adc8c
XL
561 #[inline]
562 pub fn with_ctxt(self, ctxt: SyntaxContext) -> Span {
c295e0f8
XL
563 self.data_untracked().with_ctxt(ctxt)
564 }
565 #[inline]
566 pub fn parent(self) -> Option<LocalDefId> {
567 self.data().parent
568 }
569 #[inline]
570 pub fn with_parent(self, ctxt: Option<LocalDefId>) -> Span {
571 self.data().with_parent(ctxt)
ea8adc8c
XL
572 }
573
8faf50e0
XL
574 /// Returns `true` if this is a dummy span with any hygienic context.
575 #[inline]
576 pub fn is_dummy(self) -> bool {
c295e0f8 577 self.data_untracked().is_dummy()
8faf50e0
XL
578 }
579
9c376795
FG
580 #[inline]
581 pub fn is_visible(self, sm: &SourceMap) -> bool {
582 self.data_untracked().is_visible(sm)
583 }
584
f2b60f7d 585 /// Returns `true` if this span comes from any kind of macro, desugaring or inlining.
e1599b0c
XL
586 #[inline]
587 pub fn from_expansion(self) -> bool {
588 self.ctxt() != SyntaxContext::root()
589 }
590
f2b60f7d
FG
591 /// Returns `true` if `span` originates in a macro's expansion where debuginfo should be
592 /// collapsed.
593 pub fn in_macro_expansion_with_collapse_debuginfo(self) -> bool {
594 let outer_expn = self.ctxt().outer_expn_data();
595 matches!(outer_expn.kind, ExpnKind::Macro(..)) && outer_expn.collapse_debuginfo
596 }
597
598 /// Returns `true` if this span comes from MIR inlining.
599 pub fn is_inlined(self) -> bool {
600 let outer_expn = self.ctxt().outer_expn_data();
601 matches!(outer_expn.kind, ExpnKind::Inlined)
602 }
603
dfeec247
XL
604 /// Returns `true` if `span` originates in a derive-macro's expansion.
605 pub fn in_derive_expansion(self) -> bool {
136023e0 606 matches!(self.ctxt().outer_expn_data().kind, ExpnKind::Macro(MacroKind::Derive, _))
dfeec247
XL
607 }
608
a2a8927a
XL
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 || (matches!(self.ctxt().outer_expn_data().kind, ExpnKind::Macro(MacroKind::Derive, _))
616 && self.parent_callsite().map(|p| (p.lo(), p.hi())) != Some((self.lo(), self.hi())))
617 }
618
e1599b0c
XL
619 #[inline]
620 pub fn with_root_ctxt(lo: BytePos, hi: BytePos) -> Span {
c295e0f8 621 Span::new(lo, hi, SyntaxContext::root(), None)
e1599b0c
XL
622 }
623
5869c6ff 624 /// Returns a new span representing an empty span at the beginning of this span.
0531ce1d
XL
625 #[inline]
626 pub fn shrink_to_lo(self) -> Span {
c295e0f8 627 let span = self.data_untracked();
0531ce1d
XL
628 span.with_hi(span.lo)
629 }
0731742a 630 /// Returns a new span representing an empty span at the end of this span.
0531ce1d
XL
631 #[inline]
632 pub fn shrink_to_hi(self) -> Span {
c295e0f8 633 let span = self.data_untracked();
0531ce1d
XL
634 span.with_lo(span.hi)
635 }
636
1b1a35ee 637 #[inline]
5869c6ff 638 /// Returns `true` if `hi == lo`.
5099ac24 639 pub fn is_empty(self) -> bool {
c295e0f8 640 let span = self.data_untracked();
1b1a35ee
XL
641 span.hi == span.lo
642 }
643
3157f602
XL
644 /// Returns `self` if `self` is not the dummy span, and `other` otherwise.
645 pub fn substitute_dummy(self, other: Span) -> Span {
8faf50e0 646 if self.is_dummy() { other } else { self }
3157f602
XL
647 }
648
9fa01778 649 /// Returns `true` if `self` fully encloses `other`.
3157f602 650 pub fn contains(self, other: Span) -> bool {
abe05a73
XL
651 let span = self.data();
652 let other = other.data();
c295e0f8 653 span.contains(other)
3157f602
XL
654 }
655
9fa01778 656 /// Returns `true` if `self` touches `other`.
0731742a
XL
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
661 }
662
9fa01778 663 /// Returns `true` if the spans are equal with regards to the source text.
3157f602
XL
664 ///
665 /// Use this instead of `==` when either span could be generated code,
666 /// and you only care that they point to the same bytes of source text.
5099ac24 667 pub fn source_equal(self, other: Span) -> bool {
abe05a73
XL
668 let span = self.data();
669 let other = other.data();
670 span.lo == other.lo && span.hi == other.hi
3157f602
XL
671 }
672
0731742a 673 /// Returns `Some(span)`, where the start is trimmed by the end of `other`.
3157f602 674 pub fn trim_start(self, other: Span) -> Option<Span> {
abe05a73
XL
675 let span = self.data();
676 let other = other.data();
dfeec247 677 if span.hi > other.hi { Some(span.with_lo(cmp::max(span.lo, other.hi))) } else { None }
3157f602 678 }
cc61c64b 679
9fa01778 680 /// Returns the source span -- this is either the supplied span, or the span for
cc61c64b
XL
681 /// the macro callsite that expanded to it.
682 pub fn source_callsite(self) -> Span {
e1599b0c
XL
683 let expn_data = self.ctxt().outer_expn_data();
684 if !expn_data.is_root() { expn_data.call_site.source_callsite() } else { self }
cc61c64b
XL
685 }
686
83c7162d 687 /// The `Span` for the tokens in the previous macro expansion from which `self` was generated,
0731742a 688 /// if any.
c295e0f8 689 pub fn parent_callsite(self) -> Option<Span> {
e1599b0c
XL
690 let expn_data = self.ctxt().outer_expn_data();
691 if !expn_data.is_root() { Some(expn_data.call_site) } else { None }
83c7162d
XL
692 }
693
94222f64
XL
694 /// Walk down the expansion ancestors to find a span that's contained within `outer`.
695 pub fn find_ancestor_inside(mut self, outer: Span) -> Option<Span> {
696 while !outer.contains(self) {
c295e0f8 697 self = self.parent_callsite()?;
94222f64
XL
698 }
699 Some(self)
700 }
701
f2b60f7d
FG
702 /// Like `find_ancestor_inside`, but specifically for when spans might not
703 /// overlaps. Take care when using this, and prefer `find_ancestor_inside`
704 /// when you know that the spans are nested (modulo macro expansion).
705 pub fn find_ancestor_in_same_ctxt(mut self, other: Span) -> Option<Span> {
706 while !Span::eq_ctxt(self, other) {
707 self = self.parent_callsite()?;
708 }
709 Some(self)
710 }
711
94b46f34
XL
712 /// Edition of the crate from which this span came.
713 pub fn edition(self) -> edition::Edition {
5869c6ff 714 self.ctxt().edition()
94b46f34
XL
715 }
716
13cf67c4 717 #[inline]
9ffffee4
FG
718 pub fn is_rust_2015(self) -> bool {
719 self.edition().is_rust_2015()
13cf67c4
XL
720 }
721
722 #[inline]
5099ac24 723 pub fn rust_2018(self) -> bool {
9ffffee4 724 self.edition().rust_2018()
13cf67c4
XL
725 }
726
5869c6ff 727 #[inline]
5099ac24 728 pub fn rust_2021(self) -> bool {
9ffffee4 729 self.edition().rust_2021()
5869c6ff
XL
730 }
731
04454e1e
FG
732 #[inline]
733 pub fn rust_2024(self) -> bool {
9ffffee4 734 self.edition().rust_2024()
04454e1e
FG
735 }
736
9fa01778 737 /// Returns the source callee.
cc61c64b 738 ///
8faf50e0 739 /// Returns `None` if the supplied span has no expansion trace,
e1599b0c 740 /// else returns the `ExpnData` for the macro definition
cc61c64b 741 /// corresponding to the source callsite.
e1599b0c
XL
742 pub fn source_callee(self) -> Option<ExpnData> {
743 fn source_callee(expn_data: ExpnData) -> ExpnData {
744 let next_expn_data = expn_data.call_site.ctxt().outer_expn_data();
745 if !next_expn_data.is_root() { source_callee(next_expn_data) } else { expn_data }
cc61c64b 746 }
e1599b0c
XL
747 let expn_data = self.ctxt().outer_expn_data();
748 if !expn_data.is_root() { Some(source_callee(expn_data)) } else { None }
cc61c64b
XL
749 }
750
9fa01778 751 /// Checks if a span is "internal" to a macro in which `#[unstable]`
cc61c64b
XL
752 /// items can be used (that is, a macro marked with
753 /// `#[allow_internal_unstable]`).
5099ac24 754 pub fn allows_unstable(self, feature: Symbol) -> bool {
6a06907d
XL
755 self.ctxt()
756 .outer_expn_data()
757 .allow_internal_unstable
758 .map_or(false, |features| features.iter().any(|&f| f == feature))
cc61c64b
XL
759 }
760
9fa01778 761 /// Checks if this span arises from a compiler desugaring of kind `kind`.
5099ac24 762 pub fn is_desugaring(self, kind: DesugaringKind) -> bool {
e1599b0c
XL
763 match self.ctxt().outer_expn_data().kind {
764 ExpnKind::Desugaring(k) => k == kind,
765 _ => false,
3b2f2976
XL
766 }
767 }
768
9fa01778 769 /// Returns the compiler desugaring that created this span, or `None`
ea8adc8c 770 /// if this span is not from a desugaring.
5099ac24 771 pub fn desugaring_kind(self) -> Option<DesugaringKind> {
e1599b0c
XL
772 match self.ctxt().outer_expn_data().kind {
773 ExpnKind::Desugaring(k) => Some(k),
dfeec247 774 _ => None,
ea8adc8c
XL
775 }
776 }
777
9fa01778 778 /// Checks if a span is "internal" to a macro in which `unsafe`
5869c6ff 779 /// can be used without triggering the `unsafe_code` lint.
487cf647 780 /// (that is, a macro marked with `#[allow_internal_unsafe]`).
5099ac24 781 pub fn allows_unsafe(self) -> bool {
e1599b0c 782 self.ctxt().outer_expn_data().allow_internal_unsafe
3b2f2976
XL
783 }
784
dfeec247 785 pub fn macro_backtrace(mut self) -> impl Iterator<Item = ExpnData> {
cc61c64b 786 let mut prev_span = DUMMY_SP;
dfeec247
XL
787 std::iter::from_fn(move || {
788 loop {
789 let expn_data = self.ctxt().outer_expn_data();
790 if expn_data.is_root() {
791 return None;
792 }
cc61c64b 793
5099ac24 794 let is_recursive = expn_data.call_site.source_equal(prev_span);
dfeec247
XL
795
796 prev_span = self;
797 self = expn_data.call_site;
798
799 // Don't print recursive invocations.
800 if !is_recursive {
801 return Some(expn_data);
802 }
803 }
804 })
cc61c64b
XL
805 }
806
353b0b11
FG
807 /// Splits a span into two composite spans around a certain position.
808 pub fn split_at(self, pos: u32) -> (Span, Span) {
809 let len = self.hi().0 - self.lo().0;
810 debug_assert!(pos <= len);
811
812 let split_pos = BytePos(self.lo().0 + pos);
813 (
814 Span::new(self.lo(), split_pos, self.ctxt(), self.parent()),
815 Span::new(split_pos, self.hi(), self.ctxt(), self.parent()),
816 )
817 }
818
9fa01778 819 /// Returns a `Span` that would enclose both `self` and `end`.
1b1a35ee 820 ///
9c376795
FG
821 /// Note that this can also be used to extend the span "backwards":
822 /// `start.to(end)` and `end.to(start)` return the same `Span`.
823 ///
1b1a35ee
XL
824 /// ```text
825 /// ____ ___
826 /// self lorem ipsum end
827 /// ^^^^^^^^^^^^^^^^^^^^
828 /// ```
cc61c64b 829 pub fn to(self, end: Span) -> Span {
2c00a5a8
XL
830 let span_data = self.data();
831 let end_data = end.data();
0731742a 832 // FIXME(jseyfried): `self.ctxt` should always equal `end.ctxt` here (cf. issue #23480).
2c00a5a8
XL
833 // Return the macro span on its own to avoid weird diagnostic output. It is preferable to
834 // have an incomplete span than a completely nonsensical one.
835 if span_data.ctxt != end_data.ctxt {
e1599b0c 836 if span_data.ctxt == SyntaxContext::root() {
2c00a5a8 837 return end;
e1599b0c 838 } else if end_data.ctxt == SyntaxContext::root() {
2c00a5a8
XL
839 return self;
840 }
0731742a
XL
841 // Both spans fall within a macro.
842 // FIXME(estebank): check if it is the *same* macro.
2c00a5a8 843 }
ea8adc8c 844 Span::new(
2c00a5a8
XL
845 cmp::min(span_data.lo, end_data.lo),
846 cmp::max(span_data.hi, end_data.hi),
e1599b0c 847 if span_data.ctxt == SyntaxContext::root() { end_data.ctxt } else { span_data.ctxt },
c295e0f8 848 if span_data.parent == end_data.parent { span_data.parent } else { None },
ea8adc8c 849 )
cc61c64b
XL
850 }
851
9fa01778 852 /// Returns a `Span` between the end of `self` to the beginning of `end`.
1b1a35ee
XL
853 ///
854 /// ```text
855 /// ____ ___
856 /// self lorem ipsum end
857 /// ^^^^^^^^^^^^^
858 /// ```
cc61c64b 859 pub fn between(self, end: Span) -> Span {
abe05a73
XL
860 let span = self.data();
861 let end = end.data();
ea8adc8c 862 Span::new(
abe05a73
XL
863 span.hi,
864 end.lo,
e1599b0c 865 if end.ctxt == SyntaxContext::root() { end.ctxt } else { span.ctxt },
c295e0f8 866 if span.parent == end.parent { span.parent } else { None },
ea8adc8c 867 )
cc61c64b
XL
868 }
869
1b1a35ee
XL
870 /// Returns a `Span` from the beginning of `self` until the beginning of `end`.
871 ///
872 /// ```text
873 /// ____ ___
874 /// self lorem ipsum end
875 /// ^^^^^^^^^^^^^^^^^
876 /// ```
cc61c64b 877 pub fn until(self, end: Span) -> Span {
c295e0f8
XL
878 // Most of this function's body is copied from `to`.
879 // We can't just do `self.to(end.shrink_to_lo())`,
880 // because to also does some magic where it uses min/max so
881 // it can handle overlapping spans. Some advanced mis-use of
882 // `until` with different ctxts makes this visible.
883 let span_data = self.data();
884 let end_data = end.data();
885 // FIXME(jseyfried): `self.ctxt` should always equal `end.ctxt` here (cf. issue #23480).
886 // Return the macro span on its own to avoid weird diagnostic output. It is preferable to
887 // have an incomplete span than a completely nonsensical one.
888 if span_data.ctxt != end_data.ctxt {
889 if span_data.ctxt == SyntaxContext::root() {
890 return end;
891 } else if end_data.ctxt == SyntaxContext::root() {
892 return self;
893 }
894 // Both spans fall within a macro.
895 // FIXME(estebank): check if it is the *same* macro.
896 }
ea8adc8c 897 Span::new(
c295e0f8
XL
898 span_data.lo,
899 end_data.lo,
900 if end_data.ctxt == SyntaxContext::root() { end_data.ctxt } else { span_data.ctxt },
901 if span_data.parent == end_data.parent { span_data.parent } else { None },
ea8adc8c 902 )
cc61c64b 903 }
83c7162d 904
dc9dc135 905 pub fn from_inner(self, inner: InnerSpan) -> Span {
94b46f34 906 let span = self.data();
dfeec247
XL
907 Span::new(
908 span.lo + BytePos::from_usize(inner.start),
909 span.lo + BytePos::from_usize(inner.end),
910 span.ctxt,
c295e0f8 911 span.parent,
dfeec247 912 )
94b46f34
XL
913 }
914
e1599b0c
XL
915 /// Equivalent of `Span::def_site` from the proc macro API,
916 /// except that the location is taken from the `self` span.
917 pub fn with_def_site_ctxt(self, expn_id: ExpnId) -> Span {
918 self.with_ctxt_from_mark(expn_id, Transparency::Opaque)
919 }
920
921 /// Equivalent of `Span::call_site` from the proc macro API,
922 /// except that the location is taken from the `self` span.
5099ac24 923 pub fn with_call_site_ctxt(self, expn_id: ExpnId) -> Span {
e1599b0c
XL
924 self.with_ctxt_from_mark(expn_id, Transparency::Transparent)
925 }
926
e74abb32
XL
927 /// Equivalent of `Span::mixed_site` from the proc macro API,
928 /// except that the location is taken from the `self` span.
5099ac24 929 pub fn with_mixed_site_ctxt(self, expn_id: ExpnId) -> Span {
e74abb32
XL
930 self.with_ctxt_from_mark(expn_id, Transparency::SemiTransparent)
931 }
932
e1599b0c
XL
933 /// Produces a span with the same location as `self` and context produced by a macro with the
934 /// given ID and transparency, assuming that macro was defined directly and not produced by
935 /// some other macro (which is the case for built-in and procedural macros).
936 pub fn with_ctxt_from_mark(self, expn_id: ExpnId, transparency: Transparency) -> Span {
937 self.with_ctxt(SyntaxContext::root().apply_mark(expn_id, transparency))
938 }
939
83c7162d 940 #[inline]
e1599b0c 941 pub fn apply_mark(self, expn_id: ExpnId, transparency: Transparency) -> Span {
83c7162d 942 let span = self.data();
e1599b0c 943 span.with_ctxt(span.ctxt.apply_mark(expn_id, transparency))
83c7162d
XL
944 }
945
946 #[inline]
416331ca 947 pub fn remove_mark(&mut self) -> ExpnId {
83c7162d
XL
948 let mut span = self.data();
949 let mark = span.ctxt.remove_mark();
c295e0f8 950 *self = Span::new(span.lo, span.hi, span.ctxt, span.parent);
83c7162d
XL
951 mark
952 }
953
954 #[inline]
416331ca 955 pub fn adjust(&mut self, expn_id: ExpnId) -> Option<ExpnId> {
83c7162d 956 let mut span = self.data();
416331ca 957 let mark = span.ctxt.adjust(expn_id);
c295e0f8 958 *self = Span::new(span.lo, span.hi, span.ctxt, span.parent);
83c7162d
XL
959 mark
960 }
961
962 #[inline]
ba9703b0 963 pub fn normalize_to_macros_2_0_and_adjust(&mut self, expn_id: ExpnId) -> Option<ExpnId> {
83c7162d 964 let mut span = self.data();
ba9703b0 965 let mark = span.ctxt.normalize_to_macros_2_0_and_adjust(expn_id);
c295e0f8 966 *self = Span::new(span.lo, span.hi, span.ctxt, span.parent);
83c7162d
XL
967 mark
968 }
969
970 #[inline]
416331ca 971 pub fn glob_adjust(&mut self, expn_id: ExpnId, glob_span: Span) -> Option<Option<ExpnId>> {
dc9dc135 972 let mut span = self.data();
416331ca 973 let mark = span.ctxt.glob_adjust(expn_id, glob_span);
c295e0f8 974 *self = Span::new(span.lo, span.hi, span.ctxt, span.parent);
dc9dc135
XL
975 mark
976 }
977
978 #[inline]
dfeec247
XL
979 pub fn reverse_glob_adjust(
980 &mut self,
981 expn_id: ExpnId,
982 glob_span: Span,
983 ) -> Option<Option<ExpnId>> {
83c7162d 984 let mut span = self.data();
416331ca 985 let mark = span.ctxt.reverse_glob_adjust(expn_id, glob_span);
c295e0f8 986 *self = Span::new(span.lo, span.hi, span.ctxt, span.parent);
83c7162d
XL
987 mark
988 }
989
990 #[inline]
ba9703b0 991 pub fn normalize_to_macros_2_0(self) -> Span {
83c7162d 992 let span = self.data();
ba9703b0 993 span.with_ctxt(span.ctxt.normalize_to_macros_2_0())
83c7162d 994 }
8faf50e0
XL
995
996 #[inline]
ba9703b0 997 pub fn normalize_to_macro_rules(self) -> Span {
8faf50e0 998 let span = self.data();
ba9703b0 999 span.with_ctxt(span.ctxt.normalize_to_macro_rules())
8faf50e0 1000 }
3157f602
XL
1001}
1002
3b2f2976
XL
1003impl Default for Span {
1004 fn default() -> Self {
1005 DUMMY_SP
1006 }
1007}
1008
3dfed10e 1009impl<E: Encoder> Encodable<E> for Span {
923072b8 1010 default fn encode(&self, s: &mut E) {
abe05a73 1011 let span = self.data();
923072b8
FG
1012 span.lo.encode(s);
1013 span.hi.encode(s);
3157f602
XL
1014 }
1015}
3dfed10e 1016impl<D: Decoder> Decodable<D> for Span {
5099ac24 1017 default fn decode(s: &mut D) -> Span {
5e7ed085
FG
1018 let lo = Decodable::decode(s);
1019 let hi = Decodable::decode(s);
3dfed10e 1020
5e7ed085 1021 Span::new(lo, hi, SyntaxContext::root(), None)
3157f602
XL
1022 }
1023}
1024
353b0b11
FG
1025/// Insert `source_map` into the session globals for the duration of the
1026/// closure's execution.
1027pub fn set_source_map<T, F: FnOnce() -> T>(source_map: Lrc<SourceMap>, f: F) -> T {
136023e0 1028 with_session_globals(|session_globals| {
f035d41b
XL
1029 *session_globals.source_map.borrow_mut() = Some(source_map);
1030 });
1031 struct ClearSourceMap;
1032 impl Drop for ClearSourceMap {
1033 fn drop(&mut self) {
136023e0 1034 with_session_globals(|session_globals| {
f035d41b
XL
1035 session_globals.source_map.borrow_mut().take();
1036 });
1037 }
1038 }
1039
1040 let _guard = ClearSourceMap;
1041 f()
1042}
1043
3157f602 1044impl fmt::Debug for Span {
9fa01778 1045 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
353b0b11
FG
1046 // Use the global `SourceMap` to print the span. If that's not
1047 // available, fall back to printing the raw values.
5099ac24
FG
1048 with_session_globals(|session_globals| {
1049 if let Some(source_map) = &*session_globals.source_map.borrow() {
1050 write!(f, "{} ({:?})", source_map.span_to_diagnostic_string(*self), self.ctxt())
1051 } else {
1052 f.debug_struct("Span")
1053 .field("lo", &self.lo())
1054 .field("hi", &self.hi())
1055 .field("ctxt", &self.ctxt())
1056 .finish()
1057 }
1058 })
3157f602
XL
1059 }
1060}
1061
ea8adc8c 1062impl fmt::Debug for SpanData {
9fa01778 1063 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
5099ac24 1064 fmt::Debug::fmt(&Span::new(self.lo, self.hi, self.ctxt, self.parent), f)
ea8adc8c
XL
1065 }
1066}
3157f602 1067
0731742a 1068/// Identifies an offset of a multi-byte character in a `SourceFile`.
3dfed10e 1069#[derive(Copy, Clone, Encodable, Decodable, Eq, PartialEq, Debug)]
3157f602 1070pub struct MultiByteChar {
0731742a 1071 /// The absolute offset of the character in the `SourceMap`.
3157f602 1072 pub pos: BytePos,
0731742a 1073 /// The number of bytes, `>= 2`.
8faf50e0 1074 pub bytes: u8,
3157f602
XL
1075}
1076
0731742a 1077/// Identifies an offset of a non-narrow character in a `SourceFile`.
3dfed10e 1078#[derive(Copy, Clone, Encodable, Decodable, Eq, PartialEq, Debug)]
abe05a73 1079pub enum NonNarrowChar {
0731742a 1080 /// Represents a zero-width character.
abe05a73 1081 ZeroWidth(BytePos),
0731742a 1082 /// Represents a wide (full-width) character.
abe05a73 1083 Wide(BytePos),
0731742a 1084 /// Represents a tab character, represented visually with a width of 4 characters.
ff7c6d11 1085 Tab(BytePos),
abe05a73
XL
1086}
1087
1088impl NonNarrowChar {
1089 fn new(pos: BytePos, width: usize) -> Self {
1090 match width {
1091 0 => NonNarrowChar::ZeroWidth(pos),
1092 2 => NonNarrowChar::Wide(pos),
ff7c6d11 1093 4 => NonNarrowChar::Tab(pos),
9c376795 1094 _ => panic!("width {width} given for non-narrow character"),
abe05a73
XL
1095 }
1096 }
1097
0731742a 1098 /// Returns the absolute offset of the character in the `SourceMap`.
abe05a73
XL
1099 pub fn pos(&self) -> BytePos {
1100 match *self {
dfeec247 1101 NonNarrowChar::ZeroWidth(p) | NonNarrowChar::Wide(p) | NonNarrowChar::Tab(p) => p,
abe05a73
XL
1102 }
1103 }
1104
0731742a 1105 /// Returns the width of the character, 0 (zero-width) or 2 (wide).
abe05a73
XL
1106 pub fn width(&self) -> usize {
1107 match *self {
1108 NonNarrowChar::ZeroWidth(_) => 0,
1109 NonNarrowChar::Wide(_) => 2,
ff7c6d11 1110 NonNarrowChar::Tab(_) => 4,
abe05a73
XL
1111 }
1112 }
1113}
1114
1115impl Add<BytePos> for NonNarrowChar {
1116 type Output = Self;
1117
1118 fn add(self, rhs: BytePos) -> Self {
1119 match self {
1120 NonNarrowChar::ZeroWidth(pos) => NonNarrowChar::ZeroWidth(pos + rhs),
1121 NonNarrowChar::Wide(pos) => NonNarrowChar::Wide(pos + rhs),
ff7c6d11 1122 NonNarrowChar::Tab(pos) => NonNarrowChar::Tab(pos + rhs),
abe05a73
XL
1123 }
1124 }
1125}
1126
1127impl Sub<BytePos> for NonNarrowChar {
1128 type Output = Self;
1129
1130 fn sub(self, rhs: BytePos) -> Self {
1131 match self {
1132 NonNarrowChar::ZeroWidth(pos) => NonNarrowChar::ZeroWidth(pos - rhs),
1133 NonNarrowChar::Wide(pos) => NonNarrowChar::Wide(pos - rhs),
ff7c6d11 1134 NonNarrowChar::Tab(pos) => NonNarrowChar::Tab(pos - rhs),
abe05a73
XL
1135 }
1136 }
1137}
1138
e74abb32 1139/// Identifies an offset of a character that was normalized away from `SourceFile`.
3dfed10e 1140#[derive(Copy, Clone, Encodable, Decodable, Eq, PartialEq, Debug)]
e74abb32
XL
1141pub struct NormalizedPos {
1142 /// The absolute offset of the character in the `SourceMap`.
1143 pub pos: BytePos,
1144 /// The difference between original and normalized string at position.
1145 pub diff: u32,
1146}
1147
ba9703b0 1148#[derive(PartialEq, Eq, Clone, Debug)]
041b39d2 1149pub enum ExternalSource {
ba9703b0
XL
1150 /// No external source has to be loaded, since the `SourceFile` represents a local crate.
1151 Unneeded,
1152 Foreign {
1153 kind: ExternalSourceKind,
f2b60f7d
FG
1154 /// Index of the file inside metadata.
1155 metadata_index: u32,
ba9703b0
XL
1156 },
1157}
1158
1159/// The state of the lazy external source loading mechanism of a `SourceFile`.
1160#[derive(PartialEq, Eq, Clone, Debug)]
1161pub enum ExternalSourceKind {
041b39d2 1162 /// The external source has been loaded already.
ba9703b0 1163 Present(Lrc<String>),
041b39d2
XL
1164 /// No attempt has been made to load the external source.
1165 AbsentOk,
1166 /// A failed attempt has been made to load the external source.
1167 AbsentErr,
041b39d2
XL
1168 Unneeded,
1169}
1170
1171impl ExternalSource {
ba9703b0
XL
1172 pub fn get_source(&self) -> Option<&Lrc<String>> {
1173 match self {
1174 ExternalSource::Foreign { kind: ExternalSourceKind::Present(ref src), .. } => Some(src),
041b39d2
XL
1175 _ => None,
1176 }
1177 }
1178}
1179
dc9dc135
XL
1180#[derive(Debug)]
1181pub struct OffsetOverflowError;
1182
3dfed10e 1183#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Encodable, Decodable)]
04454e1e 1184#[derive(HashStable_Generic)]
ba9703b0
XL
1185pub enum SourceFileHashAlgorithm {
1186 Md5,
1187 Sha1,
29967ef6 1188 Sha256,
ba9703b0
XL
1189}
1190
1191impl FromStr for SourceFileHashAlgorithm {
1192 type Err = ();
1193
1194 fn from_str(s: &str) -> Result<SourceFileHashAlgorithm, ()> {
1195 match s {
1196 "md5" => Ok(SourceFileHashAlgorithm::Md5),
1197 "sha1" => Ok(SourceFileHashAlgorithm::Sha1),
29967ef6 1198 "sha256" => Ok(SourceFileHashAlgorithm::Sha256),
ba9703b0
XL
1199 _ => Err(()),
1200 }
1201 }
1202}
1203
ba9703b0 1204/// The hash of the on-disk source file used for debug info.
923072b8 1205#[derive(Copy, Clone, PartialEq, Eq, Debug, Hash)]
3dfed10e 1206#[derive(HashStable_Generic, Encodable, Decodable)]
ba9703b0
XL
1207pub struct SourceFileHash {
1208 pub kind: SourceFileHashAlgorithm,
29967ef6 1209 value: [u8; 32],
ba9703b0
XL
1210}
1211
1212impl SourceFileHash {
1213 pub fn new(kind: SourceFileHashAlgorithm, src: &str) -> SourceFileHash {
1214 let mut hash = SourceFileHash { kind, value: Default::default() };
1215 let len = hash.hash_len();
1216 let value = &mut hash.value[..len];
1217 let data = src.as_bytes();
1218 match kind {
1219 SourceFileHashAlgorithm::Md5 => {
1220 value.copy_from_slice(&Md5::digest(data));
1221 }
1222 SourceFileHashAlgorithm::Sha1 => {
1223 value.copy_from_slice(&Sha1::digest(data));
1224 }
29967ef6
XL
1225 SourceFileHashAlgorithm::Sha256 => {
1226 value.copy_from_slice(&Sha256::digest(data));
1227 }
ba9703b0
XL
1228 }
1229 hash
1230 }
1231
1232 /// Check if the stored hash matches the hash of the string.
1233 pub fn matches(&self, src: &str) -> bool {
1234 Self::new(self.kind, src) == *self
1235 }
1236
1237 /// The bytes of the hash.
1238 pub fn hash_bytes(&self) -> &[u8] {
1239 let len = self.hash_len();
1240 &self.value[..len]
1241 }
1242
1243 fn hash_len(&self) -> usize {
1244 match self.kind {
1245 SourceFileHashAlgorithm::Md5 => 16,
1246 SourceFileHashAlgorithm::Sha1 => 20,
29967ef6 1247 SourceFileHashAlgorithm::Sha256 => 32,
ba9703b0
XL
1248 }
1249 }
1250}
1251
04454e1e
FG
1252#[derive(HashStable_Generic)]
1253#[derive(Copy, PartialEq, PartialOrd, Clone, Ord, Eq, Hash, Debug, Encodable, Decodable)]
1254pub enum DebuggerVisualizerType {
1255 Natvis,
923072b8 1256 GdbPrettyPrinter,
04454e1e
FG
1257}
1258
1259/// A single debugger visualizer file.
1260#[derive(HashStable_Generic)]
1261#[derive(Clone, Debug, Hash, PartialEq, Eq, PartialOrd, Ord, Encodable, Decodable)]
1262pub struct DebuggerVisualizerFile {
1263 /// The complete debugger visualizer source.
1264 pub src: Arc<[u8]>,
1265 /// Indicates which visualizer type this targets.
1266 pub visualizer_type: DebuggerVisualizerType,
1267}
1268
1269impl DebuggerVisualizerFile {
1270 pub fn new(src: Arc<[u8]>, visualizer_type: DebuggerVisualizerType) -> Self {
1271 DebuggerVisualizerFile { src, visualizer_type }
1272 }
1273}
1274
923072b8
FG
1275#[derive(Clone)]
1276pub enum SourceFileLines {
1277 /// The source file lines, in decoded (random-access) form.
1278 Lines(Vec<BytePos>),
1279
1280 /// The source file lines, in undecoded difference list form.
1281 Diffs(SourceFileDiffs),
1282}
1283
1284impl SourceFileLines {
1285 pub fn is_lines(&self) -> bool {
1286 matches!(self, SourceFileLines::Lines(_))
1287 }
1288}
1289
1290/// The source file lines in difference list form. This matches the form
1291/// used within metadata, which saves space by exploiting the fact that the
1292/// lines list is sorted and individual lines are usually not that long.
1293///
1294/// We read it directly from metadata and only decode it into `Lines` form
1295/// when necessary. This is a significant performance win, especially for
1296/// small crates where very little of `std`'s metadata is used.
1297#[derive(Clone)]
1298pub struct SourceFileDiffs {
1299 /// Position of the first line. Note that this is always encoded as a
1300 /// `BytePos` because it is often much larger than any of the
1301 /// differences.
1302 line_start: BytePos,
1303
1304 /// Always 1, 2, or 4. Always as small as possible, while being big
1305 /// enough to hold the length of the longest line in the source file.
1306 /// The 1 case is by far the most common.
1307 bytes_per_diff: usize,
1308
1309 /// The number of diffs encoded in `raw_diffs`. Always one less than
1310 /// the number of lines in the source file.
1311 num_diffs: usize,
1312
1313 /// The diffs in "raw" form. Each segment of `bytes_per_diff` length
1314 /// encodes one little-endian diff. Note that they aren't LEB128
1315 /// encoded. This makes for much faster decoding. Besides, the
1316 /// bytes_per_diff==1 case is by far the most common, and LEB128
1317 /// encoding has no effect on that case.
1318 raw_diffs: Vec<u8>,
1319}
1320
5869c6ff 1321/// A single source in the [`SourceMap`].
b7449926 1322pub struct SourceFile {
e74abb32 1323 /// The name of the file that the source came from. Source that doesn't
0731742a
XL
1324 /// originate from files has names between angle brackets by convention
1325 /// (e.g., `<anon>`).
3157f602 1326 pub name: FileName,
0731742a 1327 /// The complete source code.
0531ce1d 1328 pub src: Option<Lrc<String>>,
0731742a 1329 /// The source code's hash.
ba9703b0 1330 pub src_hash: SourceFileHash,
041b39d2
XL
1331 /// The external source code (used for external crates, which will have a `None`
1332 /// value as `self.src`.
0531ce1d 1333 pub external_src: Lock<ExternalSource>,
0731742a 1334 /// The start position of this source in the `SourceMap`.
3157f602 1335 pub start_pos: BytePos,
0731742a 1336 /// The end position of this source in the `SourceMap`.
3157f602 1337 pub end_pos: BytePos,
0731742a 1338 /// Locations of lines beginnings in the source code.
923072b8 1339 pub lines: Lock<SourceFileLines>,
0731742a 1340 /// Locations of multi-byte characters in the source code.
8faf50e0 1341 pub multibyte_chars: Vec<MultiByteChar>,
0731742a 1342 /// Width of characters that are not narrow in the source code.
8faf50e0 1343 pub non_narrow_chars: Vec<NonNarrowChar>,
e74abb32
XL
1344 /// Locations of characters removed during normalization.
1345 pub normalized_pos: Vec<NormalizedPos>,
0731742a 1346 /// A hash of the filename, used for speeding up hashing in incremental compilation.
ff7c6d11 1347 pub name_hash: u128,
ba9703b0
XL
1348 /// Indicates which crate this `SourceFile` was imported from.
1349 pub cnum: CrateNum,
3157f602
XL
1350}
1351
353b0b11
FG
1352impl Clone for SourceFile {
1353 fn clone(&self) -> Self {
1354 Self {
1355 name: self.name.clone(),
1356 src: self.src.clone(),
1357 src_hash: self.src_hash,
1358 external_src: Lock::new(self.external_src.borrow().clone()),
1359 start_pos: self.start_pos,
1360 end_pos: self.end_pos,
1361 lines: Lock::new(self.lines.borrow().clone()),
1362 multibyte_chars: self.multibyte_chars.clone(),
1363 non_narrow_chars: self.non_narrow_chars.clone(),
1364 normalized_pos: self.normalized_pos.clone(),
1365 name_hash: self.name_hash,
1366 cnum: self.cnum,
1367 }
1368 }
1369}
1370
3dfed10e 1371impl<S: Encoder> Encodable<S> for SourceFile {
923072b8
FG
1372 fn encode(&self, s: &mut S) {
1373 self.name.encode(s);
1374 self.src_hash.encode(s);
1375 self.start_pos.encode(s);
1376 self.end_pos.encode(s);
1377
1378 // We are always in `Lines` form by the time we reach here.
1379 assert!(self.lines.borrow().is_lines());
1380 self.lines(|lines| {
1381 // Store the length.
1382 s.emit_u32(lines.len() as u32);
1383
1384 // Compute and store the difference list.
1385 if lines.len() != 0 {
1386 let max_line_length = if lines.len() == 1 {
1387 0
1388 } else {
1389 lines
1390 .array_windows()
1391 .map(|&[fst, snd]| snd - fst)
1392 .map(|bp| bp.to_usize())
1393 .max()
1394 .unwrap()
1395 };
1396
1397 let bytes_per_diff: usize = match max_line_length {
1398 0..=0xFF => 1,
1399 0x100..=0xFFFF => 2,
1400 _ => 4,
1401 };
1402
1403 // Encode the number of bytes used per diff.
1404 s.emit_u8(bytes_per_diff as u8);
1405
1406 // Encode the first element.
1407 lines[0].encode(s);
1408
1409 // Encode the difference list.
1410 let diff_iter = lines.array_windows().map(|&[fst, snd]| snd - fst);
1411 let num_diffs = lines.len() - 1;
1412 let mut raw_diffs;
1413 match bytes_per_diff {
1414 1 => {
1415 raw_diffs = Vec::with_capacity(num_diffs);
1416 for diff in diff_iter {
1417 raw_diffs.push(diff.0 as u8);
dfeec247 1418 }
923072b8
FG
1419 }
1420 2 => {
1421 raw_diffs = Vec::with_capacity(bytes_per_diff * num_diffs);
1422 for diff in diff_iter {
1423 raw_diffs.extend_from_slice(&(diff.0 as u16).to_le_bytes());
dfeec247 1424 }
923072b8
FG
1425 }
1426 4 => {
1427 raw_diffs = Vec::with_capacity(bytes_per_diff * num_diffs);
1428 for diff in diff_iter {
9c376795 1429 raw_diffs.extend_from_slice(&(diff.0).to_le_bytes());
dfeec247 1430 }
3157f602 1431 }
923072b8 1432 _ => unreachable!(),
3157f602 1433 }
923072b8
FG
1434 s.emit_raw_bytes(&raw_diffs);
1435 }
1436 });
3157f602 1437
923072b8
FG
1438 self.multibyte_chars.encode(s);
1439 self.non_narrow_chars.encode(s);
1440 self.name_hash.encode(s);
1441 self.normalized_pos.encode(s);
1442 self.cnum.encode(s);
3157f602
XL
1443 }
1444}
1445
3dfed10e 1446impl<D: Decoder> Decodable<D> for SourceFile {
5099ac24 1447 fn decode(d: &mut D) -> SourceFile {
5e7ed085
FG
1448 let name: FileName = Decodable::decode(d);
1449 let src_hash: SourceFileHash = Decodable::decode(d);
1450 let start_pos: BytePos = Decodable::decode(d);
1451 let end_pos: BytePos = Decodable::decode(d);
923072b8 1452 let lines = {
5e7ed085 1453 let num_lines: u32 = Decodable::decode(d);
5e7ed085
FG
1454 if num_lines > 0 {
1455 // Read the number of bytes used per diff.
923072b8 1456 let bytes_per_diff = d.read_u8() as usize;
5e7ed085
FG
1457
1458 // Read the first element.
923072b8
FG
1459 let line_start: BytePos = Decodable::decode(d);
1460
1461 // Read the difference list.
1462 let num_diffs = num_lines as usize - 1;
1463 let raw_diffs = d.read_raw_bytes(bytes_per_diff * num_diffs).to_vec();
1464 SourceFileLines::Diffs(SourceFileDiffs {
1465 line_start,
1466 bytes_per_diff,
1467 num_diffs,
1468 raw_diffs,
1469 })
1470 } else {
1471 SourceFileLines::Lines(vec![])
5099ac24 1472 }
5e7ed085
FG
1473 };
1474 let multibyte_chars: Vec<MultiByteChar> = Decodable::decode(d);
1475 let non_narrow_chars: Vec<NonNarrowChar> = Decodable::decode(d);
1476 let name_hash: u128 = Decodable::decode(d);
1477 let normalized_pos: Vec<NormalizedPos> = Decodable::decode(d);
1478 let cnum: CrateNum = Decodable::decode(d);
1479 SourceFile {
1480 name,
1481 start_pos,
1482 end_pos,
1483 src: None,
1484 src_hash,
1485 // Unused - the metadata decoder will construct
1486 // a new SourceFile, filling in `external_src` properly
1487 external_src: Lock::new(ExternalSource::Unneeded),
923072b8 1488 lines: Lock::new(lines),
5e7ed085
FG
1489 multibyte_chars,
1490 non_narrow_chars,
1491 normalized_pos,
1492 name_hash,
1493 cnum,
1494 }
3157f602
XL
1495 }
1496}
1497
b7449926 1498impl fmt::Debug for SourceFile {
9fa01778 1499 fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
17df50a5 1500 write!(fmt, "SourceFile({:?})", self.name)
3157f602
XL
1501 }
1502}
1503
b7449926 1504impl SourceFile {
dfeec247
XL
1505 pub fn new(
1506 name: FileName,
dfeec247
XL
1507 mut src: String,
1508 start_pos: BytePos,
ba9703b0 1509 hash_kind: SourceFileHashAlgorithm,
74b04a01 1510 ) -> Self {
ba9703b0
XL
1511 // Compute the file hash before any normalization.
1512 let src_hash = SourceFileHash::new(hash_kind, &src);
e74abb32 1513 let normalized_pos = normalize_src(&mut src, start_pos);
041b39d2 1514
ff7c6d11 1515 let name_hash = {
e74abb32 1516 let mut hasher: StableHasher = StableHasher::new();
ff7c6d11 1517 name.hash(&mut hasher);
e74abb32 1518 hasher.finish::<u128>()
ff7c6d11 1519 };
041b39d2 1520 let end_pos = start_pos.to_usize() + src.len();
f035d41b 1521 assert!(end_pos <= u32::MAX as usize);
041b39d2 1522
8faf50e0 1523 let (lines, multibyte_chars, non_narrow_chars) =
a2a8927a 1524 analyze_source_file::analyze_source_file(&src, start_pos);
8faf50e0 1525
74b04a01 1526 SourceFile {
3b2f2976 1527 name,
0531ce1d 1528 src: Some(Lrc::new(src)),
3b2f2976 1529 src_hash,
0531ce1d 1530 external_src: Lock::new(ExternalSource::Unneeded),
3b2f2976 1531 start_pos,
041b39d2 1532 end_pos: Pos::from_usize(end_pos),
923072b8 1533 lines: Lock::new(SourceFileLines::Lines(lines)),
8faf50e0
XL
1534 multibyte_chars,
1535 non_narrow_chars,
e74abb32 1536 normalized_pos,
ff7c6d11 1537 name_hash,
ba9703b0 1538 cnum: LOCAL_CRATE,
74b04a01 1539 }
041b39d2
XL
1540 }
1541
923072b8
FG
1542 pub fn lines<F, R>(&self, f: F) -> R
1543 where
1544 F: FnOnce(&[BytePos]) -> R,
1545 {
1546 let mut guard = self.lines.borrow_mut();
1547 match &*guard {
1548 SourceFileLines::Lines(lines) => f(lines),
1549 SourceFileLines::Diffs(SourceFileDiffs {
1550 mut line_start,
1551 bytes_per_diff,
1552 num_diffs,
1553 raw_diffs,
1554 }) => {
1555 // Convert from "diffs" form to "lines" form.
1556 let num_lines = num_diffs + 1;
1557 let mut lines = Vec::with_capacity(num_lines);
1558 lines.push(line_start);
1559
1560 assert_eq!(*num_diffs, raw_diffs.len() / bytes_per_diff);
1561 match bytes_per_diff {
1562 1 => {
1563 lines.extend(raw_diffs.into_iter().map(|&diff| {
1564 line_start = line_start + BytePos(diff as u32);
1565 line_start
1566 }));
1567 }
1568 2 => {
1569 lines.extend((0..*num_diffs).map(|i| {
1570 let pos = bytes_per_diff * i;
1571 let bytes = [raw_diffs[pos], raw_diffs[pos + 1]];
1572 let diff = u16::from_le_bytes(bytes);
1573 line_start = line_start + BytePos(diff as u32);
1574 line_start
1575 }));
1576 }
1577 4 => {
1578 lines.extend((0..*num_diffs).map(|i| {
1579 let pos = bytes_per_diff * i;
1580 let bytes = [
1581 raw_diffs[pos],
1582 raw_diffs[pos + 1],
1583 raw_diffs[pos + 2],
1584 raw_diffs[pos + 3],
1585 ];
1586 let diff = u32::from_le_bytes(bytes);
1587 line_start = line_start + BytePos(diff);
1588 line_start
1589 }));
1590 }
1591 _ => unreachable!(),
1592 }
1593 let res = f(&lines);
1594 *guard = SourceFileLines::Lines(lines);
1595 res
1596 }
1597 }
1598 }
1599
9fa01778 1600 /// Returns the `BytePos` of the beginning of the current line.
8faf50e0
XL
1601 pub fn line_begin_pos(&self, pos: BytePos) -> BytePos {
1602 let line_index = self.lookup_line(pos).unwrap();
923072b8 1603 self.lines(|lines| lines[line_index])
94b46f34
XL
1604 }
1605
041b39d2
XL
1606 /// Add externally loaded source.
1607 /// If the hash of the input doesn't match or no input is supplied via None,
1608 /// it is interpreted as an error and the corresponding enum variant is set.
1609 /// The return value signifies whether some kind of source is present.
1610 pub fn add_external_src<F>(&self, get_src: F) -> bool
dfeec247
XL
1611 where
1612 F: FnOnce() -> Option<String>,
041b39d2 1613 {
ba9703b0
XL
1614 if matches!(
1615 *self.external_src.borrow(),
1616 ExternalSource::Foreign { kind: ExternalSourceKind::AbsentOk, .. }
1617 ) {
041b39d2
XL
1618 let src = get_src();
1619 let mut external_src = self.external_src.borrow_mut();
0531ce1d 1620 // Check that no-one else have provided the source while we were getting it
ba9703b0
XL
1621 if let ExternalSource::Foreign {
1622 kind: src_kind @ ExternalSourceKind::AbsentOk, ..
1623 } = &mut *external_src
1624 {
1625 if let Some(mut src) = src {
1626 // The src_hash needs to be computed on the pre-normalized src.
1627 if self.src_hash.matches(&src) {
1628 normalize_src(&mut src, BytePos::from_usize(0));
1629 *src_kind = ExternalSourceKind::Present(Lrc::new(src));
0531ce1d
XL
1630 return true;
1631 }
1632 } else {
ba9703b0 1633 *src_kind = ExternalSourceKind::AbsentErr;
041b39d2 1634 }
0531ce1d
XL
1635
1636 false
041b39d2 1637 } else {
0531ce1d 1638 self.src.is_some() || external_src.get_source().is_some()
041b39d2 1639 }
041b39d2
XL
1640 } else {
1641 self.src.is_some() || self.external_src.borrow().get_source().is_some()
1642 }
1643 }
1644
9fa01778 1645 /// Gets a line from the list of pre-computed line-beginnings.
041b39d2 1646 /// The line number here is 0-based.
9fa01778 1647 pub fn get_line(&self, line_number: usize) -> Option<Cow<'_, str>> {
041b39d2
XL
1648 fn get_until_newline(src: &str, begin: usize) -> &str {
1649 // We can't use `lines.get(line_number+1)` because we might
1650 // be parsing when we call this function and thus the current
1651 // line is the last one we have line info for.
1652 let slice = &src[begin..];
1653 match slice.find('\n') {
1654 Some(e) => &slice[..e],
dfeec247 1655 None => slice,
3157f602 1656 }
041b39d2
XL
1657 }
1658
0531ce1d 1659 let begin = {
923072b8
FG
1660 let line = self.lines(|lines| lines.get(line_number).copied())?;
1661 let begin: BytePos = line - self.start_pos;
0531ce1d 1662 begin.to_usize()
041b39d2 1663 };
041b39d2
XL
1664
1665 if let Some(ref src) = self.src {
1666 Some(Cow::from(get_until_newline(src, begin)))
1667 } else if let Some(src) = self.external_src.borrow().get_source() {
1668 Some(Cow::Owned(String::from(get_until_newline(src, begin))))
1669 } else {
1670 None
3157f602
XL
1671 }
1672 }
1673
3157f602 1674 pub fn is_real_file(&self) -> bool {
ff7c6d11 1675 self.name.is_real()
3157f602
XL
1676 }
1677
064997fb 1678 #[inline]
3157f602
XL
1679 pub fn is_imported(&self) -> bool {
1680 self.src.is_none()
1681 }
1682
1683 pub fn count_lines(&self) -> usize {
923072b8 1684 self.lines(|lines| lines.len())
3157f602 1685 }
9e0c209e 1686
9fa01778 1687 /// Finds the line containing the given position. The return value is the
0731742a 1688 /// index into the `lines` array of this `SourceFile`, not the 1-based line
b7449926 1689 /// number. If the source_file is empty or the position is located before the
0731742a 1690 /// first line, `None` is returned.
9e0c209e 1691 pub fn lookup_line(&self, pos: BytePos) -> Option<usize> {
2b03887a 1692 self.lines(|lines| lines.partition_point(|x| x <= &pos).checked_sub(1))
9e0c209e
SL
1693 }
1694
29967ef6
XL
1695 pub fn line_bounds(&self, line_index: usize) -> Range<BytePos> {
1696 if self.is_empty() {
1697 return self.start_pos..self.end_pos;
9e0c209e
SL
1698 }
1699
923072b8
FG
1700 self.lines(|lines| {
1701 assert!(line_index < lines.len());
1702 if line_index == (lines.len() - 1) {
1703 lines[line_index]..self.end_pos
1704 } else {
1705 lines[line_index]..lines[line_index + 1]
1706 }
1707 })
9e0c209e 1708 }
ff7c6d11 1709
29967ef6
XL
1710 /// Returns whether or not the file contains the given `SourceMap` byte
1711 /// position. The position one past the end of the file is considered to be
1712 /// contained by the file. This implies that files for which `is_empty`
1713 /// returns true still contain one byte position according to this function.
ff7c6d11
XL
1714 #[inline]
1715 pub fn contains(&self, byte_pos: BytePos) -> bool {
1716 byte_pos >= self.start_pos && byte_pos <= self.end_pos
1717 }
e74abb32 1718
29967ef6
XL
1719 #[inline]
1720 pub fn is_empty(&self) -> bool {
1721 self.start_pos == self.end_pos
1722 }
1723
e74abb32
XL
1724 /// Calculates the original byte position relative to the start of the file
1725 /// based on the given byte position.
1726 pub fn original_relative_byte_pos(&self, pos: BytePos) -> BytePos {
e74abb32
XL
1727 // Diff before any records is 0. Otherwise use the previously recorded
1728 // diff as that applies to the following characters until a new diff
1729 // is recorded.
dfeec247 1730 let diff = match self.normalized_pos.binary_search_by(|np| np.pos.cmp(&pos)) {
e74abb32
XL
1731 Ok(i) => self.normalized_pos[i].diff,
1732 Err(i) if i == 0 => 0,
dfeec247 1733 Err(i) => self.normalized_pos[i - 1].diff,
e74abb32
XL
1734 };
1735
1736 BytePos::from_u32(pos.0 - self.start_pos.0 + diff)
1737 }
29967ef6
XL
1738
1739 /// Converts an absolute `BytePos` to a `CharPos` relative to the `SourceFile`.
1740 pub fn bytepos_to_file_charpos(&self, bpos: BytePos) -> CharPos {
1741 // The number of extra bytes due to multibyte chars in the `SourceFile`.
1742 let mut total_extra_bytes = 0;
1743
1744 for mbc in self.multibyte_chars.iter() {
1745 debug!("{}-byte char at {:?}", mbc.bytes, mbc.pos);
1746 if mbc.pos < bpos {
1747 // Every character is at least one byte, so we only
1748 // count the actual extra bytes.
1749 total_extra_bytes += mbc.bytes as u32 - 1;
1750 // We should never see a byte position in the middle of a
1751 // character.
1752 assert!(bpos.to_u32() >= mbc.pos.to_u32() + mbc.bytes as u32);
1753 } else {
1754 break;
1755 }
1756 }
1757
1758 assert!(self.start_pos.to_u32() + total_extra_bytes <= bpos.to_u32());
1759 CharPos(bpos.to_usize() - self.start_pos.to_usize() - total_extra_bytes as usize)
1760 }
1761
1762 /// Looks up the file's (1-based) line number and (0-based `CharPos`) column offset, for a
1763 /// given `BytePos`.
1764 pub fn lookup_file_pos(&self, pos: BytePos) -> (usize, CharPos) {
1765 let chpos = self.bytepos_to_file_charpos(pos);
1766 match self.lookup_line(pos) {
1767 Some(a) => {
1768 let line = a + 1; // Line numbers start at 1
923072b8 1769 let linebpos = self.lines(|lines| lines[a]);
29967ef6
XL
1770 let linechpos = self.bytepos_to_file_charpos(linebpos);
1771 let col = chpos - linechpos;
1772 debug!("byte pos {:?} is on the line at byte pos {:?}", pos, linebpos);
1773 debug!("char pos {:?} is on the line at char pos {:?}", chpos, linechpos);
1774 debug!("byte is on line: {}", line);
1775 assert!(chpos >= linechpos);
1776 (line, col)
1777 }
1778 None => (0, chpos),
1779 }
1780 }
1781
1782 /// Looks up the file's (1-based) line number, (0-based `CharPos`) column offset, and (0-based)
1783 /// column offset when displayed, for a given `BytePos`.
1784 pub fn lookup_file_pos_with_col_display(&self, pos: BytePos) -> (usize, CharPos, usize) {
1785 let (line, col_or_chpos) = self.lookup_file_pos(pos);
1786 if line > 0 {
1787 let col = col_or_chpos;
923072b8 1788 let linebpos = self.lines(|lines| lines[line - 1]);
29967ef6
XL
1789 let col_display = {
1790 let start_width_idx = self
1791 .non_narrow_chars
1792 .binary_search_by_key(&linebpos, |x| x.pos())
1793 .unwrap_or_else(|x| x);
1794 let end_width_idx = self
1795 .non_narrow_chars
1796 .binary_search_by_key(&pos, |x| x.pos())
1797 .unwrap_or_else(|x| x);
1798 let special_chars = end_width_idx - start_width_idx;
1799 let non_narrow: usize = self.non_narrow_chars[start_width_idx..end_width_idx]
1800 .iter()
1801 .map(|x| x.width())
1802 .sum();
1803 col.0 - special_chars + non_narrow
1804 };
1805 (line, col, col_display)
1806 } else {
1807 let chpos = col_or_chpos;
1808 let col_display = {
1809 let end_width_idx = self
1810 .non_narrow_chars
1811 .binary_search_by_key(&pos, |x| x.pos())
1812 .unwrap_or_else(|x| x);
1813 let non_narrow: usize =
1814 self.non_narrow_chars[0..end_width_idx].iter().map(|x| x.width()).sum();
1815 chpos.0 - end_width_idx + non_narrow
1816 };
1817 (0, chpos, col_display)
1818 }
1819 }
e74abb32
XL
1820}
1821
1822/// Normalizes the source code and records the normalizations.
1823fn normalize_src(src: &mut String, start_pos: BytePos) -> Vec<NormalizedPos> {
1824 let mut normalized_pos = vec![];
1825 remove_bom(src, &mut normalized_pos);
1826 normalize_newlines(src, &mut normalized_pos);
1827
1828 // Offset all the positions by start_pos to match the final file positions.
1829 for np in &mut normalized_pos {
1830 np.pos.0 += start_pos.0;
1831 }
1832
1833 normalized_pos
3157f602
XL
1834}
1835
9fa01778 1836/// Removes UTF-8 BOM, if any.
e74abb32 1837fn remove_bom(src: &mut String, normalized_pos: &mut Vec<NormalizedPos>) {
29967ef6 1838 if src.starts_with('\u{feff}') {
041b39d2 1839 src.drain(..3);
e74abb32
XL
1840 normalized_pos.push(NormalizedPos { pos: BytePos(0), diff: 3 });
1841 }
1842}
1843
e74abb32
XL
1844/// Replaces `\r\n` with `\n` in-place in `src`.
1845///
5869c6ff 1846/// Returns error if there's a lone `\r` in the string.
e74abb32
XL
1847fn normalize_newlines(src: &mut String, normalized_pos: &mut Vec<NormalizedPos>) {
1848 if !src.as_bytes().contains(&b'\r') {
1849 return;
1850 }
1851
1852 // We replace `\r\n` with `\n` in-place, which doesn't break utf-8 encoding.
1853 // While we *can* call `as_mut_vec` and do surgery on the live string
1854 // directly, let's rather steal the contents of `src`. This makes the code
1855 // safe even if a panic occurs.
1856
1857 let mut buf = std::mem::replace(src, String::new()).into_bytes();
1858 let mut gap_len = 0;
1859 let mut tail = buf.as_mut_slice();
1860 let mut cursor = 0;
1861 let original_gap = normalized_pos.last().map_or(0, |l| l.diff);
1862 loop {
1863 let idx = match find_crlf(&tail[gap_len..]) {
1864 None => tail.len(),
1865 Some(idx) => idx + gap_len,
1866 };
1867 tail.copy_within(gap_len..idx, 0);
1868 tail = &mut tail[idx - gap_len..];
1869 if tail.len() == gap_len {
1870 break;
1871 }
1872 cursor += idx - gap_len;
1873 gap_len += 1;
1874 normalized_pos.push(NormalizedPos {
1875 pos: BytePos::from_usize(cursor + 1),
1876 diff: original_gap + gap_len as u32,
1877 });
1878 }
1879
1880 // Account for removed `\r`.
1881 // After `set_len`, `buf` is guaranteed to contain utf-8 again.
1882 let new_len = buf.len() - gap_len;
1883 unsafe {
1884 buf.set_len(new_len);
1885 *src = String::from_utf8_unchecked(buf);
1886 }
1887
1888 fn find_crlf(src: &[u8]) -> Option<usize> {
1889 let mut search_idx = 0;
1890 while let Some(idx) = find_cr(&src[search_idx..]) {
1891 if src[search_idx..].get(idx + 1) != Some(&b'\n') {
1892 search_idx += idx + 1;
1893 continue;
1894 }
1895 return Some(search_idx + idx);
1896 }
1897 None
1898 }
1899
1900 fn find_cr(src: &[u8]) -> Option<usize> {
1901 src.iter().position(|&b| b == b'\r')
041b39d2
XL
1902 }
1903}
1904
3157f602
XL
1905// _____________________________________________________________________________
1906// Pos, BytePos, CharPos
1907//
1908
1909pub trait Pos {
1910 fn from_usize(n: usize) -> Self;
1911 fn to_usize(&self) -> usize;
8faf50e0
XL
1912 fn from_u32(n: u32) -> Self;
1913 fn to_u32(&self) -> u32;
3157f602
XL
1914}
1915
1b1a35ee
XL
1916macro_rules! impl_pos {
1917 (
1918 $(
1919 $(#[$attr:meta])*
1920 $vis:vis struct $ident:ident($inner_vis:vis $inner_ty:ty);
1921 )*
1922 ) => {
1923 $(
1924 $(#[$attr])*
1925 $vis struct $ident($inner_vis $inner_ty);
1926
1927 impl Pos for $ident {
1928 #[inline(always)]
1929 fn from_usize(n: usize) -> $ident {
1930 $ident(n as $inner_ty)
1931 }
3157f602 1932
1b1a35ee
XL
1933 #[inline(always)]
1934 fn to_usize(&self) -> usize {
1935 self.0 as usize
1936 }
3157f602 1937
1b1a35ee
XL
1938 #[inline(always)]
1939 fn from_u32(n: u32) -> $ident {
1940 $ident(n as $inner_ty)
1941 }
83c7162d 1942
1b1a35ee
XL
1943 #[inline(always)]
1944 fn to_u32(&self) -> u32 {
1945 self.0 as u32
1946 }
1947 }
8faf50e0 1948
1b1a35ee
XL
1949 impl Add for $ident {
1950 type Output = $ident;
8faf50e0 1951
1b1a35ee
XL
1952 #[inline(always)]
1953 fn add(self, rhs: $ident) -> $ident {
1954 $ident(self.0 + rhs.0)
1955 }
1956 }
3157f602 1957
1b1a35ee
XL
1958 impl Sub for $ident {
1959 type Output = $ident;
3157f602 1960
1b1a35ee
XL
1961 #[inline(always)]
1962 fn sub(self, rhs: $ident) -> $ident {
1963 $ident(self.0 - rhs.0)
1964 }
1965 }
1966 )*
1967 };
3157f602
XL
1968}
1969
1b1a35ee 1970impl_pos! {
5869c6ff
XL
1971 /// A byte offset.
1972 ///
1973 /// Keep this small (currently 32-bits), as AST contains a lot of them.
1b1a35ee
XL
1974 #[derive(Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord, Debug)]
1975 pub struct BytePos(pub u32);
1976
5869c6ff
XL
1977 /// A character offset.
1978 ///
1979 /// Because of multibyte UTF-8 characters, a byte offset
1980 /// is not equivalent to a character offset. The [`SourceMap`] will convert [`BytePos`]
1b1a35ee
XL
1981 /// values to `CharPos` values as necessary.
1982 #[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Debug)]
1983 pub struct CharPos(pub usize);
3157f602
XL
1984}
1985
923072b8
FG
1986impl<S: Encoder> Encodable<S> for BytePos {
1987 fn encode(&self, s: &mut S) {
1988 s.emit_u32(self.0);
3157f602
XL
1989 }
1990}
1991
923072b8 1992impl<D: Decoder> Decodable<D> for BytePos {
5099ac24
FG
1993 fn decode(d: &mut D) -> BytePos {
1994 BytePos(d.read_u32())
3157f602
XL
1995 }
1996}
1997
3157f602 1998// _____________________________________________________________________________
48663c56 1999// Loc, SourceFileAndLine, SourceFileAndBytePos
3157f602
XL
2000//
2001
0731742a 2002/// A source code location used for error reporting.
5bcae85e 2003#[derive(Debug, Clone)]
3157f602 2004pub struct Loc {
0731742a 2005 /// Information about the original source.
b7449926 2006 pub file: Lrc<SourceFile>,
0731742a 2007 /// The (1-based) line number.
3157f602 2008 pub line: usize,
0731742a 2009 /// The (0-based) column offset.
abe05a73 2010 pub col: CharPos,
0731742a 2011 /// The (0-based) column offset when displayed.
abe05a73 2012 pub col_display: usize,
3157f602
XL
2013}
2014
0731742a 2015// Used to be structural records.
3157f602 2016#[derive(Debug)]
dfeec247
XL
2017pub struct SourceFileAndLine {
2018 pub sf: Lrc<SourceFile>,
3c0e092e 2019 /// Index of line, starting from 0.
dfeec247
XL
2020 pub line: usize,
2021}
3157f602 2022#[derive(Debug)]
dfeec247
XL
2023pub struct SourceFileAndBytePos {
2024 pub sf: Lrc<SourceFile>,
2025 pub pos: BytePos,
2026}
3157f602
XL
2027
2028#[derive(Copy, Clone, Debug, PartialEq, Eq)]
2029pub struct LineInfo {
2030 /// Index of line, starting from 0.
2031 pub line_index: usize,
2032
2033 /// Column in line where span begins, starting from 0.
2034 pub start_col: CharPos,
2035
2036 /// Column in line where span ends, starting from 0, exclusive.
2037 pub end_col: CharPos,
2038}
2039
2040pub struct FileLines {
b7449926 2041 pub file: Lrc<SourceFile>,
dfeec247 2042 pub lines: Vec<LineInfo>,
3157f602
XL
2043}
2044
c295e0f8 2045pub static SPAN_TRACK: AtomicRef<fn(LocalDefId)> = AtomicRef::new(&((|_| {}) as fn(_)));
3157f602
XL
2046
2047// _____________________________________________________________________________
a1dfa0c6 2048// SpanLinesError, SpanSnippetError, DistinctSources, MalformedSourceMapPositions
3157f602
XL
2049//
2050
2051pub type FileLinesResult = Result<FileLines, SpanLinesError>;
2052
2053#[derive(Clone, PartialEq, Eq, Debug)]
2054pub enum SpanLinesError {
353b0b11 2055 DistinctSources(Box<DistinctSources>),
3157f602
XL
2056}
2057
2058#[derive(Clone, PartialEq, Eq, Debug)]
2059pub enum SpanSnippetError {
2060 IllFormedSpan(Span),
353b0b11 2061 DistinctSources(Box<DistinctSources>),
a1dfa0c6 2062 MalformedForSourcemap(MalformedSourceMapPositions),
dfeec247 2063 SourceNotAvailable { filename: FileName },
3157f602
XL
2064}
2065
2066#[derive(Clone, PartialEq, Eq, Debug)]
2067pub struct DistinctSources {
ff7c6d11 2068 pub begin: (FileName, BytePos),
dfeec247 2069 pub end: (FileName, BytePos),
3157f602
XL
2070}
2071
2072#[derive(Clone, PartialEq, Eq, Debug)]
a1dfa0c6 2073pub struct MalformedSourceMapPositions {
ff7c6d11 2074 pub name: FileName,
3157f602
XL
2075 pub source_len: usize,
2076 pub begin_pos: BytePos,
dfeec247 2077 pub end_pos: BytePos,
3157f602
XL
2078}
2079
416331ca 2080/// Range inside of a `Span` used for diagnostics when we only have access to relative positions.
dc9dc135
XL
2081#[derive(Copy, Clone, PartialEq, Eq, Debug)]
2082pub struct InnerSpan {
2083 pub start: usize,
2084 pub end: usize,
2085}
2086
2087impl InnerSpan {
2088 pub fn new(start: usize, end: usize) -> InnerSpan {
2089 InnerSpan { start, end }
2090 }
2091}
2092
60c5eb7d 2093/// Requirements for a `StableHashingContext` to be used in this crate.
5869c6ff
XL
2094///
2095/// This is a hack to allow using the [`HashStable_Generic`] derive macro
2096/// instead of implementing everything in rustc_middle.
60c5eb7d 2097pub trait HashStableContext {
136023e0 2098 fn def_path_hash(&self, def_id: DefId) -> DefPathHash;
3dfed10e 2099 fn hash_spans(&self) -> bool;
064997fb 2100 /// Accesses `sess.opts.unstable_opts.incremental_ignore_spans` since
5099ac24 2101 /// we don't have easy access to a `Session`
064997fb 2102 fn unstable_opts_incremental_ignore_spans(&self) -> bool;
c295e0f8 2103 fn def_span(&self, def_id: LocalDefId) -> Span;
5869c6ff
XL
2104 fn span_data_to_lines_and_cols(
2105 &mut self,
2106 span: &SpanData,
2107 ) -> Option<(Lrc<SourceFile>, usize, BytePos, usize, BytePos)>;
5099ac24 2108 fn hashing_controls(&self) -> HashingControls;
60c5eb7d
XL
2109}
2110
2111impl<CTX> HashStable<CTX> for Span
dfeec247
XL
2112where
2113 CTX: HashStableContext,
60c5eb7d
XL
2114{
2115 /// Hashes a span in a stable way. We can't directly hash the span's `BytePos`
2116 /// fields (that would be similar to hashing pointers, since those are just
2117 /// offsets into the `SourceMap`). Instead, we hash the (file name, line, column)
2118 /// triple, which stays the same even if the containing `SourceFile` has moved
2119 /// within the `SourceMap`.
5869c6ff 2120 ///
60c5eb7d
XL
2121 /// Also note that we are hashing byte offsets for the column, not unicode
2122 /// codepoint offsets. For the purpose of the hash that's sufficient.
2123 /// Also, hashing filenames is expensive so we avoid doing it twice when the
2124 /// span starts and ends in the same file, which is almost always the case.
2125 fn hash_stable(&self, ctx: &mut CTX, hasher: &mut StableHasher) {
2126 const TAG_VALID_SPAN: u8 = 0;
2127 const TAG_INVALID_SPAN: u8 = 1;
c295e0f8 2128 const TAG_RELATIVE_SPAN: u8 = 2;
60c5eb7d
XL
2129
2130 if !ctx.hash_spans() {
dfeec247 2131 return;
60c5eb7d
XL
2132 }
2133
c295e0f8
XL
2134 let span = self.data_untracked();
2135 span.ctxt.hash_stable(ctx, hasher);
2136 span.parent.hash_stable(ctx, hasher);
6a06907d 2137
c295e0f8 2138 if span.is_dummy() {
29967ef6 2139 Hash::hash(&TAG_INVALID_SPAN, hasher);
3dfed10e 2140 return;
60c5eb7d
XL
2141 }
2142
c295e0f8
XL
2143 if let Some(parent) = span.parent {
2144 let def_span = ctx.def_span(parent).data_untracked();
2145 if def_span.contains(span) {
2146 // This span is enclosed in a definition: only hash the relative position.
2147 Hash::hash(&TAG_RELATIVE_SPAN, hasher);
2148 (span.lo - def_span.lo).to_u32().hash_stable(ctx, hasher);
2149 (span.hi - def_span.lo).to_u32().hash_stable(ctx, hasher);
2150 return;
2151 }
2152 }
2153
60c5eb7d
XL
2154 // If this is not an empty or invalid span, we want to hash the last
2155 // position that belongs to it, as opposed to hashing the first
2156 // position past it.
5e7ed085
FG
2157 let Some((file, line_lo, col_lo, line_hi, col_hi)) = ctx.span_data_to_lines_and_cols(&span) else {
2158 Hash::hash(&TAG_INVALID_SPAN, hasher);
2159 return;
29967ef6
XL
2160 };
2161
2162 Hash::hash(&TAG_VALID_SPAN, hasher);
60c5eb7d
XL
2163 // We truncate the stable ID hash and line and column numbers. The chances
2164 // of causing a collision this way should be minimal.
5869c6ff 2165 Hash::hash(&(file.name_hash as u64), hasher);
29967ef6
XL
2166
2167 // Hash both the length and the end location (line/column) of a span. If we
2168 // hash only the length, for example, then two otherwise equal spans with
2169 // different end locations will have the same hash. This can cause a problem
2170 // during incremental compilation wherein a previous result for a query that
2171 // depends on the end location of a span will be incorrectly reused when the
2172 // end location of the span it depends on has changed (see issue #74890). A
2173 // similar analysis applies if some query depends specifically on the length
2174 // of the span, but we only hash the end location. So hash both.
2175
2176 let col_lo_trunc = (col_lo.0 as u64) & 0xFF;
2177 let line_lo_trunc = ((line_lo as u64) & 0xFF_FF_FF) << 8;
2178 let col_hi_trunc = (col_hi.0 as u64) & 0xFF << 32;
2179 let line_hi_trunc = ((line_hi as u64) & 0xFF_FF_FF) << 40;
2180 let col_line = col_lo_trunc | line_lo_trunc | col_hi_trunc | line_hi_trunc;
2181 let len = (span.hi - span.lo).0;
2182 Hash::hash(&col_line, hasher);
2183 Hash::hash(&len, hasher);
3dfed10e
XL
2184 }
2185}
9ffffee4
FG
2186
2187/// Useful type to use with `Result<>` indicate that an error has already
2188/// been reported to the user, so no need to continue checking.
2189#[derive(Clone, Copy, Debug, Encodable, Decodable, Hash, PartialEq, Eq, PartialOrd, Ord)]
2190#[derive(HashStable_Generic)]
2191pub struct ErrorGuaranteed(());
2192
2193impl ErrorGuaranteed {
2194 /// To be used only if you really know what you are doing... ideally, we would find a way to
2195 /// eliminate all calls to this method.
2196 pub fn unchecked_claim_error_was_emitted() -> Self {
2197 ErrorGuaranteed(())
2198 }
2199}