about summary refs log tree commit diff
path: root/src
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2017-08-01 06:05:34 +0000
committerbors <bors@rust-lang.org>2017-08-01 06:05:34 +0000
commit6e8452ee4f66ef8b3b1f7a33d873e102bf8603d0 (patch)
tree1bf722dfb9524809ddfed52e2fefabbbae508024 /src
parentdf90a546624c965fb2f859ed665049dbf824f40a (diff)
parenta6993d6469f73adab1bc2a73e148d1caad0ab257 (diff)
Auto merge of #43552 - petrochenkov:instab, r=jseyfried
resolve: Try to fix instability in import suggestions

cc https://github.com/rust-lang/rust/pull/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
Diffstat (limited to 'src')
-rw-r--r--src/librustc_resolve/lib.rs20
-rw-r--r--src/libsyntax_pos/symbol.rs2
-rw-r--r--src/test/compile-fail/issue-35675.rs67
-rw-r--r--src/test/ui/issue-35675.rs16
-rw-r--r--src/test/ui/issue-35675.stderr24
5 files changed, 55 insertions, 74 deletions
diff --git a/src/librustc_resolve/lib.rs b/src/librustc_resolve/lib.rs
index 349a21af895..2317e36a0ab 100644
--- a/src/librustc_resolve/lib.rs
+++ b/src/librustc_resolve/lib.rs
@@ -546,7 +546,7 @@ impl<'a> PathSource<'a> {
     }
 }
 
-#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)]
+#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)]
 pub enum Namespace {
     TypeNS,
     ValueNS,
@@ -898,6 +898,19 @@ impl<'a> ModuleData<'a> {
         }
     }
 
+    fn for_each_child_stable<F: FnMut(Ident, Namespace, &'a NameBinding<'a>)>(&self, mut f: F) {
+        let resolutions = self.resolutions.borrow();
+        let mut resolutions = resolutions.iter().map(|(&(ident, ns), &resolution)| {
+                                                    // Pre-compute keys for sorting
+                                                    (ident.name.as_str(), ns, ident, resolution)
+                                                })
+                                                .collect::<Vec<_>>();
+        resolutions.sort_unstable_by_key(|&(str, ns, ..)| (str, ns));
+        for &(_, ns, ident, resolution) in resolutions.iter() {
+            resolution.borrow().binding.map(|binding| f(ident, ns, binding));
+        }
+    }
+
     fn def(&self) -> Option<Def> {
         match self.kind {
             ModuleKind::Def(def, _) => Some(def),
@@ -3352,8 +3365,9 @@ impl<'a> Resolver<'a> {
                         in_module_is_extern)) = worklist.pop() {
             self.populate_module_if_necessary(in_module);
 
-            in_module.for_each_child(|ident, ns, name_binding| {
-
+            // We have to visit module children in deterministic order to avoid
+            // instabilities in reported imports (#43552).
+            in_module.for_each_child_stable(|ident, ns, name_binding| {
                 // avoid imports entirely
                 if name_binding.is_import() && !name_binding.is_extern_crate() { return; }
                 // avoid non-importable candidates as well
diff --git a/src/libsyntax_pos/symbol.rs b/src/libsyntax_pos/symbol.rs
index debac70545a..e49f1f28e5f 100644
--- a/src/libsyntax_pos/symbol.rs
+++ b/src/libsyntax_pos/symbol.rs
@@ -326,7 +326,7 @@ fn with_interner<T, F: FnOnce(&mut Interner) -> T>(f: F) -> T {
 /// destroyed. In particular, they must not access string contents. This can
 /// be fixed in the future by just leaking all strings until thread death
 /// somehow.
-#[derive(Clone, Hash, PartialOrd, Eq, Ord)]
+#[derive(Clone, Copy, Hash, PartialOrd, Eq, Ord)]
 pub struct InternedString {
     string: &'static str,
 }
diff --git a/src/test/compile-fail/issue-35675.rs b/src/test/compile-fail/issue-35675.rs
deleted file mode 100644
index c09e56cbc5b..00000000000
--- a/src/test/compile-fail/issue-35675.rs
+++ /dev/null
@@ -1,67 +0,0 @@
-// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
-// file at the top-level directory of this distribution and at
-// http://rust-lang.org/COPYRIGHT.
-//
-// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-// these two HELPs are actually in a new line between this line and the `enum Fruit` line
-enum Fruit { //~ HELP possible candidate is found in another module, you can import it into scope
-    //~^ HELP possible candidate is found in another module, you can import it into scope
-    Apple(i64),
-    Orange(i64),
-}
-
-fn should_return_fruit() -> Apple {
-    //~^ ERROR cannot find type `Apple` in this scope
-    //~| NOTE not found in this scope
-    //~| HELP you can try using the variant's enum
-    Apple(5)
-    //~^ ERROR cannot find function `Apple` in this scope
-    //~| NOTE not found in this scope
-}
-
-fn should_return_fruit_too() -> Fruit::Apple {
-    //~^ ERROR expected type, found variant `Fruit::Apple`
-    //~| HELP you can try using the variant's enum
-    //~| NOTE not a type
-    Apple(5)
-    //~^ ERROR cannot find function `Apple` in this scope
-    //~| NOTE not found in this scope
-}
-
-fn foo() -> Ok {
-    //~^ ERROR expected type, found variant `Ok`
-    //~| NOTE not a type
-    //~| HELP there is an enum variant
-    //~| HELP there is an enum variant
-    Ok(())
-}
-
-fn bar() -> Variant3 {
-    //~^ ERROR cannot find type `Variant3` in this scope
-    //~| HELP you can try using the variant's enum
-    //~| NOTE not found in this scope
-}
-
-fn qux() -> Some {
-    //~^ ERROR expected type, found variant `Some`
-    //~| NOTE not a type
-    //~| HELP there is an enum variant
-    //~| HELP there is an enum variant
-    Some(1)
-}
-
-fn main() {}
-
-mod x {
-    enum Enum {
-        Variant1,
-        Variant2(),
-        Variant3(usize),
-        Variant4 {},
-    }
-}
diff --git a/src/test/ui/issue-35675.rs b/src/test/ui/issue-35675.rs
index 391e1f2db5c..001c1f2eddc 100644
--- a/src/test/ui/issue-35675.rs
+++ b/src/test/ui/issue-35675.rs
@@ -33,11 +33,27 @@ fn should_return_fruit_too() -> Fruit::Apple {
     //~| NOTE not found in this scope
 }
 
+fn foo() -> Ok {
+    //~^ ERROR expected type, found variant `Ok`
+    //~| NOTE not a type
+    //~| HELP there is an enum variant
+    //~| HELP there is an enum variant
+    Ok(())
+}
+
 fn bar() -> Variant3 {
     //~^ ERROR cannot find type `Variant3` in this scope
     //~| NOTE not found in this scope
 }
 
+fn qux() -> Some {
+    //~^ ERROR expected type, found variant `Some`
+    //~| NOTE not a type
+    //~| HELP there is an enum variant
+    //~| HELP there is an enum variant
+    Some(1)
+}
+
 fn main() {}
 
 mod x {
diff --git a/src/test/ui/issue-35675.stderr b/src/test/ui/issue-35675.stderr
index c2c10724646..ed330f47208 100644
--- a/src/test/ui/issue-35675.stderr
+++ b/src/test/ui/issue-35675.stderr
@@ -38,14 +38,32 @@ help: possible candidate is found in another module, you can import it into scop
 12 | use Fruit::Apple;
    |
 
-error[E0412]: cannot find type `Variant3` in this scope
+error[E0573]: expected type, found variant `Ok`
   --> $DIR/issue-35675.rs:36:13
    |
-36 | fn bar() -> Variant3 {
+36 | fn foo() -> Ok {
+   |             ^^ not a type
+   |
+   = help: there is an enum variant `std::prelude::v1::Ok`, try using `std::prelude::v1`?
+   = help: there is an enum variant `std::result::Result::Ok`, try using `std::result::Result`?
+
+error[E0412]: cannot find type `Variant3` in this scope
+  --> $DIR/issue-35675.rs:44:13
+   |
+44 | fn bar() -> Variant3 {
    |             ^^^^^^^^
    |             |
    |             not found in this scope
    |             help: you can try using the variant's enum: `x::Enum`
 
-error: aborting due to 5 previous errors
+error[E0573]: expected type, found variant `Some`
+  --> $DIR/issue-35675.rs:49:13
+   |
+49 | fn qux() -> Some {
+   |             ^^^^ not a type
+   |
+   = help: there is an enum variant `std::prelude::v1::Option::Some`, try using `std::prelude::v1::Option`?
+   = help: there is an enum variant `std::prelude::v1::Some`, try using `std::prelude::v1`?
+
+error: aborting due to 7 previous errors