about summary refs log tree commit diff
path: root/src
diff options
context:
space:
mode:
authorNiko Matsakis <niko@alum.mit.edu>2015-01-10 11:54:15 -0500
committerNiko Matsakis <niko@alum.mit.edu>2015-01-28 05:15:23 -0500
commit07cdb853317697c247b41e61f7a429c3fb623524 (patch)
tree4b44f3fb2fa20220413aea7b6c844a5b99e9a196 /src
parentc61d7889b4bb270102dafe54cdfffbd737d168ff (diff)
downloadrust-07cdb853317697c247b41e61f7a429c3fb623524.tar.gz
rust-07cdb853317697c247b41e61f7a429c3fb623524.zip
Move return type an associated type of the `Fn*` traits. Mostly this involves tweaking things in
the compiler that assumed two input types to assume two ouputs; we also have to teach `project.rs`
to project `Output` from the unboxed closure and fn traits.
Diffstat (limited to 'src')
-rw-r--r--src/libcollections/btree/set.rs4
-rw-r--r--src/libcore/ops.rs75
-rw-r--r--src/libcore/str/mod.rs11
-rw-r--r--src/librustc/middle/traits/project.rs237
-rw-r--r--src/librustc/middle/traits/select.rs82
-rw-r--r--src/librustc/middle/traits/util.rs30
-rw-r--r--src/librustc/util/common.rs3
-rw-r--r--src/librustc/util/ppaux.rs5
-rw-r--r--src/librustc_typeck/astconv.rs35
-rw-r--r--src/libsyntax/ast.rs3
-rw-r--r--src/libsyntax/fold.rs5
-rw-r--r--src/libsyntax/parse/parser.rs7
12 files changed, 361 insertions, 136 deletions
diff --git a/src/libcollections/btree/set.rs b/src/libcollections/btree/set.rs
index e95087fa846..a090e4f24ce 100644
--- a/src/libcollections/btree/set.rs
+++ b/src/libcollections/btree/set.rs
@@ -758,7 +758,9 @@ mod test {
         expected: &'b [int],
     }
 
-    impl<'a, 'b, 'c> FnMut(&'c int) -> bool for Counter<'a, 'b> {
+    impl<'a, 'b, 'c> FnMut<(&'c int,)> for Counter<'a, 'b> {
+        type Output = bool;
+
         extern "rust-call" fn call_mut(&mut self, (&x,): (&'c int,)) -> bool {
             assert_eq!(x, self.expected[*self.i]);
             *self.i += 1;
diff --git a/src/libcore/ops.rs b/src/libcore/ops.rs
index d482888e3bc..0e99a2c9c3e 100644
--- a/src/libcore/ops.rs
+++ b/src/libcore/ops.rs
@@ -1117,29 +1117,33 @@ impl<'a, T: ?Sized> DerefMut for &'a mut T {
 #[lang="fn"]
 #[unstable(feature = "core",
            reason = "uncertain about variadic generics, input versus associated types")]
-pub trait Fn<Args,Result> {
+#[cfg(stage0)]
+pub trait Fn<Args,Output> {
     /// This is called when the call operator is used.
-    extern "rust-call" fn call(&self, args: Args) -> Result;
+    extern "rust-call" fn call(&self, args: Args) -> Output;
 }
 
 /// A version of the call operator that takes a mutable receiver.
 #[lang="fn_mut"]
 #[unstable(feature = "core",
            reason = "uncertain about variadic generics, input versus associated types")]
-pub trait FnMut<Args,Result> {
+#[cfg(stage0)]
+pub trait FnMut<Args,Output> {
     /// This is called when the call operator is used.
-    extern "rust-call" fn call_mut(&mut self, args: Args) -> Result;
+    extern "rust-call" fn call_mut(&mut self, args: Args) -> Output;
 }
 
 /// A version of the call operator that takes a by-value receiver.
 #[lang="fn_once"]
 #[unstable(feature = "core",
            reason = "uncertain about variadic generics, input versus associated types")]
-pub trait FnOnce<Args,Result> {
+#[cfg(stage0)]
+pub trait FnOnce<Args,Output> {
     /// This is called when the call operator is used.
-    extern "rust-call" fn call_once(self, args: Args) -> Result;
+    extern "rust-call" fn call_once(self, args: Args) -> Output;
 }
 
+#[cfg(stage0)]
 impl<F: ?Sized, A, R> FnMut<A, R> for F
     where F : Fn<A, R>
 {
@@ -1148,6 +1152,7 @@ impl<F: ?Sized, A, R> FnMut<A, R> for F
     }
 }
 
