rustc_middle/infer/
canonical.rs

1//! **Canonicalization** is the key to constructing a query in the
2//! middle of type inference. Ordinarily, it is not possible to store
3//! types from type inference in query keys, because they contain
4//! references to inference variables whose lifetimes are too short
5//! and so forth. Canonicalizing a value T1 using `canonicalize_query`
6//! produces two things:
7//!
8//! - a value T2 where each unbound inference variable has been
9//!   replaced with a **canonical variable**;
10//! - a map M (of type `CanonicalVarValues`) from those canonical
11//!   variables back to the original.
12//!
13//! We can then do queries using T2. These will give back constraints
14//! on the canonical variables which can be translated, using the map
15//! M, into constraints in our source context. This process of
16//! translating the results back is done by the
17//! `instantiate_query_result` method.
18//!
19//! For a more detailed look at what is happening here, check
20//! out the [chapter in the rustc dev guide][c].
21//!
22//! [c]: https://rust-lang.github.io/chalk/book/canonical_queries/canonicalization.html
23
24use std::collections::hash_map::Entry;
25
26use rustc_data_structures::fx::FxHashMap;
27use rustc_data_structures::sync::Lock;
28use rustc_macros::{HashStable, TypeFoldable, TypeVisitable};
29pub use rustc_type_ir as ir;
30use smallvec::SmallVec;
31
32use crate::mir::ConstraintCategory;
33use crate::ty::{self, GenericArg, List, Ty, TyCtxt, TypeFlags, TypeVisitableExt};
34
35pub type CanonicalQueryInput<'tcx, V> = ir::CanonicalQueryInput<TyCtxt<'tcx>, V>;
36pub type Canonical<'tcx, V> = ir::Canonical<TyCtxt<'tcx>, V>;
37pub type CanonicalVarKind<'tcx> = ir::CanonicalVarKind<TyCtxt<'tcx>>;
38pub type CanonicalVarValues<'tcx> = ir::CanonicalVarValues<TyCtxt<'tcx>>;
39pub type CanonicalVarKinds<'tcx> = &'tcx List<CanonicalVarKind<'tcx>>;
40
41/// When we canonicalize a value to form a query, we wind up replacing
42/// various parts of it with canonical variables. This struct stores
43/// those replaced bits to remember for when we process the query
44/// result.
45#[derive(#[automatically_derived]
impl<'tcx> ::core::clone::Clone for OriginalQueryValues<'tcx> {
    #[inline]
    fn clone(&self) -> OriginalQueryValues<'tcx> {
        OriginalQueryValues {
            universe_map: ::core::clone::Clone::clone(&self.universe_map),
            var_values: ::core::clone::Clone::clone(&self.var_values),
        }
    }
}Clone, #[automatically_derived]
impl<'tcx> ::core::fmt::Debug for OriginalQueryValues<'tcx> {
    #[inline]
    fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
        ::core::fmt::Formatter::debug_struct_field2_finish(f,
            "OriginalQueryValues", "universe_map", &self.universe_map,
            "var_values", &&self.var_values)
    }
}Debug)]
46pub struct OriginalQueryValues<'tcx> {
47    /// Map from the universes that appear in the query to the universes in the
48    /// caller context. For all queries except `evaluate_goal` (used by Chalk),
49    /// we only ever put ROOT values into the query, so this map is very
50    /// simple.
51    pub universe_map: SmallVec<[ty::UniverseIndex; 4]>,
52
53    /// This is equivalent to `CanonicalVarValues`, but using a
54    /// `SmallVec` yields a significant performance win.
55    pub var_values: SmallVec<[GenericArg<'tcx>; 8]>,
56}
57
58impl<'tcx> Default for OriginalQueryValues<'tcx> {
59    fn default() -> Self {
60        let mut universe_map = SmallVec::default();
61        universe_map.push(ty::UniverseIndex::ROOT);
62
63        Self { universe_map, var_values: SmallVec::default() }
64    }
65}
66
67/// After we execute a query with a canonicalized key, we get back a
68/// `Canonical<QueryResponse<..>>`. You can use
69/// `instantiate_query_result` to access the data in this result.
70#[derive(#[automatically_derived]
impl<'tcx, R: ::core::clone::Clone> ::core::clone::Clone for
    QueryResponse<'tcx, R> {
    #[inline]
    fn clone(&self) -> QueryResponse<'tcx, R> {
        QueryResponse {
            var_values: ::core::clone::Clone::clone(&self.var_values),
            region_constraints: ::core::clone::Clone::clone(&self.region_constraints),
            certainty: ::core::clone::Clone::clone(&self.certainty),
            opaque_types: ::core::clone::Clone::clone(&self.opaque_types),
            value: ::core::clone::Clone::clone(&self.value),
        }
    }
}Clone, #[automatically_derived]
impl<'tcx, R: ::core::fmt::Debug> ::core::fmt::Debug for
    QueryResponse<'tcx, R> {
    #[inline]
    fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
        ::core::fmt::Formatter::debug_struct_field5_finish(f, "QueryResponse",
            "var_values", &self.var_values, "region_constraints",
            &self.region_constraints, "certainty", &self.certainty,
            "opaque_types", &self.opaque_types, "value", &&self.value)
    }
}Debug, const _: () =
    {
        impl<'tcx, '__ctx, R>
            ::rustc_data_structures::stable_hasher::HashStable<::rustc_query_system::ich::StableHashingContext<'__ctx>>
            for QueryResponse<'tcx, R> where
            R: ::rustc_data_structures::stable_hasher::HashStable<::rustc_query_system::ich::StableHashingContext<'__ctx>>
            {
            #[inline]
            fn hash_stable(&self,
                __hcx:
                    &mut ::rustc_query_system::ich::StableHashingContext<'__ctx>,
                __hasher:
                    &mut ::rustc_data_structures::stable_hasher::StableHasher) {
                match *self {
                    QueryResponse {
                        var_values: ref __binding_0,
                        region_constraints: ref __binding_1,
                        certainty: ref __binding_2,
                        opaque_types: ref __binding_3,
                        value: ref __binding_4 } => {
                        { __binding_0.hash_stable(__hcx, __hasher); }
                        { __binding_1.hash_stable(__hcx, __hasher); }
                        { __binding_2.hash_stable(__hcx, __hasher); }
                        { __binding_3.hash_stable(__hcx, __hasher); }
                        { __binding_4.hash_stable(__hcx, __hasher); }
                    }
                }
            }
        }
    };HashStable, const _: () =
    {
        impl<'tcx, R>
            ::rustc_middle::ty::TypeFoldable<::rustc_middle::ty::TyCtxt<'tcx>>
            for QueryResponse<'tcx, R> where
            R: ::rustc_middle::ty::TypeFoldable<::rustc_middle::ty::TyCtxt<'tcx>>
            {
            fn try_fold_with<__F: ::rustc_middle::ty::FallibleTypeFolder<::rustc_middle::ty::TyCtxt<'tcx>>>(self,
                __folder: &mut __F) -> Result<Self, __F::Error> {
                Ok(match self {
                        QueryResponse {
                            var_values: __binding_0,
                            region_constraints: __binding_1,
                            certainty: __binding_2,
                            opaque_types: __binding_3,
                            value: __binding_4 } => {
                            QueryResponse {
                                var_values: ::rustc_middle::ty::TypeFoldable::try_fold_with(__binding_0,
                                        __folder)?,
                                region_constraints: ::rustc_middle::ty::TypeFoldable::try_fold_with(__binding_1,
                                        __folder)?,
                                certainty: ::rustc_middle::ty::TypeFoldable::try_fold_with(__binding_2,
                                        __folder)?,
                                opaque_types: ::rustc_middle::ty::TypeFoldable::try_fold_with(__binding_3,
                                        __folder)?,
                                value: ::rustc_middle::ty::TypeFoldable::try_fold_with(__binding_4,
                                        __folder)?,
                            }
                        }
                    })
            }
            fn fold_with<__F: ::rustc_middle::ty::TypeFolder<::rustc_middle::ty::TyCtxt<'tcx>>>(self,
                __folder: &mut __F) -> Self {
                match self {
                    QueryResponse {
                        var_values: __binding_0,
                        region_constraints: __binding_1,
                        certainty: __binding_2,
                        opaque_types: __binding_3,
                        value: __binding_4 } => {
                        QueryResponse {
                            var_values: ::rustc_middle::ty::TypeFoldable::fold_with(__binding_0,
                                __folder),
                            region_constraints: ::rustc_middle::ty::TypeFoldable::fold_with(__binding_1,
                                __folder),
                            certainty: ::rustc_middle::ty::TypeFoldable::fold_with(__binding_2,
                                __folder),
                            opaque_types: ::rustc_middle::ty::TypeFoldable::fold_with(__binding_3,
                                __folder),
                            value: ::rustc_middle::ty::TypeFoldable::fold_with(__binding_4,
                                __folder),
                        }
                    }
                }
            }
        }
    };TypeFoldable, const _: () =
    {
        impl<'tcx, R>
            ::rustc_middle::ty::TypeVisitable<::rustc_middle::ty::TyCtxt<'tcx>>
            for QueryResponse<'tcx, R> where
            R: ::rustc_middle::ty::TypeVisitable<::rustc_middle::ty::TyCtxt<'tcx>>
            {
            fn visit_with<__V: ::rustc_middle::ty::TypeVisitor<::rustc_middle::ty::TyCtxt<'tcx>>>(&self,
                __visitor: &mut __V) -> __V::Result {
                match *self {
                    QueryResponse {
                        var_values: ref __binding_0,
                        region_constraints: ref __binding_1,
                        certainty: ref __binding_2,
                        opaque_types: ref __binding_3,
                        value: ref __binding_4 } => {
                        {
                            match ::rustc_middle::ty::VisitorResult::branch(::rustc_middle::ty::TypeVisitable::visit_with(__binding_0,
                                        __visitor)) {
                                ::core::ops::ControlFlow::Continue(()) => {}
                                ::core::ops::ControlFlow::Break(r) => {
                                    return ::rustc_middle::ty::VisitorResult::from_residual(r);
                                }
                            }
                        }
                        {
                            match ::rustc_middle::ty::VisitorResult::branch(::rustc_middle::ty::TypeVisitable::visit_with(__binding_1,
                                        __visitor)) {
                                ::core::ops::ControlFlow::Continue(()) => {}
                                ::core::ops::ControlFlow::Break(r) => {
                                    return ::rustc_middle::ty::VisitorResult::from_residual(r);
                                }
                            }
                        }
                        {
                            match ::rustc_middle::ty::VisitorResult::branch(::rustc_middle::ty::TypeVisitable::visit_with(__binding_2,
                                        __visitor)) {
                                ::core::ops::ControlFlow::Continue(()) => {}
                                ::core::ops::ControlFlow::Break(r) => {
                                    return ::rustc_middle::ty::VisitorResult::from_residual(r);
                                }
                            }
                        }
                        {
                            match ::rustc_middle::ty::VisitorResult::branch(::rustc_middle::ty::TypeVisitable::visit_with(__binding_3,
                                        __visitor)) {
                                ::core::ops::ControlFlow::Continue(()) => {}
                                ::core::ops::ControlFlow::Break(r) => {
                                    return ::rustc_middle::ty::VisitorResult::from_residual(r);
                                }
                            }
                        }
                        {
                            match ::rustc_middle::ty::VisitorResult::branch(::rustc_middle::ty::TypeVisitable::visit_with(__binding_4,
                                        __visitor)) {
                                ::core::ops::ControlFlow::Continue(()) => {}
                                ::core::ops::ControlFlow::Break(r) => {
                                    return ::rustc_middle::ty::VisitorResult::from_residual(r);
                                }
                            }
                        }
                    }
                }
                <__V::Result as ::rustc_middle::ty::VisitorResult>::output()
            }
        }
    };TypeVisitable)]
