Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 14 additions & 1 deletion compiler/rustc_span/src/source_map.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@

use std::fs::File;
use std::io::{self, BorrowedBuf, Read};
use std::sync::atomic::{AtomicUsize, Ordering};
use std::{fs, path};

use rustc_data_structures::sync::{IntoDynSyncSend, MappedReadGuard, ReadGuard, RwLock};
Expand Down Expand Up @@ -196,6 +197,7 @@ pub struct SourceMapInputs {

pub struct SourceMap {
files: RwLock<SourceMapFiles>,
recent_file_index: AtomicUsize,
file_loader: IntoDynSyncSend<Box<dyn FileLoader + Sync + Send>>,

// This is used to apply the file path remapping as specified via
Expand All @@ -219,6 +221,7 @@ impl std::fmt::Debug for SourceMap {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
let SourceMap {
files,
recent_file_index: _,
file_loader,
path_mapping,
working_dir,
Expand Down Expand Up @@ -257,6 +260,7 @@ impl SourceMap {
debug!(?working_dir);
SourceMap {
files: Default::default(),
recent_file_index: AtomicUsize::new(usize::MAX),
working_dir,
file_loader: IntoDynSyncSend(file_loader),
path_mapping,
Expand Down Expand Up @@ -1086,7 +1090,16 @@ impl SourceMap {
/// This index is guaranteed to be valid for the lifetime of this `SourceMap`,
/// since `source_files` is a `MonotonicVec`
pub fn lookup_source_file_idx(&self, pos: BytePos) -> usize {
self.files.borrow().source_files.partition_point(|x| x.start_pos <= pos) - 1
let files = self.files.borrow();
let recent = self.recent_file_index.load(Ordering::Relaxed);
// Files are append-only and their inclusive position ranges never overlap.
// The hint carries no synchronization: validate it against the borrowed table.
if files.source_files.get(recent).is_some_and(|file| file.contains(pos)) {
return recent;
}
let index = files.source_files.partition_point(|x| x.start_pos <= pos) - 1;
self.recent_file_index.store(index, Ordering::Relaxed);
index
}

pub fn count_lines(&self) -> usize {
Expand Down
17 changes: 17 additions & 0 deletions compiler/rustc_span/src/source_map/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -797,3 +797,20 @@ fn read_binary_file_handles_lying_stat() {
let bin = RealFileLoader.read_binary_file(kernel_max).unwrap();
assert_eq!(&real[..], &bin[..]);
}

#[test]
fn lookup_source_file_hint_matches_search_after_append() {
create_default_session_globals_then(|| {
let sm = init_source_map();
for extra in ["", "aé\nb", "last"] {
let end = sm.files().last().unwrap().end_position().0;
for pos in (0..=end + 4).chain((0..=end + 4).rev()) {
let pos = BytePos(pos);
let expected = sm.files().partition_point(|file| file.start_pos <= pos) - 1;
assert_eq!(sm.lookup_source_file_idx(pos), expected);
assert_eq!(sm.lookup_source_file_idx(pos), expected);
}
sm.new_source_file(filename(&sm, &format!("extra-{end}.rs")), extra.into());
}
});
}