1use std::fmt;
2use std::hash::Hash;
3use std::ops::Index;
4
5use derive_where::derive_where;
6#[cfg(feature = "nightly")]
7use rustc_macros::{Decodable_NoContext, Encodable_NoContext, HashStable_NoContext};
8use rustc_type_ir_macros::{Lift_Generic, TypeFoldable_Generic, TypeVisitable_Generic};
9
10use crate::data_structures::HashMap;
11use crate::inherent::*;
12use crate::{self as ty, Interner, TypingMode, UniverseIndex};
13
14#[derive_where(Clone, Hash, PartialEq, Debug; I: Interner, V)]
15#[derive_where(Copy; I: Interner, V: Copy)]
16#[cfg_attr(
17 feature = "nightly",
18 derive(Encodable_NoContext, Decodable_NoContext, HashStable_NoContext)
19)]
20pub struct CanonicalQueryInput<I: Interner, V> {
21 pub canonical: Canonical<I, V>,
22 pub typing_mode: TypingMode<I>,
23}
24
25impl<I: Interner, V: Eq> Eq for CanonicalQueryInput<I, V> {}
26
27#[derive_where(Clone, Hash, PartialEq, Debug; I: Interner, V)]
31#[derive_where(Copy; I: Interner, V: Copy)]
32#[cfg_attr(
33 feature = "nightly",
34 derive(Encodable_NoContext, Decodable_NoContext, HashStable_NoContext)
35)]
36pub struct Canonical<I: Interner, V> {
37 pub value: V,
38 pub max_universe: UniverseIndex,
39 pub variables: I::CanonicalVarKinds,
40}
41
42impl<I: Interner, V: Eq> Eq for Canonical<I, V> {}
43
44impl<I: Interner, V> Canonical<I, V> {
45 pub fn unchecked_map<W>(self, map_op: impl FnOnce(V) -> W) -> Canonical<I, W> {
69 let Canonical { max_universe, variables, value } = self;
70 Canonical { max_universe, variables, value: map_op(value) }
71 }
72}
73
74impl<I: Interner, V: fmt::Display> fmt::Display for Canonical<I, V> {
75 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
76 let Self { value, max_universe, variables } = self;
77 write!(
78 f,
79 "Canonical {{ value: {value}, max_universe: {max_universe:?}, variables: {variables:?} }}",
80 )
81 }
82}
83
84#[derive_where(Clone, Copy, Hash, PartialEq, Debug; I: Interner)]
89#[cfg_attr(
90 feature = "nightly",
91 derive(Decodable_NoContext, Encodable_NoContext, HashStable_NoContext)
92)]
93pub enum CanonicalVarKind<I: Interner> {
94 Ty(CanonicalTyVarKind),
96
97 PlaceholderTy(I::PlaceholderTy),
99
100 Region(UniverseIndex),
102
103 PlaceholderRegion(I::PlaceholderRegion),
107
108 Const(UniverseIndex),
110
111 PlaceholderConst(I::PlaceholderConst),
113}
114
115impl<I: Interner> Eq for CanonicalVarKind<I> {}
116
117impl<I: Interner> CanonicalVarKind<I> {
118 pub fn universe(self) -> UniverseIndex {
119 match self {
120 CanonicalVarKind::Ty(CanonicalTyVarKind::General(ui)) => ui,
121 CanonicalVarKind::Region(ui) => ui,
122 CanonicalVarKind::Const(ui) => ui,
123 CanonicalVarKind::PlaceholderTy(placeholder) => placeholder.universe(),
124 CanonicalVarKind::PlaceholderRegion(placeholder) => placeholder.universe(),
125 CanonicalVarKind::PlaceholderConst(placeholder) => placeholder.universe(),
126 CanonicalVarKind::Ty(CanonicalTyVarKind::Float | CanonicalTyVarKind::Int) => {
127 UniverseIndex::ROOT
128 }
129 }
130 }
131
132 pub fn with_updated_universe(self, ui: UniverseIndex) -> CanonicalVarKind<I> {
137 match self {
138 CanonicalVarKind::Ty(CanonicalTyVarKind::General(_)) => {
139 CanonicalVarKind::Ty(CanonicalTyVarKind::General(ui))
140 }
141 CanonicalVarKind::Region(_) => CanonicalVarKind::Region(ui),
142 CanonicalVarKind::Const(_) => CanonicalVarKind::Const(ui),
143
144 CanonicalVarKind::PlaceholderTy(placeholder) => {
145 CanonicalVarKind::PlaceholderTy(placeholder.with_updated_universe(ui))
146 }
147 CanonicalVarKind::PlaceholderRegion(placeholder) => {
148 CanonicalVarKind::PlaceholderRegion(placeholder.with_updated_universe(ui))
149 }
150 CanonicalVarKind::PlaceholderConst(placeholder) => {
151 CanonicalVarKind::PlaceholderConst(placeholder.with_updated_universe(ui))
152 }
153 CanonicalVarKind::Ty(CanonicalTyVarKind::Int | CanonicalTyVarKind::Float) => {
154 assert_eq!(ui, UniverseIndex::ROOT);
155 self
156 }
157 }
158 }
159
160 pub fn is_existential(self) -> bool {
161 match self {
162 CanonicalVarKind::Ty(_) => true,
163 CanonicalVarKind::PlaceholderTy(_) => false,
164 CanonicalVarKind::Region(_) => true,
165 CanonicalVarKind::PlaceholderRegion(..) => false,
166 CanonicalVarKind::Const(_) => true,
167 CanonicalVarKind::PlaceholderConst(_) => false,
168 }
169 }
170
171 pub fn is_region(self) -> bool {
172 match self {
173 CanonicalVarKind::Region(_) | CanonicalVarKind::PlaceholderRegion(_) => true,
174 CanonicalVarKind::Ty(_)
175 | CanonicalVarKind::PlaceholderTy(_)
176 | CanonicalVarKind::Const(_)
177 | CanonicalVarKind::PlaceholderConst(_) => false,
178 }
179 }
180
181 pub fn expect_placeholder_index(self) -> usize {
182 match self {
183 CanonicalVarKind::Ty(_) | CanonicalVarKind::Region(_) | CanonicalVarKind::Const(_) => {
184 panic!("expected placeholder: {self:?}")
185 }
186
187 CanonicalVarKind::PlaceholderRegion(placeholder) => placeholder.var().as_usize(),
188 CanonicalVarKind::PlaceholderTy(placeholder) => placeholder.var().as_usize(),
189 CanonicalVarKind::PlaceholderConst(placeholder) => placeholder.var().as_usize(),
190 }
191 }
192}
193
194#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
200#[cfg_attr(
201 feature = "nightly",
202 derive(Decodable_NoContext, Encodable_NoContext, HashStable_NoContext)
203)]
204pub enum CanonicalTyVarKind {
205 General(UniverseIndex),
207
208 Int,
210
211 Float,
213}
214
215#[derive_where(Clone, Copy, Hash, PartialEq, Debug; I: Interner)]
225#[cfg_attr(
226 feature = "nightly",
227 derive(Encodable_NoContext, Decodable_NoContext, HashStable_NoContext)
228)]
229#[derive(TypeVisitable_Generic, TypeFoldable_Generic, Lift_Generic)]
230pub struct CanonicalVarValues<I: Interner> {
231 pub var_values: I::GenericArgs,
232}
233
234impl<I: Interner> Eq for CanonicalVarValues<I> {}
235
236impl<I: Interner> CanonicalVarValues<I> {
237 pub fn is_identity(&self) -> bool {
238 self.var_values.iter().enumerate().all(|(bv, arg)| match arg.kind() {
239 ty::GenericArgKind::Lifetime(r) => {
240 matches!(r.kind(), ty::ReBound(ty::INNERMOST, br) if br.var().as_usize() == bv)
241 }
242 ty::GenericArgKind::Type(ty) => {
243 matches!(ty.kind(), ty::Bound(ty::INNERMOST, bt) if bt.var().as_usize() == bv)
244 }
245 ty::GenericArgKind::Const(ct) => {
246 matches!(ct.kind(), ty::ConstKind::Bound(ty::INNERMOST, bc) if bc.var().as_usize() == bv)
247 }
248 })
249 }
250
251 pub fn is_identity_modulo_regions(&self) -> bool {
252 let mut var = ty::BoundVar::ZERO;
253 for arg in self.var_values.iter() {
254 match arg.kind() {
255 ty::GenericArgKind::Lifetime(r) => {
256 if matches!(r.kind(), ty::ReBound(ty::INNERMOST, br) if var == br.var()) {
257 var = var + 1;
258 } else {
259 }
261 }
262 ty::GenericArgKind::Type(ty) => {
263 if matches!(ty.kind(), ty::Bound(ty::INNERMOST, bt) if var == bt.var()) {
264 var = var + 1;
265 } else {
266 return false;
267 }
268 }
269 ty::GenericArgKind::Const(ct) => {
270 if matches!(ct.kind(), ty::ConstKind::Bound(ty::INNERMOST, bc) if var == bc.var())
271 {
272 var = var + 1;
273 } else {
274 return false;
275 }
276 }
277 }
278 }
279
280 true
281 }
282
283 pub fn make_identity(cx: I, infos: I::CanonicalVarKinds) -> CanonicalVarValues<I> {
286 CanonicalVarValues {
287 var_values: cx.mk_args_from_iter(infos.iter().enumerate().map(
288 |(i, kind)| -> I::GenericArg {
289 match kind {
290 CanonicalVarKind::Ty(_) | CanonicalVarKind::PlaceholderTy(_) => {
291 Ty::new_anon_bound(cx, ty::INNERMOST, ty::BoundVar::from_usize(i))
292 .into()
293 }
294 CanonicalVarKind::Region(_) | CanonicalVarKind::PlaceholderRegion(_) => {
295 Region::new_anon_bound(cx, ty::INNERMOST, ty::BoundVar::from_usize(i))
296 .into()
297 }
298 CanonicalVarKind::Const(_) | CanonicalVarKind::PlaceholderConst(_) => {
299 Const::new_anon_bound(cx, ty::INNERMOST, ty::BoundVar::from_usize(i))
300 .into()
301 }
302 }
303 },
304 )),
305 }
306 }
307
308 pub fn dummy() -> CanonicalVarValues<I> {
311 CanonicalVarValues { var_values: Default::default() }
312 }
313
314 #[inline]
315 pub fn len(&self) -> usize {
316 self.var_values.len()
317 }
318}
319
320impl<'a, I: Interner> IntoIterator for &'a CanonicalVarValues<I> {
321 type Item = I::GenericArg;
322 type IntoIter = <I::GenericArgs as SliceLike>::IntoIter;
323
324 fn into_iter(self) -> Self::IntoIter {
325 self.var_values.iter()
326 }
327}
328
329impl<I: Interner> Index<ty::BoundVar> for CanonicalVarValues<I> {
330 type Output = I::GenericArg;
331
332 fn index(&self, value: ty::BoundVar) -> &I::GenericArg {
333 &self.var_values.as_slice()[value.as_usize()]
334 }
335}
336
337#[derive_where(Clone, Debug; I: Interner)]
338pub struct CanonicalParamEnvCacheEntry<I: Interner> {
339 pub param_env: I::ParamEnv,
340 pub variables: Vec<I::GenericArg>,
341 pub variable_lookup_table: HashMap<I::GenericArg, usize>,
342 pub var_kinds: Vec<CanonicalVarKind<I>>,
343}