@@ -630,10 +630,12 @@ pub struct Ident {
630630
631631impl Ident {
632632 #[ inline]
633+ /// Constructs a new identifier from a symbol and a span.
633634 pub const fn new ( name : Symbol , span : Span ) -> Ident {
634635 Ident { name, span }
635636 }
636637
638+ /// Constructs a new identifier with an empty syntax context.
637639 #[ inline]
638640 pub const fn with_empty_ctxt ( name : Symbol ) -> Ident {
639641 Ident :: new ( name, DUMMY_SP )
@@ -644,11 +646,16 @@ impl Ident {
644646 Ident :: with_empty_ctxt ( string. as_symbol ( ) )
645647 }
646648
647- /// Maps a string to an identifier with an empty syntax context .
649+ /// Maps a string to an identifier with an empty span .
648650 pub fn from_str ( string : & str ) -> Ident {
649651 Ident :: with_empty_ctxt ( Symbol :: intern ( string) )
650652 }
651653
654+ /// Maps a string and a span to an identifier.
655+ pub fn from_str_and_span ( string : & str , span : Span ) -> Ident {
656+ Ident :: new ( Symbol :: intern ( string) , span)
657+ }
658+
652659 /// Replaces `lo` and `hi` with those from `span`, but keep hygiene context.
653660 pub fn with_span_pos ( self , span : Span ) -> Ident {
654661 Ident :: new ( self . name , span. with_ctxt ( self . span . ctxt ( ) ) )
@@ -676,11 +683,14 @@ impl Ident {
676683 Ident :: new ( self . name , self . span . modern_and_legacy ( ) )
677684 }
678685
686+ /// Transforms an identifier into one with the same name, but gensymed.
679687 pub fn gensym ( self ) -> Ident {
680688 let name = with_interner ( |interner| interner. gensymed ( self . name ) ) ;
681689 Ident :: new ( name, self . span )
682690 }
683691
692+ /// Transforms an underscore identifier into one with the same name, but
693+ /// gensymed. Leaves non-underscore identifiers unchanged.
684694 pub fn gensym_if_underscore ( self ) -> Ident {
685695 if self . name == keywords:: Underscore . name ( ) { self . gensym ( ) } else { self }
686696 }
@@ -742,30 +752,34 @@ impl Decodable for Ident {
742752 Ok ( if !string. starts_with ( '#' ) {
743753 Ident :: from_str ( & string)
744754 } else { // FIXME(jseyfried): intercrate hygiene
745- Ident :: with_empty_ctxt ( Symbol :: gensym ( & string[ 1 ..] ) )
755+ Ident :: from_str ( & string[ 1 ..] ) . gensym ( )
746756 } )
747757 }
748758}
749759
750760/// A symbol is an interned or gensymed string. A gensym is a symbol that is
751- /// never equal to any other symbol. E.g.:
752- /// ```
753- /// assert_eq!(Symbol::intern("x"), Symbol::intern("x"))
754- /// assert_ne!(Symbol::gensym("x"), Symbol::intern("x"))
755- /// assert_ne!(Symbol::gensym("x"), Symbol::gensym("x"))
756- /// ```
761+ /// never equal to any other symbol.
762+ ///
757763/// Conceptually, a gensym can be thought of as a normal symbol with an
758764/// invisible unique suffix. Gensyms are useful when creating new identifiers
759765/// that must not match any existing identifiers, e.g. during macro expansion
760- /// and syntax desugaring.
766+ /// and syntax desugaring. Because gensyms should always be identifiers, all
767+ /// gensym operations are on `Ident` rather than `Symbol`. (Indeed, in the
768+ /// future the gensym-ness may be moved from `Symbol` to hygiene data.)
761769///
762- /// Internally, a Symbol is implemented as an index, and all operations
770+ /// Examples:
771+ /// ```
772+ /// assert_eq!(Ident::from_str("x"), Ident::from_str("x"))
773+ /// assert_ne!(Ident::from_str("x").gensym(), Ident::from_str("x"))
774+ /// assert_ne!(Ident::from_str("x").gensym(), Ident::from_str("x").gensym())
775+ /// ```
776+ /// Internally, a symbol is implemented as an index, and all operations
763777/// (including hashing, equality, and ordering) operate on that index. The use
764778/// of `newtype_index!` means that `Option<Symbol>` only takes up 4 bytes,
765779/// because `newtype_index!` reserves the last 256 values for tagging purposes.
766780///
767- /// Note that `Symbol` cannot directly be a `newtype_index!` because it implements
768- /// `fmt::Debug`, `Encodable`, and `Decodable` in special ways.
781+ /// Note that `Symbol` cannot directly be a `newtype_index!` because it
782+ /// implements `fmt::Debug`, `Encodable`, and `Decodable` in special ways.
769783#[ derive( Clone , Copy , PartialEq , Eq , PartialOrd , Ord , Hash ) ]
770784pub struct Symbol ( SymbolIndex ) ;
771785
@@ -783,11 +797,6 @@ impl Symbol {
783797 with_interner ( |interner| interner. intern ( string) )
784798 }
785799
786- /// Gensyms a new `usize`, using the current interner.
787- pub fn gensym ( string : & str ) -> Self {
788- with_interner ( |interner| interner. gensym ( string) )
789- }
790-
791800 pub fn as_str ( self ) -> LocalInternedString {
792801 with_interner ( |interner| unsafe {
793802 LocalInternedString {
@@ -895,11 +904,6 @@ impl Interner {
895904 }
896905 }
897906
898- fn gensym ( & mut self , string : & str ) -> Symbol {
899- let symbol = self . intern ( string) ;
900- self . gensymed ( symbol)
901- }
902-
903907 fn gensymed ( & mut self , symbol : Symbol ) -> Symbol {
904908 self . gensyms . push ( symbol) ;
905909 Symbol :: new ( SymbolIndex :: MAX_AS_U32 - self . gensyms . len ( ) as u32 + 1 )
@@ -1267,11 +1271,13 @@ mod tests {
12671271 assert_eq ! ( i. intern( "cat" ) , Symbol :: new( 1 ) ) ;
12681272 // dog is still at zero
12691273 assert_eq ! ( i. intern( "dog" ) , Symbol :: new( 0 ) ) ;
1270- assert_eq ! ( i. gensym( "zebra" ) , Symbol :: new( SymbolIndex :: MAX_AS_U32 ) ) ;
1274+ let z = i. intern ( "zebra" ) ;
1275+ assert_eq ! ( i. gensymed( z) , Symbol :: new( SymbolIndex :: MAX_AS_U32 ) ) ;
12711276 // gensym of same string gets new number:
1272- assert_eq ! ( i. gensym ( "zebra" ) , Symbol :: new( SymbolIndex :: MAX_AS_U32 - 1 ) ) ;
1277+ assert_eq ! ( i. gensymed ( z ) , Symbol :: new( SymbolIndex :: MAX_AS_U32 - 1 ) ) ;
12731278 // gensym of *existing* string gets new number:
1274- assert_eq ! ( i. gensym( "dog" ) , Symbol :: new( SymbolIndex :: MAX_AS_U32 - 2 ) ) ;
1279+ let d = i. intern ( "dog" ) ;
1280+ assert_eq ! ( i. gensymed( d) , Symbol :: new( SymbolIndex :: MAX_AS_U32 - 2 ) ) ;
12751281 }
12761282
12771283 #[ test]
0 commit comments