rustc_middle/query/arena_cached.rs
1use std::mem;
2
3use rustc_arena::TypedArena;
4
5use crate::ty::TyCtxt;
6
7/// Helper trait that allows `arena_cache` queries to return `Option<&T>`
8/// instead of `&Option<T>`, and avoid allocating `None` in the arena.
9///
10/// An arena-cached query must be declared to return a type that implements
11/// this trait, i.e. either `&'tcx T` or `Option<&'tcx T>`. This trait then
12/// determines the types returned by the provider and stored in the arena,
13/// and provides a function to bridge between the three types.
14pub trait ArenaCached<'tcx>: Sized {
15 /// Type that is returned by the query provider.
16 type Provided;
17 /// Type that is stored in the arena.
18 type Allocated: 'tcx;
19
20 /// Takes a provided value, and allocates it in an appropriate arena,
21 /// unless the particular value doesn't need allocation (e.g. `None`).
22 fn alloc_in_arena(
23 tcx: TyCtxt<'tcx>,
24 typed_arena: &'tcx TypedArena<Self::Allocated>,
25 value: Self::Provided,
26 ) -> Self;
27}
28
29impl<'tcx, T> ArenaCached<'tcx> for &'tcx T {
30 type Provided = T;
31 type Allocated = T;
32
33 fn alloc_in_arena(tcx: TyCtxt<'tcx>, typed_arena: &'tcx TypedArena<T>, value: T) -> Self {
34 // Just allocate in the arena normally.
35 do_alloc(tcx, typed_arena, value)
36 }
37}
38
39impl<'tcx, T> ArenaCached<'tcx> for Option<&'tcx T> {
40 type Provided = Option<T>;
41 /// The provide value is `Option<T>`, but we only store `T` in the arena.
42 type Allocated = T;
43
44 fn alloc_in_arena(
45 tcx: TyCtxt<'tcx>,
46 typed_arena: &'tcx TypedArena<T>,
47 value: Option<T>,
48 ) -> Self {
49 // Don't store None in the arena, and wrap the allocated reference in Some.
50 try { do_alloc(tcx, typed_arena, value?) }
51 }
52}
53
54/// Allocates a value in either its dedicated arena, or in the common dropless
55/// arena, depending on whether it needs to be dropped.
56fn do_alloc<'tcx, T>(tcx: TyCtxt<'tcx>, typed_arena: &'tcx TypedArena<T>, value: T) -> &'tcx T {
57 if mem::needs_drop::<T>() { typed_arena.alloc(value) } else { tcx.arena.dropless.alloc(value) }
58}