Skip to content

Commit d681bcc

Browse files
committed
auto merge of #7471 : msullivan/rust/default-methods, r=graydon
This fixes a bunch of default method bugs and restructures how vtable resolutions are represented. (It also adds a depth counter to llvm::type_to_str as a hacky work around for our circular llvm types. This is related in the sense that I needed to do it to make debug tracing not cause rustc to crash after running out of stack space.)
2 parents e239346 + 9340fd5 commit d681bcc

18 files changed

+425
-177
lines changed

Diff for: src/librustc/lib/llvm.rs

+17-6
Original file line numberDiff line numberDiff line change
@@ -2149,18 +2149,24 @@ impl TypeNames {
21492149
self.named_types.find_equiv(&s).map_consume(|x| Type::from_ref(*x))
21502150
}
21512151

2152-
pub fn type_to_str(&self, ty: Type) -> ~str {
2152+
// We have a depth count, because we seem to make infinite types.
2153+
pub fn type_to_str_depth(&self, ty: Type, depth: int) -> ~str {
21532154
match self.find_name(&ty) {
21542155
option::Some(name) => return name.to_owned(),
21552156
None => ()
21562157
}
21572158

2159+
if depth == 0 {
2160+
return ~"###";
2161+
}
2162+
21582163
unsafe {
21592164
let kind = ty.kind();
21602165

21612166
match kind {
21622167
Void => ~"Void",
21632168
Half => ~"Half",
2169+
Float => ~"Float",
21642170
Double => ~"Double",
21652171
X86_FP80 => ~"X86_FP80",
21662172
FP128 => ~"FP128",
@@ -2175,31 +2181,36 @@ impl TypeNames {
21752181
Function => {
21762182
let out_ty = ty.return_type();
21772183
let args = ty.func_params();
2178-
let args = args.map(|&ty| self.type_to_str(ty)).connect(", ");
2179-
let out_ty = self.type_to_str(out_ty);
2184+
let args =
2185+
args.map(|&ty| self.type_to_str_depth(ty, depth-1)).connect(", ");
2186+
let out_ty = self.type_to_str_depth(out_ty, depth-1);
21802187
fmt!("fn(%s) -> %s", args, out_ty)
21812188
}
21822189
Struct => {
21832190
let tys = ty.field_types();
2184-
let tys = tys.map(|&ty| self.type_to_str(ty)).connect(", ");
2191+
let tys = tys.map(|&ty| self.type_to_str_depth(ty, depth-1)).connect(", ");
21852192
fmt!("{%s}", tys)
21862193
}
21872194
Array => {
21882195
let el_ty = ty.element_type();
2189-
let el_ty = self.type_to_str(el_ty);
2196+
let el_ty = self.type_to_str_depth(el_ty, depth-1);
21902197
let len = ty.array_length();
21912198
fmt!("[%s x %u]", el_ty, len)
21922199
}
21932200
Pointer => {
21942201
let el_ty = ty.element_type();
2195-
let el_ty = self.type_to_str(el_ty);
2202+
let el_ty = self.type_to_str_depth(el_ty, depth-1);
21962203
fmt!("*%s", el_ty)
21972204
}
21982205
_ => fail!("Unknown Type Kind (%u)", kind as uint)
21992206
}
22002207
}
22012208
}
22022209

2210+
pub fn type_to_str(&self, ty: Type) -> ~str {
2211+
self.type_to_str_depth(ty, 30)
2212+
}
2213+
22032214
pub fn val_to_str(&self, val: ValueRef) -> ~str {
22042215
unsafe {
22052216
let ty = Type::from_ref(llvm::LLVMTypeOf(val));

Diff for: src/librustc/middle/astencode.rs

+24-4
Original file line numberDiff line numberDiff line change
@@ -599,8 +599,10 @@ fn encode_vtable_res(ecx: &e::EncodeContext,
599599
// ty::t doesn't work, and there is no way (atm) to have
600600
// hand-written encoding routines combine with auto-generated
601601
// ones. perhaps we should fix this.
602-
do ebml_w.emit_from_vec(*dr) |ebml_w, vtable_origin| {
603-
encode_vtable_origin(ecx, ebml_w, vtable_origin)
602+
do ebml_w.emit_from_vec(*dr) |ebml_w, param_tables| {
603+
do ebml_w.emit_from_vec(**param_tables) |ebml_w, vtable_origin| {
604+
encode_vtable_origin(ecx, ebml_w, vtable_origin)
605+
}
604606
}
605607
}
606608

@@ -632,6 +634,13 @@ fn encode_vtable_origin(ecx: &e::EncodeContext,
632634
}
633635
}
634636
}
637+
typeck::vtable_self(def_id) => {
638+
do ebml_w.emit_enum_variant("vtable_self", 2u, 1u) |ebml_w| {
639+
do ebml_w.emit_enum_variant_arg(0u) |ebml_w| {
640+
ebml_w.emit_def_id(def_id)
641+
}
642+
}
643+
}
635644
}
636645
}
637646
}
@@ -646,13 +655,17 @@ trait vtable_decoder_helpers {
646655
impl vtable_decoder_helpers for reader::Decoder {
647656
fn read_vtable_res(&mut self, xcx: @ExtendedDecodeContext)
648657
-> typeck::vtable_res {
649-
@self.read_to_vec(|this| this.read_vtable_origin(xcx))
658+
@self.read_to_vec(|this|
659+
@this.read_to_vec(|this|
660+
this.read_vtable_origin(xcx)))
650661
}
651662

652663
fn read_vtable_origin(&mut self, xcx: @ExtendedDecodeContext)
653664
-> typeck::vtable_origin {
654665
do self.read_enum("vtable_origin") |this| {
655-
do this.read_enum_variant(["vtable_static", "vtable_param"])
666+
do this.read_enum_variant(["vtable_static",
667+
"vtable_param",
668+
"vtable_self"])
656669
|this, i| {
657670
match i {
658671
0 => {
@@ -678,6 +691,13 @@ impl vtable_decoder_helpers for reader::Decoder {
678691
}
679692
)
680693
}
694+
2 => {
695+
typeck::vtable_self(
696+
do this.read_enum_variant_arg(0u) |this| {
697+
this.read_def_id(xcx)
698+
}
699+
)
700+
}
681701
// hard to avoid - user input
682702
_ => fail!("bad enum variant")
683703
}

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

+3-12
Original file line numberDiff line numberDiff line change
@@ -461,6 +461,7 @@ pub fn get_res_dtor(ccx: @mut CrateContext,
461461
&tsubsts,
462462
None,
463463
None,
464+
None,
464465
None);
465466

466467
val
@@ -1544,17 +1545,15 @@ pub fn new_fn_ctxt_w_id(ccx: @mut CrateContext,
15441545
llfndecl: ValueRef,
15451546
id: ast::node_id,
15461547
output_type: ty::t,
1547-
impl_id: Option<ast::def_id>,
15481548
param_substs: Option<@param_substs>,
15491549
sp: Option<span>)
15501550
-> fn_ctxt {
15511551
for param_substs.iter().advance |p| { p.validate(); }
15521552

1553-
debug!("new_fn_ctxt_w_id(path=%s, id=%?, impl_id=%?, \
1553+
debug!("new_fn_ctxt_w_id(path=%s, id=%?, \
15541554
param_substs=%s)",
15551555
path_str(ccx.sess, path),
15561556
id,
1557-
impl_id,
15581557
param_substs.repr(ccx.tcx));
15591558

15601559
let llbbs = mk_standard_basic_blocks(llfndecl);
@@ -1583,7 +1582,6 @@ pub fn new_fn_ctxt_w_id(ccx: @mut CrateContext,
15831582
lllocals: @mut HashMap::new(),
15841583
llupvars: @mut HashMap::new(),
15851584
id: id,
1586-
impl_id: impl_id,
15871585
param_substs: param_substs,
15881586
span: sp,
15891587
path: path,
@@ -1604,7 +1602,7 @@ pub fn new_fn_ctxt(ccx: @mut CrateContext,
16041602
output_type: ty::t,
16051603
sp: Option<span>)
16061604
-> fn_ctxt {
1607-
new_fn_ctxt_w_id(ccx, path, llfndecl, -1, output_type, None, None, sp)
1605+
new_fn_ctxt_w_id(ccx, path, llfndecl, -1, output_type, None, sp)
16081606
}
16091607

16101608
// NB: must keep 4 fns in sync:
@@ -1773,7 +1771,6 @@ pub fn trans_closure(ccx: @mut CrateContext,
17731771
self_arg: self_arg,
17741772
param_substs: Option<@param_substs>,
17751773
id: ast::node_id,
1776-
impl_id: Option<ast::def_id>,
17771774
attributes: &[ast::attribute],
17781775
output_type: ty::t,
17791776
maybe_load_env: &fn(fn_ctxt),
@@ -1791,7 +1788,6 @@ pub fn trans_closure(ccx: @mut CrateContext,
17911788
llfndecl,
17921789
id,
17931790
output_type,
1794-
impl_id,
17951791
param_substs,
17961792
Some(body.span));
17971793
let raw_llargs = create_llargs_for_fn_args(fcx, self_arg, decl.inputs);
@@ -1850,7 +1846,6 @@ pub fn trans_fn(ccx: @mut CrateContext,
18501846
self_arg: self_arg,
18511847
param_substs: Option<@param_substs>,
18521848
id: ast::node_id,
1853-
impl_id: Option<ast::def_id>,
18541849
attrs: &[ast::attribute]) {
18551850
let do_time = ccx.sess.trans_stats();
18561851
let start = if do_time { time::get_time() }
@@ -1870,7 +1865,6 @@ pub fn trans_fn(ccx: @mut CrateContext,
18701865
self_arg,
18711866
param_substs,
18721867
id,
1873-
impl_id,
18741868
attrs,
18751869
output_type,
18761870
|fcx| {
@@ -1920,7 +1914,6 @@ pub fn trans_enum_variant(ccx: @mut CrateContext,
19201914
llfndecl,
19211915
variant.node.id,
19221916
enum_ty,
1923-
None,
19241917
param_substs,
19251918
None);
19261919

@@ -2000,7 +1993,6 @@ pub fn trans_tuple_struct(ccx: @mut CrateContext,
20001993
llfndecl,
20011994
ctor_id,
20021995
tup_ty,
2003-
None,
20041996
param_substs,
20051997
None);
20061998
@@ -2080,7 +2072,6 @@ pub fn trans_item(ccx: @mut CrateContext, item: &ast::item) {
20802072
no_self,
20812073
None,
20822074
item.id,
2083-
None,
20842075
item.attrs);
20852076
} else {
20862077
for body.node.stmts.iter().advance |stmt| {

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

+90-8
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
// closure.
1818

1919
use core::prelude::*;
20+
use core::vec;
2021

2122
use back::abi;
2223
use driver::session;
@@ -194,6 +195,58 @@ pub fn trans_fn_ref_with_vtables_to_callee(
194195
type_params, vtables))}
195196
}
196197

198+
fn get_impl_resolutions(bcx: block,
199+
impl_id: ast::def_id)
200+
-> typeck::vtable_res {
201+
if impl_id.crate == ast::local_crate {
202+
*bcx.ccx().maps.vtable_map.get(&impl_id.node)
203+
} else {
204+
// XXX: This is a temporary hack to work around not properly
205+
// exporting information about resolutions for impls.
206+
// This doesn't actually work if the trait has param bounds,
207+
// but it does allow us to survive the case when it does not.
208+
let trait_ref = ty::impl_trait_ref(bcx.tcx(), impl_id).get();
209+
@vec::from_elem(trait_ref.substs.tps.len(), @~[])
210+
}
211+
}
212+
213+
fn resolve_default_method_vtables(bcx: block,
214+
impl_id: ast::def_id,
215+
method: &ty::Method,
216+
substs: &ty::substs,
217+
impl_vtables: Option<typeck::vtable_res>)
218+
-> typeck::vtable_res {
219+
220+
// Get the vtables that the impl implements the trait at
221+
let trait_vtables = get_impl_resolutions(bcx, impl_id);
222+
223+
// Build up a param_substs that we are going to resolve the
224+
// trait_vtables under.
225+
let param_substs = Some(@param_substs {
226+
tys: copy substs.tps,
227+
self_ty: substs.self_ty,
228+
vtables: impl_vtables,
229+
self_vtable: None
230+
});
231+
232+
let trait_vtables_fixed = resolve_vtables_under_param_substs(
233+
bcx.tcx(), param_substs, trait_vtables);
234+
235+
// Now we pull any vtables for parameters on the actual method.
236+
let num_method_vtables = method.generics.type_param_defs.len();
237+
let method_vtables = match impl_vtables {
238+
Some(vtables) => {
239+
let num_impl_type_parameters =
240+
vtables.len() - num_method_vtables;
241+
vtables.tailn(num_impl_type_parameters).to_owned()
242+
},
243+
None => vec::from_elem(num_method_vtables, @~[])
244+
};
245+
246+
@(*trait_vtables_fixed + method_vtables)
247+
}
248+
249+
197250
pub fn trans_fn_ref_with_vtables(
198251
bcx: block, //
199252
def_id: ast::def_id, // def id of fn
@@ -233,15 +286,21 @@ pub fn trans_fn_ref_with_vtables(
233286
// Polytype of the function item (may have type params)
234287
let fn_tpt = ty::lookup_item_type(tcx, def_id);
235288

236-
let substs = ty::substs { self_r: None, self_ty: None,
289+
// For simplicity, we want to use the Subst trait when composing
290+
// substitutions for default methods. The subst trait does
291+
// substitutions with regions, though, so we put a dummy self
292+
// region parameter in to keep it from failing. This is a hack.
293+
let substs = ty::substs { self_r: Some(ty::re_empty),
294+
self_ty: None,
237295
tps: /*bad*/ type_params.to_owned() };
238296

239297

240298
// We need to do a bunch of special handling for default methods.
241299
// We need to modify the def_id and our substs in order to monomorphize
242300
// the function.
243-
let (def_id, opt_impl_did, substs) = match tcx.provided_method_sources.find(&def_id) {
244-
None => (def_id, None, substs),
301+
let (def_id, opt_impl_did, substs, self_vtable, vtables) =
302+
match tcx.provided_method_sources.find(&def_id) {
303+
None => (def_id, None, substs, None, vtables),
245304
Some(source) => {
246305
// There are two relevant substitutions when compiling
247306
// default methods. First, there is the substitution for
@@ -261,20 +320,42 @@ pub fn trans_fn_ref_with_vtables(
261320
default methods");
262321
let method = ty::method(tcx, source.method_id);
263322

323+
// Get all of the type params for the receiver
324+
let param_defs = method.generics.type_param_defs;
325+
let receiver_substs =
326+
type_params.initn(param_defs.len()).to_owned();
327+
let receiver_vtables = match vtables {
328+
None => @~[],
329+
Some(call_vtables) => {
330+
@call_vtables.initn(param_defs.len()).to_owned()
331+
}
332+
};
333+
334+
let self_vtable =
335+
typeck::vtable_static(source.impl_id, receiver_substs,
336+
receiver_vtables);
264337
// Compute the first substitution
265338
let first_subst = make_substs_for_receiver_types(
266339
tcx, source.impl_id, trait_ref, method);
267340

268341
// And compose them
269342
let new_substs = first_subst.subst(tcx, &substs);
343+
344+
345+
let vtables =
346+
resolve_default_method_vtables(bcx, source.impl_id,
347+
method, &new_substs, vtables);
348+
270349
debug!("trans_fn_with_vtables - default method: \
271350
substs = %s, trait_subst = %s, \
272-
first_subst = %s, new_subst = %s",
351+
first_subst = %s, new_subst = %s, \
352+
self_vtable = %s, vtables = %s",
273353
substs.repr(tcx), trait_ref.substs.repr(tcx),
274-
first_subst.repr(tcx), new_substs.repr(tcx));
275-
354+
first_subst.repr(tcx), new_substs.repr(tcx),
355+
self_vtable.repr(tcx), vtables.repr(tcx));
276356

277-
(source.method_id, Some(source.impl_id), new_substs)
357+
(source.method_id, Some(source.impl_id),
358+
new_substs, Some(self_vtable), Some(vtables))
278359
}
279360
};
280361

@@ -321,7 +402,8 @@ pub fn trans_fn_ref_with_vtables(
321402

322403
let (val, must_cast) =
323404
monomorphize::monomorphic_fn(ccx, def_id, &substs,
324-
vtables, opt_impl_did, Some(ref_id));
405+
vtables, self_vtable,
406+
opt_impl_did, Some(ref_id));
325407
let mut val = val;
326408
if must_cast && ref_id != 0 {
327409
// Monotype of the REFERENCE to the function (type params

Diff for: src/librustc/middle/trans/closure.rs

-1
Original file line numberDiff line numberDiff line change
@@ -444,7 +444,6 @@ pub fn trans_expr_fn(bcx: block,
444444
no_self,
445445
/*bad*/ copy bcx.fcx.param_substs,
446446
user_id,
447-
None,
448447
[],
449448
real_return_type,
450449
|fcx| load_environment(fcx, cdata_ty, cap_vars,

0 commit comments

Comments
 (0)