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, OpaqueTypeKey, ProvisionalHiddenType, Ty};
7use tracing::instrument;
8
9use crate::infer::snapshot::undo_log::{InferCtxtUndoLogs, UndoLog};
10
11#[derive(#[automatically_derived]
impl<'tcx> ::core::default::Default for OpaqueTypeStorage<'tcx> {
    #[inline]
    fn default() -> OpaqueTypeStorage<'tcx> {
        OpaqueTypeStorage {
            opaque_types: ::core::default::Default::default(),
            duplicate_entries: ::core::default::Default::default(),
        }
    }
}Default, #[automatically_derived]
impl<'tcx> ::core::fmt::Debug for OpaqueTypeStorage<'tcx> {
    #[inline]
    fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
        ::core::fmt::Formatter::debug_struct_field2_finish(f,
            "OpaqueTypeStorage", "opaque_types", &self.opaque_types,
            "duplicate_entries", &&self.duplicate_entries)
    }
}Debug, #[automatically_derived]
impl<'tcx> ::core::clone::Clone for OpaqueTypeStorage<'tcx> {
    #[inline]
    fn clone(&self) -> OpaqueTypeStorage<'tcx> {
        OpaqueTypeStorage {
            opaque_types: ::core::clone::Clone::clone(&self.opaque_types),
            duplicate_entries: ::core::clone::Clone::clone(&self.duplicate_entries),
        }
    }
}Clone)]
12pub struct OpaqueTypeStorage<'tcx> {
13    opaque_types: FxIndexMap<OpaqueTypeKey<'tcx>, ProvisionalHiddenType<'tcx>>,
14    duplicate_entries: Vec<(OpaqueTypeKey<'tcx>, ProvisionalHiddenType<'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(#[automatically_derived]
impl ::core::default::Default for OpaqueTypeStorageEntries {
    #[inline]
    fn default() -> OpaqueTypeStorageEntries {
        OpaqueTypeStorageEntries {
            opaque_types: ::core::default::Default::default(),
            duplicate_entries: ::core::default::Default::default(),
        }
    }
}Default, #[automatically_derived]
impl ::core::fmt::Debug for OpaqueTypeStorageEntries {
    #[inline]
    fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
        ::core::fmt::Formatter::debug_struct_field2_finish(f,
            "OpaqueTypeStorageEntries", "opaque_types", &self.opaque_types,
            "duplicate_entries", &&self.duplicate_entries)
    }
}Debug, #[automatically_derived]
impl ::core::clone::Clone for OpaqueTypeStorageEntries {
    #[inline]
    fn clone(&self) -> OpaqueTypeStorageEntries {
        let _: ::core::clone::AssertParamIsClone<usize>;
        *self
    }
}Clone, #[automatically_derived]
impl ::core::marker::Copy for OpaqueTypeStorageEntries { }Copy, #[automatically_derived]
impl ::core::cmp::PartialEq for OpaqueTypeStorageEntries {
    #[inline]
    fn eq(&self, other: &OpaqueTypeStorageEntries) -> bool {
        self.opaque_types == other.opaque_types &&
            self.duplicate_entries == other.duplicate_entries
    }
}PartialEq, #[automatically_derived]
impl ::core::cmp::Eq for OpaqueTypeStorageEntries {
    #[inline]
    #[doc(hidden)]
    #[coverage(off)]
    fn assert_receiver_is_total_eq(&self) -> () {
        let _: ::core::cmp::AssertParamIsEq<usize>;
    }
}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    #[allow(clippy :: suspicious_else_formatting)]
{
    let __tracing_attr_span;
    let __tracing_attr_guard;
    if ::tracing::Level::DEBUG <= ::tracing::level_filters::STATIC_MAX_LEVEL
                &&
                ::tracing::Level::DEBUG <=
                    ::tracing::level_filters::LevelFilter::current() ||
            { false } {
        __tracing_attr_span =
            {
                use ::tracing::__macro_support::Callsite as _;
                static __CALLSITE: ::tracing::callsite::DefaultCallsite =
                    {
                        static META: ::tracing::Metadata<'static> =
                            {
                                ::tracing_core::metadata::Metadata::new("remove",
                                    "rustc_infer::infer::opaque_types::table",
                                    ::tracing::Level::DEBUG,
                                    ::tracing_core::__macro_support::Option::Some("compiler/rustc_infer/src/infer/opaque_types/table.rs"),
                                    ::tracing_core::__macro_support::Option::Some(34u32),
                                    ::tracing_core::__macro_support::Option::Some("rustc_infer::infer::opaque_types::table"),
                                    ::tracing_core::field::FieldSet::new(&["self", "key",
                                                    "prev"], ::tracing_core::callsite::Identifier(&__CALLSITE)),
                                    ::tracing::metadata::Kind::SPAN)
                            };
                        ::tracing::callsite::DefaultCallsite::new(&META)
                    };
                let mut interest = ::tracing::subscriber::Interest::never();
                if ::tracing::Level::DEBUG <=
                                    ::tracing::level_filters::STATIC_MAX_LEVEL &&
                                ::tracing::Level::DEBUG <=
                                    ::tracing::level_filters::LevelFilter::current() &&
                            { interest = __CALLSITE.interest(); !interest.is_never() }
                        &&
                        ::tracing::__macro_support::__is_enabled(__CALLSITE.metadata(),
                            interest) {
                    let meta = __CALLSITE.metadata();
                    ::tracing::Span::new(meta,
                        &{
                                #[allow(unused_imports)]
                                use ::tracing::field::{debug, display, Value};
                                let mut iter = meta.fields().iter();
                                meta.fields().value_set(&[(&::tracing::__macro_support::Iterator::next(&mut iter).expect("FieldSet corrupted (this is a bug)"),
                                                    ::tracing::__macro_support::Option::Some(&::tracing::field::debug(&self)
                                                            as &dyn Value)),
                                                (&::tracing::__macro_support::Iterator::next(&mut iter).expect("FieldSet corrupted (this is a bug)"),
                                                    ::tracing::__macro_support::Option::Some(&::tracing::field::debug(&key)
                                                            as &dyn Value)),
                                                (&::tracing::__macro_support::Iterator::next(&mut iter).expect("FieldSet corrupted (this is a bug)"),
                                                    ::tracing::__macro_support::Option::Some(&::tracing::field::debug(&prev)
                                                            as &dyn Value))])
                            })
                } else {
                    let span =
                        ::tracing::__macro_support::__disabled_span(__CALLSITE.metadata());
                    {};
                    span
                }
            };
        __tracing_attr_guard = __tracing_attr_span.enter();
    }

    #[warn(clippy :: suspicious_else_formatting)]
    {

        #[allow(unknown_lints, unreachable_code, clippy ::
        diverging_sub_expression, clippy :: empty_loop, clippy ::
        let_unit_value, clippy :: let_with_type_underscore, clippy ::
        needless_return, clippy :: unreachable)]
        if false {
            let __tracing_attr_fake_return: () = loop {};
            return __tracing_attr_fake_return;
        }
        {
            if let Some(prev) = prev {
                *self.opaque_types.get_mut(&key).unwrap() = prev;
            } else {
                match self.opaque_types.swap_remove(&key) {
                    None =>
                        ::rustc_middle::util::bug::bug_fmt(format_args!("reverted opaque type inference that was never registered: {0:?}",
                                key)),
                    Some(_) => {}
                }
            }
        }
    }
}#[instrument(level = "debug")]
35    pub(crate) fn remove(
36        &mut self,
37        key: OpaqueTypeKey<'tcx>,
38        prev: Option<ProvisionalHiddenType<'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        if !entry.is_some() {
    ::core::panicking::panic("assertion failed: entry.is_some()")
};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>, ProvisionalHiddenType<'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>, ProvisionalHiddenType<'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>, ProvisionalHiddenType<'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>, ProvisionalHiddenType<'tcx>)> {
105        self.duplicate_entries.iter().copied()
106    }
107
108    pub fn iter_opaque_types(
109        &self,
110    ) -> impl Iterator<Item = (OpaqueTypeKey<'tcx>, ProvisionalHiddenType<'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(::alloc::__export::must_use({
        ::alloc::fmt::format(format_args!("{0:?}", self.opaque_types))
    })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    #[allow(clippy :: suspicious_else_formatting)]
{
    let __tracing_attr_span;
    let __tracing_attr_guard;
    if ::tracing::Level::DEBUG <= ::tracing::level_filters::STATIC_MAX_LEVEL
                &&
                ::tracing::Level::DEBUG <=
                    ::tracing::level_filters::LevelFilter::current() ||
            { false } {
        __tracing_attr_span =
            {
                use ::tracing::__macro_support::Callsite as _;
                static __CALLSITE: ::tracing::callsite::DefaultCallsite =
                    {
                        static META: ::tracing::Metadata<'static> =
                            {
                                ::tracing_core::metadata::Metadata::new("register",
                                    "rustc_infer::infer::opaque_types::table",
                                    ::tracing::Level::DEBUG,
                                    ::tracing_core::__macro_support::Option::Some("compiler/rustc_infer/src/infer/opaque_types/table.rs"),
                                    ::tracing_core::__macro_support::Option::Some(145u32),
                                    ::tracing_core::__macro_support::Option::Some("rustc_infer::infer::opaque_types::table"),
                                    ::tracing_core::field::FieldSet::new(&["key",
                                                    "hidden_type"],
                                        ::tracing_core::callsite::Identifier(&__CALLSITE)),
                                    ::tracing::metadata::Kind::SPAN)
                            };
                        ::tracing::callsite::DefaultCallsite::new(&META)
                    };
                let mut interest = ::tracing::subscriber::Interest::never();
                if ::tracing::Level::DEBUG <=
                                    ::tracing::level_filters::STATIC_MAX_LEVEL &&
                                ::tracing::Level::DEBUG <=
                                    ::tracing::level_filters::LevelFilter::current() &&
                            { interest = __CALLSITE.interest(); !interest.is_never() }
                        &&
                        ::tracing::__macro_support::__is_enabled(__CALLSITE.metadata(),
                            interest) {
                    let meta = __CALLSITE.metadata();
                    ::tracing::Span::new(meta,
                        &{
                                #[allow(unused_imports)]
                                use ::tracing::field::{debug, display, Value};
                                let mut iter = meta.fields().iter();
                                meta.fields().value_set(&[(&::tracing::__macro_support::Iterator::next(&mut iter).expect("FieldSet corrupted (this is a bug)"),
                                                    ::tracing::__macro_support::Option::Some(&::tracing::field::debug(&key)
                                                            as &dyn Value)),
                                                (&::tracing::__macro_support::Iterator::next(&mut iter).expect("FieldSet corrupted (this is a bug)"),
                                                    ::tracing::__macro_support::Option::Some(&::tracing::field::debug(&hidden_type)
                                                            as &dyn Value))])
                            })
                } else {
                    let span =
                        ::tracing::__macro_support::__disabled_span(__CALLSITE.metadata());
                    {};
                    span
                }
            };
        __tracing_attr_guard = __tracing_attr_span.enter();
    }

    #[warn(clippy :: suspicious_else_formatting)]
    {

        #[allow(unknown_lints, unreachable_code, clippy ::
        diverging_sub_expression, clippy :: empty_loop, clippy ::
        let_unit_value, clippy :: let_with_type_underscore, clippy ::
        needless_return, clippy :: unreachable)]
        if false {
            let __tracing_attr_fake_return: Option<Ty<'tcx>> = loop {};
            return __tracing_attr_fake_return;
        }
        {
            if let Some(entry) = self.storage.opaque_types.get_mut(&key) {
                let prev = std::mem::replace(entry, hidden_type);
                self.undo_log.push(UndoLog::OpaqueTypes(key, Some(prev)));
                return Some(prev.ty);
            }
            self.storage.opaque_types.insert(key, hidden_type);
            self.undo_log.push(UndoLog::OpaqueTypes(key, None));
            None
        }
    }
}#[instrument(skip(self), level = "debug")]
146    pub fn register(
147        &mut self,
148        key: OpaqueTypeKey<'tcx>,
149        hidden_type: ProvisionalHiddenType<'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(
162        &mut self,
163        key: OpaqueTypeKey<'tcx>,
164        hidden_type: ProvisionalHiddenType<'tcx>,
165    ) {
166        self.storage.duplicate_entries.push((key, hidden_type));
167        self.undo_log.push(UndoLog::DuplicateOpaqueType);
168    }
169}