1use std::fmt;
2use std::hash::Hash;
3use std::ops::Index;
4
5use derive_where::derive_where;
6#[cfg(feature = "nightly")]
7use rustc_macros::{HashStable_NoContext, TyDecodable, TyEncodable};
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(feature = "nightly", derive(TyEncodable, TyDecodable, HashStable_NoContext))]
20pub struct CanonicalQueryInput<I: Interner, V> {
21 pub canonical: Canonical<I, V>,
22 pub typing_mode: TypingMode<I>,
23}
24
25#[derive_where(Clone; I: Interner, V: Clone)]
29#[derive_where(Hash; I: Interner, V: Hash)]
30#[derive_where(PartialEq; I: Interner, V: PartialEq)]
31#[derive_where(Eq; I: Interner, V: Eq)]
32#[derive_where(Debug; I: Interner, V: fmt::Debug)]
33#[derive_where(Copy; I: Interner, V: Copy)]
34#[derive(TypeVisitable_Generic, TypeFoldable_Generic)]
35#[cfg_attr(feature = "nightly", derive(TyEncodable, TyDecodable, HashStable_NoContext))]
36pub struct Canonical<I: Interner, V> {
37 pub value: V,
38 pub max_universe: UniverseIndex,
39 pub variables: I::CanonicalVars,
40}
41
42impl<I: Interner, V> Canonical<I, V> {
43 pub fn unchecked_map<W>(self, map_op: impl FnOnce(V) -> W) -> Canonical<I, W> {
67 let Canonical { max_universe, variables, value } = self;
68 Canonical { max_universe, variables, value: map_op(value) }
69 }
70}
71
72impl<I: Interner, V: fmt::Display> fmt::Display for Canonical<I, V> {
73 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
74 let Self { value, max_universe, variables } = self;
75 write!(
76 f,
77 "Canonical {{ value: {value}, max_universe: {max_universe:?}, variables: {variables:?} }}",
78 )
79 }
80}
81
82#[derive_where(Clone, Copy, Hash, PartialEq, Eq, Debug; I: Interner)]
87#[derive(TypeVisitable_Generic, TypeFoldable_Generic)]
88#[cfg_attr(feature = "nightly", derive(TyDecodable, TyEncodable, HashStable_NoContext))]
89pub struct CanonicalVarInfo<I: Interner> {
90 pub kind: CanonicalVarKind<I>,
91}
92
93impl<I: Interner> CanonicalVarInfo<I> {
94 pub fn universe(self) -> UniverseIndex {
95 self.kind.universe()
96 }
97
98 #[must_use]
99 pub fn with_updated_universe(self, ui: UniverseIndex) -> CanonicalVarInfo<I> {
100 CanonicalVarInfo { kind: self.kind.with_updated_universe(ui) }
101 }
102
103 pub fn is_existential(&self) -> bool {
104 match self.kind {
105 CanonicalVarKind::Ty(_) => true,
106 CanonicalVarKind::PlaceholderTy(_) => false,
107 CanonicalVarKind::Region(_) => true,
108 CanonicalVarKind::PlaceholderRegion(..) => false,
109 CanonicalVarKind::Const(_) => true,
110 CanonicalVarKind::PlaceholderConst(_) => false,
111 }
112 }
113
114 pub fn is_region(&self) -> bool {
115 match self.kind {
116 CanonicalVarKind::Region(_) | CanonicalVarKind::PlaceholderRegion(_) => true,
117 CanonicalVarKind::Ty(_)
118 | CanonicalVarKind::PlaceholderTy(_)
119 | CanonicalVarKind::Const(_)
120 | CanonicalVarKind::PlaceholderConst(_) => false,
121 }
122 }
123
124 pub fn expect_placeholder_index(self) -> usize {
125 match self.kind {
126 CanonicalVarKind::Ty(_) | CanonicalVarKind::Region(_) | CanonicalVarKind::Const(_) => {
127 panic!("expected placeholder: {self:?}")
128 }
129
130 CanonicalVarKind::PlaceholderRegion(placeholder) => placeholder.var().as_usize(),
131 CanonicalVarKind::PlaceholderTy(placeholder) => placeholder.var().as_usize(),
132 CanonicalVarKind::PlaceholderConst(placeholder) => placeholder.var().as_usize(),
133 }
134 }
135}
136
137#[derive_where(Clone, Copy, Hash, PartialEq, Eq, Debug; I: Interner)]
141#[derive(TypeVisitable_Generic, TypeFoldable_Generic)]
142#[cfg_attr(feature = "nightly", derive(TyDecodable, TyEncodable, HashStable_NoContext))]
143pub enum CanonicalVarKind<I: Interner> {
144 Ty(CanonicalTyVarKind),
146
147 PlaceholderTy(I::PlaceholderTy),
149
150 Region(UniverseIndex),
152
153 PlaceholderRegion(I::PlaceholderRegion),
157
158 Const(UniverseIndex),
160
161 PlaceholderConst(I::PlaceholderConst),
163}
164
165impl<I: Interner> CanonicalVarKind<I> {
166 pub fn universe(self) -> UniverseIndex {
167 match self {
168 CanonicalVarKind::Ty(CanonicalTyVarKind::General(ui)) => ui,
169 CanonicalVarKind::Region(ui) => ui,
170 CanonicalVarKind::Const(ui) => ui,
171 CanonicalVarKind::PlaceholderTy(placeholder) => placeholder.universe(),
172 CanonicalVarKind::PlaceholderRegion(placeholder) => placeholder.universe(),
173 CanonicalVarKind::PlaceholderConst(placeholder) => placeholder.universe(),
174 CanonicalVarKind::Ty(CanonicalTyVarKind::Float | CanonicalTyVarKind::Int) => {
175 UniverseIndex::ROOT
176 }
177 }
178 }
179
180 pub fn with_updated_universe(self, ui: UniverseIndex) -> CanonicalVarKind<I> {
185 match self {
186 CanonicalVarKind::Ty(CanonicalTyVarKind::General(_)) => {
187 CanonicalVarKind::Ty(CanonicalTyVarKind::General(ui))
188 }
189 CanonicalVarKind::Region(_) => CanonicalVarKind::Region(ui),
190 CanonicalVarKind::Const(_) => CanonicalVarKind::Const(ui),
191
192 CanonicalVarKind::PlaceholderTy(placeholder) => {
193 CanonicalVarKind::PlaceholderTy(placeholder.with_updated_universe(ui))
194 }
195 CanonicalVarKind::PlaceholderRegion(placeholder) => {
196 CanonicalVarKind::PlaceholderRegion(placeholder.with_updated_universe(ui))
197 }
198 CanonicalVarKind::PlaceholderConst(placeholder) => {
199 CanonicalVarKind::PlaceholderConst(placeholder.with_updated_universe(ui))
200 }
201 CanonicalVarKind::Ty(CanonicalTyVarKind::Int | CanonicalTyVarKind::Float) => {
202 assert_eq!(ui, UniverseIndex::ROOT);
203 self
204 }
205 }
206 }
207}
208
209#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
215#[derive(TypeVisitable_Generic, TypeFoldable_Generic)]
216#[cfg_attr(feature = "nightly", derive(TyDecodable, TyEncodable, HashStable_NoContext))]
217pub enum CanonicalTyVarKind {
218 General(UniverseIndex),
220
221 Int,
223
224 Float,
226}
227
228#[derive_where(Clone, Copy, Hash, PartialEq, Eq, Debug; I: Interner)]
238#[cfg_attr(feature = "nightly", derive(TyEncodable, TyDecodable, HashStable_NoContext))]
239#[derive(TypeVisitable_Generic, TypeFoldable_Generic, Lift_Generic)]
240pub struct CanonicalVarValues<I: Interner> {
241 pub var_values: I::GenericArgs,
242}
243
244impl<I: Interner> CanonicalVarValues<I> {
245 pub fn is_identity(&self) -> bool {
246 self.var_values.iter().enumerate().all(|(bv, arg)| match arg.kind() {
247 ty::GenericArgKind::Lifetime(r) => {
248 matches!(r.kind(), ty::ReBound(ty::INNERMOST, br) if br.var().as_usize() == bv)
249 }
250 ty::GenericArgKind::Type(ty) => {
251 matches!(ty.kind(), ty::Bound(ty::INNERMOST, bt) if bt.var().as_usize() == bv)
252 }
253 ty::GenericArgKind::Const(ct) => {
254 matches!(ct.kind(), ty::ConstKind::Bound(ty::INNERMOST, bc) if bc.var().as_usize() == bv)
255 }
256 })
257 }
258
259 pub fn is_identity_modulo_regions(&self) -> bool {
260 let mut var = ty::BoundVar::ZERO;
261 for arg in self.var_values.iter() {
262 match arg.kind() {
263 ty::GenericArgKind::Lifetime(r) => {
264 if matches!(r.kind(), ty::ReBound(ty::INNERMOST, br) if var == br.var()) {
265 var = var + 1;
266 } else {
267 }
269 }
270 ty::GenericArgKind::Type(ty) => {
271 if matches!(ty.kind(), ty::Bound(ty::INNERMOST, bt) if var == bt.var()) {
272 var = var + 1;
273 } else {
274 return false;
275 }
276 }
277 ty::GenericArgKind::Const(ct) => {
278 if matches!(ct.kind(), ty::ConstKind::Bound(ty::INNERMOST, bc) if var == bc.var())
279 {
280 var = var + 1;
281 } else {
282 return false;
283 }
284 }
285 }
286 }
287
288 true
289 }
290
291 pub fn make_identity(cx: I, infos: I::CanonicalVars) -> CanonicalVarValues<I> {
294 CanonicalVarValues {
295 var_values: cx.mk_args_from_iter(infos.iter().enumerate().map(
296 |(i, info)| -> I::GenericArg {
297 match info.kind {
298 CanonicalVarKind::Ty(_) | CanonicalVarKind::PlaceholderTy(_) => {
299 Ty::new_anon_bound(cx, ty::INNERMOST, ty::BoundVar::from_usize(i))
300 .into()
301 }
302 CanonicalVarKind::Region(_) | CanonicalVarKind::PlaceholderRegion(_) => {
303 Region::new_anon_bound(cx, ty::INNERMOST, ty::BoundVar::from_usize(i))
304 .into()
305 }
306 CanonicalVarKind::Const(_) | CanonicalVarKind::PlaceholderConst(_) => {
307 Const::new_anon_bound(cx, ty::INNERMOST, ty::BoundVar::from_usize(i))
308 .into()
309 }
310 }
311 },
312 )),
313 }
314 }
315
316 pub fn dummy() -> CanonicalVarValues<I> {
319 CanonicalVarValues { var_values: Default::default() }
320 }
321
322 #[inline]
323 pub fn len(&self) -> usize {
324 self.var_values.len()
325 }
326}
327
328impl<'a, I: Interner> IntoIterator for &'a CanonicalVarValues<I> {
329 type Item = I::GenericArg;
330 type IntoIter = <I::GenericArgs as SliceLike>::IntoIter;
331
332 fn into_iter(self) -> Self::IntoIter {
333 self.var_values.iter()
334 }
335}
336
337impl<I: Interner> Index<ty::BoundVar> for CanonicalVarValues<I> {
338 type Output = I::GenericArg;
339
340 fn index(&self, value: ty::BoundVar) -> &I::GenericArg {
341 &self.var_values.as_slice()[value.as_usize()]
342 }
343}