1
0
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:
Felipe Pena 2023-07-10 15:24:13 -03:00 committed by GitHub
parent 6a8a22891d
commit 6b29d628c3
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 74 additions and 6 deletions

View File

@ -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

View File

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

View File

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

View 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{}
}