Skip to content

Cyclic type aliases crash codegen with RecursionError instead of clean E1xx diagnostic #648

@aallan

Description

@aallan

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:

  1. After _register_all finishes in vera/checker/registration.py, walk every alias's AST type_expr chain.
  2. Detect cycles using a seen set per alias.
  3. 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

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions