]> git.lizzy.rs Git - rust.git/blobdiff - src/librustc_resolve/resolve_imports.rs
Refactor away separate tracking of used_public and used_reexport.
[rust.git] / src / librustc_resolve / resolve_imports.rs
index 364218d84137cf0648801f185743b31899e7eade..54dcd0001c4a5ee409be361f19af8874d7fafde4 100644 (file)
 use DefModifiers;
 use Module;
 use Namespace::{self, TypeNS, ValueNS};
-use {NameBindings, NameBinding};
-use NamespaceResult::{BoundResult, UnboundResult, UnknownResult};
-use NamespaceResult;
+use {NameBinding, NameBindingKind};
 use ResolveResult;
+use ResolveResult::*;
 use Resolver;
 use UseLexicalScopeFlag;
 use {names_to_string, module_to_string};
@@ -51,7 +50,7 @@ pub enum Shadowable {
 }
 
 /// One import directive.
-#[derive(Debug)]
+#[derive(Debug,Clone)]
 pub struct ImportDirective {
     pub module_path: Vec<Name>,
     pub subclass: ImportDirectiveSubclass,
@@ -78,89 +77,78 @@ pub fn new(module_path: Vec<Name>,
             shadowable: shadowable,
         }
     }
-}
 
-/// The item that an import resolves to.
-#[derive(Clone,Debug)]
-pub struct Target<'a> {
-    pub target_module: Module<'a>,
-    pub binding: NameBinding<'a>,
-    pub shadowable: Shadowable,
-}
+    // Given the binding to which this directive resolves in a particular namespace,
+    // this returns the binding for the name this directive defines in that namespace.
+    fn import<'a>(&self, binding: &'a NameBinding<'a>) -> NameBinding<'a> {
+        let mut modifiers = match self.is_public {
+            true => DefModifiers::PUBLIC | DefModifiers::IMPORTABLE,
+            false => DefModifiers::empty(),
+        };
+        if let GlobImport = self.subclass {
+            modifiers = modifiers | DefModifiers::GLOB_IMPORTED;
+        }
+        if self.shadowable == Shadowable::Always {
+            modifiers = modifiers | DefModifiers::PRELUDE;
+        }
 
-impl<'a> Target<'a> {
-    pub fn new(target_module: Module<'a>, binding: NameBinding<'a>, shadowable: Shadowable)
-               -> Self {
-        Target {
-            target_module: target_module,
-            binding: binding,
-            shadowable: shadowable,
+        NameBinding {
+            kind: NameBindingKind::Import { binding: binding, id: self.id },
+            span: Some(self.span),
+            modifiers: modifiers,
         }
     }
 }
 
 #[derive(Debug)]
-/// An ImportResolutionPerNamespace records what we know about an imported name.
+/// An ImportResolution records what we know about an imported name in a given namespace.
 /// More specifically, it records the number of unresolved `use` directives that import the name,
-/// and for each namespace, it records the `use` directive importing the name in the namespace
-/// and the `Target` to which the name in the namespace resolves (if applicable).
+/// the `use` directive importing the name in the namespace, and the `NameBinding` to which the
+/// name in the namespace resolves (if applicable).
 /// Different `use` directives may import the same name in different namespaces.
-pub struct ImportResolutionPerNamespace<'a> {
+pub struct ImportResolution<'a> {
     // When outstanding_references reaches zero, outside modules can count on the targets being
     // correct. Before then, all bets are off; future `use` directives could override the name.
     // Since shadowing is forbidden, the only way outstanding_references > 1 in a legal program
     // is if the name is imported by exactly two `use` directives, one of which resolves to a
     // value and the other of which resolves to a type.
     pub outstanding_references: usize,
-    pub type_ns: ImportResolution<'a>,
-    pub value_ns: ImportResolution<'a>,
-}
 
-/// Records what we know about an imported name in a namespace (see `ImportResolutionPerNamespace`).
-#[derive(Clone,Debug)]
-pub struct ImportResolution<'a> {
-    /// Whether the name in the namespace was imported with a `use` or a `pub use`.
+    /// Whether this resolution came from a `use` or a `pub use`.
     pub is_public: bool,
 
     /// Resolution of the name in the namespace
-    pub target: Option<Target<'a>>,
+    pub binding: Option<&'a NameBinding<'a>>,
 
     /// The source node of the `use` directive
     pub id: NodeId,
 }
 
