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)}; }
|
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", ||
|
time(time_passes, ~"loop checking", ||
|
||||||
middle::check_loop::check_crate(ty_cx, crate));
|
middle::check_loop::check_crate(ty_cx, crate));
|
||||||
|
|
||||||
|
75
src/rustc/middle/privacy.rs
Normal file
75
src/rustc/middle/privacy.rs
Normal 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);
|
||||||
|
}
|
||||||
|
|
@ -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 {
|
pure fn is_public(f: field_ty) -> bool {
|
||||||
// XXX: This is wrong.
|
// XXX: This is wrong.
|
||||||
match f.vis {
|
match f.vis {
|
||||||
|
@ -51,9 +51,8 @@ use util::common::may_break;
|
|||||||
use syntax::codemap::span;
|
use syntax::codemap::span;
|
||||||
use pat_util::{pat_is_variant, pat_id_map};
|
use pat_util::{pat_is_variant, pat_id_map};
|
||||||
use middle::ty;
|
use middle::ty;
|
||||||
use middle::ty::{arg, field, node_type_table, mk_nil,
|
use middle::ty::{arg, field, node_type_table, mk_nil, ty_param_bounds_and_ty};
|
||||||
ty_param_bounds_and_ty, lookup_public_fields,
|
use middle::ty::{vstore_uniq};
|
||||||
vstore_uniq};
|
|
||||||
use std::smallintmap;
|
use std::smallintmap;
|
||||||
use std::map;
|
use std::map;
|
||||||
use std::map::{hashmap, int_hash};
|
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
|
// (1) verify that the class id actually has a field called
|
||||||
// field
|
// field
|
||||||
debug!("class named %s", ty_to_str(tcx, base_t));
|
debug!("class named %s", ty_to_str(tcx, base_t));
|
||||||
/*
|
let cls_items = ty::lookup_class_fields(tcx, base_id);
|
||||||
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)
|
|
||||||
};
|
|
||||||
match lookup_field_ty(tcx, base_id, cls_items, field, &substs) {
|
match lookup_field_ty(tcx, base_id, cls_items, field, &substs) {
|
||||||
Some(field_ty) => {
|
Some(field_ty) => {
|
||||||
// (2) look up what field's type is, and return it
|
// (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 =
|
let msg =
|
||||||
fmt!(
|
fmt!(
|
||||||
"attempted access of field `%s` on type `%s`, \
|
"attempted access of field `%s` on type `%s`, \
|
||||||
but no public field or method with that name \
|
but no field or method with that name was found",
|
||||||
was found",
|
|
||||||
tcx.sess.str_of(field),
|
tcx.sess.str_of(field),
|
||||||
fcx.infcx().ty_to_str(t_err));
|
fcx.infcx().ty_to_str(t_err));
|
||||||
tcx.sess.span_err(expr.span, msg);
|
tcx.sess.span_err(expr.span, msg);
|
||||||
|
@ -102,6 +102,7 @@ mod middle {
|
|||||||
mod const_eval;
|
mod const_eval;
|
||||||
mod astencode;
|
mod astencode;
|
||||||
mod lang_items;
|
mod lang_items;
|
||||||
|
mod privacy;
|
||||||
}
|
}
|
||||||
|
|
||||||
mod front {
|
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
|
// xfail-fast
|
||||||
// aux-build:cci_class.rs
|
// aux-build:cci_class.rs
|
||||||
use cci_class;
|
use cci_class;
|
||||||
@ -6,5 +5,5 @@ import cci_class::kitties::*;
|
|||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
let nyan : cat = cat(52u, 99);
|
let nyan : cat = cat(52u, 99);
|
||||||
assert (nyan.meows == 52u);
|
assert (nyan.meows == 52u); //~ ERROR field `meows` is private
|
||||||
}
|
}
|
14
src/test/compile-fail/private-struct-field.rs
Normal file
14
src/test/compile-fail/private-struct-field.rs
Normal 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
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user