Auto merge of #39158 - petrochenkov:bounds, r=nikomatsakis
Bounds parsing refactoring 2 See https://github.com/rust-lang/rust/pull/37511 for previous discussion. cc @matklad Relaxed parsing rules: - zero bounds after `:` are allowed in all contexts. - zero predicates are allowed after `where`. - trailing separator `,` is allowed after predicates in `where` clauses not followed by `{`. Other parsing rules: - trailing separator `+` is still allowed in all bound lists. Code is also cleaned up and tests added. I haven't touched parsing of trait object types yet, I'll do it later.
This commit is contained in:
commit
23a94697c2
32 changed files with 564 additions and 468 deletions
|
@ -146,6 +146,12 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
|
||||||
TyKind::TraitObject(ref bounds) => {
|
TyKind::TraitObject(ref bounds) => {
|
||||||
self.no_questions_in_bounds(bounds, "trait object types", false);
|
self.no_questions_in_bounds(bounds, "trait object types", false);
|
||||||
}
|
}
|
||||||
|
TyKind::ImplTrait(ref bounds) => {
|
||||||
|
if !bounds.iter()
|
||||||
|
.any(|b| if let TraitTyParamBound(..) = *b { true } else { false }) {
|
||||||
|
self.err_handler().span_err(ty.span, "at least one trait must be specified");
|
||||||
|
}
|
||||||
|
}
|
||||||
_ => {}
|
_ => {}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -284,6 +290,26 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
|
||||||
|
|
||||||
visit::walk_vis(self, vis)
|
visit::walk_vis(self, vis)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn visit_generics(&mut self, g: &'a Generics) {
|
||||||
|
let mut seen_default = None;
|
||||||
|
for ty_param in &g.ty_params {
|
||||||
|
if ty_param.default.is_some() {
|
||||||
|
seen_default = Some(ty_param.span);
|
||||||
|
} else if let Some(span) = seen_default {
|
||||||
|
self.err_handler()
|
||||||
|
.span_err(span, "type parameters with a default must be trailing");
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for predicate in &g.where_clause.predicates {
|
||||||
|
if let WherePredicate::EqPredicate(ref predicate) = *predicate {
|
||||||
|
self.err_handler().span_err(predicate.span, "equality constraints are not yet \
|
||||||
|
supported in where clauses (#20041)");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
visit::walk_generics(self, g)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn check_crate(session: &Session, krate: &Crate) {
|
pub fn check_crate(session: &Session, krate: &Crate) {
|
||||||
|
|
|
@ -1833,11 +1833,8 @@ fn ty_generic_predicates<'a,'tcx>(ccx: &CrateCtxt<'a,'tcx>,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
&hir::WherePredicate::EqPredicate(ref eq_pred) => {
|
&hir::WherePredicate::EqPredicate(..) => {
|
||||||
// FIXME(#20041)
|
// FIXME(#20041)
|
||||||
span_bug!(eq_pred.span,
|
|
||||||
"Equality constraints are not yet \
|
|
||||||
implemented (#20041)")
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -842,8 +842,11 @@ impl Clean<WherePredicate> for hir::WherePredicate {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
hir::WherePredicate::EqPredicate(_) => {
|
hir::WherePredicate::EqPredicate(ref wrp) => {
|
||||||
unimplemented!() // FIXME(#20041)
|
WherePredicate::EqPredicate {
|
||||||
|
lhs: wrp.lhs_ty.clean(cx),
|
||||||
|
rhs: wrp.rhs_ty.clean(cx)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -22,7 +22,7 @@ use ast::{Expr, ExprKind, RangeLimits};
|
||||||
use ast::{Field, FnDecl};
|
use ast::{Field, FnDecl};
|
||||||
use ast::{ForeignItem, ForeignItemKind, FunctionRetTy};
|
use ast::{ForeignItem, ForeignItemKind, FunctionRetTy};
|
||||||
use ast::{Ident, ImplItem, Item, ItemKind};
|
use ast::{Ident, ImplItem, Item, ItemKind};
|
||||||
use ast::{Lit, LitKind, UintTy};
|
use ast::{Lifetime, LifetimeDef, Lit, LitKind, UintTy};
|
||||||
use ast::Local;
|
use ast::Local;
|
||||||
use ast::MacStmtStyle;
|
use ast::MacStmtStyle;
|
||||||
use ast::Mac_;
|
use ast::Mac_;
|
||||||
|
@ -193,14 +193,22 @@ pub enum TokenType {
|
||||||
Token(token::Token),
|
Token(token::Token),
|
||||||
Keyword(keywords::Keyword),
|
Keyword(keywords::Keyword),
|
||||||
Operator,
|
Operator,
|
||||||
|
Lifetime,
|
||||||
|
Ident,
|
||||||
|
Path,
|
||||||
|
Type,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl TokenType {
|
impl TokenType {
|
||||||
fn to_string(&self) -> String {
|
fn to_string(&self) -> String {
|
||||||
match *self {
|
match *self {
|
||||||
TokenType::Token(ref t) => format!("`{}`", Parser::token_to_string(t)),
|
TokenType::Token(ref t) => format!("`{}`", Parser::token_to_string(t)),
|
||||||
TokenType::Operator => "an operator".to_string(),
|
|
||||||
TokenType::Keyword(kw) => format!("`{}`", kw.name()),
|
TokenType::Keyword(kw) => format!("`{}`", kw.name()),
|
||||||
|
TokenType::Operator => "an operator".to_string(),
|
||||||
|
TokenType::Lifetime => "lifetime".to_string(),
|
||||||
|
TokenType::Ident => "identifier".to_string(),
|
||||||
|
TokenType::Path => "path".to_string(),
|
||||||
|
TokenType::Type => "type".to_string(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -553,6 +561,33 @@ impl<'a> Parser<'a> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn check_ident(&mut self) -> bool {
|
||||||
|
if self.token.is_ident() {
|
||||||
|
true
|
||||||
|
} else {
|
||||||
|
self.expected_tokens.push(TokenType::Ident);
|
||||||
|
false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn check_path(&mut self) -> bool {
|
||||||
|
if self.token.is_path_start() {
|
||||||
|
true
|
||||||
|
} else {
|
||||||
|
self.expected_tokens.push(TokenType::Path);
|
||||||
|
false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn check_type(&mut self) -> bool {
|
||||||
|
if self.token.can_begin_type() {
|
||||||
|
true
|
||||||
|
} else {
|
||||||
|
self.expected_tokens.push(TokenType::Type);
|
||||||
|
false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Expect and consume an `&`. If `&&` is seen, replace it with a single
|
/// Expect and consume an `&`. If `&&` is seen, replace it with a single
|
||||||
/// `&` and continue. If an `&` is not seen, signal an error.
|
/// `&` and continue. If an `&` is not seen, signal an error.
|
||||||
fn expect_and(&mut self) -> PResult<'a, ()> {
|
fn expect_and(&mut self) -> PResult<'a, ()> {
|
||||||
|
@ -639,13 +674,7 @@ impl<'a> Parser<'a> {
|
||||||
let lo = span.lo + BytePos(1);
|
let lo = span.lo + BytePos(1);
|
||||||
Ok(self.bump_with(token::Eq, lo, span.hi))
|
Ok(self.bump_with(token::Eq, lo, span.hi))
|
||||||
}
|
}
|
||||||
_ => {
|
_ => self.unexpected()
|
||||||
let gt_str = Parser::token_to_string(&token::Gt);
|
|
||||||
let this_token_str = self.this_token_to_string();
|
|
||||||
Err(self.fatal(&format!("expected `{}`, found `{}`",
|
|
||||||
gt_str,
|
|
||||||
this_token_str)))
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -972,20 +1001,11 @@ impl<'a> Parser<'a> {
|
||||||
Parses whatever can come after a `for` keyword in a type.
|
Parses whatever can come after a `for` keyword in a type.
|
||||||
The `for` hasn't been consumed.
|
The `for` hasn't been consumed.
|
||||||
|
|
||||||
Deprecated:
|
|
||||||
|
|
||||||
- for <'lt> |S| -> T
|
|
||||||
|
|
||||||
Eventually:
|
|
||||||
|
|
||||||
- for <'lt> [unsafe] [extern "ABI"] fn (S) -> T
|
- for <'lt> [unsafe] [extern "ABI"] fn (S) -> T
|
||||||
- for <'lt> path::foo(a, b)
|
- for <'lt> path::foo(a, b) + Trait + 'a
|
||||||
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
// parse <'lt>
|
|
||||||
let lo = self.span.lo;
|
let lo = self.span.lo;
|
||||||
|
|
||||||
let lifetime_defs = self.parse_late_bound_lifetime_defs()?;
|
let lifetime_defs = self.parse_late_bound_lifetime_defs()?;
|
||||||
|
|
||||||
// examine next token to decide to do
|
// examine next token to decide to do
|
||||||
|
@ -994,7 +1014,7 @@ impl<'a> Parser<'a> {
|
||||||
} else {
|
} else {
|
||||||
let hi = self.span.hi;
|
let hi = self.span.hi;
|
||||||
let trait_ref = self.parse_trait_ref()?;
|
let trait_ref = self.parse_trait_ref()?;
|
||||||
let poly_trait_ref = ast::PolyTraitRef { bound_lifetimes: lifetime_defs,
|
let poly_trait_ref = PolyTraitRef { bound_lifetimes: lifetime_defs,
|
||||||
trait_ref: trait_ref,
|
trait_ref: trait_ref,
|
||||||
span: mk_sp(lo, hi)};
|
span: mk_sp(lo, hi)};
|
||||||
let other_bounds = if self.eat(&token::BinOp(token::Plus)) {
|
let other_bounds = if self.eat(&token::BinOp(token::Plus)) {
|
||||||
|
@ -1011,18 +1031,9 @@ impl<'a> Parser<'a> {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn parse_impl_trait_type(&mut self) -> PResult<'a, TyKind> {
|
pub fn parse_impl_trait_type(&mut self) -> PResult<'a, TyKind> {
|
||||||
/*
|
// Parses whatever can come after a `impl` keyword in a type.
|
||||||
Parses whatever can come after a `impl` keyword in a type.
|
// The `impl` has already been consumed.
|
||||||
The `impl` has already been consumed.
|
Ok(ast::TyKind::ImplTrait(self.parse_ty_param_bounds()?))
|
||||||
*/
|
|
||||||
|
|
||||||
let bounds = self.parse_ty_param_bounds()?;
|
|
||||||
|
|
||||||
if !bounds.iter().any(|b| if let TraitTyParamBound(..) = *b { true } else { false }) {
|
|
||||||
self.span_err(self.prev_span, "at least one trait must be specified");
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(ast::TyKind::ImplTrait(bounds))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn parse_ty_path(&mut self) -> PResult<'a, TyKind> {
|
pub fn parse_ty_path(&mut self) -> PResult<'a, TyKind> {
|
||||||
|
@ -1030,7 +1041,7 @@ impl<'a> Parser<'a> {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// parse a TyKind::BareFn type:
|
/// parse a TyKind::BareFn type:
|
||||||
pub fn parse_ty_bare_fn(&mut self, lifetime_defs: Vec<ast::LifetimeDef>)
|
pub fn parse_ty_bare_fn(&mut self, lifetime_defs: Vec<LifetimeDef>)
|
||||||
-> PResult<'a, TyKind> {
|
-> PResult<'a, TyKind> {
|
||||||
/*
|
/*
|
||||||
|
|
||||||
|
@ -1202,13 +1213,6 @@ impl<'a> Parser<'a> {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Parse a possibly mutable type
|
|
||||||
pub fn parse_mt(&mut self) -> PResult<'a, MutTy> {
|
|
||||||
let mutbl = self.parse_mutability()?;
|
|
||||||
let t = self.parse_ty_no_plus()?;
|
|
||||||
Ok(MutTy { ty: t, mutbl: mutbl })
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Parse optional return type [ -> TY ] in function decl
|
/// Parse optional return type [ -> TY ] in function decl
|
||||||
pub fn parse_ret_ty(&mut self) -> PResult<'a, FunctionRetTy> {
|
pub fn parse_ret_ty(&mut self) -> PResult<'a, FunctionRetTy> {
|
||||||
if self.eat(&token::RArrow) {
|
if self.eat(&token::RArrow) {
|
||||||
|
@ -1260,8 +1264,8 @@ impl<'a> Parser<'a> {
|
||||||
pprust::ty_to_string(&lhs));
|
pprust::ty_to_string(&lhs));
|
||||||
err.span_label(lhs.span, &format!("expected a path"));
|
err.span_label(lhs.span, &format!("expected a path"));
|
||||||
let hi = bounds.iter().map(|x| match *x {
|
let hi = bounds.iter().map(|x| match *x {
|
||||||
ast::TraitTyParamBound(ref tr, _) => tr.span.hi,
|
TraitTyParamBound(ref tr, _) => tr.span.hi,
|
||||||
ast::RegionTyParamBound(ref r) => r.span.hi,
|
RegionTyParamBound(ref r) => r.span.hi,
|
||||||
}).max_by_key(|x| x.to_usize());
|
}).max_by_key(|x| x.to_usize());
|
||||||
let full_span = hi.map(|hi| Span {
|
let full_span = hi.map(|hi| Span {
|
||||||
lo: lhs.span.lo,
|
lo: lhs.span.lo,
|
||||||
|
@ -1309,9 +1313,7 @@ impl<'a> Parser<'a> {
|
||||||
|
|
||||||
let lo = self.span.lo;
|
let lo = self.span.lo;
|
||||||
|
|
||||||
let t = if self.check(&token::OpenDelim(token::Paren)) {
|
let t = if self.eat(&token::OpenDelim(token::Paren)) {
|
||||||
self.bump();
|
|
||||||
|
|
||||||
// (t) is a parenthesized ty
|
// (t) is a parenthesized ty
|
||||||
// (t,) is the type of a tuple with only one field,
|
// (t,) is the type of a tuple with only one field,
|
||||||
// of type t
|
// of type t
|
||||||
|
@ -1319,9 +1321,8 @@ impl<'a> Parser<'a> {
|
||||||
let mut last_comma = false;
|
let mut last_comma = false;
|
||||||
while self.token != token::CloseDelim(token::Paren) {
|
while self.token != token::CloseDelim(token::Paren) {
|
||||||
ts.push(self.parse_ty()?);
|
ts.push(self.parse_ty()?);
|
||||||
if self.check(&token::Comma) {
|
if self.eat(&token::Comma) {
|
||||||
last_comma = true;
|
last_comma = true;
|
||||||
self.bump();
|
|
||||||
} else {
|
} else {
|
||||||
last_comma = false;
|
last_comma = false;
|
||||||
break;
|
break;
|
||||||
|
@ -1336,13 +1337,11 @@ impl<'a> Parser<'a> {
|
||||||
}
|
}
|
||||||
} else if self.eat(&token::Not) {
|
} else if self.eat(&token::Not) {
|
||||||
TyKind::Never
|
TyKind::Never
|
||||||
} else if self.check(&token::BinOp(token::Star)) {
|
} else if self.eat(&token::BinOp(token::Star)) {
|
||||||
// STAR POINTER (bare pointer?)
|
// STAR POINTER (bare pointer?)
|
||||||
self.bump();
|
|
||||||
TyKind::Ptr(self.parse_ptr()?)
|
TyKind::Ptr(self.parse_ptr()?)
|
||||||
} else if self.check(&token::OpenDelim(token::Bracket)) {
|
} else if self.eat(&token::OpenDelim(token::Bracket)) {
|
||||||
// VECTOR
|
// VECTOR
|
||||||
self.expect(&token::OpenDelim(token::Bracket))?;
|
|
||||||
let t = self.parse_ty()?;
|
let t = self.parse_ty()?;
|
||||||
|
|
||||||
// Parse the `; e` in `[ i32; e ]`
|
// Parse the `; e` in `[ i32; e ]`
|
||||||
|
@ -1354,13 +1353,15 @@ impl<'a> Parser<'a> {
|
||||||
self.expect(&token::CloseDelim(token::Bracket))?;
|
self.expect(&token::CloseDelim(token::Bracket))?;
|
||||||
t
|
t
|
||||||
} else if self.check(&token::BinOp(token::And)) ||
|
} else if self.check(&token::BinOp(token::And)) ||
|
||||||
self.token == token::AndAnd {
|
self.check(&token::AndAnd) {
|
||||||
// BORROWED POINTER
|
// BORROWED POINTER
|
||||||
self.expect_and()?;
|
self.expect_and()?;
|
||||||
self.parse_borrowed_pointee()?
|
self.parse_borrowed_pointee()?
|
||||||
} else if self.check_keyword(keywords::For) {
|
} else if self.check_keyword(keywords::For) {
|
||||||
|
// FIXME `+` has incorrect priority in trait object types starting with `for` (#39317).
|
||||||
self.parse_for_in_type()?
|
self.parse_for_in_type()?
|
||||||
} else if self.eat_keyword(keywords::Impl) {
|
} else if self.eat_keyword(keywords::Impl) {
|
||||||
|
// FIXME figure out priority of `+` in `impl Trait1 + Trait2` (#34511).
|
||||||
self.parse_impl_trait_type()?
|
self.parse_impl_trait_type()?
|
||||||
} else if self.token_is_bare_fn_keyword() {
|
} else if self.token_is_bare_fn_keyword() {
|
||||||
// BARE FUNCTION
|
// BARE FUNCTION
|
||||||
|
@ -1373,10 +1374,7 @@ impl<'a> Parser<'a> {
|
||||||
self.expect(&token::CloseDelim(token::Paren))?;
|
self.expect(&token::CloseDelim(token::Paren))?;
|
||||||
TyKind::Typeof(e)
|
TyKind::Typeof(e)
|
||||||
} else if self.eat_lt() {
|
} else if self.eat_lt() {
|
||||||
|
let (qself, path) = self.parse_qualified_path(PathStyle::Type)?;
|
||||||
let (qself, path) =
|
|
||||||
self.parse_qualified_path(PathStyle::Type)?;
|
|
||||||
|
|
||||||
TyKind::Path(Some(qself), path)
|
TyKind::Path(Some(qself), path)
|
||||||
} else if self.token.is_path_start() {
|
} else if self.token.is_path_start() {
|
||||||
let path = self.parse_path(PathStyle::Type)?;
|
let path = self.parse_path(PathStyle::Type)?;
|
||||||
|
@ -1406,10 +1404,10 @@ impl<'a> Parser<'a> {
|
||||||
|
|
||||||
pub fn parse_borrowed_pointee(&mut self) -> PResult<'a, TyKind> {
|
pub fn parse_borrowed_pointee(&mut self) -> PResult<'a, TyKind> {
|
||||||
// look for `&'lt` or `&'foo ` and interpret `foo` as the region name:
|
// look for `&'lt` or `&'foo ` and interpret `foo` as the region name:
|
||||||
let opt_lifetime = self.parse_opt_lifetime()?;
|
let opt_lifetime = self.eat_lifetime();
|
||||||
|
let mutbl = self.parse_mutability()?;
|
||||||
let mt = self.parse_mt()?;
|
let ty = self.parse_ty_no_plus()?;
|
||||||
return Ok(TyKind::Rptr(opt_lifetime, mt));
|
return Ok(TyKind::Rptr(opt_lifetime, MutTy { ty: ty, mutbl: mutbl }));
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn parse_ptr(&mut self) -> PResult<'a, MutTy> {
|
pub fn parse_ptr(&mut self) -> PResult<'a, MutTy> {
|
||||||
|
@ -1505,8 +1503,7 @@ impl<'a> Parser<'a> {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn maybe_parse_fixed_length_of_vec(&mut self) -> PResult<'a, Option<P<ast::Expr>>> {
|
pub fn maybe_parse_fixed_length_of_vec(&mut self) -> PResult<'a, Option<P<ast::Expr>>> {
|
||||||
if self.check(&token::Semi) {
|
if self.eat(&token::Semi) {
|
||||||
self.bump();
|
|
||||||
Ok(Some(self.parse_expr()?))
|
Ok(Some(self.parse_expr()?))
|
||||||
} else {
|
} else {
|
||||||
Ok(None)
|
Ok(None)
|
||||||
|
@ -1728,7 +1725,8 @@ impl<'a> Parser<'a> {
|
||||||
|
|
||||||
// Parse types, optionally.
|
// Parse types, optionally.
|
||||||
let parameters = if self.eat_lt() {
|
let parameters = if self.eat_lt() {
|
||||||
let (lifetimes, types, bindings) = self.parse_generic_values_after_lt()?;
|
let (lifetimes, types, bindings) = self.parse_generic_args()?;
|
||||||
|
self.expect_gt()?;
|
||||||
ast::AngleBracketedParameterData {
|
ast::AngleBracketedParameterData {
|
||||||
lifetimes: lifetimes,
|
lifetimes: lifetimes,
|
||||||
types: types,
|
types: types,
|
||||||
|
@ -1786,7 +1784,8 @@ impl<'a> Parser<'a> {
|
||||||
// Check for a type segment.
|
// Check for a type segment.
|
||||||
if self.eat_lt() {
|
if self.eat_lt() {
|
||||||
// Consumed `a::b::<`, go look for types
|
// Consumed `a::b::<`, go look for types
|
||||||
let (lifetimes, types, bindings) = self.parse_generic_values_after_lt()?;
|
let (lifetimes, types, bindings) = self.parse_generic_args()?;
|
||||||
|
self.expect_gt()?;
|
||||||
segments.push(ast::PathSegment {
|
segments.push(ast::PathSegment {
|
||||||
identifier: identifier,
|
identifier: identifier,
|
||||||
parameters: ast::AngleBracketedParameterData {
|
parameters: ast::AngleBracketedParameterData {
|
||||||
|
@ -1828,124 +1827,24 @@ impl<'a> Parser<'a> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// parses 0 or 1 lifetime
|
/// Parse single lifetime 'a or nothing.
|
||||||
pub fn parse_opt_lifetime(&mut self) -> PResult<'a, Option<ast::Lifetime>> {
|
pub fn eat_lifetime(&mut self) -> Option<Lifetime> {
|
||||||
match self.token {
|
match self.token {
|
||||||
token::Lifetime(..) => {
|
token::Lifetime(ident) => {
|
||||||
Ok(Some(self.parse_lifetime()?))
|
|
||||||
}
|
|
||||||
_ => {
|
|
||||||
Ok(None)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Parses a single lifetime
|
|
||||||
/// Matches lifetime = LIFETIME
|
|
||||||
pub fn parse_lifetime(&mut self) -> PResult<'a, ast::Lifetime> {
|
|
||||||
match self.token {
|
|
||||||
token::Lifetime(i) => {
|
|
||||||
let span = self.span;
|
|
||||||
self.bump();
|
self.bump();
|
||||||
return Ok(ast::Lifetime {
|
Some(Lifetime {
|
||||||
id: ast::DUMMY_NODE_ID,
|
id: ast::DUMMY_NODE_ID,
|
||||||
span: span,
|
span: self.prev_span,
|
||||||
name: i.name
|
name: ident.name
|
||||||
});
|
})
|
||||||
}
|
}
|
||||||
_ => {
|
_ => {
|
||||||
return Err(self.fatal("expected a lifetime name"));
|
self.expected_tokens.push(TokenType::Lifetime);
|
||||||
|
None
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Parses `lifetime_defs = [ lifetime_defs { ',' lifetime_defs } ]` where `lifetime_def =
|
|
||||||
/// lifetime [':' lifetimes]`
|
|
||||||
///
|
|
||||||
/// If `followed_by_ty_params` is None, then we are in a context
|
|
||||||
/// where only lifetime parameters are allowed, and thus we should
|
|
||||||
/// error if we encounter attributes after the bound lifetimes.
|
|
||||||
///
|
|
||||||
/// If `followed_by_ty_params` is Some(r), then there may be type
|
|
||||||
/// parameter bindings after the lifetimes, so we should pass
|
|
||||||
/// along the parsed attributes to be attached to the first such
|
|
||||||
/// type parmeter.
|
|
||||||
pub fn parse_lifetime_defs(&mut self,
|
|
||||||
followed_by_ty_params: Option<&mut Vec<ast::Attribute>>)
|
|
||||||
-> PResult<'a, Vec<ast::LifetimeDef>>
|
|
||||||
{
|
|
||||||
let mut res = Vec::new();
|
|
||||||
loop {
|
|
||||||
let attrs = self.parse_outer_attributes()?;
|
|
||||||
match self.token {
|
|
||||||
token::Lifetime(_) => {
|
|
||||||
let lifetime = self.parse_lifetime()?;
|
|
||||||
let bounds =
|
|
||||||
if self.eat(&token::Colon) {
|
|
||||||
self.parse_lifetimes(token::BinOp(token::Plus))?
|
|
||||||
} else {
|
|
||||||
Vec::new()
|
|
||||||
};
|
|
||||||
res.push(ast::LifetimeDef { attrs: attrs.into(),
|
|
||||||
lifetime: lifetime,
|
|
||||||
bounds: bounds });
|
|
||||||
}
|
|
||||||
|
|
||||||
_ => {
|
|
||||||
if let Some(recv) = followed_by_ty_params {
|
|
||||||
assert!(recv.is_empty());
|
|
||||||
*recv = attrs;
|
|
||||||
debug!("parse_lifetime_defs ret {:?}", res);
|
|
||||||
return Ok(res);
|
|
||||||
} else if !attrs.is_empty() {
|
|
||||||
let msg = "trailing attribute after lifetime parameters";
|
|
||||||
return Err(self.fatal(msg));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
match self.token {
|
|
||||||
token::Comma => { self.bump();}
|
|
||||||
token::Gt => { return Ok(res); }
|
|
||||||
token::BinOp(token::Shr) => { return Ok(res); }
|
|
||||||
_ => {
|
|
||||||
let this_token_str = self.this_token_to_string();
|
|
||||||
let msg = format!("expected `,` or `>` after lifetime \
|
|
||||||
name, found `{}`",
|
|
||||||
this_token_str);
|
|
||||||
return Err(self.fatal(&msg[..]));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// matches lifetimes = ( lifetime ) | ( lifetime , lifetimes ) actually, it matches the empty
|
|
||||||
/// one too, but putting that in there messes up the grammar....
|
|
||||||
///
|
|
||||||
/// Parses zero or more comma separated lifetimes. Expects each lifetime to be followed by
|
|
||||||
/// either a comma or `>`. Used when parsing type parameter lists, where we expect something
|
|
||||||
/// like `<'a, 'b, T>`.
|
|
||||||
pub fn parse_lifetimes(&mut self, sep: token::Token) -> PResult<'a, Vec<ast::Lifetime>> {
|
|
||||||
|
|
||||||
let mut res = Vec::new();
|
|
||||||
loop {
|
|
||||||
match self.token {
|
|
||||||
token::Lifetime(_) => {
|
|
||||||
res.push(self.parse_lifetime()?);
|
|
||||||
}
|
|
||||||
_ => {
|
|
||||||
return Ok(res);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if self.token != sep {
|
|
||||||
return Ok(res);
|
|
||||||
}
|
|
||||||
|
|
||||||
self.bump();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Parse mutability (`mut` or nothing).
|
/// Parse mutability (`mut` or nothing).
|
||||||
pub fn parse_mutability(&mut self) -> PResult<'a, Mutability> {
|
pub fn parse_mutability(&mut self) -> PResult<'a, Mutability> {
|
||||||
if self.eat_keyword(keywords::Mut) {
|
if self.eat_keyword(keywords::Mut) {
|
||||||
|
@ -2459,7 +2358,9 @@ impl<'a> Parser<'a> {
|
||||||
-> PResult<'a, P<Expr>> {
|
-> PResult<'a, P<Expr>> {
|
||||||
let (_, tys, bindings) = if self.eat(&token::ModSep) {
|
let (_, tys, bindings) = if self.eat(&token::ModSep) {
|
||||||
self.expect_lt()?;
|
self.expect_lt()?;
|
||||||
self.parse_generic_values_after_lt()?
|
let args = self.parse_generic_args()?;
|
||||||
|
self.expect_gt()?;
|
||||||
|
args
|
||||||
} else {
|
} else {
|
||||||
(Vec::new(), Vec::new(), Vec::new())
|
(Vec::new(), Vec::new(), Vec::new())
|
||||||
};
|
};
|
||||||
|
@ -4094,69 +3995,68 @@ impl<'a> Parser<'a> {
|
||||||
}).emit();
|
}).emit();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Parses a sequence of bounds if a `:` is found,
|
// Parse bounds of a type parameter `BOUND + BOUND + BOUND` without trailing `+`.
|
||||||
// otherwise returns empty list.
|
// BOUND = TY_BOUND | LT_BOUND
|
||||||
fn parse_colon_then_ty_param_bounds(&mut self) -> PResult<'a, TyParamBounds>
|
// LT_BOUND = LIFETIME (e.g. `'a`)
|
||||||
{
|
// TY_BOUND = [?] [for<LT_PARAM_DEFS>] SIMPLE_PATH (e.g. `?for<'a: 'b> m::Trait<'a>`)
|
||||||
if !self.eat(&token::Colon) {
|
|
||||||
Ok(Vec::new())
|
|
||||||
} else {
|
|
||||||
self.parse_ty_param_bounds()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// matches bounds = ( boundseq )?
|
|
||||||
// where boundseq = ( polybound + boundseq ) | polybound
|
|
||||||
// and polybound = ( 'for' '<' 'region '>' )? bound
|
|
||||||
// and bound = 'region | trait_ref
|
|
||||||
fn parse_ty_param_bounds(&mut self) -> PResult<'a, TyParamBounds>
|
fn parse_ty_param_bounds(&mut self) -> PResult<'a, TyParamBounds>
|
||||||
{
|
{
|
||||||
let mut result = vec![];
|
let mut bounds = Vec::new();
|
||||||
loop {
|
loop {
|
||||||
let question_span = self.span;
|
let question = if self.eat(&token::Question) { Some(self.prev_span) } else { None };
|
||||||
let ate_question = self.eat(&token::Question);
|
if let Some(lifetime) = self.eat_lifetime() {
|
||||||
match self.token {
|
if let Some(question_span) = question {
|
||||||
token::Lifetime(lifetime) => {
|
|
||||||
if ate_question {
|
|
||||||
self.span_err(question_span,
|
self.span_err(question_span,
|
||||||
"`?` may only modify trait bounds, not lifetime bounds");
|
"`?` may only modify trait bounds, not lifetime bounds");
|
||||||
}
|
}
|
||||||
result.push(RegionTyParamBound(ast::Lifetime {
|
bounds.push(RegionTyParamBound(lifetime));
|
||||||
id: ast::DUMMY_NODE_ID,
|
} else {if self.check_keyword(keywords::For) || self.check_path() {
|
||||||
span: self.span,
|
|
||||||
name: lifetime.name
|
|
||||||
}));
|
|
||||||
self.bump();
|
|
||||||
}
|
|
||||||
_ if self.token.is_path_start() || self.token.is_keyword(keywords::For) => {
|
|
||||||
let poly_trait_ref = self.parse_poly_trait_ref()?;
|
let poly_trait_ref = self.parse_poly_trait_ref()?;
|
||||||
let modifier = if ate_question {
|
let modifier = if question.is_some() {
|
||||||
TraitBoundModifier::Maybe
|
TraitBoundModifier::Maybe
|
||||||
} else {
|
} else {
|
||||||
TraitBoundModifier::None
|
TraitBoundModifier::None
|
||||||
};
|
};
|
||||||
result.push(TraitTyParamBound(poly_trait_ref, modifier))
|
bounds.push(TraitTyParamBound(poly_trait_ref, modifier));
|
||||||
}
|
} else {
|
||||||
_ => break,
|
break
|
||||||
}
|
}}
|
||||||
|
|
||||||
if !self.eat(&token::BinOp(token::Plus)) {
|
if !self.eat(&token::BinOp(token::Plus)) {
|
||||||
break;
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return Ok(result);
|
return Ok(bounds);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Parse bounds of a type parameter `BOUND + BOUND + BOUND` without trailing `+`.
|
||||||
|
// BOUND = LT_BOUND (e.g. `'a`)
|
||||||
|
fn parse_lt_param_bounds(&mut self) -> Vec<Lifetime> {
|
||||||
|
let mut lifetimes = Vec::new();
|
||||||
|
while let Some(lifetime) = self.eat_lifetime() {
|
||||||
|
lifetimes.push(lifetime);
|
||||||
|
|
||||||
|
if !self.eat(&token::BinOp(token::Plus)) {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
lifetimes
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Matches typaram = IDENT (`?` unbound)? optbounds ( EQ ty )?
|
/// Matches typaram = IDENT (`?` unbound)? optbounds ( EQ ty )?
|
||||||
fn parse_ty_param(&mut self, preceding_attrs: Vec<ast::Attribute>) -> PResult<'a, TyParam> {
|
fn parse_ty_param(&mut self, preceding_attrs: Vec<Attribute>) -> PResult<'a, TyParam> {
|
||||||
let span = self.span;
|
let span = self.span;
|
||||||
let ident = self.parse_ident()?;
|
let ident = self.parse_ident()?;
|
||||||
|
|
||||||
let bounds = self.parse_colon_then_ty_param_bounds()?;
|
// Parse optional colon and param bounds.
|
||||||
|
let bounds = if self.eat(&token::Colon) {
|
||||||
|
self.parse_ty_param_bounds()?
|
||||||
|
} else {
|
||||||
|
Vec::new()
|
||||||
|
};
|
||||||
|
|
||||||
let default = if self.check(&token::Eq) {
|
let default = if self.eat(&token::Eq) {
|
||||||
self.bump();
|
|
||||||
Some(self.parse_ty()?)
|
Some(self.parse_ty()?)
|
||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
|
@ -4172,6 +4072,51 @@ impl<'a> Parser<'a> {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Parses (possibly empty) list of lifetime and type parameters, possibly including
|
||||||
|
/// trailing comma and erroneous trailing attributes.
|
||||||
|
pub fn parse_generic_params(&mut self) -> PResult<'a, (Vec<LifetimeDef>, Vec<TyParam>)> {
|
||||||
|
let mut lifetime_defs = Vec::new();
|
||||||
|
let mut ty_params = Vec::new();
|
||||||
|
let mut seen_ty_param = false;
|
||||||
|
loop {
|
||||||
|
let attrs = self.parse_outer_attributes()?;
|
||||||
|
if let Some(lifetime) = self.eat_lifetime() {
|
||||||
|
// Parse lifetime parameter.
|
||||||
|
let bounds = if self.eat(&token::Colon) {
|
||||||
|
self.parse_lt_param_bounds()
|
||||||
|
} else {
|
||||||
|
Vec::new()
|
||||||
|
};
|
||||||
|
lifetime_defs.push(LifetimeDef {
|
||||||
|
attrs: attrs.into(),
|
||||||
|
lifetime: lifetime,
|
||||||
|
bounds: bounds,
|
||||||
|
});
|
||||||
|
if seen_ty_param {
|
||||||
|
self.span_err(self.prev_span,
|
||||||
|
"lifetime parameters must be declared prior to type parameters");
|
||||||
|
}
|
||||||
|
} else {if self.check_ident() {
|
||||||
|
// Parse type parameter.
|
||||||
|
ty_params.push(self.parse_ty_param(attrs)?);
|
||||||
|
seen_ty_param = true;
|
||||||
|
} else {
|
||||||
|
// Check for trailing attributes and stop parsing.
|
||||||
|
if !attrs.is_empty() {
|
||||||
|
let param_kind = if seen_ty_param { "type" } else { "lifetime" };
|
||||||
|
self.span_err(attrs[0].span,
|
||||||
|
&format!("trailing attribute after {} parameters", param_kind));
|
||||||
|
}
|
||||||
|
break
|
||||||
|
}}
|
||||||
|
|
||||||
|
if !self.eat(&token::Comma) {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Ok((lifetime_defs, ty_params))
|
||||||
|
}
|
||||||
|
|
||||||
/// Parse a set of optional generic type parameter declarations. Where
|
/// Parse a set of optional generic type parameter declarations. Where
|
||||||
/// clauses are not parsed here, and must be added later via
|
/// clauses are not parsed here, and must be added later via
|
||||||
/// `parse_where_clause()`.
|
/// `parse_where_clause()`.
|
||||||
|
@ -4181,45 +4126,11 @@ impl<'a> Parser<'a> {
|
||||||
/// where typaramseq = ( typaram ) | ( typaram , typaramseq )
|
/// where typaramseq = ( typaram ) | ( typaram , typaramseq )
|
||||||
pub fn parse_generics(&mut self) -> PResult<'a, ast::Generics> {
|
pub fn parse_generics(&mut self) -> PResult<'a, ast::Generics> {
|
||||||
maybe_whole!(self, NtGenerics, |x| x);
|
maybe_whole!(self, NtGenerics, |x| x);
|
||||||
let span_lo = self.span.lo;
|
|
||||||
|
|
||||||
if self.eat(&token::Lt) {
|
let span_lo = self.span.lo;
|
||||||
// Upon encountering attribute in generics list, we do not
|
if self.eat_lt() {
|
||||||
// know if it is attached to lifetime or to type param.
|
let (lifetime_defs, ty_params) = self.parse_generic_params()?;
|
||||||
//
|
self.expect_gt()?;
|
||||||
// Solution: 1. eagerly parse attributes in tandem with
|
|
||||||
// lifetime defs, 2. store last set of parsed (and unused)
|
|
||||||
// attributes in `attrs`, and 3. pass in those attributes
|
|
||||||
// when parsing formal type param after lifetime defs.
|
|
||||||
let mut attrs = vec![];
|
|
||||||
let lifetime_defs = self.parse_lifetime_defs(Some(&mut attrs))?;
|
|
||||||
let mut seen_default = false;
|
|
||||||
let mut post_lifetime_attrs = Some(attrs);
|
|
||||||
let ty_params = self.parse_seq_to_gt(Some(token::Comma), |p| {
|
|
||||||
p.forbid_lifetime()?;
|
|
||||||
// Move out of `post_lifetime_attrs` if present. O/w
|
|
||||||
// not first type param: parse attributes anew.
|
|
||||||
let attrs = match post_lifetime_attrs.as_mut() {
|
|
||||||
None => p.parse_outer_attributes()?,
|
|
||||||
Some(attrs) => mem::replace(attrs, vec![]),
|
|
||||||
};
|
|
||||||
post_lifetime_attrs = None;
|
|
||||||
let ty_param = p.parse_ty_param(attrs)?;
|
|
||||||
if ty_param.default.is_some() {
|
|
||||||
seen_default = true;
|
|
||||||
} else if seen_default {
|
|
||||||
let prev_span = p.prev_span;
|
|
||||||
p.span_err(prev_span,
|
|
||||||
"type parameters with a default must be trailing");
|
|
||||||
}
|
|
||||||
Ok(ty_param)
|
|
||||||
})?;
|
|
||||||
if let Some(attrs) = post_lifetime_attrs {
|
|
||||||
if !attrs.is_empty() {
|
|
||||||
self.span_err(attrs[0].span,
|
|
||||||
"trailing attribute after lifetime parameters");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Ok(ast::Generics {
|
Ok(ast::Generics {
|
||||||
lifetimes: lifetime_defs,
|
lifetimes: lifetime_defs,
|
||||||
ty_params: ty_params,
|
ty_params: ty_params,
|
||||||
|
@ -4234,85 +4145,52 @@ impl<'a> Parser<'a> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn parse_generic_values_after_lt(&mut self) -> PResult<'a, (Vec<ast::Lifetime>,
|
/// Parses (possibly empty) list of lifetime and type arguments and associated type bindings,
|
||||||
Vec<P<Ty>>,
|
/// possibly including trailing comma.
|
||||||
Vec<TypeBinding>)> {
|
fn parse_generic_args(&mut self) -> PResult<'a, (Vec<Lifetime>, Vec<P<Ty>>, Vec<TypeBinding>)> {
|
||||||
let span_lo = self.span.lo;
|
let mut lifetimes = Vec::new();
|
||||||
let lifetimes = self.parse_lifetimes(token::Comma)?;
|
let mut types = Vec::new();
|
||||||
|
let mut bindings = Vec::new();
|
||||||
let missing_comma = !lifetimes.is_empty() &&
|
let mut seen_type = false;
|
||||||
!self.token.is_like_gt() &&
|
let mut seen_binding = false;
|
||||||
self.prev_token_kind != PrevTokenKind::Comma;
|
loop {
|
||||||
|
if let Some(lifetime) = self.eat_lifetime() {
|
||||||
if missing_comma {
|
// Parse lifetime argument.
|
||||||
|
lifetimes.push(lifetime);
|
||||||
let msg = format!("expected `,` or `>` after lifetime \
|
if seen_type || seen_binding {
|
||||||
name, found `{}`",
|
self.span_err(self.prev_span,
|
||||||
self.this_token_to_string());
|
"lifetime parameters must be declared prior to type parameters");
|
||||||
let mut err = self.diagnostic().struct_span_err(self.span, &msg);
|
|
||||||
|
|
||||||
let span_hi = self.span.hi;
|
|
||||||
let span_hi = match self.parse_ty_no_plus() {
|
|
||||||
Ok(..) => self.span.hi,
|
|
||||||
Err(ref mut err) => {
|
|
||||||
self.cancel(err);
|
|
||||||
span_hi
|
|
||||||
}
|
}
|
||||||
};
|
} else {if self.check_ident() && self.look_ahead(1, |t| t == &token::Eq) {
|
||||||
|
// Parse associated type binding.
|
||||||
let msg = format!("did you mean a single argument type &'a Type, \
|
let lo = self.span.lo;
|
||||||
or did you mean the comma-separated arguments \
|
let ident = self.parse_ident()?;
|
||||||
'a, Type?");
|
self.bump();
|
||||||
err.span_note(mk_sp(span_lo, span_hi), &msg);
|
let ty = self.parse_ty()?;
|
||||||
return Err(err);
|
bindings.push(TypeBinding {
|
||||||
}
|
id: ast::DUMMY_NODE_ID,
|
||||||
|
|
||||||
// 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) {
|
|
||||||
Ok(None)
|
|
||||||
} else {
|
|
||||||
Ok(Some(p.parse_ty()?))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
)?;
|
|
||||||
|
|
||||||
// If we found the `>`, don't continue.
|
|
||||||
if !returned {
|
|
||||||
return Ok((lifetimes, types, 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()?;
|
|
||||||
p.expect(&token::Eq)?;
|
|
||||||
let ty = p.parse_ty_no_plus()?;
|
|
||||||
let hi = ty.span.hi;
|
|
||||||
let span = mk_sp(lo, hi);
|
|
||||||
return Ok(TypeBinding{id: ast::DUMMY_NODE_ID,
|
|
||||||
ident: ident,
|
ident: ident,
|
||||||
ty: ty,
|
ty: ty,
|
||||||
span: span,
|
span: mk_sp(lo, self.prev_span.hi),
|
||||||
});
|
});
|
||||||
|
seen_binding = true;
|
||||||
|
} else if self.check_type() {
|
||||||
|
// Parse type argument.
|
||||||
|
types.push(self.parse_ty()?);
|
||||||
|
if seen_binding {
|
||||||
|
self.span_err(types[types.len() - 1].span,
|
||||||
|
"type parameters must be declared prior to associated type bindings");
|
||||||
}
|
}
|
||||||
)?;
|
seen_type = true;
|
||||||
Ok((lifetimes, types, bindings))
|
} else {
|
||||||
}
|
break
|
||||||
|
}}
|
||||||
|
|
||||||
fn forbid_lifetime(&mut self) -> PResult<'a, ()> {
|
if !self.eat(&token::Comma) {
|
||||||
if self.token.is_lifetime() {
|
break
|
||||||
let span = self.span;
|
|
||||||
return Err(self.diagnostic().struct_span_err(span, "lifetime parameters must be \
|
|
||||||
declared prior to type parameters"))
|
|
||||||
}
|
}
|
||||||
Ok(())
|
}
|
||||||
|
Ok((lifetimes, types, bindings))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Parses an optional `where` clause and places it in `generics`.
|
/// Parses an optional `where` clause and places it in `generics`.
|
||||||
|
@ -4320,7 +4198,7 @@ impl<'a> Parser<'a> {
|
||||||
/// ```ignore
|
/// ```ignore
|
||||||
/// where T : Trait<U, V> + 'b, 'a : 'b
|
/// where T : Trait<U, V> + 'b, 'a : 'b
|
||||||
/// ```
|
/// ```
|
||||||
pub fn parse_where_clause(&mut self) -> PResult<'a, ast::WhereClause> {
|
pub fn parse_where_clause(&mut self) -> PResult<'a, WhereClause> {
|
||||||
maybe_whole!(self, NtWhereClause, |x| x);
|
maybe_whole!(self, NtWhereClause, |x| x);
|
||||||
|
|
||||||
let mut where_clause = WhereClause {
|
let mut where_clause = WhereClause {
|
||||||
|
@ -4332,7 +4210,7 @@ impl<'a> Parser<'a> {
|
||||||
return Ok(where_clause);
|
return Ok(where_clause);
|
||||||
}
|
}
|
||||||
|
|
||||||
// This is a temporary hack.
|
// This is a temporary future proofing.
|
||||||
//
|
//
|
||||||
// We are considering adding generics to the `where` keyword as an alternative higher-rank
|
// We are considering adding generics to the `where` keyword as an alternative higher-rank
|
||||||
// parameter syntax (as in `where<'a>` or `where<T>`. To avoid that being a breaking
|
// parameter syntax (as in `where<'a>` or `where<T>`. To avoid that being a breaking
|
||||||
|
@ -4349,106 +4227,64 @@ impl<'a> Parser<'a> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut parsed_something = false;
|
|
||||||
loop {
|
loop {
|
||||||
let lo = self.span.lo;
|
let lo = self.span.lo;
|
||||||
match self.token {
|
if let Some(lifetime) = self.eat_lifetime() {
|
||||||
token::OpenDelim(token::Brace) => {
|
// Bounds starting with a colon are mandatory, but possibly empty.
|
||||||
break
|
|
||||||
}
|
|
||||||
|
|
||||||
token::Lifetime(..) => {
|
|
||||||
let bounded_lifetime =
|
|
||||||
self.parse_lifetime()?;
|
|
||||||
|
|
||||||
self.expect(&token::Colon)?;
|
self.expect(&token::Colon)?;
|
||||||
|
let bounds = self.parse_lt_param_bounds();
|
||||||
let bounds =
|
|
||||||
self.parse_lifetimes(token::BinOp(token::Plus))?;
|
|
||||||
|
|
||||||
let hi = self.prev_span.hi;
|
|
||||||
let span = mk_sp(lo, hi);
|
|
||||||
|
|
||||||
where_clause.predicates.push(ast::WherePredicate::RegionPredicate(
|
where_clause.predicates.push(ast::WherePredicate::RegionPredicate(
|
||||||
ast::WhereRegionPredicate {
|
ast::WhereRegionPredicate {
|
||||||
span: span,
|
span: mk_sp(lo, self.prev_span.hi),
|
||||||
lifetime: bounded_lifetime,
|
lifetime: lifetime,
|
||||||
bounds: bounds
|
bounds: bounds,
|
||||||
}
|
}
|
||||||
));
|
));
|
||||||
|
} else {if self.check_type() {
|
||||||
|
// Parse optional `for<'a, 'b>`.
|
||||||
|
// This `for` is parsed greedily and applies to the whole predicate,
|
||||||
|
// the bounded type can have its own `for` applying only to it.
|
||||||
|
// Example 1: for<'a> Trait1<'a>: Trait2<'a /*ok*/>
|
||||||
|
// Example 2: (for<'a> Trait1<'a>): Trait2<'a /*not ok*/>
|
||||||
|
// Example 3: for<'a> for<'b> Trait1<'a, 'b>: Trait2<'a /*ok*/, 'b /*not ok*/>
|
||||||
|
let lifetime_defs = self.parse_late_bound_lifetime_defs()?;
|
||||||
|
|
||||||
parsed_something = true;
|
// Parse type with mandatory colon and (possibly empty) bounds,
|
||||||
}
|
// or with mandatory equality sign and the second type.
|
||||||
|
let ty = self.parse_ty()?;
|
||||||
_ => {
|
|
||||||
let bound_lifetimes = if self.eat_keyword(keywords::For) {
|
|
||||||
// Higher ranked constraint.
|
|
||||||
self.expect(&token::Lt)?;
|
|
||||||
let lifetime_defs = self.parse_lifetime_defs(None)?;
|
|
||||||
self.expect_gt()?;
|
|
||||||
lifetime_defs
|
|
||||||
} else {
|
|
||||||
vec![]
|
|
||||||
};
|
|
||||||
|
|
||||||
let bounded_ty = self.parse_ty_no_plus()?;
|
|
||||||
|
|
||||||
if self.eat(&token::Colon) {
|
if self.eat(&token::Colon) {
|
||||||
let bounds = self.parse_ty_param_bounds()?;
|
let bounds = self.parse_ty_param_bounds()?;
|
||||||
let hi = self.prev_span.hi;
|
|
||||||
let span = mk_sp(lo, hi);
|
|
||||||
|
|
||||||
if bounds.is_empty() {
|
|
||||||
self.span_err(span,
|
|
||||||
"each predicate in a `where` clause must have \
|
|
||||||
at least one bound in it");
|
|
||||||
}
|
|
||||||
|
|
||||||
where_clause.predicates.push(ast::WherePredicate::BoundPredicate(
|
where_clause.predicates.push(ast::WherePredicate::BoundPredicate(
|
||||||
ast::WhereBoundPredicate {
|
ast::WhereBoundPredicate {
|
||||||
span: span,
|
span: mk_sp(lo, self.prev_span.hi),
|
||||||
bound_lifetimes: bound_lifetimes,
|
bound_lifetimes: lifetime_defs,
|
||||||
bounded_ty: bounded_ty,
|
bounded_ty: ty,
|
||||||
bounds: bounds,
|
bounds: bounds,
|
||||||
}));
|
}
|
||||||
|
));
|
||||||
parsed_something = true;
|
// FIXME: Decide what should be used here, `=` or `==`.
|
||||||
} else if self.eat(&token::Eq) {
|
} else if self.eat(&token::Eq) || self.eat(&token::EqEq) {
|
||||||
// let ty = try!(self.parse_ty_no_plus());
|
let rhs_ty = self.parse_ty()?;
|
||||||
let hi = self.prev_span.hi;
|
where_clause.predicates.push(ast::WherePredicate::EqPredicate(
|
||||||
let span = mk_sp(lo, hi);
|
ast::WhereEqPredicate {
|
||||||
// where_clause.predicates.push(
|
span: mk_sp(lo, self.prev_span.hi),
|
||||||
// ast::WherePredicate::EqPredicate(ast::WhereEqPredicate {
|
lhs_ty: ty,
|
||||||
// id: ast::DUMMY_NODE_ID,
|
rhs_ty: rhs_ty,
|
||||||
// span: span,
|
id: ast::DUMMY_NODE_ID,
|
||||||
// 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 {
|
} else {
|
||||||
let prev_span = self.prev_span;
|
return self.unexpected();
|
||||||
self.span_err(prev_span,
|
|
||||||
"unexpected token in `where` clause");
|
|
||||||
}
|
}
|
||||||
}
|
} else {
|
||||||
};
|
break
|
||||||
|
}}
|
||||||
|
|
||||||
if !self.eat(&token::Comma) {
|
if !self.eat(&token::Comma) {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if !parsed_something {
|
|
||||||
let prev_span = self.prev_span;
|
|
||||||
self.span_err(prev_span,
|
|
||||||
"a `where` clause must have at least one predicate \
|
|
||||||
in it");
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(where_clause)
|
Ok(where_clause)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -4547,13 +4383,13 @@ impl<'a> Parser<'a> {
|
||||||
} else if self.look_ahead(1, |t| t.is_lifetime()) &&
|
} else if self.look_ahead(1, |t| t.is_lifetime()) &&
|
||||||
isolated_self(self, 2) {
|
isolated_self(self, 2) {
|
||||||
self.bump();
|
self.bump();
|
||||||
let lt = self.parse_lifetime()?;
|
let lt = self.eat_lifetime().expect("not a lifetime");
|
||||||
(SelfKind::Region(Some(lt), Mutability::Immutable), expect_ident(self))
|
(SelfKind::Region(Some(lt), Mutability::Immutable), expect_ident(self))
|
||||||
} else if self.look_ahead(1, |t| t.is_lifetime()) &&
|
} else if self.look_ahead(1, |t| t.is_lifetime()) &&
|
||||||
self.look_ahead(2, |t| t.is_keyword(keywords::Mut)) &&
|
self.look_ahead(2, |t| t.is_keyword(keywords::Mut)) &&
|
||||||
isolated_self(self, 3) {
|
isolated_self(self, 3) {
|
||||||
self.bump();
|
self.bump();
|
||||||
let lt = self.parse_lifetime()?;
|
let lt = self.eat_lifetime().expect("not a lifetime");
|
||||||
self.bump();
|
self.bump();
|
||||||
(SelfKind::Region(Some(lt), Mutability::Mutable), expect_ident(self))
|
(SelfKind::Region(Some(lt), Mutability::Mutable), expect_ident(self))
|
||||||
} else {
|
} else {
|
||||||
|
@ -4855,8 +4691,12 @@ impl<'a> Parser<'a> {
|
||||||
let ident = self.parse_ident()?;
|
let ident = self.parse_ident()?;
|
||||||
let mut tps = self.parse_generics()?;
|
let mut tps = self.parse_generics()?;
|
||||||
|
|
||||||
// Parse supertrait bounds.
|
// Parse optional colon and supertrait bounds.
|
||||||
let bounds = self.parse_colon_then_ty_param_bounds()?;
|
let bounds = if self.eat(&token::Colon) {
|
||||||
|
self.parse_ty_param_bounds()?
|
||||||
|
} else {
|
||||||
|
Vec::new()
|
||||||
|
};
|
||||||
|
|
||||||
tps.where_clause = self.parse_where_clause()?;
|
tps.where_clause = self.parse_where_clause()?;
|
||||||
|
|
||||||
|
@ -4947,17 +4787,21 @@ impl<'a> Parser<'a> {
|
||||||
|
|
||||||
/// Parse a::B<String,i32>
|
/// Parse a::B<String,i32>
|
||||||
fn parse_trait_ref(&mut self) -> PResult<'a, TraitRef> {
|
fn parse_trait_ref(&mut self) -> PResult<'a, TraitRef> {
|
||||||
Ok(ast::TraitRef {
|
Ok(TraitRef {
|
||||||
path: self.parse_path(PathStyle::Type)?,
|
path: self.parse_path(PathStyle::Type)?,
|
||||||
ref_id: ast::DUMMY_NODE_ID,
|
ref_id: ast::DUMMY_NODE_ID,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
fn parse_late_bound_lifetime_defs(&mut self) -> PResult<'a, Vec<ast::LifetimeDef>> {
|
fn parse_late_bound_lifetime_defs(&mut self) -> PResult<'a, Vec<LifetimeDef>> {
|
||||||
if self.eat_keyword(keywords::For) {
|
if self.eat_keyword(keywords::For) {
|
||||||
self.expect(&token::Lt)?;
|
self.expect_lt()?;
|
||||||
let lifetime_defs = self.parse_lifetime_defs(None)?;
|
let (lifetime_defs, ty_params) = self.parse_generic_params()?;
|
||||||
self.expect_gt()?;
|
self.expect_gt()?;
|
||||||
|
if !ty_params.is_empty() {
|
||||||
|
self.span_err(ty_params[0].span,
|
||||||
|
"only lifetime parameters can be used in this context");
|
||||||
|
}
|
||||||
Ok(lifetime_defs)
|
Ok(lifetime_defs)
|
||||||
} else {
|
} else {
|
||||||
Ok(Vec::new())
|
Ok(Vec::new())
|
||||||
|
@ -4969,7 +4813,7 @@ impl<'a> Parser<'a> {
|
||||||
let lo = self.span.lo;
|
let lo = self.span.lo;
|
||||||
let lifetime_defs = self.parse_late_bound_lifetime_defs()?;
|
let lifetime_defs = self.parse_late_bound_lifetime_defs()?;
|
||||||
|
|
||||||
Ok(ast::PolyTraitRef {
|
Ok(PolyTraitRef {
|
||||||
bound_lifetimes: lifetime_defs,
|
bound_lifetimes: lifetime_defs,
|
||||||
trait_ref: self.parse_trait_ref()?,
|
trait_ref: self.parse_trait_ref()?,
|
||||||
span: mk_sp(lo, self.prev_span.hi),
|
span: mk_sp(lo, self.prev_span.hi),
|
||||||
|
|
|
@ -187,6 +187,29 @@ impl Token {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Returns `true` if the token can appear at the start of a type.
|
||||||
|
pub fn can_begin_type(&self) -> bool {
|
||||||
|
match *self {
|
||||||
|
OpenDelim(Paren) => true, // tuple
|
||||||
|
OpenDelim(Bracket) => true, // array
|
||||||
|
Ident(..) => true, // type name or keyword
|
||||||
|
Underscore => true, // placeholder
|
||||||
|
Not => true, // never
|
||||||
|
BinOp(Star) => true, // raw pointer
|
||||||
|
BinOp(And) => true, // reference
|
||||||
|
AndAnd => true, // double reference
|
||||||
|
Lt | BinOp(Shl) => true, // associated path
|
||||||
|
ModSep => true, // global path
|
||||||
|
Interpolated(ref nt) => match **nt {
|
||||||
|
NtTy(..) => true,
|
||||||
|
NtIdent(..) => true,
|
||||||
|
NtPath(..) => true,
|
||||||
|
_ => false,
|
||||||
|
},
|
||||||
|
_ => false,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Returns `true` if the token is any literal
|
/// Returns `true` if the token is any literal
|
||||||
pub fn is_lit(&self) -> bool {
|
pub fn is_lit(&self) -> bool {
|
||||||
match *self {
|
match *self {
|
||||||
|
|
|
@ -17,10 +17,7 @@
|
||||||
|
|
||||||
struct RefAny<'a, T>(&'a T);
|
struct RefAny<'a, T>(&'a T);
|
||||||
|
|
||||||
impl<#[rustc_1] 'a, #[rustc_2] T, #[oops]> RefAny<'a, T> {
|
impl<#[rustc_1] 'a, #[rustc_2] T, #[oops]> RefAny<'a, T> {}
|
||||||
//~^ ERROR expected identifier, found `>`
|
//~^ ERROR trailing attribute after type parameters
|
||||||
}
|
|
||||||
|
|
||||||
fn main() {
|
fn main() {}
|
||||||
|
|
||||||
}
|
|
||||||
|
|
20
src/test/compile-fail/generic-non-trailing-defaults.rs
Normal file
20
src/test/compile-fail/generic-non-trailing-defaults.rs
Normal file
|
@ -0,0 +1,20 @@
|
||||||
|
// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
|
||||||
|
// file at the top-level directory of this distribution and at
|
||||||
|
// http://rust-lang.org/COPYRIGHT.
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||||
|
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||||
|
// option. This file may not be copied, modified, or distributed
|
||||||
|
// except according to those terms.
|
||||||
|
|
||||||
|
struct Heap;
|
||||||
|
|
||||||
|
struct Vec<A = Heap, T>;
|
||||||
|
//~^ ERROR type parameters with a default must be trailing
|
||||||
|
|
||||||
|
struct Foo<A, B = Vec<C>, C>;
|
||||||
|
//~^ ERROR type parameters with a default must be trailing
|
||||||
|
//~| ERROR type parameters with a default cannot use forward declared identifiers
|
||||||
|
|
||||||
|
fn main() {}
|
15
src/test/compile-fail/impl-trait/no-trait.rs
Normal file
15
src/test/compile-fail/impl-trait/no-trait.rs
Normal file
|
@ -0,0 +1,15 @@
|
||||||
|
// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
|
||||||
|
// file at the top-level directory of this distribution and at
|
||||||
|
// http://rust-lang.org/COPYRIGHT.
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||||
|
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||||
|
// option. This file may not be copied, modified, or distributed
|
||||||
|
// except according to those terms.
|
||||||
|
|
||||||
|
#![feature(conservative_impl_trait)]
|
||||||
|
|
||||||
|
fn f() -> impl 'static {} //~ ERROR at least one trait must be specified
|
||||||
|
|
||||||
|
fn main() {}
|
|
@ -16,7 +16,7 @@
|
||||||
type Type_1_<'a, T> = &'a T;
|
type Type_1_<'a, T> = &'a T;
|
||||||
|
|
||||||
|
|
||||||
type Type_1<'a T> = &'a T; //~ error: expected `,` or `>` after lifetime name, found `T`
|
type Type_1<'a T> = &'a T; //~ error: expected one of `,`, `:`, or `>`, found `T`
|
||||||
|
|
||||||
|
|
||||||
//type Type_2 = Type_1_<'static ()>; // error: expected `,` or `>` after lifetime name, found `(`
|
//type Type_2 = Type_1_<'static ()>; // error: expected `,` or `>` after lifetime name, found `(`
|
||||||
|
|
|
@ -19,7 +19,7 @@ type Type_1_<'a, T> = &'a T;
|
||||||
//type Type_1<'a T> = &'a T; // error: expected `,` or `>` after lifetime name, found `T`
|
//type Type_1<'a T> = &'a T; // error: expected `,` or `>` after lifetime name, found `T`
|
||||||
|
|
||||||
|
|
||||||
type Type_2 = Type_1_<'static ()>; //~ error: expected `,` or `>` after lifetime name, found `(`
|
type Type_2 = Type_1_<'static ()>; //~ error: expected one of `,` or `>`, found `(`
|
||||||
|
|
||||||
|
|
||||||
//type Type_3<T> = Box<T,,>; // error: expected type, found `,`
|
//type Type_3<T> = Box<T,,>; // error: expected type, found `,`
|
||||||
|
|
|
@ -22,7 +22,7 @@ type Type_1_<'a, T> = &'a T;
|
||||||
//type Type_2 = Type_1_<'static ()>; // error: expected `,` or `>` after lifetime name, found `(`
|
//type Type_2 = Type_1_<'static ()>; // error: expected `,` or `>` after lifetime name, found `(`
|
||||||
|
|
||||||
|
|
||||||
type Type_3<T> = Box<T,,>; //~ error: expected type, found `,`
|
type Type_3<T> = Box<T,,>; //~ error: expected one of `>`, identifier, lifetime, or type, found `,`
|
||||||
|
|
||||||
|
|
||||||
//type Type_4<T> = Type_1_<'static,, T>; // error: expected type, found `,`
|
//type Type_4<T> = Type_1_<'static,, T>; // error: expected type, found `,`
|
||||||
|
|
|
@ -25,7 +25,8 @@ type Type_1_<'a, T> = &'a T;
|
||||||
//type Type_3<T> = Box<T,,>; // error: expected type, found `,`
|
//type Type_3<T> = Box<T,,>; // error: expected type, found `,`
|
||||||
|
|
||||||
|
|
||||||
type Type_4<T> = Type_1_<'static,, T>; //~ error: expected type, found `,`
|
type Type_4<T> = Type_1_<'static,, T>;
|
||||||
|
//~^ error: expected one of `>`, identifier, lifetime, or type, found `,`
|
||||||
|
|
||||||
|
|
||||||
type Type_5_<'a> = Type_1_<'a, ()>;
|
type Type_5_<'a> = Type_1_<'a, ()>;
|
||||||
|
|
|
@ -31,7 +31,8 @@ type Type_1_<'a, T> = &'a T;
|
||||||
type Type_5_<'a> = Type_1_<'a, ()>;
|
type Type_5_<'a> = Type_1_<'a, ()>;
|
||||||
|
|
||||||
|
|
||||||
type Type_5<'a> = Type_1_<'a, (),,>; //~ error: expected type, found `,`
|
type Type_5<'a> = Type_1_<'a, (),,>;
|
||||||
|
//~^ error: expected one of `>`, identifier, lifetime, or type, found `,`
|
||||||
|
|
||||||
|
|
||||||
//type Type_6 = Type_5_<'a,,>; // error: expected type, found `,`
|
//type Type_6 = Type_5_<'a,,>; // error: expected type, found `,`
|
||||||
|
|
|
@ -34,7 +34,8 @@ type Type_5_<'a> = Type_1_<'a, ()>;
|
||||||
//type Type_5<'a> = Type_1_<'a, (),,>; // error: expected type, found `,`
|
//type Type_5<'a> = Type_1_<'a, (),,>; // error: expected type, found `,`
|
||||||
|
|
||||||
|
|
||||||
type Type_6 = Type_5_<'a,,>; //~ error: expected type, found `,`
|
type Type_6 = Type_5_<'a,,>;
|
||||||
|
//~^ error: expected one of `>`, identifier, lifetime, or type, found `,`
|
||||||
|
|
||||||
|
|
||||||
//type Type_7 = Box<(),,>; // error: expected type, found `,`
|
//type Type_7 = Box<(),,>; // error: expected type, found `,`
|
||||||
|
|
|
@ -37,7 +37,7 @@ type Type_5_<'a> = Type_1_<'a, ()>;
|
||||||
//type Type_6 = Type_5_<'a,,>; // error: expected type, found `,`
|
//type Type_6 = Type_5_<'a,,>; // error: expected type, found `,`
|
||||||
|
|
||||||
|
|
||||||
type Type_7 = Box<(),,>; //~ error: expected type, found `,`
|
type Type_7 = Box<(),,>; //~ error: expected one of `>`, identifier, lifetime, or type, found `,`
|
||||||
|
|
||||||
|
|
||||||
//type Type_8<'a,,> = &'a (); // error: expected ident, found `,`
|
//type Type_8<'a,,> = &'a (); // error: expected ident, found `,`
|
||||||
|
|
|
@ -40,7 +40,7 @@ type Type_5_<'a> = Type_1_<'a, ()>;
|
||||||
//type Type_7 = Box<(),,>; // error: expected type, found `,`
|
//type Type_7 = Box<(),,>; // error: expected type, found `,`
|
||||||
|
|
||||||
|
|
||||||
type Type_8<'a,,> = &'a (); //~ error: expected identifier, found `,`
|
type Type_8<'a,,> = &'a (); //~ error: expected one of `>`, identifier, or lifetime, found `,`
|
||||||
|
|
||||||
|
|
||||||
//type Type_9<T,,> = Box<T>; // error: expected identifier, found `,`
|
//type Type_9<T,,> = Box<T>; // error: expected identifier, found `,`
|
||||||
|
|
|
@ -43,4 +43,4 @@ type Type_5_<'a> = Type_1_<'a, ()>;
|
||||||
//type Type_8<'a,,> = &'a (); // error: expected identifier, found `,`
|
//type Type_8<'a,,> = &'a (); // error: expected identifier, found `,`
|
||||||
|
|
||||||
|
|
||||||
type Type_9<T,,> = Box<T>; //~ error: expected identifier, found `,`
|
type Type_9<T,,> = Box<T>; //~ error: expected one of `>`, identifier, or lifetime, found `,`
|
||||||
|
|
16
src/test/compile-fail/where-equality-constraints.rs
Normal file
16
src/test/compile-fail/where-equality-constraints.rs
Normal file
|
@ -0,0 +1,16 @@
|
||||||
|
// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
|
||||||
|
// file at the top-level directory of this distribution and at
|
||||||
|
// http://rust-lang.org/COPYRIGHT.
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||||
|
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||||
|
// option. This file may not be copied, modified, or distributed
|
||||||
|
// except according to those terms.
|
||||||
|
|
||||||
|
fn f() where u8 = u16 {}
|
||||||
|
//~^ ERROR equality constraints are not yet supported in where clauses
|
||||||
|
fn g() where for<'a> &(u8,) == u16, {}
|
||||||
|
//~^ ERROR equality constraints are not yet supported in where clauses
|
||||||
|
|
||||||
|
fn main() {}
|
23
src/test/compile-fail/where-lifetime-resolution.rs
Normal file
23
src/test/compile-fail/where-lifetime-resolution.rs
Normal file
|
@ -0,0 +1,23 @@
|
||||||
|
// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
|
||||||
|
// file at the top-level directory of this distribution and at
|
||||||
|
// http://rust-lang.org/COPYRIGHT.
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||||
|
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||||
|
// option. This file may not be copied, modified, or distributed
|
||||||
|
// except according to those terms.
|
||||||
|
|
||||||
|
trait Trait1 {}
|
||||||
|
trait Trait2 {}
|
||||||
|
|
||||||
|
fn f() where
|
||||||
|
for<'a> Trait1<'a>: Trait1<'a>, // OK
|
||||||
|
(for<'a> Trait1<'a>): Trait1<'a>,
|
||||||
|
//~^ ERROR use of undeclared lifetime name `'a`
|
||||||
|
for<'a> for<'b> Trait2<'a, 'b>: Trait2<'a, 'b>,
|
||||||
|
//~^ ERROR use of undeclared lifetime name `'b`
|
||||||
|
//~| ERROR nested quantification of lifetimes
|
||||||
|
{}
|
||||||
|
|
||||||
|
fn main() {}
|
15
src/test/parse-fail/bounds-lifetime-1.rs
Normal file
15
src/test/parse-fail/bounds-lifetime-1.rs
Normal file
|
@ -0,0 +1,15 @@
|
||||||
|
// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
|
||||||
|
// file at the top-level directory of this distribution and at
|
||||||
|
// http://rust-lang.org/COPYRIGHT.
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||||
|
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||||
|
// option. This file may not be copied, modified, or distributed
|
||||||
|
// except according to those terms.
|
||||||
|
|
||||||
|
// compile-flags: -Z parse-only
|
||||||
|
|
||||||
|
type A = for<'a 'b> fn(); //~ ERROR expected one of `,`, `:`, or `>`, found `'b`
|
||||||
|
|
||||||
|
fn main() {}
|
15
src/test/parse-fail/bounds-lifetime-2.rs
Normal file
15
src/test/parse-fail/bounds-lifetime-2.rs
Normal file
|
@ -0,0 +1,15 @@
|
||||||
|
// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
|
||||||
|
// file at the top-level directory of this distribution and at
|
||||||
|
// http://rust-lang.org/COPYRIGHT.
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||||
|
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||||
|
// option. This file may not be copied, modified, or distributed
|
||||||
|
// except according to those terms.
|
||||||
|
|
||||||
|
// compile-flags: -Z parse-only
|
||||||
|
|
||||||
|
type A = for<'a + 'b> fn(); //~ ERROR expected one of `,`, `:`, or `>`, found `+`
|
||||||
|
|
||||||
|
fn main() {}
|
15
src/test/parse-fail/bounds-lifetime-where-1.rs
Normal file
15
src/test/parse-fail/bounds-lifetime-where-1.rs
Normal file
|
@ -0,0 +1,15 @@
|
||||||
|
// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
|
||||||
|
// file at the top-level directory of this distribution and at
|
||||||
|
// http://rust-lang.org/COPYRIGHT.
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||||
|
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||||
|
// option. This file may not be copied, modified, or distributed
|
||||||
|
// except according to those terms.
|
||||||
|
|
||||||
|
// compile-flags: -Z parse-only
|
||||||
|
|
||||||
|
type A where 'a; //~ ERROR expected `:`, found `;`
|
||||||
|
|
||||||
|
fn main() {}
|
22
src/test/parse-fail/bounds-lifetime-where.rs
Normal file
22
src/test/parse-fail/bounds-lifetime-where.rs
Normal file
|
@ -0,0 +1,22 @@
|
||||||
|
// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
|
||||||
|
// file at the top-level directory of this distribution and at
|
||||||
|
// http://rust-lang.org/COPYRIGHT.
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||||
|
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||||
|
// option. This file may not be copied, modified, or distributed
|
||||||
|
// except according to those terms.
|
||||||
|
|
||||||
|
// compile-flags: -Z parse-only
|
||||||
|
|
||||||
|
type A where 'a: 'b + 'c = u8; // OK
|
||||||
|
type A where 'a: 'b, = u8; // OK
|
||||||
|
type A where 'a: = u8; // OK
|
||||||
|
type A where 'a:, = u8; // OK
|
||||||
|
type A where 'a: 'b + 'c = u8; // OK
|
||||||
|
type A where = u8; // OK
|
||||||
|
type A where 'a: 'b + = u8; // OK
|
||||||
|
type A where , = u8; //~ ERROR expected one of `=`, lifetime, or type, found `,`
|
||||||
|
|
||||||
|
fn main() {}
|
24
src/test/parse-fail/bounds-lifetime.rs
Normal file
24
src/test/parse-fail/bounds-lifetime.rs
Normal file
|
@ -0,0 +1,24 @@
|
||||||
|
// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
|
||||||
|
// file at the top-level directory of this distribution and at
|
||||||
|
// http://rust-lang.org/COPYRIGHT.
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||||
|
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||||
|
// option. This file may not be copied, modified, or distributed
|
||||||
|
// except according to those terms.
|
||||||
|
|
||||||
|
// compile-flags: -Z parse-only -Z continue-parse-after-error
|
||||||
|
|
||||||
|
type A = for<'a: 'b + 'c> fn(); // OK
|
||||||
|
type A = for<'a: 'b,> fn(); // OK
|
||||||
|
type A = for<'a:> fn(); // OK
|
||||||
|
type A = for<'a:,> fn(); // OK
|
||||||
|
type A = for<'a> fn(); // OK
|
||||||
|
type A = for<> fn(); // OK
|
||||||
|
type A = for<'a: 'b +> fn(); // OK
|
||||||
|
|
||||||
|
type A = for<'a, T> fn(); //~ ERROR only lifetime parameters can be used in this context
|
||||||
|
type A = for<,> fn(); //~ ERROR expected one of `>`, identifier, or lifetime, found `,`
|
||||||
|
|
||||||
|
fn main() {}
|
23
src/test/parse-fail/bounds-type-where.rs
Normal file
23
src/test/parse-fail/bounds-type-where.rs
Normal file
|
@ -0,0 +1,23 @@
|
||||||
|
// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
|
||||||
|
// file at the top-level directory of this distribution and at
|
||||||
|
// http://rust-lang.org/COPYRIGHT.
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||||
|
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||||
|
// option. This file may not be copied, modified, or distributed
|
||||||
|
// except according to those terms.
|
||||||
|
|
||||||
|
// compile-flags: -Z parse-only
|
||||||
|
|
||||||
|
type A where for<'a> for<'b> Trait1 + ?Trait2: 'a + Trait = u8; // OK
|
||||||
|
type A where T: Trait, = u8; // OK
|
||||||
|
type A where T: = u8; // OK
|
||||||
|
type A where T:, = u8; // OK
|
||||||
|
type A where T: Trait + Trait = u8; // OK
|
||||||
|
type A where = u8; // OK
|
||||||
|
type A where T: Trait + = u8; // OK
|
||||||
|
type A where T, = u8;
|
||||||
|
//~^ ERROR expected one of `!`, `(`, `+`, `::`, `:`, `<`, `==`, or `=`, found `,`
|
||||||
|
|
||||||
|
fn main() {}
|
23
src/test/parse-fail/bounds-type.rs
Normal file
23
src/test/parse-fail/bounds-type.rs
Normal file
|
@ -0,0 +1,23 @@
|
||||||
|
// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
|
||||||
|
// file at the top-level directory of this distribution and at
|
||||||
|
// http://rust-lang.org/COPYRIGHT.
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||||
|
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||||
|
// option. This file may not be copied, modified, or distributed
|
||||||
|
// except according to those terms.
|
||||||
|
|
||||||
|
// compile-flags: -Z parse-only -Z continue-parse-after-error
|
||||||
|
|
||||||
|
struct S<
|
||||||
|
T: 'a + Tr, // OK
|
||||||
|
T: Tr + 'a, // OK
|
||||||
|
T: 'a, // OK
|
||||||
|
T:, // OK
|
||||||
|
T: ?for<'a: 'b + 'c> Trait, // OK
|
||||||
|
T: Tr +, // OK
|
||||||
|
T: ?'a, //~ ERROR `?` may only modify trait bounds, not lifetime bounds
|
||||||
|
>;
|
||||||
|
|
||||||
|
fn main() {}
|
|
@ -12,4 +12,3 @@
|
||||||
|
|
||||||
fn bar<'a, T>(x: mymodule::X<'a, T, 'b, 'c>) {}
|
fn bar<'a, T>(x: mymodule::X<'a, T, 'b, 'c>) {}
|
||||||
//~^ ERROR lifetime parameters must be declared prior to type parameters
|
//~^ ERROR lifetime parameters must be declared prior to type parameters
|
||||||
//~^^ ERROR expected pattern, found `'c`
|
|
||||||
|
|
|
@ -10,10 +10,6 @@
|
||||||
|
|
||||||
// compile-flags: -Z parse-only -Z continue-parse-after-error
|
// compile-flags: -Z parse-only -Z continue-parse-after-error
|
||||||
|
|
||||||
struct Heap;
|
struct Bar<T> { x: T } where T: Copy //~ ERROR expected item, found `where`
|
||||||
|
|
||||||
struct Vec<A = Heap, T>; //~ ERROR type parameters with a default must be trailing
|
|
||||||
|
|
||||||
struct Foo<A, B = Vec<C>, C>; //~ ERROR type parameters with a default must be trailing
|
|
||||||
|
|
||||||
fn main() {}
|
fn main() {}
|
|
@ -13,7 +13,6 @@
|
||||||
struct Baz<U> where U: Eq(U); //This is parsed as the new Fn* style parenthesis syntax.
|
struct Baz<U> where U: Eq(U); //This is parsed as the new Fn* style parenthesis syntax.
|
||||||
struct Baz<U> where U: Eq(U) -> R; // Notice this parses as well.
|
struct Baz<U> where U: Eq(U) -> R; // Notice this parses as well.
|
||||||
struct Baz<U>(U) where U: Eq; // This rightfully signals no error as well.
|
struct Baz<U>(U) where U: Eq; // This rightfully signals no error as well.
|
||||||
struct Foo<T> where T: Copy, (T); //~ ERROR unexpected token in `where` clause
|
struct Foo<T> where T: Copy, (T); //~ ERROR expected one of `+`, `:`, `==`, or `=`, found `;`
|
||||||
struct Bar<T> { x: T } where T: Copy //~ ERROR expected item, found `where`
|
|
||||||
|
|
||||||
fn main() {}
|
fn main() {}
|
||||||
|
|
|
@ -10,8 +10,7 @@
|
||||||
|
|
||||||
// compile-flags: -Z parse-only -Z continue-parse-after-error
|
// compile-flags: -Z parse-only -Z continue-parse-after-error
|
||||||
|
|
||||||
pub fn test<W, I: Iterator<Item=(), W> >() {
|
pub fn test<W, I: Iterator<Item=(), W> >() {}
|
||||||
//~^ ERROR expected `=`, found `>`
|
//~^ ERROR type parameters must be declared prior to associated type bindings
|
||||||
}
|
|
||||||
|
|
||||||
fn main() { }
|
fn main() { }
|
||||||
|
|
|
@ -15,5 +15,4 @@ struct Foo<'a, 'b> {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn foo<'a, 'b>(x: &mut Foo<'a; 'b>) {}
|
fn foo<'a, 'b>(x: &mut Foo<'a; 'b>) {}
|
||||||
//~^ ERROR expected `,` or `>` after lifetime name, found `;`
|
//~^ ERROR expected one of `,` or `>`, found `;`
|
||||||
//~^^ NOTE did you mean a single argument type &'a Type, or did you mean the comma-separated
|
|
||||||
|
|
|
@ -10,13 +10,13 @@
|
||||||
|
|
||||||
// compile-flags: -Z parse-only -Z continue-parse-after-error
|
// compile-flags: -Z parse-only -Z continue-parse-after-error
|
||||||
|
|
||||||
|
// Empty predicate list is OK
|
||||||
fn equal1<T>(_: &T, _: &T) -> bool where {
|
fn equal1<T>(_: &T, _: &T) -> bool where {
|
||||||
//~^ ERROR a `where` clause must have at least one predicate in it
|
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Empty bound list is OK
|
||||||
fn equal2<T>(_: &T, _: &T) -> bool where T: {
|
fn equal2<T>(_: &T, _: &T) -> bool where T: {
|
||||||
//~^ ERROR each predicate in a `where` clause must have at least one bound
|
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue