rustc_infer/infer/opaque_types/
table.rs

1use std::ops::Deref;
2
3use rustc_data_structures::fx::FxIndexMap;
4use rustc_data_structures::undo_log::UndoLogs;
5use rustc_middle::bug;
6use rustc_middle::ty::{self, OpaqueHiddenType, OpaqueTypeKey, Ty};
7use tracing::instrument;
8
9use crate::infer::snapshot::undo_log::{InferCtxtUndoLogs, UndoLog};
10
11#[derive(Default, Debug, Clone)]
12pub struct OpaqueTypeStorage<'tcx> {
13    opaque_types: FxIndexMap<OpaqueTypeKey<'tcx>, OpaqueHiddenType<'tcx>>,
14    duplicate_entries: Vec<(OpaqueTypeKey<'tcx>, OpaqueHiddenType<'tcx>)>,
15}
16
17/// The number of entries in the opaque type storage at a given point.
18///
19/// Used to check that we haven't added any new opaque types after checking
20/// the opaque types currently in the storage.
21#[derive(Default, Debug, Clone, Copy, PartialEq, Eq)]
22pub struct OpaqueTypeStorageEntries {
23    opaque_types: usize,
24    duplicate_entries: usize,
25}
26
27impl rustc_type_ir::inherent::OpaqueTypeStorageEntries for OpaqueTypeStorageEntries {
28    fn needs_reevaluation(self, canonicalized: usize) -> bool {
29        self.opaque_types != canonicalized
30    }
31}
32
33impl<'tcx> OpaqueTypeStorage<'tcx> {
34    #[instrument(level = "debug")]
35    pub(crate) fn remove(
36        &mut self,
37        key: OpaqueTypeKey<'tcx>,
38        prev: Option<OpaqueHiddenType<'tcx>>,
39    ) {
40        if let Some(prev) = prev {
41            *self.opaque_types.get_mut(&key).unwrap() = prev;
42        } else {
43            // FIXME(#120456) - is `swap_remove` correct?
44            match self.opaque_types.swap_remove(&key) {
45                None => bug!("reverted opaque type inference that was never registered: {:?}", key),
46                Some(_) => {}
47            }
48        }
49    }
50
51    pub(crate) fn pop_duplicate_entry(&mut self) {
52        let entry = self.duplicate_entries.pop();
53        assert!(entry.is_some());
54    }
55
56    pub fn is_empty(&self) -> bool {
57        let OpaqueTypeStorage { opaque_types, duplicate_entries } = self;
58        opaque_types.is_empty() && duplicate_entries.is_empty()
59    }
60
61    pub(crate) fn take_opaque_types(
62        &mut self,
63    ) -> impl Iterator<Item = (OpaqueTypeKey<'tcx>, OpaqueHiddenType<'tcx>)> {
64        let OpaqueTypeStorage { opaque_types, duplicate_entries } = self;
65        std::mem::take(opaque_types).into_iter().chain(std::mem::take(duplicate_entries))
66    }
67
68    pub fn num_entries(&self) -> OpaqueTypeStorageEntries {
69        OpaqueTypeStorageEntries {
70            opaque_types: self.opaque_types.len(),
71            duplicate_entries: self.duplicate_entries.len(),
72        }
73    }
74
75    pub fn opaque_types_added_since(
76        &self,
77        prev_entries: OpaqueTypeStorageEntries,
78    ) -> impl Iterator<Item = (OpaqueTypeKey<'tcx>, OpaqueHiddenType<'tcx>)> {
79        self.opaque_types
80            .iter()
81            .skip(prev_entries.opaque_types)
82            .map(|(k, v)| (*k, *v))
83            .chain(self.duplicate_entries.iter().skip(prev_entries.duplicate_entries).copied())
84    }
85
86    /// Only returns the opaque types from the lookup table. These are used
87    /// when normalizing opaque types and have a unique key.
88    ///
89    /// Outside of canonicalization one should generally use `iter_opaque_types`
90    /// to also consider duplicate entries.
91    pub fn iter_lookup_table(
92        &self,
93    ) -> impl Iterator<Item = (OpaqueTypeKey<'tcx>, OpaqueHiddenType<'tcx>)> {
94        self.opaque_types.iter().map(|(k, v)| (*k, *v))
95    }
96
97    /// Only returns the opaque types which are stored in `duplicate_entries`.
98    ///
99    /// These have to considered when checking all opaque type uses but are e.g.
100    /// irrelevant for canonical inputs as nested queries never meaningfully
101    /// accesses them.
102    pub fn iter_duplicate_entries(
103        &self,
104    ) -> impl Iterator<Item = (OpaqueTypeKey<'tcx>, OpaqueHiddenType<'tcx>)> {
105        self.duplicate_entries.iter().copied()
106    }
107
108    pub fn iter_opaque_types(
109        &self,
110    ) -> impl Iterator<Item = (OpaqueTypeKey<'tcx>, OpaqueHiddenType<'tcx>)> {
111        let OpaqueTypeStorage { opaque_types, duplicate_entries } = self;
112        opaque_types.iter().map(|(k, v)| (*k, *v)).chain(duplicate_entries.iter().copied())
113    }
114
115    #[inline]
116    pub(crate) fn with_log<'a>(
117        &'a mut self,
118        undo_log: &'a mut InferCtxtUndoLogs<'tcx>,
119    ) -> OpaqueTypeTable<'a, 'tcx> {
120        OpaqueTypeTable { storage: self, undo_log }
121    }
122}
123
124impl<'tcx> Drop for OpaqueTypeStorage<'tcx> {
125    fn drop(&mut self) {
126        if !self.is_empty() {
127            ty::tls::with(|tcx| tcx.dcx().delayed_bug(format!("{:?}", self.opaque_types)));
128        }
129    }
130}
131
132pub struct OpaqueTypeTable<'a, 'tcx> {
133    storage: &'a mut OpaqueTypeStorage<'tcx>,
134
135    undo_log: &'a mut InferCtxtUndoLogs<'tcx>,
136}
137impl<'tcx> Deref for OpaqueTypeTable<'_, 'tcx> {
138    type Target = OpaqueTypeStorage<'tcx>;
139    fn deref(&self) -> &Self::Target {
140        self.storage
141    }
142}
143
144impl<'a, 'tcx> OpaqueTypeTable<'a, 'tcx> {
145    #[instrument(skip(self), level = "debug")]
146    pub fn register(
147        &mut self,
148        key: OpaqueTypeKey<'tcx>,
149        hidden_type: OpaqueHiddenType<'tcx>,
150    ) -> Option<Ty<'tcx>> {
151        if let Some(entry) = self.storage.opaque_types.get_mut(&key) {
152            let prev = std::mem::replace(entry, hidden_type);
153            self.undo_log.push(UndoLog::OpaqueTypes(key, Some(prev)));
154            return Some(prev.ty);
155        }
156        self.storage.opaque_types.insert(key, hidden_type);
157        self.undo_log.push(UndoLog::OpaqueTypes(key, None));
158        None
159    }
160
161    pub fn add_duplicate(&mut self, key: OpaqueTypeKey<'tcx>, hidden_type: OpaqueHiddenType<'tcx>) {
162        self.storage.duplicate_entries.push((key, hidden_type));
163        self.undo_log.push(UndoLog::DuplicateOpaqueType);
164    }
165}