Skip to content

Commit 77e4594

Browse files
authored
cgen: fix different option alias type as fn arg (fix #23086) (#23131)
1 parent 2d314fc commit 77e4594

File tree

3 files changed

+65
-16
lines changed

3 files changed

+65
-16
lines changed

vlib/v/gen/c/assign.v

Lines changed: 42 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,38 @@ fn (mut g Gen) expr_with_opt_or_block(expr ast.Expr, expr_typ ast.Type, var_expr
5454
}
5555
}
5656

57+
// expr_opt_with_alias handles conversion from different option alias type name
58+
fn (mut g Gen) expr_opt_with_alias(expr ast.Expr, expr_typ ast.Type, ret_typ ast.Type, tmp_var string) string {
59+
styp := g.base_type(ret_typ)
60+
61+
line := g.go_before_last_stmt().trim_space()
62+
g.empty_line = true
63+
64+
ret_var := g.new_tmp_var()
65+
ret_styp := g.styp(ret_typ).replace('*', '_ptr')
66+
g.writeln('${ret_styp} ${ret_var} = {0};')
67+
68+
g.write('_option_clone((${option_name}*)')
69+
has_addr := expr !in [ast.Ident, ast.SelectorExpr]
70+
if has_addr {
71+
expr_styp := g.styp(expr_typ).replace('*', '_ptr')
72+
g.write('ADDR(${expr_styp}, ')
73+
} else {
74+
g.write('&')
75+
}
76+
g.expr(expr)
77+
if has_addr {
78+
g.write(')')
79+
}
80+
g.writeln(', (${option_name}*)&${ret_var}, sizeof(${styp}));')
81+
g.write(line)
82+
if g.inside_return {
83+
g.write(' ')
84+
}
85+
g.write(ret_var)
86+
return ret_var
87+
}
88+
5789
// expr_opt_with_cast is used in cast expr when converting compatible option types
5890
// e.g. ?int(?u8(0))
5991
fn (mut g Gen) expr_opt_with_cast(expr ast.Expr, expr_typ ast.Type, ret_typ ast.Type) string {
@@ -64,22 +96,17 @@ fn (mut g Gen) expr_opt_with_cast(expr ast.Expr, expr_typ ast.Type, ret_typ ast.
6496
if expr_typ.idx() == ret_typ.idx() && g.table.sym(expr_typ).kind != .alias {
6597
return g.expr_with_opt(expr, expr_typ, ret_typ)
6698
} else {
67-
past := g.past_tmp_var_new()
68-
defer {
69-
g.past_tmp_var_done(past)
70-
}
71-
styp := g.base_type(ret_typ)
72-
decl_styp := g.styp(ret_typ).replace('*', '_ptr')
73-
g.writeln('${decl_styp} ${past.tmp_var};')
74-
is_none := expr is ast.CastExpr && expr.expr is ast.None
7599
if expr is ast.CallExpr && expr.return_type.has_flag(.option) {
76-
tmp_var := g.new_tmp_var()
77-
ret_styp := g.styp(expr.return_type).replace('*', '_ptr')
78-
g.write('${ret_styp} ${tmp_var} = ')
79-
g.expr(expr)
80-
g.writeln(';')
81-
g.writeln('_option_clone(&${tmp_var}, (${option_name}*)(&${past.tmp_var}), sizeof(${styp}));')
100+
return g.expr_opt_with_alias(expr, expr_typ, ret_typ, '')
82101
} else {
102+
past := g.past_tmp_var_new()
103+
defer {
104+
g.past_tmp_var_done(past)
105+
}
106+
styp := g.base_type(ret_typ)
107+
decl_styp := g.styp(ret_typ).replace('*', '_ptr')
108+
g.writeln('${decl_styp} ${past.tmp_var};')
109+
is_none := expr is ast.CastExpr && expr.expr is ast.None
83110
if is_none {
84111
g.write('_option_none(&(${styp}[]) {')
85112
} else {
@@ -96,8 +123,8 @@ fn (mut g Gen) expr_opt_with_cast(expr ast.Expr, expr_typ ast.Type, ret_typ ast.
96123
g.inside_opt_or_res = old_inside_opt_or_res
97124
}
98125
g.writeln(' }, (${option_name}*)(&${past.tmp_var}), sizeof(${styp}));')
126+
return past.tmp_var
99127
}
100-
return past.tmp_var
101128
}
102129
}
103130

vlib/v/gen/c/fn.v

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2946,7 +2946,11 @@ fn (mut g Gen) ref_or_deref_arg(arg ast.CallArg, expected_type ast.Type, lang as
29462946
g.write('->val')
29472947
return
29482948
} else if expected_type.has_flag(.option) {
2949-
g.expr_with_opt(arg.expr, arg_typ, expected_type)
2949+
if arg_sym.info is ast.Alias && expected_type != arg_typ {
2950+
g.expr_opt_with_alias(arg.expr, arg_typ, expected_type, '')
2951+
} else {
2952+
g.expr_with_opt(arg.expr, arg_typ, expected_type)
2953+
}
29502954
return
29512955
} else if arg.expr is ast.ArrayInit {
29522956
if arg.expr.is_fixed {
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
import time
2+
3+
struct Foo[T] {
4+
pub:
5+
value ?T
6+
}
7+
8+
fn t(x ?i64) i64 {
9+
return x or { -1 }
10+
}
11+
12+
fn test_main() {
13+
bar := Foo[time.Duration]{
14+
value: time.Duration(0)
15+
}
16+
17+
assert t(bar.value) == 0
18+
}

0 commit comments

Comments
 (0)