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_struct_init bool
|
||||||
inside_or_block bool
|
inside_or_block bool
|
||||||
inside_call bool
|
inside_call bool
|
||||||
|
inside_curry_call bool // inside foo()()!, foo()()?, foo()()
|
||||||
inside_for_c_stmt bool
|
inside_for_c_stmt bool
|
||||||
inside_comptime_for_field bool
|
inside_comptime_for_field bool
|
||||||
inside_cast_in_heap int // inside cast to interface type in heap (resolve recursive calls)
|
inside_cast_in_heap int // inside cast to interface type in heap (resolve recursive calls)
|
||||||
@ -144,6 +145,7 @@ mut:
|
|||||||
inside_lambda bool
|
inside_lambda bool
|
||||||
inside_for_in_any_cond bool
|
inside_for_in_any_cond bool
|
||||||
inside_cinit bool
|
inside_cinit bool
|
||||||
|
last_tmp_call_var []string
|
||||||
loop_depth int
|
loop_depth int
|
||||||
ternary_names map[string]string
|
ternary_names map[string]string
|
||||||
ternary_level_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.is_fn_index_call = true
|
||||||
g.expr(node.left)
|
g.expr(node.left)
|
||||||
g.is_fn_index_call = false
|
g.is_fn_index_call = false
|
||||||
} else if node.left is ast.CallExpr && node.name == '' {
|
} else if !g.inside_curry_call && node.left is ast.CallExpr && node.name == '' {
|
||||||
|
if node.or_block.kind == .absent {
|
||||||
g.expr(node.left)
|
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
|
old_inside_call := g.inside_call
|
||||||
g.inside_call = true
|
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]
|
&& 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
|
gen_or := node.or_block.kind != .absent // && !g.is_autofree
|
||||||
is_gen_or_and_assign_rhs := gen_or && !g.discard_or_result
|
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 { ...}`
|
// `x := foo() or { ...}`
|
||||||
// cut everything that has been generated to prepend option variable creation
|
// cut everything that has been generated to prepend option variable creation
|
||||||
line := g.go_before_stmt(0)
|
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"*/')
|
// 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 {
|
if gen_or || gen_keep_alive {
|
||||||
mut ret_typ := node.return_type
|
mut ret_typ := node.return_type
|
||||||
if g.table.sym(ret_typ).kind == .alias {
|
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.writeln('if (${g.infix_left_var_name}) {')
|
||||||
g.indent++
|
g.indent++
|
||||||
g.write('${tmp_opt} = ')
|
g.write('${tmp_opt} = ')
|
||||||
} else {
|
} else if !g.inside_curry_call {
|
||||||
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)
|
||||||
@ -752,7 +781,7 @@ fn (mut g Gen) call_expr(node ast.CallExpr) {
|
|||||||
}
|
}
|
||||||
if unwrapped_typ == ast.void_type {
|
if unwrapped_typ == ast.void_type {
|
||||||
g.write('\n ${cur_line}')
|
g.write('\n ${cur_line}')
|
||||||
} else {
|
} else if !g.inside_curry_call {
|
||||||
if !g.inside_const_opt_or_res {
|
if !g.inside_const_opt_or_res {
|
||||||
g.write('\n ${cur_line} (*(${unwrapped_styp}*)${tmp_opt}.data)')
|
g.write('\n ${cur_line} (*(${unwrapped_styp}*)${tmp_opt}.data)')
|
||||||
} else {
|
} else {
|
||||||
|
@ -2633,11 +2633,29 @@ pub fn (mut p Parser) name_expr() ast.Expr {
|
|||||||
pos := p.tok.pos()
|
pos := p.tok.pos()
|
||||||
args := p.call_args()
|
args := p.call_args()
|
||||||
p.check(.rpar)
|
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{
|
node = ast.CallExpr{
|
||||||
left: node
|
left: node
|
||||||
args: args
|
args: args
|
||||||
pos: pos
|
pos: pos
|
||||||
scope: p.scope
|
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…
x
Reference in New Issue
Block a user