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;
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#[derive(Clone, Debug)]
46pub struct OriginalQueryValues<'tcx> {
47 pub universe_map: SmallVec<[ty::UniverseIndex; 4]>,
52
53 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#[derive(Clone, Debug, HashStable, TypeFoldable, 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(Clone, Debug, Default, PartialEq, Eq, Hash)]
80#[derive(HashStable, TypeFoldable, TypeVisitable)]
81pub struct QueryRegionConstraints<'tcx> {
82 pub outlives: Vec<QueryOutlivesConstraint<'tcx>>,
83 pub assumptions: Vec<ty::ArgOutlivesPredicate<'tcx>>,
84}
85
86impl QueryRegionConstraints<'_> {
87 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#[derive(Copy, Clone, Debug, HashStable)]
103pub enum Certainty {
104 Proven,
107
108 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(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 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 variables: List::empty(),
173 value: key,
174 };
175 }
176
177 assert_eq!(state.var_values.len(), 0);
178 assert_eq!(state.universe_map.len(), 1);
179 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 cfg!(debug_assertions) {
185 let mut state = state.clone();
186 let rerun_canonical = canonicalize_op(tcx, key, &mut state);
187 assert_eq!(rerun_canonical, *canonical);
188 let OriginalQueryValues { var_values: rerun_var_values, universe_map } = state;
189 assert_eq!(universe_map.len(), 1);
190 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 assert_eq!(universe_map.len(), 1);
199 e.insert((canonical, tcx.arena.alloc_slice(var_values)));
200 canonical
201 }
202 }
203 }
204}