auto merge of #8015 : msullivan/rust/default-methods, r=nikomatsakis
Lots of changes to vtable resolution, handling of super/self method calls in default methods. Fix a lot of trait inheritance bugs. r? @nikomatsakis
This commit is contained in:
commit
906264b50f
src
@ -732,6 +732,11 @@ impl Ord for Sign {
|
||||
}
|
||||
}
|
||||
|
||||
impl TotalEq for Sign {
|
||||
fn equals(&self, other: &Sign) -> bool {
|
||||
*self == *other
|
||||
}
|
||||
}
|
||||
impl TotalOrd for Sign {
|
||||
|
||||
fn cmp(&self, other: &Sign) -> Ordering {
|
||||
|
@ -110,6 +110,25 @@ cmp_impl!(impl TotalEq, equals)
|
||||
cmp_impl!(impl Ord, lt, gt, le, ge)
|
||||
cmp_impl!(impl TotalOrd, cmp -> cmp::Ordering)
|
||||
|
||||
impl<T: Clone + Integer + Ord> Orderable for Ratio<T> {
|
||||
#[inline]
|
||||
fn min(&self, other: &Ratio<T>) -> Ratio<T> {
|
||||
if *self < *other { self.clone() } else { other.clone() }
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn max(&self, other: &Ratio<T>) -> Ratio<T> {
|
||||
if *self > *other { self.clone() } else { other.clone() }
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn clamp(&self, mn: &Ratio<T>, mx: &Ratio<T>) -> Ratio<T> {
|
||||
if *self > *mx { mx.clone()} else
|
||||
if *self < *mn { mn.clone() } else { self.clone() }
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* Arithmetic */
|
||||
// a/b * c/d = (a*c)/(b*d)
|
||||
impl<T: Clone + Integer + Ord>
|
||||
|
@ -180,6 +180,7 @@ pub static tag_misc_info: uint = 0x7f;
|
||||
pub static tag_misc_info_crate_items: uint = 0x80;
|
||||
|
||||
pub static tag_item_method_provided_source: uint = 0x81;
|
||||
pub static tag_item_impl_vtables: uint = 0x82;
|
||||
|
||||
pub struct LinkMeta {
|
||||
name: @str,
|
||||
|
@ -16,6 +16,7 @@ use metadata::cstore;
|
||||
use metadata::decoder;
|
||||
use metadata;
|
||||
use middle::ty;
|
||||
use middle::typeck;
|
||||
|
||||
use std::vec;
|
||||
use reader = extra::ebml::reader;
|
||||
@ -216,6 +217,14 @@ pub fn get_impl_trait(tcx: ty::ctxt,
|
||||
decoder::get_impl_trait(cdata, def.node, tcx)
|
||||
}
|
||||
|
||||
// Given a def_id for an impl, return information about its vtables
|
||||
pub fn get_impl_vtables(tcx: ty::ctxt,
|
||||
def: ast::def_id) -> typeck::impl_res {
|
||||
let cstore = tcx.cstore;
|
||||
let cdata = cstore::get_crate_data(cstore, def.crate);
|
||||
decoder::get_impl_vtables(cdata, def.node, tcx)
|
||||
}
|
||||
|
||||
pub fn get_impl_method(cstore: @mut cstore::CStore,
|
||||
def: ast::def_id,
|
||||
mname: ast::ident)
|
||||
|
@ -21,6 +21,9 @@ use metadata::tydecode::{parse_ty_data, parse_def_id,
|
||||
parse_type_param_def_data,
|
||||
parse_bare_fn_ty_data, parse_trait_ref_data};
|
||||
use middle::ty;
|
||||
use middle::typeck;
|
||||
use middle::astencode::vtable_decoder_helpers;
|
||||
|
||||
|
||||
use std::hash::HashUtil;
|
||||
use std::uint;
|
||||
@ -410,6 +413,21 @@ pub fn get_impl_trait(cdata: cmd,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_impl_vtables(cdata: cmd,
|
||||
id: ast::node_id,
|
||||
tcx: ty::ctxt) -> typeck::impl_res
|
||||
{
|
||||
let item_doc = lookup_item(id, cdata.data);
|
||||
let vtables_doc = reader::get_doc(item_doc, tag_item_impl_vtables);
|
||||
let mut decoder = reader::Decoder(vtables_doc);
|
||||
|
||||
typeck::impl_res {
|
||||
trait_vtables: decoder.read_vtable_res(tcx, cdata),
|
||||
self_vtables: decoder.read_vtable_param_res(tcx, cdata)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
pub fn get_impl_method(intr: @ident_interner, cdata: cmd, id: ast::node_id,
|
||||
name: ast::ident) -> Option<ast::def_id> {
|
||||
let items = reader::get_doc(reader::Doc(cdata.data), tag_items);
|
||||
|
@ -17,6 +17,8 @@ use metadata::decoder;
|
||||
use metadata::tyencode;
|
||||
use middle::ty::{node_id_to_type, lookup_item_type};
|
||||
use middle::ty;
|
||||
use middle::typeck;
|
||||
use middle::astencode;
|
||||
use middle;
|
||||
|
||||
use std::hash::HashUtil;
|
||||
@ -161,6 +163,15 @@ fn encode_trait_ref(ebml_w: &mut writer::Encoder,
|
||||
ebml_w.end_tag();
|
||||
}
|
||||
|
||||
fn encode_impl_vtables(ebml_w: &mut writer::Encoder,
|
||||
ecx: &EncodeContext,
|
||||
vtables: &typeck::impl_res) {
|
||||
ebml_w.start_tag(tag_item_impl_vtables);
|
||||
astencode::encode_vtable_res(ecx, ebml_w, vtables.trait_vtables);
|
||||
astencode::encode_vtable_param_res(ecx, ebml_w, vtables.self_vtables);
|
||||
ebml_w.end_tag();
|
||||
}
|
||||
|
||||
// Item info table encoding
|
||||
fn encode_family(ebml_w: &mut writer::Encoder, c: char) {
|
||||
ebml_w.start_tag(tag_items_data_item_family);
|
||||
@ -1008,6 +1019,8 @@ fn encode_info_for_item(ecx: &EncodeContext,
|
||||
let trait_ref = ty::node_id_to_trait_ref(
|
||||
tcx, ast_trait_ref.ref_id);
|
||||
encode_trait_ref(ebml_w, ecx, trait_ref, tag_item_trait_ref);
|
||||
let impl_vtables = ty::lookup_impl_vtables(tcx, def_id);
|
||||
encode_impl_vtables(ebml_w, ecx, &impl_vtables);
|
||||
}
|
||||
encode_path(ecx, ebml_w, path, ast_map::path_name(item.ident));
|
||||
ebml_w.end_tag();
|
||||
|
@ -250,6 +250,8 @@ impl<S:serialize::Encoder> def_id_encoder_helpers for S {
|
||||
|
||||
trait def_id_decoder_helpers {
|
||||
fn read_def_id(&mut self, xcx: @ExtendedDecodeContext) -> ast::def_id;
|
||||
fn read_def_id_noxcx(&mut self,
|
||||
cdata: @cstore::crate_metadata) -> ast::def_id;
|
||||
}
|
||||
|
||||
impl<D:serialize::Decoder> def_id_decoder_helpers for D {
|
||||
@ -257,6 +259,12 @@ impl<D:serialize::Decoder> def_id_decoder_helpers for D {
|
||||
let did: ast::def_id = Decodable::decode(self);
|
||||
did.tr(xcx)
|
||||
}
|
||||
|
||||
fn read_def_id_noxcx(&mut self,
|
||||
cdata: @cstore::crate_metadata) -> ast::def_id {
|
||||
let did: ast::def_id = Decodable::decode(self);
|
||||
decoder::translate_def_id(cdata, did)
|
||||
}
|
||||
}
|
||||
|
||||
// ______________________________________________________________________
|
||||
@ -582,12 +590,6 @@ impl tr for method_origin {
|
||||
typeck::method_trait(did, m, vstore) => {
|
||||
typeck::method_trait(did.tr(xcx), m, vstore)
|
||||
}
|
||||
typeck::method_self(did, m) => {
|
||||
typeck::method_self(did.tr(xcx), m)
|
||||
}
|
||||
typeck::method_super(trait_did, m) => {
|
||||
typeck::method_super(trait_did.tr(xcx), m)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -595,7 +597,7 @@ impl tr for method_origin {
|
||||
// ______________________________________________________________________
|
||||
// Encoding and decoding vtable_res
|
||||
|
||||
fn encode_vtable_res(ecx: &e::EncodeContext,
|
||||
pub fn encode_vtable_res(ecx: &e::EncodeContext,
|
||||
ebml_w: &mut writer::Encoder,
|
||||
dr: typeck::vtable_res) {
|
||||
// can't autogenerate this code because automatic code of
|
||||
@ -603,13 +605,20 @@ fn encode_vtable_res(ecx: &e::EncodeContext,
|
||||
// hand-written encoding routines combine with auto-generated
|
||||
// ones. perhaps we should fix this.
|
||||
do ebml_w.emit_from_vec(*dr) |ebml_w, param_tables| {
|
||||
do ebml_w.emit_from_vec(**param_tables) |ebml_w, vtable_origin| {
|
||||
encode_vtable_origin(ecx, ebml_w, vtable_origin)
|
||||
}
|
||||
encode_vtable_param_res(ecx, ebml_w, *param_tables);
|
||||
}
|
||||
}
|
||||
|
||||
fn encode_vtable_origin(ecx: &e::EncodeContext,
|
||||
pub fn encode_vtable_param_res(ecx: &e::EncodeContext,
|
||||
ebml_w: &mut writer::Encoder,
|
||||
param_tables: typeck::vtable_param_res) {
|
||||
do ebml_w.emit_from_vec(*param_tables) |ebml_w, vtable_origin| {
|
||||
encode_vtable_origin(ecx, ebml_w, vtable_origin)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
pub fn encode_vtable_origin(ecx: &e::EncodeContext,
|
||||
ebml_w: &mut writer::Encoder,
|
||||
vtable_origin: &typeck::vtable_origin) {
|
||||
do ebml_w.emit_enum("vtable_origin") |ebml_w| {
|
||||
@ -630,40 +639,46 @@ fn encode_vtable_origin(ecx: &e::EncodeContext,
|
||||
typeck::vtable_param(pn, bn) => {
|
||||
do ebml_w.emit_enum_variant("vtable_param", 1u, 2u) |ebml_w| {
|
||||
do ebml_w.emit_enum_variant_arg(0u) |ebml_w| {
|
||||
ebml_w.emit_uint(pn);
|
||||
pn.encode(ebml_w);
|
||||
}
|
||||
do ebml_w.emit_enum_variant_arg(1u) |ebml_w| {
|
||||
ebml_w.emit_uint(bn);
|
||||
}
|
||||
}
|
||||
}
|
||||
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)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
trait vtable_decoder_helpers {
|
||||
fn read_vtable_res(&mut self, xcx: @ExtendedDecodeContext)
|
||||
pub trait vtable_decoder_helpers {
|
||||
fn read_vtable_res(&mut self,
|
||||
tcx: ty::ctxt, cdata: @cstore::crate_metadata)
|
||||
-> typeck::vtable_res;
|
||||
fn read_vtable_origin(&mut self, xcx: @ExtendedDecodeContext)
|
||||
fn read_vtable_param_res(&mut self,
|
||||
tcx: ty::ctxt, cdata: @cstore::crate_metadata)
|
||||
-> typeck::vtable_param_res;
|
||||
fn read_vtable_origin(&mut self,
|
||||
tcx: ty::ctxt, cdata: @cstore::crate_metadata)
|
||||
-> typeck::vtable_origin;
|
||||
}
|
||||
|
||||
impl vtable_decoder_helpers for reader::Decoder {
|
||||
fn read_vtable_res(&mut self, xcx: @ExtendedDecodeContext)
|
||||
fn read_vtable_res(&mut self,
|
||||
tcx: ty::ctxt, cdata: @cstore::crate_metadata)
|
||||
-> typeck::vtable_res {
|
||||
@self.read_to_vec(|this|
|
||||
@this.read_to_vec(|this|
|
||||
this.read_vtable_origin(xcx)))
|
||||
this.read_vtable_param_res(tcx, cdata))
|
||||
}
|
||||
|
||||
fn read_vtable_origin(&mut self, xcx: @ExtendedDecodeContext)
|
||||
fn read_vtable_param_res(&mut self,
|
||||
tcx: ty::ctxt, cdata: @cstore::crate_metadata)
|
||||
-> typeck::vtable_param_res {
|
||||
@self.read_to_vec(|this|
|
||||
this.read_vtable_origin(tcx, cdata))
|
||||
}
|
||||
|
||||
fn read_vtable_origin(&mut self,
|
||||
tcx: ty::ctxt, cdata: @cstore::crate_metadata)
|
||||
-> typeck::vtable_origin {
|
||||
do self.read_enum("vtable_origin") |this| {
|
||||
do this.read_enum_variant(["vtable_static",
|
||||
@ -674,33 +689,26 @@ impl vtable_decoder_helpers for reader::Decoder {
|
||||
0 => {
|
||||
typeck::vtable_static(
|
||||
do this.read_enum_variant_arg(0u) |this| {
|
||||
this.read_def_id(xcx)
|
||||
this.read_def_id_noxcx(cdata)
|
||||
},
|
||||
do this.read_enum_variant_arg(1u) |this| {
|
||||
this.read_tys(xcx)
|
||||
this.read_tys_noxcx(tcx, cdata)
|
||||
},
|
||||
do this.read_enum_variant_arg(2u) |this| {
|
||||
this.read_vtable_res(xcx)
|
||||
this.read_vtable_res(tcx, cdata)
|
||||
}
|
||||
)
|
||||
}
|
||||
1 => {
|
||||
typeck::vtable_param(
|
||||
do this.read_enum_variant_arg(0u) |this| {
|
||||
this.read_uint()
|
||||
Decodable::decode(this)
|
||||
},
|
||||
do this.read_enum_variant_arg(1u) |this| {
|
||||
this.read_uint()
|
||||
}
|
||||
)
|
||||
}
|
||||
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")
|
||||
}
|
||||
@ -995,9 +1003,35 @@ trait ebml_decoder_decoder_helpers {
|
||||
source: DefIdSource,
|
||||
did: ast::def_id)
|
||||
-> ast::def_id;
|
||||
|
||||
// Versions of the type reading functions that don't need the full
|
||||
// ExtendedDecodeContext.
|
||||
fn read_ty_noxcx(&mut self,
|
||||
tcx: ty::ctxt, cdata: @cstore::crate_metadata) -> ty::t;
|
||||
fn read_tys_noxcx(&mut self,
|
||||
tcx: ty::ctxt,
|
||||
cdata: @cstore::crate_metadata) -> ~[ty::t];
|
||||
}
|
||||
|
||||
impl ebml_decoder_decoder_helpers for reader::Decoder {
|
||||
fn read_ty_noxcx(&mut self,
|
||||
tcx: ty::ctxt, cdata: @cstore::crate_metadata) -> ty::t {
|
||||
do self.read_opaque |_, doc| {
|
||||
tydecode::parse_ty_data(
|
||||
*doc.data,
|
||||
cdata.cnum,
|
||||
doc.start,
|
||||
tcx,
|
||||
|_, id| decoder::translate_def_id(cdata, id))
|
||||
}
|
||||
}
|
||||
|
||||
fn read_tys_noxcx(&mut self,
|
||||
tcx: ty::ctxt,
|
||||
cdata: @cstore::crate_metadata) -> ~[ty::t] {
|
||||
self.read_to_vec(|this| this.read_ty_noxcx(tcx, cdata) )
|
||||
}
|
||||
|
||||
fn read_ty(&mut self, xcx: @ExtendedDecodeContext) -> ty::t {
|
||||
// Note: regions types embed local node ids. In principle, we
|
||||
// should translate these node ids into the new decode
|
||||
@ -1160,8 +1194,9 @@ fn decode_side_tables(xcx: @ExtendedDecodeContext,
|
||||
val_dsr.read_method_map_entry(xcx));
|
||||
}
|
||||
c::tag_table_vtable_map => {
|
||||
dcx.maps.vtable_map.insert(id,
|
||||
val_dsr.read_vtable_res(xcx));
|
||||
dcx.maps.vtable_map.insert(
|
||||
id,
|
||||
val_dsr.read_vtable_res(xcx.dcx.tcx, xcx.dcx.cdata));
|
||||
}
|
||||
c::tag_table_adjustments => {
|
||||
let adj: @ty::AutoAdjustment = @Decodable::decode(val_dsr);
|
||||
|
@ -15,8 +15,7 @@
|
||||
use metadata::csearch;
|
||||
use middle::ty::{ty_struct, ty_enum};
|
||||
use middle::ty;
|
||||
use middle::typeck::{method_map, method_origin, method_param, method_self};
|
||||
use middle::typeck::{method_super};
|
||||
use middle::typeck::{method_map, method_origin, method_param};
|
||||
use middle::typeck::{method_static, method_trait};
|
||||
|
||||
use std::util::ignore;
|
||||
@ -291,9 +290,7 @@ pub fn check_crate<'mm>(tcx: ty::ctxt,
|
||||
method_num: method_num,
|
||||
_
|
||||
}) |
|
||||
method_trait(trait_id, method_num, _) |
|
||||
method_self(trait_id, method_num) |
|
||||
method_super(trait_id, method_num) => {
|
||||
method_trait(trait_id, method_num, _) => {
|
||||
if trait_id.crate == local_crate {
|
||||
match tcx.items.find(&trait_id.node) {
|
||||
Some(&node_item(item, _)) => {
|
||||
|
@ -193,30 +193,15 @@ pub fn trans_fn_ref_with_vtables_to_callee(
|
||||
type_params, vtables))}
|
||||
}
|
||||
|
||||
fn get_impl_resolutions(bcx: @mut Block,
|
||||
impl_id: ast::def_id)
|
||||
-> typeck::vtable_res {
|
||||
if impl_id.crate == ast::local_crate {
|
||||
bcx.ccx().maps.vtable_map.get_copy(&impl_id.node)
|
||||
} else {
|
||||
// XXX: This is a temporary hack to work around not properly
|
||||
// exporting information about resolutions for impls.
|
||||
// This doesn't actually work if the trait has param bounds,
|
||||
// but it does allow us to survive the case when it does not.
|
||||
let trait_ref = ty::impl_trait_ref(bcx.tcx(), impl_id).get();
|
||||
@vec::from_elem(trait_ref.substs.tps.len(), @~[])
|
||||
}
|
||||
}
|
||||
|
||||
fn resolve_default_method_vtables(bcx: @mut Block,
|
||||
impl_id: ast::def_id,
|
||||
method: &ty::Method,
|
||||
substs: &ty::substs,
|
||||
impl_vtables: Option<typeck::vtable_res>)
|
||||
-> typeck::vtable_res {
|
||||
-> (typeck::vtable_res, typeck::vtable_param_res) {
|
||||
|
||||
// Get the vtables that the impl implements the trait at
|
||||
let trait_vtables = get_impl_resolutions(bcx, impl_id);
|
||||
let impl_res = ty::lookup_impl_vtables(bcx.tcx(), impl_id);
|
||||
|
||||
// Build up a param_substs that we are going to resolve the
|
||||
// trait_vtables under.
|
||||
@ -224,11 +209,11 @@ fn resolve_default_method_vtables(bcx: @mut Block,
|
||||
tys: substs.tps.clone(),
|
||||
self_ty: substs.self_ty,
|
||||
vtables: impl_vtables,
|
||||
self_vtable: None
|
||||
self_vtables: None
|
||||
});
|
||||
|
||||
let trait_vtables_fixed = resolve_vtables_under_param_substs(
|
||||
bcx.tcx(), param_substs, trait_vtables);
|
||||
bcx.tcx(), param_substs, impl_res.trait_vtables);
|
||||
|
||||
// Now we pull any vtables for parameters on the actual method.
|
||||
let num_method_vtables = method.generics.type_param_defs.len();
|
||||
@ -241,7 +226,12 @@ fn resolve_default_method_vtables(bcx: @mut Block,
|
||||
None => vec::from_elem(num_method_vtables, @~[])
|
||||
};
|
||||
|
||||
@(*trait_vtables_fixed + method_vtables)
|
||||
let param_vtables = @(*trait_vtables_fixed + method_vtables);
|
||||
|
||||
let self_vtables = resolve_param_vtables_under_param_substs(
|
||||
bcx.tcx(), param_substs, impl_res.self_vtables);
|
||||
|
||||
(param_vtables, self_vtables)
|
||||
}
|
||||
|
||||
|
||||
@ -296,7 +286,7 @@ 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 (is_default, def_id, substs, self_vtable, vtables) =
|
||||
let (is_default, def_id, substs, self_vtables, vtables) =
|
||||
match ty::provided_source(tcx, def_id) {
|
||||
None => (false, def_id, substs, None, vtables),
|
||||
Some(source_id) => {
|
||||
@ -319,20 +309,6 @@ pub fn trans_fn_ref_with_vtables(
|
||||
.expect("could not find trait_ref for impl with \
|
||||
default methods");
|
||||
|
||||
// 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) => {
|
||||
@call_vtables.initn(param_defs.len()).to_owned()
|
||||
}
|
||||
};
|
||||
|
||||
let self_vtable =
|
||||
typeck::vtable_static(impl_id, receiver_substs,
|
||||
receiver_vtables);
|
||||
// Compute the first substitution
|
||||
let first_subst = make_substs_for_receiver_types(
|
||||
tcx, impl_id, trait_ref, method);
|
||||
@ -341,20 +317,22 @@ pub fn trans_fn_ref_with_vtables(
|
||||
let new_substs = first_subst.subst(tcx, &substs);
|
||||
|
||||
|
||||
let vtables =
|
||||
let (param_vtables, self_vtables) =
|
||||
resolve_default_method_vtables(bcx, impl_id,
|
||||
method, &new_substs, vtables);
|
||||
method, &substs, vtables);
|
||||
|
||||
debug!("trans_fn_with_vtables - default method: \
|
||||
substs = %s, trait_subst = %s, \
|
||||
first_subst = %s, new_subst = %s, \
|
||||
self_vtable = %s, vtables = %s",
|
||||
vtables = %s, \
|
||||
self_vtable = %s, param_vtables = %s",
|
||||
substs.repr(tcx), trait_ref.substs.repr(tcx),
|
||||
first_subst.repr(tcx), new_substs.repr(tcx),
|
||||
self_vtable.repr(tcx), vtables.repr(tcx));
|
||||
vtables.repr(tcx),
|
||||
self_vtables.repr(tcx), param_vtables.repr(tcx));
|
||||
|
||||
(true, source_id,
|
||||
new_substs, Some(self_vtable), Some(vtables))
|
||||
new_substs, Some(self_vtables), Some(param_vtables))
|
||||
}
|
||||
};
|
||||
|
||||
@ -400,7 +378,7 @@ pub fn trans_fn_ref_with_vtables(
|
||||
|
||||
let (val, must_cast) =
|
||||
monomorphize::monomorphic_fn(ccx, def_id, &substs,
|
||||
vtables, self_vtable,
|
||||
vtables, self_vtables,
|
||||
Some(ref_id));
|
||||
let mut val = val;
|
||||
if must_cast && ref_id != 0 {
|
||||
|
@ -133,7 +133,7 @@ pub struct param_substs {
|
||||
tys: ~[ty::t],
|
||||
self_ty: Option<ty::t>,
|
||||
vtables: Option<typeck::vtable_res>,
|
||||
self_vtable: Option<typeck::vtable_origin>
|
||||
self_vtables: Option<typeck::vtable_param_res>
|
||||
}
|
||||
|
||||
impl param_substs {
|
||||
@ -1020,14 +1020,25 @@ pub fn resolve_vtables_under_param_substs(tcx: ty::ctxt,
|
||||
vts: typeck::vtable_res)
|
||||
-> typeck::vtable_res {
|
||||
@vts.iter().transform(|ds|
|
||||
@ds.iter().transform(
|
||||
|d| resolve_vtable_under_param_substs(tcx,
|
||||
param_substs,
|
||||
d))
|
||||
.collect::<~[typeck::vtable_origin]>())
|
||||
.collect::<~[typeck::vtable_param_res]>()
|
||||
resolve_param_vtables_under_param_substs(tcx,
|
||||
param_substs,
|
||||
*ds))
|
||||
.collect()
|
||||
}
|
||||
|
||||
pub fn resolve_param_vtables_under_param_substs(
|
||||
tcx: ty::ctxt,
|
||||
param_substs: Option<@param_substs>,
|
||||
ds: typeck::vtable_param_res)
|
||||
-> typeck::vtable_param_res {
|
||||
@ds.iter().transform(
|
||||
|d| resolve_vtable_under_param_substs(tcx,
|
||||
param_substs,
|
||||
d))
|
||||
.collect()
|
||||
}
|
||||
|
||||
|
||||
|
||||
// Apply the typaram substitutions in the FunctionContext to a vtable. This should
|
||||
// eliminate any vtable_params.
|
||||
@ -1068,31 +1079,26 @@ pub fn resolve_vtable_under_param_substs(tcx: ty::ctxt,
|
||||
}
|
||||
}
|
||||
}
|
||||
typeck::vtable_self(_trait_id) => {
|
||||
match param_substs {
|
||||
Some(@param_substs
|
||||
{self_vtable: Some(ref self_vtable), _}) => {
|
||||
(*self_vtable).clone()
|
||||
}
|
||||
_ => {
|
||||
tcx.sess.bug(fmt!(
|
||||
"resolve_vtable_in_fn_ctxt: asked to lookup but \
|
||||
no self_vtable in the fn_ctxt!"))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn find_vtable(tcx: ty::ctxt,
|
||||
ps: ¶m_substs,
|
||||
n_param: uint,
|
||||
n_param: typeck::param_index,
|
||||
n_bound: uint)
|
||||
-> typeck::vtable_origin {
|
||||
debug!("find_vtable(n_param=%u, n_bound=%u, ps=%s)",
|
||||
debug!("find_vtable(n_param=%?, n_bound=%u, ps=%s)",
|
||||
n_param, n_bound, ps.repr(tcx));
|
||||
|
||||
ps.vtables.get()[n_param][n_bound].clone()
|
||||
let param_bounds = match n_param {
|
||||
typeck::param_self => ps.self_vtables.expect("self vtables missing"),
|
||||
typeck::param_numbered(n) => {
|
||||
let tables = ps.vtables
|
||||
.expect("vtables missing where they are needed");
|
||||
tables[n]
|
||||
}
|
||||
};
|
||||
param_bounds[n_bound].clone()
|
||||
}
|
||||
|
||||
pub fn dummy_substs(tps: ~[ty::t]) -> ty::substs {
|
||||
|
@ -147,46 +147,13 @@ pub fn trans_method_callee(bcx: @mut Block,
|
||||
mentry: typeck::method_map_entry)
|
||||
-> Callee {
|
||||
let _icx = push_ctxt("impl::trans_method_callee");
|
||||
let tcx = bcx.tcx();
|
||||
|
||||
debug!("trans_method_callee(callee_id=%?, this=%s, mentry=%s)",
|
||||
callee_id,
|
||||
bcx.expr_to_str(this),
|
||||
mentry.repr(bcx.tcx()));
|
||||
|
||||
// Replace method_self with method_static here.
|
||||
let mut origin = mentry.origin;
|
||||
match origin {
|
||||
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);
|
||||
// <impl_id> is the ID of the implementation of
|
||||
// trait <trait_id> for type <self_ty>
|
||||
let impl_id = ty::bogus_get_impl_id_from_ty(tcx, trait_id, self_ty);
|
||||
// Get the supertrait's methods
|
||||
let supertrait_method_def_ids = ty::trait_method_def_ids(tcx, trait_id);
|
||||
// Make sure to fail with a readable error message if
|
||||
// there's some internal error here
|
||||
if !(method_index < supertrait_method_def_ids.len()) {
|
||||
tcx.sess.bug("trans_method_callee: supertrait method \
|
||||
index is out of bounds");
|
||||
}
|
||||
// Get the method name using the method index in the origin
|
||||
let method_name =
|
||||
ty::method(tcx, supertrait_method_def_ids[method_index]).ident;
|
||||
// Now that we know the impl ID, we can look up the method
|
||||
// ID from its name
|
||||
origin = typeck::method_static(
|
||||
method_with_name(bcx.ccx(), impl_id, method_name));
|
||||
}
|
||||
typeck::method_self(*) |
|
||||
typeck::method_static(*) | typeck::method_param(*) |
|
||||
typeck::method_trait(*) => {}
|
||||
}
|
||||
|
||||
debug!("origin=%?", origin);
|
||||
|
||||
match origin {
|
||||
match mentry.origin {
|
||||
typeck::method_static(did) => {
|
||||
let callee_fn = callee::trans_fn_ref(bcx, did, callee_id);
|
||||
let mut temp_cleanups = ~[];
|
||||
@ -210,7 +177,8 @@ pub fn trans_method_callee(bcx: @mut Block,
|
||||
}) => {
|
||||
match bcx.fcx.param_substs {
|
||||
Some(substs) => {
|
||||
let vtbl = find_vtable(bcx.tcx(), substs, p, b);
|
||||
let vtbl = find_vtable(bcx.tcx(), substs,
|
||||
p, b);
|
||||
trans_monomorphized_callee(bcx, callee_id, this, mentry,
|
||||
trait_id, off, vtbl)
|
||||
}
|
||||
@ -219,24 +187,6 @@ pub fn trans_method_callee(bcx: @mut Block,
|
||||
}
|
||||
}
|
||||
|
||||
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,
|
||||
(*vtbl).clone())
|
||||
}
|
||||
_ => {
|
||||
fail!("trans_method_callee: missing self_vtable")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
typeck::method_trait(_, off, store) => {
|
||||
trans_trait_callee(bcx,
|
||||
callee_id,
|
||||
@ -245,9 +195,6 @@ pub fn trans_method_callee(bcx: @mut Block,
|
||||
store,
|
||||
mentry.explicit_self)
|
||||
}
|
||||
typeck::method_super(*) => {
|
||||
fail!("method_super should have been handled above")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -402,9 +349,6 @@ pub fn trans_monomorphized_callee(bcx: @mut 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");
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
@ -611,7 +555,7 @@ pub fn vtable_id(ccx: @mut CrateContext,
|
||||
tys: (*substs).clone(),
|
||||
vtables: Some(sub_vtables),
|
||||
self_ty: None,
|
||||
self_vtable: None
|
||||
self_vtables: None
|
||||
};
|
||||
|
||||
monomorphize::make_mono_id(
|
||||
|
@ -41,7 +41,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>,
|
||||
self_vtables: Option<typeck::vtable_param_res>,
|
||||
ref_id: Option<ast::node_id>)
|
||||
-> (ValueRef, bool)
|
||||
{
|
||||
@ -54,7 +54,7 @@ pub fn monomorphic_fn(ccx: @mut CrateContext,
|
||||
fn_id.repr(ccx.tcx),
|
||||
real_substs.repr(ccx.tcx),
|
||||
vtables.repr(ccx.tcx),
|
||||
self_vtable.repr(ccx.tcx),
|
||||
self_vtables.repr(ccx.tcx),
|
||||
ref_id);
|
||||
|
||||
assert!(real_substs.tps.iter().all(|t| !ty::type_needs_infer(*t)));
|
||||
@ -72,7 +72,7 @@ pub fn monomorphic_fn(ccx: @mut CrateContext,
|
||||
tys: real_substs.tps.map(|x| do_normalize(x)),
|
||||
vtables: vtables,
|
||||
self_ty: real_substs.self_ty.map(|x| do_normalize(x)),
|
||||
self_vtable: self_vtable
|
||||
self_vtables: self_vtables
|
||||
};
|
||||
|
||||
for real_substs.tps.iter().advance |s| { assert!(!ty::type_has_params(*s)); }
|
||||
@ -371,8 +371,7 @@ pub fn make_mono_id(ccx: @mut CrateContext,
|
||||
Some(vts) => {
|
||||
debug!("make_mono_id vtables=%s substs=%s",
|
||||
vts.repr(ccx.tcx), substs.tys.repr(ccx.tcx));
|
||||
let self_vtables = substs.self_vtable.map(|vtbl| @~[(*vtbl).clone()]);
|
||||
let vts_iter = self_vtables.iter().chain_(vts.iter());
|
||||
let vts_iter = substs.self_vtables.iter().chain_(vts.iter());
|
||||
vts_iter.zip(substs_iter).transform(|(vtable, subst)| {
|
||||
let v = vtable.map(|vt| meth::vtable_id(ccx, vt));
|
||||
(*subst, if !v.is_empty() { Some(@v) } else { None })
|
||||
|
@ -274,13 +274,12 @@ pub fn mark_for_method_call(cx: &Context, e_id: node_id, callee_id: node_id) {
|
||||
opt_static_did = Some(did);
|
||||
}
|
||||
typeck::method_param(typeck::method_param {
|
||||
param_num: param,
|
||||
param_num: typeck::param_numbered(param),
|
||||
_
|
||||
}) => {
|
||||
cx.uses[param] |= use_tydesc;
|
||||
}
|
||||
typeck::method_trait(*) | typeck::method_self(*)
|
||||
| typeck::method_super(*) => (),
|
||||
_ => (),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -317,6 +317,9 @@ struct ctxt_ {
|
||||
// some point. Local variable definitions not in this set can be warned
|
||||
// about.
|
||||
used_mut_nodes: @mut HashSet<ast::node_id>,
|
||||
|
||||
// vtable resolution information for impl declarations
|
||||
impl_vtables: typeck::impl_vtable_map
|
||||
}
|
||||
|
||||
pub enum tbox_flag {
|
||||
@ -911,6 +914,7 @@ pub fn mk_ctxt(s: session::Session,
|
||||
impls: @mut HashMap::new(),
|
||||
used_unsafe: @mut HashSet::new(),
|
||||
used_mut_nodes: @mut HashSet::new(),
|
||||
impl_vtables: @mut HashMap::new(),
|
||||
}
|
||||
}
|
||||
|
||||
@ -3061,9 +3065,7 @@ 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_self(trt_id, n_mth) |
|
||||
typeck::method_super(trt_id, n_mth) => {
|
||||
typeck::method_trait(trt_id, 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.
|
||||
@ -3956,6 +3958,14 @@ pub fn lookup_item_type(cx: ctxt,
|
||||
|| csearch::get_type(cx, did))
|
||||
}
|
||||
|
||||
pub fn lookup_impl_vtables(cx: ctxt,
|
||||
did: ast::def_id)
|
||||
-> typeck::impl_res {
|
||||
lookup_locally_or_in_crate_store(
|
||||
"impl_vtables", did, cx.impl_vtables,
|
||||
|| csearch::get_impl_vtables(cx, did) )
|
||||
}
|
||||
|
||||
/// Given the did of a trait, returns its canonical trait ref.
|
||||
pub fn lookup_trait_def(cx: ctxt, did: ast::def_id) -> @ty::TraitDef {
|
||||
match cx.trait_defs.find(&did) {
|
||||
@ -4339,9 +4349,9 @@ pub fn determine_inherited_purity(parent: (ast::purity, ast::node_id),
|
||||
// relation on the supertraits from each bounded trait's constraint
|
||||
// list.
|
||||
pub fn each_bound_trait_and_supertraits(tcx: ctxt,
|
||||
bounds: &ParamBounds,
|
||||
bounds: &[@TraitRef],
|
||||
f: &fn(@TraitRef) -> bool) -> bool {
|
||||
for bounds.trait_bounds.iter().advance |&bound_trait_ref| {
|
||||
for bounds.iter().advance |&bound_trait_ref| {
|
||||
let mut supertrait_set = HashMap::new();
|
||||
let mut trait_refs = ~[];
|
||||
let mut i = 0;
|
||||
@ -4383,38 +4393,14 @@ pub fn count_traits_and_supertraits(tcx: ctxt,
|
||||
type_param_defs: &[TypeParameterDef]) -> uint {
|
||||
let mut total = 0;
|
||||
for type_param_defs.iter().advance |type_param_def| {
|
||||
for each_bound_trait_and_supertraits(tcx, type_param_def.bounds) |_| {
|
||||
for each_bound_trait_and_supertraits(
|
||||
tcx, type_param_def.bounds.trait_bounds) |_| {
|
||||
total += 1;
|
||||
}
|
||||
}
|
||||
return total;
|
||||
}
|
||||
|
||||
// Given a trait and a type, returns the impl of that type.
|
||||
// This is broken, of course, by parametric impls. This used to use
|
||||
// a table specifically for this mapping, but I removed that table.
|
||||
// This is only used when calling a supertrait method from a default method,
|
||||
// and should go away once I fix how that works. -sully
|
||||
pub fn bogus_get_impl_id_from_ty(tcx: ctxt,
|
||||
trait_id: def_id, self_ty: t) -> def_id {
|
||||
match tcx.trait_impls.find(&trait_id) {
|
||||
Some(ty_to_impl) => {
|
||||
for ty_to_impl.iter().advance |imp| {
|
||||
let impl_ty = tcx.tcache.get_copy(&imp.did);
|
||||
if impl_ty.ty == self_ty { return imp.did; }
|
||||
}
|
||||
// try autoderef!
|
||||
match deref(tcx, self_ty, false) {
|
||||
Some(some_ty) =>
|
||||
bogus_get_impl_id_from_ty(tcx, trait_id, some_ty.ty),
|
||||
None => tcx.sess.bug("get_impl_id: no impl of trait for \
|
||||
this type")
|
||||
}
|
||||
},
|
||||
None => tcx.sess.bug("get_impl_id: trait isn't in trait_impls")
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_tydesc_ty(tcx: ctxt) -> Result<t, ~str> {
|
||||
do tcx.lang_items.require(TyDescStructLangItem).map |tydesc_lang_item| {
|
||||
tcx.intrinsic_defs.find_copy(tydesc_lang_item)
|
||||
|
@ -90,7 +90,8 @@ use middle::typeck::check::vtable;
|
||||
use middle::typeck::check;
|
||||
use middle::typeck::infer;
|
||||
use middle::typeck::{method_map_entry, method_origin, method_param};
|
||||
use middle::typeck::{method_self, method_static, method_trait, method_super};
|
||||
use middle::typeck::{method_static, method_trait};
|
||||
use middle::typeck::{param_numbered, param_self, param_index};
|
||||
use middle::typeck::check::regionmanip::replace_bound_regions_in_fn_sig;
|
||||
use util::common::indenter;
|
||||
|
||||
@ -328,64 +329,6 @@ impl<'self> LookupContext<'self> {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn push_inherent_candidates_from_param(&self,
|
||||
rcvr_ty: ty::t,
|
||||
param_ty: param_ty) {
|
||||
debug!("push_inherent_candidates_from_param(param_ty=%?)",
|
||||
param_ty);
|
||||
let _indenter = indenter();
|
||||
|
||||
let tcx = self.tcx();
|
||||
let mut next_bound_idx = 0; // count only trait bounds
|
||||
let type_param_def = match tcx.ty_param_defs.find(¶m_ty.def_id.node) {
|
||||
Some(t) => t,
|
||||
None => {
|
||||
tcx.sess.span_bug(
|
||||
self.expr.span,
|
||||
fmt!("No param def for %?", param_ty));
|
||||
}
|
||||
};
|
||||
|
||||
for ty::each_bound_trait_and_supertraits(tcx, type_param_def.bounds)
|
||||
|bound_trait_ref|
|
||||
{
|
||||
let this_bound_idx = next_bound_idx;
|
||||
next_bound_idx += 1;
|
||||
|
||||
let trait_methods = ty::trait_methods(tcx, bound_trait_ref.def_id);
|
||||
let pos = {
|
||||
match trait_methods.iter().position(|m| {
|
||||
m.explicit_self != ast::sty_static &&
|
||||
m.ident == self.m_name })
|
||||
{
|
||||
Some(pos) => pos,
|
||||
None => {
|
||||
debug!("trait doesn't contain method: %?",
|
||||
bound_trait_ref.def_id);
|
||||
loop; // check next trait or bound
|
||||
}
|
||||
}
|
||||
};
|
||||
let method = trait_methods[pos];
|
||||
|
||||
let cand = Candidate {
|
||||
rcvr_ty: rcvr_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_ty.idx,
|
||||
bound_num: this_bound_idx,
|
||||
})
|
||||
};
|
||||
|
||||
debug!("pushing inherent candidate for param: %?", cand);
|
||||
self.inherent_candidates.push(cand);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn push_inherent_candidates_from_trait(&self,
|
||||
self_ty: ty::t,
|
||||
did: def_id,
|
||||
@ -438,69 +381,87 @@ impl<'self> LookupContext<'self> {
|
||||
});
|
||||
}
|
||||
|
||||
pub fn push_inherent_candidates_from_param(&self,
|
||||
rcvr_ty: ty::t,
|
||||
param_ty: param_ty) {
|
||||
debug!("push_inherent_candidates_from_param(param_ty=%?)",
|
||||
param_ty);
|
||||
let _indenter = indenter();
|
||||
|
||||
let tcx = self.tcx();
|
||||
let type_param_def = match tcx.ty_param_defs.find(¶m_ty.def_id.node) {
|
||||
Some(t) => t,
|
||||
None => {
|
||||
tcx.sess.span_bug(
|
||||
self.expr.span,
|
||||
fmt!("No param def for %?", param_ty));
|
||||
}
|
||||
};
|
||||
|
||||
self.push_inherent_candidates_from_bounds(
|
||||
rcvr_ty, type_param_def.bounds.trait_bounds,
|
||||
param_numbered(param_ty.idx));
|
||||
}
|
||||
|
||||
|
||||
pub fn push_inherent_candidates_from_self(&self,
|
||||
self_ty: ty::t,
|
||||
did: def_id) {
|
||||
struct MethodInfo {
|
||||
method_ty: @ty::Method,
|
||||
trait_def_id: ast::def_id,
|
||||
index: uint,
|
||||
trait_ref: @ty::TraitRef
|
||||
}
|
||||
|
||||
let tcx = self.tcx();
|
||||
// First, try self methods
|
||||
let mut method_info: Option<MethodInfo> = None;
|
||||
let methods = ty::trait_methods(tcx, did);
|
||||
match methods.iter().position(|m| m.ident == self.m_name) {
|
||||
Some(i) => {
|
||||
method_info = Some(MethodInfo {
|
||||
method_ty: methods[i],
|
||||
index: i,
|
||||
trait_def_id: did,
|
||||
trait_ref: ty::lookup_trait_def(tcx, did).trait_ref
|
||||
});
|
||||
}
|
||||
None => ()
|
||||
}
|
||||
// No method found yet? Check each supertrait
|
||||
if method_info.is_none() {
|
||||
for ty::trait_supertraits(tcx, did).iter().advance |trait_ref| {
|
||||
let supertrait_methods =
|
||||
ty::trait_methods(tcx, trait_ref.def_id);
|
||||
match supertrait_methods.iter().position(|m| m.ident == self.m_name) {
|
||||
Some(i) => {
|
||||
method_info = Some(MethodInfo {
|
||||
method_ty: supertrait_methods[i],
|
||||
index: i,
|
||||
trait_def_id: trait_ref.def_id,
|
||||
trait_ref: *trait_ref
|
||||
});
|
||||
break;
|
||||
|
||||
let trait_ref = ty::lookup_trait_def(tcx, did).trait_ref;
|
||||
self.push_inherent_candidates_from_bounds(
|
||||
self_ty, &[trait_ref], param_self);
|
||||
}
|
||||
|
||||
pub fn push_inherent_candidates_from_bounds(&self,
|
||||
self_ty: ty::t,
|
||||
bounds: &[@TraitRef],
|
||||
param: param_index) {
|
||||
let tcx = self.tcx();
|
||||
let mut next_bound_idx = 0; // count only trait bounds
|
||||
|
||||
for ty::each_bound_trait_and_supertraits(tcx, bounds)
|
||||
|bound_trait_ref|
|
||||
{
|
||||
let this_bound_idx = next_bound_idx;
|
||||
next_bound_idx += 1;
|
||||
|
||||
let trait_methods = ty::trait_methods(tcx, bound_trait_ref.def_id);
|
||||
let pos = {
|
||||
match trait_methods.iter().position(|m| {
|
||||
m.explicit_self != ast::sty_static &&
|
||||
m.ident == self.m_name })
|
||||
{
|
||||
Some(pos) => pos,
|
||||
None => {
|
||||
debug!("trait doesn't contain method: %?",
|
||||
bound_trait_ref.def_id);
|
||||
loop; // check next trait or bound
|
||||
}
|
||||
None => ()
|
||||
}
|
||||
}
|
||||
}
|
||||
match method_info {
|
||||
Some(ref info) => {
|
||||
// We've found a method -- return it
|
||||
let origin = if did == info.trait_def_id {
|
||||
method_self(info.trait_def_id, info.index)
|
||||
} else {
|
||||
method_super(info.trait_def_id, info.index)
|
||||
};
|
||||
self.inherent_candidates.push(Candidate {
|
||||
rcvr_ty: self_ty,
|
||||
rcvr_substs: info.trait_ref.substs.clone(),
|
||||
method_ty: info.method_ty,
|
||||
origin: origin
|
||||
});
|
||||
}
|
||||
_ => return
|
||||
};
|
||||
let method = trait_methods[pos];
|
||||
|
||||
let cand = Candidate {
|
||||
rcvr_ty: 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,
|
||||
})
|
||||
};
|
||||
|
||||
debug!("pushing inherent candidate for param: %?", cand);
|
||||
self.inherent_candidates.push(cand);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
pub fn push_inherent_impl_candidates_for_type(&self, did: def_id) {
|
||||
let opt_impl_infos = self.tcx().inherent_impls.find(&did);
|
||||
for opt_impl_infos.iter().advance |impl_infos| {
|
||||
@ -1005,14 +966,13 @@ impl<'self> LookupContext<'self> {
|
||||
/*!
|
||||
*
|
||||
* There are some limitations to calling functions through a
|
||||
* traint instance, because (a) the self type is not known
|
||||
* trait instance, because (a) the self type is not known
|
||||
* (that's the whole point of a trait instance, after all, to
|
||||
* obscure the self type) and (b) the call must go through a
|
||||
* vtable and hence cannot be monomorphized. */
|
||||
|
||||
match candidate.origin {
|
||||
method_static(*) | method_param(*) |
|
||||
method_self(*) | method_super(*) => {
|
||||
method_static(*) | method_param(*) => {
|
||||
return; // not a call to a trait instance
|
||||
}
|
||||
method_trait(*) => {}
|
||||
@ -1036,10 +996,11 @@ impl<'self> LookupContext<'self> {
|
||||
// No code can call the finalize method explicitly.
|
||||
let bad;
|
||||
match candidate.origin {
|
||||
method_static(method_id) | method_self(method_id, _)
|
||||
| method_super(method_id, _) => {
|
||||
method_static(method_id) => {
|
||||
bad = self.tcx().destructors.contains(&method_id);
|
||||
}
|
||||
// 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, _, _) => {
|
||||
bad = self.tcx().destructor_for_type.contains_key(&trait_id);
|
||||
@ -1158,8 +1119,7 @@ impl<'self> LookupContext<'self> {
|
||||
method_param(ref mp) => {
|
||||
type_of_trait_method(self.tcx(), mp.trait_id, mp.method_num)
|
||||
}
|
||||
method_trait(did, idx, _) | method_self(did, idx) |
|
||||
method_super(did, idx) => {
|
||||
method_trait(did, idx, _) => {
|
||||
type_of_trait_method(self.tcx(), did, idx)
|
||||
}
|
||||
};
|
||||
@ -1180,8 +1140,7 @@ impl<'self> LookupContext<'self> {
|
||||
method_param(ref mp) => {
|
||||
self.report_param_candidate(idx, (*mp).trait_id)
|
||||
}
|
||||
method_trait(trait_did, _, _) | method_self(trait_did, _)
|
||||
| method_super(trait_did, _) => {
|
||||
method_trait(trait_did, _, _) => {
|
||||
self.report_trait_candidate(idx, trait_did)
|
||||
}
|
||||
}
|
||||
|
@ -16,11 +16,11 @@ 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_res};
|
||||
use middle::typeck::{vtable_static, vtable_param, vtable_self};
|
||||
use middle::typeck::{CrateCtxt, vtable_origin, vtable_res, vtable_param_res};
|
||||
use middle::typeck::{vtable_static, vtable_param, impl_res};
|
||||
use middle::typeck::{param_numbered, param_self, param_index};
|
||||
use middle::subst::Subst;
|
||||
use util::common::indenter;
|
||||
use util::ppaux::tys_to_str;
|
||||
use util::ppaux;
|
||||
|
||||
use std::hashmap::HashSet;
|
||||
@ -46,6 +46,16 @@ use syntax::visit;
|
||||
// *fully* resolved. (We could be less restrictive than that, but it
|
||||
// would require much more care, and this seems to work decently in
|
||||
// practice.)
|
||||
//
|
||||
// While resolution on a single type requires the type to be fully
|
||||
// resolved, when resolving a substitution against a list of bounds,
|
||||
// we do not require all of the types to be resolved in advance.
|
||||
// Furthermore, we process substitutions in reverse order, which
|
||||
// allows resolution on later parameters to give information on
|
||||
// earlier params referenced by the typeclass bounds.
|
||||
// It may be better to do something more clever, like processing fully
|
||||
// resolved types first.
|
||||
|
||||
|
||||
/// Location info records the span and ID of the expression or item that is
|
||||
/// responsible for this vtable instantiation. (This may not be an expression
|
||||
@ -84,42 +94,19 @@ fn lookup_vtables(vcx: &VtableContext,
|
||||
substs.repr(vcx.tcx()));
|
||||
let _i = indenter();
|
||||
|
||||
let tcx = vcx.tcx();
|
||||
let mut result = ~[];
|
||||
let mut i = 0u;
|
||||
for substs.tps.iter().advance |ty| {
|
||||
// ty is the value supplied for the type parameter A...
|
||||
let mut param_result = ~[];
|
||||
|
||||
for ty::each_bound_trait_and_supertraits(
|
||||
tcx, type_param_defs[i].bounds) |trait_ref|
|
||||
{
|
||||
// ...and here trait_ref is each bound that was declared on A,
|
||||
// expressed in terms of the type parameters.
|
||||
// We do this backwards for reasons discussed above.
|
||||
assert_eq!(substs.tps.len(), type_param_defs.len());
|
||||
let mut result =
|
||||
substs.tps.rev_iter()
|
||||
.zip(type_param_defs.rev_iter())
|
||||
.transform(|(ty, def)|
|
||||
lookup_vtables_for_param(vcx, location_info, Some(substs),
|
||||
&*def.bounds, *ty, is_early))
|
||||
.to_owned_vec();
|
||||
result.reverse();
|
||||
|
||||
debug!("about to subst: %s, %s", trait_ref.repr(tcx), substs.repr(tcx));
|
||||
|
||||
// Substitute the values of the type parameters that may
|
||||
// appear in the bound.
|
||||
let trait_ref = trait_ref.subst(tcx, substs);
|
||||
|
||||
debug!("after subst: %s", trait_ref.repr(tcx));
|
||||
|
||||
match lookup_vtable(vcx, location_info, *ty, trait_ref, is_early) {
|
||||
Some(vtable) => param_result.push(vtable),
|
||||
None => {
|
||||
vcx.tcx().sess.span_fatal(
|
||||
location_info.span,
|
||||
fmt!("failed to find an implementation of \
|
||||
trait %s for %s",
|
||||
vcx.infcx.trait_ref_to_str(trait_ref),
|
||||
vcx.infcx.ty_to_str(*ty)));
|
||||
}
|
||||
}
|
||||
}
|
||||
result.push(@param_result);
|
||||
i += 1u;
|
||||
}
|
||||
assert_eq!(substs.tps.len(), result.len());
|
||||
debug!("lookup_vtables result(\
|
||||
location_info=%?, \
|
||||
type_param_defs=%s, \
|
||||
@ -132,25 +119,58 @@ fn lookup_vtables(vcx: &VtableContext,
|
||||
@result
|
||||
}
|
||||
|
||||
fn fixup_substs(vcx: &VtableContext,
|
||||
location_info: &LocationInfo,
|
||||
id: ast::def_id,
|
||||
substs: ty::substs,
|
||||
is_early: bool)
|
||||
-> Option<ty::substs> {
|
||||
fn lookup_vtables_for_param(vcx: &VtableContext,
|
||||
location_info: &LocationInfo,
|
||||
// None for substs means the identity
|
||||
substs: Option<&ty::substs>,
|
||||
type_param_bounds: &ty::ParamBounds,
|
||||
ty: ty::t,
|
||||
is_early: bool) -> vtable_param_res {
|
||||
let tcx = vcx.tcx();
|
||||
// use a dummy type just to package up the substs that need fixing up
|
||||
let t = ty::mk_trait(tcx,
|
||||
id, substs,
|
||||
ty::RegionTraitStore(ty::re_static),
|
||||
ast::m_imm,
|
||||
ty::EmptyBuiltinBounds());
|
||||
do fixup_ty(vcx, location_info, t, is_early).map |t_f| {
|
||||
match ty::get(*t_f).sty {
|
||||
ty::ty_trait(_, ref substs_f, _, _, _) => (*substs_f).clone(),
|
||||
_ => fail!("t_f should be a trait")
|
||||
|
||||
// ty is the value supplied for the type parameter A...
|
||||
let mut param_result = ~[];
|
||||
|
||||
for ty::each_bound_trait_and_supertraits(
|
||||
tcx, type_param_bounds.trait_bounds) |trait_ref|
|
||||
{
|
||||
// ...and here trait_ref is each bound that was declared on A,
|
||||
// expressed in terms of the type parameters.
|
||||
|
||||
// Substitute the values of the type parameters that may
|
||||
// appear in the bound.
|
||||
let trait_ref = substs.map_default(trait_ref, |substs| {
|
||||
debug!("about to subst: %s, %s",
|
||||
trait_ref.repr(tcx), substs.repr(tcx));
|
||||
trait_ref.subst(tcx, *substs)
|
||||
});
|
||||
|
||||
debug!("after subst: %s", trait_ref.repr(tcx));
|
||||
|
||||
match lookup_vtable(vcx, location_info, ty, trait_ref, is_early) {
|
||||
Some(vtable) => param_result.push(vtable),
|
||||
None => {
|
||||
vcx.tcx().sess.span_fatal(
|
||||
location_info.span,
|
||||
fmt!("failed to find an implementation of \
|
||||
trait %s for %s",
|
||||
vcx.infcx.trait_ref_to_str(trait_ref),
|
||||
vcx.infcx.ty_to_str(ty)));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
debug!("lookup_vtables_for_param result(\
|
||||
location_info=%?, \
|
||||
type_param_bounds=%s, \
|
||||
ty=%s, \
|
||||
result=%s)",
|
||||
location_info,
|
||||
type_param_bounds.repr(vcx.tcx()),
|
||||
ty.repr(vcx.tcx()),
|
||||
param_result.repr(vcx.tcx()));
|
||||
|
||||
return @param_result;
|
||||
}
|
||||
|
||||
fn relate_trait_refs(vcx: &VtableContext,
|
||||
@ -173,10 +193,15 @@ fn relate_trait_refs(vcx: &VtableContext,
|
||||
{
|
||||
result::Ok(()) => {} // Ok.
|
||||
result::Err(ref err) => {
|
||||
// There is an error, but we need to do some work to make
|
||||
// the message good.
|
||||
// Resolve any type vars in the trait refs
|
||||
let r_act_trait_ref =
|
||||
vcx.infcx.resolve_type_vars_in_trait_ref_if_possible(act_trait_ref);
|
||||
let r_exp_trait_ref =
|
||||
vcx.infcx.resolve_type_vars_in_trait_ref_if_possible(exp_trait_ref);
|
||||
// Only print the message if there aren't any previous type errors
|
||||
// inside the types.
|
||||
if !ty::trait_ref_contains_error(&r_act_trait_ref) &&
|
||||
!ty::trait_ref_contains_error(&r_exp_trait_ref)
|
||||
{
|
||||
@ -192,8 +217,7 @@ fn relate_trait_refs(vcx: &VtableContext,
|
||||
}
|
||||
}
|
||||
|
||||
// Look up the vtable to use when treating an item of type `t` as if it has
|
||||
// type `trait_ty`
|
||||
// Look up the vtable implementing the trait `trait_ref` at type `t`
|
||||
fn lookup_vtable(vcx: &VtableContext,
|
||||
location_info: &LocationInfo,
|
||||
ty: ty::t,
|
||||
@ -216,222 +240,249 @@ fn lookup_vtable(vcx: &VtableContext,
|
||||
// The type has unconstrained type variables in it, so we can't
|
||||
// do early resolution on it. Return some completely bogus vtable
|
||||
// information: we aren't storing it anyways.
|
||||
return Some(vtable_param(0, 0));
|
||||
return Some(vtable_param(param_self, 0));
|
||||
}
|
||||
};
|
||||
|
||||
match ty::get(ty).sty {
|
||||
// If the type is self or a param, we look at the trait/supertrait
|
||||
// bounds to see if they include the trait we are looking for.
|
||||
let vtable_opt = match ty::get(ty).sty {
|
||||
ty::ty_param(param_ty {idx: n, def_id: did}) => {
|
||||
let mut n_bound = 0;
|
||||
let type_param_def = tcx.ty_param_defs.get(&did.node);
|
||||
for ty::each_bound_trait_and_supertraits(
|
||||
tcx, type_param_def.bounds) |bound_trait_ref|
|
||||
{
|
||||
debug!("checking bounds trait %s", bound_trait_ref.repr(vcx.tcx()));
|
||||
|
||||
if bound_trait_ref.def_id == trait_ref.def_id {
|
||||
relate_trait_refs(vcx,
|
||||
location_info,
|
||||
bound_trait_ref,
|
||||
trait_ref);
|
||||
let vtable = vtable_param(n, n_bound);
|
||||
debug!("found param vtable: %?",
|
||||
vtable);
|
||||
return Some(vtable);
|
||||
}
|
||||
|
||||
n_bound += 1;
|
||||
}
|
||||
lookup_vtable_from_bounds(vcx, location_info,
|
||||
type_param_def.bounds.trait_bounds,
|
||||
param_numbered(n),
|
||||
trait_ref)
|
||||
}
|
||||
|
||||
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 self_trait_ref = ty::lookup_trait_def(tcx, trait_id).trait_ref;
|
||||
lookup_vtable_from_bounds(vcx, location_info,
|
||||
&[self_trait_ref],
|
||||
param_self,
|
||||
trait_ref)
|
||||
}
|
||||
|
||||
_ => {
|
||||
let mut found = ~[];
|
||||
// Default case just falls through
|
||||
_ => None
|
||||
};
|
||||
|
||||
let mut impls_seen = HashSet::new();
|
||||
if vtable_opt.is_some() { return vtable_opt; }
|
||||
|
||||
match tcx.trait_impls.find(&trait_ref.def_id) {
|
||||
None => {
|
||||
// Nothing found. Continue.
|
||||
}
|
||||
Some(implementations) => {
|
||||
// implementations is the list of all impls in scope for
|
||||
// trait_ref. (Usually, there's just one.)
|
||||
for implementations.iter().advance |im| {
|
||||
// im is one specific impl of trait_ref.
|
||||
// If we aren't a self type or param, or it was, but we didn't find it,
|
||||
// do a search.
|
||||
return search_for_vtable(vcx, location_info,
|
||||
ty, trait_ref, is_early)
|
||||
}
|
||||
|
||||
// First, ensure we haven't processed this impl yet.
|
||||
if impls_seen.contains(&im.did) {
|
||||
loop;
|
||||
}
|
||||
impls_seen.insert(im.did);
|
||||
// Given a list of bounds on a type, search those bounds to see if any
|
||||
// of them are the vtable we are looking for.
|
||||
fn lookup_vtable_from_bounds(vcx: &VtableContext,
|
||||
location_info: &LocationInfo,
|
||||
bounds: &[@ty::TraitRef],
|
||||
param: param_index,
|
||||
trait_ref: @ty::TraitRef)
|
||||
-> Option<vtable_origin> {
|
||||
let tcx = vcx.tcx();
|
||||
|
||||
// ty::impl_traits gives us the trait im implements,
|
||||
// if there is one (there's either zero or one).
|
||||
//
|
||||
// If foo implements a trait t, and if t is the
|
||||
// same trait as trait_ref, we need to
|
||||
// unify it with trait_ref in order to get all
|
||||
// the ty vars sorted out.
|
||||
let r = ty::impl_trait_ref(tcx, im.did);
|
||||
for r.iter().advance |&of_trait_ref| {
|
||||
if of_trait_ref.def_id != trait_ref.def_id { loop; }
|
||||
let mut n_bound = 0;
|
||||
for ty::each_bound_trait_and_supertraits(tcx, bounds) |bound_trait_ref| {
|
||||
debug!("checking bounds trait %s",
|
||||
bound_trait_ref.repr(vcx.tcx()));
|
||||
|
||||
// At this point, we know that of_trait_ref is
|
||||
// the same trait as trait_ref, but
|
||||
// possibly applied to different substs.
|
||||
//
|
||||
// Next, we check whether the "for" ty in
|
||||
// the impl is compatible with the type
|
||||
// that we're casting to a trait. That is,
|
||||
// if im is:
|
||||
//
|
||||
// impl<T> self_ty<T>: some_trait<T> { ... }
|
||||
//
|
||||
// we check whether self_ty<T> is the type
|
||||
// of the thing that we're trying to cast
|
||||
// to some_trait. If not, then we try the next
|
||||
// impl.
|
||||
//
|
||||
// FIXME(#5781) this should be mk_eqty not mk_subty
|
||||
let ty::ty_param_substs_and_ty {
|
||||
substs: substs,
|
||||
ty: for_ty
|
||||
} = impl_self_ty(vcx, location_info, im.did);
|
||||
match infer::mk_subty(vcx.infcx,
|
||||
false,
|
||||
infer::RelateSelfType(
|
||||
location_info.span),
|
||||
ty,
|
||||
for_ty) {
|
||||
result::Err(_) => loop,
|
||||
result::Ok(()) => ()
|
||||
}
|
||||
|
||||
// Now, in the previous example, for_ty is
|
||||
// bound to the type self_ty, and substs
|
||||
// is bound to [T].
|
||||
debug!("The self ty is %s and its substs are %s",
|
||||
vcx.infcx.ty_to_str(for_ty),
|
||||
tys_to_str(vcx.tcx(), substs.tps));
|
||||
|
||||
// Next, we unify trait_ref -- the type
|
||||
// that we want to cast to -- with of_trait_ref
|
||||
// -- the trait that im implements. At
|
||||
// this point, we require that they be
|
||||
// unifiable with each other -- that's
|
||||
// what relate_trait_refs does.
|
||||
//
|
||||
// For example, in the above example,
|
||||
// of_trait_ref would be some_trait<T>, so we
|
||||
// would be unifying trait_ref<U> (for some
|
||||
// value of U) with some_trait<T>. This
|
||||
// would fail if T and U weren't
|
||||
// compatible.
|
||||
|
||||
debug!("(checking vtable) @2 relating trait \
|
||||
ty %s to of_trait_ref %s",
|
||||
vcx.infcx.trait_ref_to_str(trait_ref),
|
||||
vcx.infcx.trait_ref_to_str(of_trait_ref));
|
||||
|
||||
let of_trait_ref = of_trait_ref.subst(tcx, &substs);
|
||||
relate_trait_refs(
|
||||
vcx, location_info,
|
||||
of_trait_ref, trait_ref);
|
||||
|
||||
// Recall that trait_ref -- the trait type
|
||||
// we're casting to -- is the trait with
|
||||
// id trait_ref.def_id applied to the substs
|
||||
// trait_ref.substs. Now we extract out the
|
||||
// types themselves from trait_ref.substs.
|
||||
|
||||
// Recall that substs is the impl self
|
||||
// type's list of substitutions. That is,
|
||||
// if this is an impl of some trait for
|
||||
// foo<T, U>, then substs is [T,
|
||||
// U]. substs might contain type
|
||||
// variables, so we call fixup_substs to
|
||||
// resolve them.
|
||||
|
||||
let substs_f = match fixup_substs(vcx,
|
||||
location_info,
|
||||
trait_ref.def_id,
|
||||
substs,
|
||||
is_early) {
|
||||
Some(ref substs) => (*substs).clone(),
|
||||
None => {
|
||||
assert!(is_early);
|
||||
// Bail out with a bogus answer
|
||||
return Some(vtable_param(0, 0));
|
||||
}
|
||||
};
|
||||
|
||||
debug!("The fixed-up substs are %s - \
|
||||
they will be unified with the bounds for \
|
||||
the target ty, %s",
|
||||
tys_to_str(vcx.tcx(), substs_f.tps),
|
||||
vcx.infcx.trait_ref_to_str(trait_ref));
|
||||
|
||||
// Next, we unify the fixed-up
|
||||
// substitutions for the impl self ty with
|
||||
// the substitutions from the trait type
|
||||
// that we're trying to cast
|
||||
// to. connect_trait_tps requires these
|
||||
// lists of types to unify pairwise.
|
||||
|
||||
let im_generics =
|
||||
ty::lookup_item_type(tcx, im.did).generics;
|
||||
connect_trait_tps(vcx,
|
||||
location_info,
|
||||
&substs_f,
|
||||
trait_ref,
|
||||
im.did);
|
||||
let subres = lookup_vtables(
|
||||
vcx, location_info,
|
||||
*im_generics.type_param_defs, &substs_f,
|
||||
is_early);
|
||||
|
||||
// Finally, we register that we found a
|
||||
// matching impl, and record the def ID of
|
||||
// the impl as well as the resolved list
|
||||
// of type substitutions for the target
|
||||
// trait.
|
||||
found.push(vtable_static(im.did,
|
||||
substs_f.tps.clone(),
|
||||
subres));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
match found.len() {
|
||||
0 => { /* fallthrough */ }
|
||||
1 => return Some(found[0].clone()),
|
||||
_ => {
|
||||
if !is_early {
|
||||
vcx.tcx().sess.span_err(
|
||||
location_info.span,
|
||||
"multiple applicable methods in scope");
|
||||
}
|
||||
return Some(found[0].clone());
|
||||
}
|
||||
}
|
||||
if bound_trait_ref.def_id == trait_ref.def_id {
|
||||
relate_trait_refs(vcx,
|
||||
location_info,
|
||||
bound_trait_ref,
|
||||
trait_ref);
|
||||
let vtable = vtable_param(param, n_bound);
|
||||
debug!("found param vtable: %?",
|
||||
vtable);
|
||||
return Some(vtable);
|
||||
}
|
||||
|
||||
n_bound += 1;
|
||||
}
|
||||
|
||||
return None;
|
||||
}
|
||||
|
||||
fn search_for_vtable(vcx: &VtableContext,
|
||||
location_info: &LocationInfo,
|
||||
ty: ty::t,
|
||||
trait_ref: @ty::TraitRef,
|
||||
is_early: bool)
|
||||
-> Option<vtable_origin>
|
||||
{
|
||||
let tcx = vcx.tcx();
|
||||
|
||||
let mut found = ~[];
|
||||
let mut impls_seen = HashSet::new();
|
||||
|
||||
// XXX: this is a bad way to do this, since we do
|
||||
// pointless allocations.
|
||||
let impls = tcx.trait_impls.find(&trait_ref.def_id)
|
||||
.map_default(@mut ~[], |x| **x);
|
||||
// impls is the list of all impls in scope for trait_ref.
|
||||
for impls.iter().advance |im| {
|
||||
// im is one specific impl of trait_ref.
|
||||
|
||||
// First, ensure we haven't processed this impl yet.
|
||||
if impls_seen.contains(&im.did) {
|
||||
loop;
|
||||
}
|
||||
impls_seen.insert(im.did);
|
||||
|
||||
// ty::impl_traits gives us the trait im implements.
|
||||
//
|
||||
// If foo implements a trait t, and if t is the same trait as
|
||||
// trait_ref, we need to unify it with trait_ref in order to
|
||||
// get all the ty vars sorted out.
|
||||
let r = ty::impl_trait_ref(tcx, im.did);
|
||||
let of_trait_ref = r.expect("trait_ref missing on trait impl");
|
||||
if of_trait_ref.def_id != trait_ref.def_id { loop; }
|
||||
|
||||
// At this point, we know that of_trait_ref is the same trait
|
||||
// as trait_ref, but possibly applied to different substs.
|
||||
//
|
||||
// Next, we check whether the "for" ty in the impl is
|
||||
// compatible with the type that we're casting to a
|
||||
// trait. That is, if im is:
|
||||
//
|
||||
// impl<T> some_trait<T> for self_ty<T> { ... }
|
||||
//
|
||||
// we check whether self_ty<T> is the type of the thing that
|
||||
// we're trying to cast to some_trait. If not, then we try
|
||||
// the next impl.
|
||||
//
|
||||
// XXX: document a bit more what this means
|
||||
//
|
||||
// FIXME(#5781) this should be mk_eqty not mk_subty
|
||||
let ty::ty_param_substs_and_ty {
|
||||
substs: substs,
|
||||
ty: for_ty
|
||||
} = impl_self_ty(vcx, location_info, im.did);
|
||||
match infer::mk_subty(vcx.infcx,
|
||||
false,
|
||||
infer::RelateSelfType(
|
||||
location_info.span),
|
||||
ty,
|
||||
for_ty) {
|
||||
result::Err(_) => loop,
|
||||
result::Ok(()) => ()
|
||||
}
|
||||
|
||||
// Now, in the previous example, for_ty is bound to
|
||||
// the type self_ty, and substs is bound to [T].
|
||||
debug!("The self ty is %s and its substs are %s",
|
||||
vcx.infcx.ty_to_str(for_ty),
|
||||
vcx.infcx.tys_to_str(substs.tps));
|
||||
|
||||
// Next, we unify trait_ref -- the type that we want to cast
|
||||
// to -- with of_trait_ref -- the trait that im implements. At
|
||||
// this point, we require that they be unifiable with each
|
||||
// other -- that's what relate_trait_refs does.
|
||||
//
|
||||
// For example, in the above example, of_trait_ref would be
|
||||
// some_trait<T>, so we would be unifying trait_ref<U> (for
|
||||
// some value of U) with some_trait<T>. This would fail if T
|
||||
// and U weren't compatible.
|
||||
|
||||
debug!("(checking vtable) @2 relating trait \
|
||||
ty %s to of_trait_ref %s",
|
||||
vcx.infcx.trait_ref_to_str(trait_ref),
|
||||
vcx.infcx.trait_ref_to_str(of_trait_ref));
|
||||
|
||||
let of_trait_ref = of_trait_ref.subst(tcx, &substs);
|
||||
relate_trait_refs(vcx, location_info, of_trait_ref, trait_ref);
|
||||
|
||||
|
||||
// Recall that trait_ref -- the trait type we're casting to --
|
||||
// is the trait with id trait_ref.def_id applied to the substs
|
||||
// trait_ref.substs.
|
||||
|
||||
// Resolve any sub bounds. Note that there still may be free
|
||||
// type variables in substs. This might still be OK: the
|
||||
// process of looking up bounds might constrain some of them.
|
||||
let im_generics =
|
||||
ty::lookup_item_type(tcx, im.did).generics;
|
||||
let subres = lookup_vtables(vcx, location_info,
|
||||
*im_generics.type_param_defs, &substs,
|
||||
is_early);
|
||||
|
||||
|
||||
// substs might contain type variables, so we call
|
||||
// fixup_substs to resolve them.
|
||||
let substs_f = match fixup_substs(vcx,
|
||||
location_info,
|
||||
trait_ref.def_id,
|
||||
substs,
|
||||
is_early) {
|
||||
Some(ref substs) => (*substs).clone(),
|
||||
None => {
|
||||
assert!(is_early);
|
||||
// Bail out with a bogus answer
|
||||
return Some(vtable_param(param_self, 0));
|
||||
}
|
||||
};
|
||||
|
||||
debug!("The fixed-up substs are %s - \
|
||||
they will be unified with the bounds for \
|
||||
the target ty, %s",
|
||||
vcx.infcx.tys_to_str(substs_f.tps),
|
||||
vcx.infcx.trait_ref_to_str(trait_ref));
|
||||
|
||||
// Next, we unify the fixed-up substitutions for the impl self
|
||||
// ty with the substitutions from the trait type that we're
|
||||
// trying to cast to. connect_trait_tps requires these lists
|
||||
// of types to unify pairwise.
|
||||
// I am a little confused about this, since it seems to be
|
||||
// very similar to the relate_trait_refs we already do,
|
||||
// but problems crop up if it is removed, so... -sully
|
||||
connect_trait_tps(vcx, location_info, &substs_f, trait_ref, im.did);
|
||||
|
||||
// Finally, we register that we found a matching impl, and
|
||||
// record the def ID of the impl as well as the resolved list
|
||||
// of type substitutions for the target trait.
|
||||
found.push(vtable_static(im.did, substs_f.tps.clone(), subres));
|
||||
}
|
||||
|
||||
match found.len() {
|
||||
0 => { return None }
|
||||
1 => return Some(found[0].clone()),
|
||||
_ => {
|
||||
if !is_early {
|
||||
vcx.tcx().sess.span_err(
|
||||
location_info.span,
|
||||
"multiple applicable methods in scope");
|
||||
}
|
||||
return Some(found[0].clone());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
fn fixup_substs(vcx: &VtableContext,
|
||||
location_info: &LocationInfo,
|
||||
id: ast::def_id,
|
||||
substs: ty::substs,
|
||||
is_early: bool)
|
||||
-> Option<ty::substs> {
|
||||
let tcx = vcx.tcx();
|
||||
// use a dummy type just to package up the substs that need fixing up
|
||||
let t = ty::mk_trait(tcx,
|
||||
id, substs,
|
||||
ty::RegionTraitStore(ty::re_static),
|
||||
ast::m_imm,
|
||||
ty::EmptyBuiltinBounds());
|
||||
do fixup_ty(vcx, location_info, t, is_early).map |t_f| {
|
||||
match ty::get(*t_f).sty {
|
||||
ty::ty_trait(_, ref substs_f, _, _, _) => (*substs_f).clone(),
|
||||
_ => fail!("t_f should be a trait")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn fixup_ty(vcx: &VtableContext,
|
||||
location_info: &LocationInfo,
|
||||
ty: ty::t,
|
||||
@ -682,16 +733,39 @@ pub fn resolve_impl(ccx: @mut CrateCtxt, impl_item: @ast::item) {
|
||||
Some(trait_ref) => {
|
||||
let infcx = infer::new_infer_ctxt(ccx.tcx);
|
||||
let vcx = VtableContext { ccx: ccx, infcx: infcx };
|
||||
let trait_def = ty::lookup_trait_def(ccx.tcx, trait_ref.def_id);
|
||||
let loc_info = location_info_for_item(impl_item);
|
||||
|
||||
// First, check that the impl implements any trait bounds
|
||||
// on the trait.
|
||||
let trait_def = ty::lookup_trait_def(ccx.tcx, trait_ref.def_id);
|
||||
let vtbls = lookup_vtables(&vcx,
|
||||
&location_info_for_item(impl_item),
|
||||
&loc_info,
|
||||
*trait_def.generics.type_param_defs,
|
||||
&trait_ref.substs,
|
||||
false);
|
||||
|
||||
// FIXME(#7450): Doesn't work cross crate
|
||||
ccx.vtable_map.insert(impl_item.id, vtbls);
|
||||
// Now, locate the vtable for the impl itself. The real
|
||||
// purpose of this is to check for supertrait impls,
|
||||
// but that falls out of doing this.
|
||||
let param_bounds = ty::ParamBounds {
|
||||
builtin_bounds: ty::EmptyBuiltinBounds(),
|
||||
trait_bounds: ~[trait_ref]
|
||||
};
|
||||
let t = ty::node_id_to_type(ccx.tcx, impl_item.id);
|
||||
debug!("=== Doing a self lookup now.");
|
||||
// Right now, we don't have any place to store this.
|
||||
// We will need to make one so we can use this information
|
||||
// for compiling default methods that refer to supertraits.
|
||||
let self_vtable_res =
|
||||
lookup_vtables_for_param(&vcx, &loc_info, None,
|
||||
¶m_bounds, t, false);
|
||||
|
||||
|
||||
let res = impl_res {
|
||||
trait_vtables: vtbls,
|
||||
self_vtables: self_vtable_res
|
||||
};
|
||||
ccx.tcx.impl_vtables.insert(def_id, res);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -20,7 +20,7 @@ use middle::typeck::infer::{force_all, resolve_all, resolve_region};
|
||||
use middle::typeck::infer::resolve_type;
|
||||
use middle::typeck::infer;
|
||||
use middle::typeck::{vtable_res, vtable_origin};
|
||||
use middle::typeck::{vtable_static, vtable_param, vtable_self};
|
||||
use middle::typeck::{vtable_static, vtable_param};
|
||||
use middle::typeck::method_map_entry;
|
||||
use middle::typeck::write_substs_to_tcx;
|
||||
use middle::typeck::write_ty_to_tcx;
|
||||
@ -109,9 +109,6 @@ 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)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -653,6 +653,11 @@ impl InferCtxt {
|
||||
self.resolve_type_vars_if_possible(t))
|
||||
}
|
||||
|
||||
pub fn tys_to_str(@mut self, ts: &[ty::t]) -> ~str {
|
||||
let tstrs = ts.map(|t| self.ty_to_str(*t));
|
||||
fmt!("(%s)", tstrs.connect(", "))
|
||||
}
|
||||
|
||||
pub fn trait_ref_to_str(@mut self, t: &ty::TraitRef) -> ~str {
|
||||
let t = self.resolve_type_vars_in_trait_ref_if_possible(t);
|
||||
trait_ref_to_str(self.tcx, &t)
|
||||
|
@ -75,14 +75,14 @@ pub mod infer;
|
||||
pub mod collect;
|
||||
pub mod coherence;
|
||||
|
||||
#[deriving(Clone, Encodable, Decodable, Eq, Ord)]
|
||||
pub enum param_index {
|
||||
param_numbered(uint),
|
||||
param_self
|
||||
}
|
||||
|
||||
#[deriving(Clone, Encodable, Decodable)]
|
||||
pub enum method_origin {
|
||||
// supertrait method invoked on "self" inside a default method
|
||||
// first field is supertrait ID;
|
||||
// second field is method index (relative to the *supertrait*
|
||||
// method list)
|
||||
method_super(ast::def_id, uint),
|
||||
|
||||
// fully statically resolved method
|
||||
method_static(ast::def_id),
|
||||
|
||||
@ -92,9 +92,6 @@ pub enum method_origin {
|
||||
// method invoked on a trait instance
|
||||
method_trait(ast::def_id, uint, ty::TraitStore),
|
||||
|
||||
// method invoked on "self" inside a default method
|
||||
method_self(ast::def_id, uint)
|
||||
|
||||
}
|
||||
|
||||
// details for a method invoked with a receiver whose type is a type parameter
|
||||
@ -109,7 +106,7 @@ pub struct method_param {
|
||||
|
||||
// index of the type parameter (from those that are in scope) that is
|
||||
// the type of the receiver
|
||||
param_num: uint,
|
||||
param_num: param_index,
|
||||
|
||||
// index of the bound for this type parameter which specifies the trait
|
||||
bound_num: uint,
|
||||
@ -153,15 +150,10 @@ pub enum vtable_origin {
|
||||
fn foo<T:quux,baz,bar>(a: T) -- a's vtable would have a
|
||||
vtable_param origin
|
||||
|
||||
The first uint is the param number (identifying T in the example),
|
||||
The first argument is the param index (identifying T in the example),
|
||||
and the second is the bound number (identifying baz)
|
||||
*/
|
||||
vtable_param(uint, uint),
|
||||
|
||||
/*
|
||||
Dynamic vtable, comes from self.
|
||||
*/
|
||||
vtable_self(ast::def_id)
|
||||
vtable_param(param_index, uint),
|
||||
}
|
||||
|
||||
impl Repr for vtable_origin {
|
||||
@ -178,15 +170,34 @@ impl Repr for vtable_origin {
|
||||
vtable_param(x, y) => {
|
||||
fmt!("vtable_param(%?, %?)", x, y)
|
||||
}
|
||||
vtable_self(def_id) => {
|
||||
fmt!("vtable_self(%?)", def_id)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub type vtable_map = @mut HashMap<ast::node_id, vtable_res>;
|
||||
|
||||
|
||||
// Information about the vtable resolutions for for a trait impl.
|
||||
// Mostly the information is important for implementing default
|
||||
// methods.
|
||||
#[deriving(Clone)]
|
||||
pub struct impl_res {
|
||||
// resolutions for any bounded params on the trait definition
|
||||
trait_vtables: vtable_res,
|
||||
// resolutions for the trait /itself/ (and for supertraits)
|
||||
self_vtables: vtable_param_res
|
||||
}
|
||||
|
||||
impl Repr for impl_res {
|
||||
fn repr(&self, tcx: ty::ctxt) -> ~str {
|
||||
fmt!("impl_res {trait_vtables=%s, self_vtables=%s}",
|
||||
self.trait_vtables.repr(tcx),
|
||||
self.self_vtables.repr(tcx))
|
||||
}
|
||||
}
|
||||
|
||||
pub type impl_vtable_map = @mut HashMap<ast::def_id, impl_res>;
|
||||
|
||||
pub struct CrateCtxt {
|
||||
// A mapping from method call sites to traits that have that method.
|
||||
trait_map: resolve::TraitMap,
|
||||
|
@ -715,10 +715,6 @@ impl Repr for typeck::method_map_entry {
|
||||
impl Repr for typeck::method_origin {
|
||||
fn repr(&self, tcx: ctxt) -> ~str {
|
||||
match self {
|
||||
&typeck::method_super(def_id, n) => {
|
||||
fmt!("method_super(%s, %?)",
|
||||
def_id.repr(tcx), n)
|
||||
}
|
||||
&typeck::method_static(def_id) => {
|
||||
fmt!("method_static(%s)", def_id.repr(tcx))
|
||||
}
|
||||
@ -729,9 +725,6 @@ impl Repr for typeck::method_origin {
|
||||
fmt!("method_trait(%s, %?, %s)", def_id.repr(tcx), n,
|
||||
st.repr(tcx))
|
||||
}
|
||||
&typeck::method_self(def_id, n) => {
|
||||
fmt!("method_self(%s, %?)", def_id.repr(tcx), n)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -86,6 +86,12 @@ pub trait TotalOrd: TotalEq {
|
||||
fn cmp(&self, other: &Self) -> Ordering;
|
||||
}
|
||||
|
||||
impl TotalEq for Ordering {
|
||||
#[inline]
|
||||
fn equals(&self, other: &Ordering) -> bool {
|
||||
*self == *other
|
||||
}
|
||||
}
|
||||
impl TotalOrd for Ordering {
|
||||
#[inline]
|
||||
fn cmp(&self, other: &Ordering) -> Ordering {
|
||||
|
@ -96,7 +96,7 @@ impl<A, T: DoubleEndedIterator<A>> Iterator<A> for InvertIterator<A, T> {
|
||||
fn size_hint(&self) -> (uint, Option<uint>) { self.iter.size_hint() }
|
||||
}
|
||||
|
||||
impl<A, T: Iterator<A>> DoubleEndedIterator<A> for InvertIterator<A, T> {
|
||||
impl<A, T: DoubleEndedIterator<A>> DoubleEndedIterator<A> for InvertIterator<A, T> {
|
||||
#[inline]
|
||||
fn next_back(&mut self) -> Option<A> { self.iter.next() }
|
||||
}
|
||||
@ -343,6 +343,18 @@ pub trait IteratorUtil<A> {
|
||||
/// ~~~
|
||||
fn collect<B: FromIterator<A, Self>>(&mut self) -> B;
|
||||
|
||||
/// Loops through the entire iterator, collecting all of the elements into
|
||||
/// a unique vector. This is simply collect() specialized for vectors.
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ~~~ {.rust}
|
||||
/// let a = [1, 2, 3, 4, 5];
|
||||
/// let b: ~[int] = a.iter().transform(|&x| x).to_owned_vec();
|
||||
/// assert!(a == b);
|
||||
/// ~~~
|
||||
fn to_owned_vec(&mut self) -> ~[A];
|
||||
|
||||
/// Loops through `n` iterations, returning the `n`th element of the
|
||||
/// iterator.
|
||||
///
|
||||
@ -539,6 +551,11 @@ impl<A, T: Iterator<A>> IteratorUtil<A> for T {
|
||||
FromIterator::from_iterator(self)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn to_owned_vec(&mut self) -> ~[A] {
|
||||
self.collect()
|
||||
}
|
||||
|
||||
/// Return the `n`th item yielded by an iterator.
|
||||
#[inline]
|
||||
fn nth(&mut self, mut n: uint) -> Option<A> {
|
||||
|
@ -14,12 +14,13 @@
|
||||
#[crate_type = "lib"];
|
||||
|
||||
trait Positioned {
|
||||
fn SetX(&self, int);
|
||||
fn SetX(&mut self, int);
|
||||
fn X(&self) -> int;
|
||||
}
|
||||
|
||||
trait Movable: Positioned {
|
||||
fn translate(&self, dx: int) {
|
||||
self.SetX(self.X() + dx);
|
||||
fn translate(&mut self, dx: int) {
|
||||
let x = self.X() + dx;
|
||||
self.SetX(x);
|
||||
}
|
||||
}
|
||||
|
36
src/test/run-pass/default-method-supertrait-vtable.rs
Normal file
36
src/test/run-pass/default-method-supertrait-vtable.rs
Normal file
@ -0,0 +1,36 @@
|
||||
// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
|
||||
// Tests that we can call a function bounded over a supertrait from
|
||||
// a default method
|
||||
|
||||
fn require_y<T: Y>(x: T) -> int { x.y() }
|
||||
|
||||
trait Y {
|
||||
fn y(self) -> int;
|
||||
}
|
||||
|
||||
|
||||
trait Z: Y {
|
||||
fn x(self) -> int {
|
||||
require_y(self)
|
||||
}
|
||||
}
|
||||
|
||||
impl Y for int {
|
||||
fn y(self) -> int { self }
|
||||
}
|
||||
|
||||
impl Z for int;
|
||||
|
||||
fn main() {
|
||||
assert_eq!(12.x(), 12);
|
||||
}
|
@ -8,8 +8,6 @@
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
// xfail-test
|
||||
|
||||
trait A {
|
||||
fn a_method(&self);
|
||||
}
|
||||
|
@ -8,15 +8,15 @@
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
// xfail-test FIXME #5946
|
||||
trait Positioned<S> {
|
||||
fn SetX(&mut self, S);
|
||||
fn X(&self) -> S;
|
||||
}
|
||||
|
||||
trait Movable<S, T>: Positioned<T> {
|
||||
fn translate(&self, dx: T) {
|
||||
self.SetX(self.X() + dx);
|
||||
trait Movable<S: Add<S, S>>: Positioned<S> {
|
||||
fn translate(&mut self, dx: S) {
|
||||
let x = self.X() + dx;
|
||||
self.SetX(x);
|
||||
}
|
||||
}
|
||||
|
||||
@ -31,10 +31,10 @@ impl Positioned<int> for Point {
|
||||
}
|
||||
}
|
||||
|
||||
impl Movable<int, int> for Point;
|
||||
impl Movable<int> for Point;
|
||||
|
||||
pub fn main() {
|
||||
let p = Point{ x: 1, y: 2};
|
||||
let mut p = Point{ x: 1, y: 2};
|
||||
p.translate(3);
|
||||
assert_eq!(p.X(), 4);
|
||||
}
|
||||
|
@ -8,7 +8,7 @@
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
// xfail-test // tjc: ???
|
||||
// xfail-fast
|
||||
// aux-build:issue_3979_traits.rs
|
||||
extern mod issue_3979_traits;
|
||||
use issue_3979_traits::*;
|
||||
|
@ -1,5 +1,3 @@
|
||||
// xfail-test
|
||||
// Reason: ICE with explicit self
|
||||
|
||||
// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
|
42
src/test/run-pass/supertrait-default-generics.rs
Normal file
42
src/test/run-pass/supertrait-default-generics.rs
Normal file
@ -0,0 +1,42 @@
|
||||
// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
// There is some other borrowck bug, so we make the stuff not mut.
|
||||
|
||||
trait Positioned<S> {
|
||||
fn SetX(&mut self, S);
|
||||
fn X(&self) -> S;
|
||||
}
|
||||
|
||||
trait Movable<S: Add<S, S>>: Positioned<S> {
|
||||
fn translate(&mut self, dx: S) {
|
||||
let x = self.X() + dx;
|
||||
self.SetX(x);
|
||||
}
|
||||
}
|
||||
|
||||
struct Point<S> { x: S, y: S }
|
||||
|
||||
impl<S: Clone> Positioned<S> for Point<S> {
|
||||
fn SetX(&mut self, x: S) {
|
||||
self.x = x;
|
||||
}
|
||||
fn X(&self) -> S {
|
||||
self.x.clone()
|
||||
}
|
||||
}
|
||||
|
||||
impl<S: Clone + Add<S, S>> Movable<S> for Point<S>;
|
||||
|
||||
pub fn main() {
|
||||
let mut p = Point{ x: 1, y: 2};
|
||||
p.translate(3);
|
||||
assert_eq!(p.X(), 4);
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user