71pub struct QueryResponse<'tcx, R> {
72    pub var_values: CanonicalVarValues<'tcx>,
73    pub region_constraints: QueryRegionConstraints<'tcx>,
74    pub certainty: Certainty,
75    pub opaque_types: Vec<(ty::OpaqueTypeKey<'tcx>, Ty<'tcx>)>,
76    pub value: R,
77}
78
79#[derive(#[automatically_derived]
impl<'tcx> ::core::clone::Clone for QueryRegionConstraints<'tcx> {
    #[inline]
    fn clone(&self) -> QueryRegionConstraints<'tcx> {
        QueryRegionConstraints {
            outlives: ::core::clone::Clone::clone(&self.outlives),
            assumptions: ::core::clone::Clone::clone(&self.assumptions),
        }
    }
}Clone, #[automatically_derived]
impl<'tcx> ::core::fmt::Debug for QueryRegionConstraints<'tcx> {
    #[inline]
    fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
        ::core::fmt::Formatter::debug_struct_field2_finish(f,
            "QueryRegionConstraints", "outlives", &self.outlives,
            "assumptions", &&self.assumptions)
    }
}Debug, #[automatically_derived]
impl<'tcx> ::core::default::Default for QueryRegionConstraints<'tcx> {
    #[inline]
    fn default() -> QueryRegionConstraints<'tcx> {
        QueryRegionConstraints {
            outlives: ::core::default::Default::default(),
            assumptions: ::core::default::Default::default(),
        }
    }
}Default, #[automatically_derived]
impl<'tcx> ::core::cmp::PartialEq for QueryRegionConstraints<'tcx> {
    #[inline]
    fn eq(&self, other: &QueryRegionConstraints<'tcx>) -> bool {
        self.outlives == other.outlives &&
            self.assumptions == other.assumptions
    }
}PartialEq, #[automatically_derived]
impl<'tcx> ::core::cmp::Eq for QueryRegionConstraints<'tcx> {
    #[inline]
    #[doc(hidden)]
    #[coverage(off)]
    fn assert_receiver_is_total_eq(&self) -> () {
        let _:
                ::core::cmp::AssertParamIsEq<Vec<QueryOutlivesConstraint<'tcx>>>;
        let _:
                ::core::cmp::AssertParamIsEq<Vec<ty::ArgOutlivesPredicate<'tcx>>>;
    }
}Eq, #[automatically_derived]
impl<'tcx> ::core::hash::Hash for QueryRegionConstraints<'tcx> {
    #[inline]
    fn hash<__H: ::core::hash::Hasher>(&self, state: &mut __H) -> () {
        ::core::hash::Hash::hash(&self.outlives, state);
        ::core::hash::Hash::hash(&self.assumptions, state)
    }
}Hash)]
80#[derive(const _: () =
    {
        impl<'tcx, '__ctx>
            ::rustc_data_structures::stable_hasher::HashStable<::rustc_query_system::ich::StableHashingContext<'__ctx>>
            for QueryRegionConstraints<'tcx> {
            #[inline]
            fn hash_stable(&self,
                __hcx:
                    &mut ::rustc_query_system::ich::StableHashingContext<'__ctx>,
                __hasher:
                    &mut ::rustc_data_structures::stable_hasher::StableHasher) {
                match *self {
                    QueryRegionConstraints {
                        outlives: ref __binding_0, assumptions: ref __binding_1 } =>
                        {
                        { __binding_0.hash_stable(__hcx, __hasher); }
                        { __binding_1.hash_stable(__hcx, __hasher); }
                    }
                }
            }
        }
    };HashStable, const _: () =
    {
        impl<'tcx>
            ::rustc_middle::ty::TypeFoldable<::rustc_middle::ty::TyCtxt<'tcx>>
            for QueryRegionConstraints<'tcx> {
            fn try_fold_with<__F: ::rustc_middle::ty::FallibleTypeFolder<::rustc_middle::ty::TyCtxt<'tcx>>>(self,
                __folder: &mut __F) -> Result<Self, __F::Error> {
                Ok(match self {
                        QueryRegionConstraints {
                            outlives: __binding_0, assumptions: __binding_1 } => {
                            QueryRegionConstraints {
                                outlives: ::rustc_middle::ty::TypeFoldable::try_fold_with(__binding_0,
                                        __folder)?,
                                assumptions: ::rustc_middle::ty::TypeFoldable::try_fold_with(__binding_1,
                                        __folder)?,
                            }
                        }
                    })
            }
            fn fold_with<__F: ::rustc_middle::ty::TypeFolder<::rustc_middle::ty::TyCtxt<'tcx>>>(self,
                __folder: &mut __F) -> Self {
                match self {
                    QueryRegionConstraints {
                        outlives: __binding_0, assumptions: __binding_1 } => {
                        QueryRegionConstraints {
                            outlives: ::rustc_middle::ty::TypeFoldable::fold_with(__binding_0,
                                __folder),
                            assumptions: ::rustc_middle::ty::TypeFoldable::fold_with(__binding_1,
                                __folder),
                        }
                    }
                }
            }
        }
    };TypeFoldable, const _: () =
    {
        impl<'tcx>
            ::rustc_middle::ty::TypeVisitable<::rustc_middle::ty::TyCtxt<'tcx>>
            for QueryRegionConstraints<'tcx> {
            fn visit_with<__V: ::rustc_middle::ty::TypeVisitor<::rustc_middle::ty::TyCtxt<'tcx>>>(&self,
                __visitor: &mut __V) -> __V::Result {
                match *self {
                    QueryRegionConstraints {
                        outlives: ref __binding_0, assumptions: ref __binding_1 } =>
                        {
                        {
                            match ::rustc_middle::ty::VisitorResult::branch(::rustc_middle::ty::TypeVisitable::visit_with(__binding_0,
                                        __visitor)) {
                                ::core::ops::ControlFlow::Continue(()) => {}
                                ::core::ops::ControlFlow::Break(r) => {
                                    return ::rustc_middle::ty::VisitorResult::from_residual(r);
                                }
                            }
                        }
                        {
                            match ::rustc_middle::ty::VisitorResult::branch(::rustc_middle::ty::TypeVisitable::visit_with(__binding_1,
                                        __visitor)) {
                                ::core::ops::ControlFlow::Continue(()) => {}
                                ::core::ops::ControlFlow::Break(r) => {
                                    return ::rustc_middle::ty::VisitorResult::from_residual(r);
                                }
                            }
                        }
                    }
                }
                <__V::Result as ::rustc_middle::ty::VisitorResult>::output()
            }
        }
    };TypeVisitable)]
