Skip to content

Commit 3498eec

Browse files
committed
Auto merge of #64623 - matthewjasper:underscore-imports, r=<try>
Remove last uses of gensyms Bindings are now indexed in resolve with an additional disambiguator that's used for underscore bindings. This is the last use of gensyms in the compiler. I'm not completely happy with this approach, so suggestions are welcome. Moving undescore bindings into their own map didn't turn out any better: master...matthewjasper:remove-underscore-gensyms. closes #49300 cc #60869 r? @petrochenkov
2 parents d046ffd + 0e1c0b5 commit 3498eec

File tree

14 files changed

+208
-101
lines changed

14 files changed

+208
-101
lines changed

src/librustc/ich/impls_syntax.rs

+1
Original file line numberDiff line numberDiff line change
@@ -373,6 +373,7 @@ impl_stable_hash_for!(enum ::syntax_pos::hygiene::ExpnKind {
373373
Root,
374374
Macro(kind, descr),
375375
AstPass(kind),
376+
Underscore,
376377
Desugaring(kind)
377378
});
378379

src/librustc/lint/mod.rs

+3-1
Original file line numberDiff line numberDiff line change
@@ -871,7 +871,9 @@ pub fn provide(providers: &mut Providers<'_>) {
871871
pub fn in_external_macro(sess: &Session, span: Span) -> bool {
872872
let expn_data = span.ctxt().outer_expn_data();
873873
match expn_data.kind {
874-
ExpnKind::Root | ExpnKind::Desugaring(DesugaringKind::ForLoop) => false,
874+
ExpnKind::Root
875+
| ExpnKind::Underscore
876+
| ExpnKind::Desugaring(DesugaringKind::ForLoop) => false,
875877
ExpnKind::AstPass(_) | ExpnKind::Desugaring(_) => true, // well, it's "external"
876878
ExpnKind::Macro(MacroKind::Bang, _) => {
877879
if expn_data.def_site.is_dummy() {

src/librustc/ty/print/pretty.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -1480,7 +1480,7 @@ impl<F: fmt::Write> FmtPrinter<'_, 'tcx, F> {
14801480
}
14811481

14821482
// Replace any anonymous late-bound regions with named
1483-
// variants, using gensym'd identifiers, so that we can
1483+
// variants, using new unique identifiers, so that we can
14841484
// clearly differentiate between named and unnamed regions in
14851485
// the output. We'll probably want to tweak this over time to
14861486
// decide just how much information to give.

src/librustc_resolve/build_reduced_graph.rs

+6-6
Original file line numberDiff line numberDiff line change
@@ -406,7 +406,7 @@ impl<'a, 'b> BuildReducedGraphVisitor<'a, 'b> {
406406
};
407407
match use_tree.kind {
408408
ast::UseTreeKind::Simple(rename, ..) => {
409-
let mut ident = use_tree.ident().gensym_if_underscore();
409+
let mut ident = use_tree.ident().unique_if_underscore();
410410
let mut module_path = prefix;
411411
let mut source = module_path.pop().unwrap();
412412
let mut type_ns_only = false;
@@ -584,7 +584,7 @@ impl<'a, 'b> BuildReducedGraphVisitor<'a, 'b> {
584584
let parent_scope = &self.parent_scope;
585585
let parent = parent_scope.module;
586586
let expansion = parent_scope.expansion;
587-
let ident = item.ident.gensym_if_underscore();
587+
let ident = item.ident.unique_if_underscore();
588588
let sp = item.span;
589589
let vis = self.resolve_visibility(&item.vis);
590590

@@ -849,10 +849,10 @@ impl<'a, 'b> BuildReducedGraphVisitor<'a, 'b> {
849849
fn build_reduced_graph_for_external_crate_res(&mut self, child: Export<NodeId>) {
850850
let parent = self.parent_scope.module;
851851
let Export { ident, res, vis, span } = child;
852-
// FIXME: We shouldn't create the gensym here, it should come from metadata,
853-
// but metadata cannot encode gensyms currently, so we create it here.
854-
// This is only a guess, two equivalent idents may incorrectly get different gensyms here.
855-
let ident = ident.gensym_if_underscore();
852+
// FIXME: We shouldn't create the SyntaxContext here, it should come from metadata,
853+
// but metadata doesn't encode hygiene information currently, so we create it here.
854+
// This is only a guess, two equivalent idents will get different SyntaxContexts here.
855+
let ident = ident.unique_if_underscore();
856856
let expansion = ExpnId::root(); // FIXME(jseyfried) intercrate hygiene
857857
// Record primary definitions.
858858
match res {

src/librustc_resolve/resolve_imports.rs

+7-3
Original file line numberDiff line numberDiff line change
@@ -1340,7 +1340,7 @@ impl<'a, 'b> ImportResolver<'a, 'b> {
13401340
// hygiene.
13411341
// FIXME: Implement actual cross-crate hygiene.
13421342
let is_good_import = binding.is_import() && !binding.is_ambiguity()
1343-
&& !ident.span.modern().from_expansion();
1343+
&& (!ident.span.from_expansion() || ident.name == kw::Underscore);
13441344
if is_good_import || binding.is_macro_def() {
13451345
let res = binding.res();
13461346
if res != Res::Err {
@@ -1350,8 +1350,8 @@ impl<'a, 'b> ImportResolver<'a, 'b> {
13501350
}
13511351
}
13521352
reexports.push(Export {
1353-
ident: ident.modern(),
1354-
res: res,
1353+
ident,
1354+
res,
13551355
span: binding.span,
13561356
vis: binding.vis,
13571357
});
@@ -1418,6 +1418,10 @@ impl<'a, 'b> ImportResolver<'a, 'b> {
14181418
}
14191419

14201420
if reexports.len() > 0 {
1421+
// Type pretty printing will prefer reexports that appear earlier
1422+
// in this map, so sort them to ensure that diagnostic output is
1423+
// stable.
1424+
reexports.sort_by_cached_key(|export| export.ident.as_str());
14211425
if let Some(def_id) = module.def_id() {
14221426
self.r.export_map.insert(def_id, reexports);
14231427
}

src/libsyntax/ext/proc_macro_server.rs

+1-2
Original file line numberDiff line numberDiff line change
@@ -332,8 +332,7 @@ impl Ident {
332332
if !Self::is_valid(&string) {
333333
panic!("`{:?}` is not a valid identifier", string)
334334
}
335-
// Get rid of gensyms to conservatively check rawness on the string contents only.
336-
if is_raw && !sym.as_interned_str().as_symbol().can_be_raw() {
335+
if is_raw && !sym.can_be_raw() {
337336
panic!("`{}` cannot be a raw identifier", string);
338337
}
339338
Ident { sym, is_raw, span }

src/libsyntax_pos/hygiene.rs

+27-3
Original file line numberDiff line numberDiff line change
@@ -217,8 +217,14 @@ impl HygieneData {
217217

218218
fn adjust(&self, ctxt: &mut SyntaxContext, expn_id: ExpnId) -> Option<ExpnId> {
219219
let mut scope = None;
220-
while !self.is_descendant_of(expn_id, self.outer_expn(*ctxt)) {
221-
scope = Some(self.remove_mark(ctxt).0);
220+
let mut outer = self.outer_expn(*ctxt);
221+
while !self.is_descendant_of(expn_id, outer) {
222+
if let ExpnData { kind: ExpnKind::Underscore, call_site, .. } = *self.expn_data(outer) {
223+
*ctxt = call_site.ctxt();
224+
} else {
225+
scope = Some(self.remove_mark(ctxt).0);
226+
}
227+
outer = self.outer_expn(*ctxt);
222228
}
223229
scope
224230
}
@@ -420,6 +426,21 @@ impl SyntaxContext {
420426
HygieneData::with(|data| data.marks(self))
421427
}
422428

429+
crate fn unique(base_span: Span) -> Self {
430+
HygieneData::with(|data| {
431+
// We store the original span as the call-site so that we can
432+
// recover it. We call `modern` here to save us calling it when we
433+
// access `call_site`.
434+
let modern = base_span.with_ctxt(data.modern(base_span.ctxt()));
435+
let expn_id = data.fresh_expn(Some(ExpnData::default(
436+
ExpnKind::Underscore,
437+
modern,
438+
data.expn_data(data.outer_expn(modern.ctxt())).edition,
439+
)));
440+
data.apply_mark(SyntaxContext::root(), expn_id, Transparency::Opaque)
441+
})
442+
}
443+
423444
/// Adjust this context for resolution in a scope created by the given expansion.
424445
/// For example, consider the following three resolutions of `f`:
425446
///
@@ -508,7 +529,7 @@ impl SyntaxContext {
508529
pub fn reverse_glob_adjust(&mut self, expn_id: ExpnId, glob_span: Span)
509530
-> Option<Option<ExpnId>> {
510531
HygieneData::with(|data| {
511-
if data.adjust(self, expn_id).is_some() {
532+
if data.adjust(&mut {*self}, expn_id).is_some() {
512533
return None;
513534
}
514535

@@ -674,6 +695,8 @@ pub enum ExpnKind {
674695
Macro(MacroKind, Symbol),
675696
/// Transform done by the compiler on the AST.
676697
AstPass(AstPass),
698+
/// Generated by name resolution to give underscores unique identifiers.
699+
Underscore,
677700
/// Desugaring done by the compiler during HIR lowering.
678701
Desugaring(DesugaringKind)
679702
}
@@ -684,6 +707,7 @@ impl ExpnKind {
684707
ExpnKind::Root => kw::PathRoot,
685708
ExpnKind::Macro(_, descr) => descr,
686709
ExpnKind::AstPass(kind) => Symbol::intern(kind.descr()),
710+
ExpnKind::Underscore => kw::Underscore,
687711
ExpnKind::Desugaring(kind) => Symbol::intern(kind.descr()),
688712
}
689713
}

src/libsyntax_pos/lib.rs

+1
Original file line numberDiff line numberDiff line change
@@ -443,6 +443,7 @@ impl Span {
443443
ExpnKind::Root => break,
444444
ExpnKind::Desugaring(..) => ("desugaring of ", ""),
445445
ExpnKind::AstPass(..) => ("", ""),
446+
ExpnKind::Underscore => ("", ""),
446447
ExpnKind::Macro(macro_kind, _) => match macro_kind {
447448
MacroKind::Bang => ("", "!"),
448449
MacroKind::Attr => ("#[", "]"),

src/libsyntax_pos/symbol.rs

+16-78
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ use std::fmt;
1515
use std::hash::{Hash, Hasher};
1616
use std::str;
1717

18-
use crate::{Span, DUMMY_SP, GLOBALS};
18+
use crate::{Span, SyntaxContext, DUMMY_SP, GLOBALS};
1919

2020
#[cfg(test)]
2121
mod tests;
@@ -803,15 +803,14 @@ impl Ident {
803803
Ident::new(self.name, self.span.modern_and_legacy())
804804
}
805805

806-
/// Transforms an underscore identifier into one with the same name, but
807-
/// gensymed. Leaves non-underscore identifiers unchanged.
808-
pub fn gensym_if_underscore(self) -> Ident {
806+
/// If the name of this ident is "_", then return a new unique identifier.
807+
/// Otherwise returns `self` unmodified
808+
#[inline]
809+
pub fn unique_if_underscore(mut self) -> Ident {
809810
if self.name == kw::Underscore {
810-
let name = with_interner(|interner| interner.gensymed(self.name));
811-
Ident::new(name, self.span)
812-
} else {
813-
self
811+
self.span = self.span.with_ctxt(SyntaxContext::unique(self.span));
814812
}
813+
self
815814
}
816815

817816
/// Convert the name to a `LocalInternedString`. This is a slowish
@@ -820,8 +819,7 @@ impl Ident {
820819
self.name.as_str()
821820
}
822821

823-
/// Convert the name to an `InternedString`. This is a slowish operation
824-
/// because it requires locking the symbol interner.
822+
/// Convert the name to an `InternedString`.
825823
pub fn as_interned_str(self) -> InternedString {
826824
self.name.as_interned_str()
827825
}
@@ -876,26 +874,9 @@ impl UseSpecializedDecodable for Ident {
876874
}
877875
}
878876

879-
/// A symbol is an interned or gensymed string. A gensym is a symbol that is
880-
/// never equal to any other symbol.
881-
///
882-
/// Conceptually, a gensym can be thought of as a normal symbol with an
883-
/// invisible unique suffix. Gensyms are useful when creating new identifiers
884-
/// that must not match any existing identifiers, e.g. during macro expansion
885-
/// and syntax desugaring. Because gensyms should always be identifiers, all
886-
/// gensym operations are on `Ident` rather than `Symbol`. (Indeed, in the
887-
/// future the gensym-ness may be moved from `Symbol` to hygiene data.)
877+
/// An interned string.
888878
///
889-
/// Examples:
890-
/// ```
891-
/// assert_eq!(Ident::from_str("_"), Ident::from_str("_"))
892-
/// assert_ne!(Ident::from_str("_").gensym_if_underscore(), Ident::from_str("_"))
893-
/// assert_ne!(
894-
/// Ident::from_str("_").gensym_if_underscore(),
895-
/// Ident::from_str("_").gensym_if_underscore(),
896-
/// )
897-
/// ```
898-
/// Internally, a symbol is implemented as an index, and all operations
879+
/// Internally, a `Symbol` is implemented as an index, and all operations
899880
/// (including hashing, equality, and ordering) operate on that index. The use
900881
/// of `newtype_index!` means that `Option<Symbol>` only takes up 4 bytes,
901882
/// because `newtype_index!` reserves the last 256 values for tagging purposes.
@@ -946,12 +927,9 @@ impl Symbol {
946927
})
947928
}
948929

949-
/// Convert to an `InternedString`. This is a slowish operation because it
950-
/// requires locking the symbol interner.
930+
/// Convert to an `InternedString`.
951931
pub fn as_interned_str(self) -> InternedString {
952-
with_interner(|interner| InternedString {
953-
symbol: interner.interned(self)
954-
})
932+
InternedString { symbol: self }
955933
}
956934

957935
pub fn as_u32(self) -> u32 {
@@ -961,12 +939,7 @@ impl Symbol {
961939

962940
impl fmt::Debug for Symbol {
963941
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
964-
let is_gensymed = with_interner(|interner| interner.is_gensymed(*self));
965-
if is_gensymed {
966-
write!(f, "{}({:?})", self, self.0)
967-
} else {
968-
write!(f, "{}", self)
969-
}
942+
fmt::Display::fmt(self, f)
970943
}
971944
}
972945

@@ -989,15 +962,11 @@ impl Decodable for Symbol {
989962
}
990963

991964
// The `&'static str`s in this type actually point into the arena.
992-
//
993-
// Note that normal symbols are indexed upward from 0, and gensyms are indexed
994-
// downward from SymbolIndex::MAX_AS_U32.
995965
#[derive(Default)]
996966
pub struct Interner {
997967
arena: DroplessArena,
998968
names: FxHashMap<&'static str, Symbol>,
999969
strings: Vec<&'static str>,
1000-
gensyms: Vec<Symbol>,
1001970
}
1002971

1003972
impl Interner {
@@ -1030,34 +999,10 @@ impl Interner {
1030999
self.names.insert(string, name);
10311000
name
10321001
}
1033-
1034-
fn interned(&self, symbol: Symbol) -> Symbol {
1035-
if (symbol.0.as_usize()) < self.strings.len() {
1036-
symbol
1037-
} else {
1038-
self.gensyms[(SymbolIndex::MAX_AS_U32 - symbol.0.as_u32()) as usize]
1039-
}
1040-
}
1041-
1042-
fn gensymed(&mut self, symbol: Symbol) -> Symbol {
1043-
self.gensyms.push(symbol);
1044-
Symbol::new(SymbolIndex::MAX_AS_U32 - self.gensyms.len() as u32 + 1)
1045-
}
1046-
1047-
fn is_gensymed(&mut self, symbol: Symbol) -> bool {
1048-
symbol.0.as_usize() >= self.strings.len()
1049-
}
1050-
10511002
// Get the symbol as a string. `Symbol::as_str()` should be used in
10521003
// preference to this function.
10531004
pub fn get(&self, symbol: Symbol) -> &str {
1054-
match self.strings.get(symbol.0.as_usize()) {
1055-
Some(string) => string,
1056-
None => {
1057-
let symbol = self.gensyms[(SymbolIndex::MAX_AS_U32 - symbol.0.as_u32()) as usize];
1058-
self.strings[symbol.0.as_usize()]
1059-
}
1060-
}
1005+
self.strings[symbol.0.as_usize()]
10611006
}
10621007
}
10631008

@@ -1242,19 +1187,12 @@ impl fmt::Display for LocalInternedString {
12421187
}
12431188
}
12441189

1245-
/// An alternative to `Symbol` that is focused on string contents. It has two
1246-
/// main differences to `Symbol`.
1190+
/// An alternative to `Symbol` that is focused on string contents.
12471191
///
1248-
/// First, its implementations of `Hash`, `PartialOrd` and `Ord` work with the
1192+
/// Its implementations of `Hash`, `PartialOrd` and `Ord` work with the
12491193
/// string chars rather than the symbol integer. This is useful when hash
12501194
/// stability is required across compile sessions, or a guaranteed sort
12511195
/// ordering is required.
1252-
///
1253-
/// Second, gensym-ness is irrelevant. E.g.:
1254-
/// ```
1255-
/// assert_ne!(Symbol::gensym("x"), Symbol::gensym("x"))
1256-
/// assert_eq!(Symbol::gensym("x").as_interned_str(), Symbol::gensym("x").as_interned_str())
1257-
/// ```
12581196
#[derive(Clone, Copy, PartialEq, Eq)]
12591197
pub struct InternedString {
12601198
symbol: Symbol,

src/libsyntax_pos/symbol/tests.rs

-7
Original file line numberDiff line numberDiff line change
@@ -14,13 +14,6 @@ fn interner_tests() {
1414
assert_eq!(i.intern("cat"), Symbol::new(1));
1515
// dog is still at zero
1616
assert_eq!(i.intern("dog"), Symbol::new(0));
17-
let z = i.intern("zebra");
18-
assert_eq!(i.gensymed(z), Symbol::new(SymbolIndex::MAX_AS_U32));
19-
// gensym of same string gets new number:
20-
assert_eq!(i.gensymed(z), Symbol::new(SymbolIndex::MAX_AS_U32 - 1));
21-
// gensym of *existing* string gets new number:
22-
let d = i.intern("dog");
23-
assert_eq!(i.gensymed(d), Symbol::new(SymbolIndex::MAX_AS_U32 - 2));
2417
}
2518

2619
#[test]
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
// Make sure that underscore imports with different contexts can exist in the
2+
// same scope.
3+
4+
// check-pass
5+
6+
#![feature(decl_macro)]
7+
8+
mod x {
9+
pub use std::ops::Deref as _;
10+
}
11+
12+
macro n() {
13+
pub use crate::x::*;
14+
}
15+
16+
#[macro_export]
17+
macro_rules! p {
18+
() => { pub use crate::x::*; }
19+
}
20+
21+
macro m($y:ident) {
22+
mod $y {
23+
crate::n!(); // Reexport of `Deref` should not be imported in `main`
24+
crate::p!(); // Reexport of `Deref` should be imported into `main`
25+
}
26+
}
27+
28+
m!(y);
29+
30+
fn main() {
31+
use crate::y::*;
32+
(&()).deref();
33+
}

0 commit comments

Comments
 (0)