Given the ids and values of a LetRec, it computes the subset of ids that are used across iterations. These are those ids that have a reference before they are defined, when reading all the bindings in order. For example: ```SQL WITH MUTUALLY RECURSIVE x(...) AS f(z), y(...) AS g(x), z(...) AS h(y) ...; ``` Here, only `z` is returned, because `x` and `y` are referenced only within the same iterati
(ids: &[LocalId], values: &[MirRelationExpr])
| 2046 | /// |
| 2047 | /// Note that if a binding references itself, that is also returned. |
| 2048 | pub fn recursive_ids(ids: &[LocalId], values: &[MirRelationExpr]) -> BTreeSet<LocalId> { |
| 2049 | let mut used_across_iterations = BTreeSet::new(); |
| 2050 | let mut defined = BTreeSet::new(); |
| 2051 | for (binding_id, value) in itertools::zip_eq(ids.iter(), values.iter()) { |
| 2052 | value.visit_pre(|expr| { |
| 2053 | if let MirRelationExpr::Get { |
| 2054 | id: Local(get_id), .. |
| 2055 | } = expr |
| 2056 | { |
| 2057 | // If we haven't seen a definition for it yet, then this will refer |
| 2058 | // to the previous iteration. |
| 2059 | // The `ids.contains` part of the condition is needed to exclude |
| 2060 | // those ids that are not really in this LetRec, but either an inner |
| 2061 | // or outer one. |
| 2062 | if !defined.contains(get_id) && ids.contains(get_id) { |
| 2063 | used_across_iterations.insert(*get_id); |
| 2064 | } |
| 2065 | } |
| 2066 | }); |
| 2067 | defined.insert(*binding_id); |
| 2068 | } |
| 2069 | used_across_iterations |
| 2070 | } |
| 2071 | |
| 2072 | /// Replaces `LetRec` nodes with a stack of `Let` nodes. |
| 2073 | /// |