// Hash a span in a stable way. We can't directly hash the span's BytePos
// fields (that would be similar to hashing pointers, since those are just
// offsets into the SourceMap). Instead, we hash the (file name, line, column)
// triple, which stays the same even if the containing SourceFile has moved
// within the SourceMap.
// Also note that we are hashing byte offsets for the column, not unicode
// codepoint offsets. For the purpose of the hash that's sufficient.
// Also, hashing filenames is expensive so we avoid doing it twice when the
// span starts and ends in the same file, which is almost always the case.
Hash a span in a stable way. We can't directly hash the span's BytePos
fields (that would be similar to hashing pointers, since those are just
offsets into the SourceMap). Instead, we hash the (file name, line, column)
triple, which stays the same even if the containing SourceFile has moved
within the SourceMap.
Also note that we are hashing byte offsets for the column, not unicode
codepoint offsets. For the purpose of the hash that's sufficient.
Also, hashing filenames is expensive so we avoid doing it twice when the
span starts and ends in the same file, which is almost always the case.
Hash a span in a stable way . We can ' t directly hash the span ' s BytePos fields ( that would be similar to hashing pointers since those are just offsets into the SourceMap ) . Instead we hash the ( file name line column ) triple which stays the same even if the containing SourceFile has moved within the SourceMap . Also note that we are hashing byte offsets for the column not unicode codepoint offsets . For the purpose of the hash that ' s sufficient . Also hashing filenames is expensive so we avoid doing it twice when the span starts and ends in the same file which is almost always the case .
fn hash_stable<W: StableHasherResult>(&self,
                                          hcx: &mut StableHashingContext<'a>,
                                          hasher: &mut StableHasher<W>) {
        const TAG_VALID_SPAN: u8 = 0;
        const TAG_INVALID_SPAN: u8 = 1;
        const TAG_EXPANSION: u8 = 0;
        const TAG_NO_EXPANSION: u8 = 1;
        if !hcx.hash_spans {
            return
        }
        if *self == DUMMY_SP {
            return std_hash::Hash::hash(&TAG_INVALID_SPAN, hasher);
        }
        // If this is not an empty or invalid span, we want to hash the last
        // position that belongs to it, as opposed to hashing the first
        // position past it.
        let span = self.data();
        if span.hi < span.lo {
            return std_hash::Hash::hash(&TAG_INVALID_SPAN, hasher);
        }
        let (file_lo, line_lo, col_lo) = match hcx.source_map()
                                                  .byte_pos_to_line_and_col(span.lo) {
            Some(pos) => pos,
            None => {
                return std_hash::Hash::hash(&TAG_INVALID_SPAN, hasher);
            }
        };
        if !file_lo.contains(span.hi) {
            return std_hash::Hash::hash(&TAG_INVALID_SPAN, hasher);
        }
        std_hash::Hash::hash(&TAG_VALID_SPAN, hasher);
        // We truncate the stable_id hash and line and col numbers. The chances
        // of causing a collision this way should be minimal.
        std_hash::Hash::hash(&(file_lo.name_hash as u64), hasher);
        let col = (col_lo.0 as u64) & 0xFF;
        let line = ((line_lo as u64) & 0xFF_FF_FF) << 8;
        let len = ((span.hi - span.lo).0 as u64) << 32;
        let line_col_len = col | line | len;
        std_hash::Hash::hash(&line_col_len, hasher);
        if span.ctxt == SyntaxContext::empty() {
            TAG_NO_EXPANSION.hash_stable(hcx, hasher);
        } else {
            TAG_EXPANSION.hash_stable(hcx, hasher);
            // Since the same expansion context is usually referenced many
            // times, we cache a stable hash of it and hash that instead of
            // recursing every time.
            thread_local! {
                static CACHE: RefCell<FxHashMap<hygiene::Mark, u64>> =
                    RefCell::new(FxHashMap());
            }
            let sub_hash: u64 = CACHE.with(|cache| {
                let mark = span.ctxt.outer();
                if let Some(&sub_hash) = cache.borrow().get(&mark) {
                    return sub_hash;
                }
                let mut hasher = StableHasher::new();
                mark.expn_info().hash_stable(hcx, &mut hasher);
                let sub_hash: Fingerprint = hasher.finish();
                let sub_hash = sub_hash.to_smaller_hash();
                cache.borrow_mut().insert(mark, sub_hash);
                sub_hash
            });
            sub_hash.hash_stable(hcx, hasher);
        }
    }
fn hash_stable < W : StableHasherResult > ( & self , hcx : & mut StableHashingContext < ' a > , hasher : & mut StableHasher < W > ) { const TAG_VALID_SPAN : u8 = 0 ; const TAG_INVALID_SPAN : u8 = 1 ; const TAG_EXPANSION : u8 = 0 ; const TAG_NO_EXPANSION : u8 = 1 ; if ! hcx . hash_spans { return } if * self == DUMMY_SP { return std_hash :: Hash :: hash ( & TAG_INVALID_SPAN , hasher ) ; } // If this is not an empty or invalid span, we want to hash the last // position that belongs to it, as opposed to hashing the first // position past it. let span = self . data ( ) ; if span . hi < span . lo { return std_hash :: Hash :: hash ( & TAG_INVALID_SPAN , hasher ) ; } let ( file_lo , line_lo , col_lo ) = match hcx . source_map ( ) . byte_pos_to_line_and_col ( span . lo ) { Some ( pos ) => pos , None => { return std_hash :: Hash :: hash ( & TAG_INVALID_SPAN , hasher ) ; } } ; if ! file_lo . contains ( span . hi ) { return std_hash :: Hash :: hash ( & TAG_INVALID_SPAN , hasher ) ; } std_hash :: Hash :: hash ( & TAG_VALID_SPAN , hasher ) ; // We truncate the stable_id hash and line and col numbers. The chances // of causing a collision this way should be minimal. std_hash :: Hash :: hash ( & ( file_lo . name_hash as u64 ) , hasher ) ; let col = ( col_lo . 0 as u64 ) & 0xFF ; let line = ( ( line_lo as u64 ) & 0xFF_FF_FF ) << 8 ; let len = ( ( span . hi - span . lo ) . 0 as u64 ) << 32 ; let line_col_len = col | line | len ; std_hash :: Hash :: hash ( & line_col_len , hasher ) ; if span . ctxt == SyntaxContext :: empty ( ) { TAG_NO_EXPANSION . hash_stable ( hcx , hasher ) ; } else { TAG_EXPANSION . hash_stable ( hcx , hasher ) ; // Since the same expansion context is usually referenced many // times, we cache a stable hash of it and hash that instead of // recursing every time. thread_local ! { static CACHE RefCell FxHashMap hygiene Mark u64 RefCell new ( FxHashMap ( ) ) } let sub_hash : u64 = CACHE . with ( | cache | { let mark = span . ctxt . outer ( ) ; if let Some ( & sub_hash ) = cache . borrow ( ) . get ( & mark ) { return sub_hash ; } let mut hasher = StableHasher :: new ( ) ; mark . expn_info ( ) . hash_stable ( hcx , & mut hasher ) ; let sub_hash : Fingerprint = hasher . finish ( ) ; let sub_hash = sub_hash . to_smaller_hash ( ) ; cache . borrow_mut ( ) . insert ( mark , sub_hash ) ; sub_hash } ) ; sub_hash . hash_stable ( hcx , hasher ) ; } }
Hash a span in a stable way.
Hash a span in a stable way .
&self
hcx
&mut StableHashingContext<'a>
hasher
&mut StableHasher<W>