about summary refs log tree commit diff
path: root/src
diff options
context:
space:
mode:
authorDylan DPC <dylan.dpc@gmail.com>2020-05-20 14:21:00 +0200
committerGitHub <noreply@github.com>2020-05-20 14:21:00 +0200
commit14c439177b779408452fdf2c8f4fc620f27905d1 (patch)
tree8393244fdbc73646e1ed9b0ec4594b07756ab1c4 /src
parent64ad709ad4d2863b7995d8b9e90a1bedb7d0ccf1 (diff)
parentaaeea7ffc36cd705116bf45f0479e51788ae33c5 (diff)
downloadrust-14c439177b779408452fdf2c8f4fc620f27905d1.tar.gz
rust-14c439177b779408452fdf2c8f4fc620f27905d1.zip
Rollup merge of #71863 - mibac138:self-import, r=estebank
Suggest fixes and add error recovery for `use foo::self`

Fixes #63741.
I have implemented 2 suggestions on how to fix a `use foo::self` import, however I feel like showing them both might be too verbose.

Additionally, I have also implemented error recovery as [menitoned](https://github.com/rust-lang/rust/issues/63741#issuecomment-602391091) by @comex.

I believe r? @estebank deals with diagnostics.
Diffstat (limited to 'src')
-rw-r--r--src/librustc_resolve/build_reduced_graph.rs29
-rw-r--r--src/librustc_resolve/diagnostics.rs41
-rw-r--r--src/librustc_resolve/lib.rs2
-rw-r--r--src/test/ui/error-codes/E0429.stderr13
-rw-r--r--src/test/ui/issues/issue-45829/import-self.rs2
-rw-r--r--src/test/ui/issues/issue-45829/import-self.stderr30
-rw-r--r--src/test/ui/use/use-keyword.stderr2
-rw-r--r--src/test/ui/use/use-mod/use-mod-4.stderr28
-rw-r--r--src/test/ui/use/use-mod/use-mod-5.rs13
-rw-r--r--src/test/ui/use/use-mod/use-mod-5.stderr18
-rw-r--r--src/test/ui/use/use-mod/use-mod-6.rs13
-rw-r--r--src/test/ui/use/use-mod/use-mod-6.stderr18
12 files changed, 186 insertions, 23 deletions
diff --git a/src/librustc_resolve/build_reduced_graph.rs b/src/librustc_resolve/build_reduced_graph.rs
index d0eb1cfc222..988ec3d4374 100644
--- a/src/librustc_resolve/build_reduced_graph.rs
+++ b/src/librustc_resolve/build_reduced_graph.rs
@@ -426,7 +426,7 @@ impl<'a, 'b> BuildReducedGraphVisitor<'a, 'b> {
                             return;
                         }
 
-                        // Replace `use foo::self;` with `use foo;`
+                        // Replace `use foo::{ self };` with `use foo;`
                         source = module_path.pop().unwrap();
                         if rename.is_none() {
                             ident = source.ident;
@@ -435,10 +435,33 @@ impl<'a, 'b> BuildReducedGraphVisitor<'a, 'b> {
                 } else {
                     // Disallow `self`
                     if source.ident.name == kw::SelfLower {
+                        let parent = module_path.last();
+
+                        let span = match parent {
+                            // only `::self` from `use foo::self as bar`
+                            Some(seg) => seg.ident.span.shrink_to_hi().to(source.ident.span),
+                            None => source.ident.span,
+                        };
+                        let span_with_rename = match rename {
+                            // only `self as bar` from `use foo::self as bar`
+                            Some(rename) => source.ident.span.to(rename.span),
+                            None => source.ident.span,
+                        };
                         self.r.report_error(
-                            use_tree.span,
-                            ResolutionError::SelfImportsOnlyAllowedWithin,
+                            span,
+                            ResolutionError::SelfImportsOnlyAllowedWithin {
+                                root: parent.is_none(),
+                                span_with_rename,
+                            },
                         );
+
+                        // Error recovery: replace `use foo::self;` with `use foo;`
+                        if let Some(parent) = module_path.pop() {
+                            source = parent;
+                            if rename.is_none() {
+                                ident = source.ident;
+                            }
+                        }
                     }
 
                     // Disallow `use $crate;`
diff --git a/src/librustc_resolve/diagnostics.rs b/src/librustc_resolve/diagnostics.rs
index c66e9a60406..ea237f1a04f 100644
--- a/src/librustc_resolve/diagnostics.rs
+++ b/src/librustc_resolve/diagnostics.rs
@@ -301,13 +301,40 @@ impl<'a> Resolver<'a> {
                 }
                 err
             }
-            ResolutionError::SelfImportsOnlyAllowedWithin => struct_span_err!(
-                self.session,
-                span,
-                E0429,
-                "{}",
-                "`self` imports are only allowed within a { } list"
-            ),
+            ResolutionError::SelfImportsOnlyAllowedWithin { root, span_with_rename } => {
+                let mut err = struct_span_err!(
+                    self.session,
+                    span,
+                    E0429,
+                    "{}",
+                    "`self` imports are only allowed within a { } list"
+                );
+
+                // None of the suggestions below would help with a case like `use self`.
+                if !root {
+                    // use foo::bar::self        -> foo::bar
+                    // use foo::bar::self as abc -> foo::bar as abc
+                    err.span_suggestion(
+                        span,
+                        "consider importing the module directly",
+                        "".to_string(),
+                        Applicability::MachineApplicable,
+                    );
+
+                    // use foo::bar::self        -> foo::bar::{self}
+                    // use foo::bar::self as abc -> foo::bar::{self as abc}
+                    let braces = vec![
+                        (span_with_rename.shrink_to_lo(), "{".to_string()),
+                        (span_with_rename.shrink_to_hi(), "}".to_string()),
+                    ];
+                    err.multipart_suggestion(
+                        "alternatively, use the multi-path `use` syntax to import `self`",
+                        braces,
+                        Applicability::MachineApplicable,
+                    );
+                }
+                err
+            }
             ResolutionError::SelfImportCanOnlyAppearOnceInTheList => {
                 let mut err = struct_span_err!(
                     self.session,
diff --git a/src/librustc_resolve/lib.rs b/src/librustc_resolve/lib.rs
index 2031b7868c0..bfb7f081fc3 100644
--- a/src/librustc_resolve/lib.rs
+++ b/src/librustc_resolve/lib.rs
@@ -194,7 +194,7 @@ enum ResolutionError<'a> {
     /// Error E0426: use of undeclared label.
     UndeclaredLabel(&'a str, Option<Symbol>),
     /// Error E0429: `self` imports are only allowed within a `{ }` list.
-    SelfImportsOnlyAllowedWithin,
+    SelfImportsOnlyAllowedWithin { root: bool, span_with_rename: Span },
     /// Error E0430: `self` import can only appear once in the list.
     SelfImportCanOnlyAppearOnceInTheList,
     /// Error E0431: `self` import can only appear in an import list with a non-empty prefix.
diff --git a/src/test/ui/error-codes/E0429.stderr b/src/test/ui/error-codes/E0429.stderr
index b5f76a1fcd8..c598803fa6c 100644
--- a/src/test/ui/error-codes/E0429.stderr
+++ b/src/test/ui/error-codes/E0429.stderr
@@ -1,8 +1,17 @@
 error[E0429]: `self` imports are only allowed within a { } list
-  --> $DIR/E0429.rs:1:5
+  --> $DIR/E0429.rs:1:13
    |
 LL | use std::fmt::self;
-   |     ^^^^^^^^^^^^^^
+   |             ^^^^^^
+   |
+help: consider importing the module directly
+   |
+LL | use std::fmt;
+   |            --
+help: alternatively, use the multi-path `use` syntax to import `self`
+   |
+LL | use std::fmt::{self};
+   |               ^    ^
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/issues/issue-45829/import-self.rs b/src/test/ui/issues/issue-45829/import-self.rs
index 6cb18e1cdb7..2dc4331ced7 100644
--- a/src/test/ui/issues/issue-45829/import-self.rs
+++ b/src/test/ui/issues/issue-45829/import-self.rs
@@ -9,7 +9,7 @@ use foo::{self};
 use foo as self;
 //~^ ERROR expected identifier
 
-use foo::self;
+use foo::self; //~ ERROR is defined multiple times
 //~^ ERROR `self` imports are only allowed within a { } list
 
 use foo::A;
diff --git a/src/test/ui/issues/issue-45829/import-self.stderr b/src/test/ui/issues/issue-45829/import-self.stderr
index 39522cd8183..158e81cdd96 100644
--- a/src/test/ui/issues/issue-45829/import-self.stderr
+++ b/src/test/ui/issues/issue-45829/import-self.stderr
@@ -5,10 +5,19 @@ LL | use foo as self;
    |            ^^^^ expected identifier, found keyword
 
 error[E0429]: `self` imports are only allowed within a { } list
-  --> $DIR/import-self.rs:12:5
+  --> $DIR/import-self.rs:12:8
    |
 LL | use foo::self;
-   |     ^^^^^^^^^
+   |        ^^^^^^
+   |
+help: consider importing the module directly
+   |
+LL | use foo;
+   |       --
+help: alternatively, use the multi-path `use` syntax to import `self`
+   |
+LL | use foo::{self};
+   |          ^    ^
 
 error[E0255]: the name `foo` is defined multiple times
   --> $DIR/import-self.rs:6:11
@@ -25,6 +34,21 @@ help: you can use `as` to change the binding name of the import
 LL | use foo::{self as other_foo};
    |           ^^^^^^^^^^^^^^^^^
 
+error[E0255]: the name `foo` is defined multiple times
+  --> $DIR/import-self.rs:12:5
+   |
+LL | mod foo {
+   | ------- previous definition of the module `foo` here
+...
+LL | use foo::self;
+   |     ^^^^^^^^^ `foo` reimported here
+   |
+   = note: `foo` must be defined only once in the type namespace of this module
+help: you can use `as` to change the binding name of the import
+   |
+LL | use foo as other_foo;
+   |     ^^^^^^^^^^^^^^^^
+
 error[E0252]: the name `A` is defined multiple times
   --> $DIR/import-self.rs:16:11
    |
@@ -39,7 +63,7 @@ help: you can use `as` to change the binding name of the import
 LL | use foo::{self as OtherA};
    |           ^^^^^^^^^^^^^^
 
-error: aborting due to 4 previous errors
+error: aborting due to 5 previous errors
 
 Some errors have detailed explanations: E0252, E0255, E0429.
 For more information about an error, try `rustc --explain E0252`.
diff --git a/src/test/ui/use/use-keyword.stderr b/src/test/ui/use/use-keyword.stderr
index 62b6a77fbfb..501d14be521 100644
--- a/src/test/ui/use/use-keyword.stderr
+++ b/src/test/ui/use/use-keyword.stderr
@@ -2,7 +2,7 @@ error[E0429]: `self` imports are only allowed within a { } list
   --> $DIR/use-keyword.rs:6:13
    |
 LL |         use self as A;
-   |             ^^^^^^^^^
+   |             ^^^^
 
 error[E0432]: unresolved import `super`
   --> $DIR/use-keyword.rs:8:13
diff --git a/src/test/ui/use/use-mod/use-mod-4.stderr b/src/test/ui/use/use-mod/use-mod-4.stderr
index e30e5c3ceb1..a29bd07ac44 100644
--- a/src/test/ui/use/use-mod/use-mod-4.stderr
+++ b/src/test/ui/use/use-mod/use-mod-4.stderr
@@ -1,20 +1,38 @@
 error[E0429]: `self` imports are only allowed within a { } list
-  --> $DIR/use-mod-4.rs:1:5
+  --> $DIR/use-mod-4.rs:1:8
    |
 LL | use foo::self;
-   |     ^^^^^^^^^
+   |        ^^^^^^
+   |
+help: consider importing the module directly
+   |
+LL | use foo;
+   |       --
+help: alternatively, use the multi-path `use` syntax to import `self`
+   |
+LL | use foo::{self};
+   |          ^    ^
 
 error[E0429]: `self` imports are only allowed within a { } list
-  --> $DIR/use-mod-4.rs:4:5
+  --> $DIR/use-mod-4.rs:4:13
    |
 LL | use std::mem::self;
-   |     ^^^^^^^^^^^^^^
+   |             ^^^^^^
+   |
+help: consider importing the module directly
+   |
+LL | use std::mem;
+   |            --
+help: alternatively, use the multi-path `use` syntax to import `self`
+   |
+LL | use std::mem::{self};
+   |               ^    ^
 
 error[E0432]: unresolved import `foo`
   --> $DIR/use-mod-4.rs:1:5
    |
 LL | use foo::self;
-   |     ^^^ maybe a missing crate `foo`?
+   |     ^^^^^^^^^ no `foo` in the root
 
 error: aborting due to 3 previous errors
 
diff --git a/src/test/ui/use/use-mod/use-mod-5.rs b/src/test/ui/use/use-mod/use-mod-5.rs
new file mode 100644
index 00000000000..df5b423ec57
--- /dev/null
+++ b/src/test/ui/use/use-mod/use-mod-5.rs
@@ -0,0 +1,13 @@
+mod foo {
+    pub mod bar {
+        pub fn drop() {}
+    }
+}
+
+use foo::bar::self;
+//~^ ERROR `self` imports are only allowed within a { } list
+
+fn main() {
+    // Because of error recovery this shouldn't error
+    bar::drop();
+}
diff --git a/src/test/ui/use/use-mod/use-mod-5.stderr b/src/test/ui/use/use-mod/use-mod-5.stderr
new file mode 100644
index 00000000000..ebb71c51293
--- /dev/null
+++ b/src/test/ui/use/use-mod/use-mod-5.stderr
@@ -0,0 +1,18 @@
+error[E0429]: `self` imports are only allowed within a { } list
+  --> $DIR/use-mod-5.rs:7:13
+   |
+LL | use foo::bar::self;
+   |             ^^^^^^
+   |
+help: consider importing the module directly
+   |
+LL | use foo::bar;
+   |            --
+help: alternatively, use the multi-path `use` syntax to import `self`
+   |
+LL | use foo::bar::{self};
+   |               ^    ^
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0429`.
diff --git a/src/test/ui/use/use-mod/use-mod-6.rs b/src/test/ui/use/use-mod/use-mod-6.rs
new file mode 100644
index 00000000000..1f8777daca4
--- /dev/null
+++ b/src/test/ui/use/use-mod/use-mod-6.rs
@@ -0,0 +1,13 @@
+mod foo {
+    pub mod bar {
+        pub fn drop() {}
+    }
+}
+
+use foo::bar::self as abc;
+//~^ ERROR `self` imports are only allowed within a { } list
+
+fn main() {
+    // Because of error recovery this shouldn't error
+    abc::drop();
+}
diff --git a/src/test/ui/use/use-mod/use-mod-6.stderr b/src/test/ui/use/use-mod/use-mod-6.stderr
new file mode 100644
index 00000000000..36fdf9c75c7
--- /dev/null
+++ b/src/test/ui/use/use-mod/use-mod-6.stderr
@@ -0,0 +1,18 @@
+error[E0429]: `self` imports are only allowed within a { } list
+  --> $DIR/use-mod-6.rs:7:13
+   |
+LL | use foo::bar::self as abc;
+   |             ^^^^^^
+   |
+help: consider importing the module directly
+   |
+LL | use foo::bar as abc;
+   |            --
+help: alternatively, use the multi-path `use` syntax to import `self`
+   |
+LL | use foo::bar::{self as abc};
+   |               ^           ^
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0429`.