mirror of
https://github.com/vlang/v.git
synced 2023-08-10 21:13:21 +03:00
cgen: fix nested fn call with result/option propagation (#17738)
This commit is contained in:
parent
dc11f1fe05
commit
ca198ace7d
@ -136,6 +136,7 @@ mut:
|
||||
inside_struct_init bool
|
||||
inside_or_block bool
|
||||
inside_call bool
|
||||
inside_curry_call bool // inside foo()()!, foo()()?, foo()()
|
||||
inside_for_c_stmt bool
|
||||
inside_comptime_for_field bool
|
||||
inside_cast_in_heap int // inside cast to interface type in heap (resolve recursive calls)
|
||||
@ -144,6 +145,7 @@ mut:
|
||||
inside_lambda bool
|
||||
inside_for_in_any_cond bool
|
||||
inside_cinit bool
|
||||
last_tmp_call_var []string
|
||||
loop_depth int
|
||||
ternary_names map[string]string
|
||||
ternary_level_names map[string][]string
|
||||
|
@ -677,8 +677,29 @@ fn (mut g Gen) call_expr(node ast.CallExpr) {
|
||||
g.is_fn_index_call = true
|
||||
g.expr(node.left)
|
||||
g.is_fn_index_call = false
|
||||
} else if node.left is ast.CallExpr && node.name == '' {
|
||||
g.expr(node.left)
|
||||
} else if !g.inside_curry_call && node.left is ast.CallExpr && node.name == '' {
|
||||
if node.or_block.kind == .absent {
|
||||
g.expr(node.left)
|
||||
} else {
|
||||
old_inside_curry_call := g.inside_curry_call
|
||||
g.inside_curry_call = true
|
||||
ret_typ := node.return_type
|
||||
|
||||
line := g.go_before_stmt(0)
|
||||
g.empty_line = true
|
||||
|
||||
tmp_res := g.new_tmp_var()
|
||||
g.write('${g.typ(ret_typ)} ${tmp_res} = ')
|
||||
|
||||
g.last_tmp_call_var << tmp_res
|
||||
g.expr(node.left)
|
||||
g.expr(node)
|
||||
|
||||
g.inside_curry_call = old_inside_curry_call
|
||||
g.write(line)
|
||||
g.write('*(${g.base_type(ret_typ)}*)${tmp_res}.data')
|
||||
return
|
||||
}
|
||||
}
|
||||
old_inside_call := g.inside_call
|
||||
g.inside_call = true
|
||||
@ -689,7 +710,7 @@ fn (mut g Gen) call_expr(node ast.CallExpr) {
|
||||
&& g.pref.gc_mode in [.boehm_full, .boehm_incr, .boehm_full_opt, .boehm_incr_opt]
|
||||
gen_or := node.or_block.kind != .absent // && !g.is_autofree
|
||||
is_gen_or_and_assign_rhs := gen_or && !g.discard_or_result
|
||||
mut cur_line := if is_gen_or_and_assign_rhs || gen_keep_alive { // && !g.is_autofree {
|
||||
mut cur_line := if !g.inside_curry_call && (is_gen_or_and_assign_rhs || gen_keep_alive) { // && !g.is_autofree {
|
||||
// `x := foo() or { ...}`
|
||||
// cut everything that has been generated to prepend option variable creation
|
||||
line := g.go_before_stmt(0)
|
||||
@ -699,7 +720,15 @@ fn (mut g Gen) call_expr(node ast.CallExpr) {
|
||||
''
|
||||
}
|
||||
// g.write('/*EE line="$cur_line"*/')
|
||||
tmp_opt := if gen_or || gen_keep_alive { g.new_tmp_var() } else { '' }
|
||||
tmp_opt := if gen_or || gen_keep_alive {
|
||||
if g.inside_curry_call && g.last_tmp_call_var.len > 0 {
|
||||
g.last_tmp_call_var.pop()
|
||||
} else {
|
||||
g.new_tmp_var()
|
||||
}
|
||||
} else {
|
||||
''
|
||||
}
|
||||
if gen_or || gen_keep_alive {
|
||||
mut ret_typ := node.return_type
|
||||
if g.table.sym(ret_typ).kind == .alias {
|
||||
@ -717,7 +746,7 @@ fn (mut g Gen) call_expr(node ast.CallExpr) {
|
||||
g.writeln('if (${g.infix_left_var_name}) {')
|
||||
g.indent++
|
||||
g.write('${tmp_opt} = ')
|
||||
} else {
|
||||
} else if !g.inside_curry_call {
|
||||
g.write('${styp} ${tmp_opt} = ')
|
||||
if node.left is ast.AnonFn {
|
||||
g.expr(node.left)
|
||||
@ -752,7 +781,7 @@ fn (mut g Gen) call_expr(node ast.CallExpr) {
|
||||
}
|
||||
if unwrapped_typ == ast.void_type {
|
||||
g.write('\n ${cur_line}')
|
||||
} else {
|
||||
} else if !g.inside_curry_call {
|
||||
if !g.inside_const_opt_or_res {
|
||||
g.write('\n ${cur_line} (*(${unwrapped_styp}*)${tmp_opt}.data)')
|
||||
} else {
|
||||
|
@ -2633,11 +2633,29 @@ pub fn (mut p Parser) name_expr() ast.Expr {
|
||||
pos := p.tok.pos()
|
||||
args := p.call_args()
|
||||
p.check(.rpar)
|
||||
|
||||
mut or_kind := ast.OrKind.absent
|
||||
mut or_stmts := []ast.Stmt{}
|
||||
mut or_pos := p.tok.pos()
|
||||
if p.tok.kind in [.not, .question] {
|
||||
or_kind = if p.tok.kind == .not { .propagate_result } else { .propagate_option }
|
||||
p.next()
|
||||
}
|
||||
if p.tok.kind == .key_orelse {
|
||||
// `foo() or {}``
|
||||
or_kind = .block
|
||||
or_stmts, or_pos = p.or_block(.with_err_var)
|
||||
}
|
||||
node = ast.CallExpr{
|
||||
left: node
|
||||
args: args
|
||||
pos: pos
|
||||
scope: p.scope
|
||||
or_block: ast.OrExpr{
|
||||
stmts: or_stmts
|
||||
kind: or_kind
|
||||
pos: or_pos
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
55
vlib/v/tests/call_on_anon_test.v
Normal file
55
vlib/v/tests/call_on_anon_test.v
Normal file
@ -0,0 +1,55 @@
|
||||
fn f1(s string) fn (string) !string {
|
||||
return fn [s] (str string) !string {
|
||||
return s + str
|
||||
}
|
||||
}
|
||||
|
||||
fn f2(s string) fn (string) ?string {
|
||||
return fn [s] (str string) ?string {
|
||||
return s + str
|
||||
}
|
||||
}
|
||||
|
||||
fn f3(s string) fn (string) string {
|
||||
return fn [s] (str string) string {
|
||||
return s + str
|
||||
}
|
||||
}
|
||||
|
||||
fn f4(s string) fn (string) ?string {
|
||||
return fn (str string) ?string {
|
||||
return none
|
||||
}
|
||||
}
|
||||
|
||||
fn f5(s string) fn (string) !string {
|
||||
return fn (str string) !string {
|
||||
return error('test')
|
||||
}
|
||||
}
|
||||
|
||||
fn test_call_nested_anon() {
|
||||
println(main.f1('V')('Lang')!)
|
||||
s1 := main.f1('V')('Lang')!
|
||||
println(s1)
|
||||
s2 := main.f1('V')('Lang') or { 'ErrLang' }
|
||||
println(s2)
|
||||
s3 := main.f2('V')('Lang')?
|
||||
println(s3)
|
||||
s4 := main.f2('V')('Lang') or { 'NoneLang' }
|
||||
println(s4)
|
||||
s := main.f3('V')('Lang')
|
||||
println(s)
|
||||
assert s == 'VLang'
|
||||
assert s1 == 'VLang'
|
||||
assert s2 == 'VLang'
|
||||
assert s3 == 'VLang'
|
||||
assert s4 == 'VLang'
|
||||
|
||||
s5 := main.f4('V')('Lang') or { 'Lang++' }
|
||||
println(s5)
|
||||
assert s5 == 'Lang++'
|
||||
s6 := main.f5('V')('Lang') or { '${err}' }
|
||||
println(s6)
|
||||
assert s6 == 'test'
|
||||
}
|
Loading…
Reference in New Issue
Block a user