Skip to content

Commit 57d1590

Browse files
author
Orion Gonzalez
committed
improve parse item fallback
1 parent 011dd54 commit 57d1590

File tree

8 files changed

+70
-31
lines changed

8 files changed

+70
-31
lines changed

compiler/rustc_ast_pretty/src/pprust/mod.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ use std::borrow::Cow;
77
use rustc_ast as ast;
88
use rustc_ast::token::{Nonterminal, Token, TokenKind};
99
use rustc_ast::tokenstream::{TokenStream, TokenTree};
10-
pub use state::{print_crate, AnnNode, Comments, PpAnn, PrintState, State};
10+
pub use state::{AnnNode, Comments, PpAnn, PrintState, State, print_crate};
1111

1212
pub fn nonterminal_to_string(nt: &Nonterminal) -> String {
1313
State::new().nonterminal_to_string(nt)

compiler/rustc_parse/src/parser/item.rs

Lines changed: 29 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -10,15 +10,15 @@ use rustc_ast::util::case::Case;
1010
use rustc_ast::{self as ast};
1111
use rustc_ast_pretty::pprust;
1212
use rustc_errors::codes::*;
13-
use rustc_errors::{struct_span_code_err, Applicability, PResult, StashKey};
13+
use rustc_errors::{Applicability, PResult, StashKey, struct_span_code_err};
1414
use rustc_span::edit_distance::edit_distance;
1515
use rustc_span::edition::Edition;
16-
use rustc_span::symbol::{kw, sym, Ident, Symbol};
17-
use rustc_span::{source_map, ErrorGuaranteed, Span, DUMMY_SP};
18-
use thin_vec::{thin_vec, ThinVec};
16+
use rustc_span::symbol::{Ident, Symbol, kw, sym};
17+
use rustc_span::{DUMMY_SP, ErrorGuaranteed, Span, source_map};
18+
use thin_vec::{ThinVec, thin_vec};
1919
use tracing::debug;
2020

21-
use super::diagnostics::{dummy_arg, ConsumeClosingDelim};
21+
use super::diagnostics::{ConsumeClosingDelim, dummy_arg};
2222
use super::ty::{AllowPlus, RecoverQPath, RecoverReturnSign};
2323
use super::{
2424
AttemptLocalParseRecovery, AttrWrapper, FollowedByType, ForceCollect, Parser, PathStyle,
@@ -75,6 +75,8 @@ impl<'a> Parser<'a> {
7575
items.push(item);
7676
}
7777

78+
// The last token should be `term`: either EOF or `}`. If it's not that means that we've had an error
79+
// parsing an item
7880
if !self.eat(term) {
7981
if !self.maybe_consume_incorrect_semicolon(items.last().map(|x| &**x)) {
8082
let err = self.fallback_incorrect_item();
@@ -90,12 +92,15 @@ impl<'a> Parser<'a> {
9092
/// Tries to parse the item as a statement to provide further diagnostics.
9193
fn fallback_incorrect_item(&mut self) -> rustc_errors::Diag<'a> {
9294
let token_str = super::token_descr(&self.token);
93-
let mut err = self
94-
.dcx()
95-
.struct_span_err(self.token.span, format!("expected item, found {token_str}"));
95+
let token_span = self.token.span;
96+
let mut err =
97+
self.dcx().struct_span_err(token_span, format!("expected item, found {token_str}"));
98+
99+
let mut do_default_diag = true;
96100

97101
match self.parse_full_stmt(AttemptLocalParseRecovery::No) {
98102
Ok(Some(stmt)) => {
103+
do_default_diag = false;
99104
let span = stmt.span;
100105
match &stmt.kind {
101106
StmtKind::Let(_) => {
@@ -121,16 +126,22 @@ impl<'a> Parser<'a> {
121126
);
122127
}
123128
StmtKind::Item(_) | StmtKind::MacCall(_) => {
124-
unreachable!("These should be valid.")
129+
unreachable!("These should be valid items!")
125130
}
126131
};
127132
}
128-
Ok(None) => {} // It's not a statement, not much we can do.
133+
// It's not a statement, we can't do much recovery.
134+
Ok(None) => {}
129135
Err(e) => {
130136
// We don't really care about an error parsing this statement.
131137
e.cancel();
132138
}
133139
}
140+
141+
if do_default_diag {
142+
err.span_label(token_span, "expected item");
143+
}
144+
134145
err.note("for a full list of items that can appear in modules, see <https://doc.rust-lang.org/reference/items.html>");
135146

136147
err
@@ -490,11 +501,7 @@ impl<'a> Parser<'a> {
490501
None
491502
};
492503

493-
if let Some(err) = err {
494-
Err(self.dcx().create_err(err))
495-
} else {
496-
Ok(())
497-
}
504+
if let Some(err) = err { Err(self.dcx().create_err(err)) } else { Ok(()) }
498505
}
499506

500507
fn parse_item_builtin(&mut self) -> PResult<'a, Option<ItemInfo>> {
@@ -1154,11 +1161,7 @@ impl<'a> Parser<'a> {
11541161
}
11551162

11561163
fn parse_rename(&mut self) -> PResult<'a, Option<Ident>> {
1157-
if self.eat_keyword(kw::As) {
1158-
self.parse_ident_or_underscore().map(Some)
1159-
} else {
1160-
Ok(None)
1161-
}
1164+
if self.eat_keyword(kw::As) { self.parse_ident_or_underscore().map(Some) } else { Ok(None) }
11621165
}
11631166

11641167
fn parse_ident_or_underscore(&mut self) -> PResult<'a, Ident> {
@@ -1241,7 +1244,7 @@ impl<'a> Parser<'a> {
12411244
mut safety: Safety,
12421245
) -> PResult<'a, ItemInfo> {
12431246
let abi = self.parse_abi(); // ABI?
1244-
// FIXME: This recovery should be tested better.
1247+
// FIXME: This recovery should be tested better.
12451248
if safety == Safety::Default
12461249
&& self.token.is_keyword(kw::Unsafe)
12471250
&& self.look_ahead(1, |t| *t == token::OpenDelim(Delimiter::Brace))
@@ -1943,10 +1946,10 @@ impl<'a> Parser<'a> {
19431946
// Try to recover extra trailing angle brackets
19441947
if let TyKind::Path(_, Path { segments, .. }) = &a_var.ty.kind {
19451948
if let Some(last_segment) = segments.last() {
1946-
let guar = self.check_trailing_angle_brackets(
1947-
last_segment,
1948-
&[&token::Comma, &token::CloseDelim(Delimiter::Brace)],
1949-
);
1949+
let guar = self.check_trailing_angle_brackets(last_segment, &[
1950+
&token::Comma,
1951+
&token::CloseDelim(Delimiter::Brace),
1952+
]);
19501953
if let Some(_guar) = guar {
19511954
// Handle a case like `Vec<u8>>,` where we can continue parsing fields
19521955
// after the comma
@@ -2153,7 +2156,7 @@ impl<'a> Parser<'a> {
21532156
self.unexpected()?;
21542157
}
21552158
let body = self.parse_token_tree(); // `MacBody`
2156-
// Convert `MacParams MacBody` into `{ MacParams => MacBody }`.
2159+
// Convert `MacParams MacBody` into `{ MacParams => MacBody }`.
21572160
let bspan = body.span();
21582161
let arrow = TokenTree::token_alone(token::FatArrow, pspan.between(bspan)); // `=>`
21592162
let tokens = TokenStream::new(vec![params, arrow, body]);

tests/ui/parser/issues/issue-113110-non-item-at-module-root.stderr

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,9 @@ error: expected item, found `5`
22
--> $DIR/issue-113110-non-item-at-module-root.rs:1:2
33
|
44
LL | 5
5-
| ^ expected item
5+
| ^ unexpected expression
66
|
7+
= help: consider putting it inside a function: fn foo() { 5 }
78
= note: for a full list of items that can appear in modules, see <https://doc.rust-lang.org/reference/items.html>
89

910
error: aborting due to 1 previous error

tests/ui/parser/issues/issue-62913.stderr

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,8 +16,9 @@ error: expected item, found `"\u\"`
1616
--> $DIR/issue-62913.rs:1:1
1717
|
1818
LL | "\u\"
19-
| ^^^^^^ expected item
19+
| ^^^^^^ unexpected expression
2020
|
21+
= help: consider putting it inside a function: fn foo() { "\u\" }
2122
= note: for a full list of items that can appear in modules, see <https://doc.rust-lang.org/reference/items.html>
2223

2324
error: aborting due to 3 previous errors
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
mod m {
2+
pub let answer = 42;
3+
//~^ ERROR visibility `pub` is not followed by an item
4+
//~| ERROR expected item, found keyword `let`
5+
}
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
error: visibility `pub` is not followed by an item
2+
--> $DIR/pub-let-outside-fn.rs:2:5
3+
|
4+
LL | pub let answer = 42;
5+
| ^^^ the visibility
6+
|
7+
= help: you likely meant to define an item, e.g., `pub fn foo() {}`
8+
9+
error: expected item, found keyword `let`
10+
--> $DIR/pub-let-outside-fn.rs:2:9
11+
|
12+
LL | pub let answer = 42;
13+
| ^^^-------------
14+
| |
15+
| unexpected `let` binding outside of a function
16+
|
17+
= help: consider using `const` or `static` instead of `let` for global variables, or put it inside of a function: fn foo() { let answer = 42; }
18+
= note: for a full list of items that can appear in modules, see <https://doc.rust-lang.org/reference/items.html>
19+
20+
error: aborting due to 2 previous errors
21+

tests/ui/parser/shebang/shebang-doc-comment.stderr

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,11 @@ error: expected item, found `[`
22
--> $DIR/shebang-doc-comment.rs:2:1
33
|
44
LL | [allow(unused_variables)]
5-
| ^ expected item
5+
| ^------------------------
6+
| |
7+
| unexpected expression
68
|
9+
= help: consider putting it inside a function: fn foo() { [allow(unused_variables)] }
710
= note: for a full list of items that can appear in modules, see <https://doc.rust-lang.org/reference/items.html>
811

912
error: aborting due to 1 previous error

tests/ui/parser/suggest-const-for-global-var.stderr

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,12 @@ error: expected item, found keyword `let`
22
--> $DIR/suggest-const-for-global-var.rs:1:1
33
|
44
LL | let X: i32 = 12;
5-
| ^^^ consider using `const` or `static` instead of `let` for global variables
5+
| ^^^-------------
6+
| |
7+
| unexpected `let` binding outside of a function
8+
|
9+
= help: consider using `const` or `static` instead of `let` for global variables, or put it inside of a function: fn foo() { let X: i32 = 12; }
10+
= note: for a full list of items that can appear in modules, see <https://doc.rust-lang.org/reference/items.html>
611

712
error: aborting due to 1 previous error
813

0 commit comments

Comments
 (0)