about summary refs log tree commit diff
diff options
context:
space:
mode:
authorPatrick Walton <pcwalton@mimiga.net>2012-09-04 18:28:22 -0700
committerPatrick Walton <pcwalton@mimiga.net>2012-09-04 18:30:27 -0700
commitfba673b26bc029ef234f56e177559fd0b9e48507 (patch)
tree2a21c1ea78a14b76233af8ec4da4852f21bdd4a3
parenta618d0d7ce913e5c7f1393561149ada6f7c32ff3 (diff)
downloadrust-fba673b26bc029ef234f56e177559fd0b9e48507.tar.gz
rust-fba673b26bc029ef234f56e177559fd0b9e48507.zip
rustc: Implement private methods.
Doesn't work cross-crate yet.
-rw-r--r--src/libsyntax/ast.rs3
-rw-r--r--src/libsyntax/parse/parser.rs3
-rw-r--r--src/rustc/driver/driver.rs2
-rw-r--r--src/rustc/middle/privacy.rs166
-rw-r--r--src/test/compile-fail/private-impl-method.rs15
5 files changed, 157 insertions, 32 deletions
diff --git a/src/libsyntax/ast.rs b/src/libsyntax/ast.rs
index 083f67947e9..ceed0718f6b 100644
--- a/src/libsyntax/ast.rs
+++ b/src/libsyntax/ast.rs
@@ -1041,8 +1041,7 @@ type method = {ident: ident, attrs: ~[attribute],
                tps: ~[ty_param], self_ty: self_ty,
                purity: purity, decl: fn_decl, body: blk,
                id: node_id, span: span, self_id: node_id,
-               vis: visibility};  // always public, unless it's a
-                                  // class method
+               vis: visibility};
 
 #[auto_serialize]
 type _mod = {view_items: ~[@view_item], items: ~[@item]};
diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs
index eca6063df39..367fb9a1bde 100644
--- a/src/libsyntax/parse/parser.rs
+++ b/src/libsyntax/parse/parser.rs
@@ -2533,7 +2533,8 @@ struct parser {
         let mut meths = ~[];
         self.expect(token::LBRACE);
         while !self.eat(token::RBRACE) {
-            vec::push(meths, self.parse_method(public));
+            let vis = self.parse_visibility();
+            vec::push(meths, self.parse_method(vis));
         }
         (ident, item_impl(tps, traits, ty, meths), None)
     }
diff --git a/src/rustc/driver/driver.rs b/src/rustc/driver/driver.rs
index 9c6a168d10f..024452302da 100644
--- a/src/rustc/driver/driver.rs
+++ b/src/rustc/driver/driver.rs
@@ -222,7 +222,7 @@ fn compile_upto(sess: session, cfg: ast::crate_cfg,
     if upto == cu_typeck { return {crate: crate, tcx: Some(ty_cx)}; }
 
     time(time_passes, ~"privacy checking", ||
-        middle::privacy::check_crate(ty_cx, crate));
+        middle::privacy::check_crate(ty_cx, &method_map, crate));
 
     time(time_passes, ~"loop checking", ||
         middle::check_loop::check_crate(ty_cx, crate));
diff --git a/src/rustc/middle/privacy.rs b/src/rustc/middle/privacy.rs
index 5c7ca0092c7..b4b48f21405 100644
--- a/src/rustc/middle/privacy.rs
+++ b/src/rustc/middle/privacy.rs
@@ -3,23 +3,26 @@
 
 use /*mod*/ syntax::ast;
 use /*mod*/ syntax::visit;
-use syntax::ast::{expr_field, ident, item_class, local_crate, node_id};
-use syntax::ast::{private};
+use syntax::ast::{expr_field, ident, item_class, item_impl, item_trait};
+use syntax::ast::{local_crate, node_id, private, provided, required};
+use syntax::ast_map::{node_item, node_method};
 use ty::ty_class;
+use typeck::{method_map, method_origin, method_param, method_static};
+use typeck::{method_trait};
 
 use core::util::ignore;
 use dvec::DVec;
-use send_map::linear::LinearMap;
 
