Skip to content

Commit 3729002

Browse files
authored
Unrolled build for #143065
Rollup merge of #143065 - compiler-errors:enum-recovery, r=oli-obk Improve recovery when users write `where:` Improve recovery of `where:`. Fixes #143023 The erroneous suggestion was because we were seeing `:` then a type, which the original impl thought must be a struct field. Make this a bit more accurate by checking for a non-reserved ident (which should be a field name). Also, make a custom parser error for `where:` so we can continue parsing after the colon.
2 parents 13c46fd + 4e51e67 commit 3729002

File tree

11 files changed

+53
-16
lines changed

11 files changed

+53
-16
lines changed

compiler/rustc_ast/src/token.rs

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -893,7 +893,7 @@ impl Token {
893893
|| self.is_qpath_start()
894894
|| matches!(self.is_metavar_seq(), Some(MetaVarKind::Path))
895895
|| self.is_path_segment_keyword()
896-
|| self.is_ident() && !self.is_reserved_ident()
896+
|| self.is_non_reserved_ident()
897897
}
898898

899899
/// Returns `true` if the token is a given keyword, `kw`.
@@ -937,6 +937,10 @@ impl Token {
937937
self.is_non_raw_ident_where(Ident::is_reserved)
938938
}
939939

940+
pub fn is_non_reserved_ident(&self) -> bool {
941+
self.ident().is_some_and(|(id, raw)| raw == IdentIsRaw::Yes || !Ident::is_reserved(id))
942+
}
943+
940944
/// Returns `true` if the token is the identifier `true` or `false`.
941945
pub fn is_bool_lit(&self) -> bool {
942946
self.is_non_raw_ident_where(|id| id.name.is_bool_lit())

compiler/rustc_ast/src/tokenstream.rs

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -634,10 +634,8 @@ impl TokenStream {
634634
(
635635
TokenTree::Token(token_left, Spacing::Alone),
636636
TokenTree::Token(token_right, _),
637-
) if ((token_left.is_ident() && !token_left.is_reserved_ident())
638-
|| token_left.is_lit())
639-
&& ((token_right.is_ident() && !token_right.is_reserved_ident())
640-
|| token_right.is_lit()) =>
637+
) if (token_left.is_non_reserved_ident() || token_left.is_lit())
638+
&& (token_right.is_non_reserved_ident() || token_right.is_lit()) =>
641639
{
642640
token_left.span
643641
}

compiler/rustc_parse/src/parser/diagnostics.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2731,7 +2731,7 @@ impl<'a> Parser<'a> {
27312731
return first_pat;
27322732
}
27332733
if !matches!(first_pat.kind, PatKind::Ident(_, _, None) | PatKind::Path(..))
2734-
|| !self.look_ahead(1, |token| token.is_ident() && !token.is_reserved_ident())
2734+
|| !self.look_ahead(1, |token| token.is_non_reserved_ident())
27352735
{
27362736
let mut snapshot_type = self.create_snapshot_for_diagnostic();
27372737
snapshot_type.bump(); // `:`

compiler/rustc_parse/src/parser/expr.rs

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3875,8 +3875,7 @@ impl<'a> Parser<'a> {
38753875
// Check if a colon exists one ahead. This means we're parsing a fieldname.
38763876
let is_shorthand = !this.look_ahead(1, |t| t == &token::Colon || t == &token::Eq);
38773877
// Proactively check whether parsing the field will be incorrect.
3878-
let is_wrong = this.token.is_ident()
3879-
&& !this.token.is_reserved_ident()
3878+
let is_wrong = this.token.is_non_reserved_ident()
38803879
&& !this.look_ahead(1, |t| {
38813880
t == &token::Colon
38823881
|| t == &token::Eq

compiler/rustc_parse/src/parser/generics.rs

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -353,6 +353,20 @@ impl<'a> Parser<'a> {
353353
if !self.eat_keyword(exp!(Where)) {
354354
return Ok((where_clause, None));
355355
}
356+
357+
if self.eat_noexpect(&token::Colon) {
358+
let colon_span = self.prev_token.span;
359+
self.dcx()
360+
.struct_span_err(colon_span, "unexpected colon after `where`")
361+
.with_span_suggestion_short(
362+
colon_span,
363+
"remove the colon",
364+
"",
365+
Applicability::MachineApplicable,
366+
)
367+
.emit();
368+
}
369+
356370
where_clause.has_where_token = true;
357371
let where_lo = self.prev_token.span;
358372

compiler/rustc_parse/src/parser/item.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1552,7 +1552,8 @@ impl<'a> Parser<'a> {
15521552
})
15531553
.map_err(|mut err| {
15541554
err.span_label(ident.span, "while parsing this enum");
1555-
if self.token == token::Colon {
1555+
// Try to recover `enum Foo { ident : Ty }`.
1556+
if self.prev_token.is_non_reserved_ident() && self.token == token::Colon {
15561557
let snapshot = self.create_snapshot_for_diagnostic();
15571558
self.bump();
15581559
match self.parse_ty() {

compiler/rustc_parse/src/parser/mod.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -685,7 +685,7 @@ impl<'a> Parser<'a> {
685685

686686
/// Is the given keyword `kw` followed by a non-reserved identifier?
687687
fn is_kw_followed_by_ident(&self, kw: Symbol) -> bool {
688-
self.token.is_keyword(kw) && self.look_ahead(1, |t| t.is_ident() && !t.is_reserved_ident())
688+
self.token.is_keyword(kw) && self.look_ahead(1, |t| t.is_non_reserved_ident())
689689
}
690690

691691
#[inline]

compiler/rustc_parse/src/parser/path.rs

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -126,7 +126,7 @@ impl<'a> Parser<'a> {
126126
/// ```
127127
fn recover_colon_before_qpath_proj(&mut self) -> bool {
128128
if !self.check_noexpect(&TokenKind::Colon)
129-
|| self.look_ahead(1, |t| !t.is_ident() || t.is_reserved_ident())
129+
|| self.look_ahead(1, |t| !t.is_non_reserved_ident())
130130
{
131131
return false;
132132
}
@@ -260,7 +260,7 @@ impl<'a> Parser<'a> {
260260
if self.may_recover()
261261
&& style == PathStyle::Expr // (!)
262262
&& self.token == token::Colon
263-
&& self.look_ahead(1, |token| token.is_ident() && !token.is_reserved_ident())
263+
&& self.look_ahead(1, |token| token.is_non_reserved_ident())
264264
{
265265
// Emit a special error message for `a::b:c` to help users
266266
// otherwise, `a: c` might have meant to introduce a new binding
@@ -334,9 +334,7 @@ impl<'a> Parser<'a> {
334334
self.expect_gt().map_err(|mut err| {
335335
// Try to recover a `:` into a `::`
336336
if self.token == token::Colon
337-
&& self.look_ahead(1, |token| {
338-
token.is_ident() && !token.is_reserved_ident()
339-
})
337+
&& self.look_ahead(1, |token| token.is_non_reserved_ident())
340338
{
341339
err.cancel();
342340
err = self.dcx().create_err(PathSingleColon {

compiler/rustc_parse/src/parser/stmt.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -798,7 +798,7 @@ impl<'a> Parser<'a> {
798798
}
799799
if self.prev_token.is_reserved_ident() && self.prev_token.is_ident_named(kw::Await) {
800800
// Likely `foo.await bar`
801-
} else if !self.prev_token.is_reserved_ident() && self.prev_token.is_ident() {
801+
} else if self.prev_token.is_non_reserved_ident() {
802802
// Likely `foo bar`
803803
} else if self.prev_token.kind == token::Question {
804804
// `foo? bar`
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
pub enum Foo<T>
2+
where:
3+
//~^ ERROR unexpected colon after `where`
4+
T: Missing, {}
5+
//~^ ERROR cannot find trait `Missing` in this scope
6+
// (evidence that we continue parsing after the erroneous colon)
7+
8+
fn main() {}
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
error: unexpected colon after `where`
2+
--> $DIR/recover-enum-with-bad-where.rs:2:6
3+
|
4+
LL | where:
5+
| ^ help: remove the colon
6+
7+
error[E0405]: cannot find trait `Missing` in this scope
8+
--> $DIR/recover-enum-with-bad-where.rs:4:8
9+
|
10+
LL | T: Missing, {}
11+
| ^^^^^^^ not found in this scope
12+
13+
error: aborting due to 2 previous errors
14+
15+
For more information about this error, try `rustc --explain E0405`.

0 commit comments

Comments
 (0)