summaryrefslogtreecommitdiffstats
path: root/compiler/rustc_span/src/lib.rs
diff options
context:
space:
mode:
Diffstat (limited to 'compiler/rustc_span/src/lib.rs')
-rw-r--r--compiler/rustc_span/src/lib.rs512
1 files changed, 268 insertions, 244 deletions
diff --git a/compiler/rustc_span/src/lib.rs b/compiler/rustc_span/src/lib.rs
index c24b8d9ec..772e09291 100644
--- a/compiler/rustc_span/src/lib.rs
+++ b/compiler/rustc_span/src/lib.rs
@@ -21,9 +21,11 @@
#![feature(rustc_attrs)]
#![feature(let_chains)]
#![feature(round_char_boundary)]
+#![feature(read_buf)]
+#![feature(new_uninit)]
#![deny(rustc::untranslatable_diagnostic)]
#![deny(rustc::diagnostic_outside_of_impl)]
-#![cfg_attr(not(bootstrap), allow(internal_features))]
+#![allow(internal_features)]
#[macro_use]
extern crate rustc_macros;
@@ -31,7 +33,7 @@ extern crate rustc_macros;
#[macro_use]
extern crate tracing;
-use rustc_data_structures::AtomicRef;
+use rustc_data_structures::{outline, AtomicRef};
use rustc_macros::HashStable_Generic;
use rustc_serialize::{Decodable, Decoder, Encodable, Encoder};
@@ -62,7 +64,7 @@ pub mod fatal_error;
pub mod profiling;
use rustc_data_structures::stable_hasher::{Hash128, Hash64, HashStable, StableHasher};
-use rustc_data_structures::sync::{Lock, Lrc};
+use rustc_data_structures::sync::{FreezeLock, FreezeWriteGuard, Lock, Lrc};
use std::borrow::Cow;
use std::cmp::{self, Ordering};
@@ -508,10 +510,6 @@ impl SpanData {
pub fn is_dummy(self) -> bool {
self.lo.0 == 0 && self.hi.0 == 0
}
- #[inline]
- pub fn is_visible(self, sm: &SourceMap) -> bool {
- !self.is_dummy() && sm.is_span_accessible(self.span())
- }
/// Returns `true` if `self` fully encloses `other`.
pub fn contains(self, other: Self) -> bool {
self.lo <= other.lo && other.hi <= self.hi
@@ -571,15 +569,9 @@ impl Span {
self.data().with_parent(ctxt)
}
- /// Returns `true` if this is a dummy span with any hygienic context.
- #[inline]
- pub fn is_dummy(self) -> bool {
- self.data_untracked().is_dummy()
- }
-
#[inline]
pub fn is_visible(self, sm: &SourceMap) -> bool {
- self.data_untracked().is_visible(sm)
+ !self.is_dummy() && sm.is_span_accessible(self)
}
/// Returns `true` if this span comes from any kind of macro, desugaring or inlining.
@@ -1105,27 +1097,27 @@ impl fmt::Debug for SpanData {
}
/// Identifies an offset of a multi-byte character in a `SourceFile`.
-#[derive(Copy, Clone, Encodable, Decodable, Eq, PartialEq, Debug)]
+#[derive(Copy, Clone, Encodable, Decodable, Eq, PartialEq, Debug, HashStable_Generic)]
pub struct MultiByteChar {
- /// The absolute offset of the character in the `SourceMap`.
- pub pos: BytePos,
+ /// The relative offset of the character in the `SourceFile`.
+ pub pos: RelativeBytePos,
/// The number of bytes, `>= 2`.
pub bytes: u8,
}
/// Identifies an offset of a non-narrow character in a `SourceFile`.
-#[derive(Copy, Clone, Encodable, Decodable, Eq, PartialEq, Debug)]
+#[derive(Copy, Clone, Encodable, Decodable, Eq, PartialEq, Debug, HashStable_Generic)]
pub enum NonNarrowChar {
/// Represents a zero-width character.
- ZeroWidth(BytePos),
+ ZeroWidth(RelativeBytePos),
/// Represents a wide (full-width) character.
- Wide(BytePos),
+ Wide(RelativeBytePos),
/// Represents a tab character, represented visually with a width of 4 characters.
- Tab(BytePos),
+ Tab(RelativeBytePos),
}
impl NonNarrowChar {
- fn new(pos: BytePos, width: usize) -> Self {
+ fn new(pos: RelativeBytePos, width: usize) -> Self {
match width {
0 => NonNarrowChar::ZeroWidth(pos),
2 => NonNarrowChar::Wide(pos),
@@ -1134,8 +1126,8 @@ impl NonNarrowChar {
}
}
- /// Returns the absolute offset of the character in the `SourceMap`.
- pub fn pos(&self) -> BytePos {
+ /// Returns the relative offset of the character in the `SourceFile`.
+ pub fn pos(&self) -> RelativeBytePos {
match *self {
NonNarrowChar::ZeroWidth(p) | NonNarrowChar::Wide(p) | NonNarrowChar::Tab(p) => p,
}
@@ -1151,10 +1143,10 @@ impl NonNarrowChar {
}
}
-impl Add<BytePos> for NonNarrowChar {
+impl Add<RelativeBytePos> for NonNarrowChar {
type Output = Self;
- fn add(self, rhs: BytePos) -> Self {
+ fn add(self, rhs: RelativeBytePos) -> Self {
match self {
NonNarrowChar::ZeroWidth(pos) => NonNarrowChar::ZeroWidth(pos + rhs),
NonNarrowChar::Wide(pos) => NonNarrowChar::Wide(pos + rhs),
@@ -1163,10 +1155,10 @@ impl Add<BytePos> for NonNarrowChar {
}
}
-impl Sub<BytePos> for NonNarrowChar {
+impl Sub<RelativeBytePos> for NonNarrowChar {
type Output = Self;
- fn sub(self, rhs: BytePos) -> Self {
+ fn sub(self, rhs: RelativeBytePos) -> Self {
match self {
NonNarrowChar::ZeroWidth(pos) => NonNarrowChar::ZeroWidth(pos - rhs),
NonNarrowChar::Wide(pos) => NonNarrowChar::Wide(pos - rhs),
@@ -1176,10 +1168,10 @@ impl Sub<BytePos> for NonNarrowChar {
}
/// Identifies an offset of a character that was normalized away from `SourceFile`.
-#[derive(Copy, Clone, Encodable, Decodable, Eq, PartialEq, Debug)]
+#[derive(Copy, Clone, Encodable, Decodable, Eq, PartialEq, Debug, HashStable_Generic)]
pub struct NormalizedPos {
- /// The absolute offset of the character in the `SourceMap`.
- pub pos: BytePos,
+ /// The relative offset of the character in the `SourceFile`.
+ pub pos: RelativeBytePos,
/// The difference between original and normalized string at position.
pub diff: u32,
}
@@ -1204,7 +1196,6 @@ pub enum ExternalSourceKind {
AbsentOk,
/// A failed attempt has been made to load the external source.
AbsentErr,
- Unneeded,
}
impl ExternalSource {
@@ -1291,7 +1282,7 @@ impl SourceFileHash {
#[derive(Clone)]
pub enum SourceFileLines {
/// The source file lines, in decoded (random-access) form.
- Lines(Vec<BytePos>),
+ Lines(Vec<RelativeBytePos>),
/// The source file lines, in undecoded difference list form.
Diffs(SourceFileDiffs),
@@ -1312,11 +1303,6 @@ impl SourceFileLines {
/// 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.
@@ -1346,13 +1332,13 @@ pub struct SourceFile {
pub src_hash: SourceFileHash,
/// The external source code (used for external crates, which will have a `None`
/// value as `self.src`.
- pub external_src: Lock<ExternalSource>,
+ pub external_src: FreezeLock<ExternalSource>,
/// The start position of this source in the `SourceMap`.
pub start_pos: BytePos,
- /// The end position of this source in the `SourceMap`.
- pub end_pos: BytePos,
+ /// The byte length of this source.
+ pub source_len: RelativeBytePos,
/// Locations of lines beginnings in the source code.
- pub lines: Lock<SourceFileLines>,
+ pub lines: FreezeLock<SourceFileLines>,
/// Locations of multi-byte characters in the source code.
pub multibyte_chars: Vec<MultiByteChar>,
/// Width of characters that are not narrow in the source code.
@@ -1371,10 +1357,10 @@ impl Clone for SourceFile {
name: self.name.clone(),
src: self.src.clone(),
src_hash: self.src_hash,
- external_src: Lock::new(self.external_src.borrow().clone()),
+ external_src: self.external_src.clone(),
start_pos: self.start_pos,
- end_pos: self.end_pos,
- lines: Lock::new(self.lines.borrow().clone()),
+ source_len: self.source_len,
+ lines: self.lines.clone(),
multibyte_chars: self.multibyte_chars.clone(),
non_narrow_chars: self.non_narrow_chars.clone(),
normalized_pos: self.normalized_pos.clone(),
@@ -1388,68 +1374,67 @@ impl<S: Encoder> Encodable<S> for SourceFile {
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);
+ // Do not encode `start_pos` as it's global state for this session.
+ self.source_len.encode(s);
// We are always in `Lines` form by the time we reach here.
- assert!(self.lines.borrow().is_lines());
- self.lines(|lines| {
- // Store the length.
- s.emit_u32(lines.len() as u32);
-
- // 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.
- s.emit_u8(bytes_per_diff as u8);
-
- // Encode the first element.
- lines[0].encode(s);
-
- // 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);
- }
+ assert!(self.lines.read().is_lines());
+ let lines = self.lines();
+ // Store the length.
+ s.emit_u32(lines.len() as u32);
+
+ // 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.
+ s.emit_u8(bytes_per_diff as u8);
+
+ // Encode the first element.
+ assert_eq!(lines[0], RelativeBytePos(0));
+
+ // 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);
}
- 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());
- }
+ }
+ 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).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).to_le_bytes());
}
- _ => unreachable!(),
}
- s.emit_raw_bytes(&raw_diffs);
+ _ => unreachable!(),
}
- });
+ s.emit_raw_bytes(&raw_diffs);
+ }
self.multibyte_chars.encode(s);
self.non_narrow_chars.encode(s);
@@ -1463,26 +1448,17 @@ impl<D: Decoder> Decodable<D> for SourceFile {
fn decode(d: &mut D) -> SourceFile {
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);
+ let source_len: RelativeBytePos = Decodable::decode(d);
let lines = {
let num_lines: u32 = Decodable::decode(d);
if num_lines > 0 {
// Read the number of bytes used per diff.
let bytes_per_diff = d.read_u8() as usize;
- // Read the first element.
- let line_start: BytePos = Decodable::decode(d);
-
// 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();
- SourceFileLines::Diffs(SourceFileDiffs {
- line_start,
- bytes_per_diff,
- num_diffs,
- raw_diffs,
- })
+ SourceFileLines::Diffs(SourceFileDiffs { bytes_per_diff, num_diffs, raw_diffs })
} else {
SourceFileLines::Lines(vec![])
}
@@ -1494,14 +1470,14 @@ impl<D: Decoder> Decodable<D> for SourceFile {
let cnum: CrateNum = Decodable::decode(d);
SourceFile {
name,
- start_pos,
- end_pos,
+ start_pos: BytePos::from_u32(0),
+ source_len,
src: None,
src_hash,
// Unused - the metadata decoder will construct
// a new SourceFile, filling in `external_src` properly
- external_src: Lock::new(ExternalSource::Unneeded),
- lines: Lock::new(lines),
+ external_src: FreezeLock::frozen(ExternalSource::Unneeded),
+ lines: FreezeLock::new(lines),
multibyte_chars,
non_narrow_chars,
normalized_pos,
@@ -1521,102 +1497,116 @@ impl SourceFile {
pub fn new(
name: FileName,
mut src: String,
- start_pos: BytePos,
hash_kind: SourceFileHashAlgorithm,
- ) -> Self {
+ ) -> Result<Self, OffsetOverflowError> {
// Compute the file hash before any normalization.
let src_hash = SourceFileHash::new(hash_kind, &src);
- let normalized_pos = normalize_src(&mut src, start_pos);
+ let normalized_pos = normalize_src(&mut src);
let name_hash = {
let mut hasher: StableHasher = StableHasher::new();
name.hash(&mut hasher);
hasher.finish()
};
- let end_pos = start_pos.to_usize() + src.len();
- assert!(end_pos <= u32::MAX as usize);
+ let source_len = src.len();
+ let source_len = u32::try_from(source_len).map_err(|_| OffsetOverflowError)?;
let (lines, multibyte_chars, non_narrow_chars) =
- analyze_source_file::analyze_source_file(&src, start_pos);
+ analyze_source_file::analyze_source_file(&src);
- SourceFile {
+ Ok(SourceFile {
name,
src: Some(Lrc::new(src)),
src_hash,
- external_src: Lock::new(ExternalSource::Unneeded),
- start_pos,
- end_pos: Pos::from_usize(end_pos),
- lines: Lock::new(SourceFileLines::Lines(lines)),
+ external_src: FreezeLock::frozen(ExternalSource::Unneeded),
+ start_pos: BytePos::from_u32(0),
+ source_len: RelativeBytePos::from_u32(source_len),
+ lines: FreezeLock::frozen(SourceFileLines::Lines(lines)),
multibyte_chars,
non_narrow_chars,
normalized_pos,
name_hash,
cnum: LOCAL_CRATE,
- }
+ })
}
- pub fn lines<F, R>(&self, f: F) -> R
- where
- F: FnOnce(&[BytePos]) -> R,
- {
- let mut guard = self.lines.borrow_mut();
- match &*guard {
- SourceFileLines::Lines(lines) => f(lines),
- SourceFileLines::Diffs(SourceFileDiffs {
- mut line_start,
- bytes_per_diff,
- num_diffs,
- raw_diffs,
- }) => {
- // 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);
- *guard = SourceFileLines::Lines(lines);
- res
+ /// This converts the `lines` field to contain `SourceFileLines::Lines` if needed and freezes it.
+ fn convert_diffs_to_lines_frozen(&self) {
+ let mut guard = if let Some(guard) = self.lines.try_write() { guard } else { return };
+
+ let SourceFileDiffs { bytes_per_diff, num_diffs, raw_diffs } = match &*guard {
+ SourceFileLines::Diffs(diffs) => diffs,
+ SourceFileLines::Lines(..) => {
+ FreezeWriteGuard::freeze(guard);
+ return;
+ }
+ };
+
+ // Convert from "diffs" form to "lines" form.
+ let num_lines = num_diffs + 1;
+ let mut lines = Vec::with_capacity(num_lines);
+ let mut line_start = RelativeBytePos(0);
+ 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 + RelativeBytePos(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 + RelativeBytePos(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 + RelativeBytePos(diff);
+ line_start
+ }));
+ }
+ _ => unreachable!(),
}
+
+ *guard = SourceFileLines::Lines(lines);
+
+ FreezeWriteGuard::freeze(guard);
+ }
+
+ pub fn lines(&self) -> &[RelativeBytePos] {
+ if let Some(SourceFileLines::Lines(lines)) = self.lines.get() {
+ return &lines[..];
+ }
+
+ outline(|| {
+ self.convert_diffs_to_lines_frozen();
+ if let Some(SourceFileLines::Lines(lines)) = self.lines.get() {
+ return &lines[..];
+ }
+ unreachable!()
+ })
}
/// Returns the `BytePos` of the beginning of the current line.
pub fn line_begin_pos(&self, pos: BytePos) -> BytePos {
+ let pos = self.relative_position(pos);
let line_index = self.lookup_line(pos).unwrap();
- self.lines(|lines| lines[line_index])
+ let line_start_pos = self.lines()[line_index];
+ self.absolute_position(line_start_pos)
}
/// Add externally loaded source.
@@ -1627,35 +1617,37 @@ impl SourceFile {
where
F: FnOnce() -> Option<String>,
{
- if matches!(
- *self.external_src.borrow(),
- ExternalSource::Foreign { kind: ExternalSourceKind::AbsentOk, .. }
- ) {
+ if !self.external_src.is_frozen() {
let src = get_src();
- let mut external_src = self.external_src.borrow_mut();
- // Check that no-one else have provided the source while we were getting it
- if let ExternalSource::Foreign {
- kind: src_kind @ ExternalSourceKind::AbsentOk, ..
- } = &mut *external_src
- {
- if let Some(mut src) = src {
- // The src_hash needs to be computed on the pre-normalized src.
- if self.src_hash.matches(&src) {
- normalize_src(&mut src, BytePos::from_usize(0));
- *src_kind = ExternalSourceKind::Present(Lrc::new(src));
- return true;
- }
+ let src = src.and_then(|mut src| {
+ // The src_hash needs to be computed on the pre-normalized src.
+ self.src_hash.matches(&src).then(|| {
+ normalize_src(&mut src);
+ src
+ })
+ });
+
+ self.external_src.try_write().map(|mut external_src| {
+ if let ExternalSource::Foreign {
+ kind: src_kind @ ExternalSourceKind::AbsentOk,
+ ..
+ } = &mut *external_src
+ {
+ *src_kind = if let Some(src) = src {
+ ExternalSourceKind::Present(Lrc::new(src))
+ } else {
+ ExternalSourceKind::AbsentErr
+ };
} else {
- *src_kind = ExternalSourceKind::AbsentErr;
+ panic!("unexpected state {:?}", *external_src)
}
- false
- } else {
- self.src.is_some() || external_src.get_source().is_some()
- }
- } else {
- self.src.is_some() || self.external_src.borrow().get_source().is_some()
+ // Freeze this so we don't try to load the source again.
+ FreezeWriteGuard::freeze(external_src)
+ });
}
+
+ self.src.is_some() || self.external_src.read().get_source().is_some()
}
/// Gets a line from the list of pre-computed line-beginnings.
@@ -1673,9 +1665,8 @@ impl SourceFile {
}
let begin = {
- let line = self.lines(|lines| lines.get(line_number).copied())?;
- let begin: BytePos = line - self.start_pos;
- begin.to_usize()
+ let line = self.lines().get(line_number).copied()?;
+ line.to_usize()
};
if let Some(ref src) = self.src {
@@ -1698,30 +1689,44 @@ impl SourceFile {
}
pub fn count_lines(&self) -> usize {
- self.lines(|lines| lines.len())
+ self.lines().len()
+ }
+
+ #[inline]
+ pub fn absolute_position(&self, pos: RelativeBytePos) -> BytePos {
+ BytePos::from_u32(pos.to_u32() + self.start_pos.to_u32())
+ }
+
+ #[inline]
+ pub fn relative_position(&self, pos: BytePos) -> RelativeBytePos {
+ RelativeBytePos::from_u32(pos.to_u32() - self.start_pos.to_u32())
+ }
+
+ #[inline]
+ pub fn end_position(&self) -> BytePos {
+ self.absolute_position(self.source_len)
}
/// Finds the line containing the given position. The return value is the
/// index into the `lines` array of this `SourceFile`, not the 1-based line
/// number. If the source_file is empty or the position is located before the
/// first line, `None` is returned.
- pub fn lookup_line(&self, pos: BytePos) -> Option<usize> {
- self.lines(|lines| lines.partition_point(|x| x <= &pos).checked_sub(1))
+ pub fn lookup_line(&self, pos: RelativeBytePos) -> Option<usize> {
+ self.lines().partition_point(|x| x <= &pos).checked_sub(1)
}
pub fn line_bounds(&self, line_index: usize) -> Range<BytePos> {
if self.is_empty() {
- return self.start_pos..self.end_pos;
+ return self.start_pos..self.start_pos;
}
- 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]
- }
- })
+ let lines = self.lines();
+ assert!(line_index < lines.len());
+ if line_index == (lines.len() - 1) {
+ self.absolute_position(lines[line_index])..self.end_position()
+ } else {
+ self.absolute_position(lines[line_index])..self.absolute_position(lines[line_index + 1])
+ }
}
/// Returns whether or not the file contains the given `SourceMap` byte
@@ -1730,27 +1735,29 @@ impl SourceFile {
/// returns true still contain one byte position according to this function.
#[inline]
pub fn contains(&self, byte_pos: BytePos) -> bool {
- byte_pos >= self.start_pos && byte_pos <= self.end_pos
+ byte_pos >= self.start_pos && byte_pos <= self.end_position()
}
#[inline]
pub fn is_empty(&self) -> bool {
- self.start_pos == self.end_pos
+ self.source_len.to_u32() == 0
}
/// 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 {
+ pub fn original_relative_byte_pos(&self, pos: BytePos) -> RelativeBytePos {
+ let pos = self.relative_position(pos);
+
// 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(0) => 0,
Err(i) => self.normalized_pos[i - 1].diff,
};
- BytePos::from_u32(pos.0 - self.start_pos.0 + diff)
+ RelativeBytePos::from_u32(pos.0 + diff)
}
/// Calculates a normalized byte position from a byte offset relative to the
@@ -1768,15 +1775,15 @@ impl SourceFile {
.binary_search_by(|np| (np.pos.0 + np.diff).cmp(&(self.start_pos.0 + offset)))
{
Ok(i) => self.normalized_pos[i].diff,
- Err(i) if i == 0 => 0,
+ Err(0) => 0,
Err(i) => self.normalized_pos[i - 1].diff,
};
BytePos::from_u32(self.start_pos.0 + offset - diff)
}
- /// Converts an absolute `BytePos` to a `CharPos` relative to the `SourceFile`.
- pub fn bytepos_to_file_charpos(&self, bpos: BytePos) -> CharPos {
+ /// Converts an relative `RelativeBytePos` to a `CharPos` relative to the `SourceFile`.
+ fn bytepos_to_file_charpos(&self, bpos: RelativeBytePos) -> CharPos {
// The number of extra bytes due to multibyte chars in the `SourceFile`.
let mut total_extra_bytes = 0;
@@ -1794,18 +1801,18 @@ impl SourceFile {
}
}
- 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)
+ assert!(total_extra_bytes <= bpos.to_u32());
+ CharPos(bpos.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) {
+ /// given `RelativeBytePos`.
+ fn lookup_file_pos(&self, pos: RelativeBytePos) -> (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
- let linebpos = self.lines(|lines| lines[a]);
+ let linebpos = self.lines()[a];
let linechpos = self.bytepos_to_file_charpos(linebpos);
let col = chpos - linechpos;
debug!("byte pos {:?} is on the line at byte pos {:?}", pos, linebpos);
@@ -1821,10 +1828,11 @@ impl SourceFile {
/// 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 pos = self.relative_position(pos);
let (line, col_or_chpos) = self.lookup_file_pos(pos);
if line > 0 {
let col = col_or_chpos;
- let linebpos = self.lines(|lines| lines[line - 1]);
+ let linebpos = self.lines()[line - 1];
let col_display = {
let start_width_idx = self
.non_narrow_chars
@@ -1859,16 +1867,10 @@ impl SourceFile {
}
/// Normalizes the source code and records the normalizations.
-fn normalize_src(src: &mut String, start_pos: BytePos) -> Vec<NormalizedPos> {
+fn normalize_src(src: &mut String) -> 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
}
@@ -1876,7 +1878,7 @@ fn normalize_src(src: &mut String, start_pos: BytePos) -> Vec<NormalizedPos> {
fn remove_bom(src: &mut String, normalized_pos: &mut Vec<NormalizedPos>) {
if src.starts_with('\u{feff}') {
src.drain(..3);
- normalized_pos.push(NormalizedPos { pos: BytePos(0), diff: 3 });
+ normalized_pos.push(NormalizedPos { pos: RelativeBytePos(0), diff: 3 });
}
}
@@ -1911,7 +1913,7 @@ fn normalize_newlines(src: &mut String, normalized_pos: &mut Vec<NormalizedPos>)
cursor += idx - gap_len;
gap_len += 1;
normalized_pos.push(NormalizedPos {
- pos: BytePos::from_usize(cursor + 1),
+ pos: RelativeBytePos::from_usize(cursor + 1),
diff: original_gap + gap_len as u32,
});
}
@@ -2013,6 +2015,10 @@ impl_pos! {
#[derive(Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord, Debug)]
pub struct BytePos(pub u32);
+ /// A byte offset relative to file beginning.
+ #[derive(Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord, Debug)]
+ pub struct RelativeBytePos(pub u32);
+
/// A character offset.
///
/// Because of multibyte UTF-8 characters, a byte offset
@@ -2034,6 +2040,24 @@ impl<D: Decoder> Decodable<D> for BytePos {
}
}
+impl<H: HashStableContext> HashStable<H> for RelativeBytePos {
+ fn hash_stable(&self, hcx: &mut H, hasher: &mut StableHasher) {
+ self.0.hash_stable(hcx, hasher);
+ }
+}
+
+impl<S: Encoder> Encodable<S> for RelativeBytePos {
+ fn encode(&self, s: &mut S) {
+ s.emit_u32(self.0);
+ }
+}
+
+impl<D: Decoder> Decodable<D> for RelativeBytePos {
+ fn decode(d: &mut D) -> RelativeBytePos {
+ RelativeBytePos(d.read_u32())
+ }
+}
+
// _____________________________________________________________________________
// Loc, SourceFileAndLine, SourceFileAndBytePos
//