cache types during normalization

This commit is contained in:
Bastian Kauschke 2020-09-19 17:27:13 +02:00
parent 4e8a8b49ae
commit 1146c39da7
7 changed files with 83 additions and 68 deletions

View File

@ -3435,6 +3435,7 @@ dependencies = [
name = "rustc_data_structures"
version = "0.0.0"
dependencies = [
"arrayvec",
"bitflags",
"cfg-if",
"crossbeam-utils 0.7.2",

View File

@ -8,6 +8,7 @@ edition = "2018"
doctest = false
[dependencies]
arrayvec = { version = "0.5.1", default-features = false }
ena = "0.14"
indexmap = "1.5.1"
tracing = "0.1"

View File

@ -87,25 +87,27 @@ pub mod sorted_map;
pub mod stable_set;
#[macro_use]
pub mod stable_hasher;
mod atomic_ref;
pub mod fingerprint;
pub mod profiling;
pub mod sharded;
pub mod stack;
pub mod sync;
pub mod thin_vec;
pub mod tiny_list;
pub mod transitive_relation;
pub use ena::undo_log;
pub use ena::unify;
mod atomic_ref;
pub mod fingerprint;
pub mod profiling;
pub mod vec_linked_list;
pub mod work_queue;
pub use atomic_ref::AtomicRef;
pub mod frozen;
pub mod mini_map;
pub mod tagged_ptr;
pub mod temp_dir;
pub mod unhash;
pub use ena::undo_log;
pub use ena::unify;
pub struct OnDrop<F: Fn()>(pub F);
impl<F: Fn()> OnDrop<F> {

View File

@ -0,0 +1,61 @@
use crate::fx::FxHashMap;
use arrayvec::ArrayVec;
use std::hash::Hash;
/// Small-storage-optimized implementation of a map
/// made specifically for caching results.
///
/// Stores elements in a small array up to a certain length
/// and switches to `HashMap` when that length is exceeded.
pub enum MiniMap<K, V> {
Array(ArrayVec<[(K, V); 8]>),
Map(FxHashMap<K, V>),
}
impl<K: Eq + Hash, V> MiniMap<K, V> {
/// Creates an empty `MiniMap`.
pub fn new() -> Self {
MiniMap::Array(ArrayVec::new())
}
/// Inserts or updates value in the map.
pub fn insert(&mut self, key: K, value: V) {
match self {
MiniMap::Array(array) => {
for pair in array.iter_mut() {
if pair.0 == key {
pair.1 = value;
return;
}
}
if let Err(error) = array.try_push((key, value)) {
let mut map: FxHashMap<K, V> = array.drain(..).collect();
let (key, value) = error.element();
map.insert(key, value);
*self = MiniMap::Map(map);
}
}
MiniMap::Map(map) => {
map.insert(key, value);
}
}
}
/// Return value by key if any.
pub fn get(&self, key: &K) -> Option<&V> {
match self {
MiniMap::Array(array) => {
for pair in array {
if pair.0 == *key {
return Some(&pair.1);
}
}
return None;
}
MiniMap::Map(map) => {
return map.get(key);
}
}
}
}

View File

@ -8,6 +8,6 @@ edition = "2018"
doctest = false
[dependencies]
arrayvec = "0.5.1"
arrayvec = { version = "0.5.1", default-features = false }
rustc_serialize = { path = "../rustc_serialize" }
rustc_macros = { path = "../rustc_macros" }

View File

@ -31,13 +31,11 @@ use super::unify_key::replace_if_possible;
use super::unify_key::{ConstVarValue, ConstVariableValue};
use super::unify_key::{ConstVariableOrigin, ConstVariableOriginKind};
use super::{InferCtxt, MiscVariable, TypeTrace};
use arrayvec::ArrayVec;
use rustc_data_structures::fx::FxHashMap;
use std::hash::Hash;
use crate::traits::{Obligation, PredicateObligations};
use rustc_ast as ast;
use rustc_data_structures::mini_map::MiniMap;
use rustc_hir::def_id::DefId;
use rustc_middle::traits::ObligationCause;
use rustc_middle::ty::error::TypeError;
@ -47,63 +45,6 @@ use rustc_middle::ty::{self, InferConst, ToPredicate, Ty, TyCtxt, TypeFoldable};
use rustc_middle::ty::{IntType, UintType};
use rustc_span::DUMMY_SP;
/// Small-storage-optimized implementation of a map
/// made specifically for caching results.
///
/// Stores elements in a small array up to a certain length
/// and switches to `HashMap` when that length is exceeded.
enum MiniMap<K, V> {
Array(ArrayVec<[(K, V); 8]>),
Map(FxHashMap<K, V>),
}
impl<K: Eq + Hash, V> MiniMap<K, V> {
/// Creates an empty `MiniMap`.
pub fn new() -> Self {
MiniMap::Array(ArrayVec::new())
}
/// Inserts or updates value in the map.
pub fn insert(&mut self, key: K, value: V) {
match self {
MiniMap::Array(array) => {
for pair in array.iter_mut() {
if pair.0 == key {
pair.1 = value;
return;
}
}
if let Err(error) = array.try_push((key, value)) {
let mut map: FxHashMap<K, V> = array.drain(..).collect();
let (key, value) = error.element();
map.insert(key, value);
*self = MiniMap::Map(map);
}
}
MiniMap::Map(map) => {
map.insert(key, value);
}
}
}
/// Return value by key if any.
pub fn get(&self, key: &K) -> Option<&V> {
match self {
MiniMap::Array(array) => {
for pair in array {
if pair.0 == *key {
return Some(&pair.1);
}
}
return None;
}
MiniMap::Map(map) => {
return map.get(key);
}
}
}
}
#[derive(Clone)]
pub struct CombineFields<'infcx, 'tcx> {
pub infcx: &'infcx InferCtxt<'infcx, 'tcx>,

View File

@ -7,6 +7,7 @@ use crate::infer::canonical::OriginalQueryValues;
use crate::infer::{InferCtxt, InferOk};
use crate::traits::error_reporting::InferCtxtExt;
use crate::traits::{Obligation, ObligationCause, PredicateObligation, Reveal};
use rustc_data_structures::mini_map::MiniMap;
use rustc_data_structures::stack::ensure_sufficient_stack;
use rustc_infer::traits::Normalized;
use rustc_middle::ty::fold::{TypeFoldable, TypeFolder};
@ -57,6 +58,7 @@ impl<'cx, 'tcx> AtExt<'tcx> for At<'cx, 'tcx> {
param_env: self.param_env,
obligations: vec![],
error: false,
cache: MiniMap::new(),
anon_depth: 0,
};
@ -85,6 +87,7 @@ struct QueryNormalizer<'cx, 'tcx> {
cause: &'cx ObligationCause<'tcx>,
param_env: ty::ParamEnv<'tcx>,
obligations: Vec<PredicateObligation<'tcx>>,
cache: MiniMap<Ty<'tcx>, Ty<'tcx>>,
error: bool,
anon_depth: usize,
}
@ -99,8 +102,12 @@ impl<'cx, 'tcx> TypeFolder<'tcx> for QueryNormalizer<'cx, 'tcx> {
return ty;
}
if let Some(ty) = self.cache.get(&ty) {
return ty;
}
let ty = ty.super_fold_with(self);
match *ty.kind() {
let res = (|| match *ty.kind() {
ty::Opaque(def_id, substs) => {
// Only normalize `impl Trait` after type-checking, usually in codegen.
match self.param_env.reveal() {
@ -197,7 +204,9 @@ impl<'cx, 'tcx> TypeFolder<'tcx> for QueryNormalizer<'cx, 'tcx> {
}
_ => ty,
}
})();
self.cache.insert(ty, res);
res
}
fn fold_const(&mut self, constant: &'tcx ty::Const<'tcx>) -> &'tcx ty::Const<'tcx> {