From f407d6de020f60f7dc14799eaa5f2425f0929b47 Mon Sep 17 00:00:00 2001 From: yuyi Date: Mon, 13 Dec 2021 01:42:40 +0800 Subject: [PATCH] ast, checker, cgen: fix generics multiple type comptime call (fix #12777) (#12806) --- cmd/tools/vast/vast.v | 2 +- vlib/v/ast/ast.v | 2 +- vlib/v/checker/comptime.v | 4 +- vlib/v/gen/c/comptime.v | 13 ++++--- .../generics_multi_type_comptime_call_test.v | 39 +++++++++++++++++++ 5 files changed, 50 insertions(+), 10 deletions(-) create mode 100644 vlib/v/tests/generics_multi_type_comptime_call_test.v diff --git a/cmd/tools/vast/vast.v b/cmd/tools/vast/vast.v index f5142e062a..50deb639d9 100644 --- a/cmd/tools/vast/vast.v +++ b/cmd/tools/vast/vast.v @@ -966,11 +966,11 @@ fn (t Tree) comptime_call(node ast.ComptimeCall) &Node { obj.add_terse('is_vweb', t.bool_node(node.is_vweb)) obj.add_terse('vweb_tmpl', t.string_node(node.vweb_tmpl.path)) obj.add_terse('args_var', t.string_node(node.args_var)) - obj.add_terse('sym', t.string_node(node.sym.name)) obj.add_terse('has_parens', t.bool_node(node.has_parens)) obj.add_terse('is_embed', t.bool_node(node.is_embed)) obj.add_terse('embed_file', t.embed_file(node.embed_file)) obj.add('method_pos', t.position(node.method_pos)) + obj.add_terse('left_type', t.type_node(node.left_type)) obj.add_terse('result_type', t.type_node(node.result_type)) obj.add('scope', t.scope(node.scope)) obj.add_terse('env_value', t.string_node(node.env_value)) diff --git a/vlib/v/ast/ast.v b/vlib/v/ast/ast.v index 6fbad9a28b..df5df3851e 100644 --- a/vlib/v/ast/ast.v +++ b/vlib/v/ast/ast.v @@ -1559,7 +1559,7 @@ pub: // is_pkgconfig bool pub mut: - sym TypeSymbol + left_type Type result_type Type env_value string args []CallArg diff --git a/vlib/v/checker/comptime.v b/vlib/v/checker/comptime.v index 02d24cb76e..10b9fd1716 100644 --- a/vlib/v/checker/comptime.v +++ b/vlib/v/checker/comptime.v @@ -10,7 +10,7 @@ import v.pkgconfig fn (mut c Checker) comptime_call(mut node ast.ComptimeCall) ast.Type { sym := c.table.get_type_symbol(c.unwrap_generic(c.expr(node.left))) - node.sym = *sym + node.left_type = c.expr(node.left) if node.is_env { env_value := util.resolve_env_value("\$env('$node.args_var')", false) or { c.error(err.msg, node.env_pos) @@ -91,7 +91,7 @@ fn (mut c Checker) comptime_call(mut node ast.ComptimeCall) ast.Type { } else { c.error('todo: not a string literal', node.method_pos) } - f := node.sym.find_method(method_name) or { + f := sym.find_method(method_name) or { c.error('could not find method `$method_name`', node.method_pos) return ast.void_type } diff --git a/vlib/v/gen/c/comptime.v b/vlib/v/gen/c/comptime.v index 47fcf33837..aae42b7cee 100644 --- a/vlib/v/gen/c/comptime.v +++ b/vlib/v/gen/c/comptime.v @@ -76,10 +76,11 @@ fn (mut g Gen) comptime_call(mut node ast.ComptimeCall) { } return } - g.trace_autofree('// \$method call. sym="$node.sym.name"') + sym := g.table.get_type_symbol(g.unwrap_generic(node.left_type)) + g.trace_autofree('// \$method call. sym="$sym.name"') if node.method_name == 'method' { // `app.$method()` - m := node.sym.find_method(g.comptime_for_method) or { return } + m := sym.find_method(g.comptime_for_method) or { return } /* vals := m.attrs[0].split('/') args := vals.filter(it.starts_with(':')).map(it[1..]) @@ -99,7 +100,7 @@ fn (mut g Gen) comptime_call(mut node ast.ComptimeCall) { // check argument length and types if m.params.len - 1 != node.args.len && !expand_strs { // do not generate anything if the argument lengths don't match - g.writeln('/* skipping ${node.sym.name}.$m.name due to mismatched arguments list */') + g.writeln('/* skipping ${sym.name}.$m.name due to mismatched arguments list */') // g.writeln('println(_SLIT("skipping ${node.sym.name}.$m.name due to mismatched arguments list"));') // eprintln('info: skipping ${node.sym.name}.$m.name due to mismatched arguments list\n' + //'method.params: $m.params, args: $node.args\n\n') @@ -107,7 +108,7 @@ fn (mut g Gen) comptime_call(mut node ast.ComptimeCall) { return } // TODO: check argument types - g.write('${util.no_dots(node.sym.name)}_${g.comptime_for_method}(') + g.write('${util.no_dots(sym.name)}_${g.comptime_for_method}(') // try to see if we need to pass a pointer if node.left is ast.Ident { @@ -153,7 +154,7 @@ fn (mut g Gen) comptime_call(mut node ast.ComptimeCall) { return } mut j := 0 - for method in node.sym.methods { + for method in sym.methods { // if method.return_type != ast.void_type { if method.return_type != node.result_type { continue @@ -172,7 +173,7 @@ fn (mut g Gen) comptime_call(mut node ast.ComptimeCall) { } g.write('if (string__eq($node.method_name, _SLIT("$method.name"))) ') } - g.write('${util.no_dots(node.sym.name)}_${method.name}($amp ') + g.write('${util.no_dots(sym.name)}_${method.name}($amp ') g.expr(node.left) g.writeln(');') j++ diff --git a/vlib/v/tests/generics_multi_type_comptime_call_test.v b/vlib/v/tests/generics_multi_type_comptime_call_test.v new file mode 100644 index 0000000000..6900690e48 --- /dev/null +++ b/vlib/v/tests/generics_multi_type_comptime_call_test.v @@ -0,0 +1,39 @@ +struct Foo {} + +['/'; 'GET'] +fn (mut f Foo) hello() string { + return @FN +} + +struct Bar {} + +['/'; 'GET'] +fn (b &Bar) world() string { + return @FN +} + +fn execute_methods() string { + tmp := T{} + $for method in T.methods { + if method.attrs.len >= 2 { + fun_path := method.attrs[0] + fun_method := method.attrs[1] + + if fun_path == '/' && fun_method == 'GET' { + ret := tmp.$method() + return ret + } + } + } + return '' +} + +fn test_generics_multi_type_comptime_call() { + ret1 := execute_methods() + println(ret1) + assert ret1 == 'hello' + + ret2 := execute_methods() + println(ret2) + assert ret2 == 'world' +}