about summary refs log tree commit diff
diff options
context:
space:
mode:
authorAlex Crichton <alex@alexcrichton.com>2014-11-06 13:31:18 -0800
committerAlex Crichton <alex@alexcrichton.com>2014-11-06 13:31:18 -0800
commit76d2abe0e7fb33ed41137a0c99fbbc2905d8ca91 (patch)
tree1ea979f4b18b619db872eded0bbdb7971e6cc379
parent08ddfc10e4170ac5f4522a71c0d1aea8cf799f29 (diff)
parentd0fa4c6239accc08aae11d9db3e13d4153add432 (diff)
downloadrust-76d2abe0e7fb33ed41137a0c99fbbc2905d8ca91.tar.gz
rust-76d2abe0e7fb33ed41137a0c99fbbc2905d8ca91.zip
rollup merge of #18630 : nikomatsakis/purge-the-bars
-rw-r--r--src/librustc/diagnostics.rs5
-rw-r--r--src/librustc/middle/check_const.rs2
-rw-r--r--src/librustc/middle/pat_util.rs4
-rw-r--r--src/librustc/middle/privacy.rs4
-rw-r--r--src/librustc/middle/resolve.rs45
-rw-r--r--src/librustc/middle/resolve_lifetime.rs15
-rw-r--r--src/librustc/middle/save/mod.rs2
-rw-r--r--src/librustc/middle/trans/base.rs6
-rw-r--r--src/librustc/middle/trans/consts.rs2
-rw-r--r--src/librustc/middle/ty.rs8
-rw-r--r--src/librustc/middle/typeck/astconv.rs285
-rw-r--r--src/librustc/middle/typeck/check/mod.rs90
-rw-r--r--src/librustc/middle/typeck/collect.rs60
-rw-r--r--src/librustc/middle/typeck/infer/error_reporting.rs74
-rw-r--r--src/librustdoc/clean/inline.rs1
-rw-r--r--src/librustdoc/clean/mod.rs34
-rw-r--r--src/librustdoc/html/format.rs6
-rw-r--r--src/libsyntax/ast.rs113
-rw-r--r--src/libsyntax/ast_map/mod.rs3
-rw-r--r--src/libsyntax/ast_util.rs18
-rw-r--r--src/libsyntax/ext/build.rs9
-rw-r--r--src/libsyntax/ext/concat_idents.rs4
-rw-r--r--src/libsyntax/feature_gate.rs5
-rw-r--r--src/libsyntax/fold.rs73
-rw-r--r--src/libsyntax/parse/mod.rs24
-rw-r--r--src/libsyntax/parse/parser.rs266
-rw-r--r--src/libsyntax/print/pprust.rs112
-rw-r--r--src/libsyntax/std_inject.rs7
-rw-r--r--src/libsyntax/test.rs3
-rw-r--r--src/libsyntax/visit.rs35
-rw-r--r--src/test/compile-fail/issue-14092.rs2
-rw-r--r--src/test/compile-fail/issue-18423.rs18
-rw-r--r--src/test/compile-fail/unboxed-closure-sugar-default.rs37
-rw-r--r--src/test/compile-fail/unboxed-closure-sugar-equiv.rs39
-rw-r--r--src/test/compile-fail/unboxed-closure-sugar-nonexistent-trait.rs2
-rw-r--r--src/test/compile-fail/unboxed-closure-sugar-region.rs45
-rw-r--r--src/test/compile-fail/unboxed-closure-sugar-wrong-number-number-type-parameters-1.rs16
-rw-r--r--src/test/compile-fail/unboxed-closure-sugar-wrong-number-number-type-parameters-3.rs16
-rw-r--r--src/test/compile-fail/unboxed-closure-sugar-wrong-number-number-type-parameters.rs16
-rw-r--r--src/test/compile-fail/unboxed-closure-sugar-wrong-trait.rs2
-rw-r--r--src/test/run-pass/unboxed-closures-manual-impl.rs2
-rw-r--r--src/test/run-pass/unboxed-closures-prelude.rs2
-rw-r--r--src/test/run-pass/unboxed-closures-sugar-1.rs34
-rw-r--r--src/test/run-pass/unboxed-closures-sugar-object.rs34
-rw-r--r--src/test/run-pass/unboxed-closures-unboxing-shim.rs2
45 files changed, 953 insertions, 629 deletions
diff --git a/src/librustc/diagnostics.rs b/src/librustc/diagnostics.rs
index c4e21379088..d5e9c1ef99f 100644
--- a/src/librustc/diagnostics.rs
+++ b/src/librustc/diagnostics.rs
@@ -57,7 +57,6 @@ register_diagnostics!(
     E0044,
     E0045,
     E0046,
-    E0047,
     E0049,
     E0050,
     E0051,
@@ -111,7 +110,6 @@ register_diagnostics!(
     E0108,
     E0109,
     E0110,
-    E0113,
     E0116,
     E0117,
     E0118,
@@ -145,5 +143,6 @@ register_diagnostics!(
     E0163,
     E0164,
     E0165,
-    E0166
+    E0166,
+    E0167
 )
diff --git a/src/librustc/middle/check_const.rs b/src/librustc/middle/check_const.rs
index b03fe0f3f6f..7a97589b9fa 100644
--- a/src/librustc/middle/check_const.rs
+++ b/src/librustc/middle/check_const.rs
@@ -138,7 +138,7 @@ fn check_expr(v: &mut CheckCrateVisitor, e: &Expr) -> bool {
             // to handle on-demand instantiation of functions via
             // foo::<bar> in a const. Currently that is only done on
             // a path in trans::callee that only works in block contexts.
-            if !pth.segments.iter().all(|segment| segment.types.is_empty()) {
+            if !pth.segments.iter().all(|segment| segment.parameters.is_empty()) {
                 span_err!(v.tcx.sess, e.span, E0013,
                           "paths in constants may only refer to items without \
                            type parameters");
diff --git a/src/librustc/middle/pat_util.rs b/src/librustc/middle/pat_util.rs
index 958f65d7efb..e320f47075e 100644
--- a/src/librustc/middle/pat_util.rs
+++ b/src/librustc/middle/pat_util.rs
@@ -16,7 +16,6 @@ use std::collections::HashMap;
 use syntax::ast::*;
 use syntax::ast_util::{walk_pat};
 use syntax::codemap::{Span, DUMMY_SP};
-use syntax::owned_slice::OwnedSlice;
 
 pub type PatIdMap = HashMap<Ident, NodeId>;
 
@@ -133,8 +132,7 @@ pub fn def_to_path(tcx: &ty::ctxt, id: DefId) -> Path {
         global: false,
         segments: path.last().map(|elem| PathSegment {
             identifier: Ident::new(elem.name()),
-            lifetimes: vec!(),
-            types: OwnedSlice::empty()
+            parameters: PathParameters::none(),
         }).into_iter().collect(),
         span: DUMMY_SP,
     })
diff --git a/src/librustc/middle/privacy.rs b/src/librustc/middle/privacy.rs
index 24c653e415e..21b94babcb6 100644
--- a/src/librustc/middle/privacy.rs
+++ b/src/librustc/middle/privacy.rs
@@ -27,7 +27,6 @@ use syntax::ast_map;
 use syntax::ast_util::{is_local, local_def, PostExpansionMethod};
 use syntax::codemap::Span;
 use syntax::parse::token;
-use syntax::owned_slice::OwnedSlice;
 use syntax::visit;
 use syntax::visit::Visitor;
 
@@ -945,8 +944,7 @@ impl<'a, 'tcx, 'v> Visitor<'v> for PrivacyVisitor<'a, 'tcx> {
                                     debug!("privacy - ident item {}", id);
                                     let seg = ast::PathSegment {
                                         identifier: name,
-                                        lifetimes: Vec::new(),
-                                        types: OwnedSlice::empty(),
+                                        parameters: ast::PathParameters::none(),
                                     };
                                     let segs = vec![seg];
                                     let path = ast::Path {
diff --git a/src/librustc/middle/resolve.rs b/src/librustc/middle/resolve.rs
index a8adbbe8fec..a1a8cccf55a 100644
--- a/src/librustc/middle/resolve.rs
+++ b/src/librustc/middle/resolve.rs
@@ -40,7 +40,7 @@ use syntax::ast::{TupleVariantKind, Ty, TyBool, TyChar, TyClosure, TyF32};
 use syntax::ast::{TyF64, TyFloat, TyI, TyI8, TyI16, TyI32, TyI64, TyInt};
 use syntax::ast::{TyParam, TyParamBound, TyPath, TyPtr, TyProc, TyQPath};
 use syntax::ast::{TyRptr, TyStr, TyU, TyU8, TyU16, TyU32, TyU64, TyUint};
-use syntax::ast::{TypeImplItem, UnboxedFnTyParamBound, UnnamedField};
+use syntax::ast::{TypeImplItem, UnnamedField};
 use syntax::ast::{Variant, ViewItem, ViewItemExternCrate};
 use syntax::ast::{ViewItemUse, ViewPathGlob, ViewPathList, ViewPathSimple};
 use syntax::ast::{Visibility};
@@ -4523,41 +4523,6 @@ impl<'a> Resolver<'a> {
             TraitTyParamBound(ref tref) => {
                 self.resolve_trait_reference(id, tref, reference_type)
             }
-            UnboxedFnTyParamBound(ref unboxed_function) => {
-                match self.resolve_path(unboxed_function.ref_id,
-                                        &unboxed_function.path,
-                                        TypeNS,
-                                        true) {
-                    None => {
-                        let path_str = self.path_names_to_string(
-                            &unboxed_function.path);
-                        self.resolve_error(unboxed_function.path.span,
-                                           format!("unresolved trait `{}`",
-                                                   path_str).as_slice())
-                    }
-                    Some(def) => {
-                        match def {
-                            (DefTrait(_), _) => {
-                                self.record_def(unboxed_function.ref_id, def);
-                            }
-                            _ => {
-                                let msg =
-                                    format!("`{}` is not a trait",
-                                            self.path_names_to_string(
-                                                &unboxed_function.path));
-                                self.resolve_error(unboxed_function.path.span,
-                                                   msg.as_slice());
-                            }
-                        }
-                    }
-                }
-
-                for argument in unboxed_function.decl.inputs.iter() {
-                    self.resolve_type(&*argument.ty);
-                }
-
-                self.resolve_type(&*unboxed_function.decl.output);
-            }
             RegionTyParamBound(..) => {}
         }
     }
@@ -4951,12 +4916,12 @@ impl<'a> Resolver<'a> {
 
                             if path.segments
                                    .iter()
-                                   .any(|s| !s.lifetimes.is_empty()) {
+                                   .any(|s| s.parameters.has_lifetimes()) {
                                 span_err!(self.session, path.span, E0157,
                                     "lifetime parameters are not allowed on this type");
                             } else if path.segments
                                           .iter()
-                                          .any(|s| s.types.len() > 0) {
+                                          .any(|s| !s.parameters.is_empty()) {
                                 span_err!(self.session, path.span, E0153,
                                     "type parameters are not allowed on this type");
                             }
@@ -5234,7 +5199,7 @@ impl<'a> Resolver<'a> {
                     // Check the types in the path pattern.
                     for ty in path.segments
                                   .iter()
-                                  .flat_map(|s| s.types.iter()) {
+                                  .flat_map(|s| s.parameters.types().into_iter()) {
                         self.resolve_type(&**ty);
                     }
                 }
@@ -5340,7 +5305,7 @@ impl<'a> Resolver<'a> {
                     namespace: Namespace,
                     check_ribs: bool) -> Option<(Def, LastPrivate)> {
         // First, resolve the types.
-        for ty in path.segments.iter().flat_map(|s| s.types.iter()) {
+        for ty in path.segments.iter().flat_map(|s| s.parameters.types().into_iter()) {
             self.resolve_type(&**ty);
         }
 
diff --git a/src/librustc/middle/resolve_lifetime.rs b/src/librustc/middle/resolve_lifetime.rs
index eda4c241f86..8246970c24a 100644
--- a/src/librustc/middle/resolve_lifetime.rs
+++ b/src/librustc/middle/resolve_lifetime.rs
@@ -204,9 +204,6 @@ impl<'a> LifetimeContext<'a> {
                 ast::TraitTyParamBound(ref trait_ref) => {
                     self.visit_trait_ref(trait_ref);
                 }
-                ast::UnboxedFnTyParamBound(ref fn_decl) => {
-                    self.visit_unboxed_fn_ty_param_bound(&**fn_decl);
-                }
                 ast::RegionTyParamBound(ref lifetime) => {
                     self.visit_lifetime_ref(lifetime);
                 }
@@ -226,18 +223,6 @@ impl<'a> LifetimeContext<'a> {
         })
     }
 
-    fn visit_unboxed_fn_ty_param_bound(&mut self,
-                                       bound: &ast::UnboxedFnBound) {
-        self.with(|scope, f| {
-            f(LateScope(bound.ref_id, &bound.lifetimes, scope))
-        }, |v| {
-            for argument in bound.decl.inputs.iter() {
-                v.visit_ty(&*argument.ty);
-            }
-            v.visit_ty(&*bound.decl.output);
-        })
-    }
-
     /// Visits self by adding a scope and handling recursive walk over the contents with `walk`.
     fn visit_fn_decl(&mut self,
                      n: ast::NodeId,
diff --git a/src/librustc/middle/save/mod.rs b/src/librustc/middle/save/mod.rs
index 90a21d47903..b64a160ab1f 100644
--- a/src/librustc/middle/save/mod.rs
+++ b/src/librustc/middle/save/mod.rs
@@ -705,7 +705,7 @@ impl <'l, 'tcx> DxrVisitor<'l, 'tcx> {
                 ast::TraitTyParamBound(ref trait_ref) => {
                     trait_ref
                 }
-                ast::UnboxedFnTyParamBound(..) | ast::RegionTyParamBound(..) => {
+                ast::RegionTyParamBound(..) => {
                     continue;
                 }
             };
diff --git a/src/librustc/middle/trans/base.rs b/src/librustc/middle/trans/base.rs
index 3b3b886c6d0..0d8ef560c7d 100644
--- a/src/librustc/middle/trans/base.rs
+++ b/src/librustc/middle/trans/base.rs
@@ -1836,11 +1836,7 @@ pub fn trans_closure(ccx: &CrateContext,
         NotUnboxedClosure => monomorphized_arg_types,
 
         // Tuple up closure argument types for the "rust-call" ABI.
-        IsUnboxedClosure => vec![if monomorphized_arg_types.is_empty() {
-            ty::mk_nil()
-        } else {
-            ty::mk_tup(ccx.tcx(), monomorphized_arg_types)
-        }]
+        IsUnboxedClosure => vec![ty::mk_tup_or_nil(ccx.tcx(), monomorphized_arg_types)]
     };
     for monomorphized_arg_type in monomorphized_arg_types.iter() {
         debug!("trans_closure: monomorphized_arg_type: {}",
diff --git a/src/librustc/middle/trans/consts.rs b/src/librustc/middle/trans/consts.rs
index ced6c2f4949..409809e0cb3 100644
--- a/src/librustc/middle/trans/consts.rs
+++ b/src/librustc/middle/trans/consts.rs
@@ -625,7 +625,7 @@ fn const_expr_unadjusted(cx: &CrateContext, e: &ast::Expr) -> ValueRef {
           }
           ast::ExprPath(ref pth) => {
             // Assert that there are no type parameters in this path.
-            assert!(pth.segments.iter().all(|seg| seg.types.is_empty()));
+            assert!(pth.segments.iter().all(|seg| !seg.parameters.has_types()));
 
             let opt_def = cx.tcx().def_map.borrow().find_copy(&e.id);
             match opt_def {
diff --git a/src/librustc/middle/ty.rs b/src/librustc/middle/ty.rs
index 421042a8648..d1baeac81ab 100644
--- a/src/librustc/middle/ty.rs
+++ b/src/librustc/middle/ty.rs
@@ -1838,6 +1838,14 @@ pub fn mk_slice(cx: &ctxt, r: Region, tm: mt) -> t {
 
 pub fn mk_tup(cx: &ctxt, ts: Vec<t>) -> t { mk_t(cx, ty_tup(ts)) }
 
+pub fn mk_tup_or_nil(cx: &ctxt, ts: Vec<t>) -> t {
+    if ts.len() == 0 {
+        ty::mk_nil()
+    } else {
+        mk_t(cx, ty_tup(ts))
+    }
+}
+
 pub fn mk_closure(cx: &ctxt, fty: ClosureTy) -> t {
     mk_t(cx, ty_closure(box fty))
 }
diff --git a/src/librustc/middle/typeck/astconv.rs b/src/librustc/middle/typeck/astconv.rs
index 32fd385aa5d..ae0bbd617e2 100644
--- a/src/librustc/middle/typeck/astconv.rs
+++ b/src/librustc/middle/typeck/astconv.rs
@@ -59,7 +59,7 @@ use middle::subst::{VecPerParamSpace};
 use middle::ty;
 use middle::typeck::lookup_def_tcx;
 use middle::typeck::infer;
-use middle::typeck::rscope::{UnelidableRscope, RegionScope, SpecificRscope};
+use middle::typeck::rscope::{UnelidableRscope, RegionScope, SpecificRscope, BindingRscope};
 use middle::typeck::rscope;
 use middle::typeck::TypeAndSubsts;
 use middle::typeck;
@@ -207,15 +207,16 @@ pub fn opt_ast_region_to_region<'tcx, AC: AstConv<'tcx>, RS: RegionScope>(
 }
 
 fn ast_path_substs<'tcx,AC,RS>(
-                   this: &AC,
-                   rscope: &RS,
-                   decl_def_id: ast::DefId,
-                   decl_generics: &ty::Generics,
-                   self_ty: Option<ty::t>,
-                   associated_ty: Option<ty::t>,
-                   path: &ast::Path)
-                   -> Substs
-                   where AC: AstConv<'tcx>, RS: RegionScope
+    this: &AC,
+    rscope: &RS,
+    decl_def_id: ast::DefId,
+    decl_generics: &ty::Generics,
+    self_ty: Option<ty::t>,
+    associated_ty: Option<ty::t>,
+    path: &ast::Path,
+    binder_id: ast::NodeId)
+    -> Substs
+    where AC: AstConv<'tcx>, RS: RegionScope
 {
     /*!
      * Given a path `path` that refers to an item `I` with the
@@ -236,45 +237,51 @@ fn ast_path_substs<'tcx,AC,RS>(
     assert!(decl_generics.regions.all(|d| d.space == TypeSpace));
     assert!(decl_generics.types.all(|d| d.space != FnSpace));
 
+    let (regions, types) = match path.segments.last().unwrap().parameters {
+        ast::AngleBracketedParameters(ref data) =>
+            angle_bracketed_parameters(this, rscope, data),
+        ast::ParenthesizedParameters(ref data) =>
+            parenthesized_parameters(this, binder_id, data),
+    };
+
     // If the type is parameterized by the this region, then replace this
     // region with the current anon region binding (in other words,
     // whatever & would get replaced with).
     let expected_num_region_params = decl_generics.regions.len(TypeSpace);
-    let supplied_num_region_params = path.segments.last().unwrap().lifetimes.len();
+    let supplied_num_region_params = regions.len();
     let regions = if expected_num_region_params == supplied_num_region_params {
-        path.segments.last().unwrap().lifetimes.iter().map(
-            |l| ast_region_to_region(this.tcx(), l)).collect::<Vec<_>>()
+        regions
     } else {
         let anon_regions =
             rscope.anon_regions(path.span, expected_num_region_params);
 
         if supplied_num_region_params != 0 || anon_regions.is_err() {
             span_err!(tcx.sess, path.span, E0107,
-                "wrong number of lifetime parameters: expected {}, found {}",
-                expected_num_region_params, supplied_num_region_params);
+                      "wrong number of lifetime parameters: expected {}, found {}",
+                      expected_num_region_params, supplied_num_region_params);
         }
 
         match anon_regions {
             Ok(v) => v.into_iter().collect(),
             Err(_) => Vec::from_fn(expected_num_region_params,
-                                    |_| ty::ReStatic) // hokey
+                                   |_| ty::ReStatic) // hokey
         }
     };
 
     // Convert the type parameters supplied by the user.
     let ty_param_defs = decl_generics.types.get_slice(TypeSpace);
-    let supplied_ty_param_count = path.segments.iter().flat_map(|s| s.types.iter()).count();
+    let supplied_ty_param_count = types.len();
     let formal_ty_param_count =
         ty_param_defs.iter()
-                     .take_while(|x| !ty::is_associated_type(tcx, x.def_id))
-                     .count();
+        .take_while(|x| !ty::is_associated_type(tcx, x.def_id))
+        .count();
     let required_ty_param_count =
         ty_param_defs.iter()
-                     .take_while(|x| {
-                        x.default.is_none() &&
-                        !ty::is_associated_type(tcx, x.def_id)
-                     })
-                     .count();
+        .take_while(|x| {
+            x.default.is_none() &&
+                !ty::is_associated_type(tcx, x.def_id)
+        })
+        .count();
     if supplied_ty_param_count < required_ty_param_count {
         let expected = if required_ty_param_count < formal_ty_param_count {
             "expected at least"
@@ -282,10 +289,10 @@ fn ast_path_substs<'tcx,AC,RS>(
             "expected"
         };
         this.tcx().sess.span_fatal(path.span,
-            format!("wrong number of type arguments: {} {}, found {}",
-                    expected,
-                    required_ty_param_count,
-                    supplied_ty_param_count).as_slice());
+                                   format!("wrong number of type arguments: {} {}, found {}",
+                                           expected,
+                                           required_ty_param_count,
+                                           supplied_ty_param_count).as_slice());
     } else if supplied_ty_param_count > formal_ty_param_count {
         let expected = if required_ty_param_count < formal_ty_param_count {
             "expected at most"
@@ -293,10 +300,10 @@ fn ast_path_substs<'tcx,AC,RS>(
             "expected"
         };
         this.tcx().sess.span_fatal(path.span,
-            format!("wrong number of type arguments: {} {}, found {}",
-                    expected,
-                    formal_ty_param_count,
-                    supplied_ty_param_count).as_slice());
+                                   format!("wrong number of type arguments: {} {}, found {}",
+                                           expected,
+                                           formal_ty_param_count,
+                                           supplied_ty_param_count).as_slice());
     }
 
     if supplied_ty_param_count > required_ty_param_count
@@ -307,13 +314,7 @@ fn ast_path_substs<'tcx,AC,RS>(
             "add #![feature(default_type_params)] to the crate attributes to enable");
     }
 
-    let tps = path.segments
-                  .iter()
-                  .flat_map(|s| s.types.iter())
-                  .map(|a_t| ast_ty_to_ty(this, rscope, &**a_t))
-                  .collect();
-
-    let mut substs = Substs::new_type(tps, regions);
+    let mut substs = Substs::new_type(types, regions);
 
     match self_ty {
         None => {
@@ -354,7 +355,47 @@ fn ast_path_substs<'tcx,AC,RS>(
                                          param.def_id))
     }
 
-    substs
+    return substs;
+
+    fn angle_bracketed_parameters<'tcx, AC, RS>(this: &AC,
+                                                rscope: &RS,
+                                                data: &ast::AngleBracketedParameterData)
+                                                -> (Vec<ty::Region>, Vec<ty::t>)
+        where AC: AstConv<'tcx>, RS: RegionScope
+    {
+        let regions: Vec<_> =
+            data.lifetimes.iter()
+            .map(|l| ast_region_to_region(this.tcx(), l))
+            .collect();
+
+        let types: Vec<_> =
+            data.types.iter()
+            .map(|t| ast_ty_to_ty(this, rscope, &**t))
+            .collect();
+
+        (regions, types)
+    }
+
+    fn parenthesized_parameters<'tcx,AC>(this: &AC,
+                                         binder_id: ast::NodeId,
+                                         data: &ast::ParenthesizedParameterData)
+                                         -> (Vec<ty::Region>, Vec<ty::t>)
+        where AC: AstConv<'tcx>
+    {
+        let binding_rscope = BindingRscope::new(binder_id);
+
+        let inputs = data.inputs.iter()
+                                .map(|a_t| ast_ty_to_ty(this, &binding_rscope, &**a_t))
+                                .collect();
+        let input_ty = ty::mk_tup_or_nil(this.tcx(), inputs);
+
+        let output = match data.output {
+            Some(ref output_ty) => ast_ty_to_ty(this, &binding_rscope, &**output_ty),
+            None => ty::mk_nil()
+        };
+
+        (Vec::new(), vec![input_ty, output])
+    }
 }
 
 pub fn ast_path_to_trait_ref<'tcx,AC,RS>(this: &AC,
@@ -362,7 +403,8 @@ pub fn ast_path_to_trait_ref<'tcx,AC,RS>(this: &AC,
                                          trait_def_id: ast::DefId,
                                          self_ty: Option<ty::t>,
                                          associated_type: Option<ty::t>,
-                                         path: &ast::Path)
+                                         path: &ast::Path,
+                                         binder_id: ast::NodeId)
                                          -> Rc<ty::TraitRef>
                                          where AC: AstConv<'tcx>,
                                                RS: RegionScope {
@@ -375,7 +417,8 @@ pub fn ast_path_to_trait_ref<'tcx,AC,RS>(this: &AC,
                                 &trait_def.generics,
                                 self_ty,
                                 associated_type,
-                                path)
+                                path,
+                                binder_id)
     })
 }
 
@@ -383,8 +426,10 @@ pub fn ast_path_to_ty<'tcx, AC: AstConv<'tcx>, RS: RegionScope>(
     this: &AC,
     rscope: &RS,
     did: ast::DefId,
-    path: &ast::Path)
-    -> TypeAndSubsts {
+    path: &ast::Path,
+    binder_id: ast::NodeId)
+    -> TypeAndSubsts
+{
     let tcx = this.tcx();
     let ty::Polytype {
         generics,
@@ -397,7 +442,8 @@ pub fn ast_path_to_ty<'tcx, AC: AstConv<'tcx>, RS: RegionScope>(
                                  &generics,
                                  None,
                                  None,
-                                 path);
+                                 path,
+                                 binder_id);
     let ty = decl_ty.subst(tcx, &substs);
     TypeAndSubsts { substs: substs, ty: ty }
 }
@@ -407,24 +453,29 @@ pub fn ast_path_to_ty<'tcx, AC: AstConv<'tcx>, RS: RegionScope>(
 /// and/or region variables are substituted.
 ///
 /// This is used when checking the constructor in struct literals.
-pub fn ast_path_to_ty_relaxed<'tcx, AC: AstConv<'tcx>,
-                              RS:RegionScope>(
-                              this: &AC,
-                              rscope: &RS,
-                              did: ast::DefId,
-                              path: &ast::Path)
-                              -> TypeAndSubsts {
+pub fn ast_path_to_ty_relaxed<'tcx,AC,RS>(
+    this: &AC,
+    rscope: &RS,
+    did: ast::DefId,
+    path: &ast::Path,
+    binder_id: ast::NodeId)
+    -> TypeAndSubsts
+    where AC : AstConv<'tcx>, RS : RegionScope
+{
     let tcx = this.tcx();
     let ty::Polytype {
         generics,
         ty: decl_ty
     } = this.get_item_ty(did);
 
-    let substs = if (generics.has_type_params(TypeSpace) ||
-        generics.has_region_params(TypeSpace)) &&
-            path.segments.iter().all(|s| {
-                s.lifetimes.len() == 0 && s.types.len() == 0
-            }) {
+    let wants_params =
+        generics.has_type_params(TypeSpace) || generics.has_region_params(TypeSpace);
+
+    let needs_defaults =
+        wants_params &&
+        path.segments.iter().all(|s| s.parameters.is_empty());
+
+    let substs = if needs_defaults {
         let type_params = Vec::from_fn(generics.types.len(TypeSpace),
                                        |_| this.ty_infer(path.span));
         let region_params =
@@ -433,7 +484,7 @@ pub fn ast_path_to_ty_relaxed<'tcx, AC: AstConv<'tcx>,
         Substs::new(VecPerParamSpace::params_from_type(type_params),
                     VecPerParamSpace::params_from_type(region_params))
     } else {
-        ast_path_substs(this, rscope, did, &generics, None, None, path)
+        ast_path_substs(this, rscope, did, &generics, None, None, path, binder_id)
     };
 
     let ty = decl_ty.subst(tcx, &substs);
@@ -450,14 +501,14 @@ fn check_path_args(tcx: &ty::ctxt,
                    path: &ast::Path,
                    flags: uint) {
     if (flags & NO_TPS) != 0u {
-        if !path.segments.iter().all(|s| s.types.is_empty()) {
+        if path.segments.iter().any(|s| s.parameters.has_types()) {
             span_err!(tcx.sess, path.span, E0109,
                 "type parameters are not allowed on this type");
         }
     }
 
     if (flags & NO_REGIONS) != 0u {
-        if !path.segments.last().unwrap().lifetimes.is_empty() {
+        if path.segments.iter().any(|s| s.parameters.has_lifetimes()) {
             span_err!(tcx.sess, path.span, E0110,
                 "region parameters are not allowed on this type");
         }
@@ -538,29 +589,23 @@ pub fn ast_ty_to_builtin_ty<'tcx, AC: AstConv<'tcx>, RS: RegionScope>(
             // FIXME(#12938): This is a hack until we have full support for
             // DST.
             match a_def {
-                def::DefTy(did, _) | def::DefStruct(did)
-                        if Some(did) == this.tcx().lang_items.owned_box() => {
-                    if path.segments
-                           .iter()
-                           .flat_map(|s| s.types.iter())
-                           .count() > 1 {
-                        span_err!(this.tcx().sess, path.span, E0047,
-                                  "`Box` has only one type parameter");
-                    }
-
-                    for inner_ast_type in path.segments
-                                              .iter()
-                                              .flat_map(|s| s.types.iter()) {
-                        return Some(mk_pointer(this,
-                                               rscope,
-                                               ast::MutImmutable,
-                                               &**inner_ast_type,
-                                               Uniq,
-                                               |typ| ty::mk_uniq(this.tcx(), typ)));
+                def::DefTy(did, _) |
+                def::DefStruct(did) if Some(did) == this.tcx().lang_items.owned_box() => {
+                    let ty = ast_path_to_ty(this, rscope, did, path, id).ty;
+                    match ty::get(ty).sty {
+                        ty::ty_struct(struct_def_id, ref substs) => {
+                            assert_eq!(struct_def_id, did);
+                            assert_eq!(substs.types.len(TypeSpace), 1);
+                            let referent_ty = *substs.types.get(TypeSpace, 0);
+                            Some(ty::mk_uniq(this.tcx(), referent_ty))
+                        }
+                        _ => {
+                            this.tcx().sess.span_bug(
+                                path.span,
+                                format!("converting `Box` to `{}`",
+                                        ty.repr(this.tcx()))[]);
+                        }
                     }
-                    span_err!(this.tcx().sess, path.span, E0113,
-                              "not enough type parameters supplied to `Box<T>`");
-                    Some(ty::mk_err())
                 }
                 _ => None
             }
@@ -575,15 +620,6 @@ enum PointerTy {
     Uniq
 }
 
-impl PointerTy {
-    fn default_region(&self) -> ty::Region {
-        match *self {
-            Uniq => ty::ReStatic,
-            RPtr(r) => r,
-        }
-    }
-}
-
 pub fn trait_ref_for_unboxed_function<'tcx, AC: AstConv<'tcx>,
                                       RS:RegionScope>(
                                       this: &AC,
@@ -603,11 +639,7 @@ pub fn trait_ref_for_unboxed_function<'tcx, AC: AstConv<'tcx>,
                           .map(|input| {
                             ast_ty_to_ty(this, rscope, &*input.ty)
                           }).collect::<Vec<_>>();
-    let input_tuple = if input_types.len() == 0 {
-        ty::mk_nil()
-    } else {
-        ty::mk_tup(this.tcx(), input_types)
-    };
+    let input_tuple = ty::mk_tup_or_nil(this.tcx(), input_types);
     let output_type = ast_ty_to_ty(this, rscope, &*decl.output);
     let mut substs = Substs::new_type(vec!(input_tuple, output_type),
                                       Vec::new());
@@ -646,31 +678,6 @@ fn mk_pointer<'tcx, AC: AstConv<'tcx>, RS: RegionScope>(
             let ty = ast_ty_to_ty(this, rscope, &**ty);
             return constr(ty::mk_vec(tcx, ty, None));
         }
-        ast::TyUnboxedFn(ref unboxed_function) => {
-            let ty::TraitRef {
-                def_id,
-                substs
-            } = trait_ref_for_unboxed_function(this,
-                                               rscope,
-                                               unboxed_function.kind,
-                                               &*unboxed_function.decl,
-                                               None);
-            let r = ptr_ty.default_region();
-            let tr = ty::mk_trait(this.tcx(),
-                                  def_id,
-                                  substs,
-                                  ty::region_existential_bound(r));
-            match ptr_ty {
-                Uniq => {
-                    return ty::mk_uniq(this.tcx(), tr);
-                }
-                RPtr(r) => {
-                    return ty::mk_rptr(this.tcx(),
-                                       r,
-                                       ty::mt {mutbl: a_seq_mutbl, ty: tr});
-                }
-            }
-        }
         ast::TyPath(ref path, ref opt_bounds, id) => {
             // Note that the "bounds must be empty if path is not a trait"
             // restriction is enforced in the below case for ty_path, which
@@ -693,7 +700,8 @@ fn mk_pointer<'tcx, AC: AstConv<'tcx>, RS: RegionScope>(
                                                        trait_def_id,
                                                        None,
                                                        None,
-                                                       path);
+                                                       path,
+                                                       id);
                     let bounds = match *opt_bounds {
                         None => {
                             conv_existential_bounds(this,
@@ -771,7 +779,12 @@ fn associated_ty_to_ty<'tcx,AC,RS>(this: &AC,
                                           trait_did,
                                           None,
                                           Some(for_type),
-                                          trait_path);
+                                          trait_path,
+                                          ast::DUMMY_NODE_ID); // *see below
+
+    // * The trait in a qualified path cannot be "higher-ranked" and
+    // hence cannot use the parenthetical sugar, so the binder-id is
+    // irrelevant.
 
     debug!("associated_ty_to_ty(trait_ref={})",
            trait_ref.repr(this.tcx()));
@@ -894,11 +907,6 @@ pub fn ast_ty_to_ty<'tcx, AC: AstConv<'tcx>, RS: RegionScope>(
 
                 ty::mk_closure(tcx, fn_decl)
             }
-            ast::TyUnboxedFn(..) => {
-                tcx.sess.span_err(ast_ty.span,
-                                  "cannot use unboxed functions here");
-                ty::mk_err()
-            }
             ast::TyPath(ref path, ref bounds, id) => {
                 let a_def = match tcx.def_map.borrow().get(&id) {
                     None => {
@@ -925,7 +933,8 @@ pub fn ast_ty_to_ty<'tcx, AC: AstConv<'tcx>, RS: RegionScope>(
                                                            trait_def_id,
                                                            None,
                                                            None,
-                                                           path);
+                                                           path,
+                                                           id);
                         let empty_bounds: &[ast::TyParamBound] = &[];
                         let ast_bounds = match *bounds {
                             Some(ref b) => b.as_slice(),
@@ -942,7 +951,7 @@ pub fn ast_ty_to_ty<'tcx, AC: AstConv<'tcx>, RS: RegionScope>(
                                      bounds)
                     }
                     def::DefTy(did, _) | def::DefStruct(did) => {
-                        ast_path_to_ty(this, rscope, did, path).ty
+                        ast_path_to_ty(this, rscope, did, path, id).ty
                     }
                     def::DefTyParam(space, id, n) => {
                         check_path_args(tcx, path, NO_TPS | NO_REGIONS);
@@ -1377,8 +1386,7 @@ pub fn conv_existential_bounds<'tcx, AC: AstConv<'tcx>, RS:RegionScope>(
 
     let PartitionedBounds { builtin_bounds,
                             trait_bounds,
-                            region_bounds,
-                            unboxed_fn_ty_bounds } =
+                            region_bounds } =
         partition_bounds(this.tcx(), span, ast_bound_refs.as_slice());
 
     if !trait_bounds.is_empty() {
@@ -1389,13 +1397,6 @@ pub fn conv_existential_bounds<'tcx, AC: AstConv<'tcx>, RS:RegionScope>(
                      as closure or object bounds").as_slice());
     }
 
-    if !unboxed_fn_ty_bounds.is_empty() {
-        this.tcx().sess.span_err(
-            span,
-            format!("only the builtin traits can be used \
-                     as closure or object bounds").as_slice());
-    }
-
     // The "main trait refs", rather annoyingly, have no type
     // specified for the `Self` parameter of the trait. The reason for
     // this is that they are, after all, *existential* types, and
@@ -1524,7 +1525,6 @@ fn compute_region_bound<'tcx, AC: AstConv<'tcx>, RS:RegionScope>(
 pub struct PartitionedBounds<'a> {
     pub builtin_bounds: ty::BuiltinBounds,
     pub trait_bounds: Vec<&'a ast::TraitRef>,
-    pub unboxed_fn_ty_bounds: Vec<&'a ast::UnboxedFnBound>,
     pub region_bounds: Vec<&'a ast::Lifetime>,
 }
 
@@ -1542,7 +1542,6 @@ pub fn partition_bounds<'a>(tcx: &ty::ctxt,
     let mut builtin_bounds = ty::empty_builtin_bounds();
     let mut region_bounds = Vec::new();
     let mut trait_bounds = Vec::new();
-    let mut unboxed_fn_ty_bounds = Vec::new();
     let mut trait_def_ids = HashMap::new();
     for &ast_bound in ast_bounds.iter() {
         match *ast_bound {
@@ -1587,9 +1586,6 @@ pub fn partition_bounds<'a>(tcx: &ty::ctxt,
             ast::RegionTyParamBound(ref l) => {
                 region_bounds.push(l);
             }
-            ast::UnboxedFnTyParamBound(ref unboxed_function) => {
-                unboxed_fn_ty_bounds.push(&**unboxed_function);
-            }
         }
     }
 
@@ -1597,7 +1593,6 @@ pub fn partition_bounds<'a>(tcx: &ty::ctxt,
         builtin_bounds: builtin_bounds,
         trait_bounds: trait_bounds,
         region_bounds: region_bounds,
-        unboxed_fn_ty_bounds: unboxed_fn_ty_bounds
     }
 }
 
diff --git a/src/librustc/middle/typeck/check/mod.rs b/src/librustc/middle/typeck/check/mod.rs
index b83c81cd986..ccd6a8103b9 100644
--- a/src/librustc/middle/typeck/check/mod.rs
+++ b/src/librustc/middle/typeck/check/mod.rs
@@ -3481,11 +3481,7 @@ fn check_expr_with_unifier(fcx: &FnCtxt,
 
         // Tuple up the arguments and insert the resulting function type into
         // the `unboxed_closures` table.
-        fn_ty.sig.inputs = if fn_ty.sig.inputs.len() == 0 {
-            vec![ty::mk_nil()]
-        } else {
-            vec![ty::mk_tup(fcx.tcx(), fn_ty.sig.inputs)]
-        };
+        fn_ty.sig.inputs = vec![ty::mk_tup_or_nil(fcx.tcx(), fn_ty.sig.inputs)];
 
         let kind = match kind {
             ast::FnUnboxedClosureKind => ty::FnUnboxedClosureKind,
@@ -4478,7 +4474,8 @@ fn check_expr_with_unifier(fcx: &FnCtxt,
             let type_and_substs = astconv::ast_path_to_ty_relaxed(fcx,
                                                                   fcx.infcx(),
                                                                   struct_id,
-                                                                  path);
+                                                                  path,
+                                                                  expr.id);
             match fcx.mk_subty(false,
                                infer::Misc(path.span),
                                actual_structure_type,
@@ -5339,6 +5336,7 @@ pub fn instantiate_path(fcx: &FnCtxt,
             Some(space) => {
                 push_explicit_parameters_from_segment_to_substs(fcx,
                                                                 space,
+                                                                path.span,
                                                                 type_defs,
                                                                 region_defs,
                                                                 segment,
@@ -5374,13 +5372,13 @@ pub fn instantiate_path(fcx: &FnCtxt,
         fcx: &FnCtxt,
         segment: &ast::PathSegment)
     {
-        for typ in segment.types.iter() {
+        for typ in segment.parameters.types().iter() {
             span_err!(fcx.tcx().sess, typ.span, E0085,
                 "type parameters may not appear here");
             break;
         }
 
-        for lifetime in segment.lifetimes.iter() {
+        for lifetime in segment.parameters.lifetimes().iter() {
             span_err!(fcx.tcx().sess, lifetime.span, E0086,
                 "lifetime parameters may not appear here");
             break;
@@ -5390,6 +5388,7 @@ pub fn instantiate_path(fcx: &FnCtxt,
     fn push_explicit_parameters_from_segment_to_substs(
         fcx: &FnCtxt,
         space: subst::ParamSpace,
+        span: Span,
         type_defs: &VecPerParamSpace<ty::TypeParameterDef>,
         region_defs: &VecPerParamSpace<ty::RegionParameterDef>,
         segment: &ast::PathSegment,
@@ -5412,10 +5411,31 @@ pub fn instantiate_path(fcx: &FnCtxt,
          * span of the N+1'th parameter.
          */
 
+        match segment.parameters {
+            ast::AngleBracketedParameters(ref data) => {
+                push_explicit_angle_bracketed_parameters_from_segment_to_substs(
+                    fcx, space, type_defs, region_defs, data, substs);
+            }
+
+            ast::ParenthesizedParameters(ref data) => {
+                push_explicit_parenthesized_parameters_from_segment_to_substs(
+                    fcx, space, span, type_defs, data, substs);
+            }
+        }
+    }
+
+    fn push_explicit_angle_bracketed_parameters_from_segment_to_substs(
+        fcx: &FnCtxt,
+        space: subst::ParamSpace,
+        type_defs: &VecPerParamSpace<ty::TypeParameterDef>,
+        region_defs: &VecPerParamSpace<ty::RegionParameterDef>,
+        data: &ast::AngleBracketedParameterData,
+        substs: &mut Substs)
+    {
         {
             let type_count = type_defs.len(space);
             assert_eq!(substs.types.len(space), 0);
-            for (i, typ) in segment.types.iter().enumerate() {
+            for (i, typ) in data.types.iter().enumerate() {
                 let t = fcx.to_ty(&**typ);
                 if i < type_count {
                     substs.types.push(space, t);
@@ -5424,7 +5444,7 @@ pub fn instantiate_path(fcx: &FnCtxt,
                         "too many type parameters provided: \
                          expected at most {} parameter(s), \
                          found {} parameter(s)",
-                         type_count, segment.types.len());
+                         type_count, data.types.len());
                     substs.types.truncate(space, 0);
                 }
             }
@@ -5433,7 +5453,7 @@ pub fn instantiate_path(fcx: &FnCtxt,
         {
             let region_count = region_defs.len(space);
             assert_eq!(substs.regions().len(space), 0);
-            for (i, lifetime) in segment.lifetimes.iter().enumerate() {
+            for (i, lifetime) in data.lifetimes.iter().enumerate() {
                 let r = ast_region_to_region(fcx.tcx(), lifetime);
                 if i < region_count {
                     substs.mut_regions().push(space, r);
@@ -5442,13 +5462,59 @@ pub fn instantiate_path(fcx: &FnCtxt,
                         "too many lifetime parameters provided: \
                          expected {} parameter(s), found {} parameter(s)",
                         region_count,
-                        segment.lifetimes.len());
+                        data.lifetimes.len());
                     substs.mut_regions().truncate(space, 0);
                 }
             }
         }
     }
 
+    fn push_explicit_parenthesized_parameters_from_segment_to_substs(
+        fcx: &FnCtxt,
+        space: subst::ParamSpace,
+        span: Span,
+        type_defs: &VecPerParamSpace<ty::TypeParameterDef>,
+        data: &ast::ParenthesizedParameterData,
+        substs: &mut Substs)
+    {
+        /*!
+         * As with
+         * `push_explicit_angle_bracketed_parameters_from_segment_to_substs`,
+         * but intended for `Foo(A,B) -> C` form. This expands to
+         * roughly the same thing as `Foo<(A,B),C>`. One important
+         * difference has to do with the treatment of anonymous
+         * regions, which are translated into bound regions (NYI).
+         */
+
+        let type_count = type_defs.len(space);
+        if type_count < 2 {
+            span_err!(fcx.tcx().sess, span, E0167,
+                      "parenthesized form always supplies 2 type parameters, \
+                      but only {} parameter(s) were expected",
+                      type_count);
+        }
+
+        let input_tys: Vec<ty::t> =
+            data.inputs.iter().map(|ty| fcx.to_ty(&**ty)).collect();
+
+        let tuple_ty =
+            ty::mk_tup_or_nil(fcx.tcx(), input_tys);
+
+        if type_count >= 1 {
+            substs.types.push(space, tuple_ty);
+        }
+
+        let output_ty: Option<ty::t> =
+            data.output.as_ref().map(|ty| fcx.to_ty(&**ty));
+
+        let output_ty =
+            output_ty.unwrap_or(ty::mk_nil());
+
+        if type_count >= 2 {
+            substs.types.push(space, output_ty);
+        }
+    }
+
     fn adjust_type_parameters(
         fcx: &FnCtxt,
         span: Span,
diff --git a/src/librustc/middle/typeck/collect.rs b/src/librustc/middle/typeck/collect.rs
index d137e5536a5..ae2073f6316 100644
--- a/src/librustc/middle/typeck/collect.rs
+++ b/src/librustc/middle/typeck/collect.rs
@@ -638,7 +638,7 @@ pub fn ensure_no_ty_param_bounds(ccx: &CrateCtxt,
         let mut bounds = bounds.chain(ty_param.unbound.iter());
         for bound in bounds {
             match *bound {
-                ast::TraitTyParamBound(..) | ast::UnboxedFnTyParamBound(..) => {
+                ast::TraitTyParamBound(..) => {
                     // According to accepted RFC #XXX, we should
                     // eventually accept these, but it will not be
                     // part of this PR. Still, convert to warning to
@@ -1340,7 +1340,8 @@ pub fn instantiate_trait_ref<'tcx,AC>(this: &AC,
                                                trait_did,
                                                Some(self_ty),
                                                associated_type,
-                                               &ast_trait_ref.path);
+                                               &ast_trait_ref.path,
+                                               ast_trait_ref.ref_id);
 
             this.tcx().trait_refs.borrow_mut().insert(ast_trait_ref.ref_id,
                                                       trait_ref.clone());
@@ -1355,20 +1356,6 @@ pub fn instantiate_trait_ref<'tcx,AC>(this: &AC,
     }
 }
 
-pub fn instantiate_unboxed_fn_ty<'tcx,AC>(this: &AC,
-                                          unboxed_function: &ast::UnboxedFnTy,
-                                          param_ty: ty::ParamTy)
-                                          -> Rc<ty::TraitRef>
-                                          where AC: AstConv<'tcx> {
-    let rscope = ExplicitRscope;
-    let param_ty = param_ty.to_ty(this.tcx());
-    Rc::new(astconv::trait_ref_for_unboxed_function(this,
-                                                    &rscope,
-                                                    unboxed_function.kind,
-                                                    &*unboxed_function.decl,
-                                                    Some(param_ty)))
-}
-
 fn get_trait_def(ccx: &CrateCtxt, trait_id: ast::DefId) -> Rc<ty::TraitDef> {
     if trait_id.krate != ast::LOCAL_CRATE {
         return ty::lookup_trait_def(ccx.tcx, trait_id)
@@ -1878,7 +1865,6 @@ fn ty_generics<'tcx,AC>(this: &AC,
                 // In the above example, `ast_trait_ref` is `Iterator`.
                 let ast_trait_ref = match *bound {
                     ast::TraitTyParamBound(ref r) => r,
-                    ast::UnboxedFnTyParamBound(..) => { continue; }
                     ast::RegionTyParamBound(..) => { continue; }
                 };
 
@@ -2056,45 +2042,8 @@ fn conv_param_bounds<'tcx,AC>(this: &AC,
         merge_param_bounds(this.tcx(), param_ty, ast_bounds, where_clause);
     let astconv::PartitionedBounds { builtin_bounds,
                                      trait_bounds,
-                                     region_bounds,
-                                     unboxed_fn_ty_bounds } =
+                                     region_bounds } =
         astconv::partition_bounds(this.tcx(), span, all_bounds.as_slice());
-
-    let unboxed_fn_ty_bounds = unboxed_fn_ty_bounds.into_iter().map(|b| {
-        let trait_id = (*this.tcx().def_map.borrow())[b.ref_id].def_id();
-        let mut kind = None;
-        for &(lang_item, this_kind) in [
-            (this.tcx().lang_items.fn_trait(), ast::FnUnboxedClosureKind),
-            (this.tcx().lang_items.fn_mut_trait(),
-             ast::FnMutUnboxedClosureKind),
-            (this.tcx().lang_items.fn_once_trait(),
-             ast::FnOnceUnboxedClosureKind)
-        ].iter() {
-            if Some(trait_id) == lang_item {
-                kind = Some(this_kind);
-                break
-            }
-        }
-
-        let kind = match kind {
-            Some(kind) => kind,
-            None => {
-                this.tcx().sess.span_err(b.path.span,
-                                         "unboxed function trait must be one \
-                                          of `Fn`, `FnMut`, or `FnOnce`");
-                ast::FnMutUnboxedClosureKind
-            }
-        };
-
-        let rscope = ExplicitRscope;
-        let param_ty = param_ty.to_ty(this.tcx());
-        Rc::new(astconv::trait_ref_for_unboxed_function(this,
-                                                        &rscope,
-                                                        kind,
-                                                        &*b.decl,
-                                                        Some(param_ty)))
-    });
-
     let trait_bounds: Vec<Rc<ty::TraitRef>> =
         trait_bounds.into_iter()
         .map(|b| {
@@ -2103,7 +2052,6 @@ fn conv_param_bounds<'tcx,AC>(this: &AC,
                                   param_ty.to_ty(this.tcx()),
                                   Some(param_ty.to_ty(this.tcx())))
         })
-        .chain(unboxed_fn_ty_bounds)
         .collect();
     let region_bounds: Vec<ty::Region> =
         region_bounds.into_iter()
diff --git a/src/librustc/middle/typeck/infer/error_reporting.rs b/src/librustc/middle/typeck/infer/error_reporting.rs
index 20c14580b3b..4ca62253467 100644
--- a/src/librustc/middle/typeck/infer/error_reporting.rs
+++ b/src/librustc/middle/typeck/infer/error_reporting.rs
@@ -1102,13 +1102,11 @@ impl<'a, 'tcx> Rebuilder<'a, 'tcx> {
                     // be passing down a map.
                     ast::RegionTyParamBound(lt)
                 }
-                &ast::UnboxedFnTyParamBound(ref unboxed_function_type) => {
-                    ast::UnboxedFnTyParamBound((*unboxed_function_type).clone())
-                }
                 &ast::TraitTyParamBound(ref tr) => {
                     let last_seg = tr.path.segments.last().unwrap();
                     let mut insert = Vec::new();
-                    for (i, lt) in last_seg.lifetimes.iter().enumerate() {
+                    let lifetimes = last_seg.parameters.lifetimes();
+                    for (i, lt) in lifetimes.iter().enumerate() {
                         if region_names.contains(&lt.name) {
                             insert.push(i);
                         }
@@ -1116,7 +1114,7 @@ impl<'a, 'tcx> Rebuilder<'a, 'tcx> {
                     let rebuild_info = RebuildPathInfo {
                         path: &tr.path,
                         indexes: insert,
-                        expected: last_seg.lifetimes.len(),
+                        expected: lifetimes.len(),
                         anon_nums: &HashSet::new(),
                         region_names: region_names
                     };
@@ -1257,7 +1255,7 @@ impl<'a, 'tcx> Rebuilder<'a, 'tcx> {
                             let expected =
                                 generics.regions.len(subst::TypeSpace);
                             let lifetimes =
-                                &path.segments.last().unwrap().lifetimes;
+                                path.segments.last().unwrap().parameters.lifetimes();
                             let mut insert = Vec::new();
                             if lifetimes.len() == 0 {
                                 let anon = self.cur_anon.get();
@@ -1357,7 +1355,8 @@ impl<'a, 'tcx> Rebuilder<'a, 'tcx> {
     fn rebuild_path(&self,
                     rebuild_info: RebuildPathInfo,
                     lifetime: ast::Lifetime)
-                    -> ast::Path {
+                    -> ast::Path
+    {
         let RebuildPathInfo {
             path,
             indexes,
@@ -1367,37 +1366,48 @@ impl<'a, 'tcx> Rebuilder<'a, 'tcx> {
         } = rebuild_info;
 
         let last_seg = path.segments.last().unwrap();
-        let mut new_lts = Vec::new();
-        if last_seg.lifetimes.len() == 0 {
-            // traverse once to see if there's a need to insert lifetime
-            let need_insert = range(0, expected).any(|i| {
-                indexes.contains(&i)
-            });
-            if need_insert {
-                for i in range(0, expected) {
-                    if indexes.contains(&i) {
-                        new_lts.push(lifetime);
-                    } else {
-                        new_lts.push(self.life_giver.give_lifetime());
+        let new_parameters = match last_seg.parameters {
+            ast::ParenthesizedParameters(..) => {
+                last_seg.parameters.clone()
+            }
+
+            ast::AngleBracketedParameters(ref data) => {
+                let mut new_lts = Vec::new();
+                if data.lifetimes.len() == 0 {
+                    // traverse once to see if there's a need to insert lifetime
+                    let need_insert = range(0, expected).any(|i| {
+                        indexes.contains(&i)
+                    });
+                    if need_insert {
+                        for i in range(0, expected) {
+                            if indexes.contains(&i) {
+                                new_lts.push(lifetime);
+                            } else {
+                                new_lts.push(self.life_giver.give_lifetime());
+                            }
+                        }
                     }
-                }
-            }
-        } else {
-            for (i, lt) in last_seg.lifetimes.iter().enumerate() {
-                if indexes.contains(&i) {
-                    new_lts.push(lifetime);
                 } else {
-                    new_lts.push(*lt);
+                    for (i, lt) in data.lifetimes.iter().enumerate() {
+                        if indexes.contains(&i) {
+                            new_lts.push(lifetime);
+                        } else {
+                            new_lts.push(*lt);
+                        }
+                    }
                 }
+                let new_types = data.types.map(|t| {
+                    self.rebuild_arg_ty_or_output(&**t, lifetime, anon_nums, region_names)
+                });
+                ast::AngleBracketedParameters(ast::AngleBracketedParameterData {
+                    lifetimes: new_lts,
+                    types: new_types
+                })
             }
-        }
-        let new_types = last_seg.types.map(|t| {
-            self.rebuild_arg_ty_or_output(&**t, lifetime, anon_nums, region_names)
-        });
+        };
         let new_seg = ast::PathSegment {
             identifier: last_seg.identifier,
-            lifetimes: new_lts,
-            types: new_types,
+            parameters: new_parameters
         };
         let mut new_segs = Vec::new();
         new_segs.push_all(path.segments.init());
diff --git a/src/librustdoc/clean/inline.rs b/src/librustdoc/clean/inline.rs
index 545eeaf7406..bcbd09d7b11 100644
--- a/src/librustdoc/clean/inline.rs
+++ b/src/librustdoc/clean/inline.rs
@@ -323,7 +323,6 @@ fn build_impl(cx: &DocContext, tcx: &ty::ctxt,
             trait_: associated_trait.clean(cx).map(|bound| {
                 match bound {
                     clean::TraitBound(ty) => ty,
-                    clean::UnboxedFnBound(..) |
                     clean::RegionBound(..) => unreachable!(),
                 }
             }),
diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs
index bd6c696ad74..4478c29f66a 100644
--- a/src/librustdoc/clean/mod.rs
+++ b/src/librustdoc/clean/mod.rs
@@ -476,7 +476,6 @@ impl Clean<TyParam> for ty::TypeParameterDef {
 #[deriving(Clone, Encodable, Decodable, PartialEq)]
 pub enum TyParamBound {
     RegionBound(Lifetime),
-    UnboxedFnBound(UnboxedFnType),
     TraitBound(Type)
 }
 
@@ -484,7 +483,6 @@ impl Clean<TyParamBound> for ast::TyParamBound {
     fn clean(&self, cx: &DocContext) -> TyParamBound {
         match *self {
             ast::RegionTyParamBound(lt) => RegionBound(lt.clean(cx)),
-            ast::UnboxedFnTyParamBound(ref ty) => { UnboxedFnBound(ty.clean(cx)) },
             ast::TraitTyParamBound(ref t) => TraitBound(t.clean(cx)),
         }
     }
@@ -600,21 +598,6 @@ impl Clean<Option<Vec<TyParamBound>>> for subst::Substs {
 }
 
 #[deriving(Clone, Encodable, Decodable, PartialEq)]
-pub struct UnboxedFnType {
-    pub path: Path,
-    pub decl: FnDecl
-}
-
-impl Clean<UnboxedFnType> for ast::UnboxedFnBound {
-    fn clean(&self, cx: &DocContext) -> UnboxedFnType {
-        UnboxedFnType {
-            path: self.path.clean(cx),
-            decl: self.decl.clean(cx)
-        }
-    }
-}
-
-#[deriving(Clone, Encodable, Decodable, PartialEq)]
 pub struct Lifetime(String);
 
 impl Lifetime {
@@ -1641,10 +1624,23 @@ pub struct PathSegment {
 
 impl Clean<PathSegment> for ast::PathSegment {
     fn clean(&self, cx: &DocContext) -> PathSegment {
+        let (lifetimes, types) = match self.parameters {
+            ast::AngleBracketedParameters(ref data) => {
+                (data.lifetimes.clean(cx), data.types.clean(cx))
+            }
+
+            ast::ParenthesizedParameters(ref data) => {
+                // FIXME -- rustdoc should be taught about Foo() notation
+                let inputs = Tuple(data.inputs.clean(cx));
+                let output = data.output.as_ref().map(|t| t.clean(cx)).unwrap_or(Tuple(Vec::new()));
+                (Vec::new(), vec![inputs, output])
+            }
+        };
+
         PathSegment {
             name: self.identifier.clean(cx),
-            lifetimes: self.lifetimes.clean(cx),
-            types: self.types.clean(cx),
+            lifetimes: lifetimes,
+            types: types,
         }
     }
 }
diff --git a/src/librustdoc/html/format.rs b/src/librustdoc/html/format.rs
index 320f84adea7..fe96c9b3a9f 100644
--- a/src/librustdoc/html/format.rs
+++ b/src/librustdoc/html/format.rs
@@ -143,9 +143,6 @@ impl fmt::Show for clean::TyParamBound {
             clean::RegionBound(ref lt) => {
                 write!(f, "{}", *lt)
             }
-            clean::UnboxedFnBound(ref ty) => {
-                write!(f, "{}{}", ty.path, ty.decl)
-            }
             clean::TraitBound(ref ty) => {
                 write!(f, "{}", *ty)
             }
@@ -404,8 +401,7 @@ impl fmt::Show for clean::Type {
                            let mut ret = String::new();
                            for bound in decl.bounds.iter() {
                                 match *bound {
-                                    clean::RegionBound(..) |
-                                    clean::UnboxedFnBound(..) => {}
+                                    clean::RegionBound(..) => {}
                                     clean::TraitBound(ref t) => {
                                         if ret.len() == 0 {
                                             ret.push_str(": ");
diff --git a/src/libsyntax/ast.rs b/src/libsyntax/ast.rs
index 078e393eb28..6a354fa20e1 100644
--- a/src/libsyntax/ast.rs
+++ b/src/libsyntax/ast.rs
@@ -171,7 +171,7 @@ pub struct Path {
     /// module (like paths in an import).
     pub global: bool,
     /// The segments in the path: the things separated by `::`.
-    pub segments: Vec<PathSegment> ,
+    pub segments: Vec<PathSegment>,
 }
 
 /// A segment of a path: an identifier, an optional lifetime, and a set of
@@ -180,12 +180,107 @@ pub struct Path {
 pub struct PathSegment {
     /// The identifier portion of this path segment.
     pub identifier: Ident,
+
+    /// Type/lifetime parameters attached to this path. They come in
+    /// two flavors: `Path<A,B,C>` and `Path(A,B) -> C`. Note that
+    /// this is more than just simple syntactic sugar; the use of
+    /// parens affects the region binding rules, so we preserve the
+    /// distinction.
+    pub parameters: PathParameters,
+}
+
+#[deriving(Clone, PartialEq, Eq, Encodable, Decodable, Hash, Show)]
+pub enum PathParameters {
+    AngleBracketedParameters(AngleBracketedParameterData),
+    ParenthesizedParameters(ParenthesizedParameterData),
+}
+
+impl PathParameters {
+    pub fn none() -> PathParameters {
+        AngleBracketedParameters(AngleBracketedParameterData {
+            lifetimes: Vec::new(),
+            types: OwnedSlice::empty(),
+        })
+    }
+
+    pub fn is_empty(&self) -> bool {
+        match *self {
+            AngleBracketedParameters(ref data) => data.is_empty(),
+
+            // Even if the user supplied no types, something like
+            // `X()` is equivalent to `X<(),()>`.
+            ParenthesizedParameters(..) => false,
+        }
+    }
+
+    pub fn has_lifetimes(&self) -> bool {
+        match *self {
+            AngleBracketedParameters(ref data) => !data.lifetimes.is_empty(),
+            ParenthesizedParameters(_) => false,
+        }
+    }
+
+    pub fn has_types(&self) -> bool {
+        match *self {
+            AngleBracketedParameters(ref data) => !data.types.is_empty(),
+            ParenthesizedParameters(..) => true,
+        }
+    }
+
+    pub fn types(&self) -> Vec<&P<Ty>> {
+        /*!
+         * Returns the types that the user wrote. Note that these do not
+         * necessarily map to the type parameters in the parenthesized case.
+         */
+        match *self {
+            AngleBracketedParameters(ref data) => {
+                data.types.iter().collect()
+            }
+            ParenthesizedParameters(ref data) => {
+                data.inputs.iter()
+                    .chain(data.output.iter())
+                    .collect()
+            }
+        }
+    }
+
+    pub fn lifetimes(&self) -> Vec<&Lifetime> {
+        match *self {
+            AngleBracketedParameters(ref data) => {
+                data.lifetimes.iter().collect()
+            }
+            ParenthesizedParameters(_) => {
+                Vec::new()
+            }
+        }
+    }
+}
+
+/// A path like `Foo<'a, T>`
+#[deriving(Clone, PartialEq, Eq, Encodable, Decodable, Hash, Show)]
+pub struct AngleBracketedParameterData {
     /// The lifetime parameters for this path segment.
     pub lifetimes: Vec<Lifetime>,
     /// The type parameters for this path segment, if present.
     pub types: OwnedSlice<P<Ty>>,
 }
 
+impl AngleBracketedParameterData {
+    fn is_empty(&self) -> bool {
+        self.lifetimes.is_empty() && self.types.is_empty()
+    }
+}
+
+/// A path like `Foo(A,B) -> C`
+#[deriving(Clone, PartialEq, Eq, Encodable, Decodable, Hash, Show)]
+pub struct ParenthesizedParameterData {
+    /// `(A,B)`
+    pub inputs: Vec<P<Ty>>,
+
+    /// `C`
+    pub output: Option<P<Ty>>,
+}
+
 pub type CrateNum = u32;
 
 pub type NodeId = u32;
@@ -213,21 +308,12 @@ pub const DUMMY_NODE_ID: NodeId = -1;
 #[deriving(Clone, PartialEq, Eq, Encodable, Decodable, Hash, Show)]
 pub enum TyParamBound {
     TraitTyParamBound(TraitRef),
-    UnboxedFnTyParamBound(P<UnboxedFnBound>),
     RegionTyParamBound(Lifetime)
 }
 
 pub type TyParamBounds = OwnedSlice<TyParamBound>;
 
 #[deriving(Clone, PartialEq, Eq, Encodable, Decodable, Hash, Show)]
-pub struct UnboxedFnBound {
-    pub path: Path,
-    pub decl: P<FnDecl>,
-    pub lifetimes: Vec<LifetimeDef>,
-    pub ref_id: NodeId,
-}
-
-#[deriving(Clone, PartialEq, Eq, Encodable, Decodable, Hash, Show)]
 pub struct TyParam {
     pub ident: Ident,
     pub id: NodeId,
@@ -995,12 +1081,6 @@ pub struct BareFnTy {
 }
 
 #[deriving(Clone, PartialEq, Eq, Encodable, Decodable, Hash, Show)]
-pub struct UnboxedFnTy {
-    pub kind: UnboxedClosureKind,
-    pub decl: P<FnDecl>,
-}
-
-#[deriving(Clone, PartialEq, Eq, Encodable, Decodable, Hash, Show)]
 pub enum Ty_ {
     TyNil,
     TyBot, /* bottom type */
@@ -1012,7 +1092,6 @@ pub enum Ty_ {
     TyClosure(P<ClosureTy>),
     TyProc(P<ClosureTy>),
     TyBareFn(P<BareFnTy>),
-    TyUnboxedFn(P<UnboxedFnTy>),
     TyTup(Vec<P<Ty>> ),
     TyPath(Path, Option<TyParamBounds>, NodeId), // for #7264; see above
     /// A "qualified path", e.g. `<Vec<T> as SomeTrait>::SomeType`
diff --git a/src/libsyntax/ast_map/mod.rs b/src/libsyntax/ast_map/mod.rs
index f049b964ff3..3adb062864e 100644
--- a/src/libsyntax/ast_map/mod.rs
+++ b/src/libsyntax/ast_map/mod.rs
@@ -848,9 +848,6 @@ impl<'ast> Visitor<'ast> for NodeCollector<'ast> {
             TyBareFn(ref fd) => {
                 self.visit_fn_decl(&*fd.decl);
             }
-            TyUnboxedFn(ref fd) => {
-                self.visit_fn_decl(&*fd.decl);
-            }
             _ => {}
         }
         visit::walk_ty(self, ty);
diff --git a/src/libsyntax/ast_util.rs b/src/libsyntax/ast_util.rs
index 3aa60236d70..2e3a15bfd4b 100644
--- a/src/libsyntax/ast_util.rs
+++ b/src/libsyntax/ast_util.rs
@@ -171,8 +171,10 @@ pub fn ident_to_path(s: Span, identifier: Ident) -> Path {
         segments: vec!(
             ast::PathSegment {
                 identifier: identifier,
-                lifetimes: Vec::new(),
-                types: OwnedSlice::empty(),
+                parameters: ast::AngleBracketedParameters(ast::AngleBracketedParameterData {
+                    lifetimes: Vec::new(),
+                    types: OwnedSlice::empty(),
+                })
             }
         ),
     }
@@ -681,11 +683,11 @@ pub fn segments_name_eq(a : &[ast::PathSegment], b : &[ast::PathSegment]) -> boo
         false
     } else {
         for (idx,seg) in a.iter().enumerate() {
-            if (seg.identifier.name != b[idx].identifier.name)
+            if seg.identifier.name != b[idx].identifier.name
                 // FIXME #7743: ident -> name problems in lifetime comparison?
-                || (seg.lifetimes != b[idx].lifetimes)
                 // can types contain idents?
-                || (seg.types != b[idx].types) {
+                || seg.parameters != b[idx].parameters
+            {
                 return false;
             }
         }
@@ -747,12 +749,10 @@ impl PostExpansionMethod for Method {
 mod test {
     use ast::*;
     use super::*;
-    use owned_slice::OwnedSlice;
 
     fn ident_to_segment(id : &Ident) -> PathSegment {
-        PathSegment {identifier:id.clone(),
-                     lifetimes: Vec::new(),
-                     types: OwnedSlice::empty()}
+        PathSegment {identifier: id.clone(),
+                     parameters: PathParameters::none()}
     }
 
     #[test] fn idents_name_eq_test() {
diff --git a/src/libsyntax/ext/build.rs b/src/libsyntax/ext/build.rs
index dc4eaf7d7ad..5921d630b89 100644
--- a/src/libsyntax/ext/build.rs
+++ b/src/libsyntax/ext/build.rs
@@ -313,14 +313,15 @@ impl<'a> AstBuilder for ExtCtxt<'a> {
                                                       .map(|ident| {
             ast::PathSegment {
                 identifier: ident,
-                lifetimes: Vec::new(),
-                types: OwnedSlice::empty(),
+                parameters: ast::PathParameters::none(),
             }
         }).collect();
         segments.push(ast::PathSegment {
             identifier: last_identifier,
-            lifetimes: lifetimes,
-            types: OwnedSlice::from_vec(types),
+            parameters: ast::AngleBracketedParameters(ast::AngleBracketedParameterData {
+                lifetimes: lifetimes,
+                types: OwnedSlice::from_vec(types),
+            })
         });
         ast::Path {
             span: sp,
diff --git a/src/libsyntax/ext/concat_idents.rs b/src/libsyntax/ext/concat_idents.rs
index e5e93a7d8b3..aa18b1be31a 100644
--- a/src/libsyntax/ext/concat_idents.rs
+++ b/src/libsyntax/ext/concat_idents.rs
@@ -12,7 +12,6 @@ use ast;
 use codemap::Span;
 use ext::base::*;
 use ext::base;
-use owned_slice::OwnedSlice;
 use parse::token;
 use parse::token::{str_to_ident};
 use ptr::P;
@@ -52,8 +51,7 @@ pub fn expand_syntax_ext<'cx>(cx: &mut ExtCtxt, sp: Span, tts: &[ast::TokenTree]
                  segments: vec!(
                     ast::PathSegment {
                         identifier: res,
-                        lifetimes: Vec::new(),
-                        types: OwnedSlice::empty(),
+                        parameters: ast::PathParameters::none(),
                     }
                 )
             }
diff --git a/src/libsyntax/feature_gate.rs b/src/libsyntax/feature_gate.rs
index 7701f495f72..80b158a54d3 100644
--- a/src/libsyntax/feature_gate.rs
+++ b/src/libsyntax/feature_gate.rs
@@ -313,11 +313,6 @@ impl<'a, 'v> Visitor<'v> for Context<'a> {
                                    experimental and likely to be removed");
 
             },
-            ast::TyUnboxedFn(..) => {
-                self.gate_feature("unboxed_closure_sugar",
-                                  t.span,
-                                  "unboxed closure trait sugar is experimental");
-            }
             _ => {}
         }
 
diff --git a/src/libsyntax/fold.rs b/src/libsyntax/fold.rs
index 6535c8e89fd..cd4a3d10c48 100644
--- a/src/libsyntax/fold.rs
+++ b/src/libsyntax/fold.rs
@@ -166,6 +166,22 @@ pub trait Folder {
         noop_fold_path(p, self)
     }
 
+    fn fold_path_parameters(&mut self, p: PathParameters) -> PathParameters {
+        noop_fold_path_parameters(p, self)
+    }
+
+    fn fold_angle_bracketed_parameter_data(&mut self, p: AngleBracketedParameterData)
+                                           -> AngleBracketedParameterData
+    {
+        noop_fold_angle_bracketed_parameter_data(p, self)
+    }
+
+    fn fold_parenthesized_parameter_data(&mut self, p: ParenthesizedParameterData)
+                                         -> ParenthesizedParameterData
+    {
+        noop_fold_parenthesized_parameter_data(p, self)
+    }
+
     fn fold_local(&mut self, l: P<Local>) -> P<Local> {
         noop_fold_local(l, self)
     }
@@ -408,12 +424,6 @@ pub fn noop_fold_ty<T: Folder>(t: P<Ty>, fld: &mut T) -> P<Ty> {
                     decl: fld.fold_fn_decl(decl)
                 }))
             }
-            TyUnboxedFn(f) => {
-                TyUnboxedFn(f.map(|UnboxedFnTy {decl, kind}| UnboxedFnTy {
-                    decl: fld.fold_fn_decl(decl),
-                    kind: kind,
-                }))
-            }
             TyTup(tys) => TyTup(tys.move_map(|ty| fld.fold_ty(ty))),
             TyParen(ty) => TyParen(fld.fold_ty(ty)),
             TyPath(path, bounds, id) => {
@@ -480,15 +490,43 @@ pub fn noop_fold_uint<T: Folder>(i: uint, _: &mut T) -> uint {
 pub fn noop_fold_path<T: Folder>(Path {global, segments, span}: Path, fld: &mut T) -> Path {
     Path {
         global: global,
-        segments: segments.move_map(|PathSegment {identifier, lifetimes, types}| PathSegment {
+        segments: segments.move_map(|PathSegment {identifier, parameters}| PathSegment {
             identifier: fld.fold_ident(identifier),
-            lifetimes: fld.fold_lifetimes(lifetimes),
-            types: types.move_map(|typ| fld.fold_ty(typ)),
+            parameters: fld.fold_path_parameters(parameters),
         }),
         span: fld.new_span(span)
     }
 }
 
+pub fn noop_fold_path_parameters<T: Folder>(path_parameters: PathParameters, fld: &mut T)
+                                            -> PathParameters
+{
+    match path_parameters {
+        AngleBracketedParameters(data) =>
+            AngleBracketedParameters(fld.fold_angle_bracketed_parameter_data(data)),
+        ParenthesizedParameters(data) =>
+            ParenthesizedParameters(fld.fold_parenthesized_parameter_data(data)),
+    }
+}
+
+pub fn noop_fold_angle_bracketed_parameter_data<T: Folder>(data: AngleBracketedParameterData,
+                                                           fld: &mut T)
+                                                           -> AngleBracketedParameterData
+{
+    let AngleBracketedParameterData { lifetimes, types } = data;
+    AngleBracketedParameterData { lifetimes: fld.fold_lifetimes(lifetimes),
+                                  types: types.move_map(|ty| fld.fold_ty(ty)) }
+}
+
+pub fn noop_fold_parenthesized_parameter_data<T: Folder>(data: ParenthesizedParameterData,
+                                                         fld: &mut T)
+                                                         -> ParenthesizedParameterData
+{
+    let ParenthesizedParameterData { inputs, output } = data;
+    ParenthesizedParameterData { inputs: inputs.move_map(|ty| fld.fold_ty(ty)),
+                                 output: output.map(|ty| fld.fold_ty(ty)) }
+}
+
 pub fn noop_fold_local<T: Folder>(l: P<Local>, fld: &mut T) -> P<Local> {
     l.map(|Local {id, pat, ty, init, source, span}| Local {
         id: fld.new_id(id),
@@ -671,23 +709,6 @@ pub fn noop_fold_ty_param_bound<T>(tpb: TyParamBound, fld: &mut T)
     match tpb {
         TraitTyParamBound(ty) => TraitTyParamBound(fld.fold_trait_ref(ty)),
         RegionTyParamBound(lifetime) => RegionTyParamBound(fld.fold_lifetime(lifetime)),
-        UnboxedFnTyParamBound(bound) => {
-            match *bound {
-                UnboxedFnBound {
-                    ref path,
-                    ref decl,
-                    ref lifetimes,
-                    ref_id
-                } => {
-                    UnboxedFnTyParamBound(P(UnboxedFnBound {
-                        path: fld.fold_path(path.clone()),
-                        decl: fld.fold_fn_decl(decl.clone()),
-                        lifetimes: fld.fold_lifetime_defs(lifetimes.clone()),
-                        ref_id: fld.new_id(ref_id),
-                    }))
-                }
-            }
-        }
     }
 }
 
diff --git a/src/libsyntax/parse/mod.rs b/src/libsyntax/parse/mod.rs
index 83499ec54c6..996708b2174 100644
--- a/src/libsyntax/parse/mod.rs
+++ b/src/libsyntax/parse/mod.rs
@@ -749,8 +749,7 @@ mod test {
                         segments: vec!(
                             ast::PathSegment {
                                 identifier: str_to_ident("a"),
-                                lifetimes: Vec::new(),
-                                types: OwnedSlice::empty(),
+                                parameters: ast::PathParameters::none(),
                             }
                         ),
                     }),
@@ -768,13 +767,11 @@ mod test {
                             segments: vec!(
                                 ast::PathSegment {
                                     identifier: str_to_ident("a"),
-                                    lifetimes: Vec::new(),
-                                    types: OwnedSlice::empty(),
+                                    parameters: ast::PathParameters::none(),
                                 },
                                 ast::PathSegment {
                                     identifier: str_to_ident("b"),
-                                    lifetimes: Vec::new(),
-                                    types: OwnedSlice::empty(),
+                                    parameters: ast::PathParameters::none(),
                                 }
                             )
                         }),
@@ -952,8 +949,7 @@ mod test {
                             segments: vec!(
                                 ast::PathSegment {
                                     identifier: str_to_ident("d"),
-                                    lifetimes: Vec::new(),
-                                    types: OwnedSlice::empty(),
+                                    parameters: ast::PathParameters::none(),
                                 }
                             ),
                         }),
@@ -974,8 +970,7 @@ mod test {
                                segments: vec!(
                                 ast::PathSegment {
                                     identifier: str_to_ident("b"),
-                                    lifetimes: Vec::new(),
-                                    types: OwnedSlice::empty(),
+                                    parameters: ast::PathParameters::none(),
                                 }
                                ),
                             }),
@@ -1022,8 +1017,7 @@ mod test {
                                             ast::PathSegment {
                                                 identifier:
                                                     str_to_ident("int"),
-                                                lifetimes: Vec::new(),
-                                                types: OwnedSlice::empty(),
+                                                parameters: ast::PathParameters::none(),
                                             }
                                         ),
                                         }, None, ast::DUMMY_NODE_ID),
@@ -1072,10 +1066,8 @@ mod test {
                                                                 identifier:
                                                                 str_to_ident(
                                                                     "b"),
-                                                                lifetimes:
-                                                                Vec::new(),
-                                                                types:
-                                                                OwnedSlice::empty()
+                                                                parameters:
+                                                                ast::PathParameters::none(),
                                                             }
                                                         ),
                                                       }),
diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs
index 10bb9ef3625..18dd7074d28 100644
--- a/src/libsyntax/parse/parser.rs
+++ b/src/libsyntax/parse/parser.rs
@@ -53,9 +53,8 @@ use ast::{TtNonterminal, TupleVariantKind, Ty, Ty_, TyBot};
 use ast::{TypeField, TyFixedLengthVec, TyClosure, TyProc, TyBareFn};
 use ast::{TyTypeof, TyInfer, TypeMethod};
 use ast::{TyNil, TyParam, TyParamBound, TyParen, TyPath, TyPtr, TyQPath};
-use ast::{TyRptr, TyTup, TyU32, TyUnboxedFn, TyUniq, TyVec, UnUniq};
+use ast::{TyRptr, TyTup, TyU32, TyUniq, TyVec, UnUniq};
 use ast::{TypeImplItem, TypeTraitItem, Typedef, UnboxedClosureKind};
-use ast::{UnboxedFnBound, UnboxedFnTy, UnboxedFnTyParamBound};
 use ast::{UnnamedField, UnsafeBlock};
 use ast::{UnsafeFn, ViewItem, ViewItem_, ViewItemExternCrate, ViewItemUse};
 use ast::{ViewPath, ViewPathGlob, ViewPathList, ViewPathSimple};
@@ -1127,19 +1126,16 @@ impl<'a> Parser<'a> {
             Vec::new()
         };
 
-        let (optional_unboxed_closure_kind, inputs) = if self.eat(&token::OrOr) {
-            (None, Vec::new())
+        let inputs = if self.eat(&token::OrOr) {
+            Vec::new()
         } else {
             self.expect_or();
 
-            let optional_unboxed_closure_kind =
-                self.parse_optional_unboxed_closure_kind();
-
             let inputs = self.parse_seq_to_before_or(
                 &token::Comma,
                 |p| p.parse_arg_general(false));
             self.expect_or();
-            (optional_unboxed_closure_kind, inputs)
+            inputs
         };
 
         let bounds = self.parse_colon_then_ty_param_bounds();
@@ -1152,23 +1148,13 @@ impl<'a> Parser<'a> {
             variadic: false
         });
 
-        match optional_unboxed_closure_kind {
-            Some(unboxed_closure_kind) => {
-                TyUnboxedFn(P(UnboxedFnTy {
-                    kind: unboxed_closure_kind,
-                    decl: decl,
-                }))
-            }
-            None => {
-                TyClosure(P(ClosureTy {
-                    fn_style: fn_style,
-                    onceness: onceness,
-                    bounds: bounds,
-                    decl: decl,
-                    lifetimes: lifetime_defs,
-                }))
-            }
-        }
+        TyClosure(P(ClosureTy {
+            fn_style: fn_style,
+            onceness: onceness,
+            bounds: bounds,
+            decl: decl,
+            lifetimes: lifetime_defs,
+        }))
     }
 
     pub fn parse_unsafety(&mut self) -> FnStyle {
@@ -1487,9 +1473,9 @@ impl<'a> Parser<'a> {
                 trait_name: trait_name.path,
                 item_name: item_name,
             }))
-        } else if self.token == token::ModSep
-            || self.token.is_ident()
-            || self.token.is_path() {
+        } else if self.token == token::ModSep ||
+                  self.token.is_ident() ||
+                  self.token.is_path() {
             // NAMED TYPE
             let mode = if plus_allowed {
                 LifetimeAndTypesAndBounds
@@ -1706,50 +1692,18 @@ impl<'a> Parser<'a> {
         // Parse any number of segments and bound sets. A segment is an
         // identifier followed by an optional lifetime and a set of types.
         // A bound set is a set of type parameter bounds.
-        let mut segments = Vec::new();
-        loop {
-            // First, parse an identifier.
-            let identifier = self.parse_ident();
-
-            // Parse the '::' before type parameters if it's required. If
-            // it is required and wasn't present, then we're done.
-            if mode == LifetimeAndTypesWithColons &&
-                    !self.eat(&token::ModSep) {
-                segments.push(ast::PathSegment {
-                    identifier: identifier,
-                    lifetimes: Vec::new(),
-                    types: OwnedSlice::empty(),
-                });
-                break
+        let segments = match mode {
+            LifetimeAndTypesWithoutColons |
+            LifetimeAndTypesAndBounds => {
+                self.parse_path_segments_without_colons()
             }
-
-            // Parse the `<` before the lifetime and types, if applicable.
-            let (any_lifetime_or_types, lifetimes, types) = {
-                if mode != NoTypesAllowed && self.eat_lt(false) {
-                    let (lifetimes, types) =
-                        self.parse_generic_values_after_lt();
-                    (true, lifetimes, OwnedSlice::from_vec(types))
-                } else {
-                    (false, Vec::new(), OwnedSlice::empty())
-                }
-            };
-
-            // Assemble and push the result.
-            segments.push(ast::PathSegment {
-                identifier: identifier,
-                lifetimes: lifetimes,
-                types: types,
-            });
-
-            // We're done if we don't see a '::', unless the mode required
-            // a double colon to get here in the first place.
-            if !(mode == LifetimeAndTypesWithColons &&
-                    !any_lifetime_or_types) {
-                if !self.eat(&token::ModSep) {
-                    break
-                }
+            LifetimeAndTypesWithColons => {
+                self.parse_path_segments_with_colons()
             }
-        }
+            NoTypesAllowed => {
+                self.parse_path_segments_without_types()
+            }
+        };
 
         // Next, parse a plus and bounded type parameters, if
         // applicable. We need to remember whether the separate was
@@ -1792,6 +1746,123 @@ impl<'a> Parser<'a> {
         }
     }
 
+    /// Examples:
+    /// - `a::b<T,U>::c<V,W>`
+    /// - `a::b<T,U>::c(V) -> W`
+    /// - `a::b<T,U>::c(V)`
+    pub fn parse_path_segments_without_colons(&mut self) -> Vec<ast::PathSegment> {
+        let mut segments = Vec::new();
+        loop {
+            // First, parse an identifier.
+            let identifier = self.parse_ident();
+
+            // Parse types, optionally.
+            let parameters = if self.eat_lt(false) {
+                let (lifetimes, types) = self.parse_generic_values_after_lt();
+
+                ast::AngleBracketedParameters(ast::AngleBracketedParameterData {
+                    lifetimes: lifetimes,
+                    types: OwnedSlice::from_vec(types),
+                })
+            } else if self.eat(&token::OpenDelim(token::Paren)) {
+                let inputs = self.parse_seq_to_end(
+                    &token::CloseDelim(token::Paren),
+                    seq_sep_trailing_allowed(token::Comma),
+                    |p| p.parse_ty(true));
+
+                let output_ty = if self.eat(&token::RArrow) {
+                    Some(self.parse_ty(true))
+                } else {
+                    None
+                };
+
+                ast::ParenthesizedParameters(ast::ParenthesizedParameterData {
+                    inputs: inputs,
+                    output: output_ty
+                })
+            } else {
+                ast::PathParameters::none()
+            };
+
+            // Assemble and push the result.
+            segments.push(ast::PathSegment { identifier: identifier,
+                                             parameters: parameters });
+
+            // Continue only if we see a `::`
+            if !self.eat(&token::ModSep) {
+                return segments;
+            }
+        }
+    }
+
+    /// Examples:
+    /// - `a::b::<T,U>::c`
+    pub fn parse_path_segments_with_colons(&mut self) -> Vec<ast::PathSegment> {
+        let mut segments = Vec::new();
+        loop {
+            // First, parse an identifier.
+            let identifier = self.parse_ident();
+
+            // If we do not see a `::`, stop.
+            if !self.eat(&token::ModSep) {
+                segments.push(ast::PathSegment {
+                    identifier: identifier,
+                    parameters: ast::AngleBracketedParameters(ast::AngleBracketedParameterData {
+                        lifetimes: Vec::new(),
+                        types: OwnedSlice::empty(),
+                    })
+                });
+                return segments;
+            }
+
+            // Check for a type segment.
+            if self.eat_lt(false) {
+                // Consumed `a::b::<`, go look for types
+                let (lifetimes, types) = self.parse_generic_values_after_lt();
+                segments.push(ast::PathSegment {
+                    identifier: identifier,
+                    parameters: ast::AngleBracketedParameters(ast::AngleBracketedParameterData {
+                        lifetimes: lifetimes,
+                        types: OwnedSlice::from_vec(types),
+                    }),
+                });
+
+                // Consumed `a::b::<T,U>`, check for `::` before proceeding
+                if !self.eat(&token::ModSep) {
+                    return segments;
+                }
+            } else {
+                // Consumed `a::`, go look for `b`
+                segments.push(ast::PathSegment {
+                    identifier: identifier,
+                    parameters: ast::PathParameters::none(),
+                });
+            }
+        }
+    }
+
+
+    /// Examples:
+    /// - `a::b::c`
+    pub fn parse_path_segments_without_types(&mut self) -> Vec<ast::PathSegment> {
+        let mut segments = Vec::new();
+        loop {
+            // First, parse an identifier.
+            let identifier = self.parse_ident();
+
+            // Assemble and push the result.
+            segments.push(ast::PathSegment {
+                identifier: identifier,
+                parameters: ast::PathParameters::none()
+            });
+
+            // If we do not see a `::`, stop.
+            if !self.eat(&token::ModSep) {
+                return segments;
+            }
+        }
+    }
+
     /// parses 0 or 1 lifetime
     pub fn parse_opt_lifetime(&mut self) -> Option<ast::Lifetime> {
         match self.token {
@@ -3389,13 +3460,9 @@ impl<'a> Parser<'a> {
                           },
                           _ => {
                               if !enum_path.global &&
-                                    enum_path.segments.len() == 1 &&
-                                    enum_path.segments[0]
-                                             .lifetimes
-                                             .len() == 0 &&
-                                    enum_path.segments[0]
-                                             .types
-                                             .len() == 0 {
+                                  enum_path.segments.len() == 1 &&
+                                  enum_path.segments[0].parameters.is_empty()
+                              {
                                   // it could still be either an enum
                                   // or an identifier pattern, resolve
                                   // will sort it out:
@@ -3854,31 +3921,11 @@ impl<'a> Parser<'a> {
                 token::ModSep | token::Ident(..) => {
                     let path =
                         self.parse_path(LifetimeAndTypesWithoutColons).path;
-                    if self.token == token::OpenDelim(token::Paren) {
-                        self.bump();
-                        let inputs = self.parse_seq_to_end(
-                            &token::CloseDelim(token::Paren),
-                            seq_sep_trailing_allowed(token::Comma),
-                            |p| p.parse_arg_general(false));
-                        let (return_style, output) = self.parse_ret_ty();
-                        result.push(UnboxedFnTyParamBound(P(UnboxedFnBound {
-                            path: path,
-                            decl: P(FnDecl {
-                                inputs: inputs,
-                                output: output,
-                                cf: return_style,
-                                variadic: false,
-                            }),
-                            lifetimes: lifetime_defs,
-                            ref_id: ast::DUMMY_NODE_ID,
-                        })));
-                    } else {
-                        result.push(TraitTyParamBound(ast::TraitRef {
-                            path: path,
-                            ref_id: ast::DUMMY_NODE_ID,
-                            lifetimes: lifetime_defs,
-                        }))
-                    }
+                    result.push(TraitTyParamBound(ast::TraitRef {
+                        path: path,
+                        ref_id: ast::DUMMY_NODE_ID,
+                        lifetimes: lifetime_defs,
+                    }))
                 }
                 _ => break,
             }
@@ -3894,8 +3941,7 @@ impl<'a> Parser<'a> {
     fn trait_ref_from_ident(ident: Ident, span: Span) -> ast::TraitRef {
         let segment = ast::PathSegment {
             identifier: ident,
-            lifetimes: Vec::new(),
-            types: OwnedSlice::empty(),
+            parameters: ast::PathParameters::none()
         };
         let path = ast::Path {
             span: span,
@@ -5611,8 +5657,7 @@ impl<'a> Parser<'a> {
                 segments: path.into_iter().map(|identifier| {
                     ast::PathSegment {
                         identifier: identifier,
-                        lifetimes: Vec::new(),
-                        types: OwnedSlice::empty(),
+                        parameters: ast::PathParameters::none(),
                     }
                 }).collect()
             };
@@ -5646,8 +5691,7 @@ impl<'a> Parser<'a> {
                         segments: path.into_iter().map(|identifier| {
                             ast::PathSegment {
                                 identifier: identifier,
-                                lifetimes: Vec::new(),
-                                types: OwnedSlice::empty(),
+                                parameters: ast::PathParameters::none(),
                             }
                         }).collect()
                     };
@@ -5664,8 +5708,7 @@ impl<'a> Parser<'a> {
                         segments: path.into_iter().map(|identifier| {
                             ast::PathSegment {
                                 identifier: identifier,
-                                lifetimes: Vec::new(),
-                                types: OwnedSlice::empty(),
+                                parameters: ast::PathParameters::none(),
                             }
                         }).collect()
                     };
@@ -5686,8 +5729,7 @@ impl<'a> Parser<'a> {
             segments: path.into_iter().map(|identifier| {
                 ast::PathSegment {
                     identifier: identifier,
-                    lifetimes: Vec::new(),
-                    types: OwnedSlice::empty(),
+                    parameters: ast::PathParameters::none(),
                 }
             }).collect()
         };
diff --git a/src/libsyntax/print/pprust.rs b/src/libsyntax/print/pprust.rs
index 106e3f1faae..2448eacbb39 100644
--- a/src/libsyntax/print/pprust.rs
+++ b/src/libsyntax/print/pprust.rs
@@ -13,7 +13,7 @@ use ast::{FnUnboxedClosureKind, FnMutUnboxedClosureKind};
 use ast::{FnOnceUnboxedClosureKind};
 use ast::{MethodImplItem, RegionTyParamBound, TraitTyParamBound};
 use ast::{RequiredMethod, ProvidedMethod, TypeImplItem, TypeTraitItem};
-use ast::{UnboxedClosureKind, UnboxedFnTyParamBound};
+use ast::{UnboxedClosureKind};
 use ast;
 use ast_util;
 use owned_slice::OwnedSlice;
@@ -699,7 +699,6 @@ impl<'a> State<'a> {
                                       None,
                                       &OwnedSlice::empty(),
                                       Some(&generics),
-                                      None,
                                       None));
             }
             ast::TyClosure(ref f) => {
@@ -719,7 +718,6 @@ impl<'a> State<'a> {
                                       None,
                                       &f.bounds,
                                       Some(&generics),
-                                      None,
                                       None));
             }
             ast::TyProc(ref f) => {
@@ -739,21 +737,8 @@ impl<'a> State<'a> {
                                       None,
                                       &f.bounds,
                                       Some(&generics),
-                                      None,
                                       None));
             }
-            ast::TyUnboxedFn(ref f) => {
-                try!(self.print_ty_fn(None,
-                                      None,
-                                      ast::NormalFn,
-                                      ast::Many,
-                                      &*f.decl,
-                                      None,
-                                      &OwnedSlice::empty(),
-                                      None,
-                                      None,
-                                      Some(f.kind)));
-            }
             ast::TyPath(ref path, ref bounds, _) => {
                 try!(self.print_bounded_path(path, bounds));
             }
@@ -1212,8 +1197,7 @@ impl<'a> State<'a> {
                               Some(m.ident),
                               &OwnedSlice::empty(),
                               Some(&m.generics),
-                              Some(&m.explicit_self.node),
-                              None));
+                              Some(&m.explicit_self.node)));
         word(&mut self.s, ";")
     }
 
@@ -1995,14 +1979,34 @@ impl<'a> State<'a> {
 
             try!(self.print_ident(segment.identifier));
 
-            if !segment.lifetimes.is_empty() || !segment.types.is_empty() {
-                if colons_before_params {
-                    try!(word(&mut self.s, "::"))
-                }
+            try!(self.print_path_parameters(&segment.parameters, colons_before_params));
+        }
+
+        match *opt_bounds {
+            None => Ok(()),
+            Some(ref bounds) => self.print_bounds("+", bounds)
+        }
+    }
+
+    fn print_path_parameters(&mut self,
+                             parameters: &ast::PathParameters,
+                             colons_before_params: bool)
+                             -> IoResult<()>
+    {
+        if parameters.is_empty() {
+            return Ok(());
+        }
+
+        if colons_before_params {
+            try!(word(&mut self.s, "::"))
+        }
+
+        match *parameters {
+            ast::AngleBracketedParameters(ref data) => {
                 try!(word(&mut self.s, "<"));
 
                 let mut comma = false;
-                for lifetime in segment.lifetimes.iter() {
+                for lifetime in data.lifetimes.iter() {
                     if comma {
                         try!(self.word_space(","))
                     }
@@ -2010,24 +2014,38 @@ impl<'a> State<'a> {
                     comma = true;
                 }
 
-                if !segment.types.is_empty() {
+                if !data.types.is_empty() {
                     if comma {
                         try!(self.word_space(","))
                     }
                     try!(self.commasep(
                         Inconsistent,
-                        segment.types.as_slice(),
+                        data.types.as_slice(),
                         |s, ty| s.print_type(&**ty)));
                 }
 
                 try!(word(&mut self.s, ">"))
             }
-        }
 
-        match *opt_bounds {
-            None => Ok(()),
-            Some(ref bounds) => self.print_bounds("+", bounds)
+            ast::ParenthesizedParameters(ref data) => {
+                try!(word(&mut self.s, "("));
+                try!(self.commasep(
+                    Inconsistent,
+                    data.inputs.as_slice(),
+                    |s, ty| s.print_type(&**ty)));
+                try!(word(&mut self.s, ")"));
+
+                match data.output {
+                    None => { }
+                    Some(ref ty) => {
+                        try!(self.word_space("->"));
+                        try!(self.print_type(&**ty));
+                    }
+                }
+            }
         }
+
+        Ok(())
     }
 
     fn print_path(&mut self, path: &ast::Path,
@@ -2373,15 +2391,6 @@ impl<'a> State<'a> {
                     RegionTyParamBound(ref lt) => {
                         self.print_lifetime(lt)
                     }
-                    UnboxedFnTyParamBound(ref unboxed_function_type) => {
-                        try!(self.print_path(&unboxed_function_type.path,
-                                             false));
-                        try!(self.popen());
-                        try!(self.print_fn_args(&*unboxed_function_type.decl,
-                                                None));
-                        try!(self.pclose());
-                        self.print_fn_output(&*unboxed_function_type.decl)
-                    }
                 })
             }
             Ok(())
@@ -2641,9 +2650,7 @@ impl<'a> State<'a> {
                        id: Option<ast::Ident>,
                        bounds: &OwnedSlice<ast::TyParamBound>,
                        generics: Option<&ast::Generics>,
-                       opt_explicit_self: Option<&ast::ExplicitSelf_>,
-                       opt_unboxed_closure_kind:
-                        Option<ast::UnboxedClosureKind>)
+                       opt_explicit_self: Option<&ast::ExplicitSelf_>)
                        -> IoResult<()> {
         try!(self.ibox(indent_unit));
 
@@ -2660,9 +2667,7 @@ impl<'a> State<'a> {
             try!(self.print_fn_style(fn_style));
             try!(self.print_opt_abi_and_extern_if_nondefault(opt_abi));
             try!(self.print_onceness(onceness));
-            if opt_unboxed_closure_kind.is_none() {
-                try!(word(&mut self.s, "fn"));
-            }
+            try!(word(&mut self.s, "fn"));
         }
 
         match id {
@@ -2676,30 +2681,15 @@ impl<'a> State<'a> {
         match generics { Some(g) => try!(self.print_generics(g)), _ => () }
         try!(zerobreak(&mut self.s));
 
-        if opt_unboxed_closure_kind.is_some() || opt_sigil == Some('&') {
+        if opt_sigil == Some('&') {
             try!(word(&mut self.s, "|"));
         } else {
             try!(self.popen());
         }
 
-        match opt_unboxed_closure_kind {
-            Some(ast::FnUnboxedClosureKind) => {
-                try!(word(&mut self.s, "&"));
-                try!(self.word_space(":"));
-            }
-            Some(ast::FnMutUnboxedClosureKind) => {
-                try!(word(&mut self.s, "&mut"));
-                try!(self.word_space(":"));
-            }
-            Some(ast::FnOnceUnboxedClosureKind) => {
-                try!(self.word_space(":"));
-            }
-            None => {}
-        }
-
         try!(self.print_fn_args(decl, opt_explicit_self));
 
-        if opt_unboxed_closure_kind.is_some() || opt_sigil == Some('&') {
+        if opt_sigil == Some('&') {
             try!(word(&mut self.s, "|"));
         } else {
             if decl.variadic {
diff --git a/src/libsyntax/std_inject.rs b/src/libsyntax/std_inject.rs
index 0f86fb751da..6a4ab365a50 100644
--- a/src/libsyntax/std_inject.rs
+++ b/src/libsyntax/std_inject.rs
@@ -14,7 +14,6 @@ use codemap::DUMMY_SP;
 use codemap;
 use fold::Folder;
 use fold;
-use owned_slice::OwnedSlice;
 use parse::token::InternedString;
 use parse::token::special_idents;
 use parse::token;
@@ -181,13 +180,11 @@ impl<'a> fold::Folder for PreludeInjector<'a> {
             segments: vec!(
                 ast::PathSegment {
                     identifier: token::str_to_ident("std"),
-                    lifetimes: Vec::new(),
-                    types: OwnedSlice::empty(),
+                    parameters: ast::PathParameters::none(),
                 },
                 ast::PathSegment {
                     identifier: token::str_to_ident("prelude"),
-                    lifetimes: Vec::new(),
-                    types: OwnedSlice::empty(),
+                    parameters: ast::PathParameters::none(),
                 }),
         };
 
diff --git a/src/libsyntax/test.rs b/src/libsyntax/test.rs
index 37586f6abd7..a7db8e800a9 100644
--- a/src/libsyntax/test.rs
+++ b/src/libsyntax/test.rs
@@ -453,8 +453,7 @@ fn path_node(ids: Vec<ast::Ident> ) -> ast::Path {
         global: false,
         segments: ids.into_iter().map(|identifier| ast::PathSegment {
             identifier: identifier,
-            lifetimes: Vec::new(),
-            types: OwnedSlice::empty(),
+            parameters: ast::PathParameters::none(),
         }).collect()
     }
 }
diff --git a/src/libsyntax/visit.rs b/src/libsyntax/visit.rs
index 86ee23d71a6..9751abacbd3 100644
--- a/src/libsyntax/visit.rs
+++ b/src/libsyntax/visit.rs
@@ -365,12 +365,6 @@ pub fn walk_ty<'v, V: Visitor<'v>>(visitor: &mut V, typ: &'v Ty) {
             visitor.visit_ty(&*function_declaration.decl.output);
             walk_lifetime_decls(visitor, &function_declaration.lifetimes);
         }
-        TyUnboxedFn(ref function_declaration) => {
-            for argument in function_declaration.decl.inputs.iter() {
-                visitor.visit_ty(&*argument.ty)
-            }
-            visitor.visit_ty(&*function_declaration.decl.output);
-        }
         TyPath(ref path, ref opt_bounds, id) => {
             visitor.visit_path(path, id);
             match *opt_bounds {
@@ -407,11 +401,23 @@ pub fn walk_path<'v, V: Visitor<'v>>(visitor: &mut V, path: &'v Path) {
     for segment in path.segments.iter() {
         visitor.visit_ident(path.span, segment.identifier);
 
-        for typ in segment.types.iter() {
-            visitor.visit_ty(&**typ);
-        }
-        for lifetime in segment.lifetimes.iter() {
-            visitor.visit_lifetime_ref(lifetime);
+        match segment.parameters {
+            ast::AngleBracketedParameters(ref data) => {
+                for typ in data.types.iter() {
+                    visitor.visit_ty(&**typ);
+                }
+                for lifetime in data.lifetimes.iter() {
+                    visitor.visit_lifetime_ref(lifetime);
+                }
+            }
+            ast::ParenthesizedParameters(ref data) => {
+                for typ in data.inputs.iter() {
+                    visitor.visit_ty(&**typ);
+                }
+                for typ in data.output.iter() {
+                    visitor.visit_ty(&**typ);
+                }
+            }
         }
     }
 }
@@ -493,13 +499,6 @@ pub fn walk_ty_param_bounds<'v, V: Visitor<'v>>(visitor: &mut V,
             TraitTyParamBound(ref typ) => {
                 walk_trait_ref_helper(visitor, typ)
             }
-            UnboxedFnTyParamBound(ref function_declaration) => {
-                for argument in function_declaration.decl.inputs.iter() {
-                    visitor.visit_ty(&*argument.ty)
-                }
-                visitor.visit_ty(&*function_declaration.decl.output);
-                walk_lifetime_decls(visitor, &function_declaration.lifetimes);
-            }
             RegionTyParamBound(ref lifetime) => {
                 visitor.visit_lifetime_ref(lifetime);
             }
diff --git a/src/test/compile-fail/issue-14092.rs b/src/test/compile-fail/issue-14092.rs
index 4d663d00fb2..0ab37a88826 100644
--- a/src/test/compile-fail/issue-14092.rs
+++ b/src/test/compile-fail/issue-14092.rs
@@ -8,7 +8,7 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-fn fn1(0: Box) {} //~ ERROR: not enough type parameters supplied to `Box<T>`
+fn fn1(0: Box) {} //~ ERROR: wrong number of type arguments: expected 1, found 0
 
 fn main() {}
 
diff --git a/src/test/compile-fail/issue-18423.rs b/src/test/compile-fail/issue-18423.rs
new file mode 100644
index 00000000000..63b110b5579
--- /dev/null
+++ b/src/test/compile-fail/issue-18423.rs
@@ -0,0 +1,18 @@
+// 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.
+
+// Test that `Box` cannot be used with a lifetime parameter.
+
+struct Foo<'a> {
+    x: Box<'a, int> //~ ERROR wrong number of lifetime parameters
+}
+
+pub fn main() {
+}
diff --git a/src/test/compile-fail/unboxed-closure-sugar-default.rs b/src/test/compile-fail/unboxed-closure-sugar-default.rs
new file mode 100644
index 00000000000..9866a200045
--- /dev/null
+++ b/src/test/compile-fail/unboxed-closure-sugar-default.rs
@@ -0,0 +1,37 @@
+// 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.
+
+// Test interaction between unboxed closure sugar and default type
+// parameters (should be exactly as if angle brackets were used).
+
+#![feature(default_type_params)]
+#![allow(dead_code)]
+
+struct Foo<T,U,V=T> {
+    t: T, u: U
+}
+
+trait Eq<X> { }
+impl<X> Eq<X> for X { }
+fn eq<A,B:Eq<A>>() { }
+
+fn test<'a,'b>() {
+    // Parens are equivalent to omitting default in angle.
+    eq::< Foo<(int,),()>,               Foo(int)                      >();
+
+    // In angle version, we supply something other than the default
+    eq::< Foo<(int,),(),int>,           Foo(int)                      >();
+    //~^ ERROR not implemented
+
+    // Supply default explicitly.
+    eq::< Foo<(int,),(),(int,)>,        Foo(int)                      >();
+}
+
+fn main() { }
diff --git a/src/test/compile-fail/unboxed-closure-sugar-equiv.rs b/src/test/compile-fail/unboxed-closure-sugar-equiv.rs
new file mode 100644
index 00000000000..c38010c1ee2
--- /dev/null
+++ b/src/test/compile-fail/unboxed-closure-sugar-equiv.rs
@@ -0,0 +1,39 @@
+// 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.
+
+// Test that the unboxed closure sugar can be used with an arbitrary
+// struct type and that it is equivalent to the same syntax using
+// angle brackets. This test covers only simple types and in
+// particular doesn't test bound regions.
+
+#![allow(dead_code)]
+
+struct Foo<T,U> {
+    t: T, u: U
+}
+
+trait Eq<X> { }
+impl<X> Eq<X> for X { }
+fn eq<A,B:Eq<A>>() { }
+
+fn test<'a,'b>() {
+    // No errors expected:
+    eq::< Foo<(),()>,                   Foo()                         >();
+    eq::< Foo<(int,),()>,               Foo(int)                      >();
+    eq::< Foo<(int,uint),()>,           Foo(int,uint)                 >();
+    eq::< Foo<(int,uint),uint>,         Foo(int,uint) -> uint         >();
+    eq::< Foo<(&'a int,&'b uint),uint>, Foo(&'a int,&'b uint) -> uint >();
+
+    // Errors expected:
+    eq::< Foo<(),()>,                   Foo(char)                     >();
+    //~^ ERROR not implemented
+}
+
+fn main() { }
diff --git a/src/test/compile-fail/unboxed-closure-sugar-nonexistent-trait.rs b/src/test/compile-fail/unboxed-closure-sugar-nonexistent-trait.rs
index f51160a1b23..d89c3802508 100644
--- a/src/test/compile-fail/unboxed-closure-sugar-nonexistent-trait.rs
+++ b/src/test/compile-fail/unboxed-closure-sugar-nonexistent-trait.rs
@@ -8,7 +8,7 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-fn f<F:Nonexist(int) -> int>(x: F) {} //~ ERROR unresolved trait
+fn f<F:Nonexist(int) -> int>(x: F) {} //~ ERROR nonexistent trait `Nonexist`
 
 type Typedef = int;
 
diff --git a/src/test/compile-fail/unboxed-closure-sugar-region.rs b/src/test/compile-fail/unboxed-closure-sugar-region.rs
new file mode 100644
index 00000000000..962e233dea6
--- /dev/null
+++ b/src/test/compile-fail/unboxed-closure-sugar-region.rs
@@ -0,0 +1,45 @@
+// 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.
+
+// Test interaction between unboxed closure sugar and region
+// parameters (should be exactly as if angle brackets were used
+// and regions omitted).
+
+#![feature(default_type_params)]
+#![allow(dead_code)]
+
+use std::kinds::marker;
+
+struct Foo<'a,T,U> {
+    t: T,
+    u: U,
+    m: marker::InvariantLifetime<'a>
+}
+
+trait Eq<X> { }
+impl<X> Eq<X> for X { }
+fn eq<A,B:Eq<A>>() { }
+fn same_type<A,B:Eq<A>>(a: A, b: B) { }
+
+fn test<'a,'b>() {
+    // Parens are equivalent to omitting default in angle.
+    eq::< Foo<(int,),()>,               Foo(int)                      >();
+
+    // Here we specify 'static explicitly in angle-bracket version.
+    // Parenthesized winds up getting inferred.
+    eq::< Foo<'static, (int,),()>,               Foo(int)                      >();
+}
+
+fn test2(x: Foo<(int,),()>, y: Foo(int)) {
+    // Here, the omitted lifetimes are expanded to distinct things.
+    same_type(x, y) //~ ERROR cannot infer
+}
+
+fn main() { }
diff --git a/src/test/compile-fail/unboxed-closure-sugar-wrong-number-number-type-parameters-1.rs b/src/test/compile-fail/unboxed-closure-sugar-wrong-number-number-type-parameters-1.rs
new file mode 100644
index 00000000000..e122b87b1e0
--- /dev/null
+++ b/src/test/compile-fail/unboxed-closure-sugar-wrong-number-number-type-parameters-1.rs
@@ -0,0 +1,16 @@
+// 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.
+
+struct One<A>;
+
+fn foo(_: One()) //~ ERROR wrong number of type arguments
+{}
+
+fn main() { }
diff --git a/src/test/compile-fail/unboxed-closure-sugar-wrong-number-number-type-parameters-3.rs b/src/test/compile-fail/unboxed-closure-sugar-wrong-number-number-type-parameters-3.rs
new file mode 100644
index 00000000000..7a66abb39df
--- /dev/null
+++ b/src/test/compile-fail/unboxed-closure-sugar-wrong-number-number-type-parameters-3.rs
@@ -0,0 +1,16 @@
+// 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.
+
+struct Three<A,B,C>;
+
+fn foo(_: Three()) //~ ERROR wrong number of type arguments
+{}
+
+fn main() { }
diff --git a/src/test/compile-fail/unboxed-closure-sugar-wrong-number-number-type-parameters.rs b/src/test/compile-fail/unboxed-closure-sugar-wrong-number-number-type-parameters.rs
new file mode 100644
index 00000000000..e265a3d56b8
--- /dev/null
+++ b/src/test/compile-fail/unboxed-closure-sugar-wrong-number-number-type-parameters.rs
@@ -0,0 +1,16 @@
+// 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.
+
+struct Zero;
+
+fn foo(_: Zero()) //~ ERROR wrong number of type arguments
+{}
+
+fn main() { }
diff --git a/src/test/compile-fail/unboxed-closure-sugar-wrong-trait.rs b/src/test/compile-fail/unboxed-closure-sugar-wrong-trait.rs
index a751ae1c518..1394f8fa65f 100644
--- a/src/test/compile-fail/unboxed-closure-sugar-wrong-trait.rs
+++ b/src/test/compile-fail/unboxed-closure-sugar-wrong-trait.rs
@@ -11,7 +11,7 @@
 trait Trait {}
 
 fn f<F:Trait(int) -> int>(x: F) {}
-//~^ ERROR unboxed function trait must be one of `Fn`, `FnMut`, or `FnOnce`
+//~^ ERROR wrong number of type arguments: expected 0, found 2
 
 fn main() {}
 
diff --git a/src/test/run-pass/unboxed-closures-manual-impl.rs b/src/test/run-pass/unboxed-closures-manual-impl.rs
index b0947f46a86..8f6cfe04997 100644
--- a/src/test/run-pass/unboxed-closures-manual-impl.rs
+++ b/src/test/run-pass/unboxed-closures-manual-impl.rs
@@ -25,7 +25,7 @@ fn call_it<F:FnMut(int)->int>(mut f: F, x: int) -> int {
     f.call_mut((x,)) + 3
 }
 
-fn call_box(f: &mut |&mut: int|->int, x: int) -> int {
+fn call_box(f: &mut FnMut(int) -> int, x: int) -> int {
     f.call_mut((x,)) + 3
 }
 
diff --git a/src/test/run-pass/unboxed-closures-prelude.rs b/src/test/run-pass/unboxed-closures-prelude.rs
index 4226ed427e7..f9d2ba02123 100644
--- a/src/test/run-pass/unboxed-closures-prelude.rs
+++ b/src/test/run-pass/unboxed-closures-prelude.rs
@@ -13,7 +13,7 @@
 #![feature(unboxed_closures, unboxed_closure_sugar)]
 
 fn main() {
-    let task: Box<|: int| -> int> = box |: x| x;
+    let task: Box<FnOnce(int) -> int> = box |: x| x;
     task.call_once((0i, ));
 }
 
diff --git a/src/test/run-pass/unboxed-closures-sugar-1.rs b/src/test/run-pass/unboxed-closures-sugar-1.rs
new file mode 100644
index 00000000000..b358e7ce288
--- /dev/null
+++ b/src/test/run-pass/unboxed-closures-sugar-1.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.
+
+// Test that the unboxed closure sugar can be used with an arbitrary
+// struct type and that it is equivalent to the same syntax using
+// angle brackets. This test covers only simple types and in
+// particular doesn't test bound regions.
+
+#![allow(dead_code)]
+
+struct Foo<T,U> {
+    t: T, u: U
+}
+
+trait Eq<X> { }
+impl<X> Eq<X> for X { }
+fn eq<A,B:Eq<A>>() { }
+
+fn test<'a,'b>() {
+    eq::< Foo<(),()>,                   Foo()                         >();
+    eq::< Foo<(int,),()>,               Foo(int)                      >();
+    eq::< Foo<(int,uint),()>,           Foo(int,uint)                 >();
+    eq::< Foo<(int,uint),uint>,         Foo(int,uint) -> uint         >();
+    eq::< Foo<(&'a int,&'b uint),uint>, Foo(&'a int,&'b uint) -> uint >();
+}
+
+fn main() { }
diff --git a/src/test/run-pass/unboxed-closures-sugar-object.rs b/src/test/run-pass/unboxed-closures-sugar-object.rs
new file mode 100644
index 00000000000..3b38f72432f
--- /dev/null
+++ b/src/test/run-pass/unboxed-closures-sugar-object.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.
+
+// Test unboxed closure sugar used in object types.
+
+#![allow(dead_code)]
+
+struct Foo<T,U> {
+    t: T, u: U
+}
+
+trait Getter<A,R> {
+    fn get(&self, arg: A) -> R;
+}
+
+struct Identity;
+impl<X> Getter<X,X> for Identity {
+    fn get(&self, arg: X) -> X {
+        arg
+    }
+}
+
+fn main() {
+    let x: &Getter(int) -> (int,) = &Identity;
+    let (y,) = x.get((22,));
+    assert_eq!(y, 22);
+}
diff --git a/src/test/run-pass/unboxed-closures-unboxing-shim.rs b/src/test/run-pass/unboxed-closures-unboxing-shim.rs
index 0a7baa3ba36..426352cadd8 100644
--- a/src/test/run-pass/unboxed-closures-unboxing-shim.rs
+++ b/src/test/run-pass/unboxed-closures-unboxing-shim.rs
@@ -13,7 +13,7 @@
 use std::ops::FnOnce;
 
 fn main() {
-    let task: Box<|: int| -> int> = box |: x| x;
+    let task: Box<FnOnce(int) -> int> = box |: x| x;
     assert!(task.call_once((1234i,)) == 1234i);
 }