Skip to content

Commit a64a982

Browse files
authored
Rollup merge of rust-lang#97819 - compiler-errors:use-import, r=wesleywiser
Recover `import` instead of `use` in item When we definitely don't have a macro invocation (i.e. when we don't have `import ::`), then it's more productive to parse `import` as if it was incorrectly mistaken for `use`. Not sure if this needs to be a verbose suggestion, but it renders strangely when it's not verbose: ``` error: expected item, found `import` --> /home/michael/test.rs:1:1 | 1 | import std::{io::{self, Write}, rc::Rc}; | ^^^^^^ help: items are imported using the `use` keyword: `use` ``` Happy to change it to `span_suggestion` instead of `span_suggestion_verbose` though. Fixes rust-lang#97788
2 parents d380b45 + b7ed860 commit a64a982

File tree

4 files changed

+93
-20
lines changed

4 files changed

+93
-20
lines changed

compiler/rustc_parse/src/parser/item.rs

+49-20
Original file line numberDiff line numberDiff line change
@@ -204,25 +204,7 @@ impl<'a> Parser<'a> {
204204
let mut def = || mem::replace(def, Defaultness::Final);
205205

206206
let info = if self.eat_keyword(kw::Use) {
207-
// USE ITEM
208-
let tree = self.parse_use_tree()?;
209-
210-
// If wildcard or glob-like brace syntax doesn't have `;`,
211-
// the user may not know `*` or `{}` should be the last.
212-
if let Err(mut e) = self.expect_semi() {
213-
match tree.kind {
214-
UseTreeKind::Glob => {
215-
e.note("the wildcard token must be last on the path");
216-
}
217-
UseTreeKind::Nested(..) => {
218-
e.note("glob-like brace syntax must be last on the path");
219-
}
220-
_ => (),
221-
}
222-
return Err(e);
223-
}
224-
225-
(Ident::empty(), ItemKind::Use(tree))
207+
self.parse_use_item()?
226208
} else if self.check_fn_front_matter(def_final) {
227209
// FUNCTION ITEM
228210
let (ident, sig, generics, body) = self.parse_fn(attrs, fn_parse_mode, lo, vis)?;
@@ -288,7 +270,12 @@ impl<'a> Parser<'a> {
288270
} else if let IsMacroRulesItem::Yes { has_bang } = self.is_macro_rules_item() {
289271
// MACRO_RULES ITEM
290272
self.parse_item_macro_rules(vis, has_bang)?
291-
} else if vis.kind.is_pub() && self.isnt_macro_invocation() {
273+
} else if self.isnt_macro_invocation()
274+
&& (self.token.is_ident_named(Symbol::intern("import"))
275+
|| self.token.is_ident_named(Symbol::intern("using")))
276+
{
277+
return self.recover_import_as_use();
278+
} else if self.isnt_macro_invocation() && vis.kind.is_pub() {
292279
self.recover_missing_kw_before_item()?;
293280
return Ok(None);
294281
} else if macros_allowed && self.check_path() {
@@ -300,6 +287,48 @@ impl<'a> Parser<'a> {
300287
Ok(Some(info))
301288
}
302289

290+
fn recover_import_as_use(&mut self) -> PResult<'a, Option<(Ident, ItemKind)>> {
291+
let span = self.token.span;
292+
let token_name = super::token_descr(&self.token);
293+
let snapshot = self.create_snapshot_for_diagnostic();
294+
self.bump();
295+
match self.parse_use_item() {
296+
Ok(u) => {
297+
self.struct_span_err(span, format!("expected item, found {token_name}"))
298+
.span_suggestion_short(
299+
span,
300+
"items are imported using the `use` keyword",
301+
"use".to_owned(),
302+
Applicability::MachineApplicable,
303+
)
304+
.emit();
305+
Ok(Some(u))
306+
}
307+
Err(e) => {
308+
e.cancel();
309+
self.restore_snapshot(snapshot);
310+
Ok(None)
311+
}
312+
}
313+
}
314+
315+
fn parse_use_item(&mut self) -> PResult<'a, (Ident, ItemKind)> {
316+
let tree = self.parse_use_tree()?;
317+
if let Err(mut e) = self.expect_semi() {
318+
match tree.kind {
319+
UseTreeKind::Glob => {
320+
e.note("the wildcard token must be last on the path");
321+
}
322+
UseTreeKind::Nested(..) => {
323+
e.note("glob-like brace syntax must be last on the path");
324+
}
325+
_ => (),
326+
}
327+
return Err(e);
328+
}
329+
Ok((Ident::empty(), ItemKind::Use(tree)))
330+
}
331+
303332
/// When parsing a statement, would the start of a path be an item?
304333
pub(super) fn is_path_start_item(&mut self) -> bool {
305334
self.is_kw_followed_by_ident(kw::Union) // no: `union::b`, yes: `union U { .. }`
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
// run-rustfix
2+
3+
use std::{
4+
//~^ ERROR expected item, found `import`
5+
io::Write,
6+
rc::Rc,
7+
};
8+
9+
pub use std::io;
10+
//~^ ERROR expected item, found `using`
11+
12+
fn main() {
13+
let x = Rc::new(1);
14+
let _ = write!(io::stdout(), "{:?}", x);
15+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
// run-rustfix
2+
3+
import std::{
4+
//~^ ERROR expected item, found `import`
5+
io::Write,
6+
rc::Rc,
7+
};
8+
9+
pub using std::io;
10+
//~^ ERROR expected item, found `using`
11+
12+
fn main() {
13+
let x = Rc::new(1);
14+
let _ = write!(io::stdout(), "{:?}", x);
15+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
error: expected item, found `import`
2+
--> $DIR/use_instead_of_import.rs:3:1
3+
|
4+
LL | import std::{
5+
| ^^^^^^ help: items are imported using the `use` keyword
6+
7+
error: expected item, found `using`
8+
--> $DIR/use_instead_of_import.rs:9:5
9+
|
10+
LL | pub using std::io;
11+
| ^^^^^ help: items are imported using the `use` keyword
12+
13+
error: aborting due to 2 previous errors
14+

0 commit comments

Comments
 (0)