about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--src/libcore/num/mod.rs4
-rw-r--r--src/libcore/ops.rs2
-rw-r--r--src/librustc/middle/borrowck/graphviz.rs8
-rw-r--r--src/librustc/middle/cfg/graphviz.rs16
-rw-r--r--src/librustc/middle/traits/doc.rs7
-rw-r--r--src/librustc/middle/traits/mod.rs18
-rw-r--r--src/librustc/middle/traits/select.rs442
-rw-r--r--src/librustc/middle/ty.rs19
-rw-r--r--src/librustc/middle/typeck/check/method.rs1238
-rw-r--r--src/librustc/middle/typeck/check/mod.rs101
-rw-r--r--src/librustc/middle/typeck/check/regionmanip.rs35
-rw-r--r--src/librustc/middle/typeck/check/wf.rs6
-rw-r--r--src/librustc/middle/typeck/infer/coercion.rs4
-rw-r--r--src/librustc/middle/typeck/infer/combine.rs39
-rw-r--r--src/librustc/middle/typeck/infer/mod.rs4
-rw-r--r--src/librustc/middle/typeck/infer/sub.rs21
-rw-r--r--src/libsyntax/ast_map/mod.rs8
-rw-r--r--src/test/auxiliary/regions-bounded-method-type-parameters-cross-crate-lib.rs11
-rw-r--r--src/test/compile-fail/coherence-blanket-conflicts-with-blanket-implemented.rs38
-rw-r--r--src/test/compile-fail/coherence-blanket-conflicts-with-blanket-unimplemented.rs34
-rw-r--r--src/test/compile-fail/issue-17033.rs4
-rw-r--r--src/test/compile-fail/issue-17636.rs2
-rw-r--r--src/test/compile-fail/issue-2149.rs1
-rw-r--r--src/test/compile-fail/issue-7575.rs19
-rw-r--r--src/test/compile-fail/method-ambig-one-trait-coerce.rs44
-rw-r--r--src/test/compile-fail/method-ambig-one-trait-unknown-int-type.rs45
-rw-r--r--src/test/compile-fail/method-ambig-two-traits-cross-crate.rs (renamed from src/test/compile-fail/ambig_impl_2_exe.rs)9
-rw-r--r--src/test/compile-fail/method-ambig-two-traits-from-bounds.rs (renamed from src/test/compile-fail/ambig_impl_bounds.rs)4
-rw-r--r--src/test/compile-fail/method-ambig-two-traits-with-default-method.rs (renamed from src/test/compile-fail/ambig-default-method.rs)10
-rw-r--r--src/test/compile-fail/method-commit-to-trait.rs33
-rw-r--r--src/test/compile-fail/regions-bounded-method-type-parameters-cross-crate.rs6
-rw-r--r--src/test/compile-fail/selftype-traittype.rs2
-rw-r--r--src/test/compile-fail/unique-pinned-nocopy.rs2
-rw-r--r--src/test/compile-fail/unique-vec-res.rs4
-rw-r--r--src/test/compile-fail/vec-res-add.rs4
-rw-r--r--src/test/compile-fail/wrong-mul-method-signature.rs12
-rw-r--r--src/test/run-pass/method-two-trait-defer-resolution-1.rs (renamed from src/test/compile-fail/ambig_impl_unify.rs)24
-rw-r--r--src/test/run-pass/method-two-trait-defer-resolution-2.rs48
38 files changed, 1464 insertions, 864 deletions
diff --git a/src/libcore/num/mod.rs b/src/libcore/num/mod.rs
index 42ea138acd4..3dceb42e206 100644
--- a/src/libcore/num/mod.rs
+++ b/src/libcore/num/mod.rs
@@ -1374,7 +1374,7 @@ macro_rules! checkeddiv_int_impl(
                 if *v == 0 || (*self == $min && *v == -1) {
                     None
                 } else {
-                    Some(self / *v)
+                    Some(*self / *v)
                 }
             }
         }
@@ -1395,7 +1395,7 @@ macro_rules! checkeddiv_uint_impl(
                 if *v == 0 {
                     None
                 } else {
-                    Some(self / *v)
+                    Some(*self / *v)
                 }
             }
         }
