Skip to content

Commit fea5ab1

Browse files
committed
Prefer accessible paths in 'use' suggestions
This fixes an issue with the following sample: mod foo { mod inaccessible { pub struct X; } pub mod avail { pub struct X; } } fn main() { X; } Instead of suggesting both `use crate::foo::inaccessible::X;` and `use crate::foo::avail::X;`, it should only suggest the latter. It is done by trimming the list of suggestions from inaccessible paths if accessible paths are present. Visibility is checked with `is_accessible_from` now instead of being hard-coded. - Some tests fixes are trivial, and others require a bit more explaining, here are my comments: src/test/ui/issues/issue-35675.stderr: Only needs to make the enum public to have the suggestion make sense. src/test/ui/issues/issue-42944.stderr: Importing the tuple struct won't help because its constructor is not visible, so the attempted constructor does not work. In that case, it's better not to suggest it. The case where the constructor is public is covered in `issue-26545.rs`.
1 parent a39c778 commit fea5ab1

13 files changed

+99
-82
lines changed

src/librustc_resolve/diagnostics.rs

+43-22
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,7 @@ crate struct ImportSuggestion {
4949
pub did: Option<DefId>,
5050
pub descr: &'static str,
5151
pub path: Path,
52+
pub accessible: bool,
5253
}
5354

