Perform simultaneous substitution: replace `Var(depth)..Var(depth+n-1)` with `substs[0]..substs[n-1]`, shifting free variables above by `-n`. Uses the same per-call pointer-identity memoization as `subst` so shared sub-expressions are traversed once per depth level (see the module-level docs).
( env: &mut InternTable<M>, body: &KExpr<M>, substs: &[KExpr<M>], depth: u64, )
| 233 | /// with `substs[0]..substs[n-1]`, shifting free variables above by `-n`. |
| 234 | /// |
| 235 | /// Uses the same per-call pointer-identity memoization as `subst` so |
| 236 | /// shared sub-expressions are traversed once per depth level (see the |
| 237 | /// module-level docs). |
| 238 | pub fn simul_subst<M: KernelMode>( |
| 239 | env: &mut InternTable<M>, |
| 240 | body: &KExpr<M>, |
| 241 | substs: &[KExpr<M>], |
| 242 | depth: u64, |
| 243 | ) -> KExpr<M> { |
| 244 | if body.lbr() <= depth { |
| 245 | return body.clone(); |
| 246 | } |
| 247 | // See `subst` for the mem::take/restore pattern. `simul_subst_cached` |
| 248 | // does not call into `subst`/`simul_subst`, so it is safe to share the |
| 249 | // single `subst_scratch` between them. |
| 250 | let mut cache = std::mem::take(&mut env.subst_scratch); |
| 251 | cache.clear(); |
| 252 | let result = simul_subst_cached(env, body, substs, depth, &mut cache); |
| 253 | env.subst_scratch = cache; |
| 254 | result |
| 255 | } |