Make calling methods parameterized on the trait work from default methods.

This is done by adding a new notion of "vtable_self".
We do not yet properly handle super traits.

Closes #7183.
This commit is contained in:
Michael Sullivan 2013-06-20 09:29:24 -07:00
parent a9e51f5f70
commit 817f98085f
9 changed files with 117 additions and 31 deletions

View file

@ -632,6 +632,13 @@ fn encode_vtable_origin(ecx: &e::EncodeContext,
}
}
}
typeck::vtable_self(def_id) => {
do ebml_w.emit_enum_variant("vtable_self", 2u, 1u) |ebml_w| {
do ebml_w.emit_enum_variant_arg(0u) |ebml_w| {
ebml_w.emit_def_id(def_id)
}
}
}
}
}
}
@ -652,7 +659,9 @@ impl vtable_decoder_helpers for reader::Decoder {
fn read_vtable_origin(&mut self, xcx: @ExtendedDecodeContext)
-> typeck::vtable_origin {
do self.read_enum("vtable_origin") |this| {
do this.read_enum_variant(["vtable_static", "vtable_param"])
do this.read_enum_variant(["vtable_static",
"vtable_param",
"vtable_self"])
|this, i| {
match i {
0 => {
@ -678,6 +687,13 @@ impl vtable_decoder_helpers for reader::Decoder {
}
)
}
2 => {
typeck::vtable_self(
do this.read_enum_variant_arg(0u) |this| {
this.read_def_id(xcx)
}
)
}
// hard to avoid - user input
_ => fail!("bad enum variant")
}

View file

@ -461,6 +461,7 @@ pub fn get_res_dtor(ccx: @mut CrateContext,
&tsubsts,
None,
None,
None,
None);
val

View file

@ -245,8 +245,9 @@ pub fn trans_fn_ref_with_vtables(
// We need to do a bunch of special handling for default methods.
// We need to modify the def_id and our substs in order to monomorphize
// the function.
let (def_id, opt_impl_did, substs) = match tcx.provided_method_sources.find(&def_id) {
None => (def_id, None, substs),
let (def_id, opt_impl_did, substs, self_vtable) =
match tcx.provided_method_sources.find(&def_id) {
None => (def_id, None, substs, None),
Some(source) => {
// There are two relevant substitutions when compiling
// default methods. First, there is the substitution for
@ -266,6 +267,26 @@ pub fn trans_fn_ref_with_vtables(
default methods");
let method = ty::method(tcx, source.method_id);
// Get all of the type params for the receiver
let param_defs = method.generics.type_param_defs;
let receiver_substs =
type_params.initn(param_defs.len()).to_owned();
let receiver_vtables = match vtables {
None => @~[],
Some(call_vtables) => {
let num_method_vtables =
ty::count_traits_and_supertraits(tcx, *param_defs);
@call_vtables.initn(num_method_vtables).to_owned()
}
};
let self_vtable =
typeck::vtable_static(source.impl_id, receiver_substs,
receiver_vtables);
// XXX: I think that if the *trait* has vtables on it,
// it is all over
// Compute the first substitution
let first_subst = make_substs_for_receiver_types(
tcx, source.impl_id, trait_ref, method);
@ -279,7 +300,8 @@ pub fn trans_fn_ref_with_vtables(
first_subst.repr(tcx), new_substs.repr(tcx));
(source.method_id, Some(source.impl_id), new_substs)
(source.method_id, Some(source.impl_id),
new_substs, Some(self_vtable))
}
};
@ -326,7 +348,8 @@ pub fn trans_fn_ref_with_vtables(
let (val, must_cast) =
monomorphize::monomorphic_fn(ccx, def_id, &substs,
vtables, opt_impl_did, Some(ref_id));
vtables, self_vtable,
opt_impl_did, Some(ref_id));
let mut val = val;
if must_cast && ref_id != 0 {
// Monotype of the REFERENCE to the function (type params

View file

@ -132,7 +132,8 @@ pub struct param_substs {
tys: ~[ty::t],
vtables: Option<typeck::vtable_res>,
type_param_defs: @~[ty::TypeParameterDef],
self_ty: Option<ty::t>
self_ty: Option<ty::t>,
self_vtable: Option<typeck::vtable_origin>
}
impl param_substs {
@ -981,7 +982,11 @@ pub fn monomorphize_type(bcx: block, t: ty::t) -> ty::t {
Some(substs) => {
ty::subst_tps(bcx.tcx(), substs.tys, substs.self_ty, t)
}
_ => { assert!(!ty::type_has_params(t)); t }
_ => {
assert!(!ty::type_has_params(t));
assert!(!ty::type_has_self(t));
t
}
}
}
@ -1063,6 +1068,19 @@ pub fn resolve_vtable_in_fn_ctxt(fcx: fn_ctxt, vt: typeck::vtable_origin)
}
}
}
typeck::vtable_self(_trait_id) => {
match fcx.param_substs {
Some(@param_substs
{self_vtable: Some(ref self_vtable), _}) => {
copy *self_vtable
}
_ => {
tcx.sess.bug(fmt!(
"resolve_vtable_in_fn_ctxt: asked to lookup but \
no self_vtable in the fn_ctxt!"))
}
}
}
}
}

View file

@ -139,7 +139,6 @@ pub fn trans_self_arg(bcx: block,
// Compute the type of self.
let self_ty = monomorphize_type(bcx, mentry.self_ty);
let result = trans_arg_expr(bcx,
self_ty,
mentry.self_mode,
@ -174,21 +173,6 @@ pub fn trans_method_callee(bcx: block,
// Replace method_self with method_static here.
let mut origin = mentry.origin;
match origin {
typeck::method_self(trait_id, method_index) => {
// Get the ID of the impl we're inside.
let impl_def_id = bcx.fcx.impl_id.get();
debug!("impl_def_id is %?", impl_def_id);
// Get the ID of the method we're calling.
let method_name =
ty::trait_method(tcx, trait_id, method_index).ident;
let method_id =
method_with_name_or_default(bcx.ccx(),
impl_def_id,
method_name);
origin = typeck::method_static(method_id);
}
typeck::method_super(trait_id, method_index) => {
// <self_ty> is the self type for this method call
let self_ty = node_id_type(bcx, this.id);
@ -213,6 +197,7 @@ pub fn trans_method_callee(bcx: block,
impl_id,
method_name));
}
typeck::method_self(*) |
typeck::method_static(*) | typeck::method_param(*) |
typeck::method_trait(*) => {}
}
@ -250,6 +235,21 @@ pub fn trans_method_callee(bcx: block,
None => fail!("trans_method_callee: missing param_substs")
}
}
typeck::method_self(trait_id, method_index) => {
match bcx.fcx.param_substs {
Some(@param_substs
{self_vtable: Some(ref vtbl), _}) => {
trans_monomorphized_callee(bcx, callee_id, this, mentry,
trait_id, method_index,
copy *vtbl)
}
_ => {
fail!("trans_method_callee: missing self_vtable")
}
}
}
typeck::method_trait(_, off, store) => {
trans_trait_callee(bcx,
callee_id,
@ -258,9 +258,9 @@ pub fn trans_method_callee(bcx: block,
store,
mentry.explicit_self)
}
typeck::method_self(*) | typeck::method_super(*) => {
fail!("method_self or method_super should have been handled \
above")
typeck::method_super(*) => {
fail!("method_super should have been handled \
above")
}
}
}
@ -460,6 +460,9 @@ pub fn trans_monomorphized_callee(bcx: block,
typeck::vtable_param(*) => {
fail!("vtable_param left in monomorphized function's vtable substs");
}
typeck::vtable_self(*) => {
fail!("vtable_self left in monomorphized function's vtable substs");
}
};
}

View file

@ -43,6 +43,7 @@ pub fn monomorphic_fn(ccx: @mut CrateContext,
fn_id: ast::def_id,
real_substs: &ty::substs,
vtables: Option<typeck::vtable_res>,
self_vtable: Option<typeck::vtable_origin>,
impl_did_opt: Option<ast::def_id>,
ref_id: Option<ast::node_id>)
-> (ValueRef, bool)
@ -165,6 +166,7 @@ pub fn monomorphic_fn(ccx: @mut CrateContext,
let mut pt = /* bad */copy (*pt);
pt.push(elt);
let s = mangle_exported_name(ccx, /*bad*/copy pt, mono_ty);
debug!("monomorphize_fn mangled to %s", s);
let mk_lldecl = || {
let lldecl = decl_internal_cdecl_fn(ccx.llmod, /*bad*/copy s, llfty);
@ -176,7 +178,8 @@ pub fn monomorphic_fn(ccx: @mut CrateContext,
tys: substs,
vtables: vtables,
type_param_defs: tpt.generics.type_param_defs,
self_ty: real_substs.self_ty
self_ty: real_substs.self_ty,
self_vtable: self_vtable
});
let lldecl = match map_node {

View file

@ -17,8 +17,8 @@ use middle::typeck::check::{structurally_resolved_type};
use middle::typeck::infer::fixup_err_to_str;
use middle::typeck::infer::{resolve_and_force_all_but_regions, resolve_type};
use middle::typeck::infer;
use middle::typeck::{CrateCtxt, vtable_origin, vtable_param, vtable_res};
use middle::typeck::vtable_static;
use middle::typeck::{CrateCtxt, vtable_origin, vtable_res};
use middle::typeck::{vtable_static, vtable_param, vtable_self};
use middle::subst::Subst;
use util::common::indenter;
use util::ppaux::tys_to_str;
@ -237,6 +237,17 @@ fn lookup_vtable(vcx: &VtableContext,
}
}
ty::ty_self(trait_id) => {
debug!("trying to find %? vtable for type %?",
trait_ref.def_id, trait_id);
if trait_id == trait_ref.def_id {
let vtable = vtable_self(trait_id);
debug!("found self vtable: %?", vtable);
return Some(vtable);
}
}
_ => {
let mut found = ~[];

View file

@ -20,7 +20,7 @@ use middle::typeck::check::{FnCtxt, SelfInfo};
use middle::typeck::infer::{force_all, resolve_all, resolve_region};
use middle::typeck::infer::resolve_type;
use middle::typeck::infer;
use middle::typeck::{vtable_origin, vtable_static, vtable_param};
use middle::typeck::{vtable_origin, vtable_static, vtable_param, vtable_self};
use middle::typeck::method_map_entry;
use middle::typeck::write_substs_to_tcx;
use middle::typeck::write_ty_to_tcx;
@ -104,6 +104,9 @@ fn resolve_vtable_map_entry(fcx: @mut FnCtxt, sp: span, id: ast::node_id) {
&vtable_param(n, b) => {
vtable_param(n, b)
}
&vtable_self(def_id) => {
vtable_self(def_id)
}
}
}
}

View file

@ -154,7 +154,12 @@ pub enum vtable_origin {
The first uint is the param number (identifying T in the example),
and the second is the bound number (identifying baz)
*/
vtable_param(uint, uint)
vtable_param(uint, uint),
/*
Dynamic vtable, comes from self.
*/
vtable_self(ast::def_id)
}
impl Repr for vtable_origin {
@ -171,6 +176,9 @@ impl Repr for vtable_origin {
vtable_param(x, y) => {
fmt!("vtable_param(%?, %?)", x, y)
}
vtable_self(def_id) => {
fmt!("vtable_self(%?)", def_id)
}
}
}
}