diff --git a/src/librustc_resolve/build_reduced_graph.rs b/src/librustc_resolve/build_reduced_graph.rs index dbbaf0e23c7e8..b3d7be4775e42 100644 --- a/src/librustc_resolve/build_reduced_graph.rs +++ b/src/librustc_resolve/build_reduced_graph.rs @@ -98,14 +98,14 @@ impl<'a, 'b:'a, 'tcx:'b> GraphBuilder<'a, 'b, 'tcx> { fn try_define(&self, parent: Module<'b>, name: Name, ns: Namespace, def: T) where T: ToNameBinding<'b> { - let _ = parent.try_define_child(name, ns, self.new_name_binding(def.to_name_binding())); + let _ = parent.try_define_child(name, ns, def.to_name_binding()); } /// Defines `name` in namespace `ns` of module `parent` to be `def` if it is not yet defined; /// otherwise, reports an error. fn define>(&self, parent: Module<'b>, name: Name, ns: Namespace, def: T) { - let binding = self.new_name_binding(def.to_name_binding()); - let old_binding = match parent.try_define_child(name, ns, binding) { + let binding = def.to_name_binding(); + let old_binding = match parent.try_define_child(name, ns, binding.clone()) { Ok(()) => return, Err(old_binding) => old_binding, }; @@ -207,7 +207,7 @@ impl<'a, 'b:'a, 'tcx:'b> GraphBuilder<'a, 'b, 'tcx> { ResolutionError::SelfImportsOnlyAllowedWithin); } - let subclass = SingleImport(binding, source_name); + let subclass = ImportDirectiveSubclass::single(binding, source_name); self.build_import_directive(parent, module_path, subclass, @@ -258,9 +258,10 @@ impl<'a, 'b:'a, 'tcx:'b> GraphBuilder<'a, 'b, 'tcx> { (module_path.to_vec(), name, rename) } }; + let subclass = ImportDirectiveSubclass::single(rename, name); self.build_import_directive(parent, module_path, - SingleImport(rename, name), + subclass, source_item.span, source_item.node.id(), is_public, @@ -294,14 +295,6 @@ impl<'a, 'b:'a, 'tcx:'b> GraphBuilder<'a, 'b, 'tcx> { let module = self.new_extern_crate_module(parent_link, def, is_public, item.id); self.define(parent, name, TypeNS, (module, sp)); - if is_public { - let export = Export { name: name, def_id: def_id }; - if let Some(def_id) = parent.def_id() { - let node_id = self.resolver.ast_map.as_local_node_id(def_id).unwrap(); - self.export_map.entry(node_id).or_insert(Vec::new()).push(export); - } - } - self.build_reduced_graph_for_external_crate(module); } parent @@ -683,33 +676,25 @@ impl<'a, 'b:'a, 'tcx:'b> GraphBuilder<'a, 'b, 'tcx> { id: NodeId, is_public: bool, shadowable: Shadowable) { - module_.unresolved_imports - .borrow_mut() - .push(ImportDirective::new(module_path, subclass, span, id, is_public, shadowable)); - self.unresolved_imports += 1; - - if is_public { - module_.inc_pub_count(); - } - // Bump the reference count on the name. Or, if this is a glob, set // the appropriate flag. match subclass { - SingleImport(target, _) => { + SingleImport { target, .. } => { module_.increment_outstanding_references_for(target, ValueNS); module_.increment_outstanding_references_for(target, TypeNS); } GlobImport => { // Set the glob flag. This tells us that we don't know the // module's exports ahead of time. - - module_.inc_glob_count(); - if is_public { - module_.inc_pub_glob_count(); - } + module_.inc_glob_count(is_public) } } + + let directive = + ImportDirective::new(module_path, subclass, span, id, is_public, shadowable); + module_.add_import_directive(directive); + self.unresolved_imports += 1; } } diff --git a/src/librustc_resolve/lib.rs b/src/librustc_resolve/lib.rs index a160e1384d12e..a205bfb98acfe 100644 --- a/src/librustc_resolve/lib.rs +++ b/src/librustc_resolve/lib.rs @@ -18,6 +18,7 @@ #![cfg_attr(not(stage0), deny(warnings))] #![feature(associated_consts)] +#![feature(borrow_state)] #![feature(rustc_diagnostic_macros)] #![feature(rustc_private)] #![feature(staged_api)] @@ -812,7 +813,7 @@ pub struct ModuleS<'a> { extern_crate_id: Option, resolutions: RefCell>>, - unresolved_imports: RefCell>, + unresolved_imports: RefCell>, // The module children of this node, including normal modules and anonymous modules. // Anonymous children are pseudo-modules that are implicitly created around items @@ -832,26 +833,31 @@ pub struct ModuleS<'a> { shadowed_traits: RefCell>>, - // The number of unresolved globs that this module exports. - glob_count: Cell, + glob_importers: RefCell, &'a ImportDirective)>>, + resolved_globs: RefCell<(Vec> /* public */, Vec> /* private */)>, - // The number of unresolved pub imports (both regular and globs) in this module - pub_count: Cell, + // The number of public glob imports in this module. + public_glob_count: Cell, - // The number of unresolved pub glob imports in this module - pub_glob_count: Cell, + // The number of private glob imports in this module. + private_glob_count: Cell, // Whether this module is populated. If not populated, any attempt to // access the children must be preceded with a // `populate_module_if_necessary` call. populated: Cell, + + arenas: &'a ResolverArenas<'a>, } pub type Module<'a> = &'a ModuleS<'a>; impl<'a> ModuleS<'a> { - - fn new(parent_link: ParentLink<'a>, def: Option, external: bool, is_public: bool) -> Self { + fn new(parent_link: ParentLink<'a>, + def: Option, + external: bool, + is_public: bool, + arenas: &'a ResolverArenas<'a>) -> Self { ModuleS { parent_link: parent_link, def: def, @@ -861,53 +867,18 @@ impl<'a> ModuleS<'a> { unresolved_imports: RefCell::new(Vec::new()), module_children: RefCell::new(NodeMap()), shadowed_traits: RefCell::new(Vec::new()), - glob_count: Cell::new(0), - pub_count: Cell::new(0), - pub_glob_count: Cell::new(0), + glob_importers: RefCell::new(Vec::new()), + resolved_globs: RefCell::new((Vec::new(), Vec::new())), + public_glob_count: Cell::new(0), + private_glob_count: Cell::new(0), populated: Cell::new(!external), + arenas: arenas } } - fn resolve_name(&self, name: Name, ns: Namespace, allow_private_imports: bool) - -> ResolveResult<&'a NameBinding<'a>> { - let glob_count = - if allow_private_imports { self.glob_count.get() } else { self.pub_glob_count.get() }; - - self.resolutions.borrow().get(&(name, ns)).cloned().unwrap_or_default().result(glob_count) - .and_then(|binding| { - let allowed = allow_private_imports || !binding.is_import() || binding.is_public(); - if allowed { Success(binding) } else { Failed(None) } - }) - } - - // Define the name or return the existing binding if there is a collision. - fn try_define_child(&self, name: Name, ns: Namespace, binding: &'a NameBinding<'a>) - -> Result<(), &'a NameBinding<'a>> { - let mut children = self.resolutions.borrow_mut(); - let resolution = children.entry((name, ns)).or_insert_with(Default::default); - - // FIXME #31379: We can use methods from imported traits shadowed by non-import items - if let Some(old_binding) = resolution.binding { - if !old_binding.is_import() && binding.is_import() { - if let Some(Def::Trait(_)) = binding.def() { - self.shadowed_traits.borrow_mut().push(binding); - } - } - } - - resolution.try_define(binding) - } - - fn increment_outstanding_references_for(&self, name: Name, ns: Namespace) { - let mut children = self.resolutions.borrow_mut(); - children.entry((name, ns)).or_insert_with(Default::default).outstanding_references += 1; - } - - fn decrement_outstanding_references_for(&self, name: Name, ns: Namespace) { - match self.resolutions.borrow_mut().get_mut(&(name, ns)).unwrap().outstanding_references { - 0 => panic!("No more outstanding references!"), - ref mut outstanding_references => { *outstanding_references -= 1; } - } + fn add_import_directive(&self, import_directive: ImportDirective) { + let import_directive = self.arenas.alloc_import_directive(import_directive); + self.unresolved_imports.borrow_mut().push(import_directive); } fn for_each_child)>(&self, mut f: F) { @@ -943,26 +914,9 @@ impl<'a> ModuleS<'a> { } } - pub fn inc_glob_count(&self) { - self.glob_count.set(self.glob_count.get() + 1); - } - pub fn dec_glob_count(&self) { - assert!(self.glob_count.get() > 0); - self.glob_count.set(self.glob_count.get() - 1); - } - pub fn inc_pub_count(&self) { - self.pub_count.set(self.pub_count.get() + 1); - } - pub fn dec_pub_count(&self) { - assert!(self.pub_count.get() > 0); - self.pub_count.set(self.pub_count.get() - 1); - } - pub fn inc_pub_glob_count(&self) { - self.pub_glob_count.set(self.pub_glob_count.get() + 1); - } - pub fn dec_pub_glob_count(&self) { - assert!(self.pub_glob_count.get() > 0); - self.pub_glob_count.set(self.pub_glob_count.get() - 1); + fn inc_glob_count(&self, is_public: bool) { + let glob_count = if is_public { &self.public_glob_count } else { &self.private_glob_count }; + glob_count.set(glob_count.get() + 1); } } @@ -995,14 +949,14 @@ bitflags! { } // Records a possibly-private value, type, or module definition. -#[derive(Debug)] +#[derive(Clone, Debug)] pub struct NameBinding<'a> { modifiers: DefModifiers, kind: NameBindingKind<'a>, span: Option, } -#[derive(Debug)] +#[derive(Clone, Debug)] enum NameBindingKind<'a> { Def(Def), Module(Module<'a>), @@ -1167,6 +1121,19 @@ pub struct Resolver<'a, 'tcx: 'a> { pub struct ResolverArenas<'a> { modules: arena::TypedArena>, name_bindings: arena::TypedArena>, + import_directives: arena::TypedArena, +} + +impl<'a> ResolverArenas<'a> { + fn alloc_module(&'a self, module: ModuleS<'a>) -> Module<'a> { + self.modules.alloc(module) + } + fn alloc_name_binding(&'a self, name_binding: NameBinding<'a>) -> &'a NameBinding<'a> { + self.name_bindings.alloc(name_binding) + } + fn alloc_import_directive(&'a self, import_directive: ImportDirective) -> &'a ImportDirective { + self.import_directives.alloc(import_directive) + } } #[derive(PartialEq)] @@ -1182,8 +1149,9 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { arenas: &'a ResolverArenas<'a>) -> Resolver<'a, 'tcx> { let root_def_id = ast_map.local_def_id(CRATE_NODE_ID); - let graph_root = ModuleS::new(NoParentLink, Some(Def::Mod(root_def_id)), false, true); - let graph_root = arenas.modules.alloc(graph_root); + let graph_root = + ModuleS::new(NoParentLink, Some(Def::Mod(root_def_id)), false, true, arenas); + let graph_root = arenas.alloc_module(graph_root); Resolver { session: session, @@ -1234,6 +1202,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { ResolverArenas { modules: arena::TypedArena::new(), name_bindings: arena::TypedArena::new(), + import_directives: arena::TypedArena::new(), } } @@ -1242,11 +1211,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { def: Option, external: bool, is_public: bool) -> Module<'a> { - self.arenas.modules.alloc(ModuleS::new(parent_link, def, external, is_public)) - } - - fn new_name_binding(&self, name_binding: NameBinding<'a>) -> &'a NameBinding<'a> { - self.arenas.name_bindings.alloc(name_binding) + self.arenas.alloc_module(ModuleS::new(parent_link, def, external, is_public, self.arenas)) } fn new_extern_crate_module(&self, @@ -1255,7 +1220,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { is_public: bool, local_node_id: NodeId) -> Module<'a> { - let mut module = ModuleS::new(parent_link, Some(def), false, is_public); + let mut module = ModuleS::new(parent_link, Some(def), false, is_public, self.arenas); module.extern_crate_id = Some(local_node_id); self.arenas.modules.alloc(module) } @@ -1626,18 +1591,6 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { }) } - fn report_unresolved_imports(&mut self, module_: Module<'a>) { - for import in module_.unresolved_imports.borrow().iter() { - resolve_error(self, import.span, ResolutionError::UnresolvedImport(None)); - break; - } - - // Descend into children and anonymous children. - for (_, module_) in module_.module_children.borrow().iter() { - self.report_unresolved_imports(module_); - } - } - // AST resolution // // We maintain a list of value ribs and type ribs. diff --git a/src/librustc_resolve/resolve_imports.rs b/src/librustc_resolve/resolve_imports.rs index f6d23c8caa2c7..f1f47381e4c81 100644 --- a/src/librustc_resolve/resolve_imports.rs +++ b/src/librustc_resolve/resolve_imports.rs @@ -32,14 +32,31 @@ use syntax::codemap::Span; use syntax::util::lev_distance::find_best_match_for_name; use std::mem::replace; +use std::cell::Cell; /// Contains data for specific types of import directives. -#[derive(Copy, Clone,Debug)] +#[derive(Clone, Debug)] pub enum ImportDirectiveSubclass { - SingleImport(Name /* target */, Name /* source */), + SingleImport { + target: Name, + source: Name, + type_determined: Cell, + value_determined: Cell, + }, GlobImport, } +impl ImportDirectiveSubclass { + pub fn single(target: Name, source: Name) -> Self { + SingleImport { + target: target, + source: source, + type_determined: Cell::new(false), + value_determined: Cell::new(false), + } + } +} + /// Whether an import can be shadowed by another import. #[derive(Debug,PartialEq,Clone,Copy)] pub enum Shadowable { @@ -108,54 +125,170 @@ impl ImportDirective { /// Records information about the resolution of a name in a module. pub struct NameResolution<'a> { /// The number of unresolved single imports that could define the name. - pub outstanding_references: usize, + outstanding_references: usize, /// The least shadowable known binding for this name, or None if there are no known bindings. pub binding: Option<&'a NameBinding<'a>>, + duplicate_globs: Vec<&'a NameBinding<'a>>, } impl<'a> NameResolution<'a> { - pub fn result(&self, outstanding_globs: usize) -> ResolveResult<&'a NameBinding<'a>> { - // If no unresolved imports (single or glob) can define the name, self.binding is final. - if self.outstanding_references == 0 && outstanding_globs == 0 { - return self.binding.map(Success).unwrap_or(Failed(None)); - } - - if let Some(binding) = self.binding { - // Single imports will never be shadowable by other single or glob imports. - if !binding.defined_with(DefModifiers::GLOB_IMPORTED) { return Success(binding); } - // Non-PRELUDE glob imports will never be shadowable by other glob imports. - if self.outstanding_references == 0 && !binding.defined_with(DefModifiers::PRELUDE) { - return Success(binding); + fn try_define(&mut self, binding: &'a NameBinding<'a>) -> Result<(), &'a NameBinding<'a>> { + match self.binding { + Some(old_binding) if !old_binding.defined_with(DefModifiers::PRELUDE) => { + if binding.defined_with(DefModifiers::GLOB_IMPORTED) { + self.duplicate_globs.push(binding); + } else if old_binding.defined_with(DefModifiers::GLOB_IMPORTED) { + self.duplicate_globs.push(old_binding); + self.binding = Some(binding); + } else { + return Err(old_binding); + } } + _ => self.binding = Some(binding), } - Indeterminate + Ok(()) } - // Define the name or return the existing binding if there is a collision. - pub fn try_define(&mut self, binding: &'a NameBinding<'a>) -> Result<(), &'a NameBinding<'a>> { - let is_prelude = |binding: &NameBinding| binding.defined_with(DefModifiers::PRELUDE); - let old_binding = match self.binding { - Some(_) if is_prelude(binding) => return Ok(()), - Some(old_binding) if !is_prelude(old_binding) => old_binding, - _ => { self.binding = Some(binding); return Ok(()); } + // Returns the resolution of the name assuming no more globs will define it. + fn result(&self) -> ResolveResult<&'a NameBinding<'a>> { + match self.binding { + Some(binding) if !binding.defined_with(DefModifiers::GLOB_IMPORTED) => Success(binding), + _ if self.outstanding_references > 0 => Indeterminate, + Some(binding) => Success(binding), + None => Failed(None), + } + } + + // Returns Some(the resolution of the name), or None if the resolution depends + // on whether more globs can define the name. + fn try_result(&self) -> Option>> { + match self.result() { + Success(binding) if binding.defined_with(DefModifiers::PRELUDE) => None, + Failed(_) => None, + result @ _ => Some(result), + } + } + + fn report_conflicts(&self, mut report: F) { + let binding = match self.binding { + Some(binding) => binding, + None => return, }; - // FIXME #31337: We currently allow items to shadow glob-imported re-exports. - if !old_binding.is_import() && binding.defined_with(DefModifiers::GLOB_IMPORTED) { - if let NameBindingKind::Import { binding, .. } = binding.kind { - if binding.is_import() { return Ok(()); } + for duplicate_glob in self.duplicate_globs.iter() { + if duplicate_glob.defined_with(DefModifiers::PRELUDE) { continue } + + // FIXME #31337: We currently allow items to shadow glob-imported re-exports. + if !binding.is_import() { + if let NameBindingKind::Import { binding, .. } = duplicate_glob.kind { + if binding.is_import() { continue } + } + } + + report(duplicate_glob, binding); + } + } +} + +impl<'a> ::ModuleS<'a> { + pub fn resolve_name(&self, name: Name, ns: Namespace, allow_private_imports: bool) + -> ResolveResult<&'a NameBinding<'a>> { + let resolutions = match self.resolutions.borrow_state() { + ::std::cell::BorrowState::Unused => self.resolutions.borrow(), + _ => return Failed(None), // This happens when there is a cycle of glob imports + }; + + let resolution = resolutions.get(&(name, ns)).cloned().unwrap_or_default(); + if let Some(result) = resolution.try_result() { + // If the resolution doesn't depend on glob definability, check privacy and return. + return result.and_then(|binding| { + let allowed = allow_private_imports || !binding.is_import() || binding.is_public(); + if allowed { Success(binding) } else { Failed(None) } + }); + } + + let (ref mut public_globs, ref mut private_globs) = *self.resolved_globs.borrow_mut(); + + // Check if the public globs are determined + if public_globs.len() < self.public_glob_count.get() { + return Indeterminate; + } + for module in public_globs.iter() { + if let Indeterminate = module.resolve_name(name, ns, false) { + return Indeterminate; + } + } + + if !allow_private_imports { + return Failed(None); + } + + // Check if the private globs are determined + if private_globs.len() < self.private_glob_count.get() { + return Indeterminate; + } + for module in private_globs.iter() { + if let Indeterminate = module.resolve_name(name, ns, false) { + return Indeterminate; } } - Err(old_binding) + resolution.result() + } + + // Define the name or return the existing binding if there is a collision. + pub fn try_define_child(&self, name: Name, ns: Namespace, binding: NameBinding<'a>) + -> Result<(), &'a NameBinding<'a>> { + if self.resolutions.borrow_state() != ::std::cell::BorrowState::Unused { return Ok(()); } + self.update_resolution(name, ns, |resolution| { + resolution.try_define(self.arenas.alloc_name_binding(binding)) + }) + } + + pub fn increment_outstanding_references_for(&self, name: Name, ns: Namespace) { + let mut resolutions = self.resolutions.borrow_mut(); + resolutions.entry((name, ns)).or_insert_with(Default::default).outstanding_references += 1; + } + + fn decrement_outstanding_references_for(&self, name: Name, ns: Namespace) { + self.update_resolution(name, ns, |resolution| match resolution.outstanding_references { + 0 => panic!("No more outstanding references!"), + ref mut outstanding_references => *outstanding_references -= 1, + }) + } + + // Use `update` to mutate the resolution for the name. + // If the resolution becomes a success, define it in the module's glob importers. + fn update_resolution(&self, name: Name, ns: Namespace, update: F) -> T + where F: FnOnce(&mut NameResolution<'a>) -> T + { + let mut resolutions = self.resolutions.borrow_mut(); + let resolution = resolutions.entry((name, ns)).or_insert_with(Default::default); + let was_success = resolution.try_result().and_then(ResolveResult::success).is_some(); + + let t = update(resolution); + if !was_success { + if let Some(Success(binding)) = resolution.try_result() { + self.define_in_glob_importers(name, ns, binding); + } + } + t + } + + fn define_in_glob_importers(&self, name: Name, ns: Namespace, binding: &'a NameBinding<'a>) { + if !binding.defined_with(DefModifiers::PUBLIC | DefModifiers::IMPORTABLE) { return } + if binding.is_extern_crate() { return } + for &(importer, directive) in self.glob_importers.borrow_mut().iter() { + let _ = importer.try_define_child(name, ns, directive.import(binding, None)); + } } } struct ImportResolvingError<'a> { /// Module where the error happened source_module: Module<'a>, - import_directive: ImportDirective, + import_directive: &'a ImportDirective, span: Span, help: String, } @@ -189,21 +322,19 @@ impl<'a, 'b:'a, 'tcx:'b> ImportResolver<'a, 'b, 'tcx> { if self.resolver.unresolved_imports == 0 { debug!("(resolving imports) success"); + self.finalize_resolutions(self.resolver.graph_root, false); break; } if self.resolver.unresolved_imports == prev_unresolved_imports { // resolving failed - if errors.len() > 0 { - for e in errors { - self.import_resolving_error(e) - } - } else { - // Report unresolved imports only if no hard error was already reported - // to avoid generating multiple errors on the same import. - // Imports that are still indeterminate at this point are actually blocked - // by errored imports, so there is no point reporting them. - self.resolver.report_unresolved_imports(self.resolver.graph_root); + // Report unresolved imports only if no hard error was already reported + // to avoid generating multiple errors on the same import. + // Imports that are still indeterminate at this point are actually blocked + // by errored imports, so there is no point reporting them. + self.finalize_resolutions(self.resolver.graph_root, errors.len() == 0); + for e in errors { + self.import_resolving_error(e) } break; } @@ -218,21 +349,20 @@ impl<'a, 'b:'a, 'tcx:'b> ImportResolver<'a, 'b, 'tcx> { 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 dummy_binding = self.resolver.new_name_binding(NameBinding { + if let SingleImport { target, .. } = e.import_directive.subclass { + let dummy_binding = self.resolver.arenas.alloc_name_binding(NameBinding { modifiers: DefModifiers::PRELUDE, kind: NameBindingKind::Def(Def::Err), span: None, }); - let dummy_binding = - self.resolver.new_name_binding(e.import_directive.import(dummy_binding, None)); + let dummy_binding = e.import_directive.import(dummy_binding, None); - let _ = e.source_module.try_define_child(target, ValueNS, dummy_binding); + let _ = e.source_module.try_define_child(target, ValueNS, dummy_binding.clone()); let _ = e.source_module.try_define_child(target, TypeNS, dummy_binding); } let path = import_path_to_string(&e.import_directive.module_path, - e.import_directive.subclass); + &e.import_directive.subclass); resolve_error(self.resolver, e.span, @@ -290,7 +420,7 @@ impl<'a, 'b:'a, 'tcx:'b> ImportResolver<'a, 'b, 'tcx> { /// If successful, the resolved bindings are written into the module. fn resolve_import_for_module(&mut self, module_: Module<'b>, - import_directive: &ImportDirective) + import_directive: &'b ImportDirective) -> ResolveResult<()> { debug!("(resolving import for module) resolving import `{}::...` in `{}`", names_to_string(&import_directive.module_path), @@ -304,64 +434,67 @@ impl<'a, 'b:'a, 'tcx:'b> ImportResolver<'a, 'b, 'tcx> { .and_then(|containing_module| { // We found the module that the target is contained // within. Attempt to resolve the import within it. - if let SingleImport(target, source) = import_directive.subclass { - self.resolve_single_import(module_, - containing_module, - target, - source, - import_directive) - } else { - self.resolve_glob_import(module_, containing_module, import_directive) - } + self.resolve_import(module_, containing_module, import_directive) }) .and_then(|()| { // Decrement the count of unresolved imports. assert!(self.resolver.unresolved_imports >= 1); self.resolver.unresolved_imports -= 1; - - if let GlobImport = import_directive.subclass { - module_.dec_glob_count(); - if import_directive.is_public { - module_.dec_pub_glob_count(); - } - } - if import_directive.is_public { - module_.dec_pub_count(); - } Success(()) }) } - fn resolve_single_import(&mut self, - module_: Module<'b>, - target_module: Module<'b>, - target: Name, - source: Name, - directive: &ImportDirective) - -> ResolveResult<()> { - debug!("(resolving single import) resolving `{}` = `{}::{}` from `{}` id {}", - target, - module_to_string(&target_module), - source, - module_to_string(module_), - directive.id); - - // If this is a circular import, we temporarily count it as determined so that - // it fails (as opposed to being indeterminate) when nothing else can define it. - if target_module.def_id() == module_.def_id() && source == target { - module_.decrement_outstanding_references_for(target, ValueNS); - module_.decrement_outstanding_references_for(target, TypeNS); - } + fn resolve_import(&mut self, + module_: Module<'b>, + target_module: Module<'b>, + directive: &'b ImportDirective) + -> ResolveResult<()> { + let (source, target, value_determined, type_determined) = match directive.subclass { + SingleImport { source, target, ref value_determined, ref type_determined } => + (source, target, value_determined, type_determined), + GlobImport => return self.resolve_glob_import(module_, target_module, directive), + }; // We need to resolve both namespaces for this to succeed. - let value_result = - self.resolver.resolve_name_in_module(target_module, source, ValueNS, false, true); - let type_result = - self.resolver.resolve_name_in_module(target_module, source, TypeNS, false, true); + let (value_result, type_result) = { + let mut resolve_in_ns = |ns, determined: bool| { + // Temporarily count the directive as determined so that the resolution fails + // (as opposed to being indeterminate) when it can only be defined by the directive. + if !determined { module_.decrement_outstanding_references_for(target, ns) } + let result = + self.resolver.resolve_name_in_module(target_module, source, ns, false, true); + if !determined { module_.increment_outstanding_references_for(target, ns) } + result + }; + (resolve_in_ns(ValueNS, value_determined.get()), + resolve_in_ns(TypeNS, type_determined.get())) + }; + + for &(ns, result, determined) in &[(ValueNS, &value_result, value_determined), + (TypeNS, &type_result, type_determined)] { + if determined.get() { continue } + if let Indeterminate = *result { continue } + + determined.set(true); + if let Success(binding) = *result { + if !binding.defined_with(DefModifiers::IMPORTABLE) { + let msg = format!("`{}` is not directly importable", target); + span_err!(self.resolver.session, directive.span, E0253, "{}", &msg); + } - if target_module.def_id() == module_.def_id() && source == target { - module_.increment_outstanding_references_for(target, ValueNS); - module_.increment_outstanding_references_for(target, TypeNS); + let privacy_error = if !self.resolver.is_visible(binding, target_module) { + Some(Box::new(PrivacyError(directive.span, source, binding))) + } else { + None + }; + + let imported_binding = directive.import(binding, privacy_error); + let conflict = module_.try_define_child(target, ns, imported_binding); + if let Err(old_binding) = conflict { + self.report_conflict(target, ns, &directive.import(binding, None), old_binding); + } + } + module_.decrement_outstanding_references_for(target, ns); } match (&value_result, &type_result) { @@ -393,69 +526,46 @@ impl<'a, 'b:'a, 'tcx:'b> ImportResolver<'a, 'b, 'tcx> { .emit(); } - (_, &Success(name_binding)) if !name_binding.is_import() && directive.is_public => { - if !name_binding.is_public() { - if name_binding.is_extern_crate() { - let msg = format!("extern crate `{}` is private, and cannot be reexported \ - (error E0364), consider declaring with `pub`", - source); - self.resolver.session.add_lint(lint::builtin::PRIVATE_IN_PUBLIC, - directive.id, - directive.span, - msg); - } else { - 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`", + (_, &Success(name_binding)) if !name_binding.is_import() && + directive.is_public && + !name_binding.is_public() => { + if name_binding.is_extern_crate() { + let msg = format!("extern crate `{}` is private, and cannot be reexported \ + (error E0364), consider declaring with `pub`", source); self.resolver.session.add_lint(lint::builtin::PRIVATE_IN_PUBLIC, directive.id, directive.span, msg); + } else { + 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(); } } _ => {} } + // Report a privacy error here if all successful namespaces are privacy errors. let mut privacy_error = None; - let mut report_privacy_error = true; - for &(ns, result) in &[(ValueNS, &value_result), (TypeNS, &type_result)] { - if let Success(binding) = *result { - if !binding.defined_with(DefModifiers::IMPORTABLE) { - let msg = format!("`{}` is not directly importable", target); - span_err!(self.resolver.session, directive.span, E0253, "{}", &msg); - } - - privacy_error = if !self.resolver.is_visible(binding, target_module) { - Some(Box::new(PrivacyError(directive.span, source, binding))) - } else { - report_privacy_error = false; - None - }; - - self.define(module_, target, ns, directive.import(binding, privacy_error.clone())); - } - } - - if report_privacy_error { // then all successful namespaces are privacy errors - // We report here so there is an error even if the imported name is not used - self.resolver.privacy_errors.push(*privacy_error.unwrap()); + for &ns in &[ValueNS, TypeNS] { + privacy_error = match module_.resolve_name(target, ns, true) { + Success(&NameBinding { + kind: NameBindingKind::Import { ref privacy_error, .. }, .. + }) => privacy_error.as_ref().map(|error| (**error).clone()), + _ => continue, + }; + if privacy_error.is_none() { break } } + privacy_error.map(|error| self.resolver.privacy_errors.push(error)); // 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. - module_.decrement_outstanding_references_for(target, ValueNS); - module_.decrement_outstanding_references_for(target, TypeNS); - let def = match type_result.success().and_then(NameBinding::def) { Some(def) => def, None => value_result.success().and_then(NameBinding::def).unwrap(), @@ -474,36 +584,29 @@ impl<'a, 'b:'a, 'tcx:'b> ImportResolver<'a, 'b, 'tcx> { fn resolve_glob_import(&mut self, module_: Module<'b>, target_module: Module<'b>, - directive: &ImportDirective) + directive: &'b ImportDirective) -> ResolveResult<()> { - // We must bail out if the node has unresolved imports of any kind (including globs). - if target_module.pub_count.get() > 0 { - debug!("(resolving glob import) target module has unresolved pub imports; bailing out"); - return Indeterminate; - } - if module_.def_id() == target_module.def_id() { // This means we are trying to glob import a module into itself, and it is a no-go let msg = "Cannot glob-import a module into itself.".into(); return Failed(Some((directive.span, msg))); } - - // Add all children from the containing module. build_reduced_graph::populate_module_if_necessary(self.resolver, target_module); - target_module.for_each_child(|name, ns, binding| { - if !binding.defined_with(DefModifiers::IMPORTABLE | DefModifiers::PUBLIC) { return } - self.define(module_, name, ns, directive.import(binding, None)); - - if ns == TypeNS && directive.is_public && - 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, - directive.id, - directive.span, - msg); + + // Add to target_module's glob_importers and module_'s resolved_globs + target_module.glob_importers.borrow_mut().push((module_, directive)); + match *module_.resolved_globs.borrow_mut() { + (ref mut public_globs, _) if directive.is_public => public_globs.push(target_module), + (_, ref mut private_globs) => private_globs.push(target_module), + } + + for (&(name, ns), resolution) in target_module.resolutions.borrow().iter() { + if let Some(Success(binding)) = resolution.try_result() { + if binding.defined_with(DefModifiers::IMPORTABLE | DefModifiers::PUBLIC) { + let _ = module_.try_define_child(name, ns, directive.import(binding, None)); + } } - }); + } // Record the destination of this import if let Some(did) = target_module.def_id() { @@ -518,28 +621,11 @@ impl<'a, 'b:'a, 'tcx:'b> ImportResolver<'a, 'b, 'tcx> { return Success(()); } - fn define(&mut self, - parent: Module<'b>, - name: Name, - ns: Namespace, - binding: NameBinding<'b>) { - let binding = self.resolver.new_name_binding(binding); - if let Err(old_binding) = parent.try_define_child(name, ns, binding) { - self.report_conflict(name, ns, binding, old_binding); - } else if binding.is_public() { // Add to the export map - if let (Some(parent_def_id), Some(def)) = (parent.def_id(), binding.def()) { - let parent_node_id = self.resolver.ast_map.as_local_node_id(parent_def_id).unwrap(); - let export = Export { name: name, def_id: def.def_id() }; - self.resolver.export_map.entry(parent_node_id).or_insert(Vec::new()).push(export); - } - } - } - fn report_conflict(&mut self, name: Name, ns: Namespace, - binding: &'b NameBinding<'b>, - old_binding: &'b NameBinding<'b>) { + binding: &NameBinding, + old_binding: &NameBinding) { // Error on the second of two conflicting imports if old_binding.is_import() && binding.is_import() && old_binding.span.unwrap().lo > binding.span.unwrap().lo { @@ -595,9 +681,68 @@ impl<'a, 'b:'a, 'tcx:'b> ImportResolver<'a, 'b, 'tcx> { err.emit(); } } + + // Miscellaneous post-processing, including recording reexports, recording shadowed traits, + // reporting conflicts, reporting the PRIVATE_IN_PUBLIC lint, and reporting unresolved imports. + fn finalize_resolutions(&mut self, module: Module<'b>, report_unresolved_imports: bool) { + // Since import resolution is finished, globs will not define any more names. + module.public_glob_count.set(0); module.private_glob_count.set(0); + *module.resolved_globs.borrow_mut() = (Vec::new(), Vec::new()); + + let mut reexports = Vec::new(); + for (&(name, ns), resolution) in module.resolutions.borrow().iter() { + resolution.report_conflicts(|b1, b2| self.report_conflict(name, ns, b1, b2)); + let binding = match resolution.binding { + Some(binding) => binding, + None => continue, + }; + + if binding.is_public() && (binding.is_import() || binding.is_extern_crate()) { + if let Some(def) = binding.def() { + reexports.push(Export { name: name, def_id: def.def_id() }); + } + } + + if let NameBindingKind::Import { binding: orig_binding, id, .. } = binding.kind { + if ns == TypeNS && binding.is_public() && + orig_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); + let lint = lint::builtin::PRIVATE_IN_PUBLIC; + self.resolver.session.add_lint(lint, id, binding.span.unwrap(), msg); + } + } + + // FIXME #31379: We can use methods from imported traits shadowed by non-import items + if !binding.is_import() { + for glob_binding in resolution.duplicate_globs.iter() { + module.shadowed_traits.borrow_mut().push(glob_binding); + } + } + } + + if reexports.len() > 0 { + if let Some(def_id) = module.def_id() { + let node_id = self.resolver.ast_map.as_local_node_id(def_id).unwrap(); + self.resolver.export_map.insert(node_id, reexports); + } + } + + if report_unresolved_imports { + for import in module.unresolved_imports.borrow().iter() { + resolve_error(self.resolver, import.span, ResolutionError::UnresolvedImport(None)); + break; + } + } + + for (_, child) in module.module_children.borrow().iter() { + self.finalize_resolutions(child, report_unresolved_imports); + } + } } -fn import_path_to_string(names: &[Name], subclass: ImportDirectiveSubclass) -> String { +fn import_path_to_string(names: &[Name], subclass: &ImportDirectiveSubclass) -> String { if names.is_empty() { import_directive_subclass_to_string(subclass) } else { @@ -608,9 +753,9 @@ fn import_path_to_string(names: &[Name], subclass: ImportDirectiveSubclass) -> S } } -fn import_directive_subclass_to_string(subclass: ImportDirectiveSubclass) -> String { - match subclass { - SingleImport(_, source) => source.to_string(), +fn import_directive_subclass_to_string(subclass: &ImportDirectiveSubclass) -> String { + match *subclass { + SingleImport { source, .. } => source.to_string(), GlobImport => "*".to_string(), } }