]> git.lizzy.rs Git - rust.git/commitdiff
First barely-working version of casting to iface
authorMarijn Haverbeke <marijnh@gmail.com>
Sat, 7 Jan 2012 21:44:14 +0000 (22:44 +0100)
committerMarijn Haverbeke <marijnh@gmail.com>
Sun, 8 Jan 2012 22:07:15 +0000 (23:07 +0100)
Issue #1437

src/comp/middle/shape.rs
src/comp/middle/trans.rs
src/comp/middle/trans_common.rs
src/comp/middle/trans_impl.rs
src/comp/middle/ty.rs
src/comp/middle/typeck.rs

index 43afb88361bc761dcab6f2787f8828cb77f65f81..ff760230d937c654af138d21f4a418e71822f69b 100644 (file)
@@ -52,6 +52,7 @@
 const shape_var: u8 = 21u8;
 const shape_uniq: u8 = 22u8;
 const shape_opaque_closure_ptr: u8 = 23u8; // the closure itself.
+const shape_iface: u8 = 24u8;
 
 // FIXME: This is a bad API in trans_common.
 fn C_u8(n: u8) -> ValueRef { ret trans_common::C_u8(n as uint); }
@@ -387,6 +388,7 @@ fn shape_of(ccx: @crate_ctxt, t: ty::t, ty_param_map: [uint],
       }
       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);
         let ri = {did: did, t: subt};
index f6539e4f0f3e3bb7231681676f897dca008c00d7..108f2c5b1c57da884f55e4b185d28b9b0a5f71f2 100644 (file)
@@ -178,7 +178,8 @@ 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(meths) { cx.rust_object_type }
+      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);
         check non_ty_var(cx, sub1);
