Rollup merge of #94731 - TaKO8Ki:const-generic-expr-recovery, r=davidtwco,oli-obk
Suggest adding `{ .. }` around a const function call with arguments closes #91020
This commit is contained in:
commit
5eb3433ed5
6 changed files with 163 additions and 36 deletions
|
@ -151,7 +151,7 @@ impl<'a> Parser<'a> {
|
||||||
span: Span,
|
span: Span,
|
||||||
attr_type: OuterAttributeType,
|
attr_type: OuterAttributeType,
|
||||||
) -> Option<Span> {
|
) -> Option<Span> {
|
||||||
let mut snapshot = self.clone();
|
let mut snapshot = self.create_snapshot_for_diagnostic();
|
||||||
let lo = span.lo()
|
let lo = span.lo()
|
||||||
+ BytePos(match attr_type {
|
+ BytePos(match attr_type {
|
||||||
OuterAttributeType::Attribute => 1,
|
OuterAttributeType::Attribute => 1,
|
||||||
|
|
|
@ -5,6 +5,7 @@ use super::{
|
||||||
SemiColonMode, SeqSep, TokenExpectType, TokenType,
|
SemiColonMode, SeqSep, TokenExpectType, TokenType,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
use crate::lexer::UnmatchedBrace;
|
||||||
use rustc_ast as ast;
|
use rustc_ast as ast;
|
||||||
use rustc_ast::ptr::P;
|
use rustc_ast::ptr::P;
|
||||||
use rustc_ast::token::{self, Lit, LitKind, TokenKind};
|
use rustc_ast::token::{self, Lit, LitKind, TokenKind};
|
||||||
|
@ -21,6 +22,7 @@ use rustc_errors::{Applicability, DiagnosticBuilder, Handler, PResult};
|
||||||
use rustc_span::source_map::Spanned;
|
use rustc_span::source_map::Spanned;
|
||||||
use rustc_span::symbol::{kw, Ident};
|
use rustc_span::symbol::{kw, Ident};
|
||||||
use rustc_span::{MultiSpan, Span, SpanSnippetError, DUMMY_SP};
|
use rustc_span::{MultiSpan, Span, SpanSnippetError, DUMMY_SP};
|
||||||
|
use std::ops::{Deref, DerefMut};
|
||||||
|
|
||||||
use std::mem::take;
|
use std::mem::take;
|
||||||
|
|
||||||
|
@ -154,6 +156,28 @@ impl AttemptLocalParseRecovery {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// SnapshotParser is used to create a snapshot of the parser
|
||||||
|
// without causing duplicate errors being emitted when the `Parser`
|
||||||
|
// is dropped.
|
||||||
|
pub(super) struct SnapshotParser<'a> {
|
||||||
|
parser: Parser<'a>,
|
||||||
|
unclosed_delims: Vec<UnmatchedBrace>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> Deref for SnapshotParser<'a> {
|
||||||
|
type Target = Parser<'a>;
|
||||||
|
|
||||||
|
fn deref(&self) -> &Self::Target {
|
||||||
|
&self.parser
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> DerefMut for SnapshotParser<'a> {
|
||||||
|
fn deref_mut(&mut self) -> &mut Self::Target {
|
||||||
|
&mut self.parser
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl<'a> Parser<'a> {
|
impl<'a> Parser<'a> {
|
||||||
pub(super) fn span_err<S: Into<MultiSpan>>(
|
pub(super) fn span_err<S: Into<MultiSpan>>(
|
||||||
&self,
|
&self,
|
||||||
|
@ -179,6 +203,25 @@ impl<'a> Parser<'a> {
|
||||||
&self.sess.span_diagnostic
|
&self.sess.span_diagnostic
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Relace `self` with `snapshot.parser` and extend `unclosed_delims` with `snapshot.unclosed_delims`.
|
||||||
|
/// This is to avoid losing unclosed delims errors `create_snapshot_for_diagnostic` clears.
|
||||||
|
pub(super) fn restore_snapshot(&mut self, snapshot: SnapshotParser<'a>) {
|
||||||
|
*self = snapshot.parser;
|
||||||
|
self.unclosed_delims.extend(snapshot.unclosed_delims.clone());
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Create a snapshot of the `Parser`.
|
||||||
|
pub(super) fn create_snapshot_for_diagnostic(&self) -> SnapshotParser<'a> {
|
||||||
|
let mut snapshot = self.clone();
|
||||||
|
let unclosed_delims = self.unclosed_delims.clone();
|
||||||
|
// Clear `unclosed_delims` in snapshot to avoid
|
||||||
|
// duplicate errors being emitted when the `Parser`
|
||||||
|
// is dropped (which may or may not happen, depending
|
||||||
|
// if the parsing the snapshot is created for is successful)
|
||||||
|
snapshot.unclosed_delims.clear();
|
||||||
|
SnapshotParser { parser: snapshot, unclosed_delims }
|
||||||
|
}
|
||||||
|
|
||||||
pub(super) fn span_to_snippet(&self, span: Span) -> Result<String, SpanSnippetError> {
|
pub(super) fn span_to_snippet(&self, span: Span) -> Result<String, SpanSnippetError> {
|
||||||
self.sess.source_map().span_to_snippet(span)
|
self.sess.source_map().span_to_snippet(span)
|
||||||
}
|
}
|
||||||
|
@ -438,7 +481,7 @@ impl<'a> Parser<'a> {
|
||||||
// fn foo() -> Foo {
|
// fn foo() -> Foo {
|
||||||
// field: value,
|
// field: value,
|
||||||
// }
|
// }
|
||||||
let mut snapshot = self.clone();
|
let mut snapshot = self.create_snapshot_for_diagnostic();
|
||||||
let path =
|
let path =
|
||||||
Path { segments: vec![], span: self.prev_token.span.shrink_to_lo(), tokens: None };
|
Path { segments: vec![], span: self.prev_token.span.shrink_to_lo(), tokens: None };
|
||||||
let struct_expr = snapshot.parse_struct_expr(None, path, AttrVec::new(), false);
|
let struct_expr = snapshot.parse_struct_expr(None, path, AttrVec::new(), false);
|
||||||
|
@ -464,7 +507,7 @@ impl<'a> Parser<'a> {
|
||||||
Applicability::MaybeIncorrect,
|
Applicability::MaybeIncorrect,
|
||||||
)
|
)
|
||||||
.emit();
|
.emit();
|
||||||
*self = snapshot;
|
self.restore_snapshot(snapshot);
|
||||||
let mut tail = self.mk_block(
|
let mut tail = self.mk_block(
|
||||||
vec![self.mk_stmt_err(expr.span)],
|
vec![self.mk_stmt_err(expr.span)],
|
||||||
s,
|
s,
|
||||||
|
@ -678,7 +721,7 @@ impl<'a> Parser<'a> {
|
||||||
/// angle brackets.
|
/// angle brackets.
|
||||||
pub(super) fn check_turbofish_missing_angle_brackets(&mut self, segment: &mut PathSegment) {
|
pub(super) fn check_turbofish_missing_angle_brackets(&mut self, segment: &mut PathSegment) {
|
||||||
if token::ModSep == self.token.kind && segment.args.is_none() {
|
if token::ModSep == self.token.kind && segment.args.is_none() {
|
||||||
let snapshot = self.clone();
|
let snapshot = self.create_snapshot_for_diagnostic();
|
||||||
self.bump();
|
self.bump();
|
||||||
let lo = self.token.span;
|
let lo = self.token.span;
|
||||||
match self.parse_angle_args(None) {
|
match self.parse_angle_args(None) {
|
||||||
|
@ -712,14 +755,14 @@ impl<'a> Parser<'a> {
|
||||||
.emit();
|
.emit();
|
||||||
} else {
|
} else {
|
||||||
// This doesn't look like an invalid turbofish, can't recover parse state.
|
// This doesn't look like an invalid turbofish, can't recover parse state.
|
||||||
*self = snapshot;
|
self.restore_snapshot(snapshot);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Err(err) => {
|
Err(err) => {
|
||||||
// We couldn't parse generic parameters, unlikely to be a turbofish. Rely on
|
// We couldn't parse generic parameters, unlikely to be a turbofish. Rely on
|
||||||
// generic parse error instead.
|
// generic parse error instead.
|
||||||
err.cancel();
|
err.cancel();
|
||||||
*self = snapshot;
|
self.restore_snapshot(snapshot);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -825,7 +868,7 @@ impl<'a> Parser<'a> {
|
||||||
// `x == y < z`
|
// `x == y < z`
|
||||||
(BinOpKind::Eq, AssocOp::Less | AssocOp::LessEqual | AssocOp::Greater | AssocOp::GreaterEqual) => {
|
(BinOpKind::Eq, AssocOp::Less | AssocOp::LessEqual | AssocOp::Greater | AssocOp::GreaterEqual) => {
|
||||||
// Consume `z`/outer-op-rhs.
|
// Consume `z`/outer-op-rhs.
|
||||||
let snapshot = self.clone();
|
let snapshot = self.create_snapshot_for_diagnostic();
|
||||||
match self.parse_expr() {
|
match self.parse_expr() {
|
||||||
Ok(r2) => {
|
Ok(r2) => {
|
||||||
// We are sure that outer-op-rhs could be consumed, the suggestion is
|
// We are sure that outer-op-rhs could be consumed, the suggestion is
|
||||||
|
@ -835,14 +878,14 @@ impl<'a> Parser<'a> {
|
||||||
}
|
}
|
||||||
Err(expr_err) => {
|
Err(expr_err) => {
|
||||||
expr_err.cancel();
|
expr_err.cancel();
|
||||||
*self = snapshot;
|
self.restore_snapshot(snapshot);
|
||||||
false
|
false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// `x > y == z`
|
// `x > y == z`
|
||||||
(BinOpKind::Lt | BinOpKind::Le | BinOpKind::Gt | BinOpKind::Ge, AssocOp::Equal) => {
|
(BinOpKind::Lt | BinOpKind::Le | BinOpKind::Gt | BinOpKind::Ge, AssocOp::Equal) => {
|
||||||
let snapshot = self.clone();
|
let snapshot = self.create_snapshot_for_diagnostic();
|
||||||
// At this point it is always valid to enclose the lhs in parentheses, no
|
// At this point it is always valid to enclose the lhs in parentheses, no
|
||||||
// further checks are necessary.
|
// further checks are necessary.
|
||||||
match self.parse_expr() {
|
match self.parse_expr() {
|
||||||
|
@ -852,7 +895,7 @@ impl<'a> Parser<'a> {
|
||||||
}
|
}
|
||||||
Err(expr_err) => {
|
Err(expr_err) => {
|
||||||
expr_err.cancel();
|
expr_err.cancel();
|
||||||
*self = snapshot;
|
self.restore_snapshot(snapshot);
|
||||||
false
|
false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -917,7 +960,7 @@ impl<'a> Parser<'a> {
|
||||||
|| outer_op.node == AssocOp::Greater
|
|| outer_op.node == AssocOp::Greater
|
||||||
{
|
{
|
||||||
if outer_op.node == AssocOp::Less {
|
if outer_op.node == AssocOp::Less {
|
||||||
let snapshot = self.clone();
|
let snapshot = self.create_snapshot_for_diagnostic();
|
||||||
self.bump();
|
self.bump();
|
||||||
// So far we have parsed `foo<bar<`, consume the rest of the type args.
|
// So far we have parsed `foo<bar<`, consume the rest of the type args.
|
||||||
let modifiers =
|
let modifiers =
|
||||||
|
@ -929,7 +972,7 @@ impl<'a> Parser<'a> {
|
||||||
{
|
{
|
||||||
// We don't have `foo< bar >(` or `foo< bar >::`, so we rewind the
|
// We don't have `foo< bar >(` or `foo< bar >::`, so we rewind the
|
||||||
// parser and bail out.
|
// parser and bail out.
|
||||||
*self = snapshot.clone();
|
self.restore_snapshot(snapshot);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return if token::ModSep == self.token.kind {
|
return if token::ModSep == self.token.kind {
|
||||||
|
@ -937,7 +980,7 @@ impl<'a> Parser<'a> {
|
||||||
// `foo< bar >::`
|
// `foo< bar >::`
|
||||||
suggest(&mut err);
|
suggest(&mut err);
|
||||||
|
|
||||||
let snapshot = self.clone();
|
let snapshot = self.create_snapshot_for_diagnostic();
|
||||||
self.bump(); // `::`
|
self.bump(); // `::`
|
||||||
|
|
||||||
// Consume the rest of the likely `foo<bar>::new()` or return at `foo<bar>`.
|
// Consume the rest of the likely `foo<bar>::new()` or return at `foo<bar>`.
|
||||||
|
@ -954,7 +997,7 @@ impl<'a> Parser<'a> {
|
||||||
expr_err.cancel();
|
expr_err.cancel();
|
||||||
// Not entirely sure now, but we bubble the error up with the
|
// Not entirely sure now, but we bubble the error up with the
|
||||||
// suggestion.
|
// suggestion.
|
||||||
*self = snapshot;
|
self.restore_snapshot(snapshot);
|
||||||
Err(err)
|
Err(err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1008,7 +1051,7 @@ impl<'a> Parser<'a> {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn consume_fn_args(&mut self) -> Result<(), ()> {
|
fn consume_fn_args(&mut self) -> Result<(), ()> {
|
||||||
let snapshot = self.clone();
|
let snapshot = self.create_snapshot_for_diagnostic();
|
||||||
self.bump(); // `(`
|
self.bump(); // `(`
|
||||||
|
|
||||||
// Consume the fn call arguments.
|
// Consume the fn call arguments.
|
||||||
|
@ -1018,7 +1061,7 @@ impl<'a> Parser<'a> {
|
||||||
|
|
||||||
if self.token.kind == token::Eof {
|
if self.token.kind == token::Eof {
|
||||||
// Not entirely sure that what we consumed were fn arguments, rollback.
|
// Not entirely sure that what we consumed were fn arguments, rollback.
|
||||||
*self = snapshot;
|
self.restore_snapshot(snapshot);
|
||||||
Err(())
|
Err(())
|
||||||
} else {
|
} else {
|
||||||
// 99% certain that the suggestion is correct, continue parsing.
|
// 99% certain that the suggestion is correct, continue parsing.
|
||||||
|
@ -1959,12 +2002,12 @@ impl<'a> Parser<'a> {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn recover_const_param_decl(&mut self, ty_generics: Option<&Generics>) -> Option<GenericArg> {
|
fn recover_const_param_decl(&mut self, ty_generics: Option<&Generics>) -> Option<GenericArg> {
|
||||||
let snapshot = self.clone();
|
let snapshot = self.create_snapshot_for_diagnostic();
|
||||||
let param = match self.parse_const_param(vec![]) {
|
let param = match self.parse_const_param(vec![]) {
|
||||||
Ok(param) => param,
|
Ok(param) => param,
|
||||||
Err(err) => {
|
Err(err) => {
|
||||||
err.cancel();
|
err.cancel();
|
||||||
*self = snapshot;
|
self.restore_snapshot(snapshot);
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -2056,7 +2099,7 @@ impl<'a> Parser<'a> {
|
||||||
// We perform these checks and early return to avoid taking a snapshot unnecessarily.
|
// We perform these checks and early return to avoid taking a snapshot unnecessarily.
|
||||||
return Err(err);
|
return Err(err);
|
||||||
}
|
}
|
||||||
let snapshot = self.clone();
|
let snapshot = self.create_snapshot_for_diagnostic();
|
||||||
if is_op_or_dot {
|
if is_op_or_dot {
|
||||||
self.bump();
|
self.bump();
|
||||||
}
|
}
|
||||||
|
@ -2101,7 +2144,7 @@ impl<'a> Parser<'a> {
|
||||||
err.cancel();
|
err.cancel();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
*self = snapshot;
|
self.restore_snapshot(snapshot);
|
||||||
Err(err)
|
Err(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2161,7 +2204,7 @@ impl<'a> Parser<'a> {
|
||||||
let span = self.token.span;
|
let span = self.token.span;
|
||||||
// We only emit "unexpected `:`" error here if we can successfully parse the
|
// We only emit "unexpected `:`" error here if we can successfully parse the
|
||||||
// whole pattern correctly in that case.
|
// whole pattern correctly in that case.
|
||||||
let snapshot = self.clone();
|
let snapshot = self.create_snapshot_for_diagnostic();
|
||||||
|
|
||||||
// Create error for "unexpected `:`".
|
// Create error for "unexpected `:`".
|
||||||
match self.expected_one_of_not_found(&[], &[]) {
|
match self.expected_one_of_not_found(&[], &[]) {
|
||||||
|
@ -2173,7 +2216,7 @@ impl<'a> Parser<'a> {
|
||||||
// reasonable error.
|
// reasonable error.
|
||||||
inner_err.cancel();
|
inner_err.cancel();
|
||||||
err.cancel();
|
err.cancel();
|
||||||
*self = snapshot;
|
self.restore_snapshot(snapshot);
|
||||||
}
|
}
|
||||||
Ok(mut pat) => {
|
Ok(mut pat) => {
|
||||||
// We've parsed the rest of the pattern.
|
// We've parsed the rest of the pattern.
|
||||||
|
@ -2252,7 +2295,7 @@ impl<'a> Parser<'a> {
|
||||||
}
|
}
|
||||||
_ => {
|
_ => {
|
||||||
// Carry on as if we had not done anything. This should be unreachable.
|
// Carry on as if we had not done anything. This should be unreachable.
|
||||||
*self = snapshot;
|
self.restore_snapshot(snapshot);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
first_pat
|
first_pat
|
||||||
|
|
|
@ -703,7 +703,7 @@ impl<'a> Parser<'a> {
|
||||||
ExprKind::Path(None, ast::Path { segments, .. }),
|
ExprKind::Path(None, ast::Path { segments, .. }),
|
||||||
TokenKind::Ident(kw::For | kw::Loop | kw::While, false),
|
TokenKind::Ident(kw::For | kw::Loop | kw::While, false),
|
||||||
) if segments.len() == 1 => {
|
) if segments.len() == 1 => {
|
||||||
let snapshot = self.clone();
|
let snapshot = self.create_snapshot_for_diagnostic();
|
||||||
let label = Label {
|
let label = Label {
|
||||||
ident: Ident::from_str_and_span(
|
ident: Ident::from_str_and_span(
|
||||||
&format!("'{}", segments[0].ident),
|
&format!("'{}", segments[0].ident),
|
||||||
|
@ -725,7 +725,7 @@ impl<'a> Parser<'a> {
|
||||||
}
|
}
|
||||||
Err(err) => {
|
Err(err) => {
|
||||||
err.cancel();
|
err.cancel();
|
||||||
*self = snapshot;
|
self.restore_snapshot(snapshot);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1885,7 +1885,7 @@ impl<'a> Parser<'a> {
|
||||||
lo: Span,
|
lo: Span,
|
||||||
attrs: AttrVec,
|
attrs: AttrVec,
|
||||||
) -> Option<P<Expr>> {
|
) -> Option<P<Expr>> {
|
||||||
let mut snapshot = self.clone();
|
let mut snapshot = self.create_snapshot_for_diagnostic();
|
||||||
match snapshot.parse_array_or_repeat_expr(attrs, token::Brace) {
|
match snapshot.parse_array_or_repeat_expr(attrs, token::Brace) {
|
||||||
Ok(arr) => {
|
Ok(arr) => {
|
||||||
let hi = snapshot.prev_token.span;
|
let hi = snapshot.prev_token.span;
|
||||||
|
@ -1901,7 +1901,7 @@ impl<'a> Parser<'a> {
|
||||||
.note("to define an array, one would use square brackets instead of curly braces")
|
.note("to define an array, one would use square brackets instead of curly braces")
|
||||||
.emit();
|
.emit();
|
||||||
|
|
||||||
*self = snapshot;
|
self.restore_snapshot(snapshot);
|
||||||
Some(self.mk_expr_err(arr.span))
|
Some(self.mk_expr_err(arr.span))
|
||||||
}
|
}
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
|
@ -2369,7 +2369,7 @@ impl<'a> Parser<'a> {
|
||||||
if self.token.kind != token::Semi {
|
if self.token.kind != token::Semi {
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
let start_snapshot = self.clone();
|
let start_snapshot = self.create_snapshot_for_diagnostic();
|
||||||
let semi_sp = self.token.span;
|
let semi_sp = self.token.span;
|
||||||
self.bump(); // `;`
|
self.bump(); // `;`
|
||||||
let mut stmts =
|
let mut stmts =
|
||||||
|
@ -2417,15 +2417,15 @@ impl<'a> Parser<'a> {
|
||||||
return Some(err(self, stmts));
|
return Some(err(self, stmts));
|
||||||
}
|
}
|
||||||
if self.token.kind == token::Comma {
|
if self.token.kind == token::Comma {
|
||||||
*self = start_snapshot;
|
self.restore_snapshot(start_snapshot);
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
let pre_pat_snapshot = self.clone();
|
let pre_pat_snapshot = self.create_snapshot_for_diagnostic();
|
||||||
match self.parse_pat_no_top_alt(None) {
|
match self.parse_pat_no_top_alt(None) {
|
||||||
Ok(_pat) => {
|
Ok(_pat) => {
|
||||||
if self.token.kind == token::FatArrow {
|
if self.token.kind == token::FatArrow {
|
||||||
// Reached arm end.
|
// Reached arm end.
|
||||||
*self = pre_pat_snapshot;
|
self.restore_snapshot(pre_pat_snapshot);
|
||||||
return Some(err(self, stmts));
|
return Some(err(self, stmts));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2434,21 +2434,21 @@ impl<'a> Parser<'a> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
*self = pre_pat_snapshot;
|
self.restore_snapshot(pre_pat_snapshot);
|
||||||
match self.parse_stmt_without_recovery(true, ForceCollect::No) {
|
match self.parse_stmt_without_recovery(true, ForceCollect::No) {
|
||||||
// Consume statements for as long as possible.
|
// Consume statements for as long as possible.
|
||||||
Ok(Some(stmt)) => {
|
Ok(Some(stmt)) => {
|
||||||
stmts.push(stmt);
|
stmts.push(stmt);
|
||||||
}
|
}
|
||||||
Ok(None) => {
|
Ok(None) => {
|
||||||
*self = start_snapshot;
|
self.restore_snapshot(start_snapshot);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
// We couldn't parse either yet another statement missing it's
|
// We couldn't parse either yet another statement missing it's
|
||||||
// enclosing block nor the next arm's pattern or closing brace.
|
// enclosing block nor the next arm's pattern or closing brace.
|
||||||
Err(stmt_err) => {
|
Err(stmt_err) => {
|
||||||
stmt_err.cancel();
|
stmt_err.cancel();
|
||||||
*self = start_snapshot;
|
self.restore_snapshot(start_snapshot);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -624,9 +624,18 @@ impl<'a> Parser<'a> {
|
||||||
GenericArg::Const(self.parse_const_arg()?)
|
GenericArg::Const(self.parse_const_arg()?)
|
||||||
} else if self.check_type() {
|
} else if self.check_type() {
|
||||||
// Parse type argument.
|
// Parse type argument.
|
||||||
|
let is_const_fn = self.look_ahead(1, |t| t.kind == token::OpenDelim(token::Paren));
|
||||||
|
let mut snapshot = self.create_snapshot_for_diagnostic();
|
||||||
match self.parse_ty() {
|
match self.parse_ty() {
|
||||||
Ok(ty) => GenericArg::Type(ty),
|
Ok(ty) => GenericArg::Type(ty),
|
||||||
Err(err) => {
|
Err(err) => {
|
||||||
|
if is_const_fn {
|
||||||
|
if let Ok(expr) = (*snapshot).parse_expr_res(Restrictions::CONST_EXPR, None)
|
||||||
|
{
|
||||||
|
self.restore_snapshot(snapshot);
|
||||||
|
return Ok(Some(self.dummy_const_arg_needs_braces(err, expr.span)));
|
||||||
|
}
|
||||||
|
}
|
||||||
// Try to recover from possible `const` arg without braces.
|
// Try to recover from possible `const` arg without braces.
|
||||||
return self.recover_const_arg(start, err).map(Some);
|
return self.recover_const_arg(start, err).map(Some);
|
||||||
}
|
}
|
||||||
|
@ -636,7 +645,7 @@ impl<'a> Parser<'a> {
|
||||||
} else {
|
} else {
|
||||||
// Fall back by trying to parse a const-expr expression. If we successfully do so,
|
// 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.
|
// then we should report an error that it needs to be wrapped in braces.
|
||||||
let snapshot = self.clone();
|
let snapshot = self.create_snapshot_for_diagnostic();
|
||||||
match self.parse_expr_res(Restrictions::CONST_EXPR, None) {
|
match self.parse_expr_res(Restrictions::CONST_EXPR, None) {
|
||||||
Ok(expr) => {
|
Ok(expr) => {
|
||||||
return Ok(Some(self.dummy_const_arg_needs_braces(
|
return Ok(Some(self.dummy_const_arg_needs_braces(
|
||||||
|
@ -645,7 +654,7 @@ impl<'a> Parser<'a> {
|
||||||
)));
|
)));
|
||||||
}
|
}
|
||||||
Err(err) => {
|
Err(err) => {
|
||||||
*self = snapshot;
|
self.restore_snapshot(snapshot);
|
||||||
err.cancel();
|
err.cancel();
|
||||||
return Ok(None);
|
return Ok(None);
|
||||||
}
|
}
|
||||||
|
|
21
src/test/ui/const-generics/const-generic-function.rs
Normal file
21
src/test/ui/const-generics/const-generic-function.rs
Normal file
|
@ -0,0 +1,21 @@
|
||||||
|
fn foo<const N: i32>() -> i32 {
|
||||||
|
N
|
||||||
|
}
|
||||||
|
|
||||||
|
const fn bar(n: i32, m: i32) -> i32 {
|
||||||
|
n
|
||||||
|
}
|
||||||
|
|
||||||
|
const fn baz() -> i32 {
|
||||||
|
1
|
||||||
|
}
|
||||||
|
|
||||||
|
const FOO: i32 = 3;
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
foo::<baz()>(); //~ ERROR expected type, found function `baz`
|
||||||
|
//~| ERROR unresolved item provided when a constant was expected
|
||||||
|
foo::<bar(bar(1, 1), bar(1, 1))>(); //~ ERROR expected type, found `1`
|
||||||
|
foo::<bar(1, 1)>(); //~ ERROR expected type, found `1`
|
||||||
|
foo::<bar(FOO, 2)>(); //~ ERROR expected type, found `2`
|
||||||
|
}
|
54
src/test/ui/const-generics/const-generic-function.stderr
Normal file
54
src/test/ui/const-generics/const-generic-function.stderr
Normal file
|
@ -0,0 +1,54 @@
|
||||||
|
error: expected type, found `1`
|
||||||
|
--> $DIR/const-generic-function.rs:18:19
|
||||||
|
|
|
||||||
|
LL | foo::<bar(bar(1, 1), bar(1, 1))>();
|
||||||
|
| ^ expected type
|
||||||
|
|
|
||||||
|
help: expressions must be enclosed in braces to be used as const generic arguments
|
||||||
|
|
|
||||||
|
LL | foo::<{ bar(bar(1, 1), bar(1, 1)) }>();
|
||||||
|
| + +
|
||||||
|
|
||||||
|
error: expected type, found `1`
|
||||||
|
--> $DIR/const-generic-function.rs:19:15
|
||||||
|
|
|
||||||
|
LL | foo::<bar(1, 1)>();
|
||||||
|
| ^ expected type
|
||||||
|
|
|
||||||
|
help: expressions must be enclosed in braces to be used as const generic arguments
|
||||||
|
|
|
||||||
|
LL | foo::<{ bar(1, 1) }>();
|
||||||
|
| + +
|
||||||
|
|
||||||
|
error: expected type, found `2`
|
||||||
|
--> $DIR/const-generic-function.rs:20:20
|
||||||
|
|
|
||||||
|
LL | foo::<bar(FOO, 2)>();
|
||||||
|
| ^ expected type
|
||||||
|
|
|
||||||
|
help: expressions must be enclosed in braces to be used as const generic arguments
|
||||||
|
|
|
||||||
|
LL | foo::<{ bar(FOO, 2) }>();
|
||||||
|
| + +
|
||||||
|
|
||||||
|
error[E0573]: expected type, found function `baz`
|
||||||
|
--> $DIR/const-generic-function.rs:16:11
|
||||||
|
|
|
||||||
|
LL | foo::<baz()>();
|
||||||
|
| ^^^^^ not a type
|
||||||
|
|
||||||
|
error[E0747]: unresolved item provided when a constant was expected
|
||||||
|
--> $DIR/const-generic-function.rs:16:11
|
||||||
|
|
|
||||||
|
LL | foo::<baz()>();
|
||||||
|
| ^^^^^
|
||||||
|
|
|
||||||
|
help: if this generic argument was intended as a const parameter, surround it with braces
|
||||||
|
|
|
||||||
|
LL | foo::<{ baz() }>();
|
||||||
|
| + +
|
||||||
|
|
||||||
|
error: aborting due to 5 previous errors
|
||||||
|
|
||||||
|
Some errors have detailed explanations: E0573, E0747.
|
||||||
|
For more information about an error, try `rustc --explain E0573`.
|
Loading…
Add table
Add a link
Reference in a new issue