Skip to content

Commit 7e411e7

Browse files
committed
Implement HashStable for Span in libsyntax_pos.
1 parent ea0c354 commit 7e411e7

File tree

2 files changed

+100
-93
lines changed

2 files changed

+100
-93
lines changed

src/librustc/ich/hcx.rs

+10-83
Original file line numberDiff line numberDiff line change
@@ -2,25 +2,23 @@ use crate::hir;
22
use crate::hir::def_id::{DefId, DefIndex};
33
use crate::hir::map::DefPathHash;
44
use crate::hir::map::definitions::Definitions;
5-
use crate::ich::{self, CachingSourceMapView, Fingerprint};
5+
use crate::ich::{self, CachingSourceMapView};
66
use crate::middle::cstore::CrateStore;
77
use crate::ty::{TyCtxt, fast_reject};
88
use crate::session::Session;
99

1010
use std::cmp::Ord;
11-
use std::hash as std_hash;
12-
use std::cell::RefCell;
1311

1412
use syntax::ast;
1513
use syntax::source_map::SourceMap;
1614
use syntax::symbol::Symbol;
17-
use syntax_pos::{Span, DUMMY_SP};
18-
use syntax_pos::hygiene::{self, SyntaxContext};
15+
use syntax_pos::{SourceFile, BytePos};
1916

2017
use rustc_data_structures::stable_hasher::{
2118
HashStable, StableHasher, ToStableHashKey,
2219
};
2320
use rustc_data_structures::fx::{FxHashSet, FxHashMap};
21+
use rustc_data_structures::sync::Lrc;
2422
use smallvec::SmallVec;
2523

