rustc_middle/infer/
canonical.rs1use 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;
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 CanonicalVarKind<'tcx> = ir::CanonicalVarKind<TyCtxt<'tcx>>;
39pub type CanonicalVarValues<'tcx> = ir::CanonicalVarValues<TyCtxt<'tcx>>;
40pub type CanonicalVarKinds<'tcx> = &'tcx List<CanonicalVarKind<'tcx>>;
41
42#[derive(Clone, Debug)]
47pub struct OriginalQueryValues<'tcx> {
48 pub universe_map: SmallVec<[ty::UniverseIndex; 4]>,
53
54 pub var_values: SmallVec<[GenericArg<'tcx>; 8]>,
57}
58
59impl<'tcx> Default for OriginalQueryValues<'tcx> {
60 fn default() -> Self {
61 let mut universe_map = SmallVec::default();
62 universe_map.push(ty::UniverseIndex::ROOT);
63
64 Self { universe_map, var_values: SmallVec::default() }
65 }
66}
67
68#[derive(Clone, Debug, HashStable, TypeFoldable, TypeVisitable)]
72pub struct QueryResponse<'tcx, R> {
73 pub var_values: CanonicalVarValues<'tcx>,
74 pub region_constraints: QueryRegionConstraints<'tcx>,
75 pub certainty: Certainty,
76 pub opaque_types: Vec<(ty::OpaqueTypeKey<'tcx>, Ty<'tcx>)>,
77 pub value: R,
78}
79
80#[derive(Clone, Debug, Default, PartialEq, Eq, Hash)]
81#[derive(HashStable, TypeFoldable, TypeVisitable)]
82pub struct QueryRegionConstraints<'tcx> {
83 pub outlives: Vec<QueryOutlivesConstraint<'tcx>>,
84 pub assumptions: Vec<ty::ArgOutlivesPredicate<'tcx>>,
85}
86
87impl QueryRegionConstraints<'_> {
88 pub fn is_empty(&self) -> bool {
95 self.outlives.is_empty() && self.assumptions.is_empty()
96 }
97}
98
99pub type CanonicalQueryResponse<'tcx, T> = &'tcx Canonical<'tcx, QueryResponse<'tcx, T>>;
100
101#[derive(Copy, Clone, Debug, HashStable)]
104pub enum Certainty {
105 Proven,
108
109 Ambiguous,
121}
122
123impl Certainty {
124 pub fn is_proven(&self) -> bool {
125 match self {
126 Certainty::Proven => true,
127 Certainty::Ambiguous => false,
128 }
129 }
130}
131
132impl<'tcx, R> QueryResponse<'tcx, R> {
133 pub fn is_proven(&self) -> bool {
134 self.certainty.is_proven()
135 }
136}
137
138pub type QueryOutlivesConstraint<'tcx> = (ty::ArgOutlivesPredicate<'tcx>, ConstraintCategory<'tcx>);
139
140#[derive(Default)]
141pub struct CanonicalParamEnvCache<'tcx> {
142 map: Lock<
143 FxHashMap<
144 ty::ParamEnv<'tcx>,
145 (Canonical<'tcx, ty::ParamEnv<'tcx>>, &'tcx [GenericArg<'tcx>]),
146 >,
147 >,
148}
149
150impl<'tcx> CanonicalParamEnvCache<'tcx> {
151 pub fn get_or_insert(
158 &self,
159 tcx: TyCtxt<'tcx>,
160 key: ty::ParamEnv<'tcx>,
161 state: &mut OriginalQueryValues<'tcx>,
162 canonicalize_op: fn(
163 TyCtxt<'tcx>,
164 ty::ParamEnv<'tcx>,
165 &mut OriginalQueryValues<'tcx>,
166 ) -> Canonical<'tcx, ty::ParamEnv<'tcx>>,
167 ) -> Canonical<'tcx, ty::ParamEnv<'tcx>> {
168 if !key.has_type_flags(
169 TypeFlags::HAS_INFER | TypeFlags::HAS_PLACEHOLDER | TypeFlags::HAS_FREE_REGIONS,
170 ) {
171 return Canonical {
172 max_universe: ty::UniverseIndex::ROOT,
173 variables: List::empty(),
174 value: key,
175 };
176 }
177
178 assert_eq!(state.var_values.len(), 0);
179 assert_eq!(state.universe_map.len(), 1);
180 debug_assert_eq!(&*state.universe_map, &[ty::UniverseIndex::ROOT]);
181
182 match self.map.borrow().entry(key) {
183 Entry::Occupied(e) => {
184 let (canonical, var_values) = e.get();
185 if cfg!(debug_assertions) {
186 let mut state = state.clone();
187 let rerun_canonical = canonicalize_op(tcx, key, &mut state);
188 assert_eq!(rerun_canonical, *canonical);
189 let OriginalQueryValues { var_values: rerun_var_values, universe_map } = state;
190 assert_eq!(universe_map.len(), 1);
191 assert_eq!(**var_values, *rerun_var_values);
192 }
193 state.var_values.extend_from_slice(var_values);
194 *canonical
195 }
196 Entry::Vacant(e) => {
197 let canonical = canonicalize_op(tcx, key, state);
198 let OriginalQueryValues { var_values, universe_map } = state;
199 assert_eq!(universe_map.len(), 1);
200 e.insert((canonical, tcx.arena.alloc_slice(var_values)));
201 canonical
202 }
203 }
204 }
205}