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:
parent
1dd2f1ec03
commit
7efef98901
@ -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 }
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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);
|
||||
|
@ -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) ->
|
||||
|
@ -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");
|
||||
|
@ -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
|
||||
}
|
||||
};
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
|
@ -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); }
|
||||
|
@ -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;
|
||||
|
@ -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};
|
||||
|
@ -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);
|
||||
|
@ -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))
|
||||
|
@ -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) }
|
||||
|
@ -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 {
|
||||
|
@ -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); }
|
||||
|
@ -1,4 +1,4 @@
|
||||
// error-pattern:self-call in non-object context
|
||||
// error-pattern:unresolved name: self
|
||||
|
||||
// Fix for issue #707.
|
||||
fn main() {
|
||||
|
@ -1,4 +1,4 @@
|
||||
// error-pattern:expecting ., found (
|
||||
// error-pattern:attempted field access on type fn
|
||||
fn main() {
|
||||
|
||||
obj foo() {
|
||||
|
Loading…
Reference in New Issue
Block a user