From 8a1de57a4aaf4ff13d20fdbc162064f237bb7679 Mon Sep 17 00:00:00 2001 From: Michael Woerister Date: Fri, 2 Dec 2022 16:27:25 +0100 Subject: [PATCH 1/4] Use UnordSet instead of FxHashSet in define_id_collections!(). --- .../src/coverageinfo/mapgen.rs | 8 +++--- compiler/rustc_codegen_ssa/src/base.rs | 15 ++++++----- compiler/rustc_data_structures/src/fx.rs | 2 +- compiler/rustc_data_structures/src/unord.rs | 26 ++++++++++++++++--- compiler/rustc_hir_typeck/src/writeback.rs | 14 +++++++--- src/tools/clippy/clippy_lints/src/len_zero.rs | 2 +- 6 files changed, 49 insertions(+), 18 deletions(-) diff --git a/compiler/rustc_codegen_llvm/src/coverageinfo/mapgen.rs b/compiler/rustc_codegen_llvm/src/coverageinfo/mapgen.rs index 393bf30e9f8..22c61248b7d 100644 --- a/compiler/rustc_codegen_llvm/src/coverageinfo/mapgen.rs +++ b/compiler/rustc_codegen_llvm/src/coverageinfo/mapgen.rs @@ -8,7 +8,7 @@ use rustc_codegen_ssa::coverageinfo::map::{Counter, CounterExpression}; use rustc_codegen_ssa::traits::{ConstMethods, CoverageInfoMethods}; use rustc_data_structures::fx::FxIndexSet; use rustc_hir::def::DefKind; -use rustc_hir::def_id::DefIdSet; +use rustc_hir::def_id::DefId; use rustc_llvm::RustString; use rustc_middle::bug; use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrFlags; @@ -291,7 +291,7 @@ fn add_unused_functions(cx: &CodegenCx<'_, '_>) { let ignore_unused_generics = tcx.sess.instrument_coverage_except_unused_generics(); - let eligible_def_ids: DefIdSet = tcx + let eligible_def_ids: Vec = tcx .mir_keys(()) .iter() .filter_map(|local_def_id| { @@ -317,7 +317,9 @@ fn add_unused_functions(cx: &CodegenCx<'_, '_>) { let codegenned_def_ids = tcx.codegened_and_inlined_items(()); - for &non_codegenned_def_id in eligible_def_ids.difference(codegenned_def_ids) { + for non_codegenned_def_id in + eligible_def_ids.into_iter().filter(|id| !codegenned_def_ids.contains(id)) + { let codegen_fn_attrs = tcx.codegen_fn_attrs(non_codegenned_def_id); // If a function is marked `#[no_coverage]`, then skip generating a diff --git a/compiler/rustc_codegen_ssa/src/base.rs b/compiler/rustc_codegen_ssa/src/base.rs index f7312f6fcda..32d3cfe6fc6 100644 --- a/compiler/rustc_codegen_ssa/src/base.rs +++ b/compiler/rustc_codegen_ssa/src/base.rs @@ -964,16 +964,19 @@ pub fn provide(providers: &mut Providers) { }; let (defids, _) = tcx.collect_and_partition_mono_items(cratenum); - for id in &*defids { + + let any_for_speed = defids.items().any(|id| { let CodegenFnAttrs { optimize, .. } = tcx.codegen_fn_attrs(*id); match optimize { - attr::OptimizeAttr::None => continue, - attr::OptimizeAttr::Size => continue, - attr::OptimizeAttr::Speed => { - return for_speed; - } + attr::OptimizeAttr::None | attr::OptimizeAttr::Size => false, + attr::OptimizeAttr::Speed => true, } + }); + + if any_for_speed { + return for_speed; } + tcx.sess.opts.optimize }; } diff --git a/compiler/rustc_data_structures/src/fx.rs b/compiler/rustc_data_structures/src/fx.rs index 0d0c51b6819..11f9def34aa 100644 --- a/compiler/rustc_data_structures/src/fx.rs +++ b/compiler/rustc_data_structures/src/fx.rs @@ -12,7 +12,7 @@ pub type IndexEntry<'a, K, V> = indexmap::map::Entry<'a, K, V>; macro_rules! define_id_collections { ($map_name:ident, $set_name:ident, $entry_name:ident, $key:ty) => { pub type $map_name = $crate::fx::FxHashMap<$key, T>; - pub type $set_name = $crate::fx::FxHashSet<$key>; + pub type $set_name = $crate::unord::UnordSet<$key>; pub type $entry_name<'a, T> = $crate::fx::StdEntry<'a, $key, T>; }; } diff --git a/compiler/rustc_data_structures/src/unord.rs b/compiler/rustc_data_structures/src/unord.rs index 14257e4d5c6..cfd7ee097a3 100644 --- a/compiler/rustc_data_structures/src/unord.rs +++ b/compiler/rustc_data_structures/src/unord.rs @@ -38,17 +38,17 @@ impl> UnordItems { } #[inline] - pub fn all bool>(mut self, f: F) -> bool { + pub fn all bool>(mut self, f: F) -> bool { self.0.all(f) } #[inline] - pub fn any bool>(mut self, f: F) -> bool { + pub fn any bool>(mut self, f: F) -> bool { self.0.any(f) } #[inline] - pub fn filter bool>(self, f: F) -> UnordItems> { + pub fn filter bool>(self, f: F) -> UnordItems> { UnordItems(self.0.filter(f)) } @@ -96,6 +96,15 @@ impl> UnordItems { pub fn count(self) -> usize { self.0.count() } + + #[inline] + pub fn flat_map(self, f: F) -> UnordItems> + where + U: IntoIterator, + F: Fn(T) -> U, + { + UnordItems(self.0.flat_map(f)) + } } impl<'a, T: Clone + 'a, I: Iterator> UnordItems<&'a T, I> { @@ -193,6 +202,11 @@ impl UnordSet { pub fn extend>(&mut self, items: UnordItems) { self.inner.extend(items.0) } + + #[inline] + pub fn clear(&mut self) { + self.inner.clear(); + } } impl Extend for UnordSet { @@ -201,6 +215,12 @@ impl Extend for UnordSet { } } +impl FromIterator for UnordSet { + fn from_iter>(iter: T) -> Self { + UnordSet { inner: FxHashSet::from_iter(iter) } + } +} + impl> HashStable for UnordSet { #[inline] fn hash_stable(&self, hcx: &mut HCX, hasher: &mut StableHasher) { diff --git a/compiler/rustc_hir_typeck/src/writeback.rs b/compiler/rustc_hir_typeck/src/writeback.rs index 30ef7f3ba29..b8c1bcc5a28 100644 --- a/compiler/rustc_hir_typeck/src/writeback.rs +++ b/compiler/rustc_hir_typeck/src/writeback.rs @@ -19,6 +19,7 @@ use rustc_middle::ty::TypeckResults; use rustc_middle::ty::{self, ClosureSizeProfileData, Ty, TyCtxt}; use rustc_span::symbol::sym; use rustc_span::Span; +use smallvec::SmallVec; use std::mem; use std::ops::ControlFlow; @@ -458,12 +459,17 @@ impl<'cx, 'tcx> WritebackCx<'cx, 'tcx> { fn visit_coercion_casts(&mut self) { let fcx_typeck_results = self.fcx.typeck_results.borrow(); - let fcx_coercion_casts = fcx_typeck_results.coercion_casts(); + assert_eq!(fcx_typeck_results.hir_owner, self.typeck_results.hir_owner); - for local_id in fcx_coercion_casts { - self.typeck_results.set_coercion_cast(*local_id); - } + self.tcx().with_stable_hashing_context(|hcx| { + let fcx_coercion_casts: SmallVec<[_; 32]> = + fcx_typeck_results.coercion_casts().items().cloned().into_sorted_small_vec(&hcx); + + for local_id in fcx_coercion_casts { + self.typeck_results.set_coercion_cast(local_id); + } + }); } fn visit_user_provided_tys(&mut self) { diff --git a/src/tools/clippy/clippy_lints/src/len_zero.rs b/src/tools/clippy/clippy_lints/src/len_zero.rs index 9eba4675629..3c70c9cf19a 100644 --- a/src/tools/clippy/clippy_lints/src/len_zero.rs +++ b/src/tools/clippy/clippy_lints/src/len_zero.rs @@ -219,7 +219,7 @@ fn check_trait_items(cx: &LateContext<'_>, visited_trait: &Item<'_>, trait_items let is_empty = sym!(is_empty); let is_empty_method_found = current_and_super_traits - .iter() + .items() .flat_map(|&i| cx.tcx.associated_items(i).filter_by_name_unhygienic(is_empty)) .any(|i| { i.kind == ty::AssocKind::Fn From c3d25731207e466fc20b00124a5aadd435d3b885 Mon Sep 17 00:00:00 2001 From: Michael Woerister Date: Tue, 17 Jan 2023 12:05:01 +0100 Subject: [PATCH 2/4] Use UnordMap instead of FxHashMap in define_id_collections!(). --- .../src/back/symbol_export.rs | 14 ++- compiler/rustc_data_structures/src/fx.rs | 2 +- compiler/rustc_data_structures/src/unord.rs | 110 +++++++++++++++++- .../rustc_hir_analysis/src/variance/solve.rs | 15 +-- compiler/rustc_hir_typeck/src/writeback.rs | 86 ++++++++------ compiler/rustc_lint_defs/src/lib.rs | 5 +- .../src/rmeta/decoder/cstore_impl.rs | 7 +- compiler/rustc_metadata/src/rmeta/encoder.rs | 7 +- compiler/rustc_middle/src/ty/mod.rs | 4 +- .../rustc_middle/src/ty/typeck_results.rs | 37 ++++-- compiler/rustc_resolve/src/check_unused.rs | 10 +- .../clippy/clippy_lints/src/inherent_impl.rs | 26 ++--- .../src/loops/while_immutable_condition.rs | 2 +- .../clippy_lints/src/missing_trait_methods.rs | 26 +++-- .../clippy_lints/src/pass_by_ref_or_value.rs | 4 +- 15 files changed, 253 insertions(+), 102 deletions(-) diff --git a/compiler/rustc_codegen_ssa/src/back/symbol_export.rs b/compiler/rustc_codegen_ssa/src/back/symbol_export.rs index 8cb7d74b90d..b442483346d 100644 --- a/compiler/rustc_codegen_ssa/src/back/symbol_export.rs +++ b/compiler/rustc_codegen_ssa/src/back/symbol_export.rs @@ -173,11 +173,15 @@ fn exported_symbols_provider_local( return &[]; } - let mut symbols: Vec<_> = tcx - .reachable_non_generics(LOCAL_CRATE) - .iter() - .map(|(&def_id, &info)| (ExportedSymbol::NonGeneric(def_id), info)) - .collect(); + // FIXME: Sorting this is unnecessary since we are sorting later anyway. + // Can we skip the later sorting? + let mut symbols: Vec<_> = tcx.with_stable_hashing_context(|hcx| { + tcx.reachable_non_generics(LOCAL_CRATE) + .to_sorted(&hcx) + .into_iter() + .map(|(&def_id, &info)| (ExportedSymbol::NonGeneric(def_id), info)) + .collect() + }); if tcx.entry_fn(()).is_some() { let exported_symbol = diff --git a/compiler/rustc_data_structures/src/fx.rs b/compiler/rustc_data_structures/src/fx.rs index 11f9def34aa..9fce0e1e65c 100644 --- a/compiler/rustc_data_structures/src/fx.rs +++ b/compiler/rustc_data_structures/src/fx.rs @@ -11,7 +11,7 @@ pub type IndexEntry<'a, K, V> = indexmap::map::Entry<'a, K, V>; #[macro_export] macro_rules! define_id_collections { ($map_name:ident, $set_name:ident, $entry_name:ident, $key:ty) => { - pub type $map_name = $crate::fx::FxHashMap<$key, T>; + pub type $map_name = $crate::unord::UnordMap<$key, T>; pub type $set_name = $crate::unord::UnordSet<$key>; pub type $entry_name<'a, T> = $crate::fx::StdEntry<'a, $key, T>; }; diff --git a/compiler/rustc_data_structures/src/unord.rs b/compiler/rustc_data_structures/src/unord.rs index cfd7ee097a3..1e71629a7c4 100644 --- a/compiler/rustc_data_structures/src/unord.rs +++ b/compiler/rustc_data_structures/src/unord.rs @@ -6,8 +6,10 @@ use rustc_hash::{FxHashMap, FxHashSet}; use smallvec::SmallVec; use std::{ borrow::Borrow, + collections::hash_map::Entry, hash::Hash, iter::{Product, Sum}, + ops::Index, }; use crate::{ @@ -187,7 +189,16 @@ impl UnordSet { } #[inline] - pub fn items(&self) -> UnordItems<&V, impl Iterator> { + pub fn remove(&mut self, k: &Q) -> bool + where + V: Borrow, + Q: Hash + Eq, + { + self.inner.remove(k) + } + + #[inline] + pub fn items<'a>(&'a self) -> UnordItems<&'a V, impl Iterator> { UnordItems(self.inner.iter()) } @@ -254,6 +265,18 @@ impl Extend<(K, V)> for UnordMap { } } +impl FromIterator<(K, V)> for UnordMap { + fn from_iter>(iter: T) -> Self { + UnordMap { inner: FxHashMap::from_iter(iter) } + } +} + +impl> From> for UnordMap { + fn from(items: UnordItems<(K, V), I>) -> Self { + UnordMap { inner: FxHashMap::from_iter(items.0) } + } +} + impl UnordMap { #[inline] pub fn len(&self) -> usize { @@ -275,7 +298,44 @@ impl UnordMap { } #[inline] - pub fn items(&self) -> UnordItems<(&K, &V), impl Iterator> { + pub fn is_empty(&self) -> bool { + self.inner.is_empty() + } + + #[inline] + pub fn entry(&mut self, key: K) -> Entry<'_, K, V> { + self.inner.entry(key) + } + + #[inline] + pub fn get(&self, k: &Q) -> Option<&V> + where + K: Borrow, + Q: Hash + Eq, + { + self.inner.get(k) + } + + #[inline] + pub fn get_mut(&mut self, k: &Q) -> Option<&mut V> + where + K: Borrow, + Q: Hash + Eq, + { + self.inner.get_mut(k) + } + + #[inline] + pub fn remove(&mut self, k: &Q) -> Option + where + K: Borrow, + Q: Hash + Eq, + { + self.inner.remove(k) + } + + #[inline] + pub fn items<'a>(&'a self) -> UnordItems<(&'a K, &'a V), impl Iterator> { UnordItems(self.inner.iter()) } @@ -290,6 +350,46 @@ impl UnordMap { pub fn extend>(&mut self, items: UnordItems<(K, V), I>) { self.inner.extend(items.0) } + + pub fn to_sorted(&self, hcx: &HCX) -> Vec<(&K, &V)> + where + K: ToStableHashKey, + { + let mut items: Vec<(&K, &V)> = self.inner.iter().collect(); + items.sort_by_cached_key(|(k, _)| k.to_stable_hash_key(hcx)); + items + } + + pub fn into_sorted(self, hcx: &HCX) -> Vec<(K, V)> + where + K: ToStableHashKey, + { + let mut items: Vec<(K, V)> = self.inner.into_iter().collect(); + items.sort_by_cached_key(|(k, _)| k.to_stable_hash_key(hcx)); + items + } + + pub fn values_sorted(&self, hcx: &HCX) -> impl Iterator + where + K: ToStableHashKey, + { + let mut items: Vec<(&K, &V)> = self.inner.iter().collect(); + items.sort_by_cached_key(|(k, _)| k.to_stable_hash_key(hcx)); + items.into_iter().map(|(_, v)| v) + } +} + +impl Index<&Q> for UnordMap +where + K: Eq + Hash + Borrow, + Q: Eq + Hash, +{ + type Output = V; + + #[inline] + fn index(&self, key: &Q) -> &V { + &self.inner[key] + } } impl, V: HashStable> HashStable for UnordMap { @@ -354,6 +454,12 @@ impl Extend for UnordBag { } } +impl> From> for UnordBag { + fn from(value: UnordItems) -> Self { + UnordBag { inner: Vec::from_iter(value.0) } + } +} + impl> HashStable for UnordBag { #[inline] fn hash_stable(&self, hcx: &mut HCX, hasher: &mut StableHasher) { diff --git a/compiler/rustc_hir_analysis/src/variance/solve.rs b/compiler/rustc_hir_analysis/src/variance/solve.rs index c9b59d35704..2d283532bdf 100644 --- a/compiler/rustc_hir_analysis/src/variance/solve.rs +++ b/compiler/rustc_hir_analysis/src/variance/solve.rs @@ -5,8 +5,7 @@ //! optimal solution to the constraints. The final variance for each //! inferred is then written into the `variance_map` in the tcx. -use rustc_data_structures::fx::FxHashMap; -use rustc_hir::def_id::DefId; +use rustc_hir::def_id::DefIdMap; use rustc_middle::ty; use super::constraints::*; @@ -89,14 +88,12 @@ impl<'a, 'tcx> SolveContext<'a, 'tcx> { } } - fn create_map(&self) -> FxHashMap { + fn create_map(&self) -> DefIdMap<&'tcx [ty::Variance]> { let tcx = self.terms_cx.tcx; let solutions = &self.solutions; - self.terms_cx - .inferred_starts - .iter() - .map(|(&def_id, &InferredIndex(start))| { + DefIdMap::from(self.terms_cx.inferred_starts.items().map( + |(&def_id, &InferredIndex(start))| { let generics = tcx.generics_of(def_id); let count = generics.count(); @@ -115,8 +112,8 @@ impl<'a, 'tcx> SolveContext<'a, 'tcx> { } (def_id.to_def_id(), &*variances) - }) - .collect() + }, + )) } fn evaluate(&self, term: VarianceTermPtr<'a>) -> ty::Variance { diff --git a/compiler/rustc_hir_typeck/src/writeback.rs b/compiler/rustc_hir_typeck/src/writeback.rs index b8c1bcc5a28..6e6b63beca2 100644 --- a/compiler/rustc_hir_typeck/src/writeback.rs +++ b/compiler/rustc_hir_typeck/src/writeback.rs @@ -449,8 +449,11 @@ impl<'cx, 'tcx> WritebackCx<'cx, 'tcx> { assert_eq!(fcx_typeck_results.hir_owner, self.typeck_results.hir_owner); let common_hir_owner = fcx_typeck_results.hir_owner; - for (id, origin) in fcx_typeck_results.closure_kind_origins().iter() { - let hir_id = hir::HirId { owner: common_hir_owner, local_id: *id }; + let fcx_closure_kind_origins = + fcx_typeck_results.closure_kind_origins().items_in_stable_order(self.tcx()); + + for (&local_id, origin) in fcx_closure_kind_origins { + let hir_id = hir::HirId { owner: common_hir_owner, local_id }; let place_span = origin.0; let place = self.resolve(origin.1.clone(), &place_span); self.typeck_results.closure_kind_origins_mut().insert(hir_id, (place_span, place)); @@ -477,22 +480,15 @@ impl<'cx, 'tcx> WritebackCx<'cx, 'tcx> { assert_eq!(fcx_typeck_results.hir_owner, self.typeck_results.hir_owner); let common_hir_owner = fcx_typeck_results.hir_owner; - let mut errors_buffer = Vec::new(); - for (&local_id, c_ty) in fcx_typeck_results.user_provided_types().iter() { - let hir_id = hir::HirId { owner: common_hir_owner, local_id }; + if self.rustc_dump_user_substs { + let sorted_user_provided_types = + fcx_typeck_results.user_provided_types().items_in_stable_order(self.tcx()); - if cfg!(debug_assertions) && c_ty.needs_infer() { - span_bug!( - hir_id.to_span(self.fcx.tcx), - "writeback: `{:?}` has inference variables", - c_ty - ); - }; + let mut errors_buffer = Vec::new(); + for (&local_id, c_ty) in sorted_user_provided_types { + let hir_id = hir::HirId { owner: common_hir_owner, local_id }; - self.typeck_results.user_provided_types_mut().insert(hir_id, *c_ty); - - if let ty::UserType::TypeOf(_, user_substs) = c_ty.value { - if self.rustc_dump_user_substs { + if let ty::UserType::TypeOf(_, user_substs) = c_ty.value { // This is a unit-testing mechanism. let span = self.tcx().hir().span(hir_id); // We need to buffer the errors in order to guarantee a consistent @@ -504,31 +500,49 @@ impl<'cx, 'tcx> WritebackCx<'cx, 'tcx> { err.buffer(&mut errors_buffer); } } - } - if !errors_buffer.is_empty() { - errors_buffer.sort_by_key(|diag| diag.span.primary_span()); - for mut diag in errors_buffer { - self.tcx().sess.diagnostic().emit_diagnostic(&mut diag); + if !errors_buffer.is_empty() { + errors_buffer.sort_by_key(|diag| diag.span.primary_span()); + for mut diag in errors_buffer { + self.tcx().sess.diagnostic().emit_diagnostic(&mut diag); + } } } + + self.typeck_results.user_provided_types_mut().extend( + fcx_typeck_results.user_provided_types().items().map(|(local_id, c_ty)| { + let hir_id = hir::HirId { owner: common_hir_owner, local_id }; + + if cfg!(debug_assertions) && c_ty.needs_infer() { + span_bug!( + hir_id.to_span(self.fcx.tcx), + "writeback: `{:?}` has inference variables", + c_ty + ); + }; + + (hir_id, *c_ty) + }), + ); } fn visit_user_provided_sigs(&mut self) { let fcx_typeck_results = self.fcx.typeck_results.borrow(); assert_eq!(fcx_typeck_results.hir_owner, self.typeck_results.hir_owner); - for (&def_id, c_sig) in fcx_typeck_results.user_provided_sigs.iter() { - if cfg!(debug_assertions) && c_sig.needs_infer() { - span_bug!( - self.fcx.tcx.def_span(def_id), - "writeback: `{:?}` has inference variables", - c_sig - ); - }; + self.typeck_results.user_provided_sigs.extend( + fcx_typeck_results.user_provided_sigs.items().map(|(&def_id, c_sig)| { + if cfg!(debug_assertions) && c_sig.needs_infer() { + span_bug!( + self.fcx.tcx.def_span(def_id), + "writeback: `{:?}` has inference variables", + c_sig + ); + }; - self.typeck_results.user_provided_sigs.insert(def_id, *c_sig); - } + (def_id, *c_sig) + }), + ); } fn visit_generator_interior_types(&mut self) { @@ -647,7 +661,10 @@ impl<'cx, 'tcx> WritebackCx<'cx, 'tcx> { assert_eq!(fcx_typeck_results.hir_owner, self.typeck_results.hir_owner); let common_hir_owner = fcx_typeck_results.hir_owner; - for (&local_id, &fn_sig) in fcx_typeck_results.liberated_fn_sigs().iter() { + let fcx_liberated_fn_sigs = + fcx_typeck_results.liberated_fn_sigs().items_in_stable_order(self.tcx()); + + for (&local_id, &fn_sig) in fcx_liberated_fn_sigs { let hir_id = hir::HirId { owner: common_hir_owner, local_id }; let fn_sig = self.resolve(fn_sig, &hir_id); self.typeck_results.liberated_fn_sigs_mut().insert(hir_id, fn_sig); @@ -659,7 +676,10 @@ impl<'cx, 'tcx> WritebackCx<'cx, 'tcx> { assert_eq!(fcx_typeck_results.hir_owner, self.typeck_results.hir_owner); let common_hir_owner = fcx_typeck_results.hir_owner; - for (&local_id, ftys) in fcx_typeck_results.fru_field_types().iter() { + let fcx_fru_field_types = + fcx_typeck_results.fru_field_types().items_in_stable_order(self.tcx()); + + for (&local_id, ftys) in fcx_fru_field_types { let hir_id = hir::HirId { owner: common_hir_owner, local_id }; let ftys = self.resolve(ftys.clone(), &hir_id); self.typeck_results.fru_field_types_mut().insert(hir_id, ftys); diff --git a/compiler/rustc_lint_defs/src/lib.rs b/compiler/rustc_lint_defs/src/lib.rs index f4b4c5168bf..9aca485e502 100644 --- a/compiler/rustc_lint_defs/src/lib.rs +++ b/compiler/rustc_lint_defs/src/lib.rs @@ -6,8 +6,9 @@ extern crate rustc_macros; pub use self::Level::*; -use rustc_ast::node_id::{NodeId, NodeMap}; +use rustc_ast::node_id::NodeId; use rustc_ast::{AttrId, Attribute}; +use rustc_data_structures::fx::FxIndexMap; use rustc_data_structures::stable_hasher::{HashStable, StableHasher, ToStableHashKey}; use rustc_error_messages::{DiagnosticMessage, MultiSpan}; use rustc_hir::HashStableContext; @@ -544,7 +545,7 @@ pub struct BufferedEarlyLint { #[derive(Default)] pub struct LintBuffer { - pub map: NodeMap>, + pub map: FxIndexMap>, } impl LintBuffer { diff --git a/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs b/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs index cb451931dfe..78997961d17 100644 --- a/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs +++ b/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs @@ -382,7 +382,7 @@ pub(in crate::rmeta) fn provide(providers: &mut Providers) { // keys from the former. // This is a rudimentary check that does not catch all cases, // just the easiest. - let mut fallback_map: DefIdMap = Default::default(); + let mut fallback_map: Vec<(DefId, DefId)> = Default::default(); // Issue 46112: We want the map to prefer the shortest // paths when reporting the path to an item. Therefore we @@ -412,12 +412,12 @@ pub(in crate::rmeta) fn provide(providers: &mut Providers) { if let Some(def_id) = child.res.opt_def_id() { if child.ident.name == kw::Underscore { - fallback_map.insert(def_id, parent); + fallback_map.push((def_id, parent)); return; } if ty::util::is_doc_hidden(tcx, parent) { - fallback_map.insert(def_id, parent); + fallback_map.push((def_id, parent)); return; } @@ -451,6 +451,7 @@ pub(in crate::rmeta) fn provide(providers: &mut Providers) { // Fill in any missing entries with the less preferable path. // If this path re-exports the child as `_`, we still use this // path in a diagnostic that suggests importing `::*`. + for (child, parent) in fallback_map { visible_parent_map.entry(child).or_insert(parent); } diff --git a/compiler/rustc_metadata/src/rmeta/encoder.rs b/compiler/rustc_metadata/src/rmeta/encoder.rs index a3d44fa890d..c3292681cc6 100644 --- a/compiler/rustc_metadata/src/rmeta/encoder.rs +++ b/compiler/rustc_metadata/src/rmeta/encoder.rs @@ -1187,8 +1187,11 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { record!(self.tables.trait_impl_trait_tys[def_id] <- table); } } - let inherent_impls = tcx.crate_inherent_impls(()); - for (def_id, implementations) in inherent_impls.inherent_impls.iter() { + let inherent_impls = tcx.with_stable_hashing_context(|hcx| { + tcx.crate_inherent_impls(()).inherent_impls.to_sorted(&hcx) + }); + + for (def_id, implementations) in inherent_impls { if implementations.is_empty() { continue; } diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs index d681df14af1..7dfcd1bb507 100644 --- a/compiler/rustc_middle/src/ty/mod.rs +++ b/compiler/rustc_middle/src/ty/mod.rs @@ -38,7 +38,7 @@ use rustc_data_structures::stable_hasher::{HashStable, StableHasher}; use rustc_data_structures::tagged_ptr::CopyTaggedPtr; use rustc_hir as hir; use rustc_hir::def::{CtorKind, CtorOf, DefKind, LifetimeRes, Res}; -use rustc_hir::def_id::{CrateNum, DefId, LocalDefId, LocalDefIdMap}; +use rustc_hir::def_id::{CrateNum, DefId, DefIdMap, LocalDefId, LocalDefIdMap}; use rustc_hir::Node; use rustc_index::vec::IndexVec; use rustc_macros::HashStable; @@ -436,7 +436,7 @@ pub struct CrateVariancesMap<'tcx> { /// For each item with generics, maps to a vector of the variance /// of its generics. If an item has no generics, it will have no /// entry. - pub variances: FxHashMap, + pub variances: DefIdMap<&'tcx [ty::Variance]>, } // Contains information needed to resolve types and (in the future) look up diff --git a/compiler/rustc_middle/src/ty/typeck_results.rs b/compiler/rustc_middle/src/ty/typeck_results.rs index 18281b5175c..0eaa47178c0 100644 --- a/compiler/rustc_middle/src/ty/typeck_results.rs +++ b/compiler/rustc_middle/src/ty/typeck_results.rs @@ -6,7 +6,12 @@ use crate::{ GenericArgKind, InternalSubsts, SubstsRef, Ty, UserSubsts, }, }; -use rustc_data_structures::{fx::FxHashMap, sync::Lrc, unord::UnordSet, vec_map::VecMap}; +use rustc_data_structures::{ + fx::FxHashMap, + sync::Lrc, + unord::{UnordItems, UnordSet}, + vec_map::VecMap, +}; use rustc_errors::ErrorGuaranteed; use rustc_hir as hir; use rustc_hir::{ @@ -20,13 +25,9 @@ use rustc_macros::HashStable; use rustc_middle::mir::FakeReadCause; use rustc_session::Session; use rustc_span::Span; -use std::{ - collections::hash_map::{self, Entry}, - hash::Hash, - iter, -}; +use std::{collections::hash_map::Entry, hash::Hash, iter}; -use super::RvalueScopes; +use super::{RvalueScopes, TyCtxt}; #[derive(TyEncodable, TyDecodable, Debug, HashStable)] pub struct TypeckResults<'tcx> { @@ -567,8 +568,16 @@ impl<'a, V> LocalTableInContext<'a, V> { self.data.get(&id.local_id) } - pub fn iter(&self) -> hash_map::Iter<'_, hir::ItemLocalId, V> { - self.data.iter() + pub fn items( + &'a self, + ) -> UnordItems<(hir::ItemLocalId, &'a V), impl Iterator> + { + self.data.items().map(|(id, value)| (*id, value)) + } + + #[allow(rustc::pass_by_value)] + pub fn items_in_stable_order(&self, tcx: TyCtxt<'_>) -> Vec<(&'a ItemLocalId, &'a V)> { + tcx.with_stable_hashing_context(|hcx| self.data.to_sorted(&hcx)) } } @@ -605,6 +614,16 @@ impl<'a, V> LocalTableInContextMut<'a, V> { validate_hir_id_for_typeck_results(self.hir_owner, id); self.data.remove(&id.local_id) } + + pub fn extend( + &mut self, + items: UnordItems<(hir::HirId, V), impl Iterator>, + ) { + self.data.extend(items.map(|(id, value)| { + validate_hir_id_for_typeck_results(self.hir_owner, id); + (id.local_id, value) + })) + } } rustc_index::newtype_index! { diff --git a/compiler/rustc_resolve/src/check_unused.rs b/compiler/rustc_resolve/src/check_unused.rs index 32fb5e18276..eae4c9992eb 100644 --- a/compiler/rustc_resolve/src/check_unused.rs +++ b/compiler/rustc_resolve/src/check_unused.rs @@ -28,9 +28,9 @@ use crate::module_to_string; use crate::Resolver; use rustc_ast as ast; -use rustc_ast::node_id::NodeMap; use rustc_ast::visit::{self, Visitor}; -use rustc_data_structures::fx::FxHashSet; +use rustc_data_structures::fx::FxIndexMap; +use rustc_data_structures::unord::UnordSet; use rustc_errors::{pluralize, MultiSpan}; use rustc_session::lint::builtin::{MACRO_USE_EXTERN_CRATE, UNUSED_IMPORTS}; use rustc_session::lint::BuiltinLintDiagnostics; @@ -40,7 +40,7 @@ struct UnusedImport<'a> { use_tree: &'a ast::UseTree, use_tree_id: ast::NodeId, item_span: Span, - unused: FxHashSet, + unused: UnordSet, } impl<'a> UnusedImport<'a> { @@ -52,7 +52,7 @@ impl<'a> UnusedImport<'a> { struct UnusedImportCheckVisitor<'a, 'b> { r: &'a mut Resolver<'b>, /// All the (so far) unused imports, grouped path list - unused_imports: NodeMap>, + unused_imports: FxIndexMap>, base_use_tree: Option<&'a ast::UseTree>, base_id: ast::NodeId, item_span: Span, @@ -89,7 +89,7 @@ impl<'a, 'b> UnusedImportCheckVisitor<'a, 'b> { use_tree, use_tree_id, item_span, - unused: FxHashSet::default(), + unused: Default::default(), }) } } diff --git a/src/tools/clippy/clippy_lints/src/inherent_impl.rs b/src/tools/clippy/clippy_lints/src/inherent_impl.rs index c5abcc46254..81b37ce5dfc 100644 --- a/src/tools/clippy/clippy_lints/src/inherent_impl.rs +++ b/src/tools/clippy/clippy_lints/src/inherent_impl.rs @@ -52,21 +52,19 @@ impl<'tcx> LateLintPass<'tcx> for MultipleInherentImpl { // List of spans to lint. (lint_span, first_span) let mut lint_spans = Vec::new(); - for (_, impl_ids) in cx + let inherent_impls = cx .tcx - .crate_inherent_impls(()) - .inherent_impls - .iter() - .filter(|(&id, impls)| { - impls.len() > 1 - // Check for `#[allow]` on the type definition - && !is_lint_allowed( - cx, - MULTIPLE_INHERENT_IMPL, - cx.tcx.hir().local_def_id_to_hir_id(id), - ) - }) - { + .with_stable_hashing_context(|hcx| cx.tcx.crate_inherent_impls(()).inherent_impls.to_sorted(&hcx)); + + for (_, impl_ids) in inherent_impls.into_iter().filter(|(&id, impls)| { + impls.len() > 1 + // Check for `#[allow]` on the type definition + && !is_lint_allowed( + cx, + MULTIPLE_INHERENT_IMPL, + cx.tcx.hir().local_def_id_to_hir_id(id), + ) + }) { for impl_id in impl_ids.iter().map(|id| id.expect_local()) { match type_map.entry(cx.tcx.type_of(impl_id)) { Entry::Vacant(e) => { diff --git a/src/tools/clippy/clippy_lints/src/loops/while_immutable_condition.rs b/src/tools/clippy/clippy_lints/src/loops/while_immutable_condition.rs index a63422d2a36..d1a1f773f87 100644 --- a/src/tools/clippy/clippy_lints/src/loops/while_immutable_condition.rs +++ b/src/tools/clippy/clippy_lints/src/loops/while_immutable_condition.rs @@ -35,7 +35,7 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, cond: &'tcx Expr<'_>, expr: &' } else { return; }; - let mutable_static_in_cond = var_visitor.def_ids.iter().any(|(_, v)| *v); + let mutable_static_in_cond = var_visitor.def_ids.items().any(|(_, v)| *v); let mut has_break_or_return_visitor = HasBreakOrReturnVisitor { has_break_or_return: false, diff --git a/src/tools/clippy/clippy_lints/src/missing_trait_methods.rs b/src/tools/clippy/clippy_lints/src/missing_trait_methods.rs index 68af8a672f6..1c61c6e551c 100644 --- a/src/tools/clippy/clippy_lints/src/missing_trait_methods.rs +++ b/src/tools/clippy/clippy_lints/src/missing_trait_methods.rs @@ -80,19 +80,21 @@ impl<'tcx> LateLintPass<'tcx> for MissingTraitMethods { } } - for assoc in provided.values() { - let source_map = cx.tcx.sess.source_map(); - let definition_span = source_map.guess_head_span(cx.tcx.def_span(assoc.def_id)); + cx.tcx.with_stable_hashing_context(|hcx| { + for assoc in provided.values_sorted(&hcx) { + let source_map = cx.tcx.sess.source_map(); + let definition_span = source_map.guess_head_span(cx.tcx.def_span(assoc.def_id)); - span_lint_and_help( - cx, - MISSING_TRAIT_METHODS, - source_map.guess_head_span(item.span), - &format!("missing trait method provided by default: `{}`", assoc.name), - Some(definition_span), - "implement the method", - ); - } + span_lint_and_help( + cx, + MISSING_TRAIT_METHODS, + source_map.guess_head_span(item.span), + &format!("missing trait method provided by default: `{}`", assoc.name), + Some(definition_span), + "implement the method", + ); + } + }) } } } diff --git a/src/tools/clippy/clippy_lints/src/pass_by_ref_or_value.rs b/src/tools/clippy/clippy_lints/src/pass_by_ref_or_value.rs index 870a1c7d88d..2d21aaa4f7f 100644 --- a/src/tools/clippy/clippy_lints/src/pass_by_ref_or_value.rs +++ b/src/tools/clippy/clippy_lints/src/pass_by_ref_or_value.rs @@ -190,10 +190,10 @@ impl<'tcx> PassByRefOrValue { // Don't lint if an unsafe pointer is created. // TODO: Limit the check only to unsafe pointers to the argument (or part of the argument) // which escape the current function. - if typeck.node_types().iter().any(|(_, &ty)| ty.is_unsafe_ptr()) + if typeck.node_types().items().any(|(_, &ty)| ty.is_unsafe_ptr()) || typeck .adjustments() - .iter() + .items() .flat_map(|(_, a)| a) .any(|a| matches!(a.kind, Adjust::Pointer(PointerCast::UnsafeFnPointer))) { From 72ee14ce3960ca02ba4f4a19b84bf9c27ec6de9d Mon Sep 17 00:00:00 2001 From: Michael Woerister Date: Wed, 18 Jan 2023 10:47:31 +0100 Subject: [PATCH 3/4] Allow for more efficient sorting when exporting Unord collections. --- .../src/back/symbol_export.rs | 2 +- compiler/rustc_data_structures/src/unord.rs | 87 +++++++++++++++++-- compiler/rustc_hir_typeck/src/writeback.rs | 31 +++---- compiler/rustc_metadata/src/rmeta/encoder.rs | 2 +- .../rustc_middle/src/ty/typeck_results.rs | 7 +- .../clippy/clippy_lints/src/inherent_impl.rs | 2 +- .../clippy_lints/src/missing_trait_methods.rs | 2 +- 7 files changed, 99 insertions(+), 34 deletions(-) diff --git a/compiler/rustc_codegen_ssa/src/back/symbol_export.rs b/compiler/rustc_codegen_ssa/src/back/symbol_export.rs index b442483346d..57a99e74c21 100644 --- a/compiler/rustc_codegen_ssa/src/back/symbol_export.rs +++ b/compiler/rustc_codegen_ssa/src/back/symbol_export.rs @@ -177,7 +177,7 @@ fn exported_symbols_provider_local( // Can we skip the later sorting? let mut symbols: Vec<_> = tcx.with_stable_hashing_context(|hcx| { tcx.reachable_non_generics(LOCAL_CRATE) - .to_sorted(&hcx) + .to_sorted(&hcx, true) .into_iter() .map(|(&def_id, &info)| (ExportedSymbol::NonGeneric(def_id), info)) .collect() diff --git a/compiler/rustc_data_structures/src/unord.rs b/compiler/rustc_data_structures/src/unord.rs index 1e71629a7c4..d29b4987274 100644 --- a/compiler/rustc_data_structures/src/unord.rs +++ b/compiler/rustc_data_structures/src/unord.rs @@ -14,7 +14,7 @@ use std::{ use crate::{ fingerprint::Fingerprint, - stable_hasher::{HashStable, StableHasher, ToStableHashKey}, + stable_hasher::{HashStable, StableHasher, StableOrd, ToStableHashKey}, }; /// `UnordItems` is the order-less version of `Iterator`. It only contains methods @@ -158,6 +158,7 @@ pub struct UnordSet { } impl Default for UnordSet { + #[inline] fn default() -> Self { Self { inner: FxHashSet::default() } } @@ -207,6 +208,46 @@ impl UnordSet { UnordItems(self.inner.into_iter()) } + #[inline] + pub fn to_sorted(&self, hcx: &HCX, cache_sort_key: bool) -> Vec<&V> + where + V: ToStableHashKey, + { + let mut items: Vec<&V> = self.inner.iter().collect(); + if cache_sort_key { + items.sort_by_cached_key(|k| k.to_stable_hash_key(hcx)); + } else { + items.sort_unstable_by_key(|k| k.to_stable_hash_key(hcx)); + } + + items + } + + #[inline] + pub fn to_sorted_stable_ord(&self) -> Vec + where + V: Ord + StableOrd + Copy, + { + let mut items: Vec = self.inner.iter().copied().collect(); + items.sort_unstable(); + items + } + + #[inline] + pub fn into_sorted(self, hcx: &HCX, cache_sort_key: bool) -> Vec + where + V: ToStableHashKey, + { + let mut items: Vec = self.inner.into_iter().collect(); + if cache_sort_key { + items.sort_by_cached_key(|k| k.to_stable_hash_key(hcx)); + } else { + items.sort_unstable_by_key(|k| k.to_stable_hash_key(hcx)); + } + + items + } + // We can safely extend this UnordSet from a set of unordered values because that // won't expose the internal ordering anywhere. #[inline] @@ -221,12 +262,14 @@ impl UnordSet { } impl Extend for UnordSet { + #[inline] fn extend>(&mut self, iter: T) { self.inner.extend(iter) } } impl FromIterator for UnordSet { + #[inline] fn from_iter>(iter: T) -> Self { UnordSet { inner: FxHashSet::from_iter(iter) } } @@ -254,24 +297,28 @@ pub struct UnordMap { } impl Default for UnordMap { + #[inline] fn default() -> Self { Self { inner: FxHashMap::default() } } } impl Extend<(K, V)> for UnordMap { + #[inline] fn extend>(&mut self, iter: T) { self.inner.extend(iter) } } impl FromIterator<(K, V)> for UnordMap { + #[inline] fn from_iter>(iter: T) -> Self { UnordMap { inner: FxHashMap::from_iter(iter) } } } impl> From> for UnordMap { + #[inline] fn from(items: UnordItems<(K, V), I>) -> Self { UnordMap { inner: FxHashMap::from_iter(items.0) } } @@ -351,30 +398,56 @@ impl UnordMap { self.inner.extend(items.0) } - pub fn to_sorted(&self, hcx: &HCX) -> Vec<(&K, &V)> + #[inline] + pub fn to_sorted(&self, hcx: &HCX, cache_sort_key: bool) -> Vec<(&K, &V)> where K: ToStableHashKey, { let mut items: Vec<(&K, &V)> = self.inner.iter().collect(); - items.sort_by_cached_key(|(k, _)| k.to_stable_hash_key(hcx)); + if cache_sort_key { + items.sort_by_cached_key(|(k, _)| k.to_stable_hash_key(hcx)); + } else { + items.sort_unstable_by_key(|(k, _)| k.to_stable_hash_key(hcx)); + } + items } - pub fn into_sorted(self, hcx: &HCX) -> Vec<(K, V)> + #[inline] + pub fn to_sorted_stable_ord(&self) -> Vec<(K, &V)> + where + K: Ord + StableOrd + Copy, + { + let mut items: Vec<(K, &V)> = self.inner.iter().map(|(&k, v)| (k, v)).collect(); + items.sort_unstable_by_key(|&(k, _)| k); + items + } + + #[inline] + pub fn into_sorted(self, hcx: &HCX, cache_sort_key: bool) -> Vec<(K, V)> where K: ToStableHashKey, { let mut items: Vec<(K, V)> = self.inner.into_iter().collect(); - items.sort_by_cached_key(|(k, _)| k.to_stable_hash_key(hcx)); + if cache_sort_key { + items.sort_by_cached_key(|(k, _)| k.to_stable_hash_key(hcx)); + } else { + items.sort_unstable_by_key(|(k, _)| k.to_stable_hash_key(hcx)); + } items } - pub fn values_sorted(&self, hcx: &HCX) -> impl Iterator + #[inline] + pub fn values_sorted(&self, hcx: &HCX, cache_sort_key: bool) -> impl Iterator where K: ToStableHashKey, { let mut items: Vec<(&K, &V)> = self.inner.iter().collect(); - items.sort_by_cached_key(|(k, _)| k.to_stable_hash_key(hcx)); + if cache_sort_key { + items.sort_by_cached_key(|(k, _)| k.to_stable_hash_key(hcx)); + } else { + items.sort_unstable_by_key(|(k, _)| k.to_stable_hash_key(hcx)); + } items.into_iter().map(|(_, v)| v) } } diff --git a/compiler/rustc_hir_typeck/src/writeback.rs b/compiler/rustc_hir_typeck/src/writeback.rs index 6e6b63beca2..250f4cd3f65 100644 --- a/compiler/rustc_hir_typeck/src/writeback.rs +++ b/compiler/rustc_hir_typeck/src/writeback.rs @@ -19,7 +19,6 @@ use rustc_middle::ty::TypeckResults; use rustc_middle::ty::{self, ClosureSizeProfileData, Ty, TyCtxt}; use rustc_span::symbol::sym; use rustc_span::Span; -use smallvec::SmallVec; use std::mem; use std::ops::ControlFlow; @@ -450,9 +449,9 @@ impl<'cx, 'tcx> WritebackCx<'cx, 'tcx> { let common_hir_owner = fcx_typeck_results.hir_owner; let fcx_closure_kind_origins = - fcx_typeck_results.closure_kind_origins().items_in_stable_order(self.tcx()); + fcx_typeck_results.closure_kind_origins().items_in_stable_order(); - for (&local_id, origin) in fcx_closure_kind_origins { + for (local_id, origin) in fcx_closure_kind_origins { let hir_id = hir::HirId { owner: common_hir_owner, local_id }; let place_span = origin.0; let place = self.resolve(origin.1.clone(), &place_span); @@ -465,14 +464,10 @@ impl<'cx, 'tcx> WritebackCx<'cx, 'tcx> { assert_eq!(fcx_typeck_results.hir_owner, self.typeck_results.hir_owner); - self.tcx().with_stable_hashing_context(|hcx| { - let fcx_coercion_casts: SmallVec<[_; 32]> = - fcx_typeck_results.coercion_casts().items().cloned().into_sorted_small_vec(&hcx); - - for local_id in fcx_coercion_casts { - self.typeck_results.set_coercion_cast(local_id); - } - }); + let fcx_coercion_casts = fcx_typeck_results.coercion_casts().to_sorted_stable_ord(); + for local_id in fcx_coercion_casts { + self.typeck_results.set_coercion_cast(local_id); + } } fn visit_user_provided_tys(&mut self) { @@ -482,10 +477,10 @@ impl<'cx, 'tcx> WritebackCx<'cx, 'tcx> { if self.rustc_dump_user_substs { let sorted_user_provided_types = - fcx_typeck_results.user_provided_types().items_in_stable_order(self.tcx()); + fcx_typeck_results.user_provided_types().items_in_stable_order(); let mut errors_buffer = Vec::new(); - for (&local_id, c_ty) in sorted_user_provided_types { + for (local_id, c_ty) in sorted_user_provided_types { let hir_id = hir::HirId { owner: common_hir_owner, local_id }; if let ty::UserType::TypeOf(_, user_substs) = c_ty.value { @@ -661,10 +656,9 @@ impl<'cx, 'tcx> WritebackCx<'cx, 'tcx> { assert_eq!(fcx_typeck_results.hir_owner, self.typeck_results.hir_owner); let common_hir_owner = fcx_typeck_results.hir_owner; - let fcx_liberated_fn_sigs = - fcx_typeck_results.liberated_fn_sigs().items_in_stable_order(self.tcx()); + let fcx_liberated_fn_sigs = fcx_typeck_results.liberated_fn_sigs().items_in_stable_order(); - for (&local_id, &fn_sig) in fcx_liberated_fn_sigs { + for (local_id, &fn_sig) in fcx_liberated_fn_sigs { let hir_id = hir::HirId { owner: common_hir_owner, local_id }; let fn_sig = self.resolve(fn_sig, &hir_id); self.typeck_results.liberated_fn_sigs_mut().insert(hir_id, fn_sig); @@ -676,10 +670,9 @@ impl<'cx, 'tcx> WritebackCx<'cx, 'tcx> { assert_eq!(fcx_typeck_results.hir_owner, self.typeck_results.hir_owner); let common_hir_owner = fcx_typeck_results.hir_owner; - let fcx_fru_field_types = - fcx_typeck_results.fru_field_types().items_in_stable_order(self.tcx()); + let fcx_fru_field_types = fcx_typeck_results.fru_field_types().items_in_stable_order(); - for (&local_id, ftys) in fcx_fru_field_types { + for (local_id, ftys) in fcx_fru_field_types { let hir_id = hir::HirId { owner: common_hir_owner, local_id }; let ftys = self.resolve(ftys.clone(), &hir_id); self.typeck_results.fru_field_types_mut().insert(hir_id, ftys); diff --git a/compiler/rustc_metadata/src/rmeta/encoder.rs b/compiler/rustc_metadata/src/rmeta/encoder.rs index c3292681cc6..5b6f327c5c2 100644 --- a/compiler/rustc_metadata/src/rmeta/encoder.rs +++ b/compiler/rustc_metadata/src/rmeta/encoder.rs @@ -1188,7 +1188,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { } } let inherent_impls = tcx.with_stable_hashing_context(|hcx| { - tcx.crate_inherent_impls(()).inherent_impls.to_sorted(&hcx) + tcx.crate_inherent_impls(()).inherent_impls.to_sorted(&hcx, true) }); for (def_id, implementations) in inherent_impls { diff --git a/compiler/rustc_middle/src/ty/typeck_results.rs b/compiler/rustc_middle/src/ty/typeck_results.rs index 0eaa47178c0..2902c6dc556 100644 --- a/compiler/rustc_middle/src/ty/typeck_results.rs +++ b/compiler/rustc_middle/src/ty/typeck_results.rs @@ -27,7 +27,7 @@ use rustc_session::Session; use rustc_span::Span; use std::{collections::hash_map::Entry, hash::Hash, iter}; -use super::{RvalueScopes, TyCtxt}; +use super::RvalueScopes; #[derive(TyEncodable, TyDecodable, Debug, HashStable)] pub struct TypeckResults<'tcx> { @@ -575,9 +575,8 @@ impl<'a, V> LocalTableInContext<'a, V> { self.data.items().map(|(id, value)| (*id, value)) } - #[allow(rustc::pass_by_value)] - pub fn items_in_stable_order(&self, tcx: TyCtxt<'_>) -> Vec<(&'a ItemLocalId, &'a V)> { - tcx.with_stable_hashing_context(|hcx| self.data.to_sorted(&hcx)) + pub fn items_in_stable_order(&self) -> Vec<(ItemLocalId, &'a V)> { + self.data.to_sorted_stable_ord() } } diff --git a/src/tools/clippy/clippy_lints/src/inherent_impl.rs b/src/tools/clippy/clippy_lints/src/inherent_impl.rs index 81b37ce5dfc..e9b2e31a769 100644 --- a/src/tools/clippy/clippy_lints/src/inherent_impl.rs +++ b/src/tools/clippy/clippy_lints/src/inherent_impl.rs @@ -54,7 +54,7 @@ impl<'tcx> LateLintPass<'tcx> for MultipleInherentImpl { let inherent_impls = cx .tcx - .with_stable_hashing_context(|hcx| cx.tcx.crate_inherent_impls(()).inherent_impls.to_sorted(&hcx)); + .with_stable_hashing_context(|hcx| cx.tcx.crate_inherent_impls(()).inherent_impls.to_sorted(&hcx, true)); for (_, impl_ids) in inherent_impls.into_iter().filter(|(&id, impls)| { impls.len() > 1 diff --git a/src/tools/clippy/clippy_lints/src/missing_trait_methods.rs b/src/tools/clippy/clippy_lints/src/missing_trait_methods.rs index 1c61c6e551c..3371b4cce32 100644 --- a/src/tools/clippy/clippy_lints/src/missing_trait_methods.rs +++ b/src/tools/clippy/clippy_lints/src/missing_trait_methods.rs @@ -81,7 +81,7 @@ impl<'tcx> LateLintPass<'tcx> for MissingTraitMethods { } cx.tcx.with_stable_hashing_context(|hcx| { - for assoc in provided.values_sorted(&hcx) { + for assoc in provided.values_sorted(&hcx, true) { let source_map = cx.tcx.sess.source_map(); let definition_span = source_map.guess_head_span(cx.tcx.def_span(assoc.def_id)); From f219771961c94f218d23bfab66aa678c48840fc4 Mon Sep 17 00:00:00 2001 From: Michael Woerister Date: Thu, 19 Jan 2023 17:37:59 +0100 Subject: [PATCH 4/4] Clean up and document unord collections a bit. --- compiler/rustc_data_structures/src/unord.rs | 104 +++++++++++++------- 1 file changed, 66 insertions(+), 38 deletions(-) diff --git a/compiler/rustc_data_structures/src/unord.rs b/compiler/rustc_data_structures/src/unord.rs index d29b4987274..f35f18e51cb 100644 --- a/compiler/rustc_data_structures/src/unord.rs +++ b/compiler/rustc_data_structures/src/unord.rs @@ -208,21 +208,24 @@ impl UnordSet { UnordItems(self.inner.into_iter()) } + /// Returns the items of this set in stable sort order (as defined by `ToStableHashKey`). + /// + /// The `cache_sort_key` parameter controls if [slice::sort_by_cached_key] or + /// [slice::sort_unstable_by_key] will be used for sorting the vec. Use + /// `cache_sort_key` when the [ToStableHashKey::to_stable_hash_key] implementation + /// for `V` is expensive (e.g. a `DefId -> DefPathHash` lookup). #[inline] pub fn to_sorted(&self, hcx: &HCX, cache_sort_key: bool) -> Vec<&V> where V: ToStableHashKey, { - let mut items: Vec<&V> = self.inner.iter().collect(); - if cache_sort_key { - items.sort_by_cached_key(|k| k.to_stable_hash_key(hcx)); - } else { - items.sort_unstable_by_key(|k| k.to_stable_hash_key(hcx)); - } - - items + to_sorted_vec(hcx, self.inner.iter(), cache_sort_key, |&x| x) } + /// Returns the items of this set in stable sort order (as defined by + /// `StableOrd`). This method is much more efficient than + /// `into_sorted` because it does not need to transform keys to their + /// `ToStableHashKey` equivalent. #[inline] pub fn to_sorted_stable_ord(&self) -> Vec where @@ -233,19 +236,18 @@ impl UnordSet { items } + /// Returns the items of this set in stable sort order (as defined by `ToStableHashKey`). + /// + /// The `cache_sort_key` parameter controls if [slice::sort_by_cached_key] or + /// [slice::sort_unstable_by_key] will be used for sorting the vec. Use + /// `cache_sort_key` when the [ToStableHashKey::to_stable_hash_key] implementation + /// for `V` is expensive (e.g. a `DefId -> DefPathHash` lookup). #[inline] pub fn into_sorted(self, hcx: &HCX, cache_sort_key: bool) -> Vec where V: ToStableHashKey, { - let mut items: Vec = self.inner.into_iter().collect(); - if cache_sort_key { - items.sort_by_cached_key(|k| k.to_stable_hash_key(hcx)); - } else { - items.sort_unstable_by_key(|k| k.to_stable_hash_key(hcx)); - } - - items + to_sorted_vec(hcx, self.inner.into_iter(), cache_sort_key, |x| x) } // We can safely extend this UnordSet from a set of unordered values because that @@ -398,21 +400,23 @@ impl UnordMap { self.inner.extend(items.0) } + /// Returns the entries of this map in stable sort order (as defined by `ToStableHashKey`). + /// + /// The `cache_sort_key` parameter controls if [slice::sort_by_cached_key] or + /// [slice::sort_unstable_by_key] will be used for sorting the vec. Use + /// `cache_sort_key` when the [ToStableHashKey::to_stable_hash_key] implementation + /// for `K` is expensive (e.g. a `DefId -> DefPathHash` lookup). #[inline] pub fn to_sorted(&self, hcx: &HCX, cache_sort_key: bool) -> Vec<(&K, &V)> where K: ToStableHashKey, { - let mut items: Vec<(&K, &V)> = self.inner.iter().collect(); - if cache_sort_key { - items.sort_by_cached_key(|(k, _)| k.to_stable_hash_key(hcx)); - } else { - items.sort_unstable_by_key(|(k, _)| k.to_stable_hash_key(hcx)); - } - - items + to_sorted_vec(hcx, self.inner.iter(), cache_sort_key, |&(k, _)| k) } + /// Returns the entries of this map in stable sort order (as defined by `StableOrd`). + /// This method can be much more efficient than `into_sorted` because it does not need + /// to transform keys to their `ToStableHashKey` equivalent. #[inline] pub fn to_sorted_stable_ord(&self) -> Vec<(K, &V)> where @@ -423,32 +427,35 @@ impl UnordMap { items } + /// Returns the entries of this map in stable sort order (as defined by `ToStableHashKey`). + /// + /// The `cache_sort_key` parameter controls if [slice::sort_by_cached_key] or + /// [slice::sort_unstable_by_key] will be used for sorting the vec. Use + /// `cache_sort_key` when the [ToStableHashKey::to_stable_hash_key] implementation + /// for `K` is expensive (e.g. a `DefId -> DefPathHash` lookup). #[inline] pub fn into_sorted(self, hcx: &HCX, cache_sort_key: bool) -> Vec<(K, V)> where K: ToStableHashKey, { - let mut items: Vec<(K, V)> = self.inner.into_iter().collect(); - if cache_sort_key { - items.sort_by_cached_key(|(k, _)| k.to_stable_hash_key(hcx)); - } else { - items.sort_unstable_by_key(|(k, _)| k.to_stable_hash_key(hcx)); - } - items + to_sorted_vec(hcx, self.inner.into_iter(), cache_sort_key, |(k, _)| k) } + /// Returns the values of this map in stable sort order (as defined by K's + /// `ToStableHashKey` implementation). + /// + /// The `cache_sort_key` parameter controls if [slice::sort_by_cached_key] or + /// [slice::sort_unstable_by_key] will be used for sorting the vec. Use + /// `cache_sort_key` when the [ToStableHashKey::to_stable_hash_key] implementation + /// for `K` is expensive (e.g. a `DefId -> DefPathHash` lookup). #[inline] pub fn values_sorted(&self, hcx: &HCX, cache_sort_key: bool) -> impl Iterator where K: ToStableHashKey, { - let mut items: Vec<(&K, &V)> = self.inner.iter().collect(); - if cache_sort_key { - items.sort_by_cached_key(|(k, _)| k.to_stable_hash_key(hcx)); - } else { - items.sort_unstable_by_key(|(k, _)| k.to_stable_hash_key(hcx)); - } - items.into_iter().map(|(_, v)| v) + to_sorted_vec(hcx, self.inner.iter(), cache_sort_key, |&(k, _)| k) + .into_iter() + .map(|(_, v)| v) } } @@ -540,6 +547,27 @@ impl> HashStable for UnordBag { } } +#[inline] +fn to_sorted_vec( + hcx: &HCX, + iter: I, + cache_sort_key: bool, + extract_key: fn(&T) -> &K, +) -> Vec +where + I: Iterator, + K: ToStableHashKey, +{ + let mut items: Vec = iter.collect(); + if cache_sort_key { + items.sort_by_cached_key(|x| extract_key(x).to_stable_hash_key(hcx)); + } else { + items.sort_unstable_by_key(|x| extract_key(x).to_stable_hash_key(hcx)); + } + + items +} + fn hash_iter_order_independent< HCX, T: HashStable,