27
27
use crate :: edition:: Edition ;
28
28
use crate :: symbol:: { kw, sym, Symbol } ;
29
29
use crate :: with_session_globals;
30
- use crate :: { BytePos , CachingSourceMapView , ExpnIdCache , SourceFile , Span , DUMMY_SP } ;
30
+ use crate :: { BytePos , CachingSourceMapView , HashStableContext , SourceFile , Span , DUMMY_SP } ;
31
31
32
32
use crate :: def_id:: { CrateNum , DefId , DefPathHash , CRATE_DEF_INDEX , LOCAL_CRATE } ;
33
33
use rustc_data_structures:: fingerprint:: Fingerprint ;
@@ -36,6 +36,7 @@ use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
36
36
use rustc_data_structures:: sync:: { Lock , Lrc } ;
37
37
use rustc_macros:: HashStable_Generic ;
38
38
use rustc_serialize:: { Decodable , Decoder , Encodable , Encoder } ;
39
+ use std:: cell:: RefCell ;
39
40
use std:: fmt;
40
41
use std:: hash:: Hash ;
41
42
use std:: thread:: LocalKey ;
@@ -1407,3 +1408,60 @@ fn update_disambiguator(expn_id: ExpnId) {
1407
1408
} ;
1408
1409
}
1409
1410
}
1411
+
1412
+ impl < CTX : HashStableContext > HashStable < CTX > for SyntaxContext {
1413
+ fn hash_stable ( & self , ctx : & mut CTX , hasher : & mut StableHasher ) {
1414
+ const TAG_EXPANSION : u8 = 0 ;
1415
+ const TAG_NO_EXPANSION : u8 = 1 ;
1416
+
1417
+ if * self == SyntaxContext :: root ( ) {
1418
+ TAG_NO_EXPANSION . hash_stable ( ctx, hasher) ;
1419
+ } else {
1420
+ TAG_EXPANSION . hash_stable ( ctx, hasher) ;
1421
+ let ( expn_id, transparency) = self . outer_mark ( ) ;
1422
+ expn_id. hash_stable ( ctx, hasher) ;
1423
+ transparency. hash_stable ( ctx, hasher) ;
1424
+ }
1425
+ }
1426
+ }
1427
+
1428
+ pub type ExpnIdCache = RefCell < Vec < Option < Fingerprint > > > ;
1429
+
1430
+ impl < CTX : HashStableContext > HashStable < CTX > for ExpnId {
1431
+ fn hash_stable ( & self , ctx : & mut CTX , hasher : & mut StableHasher ) {
1432
+ const TAG_ROOT : u8 = 0 ;
1433
+ const TAG_NOT_ROOT : u8 = 1 ;
1434
+
1435
+ if * self == ExpnId :: root ( ) {
1436
+ TAG_ROOT . hash_stable ( ctx, hasher) ;
1437
+ return ;
1438
+ }
1439
+
1440
+ // Since the same expansion context is usually referenced many
1441
+ // times, we cache a stable hash of it and hash that instead of
1442
+ // recursing every time.
1443
+ let index = self . as_u32 ( ) as usize ;
1444
+ let res = CTX :: expn_id_cache ( ) . with ( |cache| cache. borrow ( ) . get ( index) . copied ( ) . flatten ( ) ) ;
1445
+
1446
+ if let Some ( res) = res {
1447
+ res. hash_stable ( ctx, hasher) ;
1448
+ } else {
1449
+ let new_len = index + 1 ;
1450
+
1451
+ let mut sub_hasher = StableHasher :: new ( ) ;
1452
+ TAG_NOT_ROOT . hash_stable ( ctx, & mut sub_hasher) ;
1453
+ self . expn_data ( ) . hash_stable ( ctx, & mut sub_hasher) ;
1454
+ let sub_hash: Fingerprint = sub_hasher. finish ( ) ;
1455
+
1456
+ CTX :: expn_id_cache ( ) . with ( |cache| {
1457
+ let mut cache = cache. borrow_mut ( ) ;
1458
+ if cache. len ( ) < new_len {
1459
+ cache. resize ( new_len, None ) ;
1460
+ }
1461
+ let prev = cache[ index] . replace ( sub_hash) ;
1462
+ assert_eq ! ( prev, None , "Cache slot was filled" ) ;
1463
+ } ) ;
1464
+ sub_hash. hash_stable ( ctx, hasher) ;
1465
+ }
1466
+ }
1467
+ }
0 commit comments