From 0b6d585b0710d384206fa5bbc38e883904eb79f8 Mon Sep 17 00:00:00 2001 From: Delyan Angelov Date: Tue, 7 Sep 2021 11:30:33 +0300 Subject: [PATCH] v.gen.c: allow overriding of the == operator on C.Struct type aliases --- vlib/v/gen/c/auto_eq_methods.v | 17 +++--- vlib/v/gen/c/infix_expr.v | 13 +++-- vlib/v/tests/aliasing_c_structs/cstructs.h | 8 +++ ...operator_overload_of_c_struct_alias_test.v | 58 +++++++++++++++++++ vlib/v/tests/aliasing_c_structs/v.mod | 0 5 files changed, 84 insertions(+), 12 deletions(-) create mode 100644 vlib/v/tests/aliasing_c_structs/cstructs.h create mode 100644 vlib/v/tests/aliasing_c_structs/eq_operator_overload_of_c_struct_alias_test.v create mode 100644 vlib/v/tests/aliasing_c_structs/v.mod diff --git a/vlib/v/gen/c/auto_eq_methods.v b/vlib/v/gen/c/auto_eq_methods.v index 776c590481..dc83b30b51 100644 --- a/vlib/v/gen/c/auto_eq_methods.v +++ b/vlib/v/gen/c/auto_eq_methods.v @@ -58,24 +58,25 @@ fn (mut g Gen) gen_sumtype_equality_fn(left_type ast.Type) string { fn (mut g Gen) gen_struct_equality_fn(left_type ast.Type) string { left := g.unwrap(left_type) ptr_styp := g.typ(left.typ.set_nr_muls(0)) - if ptr_styp in g.struct_fn_definitions { - return ptr_styp + fn_name := ptr_styp.replace('struct ', '') + if fn_name in g.struct_fn_definitions { + return fn_name } - g.struct_fn_definitions << ptr_styp + g.struct_fn_definitions << fn_name info := left.sym.struct_info() - g.type_definitions.writeln('static bool ${ptr_styp}_struct_eq($ptr_styp a, $ptr_styp b); // auto') + g.type_definitions.writeln('static bool ${fn_name}_struct_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 bool ${ptr_styp}_struct_eq($ptr_styp a, $ptr_styp b) {') + fn_builder.writeln('static bool ${fn_name}_struct_eq($ptr_styp a, $ptr_styp b) {') // overloaded if left.sym.has_method('==') { - fn_builder.writeln('\treturn ${ptr_styp}__eq(a, b);') + fn_builder.writeln('\treturn ${fn_name}__eq(a, b);') fn_builder.writeln('}') - return ptr_styp + return fn_name } fn_builder.write_string('\treturn ') @@ -117,7 +118,7 @@ fn (mut g Gen) gen_struct_equality_fn(left_type ast.Type) string { } fn_builder.writeln(';') fn_builder.writeln('}') - return ptr_styp + return fn_name } fn (mut g Gen) gen_alias_equality_fn(left_type ast.Type) string { diff --git a/vlib/v/gen/c/infix_expr.v b/vlib/v/gen/c/infix_expr.v index dc842c9730..2ed706b412 100644 --- a/vlib/v/gen/c/infix_expr.v +++ b/vlib/v/gen/c/infix_expr.v @@ -81,10 +81,11 @@ fn (mut g Gen) infix_expr_arrow_op(node ast.InfixExpr) { fn (mut g Gen) infix_expr_eq_op(node ast.InfixExpr) { left := g.unwrap(node.left_type) right := g.unwrap(node.right_type) - has_operator_overloading := g.table.type_has_method(left.sym, '==') + has_defined_eq_operator := g.table.type_has_method(left.sym, '==') + has_alias_eq_op_overload := left.sym.info is ast.Alias && left.sym.has_method('==') if (left.typ.is_ptr() && right.typ.is_int()) || (right.typ.is_ptr() && left.typ.is_int()) { g.gen_plain_infix_expr(node) - } else if (left.typ.idx() == ast.string_type_idx || (!has_operator_overloading + } else if (left.typ.idx() == ast.string_type_idx || (!has_defined_eq_operator && left.unaliased.idx() == ast.string_type_idx)) && node.right is ast.StringLiteral && (node.right as ast.StringLiteral).val == '' { // `str == ''` -> `str.len == 0` optimization @@ -93,11 +94,15 @@ fn (mut g Gen) infix_expr_eq_op(node ast.InfixExpr) { g.write(')') arrow := if left.typ.is_ptr() { '->' } else { '.' } g.write('${arrow}len $node.op 0') - } else if has_operator_overloading { + } else if has_defined_eq_operator { if node.op == .ne { g.write('!') } - g.write(g.typ(left.unaliased.set_nr_muls(0))) + if has_alias_eq_op_overload { + g.write(g.typ(left.typ.set_nr_muls(0))) + } else { + g.write(g.typ(left.unaliased.set_nr_muls(0))) + } g.write('__eq(') g.write('*'.repeat(left.typ.nr_muls())) g.expr(node.left) diff --git a/vlib/v/tests/aliasing_c_structs/cstructs.h b/vlib/v/tests/aliasing_c_structs/cstructs.h new file mode 100644 index 0000000000..46216d1a6c --- /dev/null +++ b/vlib/v/tests/aliasing_c_structs/cstructs.h @@ -0,0 +1,8 @@ + +struct __mpz_struct1 { + int x; +}; + +typedef struct __mpz_struct2 { + int x; +} __mpz_struct_typedef; diff --git a/vlib/v/tests/aliasing_c_structs/eq_operator_overload_of_c_struct_alias_test.v b/vlib/v/tests/aliasing_c_structs/eq_operator_overload_of_c_struct_alias_test.v new file mode 100644 index 0000000000..8e77b82a5c --- /dev/null +++ b/vlib/v/tests/aliasing_c_structs/eq_operator_overload_of_c_struct_alias_test.v @@ -0,0 +1,58 @@ +#include "@VMODROOT/cstructs.h" + +struct C.__mpz_struct1 { + x int +} + +[typedef] +struct C.__mpz_struct_typedef { + x int +} + +type Bigint = C.__mpz_struct1 +type BigintTypedef = C.__mpz_struct_typedef + +pub fn (a Bigint) == (b Bigint) bool { + println('>>>> struct a.x: $a.x | == | b.x: $b.x => ${a.x == b.x:-5} <<<<') + return a.x == b.x +} + +pub fn (a BigintTypedef) == (b BigintTypedef) bool { + println('>>>> typedef struct a.x: $a.x | == | b.x: $b.x => ${a.x == b.x:-5} <<<<') + return a.x == b.x +} + +fn test_ordinary_c_struct_aliases_with_an_equal_op_overload() { + bi_1 := Bigint{ + x: 12 + } + bi_2 := Bigint{ + x: 34 + } + bi_3 := Bigint{ + x: 12 + } + println(bi_1) + println(bi_2) + assert bi_1 == bi_1 + assert bi_1 == bi_3 + assert bi_1 != bi_2 +} + +fn test_typedefed_c_struct_aliases_with_an_equal_op_overload() { + bit_1 := BigintTypedef{ + x: 55 + } + bit_2 := BigintTypedef{ + x: 99 + } + bit_3 := BigintTypedef{ + x: 55 + } + println(bit_1) + println(bit_2) + println(bit_3) + assert bit_1 == bit_1 + assert bit_1 == bit_3 + assert bit_1 != bit_2 +} diff --git a/vlib/v/tests/aliasing_c_structs/v.mod b/vlib/v/tests/aliasing_c_structs/v.mod new file mode 100644 index 0000000000..e69de29bb2