checker,gen: fix generic type inference from a callback with Result return type#27679
checker,gen: fix generic type inference from a callback with Result return type#27679rilaaax wants to merge 1 commit into
Conversation
80a5506 to
36250cf
Compare
|
@codex review |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 36250cf2d2
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| if param_sym.info.func.return_type.has_flag(.generic) | ||
| && c.table.sym(param_sym.info.func.return_type).name == gt_name { | ||
| typ = arg_sym.info.func.return_type | ||
| typ = arg_sym.info.func.return_type.clear_option_and_result() |
There was a problem hiding this comment.
Do not strip plain generic callback returns
This unwrap runs for every callback return that binds a generic, but it is only correct when the formal return type is itself ?T/!T. For an API such as fn use[T](cb fn () T) T, callers can legitimately pass a fn () !int/fn () ?int and infer T as the option/result type; this line now infers T=int, so the call is checked/generated as fn () int instead of preserving T=!int. Please condition the unwrap on the formal return carrying option/result flags, and mirror the same guard in the cgen duplicate.
Useful? React with 👍 / 👎.
Fixes #27108
Problem
fails with a C compilation error:
The issue is specific to the combination of: a generic parameter that is itself a callback (
fn () !T), where the callback's return type carries the generic marker inside a Result (!T).Note: the wrong inference happens unconditionally whenever a generic function takes a callback parameter typed
fn () !T— it isn't specific to usingT{}in the body. It only surfaces as a visible compile error when the body does something that needs T's plain (unwrapped) C representation, like zero-initializingT{}; without that, the mismatch can go unnoticed since the code still happens to work despite T being wrong internally.Cause
V infers
There by structurally comparing the parameter's function type against the argument's actual function type. Two separate places do this comparison (once in the checker, once in a duplicate implementation in cgen), and in both, the branch that extracts the concrete type from the return position took the argument's return type as-is, without stripping its.resultflag first. So for a closure returning!int,Tgot inferred as!int(the Result-wrapped type) instead ofint. This produced two inconsistent monomorphized versions of the generic function — one correctly named/typed forT=int, and a second, wrongly named forT=!int, which is the one actually invoked at the call site, leading to invalid C.Fix
Strip the option/result flags before binding the inferred type, in both places, using the existing
clear_option_and_result()helper (already used a few lines above for the analogous case where the parameter itself, rather than just its return type, is Result-wrapped).Test
Regression test added.
NB: credits to Claude