From d899c3a5792da29ac2bf71caf76b56017b5f42d0 Mon Sep 17 00:00:00 2001 From: Graydon Hoare Date: Mon, 14 May 2012 15:48:58 -0700 Subject: [PATCH] More work on reflection, now calls iface visitors back as well. --- src/rustc/middle/trans/impl.rs | 35 ++--- src/rustc/middle/trans/native.rs | 96 +++++++------ src/test/run-pass/reflect-visit-type.rs | 181 ++++++++++++------------ 3 files changed, 158 insertions(+), 154 deletions(-) diff --git a/src/rustc/middle/trans/impl.rs b/src/rustc/middle/trans/impl.rs index 7578b0d1351..4b4dbe98769 100644 --- a/src/rustc/middle/trans/impl.rs +++ b/src/rustc/middle/trans/impl.rs @@ -64,24 +64,13 @@ fn trans_method_callee(bcx: block, callee_id: ast::node_id, } } typeck::method_iface(_, off) { - trans_iface_callee(bcx, self, callee_id, off) + let {bcx, val} = trans_temp_expr(bcx, self); + let fty = node_id_type(bcx, callee_id); + trans_iface_callee(bcx, val, fty, off) } } } -fn trans_vtable_callee(bcx: block, env: callee_env, vtable: ValueRef, - callee_id: ast::node_id, n_method: uint) - -> lval_maybe_callee { - let _icx = bcx.insn_ctxt("impl::trans_vtable_callee"); - let bcx = bcx, ccx = bcx.ccx(); - let fty = node_id_type(bcx, callee_id); - let llfty = type_of::type_of_fn_from_ty(ccx, fty); - let vtable = PointerCast(bcx, vtable, - T_ptr(T_array(T_ptr(llfty), n_method + 1u))); - let mptr = Load(bcx, GEPi(bcx, vtable, [0u, n_method])); - {bcx: bcx, val: mptr, kind: owned, env: env} -} - fn method_from_methods(ms: [@ast::method], name: ast::ident) -> ast::def_id { local_def(option::get(vec::find(ms, {|m| m.ident == name})).id) } @@ -139,7 +128,9 @@ fn trans_monomorphized_callee(bcx: block, callee_id: ast::node_id, with lval} } typeck::vtable_iface(iid, tps) { - trans_iface_callee(bcx, base, callee_id, n_method) + let {bcx, val} = trans_temp_expr(bcx, base); + let fty = node_id_type(bcx, callee_id); + trans_iface_callee(bcx, val, fty, n_method) } typeck::vtable_param(n_param, n_bound) { fail "vtable_param left in monomorphized function's vtable substs"; @@ -148,18 +139,22 @@ fn trans_monomorphized_callee(bcx: block, callee_id: ast::node_id, } // Method callee where the vtable comes from a boxed iface -fn trans_iface_callee(bcx: block, base: @ast::expr, - callee_id: ast::node_id, n_method: uint) +fn trans_iface_callee(bcx: block, val: ValueRef, + callee_ty: ty::t, n_method: uint) -> lval_maybe_callee { let _icx = bcx.insn_ctxt("impl::trans_iface_callee"); - let {bcx, val} = trans_temp_expr(bcx, base); + let ccx = bcx.ccx(); let vtable = Load(bcx, PointerCast(bcx, GEPi(bcx, val, [0u, 0u]), - T_ptr(T_ptr(T_vtable())))); + T_ptr(T_ptr(T_vtable())))); let box = Load(bcx, GEPi(bcx, val, [0u, 1u])); // FIXME[impl] I doubt this is alignment-safe let self = GEPi(bcx, box, [0u, abi::box_field_body]); let env = self_env(self, ty::mk_opaque_box(bcx.tcx()), some(box)); - trans_vtable_callee(bcx, env, vtable, callee_id, n_method) + let llfty = type_of::type_of_fn_from_ty(ccx, callee_ty); + let vtable = PointerCast(bcx, vtable, + T_ptr(T_array(T_ptr(llfty), n_method + 1u))); + let mptr = Load(bcx, GEPi(bcx, vtable, [0u, n_method])); + {bcx: bcx, val: mptr, kind: owned, env: env} } fn find_vtable_in_fn_ctxt(ps: param_substs, n_param: uint, n_bound: uint) diff --git a/src/rustc/middle/trans/native.rs b/src/rustc/middle/trans/native.rs index 521cf50ee3e..f5b1a59d15f 100644 --- a/src/rustc/middle/trans/native.rs +++ b/src/rustc/middle/trans/native.rs @@ -10,7 +10,7 @@ import lib::llvm::{ llvm, TypeRef, ValueRef, StructRetAttribute, ByValAttribute }; import syntax::{ast, ast_util}; -import back::link; +import back::{link, abi}; import common::*; import build::*; import base::*; @@ -842,63 +842,65 @@ fn trans_intrinsic(ccx: @crate_ctxt, decl: ValueRef, item: @ast::native_item, let vp_ty = substs.tys[1]; let visitor = get_param(decl, first_real_arg); - // We're going to synthesize a monomorphized vtbl call here much - // like what impl::trans_monomorphized_callee does, but without - // having quite as much source machinery to go on. + let (tyname, args) = alt ty::get(tp_ty).struct { + ty::ty_bot { ("bot", []) } + ty::ty_nil { ("nil", []) } + ty::ty_bool { ("bool", []) } + ty::ty_int(ast::ty_i) { ("int", []) } + ty::ty_int(ast::ty_char) { ("char", []) } + ty::ty_int(ast::ty_i8) { ("i8", []) } + ty::ty_int(ast::ty_i16) { ("i16", []) } + ty::ty_int(ast::ty_i32) { ("i32", []) } + ty::ty_int(ast::ty_i64) { ("i64", []) } + ty::ty_uint(ast::ty_u) { ("uint", []) } + ty::ty_uint(ast::ty_u8) { ("u8", []) } + ty::ty_uint(ast::ty_u16) { ("u16", []) } + ty::ty_uint(ast::ty_u32) { ("u32", []) } + ty::ty_uint(ast::ty_u64) { ("u64", []) } + ty::ty_float(ast::ty_f) { ("float", []) } + ty::ty_float(ast::ty_f32) { ("f32", []) } + ty::ty_float(ast::ty_f64) { ("f64", []) } + ty::ty_str { ("str", []) } + _ { + bcx.sess().unimpl("trans::native::visit_ty on " + + ty_to_str(ccx.tcx, tp_ty)); + } + }; + + let mth_name = "visit_" + tyname; + let dest = ignore; alt impl::find_vtable_in_fn_ctxt(substs, 1u, /* n_param */ 0u /* n_bound */ ) { typeck::vtable_static(impl_did, impl_substs, sub_origins) { - - let (tyname, args) = alt ty::get(tp_ty).struct { - ty::ty_bot { ("bot", []) } - ty::ty_nil { ("nil", []) } - ty::ty_bool { ("bool", []) } - ty::ty_int(ast::ty_i) { ("int", []) } - ty::ty_int(ast::ty_char) { ("char", []) } - ty::ty_int(ast::ty_i8) { ("i8", []) } - ty::ty_int(ast::ty_i16) { ("i16", []) } - ty::ty_int(ast::ty_i32) { ("i32", []) } - ty::ty_int(ast::ty_i64) { ("i64", []) } - ty::ty_uint(ast::ty_u) { ("uint", []) } - ty::ty_uint(ast::ty_u8) { ("u8", []) } - ty::ty_uint(ast::ty_u16) { ("u16", []) } - ty::ty_uint(ast::ty_u32) { ("u32", []) } - ty::ty_uint(ast::ty_u64) { ("u64", []) } - ty::ty_float(ast::ty_f) { ("float", []) } - ty::ty_float(ast::ty_f32) { ("f32", []) } - ty::ty_float(ast::ty_f64) { ("f64", []) } - ty::ty_str { ("str", []) } - _ { - bcx.sess().unimpl("trans::native::visit_ty on " - + ty_to_str(ccx.tcx, tp_ty)); - } - }; - - let mth_id = impl::method_with_name(ccx, impl_did, - "visit_" + tyname); + let mth_id = impl::method_with_name(ccx, impl_did, mth_name); let mth_ty = ty::lookup_item_type(ccx.tcx, mth_id).ty; - // FIXME: is this safe? There is no callee AST node, // we're synthesizing it. let callee_id = (-1) as ast::node_id; - - let dest = ignore; - - bcx = trans_call_inner(bcx, - mth_ty, - ty::mk_nil(ccx.tcx), - {|bcx| - let lval = - lval_static_fn_inner - (bcx, mth_id, callee_id, - impl_substs, some(sub_origins)); - {env: self_env(visitor, vp_ty, none) - with lval} - }, arg_vals(args), dest); + let get_lval = {|bcx| + let lval = lval_static_fn_inner(bcx, mth_id, callee_id, + impl_substs, + some(sub_origins)); + {env: self_env(visitor, vp_ty, none) with lval} + }; + bcx = trans_call_inner(bcx, mth_ty, ty::mk_bool(ccx.tcx), + get_lval, arg_vals(args), dest); } + + typeck::vtable_iface(iid, _tps) { + let methods = ty::iface_methods(ccx.tcx, iid); + let mth_idx = option::get(ty::method_idx(mth_name, *methods)); + let mth_ty = ty::mk_fn(ccx.tcx, methods[mth_idx].fty); + let get_lval = {|bcx| + impl::trans_iface_callee(bcx, visitor, mth_ty, mth_idx) + }; + bcx = trans_call_inner(bcx, mth_ty, ty::mk_bool(ccx.tcx), + get_lval, arg_vals(args), dest); + } + _ { ccx.sess.span_bug(item.span, "non-static callee in 'visit_ty' intrinsinc"); diff --git a/src/test/run-pass/reflect-visit-type.rs b/src/test/run-pass/reflect-visit-type.rs index f5c991ccde4..66a7f109d21 100644 --- a/src/test/run-pass/reflect-visit-type.rs +++ b/src/test/run-pass/reflect-visit-type.rs @@ -7,107 +7,105 @@ // iface ty_visitor { - fn visit_bot(); - fn visit_nil(); - fn visit_bool(); + fn visit_bot() -> bool; + fn visit_nil() -> bool; + fn visit_bool() -> bool; - fn visit_int(); - fn visit_i8(); - fn visit_i16(); - fn visit_i32(); - fn visit_i64(); + fn visit_int() -> bool; + fn visit_i8() -> bool; + fn visit_i16() -> bool; + fn visit_i32() -> bool; + fn visit_i64() -> bool; - fn visit_uint(); - fn visit_u8(); - fn visit_u16(); - fn visit_u32(); - fn visit_u64(); + fn visit_uint() -> bool; + fn visit_u8() -> bool; + fn visit_u16() -> bool; + fn visit_u32() -> bool; + fn visit_u64() -> bool; - fn visit_float(); - fn visit_f32(); - fn visit_f64(); + fn visit_float() -> bool; + fn visit_f32() -> bool; + fn visit_f64() -> bool; - fn visit_char(); - fn visit_str(); + fn visit_char() -> bool; + fn visit_str() -> bool; - fn visit_vec(cells_mut: bool, - visit_cell: fn(uint, self)); - - fn visit_box(inner_mut: bool, - visit_inner: fn(self)); - - fn visit_uniq(inner_mut: bool, - visit_inner: fn(self)); - - fn visit_ptr(inner_mut: bool, - visit_inner: fn(self)); - - fn visit_rptr(inner_mut: bool, - visit_inner: fn(self)); - - fn visit_rec(n_fields: uint, - field_name: fn(uint) -> str/&, - field_mut: fn(uint) -> bool, - visit_field: fn(uint, self)); - fn visit_tup(n_fields: uint, - visit_field: fn(uint, self)); - fn visit_enum(n_variants: uint, - variant: uint, - variant_name: fn(uint) -> str/&, - visit_variant: fn(uint, self)); + // FIXME: possibly pair these as enter/leave calls + // not just enter with implicit number of subsequent + // calls. + fn visit_vec_of(is_mut: bool) -> bool; + fn visit_box_of(is_mut: bool) -> bool; + fn visit_uniq_of(is_mut: bool) -> bool; + fn visit_ptr_of(is_mut: bool) -> bool; + fn visit_rptr_of(is_mut: bool) -> bool; + fn visit_rec_of(n_fields: uint) -> bool; + fn visit_rec_field(name: str/&, is_mut: bool) -> bool; + fn visit_tup_of(n_fields: uint) -> bool; + fn visit_tup_field(is_mut: bool) -> bool; + fn visit_enum_of(n_variants: uint) -> bool; + fn visit_enum_variant(name: str/&) -> bool; } enum my_visitor = { mut types: [str] }; impl of ty_visitor for my_visitor { - fn visit_bot() { self.types += ["bot"] } - fn visit_nil() { self.types += ["nil"] } - fn visit_bool() { self.types += ["bool"] } + fn visit_bot() -> bool { + self.types += ["bot"]; + #error("visited bot type"); + true + } + fn visit_nil() -> bool { + self.types += ["nil"]; + #error("visited nil type"); + true + } + fn visit_bool() -> bool { + self.types += ["bool"]; + #error("visited bool type"); + true + } + fn visit_int() -> bool { + self.types += ["int"]; + #error("visited int type"); + true + } + fn visit_i8() -> bool { + self.types += ["i8"]; + #error("visited i8 type"); + true + } + fn visit_i16() -> bool { + self.types += ["i16"]; + #error("visited i16 type"); + true + } + fn visit_i32() -> bool { true } + fn visit_i64() -> bool { true } - fn visit_int() { self.types += ["int"] } - fn visit_i8() { self.types += ["i8"] } - fn visit_i16() { self.types += ["i16"] } - fn visit_i32() { } - fn visit_i64() { } + fn visit_uint() -> bool { true } + fn visit_u8() -> bool { true } + fn visit_u16() -> bool { true } + fn visit_u32() -> bool { true } + fn visit_u64() -> bool { true } - fn visit_uint() { } - fn visit_u8() { } - fn visit_u16() { } - fn visit_u32() { } - fn visit_u64() { } + fn visit_float() -> bool { true } + fn visit_f32() -> bool { true } + fn visit_f64() -> bool { true } - fn visit_float() { } - fn visit_f32() { } - fn visit_f64() { } + fn visit_char() -> bool { true } + fn visit_str() -> bool { true } - fn visit_char() { } - fn visit_str() { } - - fn visit_vec(_cells_mut: bool, - _visit_cell: fn(uint, my_visitor)) { } - - fn visit_box(_inner_mut: bool, - _visit_inner: fn(my_visitor)) { } - - fn visit_uniq(_inner_mut: bool, - _visit_inner: fn(my_visitor)) { } - - fn visit_ptr(_inner_mut: bool, - _visit_inner: fn(my_visitor)) { } - - fn visit_rptr(_inner_mut: bool, - _visit_inner: fn(my_visitor)) { } - - fn visit_rec(_n_fields: uint, - _field_name: fn(uint) -> str/&, - _field_mut: fn(uint) -> bool, - _visit_field: fn(uint, my_visitor)) { } - fn visit_tup(_n_fields: uint, - _visit_field: fn(uint, my_visitor)) { } - fn visit_enum(_n_variants: uint, - _variant: uint, - _variant_name: fn(uint) -> str/&, - _visit_variant: fn(uint, my_visitor)) { } + fn visit_vec_of(_is_mut: bool) -> bool { true } + fn visit_box_of(_is_mut: bool) -> bool { true } + fn visit_uniq_of(_is_mut: bool) -> bool { true } + fn visit_ptr_of(_is_mut: bool) -> bool { true } + fn visit_rptr_of(_is_mut: bool) -> bool { true } + fn visit_rec_of(_n_fields: uint) -> bool { true } + fn visit_rec_field(_name: str/&, _is_mut: bool) -> bool { true } + fn visit_tup_of(_n_fields: uint) -> bool { true } + fn visit_tup_field(_is_mut: bool) -> bool { true } + fn visit_enum_of(_n_variants: uint) -> bool { true } + fn visit_enum_variant(_name: str/&) -> bool { true } } #[abi = "rust-intrinsic"] @@ -115,6 +113,13 @@ native mod rusti { fn visit_ty(tv: V); } +fn via_iface(v: ty_visitor) { + rusti::visit_ty::(v); + rusti::visit_ty::(v); + rusti::visit_ty::(v); + rusti::visit_ty::(v); +} + fn main() { let v = my_visitor({mut types: []}); @@ -127,4 +132,6 @@ fn main() { io::println(#fmt("type: %s", s)); } assert v.types == ["bool", "int", "i8", "i16"]; + + via_iface(v as ty_visitor); }