rustc: Implement private fields for max/min classes

This commit is contained in:
Patrick Walton 2012-09-04 14:48:32 -07:00
parent 8182497359
commit 127144bf38
9 changed files with 98 additions and 38 deletions

View File

@ -221,6 +221,9 @@ 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));
time(time_passes, ~"loop checking", ||
middle::check_loop::check_crate(ty_cx, crate));

View File

@ -0,0 +1,75 @@
// A pass that checks to make sure private fields and methods aren't used
// outside their scopes.
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 ty::ty_class;
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();
let add_privileged_structs = |items: &[@ast::item]| {
let mut count = 0;
for items.each |item| {
match item.node {
item_class(*) => {
privileged_structs.push(item.id);
count += 1;
}
_ => {}
}
}
count
};
let visitor = visit::mk_vt(@{
visit_mod: |the_module, span, node_id, env, visitor| {
let n_added = add_privileged_structs(the_module.items);
visit::visit_mod(the_module, span, node_id, env, visitor);
for n_added.times {
ignore(privileged_structs.pop());
}
},
visit_expr: |expr, env, 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)));
}
break;
}
}
_ => {}
}
}
_ => {}
}
visit::visit_expr(expr, env, visitor);
}
with *visit::default_visitor()
});
visit::visit_crate(*crate, (), visitor);
}

View File

@ -3160,10 +3160,6 @@ fn lookup_class_field(cx: ctxt, parent: ast::def_id, field_id: ast::def_id)
}
}
fn lookup_public_fields(cx: ctxt, did: ast::def_id) -> ~[field_ty] {
vec::filter(lookup_class_fields(cx, did), is_public)
}
pure fn is_public(f: field_ty) -> bool {
// XXX: This is wrong.
match f.vis {

View File

@ -51,9 +51,8 @@ use util::common::may_break;
use syntax::codemap::span;
use pat_util::{pat_is_variant, pat_id_map};
use middle::ty;
use middle::ty::{arg, field, node_type_table, mk_nil,
ty_param_bounds_and_ty, lookup_public_fields,
vstore_uniq};
use middle::ty::{arg, field, node_type_table, mk_nil, ty_param_bounds_and_ty};
use middle::ty::{vstore_uniq};
use std::smallintmap;
use std::map;
use std::map::{hashmap, int_hash};

View File

@ -1317,18 +1317,7 @@ fn check_expr_with_unifier(fcx: @fn_ctxt,
// (1) verify that the class id actually has a field called
// field
debug!("class named %s", ty_to_str(tcx, base_t));
/*
check whether this is a self-reference or not, which
determines whether we look at all fields or only public
ones
*/
let cls_items = if self_ref(fcx, base.id) {
// base expr is "self" -- consider all fields
ty::lookup_class_fields(tcx, base_id)
}
else {
lookup_public_fields(tcx, base_id)
};
let cls_items = ty::lookup_class_fields(tcx, base_id);
match lookup_field_ty(tcx, base_id, cls_items, field, &substs) {
Some(field_ty) => {
// (2) look up what field's type is, and return it
@ -1370,8 +1359,7 @@ fn check_expr_with_unifier(fcx: @fn_ctxt,
let msg =
fmt!(
"attempted access of field `%s` on type `%s`, \
but no public field or method with that name \
was found",
but no field or method with that name was found",
tcx.sess.str_of(field),
fcx.infcx().ty_to_str(t_err));
tcx.sess.span_err(expr.span, msg);

View File

@ -102,6 +102,7 @@ mod middle {
mod const_eval;
mod astencode;
mod lang_items;
mod privacy;
}
mod front {

View File

@ -1,15 +0,0 @@
// error-pattern:no public field or method with that name
struct cat {
priv {
let mut meows : uint;
}
let how_hungry : int;
new(in_x : uint, in_y : int) { self.meows = in_x; self.how_hungry = in_y; }
}
fn main() {
let nyan : cat = cat(52u, 99);
assert (nyan.meows == 52u);
}

View File

@ -1,4 +1,3 @@
// error-pattern:no public field or method with that name
// xfail-fast
// aux-build:cci_class.rs
use cci_class;
@ -6,5 +5,5 @@ import cci_class::kitties::*;
fn main() {
let nyan : cat = cat(52u, 99);
assert (nyan.meows == 52u);
assert (nyan.meows == 52u); //~ ERROR field `meows` is private
}

View File

@ -0,0 +1,14 @@
mod cat {
struct Cat {
priv meows: uint;
}
fn new_cat() -> Cat {
Cat { meows: 52 }
}
}
fn main() {
let nyan = cat::new_cat();
assert nyan.meows == 52; //~ ERROR field `meows` is private
}