mz_expr/visit.rs
1// Copyright Materialize, Inc. and contributors. All rights reserved.
2//
3// Use of this software is governed by the Business Source License
4// included in the LICENSE file.
5//
6// As of the Change Date specified in that file, in accordance with
7// the Business Source License, use of this software will be governed
8// by the Apache License, Version 2.0.
9
10//! Visitor support for recursive data types.
11//!
12//! Recursive types can implement the [`VisitChildren`] trait, to
13//! specify how their recursive entries can be accessed. The extension
14//! trait [`Visit`] then adds support for iteratively traversing
15//! instances of those types.
16//!
17//! # Naming
18//!
19//! Visitor methods follow this naming pattern:
20//!
21//! ```text
22//! [try_]visit_[mut_]{children,post,pre}
23//! ```
24//!
25//! * The `try`-prefix specifies whether the visitor callback is
26//! fallible (prefix present) or infallible (prefix omitted).
27//! * The `mut`-suffix specifies whether the visitor callback gets
28//! access to mutable (prefix present) or immutable (prefix omitted)
29//! child references.
30//! * The final suffix determines the nature of the traversal:
31//! * `children`: only visit direct children
32//! * `post`: recursively visit children in post-order
33//! * `pre`: recursively visit children in pre-order
34//! * no suffix: recursively visit children in pre- and post-order
35//! using a ~Visitor~` that encapsulates the shared context.
36
37/// A trait for types that can visit their direct children of type `T`.
38///
39/// Implementing [`VisitChildren<Self>`] automatically also implements
40/// the [`Visit`] trait, which enables recursive traversal.
41///
42/// Note that care needs to be taken when implementing this trait for
43/// mutually recursive types (such as a type A where A has children
44/// of type B and vice versa). More specifically, at the moment it is
45/// not possible to implement versions of `VisitChildren<A> for A` such
46/// that A considers as its children all A-nodes occurring at leaf
47/// positions of B-children and vice versa for `VisitChildren<B> for B`.
48/// Doing this will result in recursion limit violations as indicated
49/// in the accompanying `test_recursive_types_b` test.
50pub trait VisitChildren<T> {
51 /// Apply an infallible immutable function `f` to each direct child.
52 fn visit_children<F>(&self, f: F)
53 where
54 F: FnMut(&T),
55 {
56 self.children().for_each(f);
57 }
58
59 /// Apply an infallible mutable function `f` to each direct child.
60 fn visit_mut_children<F>(&mut self, f: F)
61 where
62 F: FnMut(&mut T),
63 {
64 self.children_mut().for_each(f);
65 }
66
67 /// Apply a fallible immutable function `f` to each direct child.
68 fn try_visit_children<F, E>(&self, mut f: F) -> Result<(), E>
69 where
70 F: FnMut(&T) -> Result<(), E>,
71 {
72 for child in self.children() {
73 f(child)?;
74 }
75
76 Ok(())
77 }
78
79 /// Apply a fallible mutable function `f` to each direct child.
80 fn try_visit_mut_children<F, E>(&mut self, mut f: F) -> Result<(), E>
81 where
82 F: FnMut(&mut T) -> Result<(), E>,
83 {
84 for child in self.children_mut() {
85 f(child)?;
86 }
87
88 Ok(())
89 }
90
91 /// The `T`-typed children of this element.
92 fn children<'a>(&'a self) -> impl DoubleEndedIterator<Item = &'a T>
93 where
94 T: 'a;
95
96 /// The `&mut T`-typed children of this element.
97 ///
98 /// It is critical for the safety of mutable post-order traversals that this
99 /// function be written using safe code.
100 fn children_mut<'a>(&'a mut self) -> impl DoubleEndedIterator<Item = &'a mut T>
101 where
102 T: 'a;
103}
104
105/// A trait for types that can recursively visit their children of the
106/// same type.
107///
108/// This trait is automatically implemented for all implementors of
109/// [`VisitChildren`].
110///
111/// All methods provided by this trait are iterative.
112///
113/// NB that any visitor with mutable post-traversal uses unsafe code. It is critical
114/// that `VisitChildren::children_mut` be written using safe code, i.e., no aliasing
115/// of children or access to parents.
116pub trait Visit {
117 /// Post-order immutable infallible visitor for `self`.
118 fn visit_post<F>(&self, f: &mut F)
119 where
120 F: FnMut(&Self);
121
122 /// Post-order mutable infallible visitor for `self`.
123 fn visit_mut_post<F>(&mut self, f: &mut F)
124 where
125 F: FnMut(&mut Self);
126
127 /// Post-order immutable fallible visitor for `self`.
128 fn try_visit_post<F, E>(&self, f: &mut F) -> Result<(), E>
129 where
130 F: FnMut(&Self) -> Result<(), E>;
131
132 /// Post-order mutable fallible visitor for `self`.
133 fn try_visit_mut_post<F, E>(&mut self, f: &mut F) -> Result<(), E>
134 where
135 F: FnMut(&mut Self) -> Result<(), E>;
136
137 /// Pre-order immutable infallible visitor for `self`.
138 fn visit_pre<F>(&self, f: &mut F)
139 where
140 F: FnMut(&Self);
141
142 /// Pre-order immutable infallible visitor for `self`, which also accumulates context
143 /// information along the path from the root to the current node's parent.
144 /// `acc_fun` is a similar closure as in `fold`. The accumulated context is passed to the
145 /// visitor, along with the current node.
146 ///
147 /// For example, one can use this on a `MirScalarExpr` to tell the visitor whether the current
148 /// subexpression has a negation somewhere above it.
149 ///
150 /// When using it on a `MirRelationExpr`, one has to be mindful that `Let` bindings are not
151 /// followed, i.e., the context won't include what happens with a `Let` binding in some other
152 /// `MirRelationExpr` where the binding occurs in a `Get`.
153 fn visit_pre_with_context<Context, AccFun, Visitor>(
154 &self,
155 init: Context,
156 acc_fun: &mut AccFun,
157 visitor: &mut Visitor,
158 ) where
159 Context: Clone,
160 AccFun: FnMut(Context, &Self) -> Context,
161 Visitor: FnMut(&Context, &Self);
162
163 /// Pre-order mutable infallible visitor for `self`.
164 fn visit_mut_pre<F>(&mut self, f: &mut F)
165 where
166 F: FnMut(&mut Self);
167
168 /// Pre-order immutable fallible visitor for `self`.
169 fn try_visit_pre<F, E>(&self, f: &mut F) -> Result<(), E>
170 where
171 F: FnMut(&Self) -> Result<(), E>;
172
173 /// Pre-order mutable fallible visitor for `self`.
174 fn try_visit_mut_pre<F, E>(&mut self, f: &mut F) -> Result<(), E>
175 where
176 F: FnMut(&mut Self) -> Result<(), E>;
177
178 /// A generalization of [`Visit::visit_pre`] and [`Visit::visit_post`].
179 ///
180 /// The function `pre` runs on `self` before it runs on any of the children.
181 /// The function `post` runs on children first before the parent.
182 ///
183 /// Optionally, `pre` can return which children, if any, should be visited
184 /// (default is to visit all children).
185 fn visit_pre_post<F1, F2>(&self, pre: &mut F1, post: &mut F2)
186 where
187 F1: FnMut(&Self) -> Option<Vec<&Self>>,
188 F2: FnMut(&Self);
189
190 /// A generalization of [`Visit::visit_mut_pre`] and [`Visit::visit_mut_post`].
191 ///
192 /// The function `pre` runs on `self` before it runs on any of the children.
193 /// The function `post` runs on children first before the parent.
194 ///
195 /// Optionally, `pre` can return which children, if any, should be visited
196 /// (default is to visit all children).
197 ///
198 /// It is important for safety that `pre` is (a) safe code and (b) returns children only.
199 fn visit_mut_pre_post<F1, F2>(&mut self, pre: &mut F1, post: &mut F2)
200 where
201 F1: FnMut(&mut Self) -> Option<Vec<&mut Self>>,
202 F2: FnMut(&mut Self);
203}
204
205/// Frames for immutable post-traversals, will be kept in a stack.
206enum VisitAction<'a, T> {
207 /// Put on the stack when entering a node.
208 ///
209 /// Causes us to push children.
210 Enter(&'a T),
211 /// Put on the stack when leaving a node, all children visited.
212 ///
213 /// Causes us to do the post-traversal visit of the parent.
214 Leave(&'a T),
215}
216
217/// Frames for mutable post-traversals, will be kept in a stack.
218///
219/// Notice that we use mutable pointers, because mutable post-traversal is unsafe in rust.
220///
221/// The core argument for correctness mirrors the tree-borrow correctness argument Rust's
222/// borrow checker uses for the ordinary function call stack. Loosely:
223///
224/// - We split a mutable parent node into its children, and put them on the stack.
225/// - We keep a mutable pointer to the parent node, but won't touch it until we're done with all children.
226/// + In the function call stack, this mutable pointer is the stack frame, safely inaccessible.
227/// + In our `unsafe` action stack, this mutable pointer is below all of the `Enter` actions,
228/// and we promise not to touch it until they complete.
229/// - When we have processed all children, we can reassemble access to the parent from its parts.
230/// + In the function call stack, we do this on return from recursive calls.
231/// - In our `unsafe` action stack, we do this after popping all children.
232enum VisitMutAction<T> {
233 /// Put on the stack when entering a node.
234 ///
235 /// Causes us to push children.
236 Enter(*mut T),
237 /// Put on the stack when leaving a node, all children visited.
238 ///
239 /// Causes us to do the post-traversal visit of the parent.
240 Leave(*mut T),
241}
242
243impl<T: VisitChildren<T>> Visit for T {
244 fn visit_post<F>(&self, f: &mut F)
245 where
246 F: FnMut(&Self),
247 {
248 use VisitAction::*;
249 let mut stack = vec![Enter(self)];
250 while let Some(action) = stack.pop() {
251 match action {
252 Enter(elt) => {
253 stack.push(Leave(elt));
254 // Push children in reverse so they pop (and are visited) left-to-right.
255 stack.extend(elt.children().rev().map(Enter));
256 }
257 Leave(elt) => f(elt),
258 }
259 }
260 }
261
262 #[allow(clippy::as_conversions)]
263 fn visit_mut_post<F>(&mut self, f: &mut F)
264 where
265 F: FnMut(&mut Self),
266 {
267 // This code uses `unsafe`. The core safety argument is that:
268 //
269 // - `children_mut()` produces disjoint children
270 // - no aliasing means each `Enter` is processed separately, and we `Leave` each node exactly once
271 //
272 // Put another way, our `stack` mirrors the function call stack, which allows multiple `&mut` refs at once,
273 // since only one stack frame can be active at a time.
274
275 use VisitMutAction::*;
276 let mut stack = vec![Enter(self as *mut T)];
277 while let Some(action) = stack.pop() {
278 match action {
279 Enter(ptr) => {
280 stack.push(Leave(ptr));
281 let elt = unsafe { &mut *ptr };
282 // Push children in reverse so they pop (and are visited) left-to-right.
283 stack.extend(elt.children_mut().rev().map(|child| Enter(child as *mut T)));
284 }
285 Leave(elt) => f(unsafe { &mut *elt }),
286 }
287 }
288 }
289
290 fn try_visit_post<F, E>(&self, f: &mut F) -> Result<(), E>
291 where
292 F: FnMut(&Self) -> Result<(), E>,
293 {
294 use VisitAction::*;
295 let mut stack = vec![Enter(self)];
296 while let Some(action) = stack.pop() {
297 match action {
298 Enter(elt) => {
299 stack.push(Leave(elt));
300 // Push children in reverse so they pop (and are visited) left-to-right.
301 stack.extend(elt.children().rev().map(Enter));
302 }
303 Leave(elt) => f(elt)?,
304 }
305 }
306
307 Ok(())
308 }
309
310 #[allow(clippy::as_conversions)]
311 fn try_visit_mut_post<F, E>(&mut self, f: &mut F) -> Result<(), E>
312 where
313 F: FnMut(&mut Self) -> Result<(), E>,
314 {
315 // This code uses `unsafe`. The core safety argument is that:
316 //
317 // - `children_mut()` produces disjoint children
318 // - no aliasing means each `Enter` is processed separately, and we `Leave` each node exactly once
319 //
320 // Put another way, our `stack` mirrors the function call stack, which allows multiple `&mut` refs at once,
321 // since only one stack frame can be active at a time.
322
323 use VisitMutAction::*;
324 let mut stack = vec![Enter(self as *mut T)];
325 while let Some(action) = stack.pop() {
326 match action {
327 Enter(ptr) => {
328 stack.push(Leave(ptr));
329 let elt = unsafe { &mut *ptr };
330 // Push children in reverse so they pop (and are visited) left-to-right.
331 stack.extend(elt.children_mut().rev().map(|child| Enter(child as *mut T)));
332 }
333 Leave(ptr) => f(unsafe { &mut *ptr })?,
334 }
335 }
336
337 Ok(())
338 }
339
340 fn visit_pre<F>(&self, f: &mut F)
341 where
342 F: FnMut(&Self),
343 {
344 let mut stack = vec![self];
345 while let Some(elt) = stack.pop() {
346 f(elt);
347 // Push children in reverse so they pop (and are visited) left-to-right.
348 stack.extend(elt.children().rev());
349 }
350 }
351
352 fn visit_pre_with_context<Context, AccFun, Visitor>(
353 &self,
354 init: Context,
355 acc_fun: &mut AccFun,
356 visitor: &mut Visitor,
357 ) where
358 Context: Clone,
359 AccFun: FnMut(Context, &Self) -> Context,
360 Visitor: FnMut(&Context, &Self),
361 {
362 let mut stack = vec![(self, init)];
363 while let Some((elt, ctx)) = stack.pop() {
364 visitor(&ctx, elt);
365 let ctx = acc_fun(ctx, elt);
366 // Push children in reverse so they pop (and are visited) left-to-right.
367 stack.extend(elt.children().rev().map(|child| (child, ctx.clone())));
368 }
369 }
370
371 fn visit_mut_pre<F>(&mut self, f: &mut F)
372 where
373 F: FnMut(&mut Self),
374 {
375 let mut stack = vec![self];
376 while let Some(elt) = stack.pop() {
377 f(elt);
378 // Push children in reverse so they pop (and are visited) left-to-right.
379 stack.extend(elt.children_mut().rev())
380 }
381 }
382
383 fn try_visit_pre<F, E>(&self, f: &mut F) -> Result<(), E>
384 where
385 F: FnMut(&Self) -> Result<(), E>,
386 {
387 let mut stack = vec![self];
388 while let Some(elt) = stack.pop() {
389 f(elt)?;
390 // Push children in reverse so they pop (and are visited) left-to-right.
391 stack.extend(elt.children().rev());
392 }
393
394 Ok(())
395 }
396
397 fn try_visit_mut_pre<F, E>(&mut self, f: &mut F) -> Result<(), E>
398 where
399 F: FnMut(&mut Self) -> Result<(), E>,
400 {
401 let mut stack = vec![self];
402 while let Some(elt) = stack.pop() {
403 f(elt)?;
404 // Push children in reverse so they pop (and are visited) left-to-right.
405 stack.extend(elt.children_mut().rev());
406 }
407
408 Ok(())
409 }
410 fn visit_pre_post<F1, F2>(&self, pre: &mut F1, post: &mut F2)
411 where
412 F1: FnMut(&Self) -> Option<Vec<&Self>>,
413 F2: FnMut(&Self),
414 {
415 use VisitAction::*;
416 let mut stack = vec![Enter(self)];
417 while let Some(action) = stack.pop() {
418 match action {
419 Enter(elt) => {
420 stack.push(Leave(elt));
421 if let Some(children) = pre(elt) {
422 for child in children.into_iter().rev() {
423 stack.push(Enter(child));
424 }
425 } else {
426 for child in elt.children().rev() {
427 stack.push(Enter(child));
428 }
429 }
430 }
431 Leave(elt) => {
432 post(elt);
433 }
434 }
435 }
436 }
437
438 #[allow(clippy::as_conversions)]
439 fn visit_mut_pre_post<F1, F2>(&mut self, pre: &mut F1, post: &mut F2)
440 where
441 F1: FnMut(&mut Self) -> Option<Vec<&mut Self>>,
442 F2: FnMut(&mut Self),
443 {
444 // This code uses `unsafe`. The core safety argument is that:
445 //
446 // - `children_mut()` produces disjoint children
447 // - no aliasing means each `Enter` is processed separately, and we `Leave` each node exactly once
448 // - even if `pre` modifies the pointer, we retake it before computing children
449 //
450 // Put another way, our `stack` mirrors the function call stack, which allows multiple `&mut` refs at once,
451 // since only one stack frame can be active at a time.
452
453 use VisitMutAction::*;
454 let mut stack = vec![Enter(self as *mut T)];
455 while let Some(action) = stack.pop() {
456 match action {
457 Enter(ptr) => {
458 let elt = unsafe { &mut *ptr };
459 stack.push(Leave(ptr));
460
461 if let Some(children) = pre(elt) {
462 for child in children.into_iter().rev() {
463 stack.push(Enter(child));
464 }
465 } else {
466 let elt = unsafe { &mut *ptr };
467 for child in elt.children_mut().rev() {
468 stack.push(Enter(child));
469 }
470 }
471 }
472 Leave(ptr) => {
473 post(unsafe { &mut *ptr });
474 }
475 }
476 }
477 }
478}
479
480#[cfg(test)]
481mod tests {
482 use super::*;
483
484 // This test demonstrates how to build visitors for mutually recursive definitions.
485 // The key move here is the `direct_sub_*` methods, which are worklist-based traversals
486 // that find children of appropriate type.
487
488 #[derive(Debug, Eq, PartialEq)]
489 enum A {
490 Add(Box<A>, Box<A>),
491 Lit(u64),
492 FrB(Box<B>),
493 }
494
495 #[derive(Debug, Eq, PartialEq)]
496 enum B {
497 Mul(Box<B>, Box<B>),
498 Lit(u64),
499 FrA(Box<A>),
500 }
501
502 impl A {
503 fn direct_sub_b(&self) -> Vec<&B> {
504 let mut subs: Vec<&B> = vec![];
505
506 let mut worklist = vec![self];
507 while let Some(a) = worklist.pop() {
508 match a {
509 A::Add(lhs, rhs) => {
510 worklist.push(&*lhs);
511 worklist.push(&*rhs);
512 }
513 A::Lit(_) => (),
514 A::FrB(b) => subs.push(&*b),
515 }
516 }
517
518 subs
519 }
520
521 fn direct_sub_b_mut(&mut self) -> Vec<&mut B> {
522 let mut subs: Vec<&mut B> = vec![];
523
524 let mut worklist = vec![self];
525 while let Some(a) = worklist.pop() {
526 match a {
527 A::Add(lhs, rhs) => {
528 worklist.push(&mut **lhs);
529 worklist.push(&mut **rhs);
530 }
531 A::Lit(_) => (),
532 A::FrB(b) => subs.push(&mut **b),
533 }
534 }
535
536 subs
537 }
538 }
539
540 impl B {
541 fn direct_sub_a(&self) -> Vec<&A> {
542 let mut subs: Vec<&A> = vec![];
543
544 let mut worklist = vec![self];
545 while let Some(b) = worklist.pop() {
546 match b {
547 B::Mul(lhs, rhs) => {
548 worklist.push(&*lhs);
549 worklist.push(&*rhs);
550 }
551 B::Lit(_) => (),
552 B::FrA(a) => subs.push(&*a),
553 }
554 }
555
556 subs
557 }
558
559 fn direct_sub_a_mut(&mut self) -> Vec<&mut A> {
560 let mut subs: Vec<&mut A> = vec![];
561
562 let mut worklist = vec![self];
563 while let Some(b) = worklist.pop() {
564 match b {
565 B::Mul(lhs, rhs) => {
566 worklist.push(&mut **lhs);
567 worklist.push(&mut **rhs);
568 }
569 B::Lit(_) => (),
570 B::FrA(a) => subs.push(&mut **a),
571 }
572 }
573
574 subs
575 }
576 }
577
578 impl VisitChildren<A> for A {
579 fn visit_children<F>(&self, mut f: F)
580 where
581 F: FnMut(&A),
582 {
583 VisitChildren::visit_children(self, |expr: &B| {
584 Visit::visit_post(expr, &mut |expr| match expr {
585 B::FrA(expr) => f(expr.as_ref()),
586 _ => (),
587 });
588 });
589
590 match self {
591 A::Add(lhs, rhs) => {
592 f(lhs);
593 f(rhs);
594 }
595 A::Lit(_) => (),
596 A::FrB(_) => (),
597 }
598 }
599
600 fn visit_mut_children<F>(&mut self, mut f: F)
601 where
602 F: FnMut(&mut A),
603 {
604 VisitChildren::visit_mut_children(self, |expr: &mut B| {
605 Visit::visit_mut_post(expr, &mut |expr| match expr {
606 B::FrA(expr) => f(expr.as_mut()),
607 _ => (),
608 });
609 });
610
611 match self {
612 A::Add(lhs, rhs) => {
613 f(lhs);
614 f(rhs);
615 }
616 A::Lit(_) => (),
617 A::FrB(_) => (),
618 }
619 }
620
621 fn try_visit_children<F, E>(&self, mut f: F) -> Result<(), E>
622 where
623 F: FnMut(&A) -> Result<(), E>,
624 {
625 VisitChildren::try_visit_children(self, |expr: &B| {
626 Visit::try_visit_post(expr, &mut |expr| match expr {
627 B::FrA(expr) => f(expr.as_ref()),
628 _ => Ok(()),
629 })
630 })?;
631
632 match self {
633 A::Add(lhs, rhs) => {
634 f(lhs)?;
635 f(rhs)?;
636 }
637 A::Lit(_) => (),
638 A::FrB(_) => (),
639 }
640 Ok(())
641 }
642
643 fn try_visit_mut_children<F, E>(&mut self, mut f: F) -> Result<(), E>
644 where
645 F: FnMut(&mut A) -> Result<(), E>,
646 {
647 VisitChildren::try_visit_mut_children(self, |expr: &mut B| {
648 Visit::try_visit_mut_post(expr, &mut |expr| match expr {
649 B::FrA(expr) => f(expr.as_mut()),
650 _ => Ok(()),
651 })
652 })?;
653
654 match self {
655 A::Add(lhs, rhs) => {
656 f(lhs)?;
657 f(rhs)?;
658 }
659 A::Lit(_) => (),
660 A::FrB(_) => (),
661 }
662 Ok(())
663 }
664
665 fn children<'a>(&'a self) -> impl DoubleEndedIterator<Item = &'a A>
666 where
667 A: 'a,
668 {
669 let mut v: Vec<&A> = vec![];
670 match self {
671 A::Add(lhs, rhs) => {
672 v.push(&*lhs);
673 v.push(&*rhs)
674 }
675 A::Lit(_) => (),
676 A::FrB(b) => {
677 v.append(&mut b.direct_sub_a());
678 }
679 }
680
681 v.into_iter()
682 }
683
684 fn children_mut<'a>(&'a mut self) -> impl DoubleEndedIterator<Item = &'a mut A>
685 where
686 A: 'a,
687 {
688 let mut v: Vec<&mut A> = vec![];
689
690 match self {
691 A::Add(lhs, rhs) => {
692 v.push(&mut **lhs);
693 v.push(&mut **rhs)
694 }
695 A::Lit(_) => (),
696 A::FrB(b) => {
697 v.append(&mut b.direct_sub_a_mut());
698 }
699 }
700
701 v.into_iter()
702 }
703 }
704
705 impl VisitChildren<B> for A {
706 fn visit_children<F>(&self, mut f: F)
707 where
708 F: FnMut(&B),
709 {
710 match self {
711 A::Add(_, _) => (),
712 A::Lit(_) => (),
713 A::FrB(expr) => f(expr),
714 }
715 }
716
717 fn visit_mut_children<F>(&mut self, mut f: F)
718 where
719 F: FnMut(&mut B),
720 {
721 match self {
722 A::Add(_, _) => (),
723 A::Lit(_) => (),
724 A::FrB(expr) => f(expr),
725 }
726 }
727
728 fn try_visit_children<F, E>(&self, mut f: F) -> Result<(), E>
729 where
730 F: FnMut(&B) -> Result<(), E>,
731 {
732 match self {
733 A::Add(_, _) => Ok(()),
734 A::Lit(_) => Ok(()),
735 A::FrB(expr) => f(expr),
736 }
737 }
738
739 fn try_visit_mut_children<F, E>(&mut self, mut f: F) -> Result<(), E>
740 where
741 F: FnMut(&mut B) -> Result<(), E>,
742 {
743 match self {
744 A::Add(_, _) => Ok(()),
745 A::Lit(_) => Ok(()),
746 A::FrB(expr) => f(expr),
747 }
748 }
749
750 fn children<'a>(&'a self) -> impl DoubleEndedIterator<Item = &'a B>
751 where
752 B: 'a,
753 {
754 let mut child: Option<&B> = None;
755 match self {
756 A::Add(_, _) | A::Lit(_) => (),
757 A::FrB(b) => child = Some(&*b),
758 }
759 child.into_iter()
760 }
761
762 fn children_mut<'a>(&'a mut self) -> impl DoubleEndedIterator<Item = &'a mut B>
763 where
764 B: 'a,
765 {
766 let mut child: Option<&mut B> = None;
767 match self {
768 A::Add(_, _) | A::Lit(_) => (),
769 A::FrB(b) => child = Some(&mut **b),
770 }
771 child.into_iter()
772 }
773 }
774
775 impl VisitChildren<B> for B {
776 fn visit_children<F>(&self, mut f: F)
777 where
778 F: FnMut(&B),
779 {
780 // VisitChildren::visit_children(self, |expr: &A| {
781 // #[allow(deprecated)]
782 // Visit::visit_post(expr, &mut |expr| match expr {
783 // A::FrB(expr) => f(expr.as_ref()),
784 // _ => (),
785 // });
786 // });
787
788 match self {
789 B::Mul(lhs, rhs) => {
790 f(lhs);
791 f(rhs);
792 }
793 B::Lit(_) => (),
794 B::FrA(_) => (),
795 }
796 }
797
798 fn visit_mut_children<F>(&mut self, mut f: F)
799 where
800 F: FnMut(&mut B),
801 {
802 // VisitChildren::visit_mut_children(self, |expr: &mut A| {
803 // #[allow(deprecated)]
804 // Visit::visit_mut_post_nolimit(expr, &mut |expr| match expr {
805 // A::FrB(expr) => f(expr.as_mut()),
806 // _ => (),
807 // });
808 // });
809
810 match self {
811 B::Mul(lhs, rhs) => {
812 f(lhs);
813 f(rhs);
814 }
815 B::Lit(_) => (),
816 B::FrA(_) => (),
817 }
818 }
819
820 fn try_visit_children<F, E>(&self, mut f: F) -> Result<(), E>
821 where
822 F: FnMut(&B) -> Result<(), E>,
823 {
824 // VisitChildren::try_visit_children(self, |expr: &A| {
825 // Visit::try_visit_post(expr, &mut |expr| match expr {
826 // A::FrB(expr) => f(expr.as_ref()),
827 // _ => Ok(()),
828 // })
829 // })?;
830
831 match self {
832 B::Mul(lhs, rhs) => {
833 f(lhs)?;
834 f(rhs)?;
835 }
836 B::Lit(_) => (),
837 B::FrA(_) => (),
838 }
839 Ok(())
840 }
841
842 fn try_visit_mut_children<F, E>(&mut self, mut f: F) -> Result<(), E>
843 where
844 F: FnMut(&mut B) -> Result<(), E>,
845 {
846 // VisitChildren::try_visit_mut_children(self, |expr: &mut A| {
847 // Visit::try_visit_mut_post(expr, &mut |expr| match expr {
848 // A::FrB(expr) => f(expr.as_mut()),
849 // _ => Ok(()),
850 // })
851 // })?;
852
853 match self {
854 B::Mul(lhs, rhs) => {
855 f(lhs)?;
856 f(rhs)?;
857 }
858 B::Lit(_) => (),
859 B::FrA(_) => (),
860 }
861 Ok(())
862 }
863
864 fn children<'a>(&'a self) -> impl DoubleEndedIterator<Item = &'a B>
865 where
866 B: 'a,
867 {
868 let mut v: Vec<&B> = vec![];
869 match self {
870 B::Mul(lhs, rhs) => {
871 v.push(&*lhs);
872 v.push(&*rhs);
873 }
874 B::Lit(_) => (),
875 B::FrA(a) => v.append(&mut a.direct_sub_b()),
876 }
877 v.into_iter()
878 }
879
880 fn children_mut<'a>(&'a mut self) -> impl DoubleEndedIterator<Item = &'a mut B>
881 where
882 B: 'a,
883 {
884 let mut v: Vec<&mut B> = vec![];
885 match self {
886 B::Mul(lhs, rhs) => {
887 v.push(&mut **lhs);
888 v.push(&mut **rhs);
889 }
890 B::Lit(_) => (),
891 B::FrA(a) => v.append(&mut a.direct_sub_b_mut()),
892 }
893 v.into_iter()
894 }
895 }
896
897 impl VisitChildren<A> for B {
898 fn visit_children<F>(&self, mut f: F)
899 where
900 F: FnMut(&A),
901 {
902 match self {
903 B::Mul(_, _) => (),
904 B::Lit(_) => (),
905 B::FrA(expr) => f(expr),
906 }
907 }
908
909 fn visit_mut_children<F>(&mut self, mut f: F)
910 where
911 F: FnMut(&mut A),
912 {
913 match self {
914 B::Mul(_, _) => (),
915 B::Lit(_) => (),
916 B::FrA(expr) => f(expr),
917 }
918 }
919
920 fn try_visit_children<F, E>(&self, mut f: F) -> Result<(), E>
921 where
922 F: FnMut(&A) -> Result<(), E>,
923 {
924 match self {
925 B::Mul(_, _) => Ok(()),
926 B::Lit(_) => Ok(()),
927 B::FrA(expr) => f(expr),
928 }
929 }
930
931 fn try_visit_mut_children<F, E>(&mut self, mut f: F) -> Result<(), E>
932 where
933 F: FnMut(&mut A) -> Result<(), E>,
934 {
935 match self {
936 B::Mul(_, _) => Ok(()),
937 B::Lit(_) => Ok(()),
938 B::FrA(expr) => f(expr),
939 }
940 }
941
942 fn children<'a>(&'a self) -> impl DoubleEndedIterator<Item = &'a A>
943 where
944 A: 'a,
945 {
946 let mut child: Option<&A> = None;
947 match self {
948 B::Mul(_, _) | B::Lit(_) => (),
949 B::FrA(a) => child = Some(&*a),
950 }
951 child.into_iter()
952 }
953
954 fn children_mut<'a>(&'a mut self) -> impl DoubleEndedIterator<Item = &'a mut A>
955 where
956 A: 'a,
957 {
958 let mut child: Option<&mut A> = None;
959 match self {
960 B::Mul(_, _) | B::Lit(_) => (),
961 B::FrA(a) => child = Some(&mut **a),
962 }
963 child.into_iter()
964 }
965 }
966
967 /// x + (y + z)
968 fn test_term_a(x: A, y: A, z: A) -> A {
969 let x = Box::new(x);
970 let y = Box::new(y);
971 let z = Box::new(z);
972 A::Add(x, Box::new(A::Add(y, z)))
973 }
974
975 /// u + (v + w)
976 fn test_term_b(u: B, v: B, w: B) -> B {
977 let u = Box::new(u);
978 let v = Box::new(v);
979 let w = Box::new(w);
980 B::Mul(u, Box::new(B::Mul(v, w)))
981 }
982
983 fn a_to_b(x: A) -> B {
984 B::FrA(Box::new(x))
985 }
986
987 fn b_to_a(x: B) -> A {
988 A::FrB(Box::new(x))
989 }
990
991 fn test_term_rec_b(b: u64) -> B {
992 test_term_b(
993 a_to_b(test_term_a(
994 b_to_a(test_term_b(B::Lit(b + 11), B::Lit(b + 12), B::Lit(b + 13))),
995 b_to_a(test_term_b(B::Lit(b + 14), B::Lit(b + 15), B::Lit(b + 16))),
996 b_to_a(test_term_b(B::Lit(b + 17), B::Lit(b + 18), B::Lit(b + 19))),
997 )),
998 a_to_b(test_term_a(
999 b_to_a(test_term_b(B::Lit(b + 21), B::Lit(b + 22), B::Lit(b + 23))),
1000 b_to_a(test_term_b(B::Lit(b + 24), B::Lit(b + 25), B::Lit(b + 26))),
1001 b_to_a(test_term_b(B::Lit(b + 27), B::Lit(b + 28), B::Lit(b + 29))),
1002 )),
1003 a_to_b(test_term_a(
1004 b_to_a(test_term_b(B::Lit(b + 31), B::Lit(b + 32), B::Lit(b + 33))),
1005 b_to_a(test_term_b(B::Lit(b + 34), B::Lit(b + 35), B::Lit(b + 36))),
1006 b_to_a(test_term_b(B::Lit(b + 37), B::Lit(b + 38), B::Lit(b + 39))),
1007 )),
1008 )
1009 }
1010
1011 fn test_term_rec_a(b: u64) -> A {
1012 test_term_a(
1013 b_to_a(test_term_b(
1014 a_to_b(test_term_a(A::Lit(b + 11), A::Lit(b + 12), A::Lit(b + 13))),
1015 a_to_b(test_term_a(A::Lit(b + 14), A::Lit(b + 15), A::Lit(b + 16))),
1016 a_to_b(test_term_a(A::Lit(b + 17), A::Lit(b + 18), A::Lit(b + 19))),
1017 )),
1018 b_to_a(test_term_b(
1019 a_to_b(test_term_a(A::Lit(b + 21), A::Lit(b + 22), A::Lit(b + 23))),
1020 a_to_b(test_term_a(A::Lit(b + 24), A::Lit(b + 25), A::Lit(b + 26))),
1021 a_to_b(test_term_a(A::Lit(b + 27), A::Lit(b + 28), A::Lit(b + 29))),
1022 )),
1023 b_to_a(test_term_b(
1024 a_to_b(test_term_a(A::Lit(b + 31), A::Lit(b + 32), A::Lit(b + 33))),
1025 a_to_b(test_term_a(A::Lit(b + 34), A::Lit(b + 35), A::Lit(b + 36))),
1026 a_to_b(test_term_a(A::Lit(b + 37), A::Lit(b + 38), A::Lit(b + 39))),
1027 )),
1028 )
1029 }
1030
1031 #[mz_ore::test]
1032 #[cfg_attr(miri, ignore)] // error: unsupported operation: can't call foreign function `rust_psm_stack_pointer` on OS `linux`
1033 fn test_recursive_types_a() {
1034 let mut act = test_term_rec_a(0);
1035 let exp = test_term_rec_a(20);
1036
1037 act.visit_mut_pre(&mut |expr| match expr {
1038 A::Lit(x) => *x = *x + 20,
1039 _ => (),
1040 });
1041
1042 assert_eq!(act, exp);
1043 }
1044
1045 #[mz_ore::test]
1046 fn test_recursive_types_b() {
1047 let mut act = test_term_rec_b(0);
1048 let exp = test_term_rec_b(30);
1049
1050 act.visit_mut_pre(&mut |expr| match expr {
1051 B::Lit(x) => *x = *x + 30,
1052 _ => (),
1053 });
1054
1055 assert_eq!(act, exp);
1056 }
1057}