Hugely simplify iface handling
With the assumption of monomorphization
This commit is contained in:
parent
168398bb3d
commit
4511f936b1
8 changed files with 138 additions and 323 deletions
|
@ -548,11 +548,14 @@ fn encode_dict_origin(ecx: @e::encode_ctxt,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
typeck::dict_iface(def_id) {
|
typeck::dict_iface(def_id, tys) {
|
||||||
ebml_w.emit_enum_variant("dict_iface", 1u, 3u) {||
|
ebml_w.emit_enum_variant("dict_iface", 1u, 3u) {||
|
||||||
ebml_w.emit_enum_variant_arg(0u) {||
|
ebml_w.emit_enum_variant_arg(0u) {||
|
||||||
ebml_w.emit_def_id(def_id)
|
ebml_w.emit_def_id(def_id)
|
||||||
}
|
}
|
||||||
|
ebml_w.emit_enum_variant_arg(1u) {||
|
||||||
|
ebml_w.emit_tys(ecx, tys);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -596,6 +599,9 @@ impl helpers for ebml::ebml_deserializer {
|
||||||
typeck::dict_iface(
|
typeck::dict_iface(
|
||||||
self.read_enum_variant_arg(0u) {||
|
self.read_enum_variant_arg(0u) {||
|
||||||
self.read_def_id(xcx)
|
self.read_def_id(xcx)
|
||||||
|
},
|
||||||
|
self.read_enum_variant_arg(1u) {||
|
||||||
|
self.read_tys(xcx)
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
|
@ -258,7 +258,7 @@ fn get_impl_iface(cdata: cmd, id: ast::node_id, tcx: ty::ctxt)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_impl_method(cdata: cmd, id: ast::node_id, name: str) -> ast::def_id {
|
fn get_impl_method(cdata: cmd, id: ast::node_id, name: str) -> ast::def_id {
|
||||||
let items = ebml::get_doc(ebml::new_doc(cdata.data), tag_items);
|
let items = ebml::get_doc(ebml::doc(cdata.data), tag_items);
|
||||||
let found = none;
|
let found = none;
|
||||||
ebml::tagged_docs(find_item(id, items), tag_item_method) {|mid|
|
ebml::tagged_docs(find_item(id, items), tag_item_method) {|mid|
|
||||||
let m_did = parse_def_id(ebml::doc_data(mid));
|
let m_did = parse_def_id(ebml::doc_data(mid));
|
||||||
|
|
|
@ -2070,7 +2070,6 @@ enum callee_env {
|
||||||
null_env,
|
null_env,
|
||||||
is_closure,
|
is_closure,
|
||||||
self_env(ValueRef, ty::t),
|
self_env(ValueRef, ty::t),
|
||||||
dict_env(ValueRef, ValueRef),
|
|
||||||
}
|
}
|
||||||
type lval_maybe_callee = {bcx: block,
|
type lval_maybe_callee = {bcx: block,
|
||||||
val: ValueRef,
|
val: ValueRef,
|
||||||
|
@ -2117,8 +2116,8 @@ fn monomorphic_fn(ccx: @crate_ctxt, fn_id: ast::def_id, substs: [ty::t],
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
let hash_id = @{def: fn_id, substs: substs, dicts: alt dicts {
|
let hash_id = @{def: fn_id, substs: substs, dicts: alt dicts {
|
||||||
some(os) { vec::map(*os, {|o| impl::dict_id(ccx.tcx, o)}) }
|
some(os) { some_dicts(vec::map(*os, impl::vtable_id)) }
|
||||||
none { [] }
|
none { no_dicts }
|
||||||
}};
|
}};
|
||||||
alt ccx.monomorphized.find(hash_id) {
|
alt ccx.monomorphized.find(hash_id) {
|
||||||
some(val) { ret some(val); }
|
some(val) { ret some(val); }
|
||||||
|
@ -2258,10 +2257,8 @@ fn lval_static_fn(bcx: block, fn_id: ast::def_id, id: ast::node_id,
|
||||||
none {
|
none {
|
||||||
alt ccx.maps.dict_map.find(id) {
|
alt ccx.maps.dict_map.find(id) {
|
||||||
some(dicts) {
|
some(dicts) {
|
||||||
alt impl::resolve_dicts_in_fn_ctxt(bcx.fcx, dicts) {
|
let rdicts = impl::resolve_vtables_in_fn_ctxt(bcx.fcx, dicts);
|
||||||
some(dicts) { monomorphic_fn(ccx, fn_id, tys, some(dicts)) }
|
monomorphic_fn(ccx, fn_id, tys, some(rdicts))
|
||||||
none { none }
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
none { monomorphic_fn(ccx, fn_id, tys, none) }
|
none { monomorphic_fn(ccx, fn_id, tys, none) }
|
||||||
}
|
}
|
||||||
|
@ -2567,7 +2564,7 @@ fn trans_lval(cx: block, e: @ast::expr) -> lval_result {
|
||||||
|
|
||||||
fn lval_maybe_callee_to_lval(c: lval_maybe_callee, ty: ty::t) -> lval_result {
|
fn lval_maybe_callee_to_lval(c: lval_maybe_callee, ty: ty::t) -> lval_result {
|
||||||
let must_bind = alt c.generic { generic_full(_) { true } _ { false } } ||
|
let must_bind = alt c.generic { generic_full(_) { true } _ { false } } ||
|
||||||
alt c.env { self_env(_, _) | dict_env(_, _) { true } _ { false } };
|
alt c.env { self_env(_, _) { true } _ { false } };
|
||||||
if must_bind {
|
if must_bind {
|
||||||
let n_args = ty::ty_fn_args(ty).len();
|
let n_args = ty::ty_fn_args(ty).len();
|
||||||
let args = vec::from_elem(n_args, none);
|
let args = vec::from_elem(n_args, none);
|
||||||
|
@ -2779,28 +2776,7 @@ fn trans_args(cx: block, llenv: ValueRef,
|
||||||
|
|
||||||
let retty = ty::ty_fn_ret(fn_ty), full_retty = retty;
|
let retty = ty::ty_fn_ret(fn_ty), full_retty = retty;
|
||||||
alt gen {
|
alt gen {
|
||||||
generic_full(g) {
|
generic_full(g) { fail; }
|
||||||
lazily_emit_all_generic_info_tydesc_glues(ccx, g);
|
|
||||||
let i = 0u, n_orig = 0u;
|
|
||||||
for param in *g.param_bounds {
|
|
||||||
lltydescs += [g.tydescs[i]];
|
|
||||||
for bound in *param {
|
|
||||||
alt bound {
|
|
||||||
ty::bound_iface(_) {
|
|
||||||
let res = impl::get_dict(
|
|
||||||
bcx, option::get(g.origins)[n_orig]);
|
|
||||||
lltydescs += [res.val];
|
|
||||||
bcx = res.bcx;
|
|
||||||
n_orig += 1u;
|
|
||||||
}
|
|
||||||
_ {}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
i += 1u;
|
|
||||||
}
|
|
||||||
args = ty::ty_fn_args(g.item_type);
|
|
||||||
retty = ty::ty_fn_ret(g.item_type);
|
|
||||||
}
|
|
||||||
generic_mono(t) {
|
generic_mono(t) {
|
||||||
args = ty::ty_fn_args(t);
|
args = ty::ty_fn_args(t);
|
||||||
retty = ty::ty_fn_ret(t);
|
retty = ty::ty_fn_ret(t);
|
||||||
|
@ -2884,17 +2860,12 @@ fn trans_call_inner(in_cx: block, fn_expr_ty: ty::t,
|
||||||
let bcx = f_res.bcx, ccx = cx.ccx();
|
let bcx = f_res.bcx, ccx = cx.ccx();
|
||||||
|
|
||||||
let faddr = f_res.val;
|
let faddr = f_res.val;
|
||||||
let llenv, dict_param = none;
|
let llenv = alt f_res.env {
|
||||||
alt f_res.env {
|
|
||||||
null_env {
|
null_env {
|
||||||
llenv = llvm::LLVMGetUndef(T_opaque_box_ptr(ccx));
|
llvm::LLVMGetUndef(T_opaque_box_ptr(ccx))
|
||||||
}
|
}
|
||||||
self_env(e, _) {
|
self_env(e, _) {
|
||||||
llenv = PointerCast(bcx, e, T_opaque_box_ptr(ccx));
|
PointerCast(bcx, e, T_opaque_box_ptr(ccx))
|
||||||
}
|
|
||||||
dict_env(dict, e) {
|
|
||||||
llenv = PointerCast(bcx, e, T_opaque_box_ptr(ccx));
|
|
||||||
dict_param = some(dict);
|
|
||||||
}
|
}
|
||||||
is_closure {
|
is_closure {
|
||||||
// It's a closure. Have to fetch the elements
|
// It's a closure. Have to fetch the elements
|
||||||
|
@ -2905,16 +2876,15 @@ fn trans_call_inner(in_cx: block, fn_expr_ty: ty::t,
|
||||||
faddr = GEPi(bcx, pair, [0, abi::fn_field_code]);
|
faddr = GEPi(bcx, pair, [0, abi::fn_field_code]);
|
||||||
faddr = Load(bcx, faddr);
|
faddr = Load(bcx, faddr);
|
||||||
let llclosure = GEPi(bcx, pair, [0, abi::fn_field_box]);
|
let llclosure = GEPi(bcx, pair, [0, abi::fn_field_box]);
|
||||||
llenv = Load(bcx, llclosure);
|
Load(bcx, llclosure)
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
|
|
||||||
let ret_ty = node_id_type(bcx, id);
|
let ret_ty = node_id_type(bcx, id);
|
||||||
let args_res =
|
let args_res =
|
||||||
trans_args(bcx, llenv, f_res.generic, args, fn_expr_ty, dest);
|
trans_args(bcx, llenv, f_res.generic, args, fn_expr_ty, dest);
|
||||||
bcx = args_res.bcx;
|
bcx = args_res.bcx;
|
||||||
let llargs = args_res.args;
|
let llargs = args_res.args;
|
||||||
option::may(dict_param) {|dict| llargs = [dict] + llargs}
|
|
||||||
let llretslot = args_res.retslot;
|
let llretslot = args_res.retslot;
|
||||||
|
|
||||||
/* If the block is terminated,
|
/* If the block is terminated,
|
||||||
|
@ -2955,6 +2925,10 @@ fn invoke_(bcx: block, llfn: ValueRef, llargs: [ValueRef],
|
||||||
// cleanups to run
|
// cleanups to run
|
||||||
if bcx.unreachable { ret bcx; }
|
if bcx.unreachable { ret bcx; }
|
||||||
let normal_bcx = sub_block(bcx, "normal return");
|
let normal_bcx = sub_block(bcx, "normal return");
|
||||||
|
/*std::io::println("fn: " + lib::llvm::type_to_str(bcx.ccx().tn, val_ty(llfn)));
|
||||||
|
for a in llargs {
|
||||||
|
std::io::println(" a: " + lib::llvm::type_to_str(bcx.ccx().tn, val_ty(a)));
|
||||||
|
}*/
|
||||||
invoker(bcx, llfn, llargs, normal_bcx.llbb, get_landing_pad(bcx));
|
invoker(bcx, llfn, llargs, normal_bcx.llbb, get_landing_pad(bcx));
|
||||||
ret normal_bcx;
|
ret normal_bcx;
|
||||||
}
|
}
|
||||||
|
@ -4791,16 +4765,6 @@ fn trans_constant(ccx: @crate_ctxt, it: @ast::item) {
|
||||||
i += 1;
|
i += 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ast::item_impl(tps, some(@{node: ast::ty_path(_, id), _}), _, ms) {
|
|
||||||
let i_did = ast_util::def_id_of_def(ccx.tcx.def_map.get(id));
|
|
||||||
impl::trans_impl_vtable(ccx, item_path(ccx, it), i_did, ms, tps, it);
|
|
||||||
}
|
|
||||||
ast::item_iface(_, _) {
|
|
||||||
if !vec::any(*ty::iface_methods(ccx.tcx, local_def(it.id)), {|m|
|
|
||||||
ty::type_has_vars(ty::mk_fn(ccx.tcx, m.fty))}) {
|
|
||||||
impl::trans_iface_vtable(ccx, item_path(ccx, it), it);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
_ { }
|
_ { }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -5032,9 +4996,9 @@ fn trans_crate(sess: session::session, crate: @ast::crate, tcx: ty::ctxt,
|
||||||
discrims: ast_util::new_def_id_hash::<ValueRef>(),
|
discrims: ast_util::new_def_id_hash::<ValueRef>(),
|
||||||
discrim_symbols: int_hash::<str>(),
|
discrim_symbols: int_hash::<str>(),
|
||||||
tydescs: ty::new_ty_hash(),
|
tydescs: ty::new_ty_hash(),
|
||||||
dicts: map::hashmap(hash_dict_id, {|a, b| a == b}),
|
|
||||||
external: util::common::new_def_hash(),
|
external: util::common::new_def_hash(),
|
||||||
monomorphized: map::hashmap(hash_mono_id, {|a, b| a == b}),
|
monomorphized: map::hashmap(hash_mono_id, {|a, b| a == b}),
|
||||||
|
vtables: map::hashmap(hash_mono_id, {|a, b| a == b}),
|
||||||
module_data: str_hash::<ValueRef>(),
|
module_data: str_hash::<ValueRef>(),
|
||||||
lltypes: ty::new_ty_hash(),
|
lltypes: ty::new_ty_hash(),
|
||||||
names: new_namegen(),
|
names: new_namegen(),
|
||||||
|
|
|
@ -515,26 +515,7 @@ fn trans_bind_1(cx: block, outgoing_fty: ty::t,
|
||||||
|
|
||||||
// Figure out which tydescs we need to pass, if any.
|
// Figure out which tydescs we need to pass, if any.
|
||||||
let (outgoing_fty_real, lltydescs, param_bounds) = alt f_res.generic {
|
let (outgoing_fty_real, lltydescs, param_bounds) = alt f_res.generic {
|
||||||
generic_full(ginfo) {
|
generic_full(ginfo) { fail; }
|
||||||
let tds = [], orig = 0u;
|
|
||||||
vec::iter2(ginfo.tydescs, *ginfo.param_bounds) {|td, bounds|
|
|
||||||
tds += [td];
|
|
||||||
for bound in *bounds {
|
|
||||||
alt bound {
|
|
||||||
ty::bound_iface(_) {
|
|
||||||
let dict = impl::get_dict(
|
|
||||||
bcx, option::get(ginfo.origins)[orig]);
|
|
||||||
tds += [PointerCast(bcx, dict.val, val_ty(td))];
|
|
||||||
orig += 1u;
|
|
||||||
bcx = dict.bcx;
|
|
||||||
}
|
|
||||||
_ {}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
lazily_emit_all_generic_info_tydesc_glues(ccx, ginfo);
|
|
||||||
(ginfo.item_type, tds, ginfo.param_bounds)
|
|
||||||
}
|
|
||||||
_ { (outgoing_fty, [], @[]) }
|
_ { (outgoing_fty, [], @[]) }
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -560,9 +541,6 @@ fn trans_bind_1(cx: block, outgoing_fty: ty::t,
|
||||||
self_env(slf, slf_t) {
|
self_env(slf, slf_t) {
|
||||||
([env_copy(slf, slf_t, owned)], target_self(f_res.val))
|
([env_copy(slf, slf_t, owned)], target_self(f_res.val))
|
||||||
}
|
}
|
||||||
dict_env(_, _) {
|
|
||||||
ccx.sess.unimpl("binding of dynamic method calls");
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
// Actually construct the closure
|
// Actually construct the closure
|
||||||
|
|
|
@ -90,11 +90,12 @@ type crate_ctxt = {
|
||||||
discrims: hashmap<ast::def_id, ValueRef>,
|
discrims: hashmap<ast::def_id, ValueRef>,
|
||||||
discrim_symbols: hashmap<ast::node_id, str>,
|
discrim_symbols: hashmap<ast::node_id, str>,
|
||||||
tydescs: hashmap<ty::t, @tydesc_info>,
|
tydescs: hashmap<ty::t, @tydesc_info>,
|
||||||
dicts: hashmap<dict_id, ValueRef>,
|
|
||||||
// Track mapping of external ids to local items imported for inlining
|
// Track mapping of external ids to local items imported for inlining
|
||||||
external: hashmap<ast::def_id, option<ast::node_id>>,
|
external: hashmap<ast::def_id, option<ast::node_id>>,
|
||||||
// Cache instances of monomorphized functions
|
// Cache instances of monomorphized functions
|
||||||
monomorphized: hashmap<mono_id, {llfn: ValueRef, fty: ty::t}>,
|
monomorphized: hashmap<mono_id, {llfn: ValueRef, fty: ty::t}>,
|
||||||
|
// Cache generated vtables
|
||||||
|
vtables: hashmap<mono_id, ValueRef>,
|
||||||
module_data: hashmap<str, ValueRef>,
|
module_data: hashmap<str, ValueRef>,
|
||||||
lltypes: hashmap<ty::t, TypeRef>,
|
lltypes: hashmap<ty::t, TypeRef>,
|
||||||
names: namegen,
|
names: namegen,
|
||||||
|
@ -846,30 +847,16 @@ pure fn type_has_static_size(cx: @crate_ctxt, t: ty::t) -> bool {
|
||||||
!ty::type_has_dynamic_size(cx.tcx, t)
|
!ty::type_has_dynamic_size(cx.tcx, t)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Used to identify cached dictionaries
|
|
||||||
enum dict_param {
|
|
||||||
dict_param_dict(dict_id),
|
|
||||||
dict_param_ty(ty::t),
|
|
||||||
}
|
|
||||||
type dict_id = @{def: ast::def_id, params: [dict_param]};
|
|
||||||
fn hash_dict_id(&&dp: dict_id) -> uint {
|
|
||||||
let h = syntax::ast_util::hash_def_id(dp.def);
|
|
||||||
for param in dp.params {
|
|
||||||
h = h << 2u;
|
|
||||||
alt param {
|
|
||||||
dict_param_dict(d) { h += hash_dict_id(d); }
|
|
||||||
dict_param_ty(t) { h += ty::type_id(t); }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
h
|
|
||||||
}
|
|
||||||
|
|
||||||
// Used to identify cached monomorphized functions
|
// Used to identify cached monomorphized functions
|
||||||
type mono_id = @{def: ast::def_id, substs: [ty::t], dicts: [dict_id]};
|
enum mono_dicts { some_dicts([mono_id]), no_dicts }
|
||||||
|
type mono_id = @{def: ast::def_id, substs: [ty::t], dicts: mono_dicts};
|
||||||
fn hash_mono_id(&&mi: mono_id) -> uint {
|
fn hash_mono_id(&&mi: mono_id) -> uint {
|
||||||
let h = syntax::ast_util::hash_def_id(mi.def);
|
let h = syntax::ast_util::hash_def_id(mi.def);
|
||||||
for ty in mi.substs { h = (h << 2u) + ty::type_id(ty); }
|
for ty in mi.substs { h = (h << 2u) + ty::type_id(ty); }
|
||||||
for dict in mi.dicts { h = (h << 2u) + hash_dict_id(dict); }
|
alt mi.dicts {
|
||||||
|
some_dicts(ds) { for d in ds { h = (h << 2u) + hash_mono_id(d); } }
|
||||||
|
_ {}
|
||||||
|
}
|
||||||
h
|
h
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -14,36 +14,6 @@ import lib::llvm::llvm::LLVMGetParam;
|
||||||
import ast_map::{path, path_mod, path_name};
|
import ast_map::{path, path_mod, path_name};
|
||||||
import std::map::hashmap;
|
import std::map::hashmap;
|
||||||
|
|
||||||
// Translation functionality related to impls and ifaces
|
|
||||||
//
|
|
||||||
// Terminology:
|
|
||||||
// vtable: a table of function pointers pointing to method wrappers
|
|
||||||
// of an impl that implements an iface
|
|
||||||
// dict: a record containing a vtable pointer along with pointers to
|
|
||||||
// all tydescs and other dicts needed to run methods in this vtable
|
|
||||||
// (i.e. corresponding to the type parameters of the impl)
|
|
||||||
// wrapper: a function that takes a dict as first argument, along
|
|
||||||
// with the method-specific tydescs for a method (and all
|
|
||||||
// other args the method expects), which fetches the extra
|
|
||||||
// tydescs and dicts from the dict, splices them into the
|
|
||||||
// arglist, and calls through to the actual method
|
|
||||||
//
|
|
||||||
// Generic functions take, along with their normal arguments, a number
|
|
||||||
// of extra tydesc and dict arguments -- one tydesc for each type
|
|
||||||
// parameter, one dict (following the tydesc in the arg order) for
|
|
||||||
// each interface bound on a type parameter.
|
|
||||||
//
|
|
||||||
// Most dicts are completely static, and are allocated and filled at
|
|
||||||
// compile time. Dicts that depend on run-time values (tydescs or
|
|
||||||
// dicts for type parameter types) are built at run-time, and interned
|
|
||||||
// through upcall_intern_dict in the runtime. This means that dict
|
|
||||||
// pointers are self-contained things that do not need to be cleaned
|
|
||||||
// up.
|
|
||||||
//
|
|
||||||
// The trans_constants pass in trans.rs outputs the vtables. Typeck
|
|
||||||
// annotates nodes with information about the methods and dicts that
|
|
||||||
// are referenced (ccx.method_map and ccx.dict_map).
|
|
||||||
|
|
||||||
fn trans_impl(ccx: @crate_ctxt, path: path, name: ast::ident,
|
fn trans_impl(ccx: @crate_ctxt, path: path, name: ast::ident,
|
||||||
methods: [@ast::method], tps: [ast::ty_param]) {
|
methods: [@ast::method], tps: [ast::ty_param]) {
|
||||||
if tps.len() > 0u { ret; }
|
if tps.len() > 0u { ret; }
|
||||||
|
@ -81,18 +51,15 @@ fn trans_method_callee(bcx: block, callee_id: ast::node_id,
|
||||||
trans_static_callee(bcx, callee_id, self, did, none)
|
trans_static_callee(bcx, callee_id, self, did, none)
|
||||||
}
|
}
|
||||||
typeck::method_param(iid, off, p, b) {
|
typeck::method_param(iid, off, p, b) {
|
||||||
alt bcx.fcx.param_substs {
|
alt check bcx.fcx.param_substs {
|
||||||
some(substs) {
|
some(substs) {
|
||||||
trans_monomorphized_callee(bcx, callee_id, self,
|
trans_monomorphized_callee(bcx, callee_id, self,
|
||||||
iid, off, p, b, substs)
|
iid, off, p, b, substs)
|
||||||
}
|
}
|
||||||
none {
|
|
||||||
trans_param_callee(bcx, callee_id, self, iid, off, p, b)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
typeck::method_iface(iid, off) {
|
typeck::method_iface(_, off) {
|
||||||
trans_iface_callee(bcx, callee_id, self, iid, off)
|
trans_iface_callee(bcx, self, callee_id, off)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -115,39 +82,20 @@ fn wrapper_fn_ty(ccx: @crate_ctxt, dict_ty: TypeRef, fty: ty::t,
|
||||||
}
|
}
|
||||||
|
|
||||||
fn trans_vtable_callee(bcx: block, env: callee_env, dict: ValueRef,
|
fn trans_vtable_callee(bcx: block, env: callee_env, dict: ValueRef,
|
||||||
callee_id: ast::node_id, iface_id: ast::def_id,
|
callee_id: ast::node_id, n_method: uint)
|
||||||
n_method: uint) -> lval_maybe_callee {
|
-> lval_maybe_callee {
|
||||||
let bcx = bcx, ccx = bcx.ccx(), tcx = ccx.tcx;
|
let bcx = bcx, ccx = bcx.ccx(), tcx = ccx.tcx;
|
||||||
let method = ty::iface_methods(tcx, iface_id)[n_method];
|
let fty = node_id_type(bcx, callee_id);
|
||||||
let method_ty = ty::mk_fn(tcx, method.fty);
|
let llfty = type_of::type_of_fn_from_ty(ccx, fty, []);
|
||||||
let {ty: fty, llty: llfty} =
|
let vtable = PointerCast(bcx, dict,
|
||||||
wrapper_fn_ty(ccx, val_ty(dict), method_ty, method.tps);
|
|
||||||
let vtable = PointerCast(bcx, Load(bcx, GEPi(bcx, dict, [0, 0])),
|
|
||||||
T_ptr(T_array(T_ptr(llfty), n_method + 1u)));
|
T_ptr(T_array(T_ptr(llfty), n_method + 1u)));
|
||||||
let mptr = Load(bcx, GEPi(bcx, vtable, [0, n_method as int]));
|
let mptr = Load(bcx, GEPi(bcx, vtable, [0, n_method as int]));
|
||||||
let generic = generic_none;
|
|
||||||
if (*method.tps).len() > 0u || ty::type_has_params(fty) {
|
|
||||||
let tydescs = [], tis = [];
|
|
||||||
let tptys = node_id_type_params(bcx, callee_id);
|
|
||||||
for t in vec::tailn(tptys, tptys.len() - (*method.tps).len()) {
|
|
||||||
let ti = none;
|
|
||||||
let td = get_tydesc(bcx, t, true, ti);
|
|
||||||
tis += [ti];
|
|
||||||
tydescs += [td.val];
|
|
||||||
bcx = td.bcx;
|
|
||||||
}
|
|
||||||
generic = generic_full({item_type: fty,
|
|
||||||
static_tis: tis,
|
|
||||||
tydescs: tydescs,
|
|
||||||
param_bounds: method.tps,
|
|
||||||
origins: ccx.maps.dict_map.find(callee_id)});
|
|
||||||
}
|
|
||||||
{bcx: bcx, val: mptr, kind: owned,
|
{bcx: bcx, val: mptr, kind: owned,
|
||||||
env: env,
|
env: env,
|
||||||
generic: generic}
|
generic: generic_none}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn method_with_name(ccx: crate_ctxt, impl_id: ast::def_id,
|
fn method_with_name(ccx: @crate_ctxt, impl_id: ast::def_id,
|
||||||
name: ast::ident) -> ast::def_id {
|
name: ast::ident) -> ast::def_id {
|
||||||
if impl_id.crate == ast::local_crate {
|
if impl_id.crate == ast::local_crate {
|
||||||
alt check ccx.tcx.items.get(impl_id.node) {
|
alt check ccx.tcx.items.get(impl_id.node) {
|
||||||
|
@ -172,8 +120,8 @@ fn trans_monomorphized_callee(bcx: block, callee_id: ast::node_id,
|
||||||
ret trans_static_callee(bcx, callee_id, base, mth_id,
|
ret trans_static_callee(bcx, callee_id, base, mth_id,
|
||||||
some((tys, sub_origins)));
|
some((tys, sub_origins)));
|
||||||
}
|
}
|
||||||
typeck::dict_iface(iid) {
|
typeck::dict_iface(iid, tps) {
|
||||||
ret trans_iface_callee(bcx, callee_id, base, iid, n_method);
|
ret trans_iface_callee(bcx, base, callee_id, n_method);
|
||||||
}
|
}
|
||||||
typeck::dict_param(n_param, n_bound) {
|
typeck::dict_param(n_param, n_bound) {
|
||||||
fail "dict_param left in monomorphized function's dict substs";
|
fail "dict_param left in monomorphized function's dict substs";
|
||||||
|
@ -181,20 +129,9 @@ fn trans_monomorphized_callee(bcx: block, callee_id: ast::node_id,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// Method callee where the dict comes from a type param
|
|
||||||
fn trans_param_callee(bcx: block, callee_id: ast::node_id,
|
|
||||||
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, dict_env(dict, val), dict,
|
|
||||||
callee_id, iface_id, n_method)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Method callee where the dict comes from a boxed iface
|
// Method callee where the dict comes from a boxed iface
|
||||||
fn trans_iface_callee(bcx: block, callee_id: ast::node_id,
|
fn trans_iface_callee(bcx: block, base: @ast::expr,
|
||||||
base: @ast::expr, iface_id: ast::def_id, n_method: uint)
|
callee_id: ast::node_id, n_method: uint)
|
||||||
-> lval_maybe_callee {
|
-> lval_maybe_callee {
|
||||||
let {bcx, val} = trans_temp_expr(bcx, base);
|
let {bcx, val} = trans_temp_expr(bcx, base);
|
||||||
let dict = Load(bcx, PointerCast(bcx, GEPi(bcx, val, [0, 0]),
|
let dict = Load(bcx, PointerCast(bcx, GEPi(bcx, val, [0, 0]),
|
||||||
|
@ -202,8 +139,8 @@ fn trans_iface_callee(bcx: block, callee_id: ast::node_id,
|
||||||
let box = Load(bcx, GEPi(bcx, val, [0, 1]));
|
let box = Load(bcx, GEPi(bcx, val, [0, 1]));
|
||||||
// FIXME[impl] I doubt this is alignment-safe
|
// FIXME[impl] I doubt this is alignment-safe
|
||||||
let self = GEPi(bcx, box, [0, abi::box_field_body]);
|
let self = GEPi(bcx, box, [0, abi::box_field_body]);
|
||||||
trans_vtable_callee(bcx, dict_env(dict, self), dict,
|
trans_vtable_callee(bcx, self_env(self, expr_ty(bcx, base)), dict,
|
||||||
callee_id, iface_id, n_method)
|
callee_id, n_method)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn llfn_arg_tys(ft: TypeRef) -> {inputs: [TypeRef], output: TypeRef} {
|
fn llfn_arg_tys(ft: TypeRef) -> {inputs: [TypeRef], output: TypeRef} {
|
||||||
|
@ -214,18 +151,6 @@ fn llfn_arg_tys(ft: TypeRef) -> {inputs: [TypeRef], output: TypeRef} {
|
||||||
{inputs: args, output: out_ty}
|
{inputs: args, output: out_ty}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn trans_vtable(ccx: @crate_ctxt, id: ast::node_id, name: str,
|
|
||||||
ptrs: [ValueRef]) {
|
|
||||||
let tbl = C_struct(ptrs);
|
|
||||||
let vt_gvar = str::as_c_str(name, {|buf|
|
|
||||||
llvm::LLVMAddGlobal(ccx.llmod, val_ty(tbl), buf)
|
|
||||||
});
|
|
||||||
llvm::LLVMSetInitializer(vt_gvar, tbl);
|
|
||||||
llvm::LLVMSetGlobalConstant(vt_gvar, lib::llvm::True);
|
|
||||||
ccx.item_vals.insert(id, vt_gvar);
|
|
||||||
ccx.item_symbols.insert(id, name);
|
|
||||||
}
|
|
||||||
|
|
||||||
fn find_dict_in_fn_ctxt(ps: param_substs, n_param: uint, n_bound: uint)
|
fn find_dict_in_fn_ctxt(ps: param_substs, n_param: uint, n_bound: uint)
|
||||||
-> typeck::dict_origin {
|
-> typeck::dict_origin {
|
||||||
let dict_off = n_bound, i = 0u;
|
let dict_off = n_bound, i = 0u;
|
||||||
|
@ -241,150 +166,93 @@ fn find_dict_in_fn_ctxt(ps: param_substs, n_param: uint, n_bound: uint)
|
||||||
option::get(ps.dicts)[dict_off]
|
option::get(ps.dicts)[dict_off]
|
||||||
}
|
}
|
||||||
|
|
||||||
fn resolve_dicts_in_fn_ctxt(fcx: fn_ctxt, dicts: typeck::dict_res)
|
fn resolve_vtables_in_fn_ctxt(fcx: fn_ctxt, vts: typeck::dict_res)
|
||||||
-> option<typeck::dict_res> {
|
-> typeck::dict_res {
|
||||||
let result = [];
|
@vec::map(*vts, {|d| resolve_vtable_in_fn_ctxt(fcx, d)})
|
||||||
for dict in *dicts {
|
}
|
||||||
result += [alt dict {
|
|
||||||
typeck::dict_static(iid, tys, sub) {
|
fn resolve_vtable_in_fn_ctxt(fcx: fn_ctxt, vt: typeck::dict_origin)
|
||||||
alt resolve_dicts_in_fn_ctxt(fcx, sub) {
|
-> typeck::dict_origin {
|
||||||
some(sub) {
|
alt vt {
|
||||||
let tys = alt fcx.param_substs {
|
typeck::dict_static(iid, tys, sub) {
|
||||||
some(substs) {
|
let tys = alt fcx.param_substs {
|
||||||
vec::map(tys, {|t|
|
some(substs) {
|
||||||
ty::substitute_type_params(fcx.ccx.tcx, substs.tys, t)
|
vec::map(tys, {|t|
|
||||||
})
|
ty::substitute_type_params(fcx.ccx.tcx, substs.tys, t)
|
||||||
}
|
})
|
||||||
_ { tys }
|
|
||||||
};
|
|
||||||
typeck::dict_static(iid, tys, sub)
|
|
||||||
}
|
|
||||||
none { ret none; }
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
typeck::dict_param(n_param, n_bound) {
|
_ { tys }
|
||||||
alt fcx.param_substs {
|
};
|
||||||
some(substs) {
|
typeck::dict_static(iid, tys, resolve_vtables_in_fn_ctxt(fcx, sub))
|
||||||
find_dict_in_fn_ctxt(substs, n_param, n_bound)
|
}
|
||||||
}
|
typeck::dict_param(n_param, n_bound) {
|
||||||
none { ret none; }
|
alt check fcx.param_substs {
|
||||||
}
|
some(substs) {
|
||||||
|
find_dict_in_fn_ctxt(substs, n_param, n_bound)
|
||||||
}
|
}
|
||||||
_ { dict }
|
}
|
||||||
}];
|
}
|
||||||
|
_ { vt }
|
||||||
}
|
}
|
||||||
some(@result)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn trans_wrapper(ccx: @crate_ctxt, pt: path, llfty: TypeRef,
|
fn vtable_id(origin: typeck::dict_origin) -> mono_id {
|
||||||
fill: fn(ValueRef, block) -> block)
|
alt check origin {
|
||||||
-> ValueRef {
|
typeck::dict_static(impl_id, substs, sub_dicts) {
|
||||||
let name = link::mangle_internal_name_by_path(ccx, pt);
|
@{def: impl_id, substs: substs,
|
||||||
let llfn = decl_internal_cdecl_fn(ccx.llmod, name, llfty);
|
dicts: if (*sub_dicts).len() == 0u { no_dicts }
|
||||||
let fcx = new_fn_ctxt(ccx, [], llfn, none);
|
else { some_dicts(vec::map(*sub_dicts, vtable_id)) } }
|
||||||
let bcx = top_scope_block(fcx, none), lltop = bcx.llbb;
|
}
|
||||||
let bcx = fill(llfn, bcx);
|
typeck::dict_iface(iface_id, substs) {
|
||||||
build_return(bcx);
|
@{def: iface_id, substs: substs, dicts: no_dicts}
|
||||||
finish_fn(fcx, lltop);
|
}
|
||||||
ret llfn;
|
|
||||||
}
|
|
||||||
|
|
||||||
fn trans_impl_wrapper(ccx: @crate_ctxt, pt: path,
|
|
||||||
extra_tps: [ty::param_bounds], real_fn: ValueRef)
|
|
||||||
-> ValueRef {
|
|
||||||
let {inputs: real_args, output: real_ret} =
|
|
||||||
llfn_arg_tys(llvm::LLVMGetElementType(val_ty(real_fn)));
|
|
||||||
let extra_ptrs = [];
|
|
||||||
for tp in extra_tps {
|
|
||||||
extra_ptrs += [T_ptr(ccx.tydesc_type)];
|
|
||||||
for bound in *tp {
|
|
||||||
alt bound {
|
|
||||||
ty::bound_iface(_) { extra_ptrs += [T_ptr(T_dict())]; }
|
|
||||||
_ {}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
let env_ty = T_ptr(T_struct([T_ptr(T_i8())] + extra_ptrs));
|
|
||||||
let n_extra_ptrs = extra_ptrs.len();
|
|
||||||
|
|
||||||
let wrap_args = [T_ptr(T_dict())] +
|
|
||||||
vec::slice(real_args, 0u, first_tp_arg) +
|
|
||||||
vec::slice(real_args, first_tp_arg + n_extra_ptrs, real_args.len());
|
|
||||||
let llfn_ty = T_fn(wrap_args, real_ret);
|
|
||||||
trans_wrapper(ccx, pt, llfn_ty, {|llfn, bcx|
|
|
||||||
let dict = PointerCast(bcx, LLVMGetParam(llfn, 0 as c_uint), env_ty);
|
|
||||||
// retptr, self
|
|
||||||
let args = [LLVMGetParam(llfn, 1 as c_uint),
|
|
||||||
LLVMGetParam(llfn, 2 as c_uint)];
|
|
||||||
let i = 0u;
|
|
||||||
// saved tydescs/dicts
|
|
||||||
while i < n_extra_ptrs {
|
|
||||||
i += 1u;
|
|
||||||
args += [load_inbounds(bcx, dict, [0, i as int])];
|
|
||||||
}
|
|
||||||
// the rest of the parameters
|
|
||||||
let j = 3u as c_uint;
|
|
||||||
let params_total = llvm::LLVMCountParamTypes(llfn_ty);
|
|
||||||
while j < params_total {
|
|
||||||
args += [LLVMGetParam(llfn, j)];
|
|
||||||
j += 1u as c_uint;
|
|
||||||
}
|
|
||||||
Call(bcx, real_fn, args);
|
|
||||||
bcx
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn trans_impl_vtable(ccx: @crate_ctxt, pt: path,
|
fn get_vtable(ccx: @crate_ctxt, origin: typeck::dict_origin)
|
||||||
iface_id: ast::def_id, ms: [@ast::method],
|
-> ValueRef {
|
||||||
tps: [ast::ty_param], it: @ast::item) {
|
let hash_id = vtable_id(origin);
|
||||||
if tps.len() > 0u { ret; }
|
alt ccx.vtables.find(hash_id) {
|
||||||
let new_pt = pt + [path_name(it.ident), path_name(int::str(it.id)),
|
some(val) { val }
|
||||||
path_name("wrap")];
|
none {
|
||||||
let extra_tps = param_bounds(ccx, tps);
|
alt check origin {
|
||||||
let ptrs = vec::map(*ty::iface_methods(ccx.tcx, iface_id), {|im|
|
typeck::dict_static(id, substs, sub_dicts) {
|
||||||
alt vec::find(ms, {|m| m.ident == im.ident}) {
|
make_impl_vtable(ccx, id, substs, sub_dicts)
|
||||||
some(m) {
|
|
||||||
trans_impl_wrapper(ccx, new_pt + [path_name(m.ident)],
|
|
||||||
extra_tps, get_item_val(ccx, m.id))
|
|
||||||
}
|
|
||||||
_ {
|
|
||||||
ccx.sess.span_bug(it.span, "no matching method \
|
|
||||||
in trans_impl_vtable");
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn make_vtable(ccx: @crate_ctxt, ptrs: [ValueRef]) -> ValueRef {
|
||||||
|
let tbl = C_struct(ptrs);
|
||||||
|
let vt_gvar = str::as_c_str(ccx.names("vtable"), {|buf|
|
||||||
|
llvm::LLVMAddGlobal(ccx.llmod, val_ty(tbl), buf)
|
||||||
});
|
});
|
||||||
let s = link::mangle_internal_name_by_path(
|
llvm::LLVMSetInitializer(vt_gvar, tbl);
|
||||||
ccx, new_pt + [path_name("!vtable")]);
|
llvm::LLVMSetGlobalConstant(vt_gvar, lib::llvm::True);
|
||||||
trans_vtable(ccx, it.id, s, ptrs);
|
lib::llvm::SetLinkage(vt_gvar, lib::llvm::InternalLinkage);
|
||||||
|
vt_gvar
|
||||||
}
|
}
|
||||||
|
|
||||||
fn trans_iface_wrapper(ccx: @crate_ctxt, pt: path, m: ty::method,
|
fn make_impl_vtable(ccx: @crate_ctxt, impl_id: ast::def_id, substs: [ty::t],
|
||||||
n: uint) -> ValueRef {
|
dicts: typeck::dict_res) -> ValueRef {
|
||||||
let {llty: llfty, _} = wrapper_fn_ty(ccx, T_ptr(T_i8()),
|
let tcx = ccx.tcx;
|
||||||
ty::mk_fn(ccx.tcx, m.fty), m.tps);
|
let ifce_id = ty::ty_to_def_id(option::get(ty::impl_iface(tcx, impl_id)));
|
||||||
trans_wrapper(ccx, pt, llfty, {|llfn, bcx|
|
make_vtable(ccx, vec::map(*ty::iface_methods(tcx, ifce_id), {|im|
|
||||||
let param = PointerCast(bcx, LLVMGetParam(llfn, 2u as c_uint),
|
let fty = ty::substitute_type_params(tcx, substs,
|
||||||
T_ptr(T_opaque_iface(ccx)));
|
ty::mk_fn(tcx, im.fty));
|
||||||
let dict = Load(bcx, GEPi(bcx, param, [0, 0]));
|
if (*im.tps).len() > 0u || ty::type_has_vars(fty) {
|
||||||
let box = Load(bcx, GEPi(bcx, param, [0, 1]));
|
C_null(type_of_fn_from_ty(ccx, fty, []))
|
||||||
let self = GEPi(bcx, box, [0, abi::box_field_body]);
|
} else {
|
||||||
let vtable = PointerCast(bcx, Load(bcx, GEPi(bcx, dict, [0, 0])),
|
let m_id = method_with_name(ccx, impl_id, im.ident);
|
||||||
T_ptr(T_array(T_ptr(llfty), n + 1u)));
|
option::get(monomorphic_fn(ccx, m_id, substs, some(dicts))).llfn
|
||||||
let mptr = Load(bcx, GEPi(bcx, vtable, [0, n as int]));
|
|
||||||
let args = [PointerCast(bcx, dict, T_ptr(T_i8())),
|
|
||||||
LLVMGetParam(llfn, 1u as c_uint),
|
|
||||||
PointerCast(bcx, self, T_opaque_cbox_ptr(ccx))];
|
|
||||||
let i = 3u as c_uint, total = llvm::LLVMCountParamTypes(llfty);
|
|
||||||
while i < total {
|
|
||||||
args += [LLVMGetParam(llfn, i)];
|
|
||||||
i += 1u as c_uint;
|
|
||||||
}
|
}
|
||||||
Call(bcx, mptr, args);
|
}))
|
||||||
bcx
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn trans_iface_vtable(ccx: @crate_ctxt, pt: path, it: @ast::item) {
|
/*
|
||||||
|
fn make_iface_vtable(ccx: @crate_ctxt, pt: path, it: @ast::item) {
|
||||||
let new_pt = pt + [path_name(it.ident), path_name(int::str(it.id))];
|
let new_pt = pt + [path_name(it.ident), path_name(int::str(it.id))];
|
||||||
let i_did = local_def(it.id), i = 0u;
|
let i_did = local_def(it.id), i = 0u;
|
||||||
let ptrs = vec::map(*ty::iface_methods(ccx.tcx, i_did), {|m|
|
let ptrs = vec::map(*ty::iface_methods(ccx.tcx, i_did), {|m|
|
||||||
|
@ -528,6 +396,7 @@ fn get_dict_ptrs(bcx: block, origin: typeck::dict_origin)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}*/
|
||||||
|
|
||||||
fn trans_cast(bcx: block, val: @ast::expr, id: ast::node_id, dest: dest)
|
fn trans_cast(bcx: block, val: @ast::expr, id: ast::node_id, dest: dest)
|
||||||
-> block {
|
-> block {
|
||||||
|
@ -541,8 +410,10 @@ fn trans_cast(bcx: block, val: @ast::expr, id: ast::node_id, dest: dest)
|
||||||
let result = get_dest_addr(dest);
|
let result = get_dest_addr(dest);
|
||||||
Store(bcx, box, PointerCast(bcx, GEPi(bcx, result, [0, 1]),
|
Store(bcx, box, PointerCast(bcx, GEPi(bcx, result, [0, 1]),
|
||||||
T_ptr(val_ty(box))));
|
T_ptr(val_ty(box))));
|
||||||
let {bcx, val: dict} = get_dict(bcx, ccx.maps.dict_map.get(id)[0]);
|
let orig = ccx.maps.dict_map.get(id)[0];
|
||||||
Store(bcx, dict, PointerCast(bcx, GEPi(bcx, result, [0, 0]),
|
let orig = resolve_vtable_in_fn_ctxt(bcx.fcx, orig);
|
||||||
T_ptr(val_ty(dict))));
|
let vtable = get_vtable(bcx.ccx(), orig);
|
||||||
|
Store(bcx, vtable, PointerCast(bcx, GEPi(bcx, result, [0, 0]),
|
||||||
|
T_ptr(val_ty(vtable))));
|
||||||
bcx
|
bcx
|
||||||
}
|
}
|
||||||
|
|
|
@ -92,6 +92,7 @@ export region, re_named, re_caller, re_block, re_inferred;
|
||||||
export get, type_has_params, type_has_vars, type_has_rptrs, type_id;
|
export get, type_has_params, type_has_vars, type_has_rptrs, type_id;
|
||||||
export same_type;
|
export same_type;
|
||||||
export ty_var_id;
|
export ty_var_id;
|
||||||
|
export ty_to_def_id;
|
||||||
export ty_fn_args;
|
export ty_fn_args;
|
||||||
export type_constr;
|
export type_constr;
|
||||||
export kind, kind_sendable, kind_copyable, kind_noncopyable;
|
export kind, kind_sendable, kind_copyable, kind_noncopyable;
|
||||||
|
@ -2290,6 +2291,14 @@ fn impl_iface(cx: ctxt, id: ast::def_id) -> option<t> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn ty_to_def_id(ty: t) -> ast::def_id {
|
||||||
|
alt check get(ty).struct {
|
||||||
|
ty_iface(id, _) | ty_class(id, _) | ty_res(id, _, _) | ty_enum(id, _) {
|
||||||
|
id
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Enum information
|
// Enum information
|
||||||
type variant_info = @{args: [t], ctor_ty: t, name: str,
|
type variant_info = @{args: [t], ctor_ty: t, name: str,
|
||||||
id: ast::def_id, disr_val: int};
|
id: ast::def_id, disr_val: int};
|
||||||
|
|
|
@ -34,7 +34,7 @@ enum dict_origin {
|
||||||
dict_static(ast::def_id, [ty::t], dict_res),
|
dict_static(ast::def_id, [ty::t], dict_res),
|
||||||
// Param number, bound number
|
// Param number, bound number
|
||||||
dict_param(uint, uint),
|
dict_param(uint, uint),
|
||||||
dict_iface(ast::def_id),
|
dict_iface(ast::def_id, [ty::t]),
|
||||||
}
|
}
|
||||||
type dict_map = hashmap<ast::node_id, dict_res>;
|
type dict_map = hashmap<ast::node_id, dict_res>;
|
||||||
|
|
||||||
|
@ -3361,8 +3361,8 @@ mod dict {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ty::ty_iface(did, _) if iface_id == did {
|
ty::ty_iface(did, tps) if iface_id == did {
|
||||||
ret dict_iface(did);
|
ret dict_iface(did, tps);
|
||||||
}
|
}
|
||||||
_ {
|
_ {
|
||||||
let found = none;
|
let found = none;
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue