Add parser support for generalized where clauses

Implement support in the parser for generalized where clauses,
as well as the conversion of ast::WherePredicates to
ty::Predicate in `collect.rs`.
This commit is contained in:
Jared Roesch 2014-12-20 02:29:19 -08:00
parent 8f51ad2420
commit e0cac488ac
25 changed files with 507 additions and 152 deletions

View file

@ -1497,9 +1497,6 @@ impl<'a> Parser<'a> {
}
/// Parse a type.
///
/// The second parameter specifies whether the `+` binary operator is
/// allowed in the type grammar.
pub fn parse_ty(&mut self) -> P<Ty> {
maybe_whole!(no_clone self, NtTy);
@ -4179,6 +4176,10 @@ impl<'a> Parser<'a> {
}
/// Parses an optional `where` clause and places it in `generics`.
///
/// ```
/// where T : Trait<U, V> + 'b, 'a : 'b
/// ```
fn parse_where_clause(&mut self, generics: &mut ast::Generics) {
if !self.eat_keyword(keywords::Where) {
return
@ -4187,58 +4188,80 @@ impl<'a> Parser<'a> {
let mut parsed_something = false;
loop {
let lo = self.span.lo;
let path = match self.token {
token::Ident(..) => self.parse_path(NoTypesAllowed),
_ => break,
};
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");
match self.token {
token::OpenDelim(token::Brace) => {
break
}
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;
}
};
token::Lifetime(..) => {
let bounded_lifetime =
self.parse_lifetime();
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,
self.eat(&token::Colon);
// FIXME(#20049)
let bounding_lifetime =
self.parse_lifetime();
let hi = self.span.hi;
let span = mk_sp(lo, hi);
generics.where_clause.predicates.push(ast::WherePredicate::RegionPredicate(
ast::WhereRegionPredicate {
span: span,
lifetime: bounded_lifetime,
bound: bounding_lifetime
}
));
parsed_something = true;
}
_ => {
let bounded_ty = self.parse_ty();
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");
}
generics.where_clause.predicates.push(ast::WherePredicate::BoundPredicate(
ast::WhereBoundPredicate {
span: span,
bounded_ty: bounded_ty,
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: panic!("NYI"), //bounded_ty,
// ty: ty,
// }));
// parsed_something = true;
// // FIXME(#18433)
self.span_err(span,
"equality constraints are not yet supported \
in where clauses (#20041)");
} else {
let last_span = self.last_span;
self.span_err(last_span,
"unexpected token in `where` clause");
}
}
}
};
if !self.eat(&token::Comma) {
break