about summary refs log tree commit diff
diff options
context:
space:
mode:
authorFabian Wolff <fabian.wolff@alumni.ethz.ch>2021-09-18 00:07:41 +0200
committerFabian Wolff <fabian.wolff@alumni.ethz.ch>2021-09-26 19:22:20 +0200
commit750018e16eb34f8b37477689fbd231bb720c8aaa (patch)
tree137531f83861633fc1f59b7e2b48c72971d56fa0
parent65eb381dec051e31d1fb17a5a7629bdee1eb9922 (diff)
downloadrust-750018e16eb34f8b37477689fbd231bb720c8aaa.tar.gz
rust-750018e16eb34f8b37477689fbd231bb720c8aaa.zip
Improve diagnostics for inaccessible items
-rw-r--r--compiler/rustc_resolve/src/diagnostics.rs81
-rw-r--r--compiler/rustc_resolve/src/lib.rs10
-rw-r--r--src/test/ui/imports/glob-resolve1.stderr42
-rw-r--r--src/test/ui/imports/issue-4366-2.stderr7
-rw-r--r--src/test/ui/resolve/issue-42944.stderr7
-rw-r--r--src/test/ui/resolve/issue-88472.rs7
-rw-r--r--src/test/ui/resolve/issue-88472.stderr24
-rw-r--r--src/test/ui/resolve/privacy-enum-ctor.stderr28
-rw-r--r--src/test/ui/resolve/privacy-struct-ctor.stderr7
-rw-r--r--src/test/ui/self/self_type_keyword.stderr7
10 files changed, 164 insertions, 56 deletions
diff --git a/compiler/rustc_resolve/src/diagnostics.rs b/compiler/rustc_resolve/src/diagnostics.rs
index e75db6f3f00..4b36196d466 100644
--- a/compiler/rustc_resolve/src/diagnostics.rs
+++ b/compiler/rustc_resolve/src/diagnostics.rs
@@ -949,7 +949,15 @@ impl<'a> Resolver<'a> {
 
         let import_suggestions =
             self.lookup_import_candidates(ident, Namespace::MacroNS, parent_scope, is_expected);
-        show_candidates(err, None, &import_suggestions, false, true);
+        show_candidates(
+            &self.definitions,
+            self.session,
+            err,
+            None,
+            &import_suggestions,
+            false,
+            true,
+        );
 
         if macro_kind == MacroKind::Derive && (ident.name == sym::Send || ident.name == sym::Sync) {
             let msg = format!("unsafe traits like `{}` should be implemented explicitly", ident);
@@ -1689,6 +1697,8 @@ fn find_span_immediately_after_crate_name(
 /// entities with that name in all crates. This method allows outputting the
 /// results of this search in a programmer-friendly way
 crate fn show_candidates(
+    definitions: &rustc_hir::definitions::Definitions,
+    session: &Session,
     err: &mut DiagnosticBuilder<'_>,
     // This is `None` if all placement locations are inside expansions
     use_placement_span: Option<Span>,
@@ -1700,22 +1710,22 @@ 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();
+    let mut accessible_path_strings: Vec<(String, &str, Option<DefId>)> = Vec::new();
+    let mut inaccessible_path_strings: Vec<(String, &str, Option<DefId>)> = 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))
+            .push((path_names_to_string(&c.path), c.descr, c.did))
     });
 
     // we want consistent results across executions, but candidates are produced
     // by iterating through a hash map, so make sure they are ordered:
     for path_strings in [&mut accessible_path_strings, &mut inaccessible_path_strings] {
-        path_strings.sort();
+        path_strings.sort_by(|a, b| a.0.cmp(&b.0));
         let core_path_strings =
-            path_strings.drain_filter(|p| p.starts_with("core::")).collect::<Vec<String>>();
+            path_strings.drain_filter(|p| p.0.starts_with("core::")).collect::<Vec<_>>();
         path_strings.extend(core_path_strings);
-        path_strings.dedup();
+        path_strings.dedup_by(|a, b| a.0 == b.0);
     }
 
     if !accessible_path_strings.is_empty() {
@@ -1755,19 +1765,56 @@ crate fn show_candidates(
     } else {
         assert!(!inaccessible_path_strings.is_empty());
 
-        let (determiner, kind, verb1, verb2) = if inaccessible_path_strings.len() == 1 {
-            ("this", inaccessible_path_strings[0].1, "exists", "is")
+        if inaccessible_path_strings.len() == 1 {
+            let (name, descr, def_id) = &inaccessible_path_strings[0];
+            let msg = format!("{} `{}` exists but is inaccessible", descr, name);
+
+            if let Some(local_def_id) = def_id.and_then(|did| did.as_local()) {
+                let span = definitions.def_span(local_def_id);
+                let span = session.source_map().guess_head_span(span);
+                let mut multi_span = MultiSpan::from_span(span);
+                multi_span.push_span_label(span, "not accessible".to_string());
+                err.span_note(multi_span, &msg);
+            } else {
+                err.note(&msg);
+            }
         } else {
-            ("these", "items", "exist", "are")
-        };
+            let (_, descr_first, _) = &inaccessible_path_strings[0];
+            let descr = if inaccessible_path_strings
+                .iter()
+                .skip(1)
+                .all(|(_, descr, _)| descr == descr_first)
+            {
+                format!("{}", descr_first)
+            } else {
+                "item".to_string()
+            };
 
-        let mut msg = format!("{} {} {} but {} inaccessible:", determiner, kind, verb1, verb2);
+            let mut msg = format!("these {}s exist but are inaccessible", descr);
+            let mut has_colon = false;
 
-        for candidate in inaccessible_path_strings {
-            msg.push('\n');
-            msg.push_str(&candidate.0);
-        }
+            let mut spans = Vec::new();
+            for (name, _, def_id) in &inaccessible_path_strings {
+                if let Some(local_def_id) = def_id.and_then(|did| did.as_local()) {
+                    let span = definitions.def_span(local_def_id);
+                    let span = session.source_map().guess_head_span(span);
+                    spans.push((name, span));
+                } else {
+                    if !has_colon {
+                        msg.push(':');
+                        has_colon = true;
+                    }
+                    msg.push('\n');
+                    msg.push_str(name);
+                }
+            }
+
+            let mut multi_span = MultiSpan::from_spans(spans.iter().map(|(_, sp)| *sp).collect());
+            for (name, span) in spans {
+                multi_span.push_span_label(span, format!("`{}`: not accessible", name));
+            }
 
-        err.note(&msg);
+            err.span_note(multi_span, &msg);
+        }
     }
 }
