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