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; I: Interner, V: Clone)]
15#[derive_where(Hash; I: Interner, V: Hash)]
16#[derive_where(PartialEq; I: Interner, V: PartialEq)]
17#[derive_where(Eq; I: Interner, V: Eq)]
18#[derive_where(Debug; I: Interner, V: fmt::Debug)]
19#[derive_where(Copy; I: Interner, V: Copy)]
20#[cfg_attr(
21 feature = "nightly",
22 derive(Encodable_NoContext, Decodable_NoContext, HashStable_NoContext)
23)]
24pub struct CanonicalQueryInput<I: Interner, V> {
25 pub canonical: Canonical<I, V>,
26 pub typing_mode: TypingMode<I>,
27}
28
29#[derive_where(Clone; I: Interner, V: Clone)]
33#[derive_where(Hash; I: Interner, V: Hash)]
34#[derive_where(PartialEq; I: Interner, V: PartialEq)]
35#[derive_where(Eq; I: Interner, V: Eq)]
36#[derive_where(Debug; I: Interner, V: fmt::Debug)]
37#[derive_where(Copy; I: Interner, V: Copy)]
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::CanonicalVarKinds,
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#[cfg_attr(
94 feature = "nightly",
95 derive(Decodable_NoContext, Encodable_NoContext, HashStable_NoContext)
96)]
97pub enum CanonicalVarKind<I: Interner> {
98 Ty(CanonicalTyVarKind),
100
101 PlaceholderTy(I::PlaceholderTy),
103
104 Region(UniverseIndex),
106
107 PlaceholderRegion(I::PlaceholderRegion),
111
112 Const(UniverseIndex),
114
115 PlaceholderConst(I::PlaceholderConst),
117}
118
119impl<I: Interner> CanonicalVarKind<I> {
120 pub fn universe(self) -> UniverseIndex {
121 match self {
122 CanonicalVarKind::Ty(CanonicalTyVarKind::General(ui)) => ui,
123 CanonicalVarKind::Region(ui) => ui,
124 CanonicalVarKind::Const(ui) => ui,
125 CanonicalVarKind::PlaceholderTy(placeholder) => placeholder.universe(),
126 CanonicalVarKind::PlaceholderRegion(placeholder) => placeholder.universe(),
127 CanonicalVarKind::PlaceholderConst(placeholder) => placeholder.universe(),
128 CanonicalVarKind::Ty(CanonicalTyVarKind::Float | CanonicalTyVarKind::Int) => {
129 UniverseIndex::ROOT
130 }
131 }
132 }
133
134 pub fn with_updated_universe(self, ui: UniverseIndex) -> CanonicalVarKind<I> {
139 match self {
140 CanonicalVarKind::Ty(CanonicalTyVarKind::General(_)) => {
141 CanonicalVarKind::Ty(CanonicalTyVarKind::General(ui))
142 }
143 CanonicalVarKind::Region(_) => CanonicalVarKind::Region(ui),
144 CanonicalVarKind::Const(_) => CanonicalVarKind::Const(ui),
145
146 CanonicalVarKind::PlaceholderTy(placeholder) => {
147 CanonicalVarKind::PlaceholderTy(placeholder.with_updated_universe(ui))
148 }
149 CanonicalVarKind::PlaceholderRegion(placeholder) => {
150 CanonicalVarKind::PlaceholderRegion(placeholder.with_updated_universe(ui))
151 }
152 CanonicalVarKind::PlaceholderConst(placeholder) => {
153 CanonicalVarKind::PlaceholderConst(placeholder.with_updated_universe(ui))
154 }
155 CanonicalVarKind::Ty(CanonicalTyVarKind::Int | CanonicalTyVarKind::Float) => {
156 assert_eq!(ui, UniverseIndex::ROOT);
157 self
158 }
159 }
160 }
161
162 pub fn is_existential(self) -> bool {
163 match self {
164 CanonicalVarKind::Ty(_) => true,
165 CanonicalVarKind::PlaceholderTy(_) => false,
166 CanonicalVarKind::Region(_) => true,
167 CanonicalVarKind::PlaceholderRegion(..) => false,
168 CanonicalVarKind::Const(_) => true,
169 CanonicalVarKind::PlaceholderConst(_) => false,
170 }
171 }
172
173 pub fn is_region(self) -> bool {
174 match self {
175 CanonicalVarKind::Region(_) | CanonicalVarKind::PlaceholderRegion(_) => true,
176 CanonicalVarKind::Ty(_)
177 | CanonicalVarKind::PlaceholderTy(_)
178 | CanonicalVarKind::Const(_)
179 | CanonicalVarKind::PlaceholderConst(_) => false,
180 }
181 }
182
183 pub fn expect_placeholder_index(self) -> usize {
184 match self {
185 CanonicalVarKind::Ty(_) | CanonicalVarKind::Region(_) | CanonicalVarKind::Const(_) => {
186 panic!("expected placeholder: {self:?}")
187 }
188
189 CanonicalVarKind::PlaceholderRegion(placeholder) => placeholder.var().as_usize(),
190 CanonicalVarKind::PlaceholderTy(placeholder) => placeholder.var().as_usize(),
191 CanonicalVarKind::PlaceholderConst(placeholder) => placeholder.var().as_usize(),
192 }
193 }
194}
195
196#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
202#[derive(TypeVisitable_Generic, TypeFoldable_Generic)]
203#[cfg_attr(
204 feature = "nightly",
205 derive(Decodable_NoContext, Encodable_NoContext, HashStable_NoContext)
206)]
207pub enum CanonicalTyVarKind {
208 General(UniverseIndex),
210
211 Int,
213
214 Float,
216}
217
218#[derive_where(Clone, Copy, Hash, PartialEq, Eq, Debug; I: Interner)]
228#[cfg_attr(
229 feature = "nightly",
230 derive(Encodable_NoContext, Decodable_NoContext, HashStable_NoContext)
231)]
232#[derive(TypeVisitable_Generic, TypeFoldable_Generic, Lift_Generic)]
233pub struct CanonicalVarValues<I: Interner> {
234 pub var_values: I::GenericArgs,
235}
236
237impl<I: Interner> CanonicalVarValues<I> {
238 pub fn is_identity(&self) -> bool {
239 self.var_values.iter().enumerate().all(|(bv, arg)| match arg.kind() {
240 ty::GenericArgKind::Lifetime(r) => {
241 matches!(r.kind(), ty::ReBound(ty::INNERMOST, br) if br.var().as_usize() == bv)
242 }
243 ty::GenericArgKind::Type(ty) => {
244 matches!(ty.kind(), ty::Bound(ty::INNERMOST, bt) if bt.var().as_usize() == bv)
245 }
246 ty::GenericArgKind::Const(ct) => {
247 matches!(ct.kind(), ty::ConstKind::Bound(ty::INNERMOST, bc) if bc.var().as_usize() == bv)
248 }
249 })
250 }
251
252 pub fn is_identity_modulo_regions(&self) -> bool {
253 let mut var = ty::BoundVar::ZERO;
254 for arg in self.var_values.iter() {
255 match arg.kind() {
256 ty::GenericArgKind::Lifetime(r) => {
257 if matches!(r.kind(), ty::ReBound(ty::INNERMOST, br) if var == br.var()) {
258 var = var + 1;
259 } else {
260 }
262 }
263 ty::GenericArgKind::Type(ty) => {
264 if matches!(ty.kind(), ty::Bound(ty::INNERMOST, bt) if var == bt.var()) {
265 var = var + 1;
266 } else {
267 return false;
268 }
269 }
270 ty::GenericArgKind::Const(ct) => {
271 if matches!(ct.kind(), ty::ConstKind::Bound(ty::INNERMOST, bc) if var == bc.var())
272 {
273 var = var + 1;
274 } else {
275 return false;
276 }
277 }
278 }
279 }
280
281 true
282 }
283
284 pub fn make_identity(cx: I, infos: I::CanonicalVarKinds) -> CanonicalVarValues<I> {
287 CanonicalVarValues {
288 var_values: cx.mk_args_from_iter(infos.iter().enumerate().map(
289 |(i, kind)| -> I::GenericArg {
290 match kind {
291 CanonicalVarKind::Ty(_) | CanonicalVarKind::PlaceholderTy(_) => {
292 Ty::new_anon_bound(cx, ty::INNERMOST, ty::BoundVar::from_usize(i))
293 .into()
294 }
295 CanonicalVarKind::Region(_) | CanonicalVarKind::PlaceholderRegion(_) => {
296 Region::new_anon_bound(cx, ty::INNERMOST, ty::BoundVar::from_usize(i))
297 .into()
298 }
299 CanonicalVarKind::Const(_) | CanonicalVarKind::PlaceholderConst(_) => {
300 Const::new_anon_bound(cx, ty::INNERMOST, ty::BoundVar::from_usize(i))
301 .into()
302 }
303 }
304 },
305 )),
306 }
307 }
308
309 pub fn dummy() -> CanonicalVarValues<I> {
312 CanonicalVarValues { var_values: Default::default() }
313 }
314
315 #[inline]
316 pub fn len(&self) -> usize {
317 self.var_values.len()
318 }
319}
320
321impl<'a, I: Interner> IntoIterator for &'a CanonicalVarValues<I> {
322 type Item = I::GenericArg;
323 type IntoIter = <I::GenericArgs as SliceLike>::IntoIter;
324
325 fn into_iter(self) -> Self::IntoIter {
326 self.var_values.iter()
327 }
328}
329
330impl<I: Interner> Index<ty::BoundVar> for CanonicalVarValues<I> {
331 type Output = I::GenericArg;
332
333 fn index(&self, value: ty::BoundVar) -> &I::GenericArg {
334 &self.var_values.as_slice()[value.as_usize()]
335 }
336}
337
338#[derive_where(Clone, Debug; I: Interner)]
339pub struct CanonicalParamEnvCacheEntry<I: Interner> {
340 pub param_env: I::ParamEnv,
341 pub variables: Vec<I::GenericArg>,
342 pub variable_lookup_table: HashMap<I::GenericArg, usize>,
343 pub var_kinds: Vec<CanonicalVarKind<I>>,
344}