]> git.lizzy.rs Git - rust.git/commitdiff
Implement HashStable for Span in libsyntax_pos.
authorCamille GILLOT <gillot.camille@gmail.com>
Sat, 23 Nov 2019 13:39:00 +0000 (14:39 +0100)
committerCamille GILLOT <gillot.camille@gmail.com>
Sat, 23 Nov 2019 17:09:36 +0000 (18:09 +0100)
src/librustc/ich/hcx.rs
src/libsyntax_pos/lib.rs

index 55c02074fce7ceaf4a00bff9ee5c1cd82f763900..8b35839c182ac921db0480899ad4c432d64108bd 100644 (file)
@@ -2,25 +2,23 @@
 use crate::hir::def_id::{DefId, DefIndex};
 use crate::hir::map::DefPathHash;
 use crate::hir::map::definitions::Definitions;
-use crate::ich::{self, CachingSourceMapView, Fingerprint};
+use crate::ich::{self, CachingSourceMapView};
 use crate::middle::cstore::CrateStore;
 use crate::ty::{TyCtxt, fast_reject};
 use crate::session::Session;
 
 use std::cmp::Ord;
-use std::hash as std_hash;
-use std::cell::RefCell;
 
 use syntax::ast;
 use syntax::source_map::SourceMap;
 use syntax::symbol::Symbol;
-use syntax_pos::{Span, DUMMY_SP};
-use syntax_pos::hygiene::{self, SyntaxContext};
+use syntax_pos::{SourceFile, BytePos};
 
 use rustc_data_structures::stable_hasher::{
     HashStable, StableHasher, ToStableHashKey,
 };
 use rustc_data_structures::fx::{FxHashSet, FxHashMap};
+use rustc_data_structures::sync::Lrc;
 use smallvec::SmallVec;
 
 fn compute_ignored_attr_names() -> FxHashSet<Symbol> {
@@ -281,85 +279,14 @@ fn to_stable_hash_key(&self,
 }
 
 impl<'a> syntax_pos::HashStableContext for StableHashingContext<'a> {
-    /// Hashes 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_span(&mut self, span: &Span, hasher: &mut StableHasher) {
-        const TAG_VALID_SPAN: u8 = 0;
-        const TAG_INVALID_SPAN: u8 = 1;
-        const TAG_EXPANSION: u8 = 0;
-        const TAG_NO_EXPANSION: u8 = 1;
-
-        if !self.hash_spans {
-            return
-        }
-
-        if *span == 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 = span.data();
-        let (file_lo, line_lo, col_lo) = match self.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 column 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::root() {
-            TAG_NO_EXPANSION.hash_stable(self, hasher);
-        } else {
-            TAG_EXPANSION.hash_stable(self, 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::ExpnId, u64>> = Default::default();
-            }
-
-            let sub_hash: u64 = CACHE.with(|cache| {
-                let expn_id = span.ctxt.outer_expn();
-
-                if let Some(&sub_hash) = cache.borrow().get(&expn_id) {
-                    return sub_hash;
-                }
-
-                let mut hasher = StableHasher::new();
-                expn_id.expn_data().hash_stable(self, &mut hasher);
-                let sub_hash: Fingerprint = hasher.finish();
-                let sub_hash = sub_hash.to_smaller_hash();
-                cache.borrow_mut().insert(expn_id, sub_hash);
-                sub_hash
-            });
+    fn hash_spans(&self) -> bool {
+        self.hash_spans
+    }
 
-            sub_hash.hash_stable(self, hasher);
-        }
+    fn byte_pos_to_line_and_col(&mut self, byte: BytePos)
+        -> Option<(Lrc<SourceFile>, usize, BytePos)>
+    {
+        self.source_map().byte_pos_to_line_and_col(byte)
     }
 }
 
index a24a2555bffae076d52edb9972517a88c316e02c..66f25770722b2563ae824c1cd9bd8c9554f653f7 100644 (file)
 pub mod fatal_error;
 
 use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
+use rustc_data_structures::fingerprint::Fingerprint;
 use rustc_data_structures::sync::{Lrc, Lock};
+use rustc_data_structures::fx::FxHashMap;
 
 use std::borrow::Cow;
-use std::cell::Cell;
+use std::cell::{Cell, RefCell};
 use std::cmp::{self, Ordering};
 use std::fmt;
 use std::hash::{Hasher, Hash};
@@ -247,14 +249,6 @@ fn cmp(&self, rhs: &Self) -> Ordering {
     }
 }
 
-impl<CTX> HashStable<CTX> for Span
-    where CTX: HashStableContext
-{
-    fn hash_stable(&self, ctx: &mut CTX, hasher: &mut StableHasher) {
-        ctx.hash_stable_span(self, hasher)
-    }
-}
-
 /// A collection of spans. Spans have two orthogonal attributes:
 ///
 /// - They can be *primary spans*. In this case they are the locus of
@@ -1577,5 +1571,91 @@ fn lookup_line(lines: &[BytePos], pos: BytePos) -> isize {
 /// This is a hack to allow using the `HashStable_Generic` derive macro
 /// instead of implementing everything in librustc.
 pub trait HashStableContext {
-    fn hash_stable_span(&mut self, span: &Span, hasher: &mut StableHasher);
+    fn hash_spans(&self) -> bool;
+    fn byte_pos_to_line_and_col(&mut self, byte: BytePos)
+        -> Option<(Lrc<SourceFile>, usize, BytePos)>;
+}
+
+impl<CTX> HashStable<CTX> for Span
+    where CTX: HashStableContext
+{
+    /// Hashes 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(&self, ctx: &mut CTX, hasher: &mut StableHasher) {
+        const TAG_VALID_SPAN: u8 = 0;
+        const TAG_INVALID_SPAN: u8 = 1;
+        const TAG_EXPANSION: u8 = 0;
+        const TAG_NO_EXPANSION: u8 = 1;
+
+        if !ctx.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();
+        let (file_lo, line_lo, col_lo) = match ctx.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 column 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::root() {
+            TAG_NO_EXPANSION.hash_stable(ctx, hasher);
+        } else {
+            TAG_EXPANSION.hash_stable(ctx, 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::ExpnId, u64>> = Default::default();
+            }
+
+            let sub_hash: u64 = CACHE.with(|cache| {
+                let expn_id = span.ctxt.outer_expn();
+
+                if let Some(&sub_hash) = cache.borrow().get(&expn_id) {
+                    return sub_hash;
+                }
+
+                let mut hasher = StableHasher::new();
+                expn_id.expn_data().hash_stable(ctx, &mut hasher);
+                let sub_hash: Fingerprint = hasher.finish();
+                let sub_hash = sub_hash.to_smaller_hash();
+                cache.borrow_mut().insert(expn_id, sub_hash);
+                sub_hash
+            });
+
+            sub_hash.hash_stable(ctx, hasher);
+        }
+    }
 }