rustc_middle/infer/
canonical.rs
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
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}
85
86impl QueryRegionConstraints<'_> {
87 pub fn is_empty(&self) -> bool {
90 self.outlives.is_empty()
91 }
92}
93
94pub type CanonicalQueryResponse<'tcx, T> = &'tcx Canonical<'tcx, QueryResponse<'tcx, T>>;
95
96#[derive(Copy, Clone, Debug, HashStable)]
99pub enum Certainty {
100 Proven,
103
104 Ambiguous,
116}
117
118impl Certainty {
119 pub fn is_proven(&self) -> bool {
120 match self {
121 Certainty::Proven => true,
122 Certainty::Ambiguous => false,
123 }
124 }
125}
126
127impl<'tcx, R> QueryResponse<'tcx, R> {
128 pub fn is_proven(&self) -> bool {
129 self.certainty.is_proven()
130 }
131}
132
133pub type QueryOutlivesConstraint<'tcx> =
134 (ty::OutlivesPredicate<'tcx, GenericArg<'tcx>>, ConstraintCategory<'tcx>);
135
136#[derive(Default)]
137pub struct CanonicalParamEnvCache<'tcx> {
138 map: Lock<
139 FxHashMap<
140 ty::ParamEnv<'tcx>,
141 (Canonical<'tcx, ty::ParamEnv<'tcx>>, &'tcx [GenericArg<'tcx>]),
142 >,
143 >,
144}
145
146impl<'tcx> CanonicalParamEnvCache<'tcx> {
147 pub fn get_or_insert(
154 &self,
155 tcx: TyCtxt<'tcx>,
156 key: ty::ParamEnv<'tcx>,
157 state: &mut OriginalQueryValues<'tcx>,
158 canonicalize_op: fn(
159 TyCtxt<'tcx>,
160 ty::ParamEnv<'tcx>,
161 &mut OriginalQueryValues<'tcx>,
162 ) -> Canonical<'tcx, ty::ParamEnv<'tcx>>,
163 ) -> Canonical<'tcx, ty::ParamEnv<'tcx>> {
164 if !key.has_type_flags(
165 TypeFlags::HAS_INFER | TypeFlags::HAS_PLACEHOLDER | TypeFlags::HAS_FREE_REGIONS,
166 ) {
167 return Canonical {
168 max_universe: ty::UniverseIndex::ROOT,
169 variables: List::empty(),
170 value: key,
171 };
172 }
173
174 assert_eq!(state.var_values.len(), 0);
175 assert_eq!(state.universe_map.len(), 1);
176 debug_assert_eq!(&*state.universe_map, &[ty::UniverseIndex::ROOT]);
177
178 match self.map.borrow().entry(key) {
179 Entry::Occupied(e) => {
180 let (canonical, var_values) = e.get();
181 if cfg!(debug_assertions) {
182 let mut state = state.clone();
183 let rerun_canonical = canonicalize_op(tcx, key, &mut state);
184 assert_eq!(rerun_canonical, *canonical);
185 let OriginalQueryValues { var_values: rerun_var_values, universe_map } = state;
186 assert_eq!(universe_map.len(), 1);
187 assert_eq!(**var_values, *rerun_var_values);
188 }
189 state.var_values.extend_from_slice(var_values);
190 *canonical
191 }
192 Entry::Vacant(e) => {
193 let canonical = canonicalize_op(tcx, key, state);
194 let OriginalQueryValues { var_values, universe_map } = state;
195 assert_eq!(universe_map.len(), 1);
196 e.insert((canonical, tcx.arena.alloc_slice(var_values)));
197 canonical
198 }
199 }
200 }
201}