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 is_decl := node.op == .decl_assign
g.assign_op = node.op g.assign_op = node.op
g.inside_assign = true g.inside_assign = true
g.assign_ct_type = 0
defer { defer {
g.assign_op = .unknown g.assign_op = .unknown
g.inside_assign = false g.inside_assign = false
g.assign_ct_type = 0
} }
op := if is_decl { token.Kind.assign } else { node.op } op := if is_decl { token.Kind.assign } else { node.op }
right_expr := node.right[0] 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) var_type = val_type.clear_flag(.option)
} }
left.obj.typ = var_type left.obj.typ = var_type
g.assign_ct_type = var_type
} }
} else if val is ast.ComptimeSelector { } else if val is ast.ComptimeSelector {
key_str := g.get_comptime_selector_key_type(val) key_str := g.get_comptime_selector_key_type(val)
@ -252,11 +255,13 @@ fn (mut g Gen) assign_stmt(node_ ast.AssignStmt) {
} else { } else {
val_type = g.comptime_var_type_map[key_str] or { var_type } val_type = g.comptime_var_type_map[key_str] or { var_type }
} }
g.assign_ct_type = var_type
} }
} else if val is ast.ComptimeCall { } else if val is ast.ComptimeCall {
key_str := '${val.method_name}.return_type' key_str := '${val.method_name}.return_type'
var_type = g.comptime_var_type_map[key_str] or { var_type } var_type = g.comptime_var_type_map[key_str] or { var_type }
left.obj.typ = 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 { } else if is_decl && val is ast.Ident && val.info is ast.IdentVar {
val_info := (val as ast.Ident).info val_info := (val as ast.Ident).info
gen_or = val.or_expr.kind != .absent gen_or = val.or_expr.kind != .absent
@ -271,6 +276,7 @@ fn (mut g Gen) assign_stmt(node_ ast.AssignStmt) {
val_type = var_type val_type = var_type
left.obj.typ = var_type left.obj.typ = var_type
} }
g.assign_ct_type = var_type
} else if val is ast.IndexExpr { } else if val is ast.IndexExpr {
if val.left is ast.Ident && g.is_generic_param_var(val.left) { 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)) 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 var_type = ctyp
val_type = var_type val_type = var_type
left.obj.typ = 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 } 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 { } else if mut left is ast.IndexExpr && val is ast.ComptimeSelector {
key_str := g.get_comptime_selector_key_type(val) key_str := g.get_comptime_selector_key_type(val)
if key_str != '' { if key_str != '' {
val_type = g.comptime_var_type_map[key_str] or { var_type } 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 styp := g.typ(var_type)
mut is_fixed_array_init := false mut is_fixed_array_init := false

View File

@ -155,6 +155,7 @@ mut:
skip_stmt_pos bool // for handling if expressions + autofree (since both prepend C statements) 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 left_is_opt bool // left hand side on assignment is an option
right_is_opt bool // right 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 indent int
empty_line bool empty_line bool
assign_op token.Kind // *=, =, etc (for array_set) 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 ret_typ = unaliased_type
} }
} }
styp := g.typ(ret_typ) mut styp := g.typ(ret_typ)
if gen_or && !is_gen_or_and_assign_rhs { if gen_or && !is_gen_or_and_assign_rhs {
cur_line = g.go_before_stmt(0) cur_line = g.go_before_stmt(0)
} }
@ -767,6 +767,9 @@ fn (mut g Gen) call_expr(node ast.CallExpr) {
g.indent++ g.indent++
g.write('${tmp_opt} = ') g.write('${tmp_opt} = ')
} else if !g.inside_curry_call { } 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} = ') g.write('${styp} ${tmp_opt} = ')
if node.left is ast.AnonFn { if node.left is ast.AnonFn {
g.expr(node.left) 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{}
}