提交 c886629d 编写于 作者: P Patrick Walton

rustc: Implement monomorphic default methods. r=nmatsakis

上级 2a1aa9fb
......@@ -124,5 +124,7 @@ enum astencode_tag { // Reserves 0x50 -- 0x6f
tag_table_legacy_boxed_trait = 0x63
}
const tag_item_trait_method_sort: uint = 0x70;
type link_meta = {name: ~str, vers: ~str, extras_hash: ~str};
......@@ -23,6 +23,7 @@
export get_enum_variants;
export get_impls_for_mod;
export get_trait_methods;
export get_provided_trait_methods;
export get_method_names_if_trait;
export get_item_attrs;
export each_path;
......@@ -31,6 +32,12 @@
export get_impl_method;
export get_item_path;
export maybe_get_item_ast, found_ast, found, found_parent, not_found;
export ProvidedTraitMethodInfo;
struct ProvidedTraitMethodInfo {
ty: ty::method,
def_id: ast::def_id
}
fn get_symbol(cstore: cstore::cstore, def: ast::def_id) -> ~str {
let cdata = cstore::get_crate_data(cstore, def.crate).data;
......@@ -99,6 +106,13 @@ fn get_trait_methods(tcx: ty::ctxt, def: ast::def_id) -> @~[ty::method] {
decoder::get_trait_methods(cstore.intr, cdata, def.node, tcx)
}
fn get_provided_trait_methods(tcx: ty::ctxt, def: ast::def_id) ->
~[ProvidedTraitMethodInfo] {
let cstore = tcx.cstore;
let cdata = cstore::get_crate_data(cstore, def.crate);
decoder::get_provided_trait_methods(cstore.intr, cdata, def.node, tcx)
}
fn get_method_names_if_trait(cstore: cstore::cstore, def: ast::def_id)
-> Option<@DVec<(ast::ident, ast::self_ty_)>> {
......
......@@ -19,6 +19,7 @@
use common::*;
use syntax::parse::token::ident_interner;
use hash::{Hash, HashUtil};
use csearch::ProvidedTraitMethodInfo;
export class_dtor;
export get_class_fields;
......@@ -40,6 +41,7 @@
export get_crate_vers;
export get_impls_for_mod;
export get_trait_methods;
export get_provided_trait_methods;
export get_method_names_if_trait;
export get_item_attrs;
export get_crate_module_paths;
......@@ -164,6 +166,13 @@ fn item_family(item: ebml::Doc) -> Family {
}
}
fn item_method_sort(item: ebml::Doc) -> char {
for ebml::tagged_docs(item, tag_item_trait_method_sort) |doc| {
return str::from_bytes(ebml::doc_data(doc))[0] as char;
}
return 'r';
}
fn item_symbol(item: ebml::Doc) -> ~str {
let sym = ebml::get_doc(item, tag_items_data_item_symbol);
return str::from_bytes(ebml::doc_data(sym));
......@@ -701,6 +710,7 @@ fn get_trait_methods(intr: @ident_interner, cdata: cmd, id: ast::node_id,
let bounds = item_ty_param_bounds(mth, tcx, cdata);
let name = item_name(intr, mth);
let ty = doc_type(mth, tcx, cdata);
let def_id = item_def_id(mth, cdata);
let fty = match ty::get(ty).sty {
ty::ty_fn(f) => f,
_ => {
......@@ -708,14 +718,52 @@ fn get_trait_methods(intr: @ident_interner, cdata: cmd, id: ast::node_id,
~"get_trait_methods: id has non-function type");
} };
let self_ty = get_self_ty(mth);
result.push({ident: name, tps: bounds, fty: fty,
self_ty: self_ty,
vis: ast::public});
result.push({ident: name, tps: bounds, fty: fty, self_ty: self_ty,
vis: ast::public, def_id: def_id});
}
debug!("get_trait_methods: }");
@result
}
fn get_provided_trait_methods(intr: @ident_interner, cdata: cmd,
id: ast::node_id, tcx: ty::ctxt) ->
~[ProvidedTraitMethodInfo] {
let data = cdata.data;
let item = lookup_item(id, data);
let mut result = ~[];
for ebml::tagged_docs(item, tag_item_trait_method) |mth| {
if item_method_sort(mth) != 'p' { loop; }
let did = item_def_id(mth, cdata);
let bounds = item_ty_param_bounds(mth, tcx, cdata);
let name = item_name(intr, mth);
let ty = doc_type(mth, tcx, cdata);
let fty;
match ty::get(ty).sty {
ty::ty_fn(f) => fty = f,
_ => {
tcx.diag.handler().bug(~"get_provided_trait_methods(): id \
has non-function type");
}
}
let self_ty = get_self_ty(mth);
let ty_method = {ident: name, tps: bounds, fty: fty, self_ty: self_ty,
vis: ast::public, def_id: did};
let provided_trait_method_info = ProvidedTraitMethodInfo {
ty: ty_method,
def_id: did
};
vec::push(&mut result, move provided_trait_method_info);
}
return move result;
}
// If the item in question is a trait, returns its set of methods and
// their self types. Otherwise, returns none. This overlaps in an
// annoying way with get_trait_methods.
......
......@@ -388,6 +388,12 @@ fn encode_self_type(ebml_w: ebml::Serializer, self_type: ast::self_ty_) {
ebml_w.end_tag();
}
fn encode_method_sort(ebml_w: ebml::Serializer, sort: char) {
ebml_w.start_tag(tag_item_trait_method_sort);
ebml_w.writer.write(&[ sort as u8 ]);
ebml_w.end_tag();
}
/* Returns an index of items in this class */
fn encode_info_for_class(ecx: @encode_ctxt, ebml_w: ebml::Serializer,
id: node_id, path: ast_map::path,
......@@ -726,6 +732,8 @@ fn add_to_index_(item: @item, ebml_w: ebml::Serializer,
}
}
item_trait(tps, traits, ms) => {
let provided_methods = dvec::DVec();
add_to_index();
ebml_w.start_tag(tag_items_data_item);
encode_def_id(ebml_w, local_def(item.id));
......@@ -746,12 +754,21 @@ fn add_to_index_(item: @item, ebml_w: ebml::Serializer,
encode_type(ecx, ebml_w, ty::mk_fn(tcx, mty.fty));
encode_family(ebml_w, purity_fn_family(mty.fty.meta.purity));
encode_self_type(ebml_w, mty.self_ty);
encode_method_sort(ebml_w, 'r');
ebml_w.end_tag();
}
provided(m) => {
encode_info_for_method(ecx, ebml_w, path,
should_inline(m.attrs), item.id,
m, m.tps);
provided_methods.push(m);
ebml_w.start_tag(tag_item_trait_method);
encode_def_id(ebml_w, local_def(m.id));
encode_name(ecx, ebml_w, mty.ident);
encode_type_param_bounds(ebml_w, ecx, m.tps);
encode_type(ecx, ebml_w, ty::mk_fn(tcx, mty.fty));
encode_family(ebml_w, purity_fn_family(mty.fty.meta.purity));
encode_self_type(ebml_w, mty.self_ty);
encode_method_sort(ebml_w, 'p');
ebml_w.end_tag();
}
}
i += 1u;
......@@ -785,7 +802,12 @@ fn add_to_index_(item: @item, ebml_w: ebml::Serializer,
ebml_w.end_tag();
}
// Finally, output all the provided methods as items.
for provided_methods.each |m| {
index.push({val: m.id, pos: ebml_w.writer.tell()});
encode_info_for_method(ecx, ebml_w, path, true, item.id, *m,
m.tps);
}
}
item_mac(*) => fail ~"item macros unimplemented"
}
......
......@@ -4680,6 +4680,9 @@ fn record_candidate_traits_for_expr_if_necessary(expr: @expr) {
}
fn search_for_traits_containing_method(name: ident) -> @DVec<def_id> {
debug!("(searching for traits containing method) looking for '%s'",
self.session.str_of(name));
let found_traits = @DVec();
let mut search_module = self.current_module;
loop {
......@@ -4687,8 +4690,8 @@ fn search_for_traits_containing_method(name: ident) -> @DVec<def_id> {
match copy self.current_trait_refs {
Some(trait_def_ids) => {
for trait_def_ids.each |trait_def_id| {
self.add_trait_info_if_containing_method
(found_traits, *trait_def_id, name);
self.add_trait_info_if_containing_method(
found_traits, *trait_def_id, name);
}
}
None => {
......@@ -4702,8 +4705,8 @@ fn search_for_traits_containing_method(name: ident) -> @DVec<def_id> {
Some(def) => {
match def.def {
def_ty(trait_def_id) => {
self.add_trait_info_if_containing_method
(found_traits, trait_def_id, name);
self.add_trait_info_if_containing_method(
found_traits, trait_def_id, name);
}
_ => {
// Continue.
......@@ -4730,8 +4733,8 @@ fn search_for_traits_containing_method(name: ident) -> @DVec<def_id> {
match def.def {
def_ty(trait_def_id) => {
self.
add_trait_info_if_containing_method
(found_traits, trait_def_id, name);
add_trait_info_if_containing_method(
found_traits, trait_def_id, name);
}
_ => {
// Continue.
......@@ -4766,6 +4769,12 @@ fn add_trait_info_if_containing_method(found_traits: @DVec<def_id>,
trait_def_id: def_id,
name: ident) {
debug!("(adding trait info if containing method) trying trait %d:%d \
for method '%s'",
trait_def_id.crate,
trait_def_id.node,
self.session.str_of(name));
match self.trait_info.find(trait_def_id) {
Some(trait_info) if trait_info.contains_key(name) => {
debug!("(adding trait info if containing method) found trait \
......
......@@ -206,7 +206,7 @@ fn GEP_enum(bcx: block, llblobptr: ValueRef, enum_id: ast::def_id,
assert ix < variant.args.len();
let arg_lltys = vec::map(variant.args, |aty| {
type_of(ccx, ty::subst_tps(ccx.tcx, ty_substs, *aty))
type_of(ccx, ty::subst_tps(ccx.tcx, ty_substs, None, *aty))
});
let typed_blobptr = PointerCast(bcx, llblobptr,
T_ptr(T_struct(arg_lltys)));
......@@ -385,16 +385,16 @@ fn get_res_dtor(ccx: @crate_ctxt, did: ast::def_id,
let _icx = ccx.insn_ctxt("trans_res_dtor");
if (substs.is_not_empty()) {
let did = if did.crate != ast::local_crate {
inline::maybe_instantiate_inline(ccx, did)
inline::maybe_instantiate_inline(ccx, did, true)
} else { did };
assert did.crate == ast::local_crate;
monomorphize::monomorphic_fn(ccx, did, substs, None, None).val
monomorphize::monomorphic_fn(ccx, did, substs, None, None, None).val
} else if did.crate == ast::local_crate {
get_item_val(ccx, did.node)
} else {
let tcx = ccx.tcx;
let name = csearch::get_symbol(ccx.sess.cstore, did);
let class_ty = ty::subst_tps(tcx, substs,
let class_ty = ty::subst_tps(tcx, substs, None,
ty::lookup_item_type(tcx, parent_id).ty);
let llty = type_of_dtor(ccx, class_ty);
get_extern_fn(ccx.externs, ccx.llmod, name, lib::llvm::CCallConv,
......@@ -529,7 +529,8 @@ fn iter_variant(cx: block, a_tup: ValueRef,
let v_id = variant.id;
for vec::each(fn_ty.sig.inputs) |a| {
let llfldp_a = GEP_enum(cx, a_tup, tid, v_id, tps, j);
let ty_subst = ty::subst_tps(ccx.tcx, tps, a.ty);
// XXX: Is "None" right here?
let ty_subst = ty::subst_tps(ccx.tcx, tps, None, a.ty);
cx = f(cx, llfldp_a, ty_subst);
j += 1u;
}
......@@ -1392,8 +1393,11 @@ fn mk_standard_basic_blocks(llfn: ValueRef) ->
// - create_llargs_for_fn_args.
// - new_fn_ctxt
// - trans_args
fn new_fn_ctxt_w_id(ccx: @crate_ctxt, path: path,
llfndecl: ValueRef, id: ast::node_id,
fn new_fn_ctxt_w_id(ccx: @crate_ctxt,
path: path,
llfndecl: ValueRef,
id: ast::node_id,
impl_id: Option<ast::def_id>,
param_substs: Option<param_substs>,
sp: Option<span>) -> fn_ctxt {
let llbbs = mk_standard_basic_blocks(llfndecl);
......@@ -1410,6 +1414,7 @@ fn new_fn_ctxt_w_id(ccx: @crate_ctxt, path: path,
lllocals: HashMap(),
llupvars: HashMap(),
id: id,
impl_id: impl_id,
param_substs: param_substs,
span: sp,
path: path,
......@@ -1418,7 +1423,7 @@ fn new_fn_ctxt_w_id(ccx: @crate_ctxt, path: path,
fn new_fn_ctxt(ccx: @crate_ctxt, path: path, llfndecl: ValueRef,
sp: Option<span>) -> fn_ctxt {
return new_fn_ctxt_w_id(ccx, path, llfndecl, -1, None, sp);
return new_fn_ctxt_w_id(ccx, path, llfndecl, -1, None, None, sp);
}
// NB: must keep 4 fns in sync:
......@@ -1561,6 +1566,7 @@ fn trans_closure(ccx: @crate_ctxt, path: path, decl: ast::fn_decl,
ty_self: self_arg,
param_substs: Option<param_substs>,
id: ast::node_id,
impl_id: Option<ast::def_id>,
maybe_load_env: fn(fn_ctxt),
finish: fn(block)) {
ccx.stats.n_closures += 1;
......@@ -1568,7 +1574,7 @@ fn trans_closure(ccx: @crate_ctxt, path: path, decl: ast::fn_decl,
set_uwtable(llfndecl);
// Set up arguments to the function.
let fcx = new_fn_ctxt_w_id(ccx, path, llfndecl, id, param_substs,
let fcx = new_fn_ctxt_w_id(ccx, path, llfndecl, id, impl_id, param_substs,
Some(body.span));
let raw_llargs = create_llargs_for_fn_args(fcx, ty_self, decl.inputs);
......@@ -1620,14 +1626,15 @@ fn trans_fn(ccx: @crate_ctxt,
llfndecl: ValueRef,
ty_self: self_arg,
param_substs: Option<param_substs>,
id: ast::node_id) {
id: ast::node_id,
impl_id: Option<ast::def_id>) {
let do_time = ccx.sess.trans_stats();
let start = if do_time { time::get_time() }
else { {sec: 0i64, nsec: 0i32} };
let _icx = ccx.insn_ctxt("trans_fn");
ccx.stats.n_fns += 1;
trans_closure(ccx, path, decl, body, llfndecl, ty_self,
param_substs, id,
param_substs, id, impl_id,
|fcx| {
if ccx.sess.opts.extra_debuginfo {
debuginfo::create_function(fcx);
......@@ -1654,7 +1661,7 @@ fn trans_enum_variant(ccx: @crate_ctxt,
ty: varg.ty,
ident: special_idents::arg,
id: varg.id});
let fcx = new_fn_ctxt_w_id(ccx, ~[], llfndecl, variant.node.id,
let fcx = new_fn_ctxt_w_id(ccx, ~[], llfndecl, variant.node.id, None,
param_substs, None);
let raw_llargs = create_llargs_for_fn_args(fcx, no_self, fn_args);
let ty_param_substs = match param_substs {
......@@ -1704,7 +1711,7 @@ fn trans_class_dtor(ccx: @crate_ctxt, path: path,
let mut class_ty = ty::lookup_item_type(tcx, parent_id).ty;
/* Substitute in the class type if necessary */
do option::iter(&psubsts) |ss| {
class_ty = ty::subst_tps(tcx, ss.tys, class_ty);
class_ty = ty::subst_tps(tcx, ss.tys, ss.self_ty, class_ty);
}
/* The dtor takes a (null) output pointer, and a self argument,
......@@ -1724,7 +1731,7 @@ fn trans_class_dtor(ccx: @crate_ctxt, path: path,
}
/* Translate the dtor body */
trans_fn(ccx, path, ast_util::dtor_dec(),
body, lldecl, impl_self(class_ty), psubsts, dtor_id);
body, lldecl, impl_self(class_ty), psubsts, dtor_id, None);
lldecl
}
......@@ -1777,7 +1784,7 @@ fn trans_item(ccx: @crate_ctxt, item: ast::item) {
let llfndecl = get_item_val(ccx, item.id);
trans_fn(ccx,
vec::append(*path, ~[path_name(item.ident)]),
decl, body, llfndecl, no_self, None, item.id);
decl, body, llfndecl, no_self, None, item.id, None);
} else {
for vec::each(body.node.stmts) |stmt| {
match stmt.node {
......@@ -1789,48 +1796,8 @@ fn trans_item(ccx: @crate_ctxt, item: ast::item) {
}
}
}
ast::item_impl(tps, trait_refs, self_ast_ty, ms) => {
meth::trans_impl(ccx, *path, item.ident, ms, tps, None);
// Translate any methods that have provided implementations.
for trait_refs.each |trait_ref_ptr| {
let trait_def = ccx.tcx.def_map.get(trait_ref_ptr.ref_id);
// XXX: Cross-crate default methods.
let trait_id = def_id_of_def(trait_def);
if trait_id.crate != ast::local_crate {
loop;
}
// Get the self type.
let self_ty;
match ccx.tcx.ast_ty_to_ty_cache.get(self_ast_ty) {
ty::atttce_resolved(self_type) => self_ty = self_type,
ty::atttce_unresolved => {
ccx.tcx.sess.impossible_case(item.span,
~"didn't cache self ast ty");
}
}
match ccx.tcx.items.get(trait_id.node) {
ast_map::node_item(trait_item, _) => {
match trait_item.node {
ast::item_trait(tps, _, trait_methods) => {
trans_trait(ccx, tps, trait_methods, path,
item.ident, self_ty);
}
_ => {
ccx.tcx.sess.impossible_case(item.span,
~"trait item not a \
trait");
}
}
}
_ => {
ccx.tcx.sess.impossible_case(item.span, ~"no trait item");
}
}
}
ast::item_impl(tps, _, _, ms) => {
meth::trans_impl(ccx, *path, item.ident, ms, tps, None, item.id);
}
ast::item_mod(m) => {
trans_mod(ccx, m);
......@@ -1871,16 +1838,7 @@ fn trans_struct_def(ccx: @crate_ctxt, struct_def: @ast::struct_def,
// If there are ty params, the ctor will get monomorphized
// Translate methods
meth::trans_impl(ccx, *path, ident, struct_def.methods, tps, None);
}
fn trans_trait(ccx: @crate_ctxt, tps: ~[ast::ty_param],
trait_methods: ~[ast::trait_method],
path: @ast_map::path, ident: ast::ident,
self_ty: ty::t) {
// Translate any methods that have provided implementations
let (_, provided_methods) = ast_util::split_trait_methods(trait_methods);
meth::trans_impl(ccx, *path, ident, provided_methods, tps, Some(self_ty));
meth::trans_impl(ccx, *path, ident, struct_def.methods, tps, None, id);
}
// Translate a module. Doing this amounts to translating the items in the
......@@ -2035,7 +1993,7 @@ fn get_dtor_symbol(ccx: @crate_ctxt, path: path, id: ast::node_id,
// this to item_symbols
match substs {
Some(ss) => {
let mono_ty = ty::subst_tps(ccx.tcx, ss.tys, t);
let mono_ty = ty::subst_tps(ccx.tcx, ss.tys, ss.self_ty, t);
mangle_exported_name(
ccx,
vec::append(path,
......
......@@ -184,21 +184,31 @@ fn trans_fn_ref_with_vtables(
// Polytype of the function item (may have type params)
let fn_tpt = ty::lookup_item_type(tcx, def_id);
// Modify the def_id if this is a default method; we want to be
// monomorphizing the trait's code.
let (def_id, opt_impl_did) =
match tcx.provided_method_sources.find(def_id) {
None => (def_id, None),
Some(source) => (source.method_id, Some(source.impl_id))
};
// Check whether this fn has an inlined copy and, if so, redirect
// def_id to the local id of the inlined copy.
let def_id = {
if def_id.crate != ast::local_crate {
inline::maybe_instantiate_inline(ccx, def_id)
let may_translate = opt_impl_did.is_none();
inline::maybe_instantiate_inline(ccx, def_id, may_translate)
} else {
def_id
}
};
// We must monomorphise if the fn has type parameters or is a rust
// intrinsic. In particular, if we see an intrinsic that is
// inlined from a different crate, we want to reemit the intrinsic
// instead of trying to call it in the other crate.
let must_monomorphise = type_params.len() > 0 || {
// We must monomorphise if the fn has type parameters, is a rust
// intrinsic, or is a default method. In particular, if we see an
// intrinsic that is inlined from a different crate, we want to reemit the
// intrinsic instead of trying to call it in the other crate.
let must_monomorphise = type_params.len() > 0 ||
opt_impl_did.is_some() || {
if def_id.crate == ast::local_crate {
let map_node = session::expect(
ccx.sess,
......@@ -222,7 +232,7 @@ fn trans_fn_ref_with_vtables(
let mut {val, must_cast} =
monomorphize::monomorphic_fn(ccx, def_id, type_params,
vtables, Some(ref_id));
vtables, opt_impl_did, Some(ref_id));
if must_cast && ref_id != 0 {
// Monotype of the REFERENCE to the function (type params
// are subst'd)
......@@ -317,7 +327,9 @@ fn trans_rtcall_or_lang_call_with_type_params(bcx: block,
match callee.data {
Fn(fn_data) => {
let substituted = ty::subst_tps(callee.bcx.tcx(),
type_params, fty);
type_params,
None,
fty);
let mut llfnty = type_of::type_of(callee.bcx.ccx(),
substituted);
llfnty = T_ptr(struct_elt(llfnty, 0));
......
......@@ -372,7 +372,7 @@ fn trans_expr_fn(bcx: block,
let {llbox, cdata_ty, bcx} = build_closure(bcx, cap_vars, ck,
ret_handle);
trans_closure(ccx, sub_path, decl, body, llfn, no_self,
bcx.fcx.param_substs, id, |fcx| {
bcx.fcx.param_substs, id, None, |fcx| {
load_environment(fcx, cdata_ty, cap_vars,
ret_handle.is_some(), ck);
}, |bcx| {
......@@ -395,7 +395,7 @@ fn trans_expr_fn(bcx: block,
}
ty::proto_bare => {
trans_closure(ccx, sub_path, decl, body, llfn, no_self, None,
id, |_fcx| { }, |_bcx| { });
id, None, |_fcx| { }, |_bcx| { });
rslt(bcx, C_null(T_opaque_box_ptr(ccx)))
}
ty::proto_vstore(ty::vstore_fixed(_)) => {
......
......@@ -181,9 +181,12 @@ struct ValSelfData {
enum local_val { local_mem(ValueRef), local_imm(ValueRef), }
// Here `self_ty` is the real type of the self parameter to this method. It
// will only be set in the case of default methods.
type param_substs = {tys: ~[ty::t],
vtables: Option<typeck::vtable_res>,
bounds: @~[ty::param_bounds]};
bounds: @~[ty::param_bounds],
self_ty: Option<ty::t>};
fn param_substs_to_str(tcx: ty::ctxt, substs: &param_substs) -> ~str {
fmt!("param_substs {tys:%?, vtables:%?, bounds:%?}",
......@@ -220,6 +223,10 @@ fn param_substs_to_str(tcx: ty::ctxt, substs: &param_substs) -> ~str {
mut llreturn: BasicBlockRef,
// The 'self' value currently in use in this function, if there
// is one.
//
// NB: This is the type of the self *variable*, not the self *type*. The
// self type is set only for default methods, while the self variable is
// set for all methods.
mut llself: Option<ValSelfData>,
// The a value alloca'd for calls to upcalls.rust_personality. Used when
// outputting the resume instruction.
......@@ -240,6 +247,9 @@ fn param_substs_to_str(tcx: ty::ctxt, substs: &param_substs) -> ~str {
// a user-defined function.
id: ast::node_id,
// The def_id of the impl we're inside, or None if we aren't inside one.
impl_id: Option<ast::def_id>,
// If this function is being monomorphized, this contains the type
// substitutions used.
param_substs: Option<param_substs>,
......@@ -1110,7 +1120,11 @@ enum mono_param_id {
datum::DatumMode),
}
type mono_id_ = {def: ast::def_id, params: ~[mono_param_id]};
type mono_id_ = {
def: ast::def_id,
params: ~[mono_param_id],
impl_did_opt: Option<ast::def_id>
};
type mono_id = @mono_id_;
......@@ -1193,7 +1207,9 @@ fn path_str(sess: session::session, p: path) -> ~str {
fn monomorphize_type(bcx: block, t: ty::t) -> ty::t {
match bcx.fcx.param_substs {
Some(substs) => ty::subst_tps(bcx.tcx(), substs.tys, t),
Some(substs) => {
ty::subst_tps(bcx.tcx(), substs.tys, substs.self_ty, t)
}
_ => { assert !ty::type_has_params(t); t }
}
}
......@@ -1213,7 +1229,9 @@ fn node_id_type_params(bcx: block, id: ast::node_id) -> ~[ty::t] {
let params = ty::node_id_to_type_params(tcx, id);
match bcx.fcx.param_substs {
Some(substs) => {
vec::map(params, |t| ty::subst_tps(tcx, substs.tys, *t))
do vec::map(params) |t| {
ty::subst_tps(tcx, substs.tys, substs.self_ty, *t)
}
}
_ => params
}
......@@ -1241,7 +1259,9 @@ fn resolve_vtable_in_fn_ctxt(fcx: fn_ctxt, vt: typeck::vtable_origin)
typeck::vtable_static(trait_id, tys, sub) => {
let tys = match fcx.param_substs {
Some(substs) => {
vec::map(tys, |t| ty::subst_tps(tcx, substs.tys, *t))
do vec::map(tys) |t| {
ty::subst_tps(tcx, substs.tys, substs.self_ty, *t)
}
}
_ => tys
};
......
......@@ -793,7 +793,9 @@ fn trans_local_var(bcx: block, def: ast::def) -> Datum {
// This cast should not be necessary. We should cast self *once*,
// but right now this conflicts with default methods.
let llselfty = T_ptr(type_of::type_of(bcx.ccx(), self_info.t));
let real_self_ty = monomorphize_type(bcx, self_info.t);
let llselfty = T_ptr(type_of::type_of(bcx.ccx(), real_self_ty));
let casted_val = PointerCast(bcx, self_info.v, llselfty);
Datum {
val: casted_val,
......
......@@ -794,7 +794,7 @@ fn trans_intrinsic(ccx: @crate_ctxt, decl: ValueRef, item: @ast::foreign_item,
{
debug!("trans_intrinsic(item.ident=%s)", ccx.sess.str_of(item.ident));
let fcx = new_fn_ctxt_w_id(ccx, path, decl, item.id,
let fcx = new_fn_ctxt_w_id(ccx, path, decl, item.id, None,
Some(substs), Some(item.span));
let mut bcx = top_scope_block(fcx, None), lltop = bcx.llbb;
match ccx.sess.str_of(item.ident) {
......@@ -1025,7 +1025,7 @@ fn build_rust_fn(ccx: @crate_ctxt, path: ast_map::path,
)));
let llty = type_of_fn_from_ty(ccx, t);
let llfndecl = decl_internal_cdecl_fn(ccx.llmod, ps, llty);
trans_fn(ccx, path, decl, body, llfndecl, no_self, None, id);
trans_fn(ccx, path, decl, body, llfndecl, no_self, None, id, None);
return llfndecl;
}
......
......@@ -5,9 +5,12 @@
use base::{trans_item, get_item_val, self_arg, trans_fn,
impl_self, get_insn_ctxt};
fn maybe_instantiate_inline(ccx: @crate_ctxt, fn_id: ast::def_id)
-> ast::def_id
{
// `translate` will be true if this function is allowed to translate the
// item and false otherwise. Currently, this parameter is set to false when
// translating default methods.
fn maybe_instantiate_inline(ccx: @crate_ctxt, fn_id: ast::def_id,
translate: bool)
-> ast::def_id {
let _icx = ccx.insn_ctxt("maybe_instantiate_inline");
match ccx.external.find(fn_id) {
Some(Some(node_id)) => {
......@@ -31,7 +34,7 @@ fn maybe_instantiate_inline(ccx: @crate_ctxt, fn_id: ast::def_id)
csearch::found(ast::ii_item(item)) => {
ccx.external.insert(fn_id, Some(item.id));
ccx.stats.n_inlines += 1;
trans_item(ccx, *item);
if translate { trans_item(ccx, *item); }
local_def(item.id)
}
csearch::found(ast::ii_foreign(item)) => {
......@@ -53,7 +56,7 @@ fn maybe_instantiate_inline(ccx: @crate_ctxt, fn_id: ast::def_id)
_ => ccx.sess.bug(~"maybe_instantiate_inline: item has a \
non-enum parent")
}
trans_item(ccx, *item);
if translate { trans_item(ccx, *item); }
local_def(my_id)
}
csearch::found_parent(_, _) => {
......@@ -65,13 +68,14 @@ fn maybe_instantiate_inline(ccx: @crate_ctxt, fn_id: ast::def_id)
ccx.external.insert(fn_id, Some(mth.id));
let {bounds: impl_bnds, region_param: _, ty: impl_ty} =
ty::lookup_item_type(ccx.tcx, impl_did);
if (*impl_bnds).len() + mth.tps.len() == 0u {
if translate && (*impl_bnds).len() + mth.tps.len() == 0u {
let llfn = get_item_val(ccx, mth.id);
let path = vec::append(
ty::item_path(ccx.tcx, impl_did),
~[path_name(mth.ident)]);
trans_fn(ccx, path, mth.decl, mth.body,
llfn, impl_self(impl_ty), None, mth.id);
llfn, impl_self(impl_ty), None, mth.id,
Some(impl_did));
}
local_def(mth.id)
}
......@@ -83,3 +87,4 @@ fn maybe_instantiate_inline(ccx: @crate_ctxt, fn_id: ast::def_id)
}
}
}
......@@ -28,7 +28,7 @@
*/
fn trans_impl(ccx: @crate_ctxt, path: path, name: ast::ident,
methods: ~[@ast::method], tps: ~[ast::ty_param],
self_ty: Option<ty::t>) {
self_ty: Option<ty::t>, id: ast::node_id) {
let _icx = ccx.insn_ctxt("impl::trans_impl");
if tps.len() > 0u { return; }
let sub_path = vec::append_one(path, path_name(name));
......@@ -36,7 +36,22 @@ fn trans_impl(ccx: @crate_ctxt, path: path, name: ast::ident,
if method.tps.len() == 0u {
let llfn = get_item_val(ccx, method.id);
let path = vec::append_one(sub_path, path_name(method.ident));
trans_method(ccx, path, *method, None, self_ty, llfn);
let param_substs_opt;
match self_ty {
None => param_substs_opt = None,
Some(self_ty) => {
param_substs_opt = Some({
tys: ~[],
vtables: None,
bounds: @~[],
self_ty: Some(self_ty)
});
}
}
trans_method(ccx, path, *method, param_substs_opt, self_ty, llfn,
ast_util::local_def(id));
}
}
}
......@@ -54,13 +69,15 @@ fn trans_impl(ccx: @crate_ctxt, path: path, name: ast::ident,
will be none if this is not a default method and must always be present
if this is a default method.
- `llfn`: the LLVM ValueRef for the method
- `impl_id`: the node ID of the impl this method is inside
*/
fn trans_method(ccx: @crate_ctxt,
path: path,
method: &ast::method,
param_substs: Option<param_substs>,
base_self_ty: Option<ty::t>,
llfn: ValueRef) {
llfn: ValueRef,
impl_id: ast::def_id) {
// figure out how self is being passed
let self_arg = match method.self_ty.node {
......@@ -76,8 +93,10 @@ fn trans_method(ccx: @crate_ctxt,
Some(provided_self_ty) => self_ty = provided_self_ty
}
let self_ty = match param_substs {
None => self_ty,
Some({tys: ref tys, _}) => ty::subst_tps(ccx.tcx, *tys, self_ty)
None => self_ty,
Some({tys: ref tys, _}) => {
ty::subst_tps(ccx.tcx, *tys, None, self_ty)
}
};
match method.self_ty.node {
ast::sty_value => {
......@@ -98,15 +117,20 @@ fn trans_method(ccx: @crate_ctxt,
llfn,
self_arg,
param_substs,
method.id);
method.id,
Some(impl_id));
}
fn trans_self_arg(bcx: block, base: @ast::expr,
fn trans_self_arg(bcx: block,
base: @ast::expr,
mentry: typeck::method_map_entry) -> Result {
let _icx = bcx.insn_ctxt("impl::trans_self_arg");
let mut temp_cleanups = ~[];
// Compute the mode and type of self.
let self_arg = {mode: mentry.self_arg.mode,
ty: monomorphize_type(bcx, mentry.self_arg.ty)};
let result = trans_arg_expr(bcx, self_arg, base,
&mut temp_cleanups, None, DontAutorefArg);
......@@ -120,11 +144,31 @@ fn trans_self_arg(bcx: block, base: @ast::expr,
}
fn trans_method_callee(bcx: block, callee_id: ast::node_id,
self: @ast::expr, mentry: typeck::method_map_entry)
-> Callee
{
self: @ast::expr, mentry: typeck::method_map_entry) ->
Callee {
let _icx = bcx.insn_ctxt("impl::trans_method_callee");
match mentry.origin {
// Replace method_self with method_static here.
let mut origin = mentry.origin;
match origin {
typeck::method_self(copy trait_id, copy method_index) => {
// Get the ID of the impl we're inside.
let impl_def_id = bcx.fcx.impl_id.get();
io::println(fmt!("impl_def_id is %?", impl_def_id));
// Get the ID of the method we're calling.
let method_name =
ty::trait_methods(bcx.tcx(), trait_id)[method_index].ident;
let method_id = method_with_name(bcx.ccx(), impl_def_id,
method_name);
origin = typeck::method_static(method_id);
}
typeck::method_static(*) | typeck::method_param(*) |
typeck::method_trait(*) => {}
}
match origin {
typeck::method_static(did) => {
let callee_fn = callee::trans_fn_ref(bcx, did, callee_id);
let Result {bcx, val} = trans_self_arg(bcx, self, mentry);
......@@ -155,7 +199,7 @@ fn trans_method_callee(bcx: block, callee_id: ast::node_id,
trans_trait_callee(bcx, callee_id, off, self, vstore)
}
typeck::method_self(*) => {
bcx.tcx().sess.span_bug(self.span, ~"self method call");
fail ~"method_self should have been handled above"
}
}
}
......@@ -519,13 +563,21 @@ fn vtable_id(ccx: @crate_ctxt, origin: typeck::vtable_origin) -> mono_id {
match origin {
typeck::vtable_static(impl_id, substs, sub_vtables) => {
monomorphize::make_mono_id(
ccx, impl_id, substs,
if (*sub_vtables).len() == 0u { None }
else { Some(sub_vtables) }, None)
ccx,
impl_id,
substs,
if (*sub_vtables).len() == 0u {
None
} else {
Some(sub_vtables)
},
None,
None)
}
typeck::vtable_trait(trait_id, substs) => {
@{def: trait_id,
params: vec::map(substs, |t| mono_precise(*t, None))}
params: vec::map(substs, |t| mono_precise(*t, None)),
impl_did_opt: None}
}
// can't this be checked at the callee?
_ => fail ~"vtable_id"
......@@ -571,7 +623,7 @@ fn make_impl_vtable(ccx: @crate_ctxt, impl_id: ast::def_id, substs: ~[ty::t],
let has_tps = (*ty::lookup_item_type(ccx.tcx, impl_id).bounds).len() > 0u;
make_vtable(ccx, vec::map(*ty::trait_methods(tcx, trt_id), |im| {
let fty = ty::subst_tps(tcx, substs, ty::mk_fn(tcx, im.fty));
let fty = ty::subst_tps(tcx, substs, None, ty::mk_fn(tcx, im.fty));
if (*im.tps).len() > 0u || ty::type_has_self(fty) {
C_null(T_ptr(T_nil()))
} else {
......@@ -580,10 +632,11 @@ fn make_impl_vtable(ccx: @crate_ctxt, impl_id: ast::def_id, substs: ~[ty::t],
// If the method is in another crate, need to make an inlined
// copy first
if m_id.crate != ast::local_crate {
m_id = inline::maybe_instantiate_inline(ccx, m_id);
// XXX: Set impl ID here?
m_id = inline::maybe_instantiate_inline(ccx, m_id, true);
}
monomorphize::monomorphic_fn(ccx, m_id, substs,
Some(vtables), None).val
Some(vtables), None, None).val
} else if m_id.crate == ast::local_crate {
get_item_val(ccx, m_id.node)
} else {
......
......@@ -16,9 +16,9 @@ fn monomorphic_fn(ccx: @crate_ctxt,
fn_id: ast::def_id,
real_substs: ~[ty::t],
vtables: Option<typeck::vtable_res>,
ref_id: Option<ast::node_id>)
-> {val: ValueRef, must_cast: bool}
{
impl_did_opt: Option<ast::def_id>,
ref_id: Option<ast::node_id>) ->
{val: ValueRef, must_cast: bool} {
let _icx = ccx.insn_ctxt("monomorphic_fn");
let mut must_cast = false;
let substs = vec::map(real_substs, |t| {
......@@ -31,7 +31,8 @@ fn monomorphic_fn(ccx: @crate_ctxt,
for real_substs.each() |s| { assert !ty::type_has_params(*s); }
for substs.each() |s| { assert !ty::type_has_params(*s); }
let param_uses = type_use::type_uses_for(ccx, fn_id, substs.len());
let hash_id = make_mono_id(ccx, fn_id, substs, vtables, Some(param_uses));
let hash_id = make_mono_id(ccx, fn_id, substs, vtables, impl_did_opt,
Some(param_uses));
if vec::any(hash_id.params,
|p| match *p { mono_precise(_, _) => false, _ => true }) {
must_cast = true;
......@@ -73,8 +74,11 @@ fn monomorphic_fn(ccx: @crate_ctxt,
}
ast_map::node_dtor(_, dtor, _, pt) =>
(pt, special_idents::dtor, dtor.span),
ast_map::node_trait_method(*) => {
ccx.tcx.sess.bug(~"Can't monomorphize a trait method")
ast_map::node_trait_method(@ast::provided(m), _, pt) => {
(pt, m.ident, m.span)
}
ast_map::node_trait_method(@ast::required(_), _, _) => {
ccx.tcx.sess.bug(~"Can't monomorphize a required trait method")
}
ast_map::node_expr(*) => {
ccx.tcx.sess.bug(~"Can't monomorphize an expr")
......@@ -93,7 +97,18 @@ fn monomorphic_fn(ccx: @crate_ctxt,
ccx.tcx.sess.bug(~"Can't monomorphize a local")
}
};
let mono_ty = ty::subst_tps(ccx.tcx, substs, llitem_ty);
// Look up the impl type if we're translating a default method.
// XXX: Generics.
let impl_ty_opt;
match impl_did_opt {
None => impl_ty_opt = None,
Some(impl_did) => {
impl_ty_opt = Some(ty::lookup_item_type(ccx.tcx, impl_did).ty);
}
}
let mono_ty = ty::subst_tps(ccx.tcx, substs, impl_ty_opt, llitem_ty);
let llfty = type_of_fn_from_ty(ccx, mono_ty);
ccx.stats.n_monos += 1;
......@@ -118,12 +133,18 @@ fn monomorphic_fn(ccx: @crate_ctxt,
lldecl
};
let psubsts = Some({tys: substs, vtables: vtables, bounds: tpt.bounds});
let psubsts = Some({
tys: substs,
vtables: vtables,
bounds: tpt.bounds,
self_ty: impl_ty_opt
});
let lldecl = match map_node {
ast_map::node_item(i@@{node: ast::item_fn(decl, _, _, body), _}, _) => {
let d = mk_lldecl();
set_inline_hint_if_appr(i.attrs, d);
trans_fn(ccx, pt, decl, body, d, no_self, psubsts, fn_id.node);
trans_fn(ccx, pt, decl, body, d, no_self, psubsts, fn_id.node, None);
d
}
ast_map::node_item(*) => {
......@@ -154,11 +175,19 @@ fn monomorphic_fn(ccx: @crate_ctxt,
}
d
}
ast_map::node_method(mth, _, _) => {
ast_map::node_method(mth, supplied_impl_did, _) => {
// XXX: What should the self type be here?
let d = mk_lldecl();
set_inline_hint_if_appr(mth.attrs, d);
meth::trans_method(ccx, pt, mth, psubsts, None, d);
// Override the impl def ID if necessary.
let impl_did;
match impl_did_opt {
None => impl_did = supplied_impl_did,
Some(override_impl_did) => impl_did = override_impl_did
}
meth::trans_method(ccx, pt, mth, psubsts, None, d, impl_did);
d
}
ast_map::node_dtor(_, dtor, _, pt) => {
......@@ -171,6 +200,15 @@ fn monomorphic_fn(ccx: @crate_ctxt,
trans_class_dtor(ccx, *pt, dtor.node.body,
dtor.node.id, psubsts, Some(hash_id), parent_id)
}
ast_map::node_trait_method(@ast::provided(mth), _, pt) => {
let d = mk_lldecl();
set_inline_hint_if_appr(mth.attrs, d);
io::println(fmt!("monomorphic_fn impl_did_opt is %?", impl_did_opt));
meth::trans_method(ccx, *pt, mth, psubsts, None, d,
impl_did_opt.get());
d
}
// Ugh -- but this ensures any new variants won't be forgotten
ast_map::node_expr(*) |
ast_map::node_stmt(*) |
......@@ -226,6 +264,7 @@ fn normalize_for_monomorphization(tcx: ty::ctxt, ty: ty::t) -> Option<ty::t> {
fn make_mono_id(ccx: @crate_ctxt, item: ast::def_id, substs: ~[ty::t],
vtables: Option<typeck::vtable_res>,
impl_did_opt: Option<ast::def_id>,
param_uses: Option<~[type_use::type_uses]>) -> mono_id {
let precise_param_ids = match vtables {
Some(vts) => {
......@@ -295,5 +334,5 @@ fn make_mono_id(ccx: @crate_ctxt, item: ast::def_id, substs: ~[ty::t],
})
}
};
@{def: item, params: param_ids}
@{def: item, params: param_ids, impl_did_opt: impl_did_opt}
}
......@@ -40,8 +40,13 @@ fn type_uses_for(ccx: @crate_ctxt, fn_id: def_id, n_tps: uint)
Some(uses) => return uses,
None => ()
}
let fn_id_loc = if fn_id.crate == local_crate { fn_id }
else { inline::maybe_instantiate_inline(ccx, fn_id) };
let fn_id_loc = if fn_id.crate == local_crate {
fn_id
} else {
inline::maybe_instantiate_inline(ccx, fn_id, true)
};
// Conservatively assume full use for recursive loops
ccx.type_use_cache.insert(fn_id, vec::from_elem(n_tps, 3u));
......
......@@ -19,6 +19,7 @@
use syntax::print::pprust::*;
use util::ppaux::{ty_to_str, proto_ty_to_str, tys_to_str};
export ProvidedMethodSource;
export TyVid, IntVid, FnVid, RegionVid, vid;
export br_hashmap;
export is_instantiable;
......@@ -207,7 +208,8 @@
tps: @~[param_bounds],
fty: FnTy,
self_ty: ast::self_ty_,
vis: ast::visibility};
vis: ast::visibility,
def_id: ast::def_id};
type mt = {ty: t, mutbl: ast::mutability};
......@@ -314,6 +316,11 @@ enum AutoRefKind {
AutoPtr
}
struct ProvidedMethodSource {
method_id: ast::def_id,
impl_id: ast::def_id
}
type ctxt =
@{diag: syntax::diagnostic::span_handler,
interner: HashMap<intern_key, t_box>,
......@@ -356,7 +363,8 @@ enum AutoRefKind {
adjustments: HashMap<ast::node_id, @AutoAdjustment>,
normalized_cache: HashMap<t, t>,
lang_items: middle::lang_items::LanguageItems,
legacy_boxed_traits: HashMap<node_id, ()>};
legacy_boxed_traits: HashMap<node_id, ()>,
provided_method_sources: HashMap<ast::def_id, ProvidedMethodSource>};
enum tbox_flag {
has_params = 1,
......@@ -879,7 +887,8 @@ fn mk_ctxt(s: session::session,
adjustments: HashMap(),
normalized_cache: new_ty_hash(),
lang_items: move lang_items,
legacy_boxed_traits: HashMap()}
legacy_boxed_traits: HashMap(),
provided_method_sources: HashMap()}
}
......@@ -1392,13 +1401,23 @@ fn do_fold(cx: ctxt, t0: t, under_r: bool,
}
// Substitute *only* type parameters. Used in trans where regions are erased.
fn subst_tps(cx: ctxt, tps: &[t], typ: t) -> t {
if tps.len() == 0u { return typ; }
fn subst_tps(cx: ctxt, tps: &[t], self_ty_opt: Option<t>, typ: t) -> t {
if tps.len() == 0u && self_ty_opt.is_none() { return typ; }
let tb = ty::get(typ);
if !tbox_has_flag(tb, has_params) { return typ; }
if self_ty_opt.is_none() && !tbox_has_flag(tb, has_params) { return typ; }
match tb.sty {
ty_param(p) => tps[p.idx],
ref sty => fold_sty_to_ty(cx, sty, |t| subst_tps(cx, tps, t))
ty_param(p) => tps[p.idx],
ty_self => {
match self_ty_opt {
None => cx.sess.bug(~"ty_self unexpected here"),
Some(self_ty) => {
subst_tps(cx, tps, self_ty_opt, self_ty)
}
}
}
ref sty => {
fold_sty_to_ty(cx, sty, |t| subst_tps(cx, tps, self_ty_opt, t))
}
}
}
......@@ -3328,20 +3347,18 @@ fn store_trait_methods(cx: ctxt, id: ast::node_id, ms: @~[method]) {
cx.trait_method_cache.insert(ast_util::local_def(id), ms);
}
fn provided_trait_methods(cx: ctxt, id: ast::def_id) -> ~[@ast::method] {
fn provided_trait_methods(cx: ctxt, id: ast::def_id) -> ~[ast::ident] {
if is_local(id) {
match cx.items.find(id.node) {
Some(ast_map::node_item(@{node: item_trait(_, _, ms),_}, _)) =>
match ast_util::split_trait_methods(ms) {
(_, p) => p
(_, p) => p.map(|method| method.ident)
},
_ => cx.sess.bug(fmt!("provided_trait_methods: %? is not a trait",
id))
}
}
else {
// FIXME #2794: default methods for traits don't work cross-crate
~[]
} else {
csearch::get_provided_trait_methods(cx, id).map(|info| info.ty.ident)
}
}
......@@ -3599,10 +3616,12 @@ fn enum_variant_with_id(cx: ctxt, enum_id: ast::def_id,
// the type cache. Returns the type parameters and type.
fn lookup_item_type(cx: ctxt, did: ast::def_id) -> ty_param_bounds_and_ty {
match cx.tcache.find(did) {
Some(tpt) => return tpt,
None => {
Some(tpt) => {
// The item is in this crate. The caller should have added it to the
// type cache already
return tpt;
}
None => {
assert did.crate != ast::local_crate;
let tyt = csearch::get_type(cx, did);
cx.tcache.insert(did, tyt);
......
......@@ -62,6 +62,7 @@
use util::common::{indent, indenter};
use std::list;
use list::{List, Nil, Cons};
use dvec::DVec;
export check_crate;
export infer;
......@@ -174,12 +175,6 @@ fn to_str(tcx: ty::ctxt) -> ~str {
type vtable_map = HashMap<ast::node_id, vtable_res>;
// Stores information about provided methods, aka "default methods" in traits.
// Maps from a trait's def_id to a MethodInfo about
// that method in that trait.
type provided_methods_map = HashMap<ast::node_id,
~[@resolve::MethodInfo]>;
type ty_param_substs_and_ty = {substs: ty::substs, ty: ty::t};
type crate_ctxt_ = {// A mapping from method call sites to traits that have
......@@ -188,7 +183,6 @@ fn to_str(tcx: ty::ctxt) -> ~str {
method_map: method_map,
vtable_map: vtable_map,
coherence_info: @coherence::CoherenceInfo,
provided_methods_map: provided_methods_map,
tcx: ty::ctxt};
enum crate_ctxt {
......@@ -340,7 +334,6 @@ fn check_crate(tcx: ty::ctxt,
method_map: std::map::HashMap(),
vtable_map: std::map::HashMap(),
coherence_info: @coherence::CoherenceInfo(),
provided_methods_map: std::map::HashMap(),
tcx: tcx});
collect::collect_item_types(ccx, crate);
coherence::check_coherence(ccx, crate);
......
......@@ -69,7 +69,7 @@ trait `ToStr` imported, and I call `to_str()` on a value of type `T`,
*/
use coherence::get_base_type_def_id;
use coherence::{ProvidedMethodInfo, get_base_type_def_id};
use middle::resolve::{Impl, MethodInfo};
use middle::ty::*;
use syntax::ast::{def_id, sty_by_ref, sty_value, sty_region, sty_box,
......@@ -146,7 +146,7 @@ fn do_lookup(&self, self_ty: ty::t) -> Option<method_map_entry> {
// Prepare the list of candidates
self.push_inherent_candidates(self_ty);
self.push_extension_candidates();
self.push_extension_candidates(self_ty);
let enum_dids = DVec();
let mut self_ty = self_ty;
......@@ -251,7 +251,7 @@ fn push_inherent_candidates(&self, self_ty: ty::t) {
}
}
fn push_extension_candidates(&self) {
fn push_extension_candidates(&self, self_ty: ty::t) {
// If the method being called is associated with a trait, then
// find all the impls of that trait. Each of those are
// candidates.
......@@ -259,6 +259,8 @@ fn push_extension_candidates(&self) {
for opt_applicable_traits.each |applicable_traits| {
for applicable_traits.each |trait_did| {
let coherence_info = self.fcx.ccx.coherence_info;
// Look for explicit implementations.
let opt_impl_infos =
coherence_info.extension_methods.find(*trait_did);
for opt_impl_infos.each |impl_infos| {
......@@ -267,12 +269,21 @@ fn push_extension_candidates(&self) {
&self.extension_candidates, *impl_info);
}
}
// Look for default methods.
match coherence_info.provided_methods.find(*trait_did) {
Some(methods) => {
self.push_candidates_from_provided_methods(
&self.extension_candidates, self_ty, *trait_did,
methods);
}
None => {}
}
}
}
}
fn push_inherent_candidates_from_param(&self, param_ty: param_ty)
{
fn push_inherent_candidates_from_param(&self, param_ty: param_ty) {
debug!("push_inherent_candidates_from_param(param_ty=%?)",
param_ty);
let _indenter = indenter();
......@@ -348,8 +359,7 @@ fn push_inherent_candidates_from_trait(&self,
self_ty: ty::t,
did: def_id,
substs: &ty::substs,
vstore: ty::vstore)
{
vstore: ty::vstore) {
debug!("push_inherent_candidates_from_trait(did=%s, substs=%s)",
self.did_to_str(did),
substs_to_str(self.tcx(), substs));
......@@ -423,8 +433,7 @@ fn push_inherent_candidates_from_self(&self,
});
}
fn push_inherent_impl_candidates_for_type(did: def_id)
{
fn push_inherent_impl_candidates_for_type(did: def_id) {
let opt_impl_infos =
self.fcx.ccx.coherence_info.inherent_methods.find(did);
for opt_impl_infos.each |impl_infos| {
......@@ -436,8 +445,7 @@ fn push_inherent_impl_candidates_for_type(did: def_id)
}
fn push_candidates_from_impl(&self, candidates: &DVec<Candidate>,
impl_info: &resolve::Impl)
{
impl_info: &resolve::Impl) {
if !self.impl_dups.insert(impl_info.did, ()) {
return; // already visited
}
......@@ -471,12 +479,47 @@ fn push_candidates_from_impl(&self, candidates: &DVec<Candidate>,
});
}
fn push_candidates_from_provided_methods(
&self,
candidates: &DVec<Candidate>,
self_ty: ty::t,
trait_def_id: def_id,
methods: @DVec<@ProvidedMethodInfo>) {
debug!("(pushing candidates from provided methods) considering trait \
id %d:%d",
trait_def_id.crate,
trait_def_id.node);
for methods.each |provided_method_info| {
if provided_method_info.method_info.ident != self.m_name { loop; }
debug!("(pushing candidates from provided methods) adding \
candidate");
// XXX: Needs to support generics.
let dummy_substs = { self_r: None, self_ty: None, tps: ~[] };
let (impl_ty, impl_substs) =
self.create_rcvr_ty_and_substs_for_method(
provided_method_info.method_info.self_type,
self_ty,
dummy_substs);
candidates.push(Candidate {
rcvr_ty: impl_ty,
rcvr_substs: move impl_substs,
num_method_tps: provided_method_info.method_info.n_tps,
self_mode: get_mode_from_self_type(
provided_method_info.method_info.self_type),
origin: method_static(provided_method_info.method_info.did)
});
}
}
fn create_rcvr_ty_and_substs_for_method(&self,
self_decl: ast::self_ty_,
self_ty: ty::t,
+self_substs: ty::substs)
-> (ty::t, ty::substs)
{
-> (ty::t, ty::substs) {
// If the self type includes a region (like &self), we need to
// ensure that the receiver substitutions have a self region.
// If the receiver type does not itself contain borrowed
......@@ -693,8 +736,7 @@ fn consider_candidates(&self,
fn confirm_candidate(&self,
self_ty: ty::t,
candidate: &Candidate)
-> method_map_entry
{
-> method_map_entry {
let tcx = self.tcx();
let fty = self.fn_ty_from_origin(&candidate.origin);
......
......@@ -444,7 +444,7 @@ fn connect_trait_tps(fcx: @fn_ctxt, expr: @ast::expr, impl_tys: ~[ty::t],
// XXX: This should work for multiple traits.
let ity = ty::impl_traits(tcx, impl_did, vstore)[0];
let trait_ty = ty::subst_tps(tcx, impl_tys, ity);
let trait_ty = ty::subst_tps(tcx, impl_tys, None, ity);
debug!("(connect trait tps) trait type is %?, impl did is %?",
ty::get(trait_ty).sty, impl_did);
match ty::get(trait_ty).sty {
......
......@@ -4,12 +4,13 @@
// has at most one implementation for each type. Then we build a mapping from
// each trait in the system to its implementations.
use metadata::csearch::{each_path, get_impl_traits, get_impls_for_mod};
use metadata::csearch::{ProvidedTraitMethodInfo, each_path, get_impl_traits};
use metadata::csearch::{get_impls_for_mod};
use metadata::cstore::{cstore, iter_crate_data};
use metadata::decoder::{dl_def, dl_field, dl_impl};
use middle::resolve::{Impl, MethodInfo};
use middle::ty::{get, lookup_item_type, subst, t, ty_box};
use middle::ty::{ty_uniq, ty_ptr, ty_rptr, ty_enum};
use middle::ty::{ProvidedMethodSource, get, lookup_item_type, subst, t};
use middle::ty::{ty_box, ty_uniq, ty_ptr, ty_rptr, ty_enum};
use middle::ty::{ty_class, ty_nil, ty_bot, ty_bool, ty_int, ty_uint};
use middle::ty::{ty_float, ty_estr, ty_evec, ty_rec};
use middle::ty::{ty_fn, ty_trait, ty_tup, ty_infer};
......@@ -17,7 +18,7 @@
use middle::ty::{ty_opaque_closure_ptr, ty_unboxed_vec, type_is_ty_var};
use middle::typeck::infer::{infer_ctxt, can_mk_subty};
use middle::typeck::infer::{new_infer_ctxt, resolve_ivar, resolve_type};
use syntax::ast::{crate, def_id, def_mod};
use syntax::ast::{crate, def_id, def_mod, def_ty};
use syntax::ast::{item, item_class, item_const, item_enum, item_fn};
use syntax::ast::{item_foreign_mod, item_impl, item_mac, item_mod};
use syntax::ast::{item_trait, item_ty, local_crate, method, node_id};
......@@ -118,6 +119,21 @@ fn method_to_MethodInfo(ast_method: @method) -> @MethodInfo {
}
}
// Stores the method info and definition ID of the associated trait method for
// each instantiation of each provided method.
struct ProvidedMethodInfo {
method_info: @MethodInfo,
trait_method_def_id: def_id
}
// Stores information about provided methods (a.k.a. default methods) in
// implementations.
//
// This is a map from ID of each implementation to the method info and trait
// method ID of each of the default methods belonging to the trait that that
// implementation implements.
type ProvidedMethodsMap = HashMap<def_id,@DVec<@ProvidedMethodInfo>>;
struct CoherenceInfo {
// Contains implementations of methods that are inherent to a type.
// Methods in these implementations don't need to be exported.
......@@ -128,14 +144,20 @@ struct CoherenceInfo {
extension_methods: HashMap<def_id,@DVec<@Impl>>,
// A mapping from a supertrait to its subtraits.
supertrait_to_subtraits: HashMap<def_id,@DVec<def_id>>
supertrait_to_subtraits: HashMap<def_id,@DVec<def_id>>,
// A mapping from an implementation ID to the method info and trait method
// ID of the provided (a.k.a. default) methods in the traits that that
// implementation implements.
provided_methods: ProvidedMethodsMap,
}
fn CoherenceInfo() -> CoherenceInfo {
CoherenceInfo {
inherent_methods: HashMap(),
extension_methods: HashMap(),
supertrait_to_subtraits: HashMap()
supertrait_to_subtraits: HashMap(),
provided_methods: HashMap(),
}
}
......@@ -165,68 +187,6 @@ struct CoherenceChecker {
}
impl CoherenceChecker {
// Create a mapping containing a MethodInfo for every provided
// method in every trait.
fn build_provided_methods_map(crate: @crate) {
let sess = self.crate_context.tcx.sess;
let pmm = self.crate_context.provided_methods_map;
visit_crate(*crate, (), mk_simple_visitor(@{
visit_item: |item| {
match item.node {
item_trait(_, _, trait_methods) => {
for trait_methods.each |trait_method| {
debug!("(building provided methods map) checking \
trait `%s` with id %d",
sess.str_of(item.ident), item.id);
match *trait_method {
required(_) => { /* fall through */}
provided(m) => {
// For every provided method in the
// trait, store a MethodInfo.
let mi = method_to_MethodInfo(m);
match pmm.find(item.id) {
Some(mis) => {
// If the trait already has an
// entry in the
// provided_methods_map, we just
// need to add this method to
// that entry.
debug!("(building provided \
methods map) adding \
method `%s` to entry for \
existing trait",
sess.str_of(mi.ident));
let mut method_infos = mis;
method_infos.push(mi);
pmm.insert(item.id, method_infos);
}
None => {
// If the trait doesn't have an
// entry yet, create one.
debug!("(building provided \
methods map) creating new \
entry for method `%s`",
sess.str_of(mi.ident));
pmm.insert(item.id, ~[mi]);
}
}
}
}
}
}
_ => {
// Nothing to do.
}
};
},
.. *default_simple_visitor()
}));
}
fn check_coherence(crate: @crate) {
// Check implementations and traits. This populates the tables
// containing the inherent methods and extension methods. It also
......@@ -307,6 +267,7 @@ fn check_implementation(item: @item, associated_traits: ~[@trait_ref]) {
self.crate_context.tcx.sess.parse_sess.interner),
self.crate_context.tcx.sess.str_of(item.ident));
self.instantiate_default_methods(item.id, trait_did);
let implementation = self.create_impl_from_item(item);
self.add_trait_method(trait_did, implementation);
}
......@@ -321,6 +282,7 @@ fn check_implementation(item: @item, associated_traits: ~[@trait_ref]) {
// Nothing to do.
}
Some(base_type_def_id) => {
// XXX: Gather up default methods?
let implementation = self.create_impl_from_item(item);
self.add_inherent_method(base_type_def_id, implementation);
......@@ -330,6 +292,68 @@ fn check_implementation(item: @item, associated_traits: ~[@trait_ref]) {
}
}
// Creates default method IDs and performs type substitutions for an impl
// and trait pair. Then, for each provided method in the trait, inserts a
// `ProvidedMethodInfo` instance into the `provided_method_sources` map.
fn instantiate_default_methods(impl_id: ast::node_id,
trait_did: ast::def_id) {
for self.each_provided_trait_method(trait_did) |trait_method| {
// Synthesize an ID.
let tcx = self.crate_context.tcx;
let new_id = syntax::parse::next_node_id(tcx.sess.parse_sess);
let new_did = local_def(new_id);
// XXX: Perform substitutions.
let new_polytype = ty::lookup_item_type(tcx, trait_method.def_id);
tcx.tcache.insert(new_did, new_polytype);
// Pair the new synthesized ID up with the
// ID of the method.
let source = ProvidedMethodSource {
method_id: trait_method.def_id,
impl_id: local_def(impl_id)
};
self.crate_context.tcx.provided_method_sources.insert(new_did,
source);
let provided_method_info =
@ProvidedMethodInfo {
method_info: @{
did: new_did,
n_tps: trait_method.tps.len(),
ident: trait_method.ident,
self_type: trait_method.self_ty
},
trait_method_def_id: trait_method.def_id
};
let pmm = self.crate_context.coherence_info.provided_methods;
match pmm.find(local_def(impl_id)) {
Some(mis) => {
// If the trait already has an entry in the
// provided_methods_map, we just need to add this
// method to that entry.
debug!("(checking implementation) adding method `%s` \
to entry for existing trait",
self.crate_context.tcx.sess.str_of(
provided_method_info.method_info.ident));
mis.push(provided_method_info);
}
None => {
// If the trait doesn't have an entry yet, create one.
debug!("(checking implementation) creating new entry \
for method `%s`",
self.crate_context.tcx.sess.str_of(
provided_method_info.method_info.ident));
let method_infos = @DVec();
method_infos.push(provided_method_info);
pmm.insert(local_def(impl_id), method_infos);
}
}
}
}
fn register_inherited_trait(item: @item, supertraits: ~[@trait_ref]) {
// XXX: This is wrong. We need to support substitutions; e.g.
// trait Foo : Bar<int>.
......@@ -354,8 +378,7 @@ fn register_inherited_trait(item: @item, supertraits: ~[@trait_ref]) {
fn add_inherent_method(base_def_id: def_id, implementation: @Impl) {
let implementation_list;
match self.crate_context.coherence_info.inherent_methods
.find(base_def_id) {
.find(base_def_id) {
None => {
implementation_list = @DVec();
self.crate_context.coherence_info.inherent_methods
......@@ -372,8 +395,7 @@ fn add_inherent_method(base_def_id: def_id, implementation: @Impl) {
fn add_trait_method(trait_id: def_id, implementation: @Impl) {
let implementation_list;
match self.crate_context.coherence_info.extension_methods
.find(trait_id) {
.find(trait_id) {
None => {
implementation_list = @DVec();
self.crate_context.coherence_info.extension_methods
......@@ -413,6 +435,26 @@ fn check_implementation_coherence(_trait_def_id: def_id,
}
}
fn each_provided_trait_method(
trait_did: ast::def_id,
f: &fn(x: &ty::method) -> bool) {
// Make a list of all the names of the provided methods.
// XXX: This is horrible.
let provided_method_idents = HashMap();
let tcx = self.crate_context.tcx;
for ty::provided_trait_methods(tcx, trait_did).each |ident| {
provided_method_idents.insert(*ident, ());
}
for ty::trait_methods(tcx, trait_did).each |method| {
if provided_method_idents.contains_key(method.ident) {
if !f(method) {
break;
}
}
}
}
fn polytypes_unify(polytype_a: ty_param_bounds_and_ty,
polytype_b: ty_param_bounds_and_ty)
-> bool {
......@@ -449,7 +491,6 @@ fn universally_quantify_polytype(polytype: ty_param_bounds_and_ty) -> t {
fn get_self_type_for_implementation(implementation: @Impl)
-> ty_param_bounds_and_ty {
return self.crate_context.tcx.tcache.get(implementation.did);
}
......@@ -552,33 +593,15 @@ fn trait_ref_to_trait_def_id(trait_ref: @trait_ref) -> def_id {
// Converts an implementation in the AST to an Impl structure.
fn create_impl_from_item(item: @item) -> @Impl {
fn add_provided_methods(inherent_methods: ~[@MethodInfo],
all_provided_methods: ~[@MethodInfo],
sess: driver::session::session)
-> ~[@MethodInfo] {
let mut methods = inherent_methods;
// If there's no inherent method with the same name as a
// provided method, add that provided method to `methods`.
fn add_provided_methods(all_methods: &mut ~[@MethodInfo],
all_provided_methods: ~[@ProvidedMethodInfo],
sess: driver::session::session) {
for all_provided_methods.each |provided_method| {
let mut method_inherent_to_impl = false;
for inherent_methods.each |inherent_method| {
if provided_method.ident == inherent_method.ident {
method_inherent_to_impl = true;
}
}
if !method_inherent_to_impl {
debug!(
"(creating impl) adding provided method `%s` to impl",
sess.str_of(provided_method.ident));
methods.push(*provided_method);
}
debug!(
"(creating impl) adding provided method `%s` to impl",
sess.str_of(provided_method.method_info.ident));
vec::push(all_methods, provided_method.method_info);
}
return methods;
}
match item.node {
......@@ -598,24 +621,22 @@ fn add_provided_methods(inherent_methods: ~[@MethodInfo],
let trait_did =
self.trait_ref_to_trait_def_id(*trait_ref);
match self.crate_context.provided_methods_map
.find(trait_did.node) {
match self.crate_context
.coherence_info
.provided_methods
.find(local_def(item.id)) {
None => {
debug!("(creating impl) trait with node_id `%d` \
has no provided methods", trait_did.node);
/* fall through */
}
Some(all_provided)
=> {
Some(all_provided) => {
debug!("(creating impl) trait with node_id `%d` \
has provided methods", trait_did.node);
// Selectively add only those provided
// methods that aren't inherent to the
// trait.
// XXX: could probably be doing this with filter.
methods = add_provided_methods(
methods, all_provided,
// Add all provided methods.
add_provided_methods(
&mut methods,
all_provided.get(),
self.crate_context.tcx.sess);
}
}
......@@ -758,6 +779,41 @@ fn add_impls_for_module(impls_seen: HashMap<def_id,()>,
}
}
fn add_default_methods_for_external_trait(trait_def_id: ast::def_id) {
let tcx = self.crate_context.tcx;
let pmm = self.crate_context.coherence_info.provided_methods;
if pmm.contains_key(trait_def_id) { return; }
debug!("(adding default methods for trait) processing trait");
for csearch::get_provided_trait_methods(tcx,
trait_def_id).each |info| {
debug!("(adding default methods for trait) found default method");
// Create a new def ID for this provided method.
let parse_sess = &self.crate_context.tcx.sess.parse_sess;
let new_did = local_def(syntax::parse::next_node_id(*parse_sess));
let provided_method_info =
@ProvidedMethodInfo {
method_info: @{
did: new_did,
n_tps: info.ty.tps.len(),
ident: info.ty.ident,
self_type: info.ty.self_ty
},
trait_method_def_id: info.def_id
};
let method_infos = @DVec();
method_infos.push(provided_method_info);
pmm.insert(trait_def_id, method_infos);
}
}
// Adds implementations and traits from external crates to the coherence
// info.
fn add_external_crates() {
let impls_seen = HashMap();
......@@ -768,20 +824,28 @@ fn add_external_crates() {
{ crate: crate_number, node: 0 });
for each_path(crate_store, crate_number) |path_entry| {
let module_def_id;
match path_entry.def_like {
dl_def(def_mod(def_id)) => {
module_def_id = def_id;
self.add_impls_for_module(impls_seen,
crate_store,
def_id);
}
dl_def(def_ty(def_id)) => {
let tcx = self.crate_context.tcx;
let polytype = csearch::get_type(tcx, def_id);
match ty::get(polytype.ty).sty {
ty::ty_trait(*) => {
self.add_default_methods_for_external_trait(
def_id);
}
_ => {}
}
}
dl_def(_) | dl_impl(_) | dl_field => {
// Skip this.
loop;
}
}
self.add_impls_for_module(impls_seen,
crate_store,
module_def_id);
}
}
}
......@@ -789,7 +853,6 @@ fn add_external_crates() {
fn check_coherence(crate_context: @crate_ctxt, crate: @crate) {
let coherence_checker = @CoherenceChecker(crate_context);
(*coherence_checker).build_provided_methods_map(crate);
(*coherence_checker).check_coherence(crate);
}
......@@ -212,9 +212,15 @@ fn make_static_method_ty(ccx: @crate_ctxt,
match tcx.items.get(id) {
ast_map::node_item(@{node: ast::item_trait(params, _, ms), _}, _) => {
store_methods::<ast::trait_method>(ccx, id, ms, |m| {
let def_id;
match *m {
ast::required(ty_method) => def_id = local_def(ty_method.id),
ast::provided(method) => def_id = local_def(method.id)
}
let trait_bounds = ty_param_bounds(ccx, params);
let ty_m = trait_method_to_ty_method(*m);
let method_ty = ty_of_ty_method(ccx, ty_m, region_paramd);
let method_ty = ty_of_ty_method(ccx, ty_m, region_paramd, def_id);
if ty_m.self_ty.node == ast::sty_static {
make_static_method_ty(ccx, ty_m, region_paramd,
method_ty, trait_ty, trait_bounds);
......@@ -373,7 +379,7 @@ fn check_methods_against_trait(ccx: @crate_ctxt,
let provided_methods = ty::provided_trait_methods(tcx, did);
match vec::find(provided_methods, |provided_method|
provided_method.ident == trait_m.ident) {
*provided_method == trait_m.ident) {
Some(_) => {
// If there's a provided method with the name we
// want, then we're fine; nothing else to do.
......@@ -546,19 +552,22 @@ fn ty_of_method(ccx: @crate_ctxt,
m.purity, @~[],
m.decl, None, m.span),
self_ty: m.self_ty.node,
vis: m.vis}
vis: m.vis,
def_id: local_def(m.id)}
}
fn ty_of_ty_method(self: @crate_ctxt,
m: ast::ty_method,
rp: Option<ty::region_variance>) -> ty::method {
rp: Option<ty::region_variance>,
id: ast::def_id) -> ty::method {
{ident: m.ident,
tps: ty_param_bounds(self, m.tps),
fty: ty_of_fn_decl(self, type_rscope(rp), ast::proto_bare, m.purity,
@~[], m.decl, None, m.span),
// assume public, because this is only invoked on trait methods
self_ty: m.self_ty.node,
vis: ast::public}
vis: ast::public,
def_id: id}
}
/*
......
trait Foo {
fn f() {
io::println("Hello!");
self.g();
}
fn g();
}
struct A {
x: int
}
impl A : Foo {
fn g() {
io::println("Goodbye!");
}
}
fn main() {
let a = A { x: 1 };
a.f();
}
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册