@@ -33,6 +33,7 @@ use std::cell::Ref;
3333use std:: collections:: BTreeMap ;
3434use std:: io;
3535use std:: mem;
36+ use std:: ops:: RangeInclusive ;
3637use std:: rc:: Rc ;
3738use std:: u32;
3839
@@ -50,9 +51,6 @@ pub struct DecodeContext<'a, 'tcx: 'a> {
5051 sess : Option < & ' a Session > ,
5152 tcx : Option < TyCtxt < ' a , ' tcx , ' tcx > > ,
5253
53- // Cache the last used filemap for translating spans as an optimization.
54- last_filemap_index : usize ,
55-
5654 lazy_state : LazyState ,
5755}
5856
@@ -70,7 +68,7 @@ pub trait Metadata<'a, 'tcx>: Copy {
7068 cdata : self . cdata ( ) ,
7169 sess : self . sess ( ) . or ( tcx. map ( |tcx| tcx. sess ) ) ,
7270 tcx,
73- last_filemap_index : 0 ,
71+
7472 lazy_state : LazyState :: NoNode ,
7573 }
7674 }
@@ -270,63 +268,46 @@ impl<'a, 'tcx> SpecializedDecoder<DefIndex> for DecodeContext<'a, 'tcx> {
270268
271269impl < ' a , ' tcx > SpecializedDecoder < Span > for DecodeContext < ' a , ' tcx > {
272270 fn specialized_decode ( & mut self ) -> Result < Span , Self :: Error > {
273- let tag = u8 :: decode ( self ) ?;
271+ let cnum_tag = u32 :: decode ( self ) ?;
274272
275- if tag == TAG_INVALID_SPAN {
273+ if cnum_tag == TAG_INVALID_SPAN_CNUM {
276274 return Ok ( DUMMY_SP )
277275 }
278276
279- debug_assert_eq ! ( tag, TAG_VALID_SPAN ) ;
277+ let original_cnum = CrateNum :: from_u32 ( cnum_tag - TAG_VALID_SPAN_CNUM_START ) ;
278+ let cnum = self . map_encoded_cnum_to_current ( original_cnum) ;
280279
281280 let lo = BytePos :: decode ( self ) ?;
282281 let len = BytePos :: decode ( self ) ?;
283- let hi = lo + len;
284282
285283 let sess = if let Some ( sess) = self . sess {
286284 sess
287285 } else {
288286 bug ! ( "Cannot decode Span without Session." )
289287 } ;
290288
291- let imported_filemaps = self . cdata ( ) . imported_filemaps ( & sess. codemap ( ) ) ;
292- let filemap = {
293- // Optimize for the case that most spans within a translated item
294- // originate from the same filemap.
295- let last_filemap = & imported_filemaps[ self . last_filemap_index ] ;
296-
297- if lo >= last_filemap. original_start_pos &&
298- lo <= last_filemap. original_end_pos {
299- last_filemap
300- } else {
301- let mut a = 0 ;
302- let mut b = imported_filemaps. len ( ) ;
303-
304- while b - a > 1 {
305- let m = ( a + b) / 2 ;
306- if imported_filemaps[ m] . original_start_pos > lo {
307- b = m;
308- } else {
309- a = m;
310- }
311- }
312-
313- self . last_filemap_index = a;
314- & imported_filemaps[ a]
315- }
289+ let span_cdata_rc_any;
290+ let span_cdata = if original_cnum == LOCAL_CRATE {
291+ self . cdata ( )
292+ } else {
293+ // FIXME(eddyb) this requires the `tcx` which isn't always available.
294+ // However, currently only MIR inlining can end up producing such
295+ // cross-crate spans, and decoding MIR always provides a `tcx`.
296+ span_cdata_rc_any = self . tcx ( ) . crate_data_as_rc_any ( cnum) ;
297+ span_cdata_rc_any. downcast_ref :: < CrateMetadata > ( )
298+ . expect ( "CrateStore crate data is not a CrateMetadata" )
316299 } ;
317300
318- // Make sure our binary search above is correct.
319- debug_assert ! ( lo >= filemap. original_start_pos &&
320- lo <= filemap . original_end_pos ) ;
301+ let filemap = span_cdata . imported_filemap_containing ( & sess . codemap ( ) , lo , |filemap| {
302+ filemap. original_start_pos ..=filemap . original_end_pos
303+ } ) ;
321304
322305 // Make sure we correctly filtered out invalid spans during encoding
323- debug_assert ! ( hi >= filemap. original_start_pos &&
324- hi <= filemap. original_end_pos) ;
306+ debug_assert ! ( lo + len >= filemap. original_start_pos &&
307+ lo + len <= filemap. original_end_pos) ;
325308
326309 let lo = ( lo + filemap. translated_filemap . start_pos ) - filemap. original_start_pos ;
327- let hi = ( hi + filemap. translated_filemap . start_pos ) - filemap. original_start_pos ;
328-
329- Ok ( Span :: new ( lo, hi, NO_EXPANSION ) )
310+ Ok ( Span :: new ( lo, lo + len, NO_EXPANSION ) )
330311 }
331312}
332313
@@ -1169,4 +1150,41 @@ impl<'a, 'tcx> CrateMetadata {
11691150 * self . codemap_import_info . borrow_mut ( ) = imported_filemaps;
11701151 self . codemap_import_info . borrow ( )
11711152 }
1153+
1154+ pub fn imported_filemap_containing < F > ( & ' a self ,
1155+ local_codemap : & codemap:: CodeMap ,
1156+ pos : BytePos ,
1157+ range_of : F )
1158+ -> Ref < ' a , cstore:: ImportedFileMap >
1159+ where F : Fn ( & cstore:: ImportedFileMap ) -> RangeInclusive < BytePos >
1160+ {
1161+ Ref :: map ( self . imported_filemaps ( local_codemap) , |imported_filemaps| {
1162+ // Optimize for the case that most spans within a translated item
1163+ // originate from the same filemap.
1164+ let last_filemap = & imported_filemaps[ self . last_filemap_index . get ( ) ] ;
1165+ if range_of ( last_filemap) . contains ( pos) {
1166+ last_filemap
1167+ } else {
1168+ let mut a = 0 ;
1169+ let mut b = imported_filemaps. len ( ) ;
1170+
1171+ while b - a > 1 {
1172+ let m = ( a + b) / 2 ;
1173+ if range_of ( & imported_filemaps[ m] ) . start > pos {
1174+ b = m;
1175+ } else {
1176+ a = m;
1177+ }
1178+ }
1179+
1180+ self . last_filemap_index . set ( a) ;
1181+ let filemap = & imported_filemaps[ a] ;
1182+
1183+ // Make sure our binary search above is correct.
1184+ debug_assert ! ( range_of( filemap) . contains( pos) ) ;
1185+
1186+ filemap
1187+ }
1188+ } )
1189+ }
11721190}
0 commit comments