about summary refs log tree commit diff
path: root/src/libsyntax
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 /src/libsyntax
parent08ddfc10e4170ac5f4522a71c0d1aea8cf799f29 (diff)
parentd0fa4c6239accc08aae11d9db3e13d4153add432 (diff)
downloadrust-76d2abe0e7fb33ed41137a0c99fbbc2905d8ca91.tar.gz
rust-76d2abe0e7fb33ed41137a0c99fbbc2905d8ca91.zip
rollup merge of #18630 : nikomatsakis/purge-the-bars
Diffstat (limited to 'src/libsyntax')
-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
13 files changed, 391 insertions, 281 deletions
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);
             }