]> 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 47b91ccb9d6f9497c8ec0e87f37914211f350dd3..54dcd0001c4a5ee409be361f19af8874d7fafde4 100644 (file)
@@ -13,7 +13,7 @@
 use DefModifiers;
 use Module;
 use Namespace::{self, TypeNS, ValueNS};
-use NameBinding;
+use {NameBinding, NameBindingKind};
 use ResolveResult;
 use ResolveResult::*;
 use Resolver;
@@ -50,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,
@@ -77,23 +77,25 @@ 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,
         }
     }
 }
@@ -116,7 +118,7 @@ pub struct ImportResolution<'a> {
     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,
@@ -127,22 +129,26 @@ pub fn new(id: NodeId, is_public: bool) -> Self {
         ImportResolution {
             outstanding_references: 0,
             id: id,
-            target: None,
+            binding: None,
             is_public: is_public,
         }
     }
 
     pub fn shadowable(&self) -> Shadowable {
-        match self.target {
-            Some(ref target) => target.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,
 }
 
@@ -181,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
@@ -200,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_));
@@ -212,7 +254,7 @@ 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_);
+        build_reduced_graph::populate_module_if_necessary(self.resolver, module_);
         module_.for_each_local_child(|_, _, child_node| {
             match child_node.module() {
                 None => {
@@ -232,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() {
@@ -254,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,
                     });
                 }
@@ -287,103 +329,55 @@ 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();
                 }
-            }
-            if import_directive.is_public {
-                module_.dec_pub_count();
-            }
-        }
-
-        return resolution_result;
+                Success(())
+            })
     }
 
     /// Resolves the name in the namespace of the module because it is being imported by
-    /// importing_module. Returns the module in which the name was defined (as opposed to imported),
-    /// the name bindings defining the name, and whether or not the name was imported into `module`.
+    /// 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<(Module<'b>, NameBinding<'b>)>, bool) {
+                              -> 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() {
@@ -392,38 +386,32 @@ fn resolve_name_in_module(&mut self,
                     self.resolver.used_crates.insert(krate);
                 }
             }
-            return (Success((module, name_binding)), false)
+            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, false);
+            return Indeterminate;
         }
 
         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), false),
+            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), false);
+                    return Failed(None);
                 }
 
-                let target = resolution.target.clone();
-                if let Some(Target { target_module, binding, shadowable: _ }) = target {
-                    // track used imports and extern crates as well
-                    self.resolver.used_imports.insert((resolution.id, ns));
-                    self.resolver.record_import_use(resolution.id, name);
-                    if let Some(DefId { krate, .. }) = target_module.def_id() {
-                        self.resolver.used_crates.insert(krate);
-                    }
-                    (Success((target_module, binding)), true)
+                if let Some(binding) = resolution.binding {
+                    self.resolver.record_import_use(name, ns, &resolution);
+                    Success(binding)
                 } else {
-                    (Failed(None), false)
+                    Failed(None)
                 }
             }
 
@@ -438,8 +426,8 @@ fn resolve_name_in_module(&mut self,
             // 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), false),
-                _ => (Indeterminate, false)
+                (Some(id1), Some(id2)) if id1 == id2 => Failed(None),
+                _ => Indeterminate
             },
         }
     }
@@ -471,15 +459,15 @@ fn resolve_single_import(&mut self,
         };
 
         // We need to resolve both namespaces for this to succeed.
