From 129c81f34d4280e1253de12c8dc828752005a742 Mon Sep 17 00:00:00 2001 From: 05st <60903484+05st@users.noreply.github.com> Date: Sun, 3 Oct 2021 01:04:05 -0500 Subject: [PATCH] cgen: implement eq operator for interfaces (#12047) --- vlib/v/gen/c/auto_eq_methods.v | 69 ++++++++++++++++++++++++++ vlib/v/gen/c/infix_expr.v | 19 ++++++- vlib/v/tests/interface_equality_test.v | 23 +++++++++ 3 files changed, 110 insertions(+), 1 deletion(-) create mode 100644 vlib/v/tests/interface_equality_test.v diff --git a/vlib/v/gen/c/auto_eq_methods.v b/vlib/v/gen/c/auto_eq_methods.v index d02cac0789..9fe60bc8d8 100644 --- a/vlib/v/gen/c/auto_eq_methods.v +++ b/vlib/v/gen/c/auto_eq_methods.v @@ -39,6 +39,9 @@ fn (mut g Gen) gen_equality_fns() { .alias { g.gen_alias_equality_fn(needed_typ) } + .interface_ { + g.gen_interface_equality_fn(needed_typ) + } else { verror('could not generate equality function for type $sym.kind') } @@ -386,3 +389,69 @@ fn (mut g Gen) gen_map_equality_fn(left_type ast.Type) string { g.auto_fn_definitions << fn_builder.str() return ptr_styp } + +fn (mut g Gen) gen_interface_equality_fn(left_type ast.Type) string { + left := g.unwrap(left_type) + ptr_styp := g.typ(left.typ.set_nr_muls(0)) + fn_name := ptr_styp.replace('interface ', '') + if left_type in g.generated_eq_fns { + return fn_name + } + g.generated_eq_fns << left_type + info := left.sym.info + g.type_definitions.writeln('static bool ${ptr_styp}_interface_eq($ptr_styp a, $ptr_styp b); // auto') + + mut fn_builder := strings.new_builder(512) + defer { + g.auto_fn_definitions << fn_builder.str() + } + fn_builder.writeln('static int v_typeof_interface_idx_${ptr_styp}(int sidx); // for auto eq method') + fn_builder.writeln('static bool ${fn_name}_interface_eq($ptr_styp a, $ptr_styp b) {') + fn_builder.writeln('\tif (a._typ == b._typ) {') + fn_builder.writeln('\t\tint idx = v_typeof_interface_idx_${ptr_styp}(a._typ);') + if info is ast.Interface { + for typ in info.types { + fn_builder.writeln('\t\tif (idx == $typ) {') + fn_builder.write_string('\t\t\treturn ') + match g.table.type_kind(typ) { + .struct_ { + eq_fn := g.gen_struct_equality_fn(typ) + fn_builder.write_string('${eq_fn}_struct_eq(*(a._$eq_fn), *(b._$eq_fn))') + } + .string { + fn_builder.write_string('string__eq(*(a._string), *(b._string))') + } + .sum_type { + eq_fn := g.gen_sumtype_equality_fn(typ) + fn_builder.write_string('${eq_fn}_sumtype_eq(*(a._$eq_fn), *(b._$eq_fn))') + } + .array { + eq_fn := g.gen_array_equality_fn(typ) + fn_builder.write_string('${eq_fn}_arr_eq(*(a._$eq_fn), *(b._$eq_fn))') + } + .array_fixed { + eq_fn := g.gen_fixed_array_equality_fn(typ) + fn_builder.write_string('${eq_fn}_arr_eq(*(a._$eq_fn), *(b._$eq_fn))') + } + .map { + eq_fn := g.gen_map_equality_fn(typ) + fn_builder.write_string('${eq_fn}_map_eq(*(a._$eq_fn), *(b._$eq_fn))') + } + .alias { + eq_fn := g.gen_alias_equality_fn(typ) + fn_builder.write_string('${eq_fn}_alias_eq(*(a._$eq_fn), *(b._$eq_fn))') + } + else { + fn_builder.write_string('false') + } + } + fn_builder.writeln(';') + fn_builder.writeln('\t\t}') + } + } + fn_builder.writeln('\t}') + fn_builder.writeln('\treturn false;') + fn_builder.writeln('}') + + return fn_name +} diff --git a/vlib/v/gen/c/infix_expr.v b/vlib/v/gen/c/infix_expr.v index 28dd848677..bb52d57c29 100644 --- a/vlib/v/gen/c/infix_expr.v +++ b/vlib/v/gen/c/infix_expr.v @@ -111,7 +111,7 @@ fn (mut g Gen) infix_expr_eq_op(node ast.InfixExpr) { g.expr(node.right) g.write(')') } else if left.typ.idx() == right.typ.idx() - && left.sym.kind in [.array, .array_fixed, .alias, .map, .struct_, .sum_type] { + && left.sym.kind in [.array, .array_fixed, .alias, .map, .struct_, .sum_type, .interface_] { match left.sym.kind { .alias { ptr_typ := g.equality_fn(left.typ) @@ -226,6 +226,23 @@ fn (mut g Gen) infix_expr_eq_op(node ast.InfixExpr) { g.expr(node.right) g.write(')') } + .interface_ { + ptr_typ := g.equality_fn(left.unaliased) + if node.op == .ne { + g.write('!') + } + g.write('${ptr_typ}_interface_eq(') + if left.typ.is_ptr() { + g.write('*') + } + g.expr(node.left) + g.write(', ') + if right.typ.is_ptr() { + g.write('*') + } + g.expr(node.right) + g.write(')') + } else {} } } else if left.unaliased.idx() in [ast.u32_type_idx, ast.u64_type_idx] diff --git a/vlib/v/tests/interface_equality_test.v b/vlib/v/tests/interface_equality_test.v new file mode 100644 index 0000000000..4948151f28 --- /dev/null +++ b/vlib/v/tests/interface_equality_test.v @@ -0,0 +1,23 @@ +interface IExample {} + +struct Example { + id string +} + +struct Example2 { + n int +} + +fn equals(a IExample, b IExample) bool { + return a == b +} + +fn test_equality() { + assert !equals(Example{ id: 'a' }, 'abc') + assert !equals(Example{ id: 'a' }, Example{ + id: 'b' + }) + assert equals(Example{ id: 'a' }, Example{ + id: 'a' + }) +}