Skip to content

Commit 6a6d3b6

Browse files
committed
Make supertrait methods callable on object types.
This requires changes to method search and to codegen. We now emit a vtable for objects that includes methods from all supertraits. Closes #4100. Also, actually populate the cache for vtables, and also key it by type so that it actually works.
1 parent dc9b3e3 commit 6a6d3b6

File tree

10 files changed

+225
-170
lines changed

10 files changed

+225
-170
lines changed

src/librustc/middle/astencode.rs

+7-2
Original file line numberDiff line numberDiff line change
@@ -586,8 +586,13 @@ impl tr for method_origin {
586586
}
587587
)
588588
}
589-
typeck::method_trait(did, m) => {
590-
typeck::method_trait(did.tr(xcx), m)
589+
typeck::method_object(ref mo) => {
590+
typeck::method_object(
591+
typeck::method_object {
592+
trait_id: mo.trait_id.tr(xcx),
593+
.. *mo
594+
}
595+
)
591596
}
592597
}
593598
}

src/librustc/middle/privacy.rs

+7-3
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ use metadata::csearch;
1616
use middle::ty::{ty_struct, ty_enum};
1717
use middle::ty;
1818
use middle::typeck::{method_map, method_origin, method_param};
19-
use middle::typeck::{method_static, method_trait};
19+
use middle::typeck::{method_static, method_object};
2020

