From d1b0ce9e0c694672297d3fe3871d2a6e6d29be14 Mon Sep 17 00:00:00 2001 From: yuyi Date: Tue, 30 Nov 2021 21:03:44 +0800 Subject: [PATCH] cgen: fix error of the interface str method (fix #12538) (#12620) --- vlib/v/gen/c/cgen.v | 2 +- vlib/v/gen/c/fn.v | 13 +++++++++++++ vlib/v/gen/c/str_intp.v | 10 ++++++++++ vlib/v/tests/interface_str_method_test.v | 20 ++++++++++++++++++++ 4 files changed, 44 insertions(+), 1 deletion(-) create mode 100644 vlib/v/tests/interface_str_method_test.v diff --git a/vlib/v/gen/c/cgen.v b/vlib/v/gen/c/cgen.v index c49e645b39..e8ddd80db4 100644 --- a/vlib/v/gen/c/cgen.v +++ b/vlib/v/gen/c/cgen.v @@ -7367,7 +7367,7 @@ static inline $interface_name I_${cctype}_to_Interface_${interface_name}($cctype // .speak = Cat_speak_Interface_Animal_method_wrapper method_call += iwpostfix } - if g.pref.build_mode != .build_module { + if g.pref.build_mode != .build_module && st != ast.voidptr_type { methods_struct.writeln('\t\t._method_${c_name(method.name)} = (void*) $method_call,') } } diff --git a/vlib/v/gen/c/fn.v b/vlib/v/gen/c/fn.v index d56729036a..4a37b7002d 100644 --- a/vlib/v/gen/c/fn.v +++ b/vlib/v/gen/c/fn.v @@ -1141,6 +1141,19 @@ fn (mut g Gen) fn_call(node ast.CallExpr) { } if typ != ast.string_type { expr := node.args[0].expr + typ_sym := g.table.get_type_symbol(typ) + if typ_sym.kind == .interface_ && (typ_sym.info as ast.Interface).defines_method('str') { + g.write('${c_name(print_method)}(') + rec_type_name := util.no_dots(g.cc_type(typ, false)) + g.write('${c_name(rec_type_name)}_name_table[') + g.expr(expr) + dot := if typ.is_ptr() { '->' } else { '.' } + g.write('${dot}_typ]._method_str(') + g.expr(expr) + g.write('${dot}_object') + g.writeln('));') + return + } if g.is_autofree && !typ.has_flag(.optional) { // Create a temporary variable so that the value can be freed tmp := g.new_tmp_var() diff --git a/vlib/v/gen/c/str_intp.v b/vlib/v/gen/c/str_intp.v index fea23834e8..b4fc54dbb7 100644 --- a/vlib/v/gen/c/str_intp.v +++ b/vlib/v/gen/c/str_intp.v @@ -125,6 +125,7 @@ fn (mut g Gen) str_val(node ast.StringInterLiteral, i int) { expr := node.exprs[i] typ := g.unwrap_generic(node.expr_types[i]) + typ_sym := g.table.get_type_symbol(typ) if typ == ast.string_type { if g.inside_vweb_tmpl { g.write('vweb__filter(') @@ -139,6 +140,15 @@ fn (mut g Gen) str_val(node ast.StringInterLiteral, i int) { } g.expr(expr) } + } else if typ_sym.kind == .interface_ && (typ_sym.info as ast.Interface).defines_method('str') { + rec_type_name := util.no_dots(g.cc_type(typ, false)) + g.write('${c_name(rec_type_name)}_name_table[') + g.expr(expr) + dot := if typ.is_ptr() { '->' } else { '.' } + g.write('${dot}_typ]._method_str(') + g.expr(expr) + g.write('${dot}_object') + g.write(')') } else if node.fmts[i] == `s` || typ.has_flag(.variadic) { mut exp_typ := typ if expr is ast.Ident && g.comptime_var_type_map.len > 0 { diff --git a/vlib/v/tests/interface_str_method_test.v b/vlib/v/tests/interface_str_method_test.v new file mode 100644 index 0000000000..cace55c260 --- /dev/null +++ b/vlib/v/tests/interface_str_method_test.v @@ -0,0 +1,20 @@ +interface Str { + str() string +} + +struct St {} + +fn (s St) str() string { + return 's' +} + +fn printer(s Str) string { + println(s) + return '$s' +} + +fn test_interface_str_method() { + s := St{} + ret := printer(s) + assert ret == 's' +}