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