diff --git a/compiler/rustc_resolve/src/lib.rs b/compiler/rustc_resolve/src/lib.rs
index 1cbe8f41d92..5ca2392a60a 100644
--- a/compiler/rustc_resolve/src/lib.rs
+++ b/compiler/rustc_resolve/src/lib.rs
@@ -2966,7 +2966,15 @@ impl<'a> Resolver<'a> {
                 (None, false)
             };
             if !candidates.is_empty() {
-                diagnostics::show_candidates(&mut err, span, &candidates, instead, found_use);
+                diagnostics::show_candidates(
+                    &self.definitions,
+                    self.session,
+                    &mut err,
+                    span,
+                    &candidates,
+                    instead,
+                    found_use,
+                );
             } else if let Some((span, msg, sugg, appl)) = suggestion {
                 err.span_suggestion(span, msg, sugg, appl);
             }
diff --git a/src/test/ui/imports/glob-resolve1.stderr b/src/test/ui/imports/glob-resolve1.stderr
index 3e23c278d66..3b66a5e3150 100644
--- a/src/test/ui/imports/glob-resolve1.stderr
+++ b/src/test/ui/imports/glob-resolve1.stderr
@@ -4,8 +4,11 @@ error[E0425]: cannot find function `fpriv` in this scope
 LL |     fpriv();
    |     ^^^^^ not found in this scope
    |
-   = note: this function exists but is inaccessible:
-           bar::fpriv
+note: function `bar::fpriv` exists but is inaccessible
+  --> $DIR/glob-resolve1.rs:7:5
+   |
+LL |     fn fpriv() {}
+   |     ^^^^^^^^^^ not accessible
 
 error[E0425]: cannot find function `epriv` in this scope
   --> $DIR/glob-resolve1.rs:27:5
@@ -13,8 +16,11 @@ error[E0425]: cannot find function `epriv` in this scope
 LL |     epriv();
    |     ^^^^^ not found in this scope
    |
-   = note: this function exists but is inaccessible:
-           bar::epriv
+note: function `bar::epriv` exists but is inaccessible
+  --> $DIR/glob-resolve1.rs:9:9
+   |
+LL |         fn epriv();
+   |         ^^^^^^^^^^^ not accessible
 
 error[E0423]: expected value, found enum `B`
   --> $DIR/glob-resolve1.rs:28:5
@@ -40,8 +46,11 @@ error[E0425]: cannot find value `C` in this scope
 LL |     C;
    |     ^ not found in this scope
    |
-   = note: this unit struct exists but is inaccessible:
-           bar::C
+note: unit struct `bar::C` exists but is inaccessible
+  --> $DIR/glob-resolve1.rs:18:5
+   |
+LL |     struct C;
+   |     ^^^^^^^^^ not accessible
 
 error[E0425]: cannot find function `import` in this scope
   --> $DIR/glob-resolve1.rs:30:5
