Skip to content

checker,gen: fix generic type inference from a callback with Result return type#27679

Open
rilaaax wants to merge 1 commit into
vlang:masterfrom
rilaaax:fix-generic-fn-callback-result-return-inference
Open

checker,gen: fix generic type inference from a callback with Result return type#27679
rilaaax wants to merge 1 commit into
vlang:masterfrom
rilaaax:fix-generic-fn-callback-result-return-inference

Conversation

@rilaaax

@rilaaax rilaaax commented Jul 6, 2026

Copy link
Copy Markdown
Contributor

Fixes #27108

Problem

fn run[T](cb fn () !T) !T {
	mut r := T{}
	r = cb()!
	return r
}

fn main() {
	cb := fn () !int {
		return -1
	}
	run(cb)!
}

fails with a C compilation error:

error: initializing '_result_int' (aka 'struct _result_int') with an expression of incompatible type 'int'

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).

A generic function with a plain (non-callback) parameter and a !T return already works fine.
A callback parameter with a plain (non-Result) return already works fine too.

Note: the wrong inference happens unconditionally whenever a generic function takes a callback parameter typed fn () !T — it isn't specific to using T{} 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-initializing T{}; without that, the mismatch can go unnoticed since the code still happens to work despite T being wrong internally.

Cause

V infers T here 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 .result flag first. So for a closure returning !int, T got inferred as !int (the Result-wrapped type) instead of int. This produced two inconsistent monomorphized versions of the generic function — one correctly named/typed for T=int, and a second, wrongly named for T=!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

@rilaaax rilaaax force-pushed the fix-generic-fn-callback-result-return-inference branch from 80a5506 to 36250cf Compare July 9, 2026 13:38
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.

C error on returning generic anon fn result

1 participant