diff options
| author | Tim Chevalier <chevalier@alum.wellesley.edu> | 2012-03-28 14:17:41 -0700 |
|---|---|---|
| committer | Tim Chevalier <chevalier@alum.wellesley.edu> | 2012-03-28 14:19:00 -0700 |
| commit | ca6636d6b689fe209a210b0eda51e368f01cdb0f (patch) | |
| tree | 7c979884781d3179bb918045f414426eb6158cea | |
| parent | c141e7a068e3fbb1a5d24dcd000567b7731910bb (diff) | |
| download | rust-ca6636d6b689fe209a210b0eda51e368f01cdb0f.tar.gz rust-ca6636d6b689fe209a210b0eda51e368f01cdb0f.zip | |
Allow references to "self" within classes
Allow writing self.f within a class that has a field f. Currently, the compiler accepts either self.f or f. In a future commit I'll require writing self.f and not f. Not sure whether self.f() works if f is a method (making sure that works next).
| -rw-r--r-- | src/rustc/middle/alias.rs | 2 | ||||
| -rw-r--r-- | src/rustc/middle/mutbl.rs | 39 | ||||
| -rw-r--r-- | src/rustc/middle/resolve.rs | 14 | ||||
| -rw-r--r-- | src/rustc/middle/typeck.rs | 53 | ||||
| -rw-r--r-- | src/rustc/syntax/ast.rs | 1 | ||||
| -rw-r--r-- | src/rustc/syntax/parse/parser.rs | 4 | ||||
| -rw-r--r-- | src/test/run-pass/classes-simple.rs | 2 |
7 files changed, 82 insertions, 33 deletions
diff --git a/src/rustc/middle/alias.rs b/src/rustc/middle/alias.rs index 3fe17f96bbd..5ad5d42896f 100644 --- a/src/rustc/middle/alias.rs +++ b/src/rustc/middle/alias.rs @@ -647,7 +647,7 @@ fn pattern_roots(tcx: ty::ctxt, mutbl: option<unsafe_ty>, pat: @ast::pat) // return-by-reference fn expr_root(cx: ctx, ex: @ast::expr, autoderef: bool) -> {ex: @ast::expr, mutbl: option<unsafe_ty>} { - let base_root = mutbl::expr_root(cx.tcx, ex, autoderef); + let base_root = mutbl::expr_root_(cx.tcx, none, ex, autoderef); let mut unsafe_ty = none; for d in *base_root.ds { if d.mutbl { unsafe_ty = some(contains(d.outer_t)); break; } diff --git a/src/rustc/middle/mutbl.rs b/src/rustc/middle/mutbl.rs index 8bebb3b5e68..be06a16a0dc 100644 --- a/src/rustc/middle/mutbl.rs +++ b/src/rustc/middle/mutbl.rs @@ -12,7 +12,13 @@ type deref = @{mutbl: bool, kind: deref_t, outer_t: ty::t}; // vec of dereferences that were used on this root. Note that, in this vec, // the inner derefs come in front, so foo.bar[1] becomes rec(ex=foo, // ds=[index,field]) -fn expr_root(tcx: ty::ctxt, ex: @expr, autoderef: bool) -> +fn expr_root(cx: @ctx, ex: @expr, autoderef: bool) + -> {ex: @expr, ds: @[deref]} { + expr_root_(cx.tcx, cx.in_ctor, ex, autoderef) +} + +fn expr_root_(tcx: ty::ctxt, ctor_self: option<node_id>, + ex: @expr, autoderef: bool) -> {ex: @expr, ds: @[deref]} { fn maybe_auto_unbox(tcx: ty::ctxt, t: ty::t) -> {t: ty::t, ds: [deref]} { let mut ds = [], t = t; @@ -58,13 +64,23 @@ fn expr_root(tcx: ty::ctxt, ex: @expr, autoderef: bool) -> } } ty::ty_class(did, _) { - util::common::log_expr(*ex); + util::common::log_expr(*base); + let in_self = alt ctor_self { + some(selfid) { + alt tcx.def_map.find(base.id) { + some(def_self(slfid)) { slfid == selfid } + _ { false } + } + } + none { false } + }; for fld: ty::field_ty in ty::lookup_class_fields(tcx, did) { - #debug("%s %?", fld.ident, fld.mutability); if str::eq(ident, fld.ident) { - is_mutbl = fld.mutability == class_mutable; + is_mutbl = fld.mutability == class_mutable + || in_self; // all fields can be mutated + // in the ctor + break; } - break; } } _ {} @@ -126,10 +142,11 @@ fn expr_root(tcx: ty::ctxt, ex: @expr, autoderef: bool) -> type mutbl_map = std::map::hashmap<node_id, ()>; // Keep track of whether we're inside a ctor, so as to // allow mutating immutable fields in the same class -type ctx = {tcx: ty::ctxt, mutbl_map: mutbl_map, in_ctor: bool}; +// if we are in a ctor, we track the self id +type ctx = {tcx: ty::ctxt, mutbl_map: mutbl_map, in_ctor: option<node_id>}; fn check_crate(tcx: ty::ctxt, crate: @crate) -> mutbl_map { - let cx = @{tcx: tcx, mutbl_map: std::map::int_hash(), in_ctor: false}; + let cx = @{tcx: tcx, mutbl_map: std::map::int_hash(), in_ctor: none}; let v = @{visit_expr: visit_expr, visit_decl: visit_decl, visit_item: visit_item @@ -204,7 +221,7 @@ fn visit_item(item: @item, &&cx: @ctx, v: visit::vt<@ctx>) { i.node.privacy, i.node.decl, cx, v); }); v.visit_fn(visit::fk_ctor(item.ident, tps), ctor.node.dec, ctor.node.body, ctor.span, ctor.node.id, - @{in_ctor: true with *cx}, v); + @{in_ctor: some(ctor.node.self_id) with *cx}, v); } _ { visit::visit_item(item, cx, v); } } @@ -221,7 +238,7 @@ fn check_lval(cx: @ctx, dest: @expr, msg: msg) { cx.mutbl_map.insert(ast_util::def_id_of_def(def).node, ()); } _ { - let root = expr_root(cx.tcx, dest, false); + let root = expr_root(cx, dest, false); if vec::len(*root.ds) == 0u { if msg != msg_move_out { mk_err(cx, dest.span, msg, "non-lvalue"); @@ -251,7 +268,7 @@ fn check_move_rhs(cx: @ctx, src: @expr) { check_lval(cx, src, msg_move_out); } _ { - let root = expr_root(cx.tcx, src, false); + let root = expr_root(cx, src, false); // Not a path and no-derefs means this is a temporary. if vec::len(*root.ds) != 0u && @@ -339,7 +356,7 @@ fn is_illegal_to_modify_def(cx: @ctx, def: def, msg: msg) -> option<str> { def_binding(_) { some("binding") } def_class_field(parent,fld) { - if !cx.in_ctor { + if option::is_none(cx.in_ctor) { /* Enforce mutability *unless* we're inside a ctor */ alt ty::lookup_class_field(cx.tcx, parent, fld).mutability { class_mutable { none } diff --git a/src/rustc/middle/resolve.rs b/src/rustc/middle/resolve.rs index 712ccbf02af..91aac1c7d6a 100644 --- a/src/rustc/middle/resolve.rs +++ b/src/rustc/middle/resolve.rs @@ -523,17 +523,23 @@ fn visit_item_with_scope(e: @env, i: @ast::item, sc: scopes, v: vt<scopes>) { } ast::item_class(tps, members, ctor) { visit::visit_ty_params(tps, sc, v); + // Can maybe skip this now that we require self on class fields let class_scope = cons(scope_item(i), @sc); /* visit the constructor... */ + let ctor_scope = cons(scope_method(ctor.node.self_id, tps), + @class_scope); visit_fn_with_scope(e, visit::fk_item_fn(i.ident, tps), ctor.node.dec, ctor.node.body, ctor.span, ctor.node.id, - class_scope, v); + ctor_scope, v); /* visit the items */ for cm in members { alt cm.node.decl { - class_method(m) { visit_fn_with_scope(e, - visit::fk_item_fn(m.ident, tps), m.decl, m.body, - m.span, m.id, class_scope, v); } + class_method(m) { + let msc = cons(scope_method(m.self_id, tps + m.tps), + @class_scope); + visit_fn_with_scope(e, + visit::fk_item_fn(m.ident, tps), m.decl, m.body, + m.span, m.id, msc, v); } instance_var(_,t,_,_) { v.visit_ty(t, class_scope, v); } } } diff --git a/src/rustc/middle/typeck.rs b/src/rustc/middle/typeck.rs index 721b846e052..63a30f02434 100644 --- a/src/rustc/middle/typeck.rs +++ b/src/rustc/middle/typeck.rs @@ -49,7 +49,9 @@ type vtable_map = hashmap<ast::node_id, vtable_res>; type ty_table = hashmap<ast::def_id, ty::t>; // Used for typechecking the methods of an impl -enum self_info { self_impl(ty::t) } +// first field is the self type, second is the ID for the "self" object +// that's currently in scope +enum self_info { self_impl(ty::t, ast::node_id) } type crate_ctxt = {mut self_infos: [self_info], impl_map: resolve::impl_map, @@ -117,7 +119,7 @@ fn ty_param_bounds_and_ty_for_def(fcx: @fn_ctxt, sp: span, defn: ast::def) -> } ast::def_self(_) { alt get_self_info(fcx.ccx) { - some(self_impl(impl_t)) { + some(self_impl(impl_t,_)) { ret {bounds: @[], ty: impl_t}; } none { @@ -3128,20 +3130,28 @@ fn check_expr_with_unifier(fcx: @fn_ctxt, expr: @ast::expr, unify: unifier, // field #debug("class named %s", ty_to_str(tcx, base_t)); /* - This is an external reference, so only consider public - fields + check whether this is a self-reference or not, which + determines whether we look at all fields or only public + ones */ - let cls_items = lookup_public_fields(tcx, base_id); - #debug("cls_items: %?", cls_items); - alt lookup_field_ty(tcx, base_id, cls_items, field) { + let node_def = lookup_def(fcx, base.span, base.id); + let cls_items = alt get_self_info(fcx.ccx) { + some(self_impl(_, n_id)) if alt node_def { + ast::def_self(base_id) { base_id == n_id } + _ { false }} { + // base expr is "self" -- consider all fields + ty::lookup_class_fields(tcx, base_id) + } + _ { lookup_public_fields(tcx, base_id) } + }; + alt lookup_field_ty(tcx, base_id, cls_items, field) { some(field_ty) { - #debug("a"); // (2) look up what field's type is, and return it // FIXME: actually instantiate any type params write_ty(tcx, id, field_ty); handled = true; } - none { #debug("b"); } + none {} } } _ {} @@ -3659,11 +3669,16 @@ fn class_types(ccx: @crate_ctxt, members: [@ast::class_item]) -> class_map { rslt } -fn check_class_member(ccx: @crate_ctxt, cm: ast::class_member) { +fn check_class_member(ccx: @crate_ctxt, class_t: ty::t, + cm: ast::class_member) { alt cm { ast::instance_var(_,t,_,_) { } - ast::class_method(m) { check_method(ccx, m); } + ast::class_method(m) { + ccx.self_infos += [self_impl(class_t, m.self_id)]; + check_method(ccx, m); + vec::pop(ccx.self_infos); + } } } @@ -3681,20 +3696,28 @@ fn check_item(ccx: @crate_ctxt, it: @ast::item) { let mut self_ty = ast_ty_to_ty(ccx.tcx, m_check, ty); let self_region = ty::re_self; self_ty = instantiate_self_regions(ccx.tcx, self_region, self_ty); - ccx.self_infos += [self_impl(self_ty)]; - for m in ms { check_method(ccx, m); } - vec::pop(ccx.self_infos); + for m in ms { + ccx.self_infos += [self_impl(self_ty, m.id)]; + check_method(ccx, m); + vec::pop(ccx.self_infos); + } } ast::item_class(tps, members, ctor) { let cid = some(it.id); + let class_t = node_id_to_type(ccx.tcx, it.id); let members_info = class_types(ccx, members); + // can also ditch the enclosing_class stuff once we move to self + // FIXME let class_ccx = @{enclosing_class_id:cid, enclosing_class:members_info with *ccx}; + class_ccx.self_infos += [self_impl(class_t, ctor.node.self_id)]; // typecheck the ctor check_fn(class_ccx, ast::proto_bare, ctor.node.dec, ctor.node.body, ctor.node.id, false, none); + vec::pop(class_ccx.self_infos); // typecheck the members - for m in members { check_class_member(class_ccx, m.node.decl); } + for m in members { check_class_member(class_ccx, class_t, + m.node.decl); } } _ {/* nothing to do */ } } diff --git a/src/rustc/syntax/ast.rs b/src/rustc/syntax/ast.rs index 95c5b607cd4..447d754895e 100644 --- a/src/rustc/syntax/ast.rs +++ b/src/rustc/syntax/ast.rs @@ -684,6 +684,7 @@ type class_ctor = spanned<class_ctor_>; #[auto_serialize] type class_ctor_ = {id: node_id, + self_id: node_id, dec: fn_decl, body: blk}; diff --git a/src/rustc/syntax/parse/parser.rs b/src/rustc/syntax/parse/parser.rs index 3ca2e6a588b..61cc675c492 100644 --- a/src/rustc/syntax/parse/parser.rs +++ b/src/rustc/syntax/parse/parser.rs @@ -2092,10 +2092,12 @@ fn parse_item_class(p: parser, attrs: [ast::attribute]) -> @ast::item { } p.bump(); alt the_ctor { - some((ct_d, ct_b, ct_s)) { ret mk_item(p, lo, p.last_span.hi, + some((ct_d, ct_b, ct_s)) { + ret mk_item(p, lo, p.last_span.hi, class_name, ast::item_class(ty_params, items, {node: {id: ctor_id, + self_id: p.get_id(), dec: ct_d, body: ct_b}, span: ct_s}), attrs); } diff --git a/src/test/run-pass/classes-simple.rs b/src/test/run-pass/classes-simple.rs index bb0384f902e..ae37fb9a997 100644 --- a/src/test/run-pass/classes-simple.rs +++ b/src/test/run-pass/classes-simple.rs @@ -5,7 +5,7 @@ class cat { let how_hungry : int; - new(in_x : uint, in_y : int) { meows = in_x; how_hungry = in_y; } + new(in_x : uint, in_y : int) { self.meows = in_x; self.how_hungry = in_y; } } fn main() { |