81pub struct QueryRegionConstraints<'tcx> {
82    pub outlives: Vec<QueryOutlivesConstraint<'tcx>>,
83    pub assumptions: Vec<ty::ArgOutlivesPredicate<'tcx>>,
84}
85
86impl QueryRegionConstraints<'_> {
87    /// Represents an empty (trivially true) set of region constraints.
88    ///
89    /// FIXME(higher_ranked_auto): This could still just be true if there are only assumptions?
90    /// Because I don't expect for us to get cases where an assumption from one query would
91    /// discharge a requirement from another query, which is a potential problem if we did throw
92    /// away these assumptions because there were no constraints.
93    pub fn is_empty(&self) -> bool {
94        self.outlives.is_empty() && self.assumptions.is_empty()
95    }
96}
97
98pub type CanonicalQueryResponse<'tcx, T> = &'tcx Canonical<'tcx, QueryResponse<'tcx, T>>;
99
100/// Indicates whether or not we were able to prove the query to be
101/// true.
102#[derive(#[automatically_derived]
impl ::core::marker::Copy for Certainty { }Copy, #[automatically_derived]
impl ::core::clone::Clone for Certainty {
    #[inline]
    fn clone(&self) -> Certainty { *self }
}Clone, #[automatically_derived]
impl ::core::fmt::Debug for Certainty {
    #[inline]
    fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
        ::core::fmt::Formatter::write_str(f,
            match self {
                Certainty::Proven => "Proven",
                Certainty::Ambiguous => "Ambiguous",
            })
    }
}Debug, const _: () =
    {
        impl<'__ctx>
            ::rustc_data_structures::stable_hasher::HashStable<::rustc_query_system::ich::StableHashingContext<'__ctx>>
            for Certainty {
            #[inline]
            fn hash_stable(&self,
                __hcx:
                    &mut ::rustc_query_system::ich::StableHashingContext<'__ctx>,
                __hasher:
                    &mut ::rustc_data_structures::stable_hasher::StableHasher) {
                ::std::mem::discriminant(self).hash_stable(__hcx, __hasher);
                match *self {
                    Certainty::Proven => {}
                    Certainty::Ambiguous => {}
                }
            }
        }
    };HashStable)]