@@ -483,7 +484,9 @@ fn mk_obstack_token(ccx: @crate_ctxt, fcx: @fn_ctxt) ->
 fn simplify_type(ccx: @crate_ctxt, typ: ty::t) -> ty::t {
     fn simplifier(ccx: @crate_ctxt, typ: ty::t) -> ty::t {
         alt ty::struct(ccx.tcx, typ) {
-          ty::ty_box(_) { ret ty::mk_imm_box(ccx.tcx, ty::mk_nil(ccx.tcx)); }
+          ty::ty_box(_) | ty::ty_iface(_, _) {
+            ret ty::mk_imm_box(ccx.tcx, ty::mk_nil(ccx.tcx));
+          }
           ty::ty_uniq(_) {
             ret ty::mk_imm_uniq(ccx.tcx, ty::mk_nil(ccx.tcx));
           }
@@ -1386,9 +1389,10 @@ 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_obj(_) | ty::ty_iface(_, _) {
         // Call through the obj'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 b = PointerCast(bcx, v, llbox_ty);
@@ -1425,13 +1429,14 @@ fn make_drop_glue(bcx: @block_ctxt, v0: ValueRef, t: ty::t) {
     let ccx = bcx_ccx(bcx);
     let bcx =
         alt ty::struct(ccx.tcx, t) {
-          ty::ty_box(_) { decr_refcnt_maybe_free(bcx, Load(bcx, v0), t) }
+          ty::ty_box(_) | ty::ty_iface(_, _) {
+              decr_refcnt_maybe_free(bcx, Load(bcx, v0), 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]);
+            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) {
@@ -1935,22 +1940,22 @@ fn drop_ty(cx: @block_ctxt, v: ValueRef, t: ty::t) -> @block_ctxt {
 
 fn drop_ty_immediate(bcx: @block_ctxt, v: ValueRef, t: ty::t) -> @block_ctxt {
     alt ty::struct(bcx_tcx(bcx), t) {
-      ty::ty_uniq(_) | ty::ty_vec(_) | ty::ty_str. {
-        ret free_ty(bcx, v, t);
-      }
-      ty::ty_box(_) { ret decr_refcnt_maybe_free(bcx, v, t); }
+      ty::ty_uniq(_) | ty::ty_vec(_) | ty::ty_str. { free_ty(bcx, v, t) }
+      ty::ty_box(_) | ty::ty_iface(_, _) { decr_refcnt_maybe_free(bcx, v, t) }
     }
 }
 
 fn take_ty_immediate(bcx: @block_ctxt, v: ValueRef, t: ty::t) -> result {
     alt ty::struct(bcx_tcx(bcx), t) {
-      ty::ty_box(_) { ret rslt(incr_refcnt_of_boxed(bcx, v), v); }
+      ty::ty_box(_) | ty::ty_iface(_, _) {
+        rslt(incr_refcnt_of_boxed(bcx, v), v)
+      }
       ty::ty_uniq(_) {
         check trans_uniq::type_is_unique_box(bcx, t);
-        ret trans_uniq::duplicate(bcx, v, t);
+        trans_uniq::duplicate(bcx, v, t)
       }
-      ty::ty_str. | ty::ty_vec(_) { ret tvec::duplicate(bcx, v, t); }
-      _ { ret rslt(bcx, v); }
+      ty::ty_str. | ty::ty_vec(_) { tvec::duplicate(bcx, v, t) }
+      _ { rslt(bcx, v) }
     }
 }
 
@@ -2873,9 +2878,12 @@ fn trans_callee(bcx: @block_ctxt, e: @ast::expr) -> lval_maybe_callee {
                 ret trans_impl::trans_static_callee(bcx, e, base, did);
               }
               some(typeck::method_param(iid, off, p, b)) {
-                ret trans_impl::trans_dict_callee(
+                ret trans_impl::trans_param_callee(
                     bcx, e, base, iid, off, p, b);
               }
+              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,
@@ -3001,10 +3009,14 @@ fn float_cast(bcx: @block_ctxt, lldsttype: TypeRef, llsrctype: TypeRef,
 fn trans_cast(cx: @block_ctxt, e: @ast::expr, id: ast::node_id,
               dest: dest) -> @block_ctxt {
     let ccx = bcx_ccx(cx);
+    let t_out = node_id_type(ccx, id);
+    alt ty::struct(ccx.tcx, t_out) {
+      ty::ty_iface(_, _) { ret trans_impl::trans_cast(cx, e, id, dest); }
+      _ {}
+    }
     let e_res = trans_temp_expr(cx, e);
     let ll_t_in = val_ty(e_res.val);
     let t_in = ty::expr_ty(ccx.tcx, e);
-    let t_out = node_id_type(ccx, id);
     // Check should be avoidable because it's a cast.
     // FIXME: Constrain types so as to avoid this check.
     check (type_has_static_size(ccx, t_out));
index 8b99efc337b133e09fdbf67f1e33d9b738b83238..72803fd309a477a63e3f9fb7c2dcd0079642cac0 100644 (file)
@@ -754,6 +754,11 @@ fn T_obj(cx: @crate_ctxt, n_captured_tydescs: uint) -> TypeRef {
 
 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()])))
+}
+
 fn T_opaque_port_ptr() -> TypeRef { ret T_ptr(T_i8()); }
 
 fn T_opaque_chan_ptr() -> TypeRef { ret T_ptr(T_i8()); }
index 284cef0f289d33ef593f23fbf5c1eddce2327728..f4d9e58e427ec459098929b00db7274ff36c2b77 100644 (file)
@@ -4,7 +4,7 @@
 import option::{some, none};
 import syntax::{ast, ast_util};
 import metadata::csearch;
-import back::link;
+import back::{link, abi};
 import lib::llvm::llvm;
 import llvm::{ValueRef, TypeRef, LLVMGetParam};
 
@@ -61,21 +61,20 @@ fn trans_self_arg(bcx: @block_ctxt, base: @ast::expr) -> result {
     rslt(bcx, PointerCast(bcx, val, T_opaque_cbox_ptr(bcx_ccx(bcx))))
 }
 
+// Method callee where the method is statically known
 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)}
 }
 
-fn trans_dict_callee(bcx: @block_ctxt, e: @ast::expr, base: @ast::expr,
-                     iface_id: ast::def_id, n_method: uint,
-                     n_param: uint, n_bound: uint) -> lval_maybe_callee {
-    let tcx = bcx_tcx(bcx);
-    let {bcx, val} = trans_self_arg(bcx, base);
-    let dict = option::get(bcx.fcx.lltyparams[n_param].dicts)[n_bound];
+fn trans_vtable_callee(bcx: @block_ctxt, self: ValueRef, dict: ValueRef,
+                       fld_expr: @ast::expr, iface_id: ast::def_id,
+                       n_method: uint) -> lval_maybe_callee {
+    let bcx = bcx, ccx = bcx_ccx(bcx), tcx = ccx.tcx;
     let method = ty::iface_methods(tcx, iface_id)[n_method];
-    let fty = ty::expr_ty(tcx, e);
-    let bare_fn_ty = type_of_fn_from_ty(bcx_ccx(bcx), ast_util::dummy_sp(),
+    let fty = ty::expr_ty(tcx, fld_expr);
+    let bare_fn_ty = type_of_fn_from_ty(ccx, ast_util::dummy_sp(),
                                         fty, *method.tps);
     let {inputs: bare_inputs, output} = llfn_arg_tys(bare_fn_ty);
     let fn_ty = T_fn([val_ty(dict)] + bare_inputs, output);
@@ -85,9 +84,8 @@ fn trans_dict_callee(bcx: @block_ctxt, e: @ast::expr, base: @ast::expr,
     let generic = none;
     if vec::len(*method.tps) > 0u {
         let tydescs = [], tis = [];
-        let tptys = ty::node_id_to_type_params(tcx, e.id);
+        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)) {
-            // TODO: Doesn't always escape.
             let ti = none;
             let td = get_tydesc(bcx, t, true, tps_normal, ti).result;
             tis += [ti];
@@ -98,13 +96,40 @@ fn trans_dict_callee(bcx: @block_ctxt, e: @ast::expr, base: @ast::expr,
                         static_tis: tis,
                         tydescs: tydescs,
                         param_bounds: method.tps,
-                        origins: bcx_ccx(bcx).dict_map.find(e.id)});
+                        origins: bcx_ccx(bcx).dict_map.find(fld_expr.id)});
     }
     {bcx: bcx, val: mptr, kind: owned,
-     env: dict_env(dict, val),
+     env: dict_env(dict, self),
      generic: generic}
 }
 
+// Method callee where the dict comes from a type param
+fn trans_param_callee(bcx: @block_ctxt, fld_expr: @ast::expr,
+                      base: @ast::expr, iface_id: ast::def_id, n_method: uint,
+                      n_param: uint, n_bound: uint) -> lval_maybe_callee {
+    let {bcx, val} = trans_self_arg(bcx, base);
+    let dict = option::get(bcx.fcx.lltyparams[n_param].dicts)[n_bound];
+    trans_vtable_callee(bcx, val, dict, fld_expr, iface_id, n_method)
+}
+
+// Method callee where the dict comes from a boxed iface
+fn trans_iface_callee(bcx: @block_ctxt, fld_expr: @ast::expr, base: @ast::expr,
+                      n_method: uint)
+    -> lval_maybe_callee {
+    let tcx = bcx_tcx(bcx);
+    let {bcx, val} = trans_temp_expr(bcx, base);
+    let box_body = GEPi(bcx, val, [0, abi::box_rc_field_body]);
+    let dict = Load(bcx, PointerCast(bcx, GEPi(bcx, box_body, [0, 1]),
+                                     T_ptr(T_ptr(T_dict()))));
+    // FIXME[impl] I doubt this is alignment-safe
+    let self = PointerCast(bcx, GEPi(bcx, box_body, [0, 2]),
+                           T_opaque_cbox_ptr(bcx_ccx(bcx)));
+    let iface_id = alt ty::struct(tcx, ty::expr_ty(tcx, base)) {
+        ty::ty_iface(did, _) { did }
+    };
+    trans_vtable_callee(bcx, self, dict, fld_expr, iface_id, n_method)
+}
+
 fn llfn_arg_tys(ft: TypeRef) -> {inputs: [TypeRef], output: TypeRef} {
     let out_ty = llvm::LLVMGetReturnType(ft);
     let n_args = llvm::LLVMCountParamTypes(ft);
@@ -274,3 +299,22 @@ fn get_dict_ptrs(bcx: @block_ctxt, origin: typeck::dict_origin)
       }
     }
 }
