about summary refs log tree commit diff
diff options
context:
space:
mode:
authorDavid Wood <david@davidtw.co>2018-10-03 15:20:20 +0200
committerDavid Wood <david@davidtw.co>2018-10-03 15:20:20 +0200
commit5872d3eacd61113c8c241444b2d2403aaec2fbfd (patch)
treebfbc85b2a5627e6fa33adca42524e06d961ccbd3
parent9d408e0511aeb02ae46c692b2432886372f71c37 (diff)
downloadrust-5872d3eacd61113c8c241444b2d2403aaec2fbfd.tar.gz
rust-5872d3eacd61113c8c241444b2d2403aaec2fbfd.zip
Deterministic external crate suggestion.
This commit ensures that the external crate suggestion is deterministic
by using a `BTreeMap` rather than a `FxHashMap`. This is particularly
useful as `std` and `core` will often contain the same items and
therefore the suggestion would previously suggest either for any given
error - in this case, the suggestion will always prefer `std` now.
-rw-r--r--src/librustc_resolve/error_reporting.rs15
1 files changed, 11 insertions, 4 deletions
diff --git a/src/librustc_resolve/error_reporting.rs b/src/librustc_resolve/error_reporting.rs
index 7a66750d700..b9194fdfc15 100644
--- a/src/librustc_resolve/error_reporting.rs
+++ b/src/librustc_resolve/error_reporting.rs
@@ -10,8 +10,10 @@
 
 use {CrateLint, PathResult};
 
+use std::collections::BTreeSet;
+
 use syntax::ast::Ident;
-use syntax::symbol::keywords;
+use syntax::symbol::{keywords, Symbol};
 use syntax_pos::Span;
 
 use resolve_imports::ImportResolver;
@@ -131,14 +133,19 @@ impl<'a, 'b:'a, 'c: 'b> ImportResolver<'a, 'b, 'c> {
         span: Span,
         mut path: Vec<Ident>
     ) -> Option<Vec<Ident>> {
-        // Need to clone else we can't call `resolve_path` without a borrow error.
-        let external_crate_names = self.resolver.session.extern_prelude.clone();
+        // Need to clone else we can't call `resolve_path` without a borrow error. We also store
+        // into a `BTreeMap` so we can get consistent ordering (and therefore the same diagnostic)
+        // each time.
+        let external_crate_names: BTreeSet<Symbol> = self.resolver.session.extern_prelude
+            .clone().drain().collect();
 
         // Insert a new path segment that we can replace.
         let new_path_segment = path[0].clone();
         path.insert(1, new_path_segment);
 
-        for name in &external_crate_names {
+        // Iterate in reverse so that we start with crates at the end of the alphabet. This means
+        // that we'll always get `std` before `core`.
+        for name in external_crate_names.iter().rev() {
             let ident = Ident::with_empty_ctxt(*name);
             // Calling `maybe_process_path_extern` ensures that we're only running `resolve_path`
             // on a crate name that won't ICE.