103pub enum Certainty {
104    /// The query is known to be true, presuming that you apply the
105    /// given `var_values` and the region-constraints are satisfied.
106    Proven,
107
108    /// The query is not known to be true, but also not known to be
109    /// false. The `var_values` represent *either* values that must
110    /// hold in order for the query to be true, or helpful tips that
111    /// *might* make it true. Currently rustc's trait solver cannot
112    /// distinguish the two (e.g., due to our preference for where
113    /// clauses over impls).
114    ///
115    /// After some unification and things have been done, it makes
116    /// sense to try and prove again -- of course, at that point, the
117    /// canonical form will be different, making this a distinct
118    /// query.
119    Ambiguous,
120}
121
122impl Certainty {
123    pub fn is_proven(&self) -> bool {
124        match self {
125            Certainty::Proven => true,
126            Certainty::Ambiguous => false,
127        }
128    }
129}
130
131impl<'tcx, R> QueryResponse<'tcx, R> {
132    pub fn is_proven(&self) -> bool {
133        self.certainty.is_proven()
134    }
135}
136
137pub type QueryOutlivesConstraint<'tcx> = (ty::ArgOutlivesPredicate<'tcx>, ConstraintCategory<'tcx>);
138
139#[derive(#[automatically_derived]
impl<'tcx> ::core::default::Default for CanonicalParamEnvCache<'tcx> {
    #[inline]
    fn default() -> CanonicalParamEnvCache<'tcx> {
        CanonicalParamEnvCache { map: ::core::default::Default::default() }
    }
}Default)]
140pub struct CanonicalParamEnvCache<'tcx> {
141    map: Lock<
142        FxHashMap<
143            ty::ParamEnv<'tcx>,
144            (Canonical<'tcx, ty::ParamEnv<'tcx>>, &'tcx [GenericArg<'tcx>]),
145        >,
146    >,
147}
148
149impl<'tcx> CanonicalParamEnvCache<'tcx> {
150    /// Gets the cached canonical form of `key` or executes
151    /// `canonicalize_op` and caches the result if not present.
152    ///
153    /// `canonicalize_op` is intentionally not allowed to be a closure to
154    /// statically prevent it from capturing `InferCtxt` and resolving
155    /// inference variables, which invalidates the cache.
156    pub fn get_or_insert(
157        &self,
158        tcx: TyCtxt<'tcx>,
159        key: ty::ParamEnv<'tcx>,
160        state: &mut OriginalQueryValues<'tcx>,
161        canonicalize_op: fn(
162            TyCtxt<'tcx>,
163            ty::ParamEnv<'tcx>,
164            &mut OriginalQueryValues<'tcx>,
165        ) -> Canonical<'tcx, ty::ParamEnv<'tcx>>,
166    ) -> Canonical<'tcx, ty::ParamEnv<'tcx>> {
167        if !key.has_type_flags(
168            TypeFlags::HAS_INFER | TypeFlags::HAS_PLACEHOLDER | TypeFlags::HAS_FREE_REGIONS,
169        ) {
170            return Canonical {
171                max_universe: ty::UniverseIndex::ROOT,
172                var_kinds: List::empty(),
173                value: key,
174            };
175        }
176
177        match (&state.var_values.len(), &0) {
    (left_val, right_val) => {
        if !(*left_val == *right_val) {
            let kind = ::core::panicking::AssertKind::Eq;
            ::core::panicking::assert_failed(kind, &*left_val, &*right_val,
                ::core::option::Option::None);
        }
    }
};assert_eq!(state.var_values.len(), 0);
178        match (&state.universe_map.len(), &1) {
    (left_val, right_val) => {
        if !(*left_val == *right_val) {
            let kind = ::core::panicking::AssertKind::Eq;
            ::core::panicking::assert_failed(kind, &*left_val, &*right_val,
                ::core::option::Option::None);
        }
    }
};assert_eq!(state.universe_map.len(), 1);
179        if true {
    match (&&*state.universe_map, &&[ty::UniverseIndex::ROOT]) {
        (left_val, right_val) => {
            if !(*left_val == *right_val) {
                let kind = ::core::panicking::AssertKind::Eq;
                ::core::panicking::assert_failed(kind, &*left_val,
                    &*right_val, ::core::option::Option::None);
            }
        }
    };
};debug_assert_eq!(&*state.universe_map, &[ty::UniverseIndex::ROOT]);
180
181        match self.map.borrow().entry(key) {
182            Entry::Occupied(e) => {
183                let (canonical, var_values) = e.get();
184                if truecfg!(debug_assertions) {
185                    let mut state = state.clone();
186                    let rerun_canonical = canonicalize_op(tcx, key, &mut state);
187                    match (&rerun_canonical, &*canonical) {
    (left_val, right_val) => {
        if !(*left_val == *right_val) {
            let kind = ::core::panicking::AssertKind::Eq;
            ::core::panicking::assert_failed(kind, &*left_val, &*right_val,
                ::core::option::Option::None);
        }
    }
};assert_eq!(rerun_canonical, *canonical);
188                    let OriginalQueryValues { var_values: rerun_var_values, universe_map } = state;
189                    match (&universe_map.len(), &1) {
    (left_val, right_val) => {
        if !(*left_val == *right_val) {
            let kind = ::core::panicking::AssertKind::Eq;
            ::core::panicking::assert_failed(kind, &*left_val, &*right_val,
                ::core::option::Option::None);
        }
    }
};assert_eq!(universe_map.len(), 1);
190                    match (&**var_values, &*rerun_var_values) {
    (left_val, right_val) => {
        if !(*left_val == *right_val) {
            let kind = ::core::panicking::AssertKind::Eq;
            ::core::panicking::assert_failed(kind, &*left_val, &*right_val,
                ::core::option::Option::None);
        }
    }
};assert_eq!(**var_values, *rerun_var_values);
191                }
192                state.var_values.extend_from_slice(var_values);
193                *canonical
194            }
195            Entry::Vacant(e) => {
196                let canonical = canonicalize_op(tcx, key, state);
197                let OriginalQueryValues { var_values, universe_map } = state;
198                match (&universe_map.len(), &1) {
    (left_val, right_val) => {
        if !(*left_val == *right_val) {
            let kind = ::core::panicking::AssertKind::Eq;
            ::core::panicking::assert_failed(kind, &*left_val, &*right_val,
                ::core::option::Option::None);
        }
    }
};assert_eq!(universe_map.len(), 1);
199                e.insert((canonical, tcx.arena.alloc_slice(var_values)));
200                canonical
201            }
202        }
203    }
204}