auto merge of #8519 : msullivan/rust/objects, r=catamorphism

r?
This commit is contained in:
bors 2013-08-20 13:32:00 -07:00
commit 293660d443
11 changed files with 226 additions and 171 deletions

View File

@ -586,8 +586,13 @@ fn tr(&self, xcx: @ExtendedDecodeContext) -> method_origin {
}
)
}
typeck::method_trait(did, m) => {
typeck::method_trait(did.tr(xcx), m)
typeck::method_object(ref mo) => {
typeck::method_object(
typeck::method_object {
trait_id: mo.trait_id.tr(xcx),
.. *mo
}
)
}
}
}

View File

@ -16,7 +16,7 @@
use middle::ty::{ty_struct, ty_enum};
use middle::ty;
use middle::typeck::{method_map, method_origin, method_param};
use middle::typeck::{method_static, method_trait};
use middle::typeck::{method_static, method_object};
use std::util::ignore;
use syntax::ast::{decl_item, def, def_fn, def_id, def_static_method};
@ -280,10 +280,14 @@ fn check_method(&mut self, span: span, origin: &method_origin, ident: ast::ident
}
method_param(method_param {
trait_id: trait_id,
method_num: method_num,
method_num: method_num,
_
}) |
method_trait(trait_id, method_num) => {
method_object(method_object {
trait_id: trait_id,
method_num: method_num,
_
}) => {
if trait_id.crate == LOCAL_CRATE {
match self.tcx.items.find(&trait_id.node) {
Some(&node_item(item, _)) => {

View File

@ -1015,6 +1015,8 @@ pub fn node_vtables(bcx: @mut Block, id: ast::NodeId)
raw_vtables.map_move(|vts| resolve_vtables_in_fn_ctxt(bcx.fcx, *vts))
}
// Apply the typaram substitutions in the FunctionContext to some
// vtables. This should eliminate any vtable_params.
pub fn resolve_vtables_in_fn_ctxt(fcx: &FunctionContext, vts: typeck::vtable_res)
-> typeck::vtable_res {
resolve_vtables_under_param_substs(fcx.ccx.tcx,
@ -1047,15 +1049,6 @@ pub fn resolve_param_vtables_under_param_substs(
// Apply the typaram substitutions in the FunctionContext to a vtable. This should
// eliminate any vtable_params.
pub fn resolve_vtable_in_fn_ctxt(fcx: &FunctionContext, vt: &typeck::vtable_origin)
-> typeck::vtable_origin {
resolve_vtable_under_param_substs(fcx.ccx.tcx,
fcx.param_substs,
vt)
}
pub fn resolve_vtable_under_param_substs(tcx: ty::ctxt,
param_substs: Option<@param_substs>,
vt: &typeck::vtable_origin)
@ -1081,8 +1074,8 @@ pub fn resolve_vtable_under_param_substs(tcx: ty::ctxt,
}
_ => {
tcx.sess.bug(fmt!(
"resolve_vtable_in_fn_ctxt: asked to lookup but \
no vtables in the fn_ctxt!"))
"resolve_vtable_under_param_substs: asked to lookup \
but no vtables in the fn_ctxt!"))
}
}
}

View File

@ -67,7 +67,7 @@ pub struct CrateContext {
// Cache computed type parameter uses (see type_use.rs)
type_use_cache: HashMap<ast::def_id, @~[type_use::type_uses]>,
// Cache generated vtables
vtables: HashMap<mono_id, ValueRef>,
vtables: HashMap<(ty::t, mono_id), ValueRef>,
// Cache of constant strings,
const_cstr_cache: HashMap<@str, ValueRef>,

View File

@ -186,10 +186,10 @@ pub fn trans_method_callee(bcx: @mut Block,
}
}
typeck::method_trait(_, off) => {
typeck::method_object(ref mt) => {
trans_trait_callee(bcx,
callee_id,
off,
mt.real_index,
this)
}
}
@ -398,7 +398,6 @@ pub fn combine_impl_and_methods_tps(bcx: @mut Block,
return (ty_substs, vtables);
}
pub fn trans_trait_callee(bcx: @mut Block,
callee_id: ast::NodeId,
n_method: uint,
@ -506,20 +505,35 @@ pub fn vtable_id(ccx: @mut CrateContext,
/// This is used only for objects.
pub fn get_vtable(bcx: @mut Block,
self_ty: ty::t,
origin: typeck::vtable_origin)
origins: typeck::vtable_param_res)
-> ValueRef {
let hash_id = vtable_id(bcx.ccx(), &origin);
match bcx.ccx().vtables.find(&hash_id) {
Some(&val) => val,
None => {
match origin {
typeck::vtable_static(id, substs, sub_vtables) => {
make_impl_vtable(bcx, id, self_ty, substs, sub_vtables)
}
_ => fail!("get_vtable: expected a static origin"),
}
}
let ccx = bcx.ccx();
let _icx = push_ctxt("impl::get_vtable");
// Check the cache.
let hash_id = (self_ty, vtable_id(ccx, &origins[0]));
match ccx.vtables.find(&hash_id) {
Some(&val) => { return val }
None => { }
}
// Not in the cache. Actually build it.
let methods = do origins.flat_map |origin| {
match *origin {
typeck::vtable_static(id, ref substs, sub_vtables) => {
emit_vtable_methods(bcx, id, *substs, sub_vtables)
}
_ => ccx.sess.bug("get_vtable: expected a static origin"),
}
};
// Generate a type descriptor for the vtable.
let tydesc = get_tydesc(ccx, self_ty);
glue::lazily_emit_all_tydesc_glue(ccx, tydesc);
let vtable = make_vtable(ccx, tydesc, methods);
ccx.vtables.insert(hash_id, vtable);
return vtable;
}
/// Helper function to declare and initialize the vtable.
@ -547,15 +561,12 @@ pub fn make_vtable(ccx: &mut CrateContext,
}
}
/// Generates a dynamic vtable for objects.
pub fn make_impl_vtable(bcx: @mut Block,
impl_id: ast::def_id,
self_ty: ty::t,
substs: &[ty::t],
vtables: typeck::vtable_res)
-> ValueRef {
fn emit_vtable_methods(bcx: @mut Block,
impl_id: ast::def_id,
substs: &[ty::t],
vtables: typeck::vtable_res)
-> ~[ValueRef] {
let ccx = bcx.ccx();
let _icx = push_ctxt("impl::make_impl_vtable");
let tcx = ccx.tcx;
let trt_id = match ty::impl_trait_ref(tcx, impl_id) {
@ -565,7 +576,7 @@ pub fn make_impl_vtable(bcx: @mut Block,
};
let trait_method_def_ids = ty::trait_method_def_ids(tcx, trt_id);
let methods = do trait_method_def_ids.map |method_def_id| {
do trait_method_def_ids.map |method_def_id| {
let im = ty::method(tcx, *method_def_id);
let fty = ty::subst_tps(tcx,
substs,
@ -583,13 +594,7 @@ pub fn make_impl_vtable(bcx: @mut Block,
trans_fn_ref_with_vtables(bcx, m_id, 0,
substs, Some(vtables)).llfn
}
};
// Generate a type descriptor for the vtable.
let tydesc = get_tydesc(ccx, self_ty);
glue::lazily_emit_all_tydesc_glue(ccx, tydesc);
make_vtable(ccx, tydesc, methods)
}
}
pub fn trans_trait_cast(bcx: @mut Block,
@ -621,9 +626,13 @@ pub fn trans_trait_cast(bcx: @mut Block,
bcx = expr::trans_into(bcx, val, SaveIn(llboxdest));
// Store the vtable into the pair or triple.
let orig = ccx.maps.vtable_map.get(&id)[0][0].clone();
let orig = resolve_vtable_in_fn_ctxt(bcx.fcx, &orig);
let vtable = get_vtable(bcx, v_ty, orig);
// This is structured a bit funny because of dynamic borrow failures.
let origins = {
let res = ccx.maps.vtable_map.get(&id);
let res = resolve_vtables_in_fn_ctxt(bcx.fcx, *res);
res[0]
};
let vtable = get_vtable(bcx, v_ty, origins);
Store(bcx, vtable, PointerCast(bcx,
GEPi(bcx, lldest, [0u, abi::trt_field_vtable]),
val_ty(vtable).ptr_to()));

View File

@ -59,6 +59,7 @@ pub struct field {
mt: mt
}
#[deriving(Clone)]
pub struct Method {
ident: ast::ident,
generics: ty::Generics,
@ -3136,12 +3137,14 @@ pub fn method_call_type_param_defs(tcx: ctxt,
typeck::method_param(typeck::method_param {
trait_id: trt_id,
method_num: n_mth, _}) |
typeck::method_trait(trt_id, n_mth) => {
typeck::method_object(typeck::method_object {
trait_id: trt_id,
method_num: n_mth, _}) => {
// ...trait methods bounds, in contrast, include only the
// method bounds, so we must preprend the tps from the
// trait itself. This ought to be harmonized.
let trait_type_param_defs =
ty::lookup_trait_def(tcx, trt_id).generics.type_param_defs;
lookup_trait_def(tcx, trt_id).generics.type_param_defs;
@vec::append(
(*trait_type_param_defs).clone(),
*ty::trait_method(tcx,

View File

@ -90,7 +90,7 @@ trait `ToStr` imported, and I call `to_str()` on a value of type `T`,
use middle::typeck::check;
use middle::typeck::infer;
use middle::typeck::{method_map_entry, method_origin, method_param};
use middle::typeck::{method_static, method_trait};
use middle::typeck::{method_static, method_object};
use middle::typeck::{param_numbered, param_self, param_index};
use middle::typeck::check::regionmanip::replace_bound_regions_in_fn_sig;
use util::common::indenter;
@ -298,7 +298,7 @@ fn push_inherent_candidates(&self, self_ty: ty::t) {
loop {
match get(self_ty).sty {
ty_trait(did, ref substs, _, _, _) => {
self.push_inherent_candidates_from_trait(did, substs);
self.push_inherent_candidates_from_object(did, substs);
self.push_inherent_impl_candidates_for_type(did);
}
ty_enum(did, _) | ty_struct(did, _) => {
@ -363,53 +363,85 @@ fn push_extension_candidates(&self) {
}
}
fn push_inherent_candidates_from_trait(&self,
did: def_id,
substs: &ty::substs) {
debug!("push_inherent_candidates_from_trait(did=%s, substs=%s)",
// Determine the index of a method in the list of all methods belonging
// to a trait and its supertraits.
fn get_method_index(&self,
trait_ref: @TraitRef,
subtrait_id: ast::def_id,
n_method: uint) -> uint {
let tcx = self.tcx();
// We need to figure the "real index" of the method in a
// listing of all the methods of an object. We do this by
// iterating down the supertraits of the object's trait until
// we find the trait the method came from, counting up the
// methods from them.
let mut method_count = 0;
do ty::each_bound_trait_and_supertraits(tcx, &[trait_ref])
|bound_ref| {
if bound_ref.def_id == subtrait_id { false }
else {
method_count += ty::trait_methods(tcx, bound_ref.def_id).len();
true
}
};
return method_count + n_method;
}
fn push_inherent_candidates_from_object(&self,
did: def_id,
substs: &ty::substs) {
debug!("push_inherent_candidates_from_object(did=%s, substs=%s)",
self.did_to_str(did),
substs_to_str(self.tcx(), substs));
let _indenter = indenter();
let tcx = self.tcx();
let ms = ty::trait_methods(tcx, did);
let index = match ms.iter().position(|m| m.ident == self.m_name) {
Some(i) => i,
None => { return; } // no method with the right name
};
let method = ms[index];
match method.explicit_self {
ast::sty_static => {
return; // not a method we can call with dot notation
}
_ => {}
}
// It is illegal to invoke a method on a trait instance that
// refers to the `self` type. An error will be reported by
// `enforce_object_limitations()` if the method refers
// to the `Self` type. Substituting ty_err here allows
// compiler to soldier on.
//
// NOTE: `confirm_candidate()` also relies upon this substitution
// `confirm_candidate()` also relies upon this substitution
// for Self. (fix)
let rcvr_substs = substs {
self_ty: Some(ty::mk_err()),
..(*substs).clone()
};
let trait_ref = @TraitRef { def_id: did, substs: rcvr_substs.clone() };
self.inherent_candidates.push(Candidate {
rcvr_match_condition: RcvrMatchesIfObject(did),
rcvr_substs: rcvr_substs,
method_ty: method,
origin: method_trait(did, index)
});
do self.push_inherent_candidates_from_bounds_inner(&[trait_ref])
|trait_ref, m, method_num, _bound_num| {
let vtable_index =
self.get_method_index(trait_ref, trait_ref.def_id, method_num);
// We need to fix up the transformed self type.
let transformed_self_ty =
self.construct_transformed_self_ty_for_object(
did, &rcvr_substs, m);
let m = @Method {
transformed_self_ty: Some(transformed_self_ty),
.. (*m).clone()
};
Candidate {
rcvr_match_condition: RcvrMatchesIfObject(did),
rcvr_substs: trait_ref.substs.clone(),
method_ty: m,
origin: method_object(method_object {
trait_id: trait_ref.def_id,
object_trait_id: did,
method_num: method_num,
real_index: vtable_index
})
}
};
}
fn push_inherent_candidates_from_param(&self,
rcvr_ty: ty::t,
param_ty: param_ty) {
rcvr_ty: ty::t,
param_ty: param_ty) {
debug!("push_inherent_candidates_from_param(param_ty=%?)",
param_ty);
let _indenter = indenter();
@ -441,9 +473,34 @@ fn push_inherent_candidates_from_self(&self,
}
fn push_inherent_candidates_from_bounds(&self,
self_ty: ty::t,
bounds: &[@TraitRef],
param: param_index) {
self_ty: ty::t,
bounds: &[@TraitRef],
param: param_index) {
do self.push_inherent_candidates_from_bounds_inner(bounds)
|trait_ref, m, method_num, bound_num| {
Candidate {
rcvr_match_condition: RcvrMatchesIfSubtype(self_ty),
rcvr_substs: trait_ref.substs.clone(),
method_ty: m,
origin: method_param(
method_param {
trait_id: trait_ref.def_id,
method_num: method_num,
param_num: param,
bound_num: bound_num,
})
}
}
}
// Do a search through a list of bounds, using a callback to actually
// create the candidates.
fn push_inherent_candidates_from_bounds_inner(
&self,
bounds: &[@TraitRef],
mk_cand: &fn(trait_ref: @TraitRef, m: @ty::Method, method_num: uint,
bound_num: uint) -> Candidate) {
let tcx = self.tcx();
let mut next_bound_idx = 0; // count only trait bounds
@ -459,18 +516,8 @@ fn push_inherent_candidates_from_bounds(&self,
Some(pos) => {
let method = trait_methods[pos];
let cand = Candidate {
rcvr_match_condition: RcvrMatchesIfSubtype(self_ty),
rcvr_substs: bound_trait_ref.substs.clone(),
method_ty: method,
origin: method_param(
method_param {
trait_id: bound_trait_ref.def_id,
method_num: pos,
param_num: param,
bound_num: this_bound_idx,
})
};
let cand = mk_cand(bound_trait_ref, method,
pos, this_bound_idx);
debug!("pushing inherent candidate for param: %?", cand);
self.inherent_candidates.push(cand);
@ -879,7 +926,7 @@ fn merge_candidates(&self, candidates: &[Candidate]) -> ~[Candidate] {
fn confirm_candidate(&self, rcvr_ty: ty::t, candidate: &Candidate)
-> method_map_entry {
let tcx = self.tcx();
let fty = self.fn_ty_from_origin(&candidate.origin);
let fty = ty::mk_bare_fn(tcx, candidate.method_ty.fty.clone());
debug!("confirm_candidate(expr=%s, candidate=%s, fty=%s)",
self.expr.repr(tcx),
@ -891,17 +938,9 @@ fn confirm_candidate(&self, rcvr_ty: ty::t, candidate: &Candidate)
// static methods should never have gotten this far:
assert!(candidate.method_ty.explicit_self != sty_static);
let transformed_self_ty = match candidate.origin {
method_trait(trait_def_id, _) => {
self.construct_transformed_self_ty_for_object(
trait_def_id, candidate)
}
_ => {
let t = candidate.method_ty.transformed_self_ty.unwrap();
ty::subst(tcx, &candidate.rcvr_substs, t)
}
};
let transformed_self_ty =
ty::subst(tcx, &candidate.rcvr_substs,
candidate.method_ty.transformed_self_ty.unwrap());
// Determine the values for the type parameters of the method.
// If they were not explicitly supplied, just construct fresh
@ -992,9 +1031,11 @@ fn confirm_candidate(&self, rcvr_ty: ty::t, candidate: &Candidate)
}
}
fn construct_transformed_self_ty_for_object(&self,
trait_def_id: ast::def_id,
candidate: &Candidate) -> ty::t
fn construct_transformed_self_ty_for_object(
&self,
trait_def_id: ast::def_id,
rcvr_substs: &ty::substs,
method_ty: &ty::Method) -> ty::t
{
/*!
* This is a bit tricky. We have a match against a trait method
@ -1010,17 +1051,17 @@ fn construct_transformed_self_ty_for_object(&self,
* result to be `&'a Foo`. Assuming that `m_method` is being
* called, we want the result to be `@mut Foo`. Of course,
* this transformation has already been done as part of
* `candidate.method_ty.transformed_self_ty`, but there the
* `method_ty.transformed_self_ty`, but there the
* type is expressed in terms of `Self` (i.e., `&'a Self`, `@mut Self`).
* Because objects are not standalone types, we can't just substitute
* `s/Self/Foo/`, so we must instead perform this kind of hokey
* match below.
*/
let substs = ty::substs {regions: candidate.rcvr_substs.regions.clone(),
let substs = ty::substs {regions: rcvr_substs.regions.clone(),
self_ty: None,
tps: candidate.rcvr_substs.tps.clone()};
match candidate.method_ty.explicit_self {
tps: rcvr_substs.tps.clone()};
match method_ty.explicit_self {
ast::sty_static => {
self.bug(~"static method for object type receiver");
}
@ -1029,7 +1070,7 @@ fn construct_transformed_self_ty_for_object(&self,
}
ast::sty_region(*) | ast::sty_box(*) | ast::sty_uniq(*) => {
let transformed_self_ty =
candidate.method_ty.transformed_self_ty.clone().unwrap();
method_ty.transformed_self_ty.clone().unwrap();
match ty::get(transformed_self_ty).sty {
ty::ty_rptr(r, mt) => { // must be sty_region
ty::mk_trait(self.tcx(), trait_def_id,
@ -1072,7 +1113,7 @@ fn enforce_object_limitations(&self,
method_static(*) | method_param(*) => {
return; // not a call to a trait instance
}
method_trait(*) => {}
method_object(*) => {}
}
match candidate.method_ty.explicit_self {
@ -1117,7 +1158,7 @@ fn enforce_drop_trait_limitations(&self, candidate: &Candidate) {
// XXX: does this properly enforce this on everything now
// that self has been merged in? -sully
method_param(method_param { trait_id: trait_id, _ }) |
method_trait(trait_id, _) => {
method_object(method_object { trait_id: trait_id, _ }) => {
bad = self.tcx().destructor_for_type.contains_key(&trait_id);
}
}
@ -1235,27 +1276,6 @@ fn mutability_matches(self_mutbl: ast::mutability,
}
}
fn fn_ty_from_origin(&self, origin: &method_origin) -> ty::t {
return match *origin {
method_static(did) => {
ty::lookup_item_type(self.tcx(), did).ty
}
method_param(ref mp) => {
type_of_trait_method(self.tcx(), mp.trait_id, mp.method_num)
}
method_trait(did, idx) => {
type_of_trait_method(self.tcx(), did, idx)
}
};
fn type_of_trait_method(tcx: ty::ctxt,
trait_did: def_id,
method_num: uint) -> ty::t {
let trait_methods = ty::trait_methods(tcx, trait_did);
ty::mk_bare_fn(tcx, trait_methods[method_num].fty.clone())
}
}
fn report_candidate(&self, idx: uint, origin: &method_origin) {
match *origin {
method_static(impl_did) => {
@ -1264,8 +1284,8 @@ fn report_candidate(&self, idx: uint, origin: &method_origin) {
method_param(ref mp) => {
self.report_param_candidate(idx, (*mp).trait_id)
}
method_trait(trait_did, _) => {
self.report_trait_candidate(idx, trait_did)
method_object(ref mo) => {
self.report_trait_candidate(idx, mo.trait_id)
}
}
}

View File

@ -647,30 +647,21 @@ fn mutability_allowed(a_mutbl: ast::mutability,
self_ty: Some(mt.ty)
}
};
let vtable_opt =
lookup_vtable(&vcx,
location_info,
mt.ty,
target_trait_ref,
is_early);
match vtable_opt {
Some(vtable) => {
// Map this expression to that
// vtable (that is: "ex has vtable
// <vtable>")
if !is_early {
insert_vtables(fcx, ex.id,
@~[@~[vtable]]);
}
}
None => {
fcx.tcx().sess.span_err(
ex.span,
fmt!("failed to find an implementation \
of trait %s for %s",
fcx.infcx().ty_to_str(target_ty),
fcx.infcx().ty_to_str(mt.ty)));
}
let param_bounds = ty::ParamBounds {
builtin_bounds: ty::EmptyBuiltinBounds(),
trait_bounds: ~[target_trait_ref]
};
let vtables =
lookup_vtables_for_param(&vcx,
location_info,
None,
&param_bounds,
mt.ty,
is_early);
if !is_early {
insert_vtables(fcx, ex.id, @~[vtables]);
}
// Now, if this is &trait, we need to link the

View File

@ -88,7 +88,7 @@ pub enum method_origin {
method_param(method_param),
// method invoked on a trait instance
method_trait(ast::def_id, uint),
method_object(method_object),
}
@ -110,6 +110,26 @@ pub struct method_param {
bound_num: uint,
}
// details for a method invoked with a receiver whose type is an object
#[deriving(Clone, Encodable, Decodable)]
pub struct method_object {
// the (super)trait containing the method to be invoked
trait_id: ast::def_id,
// the actual base trait id of the object
object_trait_id: ast::def_id,
// index of the method to be invoked amongst the trait's methods
method_num: uint,
// index into the actual runtime vtable.
// the vtable is formed by concatenating together the method lists of
// the base object trait and all supertraits; this is the index into
// that vtable
real_index: uint,
}
#[deriving(Clone)]
pub struct method_map_entry {
// the type of the self parameter, which is not reflected in the fn type

View File

@ -747,8 +747,8 @@ fn repr(&self, tcx: ctxt) -> ~str {
&typeck::method_param(ref p) => {
p.repr(tcx)
}
&typeck::method_trait(def_id, n) => {
fmt!("method_trait(%s, %?)", def_id.repr(tcx), n)
&typeck::method_object(ref p) => {
p.repr(tcx)
}
}
}
@ -764,6 +764,16 @@ fn repr(&self, tcx: ctxt) -> ~str {
}
}
impl Repr for typeck::method_object {
fn repr(&self, tcx: ctxt) -> ~str {
fmt!("method_object(%s,%?,%?)",
self.trait_id.repr(tcx),
self.method_num,
self.real_index)
}
}
impl Repr for ty::RegionVid {
fn repr(&self, _tcx: ctxt) -> ~str {
fmt!("%?", *self)

View File

@ -38,7 +38,7 @@ fn log(&mut self, msg: Either<~str, &'static str>) {
};
// Truncate the string
let buf_bytes = 256;
let buf_bytes = 2048;
if s.len() > buf_bytes {
let s = s.slice(0, buf_bytes) + "[...]";
print(s);