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