@@ -47,7 +47,7 @@ impl<'sm> CachingSourceMapView<'sm> {
4747
4848 // Check if the position is in one of the cached lines
4949 for cache_entry in self . line_cache . iter_mut ( ) {
50- if pos >= cache_entry. line_start && pos < cache_entry. line_end {
50+ if line_contains ( ( cache_entry. line_start , cache_entry. line_end ) , pos ) {
5151 cache_entry. time_stamp = self . time_stamp ;
5252
5353 return Some ( (
@@ -69,13 +69,13 @@ impl<'sm> CachingSourceMapView<'sm> {
6969 let cache_entry = & mut self . line_cache [ oldest] ;
7070
7171 // If the entry doesn't point to the correct file, fix it up
72- if pos < cache_entry. file . start_pos || pos >= cache_entry . file . end_pos {
72+ if ! file_contains ( & cache_entry. file , pos) {
7373 let file_valid;
7474 if self . source_map . files ( ) . len ( ) > 0 {
7575 let file_index = self . source_map . lookup_source_file_idx ( pos) ;
7676 let file = self . source_map . files ( ) [ file_index] . clone ( ) ;
7777
78- if pos >= file. start_pos && pos < file . end_pos {
78+ if file_contains ( & file, pos) {
7979 cache_entry. file = file;
8080 cache_entry. file_index = file_index;
8181 file_valid = true ;
@@ -102,3 +102,29 @@ impl<'sm> CachingSourceMapView<'sm> {
102102 Some ( ( cache_entry. file . clone ( ) , cache_entry. line_number , pos - cache_entry. line_start ) )
103103 }
104104}
105+
106+ #[ inline]
107+ fn line_contains ( line_bounds : ( BytePos , BytePos ) , pos : BytePos ) -> bool {
108+ // This condition will be false in one case where we'd rather it wasn't. Spans often start/end
109+ // one past something, and when that something is the last character of a file (this can happen
110+ // when a file doesn't end in a newline, for example), we'd still like for the position to be
111+ // considered within the last line. However, it isn't according to the exclusive upper bound
112+ // below. We cannot change the upper bound to be inclusive, because for most lines, the upper
113+ // bound is the same as the lower bound of the next line, so there would be an ambiguity.
114+ //
115+ // Supposing we only use this function to check whether or not the line cache entry contains
116+ // a position, the only ramification of the above is that we will get cache misses for these
117+ // rare positions. A line lookup for the position via `SourceMap::lookup_line` after a cache
118+ // miss will produce the last line number, as desired.
119+ line_bounds. 0 <= pos && pos < line_bounds. 1
120+ }
121+
122+ #[ inline]
123+ fn file_contains ( file : & SourceFile , pos : BytePos ) -> bool {
124+ // `SourceMap::lookup_source_file_idx` and `SourceFile::contains` both consider the position
125+ // one past the end of a file to belong to it. Normally, that's what we want. But for the
126+ // purposes of converting a byte position to a line and column number, we can't come up with a
127+ // line and column number if the file is empty, because an empty file doesn't contain any
128+ // lines. So for our purposes, we don't consider empty files to contain any byte position.
129+ file. contains ( pos) && !file. is_empty ( )
130+ }
0 commit comments