]> git.lizzy.rs Git - rust.git/commitdiff
Lay the groundwork for privacy checking in typeck
authorJeffrey Seyfried <jeffrey.seyfried@gmail.com>
Thu, 25 Feb 2016 01:55:54 +0000 (01:55 +0000)
committerJeffrey Seyfried <jeffrey.seyfried@gmail.com>
Fri, 26 Feb 2016 00:37:14 +0000 (00:37 +0000)
src/librustc/front/map/mod.rs
src/librustc/middle/def.rs
src/librustc/middle/ty/mod.rs
src/librustc_privacy/lib.rs
src/librustc_typeck/check/method/mod.rs
src/librustc_typeck/check/mod.rs

index adf14d0d89c19cc989ccb436be1100e5bcff0929..44f588c2e9ca0e9d379d3f47f7f561cf901bd188 100644 (file)
@@ -495,6 +495,30 @@ pub fn get_parent(&self, id: NodeId) -> NodeId {
         }
     }
 
+    /// Returns the NodeId of `id`'s nearest module parent, or `id` itself if no
+    /// module parent is in this map.
+    fn get_module_parent(&self, id: NodeId) -> NodeId {
+        match self.walk_parent_nodes(id, |node| match *node {
+            NodeItem(&Item { node: Item_::ItemMod(_), .. }) => true,
+            _ => false,
+        }) {
+            Ok(id) => id,
+            Err(id) => id,
+        }
+    }
+
+    pub fn private_item_is_visible_from(&self, item: NodeId, block: NodeId) -> bool {
+        // A private item is visible from everything in its nearest module parent.
+        let visibility = self.get_module_parent(item);
+        let mut block_ancestor = self.get_module_parent(block);
+        loop {
+            if block_ancestor == visibility { return true }
+            let block_ancestor_parent = self.get_module_parent(block_ancestor);
+            if block_ancestor_parent == block_ancestor { return false }
+            block_ancestor = block_ancestor_parent;
+        }
+    }
+
     /// Returns the nearest enclosing scope. A scope is an item or block.
     /// FIXME it is not clear to me that all items qualify as scopes - statics
     /// and associated types probably shouldn't, for example. Behaviour in this
index aee8fb10c2a3aa674ad9e6c80d3c2f8abf9420b7..c0a5d27a506ff7aae9d955acf73ab92190237c2a 100644 (file)
@@ -152,4 +152,29 @@ pub fn variant_def_ids(&self) -> Option<(DefId, DefId)> {
             _ => None
         }
     }
+
+    pub fn kind_name(&self) -> &'static str {
+        match *self {
+            Def::Fn(..) => "function",
+            Def::Mod(..) => "module",
+            Def::ForeignMod(..) => "foreign module",
+            Def::Static(..) => "static",
+            Def::Variant(..) => "variant",
+            Def::Enum(..) => "enum",
+            Def::TyAlias(..) => "type",
+            Def::AssociatedTy(..) => "associated type",
+            Def::Struct(..) => "struct",
+            Def::Trait(..) => "trait",
+            Def::Method(..) => "method",
+            Def::Const(..) => "const",
+            Def::AssociatedConst(..) => "associated const",
+            Def::TyParam(..) => "type parameter",
+            Def::PrimTy(..) => "builtin type",
+            Def::Local(..) => "local variable",
+            Def::Upvar(..) => "closure capture",
+            Def::Label(..) => "label",
+            Def::SelfTy(..) => "self type",
+            Def::Err => "unresolved item",
+        }
+    }
 }
index 00a011c6b5d6ac9f2bf8b3ef599a8f0a85808728..b6e8a670182330837af4f39d4588b95a9f8834a9 100644 (file)
@@ -173,6 +173,14 @@ fn id(&self) -> ImplOrTraitItemId {
         }
     }
 
