1use 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;
30pub use rustc_type_ir::{CanonicalTyVarKind, CanonicalVarKind};
31use smallvec::SmallVec;
32
33use crate::mir::ConstraintCategory;
34use crate::ty::{self, GenericArg, List, Ty, TyCtxt, TypeFlags, TypeVisitableExt};
35
36pub type CanonicalQueryInput<'tcx, V> = ir::CanonicalQueryInput<TyCtxt<'tcx>, V>;
37pub type Canonical<'tcx, V> = ir::Canonical<TyCtxt<'tcx>, V>;
38pub type CanonicalVarInfo<'tcx> = ir::CanonicalVarInfo<TyCtxt<'tcx>>;
39pub type CanonicalVarValues<'tcx> = ir::CanonicalVarValues<TyCtxt<'tcx>>;
40pub type CanonicalVarInfos<'tcx> = &'tcx List<CanonicalVarInfo<'tcx>>;
41
42impl<'tcx> ty::TypeFoldable<TyCtxt<'tcx>> for CanonicalVarInfos<'tcx> {
43 fn try_fold_with<F: ty::FallibleTypeFolder<TyCtxt<'tcx>>>(
44 self,
45 folder: &mut F,
46 ) -> Result<Self, F::Error> {
47 ty::util::fold_list(self, folder, |tcx, v| tcx.mk_canonical_var_infos(v))
48 }
49}
50
51#[derive(Clone, Debug)]
56pub struct OriginalQueryValues<'tcx> {
57 pub universe_map: SmallVec<[ty::UniverseIndex; 4]>,
62
63 pub var_values: SmallVec<[GenericArg<'tcx>; 8]>,
66}
67
68impl<'tcx> Default for OriginalQueryValues<'tcx> {
69 fn default() -> Self {
70 let mut universe_map = SmallVec::default();
71 universe_map.push(ty::UniverseIndex::ROOT);
72
73 Self { universe_map, var_values: SmallVec::default() }
74 }
75}
76
77#[derive(Clone, Debug, HashStable, TypeFoldable, TypeVisitable)]
81pub struct QueryResponse<'tcx, R> {
82 pub var_values: CanonicalVarValues<'tcx>,
83 pub region_constraints: QueryRegionConstraints<'tcx>,
84 pub certainty: Certainty,
85 pub opaque_types: Vec<(ty::OpaqueTypeKey<'tcx>, Ty<'tcx>)>,
86 pub value: R,
87}
88
89#[derive(Clone, Debug, Default, PartialEq, Eq, Hash)]
90#[derive(HashStable, TypeFoldable, TypeVisitable)]
91pub struct QueryRegionConstraints<'tcx> {
92 pub outlives: Vec<QueryOutlivesConstraint<'tcx>>,
93}
94
95impl QueryRegionConstraints<'_> {
96 pub fn is_empty(&self) -> bool {
99 self.outlives.is_empty()
100 }
101}
102
103pub type CanonicalQueryResponse<'tcx, T> = &'tcx Canonical<'tcx, QueryResponse<'tcx, T>>;
104
105#[derive(Copy, Clone, Debug, HashStable)]
108pub enum Certainty {
109 Proven,
112
113 Ambiguous,
125}
126
127impl Certainty {
128 pub fn is_proven(&self) -> bool {
129 match self {
130 Certainty::Proven => true,
131 Certainty::Ambiguous => false,
132 }
133 }
134}
135
136impl<'tcx, R> QueryResponse<'tcx, R> {
137 pub fn is_proven(&self) -> bool {
138 self.certainty.is_proven()
139 }
140}
141
142pub type QueryOutlivesConstraint<'tcx> =
143 (ty::OutlivesPredicate<'tcx, GenericArg<'tcx>>, ConstraintCategory<'tcx>);
144
145#[derive(Default)]
146pub struct CanonicalParamEnvCache<'tcx> {
147 map: Lock<
148 FxHashMap<
149 ty::ParamEnv<'tcx>,
150 (Canonical<'tcx, ty::ParamEnv<'tcx>>, &'tcx [GenericArg<'tcx>]),
151 >,
152 >,
153}
154
155impl<'tcx> CanonicalParamEnvCache<'tcx> {
156 pub fn get_or_insert(
163 &self,
164 tcx: TyCtxt<'tcx>,
165 key: ty::ParamEnv<'tcx>,
166 state: &mut OriginalQueryValues<'tcx>,
167 canonicalize_op: fn(
168 TyCtxt<'tcx>,
169 ty::ParamEnv<'tcx>,
170 &mut OriginalQueryValues<'tcx>,
171 ) -> Canonical<'tcx, ty::ParamEnv<'tcx>>,
172 ) -> Canonical<'tcx, ty::ParamEnv<'tcx>> {
173 if !key.has_type_flags(
174 TypeFlags::HAS_INFER | TypeFlags::HAS_PLACEHOLDER | TypeFlags::HAS_FREE_REGIONS,
175 ) {
176 return Canonical {
177 max_universe: ty::UniverseIndex::ROOT,
178 variables: List::empty(),
179 value: key,
180 };
181 }
182
183 assert_eq!(state.var_values.len(), 0);
184 assert_eq!(state.universe_map.len(), 1);
185 debug_assert_eq!(&*state.universe_map, &[ty::UniverseIndex::ROOT]);
186
187 match self.map.borrow().entry(key) {
188 Entry::Occupied(e) => {
189 let (canonical, var_values) = e.get();
190 if cfg!(debug_assertions) {
191 let mut state = state.clone();
192 let rerun_canonical = canonicalize_op(tcx, key, &mut state);
193 assert_eq!(rerun_canonical, *canonical);
194 let OriginalQueryValues { var_values: rerun_var_values, universe_map } = state;
195 assert_eq!(universe_map.len(), 1);
196 assert_eq!(**var_values, *rerun_var_values);
197 }
198 state.var_values.extend_from_slice(var_values);
199 *canonical
200 }
201 Entry::Vacant(e) => {
202 let canonical = canonicalize_op(tcx, key, state);
203 let OriginalQueryValues { var_values, universe_map } = state;
204 assert_eq!(universe_map.len(), 1);
205 e.insert((canonical, tcx.arena.alloc_slice(var_values)));
206 canonical
207 }
208 }
209 }
210}