Skip to content

Commit d5a27a0

Browse files
committed
rustc: Translate monomorphic intra-crate automatically-derived methods that follow the "eq" format
1 parent c7ec183 commit d5a27a0

File tree

7 files changed

+266
-33
lines changed

7 files changed

+266
-33
lines changed

Diff for: src/libsyntax/ast_map.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -74,7 +74,7 @@ enum ast_node {
7474
// Destructor for a class
7575
node_dtor(~[ty_param], @class_dtor, def_id, @path),
7676
node_block(blk),
77-
node_struct_ctor(@struct_def, @item, @path)
77+
node_struct_ctor(@struct_def, @item, @path),
7878
}
7979

8080
type map = std::map::HashMap<node_id, ast_node>;

Diff for: src/rustc/middle/trans/base.rs

+42-1
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@ use util::ppaux;
4242
use util::ppaux::{ty_to_str, ty_to_short_str};
4343
use syntax::diagnostic::expect;
4444
use util::common::indenter;
45+
use ty::DerivedMethodInfo;
4546

4647
use build::*;
4748
use shape::*;
@@ -1843,7 +1844,7 @@ fn trans_item(ccx: @crate_ctxt, item: ast::item) {
18431844
match ms_opt {
18441845
None => {
18451846
deriving::trans_deriving_impl(ccx, *path, item.ident, tps,
1846-
None, item.id);
1847+
item.id);
18471848
}
18481849
Some(ms) => {
18491850
meth::trans_impl(ccx, *path, item.ident, ms, tps, None,
@@ -2079,6 +2080,20 @@ fn get_item_val(ccx: @crate_ctxt, id: ast::node_id) -> ValueRef {
20792080
match ccx.item_vals.find(id) {
20802081
Some(v) => v,
20812082
None => {
2083+
// First, check whether we need to automatically generate a method
2084+
// via the deriving mechanism.
2085+
match ccx.tcx.automatically_derived_methods.find(local_def(id)) {
2086+
None => {} // Continue.
2087+
Some(ref derived_method_info) => {
2088+
// XXX: Mark as internal if necessary.
2089+
let llfn = register_deriving_method(
2090+
ccx, id, derived_method_info);
2091+
ccx.item_vals.insert(id, llfn);
2092+
return llfn;
2093+
}
2094+
}
2095+
2096+
// Failing that, look for an item.
20822097
let mut exprt = false;
20832098
let val = match ccx.tcx.items.get(id) {
20842099
ast_map::node_item(i, pth) => {
@@ -2226,6 +2241,32 @@ fn register_method(ccx: @crate_ctxt, id: ast::node_id, pth: @ast_map::path,
22262241
llfn
22272242
}
22282243

2244+
fn register_deriving_method(ccx: @crate_ctxt,
2245+
id: ast::node_id,
2246+
derived_method_info: &DerivedMethodInfo) ->
2247+
ValueRef {
2248+
// Find the path of the item.
2249+
let path, span;
2250+
match ccx.tcx.items.get(derived_method_info.containing_impl.node) {
2251+
ast_map::node_item(item, found_path) => {
2252+
path = found_path;
2253+
span = item.span;
2254+
}
2255+
_ => {
2256+
ccx.tcx.sess.bug(~"derived method info containing impl didn't \
2257+
refer to an item");
2258+
}
2259+
}
2260+
2261+
let path = vec::append(*path, ~[
2262+
ast_map::path_name(derived_method_info.method_info.ident)
2263+
]);
2264+
let mty = ty::lookup_item_type(ccx.tcx, local_def(id)).ty;
2265+
let llfn = register_fn_full(ccx, span, path, id, mty);
2266+
// XXX: Inline hint.
2267+
llfn
2268+
}
2269+
22292270
// The constant translation pass.
22302271
fn trans_constant(ccx: @crate_ctxt, it: @ast::item) {
22312272
let _icx = ccx.insn_ctxt("trans_constant");

Diff for: src/rustc/middle/trans/callee.rs

+31-15
Original file line numberDiff line numberDiff line change
@@ -210,23 +210,30 @@ fn trans_fn_ref_with_vtables(
210210
// intrinsic, or is a default method. In particular, if we see an
211211
// intrinsic that is inlined from a different crate, we want to reemit the
212212
// intrinsic instead of trying to call it in the other crate.
213-
let must_monomorphise = type_params.len() > 0 ||
214-
opt_impl_did.is_some() || {
215-
if def_id.crate == ast::local_crate {
216-
let map_node = session::expect(
217-
ccx.sess,
218-
ccx.tcx.items.find(def_id.node),
219-
|| fmt!("local item should be in ast map"));
220-
221-
match map_node {
222-
ast_map::node_foreign_item(
223-
_, ast::foreign_abi_rust_intrinsic, _) => true,
224-
_ => false
213+
let must_monomorphise;
214+
if type_params.len() > 0 || opt_impl_did.is_some() {
215+
must_monomorphise = true;
216+
} else if ccx.tcx.automatically_derived_methods.contains_key(def_id) {
217+
must_monomorphise = false;
218+
} else if def_id.crate == ast::local_crate {
219+
let map_node = session::expect(
220+
ccx.sess,
221+
ccx.tcx.items.find(def_id.node),
222+
|| fmt!("local item should be in ast map"));
223+
224+
match map_node {
225+
ast_map::node_foreign_item(_,
226+
ast::foreign_abi_rust_intrinsic,
227+
_) => {
228+
must_monomorphise = true;
229+
}
230+
_ => {
231+
must_monomorphise = false;
225232
}
226-
} else {
227-
false
228233
}
229-
};
234+
} else {
235+
must_monomorphise = false;
236+
}
230237

231238
// Create a monomorphic verison of generic functions
232239
if must_monomorphise {
@@ -434,6 +441,15 @@ fn trans_call_inner(
434441
_ => {}
435442
}
436443

444+
// Uncomment this to debug calls.
445+
/*
446+
io::println(fmt!("calling: %s", bcx.val_str(llfn)));
447+
for llargs.each |llarg| {
448+
io::println(fmt!("arg: %s", bcx.val_str(*llarg)));
449+
}
450+
io::println("---");
451+
*/
452+
437453
// If the block is terminated, then one or more of the args
438454
// has type _|_. Since that means it diverges, the code for
439455
// the call itself is unreachable.

Diff for: src/rustc/middle/trans/deriving.rs

+111-6
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,126 @@
11
// Translation of automatically-derived trait implementations. This handles
22
// enums and structs only; other types cannot be automatically derived.
33

4-
use middle::trans::base::get_insn_ctxt;
5-
use middle::trans::common::crate_ctxt;
6-
use syntax::ast::{ident, node_id, ty_param};
4+
use lib::llvm::llvm;
5+
use middle::trans::base::{finish_fn, get_insn_ctxt, get_item_val};
6+
use middle::trans::base::{new_fn_ctxt, sub_block, top_scope_block};
7+
use middle::trans::build::{Br, CondBr, GEPi, Load, PointerCast, Store};
8+
use middle::trans::build::{ValueRef};
9+
use middle::trans::callee;
10+
use middle::trans::callee::{ArgVals, Callee, DontAutorefArg, Method};
11+
use middle::trans::callee::{MethodData};
12+
use middle::trans::common;
13+
use middle::trans::common::{C_bool, T_ptr, block, crate_ctxt};
14+
use middle::trans::expr::SaveIn;
15+
use middle::trans::type_of::type_of;
16+
use middle::typeck::method_static;
17+
use syntax::ast;
18+
use syntax::ast::{def_id, ident, node_id, ty_param};
719
use syntax::ast_map::path;
20+
use syntax::ast_util;
21+
use syntax::ast_util::local_def;
822

923
/// The main "translation" pass for automatically-derived impls. Generates
1024
/// code for monomorphic methods only. Other methods will be generated when
1125
/// they are invoked with specific type parameters; see
1226
/// `trans::base::lval_static_fn()` or `trans::base::monomorphic_fn()`.
1327
pub fn trans_deriving_impl(ccx: @crate_ctxt, _path: path, _name: ident,
14-
tps: ~[ty_param], _self_ty: Option<ty::t>,
15-
_id: node_id) {
28+
tps: ~[ty_param], id: node_id) {
1629
let _icx = ccx.insn_ctxt("deriving::trans_deriving_impl");
1730
if tps.len() > 0 { return; }
1831

19-
// XXX: Unimplemented.
32+
let impl_def_id = local_def(id);
33+
let self_ty = ty::lookup_item_type(ccx.tcx, impl_def_id);
34+
let method_dids = ccx.tcx.automatically_derived_methods_for_impl.get(
35+
impl_def_id);
36+
37+
for method_dids.each |method_did| {
38+
let llfn = get_item_val(ccx, method_did.node);
39+
match ty::get(self_ty.ty).sty {
40+
ty::ty_class(*) => {
41+
trans_deriving_struct_method(ccx, llfn, impl_def_id,
42+
self_ty.ty);
43+
}
44+
_ => {
45+
ccx.tcx.sess.unimpl(~"translation of non-struct deriving \
46+
method");
47+
}
48+
}
49+
}
50+
}
51+
52+
fn trans_deriving_struct_method(ccx: @crate_ctxt, llfn: ValueRef,
53+
impl_did: def_id, self_ty: ty::t) {
54+
let _icx = ccx.insn_ctxt("trans_deriving_struct_method");
55+
let fcx = new_fn_ctxt(ccx, ~[], llfn, None);
56+
let top_bcx = top_scope_block(fcx, None);
57+
let lltop = top_bcx.llbb;
58+
let mut bcx = top_bcx;
59+
60+
let llselfty = type_of(ccx, self_ty);
61+
let llselfval = PointerCast(bcx, fcx.llenv, T_ptr(llselfty));
62+
let llotherval = llvm::LLVMGetParam(llfn, 2);
63+
64+
let struct_field_tys;
65+
match ty::get(self_ty).sty {
66+
ty::ty_class(struct_id, ref struct_substs) => {
67+
struct_field_tys = ty::class_items_as_fields(
68+
ccx.tcx, struct_id, struct_substs);
69+
}
70+
_ => {
71+
ccx.tcx.sess.bug(~"passed non-struct to \
72+
trans_deriving_struct_method");
73+
}
74+
}
75+
76+
// Iterate over every element of the struct.
77+
for ccx.tcx.deriving_struct_methods.get(impl_did).eachi
78+
|i, derived_method_info| {
79+
let target_method_def_id;
80+
match *derived_method_info {
81+
method_static(did) => target_method_def_id = did,
82+
_ => fail ~"derived method didn't resolve to a static method"
83+
}
84+
85+
let fn_expr_ty =
86+
ty::lookup_item_type(ccx.tcx, target_method_def_id).ty;
87+
88+
let llselfval = GEPi(bcx, llselfval, [0, 0, i]);
89+
let llotherval = GEPi(bcx, llotherval, [0, 0, i]);
90+
91+
// XXX: Cross-crate won't work!
92+
let llfn = get_item_val(ccx, target_method_def_id.node);
93+
let cb: &fn(block) -> Callee = |block| {
94+
Callee {
95+
bcx: block,
96+
data: Method(MethodData {
97+
llfn: llfn,
98+
llself: llselfval,
99+
self_ty: struct_field_tys[i].mt.ty,
100+
self_mode: ast::by_copy
101+
})
102+
}
103+
};
104+
105+
bcx = callee::trans_call_inner(bcx,
106+
None,
107+
fn_expr_ty,
108+
ty::mk_bool(ccx.tcx),
109+
cb,
110+
ArgVals(~[llotherval]),
111+
SaveIn(fcx.llretptr),
112+
DontAutorefArg);
113+
114+
// Return immediately if the call returned false.
115+
let next_block = sub_block(top_bcx, ~"next");
116+
let llcond = Load(bcx, fcx.llretptr);
117+
CondBr(bcx, llcond, next_block.llbb, fcx.llreturn);
118+
bcx = next_block;
119+
}
120+
121+
Store(bcx, C_bool(true), fcx.llretptr);
122+
Br(bcx, fcx.llreturn);
123+
124+
finish_fn(fcx, lltop);
20125
}
21126

Diff for: src/rustc/middle/ty.rs

+20-2
Original file line numberDiff line numberDiff line change
@@ -200,6 +200,7 @@ export provided_trait_methods;
200200
export trait_supertraits;
201201
export AutoAdjustment;
202202
export AutoRef, AutoRefKind, AutoSlice, AutoPtr;
203+
export DerivedMethodInfo;
203204

204205
// Data types
205206

@@ -333,6 +334,11 @@ struct InstantiatedTraitRef {
333334
tpt: ty_param_substs_and_ty
334335
}
335336

337+
struct DerivedMethodInfo {
338+
method_info: @middle::resolve::MethodInfo,
339+
containing_impl: ast::def_id
340+
}
341+
336342
type ctxt =
337343
@{diag: syntax::diagnostic::span_handler,
338344
interner: HashMap<intern_key, t_box>,
@@ -379,7 +385,17 @@ type ctxt =
379385
provided_method_sources: HashMap<ast::def_id, ProvidedMethodSource>,
380386
supertraits: HashMap<ast::def_id, @~[InstantiatedTraitRef]>,
381387
deriving_struct_methods: HashMap<ast::def_id,
382-
@~[typeck::method_origin]>};
388+
@~[typeck::method_origin]>,
389+
390+
// A mapping from the def ID of a method that was automatically derived
391+
// to information about it.
392+
automatically_derived_methods: HashMap<ast::def_id, DerivedMethodInfo>,
393+
394+
// A mapping from the def ID of an impl to the IDs of the derived
395+
// methods within it.
396+
automatically_derived_methods_for_impl:
397+
HashMap<ast::def_id, @~[ast::def_id]>
398+
};
383399

384400
enum tbox_flag {
385401
has_params = 1,
@@ -942,7 +958,9 @@ fn mk_ctxt(s: session::Session,
942958
legacy_boxed_traits: HashMap(),
943959
provided_method_sources: HashMap(),
944960
supertraits: HashMap(),
945-
deriving_struct_methods: HashMap()}
961+
deriving_struct_methods: HashMap(),
962+
automatically_derived_methods: HashMap(),
963+
automatically_derived_methods_for_impl: HashMap()}
946964
}
947965

948966

Diff for: src/rustc/middle/typeck/coherence.rs

+29-8
Original file line numberDiff line numberDiff line change
@@ -9,10 +9,10 @@ use metadata::csearch::{get_impls_for_mod};
99
use metadata::cstore::{CStore, iter_crate_data};
1010
use metadata::decoder::{dl_def, dl_field, dl_impl};
1111
use middle::resolve::{Impl, MethodInfo};
12-
use middle::ty::{ProvidedMethodSource, get, lookup_item_type, subst, t};
13-
use middle::ty::{ty_box, ty_uniq, ty_ptr, ty_rptr, ty_enum};
14-
use middle::ty::{ty_class, ty_nil, ty_bot, ty_bool, ty_int, ty_uint};
15-
use middle::ty::{ty_float, ty_estr, ty_evec, ty_rec};
12+
use middle::ty::{DerivedMethodInfo, ProvidedMethodSource, get};
13+
use middle::ty::{lookup_item_type, subst, t, ty_bot, ty_box, ty_class};
14+
use middle::ty::{ty_bool, ty_enum, ty_int, ty_nil, ty_ptr, ty_rptr, ty_uint};
15+
use middle::ty::{ty_float, ty_estr, ty_evec, ty_rec, ty_uniq};
1616
use middle::ty::{ty_fn, ty_trait, ty_tup, ty_infer};
1717
use middle::ty::{ty_param, ty_self, ty_type, ty_opaque_box};
1818
use middle::ty::{ty_opaque_closure_ptr, ty_unboxed_vec, type_is_ty_var};
@@ -592,17 +592,33 @@ impl CoherenceChecker {
592592
}
593593
594594
fn add_automatically_derived_methods_from_trait(
595-
all_methods: &mut ~[@MethodInfo], trait_did: def_id, self_ty: ty::t) {
595+
all_methods: &mut ~[@MethodInfo],
596+
trait_did: def_id,
597+
self_ty: ty::t,
598+
impl_did: def_id) {
596599
let tcx = self.crate_context.tcx;
600+
let new_method_dids = dvec::DVec();
597601
for (*ty::trait_methods(tcx, trait_did)).each |method| {
598602
// Generate a def ID for each node.
599603
let new_def_id = local_def(tcx.sess.next_node_id());
600-
all_methods.push(@{
604+
let method_info = @{
601605
did: new_def_id,
602606
n_tps: method.tps.len(),
603607
ident: method.ident,
604608
self_type: method.self_ty
605-
});
609+
};
610+
all_methods.push(method_info);
611+
612+
// Note that this method was automatically derived so that trans
613+
// can handle it differently.
614+
let derived_method_info = DerivedMethodInfo {
615+
method_info: method_info,
616+
containing_impl: impl_did
617+
};
618+
tcx.automatically_derived_methods.insert(new_def_id,
619+
derived_method_info);
620+
621+
new_method_dids.push(new_def_id);
606622
607623
// Additionally, generate the type for the derived method and add
608624
// it to the type cache.
@@ -615,6 +631,10 @@ impl CoherenceChecker {
615631
ty: ty::subst(tcx, &substs, ty::mk_fn(tcx, method.fty))
616632
});
617633
}
634+
635+
let new_method_dids = @dvec::unwrap(move new_method_dids);
636+
tcx.automatically_derived_methods_for_impl.insert(impl_did,
637+
new_method_dids);
618638
}
619639
620640
// Converts an implementation in the AST to an Impl structure.
@@ -651,7 +671,8 @@ impl CoherenceChecker {
651671
let trait_did =
652672
self.trait_ref_to_trait_def_id(*trait_ref);
653673
self.add_automatically_derived_methods_from_trait(
654-
&mut methods, trait_did, self_ty.ty);
674+
&mut methods, trait_did, self_ty.ty,
675+
local_def(item.id));
655676
}
656677
}
657678
}

0 commit comments

Comments
 (0)