From 817f98085f2332b604f0a2da5127f29c8fabc41f Mon Sep 17 00:00:00 2001 From: Michael Sullivan Date: Thu, 20 Jun 2013 09:29:24 -0700 Subject: [PATCH] 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. --- src/librustc/middle/astencode.rs | 18 +++++++- src/librustc/middle/trans/base.rs | 1 + src/librustc/middle/trans/callee.rs | 31 ++++++++++++-- src/librustc/middle/trans/common.rs | 22 +++++++++- src/librustc/middle/trans/meth.rs | 41 ++++++++++--------- src/librustc/middle/trans/monomorphize.rs | 5 ++- src/librustc/middle/typeck/check/vtable.rs | 15 ++++++- src/librustc/middle/typeck/check/writeback.rs | 5 ++- src/librustc/middle/typeck/mod.rs | 10 ++++- 9 files changed, 117 insertions(+), 31 deletions(-) diff --git a/src/librustc/middle/astencode.rs b/src/librustc/middle/astencode.rs index 70e94844319e..c1d553b04541 100644 --- a/src/librustc/middle/astencode.rs +++ b/src/librustc/middle/astencode.rs @@ -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") } diff --git a/src/librustc/middle/trans/base.rs b/src/librustc/middle/trans/base.rs index df7f73a52436..8e8270320c69 100644 --- a/src/librustc/middle/trans/base.rs +++ b/src/librustc/middle/trans/base.rs @@ -461,6 +461,7 @@ pub fn get_res_dtor(ccx: @mut CrateContext, &tsubsts, None, None, + None, None); val diff --git a/src/librustc/middle/trans/callee.rs b/src/librustc/middle/trans/callee.rs index 27f1c4d039da..dc18c6b17ee5 100644 --- a/src/librustc/middle/trans/callee.rs +++ b/src/librustc/middle/trans/callee.rs @@ -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 diff --git a/src/librustc/middle/trans/common.rs b/src/librustc/middle/trans/common.rs index a7ffa8e13b02..b9e1ba7a8d9a 100644 --- a/src/librustc/middle/trans/common.rs +++ b/src/librustc/middle/trans/common.rs @@ -132,7 +132,8 @@ pub struct param_substs { tys: ~[ty::t], vtables: Option, type_param_defs: @~[ty::TypeParameterDef], - self_ty: Option + self_ty: Option, + self_vtable: Option } 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!")) + } + } + } } } diff --git a/src/librustc/middle/trans/meth.rs b/src/librustc/middle/trans/meth.rs index fc0c9c06c450..5087fcca7886 100644 --- a/src/librustc/middle/trans/meth.rs +++ b/src/librustc/middle/trans/meth.rs @@ -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) => { // 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"); + } }; } diff --git a/src/librustc/middle/trans/monomorphize.rs b/src/librustc/middle/trans/monomorphize.rs index 586dfd7e98a0..06dec1995d94 100644 --- a/src/librustc/middle/trans/monomorphize.rs +++ b/src/librustc/middle/trans/monomorphize.rs @@ -43,6 +43,7 @@ pub fn monomorphic_fn(ccx: @mut CrateContext, fn_id: ast::def_id, real_substs: &ty::substs, vtables: Option, + self_vtable: Option, impl_did_opt: Option, ref_id: Option) -> (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 { diff --git a/src/librustc/middle/typeck/check/vtable.rs b/src/librustc/middle/typeck/check/vtable.rs index bd78e9cc5fb4..a886e06139ec 100644 --- a/src/librustc/middle/typeck/check/vtable.rs +++ b/src/librustc/middle/typeck/check/vtable.rs @@ -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 = ~[]; diff --git a/src/librustc/middle/typeck/check/writeback.rs b/src/librustc/middle/typeck/check/writeback.rs index dd9d68beb1fd..73710978ad49 100644 --- a/src/librustc/middle/typeck/check/writeback.rs +++ b/src/librustc/middle/typeck/check/writeback.rs @@ -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) + } } } } diff --git a/src/librustc/middle/typeck/mod.rs b/src/librustc/middle/typeck/mod.rs index d834998d4ee2..3511844bb9f4 100644 --- a/src/librustc/middle/typeck/mod.rs +++ b/src/librustc/middle/typeck/mod.rs @@ -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) + } } } }