Skip to content

Commit d1b4f65

Browse files
authored
cgen: add deref for aliased reference types using mut captures (#27377)
1 parent 94a763e commit d1b4f65

2 files changed

Lines changed: 39 additions & 2 deletions

File tree

vlib/v/gen/c/fn.v

Lines changed: 19 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1874,7 +1874,8 @@ fn (mut g Gen) gen_anon_fn(mut node ast.AnonFn) {
18741874
if obj := node.decl.scope.parent.find(var.name) {
18751875
if obj is ast.Var {
18761876
is_auto_heap = !obj.is_stack_obj && obj.is_auto_heap
1877-
is_auto_deref_capture = obj.is_auto_deref && !var.is_mut
1877+
is_auto_deref_capture = obj.is_auto_deref
1878+
&& (!var.is_mut || g.table.sym(obj.typ).kind == .alias)
18781879
&& (is_ptr || obj.typ.is_ptr())
18791880
if obj.smartcasts.len > 0 {
18801881
if g.table.type_kind(obj.typ) == .sum_type {
@@ -1917,12 +1918,15 @@ fn (mut g Gen) gen_anon_fn_decl(mut node ast.AnonFn) {
19171918
// so strip one pointer level from the field type.
19181919
// Similarly, when a `mut` parameter (is_auto_deref) is captured
19191920
// without `mut`, the closure stores the dereferenced value.
1921+
// For alias types (`type AppRef = &App`), the deref is needed for
1922+
// `mut` captures too, since the alias adds an indirection level.
19201923
if node.decl.scope != unsafe { nil } && node.decl.scope.parent != unsafe { nil } {
19211924
if scope_var := node.decl.scope.parent.find_var(var.name) {
19221925
if scope_var.is_auto_heap && !scope_var.is_stack_obj
19231926
&& resolved_var_typ.is_ptr() {
19241927
resolved_var_typ = resolved_var_typ.deref()
1925-
} else if scope_var.is_auto_deref && !var.is_mut
1928+
} else if scope_var.is_auto_deref
1929+
&& (!var.is_mut || g.table.sym(scope_var.typ).kind == .alias)
19261930
&& resolved_var_typ.is_ptr() {
19271931
resolved_var_typ = resolved_var_typ.deref()
19281932
}
@@ -7102,6 +7106,19 @@ fn (mut g Gen) ref_or_deref_arg_ex(arg ast.CallArg, expected_type_ ast.Type, lan
71027106
}
71037107
if arg.is_mut && !exp_is_ptr {
71047108
g.write('&/*mut*/')
7109+
} else if arg.is_mut && arg_typ.is_ptr() && expected_type.is_ptr() && exp_sym.kind == .alias
7110+
&& g.table.unaliased_type(expected_type) == arg_typ {
7111+
if arg.expr is ast.PrefixExpr && arg.expr.op == .amp {
7112+
g.write('&(${exp_sym.cname}[]){')
7113+
g.arg_no_auto_deref = true
7114+
g.expr(ast.Expr(arg.expr))
7115+
g.arg_no_auto_deref = false
7116+
g.write('}[0]')
7117+
} else {
7118+
g.write('&/*mut alias*/')
7119+
g.expr(arg.expr)
7120+
}
7121+
return
71057122
} else if arg.is_mut && arg_typ.is_ptr() && expected_type.is_ptr()
71067123
&& g.table.sym(arg_typ).kind == .struct && expected_type == arg_typ.ref() {
71077124
if arg.expr is ast.PrefixExpr && arg.expr.op == .amp {
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
struct App {
2+
mut:
3+
score int
4+
}
5+
6+
type AppRef = &App
7+
8+
fn make_handler(mut app AppRef) fn () {
9+
return fn [mut app] () {
10+
app.score++
11+
}
12+
}
13+
14+
fn test_main() {
15+
mut a := App{}
16+
h := make_handler(mut &a)
17+
assert a.score == 0
18+
h()
19+
assert a.score == 1
20+
}

0 commit comments

Comments
 (0)