Rollup merge of #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 #97788
This commit is contained in:
Dylan DPC 2022-06-08 07:37:31 +02:00 committed by GitHub
commit a64a9829c8
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 93 additions and 20 deletions

View File

@ -204,25 +204,7 @@ fn parse_item_kind(
let mut def = || mem::replace(def, Defaultness::Final);
let info = if self.eat_keyword(kw::Use) {
// USE ITEM
let tree = self.parse_use_tree()?;
// If wildcard or glob-like brace syntax doesn't have `;`,
// the user may not know `*` or `{}` should be the last.
if let Err(mut e) = self.expect_semi() {
match tree.kind {
UseTreeKind::Glob => {
e.note("the wildcard token must be last on the path");
}
UseTreeKind::Nested(..) => {
e.note("glob-like brace syntax must be last on the path");
}
_ => (),
}
return Err(e);
}
(Ident::empty(), ItemKind::Use(tree))
self.parse_use_item()?
} else if self.check_fn_front_matter(def_final) {
// FUNCTION ITEM
let (ident, sig, generics, body) = self.parse_fn(attrs, fn_parse_mode, lo, vis)?;
@ -288,7 +270,12 @@ fn parse_item_kind(
} else if let IsMacroRulesItem::Yes { has_bang } = self.is_macro_rules_item() {
// MACRO_RULES ITEM
self.parse_item_macro_rules(vis, has_bang)?
} else if vis.kind.is_pub() && self.isnt_macro_invocation() {
} else if self.isnt_macro_invocation()
&& (self.token.is_ident_named(Symbol::intern("import"))
|| self.token.is_ident_named(Symbol::intern("using")))
{
return self.recover_import_as_use();
} else if self.isnt_macro_invocation() && vis.kind.is_pub() {
self.recover_missing_kw_before_item()?;
return Ok(None);
} else if macros_allowed && self.check_path() {
@ -300,6 +287,48 @@ fn parse_item_kind(
Ok(Some(info))
}
fn recover_import_as_use(&mut self) -> PResult<'a, Option<(Ident, ItemKind)>> {
let span = self.token.span;
let token_name = super::token_descr(&self.token);
let snapshot = self.create_snapshot_for_diagnostic();
self.bump();
match self.parse_use_item() {
Ok(u) => {
self.struct_span_err(span, format!("expected item, found {token_name}"))
.span_suggestion_short(
span,
"items are imported using the `use` keyword",
"use".to_owned(),
Applicability::MachineApplicable,
)
.emit();
Ok(Some(u))
}
Err(e) => {
e.cancel();
self.restore_snapshot(snapshot);
Ok(None)
}
}
}
fn parse_use_item(&mut self) -> PResult<'a, (Ident, ItemKind)> {
let tree = self.parse_use_tree()?;
if let Err(mut e) = self.expect_semi() {
match tree.kind {
UseTreeKind::Glob => {
e.note("the wildcard token must be last on the path");
}
UseTreeKind::Nested(..) => {
e.note("glob-like brace syntax must be last on the path");
}
_ => (),
}
return Err(e);
}
Ok((Ident::empty(), ItemKind::Use(tree)))
}
/// When parsing a statement, would the start of a path be an item?
pub(super) fn is_path_start_item(&mut self) -> bool {
self.is_kw_followed_by_ident(kw::Union) // no: `union::b`, yes: `union U { .. }`

View File

@ -0,0 +1,15 @@
// run-rustfix
use std::{
//~^ ERROR expected item, found `import`
io::Write,
rc::Rc,
};
pub use std::io;
//~^ ERROR expected item, found `using`
fn main() {
let x = Rc::new(1);
let _ = write!(io::stdout(), "{:?}", x);
}

View File

@ -0,0 +1,15 @@
// run-rustfix
import std::{
//~^ ERROR expected item, found `import`
io::Write,
rc::Rc,
};
pub using std::io;
//~^ ERROR expected item, found `using`
fn main() {
let x = Rc::new(1);
let _ = write!(io::stdout(), "{:?}", x);
}

View File

@ -0,0 +1,14 @@
error: expected item, found `import`
--> $DIR/use_instead_of_import.rs:3:1
|
LL | import std::{
| ^^^^^^ help: items are imported using the `use` keyword
error: expected item, found `using`
--> $DIR/use_instead_of_import.rs:9:5
|
LL | pub using std::io;
| ^^^^^ help: items are imported using the `use` keyword
error: aborting due to 2 previous errors