]> git.proxmox.com Git - rustc.git/blobdiff - src/librustc_resolve/resolve_imports.rs
New upstream version 1.17.0+dfsg1
[rustc.git] / src / librustc_resolve / resolve_imports.rs
index fe21e5295911c4edfb29f0f2442a3c6b3916a7ab..dbc8bca548b769a1334f15facf53288a0a7e8845 100644 (file)
@@ -8,78 +8,62 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-use self::Determinacy::*;
 use self::ImportDirectiveSubclass::*;
 
-use Module;
-use Namespace::{self, TypeNS, ValueNS};
-use {NameBinding, NameBindingKind, PrivacyError, ToNameBinding};
-use ResolveResult;
-use ResolveResult::*;
+use {AmbiguityError, Module, PerNS};
+use Namespace::{self, TypeNS, MacroNS};
+use {NameBinding, NameBindingKind, PathResult, PrivacyError};
 use Resolver;
-use UseLexicalScopeFlag::DontUseLexicalScope;
 use {names_to_string, module_to_string};
 use {resolve_error, ResolutionError};
 
 use rustc::ty;
 use rustc::lint::builtin::PRIVATE_IN_PUBLIC;
+use rustc::hir::def_id::DefId;
 use rustc::hir::def::*;
+use rustc::util::nodemap::FxHashSet;
 
-use syntax::ast::{NodeId, Name};
+use syntax::ast::{Ident, NodeId};
+use syntax::ext::base::Determinacy::{self, Determined, Undetermined};
+use syntax::ext::hygiene::Mark;
+use syntax::parse::token;
+use syntax::symbol::keywords;
 use syntax::util::lev_distance::find_best_match_for_name;
 use syntax_pos::Span;
 
 use std::cell::{Cell, RefCell};
-
-impl<'a> Resolver<'a> {
-    pub fn resolve_imports(&mut self) {
-        ImportResolver { resolver: self }.resolve_imports();
-    }
-}
-
-#[derive(Copy, Clone, Debug)]
-pub enum Determinacy {
-    Determined,
-    Undetermined,
-}
+use std::mem;
 
 /// Contains data for specific types of import directives.
 #[derive(Clone, Debug)]
 pub enum ImportDirectiveSubclass<'a> {
     SingleImport {
-        target: Name,
-        source: Name,
-        value_result: Cell<Result<&'a NameBinding<'a>, Determinacy>>,
-        type_result: Cell<Result<&'a NameBinding<'a>, Determinacy>>,
+        target: Ident,
+        source: Ident,
+        result: PerNS<Cell<Result<&'a NameBinding<'a>, Determinacy>>>,
+        type_ns_only: bool,
     },
     GlobImport {
         is_prelude: bool,
         max_vis: Cell<ty::Visibility>, // The visibility of the greatest reexport.
         // n.b. `max_vis` is only used in `finalize_import` to check for reexport errors.
     },
-}
-
-impl<'a> ImportDirectiveSubclass<'a> {
-    pub fn single(target: Name, source: Name) -> Self {
-        SingleImport {
-            target: target,
-            source: source,
-            type_result: Cell::new(Err(Undetermined)),
-            value_result: Cell::new(Err(Undetermined)),
-        }
-    }
+    ExternCrate,
+    MacroUse,
 }
 
 /// One import directive.
 #[derive(Debug,Clone)]
 pub struct ImportDirective<'a> {
     pub id: NodeId,
-    parent: Module<'a>,
-    module_path: Vec<Name>,
-    imported_module: Cell<Option<Module<'a>>>, // the resolution of `module_path`
-    subclass: ImportDirectiveSubclass<'a>,
-    span: Span,
-    vis: Cell<ty::Visibility>,
+    pub parent: Module<'a>,
+    pub module_path: Vec<Ident>,
+    pub imported_module: Cell<Option<Module<'a>>>, // the resolution of `module_path`
+    pub subclass: ImportDirectiveSubclass<'a>,
+    pub span: Span,
+    pub vis: Cell<ty::Visibility>,
+    pub expansion: Mark,
+    pub used: Cell<bool>,
 }
 
 impl<'a> ImportDirective<'a> {
@@ -95,7 +79,7 @@ pub struct NameResolution<'a> {
     single_imports: SingleImports<'a>,
     /// The least shadowable known binding for this name, or None if there are no known bindings.
     pub binding: Option<&'a NameBinding<'a>>,
-    duplicate_globs: Vec<&'a NameBinding<'a>>,
+    shadows_glob: Option<&'a NameBinding<'a>>,
 }
 
 #[derive(Clone, Debug)]
