Remove gensyms
This commit is contained in:
parent
1a2597b64a
commit
94967f23f7
2 changed files with 9 additions and 88 deletions
|
@ -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,35 +993,11 @@ 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()]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// This module has a very short name because it's used a lot.
|
||||
|
@ -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,
|
||||
|
|
|
@ -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]
|
||||
|
|
Loading…
Add table
Reference in a new issue