Skip to content

Commit 33a96c8

Browse files
authored
Rollup merge of rust-lang#72623 - da-x:use-suggest-public-path, r=petrochenkov
Prefer accessible paths in 'use' suggestions This PR addresses issue rust-lang#26454, where `use` suggestions are made for paths that don't work. For example: ```rust mod foo { mod bar { struct X; } } fn main() { X; } // suggests `use foo::bar::X;` ```
2 parents 311f99f + fea5ab1 commit 33a96c8

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)