about summary refs log tree commit diff
diff options
context:
space:
mode:
authorMichael Sullivan <sully@msully.net>2013-06-12 14:22:17 -0700
committerMichael Sullivan <sully@msully.net>2013-06-20 15:42:16 -0700
commit1a8969f64be0a7e7a2cd61f04d6c4d94abe35c75 (patch)
tree2dd808aae1099d69578f601eb566ee91a3ce0e10
parent6759ce4fd2083595193c93c3fd72383d24a73a5e (diff)
downloadrust-1a8969f64be0a7e7a2cd61f04d6c4d94abe35c75.tar.gz
rust-1a8969f64be0a7e7a2cd61f04d6c4d94abe35c75.zip
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.
-rw-r--r--src/librustc/metadata/csearch.rs2
-rw-r--r--src/librustc/metadata/decoder.rs41
-rw-r--r--src/librustc/middle/trans/callee.rs51
-rw-r--r--src/librustc/middle/trans/inline.rs15
-rw-r--r--src/librustc/middle/trans/meth.rs89
-rw-r--r--src/librustc/middle/typeck/check/method.rs4
-rw-r--r--src/librustc/middle/typeck/coherence.rs163
-rw-r--r--src/test/auxiliary/trait_default_method_xc_aux.rs34
-rw-r--r--src/test/run-pass/trait-default-method-bound-subst.rs2
-rw-r--r--src/test/run-pass/trait-default-method-xc.rs71
10 files changed, 255 insertions, 217 deletions
diff --git a/src/librustc/metadata/csearch.rs b/src/librustc/metadata/csearch.rs
index 5b154f6836c..e1cd7caa19c 100644
--- a/src/librustc/metadata/csearch.rs
+++ b/src/librustc/metadata/csearch.rs
@@ -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)
 }
diff --git a/src/librustc/metadata/decoder.rs b/src/librustc/metadata/decoder.rs
index fdef25b5e71..7f06953663b 100644
--- a/src/librustc/metadata/decoder.rs
+++ b/src/librustc/metadata/decoder.rs
@@ -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| {
-        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);
+    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);
 
-        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");
-            }
-        };
+        if item_method_sort(mth) != 'p' { loop; }
 
-        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
diff --git a/src/librustc/middle/trans/callee.rs b/src/librustc/middle/trans/callee.rs
index bfbe078c4f5..7fab21b4156 100644
--- a/src/librustc/middle/trans/callee.rs
+++ b/src/librustc/middle/trans/callee.rs
@@ -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);
-
-            // 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};
+            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);
 
-            // And compose them.
+            // Compute the first substitution
+            let first_subst = make_substs_for_receiver_types(
+                tcx, source.impl_id, trait_ref, method);
+
+            // 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)
         }
     };
diff --git a/src/librustc/middle/trans/inline.rs b/src/librustc/middle/trans/inline.rs
index b0aedbae79b..00afece9197 100644
--- a/src/librustc/middle/trans/inline.rs
+++ b/src/librustc/middle/trans/inline.rs
@@ -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),
diff --git a/src/librustc/middle/trans/meth.rs b/src/librustc/middle/trans/meth.rs
index c59b3f36779..bd79cb1cfeb 100644
--- a/src/librustc/middle/trans/meth.rs
+++ b/src/librustc/middle/trans/meth.rs
@@ -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!()
-                            }
-                        }
-                    }
-                    _ => fail!("method_with_name")
-                }
-            } else {
-                csearch::get_impl_method(ccx.sess.cstore, impl_id, name)
-            };
+        Some(m) => return m,
+        None => {}
+    }
 
-            ccx.impl_method_cache.insert((impl_id, name), imp);
+    // 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)
+    };
 
-            imp
+    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);
+                    }
+                }
+            }
+            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,
diff --git a/src/librustc/middle/typeck/check/method.rs b/src/librustc/middle/typeck/check/method.rs
index b2c9d27241d..7fc1728a720 100644
--- a/src/librustc/middle/typeck/check/method.rs
+++ b/src/librustc/middle/typeck/check/method.rs
@@ -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) {
diff --git a/src/librustc/middle/typeck/coherence.rs b/src/librustc/middle/typeck/coherence.rs
index 9528c825fbe..d404ac39a15 100644
--- a/src/librustc/middle/typeck/coherence.rs
+++ b/src/librustc/middle/typeck/coherence.rs
@@ -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 {
         }
     }
 
-    // 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);
+    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 {
         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,
diff --git a/src/test/auxiliary/trait_default_method_xc_aux.rs b/src/test/auxiliary/trait_default_method_xc_aux.rs
new file mode 100644
index 00000000000..5ee243179df
--- /dev/null
+++ b/src/test/auxiliary/trait_default_method_xc_aux.rs
@@ -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
+    }
+}
diff --git a/src/test/run-pass/trait-default-method-bound-subst.rs b/src/test/run-pass/trait-default-method-bound-subst.rs
index adabafc082a..9dbbcee0f77 100644
--- a/src/test/run-pass/trait-default-method-bound-subst.rs
+++ b/src/test/run-pass/trait-default-method-bound-subst.rs
@@ -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));
 }
diff --git a/src/test/run-pass/trait-default-method-xc.rs b/src/test/run-pass/trait-default-method-xc.rs
new file mode 100644
index 00000000000..e6e5b8605a1
--- /dev/null
+++ b/src/test/run-pass/trait-default-method-xc.rs
@@ -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));
+}