From 257d279fe47bbf3431c76f0942654c1bcf60d501 Mon Sep 17 00:00:00 2001 From: Michael Woerister Date: Wed, 23 May 2018 15:59:42 +0200 Subject: [PATCH] Make FileMap::{lines, multibyte_chars, non_narrow_chars} non-mutable. --- src/librustc/ich/impls_syntax.rs | 30 ++--- src/librustc/ty/query/on_disk_cache.rs | 2 +- src/librustc_metadata/decoder.rs | 9 +- src/libsyntax/codemap.rs | 40 +++---- src/libsyntax/parse/lexer/mod.rs | 20 +--- src/libsyntax_pos/lib.rs | 158 ++++++++++++++----------- 6 files changed, 121 insertions(+), 138 deletions(-) diff --git a/src/librustc/ich/impls_syntax.rs b/src/librustc/ich/impls_syntax.rs index 935bc4c8c6d8..a7a6a71474f0 100644 --- a/src/librustc/ich/impls_syntax.rs +++ b/src/librustc/ich/impls_syntax.rs @@ -455,27 +455,21 @@ impl<'a> HashStable> for FileMap { src_hash.hash_stable(hcx, hasher); // We only hash the relative position within this filemap - lines.with_lock(|lines| { - lines.len().hash_stable(hcx, hasher); - for &line in lines.iter() { - stable_byte_pos(line, start_pos).hash_stable(hcx, hasher); - } - }); + lines.len().hash_stable(hcx, hasher); + for &line in lines.iter() { + stable_byte_pos(line, start_pos).hash_stable(hcx, hasher); + } // We only hash the relative position within this filemap - multibyte_chars.with_lock(|multibyte_chars| { - multibyte_chars.len().hash_stable(hcx, hasher); - for &char_pos in multibyte_chars.iter() { - stable_multibyte_char(char_pos, start_pos).hash_stable(hcx, hasher); - } - }); + multibyte_chars.len().hash_stable(hcx, hasher); + for &char_pos in multibyte_chars.iter() { + stable_multibyte_char(char_pos, start_pos).hash_stable(hcx, hasher); + } - non_narrow_chars.with_lock(|non_narrow_chars| { - non_narrow_chars.len().hash_stable(hcx, hasher); - for &char_pos in non_narrow_chars.iter() { - stable_non_narrow_char(char_pos, start_pos).hash_stable(hcx, hasher); - } - }); + non_narrow_chars.len().hash_stable(hcx, hasher); + for &char_pos in non_narrow_chars.iter() { + stable_non_narrow_char(char_pos, start_pos).hash_stable(hcx, hasher); + } } } diff --git a/src/librustc/ty/query/on_disk_cache.rs b/src/librustc/ty/query/on_disk_cache.rs index 3285380c8239..7aa6f3a55ad7 100644 --- a/src/librustc/ty/query/on_disk_cache.rs +++ b/src/librustc/ty/query/on_disk_cache.rs @@ -623,7 +623,7 @@ impl<'a, 'tcx, 'x> SpecializedDecoder for CacheDecoder<'a, 'tcx, 'x> { let len = BytePos::decode(self)?; let file_lo = self.file_index_to_file(file_lo_index); - let lo = file_lo.lines.borrow()[line_lo - 1] + col_lo; + let lo = file_lo.lines[line_lo - 1] + col_lo; let hi = lo + len; let expn_info_tag = u8::decode(self)?; diff --git a/src/librustc_metadata/decoder.rs b/src/librustc_metadata/decoder.rs index 9e4f695d28fd..a01e0b608646 100644 --- a/src/librustc_metadata/decoder.rs +++ b/src/librustc_metadata/decoder.rs @@ -1138,9 +1138,9 @@ impl<'a, 'tcx> CrateMetadata { src_hash, start_pos, end_pos, - lines, - multibyte_chars, - non_narrow_chars, + mut lines, + mut multibyte_chars, + mut non_narrow_chars, name_hash, .. } = filemap_to_import; @@ -1151,15 +1151,12 @@ impl<'a, 'tcx> CrateMetadata { // `CodeMap::new_imported_filemap()` will then translate those // coordinates to their new global frame of reference when the // offset of the FileMap is known. - let mut lines = lines.into_inner(); for pos in &mut lines { *pos = *pos - start_pos; } - let mut multibyte_chars = multibyte_chars.into_inner(); for mbc in &mut multibyte_chars { mbc.pos = mbc.pos - start_pos; } - let mut non_narrow_chars = non_narrow_chars.into_inner(); for swc in &mut non_narrow_chars { *swc = *swc - start_pos; } diff --git a/src/libsyntax/codemap.rs b/src/libsyntax/codemap.rs index 8e4b7660a1cc..000f16075148 100644 --- a/src/libsyntax/codemap.rs +++ b/src/libsyntax/codemap.rs @@ -250,16 +250,7 @@ impl CodeMap { /// Creates a new filemap and sets its line information. /// This does not ensure that only one FileMap exists per file name. pub fn new_filemap_and_lines(&self, filename: &Path, src: &str) -> Lrc { - let fm = self.new_filemap(filename.to_owned().into(), src.to_owned()); - let mut byte_pos: u32 = fm.start_pos.0; - for line in src.lines() { - // register the start of this line - fm.next_line(BytePos(byte_pos)); - - // update byte_pos to include this line and the \n at the end - byte_pos += line.len() as u32 + 1; - } - fm + self.new_filemap(filename.to_owned().into(), src.to_owned()) } @@ -305,9 +296,9 @@ impl CodeMap { external_src: Lock::new(ExternalSource::AbsentOk), start_pos, end_pos, - lines: Lock::new(file_local_lines), - multibyte_chars: Lock::new(file_local_multibyte_chars), - non_narrow_chars: Lock::new(file_local_non_narrow_chars), + lines: file_local_lines, + multibyte_chars: file_local_multibyte_chars, + non_narrow_chars: file_local_non_narrow_chars, name_hash, }); @@ -345,21 +336,22 @@ impl CodeMap { match self.lookup_line(pos) { Ok(FileMapAndLine { fm: f, line: a }) => { let line = a + 1; // Line numbers start at 1 - let linebpos = (*f.lines.borrow())[a]; + let linebpos = f.lines[a]; let linechpos = self.bytepos_to_file_charpos(linebpos); let col = chpos - linechpos; let col_display = { - let non_narrow_chars = f.non_narrow_chars.borrow(); - let start_width_idx = non_narrow_chars + let start_width_idx = f + .non_narrow_chars .binary_search_by_key(&linebpos, |x| x.pos()) .unwrap_or_else(|x| x); - let end_width_idx = non_narrow_chars + let end_width_idx = f + .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 = - non_narrow_chars[start_width_idx..end_width_idx] + let non_narrow: usize = f + .non_narrow_chars[start_width_idx..end_width_idx] .into_iter() .map(|x| x.width()) .sum(); @@ -380,12 +372,12 @@ impl CodeMap { } Err(f) => { let col_display = { - let non_narrow_chars = f.non_narrow_chars.borrow(); - let end_width_idx = non_narrow_chars + let end_width_idx = f + .non_narrow_chars .binary_search_by_key(&pos, |x| x.pos()) .unwrap_or_else(|x| x); - let non_narrow: usize = - non_narrow_chars[0..end_width_idx] + let non_narrow: usize = f + .non_narrow_chars[0..end_width_idx] .into_iter() .map(|x| x.width()) .sum(); @@ -830,7 +822,7 @@ impl CodeMap { // The number of extra bytes due to multibyte chars in the FileMap let mut total_extra_bytes = 0; - for mbc in map.multibyte_chars.borrow().iter() { + for mbc in map.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 diff --git a/src/libsyntax/parse/lexer/mod.rs b/src/libsyntax/parse/lexer/mod.rs index c09cfd910d20..dcc71e787785 100644 --- a/src/libsyntax/parse/lexer/mod.rs +++ b/src/libsyntax/parse/lexer/mod.rs @@ -51,11 +51,7 @@ pub struct StringReader<'a> { pub ch: Option, pub filemap: Lrc, /// Stop reading src at this index. - end_src_index: usize, - /// Whether to record new-lines and multibyte chars in filemap. - /// This is only necessary the first time a filemap is lexed. - /// If part of a filemap is being re-lexed, this should be set to false. - save_new_lines_and_multibyte: bool, + pub end_src_index: usize, // cached: peek_tok: token::Token, peek_span: Span, @@ -188,7 +184,6 @@ impl<'a> StringReader<'a> { ch: Some('\n'), filemap, end_src_index: src.len(), - save_new_lines_and_multibyte: true, // dummy values; not read peek_tok: token::Eof, peek_span: syntax_pos::DUMMY_SP, @@ -225,7 +220,6 @@ impl<'a> StringReader<'a> { let mut sr = StringReader::new_raw_internal(sess, begin.fm, None); // Seek the lexer to the right byte range. - sr.save_new_lines_and_multibyte = false; sr.next_pos = span.lo(); sr.end_src_index = sr.src_index(span.hi()); @@ -458,18 +452,6 @@ impl<'a> StringReader<'a> { let next_ch = char_at(&self.src, next_src_index); let next_ch_len = next_ch.len_utf8(); - if self.ch.unwrap() == '\n' { - if self.save_new_lines_and_multibyte { - self.filemap.next_line(self.next_pos); - } - } - if next_ch_len > 1 { - if self.save_new_lines_and_multibyte { - self.filemap.record_multibyte_char(self.next_pos, next_ch_len); - } - } - self.filemap.record_width(self.next_pos, next_ch); - self.ch = Some(next_ch); self.pos = self.next_pos; self.next_pos = self.next_pos + Pos::from_usize(next_ch_len); diff --git a/src/libsyntax_pos/lib.rs b/src/libsyntax_pos/lib.rs index 756e0c059a72..266737dd7b66 100644 --- a/src/libsyntax_pos/lib.rs +++ b/src/libsyntax_pos/lib.rs @@ -779,11 +779,11 @@ pub struct FileMap { /// The end position of this source in the CodeMap pub end_pos: BytePos, /// Locations of lines beginnings in the source code - pub lines: Lock>, + pub lines: Vec, /// Locations of multi-byte characters in the source code - pub multibyte_chars: Lock>, + pub multibyte_chars: Vec, /// Width of characters that are not narrow in the source code - pub non_narrow_chars: Lock>, + pub non_narrow_chars: Vec, /// A hash of the filename, used for speeding up the incr. comp. hashing. pub name_hash: u128, } @@ -797,7 +797,7 @@ impl Encodable for FileMap { s.emit_struct_field("start_pos", 4, |s| self.start_pos.encode(s))?; s.emit_struct_field("end_pos", 5, |s| self.end_pos.encode(s))?; s.emit_struct_field("lines", 6, |s| { - let lines = self.lines.borrow(); + let lines = &self.lines[..]; // store the length s.emit_u32(lines.len() as u32)?; @@ -843,10 +843,10 @@ impl Encodable for FileMap { Ok(()) })?; s.emit_struct_field("multibyte_chars", 7, |s| { - (*self.multibyte_chars.borrow()).encode(s) + self.multibyte_chars.encode(s) })?; s.emit_struct_field("non_narrow_chars", 8, |s| { - (*self.non_narrow_chars.borrow()).encode(s) + self.non_narrow_chars.encode(s) })?; s.emit_struct_field("name_hash", 9, |s| { self.name_hash.encode(s) @@ -914,9 +914,9 @@ impl Decodable for FileMap { src: None, src_hash, external_src: Lock::new(ExternalSource::AbsentOk), - lines: Lock::new(lines), - multibyte_chars: Lock::new(multibyte_chars), - non_narrow_chars: Lock::new(non_narrow_chars), + lines, + multibyte_chars, + non_narrow_chars, name_hash, }) }) @@ -949,6 +949,9 @@ impl FileMap { }; let end_pos = start_pos.to_usize() + src.len(); + let (lines, multibyte_chars, non_narrow_chars) = + Self::find_newlines_and_special_chars(&src[..], start_pos); + FileMap { name, name_was_remapped, @@ -959,34 +962,81 @@ impl FileMap { external_src: Lock::new(ExternalSource::Unneeded), start_pos, end_pos: Pos::from_usize(end_pos), - lines: Lock::new(Vec::new()), - multibyte_chars: Lock::new(Vec::new()), - non_narrow_chars: Lock::new(Vec::new()), + lines, + multibyte_chars, + non_narrow_chars, name_hash, } } - /// EFFECT: register a start-of-line offset in the - /// table of line-beginnings. - /// UNCHECKED INVARIANT: these offsets must be added in the right - /// order and must be in the right places; there is shared knowledge - /// about what ends a line between this file and parse.rs - /// WARNING: pos param here is the offset relative to start of CodeMap, - /// and CodeMap will append a newline when adding a filemap without a newline at the end, - /// so the safe way to call this is with value calculated as - /// filemap.start_pos + newline_offset_relative_to_the_start_of_filemap. - pub fn next_line(&self, pos: BytePos) { - // the new charpos must be > the last one (or it's the first one). - let mut lines = self.lines.borrow_mut(); - let line_len = lines.len(); - assert!(line_len == 0 || ((*lines)[line_len - 1] < pos)); - lines.push(pos); + fn find_newlines_and_special_chars(src: &str, filemap_start_pos: BytePos) + -> (Vec, Vec, Vec) { + + let mut index = 0; + let mut lines = vec![filemap_start_pos]; + let mut multibyte_chars = vec![]; + let mut non_narrow_chars = vec![]; + + while index < src.len() { + let byte_pos = BytePos::from_usize(index) + filemap_start_pos; + let byte = src.as_bytes()[index]; + + if byte.is_ascii() { + match byte { + b'\n' => { + lines.push(byte_pos + BytePos(1)); + } + b'\t' => { + // Tabs will consume 4 columns. + non_narrow_chars.push(NonNarrowChar::new(byte_pos, 4)); + } + c => if c.is_ascii_control() { + // Assume control characters are zero width. + non_narrow_chars.push(NonNarrowChar::new(byte_pos, 0)); + } + } + + index += 1; + } else { + let c = (&src[index..]).chars().next().unwrap(); + let c_len = c.len_utf8(); + + if c_len > 1 { + assert!(c_len >=2 && c_len <= 4); + let mbc = MultiByteChar { + pos: byte_pos, + bytes: c_len, + }; + multibyte_chars.push(mbc); + } + + // Assume control characters are zero width. + // FIXME: How can we decide between `width` and `width_cjk`? + let c_width = unicode_width::UnicodeWidthChar::width(c).unwrap_or(0); + + if c_width != 1 { + non_narrow_chars.push(NonNarrowChar::new(byte_pos, c_width)); + } + + index += c_len; + } + } + + // The loop above optimistically registers a new line *after* each of \n + // it encounters. If that point is already outside the filemap, remove + // it again. + if let Some(&last_line_start) = lines.last() { + if last_line_start == filemap_start_pos + BytePos::from_usize(src.len()) { + lines.pop(); + } + } + + (lines, multibyte_chars, non_narrow_chars) } /// Return the BytePos of the beginning of the current line. pub fn line_begin_pos(&self) -> BytePos { - let lines = self.lines.borrow(); - match lines.last() { + match self.lines.last() { Some(&line_pos) => line_pos, None => self.start_pos, } @@ -1040,8 +1090,7 @@ impl FileMap { } let begin = { - let lines = self.lines.borrow(); - let line = if let Some(line) = lines.get(line_number) { + let line = if let Some(line) = self.lines.get(line_number) { line } else { return None; @@ -1059,35 +1108,6 @@ impl FileMap { } } - pub fn record_multibyte_char(&self, pos: BytePos, bytes: usize) { - assert!(bytes >=2 && bytes <= 4); - let mbc = MultiByteChar { - pos, - bytes, - }; - self.multibyte_chars.borrow_mut().push(mbc); - } - - #[inline] - pub fn record_width(&self, pos: BytePos, ch: char) { - let width = match ch { - '\t' => - // Tabs will consume 4 columns. - 4, - '\n' => - // Make newlines take one column so that displayed spans can point them. - 1, - ch => - // Assume control characters are zero width. - // FIXME: How can we decide between `width` and `width_cjk`? - unicode_width::UnicodeWidthChar::width(ch).unwrap_or(0), - }; - // Only record non-narrow characters. - if width != 1 { - self.non_narrow_chars.borrow_mut().push(NonNarrowChar::new(pos, width)); - } - } - pub fn is_real_file(&self) -> bool { self.name.is_real() } @@ -1100,7 +1120,7 @@ impl FileMap { self.end_pos.0 - self.start_pos.0 } pub fn count_lines(&self) -> usize { - self.lines.borrow().len() + self.lines.len() } /// Find the line containing the given position. The return value is the @@ -1108,13 +1128,12 @@ impl FileMap { /// number. If the filemap is empty or the position is located before the /// first line, None is returned. pub fn lookup_line(&self, pos: BytePos) -> Option { - let lines = self.lines.borrow(); - if lines.len() == 0 { + if self.lines.len() == 0 { return None; } - let line_index = lookup_line(&lines[..], pos); - assert!(line_index < lines.len() as isize); + let line_index = lookup_line(&self.lines[..], pos); + assert!(line_index < self.lines.len() as isize); if line_index >= 0 { Some(line_index as usize) } else { @@ -1127,12 +1146,11 @@ impl FileMap { return (self.start_pos, self.end_pos); } - let lines = self.lines.borrow(); - assert!(line_index < lines.len()); - if line_index == (lines.len() - 1) { - (lines[line_index], self.end_pos) + assert!(line_index < self.lines.len()); + if line_index == (self.lines.len() - 1) { + (self.lines[line_index], self.end_pos) } else { - (lines[line_index], lines[line_index + 1]) + (self.lines[line_index], self.lines[line_index + 1]) } }