mirror of
https://github.com/rust-lang/rust.git
synced 2024-11-22 06:44:35 +00:00
cache types during normalization
This commit is contained in:
parent
4e8a8b49ae
commit
1146c39da7
@ -3435,6 +3435,7 @@ dependencies = [
|
||||
name = "rustc_data_structures"
|
||||
version = "0.0.0"
|
||||
dependencies = [
|
||||
"arrayvec",
|
||||
"bitflags",
|
||||
"cfg-if",
|
||||
"crossbeam-utils 0.7.2",
|
||||
|
@ -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"
|
||||
|
@ -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> {
|
||||
|
61
compiler/rustc_data_structures/src/mini_map.rs
Normal file
61
compiler/rustc_data_structures/src/mini_map.rs
Normal 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -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" }
|
||||
|
@ -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>,
|
||||
|
@ -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> {
|
||||
|
Loading…
Reference in New Issue
Block a user