diff --git a/src/comp/driver/rustc.rs b/src/comp/driver/rustc.rs index 2ba91d2ecbd..758f9bf85b6 100644 --- a/src/comp/driver/rustc.rs +++ b/src/comp/driver/rustc.rs @@ -171,8 +171,8 @@ fn compile_input(sess: session::session, cfg: ast::crate_cfg, input: str, time(time_passes, "const checking", bind middle::check_const::check_crate(sess, crate)); let ty_cx = ty::mk_ctxt(sess, def_map, ext_map, ast_map, freevars); - time(time_passes, "typechecking", - bind typeck::check_crate(ty_cx, impl_map, crate)); + let method_map = time(time_passes, "typechecking", + bind typeck::check_crate(ty_cx, impl_map, crate)); time(time_passes, "block-use checking", bind middle::block_use::check_crate(ty_cx, crate)); time(time_passes, "function usage", @@ -190,7 +190,7 @@ fn compile_input(sess: session::session, cfg: ast::crate_cfg, input: str, let last_uses = time(time_passes, "last use finding", bind last_use::find_last_uses(crate, def_map, ref_map, ty_cx)); time(time_passes, "kind checking", - bind kind::check_crate(ty_cx, last_uses, crate)); + bind kind::check_crate(ty_cx, method_map, last_uses, crate)); if sess.get_opts().no_trans { ret; } let outputs = build_output_filenames(input, outdir, output, sess); @@ -199,7 +199,8 @@ fn compile_input(sess: session::session, cfg: ast::crate_cfg, input: str, time(time_passes, "translation", bind trans::trans_crate(sess, crate, ty_cx, outputs.obj_filename, exp_map, ast_map, - mut_map, copy_map, last_uses)); + mut_map, copy_map, last_uses, + method_map)); time(time_passes, "LLVM passes", bind link::write::run_passes(sess, llmod, outputs.obj_filename)); diff --git a/src/comp/middle/kind.rs b/src/comp/middle/kind.rs index 8e577484303..863d02d3d92 100644 --- a/src/comp/middle/kind.rs +++ b/src/comp/middle/kind.rs @@ -30,12 +30,15 @@ type rval_map = std::map::hashmap; type ctx = {tcx: ty::ctxt, rval_map: rval_map, + method_map: typeck::method_map, last_uses: last_use::last_uses}; -fn check_crate(tcx: ty::ctxt, last_uses: last_use::last_uses, - crate: @crate) -> rval_map { +fn check_crate(tcx: ty::ctxt, method_map: typeck::method_map, + last_uses: last_use::last_uses, crate: @crate) + -> rval_map { let ctx = {tcx: tcx, rval_map: std::map::new_int_hash(), + method_map: method_map, last_uses: last_uses}; let visit = visit::mk_vt(@{ visit_expr: check_expr, @@ -150,7 +153,8 @@ fn maybe_copy(cx: ctx, ex: @expr) { } fn check_copy_ex(cx: ctx, ex: @expr, _warn: bool) { - if ty::expr_is_lval(cx.tcx, ex) && !cx.last_uses.contains_key(ex.id) { + if ty::expr_is_lval(cx.method_map, cx.tcx, ex) && + !cx.last_uses.contains_key(ex.id) { let ty = ty::expr_ty(cx.tcx, ex); check_copy(cx, ty, ex.span); // FIXME turn this on again once vector types are no longer unique. diff --git a/src/comp/middle/trans.rs b/src/comp/middle/trans.rs index a0493b8cbc8..886a8da2048 100644 --- a/src/comp/middle/trans.rs +++ b/src/comp/middle/trans.rs @@ -13,7 +13,7 @@ // but many TypeRefs correspond to one ty::t; for instance, tup(int, int, // int) and rec(x=int, y=int, z=int) will have the same TypeRef. -import core::{either, str, uint, option, vec}; +import core::{either, str, int, uint, option, vec}; import std::{map, time}; import std::map::hashmap; import std::map::{new_int_hash, new_str_hash}; @@ -948,8 +948,6 @@ fn get_derived_tydesc(cx: @block_ctxt, t: ty::t, escapes: bool, &static_ti: option::t<@tydesc_info>) -> result { alt cx.fcx.derived_tydescs.find(t) { some(info) { - - // If the tydesc escapes in this context, the cached derived // tydesc also has to be one that was marked as escaping. if !(escapes && !info.escapes) && storage == tps_normal { @@ -2606,8 +2604,9 @@ fn trans_external_path(cx: @block_ctxt, did: ast::def_id, type_of_ty_param_kinds_and_ty(lcx, cx.sp, tpt)); } -fn lval_static_fn(bcx: @block_ctxt, tpt: ty::ty_param_kinds_and_ty, - fn_id: ast::def_id, id: ast::node_id) -> lval_maybe_callee { +fn lval_static_fn(bcx: @block_ctxt, fn_id: ast::def_id, id: ast::node_id) + -> lval_maybe_callee { + let tpt = ty::lookup_item_type(bcx_tcx(bcx), fn_id); let val = if fn_id.crate == ast::local_crate { // Internal reference. assert (bcx_ccx(bcx).item_ids.contains_key(fn_id.node)); @@ -2698,17 +2697,13 @@ fn trans_var(cx: @block_ctxt, sp: span, def: ast::def, id: ast::node_id) let ccx = bcx_ccx(cx); alt def { ast::def_fn(did, _) | ast::def_native_fn(did, _) { - let tyt = ty::lookup_item_type(ccx.tcx, did); - ret lval_static_fn(cx, tyt, did, id); + ret lval_static_fn(cx, did, id); } ast::def_variant(tid, vid) { - let v_tyt = ty::lookup_item_type(ccx.tcx, vid); - alt ty::struct(ccx.tcx, v_tyt.ty) { - ty::ty_fn(_, _, _, _, _) { + if vec::len(ty::tag_variant_with_id(ccx.tcx, tid, vid).args) > 0u { // N-ary variant. - ret lval_static_fn(cx, v_tyt, vid, id); - } - _ { + ret lval_static_fn(cx, vid, id); + } else { // Nullary variant. let tag_ty = node_id_type(ccx, id); let alloc_result = alloc_ty(cx, tag_ty); @@ -2724,7 +2719,6 @@ fn trans_var(cx: @block_ctxt, sp: span, def: ast::def, id: ast::node_id) } else { C_int(ccx, 0) }; Store(bcx, d, lldiscrimptr); ret lval_no_env(bcx, lltagptr, temporary); - } } } ast::def_const(did) { @@ -2838,15 +2832,30 @@ fn trans_index(cx: @block_ctxt, sp: span, base: @ast::expr, idx: @ast::expr, ret lval_owned(next_cx, elt); } +// 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) +} + 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(bcx_tcx(bcx), e) { - let of = trans_object_field(bcx, base, ident); - ret {bcx: of.bcx, val: of.mthptr, kind: owned, - env: obj_env(of.objptr), generic: none}; + if !ty::expr_is_lval(method_map, bcx_tcx(bcx), e) { + alt method_map.find(e.id) { + some(did) { // An impl method + ret trans_method_callee(bcx, e, base, did); + } + none. { // An object method + let of = trans_object_field(bcx, base, ident); + ret {bcx: of.bcx, val: of.mthptr, kind: owned, + env: obj_env(of.objptr), generic: none}; + } + } } } ast::expr_self_method(ident) { @@ -3466,7 +3475,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_tcx(bcx), e) { + if ty::expr_is_lval(bcx_ccx(bcx).method_map, bcx_tcx(bcx), e) { ret trans_lval(bcx, e); } else { let tcx = bcx_tcx(bcx); @@ -3504,7 +3513,9 @@ 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(tcx, e) { ret lval_to_dps(bcx, e, dest); } + if ty::expr_is_lval(bcx_ccx(bcx).method_map, tcx, e) { + ret lval_to_dps(bcx, e, dest); + } alt e.node { ast::expr_if(cond, thn, els) | ast::expr_if_check(cond, thn, els) { @@ -3544,7 +3555,9 @@ 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(tcx, a) { ret trans_expr(bcx, a, dest); } + if !ty::expr_is_lval(bcx_ccx(bcx).method_map, tcx, a) { + ret trans_expr(bcx, a, dest); + } else { ret lval_to_dps(bcx, a, dest); } } ast::expr_cast(val, _) { @@ -3945,7 +3958,8 @@ fn init_local(bcx: @block_ctxt, local: @ast::local) -> @block_ctxt { alt local.node.init { some(init) { if init.op == ast::init_assign || - !ty::expr_is_lval(bcx_tcx(bcx), init.expr) { + !ty::expr_is_lval(bcx_ccx(bcx).method_map, bcx_tcx(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); @@ -4641,6 +4655,18 @@ 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]) { + let sub_cx = extend_path(cx, name); + for m in methods { + alt cx.ccx.item_ids.find(m.node.id) { + some(llfndecl) { + trans_fn(extend_path(sub_cx, m.node.ident), m.span, m.node.meth, + llfndecl, none, [], m.node.id); + } + } + } +} + // FIXME: this should do some structural hash-consing to avoid // duplicate constants. I think. Maybe LLVM has a magical mode @@ -4949,10 +4975,7 @@ 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(_, _, _) { - - fail "FIXME[impl]"; - } + ast::item_impl(_, _, ms) { trans_impl(cx, item.ident, ms); } ast::item_res(dtor, dtor_id, tps, ctor_id) { trans_res_ctor(cx, item.span, dtor, ctor_id, tps); @@ -5167,8 +5190,6 @@ fn raw_native_fn_type(ccx: @crate_ctxt, sp: span, args: [ty::arg], ret T_fn(type_of_explicit_args(ccx, sp, args), type_of(ccx, sp, ret_ty)); } -fn item_path(item: @ast::item) -> [str] { ret [item.ident]; } - fn link_name(i: @ast::native_item) -> str { alt attr::get_meta_item_value_str_by_name(i.attrs, "link_name") { none. { ret i.ident; } @@ -5259,12 +5280,12 @@ fn collect_item_1(ccx: @crate_ctxt, abi: @mutable option::t, } _ { } } - visit::visit_item(i, pt + item_path(i), v); + visit::visit_item(i, pt + [i.ident], v); } fn collect_item_2(ccx: @crate_ctxt, i: @ast::item, &&pt: [str], v: vt<[str]>) { - let new_pt = pt + item_path(i); + let new_pt = pt + [i.ident]; visit::visit_item(i, new_pt, v); alt i.node { ast::item_fn(f, tps) { @@ -5278,6 +5299,13 @@ fn collect_item_2(ccx: @crate_ctxt, i: @ast::item, &&pt: [str], ccx.obj_methods.insert(m.node.id, ()); } } + ast::item_impl(_, _, methods) { + let name = ccx.names.next(i.ident); + for m in methods { + register_fn(ccx, i.span, pt + [name, m.node.ident], + "impl_method", [], m.node.id); + } + } ast::item_res(_, dtor_id, tps, ctor_id) { register_fn(ccx, i.span, new_pt, "res_ctor", tps, ctor_id); // Note that the destructor is associated with the item's id, not @@ -5307,7 +5335,7 @@ fn collect_items(ccx: @crate_ctxt, crate: @ast::crate) { fn collect_tag_ctor(ccx: @crate_ctxt, i: @ast::item, &&pt: [str], v: vt<[str]>) { - let new_pt = pt + item_path(i); + let new_pt = pt + [i.ident]; visit::visit_item(i, new_pt, v); alt i.node { ast::item_tag(variants, tps) { @@ -5333,7 +5361,7 @@ fn collect_tag_ctors(ccx: @crate_ctxt, crate: @ast::crate) { // The constant translation pass. fn trans_constant(ccx: @crate_ctxt, it: @ast::item, &&pt: [str], v: vt<[str]>) { - let new_pt = pt + item_path(it); + let new_pt = pt + [it.ident]; visit::visit_item(it, new_pt, v); alt it.node { ast::item_tag(variants, _) { @@ -5520,7 +5548,7 @@ fn write_abi_version(ccx: @crate_ctxt) { fn trans_crate(sess: session::session, crate: @ast::crate, tcx: ty::ctxt, output: str, emap: resolve::exp_map, amap: ast_map::map, mut_map: mut::mut_map, copy_map: alias::copy_map, - last_uses: last_use::last_uses) + last_uses: last_use::last_uses, method_map: typeck::method_map) -> (ModuleRef, link::link_meta) { let sha = std::sha1::mk_sha1(); let link_meta = link::build_link_meta(sess, *crate, output, sha); @@ -5595,6 +5623,7 @@ fn trans_crate(sess: session::session, crate: @ast::crate, tcx: ty::ctxt, mut_map: mut_map, copy_map: copy_map, last_uses: last_uses, + method_map: method_map, stats: {mutable n_static_tydescs: 0u, mutable n_derived_tydescs: 0u, diff --git a/src/comp/middle/trans_common.rs b/src/comp/middle/trans_common.rs index 7d9775a6c2a..19f439235e4 100644 --- a/src/comp/middle/trans_common.rs +++ b/src/comp/middle/trans_common.rs @@ -104,6 +104,7 @@ type crate_ctxt = mut_map: mut::mut_map, copy_map: alias::copy_map, last_uses: last_use::last_uses, + method_map: typeck::method_map, stats: stats, upcalls: @upcall::upcalls, rust_object_type: TypeRef, diff --git a/src/comp/middle/ty.rs b/src/comp/middle/ty.rs index 1c5bdcb18f5..4265044c296 100644 --- a/src/comp/middle/ty.rs +++ b/src/comp/middle/ty.rs @@ -1672,15 +1672,18 @@ fn expr_has_ty_params(cx: ctxt, expr: @ast::expr) -> bool { ret node_id_has_type_params(cx, expr.id); } -fn expr_is_lval(tcx: ty::ctxt, e: @ast::expr) -> bool { +fn expr_is_lval(method_map: typeck::method_map, tcx: ty::ctxt, + e: @ast::expr) -> bool { alt e.node { ast::expr_path(_) | ast::expr_index(_, _) | ast::expr_unary(ast::deref., _) { true } ast::expr_field(base, ident) { - let basety = type_autoderef(tcx, expr_ty(tcx, base)); - alt struct(tcx, basety) { - ty_obj(_) { false } - ty_rec(_) { true } + method_map.contains_key(e.id) ? false : { + let basety = type_autoderef(tcx, expr_ty(tcx, base)); + alt struct(tcx, basety) { + ty_obj(_) { false } + ty_rec(_) { true } + } } } _ { false } diff --git a/src/comp/middle/typeck.rs b/src/comp/middle/typeck.rs index 10814ed61ae..03b7f40470d 100644 --- a/src/comp/middle/typeck.rs +++ b/src/comp/middle/typeck.rs @@ -18,7 +18,9 @@ import std::map::{hashmap, new_int_hash}; import option::{none, some}; import syntax::print::pprust::*; -export check_crate; +export check_crate, method_map; + +type method_map = hashmap; type ty_table = hashmap; @@ -35,6 +37,7 @@ tag obj_info { type crate_ctxt = {mutable obj_infos: [obj_info], impl_map: resolve::impl_map, + method_map: method_map, tcx: ty::ctxt}; type fn_ctxt = @@ -74,22 +77,21 @@ fn lookup_def(fcx: @fn_ctxt, sp: span, id: ast::node_id) -> ast::def { // Returns the type parameter count and the type for the given definition. fn ty_param_kinds_and_ty_for_def(fcx: @fn_ctxt, sp: span, defn: ast::def) -> ty_param_kinds_and_ty { - let no_kinds: [ast::kind] = []; alt defn { ast::def_arg(id, _) { assert (fcx.locals.contains_key(id.node)); let typ = ty::mk_var(fcx.ccx.tcx, lookup_local(fcx, sp, id.node)); - ret {kinds: no_kinds, ty: typ}; + ret {kinds: [], ty: typ}; } ast::def_local(id, _) { assert (fcx.locals.contains_key(id.node)); let typ = ty::mk_var(fcx.ccx.tcx, lookup_local(fcx, sp, id.node)); - ret {kinds: no_kinds, ty: typ}; + ret {kinds: [], ty: typ}; } ast::def_obj_field(id, _) { assert (fcx.locals.contains_key(id.node)); let typ = ty::mk_var(fcx.ccx.tcx, lookup_local(fcx, sp, id.node)); - ret {kinds: no_kinds, ty: typ}; + ret {kinds: [], ty: typ}; } ast::def_self(id) { fail "FIXME[impl]"; } ast::def_fn(id, _) { ret ty::lookup_item_type(fcx.ccx.tcx, id); } @@ -99,12 +101,12 @@ fn ty_param_kinds_and_ty_for_def(fcx: @fn_ctxt, sp: span, defn: ast::def) -> ast::def_binding(id) { assert (fcx.locals.contains_key(id.node)); let typ = ty::mk_var(fcx.ccx.tcx, lookup_local(fcx, sp, id.node)); - ret {kinds: no_kinds, ty: typ}; + ret {kinds: [], ty: typ}; } ast::def_mod(_) { // Hopefully part of a path. // TODO: return a type that's more poisonous, perhaps? - ret {kinds: no_kinds, ty: ty::mk_nil(fcx.ccx.tcx)}; + ret {kinds: [], ty: ty::mk_nil(fcx.ccx.tcx)}; } ast::def_ty(_) { fcx.ccx.tcx.sess.span_fatal(sp, "expected value but found type"); @@ -410,11 +412,10 @@ fn ast_ty_to_ty(tcx: ty::ctxt, mode: mode, &&ast_ty: @ast::ty) -> ty::t { fn ty_of_item(tcx: ty::ctxt, mode: mode, it: @ast::item) -> ty::ty_param_kinds_and_ty { - let no_kinds: [ast::kind] = []; alt it.node { ast::item_const(t, _) { let typ = ast_ty_to_ty(tcx, mode, t); - let tpt = {kinds: no_kinds, ty: typ}; + let tpt = {kinds: [], ty: typ}; tcx.tcache.insert(local_def(it.id), tpt); ret tpt; } @@ -463,7 +464,6 @@ fn ty_of_item(tcx: ty::ctxt, mode: mode, it: @ast::item) } fn ty_of_native_item(tcx: ty::ctxt, mode: mode, it: @ast::native_item) -> ty::ty_param_kinds_and_ty { - let no_kinds: [ast::kind] = []; alt it.node { ast::native_item_fn(fn_decl, params) { ret ty_of_native_fn_decl(tcx, mode, fn_decl, params, @@ -475,7 +475,7 @@ fn ty_of_native_item(tcx: ty::ctxt, mode: mode, it: @ast::native_item) none. { } } let t = ty::mk_native(tcx, ast_util::local_def(it.id)); - let tpt = {kinds: no_kinds, ty: t}; + let tpt = {kinds: [], ty: t}; tcx.tcache.insert(local_def(it.id), tpt); ret tpt; } @@ -698,9 +698,11 @@ mod collect { } ast::item_impl(_, _, ms) { for m in ms { - write::ty_only(cx.tcx, m.node.id, - ty::method_ty_to_fn_ty(cx.tcx, ty_of_method( - cx.tcx, m_collect, m))); + let ty = ty::method_ty_to_fn_ty( + cx.tcx, ty_of_method(cx.tcx, m_collect, m)); + cx.tcx.tcache.insert(local_def(m.node.id), + {kinds: [], ty: ty}); + write::ty_only(cx.tcx, m.node.id, ty); } } ast::item_obj(object, ty_params, ctor_id) { @@ -2179,6 +2181,7 @@ fn check_expr_with_unifier(fcx: @fn_ctxt, expr: @ast::expr, unify: unifier, 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); + fcx.ccx.method_map.insert(id, local_def(method.node.id)); } _ { base_t = do_autoderef(fcx, expr.span, base_t); @@ -2695,13 +2698,14 @@ fn check_for_main_fn(tcx: ty::ctxt, crate: @ast::crate) { } fn check_crate(tcx: ty::ctxt, impl_map: resolve::impl_map, - crate: @ast::crate) { + crate: @ast::crate) -> method_map { collect::collect_item_types(tcx, crate); let obj_infos: [obj_info] = []; let ccx = @{mutable obj_infos: obj_infos, impl_map: impl_map, + method_map: std::map::new_int_hash(), tcx: tcx}; let visit = visit::mk_simple_visitor(@{visit_item: bind check_item(ccx, _) @@ -2709,6 +2713,7 @@ fn check_crate(tcx: ty::ctxt, impl_map: resolve::impl_map, visit::visit_crate(*crate, (), visit); check_for_main_fn(tcx, crate); tcx.sess.abort_if_errors(); + ccx.method_map } // // Local Variables: