Skip to content

Commit 1db1417

Browse files
committed
Auto merge of #27547 - vberger:more_perseverant_resolve, r=nrc
As noted in my previous PR #27439 , the import resolution algorithm has two cases where it bails out: - The algorithm will delay an import if the module containing the target of the import still has unresolved glob imports - The algorithm will delay a glob import of the target module still has unresolved imports This PR alters the behaviour to only bail out when the above described unresolved imports are `pub`, as non-pub imports don't affect the result anyway. It is still possible to fail the algorithm with examples like ```rust pub mod a { pub use b::*; } pub mod b { pub use a::*; } ``` but such configurations cannot be resolved in any meaningful way, as these are cyclic imports. Closes #4865
2 parents a136d4c + 5847ea7 commit 1db1417

File tree

7 files changed

+138
-15
lines changed

7 files changed

+138
-15
lines changed

src/librustc_resolve/build_reduced_graph.rs

+9-1
Original file line numberDiff line numberDiff line change
@@ -924,6 +924,11 @@ impl<'a, 'b:'a, 'tcx:'b> GraphBuilder<'a, 'b, 'tcx> {
924924
is_public,
925925
shadowable));
926926
self.unresolved_imports += 1;
927+
928+
if is_public {
929+
module_.inc_pub_count();
930+
}
931+
927932
// Bump the reference count on the name. Or, if this is a glob, set
928933
// the appropriate flag.
929934

@@ -956,7 +961,10 @@ impl<'a, 'b:'a, 'tcx:'b> GraphBuilder<'a, 'b, 'tcx> {
956961
// Set the glob flag. This tells us that we don't know the
957962
// module's exports ahead of time.
958963

959-
module_.glob_count.set(module_.glob_count.get() + 1);
964+
module_.inc_glob_count();
965+
if is_public {
966+
module_.inc_pub_glob_count();
967+
}
960968
}
961969
}
962970
}

src/librustc_resolve/lib.rs

+32
Original file line numberDiff line numberDiff line change
@@ -699,6 +699,12 @@ pub struct Module {
699699
// The number of unresolved globs that this module exports.
700700
glob_count: Cell<usize>,
701701

702+
// The number of unresolved pub imports (both regular and globs) in this module
703+
pub_count: Cell<usize>,
704+
705+
// The number of unresolved pub glob imports in this module
706+
pub_glob_count: Cell<usize>,
707+
702708
// The index of the import we're resolving.
703709
resolved_import_count: Cell<usize>,
704710

@@ -726,6 +732,8 @@ impl Module {
726732
anonymous_children: RefCell::new(NodeMap()),
727733
import_resolutions: RefCell::new(HashMap::new()),
728734
glob_count: Cell::new(0),
735+
pub_count: Cell::new(0),
736+
pub_glob_count: Cell::new(0),
729737
resolved_import_count: Cell::new(0),
730738
populated: Cell::new(!external),
731739
}
@@ -741,6 +749,30 @@ impl Module {
741749
}
742750
}
743751

752+
impl Module {
753+
pub fn inc_glob_count(&self) {
754+
self.glob_count.set(self.glob_count.get() + 1);
755+
}
756+
pub fn dec_glob_count(&self) {
757+
assert!(self.glob_count.get() > 0);
758+
self.glob_count.set(self.glob_count.get() - 1);
759+
}
760+
pub fn inc_pub_count(&self) {
761+
self.pub_count.set(self.pub_count.get() + 1);
762+
}
763+
pub fn dec_pub_count(&self) {
764+
assert!(self.pub_count.get() > 0);
765+
self.pub_count.set(self.pub_count.get() - 1);
766+
}
767+
pub fn inc_pub_glob_count(&self) {
768+
self.pub_glob_count.set(self.pub_glob_count.get() + 1);
769+
}
770+
pub fn dec_pub_glob_count(&self) {
771+
assert!(self.pub_glob_count.get() > 0);
772+
self.pub_glob_count.set(self.pub_glob_count.get() - 1);
773+
}
774+
}
775+
744776
impl fmt::Debug for Module {
745777
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
746778
write!(f, "{:?}, kind: {:?}, {}",

src/librustc_resolve/resolve_imports.rs

+23-8
Original file line numberDiff line numberDiff line change
@@ -407,13 +407,18 @@ impl<'a, 'b:'a, 'tcx:'b> ImportResolver<'a, 'b, 'tcx> {
407407
if resolution_result.success() {
408408
match import_directive.subclass {
409409
GlobImport => {
410-
assert!(module_.glob_count.get() >= 1);
411-
module_.glob_count.set(module_.glob_count.get() - 1);
410+
module_.dec_glob_count();
411+
if import_directive.is_public {
412+
module_.dec_pub_glob_count();
413+
}
412414
}
413415
SingleImport(..) => {
414416
// Ignore.
415417
}
416418
}
419+
if import_directive.is_public {
420+
module_.dec_pub_count();
421+
}
417422
}
418423

419424
return resolution_result;
@@ -503,8 +508,8 @@ impl<'a, 'b:'a, 'tcx:'b> ImportResolver<'a, 'b, 'tcx> {
503508
// containing module, bail out. We don't know enough to be
504509
// able to resolve this import.
505510

506-
if target_module.glob_count.get() > 0 {
507-
debug!("(resolving single import) unresolved glob; \
511+
if target_module.pub_glob_count.get() > 0 {
512+
debug!("(resolving single import) unresolved pub glob; \
508513
bailing out");
509514
return ResolveResult::Indeterminate;
510515
}
@@ -767,16 +772,26 @@ impl<'a, 'b:'a, 'tcx:'b> ImportResolver<'a, 'b, 'tcx> {
767772

768773
// We must bail out if the node has unresolved imports of any kind
769774
// (including globs).
770-
if !(*target_module).all_imports_resolved() {
775+
if (*target_module).pub_count.get() > 0 {
771776
debug!("(resolving glob import) target module has unresolved \
772-
imports; bailing out");
777+
pub imports; bailing out");
773778
return ResolveResult::Indeterminate;
774779
}
775780

776-
assert_eq!(target_module.glob_count.get(), 0);
777-
778781
// Add all resolved imports from the containing module.
779782
let import_resolutions = target_module.import_resolutions.borrow();
783+
784+
if module_.import_resolutions.borrow_state() != ::std::cell::BorrowState::Unused {
785+
// In this case, target_module == module_
786+
// This means we are trying to glob import a module into itself,
787+
// and it is a no-go
788+
debug!("(resolving glob imports) target module is current module; giving up");
789+
return ResolveResult::Failed(Some((
790+
import_directive.span,
791+
"Cannot glob-import a module into itself.".into()
792+
)));
793+
}
794+
780795
for (ident, target_import_resolution) in import_resolutions.iter() {
781796
debug!("(resolving glob import) writing module resolution \
782797
{} into `{}`",

src/test/compile-fail/issue-25396.rs

+5-5
Original file line numberDiff line numberDiff line change
@@ -11,14 +11,14 @@
1111
use foo::baz;
1212
use bar::baz; //~ ERROR a module named `baz` has already been imported
1313

14-
use bar::Quux; //~ ERROR a trait named `Quux` has already been imported
1514
use foo::Quux;
15+
use bar::Quux; //~ ERROR a trait named `Quux` has already been imported
1616

17-
use foo::blah; //~ ERROR a type named `blah` has already been imported
18-
use bar::blah;
17+
use foo::blah;
18+
use bar::blah; //~ ERROR a type named `blah` has already been imported
1919

20-
use foo::WOMP; //~ ERROR a value named `WOMP` has already been imported
21-
use bar::WOMP;
20+
use foo::WOMP;
21+
use bar::WOMP; //~ ERROR a value named `WOMP` has already been imported
2222

2323
fn main() {}
2424

src/test/compile-fail/issue-8208.rs

+11-1
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,17 @@
88
// option. This file may not be copied, modified, or distributed
99
// except according to those terms.
1010

11-
use self::*; //~ ERROR: unresolved import
11+
use self::*; //~ ERROR: unresolved import `self::*`. Cannot glob-import a module into itself.
12+
13+
mod foo {
14+
use foo::*; //~ ERROR: unresolved import `foo::*`. Cannot glob-import a module into itself.
15+
16+
mod bar {
17+
use super::bar::*;
18+
//~^ ERROR: unresolved import `super::bar::*`. Cannot glob-import a module into itself.
19+
}
20+
21+
}
1222

1323
fn main() {
1424
}

src/test/run-pass/issue-4865-2.rs

+33
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
2+
// file at the top-level directory of this distribution and at
3+
// http://rust-lang.org/COPYRIGHT.
4+
//
5+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6+
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8+
// option. This file may not be copied, modified, or distributed
9+
// except according to those terms.
10+
11+
// Previously, this would have failed to resolve due to the circular
12+
// block between `use say` and `pub use hello::*`.
13+
//
14+
// Now, as `use say` is not `pub`, the glob import can resolve
15+
// without any problem and this resolves fine.
16+
17+
pub use hello::*;
18+
19+
pub mod say {
20+
pub fn hello() { println!("hello"); }
21+
}
22+
23+
pub mod hello {
24+
use say;
25+
26+
pub fn hello() {
27+
say::hello();
28+
}
29+
}
30+
31+
fn main() {
32+
hello();
33+
}

src/test/run-pass/issue-4865-3.rs

+25
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
2+
// file at the top-level directory of this distribution and at
3+
// http://rust-lang.org/COPYRIGHT.
4+
//
5+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6+
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8+
// option. This file may not be copied, modified, or distributed
9+
// except according to those terms.
10+
11+
// This should resolve fine even with the circular imports as
12+
// they are not `pub`.
13+
14+
pub mod a {
15+
use b::*;
16+
}
17+
18+
pub mod b {
19+
use a::*;
20+
}
21+
22+
use a::*;
23+
24+
fn main() {
25+
}

0 commit comments

Comments
 (0)