Skip to content

CGEN: inline if expression cannot return a closure #26595

@mike-ward

Description

@mike-ward

Describe the bug

// Bug: inline `if` expression cannot return a closure when
// local variables are declared in the `if` block before the
// closure literal, and the else branch returns an existing
// function-pointer variable.
//
// To reproduce the bug:
//   v -d show_bug run examples/bug_inline_if_closure.v
//
// To run with workaround:
//   v run examples/bug_inline_if_closure.v
//
// Expected: compiles and prints "wrapped(tag): 42"
// Actual (with -d show_bug): C compilation error:
//   error: expected ';' after expression
//   error: use of undeclared identifier '_t1'
//
// Workaround: use a mutable variable with conditional assignment
// instead of an inline `if` expression.
module main

import time

struct Event {
mut:
	value int
}

@[heap]
struct Cfg {
	wrap     bool
	delay    time.Duration
	callback fn (&int, mut Event) = unsafe { nil }
}

fn resolve(cfg Cfg) fn (&int, mut Event) {
	user_cb := cfg.callback

	$if show_bug ? {
		// BUG: local declarations inside `if` block before
		// closure literal; else branch returns struct field.
		result := if cfg.wrap && cfg.delay > 0 {
			tag := 'tag'
			dur := cfg.delay
			fn [user_cb, tag, dur] (x &int, mut e Event) {
				_ = dur
				if user_cb != unsafe { nil } {
					user_cb(x, mut e)
				}
				e.value += 1
				println('wrapped(${tag}): ${e.value}')
			}
		} else {
			cfg.callback
		}
		return result
	} $else {
		// WORKAROUND: mut variable with conditional assignment
		mut result := cfg.callback
		if cfg.wrap && cfg.delay > 0 {
			tag := 'tag'
			dur := cfg.delay
			result = fn [user_cb, tag, dur] (x &int, mut e Event) {
				_ = dur
				if user_cb != unsafe { nil } {
					user_cb(x, mut e)
				}
				e.value += 1
				println('wrapped(${tag}): ${e.value}')
			}
		}
		return result
	}
}

fn main() {
	cb := resolve(Cfg{
		wrap:     true
		delay:    2 * time.second
		callback: fn (x &int, mut e Event) {
			e.value = *x
		}
	})
	n := 41
	mut e := Event{}
	cb(&n, mut e)
}

Reproduction Steps

Assume code is in file: bug_inline_if_closure.v

v run bug_inline_if_closure.v runs the workaround, v -d show_bug run bug_inline_if_closure.v triggers the bug.

Expected Behavior

.

Current Behavior

.

Possible Solution

No response

Additional Information/Context

No response

V version

V 0.5.0 b29ac57

Environment details (OS name and version, etc.)

V full version V 0.5.0 213fad4.b29ac57
OS macos, macOS, 26.2, 25C56
Processor 8 cpus, 64bit, little endian, Apple M2
Memory 0.06GB/8GB
V executable /Users/mike/Documents/github/v/v
V last modified time 2026-02-11 21:54:42
V home dir OK, value: /Users/mike/Documents/github/v
VMODULES OK, value: /Users/mike/.vmodules
VTMP OK, value: /tmp/v_501
Current working dir OK, value: /Users/mike/Documents/github/gui/examples
env VFLAGS "-message-limit 5"
env LDFLAGS "-L/opt/homebrew/opt/ruby/lib"
Git version git version 2.53.0
V git status b29ac57
.git/config present true
cc version Apple clang version 17.0.0 (clang-1700.6.3.2)
gcc version Apple clang version 17.0.0 (clang-1700.6.3.2)
clang version Apple clang version 17.0.0 (clang-1700.6.3.2)
tcc version tcc version 0.9.28rc 2026-01-10 HEAD@5ec0e6f8 (AArch64 Darwin)
tcc git status thirdparty-macos-arm64 f995efa3
emcc version N/A
glibc version N/A

Note

You can use the 👍 reaction to increase the issue's priority for developers.

Please note that only the 👍 reaction to the issue itself counts as a vote.
Other reactions and those to comments will not be taken into account.

Metadata

Metadata

Assignees

Labels

BugThis tag is applied to issues which reports bugs.Unit: cgenBugs/feature requests, that are related to the default C generating backend.

Type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions