Skip to content

Commit fba673b

Browse files
committed
rustc: Implement private methods.
Doesn't work cross-crate yet.
1 parent a618d0d commit fba673b

File tree

5 files changed

+157
-32
lines changed

5 files changed

+157
-32
lines changed

src/libsyntax/ast.rs

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1041,8 +1041,7 @@ type method = {ident: ident, attrs: ~[attribute],
10411041
tps: ~[ty_param], self_ty: self_ty,
10421042
purity: purity, decl: fn_decl, body: blk,
10431043
id: node_id, span: span, self_id: node_id,
1044-
vis: visibility}; // always public, unless it's a
1045-
// class method
1044+
vis: visibility};
10461045

10471046
#[auto_serialize]
10481047
type _mod = {view_items: ~[@view_item], items: ~[@item]};

src/libsyntax/parse/parser.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2533,7 +2533,8 @@ struct parser {
25332533
let mut meths = ~[];
25342534
self.expect(token::LBRACE);
25352535
while !self.eat(token::RBRACE) {
2536-
vec::push(meths, self.parse_method(public));
2536+
let vis = self.parse_visibility();
2537+
vec::push(meths, self.parse_method(vis));
25372538
}
25382539
(ident, item_impl(tps, traits, ty, meths), None)
25392540
}

src/rustc/driver/driver.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -222,7 +222,7 @@ fn compile_upto(sess: session, cfg: ast::crate_cfg,
222222
if upto == cu_typeck { return {crate: crate, tcx: Some(ty_cx)}; }
223223

224224
time(time_passes, ~"privacy checking", ||
225-
middle::privacy::check_crate(ty_cx, crate));
225+
middle::privacy::check_crate(ty_cx, &method_map, crate));
226226

227227
time(time_passes, ~"loop checking", ||
228228
middle::check_loop::check_crate(ty_cx, crate));

src/rustc/middle/privacy.rs

Lines changed: 138 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -3,23 +3,26 @@
33

44
use /*mod*/ syntax::ast;
55
use /*mod*/ syntax::visit;
6-
use syntax::ast::{expr_field, ident, item_class, local_crate, node_id};
7-
use syntax::ast::{private};
6+
use syntax::ast::{expr_field, ident, item_class, item_impl, item_trait};
7+
use syntax::ast::{local_crate, node_id, private, provided, required};
8+
use syntax::ast_map::{node_item, node_method};
89
use ty::ty_class;
10+
use typeck::{method_map, method_origin, method_param, method_static};
11+
use typeck::{method_trait};
912

1013
use core::util::ignore;
1114
use dvec::DVec;
12-
use send_map::linear::LinearMap;
1315

