]> git.lizzy.rs Git - rust.git/commitdiff
Deterministic external crate suggestion.
authorDavid Wood <david@davidtw.co>
Wed, 3 Oct 2018 13:20:20 +0000 (15:20 +0200)
committerDavid Wood <david@davidtw.co>
Wed, 3 Oct 2018 13:20:20 +0000 (15:20 +0200)
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.

src/librustc_resolve/error_reporting.rs

index 7a66750d700ba502da3c7fd9154303346c6a1a7e..b9194fdfc15d73d9e0986c0f3955a47620af368e 100644 (file)
 
 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 @@ fn make_external_crate_suggestion(
         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.