-impl<'a> ::std::ops::Index<Namespace> for ImportResolutionPerNamespace<'a> {
-    type Output = ImportResolution<'a>;
-    fn index(&self, ns: Namespace) -> &ImportResolution<'a> {
-        match ns { TypeNS => &self.type_ns, ValueNS => &self.value_ns }
-    }
-}
-
-impl<'a> ::std::ops::IndexMut<Namespace> for ImportResolutionPerNamespace<'a> {
-    fn index_mut(&mut self, ns: Namespace) -> &mut ImportResolution<'a> {
-        match ns { TypeNS => &mut self.type_ns, ValueNS => &mut self.value_ns }
-    }
-}
-
-impl<'a> ImportResolutionPerNamespace<'a> {
+impl<'a> ImportResolution<'a> {
     pub fn new(id: NodeId, is_public: bool) -> Self {
-        let resolution = ImportResolution { id: id, is_public: is_public, target: None };
-        ImportResolutionPerNamespace {
-            outstanding_references: 0, type_ns: resolution.clone(), value_ns: resolution,
+        ImportResolution {
+            outstanding_references: 0,
+            id: id,
+            binding: None,
+            is_public: is_public,
         }
     }
 
-    pub fn shadowable(&self, namespace: Namespace) -> Shadowable {
-        match self[namespace].target {
-            Some(ref target) => target.shadowable,
+    pub fn shadowable(&self) -> Shadowable {
+        match self.binding {
+            Some(binding) if binding.defined_with(DefModifiers::PRELUDE) =>
+                Shadowable::Always,
+            Some(_) => Shadowable::Never,
             None => Shadowable::Always,
         }
     }
 }
 
-struct ImportResolvingError {
+struct ImportResolvingError<'a> {
+    /// Module where the error happened
+    source_module: Module<'a>,
+    import_directive: ImportDirective,
     span: Span,
-    path: String,
     help: String,
 }
 
@@ -199,9 +187,7 @@ fn resolve_imports(&mut self) {
                 // resolving failed
                 if errors.len() > 0 {
                     for e in errors {
-                        resolve_error(self.resolver,
-                                      e.span,
-                                      ResolutionError::UnresolvedImport(Some((&e.path, &e.help))));
+                        self.import_resolving_error(e)
                     }
                 } else {
                     // Report unresolved imports only if no hard error was already reported
@@ -218,11 +204,49 @@ fn resolve_imports(&mut self) {
         }
     }
 
+    /// Resolves an `ImportResolvingError` into the correct enum discriminant
+    /// and passes that on to `resolve_error`.
+    fn import_resolving_error(&self, e: ImportResolvingError<'b>) {
+        // If it's a single failed import then create a "fake" import
+        // resolution for it so that later resolve stages won't complain.
+        if let SingleImport(target, _) = e.import_directive.subclass {
+            let mut import_resolutions = e.source_module.import_resolutions.borrow_mut();
+
+            let resolution = import_resolutions.entry((target, ValueNS)).or_insert_with(|| {
+                debug!("(resolving import error) adding import resolution for `{}`",
+                       target);
+
+                ImportResolution::new(e.import_directive.id,
+                                      e.import_directive.is_public)
+            });
+
+            if resolution.binding.is_none() {
+                debug!("(resolving import error) adding fake target to import resolution of `{}`",
+                       target);
+
+                let dummy_binding = self.resolver.new_name_binding(NameBinding {
+                    modifiers: DefModifiers::IMPORTABLE,
+                    kind: NameBindingKind::Def(Def::Err),
+                    span: None,
+                });
+
+                resolution.binding = Some(dummy_binding);
+            }
+        }
+
+        let path = import_path_to_string(&e.import_directive.module_path,
+                                         e.import_directive.subclass);
+
+        resolve_error(self.resolver,
+                      e.span,
+                      ResolutionError::UnresolvedImport(Some((&path, &e.help))));
+    }
+
     /// Attempts to resolve imports for the given module and all of its
     /// submodules.
     fn resolve_imports_for_module_subtree(&mut self,
                                           module_: Module<'b>)
-                                          -> Vec<ImportResolvingError> {
+                                          -> Vec<ImportResolvingError<'b>> {
         let mut errors = Vec::new();
         debug!("(resolving imports for module subtree) resolving {}",
                module_to_string(&*module_));
@@ -230,9 +254,9 @@ fn resolve_imports_for_module_subtree(&mut self,
         errors.extend(self.resolve_imports_for_module(module_));
         self.resolver.current_module = orig_module;
 
-        build_reduced_graph::populate_module_if_necessary(self.resolver, &module_);
-        for (_, child_node) in module_.children.borrow().iter() {
-            match child_node.type_ns.module() {
+        build_reduced_graph::populate_module_if_necessary(self.resolver, module_);
+        module_.for_each_local_child(|_, _, child_node| {
+            match child_node.module() {
                 None => {
                     // Nothing to do.
                 }
@@ -240,7 +264,7 @@ fn resolve_imports_for_module_subtree(&mut self,
                     errors.extend(self.resolve_imports_for_module_subtree(child_module));
                 }
             }
-        }
+        });
 
         for (_, child_module) in module_.anonymous_children.borrow().iter() {
             errors.extend(self.resolve_imports_for_module_subtree(child_module));
@@ -250,7 +274,7 @@ fn resolve_imports_for_module_subtree(&mut self,
     }
 
     /// Attempts to resolve imports for the given module only.
-    fn resolve_imports_for_module(&mut self, module: Module<'b>) -> Vec<ImportResolvingError> {
+    fn resolve_imports_for_module(&mut self, module: Module<'b>) -> Vec<ImportResolvingError<'b>> {
         let mut errors = Vec::new();
 
         if module.all_imports_resolved() {
@@ -272,9 +296,9 @@ fn resolve_imports_for_module(&mut self, module: Module<'b>) -> Vec<ImportResolv
                         None => (import_directive.span, String::new()),
                     };
                     errors.push(ImportResolvingError {
+                        source_module: module,
+                        import_directive: import_directive.clone(),
                         span: span,
-                        path: import_path_to_string(&import_directive.module_path,
-                                                    import_directive.subclass),
                         help: help,
                     });
                 }
@@ -305,92 +329,107 @@ fn resolve_import_for_module(&mut self,
                                  module_: Module<'b>,
                                  import_directive: &ImportDirective)
                                  -> ResolveResult<()> {
-        let mut resolution_result = ResolveResult::Failed(None);
-        let module_path = &import_directive.module_path;
-
         debug!("(resolving import for module) resolving import `{}::...` in `{}`",
-               names_to_string(&module_path[..]),
+               names_to_string(&import_directive.module_path),
                module_to_string(&*module_));
 
-        // First, resolve the module path for the directive, if necessary.
-        let container = if module_path.is_empty() {
-            // Use the crate root.
-            Some((self.resolver.graph_root, LastMod(AllPublic)))
-        } else {
-            match self.resolver.resolve_module_path(module_,
-                                                    &module_path[..],
-                                                    UseLexicalScopeFlag::DontUseLexicalScope,
-                                                    import_directive.span) {
-                ResolveResult::Failed(err) => {
-                    resolution_result = ResolveResult::Failed(err);
-                    None
-                }
-                ResolveResult::Indeterminate => {
-                    resolution_result = ResolveResult::Indeterminate;
-                    None
-                }
-                ResolveResult::Success(container) => Some(container),
-            }
-        };
-
-        match container {
-            None => {}
-            Some((containing_module, lp)) => {
+        self.resolver
+            .resolve_module_path(module_,
+                                 &import_directive.module_path,
+                                 UseLexicalScopeFlag::DontUseLexicalScope,
+                                 import_directive.span)
+            .and_then(|(containing_module, lp)| {
                 // We found the module that the target is contained
                 // within. Attempt to resolve the import within it.
-
-                match import_directive.subclass {
-                    SingleImport(target, source) => {
-                        resolution_result = self.resolve_single_import(&module_,
-                                                                       containing_module,
-                                                                       target,
-                                                                       source,
-                                                                       import_directive,
-                                                                       lp);
-                    }
-                    GlobImport => {
-                        resolution_result = self.resolve_glob_import(&module_,
-                                                                     containing_module,
-                                                                     import_directive,
-                                                                     lp);
-                    }
+                if let SingleImport(target, source) = import_directive.subclass {
+                    self.resolve_single_import(module_,
+                                               containing_module,
+                                               target,
+                                               source,
+                                               import_directive,
+                                               lp)
+                } else {
+                    self.resolve_glob_import(module_, containing_module, import_directive, lp)
                 }
-            }
-        }
-
-        // Decrement the count of unresolved imports.
-        match resolution_result {
-            ResolveResult::Success(()) => {
+            })
+            .and_then(|()| {
+                // Decrement the count of unresolved imports.
                 assert!(self.resolver.unresolved_imports >= 1);
                 self.resolver.unresolved_imports -= 1;
-            }
-            _ => {
-                // Nothing to do here; just return the error.
-            }
-        }
-
-        // Decrement the count of unresolved globs if necessary. But only if
-        // the resolution result is a success -- other cases will
-        // be handled by the main loop.
 
-        if resolution_result.success() {
-            match import_directive.subclass {
-                GlobImport => {
+                if let GlobImport = import_directive.subclass {
                     module_.dec_glob_count();
                     if import_directive.is_public {
                         module_.dec_pub_glob_count();
                     }
                 }
-                SingleImport(..) => {
-                    // Ignore.
+                if import_directive.is_public {
+                    module_.dec_pub_count();
+                }
+                Success(())
+            })
+    }
+
+    /// Resolves the name in the namespace of the module because it is being imported by
+    /// importing_module. Returns the name bindings defining the name.
+    fn resolve_name_in_module(&mut self,
+                              module: Module<'b>, // Module containing the name
+                              name: Name,
+                              ns: Namespace,
+                              importing_module: Module<'b>) // Module importing the name
+                              -> ResolveResult<&'b NameBinding<'b>> {
+        build_reduced_graph::populate_module_if_necessary(self.resolver, module);
+        if let Some(name_binding) = module.get_child(name, ns) {
+            if name_binding.is_extern_crate() {
+                // track the extern crate as used.
+                if let Some(DefId { krate, .. }) = name_binding.module().unwrap().def_id() {
+                    self.resolver.used_crates.insert(krate);
                 }
             }
-            if import_directive.is_public {
-                module_.dec_pub_count();
-            }
+            return Success(name_binding);
+        }
+
+        // If there is an unresolved glob at this point in the containing module, bail out.
+        // We don't know enough to be able to resolve the name.
+        if module.pub_glob_count.get() > 0 {
+            return Indeterminate;
         }
 
-        return resolution_result;
+        match module.import_resolutions.borrow().get(&(name, ns)) {
+            // The containing module definitely doesn't have an exported import with the
+            // name in question. We can therefore accurately report that names are unbound.
+            None => Failed(None),
+
+            // The name is an import which has been fully resolved, so we just follow it.
+            Some(resolution) if resolution.outstanding_references == 0 => {
+                // Import resolutions must be declared with "pub" in order to be exported.
+                if !resolution.is_public {
+                    return Failed(None);
+                }
+
+                if let Some(binding) = resolution.binding {
+                    self.resolver.record_import_use(name, ns, &resolution);
+                    Success(binding)
+                } else {
+                    Failed(None)
+                }
+            }
+
+            // If module is the same module whose import we are resolving and
+            // it has an unresolved import with the same name as `name`, then the user
+            // is actually trying to import an item that is declared in the same scope
+            //
+            // e.g
+            // use self::submodule;
+            // pub mod submodule;
+            //
+            // In this case we continue as if we resolved the import and let
+            // check_for_conflicts_between_imports_and_items handle the conflict
+            Some(_) => match (importing_module.def_id(), module.def_id()) {
+                (Some(id1), Some(id2)) if id1 == id2 => Failed(None),
+                _ => Indeterminate
+            },
+        }
     }
 
     fn resolve_single_import(&mut self,
@@ -420,253 +459,82 @@ fn resolve_single_import(&mut self,
         };
 
         // We need to resolve both namespaces for this to succeed.
-
-        let mut value_result = UnknownResult;
-        let mut type_result = UnknownResult;
-        let mut lev_suggestion = "".to_owned();
-
-        // Search for direct children of the containing module.
-        build_reduced_graph::populate_module_if_necessary(self.resolver, &target_module);
-
-        match target_module.children.borrow().get(&source) {
-            None => {
-                let names = target_module.children.borrow();
-                if let Some(name) = find_best_match_for_name(names.keys(),
-                                                             &source.as_str(),
-                                                             None) {
-                    lev_suggestion = format!(". Did you mean to use `{}`?", name);
-                }
+        let value_result =
+            self.resolve_name_in_module(target_module, source, ValueNS, module_);
+        let type_result =
+            self.resolve_name_in_module(target_module, source, TypeNS, module_);
+
+        match (&value_result, &type_result) {
+            (&Success(name_binding), _) if !name_binding.is_import() &&
+                                           directive.is_public &&
+                                           !name_binding.is_public() => {
+                let msg = format!("`{}` is private, and cannot be reexported", source);
+                let note_msg = format!("Consider marking `{}` as `pub` in the imported module",
+                                        source);
+                struct_span_err!(self.resolver.session, directive.span, E0364, "{}", &msg)
+                    .span_note(directive.span, &note_msg)
+                    .emit();
             }
-            Some(ref child_name_bindings) => {
-                // pub_err makes sure we don't give the same error twice.
-                let mut pub_err = false;
-                if child_name_bindings.value_ns.defined() {
-                    debug!("(resolving single import) found value binding");
-                    value_result = BoundResult(target_module,
-                                               child_name_bindings.value_ns.clone());
-                    if directive.is_public && !child_name_bindings.value_ns.is_public() {
-                        let msg = format!("`{}` is private, and cannot be reexported", source);
-                        let note_msg = format!("Consider marking `{}` as `pub` in the imported \
-                                                module",
-                                               source);
-                        struct_span_err!(self.resolver.session, directive.span, E0364, "{}", &msg)
-                            .span_note(directive.span, &note_msg)
-                            .emit();
-                        pub_err = true;
-                    }
-                    if directive.is_public && child_name_bindings.value_ns.
-                                              defined_with(DefModifiers::PRIVATE_VARIANT) {
-                        let msg = format!("variant `{}` is private, and cannot be reexported ( \
-                                           error E0364), consider declaring its enum as `pub`",
-                                           source);
-                        self.resolver.session.add_lint(lint::builtin::PRIVATE_IN_PUBLIC,
-                                                       directive.id,
-                                                       directive.span,
-                                                       msg);
-                        pub_err = true;
-                    }
-                }
-                if child_name_bindings.type_ns.defined() {
-                    debug!("(resolving single import) found type binding");
-                    type_result = BoundResult(target_module,
-                                              child_name_bindings.type_ns.clone());
-                    if !pub_err && directive.is_public &&
-                       !child_name_bindings.type_ns.is_public() {
-                        let msg = format!("`{}` is private, and cannot be reexported", source);
-                        let note_msg = format!("Consider declaring module `{}` as a `pub mod`",
-                                               source);
-                        struct_span_err!(self.resolver.session, directive.span, E0365, "{}", &msg)
-                            .span_note(directive.span, &note_msg)
-                            .emit();
-                    }
-                    if !pub_err && directive.is_public && child_name_bindings.type_ns.
-                                                    defined_with(DefModifiers::PRIVATE_VARIANT) {
-                        let msg = format!("variant `{}` is private, and cannot be reexported ( \
-                                           error E0365), consider declaring its enum as `pub`",
-                                           source);
-                        self.resolver.session.add_lint(lint::builtin::PRIVATE_IN_PUBLIC,
-                                                       directive.id,
-                                                       directive.span,
-                                                       msg);
-                    }
-                }
-            }
-        }
-
-        // Unless we managed to find a result in both namespaces (unlikely),
-        // search imports as well.
-        let mut value_used_reexport = false;
-        let mut type_used_reexport = false;
-        match (value_result.clone(), type_result.clone()) {
-            (BoundResult(..), BoundResult(..)) => {} // Continue.
-            _ => {
-                // If there is an unresolved glob at this point in the
-                // containing module, bail out. We don't know enough to be
-                // able to resolve this import.
-
-                if target_module.pub_glob_count.get() > 0 {
-                    debug!("(resolving single import) unresolved pub glob; bailing out");
-                    return ResolveResult::Indeterminate;
-                }
-
-                // Now search the exported imports within the containing module.
-                match target_module.import_resolutions.borrow().get(&source) {
-                    None => {
-                        debug!("(resolving single import) no import");
-                        // The containing module definitely doesn't have an
-                        // exported import with the name in question. We can
-                        // therefore accurately report that the names are
-                        // unbound.
-
-                        if lev_suggestion.is_empty() {  // skip if we already have a suggestion
-                            let names = target_module.import_resolutions.borrow();
-                            if let Some(name) = find_best_match_for_name(names.keys(),
-                                                                         &source.as_str(),
-                                                                         None) {
-                                lev_suggestion =
-                                    format!(". Did you mean to use the re-exported import `{}`?",
-                                            name);
-                            }
-                        }
-
-                        if value_result.is_unknown() {
-                            value_result = UnboundResult;
-                        }
-                        if type_result.is_unknown() {
-                            type_result = UnboundResult;
-                        }
-                    }
-                    Some(import_resolution) if import_resolution.outstanding_references == 0 => {
-
-                        fn get_binding<'a>(this: &mut Resolver,
-                                           import_resolution: &ImportResolutionPerNamespace<'a>,
-                                           namespace: Namespace,
-                                           source: Name)
-                                           -> NamespaceResult<'a> {
-
-                            // Import resolutions must be declared with "pub"
-                            // in order to be exported.
-                            if !import_resolution[namespace].is_public {
-                                return UnboundResult;
-                            }
-
-                            match import_resolution[namespace].target.clone() {
-                                None => {
-                                    return UnboundResult;
-                                }
-                                Some(Target {
-                                    target_module,
-                                    binding,
-                                    shadowable: _
-                                }) => {
-                                    debug!("(resolving single import) found import in ns {:?}",
-                                           namespace);
-                                    let id = import_resolution[namespace].id;
-                                    // track used imports and extern crates as well
-                                    this.used_imports.insert((id, namespace));
-                                    this.record_import_use(id, source);
-                                    match target_module.def_id() {
-                                        Some(DefId{krate: kid, ..}) => {
-                                            this.used_crates.insert(kid);
-                                        }
-                                        _ => {}
-                                    }
-                                    return BoundResult(target_module, binding);
-                                }
-                            }
-                        }
-
-                        // The name is an import which has been fully
-                        // resolved. We can, therefore, just follow it.
-                        if value_result.is_unknown() {
-                            value_result = get_binding(self.resolver,
-                                                       import_resolution,
-                                                       ValueNS,
-                                                       source);
-                            value_used_reexport = import_resolution.value_ns.is_public;
-                        }
-                        if type_result.is_unknown() {
-                            type_result = get_binding(self.resolver,
-                                                      import_resolution,
-                                                      TypeNS,
-                                                      source);
-                            type_used_reexport = import_resolution.type_ns.is_public;
-                        }
 
-                    }
-                    Some(_) => {
-                        // If target_module is the same module whose import we are resolving
-                        // and there it has an unresolved import with the same name as `source`,
-                        // then the user is actually trying to import an item that is declared
-                        // in the same scope
-                        //
-                        // e.g
-                        // use self::submodule;
-                        // pub mod submodule;
-                        //
-                        // In this case we continue as if we resolved the import and let the
-                        // check_for_conflicts_between_imports_and_items call below handle
-                        // the conflict
-                        match (module_.def_id(), target_module.def_id()) {
-                            (Some(id1), Some(id2)) if id1 == id2 => {
-                                if value_result.is_unknown() {
-                                    value_result = UnboundResult;
-                                }
-                                if type_result.is_unknown() {
-                                    type_result = UnboundResult;
-                                }
-                            }
-                            _ => {
-                                // The import is unresolved. Bail out.
-                                debug!("(resolving single import) unresolved import; bailing out");
-                                return ResolveResult::Indeterminate;
-                            }
-                        }
-                    }
+            (_, &Success(name_binding)) if !name_binding.is_import() && directive.is_public => {
+                if !name_binding.is_public() {
+                    let msg = format!("`{}` is private, and cannot be reexported", source);
+                    let note_msg =
+                        format!("Consider declaring type or module `{}` with `pub`", source);
+                    struct_span_err!(self.resolver.session, directive.span, E0365, "{}", &msg)
+                        .span_note(directive.span, &note_msg)
+                        .emit();
+                } else if name_binding.defined_with(DefModifiers::PRIVATE_VARIANT) {
+                    let msg = format!("variant `{}` is private, and cannot be reexported \
+                                       (error E0364), consider declaring its enum as `pub`",
+                                       source);
+                    self.resolver.session.add_lint(lint::builtin::PRIVATE_IN_PUBLIC,
+                                                   directive.id,
+                                                   directive.span,
+                                                   msg);
                 }
             }
+
+            _ => {}
         }
 
-        let mut value_used_public = false;
-        let mut type_used_public = false;
-
-        // If we didn't find a result in the type namespace, search the
-        // external modules.
-        match type_result {
-            BoundResult(..) => {}
-            _ => {
-                match target_module.external_module_children.borrow_mut().get(&source) {
-                    None => {} // Continue.
-                    Some(module) => {
-                        debug!("(resolving single import) found external module");
-                        // track the module as used.
-                        match module.def_id() {
-                            Some(DefId{krate: kid, ..}) => {
-                                self.resolver.used_crates.insert(kid);
-                            }
-                            _ => {}
-                        }
-                        let name_binding = NameBinding::create_from_module(module);
-                        type_result = BoundResult(target_module, name_binding);
-                        type_used_public = true;
+        let mut lev_suggestion = "".to_owned();
+        match (&value_result, &type_result) {
+            (&Indeterminate, _) | (_, &Indeterminate) => return Indeterminate,
+            (&Failed(_), &Failed(_)) => {
+                let children = target_module.children.borrow();
+                let names = children.keys().map(|&(ref name, _)| name);
+                if let Some(name) = find_best_match_for_name(names, &source.as_str(), None) {
+                    lev_suggestion = format!(". Did you mean to use `{}`?", name);
+                } else {
+                    let resolutions = target_module.import_resolutions.borrow();
+                    let names = resolutions.keys().map(|&(ref name, _)| name);
+                    if let Some(name) = find_best_match_for_name(names,
+                                                                 &source.as_str(),
+                                                                 None) {
+                        lev_suggestion =
+                            format!(". Did you mean to use the re-exported import `{}`?", name);
                     }
                 }
             }
+            _ => (),
         }
 
         // We've successfully resolved the import. Write the results in.
         let mut import_resolutions = module_.import_resolutions.borrow_mut();
-        let import_resolution = import_resolutions.get_mut(&target).unwrap();
 
         {
-            let mut check_and_write_import = |namespace, result: &_, used_public: &mut bool| {
+            let mut check_and_write_import = |namespace, result| {
+                let result: &ResolveResult<&NameBinding> = result;
+
+                let import_resolution = import_resolutions.get_mut(&(target, namespace)).unwrap();
                 let namespace_name = match namespace {
                     TypeNS => "type",
                     ValueNS => "value",
                 };
 
                 match *result {
-                    BoundResult(ref target_module, ref name_binding) => {
+                    Success(name_binding) => {
                         debug!("(resolving single import) found {:?} target: {:?}",
                                namespace_name,
                                name_binding.def());
@@ -679,67 +547,63 @@ fn get_binding<'a>(this: &mut Resolver,
                                                              directive.span,
                                                              target);
 
-                        import_resolution[namespace] = ImportResolution {
-                            target: Some(Target::new(target_module,
-                                                     name_binding.clone(),
-                                                     directive.shadowable)),
-                            id: directive.id,
-                            is_public: directive.is_public
-                        };
+                        import_resolution.binding =
+                            Some(self.resolver.new_name_binding(directive.import(name_binding)));
+                        import_resolution.id = directive.id;
+                        import_resolution.is_public = directive.is_public;
 
-                        self.add_export(module_, target, &import_resolution[namespace]);
-                        *used_public = name_binding.is_public();
+                        self.add_export(module_, target, &import_resolution);
                     }
-                    UnboundResult => {
+                    Failed(_) => {
                         // Continue.
                     }
-                    UnknownResult => {
+                    Indeterminate => {
                         panic!("{:?} result should be known at this point", namespace_name);
                     }
                 }
+
+                self.check_for_conflicts_between_imports_and_items(module_,
+                                                                   import_resolution,
+                                                                   directive.span,
+                                                                   (target, namespace));
             };
-            check_and_write_import(ValueNS, &value_result, &mut value_used_public);
-            check_and_write_import(TypeNS, &type_result, &mut type_used_public);
+            check_and_write_import(ValueNS, &value_result);
+            check_and_write_import(TypeNS, &type_result);
         }
 
-        self.check_for_conflicts_between_imports_and_items(module_,
-                                                           import_resolution,
-                                                           directive.span,
-                                                           target);
-
-        if value_result.is_unbound() && type_result.is_unbound() {
+        if let (&Failed(_), &Failed(_)) = (&value_result, &type_result) {
             let msg = format!("There is no `{}` in `{}`{}",
                               source,
-                              module_to_string(&target_module), lev_suggestion);
-            return ResolveResult::Failed(Some((directive.span, msg)));
+                              module_to_string(target_module), lev_suggestion);
+            return Failed(Some((directive.span, msg)));
         }
-        let value_used_public = value_used_reexport || value_used_public;
-        let type_used_public = type_used_reexport || type_used_public;
-
-        assert!(import_resolution.outstanding_references >= 1);
-        import_resolution.outstanding_references -= 1;
-
-        // 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 value_def_and_priv = import_resolution.value_ns.target.as_ref().map(|target| {
-            let def = target.binding.def().unwrap();
-            (def,
-             if value_used_public {
-                lp
-            } else {
-                DependsOn(def.def_id())
+
+        let value_def_and_priv = {
+            let import_resolution_value = import_resolutions.get_mut(&(target, ValueNS)).unwrap();
+            assert!(import_resolution_value.outstanding_references >= 1);
+            import_resolution_value.outstanding_references -= 1;
+
+            // 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.
+            import_resolution_value.binding.as_ref().map(|binding| {
+                let def = binding.def().unwrap();
+                let last_private = if binding.is_public() { lp } else { DependsOn(def.def_id()) };
+                (def, last_private)
             })
-        });
-        let type_def_and_priv = import_resolution.type_ns.target.as_ref().map(|target| {
-            let def = target.binding.def().unwrap();
-            (def,
-             if type_used_public {
-                lp
-            } else {
-                DependsOn(def.def_id())
+        };
+
+        let type_def_and_priv = {
+            let import_resolution_type = import_resolutions.get_mut(&(target, TypeNS)).unwrap();
+            assert!(import_resolution_type.outstanding_references >= 1);
+            import_resolution_type.outstanding_references -= 1;
+
+            import_resolution_type.binding.as_ref().map(|binding| {
+                let def = binding.def().unwrap();
+                let last_private = if binding.is_public() { lp } else { DependsOn(def.def_id()) };
+                (def, last_private)
             })
-        });
+        };
 
         let import_lp = LastImport {
             value_priv: value_def_and_priv.map(|(_, p)| p),
@@ -766,7 +630,7 @@ fn get_binding<'a>(this: &mut Resolver,
         }
 
         debug!("(resolving single import) successfully resolved import");
-        return ResolveResult::Success(());
+        return Success(());
     }
 
     // Resolves a glob import. Note that this function cannot fail; it either
@@ -806,45 +670,43 @@ fn resolve_glob_import(&mut self,
                                                "Cannot glob-import a module into itself.".into())));
         }
 
-        for (name, target_import_resolution) in import_resolutions.iter() {
+        for (&(name, ns), target_import_resolution) in import_resolutions.iter() {
             debug!("(resolving glob import) writing module resolution {} into `{}`",
-                   *name,
+                   name,
                    module_to_string(module_));
 
             // Here we merge two import resolutions.
             let mut import_resolutions = module_.import_resolutions.borrow_mut();
-            let mut dest_import_resolution = import_resolutions.entry(*name).or_insert_with(|| {
-                ImportResolutionPerNamespace::new(id, is_public)
-            });
-
-            for &ns in [TypeNS, ValueNS].iter() {
-                match target_import_resolution[ns].target {
-                    Some(ref target) if target_import_resolution[ns].is_public => {
-                        self.check_for_conflicting_import(&dest_import_resolution,
-                                                          import_directive.span,
-                                                          *name,
-                                                          ns);
-                        dest_import_resolution[ns] = ImportResolution {
-                            id: id, is_public: is_public, target: Some(target.clone())
-                        };
-                        self.add_export(module_, *name, &dest_import_resolution[ns]);
-                    }
-                    _ => {}
+            let mut dest_import_resolution =
+                import_resolutions.entry((name, ns))
+                                  .or_insert_with(|| ImportResolution::new(id, is_public));
+
+            match target_import_resolution.binding {
+                Some(binding) if target_import_resolution.is_public => {
+                    self.check_for_conflicting_import(&dest_import_resolution,
+                                                      import_directive.span,
+                                                      name,
+                                                      ns);
+                    dest_import_resolution.id = id;
+                    dest_import_resolution.is_public = is_public;
+                    dest_import_resolution.binding =
+                        Some(self.resolver.new_name_binding(import_directive.import(binding)));
+                    self.add_export(module_, name, &dest_import_resolution);
                 }
+                _ => {}
             }
         }
 
         // Add all children from the containing module.
-        build_reduced_graph::populate_module_if_necessary(self.resolver, &target_module);
+        build_reduced_graph::populate_module_if_necessary(self.resolver, target_module);
 
-        for (&name, name_bindings) in target_module.children.borrow().iter() {
+        target_module.for_each_local_child(|name, ns, name_binding| {
             self.merge_import_resolution(module_,
                                          target_module,
                                          import_directive,
-                                         name,
-                                         name_bindings.clone());
-
-        }
+                                         (name, ns),
+                                         name_binding);
+        });
 
         // Record the destination of this import
         if let Some(did) = target_module.def_id() {
@@ -864,14 +726,14 @@ fn merge_import_resolution(&mut self,
                                module_: Module<'b>,
                                containing_module: Module<'b>,
                                import_directive: &ImportDirective,
-                               name: Name,
-                               name_bindings: NameBindings<'b>) {
+                               (name, ns): (Name, Namespace),
+                               name_binding: &'b NameBinding<'b>) {
         let id = import_directive.id;
         let is_public = import_directive.is_public;
 
         let mut import_resolutions = module_.import_resolutions.borrow_mut();
-        let dest_import_resolution = import_resolutions.entry(name).or_insert_with(|| {
-            ImportResolutionPerNamespace::new(id, is_public)
+        let dest_import_resolution = import_resolutions.entry((name, ns)).or_insert_with(|| {
+            ImportResolution::new(id, is_public)
         });
 
         debug!("(resolving glob import) writing resolution `{}` in `{}` to `{}`",
@@ -880,61 +742,41 @@ fn merge_import_resolution(&mut self,
                module_to_string(module_));
 
         // Merge the child item into the import resolution.
-        // pub_err makes sure we don't give the same error twice.
-        let mut pub_err = false;
-        {
-            let mut merge_child_item = |namespace| {
-                if !pub_err && is_public &&
-                        name_bindings[namespace].defined_with(DefModifiers::PRIVATE_VARIANT) {
-                    let msg = format!("variant `{}` is private, and cannot be reexported (error \
-                                       E0364), consider declaring its enum as `pub`", name);
-                    self.resolver.session.add_lint(lint::builtin::PRIVATE_IN_PUBLIC,
-                                                   import_directive.id,
-                                                   import_directive.span,
-                                                   msg);
-                    pub_err = true;
-                }
+        let modifier = DefModifiers::IMPORTABLE | DefModifiers::PUBLIC;
+
+        if ns == TypeNS && is_public && name_binding.defined_with(DefModifiers::PRIVATE_VARIANT) {
+            let msg = format!("variant `{}` is private, and cannot be reexported (error \
+                               E0364), consider declaring its enum as `pub`", name);
+            self.resolver.session.add_lint(lint::builtin::PRIVATE_IN_PUBLIC,
+                                           import_directive.id,
+                                           import_directive.span,
+                                           msg);
+        }
 
-                let modifier = DefModifiers::IMPORTABLE | DefModifiers::PUBLIC;
-                if name_bindings[namespace].defined_with(modifier) {
-                    let namespace_name = match namespace {
-                        TypeNS => "type",
-                        ValueNS => "value",
-                    };
-                    debug!("(resolving glob import) ... for {} target", namespace_name);
-                    if dest_import_resolution.shadowable(namespace) == Shadowable::Never {
-                        let msg = format!("a {} named `{}` has already been imported in this \
-                                           module",
-                                          namespace_name,
-                                          name);
-                        span_err!(self.resolver.session,
-                                  import_directive.span,
-                                  E0251,
-                                  "{}",
-                                  msg);
-                    } else {
-                        dest_import_resolution[namespace] = ImportResolution {
-                            target: Some(Target::new(containing_module,
-                                                     name_bindings[namespace].clone(),
-                                                     import_directive.shadowable)),
-                            id: id,
-                            is_public: is_public
-                        };
-                        self.add_export(module_, name, &dest_import_resolution[namespace]);
-                    }
-                } else {
-                    // FIXME #30159: This is required for backwards compatability.
-                    dest_import_resolution[namespace].is_public |= is_public;
-                }
+        if name_binding.defined_with(modifier) {
+            let namespace_name = match ns {
+                TypeNS => "type",
+                ValueNS => "value",
             };
-            merge_child_item(ValueNS);
-            merge_child_item(TypeNS);
+            debug!("(resolving glob import) ... for {} target", namespace_name);
+            if dest_import_resolution.shadowable() == Shadowable::Never {
+                let msg = format!("a {} named `{}` has already been imported in this module",
+                                 namespace_name,
+                                 name);
+                span_err!(self.resolver.session, import_directive.span, E0251, "{}", msg);
+            } else {
+                dest_import_resolution.binding =
+                    Some(self.resolver.new_name_binding(import_directive.import(name_binding)));
+                dest_import_resolution.id = id;
+                dest_import_resolution.is_public = is_public;
+                self.add_export(module_, name, &dest_import_resolution);
+            }
         }
 
         self.check_for_conflicts_between_imports_and_items(module_,
                                                            dest_import_resolution,
                                                            import_directive.span,
-                                                           name);
+                                                           (name, ns));
     }
 
     fn add_export(&mut self, module: Module<'b>, name: Name, resolution: &ImportResolution<'b>) {
@@ -943,7 +785,7 @@ fn add_export(&mut self, module: Module<'b>, name: Name, resolution: &ImportReso
             Some(def_id) => self.resolver.ast_map.as_local_node_id(def_id).unwrap(),
             None => return,
         };
-        let export = match resolution.target.as_ref().unwrap().binding.def() {
+        let export = match resolution.binding.as_ref().unwrap().def() {
             Some(def) => Export { name: name, def_id: def.def_id() },
             None => return,
         };
@@ -952,20 +794,20 @@ fn add_export(&mut self, module: Module<'b>, name: Name, resolution: &ImportReso
 
     /// Checks that imported names and items don't have the same name.
     fn check_for_conflicting_import(&mut self,
-                                    import_resolution: &ImportResolutionPerNamespace,
+                                    import_resolution: &ImportResolution,
                                     import_span: Span,
                                     name: Name,
                                     namespace: Namespace) {
-        let target = &import_resolution[namespace].target;
+        let binding = &import_resolution.binding;
         debug!("check_for_conflicting_import: {}; target exists: {}",
                name,
-               target.is_some());
+               binding.is_some());
 
-        match *target {
-            Some(ref target) if target.shadowable != Shadowable::Always => {
+        match *binding {
+            Some(binding) if !binding.defined_with(DefModifiers::PRELUDE) => {
                 let ns_word = match namespace {
                     TypeNS => {
-                        match target.binding.module() {
+                        match binding.module() {
                             Some(ref module) if module.is_normal() => "module",
                             Some(ref module) if module.is_trait() => "trait",
                             _ => "type",
@@ -973,7 +815,7 @@ fn check_for_conflicting_import(&mut self,
                     }
                     ValueNS => "value",
                 };
-                let use_id = import_resolution[namespace].id;
+                let use_id = import_resolution.id;
                 let item = self.resolver.ast_map.expect_item(use_id);
                 let mut err = struct_span_err!(self.resolver.session,
                                                import_span,
@@ -1006,55 +848,46 @@ fn check_that_import_is_importable(&mut self,
     /// Checks that imported names and items don't have the same name.
     fn check_for_conflicts_between_imports_and_items(&mut self,
                                                      module: Module<'b>,
-                                                     import: &ImportResolutionPerNamespace<'b>,
+                                                     import: &ImportResolution<'b>,
                                                      import_span: Span,
-                                                     name: Name) {
-        // First, check for conflicts between imports and `extern crate`s.
-        if module.external_module_children
-                 .borrow()
-                 .contains_key(&name) {
-            match import.type_ns.target {
-                Some(ref target) if target.shadowable != Shadowable::Always => {
-                    let msg = format!("import `{0}` conflicts with imported crate in this module \
-                                       (maybe you meant `use {0}::*`?)",
-                                      name);
-                    span_err!(self.resolver.session, import_span, E0254, "{}", &msg[..]);
-                }
-                Some(_) | None => {}
-            }
-        }
-
+                                                     (name, ns): (Name, Namespace)) {
         // Check for item conflicts.
-        let name_bindings = match module.children.borrow().get(&name) {
+        let name_binding = match module.get_child(name, ns) {
             None => {
                 // There can't be any conflicts.
                 return;
             }
-            Some(ref name_bindings) => (*name_bindings).clone(),
+            Some(name_binding) => name_binding,
         };
 
-        match import.value_ns.target {
-            Some(ref target) if target.shadowable != Shadowable::Always => {
-                if let Some(ref value) = *name_bindings.value_ns.borrow() {
+        if ns == ValueNS {
+            match import.binding {
+                Some(binding) if !binding.defined_with(DefModifiers::PRELUDE) => {
                     let mut err = struct_span_err!(self.resolver.session,
                                                    import_span,
                                                    E0255,
                                                    "import `{}` conflicts with \
                                                     value in this module",
                                                    name);
-                    if let Some(span) = value.span {
+                    if let Some(span) = name_binding.span {
                         err.span_note(span, "conflicting value here");
                     }
                     err.emit();
                 }
+                Some(_) | None => {}
             }
-            Some(_) | None => {}
-        }
+        } else {
+            match import.binding {
+                Some(binding) if !binding.defined_with(DefModifiers::PRELUDE) => {
+                    if name_binding.is_extern_crate() {
+                        let msg = format!("import `{0}` conflicts with imported crate \
+                                           in this module (maybe you meant `use {0}::*`?)",
+                                          name);
+                        span_err!(self.resolver.session, import_span, E0254, "{}", &msg[..]);
+                        return;
+                    }
 
-        match import.type_ns.target {
-            Some(ref target) if target.shadowable != Shadowable::Always => {
-                if let Some(ref ty) = *name_bindings.type_ns.borrow() {
-                    let (what, note) = match ty.module() {
+                    let (what, note) = match name_binding.module() {
                         Some(ref module) if module.is_normal() =>
                             ("existing submodule", "note conflicting module here"),
                         Some(ref module) if module.is_trait() =>
@@ -1067,13 +900,13 @@ fn check_for_conflicts_between_imports_and_items(&mut self,
                                                    "import `{}` conflicts with {}",
                                                    name,
                                                    what);
-                    if let Some(span) = ty.span {
+                    if let Some(span) = name_binding.span {
                         err.span_note(span, note);
                     }
                     err.emit();
                 }
+                Some(_) | None => {}
             }
-            Some(_) | None => {}
         }
     }
 }