Skip to content

Commit 6e8452e

Browse files
committed
Auto merge of #43552 - petrochenkov:instab, r=jseyfried
resolve: Try to fix instability in import suggestions cc #42033 `lookup_import_candidates` walks module graph in DFS order and skips modules that were already visited (which is correct because there can be cycles). However it means that if we visited `std::prelude::v1::Result::Ok` first, we will never visit `std::result::Result::Ok` because `Result` will be skipped as already visited (note: enums are also modules here), and otherwise, if we visited `std::result::Result::Ok` first, we will never get to `std::prelude::v1::Result::Ok`. What child module of `std` (`prelude` or `result`) we will visit first, depends on randomized hashing, so we have instability in diagnostics. With this patch modules' children are visited in stable order in `lookup_import_candidates`, this should fix the issue, but let's see what Travis will say. r? @oli-obk
2 parents df90a54 + a6993d6 commit 6e8452e

File tree

5 files changed

+55
-74
lines changed

5 files changed

+55
-74
lines changed

src/librustc_resolve/lib.rs

+17-3
Original file line numberDiff line numberDiff line change
@@ -546,7 +546,7 @@ impl<'a> PathSource<'a> {
546546
}
547547
}
548548

549-
#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)]
549+
#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)]
550550
pub enum Namespace {
551551
TypeNS,
552552
ValueNS,
@@ -898,6 +898,19 @@ impl<'a> ModuleData<'a> {
898898
}
899899
}
900900

901+
fn for_each_child_stable<F: FnMut(Ident, Namespace, &'a NameBinding<'a>)>(&self, mut f: F) {
902+
let resolutions = self.resolutions.borrow();
903+
let mut resolutions = resolutions.iter().map(|(&(ident, ns), &resolution)| {
904+
// Pre-compute keys for sorting
905+
(ident.name.as_str(), ns, ident, resolution)
906+
})
907+
.collect::<Vec<_>>();
908+
resolutions.sort_unstable_by_key(|&(str, ns, ..)| (str, ns));
909+
for &(_, ns, ident, resolution) in resolutions.iter() {
910+
resolution.borrow().binding.map(|binding| f(ident, ns, binding));
911+
}
912+
}
913+
901914
fn def(&self) -> Option<Def> {
902915
match self.kind {
903916
ModuleKind::Def(def, _) => Some(def),
@@ -3352,8 +3365,9 @@ impl<'a> Resolver<'a> {
33523365
in_module_is_extern)) = worklist.pop() {
33533366
self.populate_module_if_necessary(in_module);
33543367

3355-
in_module.for_each_child(|ident, ns, name_binding| {
3356-
3368+
// We have to visit module children in deterministic order to avoid
3369+
// instabilities in reported imports (#43552).
3370+
in_module.for_each_child_stable(|ident, ns, name_binding| {
33573371
// avoid imports entirely
33583372
if name_binding.is_import() && !name_binding.is_extern_crate() { return; }
33593373
// avoid non-importable candidates as well

src/libsyntax_pos/symbol.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -326,7 +326,7 @@ fn with_interner<T, F: FnOnce(&mut Interner) -> T>(f: F) -> T {
326326
/// destroyed. In particular, they must not access string contents. This can
327327
/// be fixed in the future by just leaking all strings until thread death
328328
/// somehow.
329-
#[derive(Clone, Hash, PartialOrd, Eq, Ord)]
329+
#[derive(Clone, Copy, Hash, PartialOrd, Eq, Ord)]
330330
pub struct InternedString {
331331
string: &'static str,
332332
}

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

-67
This file was deleted.

src/test/ui/issue-35675.rs

+16
Original file line numberDiff line numberDiff line change
@@ -33,11 +33,27 @@ fn should_return_fruit_too() -> Fruit::Apple {
3333
//~| NOTE not found in this scope
3434
}
3535

36+
fn foo() -> Ok {
37+
//~^ ERROR expected type, found variant `Ok`
38+
//~| NOTE not a type
39+
//~| HELP there is an enum variant
40+
//~| HELP there is an enum variant
41+
Ok(())
42+
}
43+
3644
fn bar() -> Variant3 {
3745
//~^ ERROR cannot find type `Variant3` in this scope
3846
//~| NOTE not found in this scope
3947
}
4048

49+
fn qux() -> Some {
50+
//~^ ERROR expected type, found variant `Some`
51+
//~| NOTE not a type
52+
//~| HELP there is an enum variant
53+
//~| HELP there is an enum variant
54+
Some(1)
55+
}
56+
4157
fn main() {}
4258

4359
mod x {

src/test/ui/issue-35675.stderr

+21-3
Original file line numberDiff line numberDiff line change
@@ -38,14 +38,32 @@ help: possible candidate is found in another module, you can import it into scop
3838
12 | use Fruit::Apple;
3939
|
4040

41-
error[E0412]: cannot find type `Variant3` in this scope
41+
error[E0573]: expected type, found variant `Ok`
4242
--> $DIR/issue-35675.rs:36:13
4343
|
44-
36 | fn bar() -> Variant3 {
44+
36 | fn foo() -> Ok {
45+
| ^^ not a type
46+
|
47+
= help: there is an enum variant `std::prelude::v1::Ok`, try using `std::prelude::v1`?
48+
= help: there is an enum variant `std::result::Result::Ok`, try using `std::result::Result`?
49+
50+
error[E0412]: cannot find type `Variant3` in this scope
51+
--> $DIR/issue-35675.rs:44:13
52+
|
53+
44 | fn bar() -> Variant3 {
4554
| ^^^^^^^^
4655
| |
4756
| not found in this scope
4857
| help: you can try using the variant's enum: `x::Enum`
4958

50-
error: aborting due to 5 previous errors
59+
error[E0573]: expected type, found variant `Some`
60+
--> $DIR/issue-35675.rs:49:13
61+
|
62+
49 | fn qux() -> Some {
63+
| ^^^^ not a type
64+
|
65+
= help: there is an enum variant `std::prelude::v1::Option::Some`, try using `std::prelude::v1::Option`?
66+
= help: there is an enum variant `std::prelude::v1::Some`, try using `std::prelude::v1`?
67+
68+
error: aborting due to 7 previous errors
5169

0 commit comments

Comments
 (0)