Skip to main content

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}