diff --git a/src/libcore/ops.rs b/src/libcore/ops.rs
index 8d072fffb60a4..ac735492be4a5 100644
--- a/src/libcore/ops.rs
+++ b/src/libcore/ops.rs
@@ -866,13 +866,45 @@ pub trait FnOnce<Args,Result> {
     extern "rust-call" fn call_once(self, args: Args) -> Result;
 }
 
-macro_rules! def_fn_mut(
+impl<F,A,R> FnMut<A,R> for F
+    where F : Fn<A,R>
+{
+    extern "rust-call" fn call_mut(&mut self, args: A) -> R {
+        self.call(args)
+    }
+}
+
+impl<F,A,R> FnOnce<A,R> for F
+    where F : FnMut<A,R>
+{
+    extern "rust-call" fn call_once(mut self, args: A) -> R {
+        self.call_mut(args)
+    }
+}
+
+
+impl<Result> Fn<(),Result> for extern "Rust" fn() -> Result {
+    #[allow(non_snake_case)]
+    extern "rust-call" fn call(&self, _args: ()) -> Result {
+        (*self)()
+    }
+}
+
+impl<Result,A0> Fn<(A0,),Result> for extern "Rust" fn(A0) -> Result {
+    #[allow(non_snake_case)]
+    extern "rust-call" fn call(&self, args: (A0,)) -> Result {
+        let (a0,) = args;
+        (*self)(a0)
+    }
+}
+
+macro_rules! def_fn(
     ($($args:ident)*) => (
         impl<Result$(,$args)*>
-        FnMut<($($args,)*),Result>
+        Fn<($($args,)*),Result>
         for extern "Rust" fn($($args: $args,)*) -> Result {
             #[allow(non_snake_case)]
-            extern "rust-call" fn call_mut(&mut self, args: ($($args,)*)) -> Result {
+            extern "rust-call" fn call(&self, args: ($($args,)*)) -> Result {
                 let ($($args,)*) = args;
                 (*self)($($args,)*)
             }
@@ -880,20 +912,18 @@ macro_rules! def_fn_mut(
     )
 )
 
-def_fn_mut!()
-def_fn_mut!(A0)
-def_fn_mut!(A0 A1)
-def_fn_mut!(A0 A1 A2)
-def_fn_mut!(A0 A1 A2 A3)
-def_fn_mut!(A0 A1 A2 A3 A4)
-def_fn_mut!(A0 A1 A2 A3 A4 A5)
-def_fn_mut!(A0 A1 A2 A3 A4 A5 A6)
-def_fn_mut!(A0 A1 A2 A3 A4 A5 A6 A7)
-def_fn_mut!(A0 A1 A2 A3 A4 A5 A6 A7 A8)
-def_fn_mut!(A0 A1 A2 A3 A4 A5 A6 A7 A8 A9)
-def_fn_mut!(A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 A10)
-def_fn_mut!(A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 A10 A11)
-def_fn_mut!(A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 A10 A11 A12)
-def_fn_mut!(A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 A10 A11 A12 A13)
-def_fn_mut!(A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 A10 A11 A12 A13 A14)
-def_fn_mut!(A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 A10 A11 A12 A13 A14 A15)
+def_fn!(A0 A1)
+def_fn!(A0 A1 A2)
+def_fn!(A0 A1 A2 A3)
+def_fn!(A0 A1 A2 A3 A4)
+def_fn!(A0 A1 A2 A3 A4 A5)
+def_fn!(A0 A1 A2 A3 A4 A5 A6)
+def_fn!(A0 A1 A2 A3 A4 A5 A6 A7)
+def_fn!(A0 A1 A2 A3 A4 A5 A6 A7 A8)
+def_fn!(A0 A1 A2 A3 A4 A5 A6 A7 A8 A9)
+def_fn!(A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 A10)
+def_fn!(A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 A10 A11)
+def_fn!(A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 A10 A11 A12)
+def_fn!(A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 A10 A11 A12 A13)
+def_fn!(A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 A10 A11 A12 A13 A14)
+def_fn!(A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 A10 A11 A12 A13 A14 A15)
diff --git a/src/librustc/middle/traits/coherence.rs b/src/librustc/middle/traits/coherence.rs
index 8b2ddca313197..09490f9bdf7e9 100644
--- a/src/librustc/middle/traits/coherence.rs
+++ b/src/librustc/middle/traits/coherence.rs
@@ -43,7 +43,7 @@ pub fn impl_can_satisfy(infcx: &InferCtxt,
     // Determine whether `impl2` can provide an implementation for those
     // same types.
     let param_env = ty::empty_parameter_environment();
-    let mut selcx = SelectionContext::new(infcx, &param_env, infcx.tcx);
+    let mut selcx = SelectionContext::intercrate(infcx, &param_env, infcx.tcx);
     let obligation = Obligation::misc(DUMMY_SP, impl1_trait_ref);
     debug!("impl_can_satisfy obligation={}", obligation.repr(infcx.tcx));
     selcx.evaluate_impl(impl2_def_id, &obligation)
diff --git a/src/librustc/middle/traits/select.rs b/src/librustc/middle/traits/select.rs
index 9a2d5b4d4dc0a..09bd0f52985b1 100644
--- a/src/librustc/middle/traits/select.rs
+++ b/src/librustc/middle/traits/select.rs
@@ -45,6 +45,22 @@ pub struct SelectionContext<'cx, 'tcx:'cx> {
     /// which is important for checking for trait bounds that
     /// recursively require themselves.
     skolemizer: TypeSkolemizer<'cx, 'tcx>,
+
+    /// If true, indicates that the evaluation should be conservative
+    /// and consider the possibility of types outside this crate.
+    /// This comes up primarily when resolving ambiguity. Imagine
+    /// there is some trait reference `$0 : Bar` where `$0` is an
+    /// inference variable. If `intercrate` is true, then we can never
+    /// say for sure that this reference is not implemented, even if
+    /// there are *no impls at all for `Bar`*, because `$0` could be
+    /// bound to some type that in a downstream crate that implements
+    /// `Bar`. This is the suitable mode for coherence. Elsewhere,
+    /// though, we set this to false, because we are only interested
+    /// in types that the user could actually have written --- in
+    /// other words, we consider `$0 : Bar` to be unimplemented if
+    /// there is no type that the user could *actually name* that
+    /// would satisfy it. This avoids crippling inference, basically.
+    intercrate: bool,
 }
 
 // A stack that walks back up the stack frame.
@@ -142,6 +158,20 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
             param_env: param_env,
             typer: typer,
             skolemizer: infcx.skolemizer(),
+            intercrate: false,
+        }
+    }
+
+    pub fn intercrate(infcx: &'cx InferCtxt<'cx, 'tcx>,
+                      param_env: &'cx ty::ParameterEnvironment,
+                      typer: &'cx Typer<'tcx>)
+                      -> SelectionContext<'cx, 'tcx> {
+        SelectionContext {
+            infcx: infcx,
+            param_env: param_env,
+            typer: typer,
+            skolemizer: infcx.skolemizer(),
+            intercrate: true,
         }
     }
 
@@ -214,44 +244,20 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
     // The result is "true" if the obligation *may* hold and "false" if
     // we can be sure it does not.
 
-    pub fn evaluate_obligation_intercrate(&mut self,
-                                          obligation: &Obligation)
-                                          -> bool
+    pub fn evaluate_obligation(&mut self,
+                               obligation: &Obligation)
+                               -> bool
     {
         /*!
          * Evaluates whether the obligation `obligation` can be
-         * 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.
+         * satisfied (by any means).
          */
 
-        debug!("evaluate_obligation_intercrate({})",
+        debug!("evaluate_obligation({})",
                obligation.repr(self.tcx()));
 
         let stack = self.push_stack(None, obligation);
-        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()
+        self.evaluate_stack(&stack).may_apply()
     }
 
     fn evaluate_builtin_bound_recursively(&mut self,
@@ -288,46 +294,53 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
 
         let stack = self.push_stack(previous_stack.map(|x| x), obligation);
 
-        // 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);
+        let result = self.evaluate_stack(&stack);
 
         debug!("result: {}", result);
         result
     }
 
-    fn evaluate_stack_intercrate(&mut self,
+    fn evaluate_stack(&mut self,
                       stack: &ObligationStack)
                       -> EvaluationResult
     {
-        // Whenever any of the types are unbound, there can always be
-        // 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.
+        // In intercrate mode, whenever any of the types are unbound,
+        // there can always be 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.
+        //
+        // In intracrate mode, we must still be conservative. The reason is
+        // that we want to avoid cycles. Imagine an impl like:
+        //
+        //     impl<T:Eq> Eq for Vec<T>
+        //
+        // and a trait reference like `$0 : Eq` where `$0` is an
+        // unbound variable. When we evaluate this trait-reference, we
+        // will unify `$0` with `Vec<$1>` (for some fresh variable
+        // `$1`), on the condition that `$1 : Eq`. We will then wind
+        // up with many candidates (since that are other `Eq` impls
+        // that apply) and try to winnow things down. This results in
+        // a recurssive evaluation that `$1 : Eq` -- as you can
+        // imagine, this is just where we started. To avoid that, we
+        // check for unbound variables and return an ambiguous (hence possible)
+        // match if we've seen this trait before.
+        //
+        // This suffices to allow chains like `FnMut` implemented in
+        // terms of `Fn` etc, but we could probably make this more
+        // precise still.
         let input_types = stack.skol_trait_ref.input_types();
-        if input_types.iter().any(|&t| ty::type_is_skolemized(t)) {
-            debug!("evaluate_stack_intercrate({}) --> unbound argument, must be ambiguous",
+        let unbound_input_types = input_types.iter().any(|&t| ty::type_is_skolemized(t));
+        if
+            unbound_input_types &&
+             (self.intercrate ||
+              stack.iter().skip(1).any(
+                  |prev| stack.skol_trait_ref.def_id == prev.skol_trait_ref.def_id))
+        {
+            debug!("evaluate_stack_intracrate({}) --> unbound argument, recursion -->  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
@@ -592,7 +605,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
                 Err(_) => { return Err(()); }
             }
 
-            if self.evaluate_obligation_intracrate(obligation) {
+            if self.evaluate_obligation(obligation) {
                 Ok(())
             } else {
                 Err(())
@@ -804,12 +817,12 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
                                                                           &candidates[i],
                                                                           &candidates[j]));
                 if is_dup {
-                    debug!("Dropping candidate #{}/#{}: {}",
+                    debug!("Dropping candidate #{}/{}: {}",
                            i, candidates.len(), candidates[i].repr(self.tcx()));
                     candidates.swap_remove(i);
                 } else {
-                    debug!("Retaining candidate #{}/#{}",
-                           i, candidates.len());
+                    debug!("Retaining candidate #{}/{}: {}",
+                           i, candidates.len(), candidates[i].repr(self.tcx()));
                     i += 1;
                 }
             }
@@ -828,7 +841,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
         // 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
+        // is checked for in `evaluate_stack` (and hence users
         // who might care about this case, like coherence, should use
         // that function).
         if candidates.len() == 0 {
@@ -849,6 +862,17 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
         // global cache. We want the cache that is specific to this
         // scope whenever where clauses might affect the result.
 
+        // Avoid using the master cache during coherence and just rely
+        // on the local cache. This effectively disables caching
+        // during coherence. It is really just a simplification to
+        // avoid us having to fear that coherence results "pollute"
+        // the master cache. Since coherence executes pretty quickly,
+        // it's not worth going to more trouble to increase the
+        // hit-rate I don't think.
+        if self.intercrate {
+            return &self.param_env.selection_cache;
+        }
+
         // If the trait refers to any parameters in scope, then use
         // the cache of the param-environment.
         if
diff --git a/src/librustc/middle/typeck/check/method.rs b/src/librustc/middle/typeck/check/method.rs
index abffa857a089a..f854bc52acd7b 100644
--- a/src/librustc/middle/typeck/check/method.rs
+++ b/src/librustc/middle/typeck/check/method.rs
@@ -235,7 +235,7 @@ pub fn lookup_in_trait_adjusted<'a, 'tcx>(
     let mut selcx = traits::SelectionContext::new(fcx.infcx(),
                                                   &fcx.inh.param_env,
                                                   fcx);
-    if !selcx.evaluate_obligation_intracrate(&obligation) {
+    if !selcx.evaluate_obligation(&obligation) {
         debug!("--> Cannot match obligation");
         return None; // Cannot be matched, no such method resolution is possible.
     }
diff --git a/src/librustc/middle/typeck/check/mod.rs b/src/librustc/middle/typeck/check/mod.rs
index 0e3a77ba9639c..bcb875a6aa830 100644
--- a/src/librustc/middle/typeck/check/mod.rs
+++ b/src/librustc/middle/typeck/check/mod.rs
@@ -2147,11 +2147,11 @@ fn try_overloaded_call<'a>(fcx: &FnCtxt,
         _ => {}
     }
 
-    // Try `FnOnce`, then `FnMut`, then `Fn`.
+    // Try the options that are least restrictive on the caller first.
     for &(maybe_function_trait, method_name) in [
-        (fcx.tcx().lang_items.fn_once_trait(), token::intern("call_once")),
+        (fcx.tcx().lang_items.fn_trait(), token::intern("call")),
         (fcx.tcx().lang_items.fn_mut_trait(), token::intern("call_mut")),
-        (fcx.tcx().lang_items.fn_trait(), token::intern("call"))
+        (fcx.tcx().lang_items.fn_once_trait(), token::intern("call_once")),
     ].iter() {
         let function_trait = match maybe_function_trait {
             None => continue,
@@ -3493,6 +3493,11 @@ fn check_expr_with_unifier(fcx: &FnCtxt,
             ast::FnOnceUnboxedClosureKind => ty::FnOnceUnboxedClosureKind,
         };
 
+        debug!("unboxed_closure for {} --> sig={} kind={}",
+               local_def(expr.id).repr(fcx.tcx()),
+               fn_ty.sig.repr(fcx.tcx()),
+               kind);
+
         let unboxed_closure = ty::UnboxedClosure {
             closure_type: fn_ty,
             kind: kind,
diff --git a/src/test/compile-fail/unboxed-closures-fnmut-as-fn.rs b/src/test/compile-fail/unboxed-closures-fnmut-as-fn.rs
new file mode 100644
index 0000000000000..20d7262432f0c
--- /dev/null
+++ b/src/test/compile-fail/unboxed-closures-fnmut-as-fn.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.
+
+// Checks that the Fn trait hierarchy rules do not permit
+// Fn to be used where FnMut is implemented.
+
+#![feature(unboxed_closure_sugar)]
+#![feature(overloaded_calls)]
+
+use std::ops::{Fn,FnMut,FnOnce};
+
+struct S;
+
+impl FnMut<(int,),int> for S {
+    extern "rust-call" fn call_mut(&mut self, (x,): (int,)) -> int {
+        x * x
+    }
+}
+
+fn call_it<F:Fn(int)->int>(f: &F, x: int) -> int {
+    f.call((x,))
+}
+
+fn main() {
+    let x = call_it(&S, 22); //~ ERROR not implemented
+}
+
diff --git a/src/test/compile-fail/unboxed-closures-static-call-wrong-trait.rs b/src/test/compile-fail/unboxed-closures-static-call-wrong-trait.rs
index 871889f26dfd2..4fa72b383067d 100644
--- a/src/test/compile-fail/unboxed-closures-static-call-wrong-trait.rs
+++ b/src/test/compile-fail/unboxed-closures-static-call-wrong-trait.rs
@@ -12,6 +12,6 @@
 
 fn main() {
     let mut_ = |&mut: x| x;
-    mut_.call_once((0i, )); //~ ERROR type `closure` does not implement
+    mut_.call((0i, )); //~ ERROR type `closure` does not implement
 }
 
diff --git a/src/test/compile-fail/unboxed-closures-vtable-mismatch.rs b/src/test/compile-fail/unboxed-closures-vtable-mismatch.rs
index a96bde7cca4cd..5a22490b6d616 100644
--- a/src/test/compile-fail/unboxed-closures-vtable-mismatch.rs
+++ b/src/test/compile-fail/unboxed-closures-vtable-mismatch.rs
@@ -18,7 +18,7 @@ fn call_it<F:FnMut<(int,int),int>>(y: int, mut f: F) -> int {
 
 pub fn main() {
     let f = |&mut: x: uint, y: int| -> int { (x as int) + y };
-    let z = call_it(3, f);  //~ ERROR type mismatch
+    let z = call_it(3, f);  //~ ERROR not implemented
     println!("{}", z);
 }
 
diff --git a/src/test/compile-fail/unboxed-closures-wrong-trait.rs b/src/test/compile-fail/unboxed-closures-wrong-trait.rs
index 97ad64a77baf4..e15fe8ad049b0 100644
--- a/src/test/compile-fail/unboxed-closures-wrong-trait.rs
+++ b/src/test/compile-fail/unboxed-closures-wrong-trait.rs
@@ -10,13 +10,13 @@
 
 #![feature(lang_items, overloaded_calls, unboxed_closures)]
 
-fn c<F:FnOnce(int, int) -> int>(f: F) -> int {
+fn c<F:Fn(int, int) -> int>(f: F) -> int {
     f(5, 6)
 }
 
 fn main() {
     let z: int = 7;
-    assert_eq!(c(|&: x: int, y| x + y + z), 10);
+    assert_eq!(c(|&mut: x: int, y| x + y + z), 10);
     //~^ ERROR not implemented
 }
 
diff --git a/src/test/run-pass/issue-16668.rs b/src/test/run-pass/issue-16668.rs
index 92f8030a0dc56..f36594cb40145 100644
--- a/src/test/run-pass/issue-16668.rs
+++ b/src/test/run-pass/issue-16668.rs
@@ -20,8 +20,8 @@ impl<'a, I, O: 'a> Parser<'a, I, O> {
     fn compose<K: 'a>(mut self, mut rhs: Parser<'a, O, K>) -> Parser<'a, I, K> {
         Parser {
             parse: box move |&mut: x: I| {
-                match self.parse.call_mut((x,)) {
-                    Ok(r) => rhs.parse.call_mut((r,)),
+                match (*self.parse).call_mut((x,)) {
+                    Ok(r) => (*rhs.parse).call_mut((r,)),
                     Err(e) => Err(e)
                 }
             }
diff --git a/src/test/run-pass/unboxed-closures-extern-fn.rs b/src/test/run-pass/unboxed-closures-extern-fn.rs
new file mode 100644
index 0000000000000..82d51ba1f1645
--- /dev/null
+++ b/src/test/run-pass/unboxed-closures-extern-fn.rs
@@ -0,0 +1,40 @@
+// 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.
+
+// Checks that extern fn points implement the full range of Fn traits.
+
+#![feature(unboxed_closure_sugar)]
+#![feature(overloaded_calls)]
+
+use std::ops::{Fn,FnMut,FnOnce};
+
+fn square(x: int) -> int { x * x }
+
+fn call_it<F:Fn(int)->int>(f: &F, x: int) -> int {
+    f.call((x,))
+}
+
+fn call_it_mut<F:FnMut(int)->int>(f: &mut F, x: int) -> int {
+    f.call_mut((x,))
+}
+
+fn call_it_once<F:FnOnce(int)->int>(f: F, x: int) -> int {
+    f.call_once((x,))
+}
+
+fn main() {
+    let x = call_it(&square, 22);
+    let y = call_it_mut(&mut square, 22);
+    let z = call_it_once(square, 22);
+    assert_eq!(x, square(22));
+    assert_eq!(y, square(22));
+    assert_eq!(z, square(22));
+}
+
diff --git a/src/test/run-pass/unboxed-closures-fn-as-fnmut-and-fnonce.rs b/src/test/run-pass/unboxed-closures-fn-as-fnmut-and-fnonce.rs
new file mode 100644
index 0000000000000..90272636bc59d
--- /dev/null
+++ b/src/test/run-pass/unboxed-closures-fn-as-fnmut-and-fnonce.rs
@@ -0,0 +1,46 @@
+// 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.
+
+// Checks that the Fn trait hierarchy rules permit
+// any Fn trait to be used where Fn is implemented.
+
+#![feature(unboxed_closure_sugar)]
+#![feature(overloaded_calls)]
+
+use std::ops::{Fn,FnMut,FnOnce};
+
+struct S;
+
+impl Fn<(int,),int> for S {
+    extern "rust-call" fn call(&self, (x,): (int,)) -> int {
+        x * x
+    }
+}
+
+fn call_it<F:Fn(int)->int>(f: &F, x: int) -> int {
+    f.call((x,))
+}
+
+fn call_it_mut<F:FnMut(int)->int>(f: &mut F, x: int) -> int {
+    f.call_mut((x,))
+}
+
+fn call_it_once<F:FnOnce(int)->int>(f: F, x: int) -> int {
+    f.call_once((x,))
+}
+
+fn main() {
+    let x = call_it(&S, 22);
+    let y = call_it_mut(&mut S, 22);
+    let z = call_it_once(S, 22);
+    assert_eq!(x, y);
+    assert_eq!(y, z);
+}
+
diff --git a/src/test/run-pass/unboxed-closures-fnmut-as-fnonce.rs b/src/test/run-pass/unboxed-closures-fnmut-as-fnonce.rs
new file mode 100644
index 0000000000000..bd01910a210ab
--- /dev/null
+++ b/src/test/run-pass/unboxed-closures-fnmut-as-fnonce.rs
@@ -0,0 +1,40 @@
+// 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.
+
+// Checks that the Fn trait hierarchy rules permit
+// FnMut or FnOnce to be used where FnMut is implemented.
+
+#![feature(unboxed_closure_sugar)]
+#![feature(overloaded_calls)]
+
+use std::ops::{FnMut,FnOnce};
+
+struct S;
+
+impl FnMut<(int,),int> for S {
+    extern "rust-call" fn call_mut(&mut self, (x,): (int,)) -> int {
+        x * x
+    }
+}
+
+fn call_it_mut<F:FnMut(int)->int>(f: &mut F, x: int) -> int {
+    f.call_mut((x,))
+}
+
+fn call_it_once<F:FnOnce(int)->int>(f: F, x: int) -> int {
+    f.call_once((x,))
+}
+
+fn main() {
+    let y = call_it_mut(&mut S, 22);
+    let z = call_it_once(S, 22);
+    assert_eq!(y, z);
+}
+
diff --git a/src/test/run-pass/fn-trait-sugar.rs b/src/test/run-pass/unboxed-closures-manual-impl.rs
similarity index 100%
rename from src/test/run-pass/fn-trait-sugar.rs
rename to src/test/run-pass/unboxed-closures-manual-impl.rs
diff --git a/src/test/run-pass/unboxed-closures-zero-args.rs b/src/test/run-pass/unboxed-closures-zero-args.rs
index 6d6d81fd0ef12..f2eddd84af832 100644
--- a/src/test/run-pass/unboxed-closures-zero-args.rs
+++ b/src/test/run-pass/unboxed-closures-zero-args.rs
@@ -12,6 +12,6 @@
 
 fn main() {
     let mut zero = |&mut:| {};
-    zero.call_mut(());
+    let () = zero.call_mut(());
 }