@@ -63,8 +72,11 @@ LL |     pub enum B {
 LL |     foo::<A>();
    |           ^ help: an enum with a similar name exists: `B`
    |
-   = note: this enum exists but is inaccessible:
-           bar::A
+note: enum `bar::A` exists but is inaccessible
+  --> $DIR/glob-resolve1.rs:11:5
+   |
+LL |     enum A {
+   |     ^^^^^^ not accessible
 
 error[E0412]: cannot find type `C` in this scope
   --> $DIR/glob-resolve1.rs:33:11
@@ -75,8 +87,11 @@ LL |     pub enum B {
 LL |     foo::<C>();
    |           ^ help: an enum with a similar name exists: `B`
    |
-   = note: this struct exists but is inaccessible:
-           bar::C
+note: struct `bar::C` exists but is inaccessible
+  --> $DIR/glob-resolve1.rs:18:5
+   |
+LL |     struct C;
+   |     ^^^^^^^^^ not accessible
 
 error[E0412]: cannot find type `D` in this scope
   --> $DIR/glob-resolve1.rs:34:11
@@ -87,8 +102,11 @@ LL |     pub enum B {
 LL |     foo::<D>();
    |           ^ help: an enum with a similar name exists: `B`
    |
-   = note: this type alias exists but is inaccessible:
-           bar::D
+note: type alias `bar::D` exists but is inaccessible
+  --> $DIR/glob-resolve1.rs:20:5
+   |
+LL |     type D = isize;
+   |     ^^^^^^^^^^^^^^^ not accessible
 
 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 225104d0dde..4c94634ee60 100644
--- a/src/test/ui/imports/issue-4366-2.stderr
+++ b/src/test/ui/imports/issue-4366-2.stderr
@@ -4,8 +4,11 @@ error[E0412]: cannot find type `Bar` in this scope
 LL |         fn sub() -> Bar { 1 }
    |                     ^^^ not found in this scope
    |
-   = note: this type alias exists but is inaccessible:
-           a::b::Bar
+note: type alias `a::b::Bar` exists but is inaccessible
+  --> $DIR/issue-4366-2.rs:11:9
+   |
+LL |         type Bar = isize;
+   |         ^^^^^^^^^^^^^^^^^ not accessible
 
 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 1ca7a6d34f7..cad3ccc4a0e 100644
--- a/src/test/ui/resolve/issue-42944.stderr
+++ b/src/test/ui/resolve/issue-42944.stderr
@@ -16,8 +16,11 @@ error[E0425]: cannot find function, tuple struct or tuple variant `Bx` in this s
 LL |         Bx(());
    |         ^^ not found in this scope
    |
-   = note: this tuple struct exists but is inaccessible:
-           foo::Bx
+note: tuple struct `foo::Bx` exists but is inaccessible
+  --> $DIR/issue-42944.rs:2:5
+   |
+LL |     pub struct Bx(());
+   |     ^^^^^^^^^^^^^^^^^^ not accessible
 
 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
index 53cfec57466..6bf7caeddbf 100644
--- a/src/test/ui/resolve/issue-88472.rs
+++ b/src/test/ui/resolve/issue-88472.rs
@@ -6,6 +6,8 @@
 
 mod a {
     struct Foo;
+    //~^ NOTE: struct `a::Foo` exists but is inaccessible
+    //~| NOTE: not accessible
 }
 
 mod b {
@@ -14,14 +16,16 @@ mod b {
     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 {}
+    //~^ NOTE: these enums exist but are inaccessible
+    //~| NOTE: `c::Eee`: not accessible
 
     mod d {
         enum Eee {}
+        //~^ NOTE: `c::d::Eee`: not accessible
     }
 }
 
@@ -29,7 +33,6 @@ 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
index 6846210b302..8431fc97766 100644
--- a/src/test/ui/resolve/issue-88472.stderr
+++ b/src/test/ui/resolve/issue-88472.stderr
@@ -1,24 +1,32 @@
 error[E0412]: cannot find type `Foo` in this scope
-  --> $DIR/issue-88472.rs:14:16
+  --> $DIR/issue-88472.rs:16:16
    |
 LL |     type Bar = Foo;
    |                ^^^ not found in this scope
    |
-   = note: this struct exists but is inaccessible:
-           a::Foo
+note: struct `a::Foo` exists but is inaccessible
+  --> $DIR/issue-88472.rs:8:5
+   |
+LL |     struct Foo;
+   |     ^^^^^^^^^^^ not accessible
 
 error[E0412]: cannot find type `Eee` in this scope
-  --> $DIR/issue-88472.rs:29:16
+  --> $DIR/issue-88472.rs:33:16
    |
 LL |     type Baz = Eee;
    |                ^^^ not found in this scope
    |
-   = note: these items exist but are inaccessible:
-           c::Eee
-           c::d::Eee
+note: these enums exist but are inaccessible
+  --> $DIR/issue-88472.rs:22:5
+   |
+LL |     enum Eee {}
+   |     ^^^^^^^^ `c::Eee`: not accessible
+...
+LL |         enum Eee {}
+   |         ^^^^^^^^ `c::d::Eee`: not accessible
 
 warning: unused import: `crate::a::*`
-  --> $DIR/issue-88472.rs:12:9
+  --> $DIR/issue-88472.rs:14:9
    |
 LL |     use crate::a::*;
    |         ^^^^^^^^^^^
diff --git a/src/test/ui/resolve/privacy-enum-ctor.stderr b/src/test/ui/resolve/privacy-enum-ctor.stderr
index e79f953970a..ff72b0b563a 100644
--- a/src/test/ui/resolve/privacy-enum-ctor.stderr
+++ b/src/test/ui/resolve/privacy-enum-ctor.stderr
@@ -171,8 +171,11 @@ LL |     pub enum E {
 LL |     let _: Z = m::n::Z;
    |            ^ help: an enum with a similar name exists: `E`
    |
-   = note: this enum exists but is inaccessible:
-           m::Z
+note: enum `m::Z` exists but is inaccessible
+  --> $DIR/privacy-enum-ctor.rs:11:9
+   |
+LL |         pub(in m) enum Z {
+   |         ^^^^^^^^^^^^^^^^ not accessible
 
 error[E0423]: expected value, found enum `m::n::Z`
   --> $DIR/privacy-enum-ctor.rs:57:16
@@ -211,8 +214,11 @@ LL |     pub enum E {
 LL |     let _: Z = m::n::Z::Fn;
    |            ^ help: an enum with a similar name exists: `E`
    |
-   = note: this enum exists but is inaccessible:
-           m::Z
+note: enum `m::Z` exists but is inaccessible
+  --> $DIR/privacy-enum-ctor.rs:11:9
+   |
+LL |         pub(in m) enum Z {
+   |         ^^^^^^^^^^^^^^^^ not accessible
 
 error[E0412]: cannot find type `Z` in this scope
   --> $DIR/privacy-enum-ctor.rs:64:12
@@ -223,8 +229,11 @@ LL |     pub enum E {
 LL |     let _: Z = m::n::Z::Struct;
    |            ^ help: an enum with a similar name exists: `E`
    |
-   = note: this enum exists but is inaccessible:
-           m::Z
+note: enum `m::Z` exists but is inaccessible
+  --> $DIR/privacy-enum-ctor.rs:11:9
+   |
+LL |         pub(in m) enum Z {
+   |         ^^^^^^^^^^^^^^^^ not accessible
 
 error[E0423]: expected value, found struct variant `m::n::Z::Struct`
   --> $DIR/privacy-enum-ctor.rs:64:16
@@ -246,8 +255,11 @@ LL |     pub enum E {
 LL |     let _: Z = m::n::Z::Unit {};
    |            ^ help: an enum with a similar name exists: `E`
    |
-   = note: this enum exists but is inaccessible:
-           m::Z
+note: enum `m::Z` exists but is inaccessible
+  --> $DIR/privacy-enum-ctor.rs:11:9
+   |
+LL |         pub(in m) enum Z {
+   |         ^^^^^^^^^^^^^^^^ not accessible
 
 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 bf1d6753cc1..ada053014ef 100644
--- a/src/test/ui/resolve/privacy-struct-ctor.stderr
+++ b/src/test/ui/resolve/privacy-struct-ctor.stderr
@@ -33,8 +33,11 @@ error[E0423]: expected value, found struct `xcrate::S`
 LL |     xcrate::S;
    |     ^^^^^^^^^ constructor is not visible here due to private fields
    |
-   = note: this tuple struct exists but is inaccessible:
-           m::S
+note: tuple struct `m::S` exists but is inaccessible
+  --> $DIR/privacy-struct-ctor.rs:6:5
+   |
+LL |     pub struct S(u8);
+   |     ^^^^^^^^^^^^^^^^^ not accessible
 
 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 57b46058777..aca08d81163 100644
--- a/src/test/ui/self/self_type_keyword.stderr
+++ b/src/test/ui/self/self_type_keyword.stderr
@@ -66,8 +66,11 @@ error[E0531]: cannot find unit struct, unit variant or constant `Self` in this s
 LL |         mut Self => (),
    |             ^^^^ not found in this scope
    |
-   = note: this unit struct exists but is inaccessible:
-           foo::Self
+note: unit struct `foo::Self` exists but is inaccessible
+  --> $DIR/self_type_keyword.rs:2:3
+   |
+LL |   struct Self;
+   |   ^^^^^^^^^^^^ not accessible
 
 error[E0392]: parameter `'Self` is never used
   --> $DIR/self_type_keyword.rs:6:12