Skip to content

Commit 38df4bc

Browse files
committed
Refactor anymap to its own module
1 parent 72fc2d9 commit 38df4bc

File tree

5 files changed

+106
-25
lines changed

5 files changed

+106
-25
lines changed

.vscode/settings.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
11
{
2-
"rust-analyzer.rustc.source": "discover"
2+
"rust-analyzer.rustc.source": "discover",
3+
"rust-analyzer.imports.granularity.group": "module"
34
}

src/ctxt.rs

Lines changed: 9 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,8 @@
22
//
33
// SPDX-License-Identifier: MIT OR Apache-2.0
44

5-
use std::any::{Any, TypeId};
5+
use std::any::Any;
6+
use std::marker::PhantomData;
67
use std::sync::Arc;
78

89
use rusqlite::{Connection, OptionalExtension};
@@ -15,6 +16,7 @@ use rustc_session::config::OutputType;
1516
use rustc_span::{DUMMY_SP, Span};
1617

1718
use crate::diagnostic::use_stack::UseSite;
19+
use crate::utils::anymap::AnyMap;
1820

1921
pub(crate) trait Query: 'static {
2022
const NAME: &'static str;
@@ -55,7 +57,7 @@ pub struct AnalysisCtxt<'tcx> {
5557
pub sql_conn: RwLock<FxHashMap<CrateNum, Option<Arc<MTLock<Connection>>>>>,
5658

5759
pub call_stack: RwLock<Vec<UseSite<'tcx>>>,
58-
pub query_cache: RwLock<FxHashMap<TypeId, Arc<dyn Any + DynSend + DynSync>>>,
60+
pub query_cache: RwLock<AnyMap<dyn Any + DynSend + DynSync>>,
5961
}
6062

6163
// Everything in `AnalysisCtxt` is either `DynSend/DynSync` or `Send/Sync`, but since there're no relation between two right now compiler cannot infer this.
@@ -114,38 +116,21 @@ impl Drop for AnalysisCtxt<'_> {
114116
}
115117
}
116118

