rust-lang/rust · #163148
Clean up diagnostic hashing
compiler/rustc_errors/src/diagnostic.rs29 + / 42 −
@@ -1,13 +1,15 @@ use std::borrow::Cow; use std::fmt::{self, Debug};-use std::hash::{Hash, Hasher};+use std::hash::Hash; use std::ops::{Deref, DerefMut}; use std::panic; use std::path::PathBuf; use std::thread::panicking; use rustc_ast::attr::version::RustcVersion;-use rustc_error_messages::{DiagArgMap, DiagArgName, DiagArgValue, IntoDiagArg};+use rustc_data_structures::stable_hash::StableHasher;+use rustc_error_messages::{DiagArgMap, DiagArgName, IntoDiagArg};+use rustc_hashes::Hash128; use rustc_lint_defs::{Applicability, LintExpectationId}; use rustc_macros::{Decodable, Encodable}; use rustc_span::{DUMMY_SP, Span, Spanned, Symbol};@@ -305,46 +307,31 @@ impl DiagInner { } } - /// Fields used for Hash, and PartialEq trait.- fn keys(- &self,- ) -> (- &Level,- &[(DiagMessage, Style)],- &Option<ErrCode>,- &MultiSpan,- &[Subdiag],- &Suggestions,- Vec<(&DiagArgName, &DiagArgValue)>,- &Option<IsLint>,- ) {- (- &self.level,- &self.messages,- &self.code,- &self.span,- &self.children,- &self.suggestions,- self.args.iter().collect(),- // omit self.sort_span- &self.is_lint,- // omit self.emitted_at- )- }-}--impl Hash for DiagInner {- fn hash<H>(&self, state: &mut H)- where- H: Hasher,- {- self.keys().hash(state);- }-}--impl PartialEq for DiagInner {- fn eq(&self, other: &Self) -> bool {- self.keys() == other.keys()+ /// Hash used to determine if two diagnostics are the same. Used by+ /// `DiagCtxtInner::emitted_diagnostics`. Some fields are ignored for the hash.+ pub(crate) fn dedup_hash(&self) -> Hash128 {+ // Deconstruct to ensure all fields are considered.+ let DiagInner {+ level,+ messages,+ code,+ lint_id: _, // ignore+ span,+ children,+ suggestions,+ args,+ sort_span: _, // ignore+ is_lint,+ long_ty_path: _, // ignore+ emitted_at: _, // ignore+ } = self;++ let hashed_parts =+ (level, messages, code, span, children, suggestions, args.as_slice(), is_lint);++ let mut hasher = StableHasher::new();+ hashed_parts.hash(&mut hasher);+ hasher.finish() } } compiler/rustc_errors/src/lib.rs5 + / 8 −
@@ -325,8 +325,10 @@ struct DiagCtxtInner { emitted_diagnostic_codes: FxIndexSet<ErrCode>, /// This set contains a hash of every diagnostic that has been emitted by- /// this `DiagCtxt`. These hashes is used to avoid emitting the same error- /// twice.+ /// this `DiagCtxt`. These hashes are used to avoid emitting the same error+ /// twice. (Because we don't store the diagnostics themselves, two+ /// different diagnostics with the same hash value will be considered+ /// equivalent. Such collisions should be vanishingly rare...) emitted_diagnostics: FxHashSet<Hash128>, /// We only want to emit `recursion_depth_exceeding_limit` once per@@ -1301,12 +1303,7 @@ impl DiagCtxtInner { self.emitted_diagnostic_codes.insert(code); } - let already_emitted = {- let mut hasher = StableHasher::new();- diagnostic.hash(&mut hasher);- let diagnostic_hash = hasher.finish();- !self.emitted_diagnostics.insert(diagnostic_hash)- };+ let already_emitted = !self.emitted_diagnostics.insert(diagnostic.dedup_hash()); let is_error = diagnostic.is_error(); let is_lint = diagnostic.is_lint.is_some();