diff --git a/vlib/v/gen/fn.v b/vlib/v/gen/fn.v index ec5eac1352..735021f6c0 100644 --- a/vlib/v/gen/fn.v +++ b/vlib/v/gen/fn.v @@ -183,7 +183,14 @@ fn (mut g Gen) gen_fn_decl(it ast.FnDecl, skip bool) { default_expr := g.type_default(it.return_type) // TODO: perf? if default_expr == '{0}' { - g.writeln('\treturn ($type_name)$default_expr;') + if it.return_type.idx() == 1 && it.return_type.has_flag(.optional) { + // The default return for anonymous functions that return `?, + // should have .ok = true set, otherwise calling them with + // optfn() or { panic(err) } will cause a panic: + g.writeln('\treturn (Option_void){.ok = true};') + } else { + g.writeln('\treturn ($type_name)$default_expr;') + } } else { g.writeln('\treturn $default_expr;') } diff --git a/vlib/v/tests/anon_fn_returning_question_test.v b/vlib/v/tests/anon_fn_returning_question_test.v new file mode 100644 index 0000000000..36cd2732d8 --- /dev/null +++ b/vlib/v/tests/anon_fn_returning_question_test.v @@ -0,0 +1,25 @@ +type FnCb = fn (a string, b int) ? + +fn test_calling_an_anon_function_returning_question() { + create_and_call_anon_function() or { panic(err) } +} + +fn create_and_call_anon_function() ? { + x := fn (a string, b int) ? { + println('test') + // NB: the anon function does NOT return explicitly, + // so V should generate an implicit "OK" value and + // return it. Previously, it created an implicit optional + // filled with 0s => .ok was false, and that was treated + // as a failure, triggering or blocks. + } + should_not_call_block(x) ? + assert true +} + +fn should_not_call_block(func FnCb) ? { + func('abc', 123) or { + println('this should NOT be called') + assert false + } +}