Ensures `self` contains bindings for all of `relation`'s subexpressions, including itself, and replaces `relation` with a reference to its corresponding identifier. The algorithm performs a post-order traversal of the expression tree, binding each distinct expression to a new local identifier and replacing each expression with a reference to the identifier for the expression. It maintains the inv
(
&mut self,
id_gen: &mut IdGen,
relation: &mut MirRelationExpr,
)
| 127 | /// can break if `body` acquires a reference to an arranged term, as that arrangement is not |
| 128 | /// available outside the loop). |
| 129 | fn insert_expression( |
| 130 | &mut self, |
| 131 | id_gen: &mut IdGen, |
| 132 | relation: &mut MirRelationExpr, |
| 133 | ) -> Result<(), crate::TransformError> { |
| 134 | self.checked_recur_mut(|this| { |
| 135 | match relation { |
| 136 | MirRelationExpr::LetRec { |
| 137 | ids, |
| 138 | values, |
| 139 | body, |
| 140 | limits, |
| 141 | } => { |
| 142 | // Used for `zip_eq`. |
| 143 | use itertools::Itertools; |
| 144 | |
| 145 | // Introduce a new copy of `self`, which will be specific to this scope. |
| 146 | // This makes expressions used in the outer scope available for re-use. |
| 147 | // We will discard `scoped_anf` once we have processed the `LetRec`. |
| 148 | let mut scoped_anf = this.clone(); |
| 149 | |
| 150 | // Used to distinguish new bindings from old bindings. |
| 151 | // This is needed to extract from `scoped_anf` only the bindings added |
| 152 | // in this block, and not those inherited from `self`. |
| 153 | let id_boundary = id_gen.allocate_id(); |
| 154 | |
| 155 | // Each identifier in `ids` will be given *two* new identifiers, |
| 156 | // initially one "before" and then once bound another one "after". |
| 157 | // The two identifiers are important to distinguish references to the |
| 158 | // binding "before" it is refreshed, and "after" it is refreshed. |
| 159 | // We can equate two "before" references and two "after" references, |
| 160 | // but we must not equate a "before" and an "after" reference. |
| 161 | |
| 162 | // For each bound identifier from `ids`, a temporary identifier for the "before" version. |
| 163 | let before_ids = ids |
| 164 | .iter() |
| 165 | .map(|_id| LocalId::new(id_gen.allocate_id())) |
| 166 | .collect::<Vec<_>>(); |
| 167 | let mut after_ids = Vec::new(); |
| 168 | |
| 169 | // Install the "before" rebindings to start. |
| 170 | // These rebindings will be used for each binding until we process the binding. |
| 171 | scoped_anf |
| 172 | .rebindings |
| 173 | .extend(ids.iter().zip_eq(before_ids.iter()).map(|(x, y)| (*x, *y))); |
| 174 | |
| 175 | // Convert each bound expression into a sequence of let bindings, which are appended |
| 176 | // to the sequence of let bindings from prior bound expressions. |
| 177 | // After visiting the expression, we'll update the binding for the `id` to its "after" |
| 178 | // identifier. |
| 179 | for (index, value) in values.iter_mut().enumerate() { |
| 180 | scoped_anf.insert_expression(id_gen, value)?; |
| 181 | // Update the binding for `ids[index]` from its "before" id to a new "after" id. |
| 182 | let new_id = id_gen.allocate_id(); |
| 183 | after_ids.push(new_id); |
| 184 | scoped_anf |
| 185 | .rebindings |
| 186 | .insert(ids[index].clone(), LocalId::new(new_id)); |
no test coverage detected