Skip to main content

rustc_middle/query/
arena_cached.rs

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