1use std::fmt;
2use std::ops::Index;
3
4use arrayvec::ArrayVec;
5use derive_where::derive_where;
6#[cfg(feature = "nightly")]
7use rustc_macros::{Decodable_NoContext, Encodable_NoContext, HashStable_NoContext};
8use rustc_type_ir_macros::{
9 GenericTypeVisitable, Lift_Generic, TypeFoldable_Generic, TypeVisitable_Generic,
10};
11
12use crate::data_structures::HashMap;
13use crate::inherent::*;
14use crate::{self as ty, Interner, TypingMode, UniverseIndex};
15
16#[derive_where(Clone, Hash, PartialEq, Debug; I: Interner, V)]
17#[derive_where(Copy; I: Interner, V: Copy)]
18#[cfg_attr(
19 feature = "nightly",
20 derive(Encodable_NoContext, Decodable_NoContext, HashStable_NoContext)
21)]
22pub struct CanonicalQueryInput<I: Interner, V> {
23 pub canonical: Canonical<I, V>,
24 pub typing_mode: TypingMode<I>,
25}
26
27impl<I: Interner, V: Eq> Eq for CanonicalQueryInput<I, V> {}
28
29#[derive_where(Clone, Hash, PartialEq, Debug; I: Interner, V)]
33#[derive_where(Copy; I: Interner, V: Copy)]
34#[cfg_attr(
35 feature = "nightly",
36 derive(Encodable_NoContext, Decodable_NoContext, HashStable_NoContext)
37)]
38pub struct Canonical<I: Interner, V> {
39 pub value: V,
40 pub max_universe: UniverseIndex,
41 pub variables: I::CanonicalVarKinds,
42}
43
44impl<I: Interner, V: Eq> Eq for Canonical<I, V> {}
45
46impl<I: Interner, V> Canonical<I, V> {
47 pub fn unchecked_map<W>(self, map_op: impl FnOnce(V) -> W) -> Canonical<I, W> {
71 let Canonical { max_universe, variables, value } = self;
72 Canonical { max_universe, variables, value: map_op(value) }
73 }
74}
75
76impl<I: Interner, V: fmt::Display> fmt::Display for Canonical<I, V> {
77 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
78 let Self { value, max_universe, variables } = self;
79 write!(
80 f,
81 "Canonical {{ value: {value}, max_universe: {max_universe:?}, variables: {variables:?} }}",
82 )
83 }
84}
85
86#[derive_where(Clone, Copy, Hash, PartialEq, Debug; I: Interner)]
91#[derive(GenericTypeVisitable)]
92#[cfg_attr(
93 feature = "nightly",
94 derive(Decodable_NoContext, Encodable_NoContext, HashStable_NoContext)
95)]
96pub enum CanonicalVarKind<I: Interner> {
97 Ty { ui: UniverseIndex, sub_root: ty::BoundVar },
103
104 Int,
106
107 Float,
109
110 PlaceholderTy(I::PlaceholderTy),
112
113 Region(UniverseIndex),
115
116 PlaceholderRegion(I::PlaceholderRegion),
120
121 Const(UniverseIndex),
123
124 PlaceholderConst(I::PlaceholderConst),
126}
127
128impl<I: Interner> Eq for CanonicalVarKind<I> {}
129
130impl<I: Interner> CanonicalVarKind<I> {
131 pub fn universe(self) -> UniverseIndex {
132 match self {
133 CanonicalVarKind::Ty { ui, sub_root: _ } => ui,
134 CanonicalVarKind::Region(ui) => ui,
135 CanonicalVarKind::Const(ui) => ui,
136 CanonicalVarKind::PlaceholderTy(placeholder) => placeholder.universe(),
137 CanonicalVarKind::PlaceholderRegion(placeholder) => placeholder.universe(),
138 CanonicalVarKind::PlaceholderConst(placeholder) => placeholder.universe(),
139 CanonicalVarKind::Float | CanonicalVarKind::Int => UniverseIndex::ROOT,
140 }
141 }
142
143 pub fn with_updated_universe(self, ui: UniverseIndex) -> CanonicalVarKind<I> {
148 match self {
149 CanonicalVarKind::Ty { ui: _, sub_root } => CanonicalVarKind::Ty { ui, sub_root },
150 CanonicalVarKind::Region(_) => CanonicalVarKind::Region(ui),
151 CanonicalVarKind::Const(_) => CanonicalVarKind::Const(ui),
152
153 CanonicalVarKind::PlaceholderTy(placeholder) => {
154 CanonicalVarKind::PlaceholderTy(placeholder.with_updated_universe(ui))
155 }
156 CanonicalVarKind::PlaceholderRegion(placeholder) => {
157 CanonicalVarKind::PlaceholderRegion(placeholder.with_updated_universe(ui))
158 }
159 CanonicalVarKind::PlaceholderConst(placeholder) => {
160 CanonicalVarKind::PlaceholderConst(placeholder.with_updated_universe(ui))
161 }
162 CanonicalVarKind::Int | CanonicalVarKind::Float => {
163 assert_eq!(ui, UniverseIndex::ROOT);
164 self
165 }
166 }
167 }
168
169 pub fn is_existential(self) -> bool {
170 match self {
171 CanonicalVarKind::Ty { .. }
172 | CanonicalVarKind::Int
173 | CanonicalVarKind::Float
174 | CanonicalVarKind::Region(_)
175 | CanonicalVarKind::Const(_) => true,
176 CanonicalVarKind::PlaceholderTy(_)
177 | CanonicalVarKind::PlaceholderRegion(..)
178 | CanonicalVarKind::PlaceholderConst(_) => false,
179 }
180 }
181
182 pub fn is_region(self) -> bool {
183 match self {
184 CanonicalVarKind::Region(_) | CanonicalVarKind::PlaceholderRegion(_) => true,
185 CanonicalVarKind::Ty { .. }
186 | CanonicalVarKind::Int
187 | CanonicalVarKind::Float
188 | CanonicalVarKind::PlaceholderTy(_)
189 | CanonicalVarKind::Const(_)
190 | CanonicalVarKind::PlaceholderConst(_) => false,
191 }
192 }
193
194 pub fn expect_placeholder_index(self) -> usize {
195 match self {
196 CanonicalVarKind::Ty { .. }
197 | CanonicalVarKind::Int
198 | CanonicalVarKind::Float
199 | CanonicalVarKind::Region(_)
200 | CanonicalVarKind::Const(_) => {
201 panic!("expected placeholder: {self:?}")
202 }
203
204 CanonicalVarKind::PlaceholderRegion(placeholder) => placeholder.var().as_usize(),
205 CanonicalVarKind::PlaceholderTy(placeholder) => placeholder.var().as_usize(),
206 CanonicalVarKind::PlaceholderConst(placeholder) => placeholder.var().as_usize(),
207 }
208 }
209}
210
211#[derive_where(Clone, Copy, Hash, PartialEq, Debug; I: Interner)]
221#[cfg_attr(
222 feature = "nightly",
223 derive(Encodable_NoContext, Decodable_NoContext, HashStable_NoContext)
224)]
225#[derive(TypeVisitable_Generic, GenericTypeVisitable, TypeFoldable_Generic, Lift_Generic)]
226pub struct CanonicalVarValues<I: Interner> {
227 pub var_values: I::GenericArgs,
228}
229
230impl<I: Interner> Eq for CanonicalVarValues<I> {}
231
232impl<I: Interner> CanonicalVarValues<I> {
233 pub fn is_identity(&self) -> bool {
234 self.var_values.iter().enumerate().all(|(bv, arg)| match arg.kind() {
235 ty::GenericArgKind::Lifetime(r) => {
236 matches!(r.kind(), ty::ReBound(ty::BoundVarIndexKind::Canonical, br) if br.var().as_usize() == bv)
237 }
238 ty::GenericArgKind::Type(ty) => {
239 matches!(ty.kind(), ty::Bound(ty::BoundVarIndexKind::Canonical, bt) if bt.var().as_usize() == bv)
240 }
241 ty::GenericArgKind::Const(ct) => {
242 matches!(ct.kind(), ty::ConstKind::Bound(ty::BoundVarIndexKind::Canonical, bc) if bc.var().as_usize() == bv)
243 }
244 })
245 }
246
247 pub fn is_identity_modulo_regions(&self) -> bool {
248 let mut var = ty::BoundVar::ZERO;
249 for arg in self.var_values.iter() {
250 match arg.kind() {
251 ty::GenericArgKind::Lifetime(r) => {
252 if matches!(r.kind(), ty::ReBound(ty::BoundVarIndexKind::Canonical, br) if var == br.var())
253 {
254 var = var + 1;
255 } else {
256 }
258 }
259 ty::GenericArgKind::Type(ty) => {
260 if matches!(ty.kind(), ty::Bound(ty::BoundVarIndexKind::Canonical, bt) if var == bt.var())
261 {
262 var = var + 1;
263 } else {
264 return false;
265 }
266 }
267 ty::GenericArgKind::Const(ct) => {
268 if matches!(ct.kind(), ty::ConstKind::Bound(ty::BoundVarIndexKind::Canonical, bc) if var == bc.var())
269 {
270 var = var + 1;
271 } else {
272 return false;
273 }
274 }
275 }
276 }
277
278 true
279 }
280
281 pub fn make_identity(cx: I, infos: I::CanonicalVarKinds) -> CanonicalVarValues<I> {
284 CanonicalVarValues {
285 var_values: cx.mk_args_from_iter(infos.iter().enumerate().map(
286 |(i, kind)| -> I::GenericArg {
287 match kind {
288 CanonicalVarKind::Ty { .. }
289 | CanonicalVarKind::Int
290 | CanonicalVarKind::Float
291 | CanonicalVarKind::PlaceholderTy(_) => {
292 Ty::new_canonical_bound(cx, ty::BoundVar::from_usize(i)).into()
293 }
294 CanonicalVarKind::Region(_) | CanonicalVarKind::PlaceholderRegion(_) => {
295 Region::new_canonical_bound(cx, ty::BoundVar::from_usize(i)).into()
296 }
297 CanonicalVarKind::Const(_) | CanonicalVarKind::PlaceholderConst(_) => {
298 Const::new_canonical_bound(cx, ty::BoundVar::from_usize(i)).into()
299 }
300 }
301 },
302 )),
303 }
304 }
305
306 pub fn dummy() -> CanonicalVarValues<I> {
309 CanonicalVarValues { var_values: Default::default() }
310 }
311
312 pub fn instantiate(
313 cx: I,
314 variables: I::CanonicalVarKinds,
315 mut f: impl FnMut(&[I::GenericArg], CanonicalVarKind<I>) -> I::GenericArg,
316 ) -> CanonicalVarValues<I> {
317 if variables.len() <= 4 {
320 let mut var_values = ArrayVec::<_, 4>::new();
321 for info in variables.iter() {
322 var_values.push(f(&var_values, info));
323 }
324 CanonicalVarValues { var_values: cx.mk_args(&var_values) }
325 } else {
326 CanonicalVarValues::instantiate_cold(cx, variables, f)
327 }
328 }
329
330 #[cold]
331 fn instantiate_cold(
332 cx: I,
333 variables: I::CanonicalVarKinds,
334 mut f: impl FnMut(&[I::GenericArg], CanonicalVarKind<I>) -> I::GenericArg,
335 ) -> CanonicalVarValues<I> {
336 let mut var_values = Vec::with_capacity(variables.len());
337 for info in variables.iter() {
338 var_values.push(f(&var_values, info));
339 }
340 CanonicalVarValues { var_values: cx.mk_args(&var_values) }
341 }
342
343 #[inline]
344 pub fn len(&self) -> usize {
345 self.var_values.len()
346 }
347}
348
349impl<'a, I: Interner> IntoIterator for &'a CanonicalVarValues<I> {
350 type Item = I::GenericArg;
351 type IntoIter = <I::GenericArgs as SliceLike>::IntoIter;
352
353 fn into_iter(self) -> Self::IntoIter {
354 self.var_values.iter()
355 }
356}
357
358impl<I: Interner> Index<ty::BoundVar> for CanonicalVarValues<I> {
359 type Output = I::GenericArg;
360
361 fn index(&self, value: ty::BoundVar) -> &I::GenericArg {
362 &self.var_values.as_slice()[value.as_usize()]
363 }
364}
365
366#[derive_where(Clone, Debug; I: Interner)]
367pub struct CanonicalParamEnvCacheEntry<I: Interner> {
368 pub param_env: I::ParamEnv,
369 pub variables: Vec<I::GenericArg>,
370 pub variable_lookup_table: HashMap<I::GenericArg, usize>,
371 pub var_kinds: Vec<CanonicalVarKind<I>>,
372}