Origin: Discovered while implementing #633.
The bug
A pair of mutually-recursive type aliases:
type A = B;
type B = A;
public fn id(@A -> @A)
requires(true)
ensures(true)
effects(pure)
{
@A.0
}
Passes vera check cleanly, then crashes vera compile with:
RecursionError at vera/codegen/core.py:628 in _type_expr_to_wasm_type
Why
_register_alias in vera/checker/registration.py resolves aliases one at a time. When type A = B is processed, B is not yet registered, so it resolves to a placeholder AdtType("B", ()). Then type B = A finds A and chains to it. No cycle is observable in the resolved types because the unresolved-import fallback masks it.
But codegen stores the raw AST type_expr (vera/codegen/core.py:388 and registration.py:26), and _type_expr_to_wasm_type chases the alias chain through the AST, where the cycle is preserved. Hence the recursion explosion.
Recommended fix
A post-registration pass in the type checker:
- After
_register_all finishes in vera/checker/registration.py, walk every alias's AST type_expr chain.
- Detect cycles using a
seen set per alias.
- On detection, emit
[E132] Cyclic type alias with location, rationale, and fix suggestion.
This makes the codegen defensive cycle guards (added in #633) belt-and-braces.
Acceptance criteria
- Cyclic alias program produces
[E132] from vera check (not from vera compile).
- Diagnostic includes location of the originating declaration.
- A regression test exists in
tests/test_checker_*.py (or wherever alias tests live).
Pairs with
Origin: Discovered while implementing #633.
The bug
A pair of mutually-recursive type aliases:
Passes
vera checkcleanly, then crashesvera compilewith:Why
_register_aliasinvera/checker/registration.pyresolves aliases one at a time. Whentype A = Bis processed,Bis not yet registered, so it resolves to a placeholderAdtType("B", ()). Thentype B = AfindsAand chains to it. No cycle is observable in the resolved types because the unresolved-import fallback masks it.But codegen stores the raw AST
type_expr(vera/codegen/core.py:388andregistration.py:26), and_type_expr_to_wasm_typechases the alias chain through the AST, where the cycle is preserved. Hence the recursion explosion.Recommended fix
A post-registration pass in the type checker:
_register_allfinishes invera/checker/registration.py, walk every alias's ASTtype_exprchain.seenset per alias.[E132] Cyclic type aliaswith location, rationale, and fix suggestion.This makes the codegen defensive cycle guards (added in #633) belt-and-braces.
Acceptance criteria
[E132]fromvera check(not fromvera compile).tests/test_checker_*.py(or wherever alias tests live).Pairs with