From e0f9c042c1341fd55a7771eda947df33cd42e5d5 Mon Sep 17 00:00:00 2001 From: Alexander Medvednikov Date: Sat, 25 Apr 2020 21:24:04 +0200 Subject: [PATCH] cgen: interface fixes --- cmd/tools/vtest-fixed.v | 1 - vlib/v/gen/cgen.v | 12 ++++++------ vlib/v/gen/fn.v | 33 ++++++++++++++++++++++++++++++--- vlib/v/tests/interface_test.v | 7 +++---- 4 files changed, 39 insertions(+), 14 deletions(-) diff --git a/cmd/tools/vtest-fixed.v b/cmd/tools/vtest-fixed.v index 77f468313b..511284fe82 100644 --- a/cmd/tools/vtest-fixed.v +++ b/cmd/tools/vtest-fixed.v @@ -16,7 +16,6 @@ const ( 'vlib/v/tests/num_lit_call_method_test.v', 'vlib/v/tests/pointers_test.v', 'vlib/v/tests/type_test.v', - 'vlib/v/tests/interface_test.v', 'vlib/v/tests/valgrind/valgrind_test.v', // ubuntu-musl only 'vlib/v/tests/pointers_str_test.v', 'vlib/net/http/cookie_test.v', diff --git a/vlib/v/gen/cgen.v b/vlib/v/gen/cgen.v index 8375788057..d5e6b1a1be 100644 --- a/vlib/v/gen/cgen.v +++ b/vlib/v/gen/cgen.v @@ -573,11 +573,11 @@ fn (mut g Gen) stmt(node ast.Stmt) { } ast.Import {} ast.InterfaceDecl { - g.writeln('//interface') - g.writeln('typedef struct {') - g.writeln('\tvoid* _object;') - g.writeln('\tint _interface_idx;') - g.writeln('} $it.name;') + g.definitions.writeln('//interface') + g.definitions.writeln('typedef struct {') + g.definitions.writeln('\tvoid* _object;') + g.definitions.writeln('\tint _interface_idx;') + g.definitions.writeln('} $it.name;') } ast.Module {} ast.Return { @@ -1301,7 +1301,7 @@ fn (mut g Gen) assign_expr(node ast.AssignExpr) { g.write(', ') } g.is_assign_lhs = false - //right_sym := g.table.get_type_symbol(node.right_type) + // right_sym := g.table.get_type_symbol(node.right_type) // left_sym := g.table.get_type_symbol(node.left_type) mut cloned := false // !g.is_array_set diff --git a/vlib/v/gen/fn.v b/vlib/v/gen/fn.v index b0c9ee5f78..791cc44a35 100644 --- a/vlib/v/gen/fn.v +++ b/vlib/v/gen/fn.v @@ -249,11 +249,22 @@ fn (mut g Gen) method_call(node ast.CallExpr) { typ_sym := g.table.get_type_symbol(node.receiver_type) mut receiver_name := typ_sym.name if typ_sym.kind == .interface_ { + // Find the index of the method + mut idx := -1 + for i, method in typ_sym.methods { + if method.name == node.name { + idx = i + } + } + if idx == -1 { + verror('method_call: cannot find interface method index') + } + sret_type := g.typ(node.return_type) g.writeln('// interface method call') // `((void (*)())(Speaker_name_table[s._interface_idx][1]))(s._object);` - g.write('((void (*)())(${receiver_name}_name_table[') + g.write('(($sret_type (*)())(${receiver_name}_name_table[') g.expr(node.left) - g.write('._interface_idx][1]))(') + g.write('._interface_idx][$idx]))(') g.expr(node.left) g.write('._object)') return @@ -443,17 +454,33 @@ fn (mut g Gen) call_args(args []ast.CallArg, expected_types []table.Type) { is_forwarding_varg := args.len > 0 && args[args.len - 1].typ.flag_is(.variadic) gen_vargs := is_variadic && !is_forwarding_varg mut arg_no := 0 - for arg in args { + for i, arg in args { if gen_vargs && arg_no == expected_types.len - 1 { break } + // if arg.typ.name.starts_with('I') { + // } + mut is_interface := false // some c fn definitions dont have args (cfns.v) or are not updated in checker // when these are fixed we wont need this check if arg_no < expected_types.len { + if expected_types[arg_no] != 0 { + // Cast a type to interface + // `foo(dog)` => `foo(I_Dog_to_Animal(dog))` + exp_sym := g.table.get_type_symbol(expected_types[arg_no]) + sym := g.table.get_type_symbol(arg.typ) + if exp_sym.kind == .interface_ { + g.write('I_${sym.name}_to_${exp_sym.name}(') + is_interface = true + } + } g.ref_or_deref_arg(arg, expected_types[arg_no]) } else { g.expr(arg.expr) } + if is_interface { + g.write(')') + } if arg_no < args.len - 1 || gen_vargs { g.write(', ') } diff --git a/vlib/v/tests/interface_test.v b/vlib/v/tests/interface_test.v index 0a365e9bb1..efa34997d7 100644 --- a/vlib/v/tests/interface_test.v +++ b/vlib/v/tests/interface_test.v @@ -36,10 +36,8 @@ interface Speaker { fn perform_speak(s Speaker) { s.speak() assert true - /* name := s.name() assert name == 'Dog' || name == 'Cat' -*/ println(s.name()) } @@ -48,7 +46,7 @@ fn test_perform_speak() { perform_speak(dog) cat := Cat{} perform_speak(cat) - // perform_speakers([dog, cat]) + //perform_speakers([dog, cat]) /* f := Foo { speaker: dog @@ -56,6 +54,8 @@ fn test_perform_speak() { */ } +//fn perform_speakers(speakers []Speaker) {} + /* interface Speak2er { name ()string @@ -67,7 +67,6 @@ struct Foo { speakers []Speaker } -fn perform_speakers(speakers []Speaker) {} interface Register {