1use std::ops::ControlFlow;
5
6use flux_arc_interner::{Internable, List};
7use flux_common::bug;
8use itertools::Itertools;
9use rustc_data_structures::fx::FxHashMap;
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, normalize::Normalizer,
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) -> FxHashSet<BoundVar> {
266 struct RedundantBVarFinder {
267 current_index: DebruijnIndex,
268 total_bvar_occurrences: FxHashMap<BoundVar, usize>,
269 bvars_appearing_in_index: FxHashSet<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: FxHashMap::default(),
326 bvars_appearing_in_index: FxHashSet::default(),
327 };
328 let _ = self.visit_with(&mut finder);
329
330 finder
331 .bvars_appearing_in_index
332 .into_iter()
333 .filter(|var_index| finder.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 normalize(&self, genv: GlobalEnv) -> Self {
351 self.fold_with(&mut Normalizer::new(genv, None))
352 }
353
354 fn replace_holes(&self, f: impl FnMut(&[BoundVariableKinds], HoleKind) -> Expr) -> Self {
362 struct ReplaceHoles<F>(F, Vec<BoundVariableKinds>);
363
364 impl<F> TypeFolder for ReplaceHoles<F>
365 where
366 F: FnMut(&[BoundVariableKinds], HoleKind) -> Expr,
367 {
368 fn enter_binder(&mut self, vars: &BoundVariableKinds) {
369 self.1.push(vars.clone());
370 }
371
372 fn exit_binder(&mut self) {
373 self.1.pop();
374 }
375
376 fn fold_expr(&mut self, e: &Expr) -> Expr {
377 if let ExprKind::Hole(kind) = e.kind() {
378 self.0(&self.1, kind.clone())
379 } else {
380 e.super_fold_with(self)
381 }
382 }
383 }
384
385 self.fold_with(&mut ReplaceHoles(f, vec![]))
386 }
387
388 fn with_holes(&self) -> Self {
394 struct WithHoles;
395
396 impl TypeFolder for WithHoles {
397 fn fold_ty(&mut self, ty: &Ty) -> Ty {
398 if let Some(bty) = ty.as_bty_skipping_existentials() {
399 Ty::exists_with_constr(bty.fold_with(self), Expr::hole(HoleKind::Pred))
400 } else {
401 ty.super_fold_with(self)
402 }
403 }
404
405 fn fold_subset_ty(&mut self, constr: &SubsetTy) -> SubsetTy {
406 SubsetTy::new(constr.bty.clone(), constr.idx.clone(), Expr::hole(HoleKind::Pred))
407 }
408 }
409
410 self.fold_with(&mut WithHoles)
411 }
412
413 fn replace_evars(&self, f: &mut impl FnMut(EVid) -> Option<Expr>) -> Result<Self, EVid> {
414 struct Folder<F>(F);
415 impl<F: FnMut(EVid) -> Option<Expr>> FallibleTypeFolder for Folder<F> {
416 type Error = EVid;
417
418 fn try_fold_expr(&mut self, expr: &Expr) -> Result<Expr, Self::Error> {
419 if let ExprKind::Var(Var::EVar(evid)) = expr.kind() {
420 if let Some(sol) = (self.0)(*evid) { Ok(sol.clone()) } else { Err(*evid) }
421 } else {
422 expr.try_super_fold_with(self)
423 }
424 }
425 }
426
427 self.try_fold_with(&mut Folder(f))
428 }
429
430 fn shift_horizontally(&self, amount: usize) -> Self {
433 struct Shifter {
434 current_index: DebruijnIndex,
435 amount: usize,
436 }
437
438 impl TypeFolder for Shifter {
439 fn enter_binder(&mut self, _: &BoundVariableKinds) {
440 self.current_index.shift_in(1);
441 }
442
443 fn exit_binder(&mut self) {
444 self.current_index.shift_out(1);
445 }
446
447 fn fold_region(&mut self, re: &Region) -> Region {
448 if let ReBound(debruijn, br) = *re
449 && debruijn == self.current_index
450 {
451 ReBound(debruijn, BoundRegion { var: br.var + self.amount, kind: br.kind })
452 } else {
453 *re
454 }
455 }
456
457 fn fold_expr(&mut self, expr: &Expr) -> Expr {
458 if let ExprKind::Var(Var::Bound(debruijn, breft)) = expr.kind()
459 && debruijn == &self.current_index
460 {
461 Expr::bvar(*debruijn, breft.var + self.amount, breft.kind)
462 } else {
463 expr.super_fold_with(self)
464 }
465 }
466 }
467 self.fold_with(&mut Shifter { amount, current_index: INNERMOST })
468 }
469
470 fn shift_in_escaping(&self, amount: u32) -> Self {
471 struct Shifter {
472 current_index: DebruijnIndex,
473 amount: u32,
474 }
475
476 impl TypeFolder for Shifter {
477 fn enter_binder(&mut self, _: &BoundVariableKinds) {
478 self.current_index.shift_in(1);
479 }
480
481 fn exit_binder(&mut self) {
482 self.current_index.shift_out(1);
483 }
484
485 fn fold_region(&mut self, re: &Region) -> Region {
486 if let ReBound(debruijn, br) = *re
487 && debruijn >= self.current_index
488 {
489 ReBound(debruijn.shifted_in(self.amount), br)
490 } else {
491 *re
492 }
493 }
494
495 fn fold_expr(&mut self, expr: &Expr) -> Expr {
496 if let ExprKind::Var(Var::Bound(debruijn, breft)) = expr.kind()
497 && *debruijn >= self.current_index
498 {
499 Expr::bvar(debruijn.shifted_in(self.amount), breft.var, breft.kind)
500 } else {
501 expr.super_fold_with(self)
502 }
503 }
504 }
505 self.fold_with(&mut Shifter { amount, current_index: INNERMOST })
506 }
507
508 fn shift_out_escaping(&self, amount: u32) -> Self {
509 struct Shifter {
510 amount: u32,
511 current_index: DebruijnIndex,
512 }
513
514 impl TypeFolder for Shifter {
515 fn enter_binder(&mut self, _: &BoundVariableKinds) {
516 self.current_index.shift_in(1);
517 }
518
519 fn exit_binder(&mut self) {
520 self.current_index.shift_out(1);
521 }
522
523 fn fold_region(&mut self, re: &Region) -> Region {
524 if let ReBound(debruijn, br) = *re
525 && debruijn >= self.current_index
526 {
527 ReBound(debruijn.shifted_out(self.amount), br)
528 } else {
529 *re
530 }
531 }
532
533 fn fold_expr(&mut self, expr: &Expr) -> Expr {
534 if let ExprKind::Var(Var::Bound(debruijn, breft)) = expr.kind()
535 && debruijn >= &self.current_index
536 {
537 Expr::bvar(debruijn.shifted_out(self.amount), breft.var, breft.kind)
538 } else {
539 expr.super_fold_with(self)
540 }
541 }
542 }
543 self.fold_with(&mut Shifter { amount, current_index: INNERMOST })
544 }
545
546 fn erase_regions(&self) -> Self {
547 struct RegionEraser;
548 impl TypeFolder for RegionEraser {
549 fn fold_region(&mut self, r: &Region) -> Region {
550 match *r {
551 ReBound(..) => *r,
552 _ => ReErased,
553 }
554 }
555 }
556
557 self.fold_with(&mut RegionEraser)
558 }
559}
560
561pub trait TypeSuperFoldable: TypeFoldable {
562 fn try_super_fold_with<F: FallibleTypeFolder>(&self, folder: &mut F) -> Result<Self, F::Error>;
563
564 fn super_fold_with<F: TypeFolder>(&self, folder: &mut F) -> Self {
565 self.try_super_fold_with(folder).into_ok()
566 }
567}
568
569impl<T: TypeVisitable> TypeVisitable for OutlivesPredicate<T> {
570 fn visit_with<V: TypeVisitor>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy> {
571 self.0.visit_with(visitor)?;
572 self.1.visit_with(visitor)
573 }
574}
575
576impl<T: TypeFoldable> TypeFoldable for OutlivesPredicate<T> {
577 fn try_fold_with<F: FallibleTypeFolder>(&self, folder: &mut F) -> Result<Self, F::Error> {
578 Ok(OutlivesPredicate(self.0.try_fold_with(folder)?, self.1.try_fold_with(folder)?))
579 }
580}
581
582impl TypeVisitable for Sort {
583 fn visit_with<V: TypeVisitor>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy> {
584 visitor.visit_sort(self)
585 }
586}
587
588impl TypeSuperVisitable for Sort {
589 fn super_visit_with<V: TypeVisitor>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy> {
590 match self {
591 Sort::Tuple(sorts) => sorts.visit_with(visitor),
592 Sort::App(_, args) => args.visit_with(visitor),
593 Sort::Func(fsort) => fsort.visit_with(visitor),
594 Sort::Alias(_, alias_ty) => alias_ty.visit_with(visitor),
595 Sort::Int
596 | Sort::Bool
597 | Sort::Real
598 | Sort::Str
599 | Sort::Char
600 | Sort::BitVec(_)
601 | Sort::Loc
602 | Sort::Param(_)
603 | Sort::Var(_)
604 | Sort::Infer(_)
605 | Sort::RawPtr
606 | Sort::Err => ControlFlow::Continue(()),
607 }
608 }
609}
610
611impl TypeFoldable for Sort {
612 fn try_fold_with<F: FallibleTypeFolder>(&self, folder: &mut F) -> Result<Self, F::Error> {
613 folder.try_fold_sort(self)
614 }
615}
616
617impl TypeSuperFoldable for Sort {
618 fn try_super_fold_with<F: FallibleTypeFolder>(&self, folder: &mut F) -> Result<Self, F::Error> {
619 let sort = match self {
620 Sort::Tuple(sorts) => Sort::tuple(sorts.try_fold_with(folder)?),
621 Sort::App(ctor, sorts) => Sort::app(ctor.clone(), sorts.try_fold_with(folder)?),
622 Sort::Func(fsort) => Sort::Func(fsort.try_fold_with(folder)?),
623 Sort::Alias(kind, alias_ty) => Sort::Alias(*kind, alias_ty.try_fold_with(folder)?),
624 Sort::Int
625 | Sort::Bool
626 | Sort::Real
627 | Sort::Loc
628 | Sort::Str
629 | Sort::Char
630 | Sort::BitVec(_)
631 | Sort::Param(_)
632 | Sort::Var(_)
633 | Sort::Infer(_)
634 | Sort::RawPtr
635 | Sort::Err => self.clone(),
636 };
637 Ok(sort)
638 }
639}
640
641impl TypeVisitable for PolyFuncSort {
642 fn visit_with<V: TypeVisitor>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy> {
643 self.fsort.visit_with(visitor)
644 }
645}
646
647impl TypeFoldable for PolyFuncSort {
648 fn try_fold_with<F: FallibleTypeFolder>(&self, folder: &mut F) -> Result<Self, F::Error> {
649 Ok(PolyFuncSort { params: self.params.clone(), fsort: self.fsort.try_fold_with(folder)? })
650 }
651}
652
653impl<T> TypeVisitable for Binder<T>
654where
655 T: TypeVisitable,
656{
657 fn visit_with<V: TypeVisitor>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy> {
658 self.vars().visit_with(visitor)?;
659 visitor.enter_binder(self.vars());
660 self.skip_binder_ref().visit_with(visitor)?;
661 visitor.exit_binder();
662 ControlFlow::Continue(())
663 }
664}
665
666impl<T> TypeSuperVisitable for Binder<T>
667where
668 T: TypeVisitable,
669{
670 fn super_visit_with<V: TypeVisitor>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy> {
671 self.skip_binder_ref().visit_with(visitor)
672 }
673}
674
675impl<T> TypeFoldable for Binder<T>
676where
677 T: TypeFoldable,
678{
679 fn try_fold_with<F: FallibleTypeFolder>(&self, folder: &mut F) -> Result<Self, F::Error> {
680 let vars = self.vars().try_fold_with(folder)?;
681 folder.try_enter_binder(&vars);
682 let r = self.skip_binder_ref().try_fold_with(folder)?;
683 folder.try_exit_binder();
684 Ok(Binder::bind_with_vars(r, vars))
685 }
686}
687
688impl TypeVisitable for VariantSig {
689 fn visit_with<V: TypeVisitor>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy> {
690 self.fields.visit_with(visitor)?;
691 self.idx.visit_with(visitor)
692 }
693}
694
695impl TypeFoldable for VariantSig {
696 fn try_fold_with<F: FallibleTypeFolder>(&self, folder: &mut F) -> Result<Self, F::Error> {
697 let args = self.args.try_fold_with(folder)?;
698 let fields = self.fields.try_fold_with(folder)?;
699 let idx = self.idx.try_fold_with(folder)?;
700 let requires = self.requires.try_fold_with(folder)?;
701 Ok(VariantSig::new(self.adt_def.clone(), args, fields, idx, requires))
702 }
703}
704
705impl<T: TypeVisitable> TypeVisitable for Vec<T> {
706 fn visit_with<V: TypeVisitor>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy> {
707 self.iter().try_for_each(|t| t.visit_with(visitor))
708 }
709}
710
711impl TypeVisitable for Ensures {
712 fn visit_with<V: TypeVisitor>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy> {
713 match self {
714 Ensures::Type(path, ty) => {
715 path.to_expr().visit_with(visitor)?;
716 ty.visit_with(visitor)
717 }
718 Ensures::Pred(e) => e.visit_with(visitor),
719 }
720 }
721}
722
723impl TypeFoldable for Ensures {
724 fn try_fold_with<F: FallibleTypeFolder>(&self, folder: &mut F) -> Result<Self, F::Error> {
725 let c = match self {
726 Ensures::Type(path, ty) => {
727 let path_expr = path.to_expr().try_fold_with(folder)?;
728 Ensures::Type(
729 path_expr.to_path().unwrap_or_else(|| {
730 bug!("invalid path `{path_expr:?}` produced when folding `{self:?}`",)
731 }),
732 ty.try_fold_with(folder)?,
733 )
734 }
735 Ensures::Pred(e) => Ensures::Pred(e.try_fold_with(folder)?),
736 };
737 Ok(c)
738 }
739}
740
741impl TypeVisitable for super::TyOrBase {
742 fn visit_with<V: TypeVisitor>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy> {
743 match self {
744 Self::Ty(ty) => ty.visit_with(visitor),
745 Self::Base(bty) => bty.visit_with(visitor),
746 }
747 }
748}
749
750impl TypeVisitable for Ty {
751 fn visit_with<V: TypeVisitor>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy> {
752 visitor.visit_ty(self)
753 }
754}
755
756impl TypeSuperVisitable for Ty {
757 fn super_visit_with<V: TypeVisitor>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy> {
758 match self.kind() {
759 TyKind::Indexed(bty, idxs) => {
760 bty.visit_with(visitor)?;
761 idxs.visit_with(visitor)
762 }
763 TyKind::Exists(exists) => exists.visit_with(visitor),
764 TyKind::StrgRef(_, path, ty) => {
765 path.to_expr().visit_with(visitor)?;
766 ty.visit_with(visitor)
767 }
768 TyKind::Ptr(_, path) => path.to_expr().visit_with(visitor),
769 TyKind::Constr(pred, ty) => {
770 pred.visit_with(visitor)?;
771 ty.visit_with(visitor)
772 }
773 TyKind::Downcast(.., args, _, fields) => {
774 args.visit_with(visitor)?;
775 fields.visit_with(visitor)
776 }
777 TyKind::Blocked(ty) => ty.visit_with(visitor),
778 TyKind::Infer(_) | TyKind::Param(_) | TyKind::Discr(..) | TyKind::Uninit => {
779 ControlFlow::Continue(())
780 }
781 }
782 }
783}
784
785impl TypeFoldable for Ty {
786 fn try_fold_with<F: FallibleTypeFolder>(&self, folder: &mut F) -> Result<Self, F::Error> {
787 folder.try_fold_ty(self)
788 }
789}
790
791impl TypeSuperFoldable for Ty {
792 fn try_super_fold_with<F: FallibleTypeFolder>(&self, folder: &mut F) -> Result<Ty, F::Error> {
793 let ty = match self.kind() {
794 TyKind::Indexed(bty, idxs) => {
795 Ty::indexed(bty.try_fold_with(folder)?, idxs.try_fold_with(folder)?)
796 }
797 TyKind::Exists(exists) => TyKind::Exists(exists.try_fold_with(folder)?).intern(),
798 TyKind::StrgRef(re, path, ty) => {
799 Ty::strg_ref(
800 re.try_fold_with(folder)?,
801 path.to_expr()
802 .try_fold_with(folder)?
803 .to_path()
804 .expect("type folding produced an invalid path"),
805 ty.try_fold_with(folder)?,
806 )
807 }
808 TyKind::Ptr(pk, path) => {
809 let pk = match pk {
810 PtrKind::Mut(re) => PtrKind::Mut(re.try_fold_with(folder)?),
811 PtrKind::Box => PtrKind::Box,
812 };
813 Ty::ptr(
814 pk,
815 path.to_expr()
816 .try_fold_with(folder)?
817 .to_path()
818 .expect("type folding produced an invalid path"),
819 )
820 }
821 TyKind::Constr(pred, ty) => {
822 Ty::constr(pred.try_fold_with(folder)?, ty.try_fold_with(folder)?)
823 }
824 TyKind::Downcast(adt, args, ty, variant, fields) => {
825 Ty::downcast(
826 adt.clone(),
827 args.clone(),
828 ty.clone(),
829 *variant,
830 fields.try_fold_with(folder)?,
831 )
832 }
833 TyKind::Blocked(ty) => Ty::blocked(ty.try_fold_with(folder)?),
834 TyKind::Infer(_) | TyKind::Param(_) | TyKind::Uninit | TyKind::Discr(..) => {
835 self.clone()
836 }
837 };
838 Ok(ty)
839 }
840}
841
842impl TypeVisitable for Region {
843 fn visit_with<V: TypeVisitor>(&self, _visitor: &mut V) -> ControlFlow<V::BreakTy> {
844 ControlFlow::Continue(())
845 }
846}
847
848impl TypeFoldable for Region {
849 fn try_fold_with<F: FallibleTypeFolder>(&self, folder: &mut F) -> Result<Self, F::Error> {
850 folder.try_fold_region(self)
851 }
852}
853
854impl TypeSuperFoldable for Const {
855 fn try_super_fold_with<F: FallibleTypeFolder>(
856 &self,
857 _folder: &mut F,
858 ) -> Result<Self, F::Error> {
859 Ok(self.clone())
861 }
862}
863
864impl TypeVisitable for Const {
865 fn visit_with<V: TypeVisitor>(&self, _visitor: &mut V) -> ControlFlow<V::BreakTy> {
866 ControlFlow::Continue(())
867 }
868}
869
870impl TypeFoldable for Const {
871 fn try_fold_with<F: FallibleTypeFolder>(&self, folder: &mut F) -> Result<Self, F::Error> {
872 folder.try_fold_const(self)
873 }
874}
875
876impl TypeVisitable for BaseTy {
877 fn visit_with<V: TypeVisitor>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy> {
878 visitor.visit_bty(self)
879 }
880}
881
882impl TypeSuperVisitable for BaseTy {
883 fn super_visit_with<V: TypeVisitor>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy> {
884 match self {
885 BaseTy::Adt(_, args) => args.visit_with(visitor),
886 BaseTy::FnDef(_, args) => args.visit_with(visitor),
887 BaseTy::Slice(ty) => ty.visit_with(visitor),
888 BaseTy::RawPtr(ty, _) => ty.visit_with(visitor),
889 BaseTy::RawPtrMetadata(ty) => ty.visit_with(visitor),
890 BaseTy::Ref(_, ty, _) => ty.visit_with(visitor),
891 BaseTy::FnPtr(poly_fn_sig) => poly_fn_sig.visit_with(visitor),
892 BaseTy::Tuple(tys) => tys.visit_with(visitor),
893 BaseTy::Alias(_, alias_ty) => alias_ty.visit_with(visitor),
894 BaseTy::Array(ty, _) => ty.visit_with(visitor),
895 BaseTy::Coroutine(_, resume_ty, upvars, _) => {
896 resume_ty.visit_with(visitor)?;
897 upvars.visit_with(visitor)
898 }
899 BaseTy::Dynamic(exi_preds, _) => exi_preds.visit_with(visitor),
900 BaseTy::Int(_)
901 | BaseTy::Pat
902 | BaseTy::Uint(_)
903 | BaseTy::Bool
904 | BaseTy::Float(_)
905 | BaseTy::Str
906 | BaseTy::Char
907 | BaseTy::Closure(..)
908 | BaseTy::Never
909 | BaseTy::Infer(_)
910 | BaseTy::Foreign(_)
911 | BaseTy::Param(_) => ControlFlow::Continue(()),
912 }
913 }
914}
915
916impl TypeFoldable for BaseTy {
917 fn try_fold_with<F: FallibleTypeFolder>(&self, folder: &mut F) -> Result<Self, F::Error> {
918 folder.try_fold_bty(self)
919 }
920}
921
922impl TypeSuperFoldable for BaseTy {
923 fn try_super_fold_with<F: FallibleTypeFolder>(&self, folder: &mut F) -> Result<Self, F::Error> {
924 let bty = match self {
925 BaseTy::Adt(adt_def, args) => BaseTy::adt(adt_def.clone(), args.try_fold_with(folder)?),
926 BaseTy::FnDef(def_id, args) => BaseTy::fn_def(*def_id, args.try_fold_with(folder)?),
927 BaseTy::Foreign(def_id) => BaseTy::Foreign(*def_id),
928 BaseTy::Slice(ty) => BaseTy::Slice(ty.try_fold_with(folder)?),
929 BaseTy::RawPtr(ty, mu) => BaseTy::RawPtr(ty.try_fold_with(folder)?, *mu),
930 BaseTy::RawPtrMetadata(ty) => BaseTy::RawPtrMetadata(ty.try_fold_with(folder)?),
931 BaseTy::Ref(re, ty, mutbl) => {
932 BaseTy::Ref(re.try_fold_with(folder)?, ty.try_fold_with(folder)?, *mutbl)
933 }
934 BaseTy::FnPtr(decl) => BaseTy::FnPtr(decl.try_fold_with(folder)?),
935 BaseTy::Tuple(tys) => BaseTy::Tuple(tys.try_fold_with(folder)?),
936 BaseTy::Alias(kind, alias_ty) => BaseTy::Alias(*kind, alias_ty.try_fold_with(folder)?),
937 BaseTy::Array(ty, c) => {
938 BaseTy::Array(ty.try_fold_with(folder)?, c.try_fold_with(folder)?)
939 }
940 BaseTy::Closure(did, args, gen_args, no_panic) => {
941 BaseTy::Closure(*did, args.try_fold_with(folder)?, gen_args.clone(), *no_panic)
942 }
943 BaseTy::Coroutine(did, resume_ty, args, gen_args) => {
944 BaseTy::Coroutine(
945 *did,
946 resume_ty.try_fold_with(folder)?,
947 args.try_fold_with(folder)?,
948 gen_args.clone(),
949 )
950 }
951 BaseTy::Dynamic(preds, region) => {
952 BaseTy::Dynamic(preds.try_fold_with(folder)?, region.try_fold_with(folder)?)
953 }
954 BaseTy::Pat => BaseTy::Pat,
955 BaseTy::Int(_)
956 | BaseTy::Param(_)
957 | BaseTy::Uint(_)
958 | BaseTy::Bool
959 | BaseTy::Float(_)
960 | BaseTy::Str
961 | BaseTy::Char
962 | BaseTy::Infer(_)
963 | BaseTy::Never => self.clone(),
964 };
965 Ok(bty)
966 }
967}
968
969impl TypeVisitable for SubsetTy {
970 fn visit_with<V: TypeVisitor>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy> {
971 self.bty.visit_with(visitor)?;
972 self.idx.visit_with(visitor)?;
973 self.pred.visit_with(visitor)
974 }
975}
976impl TypeFoldable for TyOrBase {
977 fn try_fold_with<F: FallibleTypeFolder>(&self, folder: &mut F) -> Result<Self, F::Error> {
978 match self {
979 Self::Ty(ty) => Ok(Self::Ty(ty.try_fold_with(folder)?)),
980 Self::Base(bty) => Ok(Self::Base(bty.try_fold_with(folder)?)),
981 }
982 }
983}
984
985impl TypeFoldable for SubsetTy {
986 fn try_fold_with<F: FallibleTypeFolder>(&self, folder: &mut F) -> Result<Self, F::Error> {
987 folder.try_fold_subset_ty(self)
988 }
989}
990
991impl TypeSuperFoldable for SubsetTy {
992 fn try_super_fold_with<F: FallibleTypeFolder>(&self, folder: &mut F) -> Result<Self, F::Error> {
993 Ok(SubsetTy {
994 bty: self.bty.try_fold_with(folder)?,
995 idx: self.idx.try_fold_with(folder)?,
996 pred: self.pred.try_fold_with(folder)?,
997 })
998 }
999}
1000
1001impl TypeVisitable for GenericArg {
1002 fn visit_with<V: TypeVisitor>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy> {
1003 match self {
1004 GenericArg::Ty(ty) => ty.visit_with(visitor),
1005 GenericArg::Base(ty) => ty.visit_with(visitor),
1006 GenericArg::Lifetime(_) => ControlFlow::Continue(()),
1007 GenericArg::Const(_) => ControlFlow::Continue(()),
1008 }
1009 }
1010}
1011
1012impl TypeFoldable for GenericArg {
1013 fn try_fold_with<F: FallibleTypeFolder>(&self, folder: &mut F) -> Result<Self, F::Error> {
1014 let arg = match self {
1015 GenericArg::Ty(ty) => GenericArg::Ty(ty.try_fold_with(folder)?),
1016 GenericArg::Base(ctor) => GenericArg::Base(ctor.try_fold_with(folder)?),
1017 GenericArg::Lifetime(re) => GenericArg::Lifetime(re.try_fold_with(folder)?),
1018 GenericArg::Const(c) => GenericArg::Const(c.try_fold_with(folder)?),
1019 };
1020 Ok(arg)
1021 }
1022}
1023
1024impl TypeVisitable for Expr {
1025 fn visit_with<V: TypeVisitor>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy> {
1026 visitor.visit_expr(self)
1027 }
1028}
1029
1030impl TypeSuperVisitable for Expr {
1031 fn super_visit_with<V: TypeVisitor>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy> {
1032 match self.kind() {
1033 ExprKind::Var(_) => ControlFlow::Continue(()),
1034 ExprKind::BinaryOp(_, e1, e2) => {
1035 e1.visit_with(visitor)?;
1036 e2.visit_with(visitor)
1037 }
1038 ExprKind::Tuple(flds) => flds.visit_with(visitor),
1039 ExprKind::Ctor(_, flds) => flds.visit_with(visitor),
1040 ExprKind::IsCtor(_, _, e) => e.visit_with(visitor),
1041 ExprKind::FieldProj(e, _) | ExprKind::PathProj(e, _) | ExprKind::UnaryOp(_, e) => {
1042 e.visit_with(visitor)
1043 }
1044 ExprKind::App(func, sorts, arg) => {
1045 func.visit_with(visitor)?;
1046 sorts.visit_with(visitor)?;
1047 arg.visit_with(visitor)
1048 }
1049 ExprKind::IfThenElse(p, e1, e2) => {
1050 p.visit_with(visitor)?;
1051 e1.visit_with(visitor)?;
1052 e2.visit_with(visitor)
1053 }
1054 ExprKind::KVar(kvar) => kvar.visit_with(visitor),
1055 ExprKind::Alias(alias, args) => {
1056 alias.visit_with(visitor)?;
1057 args.visit_with(visitor)
1058 }
1059 ExprKind::Abs(body) => body.visit_with(visitor),
1060 ExprKind::BoundedQuant(_, _, body) => body.visit_with(visitor),
1061 ExprKind::ForAll(expr) => expr.visit_with(visitor),
1062 ExprKind::Exists(expr) => expr.visit_with(visitor),
1063 ExprKind::Let(init, body) => {
1064 init.visit_with(visitor)?;
1065 body.visit_with(visitor)
1066 }
1067 ExprKind::Constant(_)
1068 | ExprKind::Hole(_)
1069 | ExprKind::Local(_)
1070 | ExprKind::GlobalFunc(..)
1071 | ExprKind::InternalFunc(..)
1072 | ExprKind::ConstDefId(_) => ControlFlow::Continue(()),
1073 }
1074 }
1075}
1076
1077impl TypeFoldable for Expr {
1078 fn try_fold_with<F: FallibleTypeFolder>(&self, folder: &mut F) -> Result<Self, F::Error> {
1079 folder.try_fold_expr(self)
1080 }
1081}
1082
1083impl TypeSuperFoldable for Expr {
1084 fn try_super_fold_with<F: FallibleTypeFolder>(&self, folder: &mut F) -> Result<Self, F::Error> {
1085 let span = self.span();
1086 let expr = match self.kind() {
1087 ExprKind::Var(var) => Expr::var(*var),
1088 ExprKind::Local(local) => Expr::local(*local),
1089 ExprKind::Constant(c) => Expr::constant(*c),
1090 ExprKind::ConstDefId(did) => Expr::const_def_id(*did),
1091 ExprKind::BinaryOp(op, e1, e2) => {
1092 Expr::binary_op(
1093 op.try_fold_with(folder)?,
1094 e1.try_fold_with(folder)?,
1095 e2.try_fold_with(folder)?,
1096 )
1097 }
1098 ExprKind::UnaryOp(op, e) => Expr::unary_op(*op, e.try_fold_with(folder)?),
1099 ExprKind::FieldProj(e, proj) => Expr::field_proj(e.try_fold_with(folder)?, *proj),
1100 ExprKind::Tuple(flds) => Expr::tuple(flds.try_fold_with(folder)?),
1101 ExprKind::Ctor(ctor, flds) => Expr::ctor(*ctor, flds.try_fold_with(folder)?),
1102 ExprKind::IsCtor(def_id, variant_idx, e) => {
1103 Expr::is_ctor(*def_id, *variant_idx, e.try_fold_with(folder)?)
1104 }
1105 ExprKind::PathProj(e, field) => Expr::path_proj(e.try_fold_with(folder)?, *field),
1106 ExprKind::App(func, sorts, arg) => {
1107 Expr::app(
1108 func.try_fold_with(folder)?,
1109 sorts.try_fold_with(folder)?,
1110 arg.try_fold_with(folder)?,
1111 )
1112 }
1113 ExprKind::IfThenElse(p, e1, e2) => {
1114 Expr::ite(
1115 p.try_fold_with(folder)?,
1116 e1.try_fold_with(folder)?,
1117 e2.try_fold_with(folder)?,
1118 )
1119 }
1120 ExprKind::Hole(kind) => Expr::hole(kind.try_fold_with(folder)?),
1121 ExprKind::KVar(kvar) => Expr::kvar(kvar.try_fold_with(folder)?),
1122 ExprKind::Abs(lam) => Expr::abs(lam.try_fold_with(folder)?),
1123 ExprKind::BoundedQuant(kind, rng, body) => {
1124 Expr::bounded_quant(*kind, *rng, body.try_fold_with(folder)?)
1125 }
1126 ExprKind::GlobalFunc(kind) => Expr::global_func(kind.clone()),
1127 ExprKind::InternalFunc(kind) => Expr::internal_func(kind.clone()),
1128 ExprKind::Alias(alias, args) => {
1129 Expr::alias(alias.try_fold_with(folder)?, args.try_fold_with(folder)?)
1130 }
1131 ExprKind::ForAll(expr) => Expr::forall(expr.try_fold_with(folder)?),
1132 ExprKind::Exists(expr) => Expr::exists(expr.try_fold_with(folder)?),
1133 ExprKind::Let(init, body) => {
1134 Expr::let_(init.try_fold_with(folder)?, body.try_fold_with(folder)?)
1135 }
1136 };
1137 Ok(expr.at_opt(span))
1138 }
1139}
1140
1141impl<T> TypeVisitable for List<T>
1142where
1143 T: TypeVisitable,
1144 [T]: Internable,
1145{
1146 fn visit_with<V: TypeVisitor>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy> {
1147 self.iter().try_for_each(|t| t.visit_with(visitor))
1148 }
1149}
1150
1151impl<T> TypeFoldable for List<T>
1152where
1153 T: TypeFoldable,
1154 [T]: Internable,
1155{
1156 fn try_fold_with<F: FallibleTypeFolder>(&self, folder: &mut F) -> Result<Self, F::Error> {
1157 self.iter().map(|t| t.try_fold_with(folder)).try_collect()
1158 }
1159}
1160
1161macro_rules! TrivialTypeTraversalImpls {
1164 ($($ty:ty,)+) => {
1165 $(
1166 impl $crate::rty::fold::TypeFoldable for $ty {
1167 fn try_fold_with<F: $crate::rty::fold::FallibleTypeFolder>(
1168 &self,
1169 _: &mut F,
1170 ) -> ::std::result::Result<Self, F::Error> {
1171 Ok(*self)
1172 }
1173
1174 #[inline]
1175 fn fold_with<F: $crate::rty::fold::TypeFolder>(
1176 &self,
1177 _: &mut F,
1178 ) -> Self {
1179 *self
1180 }
1181 }
1182
1183 impl $crate::rty::fold::TypeVisitable for $ty {
1184 #[inline]
1185 fn visit_with<V: $crate::rty::fold::TypeVisitor>(
1186 &self,
1187 _: &mut V)
1188 -> ::core::ops::ControlFlow<V::BreakTy>
1189 {
1190 ::core::ops::ControlFlow::Continue(())
1191 }
1192 }
1193 )+
1194 };
1195}
1196
1197TrivialTypeTraversalImpls! {
1199 (),
1200 bool,
1201 usize,
1202 crate::fhir::InferMode,
1203 crate::rty::BoundReftKind,
1204 crate::rty::BvSize,
1205 crate::rty::KVid,
1206 crate::def_id::FluxDefId,
1207 crate::def_id::FluxLocalDefId,
1208 rustc_span::Symbol,
1209 rustc_hir::def_id::DefId,
1210 rustc_hir::Safety,
1211 rustc_abi::ExternAbi,
1212 rustc_type_ir::ClosureKind,
1213 flux_rustc_bridge::ty::BoundRegionKind,
1214}