about summary refs log tree commit diff
path: root/src/libsyntax/parse/parser.rs
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2013-06-23 14:58:58 -0700
committerbors <bors@rust-lang.org>2013-06-23 14:58:58 -0700
commitf82756180bec5a8405e1fc6ee1b22949db24861f (patch)
tree76bc5be01aa0605cb212ea1b0556cd48f69facdc /src/libsyntax/parse/parser.rs
parentcb58b19f023f95614e4a2bc3c812614d0938a9f2 (diff)
parentba3f43e506de97109788e4a96df438b3c89f5e49 (diff)
downloadrust-f82756180bec5a8405e1fc6ee1b22949db24861f.tar.gz
rust-f82756180bec5a8405e1fc6ee1b22949db24861f.zip
auto merge of #7314 : bblum/rust/trait-bounds2, r=nikomatsakis
Fixed a merge conflict, some tests, some bitrotting, etc., from #7248.
Diffstat (limited to 'src/libsyntax/parse/parser.rs')
-rw-r--r--src/libsyntax/parse/parser.rs63
1 files changed, 37 insertions, 26 deletions
diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs
index 753c69b23d6..f2443f9e533 100644
--- a/src/libsyntax/parse/parser.rs
+++ b/src/libsyntax/parse/parser.rs
@@ -75,7 +75,7 @@ use parse::obsolete::{ObsoleteLet, ObsoleteFieldTerminator};
 use parse::obsolete::{ObsoleteMoveInit, ObsoleteBinaryMove, ObsoleteSwap};
 use parse::obsolete::{ObsoleteSyntax, ObsoleteLowerCaseKindBounds};
 use parse::obsolete::{ObsoleteUnsafeBlock, ObsoleteImplSyntax};
-use parse::obsolete::{ObsoleteTraitBoundSeparator, ObsoleteMutOwnedPointer};
+use parse::obsolete::{ObsoleteMutOwnedPointer};
 use parse::obsolete::{ObsoleteMutVector, ObsoleteImplVisibility};
 use parse::obsolete::{ObsoleteRecordType, ObsoleteRecordPattern};
 use parse::obsolete::{ObsoletePostFnTySigil};
@@ -710,8 +710,8 @@ impl Parser {
         } else if *self.token == token::MOD_SEP
             || is_ident_or_path(self.token) {
             // NAMED TYPE
-            let path = self.parse_path_with_tps(false);
-            ty_path(path, self.get_id())
+            let (path, bounds) = self.parse_type_path();
+            ty_path(path, @bounds, self.get_id())
         } else {
             self.fatal(fmt!("expected type, found token %?",
                             *self.token));
@@ -974,10 +974,8 @@ impl Parser {
                      types: ~[] }
     }
 
-    // parse a path optionally with type parameters. If 'colons'
-    // is true, then type parameters must be preceded by colons,
-    // as in a::t::<t1,t2>
-    pub fn parse_path_with_tps(&self, colons: bool) -> @ast::Path {
+    pub fn parse_bounded_path_with_tps(&self, colons: bool,
+                                        before_tps: Option<&fn()>) -> @ast::Path {
         debug!("parse_path_with_tps(colons=%b)", colons);
 
         maybe_whole!(self, nt_path);
@@ -987,6 +985,10 @@ impl Parser {
             return path;
         }
 
+        // If the path might have bounds on it, they should be parsed before
+        // the parameters, e.g. module::TraitName:B1+B2<T>
+        before_tps.map_consume(|callback| callback());
+
         // Parse the (obsolete) trailing region parameter, if any, which will
         // be written "foo/&x"
         let rp_slash = {
@@ -1038,6 +1040,25 @@ impl Parser {
                      .. copy *path }
     }
 
+    // parse a path optionally with type parameters. If 'colons'
+    // is true, then type parameters must be preceded by colons,
+    // as in a::t::<t1,t2>
+    pub fn parse_path_with_tps(&self, colons: bool) -> @ast::Path {
+        self.parse_bounded_path_with_tps(colons, None)
+    }
+
+    // Like the above, but can also parse kind bounds in the case of a
+    // path to be used as a type that might be a trait.
+    pub fn parse_type_path(&self) -> (@ast::Path, OptVec<TyParamBound>) {
+        let mut bounds = opt_vec::Empty;
+        let path = self.parse_bounded_path_with_tps(false, Some(|| {
+            // Note: this closure might not even get called in the case of a
+            // macro-generated path. But that's the macro parser's job.
+            bounds = self.parse_optional_ty_param_bounds();
+        }));
+        (path, bounds)
+    }
+
     /// parses 0 or 1 lifetime
     pub fn parse_opt_lifetime(&self) -> Option<@ast::Lifetime> {
         match *self.token {
@@ -2847,16 +2868,6 @@ impl Parser {
         spanned(lo, hi, bloc)
     }
 
-    fn mk_ty_path(&self, i: ident) -> @Ty {
-        @Ty {
-            id: self.get_id(),
-            node: ty_path(
-                ident_to_path(*self.last_span, i),
-                self.get_id()),
-            span: *self.last_span,
-        }
-    }
-
     fn parse_optional_purity(&self) -> ast::purity {
         if self.eat_keyword(keywords::Pure) {
             self.obsolete(*self.last_span, ObsoletePurity);
@@ -2921,13 +2932,8 @@ impl Parser {
                 _ => break,
             }
 
-            if self.eat(&token::BINOP(token::PLUS)) {
-                loop;
-            }
-
-            if is_ident_or_path(self.token) {
-                self.obsolete(*self.span,
-                              ObsoleteTraitBoundSeparator);
+            if !self.eat(&token::BINOP(token::PLUS)) {
+                break;
             }
         }
 
@@ -3284,14 +3290,19 @@ impl Parser {
         let opt_trait = if could_be_trait && self.eat_keyword(keywords::For) {
             // New-style trait. Reinterpret the type as a trait.
             let opt_trait_ref = match ty.node {
-                ty_path(path, node_id) => {
+                ty_path(path, @opt_vec::Empty, node_id) => {
                     Some(@trait_ref {
                         path: path,
                         ref_id: node_id
                     })
                 }
+                ty_path(*) => {
+                    self.span_err(ty.span,
+                                  "bounded traits are only valid in type position");
+                    None
+                }
                 _ => {
-                    self.span_err(*self.span, "not a trait");
+                    self.span_err(ty.span, "not a trait");
                     None
                 }
             };