about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--src/librustc/middle/ty.rs11
-rw-r--r--src/librustc/middle/typeck/check/method.rs1234
-rw-r--r--src/librustc/middle/typeck/check/mod.rs48
-rw-r--r--src/libsyntax/ast_map/mod.rs8
4 files changed, 640 insertions, 661 deletions
diff --git a/src/librustc/middle/ty.rs b/src/librustc/middle/ty.rs
index dbaebd07b02..71855f38ba2 100644
--- a/src/librustc/middle/ty.rs
+++ b/src/librustc/middle/ty.rs
@@ -120,6 +120,13 @@ impl ImplOrTraitItem {
             TypeTraitItem(ref associated_type) => associated_type.container,
         }
     }
+
+    pub fn as_opt_method(&self) -> Option<Rc<Method>> {
+        match *self {
+            MethodTraitItem(ref m) => Some((*m).clone()),
+            TypeTraitItem(_) => None
+        }
+    }
 }
 
 #[deriving(Clone)]
@@ -1240,6 +1247,10 @@ impl Generics {
 }
 
 impl TraitRef {
+    pub fn new(def_id: ast::DefId, substs: Substs) -> TraitRef {
+        TraitRef { def_id: def_id, substs: substs }
+    }
+
     pub fn self_ty(&self) -> ty::t {
         self.substs.self_ty().unwrap()
     }
diff --git a/src/librustc/middle/typeck/check/method.rs b/src/librustc/middle/typeck/check/method.rs
index 9399c3a475a..4560c519464 100644
--- a/src/librustc/middle/typeck/check/method.rs
+++ b/src/librustc/middle/typeck/check/method.rs
@@ -81,30 +81,31 @@ obtained the type `Foo`, we would never match this method.
 
 
 use middle::subst;
-use middle::subst::Subst;
+use middle::subst::{Subst, SelfSpace};
 use middle::traits;
 use middle::ty::*;
 use middle::ty;
 use middle::typeck::astconv::AstConv;
 use middle::typeck::check::{FnCtxt, NoPreference, PreferMutLvalue};
 use middle::typeck::check::{impl_self_ty};
+use middle::typeck::check::vtable2::select_fcx_obligations_where_possible;
 use middle::typeck::check;
 use middle::typeck::infer;
 use middle::typeck::{MethodCall, MethodCallee};
 use middle::typeck::{MethodOrigin, MethodParam, MethodTypeParam};
 use middle::typeck::{MethodStatic, MethodStaticUnboxedClosure, MethodObject, MethodTraitObject};
-use middle::typeck::check::regionmanip::replace_late_bound_regions_in_fn_sig;
+use middle::typeck::check::regionmanip::replace_late_bound_regions;
 use middle::typeck::TypeAndSubsts;
+use middle::ty_fold::TypeFoldable;
 use util::common::indenter;
 use util::ppaux;
-use util::ppaux::Repr;
+use util::ppaux::{Repr, UserString};
 
 use std::collections::HashSet;
 use std::rc::Rc;
 use syntax::ast::{DefId, MutImmutable, MutMutable};
 use syntax::ast;
 use syntax::codemap::Span;
-use syntax::parse::token;
 
 #[deriving(PartialEq)]
 pub enum CheckTraitsFlag {
@@ -118,26 +119,31 @@ pub enum AutoderefReceiverFlag {
     DontAutoderefReceiver,
 }
 
-#[deriving(PartialEq)]
-pub enum StaticMethodsFlag {
-    ReportStaticMethods,
-    IgnoreStaticMethods,
+pub enum MethodError {
+    // Did not find an applicable method, but we did find various
+    // static methods that may apply.
+    NoMatch(Vec<CandidateSource>),
+
+    // Multiple methods might apply.
+    Ambiguity(Vec<CandidateSource>),
 }
 
+pub type MethodResult = Result<MethodCallee, MethodError>;
+
 pub fn lookup<'a, 'tcx>(
-        fcx: &'a FnCtxt<'a, 'tcx>,
-
-        // In a call `a.b::<X, Y, ...>(...)`:
-        expr: &ast::Expr,                   // The expression `a.b(...)`.
-        self_expr: &'a ast::Expr,           // The expression `a`.
-        m_name: ast::Name,                  // The name `b`.
-        self_ty: ty::t,                     // The type of `a`.
-        supplied_tps: &'a [ty::t],          // The list of types X, Y, ... .
-        deref_args: check::DerefArgs,       // Whether we autopointer first.
-        check_traits: CheckTraitsFlag,      // Whether we check traits only.
-        autoderef_receiver: AutoderefReceiverFlag,
-        report_statics: StaticMethodsFlag)
-     -> Option<MethodCallee> {
+    fcx: &'a FnCtxt<'a, 'tcx>,
+
+    // In a call `a.b::<X, Y, ...>(...)`:
+    expr: &ast::Expr,                   // The expression `a.b(...)`.
+    self_expr: &'a ast::Expr,           // The expression `a`.
+    m_name: ast::Name,                  // The name `b`.
+    self_ty: ty::t,                     // The type of `a`.
+    supplied_tps: &'a [ty::t],          // The list of types X, Y, ... .
+    deref_args: check::DerefArgs,       // Whether we autopointer first.
+    check_traits: CheckTraitsFlag,      // Whether we check traits only.
+    autoderef_receiver: AutoderefReceiverFlag)
+    -> MethodResult
+{
     let mut lcx = LookupContext {
         fcx: fcx,
         span: expr.span,
@@ -147,10 +153,10 @@ pub fn lookup<'a, 'tcx>(
         impl_dups: HashSet::new(),
         inherent_candidates: Vec::new(),
         extension_candidates: Vec::new(),
+        static_candidates: Vec::new(),
         deref_args: deref_args,
         check_traits: check_traits,
         autoderef_receiver: autoderef_receiver,
-        report_statics: report_statics,
     };
 
     debug!("method lookup(self_ty={}, expr={}, self_expr={})",
@@ -166,16 +172,17 @@ pub fn lookup<'a, 'tcx>(
 }
 
 pub fn lookup_in_trait<'a, 'tcx>(
-        fcx: &'a FnCtxt<'a, 'tcx>,
-
-        // In a call `a.b::<X, Y, ...>(...)`:
-        span: Span,                         // The expression `a.b(...)`'s span.
-        self_expr: Option<&'a ast::Expr>,   // The expression `a`, if available.
-        m_name: ast::Name,                  // The name `b`.
-        trait_did: DefId,                   // The trait to limit the lookup to.
-        self_ty: ty::t,                     // The type of `a`.
-        supplied_tps: &'a [ty::t])          // The list of types X, Y, ... .
-     -> Option<MethodCallee> {
+    fcx: &'a FnCtxt<'a, 'tcx>,
+
+    // In a call `a.b::<X, Y, ...>(...)`:
+    span: Span,                         // The expression `a.b(...)`'s span.
+    self_expr: Option<&'a ast::Expr>,   // The expression `a`, if available.
+    m_name: ast::Name,                  // The name `b`.
+    trait_did: DefId,                   // The trait to limit the lookup to.
+    self_ty: ty::t,                     // The type of `a`.
+    supplied_tps: &'a [ty::t])          // The list of types X, Y, ... .
+    -> Option<MethodCallee>
+{
     let mut lcx = LookupContext {
         fcx: fcx,
         span: span,
@@ -185,18 +192,107 @@ pub fn lookup_in_trait<'a, 'tcx>(
         impl_dups: HashSet::new(),
         inherent_candidates: Vec::new(),
         extension_candidates: Vec::new(),
+        static_candidates: Vec::new(),
         deref_args: check::DoDerefArgs,
         check_traits: CheckTraitsOnly,
         autoderef_receiver: DontAutoderefReceiver,
-        report_statics: IgnoreStaticMethods,
     };
 
-    debug!("method lookup_in_trait(self_ty={}, self_expr={})",
-           self_ty.repr(fcx.tcx()), self_expr.map(|e| e.repr(fcx.tcx())));
+    debug!("method lookup_in_trait(self_ty={}, self_expr={}, m_name={}, trait_did={})",
+           self_ty.repr(fcx.tcx()),
+           self_expr.repr(fcx.tcx()),
+           m_name.repr(fcx.tcx()),
+           trait_did.repr(fcx.tcx()));
 
     lcx.push_bound_candidates(self_ty, Some(trait_did));
     lcx.push_extension_candidate(trait_did);
-    lcx.search(self_ty)
+
+    // when doing a trait search, ambiguity can't really happen except
+    // as part of the trait-lookup in general
+    match lcx.search(self_ty) {
+        Ok(callee) => Some(callee),
+        Err(_) => None
+    }
+}
+
+pub fn report_error(fcx: &FnCtxt,
+                    span: Span,
+                    rcvr_ty: ty::t,
+                    method_name: ast::Name,
+                    error: MethodError)
+{
+    match error {
+        NoMatch(static_sources) => {
+            fcx.type_error_message(
+                span,
+                |actual| {
+                    format!("type `{}` does not implement any \
+                             method in scope named `{}`",
+                            actual,
+                            method_name.user_string(fcx.tcx()))
+                },
+                rcvr_ty,
+                None);
+
+            if static_sources.len() > 0 {
+                fcx.tcx().sess.fileline_note(
+                    span,
+                    "found defined static methods, maybe a `self` is missing?");
+
+                report_candidates(fcx, span, method_name, static_sources);
+            }
+        }
+
+        Ambiguity(sources) => {
+            span_err!(fcx.sess(), span, E0034,
+                      "multiple applicable methods in scope");
+
+            report_candidates(fcx, span, method_name, sources);
+        }
+    }
+
+    fn report_candidates(fcx: &FnCtxt,
+                         span: Span,
+                         method_name: ast::Name,
+                         mut sources: Vec<CandidateSource>) {
+        sources.sort();
+        sources.dedup();
+
+        for (idx, source) in sources.iter().enumerate() {
+            match *source {
+                ImplSource(impl_did) => {
+                    // Provide the best span we can. Use the method, if local to crate, else
+                    // the impl, if local to crate (method may be defaulted), else the call site.
+                    let method = impl_method(fcx.tcx(), impl_did, method_name).unwrap();
+                    let impl_span = fcx.tcx().map.def_id_span(impl_did, span);
+                    let method_span = fcx.tcx().map.def_id_span(method.def_id, impl_span);
+
+                    let impl_ty = impl_self_ty(fcx, span, impl_did).ty;
+
+                    let insertion = match impl_trait_ref(fcx.tcx(), impl_did) {
+                        None => format!(""),
+                        Some(trait_ref) => format!(" of the trait `{}`",
+                                                   ty::item_path_str(fcx.tcx(),
+                                                                     trait_ref.def_id)),
+                    };
+
+                    span_note!(fcx.sess(), method_span,
+                               "candidate #{} is defined in an impl{} for the type `{}`",
+                               idx + 1u,
+                               insertion,
+                               impl_ty.user_string(fcx.tcx()));
+                }
+                TraitSource(trait_did) => {
+                    let (_, method) = trait_method(fcx.tcx(), trait_did, method_name).unwrap();
+                    let method_span = fcx.tcx().map.def_id_span(method.def_id, span);
+                    span_note!(fcx.sess(), method_span,
+                               "candidate #{} is defined in the trait `{}`",
+                               idx + 1u,
+                               ty::item_path_str(fcx.tcx(), trait_did));
+                }
+            }
+        }
+    }
 }
 
 // Determine the index of a method in the list of all methods belonging
@@ -228,75 +324,6 @@ fn get_method_index(tcx: &ty::ctxt,
     method_count + n_method
 }
 
-fn construct_transformed_self_ty_for_object(
-    tcx: &ty::ctxt,
-    span: Span,
-    trait_def_id: ast::DefId,
-    rcvr_substs: &subst::Substs,
-    rcvr_bounds: ty::ExistentialBounds,
-    method_ty: &ty::Method)
-    -> ty::t
-{
-    /*!
-     * This is a bit tricky. We have a match against a trait method
-     * being invoked on an object, and we want to generate the
-     * self-type. As an example, consider a trait
-     *
-     *     trait Foo {
-     *         fn r_method<'a>(&'a self);
-     *         fn u_method(Box<self>);
-     *     }
-     *
-     * Now, assuming that `r_method` is being called, we want the
-     * result to be `&'a Foo`. Assuming that `u_method` is being
-     * called, we want the result to be `Box<Foo>`. Of course,
-     * this transformation has already been done as part of
-     * `method_ty.fty.sig.inputs[0]`, but there the type
-     * is expressed in terms of `Self` (i.e., `&'a Self`, `Box<Self>`).
-     * Because objects are not standalone types, we can't just substitute
-     * `s/Self/Foo/`, so we must instead perform this kind of hokey
-     * match below.
-     */
-
-    let mut obj_substs = rcvr_substs.clone();
-
-    // The subst we get in has Err as the "Self" type. For an object
-    // type, we don't put any type into the Self paramspace, so let's
-    // make a copy of rcvr_substs that has the Self paramspace empty.
-    obj_substs.types.pop(subst::SelfSpace).unwrap();
-
-    match method_ty.explicit_self {
-        StaticExplicitSelfCategory => {
-            tcx.sess.span_bug(span, "static method for object type receiver");
-        }
-        ByValueExplicitSelfCategory => {
-            let tr = ty::mk_trait(tcx, trait_def_id, obj_substs, rcvr_bounds);
-            ty::mk_uniq(tcx, tr)
-        }
-        ByReferenceExplicitSelfCategory(..) | ByBoxExplicitSelfCategory => {
-            let transformed_self_ty = method_ty.fty.sig.inputs[0];
-            match ty::get(transformed_self_ty).sty {
-                ty::ty_rptr(r, mt) => { // must be SelfRegion
-                    let r = r.subst(tcx, rcvr_substs); // handle Early-Bound lifetime
-                    let tr = ty::mk_trait(tcx, trait_def_id, obj_substs,
-                                          rcvr_bounds);
-                    ty::mk_rptr(tcx, r, ty::mt{ ty: tr, mutbl: mt.mutbl })
-                }
-                ty::ty_uniq(_) => { // must be SelfUniq
-                    let tr = ty::mk_trait(tcx, trait_def_id, obj_substs,
-                                          rcvr_bounds);
-                    ty::mk_uniq(tcx, tr)
-                }
-                _ => {
-                    tcx.sess.span_bug(span,
-                        format!("'impossible' transformed_self_ty: {}",
-                                transformed_self_ty.repr(tcx)).as_slice());
-                }
-            }
-        }
-    }
-}
-
 struct LookupContext<'a, 'tcx: 'a> {
     fcx: &'a FnCtxt<'a, 'tcx>,
     span: Span,
@@ -311,42 +338,45 @@ struct LookupContext<'a, 'tcx: 'a> {
     supplied_tps: &'a [ty::t],
     impl_dups: HashSet<DefId>,
     inherent_candidates: Vec<Candidate>,
-    extension_candidates: Vec<Candidate>,
+    extension_candidates: Vec<ExtensionCandidate>,
+    static_candidates: Vec<CandidateSource>,
     deref_args: check::DerefArgs,
     check_traits: CheckTraitsFlag,
     autoderef_receiver: AutoderefReceiverFlag,
-    report_statics: StaticMethodsFlag,
 }
 
-/**
- * A potential method that might be called, assuming the receiver
- * is of a suitable type.
- */
+// A method that the user may be trying to invoke. Initially, we
+// construct candidates only for inherent methods; for extension
+// traits, we use an ExtensionCandidate.
 #[deriving(Clone)]
 struct Candidate {
-    rcvr_match_condition: RcvrMatchCondition,
+    xform_self_ty: ty::t,
     rcvr_substs: subst::Substs,
     method_ty: Rc<ty::Method>,
     origin: MethodOrigin,
 }
 
-/// This type represents the conditions under which the receiver is
-/// considered to "match" a given method candidate. Typically the test
-/// is whether the receiver is of a particular type. However, this
-/// type is the type of the receiver *after accounting for the
-/// method's self type* (e.g., if the method is an `Box<self>` method, we
-/// have *already verified* that the receiver is of some type `Box<T>` and
-/// now we must check that the type `T` is correct).  Unfortunately,
-/// because traits are not types, this is a pain to do.
-#[deriving(Clone)]
-pub enum RcvrMatchCondition {
-    RcvrMatchesIfObject(ast::DefId),
-    RcvrMatchesIfSubtype(ty::t),
-    RcvrMatchesIfEqtype(ty::t)
+// A variation on a candidate that just stores the data needed
+// extension trait matching.  Once we pick the trait that matches,
+// we'll construct a normal candidate from that. There is no deep
+// reason for this, the code just worked out a bit cleaner.
+struct ExtensionCandidate {
+    obligation: traits::Obligation,
+    xform_self_ty: ty::t,
+    method_ty: Rc<ty::Method>,
+    method_num: uint,
+}
+
+// A pared down enum describing just the places from which a method
+// candidate can arise. Used for error reporting only.
+#[deriving(PartialOrd, Ord, PartialEq, Eq)]
+pub enum CandidateSource {
+    ImplSource(ast::DefId),
+    TraitSource(/* trait id */ ast::DefId),
 }
 
 impl<'a, 'tcx> LookupContext<'a, 'tcx> {
-    fn search(&self, self_ty: ty::t) -> Option<MethodCallee> {
+    fn search(self, self_ty: ty::t) -> MethodResult {
         let span = self.self_expr.map_or(self.span, |e| e.span);
         let self_expr_id = self.self_expr.map(|e| e.id);
 
@@ -356,18 +386,33 @@ impl<'a, 'tcx> LookupContext<'a, 'tcx> {
                 |self_ty, autoderefs| self.search_step(self_ty, autoderefs));
 
         match result {
-            Some(Some(result)) => {
+            Some(Some(Ok(result))) => {
                 self.fixup_derefs_on_method_receiver_if_necessary(&result);
-                Some(result)
+                Ok(result)
+            }
+            Some(Some(Err(err))) => {
+                Err(err)
+            }
+            None | Some(None) => {
+                Err(NoMatch(self.static_candidates))
             }
-            _ => None
         }
     }
 
     fn search_step(&self,
                    self_ty: ty::t,
                    autoderefs: uint)
-                   -> Option<Option<MethodCallee>> {
+                   -> Option<Option<MethodResult>>
+    {
+        // Oh my, what a return type!
+        //
+        // Returning:
+        // - `None` => autoderef more, keep searching
+        // - `Some(None)` => stop searching, found nothing
+        // - `Some(Some(_))` => stop searching, found either callee/error
+        //   - `Some(Some(Ok(_)))` => found a callee
+        //   - `Some(Some(Err(_)))` => found an error (ambiguity, etc)
+
         debug!("search_step: self_ty={} autoderefs={}",
                self.ty_to_string(self_ty), autoderefs);
 
@@ -418,7 +463,7 @@ impl<'a, 'tcx> LookupContext<'a, 'tcx> {
         self.self_expr.is_none()
     }
 
-    // ______________________________________________________________________
+    ///////////////////////////////////////////////////////////////////////////
     // Candidate collection (see comment at start of file)
 
     fn push_inherent_candidates(&mut self, self_ty: ty::t) {
@@ -435,8 +480,7 @@ impl<'a, 'tcx> LookupContext<'a, 'tcx> {
         check::autoderef(self.fcx, span, self_ty, None, NoPreference, |self_ty, _| {
             match get(self_ty).sty {
                 ty_trait(box TyTrait { def_id, ref substs, bounds, .. }) => {
-                    self.push_inherent_candidates_from_object(
-                        def_id, substs, bounds);
+                    self.push_inherent_candidates_from_object(self_ty, def_id, substs, bounds);
                     self.push_inherent_impl_candidates_for_type(def_id);
                 }
                 ty_enum(did, _) |
@@ -465,10 +509,6 @@ impl<'a, 'tcx> LookupContext<'a, 'tcx> {
                 ty_param(p) => {
                     self.push_inherent_candidates_from_param(self_ty, restrict_to, p);
                 }
-                ty_unboxed_closure(closure_did, _) => {
-                    self.push_unboxed_closure_call_candidates_if_applicable(
-                        closure_did);
-                }
                 _ => { /* No bound methods in these types */ }
             }
 
@@ -481,131 +521,92 @@ impl<'a, 'tcx> LookupContext<'a, 'tcx> {
         });
     }
 
-    fn push_extension_candidate(&mut self, trait_did: DefId) {
-        ty::populate_implementations_for_trait_if_necessary(self.tcx(), trait_did);
-
-        // Look for explicit implementations.
-        let impl_items = self.tcx().impl_items.borrow();
-        for impl_infos in self.tcx().trait_impls.borrow().find(&trait_did).iter() {
-            for impl_did in impl_infos.borrow().iter() {
-                let items = &(*impl_items)[*impl_did];
-                self.push_candidates_from_impl(*impl_did,
-                                               items.as_slice(),
-                                               true);
-            }
-        }
-    }
-
     fn push_extension_candidates(&mut self, expr_id: ast::NodeId) {
-        // If the method being called is associated with a trait, then
-        // find all the impls of that trait.  Each of those are
-        // candidates.
+        debug!("push_extension_candidates(expr_id={})", expr_id);
+
+        let mut duplicates = HashSet::new();
         let opt_applicable_traits = self.fcx.ccx.trait_map.find(&expr_id);
         for applicable_traits in opt_applicable_traits.into_iter() {
-            for trait_did in applicable_traits.iter() {
-                debug!("push_extension_candidates() found trait: {}",
-                       if trait_did.krate == ast::LOCAL_CRATE {
-                           self.fcx.ccx.tcx.map.node_to_string(trait_did.node)
-                       } else {
-                           "(external)".to_string()
-                       });
-                self.push_extension_candidate(*trait_did);
+            for &trait_did in applicable_traits.iter() {
+                if duplicates.insert(trait_did) {
+                    self.push_extension_candidate(trait_did);
+                }
             }
         }
     }
 
-    fn push_unboxed_closure_call_candidate_if_applicable(
-            &mut self,
-            trait_did: DefId,
-            closure_did: DefId,
-            closure_function_type: &ClosureTy) {
-        let trait_item = (*ty::trait_items(self.tcx(), trait_did))[0]
-                                                               .clone();
-        let method = match trait_item {
-            ty::MethodTraitItem(method) => method,
-            ty::TypeTraitItem(_) => {
-                self.tcx().sess.bug(
-                    "push_unboxed_closure_call_candidates_if_applicable(): \
-                     unexpected associated type in function trait")
-            }
+    fn push_extension_candidate(&mut self, trait_def_id: DefId) {
+        debug!("push_extension_candidates: trait_def_id={}", trait_def_id);
+
+        // Check whether `trait_def_id` defines a method with suitable name:
+        let trait_items =
+            ty::trait_items(self.tcx(), trait_def_id);
+        let matching_index =
+            trait_items.iter()
+                       .position(|item| item.ident().name == self.m_name);
+        let matching_index = match matching_index {
+            Some(i) => i,
+            None => { return; }
+        };
+        let method = match (&*trait_items)[matching_index].as_opt_method() {
+            Some(m) => m,
+            None => { return; }
         };
 
-        // Make sure it has the right name!
-        if method.ident.name != self.m_name {
-            return
+        // Check whether `trait_def_id` defines a method with suitable name:
+        if !self.has_applicable_self(&*method) {
+            debug!("method has inapplicable self");
+            return self.record_static_candidate(TraitSource(trait_def_id));
         }
 
-        // Get the tupled type of the arguments.
-        let arguments_type = closure_function_type.sig.inputs[0];
-        let return_type = closure_function_type.sig.output;
-
-        let closure_region =
-            self.fcx.infcx().next_region_var(infer::MiscVariable(self.span));
-        let unboxed_closure_type = ty::mk_unboxed_closure(self.tcx(),
-                                                          closure_did,
-                                                          closure_region);
-        self.extension_candidates.push(Candidate {
-            rcvr_match_condition:
-                RcvrMatchesIfSubtype(unboxed_closure_type),
-            rcvr_substs: subst::Substs::new_trait(
-                vec![arguments_type, return_type],
-                vec![],
-                self.fcx.infcx().next_ty_vars(1)[0]),
+        // Otherwise, construct the receiver type.
+        let self_ty =
+            self.fcx.infcx().next_ty_var();
+        let trait_def =
+            ty::lookup_trait_def(self.tcx(), trait_def_id);
+        let substs =
+            self.fcx.infcx().fresh_substs_for_trait(self.span,
+                                                    &trait_def.generics,
+                                                    self_ty);
+        let xform_self_ty =
+            self.xform_self_ty(&method, &substs);
+
+        // Construct the obligation which must match.
+        let trait_ref =
+            Rc::new(ty::TraitRef::new(trait_def_id, substs));
+        let obligation =
+            traits::Obligation::misc(self.span, trait_ref);
+
+        debug!("extension-candidate(xform_self_ty={} obligation={})",
+               self.infcx().ty_to_string(xform_self_ty),
+               obligation.repr(self.tcx()));
+
+        self.extension_candidates.push(ExtensionCandidate {
+            obligation: obligation,
+            xform_self_ty: xform_self_ty,
             method_ty: method,
-            origin: MethodStaticUnboxedClosure(closure_did),
+            method_num: matching_index,
         });
     }
 
-    fn push_unboxed_closure_call_candidates_if_applicable(
-            &mut self,
-            closure_did: DefId) {
-        match self.tcx().unboxed_closures.borrow().find(&closure_did) {
-            None => {}  // Fall through to try inherited.
-            Some(closure) => {
-                let tcx = self.tcx();
-                self.push_unboxed_closure_call_candidate_if_applicable(
-                    closure.kind.trait_did(tcx),
-                    closure_did,
-                    &closure.closure_type);
-                return
-            }
-        }
-
-        match self.fcx.inh.unboxed_closures.borrow().find(&closure_did) {
-            Some(closure) => {
-                let tcx = self.tcx();
-                self.push_unboxed_closure_call_candidate_if_applicable(
-                    closure.kind.trait_did(tcx),
-                    closure_did,
-                    &closure.closure_type);
-                return
-            }
-            None => {}
-        }
-
-        self.tcx().sess.bug("didn't find unboxed closure type in tcx map or \
-                             inherited map, so there")
-    }
-
     fn push_inherent_candidates_from_object(&mut self,
+                                            self_ty: ty::t,
                                             did: DefId,
                                             substs: &subst::Substs,
-                                            bounds: ty::ExistentialBounds) {
-        debug!("push_inherent_candidates_from_object(did={}, substs={})",
-               self.did_to_string(did),
-               substs.repr(self.tcx()));
+                                            _bounds: ty::ExistentialBounds) {
+        debug!("push_inherent_candidates_from_object(self_ty={})",
+               self_ty.repr(self.tcx()));
+
         let tcx = self.tcx();
-        let span = self.span;
 
         // It is illegal to invoke a method on a trait instance that
-        // refers to the `self` type. An error will be reported by
-        // `enforce_object_limitations()` if the method refers
-        // to the `Self` type. Substituting ty_err here allows
-        // compiler to soldier on.
-        //
-        // `confirm_candidate()` also relies upon this substitution
-        // for Self. (fix)
-        let rcvr_substs = substs.with_self_ty(ty::mk_err());
+        // refers to the `Self` type. An error will be reported by
+        // `enforce_object_limitations()` if the method refers to the
+        // `Self` type anywhere other than the receiver. Here, we use
+        // a substitution that replaces `Self` with the object type
+        // itself. Hence, a `&self` method will wind up with an
+        // argument type like `&Trait`.
+        let rcvr_substs = substs.with_self_ty(self_ty);
         let trait_ref = Rc::new(TraitRef {
             def_id: did,
             substs: rcvr_substs.clone()
@@ -613,20 +614,35 @@ impl<'a, 'tcx> LookupContext<'a, 'tcx> {
 
         self.push_inherent_candidates_from_bounds_inner(
             &[trait_ref.clone()],
-            |_this, new_trait_ref, m, method_num| {
+            |this, new_trait_ref, m, method_num| {
                 let vtable_index =
                     get_method_index(tcx, &*new_trait_ref,
                                      trait_ref.clone(), method_num);
-                let mut m = (*m).clone();
-                // We need to fix up the transformed self type.
-                *m.fty.sig.inputs.get_mut(0) =
-                    construct_transformed_self_ty_for_object(
-                        tcx, span, did, &rcvr_substs, bounds, &m);
+
+                // FIXME Hacky. By-value `self` methods in objects ought to be
+                // just a special case of passing ownership of a DST value
+                // as a parameter. *But* we currently hack them in and tie them to
+                // the particulars of the `Box` type. So basically for a `fn foo(self,...)`
+                // method invoked on an object, we don't want the receiver type to be
+                // `TheTrait`, but rather `Box<TheTrait>`. Yuck.
+                let mut m = m;
+                match m.explicit_self {
+                    ByValueExplicitSelfCategory => {
+                        let mut n = (*m).clone();
+                        let self_ty = n.fty.sig.inputs[0];
+                        *n.fty.sig.inputs.get_mut(0) = ty::mk_uniq(tcx, self_ty);
+                        m = Rc::new(n);
+                    }
+                    _ => { }
+                }
+
+                let xform_self_ty =
+                    this.xform_self_ty(&m, &new_trait_ref.substs);
 
                 Some(Candidate {
-                    rcvr_match_condition: RcvrMatchesIfObject(did),
+                    xform_self_ty: xform_self_ty,
                     rcvr_substs: new_trait_ref.substs.clone(),
-                    method_ty: Rc::new(m),
+                    method_ty: m,
                     origin: MethodTraitObject(MethodObject {
                         trait_ref: new_trait_ref,
                         object_trait_id: did,
@@ -650,9 +666,8 @@ impl<'a, 'tcx> LookupContext<'a, 'tcx> {
             restrict_to);
     }
 
-
     fn push_inherent_candidates_from_bounds(&mut self,
-                                            self_ty: ty::t,
+                                            _self_ty: ty::t,
                                             space: subst::ParamSpace,
                                             index: uint,
                                             restrict_to: Option<DefId>) {
@@ -670,12 +685,8 @@ impl<'a, 'tcx> LookupContext<'a, 'tcx> {
                     _ => {}
                 }
 
-                let condition = match m.explicit_self {
-                    ByReferenceExplicitSelfCategory(_, mt) if mt == MutMutable =>
-                        RcvrMatchesIfEqtype(self_ty),
-                    _ =>
-                        RcvrMatchesIfSubtype(self_ty)
-                };
+                let xform_self_ty =
+                    this.xform_self_ty(&m, &trait_ref.substs);
 
                 debug!("found match: trait_ref={} substs={} m={}",
                        trait_ref.repr(this.tcx()),
@@ -689,8 +700,9 @@ impl<'a, 'tcx> LookupContext<'a, 'tcx> {
                            trait_ref.substs.types.get_slice(subst::SelfSpace).len());
                 assert_eq!(m.generics.regions.get_slice(subst::SelfSpace).len(),
                            trait_ref.substs.regions().get_slice(subst::SelfSpace).len());
+
                 Some(Candidate {
-                    rcvr_match_condition: condition,
+                    xform_self_ty: xform_self_ty,
                     rcvr_substs: trait_ref.substs.clone(),
                     method_ty: m,
                     origin: MethodTypeParam(MethodParam {
@@ -698,7 +710,7 @@ impl<'a, 'tcx> LookupContext<'a, 'tcx> {
                         method_num: method_num,
                     })
                 })
-        })
+            })
     }
 
     // Do a search through a list of bounds, using a callback to actually
@@ -720,41 +732,24 @@ impl<'a, 'tcx> LookupContext<'a, 'tcx> {
                 continue;
             }
 
-            let trait_items = ty::trait_items(tcx, bound_trait_ref.def_id);
-            match trait_items.iter().position(|ti| {
-                match *ti {
-                    ty::MethodTraitItem(ref m) => {
-                        m.explicit_self != ty::StaticExplicitSelfCategory &&
-                        m.ident.name == self.m_name
-                    }
-                    ty::TypeTraitItem(_) => false,
-                }
-            }) {
-                Some(pos) => {
-                    let method = match (*trait_items)[pos] {
-                        ty::MethodTraitItem(ref method) => (*method).clone(),
-                        ty::TypeTraitItem(_) => {
-                            tcx.sess.bug("typechecking associated type as \
-                                          though it were a method")
-                        }
-                    };
+            let (pos, method) = match trait_method(tcx, bound_trait_ref.def_id, self.m_name) {
+                Some(v) => v,
+                None => { continue; }
+            };
 
-                    match mk_cand(self,
-                                  bound_trait_ref,
-                                  method,
-                                  pos) {
-                        Some(cand) => {
-                            debug!("pushing inherent candidate for param: {}",
-                                   cand.repr(self.tcx()));
-                            self.inherent_candidates.push(cand);
-                        }
-                        None => {}
+            if !self.has_applicable_self(&*method) {
+                self.record_static_candidate(TraitSource(bound_trait_ref.def_id));
+            } else {
+                match mk_cand(self,
+                              bound_trait_ref,
+                              method,
+                              pos) {
+                    Some(cand) => {
+                        debug!("pushing inherent candidate for param: {}",
+                               cand.repr(self.tcx()));
+                        self.inherent_candidates.push(cand);
                     }
-                }
-                None => {
-                    debug!("trait doesn't contain method: {}",
-                        bound_trait_ref.def_id);
-                    // check next trait or bound
+                    None => {}
                 }
             }
         }
@@ -766,83 +761,47 @@ impl<'a, 'tcx> LookupContext<'a, 'tcx> {
         // metadata if necessary.
         ty::populate_implementations_for_type_if_necessary(self.tcx(), did);
 
-        let impl_items = self.tcx().impl_items.borrow();
         for impl_infos in self.tcx().inherent_impls.borrow().find(&did).iter() {
             for impl_did in impl_infos.iter() {
-                let items = &(*impl_items)[*impl_did];
-                self.push_candidates_from_impl(*impl_did,
-                                               items.as_slice(),
-                                               false);
+                self.push_candidates_from_inherent_impl(*impl_did);
             }
         }
     }
 
-    fn push_candidates_from_impl(&mut self,
-                                 impl_did: DefId,
-                                 impl_items: &[ImplOrTraitItemId],
-                                 is_extension: bool) {
-        let did = if self.report_statics == ReportStaticMethods {
-            // we only want to report each base trait once
-            match ty::impl_trait_ref(self.tcx(), impl_did) {
-                Some(trait_ref) => trait_ref.def_id,
-                None => impl_did
-            }
-        } else {
-            impl_did
-        };
-
-        if !self.impl_dups.insert(did) {
+    fn push_candidates_from_inherent_impl(&mut self,
+                                          impl_did: DefId) {
+        if !self.impl_dups.insert(impl_did) {
             return; // already visited
         }
 
-        debug!("push_candidates_from_impl: {} {}",
-               token::get_name(self.m_name),
-               impl_items.iter()
-                         .map(|&did| {
-                             ty::impl_or_trait_item(self.tcx(),
-                                                    did.def_id()).ident()
-                         })
-                         .collect::<Vec<ast::Ident>>()
-                         .repr(self.tcx()));
-
-        let method = match impl_items.iter()
-                                     .map(|&did| {
-                                         ty::impl_or_trait_item(self.tcx(),
-                                                                did.def_id())
-                                     })
-                                     .find(|m| {
-                                         m.ident().name == self.m_name
-                                     }) {
-            Some(ty::MethodTraitItem(method)) => method,
-            Some(ty::TypeTraitItem(_)) | None => {
-                // No method with the right name.
-                return
-            }
+        let method = match impl_method(self.tcx(), impl_did, self.m_name) {
+            Some(m) => m,
+            None => { return; } // No method with correct name on this impl
         };
 
-        // determine the `self` of the impl with fresh
-        // variables for each parameter:
+        debug!("push_candidates_from_inherent_impl: impl_did={} method={}",
+               impl_did.repr(self.tcx()),
+               method.repr(self.tcx()));
+
+        if !self.has_applicable_self(&*method) {
+            // No receiver declared. Not a candidate.
+            return self.record_static_candidate(ImplSource(impl_did));
+        }
+
+        // Determine the `self` of the impl with fresh
+        // variables for each parameter.
         let span = self.self_expr.map_or(self.span, |e| e.span);
         let TypeAndSubsts {
             substs: impl_substs,
-            ty: impl_ty
+            ty: _impl_ty
         } = impl_self_ty(self.fcx, span, impl_did);
 
-        let condition = match method.explicit_self {
-            ByReferenceExplicitSelfCategory(_, mt) if mt == MutMutable =>
-                RcvrMatchesIfEqtype(impl_ty),
-            _ =>
-                RcvrMatchesIfSubtype(impl_ty)
-        };
-
-        let candidates = if is_extension {
-            &mut self.extension_candidates
-        } else {
-            &mut self.inherent_candidates
-        };
+        // Determine the receiver type that the method itself expects.
+        let xform_self_ty =
+            self.xform_self_ty(&method, &impl_substs);
 
-        candidates.push(Candidate {
-            rcvr_match_condition: condition,
+        self.inherent_candidates.push(Candidate {
+            xform_self_ty: xform_self_ty,
             rcvr_substs: impl_substs,
             origin: MethodStatic(method.def_id),
             method_ty: method,
@@ -855,7 +814,7 @@ impl<'a, 'tcx> LookupContext<'a, 'tcx> {
     fn search_for_autoderefd_method(&self,
                                     self_ty: ty::t,
                                     autoderefs: uint)
-                                    -> Option<MethodCallee> {
+                                    -> Option<MethodResult> {
         // Hacky. For overloaded derefs, there may be an adjustment
         // added to the expression from the outside context, so we do not store
         // an explicit adjustment, but rather we hardwire the single deref
@@ -868,8 +827,10 @@ impl<'a, 'tcx> LookupContext<'a, 'tcx> {
         let adjustment = Some((self.self_expr.unwrap().id, ty::AdjustDerefRef(auto_deref_ref)));
 
         match self.search_for_method(self_ty) {
-            None => None,
-            Some(method) => {
+            None => {
+                None
+            }
+            Some(Ok(method)) => {
                 debug!("(searching for autoderef'd method) writing \
                        adjustment {} for {}", adjustment, self.ty_to_string(self_ty));
                 match adjustment {
@@ -878,7 +839,10 @@ impl<'a, 'tcx> LookupContext<'a, 'tcx> {
                     }
                     None => {}
                 }
-                Some(method)
+                Some(Ok(method))
+            }
+            Some(Err(error)) => {
+                Some(Err(error))
             }
         }
     }
@@ -942,7 +906,9 @@ impl<'a, 'tcx> LookupContext<'a, 'tcx> {
     // Takes an [T] - an unwrapped DST pointer (either ~ or &)
     // [T] to &[T] or &&[T] (note that we started with a &[T] or ~[T] which has
     // been implicitly derefed).
-    fn auto_slice_vec(&self, ty: ty::t, autoderefs: uint) -> Option<MethodCallee> {
+    fn auto_slice_vec(&self, ty: ty::t, autoderefs: uint)
+                      -> Option<MethodResult>
+    {
         let tcx = self.tcx();
         debug!("auto_slice_vec {}", ppaux::ty_to_string(tcx, ty));
 
@@ -973,7 +939,7 @@ impl<'a, 'tcx> LookupContext<'a, 'tcx> {
     }
 
     // [T, ..len] -> [T] or &[T] or &&[T]
-    fn auto_unsize_vec(&self, ty: ty::t, autoderefs: uint, len: uint) -> Option<MethodCallee> {
+    fn auto_unsize_vec(&self, ty: ty::t, autoderefs: uint, len: uint) -> Option<MethodResult> {
         let tcx = self.tcx();
         debug!("auto_unsize_vec {}", ppaux::ty_to_string(tcx, ty));
 
@@ -1009,7 +975,7 @@ impl<'a, 'tcx> LookupContext<'a, 'tcx> {
             })
     }
 
-    fn auto_slice_str(&self, autoderefs: uint) -> Option<MethodCallee> {
+    fn auto_slice_str(&self, autoderefs: uint) -> Option<MethodResult> {
         let tcx = self.tcx();
         debug!("auto_slice_str");
 
@@ -1031,7 +997,7 @@ impl<'a, 'tcx> LookupContext<'a, 'tcx> {
     }
 
     // Coerce Box/&Trait instances to &Trait.
-    fn auto_slice_trait(&self, ty: ty::t, autoderefs: uint) -> Option<MethodCallee> {
+    fn auto_slice_trait(&self, ty: ty::t, autoderefs: uint) -> Option<MethodResult> {
         debug!("auto_slice_trait");
         match ty::get(ty).sty {
             ty_trait(box ty::TyTrait {
@@ -1055,7 +1021,8 @@ impl<'a, 'tcx> LookupContext<'a, 'tcx> {
     fn search_for_autofatptrd_method(&self,
                                      self_ty: ty::t,
                                      autoderefs: uint)
-                                     -> Option<MethodCallee> {
+                                     -> Option<MethodResult>
+    {
         /*!
          * Searches for a candidate by converting things like
          * `~[]` to `&[]`.
@@ -1082,7 +1049,8 @@ impl<'a, 'tcx> LookupContext<'a, 'tcx> {
     }
 
     fn search_for_autoptrd_method(&self, self_ty: ty::t, autoderefs: uint)
-                                  -> Option<MethodCallee> {
+                                  -> Option<MethodResult>
+    {
         /*!
          *
          * Converts any type `T` to `&M T` where `M` is an
@@ -1116,12 +1084,13 @@ impl<'a, 'tcx> LookupContext<'a, 'tcx> {
     }
 
     fn search_for_some_kind_of_autorefd_method(
-            &self,
-            kind: |Region, ast::Mutability| -> ty::AutoRef,
-            autoderefs: uint,
-            mutbls: &[ast::Mutability],
-            mk_autoref_ty: |ast::Mutability, ty::Region| -> ty::t)
-            -> Option<MethodCallee> {
+        &self,
+        kind: |Region, ast::Mutability| -> ty::AutoRef,
+        autoderefs: uint,
+        mutbls: &[ast::Mutability],
+        mk_autoref_ty: |ast::Mutability, ty::Region| -> ty::t)
+        -> Option<MethodResult>
+    {
         // Hacky. For overloaded derefs, there may be an adjustment
         // added to the expression from the outside context, so we do not store
         // an explicit adjustment, but rather we hardwire the single deref
@@ -1164,7 +1133,7 @@ impl<'a, 'tcx> LookupContext<'a, 'tcx> {
         None
     }
 
-    fn search_for_method(&self, rcvr_ty: ty::t) -> Option<MethodCallee> {
+    fn search_for_method(&self, rcvr_ty: ty::t) -> Option<MethodResult> {
         debug!("search_for_method(rcvr_ty={})", self.ty_to_string(rcvr_ty));
         let _indenter = indenter();
 
@@ -1181,49 +1150,26 @@ impl<'a, 'tcx> LookupContext<'a, 'tcx> {
         }
 
         debug!("searching extension candidates");
-        self.consider_candidates(rcvr_ty, self.extension_candidates.as_slice())
+        self.consider_extension_candidates(rcvr_ty)
     }
 
     fn consider_candidates(&self, rcvr_ty: ty::t,
                            candidates: &[Candidate])
-                           -> Option<MethodCallee> {
+                           -> Option<MethodResult> {
         let relevant_candidates = self.filter_candidates(rcvr_ty, candidates);
 
         if relevant_candidates.len() == 0 {
             return None;
         }
 
-        if self.report_statics == ReportStaticMethods {
-            // lookup should only be called with ReportStaticMethods if a regular lookup failed
-            assert!(relevant_candidates.iter()
-                                       .all(|c| {
-                c.method_ty.explicit_self == ty::StaticExplicitSelfCategory
-            }));
-
-            self.tcx().sess.fileline_note(self.span,
-                                "found defined static methods, maybe a `self` is missing?");
-
-            for (idx, candidate) in relevant_candidates.iter().enumerate() {
-                self.report_candidate(idx, &candidate.origin);
-            }
-
-            // return something so we don't get errors for every mutability
-            return Some(MethodCallee {
-                origin: relevant_candidates[0].origin.clone(),
-                ty: ty::mk_err(),
-                substs: subst::Substs::empty()
-            });
-        }
-
         if relevant_candidates.len() > 1 {
-            span_err!(self.tcx().sess, self.span, E0034,
-                "multiple applicable methods in scope");
-            for (idx, candidate) in relevant_candidates.iter().enumerate() {
-                self.report_candidate(idx, &candidate.origin);
-            }
+            let sources = relevant_candidates.iter()
+                                             .map(|candidate| candidate.to_source())
+                                             .collect();
+            return Some(Err(Ambiguity(sources)));
         }
 
-        Some(self.confirm_candidate(rcvr_ty, &relevant_candidates[0]))
+        Some(Ok(self.confirm_candidate(rcvr_ty, &relevant_candidates[0])))
     }
 
     fn filter_candidates(&self, rcvr_ty: ty::t, candidates: &[Candidate]) -> Vec<Candidate> {
@@ -1250,13 +1196,110 @@ impl<'a, 'tcx> LookupContext<'a, 'tcx> {
                     _ => false
                 }
             }) {
-                relevant_candidates.push(candidate_a.clone());
+                relevant_candidates.push((*candidate_a).clone());
             }
         }
 
         relevant_candidates
     }
 
+    fn consider_extension_candidates(&self, rcvr_ty: ty::t)
+                                     -> Option<MethodResult>
+    {
+        let mut selcx = traits::SelectionContext::new(self.infcx(),
+                                                      &self.fcx.inh.param_env,
+                                                      self.fcx);
+
+        let extension_evaluations: Vec<_> =
+            self.extension_candidates.iter()
+            .map(|ext| self.probe_extension_candidate(&mut selcx, rcvr_ty, ext))
+            .collect();
+
+        // How many traits can apply?
+        let applicable_evaluations_count =
+            extension_evaluations.iter()
+                                 .filter(|eval| eval.may_apply())
+                                 .count();
+
+        // Determine whether there are multiple traits that could apply.
+        if applicable_evaluations_count > 1 {
+            let sources =
+                self.extension_candidates.iter()
+                    .zip(extension_evaluations.iter())
+                    .filter(|&(_, eval)| eval.may_apply())
+                    .map(|(ext, _)| ext.to_source())
+                    .collect();
+            return Some(Err(Ambiguity(sources)));
+        }
+
+        // Determine whether there are no traits that could apply.
+        if applicable_evaluations_count == 0 {
+            return None;
+        }
+
+        // Exactly one trait applies. It itself could *still* be ambiguous thanks
+        // to coercions.
+        let applicable_evaluation = extension_evaluations.iter()
+                                                         .position(|eval| eval.may_apply())
+                                                         .unwrap();
+        let match_data = match extension_evaluations[applicable_evaluation] {
+            traits::MethodMatched(data) => data,
+            traits::MethodAmbiguous(ref impl_def_ids) => {
+                let sources = impl_def_ids.iter().map(|&d| ImplSource(d)).collect();
+                return Some(Err(Ambiguity(sources)));
+            }
+            traits::MethodDidNotMatch => {
+                self.bug("Method did not match and yet may_apply() is true")
+            }
+        };
+
+        let extension = &self.extension_candidates[applicable_evaluation];
+
+        debug!("picked extension={}", extension.repr(self.tcx()));
+
+        // We have to confirm the method match. This will cause the type variables
+        // in the obligation to be appropriately unified based on the subtyping/coercion
+        // between `rcvr_ty` and `extension.xform_self_ty`.
+        selcx.confirm_method_match(rcvr_ty, extension.xform_self_ty,
+                                   &extension.obligation, match_data);
+
+        // Finally, construct the candidate, now that everything is
+        // known, and confirm *that*. Note that whatever we pick
+        // (impl, whatever) we can always use the same kind of origin
+        // (trait-based method dispatch).
+        let candidate = Candidate {
+            xform_self_ty: extension.xform_self_ty,
+            rcvr_substs: extension.obligation.trait_ref.substs.clone(),
+            method_ty: extension.method_ty.clone(),
+            origin: MethodTypeParam(MethodParam{trait_ref: extension.obligation.trait_ref.clone(),
+                                                method_num: extension.method_num})
+        };
+
+        // Confirming the candidate will do the final work of
+        // instantiating late-bound variables, unifying things, and
+        // registering trait obligations (including
+        // `extension.obligation`, which should be a requirement of
+        // the `Self` trait).
+        let callee = self.confirm_candidate(rcvr_ty, &candidate);
+
+        select_fcx_obligations_where_possible(self.fcx);
+
+        Some(Ok(callee))
+    }
+
+    fn probe_extension_candidate(&self,
+                                 selcx: &mut traits::SelectionContext,
+                                 rcvr_ty: ty::t,
+                                 candidate: &ExtensionCandidate)
+                                 -> traits::MethodMatchResult
+    {
+        debug!("probe_extension_candidate(rcvr_ty={}, candidate.obligation={})",
+               rcvr_ty.repr(self.tcx()),
+               candidate.obligation.repr(self.tcx()));
+
+        selcx.evaluate_method_obligation(rcvr_ty, candidate.xform_self_ty, &candidate.obligation)
+    }
+
     fn confirm_candidate(&self, rcvr_ty: ty::t, candidate: &Candidate)
                          -> MethodCallee
     {
@@ -1273,12 +1316,17 @@ impl<'a, 'tcx> LookupContext<'a, 'tcx> {
                self.ty_to_string(rcvr_ty),
                candidate.repr(self.tcx()));
 
-        self.enforce_object_limitations(candidate);
-        self.enforce_drop_trait_limitations(candidate);
+        let mut rcvr_substs = candidate.rcvr_substs.clone();
+
+        if !self.enforce_object_limitations(candidate) {
+            // Here we change `Self` from `Trait` to `err` in the case that
+            // this is an illegal object method. This is necessary to prevent
+            // the user from getting strange, derivative errors when the method
+            // takes an argument/return-type of type `Self` etc.
+            rcvr_substs.types.get_mut_slice(SelfSpace)[0] = ty::mk_err();
+        }
 
-        // static methods should never have gotten this far:
-        assert!(candidate.method_ty.explicit_self !=
-                ty::StaticExplicitSelfCategory);
+        self.enforce_drop_trait_limitations(candidate);
 
         // Determine the values for the generic parameters of the method.
         // If they were not explicitly supplied, just construct fresh
@@ -1310,7 +1358,7 @@ impl<'a, 'tcx> LookupContext<'a, 'tcx> {
                 self.span,
                 candidate.method_ty.generics.regions.get_slice(subst::FnSpace));
 
-        let all_substs = candidate.rcvr_substs.clone().with_method(m_types, m_regions);
+        let all_substs = rcvr_substs.with_method(m_types, m_regions);
 
         let ref bare_fn_ty = candidate.method_ty.fty;
 
@@ -1319,33 +1367,14 @@ impl<'a, 'tcx> LookupContext<'a, 'tcx> {
                bare_fn_ty.repr(tcx),
                all_substs.repr(tcx));
 
-        let fn_sig = &bare_fn_ty.sig;
-        let inputs = match candidate.origin {
-            MethodTraitObject(..) => {
-                // For annoying reasons, we've already handled the
-                // substitution of self for object calls.
-                let args = fn_sig.inputs.slice_from(1).iter().map(|t| {
-                    t.subst(tcx, &all_substs)
-                });
-                Some(fn_sig.inputs[0]).into_iter().chain(args).collect()
-            }
-            _ => fn_sig.inputs.subst(tcx, &all_substs)
-        };
-        let fn_sig = ty::FnSig {
-            binder_id: fn_sig.binder_id,
-            inputs: inputs,
-            output: fn_sig.output.subst(tcx, &all_substs),
-            variadic: fn_sig.variadic
-        };
+        let fn_sig = bare_fn_ty.sig.subst(tcx, &all_substs);
 
         debug!("after subst, fty={}", fn_sig.repr(tcx));
 
         // Replace any bound regions that appear in the function
         // signature with region variables
-        let (_, fn_sig) = replace_late_bound_regions_in_fn_sig(
-            tcx, &fn_sig,
-            |br| self.fcx.infcx().next_region_var(
-                infer::LateBoundRegion(self.span, br)));
+        let fn_sig =
+            self.replace_late_bound_regions_with_fresh_var(fn_sig.binder_id, &fn_sig);
         let transformed_self_ty = fn_sig.inputs[0];
         let fty = ty::mk_bare_fn(tcx, ty::BareFnTy {
             sig: fn_sig,
@@ -1371,10 +1400,35 @@ impl<'a, 'tcx> LookupContext<'a, 'tcx> {
             }
         }
 
-        self.fcx.add_obligations_for_parameters(
-            traits::ObligationCause::misc(self.span),
-            &all_substs,
-            &candidate.method_ty.generics);
+        // FIXME(DST). Super hack. For a method on a trait object
+        // `Trait`, the generic signature requires that
+        // `Self:Trait`. Since, for an object, we bind `Self` to the
+        // type `Trait`, this leads to an obligation
+        // `Trait:Trait`. Until such time we DST is fully implemented,
+        // that obligation is not necessarily satisfied. (In the
+        // future, it would be.)
+        //
+        // To sidestep this, we overwrite the binding for `Self` with
+        // `err` (just for trait objects) when we generate the
+        // obligations.  This causes us to generate the obligation
+        // `err:Trait`, and the error type is considered to implement
+        // all traits, so we're all good. Hack hack hack.
+        match candidate.origin {
+            MethodTraitObject(..) => {
+                let mut temp_substs = all_substs.clone();
+                temp_substs.types.get_mut_slice(SelfSpace)[0] = ty::mk_err();
+                self.fcx.add_obligations_for_parameters(
+                    traits::ObligationCause::misc(self.span),
+                    &temp_substs,
+                    &candidate.method_ty.generics);
+            }
+            _ => {
+                self.fcx.add_obligations_for_parameters(
+                    traits::ObligationCause::misc(self.span),
+                    &all_substs,
+                    &candidate.method_ty.generics);
+            }
+        }
 
         MethodCallee {
             origin: candidate.origin.clone(),
@@ -1480,7 +1534,7 @@ impl<'a, 'tcx> LookupContext<'a, 'tcx> {
         }
     }
 
-    fn enforce_object_limitations(&self, candidate: &Candidate) {
+    fn enforce_object_limitations(&self, candidate: &Candidate) -> bool {
         /*!
          * There are some limitations to calling functions through an
          * object, because (a) the self type is not known
@@ -1493,7 +1547,7 @@ impl<'a, 'tcx> LookupContext<'a, 'tcx> {
             MethodStatic(..) |
             MethodTypeParam(..) |
             MethodStaticUnboxedClosure(..) => {
-                return; // not a call to a trait instance
+                return true; // not a call to a trait instance
             }
             MethodTraitObject(..) => {}
         }
@@ -1504,6 +1558,7 @@ impl<'a, 'tcx> LookupContext<'a, 'tcx> {
                     self.span,
                     "cannot call a method without a receiver \
                      through an object");
+                return false;
             }
 
             ty::ByValueExplicitSelfCategory |
@@ -1512,51 +1567,50 @@ impl<'a, 'tcx> LookupContext<'a, 'tcx> {
         }
 
         // reason (a) above
-        let check_for_self_ty = |ty| {
+        let check_for_self_ty = |ty| -> bool {
             if ty::type_has_self(ty) {
                 span_err!(self.tcx().sess, self.span, E0038,
                     "cannot call a method whose type contains a \
                      self-type through an object");
-                true
-            } else {
                 false
+            } else {
+                true
             }
         };
         let ref sig = candidate.method_ty.fty.sig;
-        let mut found_self_ty = false;
-        for &input_ty in sig.inputs.iter() {
-            if check_for_self_ty(input_ty) {
-                found_self_ty = true;
-                break;
+        for &input_ty in sig.inputs[1..].iter() {
+            if !check_for_self_ty(input_ty) {
+                return false;
             }
         }
-        if !found_self_ty {
-            check_for_self_ty(sig.output);
+        if !check_for_self_ty(sig.output) {
+            return false;
         }
 
         if candidate.method_ty.generics.has_type_params(subst::FnSpace) {
             // reason (b) above
             span_err!(self.tcx().sess, self.span, E0039,
                 "cannot call a generic method through an object");
+            return false;
         }
+
+        true
     }
 
     fn enforce_drop_trait_limitations(&self, candidate: &Candidate) {
         // No code can call the finalize method explicitly.
-        let bad;
-        match candidate.origin {
+        let bad = match candidate.origin {
             MethodStatic(method_id) => {
-                bad = self.tcx().destructors.borrow().contains(&method_id);
+                self.tcx().destructors.borrow().contains(&method_id)
+            }
+            MethodStaticUnboxedClosure(_) => {
+                false
             }
-            MethodStaticUnboxedClosure(_) => bad = false,
-            // FIXME: does this properly enforce this on everything now
-            // that self has been merged in? -sully
             MethodTypeParam(MethodParam { trait_ref: ref trait_ref, .. }) |
             MethodTraitObject(MethodObject { trait_ref: ref trait_ref, .. }) => {
-                bad = self.tcx().destructor_for_type.borrow()
-                          .contains_key(&trait_ref.def_id);
+                Some(trait_ref.def_id) == self.tcx().lang_items.drop_trait()
             }
-        }
+        };
 
         if bad {
             span_err!(self.tcx().sess, self.span, E0040,
@@ -1570,213 +1624,141 @@ impl<'a, 'tcx> LookupContext<'a, 'tcx> {
         debug!("is_relevant(rcvr_ty={}, candidate={})",
                self.ty_to_string(rcvr_ty), candidate.repr(self.tcx()));
 
-        return match candidate.method_ty.explicit_self {
-            StaticExplicitSelfCategory => {
-                debug!("(is relevant?) explicit self is static");
-                self.report_statics == ReportStaticMethods
-            }
-
-            ByValueExplicitSelfCategory => {
-                debug!("(is relevant?) explicit self is by-value");
-                match ty::get(rcvr_ty).sty {
-                    ty::ty_uniq(typ) => {
-                        match ty::get(typ).sty {
-                            ty::ty_trait(box ty::TyTrait {
-                                def_id: self_did,
-                                ..
-                            }) => {
-                                rcvr_matches_object(self_did, candidate) ||
-                                    rcvr_matches_ty(self.fcx,
-                                                    rcvr_ty,
-                                                    candidate)
-                            }
-                            _ => {
-                                rcvr_matches_ty(self.fcx, rcvr_ty, candidate)
-                            }
-                        }
-                    }
-                    _ => rcvr_matches_ty(self.fcx, rcvr_ty, candidate)
-                }
-            }
-
-            ByReferenceExplicitSelfCategory(_, m) => {
-                debug!("(is relevant?) explicit self is a region");
-                match ty::get(rcvr_ty).sty {
-                    ty::ty_rptr(_, mt) => {
-                        match ty::get(mt.ty).sty {
-                            ty::ty_trait(box ty::TyTrait { def_id: self_did, .. }) => {
-                                mutability_matches(mt.mutbl, m) &&
-                                rcvr_matches_object(self_did, candidate)
-                            }
-                            _ => mutability_matches(mt.mutbl, m) &&
-                                 rcvr_matches_ty(self.fcx, mt.ty, candidate)
-                        }
-                    }
-
-                    _ => false
-                }
-            }
-
-            ByBoxExplicitSelfCategory => {
-                debug!("(is relevant?) explicit self is a unique pointer");
-                match ty::get(rcvr_ty).sty {
-                    ty::ty_uniq(typ) => {
-                        match ty::get(typ).sty {
-                            ty::ty_trait(box ty::TyTrait { def_id: self_did, .. }) => {
-                                rcvr_matches_object(self_did, candidate)
-                            }
-                            _ => rcvr_matches_ty(self.fcx, typ, candidate),
-                        }
-                    }
+        infer::can_mk_subty(self.infcx(), rcvr_ty, candidate.xform_self_ty).is_ok()
+    }
 
-                    _ => false
-                }
-            }
-        };
+    fn infcx(&'a self) -> &'a infer::InferCtxt<'a, 'tcx> {
+        &self.fcx.inh.infcx
+    }
 
-        fn rcvr_matches_object(self_did: ast::DefId,
-                               candidate: &Candidate) -> bool {
-            match candidate.rcvr_match_condition {
-                RcvrMatchesIfObject(desired_did) => {
-                    self_did == desired_did
-                }
-                RcvrMatchesIfSubtype(_) | RcvrMatchesIfEqtype(_) => {
-                    false
-                }
-            }
-        }
+    fn tcx(&self) -> &'a ty::ctxt<'tcx> {
+        self.fcx.tcx()
+    }
 
-        fn rcvr_matches_ty(fcx: &FnCtxt,
-                           rcvr_ty: ty::t,
-                           candidate: &Candidate) -> bool {
-            match candidate.rcvr_match_condition {
-                RcvrMatchesIfObject(_) => {
-                    false
-                }
-                RcvrMatchesIfSubtype(of_type) => {
-                    fcx.can_mk_subty(rcvr_ty, of_type).is_ok()
-                }
-                RcvrMatchesIfEqtype(of_type) => {
-                    fcx.can_mk_eqty(rcvr_ty, of_type).is_ok()
-                }
-            }
-        }
+    fn ty_to_string(&self, t: ty::t) -> String {
+        self.fcx.infcx().ty_to_string(t)
+    }
 
-        fn mutability_matches(self_mutbl: ast::Mutability,
-                              candidate_mutbl: ast::Mutability)
-                              -> bool {
-            //! True if `self_mutbl <: candidate_mutbl`
-            self_mutbl == candidate_mutbl
-        }
+    fn bug(&self, s: &str) -> ! {
+        self.tcx().sess.span_bug(self.span, s)
     }
 
-    fn report_candidate(&self, idx: uint, origin: &MethodOrigin) {
-        match *origin {
-            MethodStatic(impl_did) => {
-                let did = if self.report_statics == ReportStaticMethods {
-                    // If we're reporting statics, we want to report the trait
-                    // definition if possible, rather than an impl
-                    match ty::trait_item_of_item(self.tcx(), impl_did) {
-                        None | Some(TypeTraitItemId(_)) => {
-                            debug!("(report candidate) No trait method \
-                                    found");
-                            impl_did
-                        }
-                        Some(MethodTraitItemId(trait_did)) => {
-                            debug!("(report candidate) Found trait ref");
-                            trait_did
-                        }
-                    }
-                } else {
-                    // If it is an instantiated default method, use the original
-                    // default method for error reporting.
-                    match provided_source(self.tcx(), impl_did) {
-                        None => impl_did,
-                        Some(did) => did
-                    }
-                };
-                self.report_static_candidate(idx, did)
-            }
-            MethodStaticUnboxedClosure(did) => {
-                self.report_static_candidate(idx, did)
-            }
-            MethodTypeParam(ref mp) => {
-                self.report_param_candidate(idx, mp.trait_ref.def_id)
+    fn has_applicable_self(&self, method: &ty::Method) -> bool {
+        // "fast track" -- check for usage of sugar
+        match method.explicit_self {
+            StaticExplicitSelfCategory => {
+                // fallthrough
             }
-            MethodTraitObject(ref mo) => {
-                self.report_trait_candidate(idx, mo.trait_ref.def_id)
+            ByValueExplicitSelfCategory |
+            ByReferenceExplicitSelfCategory(..) |
+            ByBoxExplicitSelfCategory => {
+                return true;
             }
         }
-    }
 
-    fn report_static_candidate(&self, idx: uint, did: DefId) {
-        let span = if did.krate == ast::LOCAL_CRATE {
-            self.tcx().map.span(did.node)
-        } else {
-            self.span
-        };
-        span_note!(self.tcx().sess, span,
-            "candidate #{} is `{}`",
-            idx + 1u, ty::item_path_str(self.tcx(), did));
-    }
-
-    fn report_param_candidate(&self, idx: uint, did: DefId) {
-        span_note!(self.tcx().sess, self.span,
-            "candidate #{} derives from the bound `{}`",
-            idx + 1u, ty::item_path_str(self.tcx(), did));
+        // FIXME -- check for types that deref to `Self`,
+        // like `Rc<Self>` and so on.
+        //
+        // Note also that the current code will break if this type
+        // includes any of the type parameters defined on the method
+        // -- but this could be overcome.
+        return false;
     }
 
-    fn report_trait_candidate(&self, idx: uint, did: DefId) {
-        span_note!(self.tcx().sess, self.span,
-            "candidate #{} derives from the type of the receiver, \
-            which is the trait `{}`",
-            idx + 1u, ty::item_path_str(self.tcx(), did));
+    fn record_static_candidate(&mut self, source: CandidateSource) {
+        self.static_candidates.push(source);
     }
 
-    fn infcx(&'a self) -> &'a infer::InferCtxt<'a, 'tcx> {
-        &self.fcx.inh.infcx
+    fn xform_self_ty(&self, method: &Rc<ty::Method>, substs: &subst::Substs) -> ty::t {
+        let xform_self_ty = method.fty.sig.inputs[0].subst(self.tcx(), substs);
+        self.replace_late_bound_regions_with_fresh_var(method.fty.sig.binder_id, &xform_self_ty)
     }
 
-    fn tcx(&self) -> &'a ty::ctxt<'tcx> {
-        self.fcx.tcx()
+    fn replace_late_bound_regions_with_fresh_var<T>(&self, binder_id: ast::NodeId, value: &T) -> T
+        where T : TypeFoldable + Repr
+    {
+        let (_, value) = replace_late_bound_regions(
+            self.fcx.tcx(),
+            binder_id,
+            value,
+            |br| self.fcx.infcx().next_region_var(infer::LateBoundRegion(self.span, br)));
+        value
     }
+}
 
-    fn ty_to_string(&self, t: ty::t) -> String {
-        self.fcx.infcx().ty_to_string(t)
-    }
+fn trait_method(tcx: &ty::ctxt,
+                trait_def_id: ast::DefId,
+                method_name: ast::Name)
+                -> Option<(uint, Rc<ty::Method>)>
+{
+    /*!
+     * Find method with name `method_name` defined in `trait_def_id` and return it,
+     * along with its index (or `None`, if no such method).
+     */
 
-    fn did_to_string(&self, did: DefId) -> String {
-        ty::item_path_str(self.tcx(), did)
-    }
+    let trait_items = ty::trait_items(tcx, trait_def_id);
+    trait_items
+        .iter()
+        .enumerate()
+        .find(|&(_, ref item)| item.ident().name == method_name)
+        .and_then(|(idx, item)| item.as_opt_method().map(|m| (idx, m)))
+}
 
-    fn bug(&self, s: &str) -> ! {
-        self.tcx().sess.span_bug(self.span, s)
-    }
+fn impl_method(tcx: &ty::ctxt,
+               impl_def_id: ast::DefId,
+               method_name: ast::Name)
+               -> Option<Rc<ty::Method>>
+{
+    let impl_items = tcx.impl_items.borrow();
+    let impl_items = impl_items.find(&impl_def_id).unwrap();
+    impl_items
+        .iter()
+        .map(|&did| ty::impl_or_trait_item(tcx, did.def_id()))
+        .find(|m| m.ident().name == method_name)
+        .and_then(|item| item.as_opt_method())
 }
 
 impl Repr for Candidate {
     fn repr(&self, tcx: &ty::ctxt) -> String {
-        format!("Candidate(rcvr_ty={}, rcvr_substs={}, method_ty={}, \
-                 origin={})",
-                self.rcvr_match_condition.repr(tcx),
+        format!("Candidate(rcvr_ty={}, rcvr_substs={}, method_ty={}, origin={})",
+                self.xform_self_ty.repr(tcx),
                 self.rcvr_substs.repr(tcx),
                 self.method_ty.repr(tcx),
                 self.origin)
     }
 }
 
-impl Repr for RcvrMatchCondition {
+impl Repr for ExtensionCandidate {
     fn repr(&self, tcx: &ty::ctxt) -> String {
-        match *self {
-            RcvrMatchesIfObject(d) => {
-                format!("RcvrMatchesIfObject({})", d.repr(tcx))
+        format!("ExtensionCandidate(obligation={}, xform_self_ty={}, method_ty={}, method_num={})",
+                self.obligation.repr(tcx),
+                self.xform_self_ty.repr(tcx),
+                self.method_ty.repr(tcx),
+                self.method_num)
+    }
+}
+
+impl Candidate {
+    fn to_source(&self) -> CandidateSource {
+        match self.origin {
+            MethodStatic(def_id) => {
+                ImplSource(def_id)
+            }
+            MethodStaticUnboxedClosure(..) => {
+                fail!("MethodStaticUnboxedClosure only used in trans")
             }
-            RcvrMatchesIfSubtype(t) => {
-                format!("RcvrMatchesIfSubtype({})", t.repr(tcx))
+            MethodTypeParam(ref param) => {
+                TraitSource(param.trait_ref.def_id)
             }
-            RcvrMatchesIfEqtype(t) => {
-                format!("RcvrMatchesIfEqtype({})", t.repr(tcx))
+            MethodTraitObject(ref obj) => {
+                TraitSource(obj.trait_ref.def_id)
             }
         }
     }
 }
+
+impl ExtensionCandidate {
+    fn to_source(&self) -> CandidateSource {
+        TraitSource(self.obligation.trait_ref.def_id)
+    }
+}
diff --git a/src/librustc/middle/typeck/check/mod.rs b/src/librustc/middle/typeck/check/mod.rs
index b9ad4a5f72a..5f7b31e573a 100644
--- a/src/librustc/middle/typeck/check/mod.rs
+++ b/src/librustc/middle/typeck/check/mod.rs
@@ -77,6 +77,7 @@ type parameter).
 */
 
 
+use driver::session::Session;
 use middle::const_eval;
 use middle::def;
 use middle::lang_items::IteratorItem;
@@ -2924,46 +2925,24 @@ fn check_expr_with_unifier(fcx: &FnCtxt,
                                                 fcx.expr_ty(&*rcvr));
 
         let tps = tps.iter().map(|ast_ty| fcx.to_ty(&**ast_ty)).collect::<Vec<_>>();
-        let fn_ty = match method::lookup(fcx, expr, &*rcvr,
+        let fn_ty = match method::lookup(fcx,
+                                         expr,
+                                         &*rcvr,
                                          method_name.node.name,
-                                         expr_t, tps.as_slice(),
+                                         expr_t,
+                                         tps.as_slice(),
                                          DontDerefArgs,
                                          CheckTraitsAndInherentMethods,
-                                         AutoderefReceiver, IgnoreStaticMethods) {
-            Some(method) => {
+                                         AutoderefReceiver) {
+            Ok(method) => {
                 let method_ty = method.ty;
                 let method_call = MethodCall::expr(expr.id);
                 fcx.inh.method_map.borrow_mut().insert(method_call, method);
                 method_ty
             }
-            None => {
-                debug!("(checking method call) failing expr is {}", expr.id);
-
-                fcx.type_error_message(method_name.span,
-                  |actual| {
-                      format!("type `{}` does not implement any \
-                               method in scope named `{}`",
-                              actual,
-                              token::get_ident(method_name.node))
-                  },
-                  expr_t,
-                  None);
-
-                // Add error type for the result
+            Err(error) => {
+                method::report_error(fcx, method_name.span, expr_t, method_name.node.name, error);
                 fcx.write_error(expr.id);
-
-                // Check for potential static matches (missing self parameters)
-                method::lookup(fcx,
-                               expr,
-                               &*rcvr,
-                               method_name.node.name,
-                               expr_t,
-                               tps.as_slice(),
-                               DontDerefArgs,
-                               CheckTraitsAndInherentMethods,
-                               DontAutoderefReceiver,
-                               ReportStaticMethods);
-
                 ty::mk_err()
             }
         };
@@ -3466,9 +3445,8 @@ fn check_expr_with_unifier(fcx: &FnCtxt,
                              tps.as_slice(),
                              DontDerefArgs,
                              CheckTraitsAndInherentMethods,
-                             AutoderefReceiver,
-                             IgnoreStaticMethods) {
-            Some(_) => {
+                             AutoderefReceiver) {
+            Ok(_) => {
                 fcx.type_error_message(
                     field.span,
                     |actual| {
@@ -3481,7 +3459,7 @@ fn check_expr_with_unifier(fcx: &FnCtxt,
                     "maybe a missing `()` to call it? If not, try an anonymous function.");
             }
 
-            None => {
+            Err(_) => {
                 fcx.type_error_message(
                     expr.span,
                     |actual| {
diff --git a/src/libsyntax/ast_map/mod.rs b/src/libsyntax/ast_map/mod.rs
index 60e4db405d7..b82a4a0b997 100644
--- a/src/libsyntax/ast_map/mod.rs
+++ b/src/libsyntax/ast_map/mod.rs
@@ -536,6 +536,14 @@ impl<'ast> Map<'ast> {
             .unwrap_or_else(|| fail!("AstMap.span: could not find span for id {}", id))
     }
 
+    pub fn def_id_span(&self, def_id: DefId, fallback: Span) -> Span {
+        if def_id.krate == LOCAL_CRATE {
+            self.span(def_id.node)
+        } else {
+            fallback
+        }
+    }
+
     pub fn node_to_string(&self, id: NodeId) -> String {
         node_id_to_string(self, id)
     }