diff options
| author | Nick Cameron <ncameron@mozilla.com> | 2014-11-29 17:08:30 +1300 |
|---|---|---|
| committer | Nick Cameron <ncameron@mozilla.com> | 2014-12-12 19:11:59 +1300 |
| commit | 397dda8aa08ee540cffd36f542ebd1140227d0bd (patch) | |
| tree | ee4cc3c5f3434375ef05a0092f7df8154708b765 /src/libsyntax/parse | |
| parent | da83ad8e2c8e2c5f522dc59963e00f55b1f8c03b (diff) | |
| download | rust-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.rs | 177 |
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 |
