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:
parent
a9e51f5f70
commit
817f98085f
9 changed files with 117 additions and 31 deletions
|
|
@ -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")
|
||||
}
|
||||
|
|
|
|||
|
|
@ -461,6 +461,7 @@ pub fn get_res_dtor(ccx: @mut CrateContext,
|
|||
&tsubsts,
|
||||
None,
|
||||
None,
|
||||
None,
|
||||
None);
|
||||
|
||||
val
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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!"))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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");
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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 {
|
||||
|
|
|
|||
|
|
@ -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 = ~[];
|
||||
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue