Remove gensyms

This commit is contained in:
Matthew Jasper 2019-08-31 16:40:20 +01:00
parent 1a2597b64a
commit 94967f23f7
2 changed files with 9 additions and 88 deletions

View file

@ -807,25 +807,13 @@ impl Ident {
Ident::new(self.name, self.span.modern_and_legacy())
}
/// Transforms an underscore identifier into one with the same name, but
/// gensymed. Leaves non-underscore identifiers unchanged.
pub fn gensym_if_underscore(self) -> Ident {
if self.name == kw::Underscore {
let name = with_interner(|interner| interner.gensymed(self.name));
Ident::new(name, self.span)
} else {
self
}
}
/// Convert the name to a `LocalInternedString`. This is a slowish
/// operation because it requires locking the symbol interner.
pub fn as_str(self) -> LocalInternedString {
self.name.as_str()
}
/// Convert the name to an `InternedString`. This is a slowish operation
/// because it requires locking the symbol interner.
/// Convert the name to an `InternedString`.
pub fn as_interned_str(self) -> InternedString {
self.name.as_interned_str()
}
@ -880,26 +868,9 @@ impl UseSpecializedDecodable for Ident {
}
}
/// A symbol is an interned or gensymed string. A gensym is a symbol that is
/// never equal to any other symbol.
/// An interned string.
///
/// Conceptually, a gensym can be thought of as a normal symbol with an
/// invisible unique suffix. Gensyms are useful when creating new identifiers
/// that must not match any existing identifiers, e.g. during macro expansion
/// and syntax desugaring. Because gensyms should always be identifiers, all
/// gensym operations are on `Ident` rather than `Symbol`. (Indeed, in the
/// future the gensym-ness may be moved from `Symbol` to hygiene data.)
///
/// Examples:
/// ```
/// assert_eq!(Ident::from_str("_"), Ident::from_str("_"))
/// assert_ne!(Ident::from_str("_").gensym_if_underscore(), Ident::from_str("_"))
/// assert_ne!(
/// Ident::from_str("_").gensym_if_underscore(),
/// Ident::from_str("_").gensym_if_underscore(),
/// )
/// ```
/// Internally, a symbol is implemented as an index, and all operations
/// Internally, a `Symbol` is implemented as an index, and all operations
/// (including hashing, equality, and ordering) operate on that index. The use
/// of `rustc_index::newtype_index!` means that `Option<Symbol>` only takes up 4 bytes,
/// because `rustc_index::newtype_index!` reserves the last 256 values for tagging purposes.
@ -950,12 +921,9 @@ impl Symbol {
})
}
/// Convert to an `InternedString`. This is a slowish operation because it
/// requires locking the symbol interner.
/// Convert to an `InternedString`.
pub fn as_interned_str(self) -> InternedString {
with_interner(|interner| InternedString {
symbol: interner.interned(self)
})
InternedString { symbol: self }
}
pub fn as_u32(self) -> u32 {
@ -965,12 +933,7 @@ impl Symbol {
impl fmt::Debug for Symbol {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let is_gensymed = with_interner(|interner| interner.is_gensymed(*self));
if is_gensymed {
write!(f, "{}({:?})", self, self.0)
} else {
write!(f, "{}", self)
}
fmt::Display::fmt(self, f)
}
}
@ -993,15 +956,11 @@ impl Decodable for Symbol {
}
// The `&'static str`s in this type actually point into the arena.
//
// Note that normal symbols are indexed upward from 0, and gensyms are indexed
// downward from SymbolIndex::MAX_AS_U32.
#[derive(Default)]
pub struct Interner {
arena: DroplessArena,
names: FxHashMap<&'static str, Symbol>,
strings: Vec<&'static str>,
gensyms: Vec<Symbol>,
}
impl Interner {
@ -1034,34 +993,10 @@ impl Interner {
self.names.insert(string, name);
name
}
fn interned(&self, symbol: Symbol) -> Symbol {
if (symbol.0.as_usize()) < self.strings.len() {
symbol
} else {
self.gensyms[(SymbolIndex::MAX_AS_U32 - symbol.0.as_u32()) as usize]
}
}
fn gensymed(&mut self, symbol: Symbol) -> Symbol {
self.gensyms.push(symbol);
Symbol::new(SymbolIndex::MAX_AS_U32 - self.gensyms.len() as u32 + 1)
}
fn is_gensymed(&mut self, symbol: Symbol) -> bool {
symbol.0.as_usize() >= self.strings.len()
}
// Get the symbol as a string. `Symbol::as_str()` should be used in
// preference to this function.
pub fn get(&self, symbol: Symbol) -> &str {
match self.strings.get(symbol.0.as_usize()) {
Some(string) => string,
None => {
let symbol = self.gensyms[(SymbolIndex::MAX_AS_U32 - symbol.0.as_u32()) as usize];
self.strings[symbol.0.as_usize()]
}
}
self.strings[symbol.0.as_usize()]
}
}
@ -1246,19 +1181,12 @@ impl fmt::Display for LocalInternedString {
}
}
/// An alternative to `Symbol` that is focused on string contents. It has two
/// main differences to `Symbol`.
/// An alternative to `Symbol` that is focused on string contents.
///
/// First, its implementations of `Hash`, `PartialOrd` and `Ord` work with the
/// Its implementations of `Hash`, `PartialOrd` and `Ord` work with the
/// string chars rather than the symbol integer. This is useful when hash
/// stability is required across compile sessions, or a guaranteed sort
/// ordering is required.
///
/// Second, gensym-ness is irrelevant. E.g.:
/// ```
/// assert_ne!(Symbol::gensym("x"), Symbol::gensym("x"))
/// assert_eq!(Symbol::gensym("x").as_interned_str(), Symbol::gensym("x").as_interned_str())
/// ```
#[derive(Clone, Copy, PartialEq, Eq)]
pub struct InternedString {
symbol: Symbol,

View file

@ -14,13 +14,6 @@ fn interner_tests() {
assert_eq!(i.intern("cat"), Symbol::new(1));
// dog is still at zero
assert_eq!(i.intern("dog"), Symbol::new(0));
let z = i.intern("zebra");
assert_eq!(i.gensymed(z), Symbol::new(SymbolIndex::MAX_AS_U32));
// gensym of same string gets new number:
assert_eq!(i.gensymed(z), Symbol::new(SymbolIndex::MAX_AS_U32 - 1));
// gensym of *existing* string gets new number:
let d = i.intern("dog");
assert_eq!(i.gensymed(d), Symbol::new(SymbolIndex::MAX_AS_U32 - 2));
}
#[test]