2727use crate :: edition:: Edition ;
2828use crate :: symbol:: { kw, sym, Symbol } ;
2929use crate :: with_session_globals;
30- use crate :: { BytePos , CachingSourceMapView , ExpnIdCache , SourceFile , Span , DUMMY_SP } ;
30+ use crate :: { BytePos , CachingSourceMapView , HashStableContext , SourceFile , Span , DUMMY_SP } ;
3131
3232use crate :: def_id:: { CrateNum , DefId , DefPathHash , CRATE_DEF_INDEX , LOCAL_CRATE } ;
3333use rustc_data_structures:: fingerprint:: Fingerprint ;
@@ -36,6 +36,7 @@ use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
3636use rustc_data_structures:: sync:: { Lock , Lrc } ;
3737use rustc_macros:: HashStable_Generic ;
3838use rustc_serialize:: { Decodable , Decoder , Encodable , Encoder } ;
39+ use std:: cell:: RefCell ;
3940use std:: fmt;
4041use std:: hash:: Hash ;
4142use std:: thread:: LocalKey ;
@@ -1407,3 +1408,60 @@ fn update_disambiguator(expn_id: ExpnId) {
14071408 } ;
14081409 }
14091410}
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