2020-12-24 01:01:03 -06:00
|
|
|
//! Source positions and related helper functions.
|
|
|
|
//!
|
|
|
|
//! Important concepts in this module include:
|
|
|
|
//!
|
|
|
|
//! - the *span*, represented by [`SpanData`] and related types;
|
|
|
|
//! - source code as represented by a [`SourceMap`]; and
|
|
|
|
//! - interned strings, represented by [`Symbol`]s, with some common symbols available statically in the [`sym`] module.
|
|
|
|
//!
|
|
|
|
//! Unlike most compilers, the span contains not only the position in the source code, but also various other metadata,
|
|
|
|
//! such as the edition and macro hygiene. This metadata is stored in [`SyntaxContext`] and [`ExpnData`].
|
2016-06-21 17:08:13 -05:00
|
|
|
//!
|
2018-11-26 20:59:49 -06:00
|
|
|
//! ## Note
|
2016-06-21 17:08:13 -05:00
|
|
|
//!
|
|
|
|
//! This API is completely unstable and subject to change.
|
|
|
|
|
2020-09-23 14:51:56 -05:00
|
|
|
#![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")]
|
2020-09-17 02:28:14 -05:00
|
|
|
#![feature(array_windows)]
|
2022-02-18 17:48:49 -06:00
|
|
|
#![feature(let_else)]
|
2021-08-16 10:29:49 -05:00
|
|
|
#![feature(if_let_guard)]
|
2020-04-22 14:45:35 -05:00
|
|
|
#![feature(negative_impls)]
|
2020-05-09 06:59:21 -05:00
|
|
|
#![feature(min_specialization)]
|
2022-02-23 07:11:17 -06:00
|
|
|
#![feature(rustc_attrs)]
|
2016-06-21 17:08:13 -05:00
|
|
|
|
2020-06-11 09:49:57 -05:00
|
|
|
#[macro_use]
|
2020-05-07 23:13:50 -05:00
|
|
|
extern crate rustc_macros;
|
|
|
|
|
2021-09-20 10:24:47 -05:00
|
|
|
#[macro_use]
|
|
|
|
extern crate tracing;
|
|
|
|
|
2019-12-25 12:38:57 -06:00
|
|
|
use rustc_data_structures::AtomicRef;
|
2019-11-09 15:25:30 -06:00
|
|
|
use rustc_macros::HashStable_Generic;
|
2019-07-23 10:50:47 -05:00
|
|
|
use rustc_serialize::{Decodable, Decoder, Encodable, Encoder};
|
2016-06-21 17:08:13 -05:00
|
|
|
|
2019-11-23 07:17:37 -06:00
|
|
|
mod caching_source_map_view;
|
2019-11-15 07:27:09 -06:00
|
|
|
pub mod source_map;
|
2019-11-23 07:17:37 -06:00
|
|
|
pub use self::caching_source_map_view::CachingSourceMapView;
|
2020-05-26 12:21:58 -05:00
|
|
|
use source_map::SourceMap;
|
2019-11-15 07:27:09 -06:00
|
|
|
|
2018-04-22 17:44:19 -05:00
|
|
|
pub mod edition;
|
2019-04-05 17:15:49 -05:00
|
|
|
use edition::Edition;
|
2017-03-16 05:23:33 -05:00
|
|
|
pub mod hygiene;
|
2020-08-04 02:16:01 -05:00
|
|
|
use hygiene::Transparency;
|
2021-10-25 23:33:12 -05:00
|
|
|
pub use hygiene::{DesugaringKind, ExpnKind, MacroKind};
|
2021-07-10 16:34:41 -05:00
|
|
|
pub use hygiene::{ExpnData, ExpnHash, ExpnId, LocalExpnId, SyntaxContext};
|
2021-12-24 15:36:33 -06:00
|
|
|
use rustc_data_structures::stable_hasher::HashingControls;
|
2020-02-08 14:06:31 -06:00
|
|
|
pub mod def_id;
|
2021-04-18 07:27:04 -05:00
|
|
|
use def_id::{CrateNum, DefId, DefPathHash, LocalDefId, LOCAL_CRATE};
|
Move lev_distance to rustc_ast, make non-generic
rustc_ast currently has a few dependencies on rustc_lexer. Ideally, an AST
would not have any dependency its lexer, for minimizing unnecessarily
design-time dependencies. Breaking this dependency would also have practical
benefits, since modifying rustc_lexer would not trigger a rebuild of rustc_ast.
This commit does not remove the rustc_ast --> rustc_lexer dependency,
but it does remove one of the sources of this dependency, which is the
code that handles fuzzy matching between symbol names for making suggestions
in diagnostics. Since that code depends only on Symbol, it is easy to move
it to rustc_span. It might even be best to move it to a separate crate,
since other tools such as Cargo use the same algorithm, and have simply
contain a duplicate of the code.
This changes the signature of find_best_match_for_name so that it is no
longer generic over its input. I checked the optimized binaries, and this
function was duplicated at nearly every call site, because most call sites
used short-lived iterator chains, generic over Map and such. But there's
no good reason for a function like this to be generic, since all it does
is immediately convert the generic input (the Iterator impl) to a concrete
Vec<Symbol>. This has all of the costs of generics (duplicated method bodies)
with no benefit.
Changing find_best_match_for_name to be non-generic removed about 10KB of
code from the optimized binary. I know it's a drop in the bucket, but we have
to start reducing binary size, and beginning to tame over-use of generics
is part of that.
2020-11-12 13:24:10 -06:00
|
|
|
pub mod lev_distance;
|
2017-09-16 13:43:05 -05:00
|
|
|
mod span_encoding;
|
|
|
|
pub use span_encoding::{Span, DUMMY_SP};
|
|
|
|
|
2017-03-16 23:04:41 -05:00
|
|
|
pub mod symbol;
|
2019-05-07 22:21:18 -05:00
|
|
|
pub use symbol::{sym, Symbol};
|
2017-03-16 05:23:33 -05:00
|
|
|
|
2018-08-18 05:13:56 -05:00
|
|
|
mod analyze_source_file;
|
2019-11-14 13:01:03 -06:00
|
|
|
pub mod fatal_error;
|
2018-05-29 10:50:13 -05:00
|
|
|
|
2022-04-01 13:59:23 -05:00
|
|
|
pub mod profiling;
|
|
|
|
|
2019-11-10 10:31:21 -06:00
|
|
|
use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
|
2018-11-26 20:59:49 -06:00
|
|
|
use rustc_data_structures::sync::{Lock, Lrc};
|
|
|
|
|
|
|
|
use std::borrow::Cow;
|
|
|
|
use std::cmp::{self, Ordering};
|
|
|
|
use std::fmt;
|
2020-03-31 00:17:15 -05:00
|
|
|
use std::hash::Hash;
|
2020-10-27 17:47:29 -05:00
|
|
|
use std::ops::{Add, Range, Sub};
|
2020-05-29 10:31:55 -05:00
|
|
|
use std::path::{Path, PathBuf};
|
2020-03-31 00:17:15 -05:00
|
|
|
use std::str::FromStr;
|
2022-04-25 20:02:43 -05:00
|
|
|
use std::sync::Arc;
|
2020-03-31 00:17:15 -05:00
|
|
|
|
2022-02-10 10:54:01 -06:00
|
|
|
use md5::Digest;
|
2020-03-31 00:17:15 -05:00
|
|
|
use md5::Md5;
|
|
|
|
use sha1::Sha1;
|
2020-10-13 10:41:06 -05:00
|
|
|
use sha2::Sha256;
|
2018-11-26 20:59:49 -06:00
|
|
|
|
Updates to experimental coverage counter injection
This is a combination of 18 commits.
Commit #2:
Additional examples and some small improvements.
Commit #3:
fixed mir-opt non-mir extensions and spanview title elements
Corrected a fairly recent assumption in runtest.rs that all MIR dump
files end in .mir. (It was appending .mir to the graphviz .dot and
spanview .html file names when generating blessed output files. That
also left outdated files in the baseline alongside the files with the
incorrect names, which I've now removed.)
Updated spanview HTML title elements to match their content, replacing a
hardcoded and incorrect name that was left in accidentally when
originally submitted.
Commit #4:
added more test examples
also improved Makefiles with support for non-zero exit status and to
force validation of tests unless a specific test overrides it with a
specific comment.
Commit #5:
Fixed rare issues after testing on real-world crate
Commit #6:
Addressed PR feedback, and removed temporary -Zexperimental-coverage
-Zinstrument-coverage once again supports the latest capabilities of
LLVM instrprof coverage instrumentation.
Also fixed a bug in spanview.
Commit #7:
Fix closure handling, add tests for closures and inner items
And cleaned up other tests for consistency, and to make it more clear
where spans start/end by breaking up lines.
Commit #8:
renamed "typical" test results "expected"
Now that the `llvm-cov show` tests are improved to normally expect
matching actuals, and to allow individual tests to override that
expectation.
Commit #9:
test coverage of inline generic struct function
Commit #10:
Addressed review feedback
* Removed unnecessary Unreachable filter.
* Replaced a match wildcard with remining variants.
* Added more comments to help clarify the role of successors() in the
CFG traversal
Commit #11:
refactoring based on feedback
* refactored `fn coverage_spans()`.
* changed the way I expand an empty coverage span to improve performance
* fixed a typo that I had accidently left in, in visit.rs
Commit #12:
Optimized use of SourceMap and SourceFile
Commit #13:
Fixed a regression, and synched with upstream
Some generated test file names changed due to some new change upstream.
Commit #14:
Stripping out crate disambiguators from demangled names
These can vary depending on the test platform.
Commit #15:
Ignore llvm-cov show diff on test with generics, expand IO error message
Tests with generics produce llvm-cov show results with demangled names
that can include an unstable "crate disambiguator" (hex value). The
value changes when run in the Rust CI Windows environment. I added a sed
filter to strip them out (in a prior commit), but sed also appears to
fail in the same environment. Until I can figure out a workaround, I'm
just going to ignore this specific test result. I added a FIXME to
follow up later, but it's not that critical.
I also saw an error with Windows GNU, but the IO error did not
specify a path for the directory or file that triggered the error. I
updated the error messages to provide more info for next, time but also
noticed some other tests with similar steps did not fail. Looks
spurious.
Commit #16:
Modify rust-demangler to strip disambiguators by default
Commit #17:
Remove std::process::exit from coverage tests
Due to Issue #77553, programs that call std::process::exit() do not
generate coverage results on Windows MSVC.
Commit #18:
fix: test file paths exceeding Windows max path len
2020-09-01 18:15:17 -05:00
|
|
|
use tracing::debug;
|
|
|
|
|
2019-07-31 19:20:23 -05:00
|
|
|
#[cfg(test)]
|
|
|
|
mod tests;
|
|
|
|
|
2020-07-05 19:53:14 -05:00
|
|
|
// Per-session global variables: this struct is stored in thread-local storage
|
|
|
|
// in such a way that it is accessible without any kind of handle to all
|
|
|
|
// threads within the compilation session, but is not accessible outside the
|
|
|
|
// session.
|
|
|
|
pub struct SessionGlobals {
|
2021-09-15 11:33:41 -05:00
|
|
|
symbol_interner: symbol::Interner,
|
2018-03-06 19:44:10 -06:00
|
|
|
span_interner: Lock<span_encoding::SpanInterner>,
|
|
|
|
hygiene_data: Lock<hygiene::HygieneData>,
|
2020-05-26 12:21:58 -05:00
|
|
|
source_map: Lock<Option<Lrc<SourceMap>>>,
|
2018-03-06 19:44:10 -06:00
|
|
|
}
|
|
|
|
|
2020-07-05 19:53:14 -05:00
|
|
|
impl SessionGlobals {
|
|
|
|
pub fn new(edition: Edition) -> SessionGlobals {
|
|
|
|
SessionGlobals {
|
2021-09-15 11:33:41 -05:00
|
|
|
symbol_interner: symbol::Interner::fresh(),
|
2018-03-06 19:44:10 -06:00
|
|
|
span_interner: Lock::new(span_encoding::SpanInterner::default()),
|
2019-07-07 08:45:41 -05:00
|
|
|
hygiene_data: Lock::new(hygiene::HygieneData::new(edition)),
|
2020-05-26 12:21:58 -05:00
|
|
|
source_map: Lock::new(None),
|
2018-03-06 19:44:10 -06:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-05-05 14:31:25 -05:00
|
|
|
#[inline]
|
|
|
|
pub fn create_session_globals_then<R>(edition: Edition, f: impl FnOnce() -> R) -> R {
|
|
|
|
assert!(
|
|
|
|
!SESSION_GLOBALS.is_set(),
|
|
|
|
"SESSION_GLOBALS should never be overwritten! \
|
|
|
|
Use another thread if you need another SessionGlobals"
|
|
|
|
);
|
2020-07-29 20:27:50 -05:00
|
|
|
let session_globals = SessionGlobals::new(edition);
|
|
|
|
SESSION_GLOBALS.set(&session_globals, f)
|
|
|
|
}
|
|
|
|
|
2021-05-05 14:31:25 -05:00
|
|
|
#[inline]
|
|
|
|
pub fn set_session_globals_then<R>(session_globals: &SessionGlobals, f: impl FnOnce() -> R) -> R {
|
|
|
|
assert!(
|
|
|
|
!SESSION_GLOBALS.is_set(),
|
|
|
|
"SESSION_GLOBALS should never be overwritten! \
|
|
|
|
Use another thread if you need another SessionGlobals"
|
|
|
|
);
|
|
|
|
SESSION_GLOBALS.set(session_globals, f)
|
|
|
|
}
|
|
|
|
|
|
|
|
#[inline]
|
|
|
|
pub fn create_default_session_if_not_set_then<R, F>(f: F) -> R
|
|
|
|
where
|
|
|
|
F: FnOnce(&SessionGlobals) -> R,
|
|
|
|
{
|
|
|
|
create_session_if_not_set_then(edition::DEFAULT_EDITION, f)
|
|
|
|
}
|
|
|
|
|
|
|
|
#[inline]
|
|
|
|
pub fn create_session_if_not_set_then<R, F>(edition: Edition, f: F) -> R
|
|
|
|
where
|
|
|
|
F: FnOnce(&SessionGlobals) -> R,
|
|
|
|
{
|
|
|
|
if !SESSION_GLOBALS.is_set() {
|
|
|
|
let session_globals = SessionGlobals::new(edition);
|
|
|
|
SESSION_GLOBALS.set(&session_globals, || SESSION_GLOBALS.with(f))
|
|
|
|
} else {
|
|
|
|
SESSION_GLOBALS.with(f)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#[inline]
|
|
|
|
pub fn with_session_globals<R, F>(f: F) -> R
|
|
|
|
where
|
|
|
|
F: FnOnce(&SessionGlobals) -> R,
|
|
|
|
{
|
|
|
|
SESSION_GLOBALS.with(f)
|
|
|
|
}
|
|
|
|
|
|
|
|
#[inline]
|
|
|
|
pub fn create_default_session_globals_then<R>(f: impl FnOnce() -> R) -> R {
|
|
|
|
create_session_globals_then(edition::DEFAULT_EDITION, f)
|
2020-07-29 20:27:50 -05:00
|
|
|
}
|
|
|
|
|
2020-03-17 10:45:02 -05:00
|
|
|
// If this ever becomes non thread-local, `decode_syntax_context`
|
|
|
|
// and `decode_expn_id` will need to be updated to handle concurrent
|
|
|
|
// deserialization.
|
2021-05-05 14:31:25 -05:00
|
|
|
scoped_tls::scoped_thread_local!(static SESSION_GLOBALS: SessionGlobals);
|
2018-03-06 19:44:10 -06:00
|
|
|
|
2020-05-30 07:19:35 -05:00
|
|
|
// FIXME: We should use this enum or something like it to get rid of the
|
|
|
|
// use of magic `/rust/1.x/...` paths across the board.
|
2021-04-08 18:54:51 -05:00
|
|
|
#[derive(Debug, Eq, PartialEq, Clone, Ord, PartialOrd)]
|
2021-08-15 10:48:53 -05:00
|
|
|
#[derive(Decodable)]
|
2020-05-29 10:31:55 -05:00
|
|
|
pub enum RealFileName {
|
2021-04-03 10:59:31 -05:00
|
|
|
LocalPath(PathBuf),
|
|
|
|
/// For remapped paths (namely paths into libstd that have been mapped
|
|
|
|
/// to the appropriate spot on the local host's file system, and local file
|
|
|
|
/// system paths that have been remapped with `FilePathMapping`),
|
|
|
|
Remapped {
|
2021-04-08 18:54:51 -05:00
|
|
|
/// `local_path` is the (host-dependent) local path to the file. This is
|
|
|
|
/// None if the file was imported from another crate
|
|
|
|
local_path: Option<PathBuf>,
|
2020-05-29 10:31:55 -05:00
|
|
|
/// `virtual_name` is the stable path rustc will store internally within
|
|
|
|
/// build artifacts.
|
|
|
|
virtual_name: PathBuf,
|
|
|
|
},
|
|
|
|
}
|
|
|
|
|
2021-04-08 18:54:51 -05:00
|
|
|
impl Hash for RealFileName {
|
|
|
|
fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
|
|
|
|
// To prevent #70924 from happening again we should only hash the
|
|
|
|
// remapped (virtualized) path if that exists. This is because
|
|
|
|
// virtualized paths to sysroot crates (/rust/$hash or /rust/$version)
|
|
|
|
// remain stable even if the corresponding local_path changes
|
|
|
|
self.remapped_path_if_available().hash(state)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// This is functionally identical to #[derive(Encodable)], with the exception of
|
|
|
|
// an added assert statement
|
|
|
|
impl<S: Encoder> Encodable<S> for RealFileName {
|
Use delayed error handling for `Encodable` and `Encoder` infallible.
There are two impls of the `Encoder` trait: `opaque::Encoder` and
`opaque::FileEncoder`. The former encodes into memory and is infallible, the
latter writes to file and is fallible.
Currently, standard `Result`/`?`/`unwrap` error handling is used, but this is a
bit verbose and has non-trivial cost, which is annoying given how rare failures
are (especially in the infallible `opaque::Encoder` case).
This commit changes how `Encoder` fallibility is handled. All the `emit_*`
methods are now infallible. `opaque::Encoder` requires no great changes for
this. `opaque::FileEncoder` now implements a delayed error handling strategy.
If a failure occurs, it records this via the `res` field, and all subsequent
encoding operations are skipped if `res` indicates an error has occurred. Once
encoding is complete, the new `finish` method is called, which returns a
`Result`. In other words, there is now a single `Result`-producing method
instead of many of them.
This has very little effect on how any file errors are reported if
`opaque::FileEncoder` has any failures.
Much of this commit is boring mechanical changes, removing `Result` return
values and `?` or `unwrap` from expressions. The more interesting parts are as
follows.
- serialize.rs: The `Encoder` trait gains an `Ok` associated type. The
`into_inner` method is changed into `finish`, which returns
`Result<Vec<u8>, !>`.
- opaque.rs: The `FileEncoder` adopts the delayed error handling
strategy. Its `Ok` type is a `usize`, returning the number of bytes
written, replacing previous uses of `FileEncoder::position`.
- Various methods that take an encoder now consume it, rather than being
passed a mutable reference, e.g. `serialize_query_result_cache`.
2022-06-06 22:30:45 -05:00
|
|
|
fn encode(&self, encoder: &mut S) {
|
2021-06-04 11:23:50 -05:00
|
|
|
match *self {
|
2021-06-04 10:33:26 -05:00
|
|
|
RealFileName::LocalPath(ref local_path) => encoder.emit_enum_variant(0, |encoder| {
|
Use delayed error handling for `Encodable` and `Encoder` infallible.
There are two impls of the `Encoder` trait: `opaque::Encoder` and
`opaque::FileEncoder`. The former encodes into memory and is infallible, the
latter writes to file and is fallible.
Currently, standard `Result`/`?`/`unwrap` error handling is used, but this is a
bit verbose and has non-trivial cost, which is annoying given how rare failures
are (especially in the infallible `opaque::Encoder` case).
This commit changes how `Encoder` fallibility is handled. All the `emit_*`
methods are now infallible. `opaque::Encoder` requires no great changes for
this. `opaque::FileEncoder` now implements a delayed error handling strategy.
If a failure occurs, it records this via the `res` field, and all subsequent
encoding operations are skipped if `res` indicates an error has occurred. Once
encoding is complete, the new `finish` method is called, which returns a
`Result`. In other words, there is now a single `Result`-producing method
instead of many of them.
This has very little effect on how any file errors are reported if
`opaque::FileEncoder` has any failures.
Much of this commit is boring mechanical changes, removing `Result` return
values and `?` or `unwrap` from expressions. The more interesting parts are as
follows.
- serialize.rs: The `Encoder` trait gains an `Ok` associated type. The
`into_inner` method is changed into `finish`, which returns
`Result<Vec<u8>, !>`.
- opaque.rs: The `FileEncoder` adopts the delayed error handling
strategy. Its `Ok` type is a `usize`, returning the number of bytes
written, replacing previous uses of `FileEncoder::position`.
- Various methods that take an encoder now consume it, rather than being
passed a mutable reference, e.g. `serialize_query_result_cache`.
2022-06-06 22:30:45 -05:00
|
|
|
local_path.encode(encoder);
|
2021-06-04 10:33:26 -05:00
|
|
|
}),
|
2021-04-08 18:54:51 -05:00
|
|
|
|
|
|
|
RealFileName::Remapped { ref local_path, ref virtual_name } => encoder
|
2021-06-04 10:33:26 -05:00
|
|
|
.emit_enum_variant(1, |encoder| {
|
2021-04-08 18:54:51 -05:00
|
|
|
// For privacy and build reproducibility, we must not embed host-dependant path in artifacts
|
|
|
|
// if they have been remapped by --remap-path-prefix
|
|
|
|
assert!(local_path.is_none());
|
Use delayed error handling for `Encodable` and `Encoder` infallible.
There are two impls of the `Encoder` trait: `opaque::Encoder` and
`opaque::FileEncoder`. The former encodes into memory and is infallible, the
latter writes to file and is fallible.
Currently, standard `Result`/`?`/`unwrap` error handling is used, but this is a
bit verbose and has non-trivial cost, which is annoying given how rare failures
are (especially in the infallible `opaque::Encoder` case).
This commit changes how `Encoder` fallibility is handled. All the `emit_*`
methods are now infallible. `opaque::Encoder` requires no great changes for
this. `opaque::FileEncoder` now implements a delayed error handling strategy.
If a failure occurs, it records this via the `res` field, and all subsequent
encoding operations are skipped if `res` indicates an error has occurred. Once
encoding is complete, the new `finish` method is called, which returns a
`Result`. In other words, there is now a single `Result`-producing method
instead of many of them.
This has very little effect on how any file errors are reported if
`opaque::FileEncoder` has any failures.
Much of this commit is boring mechanical changes, removing `Result` return
values and `?` or `unwrap` from expressions. The more interesting parts are as
follows.
- serialize.rs: The `Encoder` trait gains an `Ok` associated type. The
`into_inner` method is changed into `finish`, which returns
`Result<Vec<u8>, !>`.
- opaque.rs: The `FileEncoder` adopts the delayed error handling
strategy. Its `Ok` type is a `usize`, returning the number of bytes
written, replacing previous uses of `FileEncoder::position`.
- Various methods that take an encoder now consume it, rather than being
passed a mutable reference, e.g. `serialize_query_result_cache`.
2022-06-06 22:30:45 -05:00
|
|
|
local_path.encode(encoder);
|
|
|
|
virtual_name.encode(encoder);
|
2021-04-08 18:54:51 -05:00
|
|
|
}),
|
2021-06-04 11:23:50 -05:00
|
|
|
}
|
2021-04-08 18:54:51 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-05-29 10:31:55 -05:00
|
|
|
impl RealFileName {
|
2021-04-08 18:54:51 -05:00
|
|
|
/// Returns the path suitable for reading from the file system on the local host,
|
|
|
|
/// if this information exists.
|
2021-04-14 08:12:39 -05:00
|
|
|
/// Avoid embedding this in build artifacts; see `remapped_path_if_available()` for that.
|
2021-04-08 18:54:51 -05:00
|
|
|
pub fn local_path(&self) -> Option<&Path> {
|
2020-05-29 10:31:55 -05:00
|
|
|
match self {
|
2021-04-08 18:54:51 -05:00
|
|
|
RealFileName::LocalPath(p) => Some(p),
|
|
|
|
RealFileName::Remapped { local_path: p, virtual_name: _ } => {
|
|
|
|
p.as_ref().map(PathBuf::as_path)
|
|
|
|
}
|
2020-05-29 10:31:55 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-04-08 18:54:51 -05:00
|
|
|
/// Returns the path suitable for reading from the file system on the local host,
|
|
|
|
/// if this information exists.
|
2021-04-14 08:12:39 -05:00
|
|
|
/// Avoid embedding this in build artifacts; see `remapped_path_if_available()` for that.
|
2021-04-08 18:54:51 -05:00
|
|
|
pub fn into_local_path(self) -> Option<PathBuf> {
|
2020-05-29 10:31:55 -05:00
|
|
|
match self {
|
2021-04-08 18:54:51 -05:00
|
|
|
RealFileName::LocalPath(p) => Some(p),
|
|
|
|
RealFileName::Remapped { local_path: p, virtual_name: _ } => p,
|
2020-05-29 10:31:55 -05:00
|
|
|
}
|
|
|
|
}
|
2020-05-29 13:04:03 -05:00
|
|
|
|
2021-04-14 08:12:39 -05:00
|
|
|
/// Returns the path suitable for embedding into build artifacts. This would still
|
|
|
|
/// be a local path if it has not been remapped. A remapped path will not correspond
|
|
|
|
/// to a valid file system path: see `local_path_if_available()` for something that
|
|
|
|
/// is more likely to return paths into the local host file system.
|
|
|
|
pub fn remapped_path_if_available(&self) -> &Path {
|
2020-05-29 13:04:03 -05:00
|
|
|
match self {
|
2021-04-03 10:59:31 -05:00
|
|
|
RealFileName::LocalPath(p)
|
|
|
|
| RealFileName::Remapped { local_path: _, virtual_name: p } => &p,
|
2020-05-29 13:04:03 -05:00
|
|
|
}
|
|
|
|
}
|
2021-04-19 19:11:12 -05:00
|
|
|
|
2021-04-14 08:12:39 -05:00
|
|
|
/// Returns the path suitable for reading from the file system on the local host,
|
|
|
|
/// if this information exists. Otherwise returns the remapped name.
|
|
|
|
/// Avoid embedding this in build artifacts; see `remapped_path_if_available()` for that.
|
|
|
|
pub fn local_path_if_available(&self) -> &Path {
|
|
|
|
match self {
|
|
|
|
RealFileName::LocalPath(path)
|
|
|
|
| RealFileName::Remapped { local_path: None, virtual_name: path }
|
|
|
|
| RealFileName::Remapped { local_path: Some(path), virtual_name: _ } => path,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-08-26 05:46:01 -05:00
|
|
|
pub fn to_string_lossy(&self, display_pref: FileNameDisplayPreference) -> Cow<'_, str> {
|
|
|
|
match display_pref {
|
|
|
|
FileNameDisplayPreference::Local => self.local_path_if_available().to_string_lossy(),
|
|
|
|
FileNameDisplayPreference::Remapped => {
|
|
|
|
self.remapped_path_if_available().to_string_lossy()
|
|
|
|
}
|
2020-05-29 13:04:03 -05:00
|
|
|
}
|
|
|
|
}
|
2020-05-29 10:31:55 -05:00
|
|
|
}
|
|
|
|
|
2018-11-26 20:59:49 -06:00
|
|
|
/// Differentiates between real files and common virtual files.
|
2020-06-11 09:49:57 -05:00
|
|
|
#[derive(Debug, Eq, PartialEq, Clone, Ord, PartialOrd, Hash)]
|
2021-08-15 10:48:53 -05:00
|
|
|
#[derive(Decodable, Encodable)]
|
2017-12-14 01:09:19 -06:00
|
|
|
pub enum FileName {
|
2020-05-29 10:31:55 -05:00
|
|
|
Real(RealFileName),
|
2018-11-26 20:59:49 -06:00
|
|
|
/// Call to `quote!`.
|
2018-10-30 09:11:24 -05:00
|
|
|
QuoteExpansion(u64),
|
2018-11-26 20:59:49 -06:00
|
|
|
/// Command line.
|
2018-10-30 09:11:24 -05:00
|
|
|
Anon(u64),
|
2020-02-29 11:16:26 -06:00
|
|
|
/// Hack in `src/librustc_ast/parse.rs`.
|
2018-11-26 20:59:49 -06:00
|
|
|
// FIXME(jseyfried)
|
2018-10-30 09:11:24 -05:00
|
|
|
MacroExpansion(u64),
|
|
|
|
ProcMacroSourceCode(u64),
|
2018-11-26 20:59:49 -06:00
|
|
|
/// Strings provided as `--cfg [cfgspec]` stored in a `crate_cfg`.
|
2018-10-30 09:11:24 -05:00
|
|
|
CfgSpec(u64),
|
2018-11-26 20:59:49 -06:00
|
|
|
/// Strings provided as crate attributes in the CLI.
|
2018-10-30 09:11:24 -05:00
|
|
|
CliCrateAttr(u64),
|
2018-11-26 20:59:49 -06:00
|
|
|
/// Custom sources for explicit parser calls from plugins and drivers.
|
2017-12-14 01:09:19 -06:00
|
|
|
Custom(String),
|
2018-12-04 14:18:03 -06:00
|
|
|
DocTest(PathBuf, isize),
|
2020-12-24 01:01:03 -06:00
|
|
|
/// Post-substitution inline assembly from LLVM.
|
2020-05-26 14:07:59 -05:00
|
|
|
InlineAsm(u64),
|
2017-12-14 01:09:19 -06:00
|
|
|
}
|
|
|
|
|
2021-04-19 19:11:12 -05:00
|
|
|
impl From<PathBuf> for FileName {
|
|
|
|
fn from(p: PathBuf) -> Self {
|
|
|
|
assert!(!p.to_string_lossy().ends_with('>'));
|
|
|
|
FileName::Real(RealFileName::LocalPath(p))
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-08-26 05:46:01 -05:00
|
|
|
#[derive(Clone, Copy, Eq, PartialEq, Hash, Debug)]
|
|
|
|
pub enum FileNameDisplayPreference {
|
|
|
|
Remapped,
|
|
|
|
Local,
|
|
|
|
}
|
|
|
|
|
2021-04-19 19:11:12 -05:00
|
|
|
pub struct FileNameDisplay<'a> {
|
|
|
|
inner: &'a FileName,
|
2021-08-26 05:46:01 -05:00
|
|
|
display_pref: FileNameDisplayPreference,
|
2021-04-19 19:11:12 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
impl fmt::Display for FileNameDisplay<'_> {
|
2019-02-03 12:42:27 -06:00
|
|
|
fn fmt(&self, fmt: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
|
|
|
use FileName::*;
|
2021-04-19 19:11:12 -05:00
|
|
|
match *self.inner {
|
|
|
|
Real(ref name) => {
|
2021-08-26 05:46:01 -05:00
|
|
|
write!(fmt, "{}", name.to_string_lossy(self.display_pref))
|
2020-05-29 10:31:55 -05:00
|
|
|
}
|
2018-10-30 09:11:24 -05:00
|
|
|
QuoteExpansion(_) => write!(fmt, "<quote expansion>"),
|
|
|
|
MacroExpansion(_) => write!(fmt, "<macro expansion>"),
|
|
|
|
Anon(_) => write!(fmt, "<anon>"),
|
|
|
|
ProcMacroSourceCode(_) => write!(fmt, "<proc-macro source code>"),
|
|
|
|
CfgSpec(_) => write!(fmt, "<cfgspec>"),
|
|
|
|
CliCrateAttr(_) => write!(fmt, "<crate attribute>"),
|
2017-12-14 01:09:19 -06:00
|
|
|
Custom(ref s) => write!(fmt, "<{}>", s),
|
2018-12-04 14:18:03 -06:00
|
|
|
DocTest(ref path, _) => write!(fmt, "{}", path.display()),
|
2020-05-26 14:07:59 -05:00
|
|
|
InlineAsm(_) => write!(fmt, "<inline asm>"),
|
2017-12-14 01:09:19 -06:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-05-05 10:26:22 -05:00
|
|
|
impl<'a> FileNameDisplay<'a> {
|
|
|
|
pub fn to_string_lossy(&self) -> Cow<'a, str> {
|
2021-04-19 19:11:12 -05:00
|
|
|
match self.inner {
|
2021-08-26 05:46:01 -05:00
|
|
|
FileName::Real(ref inner) => inner.to_string_lossy(self.display_pref),
|
2022-06-06 12:33:23 -05:00
|
|
|
_ => Cow::from(self.to_string()),
|
2021-04-19 19:11:12 -05:00
|
|
|
}
|
2017-12-14 01:09:19 -06:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl FileName {
|
|
|
|
pub fn is_real(&self) -> bool {
|
2019-02-03 12:42:27 -06:00
|
|
|
use FileName::*;
|
2017-12-14 01:09:19 -06:00
|
|
|
match *self {
|
|
|
|
Real(_) => true,
|
2019-11-13 06:01:43 -06:00
|
|
|
Anon(_)
|
2018-10-30 09:11:24 -05:00
|
|
|
| MacroExpansion(_)
|
|
|
|
| ProcMacroSourceCode(_)
|
|
|
|
| CfgSpec(_)
|
|
|
|
| CliCrateAttr(_)
|
2017-12-14 01:09:19 -06:00
|
|
|
| Custom(_)
|
2018-12-04 14:18:03 -06:00
|
|
|
| QuoteExpansion(_)
|
2020-05-26 14:07:59 -05:00
|
|
|
| DocTest(_, _)
|
|
|
|
| InlineAsm(_) => false,
|
2017-12-14 01:09:19 -06:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-04-19 17:27:02 -05:00
|
|
|
pub fn prefer_remapped(&self) -> FileNameDisplay<'_> {
|
2021-08-26 05:46:01 -05:00
|
|
|
FileNameDisplay { inner: self, display_pref: FileNameDisplayPreference::Remapped }
|
2021-04-19 17:27:02 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
// This may include transient local filesystem information.
|
|
|
|
// Must not be embedded in build outputs.
|
|
|
|
pub fn prefer_local(&self) -> FileNameDisplay<'_> {
|
2021-08-26 05:46:01 -05:00
|
|
|
FileNameDisplay { inner: self, display_pref: FileNameDisplayPreference::Local }
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn display(&self, display_pref: FileNameDisplayPreference) -> FileNameDisplay<'_> {
|
|
|
|
FileNameDisplay { inner: self, display_pref }
|
2021-04-19 17:27:02 -05:00
|
|
|
}
|
|
|
|
|
2018-10-30 09:11:24 -05:00
|
|
|
pub fn macro_expansion_source_code(src: &str) -> FileName {
|
|
|
|
let mut hasher = StableHasher::new();
|
|
|
|
src.hash(&mut hasher);
|
|
|
|
FileName::MacroExpansion(hasher.finish())
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn anon_source_code(src: &str) -> FileName {
|
|
|
|
let mut hasher = StableHasher::new();
|
|
|
|
src.hash(&mut hasher);
|
|
|
|
FileName::Anon(hasher.finish())
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn proc_macro_source_code(src: &str) -> FileName {
|
|
|
|
let mut hasher = StableHasher::new();
|
|
|
|
src.hash(&mut hasher);
|
|
|
|
FileName::ProcMacroSourceCode(hasher.finish())
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn cfg_spec_source_code(src: &str) -> FileName {
|
|
|
|
let mut hasher = StableHasher::new();
|
|
|
|
src.hash(&mut hasher);
|
|
|
|
FileName::QuoteExpansion(hasher.finish())
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn cli_crate_attr_source_code(src: &str) -> FileName {
|
|
|
|
let mut hasher = StableHasher::new();
|
|
|
|
src.hash(&mut hasher);
|
|
|
|
FileName::CliCrateAttr(hasher.finish())
|
|
|
|
}
|
2018-12-04 14:18:03 -06:00
|
|
|
|
|
|
|
pub fn doc_test_source_code(path: PathBuf, line: isize) -> FileName {
|
|
|
|
FileName::DocTest(path, line)
|
|
|
|
}
|
2020-05-26 14:07:59 -05:00
|
|
|
|
|
|
|
pub fn inline_asm_source_code(src: &str) -> FileName {
|
|
|
|
let mut hasher = StableHasher::new();
|
|
|
|
src.hash(&mut hasher);
|
|
|
|
FileName::InlineAsm(hasher.finish())
|
|
|
|
}
|
2017-12-14 01:09:19 -06:00
|
|
|
}
|
2016-06-21 17:08:13 -05:00
|
|
|
|
2020-12-24 01:01:03 -06:00
|
|
|
/// Represents a span.
|
|
|
|
///
|
2016-06-21 17:08:13 -05:00
|
|
|
/// Spans represent a region of code, used for error reporting. Positions in spans
|
2020-12-24 01:01:03 -06:00
|
|
|
/// are *absolute* positions from the beginning of the [`SourceMap`], not positions
|
|
|
|
/// relative to [`SourceFile`]s. Methods on the `SourceMap` can be used to relate spans back
|
2016-06-21 17:08:13 -05:00
|
|
|
/// to the original source.
|
2020-12-24 01:01:03 -06:00
|
|
|
///
|
|
|
|
/// You must be careful if the span crosses more than one file, since you will not be
|
2018-08-18 05:14:14 -05:00
|
|
|
/// able to use many of the functions on spans in source_map and you cannot assume
|
2020-12-24 01:01:03 -06:00
|
|
|
/// that the length of the span is equal to `span.hi - span.lo`; there may be space in the
|
|
|
|
/// [`BytePos`] range between files.
|
2017-09-16 13:43:05 -05:00
|
|
|
///
|
|
|
|
/// `SpanData` is public because `Span` uses a thread-local interner and can't be
|
|
|
|
/// sent to other threads, but some pieces of performance infra run in a separate thread.
|
|
|
|
/// Using `Span` is generally preferred.
|
2021-10-30 10:11:50 -05:00
|
|
|
#[derive(Clone, Copy, Hash, PartialEq, Eq)]
|
2017-09-16 13:43:05 -05:00
|
|
|
pub struct SpanData {
|
2017-08-29 17:41:05 -05:00
|
|
|
pub lo: BytePos,
|
|
|
|
pub hi: BytePos,
|
2016-06-21 17:08:13 -05:00
|
|
|
/// Information about where the macro came from, if this piece of
|
|
|
|
/// code was created by a macro expansion.
|
2017-08-29 17:41:05 -05:00
|
|
|
pub ctxt: SyntaxContext,
|
2021-04-18 07:27:04 -05:00
|
|
|
pub parent: Option<LocalDefId>,
|
2016-06-21 17:08:13 -05:00
|
|
|
}
|
|
|
|
|
2021-10-30 10:11:50 -05:00
|
|
|
// Order spans by position in the file.
|
|
|
|
impl Ord for SpanData {
|
|
|
|
fn cmp(&self, other: &Self) -> Ordering {
|
|
|
|
let SpanData {
|
|
|
|
lo: s_lo,
|
|
|
|
hi: s_hi,
|
|
|
|
ctxt: s_ctxt,
|
|
|
|
// `LocalDefId` does not implement `Ord`.
|
|
|
|
// The other fields are enough to determine in-file order.
|
|
|
|
parent: _,
|
|
|
|
} = self;
|
|
|
|
let SpanData {
|
|
|
|
lo: o_lo,
|
|
|
|
hi: o_hi,
|
|
|
|
ctxt: o_ctxt,
|
|
|
|
// `LocalDefId` does not implement `Ord`.
|
|
|
|
// The other fields are enough to determine in-file order.
|
|
|
|
parent: _,
|
|
|
|
} = other;
|
|
|
|
|
|
|
|
(s_lo, s_hi, s_ctxt).cmp(&(o_lo, o_hi, o_ctxt))
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl PartialOrd for SpanData {
|
|
|
|
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
|
|
|
|
Some(self.cmp(other))
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-10-21 09:21:02 -05:00
|
|
|
impl SpanData {
|
2021-01-07 06:23:25 -06:00
|
|
|
#[inline]
|
|
|
|
pub fn span(&self) -> Span {
|
2021-04-18 07:27:04 -05:00
|
|
|
Span::new(self.lo, self.hi, self.ctxt, self.parent)
|
2021-01-07 06:23:25 -06:00
|
|
|
}
|
2017-10-21 09:21:02 -05:00
|
|
|
#[inline]
|
|
|
|
pub fn with_lo(&self, lo: BytePos) -> Span {
|
2021-04-18 07:27:04 -05:00
|
|
|
Span::new(lo, self.hi, self.ctxt, self.parent)
|
2017-10-21 09:21:02 -05:00
|
|
|
}
|
|
|
|
#[inline]
|
|
|
|
pub fn with_hi(&self, hi: BytePos) -> Span {
|
2021-04-18 07:27:04 -05:00
|
|
|
Span::new(self.lo, hi, self.ctxt, self.parent)
|
2017-10-21 09:21:02 -05:00
|
|
|
}
|
|
|
|
#[inline]
|
|
|
|
pub fn with_ctxt(&self, ctxt: SyntaxContext) -> Span {
|
2021-04-18 07:27:04 -05:00
|
|
|
Span::new(self.lo, self.hi, ctxt, self.parent)
|
|
|
|
}
|
|
|
|
#[inline]
|
|
|
|
pub fn with_parent(&self, parent: Option<LocalDefId>) -> Span {
|
|
|
|
Span::new(self.lo, self.hi, self.ctxt, parent)
|
|
|
|
}
|
|
|
|
/// Returns `true` if this is a dummy span with any hygienic context.
|
|
|
|
#[inline]
|
|
|
|
pub fn is_dummy(self) -> bool {
|
|
|
|
self.lo.0 == 0 && self.hi.0 == 0
|
|
|
|
}
|
|
|
|
/// Returns `true` if `self` fully encloses `other`.
|
|
|
|
pub fn contains(self, other: Self) -> bool {
|
|
|
|
self.lo <= other.lo && other.hi <= self.hi
|
2017-10-21 09:21:02 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-12-03 07:37:23 -06:00
|
|
|
// The interner is pointed to by a thread local value which is only set on the main thread
|
2018-11-26 20:59:49 -06:00
|
|
|
// with parallelization is disabled. So we don't allow `Span` to transfer between threads
|
2017-12-03 07:37:23 -06:00
|
|
|
// to avoid panics and other errors, even though it would be memory safe to do so.
|
2019-01-28 08:51:47 -06:00
|
|
|
#[cfg(not(parallel_compiler))]
|
2017-09-16 13:43:05 -05:00
|
|
|
impl !Send for Span {}
|
2019-01-28 08:51:47 -06:00
|
|
|
#[cfg(not(parallel_compiler))]
|
2017-09-16 13:43:05 -05:00
|
|
|
impl !Sync for Span {}
|
|
|
|
|
|
|
|
impl PartialOrd for Span {
|
|
|
|
fn partial_cmp(&self, rhs: &Self) -> Option<Ordering> {
|
|
|
|
PartialOrd::partial_cmp(&self.data(), &rhs.data())
|
|
|
|
}
|
|
|
|
}
|
|
|
|
impl Ord for Span {
|
|
|
|
fn cmp(&self, rhs: &Self) -> Ordering {
|
|
|
|
Ord::cmp(&self.data(), &rhs.data())
|
|
|
|
}
|
|
|
|
}
|
2017-07-31 15:04:34 -05:00
|
|
|
|
2016-06-21 17:08:13 -05:00
|
|
|
impl Span {
|
2017-07-31 15:04:34 -05:00
|
|
|
#[inline]
|
|
|
|
pub fn lo(self) -> BytePos {
|
2017-09-16 13:43:05 -05:00
|
|
|
self.data().lo
|
2017-07-31 15:04:34 -05:00
|
|
|
}
|
|
|
|
#[inline]
|
|
|
|
pub fn with_lo(self, lo: BytePos) -> Span {
|
2017-10-21 09:21:02 -05:00
|
|
|
self.data().with_lo(lo)
|
2017-07-31 15:04:34 -05:00
|
|
|
}
|
|
|
|
#[inline]
|
|
|
|
pub fn hi(self) -> BytePos {
|
2017-09-16 13:43:05 -05:00
|
|
|
self.data().hi
|
2017-07-31 15:04:34 -05:00
|
|
|
}
|
|
|
|
#[inline]
|
|
|
|
pub fn with_hi(self, hi: BytePos) -> Span {
|
2017-10-21 09:21:02 -05:00
|
|
|
self.data().with_hi(hi)
|
2017-07-31 15:04:34 -05:00
|
|
|
}
|
|
|
|
#[inline]
|
|
|
|
pub fn ctxt(self) -> SyntaxContext {
|
2021-04-30 13:16:09 -05:00
|
|
|
self.data_untracked().ctxt
|
2017-07-31 15:04:34 -05:00
|
|
|
}
|
2022-06-19 18:27:29 -05:00
|
|
|
pub fn eq_ctxt(self, other: Span) -> bool {
|
|
|
|
self.data_untracked().ctxt == other.data_untracked().ctxt
|
|
|
|
}
|
2017-07-31 15:04:34 -05:00
|
|
|
#[inline]
|
|
|
|
pub fn with_ctxt(self, ctxt: SyntaxContext) -> Span {
|
2021-04-30 13:16:09 -05:00
|
|
|
self.data_untracked().with_ctxt(ctxt)
|
2017-07-31 15:04:34 -05:00
|
|
|
}
|
2021-04-18 07:27:04 -05:00
|
|
|
#[inline]
|
|
|
|
pub fn parent(self) -> Option<LocalDefId> {
|
|
|
|
self.data().parent
|
|
|
|
}
|
|
|
|
#[inline]
|
|
|
|
pub fn with_parent(self, ctxt: Option<LocalDefId>) -> Span {
|
|
|
|
self.data().with_parent(ctxt)
|
|
|
|
}
|
2017-07-31 15:04:34 -05:00
|
|
|
|
2018-06-24 17:00:21 -05:00
|
|
|
/// Returns `true` if this is a dummy span with any hygienic context.
|
|
|
|
#[inline]
|
|
|
|
pub fn is_dummy(self) -> bool {
|
2021-04-30 13:16:09 -05:00
|
|
|
self.data_untracked().is_dummy()
|
2018-06-24 17:00:21 -05:00
|
|
|
}
|
|
|
|
|
2019-08-10 17:08:30 -05:00
|
|
|
/// Returns `true` if this span comes from a macro or desugaring.
|
|
|
|
#[inline]
|
|
|
|
pub fn from_expansion(self) -> bool {
|
2019-08-10 17:44:55 -05:00
|
|
|
self.ctxt() != SyntaxContext::root()
|
|
|
|
}
|
|
|
|
|
2020-01-08 20:03:48 -06:00
|
|
|
/// Returns `true` if `span` originates in a derive-macro's expansion.
|
|
|
|
pub fn in_derive_expansion(self) -> bool {
|
2021-07-10 14:14:52 -05:00
|
|
|
matches!(self.ctxt().outer_expn_data().kind, ExpnKind::Macro(MacroKind::Derive, _))
|
2020-01-08 20:03:48 -06:00
|
|
|
}
|
|
|
|
|
2021-11-20 12:46:36 -06:00
|
|
|
/// Gate suggestions that would not be appropriate in a context the user didn't write.
|
|
|
|
pub fn can_be_used_for_suggestions(self) -> bool {
|
|
|
|
!self.from_expansion()
|
|
|
|
// FIXME: If this span comes from a `derive` macro but it points at code the user wrote,
|
|
|
|
// the callsite span and the span will be pointing at different places. It also means that
|
|
|
|
// we can safely provide suggestions on this span.
|
|
|
|
|| (matches!(self.ctxt().outer_expn_data().kind, ExpnKind::Macro(MacroKind::Derive, _))
|
|
|
|
&& self.parent_callsite().map(|p| (p.lo(), p.hi())) != Some((self.lo(), self.hi())))
|
|
|
|
}
|
|
|
|
|
2019-08-10 17:44:55 -05:00
|
|
|
#[inline]
|
|
|
|
pub fn with_root_ctxt(lo: BytePos, hi: BytePos) -> Span {
|
2021-04-18 07:27:04 -05:00
|
|
|
Span::new(lo, hi, SyntaxContext::root(), None)
|
2019-08-10 17:08:30 -05:00
|
|
|
}
|
|
|
|
|
2020-12-24 01:01:03 -06:00
|
|
|
/// Returns a new span representing an empty span at the beginning of this span.
|
2018-02-04 06:19:14 -06:00
|
|
|
#[inline]
|
2018-03-10 08:45:47 -06:00
|
|
|
pub fn shrink_to_lo(self) -> Span {
|
2021-04-30 13:16:09 -05:00
|
|
|
let span = self.data_untracked();
|
2018-03-10 08:45:47 -06:00
|
|
|
span.with_hi(span.lo)
|
|
|
|
}
|
2018-11-26 20:59:49 -06:00
|
|
|
/// Returns a new span representing an empty span at the end of this span.
|
2018-03-10 08:45:47 -06:00
|
|
|
#[inline]
|
|
|
|
pub fn shrink_to_hi(self) -> Span {
|
2021-04-30 13:16:09 -05:00
|
|
|
let span = self.data_untracked();
|
2018-03-10 08:45:47 -06:00
|
|
|
span.with_lo(span.hi)
|
2018-02-04 06:19:14 -06:00
|
|
|
}
|
|
|
|
|
Adds two source span utility functions used in source-based coverage
`span.is_empty()` - returns true if `lo()` and `hi()` are equal. This is
not only a convenience, but makes it clear that a `Span` can be empty
(that is, retrieving the source for an empty `Span` will return an empty
string), and codifies the (otherwise undocumented--in the rustc_span
package, at least) fact that `Span` is a half-open interval (where
`hi()` is the open end).
`source_map.lookup_file_span()` - returns an enclosing `Span`
representing the start and end positions of the file enclosing the given
`BytePos`. This gives developers a clear way to quickly determine if any
any other `BytePos` or `Span` is also from the same file (for example,
by simply calling `file_span.contains(span)`).
This results in much simpler code and is much more runtime efficient
compared with the obvious alternative: calling `source_map.lookup_line()`
for any two `Span`'s byte positions, handle both arms of the `Result`
(both contain the file), and then compare files. It is also more
efficient than the non-public method `lookup_source_file_idx()` for each
`BytePos`, because, while comparing the internal source file indexes
would be efficient, looking up the source file index for every `BytePos`
or `Span` to be compared requires a binary search (worst case
performance being O(log n) for every lookup).
`source_map.lookup_file_span()` performs the binary search only once, to
get the `file_span` result that can be used to compare to any number of
other `BytePos` or `Span` values and those comparisons are always O(1).
2020-08-27 15:58:01 -05:00
|
|
|
#[inline]
|
2020-12-24 01:01:03 -06:00
|
|
|
/// Returns `true` if `hi == lo`.
|
2022-01-27 01:17:13 -06:00
|
|
|
pub fn is_empty(self) -> bool {
|
2021-04-30 13:16:09 -05:00
|
|
|
let span = self.data_untracked();
|
Adds two source span utility functions used in source-based coverage
`span.is_empty()` - returns true if `lo()` and `hi()` are equal. This is
not only a convenience, but makes it clear that a `Span` can be empty
(that is, retrieving the source for an empty `Span` will return an empty
string), and codifies the (otherwise undocumented--in the rustc_span
package, at least) fact that `Span` is a half-open interval (where
`hi()` is the open end).
`source_map.lookup_file_span()` - returns an enclosing `Span`
representing the start and end positions of the file enclosing the given
`BytePos`. This gives developers a clear way to quickly determine if any
any other `BytePos` or `Span` is also from the same file (for example,
by simply calling `file_span.contains(span)`).
This results in much simpler code and is much more runtime efficient
compared with the obvious alternative: calling `source_map.lookup_line()`
for any two `Span`'s byte positions, handle both arms of the `Result`
(both contain the file), and then compare files. It is also more
efficient than the non-public method `lookup_source_file_idx()` for each
`BytePos`, because, while comparing the internal source file indexes
would be efficient, looking up the source file index for every `BytePos`
or `Span` to be compared requires a binary search (worst case
performance being O(log n) for every lookup).
`source_map.lookup_file_span()` performs the binary search only once, to
get the `file_span` result that can be used to compare to any number of
other `BytePos` or `Span` values and those comparisons are always O(1).
2020-08-27 15:58:01 -05:00
|
|
|
span.hi == span.lo
|
|
|
|
}
|
|
|
|
|
2016-06-21 17:08:13 -05:00
|
|
|
/// Returns `self` if `self` is not the dummy span, and `other` otherwise.
|
|
|
|
pub fn substitute_dummy(self, other: Span) -> Span {
|
2020-03-19 12:55:46 -05:00
|
|
|
if self.is_dummy() { other } else { self }
|
2016-06-21 17:08:13 -05:00
|
|
|
}
|
|
|
|
|
2019-02-08 07:53:55 -06:00
|
|
|
/// Returns `true` if `self` fully encloses `other`.
|
2016-06-21 17:08:13 -05:00
|
|
|
pub fn contains(self, other: Span) -> bool {
|
2017-10-21 09:21:02 -05:00
|
|
|
let span = self.data();
|
|
|
|
let other = other.data();
|
2021-04-18 07:27:04 -05:00
|
|
|
span.contains(other)
|
2016-06-21 17:08:13 -05:00
|
|
|
}
|
|
|
|
|
2019-02-08 07:53:55 -06:00
|
|
|
/// Returns `true` if `self` touches `other`.
|
2018-12-20 18:52:52 -06:00
|
|
|
pub fn overlaps(self, other: Span) -> bool {
|
|
|
|
let span = self.data();
|
|
|
|
let other = other.data();
|
|
|
|
span.lo < other.hi && other.lo < span.hi
|
|
|
|
}
|
|
|
|
|
2019-02-08 07:53:55 -06:00
|
|
|
/// Returns `true` if the spans are equal with regards to the source text.
|
2016-06-21 17:08:13 -05:00
|
|
|
///
|
|
|
|
/// Use this instead of `==` when either span could be generated code,
|
|
|
|
/// and you only care that they point to the same bytes of source text.
|
2022-01-27 01:17:13 -06:00
|
|
|
pub fn source_equal(self, other: Span) -> bool {
|
2017-10-21 09:21:02 -05:00
|
|
|
let span = self.data();
|
|
|
|
let other = other.data();
|
|
|
|
span.lo == other.lo && span.hi == other.hi
|
2016-06-21 17:08:13 -05:00
|
|
|
}
|
|
|
|
|
2018-11-26 20:59:49 -06:00
|
|
|
/// Returns `Some(span)`, where the start is trimmed by the end of `other`.
|
2016-06-21 17:08:13 -05:00
|
|
|
pub fn trim_start(self, other: Span) -> Option<Span> {
|
2017-10-21 09:21:02 -05:00
|
|
|
let span = self.data();
|
|
|
|
let other = other.data();
|
2020-03-19 12:55:46 -05:00
|
|
|
if span.hi > other.hi { Some(span.with_lo(cmp::max(span.lo, other.hi))) } else { None }
|
2016-06-21 17:08:13 -05:00
|
|
|
}
|
2017-03-16 23:04:41 -05:00
|
|
|
|
2019-02-08 07:53:55 -06:00
|
|
|
/// Returns the source span -- this is either the supplied span, or the span for
|
2017-03-16 23:04:41 -05:00
|
|
|
/// the macro callsite that expanded to it.
|
|
|
|
pub fn source_callsite(self) -> Span {
|
2019-08-13 15:56:42 -05:00
|
|
|
let expn_data = self.ctxt().outer_expn_data();
|
2020-03-19 12:55:46 -05:00
|
|
|
if !expn_data.is_root() { expn_data.call_site.source_callsite() } else { self }
|
2017-03-16 23:04:41 -05:00
|
|
|
}
|
|
|
|
|
2018-04-26 17:28:34 -05:00
|
|
|
/// The `Span` for the tokens in the previous macro expansion from which `self` was generated,
|
2018-11-26 20:59:49 -06:00
|
|
|
/// if any.
|
2021-04-18 07:27:04 -05:00
|
|
|
pub fn parent_callsite(self) -> Option<Span> {
|
2019-08-13 15:56:42 -05:00
|
|
|
let expn_data = self.ctxt().outer_expn_data();
|
2020-03-19 12:55:46 -05:00
|
|
|
if !expn_data.is_root() { Some(expn_data.call_site) } else { None }
|
2018-04-21 17:15:54 -05:00
|
|
|
}
|
|
|
|
|
2021-08-30 13:17:12 -05:00
|
|
|
/// Walk down the expansion ancestors to find a span that's contained within `outer`.
|
|
|
|
pub fn find_ancestor_inside(mut self, outer: Span) -> Option<Span> {
|
|
|
|
while !outer.contains(self) {
|
2021-04-18 07:27:04 -05:00
|
|
|
self = self.parent_callsite()?;
|
2021-08-30 13:17:12 -05:00
|
|
|
}
|
|
|
|
Some(self)
|
|
|
|
}
|
|
|
|
|
2018-05-13 08:14:43 -05:00
|
|
|
/// Edition of the crate from which this span came.
|
|
|
|
pub fn edition(self) -> edition::Edition {
|
2021-01-07 06:23:25 -06:00
|
|
|
self.ctxt().edition()
|
2018-05-13 08:14:43 -05:00
|
|
|
}
|
|
|
|
|
2018-11-17 18:25:59 -06:00
|
|
|
#[inline]
|
2022-01-27 01:17:13 -06:00
|
|
|
pub fn rust_2015(self) -> bool {
|
2018-11-17 18:25:59 -06:00
|
|
|
self.edition() == edition::Edition::Edition2015
|
|
|
|
}
|
|
|
|
|
|
|
|
#[inline]
|
2022-01-27 01:17:13 -06:00
|
|
|
pub fn rust_2018(self) -> bool {
|
2018-11-17 18:25:59 -06:00
|
|
|
self.edition() >= edition::Edition::Edition2018
|
|
|
|
}
|
|
|
|
|
2020-12-30 07:33:46 -06:00
|
|
|
#[inline]
|
2022-01-27 01:17:13 -06:00
|
|
|
pub fn rust_2021(self) -> bool {
|
2020-12-30 07:33:46 -06:00
|
|
|
self.edition() >= edition::Edition::Edition2021
|
|
|
|
}
|
|
|
|
|
2022-02-28 17:13:24 -06:00
|
|
|
#[inline]
|
|
|
|
pub fn rust_2024(self) -> bool {
|
|
|
|
self.edition() >= edition::Edition::Edition2024
|
|
|
|
}
|
|
|
|
|
2019-02-08 07:53:55 -06:00
|
|
|
/// Returns the source callee.
|
2017-03-16 23:04:41 -05:00
|
|
|
///
|
2018-06-23 13:41:39 -05:00
|
|
|
/// Returns `None` if the supplied span has no expansion trace,
|
2019-08-13 15:56:42 -05:00
|
|
|
/// else returns the `ExpnData` for the macro definition
|
2017-03-16 23:04:41 -05:00
|
|
|
/// corresponding to the source callsite.
|
2019-08-13 15:56:42 -05:00
|
|
|
pub fn source_callee(self) -> Option<ExpnData> {
|
|
|
|
fn source_callee(expn_data: ExpnData) -> ExpnData {
|
|
|
|
let next_expn_data = expn_data.call_site.ctxt().outer_expn_data();
|
2020-03-19 12:55:46 -05:00
|
|
|
if !next_expn_data.is_root() { source_callee(next_expn_data) } else { expn_data }
|
2017-03-16 23:04:41 -05:00
|
|
|
}
|
2019-08-13 15:56:42 -05:00
|
|
|
let expn_data = self.ctxt().outer_expn_data();
|
2020-03-19 12:55:46 -05:00
|
|
|
if !expn_data.is_root() { Some(source_callee(expn_data)) } else { None }
|
2017-03-16 23:04:41 -05:00
|
|
|
}
|
|
|
|
|
2019-02-08 07:53:55 -06:00
|
|
|
/// Checks if a span is "internal" to a macro in which `#[unstable]`
|
2017-03-16 23:04:41 -05:00
|
|
|
/// items can be used (that is, a macro marked with
|
|
|
|
/// `#[allow_internal_unstable]`).
|
2022-01-27 01:17:13 -06:00
|
|
|
pub fn allows_unstable(self, feature: Symbol) -> bool {
|
2021-02-14 09:56:21 -06:00
|
|
|
self.ctxt()
|
|
|
|
.outer_expn_data()
|
|
|
|
.allow_internal_unstable
|
|
|
|
.map_or(false, |features| features.iter().any(|&f| f == feature))
|
2017-03-16 23:04:41 -05:00
|
|
|
}
|
|
|
|
|
2019-02-08 07:53:55 -06:00
|
|
|
/// Checks if this span arises from a compiler desugaring of kind `kind`.
|
2022-01-27 01:17:13 -06:00
|
|
|
pub fn is_desugaring(self, kind: DesugaringKind) -> bool {
|
2019-08-13 15:56:42 -05:00
|
|
|
match self.ctxt().outer_expn_data().kind {
|
2019-08-10 19:00:05 -05:00
|
|
|
ExpnKind::Desugaring(k) => k == kind,
|
|
|
|
_ => false,
|
2017-08-12 19:43:43 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-02-08 07:53:55 -06:00
|
|
|
/// Returns the compiler desugaring that created this span, or `None`
|
2017-08-30 16:12:34 -05:00
|
|
|
/// if this span is not from a desugaring.
|
2022-01-27 01:17:13 -06:00
|
|
|
pub fn desugaring_kind(self) -> Option<DesugaringKind> {
|
2019-08-13 15:56:42 -05:00
|
|
|
match self.ctxt().outer_expn_data().kind {
|
2019-08-10 19:00:05 -05:00
|
|
|
ExpnKind::Desugaring(k) => Some(k),
|
|
|
|
_ => None,
|
2017-08-30 16:12:34 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-02-08 07:53:55 -06:00
|
|
|
/// Checks if a span is "internal" to a macro in which `unsafe`
|
2020-12-24 01:01:03 -06:00
|
|
|
/// can be used without triggering the `unsafe_code` lint.
|
2017-08-08 10:21:20 -05:00
|
|
|
// (that is, a macro marked with `#[allow_internal_unsafe]`).
|
2022-01-27 01:17:13 -06:00
|
|
|
pub fn allows_unsafe(self) -> bool {
|
2019-08-13 15:56:42 -05:00
|
|
|
self.ctxt().outer_expn_data().allow_internal_unsafe
|
2017-08-08 10:21:20 -05:00
|
|
|
}
|
|
|
|
|
2020-01-20 17:46:53 -06:00
|
|
|
pub fn macro_backtrace(mut self) -> impl Iterator<Item = ExpnData> {
|
2017-03-16 23:04:41 -05:00
|
|
|
let mut prev_span = DUMMY_SP;
|
2020-01-20 17:46:53 -06:00
|
|
|
std::iter::from_fn(move || {
|
|
|
|
loop {
|
|
|
|
let expn_data = self.ctxt().outer_expn_data();
|
|
|
|
if expn_data.is_root() {
|
|
|
|
return None;
|
|
|
|
}
|
|
|
|
|
2022-01-27 01:17:13 -06:00
|
|
|
let is_recursive = expn_data.call_site.source_equal(prev_span);
|
2020-01-20 17:46:53 -06:00
|
|
|
|
|
|
|
prev_span = self;
|
|
|
|
self = expn_data.call_site;
|
|
|
|
|
|
|
|
// Don't print recursive invocations.
|
|
|
|
if !is_recursive {
|
|
|
|
return Some(expn_data);
|
|
|
|
}
|
2019-08-10 19:00:05 -05:00
|
|
|
}
|
2020-01-20 17:46:53 -06:00
|
|
|
})
|
2017-03-16 23:04:41 -05:00
|
|
|
}
|
2017-03-14 19:22:48 -05:00
|
|
|
|
2019-02-08 07:53:55 -06:00
|
|
|
/// Returns a `Span` that would enclose both `self` and `end`.
|
2020-09-13 07:48:15 -05:00
|
|
|
///
|
|
|
|
/// ```text
|
|
|
|
/// ____ ___
|
|
|
|
/// self lorem ipsum end
|
|
|
|
/// ^^^^^^^^^^^^^^^^^^^^
|
|
|
|
/// ```
|
2017-03-14 19:22:48 -05:00
|
|
|
pub fn to(self, end: Span) -> Span {
|
2018-02-01 13:51:49 -06:00
|
|
|
let span_data = self.data();
|
|
|
|
let end_data = end.data();
|
2018-11-26 20:59:49 -06:00
|
|
|
// FIXME(jseyfried): `self.ctxt` should always equal `end.ctxt` here (cf. issue #23480).
|
2018-02-01 13:51:49 -06:00
|
|
|
// Return the macro span on its own to avoid weird diagnostic output. It is preferable to
|
|
|
|
// have an incomplete span than a completely nonsensical one.
|
|
|
|
if span_data.ctxt != end_data.ctxt {
|
2019-08-10 17:44:55 -05:00
|
|
|
if span_data.ctxt == SyntaxContext::root() {
|
2018-02-01 13:51:49 -06:00
|
|
|
return end;
|
2019-08-10 17:44:55 -05:00
|
|
|
} else if end_data.ctxt == SyntaxContext::root() {
|
2018-02-01 13:51:49 -06:00
|
|
|
return self;
|
|
|
|
}
|
2018-11-26 20:59:49 -06:00
|
|
|
// Both spans fall within a macro.
|
|
|
|
// FIXME(estebank): check if it is the *same* macro.
|
2018-02-01 13:51:49 -06:00
|
|
|
}
|
2017-07-31 15:04:34 -05:00
|
|
|
Span::new(
|
2018-02-01 13:51:49 -06:00
|
|
|
cmp::min(span_data.lo, end_data.lo),
|
|
|
|
cmp::max(span_data.hi, end_data.hi),
|
2019-08-10 17:44:55 -05:00
|
|
|
if span_data.ctxt == SyntaxContext::root() { end_data.ctxt } else { span_data.ctxt },
|
2021-04-18 07:27:04 -05:00
|
|
|
if span_data.parent == end_data.parent { span_data.parent } else { None },
|
2017-07-31 15:04:34 -05:00
|
|
|
)
|
2017-03-14 19:22:48 -05:00
|
|
|
}
|
2017-04-03 06:58:48 -05:00
|
|
|
|
2019-02-08 07:53:55 -06:00
|
|
|
/// Returns a `Span` between the end of `self` to the beginning of `end`.
|
2020-09-13 07:48:15 -05:00
|
|
|
///
|
|
|
|
/// ```text
|
|
|
|
/// ____ ___
|
|
|
|
/// self lorem ipsum end
|
|
|
|
/// ^^^^^^^^^^^^^
|
|
|
|
/// ```
|
2017-04-03 06:58:48 -05:00
|
|
|
pub fn between(self, end: Span) -> Span {
|
2017-10-21 09:21:02 -05:00
|
|
|
let span = self.data();
|
|
|
|
let end = end.data();
|
2017-07-31 15:04:34 -05:00
|
|
|
Span::new(
|
2017-10-21 09:21:02 -05:00
|
|
|
span.hi,
|
|
|
|
end.lo,
|
2019-08-10 17:44:55 -05:00
|
|
|
if end.ctxt == SyntaxContext::root() { end.ctxt } else { span.ctxt },
|
2021-04-18 07:27:04 -05:00
|
|
|
if span.parent == end.parent { span.parent } else { None },
|
2017-07-31 15:04:34 -05:00
|
|
|
)
|
2017-04-03 06:58:48 -05:00
|
|
|
}
|
|
|
|
|
2020-09-13 07:48:15 -05:00
|
|
|
/// Returns a `Span` from the beginning of `self` until the beginning of `end`.
|
|
|
|
///
|
|
|
|
/// ```text
|
|
|
|
/// ____ ___
|
|
|
|
/// self lorem ipsum end
|
|
|
|
/// ^^^^^^^^^^^^^^^^^
|
|
|
|
/// ```
|
2017-04-03 06:58:48 -05:00
|
|
|
pub fn until(self, end: Span) -> Span {
|
2021-09-20 10:39:16 -05:00
|
|
|
// Most of this function's body is copied from `to`.
|
|
|
|
// We can't just do `self.to(end.shrink_to_lo())`,
|
|
|
|
// because to also does some magic where it uses min/max so
|
|
|
|
// it can handle overlapping spans. Some advanced mis-use of
|
|
|
|
// `until` with different ctxts makes this visible.
|
|
|
|
let span_data = self.data();
|
|
|
|
let end_data = end.data();
|
|
|
|
// FIXME(jseyfried): `self.ctxt` should always equal `end.ctxt` here (cf. issue #23480).
|
|
|
|
// Return the macro span on its own to avoid weird diagnostic output. It is preferable to
|
|
|
|
// have an incomplete span than a completely nonsensical one.
|
|
|
|
if span_data.ctxt != end_data.ctxt {
|
|
|
|
if span_data.ctxt == SyntaxContext::root() {
|
|
|
|
return end;
|
|
|
|
} else if end_data.ctxt == SyntaxContext::root() {
|
|
|
|
return self;
|
|
|
|
}
|
|
|
|
// Both spans fall within a macro.
|
|
|
|
// FIXME(estebank): check if it is the *same* macro.
|
|
|
|
}
|
2017-07-31 15:04:34 -05:00
|
|
|
Span::new(
|
2021-09-20 10:39:16 -05:00
|
|
|
span_data.lo,
|
|
|
|
end_data.lo,
|
|
|
|
if end_data.ctxt == SyntaxContext::root() { end_data.ctxt } else { span_data.ctxt },
|
|
|
|
if span_data.parent == end_data.parent { span_data.parent } else { None },
|
2017-07-31 15:04:34 -05:00
|
|
|
)
|
2017-04-03 06:58:48 -05:00
|
|
|
}
|
2018-03-17 18:57:23 -05:00
|
|
|
|
2019-06-04 10:03:43 -05:00
|
|
|
pub fn from_inner(self, inner: InnerSpan) -> Span {
|
2018-05-10 11:09:58 -05:00
|
|
|
let span = self.data();
|
2019-06-04 10:03:43 -05:00
|
|
|
Span::new(
|
|
|
|
span.lo + BytePos::from_usize(inner.start),
|
|
|
|
span.lo + BytePos::from_usize(inner.end),
|
2018-05-10 11:09:58 -05:00
|
|
|
span.ctxt,
|
2021-04-18 07:27:04 -05:00
|
|
|
span.parent,
|
2018-05-10 11:09:58 -05:00
|
|
|
)
|
|
|
|
}
|
|
|
|
|
2019-08-28 04:41:29 -05:00
|
|
|
/// Equivalent of `Span::def_site` from the proc macro API,
|
|
|
|
/// except that the location is taken from the `self` span.
|
|
|
|
pub fn with_def_site_ctxt(self, expn_id: ExpnId) -> Span {
|
|
|
|
self.with_ctxt_from_mark(expn_id, Transparency::Opaque)
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Equivalent of `Span::call_site` from the proc macro API,
|
|
|
|
/// except that the location is taken from the `self` span.
|
2022-01-27 01:17:13 -06:00
|
|
|
pub fn with_call_site_ctxt(self, expn_id: ExpnId) -> Span {
|
2019-08-28 04:41:29 -05:00
|
|
|
self.with_ctxt_from_mark(expn_id, Transparency::Transparent)
|
|
|
|
}
|
|
|
|
|
2019-09-22 10:38:02 -05:00
|
|
|
/// Equivalent of `Span::mixed_site` from the proc macro API,
|
|
|
|
/// except that the location is taken from the `self` span.
|
2022-01-27 01:17:13 -06:00
|
|
|
pub fn with_mixed_site_ctxt(self, expn_id: ExpnId) -> Span {
|
2019-09-22 10:38:02 -05:00
|
|
|
self.with_ctxt_from_mark(expn_id, Transparency::SemiTransparent)
|
|
|
|
}
|
|
|
|
|
2019-08-21 13:28:22 -05:00
|
|
|
/// Produces a span with the same location as `self` and context produced by a macro with the
|
|
|
|
/// given ID and transparency, assuming that macro was defined directly and not produced by
|
|
|
|
/// some other macro (which is the case for built-in and procedural macros).
|
|
|
|
pub fn with_ctxt_from_mark(self, expn_id: ExpnId, transparency: Transparency) -> Span {
|
2019-08-22 17:31:01 -05:00
|
|
|
self.with_ctxt(SyntaxContext::root().apply_mark(expn_id, transparency))
|
2019-08-21 13:28:22 -05:00
|
|
|
}
|
|
|
|
|
2018-03-17 18:57:23 -05:00
|
|
|
#[inline]
|
2019-08-22 17:31:01 -05:00
|
|
|
pub fn apply_mark(self, expn_id: ExpnId, transparency: Transparency) -> Span {
|
2018-03-17 18:57:23 -05:00
|
|
|
let span = self.data();
|
2019-08-22 17:31:01 -05:00
|
|
|
span.with_ctxt(span.ctxt.apply_mark(expn_id, transparency))
|
2018-03-17 18:57:23 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
#[inline]
|
2019-07-15 17:04:05 -05:00
|
|
|
pub fn remove_mark(&mut self) -> ExpnId {
|
2018-03-17 18:57:23 -05:00
|
|
|
let mut span = self.data();
|
|
|
|
let mark = span.ctxt.remove_mark();
|
2021-04-18 07:27:04 -05:00
|
|
|
*self = Span::new(span.lo, span.hi, span.ctxt, span.parent);
|
2018-03-17 18:57:23 -05:00
|
|
|
mark
|
|
|
|
}
|
|
|
|
|
|
|
|
#[inline]
|
2019-07-15 17:42:58 -05:00
|
|
|
pub fn adjust(&mut self, expn_id: ExpnId) -> Option<ExpnId> {
|
2018-03-17 18:57:23 -05:00
|
|
|
let mut span = self.data();
|
2019-07-15 17:42:58 -05:00
|
|
|
let mark = span.ctxt.adjust(expn_id);
|
2021-04-18 07:27:04 -05:00
|
|
|
*self = Span::new(span.lo, span.hi, span.ctxt, span.parent);
|
2018-03-17 18:57:23 -05:00
|
|
|
mark
|
|
|
|
}
|
|
|
|
|
2019-06-03 01:10:03 -05:00
|
|
|
#[inline]
|
2020-03-13 17:36:46 -05:00
|
|
|
pub fn normalize_to_macros_2_0_and_adjust(&mut self, expn_id: ExpnId) -> Option<ExpnId> {
|
2019-06-03 01:10:03 -05:00
|
|
|
let mut span = self.data();
|
2020-03-13 17:36:46 -05:00
|
|
|
let mark = span.ctxt.normalize_to_macros_2_0_and_adjust(expn_id);
|
2021-04-18 07:27:04 -05:00
|
|
|
*self = Span::new(span.lo, span.hi, span.ctxt, span.parent);
|
2019-06-03 01:10:03 -05:00
|
|
|
mark
|
|
|
|
}
|
|
|
|
|
2018-03-17 18:57:23 -05:00
|
|
|
#[inline]
|
2019-07-15 17:42:58 -05:00
|
|
|
pub fn glob_adjust(&mut self, expn_id: ExpnId, glob_span: Span) -> Option<Option<ExpnId>> {
|
2018-03-17 18:57:23 -05:00
|
|
|
let mut span = self.data();
|
2019-07-15 17:42:58 -05:00
|
|
|
let mark = span.ctxt.glob_adjust(expn_id, glob_span);
|
2021-04-18 07:27:04 -05:00
|
|
|
*self = Span::new(span.lo, span.hi, span.ctxt, span.parent);
|
2018-03-17 18:57:23 -05:00
|
|
|
mark
|
|
|
|
}
|
|
|
|
|
|
|
|
#[inline]
|
2019-07-15 17:42:58 -05:00
|
|
|
pub fn reverse_glob_adjust(
|
|
|
|
&mut self,
|
|
|
|
expn_id: ExpnId,
|
|
|
|
glob_span: Span,
|
2019-07-15 17:04:05 -05:00
|
|
|
) -> Option<Option<ExpnId>> {
|
2018-03-17 18:57:23 -05:00
|
|
|
let mut span = self.data();
|
2019-07-15 17:42:58 -05:00
|
|
|
let mark = span.ctxt.reverse_glob_adjust(expn_id, glob_span);
|
2021-04-18 07:27:04 -05:00
|
|
|
*self = Span::new(span.lo, span.hi, span.ctxt, span.parent);
|
2018-03-17 18:57:23 -05:00
|
|
|
mark
|
|
|
|
}
|
|
|
|
|
|
|
|
#[inline]
|
2020-03-13 17:36:46 -05:00
|
|
|
pub fn normalize_to_macros_2_0(self) -> Span {
|
2018-03-17 18:57:23 -05:00
|
|
|
let span = self.data();
|
2020-03-13 17:36:46 -05:00
|
|
|
span.with_ctxt(span.ctxt.normalize_to_macros_2_0())
|
2018-03-17 18:57:23 -05:00
|
|
|
}
|
2018-06-24 11:54:23 -05:00
|
|
|
|
|
|
|
#[inline]
|
2020-03-13 17:36:46 -05:00
|
|
|
pub fn normalize_to_macro_rules(self) -> Span {
|
2018-06-24 11:54:23 -05:00
|
|
|
let span = self.data();
|
2020-03-13 17:36:46 -05:00
|
|
|
span.with_ctxt(span.ctxt.normalize_to_macro_rules())
|
2018-06-24 11:54:23 -05:00
|
|
|
}
|
2016-06-21 17:08:13 -05:00
|
|
|
}
|
|
|
|
|
2017-07-23 12:50:56 -05:00
|
|
|
impl Default for Span {
|
|
|
|
fn default() -> Self {
|
|
|
|
DUMMY_SP
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-06-11 09:49:57 -05:00
|
|
|
impl<E: Encoder> Encodable<E> for Span {
|
Use delayed error handling for `Encodable` and `Encoder` infallible.
There are two impls of the `Encoder` trait: `opaque::Encoder` and
`opaque::FileEncoder`. The former encodes into memory and is infallible, the
latter writes to file and is fallible.
Currently, standard `Result`/`?`/`unwrap` error handling is used, but this is a
bit verbose and has non-trivial cost, which is annoying given how rare failures
are (especially in the infallible `opaque::Encoder` case).
This commit changes how `Encoder` fallibility is handled. All the `emit_*`
methods are now infallible. `opaque::Encoder` requires no great changes for
this. `opaque::FileEncoder` now implements a delayed error handling strategy.
If a failure occurs, it records this via the `res` field, and all subsequent
encoding operations are skipped if `res` indicates an error has occurred. Once
encoding is complete, the new `finish` method is called, which returns a
`Result`. In other words, there is now a single `Result`-producing method
instead of many of them.
This has very little effect on how any file errors are reported if
`opaque::FileEncoder` has any failures.
Much of this commit is boring mechanical changes, removing `Result` return
values and `?` or `unwrap` from expressions. The more interesting parts are as
follows.
- serialize.rs: The `Encoder` trait gains an `Ok` associated type. The
`into_inner` method is changed into `finish`, which returns
`Result<Vec<u8>, !>`.
- opaque.rs: The `FileEncoder` adopts the delayed error handling
strategy. Its `Ok` type is a `usize`, returning the number of bytes
written, replacing previous uses of `FileEncoder::position`.
- Various methods that take an encoder now consume it, rather than being
passed a mutable reference, e.g. `serialize_query_result_cache`.
2022-06-06 22:30:45 -05:00
|
|
|
default fn encode(&self, s: &mut E) {
|
2017-10-21 09:21:02 -05:00
|
|
|
let span = self.data();
|
Use delayed error handling for `Encodable` and `Encoder` infallible.
There are two impls of the `Encoder` trait: `opaque::Encoder` and
`opaque::FileEncoder`. The former encodes into memory and is infallible, the
latter writes to file and is fallible.
Currently, standard `Result`/`?`/`unwrap` error handling is used, but this is a
bit verbose and has non-trivial cost, which is annoying given how rare failures
are (especially in the infallible `opaque::Encoder` case).
This commit changes how `Encoder` fallibility is handled. All the `emit_*`
methods are now infallible. `opaque::Encoder` requires no great changes for
this. `opaque::FileEncoder` now implements a delayed error handling strategy.
If a failure occurs, it records this via the `res` field, and all subsequent
encoding operations are skipped if `res` indicates an error has occurred. Once
encoding is complete, the new `finish` method is called, which returns a
`Result`. In other words, there is now a single `Result`-producing method
instead of many of them.
This has very little effect on how any file errors are reported if
`opaque::FileEncoder` has any failures.
Much of this commit is boring mechanical changes, removing `Result` return
values and `?` or `unwrap` from expressions. The more interesting parts are as
follows.
- serialize.rs: The `Encoder` trait gains an `Ok` associated type. The
`into_inner` method is changed into `finish`, which returns
`Result<Vec<u8>, !>`.
- opaque.rs: The `FileEncoder` adopts the delayed error handling
strategy. Its `Ok` type is a `usize`, returning the number of bytes
written, replacing previous uses of `FileEncoder::position`.
- Various methods that take an encoder now consume it, rather than being
passed a mutable reference, e.g. `serialize_query_result_cache`.
2022-06-06 22:30:45 -05:00
|
|
|
span.lo.encode(s);
|
|
|
|
span.hi.encode(s);
|
2016-06-21 17:08:13 -05:00
|
|
|
}
|
|
|
|
}
|
2020-06-11 09:49:57 -05:00
|
|
|
impl<D: Decoder> Decodable<D> for Span {
|
Make `Decodable` and `Decoder` infallible.
`Decoder` has two impls:
- opaque: this impl is already partly infallible, i.e. in some places it
currently panics on failure (e.g. if the input is too short, or on a
bad `Result` discriminant), and in some places it returns an error
(e.g. on a bad `Option` discriminant). The number of places where
either happens is surprisingly small, just because the binary
representation has very little redundancy and a lot of input reading
can occur even on malformed data.
- json: this impl is fully fallible, but it's only used (a) for the
`.rlink` file production, and there's a `FIXME` comment suggesting it
should change to a binary format, and (b) in a few tests in
non-fundamental ways. Indeed #85993 is open to remove it entirely.
And the top-level places in the compiler that call into decoding just
abort on error anyway. So the fallibility is providing little value, and
getting rid of it leads to some non-trivial performance improvements.
Much of this commit is pretty boring and mechanical. Some notes about
a few interesting parts:
- The commit removes `Decoder::{Error,error}`.
- `InternIteratorElement::intern_with`: the impl for `T` now has the same
optimization for small counts that the impl for `Result<T, E>` has,
because it's now much hotter.
- Decodable impls for SmallVec, LinkedList, VecDeque now all use
`collect`, which is nice; the one for `Vec` uses unsafe code, because
that gave better perf on some benchmarks.
2022-01-17 20:22:50 -06:00
|
|
|
default fn decode(s: &mut D) -> Span {
|
2022-02-09 16:26:17 -06:00
|
|
|
let lo = Decodable::decode(s);
|
|
|
|
let hi = Decodable::decode(s);
|
2020-06-11 09:49:57 -05:00
|
|
|
|
2022-02-09 16:20:43 -06:00
|
|
|
Span::new(lo, hi, SyntaxContext::root(), None)
|
2016-09-17 15:31:03 -05:00
|
|
|
}
|
|
|
|
}
|
2016-06-21 17:08:13 -05:00
|
|
|
|
2020-05-26 12:21:58 -05:00
|
|
|
/// Calls the provided closure, using the provided `SourceMap` to format
|
2020-10-27 10:55:20 -05:00
|
|
|
/// any spans that are debug-printed during the closure's execution.
|
2020-05-26 12:21:58 -05:00
|
|
|
///
|
|
|
|
/// Normally, the global `TyCtxt` is used to retrieve the `SourceMap`
|
2020-12-24 01:01:03 -06:00
|
|
|
/// (see `rustc_interface::callbacks::span_debug1`). However, some parts
|
2020-05-26 12:21:58 -05:00
|
|
|
/// of the compiler (e.g. `rustc_parse`) may debug-print `Span`s before
|
|
|
|
/// a `TyCtxt` is available. In this case, we fall back to
|
|
|
|
/// the `SourceMap` provided to this function. If that is not available,
|
2020-10-27 10:55:20 -05:00
|
|
|
/// we fall back to printing the raw `Span` field values.
|
2020-05-26 12:21:58 -05:00
|
|
|
pub fn with_source_map<T, F: FnOnce() -> T>(source_map: Lrc<SourceMap>, f: F) -> T {
|
2021-05-05 14:31:25 -05:00
|
|
|
with_session_globals(|session_globals| {
|
2020-07-05 19:53:14 -05:00
|
|
|
*session_globals.source_map.borrow_mut() = Some(source_map);
|
2020-05-26 12:21:58 -05:00
|
|
|
});
|
|
|
|
struct ClearSourceMap;
|
|
|
|
impl Drop for ClearSourceMap {
|
|
|
|
fn drop(&mut self) {
|
2021-05-05 14:31:25 -05:00
|
|
|
with_session_globals(|session_globals| {
|
2020-07-05 19:53:14 -05:00
|
|
|
session_globals.source_map.borrow_mut().take();
|
2020-05-26 12:21:58 -05:00
|
|
|
});
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
let _guard = ClearSourceMap;
|
|
|
|
f()
|
|
|
|
}
|
|
|
|
|
2016-06-21 17:08:13 -05:00
|
|
|
impl fmt::Debug for Span {
|
2019-02-03 12:42:27 -06:00
|
|
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
2022-01-14 12:34:01 -06:00
|
|
|
with_session_globals(|session_globals| {
|
|
|
|
if let Some(source_map) = &*session_globals.source_map.borrow() {
|
|
|
|
write!(f, "{} ({:?})", source_map.span_to_diagnostic_string(*self), self.ctxt())
|
|
|
|
} else {
|
|
|
|
f.debug_struct("Span")
|
|
|
|
.field("lo", &self.lo())
|
|
|
|
.field("hi", &self.hi())
|
|
|
|
.field("ctxt", &self.ctxt())
|
|
|
|
.finish()
|
|
|
|
}
|
|
|
|
})
|
2016-06-21 17:08:13 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-09-16 13:43:05 -05:00
|
|
|
impl fmt::Debug for SpanData {
|
2019-02-03 12:42:27 -06:00
|
|
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
2022-01-14 12:34:01 -06:00
|
|
|
fmt::Debug::fmt(&Span::new(self.lo, self.hi, self.ctxt, self.parent), f)
|
2017-09-16 13:43:05 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-11-26 20:59:49 -06:00
|
|
|
/// Identifies an offset of a multi-byte character in a `SourceFile`.
|
2020-06-11 09:49:57 -05:00
|
|
|
#[derive(Copy, Clone, Encodable, Decodable, Eq, PartialEq, Debug)]
|
2016-06-21 17:08:13 -05:00
|
|
|
pub struct MultiByteChar {
|
2018-11-26 20:59:49 -06:00
|
|
|
/// The absolute offset of the character in the `SourceMap`.
|
2016-06-21 17:08:13 -05:00
|
|
|
pub pos: BytePos,
|
2018-11-26 20:59:49 -06:00
|
|
|
/// The number of bytes, `>= 2`.
|
2018-06-26 08:37:09 -05:00
|
|
|
pub bytes: u8,
|
2016-06-21 17:08:13 -05:00
|
|
|
}
|
|
|
|
|
2018-11-26 20:59:49 -06:00
|
|
|
/// Identifies an offset of a non-narrow character in a `SourceFile`.
|
2020-06-11 09:49:57 -05:00
|
|
|
#[derive(Copy, Clone, Encodable, Decodable, Eq, PartialEq, Debug)]
|
2017-11-01 20:25:54 -05:00
|
|
|
pub enum NonNarrowChar {
|
2018-11-26 20:59:49 -06:00
|
|
|
/// Represents a zero-width character.
|
2017-11-01 20:25:54 -05:00
|
|
|
ZeroWidth(BytePos),
|
2018-11-26 20:59:49 -06:00
|
|
|
/// Represents a wide (full-width) character.
|
2017-11-01 20:25:54 -05:00
|
|
|
Wide(BytePos),
|
2018-11-26 20:59:49 -06:00
|
|
|
/// Represents a tab character, represented visually with a width of 4 characters.
|
2017-11-13 00:06:00 -06:00
|
|
|
Tab(BytePos),
|
2017-11-01 20:25:54 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
impl NonNarrowChar {
|
|
|
|
fn new(pos: BytePos, width: usize) -> Self {
|
|
|
|
match width {
|
|
|
|
0 => NonNarrowChar::ZeroWidth(pos),
|
|
|
|
2 => NonNarrowChar::Wide(pos),
|
2017-11-13 00:06:00 -06:00
|
|
|
4 => NonNarrowChar::Tab(pos),
|
2017-11-01 20:25:54 -05:00
|
|
|
_ => panic!("width {} given for non-narrow character", width),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-11-26 20:59:49 -06:00
|
|
|
/// Returns the absolute offset of the character in the `SourceMap`.
|
2017-11-01 20:25:54 -05:00
|
|
|
pub fn pos(&self) -> BytePos {
|
|
|
|
match *self {
|
|
|
|
NonNarrowChar::ZeroWidth(p) | NonNarrowChar::Wide(p) | NonNarrowChar::Tab(p) => p,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-11-26 20:59:49 -06:00
|
|
|
/// Returns the width of the character, 0 (zero-width) or 2 (wide).
|
2017-11-01 20:25:54 -05:00
|
|
|
pub fn width(&self) -> usize {
|
|
|
|
match *self {
|
|
|
|
NonNarrowChar::ZeroWidth(_) => 0,
|
|
|
|
NonNarrowChar::Wide(_) => 2,
|
2017-11-13 00:06:00 -06:00
|
|
|
NonNarrowChar::Tab(_) => 4,
|
2017-11-01 20:25:54 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl Add<BytePos> for NonNarrowChar {
|
|
|
|
type Output = Self;
|
|
|
|
|
|
|
|
fn add(self, rhs: BytePos) -> Self {
|
|
|
|
match self {
|
|
|
|
NonNarrowChar::ZeroWidth(pos) => NonNarrowChar::ZeroWidth(pos + rhs),
|
|
|
|
NonNarrowChar::Wide(pos) => NonNarrowChar::Wide(pos + rhs),
|
2017-11-13 00:06:00 -06:00
|
|
|
NonNarrowChar::Tab(pos) => NonNarrowChar::Tab(pos + rhs),
|
2017-11-01 20:25:54 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl Sub<BytePos> for NonNarrowChar {
|
|
|
|
type Output = Self;
|
|
|
|
|
|
|
|
fn sub(self, rhs: BytePos) -> Self {
|
|
|
|
match self {
|
|
|
|
NonNarrowChar::ZeroWidth(pos) => NonNarrowChar::ZeroWidth(pos - rhs),
|
|
|
|
NonNarrowChar::Wide(pos) => NonNarrowChar::Wide(pos - rhs),
|
2017-11-13 00:06:00 -06:00
|
|
|
NonNarrowChar::Tab(pos) => NonNarrowChar::Tab(pos - rhs),
|
2017-11-01 20:25:54 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-10-02 19:55:31 -05:00
|
|
|
/// Identifies an offset of a character that was normalized away from `SourceFile`.
|
2020-06-11 09:49:57 -05:00
|
|
|
#[derive(Copy, Clone, Encodable, Decodable, Eq, PartialEq, Debug)]
|
2019-10-02 19:55:31 -05:00
|
|
|
pub struct NormalizedPos {
|
|
|
|
/// The absolute offset of the character in the `SourceMap`.
|
|
|
|
pub pos: BytePos,
|
|
|
|
/// The difference between original and normalized string at position.
|
|
|
|
pub diff: u32,
|
|
|
|
}
|
|
|
|
|
2020-02-07 13:02:24 -06:00
|
|
|
#[derive(PartialEq, Eq, Clone, Debug)]
|
2017-06-10 14:08:32 -05:00
|
|
|
pub enum ExternalSource {
|
2020-02-07 13:02:24 -06:00
|
|
|
/// No external source has to be loaded, since the `SourceFile` represents a local crate.
|
|
|
|
Unneeded,
|
|
|
|
Foreign {
|
|
|
|
kind: ExternalSourceKind,
|
2020-12-24 01:01:03 -06:00
|
|
|
/// This SourceFile's byte-offset within the source_map of its original crate.
|
2020-02-07 13:02:24 -06:00
|
|
|
original_start_pos: BytePos,
|
2020-12-24 01:01:03 -06:00
|
|
|
/// The end of this SourceFile within the source_map of its original crate.
|
2020-02-07 13:02:24 -06:00
|
|
|
original_end_pos: BytePos,
|
|
|
|
},
|
|
|
|
}
|
|
|
|
|
|
|
|
/// The state of the lazy external source loading mechanism of a `SourceFile`.
|
|
|
|
#[derive(PartialEq, Eq, Clone, Debug)]
|
|
|
|
pub enum ExternalSourceKind {
|
2017-06-11 03:19:46 -05:00
|
|
|
/// The external source has been loaded already.
|
2020-03-20 01:00:06 -05:00
|
|
|
Present(Lrc<String>),
|
2017-06-11 03:19:46 -05:00
|
|
|
/// No attempt has been made to load the external source.
|
2017-06-10 14:08:32 -05:00
|
|
|
AbsentOk,
|
2017-06-11 03:19:46 -05:00
|
|
|
/// A failed attempt has been made to load the external source.
|
2017-06-10 14:08:32 -05:00
|
|
|
AbsentErr,
|
|
|
|
Unneeded,
|
|
|
|
}
|
|
|
|
|
2017-06-11 03:19:46 -05:00
|
|
|
impl ExternalSource {
|
2020-03-20 01:00:06 -05:00
|
|
|
pub fn get_source(&self) -> Option<&Lrc<String>> {
|
2020-02-07 13:02:24 -06:00
|
|
|
match self {
|
|
|
|
ExternalSource::Foreign { kind: ExternalSourceKind::Present(ref src), .. } => Some(src),
|
2017-06-11 03:19:46 -05:00
|
|
|
_ => None,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-06-17 03:35:26 -05:00
|
|
|
#[derive(Debug)]
|
|
|
|
pub struct OffsetOverflowError;
|
|
|
|
|
2020-06-11 09:49:57 -05:00
|
|
|
#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Encodable, Decodable)]
|
2022-04-19 03:43:09 -05:00
|
|
|
#[derive(HashStable_Generic)]
|
2020-03-31 00:17:15 -05:00
|
|
|
pub enum SourceFileHashAlgorithm {
|
|
|
|
Md5,
|
|
|
|
Sha1,
|
2020-10-13 10:41:06 -05:00
|
|
|
Sha256,
|
2020-03-31 00:17:15 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
impl FromStr for SourceFileHashAlgorithm {
|
|
|
|
type Err = ();
|
|
|
|
|
|
|
|
fn from_str(s: &str) -> Result<SourceFileHashAlgorithm, ()> {
|
|
|
|
match s {
|
|
|
|
"md5" => Ok(SourceFileHashAlgorithm::Md5),
|
|
|
|
"sha1" => Ok(SourceFileHashAlgorithm::Sha1),
|
2020-10-13 10:41:06 -05:00
|
|
|
"sha256" => Ok(SourceFileHashAlgorithm::Sha256),
|
2020-03-31 00:17:15 -05:00
|
|
|
_ => Err(()),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/// The hash of the on-disk source file used for debug info.
|
2022-05-05 10:26:22 -05:00
|
|
|
#[derive(Copy, Clone, PartialEq, Eq, Debug, Hash)]
|
2020-06-11 09:49:57 -05:00
|
|
|
#[derive(HashStable_Generic, Encodable, Decodable)]
|
2020-03-31 00:17:15 -05:00
|
|
|
pub struct SourceFileHash {
|
|
|
|
pub kind: SourceFileHashAlgorithm,
|
2020-10-13 10:41:06 -05:00
|
|
|
value: [u8; 32],
|
2020-03-31 00:17:15 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
impl SourceFileHash {
|
|
|
|
pub fn new(kind: SourceFileHashAlgorithm, src: &str) -> SourceFileHash {
|
|
|
|
let mut hash = SourceFileHash { kind, value: Default::default() };
|
|
|
|
let len = hash.hash_len();
|
|
|
|
let value = &mut hash.value[..len];
|
|
|
|
let data = src.as_bytes();
|
|
|
|
match kind {
|
|
|
|
SourceFileHashAlgorithm::Md5 => {
|
|
|
|
value.copy_from_slice(&Md5::digest(data));
|
|
|
|
}
|
|
|
|
SourceFileHashAlgorithm::Sha1 => {
|
|
|
|
value.copy_from_slice(&Sha1::digest(data));
|
|
|
|
}
|
2020-10-13 10:41:06 -05:00
|
|
|
SourceFileHashAlgorithm::Sha256 => {
|
|
|
|
value.copy_from_slice(&Sha256::digest(data));
|
|
|
|
}
|
2020-03-31 00:17:15 -05:00
|
|
|
}
|
|
|
|
hash
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Check if the stored hash matches the hash of the string.
|
|
|
|
pub fn matches(&self, src: &str) -> bool {
|
|
|
|
Self::new(self.kind, src) == *self
|
|
|
|
}
|
|
|
|
|
|
|
|
/// The bytes of the hash.
|
|
|
|
pub fn hash_bytes(&self) -> &[u8] {
|
|
|
|
let len = self.hash_len();
|
|
|
|
&self.value[..len]
|
|
|
|
}
|
|
|
|
|
|
|
|
fn hash_len(&self) -> usize {
|
|
|
|
match self.kind {
|
|
|
|
SourceFileHashAlgorithm::Md5 => 16,
|
|
|
|
SourceFileHashAlgorithm::Sha1 => 20,
|
2020-10-13 10:41:06 -05:00
|
|
|
SourceFileHashAlgorithm::Sha256 => 32,
|
2020-03-31 00:17:15 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-04-25 20:02:43 -05:00
|
|
|
#[derive(HashStable_Generic)]
|
|
|
|
#[derive(Copy, PartialEq, PartialOrd, Clone, Ord, Eq, Hash, Debug, Encodable, Decodable)]
|
|
|
|
pub enum DebuggerVisualizerType {
|
|
|
|
Natvis,
|
2022-05-24 13:14:48 -05:00
|
|
|
GdbPrettyPrinter,
|
2022-04-25 20:02:43 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
/// A single debugger visualizer file.
|
|
|
|
#[derive(HashStable_Generic)]
|
|
|
|
#[derive(Clone, Debug, Hash, PartialEq, Eq, PartialOrd, Ord, Encodable, Decodable)]
|
|
|
|
pub struct DebuggerVisualizerFile {
|
|
|
|
/// The complete debugger visualizer source.
|
|
|
|
pub src: Arc<[u8]>,
|
|
|
|
/// Indicates which visualizer type this targets.
|
|
|
|
pub visualizer_type: DebuggerVisualizerType,
|
|
|
|
}
|
|
|
|
|
|
|
|
impl DebuggerVisualizerFile {
|
|
|
|
pub fn new(src: Arc<[u8]>, visualizer_type: DebuggerVisualizerType) -> Self {
|
|
|
|
DebuggerVisualizerFile { src, visualizer_type }
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-05-30 00:59:45 -05:00
|
|
|
#[derive(Clone)]
|
|
|
|
pub enum SourceFileLines {
|
|
|
|
/// The source file lines, in decoded (random-access) form.
|
2022-06-01 20:43:14 -05:00
|
|
|
Lines(Vec<BytePos>),
|
2022-05-30 00:59:45 -05:00
|
|
|
|
2022-06-01 20:43:14 -05:00
|
|
|
/// The source file lines, in undecoded difference list form.
|
|
|
|
Diffs(SourceFileDiffs),
|
|
|
|
}
|
|
|
|
|
|
|
|
impl SourceFileLines {
|
|
|
|
pub fn is_lines(&self) -> bool {
|
|
|
|
matches!(self, SourceFileLines::Lines(_))
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/// The source file lines in difference list form. This matches the form
|
|
|
|
/// used within metadata, which saves space by exploiting the fact that the
|
|
|
|
/// lines list is sorted and individual lines are usually not that long.
|
|
|
|
///
|
|
|
|
/// We read it directly from metadata and only decode it into `Lines` form
|
|
|
|
/// when necessary. This is a significant performance win, especially for
|
|
|
|
/// small crates where very little of `std`'s metadata is used.
|
|
|
|
#[derive(Clone)]
|
|
|
|
pub struct SourceFileDiffs {
|
|
|
|
/// Position of the first line. Note that this is always encoded as a
|
|
|
|
/// `BytePos` because it is often much larger than any of the
|
|
|
|
/// differences.
|
|
|
|
line_start: BytePos,
|
|
|
|
|
|
|
|
/// Always 1, 2, or 4. Always as small as possible, while being big
|
|
|
|
/// enough to hold the length of the longest line in the source file.
|
|
|
|
/// The 1 case is by far the most common.
|
|
|
|
bytes_per_diff: usize,
|
|
|
|
|
|
|
|
/// The number of diffs encoded in `raw_diffs`. Always one less than
|
|
|
|
/// the number of lines in the source file.
|
|
|
|
num_diffs: usize,
|
|
|
|
|
|
|
|
/// The diffs in "raw" form. Each segment of `bytes_per_diff` length
|
|
|
|
/// encodes one little-endian diff. Note that they aren't LEB128
|
|
|
|
/// encoded. This makes for much faster decoding. Besides, the
|
|
|
|
/// bytes_per_diff==1 case is by far the most common, and LEB128
|
|
|
|
/// encoding has no effect on that case.
|
|
|
|
raw_diffs: Vec<u8>,
|
2022-05-30 00:59:45 -05:00
|
|
|
}
|
|
|
|
|
2020-12-24 01:01:03 -06:00
|
|
|
/// A single source in the [`SourceMap`].
|
2017-04-24 12:01:19 -05:00
|
|
|
#[derive(Clone)]
|
2018-08-18 05:13:52 -05:00
|
|
|
pub struct SourceFile {
|
2019-09-29 19:06:00 -05:00
|
|
|
/// The name of the file that the source came from. Source that doesn't
|
2018-11-26 20:59:49 -06:00
|
|
|
/// originate from files has names between angle brackets by convention
|
|
|
|
/// (e.g., `<anon>`).
|
2016-06-21 17:08:13 -05:00
|
|
|
pub name: FileName,
|
2018-11-26 20:59:49 -06:00
|
|
|
/// The complete source code.
|
2018-02-27 10:11:14 -06:00
|
|
|
pub src: Option<Lrc<String>>,
|
2018-11-26 20:59:49 -06:00
|
|
|
/// The source code's hash.
|
2020-03-31 00:17:15 -05:00
|
|
|
pub src_hash: SourceFileHash,
|
2017-06-10 14:08:32 -05:00
|
|
|
/// The external source code (used for external crates, which will have a `None`
|
|
|
|
/// value as `self.src`.
|
2018-03-09 23:40:17 -06:00
|
|
|
pub external_src: Lock<ExternalSource>,
|
2018-11-26 20:59:49 -06:00
|
|
|
/// The start position of this source in the `SourceMap`.
|
2016-06-21 17:08:13 -05:00
|
|
|
pub start_pos: BytePos,
|
2018-11-26 20:59:49 -06:00
|
|
|
/// The end position of this source in the `SourceMap`.
|
2016-06-21 17:08:13 -05:00
|
|
|
pub end_pos: BytePos,
|
2018-11-26 20:59:49 -06:00
|
|
|
/// Locations of lines beginnings in the source code.
|
2022-05-30 00:59:45 -05:00
|
|
|
pub lines: Lock<SourceFileLines>,
|
2018-11-26 20:59:49 -06:00
|
|
|
/// Locations of multi-byte characters in the source code.
|
2018-05-23 08:59:42 -05:00
|
|
|
pub multibyte_chars: Vec<MultiByteChar>,
|
2018-11-26 20:59:49 -06:00
|
|
|
/// Width of characters that are not narrow in the source code.
|
2018-05-23 08:59:42 -05:00
|
|
|
pub non_narrow_chars: Vec<NonNarrowChar>,
|
2019-10-02 19:55:31 -05:00
|
|
|
/// Locations of characters removed during normalization.
|
|
|
|
pub normalized_pos: Vec<NormalizedPos>,
|
2018-11-26 20:59:49 -06:00
|
|
|
/// A hash of the filename, used for speeding up hashing in incremental compilation.
|
2017-12-19 08:14:41 -06:00
|
|
|
pub name_hash: u128,
|
2020-02-07 13:02:24 -06:00
|
|
|
/// Indicates which crate this `SourceFile` was imported from.
|
|
|
|
pub cnum: CrateNum,
|
2016-06-21 17:08:13 -05:00
|
|
|
}
|
|
|
|
|
2020-06-11 09:49:57 -05:00
|
|
|
impl<S: Encoder> Encodable<S> for SourceFile {
|
Use delayed error handling for `Encodable` and `Encoder` infallible.
There are two impls of the `Encoder` trait: `opaque::Encoder` and
`opaque::FileEncoder`. The former encodes into memory and is infallible, the
latter writes to file and is fallible.
Currently, standard `Result`/`?`/`unwrap` error handling is used, but this is a
bit verbose and has non-trivial cost, which is annoying given how rare failures
are (especially in the infallible `opaque::Encoder` case).
This commit changes how `Encoder` fallibility is handled. All the `emit_*`
methods are now infallible. `opaque::Encoder` requires no great changes for
this. `opaque::FileEncoder` now implements a delayed error handling strategy.
If a failure occurs, it records this via the `res` field, and all subsequent
encoding operations are skipped if `res` indicates an error has occurred. Once
encoding is complete, the new `finish` method is called, which returns a
`Result`. In other words, there is now a single `Result`-producing method
instead of many of them.
This has very little effect on how any file errors are reported if
`opaque::FileEncoder` has any failures.
Much of this commit is boring mechanical changes, removing `Result` return
values and `?` or `unwrap` from expressions. The more interesting parts are as
follows.
- serialize.rs: The `Encoder` trait gains an `Ok` associated type. The
`into_inner` method is changed into `finish`, which returns
`Result<Vec<u8>, !>`.
- opaque.rs: The `FileEncoder` adopts the delayed error handling
strategy. Its `Ok` type is a `usize`, returning the number of bytes
written, replacing previous uses of `FileEncoder::position`.
- Various methods that take an encoder now consume it, rather than being
passed a mutable reference, e.g. `serialize_query_result_cache`.
2022-06-06 22:30:45 -05:00
|
|
|
fn encode(&self, s: &mut S) {
|
|
|
|
self.name.encode(s);
|
|
|
|
self.src_hash.encode(s);
|
|
|
|
self.start_pos.encode(s);
|
|
|
|
self.end_pos.encode(s);
|
2021-06-04 11:23:50 -05:00
|
|
|
|
|
|
|
// We are always in `Lines` form by the time we reach here.
|
|
|
|
assert!(self.lines.borrow().is_lines());
|
|
|
|
self.lines(|lines| {
|
|
|
|
// Store the length.
|
Use delayed error handling for `Encodable` and `Encoder` infallible.
There are two impls of the `Encoder` trait: `opaque::Encoder` and
`opaque::FileEncoder`. The former encodes into memory and is infallible, the
latter writes to file and is fallible.
Currently, standard `Result`/`?`/`unwrap` error handling is used, but this is a
bit verbose and has non-trivial cost, which is annoying given how rare failures
are (especially in the infallible `opaque::Encoder` case).
This commit changes how `Encoder` fallibility is handled. All the `emit_*`
methods are now infallible. `opaque::Encoder` requires no great changes for
this. `opaque::FileEncoder` now implements a delayed error handling strategy.
If a failure occurs, it records this via the `res` field, and all subsequent
encoding operations are skipped if `res` indicates an error has occurred. Once
encoding is complete, the new `finish` method is called, which returns a
`Result`. In other words, there is now a single `Result`-producing method
instead of many of them.
This has very little effect on how any file errors are reported if
`opaque::FileEncoder` has any failures.
Much of this commit is boring mechanical changes, removing `Result` return
values and `?` or `unwrap` from expressions. The more interesting parts are as
follows.
- serialize.rs: The `Encoder` trait gains an `Ok` associated type. The
`into_inner` method is changed into `finish`, which returns
`Result<Vec<u8>, !>`.
- opaque.rs: The `FileEncoder` adopts the delayed error handling
strategy. Its `Ok` type is a `usize`, returning the number of bytes
written, replacing previous uses of `FileEncoder::position`.
- Various methods that take an encoder now consume it, rather than being
passed a mutable reference, e.g. `serialize_query_result_cache`.
2022-06-06 22:30:45 -05:00
|
|
|
s.emit_u32(lines.len() as u32);
|
2021-06-04 11:23:50 -05:00
|
|
|
|
|
|
|
// Compute and store the difference list.
|
|
|
|
if lines.len() != 0 {
|
|
|
|
let max_line_length = if lines.len() == 1 {
|
|
|
|
0
|
|
|
|
} else {
|
|
|
|
lines
|
|
|
|
.array_windows()
|
|
|
|
.map(|&[fst, snd]| snd - fst)
|
|
|
|
.map(|bp| bp.to_usize())
|
|
|
|
.max()
|
|
|
|
.unwrap()
|
|
|
|
};
|
|
|
|
|
|
|
|
let bytes_per_diff: usize = match max_line_length {
|
|
|
|
0..=0xFF => 1,
|
|
|
|
0x100..=0xFFFF => 2,
|
|
|
|
_ => 4,
|
|
|
|
};
|
|
|
|
|
|
|
|
// Encode the number of bytes used per diff.
|
Use delayed error handling for `Encodable` and `Encoder` infallible.
There are two impls of the `Encoder` trait: `opaque::Encoder` and
`opaque::FileEncoder`. The former encodes into memory and is infallible, the
latter writes to file and is fallible.
Currently, standard `Result`/`?`/`unwrap` error handling is used, but this is a
bit verbose and has non-trivial cost, which is annoying given how rare failures
are (especially in the infallible `opaque::Encoder` case).
This commit changes how `Encoder` fallibility is handled. All the `emit_*`
methods are now infallible. `opaque::Encoder` requires no great changes for
this. `opaque::FileEncoder` now implements a delayed error handling strategy.
If a failure occurs, it records this via the `res` field, and all subsequent
encoding operations are skipped if `res` indicates an error has occurred. Once
encoding is complete, the new `finish` method is called, which returns a
`Result`. In other words, there is now a single `Result`-producing method
instead of many of them.
This has very little effect on how any file errors are reported if
`opaque::FileEncoder` has any failures.
Much of this commit is boring mechanical changes, removing `Result` return
values and `?` or `unwrap` from expressions. The more interesting parts are as
follows.
- serialize.rs: The `Encoder` trait gains an `Ok` associated type. The
`into_inner` method is changed into `finish`, which returns
`Result<Vec<u8>, !>`.
- opaque.rs: The `FileEncoder` adopts the delayed error handling
strategy. Its `Ok` type is a `usize`, returning the number of bytes
written, replacing previous uses of `FileEncoder::position`.
- Various methods that take an encoder now consume it, rather than being
passed a mutable reference, e.g. `serialize_query_result_cache`.
2022-06-06 22:30:45 -05:00
|
|
|
s.emit_u8(bytes_per_diff as u8);
|
2021-06-04 11:23:50 -05:00
|
|
|
|
|
|
|
// Encode the first element.
|
Use delayed error handling for `Encodable` and `Encoder` infallible.
There are two impls of the `Encoder` trait: `opaque::Encoder` and
`opaque::FileEncoder`. The former encodes into memory and is infallible, the
latter writes to file and is fallible.
Currently, standard `Result`/`?`/`unwrap` error handling is used, but this is a
bit verbose and has non-trivial cost, which is annoying given how rare failures
are (especially in the infallible `opaque::Encoder` case).
This commit changes how `Encoder` fallibility is handled. All the `emit_*`
methods are now infallible. `opaque::Encoder` requires no great changes for
this. `opaque::FileEncoder` now implements a delayed error handling strategy.
If a failure occurs, it records this via the `res` field, and all subsequent
encoding operations are skipped if `res` indicates an error has occurred. Once
encoding is complete, the new `finish` method is called, which returns a
`Result`. In other words, there is now a single `Result`-producing method
instead of many of them.
This has very little effect on how any file errors are reported if
`opaque::FileEncoder` has any failures.
Much of this commit is boring mechanical changes, removing `Result` return
values and `?` or `unwrap` from expressions. The more interesting parts are as
follows.
- serialize.rs: The `Encoder` trait gains an `Ok` associated type. The
`into_inner` method is changed into `finish`, which returns
`Result<Vec<u8>, !>`.
- opaque.rs: The `FileEncoder` adopts the delayed error handling
strategy. Its `Ok` type is a `usize`, returning the number of bytes
written, replacing previous uses of `FileEncoder::position`.
- Various methods that take an encoder now consume it, rather than being
passed a mutable reference, e.g. `serialize_query_result_cache`.
2022-06-06 22:30:45 -05:00
|
|
|
lines[0].encode(s);
|
2021-06-04 11:23:50 -05:00
|
|
|
|
|
|
|
// Encode the difference list.
|
|
|
|
let diff_iter = lines.array_windows().map(|&[fst, snd]| snd - fst);
|
|
|
|
let num_diffs = lines.len() - 1;
|
|
|
|
let mut raw_diffs;
|
|
|
|
match bytes_per_diff {
|
|
|
|
1 => {
|
|
|
|
raw_diffs = Vec::with_capacity(num_diffs);
|
|
|
|
for diff in diff_iter {
|
|
|
|
raw_diffs.push(diff.0 as u8);
|
2019-12-22 16:42:04 -06:00
|
|
|
}
|
2016-06-21 17:08:13 -05:00
|
|
|
}
|
2021-06-04 11:23:50 -05:00
|
|
|
2 => {
|
|
|
|
raw_diffs = Vec::with_capacity(bytes_per_diff * num_diffs);
|
|
|
|
for diff in diff_iter {
|
|
|
|
raw_diffs.extend_from_slice(&(diff.0 as u16).to_le_bytes());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
4 => {
|
|
|
|
raw_diffs = Vec::with_capacity(bytes_per_diff * num_diffs);
|
|
|
|
for diff in diff_iter {
|
|
|
|
raw_diffs.extend_from_slice(&(diff.0 as u32).to_le_bytes());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
_ => unreachable!(),
|
|
|
|
}
|
Use delayed error handling for `Encodable` and `Encoder` infallible.
There are two impls of the `Encoder` trait: `opaque::Encoder` and
`opaque::FileEncoder`. The former encodes into memory and is infallible, the
latter writes to file and is fallible.
Currently, standard `Result`/`?`/`unwrap` error handling is used, but this is a
bit verbose and has non-trivial cost, which is annoying given how rare failures
are (especially in the infallible `opaque::Encoder` case).
This commit changes how `Encoder` fallibility is handled. All the `emit_*`
methods are now infallible. `opaque::Encoder` requires no great changes for
this. `opaque::FileEncoder` now implements a delayed error handling strategy.
If a failure occurs, it records this via the `res` field, and all subsequent
encoding operations are skipped if `res` indicates an error has occurred. Once
encoding is complete, the new `finish` method is called, which returns a
`Result`. In other words, there is now a single `Result`-producing method
instead of many of them.
This has very little effect on how any file errors are reported if
`opaque::FileEncoder` has any failures.
Much of this commit is boring mechanical changes, removing `Result` return
values and `?` or `unwrap` from expressions. The more interesting parts are as
follows.
- serialize.rs: The `Encoder` trait gains an `Ok` associated type. The
`into_inner` method is changed into `finish`, which returns
`Result<Vec<u8>, !>`.
- opaque.rs: The `FileEncoder` adopts the delayed error handling
strategy. Its `Ok` type is a `usize`, returning the number of bytes
written, replacing previous uses of `FileEncoder::position`.
- Various methods that take an encoder now consume it, rather than being
passed a mutable reference, e.g. `serialize_query_result_cache`.
2022-06-06 22:30:45 -05:00
|
|
|
s.emit_raw_bytes(&raw_diffs);
|
2021-06-04 11:23:50 -05:00
|
|
|
}
|
Use delayed error handling for `Encodable` and `Encoder` infallible.
There are two impls of the `Encoder` trait: `opaque::Encoder` and
`opaque::FileEncoder`. The former encodes into memory and is infallible, the
latter writes to file and is fallible.
Currently, standard `Result`/`?`/`unwrap` error handling is used, but this is a
bit verbose and has non-trivial cost, which is annoying given how rare failures
are (especially in the infallible `opaque::Encoder` case).
This commit changes how `Encoder` fallibility is handled. All the `emit_*`
methods are now infallible. `opaque::Encoder` requires no great changes for
this. `opaque::FileEncoder` now implements a delayed error handling strategy.
If a failure occurs, it records this via the `res` field, and all subsequent
encoding operations are skipped if `res` indicates an error has occurred. Once
encoding is complete, the new `finish` method is called, which returns a
`Result`. In other words, there is now a single `Result`-producing method
instead of many of them.
This has very little effect on how any file errors are reported if
`opaque::FileEncoder` has any failures.
Much of this commit is boring mechanical changes, removing `Result` return
values and `?` or `unwrap` from expressions. The more interesting parts are as
follows.
- serialize.rs: The `Encoder` trait gains an `Ok` associated type. The
`into_inner` method is changed into `finish`, which returns
`Result<Vec<u8>, !>`.
- opaque.rs: The `FileEncoder` adopts the delayed error handling
strategy. Its `Ok` type is a `usize`, returning the number of bytes
written, replacing previous uses of `FileEncoder::position`.
- Various methods that take an encoder now consume it, rather than being
passed a mutable reference, e.g. `serialize_query_result_cache`.
2022-06-06 22:30:45 -05:00
|
|
|
});
|
2021-06-04 11:23:50 -05:00
|
|
|
|
Use delayed error handling for `Encodable` and `Encoder` infallible.
There are two impls of the `Encoder` trait: `opaque::Encoder` and
`opaque::FileEncoder`. The former encodes into memory and is infallible, the
latter writes to file and is fallible.
Currently, standard `Result`/`?`/`unwrap` error handling is used, but this is a
bit verbose and has non-trivial cost, which is annoying given how rare failures
are (especially in the infallible `opaque::Encoder` case).
This commit changes how `Encoder` fallibility is handled. All the `emit_*`
methods are now infallible. `opaque::Encoder` requires no great changes for
this. `opaque::FileEncoder` now implements a delayed error handling strategy.
If a failure occurs, it records this via the `res` field, and all subsequent
encoding operations are skipped if `res` indicates an error has occurred. Once
encoding is complete, the new `finish` method is called, which returns a
`Result`. In other words, there is now a single `Result`-producing method
instead of many of them.
This has very little effect on how any file errors are reported if
`opaque::FileEncoder` has any failures.
Much of this commit is boring mechanical changes, removing `Result` return
values and `?` or `unwrap` from expressions. The more interesting parts are as
follows.
- serialize.rs: The `Encoder` trait gains an `Ok` associated type. The
`into_inner` method is changed into `finish`, which returns
`Result<Vec<u8>, !>`.
- opaque.rs: The `FileEncoder` adopts the delayed error handling
strategy. Its `Ok` type is a `usize`, returning the number of bytes
written, replacing previous uses of `FileEncoder::position`.
- Various methods that take an encoder now consume it, rather than being
passed a mutable reference, e.g. `serialize_query_result_cache`.
2022-06-06 22:30:45 -05:00
|
|
|
self.multibyte_chars.encode(s);
|
|
|
|
self.non_narrow_chars.encode(s);
|
|
|
|
self.name_hash.encode(s);
|
|
|
|
self.normalized_pos.encode(s);
|
|
|
|
self.cnum.encode(s);
|
2016-06-21 17:08:13 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-06-11 09:49:57 -05:00
|
|
|
impl<D: Decoder> Decodable<D> for SourceFile {
|
Make `Decodable` and `Decoder` infallible.
`Decoder` has two impls:
- opaque: this impl is already partly infallible, i.e. in some places it
currently panics on failure (e.g. if the input is too short, or on a
bad `Result` discriminant), and in some places it returns an error
(e.g. on a bad `Option` discriminant). The number of places where
either happens is surprisingly small, just because the binary
representation has very little redundancy and a lot of input reading
can occur even on malformed data.
- json: this impl is fully fallible, but it's only used (a) for the
`.rlink` file production, and there's a `FIXME` comment suggesting it
should change to a binary format, and (b) in a few tests in
non-fundamental ways. Indeed #85993 is open to remove it entirely.
And the top-level places in the compiler that call into decoding just
abort on error anyway. So the fallibility is providing little value, and
getting rid of it leads to some non-trivial performance improvements.
Much of this commit is pretty boring and mechanical. Some notes about
a few interesting parts:
- The commit removes `Decoder::{Error,error}`.
- `InternIteratorElement::intern_with`: the impl for `T` now has the same
optimization for small counts that the impl for `Result<T, E>` has,
because it's now much hotter.
- Decodable impls for SmallVec, LinkedList, VecDeque now all use
`collect`, which is nice; the one for `Vec` uses unsafe code, because
that gave better perf on some benchmarks.
2022-01-17 20:22:50 -06:00
|
|
|
fn decode(d: &mut D) -> SourceFile {
|
2022-02-09 16:26:17 -06:00
|
|
|
let name: FileName = Decodable::decode(d);
|
|
|
|
let src_hash: SourceFileHash = Decodable::decode(d);
|
|
|
|
let start_pos: BytePos = Decodable::decode(d);
|
|
|
|
let end_pos: BytePos = Decodable::decode(d);
|
2022-05-30 00:59:45 -05:00
|
|
|
let lines = {
|
2022-02-09 16:20:43 -06:00
|
|
|
let num_lines: u32 = Decodable::decode(d);
|
|
|
|
if num_lines > 0 {
|
|
|
|
// Read the number of bytes used per diff.
|
2022-05-30 00:59:45 -05:00
|
|
|
let bytes_per_diff = d.read_u8() as usize;
|
2022-02-09 16:20:43 -06:00
|
|
|
|
|
|
|
// Read the first element.
|
2022-05-30 00:59:45 -05:00
|
|
|
let line_start: BytePos = Decodable::decode(d);
|
2022-02-09 16:20:43 -06:00
|
|
|
|
2022-05-30 00:59:45 -05:00
|
|
|
// Read the difference list.
|
|
|
|
let num_diffs = num_lines as usize - 1;
|
|
|
|
let raw_diffs = d.read_raw_bytes(bytes_per_diff * num_diffs).to_vec();
|
2022-06-01 20:43:14 -05:00
|
|
|
SourceFileLines::Diffs(SourceFileDiffs {
|
|
|
|
line_start,
|
|
|
|
bytes_per_diff,
|
|
|
|
num_diffs,
|
|
|
|
raw_diffs,
|
|
|
|
})
|
2022-05-30 00:59:45 -05:00
|
|
|
} else {
|
2022-06-01 20:43:14 -05:00
|
|
|
SourceFileLines::Lines(vec![])
|
Make `Decodable` and `Decoder` infallible.
`Decoder` has two impls:
- opaque: this impl is already partly infallible, i.e. in some places it
currently panics on failure (e.g. if the input is too short, or on a
bad `Result` discriminant), and in some places it returns an error
(e.g. on a bad `Option` discriminant). The number of places where
either happens is surprisingly small, just because the binary
representation has very little redundancy and a lot of input reading
can occur even on malformed data.
- json: this impl is fully fallible, but it's only used (a) for the
`.rlink` file production, and there's a `FIXME` comment suggesting it
should change to a binary format, and (b) in a few tests in
non-fundamental ways. Indeed #85993 is open to remove it entirely.
And the top-level places in the compiler that call into decoding just
abort on error anyway. So the fallibility is providing little value, and
getting rid of it leads to some non-trivial performance improvements.
Much of this commit is pretty boring and mechanical. Some notes about
a few interesting parts:
- The commit removes `Decoder::{Error,error}`.
- `InternIteratorElement::intern_with`: the impl for `T` now has the same
optimization for small counts that the impl for `Result<T, E>` has,
because it's now much hotter.
- Decodable impls for SmallVec, LinkedList, VecDeque now all use
`collect`, which is nice; the one for `Vec` uses unsafe code, because
that gave better perf on some benchmarks.
2022-01-17 20:22:50 -06:00
|
|
|
}
|
2022-02-09 16:26:17 -06:00
|
|
|
};
|
|
|
|
let multibyte_chars: Vec<MultiByteChar> = Decodable::decode(d);
|
|
|
|
let non_narrow_chars: Vec<NonNarrowChar> = Decodable::decode(d);
|
|
|
|
let name_hash: u128 = Decodable::decode(d);
|
|
|
|
let normalized_pos: Vec<NormalizedPos> = Decodable::decode(d);
|
|
|
|
let cnum: CrateNum = Decodable::decode(d);
|
2022-02-09 16:20:43 -06:00
|
|
|
SourceFile {
|
|
|
|
name,
|
|
|
|
start_pos,
|
|
|
|
end_pos,
|
|
|
|
src: None,
|
|
|
|
src_hash,
|
|
|
|
// Unused - the metadata decoder will construct
|
|
|
|
// a new SourceFile, filling in `external_src` properly
|
|
|
|
external_src: Lock::new(ExternalSource::Unneeded),
|
2022-05-30 00:59:45 -05:00
|
|
|
lines: Lock::new(lines),
|
2022-02-09 16:20:43 -06:00
|
|
|
multibyte_chars,
|
|
|
|
non_narrow_chars,
|
|
|
|
normalized_pos,
|
|
|
|
name_hash,
|
|
|
|
cnum,
|
|
|
|
}
|
2016-06-21 17:08:13 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-08-18 05:13:52 -05:00
|
|
|
impl fmt::Debug for SourceFile {
|
2019-02-03 12:42:27 -06:00
|
|
|
fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
|
2021-04-14 08:12:39 -05:00
|
|
|
write!(fmt, "SourceFile({:?})", self.name)
|
2016-06-21 17:08:13 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-08-18 05:13:52 -05:00
|
|
|
impl SourceFile {
|
2017-06-10 09:09:51 -05:00
|
|
|
pub fn new(
|
|
|
|
name: FileName,
|
|
|
|
mut src: String,
|
2019-06-17 03:35:26 -05:00
|
|
|
start_pos: BytePos,
|
2020-03-31 00:17:15 -05:00
|
|
|
hash_kind: SourceFileHashAlgorithm,
|
2020-02-18 11:24:36 -06:00
|
|
|
) -> Self {
|
2020-03-31 00:17:15 -05:00
|
|
|
// Compute the file hash before any normalization.
|
|
|
|
let src_hash = SourceFileHash::new(hash_kind, &src);
|
2019-10-02 19:55:31 -05:00
|
|
|
let normalized_pos = normalize_src(&mut src, start_pos);
|
2017-06-10 09:09:51 -05:00
|
|
|
|
2017-12-19 08:14:41 -06:00
|
|
|
let name_hash = {
|
2019-09-26 17:54:39 -05:00
|
|
|
let mut hasher: StableHasher = StableHasher::new();
|
2017-12-19 08:14:41 -06:00
|
|
|
name.hash(&mut hasher);
|
2019-09-26 17:54:39 -05:00
|
|
|
hasher.finish::<u128>()
|
2017-12-19 08:14:41 -06:00
|
|
|
};
|
2017-06-10 09:09:51 -05:00
|
|
|
let end_pos = start_pos.to_usize() + src.len();
|
2020-06-02 02:59:11 -05:00
|
|
|
assert!(end_pos <= u32::MAX as usize);
|
2017-06-10 09:09:51 -05:00
|
|
|
|
2018-05-23 08:59:42 -05:00
|
|
|
let (lines, multibyte_chars, non_narrow_chars) =
|
2021-12-02 20:06:36 -06:00
|
|
|
analyze_source_file::analyze_source_file(&src, start_pos);
|
2018-05-23 08:59:42 -05:00
|
|
|
|
2020-02-18 11:24:36 -06:00
|
|
|
SourceFile {
|
2017-08-07 00:54:09 -05:00
|
|
|
name,
|
2018-02-27 10:11:14 -06:00
|
|
|
src: Some(Lrc::new(src)),
|
2017-08-07 00:54:09 -05:00
|
|
|
src_hash,
|
2018-03-09 23:40:17 -06:00
|
|
|
external_src: Lock::new(ExternalSource::Unneeded),
|
2017-08-07 00:54:09 -05:00
|
|
|
start_pos,
|
2017-06-10 09:09:51 -05:00
|
|
|
end_pos: Pos::from_usize(end_pos),
|
2022-06-01 20:43:14 -05:00
|
|
|
lines: Lock::new(SourceFileLines::Lines(lines)),
|
2018-05-23 08:59:42 -05:00
|
|
|
multibyte_chars,
|
|
|
|
non_narrow_chars,
|
2019-10-02 19:55:31 -05:00
|
|
|
normalized_pos,
|
2017-12-19 08:14:41 -06:00
|
|
|
name_hash,
|
2020-02-07 13:02:24 -06:00
|
|
|
cnum: LOCAL_CRATE,
|
2020-02-18 11:24:36 -06:00
|
|
|
}
|
2017-06-10 09:09:51 -05:00
|
|
|
}
|
|
|
|
|
2022-06-01 20:43:14 -05:00
|
|
|
pub fn lines<F, R>(&self, f: F) -> R
|
2022-05-30 00:59:45 -05:00
|
|
|
where
|
2022-06-01 20:43:14 -05:00
|
|
|
F: FnOnce(&[BytePos]) -> R,
|
2022-05-30 00:59:45 -05:00
|
|
|
{
|
|
|
|
let mut guard = self.lines.borrow_mut();
|
|
|
|
match &*guard {
|
2022-06-01 20:43:14 -05:00
|
|
|
SourceFileLines::Lines(lines) => f(lines),
|
|
|
|
SourceFileLines::Diffs(SourceFileDiffs {
|
|
|
|
mut line_start,
|
|
|
|
bytes_per_diff,
|
|
|
|
num_diffs,
|
|
|
|
raw_diffs,
|
|
|
|
}) => {
|
2022-05-30 00:59:45 -05:00
|
|
|
// Convert from "diffs" form to "lines" form.
|
|
|
|
let num_lines = num_diffs + 1;
|
|
|
|
let mut lines = Vec::with_capacity(num_lines);
|
|
|
|
lines.push(line_start);
|
|
|
|
|
|
|
|
assert_eq!(*num_diffs, raw_diffs.len() / bytes_per_diff);
|
|
|
|
match bytes_per_diff {
|
|
|
|
1 => {
|
|
|
|
lines.extend(raw_diffs.into_iter().map(|&diff| {
|
|
|
|
line_start = line_start + BytePos(diff as u32);
|
|
|
|
line_start
|
|
|
|
}));
|
|
|
|
}
|
|
|
|
2 => {
|
|
|
|
lines.extend((0..*num_diffs).map(|i| {
|
|
|
|
let pos = bytes_per_diff * i;
|
|
|
|
let bytes = [raw_diffs[pos], raw_diffs[pos + 1]];
|
|
|
|
let diff = u16::from_le_bytes(bytes);
|
|
|
|
line_start = line_start + BytePos(diff as u32);
|
|
|
|
line_start
|
|
|
|
}));
|
|
|
|
}
|
|
|
|
4 => {
|
|
|
|
lines.extend((0..*num_diffs).map(|i| {
|
|
|
|
let pos = bytes_per_diff * i;
|
|
|
|
let bytes = [
|
|
|
|
raw_diffs[pos],
|
|
|
|
raw_diffs[pos + 1],
|
|
|
|
raw_diffs[pos + 2],
|
|
|
|
raw_diffs[pos + 3],
|
|
|
|
];
|
|
|
|
let diff = u32::from_le_bytes(bytes);
|
|
|
|
line_start = line_start + BytePos(diff);
|
|
|
|
line_start
|
|
|
|
}));
|
|
|
|
}
|
|
|
|
_ => unreachable!(),
|
|
|
|
}
|
|
|
|
let res = f(&lines);
|
2022-06-01 20:43:14 -05:00
|
|
|
*guard = SourceFileLines::Lines(lines);
|
2022-05-30 00:59:45 -05:00
|
|
|
res
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-02-08 07:53:55 -06:00
|
|
|
/// Returns the `BytePos` of the beginning of the current line.
|
2018-06-28 03:45:57 -05:00
|
|
|
pub fn line_begin_pos(&self, pos: BytePos) -> BytePos {
|
|
|
|
let line_index = self.lookup_line(pos).unwrap();
|
2022-05-30 00:59:45 -05:00
|
|
|
self.lines(|lines| lines[line_index])
|
2018-05-08 04:58:54 -05:00
|
|
|
}
|
|
|
|
|
2017-06-12 08:37:26 -05:00
|
|
|
/// Add externally loaded source.
|
|
|
|
/// If the hash of the input doesn't match or no input is supplied via None,
|
2017-06-11 06:48:54 -05:00
|
|
|
/// it is interpreted as an error and the corresponding enum variant is set.
|
2017-06-12 08:37:26 -05:00
|
|
|
/// The return value signifies whether some kind of source is present.
|
2017-08-01 06:17:11 -05:00
|
|
|
pub fn add_external_src<F>(&self, get_src: F) -> bool
|
|
|
|
where
|
|
|
|
F: FnOnce() -> Option<String>,
|
|
|
|
{
|
2020-02-07 13:02:24 -06:00
|
|
|
if matches!(
|
|
|
|
*self.external_src.borrow(),
|
|
|
|
ExternalSource::Foreign { kind: ExternalSourceKind::AbsentOk, .. }
|
|
|
|
) {
|
2017-08-01 06:17:11 -05:00
|
|
|
let src = get_src();
|
2017-06-12 08:37:26 -05:00
|
|
|
let mut external_src = self.external_src.borrow_mut();
|
2018-03-09 23:40:17 -06:00
|
|
|
// Check that no-one else have provided the source while we were getting it
|
2020-02-07 13:02:24 -06:00
|
|
|
if let ExternalSource::Foreign {
|
|
|
|
kind: src_kind @ ExternalSourceKind::AbsentOk, ..
|
|
|
|
} = &mut *external_src
|
|
|
|
{
|
2020-04-11 22:21:51 -05:00
|
|
|
if let Some(mut src) = src {
|
|
|
|
// The src_hash needs to be computed on the pre-normalized src.
|
2020-03-31 00:17:15 -05:00
|
|
|
if self.src_hash.matches(&src) {
|
2020-04-11 22:21:51 -05:00
|
|
|
normalize_src(&mut src, BytePos::from_usize(0));
|
2020-03-20 01:00:06 -05:00
|
|
|
*src_kind = ExternalSourceKind::Present(Lrc::new(src));
|
2018-03-09 23:40:17 -06:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
} else {
|
2020-02-07 13:02:24 -06:00
|
|
|
*src_kind = ExternalSourceKind::AbsentErr;
|
2017-06-12 08:37:26 -05:00
|
|
|
}
|
2018-03-09 23:40:17 -06:00
|
|
|
|
|
|
|
false
|
2017-06-12 08:37:26 -05:00
|
|
|
} else {
|
2018-03-09 23:40:17 -06:00
|
|
|
self.src.is_some() || external_src.get_source().is_some()
|
2017-06-11 06:48:54 -05:00
|
|
|
}
|
|
|
|
} else {
|
2017-06-12 08:37:26 -05:00
|
|
|
self.src.is_some() || self.external_src.borrow().get_source().is_some()
|
2017-06-11 06:48:54 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-02-08 07:53:55 -06:00
|
|
|
/// Gets a line from the list of pre-computed line-beginnings.
|
2017-06-12 08:37:26 -05:00
|
|
|
/// The line number here is 0-based.
|
2019-02-03 12:42:27 -06:00
|
|
|
pub fn get_line(&self, line_number: usize) -> Option<Cow<'_, str>> {
|
2017-06-11 06:31:40 -05:00
|
|
|
fn get_until_newline(src: &str, begin: usize) -> &str {
|
|
|
|
// We can't use `lines.get(line_number+1)` because we might
|
|
|
|
// be parsing when we call this function and thus the current
|
|
|
|
// line is the last one we have line info for.
|
|
|
|
let slice = &src[begin..];
|
|
|
|
match slice.find('\n') {
|
|
|
|
Some(e) => &slice[..e],
|
|
|
|
None => slice,
|
2016-06-21 17:08:13 -05:00
|
|
|
}
|
2017-06-11 06:31:40 -05:00
|
|
|
}
|
|
|
|
|
2018-03-09 23:40:17 -06:00
|
|
|
let begin = {
|
2022-05-30 00:59:45 -05:00
|
|
|
let line = self.lines(|lines| lines.get(line_number).copied())?;
|
|
|
|
let begin: BytePos = line - self.start_pos;
|
2018-03-09 23:40:17 -06:00
|
|
|
begin.to_usize()
|
2017-06-11 06:31:40 -05:00
|
|
|
};
|
|
|
|
|
|
|
|
if let Some(ref src) = self.src {
|
|
|
|
Some(Cow::from(get_until_newline(src, begin)))
|
|
|
|
} else if let Some(src) = self.external_src.borrow().get_source() {
|
|
|
|
Some(Cow::Owned(String::from(get_until_newline(src, begin))))
|
|
|
|
} else {
|
|
|
|
None
|
2016-06-21 17:08:13 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn is_real_file(&self) -> bool {
|
2017-12-14 01:09:19 -06:00
|
|
|
self.name.is_real()
|
2016-06-21 17:08:13 -05:00
|
|
|
}
|
|
|
|
|
2022-07-06 19:00:00 -05:00
|
|
|
#[inline]
|
2016-06-21 17:08:13 -05:00
|
|
|
pub fn is_imported(&self) -> bool {
|
2017-06-11 06:31:40 -05:00
|
|
|
self.src.is_none()
|
2016-06-21 17:08:13 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
pub fn count_lines(&self) -> usize {
|
2022-05-30 00:59:45 -05:00
|
|
|
self.lines(|lines| lines.len())
|
2016-06-21 17:08:13 -05:00
|
|
|
}
|
2016-08-24 16:06:31 -05:00
|
|
|
|
2019-02-08 07:53:55 -06:00
|
|
|
/// Finds the line containing the given position. The return value is the
|
2018-11-26 20:59:49 -06:00
|
|
|
/// index into the `lines` array of this `SourceFile`, not the 1-based line
|
2018-08-18 05:13:56 -05:00
|
|
|
/// number. If the source_file is empty or the position is located before the
|
2018-11-26 20:59:49 -06:00
|
|
|
/// first line, `None` is returned.
|
2016-08-24 16:06:31 -05:00
|
|
|
pub fn lookup_line(&self, pos: BytePos) -> Option<usize> {
|
2022-05-30 00:59:45 -05:00
|
|
|
self.lines(|lines| match lines.binary_search(&pos) {
|
2021-07-04 19:00:00 -05:00
|
|
|
Ok(idx) => Some(idx),
|
|
|
|
Err(0) => None,
|
|
|
|
Err(idx) => Some(idx - 1),
|
2022-05-30 00:59:45 -05:00
|
|
|
})
|
2016-08-24 16:06:31 -05:00
|
|
|
}
|
|
|
|
|
2020-10-27 17:47:29 -05:00
|
|
|
pub fn line_bounds(&self, line_index: usize) -> Range<BytePos> {
|
2020-09-20 19:40:40 -05:00
|
|
|
if self.is_empty() {
|
2020-10-27 17:47:29 -05:00
|
|
|
return self.start_pos..self.end_pos;
|
2016-08-24 16:06:31 -05:00
|
|
|
}
|
|
|
|
|
2022-05-30 00:59:45 -05:00
|
|
|
self.lines(|lines| {
|
|
|
|
assert!(line_index < lines.len());
|
|
|
|
if line_index == (lines.len() - 1) {
|
|
|
|
lines[line_index]..self.end_pos
|
|
|
|
} else {
|
|
|
|
lines[line_index]..lines[line_index + 1]
|
|
|
|
}
|
|
|
|
})
|
2016-08-24 16:06:31 -05:00
|
|
|
}
|
2017-11-24 07:00:33 -06:00
|
|
|
|
2020-09-20 19:40:40 -05:00
|
|
|
/// Returns whether or not the file contains the given `SourceMap` byte
|
|
|
|
/// position. The position one past the end of the file is considered to be
|
|
|
|
/// contained by the file. This implies that files for which `is_empty`
|
|
|
|
/// returns true still contain one byte position according to this function.
|
2017-11-24 07:00:33 -06:00
|
|
|
#[inline]
|
|
|
|
pub fn contains(&self, byte_pos: BytePos) -> bool {
|
|
|
|
byte_pos >= self.start_pos && byte_pos <= self.end_pos
|
|
|
|
}
|
2019-10-02 19:55:31 -05:00
|
|
|
|
2020-09-20 19:40:40 -05:00
|
|
|
#[inline]
|
|
|
|
pub fn is_empty(&self) -> bool {
|
|
|
|
self.start_pos == self.end_pos
|
|
|
|
}
|
|
|
|
|
2019-10-02 19:55:31 -05:00
|
|
|
/// Calculates the original byte position relative to the start of the file
|
|
|
|
/// based on the given byte position.
|
|
|
|
pub fn original_relative_byte_pos(&self, pos: BytePos) -> BytePos {
|
|
|
|
// Diff before any records is 0. Otherwise use the previously recorded
|
|
|
|
// diff as that applies to the following characters until a new diff
|
|
|
|
// is recorded.
|
|
|
|
let diff = match self.normalized_pos.binary_search_by(|np| np.pos.cmp(&pos)) {
|
|
|
|
Ok(i) => self.normalized_pos[i].diff,
|
|
|
|
Err(i) if i == 0 => 0,
|
|
|
|
Err(i) => self.normalized_pos[i - 1].diff,
|
|
|
|
};
|
|
|
|
|
|
|
|
BytePos::from_u32(pos.0 - self.start_pos.0 + diff)
|
|
|
|
}
|
Updates to experimental coverage counter injection
This is a combination of 18 commits.
Commit #2:
Additional examples and some small improvements.
Commit #3:
fixed mir-opt non-mir extensions and spanview title elements
Corrected a fairly recent assumption in runtest.rs that all MIR dump
files end in .mir. (It was appending .mir to the graphviz .dot and
spanview .html file names when generating blessed output files. That
also left outdated files in the baseline alongside the files with the
incorrect names, which I've now removed.)
Updated spanview HTML title elements to match their content, replacing a
hardcoded and incorrect name that was left in accidentally when
originally submitted.
Commit #4:
added more test examples
also improved Makefiles with support for non-zero exit status and to
force validation of tests unless a specific test overrides it with a
specific comment.
Commit #5:
Fixed rare issues after testing on real-world crate
Commit #6:
Addressed PR feedback, and removed temporary -Zexperimental-coverage
-Zinstrument-coverage once again supports the latest capabilities of
LLVM instrprof coverage instrumentation.
Also fixed a bug in spanview.
Commit #7:
Fix closure handling, add tests for closures and inner items
And cleaned up other tests for consistency, and to make it more clear
where spans start/end by breaking up lines.
Commit #8:
renamed "typical" test results "expected"
Now that the `llvm-cov show` tests are improved to normally expect
matching actuals, and to allow individual tests to override that
expectation.
Commit #9:
test coverage of inline generic struct function
Commit #10:
Addressed review feedback
* Removed unnecessary Unreachable filter.
* Replaced a match wildcard with remining variants.
* Added more comments to help clarify the role of successors() in the
CFG traversal
Commit #11:
refactoring based on feedback
* refactored `fn coverage_spans()`.
* changed the way I expand an empty coverage span to improve performance
* fixed a typo that I had accidently left in, in visit.rs
Commit #12:
Optimized use of SourceMap and SourceFile
Commit #13:
Fixed a regression, and synched with upstream
Some generated test file names changed due to some new change upstream.
Commit #14:
Stripping out crate disambiguators from demangled names
These can vary depending on the test platform.
Commit #15:
Ignore llvm-cov show diff on test with generics, expand IO error message
Tests with generics produce llvm-cov show results with demangled names
that can include an unstable "crate disambiguator" (hex value). The
value changes when run in the Rust CI Windows environment. I added a sed
filter to strip them out (in a prior commit), but sed also appears to
fail in the same environment. Until I can figure out a workaround, I'm
just going to ignore this specific test result. I added a FIXME to
follow up later, but it's not that critical.
I also saw an error with Windows GNU, but the IO error did not
specify a path for the directory or file that triggered the error. I
updated the error messages to provide more info for next, time but also
noticed some other tests with similar steps did not fail. Looks
spurious.
Commit #16:
Modify rust-demangler to strip disambiguators by default
Commit #17:
Remove std::process::exit from coverage tests
Due to Issue #77553, programs that call std::process::exit() do not
generate coverage results on Windows MSVC.
Commit #18:
fix: test file paths exceeding Windows max path len
2020-09-01 18:15:17 -05:00
|
|
|
|
|
|
|
/// Converts an absolute `BytePos` to a `CharPos` relative to the `SourceFile`.
|
|
|
|
pub fn bytepos_to_file_charpos(&self, bpos: BytePos) -> CharPos {
|
|
|
|
// The number of extra bytes due to multibyte chars in the `SourceFile`.
|
|
|
|
let mut total_extra_bytes = 0;
|
|
|
|
|
|
|
|
for mbc in self.multibyte_chars.iter() {
|
|
|
|
debug!("{}-byte char at {:?}", mbc.bytes, mbc.pos);
|
|
|
|
if mbc.pos < bpos {
|
|
|
|
// Every character is at least one byte, so we only
|
|
|
|
// count the actual extra bytes.
|
|
|
|
total_extra_bytes += mbc.bytes as u32 - 1;
|
|
|
|
// We should never see a byte position in the middle of a
|
|
|
|
// character.
|
|
|
|
assert!(bpos.to_u32() >= mbc.pos.to_u32() + mbc.bytes as u32);
|
|
|
|
} else {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
assert!(self.start_pos.to_u32() + total_extra_bytes <= bpos.to_u32());
|
|
|
|
CharPos(bpos.to_usize() - self.start_pos.to_usize() - total_extra_bytes as usize)
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Looks up the file's (1-based) line number and (0-based `CharPos`) column offset, for a
|
|
|
|
/// given `BytePos`.
|
|
|
|
pub fn lookup_file_pos(&self, pos: BytePos) -> (usize, CharPos) {
|
|
|
|
let chpos = self.bytepos_to_file_charpos(pos);
|
|
|
|
match self.lookup_line(pos) {
|
|
|
|
Some(a) => {
|
|
|
|
let line = a + 1; // Line numbers start at 1
|
2022-05-30 00:59:45 -05:00
|
|
|
let linebpos = self.lines(|lines| lines[a]);
|
Updates to experimental coverage counter injection
This is a combination of 18 commits.
Commit #2:
Additional examples and some small improvements.
Commit #3:
fixed mir-opt non-mir extensions and spanview title elements
Corrected a fairly recent assumption in runtest.rs that all MIR dump
files end in .mir. (It was appending .mir to the graphviz .dot and
spanview .html file names when generating blessed output files. That
also left outdated files in the baseline alongside the files with the
incorrect names, which I've now removed.)
Updated spanview HTML title elements to match their content, replacing a
hardcoded and incorrect name that was left in accidentally when
originally submitted.
Commit #4:
added more test examples
also improved Makefiles with support for non-zero exit status and to
force validation of tests unless a specific test overrides it with a
specific comment.
Commit #5:
Fixed rare issues after testing on real-world crate
Commit #6:
Addressed PR feedback, and removed temporary -Zexperimental-coverage
-Zinstrument-coverage once again supports the latest capabilities of
LLVM instrprof coverage instrumentation.
Also fixed a bug in spanview.
Commit #7:
Fix closure handling, add tests for closures and inner items
And cleaned up other tests for consistency, and to make it more clear
where spans start/end by breaking up lines.
Commit #8:
renamed "typical" test results "expected"
Now that the `llvm-cov show` tests are improved to normally expect
matching actuals, and to allow individual tests to override that
expectation.
Commit #9:
test coverage of inline generic struct function
Commit #10:
Addressed review feedback
* Removed unnecessary Unreachable filter.
* Replaced a match wildcard with remining variants.
* Added more comments to help clarify the role of successors() in the
CFG traversal
Commit #11:
refactoring based on feedback
* refactored `fn coverage_spans()`.
* changed the way I expand an empty coverage span to improve performance
* fixed a typo that I had accidently left in, in visit.rs
Commit #12:
Optimized use of SourceMap and SourceFile
Commit #13:
Fixed a regression, and synched with upstream
Some generated test file names changed due to some new change upstream.
Commit #14:
Stripping out crate disambiguators from demangled names
These can vary depending on the test platform.
Commit #15:
Ignore llvm-cov show diff on test with generics, expand IO error message
Tests with generics produce llvm-cov show results with demangled names
that can include an unstable "crate disambiguator" (hex value). The
value changes when run in the Rust CI Windows environment. I added a sed
filter to strip them out (in a prior commit), but sed also appears to
fail in the same environment. Until I can figure out a workaround, I'm
just going to ignore this specific test result. I added a FIXME to
follow up later, but it's not that critical.
I also saw an error with Windows GNU, but the IO error did not
specify a path for the directory or file that triggered the error. I
updated the error messages to provide more info for next, time but also
noticed some other tests with similar steps did not fail. Looks
spurious.
Commit #16:
Modify rust-demangler to strip disambiguators by default
Commit #17:
Remove std::process::exit from coverage tests
Due to Issue #77553, programs that call std::process::exit() do not
generate coverage results on Windows MSVC.
Commit #18:
fix: test file paths exceeding Windows max path len
2020-09-01 18:15:17 -05:00
|
|
|
let linechpos = self.bytepos_to_file_charpos(linebpos);
|
|
|
|
let col = chpos - linechpos;
|
|
|
|
debug!("byte pos {:?} is on the line at byte pos {:?}", pos, linebpos);
|
|
|
|
debug!("char pos {:?} is on the line at char pos {:?}", chpos, linechpos);
|
|
|
|
debug!("byte is on line: {}", line);
|
|
|
|
assert!(chpos >= linechpos);
|
|
|
|
(line, col)
|
|
|
|
}
|
|
|
|
None => (0, chpos),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Looks up the file's (1-based) line number, (0-based `CharPos`) column offset, and (0-based)
|
|
|
|
/// column offset when displayed, for a given `BytePos`.
|
|
|
|
pub fn lookup_file_pos_with_col_display(&self, pos: BytePos) -> (usize, CharPos, usize) {
|
|
|
|
let (line, col_or_chpos) = self.lookup_file_pos(pos);
|
|
|
|
if line > 0 {
|
|
|
|
let col = col_or_chpos;
|
2022-05-30 00:59:45 -05:00
|
|
|
let linebpos = self.lines(|lines| lines[line - 1]);
|
Updates to experimental coverage counter injection
This is a combination of 18 commits.
Commit #2:
Additional examples and some small improvements.
Commit #3:
fixed mir-opt non-mir extensions and spanview title elements
Corrected a fairly recent assumption in runtest.rs that all MIR dump
files end in .mir. (It was appending .mir to the graphviz .dot and
spanview .html file names when generating blessed output files. That
also left outdated files in the baseline alongside the files with the
incorrect names, which I've now removed.)
Updated spanview HTML title elements to match their content, replacing a
hardcoded and incorrect name that was left in accidentally when
originally submitted.
Commit #4:
added more test examples
also improved Makefiles with support for non-zero exit status and to
force validation of tests unless a specific test overrides it with a
specific comment.
Commit #5:
Fixed rare issues after testing on real-world crate
Commit #6:
Addressed PR feedback, and removed temporary -Zexperimental-coverage
-Zinstrument-coverage once again supports the latest capabilities of
LLVM instrprof coverage instrumentation.
Also fixed a bug in spanview.
Commit #7:
Fix closure handling, add tests for closures and inner items
And cleaned up other tests for consistency, and to make it more clear
where spans start/end by breaking up lines.
Commit #8:
renamed "typical" test results "expected"
Now that the `llvm-cov show` tests are improved to normally expect
matching actuals, and to allow individual tests to override that
expectation.
Commit #9:
test coverage of inline generic struct function
Commit #10:
Addressed review feedback
* Removed unnecessary Unreachable filter.
* Replaced a match wildcard with remining variants.
* Added more comments to help clarify the role of successors() in the
CFG traversal
Commit #11:
refactoring based on feedback
* refactored `fn coverage_spans()`.
* changed the way I expand an empty coverage span to improve performance
* fixed a typo that I had accidently left in, in visit.rs
Commit #12:
Optimized use of SourceMap and SourceFile
Commit #13:
Fixed a regression, and synched with upstream
Some generated test file names changed due to some new change upstream.
Commit #14:
Stripping out crate disambiguators from demangled names
These can vary depending on the test platform.
Commit #15:
Ignore llvm-cov show diff on test with generics, expand IO error message
Tests with generics produce llvm-cov show results with demangled names
that can include an unstable "crate disambiguator" (hex value). The
value changes when run in the Rust CI Windows environment. I added a sed
filter to strip them out (in a prior commit), but sed also appears to
fail in the same environment. Until I can figure out a workaround, I'm
just going to ignore this specific test result. I added a FIXME to
follow up later, but it's not that critical.
I also saw an error with Windows GNU, but the IO error did not
specify a path for the directory or file that triggered the error. I
updated the error messages to provide more info for next, time but also
noticed some other tests with similar steps did not fail. Looks
spurious.
Commit #16:
Modify rust-demangler to strip disambiguators by default
Commit #17:
Remove std::process::exit from coverage tests
Due to Issue #77553, programs that call std::process::exit() do not
generate coverage results on Windows MSVC.
Commit #18:
fix: test file paths exceeding Windows max path len
2020-09-01 18:15:17 -05:00
|
|
|
let col_display = {
|
|
|
|
let start_width_idx = self
|
|
|
|
.non_narrow_chars
|
|
|
|
.binary_search_by_key(&linebpos, |x| x.pos())
|
|
|
|
.unwrap_or_else(|x| x);
|
|
|
|
let end_width_idx = self
|
|
|
|
.non_narrow_chars
|
|
|
|
.binary_search_by_key(&pos, |x| x.pos())
|
|
|
|
.unwrap_or_else(|x| x);
|
|
|
|
let special_chars = end_width_idx - start_width_idx;
|
|
|
|
let non_narrow: usize = self.non_narrow_chars[start_width_idx..end_width_idx]
|
|
|
|
.iter()
|
|
|
|
.map(|x| x.width())
|
|
|
|
.sum();
|
|
|
|
col.0 - special_chars + non_narrow
|
|
|
|
};
|
|
|
|
(line, col, col_display)
|
|
|
|
} else {
|
|
|
|
let chpos = col_or_chpos;
|
|
|
|
let col_display = {
|
|
|
|
let end_width_idx = self
|
|
|
|
.non_narrow_chars
|
|
|
|
.binary_search_by_key(&pos, |x| x.pos())
|
|
|
|
.unwrap_or_else(|x| x);
|
|
|
|
let non_narrow: usize =
|
|
|
|
self.non_narrow_chars[0..end_width_idx].iter().map(|x| x.width()).sum();
|
|
|
|
chpos.0 - end_width_idx + non_narrow
|
|
|
|
};
|
|
|
|
(0, chpos, col_display)
|
|
|
|
}
|
|
|
|
}
|
2019-10-02 19:55:31 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
/// Normalizes the source code and records the normalizations.
|
|
|
|
fn normalize_src(src: &mut String, start_pos: BytePos) -> Vec<NormalizedPos> {
|
|
|
|
let mut normalized_pos = vec![];
|
|
|
|
remove_bom(src, &mut normalized_pos);
|
|
|
|
normalize_newlines(src, &mut normalized_pos);
|
|
|
|
|
|
|
|
// Offset all the positions by start_pos to match the final file positions.
|
|
|
|
for np in &mut normalized_pos {
|
|
|
|
np.pos.0 += start_pos.0;
|
|
|
|
}
|
|
|
|
|
|
|
|
normalized_pos
|
2016-06-21 17:08:13 -05:00
|
|
|
}
|
|
|
|
|
2019-02-08 07:53:55 -06:00
|
|
|
/// Removes UTF-8 BOM, if any.
|
2019-10-02 19:55:31 -05:00
|
|
|
fn remove_bom(src: &mut String, normalized_pos: &mut Vec<NormalizedPos>) {
|
2020-11-04 06:48:50 -06:00
|
|
|
if src.starts_with('\u{feff}') {
|
2017-06-10 09:09:51 -05:00
|
|
|
src.drain(..3);
|
2019-10-02 19:55:31 -05:00
|
|
|
normalized_pos.push(NormalizedPos { pos: BytePos(0), diff: 3 });
|
2017-06-10 09:09:51 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-08-14 07:35:12 -05:00
|
|
|
/// Replaces `\r\n` with `\n` in-place in `src`.
|
|
|
|
///
|
2020-12-24 01:01:03 -06:00
|
|
|
/// Returns error if there's a lone `\r` in the string.
|
2019-10-02 19:55:31 -05:00
|
|
|
fn normalize_newlines(src: &mut String, normalized_pos: &mut Vec<NormalizedPos>) {
|
2019-08-14 07:35:12 -05:00
|
|
|
if !src.as_bytes().contains(&b'\r') {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
// We replace `\r\n` with `\n` in-place, which doesn't break utf-8 encoding.
|
|
|
|
// While we *can* call `as_mut_vec` and do surgery on the live string
|
|
|
|
// directly, let's rather steal the contents of `src`. This makes the code
|
|
|
|
// safe even if a panic occurs.
|
|
|
|
|
|
|
|
let mut buf = std::mem::replace(src, String::new()).into_bytes();
|
|
|
|
let mut gap_len = 0;
|
|
|
|
let mut tail = buf.as_mut_slice();
|
2019-10-02 19:55:31 -05:00
|
|
|
let mut cursor = 0;
|
|
|
|
let original_gap = normalized_pos.last().map_or(0, |l| l.diff);
|
2019-08-14 07:35:12 -05:00
|
|
|
loop {
|
|
|
|
let idx = match find_crlf(&tail[gap_len..]) {
|
|
|
|
None => tail.len(),
|
|
|
|
Some(idx) => idx + gap_len,
|
|
|
|
};
|
|
|
|
tail.copy_within(gap_len..idx, 0);
|
|
|
|
tail = &mut tail[idx - gap_len..];
|
|
|
|
if tail.len() == gap_len {
|
|
|
|
break;
|
|
|
|
}
|
2019-10-02 19:55:31 -05:00
|
|
|
cursor += idx - gap_len;
|
2019-08-14 07:35:12 -05:00
|
|
|
gap_len += 1;
|
2019-10-02 19:55:31 -05:00
|
|
|
normalized_pos.push(NormalizedPos {
|
|
|
|
pos: BytePos::from_usize(cursor + 1),
|
|
|
|
diff: original_gap + gap_len as u32,
|
|
|
|
});
|
2019-08-14 07:35:12 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
// Account for removed `\r`.
|
|
|
|
// After `set_len`, `buf` is guaranteed to contain utf-8 again.
|
|
|
|
let new_len = buf.len() - gap_len;
|
|
|
|
unsafe {
|
|
|
|
buf.set_len(new_len);
|
|
|
|
*src = String::from_utf8_unchecked(buf);
|
|
|
|
}
|
|
|
|
|
|
|
|
fn find_crlf(src: &[u8]) -> Option<usize> {
|
|
|
|
let mut search_idx = 0;
|
|
|
|
while let Some(idx) = find_cr(&src[search_idx..]) {
|
|
|
|
if src[search_idx..].get(idx + 1) != Some(&b'\n') {
|
|
|
|
search_idx += idx + 1;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
return Some(search_idx + idx);
|
|
|
|
}
|
|
|
|
None
|
|
|
|
}
|
|
|
|
|
|
|
|
fn find_cr(src: &[u8]) -> Option<usize> {
|
|
|
|
src.iter().position(|&b| b == b'\r')
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-06-21 17:08:13 -05:00
|
|
|
// _____________________________________________________________________________
|
|
|
|
// Pos, BytePos, CharPos
|
|
|
|
//
|
|
|
|
|
|
|
|
pub trait Pos {
|
|
|
|
fn from_usize(n: usize) -> Self;
|
|
|
|
fn to_usize(&self) -> usize;
|
2018-05-29 10:49:35 -05:00
|
|
|
fn from_u32(n: u32) -> Self;
|
|
|
|
fn to_u32(&self) -> u32;
|
2016-06-21 17:08:13 -05:00
|
|
|
}
|
|
|
|
|
2020-09-21 12:27:43 -05:00
|
|
|
macro_rules! impl_pos {
|
|
|
|
(
|
|
|
|
$(
|
|
|
|
$(#[$attr:meta])*
|
|
|
|
$vis:vis struct $ident:ident($inner_vis:vis $inner_ty:ty);
|
|
|
|
)*
|
|
|
|
) => {
|
|
|
|
$(
|
|
|
|
$(#[$attr])*
|
|
|
|
$vis struct $ident($inner_vis $inner_ty);
|
|
|
|
|
|
|
|
impl Pos for $ident {
|
|
|
|
#[inline(always)]
|
|
|
|
fn from_usize(n: usize) -> $ident {
|
|
|
|
$ident(n as $inner_ty)
|
|
|
|
}
|
2016-06-21 17:08:13 -05:00
|
|
|
|
2020-09-21 12:27:43 -05:00
|
|
|
#[inline(always)]
|
|
|
|
fn to_usize(&self) -> usize {
|
|
|
|
self.0 as usize
|
|
|
|
}
|
2016-06-21 17:08:13 -05:00
|
|
|
|
2020-09-21 12:27:43 -05:00
|
|
|
#[inline(always)]
|
|
|
|
fn from_u32(n: u32) -> $ident {
|
|
|
|
$ident(n as $inner_ty)
|
|
|
|
}
|
2018-05-02 18:12:26 -05:00
|
|
|
|
2020-09-21 12:27:43 -05:00
|
|
|
#[inline(always)]
|
|
|
|
fn to_u32(&self) -> u32 {
|
|
|
|
self.0 as u32
|
|
|
|
}
|
|
|
|
}
|
2018-05-29 10:49:35 -05:00
|
|
|
|
2020-09-21 12:27:43 -05:00
|
|
|
impl Add for $ident {
|
|
|
|
type Output = $ident;
|
2018-05-29 10:49:35 -05:00
|
|
|
|
2020-09-21 12:27:43 -05:00
|
|
|
#[inline(always)]
|
|
|
|
fn add(self, rhs: $ident) -> $ident {
|
2020-09-21 13:42:43 -05:00
|
|
|
$ident(self.0 + rhs.0)
|
2020-09-21 12:27:43 -05:00
|
|
|
}
|
|
|
|
}
|
2016-06-21 17:08:13 -05:00
|
|
|
|
2020-09-21 12:27:43 -05:00
|
|
|
impl Sub for $ident {
|
|
|
|
type Output = $ident;
|
2016-06-21 17:08:13 -05:00
|
|
|
|
2020-09-21 12:27:43 -05:00
|
|
|
#[inline(always)]
|
|
|
|
fn sub(self, rhs: $ident) -> $ident {
|
2020-09-21 13:42:43 -05:00
|
|
|
$ident(self.0 - rhs.0)
|
2020-09-21 12:27:43 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
)*
|
|
|
|
};
|
2016-06-21 17:08:13 -05:00
|
|
|
}
|
|
|
|
|
2020-09-21 12:27:43 -05:00
|
|
|
impl_pos! {
|
2020-12-24 01:01:03 -06:00
|
|
|
/// A byte offset.
|
|
|
|
///
|
|
|
|
/// Keep this small (currently 32-bits), as AST contains a lot of them.
|
2020-09-21 12:27:43 -05:00
|
|
|
#[derive(Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord, Debug)]
|
|
|
|
pub struct BytePos(pub u32);
|
|
|
|
|
2020-12-24 01:01:03 -06:00
|
|
|
/// A character offset.
|
|
|
|
///
|
|
|
|
/// Because of multibyte UTF-8 characters, a byte offset
|
|
|
|
/// is not equivalent to a character offset. The [`SourceMap`] will convert [`BytePos`]
|
2020-09-21 12:27:43 -05:00
|
|
|
/// values to `CharPos` values as necessary.
|
|
|
|
#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Debug)]
|
|
|
|
pub struct CharPos(pub usize);
|
2016-06-21 17:08:13 -05:00
|
|
|
}
|
|
|
|
|
2022-06-13 23:52:01 -05:00
|
|
|
impl<S: Encoder> Encodable<S> for BytePos {
|
Use delayed error handling for `Encodable` and `Encoder` infallible.
There are two impls of the `Encoder` trait: `opaque::Encoder` and
`opaque::FileEncoder`. The former encodes into memory and is infallible, the
latter writes to file and is fallible.
Currently, standard `Result`/`?`/`unwrap` error handling is used, but this is a
bit verbose and has non-trivial cost, which is annoying given how rare failures
are (especially in the infallible `opaque::Encoder` case).
This commit changes how `Encoder` fallibility is handled. All the `emit_*`
methods are now infallible. `opaque::Encoder` requires no great changes for
this. `opaque::FileEncoder` now implements a delayed error handling strategy.
If a failure occurs, it records this via the `res` field, and all subsequent
encoding operations are skipped if `res` indicates an error has occurred. Once
encoding is complete, the new `finish` method is called, which returns a
`Result`. In other words, there is now a single `Result`-producing method
instead of many of them.
This has very little effect on how any file errors are reported if
`opaque::FileEncoder` has any failures.
Much of this commit is boring mechanical changes, removing `Result` return
values and `?` or `unwrap` from expressions. The more interesting parts are as
follows.
- serialize.rs: The `Encoder` trait gains an `Ok` associated type. The
`into_inner` method is changed into `finish`, which returns
`Result<Vec<u8>, !>`.
- opaque.rs: The `FileEncoder` adopts the delayed error handling
strategy. Its `Ok` type is a `usize`, returning the number of bytes
written, replacing previous uses of `FileEncoder::position`.
- Various methods that take an encoder now consume it, rather than being
passed a mutable reference, e.g. `serialize_query_result_cache`.
2022-06-06 22:30:45 -05:00
|
|
|
fn encode(&self, s: &mut S) {
|
|
|
|
s.emit_u32(self.0);
|
2016-06-21 17:08:13 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-06-13 23:52:01 -05:00
|
|
|
impl<D: Decoder> Decodable<D> for BytePos {
|
Make `Decodable` and `Decoder` infallible.
`Decoder` has two impls:
- opaque: this impl is already partly infallible, i.e. in some places it
currently panics on failure (e.g. if the input is too short, or on a
bad `Result` discriminant), and in some places it returns an error
(e.g. on a bad `Option` discriminant). The number of places where
either happens is surprisingly small, just because the binary
representation has very little redundancy and a lot of input reading
can occur even on malformed data.
- json: this impl is fully fallible, but it's only used (a) for the
`.rlink` file production, and there's a `FIXME` comment suggesting it
should change to a binary format, and (b) in a few tests in
non-fundamental ways. Indeed #85993 is open to remove it entirely.
And the top-level places in the compiler that call into decoding just
abort on error anyway. So the fallibility is providing little value, and
getting rid of it leads to some non-trivial performance improvements.
Much of this commit is pretty boring and mechanical. Some notes about
a few interesting parts:
- The commit removes `Decoder::{Error,error}`.
- `InternIteratorElement::intern_with`: the impl for `T` now has the same
optimization for small counts that the impl for `Result<T, E>` has,
because it's now much hotter.
- Decodable impls for SmallVec, LinkedList, VecDeque now all use
`collect`, which is nice; the one for `Vec` uses unsafe code, because
that gave better perf on some benchmarks.
2022-01-17 20:22:50 -06:00
|
|
|
fn decode(d: &mut D) -> BytePos {
|
|
|
|
BytePos(d.read_u32())
|
2016-06-21 17:08:13 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// _____________________________________________________________________________
|
2019-04-05 14:42:40 -05:00
|
|
|
// Loc, SourceFileAndLine, SourceFileAndBytePos
|
2016-06-21 17:08:13 -05:00
|
|
|
//
|
|
|
|
|
2018-11-26 20:59:49 -06:00
|
|
|
/// A source code location used for error reporting.
|
2016-07-11 15:02:03 -05:00
|
|
|
#[derive(Debug, Clone)]
|
2016-06-21 17:08:13 -05:00
|
|
|
pub struct Loc {
|
2018-11-26 20:59:49 -06:00
|
|
|
/// Information about the original source.
|
2018-08-18 05:13:52 -05:00
|
|
|
pub file: Lrc<SourceFile>,
|
2018-11-26 20:59:49 -06:00
|
|
|
/// The (1-based) line number.
|
2016-06-21 17:08:13 -05:00
|
|
|
pub line: usize,
|
2018-11-26 20:59:49 -06:00
|
|
|
/// The (0-based) column offset.
|
2017-11-01 20:25:54 -05:00
|
|
|
pub col: CharPos,
|
2018-11-26 20:59:49 -06:00
|
|
|
/// The (0-based) column offset when displayed.
|
2017-11-01 20:25:54 -05:00
|
|
|
pub col_display: usize,
|
2016-06-21 17:08:13 -05:00
|
|
|
}
|
|
|
|
|
2018-11-26 20:59:49 -06:00
|
|
|
// Used to be structural records.
|
2016-06-21 17:08:13 -05:00
|
|
|
#[derive(Debug)]
|
2018-10-29 15:26:13 -05:00
|
|
|
pub struct SourceFileAndLine {
|
|
|
|
pub sf: Lrc<SourceFile>,
|
2021-11-15 13:40:29 -06:00
|
|
|
/// Index of line, starting from 0.
|
2018-10-29 15:26:13 -05:00
|
|
|
pub line: usize,
|
|
|
|
}
|
2016-06-21 17:08:13 -05:00
|
|
|
#[derive(Debug)]
|
2018-10-29 15:26:13 -05:00
|
|
|
pub struct SourceFileAndBytePos {
|
|
|
|
pub sf: Lrc<SourceFile>,
|
|
|
|
pub pos: BytePos,
|
|
|
|
}
|
2016-06-21 17:08:13 -05:00
|
|
|
|
|
|
|
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
|
|
|
|
pub struct LineInfo {
|
|
|
|
/// Index of line, starting from 0.
|
|
|
|
pub line_index: usize,
|
|
|
|
|
|
|
|
/// Column in line where span begins, starting from 0.
|
|
|
|
pub start_col: CharPos,
|
|
|
|
|
|
|
|
/// Column in line where span ends, starting from 0, exclusive.
|
|
|
|
pub end_col: CharPos,
|
|
|
|
}
|
|
|
|
|
|
|
|
pub struct FileLines {
|
2018-08-18 05:13:52 -05:00
|
|
|
pub file: Lrc<SourceFile>,
|
2016-06-21 17:08:13 -05:00
|
|
|
pub lines: Vec<LineInfo>,
|
|
|
|
}
|
|
|
|
|
2021-04-27 12:24:33 -05:00
|
|
|
pub static SPAN_TRACK: AtomicRef<fn(LocalDefId)> = AtomicRef::new(&((|_| {}) as fn(_)));
|
2016-06-21 17:08:13 -05:00
|
|
|
|
|
|
|
// _____________________________________________________________________________
|
2018-10-29 15:26:13 -05:00
|
|
|
// SpanLinesError, SpanSnippetError, DistinctSources, MalformedSourceMapPositions
|
2016-06-21 17:08:13 -05:00
|
|
|
//
|
|
|
|
|
|
|
|
pub type FileLinesResult = Result<FileLines, SpanLinesError>;
|
|
|
|
|
|
|
|
#[derive(Clone, PartialEq, Eq, Debug)]
|
|
|
|
pub enum SpanLinesError {
|
|
|
|
DistinctSources(DistinctSources),
|
|
|
|
}
|
|
|
|
|
|
|
|
#[derive(Clone, PartialEq, Eq, Debug)]
|
|
|
|
pub enum SpanSnippetError {
|
|
|
|
IllFormedSpan(Span),
|
|
|
|
DistinctSources(DistinctSources),
|
2018-10-29 15:26:13 -05:00
|
|
|
MalformedForSourcemap(MalformedSourceMapPositions),
|
2017-12-14 01:09:19 -06:00
|
|
|
SourceNotAvailable { filename: FileName },
|
2016-06-21 17:08:13 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
#[derive(Clone, PartialEq, Eq, Debug)]
|
|
|
|
pub struct DistinctSources {
|
2017-12-14 01:09:19 -06:00
|
|
|
pub begin: (FileName, BytePos),
|
|
|
|
pub end: (FileName, BytePos),
|
2016-06-21 17:08:13 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
#[derive(Clone, PartialEq, Eq, Debug)]
|
2018-10-29 15:26:13 -05:00
|
|
|
pub struct MalformedSourceMapPositions {
|
2017-12-14 01:09:19 -06:00
|
|
|
pub name: FileName,
|
2016-06-21 17:08:13 -05:00
|
|
|
pub source_len: usize,
|
|
|
|
pub begin_pos: BytePos,
|
|
|
|
pub end_pos: BytePos,
|
|
|
|
}
|
|
|
|
|
2019-07-29 23:43:54 -05:00
|
|
|
/// Range inside of a `Span` used for diagnostics when we only have access to relative positions.
|
2019-06-04 10:03:43 -05:00
|
|
|
#[derive(Copy, Clone, PartialEq, Eq, Debug)]
|
|
|
|
pub struct InnerSpan {
|
|
|
|
pub start: usize,
|
|
|
|
pub end: usize,
|
|
|
|
}
|
|
|
|
|
|
|
|
impl InnerSpan {
|
|
|
|
pub fn new(start: usize, end: usize) -> InnerSpan {
|
|
|
|
InnerSpan { start, end }
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-11-10 10:19:08 -06:00
|
|
|
/// Requirements for a `StableHashingContext` to be used in this crate.
|
2020-12-24 01:01:03 -06:00
|
|
|
///
|
|
|
|
/// This is a hack to allow using the [`HashStable_Generic`] derive macro
|
|
|
|
/// instead of implementing everything in rustc_middle.
|
2019-11-23 06:58:17 -06:00
|
|
|
pub trait HashStableContext {
|
2021-04-19 15:27:49 -05:00
|
|
|
fn def_path_hash(&self, def_id: DefId) -> DefPathHash;
|
2020-03-17 10:45:02 -05:00
|
|
|
fn hash_spans(&self) -> bool;
|
2022-07-06 07:44:47 -05:00
|
|
|
/// Accesses `sess.opts.unstable_opts.incremental_ignore_spans` since
|
2021-12-26 16:45:21 -06:00
|
|
|
/// we don't have easy access to a `Session`
|
2022-07-06 07:44:47 -05:00
|
|
|
fn unstable_opts_incremental_ignore_spans(&self) -> bool;
|
2021-04-18 07:27:28 -05:00
|
|
|
fn def_span(&self, def_id: LocalDefId) -> Span;
|
2020-09-20 19:40:51 -05:00
|
|
|
fn span_data_to_lines_and_cols(
|
|
|
|
&mut self,
|
|
|
|
span: &SpanData,
|
|
|
|
) -> Option<(Lrc<SourceFile>, usize, BytePos, usize, BytePos)>;
|
2021-12-24 15:36:33 -06:00
|
|
|
fn hashing_controls(&self) -> HashingControls;
|
2019-11-23 07:39:00 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
impl<CTX> HashStable<CTX> for Span
|
|
|
|
where
|
|
|
|
CTX: HashStableContext,
|
|
|
|
{
|
|
|
|
/// Hashes a span in a stable way. We can't directly hash the span's `BytePos`
|
|
|
|
/// fields (that would be similar to hashing pointers, since those are just
|
|
|
|
/// offsets into the `SourceMap`). Instead, we hash the (file name, line, column)
|
|
|
|
/// triple, which stays the same even if the containing `SourceFile` has moved
|
|
|
|
/// within the `SourceMap`.
|
2020-12-24 01:01:03 -06:00
|
|
|
///
|
2019-11-23 07:39:00 -06:00
|
|
|
/// Also note that we are hashing byte offsets for the column, not unicode
|
|
|
|
/// codepoint offsets. For the purpose of the hash that's sufficient.
|
|
|
|
/// Also, hashing filenames is expensive so we avoid doing it twice when the
|
|
|
|
/// span starts and ends in the same file, which is almost always the case.
|
|
|
|
fn hash_stable(&self, ctx: &mut CTX, hasher: &mut StableHasher) {
|
|
|
|
const TAG_VALID_SPAN: u8 = 0;
|
|
|
|
const TAG_INVALID_SPAN: u8 = 1;
|
2021-04-18 07:27:28 -05:00
|
|
|
const TAG_RELATIVE_SPAN: u8 = 2;
|
2019-11-23 07:39:00 -06:00
|
|
|
|
|
|
|
if !ctx.hash_spans() {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2021-04-30 13:15:22 -05:00
|
|
|
let span = self.data_untracked();
|
2021-04-18 07:27:28 -05:00
|
|
|
span.ctxt.hash_stable(ctx, hasher);
|
|
|
|
span.parent.hash_stable(ctx, hasher);
|
2021-03-11 05:31:31 -06:00
|
|
|
|
2021-04-18 07:27:28 -05:00
|
|
|
if span.is_dummy() {
|
2020-10-07 20:25:01 -05:00
|
|
|
Hash::hash(&TAG_INVALID_SPAN, hasher);
|
2020-03-17 10:45:02 -05:00
|
|
|
return;
|
2019-11-23 07:39:00 -06:00
|
|
|
}
|
|
|
|
|
2021-04-18 07:27:28 -05:00
|
|
|
if let Some(parent) = span.parent {
|
2021-04-30 13:15:22 -05:00
|
|
|
let def_span = ctx.def_span(parent).data_untracked();
|
2021-04-18 07:27:28 -05:00
|
|
|
if def_span.contains(span) {
|
|
|
|
// This span is enclosed in a definition: only hash the relative position.
|
|
|
|
Hash::hash(&TAG_RELATIVE_SPAN, hasher);
|
|
|
|
(span.lo - def_span.lo).to_u32().hash_stable(ctx, hasher);
|
|
|
|
(span.hi - def_span.lo).to_u32().hash_stable(ctx, hasher);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-11-23 07:39:00 -06:00
|
|
|
// If this is not an empty or invalid span, we want to hash the last
|
|
|
|
// position that belongs to it, as opposed to hashing the first
|
|
|
|
// position past it.
|
2022-02-18 17:48:49 -06:00
|
|
|
let Some((file, line_lo, col_lo, line_hi, col_hi)) = ctx.span_data_to_lines_and_cols(&span) else {
|
|
|
|
Hash::hash(&TAG_INVALID_SPAN, hasher);
|
|
|
|
return;
|
2020-09-01 23:50:07 -05:00
|
|
|
};
|
|
|
|
|
2020-10-07 20:25:01 -05:00
|
|
|
Hash::hash(&TAG_VALID_SPAN, hasher);
|
2019-11-23 07:39:00 -06:00
|
|
|
// We truncate the stable ID hash and line and column numbers. The chances
|
|
|
|
// of causing a collision this way should be minimal.
|
2020-09-20 19:40:51 -05:00
|
|
|
Hash::hash(&(file.name_hash as u64), hasher);
|
2019-11-23 07:39:00 -06:00
|
|
|
|
2020-09-01 23:50:07 -05:00
|
|
|
// Hash both the length and the end location (line/column) of a span. If we
|
|
|
|
// hash only the length, for example, then two otherwise equal spans with
|
|
|
|
// different end locations will have the same hash. This can cause a problem
|
|
|
|
// during incremental compilation wherein a previous result for a query that
|
|
|
|
// depends on the end location of a span will be incorrectly reused when the
|
|
|
|
// end location of the span it depends on has changed (see issue #74890). A
|
|
|
|
// similar analysis applies if some query depends specifically on the length
|
|
|
|
// of the span, but we only hash the end location. So hash both.
|
|
|
|
|
|
|
|
let col_lo_trunc = (col_lo.0 as u64) & 0xFF;
|
|
|
|
let line_lo_trunc = ((line_lo as u64) & 0xFF_FF_FF) << 8;
|
|
|
|
let col_hi_trunc = (col_hi.0 as u64) & 0xFF << 32;
|
|
|
|
let line_hi_trunc = ((line_hi as u64) & 0xFF_FF_FF) << 40;
|
|
|
|
let col_line = col_lo_trunc | line_lo_trunc | col_hi_trunc | line_hi_trunc;
|
|
|
|
let len = (span.hi - span.lo).0;
|
|
|
|
Hash::hash(&col_line, hasher);
|
|
|
|
Hash::hash(&len, hasher);
|
2020-03-17 10:45:02 -05:00
|
|
|
}
|
|
|
|
}
|