Skip to content

Fix #628: cross-module _fn_ret_type_exprs propagation + release v0.0.147#663

Merged
aallan merged 1 commit into
mainfrom
fix-628-cross-module-ret-types
May 12, 2026
Merged

Fix #628: cross-module _fn_ret_type_exprs propagation + release v0.0.147#663
aallan merged 1 commit into
mainfrom
fix-628-cross-module-ret-types

Conversation

@aallan

@aallan aallan commented May 12, 2026

Copy link
Copy Markdown
Owner

Summary

Closes #628.

Root cause

vera/codegen/modules.py's cross-module harvest loop populated _fn_sigs via setdefault but never touched _fn_ret_type_exprs. That registry (added in #614, re-used by #602) stores each FnDecl's full Vera return-type AST so inference walkers can extract Array<T> element types and recognise String-returning calls. Cross-module callees hit _fn_ret_type_exprs.get(name) → None and fell through to the silent-skip path that #602 / #614 had closed in-module.

Fix

One harvest block added in the cross-module loop, alongside the existing _fn_sigs harvest:

for fn_name, ret_te in temp._fn_ret_type_exprs.items():
    self._fn_ret_type_exprs.setdefault(fn_name, ret_te)

Same shape as the _fn_sigs harvest. No collision detection needed — the existing _fn_sigs collision loop above already rejects name clashes.

Regression tests

Two new tests in tests/test_codegen_modules.py::TestCrossModuleCodegen:

  1. test_cross_module_index_of_fncallmake_arr(())[0] returns 1 cross-module
  2. test_cross_module_string_interpolation_of_fncallIO.print("\(make_str(()))!\n") produces "hello!\n" cross-module

Both fail against the pre-fix code path; both pass post-fix.

Release prep (v0.0.147)

  • vera/__init__.py + pyproject.toml + uv.lock: 0.0.146 → 0.0.147
  • CHANGELOG.md: dated [0.0.147] - 2026-05-12 heading + link refs
  • HISTORY.md Stage 12 row + roll-up counter 146 → 147
  • docs/index.html: version tag
  • README.md / TESTING.md / ROADMAP.md: count refreshes

Test plan

  • mypy clean
  • pytest passes (3,801 passed, 14 skipped — was 3,799 + 2 new regression tests)
  • All 86 conformance programs pass
  • All 34 examples pass vera check + vera verify
  • e602 gate: 116 files clean, 5 allowlist matched, 0 stale
  • version-sync, doc-counts: consistent
  • CI green

🤖 Generated with Claude Code

Summary by CodeRabbit

  • Bug Fixes

    • Fixed cross-module return-type inference for imported functions, enabling array indexing and string interpolation to work correctly across modules.
  • Tests

    • Added regression tests validating cross-module function calls with array indexing and string interpolation.

Review Change Stack

…e v0.0.147

Closes #628.

## Root cause

`vera/codegen/modules.py`'s cross-module harvest loop populated
`_fn_sigs` via `setdefault` from each imported temp generator
but never touched `_fn_ret_type_exprs`.  That registry — added
in #614 (for `IndexExpr` element-type inference on
`Array<T>`-returning calls) and re-used in #602 (for `String`
interpolation segments) — stores each user-declared FnDecl's
full Vera return-type AST.  Inference walkers look up
`_fn_ret_type_exprs.get(call.name)` to figure out whether a
function call returns `Array<T>` or `String`.

For cross-module callees that lookup returned `None`, the
walkers fell through to the silent-skip path that #602 / #614
had already closed for in-module callees.  Two failure shapes:

1. `make_arr(())[0]` where `make_arr: @Unit -> @array<Int>` is
   defined in a different module: `_infer_index_element_type`
   returns None → enclosing function dropped via `[E602]` → no
   exported `main` to run.

2. `IO.print("\(make_str(()))\n")` where `make_str: @Unit ->
   @String` is cross-module: interpolation segment falls
   through to `to_string(...)` silent wrapper, the `i32_pair`
   `make_str` return trips `expected i64, found i32` at WASM
   validation.

## Fix

One-block addition in `vera/codegen/modules.py`'s cross-module
harvest loop, alongside the existing `_fn_sigs.setdefault`:

```python
for fn_name, ret_te in temp._fn_ret_type_exprs.items():
    self._fn_ret_type_exprs.setdefault(fn_name, ret_te)
```

Same shape as the `_fn_sigs` harvest above.  `setdefault` so
first-seen wins — no extra collision detection needed since
the existing `_fn_sigs` collision loop above already rejects
name clashes before reaching this code.

## Regression tests

Two new tests added to
`tests/test_codegen_modules.py::TestCrossModuleCodegen`:

1. `test_cross_module_index_of_fncall` — verifies
   `make_arr(())[0]` resolves cross-module and returns 1.
2. `test_cross_module_string_interpolation_of_fncall` —
   verifies `IO.print("\(make_str(()))!\n")` produces
   `"hello!\n"` cross-module.

Both use the existing `_resolved` / `_compile_mod` /
`_run_mod` cross-module harness.  Both fail against the
pre-fix code path; both pass post-fix.

## Release prep (v0.0.147)

Bundled per the ABSOLUTE RULE:

- `vera/__init__.py` + `pyproject.toml` + `uv.lock`: 0.0.146 → 0.0.147
- `CHANGELOG.md`: dated `[0.0.147] - 2026-05-12` heading + link refs
- `HISTORY.md` Stage 12 row: v0.0.147 + roll-up counter 146 → 147
- `docs/index.html`: version tag
- `README.md` / `TESTING.md` / `ROADMAP.md`: count refreshes
  (3,815 tests, 147 releases)

