1
Fork 0

Add support for equality constraints on associated types

This commit is contained in:
Nick Cameron 2014-11-29 17:08:30 +13:00
parent da83ad8e2c
commit 397dda8aa0
29 changed files with 791 additions and 164 deletions

View file

@ -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);
}
pub fn parse_seq_to_gt<T>(
&mut self,
sep: Option<token::Token>,
f: |&mut Parser| -> T)
-> OwnedSlice<T> {
/// 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> {
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();
p.parse_ty_sum()
if p.look_ahead(1, |t| t == &token::Eq) {
None
} else {
Some(p.parse_ty_sum())
}
}
);
(lifetimes, result.into_vec())
// 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();
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, types.into_vec(), bindings.into_vec())
}
fn forbid_lifetime(&mut self) {
@ -4070,30 +4134,59 @@ 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");
}
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");
}
generics.where_clause.predicates.push(ast::WherePredicate {
id: ast::DUMMY_NODE_ID,
span: span,
ident: ident,
bounds: bounds,
});
parsed_something = true;
if !self.eat(&token::Comma) {
break
}