diff --git a/vlib/v/checker/checker.v b/vlib/v/checker/checker.v index db841d63b31249..2f0b155b92bb0a 100644 --- a/vlib/v/checker/checker.v +++ b/vlib/v/checker/checker.v @@ -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) diff --git a/vlib/v/checker/fn.v b/vlib/v/checker/fn.v index 8c92775e8e0a5e..e73f7d0db215c0 100644 --- a/vlib/v/checker/fn.v +++ b/vlib/v/checker/fn.v @@ -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) } diff --git a/vlib/v/checker/tests/option_fn_var_err.out b/vlib/v/checker/tests/option_fn_var_err.out new file mode 100644 index 00000000000000..84e02076da4e82 --- /dev/null +++ b/vlib/v/checker/tests/option_fn_var_err.out @@ -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 | } diff --git a/vlib/v/checker/tests/option_fn_var_err.vv b/vlib/v/checker/tests/option_fn_var_err.vv new file mode 100644 index 00000000000000..b5766c6f5e8210 --- /dev/null +++ b/vlib/v/checker/tests/option_fn_var_err.vv @@ -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) +} diff --git a/vlib/v/gen/c/match.v b/vlib/v/gen/c/match.v index b79050b8a5da08..7c7ad45f9000e9 100644 --- a/vlib/v/gen/c/match.v +++ b/vlib/v/gen/c/match.v @@ -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)};' } diff --git a/vlib/v/tests/options/option_fn_var_test.v b/vlib/v/tests/options/option_fn_var_test.v new file mode 100644 index 00000000000000..22ba71b16d9562 --- /dev/null +++ b/vlib/v/tests/options/option_fn_var_test.v @@ -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' + } +}