From 2585384c977046a58e140c598ac5d4270501568d Mon Sep 17 00:00:00 2001 From: Graydon Hoare Date: Fri, 11 May 2012 13:09:49 -0700 Subject: [PATCH] First working monomorphic type-reflection. --- src/rustc/front/intrinsic.rs | 6 ++ src/rustc/middle/trans/native.rs | 86 +++++++++++++--- src/rustc/middle/trans/type_use.rs | 6 +- src/test/run-pass/reflect-visit-type.rs | 130 ++++++++++++++++++++++++ 4 files changed, 210 insertions(+), 18 deletions(-) create mode 100644 src/test/run-pass/reflect-visit-type.rs diff --git a/src/rustc/front/intrinsic.rs b/src/rustc/front/intrinsic.rs index e389b30715b..b2ea0ec7076 100644 --- a/src/rustc/front/intrinsic.rs +++ b/src/rustc/front/intrinsic.rs @@ -18,6 +18,7 @@ mod intrinsic { } iface ty_visitor { + fn visit_bot(); fn visit_nil(); fn visit_bool(); @@ -36,6 +37,8 @@ mod intrinsic { fn visit_float(); fn visit_f32(); fn visit_f64(); + + fn visit_char(); fn visit_str(); fn visit_vec(cells_mut: bool, @@ -68,6 +71,7 @@ mod intrinsic { iface val_visitor { // Basic types we can visit directly. + fn visit_bot(); fn visit_nil(); fn visit_bool(b: &bool); @@ -87,6 +91,8 @@ mod intrinsic { fn visit_f32(f: &f32); fn visit_f64(f: &f64); + fn visit_char(c: &char); + // Vecs and strs we can provide a stub view of. fn visit_str(repr: &vec::unsafe::vec_repr, visit_cell: fn(uint,self)); diff --git a/src/rustc/middle/trans/native.rs b/src/rustc/middle/trans/native.rs index 4ecbdb7a1c1..521cf50ee3e 100644 --- a/src/rustc/middle/trans/native.rs +++ b/src/rustc/middle/trans/native.rs @@ -782,7 +782,7 @@ fn trans_intrinsic(ccx: @crate_ctxt, decl: ValueRef, item: @ast::native_item, ref_id: option) { let fcx = new_fn_ctxt_w_id(ccx, path, decl, item.id, some(substs), some(item.span)); - let bcx = top_scope_block(fcx, none), lltop = bcx.llbb; + let mut bcx = top_scope_block(fcx, none), lltop = bcx.llbb; let tp_ty = substs.tys[0], lltp_ty = type_of::type_of(ccx, tp_ty); alt check item.ident { "size_of" { @@ -835,27 +835,83 @@ fn trans_intrinsic(ccx: @crate_ctxt, decl: ValueRef, item: @ast::native_item, fcx.llretptr); } "visit_ty" { - let vp_ty = substs.tys[1], _llvp_ty = type_of::type_of(ccx, vp_ty); + + // signature: fn visit_ty(tv: V); + + let tp_ty = substs.tys[0]; + let vp_ty = substs.tys[1]; let visitor = get_param(decl, first_real_arg); - // FIXME: implement a proper iface-call. Nontrivial. - Call(bcx, visitor, []); + + // 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. + + 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_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); + } + _ { + ccx.sess.span_bug(item.span, + "non-static callee in 'visit_ty' intrinsinc"); + } + } } "visit_val" { - let vp_ty = substs.tys[1], _llvp_ty = type_of::type_of(ccx, vp_ty); - let val = get_param(decl, first_real_arg); - let visitor = get_param(decl, first_real_arg + 1u); - // FIXME: implement a proper iface-call. Nontrivial. - Call(bcx, visitor, [val]); + bcx.sess().unimpl("trans::native::visit_val"); } "visit_val_pair" { - let vp_ty = substs.tys[1], _llvp_ty = type_of::type_of(ccx, vp_ty); - let a = get_param(decl, first_real_arg); - let b = get_param(decl, first_real_arg + 1u); - let visitor = get_param(decl, first_real_arg + 2u); - // FIXME: implement a proper iface-call. Nontrivial. - Call(bcx, visitor, [a, b]); + bcx.sess().unimpl("trans::native::visit_val_pair"); } } build_return(bcx); diff --git a/src/rustc/middle/trans/type_use.rs b/src/rustc/middle/trans/type_use.rs index 4b57f33af7d..65cc2a949b5 100644 --- a/src/rustc/middle/trans/type_use.rs +++ b/src/rustc/middle/trans/type_use.rs @@ -76,9 +76,9 @@ fn type_uses_for(ccx: @crate_ctxt, fn_id: def_id, n_tps: uint) ast_map::node_native_item(i@@{node: native_item_fn(_, _), _}, abi, _) { if abi == native_abi_rust_intrinsic { let flags = alt check i.ident { - "size_of" | - "pref_align_of" | "min_align_of" | "init" | - "reinterpret_cast" { use_repr } + "visit_ty" | "visit_val" | "visit_val_pair" { 3u } + "size_of" | "pref_align_of" | "min_align_of" | + "init" | "reinterpret_cast" { use_repr } "get_tydesc" | "needs_drop" { use_tydesc } "forget" | "addr_of" { 0u } }; diff --git a/src/test/run-pass/reflect-visit-type.rs b/src/test/run-pass/reflect-visit-type.rs new file mode 100644 index 00000000000..f5c991ccde4 --- /dev/null +++ b/src/test/run-pass/reflect-visit-type.rs @@ -0,0 +1,130 @@ +// xfail-test +// +// This works on stage2 currently. Once we have a snapshot +// and some fiddling with inject_intrinsic (and possibly another +// snapshot after _that_) it can be un-xfailed and changed +// to use the intrinsic:: interface and native module. +// + +iface ty_visitor { + fn visit_bot(); + fn visit_nil(); + fn visit_bool(); + + fn visit_int(); + fn visit_i8(); + fn visit_i16(); + fn visit_i32(); + fn visit_i64(); + + fn visit_uint(); + fn visit_u8(); + fn visit_u16(); + fn visit_u32(); + fn visit_u64(); + + fn visit_float(); + fn visit_f32(); + fn visit_f64(); + + fn visit_char(); + fn visit_str(); + + 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)); +} + +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_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() { } + fn visit_u8() { } + fn visit_u16() { } + fn visit_u32() { } + fn visit_u64() { } + + fn visit_float() { } + fn visit_f32() { } + fn visit_f64() { } + + 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)) { } +} + +#[abi = "rust-intrinsic"] +native mod rusti { + fn visit_ty(tv: V); +} + +fn main() { + let v = my_visitor({mut types: []}); + + rusti::visit_ty::(v); + rusti::visit_ty::(v); + rusti::visit_ty::(v); + rusti::visit_ty::(v); + + for v.types.each {|s| + io::println(#fmt("type: %s", s)); + } + assert v.types == ["bool", "int", "i8", "i16"]; +}