-        let (value_result, value_used_reexport) =
-            self.resolve_name_in_module(&target_module, source, ValueNS, module_);
-        let (type_result, type_used_reexport) =
-            self.resolve_name_in_module(&target_module, source, TypeNS, module_);
+        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((_, ref name_binding)), _) if !value_used_reexport &&
-                                                    directive.is_public &&
-                                                    !name_binding.is_public() => {
+            (&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);
@@ -488,8 +476,7 @@ fn resolve_single_import(&mut self,
                     .emit();
             }
 
-            (_, &Success((_, ref name_binding))) if !type_used_reexport &&
-                                                    directive.is_public => {
+            (_, &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 =
@@ -533,15 +520,12 @@ fn resolve_single_import(&mut self,
             _ => (),
         }
 
-        let mut value_used_public = false;
-        let mut type_used_public = false;
-
         // We've successfully resolved the import. Write the results in.
         let mut import_resolutions = module_.import_resolutions.borrow_mut();
 
         {
-            let mut check_and_write_import = |namespace, result, used_public: &mut bool| {
-                let result: &ResolveResult<(Module<'b>, NameBinding)> = result;
+            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 {
@@ -550,7 +534,7 @@ fn resolve_single_import(&mut self,
                 };
 
                 match *result {
-                    Success((ref target_module, ref name_binding)) => {
+                    Success(name_binding) => {
                         debug!("(resolving single import) found {:?} target: {:?}",
                                namespace_name,
                                name_binding.def());
@@ -563,14 +547,12 @@ fn resolve_single_import(&mut self,
                                                              directive.span,
                                                              target);
 
-                        import_resolution.target = Some(Target::new(target_module,
-                                                                    name_binding.clone(),
-                                                                    directive.shadowable));
+                        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);
-                        *used_public = name_binding.is_public();
                     }
                     Failed(_) => {
                         // Continue.
@@ -585,20 +567,17 @@ fn resolve_single_import(&mut self,
                                                                    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);
         }
 
         if let (&Failed(_), &Failed(_)) = (&value_result, &type_result) {
             let msg = format!("There is no `{}` in `{}`{}",
                               source,
-                              module_to_string(&target_module), lev_suggestion);
+                              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;
-
         let value_def_and_priv = {
             let import_resolution_value = import_resolutions.get_mut(&(target, ValueNS)).unwrap();
             assert!(import_resolution_value.outstanding_references >= 1);
@@ -607,9 +586,9 @@ fn resolve_single_import(&mut self,
             // 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.target.as_ref().map(|target| {
-                let def = target.binding.def().unwrap();
-                let last_private = if value_used_public { lp } else { DependsOn(def.def_id()) };
+            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)
             })
         };
@@ -619,9 +598,9 @@ fn resolve_single_import(&mut self,
             assert!(import_resolution_type.outstanding_references >= 1);
             import_resolution_type.outstanding_references -= 1;
 
-            import_resolution_type.target.as_ref().map(|target| {
-                let def = target.binding.def().unwrap();
-                let last_private = if type_used_public { lp } else { DependsOn(def.def_id()) };
+            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)
             })
         };
@@ -702,15 +681,16 @@ fn resolve_glob_import(&mut self,
                 import_resolutions.entry((name, ns))
                                   .or_insert_with(|| ImportResolution::new(id, is_public));
 
-            match target_import_resolution.target {
-                Some(ref target) if target_import_resolution.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.target = Some(target.clone());
+                    dest_import_resolution.binding =
+                        Some(self.resolver.new_name_binding(import_directive.import(binding)));
                     self.add_export(module_, name, &dest_import_resolution);
                 }
                 _ => {}
@@ -718,14 +698,14 @@ fn resolve_glob_import(&mut self,
         }
 
         // 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);
 
         target_module.for_each_local_child(|name, ns, name_binding| {
             self.merge_import_resolution(module_,
                                          target_module,
                                          import_directive,
                                          (name, ns),
-                                         name_binding.clone());
+                                         name_binding);
         });
 
         // Record the destination of this import
@@ -747,7 +727,7 @@ fn merge_import_resolution(&mut self,
                                containing_module: Module<'b>,
                                import_directive: &ImportDirective,
                                (name, ns): (Name, Namespace),
-                               name_binding: NameBinding<'b>) {
+                               name_binding: &'b NameBinding<'b>) {
         let id = import_directive.id;
         let is_public = import_directive.is_public;
 
@@ -784,11 +764,9 @@ fn merge_import_resolution(&mut self,
                                  namespace_name,
                                  name);
                 span_err!(self.resolver.session, import_directive.span, E0251, "{}", msg);
-           } else {
-                let target = Target::new(containing_module,
-                                         name_binding.clone(),
-                                         import_directive.shadowable);
-                dest_import_resolution.target = Some(target);
+            } 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);
@@ -807,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,
         };
@@ -820,16 +798,16 @@ fn check_for_conflicting_import(&mut self,
                                     import_span: Span,
                                     name: Name,
                                     namespace: Namespace) {
-        let target = &import_resolution.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",
@@ -883,8 +861,8 @@ fn check_for_conflicts_between_imports_and_items(&mut self,
         };
 
         if ns == ValueNS {
-            match import.target {
-                Some(ref target) if target.shadowable != Shadowable::Always => {
+            match import.binding {
+                Some(binding) if !binding.defined_with(DefModifiers::PRELUDE) => {
                     let mut err = struct_span_err!(self.resolver.session,
                                                    import_span,
                                                    E0255,
@@ -899,8 +877,8 @@ fn check_for_conflicts_between_imports_and_items(&mut self,
                 Some(_) | None => {}
             }
         } else {
-            match import.target {
-                Some(ref target) if target.shadowable != Shadowable::Always => {
+            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}::*`?)",