use DefModifiers;
use Module;
use Namespace::{self, TypeNS, ValueNS};
-use {NameBindings, NameBinding};
-use NamespaceResult::{BoundResult, UnboundResult, UnknownResult};
-use NamespaceResult;
-use NameSearchType;
+use {NameBinding, NameBindingKind};
use ResolveResult;
+use ResolveResult::*;
use Resolver;
use UseLexicalScopeFlag;
use {names_to_string, module_to_string};
}
/// One import directive.
-#[derive(Debug)]
+#[derive(Debug,Clone)]
pub struct ImportDirective {
pub module_path: Vec<Name>,
pub subclass: ImportDirectiveSubclass,
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,
}
// 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
}
}
+ /// 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_));
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.
}
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));
}
/// 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() {
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,
});
}
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,
- NameSearchType::ImportSearch) {
- 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,
};
// 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, ¬e_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, ¬e_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, ¬e_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, ¬e_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());
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),
}
debug!("(resolving single import) successfully resolved import");
- return ResolveResult::Success(());
+ return Success(());
}
// Resolves a glob import. Note that this function cannot fail; it either
"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() {
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 `{}`",
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>) {
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,
};
/// 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",
}
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,
/// 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() =>
"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 => {}
}
}
}