diff --git a/src/libcore/ops.rs b/src/libcore/ops.rs
index 6de5f31c6d1..f6e3e7f61cf 100644
--- a/src/libcore/ops.rs
+++ b/src/libcore/ops.rs
@@ -638,7 +638,7 @@ shr_impl!(uint u8 u16 u32 u64 int i8 i16 i32 i64)
  * ```
  */
 #[lang="index"]
-pub trait Index<Index, Result> {
+pub trait Index<Index, Sized? Result> {
     /// The method for the indexing (`Foo[Bar]`) operation
     fn index<'a>(&'a self, index: &Index) -> &'a Result;
 }
diff --git a/src/librustc/middle/borrowck/graphviz.rs b/src/librustc/middle/borrowck/graphviz.rs
index aab7fe8f31e..6c6750ad24b 100644
--- a/src/librustc/middle/borrowck/graphviz.rs
+++ b/src/librustc/middle/borrowck/graphviz.rs
@@ -142,8 +142,8 @@ impl<'a, 'tcx> dot::Labeller<'a, Node<'a>, Edge<'a>> for DataflowLabeller<'a, 't
 }
 
 impl<'a, 'tcx> dot::GraphWalk<'a, Node<'a>, Edge<'a>> for DataflowLabeller<'a, 'tcx> {
-    fn nodes(&self) -> dot::Nodes<'a, Node<'a>> { self.inner.nodes() }
-    fn edges(&self) -> dot::Edges<'a, Edge<'a>> { self.inner.edges() }
-    fn source(&self, edge: &Edge<'a>) -> Node<'a> { self.inner.source(edge) }
-    fn target(&self, edge: &Edge<'a>) -> Node<'a> { self.inner.target(edge) }
+    fn nodes(&'a self) -> dot::Nodes<'a, Node<'a>> { self.inner.nodes() }
+    fn edges(&'a self) -> dot::Edges<'a, Edge<'a>> { self.inner.edges() }
+    fn source(&'a self, edge: &Edge<'a>) -> Node<'a> { self.inner.source(edge) }
+    fn target(&'a self, edge: &Edge<'a>) -> Node<'a> { self.inner.target(edge) }
 }
diff --git a/src/librustc/middle/cfg/graphviz.rs b/src/librustc/middle/cfg/graphviz.rs
index bc48e476aec..fcd9a166c6a 100644
--- a/src/librustc/middle/cfg/graphviz.rs
+++ b/src/librustc/middle/cfg/graphviz.rs
@@ -91,19 +91,19 @@ impl<'a, 'ast> dot::Labeller<'a, Node<'a>, Edge<'a>> for LabelledCFG<'a, 'ast> {
 }
 
 impl<'a> dot::GraphWalk<'a, Node<'a>, Edge<'a>> for &'a cfg::CFG {
-    fn nodes(&self) -> dot::Nodes<'a, Node<'a>> {
+    fn nodes(&'a self) -> dot::Nodes<'a, Node<'a>> {
         let mut v = Vec::new();
         self.graph.each_node(|i, nd| { v.push((i, nd)); true });
         dot::maybe_owned_vec::Growable(v)
     }
-    fn edges(&self) -> dot::Edges<'a, Edge<'a>> {
+    fn edges(&'a self) -> dot::Edges<'a, Edge<'a>> {
         self.graph.all_edges().iter().collect()
     }
-    fn source(&self, edge: &Edge<'a>) -> Node<'a> {
+    fn source(&'a self, edge: &Edge<'a>) -> Node<'a> {
         let i = edge.source();
         (i, self.graph.node(i))
     }
-    fn target(&self, edge: &Edge<'a>) -> Node<'a> {
+    fn target(&'a self, edge: &Edge<'a>) -> Node<'a> {
         let i = edge.target();
         (i, self.graph.node(i))
     }
@@ -111,9 +111,9 @@ impl<'a> dot::GraphWalk<'a, Node<'a>, Edge<'a>> for &'a cfg::CFG {
 
 impl<'a, 'ast> dot::GraphWalk<'a, Node<'a>, Edge<'a>> for LabelledCFG<'a, 'ast>
 {
-    fn nodes(&self) -> dot::Nodes<'a, Node<'a>> { self.cfg.nodes() }
-    fn edges(&self) -> dot::Edges<'a, Edge<'a>> { self.cfg.edges() }
-    fn source(&self, edge: &Edge<'a>) -> Node<'a> { self.cfg.source(edge) }
-    fn target(&self, edge: &Edge<'a>) -> Node<'a> { self.cfg.target(edge) }
+    fn nodes(&'a self) -> dot::Nodes<'a, Node<'a>> { self.cfg.nodes() }
+    fn edges(&'a self) -> dot::Edges<'a, Edge<'a>> { self.cfg.edges() }
+    fn source(&'a self, edge: &Edge<'a>) -> Node<'a> { self.cfg.source(edge) }
+    fn target(&'a self, edge: &Edge<'a>) -> Node<'a> { self.cfg.target(edge) }
 }
 
diff --git a/src/librustc/middle/traits/doc.rs b/src/librustc/middle/traits/doc.rs
index 742c4cb5de0..f24121d9a3a 100644
--- a/src/librustc/middle/traits/doc.rs
+++ b/src/librustc/middle/traits/doc.rs
@@ -272,4 +272,11 @@ nested obligation `int : Bar<U>` to find out that `U=uint`.
 It would be good to only do *just as much* nested resolution as
 necessary. Currently, though, we just do a full resolution.
 
+## Method matching
+
+Method dispach follows a slightly different path than normal trait
+selection. This is because it must account for the transformed self
+type of the receiver and various other complications. The procedure is
+described in `select.rs` in the "METHOD MATCHING" section.
+
 */
diff --git a/src/librustc/middle/traits/mod.rs b/src/librustc/middle/traits/mod.rs
index f0282804540..76715561b03 100644
--- a/src/librustc/middle/traits/mod.rs
+++ b/src/librustc/middle/traits/mod.rs
@@ -24,6 +24,8 @@ use syntax::codemap::{Span, DUMMY_SP};
 pub use self::fulfill::FulfillmentContext;
 pub use self::select::SelectionContext;
 pub use self::select::SelectionCache;
+pub use self::select::{MethodMatchResult, MethodMatched, MethodAmbiguous, MethodDidNotMatch};
+pub use self::select::{MethodMatchedData}; // intentionally don't export variants
 pub use self::util::supertraits;
 pub use self::util::transitive_bounds;
 pub use self::util::Supertraits;
@@ -219,22 +221,6 @@ pub struct VtableParamData {
     pub bound: Rc<ty::TraitRef>,
 }
 
-pub fn evaluate_obligation<'a,'tcx>(infcx: &InferCtxt<'a,'tcx>,
-                                    param_env: &ty::ParameterEnvironment,
-                                    obligation: &Obligation,
-                                    typer: &Typer<'tcx>)
-                                    -> bool
-{
-    /*!
-     * Attempts to resolve the obligation given. Returns `None` if
-     * we are unable to resolve, either because of ambiguity or
-     * due to insufficient inference.
-     */
-
-    let mut selcx = select::SelectionContext::new(infcx, param_env, typer);
-    selcx.evaluate_obligation(obligation)
-}
-
 pub fn select_inherent_impl<'a,'tcx>(infcx: &InferCtxt<'a,'tcx>,
                                      param_env: &ty::ParameterEnvironment,
                                      typer: &Typer<'tcx>,
diff --git a/src/librustc/middle/traits/select.rs b/src/librustc/middle/traits/select.rs
index aca7054018d..f923cf1e590 100644
--- a/src/librustc/middle/traits/select.rs
+++ b/src/librustc/middle/traits/select.rs
@@ -62,6 +62,23 @@ pub struct SelectionCache {
     hashmap: RefCell<HashMap<Rc<ty::TraitRef>, SelectionResult<Candidate>>>,
 }
 
+pub enum MethodMatchResult {
+    MethodMatched(MethodMatchedData),
+    MethodAmbiguous(/* list of impls that could apply */ Vec<ast::DefId>),
+    MethodDidNotMatch,
+}
+
+#[deriving(Show)]
+pub enum MethodMatchedData {
+    // In the case of a precise match, we don't really need to store
+    // how the match was found. So don't.
+    PreciseMethodMatch,
+
+    // In the case of a coercion, we need to know the precise impl so
+    // that we can determine the type to which things were coerced.
+    CoerciveMethodMatch(/* impl we matched */ ast::DefId)
+}
+
 /**
  * The selection process begins by considering all impls, where
  * clauses, and so forth that might resolve an obligation.  Sometimes
@@ -190,27 +207,51 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
     ///////////////////////////////////////////////////////////////////////////
     // EVALUATION
     //
-    // Tests whether an obligation can be selected or whether an impl can be
-    // applied to particular types. It skips the "confirmation" step and
-    // hence completely ignores output type parameters.
+    // Tests whether an obligation can be selected or whether an impl
+    // can be applied to particular types. It skips the "confirmation"
+    // step and hence completely ignores output type parameters.
     //
     // The result is "true" if the obliation *may* hold and "false" if
     // we can be sure it does not.
 
-    pub fn evaluate_obligation(&mut self,
-                               obligation: &Obligation)
-                               -> bool
+    pub fn evaluate_obligation_intercrate(&mut self,
+                                          obligation: &Obligation)
+                                          -> bool
     {
         /*!
          * Evaluates whether the obligation `obligation` can be
-         * satisfied (by any means).
+         * satisfied (by any means). This "intercrate" version allows
+         * for the possibility that unbound type variables may be
+         * instantiated with types from another crate. This is
+         * important for coherence. In practice this means that
+         * unbound type variables must always be considered ambiguous.
          */
 
-        debug!("evaluate_obligation({})",
+        debug!("evaluate_obligation_intercrate({})",
                obligation.repr(self.tcx()));
 
         let stack = self.push_stack(None, obligation);
-        self.evaluate_stack(&stack).may_apply()
+        self.evaluate_stack_intercrate(&stack).may_apply()
+    }
+
+    pub fn evaluate_obligation_intracrate(&mut self,
+                                            obligation: &Obligation)
+                                            -> bool
+    {
+        /*!
+         * Evaluates whether the obligation `obligation` can be
+         * satisfied (by any means). This "intracrate" version does
+         * not allow for the possibility that unbound type variables
+         * may be instantiated with types from another crate; hence,
+         * if there are unbound inputs but no crates locally visible,
+         * it considers the result to be unimplemented.
+         */
+
+        debug!("evaluate_obligation_intracrate({})",
+               obligation.repr(self.tcx()));
+
+        let stack = self.push_stack(None, obligation);
+        self.evaluate_stack_intracrate(&stack).may_apply()
     }
 
     fn evaluate_builtin_bound_recursively(&mut self,
@@ -246,12 +287,26 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
                obligation.repr(self.tcx()));
 
         let stack = self.push_stack(previous_stack.map(|x| x), obligation);
-        let result = self.evaluate_stack(&stack);
+
+        // FIXME(#17901) -- Intercrate vs intracrate resolution is a
+        // tricky question here. For coherence, we want
+        // intercrate. Also, there was a nasty cycle around impls like
+        // `impl<T:Eq> Eq for Vec<T>` (which would wind up checking
+        // whether `$0:Eq`, where $0 was the value substituted for
+        // `T`, which could then be checked against the very same
+        // impl). This problem is avoided by the stricter rules around
+        // unbound type variables by intercrate. I suspect that in the
+        // latter case a more fine-grained rule would suffice (i.e.,
+        // consider it ambiguous if even 1 impl matches, no need to
+        // figure out which one, but call it unimplemented if 0 impls
+        // match).
+        let result = self.evaluate_stack_intercrate(&stack);
+
         debug!("result: {}", result);
         result
     }
 
-    fn evaluate_stack(&mut self,
+    fn evaluate_stack_intercrate(&mut self,
                       stack: &ObligationStack)
                       -> EvaluationResult
     {
@@ -259,13 +314,20 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
         // an impl.  Even if there are no impls in this crate, perhaps
         // the type would be unified with something from another crate
         // that does provide an impl.
-        let input_types = &stack.skol_trait_ref.substs.types;
+        let input_types = stack.skol_trait_ref.input_types();
         if input_types.iter().any(|&t| ty::type_is_skolemized(t)) {
-            debug!("evaluate_stack({}) --> unbound argument, must be ambiguous",
+            debug!("evaluate_stack_intercrate({}) --> unbound argument, must be ambiguous",
                    stack.skol_trait_ref.repr(self.tcx()));
             return EvaluatedToAmbig;
         }
 
+        self.evaluate_stack_intracrate(stack)
+    }
+
+    fn evaluate_stack_intracrate(&mut self,
+                                 stack: &ObligationStack)
+                                 -> EvaluationResult
+    {
         // If there is any previous entry on the stack that precisely
         // matches this obligation, then we can assume that the
         // obligation is satisfied for now (still all other conditions
@@ -290,7 +352,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
             .skip(1) // skip top-most frame
             .any(|prev| stack.skol_trait_ref == prev.skol_trait_ref)
         {
-            debug!("evaluate_stack({}) --> recursive",
+            debug!("evaluate_stack_intracrate({}) --> recursive",
                    stack.skol_trait_ref.repr(self.tcx()));
             return EvaluatedToOk;
         }
@@ -320,7 +382,311 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
         self.infcx.probe(|| {
             match self.match_impl(impl_def_id, obligation) {
                 Ok(substs) => {
-                    let vtable_impl = self.vtable_impl(impl_def_id, substs, obligation.cause, 0);
+                    let vtable_impl = self.vtable_impl(impl_def_id,
+                                                       substs,
+                                                       obligation.cause,
+                                                       obligation.recursion_depth + 1);
+                    self.winnow_selection(None, VtableImpl(vtable_impl)).may_apply()
+                }
+                Err(()) => {
+                    false
+                }
+            }
+        })
+    }
+
+    ///////////////////////////////////////////////////////////////////////////
+    // METHOD MATCHING
+    //
+    // Method matching is a variation on the normal select/evaluation
+    // situation.  In this scenario, rather than having a full trait
+    // reference to select from, we start with an expression like
+    // `receiver.method(...)`. This means that we have `rcvr_ty`, the
+    // type of the receiver, and we have a possible trait that
+    // supplies `method`. We must determine whether the receiver is
+    // applicable, taking into account the transformed self type
+    // declared on `method`. We also must consider the possibility
+    // that `receiver` can be *coerced* into a suitable type (for
+    // example, a receiver type like `&(Any+Send)` might be coerced
+    // into a receiver like `&Any` to allow for method dispatch).  See
+    // the body of `evaluate_method_obligation()` for more details on
+    // the algorithm.
+
+    pub fn evaluate_method_obligation(&mut self,
+                                      rcvr_ty: ty::t,
+                                      xform_self_ty: ty::t,
+                                      obligation: &Obligation)
+                                      -> MethodMatchResult
+    {
+        /*!
+         * Determine whether a trait-method is applicable to a receiver of
+         * type `rcvr_ty`. *Does not affect the inference state.*
+         *
+         * - `rcvr_ty` -- type of the receiver
+         * - `xform_self_ty` -- transformed self type declared on the method, with `Self`
+         *   to a fresh type variable
+         * - `obligation` -- a reference to the trait where the method is declared, with
+         *   the input types on the trait replaced with fresh type variables
+         */
+
+        // Here is the situation. We have a trait method declared (say) like so:
+        //
+        //     trait TheTrait {
+        //         fn the_method(self: Rc<Self>, ...) { ... }
+        //     }
+        //
+        // And then we have a call looking (say) like this:
+        //
+        //     let x: Rc<Foo> = ...;
+        //     x.the_method()
+        //
+        // Now we want to decide if `TheTrait` is applicable. As a
+        // human, we can see that `TheTrait` is applicable if there is
+        // an impl for the type `Foo`. But how does the compiler know
+        // what impl to look for, given that our receiver has type
+        // `Rc<Foo>`? We need to take the method's self type into
+        // account.
+        //
+        // On entry to this function, we have the following inputs:
+        //
+        // - `rcvr_ty = Rc<Foo>`
+        // - `xform_self_ty = Rc<$0>`
+        // - `obligation = $0 as TheTrait`
+        //
+        // We do the match in two phases. The first is a *precise
+        // match*, which means that no coercion is required. This is
+        // the preferred way to match. It works by first making
+        // `rcvr_ty` a subtype of `xform_self_ty`. This unifies `$0`
+        // and `Foo`. We can then evaluate (roughly as normal) the
+        // trait reference `Foo as TheTrait`.
+        //
+        // If this fails, we fallback to a coercive match, described below.
+
+        match self.infcx.probe(|| self.match_method_precise(rcvr_ty, xform_self_ty, obligation)) {
+            Ok(()) => { return MethodMatched(PreciseMethodMatch); }
+            Err(_) => { }
+        }
+
+        // Coercive matches work slightly differently and cannot
+        // completely reuse the normal trait matching machinery
+        // (though they employ many of the same bits and pieces). To
+        // see how it works, let's continue with our previous example,
+        // but with the following declarations:
+        //
+        // ```
+        // trait Foo : Bar { .. }
+        // trait Bar : Baz { ... }
+        // trait Baz { ... }
+        // impl TheTrait for Bar {
+        //     fn the_method(self: Rc<Bar>, ...) { ... }
+        // }
+        // ```
+        //
+        // Now we see that the receiver type `Rc<Foo>` is actually an
+        // object type. And in fact the impl we want is an impl on the
+        // supertrait `Rc<Bar>`.  The precise matching procedure won't
+        // find it, however, because `Rc<Foo>` is not a subtype of
+        // `Rc<Bar>` -- it is *coercible* to `Rc<Bar>` (actually, such
+        // coercions are not yet implemented, but let's leave that
+        // aside for now).
+        //
+        // To handle this case, we employ a different procedure. Recall
+        // that our initial state is as follows:
+        //
+        // - `rcvr_ty = Rc<Foo>`
+        // - `xform_self_ty = Rc<$0>`
+        // - `obligation = $0 as TheTrait`
+        //
+        // We now go through each impl and instantiate all of its type
+        // variables, yielding the trait reference that the impl
+        // provides. In our example, the impl would provide `Bar as
+        // TheTrait`.  Next we (try to) unify the trait reference that
+        // the impl provides with the input obligation. This would
+        // unify `$0` and `Bar`. Now we can see whether the receiver
+        // type (`Rc<Foo>`) is *coercible to* the transformed self
+        // type (`Rc<$0> == Rc<Bar>`). In this case, the answer is
+        // yes, so the impl is considered a candidate.
+        //
+        // Note that there is the possibility of ambiguity here, even
+        // when all types are known. In our example, this might occur
+        // if there was *also* an impl of `TheTrait` for `Baz`. In
+        // this case, `Rc<Foo>` would be coercible to both `Rc<Bar>`
+        // and `Rc<Baz>`. (Note that it is not a *coherence violation*
+        // to have impls for both `Bar` and `Baz`, despite this
+        // ambiguity).  In this case, we report an error, listing all
+        // the applicable impls.  The use can explicitly "up-coerce"
+        // to the type they want.
+        //
+        // Note that this coercion step only considers actual impls
+        // found in the source. This is because all the
+        // compiler-provided impls (such as those for unboxed
+        // closures) do not have relevant coercions. This simplifies
+        // life immensely.
+
+        let mut impls =
+            self.assemble_method_candidates_from_impls(rcvr_ty, xform_self_ty, obligation);
+
+        if impls.len() > 1 {
+            impls.retain(|&c| self.winnow_method_impl(c, rcvr_ty, xform_self_ty, obligation));
+        }
+
+        if impls.len() > 1 {
+            return MethodAmbiguous(impls);
+        }
+
+        match impls.pop() {
+            Some(def_id) => MethodMatched(CoerciveMethodMatch(def_id)),
+            None => MethodDidNotMatch
+        }
+    }
+
+    pub fn confirm_method_match(&mut self,
+                                rcvr_ty: ty::t,
+                                xform_self_ty: ty::t,
+                                obligation: &Obligation,
+                                data: MethodMatchedData)
+    {
+        /*!
+         * Given the successful result of a method match, this
+         * function "confirms" the result, which basically repeats the
+         * various matching operations, but outside of any snapshot so
+         * that their effects are committed into the inference state.
+         */
+
+        let is_ok = match data {
+            PreciseMethodMatch => {
+                self.match_method_precise(rcvr_ty, xform_self_ty, obligation).is_ok()
+            }
+
+            CoerciveMethodMatch(impl_def_id) => {
+                self.match_method_coerce(impl_def_id, rcvr_ty, xform_self_ty, obligation).is_ok()
+            }
+        };
+
+        if !is_ok {
+            self.tcx().sess.span_bug(
+                obligation.cause.span,
+                format!("match not repeatable: {}, {}, {}, {}",
+                        rcvr_ty.repr(self.tcx()),
+                        xform_self_ty.repr(self.tcx()),
+                        obligation.repr(self.tcx()),
+                        data)[]);
+        }
+    }
+
+    fn match_method_precise(&mut self,
+                            rcvr_ty: ty::t,
+                            xform_self_ty: ty::t,
+                            obligation: &Obligation)
+                            -> Result<(),()>
+    {
+        /*!
+         * Implements the *precise method match* procedure described in
+         * `evaluate_method_obligation()`.
+         */
+
+        self.infcx.commit_if_ok(|| {
+            match self.infcx.sub_types(false, infer::RelateSelfType(obligation.cause.span),
+                                       rcvr_ty, xform_self_ty) {
+                Ok(()) => { }
+                Err(_) => { return Err(()); }
+            }
+
+            if self.evaluate_obligation_intracrate(obligation) {
+                Ok(())
+            } else {
+                Err(())
+            }
+        })
+    }
+
+    fn assemble_method_candidates_from_impls(&mut self,
+                                             rcvr_ty: ty::t,
+                                             xform_self_ty: ty::t,
+                                             obligation: &Obligation)
+                                             -> Vec<ast::DefId>
+    {
+        /*!
+         * Assembles a list of potentially applicable impls using the
+         * *coercive match* procedure described in
+         * `evaluate_method_obligation()`.
+         */
+
+        let mut candidates = Vec::new();
+
+        let all_impls = self.all_impls(obligation.trait_ref.def_id);
+        for &impl_def_id in all_impls.iter() {
+            self.infcx.probe(|| {
+                match self.match_method_coerce(impl_def_id, rcvr_ty, xform_self_ty, obligation) {
+                    Ok(_) => { candidates.push(impl_def_id); }
+                    Err(_) => { }
+                }
+            });
+        }
+
+        candidates
+    }
+
+    fn match_method_coerce(&mut self,
+                           impl_def_id: ast::DefId,
+                           rcvr_ty: ty::t,
+                           xform_self_ty: ty::t,
+                           obligation: &Obligation)
+                           -> Result<Substs, ()>
+    {
+        /*!
+         * Applies the *coercive match* procedure described in
+         * `evaluate_method_obligation()` to a particular impl.
+         */
+
+        // This is almost always expected to succeed. It
+        // causes the impl's self-type etc to be unified with
+        // the type variable that is shared between
+        // obligation/xform_self_ty. In our example, after
+        // this is done, the type of `xform_self_ty` would
+        // change from `Rc<$0>` to `Rc<Foo>` (because $0 is
+        // unified with `Foo`).
+        let substs = try!(self.match_impl(impl_def_id, obligation));
+
+        // Next, check whether we can coerce. For now we require
+        // that the coercion be a no-op.
+        let origin = infer::Misc(obligation.cause.span);
+        match infer::mk_coercety(self.infcx, true, origin,
+                                 rcvr_ty, xform_self_ty) {
+            Ok(None) => { /* Fallthrough */ }
+            Ok(Some(_)) | Err(_) => { return Err(()); }
+        }
+
+        Ok(substs)
+    }
+
+    fn winnow_method_impl(&mut self,
+                          impl_def_id: ast::DefId,
+                          rcvr_ty: ty::t,
+                          xform_self_ty: ty::t,
+                          obligation: &Obligation)
+                          -> bool
+    {
+        /*!
+         * A version of `winnow_impl` applicable to coerice method
+         * matching.  This is basically the same as `winnow_impl` but
+         * it uses the method matching procedure and is specific to
+         * impls.
+         */
+
+        debug!("winnow_method_impl: impl_def_id={} rcvr_ty={} xform_self_ty={} obligation={}",
+               impl_def_id.repr(self.tcx()),
+               rcvr_ty.repr(self.tcx()),
+               xform_self_ty.repr(self.tcx()),
+               obligation.repr(self.tcx()));
+
+        self.infcx.probe(|| {
+            match self.match_method_coerce(impl_def_id, rcvr_ty, xform_self_ty, obligation) {
+                Ok(substs) => {
+                    let vtable_impl = self.vtable_impl(impl_def_id,
+                                                       substs,
+                                                       obligation.cause,
+                                                       obligation.recursion_depth + 1);
                     self.winnow_selection(None, VtableImpl(vtable_impl)).may_apply()
                 }
                 Err(()) => {
@@ -456,24 +822,17 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
             return Ok(None);
         }
 
-        // If there are *NO* candidates, that might mean either that
-        // there is no impl or just that we can't know anything for
-        // sure.
+        // If there are *NO* candidates, that there are no impls --
+        // that we know of, anyway. Note that in the case where there
+        // are unbound type variables within the obligation, it might
+        // be the case that you could still satisfy the obligation
+        // from another crate by instantiating the type variables with
+        // a type from another crate that does have an impl. This case
+        // is checked for in `evaluate_obligation` (and hence users
+        // who might care about this case, like coherence, should use
+        // that function).
         if candidates.len() == 0 {
-            // Annoying edge case: if there are no impls, then there
-            // is no way that this trait reference is implemented,
-            // *unless* it contains unbound variables. In that case,
-            // it is possible that one of those unbound variables will
-            // be bound to a new type from some other crate which will
-            // also contain impls.
-            let skol_obligation_self_ty = self.infcx.skolemize(stack.obligation.self_ty());
-            return if !self.contains_skolemized_types(skol_obligation_self_ty) {
-                debug!("0 matches, unimpl");
-                Err(Unimplemented)
-            } else {
-                debug!("0 matches, ambig");
-                Ok(None)
-            };
+            return Err(Unimplemented);
         }
 
         // Just one candidate left.
@@ -491,7 +850,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
         // scope. Otherwise, use the generic tcx cache, since the
         // result holds across all environments.
         if
-            cache_skol_trait_ref.substs.types.iter().any(
+            cache_skol_trait_ref.input_types().iter().any(
                 |&t| ty::type_has_self(t) || ty::type_has_params(t))
         {
             &self.param_env.selection_cache
@@ -1291,8 +1650,9 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
         // it'll do for now until we get the new trait-bound
         // region skolemization working.
         let (_, new_signature) =
-            regionmanip::replace_late_bound_regions_in_fn_sig(
+            regionmanip::replace_late_bound_regions(
                 self.tcx(),
+                closure_type.sig.binder_id,
                 &closure_type.sig,
                 |br| self.infcx.next_region_var(
                          infer::LateBoundRegion(obligation.cause.span, br)));
@@ -1365,6 +1725,10 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
                         trait_ref: Rc<ty::TraitRef>)
                         -> Result<(),()>
     {
+        debug!("match_trait_refs: obligation={} trait_ref={}",
+               obligation.repr(self.tcx()),
+               trait_ref.repr(self.tcx()));
+
         let origin = infer::RelateOutputImplTypes(obligation.cause.span);
         match self.infcx.sub_trait_refs(false,
                                         origin,
@@ -1648,3 +2012,13 @@ impl EvaluationResult {
         }
     }
 }
+
+impl MethodMatchResult {
+    pub fn may_apply(&self) -> bool {
+        match *self {
+            MethodMatched(_) => true,
+            MethodAmbiguous(_) => true,
+            MethodDidNotMatch => false,
+        }
+    }
+}
diff --git a/src/librustc/middle/ty.rs b/src/librustc/middle/ty.rs
index dbaebd07b02..a7ce93279bd 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,9 +1247,21 @@ 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()
     }
+
+    pub fn input_types(&self) -> &[ty::t] {
+        // Select only the "input types" from a trait-reference. For
+        // now this is all the types that appear in the
+        // trait-reference, but it should eventually exclude
+        // associated types.
+        self.substs.types.as_slice()
+    }
 }
 
 /// When type checking, we use the `ParameterEnvironment` to track
diff --git a/src/librustc/middle/typeck/check/method.rs b/src/librustc/middle/typeck/check/method.rs
index 798e4acd291..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,18 +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, ... .
-        autoderef_receiver: AutoderefReceiverFlag,
-        report_statics: StaticMethodsFlag)
-     -> 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,
@@ -187,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: autoderef_receiver,
-        report_statics: report_statics,
+        autoderef_receiver: DontAutoderefReceiver,
     };
 
-    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
@@ -230,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,
@@ -313,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);
 
@@ -358,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);
 