-fn check_crate(tcx: ty::ctxt, crate: @ast::crate) {
-    let privileged_structs = @DVec();
+fn check_crate(tcx: ty::ctxt, method_map: &method_map, crate: @ast::crate) {
+    let privileged_items = @DVec();
 
-    let add_privileged_structs = |items: &[@ast::item]| {
+    // Adds structs that are privileged to this scope.
+    let add_privileged_items = |items: &[@ast::item]| {
         let mut count = 0;
         for items.each |item| {
             match item.node {
-                item_class(*) => {
-                    privileged_structs.push(item.id);
+                item_class(*) | item_trait(*) | item_impl(*) => {
+                    privileged_items.push(item.id);
                     count += 1;
                 }
                 _ => {}
@@ -28,36 +31,143 @@ fn check_crate(tcx: ty::ctxt, crate: @ast::crate) {
         count
     };
 
+    // Checks that a private field is in scope.
+    let check_field = |span, id, ident| {
+        let fields = ty::lookup_class_fields(tcx, id);
+        for fields.each |field| {
+            if field.ident != ident { again; }
+            if field.vis == private {
+                tcx.sess.span_err(span, fmt!("field `%s` is private",
+                                             *tcx.sess.parse_sess.interner
+                                                 .get(ident)));
+            }
+            break;
+        }
+    };
+
+    // Checks that a private method is in scope.
+    let check_method = |span, origin: &method_origin| {
+        match *origin {
+            method_static(method_id) => {
+                if method_id.crate == local_crate {
+                    match tcx.items.find(method_id.node) {
+                        Some(node_method(method, impl_id, _)) => {
+                            if method.vis == private &&
+                                    (impl_id.crate != local_crate ||
+                                     !privileged_items
+                                     .contains(impl_id.node)) {
+                                tcx.sess.span_err(span,
+                                                  fmt!("method `%s` is \
+                                                        private",
+                                                       *tcx.sess
+                                                           .parse_sess
+                                                           .interner
+                                                           .get(method
+                                                                .ident)));
+                            }
+                        }
+                        Some(_) => {
+                            tcx.sess.span_bug(span, ~"method wasn't \
+                                                      actually a method?!");
+                        }
+                        None => {
+                            tcx.sess.span_bug(span, ~"method not found in \
+                                                      AST map?!");
+                        }
+                    }
+                } else {
+                    // XXX: External crates.
+                }
+            }
+            method_param({trait_id: trait_id, method_num: method_num, _}) |
+            method_trait(trait_id, method_num) => {
+                if trait_id.crate == local_crate {
+                    match tcx.items.find(trait_id.node) {
+                        Some(node_item(item, _)) => {
+                            match item.node {
+                                item_trait(_, _, methods) => {
+                                    if method_num >= methods.len() {
+                                        tcx.sess.span_bug(span, ~"method \
+                                                                  number \
+                                                                  out of \
+                                                                  range?!");
+                                    }
+                                    match methods[method_num] {
+                                        provided(method)
+                                                if method.vis == private &&
+                                                !privileged_items
+                                                .contains(trait_id.node) => {
+                                            tcx.sess.span_err(span,
+                                                              fmt!("method
+                                                                    `%s` \
+                                                                    is \
+                                                                    private",
+                                                                   *tcx
+                                                                   .sess
+                                                                   .parse_sess
+                                                                   .interner
+                                                                   .get
+                                                                   (method
+                                                                    .ident)));
+                                        }
+                                        provided(_) | required(_) => {
+                                            // Required methods can't be
+                                            // private.
+                                        }
+                                    }
+                                }
+                                _ => {
+                                    tcx.sess.span_bug(span, ~"trait wasn't \
+                                                              actually a \
+                                                              trait?!");
+                                }
+                            }
+                        }
+                        Some(_) => {
+                            tcx.sess.span_bug(span, ~"trait wasn't an \
+                                                      item?!");
+                        }
+                        None => {
+                            tcx.sess.span_bug(span, ~"trait item wasn't \
+                                                      found in the AST \
+                                                      map?!");
+                        }
+                    }
+                } else {
+                    // XXX: External crates.
+                }
+            }
+        }
+    };
+
     let visitor = visit::mk_vt(@{
-        visit_mod: |the_module, span, node_id, env, visitor| {
-            let n_added = add_privileged_structs(the_module.items);
+        visit_mod: |the_module, span, node_id, method_map, visitor| {
+            let n_added = add_privileged_items(the_module.items);
 
-            visit::visit_mod(the_module, span, node_id, env, visitor);
+            visit::visit_mod(the_module, span, node_id, method_map, visitor);
 
             for n_added.times {
-                ignore(privileged_structs.pop());
+                ignore(privileged_items.pop());
             }
         },
-        visit_expr: |expr, env, visitor| {
+        visit_expr: |expr, method_map: &method_map, visitor| {
             match expr.node {
                 expr_field(base, ident, _) => {
                     match ty::get(ty::expr_ty(tcx, base)).struct {
                         ty_class(id, _)
                         if id.crate != local_crate ||
-                           !privileged_structs.contains(id.node) => {
-                            let fields = ty::lookup_class_fields(tcx, id);
-                            for fields.each |field| {
-                                if field.ident != ident { again; }
-                                if field.vis == private {
-                                    tcx.sess.span_err(expr.span,
-                                                      fmt!("field `%s` is \
-                                                            private",
-                                                           *tcx.sess
-                                                               .parse_sess
-                                                               .interner
-                                                               .get(ident)));
+                           !privileged_items.contains(id.node) => {
+                            match method_map.find(expr.id) {
+                                None => {
+                                    debug!("(privacy checking) checking \
+                                            field");
+                                    check_field(expr.span, id, ident);
+                                }
+                                Some(entry) => {
+                                    debug!("(privacy checking) checking \
+                                            impl method");
+                                    check_method(expr.span, &entry.origin);
                                 }
-                                break;
                             }
                         }
                         _ => {}
@@ -66,10 +176,10 @@ fn check_crate(tcx: ty::ctxt, crate: @ast::crate) {
                 _ => {}
             }
 
-            visit::visit_expr(expr, env, visitor);
+            visit::visit_expr(expr, method_map, visitor);
         },
         .. *visit::default_visitor()
     });
-    visit::visit_crate(*crate, (), visitor);
+    visit::visit_crate(*crate, method_map, visitor);
 }
 
diff --git a/src/test/compile-fail/private-impl-method.rs b/src/test/compile-fail/private-impl-method.rs
new file mode 100644
index 00000000000..2d6047b3647
--- /dev/null
+++ b/src/test/compile-fail/private-impl-method.rs
@@ -0,0 +1,15 @@
+mod a {
+    struct Foo {
+        x: int
+    }
+
+    impl Foo {
+        priv fn foo() {}
+    }
+}
+
+fn main() {
+    let s = a::Foo { x: 1 };
+    s.foo();    //~ ERROR method `foo` is private
+}
+