1use std::convert::Infallible;
49use std::mem;
50use std::sync::Arc;
51
52use rustc_index::{Idx, IndexVec};
53use thin_vec::ThinVec;
54use tracing::{debug, instrument};
55
56use crate::inherent::*;
57use crate::visit::{TypeVisitable, TypeVisitableExt as _};
58use crate::{self as ty, BoundVarIndexKind, Interner};
59
60pub trait TypeFoldable<I: Interner>: TypeVisitable<I> + Clone {
72 fn try_fold_with<F: FallibleTypeFolder<I>>(self, folder: &mut F) -> Result<Self, F::Error>;
83
84 fn fold_with<F: TypeFolder<I>>(self, folder: &mut F) -> Self;
98}
99
100pub trait TypeSuperFoldable<I: Interner>: TypeFoldable<I> {
102 fn try_super_fold_with<F: FallibleTypeFolder<I>>(
109 self,
110 folder: &mut F,
111 ) -> Result<Self, F::Error>;
112
113 fn super_fold_with<F: TypeFolder<I>>(self, folder: &mut F) -> Self;
117}
118
119pub trait TypeFolder<I: Interner>: Sized {
125 fn cx(&self) -> I;
126
127 fn fold_binder<T>(&mut self, t: ty::Binder<I, T>) -> ty::Binder<I, T>
128 where
129 T: TypeFoldable<I>,
130 {
131 t.super_fold_with(self)
132 }
133
134 fn fold_ty(&mut self, t: I::Ty) -> I::Ty {
135 t.super_fold_with(self)
136 }
137
138 fn fold_region(&mut self, r: I::Region) -> I::Region {
141 r
142 }
143
144 fn fold_const(&mut self, c: I::Const) -> I::Const {
145 c.super_fold_with(self)
146 }
147
148 fn fold_predicate(&mut self, p: I::Predicate) -> I::Predicate {
149 p.super_fold_with(self)
150 }
151
152 fn fold_clauses(&mut self, c: I::Clauses) -> I::Clauses {
153 c.super_fold_with(self)
154 }
155}
156
157pub trait FallibleTypeFolder<I: Interner>: Sized {
165 type Error;
166
167 fn cx(&self) -> I;
168
169 fn try_fold_binder<T>(&mut self, t: ty::Binder<I, T>) -> Result<ty::Binder<I, T>, Self::Error>
170 where
171 T: TypeFoldable<I>,
172 {
173 t.try_super_fold_with(self)
174 }
175
176 fn try_fold_ty(&mut self, t: I::Ty) -> Result<I::Ty, Self::Error> {
177 t.try_super_fold_with(self)
178 }
179
180 fn try_fold_region(&mut self, r: I::Region) -> Result<I::Region, Self::Error> {
183 Ok(r)
184 }
185
186 fn try_fold_const(&mut self, c: I::Const) -> Result<I::Const, Self::Error> {
187 c.try_super_fold_with(self)
188 }
189
190 fn try_fold_predicate(&mut self, p: I::Predicate) -> Result<I::Predicate, Self::Error> {
191 p.try_super_fold_with(self)
192 }
193
194 fn try_fold_clauses(&mut self, c: I::Clauses) -> Result<I::Clauses, Self::Error> {
195 c.try_super_fold_with(self)
196 }
197}
198
199impl<I: Interner, T: TypeFoldable<I>, U: TypeFoldable<I>> TypeFoldable<I> for (T, U) {
203 fn try_fold_with<F: FallibleTypeFolder<I>>(self, folder: &mut F) -> Result<(T, U), F::Error> {
204 Ok((self.0.try_fold_with(folder)?, self.1.try_fold_with(folder)?))
205 }
206
207 fn fold_with<F: TypeFolder<I>>(self, folder: &mut F) -> Self {
208 (self.0.fold_with(folder), self.1.fold_with(folder))
209 }
210}
211
212impl<I: Interner, A: TypeFoldable<I>, B: TypeFoldable<I>, C: TypeFoldable<I>> TypeFoldable<I>
213 for (A, B, C)
214{
215 fn try_fold_with<F: FallibleTypeFolder<I>>(
216 self,
217 folder: &mut F,
218 ) -> Result<(A, B, C), F::Error> {
219 Ok((
220 self.0.try_fold_with(folder)?,
221 self.1.try_fold_with(folder)?,
222 self.2.try_fold_with(folder)?,
223 ))
224 }
225
226 fn fold_with<F: TypeFolder<I>>(self, folder: &mut F) -> Self {
227 (self.0.fold_with(folder), self.1.fold_with(folder), self.2.fold_with(folder))
228 }
229}
230
231impl<I: Interner, T: TypeFoldable<I>> TypeFoldable<I> for Option<T> {
232 fn try_fold_with<F: FallibleTypeFolder<I>>(self, folder: &mut F) -> Result<Self, F::Error> {
233 Ok(match self {
234 Some(v) => Some(v.try_fold_with(folder)?),
235 None => None,
236 })
237 }
238
239 fn fold_with<F: TypeFolder<I>>(self, folder: &mut F) -> Self {
240 Some(self?.fold_with(folder))
241 }
242}
243
244impl<I: Interner, T: TypeFoldable<I>, E: TypeFoldable<I>> TypeFoldable<I> for Result<T, E> {
245 fn try_fold_with<F: FallibleTypeFolder<I>>(self, folder: &mut F) -> Result<Self, F::Error> {
246 Ok(match self {
247 Ok(v) => Ok(v.try_fold_with(folder)?),
248 Err(e) => Err(e.try_fold_with(folder)?),
249 })
250 }
251
252 fn fold_with<F: TypeFolder<I>>(self, folder: &mut F) -> Self {
253 match self {
254 Ok(v) => Ok(v.fold_with(folder)),
255 Err(e) => Err(e.fold_with(folder)),
256 }
257 }
258}
259
260fn fold_arc<T: Clone, E>(
261 mut arc: Arc<T>,
262 fold: impl FnOnce(T) -> Result<T, E>,
263) -> Result<Arc<T>, E> {
264 unsafe {
268 Arc::make_mut(&mut arc);
274
275 let ptr = Arc::into_raw(arc).cast::<mem::ManuallyDrop<T>>();
278 let mut unique = Arc::from_raw(ptr);
279
280 let slot = Arc::get_mut(&mut unique).unwrap_unchecked();
284
285 let owned = mem::ManuallyDrop::take(slot);
290 let folded = fold(owned)?;
291 *slot = mem::ManuallyDrop::new(folded);
292
293 Ok(Arc::from_raw(Arc::into_raw(unique).cast()))
295 }
296}
297
298impl<I: Interner, T: TypeFoldable<I>> TypeFoldable<I> for Arc<T> {
299 fn try_fold_with<F: FallibleTypeFolder<I>>(self, folder: &mut F) -> Result<Self, F::Error> {
300 fold_arc(self, |t| t.try_fold_with(folder))
301 }
302
303 fn fold_with<F: TypeFolder<I>>(self, folder: &mut F) -> Self {
304 match fold_arc::<T, Infallible>(self, |t| Ok(t.fold_with(folder))) {
305 Ok(t) => t,
306 }
307 }
308}
309
310impl<I: Interner, T: TypeFoldable<I>> TypeFoldable<I> for Box<T> {
311 fn try_fold_with<F: FallibleTypeFolder<I>>(mut self, folder: &mut F) -> Result<Self, F::Error> {
312 *self = (*self).try_fold_with(folder)?;
313 Ok(self)
314 }
315
316 fn fold_with<F: TypeFolder<I>>(mut self, folder: &mut F) -> Self {
317 *self = (*self).fold_with(folder);
318 self
319 }
320}
321
322impl<I: Interner, T: TypeFoldable<I>> TypeFoldable<I> for Vec<T> {
323 fn try_fold_with<F: FallibleTypeFolder<I>>(self, folder: &mut F) -> Result<Self, F::Error> {
324 self.into_iter().map(|t| t.try_fold_with(folder)).collect()
325 }
326
327 fn fold_with<F: TypeFolder<I>>(self, folder: &mut F) -> Self {
328 self.into_iter().map(|t| t.fold_with(folder)).collect()
329 }
330}
331
332impl<I: Interner, T: TypeFoldable<I>> TypeFoldable<I> for ThinVec<T> {
333 fn try_fold_with<F: FallibleTypeFolder<I>>(self, folder: &mut F) -> Result<Self, F::Error> {
334 self.into_iter().map(|t| t.try_fold_with(folder)).collect()
335 }
336
337 fn fold_with<F: TypeFolder<I>>(self, folder: &mut F) -> Self {
338 self.into_iter().map(|t| t.fold_with(folder)).collect()
339 }
340}
341
342impl<I: Interner, T: TypeFoldable<I>> TypeFoldable<I> for Box<[T]> {
343 fn try_fold_with<F: FallibleTypeFolder<I>>(self, folder: &mut F) -> Result<Self, F::Error> {
344 Vec::from(self).try_fold_with(folder).map(Vec::into_boxed_slice)
345 }
346
347 fn fold_with<F: TypeFolder<I>>(self, folder: &mut F) -> Self {
348 Vec::into_boxed_slice(Vec::from(self).fold_with(folder))
349 }
350}
351
352impl<I: Interner, T: TypeFoldable<I>, Ix: Idx> TypeFoldable<I> for IndexVec<Ix, T> {
353 fn try_fold_with<F: FallibleTypeFolder<I>>(self, folder: &mut F) -> Result<Self, F::Error> {
354 self.raw.try_fold_with(folder).map(IndexVec::from_raw)
355 }
356
357 fn fold_with<F: TypeFolder<I>>(self, folder: &mut F) -> Self {
358 IndexVec::from_raw(self.raw.fold_with(folder))
359 }
360}
361
362struct Shifter<I: Interner> {
372 cx: I,
373 current_index: ty::DebruijnIndex,
374 amount: u32,
375}
376
377impl<I: Interner> Shifter<I> {
378 fn new(cx: I, amount: u32) -> Self {
379 Shifter { cx, current_index: ty::INNERMOST, amount }
380 }
381}
382
383impl<I: Interner> TypeFolder<I> for Shifter<I> {
384 fn cx(&self) -> I {
385 self.cx
386 }
387
388 fn fold_binder<T: TypeFoldable<I>>(&mut self, t: ty::Binder<I, T>) -> ty::Binder<I, T> {
389 self.current_index.shift_in(1);
390 let t = t.super_fold_with(self);
391 self.current_index.shift_out(1);
392 t
393 }
394
395 fn fold_region(&mut self, r: I::Region) -> I::Region {
396 match r.kind() {
397 ty::ReBound(ty::BoundVarIndexKind::Bound(debruijn), br)
398 if debruijn >= self.current_index =>
399 {
400 let debruijn = debruijn.shifted_in(self.amount);
401 Region::new_bound(self.cx, debruijn, br)
402 }
403 _ => r,
404 }
405 }
406
407 fn fold_ty(&mut self, ty: I::Ty) -> I::Ty {
408 match ty.kind() {
409 ty::Bound(BoundVarIndexKind::Bound(debruijn), bound_ty)
410 if debruijn >= self.current_index =>
411 {
412 let debruijn = debruijn.shifted_in(self.amount);
413 Ty::new_bound(self.cx, debruijn, bound_ty)
414 }
415
416 _ if ty.has_vars_bound_at_or_above(self.current_index) => ty.super_fold_with(self),
417 _ => ty,
418 }
419 }
420
421 fn fold_const(&mut self, ct: I::Const) -> I::Const {
422 match ct.kind() {
423 ty::ConstKind::Bound(ty::BoundVarIndexKind::Bound(debruijn), bound_ct)
424 if debruijn >= self.current_index =>
425 {
426 let debruijn = debruijn.shifted_in(self.amount);
427 Const::new_bound(self.cx, debruijn, bound_ct)
428 }
429 _ => ct.super_fold_with(self),
430 }
431 }
432
433 fn fold_predicate(&mut self, p: I::Predicate) -> I::Predicate {
434 if p.has_vars_bound_at_or_above(self.current_index) { p.super_fold_with(self) } else { p }
435 }
436
437 fn fold_clauses(&mut self, c: I::Clauses) -> I::Clauses {
438 if c.has_vars_bound_at_or_above(self.current_index) { c.super_fold_with(self) } else { c }
439 }
440}
441
442pub fn shift_region<I: Interner>(cx: I, region: I::Region, amount: u32) -> I::Region {
443 match region.kind() {
444 ty::ReBound(ty::BoundVarIndexKind::Bound(debruijn), br) if amount > 0 => {
445 Region::new_bound(cx, debruijn.shifted_in(amount), br)
446 }
447 _ => region,
448 }
449}
450
451x;#[instrument(level = "trace", skip(cx), ret)]
452pub fn shift_vars<I: Interner, T>(cx: I, value: T, amount: u32) -> T
453where
454 T: TypeFoldable<I>,
455{
456 if amount == 0 || !value.has_escaping_bound_vars() {
457 value
458 } else {
459 value.fold_with(&mut Shifter::new(cx, amount))
460 }
461}
462
463pub fn fold_regions<I: Interner, T>(
467 cx: I,
468 value: T,
469 f: impl FnMut(I::Region, ty::DebruijnIndex) -> I::Region,
470) -> T
471where
472 T: TypeFoldable<I>,
473{
474 value.fold_with(&mut RegionFolder::new(cx, f))
475}
476
477pub struct RegionFolder<I, F> {
485 cx: I,
486
487 current_index: ty::DebruijnIndex,
491
492 fold_region_fn: F,
496}
497
498impl<I, F> RegionFolder<I, F> {
499 #[inline]
500 pub fn new(cx: I, fold_region_fn: F) -> RegionFolder<I, F> {
501 RegionFolder { cx, current_index: ty::INNERMOST, fold_region_fn }
502 }
503}
504
505impl<I, F> TypeFolder<I> for RegionFolder<I, F>
506where
507 I: Interner,
508 F: FnMut(I::Region, ty::DebruijnIndex) -> I::Region,
509{
510 fn cx(&self) -> I {
511 self.cx
512 }
513
514 fn fold_binder<T: TypeFoldable<I>>(&mut self, t: ty::Binder<I, T>) -> ty::Binder<I, T> {
515 self.current_index.shift_in(1);
516 let t = t.super_fold_with(self);
517 self.current_index.shift_out(1);
518 t
519 }
520
521 x;#[instrument(skip(self), level = "debug", ret)]
522 fn fold_region(&mut self, r: I::Region) -> I::Region {
523 match r.kind() {
524 ty::ReBound(ty::BoundVarIndexKind::Bound(debruijn), _)
525 if debruijn < self.current_index =>
526 {
527 debug!(?self.current_index, "skipped bound region");
528 r
529 }
530 ty::ReBound(ty::BoundVarIndexKind::Canonical, _) => {
531 debug!(?self.current_index, "skipped bound region");
532 r
533 }
534 _ => {
535 debug!(?self.current_index, "folding free region");
536 (self.fold_region_fn)(r, self.current_index)
537 }
538 }
539 }
540
541 fn fold_ty(&mut self, t: I::Ty) -> I::Ty {
542 if t.has_regions() { t.super_fold_with(self) } else { t }
543 }
544
545 fn fold_const(&mut self, ct: I::Const) -> I::Const {
546 if ct.has_regions() { ct.super_fold_with(self) } else { ct }
547 }
548
549 fn fold_predicate(&mut self, p: I::Predicate) -> I::Predicate {
550 if p.has_regions() { p.super_fold_with(self) } else { p }
551 }
552
553 fn fold_clauses(&mut self, c: I::Clauses) -> I::Clauses {
554 if c.has_regions() { c.super_fold_with(self) } else { c }
555 }
556}