Make uses of self in impls compile

Get rid of expr_self_call, introduces def_self. `self` is now,
syntactically, simply a variable. A method implicitly brings a `self`
binding into scope.

Issue #1227
This commit is contained in:
Marijn Haverbeke 2011-12-14 15:23:11 +01:00
parent 1dd2f1ec03
commit 7efef98901
17 changed files with 137 additions and 203 deletions

View File

@ -240,7 +240,7 @@ fn check_call(cx: ctx, sc: scope, f: @ast::expr, args: [@ast::expr])
}
let f_may_close =
alt f.node {
ast::expr_path(_) { def_is_local(cx.tcx.def_map.get(f.id), true) }
ast::expr_path(_) { def_is_local(cx.tcx.def_map.get(f.id)) }
_ { true }
};
if f_may_close {
@ -374,7 +374,7 @@ fn check_for(cx: ctx, local: @ast::local, seq: @ast::expr, blk: ast::blk,
fn check_var(cx: ctx, ex: @ast::expr, p: @ast::path, id: ast::node_id,
assign: bool, sc: scope) {
let def = cx.tcx.def_map.get(id);
if !def_is_local(def, false) { ret; }
if !def_is_local(def) { ret; }
let my_defnum = ast_util::def_id_of_def(def).node;
let my_local_id = local_id_of_node(cx, my_defnum);
let var_t = ty::expr_ty(cx.tcx, ex);
@ -529,20 +529,19 @@ fn ty_can_unsafely_include(cx: ctx, needle: unsafe_ty, haystack: ty::t,
ret helper(cx.tcx, needle, haystack, mut);
}
fn def_is_local(d: ast::def, objfields_count: bool) -> bool {
ret alt d {
ast::def_local(_, _) | ast::def_arg(_, _) | ast::def_binding(_) |
ast::def_upvar(_, _, _) | ast::def_self(_) {
true
}
ast::def_obj_field(_, _) { objfields_count }
_ { false }
};
fn def_is_local(d: ast::def) -> bool {
alt d {
ast::def_local(_, _) | ast::def_arg(_, _) | ast::def_binding(_) |
ast::def_upvar(_, _, _) | ast::def_self(_) |
ast::def_obj_field(_, _) { true }
_ { false }
}
}
fn local_id_of_node(cx: ctx, id: node_id) -> uint {
alt cx.tcx.items.get(id) {
ast_map::node_arg(_, id) | ast_map::node_local(id) { id }
alt cx.tcx.items.find(id) {
some(ast_map::node_arg(_, id)) | some(ast_map::node_local(id)) { id }
_ { 0u }
}
}

View File

@ -203,6 +203,9 @@ fn check_move_rhs(cx: @ctx, src: @expr) {
def_obj_field(_, _) {
mk_err(cx, src.span, msg_move_out, "object field");
}
def_self(_) {
mk_err(cx, src.span, msg_move_out, "method self");
}
_ { }
}
check_lval(cx, src, msg_move_out);

View File

@ -37,6 +37,7 @@ tag scope {
scope_loop(@ast::local); // there's only 1 decl per loop.
scope_block(ast::blk, @mutable uint, @mutable uint);
scope_arm(ast::arm);
scope_self(ast::node_id);
}
type scopes = list<scope>;
@ -437,6 +438,9 @@ fn visit_expr_with_scope(x: @ast::expr, sc: scopes, v: vt<scopes>) {
v.visit_local(decl, new_sc, v);
v.visit_block(blk, new_sc, v);
}
ast::expr_anon_obj(_) {
visit::visit_expr(x, cons(scope_self(x.id), @sc), v);
}
_ { visit::visit_expr(x, sc, v); }
}
}
@ -723,7 +727,10 @@ fn def_is_local(d: def) -> bool {
}
fn def_is_obj_field(d: def) -> bool {
ret alt d { ast::def_obj_field(_, _) { true } _ { false } };
alt d {
ast::def_obj_field(_, _) | ast::def_self(_) { true }
_ { false }
}
}
fn def_is_ty_arg(d: def) -> bool {
@ -741,7 +748,7 @@ fn lookup_in_scope(e: env, sc: scopes, sp: span, name: ident, ns: namespace)
scope_item(it) {
alt it.node {
ast::item_obj(ob, ty_params, _) {
ret lookup_in_obj(name, ob, ty_params, ns);
ret lookup_in_obj(name, ob, ty_params, ns, it.id);
}
ast::item_impl(_, _, _) {
if (name == "self" && ns == ns_value) {
@ -763,6 +770,11 @@ fn lookup_in_scope(e: env, sc: scopes, sp: span, name: ident, ns: namespace)
_ { }
}
}
scope_self(id) {
if (name == "self" && ns == ns_value) {
ret some(ast::def_self(local_def(id)));
}
}
scope_native_item(it) {
alt it.node {
ast::native_item_fn(decl, ty_params) {
@ -881,9 +893,10 @@ fn lookup_in_fn(name: ident, decl: ast::fn_decl, ty_params: [ast::ty_param],
}
fn lookup_in_obj(name: ident, ob: ast::_obj, ty_params: [ast::ty_param],
ns: namespace) -> option::t<def> {
ns: namespace, id: node_id) -> option::t<def> {
alt ns {
ns_value. {
if name == "self" { ret some(ast::def_self(local_def(id))); }
for f: ast::obj_field in ob.fields {
if str::eq(f.ident, name) {
ret some(ast::def_obj_field(local_def(f.id), f.mut));
@ -1295,23 +1308,17 @@ fn index_nmod(md: ast::native_mod) -> mod_index {
// External lookups
fn ns_for_def(d: def) -> namespace {
ret alt d {
ast::def_fn(_, _) { ns_value }
ast::def_obj_field(_, _) { ns_value }
ast::def_mod(_) { ns_module }
ast::def_native_mod(_) { ns_module }
ast::def_const(_) { ns_value }
ast::def_arg(_, _) { ns_value }
ast::def_local(_, _) { ns_value }
ast::def_upvar(_, _, _) { ns_value }
ast::def_variant(_, _) { ns_value }
ast::def_ty(_) { ns_type }
ast::def_binding(_) { ns_type }
ast::def_use(_) { ns_module }
ast::def_native_ty(_) { ns_type }
ast::def_native_fn(_, _) { ns_value }
ast::def_self(_) { ns_value }
};
alt d {
ast::def_fn(_, _) | ast::def_obj_field(_, _) | ast::def_self(_) |
ast::def_const(_) | ast::def_arg(_, _) | ast::def_local(_, _) |
ast::def_upvar(_, _, _) | ast::def_variant(_, _) |
ast::def_native_fn(_, _) | ast::def_self(_) { ns_value }
ast::def_mod(_) | ast::def_native_mod(_) { ns_module }
ast::def_ty(_) | ast::def_binding(_) | ast::def_use(_) |
ast::def_native_ty(_) { ns_type }
}
}
fn lookup_external(e: env, cnum: int, ids: [ident], ns: namespace) ->

View File

@ -2678,7 +2678,9 @@ fn trans_local_var(cx: @block_ctxt, def: ast::def) -> local_var_result {
ret { val: cx.fcx.llobjfields.get(did.node), kind: owned };
}
ast::def_self(did) {
ret lval_owned(cx, cx.fcx.llenv);
let slf = option::get(cx.fcx.llself);
let ptr = PointerCast(cx, slf.v, T_ptr(type_of_or_i8(cx, slf.t)));
ret {val: ptr, kind: owned};
}
_ {
bcx_ccx(cx).sess.span_unimpl
@ -2832,21 +2834,29 @@ fn trans_index(cx: @block_ctxt, sp: span, base: @ast::expr, idx: @ast::expr,
ret lval_owned(next_cx, elt);
}
fn expr_is_lval(bcx: @block_ctxt, e: @ast::expr) -> bool {
let ccx = bcx_ccx(bcx);
ty::expr_is_lval(ccx.method_map, ccx.tcx, e)
}
// This is for impl methods, not obj methods.
fn trans_method_callee(bcx: @block_ctxt, e: @ast::expr, base: @ast::expr,
did: ast::def_id) -> lval_maybe_callee {
let bcx = trans_expr(bcx, base, ignore); // FIXME pass self
lval_static_fn(bcx, did, e.id)
let tz = [], tr = [];
let basety = ty::expr_ty(bcx_tcx(bcx), base);
let {bcx, val} = trans_arg_expr(bcx, {mode: ast::by_ref, ty: basety},
type_of_or_i8(bcx, basety), tz, tr, base);
let val = PointerCast(bcx, val, T_opaque_boxed_closure_ptr(bcx_ccx(bcx)));
{env: obj_env(val) with lval_static_fn(bcx, did, e.id)}
}
fn trans_callee(bcx: @block_ctxt, e: @ast::expr) -> lval_maybe_callee {
alt e.node {
ast::expr_path(p) { ret trans_path(bcx, p, e.id); }
ast::expr_field(base, ident) {
let method_map = bcx_ccx(bcx).method_map;
// Lval means this is a record field, so not a method
if !ty::expr_is_lval(method_map, bcx_tcx(bcx), e) {
alt method_map.find(e.id) {
if !expr_is_lval(bcx, e) {
alt bcx_ccx(bcx).method_map.find(e.id) {
some(did) { // An impl method
ret trans_method_callee(bcx, e, base, did);
}
@ -2858,15 +2868,6 @@ fn trans_callee(bcx: @block_ctxt, e: @ast::expr) -> lval_maybe_callee {
}
}
}
ast::expr_self_method(ident) {
alt bcx.fcx.llself {
some(pair) {
let fld = trans_object_field_inner(bcx, pair.v, ident, pair.t);
ret {bcx: fld.bcx, val: fld.mthptr, kind: owned,
env: obj_env(fld.objptr), generic: none};
}
}
}
_ {}
}
let lv = trans_temp_lval(bcx, e);
@ -3475,7 +3476,7 @@ fn trans_expr_save_in(bcx: @block_ctxt, e: @ast::expr, dest: ValueRef)
// use trans_temp_expr.
fn trans_temp_lval(bcx: @block_ctxt, e: @ast::expr) -> lval_result {
let bcx = bcx;
if ty::expr_is_lval(bcx_ccx(bcx).method_map, bcx_tcx(bcx), e) {
if expr_is_lval(bcx, e) {
ret trans_lval(bcx, e);
} else {
let tcx = bcx_tcx(bcx);
@ -3513,7 +3514,7 @@ fn trans_temp_expr(bcx: @block_ctxt, e: @ast::expr) -> result {
// - exprs with non-immediate type never get dest=by_val
fn trans_expr(bcx: @block_ctxt, e: @ast::expr, dest: dest) -> @block_ctxt {
let tcx = bcx_tcx(bcx);
if ty::expr_is_lval(bcx_ccx(bcx).method_map, tcx, e) {
if expr_is_lval(bcx, e) {
ret lval_to_dps(bcx, e, dest);
}
@ -3555,7 +3556,7 @@ fn trans_expr(bcx: @block_ctxt, e: @ast::expr, dest: dest) -> @block_ctxt {
ret trans_closure::trans_bind(bcx, f, args, e.id, dest);
}
ast::expr_copy(a) {
if !ty::expr_is_lval(bcx_ccx(bcx).method_map, tcx, a) {
if !expr_is_lval(bcx, a) {
ret trans_expr(bcx, a, dest);
}
else { ret lval_to_dps(bcx, a, dest); }
@ -3957,9 +3958,7 @@ fn init_local(bcx: @block_ctxt, local: @ast::local) -> @block_ctxt {
let bcx = bcx;
alt local.node.init {
some(init) {
if init.op == ast::init_assign ||
!ty::expr_is_lval(bcx_ccx(bcx).method_map, bcx_tcx(bcx),
init.expr) {
if init.op == ast::init_assign || !expr_is_lval(bcx, init.expr) {
bcx = trans_expr_save_in(bcx, init.expr, llptr);
} else { // This is a move from an lval, must perform an actual move
let sub = trans_lval(bcx, init.expr);
@ -4347,15 +4346,15 @@ fn new_fn_ctxt(cx: @local_ctxt, sp: span, llfndecl: ValueRef) -> @fn_ctxt {
// spaces that have been created for them (by code in the llallocas field of
// the function's fn_ctxt). create_llargs_for_fn_args populates the llargs
// field of the fn_ctxt with
fn create_llargs_for_fn_args(cx: @fn_ctxt, ty_self: option::t<ty::t>,
fn create_llargs_for_fn_args(cx: @fn_ctxt, ty_self: self_arg,
args: [ast::arg], ty_params: [ast::ty_param]) {
// Skip the implicit arguments 0, and 1. TODO: Pull out 2u and define
// it as a constant, since we're using it in several places in trans this
// way.
let arg_n = 2u;
alt ty_self {
some(tt) { cx.llself = some::<val_self_pair>({v: cx.llenv, t: tt}); }
none. {
obj_self(tt) | impl_self(tt) { cx.llself = some({v: cx.llenv, t: tt}); }
no_self. {
let i = 0u;
for tp: ast::ty_param in ty_params {
let llarg = llvm::LLVMGetParam(cx.llfn, arg_n);
@ -4473,19 +4472,23 @@ fn finish_fn(fcx: @fn_ctxt, lltop: BasicBlockRef) {
RetVoid(ret_cx);
}
tag self_arg { obj_self(ty::t); impl_self(ty::t); no_self; }
// trans_closure: Builds an LLVM function out of a source function.
// If the function closes over its environment a closure will be
// returned.
fn trans_closure(cx: @local_ctxt, sp: span, f: ast::_fn, llfndecl: ValueRef,
ty_self: option::t<ty::t>, ty_params: [ast::ty_param],
ty_self: self_arg, ty_params: [ast::ty_param],
id: ast::node_id, maybe_load_env: block(@fn_ctxt)) {
set_uwtable(llfndecl);
// Set up arguments to the function.
let fcx = new_fn_ctxt_w_id(cx, sp, llfndecl, id, f.decl.cf);
create_llargs_for_fn_args(fcx, ty_self, f.decl.inputs, ty_params);
alt fcx.llself {
some(llself) { populate_fn_ctxt_from_llself(fcx, llself); }
alt ty_self {
obj_self(_) {
populate_fn_ctxt_from_llself(fcx, option::get(fcx.llself));
}
_ { }
}
@ -4526,7 +4529,7 @@ fn trans_closure(cx: @local_ctxt, sp: span, f: ast::_fn, llfndecl: ValueRef,
// trans_fn: creates an LLVM function corresponding to a source language
// function.
fn trans_fn(cx: @local_ctxt, sp: span, f: ast::_fn, llfndecl: ValueRef,
ty_self: option::t<ty::t>, ty_params: [ast::ty_param],
ty_self: self_arg, ty_params: [ast::ty_param],
id: ast::node_id) {
let do_time = cx.ccx.sess.get_opts().stats;
let start = do_time ? time::get_time() : {sec: 0u32, usec: 0u32};
@ -4549,7 +4552,7 @@ fn trans_res_ctor(cx: @local_ctxt, sp: span, dtor: ast::_fn,
}
let fcx = new_fn_ctxt(cx, sp, llctor_decl);
let ret_t = ty::ret_ty_of_fn(cx.ccx.tcx, ctor_id);
create_llargs_for_fn_args(fcx, none, dtor.decl.inputs, ty_params);
create_llargs_for_fn_args(fcx, no_self, dtor.decl.inputs, ty_params);
let bcx = new_top_block_ctxt(fcx);
let lltop = bcx.llbb;
let arg_t = arg_tys_of_fn(ccx, ctor_id)[0].ty;
@ -4608,7 +4611,7 @@ fn trans_tag_variant(cx: @local_ctxt, tag_id: ast::node_id,
}
}
let fcx = new_fn_ctxt(cx, variant.span, llfndecl);
create_llargs_for_fn_args(fcx, none, fn_args, ty_params);
create_llargs_for_fn_args(fcx, no_self, fn_args, ty_params);
let ty_param_substs: [ty::t] = [];
i = 0u;
for tp: ast::ty_param in ty_params {
@ -4655,13 +4658,15 @@ fn trans_tag_variant(cx: @local_ctxt, tag_id: ast::node_id,
finish_fn(fcx, lltop);
}
fn trans_impl(cx: @local_ctxt, name: ast::ident, methods: [@ast::method]) {
fn trans_impl(cx: @local_ctxt, name: ast::ident, methods: [@ast::method],
id: ast::node_id) {
let sub_cx = extend_path(cx, name);
for m in methods {
alt cx.ccx.item_ids.find(m.node.id) {
some(llfndecl) {
some(llfn) {
trans_fn(extend_path(sub_cx, m.node.ident), m.span, m.node.meth,
llfndecl, none, [], m.node.id);
llfn, impl_self(ty::node_id_to_monotype(cx.ccx.tcx, id)),
[], m.node.id);
}
}
}
@ -4961,7 +4966,7 @@ fn trans_item(cx: @local_ctxt, item: ast::item) {
let sub_cx = extend_path(cx, item.ident);
alt cx.ccx.item_ids.find(item.id) {
some(llfndecl) {
trans_fn(sub_cx, item.span, f, llfndecl, none, tps, item.id);
trans_fn(sub_cx, item.span, f, llfndecl, no_self, tps, item.id);
}
_ {
cx.ccx.sess.span_fatal(item.span,
@ -4975,14 +4980,14 @@ fn trans_item(cx: @local_ctxt, item: ast::item) {
with *extend_path(cx, item.ident)};
trans_obj(sub_cx, item.span, ob, ctor_id, tps);
}
ast::item_impl(_, _, ms) { trans_impl(cx, item.ident, ms); }
ast::item_impl(_, _, ms) { trans_impl(cx, item.ident, ms, item.id); }
ast::item_res(dtor, dtor_id, tps, ctor_id) {
trans_res_ctor(cx, item.span, dtor, ctor_id, tps);
// Create a function for the destructor
alt cx.ccx.item_ids.find(item.id) {
some(lldtor_decl) {
trans_fn(cx, item.span, dtor, lldtor_decl, none, tps, dtor_id);
trans_fn(cx, item.span, dtor, lldtor_decl, no_self, tps, dtor_id);
}
_ {
cx.ccx.sess.span_fatal(item.span, "unbound dtor in trans_item");

View File

@ -339,7 +339,7 @@ fn trans_expr_fn(bcx: @block_ctxt, f: ast::_fn, sp: span,
let trans_closure_env = lambda(ck: ty::closure_kind) -> ValueRef {
let upvars = get_freevars(ccx.tcx, id);
let {llbox, box_ty, bcx} = build_closure(bcx, upvars, ck);
trans_closure(sub_cx, sp, f, llfn, none, [], id, {|fcx|
trans_closure(sub_cx, sp, f, llfn, no_self, [], id, {|fcx|
load_environment(bcx, fcx, box_ty, upvars, ck);
});
llbox
@ -351,7 +351,7 @@ fn trans_expr_fn(bcx: @block_ctxt, f: ast::_fn, sp: span,
ast::proto_send. { trans_closure_env(ty::closure_send) }
ast::proto_bare. {
let closure = C_null(T_opaque_boxed_closure_ptr(ccx));
trans_closure(sub_cx, sp, f, llfn, none, [], id, {|_fcx|});
trans_closure(sub_cx, sp, f, llfn, no_self, [], id, {|_fcx|});
closure
}
};

View File

@ -52,7 +52,7 @@ fn trans_obj(cx: @local_ctxt, sp: span, ob: ast::_obj, ctor_id: ast::node_id,
let lltop = bcx.llbb;
// Both regular arguments and type parameters are handled here.
create_llargs_for_fn_args(fcx, none::<ty::t>, fn_args, ty_params);
create_llargs_for_fn_args(fcx, no_self, fn_args, ty_params);
let arg_tys: [ty::arg] = arg_tys_of_fn(ccx, ctor_id);
bcx = copy_args_to_allocas(fcx, bcx, fn_args, arg_tys);
@ -893,7 +893,7 @@ fn process_normal_mthd(cx: @local_ctxt, m: @ast::method, self_ty: ty::t,
// method's definition will be in the executable.
ccx.item_ids.insert(m.node.id, llfn);
ccx.item_symbols.insert(m.node.id, s);
trans_fn(mcx, m.span, m.node.meth, llfn, some(self_ty), ty_params,
trans_fn(mcx, m.span, m.node.meth, llfn, obj_self(self_ty), ty_params,
m.node.id);
ret llfn;

View File

@ -335,7 +335,6 @@ fn find_pre_post_expr(fcx: fn_ctxt, e: @expr) {
clear_pp(rslt);
handle_var(fcx, rslt, e.id, path_to_ident(fcx.ccx.tcx, p));
}
expr_self_method(v) { clear_pp(expr_pp(fcx.ccx, e)); }
expr_log(_, arg) {
find_pre_post_expr(fcx, arg);
copy_pre_post(fcx.ccx, e.id, arg);

View File

@ -592,7 +592,6 @@ fn find_pre_post_state_expr(fcx: fn_ctxt, pres: prestate, e: @expr) -> bool {
}
expr_break. { ret pure_exp(fcx.ccx, e.id, pres); }
expr_cont. { ret pure_exp(fcx.ccx, e.id, pres); }
expr_self_method(_) { ret pure_exp(fcx.ccx, e.id, pres); }
expr_anon_obj(anon_obj) {
alt anon_obj.inner_obj {
some(wt) { ret find_pre_post_state_sub(fcx, pres, wt, e.id, none); }

View File

@ -90,6 +90,7 @@ export mk_uint;
export mk_uniq;
export mk_var;
export mk_opaque_closure;
export gen_ty;
export mode;
export mt;
export node_type_table;

View File

@ -8,7 +8,7 @@ import util::common::*;
import syntax::codemap::span;
import middle::ty;
import middle::ty::{node_id_to_type, arg, bind_params_in_type, block_ty,
expr_ty, field, node_type_table,
expr_ty, field, node_type_table, mk_nil,
ty_param_substs_opt_and_ty, ty_param_kinds_and_ty};
import util::ppaux::ty_to_str;
import middle::ty::unify::{ures_ok, ures_err, fix_ok, fix_err};
@ -25,17 +25,12 @@ type method_map = hashmap<ast::node_id, ast::def_id>;
type ty_table = hashmap<ast::def_id, ty::t>;
// Used for typechecking the methods of an object.
tag obj_info {
// Regular objects have a node_id at compile time.
regular_obj([ast::obj_field], ast::node_id);
// Anonymous objects only have a type at compile time. It's optional
// because not all anonymous objects have a inner_obj to attach to.
anon_obj([ast::obj_field], option::t<ty::sty>);
tag self_info {
self_obj([ast::obj_field], ty::t);
self_impl(ty::t);
}
type crate_ctxt = {mutable obj_infos: [obj_info],
type crate_ctxt = {mutable self_infos: [self_info],
impl_map: resolve::impl_map,
method_map: method_map,
tcx: ty::ctxt};
@ -93,7 +88,13 @@ fn ty_param_kinds_and_ty_for_def(fcx: @fn_ctxt, sp: span, defn: ast::def) ->
let typ = ty::mk_var(fcx.ccx.tcx, lookup_local(fcx, sp, id.node));
ret {kinds: [], ty: typ};
}
ast::def_self(id) { fail "FIXME[impl]"; }
ast::def_self(id) {
alt get_self_info(fcx.ccx) {
some(self_obj(_, obj_t)) | some(self_impl(obj_t)) {
ret {kinds: [], ty: obj_t};
}
}
}
ast::def_fn(id, _) { ret ty::lookup_item_type(fcx.ccx.tcx, id); }
ast::def_native_fn(id, _) { ret ty::lookup_item_type(fcx.ccx.tcx, id); }
ast::def_const(id) { ret ty::lookup_item_type(fcx.ccx.tcx, id); }
@ -696,7 +697,7 @@ mod collect {
write::ty_only(cx.tcx, it.id, tpt.ty);
get_tag_variant_types(cx, local_def(it.id), variants, ty_params);
}
ast::item_impl(_, _, ms) {
ast::item_impl(_, selfty, ms) {
for m in ms {
let ty = ty::method_ty_to_fn_ty(
cx.tcx, ty_of_method(cx.tcx, m_collect, m));
@ -704,6 +705,8 @@ mod collect {
{kinds: [], ty: ty});
write::ty_only(cx.tcx, m.node.id, ty);
}
write::ty_only(cx.tcx, it.id, ast_ty_to_ty(cx.tcx, m_collect,
selfty));
}
ast::item_obj(object, ty_params, ctor_id) {
// Now we need to call ty_of_obj_ctor(); this is the type that
@ -1115,19 +1118,13 @@ fn gather_locals(ccx: @crate_ctxt, f: ast::_fn, id: ast::node_id,
};
// Add object fields, if any.
let obj_fields = [];
alt get_obj_info(ccx) {
some(oinfo) {
alt oinfo {
regular_obj(ofs, _) { obj_fields = ofs; }
anon_obj(ofs, _) { obj_fields = ofs; }
alt get_self_info(ccx) {
some(self_obj(ofs, _)) {
for f in ofs {
assign(f.id, some(ty::node_id_to_type(ccx.tcx, f.id)));
}
}
none. {/* no fields */ }
}
for f: ast::obj_field in obj_fields {
let field_ty = ty::node_id_to_type(ccx.tcx, f.id);
assign(f.id, some(field_ty));
_ {}
}
// Add formal parameters.
@ -1992,60 +1989,6 @@ fn check_expr_with_unifier(fcx: @fn_ctxt, expr: @ast::expr, unify: unifier,
ast::expr_call(f, args, _) {
bot = check_call_full(fcx, expr.span, f, args, expr.id);
}
ast::expr_self_method(ident) {
let t = ty::mk_nil(tcx);
let this_obj_sty: option::t<ty::sty> =
some(structure_of(fcx, expr.span, ty::mk_nil(tcx)));
let this_obj_info: option::t<obj_info> = get_obj_info(fcx.ccx);
alt this_obj_info {
some(oinfo) {
alt oinfo {
regular_obj(_, obj_id) {
let did = local_def(obj_id);
// Try looking up the current object in the type
// cache.
alt tcx.tcache.find(did) {
some(tpt) {
// If we're typechecking a self-method on
// a regular object, this lookup should
// succeed.
this_obj_sty = some(structure_of(fcx, expr.span, tpt.ty));
}
none. {
tcx.sess.bug("didn't find " + int::str(did.node) +
" in type cache");
}
}
}
anon_obj(_, obj_sty) { this_obj_sty = obj_sty; }
}
}
none. {
// Shouldn't happen.
tcx.sess.span_err(expr.span, "self-call in non-object context");
}
}
// Grab this method's type out of the current object type.
alt this_obj_sty {
some(sty) {
alt sty {
ty::ty_obj(methods) {
for method: ty::method in methods {
if method.ident == ident {
t = ty::method_ty_to_fn_ty(tcx, method);
}
}
}
_ { fail; }
}
}
none. { }
}
write::ty_only_fixup(fcx, id, t);
require_impure(tcx.sess, fcx.purity, expr.span);
}
ast::expr_cast(e, t) {
bot = check_expr(fcx, e);
let t_1 = ast_ty_to_ty_crate(fcx.ccx, t);
@ -2172,15 +2115,16 @@ fn check_expr_with_unifier(fcx: @fn_ctxt, expr: @ast::expr, unify: unifier,
}
result
}
bot |= check_expr(fcx, base);
let base_t = expr_ty(tcx, base);
let iscope = fcx.ccx.impl_map.get(expr.id);
alt lookup_method(fcx, iscope, field, base_t) {
some(method) {
let mt = ty_of_method(fcx.ccx.tcx, m_check, method);
let f_ty = ty::mk_fn(fcx.ccx.tcx, mt.proto, mt.inputs,
mt.output, mt.cf, mt.constrs);
write::ty_only_fixup(fcx, id, f_ty);
let fty = ty::mk_fn(fcx.ccx.tcx, mt.proto, mt.inputs,
mt.output, mt.cf, mt.constrs);
write::ty_only_fixup(fcx, id, fty);
fcx.ccx.method_map.insert(id, local_def(method.node.id));
}
_ {
@ -2255,15 +2199,15 @@ fn check_expr_with_unifier(fcx: @fn_ctxt, expr: @ast::expr, unify: unifier,
// Typecheck 'inner_obj'. If it exists, it had better have object
// type.
let inner_obj_methods: [ty::method] = [];
let inner_obj_ty: ty::t = ty::mk_nil(tcx);
let inner_obj_sty: option::t<ty::sty> = none;
alt ao.inner_obj {
none. { }
some(e) {
// If there's a inner_obj, we push it onto the obj_infos stack
// so that self-calls can be checked within its context later.
// If there's a inner_obj, we push it onto the self_infos
// stack so that self-calls can be checked within its context
// later.
bot |= check_expr(fcx, e);
inner_obj_ty = expr_ty(tcx, e);
let inner_obj_ty = expr_ty(tcx, e);
inner_obj_sty = some(structure_of(fcx, e.span, inner_obj_ty));
alt inner_obj_sty {
@ -2283,10 +2227,6 @@ fn check_expr_with_unifier(fcx: @fn_ctxt, expr: @ast::expr, unify: unifier,
}
}
fcx.ccx.obj_infos +=
[anon_obj(vec::map(ast_util::obj_field_from_anon_obj_field,
fields), inner_obj_sty)];
// Whenever an outer method overrides an inner, we need to remove
// that inner from the type. Filter inner_obj_methods to remove
// any methods that share a name with an outer method.
@ -2311,9 +2251,7 @@ fn check_expr_with_unifier(fcx: @fn_ctxt, expr: @ast::expr, unify: unifier,
}
let f = bind filtering_fn(fcx.ccx, _, ao.methods);
inner_obj_methods =
vec::filter_map::<ty::method,
ty::method>(f, inner_obj_methods);
inner_obj_methods = vec::filter_map(f, inner_obj_methods);
method_types += inner_obj_methods;
}
@ -2325,19 +2263,22 @@ fn check_expr_with_unifier(fcx: @fn_ctxt, expr: @ast::expr, unify: unifier,
// Write the methods into the node type table. (This happens in
// collect::convert for regular objects.)
let i = 0u;
while i < vec::len::<@ast::method>(ao.methods) {
while i < vec::len(ao.methods) {
write::ty_only(tcx, ao.methods[i].node.id,
ty::method_ty_to_fn_ty(tcx, method_types[i]));
i += 1u;
}
fcx.ccx.self_infos +=
[self_obj(vec::map(ast_util::obj_field_from_anon_obj_field,
fields), ot)];
// Typecheck the methods.
for method: @ast::method in ao.methods {
check_method(fcx.ccx, method);
}
// Now remove the info from the stack.
vec::pop::<obj_info>(fcx.ccx.obj_infos);
vec::pop(fcx.ccx.self_infos);
}
_ { tcx.sess.unimpl("expr type in typeck::check_expr"); }
}
@ -2357,8 +2298,8 @@ fn next_ty_var(fcx: @fn_ctxt) -> ty::t {
ret ty::mk_var(fcx.ccx.tcx, next_ty_var_id(fcx));
}
fn get_obj_info(ccx: @crate_ctxt) -> option::t<obj_info> {
ret vec::last::<obj_info>(ccx.obj_infos);
fn get_self_info(ccx: @crate_ctxt) -> option::t<self_info> {
ret vec::last(ccx.self_infos);
}
fn check_decl_initializer(fcx: @fn_ctxt, nid: ast::node_id,
@ -2639,13 +2580,18 @@ fn check_item(ccx: @crate_ctxt, it: @ast::item) {
ast::item_res(f, dtor_id, _, _) { check_fn(ccx, f, dtor_id, none); }
ast::item_obj(ob, _, _) {
// We're entering an object, so gather up the info we need.
ccx.obj_infos += [regular_obj(ob.fields, it.id)];
ccx.self_infos += [self_obj(ob.fields,
ccx.tcx.tcache.get(local_def(it.id)).ty)];
// Typecheck the methods.
for method: @ast::method in ob.methods { check_method(ccx, method); }
// Now remove the info from the stack.
vec::pop::<obj_info>(ccx.obj_infos);
vec::pop(ccx.self_infos);
}
ast::item_impl(_, ty, ms) {
ccx.self_infos += [self_impl(ast_ty_to_ty(ccx.tcx, m_check, ty))];
for m in ms { check_method(ccx, m); }
vec::pop(ccx.self_infos);
}
ast::item_impl(_, _, ms) { for m in ms { check_method(ccx, m); } }
_ {/* nothing to do */ }
}
}
@ -2701,9 +2647,7 @@ fn check_crate(tcx: ty::ctxt, impl_map: resolve::impl_map,
crate: @ast::crate) -> method_map {
collect::collect_item_types(tcx, crate);
let obj_infos: [obj_info] = [];
let ccx = @{mutable obj_infos: obj_infos,
let ccx = @{mutable self_infos: [],
impl_map: impl_map,
method_map: std::map::new_int_hash(),
tcx: tcx};

View File

@ -28,13 +28,13 @@ type ty_param = {ident: ident, kind: kind};
tag def {
def_fn(def_id, purity);
def_obj_field(def_id, mutability);
def_self(def_id);
def_mod(def_id);
def_native_mod(def_id);
def_const(def_id);
def_arg(def_id, mode);
def_local(def_id, let_style);
def_variant(def_id /* tag */, def_id /* variant */);
def_self(def_id);
def_ty(def_id);
def_ty_param(uint, kind);
def_binding(def_id);
@ -214,7 +214,6 @@ tag expr_ {
expr_rec([field], option::t<@expr>);
expr_call(@expr, [@expr], bool);
expr_tup([@expr]);
expr_self_method(ident);
expr_bind(@expr, [option::t<@expr>]);
expr_binary(binop, @expr, @expr);
expr_unary(unop, @expr);

View File

@ -353,7 +353,6 @@ fn noop_fold_expr(e: expr_, fld: ast_fold) -> expr_ {
expr_call(fld.fold_expr(f), fld.map_exprs(fld.fold_expr, args),
blk)
}
expr_self_method(id) { expr_self_method(fld.fold_ident(id)) }
expr_bind(f, args) {
let opt_map_se = bind option::map(fld.fold_expr, _);
expr_bind(fld.fold_expr(f), vec::map(opt_map_se, args))

View File

@ -155,8 +155,7 @@ fn bad_expr_word_table() -> hashmap<str, ()> {
"cont", "ret", "be", "fail", "type", "resource", "check",
"assert", "claim", "native", "fn", "lambda", "pure",
"unsafe", "block", "import", "export", "let", "const",
"log", "log_err", "tag", "obj", "self", "copy", "sendfn",
"impl"] {
"log", "log_err", "tag", "obj", "copy", "sendfn", "impl"] {
words.insert(word, ());
}
words
@ -942,15 +941,6 @@ fn parse_bottom_expr(p: parser) -> @ast::expr {
let e = parse_expr(p);
ex = ast::expr_copy(e);
hi = e.span.hi;
} else if is_word(p, "self") && p.look_ahead(1u) == token::DOT {
p.bump(); p.bump();
// The rest is a call expression.
let f: @ast::expr = parse_self_method(p);
let es =
parse_seq(token::LPAREN, token::RPAREN, seq_sep(token::COMMA),
parse_expr, p);
hi = es.span.hi;
ex = ast::expr_call(f, es.node, false);
} else if p.peek() == token::MOD_SEP ||
is_ident(p.peek()) && !is_word(p, "true") &&
!is_word(p, "false") {
@ -998,12 +988,6 @@ fn parse_syntax_ext_naked(p: parser, lo: uint) -> @ast::expr {
ret mk_mac_expr(p, lo, hi, ast::mac_invoc(pth, e, none));
}
fn parse_self_method(p: parser) -> @ast::expr {
let sp = p.get_span();
let f_name: ast::ident = parse_ident(p);
ret mk_expr(p, sp.lo, sp.hi, ast::expr_self_method(f_name));
}
fn parse_dot_or_call_expr(p: parser) -> @ast::expr {
let b = parse_bottom_expr(p);
if expr_has_value(b) { parse_dot_or_call_expr_with(p, b) }

View File

@ -736,10 +736,6 @@ fn print_expr(s: ps, &&expr: @ast::expr) {
print_expr(s, option::get(blk));
}
}
ast::expr_self_method(ident) {
word(s.s, "self.");
print_ident(s, ident);
}
ast::expr_bind(func, args) {
fn print_opt(s: ps, expr: option::t<@ast::expr>) {
alt expr {

View File

@ -251,7 +251,6 @@ fn visit_expr<E>(ex: @expr, e: E, v: vt<E>) {
visit_exprs(args, e, v);
v.visit_expr(callee, e, v);
}
expr_self_method(_) { }
expr_bind(callee, args) {
v.visit_expr(callee, e, v);
for eo: option::t<@expr> in args { visit_expr_opt(eo, e, v); }

View File

@ -1,4 +1,4 @@
// error-pattern:self-call in non-object context
// error-pattern:unresolved name: self
// Fix for issue #707.
fn main() {

View File

@ -1,4 +1,4 @@
// error-pattern:expecting ., found (
// error-pattern:attempted field access on type fn
fn main() {
obj foo() {