about summary refs log tree commit diff
path: root/src
diff options
context:
space:
mode:
authorMatthias Krüger <matthias.krueger@famsik.de>2021-12-21 08:33:37 +0100
committerGitHub <noreply@github.com>2021-12-21 08:33:37 +0100
commitaf09d24ff66b336c8bc76b66dce19c5a4507e881 (patch)
tree40af40ee134cd4043c4926dad16f7aadfaf79939 /src
parent3009dd7c5a6da3c36c61ce89d5320ed8c0922a22 (diff)
parent682a3428a3183812789f76ca4400c83366699cbd (diff)
Rollup merge of #91412 - compiler-errors:issue-86035, r=oli-obk
Improve suggestions for importing out-of-scope traits reexported as `_`

1. Fix up the `parent_map` query to prefer visible parents that _don't_ export items with the name `_`.
    * I'm not sure if I modified this query properly. Not sure if we want to check for other idents than `kw::Underscore`.
    * This also has the side-effect of not doing BFS on any modules re-exported as `_`, but I think that's desirable here too (or else we get suggestions for paths like `a::_::b` like in [this doctest example](https://play.rust-lang.org/?version=stable&mode=debug&edition=2021&gist=d9505ea45bb80adf40bb991298f952be)).
2. Bail in `try_print_visible_def_path` if the `def_id` is re-exported as `_`, which will fall back to printing the def-id's real (definition) path.
    * Side-effect of this is that we print paths that are not actually public, but it seems we already sometimes suggest `use`ing paths that are private anyways. See [this doctest example](https://play.rust-lang.org/?version=stable&mode=debug&edition=2021&gist=bad513ed3241f8ff87579eed8046ad10) for demonstration of current behavior.
3. Suggest a glob-import (for example `my_library::prelude::*`) if the trait in question is only pub-exported as `_`, as a fallback.
    ```
    use foo::bar::prelude::*; // trait MyTrait
    ```
    * I think this is good fallback behavior to suggest instead of doing nothing. Thanks to the original issue filer for suggesting this.

I was somewhat opinionated about behaviors in this PR, and I'm totally open to limiting the impact of my changes or only landing parts of this. Happy to receive feedback if there are better ways to the same end.

Fixes #86035
Diffstat (limited to 'src')
-rw-r--r--src/test/ui/imports/auxiliary/overlapping_pub_trait_source.rs13
-rw-r--r--src/test/ui/imports/auxiliary/unnamed_pub_trait_source.rs13
-rw-r--r--src/test/ui/imports/overlapping_pub_trait.rs15
-rw-r--r--src/test/ui/imports/overlapping_pub_trait.stderr20
-rw-r--r--src/test/ui/imports/unnamed_pub_trait.rs16
-rw-r--r--src/test/ui/imports/unnamed_pub_trait.stderr20
6 files changed, 97 insertions, 0 deletions
diff --git a/src/test/ui/imports/auxiliary/overlapping_pub_trait_source.rs b/src/test/ui/imports/auxiliary/overlapping_pub_trait_source.rs
new file mode 100644
index 00000000000..2a25d60acff
--- /dev/null
+++ b/src/test/ui/imports/auxiliary/overlapping_pub_trait_source.rs
@@ -0,0 +1,13 @@
+/* This crate declares an item as both `prelude::*` and `m::Tr`.
+ * The compiler should always suggest `m::Tr`. */
+
+pub struct S;
+
+pub mod prelude {
+    pub use crate::m::Tr as _;
+}
+
+pub mod m {
+    pub trait Tr { fn method(&self); }
+    impl Tr for crate::S { fn method(&self) {} }
+}
diff --git a/src/test/ui/imports/auxiliary/unnamed_pub_trait_source.rs b/src/test/ui/imports/auxiliary/unnamed_pub_trait_source.rs
new file mode 100644
index 00000000000..d73c9a795b6
--- /dev/null
+++ b/src/test/ui/imports/auxiliary/unnamed_pub_trait_source.rs
@@ -0,0 +1,13 @@
+/* This crate declares an item that is unnamed.
+ * Its only public path is through `prelude::*`. */
+
+pub struct S;
+
+mod m {
+    pub trait Tr { fn method(&self); }
+    impl Tr for crate::S { fn method(&self) {} }
+}
+
+pub mod prelude {
+    pub use crate::m::Tr as _;
+}
diff --git a/src/test/ui/imports/overlapping_pub_trait.rs b/src/test/ui/imports/overlapping_pub_trait.rs
new file mode 100644
index 00000000000..f5f5d4ed380
--- /dev/null
+++ b/src/test/ui/imports/overlapping_pub_trait.rs
@@ -0,0 +1,15 @@
+// aux-build:overlapping_pub_trait_source.rs
+
+/*
+ * This crate declares two public paths, `m::Tr` and `prelude::_`. Make sure we prefer the former.
+ */
+extern crate overlapping_pub_trait_source;
+
+fn main() {
+    //~^ HELP the following trait is implemented but not in scope; perhaps add a `use` for it:
+    //~| SUGGESTION overlapping_pub_trait_source::m::Tr
+    use overlapping_pub_trait_source::S;
+    S.method();
+    //~^ ERROR no method named `method` found for struct `S` in the current scope [E0599]
+    //~| HELP items from traits can only be used if the trait is in scope
+}
diff --git a/src/test/ui/imports/overlapping_pub_trait.stderr b/src/test/ui/imports/overlapping_pub_trait.stderr
new file mode 100644
index 00000000000..d0c845a5e52
--- /dev/null
+++ b/src/test/ui/imports/overlapping_pub_trait.stderr
@@ -0,0 +1,20 @@
+error[E0599]: no method named `method` found for struct `S` in the current scope
+  --> $DIR/overlapping_pub_trait.rs:12:7
+   |
+LL |     S.method();
+   |       ^^^^^^ method not found in `S`
+   |
+  ::: $DIR/auxiliary/overlapping_pub_trait_source.rs:11:23
+   |
+LL |     pub trait Tr { fn method(&self); }
+   |                       ------ the method is available for `S` here
+   |
+   = help: items from traits can only be used if the trait is in scope
+help: the following trait is implemented but not in scope; perhaps add a `use` for it:
+   |
+LL | use overlapping_pub_trait_source::m::Tr;
+   |
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0599`.
diff --git a/src/test/ui/imports/unnamed_pub_trait.rs b/src/test/ui/imports/unnamed_pub_trait.rs
new file mode 100644
index 00000000000..b06b1e1d07d
--- /dev/null
+++ b/src/test/ui/imports/unnamed_pub_trait.rs
@@ -0,0 +1,16 @@
+// aux-build:unnamed_pub_trait_source.rs
+
+/*
+ * This crate declares an unnameable public path for our item. Make sure we don't suggest
+ * importing it by name, and instead we suggest importing it by glob.
+ */
+extern crate unnamed_pub_trait_source;
+
+fn main() {
+    //~^ HELP the following trait is implemented but not in scope; perhaps add a `use` for it:
+    //~| SUGGESTION unnamed_pub_trait_source::prelude::*; // trait Tr
+    use unnamed_pub_trait_source::S;
+    S.method();
+    //~^ ERROR no method named `method` found for struct `S` in the current scope [E0599]
+    //~| HELP items from traits can only be used if the trait is in scope
+}
diff --git a/src/test/ui/imports/unnamed_pub_trait.stderr b/src/test/ui/imports/unnamed_pub_trait.stderr
new file mode 100644
index 00000000000..319dfd7e1b2
--- /dev/null
+++ b/src/test/ui/imports/unnamed_pub_trait.stderr
@@ -0,0 +1,20 @@
+error[E0599]: no method named `method` found for struct `S` in the current scope
+  --> $DIR/unnamed_pub_trait.rs:13:7
+   |
+LL |     S.method();
+   |       ^^^^^^ method not found in `S`
+   |
+  ::: $DIR/auxiliary/unnamed_pub_trait_source.rs:7:23
+   |
+LL |     pub trait Tr { fn method(&self); }
+   |                       ------ the method is available for `S` here
+   |
+   = help: items from traits can only be used if the trait is in scope
+help: the following trait is implemented but not in scope; perhaps add a `use` for it:
+   |
+LL | use unnamed_pub_trait_source::prelude::*; // trait Tr
+   |
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0599`.