+    pub fn def(&self) -> Def {
+        match *self {
+            ConstTraitItem(ref associated_const) => Def::AssociatedConst(associated_const.def_id),
+            MethodTraitItem(ref method) => Def::Method(method.def_id),
+            TypeTraitItem(ref ty) => Def::AssociatedTy(ty.container.id(), ty.def_id),
+        }
+    }
+
     pub fn def_id(&self) -> DefId {
         match *self {
             ConstTraitItem(ref associated_const) => associated_const.def_id,
index 8908dac7a36dd72c9cd355cd6e94e3da09c9a13a..9f0afb7b98a59d22a19acd835ae6c66fb792c840 100644 (file)
@@ -692,32 +692,7 @@ fn local_private_accessible(&self, did: DefId) -> bool {
     /// whether the node is accessible by the current module that iteration is
     /// inside.
     fn private_accessible(&self, id: ast::NodeId) -> bool {
-        let parent = *self.parents.get(&id).unwrap();
-        debug!("privacy - accessible parent {}", self.nodestr(parent));
-
-        // After finding `did`'s closest private member, we roll ourselves back
-        // to see if this private member's parent is anywhere in our ancestry.
-        // By the privacy rules, we can access all of our ancestor's private
-        // members, so that's why we test the parent, and not the did itself.
-        let mut cur = self.curitem;
-        loop {
-            debug!("privacy - questioning {}, {}", self.nodestr(cur), cur);
-            match cur {
-                // If the relevant parent is in our history, then we're allowed
-                // to look inside any of our ancestor's immediate private items,
-                // so this access is valid.
-                x if x == parent => return true,
-
-                // If we've reached the root, then we couldn't access this item
-                // in the first place
-                ast::DUMMY_NODE_ID => return false,
-
-                // Keep going up
-                _ => {}
-            }
-
-            cur = *self.parents.get(&cur).unwrap();
-        }
+        self.tcx.map.private_item_is_visible_from(id, self.curitem)
     }
 
     fn report_error(&self, result: CheckResult) -> bool {
@@ -835,7 +810,7 @@ fn check_field(&mut self,
             }
             UnnamedField(idx) => &v.fields[idx]
         };
-        if field.vis == hir::Public || self.local_private_accessible(field.did) {
+        if field.vis == hir::Public || self.local_private_accessible(def.did) {
             return;
         }
 
@@ -945,19 +920,9 @@ fn check_path(&mut self, span: Span, path_id: ast::NodeId, last: ast::Name) {
         // def map is not. Therefore the names we work out below will not always
         // be accurate and we can get slightly wonky error messages (but type
         // checking is always correct).
-        match path_res.full_def() {
-            Def::Fn(..) => ck("function"),
-            Def::Static(..) => ck("static"),
-            Def::Const(..) => ck("const"),
-            Def::AssociatedConst(..) => ck("associated const"),
-            Def::Variant(..) => ck("variant"),
-            Def::TyAlias(..) => ck("type"),
-            Def::Enum(..) => ck("enum"),
-            Def::Trait(..) => ck("trait"),
-            Def::Struct(..) => ck("struct"),
-            Def::Method(..) => ck("method"),
-            Def::Mod(..) => ck("module"),
-            _ => {}
+        let def = path_res.full_def();
+        if def != Def::Err {
+            ck(def.kind_name());
         }
     }
 
@@ -1036,7 +1001,7 @@ fn visit_expr(&mut self, expr: &hir::Expr) {
                         _ => expr_ty
                     }.ty_adt_def().unwrap();
                     let any_priv = def.struct_variant().fields.iter().any(|f| {
-                        f.vis != hir::Public && !self.local_private_accessible(f.did)
+                        f.vis != hir::Public && !self.local_private_accessible(def.did)
                     });
                     if any_priv {
                         span_err!(self.tcx.sess, expr.span, E0450,
index fc2dd4475e3ffabf135a56b5fb95ac42b8427a70..f680607eb99580f0d7853e3a21d086a2690bcf70 100644 (file)
@@ -338,20 +338,13 @@ pub fn resolve_ufcs<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
 {
     let mode = probe::Mode::Path;
     let pick = try!(probe::probe(fcx, span, mode, method_name, self_ty, expr_id));
-    let def_id = pick.item.def_id();
+    let def_result = pick.item.def();
     let mut lp = LastMod(AllPublic);
     if let probe::InherentImplPick = pick.kind {
         if pick.item.vis() != hir::Public {
-            lp = LastMod(DependsOn(def_id));
+            lp = LastMod(DependsOn(def_result.def_id()));
         }
     }
-    let def_result = match pick.item {
-        ty::ImplOrTraitItem::MethodTraitItem(..) => Def::Method(def_id),
-        ty::ImplOrTraitItem::ConstTraitItem(..) => Def::AssociatedConst(def_id),
-        ty::ImplOrTraitItem::TypeTraitItem(..) => {
-            fcx.tcx().sess.span_bug(span, "resolve_ufcs: probe picked associated type");
-        }
-    };
     Ok((def_result, lp))
 }
 
index 7ab4975c8b8aed6ae2fb89d4e1228c0fa8fd0a68..9170c00a261d636fac4081fce2c89753b6ead397 100644 (file)
@@ -2022,6 +2022,13 @@ fn select_obligations_where_possible(&self) {
             Err(errors) => { report_fulfillment_errors(self.infcx(), &errors); }
         }
     }
+
+    fn private_item_is_visible(&self, def_id: DefId) -> bool {
+        match self.tcx().map.as_local_node_id(def_id) {
+            Some(node_id) => self.tcx().map.private_item_is_visible_from(node_id, self.body_id),
+            None => false, // Private items from other crates are never visible
+        }
+    }
 }
 
 impl<'a, 'tcx> RegionScope for FnCtxt<'a, 'tcx> {