From 5872d3eacd61113c8c241444b2d2403aaec2fbfd Mon Sep 17 00:00:00 2001 From: David Wood Date: Wed, 3 Oct 2018 15:20:20 +0200 Subject: [PATCH] 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. --- src/librustc_resolve/error_reporting.rs | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/src/librustc_resolve/error_reporting.rs b/src/librustc_resolve/error_reporting.rs index 7a66750d700ba..b9194fdfc15d7 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 ) -> Option> { - // 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 = 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.