about summary refs log tree commit diff
path: root/src/libsyntax/parse
diff options
context:
space:
mode:
authorNick Cameron <ncameron@mozilla.com>2014-11-29 17:08:30 +1300
committerNick Cameron <ncameron@mozilla.com>2014-12-12 19:11:59 +1300
commit397dda8aa08ee540cffd36f542ebd1140227d0bd (patch)
treeee4cc3c5f3434375ef05a0092f7df8154708b765 /src/libsyntax/parse
parentda83ad8e2c8e2c5f522dc59963e00f55b1f8c03b (diff)
downloadrust-397dda8aa08ee540cffd36f542ebd1140227d0bd.tar.gz
rust-397dda8aa08ee540cffd36f542ebd1140227d0bd.zip
Add support for equality constraints on associated types
Diffstat (limited to 'src/libsyntax/parse')
-rw-r--r--src/libsyntax/parse/parser.rs177
1 files changed, 135 insertions, 42 deletions
diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs
index 4929ee885ac..92c7380a61d 100644
--- a/src/libsyntax/parse/parser.rs
+++ b/src/libsyntax/parse/parser.rs
@@ -53,7 +53,7 @@ use ast::{StructVariantKind, BiSub, StrStyle};
 use ast::{SelfExplicit, SelfRegion, SelfStatic, SelfValue};
 use ast::{Delimited, SequenceRepetition, TokenTree, TraitItem, TraitRef};
 use ast::{TtDelimited, TtSequence, TtToken};
-use ast::{TupleVariantKind, Ty, Ty_};
+use ast::{TupleVariantKind, Ty, Ty_, TypeBinding};
 use ast::{TypeField, TyFixedLengthVec, TyClosure, TyProc, TyBareFn};
 use ast::{TyTypeof, TyInfer, TypeMethod};
 use ast::{TyParam, TyParamBound, TyParen, TyPath, TyPolyTraitRef, TyPtr, TyQPath};
@@ -62,7 +62,7 @@ use ast::{TypeImplItem, TypeTraitItem, Typedef, UnboxedClosureKind};
 use ast::{UnnamedField, UnsafeBlock};
 use ast::{UnsafeFn, ViewItem, ViewItem_, ViewItemExternCrate, ViewItemUse};
 use ast::{ViewPath, ViewPathGlob, ViewPathList, ViewPathSimple};
-use ast::{Visibility, WhereClause, WherePredicate};
+use ast::{Visibility, WhereClause};
 use ast;
 use ast_util::{mod, as_prec, ident_to_path, operator_prec};
 use codemap::{mod, Span, BytePos, Spanned, spanned, mk_sp};
@@ -769,13 +769,10 @@ impl<'a> Parser<'a> {
         }
     }
 
-    /// Parse a sequence bracketed by '<' and '>', stopping
-    /// before the '>'.
-    pub fn parse_seq_to_before_gt<T>(
-                                  &mut self,
-                                  sep: Option<token::Token>,
-                                  f: |&mut Parser| -> T)
-                                  -> OwnedSlice<T> {
+    pub fn parse_seq_to_before_gt_or_return<T>(&mut self,
+                                               sep: Option<token::Token>,
+                                               f: |&mut Parser| -> Option<T>)
+                                               -> (OwnedSlice<T>, bool) {
         let mut v = Vec::new();
         // This loop works by alternating back and forth between parsing types
         // and commas.  For example, given a string `A, B,>`, the parser would
@@ -792,24 +789,48 @@ impl<'a> Parser<'a> {
             }
 
             if i % 2 == 0 {
-                v.push(f(self));
+                match f(self) {
+                    Some(result) => v.push(result),
+                    None => return (OwnedSlice::from_vec(v), true)
+                }
             } else {
                 sep.as_ref().map(|t| self.expect(t));
             }
         }
-        return OwnedSlice::from_vec(v);
+        return (OwnedSlice::from_vec(v), false);
+    }
+
+    /// Parse a sequence bracketed by '<' and '>', stopping
+    /// before the '>'.
+    pub fn parse_seq_to_before_gt<T>(&mut self,
+                                     sep: Option<token::Token>,
+                                     f: |&mut Parser| -> T)
+                                     -> OwnedSlice<T> {
+        let (result, returned) = self.parse_seq_to_before_gt_or_return(sep, |p| Some(f(p)));
+        assert!(!returned);
+        return result;
     }
 
