Skip to content

Commit 5eb3433

Browse files
authored
Rollup merge of #94731 - TaKO8Ki:const-generic-expr-recovery, r=davidtwco,oli-obk
Suggest adding `{ .. }` around a const function call with arguments closes #91020
2 parents a8956e6 + 9a65322 commit 5eb3433

File tree

6 files changed

+163
-36
lines changed

6 files changed

+163
-36
lines changed

compiler/rustc_parse/src/parser/attr.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -151,7 +151,7 @@ impl<'a> Parser<'a> {
151151
span: Span,
152152
attr_type: OuterAttributeType,
153153
) -> Option<Span> {
154-
let mut snapshot = self.clone();
154+
let mut snapshot = self.create_snapshot_for_diagnostic();
155155
let lo = span.lo()
156156
+ BytePos(match attr_type {
157157
OuterAttributeType::Attribute => 1,

compiler/rustc_parse/src/parser/diagnostics.rs

+65-22
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ use super::{
55
SemiColonMode, SeqSep, TokenExpectType, TokenType,
66
};
77

8+
use crate::lexer::UnmatchedBrace;
89
use rustc_ast as ast;
910
use rustc_ast::ptr::P;
1011
use rustc_ast::token::{self, Lit, LitKind, TokenKind};
@@ -21,6 +22,7 @@ use rustc_errors::{Applicability, DiagnosticBuilder, Handler, PResult};
2122
use rustc_span::source_map::Spanned;
2223
use rustc_span::symbol::{kw, Ident};
2324
use rustc_span::{MultiSpan, Span, SpanSnippetError, DUMMY_SP};
25+
use std::ops::{Deref, DerefMut};
2426

2527
use std::mem::take;
2628

@@ -154,6 +156,28 @@ impl AttemptLocalParseRecovery {
154156
}
155157
}
156158

159+
// SnapshotParser is used to create a snapshot of the parser
160+
// without causing duplicate errors being emitted when the `Parser`
161+
// is dropped.
162+
pub(super) struct SnapshotParser<'a> {
163+
parser: Parser<'a>,
164+
unclosed_delims: Vec<UnmatchedBrace>,
165+
}
166+
167+
impl<'a> Deref for SnapshotParser<'a> {
168+
type Target = Parser<'a>;
169+
170+
fn deref(&self) -> &Self::Target {
171+
&self.parser
172+
}
173+
}
174+
175+
impl<'a> DerefMut for SnapshotParser<'a> {
176+
fn deref_mut(&mut self) -> &mut Self::Target {
177+
&mut self.parser
178+
}
179+
}
180+
157181
impl<'a> Parser<'a> {
158182
pub(super) fn span_err<S: Into<MultiSpan>>(
159183
&self,
@@ -179,6 +203,25 @@ impl<'a> Parser<'a> {
179203
&self.sess.span_diagnostic
180204
}
181205

206+
/// Relace `self` with `snapshot.parser` and extend `unclosed_delims` with `snapshot.unclosed_delims`.
207+
/// This is to avoid losing unclosed delims errors `create_snapshot_for_diagnostic` clears.
208+
pub(super) fn restore_snapshot(&mut self, snapshot: SnapshotParser<'a>) {
209+
*self = snapshot.parser;
210+
self.unclosed_delims.extend(snapshot.unclosed_delims.clone());
211+
}
212+
213+
/// Create a snapshot of the `Parser`.
214+
pub(super) fn create_snapshot_for_diagnostic(&self) -> SnapshotParser<'a> {
215+
let mut snapshot = self.clone();
216+
let unclosed_delims = self.unclosed_delims.clone();
217+
// Clear `unclosed_delims` in snapshot to avoid
218+
// duplicate errors being emitted when the `Parser`
219+
// is dropped (which may or may not happen, depending
220+
// if the parsing the snapshot is created for is successful)
221+
snapshot.unclosed_delims.clear();
222+
SnapshotParser { parser: snapshot, unclosed_delims }
223+
}
224+
182225
pub(super) fn span_to_snippet(&self, span: Span) -> Result<String, SpanSnippetError> {
183226
self.sess.source_map().span_to_snippet(span)
184227
}
@@ -438,7 +481,7 @@ impl<'a> Parser<'a> {
438481
// fn foo() -> Foo {
439482
// field: value,
440483
// }
441-
let mut snapshot = self.clone();
484+
let mut snapshot = self.create_snapshot_for_diagnostic();
442485
let path =
443486
Path { segments: vec![], span: self.prev_token.span.shrink_to_lo(), tokens: None };
444487
let struct_expr = snapshot.parse_struct_expr(None, path, AttrVec::new(), false);
@@ -464,7 +507,7 @@ impl<'a> Parser<'a> {
464507
Applicability::MaybeIncorrect,
465508
)
466509
.emit();
467-
*self = snapshot;
510+
self.restore_snapshot(snapshot);
468511
let mut tail = self.mk_block(
469512
vec![self.mk_stmt_err(expr.span)],
470513
s,
@@ -678,7 +721,7 @@ impl<'a> Parser<'a> {
678721
/// angle brackets.
679722
pub(super) fn check_turbofish_missing_angle_brackets(&mut self, segment: &mut PathSegment) {
680723
if token::ModSep == self.token.kind && segment.args.is_none() {
681-
let snapshot = self.clone();
724+
let snapshot = self.create_snapshot_for_diagnostic();
682725
self.bump();
683726
let lo = self.token.span;
684727
match self.parse_angle_args(None) {
@@ -712,14 +755,14 @@ impl<'a> Parser<'a> {
712755
.emit();
713756
} else {
714757
// This doesn't look like an invalid turbofish, can't recover parse state.
715-
*self = snapshot;
758+
self.restore_snapshot(snapshot);
716759
}
717760
}
718761
Err(err) => {
719762
// We couldn't parse generic parameters, unlikely to be a turbofish. Rely on
720763
// generic parse error instead.
721764
err.cancel();
722-
*self = snapshot;
765+
self.restore_snapshot(snapshot);
723766
}
724767
}
725768
}
@@ -825,7 +868,7 @@ impl<'a> Parser<'a> {
825868
// `x == y < z`
826869
(BinOpKind::Eq, AssocOp::Less | AssocOp::LessEqual | AssocOp::Greater | AssocOp::GreaterEqual) => {
827870
// Consume `z`/outer-op-rhs.
828-
let snapshot = self.clone();
871+
let snapshot = self.create_snapshot_for_diagnostic();
829872
match self.parse_expr() {
830873
Ok(r2) => {
831874
// We are sure that outer-op-rhs could be consumed, the suggestion is
@@ -835,14 +878,14 @@ impl<'a> Parser<'a> {
835878
}
836879
Err(expr_err) => {
837880
expr_err.cancel();
838-
*self = snapshot;
881+
self.restore_snapshot(snapshot);
839882
false
840883
}
841884
}
842885
}
843886
// `x > y == z`
844887
(BinOpKind::Lt | BinOpKind::Le | BinOpKind::Gt | BinOpKind::Ge, AssocOp::Equal) => {
845-
let snapshot = self.clone();
888+
let snapshot = self.create_snapshot_for_diagnostic();
846889
// At this point it is always valid to enclose the lhs in parentheses, no
847890
// further checks are necessary.
848891
match self.parse_expr() {
@@ -852,7 +895,7 @@ impl<'a> Parser<'a> {
852895
}
853896
Err(expr_err) => {
854897
expr_err.cancel();
855-
*self = snapshot;
898+
self.restore_snapshot(snapshot);
856899
false
857900
}
858901
}
@@ -917,7 +960,7 @@ impl<'a> Parser<'a> {
917960
|| outer_op.node == AssocOp::Greater
918961
{
919962
if outer_op.node == AssocOp::Less {
920-
let snapshot = self.clone();
963+
let snapshot = self.create_snapshot_for_diagnostic();
921964
self.bump();
922965
// So far we have parsed `foo<bar<`, consume the rest of the type args.
923966
let modifiers =
@@ -929,15 +972,15 @@ impl<'a> Parser<'a> {
929972
{
930973
// We don't have `foo< bar >(` or `foo< bar >::`, so we rewind the
931974
// parser and bail out.
932-
*self = snapshot.clone();
975+
self.restore_snapshot(snapshot);
933976
}
934977
}
935978
return if token::ModSep == self.token.kind {
936979
// We have some certainty that this was a bad turbofish at this point.
937980
// `foo< bar >::`
938981
suggest(&mut err);
939982

940-
let snapshot = self.clone();
983+
let snapshot = self.create_snapshot_for_diagnostic();
941984
self.bump(); // `::`
942985

943986
// Consume the rest of the likely `foo<bar>::new()` or return at `foo<bar>`.
@@ -954,7 +997,7 @@ impl<'a> Parser<'a> {
954997
expr_err.cancel();
955998
// Not entirely sure now, but we bubble the error up with the
956999
// suggestion.
957-
*self = snapshot;
1000+
self.restore_snapshot(snapshot);
9581001
Err(err)
9591002
}
9601003
}
@@ -1008,7 +1051,7 @@ impl<'a> Parser<'a> {
10081051
}
10091052

10101053
fn consume_fn_args(&mut self) -> Result<(), ()> {
1011-
let snapshot = self.clone();
1054+
let snapshot = self.create_snapshot_for_diagnostic();
10121055
self.bump(); // `(`
10131056

10141057
// Consume the fn call arguments.
@@ -1018,7 +1061,7 @@ impl<'a> Parser<'a> {
10181061

10191062
if self.token.kind == token::Eof {
10201063
// Not entirely sure that what we consumed were fn arguments, rollback.
1021-
*self = snapshot;
1064+
self.restore_snapshot(snapshot);
10221065
Err(())
10231066
} else {
10241067
// 99% certain that the suggestion is correct, continue parsing.
@@ -1959,12 +2002,12 @@ impl<'a> Parser<'a> {
19592002
}
19602003

19612004
fn recover_const_param_decl(&mut self, ty_generics: Option<&Generics>) -> Option<GenericArg> {
1962-
let snapshot = self.clone();
2005+
let snapshot = self.create_snapshot_for_diagnostic();
19632006
let param = match self.parse_const_param(vec![]) {
19642007
Ok(param) => param,
19652008
Err(err) => {
19662009
err.cancel();
1967-
*self = snapshot;
2010+
self.restore_snapshot(snapshot);
19682011
return None;
19692012
}
19702013
};
@@ -2056,7 +2099,7 @@ impl<'a> Parser<'a> {
20562099
// We perform these checks and early return to avoid taking a snapshot unnecessarily.
20572100
return Err(err);
20582101
}
2059-
let snapshot = self.clone();
2102+
let snapshot = self.create_snapshot_for_diagnostic();
20602103
if is_op_or_dot {
20612104
self.bump();
20622105
}
@@ -2101,7 +2144,7 @@ impl<'a> Parser<'a> {
21012144
err.cancel();
21022145
}
21032146
}
2104-
*self = snapshot;
2147+
self.restore_snapshot(snapshot);
21052148
Err(err)
21062149
}
21072150

@@ -2161,7 +2204,7 @@ impl<'a> Parser<'a> {
21612204
let span = self.token.span;
21622205
// We only emit "unexpected `:`" error here if we can successfully parse the
21632206
// whole pattern correctly in that case.
2164-
let snapshot = self.clone();
2207+
let snapshot = self.create_snapshot_for_diagnostic();
21652208

21662209
// Create error for "unexpected `:`".
21672210
match self.expected_one_of_not_found(&[], &[]) {
@@ -2173,7 +2216,7 @@ impl<'a> Parser<'a> {
21732216
// reasonable error.
21742217
inner_err.cancel();
21752218
err.cancel();
2176-
*self = snapshot;
2219+
self.restore_snapshot(snapshot);
21772220
}
21782221
Ok(mut pat) => {
21792222
// We've parsed the rest of the pattern.
@@ -2252,7 +2295,7 @@ impl<'a> Parser<'a> {
22522295
}
22532296
_ => {
22542297
// Carry on as if we had not done anything. This should be unreachable.
2255-
*self = snapshot;
2298+
self.restore_snapshot(snapshot);
22562299
}
22572300
};
22582301
first_pat

compiler/rustc_parse/src/parser/expr.rs

+11-11
Original file line numberDiff line numberDiff line change
@@ -703,7 +703,7 @@ impl<'a> Parser<'a> {
703703
ExprKind::Path(None, ast::Path { segments, .. }),
704704
TokenKind::Ident(kw::For | kw::Loop | kw::While, false),
705705
) if segments.len() == 1 => {
706-
let snapshot = self.clone();
706+
let snapshot = self.create_snapshot_for_diagnostic();
707707
let label = Label {
708708
ident: Ident::from_str_and_span(
709709
&format!("'{}", segments[0].ident),
@@ -725,7 +725,7 @@ impl<'a> Parser<'a> {
725725
}
726726
Err(err) => {
727727
err.cancel();
728-
*self = snapshot;
728+
self.restore_snapshot(snapshot);
729729
}
730730
}
731731
}
@@ -1885,7 +1885,7 @@ impl<'a> Parser<'a> {
18851885
lo: Span,
18861886
attrs: AttrVec,
18871887
) -> Option<P<Expr>> {
1888-
let mut snapshot = self.clone();
1888+
let mut snapshot = self.create_snapshot_for_diagnostic();
18891889
match snapshot.parse_array_or_repeat_expr(attrs, token::Brace) {
18901890
Ok(arr) => {
18911891
let hi = snapshot.prev_token.span;
@@ -1901,7 +1901,7 @@ impl<'a> Parser<'a> {
19011901
.note("to define an array, one would use square brackets instead of curly braces")
19021902
.emit();
19031903

1904-
*self = snapshot;
1904+
self.restore_snapshot(snapshot);
19051905
Some(self.mk_expr_err(arr.span))
19061906
}
19071907
Err(e) => {
@@ -2369,7 +2369,7 @@ impl<'a> Parser<'a> {
23692369
if self.token.kind != token::Semi {
23702370
return None;
23712371
}
2372-
let start_snapshot = self.clone();
2372+
let start_snapshot = self.create_snapshot_for_diagnostic();
23732373
let semi_sp = self.token.span;
23742374
self.bump(); // `;`
23752375
let mut stmts =
@@ -2417,15 +2417,15 @@ impl<'a> Parser<'a> {
24172417
return Some(err(self, stmts));
24182418
}
24192419
if self.token.kind == token::Comma {
2420-
*self = start_snapshot;
2420+
self.restore_snapshot(start_snapshot);
24212421
return None;
24222422
}
2423-
let pre_pat_snapshot = self.clone();
2423+
let pre_pat_snapshot = self.create_snapshot_for_diagnostic();
24242424
match self.parse_pat_no_top_alt(None) {
24252425
Ok(_pat) => {
24262426
if self.token.kind == token::FatArrow {
24272427
// Reached arm end.
2428-
*self = pre_pat_snapshot;
2428+
self.restore_snapshot(pre_pat_snapshot);
24292429
return Some(err(self, stmts));
24302430
}
24312431
}
@@ -2434,21 +2434,21 @@ impl<'a> Parser<'a> {
24342434
}
24352435
}
24362436

2437-
*self = pre_pat_snapshot;
2437+
self.restore_snapshot(pre_pat_snapshot);
24382438
match self.parse_stmt_without_recovery(true, ForceCollect::No) {
24392439
// Consume statements for as long as possible.
24402440
Ok(Some(stmt)) => {
24412441
stmts.push(stmt);
24422442
}
24432443
Ok(None) => {
2444-
*self = start_snapshot;
2444+
self.restore_snapshot(start_snapshot);
24452445
break;
24462446
}
24472447
// We couldn't parse either yet another statement missing it's
24482448
// enclosing block nor the next arm's pattern or closing brace.
24492449
Err(stmt_err) => {
24502450
stmt_err.cancel();
2451-
*self = start_snapshot;
2451+
self.restore_snapshot(start_snapshot);
24522452
break;
24532453
}
24542454
}

compiler/rustc_parse/src/parser/path.rs

+11-2
Original file line numberDiff line numberDiff line change
@@ -624,9 +624,18 @@ impl<'a> Parser<'a> {
624624
GenericArg::Const(self.parse_const_arg()?)
625625
} else if self.check_type() {
626626
// Parse type argument.
627+
let is_const_fn = self.look_ahead(1, |t| t.kind == token::OpenDelim(token::Paren));
628+
let mut snapshot = self.create_snapshot_for_diagnostic();
627629
match self.parse_ty() {
628630
Ok(ty) => GenericArg::Type(ty),
629631
Err(err) => {
632+
if is_const_fn {
633+
if let Ok(expr) = (*snapshot).parse_expr_res(Restrictions::CONST_EXPR, None)
634+
{
635+
self.restore_snapshot(snapshot);
636+
return Ok(Some(self.dummy_const_arg_needs_braces(err, expr.span)));
637+
}
638+
}
630639
// Try to recover from possible `const` arg without braces.
631640
return self.recover_const_arg(start, err).map(Some);
632641
}
@@ -636,7 +645,7 @@ impl<'a> Parser<'a> {
636645
} else {
637646
// Fall back by trying to parse a const-expr expression. If we successfully do so,
638647
// then we should report an error that it needs to be wrapped in braces.
639-
let snapshot = self.clone();
648+
let snapshot = self.create_snapshot_for_diagnostic();
640649
match self.parse_expr_res(Restrictions::CONST_EXPR, None) {
641650
Ok(expr) => {
642651
return Ok(Some(self.dummy_const_arg_needs_braces(
@@ -645,7 +654,7 @@ impl<'a> Parser<'a> {
645654
)));
646655
}
647656
Err(err) => {
648-
*self = snapshot;
657+
self.restore_snapshot(snapshot);
649658
err.cancel();
650659
return Ok(None);
651660
}

0 commit comments

Comments
 (0)