Skip to content

Commit 750018e

Browse files
committed
Improve diagnostics for inaccessible items
1 parent 65eb381 commit 750018e

10 files changed

+164
-56
lines changed

compiler/rustc_resolve/src/diagnostics.rs

+64-17
Original file line numberDiff line numberDiff line change
@@ -949,7 +949,15 @@ impl<'a> Resolver<'a> {
949949

950950
let import_suggestions =
951951
self.lookup_import_candidates(ident, Namespace::MacroNS, parent_scope, is_expected);
952-
show_candidates(err, None, &import_suggestions, false, true);
952+
show_candidates(
953+
&self.definitions,
954+
self.session,
955+
err,
956+
None,
957+
&import_suggestions,
958+
false,
959+
true,
960+
);
953961

954962
if macro_kind == MacroKind::Derive && (ident.name == sym::Send || ident.name == sym::Sync) {
955963
let msg = format!("unsafe traits like `{}` should be implemented explicitly", ident);
@@ -1689,6 +1697,8 @@ fn find_span_immediately_after_crate_name(
16891697
/// entities with that name in all crates. This method allows outputting the
16901698
/// results of this search in a programmer-friendly way
16911699
crate fn show_candidates(
1700+
definitions: &rustc_hir::definitions::Definitions,
1701+
session: &Session,
16921702
err: &mut DiagnosticBuilder<'_>,
16931703
// This is `None` if all placement locations are inside expansions
16941704
use_placement_span: Option<Span>,
@@ -1700,22 +1710,22 @@ crate fn show_candidates(
17001710
return;
17011711
}
17021712

1703-
let mut accessible_path_strings: Vec<(String, &str)> = Vec::new();
1704-
let mut inaccessible_path_strings: Vec<(String, &str)> = Vec::new();
1713+
let mut accessible_path_strings: Vec<(String, &str, Option<DefId>)> = Vec::new();
1714+
let mut inaccessible_path_strings: Vec<(String, &str, Option<DefId>)> = Vec::new();
17051715

17061716
candidates.iter().for_each(|c| {
17071717
(if c.accessible { &mut accessible_path_strings } else { &mut inaccessible_path_strings })
1708-
.push((path_names_to_string(&c.path), c.descr))
1718+
.push((path_names_to_string(&c.path), c.descr, c.did))
17091719
});
17101720

17111721
// we want consistent results across executions, but candidates are produced
17121722
// by iterating through a hash map, so make sure they are ordered:
17131723
for path_strings in [&mut accessible_path_strings, &mut inaccessible_path_strings] {
1714-
path_strings.sort();
1724+
path_strings.sort_by(|a, b| a.0.cmp(&b.0));
17151725
let core_path_strings =
1716-
path_strings.drain_filter(|p| p.starts_with("core::")).collect::<Vec<String>>();
1726+
path_strings.drain_filter(|p| p.0.starts_with("core::")).collect::<Vec<_>>();
17171727
path_strings.extend(core_path_strings);
1718-
path_strings.dedup();
1728+
path_strings.dedup_by(|a, b| a.0 == b.0);
17191729
}
17201730

17211731
if !accessible_path_strings.is_empty() {
@@ -1755,19 +1765,56 @@ crate fn show_candidates(
17551765
} else {
17561766
assert!(!inaccessible_path_strings.is_empty());
17571767

1758-
let (determiner, kind, verb1, verb2) = if inaccessible_path_strings.len() == 1 {
1759-
("this", inaccessible_path_strings[0].1, "exists", "is")
1768+
if inaccessible_path_strings.len() == 1 {
1769+
let (name, descr, def_id) = &inaccessible_path_strings[0];
1770+
let msg = format!("{} `{}` exists but is inaccessible", descr, name);
1771+
1772+
if let Some(local_def_id) = def_id.and_then(|did| did.as_local()) {
1773+
let span = definitions.def_span(local_def_id);
1774+
let span = session.source_map().guess_head_span(span);
1775+
let mut multi_span = MultiSpan::from_span(span);
1776+
multi_span.push_span_label(span, "not accessible".to_string());
1777+
err.span_note(multi_span, &msg);
1778+
} else {
1779+
err.note(&msg);
1780+
}
17601781
} else {
1761-
("these", "items", "exist", "are")
1762-
};
1782+
let (_, descr_first, _) = &inaccessible_path_strings[0];
1783+
let descr = if inaccessible_path_strings
1784+
.iter()
1785+
.skip(1)
1786+
.all(|(_, descr, _)| descr == descr_first)
1787+
{
1788+
format!("{}", descr_first)
1789+
} else {
1790+
"item".to_string()
1791+
};
17631792

1764-
let mut msg = format!("{} {} {} but {} inaccessible:", determiner, kind, verb1, verb2);
1793+
let mut msg = format!("these {}s exist but are inaccessible", descr);
1794+
let mut has_colon = false;
17651795

1766-
for candidate in inaccessible_path_strings {
1767-
msg.push('\n');
1768-
msg.push_str(&candidate.0);
1769-
}
1796+
let mut spans = Vec::new();
1797+
for (name, _, def_id) in &inaccessible_path_strings {
1798+
if let Some(local_def_id) = def_id.and_then(|did| did.as_local()) {
1799+
let span = definitions.def_span(local_def_id);
1800+
let span = session.source_map().guess_head_span(span);
1801+
spans.push((name, span));
1802+
} else {
1803+
if !has_colon {
1804+
msg.push(':');
1805+
has_colon = true;
1806+
}
1807+
msg.push('\n');
1808+
msg.push_str(name);
1809+
}
1810+
}
1811+
1812+
let mut multi_span = MultiSpan::from_spans(spans.iter().map(|(_, sp)| *sp).collect());
1813+
for (name, span) in spans {
1814+
multi_span.push_span_label(span, format!("`{}`: not accessible", name));
1815+
}
17701816

1771-
err.note(&msg);
1817+
err.span_note(multi_span, &msg);
1818+
}
17721819
}
17731820
}

compiler/rustc_resolve/src/lib.rs

+9-1
Original file line numberDiff line numberDiff line change
@@ -2966,7 +2966,15 @@ impl<'a> Resolver<'a> {
29662966
(None, false)
29672967
};
29682968
if !candidates.is_empty() {
2969-
diagnostics::show_candidates(&mut err, span, &candidates, instead, found_use);
2969+
diagnostics::show_candidates(
2970+
&self.definitions,
2971+
self.session,
2972+
&mut err,
2973+
span,
2974+
&candidates,
2975+
instead,
2976+
found_use,
2977+
);
29702978
} else if let Some((span, msg, sugg, appl)) = suggestion {
29712979
err.span_suggestion(span, msg, sugg, appl);
29722980
}

src/test/ui/imports/glob-resolve1.stderr

+30-12
Original file line numberDiff line numberDiff line change
@@ -4,17 +4,23 @@ error[E0425]: cannot find function `fpriv` in this scope
44
LL | fpriv();
55
| ^^^^^ not found in this scope
66
|
7-
= note: this function exists but is inaccessible:
8-
bar::fpriv
7+
note: function `bar::fpriv` exists but is inaccessible
8+
--> $DIR/glob-resolve1.rs:7:5
9+
|
10+
LL | fn fpriv() {}
11+
| ^^^^^^^^^^ not accessible
912

1013
error[E0425]: cannot find function `epriv` in this scope
1114
--> $DIR/glob-resolve1.rs:27:5
1215
|
1316
LL | epriv();
1417
| ^^^^^ not found in this scope
1518
|
16-
= note: this function exists but is inaccessible:
17-
bar::epriv
19+
note: function `bar::epriv` exists but is inaccessible
20+
--> $DIR/glob-resolve1.rs:9:9
21+
|
22+
LL | fn epriv();
23+
| ^^^^^^^^^^^ not accessible
1824

1925
error[E0423]: expected value, found enum `B`
2026
--> $DIR/glob-resolve1.rs:28:5
@@ -40,8 +46,11 @@ error[E0425]: cannot find value `C` in this scope
4046
LL | C;
4147
| ^ not found in this scope
4248
|
43-
= note: this unit struct exists but is inaccessible:
44-
bar::C
49+
note: unit struct `bar::C` exists but is inaccessible
50+
--> $DIR/glob-resolve1.rs:18:5
51+
|
52+
LL | struct C;
53+
| ^^^^^^^^^ not accessible
4554

4655
error[E0425]: cannot find function `import` in this scope
4756
--> $DIR/glob-resolve1.rs:30:5
@@ -63,8 +72,11 @@ LL | pub enum B {
6372
LL | foo::<A>();
6473
| ^ help: an enum with a similar name exists: `B`
6574
|
66-
= note: this enum exists but is inaccessible:
67-
bar::A
75+
note: enum `bar::A` exists but is inaccessible
76+
--> $DIR/glob-resolve1.rs:11:5
77+
|
78+
LL | enum A {
79+
| ^^^^^^ not accessible
6880

6981
error[E0412]: cannot find type `C` in this scope
7082
--> $DIR/glob-resolve1.rs:33:11
@@ -75,8 +87,11 @@ LL | pub enum B {
7587
LL | foo::<C>();
7688
| ^ help: an enum with a similar name exists: `B`
7789
|
78-
= note: this struct exists but is inaccessible:
79-
bar::C
90+
note: struct `bar::C` exists but is inaccessible
91+
--> $DIR/glob-resolve1.rs:18:5
92+
|
93+
LL | struct C;
94+
| ^^^^^^^^^ not accessible
8095

8196
error[E0412]: cannot find type `D` in this scope
8297
--> $DIR/glob-resolve1.rs:34:11
@@ -87,8 +102,11 @@ LL | pub enum B {
87102
LL | foo::<D>();
88103
| ^ help: an enum with a similar name exists: `B`
89104
|
90-
= note: this type alias exists but is inaccessible:
91-
bar::D
105+
note: type alias `bar::D` exists but is inaccessible
106+
--> $DIR/glob-resolve1.rs:20:5
107+
|
108+
LL | type D = isize;
109+
| ^^^^^^^^^^^^^^^ not accessible
92110

93111
error: aborting due to 8 previous errors
94112

src/test/ui/imports/issue-4366-2.stderr

+5-2
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,11 @@ error[E0412]: cannot find type `Bar` in this scope
44
LL | fn sub() -> Bar { 1 }
55
| ^^^ not found in this scope
66
|
7-
= note: this type alias exists but is inaccessible:
8-
a::b::Bar
7+
note: type alias `a::b::Bar` exists but is inaccessible
8+
--> $DIR/issue-4366-2.rs:11:9
9+
|
10+
LL | type Bar = isize;
11+
| ^^^^^^^^^^^^^^^^^ not accessible
912

1013
error[E0423]: expected function, found module `foo`
1114
--> $DIR/issue-4366-2.rs:25:5

src/test/ui/resolve/issue-42944.stderr

+5-2
Original file line numberDiff line numberDiff line change
@@ -16,8 +16,11 @@ error[E0425]: cannot find function, tuple struct or tuple variant `Bx` in this s
1616
LL | Bx(());
1717
| ^^ not found in this scope
1818
|
19-
= note: this tuple struct exists but is inaccessible:
20-
foo::Bx
19+
note: tuple struct `foo::Bx` exists but is inaccessible
20+
--> $DIR/issue-42944.rs:2:5
21+
|
22+
LL | pub struct Bx(());
23+
| ^^^^^^^^^^^^^^^^^^ not accessible
2124

2225
error: aborting due to 2 previous errors
2326

src/test/ui/resolve/issue-88472.rs

+5-2
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,8 @@
66

77
mod a {
88
struct Foo;
9+
//~^ NOTE: struct `a::Foo` exists but is inaccessible
10+
//~| NOTE: not accessible
911
}
1012

1113
mod b {
@@ -14,22 +16,23 @@ mod b {
1416
type Bar = Foo;
1517
//~^ ERROR: cannot find type `Foo` in this scope [E0412]
1618
//~| NOTE: not found in this scope
17-
//~| NOTE: this struct exists but is inaccessible
1819
}
1920

2021
mod c {
2122
enum Eee {}
23+
//~^ NOTE: these enums exist but are inaccessible
24+
//~| NOTE: `c::Eee`: not accessible
2225

2326
mod d {
2427
enum Eee {}
28+
//~^ NOTE: `c::d::Eee`: not accessible
2529
}
2630
}
2731

2832
mod e {
2933
type Baz = Eee;
3034
//~^ ERROR: cannot find type `Eee` in this scope [E0412]
3135
//~| NOTE: not found in this scope
32-
//~| NOTE: these items exist but are inaccessible
3336
}
3437

3538
fn main() {}

src/test/ui/resolve/issue-88472.stderr

+16-8
Original file line numberDiff line numberDiff line change
@@ -1,24 +1,32 @@
11
error[E0412]: cannot find type `Foo` in this scope
2-
--> $DIR/issue-88472.rs:14:16
2+
--> $DIR/issue-88472.rs:16:16
33
|
44
LL | type Bar = Foo;
55
| ^^^ not found in this scope
66
|
7-
= note: this struct exists but is inaccessible:
8-
a::Foo
7+
note: struct `a::Foo` exists but is inaccessible
8+
--> $DIR/issue-88472.rs:8:5
9+
|
10+
LL | struct Foo;
11+
| ^^^^^^^^^^^ not accessible
912

1013
error[E0412]: cannot find type `Eee` in this scope
11-
--> $DIR/issue-88472.rs:29:16
14+
--> $DIR/issue-88472.rs:33:16
1215
|
1316
LL | type Baz = Eee;
1417
| ^^^ not found in this scope
1518
|
16-
= note: these items exist but are inaccessible:
17-
c::Eee
18-
c::d::Eee
19+
note: these enums exist but are inaccessible
20+
--> $DIR/issue-88472.rs:22:5
21+
|
22+
LL | enum Eee {}
23+
| ^^^^^^^^ `c::Eee`: not accessible
24+
...
25+
LL | enum Eee {}
26+
| ^^^^^^^^ `c::d::Eee`: not accessible
1927

2028
warning: unused import: `crate::a::*`
21-
--> $DIR/issue-88472.rs:12:9
29+
--> $DIR/issue-88472.rs:14:9
2230
|
2331
LL | use crate::a::*;
2432
| ^^^^^^^^^^^

src/test/ui/resolve/privacy-enum-ctor.stderr

+20-8
Original file line numberDiff line numberDiff line change
@@ -171,8 +171,11 @@ LL | pub enum E {
171171
LL | let _: Z = m::n::Z;
172172
| ^ help: an enum with a similar name exists: `E`
173173
|
174-
= note: this enum exists but is inaccessible:
175-
m::Z
174+
note: enum `m::Z` exists but is inaccessible
175+
--> $DIR/privacy-enum-ctor.rs:11:9
176+
|
177+
LL | pub(in m) enum Z {
178+
| ^^^^^^^^^^^^^^^^ not accessible
176179

177180
error[E0423]: expected value, found enum `m::n::Z`
178181
--> $DIR/privacy-enum-ctor.rs:57:16
@@ -211,8 +214,11 @@ LL | pub enum E {
211214
LL | let _: Z = m::n::Z::Fn;
212215
| ^ help: an enum with a similar name exists: `E`
213216
|
214-
= note: this enum exists but is inaccessible:
215-
m::Z
217+
note: enum `m::Z` exists but is inaccessible
218+
--> $DIR/privacy-enum-ctor.rs:11:9
219+
|
220+
LL | pub(in m) enum Z {
221+
| ^^^^^^^^^^^^^^^^ not accessible
216222

217223
error[E0412]: cannot find type `Z` in this scope
218224
--> $DIR/privacy-enum-ctor.rs:64:12
@@ -223,8 +229,11 @@ LL | pub enum E {
223229
LL | let _: Z = m::n::Z::Struct;
224230
| ^ help: an enum with a similar name exists: `E`
225231
|
226-
= note: this enum exists but is inaccessible:
227-
m::Z
232+
note: enum `m::Z` exists but is inaccessible
233+
--> $DIR/privacy-enum-ctor.rs:11:9
234+
|
235+
LL | pub(in m) enum Z {
236+
| ^^^^^^^^^^^^^^^^ not accessible
228237

229238
error[E0423]: expected value, found struct variant `m::n::Z::Struct`
230239
--> $DIR/privacy-enum-ctor.rs:64:16
@@ -246,8 +255,11 @@ LL | pub enum E {
246255
LL | let _: Z = m::n::Z::Unit {};
247256
| ^ help: an enum with a similar name exists: `E`
248257
|
249-
= note: this enum exists but is inaccessible:
250-
m::Z
258+
note: enum `m::Z` exists but is inaccessible
259+
--> $DIR/privacy-enum-ctor.rs:11:9
260+
|
261+
LL | pub(in m) enum Z {
262+
| ^^^^^^^^^^^^^^^^ not accessible
251263

252264
error[E0603]: enum `Z` is private
253265
--> $DIR/privacy-enum-ctor.rs:57:22

src/test/ui/resolve/privacy-struct-ctor.stderr

+5-2
Original file line numberDiff line numberDiff line change
@@ -33,8 +33,11 @@ error[E0423]: expected value, found struct `xcrate::S`
3333
LL | xcrate::S;
3434
| ^^^^^^^^^ constructor is not visible here due to private fields
3535
|
36-
= note: this tuple struct exists but is inaccessible:
37-
m::S
36+
note: tuple struct `m::S` exists but is inaccessible
37+
--> $DIR/privacy-struct-ctor.rs:6:5
38+
|
39+
LL | pub struct S(u8);
40+
| ^^^^^^^^^^^^^^^^^ not accessible
3841

3942
error[E0603]: tuple struct constructor `Z` is private
4043
--> $DIR/privacy-struct-ctor.rs:18:12

0 commit comments

Comments
 (0)