diff options
| author | bors <bors@rust-lang.org> | 2020-10-27 09:25:54 +0000 |
|---|---|---|
| committer | bors <bors@rust-lang.org> | 2020-10-27 09:25:54 +0000 |
| commit | 20b1e05a8d0e1773dc840a3286aa37916e87d84b (patch) | |
| tree | eab6e728ec3e7f34021c2fb4b4ca69998392711a /compiler/rustc_parse/src/parser/path.rs | |
| parent | 824f900a96d752da2d882863c65f9736e5f2b347 (diff) | |
| parent | ac1454001cee3f344a1104fd0cf4012b93443b0b (diff) | |
| download | rust-20b1e05a8d0e1773dc840a3286aa37916e87d84b.tar.gz rust-20b1e05a8d0e1773dc840a3286aa37916e87d84b.zip | |
Auto merge of #77502 - varkor:const-generics-suggest-enclosing-braces, r=petrochenkov
Suggest that expressions that look like const generic arguments should be enclosed in brackets I pulled out the changes for const expressions from https://github.com/rust-lang/rust/pull/71592 (without the trait object diagnostic changes) and made some small changes; the implementation is `@estebank's.` We're also going to want to make some changes separately to account for trait objects (they result in poor diagnostics, as is evident from one of the test cases here), such as an adaption of https://github.com/rust-lang/rust/pull/72273. Fixes https://github.com/rust-lang/rust/issues/70753. r? `@petrochenkov`
Diffstat (limited to 'compiler/rustc_parse/src/parser/path.rs')
| -rw-r--r-- | compiler/rustc_parse/src/parser/path.rs | 50 |
1 files changed, 33 insertions, 17 deletions
diff --git a/compiler/rustc_parse/src/parser/path.rs b/compiler/rustc_parse/src/parser/path.rs index 66ce015d02e..06760547eba 100644 --- a/compiler/rustc_parse/src/parser/path.rs +++ b/compiler/rustc_parse/src/parser/path.rs @@ -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); }; |