@@ -420,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) {
@@ -437,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, _) |
@@ -467,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 */ }
             }
 
@@ -483,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()
@@ -615,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,
@@ -652,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>) {
@@ -672,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()),
@@ -691,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 {
@@ -700,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
@@ -722,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 => {}
                 }
             }
         }
@@ -768,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,
@@ -857,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
@@ -870,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 {
@@ -880,7 +839,10 @@ impl<'a, 'tcx> LookupContext<'a, 'tcx> {
                     }
                     None => {}
                 }
-                Some(method)
+                Some(Ok(method))
+            }
+            Some(Err(error)) => {
+                Some(Err(error))
             }
         }
     }
@@ -944,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));
 
@@ -975,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));
 
@@ -1011,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");
 
@@ -1033,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 {
@@ -1057,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 `&[]`.
@@ -1084,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
@@ -1118,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
@@ -1166,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();
 
@@ -1183,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> {
@@ -1252,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
     {
@@ -1275,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();
 
-        // static methods should never have gotten this far:
-        assert!(candidate.method_ty.explicit_self !=
-                ty::StaticExplicitSelfCategory);
+        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();
+        }
+
+        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
@@ -1312,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;
 
@@ -1321,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,
@@ -1373,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(),
@@ -1482,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
@@ -1495,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(..) => {}
         }
@@ -1506,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 |
@@ -1514,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,
@@ -1572,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 4aea9cfa293..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;
@@ -97,11 +98,8 @@ use middle::typeck::astconv::{ast_region_to_region, ast_ty_to_ty};
 use middle::typeck::astconv;
 use middle::typeck::check::_match::pat_ctxt;
 use middle::typeck::check::method::{AutoderefReceiver};
-use middle::typeck::check::method::{AutoderefReceiverFlag};
 use middle::typeck::check::method::{CheckTraitsAndInherentMethods};
-use middle::typeck::check::method::{DontAutoderefReceiver};
-use middle::typeck::check::method::{IgnoreStaticMethods, ReportStaticMethods};
-use middle::typeck::check::regionmanip::replace_late_bound_regions_in_fn_sig;
+use middle::typeck::check::regionmanip::replace_late_bound_regions;
 use middle::typeck::CrateCtxt;
 use middle::typeck::infer::{resolve_type, force_tvar};
 use middle::typeck::infer;
@@ -529,7 +527,7 @@ fn check_fn<'a, 'tcx>(ccx: &'a CrateCtxt<'a, 'tcx>,
 
     // First, we have to replace any bound regions in the fn type with free ones.
     // The free region references will be bound the node_id of the body block.
-    let (_, fn_sig) = replace_late_bound_regions_in_fn_sig(tcx, fn_sig, |br| {
+    let (_, fn_sig) = replace_late_bound_regions(tcx, fn_sig.binder_id, fn_sig, |br| {
         ty::ReFree(ty::FreeRegion {scope_id: body.id, bound_region: br})
     });
 
@@ -1531,6 +1529,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         &self.inh.infcx
     }
 
+    pub fn sess(&self) -> &Session {
+        &self.tcx().sess
+    }
+
     pub fn err_count_since_creation(&self) -> uint {
         self.ccx.tcx.sess.err_count() - self.err_count_on_creation
     }
@@ -2117,9 +2119,7 @@ fn try_overloaded_call<'a>(fcx: &FnCtxt,
                 method_name,
                 function_trait,
                 callee_type,
-                [],
-                DontAutoderefReceiver,
-                IgnoreStaticMethods) {
+                []) {
             None => continue,
             Some(method_callee) => method_callee,
         };
@@ -2160,7 +2160,7 @@ fn try_overloaded_deref(fcx: &FnCtxt,
         (PreferMutLvalue, Some(trait_did)) => {
             method::lookup_in_trait(fcx, span, base_expr.map(|x| &*x),
                                     token::intern("deref_mut"), trait_did,
-                                    base_ty, [], DontAutoderefReceiver, IgnoreStaticMethods)
+                                    base_ty, [])
         }
         _ => None
     };
@@ -2170,7 +2170,7 @@ fn try_overloaded_deref(fcx: &FnCtxt,
         (None, Some(trait_did)) => {
             method::lookup_in_trait(fcx, span, base_expr.map(|x| &*x),
                                     token::intern("deref"), trait_did,
-                                    base_ty, [], DontAutoderefReceiver, IgnoreStaticMethods)
+                                    base_ty, [])
         }
         (method, _) => method
     };
@@ -2231,9 +2231,7 @@ fn try_overloaded_slice(fcx: &FnCtxt,
                                         token::intern(method_name),
                                         trait_did,
                                         base_ty,
-                                        [],
-                                        DontAutoderefReceiver,
-                                        IgnoreStaticMethods)
+                                        [])
             }
             _ => None,
         }
@@ -2256,9 +2254,7 @@ fn try_overloaded_slice(fcx: &FnCtxt,
                                         token::intern(method_name),
                                         trait_did,
                                         base_ty,
-                                        [],
-                                        DontAutoderefReceiver,
-                                        IgnoreStaticMethods)
+                                        [])
             }
             _ => None,
         }
@@ -2314,9 +2310,7 @@ fn try_overloaded_index(fcx: &FnCtxt,
                                     token::intern("index_mut"),
                                     trait_did,
                                     base_ty,
-                                    [],
-                                    DontAutoderefReceiver,
-                                    IgnoreStaticMethods)
+                                    [])
         }
         _ => None,
     };
@@ -2330,9 +2324,7 @@ fn try_overloaded_index(fcx: &FnCtxt,
                                     token::intern("index"),
                                     trait_did,
                                     base_ty,
-                                    [],
-                                    DontAutoderefReceiver,
-                                    IgnoreStaticMethods)
+                                    [])
         }
         (method, _) => method,
     };
@@ -2376,9 +2368,7 @@ fn lookup_method_for_for_loop(fcx: &FnCtxt,
                                          token::intern("next"),
                                          trait_did,
                                          expr_type,
-                                         [],
-                                         DontAutoderefReceiver,
-                                         IgnoreStaticMethods);
+                                         []);
 
     // Regardless of whether the lookup succeeds, check the method arguments
     // so that we have *some* type for each argument.