@@ -148,121 +132,123 @@ impl<'a> NameResolution<'a> {
 }
 
 impl<'a> Resolver<'a> {
-    fn resolution(&self, module: Module<'a>, name: Name, ns: Namespace)
+    fn resolution(&self, module: Module<'a>, ident: Ident, ns: Namespace)
                   -> &'a RefCell<NameResolution<'a>> {
-        *module.resolutions.borrow_mut().entry((name, ns))
+        let ident = ident.unhygienize();
+        *module.resolutions.borrow_mut().entry((ident, ns))
                .or_insert_with(|| self.arenas.alloc_name_resolution())
     }
 
-    /// Attempts to resolve the supplied name in the given module for the given namespace.
-    /// If successful, returns the binding corresponding to the name.
+    /// Attempts to resolve `ident` in namespaces `ns` of `module`.
     /// Invariant: if `record_used` is `Some`, import resolution must be complete.
-    pub fn resolve_name_in_module(&mut self,
-                                  module: Module<'a>,
-                                  name: Name,
-                                  ns: Namespace,
-                                  allow_private_imports: bool,
-                                  record_used: Option<Span>)
-                                  -> ResolveResult<&'a NameBinding<'a>> {
+    pub fn resolve_ident_in_module(&mut self,
+                                   module: Module<'a>,
+                                   ident: Ident,
+                                   ns: Namespace,
+                                   ignore_unresolved_invocations: bool,
+                                   record_used: Option<Span>)
+                                   -> Result<&'a NameBinding<'a>, Determinacy> {
         self.populate_module_if_necessary(module);
 
-        let resolution = self.resolution(module, name, ns);
-        let resolution = match resolution.borrow_state() {
-            ::std::cell::BorrowState::Unused => resolution.borrow_mut(),
-            _ => return Failed(None), // This happens when there is a cycle of imports
-        };
-
-        let new_import_semantics = self.new_import_semantics;
-        let is_disallowed_private_import = |binding: &NameBinding| {
-            !new_import_semantics && !allow_private_imports && // disallowed
-            binding.vis != ty::Visibility::Public && binding.is_import() // non-`pub` import
-        };
+        let resolution = self.resolution(module, ident, ns)
+            .try_borrow_mut()
+            .map_err(|_| Determined)?; // This happens when there is a cycle of imports
 
         if let Some(span) = record_used {
             if let Some(binding) = resolution.binding {
-                if is_disallowed_private_import(binding) {
-                    return Failed(None);
+                if let Some(shadowed_glob) = resolution.shadows_glob {
+                    let name = ident.name;
+                    // If we ignore unresolved invocations, we must forbid
+                    // expanded shadowing to avoid time travel.
+                    if ignore_unresolved_invocations &&
+                       binding.expansion != Mark::root() &&
+                       ns != MacroNS && // In MacroNS, `try_define` always forbids this shadowing
+                       binding.def() != shadowed_glob.def() {
+                        self.ambiguity_errors.push(AmbiguityError {
+                            span: span, name: name, lexical: false, b1: binding, b2: shadowed_glob,
+                            legacy: false,
+                        });
+                    }
                 }
-                if self.record_use(name, ns, binding, span) {
-                    return Success(self.dummy_binding);
+                if self.record_use(ident, ns, binding, span) {
+                    return Ok(self.dummy_binding);
                 }
                 if !self.is_accessible(binding.vis) {
-                    self.privacy_errors.push(PrivacyError(span, name, binding));
+                    self.privacy_errors.push(PrivacyError(span, ident.name, binding));
                 }
             }
 
-            return resolution.binding.map(Success).unwrap_or(Failed(None));
+            return resolution.binding.ok_or(Determined);
         }
 
-        // If the resolution doesn't depend on glob definability, check privacy and return.
-        if let Some(result) = self.try_result(&resolution, ns) {
-            return result.and_then(|binding| {
-                if self.is_accessible(binding.vis) && !is_disallowed_private_import(binding) ||
-                   binding.is_extern_crate() { // c.f. issue #37020
-                    Success(binding)
-                } else {
-                    Failed(None)
-                }
-            });
-        }
+        let check_usable = |this: &mut Self, binding: &'a NameBinding<'a>| {
+            // `extern crate` are always usable for backwards compatability, see issue #37020.
+            let usable = this.is_accessible(binding.vis) || binding.is_extern_crate();
+            if usable { Ok(binding) } else { Err(Determined) }
+        };
 
-        // Check if the globs are determined
-        for directive in module.globs.borrow().iter() {
-            if self.is_accessible(directive.vis.get()) {
-                if let Some(module) = directive.imported_module.get() {
-                    let result = self.resolve_name_in_module(module, name, ns, true, None);
-                    if let Indeterminate = result {
-                        return Indeterminate;
-                    }
-                } else {
-                    return Indeterminate;
-                }
+        // Items and single imports are not shadowable.
+        if let Some(binding) = resolution.binding {
+            if !binding.is_glob_import() {
+                return check_usable(self, binding);
             }
         }
 
-        Failed(None)
-    }
-
-    // Returns Some(the resolution of the name), or None if the resolution depends
-    // on whether more globs can define the name.
-    fn try_result(&mut self, resolution: &NameResolution<'a>, ns: Namespace)
-                  -> Option<ResolveResult<&'a NameBinding<'a>>> {
-        match resolution.binding {
-            Some(binding) if !binding.is_glob_import() =>
-                return Some(Success(binding)), // Items and single imports are not shadowable.
-            _ => {}
-        };
-
         // Check if a single import can still define the name.
         match resolution.single_imports {
-            SingleImports::AtLeastOne => return Some(Indeterminate),
+            SingleImports::AtLeastOne => return Err(Undetermined),
             SingleImports::MaybeOne(directive) if self.is_accessible(directive.vis.get()) => {
                 let module = match directive.imported_module.get() {
                     Some(module) => module,
-                    None => return Some(Indeterminate),
+                    None => return Err(Undetermined),
                 };
-                let name = match directive.subclass {
+                let ident = match directive.subclass {
                     SingleImport { source, .. } => source,
-                    GlobImport { .. } => unreachable!(),
+                    _ => unreachable!(),
                 };
-                match self.resolve_name_in_module(module, name, ns, true, None) {
-                    Failed(_) => {}
-                    _ => return Some(Indeterminate),
+                match self.resolve_ident_in_module(module, ident, ns, false, None) {
+                    Err(Determined) => {}
+                    _ => return Err(Undetermined),
                 }
             }
             SingleImports::MaybeOne(_) | SingleImports::None => {},
         }
 
-        resolution.binding.map(Success)
+        let no_unresolved_invocations =
+            ignore_unresolved_invocations || module.unresolved_invocations.borrow().is_empty();
+        match resolution.binding {
+            // In `MacroNS`, expanded bindings do not shadow (enforced in `try_define`).
+            Some(binding) if no_unresolved_invocations || ns == MacroNS =>
+                return check_usable(self, binding),
+            None if no_unresolved_invocations => {}
+            _ => return Err(Undetermined),
+        }
+
+        // Check if the globs are determined
+        for directive in module.globs.borrow().iter() {
+            if self.is_accessible(directive.vis.get()) {
+                if let Some(module) = directive.imported_module.get() {
+                    let result = self.resolve_ident_in_module(module, ident, ns, false, None);
+                    if let Err(Undetermined) = result {
+                        return Err(Undetermined);
+                    }
+                } else {
+                    return Err(Undetermined);
+                }
+            }
+        }
+
+        Err(Determined)
     }
 
     // Add an import directive to the current module.
     pub fn add_import_directive(&mut self,
-                                module_path: Vec<Name>,
+                                module_path: Vec<Ident>,
                                 subclass: ImportDirectiveSubclass<'a>,
                                 span: Span,
                                 id: NodeId,
-                                vis: ty::Visibility) {
+                                vis: ty::Visibility,
+                                expansion: Mark) {
         let current_module = self.current_module;
         let directive = self.arenas.alloc_import_directive(ImportDirective {
             parent: current_module,
@@ -272,27 +258,30 @@ impl<'a> Resolver<'a> {
             span: span,
             id: id,
             vis: Cell::new(vis),
+            expansion: expansion,
+            used: Cell::new(false),
         });
 
         self.indeterminate_imports.push(directive);
         match directive.subclass {
             SingleImport { target, .. } => {
-                for &ns in &[ValueNS, TypeNS] {
-                    let mut resolution = self.resolution(current_module, target, ns).borrow_mut();
+                self.per_ns(|this, ns| {
+                    let mut resolution = this.resolution(current_module, target, ns).borrow_mut();
                     resolution.single_imports.add_directive(directive);
-                }
+                });
             }
             // We don't add prelude imports to the globs since they only affect lexical scopes,
             // which are not relevant to import resolution.
             GlobImport { is_prelude: true, .. } => {}
             GlobImport { .. } => self.current_module.globs.borrow_mut().push(directive),
+            _ => unreachable!(),
         }
     }
 
     // Given a binding and an import directive that resolves to it,
     // return the corresponding binding defined by the import directive.
-    fn import(&mut self, binding: &'a NameBinding<'a>, directive: &'a ImportDirective<'a>)
-              -> NameBinding<'a> {
+    pub fn import(&self, binding: &'a NameBinding<'a>, directive: &'a ImportDirective<'a>)
+                  -> &'a NameBinding<'a> {
         let vis = if binding.pseudo_vis().is_at_least(directive.vis.get(), self) ||
                      !directive.is_glob() && binding.is_extern_crate() { // c.f. `PRIVATE_IN_PUBLIC`
             directive.vis.get()
@@ -306,48 +295,46 @@ impl<'a> Resolver<'a> {
             }
         }
 
-        NameBinding {
+        self.arenas.alloc_name_binding(NameBinding {
             kind: NameBindingKind::Import {
                 binding: binding,
                 directive: directive,
                 used: Cell::new(false),
+                legacy_self_import: false,
             },
             span: directive.span,
             vis: vis,
-        }
+            expansion: directive.expansion,
+        })
     }
 
     // Define the name or return the existing binding if there is a collision.
-    pub fn try_define<T>(&mut self, module: Module<'a>, name: Name, ns: Namespace, binding: T)
-                         -> Result<(), &'a NameBinding<'a>>
-        where T: ToNameBinding<'a>
-    {
-        let binding = self.arenas.alloc_name_binding(binding.to_name_binding());
-        self.update_resolution(module, name, ns, |this, resolution| {
+    pub fn try_define(&mut self,
+                      module: Module<'a>,
+                      ident: Ident,
+                      ns: Namespace,
+                      binding: &'a NameBinding<'a>)
+                      -> Result<(), &'a NameBinding<'a>> {
+        self.update_resolution(module, ident, ns, |this, resolution| {
             if let Some(old_binding) = resolution.binding {
                 if binding.is_glob_import() {
-                    if !this.new_import_semantics || !old_binding.is_glob_import() {
-                        resolution.duplicate_globs.push(binding);
+                    if !old_binding.is_glob_import() &&
+                       !(ns == MacroNS && old_binding.expansion != Mark::root()) {
+                        resolution.shadows_glob = Some(binding);
                     } else if binding.def() != old_binding.def() {
-                        resolution.binding = Some(this.arenas.alloc_name_binding(NameBinding {
-                            kind: NameBindingKind::Ambiguity {
-                                b1: old_binding,
-                                b2: binding,
-                            },
-                            vis: if old_binding.vis.is_at_least(binding.vis, this) {
-                                old_binding.vis
-                            } else {
-                                binding.vis
-                            },
-                            span: old_binding.span,
-                        }));
-                    } else if !old_binding.vis.is_at_least(binding.vis, this) {
+                        resolution.binding = Some(this.ambiguity(old_binding, binding));
+                    } else if !old_binding.vis.is_at_least(binding.vis, &*this) {
                         // We are glob-importing the same item but with greater visibility.
                         resolution.binding = Some(binding);
                     }
                 } else if old_binding.is_glob_import() {
-                    resolution.duplicate_globs.push(old_binding);
-                    resolution.binding = Some(binding);
+                    if ns == MacroNS && binding.expansion != Mark::root() &&
+                       binding.def() != old_binding.def() {
+                        resolution.binding = Some(this.ambiguity(binding, old_binding));
+                    } else {
+                        resolution.binding = Some(binding);
+                        resolution.shadows_glob = Some(old_binding);
+                    }
                 } else {
                     return Err(old_binding);
                 }
@@ -359,21 +346,32 @@ impl<'a> Resolver<'a> {
         })
     }
 
+    pub fn ambiguity(&self, b1: &'a NameBinding<'a>, b2: &'a NameBinding<'a>)
+                     -> &'a NameBinding<'a> {
+        self.arenas.alloc_name_binding(NameBinding {
+            kind: NameBindingKind::Ambiguity { b1: b1, b2: b2, legacy: false },
+            vis: if b1.vis.is_at_least(b2.vis, self) { b1.vis } else { b2.vis },
+            span: b1.span,
+            expansion: Mark::root(),
+        })
+    }
+
     // 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<T, F>(&mut self, module: Module<'a>, name: Name, ns: Namespace, f: F) -> T
+    fn update_resolution<T, F>(&mut self, module: Module<'a>, ident: Ident, ns: Namespace, f: F)
+                               -> T
         where F: FnOnce(&mut Resolver<'a>, &mut NameResolution<'a>) -> T
     {
         // 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 mut resolution = &mut *self.resolution(module, name, ns).borrow_mut();
+            let mut resolution = &mut *self.resolution(module, ident, ns).borrow_mut();
             let old_binding = resolution.binding();
 
             let t = f(self, resolution);
 
             match resolution.binding() {
-                _ if !self.new_import_semantics && old_binding.is_some() => return t,
+                _ if old_binding.is_some() => return t,
                 None => return t,
                 Some(binding) => match old_binding {
                     Some(old_binding) if old_binding as *const _ == binding as *const _ => return t,
@@ -384,21 +382,30 @@ impl<'a> Resolver<'a> {
 
         // Define `binding` in `module`s glob importers.
         for directive in module.glob_importers.borrow_mut().iter() {
-            if match self.new_import_semantics {
-                true => self.is_accessible_from(binding.vis, directive.parent),
-                false => binding.vis == ty::Visibility::Public,
-            } {
+            if self.is_accessible_from(binding.vis, directive.parent) {
                 let imported_binding = self.import(binding, directive);
-                let _ = self.try_define(directive.parent, name, ns, imported_binding);
+                let _ = self.try_define(directive.parent, ident, ns, imported_binding);
             }
         }
 
         t
     }
+
+    // Define a "dummy" resolution containing a Def::Err as a placeholder for a
+    // failed resolution
+    fn import_dummy_binding(&mut self, directive: &'a ImportDirective<'a>) {
+        if let SingleImport { target, .. } = directive.subclass {
+            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, target, ns, dummy_binding);
+            });
+        }
+    }
 }
 
-struct ImportResolver<'a, 'b: 'a> {
-    resolver: &'a mut Resolver<'b>,
+pub struct ImportResolver<'a, 'b: 'a> {
+    pub resolver: &'a mut Resolver<'b>,
 }
 
 impl<'a, 'b: 'a> ::std::ops::Deref for ImportResolver<'a, 'b> {
@@ -414,9 +421,9 @@ impl<'a, 'b: 'a> ::std::ops::DerefMut for ImportResolver<'a, 'b> {
     }
 }
 
-impl<'a, 'b: 'a> ty::NodeIdTree for ImportResolver<'a, 'b> {
-    fn is_descendant_of(&self, node: NodeId, ancestor: NodeId) -> bool {
-        self.resolver.is_descendant_of(node, ancestor)
+impl<'a, 'b: 'a> ty::DefIdTree for &'a ImportResolver<'a, 'b> {
+    fn parent(self, id: DefId) -> Option<DefId> {
+        self.resolver.parent(id)
     }
 }
 
@@ -431,28 +438,20 @@ impl<'a, 'b:'a> ImportResolver<'a, 'b> {
 
     /// Resolves all imports for the crate. This method performs the fixed-
     /// point iteration.
-    fn resolve_imports(&mut self) {
-        let mut i = 0;
+    pub fn resolve_imports(&mut self) {
         let mut prev_num_indeterminates = self.indeterminate_imports.len() + 1;
-
         while self.indeterminate_imports.len() < prev_num_indeterminates {
             prev_num_indeterminates = self.indeterminate_imports.len();
-            debug!("(resolving imports) iteration {}, {} imports left", i, prev_num_indeterminates);
-
-            let mut imports = Vec::new();
-            ::std::mem::swap(&mut imports, &mut self.indeterminate_imports);
-
-            for import in imports {
+            for import in mem::replace(&mut self.indeterminate_imports, Vec::new()) {
                 match self.resolve_import(&import) {
-                    Failed(_) => self.determined_imports.push(import),
-                    Indeterminate => self.indeterminate_imports.push(import),
-                    Success(()) => self.determined_imports.push(import),
+                    true => self.determined_imports.push(import),
+                    false => self.indeterminate_imports.push(import),
                 }
             }
-
-            i += 1;
         }
+    }
 
+    pub fn finalize_imports(&mut self) {
         for module in self.arenas.local_modules().iter() {
             self.finalize_resolutions_in(module);
         }
@@ -460,19 +459,15 @@ impl<'a, 'b:'a> ImportResolver<'a, 'b> {
         let mut errors = false;
         for i in 0 .. self.determined_imports.len() {
             let import = self.determined_imports[i];
-            if let Failed(err) = self.finalize_import(import) {
+            if let Some(err) = self.finalize_import(import) {
                 errors = true;
-                let (span, help) = match err {
-                    Some((span, msg)) => (span, msg),
-                    None => continue,
-                };
 
                 // If the error is a single failed import then create a "fake" import
                 // resolution for it so that later resolve stages won't complain.
                 self.import_dummy_binding(import);
                 let path = import_path_to_string(&import.module_path, &import.subclass);
-                let error = ResolutionError::UnresolvedImport(Some((&path, &help)));
-                resolve_error(self.resolver, span, error);
+                let error = ResolutionError::UnresolvedImport(Some((&path, &err)));
+                resolve_error(self.resolver, import.span, error);
             }
         }
 
@@ -486,23 +481,9 @@ impl<'a, 'b:'a> ImportResolver<'a, 'b> {
         }
     }
 
-    // Define a "dummy" resolution containing a Def::Err as a placeholder for a
-    // failed resolution
-    fn import_dummy_binding(&mut self, directive: &'b ImportDirective<'b>) {
-        if let SingleImport { target, .. } = directive.subclass {
-            let dummy_binding = self.dummy_binding;
-            let dummy_binding = self.import(dummy_binding, directive);
-            let _ = self.try_define(directive.parent, target, ValueNS, dummy_binding.clone());
-            let _ = self.try_define(directive.parent, target, TypeNS, dummy_binding);
-        }
-    }
-
-    /// Attempts to resolve the given import. The return value indicates
-    /// failure if we're certain the name does not exist, indeterminate if we
-    /// don't know whether the name exists at the moment due to other
-    /// currently-unresolved imports, or success if we know the name exists.
+    /// Attempts to resolve the given import, returning true if its resolution is determined.
     /// If successful, the resolved bindings are written into the module.
-    fn resolve_import(&mut self, directive: &'b ImportDirective<'b>) -> ResolveResult<()> {
+    fn resolve_import(&mut self, directive: &'b ImportDirective<'b>) -> bool {
         debug!("(resolving import for module) resolving import `{}::...` in `{}`",
                names_to_string(&directive.module_path),
                module_to_string(self.current_module));
@@ -515,219 +496,231 @@ impl<'a, 'b:'a> ImportResolver<'a, 'b> {
             let vis = directive.vis.get();
             // For better failure detection, pretend that the import will not define any names
             // while resolving its module path.
-            directive.vis.set(ty::Visibility::PrivateExternal);
-            let result =
-                self.resolve_module_path(&directive.module_path, DontUseLexicalScope, None);
+            directive.vis.set(ty::Visibility::Invisible);
+            let result = self.resolve_path(&directive.module_path, None, None);
             directive.vis.set(vis);
 
             match result {
-                Success(module) => module,
-                Indeterminate => return Indeterminate,
-                Failed(err) => return Failed(err),
+                PathResult::Module(module) => module,
+                PathResult::Indeterminate => return false,
+                _ => return true,
             }
         };
 
         directive.imported_module.set(Some(module));
-        let (source, target, value_result, type_result) = match directive.subclass {
-            SingleImport { source, target, ref value_result, ref type_result } =>
-                (source, target, value_result, type_result),
+        let (source, target, result, type_ns_only) = match directive.subclass {
+            SingleImport { source, target, ref result, type_ns_only } =>
+                (source, target, result, type_ns_only),
             GlobImport { .. } => {
                 self.resolve_glob_import(directive);
-                return Success(());
+                return true;
             }
+            _ => unreachable!(),
         };
 
         let mut indeterminate = false;
-        for &(ns, result) in &[(ValueNS, value_result), (TypeNS, type_result)] {
-            if let Err(Undetermined) = result.get() {
-                result.set({
-                    match self.resolve_name_in_module(module, source, ns, false, None) {
-                        Success(binding) => Ok(binding),
-                        Indeterminate => Err(Undetermined),
-                        Failed(_) => Err(Determined),
-                    }
-                });
+        self.per_ns(|this, ns| if !type_ns_only || ns == TypeNS {
+            if let Err(Undetermined) = result[ns].get() {
+                result[ns].set(this.resolve_ident_in_module(module, source, ns, false, None));
             } else {
-                continue
+                return
             };
 
-            match result.get() {
+            let parent = directive.parent;
+            match result[ns].get() {
                 Err(Undetermined) => indeterminate = true,
                 Err(Determined) => {
-                    self.update_resolution(directive.parent, target, ns, |_, resolution| {
+                    this.update_resolution(parent, target, ns, |_, resolution| {
                         resolution.single_imports.directive_failed()
                     });
                 }
                 Ok(binding) if !binding.is_importable() => {
                     let msg = format!("`{}` is not directly importable", target);
-                    struct_span_err!(self.session, directive.span, E0253, "{}", &msg)
+                    struct_span_err!(this.session, directive.span, E0253, "{}", &msg)
                         .span_label(directive.span, &format!("cannot be imported directly"))
                         .emit();
                     // Do not import this illegal binding. Import a dummy binding and pretend
                     // everything is fine
-                    self.import_dummy_binding(directive);
-                    return Success(());
+                    this.import_dummy_binding(directive);
                 }
                 Ok(binding) => {
-                    let imported_binding = self.import(binding, directive);
-                    let conflict = self.try_define(directive.parent, target, ns, imported_binding);
+                    let imported_binding = this.import(binding, directive);
+                    let conflict = this.try_define(parent, target, ns, imported_binding);
                     if let Err(old_binding) = conflict {
-                        let binding = &self.import(binding, directive);
-                        self.report_conflict(directive.parent, target, ns, binding, old_binding);
+                        this.report_conflict(parent, target, ns, imported_binding, old_binding);
                     }
                 }
             }
-        }
+        });
 
-        if indeterminate { Indeterminate } else { Success(()) }
+        !indeterminate
     }
 
-    fn finalize_import(&mut self, directive: &'b ImportDirective<'b>) -> ResolveResult<()> {
+    // If appropriate, returns an error to report.
+    fn finalize_import(&mut self, directive: &'b ImportDirective<'b>) -> Option<String> {
         self.current_module = directive.parent;
 
         let ImportDirective { ref module_path, span, .. } = *directive;
-        let module_result = self.resolve_module_path(&module_path, DontUseLexicalScope, Some(span));
+        let module_result = self.resolve_path(&module_path, None, Some(span));
         let module = match module_result {
-            Success(module) => module,
-            Indeterminate => return Indeterminate,
-            Failed(err) => {
-                let self_module = self.module_map[&self.current_module.normal_ancestor_id.unwrap()];
-
-                let resolve_from_self_result = self.resolve_module_path_from_root(
-                    &self_module, &module_path, 0, Some(span));
-
-                return if let Success(_) = resolve_from_self_result {
-                    let msg = format!("Did you mean `self::{}`?", &names_to_string(module_path));
-                    Failed(Some((span, msg)))
+            PathResult::Module(module) => module,
+            PathResult::Failed(msg, _) => {
+                let (mut self_path, mut self_result) = (module_path.clone(), None);
+                if !self_path.is_empty() && !token::Ident(self_path[0]).is_path_segment_keyword() {
+                    self_path[0].name = keywords::SelfValue.name();
+                    self_result = Some(self.resolve_path(&self_path, None, None));
+                }
+                return if let Some(PathResult::Module(..)) = self_result {
+                    Some(format!("Did you mean `{}`?", names_to_string(&self_path)))
                 } else {
-                    Failed(err)
+                    Some(msg)
                 };
             },
+            _ => return None,
         };
 
-        let (name, value_result, type_result) = match directive.subclass {
-            SingleImport { source, ref value_result, ref type_result, .. } =>
-                (source, value_result.get(), type_result.get()),
+        let (ident, result, type_ns_only) = match directive.subclass {
+            SingleImport { source, ref result, type_ns_only, .. } => (source, result, type_ns_only),
             GlobImport { .. } if module.def_id() == directive.parent.def_id() => {
                 // Importing a module into itself is not allowed.
-                let msg = "Cannot glob-import a module into itself.".into();
-                return Failed(Some((directive.span, msg)));
+                return Some("Cannot glob-import a module into itself.".to_string());
             }
             GlobImport { is_prelude, ref max_vis } => {
                 if !is_prelude &&
-                   max_vis.get() != ty::Visibility::PrivateExternal && // Allow empty globs.
-                   !max_vis.get().is_at_least(directive.vis.get(), self) {
+                   max_vis.get() != ty::Visibility::Invisible && // Allow empty globs.
+                   !max_vis.get().is_at_least(directive.vis.get(), &*self) {
                     let msg = "A non-empty glob must import something with the glob's visibility";
                     self.session.span_err(directive.span, msg);
                 }
-                return Success(());
+                return None;
             }
+            _ => unreachable!(),
         };
 
-        for &(ns, result) in &[(ValueNS, value_result), (TypeNS, type_result)] {
-            if let Ok(binding) = result {
-                if self.record_use(name, ns, binding, directive.span) {
-                    self.resolution(module, name, ns).borrow_mut().binding =
-                        Some(self.dummy_binding);
+        let mut all_ns_err = true;
+        let mut legacy_self_import = None;
+        self.per_ns(|this, ns| if !type_ns_only || ns == TypeNS {
+            if let Ok(binding) = result[ns].get() {
+                all_ns_err = false;
+                if this.record_use(ident, ns, binding, directive.span) {
+                    this.resolution(module, ident, ns).borrow_mut().binding =
+                        Some(this.dummy_binding);
                 }
             }
-        }
+        } else if let Ok(binding) = this.resolve_ident_in_module(module, ident, ns, false, None) {
+            legacy_self_import = Some(directive);
+            let binding = this.arenas.alloc_name_binding(NameBinding {
+                kind: NameBindingKind::Import {
+                    binding: binding,
+                    directive: directive,
+                    used: Cell::new(false),
+                    legacy_self_import: true,
+                },
+                ..*binding
+            });
+            let _ = this.try_define(directive.parent, ident, ns, binding);
+        });
 
-        if value_result.is_err() && type_result.is_err() {
-            let (value_result, type_result);
-            value_result = self.resolve_name_in_module(module, name, ValueNS, false, Some(span));
-            type_result = self.resolve_name_in_module(module, name, TypeNS, false, Some(span));
+        if all_ns_err {
+            if let Some(directive) = legacy_self_import {
+                self.warn_legacy_self_import(directive);
+                return None;
+            }
+            let mut all_ns_failed = true;
+            self.per_ns(|this, ns| if !type_ns_only || ns == TypeNS {
+                match this.resolve_ident_in_module(module, ident, ns, false, Some(span)) {
+                    Ok(_) => all_ns_failed = false,
+                    _ => {}
+                }
+            });
 
-            return if let (Failed(_), Failed(_)) = (value_result, type_result) {
+            return if all_ns_failed {
                 let resolutions = module.resolutions.borrow();
-                let names = resolutions.iter().filter_map(|(&(ref n, _), resolution)| {
-                    if *n == name { return None; } // Never suggest the same name
+                let names = resolutions.iter().filter_map(|(&(ref i, _), resolution)| {
+                    if *i == ident { return None; } // Never suggest the same name
                     match *resolution.borrow() {
-                        NameResolution { binding: Some(_), .. } => Some(n),
+                        NameResolution { binding: Some(name_binding), .. } => {
+                            match name_binding.kind {
+                                NameBindingKind::Import { binding, .. } => {
+                                    match binding.kind {
+                                        // Never suggest the name that has binding error
+                                        // i.e. the name that cannot be previously resolved
+                                        NameBindingKind::Def(Def::Err) => return None,
+                                        _ => Some(&i.name),
+                                    }
+                                },
+                                _ => Some(&i.name),
+                            }
+                        },
                         NameResolution { single_imports: SingleImports::None, .. } => None,
-                        _ => Some(n),
+                        _ => Some(&i.name),
                     }
                 });
-                let lev_suggestion = match find_best_match_for_name(names, &name.as_str(), None) {
-                    Some(name) => format!(". Did you mean to use `{}`?", name),
-                    None => "".to_owned(),
-                };
+                let lev_suggestion =
+                    match find_best_match_for_name(names, &ident.name.as_str(), None) {
+                        Some(name) => format!(". Did you mean to use `{}`?", name),
+                        None => "".to_owned(),
+                    };
                 let module_str = module_to_string(module);
                 let msg = if &module_str == "???" {
-                    format!("no `{}` in the root{}", name, lev_suggestion)
+                    format!("no `{}` in the root{}", ident, lev_suggestion)
                 } else {
-                    format!("no `{}` in `{}`{}", name, module_str, lev_suggestion)
+                    format!("no `{}` in `{}`{}", ident, module_str, lev_suggestion)
                 };
-                Failed(Some((directive.span, msg)))
+                Some(msg)
             } else {
-                // `resolve_name_in_module` reported a privacy error.
+                // `resolve_ident_in_module` reported a privacy error.
                 self.import_dummy_binding(directive);
-                Success(())
+                None
             }
         }
 
-        let session = self.session;
-        let reexport_error = || {
-            let msg = format!("`{}` is private, and cannot be reexported", name);
-            let note_msg =
-                format!("consider marking `{}` as `pub` in the imported module", name);
-            struct_span_err!(session, directive.span, E0364, "{}", &msg)
-                .span_note(directive.span, &note_msg)
-                .emit();
-        };
-
-        let extern_crate_lint = || {
-            let msg = format!("extern crate `{}` is private, and cannot be reexported \
-                               (error E0364), consider declaring with `pub`",
-                               name);
-            session.add_lint(PRIVATE_IN_PUBLIC, directive.id, directive.span, msg);
-        };
-
-        match (value_result, type_result) {
-            // With `#![feature(item_like_imports)]`, all namespaces
-            // must be re-exported with extra visibility for an error to occur.
-            (Ok(value_binding), Ok(type_binding)) if self.new_import_semantics => {
+        let mut reexport_error = None;
+        let mut any_successful_reexport = false;
+        self.per_ns(|this, ns| {
+            if let Ok(binding) = result[ns].get() {
                 let vis = directive.vis.get();
-                if !value_binding.pseudo_vis().is_at_least(vis, self) &&
-                   !type_binding.pseudo_vis().is_at_least(vis, self) {
-                    reexport_error();
-                } else if type_binding.is_extern_crate() &&
-                          !type_binding.vis.is_at_least(vis, self) {
-                    extern_crate_lint();
-                }
-            }
-
-            (Ok(binding), _) if !binding.pseudo_vis().is_at_least(directive.vis.get(), self) => {
-                reexport_error();
-            }
-
-            (_, Ok(binding)) if !binding.pseudo_vis().is_at_least(directive.vis.get(), self) => {
-                if binding.is_extern_crate() {
-                    extern_crate_lint();
+                if !binding.pseudo_vis().is_at_least(vis, &*this) {
+                    reexport_error = Some((ns, binding));
                 } else {
-                    struct_span_err!(self.session, directive.span, E0365,
-                                     "`{}` is private, and cannot be reexported", name)
-                        .span_label(directive.span, &format!("reexport of private `{}`", name))
-                        .note(&format!("consider declaring type or module `{}` with `pub`", name))
-                        .emit();
+                    any_successful_reexport = true;
                 }
             }
+        });
 
-            _ => {}
+        // All namespaces must be re-exported with extra visibility for an error to occur.
+        if !any_successful_reexport {
+            let (ns, binding) = reexport_error.unwrap();
+            if ns == TypeNS && binding.is_extern_crate() {
+                let msg = format!("extern crate `{}` is private, and cannot be reexported \
+                                   (error E0364), consider declaring with `pub`",
+                                   ident);
+                self.session.add_lint(PRIVATE_IN_PUBLIC, directive.id, directive.span, msg);
+            } else if ns == TypeNS {
+                struct_span_err!(self.session, directive.span, E0365,
+                                 "`{}` is private, and cannot be reexported", ident)
+                    .span_label(directive.span, &format!("reexport of private `{}`", ident))
+                    .note(&format!("consider declaring type or module `{}` with `pub`", ident))
+                    .emit();
+            } else {
+                let msg = format!("`{}` is private, and cannot be reexported", ident);
+                let note_msg =
+                    format!("consider marking `{}` as `pub` in the imported module", ident);
+                struct_span_err!(self.session, directive.span, E0364, "{}", &msg)
+                    .span_note(directive.span, &note_msg)
+                    .emit();
+            }
         }
 
         // Record what this import resolves to for later uses in documentation,
         // this may resolve to either a value or a type, but for documentation
         // purposes it's good enough to just favor one over the other.
-        let def = match type_result.ok().map(NameBinding::def) {
-            Some(def) => def,
-            None => value_result.ok().map(NameBinding::def).unwrap(),
-        };
-        let path_resolution = PathResolution::new(def);
-        self.def_map.insert(directive.id, path_resolution);
+        self.per_ns(|this, ns| if let Some(binding) = result[ns].get().ok() {
+            this.def_map.entry(directive.id).or_insert(PathResolution::new(binding.def()));
+        });
 
         debug!("(resolving single import) successfully resolved import");
-        return Success(());
+        None
     }
 
     fn resolve_glob_import(&mut self, directive: &'b ImportDirective<'b>) {
@@ -749,22 +742,18 @@ impl<'a, 'b:'a> ImportResolver<'a, 'b> {
 
         // Ensure that `resolutions` isn't borrowed during `try_define`,
         // since it might get updated via a glob cycle.
-        let bindings = module.resolutions.borrow().iter().filter_map(|(name, resolution)| {
-            resolution.borrow().binding().map(|binding| (*name, binding))
+        let bindings = module.resolutions.borrow().iter().filter_map(|(&ident, resolution)| {
+            resolution.borrow().binding().map(|binding| (ident, binding))
         }).collect::<Vec<_>>();
-        for ((name, ns), binding) in bindings {
-            if binding.pseudo_vis() == ty::Visibility::Public ||
-               self.new_import_semantics && self.is_accessible(binding.vis) {
+        for ((ident, ns), binding) in bindings {
+            if binding.pseudo_vis() == ty::Visibility::Public || self.is_accessible(binding.vis) {
                 let imported_binding = self.import(binding, directive);
-                let _ = self.try_define(directive.parent, name, ns, imported_binding);
+                let _ = self.try_define(directive.parent, ident, ns, imported_binding);
             }
         }
 
         // Record the destination of this import
-        if let Some(did) = module.def_id() {
-            let resolution = PathResolution::new(Def::Mod(did));
-            self.def_map.insert(directive.id, resolution);
-        }
+        self.record_def(directive.id, PathResolution::new(module.def().unwrap()));
     }
 
     // Miscellaneous post-processing, including recording reexports, reporting conflicts,
@@ -774,43 +763,61 @@ impl<'a, 'b:'a> ImportResolver<'a, 'b> {
         *module.globs.borrow_mut() = Vec::new();
 
         let mut reexports = Vec::new();
-        for (&(name, ns), resolution) in module.resolutions.borrow().iter() {
-            let resolution = resolution.borrow();
+        if module as *const _ == self.graph_root as *const _ {
+            let mut exported_macro_names = FxHashSet();
+            for export in mem::replace(&mut self.macro_exports, Vec::new()).into_iter().rev() {
+                if exported_macro_names.insert(export.name) {
+                    reexports.push(export);
+                }
+            }
+        }
+
+        for (&(ident, ns), resolution) in module.resolutions.borrow().iter() {
+            let resolution = &mut *resolution.borrow_mut();
             let binding = match resolution.binding {
                 Some(binding) => binding,
                 None => continue,
             };
 
-            // Report conflicts
-            if !self.new_import_semantics {
-                for duplicate_glob in resolution.duplicate_globs.iter() {
-                    // FIXME #31337: We currently allow items to shadow glob-imported re-exports.
-                    if !binding.is_import() {
-                        if let NameBindingKind::Import { binding, .. } = duplicate_glob.kind {
-                            if binding.is_import() { continue }
-                        }
-                    }
-
-                    self.report_conflict(module, name, ns, duplicate_glob, binding);
-                }
-            }
-
             if binding.vis == ty::Visibility::Public &&
                (binding.is_import() || binding.is_extern_crate()) {
                 let def = binding.def();
                 if def != Def::Err {
-                    reexports.push(Export { name: name, def_id: def.def_id() });
+                    if !def.def_id().is_local() {
+                        self.session.cstore.export_macros(def.def_id().krate);
+                    }
+                    reexports.push(Export { name: ident.name, def: def });
                 }
             }
 
-            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) {
-                    let msg = format!("variant `{}` is private, and cannot be reexported \
-                                       (error E0364), consider declaring its enum as `pub`",
-                                      name);
-                    self.session.add_lint(PRIVATE_IN_PUBLIC, directive.id, binding.span, msg);
+            match binding.kind {
+                NameBindingKind::Import { binding: orig_binding, directive, .. } => {
+                    if ns == TypeNS && orig_binding.is_variant() &&
+                       !orig_binding.vis.is_at_least(binding.vis, &*self) {
+                        let msg = format!("variant `{}` is private, and cannot be reexported \
+                                           (error E0364), consider declaring its enum as `pub`",
+                                          ident);
+                        self.session.add_lint(PRIVATE_IN_PUBLIC, directive.id, binding.span, msg);
+                    }
+                }
+                NameBindingKind::Ambiguity { b1, b2, .. }
+                        if b1.is_glob_import() && b2.is_glob_import() => {
+                    let (orig_b1, orig_b2) = match (&b1.kind, &b2.kind) {
+                        (&NameBindingKind::Import { binding: b1, .. },
+                         &NameBindingKind::Import { binding: b2, .. }) => (b1, b2),
+                        _ => continue,
+                    };
+                    let (b1, b2) = match (orig_b1.vis, orig_b2.vis) {
+                        (ty::Visibility::Public, ty::Visibility::Public) => continue,
+                        (ty::Visibility::Public, _) => (b1, b2),
+                        (_, ty::Visibility::Public) => (b2, b1),
+                        _ => continue,
+                    };
+                    resolution.binding = Some(self.arenas.alloc_name_binding(NameBinding {
+                        kind: NameBindingKind::Ambiguity { b1: b1, b2: b2, legacy: true }, ..*b1
+                    }));
                 }
+                _ => {}
             }
         }
 
@@ -823,7 +830,9 @@ impl<'a, 'b:'a> ImportResolver<'a, 'b> {
     }
 }
 
-fn import_path_to_string(names: &[Name], subclass: &ImportDirectiveSubclass) -> String {
+fn import_path_to_string(names: &[Ident], subclass: &ImportDirectiveSubclass) -> String {
+    let global = !names.is_empty() && names[0].name == keywords::CrateRoot.name();
+    let names = if global { &names[1..] } else { names };
     if names.is_empty() {
         import_directive_subclass_to_string(subclass)
     } else {
@@ -838,5 +847,7 @@ fn import_directive_subclass_to_string(subclass: &ImportDirectiveSubclass) -> St
     match *subclass {
         SingleImport { source, .. } => source.to_string(),
         GlobImport { .. } => "*".to_string(),
+        ExternCrate => "<extern crate>".to_string(),
+        MacroUse => "#[macro_use]".to_string(),
     }
 }