+#[cfg(stage0)]
 impl<F,A,R> FnOnce<A,R> for F
     where F : FnMut<A,R>
 {
@@ -1155,3 +1160,61 @@ impl<F,A,R> FnOnce<A,R> for F
         self.call_mut(args)
     }
 }
+
+/// A version of the call operator that takes an immutable receiver.
+#[lang="fn"]
+#[unstable(feature = "core",
+           reason = "uncertain about variadic generics, input versus associated types")]
+#[cfg(not(stage0))]
+pub trait Fn<Args> {
+    type Output;
+
+    /// This is called when the call operator is used.
+    extern "rust-call" fn call(&self, args: Args) -> Self::Output;
+}
+
+/// A version of the call operator that takes a mutable receiver.
+#[lang="fn_mut"]
+#[unstable(feature = "core",
+           reason = "uncertain about variadic generics, input versus associated types")]
+#[cfg(not(stage0))]
+pub trait FnMut<Args> {
+    type Output;
+
+    /// This is called when the call operator is used.
+    extern "rust-call" fn call_mut(&mut self, args: Args) -> Self::Output;
+}
+
+/// A version of the call operator that takes a by-value receiver.
+#[lang="fn_once"]
+#[unstable(feature = "core",
+           reason = "uncertain about variadic generics, input versus associated types")]
+#[cfg(not(stage0))]
+pub trait FnOnce<Args> {
+    type Output;
+
+    /// This is called when the call operator is used.
+    extern "rust-call" fn call_once(self, args: Args) -> Self::Output;
+}
+
+#[cfg(not(stage0))]
+impl<F: ?Sized, A> FnMut<A> for F
+    where F : Fn<A>
+{
+    type Output = <F as Fn<A>>::Output;
+
+    extern "rust-call" fn call_mut(&mut self, args: A) -> <F as Fn<A>>::Output {
+        self.call(args)
+    }
+}
+
+#[cfg(not(stage0))]
+impl<F,A> FnOnce<A> for F
+    where F : FnMut<A>
+{
+    type Output = <F as FnMut<A>>::Output;
+
+    extern "rust-call" fn call_once(mut self, args: A) -> <F as FnMut<A>>::Output {
+        self.call_mut(args)
+    }
+}
diff --git a/src/libcore/str/mod.rs b/src/libcore/str/mod.rs
index 5b94733ea6f..101d349c351 100644
--- a/src/libcore/str/mod.rs
+++ b/src/libcore/str/mod.rs
@@ -461,6 +461,7 @@ delegate_iter!{exact u8 : Bytes<'a>}
 #[derive(Copy, Clone)]
 struct BytesDeref;
 
+#[cfg(stage0)]
 impl<'a> Fn(&'a u8) -> u8 for BytesDeref {
     #[inline]
     extern "rust-call" fn call(&self, (ptr,): (&'a u8,)) -> u8 {
@@ -468,6 +469,16 @@ impl<'a> Fn(&'a u8) -> u8 for BytesDeref {
     }
 }
 
+#[cfg(not(stage0))]
+impl<'a> Fn<(&'a u8,)> for BytesDeref {
+    type Output = u8;
+
+    #[inline]
+    extern "rust-call" fn call(&self, (ptr,): (&'a u8,)) -> u8 {
+        *ptr
+    }
+}
+
 /// An iterator over the substrings of a string, separated by `sep`.
 #[derive(Clone)]
 struct CharSplits<'a, Sep> {
diff --git a/src/librustc/middle/traits/project.rs b/src/librustc/middle/traits/project.rs
index 0011603d3fa..d1dd086a5a3 100644
--- a/src/librustc/middle/traits/project.rs
+++ b/src/librustc/middle/traits/project.rs
@@ -18,13 +18,17 @@ use super::PredicateObligation;
 use super::SelectionContext;
 use super::SelectionError;
 use super::VtableImplData;
+use super::util;
 
 use middle::infer;
-use middle::subst::Subst;
+use middle::subst::{Subst, Substs};
 use middle::ty::{self, AsPredicate, ReferencesError, RegionEscape,
                  HasProjectionTypes, ToPolyTraitRef, Ty};
 use middle::ty_fold::{self, TypeFoldable, TypeFolder};
 use std::rc::Rc;
+use syntax::ast;
+use syntax::parse::token;
+use util::common::FN_OUTPUT_NAME;
 use util::ppaux::Repr;
 
 pub type PolyProjectionObligation<'tcx> =
@@ -53,6 +57,8 @@ pub struct MismatchedProjectionTypes<'tcx> {
 enum ProjectionTyCandidate<'tcx> {
     ParamEnv(ty::PolyProjectionPredicate<'tcx>),
     Impl(VtableImplData<'tcx, PredicateObligation<'tcx>>),
+    Closure(ast::DefId, Substs<'tcx>),
+    FnPointer(Ty<'tcx>),
 }
 
 struct ProjectionTyCandidateSet<'tcx> {
@@ -486,20 +492,22 @@ fn assemble_candidates_from_predicates<'cx,'tcx>(
 
                 let is_match = same_name && infcx.probe(|_| {
                     let origin = infer::Misc(obligation.cause.span);
-                    let obligation_poly_trait_ref =
-                        obligation_trait_ref.to_poly_trait_ref();
                     let data_poly_trait_ref =
                         data.to_poly_trait_ref();
+                    let obligation_poly_trait_ref =
+                        obligation_trait_ref.to_poly_trait_ref();
                     infcx.sub_poly_trait_refs(false,
                                               origin,
-                                              obligation_poly_trait_ref,
-                                              data_poly_trait_ref).is_ok()
+                                              data_poly_trait_ref,
+                                              obligation_poly_trait_ref).is_ok()
                 });
 
-                if is_match {
-                    debug!("assemble_candidates_from_predicates: candidate {}",
-                           data.repr(selcx.tcx()));
+                debug!("assemble_candidates_from_predicates: candidate {} is_match {} same_name {}",
+                       data.repr(selcx.tcx()),
+                       is_match,
+                       same_name);
 
+                if is_match {
                     candidate_set.vec.push(
                         ProjectionTyCandidate::ParamEnv(data.clone()));
                 }
@@ -573,6 +581,14 @@ fn assemble_candidates_from_impls<'cx,'tcx>(
                 selcx, obligation, obligation_trait_ref, candidate_set,
                 data.object_ty);
         }
+        super::VtableClosure(closure_def_id, substs) => {
+            candidate_set.vec.push(
+                ProjectionTyCandidate::Closure(closure_def_id, substs));
+        }
+        super::VtableFnPointer(fn_type) => {
+            candidate_set.vec.push(
+                ProjectionTyCandidate::FnPointer(fn_type));
+        }
         super::VtableParam(..) => {
             // This case tell us nothing about the value of an
             // associated type. Consider:
@@ -600,9 +616,7 @@ fn assemble_candidates_from_impls<'cx,'tcx>(
             // projection. And the projection where clause is handled
             // in `assemble_candidates_from_param_env`.
         }
-        super::VtableBuiltin(..) |
-        super::VtableClosure(..) |
-        super::VtableFnPointer(..) => {
+        super::VtableBuiltin(..) => {
             // These traits have no associated types.
             selcx.tcx().sess.span_bug(
                 obligation.cause.span,
@@ -628,67 +642,150 @@ fn confirm_candidate<'cx,'tcx>(
 
     match candidate {
         ProjectionTyCandidate::ParamEnv(poly_projection) => {
-            let projection =
-                infcx.replace_late_bound_regions_with_fresh_var(
-                    obligation.cause.span,
-                    infer::LateBoundRegionConversionTime::HigherRankedType,
-                    &poly_projection).0;
-
-            assert_eq!(projection.projection_ty.item_name,
-                       obligation.predicate.item_name);
-
-            let origin = infer::RelateOutputImplTypes(obligation.cause.span);
-            match infcx.sub_trait_refs(false,
-                                       origin,
-                                       obligation.predicate.trait_ref.clone(),
-                                       projection.projection_ty.trait_ref.clone()) {
-                Ok(()) => { }
-                Err(e) => {
-                    selcx.tcx().sess.span_bug(
-                        obligation.cause.span,
-                        format!("Failed to unify `{}` and `{}` in projection: {}",
-                                obligation.repr(selcx.tcx()),
-                                projection.repr(selcx.tcx()),
-                                ty::type_err_to_str(selcx.tcx(), &e)).as_slice());
-                }
-            }
-
-            (projection.ty, vec!())
+            confirm_param_env_candidate(selcx, obligation, poly_projection)
         }
 
         ProjectionTyCandidate::Impl(impl_vtable) => {
-            // there don't seem to be nicer accessors to these:
-            let impl_items_map = selcx.tcx().impl_items.borrow();
-            let impl_or_trait_items_map = selcx.tcx().impl_or_trait_items.borrow();
-
-            let impl_items = &impl_items_map[impl_vtable.impl_def_id];
-            let mut impl_ty = None;
-            for impl_item in impl_items.iter() {
-                let assoc_type = match impl_or_trait_items_map[impl_item.def_id()] {
-                    ty::TypeTraitItem(ref assoc_type) => assoc_type.clone(),
-                    ty::MethodTraitItem(..) => { continue; }
-                };
-
-                if assoc_type.name != obligation.predicate.item_name {
-                    continue;
-                }
+            confirm_impl_candidate(selcx, obligation, impl_vtable)
+        }
 
-                let impl_poly_ty = ty::lookup_item_type(selcx.tcx(), assoc_type.def_id);
-                impl_ty = Some(impl_poly_ty.ty.subst(selcx.tcx(), &impl_vtable.substs));
-                break;
-            }
+        ProjectionTyCandidate::Closure(def_id, substs) => {
+            confirm_closure_candidate(selcx, obligation, def_id, &substs)
+        }
 
-            match impl_ty {
-                Some(ty) => (ty, impl_vtable.nested.into_vec()),
-                None => {
-                    // This means that the impl is missing a
-                    // definition for the associated type. This error
-                    // ought to be reported by the type checker method
-                    // `check_impl_items_against_trait`, so here we
-                    // just return ty_err.
-                    (selcx.tcx().types.err, vec!())
-                }
-            }
+        ProjectionTyCandidate::FnPointer(fn_type) => {
+            confirm_fn_pointer_candidate(selcx, obligation, fn_type)
+        }
+    }
+}
+
+fn confirm_fn_pointer_candidate<'cx,'tcx>(
+    selcx: &mut SelectionContext<'cx,'tcx>,
+    obligation: &ProjectionTyObligation<'tcx>,
+    fn_type: Ty<'tcx>)
+    -> (Ty<'tcx>, Vec<PredicateObligation<'tcx>>)
+{
+    let fn_type = selcx.infcx().shallow_resolve(fn_type);
+    let sig = ty::ty_fn_sig(fn_type);
+    confirm_callable_candidate(selcx, obligation, sig, util::TupleArgumentsFlag::Yes)
+}
+
+fn confirm_closure_candidate<'cx,'tcx>(
+    selcx: &mut SelectionContext<'cx,'tcx>,
+    obligation: &ProjectionTyObligation<'tcx>,
+    closure_def_id: ast::DefId,
+    substs: &Substs<'tcx>)
+    -> (Ty<'tcx>, Vec<PredicateObligation<'tcx>>)
+{
+    let closure_typer = selcx.closure_typer();
+    let closure_type = closure_typer.closure_type(closure_def_id, substs);
+    confirm_callable_candidate(selcx, obligation, &closure_type.sig, util::TupleArgumentsFlag::No)
+}
+
+fn confirm_callable_candidate<'cx,'tcx>(
+    selcx: &mut SelectionContext<'cx,'tcx>,
+    obligation: &ProjectionTyObligation<'tcx>,
+    fn_sig: &ty::PolyFnSig<'tcx>,
+    flag: util::TupleArgumentsFlag)
+    -> (Ty<'tcx>, Vec<PredicateObligation<'tcx>>)
+{
+    let tcx = selcx.tcx();
+
+    debug!("confirm_closure_candidate({},{})",
+           obligation.repr(tcx),
+           fn_sig.repr(tcx));
+
+    // Note: we unwrap the binder here but re-create it below (1)
+    let ty::Binder((trait_ref, ret_type)) =
+        util::closure_trait_ref_and_return_type(tcx,
+                                                obligation.predicate.trait_ref.def_id,
+                                                obligation.predicate.trait_ref.self_ty(),
+                                                fn_sig,
+                                                flag);
+
+    let predicate = ty::Binder(ty::ProjectionPredicate { // (1) recreate binder here
+        projection_ty: ty::ProjectionTy {
+            trait_ref: trait_ref,
+            item_name: token::intern(FN_OUTPUT_NAME),
+        },
+        ty: ret_type
+    });
+
+    confirm_param_env_candidate(selcx, obligation, predicate)
+}
+
+fn confirm_param_env_candidate<'cx,'tcx>(
+    selcx: &mut SelectionContext<'cx,'tcx>,
+    obligation: &ProjectionTyObligation<'tcx>,
+    poly_projection: ty::PolyProjectionPredicate<'tcx>)
+    -> (Ty<'tcx>, Vec<PredicateObligation<'tcx>>)
+{
+    let infcx = selcx.infcx();
+
+    let projection =
+        infcx.replace_late_bound_regions_with_fresh_var(
+            obligation.cause.span,
+            infer::LateBoundRegionConversionTime::HigherRankedType,
+            &poly_projection).0;
+
+    assert_eq!(projection.projection_ty.item_name,
+               obligation.predicate.item_name);
+
+    let origin = infer::RelateOutputImplTypes(obligation.cause.span);
+    match infcx.sub_trait_refs(false,
+                               origin,
+                               obligation.predicate.trait_ref.clone(),
+                               projection.projection_ty.trait_ref.clone()) {
+        Ok(()) => { }
+        Err(e) => {
+            selcx.tcx().sess.span_bug(
+                obligation.cause.span,
+                format!("Failed to unify `{}` and `{}` in projection: {}",
+                        obligation.repr(selcx.tcx()),
+                        projection.repr(selcx.tcx()),
+                        ty::type_err_to_str(selcx.tcx(), &e)).as_slice());
+        }
+    }
+
+    (projection.ty, vec!())
+}
+
+fn confirm_impl_candidate<'cx,'tcx>(
+    selcx: &mut SelectionContext<'cx,'tcx>,
+    obligation: &ProjectionTyObligation<'tcx>,
+    impl_vtable: VtableImplData<'tcx, PredicateObligation<'tcx>>)
+    -> (Ty<'tcx>, Vec<PredicateObligation<'tcx>>)
+{
+    // there don't seem to be nicer accessors to these:
+    let impl_items_map = selcx.tcx().impl_items.borrow();
+    let impl_or_trait_items_map = selcx.tcx().impl_or_trait_items.borrow();
+
+    let impl_items = &impl_items_map[impl_vtable.impl_def_id];
+    let mut impl_ty = None;
+    for impl_item in impl_items.iter() {
+        let assoc_type = match impl_or_trait_items_map[impl_item.def_id()] {
+            ty::TypeTraitItem(ref assoc_type) => assoc_type.clone(),
+            ty::MethodTraitItem(..) => { continue; }
+        };
+
+        if assoc_type.name != obligation.predicate.item_name {
+            continue;
+        }
+
+        let impl_poly_ty = ty::lookup_item_type(selcx.tcx(), assoc_type.def_id);
+        impl_ty = Some(impl_poly_ty.ty.subst(selcx.tcx(), &impl_vtable.substs));
+        break;
+    }
+
+    match impl_ty {
+        Some(ty) => (ty, impl_vtable.nested.into_vec()),
+        None => {
+            // This means that the impl is missing a
+            // definition for the associated type. This error
+            // ought to be reported by the type checker method
+            // `check_impl_items_against_trait`, so here we
+            // just return ty_err.
+            (selcx.tcx().types.err, vec!())
         }
     }
 }
@@ -710,7 +807,11 @@ impl<'tcx> Repr<'tcx> for ProjectionTyCandidate<'tcx> {
             ProjectionTyCandidate::ParamEnv(ref data) =>
                 format!("ParamEnv({})", data.repr(tcx)),
             ProjectionTyCandidate::Impl(ref data) =>
-                format!("Impl({})", data.repr(tcx))
+                format!("Impl({})", data.repr(tcx)),
+            ProjectionTyCandidate::Closure(ref a, ref b) =>
+                format!("Closure(({},{}))", a.repr(tcx), b.repr(tcx)),
+            ProjectionTyCandidate::FnPointer(a) =>
+                format!("FnPointer(({}))", a.repr(tcx)),
         }
     }
 }
diff --git a/src/librustc/middle/traits/select.rs b/src/librustc/middle/traits/select.rs
index 12ad56d316a..2ad6f63a341 100644
--- a/src/librustc/middle/traits/select.rs
+++ b/src/librustc/middle/traits/select.rs
@@ -214,6 +214,10 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
         self.closure_typer.param_env()
     }
 
+    pub fn closure_typer(&self) -> &'cx (ty::UnboxedClosureTyper<'tcx>+'cx) {
+        self.closure_typer
+    }
+
     ///////////////////////////////////////////////////////////////////////////
     // Selection
     //
@@ -1913,33 +1917,14 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
                obligation.repr(self.tcx()));
 
         let self_ty = self.infcx.shallow_resolve(obligation.self_ty());
-        let sig = match self_ty.sty {
-            ty::ty_bare_fn(_, &ty::BareFnTy {
-                unsafety: ast::Unsafety::Normal,
-                abi: abi::Rust,
-                ref sig
-            }) => {
-                sig
-            }
-            _ => {
-                self.tcx().sess.span_bug(
-                    obligation.cause.span,
-                    &format!("Fn pointer candidate for inappropriate self type: {}",
-                            self_ty.repr(self.tcx()))[]);
-            }
-        };
-
-        let arguments_tuple = ty::mk_tup(self.tcx(), sig.0.inputs.to_vec());
-        let output_type = sig.0.output.unwrap();
-        let substs =
-            Substs::new_trait(
-                vec![arguments_tuple, output_type],
-                vec![],
-                self_ty);
-        let trait_ref = ty::Binder(Rc::new(ty::TraitRef {
-            def_id: obligation.predicate.def_id(),
-            substs: self.tcx().mk_substs(substs),
-        }));
+        let sig = ty::ty_fn_sig(self_ty);
+        let ty::Binder((trait_ref, _)) =
+            util::closure_trait_ref_and_return_type(self.tcx(),
+                                                    obligation.predicate.def_id(),
+                                                    self_ty,
+                                                    sig,
+                                                    util::TupleArgumentsFlag::Yes);
+        let trait_ref = ty::Binder(trait_ref);
 
         try!(self.confirm_poly_trait_refs(obligation.cause.clone(),
                                           obligation.predicate.to_poly_trait_ref(),
@@ -1958,23 +1943,9 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
                closure_def_id.repr(self.tcx()),
                substs.repr(self.tcx()));
 
-        let closure_type = self.closure_typer.closure_type(closure_def_id, substs);
-
-        debug!("confirm_closure_candidate: closure_def_id={} closure_type={}",
-               closure_def_id.repr(self.tcx()),
-               closure_type.repr(self.tcx()));
-
-        let closure_sig = &closure_type.sig;
-        let arguments_tuple = closure_sig.0.inputs[0];
-        let trait_substs =
-            Substs::new_trait(
-                vec![arguments_tuple, closure_sig.0.output.unwrap()],
-                vec![],
-                obligation.self_ty());
-        let trait_ref = ty::Binder(Rc::new(ty::TraitRef {
-            def_id: obligation.predicate.def_id(),
-            substs: self.tcx().mk_substs(trait_substs),
-        }));
+        let trait_ref = self.closure_trait_ref(obligation,
+                                               closure_def_id,
+                                               substs);
 
         debug!("confirm_closure_candidate(closure_def_id={}, trait_ref={})",
                closure_def_id.repr(self.tcx()),
@@ -2280,6 +2251,29 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
         }
     }
 
+    fn closure_trait_ref(&self,
+                         obligation: &TraitObligation<'tcx>,
+                         closure_def_id: ast::DefId,
+                         substs: &Substs<'tcx>)
+                         -> ty::PolyTraitRef<'tcx>
+    {
+        let closure_type = self.closure_typer.closure_type(closure_def_id, substs);
+        let ty::Binder((trait_ref, _)) =
+            util::closure_trait_ref_and_return_type(self.tcx(),
+                                                    obligation.predicate.def_id(),
+                                                    obligation.predicate.0.self_ty(), // (1)
+                                                    &closure_type.sig,
+                                                    util::TupleArgumentsFlag::No);
+
+        // (1) Feels icky to skip the binder here, but OTOH we know
+        // that the self-type is an unboxed closure type and hence is
+        // in fact unparameterized (or at least does not reference any
+        // regions bound in the obligation). Still probably some
+        // refactoring could make this nicer.
+
+        ty::Binder(trait_ref)
+    }
+
     fn impl_obligations(&mut self,
                         cause: ObligationCause<'tcx>,
                         recursion_depth: uint,
diff --git a/src/librustc/middle/traits/util.rs b/src/librustc/middle/traits/util.rs
index beb28260834..f8c18489651 100644
--- a/src/librustc/middle/traits/util.rs
+++ b/src/librustc/middle/traits/util.rs
@@ -353,6 +353,36 @@ pub fn get_vtable_index_of_object_method<'tcx>(tcx: &ty::ctxt<'tcx>,
     method_count + method_index_in_trait
 }
 
+pub fn unboxed_closure_trait_ref_and_return_type<'tcx>(
+    closure_typer: &ty::UnboxedClosureTyper<'tcx>,
+    fn_trait_def_id: ast::DefId,
+    self_ty: Ty<'tcx>,
+    closure_def_id: ast::DefId,
+    substs: &Substs<'tcx>)
+    -> ty::Binder<(Rc<ty::TraitRef<'tcx>>, Ty<'tcx>)>
+{
+    let tcx = closure_typer.param_env().tcx;
+    let closure_type = closure_typer.unboxed_closure_type(closure_def_id, substs);
+
+    debug!("unboxed_closure_trait_ref: closure_def_id={} closure_type={}",
+           closure_def_id.repr(tcx),
+           closure_type.repr(tcx));
+
+    let closure_sig = &closure_type.sig;
+    let arguments_tuple = closure_sig.0.inputs[0];
+    let trait_substs =
+        Substs::new_trait(
+            vec![arguments_tuple],
+            vec![],
+            self_ty);
+    let trait_ref = Rc::new(ty::TraitRef {
+        def_id: fn_trait_def_id,
+        substs: tcx.mk_substs(trait_substs),
+    });
+
+    ty::Binder((trait_ref, closure_sig.0.output.unwrap()))
+}
+
 impl<'tcx,O:Repr<'tcx>> Repr<'tcx> for super::Obligation<'tcx, O> {
     fn repr(&self, tcx: &ty::ctxt<'tcx>) -> String {
         format!("Obligation(predicate={},depth={})",
diff --git a/src/librustc/util/common.rs b/src/librustc/util/common.rs
index 8915d55e206..bdb6ea22f8b 100644
--- a/src/librustc/util/common.rs
+++ b/src/librustc/util/common.rs
@@ -22,6 +22,9 @@ use syntax::ast;
 use syntax::visit;
 use syntax::visit::Visitor;
 
+// The name of the associated type for `Fn` return types
+pub const FN_OUTPUT_NAME: &'static str = "Output";
+
 // Useful type to use with `Result<>` indicate that an error has already
 // been reported to the user, so no need to continue checking.
 #[derive(Clone, Copy, Show)]
diff --git a/src/librustc/util/ppaux.rs b/src/librustc/util/ppaux.rs
index 5601898136c..c10ce686f08 100644
--- a/src/librustc/util/ppaux.rs
+++ b/src/librustc/util/ppaux.rs
@@ -512,7 +512,7 @@ pub fn parameterized<'tcx>(cx: &ctxt<'tcx>,
     }
 
     if cx.lang_items.fn_trait_kind(did).is_some() {
-        format!("{}({}){}",
+        format!("{}({})", // TODO
                 base,
                 if strs[0].starts_with("(") && strs[0].ends_with(",)") {
                     &strs[0][1 .. strs[0].len() - 2] // Remove '(' and ',)'
@@ -520,8 +520,7 @@ pub fn parameterized<'tcx>(cx: &ctxt<'tcx>,
                     &strs[0][1 .. strs[0].len() - 1] // Remove '(' and ')'
                 } else {
                     &strs[0][]
-                },
-                if &*strs[1] == "()" { String::new() } else { format!(" -> {}", strs[1]) })
+                })
     } else if strs.len() > 0 {
         format!("{}<{}>", base, strs.connect(", "))
     } else {
diff --git a/src/librustc_typeck/astconv.rs b/src/librustc_typeck/astconv.rs
index 921ed505fa3..6e8dd6b0ae7 100644
--- a/src/librustc_typeck/astconv.rs
+++ b/src/librustc_typeck/astconv.rs
@@ -57,7 +57,7 @@ use middle::ty::{self, RegionEscape, ToPolyTraitRef, Ty};
 use rscope::{self, UnelidableRscope, RegionScope, SpecificRscope,
              ShiftedRscope, BindingRscope};
 use TypeAndSubsts;
-use util::common::ErrorReported;
+use util::common::{ErrorReported, FN_OUTPUT_NAME};
 use util::nodemap::DefIdMap;
 use util::ppaux::{self, Repr, UserString};
 
@@ -268,7 +268,7 @@ pub fn ast_path_substs_for_ty<'tcx>(
         ast::ParenthesizedParameters(ref data) => {
             span_err!(tcx.sess, path.span, E0214,
                 "parenthesized parameters may only be used with a trait");
-            (Vec::new(), convert_parenthesized_parameters(this, data), Vec::new())
+            convert_parenthesized_parameters(this, data)
         }
     };
 
@@ -479,7 +479,9 @@ fn convert_ty_with_lifetime_elision<'tcx>(this: &AstConv<'tcx>,
 
 fn convert_parenthesized_parameters<'tcx>(this: &AstConv<'tcx>,
                                           data: &ast::ParenthesizedParameterData)
-                                          -> Vec<Ty<'tcx>>
+                                          -> (Vec<ty::Region>,
+                                              Vec<Ty<'tcx>>,
+                                              Vec<ConvertedBinding<'tcx>>)
 {
     let binding_rscope = BindingRscope::new();
     let inputs = data.inputs.iter()
@@ -492,15 +494,26 @@ fn convert_parenthesized_parameters<'tcx>(this: &AstConv<'tcx>,
 
     let input_ty = ty::mk_tup(this.tcx(), inputs);
 
-    let output = match data.output {
-        Some(ref output_ty) => convert_ty_with_lifetime_elision(this,
-                                                                implied_output_region,
-                                                                params_lifetimes,
-                                                                &**output_ty),
-        None => ty::mk_nil(this.tcx()),
+    let (output, output_span) = match data.output {
+        Some(ref output_ty) => {
+            (convert_ty_with_lifetime_elision(this,
+                                              implied_output_region,
+                                              params_lifetimes,
+                                              &**output_ty),
+             output_ty.span)
+        }
+        None => {
+            (ty::mk_nil(this.tcx()), data.span)
+        }
+    };
+
+    let output_binding = ConvertedBinding {
+        item_name: token::intern(FN_OUTPUT_NAME),
+        ty: output,
+        span: output_span
     };
 
-    vec![input_ty, output]
+    (vec![], vec![input_ty], vec![output_binding])
 }
 
 pub fn instantiate_poly_trait_ref<'tcx>(
@@ -630,7 +643,7 @@ fn ast_path_to_trait_ref<'a,'tcx>(
                             the crate attributes to enable");
             }
 
-            (Vec::new(), convert_parenthesized_parameters(this, data), Vec::new())
+            convert_parenthesized_parameters(this, data)
         }
     };
 
diff --git a/src/libsyntax/ast.rs b/src/libsyntax/ast.rs
index 4f6cd8ad356..4dada5bc81e 100644
--- a/src/libsyntax/ast.rs
+++ b/src/libsyntax/ast.rs
@@ -347,6 +347,9 @@ impl AngleBracketedParameterData {
 /// A path like `Foo(A,B) -> C`
 #[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Show)]
 pub struct ParenthesizedParameterData {
+    /// Overall span
+    pub span: Span,
+
     /// `(A,B)`
     pub inputs: Vec<P<Ty>>,
 
diff --git a/src/libsyntax/fold.rs b/src/libsyntax/fold.rs
index bf822599a88..a1362f5382c 100644
--- a/src/libsyntax/fold.rs
+++ b/src/libsyntax/fold.rs
@@ -536,9 +536,10 @@ pub fn noop_fold_parenthesized_parameter_data<T: Folder>(data: ParenthesizedPara
                                                          fld: &mut T)
                                                          -> ParenthesizedParameterData
 {
-    let ParenthesizedParameterData { inputs, output } = data;
+    let ParenthesizedParameterData { inputs, output, span } = data;
     ParenthesizedParameterData { inputs: inputs.move_map(|ty| fld.fold_ty(ty)),
-                                 output: output.map(|ty| fld.fold_ty(ty)) }
+                                 output: output.map(|ty| fld.fold_ty(ty)),
+                                 span: fld.new_span(span) }
 }
 
 pub fn noop_fold_local<T: Folder>(l: P<Local>, fld: &mut T) -> P<Local> {
diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs
index fbea265597c..4c1ae532d13 100644
--- a/src/libsyntax/parse/parser.rs
+++ b/src/libsyntax/parse/parser.rs
@@ -1796,6 +1796,8 @@ impl<'a> Parser<'a> {
                     bindings: OwnedSlice::from_vec(bindings),
                 })
             } else if self.eat(&token::OpenDelim(token::Paren)) {
+                let lo = self.last_span.lo;
+
                 let inputs = self.parse_seq_to_end(
                     &token::CloseDelim(token::Paren),
                     seq_sep_trailing_allowed(token::Comma),
@@ -1807,9 +1809,12 @@ impl<'a> Parser<'a> {
                     None
                 };
 
+                let hi = self.last_span.hi;
+
                 ast::ParenthesizedParameters(ast::ParenthesizedParameterData {
+                    span: mk_sp(lo, hi),
                     inputs: inputs,
-                    output: output_ty
+                    output: output_ty,
                 })
             } else {
                 ast::PathParameters::none()