Skip to content

Commit 1073461

Browse files
committed
Introduce type-erasure through TAIT.
1 parent 160c2eb commit 1073461

File tree

2 files changed

+273
-0
lines changed

2 files changed

+273
-0
lines changed
+272
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,272 @@
1+
use crate::mir;
2+
use crate::traits;
3+
use crate::ty;
4+
use rustc_ast::expand::allocator::AllocatorKind;
5+
use rustc_hir::MaybeOwner;
6+
pub use rustc_middle::traits::query::type_op;
7+
use std::intrinsics::type_name;
8+
use std::{
9+
fmt,
10+
mem::{size_of, transmute, transmute_copy, MaybeUninit},
11+
};
12+
13+
#[derive(Copy, Clone)]
14+
struct Erased<T: Copy> {
15+
data: MaybeUninit<T>,
16+
formatter: fn(&Self, &mut std::fmt::Formatter<'_>) -> std::fmt::Result,
17+
#[cfg(debug_assertions)]
18+
type_id: &'static str,
19+
}
20+
21+
impl<T: Copy> fmt::Debug for Erased<T> {
22+
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
23+
(self.formatter)(self, f)
24+
}
25+
}
26+
27+
pub trait EraseType: Copy {
28+
type Result: Copy;
29+
}
30+
31+
pub type Erase<T: EraseType + fmt::Debug> = impl Copy + fmt::Debug;
32+
33+
fn formatter<T: EraseType + fmt::Debug>(
34+
this: &Erase<T>,
35+
f: &mut std::fmt::Formatter<'_>,
36+
) -> fmt::Result {
37+
fmt::Debug::fmt(restore_ref(this), f)
38+
}
39+
40+
#[inline(always)]
41+
pub fn erase<T: EraseType + fmt::Debug>(src: T) -> Erase<T> {
42+
assert_eq!(
43+
size_of::<T>(),
44+
size_of::<T::Result>(),
45+
"size of {} must match erased type {}",
46+
type_name::<T>(),
47+
type_name::<T::Result>()
48+
);
49+
Erased::<<T as EraseType>::Result> {
50+
// SAFETY:: Is it safe to transmute to MaybeUninit
51+
data: unsafe { transmute_copy(&src) },
52+
#[cfg(debug_assertions)]
53+
type_id: type_name::<T>(),
54+
formatter: formatter::<T>,
55+
}
56+
}
57+
58+
/// Restores an erased value.
59+
///
60+
/// This is only safe if `value` is a valid instance of `T`.
61+
/// For example if `T` was erased with `erase` previously.
62+
#[inline(always)]
63+
pub fn restore_ref<T: EraseType + fmt::Debug>(value: &Erase<T>) -> &T {
64+
let value: &Erased<<T as EraseType>::Result> = &value;
65+
#[cfg(debug_assertions)]
66+
assert_eq!(value.type_id, type_name::<T>());
67+
assert_eq!(
68+
size_of::<T>(),
69+
size_of::<T::Result>(),
70+
"size of {} must match erased type {}",
71+
type_name::<T>(),
72+
type_name::<T::Result>()
73+
);
74+
// SAFETY: Thanks to the TAIT, this function can only be called with the result of `erase<T>`.
75+
unsafe { transmute(&value.data) }
76+
}
77+
78+
/// Restores an erased value.
79+
///
80+
/// This is only safe if `value` is a valid instance of `T`.
81+
/// For example if `T` was erased with `erase` previously.
82+
#[inline(always)]
83+
pub fn restore<T: EraseType + fmt::Debug>(value: Erase<T>) -> T {
84+
let value: Erased<<T as EraseType>::Result> = value;
85+
#[cfg(debug_assertions)]
86+
assert_eq!(value.type_id, type_name::<T>());
87+
assert_eq!(
88+
size_of::<T>(),
89+
size_of::<T::Result>(),
90+
"size of {} must match erased type {}",
91+
type_name::<T>(),
92+
type_name::<T::Result>()
93+
);
94+
// SAFETY: Thanks to the TAIT, this function can only be called with the result of `erase<T>`.
95+
unsafe { transmute_copy(&value.data) }
96+
}
97+
98+
impl<T> EraseType for &'_ T {
99+
type Result = [u8; size_of::<*const ()>()];
100+
}
101+
102+
impl<T> EraseType for &'_ [T] {
103+
type Result = [u8; size_of::<*const [()]>()];
104+
}
105+
106+
impl<T> EraseType for &'_ ty::List<T> {
107+
type Result = [u8; size_of::<*const ()>()];
108+
}
109+
110+
impl<T: Copy, E: Copy> EraseType for Result<T, E> {
111+
type Result = Self;
112+
}
113+
114+
impl<T: Copy> EraseType for Option<T> {
115+
type Result = Self;
116+
}
117+
118+
impl<T: Copy> EraseType for MaybeOwner<T> {
119+
type Result = Self;
120+
}
121+
122+
impl<T: Copy> EraseType for ty::Visibility<T> {
123+
type Result = Self;
124+
}
125+
126+
impl<T: Copy> EraseType for ty::Binder<'_, T> {
127+
type Result = Self;
128+
}
129+
130+
impl<T: Copy> EraseType for ty::EarlyBinder<T> {
131+
type Result = Self;
132+
}
133+
134+
impl<T0: Copy, T1: Copy> EraseType for (T0, T1) {
135+
type Result = Self;
136+
}
137+
138+
macro_rules! trivial {
139+
($($ty:ty),+ $(,)?) => {
140+
$(
141+
impl EraseType for $ty {
142+
type Result = [u8; size_of::<$ty>()];
143+
}
144+
)*
145+
}
146+
}
147+
148+
trivial! {
149+
(),
150+
AllocatorKind,
151+
bool,
152+
crate::metadata::ModChild,
153+
crate::middle::exported_symbols::SymbolExportInfo,
154+
crate::middle::resolve_bound_vars::ObjectLifetimeDefault,
155+
crate::middle::resolve_bound_vars::ResolvedArg,
156+
crate::middle::stability::DeprecationEntry,
157+
crate::mir::ConstQualifs,
158+
crate::mir::interpret::ErrorHandled,
159+
crate::mir::interpret::LitToConstError,
160+
crate::thir::ExprId,
161+
crate::traits::CodegenObligationError,
162+
mir::Field,
163+
mir::interpret::AllocId,
164+
rustc_attr::ConstStability,
165+
rustc_attr::DefaultBodyStability,
166+
rustc_attr::Deprecation,
167+
rustc_attr::Stability,
168+
rustc_data_structures::svh::Svh,
169+
rustc_errors::ErrorGuaranteed,
170+
rustc_hir::Constness,
171+
rustc_hir::def_id::DefId,
172+
rustc_hir::def_id::DefIndex,
173+
rustc_hir::def_id::LocalDefId,
174+
rustc_hir::def::DefKind,
175+
rustc_hir::Defaultness,
176+
rustc_hir::definitions::DefKey,
177+
rustc_hir::GeneratorKind,
178+
rustc_hir::HirId,
179+
rustc_hir::IsAsync,
180+
rustc_hir::ItemLocalId,
181+
rustc_hir::LangItem,
182+
rustc_hir::OwnerId,
183+
rustc_hir::Upvar,
184+
rustc_index::bit_set::FiniteBitSet<u32>,
185+
rustc_middle::middle::dependency_format::Linkage,
186+
rustc_session::config::CrateType,
187+
rustc_session::config::EntryFnType,
188+
rustc_session::config::OptLevel,
189+
rustc_session::config::SymbolManglingVersion,
190+
rustc_session::cstore::CrateDepKind,
191+
rustc_session::cstore::ExternCrate,
192+
rustc_session::cstore::LinkagePreference,
193+
rustc_session::Limits,
194+
rustc_session::lint::LintExpectationId,
195+
rustc_span::def_id::CrateNum,
196+
rustc_span::def_id::DefPathHash,
197+
rustc_span::ExpnHash,
198+
rustc_span::ExpnId,
199+
rustc_span::Span,
200+
rustc_span::Symbol,
201+
rustc_span::symbol::Ident,
202+
rustc_target::spec::PanicStrategy,
203+
rustc_type_ir::Variance,
204+
traits::EvaluationResult,
205+
traits::OverflowError,
206+
traits::query::NoSolution,
207+
traits::WellFormedLoc,
208+
ty::adjustment::CoerceUnsizedInfo,
209+
ty::AssocItem,
210+
ty::AssocItemContainer,
211+
ty::BoundVariableKind,
212+
ty::DeducedParamAttrs,
213+
ty::Destructor,
214+
ty::fast_reject::SimplifiedType,
215+
ty::ImplPolarity,
216+
ty::Representability,
217+
ty::ReprOptions,
218+
ty::UnusedGenericParams,
219+
ty::util::AlwaysRequiresDrop,
220+
u32,
221+
usize,
222+
}
223+
224+
macro_rules! tcx_lifetime {
225+
($($($fake_path:ident)::+),+ $(,)?) => {
226+
$(
227+
impl<'tcx> EraseType for $($fake_path)::+<'tcx> {
228+
type Result = [u8; size_of::<$($fake_path)::+<'static>>()];
229+
}
230+
)*
231+
}
232+
}
233+
234+
tcx_lifetime! {
235+
crate::middle::exported_symbols::ExportedSymbol,
236+
crate::mir::DestructuredConstant,
237+
crate::mir::interpret::ConstValue,
238+
mir::ConstantKind,
239+
mir::interpret::ConstAlloc,
240+
mir::interpret::GlobalId,
241+
mir::interpret::LitToConstInput,
242+
rustc_middle::hir::Owner,
243+
traits::ChalkEnvironmentAndGoal,
244+
traits::query::MethodAutoderefStepsResult,
245+
ty::AdtDef,
246+
ty::AliasTy,
247+
ty::Clause,
248+
ty::ClosureTypeInfo,
249+
ty::Const,
250+
ty::DestructuredConst,
251+
ty::ExistentialTraitRef,
252+
ty::FnSig,
253+
ty::GenericArg,
254+
ty::GenericPredicates,
255+
ty::inhabitedness::InhabitedPredicate,
256+
ty::Instance,
257+
ty::InstanceDef,
258+
ty::layout::FnAbiError,
259+
ty::layout::LayoutError,
260+
ty::ParamEnv,
261+
ty::Predicate,
262+
ty::SymbolName,
263+
ty::TraitRef,
264+
ty::Ty,
265+
ty::UnevaluatedConst,
266+
ty::ValTree,
267+
ty::VtblEntry,
268+
type_op::AscribeUserType,
269+
type_op::Eq,
270+
type_op::ProvePredicate,
271+
type_op::Subtype,
272+
}

compiler/rustc_middle/src/query/mod.rs

+1
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
use crate::ty::{self, print::describe_as_module, TyCtxt};
88
use rustc_span::def_id::LOCAL_CRATE;
99

10+
mod erase;
1011
mod keys;
1112
pub use keys::Key;
1213

0 commit comments

Comments
 (0)