Skip to content

Commit

Permalink
checker, cgen: fix codegen for option fntype used in a match (fix #22278
Browse files Browse the repository at this point in the history
) (#22280)
  • Loading branch information
felipensp authored Sep 22, 2024
1 parent f98e9d5 commit 4f39bac
Show file tree
Hide file tree
Showing 6 changed files with 71 additions and 5 deletions.
12 changes: 12 additions & 0 deletions vlib/v/checker/checker.v
Original file line number Diff line number Diff line change
Expand Up @@ -1197,6 +1197,18 @@ fn (mut c Checker) check_expr_option_or_result_call(expr ast.Expr, ret_type ast.
expr_ret_type = unaliased_ret_type
}
}
// var with option function
if expr.is_fn_var && expr.fn_var_type.has_option_or_result()
&& expr.or_block.kind == .absent {
ret_sym := c.table.sym(expr.fn_var_type)
if expr.fn_var_type.has_flag(.option) {
c.error('type `?${ret_sym.name}` is an Option, it must be unwrapped first',
expr.pos)
} else {
c.error('type `?${ret_sym.name}` is an Result, it must be unwrapped first',
expr.pos)
}
}
if expr_ret_type.has_option_or_result() {
if expr.or_block.kind == .absent {
ret_sym := c.table.sym(expr_ret_type)
Expand Down
2 changes: 1 addition & 1 deletion vlib/v/checker/fn.v
Original file line number Diff line number Diff line change
Expand Up @@ -1090,7 +1090,7 @@ fn (mut c Checker) fn_call(mut node ast.CallExpr, mut continue_check &bool) ast.
} else {
if obj.typ == 0 {
if mut obj.expr is ast.IfGuardExpr {
typ = c.expr(mut obj.expr.expr)
typ = c.expr(mut obj.expr.expr).clear_option_and_result()
} else {
typ = c.expr(mut obj.expr)
}
Expand Down
7 changes: 7 additions & 0 deletions vlib/v/checker/tests/option_fn_var_err.out
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
vlib/v/checker/tests/option_fn_var_err.vv:18:9: error: type `?DataFn` is an Option, it must be unwrapped first
16 | fn main() {
17 | req := find_func('vlang')
18 | fun := req('options')
| ~~~~~~~~~~~~~~
19 | println(fun)
20 | }
20 changes: 20 additions & 0 deletions vlib/v/checker/tests/option_fn_var_err.vv
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
module main

type DataFn = fn (name string) string

fn which_lang(name string) string {
return name
}

fn find_func(name string) ?DataFn {
return match name {
'vlang' { which_lang }
else { none }
}
}

fn main() {
req := find_func('vlang')
fun := req('options')
println(fun)
}
8 changes: 4 additions & 4 deletions vlib/v/gen/c/match.v
Original file line number Diff line number Diff line change
Expand Up @@ -92,10 +92,10 @@ fn (mut g Gen) match_expr(node ast.MatchExpr) {
cur_line = g.go_before_last_stmt().trim_left(' \t')
tmp_var = g.new_tmp_var()
mut func_decl := ''
if g.table.final_sym(node.return_type).kind == .function {
func_sym := g.table.final_sym(node.return_type)
if func_sym.info is ast.FnType {
def := g.fn_var_signature(func_sym.info.func.return_type, func_sym.info.func.params.map(it.typ),
ret_final_sym := g.table.final_sym(node.return_type)
if !node.return_type.has_option_or_result() && ret_final_sym.kind == .function {
if ret_final_sym.info is ast.FnType {
def := g.fn_var_signature(ret_final_sym.info.func.return_type, ret_final_sym.info.func.params.map(it.typ),
tmp_var)
func_decl = '${def} = &${g.typ(node.return_type)};'
}
Expand Down
27 changes: 27 additions & 0 deletions vlib/v/tests/options/option_fn_var_test.v
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
module main

type DataFn = fn (name string) string

fn which_lang(name string) string {
return name
}

fn find_func(name string) ?DataFn {
return match name {
'vlang' { which_lang }
else { none }
}
}

fn test_main() {
req := find_func('vlang')?
fun := req('options')
println(fun)
assert fun == 'options'
}

fn test_ifguard() {
if req2 := find_func('vlang') {
assert req2('options') == 'options'
}
}

0 comments on commit 4f39bac

Please sign in to comment.