+
+fn trans_cast(bcx: @block_ctxt, val: @ast::expr, id: ast::node_id, dest: dest)
+    -> @block_ctxt {
+    let ccx = bcx_ccx(bcx), tcx = ccx.tcx;
+    let val_ty = ty::expr_ty(tcx, val);
+    let {bcx, val: dict} = get_dict(bcx, ccx.dict_map.get(id)[0]);
+    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;
+    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]));
+    Store(bcx, PointerCast(bcx, dict, T_ptr(ccx.tydesc_type)),
+          GEPi(bcx, box_body, [0, 1]));
+    bcx = trans_expr_save_in(bcx, val, GEPi(bcx, box_body, [0, 2]));
+    store_in_dest(bcx, PointerCast(bcx, box, T_opaque_iface_ptr(ccx)), dest)
+}
index 4c7c8942f289922b1ef5abcdad2ec1570ea2ae09..42225aa2acaeceabfc6989949631143ddb5b4e8f 100644 (file)
@@ -909,7 +909,7 @@ fn get_element_type(cx: ctxt, ty: t, i: uint) -> t {
 
 pure fn type_is_boxed(cx: ctxt, ty: t) -> bool {
     alt struct(cx, ty) {
-      ty_box(_) { ret true; }
+      ty_box(_) | ty_iface(_, _) { ret true; }
       _ { ret false; }
     }
 }
index 075c0dbe2a8977eac275ca552dda790790f50db0..540bae5b32b59abd73bf0bb593ecbd0b550a7f50 100644 (file)
 import option::{none, some};
 import syntax::print::pprust::*;
 
-export check_crate, method_map, method_origin, method_static, method_param;
+export check_crate;
+export method_map, method_origin, method_static, method_param, method_iface;
 export dict_map, dict_res, dict_origin, dict_static, dict_param;
 
 tag method_origin {
     method_static(ast::def_id);
     // iface id, method num, param num, bound num
     method_param(ast::def_id, uint, uint, uint);
-    method_iface;
+    method_iface(uint);
 }
 type method_map = hashmap<ast::node_id, method_origin>;
 
@@ -1575,13 +1576,15 @@ fn lookup_method(fcx: @fn_ctxt, isc: resolve::iscopes,
         ret none;
       }
       ty::ty_iface(did, tps) {
+        let i = 0u;
         for m in *ty::iface_methods(tcx, did) {
             if m.ident == name {
                 ret some({method_ty: ty::mk_fn(tcx, m.fty),
                           n_tps: vec::len(*m.tps),
                           substs: tps,
-                          origin: method_iface});
+                          origin: method_iface(i)});
             }
+            i += 1u;
         }
       }
       _ {}