Refactor `ty::Visibility` methods to use a new trait `NodeIdTree` instead of the ast map.
PrivateExternal,
}
+pub trait NodeIdTree {
+ fn is_descendant_of(&self, node: NodeId, ancestor: NodeId) -> bool;
+}
+
+impl<'a> NodeIdTree for ast_map::Map<'a> {
+ fn is_descendant_of(&self, node: NodeId, ancestor: NodeId) -> bool {
+ let mut node_ancestor = node;
+ loop {
+ if node_ancestor == ancestor { return true }
+ let node_ancestor_parent = self.get_module_parent(node_ancestor);
+ if node_ancestor_parent == node_ancestor { return false }
+ node_ancestor = node_ancestor_parent;
+ }
+ }
+}
+
impl Visibility {
pub fn from_hir(visibility: &hir::Visibility, id: NodeId, tcx: &TyCtxt) -> Self {
match *visibility {
}
/// Returns true if an item with this visibility is accessible from the given block.
- pub fn is_accessible_from(self, block: NodeId, map: &ast_map::Map) -> bool {
+ pub fn is_accessible_from<T: NodeIdTree>(self, block: NodeId, tree: &T) -> bool {
let restriction = match self {
// Public items are visible everywhere.
Visibility::Public => return true,
Visibility::Restricted(module) => module,
};
- let mut block_ancestor = block;
- loop {
- if block_ancestor == restriction { return true }
- let block_ancestor_parent = map.get_module_parent(block_ancestor);
- if block_ancestor_parent == block_ancestor { return false }
- block_ancestor = block_ancestor_parent;
- }
+ tree.is_descendant_of(block, restriction)
}
/// Returns true if this visibility is at least as accessible as the given visibility
- pub fn is_at_least(self, vis: Visibility, map: &ast_map::Map) -> bool {
+ pub fn is_at_least<T: NodeIdTree>(self, vis: Visibility, tree: &T) -> bool {
let vis_restriction = match vis {
Visibility::Public => return self == Visibility::Public,
Visibility::PrivateExternal => return true,
Visibility::Restricted(module) => module,
};
- self.is_accessible_from(vis_restriction, map)
+ self.is_accessible_from(vis_restriction, tree)
}
}
}
}
+impl<'a, 'tcx> ty::NodeIdTree for Resolver<'a, 'tcx> {
+ fn is_descendant_of(&self, node: NodeId, ancestor: NodeId) -> bool {
+ let ancestor = self.ast_map.local_def_id(ancestor);
+ let mut module = *self.module_map.get(&node).unwrap();
+ loop {
+ if module.def_id() == Some(ancestor) { return true; }
+ let module_parent = match self.get_nearest_normal_module_parent(module) {
+ Some(parent) => parent,
+ None => return false,
+ };
+ module = module_parent;
+ }
+ }
+}
+
impl<'a, 'tcx> Resolver<'a, 'tcx> {
fn new(session: &'a Session,
ast_map: &'a hir_map::Map<'tcx>,
let graph_root =
ModuleS::new(NoParentLink, Some(Def::Mod(root_def_id)), false, arenas);
let graph_root = arenas.alloc_module(graph_root);
+ let mut module_map = NodeMap();
+ module_map.insert(CRATE_NODE_ID, graph_root);
Resolver {
session: session,
freevars_seen: NodeMap(),
export_map: NodeMap(),
trait_map: NodeMap(),
- module_map: NodeMap(),
+ module_map: module_map,
used_imports: HashSet::new(),
used_crates: HashSet::new(),
fn is_accessible(&self, vis: ty::Visibility) -> bool {
let current_module = self.get_nearest_normal_module_parent_or_self(self.current_module);
let node_id = self.ast_map.as_local_node_id(current_module.def_id().unwrap()).unwrap();
- vis.is_accessible_from(node_id, &self.ast_map)
+ vis.is_accessible_from(node_id, self)
}
fn check_privacy(&mut self, name: Name, binding: &'a NameBinding<'a>, span: Span) {
_ => (),
}
- let ast_map = self.resolver.ast_map;
match (&value_result, &type_result) {
- (&Success(binding), _) if !binding.pseudo_vis().is_at_least(directive.vis, ast_map) &&
+ (&Success(binding), _) if !binding.pseudo_vis()
+ .is_at_least(directive.vis, self.resolver) &&
self.resolver.is_accessible(binding.vis) => {
let msg = format!("`{}` is private, and cannot be reexported", source);
let note_msg = format!("consider marking `{}` as `pub` in the imported module",
.emit();
}
- (_, &Success(binding)) if !binding.pseudo_vis().is_at_least(directive.vis, ast_map) &&
+ (_, &Success(binding)) if !binding.pseudo_vis()
+ .is_at_least(directive.vis, self.resolver) &&
self.resolver.is_accessible(binding.vis) => {
if binding.is_extern_crate() {
let msg = format!("extern crate `{}` is private, and cannot be reexported \
if let NameBindingKind::Import { binding: orig_binding, directive, .. } = binding.kind {
if ns == TypeNS && orig_binding.is_variant() &&
- !orig_binding.vis.is_at_least(binding.vis, &self.resolver.ast_map) {
+ !orig_binding.vis.is_at_least(binding.vis, self.resolver) {
let msg = format!("variant `{}` is private, and cannot be reexported \
(error E0364), consider declaring its enum as `pub`",
name);