diff --git a/vlib/v/checker/containers.v b/vlib/v/checker/containers.v index 8ff9283f912cac..3a046e1c2c95ef 100644 --- a/vlib/v/checker/containers.v +++ b/vlib/v/checker/containers.v @@ -468,6 +468,12 @@ fn (mut c Checker) map_init(mut node ast.MapInit) ast.Type { node.pos) } } + } else if val_sym.info is ast.FnType { + for param in val_sym.info.func.params { + if param.typ.has_flag(.result) { + c.error('result type arguments are not supported', node.pos) + } + } } } c.ensure_type_exists(info.key_type, node.pos) diff --git a/vlib/v/checker/fn.v b/vlib/v/checker/fn.v index 53d0cd8bf32338..4b73e75c67ca16 100644 --- a/vlib/v/checker/fn.v +++ b/vlib/v/checker/fn.v @@ -264,7 +264,7 @@ fn (mut c Checker) fn_decl(mut node ast.FnDecl) { param.pos) } if param.typ.has_flag(.result) { - c.error('Result type argument is not supported currently', param.type_pos) + c.error('result type arguments are not supported', param.type_pos) } arg_typ_sym := c.table.sym(param.typ) if arg_typ_sym.info is ast.Struct { diff --git a/vlib/v/checker/tests/result_param_type_err.out b/vlib/v/checker/tests/result_param_type_err.out new file mode 100644 index 00000000000000..e8fa4c5485ec4c --- /dev/null +++ b/vlib/v/checker/tests/result_param_type_err.out @@ -0,0 +1,13 @@ +vlib/v/checker/tests/result_param_type_err.vv:3:13: error: result type arguments are not supported + 1 | module main + 2 | + 3 | fn func(arg !string, val &int) ?int { + | ~~~~~~~ + 4 | unsafe { + 5 | *val = 2 +vlib/v/checker/tests/result_param_type_err.vv:11:7: error: result type arguments are not supported + 9 | + 10 | fn main() { + 11 | _ := map[string]fn (!string, &int) ?int{} + | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + 12 | } diff --git a/vlib/v/checker/tests/result_param_type_err.vv b/vlib/v/checker/tests/result_param_type_err.vv new file mode 100644 index 00000000000000..49599256651a42 --- /dev/null +++ b/vlib/v/checker/tests/result_param_type_err.vv @@ -0,0 +1,12 @@ +module main + +fn func(arg !string, val &int) ?int { + unsafe { + *val = 2 + } + return 2 +} + +fn main() { + _ := map[string]fn (!string, &int) ?int{} +} diff --git a/vlib/v/gen/c/auto_str_methods.v b/vlib/v/gen/c/auto_str_methods.v index 72e834cec241b8..03028a90af470e 100644 --- a/vlib/v/gen/c/auto_str_methods.v +++ b/vlib/v/gen/c/auto_str_methods.v @@ -517,6 +517,9 @@ fn (mut g Gen) fn_decl_str(info ast.FnType) string { if i > 0 { fn_str += ', ' } + if arg.typ.has_flag(.option) { + fn_str += '?' + } fn_str += util.strip_main_name(g.table.get_type_name(g.unwrap_generic(arg.typ))) } fn_str += ')' diff --git a/vlib/v/gen/js/auto_str_methods.v b/vlib/v/gen/js/auto_str_methods.v index c6341a68f98c5f..4418aeb8d616c3 100644 --- a/vlib/v/gen/js/auto_str_methods.v +++ b/vlib/v/gen/js/auto_str_methods.v @@ -409,6 +409,9 @@ fn (mut g JsGen) fn_decl_str(info ast.FnType) string { if i > 0 { fn_str += ', ' } + if arg.typ.has_flag(.option) { + fn_str += '?' + } fn_str += util.strip_main_name(g.table.get_type_name(g.unwrap_generic(arg.typ))) } fn_str += ')' diff --git a/vlib/v/gen/js/js.v b/vlib/v/gen/js/js.v index ce382ae056c13b..d8958881f3e058 100644 --- a/vlib/v/gen/js/js.v +++ b/vlib/v/gen/js/js.v @@ -3425,10 +3425,16 @@ fn (mut g JsGen) gen_typeof_expr(it ast.TypeOf) { if i > 0 { repr += ', ' } + if arg.typ.has_flag(.option) { + repr += '?' + } repr += g.table.get_type_name(arg.typ) } repr += ')' if fn_info.return_type != ast.void_type { + if fn_info.return_type.has_flag(.option) { + repr += '?' + } repr += ' ${g.table.get_type_name(fn_info.return_type)}' } g.write('"${repr}"') diff --git a/vlib/v/gen/native/expr.v b/vlib/v/gen/native/expr.v index ba0562071ad13c..e224bfb6c454cf 100644 --- a/vlib/v/gen/native/expr.v +++ b/vlib/v/gen/native/expr.v @@ -236,6 +236,9 @@ fn (mut g Gen) fn_decl_str(info ast.FnType) string { if i > 0 { fn_str += ', ' } + if arg.typ.has_flag(.option) { + fn_str += '?' + } fn_str += util.strip_main_name(g.table.get_type_name(arg.typ)) } fn_str += ')' diff --git a/vlib/v/parser/fn.v b/vlib/v/parser/fn.v index cf7b7d3718fb17..0aee74446b72dd 100644 --- a/vlib/v/parser/fn.v +++ b/vlib/v/parser/fn.v @@ -918,7 +918,7 @@ fn (mut p Parser) fn_params() ([]ast.Param, bool, bool, bool) { } is_generic_type := p.tok.kind == .name && p.tok.lit.len == 1 && p.tok.lit[0].is_capital() - types_only := p.tok.kind in [.amp, .ellipsis, .key_fn, .lsbr] + types_only := p.tok.kind in [.question, .not, .amp, .ellipsis, .key_fn, .lsbr] || (p.peek_tok.kind == .comma && (p.table.known_type(param_name) || is_generic_type)) || p.peek_tok.kind == .dot || p.peek_tok.kind == .rpar || p.fn_language == .c || (p.tok.kind == .key_mut && (p.peek_tok.kind in [.amp, .ellipsis, .key_fn, .lsbr] diff --git a/vlib/v/tests/options/option_map_fn_value_test.v b/vlib/v/tests/options/option_map_fn_value_test.v new file mode 100644 index 00000000000000..a2ffcbbffdba2b --- /dev/null +++ b/vlib/v/tests/options/option_map_fn_value_test.v @@ -0,0 +1,29 @@ +module main + +fn func(arg ?string, val &int) ?int { + unsafe { + *val = 2 + } + return 2 +} + +fn test_main() { + map1 := { + 'json': func + } + assert typeof(map1['json']).name == 'fn (?string, int) ?int' + + number := 0 + ret := map1['json']('hi', &number) + assert number == ret? + assert ret? == 2 + + mut map2 := map[string]fn (?string, &int) ?int{} + map2['json'] = func + assert typeof(map2['json']).name == 'fn (?string, int) ?int' + + number2 := 0 + ret2 := map2['json']('', &number2) + assert number2 == ret2? + assert ret2? == 2 +}