1use crate::debug_span;
2use chalk_derive::FallibleTypeFolder;
3use chalk_ir::fold::{TypeFoldable, TypeFolder};
4use chalk_ir::interner::{HasInterner, Interner};
5use chalk_ir::visit::{TypeVisitable, TypeVisitor};
6use chalk_ir::*;
7use std::ops::ControlFlow;
8
9use super::InferenceTable;
10
11impl<I: Interner> InferenceTable<I> {
12 pub fn u_canonicalize<T>(interner: I, value0: &Canonical<T>) -> UCanonicalized<T>
13 where
14 T: Clone + HasInterner<Interner = I> + TypeFoldable<I> + TypeVisitable<I>,
15 T: HasInterner<Interner = I>,
16 {
17 debug_span!("u_canonicalize", "{:#?}", value0);
18
19 let mut universes = UniverseMap::new();
21
22 for universe in value0.binders.iter(interner) {
23 universes.add(*universe.skip_kind());
24 }
25
26 value0.value.visit_with(
27 &mut UCollector {
28 universes: &mut universes,
29 interner,
30 },
31 DebruijnIndex::INNERMOST,
32 );
33
34 let value1 = value0
38 .value
39 .clone()
40 .try_fold_with(
41 &mut UMapToCanonical {
42 universes: &universes,
43 interner,
44 },
45 DebruijnIndex::INNERMOST,
46 )
47 .unwrap();
48 let binders = CanonicalVarKinds::from_iter(
49 interner,
50 value0
51 .binders
52 .iter(interner)
53 .map(|pk| pk.map_ref(|&ui| universes.map_universe_to_canonical(ui).unwrap())),
54 );
55
56 UCanonicalized {
57 quantified: UCanonical {
58 universes: universes.num_canonical_universes(),
59 canonical: Canonical {
60 value: value1,
61 binders,
62 },
63 },
64 universes,
65 }
66 }
67}
68
69#[derive(Debug)]
70pub struct UCanonicalized<T: HasInterner> {
71 pub quantified: UCanonical<T>,
73
74 pub universes: UniverseMap,
76}
77
78pub trait UniverseMapExt {
79 fn add(&mut self, universe: UniverseIndex);
80 fn map_universe_to_canonical(&self, universe: UniverseIndex) -> Option<UniverseIndex>;
81 fn map_universe_from_canonical(&self, universe: UniverseIndex) -> UniverseIndex;
82 fn map_from_canonical<T, I>(&self, interner: I, canonical_value: &Canonical<T>) -> Canonical<T>
83 where
84 T: Clone + TypeFoldable<I> + HasInterner<Interner = I>,
85 T: HasInterner<Interner = I>,
86 I: Interner;
87}
88impl UniverseMapExt for UniverseMap {
89 fn add(&mut self, universe: UniverseIndex) {
90 if let Err(i) = self.universes.binary_search(&universe) {
91 self.universes.insert(i, universe);
92 }
93 }
94
95 fn map_universe_to_canonical(&self, universe: UniverseIndex) -> Option<UniverseIndex> {
103 self.universes
104 .binary_search(&universe)
105 .ok()
106 .map(|index| UniverseIndex { counter: index })
107 }
108
109 fn map_universe_from_canonical(&self, universe: UniverseIndex) -> UniverseIndex {
113 if universe.counter < self.universes.len() {
114 self.universes[universe.counter]
115 } else {
116 let difference = universe.counter - self.universes.len();
122 let max_counter = self.universes.last().unwrap().counter;
123 let new_counter = max_counter + difference + 1;
124 UniverseIndex {
125 counter: new_counter,
126 }
127 }
128 }
129
130 fn map_from_canonical<T, I>(&self, interner: I, canonical_value: &Canonical<T>) -> Canonical<T>
158 where
159 T: Clone + TypeFoldable<I> + HasInterner<Interner = I>,
160 T: HasInterner<Interner = I>,
161 I: Interner,
162 {
163 debug_span!("map_from_canonical", ?canonical_value, universes = ?self.universes);
164
165 let binders = canonical_value
166 .binders
167 .iter(interner)
168 .map(|cvk| cvk.map_ref(|&universe| self.map_universe_from_canonical(universe)));
169
170 let value = canonical_value
171 .value
172 .clone()
173 .try_fold_with(
174 &mut UMapFromCanonical {
175 interner,
176 universes: self,
177 },
178 DebruijnIndex::INNERMOST,
179 )
180 .unwrap();
181
182 Canonical {
183 binders: CanonicalVarKinds::from_iter(interner, binders),
184 value,
185 }
186 }
187}
188
189struct UCollector<'q, I> {
192 universes: &'q mut UniverseMap,
193 interner: I,
194}
195
196impl<I: Interner> TypeVisitor<I> for UCollector<'_, I> {
197 type BreakTy = ();
198
199 fn as_dyn(&mut self) -> &mut dyn TypeVisitor<I, BreakTy = Self::BreakTy> {
200 self
201 }
202
203 fn visit_free_placeholder(
204 &mut self,
205 universe: PlaceholderIndex,
206 _outer_binder: DebruijnIndex,
207 ) -> ControlFlow<()> {
208 self.universes.add(universe.ui);
209 ControlFlow::Continue(())
210 }
211
212 fn forbid_inference_vars(&self) -> bool {
213 true
214 }
215
216 fn interner(&self) -> I {
217 self.interner
218 }
219}
220
221#[derive(FallibleTypeFolder)]
222struct UMapToCanonical<'q, I: Interner> {
223 interner: I,
224 universes: &'q UniverseMap,
225}
226
227impl<'i, I: Interner> TypeFolder<I> for UMapToCanonical<'i, I> {
228 fn as_dyn(&mut self) -> &mut dyn TypeFolder<I> {
229 self
230 }
231
232 fn forbid_inference_vars(&self) -> bool {
233 true
234 }
235
236 fn fold_free_placeholder_ty(
237 &mut self,
238 universe0: PlaceholderIndex,
239 _outer_binder: DebruijnIndex,
240 ) -> Ty<I> {
241 let ui = self
242 .universes
243 .map_universe_to_canonical(universe0.ui)
244 .expect("Expected UCollector to encounter this universe");
245 PlaceholderIndex {
246 ui,
247 idx: universe0.idx,
248 }
249 .to_ty(TypeFolder::interner(self))
250 }
251
252 fn fold_free_placeholder_lifetime(
253 &mut self,
254 universe0: PlaceholderIndex,
255 _outer_binder: DebruijnIndex,
256 ) -> Lifetime<I> {
257 let universe = self
258 .universes
259 .map_universe_to_canonical(universe0.ui)
260 .expect("Expected UCollector to encounter this universe");
261
262 PlaceholderIndex {
263 ui: universe,
264 idx: universe0.idx,
265 }
266 .to_lifetime(TypeFolder::interner(self))
267 }
268
269 fn fold_free_placeholder_const(
270 &mut self,
271 ty: Ty<I>,
272 universe0: PlaceholderIndex,
273 _outer_binder: DebruijnIndex,
274 ) -> Const<I> {
275 let universe = self
276 .universes
277 .map_universe_to_canonical(universe0.ui)
278 .expect("Expected UCollector to encounter this universe");
279
280 PlaceholderIndex {
281 ui: universe,
282 idx: universe0.idx,
283 }
284 .to_const(TypeFolder::interner(self), ty)
285 }
286
287 fn interner(&self) -> I {
288 self.interner
289 }
290}
291
292#[derive(FallibleTypeFolder)]
293struct UMapFromCanonical<'q, I: Interner> {
294 interner: I,
295 universes: &'q UniverseMap,
296}
297
298impl<'i, I: Interner> TypeFolder<I> for UMapFromCanonical<'i, I> {
299 fn as_dyn(&mut self) -> &mut dyn TypeFolder<I> {
300 self
301 }
302
303 fn fold_free_placeholder_ty(
304 &mut self,
305 universe0: PlaceholderIndex,
306 _outer_binder: DebruijnIndex,
307 ) -> Ty<I> {
308 let ui = self.universes.map_universe_from_canonical(universe0.ui);
309 PlaceholderIndex {
310 ui,
311 idx: universe0.idx,
312 }
313 .to_ty(TypeFolder::interner(self))
314 }
315
316 fn fold_free_placeholder_lifetime(
317 &mut self,
318 universe0: PlaceholderIndex,
319 _outer_binder: DebruijnIndex,
320 ) -> Lifetime<I> {
321 let universe = self.universes.map_universe_from_canonical(universe0.ui);
322 PlaceholderIndex {
323 ui: universe,
324 idx: universe0.idx,
325 }
326 .to_lifetime(TypeFolder::interner(self))
327 }
328
329 fn forbid_inference_vars(&self) -> bool {
330 true
331 }
332
333 fn interner(&self) -> I {
334 self.interner
335 }
336}