rustc: Implement private fields for max/min classes
This commit is contained in:
parent
8182497359
commit
127144bf38
|
@ -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));
|
||||
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
@ -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 {
|
||||
|
|
|
@ -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};
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -102,6 +102,7 @@ mod middle {
|
|||
mod const_eval;
|
||||
mod astencode;
|
||||
mod lang_items;
|
||||
mod privacy;
|
||||
}
|
||||
|
||||
mod front {
|
||||
|
|
|
@ -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);
|
||||
}
|
|
@ -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
|
||||
}
|
|
@ -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
|
||||
}
|
Loading…
Reference in New Issue