117-
// Used when parallel compiler is used.
118-
trait ArcDowncast: Sized {
119-
fn downcast<T: Any>(self) -> Result<Arc<T>, Self>;
120-
}
121-
122-
impl ArcDowncast for Arc<dyn Any> {
123-
fn downcast<T: Any>(self) -> Result<Arc<T>, Self> {
124-
if (*self).is::<T>() {
125-
Ok(unsafe { Arc::from_raw(Arc::into_raw(self) as _) })
126-
} else {
127-
Err(self)
128-
}
129-
}
130-
}
131-
132119
impl<'tcx> AnalysisCtxt<'tcx> {
133120
pub(crate) fn query_cache<Q: Query>(
134121
&self,
135122
) -> Arc<RwLock<FxHashMap<Q::Key<'tcx>, Q::Value<'tcx>>>> {
136-
let key = TypeId::of::<Q>();
137123
let mut guard = self.query_cache.borrow_mut();
138-
let cache = (guard
139-
.entry(key)
124+
let cache = guard
125+
.entry()
140126
.or_insert_with(|| {
141127
let cache = Arc::new(RwLock::new(
142128
FxHashMap::<Q::Key<'static>, Q::Value<'static>>::default(),
143129
));
144-
cache
130+
(PhantomData::<fn() -> Q>, cache)
145131
})
146-
.clone() as Arc<dyn Any>)
147-
.downcast::<RwLock<FxHashMap<Q::Key<'static>, Q::Value<'static>>>>()
148-
.unwrap();
132+
.1
133+
.clone();
149134
// Everything stored inside query_cache is conceptually `'tcx`, but due to limitation
150135
// of `Any` we hack around the lifetime.
151136
unsafe { std::mem::transmute(cache) }

src/main.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
#![feature(once_cell_get_mut)]
1313
// Used in symbol.rs
1414
#![feature(macro_metavar_expr)]
15+
#![feature(unsize)]
1516
#![warn(rustc::internal)]
1617

1718
#[macro_use]
@@ -70,6 +71,7 @@ mod preempt_count;
7071
mod serde;
7172
mod symbol;
7273
mod util;
74+
mod utils;
7375

7476
rustc_session::declare_tool_lint! {
7577
pub klint::INCORRECT_ATTRIBUTE,

src/utils/anymap.rs

Lines changed: 92 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,92 @@
1+
use std::any::{Any, TypeId};
2+
use std::collections::hash_map as map;
3+
use std::marker::{PhantomData, Unsize};
4+
5+
use rustc_data_structures::fx::FxHashMap;
6+
7+
/// Map that can store data for arbitrary types.
8+
pub struct AnyMap<U: ?Sized> {
9+
// This is basically `FxHashMap<TypeId, Box<dyn Any>>`
10+
//
11+
// The generic `U` is present to capture auto trait bounds.
12+
map: FxHashMap<TypeId, Box<U>>,
13+
}
14+
15+
pub struct OccupiedEntry<'a, U: ?Sized, T> {
16+
entry: map::OccupiedEntry<'a, TypeId, Box<U>>,
17+
phantom: PhantomData<T>,
18+
}
19+
20+
impl<'a, U: Any + ?Sized + 'static, T: 'static> OccupiedEntry<'a, U, T> {
21+
pub fn into_mut(self) -> &'a mut T
22+
where
23+
T: Unsize<U>,
24+
{
25+
let any_ref = &mut **self.entry.into_mut();
26+
debug_assert_eq!((*any_ref).type_id(), TypeId::of::<T>());
27+
// SAFETY: by type invariant, `any_ref` is a `&mut T`.
28+
unsafe { &mut *(any_ref as *mut U as *mut T) }
29+
}
30+
}
31+
32+
pub struct VacantEntry<'a, U: ?Sized, T> {
33+
entry: map::VacantEntry<'a, TypeId, Box<U>>,
34+
phantom: PhantomData<T>,
35+
}
36+
37+
impl<'a, U: Any + ?Sized, T> VacantEntry<'a, U, T> {
38+
pub fn insert(self, value: T) -> &'a mut T
39+
where
40+
T: Unsize<U>,
41+
{
42+
let any_ref = &mut **self.entry.insert(Box::new(value) as _);
43+
// SAFETY: we just inserted it and we know the type is `Box<T>`.
44+
unsafe { &mut *(any_ref as *mut U as *mut T) }
45+
}
46+
}
47+
48+
pub enum Entry<'a, U: ?Sized, T> {
49+
Occupied(OccupiedEntry<'a, U, T>),
50+
Vacant(VacantEntry<'a, U, T>),
51+
}
52+
53+
impl<'a, U: Any + ?Sized, T: 'static> Entry<'a, U, T> {
54+
pub fn or_insert_with<F: FnOnce() -> T>(self, default: F) -> &'a mut T
55+
where
56+
T: Unsize<U>,
57+
{
58+
match self {
59+
Entry::Occupied(entry) => entry.into_mut(),
60+
Entry::Vacant(entry) => entry.insert(default()),
61+
}
62+
}
63+
}
64+
65+
impl<U: ?Sized> Default for AnyMap<U> {
66+
fn default() -> Self {
67+
Self::new()
68+
}
69+
}
70+
71+
impl<U: ?Sized> AnyMap<U> {
72+
pub fn new() -> Self {
73+
Self {
74+
map: Default::default(),
75+
}
76+
}
77+
}
78+
79+
impl<U: Any + ?Sized> AnyMap<U> {
80+
pub fn entry<T: 'static>(&mut self) -> Entry<'_, U, T> {
81+
match self.map.entry(TypeId::of::<T>()) {
82+
map::Entry::Occupied(entry) => Entry::Occupied(OccupiedEntry {
83+
entry,
84+
phantom: PhantomData,
85+
}),
86+
map::Entry::Vacant(entry) => Entry::Vacant(VacantEntry {
87+
entry,
88+
phantom: PhantomData,
89+
}),
90+
}
91+
}
92+
}

src/utils/mod.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
pub mod anymap;

0 commit comments

Comments
 (0)