Use UnordMap instead of FxHashMap in define_id_collections!().

This commit is contained in:
Michael Woerister 2023-01-17 12:05:01 +01:00
parent 8a1de57a4a
commit c3d2573120
15 changed files with 253 additions and 102 deletions

View File

@ -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 =

View File

@ -11,7 +11,7 @@
#[macro_export]
macro_rules! define_id_collections {
($map_name:ident, $set_name:ident, $entry_name:ident, $key:ty) => {
pub type $map_name<T> = $crate::fx::FxHashMap<$key, T>;
pub type $map_name<T> = $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>;
};

View File

@ -6,8 +6,10 @@
use smallvec::SmallVec;
use std::{
borrow::Borrow,
collections::hash_map::Entry,
hash::Hash,
iter::{Product, Sum},
ops::Index,
};
use crate::{
@ -187,7 +189,16 @@ pub fn contains<Q: ?Sized>(&self, v: &Q) -> bool
}
#[inline]
pub fn items(&self) -> UnordItems<&V, impl Iterator<Item = &V>> {
pub fn remove<Q: ?Sized>(&mut self, k: &Q) -> bool
where
V: Borrow<Q>,
Q: Hash + Eq,
{
self.inner.remove(k)
}
#[inline]
pub fn items<'a>(&'a self) -> UnordItems<&'a V, impl Iterator<Item = &'a V>> {
UnordItems(self.inner.iter())
}
@ -254,6 +265,18 @@ fn extend<T: IntoIterator<Item = (K, V)>>(&mut self, iter: T) {
}
}
impl<K: Hash + Eq, V> FromIterator<(K, V)> for UnordMap<K, V> {
fn from_iter<T: IntoIterator<Item = (K, V)>>(iter: T) -> Self {
UnordMap { inner: FxHashMap::from_iter(iter) }
}
}
impl<K: Hash + Eq, V, I: Iterator<Item = (K, V)>> From<UnordItems<(K, V), I>> for UnordMap<K, V> {
fn from(items: UnordItems<(K, V), I>) -> Self {
UnordMap { inner: FxHashMap::from_iter(items.0) }
}
}
impl<K: Eq + Hash, V> UnordMap<K, V> {
#[inline]
pub fn len(&self) -> usize {
@ -275,7 +298,44 @@ pub fn contains_key<Q: ?Sized>(&self, k: &Q) -> bool
}
#[inline]
pub fn items(&self) -> UnordItems<(&K, &V), impl Iterator<Item = (&K, &V)>> {
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<Q: ?Sized>(&self, k: &Q) -> Option<&V>
where
K: Borrow<Q>,
Q: Hash + Eq,
{
self.inner.get(k)
}
#[inline]
pub fn get_mut<Q: ?Sized>(&mut self, k: &Q) -> Option<&mut V>
where
K: Borrow<Q>,
Q: Hash + Eq,
{
self.inner.get_mut(k)
}
#[inline]
pub fn remove<Q: ?Sized>(&mut self, k: &Q) -> Option<V>
where
K: Borrow<Q>,
Q: Hash + Eq,
{
self.inner.remove(k)
}
#[inline]
pub fn items<'a>(&'a self) -> UnordItems<(&'a K, &'a V), impl Iterator<Item = (&'a K, &'a V)>> {
UnordItems(self.inner.iter())
}
@ -290,6 +350,46 @@ pub fn into_items(self) -> UnordItems<(K, V), impl Iterator<Item = (K, V)>> {
pub fn extend<I: Iterator<Item = (K, V)>>(&mut self, items: UnordItems<(K, V), I>) {
self.inner.extend(items.0)
}
pub fn to_sorted<HCX>(&self, hcx: &HCX) -> Vec<(&K, &V)>
where
K: ToStableHashKey<HCX>,
{
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<HCX>(self, hcx: &HCX) -> Vec<(K, V)>
where
K: ToStableHashKey<HCX>,
{
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<HCX>(&self, hcx: &HCX) -> impl Iterator<Item = &V>
where
K: ToStableHashKey<HCX>,
{
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<K, Q: ?Sized, V> Index<&Q> for UnordMap<K, V>
where
K: Eq + Hash + Borrow<Q>,
Q: Eq + Hash,
{
type Output = V;
#[inline]
fn index(&self, key: &Q) -> &V {
&self.inner[key]
}
}
impl<HCX, K: Hash + Eq + HashStable<HCX>, V: HashStable<HCX>> HashStable<HCX> for UnordMap<K, V> {
@ -354,6 +454,12 @@ fn extend<I: IntoIterator<Item = T>>(&mut self, iter: I) {
}
}
impl<T, I: Iterator<Item = T>> From<UnordItems<T, I>> for UnordBag<T> {
fn from(value: UnordItems<T, I>) -> Self {
UnordBag { inner: Vec::from_iter(value.0) }
}
}
impl<HCX, V: Hash + Eq + HashStable<HCX>> HashStable<HCX> for UnordBag<V> {
#[inline]
fn hash_stable(&self, hcx: &mut HCX, hasher: &mut StableHasher) {

View File

@ -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 @@ fn enforce_const_invariance(&self, generics: &ty::Generics, variances: &mut [ty:
}
}
fn create_map(&self) -> FxHashMap<DefId, &'tcx [ty::Variance]> {
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 @@ fn create_map(&self) -> FxHashMap<DefId, &'tcx [ty::Variance]> {
}
(def_id.to_def_id(), &*variances)
})
.collect()
},
))
}
fn evaluate(&self, term: VarianceTermPtr<'a>) -> ty::Variance {

View File

@ -449,8 +449,11 @@ fn visit_closures(&mut self) {
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 @@ fn visit_user_provided_tys(&mut self) {
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 @@ fn visit_user_provided_tys(&mut self) {
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 @@ fn visit_liberated_fn_sigs(&mut self) {
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 @@ fn visit_fru_field_types(&mut self) {
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);

View File

@ -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<Vec<BufferedEarlyLint>>,
pub map: FxIndexMap<NodeId, Vec<BufferedEarlyLint>>,
}
impl LintBuffer {

View File

@ -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<DefId> = 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);
}

View File

@ -1187,8 +1187,11 @@ fn encode_def_ids(&mut self) {
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;
}

View File

@ -38,7 +38,7 @@
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<DefId, &'tcx [ty::Variance]>,
pub variances: DefIdMap<&'tcx [ty::Variance]>,
}
// Contains information needed to resolve types and (in the future) look up

View File

@ -6,7 +6,12 @@
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_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 @@ pub fn get(&self, id: hir::HirId) -> Option<&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<Item = (hir::ItemLocalId, &'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))
}
}
@ -605,6 +614,16 @@ pub fn remove(&mut self, id: hir::HirId) -> Option<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<Item = (hir::HirId, V)>>,
) {
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! {

View File

@ -28,9 +28,9 @@
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<ast::NodeId>,
unused: UnordSet<ast::NodeId>,
}
impl<'a> UnusedImport<'a> {
@ -52,7 +52,7 @@ fn add(&mut self, id: ast::NodeId) {
struct UnusedImportCheckVisitor<'a, 'b> {
r: &'a mut Resolver<'b>,
/// All the (so far) unused imports, grouped path list
unused_imports: NodeMap<UnusedImport<'a>>,
unused_imports: FxIndexMap<ast::NodeId, UnusedImport<'a>>,
base_use_tree: Option<&'a ast::UseTree>,
base_id: ast::NodeId,
item_span: Span,
@ -89,7 +89,7 @@ fn unused_import(&mut self, id: ast::NodeId) -> &mut UnusedImport<'a> {
use_tree,
use_tree_id,
item_span,
unused: FxHashSet::default(),
unused: Default::default(),
})
}
}

View File

@ -52,21 +52,19 @@ fn check_crate_post(&mut self, cx: &LateContext<'tcx>) {
// 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) => {

View File

@ -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,

View File

@ -80,19 +80,21 @@ fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'tcx>) {
}
}
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",
);
}
})
}
}
}

View File

@ -190,10 +190,10 @@ fn check_poly_fn(&mut self, cx: &LateContext<'tcx>, def_id: LocalDefId, decl: &F
// 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)))
{