Suggest expressions that look like const generic arguments should be enclosed in brackets
Co-Authored-By: Esteban Kuber <github@kuber.com.ar>
This commit is contained in:
parent
1d2726726f
commit
ac1454001c
19 changed files with 782 additions and 35 deletions
|
@ -397,6 +397,13 @@ impl<'a> Parser<'a> {
|
|||
while let Some(arg) = self.parse_angle_arg()? {
|
||||
args.push(arg);
|
||||
if !self.eat(&token::Comma) {
|
||||
if !self.token.kind.should_end_const_arg() {
|
||||
if self.handle_ambiguous_unbraced_const_arg(&mut args)? {
|
||||
// We've managed to (partially) recover, so continue trying to parse
|
||||
// arguments.
|
||||
continue;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -476,41 +483,50 @@ impl<'a> Parser<'a> {
|
|||
Ok(self.mk_ty(span, ast::TyKind::Err))
|
||||
}
|
||||
|
||||
/// We do not permit arbitrary expressions as const arguments. They must be one of:
|
||||
/// - An expression surrounded in `{}`.
|
||||
/// - A literal.
|
||||
/// - A numeric literal prefixed by `-`.
|
||||
pub(super) fn expr_is_valid_const_arg(&self, expr: &P<rustc_ast::Expr>) -> bool {
|
||||
match &expr.kind {
|
||||
ast::ExprKind::Block(_, _) | ast::ExprKind::Lit(_) => true,
|
||||
ast::ExprKind::Unary(ast::UnOp::Neg, expr) => match &expr.kind {
|
||||
ast::ExprKind::Lit(_) => true,
|
||||
_ => false,
|
||||
},
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
|
||||
/// Parse a generic argument in a path segment.
|
||||
/// This does not include constraints, e.g., `Item = u8`, which is handled in `parse_angle_arg`.
|
||||
fn parse_generic_arg(&mut self) -> PResult<'a, Option<GenericArg>> {
|
||||
let start = self.token.span;
|
||||
let arg = if self.check_lifetime() && self.look_ahead(1, |t| !t.is_like_plus()) {
|
||||
// Parse lifetime argument.
|
||||
GenericArg::Lifetime(self.expect_lifetime())
|
||||
} else if self.check_const_arg() {
|
||||
// Parse const argument.
|
||||
let expr = if let token::OpenDelim(token::Brace) = self.token.kind {
|
||||
let value = if let token::OpenDelim(token::Brace) = self.token.kind {
|
||||
self.parse_block_expr(
|
||||
None,
|
||||
self.token.span,
|
||||
BlockCheckMode::Default,
|
||||
ast::AttrVec::new(),
|
||||
)?
|
||||
} else if self.token.is_ident() {
|
||||
// FIXME(const_generics): to distinguish between idents for types and consts,
|
||||
// we should introduce a GenericArg::Ident in the AST and distinguish when
|
||||
// lowering to the HIR. For now, idents for const args are not permitted.
|
||||
if self.token.is_bool_lit() {
|
||||
self.parse_literal_maybe_minus()?
|
||||
} else {
|
||||
let span = self.token.span;
|
||||
let msg = "identifiers may currently not be used for const generics";
|
||||
self.struct_span_err(span, msg).emit();
|
||||
let block = self.mk_block_err(span);
|
||||
self.mk_expr(span, ast::ExprKind::Block(block, None), ast::AttrVec::new())
|
||||
}
|
||||
} else {
|
||||
self.parse_literal_maybe_minus()?
|
||||
self.handle_unambiguous_unbraced_const_arg()?
|
||||
};
|
||||
GenericArg::Const(AnonConst { id: ast::DUMMY_NODE_ID, value: expr })
|
||||
GenericArg::Const(AnonConst { id: ast::DUMMY_NODE_ID, value })
|
||||
} else if self.check_type() {
|
||||
// Parse type argument.
|
||||
GenericArg::Type(self.parse_ty()?)
|
||||
match self.parse_ty() {
|
||||
Ok(ty) => GenericArg::Type(ty),
|
||||
Err(err) => {
|
||||
// Try to recover from possible `const` arg without braces.
|
||||
return self.recover_const_arg(start, err).map(Some);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
return Ok(None);
|
||||
};
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue