Skip to content

fix(mono): recover user-fn return types in generic instantiation inference (#878)#899

Merged
aallan merged 1 commit into
release/v0.1.0from
fix/878-mono-inference-return-types
Jul 3, 2026
Merged

fix(mono): recover user-fn return types in generic instantiation inference (#878)#899
aallan merged 1 commit into
release/v0.1.0from
fix/878-mono-inference-return-types

Conversation

@aallan

@aallan aallan commented Jul 3, 2026

Copy link
Copy Markdown
Owner

Closes #878 · targets release/v0.1.0. Rebased onto the post-#772 base; source overlaps with #772 auto-merged in disjoint regions (verified #772's Box soundness gate + #732 differential still pass with #878 reverted).

Problem

Mono instantiation inference missed user-fn return types in argument position: when a generic's type argument must be inferred from a user function's return value used as an argument, inference fell back to the Bool phantom-variable default — dropping main or emitting calls to skipped functions on a check-green program.

Root cause

The lossy WAT collapse i32 → "Bool" applied to user-fn returns (Decimal/ADT/Option/Result handles are all i32 = the phantom default). Two sites:

  • vera/codegen/monomorphize.py _build_mono_context seeded fn_ret_types from WAT sigs (lossy).
  • vera/wasm/inference.py _get_arg_type_info_wasm had no FnCall branch, and _infer_fncall_vera_type collapsed user-fn i32 returns to Bool.

Fix

Evidence

RED tests deliberately use Decimal returns (output 0.333…) that cannot coincide with the Bool phantom default (1/0) — the exact trap CLAUDE.md warns about. Mutation-killed (each change independently load-bearing). #732 differential green; #772/#888/#867/#891 regression suites green. Full suite 6217 passed, 124 conformance. New conformance ch09_generic_infer_user_fn_return. Adversarial review by orchestrator (CodeRabbit at rate limit).

@coderabbitai

coderabbitai Bot commented Jul 3, 2026

Copy link
Copy Markdown

Important

Review skipped

Auto reviews are disabled on base/target branches other than the default branch.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 60df161d-44df-4c53-94e2-86e4492f0c3c

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/878-mono-inference-return-types

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

@aallan aallan force-pushed the fix/878-mono-inference-return-types branch from eef7611 to e8343a9 Compare July 3, 2026 14:04
…rence (#878)

A generic whose type argument must be inferred from a user-fn call's return
type in argument position monomorphized to the Bool phantom-var default: on a
check-green program `vera run` emitted a call to a `$Bool` clone Pass 1.5 never
produced, so the caller (often `main`) was skipped and dropped from the exports
("No exported functions to call"), or a private helper left a dangling `call`
that failed WAT validation.

Root cause is the lossy WAT collapse `i32 -> "Bool"` (a Decimal handle, an ADT,
and an Option/Result pointer are all i32 — the same value as the phantom
default) applied to user-fn returns on both the discovery and the body-emission
sides:

- Discovery (vera/codegen/monomorphize.py): `_build_mono_context` seeded the
  shared `fn_ret_types` from WAT signatures, so a generic bound solely by a
  user-fn return was discovered as `$Bool` while the #732 verifier discovered
  the precise type — a differential desync masked only by identity clone
  bodies. Now seeds from each fn's declared return TypeExpr, exactly as the
  verifier does, with the WAT collapse kept only as a fallback.
- Body-emission (vera/wasm/inference.py): `_get_arg_type_info_wasm` had no
  FnCall branch, so a parameterized return in `Option<VeraT>` position bound
  nothing; and a user-fn call in bare `@VeraT` position collapsed i32 to Bool.
  It now mirrors discovery's FnCall branch (shared _BUILTIN_PARAMETERIZED_RETURNS
  plus a non-generic-user-fn parameterized case) and consults the declared
  return TypeExpr for the ambiguous i32 case. GENERIC calls are excluded from
  the user-fn branch (their declared return is over the callee's own type vars,
  not concrete types) so they fall through to generic-return resolution exactly
  as discovery does — keeping the two consultors in lockstep.

Test values are deliberately Decimal returns (`0.3333...`) that cannot coincide
with the Bool default (1/0), the exact Bool-coincidence trap CLAUDE.md warns
about. New run-level conformance program ch09_generic_infer_user_fn_return (suite
123) plus three regression tests (crash-via-IO, WAT-mangle discriminator,
discovery-vs-verifier differential); each change is independently mutation-
validated. Does not weaken #888's cross-module/closure discovery.

Co-Authored-By: Claude <[email protected]>
@aallan aallan force-pushed the fix/878-mono-inference-return-types branch from e8343a9 to 55575a4 Compare July 3, 2026 14:35
@aallan aallan merged commit 6f1ea51 into release/v0.1.0 Jul 3, 2026
1 check passed
@aallan aallan deleted the fix/878-mono-inference-return-types branch July 3, 2026 14:42
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.

1 participant