Fix #628: cross-module _fn_ret_type_exprs propagation + release v0.0.147#663
Conversation
…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>
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: Path: .coderabbit.yaml Review profile: ASSERTIVE Plan: Pro Run ID: ⛔ Files ignored due to path filters (5)
📒 Files selected for processing (9)
📝 WalkthroughWalkthroughThis PR releases v0.0.147, fixing cross-module return-type inference by propagating ChangesCross-module return-type expression propagation and release
Estimated code review effort🎯 2 (Simple) | ⏱️ ~10 minutes The core implementation in Possibly related issues
Possibly related PRs
Suggested labels
🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
Comment |
Codecov Report✅ All modified and coverable lines are covered by tests. 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
Flags with carried forward coverage won't be shown. Click here to find out more. ☔ View full report in Codecov by Sentry. 🚀 New features to boost your workflow:
|
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>
Summary
_fn_ret_type_exprsalongside_fn_sigs. Fixes two failure shapes (make_arr(())[0]IndexExpr-of-FnCall +IO.print("\(make_str(()))\n")String interpolation) for cross-module callees that worked in-module since Closure capturing data ADT and passing it to a function call inside body emits malformed WASM #614 / String-returning function call in string interpolation produces invalid WASM (i64/i32 mismatch) #602.Closes #628.
Root cause
vera/codegen/modules.py's cross-module harvest loop populated_fn_sigsviasetdefaultbut 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 extractArray<T>element types and recogniseString-returning calls. Cross-module callees hit_fn_ret_type_exprs.get(name) → Noneand 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_sigsharvest:Same shape as the
_fn_sigsharvest. No collision detection needed — the existing_fn_sigscollision loop above already rejects name clashes.Regression tests
Two new tests in
tests/test_codegen_modules.py::TestCrossModuleCodegen:test_cross_module_index_of_fncall—make_arr(())[0]returns 1 cross-moduletest_cross_module_string_interpolation_of_fncall—IO.print("\(make_str(()))!\n")produces"hello!\n"cross-moduleBoth 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.147CHANGELOG.md: dated[0.0.147] - 2026-05-12heading + link refsHISTORY.mdStage 12 row + roll-up counter 146 → 147docs/index.html: version tagREADME.md/TESTING.md/ROADMAP.md: count refreshesTest plan
vera check+vera verify🤖 Generated with Claude Code
Summary by CodeRabbit
Bug Fixes
Tests