diff --git a/src/librustc_resolve/lib.rs b/src/librustc_resolve/lib.rs index 07ded5c6723..bc0e8a56157 100644 --- a/src/librustc_resolve/lib.rs +++ b/src/librustc_resolve/lib.rs @@ -102,6 +102,12 @@ enum Weak { No, } +enum ScopeSet { + Import(Namespace), + Macro(MacroKind), + Module, +} + /// A free importable items suggested in case of resolution failure. struct ImportSuggestion { path: Path, @@ -997,22 +1003,19 @@ impl<'a> LexicalScopeBinding<'a> { } } - -#[derive(Clone, Copy, PartialEq, Debug)] -enum UniformRootKind { - CurrentScope, - ExternPrelude, -} - #[derive(Copy, Clone, Debug)] enum ModuleOrUniformRoot<'a> { /// Regular module. Module(Module<'a>), - /// This "virtual module" denotes either resolution in extern prelude - /// for paths starting with `::` on 2018 edition or `extern::`, - /// or resolution in current scope for single-segment imports. - UniformRoot(UniformRootKind), + /// Virtual module that denotes resolution in extern prelude. + /// Used for paths starting with `::` on 2018 edition or `extern::`. + ExternPrelude, + + /// Virtual module that denotes resolution in current scope. + /// Used only for resolving single-segment imports. The reason it exists is that import paths + /// are always split into two parts, the first of which should be some kind of module. + CurrentScope, } impl<'a> PartialEq for ModuleOrUniformRoot<'a> { @@ -1020,8 +1023,8 @@ impl<'a> PartialEq for ModuleOrUniformRoot<'a> { match (*self, *other) { (ModuleOrUniformRoot::Module(lhs), ModuleOrUniformRoot::Module(rhs)) => ptr::eq(lhs, rhs), - (ModuleOrUniformRoot::UniformRoot(lhs), ModuleOrUniformRoot::UniformRoot(rhs)) => - lhs == rhs, + (ModuleOrUniformRoot::ExternPrelude, ModuleOrUniformRoot::ExternPrelude) => true, + (ModuleOrUniformRoot::CurrentScope, ModuleOrUniformRoot::CurrentScope) => true, _ => false, } } @@ -1758,8 +1761,7 @@ impl<'a, 'crateloader> Resolver<'a, 'crateloader> { error_callback(self, span, ResolutionError::FailedToResolve(msg)); Def::Err } - PathResult::Module(ModuleOrUniformRoot::UniformRoot(_)) | - PathResult::Indeterminate => unreachable!(), + PathResult::Module(..) | PathResult::Indeterminate => unreachable!(), PathResult::Failed(span, msg, _) => { error_callback(self, span, ResolutionError::FailedToResolve(&msg)); Def::Err @@ -2220,11 +2222,11 @@ impl<'a, 'crateloader: 'a> Resolver<'a, 'crateloader> { self.current_module = self.macro_def_scope(def); } } - ModuleOrUniformRoot::UniformRoot(UniformRootKind::ExternPrelude) => { + ModuleOrUniformRoot::ExternPrelude => { ident.span = ident.span.modern(); ident.span.adjust(Mark::root()); } - ModuleOrUniformRoot::UniformRoot(UniformRootKind::CurrentScope) => { + ModuleOrUniformRoot::CurrentScope => { // No adjustments } } @@ -3667,8 +3669,7 @@ impl<'a, 'crateloader: 'a> Resolver<'a, 'crateloader> { resolve_error(self, span, ResolutionError::FailedToResolve(&msg)); err_path_resolution() } - PathResult::Module(ModuleOrUniformRoot::UniformRoot(_)) | - PathResult::Failed(..) => return None, + PathResult::Module(..) | PathResult::Failed(..) => return None, PathResult::Indeterminate => bug!("indetermined path result in resolve_qpath"), }; @@ -3787,8 +3788,7 @@ impl<'a, 'crateloader: 'a> Resolver<'a, 'crateloader> { } if name == keywords::Extern.name() || name == keywords::CrateRoot.name() && ident.span.rust_2018() { - module = - Some(ModuleOrUniformRoot::UniformRoot(UniformRootKind::ExternPrelude)); + module = Some(ModuleOrUniformRoot::ExternPrelude); continue; } if name == keywords::CrateRoot.name() || @@ -3821,9 +3821,9 @@ impl<'a, 'crateloader: 'a> Resolver<'a, 'crateloader> { self.resolve_ident_in_module(module, ident, ns, None, record_used, path_span) } else if opt_ns.is_none() || opt_ns == Some(MacroNS) { assert!(ns == TypeNS); - self.early_resolve_ident_in_lexical_scope(ident, ns, None, opt_ns.is_none(), - parent_scope, record_used, record_used, - path_span) + let scopes = if opt_ns.is_none() { ScopeSet::Import(ns) } else { ScopeSet::Module }; + self.early_resolve_ident_in_lexical_scope(ident, scopes, parent_scope, record_used, + record_used, path_span) } else { let record_used_id = if record_used { crate_lint.node_id().or(Some(CRATE_NODE_ID)) } else { None }; @@ -3912,8 +3912,7 @@ impl<'a, 'crateloader: 'a> Resolver<'a, 'crateloader> { PathResult::Module(match module { Some(module) => module, - None if path.is_empty() => - ModuleOrUniformRoot::UniformRoot(UniformRootKind::CurrentScope), + None if path.is_empty() => ModuleOrUniformRoot::CurrentScope, _ => span_bug!(path_span, "resolve_path: non-empty path `{:?}` has no module", path), }) } diff --git a/src/librustc_resolve/macros.rs b/src/librustc_resolve/macros.rs index bc3700b8c63..5493913fd81 100644 --- a/src/librustc_resolve/macros.rs +++ b/src/librustc_resolve/macros.rs @@ -9,11 +9,11 @@ // except according to those terms. use {AmbiguityError, AmbiguityKind, AmbiguityErrorMisc}; -use {CrateLint, Resolver, ResolutionError, Segment, Weak}; -use {Module, ModuleKind, NameBinding, NameBindingKind, PathResult, ToNameBinding}; +use {CrateLint, Resolver, ResolutionError, ScopeSet, Weak}; +use {Module, ModuleKind, NameBinding, NameBindingKind, PathResult, Segment, ToNameBinding}; use {is_known_tool, resolve_error}; use ModuleOrUniformRoot; -use Namespace::{self, *}; +use Namespace::*; use build_reduced_graph::{BuildReducedGraphVisitor, IsMacroExport}; use resolve_imports::ImportResolver; use rustc::hir::def_id::{DefId, CRATE_DEF_INDEX, DefIndex, @@ -502,7 +502,7 @@ impl<'a, 'cl> Resolver<'a, 'cl> { def } else { let binding = self.early_resolve_ident_in_lexical_scope( - path[0].ident, MacroNS, Some(kind), false, parent_scope, false, force, path_span + path[0].ident, ScopeSet::Macro(kind), parent_scope, false, force, path_span ); match binding { Ok(..) => {} @@ -527,9 +527,7 @@ impl<'a, 'cl> Resolver<'a, 'cl> { crate fn early_resolve_ident_in_lexical_scope( &mut self, orig_ident: Ident, - ns: Namespace, - macro_kind: Option, - is_import: bool, + scope_set: ScopeSet, parent_scope: &ParentScope<'a>, record_used: bool, force: bool, @@ -605,8 +603,6 @@ impl<'a, 'cl> Resolver<'a, 'cl> { } assert!(force || !record_used); // `record_used` implies `force` - assert!(macro_kind.is_none() || !is_import); // `is_import` implies no macro kind - let rust_2015 = orig_ident.span.rust_2015(); let mut ident = orig_ident.modern(); // Make sure `self`, `super` etc produce an error when passed to here. @@ -628,6 +624,12 @@ impl<'a, 'cl> Resolver<'a, 'cl> { let mut innermost_result: Option<(&NameBinding, Flags)> = None; // Go through all the scopes and try to resolve the name. + let rust_2015 = orig_ident.span.rust_2015(); + let (ns, macro_kind, is_import) = match scope_set { + ScopeSet::Import(ns) => (ns, None, true), + ScopeSet::Macro(macro_kind) => (MacroNS, Some(macro_kind), false), + ScopeSet::Module => (TypeNS, None, false), + }; let mut where_to_resolve = match ns { _ if is_import && rust_2015 => WhereToResolve::CrateRoot, TypeNS | ValueNS => WhereToResolve::Module(parent_scope.module), @@ -1041,7 +1043,7 @@ impl<'a, 'cl> Resolver<'a, 'cl> { let macro_resolutions = mem::replace(&mut *module.single_segment_macro_resolutions.borrow_mut(), Vec::new()); for (ident, kind, parent_scope, initial_binding) in macro_resolutions { - match self.early_resolve_ident_in_lexical_scope(ident, MacroNS, Some(kind), false, + match self.early_resolve_ident_in_lexical_scope(ident, ScopeSet::Macro(kind), &parent_scope, true, true, ident.span) { Ok(binding) => { let initial_def = initial_binding.map(|initial_binding| { @@ -1067,7 +1069,7 @@ impl<'a, 'cl> Resolver<'a, 'cl> { let builtin_attrs = mem::replace(&mut *module.builtin_attrs.borrow_mut(), Vec::new()); for (ident, parent_scope) in builtin_attrs { let _ = self.early_resolve_ident_in_lexical_scope( - ident, MacroNS, Some(MacroKind::Attr), false, &parent_scope, true, true, ident.span + ident, ScopeSet::Macro(MacroKind::Attr), &parent_scope, true, true, ident.span ); } } diff --git a/src/librustc_resolve/resolve_imports.rs b/src/librustc_resolve/resolve_imports.rs index 52e3e54b9f9..47bfadf932e 100644 --- a/src/librustc_resolve/resolve_imports.rs +++ b/src/librustc_resolve/resolve_imports.rs @@ -11,7 +11,7 @@ use self::ImportDirectiveSubclass::*; use {AmbiguityError, AmbiguityKind, AmbiguityErrorMisc}; -use {CrateLint, Module, ModuleOrUniformRoot, PerNS, UniformRootKind, Weak}; +use {CrateLint, Module, ModuleOrUniformRoot, PerNS, ScopeSet, Weak}; use Namespace::{self, TypeNS, MacroNS}; use {NameBinding, NameBindingKind, ToNameBinding, PathResult, PrivacyError}; use {Resolver, Segment}; @@ -162,45 +162,42 @@ impl<'a, 'crateloader> Resolver<'a, 'crateloader> { ) -> Result<&'a NameBinding<'a>, (Determinacy, Weak)> { let module = match module { ModuleOrUniformRoot::Module(module) => module, - ModuleOrUniformRoot::UniformRoot(uniform_root_kind) => { + ModuleOrUniformRoot::ExternPrelude => { assert!(!restricted_shadowing); - match uniform_root_kind { - UniformRootKind::ExternPrelude => { - return if let Some(binding) = self.extern_prelude_get(ident, !record_used) { - Ok(binding) - } else if !self.graph_root.unresolved_invocations.borrow().is_empty() { - // Macro-expanded `extern crate` items can add names to extern prelude. - Err((Undetermined, Weak::No)) - } else { - Err((Determined, Weak::No)) - } - } - UniformRootKind::CurrentScope => { - let parent_scope = - parent_scope.expect("no parent scope for a single-segment import"); + return if let Some(binding) = self.extern_prelude_get(ident, !record_used) { + Ok(binding) + } else if !self.graph_root.unresolved_invocations.borrow().is_empty() { + // Macro-expanded `extern crate` items can add names to extern prelude. + Err((Undetermined, Weak::No)) + } else { + Err((Determined, Weak::No)) + } + } + ModuleOrUniformRoot::CurrentScope => { + assert!(!restricted_shadowing); + let parent_scope = + parent_scope.expect("no parent scope for a single-segment import"); - if ns == TypeNS { - if ident.name == keywords::Crate.name() || - ident.name == keywords::DollarCrate.name() { - let module = self.resolve_crate_root(ident); - let binding = (module, ty::Visibility::Public, - module.span, Mark::root()) - .to_name_binding(self.arenas); - return Ok(binding); - } else if ident.name == keywords::Super.name() || - ident.name == keywords::SelfValue.name() { - // FIXME: Implement these with renaming requirements so that e.g. - // `use super;` doesn't work, but `use super as name;` does. - // Fall through here to get an error from `early_resolve_...`. - } - } - - let binding = self.early_resolve_ident_in_lexical_scope( - ident, ns, None, true, parent_scope, record_used, record_used, path_span - ); - return binding.map_err(|determinacy| (determinacy, Weak::No)); + if ns == TypeNS { + if ident.name == keywords::Crate.name() || + ident.name == keywords::DollarCrate.name() { + let module = self.resolve_crate_root(ident); + let binding = (module, ty::Visibility::Public, + module.span, Mark::root()) + .to_name_binding(self.arenas); + return Ok(binding); + } else if ident.name == keywords::Super.name() || + ident.name == keywords::SelfValue.name() { + // FIXME: Implement these with renaming requirements so that e.g. + // `use super;` doesn't work, but `use super as name;` does. + // Fall through here to get an error from `early_resolve_...`. } } + + let binding = self.early_resolve_ident_in_lexical_scope( + ident, ScopeSet::Import(ns), parent_scope, record_used, record_used, path_span + ); + return binding.map_err(|determinacy| (determinacy, Weak::No)); } }; @@ -333,7 +330,7 @@ impl<'a, 'crateloader> Resolver<'a, 'crateloader> { } let module = match glob_import.imported_module.get() { Some(ModuleOrUniformRoot::Module(module)) => module, - Some(ModuleOrUniformRoot::UniformRoot(_)) => continue, + Some(_) => continue, None => return Err((Undetermined, Weak::Yes)), }; let (orig_current_module, mut ident) = (self.current_module, ident.modern()); @@ -966,9 +963,8 @@ impl<'a, 'b:'a, 'c: 'b> ImportResolver<'a, 'b, 'c> { return if all_ns_failed { let resolutions = match module { - ModuleOrUniformRoot::Module(module) => - Some(module.resolutions.borrow()), - ModuleOrUniformRoot::UniformRoot(_) => None, + ModuleOrUniformRoot::Module(module) => Some(module.resolutions.borrow()), + _ => None, }; let resolutions = resolutions.as_ref().into_iter().flat_map(|r| r.iter()); let names = resolutions.filter_map(|(&(ref i, _), resolution)| { @@ -1006,7 +1002,7 @@ impl<'a, 'b:'a, 'c: 'b> ImportResolver<'a, 'b, 'c> { format!("no `{}` in the root{}", ident, lev_suggestion) } } - ModuleOrUniformRoot::UniformRoot(_) => { + _ => { if !ident.is_path_segment_keyword() { format!("no `{}` external crate{}", ident, lev_suggestion) } else { @@ -1107,9 +1103,8 @@ impl<'a, 'b:'a, 'c: 'b> ImportResolver<'a, 'b, 'c> { fn resolve_glob_import(&mut self, directive: &'b ImportDirective<'b>) { let module = match directive.imported_module.get().unwrap() { ModuleOrUniformRoot::Module(module) => module, - ModuleOrUniformRoot::UniformRoot(_) => { - self.session.span_err(directive.span, - "cannot glob-import all possible crates"); + _ => { + self.session.span_err(directive.span, "cannot glob-import all possible crates"); return; } };