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}