1use std::ops::ControlFlow;
5
6use flux_arc_interner::{Internable, List};
7use flux_common::bug;
8use itertools::Itertools;
9use rustc_data_structures::unord::{UnordMap, UnordSet};
10use rustc_hash::FxHashSet;
11use rustc_type_ir::{BoundVar, DebruijnIndex, INNERMOST};
12
13use super::{
14 BaseTy, Binder, BoundVariableKinds, Const, EVid, EarlyReftParam, Ensures, Expr, ExprKind,
15 GenericArg, Name, OutlivesPredicate, PolyFuncSort, PtrKind, ReBound, ReErased, Region, Sort,
16 SubsetTy, Ty, TyKind, TyOrBase, reduce::Reducer,
17};
18use crate::{
19 global_env::GlobalEnv,
20 rty::{BoundReft, BoundRegion, Var, VariantSig, expr::HoleKind},
21};
22
23pub trait TypeVisitor: Sized {
24 type BreakTy = !;
25
26 fn enter_binder(&mut self, _vars: &BoundVariableKinds) {}
27
28 fn exit_binder(&mut self) {}
29
30 fn visit_expr(&mut self, expr: &Expr) -> ControlFlow<Self::BreakTy> {
31 expr.super_visit_with(self)
32 }
33
34 fn visit_sort(&mut self, sort: &Sort) -> ControlFlow<Self::BreakTy> {
35 sort.super_visit_with(self)
36 }
37
38 fn visit_ty(&mut self, ty: &Ty) -> ControlFlow<Self::BreakTy> {
39 ty.super_visit_with(self)
40 }
41
42 fn visit_bty(&mut self, bty: &BaseTy) -> ControlFlow<Self::BreakTy> {
43 bty.super_visit_with(self)
44 }
45}
46
47pub trait FallibleTypeFolder: Sized {
48 type Error;
49
50 fn try_enter_binder(&mut self, _vars: &BoundVariableKinds) {}
51
52 fn try_exit_binder(&mut self) {}
53
54 fn try_fold_sort(&mut self, sort: &Sort) -> Result<Sort, Self::Error> {
55 sort.try_super_fold_with(self)
56 }
57
58 fn try_fold_ty(&mut self, ty: &Ty) -> Result<Ty, Self::Error> {
59 ty.try_super_fold_with(self)
60 }
61
62 fn try_fold_bty(&mut self, bty: &BaseTy) -> Result<BaseTy, Self::Error> {
63 bty.try_super_fold_with(self)
64 }
65
66 fn try_fold_subset_ty(&mut self, constr: &SubsetTy) -> Result<SubsetTy, Self::Error> {
67 constr.try_super_fold_with(self)
68 }
69
70 fn try_fold_region(&mut self, re: &Region) -> Result<Region, Self::Error> {
71 Ok(*re)
72 }
73
74 fn try_fold_const(&mut self, c: &Const) -> Result<Const, Self::Error> {
75 c.try_super_fold_with(self)
76 }
77
78 fn try_fold_expr(&mut self, expr: &Expr) -> Result<Expr, Self::Error> {
79 expr.try_super_fold_with(self)
80 }
81}
82
83pub trait TypeFolder: FallibleTypeFolder<Error = !> {
84 fn enter_binder(&mut self, _vars: &BoundVariableKinds) {}
85
86 fn exit_binder(&mut self) {}
87
88 fn fold_sort(&mut self, sort: &Sort) -> Sort {
89 sort.super_fold_with(self)
90 }
91
92 fn fold_ty(&mut self, ty: &Ty) -> Ty {
93 ty.super_fold_with(self)
94 }
95
96 fn fold_bty(&mut self, bty: &BaseTy) -> BaseTy {
97 bty.super_fold_with(self)
98 }
99
100 fn fold_subset_ty(&mut self, constr: &SubsetTy) -> SubsetTy {
101 constr.super_fold_with(self)
102 }
103
104 fn fold_region(&mut self, re: &Region) -> Region {
105 *re
106 }
107
108 fn fold_const(&mut self, c: &Const) -> Const {
109 c.super_fold_with(self)
110 }
111
112 fn fold_expr(&mut self, expr: &Expr) -> Expr {
113 expr.super_fold_with(self)
114 }
115}
116
117impl<F> FallibleTypeFolder for F
118where
119 F: TypeFolder,
120{
121 type Error = !;
122
123 fn try_enter_binder(&mut self, vars: &BoundVariableKinds) {
124 self.enter_binder(vars);
125 }
126
127 fn try_exit_binder(&mut self) {
128 self.exit_binder();
129 }
130
131 fn try_fold_sort(&mut self, sort: &Sort) -> Result<Sort, Self::Error> {
132 Ok(self.fold_sort(sort))
133 }
134
135 fn try_fold_ty(&mut self, ty: &Ty) -> Result<Ty, Self::Error> {
136 Ok(self.fold_ty(ty))
137 }
138
139 fn try_fold_bty(&mut self, bty: &BaseTy) -> Result<BaseTy, Self::Error> {
140 Ok(self.fold_bty(bty))
141 }
142
143 fn try_fold_subset_ty(&mut self, ty: &SubsetTy) -> Result<SubsetTy, Self::Error> {
144 Ok(self.fold_subset_ty(ty))
145 }
146
147 fn try_fold_region(&mut self, re: &Region) -> Result<Region, Self::Error> {
148 Ok(self.fold_region(re))
149 }
150
151 fn try_fold_const(&mut self, c: &Const) -> Result<Const, Self::Error> {
152 Ok(self.fold_const(c))
153 }
154
155 fn try_fold_expr(&mut self, expr: &Expr) -> Result<Expr, Self::Error> {
156 Ok(self.fold_expr(expr))
157 }
158}
159
160pub trait TypeVisitable: Sized {
161 fn visit_with<V: TypeVisitor>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy>;
162
163 fn has_escaping_bvars(&self) -> bool {
164 self.has_escaping_bvars_at_or_above(INNERMOST)
165 }
166
167 fn has_escaping_bvars_at_or_above(&self, binder: DebruijnIndex) -> bool {
172 struct HasEscapingVars {
173 outer_index: DebruijnIndex,
175 }
176
177 impl TypeVisitor for HasEscapingVars {
178 type BreakTy = ();
179
180 fn enter_binder(&mut self, _: &BoundVariableKinds) {
181 self.outer_index.shift_in(1);
182 }
183
184 fn exit_binder(&mut self) {
185 self.outer_index.shift_out(1);
186 }
187
188 fn visit_expr(&mut self, expr: &Expr) -> ControlFlow<()> {
191 if let ExprKind::Var(Var::Bound(debruijn, _)) = expr.kind() {
192 if *debruijn >= self.outer_index {
193 ControlFlow::Break(())
194 } else {
195 ControlFlow::Continue(())
196 }
197 } else {
198 expr.super_visit_with(self)
199 }
200 }
201 }
202 let mut visitor = HasEscapingVars { outer_index: binder };
203 self.visit_with(&mut visitor).is_break()
204 }
205
206 fn fvars(&self) -> FxHashSet<Name> {
209 struct CollectFreeVars(FxHashSet<Name>);
210
211 impl TypeVisitor for CollectFreeVars {
212 fn visit_expr(&mut self, e: &Expr) -> ControlFlow<Self::BreakTy> {
213 if let ExprKind::Var(Var::Free(name)) = e.kind() {
214 self.0.insert(*name);
215 }
216 e.super_visit_with(self)
217 }
218 }
219
220 let mut collector = CollectFreeVars(FxHashSet::default());
221 let _ = self.visit_with(&mut collector);
222 collector.0
223 }
224
225 fn early_params(&self) -> FxHashSet<EarlyReftParam> {
226 struct CollectEarlyParams(FxHashSet<EarlyReftParam>);
227
228 impl TypeVisitor for CollectEarlyParams {
229 fn visit_expr(&mut self, e: &Expr) -> ControlFlow<Self::BreakTy> {
230 if let ExprKind::Var(Var::EarlyParam(param)) = e.kind() {
231 self.0.insert(*param);
232 }
233 e.super_visit_with(self)
234 }
235 }
236
237 let mut collector = CollectEarlyParams(FxHashSet::default());
238 let _ = self.visit_with(&mut collector);
239 collector.0
240 }
241
242 fn redundant_bvars(&self) -> UnordSet<BoundVar> {
266 struct RedundantBVarFinder {
267 current_index: DebruijnIndex,
268 total_bvar_occurrences: UnordMap<BoundVar, usize>,
269 bvars_appearing_in_index: UnordSet<BoundVar>,
270 }
271
272 impl TypeVisitor for RedundantBVarFinder {
273 fn visit_expr(&mut self, e: &Expr) -> ControlFlow<Self::BreakTy> {
275 if let ExprKind::Var(Var::Bound(debruijn, BoundReft { var, .. })) = e.kind()
276 && debruijn == &self.current_index
277 {
278 self.total_bvar_occurrences
279 .entry(*var)
280 .and_modify(|count| {
281 *count += 1;
282 })
283 .or_insert(1);
284 }
285 e.super_visit_with(self)
286 }
287
288 fn visit_ty(&mut self, ty: &Ty) -> ControlFlow<Self::BreakTy> {
289 if let TyKind::Indexed(_bty, expr) = ty.kind() {
292 match expr.kind() {
293 ExprKind::Var(Var::Bound(debruijn, BoundReft { var, .. })) => {
294 if debruijn == &self.current_index {
295 self.bvars_appearing_in_index.insert(*var);
296 }
297 }
298 ExprKind::Ctor(_ctor, exprs) => {
299 exprs.iter().for_each(|expr| {
300 if let ExprKind::Var(Var::Bound(debruijn, BoundReft { var, .. })) =
301 expr.kind()
302 && debruijn == &self.current_index
303 {
304 self.bvars_appearing_in_index.insert(*var);
305 }
306 });
307 }
308 _ => {}
309 }
310 }
311 ty.super_visit_with(self)
312 }
313
314 fn enter_binder(&mut self, _: &BoundVariableKinds) {
315 self.current_index.shift_in(1);
316 }
317
318 fn exit_binder(&mut self) {
319 self.current_index.shift_out(1);
320 }
321 }
322
323 let mut finder = RedundantBVarFinder {
324 current_index: INNERMOST,
325 total_bvar_occurrences: UnordMap::default(),
326 bvars_appearing_in_index: UnordSet::new(),
327 };
328 let _ = self.visit_with(&mut finder);
329
330 let RedundantBVarFinder { bvars_appearing_in_index, total_bvar_occurrences, .. } = finder;
331 bvars_appearing_in_index
332 .into_items()
333 .filter(|var_index| total_bvar_occurrences.get(var_index) == Some(&1))
334 .collect()
335 }
336}
337
338pub trait TypeSuperVisitable: TypeVisitable {
339 fn super_visit_with<V: TypeVisitor>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy>;
340}
341
342pub trait TypeFoldable: TypeVisitable {
343 fn try_fold_with<F: FallibleTypeFolder>(&self, folder: &mut F) -> Result<Self, F::Error>;
344
345 fn fold_with<F: TypeFolder>(&self, folder: &mut F) -> Self {
346 self.try_fold_with(folder).into_ok()
347 }
348
349 fn reduce(&self, genv: GlobalEnv) -> Self {
354 self.fold_with(&mut Reducer::new(genv))
355 }
356
357 fn replace_holes(&self, f: impl FnMut(&[BoundVariableKinds], HoleKind) -> Expr) -> Self {
365 struct ReplaceHoles<F>(F, Vec<BoundVariableKinds>);
366
367 impl<F> TypeFolder for ReplaceHoles<F>
368 where
369 F: FnMut(&[BoundVariableKinds], HoleKind) -> Expr,
370 {
371 fn enter_binder(&mut self, vars: &BoundVariableKinds) {
372 self.1.push(vars.clone());
373 }
374
375 fn exit_binder(&mut self) {
376 self.1.pop();
377 }
378
379 fn fold_expr(&mut self, e: &Expr) -> Expr {
380 if let ExprKind::Hole(kind) = e.kind() {
381 self.0(&self.1, kind.clone())
382 } else {
383 e.super_fold_with(self)
384 }
385 }
386 }
387
388 self.fold_with(&mut ReplaceHoles(f, vec![]))
389 }
390
391 fn with_holes(&self) -> Self {
397 struct WithHoles;
398
399 impl TypeFolder for WithHoles {
400 fn fold_ty(&mut self, ty: &Ty) -> Ty {
401 if let Some(bty) = ty.as_bty_skipping_existentials() {
402 Ty::exists_with_constr(bty.fold_with(self), Expr::hole(HoleKind::Pred))
403 } else {
404 ty.super_fold_with(self)
405 }
406 }
407
408 fn fold_subset_ty(&mut self, constr: &SubsetTy) -> SubsetTy {
409 SubsetTy::new(constr.bty.clone(), constr.idx.clone(), Expr::hole(HoleKind::Pred))
410 }
411 }
412
413 self.fold_with(&mut WithHoles)
414 }
415
416 fn replace_evars(&self, f: &mut impl FnMut(EVid) -> Option<Expr>) -> Result<Self, EVid> {
417 struct Folder<F>(F);
418 impl<F: FnMut(EVid) -> Option<Expr>> FallibleTypeFolder for Folder<F> {
419 type Error = EVid;
420
421 fn try_fold_expr(&mut self, expr: &Expr) -> Result<Expr, Self::Error> {
422 if let ExprKind::Var(Var::EVar(evid)) = expr.kind() {
423 if let Some(sol) = (self.0)(*evid) { Ok(sol.clone()) } else { Err(*evid) }
424 } else {
425 expr.try_super_fold_with(self)
426 }
427 }
428 }
429
430 self.try_fold_with(&mut Folder(f))
431 }
432
433 fn shift_horizontally(&self, amount: usize) -> Self {
436 struct Shifter {
437 current_index: DebruijnIndex,
438 amount: usize,
439 }
440
441 impl TypeFolder for Shifter {
442 fn enter_binder(&mut self, _: &BoundVariableKinds) {
443 self.current_index.shift_in(1);
444 }
445
446 fn exit_binder(&mut self) {
447 self.current_index.shift_out(1);
448 }
449
450 fn fold_region(&mut self, re: &Region) -> Region {
451 if let ReBound(debruijn, br) = *re
452 && debruijn == self.current_index
453 {
454 ReBound(debruijn, BoundRegion { var: br.var + self.amount, kind: br.kind })
455 } else {
456 *re
457 }
458 }
459
460 fn fold_expr(&mut self, expr: &Expr) -> Expr {
461 if let ExprKind::Var(Var::Bound(debruijn, breft)) = expr.kind()
462 && debruijn == &self.current_index
463 {
464 Expr::bvar(*debruijn, breft.var + self.amount, breft.kind)
465 } else {
466 expr.super_fold_with(self)
467 }
468 }
469 }
470 self.fold_with(&mut Shifter { amount, current_index: INNERMOST })
471 }
472
473 fn shift_in_escaping(&self, amount: u32) -> Self {
474 struct Shifter {
475 current_index: DebruijnIndex,
476 amount: u32,
477 }
478
479 impl TypeFolder for Shifter {
480 fn enter_binder(&mut self, _: &BoundVariableKinds) {
481 self.current_index.shift_in(1);
482 }
483
484 fn exit_binder(&mut self) {
485 self.current_index.shift_out(1);
486 }
487
488 fn fold_region(&mut self, re: &Region) -> Region {
489 if let ReBound(debruijn, br) = *re
490 && debruijn >= self.current_index
491 {
492 ReBound(debruijn.shifted_in(self.amount), br)
493 } else {
494 *re
495 }
496 }
497
498 fn fold_expr(&mut self, expr: &Expr) -> Expr {
499 if let ExprKind::Var(Var::Bound(debruijn, breft)) = expr.kind()
500 && *debruijn >= self.current_index
501 {
502 Expr::bvar(debruijn.shifted_in(self.amount), breft.var, breft.kind)
503 } else {
504 expr.super_fold_with(self)
505 }
506 }
507 }
508 self.fold_with(&mut Shifter { amount, current_index: INNERMOST })
509 }
510
511 fn shift_out_escaping(&self, amount: u32) -> Self {
512 struct Shifter {
513 amount: u32,
514 current_index: DebruijnIndex,
515 }
516
517 impl TypeFolder for Shifter {
518 fn enter_binder(&mut self, _: &BoundVariableKinds) {
519 self.current_index.shift_in(1);
520 }
521
522 fn exit_binder(&mut self) {
523 self.current_index.shift_out(1);
524 }
525
526 fn fold_region(&mut self, re: &Region) -> Region {
527 if let ReBound(debruijn, br) = *re
528 && debruijn >= self.current_index
529 {
530 ReBound(debruijn.shifted_out(self.amount), br)
531 } else {
532 *re
533 }
534 }
535
536 fn fold_expr(&mut self, expr: &Expr) -> Expr {
537 if let ExprKind::Var(Var::Bound(debruijn, breft)) = expr.kind()
538 && debruijn >= &self.current_index
539 {
540 Expr::bvar(debruijn.shifted_out(self.amount), breft.var, breft.kind)
541 } else {
542 expr.super_fold_with(self)
543 }
544 }
545 }
546 self.fold_with(&mut Shifter { amount, current_index: INNERMOST })
547 }
548
549 fn erase_regions(&self) -> Self {
550 struct RegionEraser;
551 impl TypeFolder for RegionEraser {
552 fn fold_region(&mut self, r: &Region) -> Region {
553 match *r {
554 ReBound(..) => *r,
555 _ => ReErased,
556 }
557 }
558 }
559
560 self.fold_with(&mut RegionEraser)
561 }
562
563 fn erase_regions_including_bound(&self) -> Self {
565 struct RegionEraser;
566 impl TypeFolder for RegionEraser {
567 fn fold_region(&mut self, _: &Region) -> Region {
568 ReErased
569 }
570 }
571
572 self.fold_with(&mut RegionEraser)
573 }
574}
575
576pub trait TypeSuperFoldable: TypeFoldable {
577 fn try_super_fold_with<F: FallibleTypeFolder>(&self, folder: &mut F) -> Result<Self, F::Error>;
578
579 fn super_fold_with<F: TypeFolder>(&self, folder: &mut F) -> Self {
580 self.try_super_fold_with(folder).into_ok()
581 }
582}
583
584impl<T: TypeVisitable> TypeVisitable for OutlivesPredicate<T> {
585 fn visit_with<V: TypeVisitor>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy> {
586 self.0.visit_with(visitor)?;
587 self.1.visit_with(visitor)
588 }
589}
590
591impl<T: TypeFoldable> TypeFoldable for OutlivesPredicate<T> {
592 fn try_fold_with<F: FallibleTypeFolder>(&self, folder: &mut F) -> Result<Self, F::Error> {
593 Ok(OutlivesPredicate(self.0.try_fold_with(folder)?, self.1.try_fold_with(folder)?))
594 }
595}
596
597impl TypeVisitable for Sort {
598 fn visit_with<V: TypeVisitor>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy> {
599 visitor.visit_sort(self)
600 }
601}
602
603impl TypeSuperVisitable for Sort {
604 fn super_visit_with<V: TypeVisitor>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy> {
605 match self {
606 Sort::Tuple(sorts) => sorts.visit_with(visitor),
607 Sort::App(_, args) => args.visit_with(visitor),
608 Sort::Func(fsort) => fsort.visit_with(visitor),
609 Sort::Alias(alias_ty) => alias_ty.visit_with(visitor),
610 Sort::Int
611 | Sort::Bool
612 | Sort::Real
613 | Sort::Str
614 | Sort::Char
615 | Sort::BitVec(_)
616 | Sort::Loc
617 | Sort::Param(_)
618 | Sort::Var(_)
619 | Sort::Infer(_)
620 | Sort::RawPtr
621 | Sort::Err => ControlFlow::Continue(()),
622 }
623 }
624}
625
626impl TypeFoldable for Sort {
627 fn try_fold_with<F: FallibleTypeFolder>(&self, folder: &mut F) -> Result<Self, F::Error> {
628 folder.try_fold_sort(self)
629 }
630}
631
632impl TypeSuperFoldable for Sort {
633 fn try_super_fold_with<F: FallibleTypeFolder>(&self, folder: &mut F) -> Result<Self, F::Error> {
634 let sort = match self {
635 Sort::Tuple(sorts) => Sort::tuple(sorts.try_fold_with(folder)?),
636 Sort::App(ctor, sorts) => Sort::app(ctor.clone(), sorts.try_fold_with(folder)?),
637 Sort::Func(fsort) => Sort::Func(fsort.try_fold_with(folder)?),
638 Sort::Alias(alias_ty) => Sort::Alias(alias_ty.try_fold_with(folder)?),
639 Sort::Int
640 | Sort::Bool
641 | Sort::Real
642 | Sort::Loc
643 | Sort::Str
644 | Sort::Char
645 | Sort::BitVec(_)
646 | Sort::Param(_)
647 | Sort::Var(_)
648 | Sort::Infer(_)
649 | Sort::RawPtr
650 | Sort::Err => self.clone(),
651 };
652 Ok(sort)
653 }
654}
655
656impl TypeVisitable for PolyFuncSort {
657 fn visit_with<V: TypeVisitor>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy> {
658 self.fsort.visit_with(visitor)
659 }
660}
661
662impl TypeFoldable for PolyFuncSort {
663 fn try_fold_with<F: FallibleTypeFolder>(&self, folder: &mut F) -> Result<Self, F::Error> {
664 Ok(PolyFuncSort { params: self.params.clone(), fsort: self.fsort.try_fold_with(folder)? })
665 }
666}
667
668impl<T> TypeVisitable for Binder<T>
669where
670 T: TypeVisitable,
671{
672 fn visit_with<V: TypeVisitor>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy> {
673 self.vars().visit_with(visitor)?;
674 visitor.enter_binder(self.vars());
675 self.skip_binder_ref().visit_with(visitor)?;
676 visitor.exit_binder();
677 ControlFlow::Continue(())
678 }
679}
680
681impl<T> TypeSuperVisitable for Binder<T>
682where
683 T: TypeVisitable,
684{
685 fn super_visit_with<V: TypeVisitor>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy> {
686 self.skip_binder_ref().visit_with(visitor)
687 }
688}
689
690impl<T> TypeFoldable for Binder<T>
691where
692 T: TypeFoldable,
693{
694 fn try_fold_with<F: FallibleTypeFolder>(&self, folder: &mut F) -> Result<Self, F::Error> {
695 let vars = self.vars().try_fold_with(folder)?;
696 folder.try_enter_binder(&vars);
697 let r = self.skip_binder_ref().try_fold_with(folder)?;
698 folder.try_exit_binder();
699 Ok(Binder::bind_with_vars(r, vars))
700 }
701}
702
703impl TypeVisitable for VariantSig {
704 fn visit_with<V: TypeVisitor>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy> {
705 self.fields.visit_with(visitor)?;
706 self.idx.visit_with(visitor)
707 }
708}
709
710impl TypeFoldable for VariantSig {
711 fn try_fold_with<F: FallibleTypeFolder>(&self, folder: &mut F) -> Result<Self, F::Error> {
712 let args = self.args.try_fold_with(folder)?;
713 let fields = self.fields.try_fold_with(folder)?;
714 let idx = self.idx.try_fold_with(folder)?;
715 let requires = self.requires.try_fold_with(folder)?;
716 Ok(VariantSig::new(self.adt_def.clone(), args, fields, idx, requires))
717 }
718}
719
720impl<T: TypeVisitable> TypeVisitable for Vec<T> {
721 fn visit_with<V: TypeVisitor>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy> {
722 self.iter().try_for_each(|t| t.visit_with(visitor))
723 }
724}
725
726impl TypeVisitable for Ensures {
727 fn visit_with<V: TypeVisitor>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy> {
728 match self {
729 Ensures::Type(path, ty) => {
730 path.to_expr().visit_with(visitor)?;
731 ty.visit_with(visitor)
732 }
733 Ensures::Pred(e) => e.visit_with(visitor),
734 }
735 }
736}
737
738impl TypeFoldable for Ensures {
739 fn try_fold_with<F: FallibleTypeFolder>(&self, folder: &mut F) -> Result<Self, F::Error> {
740 let c = match self {
741 Ensures::Type(path, ty) => {
742 let path_expr = path.to_expr().try_fold_with(folder)?;
743 Ensures::Type(
744 path_expr.to_path().unwrap_or_else(|| {
745 bug!("invalid path `{path_expr:?}` produced when folding `{self:?}`",)
746 }),
747 ty.try_fold_with(folder)?,
748 )
749 }
750 Ensures::Pred(e) => Ensures::Pred(e.try_fold_with(folder)?),
751 };
752 Ok(c)
753 }
754}
755
756impl TypeVisitable for super::TyOrBase {
757 fn visit_with<V: TypeVisitor>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy> {
758 match self {
759 Self::Ty(ty) => ty.visit_with(visitor),
760 Self::Base(bty) => bty.visit_with(visitor),
761 }
762 }
763}
764
765impl TypeVisitable for Ty {
766 fn visit_with<V: TypeVisitor>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy> {
767 visitor.visit_ty(self)
768 }
769}
770
771impl TypeSuperVisitable for Ty {
772 fn super_visit_with<V: TypeVisitor>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy> {
773 match self.kind() {
774 TyKind::Indexed(bty, idxs) => {
775 bty.visit_with(visitor)?;
776 idxs.visit_with(visitor)
777 }
778 TyKind::Exists(exists) => exists.visit_with(visitor),
779 TyKind::StrgRef(_, path, ty) => {
780 path.to_expr().visit_with(visitor)?;
781 ty.visit_with(visitor)
782 }
783 TyKind::Ptr(_, path) => path.to_expr().visit_with(visitor),
784 TyKind::Constr(pred, ty) => {
785 pred.visit_with(visitor)?;
786 ty.visit_with(visitor)
787 }
788 TyKind::Downcast(.., args, _, fields) => {
789 args.visit_with(visitor)?;
790 fields.visit_with(visitor)
791 }
792 TyKind::Blocked(ty) => ty.visit_with(visitor),
793 TyKind::Infer(_) | TyKind::Param(_) | TyKind::Discr(..) | TyKind::Uninit => {
794 ControlFlow::Continue(())
795 }
796 }
797 }
798}
799
800impl TypeFoldable for Ty {
801 fn try_fold_with<F: FallibleTypeFolder>(&self, folder: &mut F) -> Result<Self, F::Error> {
802 folder.try_fold_ty(self)
803 }
804}
805
806impl TypeSuperFoldable for Ty {
807 fn try_super_fold_with<F: FallibleTypeFolder>(&self, folder: &mut F) -> Result<Ty, F::Error> {
808 let ty = match self.kind() {
809 TyKind::Indexed(bty, idxs) => {
810 Ty::indexed(bty.try_fold_with(folder)?, idxs.try_fold_with(folder)?)
811 }
812 TyKind::Exists(exists) => TyKind::Exists(exists.try_fold_with(folder)?).intern(),
813 TyKind::StrgRef(re, path, ty) => {
814 Ty::strg_ref(
815 re.try_fold_with(folder)?,
816 path.to_expr()
817 .try_fold_with(folder)?
818 .to_path()
819 .expect("type folding produced an invalid path"),
820 ty.try_fold_with(folder)?,
821 )
822 }
823 TyKind::Ptr(pk, path) => {
824 let pk = match pk {
825 PtrKind::Mut(re) => PtrKind::Mut(re.try_fold_with(folder)?),
826 PtrKind::Box => PtrKind::Box,
827 };
828 Ty::ptr(
829 pk,
830 path.to_expr()
831 .try_fold_with(folder)?
832 .to_path()
833 .expect("type folding produced an invalid path"),
834 )
835 }
836 TyKind::Constr(pred, ty) => {
837 Ty::constr(pred.try_fold_with(folder)?, ty.try_fold_with(folder)?)
838 }
839 TyKind::Downcast(adt, args, ty, variant, fields) => {
840 Ty::downcast(
841 adt.clone(),
842 args.clone(),
843 ty.clone(),
844 *variant,
845 fields.try_fold_with(folder)?,
846 )
847 }
848 TyKind::Blocked(ty) => Ty::blocked(ty.try_fold_with(folder)?),
849 TyKind::Infer(_) | TyKind::Param(_) | TyKind::Uninit | TyKind::Discr(..) => {
850 self.clone()
851 }
852 };
853 Ok(ty)
854 }
855}
856
857impl TypeVisitable for Region {
858 fn visit_with<V: TypeVisitor>(&self, _visitor: &mut V) -> ControlFlow<V::BreakTy> {
859 ControlFlow::Continue(())
860 }
861}
862
863impl TypeFoldable for Region {
864 fn try_fold_with<F: FallibleTypeFolder>(&self, folder: &mut F) -> Result<Self, F::Error> {
865 folder.try_fold_region(self)
866 }
867}
868
869impl TypeSuperFoldable for Const {
870 fn try_super_fold_with<F: FallibleTypeFolder>(
871 &self,
872 _folder: &mut F,
873 ) -> Result<Self, F::Error> {
874 Ok(self.clone())
876 }
877}
878
879impl TypeVisitable for Const {
880 fn visit_with<V: TypeVisitor>(&self, _visitor: &mut V) -> ControlFlow<V::BreakTy> {
881 ControlFlow::Continue(())
882 }
883}
884
885impl TypeFoldable for Const {
886 fn try_fold_with<F: FallibleTypeFolder>(&self, folder: &mut F) -> Result<Self, F::Error> {
887 folder.try_fold_const(self)
888 }
889}
890
891impl TypeVisitable for BaseTy {
892 fn visit_with<V: TypeVisitor>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy> {
893 visitor.visit_bty(self)
894 }
895}
896
897impl TypeSuperVisitable for BaseTy {
898 fn super_visit_with<V: TypeVisitor>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy> {
899 match self {
900 BaseTy::Adt(_, args) => args.visit_with(visitor),
901 BaseTy::FnDef(_, args) => args.visit_with(visitor),
902 BaseTy::Slice(ty) => ty.visit_with(visitor),
903 BaseTy::RawPtr(ty, _) => ty.visit_with(visitor),
904 BaseTy::RawPtrMetadata(ty) => ty.visit_with(visitor),
905 BaseTy::Ref(_, ty, _) => ty.visit_with(visitor),
906 BaseTy::FnPtr(poly_fn_sig) => poly_fn_sig.visit_with(visitor),
907 BaseTy::Tuple(tys) => tys.visit_with(visitor),
908 BaseTy::Alias(alias_ty) => alias_ty.visit_with(visitor),
909 BaseTy::Array(ty, _) => ty.visit_with(visitor),
910 BaseTy::Coroutine(_, resume_ty, upvars, _) => {
911 resume_ty.visit_with(visitor)?;
912 upvars.visit_with(visitor)
913 }
914 BaseTy::Dynamic(exi_preds, _) => exi_preds.visit_with(visitor),
915 BaseTy::Int(_)
916 | BaseTy::Pat
917 | BaseTy::Uint(_)
918 | BaseTy::Bool
919 | BaseTy::Float(_)
920 | BaseTy::Str
921 | BaseTy::Char
922 | BaseTy::Closure(..)
923 | BaseTy::Never
924 | BaseTy::Infer(_)
925 | BaseTy::Foreign(_)
926 | BaseTy::Param(_) => ControlFlow::Continue(()),
927 }
928 }
929}
930
931impl TypeFoldable for BaseTy {
932 fn try_fold_with<F: FallibleTypeFolder>(&self, folder: &mut F) -> Result<Self, F::Error> {
933 folder.try_fold_bty(self)
934 }
935}
936
937impl TypeSuperFoldable for BaseTy {
938 fn try_super_fold_with<F: FallibleTypeFolder>(&self, folder: &mut F) -> Result<Self, F::Error> {
939 let bty = match self {
940 BaseTy::Adt(adt_def, args) => BaseTy::adt(adt_def.clone(), args.try_fold_with(folder)?),
941 BaseTy::FnDef(def_id, args) => BaseTy::fn_def(*def_id, args.try_fold_with(folder)?),
942 BaseTy::Foreign(def_id) => BaseTy::Foreign(*def_id),
943 BaseTy::Slice(ty) => BaseTy::Slice(ty.try_fold_with(folder)?),
944 BaseTy::RawPtr(ty, mu) => BaseTy::RawPtr(ty.try_fold_with(folder)?, *mu),
945 BaseTy::RawPtrMetadata(ty) => BaseTy::RawPtrMetadata(ty.try_fold_with(folder)?),
946 BaseTy::Ref(re, ty, mutbl) => {
947 BaseTy::Ref(re.try_fold_with(folder)?, ty.try_fold_with(folder)?, *mutbl)
948 }
949 BaseTy::FnPtr(decl) => BaseTy::FnPtr(decl.try_fold_with(folder)?),
950 BaseTy::Tuple(tys) => BaseTy::Tuple(tys.try_fold_with(folder)?),
951 BaseTy::Alias(alias_ty) => BaseTy::Alias(alias_ty.try_fold_with(folder)?),
952 BaseTy::Array(ty, c) => {
953 BaseTy::Array(ty.try_fold_with(folder)?, c.try_fold_with(folder)?)
954 }
955 BaseTy::Closure(did, args, gen_args, no_panic) => {
956 BaseTy::Closure(*did, args.try_fold_with(folder)?, gen_args.clone(), *no_panic)
957 }
958 BaseTy::Coroutine(did, resume_ty, args, gen_args) => {
959 BaseTy::Coroutine(
960 *did,
961 resume_ty.try_fold_with(folder)?,
962 args.try_fold_with(folder)?,
963 gen_args.clone(),
964 )
965 }
966 BaseTy::Dynamic(preds, region) => {
967 BaseTy::Dynamic(preds.try_fold_with(folder)?, region.try_fold_with(folder)?)
968 }
969 BaseTy::Pat => BaseTy::Pat,
970 BaseTy::Int(_)
971 | BaseTy::Param(_)
972 | BaseTy::Uint(_)
973 | BaseTy::Bool
974 | BaseTy::Float(_)
975 | BaseTy::Str
976 | BaseTy::Char
977 | BaseTy::Infer(_)
978 | BaseTy::Never => self.clone(),
979 };
980 Ok(bty)
981 }
982}
983
984impl TypeVisitable for SubsetTy {
985 fn visit_with<V: TypeVisitor>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy> {
986 self.bty.visit_with(visitor)?;
987 self.idx.visit_with(visitor)?;
988 self.pred.visit_with(visitor)
989 }
990}
991impl TypeFoldable for TyOrBase {
992 fn try_fold_with<F: FallibleTypeFolder>(&self, folder: &mut F) -> Result<Self, F::Error> {
993 match self {
994 Self::Ty(ty) => Ok(Self::Ty(ty.try_fold_with(folder)?)),
995 Self::Base(bty) => Ok(Self::Base(bty.try_fold_with(folder)?)),
996 }
997 }
998}
999
1000impl TypeFoldable for SubsetTy {
1001 fn try_fold_with<F: FallibleTypeFolder>(&self, folder: &mut F) -> Result<Self, F::Error> {
1002 folder.try_fold_subset_ty(self)
1003 }
1004}
1005
1006impl TypeSuperFoldable for SubsetTy {
1007 fn try_super_fold_with<F: FallibleTypeFolder>(&self, folder: &mut F) -> Result<Self, F::Error> {
1008 Ok(SubsetTy {
1009 bty: self.bty.try_fold_with(folder)?,
1010 idx: self.idx.try_fold_with(folder)?,
1011 pred: self.pred.try_fold_with(folder)?,
1012 })
1013 }
1014}
1015
1016impl TypeVisitable for GenericArg {
1017 fn visit_with<V: TypeVisitor>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy> {
1018 match self {
1019 GenericArg::Ty(ty) => ty.visit_with(visitor),
1020 GenericArg::Base(ty) => ty.visit_with(visitor),
1021 GenericArg::Lifetime(_) => ControlFlow::Continue(()),
1022 GenericArg::Const(_) => ControlFlow::Continue(()),
1023 }
1024 }
1025}
1026
1027impl TypeFoldable for GenericArg {
1028 fn try_fold_with<F: FallibleTypeFolder>(&self, folder: &mut F) -> Result<Self, F::Error> {
1029 let arg = match self {
1030 GenericArg::Ty(ty) => GenericArg::Ty(ty.try_fold_with(folder)?),
1031 GenericArg::Base(ctor) => GenericArg::Base(ctor.try_fold_with(folder)?),
1032 GenericArg::Lifetime(re) => GenericArg::Lifetime(re.try_fold_with(folder)?),
1033 GenericArg::Const(c) => GenericArg::Const(c.try_fold_with(folder)?),
1034 };
1035 Ok(arg)
1036 }
1037}
1038
1039impl TypeVisitable for Expr {
1040 fn visit_with<V: TypeVisitor>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy> {
1041 visitor.visit_expr(self)
1042 }
1043}
1044
1045impl TypeSuperVisitable for Expr {
1046 fn super_visit_with<V: TypeVisitor>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy> {
1047 match self.kind() {
1048 ExprKind::Var(_) => ControlFlow::Continue(()),
1049 ExprKind::BinaryOp(_, e1, e2) => {
1050 e1.visit_with(visitor)?;
1051 e2.visit_with(visitor)
1052 }
1053 ExprKind::Tuple(flds) => flds.visit_with(visitor),
1054 ExprKind::Ctor(_, flds) => flds.visit_with(visitor),
1055 ExprKind::IsCtor(_, _, e) => e.visit_with(visitor),
1056 ExprKind::FieldProj(e, _) | ExprKind::PathProj(e, _) | ExprKind::UnaryOp(_, e) => {
1057 e.visit_with(visitor)
1058 }
1059 ExprKind::App(func, sorts, arg) => {
1060 func.visit_with(visitor)?;
1061 sorts.visit_with(visitor)?;
1062 arg.visit_with(visitor)
1063 }
1064 ExprKind::IfThenElse(p, e1, e2) => {
1065 p.visit_with(visitor)?;
1066 e1.visit_with(visitor)?;
1067 e2.visit_with(visitor)
1068 }
1069 ExprKind::KVar(kvar) => kvar.visit_with(visitor),
1070 ExprKind::WKVar(wkvar) => wkvar.visit_with(visitor),
1071 ExprKind::Alias(alias, args) => {
1072 alias.visit_with(visitor)?;
1073 args.visit_with(visitor)
1074 }
1075 ExprKind::Abs(body) => body.visit_with(visitor),
1076 ExprKind::Quant(_, dom, body) => {
1077 dom.visit_with(visitor)?;
1078 body.visit_with(visitor)
1079 }
1080 ExprKind::Let(init, body) => {
1081 init.visit_with(visitor)?;
1082 body.visit_with(visitor)
1083 }
1084 ExprKind::Constant(_)
1085 | ExprKind::Hole(_)
1086 | ExprKind::Local(_)
1087 | ExprKind::GlobalFunc(..)
1088 | ExprKind::InternalFunc(..)
1089 | ExprKind::ConstDefId(_) => ControlFlow::Continue(()),
1090 }
1091 }
1092}
1093
1094impl TypeFoldable for Expr {
1095 fn try_fold_with<F: FallibleTypeFolder>(&self, folder: &mut F) -> Result<Self, F::Error> {
1096 folder.try_fold_expr(self)
1097 }
1098}
1099
1100impl TypeSuperFoldable for Expr {
1101 fn try_super_fold_with<F: FallibleTypeFolder>(&self, folder: &mut F) -> Result<Self, F::Error> {
1102 let span = self.span();
1103 let expr = match self.kind() {
1104 ExprKind::Var(var) => Expr::var(*var),
1105 ExprKind::Local(local) => Expr::local(*local),
1106 ExprKind::Constant(c) => Expr::constant(*c),
1107 ExprKind::ConstDefId(did) => Expr::const_def_id(*did),
1108 ExprKind::BinaryOp(op, e1, e2) => {
1109 Expr::binary_op(
1110 op.try_fold_with(folder)?,
1111 e1.try_fold_with(folder)?,
1112 e2.try_fold_with(folder)?,
1113 )
1114 }
1115 ExprKind::UnaryOp(op, e) => Expr::unary_op(*op, e.try_fold_with(folder)?),
1116 ExprKind::FieldProj(e, proj) => Expr::field_proj(e.try_fold_with(folder)?, *proj),
1117 ExprKind::Tuple(flds) => Expr::tuple(flds.try_fold_with(folder)?),
1118 ExprKind::Ctor(ctor, flds) => Expr::ctor(*ctor, flds.try_fold_with(folder)?),
1119 ExprKind::IsCtor(def_id, variant_idx, e) => {
1120 Expr::is_ctor(*def_id, *variant_idx, e.try_fold_with(folder)?)
1121 }
1122 ExprKind::PathProj(e, field) => Expr::path_proj(e.try_fold_with(folder)?, *field),
1123 ExprKind::App(func, sorts, arg) => {
1124 Expr::app(
1125 func.try_fold_with(folder)?,
1126 sorts.try_fold_with(folder)?,
1127 arg.try_fold_with(folder)?,
1128 )
1129 }
1130 ExprKind::IfThenElse(p, e1, e2) => {
1131 Expr::ite(
1132 p.try_fold_with(folder)?,
1133 e1.try_fold_with(folder)?,
1134 e2.try_fold_with(folder)?,
1135 )
1136 }
1137 ExprKind::Hole(kind) => Expr::hole(kind.try_fold_with(folder)?),
1138 ExprKind::KVar(kvar) => Expr::kvar(kvar.try_fold_with(folder)?),
1139 ExprKind::WKVar(wkvar) => Expr::wkvar(wkvar.try_fold_with(folder)?),
1140 ExprKind::Abs(lam) => Expr::abs(lam.try_fold_with(folder)?),
1141 ExprKind::Quant(kind, dom, body) => {
1142 Expr::quant(*kind, dom.try_fold_with(folder)?, body.try_fold_with(folder)?)
1143 }
1144 ExprKind::GlobalFunc(kind) => Expr::global_func(kind.clone()),
1145 ExprKind::InternalFunc(kind) => Expr::internal_func(kind.clone()),
1146 ExprKind::Alias(alias, args) => {
1147 Expr::alias(alias.try_fold_with(folder)?, args.try_fold_with(folder)?)
1148 }
1149 ExprKind::Let(init, body) => {
1150 Expr::let_(init.try_fold_with(folder)?, body.try_fold_with(folder)?)
1151 }
1152 };
1153 Ok(expr.at_opt(span))
1154 }
1155}
1156
1157impl<T> TypeVisitable for List<T>
1158where
1159 T: TypeVisitable,
1160 [T]: Internable,
1161{
1162 fn visit_with<V: TypeVisitor>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy> {
1163 self.iter().try_for_each(|t| t.visit_with(visitor))
1164 }
1165}
1166
1167impl<S, T> TypeVisitable for (S, T)
1168where
1169 S: TypeVisitable,
1170 T: TypeVisitable,
1171{
1172 fn visit_with<V: TypeVisitor>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy> {
1173 self.0.visit_with(visitor)?;
1174 self.1.visit_with(visitor)
1175 }
1176}
1177
1178impl<T> TypeFoldable for List<T>
1179where
1180 T: TypeFoldable,
1181 [T]: Internable,
1182{
1183 fn try_fold_with<F: FallibleTypeFolder>(&self, folder: &mut F) -> Result<Self, F::Error> {
1184 self.iter().map(|t| t.try_fold_with(folder)).try_collect()
1185 }
1186}
1187
1188impl<S, T> TypeFoldable for (S, T)
1189where
1190 S: TypeFoldable,
1191 T: TypeFoldable,
1192{
1193 fn try_fold_with<F: FallibleTypeFolder>(&self, folder: &mut F) -> Result<Self, F::Error> {
1194 Ok((self.0.try_fold_with(folder)?, self.1.try_fold_with(folder)?))
1195 }
1196}
1197
1198macro_rules! TrivialTypeTraversalImpls {
1201 ($($ty:ty,)+) => {
1202 $(
1203 impl $crate::rty::fold::TypeFoldable for $ty {
1204 fn try_fold_with<F: $crate::rty::fold::FallibleTypeFolder>(
1205 &self,
1206 _: &mut F,
1207 ) -> ::std::result::Result<Self, F::Error> {
1208 Ok(*self)
1209 }
1210
1211 #[inline]
1212 fn fold_with<F: $crate::rty::fold::TypeFolder>(
1213 &self,
1214 _: &mut F,
1215 ) -> Self {
1216 *self
1217 }
1218 }
1219
1220 impl $crate::rty::fold::TypeVisitable for $ty {
1221 #[inline]
1222 fn visit_with<V: $crate::rty::fold::TypeVisitor>(
1223 &self,
1224 _: &mut V)
1225 -> ::core::ops::ControlFlow<V::BreakTy>
1226 {
1227 ::core::ops::ControlFlow::Continue(())
1228 }
1229 }
1230 )+
1231 };
1232}
1233
1234TrivialTypeTraversalImpls! {
1236 (),
1237 bool,
1238 usize,
1239 crate::fhir::InferMode,
1240 crate::rty::BoundReftKind,
1241 crate::rty::BvSize,
1242 crate::rty::KVid,
1243 crate::def_id::FluxDefId,
1244 crate::def_id::FluxLocalDefId,
1245 rustc_span::Symbol,
1246 rustc_hir::def_id::DefId,
1247 rustc_hir::Safety,
1248 rustc_abi::ExternAbi,
1249 rustc_type_ir::ClosureKind,
1250 flux_rustc_bridge::ty::BoundRegionKind,
1251 flux_rustc_bridge::ty::AliasKind,
1252 flux_rustc_bridge::ty::AliasTermKind,
1253}