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::inherent::*;
11use crate::{self as ty, Interner, TypingMode, UniverseIndex};
12
13#[derive_where(Clone; I: Interner, V: Clone)]
14#[derive_where(Hash; I: Interner, V: Hash)]
15#[derive_where(PartialEq; I: Interner, V: PartialEq)]
16#[derive_where(Eq; I: Interner, V: Eq)]
17#[derive_where(Debug; I: Interner, V: fmt::Debug)]
18#[derive_where(Copy; I: Interner, V: Copy)]
19#[cfg_attr(
20 feature = "nightly",
21 derive(Encodable_NoContext, Decodable_NoContext, HashStable_NoContext)
22)]
23pub struct CanonicalQueryInput<I: Interner, V> {
24 pub canonical: Canonical<I, V>,
25 pub typing_mode: TypingMode<I>,
26}
27
28#[derive_where(Clone; I: Interner, V: Clone)]
32#[derive_where(Hash; I: Interner, V: Hash)]
33#[derive_where(PartialEq; I: Interner, V: PartialEq)]
34#[derive_where(Eq; I: Interner, V: Eq)]
35#[derive_where(Debug; I: Interner, V: fmt::Debug)]
36#[derive_where(Copy; I: Interner, V: Copy)]
37#[cfg_attr(
38 feature = "nightly",
39 derive(Encodable_NoContext, Decodable_NoContext, HashStable_NoContext)
40)]
41pub struct Canonical<I: Interner, V> {
42 pub value: V,
43 pub max_universe: UniverseIndex,
44 pub variables: I::CanonicalVars,
45}
46
47impl<I: Interner, V> Canonical<I, V> {
48 pub fn unchecked_map<W>(self, map_op: impl FnOnce(V) -> W) -> Canonical<I, W> {
72 let Canonical { max_universe, variables, value } = self;
73 Canonical { max_universe, variables, value: map_op(value) }
74 }
75}
76
77impl<I: Interner, V: fmt::Display> fmt::Display for Canonical<I, V> {
78 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
79 let Self { value, max_universe, variables } = self;
80 write!(
81 f,
82 "Canonical {{ value: {value}, max_universe: {max_universe:?}, variables: {variables:?} }}",
83 )
84 }
85}
86
87#[derive_where(Clone, Copy, Hash, PartialEq, Eq, Debug; I: Interner)]
92#[derive(TypeVisitable_Generic, TypeFoldable_Generic)]
93#[cfg_attr(
94 feature = "nightly",
95 derive(Decodable_NoContext, Encodable_NoContext, HashStable_NoContext)
96)]
97pub struct CanonicalVarInfo<I: Interner> {
98 pub kind: CanonicalVarKind<I>,
99}
100
101impl<I: Interner> CanonicalVarInfo<I> {
102 pub fn universe(self) -> UniverseIndex {
103 self.kind.universe()
104 }
105
106 #[must_use]
107 pub fn with_updated_universe(self, ui: UniverseIndex) -> CanonicalVarInfo<I> {
108 CanonicalVarInfo { kind: self.kind.with_updated_universe(ui) }
109 }
110
111 pub fn is_existential(&self) -> bool {
112 match self.kind {
113 CanonicalVarKind::Ty(_) => true,
114 CanonicalVarKind::PlaceholderTy(_) => false,
115 CanonicalVarKind::Region(_) => true,
116 CanonicalVarKind::PlaceholderRegion(..) => false,
117 CanonicalVarKind::Const(_) => true,
118 CanonicalVarKind::PlaceholderConst(_) => false,
119 }
120 }
121
122 pub fn is_region(&self) -> bool {
123 match self.kind {
124 CanonicalVarKind::Region(_) | CanonicalVarKind::PlaceholderRegion(_) => true,
125 CanonicalVarKind::Ty(_)
126 | CanonicalVarKind::PlaceholderTy(_)
127 | CanonicalVarKind::Const(_)
128 | CanonicalVarKind::PlaceholderConst(_) => false,
129 }
130 }
131
132 pub fn expect_placeholder_index(self) -> usize {
133 match self.kind {
134 CanonicalVarKind::Ty(_) | CanonicalVarKind::Region(_) | CanonicalVarKind::Const(_) => {
135 panic!("expected placeholder: {self:?}")
136 }
137
138 CanonicalVarKind::PlaceholderRegion(placeholder) => placeholder.var().as_usize(),
139 CanonicalVarKind::PlaceholderTy(placeholder) => placeholder.var().as_usize(),
140 CanonicalVarKind::PlaceholderConst(placeholder) => placeholder.var().as_usize(),
141 }
142 }
143}
144
145#[derive_where(Clone, Copy, Hash, PartialEq, Eq, Debug; I: Interner)]
149#[cfg_attr(
150 feature = "nightly",
151 derive(Decodable_NoContext, Encodable_NoContext, HashStable_NoContext)
152)]
153pub enum CanonicalVarKind<I: Interner> {
154 Ty(CanonicalTyVarKind),
156
157 PlaceholderTy(I::PlaceholderTy),
159
160 Region(UniverseIndex),
162
163 PlaceholderRegion(I::PlaceholderRegion),
167
168 Const(UniverseIndex),
170
171 PlaceholderConst(I::PlaceholderConst),
173}
174
175impl<I: Interner> CanonicalVarKind<I> {
176 pub fn universe(self) -> UniverseIndex {
177 match self {
178 CanonicalVarKind::Ty(CanonicalTyVarKind::General(ui)) => ui,
179 CanonicalVarKind::Region(ui) => ui,
180 CanonicalVarKind::Const(ui) => ui,
181 CanonicalVarKind::PlaceholderTy(placeholder) => placeholder.universe(),
182 CanonicalVarKind::PlaceholderRegion(placeholder) => placeholder.universe(),
183 CanonicalVarKind::PlaceholderConst(placeholder) => placeholder.universe(),
184 CanonicalVarKind::Ty(CanonicalTyVarKind::Float | CanonicalTyVarKind::Int) => {
185 UniverseIndex::ROOT
186 }
187 }
188 }
189
190 pub fn with_updated_universe(self, ui: UniverseIndex) -> CanonicalVarKind<I> {
195 match self {
196 CanonicalVarKind::Ty(CanonicalTyVarKind::General(_)) => {
197 CanonicalVarKind::Ty(CanonicalTyVarKind::General(ui))
198 }
199 CanonicalVarKind::Region(_) => CanonicalVarKind::Region(ui),
200 CanonicalVarKind::Const(_) => CanonicalVarKind::Const(ui),
201
202 CanonicalVarKind::PlaceholderTy(placeholder) => {
203 CanonicalVarKind::PlaceholderTy(placeholder.with_updated_universe(ui))
204 }
205 CanonicalVarKind::PlaceholderRegion(placeholder) => {
206 CanonicalVarKind::PlaceholderRegion(placeholder.with_updated_universe(ui))
207 }
208 CanonicalVarKind::PlaceholderConst(placeholder) => {
209 CanonicalVarKind::PlaceholderConst(placeholder.with_updated_universe(ui))
210 }
211 CanonicalVarKind::Ty(CanonicalTyVarKind::Int | CanonicalTyVarKind::Float) => {
212 assert_eq!(ui, UniverseIndex::ROOT);
213 self
214 }
215 }
216 }
217}
218
219#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
225#[derive(TypeVisitable_Generic, TypeFoldable_Generic)]
226#[cfg_attr(
227 feature = "nightly",
228 derive(Decodable_NoContext, Encodable_NoContext, HashStable_NoContext)
229)]
230pub enum CanonicalTyVarKind {
231 General(UniverseIndex),
233
234 Int,
236
237 Float,
239}
240
241#[derive_where(Clone, Copy, Hash, PartialEq, Eq, Debug; I: Interner)]
251#[cfg_attr(
252 feature = "nightly",
253 derive(Encodable_NoContext, Decodable_NoContext, HashStable_NoContext)
254)]
255#[derive(TypeVisitable_Generic, TypeFoldable_Generic, Lift_Generic)]
256pub struct CanonicalVarValues<I: Interner> {
257 pub var_values: I::GenericArgs,
258}
259
260impl<I: Interner> CanonicalVarValues<I> {
261 pub fn is_identity(&self) -> bool {
262 self.var_values.iter().enumerate().all(|(bv, arg)| match arg.kind() {
263 ty::GenericArgKind::Lifetime(r) => {
264 matches!(r.kind(), ty::ReBound(ty::INNERMOST, br) if br.var().as_usize() == bv)
265 }
266 ty::GenericArgKind::Type(ty) => {
267 matches!(ty.kind(), ty::Bound(ty::INNERMOST, bt) if bt.var().as_usize() == bv)
268 }
269 ty::GenericArgKind::Const(ct) => {
270 matches!(ct.kind(), ty::ConstKind::Bound(ty::INNERMOST, bc) if bc.var().as_usize() == bv)
271 }
272 })
273 }
274
275 pub fn is_identity_modulo_regions(&self) -> bool {
276 let mut var = ty::BoundVar::ZERO;
277 for arg in self.var_values.iter() {
278 match arg.kind() {
279 ty::GenericArgKind::Lifetime(r) => {
280 if matches!(r.kind(), ty::ReBound(ty::INNERMOST, br) if var == br.var()) {
281 var = var + 1;
282 } else {
283 }
285 }
286 ty::GenericArgKind::Type(ty) => {
287 if matches!(ty.kind(), ty::Bound(ty::INNERMOST, bt) if var == bt.var()) {
288 var = var + 1;
289 } else {
290 return false;
291 }
292 }
293 ty::GenericArgKind::Const(ct) => {
294 if matches!(ct.kind(), ty::ConstKind::Bound(ty::INNERMOST, bc) if var == bc.var())
295 {
296 var = var + 1;
297 } else {
298 return false;
299 }
300 }
301 }
302 }
303
304 true
305 }
306
307 pub fn make_identity(cx: I, infos: I::CanonicalVars) -> CanonicalVarValues<I> {
310 CanonicalVarValues {
311 var_values: cx.mk_args_from_iter(infos.iter().enumerate().map(
312 |(i, info)| -> I::GenericArg {
313 match info.kind {
314 CanonicalVarKind::Ty(_) | CanonicalVarKind::PlaceholderTy(_) => {
315 Ty::new_anon_bound(cx, ty::INNERMOST, ty::BoundVar::from_usize(i))
316 .into()
317 }
318 CanonicalVarKind::Region(_) | CanonicalVarKind::PlaceholderRegion(_) => {
319 Region::new_anon_bound(cx, ty::INNERMOST, ty::BoundVar::from_usize(i))
320 .into()
321 }
322 CanonicalVarKind::Const(_) | CanonicalVarKind::PlaceholderConst(_) => {
323 Const::new_anon_bound(cx, ty::INNERMOST, ty::BoundVar::from_usize(i))
324 .into()
325 }
326 }
327 },
328 )),
329 }
330 }
331
332 pub fn dummy() -> CanonicalVarValues<I> {
335 CanonicalVarValues { var_values: Default::default() }
336 }
337
338 #[inline]
339 pub fn len(&self) -> usize {
340 self.var_values.len()
341 }
342}
343
344impl<'a, I: Interner> IntoIterator for &'a CanonicalVarValues<I> {
345 type Item = I::GenericArg;
346 type IntoIter = <I::GenericArgs as SliceLike>::IntoIter;
347
348 fn into_iter(self) -> Self::IntoIter {
349 self.var_values.iter()
350 }
351}
352
353impl<I: Interner> Index<ty::BoundVar> for CanonicalVarValues<I> {
354 type Output = I::GenericArg;
355
356 fn index(&self, value: ty::BoundVar) -> &I::GenericArg {
357 &self.var_values.as_slice()[value.as_usize()]
358 }
359}