@@ -2902,7 +2892,7 @@ fn check_expr_with_unifier(fcx: &FnCtxt,
 
         // Replace any bound regions that appear in the function
         // signature with region variables
-        let (_, fn_sig) = replace_late_bound_regions_in_fn_sig(fcx.tcx(), fn_sig, |br| {
+        let (_, fn_sig) = replace_late_bound_regions(fcx.tcx(), fn_sig.binder_id, fn_sig, |br| {
             fcx.infcx().next_region_var(infer::LateBoundRegion(call_expr.span, br))
         });
 
@@ -2935,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()
             }
         };
@@ -3069,13 +3037,11 @@ fn check_expr_with_unifier(fcx: &FnCtxt,
                                   trait_did: Option<ast::DefId>,
                                   lhs: &'a ast::Expr,
                                   rhs: Option<&P<ast::Expr>>,
-                                  autoderef_receiver: AutoderefReceiverFlag,
                                   unbound_method: ||) -> ty::t {
         let method = match trait_did {
             Some(trait_did) => {
                 method::lookup_in_trait(fcx, op_ex.span, Some(lhs), opname,
-                                        trait_did, lhs_ty, &[], autoderef_receiver,
-                                        IgnoreStaticMethods)
+                                        trait_did, lhs_ty, &[])
             }
             None => None
         };
@@ -3249,7 +3215,7 @@ fn check_expr_with_unifier(fcx: &FnCtxt,
             }
         };
         lookup_op_method(fcx, ex, lhs_resolved_t, token::intern(name),
-                         trait_did, lhs_expr, Some(rhs), DontAutoderefReceiver, || {
+                         trait_did, lhs_expr, Some(rhs), || {
             fcx.type_error_message(ex.span, |actual| {
                 format!("binary operation `{}` cannot be applied to type `{}`",
                         ast_util::binop_to_string(op),
@@ -3266,7 +3232,7 @@ fn check_expr_with_unifier(fcx: &FnCtxt,
                        rhs_expr: &ast::Expr,
                        rhs_t: ty::t) -> ty::t {
        lookup_op_method(fcx, ex, rhs_t, token::intern(mname),
-                        trait_did, rhs_expr, None, DontAutoderefReceiver, || {
+                        trait_did, rhs_expr, None, || {
             fcx.type_error_message(ex.span, |actual| {
                 format!("cannot apply unary operator `{}` to type `{}`",
                         op_str, actual)
@@ -3360,8 +3326,8 @@ fn check_expr_with_unifier(fcx: &FnCtxt,
             match expected_sty {
                 Some(ty::ty_closure(ref cenv)) => {
                     let (_, sig) =
-                        replace_late_bound_regions_in_fn_sig(
-                            tcx, &cenv.sig,
+                        replace_late_bound_regions(
+                            tcx, cenv.sig.binder_id, &cenv.sig,
                             |_| fcx.inh.infcx.fresh_bound_region(expr.id));
                     let onceness = match (&store, &cenv.store) {
                         // As the closure type and onceness go, only three
@@ -3479,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| {
@@ -3494,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/librustc/middle/typeck/check/regionmanip.rs b/src/librustc/middle/typeck/check/regionmanip.rs
index 5d75d590a09..a448a93c517 100644
--- a/src/librustc/middle/typeck/check/regionmanip.rs
+++ b/src/librustc/middle/typeck/check/regionmanip.rs
@@ -13,7 +13,7 @@
 use middle::subst::{ParamSpace, Subst, Substs};
 use middle::ty;
 use middle::ty_fold;
-use middle::ty_fold::TypeFolder;
+use middle::ty_fold::{TypeFolder, TypeFoldable};
 
 use syntax::ast;
 
@@ -23,31 +23,34 @@ use util::ppaux::Repr;
 
 // Helper functions related to manipulating region types.
 
-pub fn replace_late_bound_regions_in_fn_sig(
-        tcx: &ty::ctxt,
-        fn_sig: &ty::FnSig,
-        mapf: |ty::BoundRegion| -> ty::Region)
-        -> (HashMap<ty::BoundRegion,ty::Region>, ty::FnSig) {
-    debug!("replace_late_bound_regions_in_fn_sig({})", fn_sig.repr(tcx));
+pub fn replace_late_bound_regions<T>(
+    tcx: &ty::ctxt,
+    binder_id: ast::NodeId,
+    value: &T,
+    map_fn: |ty::BoundRegion| -> ty::Region)
+    -> (HashMap<ty::BoundRegion,ty::Region>, T)
+    where T : TypeFoldable + Repr
+{
+    debug!("replace_late_bound_regions(binder_id={}, value={})",
+           binder_id, value.repr(tcx));
 
     let mut map = HashMap::new();
-    let fn_sig = {
-        let mut f = ty_fold::RegionFolder::regions(tcx, |r| {
-            debug!("region r={}", r.to_string());
+    let new_value = {
+        let mut folder = ty_fold::RegionFolder::regions(tcx, |r| {
             match r {
-                ty::ReLateBound(s, br) if s == fn_sig.binder_id => {
-                    * match map.entry(br) {
-                        Vacant(entry) => entry.set(mapf(br)),
-                        Occupied(entry) => entry.into_mut(),
+                ty::ReLateBound(s, br) if s == binder_id => {
+                    match map.entry(br) {
+                        Vacant(entry) => *entry.set(map_fn(br)),
+                        Occupied(entry) => *entry.into_mut(),
                     }
                 }
                 _ => r
             }
         });
-        ty_fold::super_fold_sig(&mut f, fn_sig)
+        value.fold_with(&mut folder)
     };
     debug!("resulting map: {}", map);
-    (map, fn_sig)
+    (map, new_value)
 }
 
 pub enum WfConstraint {
diff --git a/src/librustc/middle/typeck/check/wf.rs b/src/librustc/middle/typeck/check/wf.rs
index 4c3cec1aff4..dc79fd4aa32 100644
--- a/src/librustc/middle/typeck/check/wf.rs
+++ b/src/librustc/middle/typeck/check/wf.rs
@@ -15,7 +15,7 @@ use middle::ty;
 use middle::ty_fold::{TypeFolder, TypeFoldable};
 use middle::typeck::astconv::AstConv;
 use middle::typeck::check::{FnCtxt, Inherited, blank_fn_ctxt, vtable2, regionck};
-use middle::typeck::check::regionmanip::replace_late_bound_regions_in_fn_sig;
+use middle::typeck::check::regionmanip::replace_late_bound_regions;
 use middle::typeck::CrateCtxt;
 use util::ppaux::Repr;
 
@@ -373,8 +373,8 @@ impl<'cx,'tcx> TypeFolder<'tcx> for BoundsChecker<'cx,'tcx> {
                 self.binding_count += 1;
 
                 let (_, fn_sig) =
-                    replace_late_bound_regions_in_fn_sig(
-                        self.fcx.tcx(), fn_sig,
+                    replace_late_bound_regions(
+                        self.fcx.tcx(), fn_sig.binder_id, fn_sig,
                         |br| ty::ReFree(ty::FreeRegion{scope_id: self.scope_id,
                                                        bound_region: br}));
 
diff --git a/src/librustc/middle/typeck/infer/coercion.rs b/src/librustc/middle/typeck/infer/coercion.rs
index 9f88bec7f42..e44aa3e8221 100644
--- a/src/librustc/middle/typeck/infer/coercion.rs
+++ b/src/librustc/middle/typeck/infer/coercion.rs
@@ -72,7 +72,6 @@ use middle::typeck::infer::{CoerceResult, resolve_type, Coercion};
 use middle::typeck::infer::combine::{CombineFields, Combine};
 use middle::typeck::infer::sub::Sub;
 use middle::typeck::infer::resolve::try_resolve_tvar_shallow;
-use util::common::indenter;
 use util::ppaux;
 use util::ppaux::Repr;
 
@@ -93,7 +92,6 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> {
         debug!("Coerce.tys({} => {})",
                a.repr(self.get_ref().infcx.tcx),
                b.repr(self.get_ref().infcx.tcx));
-        let _indent = indenter();
 
         // Special case: if the subtype is a sized array literal (`[T, ..n]`),
         // then it would get auto-borrowed to `&[T, ..n]` and then DST-ified
@@ -411,7 +409,7 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> {
 
         self.unpack_actual_value(ty_b, |sty_b|
             match (sty_a, sty_b) {
-                (&ty::ty_vec(t_a, Some(len)), _) => {
+                (&ty::ty_vec(t_a, Some(len)), &ty::ty_vec(_, None)) => {
                     let ty = ty::mk_vec(tcx, t_a, None);
                     Some((ty, ty::UnsizeLength(len)))
                 }
diff --git a/src/librustc/middle/typeck/infer/combine.rs b/src/librustc/middle/typeck/infer/combine.rs
index 15c4830646d..d2e062a20d2 100644
--- a/src/librustc/middle/typeck/infer/combine.rs
+++ b/src/librustc/middle/typeck/infer/combine.rs
@@ -363,28 +363,6 @@ pub fn super_fn_sigs<'tcx, C: Combine<'tcx>>(this: &C,
 
 pub fn super_tys<'tcx, C: Combine<'tcx>>(this: &C, a: ty::t, b: ty::t) -> cres<ty::t> {
 
-    // This is a horrible hack - historically, [T] was not treated as a type,
-    // so, for example, &T and &[U] should not unify. In fact the only thing
-    // &[U] should unify with is &[T]. We preserve that behaviour with this
-    // check.
-    fn check_ptr_to_unsized<'tcx, C: Combine<'tcx>>(this: &C,
-                                                    a: ty::t,
-                                                    b: ty::t,
-                                                    a_inner: ty::t,
-                                                    b_inner: ty::t,
-                                                    result: ty::t) -> cres<ty::t> {
-        match (&ty::get(a_inner).sty, &ty::get(b_inner).sty) {
-            (&ty::ty_vec(_, None), &ty::ty_vec(_, None)) |
-            (&ty::ty_str, &ty::ty_str) |
-            (&ty::ty_trait(..), &ty::ty_trait(..)) => Ok(result),
-            (&ty::ty_vec(_, None), _) | (_, &ty::ty_vec(_, None)) |
-            (&ty::ty_str, _) | (_, &ty::ty_str) |
-            (&ty::ty_trait(..), _) | (_, &ty::ty_trait(..))
-                => Err(ty::terr_sorts(expected_found(this, a, b))),
-            _ => Ok(result),
-        }
-    }
-
     let tcx = this.infcx().tcx;
     let a_sty = &ty::get(a).sty;
     let b_sty = &ty::get(b).sty;
@@ -402,6 +380,10 @@ pub fn super_tys<'tcx, C: Combine<'tcx>>(this: &C, a: ty::t, b: ty::t) -> cres<t
                     b.repr(this.infcx().tcx)).as_slice());
       }
 
+      (&ty::ty_err, _) | (_, &ty::ty_err) => {
+          Ok(ty::mk_err())
+      }
+
         // Relate integral variables to other types
         (&ty::ty_infer(IntVar(a_id)), &ty::ty_infer(IntVar(b_id))) => {
             try!(this.infcx().simple_vars(this.a_is_expected(),
@@ -442,8 +424,7 @@ pub fn super_tys<'tcx, C: Combine<'tcx>>(this: &C, a: ty::t, b: ty::t) -> cres<t
       (&ty::ty_bool, _) |
       (&ty::ty_int(_), _) |
       (&ty::ty_uint(_), _) |
-      (&ty::ty_float(_), _) |
-      (&ty::ty_err, _) => {
+      (&ty::ty_float(_), _) => {
         if ty::get(a).sty == ty::get(b).sty {
             Ok(a)
         } else {
@@ -494,13 +475,13 @@ pub fn super_tys<'tcx, C: Combine<'tcx>>(this: &C, a: ty::t, b: ty::t) -> cres<t
       }
 
       (&ty::ty_uniq(a_inner), &ty::ty_uniq(b_inner)) => {
-            let typ = try!(this.tys(a_inner, b_inner));
-            check_ptr_to_unsized(this, a, b, a_inner, b_inner, ty::mk_uniq(tcx, typ))
+          let typ = try!(this.tys(a_inner, b_inner));
+          Ok(ty::mk_uniq(tcx, typ))
       }
 
       (&ty::ty_ptr(ref a_mt), &ty::ty_ptr(ref b_mt)) => {
-            let mt = try!(this.mts(a_mt, b_mt));
-            check_ptr_to_unsized(this, a, b, a_mt.ty, b_mt.ty, ty::mk_ptr(tcx, mt))
+          let mt = try!(this.mts(a_mt, b_mt));
+          Ok(ty::mk_ptr(tcx, mt))
       }
 
       (&ty::ty_rptr(a_r, ref a_mt), &ty::ty_rptr(b_r, ref b_mt)) => {
@@ -516,7 +497,7 @@ pub fn super_tys<'tcx, C: Combine<'tcx>>(this: &C, a: ty::t, b: ty::t) -> cres<t
                 }
                 _ => try!(this.mts(a_mt, b_mt))
             };
-            check_ptr_to_unsized(this, a, b, a_mt.ty, b_mt.ty, ty::mk_rptr(tcx, r, mt))
+            Ok(ty::mk_rptr(tcx, r, mt))
       }
 
       (&ty::ty_vec(a_t, sz_a), &ty::ty_vec(b_t, sz_b)) => {
diff --git a/src/librustc/middle/typeck/infer/mod.rs b/src/librustc/middle/typeck/infer/mod.rs
index 7c455b85707..a466581ef39 100644
--- a/src/librustc/middle/typeck/infer/mod.rs
+++ b/src/librustc/middle/typeck/infer/mod.rs
@@ -28,7 +28,7 @@ use middle::ty::{TyVid, IntVid, FloatVid, RegionVid};
 use middle::ty;
 use middle::ty_fold;
 use middle::ty_fold::{TypeFolder, TypeFoldable};
-use middle::typeck::check::regionmanip::replace_late_bound_regions_in_fn_sig;
+use middle::typeck::check::regionmanip::replace_late_bound_regions;
 use std::cell::{RefCell};
 use std::collections::HashMap;
 use std::rc::Rc;
@@ -962,7 +962,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
                                                         HashMap<ty::BoundRegion,
                                                                 ty::Region>) {
         let (map, fn_sig) =
-            replace_late_bound_regions_in_fn_sig(self.tcx, fsig, |br| {
+            replace_late_bound_regions(self.tcx, fsig.binder_id, fsig, |br| {
                 let rvar = self.next_region_var(
                     BoundRegionInFnType(trace.origin.span(), br));
                 debug!("Bound region {} maps to {}",
diff --git a/src/librustc/middle/typeck/infer/sub.rs b/src/librustc/middle/typeck/infer/sub.rs
index 158fda802ff..4c04bcc5236 100644
--- a/src/librustc/middle/typeck/infer/sub.rs
+++ b/src/librustc/middle/typeck/infer/sub.rs
@@ -12,7 +12,7 @@
 use middle::ty::{BuiltinBounds};
 use middle::ty;
 use middle::ty::TyVar;
-use middle::typeck::check::regionmanip::replace_late_bound_regions_in_fn_sig;
+use middle::typeck::check::regionmanip::replace_late_bound_regions;
 use middle::typeck::infer::combine::*;
 use middle::typeck::infer::{cres, CresCompare};
 use middle::typeck::infer::equate::Equate;
@@ -139,30 +139,21 @@ impl<'f, 'tcx> Combine<'tcx> for Sub<'f, 'tcx> {
                     .relate_vars(a_id, SubtypeOf, b_id);
                 Ok(a)
             }
-            // The vec/str check here and below is so that we don't unify
-            // T with [T], this is necessary so we reflect subtyping of references
-            // (&T does not unify with &[T]) where that in turn is to reflect
-            // the historical non-typedness of [T].
-            (&ty::ty_infer(TyVar(_)), &ty::ty_str) |
-            (&ty::ty_infer(TyVar(_)), &ty::ty_vec(_, None)) => {
-                Err(ty::terr_sorts(expected_found(self, a, b)))
-            }
             (&ty::ty_infer(TyVar(a_id)), _) => {
                 try!(self.fields
                        .switch_expected()
                        .instantiate(b, SupertypeOf, a_id));
                 Ok(a)
             }
-
-            (&ty::ty_str, &ty::ty_infer(TyVar(_))) |
-            (&ty::ty_vec(_, None), &ty::ty_infer(TyVar(_))) => {
-                Err(ty::terr_sorts(expected_found(self, a, b)))
-            }
             (_, &ty::ty_infer(TyVar(b_id))) => {
                 try!(self.fields.instantiate(a, SubtypeOf, b_id));
                 Ok(a)
             }
 
+            (&ty::ty_err, _) | (_, &ty::ty_err) => {
+                Ok(ty::mk_err())
+            }
+
             (_, &ty::ty_bot) => {
                 Err(ty::terr_sorts(expected_found(self, a, b)))
             }
@@ -198,7 +189,7 @@ impl<'f, 'tcx> Combine<'tcx> for Sub<'f, 'tcx> {
         // Second, we instantiate each bound region in the supertype with a
         // fresh concrete region.
         let (skol_map, b_sig) = {
-            replace_late_bound_regions_in_fn_sig(self.fields.infcx.tcx, b, |br| {
+            replace_late_bound_regions(self.fields.infcx.tcx, b.binder_id, b, |br| {
                 let skol = self.fields.infcx.region_vars.new_skolemized(br);
                 debug!("Bound region {} skolemized to {}",
                        bound_region_to_string(self.fields.infcx.tcx, "", false, br),
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)
     }
diff --git a/src/test/auxiliary/regions-bounded-method-type-parameters-cross-crate-lib.rs b/src/test/auxiliary/regions-bounded-method-type-parameters-cross-crate-lib.rs
index 1e9fd035f44..000e42b9703 100644
--- a/src/test/auxiliary/regions-bounded-method-type-parameters-cross-crate-lib.rs
+++ b/src/test/auxiliary/regions-bounded-method-type-parameters-cross-crate-lib.rs
@@ -9,7 +9,7 @@
 // except according to those terms.
 
 // Check that method bounds declared on traits/impls in a cross-crate
-// scenario work. This is the libary portion of the test.
+// scenario work. This is the library portion of the test.
 
 pub enum MaybeOwned<'a> {
     Owned(int),
@@ -24,10 +24,19 @@ pub struct Inv<'a> { // invariant w/r/t 'a
 // trait, so I'll use that as the template for this test.
 pub trait IntoMaybeOwned<'a> {
     fn into_maybe_owned(self) -> MaybeOwned<'a>;
+
+    // Note: without this `into_inv` method, the trait is
+    // contravariant w/r/t `'a`, since if you look strictly at the
+    // interface, it only returns `'a`. This complicates the
+    // downstream test since it wants invariance to force an error.
+    // Hence we add this method.
+    fn into_inv(self) -> Inv<'a>;
+
     fn bigger_region<'b:'a>(self, b: Inv<'b>);
 }
 
 impl<'a> IntoMaybeOwned<'a> for Inv<'a> {
     fn into_maybe_owned(self) -> MaybeOwned<'a> { fail!() }
+    fn into_inv(self) -> Inv<'a> { fail!() }
     fn bigger_region<'b:'a>(self, b: Inv<'b>) { fail!() }
 }
diff --git a/src/test/compile-fail/coherence-blanket-conflicts-with-blanket-implemented.rs b/src/test/compile-fail/coherence-blanket-conflicts-with-blanket-implemented.rs
new file mode 100644
index 00000000000..c0d82d35e30
--- /dev/null
+++ b/src/test/compile-fail/coherence-blanket-conflicts-with-blanket-implemented.rs
@@ -0,0 +1,38 @@
+// Copyright 2014 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.
+
+use std::fmt::Show;
+use std::default::Default;
+
+// Test that two blanket impls conflict (at least without negative
+// bounds).  After all, some other crate could implement Even or Odd
+// for the same type (though this crate doesn't).
+
+trait MyTrait {
+    fn get(&self) -> uint;
+}
+
+trait Even { }
+
+trait Odd { }
+
+impl Even for int { }
+
+impl Odd for uint { }
+
+impl<T:Even> MyTrait for T { //~ ERROR E0119
+    fn get(&self) -> uint { 0 }
+}
+
+impl<T:Odd> MyTrait for T {
+    fn get(&self) -> uint { 0 }
+}
+
+fn main() { }
diff --git a/src/test/compile-fail/coherence-blanket-conflicts-with-blanket-unimplemented.rs b/src/test/compile-fail/coherence-blanket-conflicts-with-blanket-unimplemented.rs
new file mode 100644
index 00000000000..c44844bcf0b
--- /dev/null
+++ b/src/test/compile-fail/coherence-blanket-conflicts-with-blanket-unimplemented.rs
@@ -0,0 +1,34 @@
+// Copyright 2014 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.
+
+use std::fmt::Show;
+use std::default::Default;
+
+// Test that two blanket impls conflict (at least without negative
+// bounds).  After all, some other crate could implement Even or Odd
+// for the same type (though this crate doesn't implement them at all).
+
+trait MyTrait {
+    fn get(&self) -> uint;
+}
+
+trait Even { }
+
+trait Odd { }
+
+impl<T:Even> MyTrait for T { //~ ERROR E0119
+    fn get(&self) -> uint { 0 }
+}
+
+impl<T:Odd> MyTrait for T {
+    fn get(&self) -> uint { 0 }
+}
+
+fn main() { }
diff --git a/src/test/compile-fail/issue-17033.rs b/src/test/compile-fail/issue-17033.rs
index 35adb29c949..7590546d40a 100644
--- a/src/test/compile-fail/issue-17033.rs
+++ b/src/test/compile-fail/issue-17033.rs
@@ -8,8 +8,10 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
+#![feature(overloaded_calls)]
+
 fn f<'r>(p: &'r mut fn(p: &mut ())) {
-    p(()) //~ ERROR expected function, found `&'r mut fn(&mut ())`
+    p(()) //~ ERROR mismatched types: expected `&mut ()`, found `()`
 }
 
 fn main() {}
diff --git a/src/test/compile-fail/issue-17636.rs b/src/test/compile-fail/issue-17636.rs
index 635a184a9d3..ad2ebff59bc 100644
--- a/src/test/compile-fail/issue-17636.rs
+++ b/src/test/compile-fail/issue-17636.rs
@@ -15,5 +15,5 @@ pub fn build_archive<'a, I: MyItem<&'a (|&uint|:'a)>>(files: I) {}
 
 fn main() {
     build_archive(&(|_| { }));
-//~^ ERROR unable to infer enough type information to locate the impl of the trait `MyItem<&|&uint|
+//~^ ERROR not implemented
 }
diff --git a/src/test/compile-fail/issue-2149.rs b/src/test/compile-fail/issue-2149.rs
index 81f57dd9640..19d210f1905 100644
--- a/src/test/compile-fail/issue-2149.rs
+++ b/src/test/compile-fail/issue-2149.rs
@@ -18,6 +18,7 @@ impl<A> vec_monad<A> for Vec<A> {
         let mut r = fail!();
         for elt in self.iter() { r = r + f(*elt); }
         //~^ ERROR the type of this value must be known
+        //~^^ ERROR not implemented
    }
 }
 fn main() {
diff --git a/src/test/compile-fail/issue-7575.rs b/src/test/compile-fail/issue-7575.rs
index 768177785cf..d5a1040d4b4 100644
--- a/src/test/compile-fail/issue-7575.rs
+++ b/src/test/compile-fail/issue-7575.rs
@@ -8,17 +8,24 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
+// Test the mechanism for warning about possible missing `self` declarations.
+
 trait CtxtFn {
     fn f8(self, uint) -> uint;
-    fn f9(uint) -> uint; //~ NOTE candidate #
+    fn f9(uint) -> uint; //~ NOTE candidate
 }
 
 trait OtherTrait {
-    fn f9(uint) -> uint; //~ NOTE candidate #
+    fn f9(uint) -> uint; //~ NOTE candidate
 }
 
-trait UnusedTrait { // This should never show up as a candidate
-    fn f9(uint) -> uint;
+// Note: this trait is not implemented, but we can't really tell
+// whether or not an impl would match anyhow without a self
+// declaration to match against, so we wind up printing it as a
+// candidate. This seems not unreasonable -- perhaps the user meant to
+// implement it, after all.
+trait UnusedTrait {
+    fn f9(uint) -> uint; //~ NOTE candidate
 }
 
 impl CtxtFn for uint {
@@ -40,13 +47,13 @@ impl OtherTrait for uint {
 struct MyInt(int);
 
 impl MyInt {
-    fn fff(i: int) -> int { //~ NOTE candidate #1 is `MyInt::fff`
+    fn fff(i: int) -> int { //~ NOTE candidate
         i
     }
 }
 
 trait ManyImplTrait {
-    fn is_str() -> bool { //~ NOTE candidate #1 is
+    fn is_str() -> bool { //~ NOTE candidate
         false
     }
 }
diff --git a/src/test/compile-fail/method-ambig-one-trait-coerce.rs b/src/test/compile-fail/method-ambig-one-trait-coerce.rs
new file mode 100644
index 00000000000..e5c3da10df8
--- /dev/null
+++ b/src/test/compile-fail/method-ambig-one-trait-coerce.rs
@@ -0,0 +1,44 @@
+// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// Test that when we pick a trait based on coercion, versus subtyping,
+// we consider all possible coercions equivalent and don't try to pick
+// a best one.
+
+trait Object { }
+
+trait foo {
+    fn foo(self) -> int;
+}
+
+impl foo for Box<Object+'static> {
+    fn foo(self) -> int {1}
+}
+
+impl foo for Box<Object+Send> {
+    fn foo(self) -> int {2}
+}
+
+fn test1(x: Box<Object+Send+Sync>) {
+    // Ambiguous because we could coerce to either impl:
+    x.foo(); //~ ERROR E0034
+}
+
+fn test2(x: Box<Object+Send>) {
+    // Not ambiguous because it is a precise match:
+    x.foo();
+}
+
+fn test3(x: Box<Object+'static>) {
+    // Not ambiguous because it is a precise match:
+    x.foo();
+}
+
+fn main() { }
diff --git a/src/test/compile-fail/method-ambig-one-trait-unknown-int-type.rs b/src/test/compile-fail/method-ambig-one-trait-unknown-int-type.rs
new file mode 100644
index 00000000000..e211db2dcd2
--- /dev/null
+++ b/src/test/compile-fail/method-ambig-one-trait-unknown-int-type.rs
@@ -0,0 +1,45 @@
+// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// Test that we invoking `foo()` successfully resolves to the trait `foo`
+// (prompting the mismatched types error) but does not influence the choice
+// of what kind of `Vec` we have, eventually leading to a type error.
+
+trait foo {
+    fn foo(&self) -> int;
+}
+
+impl foo for Vec<uint> {
+    fn foo(&self) -> int {1}
+}
+
+impl foo for Vec<int> {
+    fn foo(&self) -> int {2}
+}
+
+// This is very hokey: we have heuristics to suppress messages about
+// type annotations required. But placing these two bits of code into
+// distinct functions, in this order, causes us to print out both
+// errors I'd like to see.
+
+fn m1() {
+    // we couldn't infer the type of the vector just based on calling foo()...
+    let mut x = Vec::new(); //~ ERROR type annotations required
+    x.foo();
+}
+
+fn m2() {
+    let mut x = Vec::new();
+
+    // ...but we still resolved `foo()` to the trait and hence know the return type.
+    let y: uint = x.foo(); //~ ERROR mismatched types
+}
+
+fn main() { }
diff --git a/src/test/compile-fail/ambig_impl_2_exe.rs b/src/test/compile-fail/method-ambig-two-traits-cross-crate.rs
index 13cceaa71ae..30e635149c4 100644
--- a/src/test/compile-fail/ambig_impl_2_exe.rs
+++ b/src/test/compile-fail/method-ambig-two-traits-cross-crate.rs
@@ -8,12 +8,15 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
+// Test an ambiguity scenario where one copy of the method is available
+// from a trait imported from another crate.
+
 // aux-build:ambig_impl_2_lib.rs
 extern crate ambig_impl_2_lib;
 use ambig_impl_2_lib::me;
 trait me2 {
     fn me(&self) -> uint;
 }
-impl me2 for uint { fn me(&self) -> uint { *self } } //~ NOTE is `uint.me2::me`
-fn main() { 1u.me(); } //~ ERROR multiple applicable methods in scope
-//~^ NOTE is `ambig_impl_2_lib::uint.me::me`
+impl me2 for uint { fn me(&self) -> uint { *self } }
+fn main() { 1u.me(); } //~ ERROR E0034
+
diff --git a/src/test/compile-fail/ambig_impl_bounds.rs b/src/test/compile-fail/method-ambig-two-traits-from-bounds.rs
index 9f26e5ae9b3..184927c0135 100644
--- a/src/test/compile-fail/ambig_impl_bounds.rs
+++ b/src/test/compile-fail/method-ambig-two-traits-from-bounds.rs
@@ -12,9 +12,7 @@ trait A { fn foo(&self); }
 trait B { fn foo(&self); }
 
 fn foo<T:A + B>(t: T) {
-    t.foo(); //~ ERROR multiple applicable methods in scope
-    //~^ NOTE candidate #1 derives from the bound `A`
-    //~^^ NOTE candidate #2 derives from the bound `B`
+    t.foo(); //~ ERROR E0034
 }
 
 fn main() {}
diff --git a/src/test/compile-fail/ambig-default-method.rs b/src/test/compile-fail/method-ambig-two-traits-with-default-method.rs
index 56ab6d7da3f..87efaed4e3d 100644
--- a/src/test/compile-fail/ambig-default-method.rs
+++ b/src/test/compile-fail/method-ambig-two-traits-with-default-method.rs
@@ -8,12 +8,16 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-trait Foo { fn method(&self) {} } //~ NOTE `Foo::method`
-trait Bar { fn method(&self) {} } //~ NOTE `Bar::method`
+// Test that we correctly report an ambiguity where two applicable traits
+// are in scope and the method being invoked is a default method not
+// defined directly in the impl.
+
+trait Foo { fn method(&self) {} }
+trait Bar { fn method(&self) {} }
 
 impl Foo for uint {}
 impl Bar for uint {}
 
 fn main() {
-    1u.method(); //~ ERROR multiple applicable methods in scope
+    1u.method(); //~ ERROR E0034
 }
diff --git a/src/test/compile-fail/method-commit-to-trait.rs b/src/test/compile-fail/method-commit-to-trait.rs
new file mode 100644
index 00000000000..6e4b5e088c9
--- /dev/null
+++ b/src/test/compile-fail/method-commit-to-trait.rs
@@ -0,0 +1,33 @@
+// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// Test that we pick `Foo`, and also pick the `impl`, even though in
+// this case the vector type `T` is not copyable. This is because
+// there is no other reasonable choice. The error you see is thus
+// about `T` being non-copyable, not about `Foo` being
+// unimplemented. This is better for user too, since it suggests minimal
+// diff requird to fix program.
+
+trait Object { }
+
+trait Foo {
+    fn foo(self) -> int;
+}
+
+impl<T:Copy> Foo for Vec<T> {
+    fn foo(self) -> int {1}
+}
+
+fn test1<T>(x: Vec<T>) {
+    x.foo();
+    //~^ ERROR `core::kinds::Copy` is not implemented for the type `T`
+}
+
+fn main() { }
diff --git a/src/test/compile-fail/regions-bounded-method-type-parameters-cross-crate.rs b/src/test/compile-fail/regions-bounded-method-type-parameters-cross-crate.rs
index 06f26800b50..1705cfec6e2 100644
--- a/src/test/compile-fail/regions-bounded-method-type-parameters-cross-crate.rs
+++ b/src/test/compile-fail/regions-bounded-method-type-parameters-cross-crate.rs
@@ -18,15 +18,15 @@ use lib::Inv;
 use lib::MaybeOwned;
 use lib::IntoMaybeOwned;
 
-fn call_into_maybe_owned<'a,F:IntoMaybeOwned<'a>>(f: F) {
+fn call_into_maybe_owned<'x,F:IntoMaybeOwned<'x>>(f: F) {
     // Exercise a code path I found to be buggy. We were not encoding
     // the region parameters from the receiver correctly on trait
     // methods.
     f.into_maybe_owned();
 }
 
-fn call_bigger_region<'a, 'b>(a: Inv<'a>, b: Inv<'b>) {
-    // Here the value provided for 'y is 'b, and hence 'b:'a does not hold.
+fn call_bigger_region<'x, 'y>(a: Inv<'x>, b: Inv<'y>) {
+    // Here the value provided for 'y is 'y, and hence 'y:'x does not hold.
     a.bigger_region(b) //~ ERROR cannot infer
 }
 
diff --git a/src/test/compile-fail/selftype-traittype.rs b/src/test/compile-fail/selftype-traittype.rs
index bf7c3b261fd..44ee5002dce 100644
--- a/src/test/compile-fail/selftype-traittype.rs
+++ b/src/test/compile-fail/selftype-traittype.rs
@@ -14,7 +14,7 @@ trait add {
 }
 
 fn do_add(x: Box<add+'static>, y: Box<add+'static>) -> Box<add+'static> {
-    x.plus(y) //~ ERROR cannot call a method whose type contains a self-type through an object
+    x.plus(y) //~ ERROR E0038
 }
 
 fn main() {}
diff --git a/src/test/compile-fail/unique-pinned-nocopy.rs b/src/test/compile-fail/unique-pinned-nocopy.rs
index c812b0d96a2..0e1e66b40ce 100644
--- a/src/test/compile-fail/unique-pinned-nocopy.rs
+++ b/src/test/compile-fail/unique-pinned-nocopy.rs
@@ -19,6 +19,6 @@ impl Drop for r {
 
 fn main() {
     let i = box r { b: true };
-    let _j = i.clone(); //~ ERROR not implemented
+    let _j = i.clone(); //~ ERROR not implement
     println!("{}", i);
 }
diff --git a/src/test/compile-fail/unique-vec-res.rs b/src/test/compile-fail/unique-vec-res.rs
index 79f29c6b359..62fabc0b33f 100644
--- a/src/test/compile-fail/unique-vec-res.rs
+++ b/src/test/compile-fail/unique-vec-res.rs
@@ -35,8 +35,8 @@ fn main() {
     let r1 = vec!(box r { i: i1 });
     let r2 = vec!(box r { i: i2 });
     f(r1.clone(), r2.clone());
-    //~^ ERROR the trait `core::clone::Clone` is not implemented
-    //~^^ ERROR the trait `core::clone::Clone` is not implemented
+    //~^ ERROR does not implement any method in scope named `clone`
+    //~^^ ERROR does not implement any method in scope named `clone`
     println!("{}", (r2, i1.get()));
     println!("{}", (r1, i2.get()));
 }
diff --git a/src/test/compile-fail/vec-res-add.rs b/src/test/compile-fail/vec-res-add.rs
index bfd52d69cb2..6221806642c 100644
--- a/src/test/compile-fail/vec-res-add.rs
+++ b/src/test/compile-fail/vec-res-add.rs
@@ -8,6 +8,7 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
+#[deriving(Show)]
 struct r {
   i:int
 }
@@ -23,7 +24,6 @@ fn main() {
     let i = vec!(r(0));
     let j = vec!(r(1));
     let k = i + j;
-    //~^ ERROR not implemented
+    //~^ ERROR binary operation `+` cannot be applied to type
     println!("{}", j);
-    //~^ ERROR not implemented
 }
diff --git a/src/test/compile-fail/wrong-mul-method-signature.rs b/src/test/compile-fail/wrong-mul-method-signature.rs
index e3aed148a23..aead739d3e0 100644
--- a/src/test/compile-fail/wrong-mul-method-signature.rs
+++ b/src/test/compile-fail/wrong-mul-method-signature.rs
@@ -58,7 +58,13 @@ impl Mul<f64, i32> for Vec3 {
 }
 
 pub fn main() {
-    Vec1 { x: 1.0 } * 2.0;
-    Vec2 { x: 1.0, y: 2.0 } * 2.0;
-    Vec3 { x: 1.0, y: 2.0, z: 3.0 } * 2.0;
+    // Check that the usage goes from the trait declaration:
+
+    let x: Vec1 = Vec1 { x: 1.0 } * 2.0; // this is OK
+
+    let x: Vec2 = Vec2 { x: 1.0, y: 2.0 } * 2.0; // trait had reversed order
+    //~^ ERROR mismatched types
+    //~^^ ERROR mismatched types
+
+    let x: i32 = Vec3 { x: 1.0, y: 2.0, z: 3.0 } * 2.0;
 }
diff --git a/src/test/compile-fail/ambig_impl_unify.rs b/src/test/run-pass/method-two-trait-defer-resolution-1.rs
index 67b7a5a7f37..e4ae33c1c50 100644
--- a/src/test/compile-fail/ambig_impl_unify.rs
+++ b/src/test/run-pass/method-two-trait-defer-resolution-1.rs
@@ -8,20 +8,36 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
+// Test that we pick which version of `foo` to run based on the
+// type that is (ultimately) inferred for `x`.
 
 trait foo {
     fn foo(&self) -> int;
 }
 
 impl foo for Vec<uint> {
-    fn foo(&self) -> int {1} //~ NOTE candidate #1 is `Vec<uint>.foo::foo`
+    fn foo(&self) -> int {1}
 }
 
 impl foo for Vec<int> {
-    fn foo(&self) -> int {2} //~ NOTE candidate #2 is `Vec<int>.foo::foo`
+    fn foo(&self) -> int {2}
+}
+
+fn call_foo_uint() -> int {
+    let mut x = Vec::new();
+    let y = x.foo();
+    x.push(0u);
+    y
+}
+
+fn call_foo_int() -> int {
+    let mut x = Vec::new();
+    let y = x.foo();
+    x.push(0i);
+    y
 }
 
 fn main() {
-    let x = Vec::new();
-    x.foo(); //~ ERROR multiple applicable methods in scope
+    assert_eq!(call_foo_uint(), 1);
+    assert_eq!(call_foo_int(), 2);
 }
diff --git a/src/test/run-pass/method-two-trait-defer-resolution-2.rs b/src/test/run-pass/method-two-trait-defer-resolution-2.rs
new file mode 100644
index 00000000000..cae783e7ea8
--- /dev/null
+++ b/src/test/run-pass/method-two-trait-defer-resolution-2.rs
@@ -0,0 +1,48 @@
+// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// Test that we pick which version of `Foo` to run based on whether
+// the type we (ultimately) inferred for `x` is copyable or not.
+//
+// In this case, the two versions are both impls of same trait, and
+// hence we we can resolve method even without knowing yet which
+// version will run (note that the `push` occurs after the call to
+// `foo()`).
+
+trait Foo {
+    fn foo(&self) -> int;
+}
+
+impl<T:Copy> Foo for Vec<T> {
+    fn foo(&self) -> int {1}
+}
+
+impl<T> Foo for Vec<Box<T>> {
+    fn foo(&self) -> int {2}
+}
+
+fn call_foo_copy() -> int {
+    let mut x = Vec::new();
+    let y = x.foo();
+    x.push(0u);
+    y
+}
+
+fn call_foo_other() -> int {
+    let mut x = Vec::new();
+    let y = x.foo();
+    x.push(box 0i);
+    y
+}
+
+fn main() {
+    assert_eq!(call_foo_copy(), 1);
+    assert_eq!(call_foo_other(), 2);
+}