5455
/// Adjust the impl span so that just the `impl` keyword is taken by removing
@@ -640,21 +641,32 @@ impl<'a> Resolver<'a> {
640641
let mut candidates = Vec::new();
641642
let mut seen_modules = FxHashSet::default();
642643
let not_local_module = crate_name.name != kw::Crate;
643-
let mut worklist = vec![(start_module, Vec::<ast::PathSegment>::new(), not_local_module)];
644+
let mut worklist =
645+
vec![(start_module, Vec::<ast::PathSegment>::new(), true, not_local_module)];
644646

645-
while let Some((in_module, path_segments, in_module_is_extern)) = worklist.pop() {
647+
while let Some((in_module, path_segments, accessible, in_module_is_extern)) = worklist.pop()
648+
{
646649
// We have to visit module children in deterministic order to avoid
647650
// instabilities in reported imports (#43552).
648651
in_module.for_each_child(self, |this, ident, ns, name_binding| {
649652
// avoid imports entirely
650653
if name_binding.is_import() && !name_binding.is_extern_crate() {
651654
return;
652655
}
656+
653657
// avoid non-importable candidates as well
654658
if !name_binding.is_importable() {
655659
return;
656660
}
657661

662+
let child_accessible =
663+
accessible && this.is_accessible_from(name_binding.vis, parent_scope.module);
664+
665+
// do not venture inside inaccessible items of other crates
666+
if in_module_is_extern && !child_accessible {
667+
return;
668+
}
669+
658670
// collect results based on the filter function
659671
// avoid suggesting anything from the same module in which we are resolving
660672
if ident.name == lookup_ident.name
@@ -673,22 +685,29 @@ impl<'a> Resolver<'a> {
673685

674686
segms.push(ast::PathSegment::from_ident(ident));
675687
let path = Path { span: name_binding.span, segments: segms };
676-
// the entity is accessible in the following cases:
677-
// 1. if it's defined in the same crate, it's always
678-
// accessible (since private entities can be made public)
679-
// 2. if it's defined in another crate, it's accessible
680-
// only if both the module is public and the entity is
681-
// declared as public (due to pruning, we don't explore
682-
// outside crate private modules => no need to check this)
683-
if !in_module_is_extern || name_binding.vis == ty::Visibility::Public {
684-
let did = match res {
685-
Res::Def(DefKind::Ctor(..), did) => this.parent(did),
686-
_ => res.opt_def_id(),
687-
};
688-
if candidates.iter().all(|v: &ImportSuggestion| v.did != did) {
689-
candidates.push(ImportSuggestion { did, descr: res.descr(), path });
688+
let did = match res {
689+
Res::Def(DefKind::Ctor(..), did) => this.parent(did),
690+
_ => res.opt_def_id(),
691+
};
692+
693+
if child_accessible {
694+
// Remove invisible match if exists
695+
if let Some(idx) = candidates
696+
.iter()
697+
.position(|v: &ImportSuggestion| v.did == did && !v.accessible)
698+
{
699+
candidates.remove(idx);
690700
}
691701
}
702+
703+
if candidates.iter().all(|v: &ImportSuggestion| v.did != did) {
704+
candidates.push(ImportSuggestion {
705+
did,
706+
descr: res.descr(),
707+
path,
708+
accessible: child_accessible,
709+
});
710+
}
692711
}
693712
}
694713

@@ -701,20 +720,22 @@ impl<'a> Resolver<'a> {
701720
let is_extern_crate_that_also_appears_in_prelude =
702721
name_binding.is_extern_crate() && lookup_ident.span.rust_2018();
703722

704-
let is_visible_to_user =
705-
!in_module_is_extern || name_binding.vis == ty::Visibility::Public;
706-
707-
if !is_extern_crate_that_also_appears_in_prelude && is_visible_to_user {
708-
// add the module to the lookup
723+
if !is_extern_crate_that_also_appears_in_prelude {
709724
let is_extern = in_module_is_extern || name_binding.is_extern_crate();
725+
// add the module to the lookup
710726
if seen_modules.insert(module.def_id().unwrap()) {
711-
worklist.push((module, path_segments, is_extern));
727+
worklist.push((module, path_segments, child_accessible, is_extern));
712728
}
713729
}
714730
}
715731
})
716732
}
717733

734+
// If only some candidates are accessible, take just them
735+
if !candidates.iter().all(|v: &ImportSuggestion| !v.accessible) {
736+
candidates = candidates.into_iter().filter(|x| x.accessible).collect();
737+
}
738+
718739
candidates
719740
}
720741

src/librustc_resolve/late/diagnostics.rs

+6-1
Original file line numberDiff line numberDiff line change
@@ -887,7 +887,12 @@ impl<'a> LateResolutionVisitor<'a, '_, '_> {
887887
let path = Path { span: name_binding.span, segments: path_segments };
888888
result = Some((
889889
module,
890-
ImportSuggestion { did: Some(def_id), descr: "module", path },
890+
ImportSuggestion {
891+
did: Some(def_id),
892+
descr: "module",
893+
path,
894+
accessible: true,
895+
},
891896
));
892897
} else {
893898
// add the module to the lookup

src/test/ui/hygiene/globs.stderr

+1-5
Original file line numberDiff line numberDiff line change
@@ -23,14 +23,10 @@ LL | | }
2323
| |_____- in this macro invocation
2424
|
2525
= note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info)
26-
help: consider importing one of these items
26+
help: consider importing this function
2727
|
2828
LL | use bar::g;
2929
|
30-
LL | use foo::test2::test::g;
31-
|
32-
LL | use foo::test::g;
33-
|
3430

3531
error[E0425]: cannot find function `f` in this scope
3632
--> $DIR/globs.rs:61:12

src/test/ui/issues/issue-26545.rs

+12
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
mod foo {
2+
pub struct B(pub ());
3+
}
4+
5+
mod baz {
6+
fn foo() {
7+
B(());
8+
//~^ ERROR cannot find function, tuple struct or tuple variant `B` in this scope [E0425]
9+
}
10+
}
11+
12+
fn main() {}

src/test/ui/issues/issue-26545.stderr

+14
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
error[E0425]: cannot find function, tuple struct or tuple variant `B` in this scope
2+
--> $DIR/issue-26545.rs:7:9
3+
|
4+
LL | B(());
5+
| ^ not found in this scope
6+
|
7+
help: consider importing this tuple struct
8+
|
9+
LL | use foo::B;
10+
|
11+
12+
error: aborting due to previous error
13+
14+
For more information about this error, try `rustc --explain E0425`.

src/test/ui/issues/issue-35675.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ fn qux() -> Some {
3333
fn main() {}
3434

3535
mod x {
36-
enum Enum {
36+
pub enum Enum {
3737
Variant1,
3838
Variant2(),
3939
Variant3(usize),

src/test/ui/issues/issue-42944.rs

+6-6
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,20 @@
11
mod foo {
2-
pub struct B(());
2+
pub struct Bx(());
33
}
44

55
mod bar {
6-
use foo::B;
6+
use foo::Bx;
77

88
fn foo() {
9-
B(());
10-
//~^ ERROR expected function, tuple struct or tuple variant, found struct `B` [E0423]
9+
Bx(());
10+
//~^ ERROR expected function, tuple struct or tuple variant, found struct `Bx` [E0423]
1111
}
1212
}
1313

1414
mod baz {
1515
fn foo() {
16-
B(());
17-
//~^ ERROR cannot find function, tuple struct or tuple variant `B` in this scope [E0425]
16+
Bx(());
17+
//~^ ERROR cannot find function, tuple struct or tuple variant `Bx` in this scope [E0425]
1818
}
1919
}
2020

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

+7-7
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,18 @@
1-
error[E0423]: expected function, tuple struct or tuple variant, found struct `B`
1+
error[E0423]: expected function, tuple struct or tuple variant, found struct `Bx`
22
--> $DIR/issue-42944.rs:9:9
33
|
4-
LL | B(());
5-
| ^ constructor is not visible here due to private fields
4+
LL | Bx(());
5+
| ^^ constructor is not visible here due to private fields
66

7-
error[E0425]: cannot find function, tuple struct or tuple variant `B` in this scope
7+
error[E0425]: cannot find function, tuple struct or tuple variant `Bx` in this scope
88
--> $DIR/issue-42944.rs:16:9
99
|
10-
LL | B(());
11-
| ^ not found in this scope
10+
LL | Bx(());
11+
| ^^ not found in this scope
1212
|
1313
help: consider importing this tuple struct
1414
|
15-
LL | use foo::B;
15+
LL | use foo::Bx;
1616
|
1717

1818
error: aborting due to 2 previous errors

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

+1-3
Original file line numberDiff line numberDiff line change
@@ -15,12 +15,10 @@ error[E0423]: expected function, found module `foo`
1515
LL | foo();
1616
| ^^^ not a function
1717
|
18-
help: consider importing one of these items instead
18+
help: consider importing this function instead
1919
|
2020
LL | use foo::foo;
2121
|
22-
LL | use m1::foo;
23-
|
2422

2523
error: aborting due to 2 previous errors
2624

src/test/ui/issues/issue-4366.stderr

+1-3
Original file line numberDiff line numberDiff line change
@@ -4,12 +4,10 @@ error[E0425]: cannot find function `foo` in this scope
44
LL | fn sub() -> isize { foo(); 1 }
55
| ^^^ not found in this scope
66
|
7-
help: consider importing one of these items
7+
help: consider importing this function
88
|
99
LL | use foo::foo;
1010
|
11-
LL | use m1::foo;
12-
|
1311

1412
error: aborting due to previous error
1513

src/test/ui/privacy/privacy-ns1.stderr

+3-15
Original file line numberDiff line numberDiff line change
@@ -11,14 +11,10 @@ help: a unit struct with a similar name exists
1111
|
1212
LL | Baz();
1313
| ^^^
14-
help: consider importing one of these items instead
15-
|
16-
LL | use foo1::Bar;
14+
help: consider importing this function instead
1715
|
1816
LL | use foo2::Bar;
1917
|
20-
LL | use foo3::Bar;
21-
|
2218

2319
error[E0425]: cannot find function, tuple struct or tuple variant `Bar` in this scope
2420
--> $DIR/privacy-ns1.rs:51:5
@@ -33,14 +29,10 @@ help: a unit struct with a similar name exists
3329
|
3430
LL | Baz();
3531
| ^^^
36-
help: consider importing one of these items
37-
|
38-
LL | use foo1::Bar;
32+
help: consider importing this function
3933
|
4034
LL | use foo2::Bar;
4135
|
42-
LL | use foo3::Bar;
43-
|
4436

4537
error[E0412]: cannot find type `Bar` in this scope
4638
--> $DIR/privacy-ns1.rs:52:17
@@ -55,14 +47,10 @@ help: a struct with a similar name exists
5547
|
5648
LL | let _x: Box<Baz>;
5749
| ^^^
58-
help: consider importing one of these items
50+
help: consider importing this trait
5951
|
6052
LL | use foo1::Bar;
6153
|
62-
LL | use foo2::Bar;
63-
|
64-
LL | use foo3::Bar;
65-
|
6654

6755
error[E0107]: wrong number of const arguments: expected 0, found 1
6856
--> $DIR/privacy-ns1.rs:35:17

src/test/ui/privacy/privacy-ns2.stderr

+3-15
Original file line numberDiff line numberDiff line change
@@ -4,14 +4,10 @@ error[E0423]: expected function, tuple struct or tuple variant, found trait `Bar
44
LL | Bar();
55
| ^^^ not a function, tuple struct or tuple variant
66
|
7-
help: consider importing one of these items instead
8-
|
9-
LL | use foo1::Bar;
7+
help: consider importing this function instead
108
|
119
LL | use foo2::Bar;
1210
|
13-
LL | use foo3::Bar;
14-
|
1511

1612
error[E0423]: expected function, tuple struct or tuple variant, found trait `Bar`
1713
--> $DIR/privacy-ns2.rs:26:5
@@ -26,14 +22,10 @@ help: a unit struct with a similar name exists
2622
|
2723
LL | Baz();
2824
| ^^^
29-
help: consider importing one of these items instead
30-
|
31-
LL | use foo1::Bar;
25+
help: consider importing this function instead
3226
|
3327
LL | use foo2::Bar;
3428
|
35-
LL | use foo3::Bar;
36-
|
3729

3830
error[E0573]: expected type, found function `Bar`
3931
--> $DIR/privacy-ns2.rs:43:14
@@ -45,14 +37,10 @@ help: use `=` if you meant to assign
4537
|
4638
LL | let _x = Bar();
4739
| ^
48-
help: consider importing one of these items instead
40+
help: consider importing this trait instead
4941
|
5042
LL | use foo1::Bar;
5143
|
52-
LL | use foo2::Bar;
53-
|
54-
LL | use foo3::Bar;
55-
|
5644

5745
error[E0603]: trait `Bar` is private
5846
--> $DIR/privacy-ns2.rs:63:15

src/test/ui/resolve/issue-21221-1.stderr

+1-4
Original file line numberDiff line numberDiff line change
@@ -25,11 +25,8 @@ LL | use mul1::Mul;
2525
|
2626
LL | use mul2::Mul;
2727
|
28-
LL | use mul3::Mul;
29-
|
30-
LL | use mul4::Mul;
28+
LL | use std::ops::Mul;
3129
|
32-
and 2 other candidates
3330

3431
error[E0405]: cannot find trait `ThisTraitReallyDoesntExistInAnyModuleReally` in this scope
3532
--> $DIR/issue-21221-1.rs:63:6

0 commit comments

Comments
 (0)