From f992099726dcee2af94a493cbfc5a7a67f09f40b Mon Sep 17 00:00:00 2001 From: Nick Treleaven Date: Sun, 31 Jan 2021 14:28:23 +0000 Subject: [PATCH] checker: check s.$method(arg) argument is []string (#8455) --- vlib/v/checker/checker.v | 16 +++++++++++++++- vlib/v/checker/tests/comptime_call_method.out | 14 ++++++++++++++ vlib/v/checker/tests/comptime_call_method.vv | 14 ++++++++++++++ vlib/v/parser/comptime.v | 1 + vlib/v/tests/comptime_call_test.v | 17 ++++++++++++++++- 5 files changed, 60 insertions(+), 2 deletions(-) create mode 100644 vlib/v/checker/tests/comptime_call_method.out create mode 100644 vlib/v/checker/tests/comptime_call_method.vv diff --git a/vlib/v/checker/checker.v b/vlib/v/checker/checker.v index 40fb1b6f7c..4081d00c2a 100644 --- a/vlib/v/checker/checker.v +++ b/vlib/v/checker/checker.v @@ -3699,7 +3699,21 @@ fn (mut c Checker) comptime_call(mut node ast.ComptimeCall) table.Type { node.result_type = rtyp return rtyp } - if node.is_vweb || node.method_name == 'method' { + if node.method_name == 'method' { + if node.args_var.len > 0 { + v := node.scope.find_var(node.args_var) or { + c.error('unknown identifier `$node.args_var`', node.method_pos) + return table.void_type + } + s := c.table.type_to_str(c.expr(v.expr)) + if s != '[]string' { + c.error('expected `[]string`, not s', node.method_pos) + } + } + // assume string for now + return table.string_type + } + if node.is_vweb { return table.string_type } // s.$my_str() diff --git a/vlib/v/checker/tests/comptime_call_method.out b/vlib/v/checker/tests/comptime_call_method.out new file mode 100644 index 0000000000..981d74a281 --- /dev/null +++ b/vlib/v/checker/tests/comptime_call_method.out @@ -0,0 +1,14 @@ +vlib/v/checker/tests/comptime_call_method.vv:10:7: error: unknown identifier `wrong` + 8 | s1 := S1{} + 9 | $for method in S1.methods { + 10 | s1.$method(wrong) + | ~~~~~~ + 11 | arg := 7 + 12 | s1.$method(arg) +vlib/v/checker/tests/comptime_call_method.vv:12:7: error: expected `[]string`, not s + 10 | s1.$method(wrong) + 11 | arg := 7 + 12 | s1.$method(arg) + | ~~~~~~ + 13 | } + 14 | } diff --git a/vlib/v/checker/tests/comptime_call_method.vv b/vlib/v/checker/tests/comptime_call_method.vv new file mode 100644 index 0000000000..f1fb66f5f7 --- /dev/null +++ b/vlib/v/checker/tests/comptime_call_method.vv @@ -0,0 +1,14 @@ +struct S1 {} + +fn (t S1) m(s string) int { + return 7 +} + +fn test_methods_arg() { + s1 := S1{} + $for method in S1.methods { + s1.$method(wrong) + arg := 7 + s1.$method(arg) + } +} diff --git a/vlib/v/parser/comptime.v b/vlib/v/parser/comptime.v index 96f0cc14ad..b465c335a7 100644 --- a/vlib/v/parser/comptime.v +++ b/vlib/v/parser/comptime.v @@ -269,6 +269,7 @@ fn (mut p Parser) comptime_selector(left ast.Expr) ast.Expr { mut args_var := '' if p.tok.kind == .name { args_var = p.tok.lit + p.mark_var_as_used(args_var) p.next() } p.check(.rpar) diff --git a/vlib/v/tests/comptime_call_test.v b/vlib/v/tests/comptime_call_test.v index 9ca461c9de..e00d43458e 100644 --- a/vlib/v/tests/comptime_call_test.v +++ b/vlib/v/tests/comptime_call_test.v @@ -31,7 +31,6 @@ fn test_for_methods() { $for method in Test.methods { // currently the checker thinks all $method calls return string $if method.return_type is string { - //~ $if method.name == 's' {println('yes')} v := test.$method() r += v.str() } @@ -50,3 +49,19 @@ fn test_for_methods() { } assert r == '?testTwo' } + +struct S1 {} + +fn (t S1) rep(s string, i int) string { + return s.repeat(i) +} + +fn test_methods_arg() { + s1 := S1{} + $for method in S1.methods { + arr := ['!', '3'] + r := s1.$method(arr) + assert r == '!!!' + } +} +