2624
fn compute_ignored_attr_names() -> FxHashSet<Symbol> {
@@ -281,85 +279,14 @@ impl<'a> ToStableHashKey<StableHashingContext<'a>> for ast::NodeId {
281279
}
282280

283281
impl<'a> syntax_pos::HashStableContext for StableHashingContext<'a> {
284-
/// Hashes a span in a stable way. We can't directly hash the span's `BytePos`
285-
/// fields (that would be similar to hashing pointers, since those are just
286-
/// offsets into the `SourceMap`). Instead, we hash the (file name, line, column)
287-
/// triple, which stays the same even if the containing `SourceFile` has moved
288-
/// within the `SourceMap`.
289-
/// Also note that we are hashing byte offsets for the column, not unicode
290-
/// codepoint offsets. For the purpose of the hash that's sufficient.
291-
/// Also, hashing filenames is expensive so we avoid doing it twice when the
292-
/// span starts and ends in the same file, which is almost always the case.
293-
fn hash_stable_span(&mut self, span: &Span, hasher: &mut StableHasher) {
294-
const TAG_VALID_SPAN: u8 = 0;
295-
const TAG_INVALID_SPAN: u8 = 1;
296-
const TAG_EXPANSION: u8 = 0;
297-
const TAG_NO_EXPANSION: u8 = 1;
298-
299-
if !self.hash_spans {
300-
return
301-
}
302-
303-
if *span == DUMMY_SP {
304-
return std_hash::Hash::hash(&TAG_INVALID_SPAN, hasher);
305-
}
306-
307-
// If this is not an empty or invalid span, we want to hash the last
308-
// position that belongs to it, as opposed to hashing the first
309-
// position past it.
310-
let span = span.data();
311-
let (file_lo, line_lo, col_lo) = match self.source_map()
312-
.byte_pos_to_line_and_col(span.lo) {
313-
Some(pos) => pos,
314-
None => {
315-
return std_hash::Hash::hash(&TAG_INVALID_SPAN, hasher);
316-
}
317-
};
318-
319-
if !file_lo.contains(span.hi) {
320-
return std_hash::Hash::hash(&TAG_INVALID_SPAN, hasher);
321-
}
322-
323-
std_hash::Hash::hash(&TAG_VALID_SPAN, hasher);
324-
// We truncate the stable ID hash and line and column numbers. The chances
325-
// of causing a collision this way should be minimal.
326-
std_hash::Hash::hash(&(file_lo.name_hash as u64), hasher);
327-
328-
let col = (col_lo.0 as u64) & 0xFF;
329-
let line = ((line_lo as u64) & 0xFF_FF_FF) << 8;
330-
let len = ((span.hi - span.lo).0 as u64) << 32;
331-
let line_col_len = col | line | len;
332-
std_hash::Hash::hash(&line_col_len, hasher);
333-
334-
if span.ctxt == SyntaxContext::root() {
335-
TAG_NO_EXPANSION.hash_stable(self, hasher);
336-
} else {
337-
TAG_EXPANSION.hash_stable(self, hasher);
338-
339-
// Since the same expansion context is usually referenced many
340-
// times, we cache a stable hash of it and hash that instead of
341-
// recursing every time.
342-
thread_local! {
343-
static CACHE: RefCell<FxHashMap<hygiene::ExpnId, u64>> = Default::default();
344-
}
345-
346-
let sub_hash: u64 = CACHE.with(|cache| {
347-
let expn_id = span.ctxt.outer_expn();
348-
349-
if let Some(&sub_hash) = cache.borrow().get(&expn_id) {
350-
return sub_hash;
351-
}
352-
353-
let mut hasher = StableHasher::new();
354-
expn_id.expn_data().hash_stable(self, &mut hasher);
355-
let sub_hash: Fingerprint = hasher.finish();
356-
let sub_hash = sub_hash.to_smaller_hash();
357-
cache.borrow_mut().insert(expn_id, sub_hash);
358-
sub_hash
359-
});
282+
fn hash_spans(&self) -> bool {
283+
self.hash_spans
284+
}
360285

361-
sub_hash.hash_stable(self, hasher);
362-
}
286+
fn byte_pos_to_line_and_col(&mut self, byte: BytePos)
287+
-> Option<(Lrc<SourceFile>, usize, BytePos)>
288+
{
289+
self.source_map().byte_pos_to_line_and_col(byte)
363290
}
364291
}
365292

src/libsyntax_pos/lib.rs

+90-10
Original file line numberDiff line numberDiff line change
@@ -37,10 +37,12 @@ mod analyze_source_file;
3737
pub mod fatal_error;
3838

3939
use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
40+
use rustc_data_structures::fingerprint::Fingerprint;
4041
use rustc_data_structures::sync::{Lrc, Lock};
42+
use rustc_data_structures::fx::FxHashMap;
4143

4244
use std::borrow::Cow;
43-
use std::cell::Cell;
45+
use std::cell::{Cell, RefCell};
4446
use std::cmp::{self, Ordering};
4547
use std::fmt;
4648
use std::hash::{Hasher, Hash};
@@ -247,14 +249,6 @@ impl Ord for Span {
247249
}
248250
}
249251

250-
impl<CTX> HashStable<CTX> for Span
251-
where CTX: HashStableContext
252-
{
253-
fn hash_stable(&self, ctx: &mut CTX, hasher: &mut StableHasher) {
254-
ctx.hash_stable_span(self, hasher)
255-
}
256-
}
257-
258252
/// A collection of spans. Spans have two orthogonal attributes:
259253
///
260254
/// - 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 {
15771571
/// This is a hack to allow using the `HashStable_Generic` derive macro
15781572
/// instead of implementing everything in librustc.
15791573
pub trait HashStableContext {
1580-
fn hash_stable_span(&mut self, span: &Span, hasher: &mut StableHasher);
1574+
fn hash_spans(&self) -> bool;
1575+
fn byte_pos_to_line_and_col(&mut self, byte: BytePos)
1576+
-> Option<(Lrc<SourceFile>, usize, BytePos)>;
1577+
}
1578+
1579+
impl<CTX> HashStable<CTX> for Span
1580+
where CTX: HashStableContext
1581+
{
1582+
/// Hashes a span in a stable way. We can't directly hash the span's `BytePos`
1583+
/// fields (that would be similar to hashing pointers, since those are just
1584+
/// offsets into the `SourceMap`). Instead, we hash the (file name, line, column)
1585+
/// triple, which stays the same even if the containing `SourceFile` has moved
1586+
/// within the `SourceMap`.
1587+
/// Also note that we are hashing byte offsets for the column, not unicode
1588+
/// codepoint offsets. For the purpose of the hash that's sufficient.
1589+
/// Also, hashing filenames is expensive so we avoid doing it twice when the
1590+
/// span starts and ends in the same file, which is almost always the case.
1591+
fn hash_stable(&self, ctx: &mut CTX, hasher: &mut StableHasher) {
1592+
const TAG_VALID_SPAN: u8 = 0;
1593+
const TAG_INVALID_SPAN: u8 = 1;
1594+
const TAG_EXPANSION: u8 = 0;
1595+
const TAG_NO_EXPANSION: u8 = 1;
1596+
1597+
if !ctx.hash_spans() {
1598+
return
1599+
}
1600+
1601+
if *self == DUMMY_SP {
1602+
return std::hash::Hash::hash(&TAG_INVALID_SPAN, hasher);
1603+
}
1604+
1605+
// If this is not an empty or invalid span, we want to hash the last
1606+
// position that belongs to it, as opposed to hashing the first
1607+
// position past it.
1608+
let span = self.data();
1609+
let (file_lo, line_lo, col_lo) = match ctx.byte_pos_to_line_and_col(span.lo) {
1610+
Some(pos) => pos,
1611+
None => {
1612+
return std::hash::Hash::hash(&TAG_INVALID_SPAN, hasher);
1613+
}
1614+
};
1615+
1616+
if !file_lo.contains(span.hi) {
1617+
return std::hash::Hash::hash(&TAG_INVALID_SPAN, hasher);
1618+
}
1619+
1620+
std::hash::Hash::hash(&TAG_VALID_SPAN, hasher);
1621+
// We truncate the stable ID hash and line and column numbers. The chances
1622+
// of causing a collision this way should be minimal.
1623+
std::hash::Hash::hash(&(file_lo.name_hash as u64), hasher);
1624+
1625+
let col = (col_lo.0 as u64) & 0xFF;
1626+
let line = ((line_lo as u64) & 0xFF_FF_FF) << 8;
1627+
let len = ((span.hi - span.lo).0 as u64) << 32;
1628+
let line_col_len = col | line | len;
1629+
std::hash::Hash::hash(&line_col_len, hasher);
1630+
1631+
if span.ctxt == SyntaxContext::root() {
1632+
TAG_NO_EXPANSION.hash_stable(ctx, hasher);
1633+
} else {
1634+
TAG_EXPANSION.hash_stable(ctx, hasher);
1635+
1636+
// Since the same expansion context is usually referenced many
1637+
// times, we cache a stable hash of it and hash that instead of
1638+
// recursing every time.
1639+
thread_local! {
1640+
static CACHE: RefCell<FxHashMap<hygiene::ExpnId, u64>> = Default::default();
1641+
}
1642+
1643+
let sub_hash: u64 = CACHE.with(|cache| {
1644+
let expn_id = span.ctxt.outer_expn();
1645+
1646+
if let Some(&sub_hash) = cache.borrow().get(&expn_id) {
1647+
return sub_hash;
1648+
}
1649+
1650+
let mut hasher = StableHasher::new();
1651+
expn_id.expn_data().hash_stable(ctx, &mut hasher);
1652+
let sub_hash: Fingerprint = hasher.finish();
1653+
let sub_hash = sub_hash.to_smaller_hash();
1654+
cache.borrow_mut().insert(expn_id, sub_hash);
1655+
sub_hash
1656+
});
1657+
1658+
sub_hash.hash_stable(ctx, hasher);
1659+
}
1660+
}
15811661
}

0 commit comments

Comments
 (0)