mirror of
https://github.com/rust-lang/rust
synced 2024-10-14 04:23:37 +00:00
Obj system? What obj system?
Removes the obj system from the compiler. Closes #1484
This commit is contained in:
parent
eb07fa4d3b
commit
24102d50ad
|
@ -46,7 +46,7 @@
|
|||
const tydesc_field_shape: int = 11;
|
||||
const tydesc_field_shape_tables: int = 12;
|
||||
const tydesc_field_n_params: int = 13;
|
||||
const tydesc_field_obj_params: int = 14;
|
||||
const tydesc_field_obj_params: int = 14; // FIXME unused
|
||||
const n_tydesc_fields: int = 15;
|
||||
|
||||
const cmp_glue_op_eq: uint = 0u;
|
||||
|
@ -55,19 +55,6 @@
|
|||
|
||||
const cmp_glue_op_le: uint = 2u;
|
||||
|
||||
const obj_field_vtbl: int = 0;
|
||||
|
||||
const obj_field_box: int = 1;
|
||||
|
||||
const obj_body_elt_tydesc: int = 0;
|
||||
|
||||
const obj_body_elt_typarams: int = 1;
|
||||
|
||||
const obj_body_elt_fields: int = 2;
|
||||
|
||||
// The base object to which an anonymous object is attached.
|
||||
const obj_body_elt_inner_obj: int = 3;
|
||||
|
||||
// The two halves of a closure: code and environment.
|
||||
const fn_field_code: int = 0;
|
||||
const fn_field_box: int = 1;
|
||||
|
|
|
@ -126,18 +126,6 @@ fn encode_module_item_paths(ebml_w: ebml::writer, module: _mod, path: [str],
|
|||
ebml::end_tag(ebml_w);
|
||||
encode_tag_variant_paths(ebml_w, variants, path, index);
|
||||
}
|
||||
item_obj(_, tps, ctor_id) {
|
||||
add_to_index(ebml_w, path, index, it.ident);
|
||||
ebml::start_tag(ebml_w, tag_paths_data_item);
|
||||
encode_name(ebml_w, it.ident);
|
||||
encode_def_id(ebml_w, local_def(ctor_id));
|
||||
ebml::end_tag(ebml_w);
|
||||
add_to_index(ebml_w, path, index, it.ident);
|
||||
ebml::start_tag(ebml_w, tag_paths_data_item);
|
||||
encode_name(ebml_w, it.ident);
|
||||
encode_def_id(ebml_w, local_def(it.id));
|
||||
ebml::end_tag(ebml_w);
|
||||
}
|
||||
item_iface(_, _) {
|
||||
add_to_index(ebml_w, path, index, it.ident);
|
||||
ebml::start_tag(ebml_w, tag_paths_data_item);
|
||||
|
@ -366,26 +354,6 @@ fn encode_info_for_item(ecx: @encode_ctxt, ebml_w: ebml::writer, item: @item,
|
|||
encode_symbol(ecx, ebml_w, ctor_id);
|
||||
ebml::end_tag(ebml_w);
|
||||
}
|
||||
item_obj(_, tps, ctor_id) {
|
||||
let fn_ty = node_id_to_monotype(tcx, ctor_id);
|
||||
|
||||
ebml::start_tag(ebml_w, tag_items_data_item);
|
||||
encode_def_id(ebml_w, local_def(item.id));
|
||||
encode_family(ebml_w, 'y' as u8);
|
||||
encode_type_param_bounds(ebml_w, ecx, tps);
|
||||
encode_type(ecx, ebml_w, ty::ty_fn_ret(tcx, fn_ty));
|
||||
encode_name(ebml_w, item.ident);
|
||||
ebml::end_tag(ebml_w);
|
||||
|
||||
index += [{val: ctor_id, pos: ebml_w.writer.tell()}];
|
||||
ebml::start_tag(ebml_w, tag_items_data_item);
|
||||
encode_def_id(ebml_w, local_def(ctor_id));
|
||||
encode_family(ebml_w, 'f' as u8);
|
||||
encode_type_param_bounds(ebml_w, ecx, tps);
|
||||
encode_type(ecx, ebml_w, fn_ty);
|
||||
encode_symbol(ecx, ebml_w, ctor_id);
|
||||
ebml::end_tag(ebml_w);
|
||||
}
|
||||
item_impl(tps, ifce, _, methods) {
|
||||
ebml::start_tag(ebml_w, tag_items_data_item);
|
||||
encode_def_id(ebml_w, local_def(item.id));
|
||||
|
|
|
@ -246,24 +246,6 @@ fn parse_ty(st: @pstate, conv: conv_did) -> ty::t {
|
|||
let func = parse_ty_fn(st, conv);
|
||||
ret ty::mk_native_fn(st.tcx, func.inputs, func.output);
|
||||
}
|
||||
'O' {
|
||||
assert (next(st) as char == '[');
|
||||
let methods: [ty::method] = [];
|
||||
while peek(st) as char != ']' {
|
||||
let proto;
|
||||
alt next(st) as char {
|
||||
'f' { proto = ast::proto_bare; }
|
||||
}
|
||||
let name = "";
|
||||
while peek(st) as char != '[' {
|
||||
name += str::unsafe_from_byte(next(st));
|
||||
}
|
||||
methods += [{ident: name, tps: @[],
|
||||
fty: {proto: proto with parse_ty_fn(st, conv)}}];
|
||||
}
|
||||
st.pos += 1u;
|
||||
ret ty::mk_obj(st.tcx, methods);
|
||||
}
|
||||
'r' {
|
||||
assert (next(st) as char == '[');
|
||||
let def = parse_def(st, conv);
|
||||
|
|
|
@ -157,15 +157,6 @@ fn enc_sty(w: io::writer, cx: @ctxt, st: ty::sty) {
|
|||
enc_ty_fn(w, cx, {proto: proto_bare, inputs: args, output: out,
|
||||
ret_style: return_val, constraints: []});
|
||||
}
|
||||
ty::ty_obj(methods) {
|
||||
w.write_str("O[");
|
||||
for m: ty::method in methods {
|
||||
enc_proto(w, m.fty.proto);
|
||||
w.write_str(m.ident);
|
||||
enc_ty_fn(w, cx, m.fty);
|
||||
}
|
||||
w.write_char(']');
|
||||
}
|
||||
ty::ty_res(def, ty, tps) {
|
||||
w.write_str("r[");
|
||||
w.write_str(cx.ds(def));
|
||||
|
|
|
@ -56,8 +56,8 @@ fn mk_binding(cx: ctx, id: node_id, span: span, root_var: option::t<node_id>,
|
|||
mutable silent: bool};
|
||||
|
||||
fn check_crate(tcx: ty::ctxt, crate: @ast::crate) -> (copy_map, ref_map) {
|
||||
// Stores information about object fields and function
|
||||
// arguments that's otherwise not easily available.
|
||||
// Stores information about function arguments that's otherwise not easily
|
||||
// available.
|
||||
let cx = @{tcx: tcx,
|
||||
copy_map: std::map::new_int_hash(),
|
||||
ref_map: std::map::new_int_hash(),
|
||||
|
@ -521,7 +521,7 @@ fn helper(tcx: ty::ctxt, needle: unsafe_ty, haystack: ty::t, mut: bool)
|
|||
}
|
||||
ty::ty_fn({proto: ast::proto_bare., _}) { ret false; }
|
||||
// These may contain anything.
|
||||
ty::ty_fn(_) | ty::ty_obj(_) { ret true; }
|
||||
ty::ty_fn(_) | ty::ty_iface(_, _) { ret true; }
|
||||
// A type param may include everything, but can only be
|
||||
// treated as opaque downstream, and is thus safe unless we
|
||||
// saw mutable fields, in which case the whole thing can be
|
||||
|
@ -536,8 +536,7 @@ fn helper(tcx: ty::ctxt, needle: unsafe_ty, haystack: ty::t, mut: bool)
|
|||
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 }
|
||||
ast::def_upvar(_, _, _) | ast::def_self(_) { true }
|
||||
_ { false }
|
||||
}
|
||||
}
|
||||
|
@ -557,10 +556,9 @@ fn score_ty(tcx: ty::ctxt, ty: ty::t) -> uint {
|
|||
ty::ty_nil. | ty::ty_bot. | ty::ty_bool. | ty::ty_int(_) |
|
||||
ty::ty_uint(_) | ty::ty_float(_) | ty::ty_type. | ty::ty_native(_) |
|
||||
ty::ty_ptr(_) { 1u }
|
||||
ty::ty_box(_) { 3u }
|
||||
ty::ty_box(_) | ty::ty_iface(_, _) { 3u }
|
||||
ty::ty_constr(t, _) | ty::ty_res(_, t, _) { score_ty(tcx, t) }
|
||||
ty::ty_fn(_) | ty::ty_native_fn(_, _) |
|
||||
ty::ty_obj(_) { 4u }
|
||||
ty::ty_fn(_) | ty::ty_native_fn(_, _) { 4u }
|
||||
ty::ty_str. | ty::ty_vec(_) | ty::ty_param(_, _) { 50u }
|
||||
ty::ty_uniq(mt) { 1u + score_ty(tcx, mt.ty) }
|
||||
ty::ty_tag(_, ts) | ty::ty_tup(ts) {
|
||||
|
@ -633,17 +631,6 @@ fn expr_root(cx: ctx, ex: @ast::expr, autoderef: bool)
|
|||
for d in *base_root.ds {
|
||||
if d.mut { unsafe_ty = some(contains(d.outer_t)); break; }
|
||||
}
|
||||
alt base_root.ex.node {
|
||||
ast::expr_path(_) {
|
||||
alt cx.tcx.def_map.get(base_root.ex.id) {
|
||||
ast::def_obj_field(_, ast::mut.) {
|
||||
unsafe_ty = some(mut_contains(ty::expr_ty(cx.tcx, base_root.ex)));
|
||||
}
|
||||
_ {}
|
||||
}
|
||||
}
|
||||
_ {}
|
||||
}
|
||||
ret {ex: base_root.ex, mut: unsafe_ty};
|
||||
}
|
||||
|
||||
|
|
|
@ -6,8 +6,6 @@
|
|||
|
||||
tag ast_node {
|
||||
node_item(@item);
|
||||
node_obj_ctor(@item);
|
||||
node_obj_method(@method);
|
||||
node_native_item(@native_item);
|
||||
node_method(@method);
|
||||
node_expr(@expr);
|
||||
|
@ -62,12 +60,6 @@ fn map_arm(cx: ctx, arm: arm) {
|
|||
fn map_item(cx: ctx, i: @item) {
|
||||
cx.map.insert(i.id, node_item(i));
|
||||
alt i.node {
|
||||
item_obj(ob, _, ctor_id) {
|
||||
cx.map.insert(ctor_id, node_obj_ctor(i));
|
||||
for m in ob.methods {
|
||||
cx.map.insert(m.id, node_obj_method(m));
|
||||
}
|
||||
}
|
||||
item_impl(_, _, _, ms) {
|
||||
for m in ms { cx.map.insert(m.id, node_method(m)); }
|
||||
}
|
||||
|
@ -85,20 +77,11 @@ fn map_native_item(cx: ctx, i: @native_item) {
|
|||
|
||||
fn map_expr(cx: ctx, ex: @expr) {
|
||||
cx.map.insert(ex.id, node_expr(ex));
|
||||
alt ex.node {
|
||||
expr_anon_obj(ao) {
|
||||
for m in ao.methods {
|
||||
cx.map.insert(m.id, node_obj_method(m));
|
||||
}
|
||||
}
|
||||
_ {}
|
||||
}
|
||||
}
|
||||
|
||||
fn node_span(node: ast_node) -> codemap::span {
|
||||
alt node {
|
||||
node_item(item) { item.span }
|
||||
node_obj_ctor(item) { item.span }
|
||||
node_native_item(nitem) { nitem.span }
|
||||
node_expr(expr) { expr.span }
|
||||
}
|
||||
|
@ -120,18 +103,6 @@ fn test_node_span_item() {
|
|||
assert (node_span(node) == expected);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_node_span_obj_ctor() {
|
||||
let expected: codemap::span = ast_util::mk_sp(20u, 30u);
|
||||
let node =
|
||||
node_obj_ctor(@{ident: "test",
|
||||
attrs: [],
|
||||
id: 0,
|
||||
node: item_mod({view_items: [], items: []}),
|
||||
span: expected});
|
||||
assert (node_span(node) == expected);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_node_span_native_item() {
|
||||
let expected: codemap::span = ast_util::mk_sp(20u, 30u);
|
||||
|
|
|
@ -727,9 +727,6 @@ fn create_function(fcx: @fn_ctxt) -> @metadata<subprogram_md> {
|
|||
}
|
||||
}
|
||||
}
|
||||
ast_map::node_obj_method(method) | ast_map::node_method(method) {
|
||||
(method.ident, method.decl.output, method.id)
|
||||
}
|
||||
ast_map::node_res_ctor(item) {
|
||||
alt item.node { ast::item_res(decl, _, _, _, ctor_id) {
|
||||
(item.ident, decl.output, ctor_id)
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
import lib::llvm::True;
|
||||
import lib::llvm::llvm::ValueRef;
|
||||
import middle::trans;
|
||||
import middle::trans::{get_tydesc, tps_normal};
|
||||
import middle::trans::get_tydesc;
|
||||
import middle::trans_common::*;
|
||||
import middle::ty;
|
||||
import option::none;
|
||||
|
@ -43,7 +43,7 @@ fn add_gc_root(cx: @block_ctxt, llval: ValueRef, ty: ty::t) -> @block_ctxt {
|
|||
bcx = trans::zero_alloca(bcx, llval, ty);
|
||||
|
||||
let ti = none;
|
||||
let td_r = get_tydesc(bcx, ty, false, tps_normal, ti);
|
||||
let td_r = get_tydesc(bcx, ty, false, ti);
|
||||
bcx = td_r.result.bcx;
|
||||
let lltydesc = td_r.result.val;
|
||||
|
||||
|
@ -147,7 +147,7 @@ fn type_is_gc_relevant(cx: ty::ctxt, ty: ty::t) -> bool {
|
|||
}
|
||||
ty::ty_constr(sub, _) { ret type_is_gc_relevant(cx, sub); }
|
||||
ty::ty_box(_) | ty::ty_uniq(_) | ty::ty_fn(_) |
|
||||
ty::ty_native_fn(_, _) | ty::ty_obj(_) | ty::ty_param(_, _) |
|
||||
ty::ty_native_fn(_, _) | ty::ty_param(_, _) |
|
||||
ty::ty_res(_, _, _) { ret true; }
|
||||
ty::ty_var(_) {
|
||||
fail "ty_var in type_is_gc_relevant";
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
// Kind analysis pass. There are three kinds:
|
||||
//
|
||||
// sendable: scalar types, and unique types containing only sendable types
|
||||
// copyable: boxes, objects, closures, and uniques containing copyable types
|
||||
// copyable: boxes, closures, and uniques containing copyable types
|
||||
// noncopyable: resources, or unique types containing resources
|
||||
//
|
||||
// This pass ensures that type parameters are only instantiated with types
|
||||
|
@ -218,7 +218,7 @@ fn maybe_copy(cx: ctx, ex: @expr) {
|
|||
}
|
||||
|
||||
fn check_copy_ex(cx: ctx, ex: @expr, _warn: bool) {
|
||||
if ty::expr_is_lval(cx.method_map, cx.tcx, ex) &&
|
||||
if ty::expr_is_lval(cx.method_map, ex) &&
|
||||
!cx.last_uses.contains_key(ex.id) {
|
||||
let ty = ty::expr_ty(cx.tcx, ex);
|
||||
check_copy(cx, ty, ex.span);
|
||||
|
|
|
@ -60,7 +60,7 @@ fn maybe_auto_unbox(tcx: ty::ctxt, t: ty::t) -> {t: ty::t, ds: [deref]} {
|
|||
}
|
||||
}
|
||||
}
|
||||
ty::ty_obj(_) { }
|
||||
_ {}
|
||||
}
|
||||
ds += [@{mut: is_mut, kind: field, outer_t: auto_unbox.t}];
|
||||
ds += auto_unbox.ds;
|
||||
|
@ -201,9 +201,6 @@ fn check_move_rhs(cx: @ctx, src: @expr) {
|
|||
alt src.node {
|
||||
expr_path(p) {
|
||||
alt cx.tcx.def_map.get(src.id) {
|
||||
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");
|
||||
}
|
||||
|
@ -267,7 +264,6 @@ fn is_immutable_def(cx: @ctx, def: def) -> option::t<str> {
|
|||
}
|
||||
def_arg(_, by_ref.) | def_arg(_, by_val.) |
|
||||
def_arg(_, mode_infer.) { some("argument") }
|
||||
def_obj_field(_, imm.) { some("immutable object field") }
|
||||
def_self(_) { some("self argument") }
|
||||
def_upvar(_, inner, node_id) {
|
||||
let ty = ty::node_id_to_monotype(cx.tcx, node_id);
|
||||
|
|
|
@ -535,9 +535,6 @@ 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_method(x.id, []), @sc), v);
|
||||
}
|
||||
_ { visit::visit_expr(x, sc, v); }
|
||||
}
|
||||
}
|
||||
|
@ -852,9 +849,9 @@ fn def_is_local(d: def) -> bool {
|
|||
}
|
||||
}
|
||||
|
||||
fn def_has_obj_scope(d: def) -> bool {
|
||||
fn def_is_self(d: def) -> bool {
|
||||
alt d {
|
||||
ast::def_obj_field(_, _) | ast::def_self(_) { true }
|
||||
ast::def_self(_) { true }
|
||||
_ { false }
|
||||
}
|
||||
}
|
||||
|
@ -874,9 +871,6 @@ fn in_scope(e: env, sp: span, name: ident, s: scope, ns: namespace) ->
|
|||
}
|
||||
scope_item(it) {
|
||||
alt it.node {
|
||||
ast::item_obj(ob, ty_params, _) {
|
||||
ret lookup_in_obj(e, name, ob, ty_params, ns, it.id);
|
||||
}
|
||||
ast::item_impl(tps, _, _, _) {
|
||||
if ns == ns_type { ret lookup_in_ty_params(e, name, tps); }
|
||||
}
|
||||
|
@ -935,7 +929,7 @@ fn in_scope(e: env, sp: span, name: ident, s: scope, ns: namespace) ->
|
|||
}
|
||||
let left_fn = false;
|
||||
let closing = [];
|
||||
// Used to determine whether obj fields are in scope
|
||||
// Used to determine whether self is in scope
|
||||
let left_fn_level2 = false;
|
||||
let sc = sc;
|
||||
while true {
|
||||
|
@ -945,9 +939,8 @@ fn in_scope(e: env, sp: span, name: ident, s: scope, ns: namespace) ->
|
|||
let fnd = in_scope(e, sp, name, hd, ns);
|
||||
if !is_none(fnd) {
|
||||
let df = option::get(fnd);
|
||||
let local = def_is_local(df),
|
||||
obj_scope = def_has_obj_scope(df);
|
||||
if left_fn && local || left_fn_level2 && obj_scope
|
||||
let local = def_is_local(df), self_scope = def_is_self(df);
|
||||
if left_fn && local || left_fn_level2 && self_scope
|
||||
|| scope_is_fn(hd) && left_fn && def_is_ty_arg(df) {
|
||||
let msg = alt ns {
|
||||
ns_type. {
|
||||
|
@ -965,7 +958,7 @@ fn in_scope(e: env, sp: span, name: ident, s: scope, ns: namespace) ->
|
|||
_ { "attempted dynamic environment-capture" }
|
||||
};
|
||||
e.sess.span_fatal(sp, msg);
|
||||
} else if local || obj_scope {
|
||||
} else if local || self_scope {
|
||||
let i = vec::len(closing);
|
||||
while i > 0u {
|
||||
i -= 1u;
|
||||
|
@ -1030,24 +1023,6 @@ fn lookup_in_fn(e: env, name: ident, decl: ast::fn_decl,
|
|||
}
|
||||
}
|
||||
|
||||
fn lookup_in_obj(e: env, name: ident, ob: ast::_obj,
|
||||
ty_params: [ast::ty_param],
|
||||
ns: namespace, id: node_id) -> option::t<def> {
|
||||
alt ns {
|
||||
ns_val(val_ty) {
|
||||
if name == "self" && val_ty == ns_any_value
|
||||
{ ret some(ast::def_self(local_def(id))); }
|
||||
for f: ast::obj_field in ob.fields {
|
||||
if str::eq(f.ident, name) && val_ty == ns_any_value {
|
||||
ret some(ast::def_obj_field(local_def(f.id), f.mut));
|
||||
}
|
||||
}
|
||||
ret none::<def>;
|
||||
}
|
||||
ns_type. { ret lookup_in_ty_params(e, name, ty_params); }
|
||||
_ { ret none::<def>; }
|
||||
}
|
||||
}
|
||||
|
||||
fn lookup_in_block(e: env, name: ident, sp: span, b: ast::blk_, pos: uint,
|
||||
loc_pos: uint, ns: namespace) -> option::t<def> {
|
||||
|
@ -1166,15 +1141,6 @@ fn found_def_item(i: @ast::item, ns: namespace) -> option::t<def> {
|
|||
_ { }
|
||||
}
|
||||
}
|
||||
ast::item_obj(_, _, ctor_id) {
|
||||
alt ns {
|
||||
ns_val(ns_any_value.) {
|
||||
ret some(ast::def_fn(local_def(ctor_id), ast::impure_fn));
|
||||
}
|
||||
ns_type. { ret some(ast::def_ty(local_def(i.id))); }
|
||||
_ { }
|
||||
}
|
||||
}
|
||||
_ { }
|
||||
}
|
||||
ret none;
|
||||
|
@ -1422,7 +1388,7 @@ fn index_mod(md: ast::_mod) -> mod_index {
|
|||
alt it.node {
|
||||
ast::item_const(_, _) | ast::item_fn(_, _, _) | ast::item_mod(_) |
|
||||
ast::item_native_mod(_) | ast::item_ty(_, _) |
|
||||
ast::item_res(_, _, _, _, _) | ast::item_obj(_, _, _) |
|
||||
ast::item_res(_, _, _, _, _) |
|
||||
ast::item_impl(_, _, _, _) | ast::item_iface(_, _) {
|
||||
add_to_index(index, it.ident, mie_item(it));
|
||||
}
|
||||
|
@ -1470,7 +1436,7 @@ fn index_nmod(md: ast::native_mod) -> mod_index {
|
|||
fn ns_for_def(d: def) -> namespace {
|
||||
alt d {
|
||||
ast::def_variant(_, _) { ns_val(ns_a_tag) }
|
||||
ast::def_fn(_, _) | ast::def_obj_field(_, _) | ast::def_self(_) |
|
||||
ast::def_fn(_, _) | ast::def_self(_) |
|
||||
ast::def_const(_) | ast::def_arg(_, _) | ast::def_local(_, _) |
|
||||
ast::def_upvar(_, _, _) | ast::def_native_fn(_, _) | ast::def_self(_)
|
||||
{ ns_val(ns_any_value) }
|
||||
|
@ -1597,15 +1563,6 @@ fn typaram_names(tps: [ast::ty_param]) -> [ident] {
|
|||
ensure_unique(*e, i.span, typaram_names(ty_params), ident_id,
|
||||
"type parameter");
|
||||
}
|
||||
ast::item_obj(ob, ty_params, _) {
|
||||
fn field_name(field: ast::obj_field) -> ident { ret field.ident; }
|
||||
ensure_unique(*e, i.span, ob.fields, field_name, "object field");
|
||||
for m: @ast::method in ob.methods {
|
||||
check_fn(*e, m.span, m.decl);
|
||||
}
|
||||
ensure_unique(*e, i.span, typaram_names(ty_params), ident_id,
|
||||
"type parameter");
|
||||
}
|
||||
ast::item_tag(_, ty_params) {
|
||||
ensure_unique(*e, i.span, typaram_names(ty_params), ident_id,
|
||||
"type parameter");
|
||||
|
@ -1687,7 +1644,7 @@ fn check_block(e: @env, b: ast::blk, &&x: (), v: vt<()>) {
|
|||
ast::item_ty(_, _) | ast::item_iface(_, _) {
|
||||
add_name(types, it.span, it.ident);
|
||||
}
|
||||
ast::item_res(_, _, _, _, _) | ast::item_obj(_, _, _) {
|
||||
ast::item_res(_, _, _, _, _) {
|
||||
add_name(types, it.span, it.ident);
|
||||
add_name(values, it.span, it.ident);
|
||||
}
|
||||
|
|
|
@ -47,7 +47,7 @@
|
|||
const shape_box: u8 = 13u8;
|
||||
const shape_struct: u8 = 17u8;
|
||||
const shape_box_fn: u8 = 18u8;
|
||||
const shape_obj: u8 = 19u8;
|
||||
const shape_UNUSED: u8 = 19u8;
|
||||
const shape_res: u8 = 20u8;
|
||||
const shape_var: u8 = 21u8;
|
||||
const shape_uniq: u8 = 22u8;
|
||||
|
@ -309,8 +309,7 @@ fn add_substr(&dest: [u8], src: [u8]) {
|
|||
dest += src;
|
||||
}
|
||||
|
||||
fn shape_of(ccx: @crate_ctxt, t: ty::t, ty_param_map: [uint],
|
||||
is_obj_body: bool) -> [u8] {
|
||||
fn shape_of(ccx: @crate_ctxt, t: ty::t, ty_param_map: [uint]) -> [u8] {
|
||||
let s = [];
|
||||
|
||||
alt ty::struct(ccx.tcx, t) {
|
||||
|
@ -335,7 +334,7 @@ fn shape_of(ccx: @crate_ctxt, t: ty::t, ty_param_map: [uint],
|
|||
s += [shape_vec];
|
||||
add_bool(s, true); // type is POD
|
||||
let unit_ty = ty::mk_mach_uint(ccx.tcx, ast::ty_u8);
|
||||
add_substr(s, shape_of(ccx, unit_ty, ty_param_map, is_obj_body));
|
||||
add_substr(s, shape_of(ccx, unit_ty, ty_param_map));
|
||||
}
|
||||
ty::ty_tag(did, tps) {
|
||||
alt tag_kind(ccx, did) {
|
||||
|
@ -363,7 +362,7 @@ fn shape_of(ccx: @crate_ctxt, t: ty::t, ty_param_map: [uint],
|
|||
|
||||
add_u16(sub, vec::len(tps) as u16);
|
||||
for tp: ty::t in tps {
|
||||
let subshape = shape_of(ccx, tp, ty_param_map, is_obj_body);
|
||||
let subshape = shape_of(ccx, tp, ty_param_map);
|
||||
add_u16(sub, vec::len(subshape) as u16);
|
||||
sub += subshape;
|
||||
}
|
||||
|
@ -374,22 +373,22 @@ fn shape_of(ccx: @crate_ctxt, t: ty::t, ty_param_map: [uint],
|
|||
}
|
||||
ty::ty_box(mt) {
|
||||
s += [shape_box];
|
||||
add_substr(s, shape_of(ccx, mt.ty, ty_param_map, is_obj_body));
|
||||
add_substr(s, shape_of(ccx, mt.ty, ty_param_map));
|
||||
}
|
||||
ty::ty_uniq(mt) {
|
||||
s += [shape_uniq];
|
||||
add_substr(s, shape_of(ccx, mt.ty, ty_param_map, is_obj_body));
|
||||
add_substr(s, shape_of(ccx, mt.ty, ty_param_map));
|
||||
}
|
||||
ty::ty_vec(mt) {
|
||||
s += [shape_vec];
|
||||
add_bool(s, ty::type_is_pod(ccx.tcx, mt.ty));
|
||||
add_substr(s, shape_of(ccx, mt.ty, ty_param_map, is_obj_body));
|
||||
add_substr(s, shape_of(ccx, mt.ty, ty_param_map));
|
||||
}
|
||||
ty::ty_rec(fields) {
|
||||
s += [shape_struct];
|
||||
let sub = [];
|
||||
for f: field in fields {
|
||||
sub += shape_of(ccx, f.mt.ty, ty_param_map, is_obj_body);
|
||||
sub += shape_of(ccx, f.mt.ty, ty_param_map);
|
||||
}
|
||||
add_substr(s, sub);
|
||||
}
|
||||
|
@ -397,12 +396,11 @@ fn shape_of(ccx: @crate_ctxt, t: ty::t, ty_param_map: [uint],
|
|||
s += [shape_struct];
|
||||
let sub = [];
|
||||
for elt in elts {
|
||||
sub += shape_of(ccx, elt, ty_param_map, is_obj_body);
|
||||
sub += shape_of(ccx, elt, ty_param_map);
|
||||
}
|
||||
add_substr(s, sub);
|
||||
}
|
||||
ty::ty_native_fn(_, _) { s += [shape_u32]; }
|
||||
ty::ty_obj(_) { s += [shape_obj]; }
|
||||
ty::ty_iface(_, _) { s += [shape_iface]; }
|
||||
ty::ty_res(did, raw_subt, tps) {
|
||||
let subt = ty::substitute_type_params(ccx.tcx, tps, raw_subt);
|
||||
|
@ -413,24 +411,19 @@ fn shape_of(ccx: @crate_ctxt, t: ty::t, ty_param_map: [uint],
|
|||
add_u16(s, id as u16);
|
||||
add_u16(s, vec::len(tps) as u16);
|
||||
for tp: ty::t in tps {
|
||||
add_substr(s, shape_of(ccx, tp, ty_param_map, is_obj_body));
|
||||
add_substr(s, shape_of(ccx, tp, ty_param_map));
|
||||
}
|
||||
add_substr(s, shape_of(ccx, subt, ty_param_map, is_obj_body));
|
||||
add_substr(s, shape_of(ccx, subt, ty_param_map));
|
||||
|
||||
}
|
||||
ty::ty_var(n) {
|
||||
fail "shape_of ty_var";
|
||||
}
|
||||
ty::ty_param(n, _) {
|
||||
if is_obj_body {
|
||||
// Just write in the parameter number.
|
||||
s += [shape_var, n as u8];
|
||||
} else {
|
||||
// Find the type parameter in the parameter list.
|
||||
alt vec::position(n, ty_param_map) {
|
||||
some(i) { s += [shape_var, i as u8]; }
|
||||
none. { fail "ty param not found in ty_param_map"; }
|
||||
}
|
||||
// Find the type parameter in the parameter list.
|
||||
alt vec::position(n, ty_param_map) {
|
||||
some(i) { s += [shape_var, i as u8]; }
|
||||
none. { fail "ty param not found in ty_param_map"; }
|
||||
}
|
||||
}
|
||||
ty::ty_fn({proto: ast::proto_box., _}) {
|
||||
|
@ -461,7 +454,7 @@ fn shape_of_variant(ccx: @crate_ctxt, v: ty::variant_info,
|
|||
while i < ty_param_count { ty_param_map += [i]; i += 1u; }
|
||||
|
||||
let s = [];
|
||||
for t: ty::t in v.args { s += shape_of(ccx, t, ty_param_map, false); }
|
||||
for t: ty::t in v.args { s += shape_of(ccx, t, ty_param_map); }
|
||||
ret s;
|
||||
}
|
||||
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
//
|
||||
// Some functions here, such as trans_block and trans_expr, return a value --
|
||||
// the result of the translation to LLVM -- while others, such as trans_fn,
|
||||
// trans_obj, and trans_item, are called only for the side effect of adding a
|
||||
// trans_impl, and trans_item, are called only for the side effect of adding a
|
||||
// particular definition to the LLVM IR output we're producing.
|
||||
//
|
||||
// Hopefully useful general knowledge about trans:
|
||||
|
@ -42,8 +42,6 @@
|
|||
|
||||
import trans_common::*;
|
||||
import trans_build::*;
|
||||
|
||||
import trans_objects::{trans_anon_obj, trans_obj};
|
||||
import tvec = trans_vec;
|
||||
|
||||
fn type_of_1(bcx: @block_ctxt, t: ty::t) -> TypeRef {
|
||||
|
@ -81,7 +79,7 @@ fn type_of_explicit_args(cx: @crate_ctxt, sp: span, inputs: [ty::arg]) ->
|
|||
// - create_llargs_for_fn_args.
|
||||
// - new_fn_ctxt
|
||||
// - trans_args
|
||||
fn type_of_fn(cx: @crate_ctxt, sp: span, is_method: bool, inputs: [ty::arg],
|
||||
fn type_of_fn(cx: @crate_ctxt, sp: span, inputs: [ty::arg],
|
||||
output: ty::t, params: [ty::param_bounds]) -> TypeRef {
|
||||
let atys: [TypeRef] = [];
|
||||
|
||||
|
@ -90,22 +88,16 @@ fn type_of_fn(cx: @crate_ctxt, sp: span, is_method: bool, inputs: [ty::arg],
|
|||
let out_ty = T_ptr(type_of_inner(cx, sp, output));
|
||||
atys += [out_ty];
|
||||
|
||||
// Arg 1: Env (closure-bindings / self-obj)
|
||||
if is_method {
|
||||
atys += [T_ptr(cx.rust_object_type)];
|
||||
} else {
|
||||
atys += [T_opaque_cbox_ptr(cx)];
|
||||
}
|
||||
// Arg 1: Environment
|
||||
atys += [T_opaque_cbox_ptr(cx)];
|
||||
|
||||
// Args >2: ty params, if not acquired via capture...
|
||||
if !is_method {
|
||||
for bounds in params {
|
||||
atys += [T_ptr(cx.tydesc_type)];
|
||||
for bound in *bounds {
|
||||
alt bound {
|
||||
ty::bound_iface(_) { atys += [T_ptr(T_dict())]; }
|
||||
_ {}
|
||||
}
|
||||
for bounds in params {
|
||||
atys += [T_ptr(cx.tydesc_type)];
|
||||
for bound in *bounds {
|
||||
alt bound {
|
||||
ty::bound_iface(_) { atys += [T_ptr(T_dict())]; }
|
||||
_ {}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -121,7 +113,7 @@ fn type_of_fn_from_ty(cx: @crate_ctxt, sp: span, fty: ty::t,
|
|||
// by returns_non_ty_var(t). Make that a postcondition
|
||||
// (see Issue #586)
|
||||
let ret_ty = ty::ty_fn_ret(cx.tcx, fty);
|
||||
ret type_of_fn(cx, sp, false, ty::ty_fn_args(cx.tcx, fty),
|
||||
ret type_of_fn(cx, sp, ty::ty_fn_args(cx.tcx, fty),
|
||||
ret_ty, param_bounds);
|
||||
}
|
||||
|
||||
|
@ -179,7 +171,6 @@ fn type_of_inner(cx: @crate_ctxt, sp: span, t: ty::t)
|
|||
let nft = native_fn_wrapper_type(cx, sp, [], t);
|
||||
T_fn_pair(cx, nft)
|
||||
}
|
||||
ty::ty_obj(_) { cx.rust_object_type }
|
||||
ty::ty_iface(_, _) { T_opaque_iface_ptr(cx) }
|
||||
ty::ty_res(_, sub, tps) {
|
||||
let sub1 = ty::substitute_type_params(cx.tcx, tps, sub);
|
||||
|
@ -465,7 +456,7 @@ fn dynastack_alloca(cx: @block_ctxt, t: TypeRef, n: ValueRef, ty: ty::t) ->
|
|||
n);
|
||||
|
||||
let ti = none;
|
||||
let lltydesc = get_tydesc(cx, ty, false, tps_normal, ti).result.val;
|
||||
let lltydesc = get_tydesc(cx, ty, false, ti).result.val;
|
||||
|
||||
let llresult = Call(dy_cx, dynastack_alloc, [llsz, lltydesc]);
|
||||
ret PointerCast(dy_cx, llresult, T_ptr(t));
|
||||
|
@ -496,11 +487,6 @@ fn simplifier(ccx: @crate_ctxt, typ: ty::t) -> ty::t {
|
|||
[ty::mk_imm_box(ccx.tcx, ty::mk_nil(ccx.tcx)),
|
||||
ty::mk_imm_box(ccx.tcx, ty::mk_nil(ccx.tcx))]);
|
||||
}
|
||||
ty::ty_obj(_) {
|
||||
ret ty::mk_tup(ccx.tcx,
|
||||
[ty::mk_imm_box(ccx.tcx, ty::mk_nil(ccx.tcx)),
|
||||
ty::mk_imm_box(ccx.tcx, ty::mk_nil(ccx.tcx))]);
|
||||
}
|
||||
ty::ty_res(_, sub, tps) {
|
||||
let sub1 = ty::substitute_type_params(ccx.tcx, tps, sub);
|
||||
ret ty::mk_tup(ccx.tcx,
|
||||
|
@ -871,7 +857,7 @@ fn trans_malloc_boxed_raw(cx: @block_ctxt, t: ty::t) -> result {
|
|||
let llty = type_of(ccx, sp, box_ptr);
|
||||
|
||||
let ti = none;
|
||||
let tydesc_result = get_tydesc(bcx, t, true, tps_normal, ti);
|
||||
let tydesc_result = get_tydesc(bcx, t, true, ti);
|
||||
let lltydesc = tydesc_result.result.val; bcx = tydesc_result.result.bcx;
|
||||
|
||||
let rval = Call(cx, ccx.upcalls.malloc,
|
||||
|
@ -899,7 +885,7 @@ fn trans_malloc_boxed(cx: @block_ctxt, t: ty::t) ->
|
|||
fn field_of_tydesc(cx: @block_ctxt, t: ty::t, escapes: bool, field: int) ->
|
||||
result {
|
||||
let ti = none::<@tydesc_info>;
|
||||
let tydesc = get_tydesc(cx, t, escapes, tps_normal, ti).result;
|
||||
let tydesc = get_tydesc(cx, t, escapes, ti).result;
|
||||
ret rslt(tydesc.bcx,
|
||||
GEPi(tydesc.bcx, tydesc.val, [0, field]));
|
||||
}
|
||||
|
@ -936,8 +922,8 @@ fn linearizer(r: @rr, t: ty::t) {
|
|||
|
||||
fn trans_stack_local_derived_tydesc(cx: @block_ctxt, llsz: ValueRef,
|
||||
llalign: ValueRef, llroottydesc: ValueRef,
|
||||
llfirstparam: ValueRef, n_params: uint,
|
||||
obj_params: uint) -> ValueRef {
|
||||
llfirstparam: ValueRef, n_params: uint)
|
||||
-> ValueRef {
|
||||
let llmyroottydesc = alloca(cx, bcx_ccx(cx).tydesc_type);
|
||||
|
||||
// By convention, desc 0 is the root descriptor.
|
||||
|
@ -954,39 +940,29 @@ fn trans_stack_local_derived_tydesc(cx: @block_ctxt, llsz: ValueRef,
|
|||
[0, abi::tydesc_field_size]);
|
||||
store_inbounds(cx, llalign, llmyroottydesc,
|
||||
[0, abi::tydesc_field_align]);
|
||||
store_inbounds(cx, C_uint(ccx, obj_params), llmyroottydesc,
|
||||
// FIXME legacy field, can be dropped
|
||||
store_inbounds(cx, C_uint(ccx, 0u), llmyroottydesc,
|
||||
[0, abi::tydesc_field_obj_params]);
|
||||
ret llmyroottydesc;
|
||||
}
|
||||
|
||||
// Objects store their type parameters differently (in the object itself
|
||||
// rather than in the type descriptor).
|
||||
tag ty_param_storage { tps_normal; tps_obj(uint); }
|
||||
|
||||
fn get_derived_tydesc(cx: @block_ctxt, t: ty::t, escapes: bool,
|
||||
storage: ty_param_storage,
|
||||
&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 {
|
||||
if !(escapes && !info.escapes) {
|
||||
ret rslt(cx, info.lltydesc);
|
||||
}
|
||||
}
|
||||
none. {/* fall through */ }
|
||||
}
|
||||
|
||||
let is_obj_body;
|
||||
alt storage {
|
||||
tps_normal. { is_obj_body = false; }
|
||||
tps_obj(_) { is_obj_body = true; }
|
||||
}
|
||||
|
||||
bcx_ccx(cx).stats.n_derived_tydescs += 1u;
|
||||
let bcx = new_raw_block_ctxt(cx.fcx, cx.fcx.llderivedtydescs);
|
||||
let tys = linearize_ty_params(bcx, t);
|
||||
let root_ti = get_static_tydesc(bcx, t, tys.params, is_obj_body);
|
||||
let root_ti = get_static_tydesc(bcx, t, tys.params);
|
||||
static_ti = some::<@tydesc_info>(root_ti);
|
||||
lazily_emit_all_tydesc_glue(cx, static_ti);
|
||||
let root = root_ti.tydesc;
|
||||
|
@ -1022,14 +998,6 @@ fn get_derived_tydesc(cx: @block_ctxt, t: ty::t, escapes: bool,
|
|||
PointerCast(bcx, llparamtydescs,
|
||||
T_ptr(T_ptr(bcx_ccx(bcx).tydesc_type)));
|
||||
|
||||
// The top bit indicates whether this type descriptor describes an object
|
||||
// (0) or a function (1).
|
||||
let obj_params;
|
||||
alt storage {
|
||||
tps_normal. { obj_params = 0u; }
|
||||
tps_obj(np) { obj_params = np; }
|
||||
}
|
||||
|
||||
let v;
|
||||
if escapes {
|
||||
let ccx = bcx_ccx(bcx);
|
||||
|
@ -1037,13 +1005,11 @@ fn get_derived_tydesc(cx: @block_ctxt, t: ty::t, escapes: bool,
|
|||
Call(bcx, ccx.upcalls.get_type_desc,
|
||||
[C_null(T_ptr(T_nil())), sz.val,
|
||||
align.val, C_uint(ccx, 1u + n_params), llfirstparam,
|
||||
C_uint(ccx, obj_params)]);
|
||||
C_uint(ccx, 0u)]);
|
||||
v = td_val;
|
||||
} else {
|
||||
v =
|
||||
trans_stack_local_derived_tydesc(bcx, sz.val, align.val, root,
|
||||
llfirstparam, n_params,
|
||||
obj_params);
|
||||
v = trans_stack_local_derived_tydesc(bcx, sz.val, align.val, root,
|
||||
llfirstparam, n_params);
|
||||
}
|
||||
bcx.fcx.derived_tydescs.insert(t, {lltydesc: v, escapes: escapes});
|
||||
ret rslt(cx, v);
|
||||
|
@ -1052,7 +1018,7 @@ fn get_derived_tydesc(cx: @block_ctxt, t: ty::t, escapes: bool,
|
|||
type get_tydesc_result = {kind: tydesc_kind, result: result};
|
||||
|
||||
fn get_tydesc(cx: @block_ctxt, t: ty::t, escapes: bool,
|
||||
storage: ty_param_storage, &static_ti: option::t<@tydesc_info>)
|
||||
&static_ti: option::t<@tydesc_info>)
|
||||
-> get_tydesc_result {
|
||||
|
||||
// Is the supplied type a type param? If so, return the passed-in tydesc.
|
||||
|
@ -1076,22 +1042,21 @@ fn get_tydesc(cx: @block_ctxt, t: ty::t, escapes: bool,
|
|||
// Does it contain a type param? If so, generate a derived tydesc.
|
||||
if ty::type_contains_params(bcx_tcx(cx), t) {
|
||||
ret {kind: tk_derived,
|
||||
result: get_derived_tydesc(cx, t, escapes, storage, static_ti)};
|
||||
result: get_derived_tydesc(cx, t, escapes, static_ti)};
|
||||
}
|
||||
// Otherwise, generate a tydesc if necessary, and return it.
|
||||
let info = get_static_tydesc(cx, t, [], false);
|
||||
static_ti = some::<@tydesc_info>(info);
|
||||
let info = get_static_tydesc(cx, t, []);
|
||||
static_ti = some(info);
|
||||
ret {kind: tk_static, result: rslt(cx, info.tydesc)};
|
||||
}
|
||||
|
||||
fn get_static_tydesc(cx: @block_ctxt, t: ty::t, ty_params: [uint],
|
||||
is_obj_body: bool) -> @tydesc_info {
|
||||
fn get_static_tydesc(cx: @block_ctxt, t: ty::t, ty_params: [uint])
|
||||
-> @tydesc_info {
|
||||
alt bcx_ccx(cx).tydescs.find(t) {
|
||||
some(info) { ret info; }
|
||||
none. {
|
||||
bcx_ccx(cx).stats.n_static_tydescs += 1u;
|
||||
let info = declare_tydesc(cx.fcx.lcx, cx.sp, t, ty_params,
|
||||
is_obj_body);
|
||||
let info = declare_tydesc(cx.fcx.lcx, cx.sp, t, ty_params);
|
||||
bcx_ccx(cx).tydescs.insert(t, info);
|
||||
ret info;
|
||||
}
|
||||
|
@ -1134,9 +1099,8 @@ fn set_glue_inlining(cx: @local_ctxt, f: ValueRef, t: ty::t) {
|
|||
|
||||
|
||||
// Generates the declaration for (but doesn't emit) a type descriptor.
|
||||
fn declare_tydesc(cx: @local_ctxt, sp: span, t: ty::t, ty_params: [uint],
|
||||
is_obj_body: bool) ->
|
||||
@tydesc_info {
|
||||
fn declare_tydesc(cx: @local_ctxt, sp: span, t: ty::t, ty_params: [uint])
|
||||
-> @tydesc_info {
|
||||
log(debug, "+++ declare_tydesc " + ty_to_str(cx.ccx.tcx, t));
|
||||
let ccx = cx.ccx;
|
||||
let llsize;
|
||||
|
@ -1171,8 +1135,7 @@ fn declare_tydesc(cx: @local_ctxt, sp: span, t: ty::t, ty_params: [uint],
|
|||
mutable drop_glue: none::<ValueRef>,
|
||||
mutable free_glue: none::<ValueRef>,
|
||||
mutable cmp_glue: none::<ValueRef>,
|
||||
ty_params: ty_params,
|
||||
is_obj_body: is_obj_body};
|
||||
ty_params: ty_params};
|
||||
log(debug, "--- declare_tydesc " + ty_to_str(cx.ccx.tcx, t));
|
||||
ret info;
|
||||
}
|
||||
|
@ -1275,8 +1238,7 @@ fn emit_tydescs(ccx: @crate_ctxt) {
|
|||
some(v) { ccx.stats.n_real_glues += 1u; v }
|
||||
};
|
||||
|
||||
let shape = shape::shape_of(ccx, key, ti.ty_params,
|
||||
ti.is_obj_body);
|
||||
let shape = shape::shape_of(ccx, key, ti.ty_params);
|
||||
let shape_tables =
|
||||
llvm::LLVMConstPointerCast(ccx.shape_cx.llshapetables,
|
||||
T_ptr(T_i8()));
|
||||
|
@ -1389,16 +1351,14 @@ fn make_free_glue(bcx: @block_ctxt, v: ValueRef, t: ty::t) {
|
|||
ty::ty_vec(_) | ty::ty_str. {
|
||||
tvec::make_free_glue(bcx, PointerCast(bcx, v, type_of_1(bcx, t)), t)
|
||||
}
|
||||
ty::ty_obj(_) | ty::ty_iface(_, _) {
|
||||
// Call through the obj's own fields-drop glue first.
|
||||
ty::ty_iface(_, _) {
|
||||
// Call through the box's own fields-drop glue first.
|
||||
// Then free the body.
|
||||
// (Same code of ifaces, whose layout is similar)
|
||||
let ccx = bcx_ccx(bcx);
|
||||
let llbox_ty = T_opaque_obj_ptr(ccx);
|
||||
let llbox_ty = T_opaque_iface_ptr(ccx);
|
||||
let b = PointerCast(bcx, v, llbox_ty);
|
||||
let body = GEPi(bcx, b, [0, abi::box_rc_field_body]);
|
||||
let tydescptr =
|
||||
GEPi(bcx, body, [0, abi::obj_body_elt_tydesc]);
|
||||
let tydescptr = GEPi(bcx, body, [0, 0]);
|
||||
let tydesc = Load(bcx, tydescptr);
|
||||
let ti = none;
|
||||
call_tydesc_glue_full(bcx, body, tydesc,
|
||||
|
@ -1435,10 +1395,6 @@ fn make_drop_glue(bcx: @block_ctxt, v0: ValueRef, t: ty::t) {
|
|||
ty::ty_uniq(_) | ty::ty_vec(_) | ty::ty_str. | ty::ty_send_type. {
|
||||
free_ty(bcx, Load(bcx, v0), t)
|
||||
}
|
||||
ty::ty_obj(_) {
|
||||
let box_cell = GEPi(bcx, v0, [0, abi::obj_field_box]);
|
||||
decr_refcnt_maybe_free(bcx, Load(bcx, box_cell), t)
|
||||
}
|
||||
ty::ty_res(did, inner, tps) {
|
||||
trans_res_drop(bcx, v0, did, inner, tps)
|
||||
}
|
||||
|
@ -1482,7 +1438,7 @@ fn trans_res_drop(cx: @block_ctxt, rs: ValueRef, did: ast::def_id,
|
|||
let args = [cx.fcx.llretptr, null_env_ptr(cx)];
|
||||
for tp: ty::t in tps {
|
||||
let ti: option::t<@tydesc_info> = none;
|
||||
let td = get_tydesc(cx, tp, false, tps_normal, ti).result;
|
||||
let td = get_tydesc(cx, tp, false, ti).result;
|
||||
args += [td.val];
|
||||
cx = td.bcx;
|
||||
}
|
||||
|
@ -1508,7 +1464,7 @@ fn decr_refcnt_maybe_free(cx: @block_ctxt, box_ptr: ValueRef, t: ty::t)
|
|||
let rc_adj_cx = new_sub_block_ctxt(cx, "rc--");
|
||||
let free_cx = new_sub_block_ctxt(cx, "free");
|
||||
let next_cx = new_sub_block_ctxt(cx, "next");
|
||||
let llbox_ty = T_opaque_obj_ptr(ccx);
|
||||
let llbox_ty = T_opaque_iface_ptr(ccx);
|
||||
let box_ptr = PointerCast(cx, box_ptr, llbox_ty);
|
||||
let null_test = IsNull(cx, box_ptr);
|
||||
CondBr(cx, null_test, next_cx.llbb, rc_adj_cx.llbb);
|
||||
|
@ -1738,10 +1694,6 @@ fn iter_variant(cx: @block_ctxt, a_tup: ValueRef,
|
|||
}
|
||||
ret next_cx;
|
||||
}
|
||||
ty::ty_obj(_) {
|
||||
let box_cell_a = GEPi(cx, av, [0, abi::obj_field_box]);
|
||||
ret iter_boxpp(cx, box_cell_a, f);
|
||||
}
|
||||
_ { bcx_ccx(cx).sess.unimpl("type in iter_structural_ty"); }
|
||||
}
|
||||
ret cx;
|
||||
|
@ -1876,7 +1828,7 @@ fn call_tydesc_glue_full(cx: @block_ctxt, v: ValueRef, tydesc: ValueRef,
|
|||
fn call_tydesc_glue(cx: @block_ctxt, v: ValueRef, t: ty::t, field: int) ->
|
||||
@block_ctxt {
|
||||
let ti: option::t<@tydesc_info> = none::<@tydesc_info>;
|
||||
let {bcx: bcx, val: td} = get_tydesc(cx, t, false, tps_normal, ti).result;
|
||||
let {bcx: bcx, val: td} = get_tydesc(cx, t, false, ti).result;
|
||||
call_tydesc_glue_full(bcx, v, td, field, ti);
|
||||
ret bcx;
|
||||
}
|
||||
|
@ -1898,7 +1850,7 @@ fn call_cmp_glue(cx: @block_ctxt, lhs: ValueRef, rhs: ValueRef, t: ty::t,
|
|||
let llrawlhsptr = BitCast(bcx, lllhs, T_ptr(T_i8()));
|
||||
let llrawrhsptr = BitCast(bcx, llrhs, T_ptr(T_i8()));
|
||||
let ti = none::<@tydesc_info>;
|
||||
r = get_tydesc(bcx, t, false, tps_normal, ti).result;
|
||||
r = get_tydesc(bcx, t, false, ti).result;
|
||||
let lltydesc = r.val;
|
||||
bcx = r.bcx;
|
||||
lazily_emit_tydesc_glue(bcx, abi::tydesc_field_cmp_glue, ti);
|
||||
|
@ -2591,7 +2543,7 @@ fn trans_do_while(cx: @block_ctxt, body: ast::blk, cond: @ast::expr) ->
|
|||
tag callee_env {
|
||||
null_env;
|
||||
is_closure;
|
||||
obj_env(ValueRef);
|
||||
self_env(ValueRef);
|
||||
dict_env(ValueRef, ValueRef);
|
||||
}
|
||||
type lval_maybe_callee = {bcx: @block_ctxt,
|
||||
|
@ -2647,7 +2599,7 @@ fn lval_static_fn(bcx: @block_ctxt, fn_id: ast::def_id, id: ast::node_id)
|
|||
for t in tys {
|
||||
// TODO: Doesn't always escape.
|
||||
let ti = none;
|
||||
let td = get_tydesc(bcx, t, true, tps_normal, ti).result;
|
||||
let td = get_tydesc(bcx, t, true, ti).result;
|
||||
tis += [ti];
|
||||
bcx = td.bcx;
|
||||
tydescs += [td.val];
|
||||
|
@ -2702,10 +2654,6 @@ fn take_local(table: hashmap<ast::node_id, local_val>,
|
|||
ast::def_local(did, _) | ast::def_binding(did) {
|
||||
ret take_local(cx.fcx.lllocals, did.node);
|
||||
}
|
||||
ast::def_obj_field(did, _) {
|
||||
assert (cx.fcx.llobjfields.contains_key(did.node));
|
||||
ret { val: cx.fcx.llobjfields.get(did.node), kind: owned };
|
||||
}
|
||||
ast::def_self(did) {
|
||||
let slf = option::get(cx.fcx.llself);
|
||||
let ptr = PointerCast(cx, slf.v, T_ptr(type_of_or_i8(cx, slf.t)));
|
||||
|
@ -2766,35 +2714,6 @@ fn trans_var(cx: @block_ctxt, sp: span, def: ast::def, id: ast::node_id)
|
|||
}
|
||||
}
|
||||
|
||||
fn trans_object_field(bcx: @block_ctxt, o: @ast::expr, field: ast::ident)
|
||||
-> {bcx: @block_ctxt, mthptr: ValueRef, objptr: ValueRef} {
|
||||
let {bcx, val} = trans_temp_expr(bcx, o);
|
||||
let {bcx, val, ty} = autoderef(bcx, val, ty::expr_ty(bcx_tcx(bcx), o));
|
||||
ret trans_object_field_inner(bcx, val, field, ty);
|
||||
}
|
||||
|
||||
fn trans_object_field_inner(bcx: @block_ctxt, o: ValueRef,
|
||||
field: ast::ident, o_ty: ty::t)
|
||||
-> {bcx: @block_ctxt, mthptr: ValueRef, objptr: ValueRef} {
|
||||
let ccx = bcx_ccx(bcx), tcx = ccx.tcx;
|
||||
let mths = alt ty::struct(tcx, o_ty) { ty::ty_obj(ms) { ms } };
|
||||
|
||||
let ix = option::get(ty::method_idx(field, mths));
|
||||
let vtbl = Load(bcx, GEPi(bcx, o, [0, abi::obj_field_vtbl]));
|
||||
let vtbl_type = T_ptr(T_array(T_ptr(T_nil()), ix + 1u));
|
||||
vtbl = PointerCast(bcx, vtbl, vtbl_type);
|
||||
|
||||
let v = GEPi(bcx, vtbl, [0, ix as int]);
|
||||
let fn_ty: ty::t = ty::mk_fn(tcx, mths[ix].fty);
|
||||
let ret_ty = ty::ty_fn_ret(tcx, fn_ty);
|
||||
// FIXME: constrain ty_obj?
|
||||
let ll_fn_ty = type_of_fn(ccx, bcx.sp, true,
|
||||
ty::ty_fn_args(tcx, fn_ty), ret_ty, []);
|
||||
v = Load(bcx, PointerCast(bcx, v, T_ptr(T_ptr(ll_fn_ty))));
|
||||
ret {bcx: bcx, mthptr: v, objptr: o};
|
||||
}
|
||||
|
||||
|
||||
fn trans_rec_field(bcx: @block_ctxt, base: @ast::expr,
|
||||
field: ast::ident) -> lval_result {
|
||||
let {bcx, val} = trans_temp_expr(bcx, base);
|
||||
|
@ -2859,7 +2778,7 @@ fn trans_index(cx: @block_ctxt, sp: span, base: @ast::expr, idx: @ast::expr,
|
|||
|
||||
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)
|
||||
ty::expr_is_lval(ccx.method_map, e)
|
||||
}
|
||||
|
||||
fn trans_callee(bcx: @block_ctxt, e: @ast::expr) -> lval_maybe_callee {
|
||||
|
@ -2879,11 +2798,6 @@ fn trans_callee(bcx: @block_ctxt, e: @ast::expr) -> lval_maybe_callee {
|
|||
some(typeck::method_iface(off)) {
|
||||
ret trans_impl::trans_iface_callee(bcx, e, base, off);
|
||||
}
|
||||
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};
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -2948,7 +2862,7 @@ fn maybe_add_env(bcx: @block_ctxt, c: lval_maybe_callee)
|
|||
-> (lval_kind, ValueRef) {
|
||||
alt c.env {
|
||||
is_closure. { (c.kind, c.val) }
|
||||
obj_env(_) | dict_env(_, _) {
|
||||
self_env(_) | dict_env(_, _) {
|
||||
fail "Taking the value of a method does not work yet (issue #435)";
|
||||
}
|
||||
null_env. {
|
||||
|
@ -3230,7 +3144,7 @@ fn trans_args(cx: @block_ctxt, llenv: ValueRef,
|
|||
llargs += [PointerCast(cx, llretslot, llretty)];
|
||||
} else { llargs += [llretslot]; }
|
||||
|
||||
// Arg 1: Env (closure-bindings / self-obj)
|
||||
// Arg 1: Env (closure-bindings / self value)
|
||||
llargs += [llenv];
|
||||
|
||||
// Args >2: ty_params ...
|
||||
|
@ -3277,7 +3191,7 @@ fn trans_call(in_cx: @block_ctxt, f: @ast::expr,
|
|||
null_env. {
|
||||
llenv = llvm::LLVMGetUndef(T_opaque_cbox_ptr(bcx_ccx(cx)));
|
||||
}
|
||||
obj_env(e) { llenv = e; }
|
||||
self_env(e) { llenv = e; }
|
||||
dict_env(dict, e) { llenv = e; dict_param = some(dict); }
|
||||
is_closure. {
|
||||
// It's a closure. Have to fetch the elements
|
||||
|
@ -3639,9 +3553,6 @@ fn trans_expr(bcx: @block_ctxt, e: @ast::expr, dest: dest) -> @block_ctxt {
|
|||
else { ret lval_to_dps(bcx, a, dest); }
|
||||
}
|
||||
ast::expr_cast(val, _) { ret trans_cast(bcx, val, e.id, dest); }
|
||||
ast::expr_anon_obj(anon_obj) {
|
||||
ret trans_anon_obj(bcx, e.span, anon_obj, e.id, dest);
|
||||
}
|
||||
ast::expr_call(f, args, _) {
|
||||
ret trans_call(bcx, f, args, e.id, dest);
|
||||
}
|
||||
|
@ -3855,7 +3766,7 @@ fn trans_log(lvl: @ast::expr, cx: @block_ctxt, e: @ast::expr) -> @block_ctxt {
|
|||
let log_bcx = sub.bcx;
|
||||
|
||||
let ti = none::<@tydesc_info>;
|
||||
let r = get_tydesc(log_bcx, e_ty, false, tps_normal, ti).result;
|
||||
let r = get_tydesc(log_bcx, e_ty, false, ti).result;
|
||||
log_bcx = r.bcx;
|
||||
let lltydesc = r.val;
|
||||
|
||||
|
@ -4350,8 +4261,6 @@ fn new_local_ctxt(ccx: @crate_ctxt) -> @local_ctxt {
|
|||
let pth: [str] = [];
|
||||
ret @{path: pth,
|
||||
module_path: [ccx.link_meta.name],
|
||||
obj_typarams: [],
|
||||
obj_fields: [],
|
||||
ccx: ccx};
|
||||
}
|
||||
|
||||
|
@ -4404,7 +4313,6 @@ fn new_fn_ctxt_w_id(cx: @local_ctxt, sp: span, llfndecl: ValueRef,
|
|||
mutable llobstacktoken: none::<ValueRef>,
|
||||
mutable llself: none::<val_self_pair>,
|
||||
llargs: new_int_hash::<local_val>(),
|
||||
llobjfields: new_int_hash::<ValueRef>(),
|
||||
lllocals: new_int_hash::<local_val>(),
|
||||
llupvars: new_int_hash::<ValueRef>(),
|
||||
mutable lltyparams: [],
|
||||
|
@ -4440,33 +4348,28 @@ fn create_llargs_for_fn_args(cx: @fn_ctxt, ty_self: self_arg,
|
|||
// way.
|
||||
let arg_n = 2u;
|
||||
alt ty_self {
|
||||
obj_self(tt) | impl_self(tt) {
|
||||
impl_self(tt) {
|
||||
cx.llself = some({v: cx.llenv, t: tt});
|
||||
}
|
||||
no_self. {}
|
||||
}
|
||||
alt ty_self {
|
||||
obj_self(_) {}
|
||||
_ {
|
||||
for tp in ty_params {
|
||||
let lltydesc = llvm::LLVMGetParam(cx.llfn, arg_n), dicts = none;
|
||||
arg_n += 1u;
|
||||
for bound in *fcx_tcx(cx).ty_param_bounds.get(tp.id) {
|
||||
alt bound {
|
||||
ty::bound_iface(_) {
|
||||
let dict = llvm::LLVMGetParam(cx.llfn, arg_n);
|
||||
arg_n += 1u;
|
||||
dicts = some(alt dicts {
|
||||
none. { [dict] }
|
||||
some(ds) { ds + [dict] }
|
||||
});
|
||||
}
|
||||
_ {}
|
||||
}
|
||||
for tp in ty_params {
|
||||
let lltydesc = llvm::LLVMGetParam(cx.llfn, arg_n), dicts = none;
|
||||
arg_n += 1u;
|
||||
for bound in *fcx_tcx(cx).ty_param_bounds.get(tp.id) {
|
||||
alt bound {
|
||||
ty::bound_iface(_) {
|
||||
let dict = llvm::LLVMGetParam(cx.llfn, arg_n);
|
||||
arg_n += 1u;
|
||||
dicts = some(alt dicts {
|
||||
none. { [dict] }
|
||||
some(ds) { ds + [dict] }
|
||||
});
|
||||
}
|
||||
_ {}
|
||||
}
|
||||
cx.lltyparams += [{desc: lltydesc, dicts: dicts}];
|
||||
}
|
||||
}
|
||||
cx.lltyparams += [{desc: lltydesc, dicts: dicts}];
|
||||
}
|
||||
|
||||
// Populate the llargs field of the function context with the ValueRefs
|
||||
|
@ -4517,54 +4420,6 @@ fn arg_tys_of_fn(ccx: @crate_ctxt, id: ast::node_id) -> [ty::arg] {
|
|||
}
|
||||
}
|
||||
|
||||
fn populate_fn_ctxt_from_llself(fcx: @fn_ctxt, llself: val_self_pair) {
|
||||
let ccx = fcx_ccx(fcx);
|
||||
let bcx = llstaticallocas_block_ctxt(fcx);
|
||||
let field_tys: [ty::t] = [];
|
||||
for f: ast::obj_field in bcx.fcx.lcx.obj_fields {
|
||||
field_tys += [node_id_type(ccx, f.id)];
|
||||
}
|
||||
// Synthesize a tuple type for the fields so that GEP_tup_like() can work
|
||||
// its magic.
|
||||
|
||||
let fields_tup_ty = ty::mk_tup(fcx.lcx.ccx.tcx, field_tys);
|
||||
let n_typarams = vec::len::<ast::ty_param>(bcx.fcx.lcx.obj_typarams);
|
||||
let llobj_box_ty: TypeRef = T_obj_ptr(ccx, n_typarams);
|
||||
let box_cell = GEPi(bcx, llself.v, [0, abi::obj_field_box]);
|
||||
let box_ptr = Load(bcx, box_cell);
|
||||
box_ptr = PointerCast(bcx, box_ptr, llobj_box_ty);
|
||||
let obj_typarams =
|
||||
GEPi(bcx, box_ptr, [0, abi::box_rc_field_body,
|
||||
abi::obj_body_elt_typarams]);
|
||||
|
||||
// The object fields immediately follow the type parameters, so we skip
|
||||
// over them to get the pointer.
|
||||
let obj_fields =
|
||||
PointerCast(bcx, GEPi(bcx, obj_typarams, [1]),
|
||||
T_ptr(type_of_or_i8(bcx, fields_tup_ty)));
|
||||
|
||||
let i: int = 0;
|
||||
for p: ast::ty_param in fcx.lcx.obj_typarams {
|
||||
let lltyparam: ValueRef =
|
||||
GEPi(bcx, obj_typarams, [0, i]);
|
||||
lltyparam = Load(bcx, lltyparam);
|
||||
fcx.lltyparams += [{desc: lltyparam, dicts: none}];
|
||||
i += 1;
|
||||
}
|
||||
i = 0;
|
||||
for f: ast::obj_field in fcx.lcx.obj_fields {
|
||||
// FIXME: silly check
|
||||
check type_is_tup_like(bcx, fields_tup_ty);
|
||||
let rslt = GEP_tup_like(bcx, fields_tup_ty, obj_fields, [0, i]);
|
||||
bcx = llstaticallocas_block_ctxt(fcx);
|
||||
let llfield = rslt.val;
|
||||
fcx.llobjfields.insert(f.id, llfield);
|
||||
i += 1;
|
||||
}
|
||||
fcx.llstaticallocas = bcx.llbb;
|
||||
}
|
||||
|
||||
|
||||
// Ties up the llstaticallocas -> llloadenv -> llderivedtydescs ->
|
||||
// lldynamicallocas -> lltop edges, and builds the return block.
|
||||
fn finish_fn(fcx: @fn_ctxt, lltop: BasicBlockRef) {
|
||||
|
@ -4578,7 +4433,7 @@ fn finish_fn(fcx: @fn_ctxt, lltop: BasicBlockRef) {
|
|||
RetVoid(ret_cx);
|
||||
}
|
||||
|
||||
tag self_arg { obj_self(ty::t); impl_self(ty::t); no_self; }
|
||||
tag self_arg { 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
|
||||
|
@ -4592,12 +4447,6 @@ fn trans_closure(cx: @local_ctxt, sp: span, decl: ast::fn_decl,
|
|||
// Set up arguments to the function.
|
||||
let fcx = new_fn_ctxt_w_id(cx, sp, llfndecl, id, decl.cf);
|
||||
create_llargs_for_fn_args(fcx, ty_self, decl.inputs, ty_params);
|
||||
alt ty_self {
|
||||
obj_self(_) {
|
||||
populate_fn_ctxt_from_llself(fcx, option::get(fcx.llself));
|
||||
}
|
||||
_ { }
|
||||
}
|
||||
|
||||
// Create the first basic block in the function and keep a handle on it to
|
||||
// pass to finish_fn later.
|
||||
|
@ -4612,7 +4461,7 @@ fn trans_closure(cx: @local_ctxt, sp: span, decl: ast::fn_decl,
|
|||
|
||||
// This call to trans_block is the place where we bridge between
|
||||
// translation calls that don't have a return value (trans_crate,
|
||||
// trans_mod, trans_item, trans_obj, et cetera) and those that do
|
||||
// trans_mod, trans_item, et cetera) and those that do
|
||||
// (trans_block, trans_expr, et cetera).
|
||||
if ty::type_is_bot(cx.ccx.tcx, block_ty) ||
|
||||
ty::type_is_nil(cx.ccx.tcx, block_ty) ||
|
||||
|
@ -5063,12 +4912,6 @@ fn trans_item(cx: @local_ctxt, item: ast::item) {
|
|||
}
|
||||
}
|
||||
}
|
||||
ast::item_obj(ob, tps, ctor_id) {
|
||||
let sub_cx =
|
||||
@{obj_typarams: tps, obj_fields: ob.fields
|
||||
with *extend_path(cx, item.ident)};
|
||||
trans_obj(sub_cx, item.span, ob, ctor_id, tps);
|
||||
}
|
||||
ast::item_impl(tps, _, _, ms) {
|
||||
trans_impl::trans_impl(cx, item.ident, ms, item.id, tps);
|
||||
}
|
||||
|
@ -5180,7 +5023,7 @@ fn create_main(ccx: @crate_ctxt, sp: span, main_llfn: ValueRef,
|
|||
ty: ty::mk_vec(ccx.tcx, {ty: unit_ty, mut: ast::imm})};
|
||||
// FIXME: mk_nil should have a postcondition
|
||||
let nt = ty::mk_nil(ccx.tcx);
|
||||
let llfty = type_of_fn(ccx, sp, false, [vecarg_ty], nt, []);
|
||||
let llfty = type_of_fn(ccx, sp, [vecarg_ty], nt, []);
|
||||
let llfdecl = decl_fn(ccx.llmod, "_rust_main",
|
||||
lib::llvm::LLVMCCallConv, llfty);
|
||||
|
||||
|
@ -5278,7 +5121,7 @@ fn native_fn_wrapper_type(cx: @crate_ctxt, sp: span,
|
|||
x: ty::t) -> TypeRef {
|
||||
alt ty::struct(cx.tcx, x) {
|
||||
ty::ty_native_fn(args, out) {
|
||||
ret type_of_fn(cx, sp, false, args, out, param_bounds);
|
||||
ret type_of_fn(cx, sp, args, out, param_bounds);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -5378,9 +5221,6 @@ fn collect_item(ccx: @crate_ctxt, abi: @mutable option::t<ast::native_abi>,
|
|||
ast::item_fn(_, tps, _) {
|
||||
register_fn(ccx, i.span, new_pt, "fn", tps, i.id);
|
||||
}
|
||||
ast::item_obj(ob, tps, ctor_id) {
|
||||
register_fn(ccx, i.span, new_pt, "obj_ctor", tps, ctor_id);
|
||||
}
|
||||
ast::item_impl(tps, _, _, methods) {
|
||||
let name = i.ident + int::str(i.id);
|
||||
for m in methods {
|
||||
|
@ -5716,7 +5556,6 @@ fn trans_crate(sess: session::session, crate: @ast::crate, tcx: ty::ctxt,
|
|||
upcalls:
|
||||
upcall::declare_upcalls(targ_cfg, tn, tydesc_type,
|
||||
llmod),
|
||||
rust_object_type: T_rust_object(),
|
||||
tydesc_type: tydesc_type,
|
||||
int_type: int_type,
|
||||
float_type: float_type,
|
||||
|
|
|
@ -222,7 +222,7 @@ fn allocate_cbox(bcx: @block_ctxt,
|
|||
let ti = none;
|
||||
let tydesc_ty = if xchgheap { cbox_ty } else { cbox_norc_ty };
|
||||
let {bcx, val:lltydesc} =
|
||||
get_tydesc(bcx, tydesc_ty, true, tps_normal, ti).result;
|
||||
get_tydesc(bcx, tydesc_ty, true, ti).result;
|
||||
let malloc = {
|
||||
if xchgheap { ccx.upcalls.shared_malloc}
|
||||
else { ccx.upcalls.malloc }
|
||||
|
@ -315,7 +315,7 @@ fn maybe_clone_tydesc(bcx: @block_ctxt,
|
|||
let ti = none;
|
||||
|
||||
let {result:closure_td, _} =
|
||||
trans::get_tydesc(bcx, cbox_ty, true, tps_normal, ti);
|
||||
trans::get_tydesc(bcx, cbox_ty, true, ti);
|
||||
trans::lazily_emit_tydesc_glue(bcx, abi::tydesc_field_take_glue, ti);
|
||||
trans::lazily_emit_tydesc_glue(bcx, abi::tydesc_field_drop_glue, ti);
|
||||
trans::lazily_emit_tydesc_glue(bcx, abi::tydesc_field_free_glue, ti);
|
||||
|
|
|
@ -46,8 +46,7 @@ fn new_namegen() -> namegen {
|
|||
mutable drop_glue: option::t<ValueRef>,
|
||||
mutable free_glue: option::t<ValueRef>,
|
||||
mutable cmp_glue: option::t<ValueRef>,
|
||||
ty_params: [uint],
|
||||
is_obj_body: bool};
|
||||
ty_params: [uint]};
|
||||
|
||||
/*
|
||||
* A note on nomenclature of linking: "upcall", "extern" and "native".
|
||||
|
@ -112,7 +111,6 @@ fn new_namegen() -> namegen {
|
|||
dict_map: typeck::dict_map,
|
||||
stats: stats,
|
||||
upcalls: @upcall::upcalls,
|
||||
rust_object_type: TypeRef,
|
||||
tydesc_type: TypeRef,
|
||||
int_type: TypeRef,
|
||||
float_type: TypeRef,
|
||||
|
@ -127,8 +125,6 @@ fn new_namegen() -> namegen {
|
|||
type local_ctxt =
|
||||
{path: [str],
|
||||
module_path: [str],
|
||||
obj_typarams: [ast::ty_param],
|
||||
obj_fields: [ast::obj_field],
|
||||
ccx: @crate_ctxt};
|
||||
|
||||
// Types used for llself.
|
||||
|
@ -156,8 +152,7 @@ fn new_namegen() -> namegen {
|
|||
// Points to the current task.
|
||||
|
||||
// Points to the current environment (bindings of variables to
|
||||
// values), if this is a regular function; points to the current
|
||||
// object, if this is a method.
|
||||
// values), if this is a regular function
|
||||
|
||||
// Points to where the return value of this function should end
|
||||
// up.
|
||||
|
@ -185,7 +180,7 @@ fn new_namegen() -> namegen {
|
|||
|
||||
// The token used to clear the dynamic allocas at the end of this frame.
|
||||
|
||||
// The 'self' object currently in use in this function, if there
|
||||
// The 'self' value currently in use in this function, if there
|
||||
// is one.
|
||||
|
||||
// If this function is actually a iter, a block containing the
|
||||
|
@ -196,9 +191,6 @@ fn new_namegen() -> namegen {
|
|||
|
||||
// Maps arguments to allocas created for them in llallocas.
|
||||
|
||||
// Maps fields in objects to pointers into the interior of
|
||||
// llself's body.
|
||||
|
||||
// Maps the def_ids for local variables to the allocas created for
|
||||
// them in llallocas.
|
||||
|
||||
|
@ -240,7 +232,6 @@ fn new_namegen() -> namegen {
|
|||
mutable llobstacktoken: option::t<ValueRef>,
|
||||
mutable llself: option::t<val_self_pair>,
|
||||
llargs: hashmap<ast::node_id, local_val>,
|
||||
llobjfields: hashmap<ast::node_id, ValueRef>,
|
||||
lllocals: hashmap<ast::node_id, local_val>,
|
||||
llupvars: hashmap<ast::node_id, ValueRef>,
|
||||
mutable lltyparams: [fn_ty_param],
|
||||
|
@ -331,7 +322,7 @@ fn get_res_dtor(ccx: @crate_ctxt, sp: span, did: ast::def_id, inner_t: ty::t)
|
|||
let nil_res = ty::mk_nil(ccx.tcx);
|
||||
// FIXME: Silly check -- mk_nil should have a postcondition
|
||||
check non_ty_var(ccx, nil_res);
|
||||
let f_t = type_of_fn(ccx, sp, false,
|
||||
let f_t = type_of_fn(ccx, sp,
|
||||
[{mode: ast::by_ref, ty: inner_t}],
|
||||
nil_res, *param_bounds);
|
||||
ret trans::get_extern_const(ccx.externs, ccx.llmod,
|
||||
|
@ -566,17 +557,6 @@ fn set_struct_body(t: TypeRef, elts: [TypeRef]) unsafe {
|
|||
|
||||
fn T_empty_struct() -> TypeRef { ret T_struct([]); }
|
||||
|
||||
// NB: This will return something different every time it's called. If
|
||||
// you need a generic object type that matches the type of your
|
||||
// existing objects, use ccx.rust_object_type. Calling
|
||||
// T_rust_object() again will return a different one.
|
||||
fn T_rust_object() -> TypeRef {
|
||||
let t = T_named_struct("rust_object");
|
||||
let e = T_ptr(T_empty_struct());
|
||||
set_struct_body(t, [e, e]);
|
||||
ret t;
|
||||
}
|
||||
|
||||
// A dict is, in reality, a vtable pointer followed by zero or more pointers
|
||||
// to tydescs and other dicts that it closes over. But the types and number of
|
||||
// those are rarely known to the code that needs to manipulate them, so they
|
||||
|
@ -745,19 +725,6 @@ fn T_captured_tydescs(cx: @crate_ctxt, n: uint) -> TypeRef {
|
|||
ret T_struct(vec::init_elt::<TypeRef>(T_ptr(cx.tydesc_type), n));
|
||||
}
|
||||
|
||||
fn T_obj_ptr(cx: @crate_ctxt, n_captured_tydescs: uint) -> TypeRef {
|
||||
// This function is not publicly exposed because it returns an incomplete
|
||||
// type. The dynamically-sized fields follow the captured tydescs.
|
||||
|
||||
fn T_obj(cx: @crate_ctxt, n_captured_tydescs: uint) -> TypeRef {
|
||||
ret T_struct([T_ptr(cx.tydesc_type),
|
||||
T_captured_tydescs(cx, n_captured_tydescs)]);
|
||||
}
|
||||
ret T_ptr(T_box(cx, T_obj(cx, n_captured_tydescs)));
|
||||
}
|
||||
|
||||
fn T_opaque_obj_ptr(cx: @crate_ctxt) -> TypeRef { ret T_obj_ptr(cx, 0u); }
|
||||
|
||||
fn T_opaque_iface_ptr(cx: @crate_ctxt) -> TypeRef {
|
||||
let tdptr = T_ptr(cx.tydesc_type);
|
||||
T_ptr(T_box(cx, T_struct([tdptr, tdptr, T_i8()])))
|
||||
|
|
|
@ -65,7 +65,7 @@ fn trans_self_arg(bcx: @block_ctxt, base: @ast::expr) -> result {
|
|||
fn trans_static_callee(bcx: @block_ctxt, e: @ast::expr, base: @ast::expr,
|
||||
did: ast::def_id) -> lval_maybe_callee {
|
||||
let {bcx, val} = trans_self_arg(bcx, base);
|
||||
{env: obj_env(val) with lval_static_fn(bcx, did, e.id)}
|
||||
{env: self_env(val) with lval_static_fn(bcx, did, e.id)}
|
||||
}
|
||||
|
||||
fn wrapper_fn_ty(ccx: @crate_ctxt, dict_ty: TypeRef, m: ty::method)
|
||||
|
@ -92,7 +92,7 @@ fn trans_vtable_callee(bcx: @block_ctxt, self: ValueRef, dict: ValueRef,
|
|||
let tptys = ty::node_id_to_type_params(tcx, fld_expr.id);
|
||||
for t in vec::tail_n(tptys, vec::len(tptys) - vec::len(*method.tps)) {
|
||||
let ti = none;
|
||||
let td = get_tydesc(bcx, t, true, tps_normal, ti).result;
|
||||
let td = get_tydesc(bcx, t, true, ti).result;
|
||||
tis += [ti];
|
||||
tydescs += [td.val];
|
||||
bcx = td.bcx;
|
||||
|
@ -158,8 +158,7 @@ fn trans_vtable(ccx: @crate_ctxt, id: ast::node_id, name: str,
|
|||
fn trans_wrapper(ccx: @crate_ctxt, pt: [ast::ident], llfty: TypeRef,
|
||||
fill: block(ValueRef, @block_ctxt) -> @block_ctxt)
|
||||
-> ValueRef {
|
||||
let lcx = @{path: pt, module_path: [],
|
||||
obj_typarams: [], obj_fields: [], ccx: ccx};
|
||||
let lcx = @{path: pt, module_path: [], ccx: ccx};
|
||||
let name = link::mangle_internal_name_by_path(ccx, pt);
|
||||
let llfn = decl_internal_cdecl_fn(ccx.llmod, name, llfty);
|
||||
let fcx = new_fn_ctxt(lcx, ast_util::dummy_sp(), llfn);
|
||||
|
@ -370,7 +369,7 @@ fn get_vtable(ccx: @crate_ctxt, did: ast::def_id) -> ValueRef {
|
|||
let ptrs = [get_vtable(ccx, impl_did)];
|
||||
let origin = 0u, ti = none, bcx = bcx;
|
||||
vec::iter2(*impl_params, tys) {|param, ty|
|
||||
let rslt = get_tydesc(bcx, ty, true, tps_normal, ti).result;
|
||||
let rslt = get_tydesc(bcx, ty, true, ti).result;
|
||||
ptrs += [rslt.val];
|
||||
bcx = rslt.bcx;
|
||||
for bound in *param {
|
||||
|
@ -401,8 +400,7 @@ fn trans_cast(bcx: @block_ctxt, val: @ast::expr, id: ast::node_id, dest: dest)
|
|||
let body_ty = ty::mk_tup(tcx, [ty::mk_type(tcx), ty::mk_type(tcx),
|
||||
val_ty]);
|
||||
let ti = none;
|
||||
let {bcx, val: tydesc} = get_tydesc(bcx, body_ty, true,
|
||||
tps_normal, ti).result;
|
||||
let {bcx, val: tydesc} = get_tydesc(bcx, body_ty, true, ti).result;
|
||||
lazily_emit_all_tydesc_glue(bcx, ti);
|
||||
let {bcx, box, body: box_body} = trans_malloc_boxed(bcx, body_ty);
|
||||
Store(bcx, tydesc, GEPi(bcx, box_body, [0, 0]));
|
||||
|
|
|
@ -1,951 +0,0 @@
|
|||
// Translation of object-related things to LLVM IR.
|
||||
|
||||
import core::{str, option, vec};
|
||||
import option::{none, some};
|
||||
|
||||
import lib::llvm::{llvm, True};
|
||||
import lib::llvm::llvm::{TypeRef, ValueRef};
|
||||
|
||||
import back::abi;
|
||||
import back::link::{mangle_internal_name_by_path,
|
||||
mangle_internal_name_by_path_and_seq};
|
||||
import syntax::{ast, ast_util};
|
||||
import syntax::codemap::span;
|
||||
|
||||
import trans_common::*;
|
||||
import trans::*;
|
||||
import trans_build::*;
|
||||
|
||||
import driver::session::session;
|
||||
|
||||
export trans_anon_obj;
|
||||
export trans_obj;
|
||||
|
||||
// trans_obj: create an LLVM function that is the object constructor for the
|
||||
// object being translated.
|
||||
fn trans_obj(cx: @local_ctxt, sp: span, ob: ast::_obj, ctor_id: ast::node_id,
|
||||
ty_params: [ast::ty_param]) {
|
||||
|
||||
// To make a function, we have to create a function context and, inside
|
||||
// that, a number of block contexts for which code is generated.
|
||||
let ccx = cx.ccx;
|
||||
let llctor_decl;
|
||||
alt ccx.item_ids.find(ctor_id) {
|
||||
some(x) { llctor_decl = x; }
|
||||
_ { cx.ccx.sess.span_fatal(sp, "unbound llctor_decl in trans_obj"); }
|
||||
}
|
||||
|
||||
// Much like trans_fn, we must create an LLVM function, but since we're
|
||||
// starting with an ast::_obj rather than an ast::_fn, we have some setup
|
||||
// work to do.
|
||||
|
||||
// The fields of our object will become the arguments to the function
|
||||
// we're creating.
|
||||
let fn_args: [ast::arg] = [];
|
||||
for f: ast::obj_field in ob.fields {
|
||||
fn_args += [{mode: ast::by_copy, ty: f.ty, ident: f.ident,
|
||||
id: f.id}];
|
||||
}
|
||||
let fcx = new_fn_ctxt(cx, sp, llctor_decl);
|
||||
|
||||
// Create the first block context in the function and keep a handle on it
|
||||
// to pass to finish_fn later.
|
||||
let bcx = new_top_block_ctxt(fcx);
|
||||
let lltop = bcx.llbb;
|
||||
|
||||
// Both regular arguments and type parameters are handled here.
|
||||
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);
|
||||
|
||||
// Pick up the type of this object by looking at our own output type, that
|
||||
// is, the output type of the object constructor we're building.
|
||||
let self_ty = ty::ret_ty_of_fn(ccx.tcx, ctor_id);
|
||||
|
||||
// Set up the two-word pair that we're going to return from the object
|
||||
// constructor we're building. The two elements of this pair will be a
|
||||
// vtable pointer and a body pointer. (llretptr already points to the
|
||||
// place where this two-word pair should go; it was pre-allocated by the
|
||||
// caller of the function.)
|
||||
let pair = bcx.fcx.llretptr;
|
||||
|
||||
// Grab onto the first and second elements of the pair.
|
||||
// abi::obj_field_vtbl and abi::obj_field_box simply specify words 0 and 1
|
||||
// of 'pair'.
|
||||
let pair_vtbl = GEPi(bcx, pair, [0, abi::obj_field_vtbl]);
|
||||
let pair_box = GEPi(bcx, pair, [0, abi::obj_field_box]);
|
||||
|
||||
// Make a vtable for this object: a static array of pointers to functions.
|
||||
// It will be located in the read-only memory of the executable we're
|
||||
// creating and will contain ValueRefs for all of this object's methods.
|
||||
// create_vtbl returns a pointer to the vtable, which we store.
|
||||
let vtbl = create_vtbl(cx, sp, self_ty, ob, ty_params, none, []);
|
||||
vtbl = PointerCast(bcx, vtbl, T_ptr(T_empty_struct()));
|
||||
|
||||
Store(bcx, vtbl, pair_vtbl);
|
||||
|
||||
// Next we have to take care of the other half of the pair we're
|
||||
// returning: a boxed (reference-counted) tuple containing a tydesc,
|
||||
// typarams, and fields.
|
||||
let llbox_ty: TypeRef = T_ptr(T_empty_struct());
|
||||
|
||||
if vec::len(ty_params) == 0u &&
|
||||
vec::len(arg_tys) == 0u {
|
||||
// If the object we're translating has no fields or type parameters,
|
||||
// there's not much to do.
|
||||
|
||||
// Store null into pair, if no args or typarams.
|
||||
Store(bcx, C_null(llbox_ty), pair_box);
|
||||
} else {
|
||||
let obj_fields: [ty::t] = [];
|
||||
for a: ty::arg in arg_tys { obj_fields += [a.ty]; }
|
||||
|
||||
let tps: [ty::t] = [];
|
||||
let tydesc_ty = ty::mk_type(ccx.tcx);
|
||||
for tp: ast::ty_param in ty_params { tps += [tydesc_ty]; }
|
||||
|
||||
// Synthesize an object body type and hand it off to
|
||||
// trans_malloc_boxed, which allocates a box, including space for a
|
||||
// refcount.
|
||||
let body_ty: ty::t =
|
||||
create_object_body_type(ccx.tcx, obj_fields, tps, none);
|
||||
|
||||
// We have to get this type descriptor now so that
|
||||
// trans_malloc_boxed() doesn't generate a type descriptor with the
|
||||
// wrong storage type and override the type descriptor we're about to
|
||||
// generate.
|
||||
let ti = none;
|
||||
let storage = tps_obj(vec::len(ty_params));
|
||||
let body_td = get_tydesc(bcx, body_ty, true, storage, ti).result;
|
||||
bcx = body_td.bcx;
|
||||
lazily_emit_tydesc_glue(bcx, abi::tydesc_field_drop_glue, ti);
|
||||
lazily_emit_tydesc_glue(bcx, abi::tydesc_field_free_glue, ti);
|
||||
|
||||
let box = trans_malloc_boxed(bcx, body_ty);
|
||||
bcx = box.bcx;
|
||||
let body = box.body;
|
||||
|
||||
// Put together a tydesc for the body, so that the object can later be
|
||||
// freed by calling through its tydesc.
|
||||
|
||||
// Every object (not just those with type parameters) needs to have a
|
||||
// tydesc to describe its body, since all objects have unknown type to
|
||||
// the user of the object. So the tydesc is needed to keep track of
|
||||
// the types of the object's fields, so that the fields can be freed
|
||||
// later.
|
||||
|
||||
// postcondition on create_object_body_type?
|
||||
check type_is_tup_like(bcx, body_ty);
|
||||
let body_tydesc =
|
||||
GEP_tup_like(bcx, body_ty, body, [0, abi::obj_body_elt_tydesc]);
|
||||
bcx = body_tydesc.bcx;
|
||||
|
||||
check type_is_tup_like(bcx, body_ty);
|
||||
let r =
|
||||
GEP_tup_like(bcx, body_ty, body, [0, abi::obj_body_elt_typarams]);
|
||||
bcx = r.bcx;
|
||||
let body_typarams = r.val;
|
||||
|
||||
Store(bcx, body_td.val, body_tydesc.val);
|
||||
|
||||
// Copy the object's type parameters and fields into the space we
|
||||
// allocated for the object body. (This is something like saving the
|
||||
// lexical environment of a function in its closure: the "captured
|
||||
// typarams" are any type parameters that are passed to the object
|
||||
// constructor and are then available to the object's methods.
|
||||
// Likewise for the object's fields.)
|
||||
|
||||
// Copy typarams into captured typarams.
|
||||
// TODO: can we just get typarams_ty out of body_ty instead?
|
||||
let typarams_ty: ty::t = ty::mk_tup(ccx.tcx, tps);
|
||||
let i: int = 0;
|
||||
for tp: ast::ty_param in ty_params {
|
||||
let typaram = bcx.fcx.lltyparams[i].desc;
|
||||
// Silly check
|
||||
check type_is_tup_like(bcx, typarams_ty);
|
||||
let capture =
|
||||
GEP_tup_like(bcx, typarams_ty, body_typarams, [0, i]);
|
||||
bcx = capture.bcx;
|
||||
bcx = copy_val(bcx, INIT, capture.val, typaram, tydesc_ty);
|
||||
i += 1;
|
||||
}
|
||||
|
||||
// Copy args into body fields.
|
||||
// how to get rid of this check?
|
||||
check type_is_tup_like(bcx, body_ty);
|
||||
let body_fields =
|
||||
GEP_tup_like(bcx, body_ty, body, [0, abi::obj_body_elt_fields]);
|
||||
bcx = body_fields.bcx;
|
||||
// TODO: can we just get fields_ty out of body_ty instead?
|
||||
let fields_ty = ty::mk_tup(ccx.tcx, obj_fields);
|
||||
i = 0;
|
||||
for f: ast::obj_field in ob.fields {
|
||||
alt bcx.fcx.llargs.find(f.id) {
|
||||
some(local_mem(arg)) {
|
||||
// Silly check
|
||||
check type_is_tup_like(bcx, fields_ty);
|
||||
let field =
|
||||
GEP_tup_like(bcx, fields_ty, body_fields.val, [0, i]);
|
||||
bcx = memmove_ty(field.bcx, field.val, arg, arg_tys[i].ty);
|
||||
i += 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Store box ptr in outer pair.
|
||||
let p = PointerCast(bcx, box.box, llbox_ty);
|
||||
Store(bcx, p, pair_box);
|
||||
}
|
||||
build_return(bcx);
|
||||
|
||||
// Insert the mandatory first few basic blocks before lltop.
|
||||
finish_fn(fcx, lltop);
|
||||
}
|
||||
|
||||
// trans_anon_obj: create and return a pointer to an object. This code
|
||||
// differs from trans_obj in that, rather than creating an object constructor
|
||||
// function and putting it in the generated code as an object item, we are
|
||||
// instead "inlining" the construction of the object and returning the object
|
||||
// itself.
|
||||
fn trans_anon_obj(bcx: @block_ctxt, sp: span, anon_obj: ast::anon_obj,
|
||||
id: ast::node_id, dest: trans::dest) -> @block_ctxt {
|
||||
let bcx = bcx;
|
||||
if dest == trans::ignore {
|
||||
alt anon_obj.inner_obj {
|
||||
some(e) { ret trans::trans_expr(bcx, e, trans::ignore); }
|
||||
none. { ret bcx; }
|
||||
}
|
||||
}
|
||||
|
||||
let ccx = bcx_ccx(bcx);
|
||||
|
||||
// Fields. FIXME (part of issue #538): Where do we fill in the field
|
||||
// *values* from the outer object?
|
||||
let additional_fields: [ast::anon_obj_field] = [];
|
||||
let additional_field_vals: [result] = [];
|
||||
let additional_field_tys: [ty::t] = [];
|
||||
alt anon_obj.fields {
|
||||
none. { }
|
||||
some(fields) {
|
||||
additional_fields = fields;
|
||||
for f: ast::anon_obj_field in fields {
|
||||
additional_field_tys += [node_id_type(ccx, f.id)];
|
||||
additional_field_vals += [trans_temp_expr(bcx, f.expr)];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Get the type of the eventual entire anonymous object, possibly with
|
||||
// extensions. NB: This type includes both inner and outer methods.
|
||||
let outer_obj_ty = ty::node_id_to_type(ccx.tcx, id);
|
||||
|
||||
// Create a vtable for the anonymous object.
|
||||
|
||||
// create_vtbl() wants an ast::_obj and all we have is an ast::anon_obj,
|
||||
// so we need to roll our own. NB: wrapper_obj includes only outer
|
||||
// methods, not inner ones.
|
||||
let wrapper_obj: ast::_obj =
|
||||
{fields:
|
||||
vec::map(additional_fields,
|
||||
ast_util::obj_field_from_anon_obj_field),
|
||||
methods: anon_obj.methods};
|
||||
|
||||
let inner_obj_ty: ty::t;
|
||||
let vtbl;
|
||||
alt anon_obj.inner_obj {
|
||||
none. {
|
||||
// We need a dummy inner_obj_ty for setting up the object body later.
|
||||
inner_obj_ty = ty::mk_type(ccx.tcx);
|
||||
|
||||
// If there's no inner_obj -- that is, if we're creating a new object
|
||||
// from nothing rather than extending an existing object -- then we
|
||||
// just pass the outer object to create_vtbl(). Our vtable won't need
|
||||
// to have any forwarding slots.
|
||||
vtbl =
|
||||
create_vtbl(bcx.fcx.lcx, sp, outer_obj_ty, wrapper_obj, [], none,
|
||||
additional_field_tys);
|
||||
}
|
||||
some(e) {
|
||||
// TODO: What makes more sense to get the type of an expr -- calling
|
||||
// ty::expr_ty(ccx.tcx, e) on it or calling
|
||||
// ty::node_id_to_type(ccx.tcx, id) on its id?
|
||||
inner_obj_ty = ty::expr_ty(ccx.tcx, e);
|
||||
//inner_obj_ty = ty::node_id_to_type(ccx.tcx, e.id);
|
||||
|
||||
// If there's a inner_obj, we pass its type along to create_vtbl().
|
||||
// Part of what create_vtbl() will do is take the set difference of
|
||||
// methods defined on the original and methods being added. For every
|
||||
// method defined on the original that does *not* have one with a
|
||||
// matching name and type being added, we'll need to create a
|
||||
// forwarding slot. And, of course, we need to create a normal vtable
|
||||
// entry for every method being added.
|
||||
vtbl =
|
||||
create_vtbl(bcx.fcx.lcx, sp, outer_obj_ty, wrapper_obj, [],
|
||||
some(inner_obj_ty), additional_field_tys);
|
||||
}
|
||||
}
|
||||
|
||||
vtbl = PointerCast(bcx, vtbl, T_ptr(T_empty_struct()));
|
||||
|
||||
// Next we have to take care of the other half of the pair we're
|
||||
// returning: a boxed (reference-counted) tuple containing a tydesc,
|
||||
// typarams, fields, and a pointer to our inner_obj.
|
||||
let llbox_ty: TypeRef = T_ptr(T_empty_struct());
|
||||
|
||||
let box = C_null(llbox_ty);
|
||||
if vec::len(additional_fields) > 0u || anon_obj.inner_obj != none {
|
||||
// Synthesize a type for the object body and hand it off to
|
||||
// trans_malloc_boxed, which allocates a box, including space for a
|
||||
// refcount.
|
||||
let body_ty: ty::t =
|
||||
create_object_body_type(ccx.tcx, additional_field_tys, [],
|
||||
some(inner_obj_ty));
|
||||
let box_r = trans_malloc_boxed(bcx, body_ty);
|
||||
box = box_r.box;
|
||||
bcx = box_r.bcx;
|
||||
add_clean_free(bcx, box, false);
|
||||
let body = box_r.body;
|
||||
|
||||
// Put together a tydesc for the body, so that the object can later be
|
||||
// freed by calling through its tydesc.
|
||||
|
||||
// Every object (not just those with type parameters) needs to have a
|
||||
// tydesc to describe its body, since all objects have unknown type to
|
||||
// the user of the object. So the tydesc is needed to keep track of
|
||||
// the types of the object's fields, so that the fields can be freed
|
||||
// later.
|
||||
// postcondition on create_object_body_type?
|
||||
check type_is_tup_like(bcx, body_ty);
|
||||
let body_tydesc =
|
||||
GEP_tup_like(bcx, body_ty, body, [0, abi::obj_body_elt_tydesc]);
|
||||
bcx = body_tydesc.bcx;
|
||||
let ti = none;
|
||||
let body_td = get_tydesc(bcx, body_ty, true, tps_normal, ti).result;
|
||||
lazily_emit_tydesc_glue(bcx, abi::tydesc_field_drop_glue, ti);
|
||||
lazily_emit_tydesc_glue(bcx, abi::tydesc_field_free_glue, ti);
|
||||
bcx = body_td.bcx;
|
||||
Store(bcx, body_td.val, body_tydesc.val);
|
||||
|
||||
// Copy the object's fields into the space we allocated for the object
|
||||
// body. (This is something like saving the lexical environment of a
|
||||
// function in its closure: the fields were passed to the object
|
||||
// constructor and are now available to the object's methods.
|
||||
check type_is_tup_like(bcx, body_ty);
|
||||
let body_fields =
|
||||
GEP_tup_like(bcx, body_ty, body, [0, abi::obj_body_elt_fields]);
|
||||
bcx = body_fields.bcx;
|
||||
let i: int = 0;
|
||||
for f: ast::anon_obj_field in additional_fields {
|
||||
// FIXME (part of issue #538): make this work eventually, when we
|
||||
// have additional field exprs in the AST.
|
||||
load_if_immediate(bcx, additional_field_vals[i].val,
|
||||
additional_field_tys[i]);
|
||||
let fields_ty: ty::t = ty::mk_tup(ccx.tcx, additional_field_tys);
|
||||
// Silly check
|
||||
check type_is_tup_like(bcx, fields_ty);
|
||||
let field = GEP_tup_like(bcx, fields_ty, body_fields.val, [0, i]);
|
||||
bcx = field.bcx;
|
||||
bcx =
|
||||
copy_val(bcx, INIT, field.val, additional_field_vals[i].val,
|
||||
additional_field_tys[i]);
|
||||
i += 1;
|
||||
}
|
||||
|
||||
// If there's a inner_obj, copy a pointer to it into the object's
|
||||
// body.
|
||||
alt anon_obj.inner_obj {
|
||||
none. { }
|
||||
some(e) {
|
||||
// If inner_obj (the object being extended) exists, translate it.
|
||||
// Translating inner_obj returns a ValueRef (pointer to a 2-word
|
||||
// value) wrapped in a result.
|
||||
check type_is_tup_like(bcx, body_ty);
|
||||
let {bcx: cx, val: body_inner_obj} = GEP_tup_like
|
||||
(bcx, body_ty, body, [0, abi::obj_body_elt_inner_obj]);
|
||||
bcx = trans_expr_save_in(cx, e, body_inner_obj);
|
||||
}
|
||||
}
|
||||
revoke_clean(bcx, box);
|
||||
box = PointerCast(bcx, box, llbox_ty);
|
||||
}
|
||||
let pair = trans::get_dest_addr(dest);
|
||||
let pair_vtbl = GEPi(bcx, pair, [0, abi::obj_field_vtbl]);
|
||||
Store(bcx, vtbl, pair_vtbl);
|
||||
let pair_box = GEPi(bcx, pair, [0, abi::obj_field_box]);
|
||||
Store(bcx, box, pair_box);
|
||||
ret bcx;
|
||||
}
|
||||
|
||||
// Used only inside create_vtbl and create_backwarding_vtbl to distinguish
|
||||
// different kinds of slots we'll have to create.
|
||||
tag vtbl_mthd {
|
||||
|
||||
// Normal methods are complete AST nodes, but for forwarding methods, the
|
||||
// only information we'll have about them is their type.
|
||||
normal_mthd(@ast::method);
|
||||
fwding_mthd(@ty::method);
|
||||
}
|
||||
|
||||
// Alphabetize ast::methods by ident. A helper for create_vtbl.
|
||||
fn ast_mthd_lteq(&&a: @ast::method, &&b: @ast::method) -> bool {
|
||||
ret str::lteq(a.ident, b.ident);
|
||||
}
|
||||
|
||||
// Alphabetize vtbl_mthds by ident. A helper for create_vtbl.
|
||||
fn vtbl_mthd_lteq(a: vtbl_mthd, b: vtbl_mthd) -> bool {
|
||||
alt a {
|
||||
normal_mthd(ma) {
|
||||
alt b {
|
||||
normal_mthd(mb) { ret str::lteq(ma.ident, mb.ident); }
|
||||
fwding_mthd(mb) { ret str::lteq(ma.ident, mb.ident); }
|
||||
}
|
||||
}
|
||||
fwding_mthd(ma) {
|
||||
alt b {
|
||||
normal_mthd(mb) { ret str::lteq(ma.ident, mb.ident); }
|
||||
fwding_mthd(mb) { ret str::lteq(ma.ident, mb.ident); }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// filtering_fn: Used by create_vtbl to filter a list of methods to remove the
|
||||
// ones that we don't need forwarding slots for.
|
||||
fn filtering_fn(cx: @local_ctxt, m: vtbl_mthd, addtl_meths: [@ast::method]) ->
|
||||
option::t<vtbl_mthd> {
|
||||
|
||||
// Since m is a fwding_mthd, and we're checking to see if it's in
|
||||
// addtl_meths (which only contains normal_mthds), we can't just check if
|
||||
// it's a member of addtl_meths. Instead, we have to go through
|
||||
// addtl_meths and see if there's some method in it that has the same name
|
||||
// as m.
|
||||
alt m {
|
||||
fwding_mthd(fm) {
|
||||
for am: @ast::method in addtl_meths {
|
||||
if str::eq(am.ident, fm.ident) { ret none; }
|
||||
}
|
||||
ret some(fwding_mthd(fm));
|
||||
}
|
||||
normal_mthd(_) {
|
||||
cx.ccx.sess.bug("create_vtbl(): shouldn't be any \
|
||||
normal_mthds in meths here");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// create_vtbl: Create a vtable for a regular object or for an outer anonymous
|
||||
// object, and return a pointer to it.
|
||||
fn create_vtbl(cx: @local_ctxt, sp: span, outer_obj_ty: ty::t, ob: ast::_obj,
|
||||
ty_params: [ast::ty_param], inner_obj_ty: option::t<ty::t>,
|
||||
additional_field_tys: [ty::t]) -> ValueRef {
|
||||
|
||||
let llmethods: [ValueRef] = [];
|
||||
|
||||
alt inner_obj_ty {
|
||||
none. {
|
||||
// We're creating a vtable for a regular object, or for an anonymous
|
||||
// object that doesn't extend an existing one.
|
||||
|
||||
// Sort and process all the methods.
|
||||
let meths =
|
||||
std::sort::merge_sort(bind ast_mthd_lteq(_, _), ob.methods);
|
||||
|
||||
for m: @ast::method in meths {
|
||||
llmethods +=
|
||||
[process_normal_mthd(cx, m, outer_obj_ty, ty_params)];
|
||||
}
|
||||
}
|
||||
some(inner_obj_ty) {
|
||||
// We're creating a vtable for an anonymous object that extends an
|
||||
// existing one.
|
||||
|
||||
// The vtable needs to contain 'forwarding slots' for any methods that
|
||||
// were on the inner object and are not being overridden by the outer
|
||||
// one. To find the set of methods that we need forwarding slots for,
|
||||
// we take the set difference of { methods on the original object }
|
||||
// and { methods being added, whether entirely new or overriding }.
|
||||
|
||||
let meths: [vtbl_mthd] = [];
|
||||
|
||||
// Gather up methods on the inner object.
|
||||
alt ty::struct(cx.ccx.tcx, inner_obj_ty) {
|
||||
ty::ty_obj(inner_obj_methods) {
|
||||
for m: ty::method in inner_obj_methods {
|
||||
meths += [fwding_mthd(@m)];
|
||||
}
|
||||
}
|
||||
_ {
|
||||
cx.ccx.sess.bug("create_vtbl(): trying to extend a \
|
||||
non-object");
|
||||
}
|
||||
}
|
||||
|
||||
// Filter out any methods that we don't need forwarding slots for
|
||||
// because they're being overridden.
|
||||
let f = bind filtering_fn(cx, _, ob.methods);
|
||||
meths = vec::filter_map(meths, f);
|
||||
|
||||
// And now add the additional ones, both overriding ones and entirely
|
||||
// new ones. These will just be normal methods.
|
||||
for m: @ast::method in ob.methods { meths += [normal_mthd(m)]; }
|
||||
|
||||
// Sort all the methods and process them.
|
||||
meths =
|
||||
std::sort::merge_sort(bind vtbl_mthd_lteq(_, _), meths);
|
||||
|
||||
// To create forwarding methods, we'll need a "backwarding" vtbl. See
|
||||
// create_backwarding_vtbl and process_bkwding_method for details.
|
||||
let backwarding_vtbl: ValueRef =
|
||||
create_backwarding_vtbl(cx, sp, inner_obj_ty, outer_obj_ty);
|
||||
|
||||
for m: vtbl_mthd in meths {
|
||||
alt m {
|
||||
normal_mthd(nm) {
|
||||
llmethods +=
|
||||
[process_normal_mthd(cx, nm, outer_obj_ty, ty_params)];
|
||||
}
|
||||
fwding_mthd(fm) {
|
||||
llmethods +=
|
||||
[process_fwding_mthd(cx, sp, fm, ty_params, inner_obj_ty,
|
||||
backwarding_vtbl,
|
||||
additional_field_tys)];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ret finish_vtbl(cx, llmethods, "vtbl");
|
||||
}
|
||||
|
||||
// create_backwarding_vtbl: Create a vtable for the inner object of an
|
||||
// anonymous object, so that any self-calls made from the inner object's
|
||||
// methods get redirected appropriately.
|
||||
fn create_backwarding_vtbl(cx: @local_ctxt, sp: span, inner_obj_ty: ty::t,
|
||||
outer_obj_ty: ty::t) -> ValueRef {
|
||||
|
||||
// This vtbl needs to have slots for all of the methods on an inner
|
||||
// object, and it needs to forward them to the corresponding slots on the
|
||||
// outer object. All we know about either one are their types.
|
||||
|
||||
let llmethods: [ValueRef] = [];
|
||||
let meths: [ty::method] = [];
|
||||
|
||||
// Gather up methods on the inner object.
|
||||
alt ty::struct(cx.ccx.tcx, inner_obj_ty) {
|
||||
ty::ty_obj(inner_obj_methods) {
|
||||
for m: ty::method in inner_obj_methods { meths += [m]; }
|
||||
}
|
||||
_ {
|
||||
// Shouldn't happen.
|
||||
cx.ccx.sess.bug("create_backwarding_vtbl(): trying to extend a \
|
||||
non-object");
|
||||
}
|
||||
}
|
||||
|
||||
// Methods should have already been sorted, so no need to do so again.
|
||||
for m: ty::method in meths {
|
||||
// We pass outer_obj_ty to process_fwding_mthd() because it's the one
|
||||
// being forwarded to.
|
||||
llmethods += [process_bkwding_mthd(cx, sp, @m, [], outer_obj_ty, [])];
|
||||
}
|
||||
ret finish_vtbl(cx, llmethods, "backwarding_vtbl");
|
||||
}
|
||||
|
||||
// finish_vtbl: Given a vector of vtable entries, create the table in
|
||||
// read-only memory and return a pointer to it.
|
||||
fn finish_vtbl(cx: @local_ctxt, llmethods: [ValueRef], name: str) ->
|
||||
ValueRef {
|
||||
let vtbl = C_struct(llmethods);
|
||||
let vtbl_name = mangle_internal_name_by_path(cx.ccx, cx.path + [name]);
|
||||
let gvar =
|
||||
str::as_buf(vtbl_name,
|
||||
{|buf|
|
||||
llvm::LLVMAddGlobal(cx.ccx.llmod, val_ty(vtbl), buf)
|
||||
});
|
||||
llvm::LLVMSetInitializer(gvar, vtbl);
|
||||
llvm::LLVMSetGlobalConstant(gvar, True);
|
||||
llvm::LLVMSetLinkage(gvar,
|
||||
lib::llvm::LLVMInternalLinkage as llvm::Linkage);
|
||||
ret gvar;
|
||||
}
|
||||
|
||||
// begin_fn: Set up an LLVM function for backwarding and forwarding functions.
|
||||
fn begin_fn(cx: @local_ctxt, sp: span, m: @ty::method,
|
||||
ty_params: [ast::ty_param], fn_name: str) -> ValueRef {
|
||||
|
||||
// Create a local context that's aware of the name of the method we're
|
||||
// creating.
|
||||
let mcx: @local_ctxt = @{path: cx.path + ["method", m.ident] with *cx};
|
||||
|
||||
// Make up a name for the function.
|
||||
let s: str =
|
||||
mangle_internal_name_by_path_and_seq(mcx.ccx, mcx.path, fn_name);
|
||||
|
||||
// Get the function's type and declare it.
|
||||
let llfn_ty: TypeRef = type_of_meth(cx.ccx, sp, m, ty_params);
|
||||
let llfn: ValueRef = decl_internal_cdecl_fn(cx.ccx.llmod, s, llfn_ty);
|
||||
|
||||
ret llfn;
|
||||
}
|
||||
|
||||
// process_bkwding_mthd: Create the backwarding function that appears in a
|
||||
// backwarding vtable slot.
|
||||
//
|
||||
// Backwarding functions are used in situations where method calls dispatch
|
||||
// back through an outer object. For example, suppose an inner object has
|
||||
// methods foo and bar, and bar contains the call self.foo(). We extend that
|
||||
// object with a foo method that overrides the inner foo. Now, a call to
|
||||
// outer.bar() should send us to to inner.bar() via a normal forwarding
|
||||
// function, and then to self.foo(). But inner.bar() was already compiled
|
||||
// under the assumption that self.foo() is inner.foo(), when we really want to
|
||||
// reach outer.foo(). So, we give 'self' a vtable of backwarding functions,
|
||||
// one for each method on inner, each of which takes all the same arguments as
|
||||
// the corresponding method on inner does, calls that method on outer, and
|
||||
// returns the value returned from that call.
|
||||
fn process_bkwding_mthd(cx: @local_ctxt, sp: span, m: @ty::method,
|
||||
ty_params: [ast::ty_param], outer_obj_ty: ty::t,
|
||||
_additional_field_tys: [ty::t]) -> ValueRef {
|
||||
|
||||
let llbackwarding_fn = begin_fn(cx, sp, m, ty_params, "backwarding_fn");
|
||||
let fcx = new_fn_ctxt(cx, sp, llbackwarding_fn);
|
||||
let bcx = new_top_block_ctxt(fcx);
|
||||
let lltop = bcx.llbb;
|
||||
|
||||
// The self-object will arrive in the backwarding function via the
|
||||
// llenv argument, but we need to jump past the first item in the
|
||||
// self-stack to get to the one we really want.
|
||||
|
||||
// Cast to self-stack's type.
|
||||
let llenv =
|
||||
PointerCast(bcx, fcx.llenv,
|
||||
T_ptr(T_struct([cx.ccx.rust_object_type,
|
||||
T_ptr(cx.ccx.rust_object_type)])));
|
||||
let llself_obj_ptr = GEPi(bcx, llenv, [0, 1]);
|
||||
llself_obj_ptr = Load(bcx, llself_obj_ptr);
|
||||
|
||||
// Cast it back to pointer-to-object-type, so LLVM won't complain.
|
||||
llself_obj_ptr =
|
||||
PointerCast(bcx, llself_obj_ptr, T_ptr(cx.ccx.rust_object_type));
|
||||
|
||||
// The 'llretptr' that will arrive in the backwarding function we're
|
||||
// creating also needs to be the correct type. Cast it to the method's
|
||||
// return type, if necessary.
|
||||
let llretptr = fcx.llretptr;
|
||||
let ccx = cx.ccx;
|
||||
if ty::type_contains_params(ccx.tcx, m.fty.output) {
|
||||
let m_output = m.fty.output;
|
||||
check non_ty_var(ccx, m_output);
|
||||
let llretty = type_of_inner(ccx, sp, m_output);
|
||||
llretptr = PointerCast(bcx, llretptr, T_ptr(llretty));
|
||||
}
|
||||
|
||||
// Get the index of the method we want.
|
||||
let ix: uint = 0u;
|
||||
alt ty::struct(bcx_tcx(bcx), outer_obj_ty) {
|
||||
ty::ty_obj(methods) {
|
||||
ix = option::get(ty::method_idx(m.ident, methods));
|
||||
}
|
||||
_ {
|
||||
// Shouldn't happen.
|
||||
cx.ccx.sess.bug("process_bkwding_mthd(): non-object type passed \
|
||||
as outer_obj_ty");
|
||||
}
|
||||
}
|
||||
|
||||
// Pick out the method being backwarded to from the outer object's vtable.
|
||||
let vtbl_type = T_ptr(T_array(T_ptr(T_nil()), ix + 1u));
|
||||
|
||||
let llouter_obj_vtbl =
|
||||
GEPi(bcx, llself_obj_ptr, [0, abi::obj_field_vtbl]);
|
||||
llouter_obj_vtbl = Load(bcx, llouter_obj_vtbl);
|
||||
llouter_obj_vtbl = PointerCast(bcx, llouter_obj_vtbl, vtbl_type);
|
||||
|
||||
let llouter_mthd =
|
||||
GEPi(bcx, llouter_obj_vtbl, [0, ix as int]);
|
||||
|
||||
// Set up the outer method to be called.
|
||||
let llouter_mthd_ty = type_of_meth(bcx_ccx(bcx), sp, m, ty_params);
|
||||
llouter_mthd =
|
||||
PointerCast(bcx, llouter_mthd, T_ptr(T_ptr(llouter_mthd_ty)));
|
||||
llouter_mthd = Load(bcx, llouter_mthd);
|
||||
|
||||
// Set up the three implicit arguments to the outer method we'll need to
|
||||
// call.
|
||||
let llouter_mthd_args: [ValueRef] = [llretptr, llself_obj_ptr];
|
||||
|
||||
// Copy the explicit arguments that are being passed into the forwarding
|
||||
// function (they're in fcx.llargs) to llouter_mthd_args.
|
||||
|
||||
let a: uint = 2u; // retptr, env come first
|
||||
for arg: ty::arg in m.fty.inputs {
|
||||
llouter_mthd_args += [llvm::LLVMGetParam(llbackwarding_fn, a)];
|
||||
a += 1u;
|
||||
}
|
||||
|
||||
// And, finally, call the outer method.
|
||||
Call(bcx, llouter_mthd, llouter_mthd_args);
|
||||
|
||||
build_return(bcx);
|
||||
finish_fn(fcx, lltop);
|
||||
|
||||
ret llbackwarding_fn;
|
||||
|
||||
}
|
||||
|
||||
// process_fwding_mthd: Create the forwarding function that appears in a
|
||||
// vtable slot for method calls that need to forward to another object. A
|
||||
// helper function for create_vtbl.
|
||||
//
|
||||
// Forwarding functions are used for method calls that fall through to an
|
||||
// inner object. For example, suppose an inner object has method foo and we
|
||||
// extend it with a method bar. The only version of 'foo' we have is on the
|
||||
// inner object, but we would like to be able to call outer.foo(). So we use
|
||||
// a forwarding function to make the foo method available on the outer object.
|
||||
// It takes all the same arguments as the foo method on the inner object does,
|
||||
// calls inner.foo() with those arguments, and then returns the value returned
|
||||
// from that call. (The inner object won't exist until run-time, but we know
|
||||
// its type statically.)
|
||||
fn process_fwding_mthd(cx: @local_ctxt, sp: span, m: @ty::method,
|
||||
ty_params: [ast::ty_param], inner_obj_ty: ty::t,
|
||||
backwarding_vtbl: ValueRef,
|
||||
additional_field_tys: [ty::t]) -> ValueRef unsafe {
|
||||
|
||||
// Create a new function context and block context for the function,
|
||||
// holding onto a pointer to the first block.
|
||||
let llforwarding_fn = begin_fn(cx, sp, m, ty_params, "forwarding_fn");
|
||||
let fcx = new_fn_ctxt(cx, sp, llforwarding_fn);
|
||||
let bcx = new_top_block_ctxt(fcx);
|
||||
let lltop = bcx.llbb;
|
||||
|
||||
// The outer object will arrive in the forwarding function via the llenv
|
||||
// argument.
|
||||
let llself_obj_ptr = fcx.llenv;
|
||||
|
||||
// The 'llretptr' that will arrive in the forwarding function we're
|
||||
// creating also needs to be the correct type. Cast it to the method's
|
||||
// return type, if necessary.
|
||||
let llretptr = fcx.llretptr;
|
||||
let ccx = cx.ccx;
|
||||
if ty::type_contains_params(ccx.tcx, m.fty.output) {
|
||||
let m_output = m.fty.output;
|
||||
check non_ty_var(ccx, m_output);
|
||||
let llretty = type_of_inner(ccx, sp, m_output);
|
||||
llretptr = PointerCast(bcx, llretptr, T_ptr(llretty));
|
||||
}
|
||||
|
||||
// Now, we have to get the the inner_obj's vtbl out of the self_obj. This
|
||||
// is a multi-step process:
|
||||
|
||||
// First, grab the box out of the self_obj. It contains a refcount and a
|
||||
// body.
|
||||
let llself_obj_box =
|
||||
GEPi(bcx, llself_obj_ptr, [0, abi::obj_field_box]);
|
||||
llself_obj_box = Load(bcx, llself_obj_box);
|
||||
|
||||
let ccx = bcx_ccx(bcx);
|
||||
let llbox_ty = T_opaque_obj_ptr(ccx);
|
||||
llself_obj_box = PointerCast(bcx, llself_obj_box, llbox_ty);
|
||||
|
||||
// Now, reach into the box and grab the body.
|
||||
let llself_obj_body =
|
||||
GEPi(bcx, llself_obj_box, [0, abi::box_rc_field_body]);
|
||||
|
||||
// Now, we need to figure out exactly what type the body is supposed to be
|
||||
// cast to.
|
||||
let body_ty: ty::t =
|
||||
create_object_body_type(cx.ccx.tcx, additional_field_tys, [],
|
||||
some(inner_obj_ty));
|
||||
// And cast to that type.
|
||||
// create_object_body_type maybe should have a postcondition...
|
||||
|
||||
let cx_ccx = cx.ccx;
|
||||
check (type_has_static_size(cx_ccx, body_ty));
|
||||
|
||||
llself_obj_body =
|
||||
PointerCast(bcx, llself_obj_body,
|
||||
T_ptr(type_of(cx_ccx, sp, body_ty)));
|
||||
|
||||
// Now, reach into the body and grab the inner_obj.
|
||||
check type_is_tup_like(bcx, body_ty);
|
||||
let llinner_obj =
|
||||
GEP_tup_like(bcx, body_ty, llself_obj_body,
|
||||
[0, abi::obj_body_elt_inner_obj]);
|
||||
bcx = llinner_obj.bcx;
|
||||
|
||||
// And, now, somewhere in inner_obj is a vtable with an entry for the
|
||||
// method we want. First, pick out the vtable, and then pluck that
|
||||
// method's entry out of the vtable so that the forwarding function can
|
||||
// call it.
|
||||
let llinner_obj_vtbl =
|
||||
GEPi(bcx, llinner_obj.val, [0, abi::obj_field_vtbl]);
|
||||
llinner_obj_vtbl = Load(bcx, llinner_obj_vtbl);
|
||||
|
||||
let llinner_obj_body =
|
||||
GEPi(bcx, llinner_obj.val, [0, abi::obj_field_box]);
|
||||
llinner_obj_body = Load(bcx, llinner_obj_body);
|
||||
|
||||
// Get the index of the method we want.
|
||||
let ix: uint = 0u;
|
||||
alt ty::struct(bcx_tcx(bcx), inner_obj_ty) {
|
||||
ty::ty_obj(methods) {
|
||||
ix = option::get(ty::method_idx(m.ident, methods));
|
||||
}
|
||||
_ {
|
||||
// Shouldn't happen.
|
||||
cx.ccx.sess.bug("process_fwding_mthd(): non-object type passed \
|
||||
as target_obj_ty");
|
||||
}
|
||||
}
|
||||
|
||||
// Pick out the original method from the vtable.
|
||||
let vtbl_type = T_ptr(T_array(T_ptr(T_nil()), ix + 1u));
|
||||
llinner_obj_vtbl = PointerCast(bcx, llinner_obj_vtbl, vtbl_type);
|
||||
|
||||
let llorig_mthd =
|
||||
GEPi(bcx, llinner_obj_vtbl, [0, ix as int]);
|
||||
|
||||
// Set up the original method to be called.
|
||||
let llorig_mthd_ty = type_of_meth(bcx_ccx(bcx), sp, m, ty_params);
|
||||
llorig_mthd = PointerCast(bcx, llorig_mthd, T_ptr(T_ptr(llorig_mthd_ty)));
|
||||
llorig_mthd = Load(bcx, llorig_mthd);
|
||||
|
||||
// Set up the self-stack.
|
||||
let self_stack =
|
||||
alloca(bcx,
|
||||
T_struct([cx.ccx.rust_object_type,
|
||||
T_ptr(cx.ccx.rust_object_type)]));
|
||||
self_stack =
|
||||
populate_self_stack(bcx, self_stack, llself_obj_ptr, backwarding_vtbl,
|
||||
llinner_obj_body);
|
||||
|
||||
// Cast self_stack back to pointer-to-object-type to make LLVM happy.
|
||||
self_stack = PointerCast(bcx, self_stack, T_ptr(cx.ccx.rust_object_type));
|
||||
|
||||
// Set up the three implicit arguments to the original method we'll need
|
||||
// to call.
|
||||
let llorig_mthd_args: [ValueRef] = [llretptr, self_stack];
|
||||
|
||||
// Copy the explicit arguments that are being passed into the forwarding
|
||||
// function (they're in fcx.llargs) to llorig_mthd_args.
|
||||
|
||||
let a: uint = 2u; // retptr, env come first
|
||||
for arg: ty::arg in m.fty.inputs {
|
||||
llorig_mthd_args += [llvm::LLVMGetParam(llforwarding_fn, a)];
|
||||
a += 1u;
|
||||
}
|
||||
|
||||
// And, finally, call the original (inner) method.
|
||||
Call(bcx, llorig_mthd, llorig_mthd_args);
|
||||
|
||||
build_return(bcx);
|
||||
finish_fn(fcx, lltop);
|
||||
|
||||
ret llforwarding_fn;
|
||||
}
|
||||
|
||||
// create_object_body_type: Synthesize a big structural tuple type for an
|
||||
// object body: [tydesc, [typaram, ...], [field, ...], inner_obj].
|
||||
fn create_object_body_type(tcx: ty::ctxt, fields_ty: [ty::t],
|
||||
typarams_ty: [ty::t],
|
||||
maybe_inner_obj_ty: option::t<ty::t>) -> ty::t {
|
||||
|
||||
let tydesc_ty: ty::t = ty::mk_type(tcx);
|
||||
let typarams_ty_tup: ty::t = ty::mk_tup(tcx, typarams_ty);
|
||||
let fields_ty_tup: ty::t = ty::mk_tup(tcx, fields_ty);
|
||||
|
||||
let body_ty: ty::t;
|
||||
alt maybe_inner_obj_ty {
|
||||
some(inner_obj_ty) {
|
||||
body_ty =
|
||||
ty::mk_tup(tcx,
|
||||
[tydesc_ty, typarams_ty_tup, fields_ty_tup,
|
||||
inner_obj_ty]);
|
||||
}
|
||||
none {
|
||||
body_ty =
|
||||
ty::mk_tup(tcx, [tydesc_ty, typarams_ty_tup, fields_ty_tup]);
|
||||
}
|
||||
}
|
||||
|
||||
ret body_ty;
|
||||
}
|
||||
|
||||
// process_normal_mthd: Create the contents of a normal vtable slot. A helper
|
||||
// function for create_vtbl.
|
||||
fn process_normal_mthd(cx: @local_ctxt, m: @ast::method, self_ty: ty::t,
|
||||
ty_params: [ast::ty_param]) -> ValueRef {
|
||||
|
||||
let llfnty = T_nil();
|
||||
let ccx = cx.ccx;
|
||||
alt ty::struct(cx.ccx.tcx, node_id_type(cx.ccx, m.id)) {
|
||||
ty::ty_fn(f) {
|
||||
let out = f.output;
|
||||
check non_ty_var(ccx, out);
|
||||
llfnty = type_of_fn(
|
||||
ccx, m.span, true, f.inputs, out,
|
||||
vec::map(ty_params, {|p| param_bounds(ccx, p)}));
|
||||
}
|
||||
}
|
||||
let mcx: @local_ctxt =
|
||||
@{path: cx.path + ["method", m.ident] with *cx};
|
||||
let s: str = mangle_internal_name_by_path(mcx.ccx, mcx.path);
|
||||
let llfn: ValueRef = decl_internal_cdecl_fn(ccx.llmod, s, llfnty);
|
||||
|
||||
// Every method on an object gets its node_id inserted into the crate-wide
|
||||
// item_ids map, together with the ValueRef that points to where that
|
||||
// method's definition will be in the executable.
|
||||
ccx.item_ids.insert(m.id, llfn);
|
||||
ccx.item_symbols.insert(m.id, s);
|
||||
trans_fn(mcx, m.span, m.decl, m.body, llfn, obj_self(self_ty), ty_params,
|
||||
m.id);
|
||||
|
||||
ret llfn;
|
||||
}
|
||||
|
||||
// Update a self-stack structure ([[wrapper_self_pair], self_pair*]) to
|
||||
// [[backwarding_vtbl*, inner_obj_body*], outer_obj*].
|
||||
//
|
||||
// We do this when we're receiving the outer object in a forwarding function
|
||||
// via the llenv argument, and we want the forwarding function to call a
|
||||
// method on a "self" that's inner-obj-shaped, but we also want to hold onto
|
||||
// the outer obj for potential use later by backwarding functions.
|
||||
fn populate_self_stack(bcx: @block_ctxt, self_stack: ValueRef,
|
||||
outer_obj: ValueRef, backwarding_vtbl: ValueRef,
|
||||
inner_obj_body: ValueRef) -> ValueRef {
|
||||
|
||||
// Drop the outer obj into the second slot.
|
||||
let self_pair_ptr = GEPi(bcx, self_stack, [0, 1]);
|
||||
Store(bcx, outer_obj, self_pair_ptr);
|
||||
|
||||
// Drop in the backwarding vtbl.
|
||||
let wrapper_pair = GEPi(bcx, self_stack, [0, 0]);
|
||||
let wrapper_vtbl_ptr = GEPi(bcx, wrapper_pair, [0, 0]);
|
||||
let backwarding_vtbl_cast =
|
||||
PointerCast(bcx, backwarding_vtbl, T_ptr(T_empty_struct()));
|
||||
Store(bcx, backwarding_vtbl_cast, wrapper_vtbl_ptr);
|
||||
|
||||
// Drop in the inner obj body.
|
||||
let wrapper_body_ptr = GEPi(bcx, wrapper_pair, [0, 1]);
|
||||
Store(bcx, inner_obj_body, wrapper_body_ptr);
|
||||
|
||||
ret self_stack;
|
||||
}
|
||||
|
||||
fn type_of_meth(ccx: @crate_ctxt, sp: span, m: @ty::method,
|
||||
tps: [ast::ty_param]) -> TypeRef {
|
||||
let out_ty = m.fty.output;
|
||||
check non_ty_var(ccx, out_ty);
|
||||
type_of_fn(ccx, sp, true, m.fty.inputs, out_ty,
|
||||
vec::map(tps, {|p| param_bounds(ccx, p)}))
|
||||
}
|
||||
|
||||
//
|
||||
// Local Variables:
|
||||
// mode: rust
|
||||
// fill-column: 78;
|
||||
// indent-tabs-mode: nil
|
||||
// c-basic-offset: 4
|
||||
// buffer-file-coding-system: utf-8-unix
|
||||
// End:
|
||||
//
|
|
@ -6,7 +6,7 @@
|
|||
import trans::{call_memmove, trans_shared_malloc, llsize_of, type_of_or_i8,
|
||||
INIT, copy_val, load_if_immediate, size_of,
|
||||
get_tydesc,
|
||||
node_id_type, new_sub_block_ctxt, tps_normal, do_spill_noroot,
|
||||
node_id_type, new_sub_block_ctxt, do_spill_noroot,
|
||||
dest};
|
||||
import trans_build::*;
|
||||
import trans_common::*;
|
||||
|
@ -201,7 +201,7 @@ fn trans_append_literal(bcx: @block_ctxt, vptrptr: ValueRef, vec_ty: ty::t,
|
|||
let elt_ty = ty::sequence_element_type(bcx_tcx(bcx), vec_ty);
|
||||
let ti = none;
|
||||
let {bcx: bcx, val: td} =
|
||||
get_tydesc(bcx, elt_ty, false, tps_normal, ti).result;
|
||||
get_tydesc(bcx, elt_ty, false, ti).result;
|
||||
trans::lazily_emit_tydesc_glue(bcx, abi::tydesc_field_take_glue, ti);
|
||||
let opaque_v = PointerCast(bcx, vptrptr,
|
||||
T_ptr(T_ptr(ccx.opaque_vec_type)));
|
||||
|
|
|
@ -73,7 +73,6 @@ fn find_pre_post_item(ccx: crate_ctxt, i: item) {
|
|||
ccx: ccx};
|
||||
find_pre_post_fn(fcx, body);
|
||||
}
|
||||
item_obj(o, _, _) {for m in o.methods { find_pre_post_method(ccx, m); }}
|
||||
item_impl(_, _, _, ms) { for m in ms { find_pre_post_method(ccx, m); } }
|
||||
}
|
||||
}
|
||||
|
@ -551,15 +550,6 @@ fn combine_pp(antec: pre_and_post, fcx: fn_ctxt, &&pp: pre_and_post,
|
|||
expr_break. { clear_pp(expr_pp(fcx.ccx, e)); }
|
||||
expr_cont. { clear_pp(expr_pp(fcx.ccx, e)); }
|
||||
expr_mac(_) { fcx.ccx.tcx.sess.bug("unexpanded macro"); }
|
||||
expr_anon_obj(anon_obj) {
|
||||
alt anon_obj.inner_obj {
|
||||
some(ex) {
|
||||
find_pre_post_expr(fcx, ex);
|
||||
copy_pre_post(fcx.ccx, e.id, ex);
|
||||
}
|
||||
none. { clear_pp(expr_pp(fcx.ccx, e)); }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -609,12 +609,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_anon_obj(anon_obj) {
|
||||
alt anon_obj.inner_obj {
|
||||
some(wt) { ret find_pre_post_state_sub(fcx, pres, wt, e.id, none); }
|
||||
none. { ret pure_exp(fcx.ccx, e.id, pres); }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -72,7 +72,6 @@
|
|||
export mk_native;
|
||||
export mk_native_fn;
|
||||
export mk_nil;
|
||||
export mk_obj;
|
||||
export mk_iface;
|
||||
export mk_res;
|
||||
export mk_param;
|
||||
|
@ -124,7 +123,6 @@
|
|||
export ty_vec;
|
||||
export ty_native;
|
||||
export ty_nil;
|
||||
export ty_obj;
|
||||
export ty_iface;
|
||||
export ty_res;
|
||||
export ty_param;
|
||||
|
@ -138,7 +136,7 @@
|
|||
export ty_uniq;
|
||||
export ty_var;
|
||||
export ty_named;
|
||||
export same_type, same_method;
|
||||
export same_type;
|
||||
export ty_var_id;
|
||||
export ty_param_substs_opt_and_ty_to_monotype;
|
||||
export ty_fn_args;
|
||||
|
@ -266,7 +264,6 @@
|
|||
ty_rec([field]);
|
||||
ty_fn(fn_ty);
|
||||
ty_native_fn([arg], t);
|
||||
ty_obj([method]);
|
||||
ty_iface(def_id, [t]);
|
||||
ty_res(def_id, t, [t]);
|
||||
ty_tup([t]);
|
||||
|
@ -298,8 +295,6 @@
|
|||
terr_record_size(uint, uint);
|
||||
terr_record_mutability;
|
||||
terr_record_fields(ast::ident, ast::ident);
|
||||
terr_meth_count;
|
||||
terr_obj_meths(ast::ident, ast::ident);
|
||||
terr_arg_count;
|
||||
terr_mode_mismatch(mode, mode);
|
||||
terr_constr_len(uint, uint);
|
||||
|
@ -497,12 +492,6 @@ fn derive_flags_sig(cx: ctxt, &has_params: bool, &has_vars: bool,
|
|||
ty_native_fn(args, tt) {
|
||||
derive_flags_sig(cx, has_params, has_vars, args, tt);
|
||||
}
|
||||
ty_obj(meths) {
|
||||
for m: method in meths {
|
||||
derive_flags_sig(cx, has_params, has_vars, m.fty.inputs,
|
||||
m.fty.output);
|
||||
}
|
||||
}
|
||||
ty_res(_, tt, tps) {
|
||||
derive_flags_t(cx, has_params, has_vars, tt);
|
||||
for tt: t in tps { derive_flags_t(cx, has_params, has_vars, tt); }
|
||||
|
@ -614,8 +603,6 @@ fn mk_native_fn(cx: ctxt, args: [arg], ty: t) -> t {
|
|||
ret gen_ty(cx, ty_native_fn(args, ty));
|
||||
}
|
||||
|
||||
fn mk_obj(cx: ctxt, meths: [method]) -> t { ret gen_ty(cx, ty_obj(meths)); }
|
||||
|
||||
fn mk_iface(cx: ctxt, did: ast::def_id, tys: [t]) -> t {
|
||||
ret gen_ty(cx, ty_iface(did, tys));
|
||||
}
|
||||
|
@ -705,12 +692,6 @@ fn walk_ty(cx: ctxt, walker: ty_walk, ty: t) {
|
|||
for a: arg in args { walk_ty(cx, walker, a.ty); }
|
||||
walk_ty(cx, walker, ret_ty);
|
||||
}
|
||||
ty_obj(methods) {
|
||||
for m: method in methods {
|
||||
for a: arg in m.fty.inputs { walk_ty(cx, walker, a.ty); }
|
||||
walk_ty(cx, walker, m.fty.output);
|
||||
}
|
||||
}
|
||||
ty_res(_, sub, tps) {
|
||||
walk_ty(cx, walker, sub);
|
||||
for tp: t in tps { walk_ty(cx, walker, tp); }
|
||||
|
@ -797,18 +778,6 @@ fn fold_ty(cx: ctxt, fld: fold_mode, ty_0: t) -> t {
|
|||
}
|
||||
ty = mk_native_fn(cx, new_args, fold_ty(cx, fld, ret_ty));
|
||||
}
|
||||
ty_obj(methods) {
|
||||
let new_methods = vec::map(methods, {|m|
|
||||
let new_args = vec::map(m.fty.inputs, {|a|
|
||||
{mode: a.mode, ty: fold_ty(cx, fld, a.ty)}
|
||||
});
|
||||
{ident: m.ident, tps: m.tps,
|
||||
fty: {inputs: new_args,
|
||||
output: fold_ty(cx, fld, m.fty.output)
|
||||
with m.fty}}
|
||||
});
|
||||
ty = mk_obj(cx, new_methods);
|
||||
}
|
||||
ty_res(did, subty, tps) {
|
||||
let new_tps = [];
|
||||
for tp: t in tps { new_tps += [fold_ty(cx, fld, tp)]; }
|
||||
|
@ -850,7 +819,7 @@ fn type_is_bool(cx: ctxt, ty: t) -> bool {
|
|||
fn type_is_structural(cx: ctxt, ty: t) -> bool {
|
||||
alt struct(cx, ty) {
|
||||
ty_rec(_) | ty_tup(_) | ty_tag(_, _) | ty_fn(_) |
|
||||
ty_native_fn(_, _) | ty_obj(_) | ty_res(_, _, _) { true }
|
||||
ty_native_fn(_, _) | ty_res(_, _, _) { true }
|
||||
_ { false }
|
||||
}
|
||||
}
|
||||
|
@ -1056,9 +1025,6 @@ fn type_kind(cx: ctxt, ty: t) -> kind {
|
|||
ty_native(_) | ty_ptr(_) |
|
||||
ty_send_type. | ty_str. | ty_native_fn(_, _) { kind_sendable }
|
||||
ty_type. { kind_copyable }
|
||||
// FIXME: obj is broken for now, since we aren't asserting
|
||||
// anything about its fields.
|
||||
ty_obj(_) { kind_copyable }
|
||||
ty_fn(f) { proto_kind(f.proto) }
|
||||
ty_opaque_closure_ptr(ck_block.) { kind_noncopyable }
|
||||
ty_opaque_closure_ptr(ck_box.) { kind_copyable }
|
||||
|
@ -1233,7 +1199,7 @@ fn type_is_pod(cx: ctxt, ty: t) -> bool {
|
|||
ty_send_type. | ty_type. | ty_native(_) | ty_ptr(_) { result = true; }
|
||||
// Boxed types
|
||||
ty_str. | ty_box(_) | ty_uniq(_) | ty_vec(_) | ty_fn(_) |
|
||||
ty_native_fn(_, _) | ty_obj(_) | ty_iface(_, _) { result = false; }
|
||||
ty_native_fn(_, _) | ty_iface(_, _) { result = false; }
|
||||
// Structural types
|
||||
ty_tag(did, tps) {
|
||||
let variants = tag_variants(cx, did);
|
||||
|
@ -1417,11 +1383,6 @@ fn hash_fn(id: uint, args: [arg], rty: t) -> uint {
|
|||
// ???
|
||||
ty_fn(f) { ret hash_fn(27u, f.inputs, f.output); }
|
||||
ty_native_fn(args, rty) { ret hash_fn(28u, args, rty); }
|
||||
ty_obj(methods) {
|
||||
let h = 29u;
|
||||
for m: method in methods { h += (h << 5u) + str::hash(m.ident); }
|
||||
ret h;
|
||||
}
|
||||
ty_var(v) { ret hash_uint(30u, v as uint); }
|
||||
ty_param(pid, _) { ret hash_uint(31u, pid); }
|
||||
ty_type. { ret 32u; }
|
||||
|
@ -1670,20 +1631,11 @@ fn expr_has_ty_params(cx: ctxt, expr: @ast::expr) -> bool {
|
|||
ret node_id_has_type_params(cx, expr.id);
|
||||
}
|
||||
|
||||
fn expr_is_lval(method_map: typeck::method_map, tcx: ty::ctxt,
|
||||
e: @ast::expr) -> bool {
|
||||
fn expr_is_lval(method_map: typeck::method_map, e: @ast::expr) -> bool {
|
||||
alt e.node {
|
||||
ast::expr_path(_) | ast::expr_index(_, _) |
|
||||
ast::expr_unary(ast::deref., _) { true }
|
||||
ast::expr_field(base, ident, _) {
|
||||
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 }
|
||||
}
|
||||
}
|
||||
}
|
||||
ast::expr_field(base, ident, _) { !method_map.contains_key(e.id) }
|
||||
_ { false }
|
||||
}
|
||||
}
|
||||
|
@ -2060,35 +2012,6 @@ fn unify_native_fn(cx: @ctxt, expected_inputs: [arg], expected_output: t,
|
|||
err { err }
|
||||
}
|
||||
}
|
||||
fn unify_obj(cx: @ctxt, expected_meths: [method],
|
||||
actual_meths: [method], variance: variance) -> result {
|
||||
let result_meths: [method] = [];
|
||||
let i: uint = 0u;
|
||||
let expected_len: uint = vec::len(expected_meths);
|
||||
let actual_len: uint = vec::len(actual_meths);
|
||||
if expected_len != actual_len { ret ures_err(terr_meth_count); }
|
||||
while i < expected_len {
|
||||
let e_meth = expected_meths[i];
|
||||
let a_meth = actual_meths[i];
|
||||
if !str::eq(e_meth.ident, a_meth.ident) {
|
||||
ret ures_err(terr_obj_meths(e_meth.ident, a_meth.ident));
|
||||
}
|
||||
alt unify_fn(cx, e_meth.fty, a_meth.fty, variance) {
|
||||
ures_ok(tfn) {
|
||||
alt struct(cx.tcx, tfn) {
|
||||
ty_fn(f) {
|
||||
result_meths += [{ident: e_meth.ident,
|
||||
tps: a_meth.tps, fty: f}];
|
||||
}
|
||||
}
|
||||
}
|
||||
err { ret err; }
|
||||
}
|
||||
i += 1u;
|
||||
}
|
||||
let t = mk_obj(cx.tcx, result_meths);
|
||||
ret ures_ok(t);
|
||||
}
|
||||
|
||||
// If the given type is a variable, returns the structure of that type.
|
||||
fn resolve_type_structure(tcx: ty_ctxt, vb: @var_bindings, typ: t) ->
|
||||
|
@ -2483,14 +2406,6 @@ fn unify_step(cx: @ctxt, expected: t, actual: t,
|
|||
_ { ret ures_err(terr_mismatch); }
|
||||
}
|
||||
}
|
||||
ty::ty_obj(expected_meths) {
|
||||
alt struct(cx.tcx, actual) {
|
||||
ty::ty_obj(actual_meths) {
|
||||
ret unify_obj(cx, expected_meths, actual_meths, variance);
|
||||
}
|
||||
_ { ret ures_err(terr_mismatch); }
|
||||
}
|
||||
}
|
||||
ty::ty_constr(expected_t, expected_constrs) {
|
||||
|
||||
// unify the base types...
|
||||
|
@ -2600,13 +2515,6 @@ fn same_type(cx: ctxt, a: t, b: t) -> bool {
|
|||
_ { false }
|
||||
}
|
||||
}
|
||||
fn same_method(cx: ctxt, a: method, b: method) -> bool {
|
||||
a.tps == b.tps && a.fty.proto == b.fty.proto && a.ident == b.ident &&
|
||||
vec::all2(a.fty.inputs, b.fty.inputs,
|
||||
{|a, b| a.mode == b.mode && same_type(cx, a.ty, b.ty) }) &&
|
||||
same_type(cx, a.fty.output, b.fty.output) &&
|
||||
a.fty.ret_style == b.fty.ret_style
|
||||
}
|
||||
|
||||
fn type_err_to_str(err: ty::type_err) -> str {
|
||||
alt err {
|
||||
|
@ -2639,11 +2547,6 @@ fn to_str(s: ast::ret_style) -> str {
|
|||
"' but found one with field '" + a_fld + "'";
|
||||
}
|
||||
terr_arg_count. { ret "incorrect number of function parameters"; }
|
||||
terr_meth_count. { ret "incorrect number of object methods"; }
|
||||
terr_obj_meths(e_meth, a_meth) {
|
||||
ret "expected an obj with method '" + e_meth +
|
||||
"' but found one with method '" + a_meth + "'";
|
||||
}
|
||||
terr_mode_mismatch(e_mode, a_mode) {
|
||||
ret "expected argument mode " + mode_str(e_mode) + " but found " +
|
||||
mode_str(a_mode);
|
||||
|
@ -2675,7 +2578,7 @@ fn substituter(_cx: ctxt, substs: @[ty::t], idx: uint, _did: def_id)
|
|||
|
||||
fn def_has_ty_params(def: ast::def) -> bool {
|
||||
alt def {
|
||||
ast::def_obj_field(_, _) | ast::def_mod(_) | ast::def_const(_) |
|
||||
ast::def_mod(_) | ast::def_const(_) |
|
||||
ast::def_arg(_, _) | ast::def_local(_, _) | ast::def_upvar(_, _, _) |
|
||||
ast::def_ty_param(_, _) | ast::def_binding(_) | ast::def_use(_) |
|
||||
ast::def_native_ty(_) | ast::def_self(_) | ast::def_ty(_) { false }
|
||||
|
|
|
@ -42,9 +42,8 @@
|
|||
|
||||
type ty_table = hashmap<ast::def_id, ty::t>;
|
||||
|
||||
// Used for typechecking the methods of an object.
|
||||
// Used for typechecking the methods of an impl
|
||||
tag self_info {
|
||||
self_obj([ast::obj_field], ty::t);
|
||||
self_impl(ty::t);
|
||||
}
|
||||
|
||||
|
@ -102,15 +101,10 @@ fn ty_param_bounds_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 {bounds: @[], 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 {bounds: @[], ty: typ};
|
||||
}
|
||||
ast::def_self(id) {
|
||||
alt get_self_info(fcx.ccx) {
|
||||
some(self_obj(_, obj_t)) | some(self_impl(obj_t)) {
|
||||
ret {bounds: @[], ty: obj_t};
|
||||
some(self_impl(impl_t)) {
|
||||
ret {bounds: @[], ty: impl_t};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -356,10 +350,6 @@ fn instantiate(tcx: ty::ctxt, sp: span, mode: mode,
|
|||
}
|
||||
}
|
||||
}
|
||||
ast::ty_obj(meths) {
|
||||
let ms = vec::map(meths, {|m| ty_of_ty_method(tcx, mode, m) });
|
||||
typ = ty::mk_obj(tcx, ty::sort_methods(ms));
|
||||
}
|
||||
ast::ty_constr(t, cs) {
|
||||
let out_cs = [];
|
||||
for constr: @ast::ty_constr in cs {
|
||||
|
@ -391,11 +381,6 @@ fn ty_of_item(tcx: ty::ctxt, mode: mode, it: @ast::item)
|
|||
ast::item_fn(decl, tps, _) {
|
||||
ret ty_of_fn(tcx, mode, decl, tps, local_def(it.id));
|
||||
}
|
||||
ast::item_obj(ob, tps, _) {
|
||||
let t_obj = ty_of_obj(tcx, mode, it.ident, ob, tps);
|
||||
tcx.tcache.insert(local_def(it.id), t_obj);
|
||||
ret t_obj;
|
||||
}
|
||||
ast::item_ty(t, tps) {
|
||||
alt tcx.tcache.find(local_def(it.id)) {
|
||||
some(tpt) { ret tpt; }
|
||||
|
@ -541,30 +526,6 @@ fn ty_of_ty_method(tcx: ty::ctxt, mode: mode, m: ast::ty_method)
|
|||
{ident: m.ident, tps: ty_param_bounds(tcx, mode, m.tps),
|
||||
fty: ty_of_fn_decl(tcx, mode, ast::proto_bare, m.decl)}
|
||||
}
|
||||
fn ty_of_obj(tcx: ty::ctxt, mode: mode, id: ast::ident, ob: ast::_obj,
|
||||
ty_params: [ast::ty_param]) -> ty::ty_param_bounds_and_ty {
|
||||
let bounds = ty_param_bounds(tcx, mode, ty_params);
|
||||
let methods = vec::map(ob.methods, {|m| ty_of_method(tcx, mode, m)});
|
||||
let t_obj = ty::mk_named(tcx, ty::mk_obj(tcx, ty::sort_methods(methods)),
|
||||
@id);
|
||||
ret {bounds: bounds, ty: t_obj};
|
||||
}
|
||||
fn ty_of_obj_ctor(tcx: ty::ctxt, mode: mode, id: ast::ident, ob: ast::_obj,
|
||||
ctor_id: ast::node_id, ty_params: [ast::ty_param])
|
||||
-> ty::ty_param_bounds_and_ty {
|
||||
let t_obj = ty_of_obj(tcx, mode, id, ob, ty_params);
|
||||
let t_inputs: [arg] = [];
|
||||
for f: ast::obj_field in ob.fields {
|
||||
let t_field = ast_ty_to_ty(tcx, mode, f.ty);
|
||||
t_inputs += [{mode: ast::by_copy, ty: t_field}];
|
||||
}
|
||||
let t_fn = ty::mk_fn(tcx, {proto: ast::proto_box,
|
||||
inputs: t_inputs, output: t_obj.ty,
|
||||
ret_style: ast::return_val, constraints: []});
|
||||
let tpt = {bounds: ty_param_bounds(tcx, mode, ty_params), ty: t_fn};
|
||||
tcx.tcache.insert(local_def(ctor_id), tpt);
|
||||
ret tpt;
|
||||
}
|
||||
|
||||
// A convenience function to use a crate_ctxt to resolve names for
|
||||
// ast_ty_to_ty.
|
||||
|
@ -766,38 +727,6 @@ fn convert(cx: @ctxt, it: @ast::item) {
|
|||
_ {}
|
||||
}
|
||||
}
|
||||
ast::item_obj(object, ty_params, ctor_id) {
|
||||
// Now we need to call ty_of_obj_ctor(); this is the type that
|
||||
// we write into the table for this item.
|
||||
ty_of_item(cx.tcx, m_collect, it);
|
||||
let tpt = ty_of_obj_ctor(cx.tcx, m_collect, it.ident, object,
|
||||
ctor_id, ty_params);
|
||||
write::ty_only(cx.tcx, ctor_id, tpt.ty);
|
||||
// Write the methods into the type table.
|
||||
//
|
||||
// FIXME: Inefficient; this ends up calling
|
||||
// get_obj_method_types() twice. (The first time was above in
|
||||
// ty_of_obj().)
|
||||
let m_types = vec::map(object.methods,
|
||||
{|m| ty_of_method(cx.tcx, m_collect, m)});
|
||||
let i = 0u;
|
||||
for m in object.methods {
|
||||
write::ty_only(cx.tcx, m.id,
|
||||
ty::mk_fn(cx.tcx, m_types[i].fty));
|
||||
i += 1u;
|
||||
}
|
||||
// Write in the types of the object fields.
|
||||
//
|
||||
// FIXME: We want to use uint::range() here, but that causes
|
||||
// an assertion in trans.
|
||||
let args = ty::ty_fn_args(cx.tcx, tpt.ty);
|
||||
i = 0u;
|
||||
while i < vec::len::<ty::arg>(args) {
|
||||
let fld = object.fields[i];
|
||||
write::ty_only(cx.tcx, fld.id, args[i].ty);
|
||||
i += 1u;
|
||||
}
|
||||
}
|
||||
ast::item_res(decl, tps, _, dtor_id, ctor_id) {
|
||||
let {bounds, params} = mk_ty_params(cx.tcx, tps);
|
||||
let t_arg = ty_of_arg(cx.tcx, m_collect, decl.inputs[0]);
|
||||
|
@ -1190,16 +1119,6 @@ fn gather_locals(ccx: @crate_ctxt,
|
|||
}
|
||||
};
|
||||
|
||||
// Add object fields, if any.
|
||||
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)));
|
||||
}
|
||||
}
|
||||
_ {}
|
||||
}
|
||||
|
||||
// Add formal parameters.
|
||||
let args = ty::ty_fn_args(ccx.tcx, ty::node_id_to_type(ccx.tcx, id));
|
||||
let i = 0u;
|
||||
|
@ -2323,21 +2242,6 @@ fn get_node(f: spanned<field>) -> field { f.node }
|
|||
_ {}
|
||||
}
|
||||
}
|
||||
ty::ty_obj(methods) {
|
||||
alt ty::method_idx(field, methods) {
|
||||
some(ix) {
|
||||
if n_tys > 0u {
|
||||
tcx.sess.span_err(expr.span,
|
||||
"can't provide type parameters \
|
||||
to an obj method");
|
||||
}
|
||||
write::ty_only_fixup(fcx, id,
|
||||
ty::mk_fn(tcx, methods[ix].fty));
|
||||
handled = true;
|
||||
}
|
||||
_ {}
|
||||
}
|
||||
}
|
||||
_ {}
|
||||
}
|
||||
if !handled {
|
||||
|
@ -2408,104 +2312,6 @@ fn get_node(f: spanned<field>) -> field { f.node }
|
|||
}
|
||||
}
|
||||
}
|
||||
ast::expr_anon_obj(ao) {
|
||||
let fields: [ast::anon_obj_field] = [];
|
||||
alt ao.fields { none. { } some(v) { fields = v; } }
|
||||
|
||||
let method_types: [ty::method] = [];
|
||||
{
|
||||
// Outer methods.
|
||||
for m: @ast::method in ao.methods {
|
||||
method_types += [ty_of_method(fcx.ccx.tcx, m_check, m)];
|
||||
}
|
||||
|
||||
// Inner methods.
|
||||
|
||||
// Typecheck 'inner_obj'. If it exists, it had better have object
|
||||
// type.
|
||||
let inner_obj_methods: [ty::method] = [];
|
||||
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 self_infos
|
||||
// stack so that self-calls can be checked within its context
|
||||
// later.
|
||||
bot |= check_expr(fcx, 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 {
|
||||
none. { }
|
||||
some(sty) {
|
||||
alt sty {
|
||||
ty::ty_obj(ms) { inner_obj_methods = ms; }
|
||||
_ {
|
||||
// The user is trying to extend a non-object.
|
||||
tcx.sess.span_fatal
|
||||
(e.span, syntax::print::pprust::expr_to_str(e)
|
||||
+ " does not have object type");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 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.
|
||||
fn filtering_fn(ccx: @crate_ctxt, m: ty::method,
|
||||
outer_obj_methods: [@ast::method]) ->
|
||||
option::t<ty::method> {
|
||||
|
||||
for om: @ast::method in outer_obj_methods {
|
||||
if str::eq(om.ident, m.ident) {
|
||||
// We'd better be overriding with one of the same
|
||||
// type. Check to make sure.
|
||||
let new_type = ty_of_method(ccx.tcx, m_check, om);
|
||||
if !ty::same_method(ccx.tcx, new_type, m) {
|
||||
ccx.tcx.sess.span_fatal
|
||||
(om.span, "attempted to override method "
|
||||
+ m.ident + " with one of a different type");
|
||||
}
|
||||
ret none;
|
||||
}
|
||||
}
|
||||
ret some(m);
|
||||
}
|
||||
|
||||
let f = bind filtering_fn(fcx.ccx, _, ao.methods);
|
||||
inner_obj_methods = vec::filter_map(inner_obj_methods, f);
|
||||
|
||||
method_types += inner_obj_methods;
|
||||
}
|
||||
|
||||
let ot = ty::mk_obj(tcx, ty::sort_methods(method_types));
|
||||
|
||||
write::ty_only_fixup(fcx, id, ot);
|
||||
|
||||
// Write the methods into the node type table. (This happens in
|
||||
// collect::convert for regular objects.)
|
||||
let i = 0u;
|
||||
while i < vec::len(ao.methods) {
|
||||
write::ty_only(tcx, ao.methods[i].id,
|
||||
ty::mk_fn(tcx, method_types[i].fty));
|
||||
i += 1u;
|
||||
}
|
||||
|
||||
fcx.ccx.self_infos +=
|
||||
[self_obj(
|
||||
vec::map(fields, ast_util::obj_field_from_anon_obj_field),
|
||||
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(fcx.ccx.self_infos);
|
||||
}
|
||||
_ { tcx.sess.unimpl("expr type in typeck::check_expr"); }
|
||||
}
|
||||
if bot { write::ty_only_fixup(fcx, expr.id, ty::mk_bot(tcx)); }
|
||||
|
@ -2832,15 +2638,6 @@ fn check_item(ccx: @crate_ctxt, it: @ast::item) {
|
|||
ast::item_res(decl, tps, body, dtor_id, _) {
|
||||
check_fn(ccx, ast::proto_bare, decl, body, dtor_id, none);
|
||||
}
|
||||
ast::item_obj(ob, tps, _) {
|
||||
// We're entering an object, so gather up the info we need.
|
||||
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(ccx.self_infos);
|
||||
}
|
||||
ast::item_impl(tps, _, ty, ms) {
|
||||
ccx.self_infos += [self_impl(ast_ty_to_ty(ccx.tcx, m_check, ty))];
|
||||
for m in ms { check_method(ccx, m); }
|
||||
|
|
|
@ -18,7 +18,6 @@ mod middle {
|
|||
mod trans_build;
|
||||
mod trans;
|
||||
mod trans_alt;
|
||||
mod trans_objects;
|
||||
mod trans_uniq;
|
||||
mod trans_closure;
|
||||
mod trans_vec;
|
||||
|
|
|
@ -34,7 +34,6 @@
|
|||
|
||||
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);
|
||||
|
@ -234,7 +233,6 @@
|
|||
/* FIXME Would be nice if expr_check desugared
|
||||
to expr_if_check. */
|
||||
expr_if_check(@expr, blk, option::t<@expr>);
|
||||
expr_anon_obj(anon_obj);
|
||||
expr_mac(mac);
|
||||
}
|
||||
|
||||
|
@ -318,7 +316,6 @@
|
|||
ty_chan(@ty);
|
||||
ty_rec([ty_field]);
|
||||
ty_fn(proto, fn_decl);
|
||||
ty_obj([ty_method]);
|
||||
ty_tup([@ty]);
|
||||
ty_path(@path, node_id);
|
||||
ty_type;
|
||||
|
@ -389,19 +386,6 @@
|
|||
type method = {ident: ident, tps: [ty_param], decl: fn_decl, body: blk,
|
||||
id: node_id, span: span};
|
||||
|
||||
type obj_field = {mut: mutability, ty: @ty, ident: ident, id: node_id};
|
||||
type anon_obj_field =
|
||||
{mut: mutability, ty: @ty, expr: @expr, ident: ident, id: node_id};
|
||||
|
||||
type _obj = {fields: [obj_field], methods: [@method]};
|
||||
|
||||
type anon_obj =
|
||||
// New fields and methods, if they exist.
|
||||
// inner_obj: the original object being extended, if it exists.
|
||||
{fields: option::t<[anon_obj_field]>,
|
||||
methods: [@method],
|
||||
inner_obj: option::t<@expr>};
|
||||
|
||||
type _mod = {view_items: [@view_item], items: [@item]};
|
||||
|
||||
tag native_abi {
|
||||
|
@ -439,9 +423,6 @@
|
|||
view_item_export([ident], node_id);
|
||||
}
|
||||
|
||||
type obj_def_ids = {ty: node_id, ctor: node_id};
|
||||
|
||||
|
||||
// Meta-data associated with an item
|
||||
type attribute = spanned<attribute_>;
|
||||
|
||||
|
@ -453,8 +434,8 @@
|
|||
|
||||
type attribute_ = {style: attr_style, value: meta_item};
|
||||
|
||||
type item = // For objs and resources, this is the type def_id
|
||||
{ident: ident, attrs: [attribute], id: node_id, node: item_, span: span};
|
||||
type item = {ident: ident, attrs: [attribute],
|
||||
id: node_id, node: item_, span: span};
|
||||
|
||||
tag item_ {
|
||||
item_const(@ty, @expr);
|
||||
|
@ -463,7 +444,6 @@
|
|||
item_native_mod(native_mod);
|
||||
item_ty(@ty, [ty_param]);
|
||||
item_tag([variant], [ty_param]);
|
||||
item_obj(_obj, [ty_param], /* constructor id */node_id);
|
||||
item_res(fn_decl /* dtor */, [ty_param], blk,
|
||||
node_id /* dtor id */, node_id /* ctor id */);
|
||||
item_iface([ty_param], [ty_method]);
|
||||
|
|
|
@ -25,7 +25,7 @@ fn variant_def_ids(d: def) -> {tg: def_id, var: def_id} {
|
|||
|
||||
fn def_id_of_def(d: def) -> def_id {
|
||||
alt d {
|
||||
def_fn(id, _) | def_obj_field(id, _) | def_self(id) | def_mod(id) |
|
||||
def_fn(id, _) | def_self(id) | def_mod(id) |
|
||||
def_native_mod(id) | def_const(id) | def_arg(id, _) | def_local(id, _) |
|
||||
def_variant(_, id) | def_ty(id) | def_ty_param(id, _) |
|
||||
def_binding(id) | def_use(id) | def_native_ty(id) |
|
||||
|
@ -215,10 +215,6 @@ fn default_block(stmts1: [@stmt], expr1: option::t<@expr>, id1: node_id) ->
|
|||
{view_items: [], stmts: stmts1, expr: expr1, id: id1, rules: default_blk}
|
||||
}
|
||||
|
||||
fn obj_field_from_anon_obj_field(f: anon_obj_field) -> obj_field {
|
||||
ret {mut: f.mut, ty: f.ty, ident: f.ident, id: f.id};
|
||||
}
|
||||
|
||||
// This is a convenience function to transfor ternary expressions to if
|
||||
// expressions so that they can be treated the same
|
||||
fn ternary_to_if(e: @expr) -> @expr {
|
||||
|
|
|
@ -95,7 +95,6 @@ fn nf_crate_directive_dummy(&&_c: @crate_directive) -> @crate_directive {
|
|||
fn nf_variant_dummy(_v: variant) -> variant { fail; }
|
||||
fn nf_ident_dummy(&&_i: ident) -> ident { fail; }
|
||||
fn nf_path_dummy(&&_p: @path) -> @path { fail; }
|
||||
fn nf_obj_field_dummy(_o: obj_field) -> obj_field { fail; }
|
||||
fn nf_local_dummy(&&_o: @local) -> @local { fail; }
|
||||
|
||||
/* some little folds that probably aren't useful to have in ast_fold itself*/
|
||||
|
@ -216,14 +215,6 @@ fn noop_fold_item(&&i: @item, fld: ast_fold) -> @item {
|
|||
}
|
||||
|
||||
fn noop_fold_item_underscore(i: item_, fld: ast_fold) -> item_ {
|
||||
fn fold_obj_field_(of: obj_field, fld: ast_fold) -> obj_field {
|
||||
ret {mut: of.mut,
|
||||
ty: fld.fold_ty(of.ty),
|
||||
ident: fld.fold_ident(of.ident),
|
||||
id: of.id};
|
||||
}
|
||||
let fold_obj_field = bind fold_obj_field_(_, fld);
|
||||
|
||||
ret alt i {
|
||||
item_const(t, e) { item_const(fld.fold_ty(t), fld.fold_expr(e)) }
|
||||
item_fn(decl, typms, body) {
|
||||
|
@ -236,11 +227,6 @@ fn fold_obj_field_(of: obj_field, fld: ast_fold) -> obj_field {
|
|||
item_tag(variants, typms) {
|
||||
item_tag(vec::map(variants, fld.fold_variant), typms)
|
||||
}
|
||||
item_obj(o, typms, d) {
|
||||
item_obj({fields: vec::map(o.fields, fold_obj_field),
|
||||
methods: vec::map(o.methods, fld.fold_method)},
|
||||
typms, d)
|
||||
}
|
||||
item_impl(tps, ifce, ty, methods) {
|
||||
item_impl(tps, option::map(ifce, fld.fold_ty), fld.fold_ty(ty),
|
||||
vec::map(methods, fld.fold_method))
|
||||
|
@ -327,29 +313,6 @@ fn fold_field_(field: field, fld: ast_fold) -> field {
|
|||
span: field.span};
|
||||
}
|
||||
let fold_field = bind fold_field_(_, fld);
|
||||
fn fold_anon_obj_(ao: anon_obj, fld: ast_fold) -> anon_obj {
|
||||
fn fold_anon_obj_field_(aof: anon_obj_field, fld: ast_fold) ->
|
||||
anon_obj_field {
|
||||
ret {mut: aof.mut,
|
||||
ty: fld.fold_ty(aof.ty),
|
||||
expr: fld.fold_expr(aof.expr),
|
||||
ident: fld.fold_ident(aof.ident),
|
||||
id: aof.id};
|
||||
}
|
||||
let fold_anon_obj_field = bind fold_anon_obj_field_(_, fld);
|
||||
|
||||
|
||||
ret {fields:
|
||||
alt ao.fields {
|
||||
option::none. { ao.fields }
|
||||
option::some(v) {
|
||||
option::some(vec::map(v, fold_anon_obj_field))
|
||||
}
|
||||
},
|
||||
methods: vec::map(ao.methods, fld.fold_method),
|
||||
inner_obj: option::map(ao.inner_obj, fld.fold_expr)}
|
||||
}
|
||||
let fold_anon_obj = bind fold_anon_obj_(_, fld);
|
||||
|
||||
let fold_mac = bind fold_mac_(_, fld);
|
||||
|
||||
|
@ -439,7 +402,6 @@ fn fold_anon_obj_field_(aof: anon_obj_field, fld: ast_fold) ->
|
|||
expr_if_check(fld.fold_expr(cond), fld.fold_block(tr),
|
||||
option::map(fl, fld.fold_expr))
|
||||
}
|
||||
expr_anon_obj(ao) { expr_anon_obj(fold_anon_obj(ao)) }
|
||||
expr_mac(mac) { expr_mac(fold_mac(mac)) }
|
||||
}
|
||||
}
|
||||
|
|
|
@ -139,8 +139,7 @@ fn bad_expr_word_table() -> hashmap<str, ()> {
|
|||
"cont", "ret", "be", "fail", "type", "resource", "check",
|
||||
"assert", "claim", "native", "fn", "pure",
|
||||
"unsafe", "block", "import", "export", "let", "const",
|
||||
"log", "tag", "obj", "copy", "sendfn", "impl", "iface",
|
||||
"enum"] {
|
||||
"log", "copy", "sendfn", "impl", "iface", "enum"] {
|
||||
words.insert(word, ());
|
||||
}
|
||||
words
|
||||
|
@ -260,12 +259,12 @@ fn parse_fn_input_ty(p: parser) -> ast::arg {
|
|||
constraints: constrs});
|
||||
}
|
||||
|
||||
fn parse_ty_methods(p: parser, allow_tps: bool) -> [ast::ty_method] {
|
||||
fn parse_ty_methods(p: parser) -> [ast::ty_method] {
|
||||
parse_seq(token::LBRACE, token::RBRACE, seq_sep_none(), {|p|
|
||||
let flo = p.span.lo;
|
||||
expect_word(p, "fn");
|
||||
let ident = parse_value_ident(p);
|
||||
let tps = allow_tps ? parse_ty_params(p) : [];
|
||||
let tps = parse_ty_params(p);
|
||||
let f = parse_ty_fn(ast::proto_bare, p), fhi = p.last_span.hi;
|
||||
expect(p, token::SEMI);
|
||||
alt f {
|
||||
|
@ -490,8 +489,6 @@ fn parse_ty(p: parser, colons_before_params: bool) -> @ast::ty {
|
|||
} else if eat_word(p, "sendfn") {
|
||||
//(breaks prettyprinting!) p.warn("sendfn is deprecated, use fn~");
|
||||
t = parse_ty_fn(ast::proto_uniq, p);
|
||||
} else if eat_word(p, "obj") {
|
||||
t = ast::ty_obj(parse_ty_methods(p, false));
|
||||
} else if p.token == token::MOD_SEP || is_ident(p.token) {
|
||||
let path = parse_path(p);
|
||||
t = ast::ty_path(path, p.get_id());
|
||||
|
@ -825,35 +822,6 @@ fn parse_bottom_expr(p: parser) -> pexpr {
|
|||
} else if p.token == token::ELLIPSIS {
|
||||
p.bump();
|
||||
ret pexpr(mk_mac_expr(p, lo, p.span.hi, ast::mac_ellipsis));
|
||||
} else if eat_word(p, "obj") {
|
||||
// Anonymous object
|
||||
|
||||
// Only make people type () if they're actually adding new fields
|
||||
let fields: option::t<[ast::anon_obj_field]> = none;
|
||||
if p.token == token::LPAREN {
|
||||
p.bump();
|
||||
fields =
|
||||
some(parse_seq_to_end(token::RPAREN, seq_sep(token::COMMA),
|
||||
parse_anon_obj_field, p));
|
||||
}
|
||||
let meths: [@ast::method] = [];
|
||||
let inner_obj: option::t<@ast::expr> = none;
|
||||
expect(p, token::LBRACE);
|
||||
while p.token != token::RBRACE {
|
||||
if eat_word(p, "with") {
|
||||
inner_obj = some(parse_expr(p));
|
||||
} else { meths += [parse_method(p, false)]; }
|
||||
}
|
||||
hi = p.span.hi;
|
||||
expect(p, token::RBRACE);
|
||||
// fields and methods may be *additional* or *overriding* fields
|
||||
// and methods if there's a inner_obj, or they may be the *only*
|
||||
// fields and methods if there's no inner_obj.
|
||||
|
||||
// We don't need to pull ".node" out of fields because it's not a
|
||||
// "spanned".
|
||||
let ob = {fields: fields, methods: meths, inner_obj: inner_obj};
|
||||
ex = ast::expr_anon_obj(ob);
|
||||
} else if eat_word(p, "bind") {
|
||||
let e = parse_expr_res(p, RESTRICT_NO_CALL_EXPRS);
|
||||
fn parse_expr_opt(p: parser) -> option::t<@ast::expr> {
|
||||
|
@ -1781,55 +1749,20 @@ fn parse_item_fn(p: parser, purity: ast::purity,
|
|||
ast::item_fn(decl, t.tps, body), attrs);
|
||||
}
|
||||
|
||||
fn parse_obj_field(p: parser) -> ast::obj_field {
|
||||
let mut = parse_mutability(p);
|
||||
let ident = parse_value_ident(p);
|
||||
expect(p, token::COLON);
|
||||
let ty = parse_ty(p, false);
|
||||
ret {mut: mut, ty: ty, ident: ident, id: p.get_id()};
|
||||
}
|
||||
|
||||
fn parse_anon_obj_field(p: parser) -> ast::anon_obj_field {
|
||||
let mut = parse_mutability(p);
|
||||
let ident = parse_value_ident(p);
|
||||
expect(p, token::COLON);
|
||||
let ty = parse_ty(p, false);
|
||||
expect(p, token::EQ);
|
||||
let expr = parse_expr(p);
|
||||
ret {mut: mut, ty: ty, expr: expr, ident: ident, id: p.get_id()};
|
||||
}
|
||||
|
||||
fn parse_method(p: parser, allow_tps: bool) -> @ast::method {
|
||||
fn parse_method(p: parser) -> @ast::method {
|
||||
let lo = p.span.lo;
|
||||
expect_word(p, "fn");
|
||||
let ident = parse_value_ident(p);
|
||||
let tps = allow_tps ? parse_ty_params(p) : [];
|
||||
let tps = parse_ty_params(p);
|
||||
let decl = parse_fn_decl(p, ast::impure_fn);
|
||||
let body = parse_block(p);
|
||||
@{ident: ident, tps: tps, decl: decl, body: body,
|
||||
id: p.get_id(), span: ast_util::mk_sp(lo, body.span.hi)}
|
||||
}
|
||||
|
||||
fn parse_item_obj(p: parser, attrs: [ast::attribute]) -> @ast::item {
|
||||
let lo = p.last_span.lo;
|
||||
let ident = parse_value_ident(p);
|
||||
let ty_params = parse_ty_params(p);
|
||||
let fields: ast::spanned<[ast::obj_field]> =
|
||||
parse_seq(token::LPAREN, token::RPAREN, seq_sep(token::COMMA),
|
||||
parse_obj_field, p);
|
||||
let meths: [@ast::method] = [];
|
||||
expect(p, token::LBRACE);
|
||||
while p.token != token::RBRACE { meths += [parse_method(p, false)]; }
|
||||
let hi = p.span.hi;
|
||||
expect(p, token::RBRACE);
|
||||
let ob: ast::_obj = {fields: fields.node, methods: meths};
|
||||
ret mk_item(p, lo, hi, ident, ast::item_obj(ob, ty_params, p.get_id()),
|
||||
attrs);
|
||||
}
|
||||
|
||||
fn parse_item_iface(p: parser, attrs: [ast::attribute]) -> @ast::item {
|
||||
let lo = p.last_span.lo, ident = parse_ident(p),
|
||||
tps = parse_ty_params(p), meths = parse_ty_methods(p, true);
|
||||
tps = parse_ty_params(p), meths = parse_ty_methods(p);
|
||||
ret mk_item(p, lo, p.last_span.hi, ident,
|
||||
ast::item_iface(tps, meths), attrs);
|
||||
}
|
||||
|
@ -1861,7 +1794,7 @@ fn wrap_path(p: parser, pt: @ast::path) -> @ast::ty {
|
|||
expect_word(p, "for");
|
||||
let ty = parse_ty(p, false), meths = [];
|
||||
expect(p, token::LBRACE);
|
||||
while !eat(p, token::RBRACE) { meths += [parse_method(p, true)]; }
|
||||
while !eat(p, token::RBRACE) { meths += [parse_method(p)]; }
|
||||
ret mk_item(p, lo, p.last_span.hi, ident,
|
||||
ast::item_impl(tps, ifce, ty, meths), attrs);
|
||||
}
|
||||
|
@ -2169,9 +2102,6 @@ fn parse_item(p: parser, attrs: [ast::attribute]) -> option::t<@ast::item> {
|
|||
ret some(parse_item_type(p, attrs));
|
||||
} else if eat_word(p, "tag") || eat_word(p, "enum") {
|
||||
ret some(parse_item_tag(p, attrs));
|
||||
} else if is_word(p, "obj") && p.look_ahead(1u) != token::LPAREN {
|
||||
p.bump();
|
||||
ret some(parse_item_obj(p, attrs));
|
||||
} else if eat_word(p, "iface") {
|
||||
ret some(parse_item_iface(p, attrs));
|
||||
} else if eat_word(p, "impl") {
|
||||
|
|
|
@ -306,12 +306,6 @@ fn print_field(s: ps, f: ast::ty_field) {
|
|||
ast::ty_fn(proto, d) {
|
||||
print_ty_fn(s, proto, d, none, none);
|
||||
}
|
||||
ast::ty_obj(methods) {
|
||||
head(s, "obj");
|
||||
bopen(s);
|
||||
for m in methods { print_ty_method(s, m); }
|
||||
bclose(s, ty.span);
|
||||
}
|
||||
ast::ty_path(path, _) { print_path(s, path, false); }
|
||||
ast::ty_type. { word(s.s, "type"); }
|
||||
ast::ty_constr(t, cs) {
|
||||
|
@ -438,32 +432,6 @@ fn print_variant_arg(s: ps, arg: ast::variant_arg) {
|
|||
bclose(s, item.span);
|
||||
}
|
||||
}
|
||||
ast::item_obj(_obj, params, _) {
|
||||
head(s, "obj");
|
||||
word(s.s, item.ident);
|
||||
print_type_params(s, params);
|
||||
popen(s);
|
||||
fn print_field(s: ps, field: ast::obj_field) {
|
||||
ibox(s, indent_unit);
|
||||
print_mutability(s, field.mut);
|
||||
word_space(s, field.ident + ":");
|
||||
print_type(s, field.ty);
|
||||
end(s);
|
||||
}
|
||||
fn get_span(f: ast::obj_field) -> codemap::span { ret f.ty.span; }
|
||||
commasep_cmnt(s, consistent, _obj.fields, print_field, get_span);
|
||||
pclose(s);
|
||||
space(s.s);
|
||||
bopen(s);
|
||||
for meth: @ast::method in _obj.methods {
|
||||
hardbreak_if_not_bol(s);
|
||||
maybe_print_comment(s, meth.span.lo);
|
||||
print_fn(s, meth.decl, meth.ident, meth.tps);
|
||||
word(s.s, " ");
|
||||
print_block(s, meth.body);
|
||||
}
|
||||
bclose(s, item.span);
|
||||
}
|
||||
ast::item_impl(tps, ifce, ty, methods) {
|
||||
head(s, "impl");
|
||||
word(s.s, item.ident);
|
||||
|
@ -972,50 +940,6 @@ fn print_opt(s: ps, expr: option::t<@ast::expr>) {
|
|||
pclose(s);
|
||||
}
|
||||
ast::expr_mac(m) { print_mac(s, m); }
|
||||
ast::expr_anon_obj(anon_obj) {
|
||||
head(s, "obj");
|
||||
|
||||
// Fields
|
||||
popen(s);
|
||||
fn print_field(s: ps, field: ast::anon_obj_field) {
|
||||
ibox(s, indent_unit);
|
||||
print_mutability(s, field.mut);
|
||||
word_space(s, field.ident + ":");
|
||||
print_type(s, field.ty);
|
||||
space(s.s);
|
||||
word_space(s, "=");
|
||||
print_expr(s, field.expr);
|
||||
end(s);
|
||||
}
|
||||
fn get_span(f: ast::anon_obj_field) -> codemap::span {
|
||||
ret f.ty.span;
|
||||
}
|
||||
alt anon_obj.fields {
|
||||
none. { }
|
||||
some(fields) {
|
||||
commasep_cmnt(s, consistent, fields, print_field, get_span);
|
||||
}
|
||||
}
|
||||
pclose(s);
|
||||
space(s.s);
|
||||
bopen(s);
|
||||
|
||||
// Methods
|
||||
for meth: @ast::method in anon_obj.methods {
|
||||
hardbreak_if_not_bol(s);
|
||||
maybe_print_comment(s, meth.span.lo);
|
||||
print_fn(s, meth.decl, meth.ident, meth.tps);
|
||||
word(s.s, " ");
|
||||
print_block(s, meth.body);
|
||||
}
|
||||
|
||||
// With object
|
||||
alt anon_obj.inner_obj {
|
||||
none. { }
|
||||
some(e) { space(s.s); word_space(s, "with"); print_expr(s, e); }
|
||||
}
|
||||
bclose(s, expr.span);
|
||||
}
|
||||
}
|
||||
s.ann.post(ann_node);
|
||||
end(s);
|
||||
|
|
|
@ -126,14 +126,6 @@ fn visit_item<E>(i: @item, e: E, v: vt<E>) {
|
|||
for va: variant_arg in vr.node.args { v.visit_ty(va.ty, e, v); }
|
||||
}
|
||||
}
|
||||
item_obj(ob, tps, _) {
|
||||
v.visit_ty_params(tps, e, v);
|
||||
for f: obj_field in ob.fields { v.visit_ty(f.ty, e, v); }
|
||||
for m: @method in ob.methods {
|
||||
v.visit_fn(fk_method(m.ident, m.tps), m.decl, m.body, m.span,
|
||||
m.id, e, v);
|
||||
}
|
||||
}
|
||||
item_impl(tps, ifce, ty, methods) {
|
||||
v.visit_ty_params(tps, e, v);
|
||||
alt ifce { some(ty) { v.visit_ty(ty, e, v); } _ {} }
|
||||
|
@ -172,12 +164,6 @@ fn visit_ty<E>(t: @ty, e: E, v: vt<E>) {
|
|||
}
|
||||
v.visit_ty(decl.output, e, v);
|
||||
}
|
||||
ty_obj(tmeths) {
|
||||
for m: ty_method in tmeths {
|
||||
for a in m.decl.inputs { v.visit_ty(a.ty, e, v); }
|
||||
v.visit_ty(m.decl.output, e, v);
|
||||
}
|
||||
}
|
||||
ty_path(p, _) { visit_path(p, e, v); }
|
||||
ty_type. {/* no-op */ }
|
||||
ty_constr(t, cs) {
|
||||
|
@ -370,25 +356,6 @@ fn visit_expr<E>(ex: @expr, e: E, v: vt<E>) {
|
|||
}
|
||||
expr_check(_, x) { v.visit_expr(x, e, v); }
|
||||
expr_assert(x) { v.visit_expr(x, e, v); }
|
||||
expr_anon_obj(anon_obj) {
|
||||
alt anon_obj.fields {
|
||||
none. { }
|
||||
some(fields) {
|
||||
for f: anon_obj_field in fields {
|
||||
v.visit_ty(f.ty, e, v);
|
||||
v.visit_expr(f.expr, e, v);
|
||||
}
|
||||
}
|
||||
}
|
||||
alt anon_obj.inner_obj {
|
||||
none. { }
|
||||
some(ex) { v.visit_expr(ex, e, v); }
|
||||
}
|
||||
for m: @method in anon_obj.methods {
|
||||
v.visit_fn(fk_method(m.ident, m.tps), m.decl, m.body, m.span,
|
||||
m.id, e, v);
|
||||
}
|
||||
}
|
||||
expr_mac(mac) { visit_mac(mac, e, v); }
|
||||
}
|
||||
}
|
||||
|
|
|
@ -112,11 +112,6 @@ fn mt_to_str(cx: ctxt, m: mt) -> str {
|
|||
fn_to_str(cx, ast::proto_bare, none, inputs, output,
|
||||
ast::return_val, [])
|
||||
}
|
||||
ty_obj(meths) {
|
||||
let strs = [];
|
||||
for m: method in meths { strs += [method_to_str(cx, m)]; }
|
||||
"obj {\n\t" + str::connect(strs, "\n\t") + "\n}"
|
||||
}
|
||||
ty_var(v) { "<T" + int::str(v) + ">" }
|
||||
ty_param(id, _) {
|
||||
"'" + str::unsafe_from_bytes([('a' as u8) + (id as u8)])
|
||||
|
|
Loading…
Reference in a new issue