14-
fn check_crate(tcx: ty::ctxt, crate: @ast::crate) {
15-
let privileged_structs = @DVec();
16+
fn check_crate(tcx: ty::ctxt, method_map: &method_map, crate: @ast::crate) {
17+
let privileged_items = @DVec();
1618

17-
let add_privileged_structs = |items: &[@ast::item]| {
19+
// Adds structs that are privileged to this scope.
20+
let add_privileged_items = |items: &[@ast::item]| {
1821
let mut count = 0;
1922
for items.each |item| {
2023
match item.node {
21-
item_class(*) => {
22-
privileged_structs.push(item.id);
24+
item_class(*) | item_trait(*) | item_impl(*) => {
25+
privileged_items.push(item.id);
2326
count += 1;
2427
}
2528
_ => {}
@@ -28,36 +31,143 @@ fn check_crate(tcx: ty::ctxt, crate: @ast::crate) {
2831
count
2932
};
3033

34+
// Checks that a private field is in scope.
35+
let check_field = |span, id, ident| {
36+
let fields = ty::lookup_class_fields(tcx, id);
37+
for fields.each |field| {
38+
if field.ident != ident { again; }
39+
if field.vis == private {
40+
tcx.sess.span_err(span, fmt!("field `%s` is private",
41+
*tcx.sess.parse_sess.interner
42+
.get(ident)));
43+
}
44+
break;
45+
}
46+
};
47+
48+
// Checks that a private method is in scope.
49+
let check_method = |span, origin: &method_origin| {
50+
match *origin {
51+
method_static(method_id) => {
52+
if method_id.crate == local_crate {
53+
match tcx.items.find(method_id.node) {
54+
Some(node_method(method, impl_id, _)) => {
55+
if method.vis == private &&
56+
(impl_id.crate != local_crate ||
57+
!privileged_items
58+
.contains(impl_id.node)) {
59+
tcx.sess.span_err(span,
60+
fmt!("method `%s` is \
61+
private",
62+
*tcx.sess
63+
.parse_sess
64+
.interner
65+
.get(method
66+
.ident)));
67+
}
68+
}
69+
Some(_) => {
70+
tcx.sess.span_bug(span, ~"method wasn't \
71+
actually a method?!");
72+
}
73+
None => {
74+
tcx.sess.span_bug(span, ~"method not found in \
75+
AST map?!");
76+
}
77+
}
78+
} else {
79+
// XXX: External crates.
80+
}
81+
}
82+
method_param({trait_id: trait_id, method_num: method_num, _}) |
83+
method_trait(trait_id, method_num) => {
84+
if trait_id.crate == local_crate {
85+
match tcx.items.find(trait_id.node) {
86+
Some(node_item(item, _)) => {
87+
match item.node {
88+
item_trait(_, _, methods) => {
89+
if method_num >= methods.len() {
90+
tcx.sess.span_bug(span, ~"method \
91+
number \
92+
out of \
93+
range?!");
94+
}
95+
match methods[method_num] {
96+
provided(method)
97+
if method.vis == private &&
98+
!privileged_items
99+
.contains(trait_id.node) => {
100+
tcx.sess.span_err(span,
101+
fmt!("method
102+
`%s` \
103+
is \
104+
private",
105+
*tcx
106+
.sess
107+
.parse_sess
108+
.interner
109+
.get
110+
(method
111+
.ident)));
112+
}
113+
provided(_) | required(_) => {
114+
// Required methods can't be
115+
// private.
116+
}
117+
}
118+
}
119+
_ => {
120+
tcx.sess.span_bug(span, ~"trait wasn't \
121+
actually a \
122+
trait?!");
123+
}
124+
}
125+
}
126+
Some(_) => {
127+
tcx.sess.span_bug(span, ~"trait wasn't an \
128+
item?!");
129+
}
130+
None => {
131+
tcx.sess.span_bug(span, ~"trait item wasn't \
132+
found in the AST \
133+
map?!");
134+
}
135+
}
136+
} else {
137+
// XXX: External crates.
138+
}
139+
}
140+
}
141+
};
142+
31143
let visitor = visit::mk_vt(@{
32-
visit_mod: |the_module, span, node_id, env, visitor| {
33-
let n_added = add_privileged_structs(the_module.items);
144+
visit_mod: |the_module, span, node_id, method_map, visitor| {
145+
let n_added = add_privileged_items(the_module.items);
34146
35-
visit::visit_mod(the_module, span, node_id, env, visitor);
147+
visit::visit_mod(the_module, span, node_id, method_map, visitor);
36148
37149
for n_added.times {
38-
ignore(privileged_structs.pop());
150+
ignore(privileged_items.pop());
39151
}
40152
},
41-
visit_expr: |expr, env, visitor| {
153+
visit_expr: |expr, method_map: &method_map, visitor| {
42154
match expr.node {
43155
expr_field(base, ident, _) => {
44156
match ty::get(ty::expr_ty(tcx, base)).struct {
45157
ty_class(id, _)
46158
if id.crate != local_crate ||
47-
!privileged_structs.contains(id.node) => {
48-
let fields = ty::lookup_class_fields(tcx, id);
49-
for fields.each |field| {
50-
if field.ident != ident { again; }
51-
if field.vis == private {
52-
tcx.sess.span_err(expr.span,
53-
fmt!("field `%s` is \
54-
private",
55-
*tcx.sess
56-
.parse_sess
57-
.interner
58-
.get(ident)));
159+
!privileged_items.contains(id.node) => {
160+
match method_map.find(expr.id) {
161+
None => {
162+
debug!("(privacy checking) checking \
163+
field");
164+
check_field(expr.span, id, ident);
165+
}
166+
Some(entry) => {
167+
debug!("(privacy checking) checking \
168+
impl method");
169+
check_method(expr.span, &entry.origin);
59170
}
60-
break;
61171
}
62172
}
63173
_ => {}
@@ -66,10 +176,10 @@ fn check_crate(tcx: ty::ctxt, crate: @ast::crate) {
66176
_ => {}
67177
}
68178

69-
visit::visit_expr(expr, env, visitor);
179+
visit::visit_expr(expr, method_map, visitor);
70180
},
71181
.. *visit::default_visitor()
72182
});
73-
visit::visit_crate(*crate, (), visitor);
183+
visit::visit_crate(*crate, method_map, visitor);
74184
}
75185

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
mod a {
2+
struct Foo {
3+
x: int
4+
}
5+
6+
impl Foo {
7+
priv fn foo() {}
8+
}
9+
}
10+
11+
fn main() {
12+
let s = a::Foo { x: 1 };
13+
s.foo(); //~ ERROR method `foo` is private
14+
}
15+

0 commit comments

Comments
 (0)