-    pub fn parse_seq_to_gt<T>(
-                           &mut self,
-                           sep: Option<token::Token>,
-                           f: |&mut Parser| -> T)
-                           -> OwnedSlice<T> {
+    pub fn parse_seq_to_gt<T>(&mut self,
+                              sep: Option<token::Token>,
+                              f: |&mut Parser| -> T)
+                              -> OwnedSlice<T> {
         let v = self.parse_seq_to_before_gt(sep, f);
         self.expect_gt();
         return v;
     }
 
+    pub fn parse_seq_to_gt_or_return<T>(&mut self,
+                                        sep: Option<token::Token>,
+                                        f: |&mut Parser| -> Option<T>)
+                                        -> (OwnedSlice<T>, bool) {
+        let (v, returned) = self.parse_seq_to_before_gt_or_return(sep, f);
+        if !returned {
+            self.expect_gt();
+        }
+        return (v, returned);
+    }
+
     /// Parse a sequence, including the closing delimiter. The function
     /// f must consume tokens until reaching the next separator or
     /// closing bracket.
@@ -1842,11 +1863,12 @@ impl<'a> Parser<'a> {
 
             // Parse types, optionally.
             let parameters = if self.eat_lt(false) {
-                let (lifetimes, types) = self.parse_generic_values_after_lt();
+                let (lifetimes, types, bindings) = self.parse_generic_values_after_lt();
 
                 ast::AngleBracketedParameters(ast::AngleBracketedParameterData {
                     lifetimes: lifetimes,
                     types: OwnedSlice::from_vec(types),
+                    bindings: OwnedSlice::from_vec(bindings),
                 })
             } else if self.eat(&token::OpenDelim(token::Paren)) {
                 let inputs = self.parse_seq_to_end(
@@ -1894,6 +1916,7 @@ impl<'a> Parser<'a> {
                     parameters: ast::AngleBracketedParameters(ast::AngleBracketedParameterData {
                         lifetimes: Vec::new(),
                         types: OwnedSlice::empty(),
+                        bindings: OwnedSlice::empty(),
                     })
                 });
                 return segments;
@@ -1902,12 +1925,13 @@ impl<'a> Parser<'a> {
             // 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();
+                let (lifetimes, types, bindings) = self.parse_generic_values_after_lt();
                 segments.push(ast::PathSegment {
                     identifier: identifier,
                     parameters: ast::AngleBracketedParameters(ast::AngleBracketedParameterData {
                         lifetimes: lifetimes,
                         types: OwnedSlice::from_vec(types),
+                        bindings: OwnedSlice::from_vec(bindings),
                     }),
                 });
 
@@ -2435,13 +2459,18 @@ impl<'a> Parser<'a> {
                     let dot = self.last_span.hi;
                     hi = self.span.hi;
                     self.bump();
-                    let (_, tys) = if self.eat(&token::ModSep) {
+                    let (_, tys, bindings) = if self.eat(&token::ModSep) {
                         self.expect_lt();
                         self.parse_generic_values_after_lt()
                     } else {
-                        (Vec::new(), Vec::new())
+                        (Vec::new(), Vec::new(), Vec::new())
                     };
 
+                    if bindings.len() > 0 {
+                        let last_span = self.last_span;
+                        self.span_err(last_span, "type bindings are only permitted on trait paths");
+                    }
+
                     // expr.f() method call
                     match self.token {
                         token::OpenDelim(token::Paren) => {
@@ -4041,16 +4070,51 @@ impl<'a> Parser<'a> {
         }
     }
 
-    fn parse_generic_values_after_lt(&mut self) -> (Vec<ast::Lifetime>, Vec<P<Ty>> ) {
+    fn parse_generic_values_after_lt(&mut self)
+                                     -> (Vec<ast::Lifetime>, Vec<P<Ty>>, Vec<P<TypeBinding>>) {
         let lifetimes = self.parse_lifetimes(token::Comma);
-        let result = self.parse_seq_to_gt(
+
+        // First parse types.
+        let (types, returned) = self.parse_seq_to_gt_or_return(
+            Some(token::Comma),
+            |p| {
+                p.forbid_lifetime();
+                if p.look_ahead(1, |t| t == &token::Eq) {
+                    None
+                } else {
+                    Some(p.parse_ty_sum())
+                }
+            }
+        );
+
+        // If we found the `>`, don't continue.
+        if !returned {
+            return (lifetimes, types.into_vec(), Vec::new());
+        }
+
+        // Then parse type bindings.
+        let bindings = self.parse_seq_to_gt(
             Some(token::Comma),
             |p| {
                 p.forbid_lifetime();
-                p.parse_ty_sum()
+                let lo = p.span.lo;
+                let ident = p.parse_ident();
+                let found_eq = p.eat(&token::Eq);
+                if !found_eq {
+                    let span = p.span;
+                    p.span_warn(span, "whoops, no =?");
+                }
+                let ty = p.parse_ty();
+                let hi = p.span.hi;
+                let span = mk_sp(lo, hi);
+                return P(TypeBinding{id: ast::DUMMY_NODE_ID,
+                    ident: ident,
+                    ty: ty,
+                    span: span,
+                });
             }
         );
-        (lifetimes, result.into_vec())
+        (lifetimes, types.into_vec(), bindings.into_vec())
     }
 
     fn forbid_lifetime(&mut self) {
@@ -4070,29 +4134,58 @@ impl<'a> Parser<'a> {
         let mut parsed_something = false;
         loop {
             let lo = self.span.lo;
-            let ident = match self.token {
-                token::Ident(..) => self.parse_ident(),
+            let path = match self.token {
+                token::Ident(..) => self.parse_path(NoTypesAllowed),
                 _ => break,
             };
-            self.expect(&token::Colon);
 
-            let bounds = self.parse_ty_param_bounds();
-            let hi = self.span.hi;
-            let span = mk_sp(lo, hi);
+            if self.eat(&token::Colon) {
+                let bounds = self.parse_ty_param_bounds();
+                let hi = self.span.hi;
+                let span = mk_sp(lo, hi);
 
-            if bounds.len() == 0 {
-                self.span_err(span,
-                              "each predicate in a `where` clause must have \
-                               at least one bound in it");
-            }
+                if bounds.len() == 0 {
+                    self.span_err(span,
+                                  "each predicate in a `where` clause must have \
+                                   at least one bound in it");
+                }
 
-            generics.where_clause.predicates.push(ast::WherePredicate {
-                id: ast::DUMMY_NODE_ID,
-                span: span,
-                ident: ident,
-                bounds: bounds,
-            });
-            parsed_something = true;
+                let ident = match ast_util::path_to_ident(&path) {
+                    Some(ident) => ident,
+                    None => {
+                        self.span_err(path.span, "expected a single identifier \
+                                                  in bound where clause");
+                        break;
+                    }
+                };
+
+                generics.where_clause.predicates.push(
+                    ast::WherePredicate::BoundPredicate(ast::WhereBoundPredicate {
+                        id: ast::DUMMY_NODE_ID,
+                        span: span,
+                        ident: ident,
+                        bounds: bounds,
+                }));
+                parsed_something = true;
+            } else if self.eat(&token::Eq) {
+                let ty = self.parse_ty();
+                let hi = self.span.hi;
+                let span = mk_sp(lo, hi);
+                generics.where_clause.predicates.push(
+                    ast::WherePredicate::EqPredicate(ast::WhereEqPredicate {
+                        id: ast::DUMMY_NODE_ID,
+                        span: span,
+                        path: path,
+                        ty: ty,
+                }));
+                parsed_something = true;
+                // FIXME(#18433)
+                self.span_err(span, "equality constraints are not yet supported in where clauses");
+            } else {
+                let last_span = self.last_span;
+                self.span_err(last_span,
+                              "unexpected token in `where` clause");
+            }
 
             if !self.eat(&token::Comma) {
                 break