From 65eb381dec051e31d1fb17a5a7629bdee1eb9922 Mon Sep 17 00:00:00 2001 From: Fabian Wolff Date: Sat, 11 Sep 2021 01:15:40 +0200 Subject: [PATCH] Do not suggest importing inaccessible items --- compiler/rustc_resolve/src/diagnostics.rs | 81 +++++++++++++------ src/test/ui/hygiene/globs.stderr | 6 +- src/test/ui/imports/glob-resolve1.stderr | 54 ++++--------- src/test/ui/imports/issue-4366-2.stderr | 6 +- src/test/ui/resolve/issue-42944.stderr | 6 +- src/test/ui/resolve/issue-88472.rs | 35 ++++++++ src/test/ui/resolve/issue-88472.stderr | 34 ++++++++ src/test/ui/resolve/privacy-enum-ctor.stderr | 48 +++-------- .../ui/resolve/privacy-struct-ctor.stderr | 6 +- src/test/ui/self/self_type_keyword.stderr | 6 +- 10 files changed, 163 insertions(+), 119 deletions(-) create mode 100644 src/test/ui/resolve/issue-88472.rs create mode 100644 src/test/ui/resolve/issue-88472.stderr diff --git a/compiler/rustc_resolve/src/diagnostics.rs b/compiler/rustc_resolve/src/diagnostics.rs index d6ff5a7e90b2..e75db6f3f002 100644 --- a/compiler/rustc_resolve/src/diagnostics.rs +++ b/compiler/rustc_resolve/src/diagnostics.rs @@ -1700,41 +1700,72 @@ crate fn show_candidates( return; } + let mut accessible_path_strings: Vec<(String, &str)> = Vec::new(); + let mut inaccessible_path_strings: Vec<(String, &str)> = Vec::new(); + + candidates.iter().for_each(|c| { + (if c.accessible { &mut accessible_path_strings } else { &mut inaccessible_path_strings }) + .push((path_names_to_string(&c.path), c.descr)) + }); + // we want consistent results across executions, but candidates are produced // by iterating through a hash map, so make sure they are ordered: - let mut path_strings: Vec<_> = - candidates.iter().map(|c| path_names_to_string(&c.path)).collect(); + for path_strings in [&mut accessible_path_strings, &mut inaccessible_path_strings] { + path_strings.sort(); + let core_path_strings = + path_strings.drain_filter(|p| p.starts_with("core::")).collect::>(); + path_strings.extend(core_path_strings); + path_strings.dedup(); + } - path_strings.sort(); - let core_path_strings = - path_strings.drain_filter(|p| p.starts_with("core::")).collect::>(); - path_strings.extend(core_path_strings); - path_strings.dedup(); + if !accessible_path_strings.is_empty() { + let (determiner, kind) = if accessible_path_strings.len() == 1 { + ("this", accessible_path_strings[0].1) + } else { + ("one of these", "items") + }; - let (determiner, kind) = if candidates.len() == 1 { - ("this", candidates[0].descr) - } else { - ("one of these", "items") - }; + let instead = if instead { " instead" } else { "" }; + let mut msg = format!("consider importing {} {}{}", determiner, kind, instead); - let instead = if instead { " instead" } else { "" }; - let mut msg = format!("consider importing {} {}{}", determiner, kind, instead); + if let Some(span) = use_placement_span { + for candidate in &mut accessible_path_strings { + // produce an additional newline to separate the new use statement + // from the directly following item. + let additional_newline = if found_use { "" } else { "\n" }; + candidate.0 = format!("use {};\n{}", &candidate.0, additional_newline); + } - if let Some(span) = use_placement_span { - for candidate in &mut path_strings { - // produce an additional newline to separate the new use statement - // from the directly following item. - let additional_newline = if found_use { "" } else { "\n" }; - *candidate = format!("use {};\n{}", candidate, additional_newline); + err.span_suggestions( + span, + &msg, + accessible_path_strings.into_iter().map(|a| a.0), + Applicability::Unspecified, + ); + } else { + msg.push(':'); + + for candidate in accessible_path_strings { + msg.push('\n'); + msg.push_str(&candidate.0); + } + + err.note(&msg); } - - err.span_suggestions(span, &msg, path_strings.into_iter(), Applicability::Unspecified); } else { - msg.push(':'); + assert!(!inaccessible_path_strings.is_empty()); - for candidate in path_strings { + let (determiner, kind, verb1, verb2) = if inaccessible_path_strings.len() == 1 { + ("this", inaccessible_path_strings[0].1, "exists", "is") + } else { + ("these", "items", "exist", "are") + }; + + let mut msg = format!("{} {} {} but {} inaccessible:", determiner, kind, verb1, verb2); + + for candidate in inaccessible_path_strings { msg.push('\n'); - msg.push_str(&candidate); + msg.push_str(&candidate.0); } err.note(&msg); diff --git a/src/test/ui/hygiene/globs.stderr b/src/test/ui/hygiene/globs.stderr index c2497f8ff74d..6c8b707b8e2f 100644 --- a/src/test/ui/hygiene/globs.stderr +++ b/src/test/ui/hygiene/globs.stderr @@ -4,7 +4,7 @@ error[E0425]: cannot find function `f` in this scope LL | f(); | ^ not found in this scope | -help: consider importing one of these items +help: consider importing this function | LL | use foo::f; | @@ -37,7 +37,7 @@ LL | n!(f); LL | n!(f); | ^ not found in this scope | - = note: consider importing one of these items: + = note: consider importing this function: foo::f = note: this error originates in the macro `n` (in Nightly builds, run with -Z macro-backtrace for more info) @@ -50,7 +50,7 @@ LL | n!(f); LL | f | ^ not found in this scope | - = note: consider importing one of these items: + = note: consider importing this function: foo::f = note: this error originates in the macro `n` (in Nightly builds, run with -Z macro-backtrace for more info) diff --git a/src/test/ui/imports/glob-resolve1.stderr b/src/test/ui/imports/glob-resolve1.stderr index 2c7a8ad5c1ad..3e23c278d669 100644 --- a/src/test/ui/imports/glob-resolve1.stderr +++ b/src/test/ui/imports/glob-resolve1.stderr @@ -4,10 +4,8 @@ error[E0425]: cannot find function `fpriv` in this scope LL | fpriv(); | ^^^^^ not found in this scope | -help: consider importing this function - | -LL | use bar::fpriv; - | + = note: this function exists but is inaccessible: + bar::fpriv error[E0425]: cannot find function `epriv` in this scope --> $DIR/glob-resolve1.rs:27:5 @@ -15,10 +13,8 @@ error[E0425]: cannot find function `epriv` in this scope LL | epriv(); | ^^^^^ not found in this scope | -help: consider importing this function - | -LL | use bar::epriv; - | + = note: this function exists but is inaccessible: + bar::epriv error[E0423]: expected value, found enum `B` --> $DIR/glob-resolve1.rs:28:5 @@ -44,10 +40,8 @@ error[E0425]: cannot find value `C` in this scope LL | C; | ^ not found in this scope | -help: consider importing this unit struct - | -LL | use bar::C; - | + = note: this unit struct exists but is inaccessible: + bar::C error[E0425]: cannot find function `import` in this scope --> $DIR/glob-resolve1.rs:30:5 @@ -67,16 +61,10 @@ LL | pub enum B { | ---------- similarly named enum `B` defined here ... LL | foo::(); - | ^ - | -help: an enum with a similar name exists - | -LL | foo::(); - | ~ -help: consider importing this enum - | -LL | use bar::A; + | ^ help: an enum with a similar name exists: `B` | + = note: this enum exists but is inaccessible: + bar::A error[E0412]: cannot find type `C` in this scope --> $DIR/glob-resolve1.rs:33:11 @@ -85,16 +73,10 @@ LL | pub enum B { | ---------- similarly named enum `B` defined here ... LL | foo::(); - | ^ - | -help: an enum with a similar name exists - | -LL | foo::(); - | ~ -help: consider importing this struct - | -LL | use bar::C; + | ^ help: an enum with a similar name exists: `B` | + = note: this struct exists but is inaccessible: + bar::C error[E0412]: cannot find type `D` in this scope --> $DIR/glob-resolve1.rs:34:11 @@ -103,16 +85,10 @@ LL | pub enum B { | ---------- similarly named enum `B` defined here ... LL | foo::(); - | ^ - | -help: an enum with a similar name exists - | -LL | foo::(); - | ~ -help: consider importing this type alias - | -LL | use bar::D; + | ^ help: an enum with a similar name exists: `B` | + = note: this type alias exists but is inaccessible: + bar::D error: aborting due to 8 previous errors diff --git a/src/test/ui/imports/issue-4366-2.stderr b/src/test/ui/imports/issue-4366-2.stderr index a86ec7fabea4..225104d0dde2 100644 --- a/src/test/ui/imports/issue-4366-2.stderr +++ b/src/test/ui/imports/issue-4366-2.stderr @@ -4,10 +4,8 @@ error[E0412]: cannot find type `Bar` in this scope LL | fn sub() -> Bar { 1 } | ^^^ not found in this scope | -help: consider importing this type alias - | -LL | use a::b::Bar; - | + = note: this type alias exists but is inaccessible: + a::b::Bar error[E0423]: expected function, found module `foo` --> $DIR/issue-4366-2.rs:25:5 diff --git a/src/test/ui/resolve/issue-42944.stderr b/src/test/ui/resolve/issue-42944.stderr index 008492529d18..1ca7a6d34f78 100644 --- a/src/test/ui/resolve/issue-42944.stderr +++ b/src/test/ui/resolve/issue-42944.stderr @@ -16,10 +16,8 @@ error[E0425]: cannot find function, tuple struct or tuple variant `Bx` in this s LL | Bx(()); | ^^ not found in this scope | -help: consider importing this tuple struct - | -LL | use foo::Bx; - | + = note: this tuple struct exists but is inaccessible: + foo::Bx error: aborting due to 2 previous errors diff --git a/src/test/ui/resolve/issue-88472.rs b/src/test/ui/resolve/issue-88472.rs new file mode 100644 index 000000000000..53cfec574666 --- /dev/null +++ b/src/test/ui/resolve/issue-88472.rs @@ -0,0 +1,35 @@ +// Regression test for #88472, where a suggestion was issued to +// import an inaccessible struct. + +#![warn(unused_imports)] +//~^ NOTE: the lint level is defined here + +mod a { + struct Foo; +} + +mod b { + use crate::a::*; + //~^ WARNING: unused import + type Bar = Foo; + //~^ ERROR: cannot find type `Foo` in this scope [E0412] + //~| NOTE: not found in this scope + //~| NOTE: this struct exists but is inaccessible +} + +mod c { + enum Eee {} + + mod d { + enum Eee {} + } +} + +mod e { + type Baz = Eee; + //~^ ERROR: cannot find type `Eee` in this scope [E0412] + //~| NOTE: not found in this scope + //~| NOTE: these items exist but are inaccessible +} + +fn main() {} diff --git a/src/test/ui/resolve/issue-88472.stderr b/src/test/ui/resolve/issue-88472.stderr new file mode 100644 index 000000000000..6846210b302b --- /dev/null +++ b/src/test/ui/resolve/issue-88472.stderr @@ -0,0 +1,34 @@ +error[E0412]: cannot find type `Foo` in this scope + --> $DIR/issue-88472.rs:14:16 + | +LL | type Bar = Foo; + | ^^^ not found in this scope + | + = note: this struct exists but is inaccessible: + a::Foo + +error[E0412]: cannot find type `Eee` in this scope + --> $DIR/issue-88472.rs:29:16 + | +LL | type Baz = Eee; + | ^^^ not found in this scope + | + = note: these items exist but are inaccessible: + c::Eee + c::d::Eee + +warning: unused import: `crate::a::*` + --> $DIR/issue-88472.rs:12:9 + | +LL | use crate::a::*; + | ^^^^^^^^^^^ + | +note: the lint level is defined here + --> $DIR/issue-88472.rs:4:9 + | +LL | #![warn(unused_imports)] + | ^^^^^^^^^^^^^^ + +error: aborting due to 2 previous errors; 1 warning emitted + +For more information about this error, try `rustc --explain E0412`. diff --git a/src/test/ui/resolve/privacy-enum-ctor.stderr b/src/test/ui/resolve/privacy-enum-ctor.stderr index 192349e0fafe..e79f953970a4 100644 --- a/src/test/ui/resolve/privacy-enum-ctor.stderr +++ b/src/test/ui/resolve/privacy-enum-ctor.stderr @@ -169,16 +169,10 @@ LL | pub enum E { | ---------- similarly named enum `E` defined here ... LL | let _: Z = m::n::Z; - | ^ - | -help: an enum with a similar name exists - | -LL | let _: E = m::n::Z; - | ~ -help: consider importing this enum - | -LL | use m::Z; + | ^ help: an enum with a similar name exists: `E` | + = note: this enum exists but is inaccessible: + m::Z error[E0423]: expected value, found enum `m::n::Z` --> $DIR/privacy-enum-ctor.rs:57:16 @@ -215,16 +209,10 @@ LL | pub enum E { | ---------- similarly named enum `E` defined here ... LL | let _: Z = m::n::Z::Fn; - | ^ - | -help: an enum with a similar name exists - | -LL | let _: E = m::n::Z::Fn; - | ~ -help: consider importing this enum - | -LL | use m::Z; + | ^ help: an enum with a similar name exists: `E` | + = note: this enum exists but is inaccessible: + m::Z error[E0412]: cannot find type `Z` in this scope --> $DIR/privacy-enum-ctor.rs:64:12 @@ -233,16 +221,10 @@ LL | pub enum E { | ---------- similarly named enum `E` defined here ... LL | let _: Z = m::n::Z::Struct; - | ^ - | -help: an enum with a similar name exists - | -LL | let _: E = m::n::Z::Struct; - | ~ -help: consider importing this enum - | -LL | use m::Z; + | ^ help: an enum with a similar name exists: `E` | + = note: this enum exists but is inaccessible: + m::Z error[E0423]: expected value, found struct variant `m::n::Z::Struct` --> $DIR/privacy-enum-ctor.rs:64:16 @@ -262,16 +244,10 @@ LL | pub enum E { | ---------- similarly named enum `E` defined here ... LL | let _: Z = m::n::Z::Unit {}; - | ^ - | -help: an enum with a similar name exists - | -LL | let _: E = m::n::Z::Unit {}; - | ~ -help: consider importing this enum - | -LL | use m::Z; + | ^ help: an enum with a similar name exists: `E` | + = note: this enum exists but is inaccessible: + m::Z error[E0603]: enum `Z` is private --> $DIR/privacy-enum-ctor.rs:57:22 diff --git a/src/test/ui/resolve/privacy-struct-ctor.stderr b/src/test/ui/resolve/privacy-struct-ctor.stderr index e5d6f7e9e24f..bf1d6753cc1d 100644 --- a/src/test/ui/resolve/privacy-struct-ctor.stderr +++ b/src/test/ui/resolve/privacy-struct-ctor.stderr @@ -33,10 +33,8 @@ error[E0423]: expected value, found struct `xcrate::S` LL | xcrate::S; | ^^^^^^^^^ constructor is not visible here due to private fields | -help: consider importing this tuple struct instead - | -LL | use m::S; - | + = note: this tuple struct exists but is inaccessible: + m::S error[E0603]: tuple struct constructor `Z` is private --> $DIR/privacy-struct-ctor.rs:18:12 diff --git a/src/test/ui/self/self_type_keyword.stderr b/src/test/ui/self/self_type_keyword.stderr index 47c04f1eb72e..57b46058777a 100644 --- a/src/test/ui/self/self_type_keyword.stderr +++ b/src/test/ui/self/self_type_keyword.stderr @@ -66,10 +66,8 @@ error[E0531]: cannot find unit struct, unit variant or constant `Self` in this s LL | mut Self => (), | ^^^^ not found in this scope | -help: consider importing this unit struct - | -LL | use foo::Self; - | + = note: this unit struct exists but is inaccessible: + foo::Self error[E0392]: parameter `'Self` is never used --> $DIR/self_type_keyword.rs:6:12