Skip to content

Commit

Permalink
parser, checker: fix option map fn type and missing check for result …
Browse files Browse the repository at this point in the history
…param type (fix #22736) (#22738)
  • Loading branch information
felipensp authored Nov 3, 2024
1 parent ea19923 commit 3108820
Show file tree
Hide file tree
Showing 10 changed files with 77 additions and 2 deletions.
6 changes: 6 additions & 0 deletions vlib/v/checker/containers.v
Original file line number Diff line number Diff line change
Expand Up @@ -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)
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 @@ -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 {
Expand Down
13 changes: 13 additions & 0 deletions vlib/v/checker/tests/result_param_type_err.out
Original file line number Diff line number Diff line change
@@ -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 | }
12 changes: 12 additions & 0 deletions vlib/v/checker/tests/result_param_type_err.vv
Original file line number Diff line number Diff line change
@@ -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{}
}
3 changes: 3 additions & 0 deletions vlib/v/gen/c/auto_str_methods.v
Original file line number Diff line number Diff line change
Expand Up @@ -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 += ')'
Expand Down
3 changes: 3 additions & 0 deletions vlib/v/gen/js/auto_str_methods.v
Original file line number Diff line number Diff line change
Expand Up @@ -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 += ')'
Expand Down
6 changes: 6 additions & 0 deletions vlib/v/gen/js/js.v
Original file line number Diff line number Diff line change
Expand Up @@ -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}"')
Expand Down
3 changes: 3 additions & 0 deletions vlib/v/gen/native/expr.v
Original file line number Diff line number Diff line change
Expand Up @@ -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 += ')'
Expand Down
2 changes: 1 addition & 1 deletion vlib/v/parser/fn.v
Original file line number Diff line number Diff line change
Expand Up @@ -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]
Expand Down
29 changes: 29 additions & 0 deletions vlib/v/tests/options/option_map_fn_value_test.v
Original file line number Diff line number Diff line change
@@ -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
}

0 comments on commit 3108820

Please sign in to comment.