fix(mono): recover user-fn return types in generic instantiation inference (#878)#899
Merged
Merged
Conversation
|
Important Review skippedAuto reviews are disabled on base/target branches other than the default branch. Please check the settings in the CodeRabbit UI or the ⚙️ Run configurationConfiguration used: Path: .coderabbit.yaml Review profile: ASSERTIVE Plan: Pro Plus Run ID: You can disable this status message by setting the Use the checkbox below for a quick retry:
✨ Finishing Touches🧪 Generate unit tests (beta)
Comment |
eef7611 to
e8343a9
Compare
…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]>
e8343a9 to
55575a4
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
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
Boolphantom-variable default — droppingmainor 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_contextseededfn_ret_typesfrom WAT sigs (lossy).vera/wasm/inference.py_get_arg_type_info_wasmhad noFnCallbranch, and_infer_fncall_vera_typecollapsed user-fn i32 returns to Bool.Fix
_build_mono_contextnow seeds from each fn's declared return TypeExpr (matching the Per-monomorphization static verification for generic functions #732 verifier's_simple_type_name), WAT collapse kept only as fallback — closes the codegen↔verifier discovery desync.FnCallbranch to_get_arg_type_info_wasm+ declared-return resolution for the ambiguous i32 case. Generic calls are excluded from the user-fn branch (guardif expr.name in self._generic_fn_info: return None) so they fall through to generic resolution exactly as discovery does — composes with fix(mono): cross-module + closure-body generic monomorphization, in verifier↔codegen lockstep (#774, #873) #888.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 conformancech09_generic_infer_user_fn_return. Adversarial review by orchestrator (CodeRabbit at rate limit).