Generate recursors for all inductives in a block (lean4lean-style). Detects nested occurrences (à la `ElimNestedInductive`), builds a flat block with auxiliary entries, and generates canonical recursor types for all block members (original + auxiliary).
(
&mut self,
block_id: &KId<M>,
)
| 2211 | // Must be either: |
| 2212 | // 1. A direct block inductive application: `I_k params args` |
| 2213 | // 2. A nested inductive application: `J Ds is` where J is a previously |
| 2214 | // declared inductive and Ds contain block inductives |
| 2215 | let (head, args) = collect_app_spine(&w); |
| 2216 | match head.data() { |
| 2217 | ExprData::Const(id, us, _) if root_addrs.contains(&id.addr) => self |
| 2218 | .check_positive_recursive_application( |
| 2219 | id, us, &args, groups, root_addrs, |
| 2220 | ), |
| 2221 | ExprData::Const(id, us, _) => { |
| 2222 | // Check if this is a nested inductive: head is an inductive type |
| 2223 | // (not in our block) and its params contain block inductives. |
| 2224 | let (n_params, n_indices, lvls, block, ctors) = match self |
| 2225 | .get_const(id)? |
| 2226 | { |
| 2227 | KConst::Indc { params, indices, lvls, block, ctors, .. } => ( |
| 2228 | u64_to_usize(params)?, |
| 2229 | u64_to_usize(indices)?, |
| 2230 | u64_to_usize(lvls)?, |
| 2231 | block.clone(), |
| 2232 | ctors.clone(), |
| 2233 | ), |
| 2234 | _ => { |
| 2235 | return Err(TcError::Other( |
| 2236 | "positivity: not a valid inductive app".into(), |
| 2237 | )); |
| 2238 | }, |
| 2239 | }; |
| 2240 | |
| 2241 | let app_arity = checked_binder_sum::<M>( |
| 2242 | "positivity nested application", |
| 2243 | n_params, |
| 2244 | n_indices, |
| 2245 | )?; |
| 2246 | if args.len() != app_arity || us.len() != lvls { |
| 2247 | return Err(TcError::Other( |
| 2248 | "positivity: malformed nested inductive application".into(), |
| 2249 | )); |
| 2250 | } |
| 2251 | |
| 2252 | // An exact repeated specialization is the recursive edge of an |
| 2253 | // already-validated synthetic auxiliary. A different |
| 2254 | // specialization of the same external family is a distinct |
| 2255 | // auxiliary (for example both `Array (ListItem (Block i b))` |
| 2256 | // and `Array (Block i b)` in `Lean.Doc.Block`). |
| 2257 | let existing_groups: Vec<PositivityGroup<M>> = groups |
| 2258 | .iter() |
| 2259 | .filter(|group| group.addrs.contains(&id.addr)) |
| 2260 | .cloned() |
| 2261 | .collect(); |
| 2262 | for group in &existing_groups { |
| 2263 | if Self::positivity_group_matches( |
| 2264 | group, &id.addr, us, &args, n_params, |
| 2265 | ) { |
| 2266 | for index in args.iter().skip(n_params) { |
| 2267 | if expr_mentions_any_addr(index, root_addrs) { |
| 2268 | return Err(TcError::Other( |
| 2269 | "positivity: recursive occurrence index mentions an active inductive" |
| 2270 | .into(), |