## Verification

- mypy clean (59 source files)
- pytest: 3,801 passed, 14 skipped (was 3,799 + 2 new regression tests)
- All 86 conformance programs pass
- All 34 examples pass `vera check` + `vera verify`
- e602 gate: 116 files clean, 5 allowlist matched, 0 stale
- version-sync, doc-counts: consistent

Refs #614 #602 #626 #628

Co-Authored-By: Claude <noreply@anthropic.invalid>
@coderabbitai

coderabbitai Bot commented May 12, 2026

Copy link
Copy Markdown

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

Run ID: 97aeb5d8-f1d5-4109-ac93-eaa5c46691cf

📥 Commits

Reviewing files that changed from the base of the PR and between d22601e and b660fb2.

⛔ Files ignored due to path filters (5)
  • docs/index.html is excluded by !docs/**
  • docs/index.md is excluded by !docs/**
  • docs/llms-full.txt is excluded by !docs/**
  • docs/llms.txt is excluded by !docs/**
  • uv.lock is excluded by !**/*.lock, !uv.lock
📒 Files selected for processing (9)
  • CHANGELOG.md
  • HISTORY.md
  • README.md
  • ROADMAP.md
  • TESTING.md
  • pyproject.toml
  • tests/test_codegen_modules.py
  • vera/__init__.py
  • vera/codegen/modules.py

📝 Walkthrough

Walkthrough

This PR releases v0.0.147, fixing cross-module return-type inference by propagating _fn_ret_type_exprs in the module import registry. Two regression tests verify array indexing and string interpolation work correctly with imported functions. Version metadata and documentation are updated throughout.

Changes

Cross-module return-type expression propagation and release

Layer / File(s) Summary
Cross-module return-type expression propagation and tests
vera/codegen/modules.py, tests/test_codegen_modules.py
CrossModuleMixin._register_modules now harvests and registers _fn_ret_type_exprs from imported functions via setdefault, ensuring cross-module return-type inference walks have access to the same expression metadata as single-module builds. Regression tests verify array indexing (make_arr(())[0]) and string interpolation (make_str() in IO.print) compile and execute correctly across module boundaries.
Version bumps and release documentation
vera/__init__.py, pyproject.toml, CHANGELOG.md, HISTORY.md, README.md, ROADMAP.md, TESTING.md
Project version incremented from 0.0.146 to 0.0.147 in metadata files. Changelog documents the _fn_ret_type_exprs propagation fix and specific cross-module inference shapes it resolves. History, README, and roadmap metrics are updated to reflect the new release and updated test counts (3,815 tests across 29 files).

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~10 minutes

The core implementation in vera/codegen/modules.py is a straightforward extension of existing cross-module registration: iterate imported _fn_ret_type_exprs and register them via setdefault following the same pattern as _fn_sigs. The regression tests directly exercise the fix with clear setup and assertions. Release housekeeping (version bumps and documentation updates) is mechanical.

Possibly related issues

  • aallan/vera#628: This PR directly implements the fix for cross-module return-type inference, adding _fn_ret_type_exprs propagation to imported functions and the matching regression tests.

Possibly related PRs

  • aallan/vera#627: Addressed return-type expression handling for String and Array i32_pair cases; this PR extends that same fix across module boundaries.
  • aallan/vera#629: Both PRs handle cross-module return-type expression registration and use, addressing the same inference failure path.
  • aallan/vera#625: Originally introduced _fn_ret_type_exprs propagation in single-module codegen; this PR extends the pattern to cross-module imports.

Suggested labels

compiler, tests, docs

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly and concisely summarises the main changes: fixing issue #628 (cross-module _fn_ret_type_exprs propagation) and the accompanying v0.0.147 release.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix-628-cross-module-ret-types

Comment @coderabbitai help to get the list of available commands and usage tips.

@codecov

codecov Bot commented May 12, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 91.05%. Comparing base (d22601e) to head (b660fb2).

Additional details and impacted files
@@           Coverage Diff           @@
##             main     #663   +/-   ##
=======================================
  Coverage   91.05%   91.05%           
=======================================
  Files          60       60           
  Lines       23199    23201    +2     
  Branches      259      259           
=======================================
+ Hits        21123    21125    +2     
  Misses       2069     2069           
  Partials        7        7           
Flag Coverage Δ
javascript 57.36% <ø> (ø)
python 94.84% <100.00%> (+<0.01%) ⬆️

Flags with carried forward coverage won't be shown. Click here to find out more.

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@aallan aallan merged commit 97da640 into main May 12, 2026
23 checks passed
@aallan aallan deleted the fix-628-cross-module-ret-types branch May 12, 2026 17:24
aallan added a commit that referenced this pull request May 12, 2026
PR #663 (v0.0.147) closed #628 but the matching row in
KNOWN_ISSUES.md's Bugs table was missed in that PR's release
prep.  Removed now while #664 is still open.

Other surfaces verified clean for #628 / #660 / #661:
- `ROADMAP.md`: no burn-down rows for these (already swept)
- `vera/README.md`: no mentions
- `spec/*.md`: no mentions
- `examples/*.vera`: no workaround code
- `tests/conformance/*.vera`: no workaround code
- `tests/test_codegen_modules.py` / `tests/test_checker.py`:
  references are the new regression tests for #628 / #660 / #661
  — intentional and kept

Limitation count: 34 → 33.

Refs #628 #660 #661 #664

Co-Authored-By: Claude <noreply@anthropic.invalid>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Cross-module imports don't propagate _fn_ret_type_exprs (#614 / #602 cross-module gap)

1 participant