Skip to content

Commit 255ce47

Browse files
committed
Make resolve more perseverant with indeterminate imports.
When encountering an indeterminate import, still try to resolve the following imports of the module. This avoids dead-lock-like situations where 2 modules are blocked, each waiting for the resolution of the other. Fixes #18083.
1 parent c1b8bd2 commit 255ce47

File tree

5 files changed

+130
-13
lines changed

5 files changed

+130
-13
lines changed

src/librustc_resolve/lib.rs

+16-3
Original file line numberDiff line numberDiff line change
@@ -1546,9 +1546,22 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
15461546
}
15471547

15481548
// We're out of luck.
1549-
debug!("(resolving name in module) failed to resolve `{}`",
1550-
&token::get_name(name));
1551-
return Failed(None);
1549+
return match name_search_type {
1550+
ImportSearch => {
1551+
// In this case, it is possible that we simply chocked on a not-yet-resolved import
1552+
// (mostly due to globs), thus we do not want to conclude too early that the
1553+
// resolve is failed. The main resolve_import loop will stop us anyway if it is
1554+
// indeed unresolved.
1555+
debug!("(resolving name in module) failed to resolve `{}` for now, bailing out.",
1556+
&token::get_name(name));
1557+
Indeterminate
1558+
},
1559+
PathSearch => {
1560+
debug!("(resolving name in module) failed to resolve `{}`",
1561+
&token::get_name(name));
1562+
Failed(None)
1563+
}
1564+
};
15521565
}
15531566

15541567
fn report_unresolved_imports(&mut self, module_: Rc<Module>) {

src/librustc_resolve/resolve_imports.rs

+17-10
Original file line numberDiff line numberDiff line change
@@ -260,14 +260,15 @@ impl<'a, 'b:'a, 'tcx:'b> ImportResolver<'a, 'b, 'tcx> {
260260
return;
261261
}
262262

263-
let imports = module.imports.borrow();
263+
let mut imports = module.imports.borrow_mut();
264264
let import_count = imports.len();
265-
while module.resolved_import_count.get() < import_count {
265+
let mut indeterminate_imports = Vec::new();
266+
while module.resolved_import_count.get() + indeterminate_imports.len() < import_count {
266267
let import_index = module.resolved_import_count.get();
267-
let import_directive = &(*imports)[import_index];
268268
match self.resolve_import_for_module(module.clone(),
269-
import_directive) {
269+
&imports[import_index]) {
270270
ResolveResult::Failed(err) => {
271+
let import_directive = &imports[import_index];
271272
let (span, help) = match err {
272273
Some((span, msg)) => (span, format!(". {}", msg)),
273274
None => (import_directive.span, String::new())
@@ -279,13 +280,17 @@ impl<'a, 'b:'a, 'tcx:'b> ImportResolver<'a, 'b, 'tcx> {
279280
help);
280281
self.resolver.resolve_error(span, &msg[..]);
281282
}
282-
ResolveResult::Indeterminate => break, // Bail out. We'll come around next time.
283+
ResolveResult::Indeterminate => {
284+
indeterminate_imports.push(imports.swap_remove(import_index));
285+
continue;
286+
},
283287
ResolveResult::Success(()) => () // Good. Continue.
284288
}
285-
286289
module.resolved_import_count
287290
.set(module.resolved_import_count.get() + 1);
288291
}
292+
// put back all the unresolved imports, for next pass
293+
imports.extend(indeterminate_imports);
289294
}
290295

291296
/// Attempts to resolve the given import. The return value indicates
@@ -654,10 +659,12 @@ impl<'a, 'b:'a, 'tcx:'b> ImportResolver<'a, 'b, 'tcx> {
654659
target);
655660

656661
if value_result.is_unbound() && type_result.is_unbound() {
657-
let msg = format!("There is no `{}` in `{}`",
658-
token::get_name(source),
659-
module_to_string(&target_module));
660-
return ResolveResult::Failed(Some((directive.span, msg)));
662+
// Due to chained imports, it is possible that this import is simply not yet
663+
// resolved, so we settle with Indeterminate.
664+
// The main loop of the algorithm will break anyway is a pass does not resolve
665+
// anything more.
666+
debug!("(resolving single import) unresolved for now, bailing out");
667+
return ResolveResult::Indeterminate;
661668
}
662669
let value_used_public = value_used_reexport || value_used_public;
663670
let type_used_public = type_used_reexport || type_used_public;

src/test/run-pass/import-glob-1.rs

+32
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
// Copyright 2012-2014 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+
#![allow(unused_imports, dead_code)]
12+
13+
mod bar {
14+
pub use self::middle::*;
15+
16+
mod middle {
17+
pub use self::baz::Baz;
18+
19+
mod baz {
20+
pub enum Baz {
21+
Baz1,
22+
Baz2
23+
}
24+
}
25+
}
26+
}
27+
28+
mod foo {
29+
use bar::Baz::{Baz1, Baz2};
30+
}
31+
32+
fn main() {}

src/test/run-pass/issue18083.rs

+29
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
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+
mod a {
12+
use b::{B};
13+
pub use self::inner::A;
14+
15+
mod inner {
16+
pub struct A;
17+
}
18+
}
19+
20+
mod b {
21+
use a::{A};
22+
pub use self::inner::B;
23+
24+
mod inner {
25+
pub struct B;
26+
}
27+
}
28+
29+
fn main() {}

src/test/run-pass/issue4865-1.rs

+36
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
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+
pub mod a {
12+
use b::fn_b;
13+
use c::*;
14+
15+
pub fn fn_a(){
16+
}
17+
}
18+
19+
pub mod b {
20+
use a::fn_a;
21+
use c::*;
22+
23+
pub fn fn_b(){
24+
}
25+
}
26+
27+
pub mod c{
28+
pub fn fn_c(){
29+
}
30+
}
31+
32+
use a::fn_a;
33+
use b::fn_b;
34+
35+
fn main() {
36+
}

0 commit comments

Comments
 (0)