diff --git a/src/librustc/ty/print/pretty.rs b/src/librustc/ty/print/pretty.rs index c4967f8d66d..363109a0582 100644 --- a/src/librustc/ty/print/pretty.rs +++ b/src/librustc/ty/print/pretty.rs @@ -1483,7 +1483,7 @@ impl FmtPrinter<'_, 'tcx, F> { } // Replace any anonymous late-bound regions with named - // variants, using gensym'd identifiers, so that we can + // variants, using new unique identifiers, so that we can // clearly differentiate between named and unnamed regions in // the output. We'll probably want to tweak this over time to // decide just how much information to give. diff --git a/src/librustc_resolve/build_reduced_graph.rs b/src/librustc_resolve/build_reduced_graph.rs index 1f86aafbddf..0d5361fe8d8 100644 --- a/src/librustc_resolve/build_reduced_graph.rs +++ b/src/librustc_resolve/build_reduced_graph.rs @@ -94,7 +94,8 @@ impl<'a> Resolver<'a> { where T: ToNameBinding<'a>, { let binding = def.to_name_binding(self.arenas); - if let Err(old_binding) = self.try_define(parent, ident, ns, binding) { + let key = self.new_key(ident, ns); + if let Err(old_binding) = self.try_define(parent, key, binding) { self.report_conflict(parent, ident, ns, old_binding, &binding); } } @@ -349,9 +350,12 @@ impl<'a, 'b> BuildReducedGraphVisitor<'a, 'b> { self.r.indeterminate_imports.push(directive); match directive.subclass { + // Don't add unresolved underscore imports to modules + SingleImport { target: Ident { name: kw::Underscore, .. }, .. } => {} SingleImport { target, type_ns_only, .. } => { self.r.per_ns(|this, ns| if !type_ns_only || ns == TypeNS { - let mut resolution = this.resolution(current_module, target, ns).borrow_mut(); + let key = this.new_key(target, ns); + let mut resolution = this.resolution(current_module, key).borrow_mut(); resolution.add_single_import(directive); }); } @@ -407,7 +411,7 @@ impl<'a, 'b> BuildReducedGraphVisitor<'a, 'b> { }; match use_tree.kind { ast::UseTreeKind::Simple(rename, ..) => { - let mut ident = use_tree.ident().gensym_if_underscore(); + let mut ident = use_tree.ident(); let mut module_path = prefix; let mut source = module_path.pop().unwrap(); let mut type_ns_only = false; @@ -585,7 +589,7 @@ impl<'a, 'b> BuildReducedGraphVisitor<'a, 'b> { let parent_scope = &self.parent_scope; let parent = parent_scope.module; let expansion = parent_scope.expansion; - let ident = item.ident.gensym_if_underscore(); + let ident = item.ident; let sp = item.span; let vis = self.resolve_visibility(&item.vis); @@ -851,10 +855,6 @@ impl<'a, 'b> BuildReducedGraphVisitor<'a, 'b> { fn build_reduced_graph_for_external_crate_res(&mut self, child: Export) { let parent = self.parent_scope.module; let Export { ident, res, vis, span } = child; - // FIXME: We shouldn't create the gensym here, it should come from metadata, - // but metadata cannot encode gensyms currently, so we create it here. - // This is only a guess, two equivalent idents may incorrectly get different gensyms here. - let ident = ident.gensym_if_underscore(); let expansion = ExpnId::root(); // FIXME(jseyfried) intercrate hygiene // Record primary definitions. match res { diff --git a/src/librustc_resolve/diagnostics.rs b/src/librustc_resolve/diagnostics.rs index d713315decb..de875808670 100644 --- a/src/librustc_resolve/diagnostics.rs +++ b/src/librustc_resolve/diagnostics.rs @@ -80,11 +80,11 @@ impl<'a> Resolver<'a> { names: &mut Vec, filter_fn: &impl Fn(Res) -> bool, ) { - for (&(ident, _), resolution) in self.resolutions(module).borrow().iter() { + for (key, resolution) in self.resolutions(module).borrow().iter() { if let Some(binding) = resolution.borrow().binding { let res = binding.res(); if filter_fn(res) { - names.push(TypoSuggestion::from_res(ident.name, res)); + names.push(TypoSuggestion::from_res(key.ident.name, res)); } } } @@ -849,7 +849,7 @@ impl<'a, 'b> ImportResolver<'a, 'b> { } let resolutions = self.r.resolutions(crate_module).borrow(); - let resolution = resolutions.get(&(ident, MacroNS))?; + let resolution = resolutions.get(&self.r.new_key(ident, MacroNS))?; let binding = resolution.borrow().binding()?; if let Res::Def(DefKind::Macro(MacroKind::Bang), _) = binding.res() { let module_name = crate_module.kind.name().unwrap(); diff --git a/src/librustc_resolve/lib.rs b/src/librustc_resolve/lib.rs index 5f77bcfeb7f..e5b0ef89a41 100644 --- a/src/librustc_resolve/lib.rs +++ b/src/librustc_resolve/lib.rs @@ -432,7 +432,22 @@ impl ModuleKind { } } -type Resolutions<'a> = RefCell>>>; +/// A key that identifies a binding in a given `Module`. +/// +/// Multiple bindings in the same module can have the same key (in a valid +/// program) if all but one of them come from glob imports. +#[derive(Copy, Clone, PartialEq, Eq, Hash)] +struct BindingKey { + /// The identifier for the binding, aways the `modern` version of the + /// identifier. + ident: Ident, + ns: Namespace, + /// 0 if ident is not `_`, otherwise a value that's unique to the specific + /// `_` in the expanded AST that introduced this binding. + disambiguator: u32, +} + +type Resolutions<'a> = RefCell>>>; /// One node in the tree of modules. pub struct ModuleData<'a> { @@ -492,8 +507,8 @@ impl<'a> ModuleData<'a> { fn for_each_child(&'a self, resolver: &mut R, mut f: F) where R: AsMut>, F: FnMut(&mut R, Ident, Namespace, &'a NameBinding<'a>) { - for (&(ident, ns), name_resolution) in resolver.as_mut().resolutions(self).borrow().iter() { - name_resolution.borrow().binding.map(|binding| f(resolver, ident, ns, binding)); + for (key, name_resolution) in resolver.as_mut().resolutions(self).borrow().iter() { + name_resolution.borrow().binding.map(|binding| f(resolver, key.ident, key.ns, binding)); } } @@ -882,6 +897,7 @@ pub struct Resolver<'a> { module_map: FxHashMap>, extern_module_map: FxHashMap>, binding_parent_modules: FxHashMap>, Module<'a>>, + underscore_disambiguator: u32, /// Maps glob imports to the names of items actually imported. pub glob_map: GlobMap, @@ -1160,6 +1176,7 @@ impl<'a> Resolver<'a> { extern_crate_map: Default::default(), export_map: FxHashMap::default(), trait_map: Default::default(), + underscore_disambiguator: 0, empty_module, module_map, block_map: Default::default(), @@ -1284,6 +1301,17 @@ impl<'a> Resolver<'a> { self.arenas.alloc_module(module) } + fn new_key(&mut self, ident: Ident, ns: Namespace) -> BindingKey { + let ident = ident.modern(); + let disambiguator = if ident.name == kw::Underscore { + self.underscore_disambiguator += 1; + self.underscore_disambiguator + } else { + 0 + }; + BindingKey { ident, ns, disambiguator } + } + fn resolutions(&mut self, module: Module<'a>) -> &'a Resolutions<'a> { if module.populate_on_access.get() { module.populate_on_access.set(false); @@ -1292,9 +1320,9 @@ impl<'a> Resolver<'a> { &module.lazy_resolutions } - fn resolution(&mut self, module: Module<'a>, ident: Ident, ns: Namespace) + fn resolution(&mut self, module: Module<'a>, key: BindingKey) -> &'a RefCell> { - *self.resolutions(module).borrow_mut().entry((ident.modern(), ns)) + *self.resolutions(module).borrow_mut().entry(key) .or_insert_with(|| self.arenas.alloc_name_resolution()) } diff --git a/src/librustc_resolve/resolve_imports.rs b/src/librustc_resolve/resolve_imports.rs index 360343169bc..56fd2da2576 100644 --- a/src/librustc_resolve/resolve_imports.rs +++ b/src/librustc_resolve/resolve_imports.rs @@ -7,7 +7,7 @@ use crate::{CrateLint, Module, ModuleOrUniformRoot, PerNS, ScopeSet, ParentScope use crate::Determinacy::{self, *}; use crate::Namespace::{self, TypeNS, MacroNS}; use crate::{NameBinding, NameBindingKind, ToNameBinding, PathResult, PrivacyError}; -use crate::{Resolver, ResolutionError, Segment, ModuleKind}; +use crate::{Resolver, ResolutionError, BindingKey, Segment, ModuleKind}; use crate::{names_to_string, module_to_string}; use crate::diagnostics::Suggestion; @@ -235,7 +235,8 @@ impl<'a> Resolver<'a> { } }; - let resolution = self.resolution(module, ident, ns) + let key = self.new_key(ident, ns); + let resolution = self.resolution(module, key) .try_borrow_mut() .map_err(|_| (Determined, Weak::No))?; // This happens when there is a cycle of imports. @@ -447,17 +448,16 @@ impl<'a> Resolver<'a> { } // Define the name or return the existing binding if there is a collision. - pub fn try_define( + crate fn try_define( &mut self, module: Module<'a>, - ident: Ident, - ns: Namespace, + key: BindingKey, binding: &'a NameBinding<'a>, ) -> Result<(), &'a NameBinding<'a>> { let res = binding.res(); - self.check_reserved_macro_name(ident, res); + self.check_reserved_macro_name(key.ident, res); self.set_binding_parent_module(binding, module); - self.update_resolution(module, ident, ns, |this, resolution| { + self.update_resolution(module, key, |this, resolution| { if let Some(old_binding) = resolution.binding { if res == Res::Err { // Do not override real bindings with `Res::Err`s from error recovery. @@ -479,8 +479,9 @@ impl<'a> Resolver<'a> { } else { (binding, old_binding) }; - if glob_binding.res() != nonglob_binding.res() && - ns == MacroNS && nonglob_binding.expansion != ExpnId::root() { + if glob_binding.res() != nonglob_binding.res() + && key.ns == MacroNS && nonglob_binding.expansion != ExpnId::root() + { resolution.binding = Some(this.ambiguity( AmbiguityKind::GlobVsExpanded, nonglob_binding, @@ -499,9 +500,9 @@ impl<'a> Resolver<'a> { DUPLICATE_MACRO_EXPORTS, CRATE_NODE_ID, binding.span, - &format!("a macro named `{}` has already been exported", ident), + &format!("a macro named `{}` has already been exported", key.ident), BuiltinLintDiagnostics::DuplicatedMacroExports( - ident, old_binding.span, binding.span)); + key.ident, old_binding.span, binding.span)); resolution.binding = Some(binding); } else { @@ -531,9 +532,9 @@ impl<'a> Resolver<'a> { // Use `f` to mutate the resolution of the name in the module. // If the resolution becomes a success, define it in the module's glob importers. fn update_resolution( - &mut self, module: Module<'a>, - ident: Ident, - ns: Namespace, + &mut self, + module: Module<'a>, + key: BindingKey, f: F, ) -> T where F: FnOnce(&mut Resolver<'a>, &mut NameResolution<'a>) -> T @@ -541,7 +542,7 @@ impl<'a> Resolver<'a> { // Ensure that `resolution` isn't borrowed when defining in the module's glob importers, // during which the resolution might end up getting re-defined via a glob cycle. let (binding, t) = { - let resolution = &mut *self.resolution(module, ident, ns).borrow_mut(); + let resolution = &mut *self.resolution(module, key).borrow_mut(); let old_binding = resolution.binding(); let t = f(self, resolution); @@ -558,7 +559,7 @@ impl<'a> Resolver<'a> { // Define `binding` in `module`s glob importers. for directive in module.glob_importers.borrow_mut().iter() { - let mut ident = ident.modern(); + let mut ident = key.ident; let scope = match ident.span.reverse_glob_adjust(module.expansion, directive.span) { Some(Some(def)) => self.macro_def_scope(def), Some(None) => directive.parent_scope.module, @@ -566,7 +567,8 @@ impl<'a> Resolver<'a> { }; if self.is_accessible_from(binding.vis, scope) { let imported_binding = self.import(binding, directive); - let _ = self.try_define(directive.parent_scope.module, ident, ns, imported_binding); + let key = BindingKey { ident, ..key }; + let _ = self.try_define(directive.parent_scope.module, key, imported_binding); } } @@ -580,7 +582,8 @@ impl<'a> Resolver<'a> { let dummy_binding = self.dummy_binding; let dummy_binding = self.import(dummy_binding, directive); self.per_ns(|this, ns| { - let _ = this.try_define(directive.parent_scope.module, target, ns, dummy_binding); + let key = this.new_key(target, ns); + let _ = this.try_define(directive.parent_scope.module, key, dummy_binding); // Consider erroneous imports used to avoid duplicate diagnostics. this.record_use(target, ns, dummy_binding, false); }); @@ -820,8 +823,11 @@ impl<'a, 'b> ImportResolver<'a, 'b> { let parent = directive.parent_scope.module; match source_bindings[ns].get() { Err(Undetermined) => indeterminate = true, + // Don't update the resolution, because it was never added. + Err(Determined) if target.name == kw::Underscore => {} Err(Determined) => { - this.update_resolution(parent, target, ns, |_, resolution| { + let key = this.new_key(target, ns); + this.update_resolution(parent, key, |_, resolution| { resolution.single_imports.remove(&PtrKey(directive)); }); } @@ -1052,7 +1058,7 @@ impl<'a, 'b> ImportResolver<'a, 'b> { _ => None, }; let resolutions = resolutions.as_ref().into_iter().flat_map(|r| r.iter()); - let names = resolutions.filter_map(|(&(ref i, _), resolution)| { + let names = resolutions.filter_map(|(BindingKey { ident: i, .. }, resolution)| { if *i == ident { return None; } // Never suggest the same name match *resolution.borrow() { NameResolution { binding: Some(name_binding), .. } => { @@ -1301,19 +1307,18 @@ impl<'a, 'b> ImportResolver<'a, 'b> { // Ensure that `resolutions` isn't borrowed during `try_define`, // since it might get updated via a glob cycle. - let bindings = self.r.resolutions(module).borrow().iter().filter_map(|(ident, resolution)| { - resolution.borrow().binding().map(|binding| (*ident, binding)) + let bindings = self.r.resolutions(module).borrow().iter().filter_map(|(key, resolution)| { + resolution.borrow().binding().map(|binding| (*key, binding)) }).collect::>(); - for ((mut ident, ns), binding) in bindings { - let scope = match ident.span.reverse_glob_adjust(module.expansion, directive.span) { + for (mut key, binding) in bindings { + let scope = match key.ident.span.reverse_glob_adjust(module.expansion, directive.span) { Some(Some(def)) => self.r.macro_def_scope(def), Some(None) => directive.parent_scope.module, None => continue, }; if self.r.is_accessible_from(binding.pseudo_vis(), scope) { let imported_binding = self.r.import(binding, directive); - let _ = - self.r.try_define(directive.parent_scope.module, ident, ns, imported_binding); + let _ = self.r.try_define(directive.parent_scope.module, key, imported_binding); } } @@ -1329,29 +1334,23 @@ impl<'a, 'b> ImportResolver<'a, 'b> { let mut reexports = Vec::new(); - for (&(ident, ns), resolution) in self.r.resolutions(module).borrow().iter() { - let resolution = &mut *resolution.borrow_mut(); - let binding = match resolution.binding { - Some(binding) => binding, - None => continue, - }; - + module.for_each_child(self.r, |this, ident, ns, binding| { // Filter away ambiguous imports and anything that has def-site // hygiene. // FIXME: Implement actual cross-crate hygiene. let is_good_import = binding.is_import() && !binding.is_ambiguity() - && !ident.span.modern().from_expansion(); + && !ident.span.from_expansion(); if is_good_import || binding.is_macro_def() { let res = binding.res(); if res != Res::Err { if let Some(def_id) = res.opt_def_id() { if !def_id.is_local() { - self.r.cstore.export_macros_untracked(def_id.krate); + this.cstore.export_macros_untracked(def_id.krate); } } reexports.push(Export { - ident: ident.modern(), - res: res, + ident, + res, span: binding.span, vis: binding.vis, }); @@ -1360,7 +1359,7 @@ impl<'a, 'b> ImportResolver<'a, 'b> { if let NameBindingKind::Import { binding: orig_binding, directive, .. } = binding.kind { if ns == TypeNS && orig_binding.is_variant() && - !orig_binding.vis.is_at_least(binding.vis, &*self) { + !orig_binding.vis.is_at_least(binding.vis, &*this) { let msg = match directive.subclass { ImportDirectiveSubclass::SingleImport { .. } => { format!("variant `{}` is private and cannot be re-exported", @@ -1372,33 +1371,34 @@ impl<'a, 'b> ImportResolver<'a, 'b> { let error_id = (DiagnosticMessageId::ErrorId(0), // no code?! Some(binding.span), msg.clone()); - let fresh = self.r.session.one_time_diagnostics + let fresh = this.session.one_time_diagnostics .borrow_mut().insert(error_id); if !fresh { - continue; + return; } msg }, ref s @ _ => bug!("unexpected import subclass {:?}", s) }; - let mut err = self.r.session.struct_span_err(binding.span, &msg); + let mut err = this.session.struct_span_err(binding.span, &msg); let imported_module = match directive.imported_module.get() { Some(ModuleOrUniformRoot::Module(module)) => module, _ => bug!("module should exist"), }; let parent_module = imported_module.parent.expect("parent should exist"); - let resolutions = self.r.resolutions(parent_module).borrow(); + let resolutions = this.resolutions(parent_module).borrow(); let enum_path_segment_index = directive.module_path.len() - 1; let enum_ident = directive.module_path[enum_path_segment_index].ident; - let enum_resolution = resolutions.get(&(enum_ident, TypeNS)) + let key = this.new_key(enum_ident, TypeNS); + let enum_resolution = resolutions.get(&key) .expect("resolution should exist"); let enum_span = enum_resolution.borrow() .binding.expect("binding should exist") .span; - let enum_def_span = self.r.session.source_map().def_span(enum_span); - let enum_def_snippet = self.r.session.source_map() + let enum_def_span = this.session.source_map().def_span(enum_span); + let enum_def_snippet = this.session.source_map() .span_to_snippet(enum_def_span).expect("snippet should exist"); // potentially need to strip extant `crate`/`pub(path)` for suggestion let after_vis_index = enum_def_snippet.find("enum") @@ -1406,7 +1406,7 @@ impl<'a, 'b> ImportResolver<'a, 'b> { let suggestion = format!("pub {}", &enum_def_snippet[after_vis_index..]); - self.r.session + this.session .diag_span_suggestion_once(&mut err, DiagnosticMessageId::ErrorId(0), enum_def_span, @@ -1415,7 +1415,7 @@ impl<'a, 'b> ImportResolver<'a, 'b> { err.emit(); } } - } + }); if reexports.len() > 0 { if let Some(def_id) = module.def_id() { diff --git a/src/libsyntax/ext/proc_macro_server.rs b/src/libsyntax/ext/proc_macro_server.rs index 300523c1b0a..e0e1a1c468c 100644 --- a/src/libsyntax/ext/proc_macro_server.rs +++ b/src/libsyntax/ext/proc_macro_server.rs @@ -334,8 +334,7 @@ impl Ident { if !Self::is_valid(&string) { panic!("`{:?}` is not a valid identifier", string) } - // Get rid of gensyms to conservatively check rawness on the string contents only. - if is_raw && !sym.as_interned_str().as_symbol().can_be_raw() { + if is_raw && !sym.can_be_raw() { panic!("`{}` cannot be a raw identifier", string); } Ident { sym, is_raw, span } diff --git a/src/libsyntax_pos/symbol.rs b/src/libsyntax_pos/symbol.rs index 8298edb42d4..8845b66a7ce 100644 --- a/src/libsyntax_pos/symbol.rs +++ b/src/libsyntax_pos/symbol.rs @@ -808,25 +808,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() } @@ -881,26 +869,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` only takes up 4 bytes, /// because `rustc_index::newtype_index!` reserves the last 256 values for tagging purposes. @@ -951,12 +922,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 { @@ -966,12 +934,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) } } @@ -994,15 +957,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, } impl Interner { @@ -1035,34 +994,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()] } } @@ -1223,19 +1158,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, diff --git a/src/libsyntax_pos/symbol/tests.rs b/src/libsyntax_pos/symbol/tests.rs index 1b91c9bb845..f74b9a0cd1d 100644 --- a/src/libsyntax_pos/symbol/tests.rs +++ b/src/libsyntax_pos/symbol/tests.rs @@ -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] diff --git a/src/test/ui/underscore-imports/hygiene-2.rs b/src/test/ui/underscore-imports/hygiene-2.rs new file mode 100644 index 00000000000..bea61eae6b5 --- /dev/null +++ b/src/test/ui/underscore-imports/hygiene-2.rs @@ -0,0 +1,33 @@ +// Make sure that underscore imports with different contexts can exist in the +// same scope. + +// check-pass + +#![feature(decl_macro)] + +mod x { + pub use std::ops::Deref as _; +} + +macro n() { + pub use crate::x::*; +} + +#[macro_export] +macro_rules! p { + () => { pub use crate::x::*; } +} + +macro m($y:ident) { + mod $y { + crate::n!(); // Reexport of `Deref` should not be imported in `main` + crate::p!(); // Reexport of `Deref` should be imported into `main` + } +} + +m!(y); + +fn main() { + use crate::y::*; + (&()).deref(); +} diff --git a/src/test/ui/underscore-imports/hygiene.rs b/src/test/ui/underscore-imports/hygiene.rs new file mode 100644 index 00000000000..a254f6eaa59 --- /dev/null +++ b/src/test/ui/underscore-imports/hygiene.rs @@ -0,0 +1,40 @@ +// Make sure that underscore imports have the same hygiene considerations as +// other imports. + +#![feature(decl_macro)] + +mod x { + pub use std::ops::Deref as _; +} + + +macro glob_import() { + pub use crate::x::*; +} + +macro underscore_import() { + use std::ops::DerefMut as _; +} + +mod y { + crate::glob_import!(); + crate::underscore_import!(); +} + +macro create_module($y:ident) { + mod $y { + crate::glob_import!(); + crate::underscore_import!(); + } +} + +create_module!(z); + +fn main() { + use crate::y::*; + use crate::z::*; + glob_import!(); + underscore_import!(); + (&()).deref(); //~ ERROR no method named `deref` + (&mut ()).deref_mut(); //~ ERROR no method named `deref_mut` +} diff --git a/src/test/ui/underscore-imports/hygiene.stderr b/src/test/ui/underscore-imports/hygiene.stderr new file mode 100644 index 00000000000..44cfc5cc5d2 --- /dev/null +++ b/src/test/ui/underscore-imports/hygiene.stderr @@ -0,0 +1,27 @@ +error[E0599]: no method named `deref` found for type `&()` in the current scope + --> $DIR/hygiene.rs:38:11 + | +LL | (&()).deref(); + | ^^^^^ method not found in `&()` + | + = help: items from traits can only be used if the trait is in scope +help: the following trait is implemented but not in scope; perhaps add a `use` for it: + | +LL | use std::ops::Deref; + | + +error[E0599]: no method named `deref_mut` found for type `&mut ()` in the current scope + --> $DIR/hygiene.rs:39:15 + | +LL | (&mut ()).deref_mut(); + | ^^^^^^^^^ method not found in `&mut ()` + | + = help: items from traits can only be used if the trait is in scope +help: the following trait is implemented but not in scope; perhaps add a `use` for it: + | +LL | use std::ops::DerefMut; + | + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0599`. diff --git a/src/test/ui/underscore-imports/macro-expanded.rs b/src/test/ui/underscore-imports/macro-expanded.rs new file mode 100644 index 00000000000..43f527bc9a4 --- /dev/null +++ b/src/test/ui/underscore-imports/macro-expanded.rs @@ -0,0 +1,45 @@ +// Check that macro expanded underscore imports behave as expected + +// check-pass + +#![feature(decl_macro, rustc_attrs)] + +mod x { + pub use std::ops::Not as _; +} + +macro m() { + mod w { + mod y { + pub use std::ops::Deref as _; + } + use crate::x::*; + use self::y::*; + use std::ops::DerefMut as _; + fn f() { + false.not(); + (&()).deref(); + (&mut ()).deref_mut(); + } + } +} + +#[rustc_macro_transparency = "transparent"] +macro n() { + mod z { + pub use std::ops::Deref as _; + } + use crate::x::*; + use crate::z::*; + use std::ops::DerefMut as _; + fn f() { + false.not(); + (&()).deref(); + (&mut ()).deref_mut(); + } +} + +m!(); +n!(); + +fn main() {}