diff options
| author | Patrick Walton <pcwalton@mimiga.net> | 2012-09-04 18:28:22 -0700 |
|---|---|---|
| committer | Patrick Walton <pcwalton@mimiga.net> | 2012-09-04 18:30:27 -0700 |
| commit | fba673b26bc029ef234f56e177559fd0b9e48507 (patch) | |
| tree | 2a21c1ea78a14b76233af8ec4da4852f21bdd4a3 | |
| parent | a618d0d7ce913e5c7f1393561149ada6f7c32ff3 (diff) | |
| download | rust-fba673b26bc029ef234f56e177559fd0b9e48507.tar.gz rust-fba673b26bc029ef234f56e177559fd0b9e48507.zip | |
rustc: Implement private methods.
Doesn't work cross-crate yet.
| -rw-r--r-- | src/libsyntax/ast.rs | 3 | ||||
| -rw-r--r-- | src/libsyntax/parse/parser.rs | 3 | ||||
| -rw-r--r-- | src/rustc/driver/driver.rs | 2 | ||||
| -rw-r--r-- | src/rustc/middle/privacy.rs | 166 | ||||
| -rw-r--r-- | src/test/compile-fail/private-impl-method.rs | 15 |
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 +} + |