2121
use std::util::ignore;
2222
use syntax::ast::{decl_item, def, def_fn, def_id, def_static_method};
@@ -280,10 +280,14 @@ impl PrivacyVisitor {
280280
}
281281
method_param(method_param {
282282
trait_id: trait_id,
283-
method_num: method_num,
283+
method_num: method_num,
284284
_
285285
}) |
286-
method_trait(trait_id, method_num) => {
286+
method_object(method_object {
287+
trait_id: trait_id,
288+
method_num: method_num,
289+
_
290+
}) => {
287291
if trait_id.crate == LOCAL_CRATE {
288292
match self.tcx.items.find(&trait_id.node) {
289293
Some(&node_item(item, _)) => {

src/librustc/middle/trans/common.rs

+4-11
Original file line numberDiff line numberDiff line change
@@ -1015,6 +1015,8 @@ pub fn node_vtables(bcx: @mut Block, id: ast::NodeId)
10151015
raw_vtables.map_move(|vts| resolve_vtables_in_fn_ctxt(bcx.fcx, *vts))
10161016
}
10171017

1018+
// Apply the typaram substitutions in the FunctionContext to some
1019+
// vtables. This should eliminate any vtable_params.
10181020
pub fn resolve_vtables_in_fn_ctxt(fcx: &FunctionContext, vts: typeck::vtable_res)
10191021
-> typeck::vtable_res {
10201022
resolve_vtables_under_param_substs(fcx.ccx.tcx,
@@ -1047,15 +1049,6 @@ pub fn resolve_param_vtables_under_param_substs(
10471049

10481050

10491051

1050-
// Apply the typaram substitutions in the FunctionContext to a vtable. This should
1051-
// eliminate any vtable_params.
1052-
pub fn resolve_vtable_in_fn_ctxt(fcx: &FunctionContext, vt: &typeck::vtable_origin)
1053-
-> typeck::vtable_origin {
1054-
resolve_vtable_under_param_substs(fcx.ccx.tcx,
1055-
fcx.param_substs,
1056-
vt)
1057-
}
1058-
10591052
pub fn resolve_vtable_under_param_substs(tcx: ty::ctxt,
10601053
param_substs: Option<@param_substs>,
10611054
vt: &typeck::vtable_origin)
@@ -1081,8 +1074,8 @@ pub fn resolve_vtable_under_param_substs(tcx: ty::ctxt,
10811074
}
10821075
_ => {
10831076
tcx.sess.bug(fmt!(
1084-
"resolve_vtable_in_fn_ctxt: asked to lookup but \
1085-
no vtables in the fn_ctxt!"))
1077+
"resolve_vtable_under_param_substs: asked to lookup \
1078+
but no vtables in the fn_ctxt!"))
10861079
}
10871080
}
10881081
}

src/librustc/middle/trans/context.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -67,7 +67,7 @@ pub struct CrateContext {
6767
// Cache computed type parameter uses (see type_use.rs)
6868
type_use_cache: HashMap<ast::def_id, @~[type_use::type_uses]>,
6969
// Cache generated vtables
70-
vtables: HashMap<mono_id, ValueRef>,
70+
vtables: HashMap<(ty::t, mono_id), ValueRef>,
7171
// Cache of constant strings,
7272
const_cstr_cache: HashMap<@str, ValueRef>,
7373

src/librustc/middle/trans/meth.rs

+42-33
Original file line numberDiff line numberDiff line change
@@ -186,10 +186,10 @@ pub fn trans_method_callee(bcx: @mut Block,
186186
}
187187
}
188188

189-
typeck::method_trait(_, off) => {
189+
typeck::method_object(ref mt) => {
190190
trans_trait_callee(bcx,
191191
callee_id,
192-
off,
192+
mt.real_index,
193193
this)
194194
}
195195
}
@@ -398,7 +398,6 @@ pub fn combine_impl_and_methods_tps(bcx: @mut Block,
398398
return (ty_substs, vtables);
399399
}
400400

401-
402401
pub fn trans_trait_callee(bcx: @mut Block,
403402
callee_id: ast::NodeId,
404403
n_method: uint,
@@ -506,20 +505,35 @@ pub fn vtable_id(ccx: @mut CrateContext,
506505
/// This is used only for objects.
507506
pub fn get_vtable(bcx: @mut Block,
508507
self_ty: ty::t,
509-
origin: typeck::vtable_origin)
508+
origins: typeck::vtable_param_res)
510509
-> ValueRef {
511-
let hash_id = vtable_id(bcx.ccx(), &origin);
512-
match bcx.ccx().vtables.find(&hash_id) {
513-
Some(&val) => val,
514-
None => {
515-
match origin {
516-
typeck::vtable_static(id, substs, sub_vtables) => {
517-
make_impl_vtable(bcx, id, self_ty, substs, sub_vtables)
518-
}
519-
_ => fail!("get_vtable: expected a static origin"),
510+
let ccx = bcx.ccx();
511+
let _icx = push_ctxt("impl::get_vtable");
512+
513+
// Check the cache.
514+
let hash_id = (self_ty, vtable_id(ccx, &origins[0]));
515+
match ccx.vtables.find(&hash_id) {
516+
Some(&val) => { return val }
517+
None => { }
518+
}
519+
520+
// Not in the cache. Actually build it.
521+
let methods = do origins.flat_map |origin| {
522+
match *origin {
523+
typeck::vtable_static(id, ref substs, sub_vtables) => {
524+
emit_vtable_methods(bcx, id, *substs, sub_vtables)
520525
}
526+
_ => ccx.sess.bug("get_vtable: expected a static origin"),
521527
}
522-
}
528+
};
529+
530+
// Generate a type descriptor for the vtable.
531+
let tydesc = get_tydesc(ccx, self_ty);
532+
glue::lazily_emit_all_tydesc_glue(ccx, tydesc);
533+
534+
let vtable = make_vtable(ccx, tydesc, methods);
535+
ccx.vtables.insert(hash_id, vtable);
536+
return vtable;
523537
}
524538

525539
/// Helper function to declare and initialize the vtable.
@@ -547,15 +561,12 @@ pub fn make_vtable(ccx: &mut CrateContext,
547561
}
548562
}
549563

550-
/// Generates a dynamic vtable for objects.
551-
pub fn make_impl_vtable(bcx: @mut Block,
552-
impl_id: ast::def_id,
553-
self_ty: ty::t,
554-
substs: &[ty::t],
555-
vtables: typeck::vtable_res)
556-
-> ValueRef {
564+
fn emit_vtable_methods(bcx: @mut Block,
565+
impl_id: ast::def_id,
566+
substs: &[ty::t],
567+
vtables: typeck::vtable_res)
568+
-> ~[ValueRef] {
557569
let ccx = bcx.ccx();
558-
let _icx = push_ctxt("impl::make_impl_vtable");
559570
let tcx = ccx.tcx;
560571

561572
let trt_id = match ty::impl_trait_ref(tcx, impl_id) {
@@ -565,7 +576,7 @@ pub fn make_impl_vtable(bcx: @mut Block,
565576
};
566577

567578
let trait_method_def_ids = ty::trait_method_def_ids(tcx, trt_id);
568-
let methods = do trait_method_def_ids.map |method_def_id| {
579+
do trait_method_def_ids.map |method_def_id| {
569580
let im = ty::method(tcx, *method_def_id);
570581
let fty = ty::subst_tps(tcx,
571582
substs,
@@ -583,13 +594,7 @@ pub fn make_impl_vtable(bcx: @mut Block,
583594
trans_fn_ref_with_vtables(bcx, m_id, 0,
584595
substs, Some(vtables)).llfn
585596
}
586-
};
587-
588-
// Generate a type descriptor for the vtable.
589-
let tydesc = get_tydesc(ccx, self_ty);
590-
glue::lazily_emit_all_tydesc_glue(ccx, tydesc);
591-
592-
make_vtable(ccx, tydesc, methods)
597+
}
593598
}
594599

595600
pub fn trans_trait_cast(bcx: @mut Block,
@@ -621,9 +626,13 @@ pub fn trans_trait_cast(bcx: @mut Block,
621626
bcx = expr::trans_into(bcx, val, SaveIn(llboxdest));
622627

623628
// Store the vtable into the pair or triple.
624-
let orig = ccx.maps.vtable_map.get(&id)[0][0].clone();
625-
let orig = resolve_vtable_in_fn_ctxt(bcx.fcx, &orig);
626-
let vtable = get_vtable(bcx, v_ty, orig);
629+
// This is structured a bit funny because of dynamic borrow failures.
630+
let origins = {
631+
let res = ccx.maps.vtable_map.get(&id);
632+
let res = resolve_vtables_in_fn_ctxt(bcx.fcx, *res);
633+
res[0]
634+
};
635+
let vtable = get_vtable(bcx, v_ty, origins);
627636
Store(bcx, vtable, PointerCast(bcx,
628637
GEPi(bcx, lldest, [0u, abi::trt_field_vtable]),
629638
val_ty(vtable).ptr_to()));

src/librustc/middle/ty.rs

+5-2
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,7 @@ pub struct field {
5959
mt: mt
6060
}
6161

62+
#[deriving(Clone)]
6263
pub struct Method {
6364
ident: ast::ident,
6465
generics: ty::Generics,
@@ -3136,12 +3137,14 @@ pub fn method_call_type_param_defs(tcx: ctxt,
31363137
typeck::method_param(typeck::method_param {
31373138
trait_id: trt_id,
31383139
method_num: n_mth, _}) |
3139-
typeck::method_trait(trt_id, n_mth) => {
3140+
typeck::method_object(typeck::method_object {
3141+
trait_id: trt_id,
3142+
method_num: n_mth, _}) => {
31403143
// ...trait methods bounds, in contrast, include only the
31413144
// method bounds, so we must preprend the tps from the
31423145
// trait itself. This ought to be harmonized.
31433146
let trait_type_param_defs =
3144-
ty::lookup_trait_def(tcx, trt_id).generics.type_param_defs;
3147+
lookup_trait_def(tcx, trt_id).generics.type_param_defs;
31453148
@vec::append(
31463149
(*trait_type_param_defs).clone(),
31473150
*ty::trait_method(tcx,

0 commit comments

Comments
 (0)