mirror of
https://github.com/vlang/v.git
synced 2023-08-10 21:13:21 +03:00
cgen: fix generated code for returning generic result/option to comptime var (#18834)
This commit is contained in:
parent
6a8a22891d
commit
6b29d628c3
@ -127,9 +127,11 @@ fn (mut g Gen) assign_stmt(node_ ast.AssignStmt) {
|
||||
is_decl := node.op == .decl_assign
|
||||
g.assign_op = node.op
|
||||
g.inside_assign = true
|
||||
g.assign_ct_type = 0
|
||||
defer {
|
||||
g.assign_op = .unknown
|
||||
g.inside_assign = false
|
||||
g.assign_ct_type = 0
|
||||
}
|
||||
op := if is_decl { token.Kind.assign } else { node.op }
|
||||
right_expr := node.right[0]
|
||||
@ -241,6 +243,7 @@ fn (mut g Gen) assign_stmt(node_ ast.AssignStmt) {
|
||||
var_type = val_type.clear_flag(.option)
|
||||
}
|
||||
left.obj.typ = var_type
|
||||
g.assign_ct_type = var_type
|
||||
}
|
||||
} else if val is ast.ComptimeSelector {
|
||||
key_str := g.get_comptime_selector_key_type(val)
|
||||
@ -252,11 +255,13 @@ fn (mut g Gen) assign_stmt(node_ ast.AssignStmt) {
|
||||
} else {
|
||||
val_type = g.comptime_var_type_map[key_str] or { var_type }
|
||||
}
|
||||
g.assign_ct_type = var_type
|
||||
}
|
||||
} else if val is ast.ComptimeCall {
|
||||
key_str := '${val.method_name}.return_type'
|
||||
var_type = g.comptime_var_type_map[key_str] or { var_type }
|
||||
left.obj.typ = var_type
|
||||
g.assign_ct_type = var_type
|
||||
} else if is_decl && val is ast.Ident && val.info is ast.IdentVar {
|
||||
val_info := (val as ast.Ident).info
|
||||
gen_or = val.or_expr.kind != .absent
|
||||
@ -271,6 +276,7 @@ fn (mut g Gen) assign_stmt(node_ ast.AssignStmt) {
|
||||
val_type = var_type
|
||||
left.obj.typ = var_type
|
||||
}
|
||||
g.assign_ct_type = var_type
|
||||
} else if val is ast.IndexExpr {
|
||||
if val.left is ast.Ident && g.is_generic_param_var(val.left) {
|
||||
ctyp := g.unwrap_generic(g.get_gn_var_type(val.left as ast.Ident))
|
||||
@ -278,6 +284,7 @@ fn (mut g Gen) assign_stmt(node_ ast.AssignStmt) {
|
||||
var_type = ctyp
|
||||
val_type = var_type
|
||||
left.obj.typ = var_type
|
||||
g.assign_ct_type = var_type
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -294,11 +301,13 @@ fn (mut g Gen) assign_stmt(node_ ast.AssignStmt) {
|
||||
val_type = g.comptime_var_type_map[key_str_right] or { var_type }
|
||||
}
|
||||
}
|
||||
g.assign_ct_type = var_type
|
||||
} else if mut left is ast.IndexExpr && val is ast.ComptimeSelector {
|
||||
key_str := g.get_comptime_selector_key_type(val)
|
||||
if key_str != '' {
|
||||
val_type = g.comptime_var_type_map[key_str] or { var_type }
|
||||
}
|
||||
g.assign_ct_type = val_type
|
||||
}
|
||||
mut styp := g.typ(var_type)
|
||||
mut is_fixed_array_init := false
|
||||
|
@ -150,11 +150,12 @@ mut:
|
||||
loop_depth int
|
||||
ternary_names map[string]string
|
||||
ternary_level_names map[string][]string
|
||||
arraymap_set_pos int // map or array set value position
|
||||
stmt_path_pos []int // positions of each statement start, for inserting C statements before the current statement
|
||||
skip_stmt_pos bool // for handling if expressions + autofree (since both prepend C statements)
|
||||
left_is_opt bool // left hand side on assignment is an option
|
||||
right_is_opt bool // right hand side on assignment is an option
|
||||
arraymap_set_pos int // map or array set value position
|
||||
stmt_path_pos []int // positions of each statement start, for inserting C statements before the current statement
|
||||
skip_stmt_pos bool // for handling if expressions + autofree (since both prepend C statements)
|
||||
left_is_opt bool // left hand side on assignment is an option
|
||||
right_is_opt bool // right hand side on assignment is an option
|
||||
assign_ct_type ast.Type // left hand side resolved comptime type
|
||||
indent int
|
||||
empty_line bool
|
||||
assign_op token.Kind // *=, =, etc (for array_set)
|
||||
|
@ -757,7 +757,7 @@ fn (mut g Gen) call_expr(node ast.CallExpr) {
|
||||
ret_typ = unaliased_type
|
||||
}
|
||||
}
|
||||
styp := g.typ(ret_typ)
|
||||
mut styp := g.typ(ret_typ)
|
||||
if gen_or && !is_gen_or_and_assign_rhs {
|
||||
cur_line = g.go_before_stmt(0)
|
||||
}
|
||||
@ -767,6 +767,9 @@ fn (mut g Gen) call_expr(node ast.CallExpr) {
|
||||
g.indent++
|
||||
g.write('${tmp_opt} = ')
|
||||
} else if !g.inside_curry_call {
|
||||
if g.assign_ct_type != 0 && node.or_block.kind in [.propagate_option, .propagate_result] {
|
||||
styp = g.typ(g.assign_ct_type.derive(ret_typ))
|
||||
}
|
||||
g.write('${styp} ${tmp_opt} = ')
|
||||
if node.left is ast.AnonFn {
|
||||
g.expr(node.left)
|
||||
|
55
vlib/v/tests/option_generic_return_test.v
Normal file
55
vlib/v/tests/option_generic_return_test.v
Normal file
@ -0,0 +1,55 @@
|
||||
fn opt_parse[T]() ?T {
|
||||
mut cfg := T{}
|
||||
opt_set_val(mut cfg)?
|
||||
return cfg
|
||||
}
|
||||
|
||||
fn opt_set_val[T](mut cfg T) ? {
|
||||
$for field in T.fields {
|
||||
$if field.is_array {
|
||||
mut arr := cfg.$(field.name)
|
||||
cfg.$(field.name) = opt_add_val(mut arr)?
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn opt_add_val[T](mut arr []T) ?[]T {
|
||||
return arr
|
||||
}
|
||||
|
||||
fn res_parse[T]() !T {
|
||||
mut cfg := T{}
|
||||
res_set_val(mut cfg)!
|
||||
return cfg
|
||||
}
|
||||
|
||||
fn res_set_val[T](mut cfg T) ! {
|
||||
$for field in T.fields {
|
||||
$if field.is_array {
|
||||
mut arr := cfg.$(field.name)
|
||||
cfg.$(field.name) = res_add_val(mut arr)!
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn res_add_val[T](mut arr []T) ![]T {
|
||||
return arr
|
||||
}
|
||||
|
||||
struct Strings {
|
||||
val []string
|
||||
}
|
||||
|
||||
struct Ints {
|
||||
val []int
|
||||
}
|
||||
|
||||
fn test_option() {
|
||||
assert dump(opt_parse[Strings]()?) == Strings{}
|
||||
assert dump(opt_parse[Ints]()?) == Ints{}
|
||||
}
|
||||
|
||||
fn test_result() {
|
||||
assert dump(res_parse[Strings]()!) == Strings{}
|
||||
assert dump(res_parse[Ints]()!) == Ints{}
|
||||
}
|
Loading…
Reference in New Issue
Block a user