about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--src/librustc/middle/astencode.rs185
-rw-r--r--src/librustc/middle/check_const.rs11
-rw-r--r--src/librustc/middle/dead.rs38
-rw-r--r--src/librustc/middle/effect.rs2
-rw-r--r--src/librustc/middle/expr_use_visitor.rs66
-rw-r--r--src/librustc/middle/infer/mod.rs9
-rw-r--r--src/librustc/middle/liveness.rs2
-rw-r--r--src/librustc/middle/reachable.rs7
-rw-r--r--src/librustc/middle/stability.rs26
-rw-r--r--src/librustc/middle/subst.rs16
-rw-r--r--src/librustc/middle/traits/mod.rs8
-rw-r--r--src/librustc/middle/traits/project.rs10
-rw-r--r--src/librustc/middle/traits/select.rs73
-rw-r--r--src/librustc/middle/traits/util.rs84
-rw-r--r--src/librustc/middle/ty.rs79
-rw-r--r--src/librustc/middle/ty_fold.rs30
-rw-r--r--src/librustc/util/ppaux.rs32
-rw-r--r--src/librustc_lint/builtin.rs149
-rw-r--r--src/librustc_privacy/lib.rs36
-rw-r--r--src/librustc_trans/save/dump_csv.rs42
-rw-r--r--src/librustc_trans/trans/callee.rs167
-rw-r--r--src/librustc_trans/trans/closure.rs13
-rw-r--r--src/librustc_trans/trans/common.rs3
-rw-r--r--src/librustc_trans/trans/consts.rs5
-rw-r--r--src/librustc_trans/trans/expr.rs28
-rw-r--r--src/librustc_trans/trans/meth.rs214
-rw-r--r--src/librustc_trans/trans/monomorphize.rs8
-rw-r--r--src/librustc_typeck/check/method/confirm.rs74
-rw-r--r--src/librustc_typeck/check/method/mod.rs38
-rw-r--r--src/librustc_typeck/check/method/probe.rs268
-rw-r--r--src/librustc_typeck/check/method/suggest.rs2
-rw-r--r--src/librustc_typeck/check/writeback.rs4
-rw-r--r--src/test/run-pass/traits-issue-26339.rs40
33 files changed, 591 insertions, 1178 deletions
diff --git a/src/librustc/middle/astencode.rs b/src/librustc/middle/astencode.rs
index 03e5ac5c381..7c76f4fe289 100644
--- a/src/librustc/middle/astencode.rs
+++ b/src/librustc/middle/astencode.rs
@@ -29,7 +29,7 @@ use middle::check_const::ConstQualif;
 use middle::privacy::{AllPublic, LastMod};
 use middle::subst;
 use middle::subst::VecPerParamSpace;
-use middle::ty::{self, Ty, MethodCall, MethodCallee, MethodOrigin};
+use middle::ty::{self, Ty};
 
 use syntax::{ast, ast_util, codemap, fold};
 use syntax::codemap::Span;
@@ -600,21 +600,21 @@ impl tr for ty::UpvarCapture {
 
 trait read_method_callee_helper<'tcx> {
     fn read_method_callee<'a, 'b>(&mut self, dcx: &DecodeContext<'a, 'b, 'tcx>)
-                                  -> (u32, MethodCallee<'tcx>);
+                                  -> (u32, ty::MethodCallee<'tcx>);
 }
 
 fn encode_method_callee<'a, 'tcx>(ecx: &e::EncodeContext<'a, 'tcx>,
                                   rbml_w: &mut Encoder,
                                   autoderef: u32,
-                                  method: &MethodCallee<'tcx>) {
+                                  method: &ty::MethodCallee<'tcx>) {
     use serialize::Encoder;
 
     rbml_w.emit_struct("MethodCallee", 4, |rbml_w| {
         rbml_w.emit_struct_field("autoderef", 0, |rbml_w| {
             autoderef.encode(rbml_w)
         });
-        rbml_w.emit_struct_field("origin", 1, |rbml_w| {
-            Ok(rbml_w.emit_method_origin(ecx, &method.origin))
+        rbml_w.emit_struct_field("def_id", 1, |rbml_w| {
+            Ok(rbml_w.emit_def_id(method.def_id))
         });
         rbml_w.emit_struct_field("ty", 2, |rbml_w| {
             Ok(rbml_w.emit_ty(ecx, method.ty))
@@ -627,21 +627,20 @@ fn encode_method_callee<'a, 'tcx>(ecx: &e::EncodeContext<'a, 'tcx>,
 
 impl<'a, 'tcx> read_method_callee_helper<'tcx> for reader::Decoder<'a> {
     fn read_method_callee<'b, 'c>(&mut self, dcx: &DecodeContext<'b, 'c, 'tcx>)
-                                  -> (u32, MethodCallee<'tcx>) {
+                                  -> (u32, ty::MethodCallee<'tcx>) {
 
         self.read_struct("MethodCallee", 4, |this| {
-            let autoderef = this.read_struct_field("autoderef", 0, |this| {
-                Decodable::decode(this)
-            }).unwrap();
-            Ok((autoderef, MethodCallee {
-                origin: this.read_struct_field("origin", 1, |this| {
-                    Ok(this.read_method_origin(dcx))
+            let autoderef = this.read_struct_field("autoderef", 0,
+                                                   Decodable::decode).unwrap();
+            Ok((autoderef, ty::MethodCallee {
+                def_id: this.read_struct_field("def_id", 1, |this| {
+                    Ok(this.read_def_id(dcx))
                 }).unwrap(),
                 ty: this.read_struct_field("ty", 2, |this| {
                     Ok(this.read_ty(dcx))
                 }).unwrap(),
                 substs: this.read_struct_field("substs", 3, |this| {
-                    Ok(this.read_substs(dcx))
+                    Ok(dcx.tcx.mk_substs(this.read_substs(dcx)))
                 }).unwrap()
             }))
         }).unwrap()
@@ -707,9 +706,6 @@ impl<'a, 'tcx> get_ty_str_ctxt<'tcx> for e::EncodeContext<'a, 'tcx> {
 trait rbml_writer_helpers<'tcx> {
     fn emit_closure_type<'a>(&mut self, ecx: &e::EncodeContext<'a, 'tcx>,
                              closure_type: &ty::ClosureTy<'tcx>);
-    fn emit_method_origin<'a>(&mut self,
-                              ecx: &e::EncodeContext<'a, 'tcx>,
-                              method_origin: &ty::MethodOrigin<'tcx>);
     fn emit_ty<'a>(&mut self, ecx: &e::EncodeContext<'a, 'tcx>, ty: Ty<'tcx>);
     fn emit_tys<'a>(&mut self, ecx: &e::EncodeContext<'a, 'tcx>, tys: &[Ty<'tcx>]);
     fn emit_type_param_def<'a>(&mut self, ecx: &e::EncodeContext<'a, 'tcx>,
@@ -741,73 +737,6 @@ impl<'a, 'tcx> rbml_writer_helpers<'tcx> for Encoder<'a> {
         });
     }
 
-    fn emit_method_origin<'b>(&mut self,
-                              ecx: &e::EncodeContext<'b, 'tcx>,
-                              method_origin: &ty::MethodOrigin<'tcx>)
-    {
-        use serialize::Encoder;
-
-        self.emit_enum("MethodOrigin", |this| {
-            match *method_origin {
-                ty::MethodStatic(def_id) => {
-                    this.emit_enum_variant("MethodStatic", 0, 1, |this| {
-                        Ok(this.emit_def_id(def_id))
-                    })
-                }
-
-                ty::MethodStaticClosure(def_id) => {
-                    this.emit_enum_variant("MethodStaticClosure", 1, 1, |this| {
-                        Ok(this.emit_def_id(def_id))
-                    })
-                }
-
-                ty::MethodTypeParam(ref p) => {
-                    this.emit_enum_variant("MethodTypeParam", 2, 1, |this| {
-                        this.emit_struct("MethodParam", 2, |this| {
-                            try!(this.emit_struct_field("trait_ref", 0, |this| {
-                                Ok(this.emit_trait_ref(ecx, &p.trait_ref))
-                            }));
-                            try!(this.emit_struct_field("method_num", 0, |this| {
-                                this.emit_uint(p.method_num)
-                            }));
-                            try!(this.emit_struct_field("impl_def_id", 0, |this| {
-                                this.emit_option(|this| {
-                                    match p.impl_def_id {
-                                        None => this.emit_option_none(),
-                                        Some(did) => this.emit_option_some(|this| {
-                                            Ok(this.emit_def_id(did))
-                                        })
-                                    }
-                                })
-                            }));
-                            Ok(())
-                        })
-                    })
-                }
-
-                ty::MethodTraitObject(ref o) => {
-                    this.emit_enum_variant("MethodTraitObject", 3, 1, |this| {
-                        this.emit_struct("MethodObject", 2, |this| {
-                            try!(this.emit_struct_field("trait_ref", 0, |this| {
-                                Ok(this.emit_trait_ref(ecx, &o.trait_ref))
-                            }));
-                            try!(this.emit_struct_field("object_trait_id", 0, |this| {
-                                Ok(this.emit_def_id(o.object_trait_id))
-                            }));
-                            try!(this.emit_struct_field("method_num", 0, |this| {
-                                this.emit_uint(o.method_num)
-                            }));
-                            try!(this.emit_struct_field("vtable_index", 0, |this| {
-                                this.emit_uint(o.vtable_index)
-                            }));
-                            Ok(())
-                        })
-                    })
-                }
-            }
-        });
-    }
-
     fn emit_ty<'b>(&mut self, ecx: &e::EncodeContext<'b, 'tcx>, ty: Ty<'tcx>) {
         self.emit_opaque(|this| Ok(e::write_type(ecx, this, ty)));
     }
@@ -1077,7 +1006,7 @@ fn encode_side_tables_for_id(ecx: &e::EncodeContext,
         })
     }
 
-    let method_call = MethodCall::expr(id);
+    let method_call = ty::MethodCall::expr(id);
     if let Some(method) = tcx.tables.borrow().method_map.get(&method_call) {
         rbml_w.tag(c::tag_table_method_map, |rbml_w| {
             rbml_w.id(id);
@@ -1089,7 +1018,7 @@ fn encode_side_tables_for_id(ecx: &e::EncodeContext,
         match *adjustment {
             ty::AdjustDerefRef(ref adj) => {
                 for autoderef in 0..adj.autoderefs {
-                    let method_call = MethodCall::autoderef(id, autoderef as u32);
+                    let method_call = ty::MethodCall::autoderef(id, autoderef as u32);
                     if let Some(method) = tcx.tables.borrow().method_map.get(&method_call) {
                         rbml_w.tag(c::tag_table_method_map, |rbml_w| {
                             rbml_w.id(id);
@@ -1150,8 +1079,6 @@ impl<'a> doc_decoder_helpers for rbml::Doc<'a> {
 }
 
 trait rbml_decoder_decoder_helpers<'tcx> {
-    fn read_method_origin<'a, 'b>(&mut self, dcx: &DecodeContext<'a, 'b, 'tcx>)
-                                  -> ty::MethodOrigin<'tcx>;
     fn read_ty<'a, 'b>(&mut self, dcx: &DecodeContext<'a, 'b, 'tcx>) -> Ty<'tcx>;
     fn read_tys<'a, 'b>(&mut self, dcx: &DecodeContext<'a, 'b, 'tcx>) -> Vec<Ty<'tcx>>;
     fn read_trait_ref<'a, 'b>(&mut self, dcx: &DecodeContext<'a, 'b, 'tcx>)
@@ -1235,88 +1162,6 @@ impl<'a, 'tcx> rbml_decoder_decoder_helpers<'tcx> for reader::Decoder<'a> {
         }).unwrap()
     }
 
-    fn read_method_origin<'b, 'c>(&mut self, dcx: &DecodeContext<'b, 'c, 'tcx>)
-                                  -> ty::MethodOrigin<'tcx>
-    {
-        self.read_enum("MethodOrigin", |this| {
-            let variants = &["MethodStatic", "MethodStaticClosure",
-                             "MethodTypeParam", "MethodTraitObject"];
-            this.read_enum_variant(variants, |this, i| {
-                Ok(match i {
-                    0 => {
-                        let def_id = this.read_def_id(dcx);
-                        ty::MethodStatic(def_id)
-                    }
-
-                    1 => {
-                        let def_id = this.read_def_id(dcx);
-                        ty::MethodStaticClosure(def_id)
-                    }
-
-                    2 => {
-                        this.read_struct("MethodTypeParam", 2, |this| {
-                            Ok(ty::MethodTypeParam(
-                                ty::MethodParam {
-                                    trait_ref: {
-                                        this.read_struct_field("trait_ref", 0, |this| {
-                                            Ok(this.read_trait_ref(dcx))
-                                        }).unwrap()
-                                    },
-                                    method_num: {
-                                        this.read_struct_field("method_num", 1, |this| {
-                                            this.read_uint()
-                                        }).unwrap()
-                                    },
-                                    impl_def_id: {
-                                        this.read_struct_field("impl_def_id", 2, |this| {
-                                            this.read_option(|this, b| {
-                                                if b {
-                                                    Ok(Some(this.read_def_id(dcx)))
-                                                } else {
-                                                    Ok(None)
-                                                }
-                                            })
-                                        }).unwrap()
-                                    }
-                                }))
-                        }).unwrap()
-                    }
-
-                    3 => {
-                        this.read_struct("MethodTraitObject", 2, |this| {
-                            Ok(ty::MethodTraitObject(
-                                ty::MethodObject {
-                                    trait_ref: {
-                                        this.read_struct_field("trait_ref", 0, |this| {
-                                            Ok(this.read_trait_ref(dcx))
-                                        }).unwrap()
-                                    },
-                                    object_trait_id: {
-                                        this.read_struct_field("object_trait_id", 1, |this| {
-                                            Ok(this.read_def_id(dcx))
-                                        }).unwrap()
-                                    },
-                                    method_num: {
-                                        this.read_struct_field("method_num", 2, |this| {
-                                            this.read_uint()
-                                        }).unwrap()
-                                    },
-                                    vtable_index: {
-                                        this.read_struct_field("vtable_index", 3, |this| {
-                                            this.read_uint()
-                                        }).unwrap()
-                                    },
-                                }))
-                        }).unwrap()
-                    }
-
-                    _ => panic!("..")
-                })
-            })
-        }).unwrap()
-    }
-
-
     fn read_ty<'b, 'c>(&mut self, dcx: &DecodeContext<'b, 'c, 'tcx>) -> Ty<'tcx> {
         // Note: regions types embed local node ids.  In principle, we
         // should translate these node ids into the new decode
@@ -1663,7 +1508,7 @@ fn decode_side_tables(dcx: &DecodeContext,
                     }
                     c::tag_table_method_map => {
                         let (autoderef, method) = val_dsr.read_method_callee(dcx);
-                        let method_call = MethodCall {
+                        let method_call = ty::MethodCall {
                             expr_id: id,
                             autoderef: autoderef
                         };
diff --git a/src/librustc/middle/check_const.rs b/src/librustc/middle/check_const.rs
index 19b688e5ccf..b5c78340d02 100644
--- a/src/librustc/middle/check_const.rs
+++ b/src/librustc/middle/check_const.rs
@@ -696,13 +696,10 @@ fn check_expr<'a, 'tcx>(v: &mut CheckCrateVisitor<'a, 'tcx>,
             }
         }
         ast::ExprMethodCall(..) => {
-            let method_did = match v.tcx.tables.borrow().method_map[&method_call].origin {
-                ty::MethodStatic(did) => Some(did),
-                _ => None
-            };
-            let is_const = match method_did {
-                Some(did) => v.handle_const_fn_call(e, did, node_ty),
-                None => false
+            let method = v.tcx.tables.borrow().method_map[&method_call];
+            let is_const = match v.tcx.impl_or_trait_item(method.def_id).container() {
+                ty::ImplContainer(_) => v.handle_const_fn_call(e, method.def_id, node_ty),
+                ty::TraitContainer(_) => false
             };
             if !is_const {
                 v.add_qualif(ConstQualif::NOT_CONST);
diff --git a/src/librustc/middle/dead.rs b/src/librustc/middle/dead.rs
index d8ee38b8478..8d2d6889b5e 100644
--- a/src/librustc/middle/dead.rs
+++ b/src/librustc/middle/dead.rs
@@ -93,40 +93,10 @@ impl<'a, 'tcx> MarkSymbolVisitor<'a, 'tcx> {
         });
     }
 
-    fn lookup_and_handle_method(&mut self, id: ast::NodeId,
-                                span: codemap::Span) {
+    fn lookup_and_handle_method(&mut self, id: ast::NodeId) {
         let method_call = ty::MethodCall::expr(id);
-        match self.tcx.tables.borrow().method_map.get(&method_call) {
-            Some(method) => {
-                match method.origin {
-                    ty::MethodStatic(def_id) => {
-                        match self.tcx.provided_source(def_id) {
-                            Some(p_did) => self.check_def_id(p_did),
-                            None => self.check_def_id(def_id)
-                        }
-                    }
-                    ty::MethodStaticClosure(_) => {}
-                    ty::MethodTypeParam(ty::MethodParam {
-                        ref trait_ref,
-                        method_num: index,
-                        ..
-                    }) |
-                    ty::MethodTraitObject(ty::MethodObject {
-                        ref trait_ref,
-                        method_num: index,
-                        ..
-                    }) => {
-                        let trait_item = self.tcx.trait_item(trait_ref.def_id, index);
-                        self.check_def_id(trait_item.def_id());
-                    }
-                }
-            }
-            None => {
-                self.tcx.sess.span_bug(span,
-                                       "method call expression not \
-                                        in method map?!")
-            }
-        }
+        let method = self.tcx.tables.borrow().method_map[&method_call];
+        self.check_def_id(method.def_id);
     }
 
     fn handle_field_access(&mut self, lhs: &ast::Expr, name: ast::Name) {
@@ -262,7 +232,7 @@ impl<'a, 'tcx, 'v> Visitor<'v> for MarkSymbolVisitor<'a, 'tcx> {
     fn visit_expr(&mut self, expr: &ast::Expr) {
         match expr.node {
             ast::ExprMethodCall(..) => {
-                self.lookup_and_handle_method(expr.id, expr.span);
+                self.lookup_and_handle_method(expr.id);
             }
             ast::ExprField(ref lhs, ref ident) => {
                 self.handle_field_access(&**lhs, ident.node.name);
diff --git a/src/librustc/middle/effect.rs b/src/librustc/middle/effect.rs
index 1ee557eb8cc..b2a064bf86c 100644
--- a/src/librustc/middle/effect.rs
+++ b/src/librustc/middle/effect.rs
@@ -120,7 +120,7 @@ impl<'a, 'tcx, 'v> Visitor<'v> for EffectCheckVisitor<'a, 'tcx> {
         match expr.node {
             ast::ExprMethodCall(_, _, _) => {
                 let method_call = MethodCall::expr(expr.id);
-                let base_type = self.tcx.tables.borrow().method_map.get(&method_call).unwrap().ty;
+                let base_type = self.tcx.tables.borrow().method_map[&method_call].ty;
                 debug!("effect: method call case, base type is {:?}",
                         base_type);
                 if type_is_unsafe_function(base_type) {
diff --git a/src/librustc/middle/expr_use_visitor.rs b/src/librustc/middle/expr_use_visitor.rs
index 3edf0490214..0d204a823af 100644
--- a/src/librustc/middle/expr_use_visitor.rs
+++ b/src/librustc/middle/expr_use_visitor.rs
@@ -23,10 +23,7 @@ use self::OverloadedCallType::*;
 use middle::{def, region, pat_util};
 use middle::infer;
 use middle::mem_categorization as mc;
-use middle::ty::{self};
-use middle::ty::{MethodCall, MethodObject, MethodTraitObject};
-use middle::ty::{MethodOrigin, MethodParam, MethodTypeParam};
-use middle::ty::{MethodStatic, MethodStaticClosure};
+use middle::ty;
 
 use syntax::{ast, ast_util};
 use syntax::ptr::P;
@@ -229,57 +226,8 @@ impl OverloadedCallType {
 
     fn from_method_id(tcx: &ty::ctxt, method_id: ast::DefId)
                       -> OverloadedCallType {
-        let method_descriptor = match tcx.impl_or_trait_item(method_id) {
-            ty::MethodTraitItem(ref method_descriptor) => {
-                (*method_descriptor).clone()
-            }
-            _ => {
-                tcx.sess.bug("overloaded call method wasn't in method map")
-            }
-        };
-        let impl_id = match method_descriptor.container {
-            ty::TraitContainer(_) => {
-                tcx.sess.bug("statically resolved overloaded call method \
-                              belonged to a trait?!")
-            }
-            ty::ImplContainer(impl_id) => impl_id,
-        };
-        let trait_ref = match tcx.impl_trait_ref(impl_id) {
-            None => {
-                tcx.sess.bug("statically resolved overloaded call impl \
-                              didn't implement a trait?!")
-            }
-            Some(ref trait_ref) => (*trait_ref).clone(),
-        };
-        OverloadedCallType::from_trait_id(tcx, trait_ref.def_id)
-    }
-
-    fn from_closure(tcx: &ty::ctxt, closure_did: ast::DefId)
-                    -> OverloadedCallType {
-        let trait_did =
-            tcx.tables
-               .borrow()
-               .closure_kinds
-               .get(&closure_did)
-               .expect("OverloadedCallType::from_closure: didn't find closure id")
-               .trait_did(tcx);
-        OverloadedCallType::from_trait_id(tcx, trait_did)
-    }
-
-    fn from_method_origin(tcx: &ty::ctxt, origin: &MethodOrigin)
-                          -> OverloadedCallType {
-        match *origin {
-            MethodStatic(def_id) => {
-                OverloadedCallType::from_method_id(tcx, def_id)
-            }
-            MethodStaticClosure(def_id) => {
-                OverloadedCallType::from_closure(tcx, def_id)
-            }
-            MethodTypeParam(MethodParam { ref trait_ref, .. }) |
-            MethodTraitObject(MethodObject { ref trait_ref, .. }) => {
-                OverloadedCallType::from_trait_id(tcx, trait_ref.def_id)
-            }
-        }
+        let method = tcx.impl_or_trait_item(method_id);
+        OverloadedCallType::from_trait_id(tcx, method.container().id())
     }
 }
 
@@ -629,11 +577,9 @@ impl<'d,'t,'a,'tcx> ExprUseVisitor<'d,'t,'a,'tcx> {
             ty::TyError => { }
             _ => {
                 let overloaded_call_type =
-                    match self.typer.node_method_origin(MethodCall::expr(call.id)) {
-                        Some(method_origin) => {
-                            OverloadedCallType::from_method_origin(
-                                self.tcx(),
-                                &method_origin)
+                    match self.typer.node_method_id(ty::MethodCall::expr(call.id)) {
+                        Some(method_id) => {
+                            OverloadedCallType::from_method_id(self.tcx(), method_id)
                         }
                         None => {
                             self.tcx().sess.span_bug(
diff --git a/src/librustc/middle/infer/mod.rs b/src/librustc/middle/infer/mod.rs
index 34726436ff7..63f31921ec2 100644
--- a/src/librustc/middle/infer/mod.rs
+++ b/src/librustc/middle/infer/mod.rs
@@ -1327,7 +1327,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
     }
 
     pub fn node_method_ty(&self, method_call: ty::MethodCall)
-                      -> Option<Ty<'tcx>> {
+                          -> Option<Ty<'tcx>> {
         self.tables
             .borrow()
             .method_map
@@ -1336,14 +1336,13 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
             .map(|ty| self.resolve_type_vars_if_possible(&ty))
     }
 
-    pub fn node_method_origin(&self, method_call: ty::MethodCall)
-                          -> Option<ty::MethodOrigin<'tcx>>
-    {
+    pub fn node_method_id(&self, method_call: ty::MethodCall)
+                          -> Option<ast::DefId> {
         self.tables
             .borrow()
             .method_map
             .get(&method_call)
-            .map(|method| method.origin.clone())
+            .map(|method| method.def_id)
     }
 
     pub fn adjustments(&self) -> Ref<NodeMap<ty::AutoAdjustment<'tcx>>> {
diff --git a/src/librustc/middle/liveness.rs b/src/librustc/middle/liveness.rs
index 68001ae1564..37460531dbd 100644
--- a/src/librustc/middle/liveness.rs
+++ b/src/librustc/middle/liveness.rs
@@ -1148,7 +1148,7 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> {
 
           ast::ExprMethodCall(_, _, ref args) => {
             let method_call = ty::MethodCall::expr(expr.id);
-            let method_ty = self.ir.tcx.tables.borrow().method_map.get(&method_call).unwrap().ty;
+            let method_ty = self.ir.tcx.tables.borrow().method_map[&method_call].ty;
             let succ = if method_ty.fn_ret().diverges() {
                 self.s.exit_ln
             } else {
diff --git a/src/librustc/middle/reachable.rs b/src/librustc/middle/reachable.rs
index 6ea726062ca..d588f7c6070 100644
--- a/src/librustc/middle/reachable.rs
+++ b/src/librustc/middle/reachable.rs
@@ -128,8 +128,9 @@ impl<'a, 'tcx, 'v> Visitor<'v> for ReachableContext<'a, 'tcx> {
             }
             ast::ExprMethodCall(..) => {
                 let method_call = ty::MethodCall::expr(expr.id);
-                match self.tcx.tables.borrow().method_map.get(&method_call).unwrap().origin {
-                    ty::MethodStatic(def_id) => {
+                let def_id = self.tcx.tables.borrow().method_map[&method_call].def_id;
+                match self.tcx.impl_or_trait_item(def_id).container() {
+                    ty::ImplContainer(_) => {
                         if is_local(def_id) {
                             if self.def_id_represents_local_inlined_item(def_id) {
                                 self.worklist.push(def_id.node)
@@ -137,7 +138,7 @@ impl<'a, 'tcx, 'v> Visitor<'v> for ReachableContext<'a, 'tcx> {
                             self.reachable_symbols.insert(def_id.node);
                         }
                     }
-                    _ => {}
+                    ty::TraitContainer(_) => {}
                 }
             }
             _ => {}
diff --git a/src/librustc/middle/stability.rs b/src/librustc/middle/stability.rs
index e6bbae6405b..46be4b75226 100644
--- a/src/librustc/middle/stability.rs
+++ b/src/librustc/middle/stability.rs
@@ -406,31 +406,7 @@ pub fn check_expr(tcx: &ty::ctxt, e: &ast::Expr,
         ast::ExprMethodCall(i, _, _) => {
             span = i.span;
             let method_call = ty::MethodCall::expr(e.id);
-            match tcx.tables.borrow().method_map.get(&method_call) {
-                Some(method) => {
-                    match method.origin {
-                        ty::MethodStatic(def_id) => {
-                            def_id
-                        }
-                        ty::MethodStaticClosure(def_id) => {
-                            def_id
-                        }
-                        ty::MethodTypeParam(ty::MethodParam {
-                            ref trait_ref,
-                            method_num: index,
-                            ..
-                        }) |
-                        ty::MethodTraitObject(ty::MethodObject {
-                            ref trait_ref,
-                            method_num: index,
-                            ..
-                        }) => {
-                            tcx.trait_item(trait_ref.def_id, index).def_id()
-                        }
-                    }
-                }
-                None => return
-            }
+            tcx.tables.borrow().method_map[&method_call].def_id
         }
         ast::ExprField(ref base_e, ref field) => {
             span = field.span;
diff --git a/src/librustc/middle/subst.rs b/src/librustc/middle/subst.rs
index 56798ae6848..4e98ef27531 100644
--- a/src/librustc/middle/subst.rs
+++ b/src/librustc/middle/subst.rs
@@ -141,19 +141,25 @@ impl<'tcx> Substs<'tcx> {
     {
         let Substs { types, regions } = self;
         let types = types.with_vec(FnSpace, m_types);
-        let regions = regions.map(m_regions,
-                                  |r, m_regions| r.with_vec(FnSpace, m_regions));
+        let regions = regions.map(|r| r.with_vec(FnSpace, m_regions));
+        Substs { types: types, regions: regions }
+    }
+
+    pub fn method_to_trait(self) -> Substs<'tcx> {
+        let Substs { mut types, regions } = self;
+        types.truncate(FnSpace, 0);
+        let regions = regions.map(|mut r| { r.truncate(FnSpace, 0); r });
         Substs { types: types, regions: regions }
     }
 }
 
 impl RegionSubsts {
-    fn map<A, F>(self, a: A, op: F) -> RegionSubsts where
-        F: FnOnce(VecPerParamSpace<ty::Region>, A) -> VecPerParamSpace<ty::Region>,
+    fn map<F>(self, op: F) -> RegionSubsts where
+        F: FnOnce(VecPerParamSpace<ty::Region>) -> VecPerParamSpace<ty::Region>,
     {
         match self {
             ErasedRegions => ErasedRegions,
-            NonerasedRegions(r) => NonerasedRegions(op(r, a))
+            NonerasedRegions(r) => NonerasedRegions(op(r))
         }
     }
 
diff --git a/src/librustc/middle/traits/mod.rs b/src/librustc/middle/traits/mod.rs
index 5126a549887..b5f01ada7e1 100644
--- a/src/librustc/middle/traits/mod.rs
+++ b/src/librustc/middle/traits/mod.rs
@@ -291,11 +291,13 @@ pub struct VtableBuiltinData<N> {
 /// for the object type `Foo`.
 #[derive(PartialEq,Eq,Clone)]
 pub struct VtableObjectData<'tcx> {
-    /// the object type `Foo`.
-    pub object_ty: Ty<'tcx>,
-
     /// `Foo` upcast to the obligation trait. This will be some supertrait of `Foo`.
     pub upcast_trait_ref: ty::PolyTraitRef<'tcx>,
+
+    /// The vtable is formed by concatenating together the method lists of
+    /// the base object trait and all supertraits; this is the start of
+    /// `upcast_trait_ref`'s methods in that vtable.
+    pub vtable_base: usize
 }
 
 /// Creates predicate obligations from the generic bounds.
diff --git a/src/librustc/middle/traits/project.rs b/src/librustc/middle/traits/project.rs
index e5f7542aa84..e29d9646509 100644
--- a/src/librustc/middle/traits/project.rs
+++ b/src/librustc/middle/traits/project.rs
@@ -629,9 +629,10 @@ fn assemble_candidates_from_object_type<'cx,'tcx>(
     selcx: &mut SelectionContext<'cx,'tcx>,
     obligation:  &ProjectionTyObligation<'tcx>,
     obligation_trait_ref: &ty::TraitRef<'tcx>,
-    candidate_set: &mut ProjectionTyCandidateSet<'tcx>,
-    object_ty: Ty<'tcx>)
+    candidate_set: &mut ProjectionTyCandidateSet<'tcx>)
 {
+    let self_ty = obligation_trait_ref.self_ty();
+    let object_ty = selcx.infcx().shallow_resolve(self_ty);
     debug!("assemble_candidates_from_object_type(object_ty={:?})",
            object_ty);
     let data = match object_ty.sty {
@@ -684,10 +685,9 @@ fn assemble_candidates_from_impls<'cx,'tcx>(
             candidate_set.vec.push(
                 ProjectionTyCandidate::Impl(data));
         }
-        super::VtableObject(data) => {
+        super::VtableObject(_) => {
             assemble_candidates_from_object_type(
-                selcx, obligation, obligation_trait_ref, candidate_set,
-                data.object_ty);
+                selcx, obligation, obligation_trait_ref, candidate_set);
         }
         super::VtableClosure(data) => {
             candidate_set.vec.push(
diff --git a/src/librustc/middle/traits/select.rs b/src/librustc/middle/traits/select.rs
index abc300869ad..ad91f664af2 100644
--- a/src/librustc/middle/traits/select.rs
+++ b/src/librustc/middle/traits/select.rs
@@ -1362,12 +1362,21 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
             debug!("assemble_candidates_from_object_ty: poly_trait_ref={:?}",
                    poly_trait_ref);
 
-            // see whether the object trait can be upcast to the trait we are looking for
-            let upcast_trait_refs = self.upcast(poly_trait_ref, obligation);
-            if upcast_trait_refs.len() > 1 {
+            // Count only those upcast versions that match the trait-ref
+            // we are looking for. Specifically, do not only check for the
+            // correct trait, but also the correct type parameters.
+            // For example, we may be trying to upcast `Foo` to `Bar<i32>`,
+            // but `Foo` is declared as `trait Foo : Bar<u32>`.
+            let upcast_trait_refs = util::supertraits(self.tcx(), poly_trait_ref)
+                .filter(|upcast_trait_ref| self.infcx.probe(|_| {
+                    let upcast_trait_ref = upcast_trait_ref.clone();
+                    self.match_poly_trait_ref(obligation, upcast_trait_ref).is_ok()
+                })).count();
+
+            if upcast_trait_refs > 1 {
                 // can be upcast in many ways; need more type information
                 candidates.ambiguous = true;
-            } else if upcast_trait_refs.len() == 1 {
+            } else if upcast_trait_refs == 1 {
                 candidates.vec.push(ObjectCandidate);
             }
 
@@ -2305,20 +2314,28 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
         // be exactly one applicable trait-reference; if this were not
         // the case, we would have reported an ambiguity error rather
         // than successfully selecting one of the candidates.
-        let upcast_trait_refs = self.upcast(poly_trait_ref.clone(), obligation);
-        assert_eq!(upcast_trait_refs.len(), 1);
-        let upcast_trait_ref = upcast_trait_refs.into_iter().next().unwrap();
+        let mut upcast_trait_refs = util::supertraits(self.tcx(), poly_trait_ref)
+            .map(|upcast_trait_ref| {
+                (upcast_trait_ref.clone(), self.infcx.probe(|_| {
+                    self.match_poly_trait_ref(obligation, upcast_trait_ref)
+                }).is_ok())
+            });
+        let mut upcast_trait_ref = None;
+        let mut vtable_base = 0;
 
-        match self.match_poly_trait_ref(obligation, upcast_trait_ref.clone()) {
-            Ok(()) => { }
-            Err(()) => {
-                self.tcx().sess.span_bug(obligation.cause.span,
-                                         "failed to match trait refs");
+        while let Some((supertrait, matches)) = upcast_trait_refs.next() {
+            if matches {
+                upcast_trait_ref = Some(supertrait);
+                break;
             }
+            vtable_base += util::count_own_vtable_entries(self.tcx(), supertrait);
         }
+        assert!(upcast_trait_refs.all(|(_, matches)| !matches));
 
-        VtableObjectData { object_ty: self_ty,
-                           upcast_trait_ref: upcast_trait_ref }
+        VtableObjectData {
+            upcast_trait_ref: upcast_trait_ref.unwrap(),
+            vtable_base: vtable_base
+        }
     }
 
     fn confirm_fn_pointer_candidate(&mut self,
@@ -2719,7 +2736,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
 
     /// Returns `Ok` if `poly_trait_ref` being true implies that the
     /// obligation is satisfied.
-    fn match_poly_trait_ref(&mut self,
+    fn match_poly_trait_ref(&self,
                             obligation: &TraitObligation<'tcx>,
                             poly_trait_ref: ty::PolyTraitRef<'tcx>)
                             -> Result<(),()>
@@ -2930,32 +2947,6 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
             obligation.cause.clone()
         }
     }
-
-    /// Upcasts an object trait-reference into those that match the obligation.
-    fn upcast(&mut self, obj_trait_ref: ty::PolyTraitRef<'tcx>, obligation: &TraitObligation<'tcx>)
-              -> Vec<ty::PolyTraitRef<'tcx>>
-    {
-        debug!("upcast(obj_trait_ref={:?}, obligation={:?})",
-               obj_trait_ref,
-               obligation);
-
-        let obligation_def_id = obligation.predicate.def_id();
-        let mut upcast_trait_refs = util::upcast(self.tcx(), obj_trait_ref, obligation_def_id);
-
-        // Retain only those upcast versions that match the trait-ref
-        // we are looking for.  In particular, we know that all of
-        // `upcast_trait_refs` apply to the correct trait, but
-        // possibly with incorrect type parameters. For example, we
-        // may be trying to upcast `Foo` to `Bar<i32>`, but `Foo` is
-        // declared as `trait Foo : Bar<u32>`.
-        upcast_trait_refs.retain(|upcast_trait_ref| {
-            let upcast_trait_ref = upcast_trait_ref.clone();
-            self.infcx.probe(|_| self.match_poly_trait_ref(obligation, upcast_trait_ref)).is_ok()
-        });
-
-        debug!("upcast: upcast_trait_refs={:?}", upcast_trait_refs);
-        upcast_trait_refs
-    }
 }
 
 impl<'tcx> SelectionCache<'tcx> {
diff --git a/src/librustc/middle/traits/util.rs b/src/librustc/middle/traits/util.rs
index 5c9a8d6c1aa..af9d5e5157d 100644
--- a/src/librustc/middle/traits/util.rs
+++ b/src/librustc/middle/traits/util.rs
@@ -396,52 +396,50 @@ pub fn upcast<'tcx>(tcx: &ty::ctxt<'tcx>,
         .collect()
 }
 
-/// Given an object of type `object_trait_ref`, returns the index of
-/// the method `n_method` found in the trait `trait_def_id` (which
-/// should be a supertrait of `object_trait_ref`) within the vtable
-/// for `object_trait_ref`.
-pub fn get_vtable_index_of_object_method<'tcx>(tcx: &ty::ctxt<'tcx>,
-                                               object_trait_ref: ty::PolyTraitRef<'tcx>,
-                                               trait_def_id: ast::DefId,
-                                               method_offset_in_trait: usize) -> usize {
-    // We need to figure the "real index" of the method in a
-    // listing of all the methods of an object. We do this by
-    // iterating down the supertraits of the object's trait until
-    // we find the trait the method came from, counting up the
-    // methods from them.
-    let mut method_count = 0;
-
-    for bound_ref in transitive_bounds(tcx, &[object_trait_ref]) {
-        if bound_ref.def_id() == trait_def_id {
-            break;
-        }
-
-        let trait_items = tcx.trait_items(bound_ref.def_id());
-        for trait_item in trait_items.iter() {
-            match *trait_item {
-                ty::MethodTraitItem(_) => method_count += 1,
-                _ => {}
-            }
+/// Given an trait `trait_ref`, returns the number of vtable entries
+/// that come from `trait_ref`, excluding its supertraits. Used in
+/// computing the vtable base for an upcast trait of a trait object.
+pub fn count_own_vtable_entries<'tcx>(tcx: &ty::ctxt<'tcx>,
+                                      trait_ref: ty::PolyTraitRef<'tcx>)
+                                      -> usize {
+    let mut entries = 0;
+    // Count number of methods and add them to the total offset.
+    // Skip over associated types and constants.
+    for trait_item in &tcx.trait_items(trait_ref.def_id())[..] {
+        if let ty::MethodTraitItem(_) = *trait_item {
+            entries += 1;
         }
     }
+    entries
+}
 
-    // count number of methods preceding the one we are selecting and
-    // add them to the total offset; skip over associated types.
-    let trait_items = tcx.trait_items(trait_def_id);
-    for trait_item in trait_items.iter().take(method_offset_in_trait) {
-        match *trait_item {
-            ty::MethodTraitItem(_) => method_count += 1,
-            _ => {}
+/// Given an upcast trait object described by `object`, returns the
+/// index of the method `method_def_id` (which should be part of
+/// `object.upcast_trait_ref`) within the vtable for `object`.
+pub fn get_vtable_index_of_object_method<'tcx>(tcx: &ty::ctxt<'tcx>,
+                                               object: &super::VtableObjectData<'tcx>,
+                                               method_def_id: ast::DefId) -> usize {
+    // Count number of methods preceding the one we are selecting and
+    // add them to the total offset.
+    // Skip over associated types and constants.
+    let mut entries = object.vtable_base;
+    for trait_item in &tcx.trait_items(object.upcast_trait_ref.def_id())[..] {
+        if trait_item.def_id() == method_def_id {
+            // The item with the ID we were given really ought to be a method.
+            assert!(match *trait_item {
+                ty::MethodTraitItem(_) => true,
+                _ => false
+            });
+
+            return entries;
+        }
+        if let ty::MethodTraitItem(_) = *trait_item {
+            entries += 1;
         }
     }
 
-    // the item at the offset we were given really ought to be a method
-    assert!(match trait_items[method_offset_in_trait] {
-        ty::MethodTraitItem(_) => true,
-        _ => false
-    });
-
-    method_count
+    tcx.sess.bug(&format!("get_vtable_index_of_object_method: {:?} was not found",
+                          method_def_id));
 }
 
 pub enum TupleArgumentsFlag { Yes, No }
@@ -490,7 +488,7 @@ impl<'tcx, N:fmt::Debug> fmt::Debug for super::Vtable<'tcx, N> {
                 write!(f, "VtableFnPointer({:?})", d),
 
             super::VtableObject(ref d) =>
-                write!(f, "VtableObject({:?})", d),
+                write!(f, "{:?}", d),
 
             super::VtableParam(ref n) =>
                 write!(f, "VtableParam({:?})", n),
@@ -535,7 +533,9 @@ impl<'tcx, N:fmt::Debug> fmt::Debug for super::VtableDefaultImplData<N> {
 
 impl<'tcx> fmt::Debug for super::VtableObjectData<'tcx> {
     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
-        write!(f, "VtableObject(object_ty={:?})", self.object_ty)
+        write!(f, "VtableObject(upcast={:?}, vtable_base={})",
+               self.upcast_trait_ref,
+               self.vtable_base)
     }
 }
 
diff --git a/src/librustc/middle/ty.rs b/src/librustc/middle/ty.rs
index 544e594dd21..715072a12eb 100644
--- a/src/librustc/middle/ty.rs
+++ b/src/librustc/middle/ty.rs
@@ -30,7 +30,6 @@ pub use self::ImplOrTraitItem::*;
 pub use self::BoundRegion::*;
 pub use self::TypeVariants::*;
 pub use self::IntVarValue::*;
-pub use self::MethodOrigin::*;
 pub use self::CopyImplementationError::*;
 
 pub use self::BuiltinBound::Send as BoundSend;
@@ -330,7 +329,7 @@ impl IntTypeExt for attr::IntType {
     }
 }
 
-#[derive(Clone, Copy, Debug)]
+#[derive(Clone, Copy, PartialEq, Eq, Debug)]
 pub enum ImplOrTraitItemContainer {
     TraitContainer(ast::DefId),
     ImplContainer(ast::DefId),
@@ -626,68 +625,12 @@ pub enum CustomCoerceUnsized {
     Struct(usize)
 }
 
-#[derive(Clone)]
-pub enum MethodOrigin<'tcx> {
-    // fully statically resolved method
-    MethodStatic(ast::DefId),
-
-    // fully statically resolved closure invocation
-    MethodStaticClosure(ast::DefId),
-
-    // method invoked on a type parameter with a bounded trait
-    MethodTypeParam(MethodParam<'tcx>),
-
-    // method invoked on a trait instance
-    MethodTraitObject(MethodObject<'tcx>),
-
-}
-
-// details for a method invoked with a receiver whose type is a type parameter
-// with a bounded trait.
-#[derive(Clone)]
-pub struct MethodParam<'tcx> {
-    // the precise trait reference that occurs as a bound -- this may
-    // be a supertrait of what the user actually typed. Note that it
-    // never contains bound regions; those regions should have been
-    // instantiated with fresh variables at this point.
-    pub trait_ref: ty::TraitRef<'tcx>,
-
-    // index of usize in the list of trait items. Note that this is NOT
-    // the index into the vtable, because the list of trait items
-    // includes associated types.
-    pub method_num: usize,
-
-    /// The impl for the trait from which the method comes. This
-    /// should only be used for certain linting/heuristic purposes
-    /// since there is no guarantee that this is Some in every
-    /// situation that it could/should be.
-    pub impl_def_id: Option<ast::DefId>,
-}
-
-// details for a method invoked with a receiver whose type is an object
-#[derive(Clone)]
-pub struct MethodObject<'tcx> {
-    // the (super)trait containing the method to be invoked
-    pub trait_ref: TraitRef<'tcx>,
-
-    // the actual base trait id of the object
-    pub object_trait_id: ast::DefId,
-
-    // index of the method to be invoked amongst the trait's items
-    pub method_num: usize,
-
-    // index into the actual runtime vtable.
-    // the vtable is formed by concatenating together the method lists of
-    // the base object trait and all supertraits; this is the index into
-    // that vtable
-    pub vtable_index: usize,
-}
-
-#[derive(Clone, Debug)]
+#[derive(Clone, Copy, Debug)]
 pub struct MethodCallee<'tcx> {
-    pub origin: MethodOrigin<'tcx>,
+    /// Impl method ID, for inherent methods, or trait method ID, otherwise.
+    pub def_id: ast::DefId,
     pub ty: Ty<'tcx>,
-    pub substs: subst::Substs<'tcx>
+    pub substs: &'tcx subst::Substs<'tcx>
 }
 
 /// With method calls, we store some extra information in
@@ -5595,11 +5538,6 @@ impl<'tcx> ctxt<'tcx> {
         }
     }
 
-    pub fn trait_item(&self, trait_did: ast::DefId, idx: usize) -> ImplOrTraitItem<'tcx> {
-        let method_def_id = self.trait_item_def_ids(trait_did)[idx].def_id();
-        self.impl_or_trait_item(method_def_id)
-    }
-
     pub fn trait_items(&self, trait_did: ast::DefId) -> Rc<Vec<ImplOrTraitItem<'tcx>>> {
         let mut trait_items = self.trait_items_cache.borrow_mut();
         match trait_items.get(&trait_did).cloned() {
@@ -6443,10 +6381,9 @@ impl<'tcx> ctxt<'tcx> {
         let name = impl_item.name();
         match self.trait_of_item(def_id) {
             Some(trait_did) => {
-                let trait_items = self.trait_items(trait_did);
-                trait_items.iter()
-                    .position(|m| m.name() == name)
-                    .map(|idx| self.trait_item(trait_did, idx).id())
+                self.trait_items(trait_did).iter()
+                    .find(|item| item.name() == name)
+                    .map(|item| item.id())
             }
             None => None
         }
diff --git a/src/librustc/middle/ty_fold.rs b/src/librustc/middle/ty_fold.rs
index 5e88a0aefd3..7016c148465 100644
--- a/src/librustc/middle/ty_fold.rs
+++ b/src/librustc/middle/ty_fold.rs
@@ -310,34 +310,6 @@ impl<'tcx> TypeFoldable<'tcx> for ty::AutoRef<'tcx> {
     }
 }
 
-impl<'tcx> TypeFoldable<'tcx> for ty::MethodOrigin<'tcx> {
-    fn fold_with<F: TypeFolder<'tcx>>(&self, folder: &mut F) -> ty::MethodOrigin<'tcx> {
-        match *self {
-            ty::MethodStatic(def_id) => {
-                ty::MethodStatic(def_id)
-            }
-            ty::MethodStaticClosure(def_id) => {
-                ty::MethodStaticClosure(def_id)
-            }
-            ty::MethodTypeParam(ref param) => {
-                ty::MethodTypeParam(ty::MethodParam {
-                    trait_ref: param.trait_ref.fold_with(folder),
-                    method_num: param.method_num,
-                    impl_def_id: param.impl_def_id,
-                })
-            }
-            ty::MethodTraitObject(ref object) => {
-                ty::MethodTraitObject(ty::MethodObject {
-                    trait_ref: object.trait_ref.fold_with(folder),
-                    object_trait_id: object.object_trait_id,
-                    method_num: object.method_num,
-                    vtable_index: object.vtable_index,
-                })
-            }
-        }
-    }
-}
-
 impl<'tcx> TypeFoldable<'tcx> for ty::BuiltinBounds {
     fn fold_with<F: TypeFolder<'tcx>>(&self, _folder: &mut F) -> ty::BuiltinBounds {
         *self
@@ -520,8 +492,8 @@ impl<'tcx, N: TypeFoldable<'tcx>> TypeFoldable<'tcx> for traits::Vtable<'tcx, N>
 impl<'tcx> TypeFoldable<'tcx> for traits::VtableObjectData<'tcx> {
     fn fold_with<F:TypeFolder<'tcx>>(&self, folder: &mut F) -> traits::VtableObjectData<'tcx> {
         traits::VtableObjectData {
-            object_ty: self.object_ty.fold_with(folder),
             upcast_trait_ref: self.upcast_trait_ref.fold_with(folder),
+            vtable_base: self.vtable_base
         }
     }
 }
diff --git a/src/librustc/util/ppaux.rs b/src/librustc/util/ppaux.rs
index 44bea1cb621..9d82b0c2aa8 100644
--- a/src/librustc/util/ppaux.rs
+++ b/src/librustc/util/ppaux.rs
@@ -494,38 +494,6 @@ impl<'tcx> fmt::Display for ty::FnSig<'tcx> {
     }
 }
 
-impl<'tcx> fmt::Debug for ty::MethodOrigin<'tcx> {
-    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
-        match *self {
-            ty::MethodStatic(def_id) => {
-                write!(f, "MethodStatic({:?})", def_id)
-            }
-            ty::MethodStaticClosure(def_id) => {
-                write!(f, "MethodStaticClosure({:?})", def_id)
-            }
-            ty::MethodTypeParam(ref p) => write!(f, "{:?}", p),
-            ty::MethodTraitObject(ref p) => write!(f, "{:?}", p)
-        }
-    }
-}
-
-impl<'tcx> fmt::Debug for ty::MethodParam<'tcx> {
-    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
-        write!(f, "MethodParam({:?},{})",
-               self.trait_ref,
-               self.method_num)
-    }
-}
-
-impl<'tcx> fmt::Debug for ty::MethodObject<'tcx> {
-    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
-        write!(f, "MethodObject({:?},{},{})",
-               self.trait_ref,
-               self.method_num,
-               self.vtable_index)
-    }
-}
-
 impl<'tcx> fmt::Debug for ty::ExistentialBounds<'tcx> {
     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
         let mut empty = true;
diff --git a/src/librustc_lint/builtin.rs b/src/librustc_lint/builtin.rs
index 8845bd06a06..fa86c0dde99 100644
--- a/src/librustc_lint/builtin.rs
+++ b/src/librustc_lint/builtin.rs
@@ -33,8 +33,10 @@
 
 use metadata::{csearch, decoder};
 use middle::def::*;
+use middle::infer;
 use middle::subst::Substs;
 use middle::ty::{self, Ty};
+use middle::traits;
 use middle::{def, pat_util, stability};
 use middle::const_eval::{eval_const_expr_partial, ConstVal};
 use middle::cfg;
@@ -1863,24 +1865,18 @@ impl LintPass for UnconditionalRecursion {
 
     fn check_fn(&mut self, cx: &Context, fn_kind: visit::FnKind, _: &ast::FnDecl,
                 blk: &ast::Block, sp: Span, id: ast::NodeId) {
-        // FIXME(#23542) Replace with type ascription.
-        #![allow(trivial_casts)]
-
         type F = for<'tcx> fn(&ty::ctxt<'tcx>,
                               ast::NodeId, ast::NodeId, ast::Ident, ast::NodeId) -> bool;
 
-        let (name, checker) = match fn_kind {
-            visit::FkItemFn(name, _, _, _, _, _) => (name, id_refers_to_this_fn as F),
-            visit::FkMethod(name, _, _) => (name, id_refers_to_this_method as F),
+        let method = match fn_kind {
+            visit::FkItemFn(..) => None,
+            visit::FkMethod(..) => {
+                cx.tcx.impl_or_trait_item(local_def(id)).as_opt_method()
+            }
             // closures can't recur, so they don't matter.
             visit::FkFnBlock => return
         };
 
-        let impl_def_id = cx.tcx.impl_of_method(local_def(id))
-            .unwrap_or(local_def(ast::DUMMY_NODE_ID));
-        assert!(ast_util::is_local(impl_def_id));
-        let impl_node_id = impl_def_id.node;
-
         // Walk through this function (say `f`) looking to see if
         // every possible path references itself, i.e. the function is
         // called recursively unconditionally. This is done by trying
@@ -1931,7 +1927,17 @@ impl LintPass for UnconditionalRecursion {
             let node_id = cfg.graph.node_data(idx).id();
 
             // is this a recursive call?
-            if node_id != ast::DUMMY_NODE_ID && checker(cx.tcx, impl_node_id, id, name, node_id) {
+            let self_recursive = if node_id != ast::DUMMY_NODE_ID {
+                match method {
+                    Some(ref method) => {
+                        expr_refers_to_this_method(cx.tcx, method, node_id)
+                    }
+                    None => expr_refers_to_this_fn(cx.tcx, id, node_id)
+                }
+            } else {
+                false
+            };
+            if self_recursive {
                 self_call_spans.push(cx.tcx.map.span(node_id));
                 // this is a self call, so we shouldn't explore past
                 // this node in the CFG.
@@ -1970,15 +1976,12 @@ impl LintPass for UnconditionalRecursion {
         // all done
         return;
 
-        // Functions for identifying if the given NodeId `id`
-        // represents a call to the function `fn_id`/method
-        // `method_id`.
+        // Functions for identifying if the given Expr NodeId `id`
+        // represents a call to the function `fn_id`/method `method`.
 
-        fn id_refers_to_this_fn<'tcx>(tcx: &ty::ctxt<'tcx>,
-                                      _: ast::NodeId,
-                                      fn_id: ast::NodeId,
-                                      _: ast::Ident,
-                                      id: ast::NodeId) -> bool {
+        fn expr_refers_to_this_fn(tcx: &ty::ctxt,
+                                  fn_id: ast::NodeId,
+                                  id: ast::NodeId) -> bool {
             match tcx.map.get(id) {
                 ast_map::NodeExpr(&ast::Expr { node: ast::ExprCall(ref callee, _), .. }) => {
                     tcx.def_map.borrow().get(&callee.id)
@@ -1988,64 +1991,68 @@ impl LintPass for UnconditionalRecursion {
             }
         }
 
-        // check if the method call `id` refers to method `method_id`
-        // (with name `method_name` contained in impl `impl_id`).
-        fn id_refers_to_this_method<'tcx>(tcx: &ty::ctxt<'tcx>,
-                                          impl_id: ast::NodeId,
-                                          method_id: ast::NodeId,
-                                          method_name: ast::Ident,
-                                          id: ast::NodeId) -> bool {
-            let did = match tcx.tables.borrow().method_map.get(&ty::MethodCall::expr(id)) {
-                None => return false,
-                Some(m) => match m.origin {
-                    // There's no way to know if a method call via a
-                    // vtable is recursion, so we assume it's not.
-                    ty::MethodTraitObject(_) => return false,
-
-                    // This `did` refers directly to the method definition.
-                    ty::MethodStatic(did) | ty::MethodStaticClosure(did) => did,
-
-                    // MethodTypeParam are methods from traits:
-
-                    // The `impl ... for ...` of this method call
-                    // isn't known, e.g. it might be a default method
-                    // in a trait, so we get the def-id of the trait
-                    // method instead.
-                    ty::MethodTypeParam(
-                        ty::MethodParam { ref trait_ref, method_num, impl_def_id: None, }) => {
-
-                        let on_self = m.substs.self_ty().map_or(false, |t| t.is_self());
-                        if !on_self {
-                            // we can only be recurring in a default
+        // Check if the method call `id` refers to method `method`.
+        fn expr_refers_to_this_method(tcx: &ty::ctxt,
+                                      method: &ty::Method,
+                                      id: ast::NodeId) -> bool {
+            let method_call = ty::MethodCall::expr(id);
+            let callee = match tcx.tables.borrow().method_map.get(&method_call) {
+                Some(&m) => m,
+                None => return false
+            };
+            let callee_item = tcx.impl_or_trait_item(callee.def_id);
+
+            match callee_item.container() {
+                // This is an inherent method, so the `def_id` refers
+                // directly to the method definition.
+                ty::ImplContainer(_) => {
+                    callee.def_id == method.def_id
+                }
+
+                // A trait method, from any number of possible sources.
+                // Attempt to select a concrete impl before checking.
+                ty::TraitContainer(trait_def_id) => {
+                    let trait_substs = callee.substs.clone().method_to_trait();
+                    let trait_substs = tcx.mk_substs(trait_substs);
+                    let trait_ref = ty::TraitRef::new(trait_def_id, trait_substs);
+                    let trait_ref = ty::Binder(trait_ref);
+                    let span = tcx.map.span(id);
+                    let obligation =
+                        traits::Obligation::new(traits::ObligationCause::misc(span, id),
+                                                trait_ref.to_poly_trait_predicate());
+
+                    let param_env = ty::ParameterEnvironment::for_item(tcx, method.def_id.node);
+                    let infcx = infer::new_infer_ctxt(tcx, &tcx.tables, Some(param_env), false);
+                    let mut selcx = traits::SelectionContext::new(&infcx);
+                    match selcx.select(&obligation) {
+                        // The method comes from a `T: Trait` bound.
+                        // If `T` is `Self`, then this call is inside
+                        // a default method definition.
+                        Ok(Some(traits::VtableParam(_))) => {
+                            let self_ty = callee.substs.self_ty();
+                            let on_self = self_ty.map_or(false, |t| t.is_self());
+                            // We can only be recurring in a default
                             // method if we're being called literally
                             // on the `Self` type.
-                            return false
+                            on_self && callee.def_id == method.def_id
                         }
 
-                        tcx.trait_item(trait_ref.def_id, method_num).def_id()
-                    }
-
-                    // The `impl` is known, so we check that with a
-                    // special case:
-                    ty::MethodTypeParam(
-                        ty::MethodParam { impl_def_id: Some(impl_def_id), .. }) => {
+                        // The `impl` is known, so we check that with a
+                        // special case:
+                        Ok(Some(traits::VtableImpl(vtable_impl))) => {
+                            let container = ty::ImplContainer(vtable_impl.impl_def_id);
+                            // It matches if it comes from the same impl,
+                            // and has the same method name.
+                            container == method.container
+                                && callee_item.name() == method.name
+                        }
 
-                        let name = match tcx.map.expect_expr(id).node {
-                            ast::ExprMethodCall(ref sp_ident, _, _) => sp_ident.node,
-                            _ => tcx.sess.span_bug(
-                                tcx.map.span(id),
-                                "non-method call expr behaving like a method call?")
-                        };
-                        // It matches if it comes from the same impl,
-                        // and has the same method name.
-                        return ast_util::is_local(impl_def_id)
-                            && impl_def_id.node == impl_id
-                            && method_name.name == name.name
+                        // There's no way to know if this call is
+                        // recursive, so we assume it's not.
+                        _ => return false
                     }
                 }
-            };
-
-            ast_util::is_local(did) && did.node == method_id
+            }
         }
     }
 }
diff --git a/src/librustc_privacy/lib.rs b/src/librustc_privacy/lib.rs
index 239141df9e8..d90e5a033a1 100644
--- a/src/librustc_privacy/lib.rs
+++ b/src/librustc_privacy/lib.rs
@@ -40,10 +40,6 @@ use rustc::middle::privacy::ImportUse::*;
 use rustc::middle::privacy::LastPrivate::*;
 use rustc::middle::privacy::PrivateDep::*;
 use rustc::middle::privacy::{ExternalExports, ExportedItems, PublicItems};
-use rustc::middle::ty::{MethodTypeParam, MethodStatic};
-use rustc::middle::ty::{MethodCall, MethodMap, MethodOrigin, MethodParam};
-use rustc::middle::ty::{MethodStaticClosure, MethodObject};
-use rustc::middle::ty::MethodTraitObject;
 use rustc::middle::ty::{self, Ty};
 use rustc::util::nodemap::{NodeMap, NodeSet};
 
@@ -53,7 +49,7 @@ use syntax::codemap::Span;
 use syntax::parse::token;
 use syntax::visit::{self, Visitor};
 
-type Context<'a, 'tcx> = (&'a MethodMap<'tcx>, &'a def::ExportMap);
+type Context<'a, 'tcx> = (&'a ty::MethodMap<'tcx>, &'a def::ExportMap);
 
 /// Result of a checking operation - None => no errors were found. Some => an
 /// error and contains the span and message for reporting that error and
@@ -848,18 +844,16 @@ impl<'a, 'tcx> PrivacyVisitor<'a, 'tcx> {
     }
 
     // Checks that a method is in scope.
-    fn check_method(&mut self, span: Span, origin: &MethodOrigin,
+    fn check_method(&mut self, span: Span, method_def_id: ast::DefId,
                     name: ast::Name) {
-        match *origin {
-            MethodStatic(method_id) => {
-                self.check_static_method(span, method_id, name)
+        match self.tcx.impl_or_trait_item(method_def_id).container() {
+            ty::ImplContainer(_) => {
+                self.check_static_method(span, method_def_id, name)
             }
-            MethodStaticClosure(_) => {}
             // Trait methods are always all public. The only controlling factor
             // is whether the trait itself is accessible or not.
-            MethodTypeParam(MethodParam { ref trait_ref, .. }) |
-            MethodTraitObject(MethodObject { ref trait_ref, .. }) => {
-                self.report_error(self.ensure_public(span, trait_ref.def_id,
+            ty::TraitContainer(trait_def_id) => {
+                self.report_error(self.ensure_public(span, trait_def_id,
                                                      None, "source trait"));
             }
         }
@@ -903,18 +897,10 @@ impl<'a, 'tcx, 'v> Visitor<'v> for PrivacyVisitor<'a, 'tcx> {
                 }
             }
             ast::ExprMethodCall(ident, _, _) => {
-                let method_call = MethodCall::expr(expr.id);
-                match self.tcx.tables.borrow().method_map.get(&method_call) {
-                    None => {
-                        self.tcx.sess.span_bug(expr.span,
-                                                "method call not in \
-                                                method map");
-                    }
-                    Some(method) => {
-                        debug!("(privacy checking) checking impl method");
-                        self.check_method(expr.span, &method.origin, ident.node.name);
-                    }
-                }
+                let method_call = ty::MethodCall::expr(expr.id);
+                let method = self.tcx.tables.borrow().method_map[&method_call];
+                debug!("(privacy checking) checking impl method");
+                self.check_method(expr.span, method.def_id, ident.node.name);
             }
             ast::ExprStruct(_, ref fields, _) => {
                 match self.tcx.expr_ty(expr).sty {
diff --git a/src/librustc_trans/save/dump_csv.rs b/src/librustc_trans/save/dump_csv.rs
index 4e3b99276a9..e88b3980737 100644
--- a/src/librustc_trans/save/dump_csv.rs
+++ b/src/librustc_trans/save/dump_csv.rs
@@ -886,43 +886,11 @@ impl <'l, 'tcx> DumpCsvVisitor<'l, 'tcx> {
     fn process_method_call(&mut self,
                            ex: &ast::Expr,
                            args: &Vec<P<ast::Expr>>) {
-        let method_map = &self.tcx.tables.borrow().method_map;
-        let method_callee = method_map.get(&ty::MethodCall::expr(ex.id)).unwrap();
-        let (def_id, decl_id) = match method_callee.origin {
-            ty::MethodStatic(def_id) |
-            ty::MethodStaticClosure(def_id) => {
-                // method invoked on an object with a concrete type (not a static method)
-                let decl_id =
-                    match self.tcx.trait_item_of_item(def_id) {
-                        None => None,
-                        Some(decl_id) => Some(decl_id.def_id()),
-                    };
-
-                // This incantation is required if the method referenced is a
-                // trait's default implementation.
-                let def_id = match self.tcx.impl_or_trait_item(def_id) {
-                    ty::MethodTraitItem(method) => {
-                        method.provided_source.unwrap_or(def_id)
-                    }
-                    _ => self.sess
-                             .span_bug(ex.span,
-                                       "save::process_method_call: non-method \
-                                        DefId in MethodStatic or MethodStaticClosure"),
-                };
-                (Some(def_id), decl_id)
-            }
-            ty::MethodTypeParam(ref mp) => {
-                // method invoked on a type parameter
-                let trait_item = self.tcx.trait_item(mp.trait_ref.def_id,
-                                                     mp.method_num);
-                (None, Some(trait_item.def_id()))
-            }
-            ty::MethodTraitObject(ref mo) => {
-                // method invoked on a trait instance
-                let trait_item = self.tcx.trait_item(mo.trait_ref.def_id,
-                                                     mo.method_num);
-                (None, Some(trait_item.def_id()))
-            }
+        let method_call = ty::MethodCall::expr(ex.id);
+        let method_id = self.tcx.tables.borrow().method_map[&method_call].def_id;
+        let (def_id, decl_id) = match self.tcx.impl_or_trait_item(method_id).container() {
+            ty::ImplContainer(_) => (Some(method_id), None),
+            ty::TraitContainer(_) => (None, Some(method_id))
         };
         let sub_span = self.span.sub_span_for_meth_name(ex.span);
         self.fmt.meth_call_str(ex.span,
diff --git a/src/librustc_trans/trans/callee.rs b/src/librustc_trans/trans/callee.rs
index dfe807d6c91..debc8dd59c0 100644
--- a/src/librustc_trans/trans/callee.rs
+++ b/src/librustc_trans/trans/callee.rs
@@ -22,7 +22,6 @@ use arena::TypedArena;
 use back::link;
 use session;
 use llvm::{self, ValueRef, get_params};
-use metadata::csearch;
 use middle::def;
 use middle::subst;
 use middle::subst::{Subst, Substs};
@@ -66,7 +65,7 @@ pub struct MethodData {
 pub enum CalleeData<'tcx> {
     // Constructor for enum variant/tuple-like-struct
     // i.e. Some, Ok
-    NamedTupleConstructor(subst::Substs<'tcx>, ty::Disr),
+    NamedTupleConstructor(ty::Disr),
 
     // Represents a (possibly monomorphized) top-level fn item or method
     // item. Note that this is just the fn-ptr and is not a Rust closure
@@ -81,6 +80,7 @@ pub enum CalleeData<'tcx> {
 pub struct Callee<'blk, 'tcx: 'blk> {
     pub bcx: Block<'blk, 'tcx>,
     pub data: CalleeData<'tcx>,
+    pub ty: Ty<'tcx>
 }
 
 fn trans<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, expr: &ast::Expr)
@@ -104,11 +104,11 @@ fn trans<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, expr: &ast::Expr)
         let DatumBlock { bcx, datum, .. } = expr::trans(bcx, expr);
         match datum.ty.sty {
             ty::TyBareFn(..) => {
-                let llval = datum.to_llscalarish(bcx);
-                return Callee {
+                Callee {
                     bcx: bcx,
-                    data: Fn(llval),
-                };
+                    ty: datum.ty,
+                    data: Fn(datum.to_llscalarish(bcx))
+                }
             }
             _ => {
                 bcx.tcx().sess.span_bug(
@@ -119,12 +119,13 @@ fn trans<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, expr: &ast::Expr)
         }
     }
 
-    fn fn_callee<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, llfn: ValueRef)
+    fn fn_callee<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, datum: Datum<'tcx, Rvalue>)
                              -> Callee<'blk, 'tcx> {
-        return Callee {
+        Callee {
             bcx: bcx,
-            data: Fn(llfn),
-        };
+            data: Fn(datum.val),
+            ty: datum.ty
+        }
     }
 
     fn trans_def<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
@@ -143,12 +144,10 @@ fn trans<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, expr: &ast::Expr)
                     _ => false
                 }
             } => {
-                let substs = common::node_id_substs(bcx.ccx(),
-                                                    ExprId(ref_expr.id),
-                                                    bcx.fcx.param_substs);
                 Callee {
                     bcx: bcx,
-                    data: NamedTupleConstructor(substs, 0)
+                    data: NamedTupleConstructor(0),
+                    ty: expr_ty
                 }
             }
             def::DefFn(did, _) if match expr_ty.sty {
@@ -159,40 +158,36 @@ fn trans<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, expr: &ast::Expr)
                                                     ExprId(ref_expr.id),
                                                     bcx.fcx.param_substs);
                 let def_id = inline::maybe_instantiate_inline(bcx.ccx(), did);
-                Callee { bcx: bcx, data: Intrinsic(def_id.node, substs) }
+                Callee { bcx: bcx, data: Intrinsic(def_id.node, substs), ty: expr_ty }
             }
             def::DefFn(did, _) | def::DefMethod(did, def::FromImpl(_)) => {
                 fn_callee(bcx, trans_fn_ref(bcx.ccx(), did, ExprId(ref_expr.id),
-                                            bcx.fcx.param_substs).val)
+                                            bcx.fcx.param_substs))
             }
             def::DefMethod(meth_did, def::FromTrait(trait_did)) => {
                 fn_callee(bcx, meth::trans_static_method_callee(bcx.ccx(),
                                                                 meth_did,
                                                                 trait_did,
                                                                 ref_expr.id,
-                                                                bcx.fcx.param_substs).val)
+                                                                bcx.fcx.param_substs))
             }
             def::DefVariant(tid, vid, _) => {
                 let vinfo = bcx.tcx().enum_variant_with_id(tid, vid);
-                let substs = common::node_id_substs(bcx.ccx(),
-                                                    ExprId(ref_expr.id),
-                                                    bcx.fcx.param_substs);
 
                 // Nullary variants are not callable
                 assert!(!vinfo.args.is_empty());
 
                 Callee {
                     bcx: bcx,
-                    data: NamedTupleConstructor(substs, vinfo.disr_val)
+                    data: NamedTupleConstructor(vinfo.disr_val),
+                    ty: expr_ty
                 }
             }
             def::DefStruct(_) => {
-                let substs = common::node_id_substs(bcx.ccx(),
-                                                    ExprId(ref_expr.id),
-                                                    bcx.fcx.param_substs);
                 Callee {
                     bcx: bcx,
-                    data: NamedTupleConstructor(substs, 0)
+                    data: NamedTupleConstructor(0),
+                    ty: expr_ty
                 }
             }
             def::DefStatic(..) |
@@ -232,21 +227,6 @@ pub fn trans_fn_ref<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
     trans_fn_ref_with_substs(ccx, def_id, node, param_substs, substs)
 }
 
-fn trans_fn_ref_with_substs_to_callee<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
-                                                  def_id: ast::DefId,
-                                                  ref_id: ast::NodeId,
-                                                  substs: subst::Substs<'tcx>)
-                                                  -> Callee<'blk, 'tcx> {
-    Callee {
-        bcx: bcx,
-        data: Fn(trans_fn_ref_with_substs(bcx.ccx(),
-                                          def_id,
-                                          ExprId(ref_id),
-                                          bcx.fcx.param_substs,
-                                          substs).val),
-    }
-}
-
 /// Translates an adapter that implements the `Fn` trait for a fn
 /// pointer. This is basically the equivalent of something like:
 ///
@@ -356,12 +336,13 @@ pub fn trans_fn_pointer_shim<'a, 'tcx>(
         expr::SaveIn(fcx.get_ret_slot(bcx, sig.output, "ret_slot"))
     );
 
-    bcx = trans_call_inner(bcx,
-                           DebugLoc::None,
-                           bare_fn_ty,
-                           |bcx, _| Callee { bcx: bcx, data: Fn(llfnpointer) },
-                           ArgVals(&llargs[(self_idx + 1)..]),
-                           dest).bcx;
+    bcx = trans_call_inner(bcx, DebugLoc::None, |bcx, _| {
+        Callee {
+            bcx: bcx,
+            data: Fn(llfnpointer),
+            ty: bare_fn_ty
+        }
+    }, ArgVals(&llargs[(self_idx + 1)..]), dest).bcx;
 
     finish_fn(&fcx, bcx, sig.output, DebugLoc::None);
 
@@ -518,7 +499,7 @@ pub fn trans_fn_ref_with_substs<'a, 'tcx>(
             let ref_ty = match node {
                 ExprId(id) => tcx.node_id_to_type(id),
                 MethodCallKey(method_call) => {
-                    tcx.tables.borrow().method_map.get(&method_call).unwrap().ty
+                    tcx.tables.borrow().method_map[&method_call].ty
                 }
             };
             let ref_ty = monomorphize::apply_param_substs(tcx,
@@ -586,17 +567,16 @@ pub fn trans_fn_ref_with_substs<'a, 'tcx>(
 // ______________________________________________________________________
 // Translating calls
 
-pub fn trans_call<'a, 'blk, 'tcx>(in_cx: Block<'blk, 'tcx>,
+pub fn trans_call<'a, 'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
                                   call_expr: &ast::Expr,
                                   f: &ast::Expr,
                                   args: CallArgs<'a, 'tcx>,
                                   dest: expr::Dest)
                                   -> Block<'blk, 'tcx> {
     let _icx = push_ctxt("trans_call");
-    trans_call_inner(in_cx,
+    trans_call_inner(bcx,
                      call_expr.debug_loc(),
-                     common::expr_ty_adjusted(in_cx, f),
-                     |cx, _| trans(cx, f),
+                     |bcx, _| trans(bcx, f),
                      args,
                      Some(dest)).bcx
 }
@@ -610,22 +590,9 @@ pub fn trans_method_call<'a, 'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
     let _icx = push_ctxt("trans_method_call");
     debug!("trans_method_call(call_expr={:?})", call_expr);
     let method_call = MethodCall::expr(call_expr.id);
-    let method_ty = match bcx.tcx().tables.borrow().method_map.get(&method_call) {
-        Some(method) => match method.origin {
-            ty::MethodTraitObject(_) => match method.ty.sty {
-                ty::TyBareFn(_, ref fty) => {
-                    bcx.tcx().mk_fn(None, meth::opaque_method_ty(bcx.tcx(), fty))
-                }
-                _ => method.ty
-            },
-            _ => method.ty
-        },
-        None => panic!("method not found in trans_method_call")
-    };
     trans_call_inner(
         bcx,
         call_expr.debug_loc(),
-        common::monomorphize_type(bcx, method_ty),
         |cx, arg_cleanup_scope| {
             meth::trans_method_callee(cx, method_call, Some(rcvr), arg_cleanup_scope)
         },
@@ -639,22 +606,18 @@ pub fn trans_lang_call<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
                                    dest: Option<expr::Dest>,
                                    debug_loc: DebugLoc)
                                    -> Result<'blk, 'tcx> {
-    let fty = if did.krate == ast::LOCAL_CRATE {
-        bcx.tcx().node_id_to_type(did.node)
-    } else {
-        csearch::get_type(bcx.tcx(), did).ty
-    };
-    callee::trans_call_inner(bcx,
-                             debug_loc,
-                             fty,
-                             |bcx, _| {
-                                trans_fn_ref_with_substs_to_callee(bcx,
-                                                                   did,
-                                                                   0,
-                                                                   subst::Substs::trans_empty())
-                             },
-                             ArgVals(args),
-                             dest)
+    callee::trans_call_inner(bcx, debug_loc, |bcx, _| {
+        let datum = trans_fn_ref_with_substs(bcx.ccx(),
+                                             did,
+                                             ExprId(0),
+                                             bcx.fcx.param_substs,
+                                             subst::Substs::trans_empty());
+        Callee {
+            bcx: bcx,
+            data: Fn(datum.val),
+            ty: datum.ty
+        }
+    }, ArgVals(args), dest)
 }
 
 /// This behemoth of a function translates function calls. Unfortunately, in order to generate more
@@ -669,7 +632,6 @@ pub fn trans_lang_call<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
 /// somewhere. Nonetheless we return the actual return value of the function.
 pub fn trans_call_inner<'a, 'blk, 'tcx, F>(bcx: Block<'blk, 'tcx>,
                                            debug_loc: DebugLoc,
-                                           callee_ty: Ty<'tcx>,
                                            get_callee: F,
                                            args: CallArgs<'a, 'tcx>,
                                            dest: Option<expr::Dest>)
@@ -690,7 +652,7 @@ pub fn trans_call_inner<'a, 'blk, 'tcx, F>(bcx: Block<'blk, 'tcx>,
     let callee = get_callee(bcx, cleanup::CustomScope(arg_cleanup_scope));
     let mut bcx = callee.bcx;
 
-    let (abi, ret_ty) = match callee_ty.sty {
+    let (abi, ret_ty) = match callee.ty.sty {
         ty::TyBareFn(_, ref f) => {
             let output = bcx.tcx().erase_late_bound_regions(&f.sig.output());
             (f.abi, output)
@@ -698,12 +660,12 @@ pub fn trans_call_inner<'a, 'blk, 'tcx, F>(bcx: Block<'blk, 'tcx>,
         _ => panic!("expected bare rust fn or closure in trans_call_inner")
     };
 
-    let (llfn, llenv, llself) = match callee.data {
+    let (llfn, llself) = match callee.data {
         Fn(llfn) => {
-            (llfn, None, None)
+            (llfn, None)
         }
         TraitItem(d) => {
-            (d.llfn, None, Some(d.llself))
+            (d.llfn, Some(d.llself))
         }
         Intrinsic(node, substs) => {
             assert!(abi == synabi::RustIntrinsic);
@@ -716,18 +678,17 @@ pub fn trans_call_inner<'a, 'blk, 'tcx, F>(bcx: Block<'blk, 'tcx>,
                 }
             };
 
-            return intrinsic::trans_intrinsic_call(bcx, node, callee_ty,
+            return intrinsic::trans_intrinsic_call(bcx, node, callee.ty,
                                                    arg_cleanup_scope, args,
                                                    dest.unwrap(), substs,
                                                    call_info);
         }
-        NamedTupleConstructor(substs, disr) => {
+        NamedTupleConstructor(disr) => {
             assert!(dest.is_some());
             fcx.pop_custom_cleanup_scope(arg_cleanup_scope);
 
-            let ctor_ty = callee_ty.subst(bcx.tcx(), &substs);
             return base::trans_named_tuple_constructor(bcx,
-                                                       ctor_ty,
+                                                       callee.ty,
                                                        disr,
                                                        args,
                                                        dest.unwrap(),
@@ -794,17 +755,15 @@ pub fn trans_call_inner<'a, 'blk, 'tcx, F>(bcx: Block<'blk, 'tcx>,
             }
         }
 
-        // Push the environment (or a trait object's self).
-        match (llenv, llself) {
-            (Some(llenv), None) => llargs.push(llenv),
-            (None, Some(llself)) => llargs.push(llself),
-            _ => {}
+        // Push a trait object's self.
+        if let Some(llself) = llself {
+            llargs.push(llself);
         }
 
         // Push the arguments.
         bcx = trans_args(bcx,
                          args,
-                         callee_ty,
+                         callee.ty,
                          &mut llargs,
                          cleanup::CustomScope(arg_cleanup_scope),
                          llself.is_some(),
@@ -816,7 +775,7 @@ pub fn trans_call_inner<'a, 'blk, 'tcx, F>(bcx: Block<'blk, 'tcx>,
         let (llret, b) = base::invoke(bcx,
                                       llfn,
                                       &llargs[..],
-                                      callee_ty,
+                                      callee.ty,
                                       debug_loc);
         bcx = b;
         llresult = llret;
@@ -845,7 +804,7 @@ pub fn trans_call_inner<'a, 'blk, 'tcx, F>(bcx: Block<'blk, 'tcx>,
         };
         bcx = trans_args(bcx,
                          args,
-                         callee_ty,
+                         callee.ty,
                          &mut llargs,
                          cleanup::CustomScope(arg_cleanup_scope),
                          false,
@@ -853,7 +812,7 @@ pub fn trans_call_inner<'a, 'blk, 'tcx, F>(bcx: Block<'blk, 'tcx>,
         fcx.scopes.borrow_mut().last_mut().unwrap().drop_non_lifetime_clean();
 
         bcx = foreign::trans_native_call(bcx,
-                                         callee_ty,
+                                         callee.ty,
                                          llfn,
                                          opt_llretslot.unwrap(),
                                          &llargs[..],
@@ -894,11 +853,11 @@ pub enum CallArgs<'a, 'tcx> {
     // value.
     ArgVals(&'a [ValueRef]),
 
-    // For overloaded operators: `(lhs, Vec(rhs, rhs_id), autoref)`. `lhs`
+    // For overloaded operators: `(lhs, Option(rhs, rhs_id), autoref)`. `lhs`
     // is the left-hand-side and `rhs/rhs_id` is the datum/expr-id of
-    // the right-hand-side arguments (if any). `autoref` indicates whether the `rhs`
+    // the right-hand-side argument (if any). `autoref` indicates whether the `rhs`
     // arguments should be auto-referenced
-    ArgOverloadedOp(Datum<'tcx, Expr>, Vec<(Datum<'tcx, Expr>, ast::NodeId)>, bool),
+    ArgOverloadedOp(Datum<'tcx, Expr>, Option<(Datum<'tcx, Expr>, ast::NodeId)>, bool),
 
     // Supply value of arguments as a list of expressions that must be
     // translated, for overloaded call operators.
@@ -1077,12 +1036,14 @@ pub fn trans_args<'a, 'blk, 'tcx>(cx: Block<'blk, 'tcx>,
                                   DontAutorefArg,
                                   llargs);
 
-            assert_eq!(arg_tys.len(), 1 + rhs.len());
-            for (rhs, rhs_id) in rhs {
+            if let Some((rhs, rhs_id)) = rhs {
+                assert_eq!(arg_tys.len(), 2);
                 bcx = trans_arg_datum(bcx, arg_tys[1], rhs,
                                       arg_cleanup_scope,
                                       if autoref { DoAutorefArg(rhs_id) } else { DontAutorefArg },
                                       llargs);
+            } else {
+                assert_eq!(arg_tys.len(), 1);
             }
         }
         ArgVals(vs) => {
diff --git a/src/librustc_trans/trans/closure.rs b/src/librustc_trans/trans/closure.rs
index 5fd0f92400f..d813e9dbf40 100644
--- a/src/librustc_trans/trans/closure.rs
+++ b/src/librustc_trans/trans/closure.rs
@@ -429,12 +429,13 @@ fn trans_fn_once_adapter_shim<'a, 'tcx>(
     let callee_data = TraitItem(MethodData { llfn: llreffn,
                                              llself: env_datum.val });
 
-    bcx = callee::trans_call_inner(bcx,
-                                   DebugLoc::None,
-                                   llref_fn_ty,
-                                   |bcx, _| Callee { bcx: bcx, data: callee_data },
-                                   ArgVals(&llargs[(self_idx + 1)..]),
-                                   dest).bcx;
+    bcx = callee::trans_call_inner(bcx, DebugLoc::None, |bcx, _| {
+        Callee {
+            bcx: bcx,
+            data: callee_data,
+            ty: llref_fn_ty
+        }
+    }, ArgVals(&llargs[(self_idx + 1)..]), dest).bcx;
 
     fcx.pop_custom_cleanup_scope(self_scope);
 
diff --git a/src/librustc_trans/trans/common.rs b/src/librustc_trans/trans/common.rs
index ed2d303b5e1..e1c1ac9a772 100644
--- a/src/librustc_trans/trans/common.rs
+++ b/src/librustc_trans/trans/common.rs
@@ -874,7 +874,6 @@ pub fn fulfill_obligation<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
     debug!("trans fulfill_obligation: trait_ref={:?} def_id={:?}",
            trait_ref, trait_ref.def_id());
 
-    tcx.populate_implementations_for_trait_if_necessary(trait_ref.def_id());
 
     // Do the initial selection for the obligation. This yields the
     // shallow result we are looking for -- that is, what specific impl.
@@ -1026,7 +1025,7 @@ pub fn node_id_substs<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
             tcx.node_id_item_substs(id).substs
         }
         MethodCallKey(method_call) => {
-            tcx.tables.borrow().method_map.get(&method_call).unwrap().substs.clone()
+            tcx.tables.borrow().method_map[&method_call].substs.clone()
         }
     };
 
diff --git a/src/librustc_trans/trans/consts.rs b/src/librustc_trans/trans/consts.rs
index 57af688ef60..e7e2793fc7e 100644
--- a/src/librustc_trans/trans/consts.rs
+++ b/src/librustc_trans/trans/consts.rs
@@ -894,10 +894,7 @@ fn const_expr_unadjusted<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
           ast::ExprMethodCall(_, _, ref args) => {
               let arg_vals = map_list(args);
               let method_call = ty::MethodCall::expr(e.id);
-              let method_did = match cx.tcx().tables.borrow().method_map[&method_call].origin {
-                  ty::MethodStatic(did) => did,
-                  _ => cx.sess().span_bug(e.span, "expected a const method def")
-              };
+              let method_did = cx.tcx().tables.borrow().method_map[&method_call].def_id;
               const_fn_call(cx, MethodCallKey(method_call),
                             method_did, &arg_vals, param_substs)
           }
diff --git a/src/librustc_trans/trans/expr.rs b/src/librustc_trans/trans/expr.rs
index d7ce50082f1..7722cb322c9 100644
--- a/src/librustc_trans/trans/expr.rs
+++ b/src/librustc_trans/trans/expr.rs
@@ -805,7 +805,7 @@ fn trans_index<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
                                                index_expr,
                                                method_call,
                                                base_datum,
-                                               vec![(ix_datum, idx.id)],
+                                               Some((ix_datum, idx.id)),
                                                Some(SaveIn(scratch.val)),
                                                false));
             let datum = scratch.to_expr_datum();
@@ -1175,21 +1175,21 @@ fn trans_rvalue_dps_unadjusted<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
             let lhs = unpack_datum!(bcx, trans(bcx, &**lhs));
             let rhs_datum = unpack_datum!(bcx, trans(bcx, &**rhs));
             trans_overloaded_op(bcx, expr, MethodCall::expr(expr.id), lhs,
-                                vec![(rhs_datum, rhs.id)], Some(dest),
+                                Some((rhs_datum, rhs.id)), Some(dest),
                                 !ast_util::is_by_value_binop(op.node)).bcx
         }
         ast::ExprUnary(op, ref subexpr) => {
             // if not overloaded, would be RvalueDatumExpr
             let arg = unpack_datum!(bcx, trans(bcx, &**subexpr));
             trans_overloaded_op(bcx, expr, MethodCall::expr(expr.id),
-                                arg, Vec::new(), Some(dest), !ast_util::is_by_value_unop(op)).bcx
+                                arg, None, Some(dest), !ast_util::is_by_value_unop(op)).bcx
         }
         ast::ExprIndex(ref base, ref idx) => {
             // if not overloaded, would be RvalueDatumExpr
             let base = unpack_datum!(bcx, trans(bcx, &**base));
             let idx_datum = unpack_datum!(bcx, trans(bcx, &**idx));
             trans_overloaded_op(bcx, expr, MethodCall::expr(expr.id), base,
-                                vec![(idx_datum, idx.id)], Some(dest), true).bcx
+                                Some((idx_datum, idx.id)), Some(dest), true).bcx
         }
         ast::ExprCast(..) => {
             // Trait casts used to come this way, now they should be coercions.
@@ -1943,19 +1943,12 @@ fn trans_overloaded_op<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
                                    expr: &ast::Expr,
                                    method_call: MethodCall,
                                    lhs: Datum<'tcx, Expr>,
-                                   rhs: Vec<(Datum<'tcx, Expr>, ast::NodeId)>,
+                                   rhs: Option<(Datum<'tcx, Expr>, ast::NodeId)>,
                                    dest: Option<Dest>,
                                    autoref: bool)
                                    -> Result<'blk, 'tcx> {
-    let method_ty = bcx.tcx()
-                       .tables
-                       .borrow()
-                       .method_map
-                       .get(&method_call).unwrap().ty;
-
     callee::trans_call_inner(bcx,
                              expr.debug_loc(),
-                             monomorphize_type(bcx, method_ty),
                              |bcx, arg_cleanup_scope| {
                                 meth::trans_method_callee(bcx,
                                                           method_call,
@@ -1974,20 +1967,11 @@ fn trans_overloaded_call<'a, 'blk, 'tcx>(mut bcx: Block<'blk, 'tcx>,
                                          -> Block<'blk, 'tcx> {
     debug!("trans_overloaded_call {}", expr.id);
     let method_call = MethodCall::expr(expr.id);
-    let method_type = bcx.tcx()
-                         .tables
-                         .borrow()
-                         .method_map
-                         .get(&method_call)
-                         .unwrap()
-                         .ty;
     let mut all_args = vec!(callee);
     all_args.extend(args.iter().map(|e| &**e));
     unpack_result!(bcx,
                    callee::trans_call_inner(bcx,
                                             expr.debug_loc(),
-                                            monomorphize_type(bcx,
-                                                              method_type),
                                             |bcx, arg_cleanup_scope| {
                                                 meth::trans_method_callee(
                                                     bcx,
@@ -2259,7 +2243,7 @@ fn deref_once<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
             let scratch = rvalue_scratch_datum(bcx, ref_ty, "overloaded_deref");
 
             unpack_result!(bcx, trans_overloaded_op(bcx, expr, method_call,
-                                                    datum, Vec::new(), Some(SaveIn(scratch.val)),
+                                                    datum, None, Some(SaveIn(scratch.val)),
                                                     false));
             scratch.to_expr_datum()
         }
diff --git a/src/librustc_trans/trans/meth.rs b/src/librustc_trans/trans/meth.rs
index 1b01fb6c7f8..1fa996f76b9 100644
--- a/src/librustc_trans/trans/meth.rs
+++ b/src/librustc_trans/trans/meth.rs
@@ -39,7 +39,6 @@ use trans::type_of::*;
 use middle::ty::{self, Ty, HasTypeFlags};
 use middle::ty::MethodCall;
 
-use syntax::abi::{Rust, RustCall};
 use syntax::parse::token;
 use syntax::{ast, attr, visit};
 use syntax::codemap::DUMMY_SP;
@@ -107,34 +106,28 @@ pub fn trans_method_callee<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
                                        -> Callee<'blk, 'tcx> {
     let _icx = push_ctxt("meth::trans_method_callee");
 
-    let (origin, method_ty) =
-        bcx.tcx()
-           .tables
-           .borrow()
-           .method_map
-           .get(&method_call)
-           .map(|method| (method.origin.clone(), method.ty))
-           .unwrap();
-
-    match origin {
-        ty::MethodStatic(did) |
-        ty::MethodStaticClosure(did) => {
-            debug!("trans_method_callee: static, {:?}", did);
+    let method = bcx.tcx().tables.borrow().method_map[&method_call];
+
+    match bcx.tcx().impl_or_trait_item(method.def_id).container() {
+        ty::ImplContainer(_) => {
+            debug!("trans_method_callee: static, {:?}", method.def_id);
+            let datum = callee::trans_fn_ref(bcx.ccx(),
+                                             method.def_id,
+                                             MethodCallKey(method_call),
+                                             bcx.fcx.param_substs);
             Callee {
                 bcx: bcx,
-                data: Fn(callee::trans_fn_ref(bcx.ccx(),
-                                              did,
-                                              MethodCallKey(method_call),
-                                              bcx.fcx.param_substs).val),
+                data: Fn(datum.val),
+                ty: datum.ty
             }
         }
 
-        ty::MethodTypeParam(ty::MethodParam {
-            ref trait_ref,
-            method_num,
-            impl_def_id: _
-        }) => {
-            let trait_ref = ty::Binder(bcx.monomorphize(trait_ref));
+        ty::TraitContainer(trait_def_id) => {
+            let trait_substs = method.substs.clone().method_to_trait();
+            let trait_substs = bcx.tcx().mk_substs(trait_substs);
+            let trait_ref = ty::TraitRef::new(trait_def_id, trait_substs);
+
+            let trait_ref = ty::Binder(bcx.monomorphize(&trait_ref));
             let span = bcx.tcx().map.span(method_call.expr_id);
             debug!("method_call={:?} trait_ref={:?} trait_ref id={:?} substs={:?}",
                    method_call,
@@ -147,25 +140,12 @@ pub fn trans_method_callee<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
             debug!("origin = {:?}", origin);
             trans_monomorphized_callee(bcx,
                                        method_call,
-                                       trait_ref.def_id(),
-                                       method_num,
-                                       origin)
-        }
-
-        ty::MethodTraitObject(ref mt) => {
-            let self_expr = match self_expr {
-                Some(self_expr) => self_expr,
-                None => {
-                    bcx.sess().span_bug(bcx.tcx().map.span(method_call.expr_id),
-                                        "self expr wasn't provided for trait object \
-                                         callee (trying to call overloaded op?)")
-                }
-            };
-            trans_trait_callee(bcx,
-                               monomorphize_type(bcx, method_ty),
-                               mt.vtable_index,
-                               self_expr,
-                               arg_cleanup_scope)
+                                       self_expr,
+                                       trait_def_id,
+                                       method.def_id,
+                                       method.ty,
+                                       origin,
+                                       arg_cleanup_scope)
         }
     }
 }
@@ -235,8 +215,7 @@ pub fn trans_static_method_callee<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
                                              Vec::new()));
     let trait_substs = tcx.mk_substs(trait_substs);
     debug!("trait_substs={:?}", trait_substs);
-    let trait_ref = ty::Binder(ty::TraitRef { def_id: trait_id,
-                                              substs: trait_substs });
+    let trait_ref = ty::Binder(ty::TraitRef::new(trait_id, trait_substs));
     let vtbl = fulfill_obligation(ccx,
                                   DUMMY_SP,
                                   trait_ref);
@@ -282,18 +261,11 @@ pub fn trans_static_method_callee<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
                                      callee_substs)
         }
         traits::VtableObject(ref data) => {
-            let trait_item_def_ids =
-                ccx.tcx().trait_item_def_ids(trait_id);
-            let method_offset_in_trait =
-                trait_item_def_ids.iter()
-                                  .position(|item| item.def_id() == method_id)
-                                  .unwrap();
-            let (llfn, ty) =
-                trans_object_shim(ccx,
-                                  data.object_ty,
-                                  data.upcast_trait_ref.clone(),
-                                  method_offset_in_trait);
-            immediate_rvalue(llfn, ty)
+            let idx = traits::get_vtable_index_of_object_method(tcx, data, method_id);
+            trans_object_shim(ccx,
+                              data.upcast_trait_ref.clone(),
+                              method_id,
+                              idx)
         }
         _ => {
             tcx.sess.bug(&format!("static call to invalid vtable: {:?}",
@@ -326,16 +298,19 @@ fn method_with_name(ccx: &CrateContext, impl_id: ast::DefId, name: ast::Name)
 
 fn trans_monomorphized_callee<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
                                           method_call: MethodCall,
+                                          self_expr: Option<&ast::Expr>,
                                           trait_id: ast::DefId,
-                                          n_method: usize,
-                                          vtable: traits::Vtable<'tcx, ()>)
+                                          method_id: ast::DefId,
+                                          method_ty: Ty<'tcx>,
+                                          vtable: traits::Vtable<'tcx, ()>,
+                                          arg_cleanup_scope: cleanup::ScopeId)
                                           -> Callee<'blk, 'tcx> {
     let _icx = push_ctxt("meth::trans_monomorphized_callee");
     match vtable {
         traits::VtableImpl(vtable_impl) => {
             let ccx = bcx.ccx();
             let impl_did = vtable_impl.impl_def_id;
-            let mname = match ccx.tcx().trait_item(trait_id, n_method) {
+            let mname = match ccx.tcx().impl_or_trait_item(method_id) {
                 ty::MethodTraitItem(method) => method.name,
                 _ => {
                     bcx.tcx().sess.bug("can't monomorphize a non-method trait \
@@ -351,13 +326,13 @@ fn trans_monomorphized_callee<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
                     bcx, MethodCallKey(method_call), vtable_impl.substs);
 
             // translate the function
-            let llfn = trans_fn_ref_with_substs(bcx.ccx(),
-                                                mth_id,
-                                                MethodCallKey(method_call),
-                                                bcx.fcx.param_substs,
-                                                callee_substs).val;
+            let datum = trans_fn_ref_with_substs(bcx.ccx(),
+                                                 mth_id,
+                                                 MethodCallKey(method_call),
+                                                 bcx.fcx.param_substs,
+                                                 callee_substs);
 
-            Callee { bcx: bcx, data: Fn(llfn) }
+            Callee { bcx: bcx, data: Fn(datum.val), ty: datum.ty }
         }
         traits::VtableClosure(vtable_closure) => {
             // The substitutions should have no type parameters remaining
@@ -372,19 +347,31 @@ fn trans_monomorphized_callee<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
             Callee {
                 bcx: bcx,
                 data: Fn(llfn),
+                ty: monomorphize_type(bcx, method_ty)
             }
         }
         traits::VtableFnPointer(fn_ty) => {
             let trait_closure_kind = bcx.tcx().lang_items.fn_trait_kind(trait_id).unwrap();
             let llfn = trans_fn_pointer_shim(bcx.ccx(), trait_closure_kind, fn_ty);
-            Callee { bcx: bcx, data: Fn(llfn) }
+            Callee {
+                bcx: bcx,
+                data: Fn(llfn),
+                ty: monomorphize_type(bcx, method_ty)
+            }
         }
         traits::VtableObject(ref data) => {
-            let (llfn, _) = trans_object_shim(bcx.ccx(),
-                                              data.object_ty,
-                                              data.upcast_trait_ref.clone(),
-                                              n_method);
-            Callee { bcx: bcx, data: Fn(llfn) }
+            let idx = traits::get_vtable_index_of_object_method(bcx.tcx(), data, method_id);
+            if let Some(self_expr) = self_expr {
+                if let ty::TyBareFn(_, ref fty) = monomorphize_type(bcx, method_ty).sty {
+                    let ty = bcx.tcx().mk_fn(None, opaque_method_ty(bcx.tcx(), fty));
+                    return trans_trait_callee(bcx, ty, idx, self_expr, arg_cleanup_scope);
+                }
+            }
+            let datum = trans_object_shim(bcx.ccx(),
+                                          data.upcast_trait_ref.clone(),
+                                          method_id,
+                                          idx);
+            Callee { bcx: bcx, data: Fn(datum.val), ty: datum.ty }
         }
         traits::VtableBuiltin(..) |
         traits::VtableDefaultImpl(..) |
@@ -438,7 +425,7 @@ fn combine_impl_and_methods_tps<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
 /// object. Objects are represented as a pair, so we first evaluate the self expression and then
 /// extract the self data and vtable out of the pair.
 fn trans_trait_callee<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
-                                  method_ty: Ty<'tcx>,
+                                  opaque_fn_ty: Ty<'tcx>,
                                   vtable_index: usize,
                                   self_expr: &ast::Expr,
                                   arg_cleanup_scope: cleanup::ScopeId)
@@ -471,51 +458,39 @@ fn trans_trait_callee<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
 
     let llself = Load(bcx, GEPi(bcx, llval, &[0, abi::FAT_PTR_ADDR]));
     let llvtable = Load(bcx, GEPi(bcx, llval, &[0, abi::FAT_PTR_EXTRA]));
-    trans_trait_callee_from_llval(bcx, method_ty, vtable_index, llself, llvtable)
+    trans_trait_callee_from_llval(bcx, opaque_fn_ty, vtable_index, llself, llvtable)
 }
 
 /// Same as `trans_trait_callee()` above, except that it is given a by-ref pointer to the object
 /// pair.
-pub fn trans_trait_callee_from_llval<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
-                                                 callee_ty: Ty<'tcx>,
-                                                 vtable_index: usize,
-                                                 llself: ValueRef,
-                                                 llvtable: ValueRef)
-                                                 -> Callee<'blk, 'tcx> {
+fn trans_trait_callee_from_llval<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
+                                             opaque_fn_ty: Ty<'tcx>,
+                                             vtable_index: usize,
+                                             llself: ValueRef,
+                                             llvtable: ValueRef)
+                                             -> Callee<'blk, 'tcx> {
     let _icx = push_ctxt("meth::trans_trait_callee");
     let ccx = bcx.ccx();
 
     // Load the data pointer from the object.
     debug!("trans_trait_callee_from_llval(callee_ty={}, vtable_index={}, llself={}, llvtable={})",
-           callee_ty,
+           opaque_fn_ty,
            vtable_index,
            bcx.val_to_string(llself),
            bcx.val_to_string(llvtable));
 
     // Replace the self type (&Self or Box<Self>) with an opaque pointer.
-    let llcallee_ty = match callee_ty.sty {
-        ty::TyBareFn(_, ref f) if f.abi == Rust || f.abi == RustCall => {
-            let fake_sig =
-                ty::Binder(ty::FnSig {
-                    inputs: f.sig.0.inputs[1..].to_vec(),
-                    output: f.sig.0.output,
-                    variadic: f.sig.0.variadic,
-                });
-            type_of_rust_fn(ccx, Some(Type::i8p(ccx)), &fake_sig, f.abi)
-        }
-        _ => {
-            ccx.sess().bug("meth::trans_trait_callee given non-bare-rust-fn");
-        }
-    };
     let mptr = Load(bcx, GEPi(bcx, llvtable, &[vtable_index + VTABLE_OFFSET]));
+    let llcallee_ty = type_of_fn_from_ty(ccx, opaque_fn_ty);
 
-    return Callee {
+    Callee {
         bcx: bcx,
         data: TraitItem(MethodData {
             llfn: PointerCast(bcx, mptr, llcallee_ty.ptr_to()),
             llself: PointerCast(bcx, llself, Type::i8p(ccx)),
-        })
-    };
+        }),
+        ty: opaque_fn_ty
+    }
 }
 
 /// Generate a shim function that allows an object type like `SomeTrait` to
@@ -540,32 +515,19 @@ pub fn trans_trait_callee_from_llval<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
 ///
 /// In fact, all virtual calls can be thought of as normal trait calls
 /// that go through this shim function.
-pub fn trans_object_shim<'a, 'tcx>(
+fn trans_object_shim<'a, 'tcx>(
     ccx: &'a CrateContext<'a, 'tcx>,
-    object_ty: Ty<'tcx>,
     upcast_trait_ref: ty::PolyTraitRef<'tcx>,
-    method_offset_in_trait: usize)
-    -> (ValueRef, Ty<'tcx>)
+    method_id: ast::DefId,
+    vtable_index: usize)
+    -> Datum<'tcx, Rvalue>
 {
     let _icx = push_ctxt("trans_object_shim");
     let tcx = ccx.tcx();
-    let trait_id = upcast_trait_ref.def_id();
 
-    debug!("trans_object_shim(object_ty={:?}, upcast_trait_ref={:?}, method_offset_in_trait={})",
-           object_ty,
+    debug!("trans_object_shim(upcast_trait_ref={:?}, method_id={:?})",
            upcast_trait_ref,
-           method_offset_in_trait);
-
-    let object_trait_ref =
-        match object_ty.sty {
-            ty::TyTrait(ref data) => {
-                data.principal_trait_ref_with_self_ty(tcx, object_ty)
-            }
-            _ => {
-                tcx.sess.bug(&format!("trans_object_shim() called on non-object: {:?}",
-                                      object_ty));
-            }
-        };
+           method_id);
 
     // Upcast to the trait in question and extract out the substitutions.
     let upcast_trait_ref = tcx.erase_late_bound_regions(&upcast_trait_ref);
@@ -573,7 +535,7 @@ pub fn trans_object_shim<'a, 'tcx>(
     debug!("trans_object_shim: object_substs={:?}", object_substs);
 
     // Lookup the type of this method as declared in the trait and apply substitutions.
-    let method_ty = match tcx.trait_item(trait_id, method_offset_in_trait) {
+    let method_ty = match tcx.impl_or_trait_item(method_id) {
         ty::MethodTraitItem(method) => method,
         _ => {
             tcx.sess.bug("can't create a method shim for a non-method item")
@@ -622,27 +584,21 @@ pub fn trans_object_shim<'a, 'tcx>(
         fcx.llretslotptr.get().map(
             |_| expr::SaveIn(fcx.get_ret_slot(bcx, sig.output, "ret_slot")));
 
-    let method_offset_in_vtable =
-        traits::get_vtable_index_of_object_method(bcx.tcx(),
-                                                  object_trait_ref.clone(),
-                                                  trait_id,
-                                                  method_offset_in_trait);
     debug!("trans_object_shim: method_offset_in_vtable={}",
-           method_offset_in_vtable);
+           vtable_index);
 
     bcx = trans_call_inner(bcx,
                            DebugLoc::None,
-                           method_bare_fn_ty,
                            |bcx, _| trans_trait_callee_from_llval(bcx,
                                                                   method_bare_fn_ty,
-                                                                  method_offset_in_vtable,
+                                                                  vtable_index,
                                                                   llself, llvtable),
                            ArgVals(&llargs[(self_idx + 2)..]),
                            dest).bcx;
 
     finish_fn(&fcx, bcx, sig.output, DebugLoc::None);
 
-    (llfn, method_bare_fn_ty)
+    immediate_rvalue(llfn, shim_fn_ty)
 }
 
 /// Creates a returns a dynamic vtable for the given type and vtable origin.
@@ -825,8 +781,8 @@ fn emit_vtable_methods<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
 }
 
 /// Replace the self type (&Self or Box<Self>) with an opaque pointer.
-pub fn opaque_method_ty<'tcx>(tcx: &ty::ctxt<'tcx>, method_ty: &ty::BareFnTy<'tcx>)
-        -> &'tcx ty::BareFnTy<'tcx> {
+fn opaque_method_ty<'tcx>(tcx: &ty::ctxt<'tcx>, method_ty: &ty::BareFnTy<'tcx>)
+                          -> &'tcx ty::BareFnTy<'tcx> {
     let mut inputs = method_ty.sig.0.inputs.clone();
     inputs[0] = tcx.mk_mut_ptr(tcx.mk_mach_int(ast::TyI8));
 
diff --git a/src/librustc_trans/trans/monomorphize.rs b/src/librustc_trans/trans/monomorphize.rs
index 3ef72e2c4af..98fe57ec314 100644
--- a/src/librustc_trans/trans/monomorphize.rs
+++ b/src/librustc_trans/trans/monomorphize.rs
@@ -59,7 +59,8 @@ pub fn monomorphic_fn<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
     let item_ty = ccx.tcx().lookup_item_type(fn_id).ty;
 
     debug!("monomorphic_fn about to subst into {:?}", item_ty);
-    let mono_ty = item_ty.subst(ccx.tcx(), psubsts);
+    let mono_ty = apply_param_substs(ccx.tcx(), psubsts, &item_ty);
+    debug!("mono_ty = {:?} (post-substitution)", mono_ty);
 
     match ccx.monomorphized().borrow().get(&hash_id) {
         Some(&val) => {
@@ -96,11 +97,6 @@ pub fn monomorphic_fn<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
         }
     }
 
-    debug!("mono_ty = {:?} (post-substitution)", mono_ty);
-
-    let mono_ty = normalize_associated_type(ccx.tcx(), &mono_ty);
-    debug!("mono_ty = {:?} (post-normalization)", mono_ty);
-
     ccx.stats().n_monos.set(ccx.stats().n_monos.get() + 1);
 
     let depth;
diff --git a/src/librustc_typeck/check/method/confirm.rs b/src/librustc_typeck/check/method/confirm.rs
index 7a887fac9d4..8db5b5e7c50 100644
--- a/src/librustc_typeck/check/method/confirm.rs
+++ b/src/librustc_typeck/check/method/confirm.rs
@@ -15,8 +15,6 @@ use check::UnresolvedTypeAction;
 use middle::subst::{self};
 use middle::traits;
 use middle::ty::{self, Ty};
-use middle::ty::{MethodCall, MethodCallee, MethodObject, MethodOrigin,
-                 MethodParam, MethodStatic, MethodTraitObject, MethodTypeParam};
 use middle::ty_fold::TypeFoldable;
 use middle::infer;
 use middle::infer::InferCtxt;
@@ -52,7 +50,7 @@ pub fn confirm<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
                          unadjusted_self_ty: Ty<'tcx>,
                          pick: probe::Pick<'tcx>,
                          supplied_method_types: Vec<Ty<'tcx>>)
-                         -> MethodCallee<'tcx>
+                         -> ty::MethodCallee<'tcx>
 {
     debug!("confirm(unadjusted_self_ty={:?}, pick={:?}, supplied_method_types={:?})",
            unadjusted_self_ty,
@@ -77,7 +75,7 @@ impl<'a,'tcx> ConfirmContext<'a,'tcx> {
                unadjusted_self_ty: Ty<'tcx>,
                pick: probe::Pick<'tcx>,
                supplied_method_types: Vec<Ty<'tcx>>)
-               -> MethodCallee<'tcx>
+               -> ty::MethodCallee<'tcx>
     {
         // Adjust the self expression the user provided and obtain the adjusted type.
         let self_ty = self.adjust_self_ty(unadjusted_self_ty, &pick);
@@ -86,8 +84,7 @@ impl<'a,'tcx> ConfirmContext<'a,'tcx> {
         self.enforce_illegal_method_limitations(&pick);
 
         // Create substitutions for the method's type parameters.
-        let (rcvr_substs, method_origin) =
-            self.fresh_receiver_substs(self_ty, &pick);
+        let rcvr_substs = self.fresh_receiver_substs(self_ty, &pick);
         let (method_types, method_regions) =
             self.instantiate_method_substs(&pick, supplied_method_types);
         let all_substs = rcvr_substs.with_method(method_types, method_regions);
@@ -112,10 +109,10 @@ impl<'a,'tcx> ConfirmContext<'a,'tcx> {
             unsafety: method_ty.fty.unsafety,
             abi: method_ty.fty.abi.clone(),
         }));
-        let callee = MethodCallee {
-            origin: method_origin,
+        let callee = ty::MethodCallee {
+            def_id: pick.item.def_id(),
             ty: fty,
-            substs: all_substs
+            substs: self.tcx().mk_substs(all_substs)
         };
 
         // If this is an `&mut self` method, bias the receiver
@@ -194,18 +191,18 @@ impl<'a,'tcx> ConfirmContext<'a,'tcx> {
     fn fresh_receiver_substs(&mut self,
                              self_ty: Ty<'tcx>,
                              pick: &probe::Pick<'tcx>)
-                             -> (subst::Substs<'tcx>, MethodOrigin<'tcx>)
+                             -> subst::Substs<'tcx>
     {
         match pick.kind {
-            probe::InherentImplPick(impl_def_id) => {
+            probe::InherentImplPick => {
+                let impl_def_id = pick.item.container().id();
                 assert!(self.tcx().impl_trait_ref(impl_def_id).is_none(),
                         "impl {:?} is not an inherent impl", impl_def_id);
-                let impl_polytype = check::impl_self_ty(self.fcx, self.span, impl_def_id);
-
-                (impl_polytype.substs, MethodStatic(pick.item.def_id()))
+                check::impl_self_ty(self.fcx, self.span, impl_def_id).substs
             }
 
-            probe::ObjectPick(trait_def_id, method_num, vtable_index) => {
+            probe::ObjectPick => {
+                let trait_def_id = pick.item.container().id();
                 self.extract_trait_ref(self_ty, |this, object_ty, data| {
                     // The object data has no entry for the Self
                     // Type. For the purposes of this method call, we
@@ -227,18 +224,11 @@ impl<'a,'tcx> ConfirmContext<'a,'tcx> {
                            original_poly_trait_ref,
                            upcast_trait_ref,
                            trait_def_id);
-                    let substs = upcast_trait_ref.substs.clone();
-                    let origin = MethodTraitObject(MethodObject {
-                        trait_ref: upcast_trait_ref,
-                        object_trait_id: trait_def_id,
-                        method_num: method_num,
-                        vtable_index: vtable_index,
-                    });
-                    (substs, origin)
+                    upcast_trait_ref.substs.clone()
                 })
             }
 
-            probe::ExtensionImplPick(impl_def_id, method_num) => {
+            probe::ExtensionImplPick(impl_def_id) => {
                 // The method being invoked is the method as defined on the trait,
                 // so return the substitutions from the trait. Consider:
                 //
@@ -254,13 +244,11 @@ impl<'a,'tcx> ConfirmContext<'a,'tcx> {
                         self.span,
                         &impl_polytype.substs,
                         &self.tcx().impl_trait_ref(impl_def_id).unwrap());
-                let origin = MethodTypeParam(MethodParam { trait_ref: impl_trait_ref.clone(),
-                                                           method_num: method_num,
-                                                           impl_def_id: Some(impl_def_id) });
-                (impl_trait_ref.substs.clone(), origin)
+                impl_trait_ref.substs.clone()
             }
 
-            probe::TraitPick(trait_def_id, method_num) => {
+            probe::TraitPick => {
+                let trait_def_id = pick.item.container().id();
                 let trait_def = self.tcx().lookup_trait_def(trait_def_id);
 
                 // Make a trait reference `$0 : Trait<$1...$n>`
@@ -268,27 +256,15 @@ impl<'a,'tcx> ConfirmContext<'a,'tcx> {
                 // the process we will unify the transformed-self-type
                 // of the method with the actual type in order to
                 // unify some of these variables.
-                let substs = self.infcx().fresh_substs_for_trait(self.span,
-                                                                 &trait_def.generics,
-                                                                 self.infcx().next_ty_var());
-
-                let trait_ref =
-                    ty::TraitRef::new(trait_def_id, self.tcx().mk_substs(substs.clone()));
-                let origin = MethodTypeParam(MethodParam { trait_ref: trait_ref,
-                                                           method_num: method_num,
-                                                           impl_def_id: None });
-                (substs, origin)
+                self.infcx().fresh_substs_for_trait(self.span,
+                                                    &trait_def.generics,
+                                                    self.infcx().next_ty_var())
             }
 
-            probe::WhereClausePick(ref poly_trait_ref, method_num) => {
+            probe::WhereClausePick(ref poly_trait_ref) => {
                 // Where clauses can have bound regions in them. We need to instantiate
                 // those to convert from a poly-trait-ref to a trait-ref.
-                let trait_ref = self.replace_late_bound_regions_with_fresh_var(&*poly_trait_ref);
-                let substs = trait_ref.substs.clone();
-                let origin = MethodTypeParam(MethodParam { trait_ref: trait_ref,
-                                                           method_num: method_num,
-                                                           impl_def_id: None });
-                (substs, origin)
+                self.replace_late_bound_regions_with_fresh_var(&*poly_trait_ref).substs.clone()
             }
         }
     }
@@ -450,7 +426,7 @@ impl<'a,'tcx> ConfirmContext<'a,'tcx> {
     /// auto-derefs, indices, etc from `Deref` and `Index` into `DerefMut` and `IndexMut`
     /// respectively.
     fn fixup_derefs_on_method_receiver_if_necessary(&self,
-                                                    method_callee: &MethodCallee) {
+                                                    method_callee: &ty::MethodCallee) {
         let sig = match method_callee.ty.sty {
             ty::TyBareFn(_, ref f) => f.sig.clone(),
             _ => return,
@@ -570,7 +546,7 @@ impl<'a,'tcx> ConfirmContext<'a,'tcx> {
 
                         let result = check::try_index_step(
                             self.fcx,
-                            MethodCall::expr(expr.id),
+                            ty::MethodCall::expr(expr.id),
                             expr,
                             &**base_expr,
                             adjusted_base_ty,
@@ -589,7 +565,7 @@ impl<'a,'tcx> ConfirmContext<'a,'tcx> {
                     ast::ExprUnary(ast::UnDeref, ref base_expr) => {
                         // if this is an overloaded deref, then re-evaluate with
                         // a preference for mut
-                        let method_call = MethodCall::expr(expr.id);
+                        let method_call = ty::MethodCall::expr(expr.id);
                         if self.fcx.inh.tables.borrow().method_map.contains_key(&method_call) {
                             check::try_overloaded_deref(
                                 self.fcx,
diff --git a/src/librustc_typeck/check/method/mod.rs b/src/librustc_typeck/check/method/mod.rs
index 7ed5c69ad61..2117cba1087 100644
--- a/src/librustc_typeck/check/method/mod.rs
+++ b/src/librustc_typeck/check/method/mod.rs
@@ -74,8 +74,6 @@ pub enum CandidateSource {
     TraitSource(/* trait id */ ast::DefId),
 }
 
-type ItemIndex = usize; // just for doc purposes
-
 /// Determines whether the type `self_ty` supports a method name `method_name` or not.
 pub fn exists<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
                         span: Span,
@@ -204,14 +202,13 @@ pub fn lookup_in_trait_adjusted<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
     // Trait must have a method named `m_name` and it should not have
     // type parameters or early-bound regions.
     let tcx = fcx.tcx();
-    let (method_num, method_ty) = trait_item(tcx, trait_def_id, m_name)
-            .and_then(|(idx, item)| item.as_opt_method().map(|m| (idx, m)))
-            .unwrap();
+    let method_item = trait_item(tcx, trait_def_id, m_name).unwrap();
+    let method_ty = method_item.as_opt_method().unwrap();
     assert_eq!(method_ty.generics.types.len(subst::FnSpace), 0);
     assert_eq!(method_ty.generics.regions.len(subst::FnSpace), 0);
 
-    debug!("lookup_in_trait_adjusted: method_num={} method_ty={:?}",
-           method_num, method_ty);
+    debug!("lookup_in_trait_adjusted: method_item={:?} method_ty={:?}",
+           method_item, method_ty);
 
     // Instantiate late-bound regions and substitute the trait
     // parameters into the method type to get the actual method type.
@@ -309,11 +306,9 @@ pub fn lookup_in_trait_adjusted<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
     }
 
     let callee = ty::MethodCallee {
-        origin: ty::MethodTypeParam(ty::MethodParam{trait_ref: trait_ref.clone(),
-                                                    method_num: method_num,
-                                                    impl_def_id: None}),
+        def_id: method_item.def_id(),
         ty: fty,
-        substs: trait_ref.substs.clone()
+        substs: trait_ref.substs
     };
 
     debug!("callee = {:?}", callee);
@@ -332,14 +327,15 @@ pub fn resolve_ufcs<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
     let pick = try!(probe::probe(fcx, span, mode, method_name, self_ty, expr_id));
     let def_id = pick.item.def_id();
     let mut lp = LastMod(AllPublic);
+    let container_def_id = pick.item.container().id();
     let provenance = match pick.kind {
-        probe::InherentImplPick(impl_def_id) => {
+        probe::InherentImplPick => {
             if pick.item.vis() != ast::Public {
                 lp = LastMod(DependsOn(def_id));
             }
-            def::FromImpl(impl_def_id)
+            def::FromImpl(container_def_id)
         }
-        _ => def::FromTrait(pick.item.container().id())
+        _ => def::FromTrait(container_def_id)
     };
     let def_result = match pick.item {
         ty::ImplOrTraitItem::MethodTraitItem(..) => def::DefMethod(def_id, provenance),
@@ -352,19 +348,17 @@ pub fn resolve_ufcs<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
 }
 
 
-/// Find item with name `item_name` defined in `trait_def_id` and return it, along with its
-/// index (or `None`, if no such item).
+/// Find item with name `item_name` defined in `trait_def_id`
+/// and return it, or `None`, if no such item.
 fn trait_item<'tcx>(tcx: &ty::ctxt<'tcx>,
                     trait_def_id: ast::DefId,
                     item_name: ast::Name)
-                    -> Option<(usize, ty::ImplOrTraitItem<'tcx>)>
+                    -> Option<ty::ImplOrTraitItem<'tcx>>
 {
     let trait_items = tcx.trait_items(trait_def_id);
-    trait_items
-        .iter()
-        .enumerate()
-        .find(|&(_, ref item)| item.name() == item_name)
-        .map(|(num, item)| (num, (*item).clone()))
+    trait_items.iter()
+               .find(|item| item.name() == item_name)
+               .cloned()
 }
 
 fn impl_item<'tcx>(tcx: &ty::ctxt<'tcx>,
diff --git a/src/librustc_typeck/check/method/probe.rs b/src/librustc_typeck/check/method/probe.rs
index 8eb4716cb2a..c43046ba0e7 100644
--- a/src/librustc_typeck/check/method/probe.rs
+++ b/src/librustc_typeck/check/method/probe.rs
@@ -10,7 +10,6 @@
 
 use super::MethodError;
 use super::NoMatchData;
-use super::ItemIndex;
 use super::{CandidateSource, ImplSource, TraitSource};
 use super::suggest;
 
@@ -70,15 +69,13 @@ struct Candidate<'tcx> {
 
 #[derive(Debug)]
 enum CandidateKind<'tcx> {
-    InherentImplCandidate(/* Impl */ ast::DefId, subst::Substs<'tcx>,
+    InherentImplCandidate(subst::Substs<'tcx>,
                           /* Normalize obligations */ Vec<traits::PredicateObligation<'tcx>>),
-    ObjectCandidate(/* Trait */ ast::DefId, /* method_num */ usize, /* vtable index */ usize),
-    ExtensionImplCandidate(/* Impl */ ast::DefId, ty::TraitRef<'tcx>,
-                           subst::Substs<'tcx>, ItemIndex,
+    ExtensionImplCandidate(/* Impl */ ast::DefId, subst::Substs<'tcx>,
                            /* Normalize obligations */ Vec<traits::PredicateObligation<'tcx>>),
-    ClosureCandidate(/* Trait */ ast::DefId, ItemIndex),
-    WhereClauseCandidate(ty::PolyTraitRef<'tcx>, ItemIndex),
-    ProjectionCandidate(ast::DefId, ItemIndex),
+    ObjectCandidate,
+    TraitCandidate,
+    WhereClauseCandidate(/* Trait */ ty::PolyTraitRef<'tcx>),
 }
 
 #[derive(Debug)]
@@ -106,11 +103,11 @@ pub struct Pick<'tcx> {
 
 #[derive(Clone,Debug)]
 pub enum PickKind<'tcx> {
-    InherentImplPick(/* Impl */ ast::DefId),
-    ObjectPick(/* Trait */ ast::DefId, /* method_num */ usize, /* real_index */ usize),
-    ExtensionImplPick(/* Impl */ ast::DefId, ItemIndex),
-    TraitPick(/* Trait */ ast::DefId, ItemIndex),
-    WhereClausePick(/* Trait */ ty::PolyTraitRef<'tcx>, ItemIndex),
+    InherentImplPick,
+    ExtensionImplPick(/* Impl */ ast::DefId),
+    ObjectPick,
+    TraitPick,
+    WhereClausePick(/* Trait */ ty::PolyTraitRef<'tcx>),
 }
 
 pub type PickResult<'tcx> = Result<Pick<'tcx>, MethodError<'tcx>>;
@@ -430,7 +427,7 @@ impl<'a,'tcx> ProbeContext<'a,'tcx> {
         self.inherent_candidates.push(Candidate {
             xform_self_ty: xform_self_ty,
             item: item,
-            kind: InherentImplCandidate(impl_def_id, impl_substs, obligations)
+            kind: InherentImplCandidate(impl_substs, obligations)
         });
     }
 
@@ -440,8 +437,6 @@ impl<'a,'tcx> ProbeContext<'a,'tcx> {
         debug!("assemble_inherent_candidates_from_object(self_ty={:?})",
                self_ty);
 
-        let tcx = self.tcx();
-
         // It is illegal to invoke a method on a trait instance that
         // refers to the `Self` type. An error will be reported by
         // `enforce_object_limitations()` if the method refers to the
@@ -450,15 +445,9 @@ impl<'a,'tcx> ProbeContext<'a,'tcx> {
         // itself. Hence, a `&self` method will wind up with an
         // argument type like `&Trait`.
         let trait_ref = data.principal_trait_ref_with_self_ty(self.tcx(), self_ty);
-        self.elaborate_bounds(&[trait_ref.clone()], |this, new_trait_ref, item, item_num| {
+        self.elaborate_bounds(&[trait_ref], |this, new_trait_ref, item| {
             let new_trait_ref = this.erase_late_bound_regions(&new_trait_ref);
 
-            let vtable_index =
-                traits::get_vtable_index_of_object_method(tcx,
-                                                          trait_ref.clone(),
-                                                          new_trait_ref.def_id,
-                                                          item_num);
-
             let xform_self_ty = this.xform_self_ty(&item,
                                                    new_trait_ref.self_ty(),
                                                    new_trait_ref.substs);
@@ -466,7 +455,7 @@ impl<'a,'tcx> ProbeContext<'a,'tcx> {
             this.inherent_candidates.push(Candidate {
                 xform_self_ty: xform_self_ty,
                 item: item,
-                kind: ObjectCandidate(new_trait_ref.def_id, item_num, vtable_index)
+                kind: ObjectCandidate
             });
         });
     }
@@ -499,7 +488,7 @@ impl<'a,'tcx> ProbeContext<'a,'tcx> {
             })
             .collect();
 
-        self.elaborate_bounds(&bounds, |this, poly_trait_ref, item, item_num| {
+        self.elaborate_bounds(&bounds, |this, poly_trait_ref, item| {
             let trait_ref =
                 this.erase_late_bound_regions(&poly_trait_ref);
 
@@ -533,7 +522,7 @@ impl<'a,'tcx> ProbeContext<'a,'tcx> {
             this.inherent_candidates.push(Candidate {
                 xform_self_ty: xform_self_ty,
                 item: item,
-                kind: WhereClauseCandidate(poly_trait_ref, item_num)
+                kind: WhereClauseCandidate(poly_trait_ref)
             });
         });
     }
@@ -549,16 +538,15 @@ impl<'a,'tcx> ProbeContext<'a,'tcx> {
             &mut ProbeContext<'b, 'tcx>,
             ty::PolyTraitRef<'tcx>,
             ty::ImplOrTraitItem<'tcx>,
-            usize,
         ),
     {
         debug!("elaborate_bounds(bounds={:?})", bounds);
 
         let tcx = self.tcx();
         for bound_trait_ref in traits::transitive_bounds(tcx, bounds) {
-            let (pos, item) = match trait_item(tcx,
-                                               bound_trait_ref.def_id(),
-                                               self.item_name) {
+            let item = match trait_item(tcx,
+                                        bound_trait_ref.def_id(),
+                                        self.item_name) {
                 Some(v) => v,
                 None => { continue; }
             };
@@ -566,7 +554,7 @@ impl<'a,'tcx> ProbeContext<'a,'tcx> {
             if !self.has_applicable_self(&item) {
                 self.record_static_candidate(TraitSource(bound_trait_ref.def_id()));
             } else {
-                mk_cand(self, bound_trait_ref, item, pos);
+                mk_cand(self, bound_trait_ref, item);
             }
         }
     }
@@ -607,14 +595,13 @@ impl<'a,'tcx> ProbeContext<'a,'tcx> {
         // Check whether `trait_def_id` defines a method with suitable name:
         let trait_items =
             self.tcx().trait_items(trait_def_id);
-        let matching_index =
+        let maybe_item =
             trait_items.iter()
-                       .position(|item| item.name() == self.item_name);
-        let matching_index = match matching_index {
+                       .find(|item| item.name() == self.item_name);
+        let item = match maybe_item {
             Some(i) => i,
             None => { return Ok(()); }
         };
-        let ref item = (&*trait_items)[matching_index];
 
         // Check whether `trait_def_id` defines a method with suitable name:
         if !self.has_applicable_self(item) {
@@ -623,29 +610,20 @@ impl<'a,'tcx> ProbeContext<'a,'tcx> {
             return Ok(());
         }
 
-        self.assemble_extension_candidates_for_trait_impls(trait_def_id,
-                                                           item.clone(),
-                                                           matching_index);
+        self.assemble_extension_candidates_for_trait_impls(trait_def_id, item.clone());
 
-        try!(self.assemble_closure_candidates(trait_def_id,
-                                              item.clone(),
-                                              matching_index));
+        try!(self.assemble_closure_candidates(trait_def_id, item.clone()));
 
-        self.assemble_projection_candidates(trait_def_id,
-                                            item.clone(),
-                                            matching_index);
+        self.assemble_projection_candidates(trait_def_id, item.clone());
 
-        self.assemble_where_clause_candidates(trait_def_id,
-                                              item.clone(),
-                                              matching_index);
+        self.assemble_where_clause_candidates(trait_def_id, item.clone());
 
         Ok(())
     }
 
     fn assemble_extension_candidates_for_trait_impls(&mut self,
                                                      trait_def_id: ast::DefId,
-                                                     item: ty::ImplOrTraitItem<'tcx>,
-                                                     item_index: usize)
+                                                     item: ty::ImplOrTraitItem<'tcx>)
     {
         let trait_def = self.tcx().lookup_trait_def(trait_def_id);
 
@@ -690,11 +668,7 @@ impl<'a,'tcx> ProbeContext<'a,'tcx> {
             self.extension_candidates.push(Candidate {
                 xform_self_ty: xform_self_ty,
                 item: item.clone(),
-                kind: ExtensionImplCandidate(impl_def_id,
-                                             impl_trait_ref,
-                                             impl_substs,
-                                             item_index,
-                                             obligations)
+                kind: ExtensionImplCandidate(impl_def_id, impl_substs, obligations)
             });
         });
     }
@@ -717,8 +691,7 @@ impl<'a,'tcx> ProbeContext<'a,'tcx> {
 
     fn assemble_closure_candidates(&mut self,
                                    trait_def_id: ast::DefId,
-                                   item: ty::ImplOrTraitItem<'tcx>,
-                                   item_index: usize)
+                                   item: ty::ImplOrTraitItem<'tcx>)
                                    -> Result<(), MethodError<'tcx>>
     {
         // Check if this is one of the Fn,FnMut,FnOnce traits.
@@ -770,7 +743,7 @@ impl<'a,'tcx> ProbeContext<'a,'tcx> {
             self.inherent_candidates.push(Candidate {
                 xform_self_ty: xform_self_ty,
                 item: item.clone(),
-                kind: ClosureCandidate(trait_def_id, item_index)
+                kind: TraitCandidate
             });
         }
 
@@ -779,16 +752,13 @@ impl<'a,'tcx> ProbeContext<'a,'tcx> {
 
     fn assemble_projection_candidates(&mut self,
                                       trait_def_id: ast::DefId,
-                                      item: ty::ImplOrTraitItem<'tcx>,
-                                      item_index: usize)
+                                      item: ty::ImplOrTraitItem<'tcx>)
     {
         debug!("assemble_projection_candidates(\
                trait_def_id={:?}, \
-               item={:?}, \
-               item_index={})",
+               item={:?})",
                trait_def_id,
-               item,
-               item_index);
+               item);
 
         for step in self.steps.iter() {
             debug!("assemble_projection_candidates: step={:?}",
@@ -830,7 +800,7 @@ impl<'a,'tcx> ProbeContext<'a,'tcx> {
                     self.extension_candidates.push(Candidate {
                         xform_self_ty: xform_self_ty,
                         item: item.clone(),
-                        kind: ProjectionCandidate(trait_def_id, item_index)
+                        kind: TraitCandidate
                     });
                 }
             }
@@ -839,8 +809,7 @@ impl<'a,'tcx> ProbeContext<'a,'tcx> {
 
     fn assemble_where_clause_candidates(&mut self,
                                         trait_def_id: ast::DefId,
-                                        item: ty::ImplOrTraitItem<'tcx>,
-                                        item_index: usize)
+                                        item: ty::ImplOrTraitItem<'tcx>)
     {
         debug!("assemble_where_clause_candidates(trait_def_id={:?})",
                trait_def_id);
@@ -862,7 +831,7 @@ impl<'a,'tcx> ProbeContext<'a,'tcx> {
             self.extension_candidates.push(Candidate {
                 xform_self_ty: xform_self_ty,
                 item: item.clone(),
-                kind: WhereClauseCandidate(poly_bound, item_index)
+                kind: WhereClauseCandidate(poly_bound)
             });
         }
     }
@@ -1048,8 +1017,7 @@ impl<'a,'tcx> ProbeContext<'a,'tcx> {
         }
 
         applicable_candidates.pop().map(|probe| {
-            let pick = probe.to_unadjusted_pick();
-            Ok(pick)
+            Ok(probe.to_unadjusted_pick())
         })
     }
 
@@ -1073,48 +1041,52 @@ impl<'a,'tcx> ProbeContext<'a,'tcx> {
             // clauses) that must be considered. Make sure that those
             // match as well (or at least may match, sometimes we
             // don't have enough information to fully evaluate).
-            match probe.kind {
-                InherentImplCandidate(impl_def_id, ref substs, ref ref_obligations) |
-                ExtensionImplCandidate(impl_def_id, _, ref substs, _, ref ref_obligations) => {
-                    let selcx = &mut traits::SelectionContext::new(self.infcx());
-                    let cause = traits::ObligationCause::misc(self.span, self.fcx.body_id);
-
-                    // Check whether the impl imposes obligations we have to worry about.
-                    let impl_bounds = self.tcx().lookup_predicates(impl_def_id);
-                    let impl_bounds = impl_bounds.instantiate(self.tcx(), substs);
-                    let traits::Normalized { value: impl_bounds,
-                                             obligations: norm_obligations } =
-                        traits::normalize(selcx, cause.clone(), &impl_bounds);
-
-                    // Convert the bounds into obligations.
-                    let obligations =
-                        traits::predicates_for_generics(cause.clone(),
-                                                        &impl_bounds);
-                    debug!("impl_obligations={:?}", obligations);
-
-                    // Evaluate those obligations to see if they might possibly hold.
-                    let mut all_true = true;
-                    for o in obligations.iter()
-                        .chain(norm_obligations.iter())
-                        .chain(ref_obligations.iter()) {
-                        if !selcx.evaluate_obligation(o) {
-                            all_true = false;
-                            if let &ty::Predicate::Trait(ref pred) = &o.predicate {
-                                possibly_unsatisfied_predicates.push(pred.0.trait_ref);
-                            }
-                        }
-                    }
-                    all_true
+            let (impl_def_id, substs, ref_obligations) = match probe.kind {
+                InherentImplCandidate(ref substs, ref ref_obligations) => {
+                    (probe.item.container().id(), substs, ref_obligations)
+                }
+
+                ExtensionImplCandidate(impl_def_id, ref substs, ref ref_obligations) => {
+                    (impl_def_id, substs, ref_obligations)
                 }
 
-                ProjectionCandidate(..) |
                 ObjectCandidate(..) |
-                ClosureCandidate(..) |
+                TraitCandidate |
                 WhereClauseCandidate(..) => {
                     // These have no additional conditions to check.
-                    true
+                    return true;
+                }
+            };
+
+            let selcx = &mut traits::SelectionContext::new(self.infcx());
+            let cause = traits::ObligationCause::misc(self.span, self.fcx.body_id);
+
+            // Check whether the impl imposes obligations we have to worry about.
+            let impl_bounds = self.tcx().lookup_predicates(impl_def_id);
+            let impl_bounds = impl_bounds.instantiate(self.tcx(), substs);
+            let traits::Normalized { value: impl_bounds,
+                                        obligations: norm_obligations } =
+                traits::normalize(selcx, cause.clone(), &impl_bounds);
+
+            // Convert the bounds into obligations.
+            let obligations =
+                traits::predicates_for_generics(cause.clone(),
+                                                &impl_bounds);
+            debug!("impl_obligations={:?}", obligations);
+
+            // Evaluate those obligations to see if they might possibly hold.
+            let mut all_true = true;
+            for o in obligations.iter()
+                .chain(norm_obligations.iter())
+                .chain(ref_obligations.iter()) {
+                if !selcx.evaluate_obligation(o) {
+                    all_true = false;
+                    if let &ty::Predicate::Trait(ref pred) = &o.predicate {
+                        possibly_unsatisfied_predicates.push(pred.0.trait_ref);
+                    }
                 }
             }
+            all_true
         })
     }
 
@@ -1139,20 +1111,19 @@ impl<'a,'tcx> ProbeContext<'a,'tcx> {
                                          probes: &[&Candidate<'tcx>])
                                          -> Option<Pick<'tcx>> {
         // Do all probes correspond to the same trait?
-        let trait_data = match probes[0].to_trait_data() {
-            Some(data) => data,
-            None => return None,
-        };
-        if probes[1..].iter().any(|p| p.to_trait_data() != Some(trait_data)) {
+        let container = probes[0].item.container();
+        match container {
+            ty::TraitContainer(_) => {}
+            ty::ImplContainer(_) => return None
+        }
+        if probes[1..].iter().any(|p| p.item.container() != container) {
             return None;
         }
 
         // If so, just use this trait and call it a day.
-        let (trait_def_id, item_num) = trait_data;
-        let item = probes[0].item.clone();
         Some(Pick {
-            item: item,
-            kind: TraitPick(trait_def_id, item_num),
+            item: probes[0].item.clone(),
+            kind: TraitPick,
             autoderefs: 0,
             autoref: None,
             unsize: None
@@ -1317,20 +1288,18 @@ fn impl_item<'tcx>(tcx: &ty::ctxt<'tcx>,
         .find(|item| item.name() == item_name)
 }
 
-/// Find item with name `item_name` defined in `trait_def_id` and return it,
-/// along with its index (or `None`, if no such item).
+/// Find item with name `item_name` defined in `trait_def_id`
+/// and return it, or `None`, if no such item.
 fn trait_item<'tcx>(tcx: &ty::ctxt<'tcx>,
                     trait_def_id: ast::DefId,
                     item_name: ast::Name)
-                    -> Option<(usize, ty::ImplOrTraitItem<'tcx>)>
+                    -> Option<ty::ImplOrTraitItem<'tcx>>
 {
     let trait_items = tcx.trait_items(trait_def_id);
     debug!("trait_method; items: {:?}", trait_items);
-    trait_items
-        .iter()
-        .enumerate()
-        .find(|&(_, ref item)| item.name() == item_name)
-        .map(|(num, ref item)| (num, (*item).clone()))
+    trait_items.iter()
+               .find(|item| item.name() == item_name)
+               .cloned()
 }
 
 impl<'tcx> Candidate<'tcx> {
@@ -1338,19 +1307,13 @@ impl<'tcx> Candidate<'tcx> {
         Pick {
             item: self.item.clone(),
             kind: match self.kind {
-                InherentImplCandidate(def_id, _, _) => {
-                    InherentImplPick(def_id)
-                }
-                ObjectCandidate(def_id, item_num, real_index) => {
-                    ObjectPick(def_id, item_num, real_index)
-                }
-                ExtensionImplCandidate(def_id, _, _, index, _) => {
-                    ExtensionImplPick(def_id, index)
+                InherentImplCandidate(_, _) => InherentImplPick,
+                ExtensionImplCandidate(def_id, _, _) => {
+                    ExtensionImplPick(def_id)
                 }
-                ClosureCandidate(trait_def_id, index) => {
-                    TraitPick(trait_def_id, index)
-                }
-                WhereClauseCandidate(ref trait_ref, index) => {
+                ObjectCandidate => ObjectPick,
+                TraitCandidate => TraitPick,
+                WhereClauseCandidate(ref trait_ref) => {
                     // Only trait derived from where-clauses should
                     // appear here, so they should not contain any
                     // inference variables or other artifacts. This
@@ -1358,10 +1321,7 @@ impl<'tcx> Candidate<'tcx> {
                     // `WhereClausePick`.
                     assert!(!trait_ref.substs().types.needs_infer());
 
-                    WhereClausePick((*trait_ref).clone(), index)
-                }
-                ProjectionCandidate(def_id, index) => {
-                    TraitPick(def_id, index)
+                    WhereClausePick(trait_ref.clone())
                 }
             },
             autoderefs: 0,
@@ -1372,35 +1332,13 @@ impl<'tcx> Candidate<'tcx> {
 
     fn to_source(&self) -> CandidateSource {
         match self.kind {
-            InherentImplCandidate(def_id, _, _) => ImplSource(def_id),
-            ObjectCandidate(def_id, _, _) => TraitSource(def_id),
-            ExtensionImplCandidate(def_id, _, _, _, _) => ImplSource(def_id),
-            ClosureCandidate(trait_def_id, _) => TraitSource(trait_def_id),
-            WhereClauseCandidate(ref trait_ref, _) => TraitSource(trait_ref.def_id()),
-            ProjectionCandidate(trait_def_id, _) => TraitSource(trait_def_id),
-        }
-    }
-
-    fn to_trait_data(&self) -> Option<(ast::DefId, ItemIndex)> {
-        match self.kind {
-            InherentImplCandidate(..) => {
-                None
-            }
-            ObjectCandidate(trait_def_id, item_num, _) => {
-                Some((trait_def_id, item_num))
-            }
-            ClosureCandidate(trait_def_id, item_num) => {
-                Some((trait_def_id, item_num))
-            }
-            ExtensionImplCandidate(_, ref trait_ref, _, item_num, _) => {
-                Some((trait_ref.def_id, item_num))
-            }
-            WhereClauseCandidate(ref trait_ref, item_num) => {
-                Some((trait_ref.def_id(), item_num))
-            }
-            ProjectionCandidate(trait_def_id, item_num) => {
-                Some((trait_def_id, item_num))
+            InherentImplCandidate(_, _) => {
+                ImplSource(self.item.container().id())
             }
+            ExtensionImplCandidate(def_id, _, _) => ImplSource(def_id),
+            ObjectCandidate |
+            TraitCandidate |
+            WhereClauseCandidate(_) => TraitSource(self.item.container().id()),
         }
     }
 }
diff --git a/src/librustc_typeck/check/method/suggest.rs b/src/librustc_typeck/check/method/suggest.rs
index d6a8b3583f8..4d86a4f7c70 100644
--- a/src/librustc_typeck/check/method/suggest.rs
+++ b/src/librustc_typeck/check/method/suggest.rs
@@ -203,7 +203,7 @@ pub fn report_error<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
                                impl_ty);
                 }
                 CandidateSource::TraitSource(trait_did) => {
-                    let (_, item) = trait_item(fcx.tcx(), trait_did, item_name).unwrap();
+                    let item = trait_item(fcx.tcx(), trait_did, item_name).unwrap();
                     let item_span = fcx.tcx().map.def_id_span(item.def_id(), span);
                     span_note!(fcx.sess(), item_span,
                                "candidate #{} is defined in the trait `{}`",
diff --git a/src/librustc_typeck/check/writeback.rs b/src/librustc_typeck/check/writeback.rs
index 1fc7224737d..419fa9e160a 100644
--- a/src/librustc_typeck/check/writeback.rs
+++ b/src/librustc_typeck/check/writeback.rs
@@ -302,9 +302,9 @@ impl<'cx, 'tcx> WritebackCx<'cx, 'tcx> {
                        method_call,
                        method);
                 let new_method = MethodCallee {
-                    origin: self.resolve(&method.origin, reason),
+                    def_id: method.def_id,
                     ty: self.resolve(&method.ty, reason),
-                    substs: self.resolve(&method.substs, reason),
+                    substs: self.tcx().mk_substs(self.resolve(method.substs, reason)),
                 };
 
                 Some(new_method)
diff --git a/src/test/run-pass/traits-issue-26339.rs b/src/test/run-pass/traits-issue-26339.rs
new file mode 100644
index 00000000000..f2cf1779d62
--- /dev/null
+++ b/src/test/run-pass/traits-issue-26339.rs
@@ -0,0 +1,40 @@
+// Copyright 2015 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.
+
+// Test that the right implementation is called through a trait
+// object when supertraits include multiple references to the
+// same trait, with different type parameters.
+
+trait A: PartialEq<Foo> + PartialEq<Bar> { }
+
+struct Foo;
+struct Bar;
+
+struct Aimpl;
+
+impl PartialEq<Foo> for Aimpl {
+    fn eq(&self, _rhs: &Foo) -> bool {
+        true
+    }
+}
+
+impl PartialEq<Bar> for Aimpl {
+    fn eq(&self, _rhs: &Bar) -> bool {
+        false
+    }
+}
+
+impl A for Aimpl { }
+
+fn main() {
+    let a = &Aimpl as &A;
+
+    assert!(*a == Foo);
+}