Get cross crate default methods working.
This fixes the large number of problems that prevented cross crate methods from ever working. It also fixes a couple lingering bugs with polymorphic default methods and cleans up some of the code paths. Closes #4102. Closes #4103.
This commit is contained in:
parent
6759ce4fd2
commit
1a8969f64b
@ -229,7 +229,7 @@ pub fn get_impl_trait(tcx: ty::ctxt,
|
||||
pub fn get_impl_method(cstore: @mut cstore::CStore,
|
||||
def: ast::def_id,
|
||||
mname: ast::ident)
|
||||
-> ast::def_id {
|
||||
-> Option<ast::def_id> {
|
||||
let cdata = cstore::get_crate_data(cstore, def.crate);
|
||||
decoder::get_impl_method(cstore.intr, cdata, def.node, mname)
|
||||
}
|
||||
|
@ -415,7 +415,7 @@ pub fn get_impl_trait(cdata: cmd,
|
||||
}
|
||||
|
||||
pub fn get_impl_method(intr: @ident_interner, cdata: cmd, id: ast::node_id,
|
||||
name: ast::ident) -> ast::def_id {
|
||||
name: ast::ident) -> Option<ast::def_id> {
|
||||
let items = reader::get_doc(reader::Doc(cdata.data), tag_items);
|
||||
let mut found = None;
|
||||
for reader::tagged_docs(find_item(id, items), tag_item_impl_method)
|
||||
@ -425,7 +425,7 @@ pub fn get_impl_method(intr: @ident_interner, cdata: cmd, id: ast::node_id,
|
||||
found = Some(translate_def_id(cdata, m_did));
|
||||
}
|
||||
}
|
||||
found.get()
|
||||
found
|
||||
}
|
||||
|
||||
pub fn get_symbol(data: @~[u8], id: ast::node_id) -> ~str {
|
||||
@ -755,40 +755,13 @@ pub fn get_provided_trait_methods(intr: @ident_interner, cdata: cmd,
|
||||
let item = lookup_item(id, data);
|
||||
let mut result = ~[];
|
||||
|
||||
for reader::tagged_docs(item, tag_item_trait_method) |mth| {
|
||||
for reader::tagged_docs(item, tag_item_trait_method) |mth_id| {
|
||||
let did = item_def_id(mth_id, cdata);
|
||||
let mth = lookup_item(did.node, data);
|
||||
|
||||
if item_method_sort(mth) != 'p' { loop; }
|
||||
|
||||
let did = item_def_id(mth, cdata);
|
||||
|
||||
let type_param_defs =
|
||||
item_ty_param_defs(mth, tcx, cdata,
|
||||
tag_items_data_item_ty_param_bounds);
|
||||
let name = item_name(intr, mth);
|
||||
let ty = doc_type(mth, tcx, cdata);
|
||||
|
||||
let fty = match ty::get(ty).sty {
|
||||
ty::ty_bare_fn(ref f) => copy *f,
|
||||
_ => {
|
||||
tcx.diag.handler().bug("get_provided_trait_methods(): id \
|
||||
has non-function type");
|
||||
}
|
||||
};
|
||||
|
||||
let transformed_self_ty = doc_transformed_self_ty(mth, tcx, cdata);
|
||||
let explicit_self = get_explicit_self(mth);
|
||||
|
||||
let ty_method = ty::Method::new(
|
||||
name,
|
||||
ty::Generics {
|
||||
type_param_defs: type_param_defs,
|
||||
region_param: None
|
||||
},
|
||||
transformed_self_ty,
|
||||
fty,
|
||||
explicit_self,
|
||||
ast::public,
|
||||
did
|
||||
);
|
||||
let ty_method = get_method(intr, cdata, did.node, tcx);
|
||||
let provided_trait_method_info = ProvidedTraitMethodInfo {
|
||||
ty: ty_method,
|
||||
def_id: did
|
||||
|
@ -42,6 +42,7 @@ use middle::trans::type_of;
|
||||
use middle::ty;
|
||||
use middle::subst::Subst;
|
||||
use middle::typeck;
|
||||
use middle::typeck::coherence::make_substs_for_receiver_types;
|
||||
use util::ppaux::Repr;
|
||||
|
||||
use core::vec;
|
||||
@ -253,50 +254,24 @@ pub fn trans_fn_ref_with_vtables(
|
||||
// So, what we need to do is find this substitution and
|
||||
// compose it with the one we already have.
|
||||
|
||||
// In order to find the substitution for the trait params,
|
||||
// we look up the impl in the ast map, find its trait_ref
|
||||
// id, then look up its trait ref. I feel like there
|
||||
// should be a better way.
|
||||
let map_node = session::expect(
|
||||
ccx.sess,
|
||||
ccx.tcx.items.find_copy(&source.impl_id.node),
|
||||
|| fmt!("couldn't find node while monomorphizing \
|
||||
default method: %?", source.impl_id.node));
|
||||
let item = match map_node {
|
||||
ast_map::node_item(item, _) => item,
|
||||
_ => ccx.tcx.sess.bug("Not an item")
|
||||
};
|
||||
let ast_trait_ref = match copy item.node {
|
||||
ast::item_impl(_, Some(tr), _, _) => tr,
|
||||
_ => ccx.tcx.sess.bug("Not an impl with trait_ref")
|
||||
};
|
||||
let trait_ref = ccx.tcx.trait_refs.get(&ast_trait_ref.ref_id);
|
||||
let trait_ref = ty::impl_trait_ref(tcx, source.impl_id)
|
||||
.expect("could not find trait_ref for impl with \
|
||||
default methods");
|
||||
let method = ty::method(tcx, source.method_id);
|
||||
|
||||
// The substs from the trait_ref only substitues for the
|
||||
// trait parameters. Our substitution also needs to be
|
||||
// able to substitute for the actual method type
|
||||
// params. To do this, we figure out how many method
|
||||
// parameters there are and pad out the substitution with
|
||||
// substitution for the variables.
|
||||
let item_ty = ty::lookup_item_type(tcx, source.method_id);
|
||||
let num_params = item_ty.generics.type_param_defs.len() -
|
||||
trait_ref.substs.tps.len();
|
||||
let id_subst = do vec::from_fn(num_params) |i| {
|
||||
ty::mk_param(tcx, i, ast::def_id {crate: 0, node: 0})
|
||||
};
|
||||
// Merge the two substitions together now.
|
||||
let first_subst = ty::substs {tps: trait_ref.substs.tps + id_subst,
|
||||
.. trait_ref.substs};
|
||||
// Compute the first substitution
|
||||
let first_subst = make_substs_for_receiver_types(
|
||||
tcx, source.impl_id, trait_ref, method);
|
||||
|
||||
// And compose them.
|
||||
// And compose them
|
||||
let new_substs = first_subst.subst(tcx, &substs);
|
||||
debug!("trans_fn_with_vtables - default method: \
|
||||
substs = %s, id_subst = %s, trait_subst = %s, \
|
||||
substs = %s, trait_subst = %s, \
|
||||
first_subst = %s, new_subst = %s",
|
||||
substs.repr(tcx),
|
||||
id_subst.repr(tcx), trait_ref.substs.repr(tcx),
|
||||
substs.repr(tcx), trait_ref.substs.repr(tcx),
|
||||
first_subst.repr(tcx), new_substs.repr(tcx));
|
||||
|
||||
|
||||
(source.method_id, Some(source.impl_id), new_substs)
|
||||
}
|
||||
};
|
||||
|
@ -93,11 +93,16 @@ pub fn maybe_instantiate_inline(ccx: @mut CrateContext, fn_id: ast::def_id,
|
||||
csearch::found(ast::ii_method(impl_did, mth)) => {
|
||||
ccx.stats.n_inlines += 1;
|
||||
ccx.external.insert(fn_id, Some(mth.id));
|
||||
let impl_tpt = ty::lookup_item_type(ccx.tcx, impl_did);
|
||||
let num_type_params =
|
||||
impl_tpt.generics.type_param_defs.len() +
|
||||
mth.generics.ty_params.len();
|
||||
if translate && num_type_params == 0 {
|
||||
// If this is a default method, we can't look up the
|
||||
// impl type. But we aren't going to translate anyways, so don't.
|
||||
if !translate { return local_def(mth.id); }
|
||||
|
||||
let impl_tpt = ty::lookup_item_type(ccx.tcx, impl_did);
|
||||
let num_type_params =
|
||||
impl_tpt.generics.type_param_defs.len() +
|
||||
mth.generics.ty_params.len();
|
||||
|
||||
if num_type_params == 0 {
|
||||
let llfn = get_item_val(ccx, mth.id);
|
||||
let path = vec::append(
|
||||
ty::item_path(ccx.tcx, impl_did),
|
||||
|
@ -383,71 +383,48 @@ pub fn method_with_name_or_default(ccx: @mut CrateContext,
|
||||
name: ast::ident) -> ast::def_id {
|
||||
let imp = ccx.impl_method_cache.find_copy(&(impl_id, name));
|
||||
match imp {
|
||||
Some(m) => m,
|
||||
None => {
|
||||
let imp = if impl_id.crate == ast::local_crate {
|
||||
match ccx.tcx.items.get_copy(&impl_id.node) {
|
||||
ast_map::node_item(@ast::item {
|
||||
node: ast::item_impl(_, _, _, ref ms), _
|
||||
}, _) => {
|
||||
let did = method_from_methods(*ms, name);
|
||||
if did.is_some() {
|
||||
did.get()
|
||||
} else {
|
||||
// Look for a default method
|
||||
let pmm = ccx.tcx.provided_methods;
|
||||
match pmm.find(&impl_id) {
|
||||
Some(pmis) => {
|
||||
for pmis.each |pmi| {
|
||||
if pmi.method_info.ident == name {
|
||||
debug!("pmi.method_info.did = %?", pmi.method_info.did);
|
||||
return pmi.method_info.did;
|
||||
}
|
||||
}
|
||||
fail!()
|
||||
}
|
||||
None => fail!()
|
||||
}
|
||||
}
|
||||
Some(m) => return m,
|
||||
None => {}
|
||||
}
|
||||
|
||||
// None of this feels like it should be the best way to do this.
|
||||
let mut did = if impl_id.crate == ast::local_crate {
|
||||
match ccx.tcx.items.get_copy(&impl_id.node) {
|
||||
ast_map::node_item(@ast::item {
|
||||
node: ast::item_impl(_, _, _, ref ms), _
|
||||
}, _) => { method_from_methods(*ms, name) },
|
||||
_ => fail!("method_with_name")
|
||||
}
|
||||
} else {
|
||||
csearch::get_impl_method(ccx.sess.cstore, impl_id, name)
|
||||
};
|
||||
|
||||
if did.is_none() {
|
||||
// Look for a default method
|
||||
let pmm = ccx.tcx.provided_methods;
|
||||
match pmm.find(&impl_id) {
|
||||
Some(pmis) => {
|
||||
for pmis.each |pmi| {
|
||||
if pmi.method_info.ident == name {
|
||||
debug!("pmi.method_info.did = %?",
|
||||
pmi.method_info.did);
|
||||
did = Some(pmi.method_info.did);
|
||||
}
|
||||
_ => fail!("method_with_name")
|
||||
}
|
||||
} else {
|
||||
csearch::get_impl_method(ccx.sess.cstore, impl_id, name)
|
||||
};
|
||||
|
||||
ccx.impl_method_cache.insert((impl_id, name), imp);
|
||||
|
||||
imp
|
||||
}
|
||||
None => {}
|
||||
}
|
||||
}
|
||||
|
||||
let imp = did.expect("could not find method while translating");
|
||||
ccx.impl_method_cache.insert((impl_id, name), imp);
|
||||
imp
|
||||
}
|
||||
|
||||
pub fn method_ty_param_count(ccx: &CrateContext, m_id: ast::def_id,
|
||||
i_id: ast::def_id) -> uint {
|
||||
debug!("method_ty_param_count: m_id: %?, i_id: %?", m_id, i_id);
|
||||
if m_id.crate == ast::local_crate {
|
||||
match ccx.tcx.items.find(&m_id.node) {
|
||||
Some(&ast_map::node_method(m, _, _)) => m.generics.ty_params.len(),
|
||||
None => {
|
||||
match ccx.tcx.provided_method_sources.find(&m_id) {
|
||||
Some(source) => {
|
||||
method_ty_param_count(
|
||||
ccx, source.method_id, source.impl_id)
|
||||
}
|
||||
None => fail!()
|
||||
}
|
||||
}
|
||||
Some(&ast_map::node_trait_method(@ast::provided(@ref m),
|
||||
_, _)) => {
|
||||
m.generics.ty_params.len()
|
||||
}
|
||||
ref e => fail!("method_ty_param_count %?", *e)
|
||||
}
|
||||
} else {
|
||||
csearch::get_type_param_count(ccx.sess.cstore, m_id) -
|
||||
csearch::get_type_param_count(ccx.sess.cstore, i_id)
|
||||
}
|
||||
ty::method(ccx.tcx, m_id).generics.type_param_defs.len()
|
||||
}
|
||||
|
||||
pub fn trans_monomorphized_callee(bcx: block,
|
||||
|
@ -541,6 +541,10 @@ impl<'self> LookupContext<'self> {
|
||||
if !self.impl_dups.insert(impl_info.did) {
|
||||
return; // already visited
|
||||
}
|
||||
debug!("push_candidates_from_impl: %s %s %s",
|
||||
self.m_name.repr(self.tcx()),
|
||||
impl_info.ident.repr(self.tcx()),
|
||||
impl_info.methods.map(|m| m.ident).repr(self.tcx()));
|
||||
|
||||
let idx = {
|
||||
match impl_info.methods.position(|m| m.ident == self.m_name) {
|
||||
|
@ -279,7 +279,7 @@ impl CoherenceChecker {
|
||||
trait_ref.repr(self.crate_context.tcx),
|
||||
self.crate_context.tcx.sess.str_of(item.ident));
|
||||
|
||||
self.instantiate_default_methods(item.id, trait_ref);
|
||||
self.instantiate_default_methods(local_def(item.id), trait_ref);
|
||||
|
||||
let implementation;
|
||||
if implementation_opt.is_none() {
|
||||
@ -327,13 +327,13 @@ impl CoherenceChecker {
|
||||
// and trait pair. Then, for each provided method in the trait, inserts a
|
||||
// `ProvidedMethodInfo` instance into the `provided_method_sources` map.
|
||||
pub fn instantiate_default_methods(&self,
|
||||
impl_id: ast::node_id,
|
||||
impl_id: ast::def_id,
|
||||
trait_ref: &ty::TraitRef) {
|
||||
let tcx = self.crate_context.tcx;
|
||||
debug!("instantiate_default_methods(impl_id=%?, trait_ref=%s)",
|
||||
impl_id, trait_ref.repr(tcx));
|
||||
|
||||
let impl_poly_type = ty::lookup_item_type(tcx, local_def(impl_id));
|
||||
let impl_poly_type = ty::lookup_item_type(tcx, impl_id);
|
||||
|
||||
for self.each_provided_trait_method(trait_ref.def_id) |trait_method| {
|
||||
// Synthesize an ID.
|
||||
@ -375,7 +375,7 @@ impl CoherenceChecker {
|
||||
// ID of the method.
|
||||
let source = ProvidedMethodSource {
|
||||
method_id: trait_method.def_id,
|
||||
impl_id: local_def(impl_id)
|
||||
impl_id: impl_id
|
||||
};
|
||||
|
||||
self.crate_context.tcx.provided_method_sources.insert(new_did,
|
||||
@ -393,7 +393,7 @@ impl CoherenceChecker {
|
||||
};
|
||||
|
||||
let pmm = self.crate_context.tcx.provided_methods;
|
||||
match pmm.find(&local_def(impl_id)) {
|
||||
match pmm.find(&impl_id) {
|
||||
Some(&mis) => {
|
||||
// If the trait already has an entry in the
|
||||
// provided_methods_map, we just need to add this
|
||||
@ -410,7 +410,7 @@ impl CoherenceChecker {
|
||||
for method `%s`",
|
||||
self.crate_context.tcx.sess.str_of(
|
||||
provided_method_info.method_info.ident));
|
||||
pmm.insert(local_def(impl_id),
|
||||
pmm.insert(impl_id,
|
||||
@mut ~[provided_method_info]);
|
||||
}
|
||||
}
|
||||
@ -733,10 +733,12 @@ impl CoherenceChecker {
|
||||
}
|
||||
// Default methods
|
||||
for ty::provided_trait_methods(tcx, trait_did).each |ident| {
|
||||
debug!("inserting provided method %s", ident.repr(tcx));
|
||||
provided_names.insert(*ident);
|
||||
}
|
||||
|
||||
for (*ty::trait_methods(tcx, trait_did)).each |method| {
|
||||
debug!("checking for %s", method.ident.repr(tcx));
|
||||
if provided_names.contains(&method.ident) { loop; }
|
||||
|
||||
tcx.sess.span_err(trait_ref_span,
|
||||
@ -785,19 +787,41 @@ impl CoherenceChecker {
|
||||
}
|
||||
}
|
||||
|
||||
fn add_provided_methods_to_impl(
|
||||
&self,
|
||||
all_methods: &mut ~[@MethodInfo],
|
||||
trait_did: &ast::def_id,
|
||||
impl_id: &ast::def_id) {
|
||||
|
||||
|
||||
match self.crate_context.tcx
|
||||
.provided_methods
|
||||
.find(impl_id) {
|
||||
None => {
|
||||
debug!("(creating impl) trait with node_id `%d` \
|
||||
has no provided methods", trait_did.node);
|
||||
/* fall through */
|
||||
}
|
||||
Some(&all_provided_methods) => {
|
||||
debug!("(creating impl) trait with node_id `%d` \
|
||||
has provided methods", trait_did.node);
|
||||
// Add all provided methods.
|
||||
for all_provided_methods.each |provided_method| {
|
||||
debug!(
|
||||
"(creating impl) adding provided method \
|
||||
`%s` to impl",
|
||||
provided_method.method_info
|
||||
.ident.repr(self.crate_context.tcx));
|
||||
vec::push(all_methods, provided_method.method_info);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
// Converts an implementation in the AST to an Impl structure.
|
||||
pub fn create_impl_from_item(&self, item: @item) -> @Impl {
|
||||
fn add_provided_methods(all_methods: &mut ~[@MethodInfo],
|
||||
all_provided_methods: &mut ~[@ProvidedMethodInfo],
|
||||
sess: driver::session::Session) {
|
||||
for all_provided_methods.each |provided_method| {
|
||||
debug!(
|
||||
"(creating impl) adding provided method `%s` to impl",
|
||||
sess.str_of(provided_method.method_info.ident));
|
||||
vec::push(all_methods, provided_method.method_info);
|
||||
}
|
||||
}
|
||||
|
||||
match item.node {
|
||||
item_impl(_, ref trait_refs, _, ref ast_methods) => {
|
||||
let mut methods = ~[];
|
||||
@ -820,27 +844,11 @@ impl CoherenceChecker {
|
||||
// if a method of that name is not inherent to the
|
||||
// impl, use the provided definition in the trait.
|
||||
for trait_refs.iter().advance |trait_ref| {
|
||||
let trait_did =
|
||||
self.trait_ref_to_trait_def_id(*trait_ref);
|
||||
|
||||
match self.crate_context.tcx
|
||||
.provided_methods
|
||||
.find(&local_def(item.id)) {
|
||||
None => {
|
||||
debug!("(creating impl) trait with node_id `%d` \
|
||||
has no provided methods", trait_did.node);
|
||||
/* fall through */
|
||||
}
|
||||
Some(&all_provided) => {
|
||||
debug!("(creating impl) trait with node_id `%d` \
|
||||
has provided methods", trait_did.node);
|
||||
// Add all provided methods.
|
||||
add_provided_methods(
|
||||
&mut methods,
|
||||
all_provided,
|
||||
self.crate_context.tcx.sess);
|
||||
}
|
||||
}
|
||||
let trait_did = self.trait_ref_to_trait_def_id(*trait_ref);
|
||||
self.add_provided_methods_to_impl(
|
||||
&mut methods,
|
||||
&trait_did,
|
||||
&local_def(item.id));
|
||||
}
|
||||
|
||||
return @Impl {
|
||||
@ -917,9 +925,23 @@ impl CoherenceChecker {
|
||||
}
|
||||
}
|
||||
|
||||
let mut implementation = *implementation;
|
||||
|
||||
// Record all the trait methods.
|
||||
for associated_traits.iter().advance |trait_ref| {
|
||||
self.add_trait_method(trait_ref.def_id, *implementation);
|
||||
self.instantiate_default_methods(implementation.did,
|
||||
&**trait_ref);
|
||||
// Could we avoid these copies when we don't need them?
|
||||
let mut methods = /*bad?*/ copy implementation.methods;
|
||||
self.add_provided_methods_to_impl(
|
||||
&mut methods,
|
||||
&trait_ref.def_id,
|
||||
&implementation.did);
|
||||
implementation = @Impl { methods: methods,
|
||||
.. *implementation };
|
||||
|
||||
|
||||
self.add_trait_method(trait_ref.def_id, implementation);
|
||||
}
|
||||
|
||||
// Add the implementation to the mapping from
|
||||
@ -937,7 +959,7 @@ impl CoherenceChecker {
|
||||
// `impl Trait for Type`:
|
||||
if associated_traits.is_none() {
|
||||
self.add_inherent_method(base_type_def_id,
|
||||
*implementation);
|
||||
implementation);
|
||||
}
|
||||
|
||||
self.base_type_def_ids.insert(implementation.did,
|
||||
@ -947,38 +969,6 @@ impl CoherenceChecker {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn add_default_methods_for_external_trait(&self,
|
||||
trait_def_id: ast::def_id) {
|
||||
let tcx = self.crate_context.tcx;
|
||||
let pmm = tcx.provided_methods;
|
||||
|
||||
if pmm.contains_key(&trait_def_id) { return; }
|
||||
|
||||
debug!("(adding default methods for trait) processing trait");
|
||||
|
||||
for csearch::get_provided_trait_methods(tcx, trait_def_id).each
|
||||
|trait_method_info| {
|
||||
debug!("(adding default methods for trait) found default method");
|
||||
|
||||
// Create a new def ID for this provided method.
|
||||
let parse_sess = &self.crate_context.tcx.sess.parse_sess;
|
||||
let new_did = local_def(parse::next_node_id(*parse_sess));
|
||||
|
||||
let provided_method_info =
|
||||
@ProvidedMethodInfo {
|
||||
method_info: @MethodInfo {
|
||||
did: new_did,
|
||||
n_tps: trait_method_info.ty.generics.type_param_defs.len(),
|
||||
ident: trait_method_info.ty.ident,
|
||||
explicit_self: trait_method_info.ty.explicit_self
|
||||
},
|
||||
trait_method_def_id: trait_method_info.def_id
|
||||
};
|
||||
|
||||
pmm.insert(trait_def_id, @mut ~[provided_method_info]);
|
||||
}
|
||||
}
|
||||
|
||||
// Adds implementations and traits from external crates to the coherence
|
||||
// info.
|
||||
pub fn add_external_crates(&self) {
|
||||
@ -998,9 +988,6 @@ impl CoherenceChecker {
|
||||
crate_store,
|
||||
def_id);
|
||||
}
|
||||
dl_def(def_trait(def_id)) => {
|
||||
self.add_default_methods_for_external_trait(def_id);
|
||||
}
|
||||
dl_def(_) | dl_impl(_) | dl_field => {
|
||||
// Skip this.
|
||||
loop;
|
||||
@ -1063,12 +1050,11 @@ impl CoherenceChecker {
|
||||
}
|
||||
}
|
||||
|
||||
fn subst_receiver_types_in_method_ty(tcx: ty::ctxt,
|
||||
impl_id: ast::node_id,
|
||||
trait_ref: &ty::TraitRef,
|
||||
new_def_id: ast::def_id,
|
||||
method: &ty::Method)
|
||||
-> ty::Method {
|
||||
pub fn make_substs_for_receiver_types(tcx: ty::ctxt,
|
||||
impl_id: ast::def_id,
|
||||
trait_ref: &ty::TraitRef,
|
||||
method: &ty::Method)
|
||||
-> ty::substs {
|
||||
/*!
|
||||
* Substitutes the values for the receiver's type parameters
|
||||
* that are found in method, leaving the method's type parameters
|
||||
@ -1079,7 +1065,7 @@ fn subst_receiver_types_in_method_ty(tcx: ty::ctxt,
|
||||
|
||||
// determine how many type parameters were declared on the impl
|
||||
let num_impl_type_parameters = {
|
||||
let impl_polytype = ty::lookup_item_type(tcx, local_def(impl_id));
|
||||
let impl_polytype = ty::lookup_item_type(tcx, impl_id);
|
||||
impl_polytype.generics.type_param_defs.len()
|
||||
};
|
||||
|
||||
@ -1105,11 +1091,22 @@ fn subst_receiver_types_in_method_ty(tcx: ty::ctxt,
|
||||
}
|
||||
});
|
||||
|
||||
let combined_substs = ty::substs {
|
||||
return ty::substs {
|
||||
self_r: trait_ref.substs.self_r,
|
||||
self_ty: trait_ref.substs.self_ty,
|
||||
tps: combined_tps
|
||||
};
|
||||
}
|
||||
|
||||
fn subst_receiver_types_in_method_ty(tcx: ty::ctxt,
|
||||
impl_id: ast::def_id,
|
||||
trait_ref: &ty::TraitRef,
|
||||
new_def_id: ast::def_id,
|
||||
method: &ty::Method)
|
||||
-> ty::Method {
|
||||
|
||||
let combined_substs = make_substs_for_receiver_types(
|
||||
tcx, impl_id, trait_ref, method);
|
||||
|
||||
ty::Method::new(
|
||||
method.ident,
|
||||
|
34
src/test/auxiliary/trait_default_method_xc_aux.rs
Normal file
34
src/test/auxiliary/trait_default_method_xc_aux.rs
Normal file
@ -0,0 +1,34 @@
|
||||
#[allow(default_methods)];
|
||||
|
||||
pub trait A {
|
||||
fn f(&self) -> int;
|
||||
fn g(&self) -> int { 10 }
|
||||
fn h(&self) -> int { 10 }
|
||||
}
|
||||
|
||||
|
||||
impl A for int {
|
||||
fn f(&self) -> int { 10 }
|
||||
}
|
||||
|
||||
trait B<T> {
|
||||
fn thing<U>(&self, x: T, y: U) -> (T, U) { (x, y) }
|
||||
}
|
||||
|
||||
impl<T> B<T> for int { }
|
||||
impl B<float> for bool { }
|
||||
|
||||
|
||||
|
||||
pub trait TestEquality {
|
||||
fn test_eq(&self, rhs: &Self) -> bool;
|
||||
fn test_neq(&self, rhs: &Self) -> bool {
|
||||
!self.test_eq(rhs)
|
||||
}
|
||||
}
|
||||
|
||||
impl TestEquality for int {
|
||||
fn test_eq(&self, rhs: &int) -> bool {
|
||||
*self == *rhs
|
||||
}
|
||||
}
|
@ -15,6 +15,7 @@ trait A<T> {
|
||||
}
|
||||
|
||||
impl A<int> for int { }
|
||||
impl<T> A<T> for uint { }
|
||||
|
||||
fn f<T, U, V: A<T>>(i: V, j: T, k: U) -> (T, U) {
|
||||
i.g(j, k)
|
||||
@ -22,4 +23,5 @@ fn f<T, U, V: A<T>>(i: V, j: T, k: U) -> (T, U) {
|
||||
|
||||
pub fn main () {
|
||||
assert_eq!(f(0, 1, 2), (1, 2));
|
||||
assert_eq!(f(0u, 1, 2), (1, 2));
|
||||
}
|
||||
|
71
src/test/run-pass/trait-default-method-xc.rs
Normal file
71
src/test/run-pass/trait-default-method-xc.rs
Normal file
@ -0,0 +1,71 @@
|
||||
// xfail-fast
|
||||
// aux-build:trait_default_method_xc_aux.rs
|
||||
|
||||
#[allow(default_methods)];
|
||||
|
||||
extern mod aux(name = "trait_default_method_xc_aux");
|
||||
use aux::{A, B, TestEquality};
|
||||
|
||||
|
||||
fn f<T: aux::A>(i: T) {
|
||||
assert_eq!(i.g(), 10);
|
||||
}
|
||||
|
||||
|
||||
pub struct thing { x: int }
|
||||
impl A for thing {
|
||||
fn f(&self) -> int { 10 }
|
||||
}
|
||||
|
||||
fn g<T, U, V: B<T>>(i: V, j: T, k: U) -> (T, U) {
|
||||
i.thing(j, k)
|
||||
}
|
||||
|
||||
fn eq<T: TestEquality>(lhs: &T, rhs: &T) -> bool {
|
||||
lhs.test_eq(rhs)
|
||||
}
|
||||
fn neq<T: TestEquality>(lhs: &T, rhs: &T) -> bool {
|
||||
lhs.test_neq(rhs)
|
||||
}
|
||||
|
||||
|
||||
impl TestEquality for thing {
|
||||
fn test_eq(&self, rhs: &thing) -> bool {
|
||||
//self.x.test_eq(&rhs.x)
|
||||
eq(&self.x, &rhs.x)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
fn main () {
|
||||
// Some tests of random things
|
||||
f(0);
|
||||
|
||||
let a = thing { x: 0 };
|
||||
let b = thing { x: 1 };
|
||||
|
||||
assert_eq!(0i.g(), 10);
|
||||
assert_eq!(a.g(), 10);
|
||||
assert_eq!(a.h(), 10);
|
||||
|
||||
|
||||
assert_eq!(0i.thing(3.14, 1), (3.14, 1));
|
||||
|
||||
assert_eq!(g(0i, 3.14, 1), (3.14, 1));
|
||||
assert_eq!(g(false, 3.14, 1), (3.14, 1));
|
||||
|
||||
let obj = @0i as @A;
|
||||
assert_eq!(obj.h(), 10);
|
||||
|
||||
|
||||
// Trying out a real one
|
||||
assert!(12.test_neq(&10));
|
||||
assert!(!10.test_neq(&10));
|
||||
assert!(a.test_neq(&b));
|
||||
assert!(!a.test_neq(&a));
|
||||
|
||||
assert!(neq(&12, &10));
|
||||
assert!(!neq(&10, &10));
|
||||
assert!(neq(&a, &b));
|
||||
assert!(!neq(&a, &a));
|
||||
}
|
Loading…
Reference in New Issue
Block a user