about summary refs log tree commit diff
path: root/compiler/rustc_middle/src/query/arena_cached.rs
blob: ec6e466ff688c2363486ecd907ddd62ded8d67bb (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
/// Helper trait that allows `arena_cache` queries to return `Option<&T>`
/// instead of `&Option<T>`, and avoid allocating `None` in the arena.
///
/// An arena-cached query must be declared to return a type that implements
/// this trait, i.e. either `&'tcx T` or `Option<&'tcx T>`. This trait then
/// determines the types returned by the provider and stored in the arena,
/// and provides a function to bridge between the three types.
pub trait ArenaCached<'tcx>: Sized {
    /// Type that is returned by the query provider.
    type Provided;
    /// Type that is stored in the arena.
    type Allocated: 'tcx;

    /// Takes a provided value, and allocates it in the arena (if appropriate)
    /// with the help of the given `arena_alloc` closure.
    fn alloc_in_arena(
        arena_alloc: impl Fn(Self::Allocated) -> &'tcx Self::Allocated,
        value: Self::Provided,
    ) -> Self;
}

impl<'tcx, T> ArenaCached<'tcx> for &'tcx T {
    type Provided = T;
    type Allocated = T;

    fn alloc_in_arena(
        arena_alloc: impl Fn(Self::Allocated) -> &'tcx Self::Allocated,
        value: Self::Provided,
    ) -> Self {
        // Just allocate in the arena normally.
        arena_alloc(value)
    }
}

impl<'tcx, T> ArenaCached<'tcx> for Option<&'tcx T> {
    type Provided = Option<T>;
    /// The provide value is `Option<T>`, but we only store `T` in the arena.
    type Allocated = T;

    fn alloc_in_arena(
        arena_alloc: impl Fn(Self::Allocated) -> &'tcx Self::Allocated,
        value: Self::Provided,
    ) -> Self {
        // Don't store None in the arena, and wrap the allocated reference in Some.
        value.map(arena_alloc)
    }
}