Auto merge of #92884 - compiler-errors:const-generic-expr-recovery, r=jackh726

Suggest adding `{ .. }` around more bad const generic exprs

Fixes #92776
This commit is contained in:
bors 2022-02-26 04:39:11 +00:00
commit 7c3331ccf9
4 changed files with 121 additions and 18 deletions

View File

@ -2030,7 +2030,7 @@ pub fn recover_const_arg(
start: Span,
mut err: DiagnosticBuilder<'a, ErrorReported>,
) -> PResult<'a, GenericArg> {
let is_op = AssocOp::from_token(&self.token)
let is_op_or_dot = AssocOp::from_token(&self.token)
.and_then(|op| {
if let AssocOp::Greater
| AssocOp::Less
@ -2046,17 +2046,18 @@ pub fn recover_const_arg(
Some(op)
}
})
.is_some();
.is_some()
|| self.token.kind == TokenKind::Dot;
// This will be true when a trait object type `Foo +` or a path which was a `const fn` with
// type params has been parsed.
let was_op =
matches!(self.prev_token.kind, token::BinOp(token::Plus | token::Shr) | token::Gt);
if !is_op && !was_op {
if !is_op_or_dot && !was_op {
// We perform these checks and early return to avoid taking a snapshot unnecessarily.
return Err(err);
}
let snapshot = self.clone();
if is_op {
if is_op_or_dot {
self.bump();
}
match self.parse_expr_res(Restrictions::CONST_EXPR, None) {
@ -2080,18 +2081,7 @@ pub fn recover_const_arg(
// |
// LL | let sr: Vec<{ (u32, _, _) = vec![] };
// | ^ ^
err.multipart_suggestion(
"expressions must be enclosed in braces to be used as const generic \
arguments",
vec![
(start.shrink_to_lo(), "{ ".to_string()),
(expr.span.shrink_to_hi(), " }".to_string()),
],
Applicability::MaybeIncorrect,
);
let value = self.mk_expr_err(start.to(expr.span));
err.emit();
return Ok(GenericArg::Const(AnonConst { id: ast::DUMMY_NODE_ID, value }));
return Ok(self.dummy_const_arg_needs_braces(err, start.to(expr.span)));
}
}
Err(err) => {
@ -2102,6 +2092,23 @@ pub fn recover_const_arg(
Err(err)
}
/// Creates a dummy const argument, and reports that the expression must be enclosed in braces
pub fn dummy_const_arg_needs_braces(
&self,
mut err: DiagnosticBuilder<'a, ErrorReported>,
span: Span,
) -> GenericArg {
err.multipart_suggestion(
"expressions must be enclosed in braces to be used as const generic \
arguments",
vec![(span.shrink_to_lo(), "{ ".to_string()), (span.shrink_to_hi(), " }".to_string())],
Applicability::MaybeIncorrect,
);
let value = self.mk_expr_err(span);
err.emit();
GenericArg::Const(AnonConst { id: ast::DUMMY_NODE_ID, value })
}
/// Get the diagnostics for the cases where `move async` is found.
///
/// `move_async_span` starts at the 'm' of the move keyword and ends with the 'c' of the async keyword

View File

@ -1,5 +1,5 @@
use super::ty::{AllowPlus, RecoverQPath, RecoverReturnSign};
use super::{Parser, TokenType};
use super::{Parser, Restrictions, TokenType};
use crate::maybe_whole;
use rustc_ast::ptr::P;
use rustc_ast::token::{self, Token};
@ -634,7 +634,22 @@ pub(super) fn parse_generic_arg(
} else if self.token.is_keyword(kw::Const) {
return self.recover_const_param_declaration(ty_generics);
} else {
return Ok(None);
// Fall back by trying to parse a const-expr expression. If we successfully do so,
// then we should report an error that it needs to be wrapped in braces.
let snapshot = self.clone();
match self.parse_expr_res(Restrictions::CONST_EXPR, None) {
Ok(expr) => {
return Ok(Some(self.dummy_const_arg_needs_braces(
self.struct_span_err(expr.span, "invalid const generic expression"),
expr.span,
)));
}
Err(err) => {
*self = snapshot;
err.cancel();
return Ok(None);
}
}
};
Ok(Some(arg))
}

View File

@ -0,0 +1,22 @@
struct Wow<const N: usize>;
fn main() {
let _: Wow<if true {}>;
//~^ ERROR invalid const generic expression
//~| HELP expressions must be enclosed in braces to be used as const generic arguments
let _: Wow<|| ()>;
//~^ ERROR invalid const generic expression
//~| HELP expressions must be enclosed in braces to be used as const generic arguments
let _: Wow<A.b>;
//~^ ERROR expected one of
//~| HELP expressions must be enclosed in braces to be used as const generic arguments
let _: Wow<A.0>;
//~^ ERROR expected one of
//~| HELP expressions must be enclosed in braces to be used as const generic arguments
// FIXME(compiler-errors): This one is still unsatisfying,
// and probably a case I could see someone typing by accident..
let _: Wow<[12]>;
//~^ ERROR expected type, found
//~| ERROR type provided when a constant was expected
}

View File

@ -0,0 +1,59 @@
error: invalid const generic expression
--> $DIR/bad-const-generic-exprs.rs:4:16
|
LL | let _: Wow<if true {}>;
| ^^^^^^^^^^
|
help: expressions must be enclosed in braces to be used as const generic arguments
|
LL | let _: Wow<{ if true {} }>;
| + +
error: invalid const generic expression
--> $DIR/bad-const-generic-exprs.rs:7:16
|
LL | let _: Wow<|| ()>;
| ^^^^^
|
help: expressions must be enclosed in braces to be used as const generic arguments
|
LL | let _: Wow<{ || () }>;
| + +
error: expected one of `,` or `>`, found `.`
--> $DIR/bad-const-generic-exprs.rs:10:17
|
LL | let _: Wow<A.b>;
| ^ expected one of `,` or `>`
|
help: expressions must be enclosed in braces to be used as const generic arguments
|
LL | let _: Wow<{ A.b }>;
| + +
error: expected one of `,` or `>`, found `.`
--> $DIR/bad-const-generic-exprs.rs:13:17
|
LL | let _: Wow<A.0>;
| ^ expected one of `,` or `>`
|
help: expressions must be enclosed in braces to be used as const generic arguments
|
LL | let _: Wow<{ A.0 }>;
| + +
error: expected type, found `12`
--> $DIR/bad-const-generic-exprs.rs:19:17
|
LL | let _: Wow<[12]>;
| ^^ expected type
error[E0747]: type provided when a constant was expected
--> $DIR/bad-const-generic-exprs.rs:19:16
|
LL | let _: Wow<[12]>;
| ^^^^
error: aborting due to 6 previous errors
For more information about this error, try `rustc --explain E0747`.