chalk_solve/solve/
truncate.rs1use crate::infer::InferenceTable;
4use chalk_ir::interner::Interner;
5use chalk_ir::visit::{TypeSuperVisitable, TypeVisitable, TypeVisitor};
6use chalk_ir::*;
7use std::cmp::max;
8use std::ops::ControlFlow;
9
10pub fn needs_truncation<I: Interner>(
23 interner: I,
24 infer: &mut InferenceTable<I>,
25 max_size: usize,
26 value: impl TypeVisitable<I>,
27) -> bool {
28 let mut visitor = TySizeVisitor::new(interner, infer);
29 value.visit_with(&mut visitor, DebruijnIndex::INNERMOST);
30
31 visitor.max_size > max_size
32}
33
34struct TySizeVisitor<'infer, I: Interner> {
35 interner: I,
36 infer: &'infer mut InferenceTable<I>,
37 size: usize,
38 depth: usize,
39 max_size: usize,
40}
41
42impl<'infer, I: Interner> TySizeVisitor<'infer, I> {
43 fn new(interner: I, infer: &'infer mut InferenceTable<I>) -> Self {
44 Self {
45 interner,
46 infer,
47 size: 0,
48 depth: 0,
49 max_size: 0,
50 }
51 }
52}
53
54impl<'infer, I: Interner> TypeVisitor<I> for TySizeVisitor<'infer, I> {
55 type BreakTy = ();
56
57 fn as_dyn(&mut self) -> &mut dyn TypeVisitor<I, BreakTy = Self::BreakTy> {
58 self
59 }
60
61 fn visit_ty(&mut self, ty: &Ty<I>, outer_binder: DebruijnIndex) -> ControlFlow<()> {
62 if let Some(normalized_ty) = self.infer.normalize_ty_shallow(self.interner, ty) {
63 normalized_ty.visit_with(self, outer_binder);
64 return ControlFlow::Continue(());
65 }
66
67 self.size += 1;
68 self.max_size = max(self.size, self.max_size);
69
70 self.depth += 1;
71 ty.super_visit_with(self, outer_binder);
72 self.depth -= 1;
73
74 if self.depth == 0 {
77 self.size = 0;
78 }
79 ControlFlow::Continue(())
80 }
81
82 fn interner(&self) -> I {
83 self.interner
84 }
85}
86
87#[cfg(test)]
88mod tests {
89 use super::*;
90 use chalk_integration::{arg, ty};
91
92 #[test]
93 fn one_type() {
94 use chalk_integration::interner::ChalkIr;
95 let interner = ChalkIr;
96 let mut table = InferenceTable::<chalk_integration::interner::ChalkIr>::new();
97 let _u1 = table.new_universe();
98
99 let ty0 = ty!(apply (item 0)
101 (apply (item 0)
102 (apply (item 0)
103 (apply (item 0)
104 (placeholder 1)))));
105
106 let mut visitor = TySizeVisitor::new(interner, &mut table);
107 ty0.visit_with(&mut visitor, DebruijnIndex::INNERMOST);
108 assert!(visitor.max_size == 5);
109 }
110
111 #[test]
112 fn multiple_types() {
113 use chalk_integration::interner::ChalkIr;
114 let interner = ChalkIr;
115 let mut table = InferenceTable::<chalk_integration::interner::ChalkIr>::new();
116 let _u1 = table.new_universe();
117
118 let ty0 = ty!(apply (item 0)
120 (apply (item 0)
121 (apply (item 0)
122 (apply (item 0)
123 (placeholder 1)))));
124
125 let ty1 = ty!(apply (item 0)
126 (apply (item 0)
127 (apply (item 0)
128 (placeholder 1))));
129
130 let mut visitor = TySizeVisitor::new(interner, &mut table);
131 vec![&ty0, &ty1].visit_with(&mut visitor, DebruijnIndex::INNERMOST);
132 assert!(visitor.max_size == 5);
133 }
134}