Build the `B → A` rename map for an alpha-collapsed mutual block. When two primary inductives (e.g. `A` and `B`) compile to the same canonical address, the original Lean env still emits separate `B`/`B.below`/`B.rec`/`B.b`/... declarations whose bodies reference `A`/`B` as distinct names. The decompiled (canonical) form, however, has those references collapsed onto a single representative — typic
( all: &[Name], env: &Env, stt: &ix_compile::compile::CompileState, )
| 260 | /// representatives so [`const_alpha_eq_with_perm`] can compare the two |
| 261 | /// sides structurally. |
| 262 | fn build_collapse_const_map( |
| 263 | all: &[Name], |
| 264 | env: &Env, |
| 265 | stt: &ix_compile::compile::CompileState, |
| 266 | ) -> FxHashMap<Name, Name> { |
| 267 | use ix_common::env::ConstantInfo as LeanCI; |
| 268 | let mut map: FxHashMap<Name, Name> = FxHashMap::default(); |
| 269 | // Group primary members by canonical address; the first member with a |
| 270 | // given address is the representative. |
| 271 | let mut rep_by_addr: FxHashMap<ix_common::address::Address, &Name> = |
| 272 | FxHashMap::default(); |
| 273 | for member in all { |
| 274 | let Some(addr) = stt.resolve_addr(member) else { |
| 275 | continue; |
| 276 | }; |
| 277 | rep_by_addr.entry(addr).or_insert(member); |
| 278 | } |
| 279 | for member in all { |
| 280 | let Some(addr) = stt.resolve_addr(member) else { |
| 281 | continue; |
| 282 | }; |
| 283 | let Some(&rep) = rep_by_addr.get(&addr) else { |
| 284 | continue; |
| 285 | }; |
| 286 | if rep == member { |
| 287 | continue; |
| 288 | } |
| 289 | map.insert(member.clone(), rep.clone()); |
| 290 | // Derived names: `.rec`, `.below`, `.brecOn`, `.brecOn.go`, |
| 291 | // `.brecOn.eq`, `.casesOn`, `.recOn`. |
| 292 | for suffix in ["rec", "below", "brecOn", "casesOn", "recOn"] { |
| 293 | let from = Name::str(member.clone(), suffix.to_string()); |
| 294 | let to = Name::str(rep.clone(), suffix.to_string()); |
| 295 | map.insert(from, to); |
| 296 | } |
| 297 | for suffix in ["go", "eq"] { |
| 298 | let from = Name::str( |
| 299 | Name::str(member.clone(), "brecOn".to_string()), |
| 300 | suffix.to_string(), |
| 301 | ); |
| 302 | let to = Name::str( |
| 303 | Name::str(rep.clone(), "brecOn".to_string()), |
| 304 | suffix.to_string(), |
| 305 | ); |
| 306 | map.insert(from, to); |
| 307 | } |
| 308 | // Constructors: positional mapping. Both members are alpha-collapsed, |
| 309 | // so they have the same number of constructors in the same order. |
| 310 | if let (Some(LeanCI::InductInfo(m_ind)), Some(LeanCI::InductInfo(r_ind))) = |
| 311 | (env.get(member).as_deref(), env.get(rep).as_deref()) |
| 312 | && m_ind.ctors.len() == r_ind.ctors.len() |
| 313 | { |
| 314 | for (m_ctor, r_ctor) in m_ind.ctors.iter().zip(r_ind.ctors.iter()) { |
| 315 | if m_ctor != r_ctor { |
| 316 | map.insert(m_ctor.clone(), r_ctor.clone()); |
| 317 | } |
| 318 | } |
| 319 | } |
no test coverage detected