Obj system? What obj system?

Removes the obj system from the compiler.

Closes #1484
This commit is contained in:
Marijn Haverbeke 2012-01-13 10:58:31 +01:00
parent eb07fa4d3b
commit 24102d50ad
30 changed files with 139 additions and 2020 deletions

View file

@ -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;

View file

@ -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));

View file

@ -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);

View file

@ -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));

View file

@ -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};
}

View file

@ -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);

View file

@ -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)

View file

@ -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";

View file

@ -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);

View file

@ -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);

View file

@ -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);
}

View file

@ -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;
}

View file

@ -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,

View file

@ -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);

View file

@ -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()])))

View file

@ -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]));

View file

@ -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:
//

View file

@ -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)));

View file

@ -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)); }
}
}
}
}

View file

@ -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); }
}
}
}
}

View file

@ -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 }

View file

@ -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); }

View file

@ -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;

View file

@ -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]);

View file

@ -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 {

View file

@ -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)) }
}
}

View file

@ -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") {

View file

@ -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);

View file

@ -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); }
}
}

View file

@ -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)])