Skip to content

Commit

Permalink
Auto merge of #92884 - compiler-errors:const-generic-expr-recovery, r…
Browse files Browse the repository at this point in the history
…=jackh726

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

Fixes #92776
  • Loading branch information
bors committed Feb 26, 2022
2 parents 12b71ed + 6b52ac2 commit 7c3331c
Show file tree
Hide file tree
Showing 4 changed files with 121 additions and 18 deletions.
39 changes: 23 additions & 16 deletions compiler/rustc_parse/src/parser/diagnostics.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2030,7 +2030,7 @@ impl<'a> Parser<'a> {
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
Expand All @@ -2046,17 +2046,18 @@ impl<'a> Parser<'a> {
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) {
Expand All @@ -2080,18 +2081,7 @@ impl<'a> Parser<'a> {
// |
// 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) => {
Expand All @@ -2102,6 +2092,23 @@ impl<'a> Parser<'a> {
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
Expand Down
19 changes: 17 additions & 2 deletions compiler/rustc_parse/src/parser/path.rs
Original file line number Diff line number Diff line change
@@ -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};
Expand Down Expand Up @@ -634,7 +634,22 @@ impl<'a> Parser<'a> {
} 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))
}
Expand Down
22 changes: 22 additions & 0 deletions src/test/ui/const-generics/bad-const-generic-exprs.rs
Original file line number Diff line number Diff line change
@@ -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
}
59 changes: 59 additions & 0 deletions src/test/ui/const-generics/bad-const-generic-exprs.stderr
Original file line number Diff line number Diff line change
@@ -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`.

0 comments on commit 7c3331c

Please sign in to comment.