1
0
mirror of https://github.com/vlang/v.git synced 2023-08-10 21:13:21 +03:00

cgen: multiple auto equality func generated fixes (#17756)

This commit is contained in:
Felipe Pena 2023-03-25 15:45:18 -03:00 committed by GitHub
parent 0a8a0fdb0e
commit 24cc5920e6
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 157 additions and 37 deletions

View File

@ -197,14 +197,14 @@ fn (mut g Gen) gen_struct_equality_fn(left_type ast.Type) string {
} else if field_type.sym.kind == .alias && !field.typ.is_ptr() {
eq_fn := g.gen_alias_equality_fn(field.typ)
fn_builder.write_string('${eq_fn}_alias_eq(${left_arg}, ${right_arg})')
} else if field_type.sym.kind == .function {
} else if field_type.sym.kind == .function && !field.typ.has_flag(.option) {
fn_builder.write_string('*((voidptr*)(${left_arg})) == *((voidptr*)(${right_arg}))')
} else if field_type.sym.kind == .interface_ {
ptr := if field.typ.is_ptr() { '*'.repeat(field.typ.nr_muls()) } else { '' }
eq_fn := g.gen_interface_equality_fn(field.typ)
fn_builder.write_string('${eq_fn}_interface_eq(${ptr}${left_arg}, ${ptr}${right_arg})')
} else if left_type.has_flag(.option) {
fn_builder.write_string('!memcmp(&${left_arg}, &${right_arg}, sizeof(${g.base_type(field.typ)}))')
} else if field.typ.has_flag(.option) {
fn_builder.write_string('${left_arg}.state == ${right_arg}.state && !memcmp(&${left_arg}.data, &${right_arg}.data, sizeof(${g.base_type(field.typ)}))')
} else {
fn_builder.write_string('${left_arg} == ${right_arg}')
}
@ -230,37 +230,40 @@ fn (mut g Gen) gen_alias_equality_fn(left_type ast.Type) string {
mut fn_builder := strings.new_builder(512)
fn_builder.writeln('static bool ${ptr_styp}_alias_eq(${ptr_styp} a, ${ptr_styp} b) {')
is_option := info.parent_type.has_flag(.option) || left.typ.has_flag(.option)
left_var := if is_option { '*' + g.read_opt(info.parent_type, 'a') } else { 'a' }
right_var := if is_option { '*' + g.read_opt(info.parent_type, 'b') } else { 'b' }
sym := g.table.sym(info.parent_type)
if sym.kind == .string {
if info.parent_type.has_flag(.option) {
fn_builder.writeln('\treturn ((${g.read_opt(info.parent_type, 'a')})->len == (${g.read_opt(info.parent_type,
'b')})->len && (${g.read_opt(info.parent_type, 'a')})->len == 0) || string__eq(*${g.read_opt(info.parent_type,
'a')}, *${g.read_opt(info.parent_type, 'b')});')
if is_option {
fn_builder.writeln('\treturn ((${left_var}).len == (${right_var}).len && (${left_var}).len == 0) || string__eq(${left_var}, ${right_var});')
} else {
fn_builder.writeln('\treturn string__eq(a, b);')
}
} else if sym.kind == .sum_type && !left.typ.is_ptr() {
eq_fn := g.gen_sumtype_equality_fn(info.parent_type)
fn_builder.writeln('\treturn ${eq_fn}_sumtype_eq(a, b);')
fn_builder.writeln('\treturn ${eq_fn}_sumtype_eq(${left_var}, ${right_var});')
} else if sym.kind == .struct_ && !left.typ.is_ptr() {
eq_fn := g.gen_struct_equality_fn(info.parent_type)
fn_builder.writeln('\treturn ${eq_fn}_struct_eq(a, b);')
fn_builder.writeln('\treturn ${eq_fn}_struct_eq(${left_var}, ${right_var});')
} else if sym.kind == .interface_ && !left.typ.is_ptr() {
eq_fn := g.gen_interface_equality_fn(info.parent_type)
fn_builder.writeln('\treturn ${eq_fn}_interface_eq(a, b);')
fn_builder.writeln('\treturn ${eq_fn}_interface_eq(${left_var}, ${right_var});')
} else if sym.kind == .array && !left.typ.is_ptr() {
eq_fn := g.gen_array_equality_fn(info.parent_type)
fn_builder.writeln('\treturn ${eq_fn}_arr_eq(a, b);')
fn_builder.writeln('\treturn ${eq_fn}_arr_eq(${left_var}, ${right_var});')
} else if sym.kind == .array_fixed && !left.typ.is_ptr() {
eq_fn := g.gen_fixed_array_equality_fn(info.parent_type)
fn_builder.writeln('\treturn ${eq_fn}_arr_eq(a, b);')
fn_builder.writeln('\treturn ${eq_fn}_arr_eq(${left_var}, ${right_var});')
} else if sym.kind == .map && !left.typ.is_ptr() {
eq_fn := g.gen_map_equality_fn(info.parent_type)
fn_builder.writeln('\treturn ${eq_fn}_map_eq(a, b);')
} else if sym.kind == .function {
fn_builder.writeln('\treturn ${eq_fn}_map_eq(${left_var}, ${right_var});')
} else if sym.kind == .function && !left.typ.has_flag(.option) {
fn_builder.writeln('\treturn *((voidptr*)(a)) == *((voidptr*)(b));')
} else if info.parent_type.has_flag(.option) || left.typ.has_flag(.option) {
fn_builder.writeln('\treturn !memcmp(&a.data, &b.data, sizeof(${g.base_type(info.parent_type)}));')
fn_builder.writeln('\treturn a.state == b.state && !memcmp(&a.data, &b.data, sizeof(${g.base_type(info.parent_type)}));')
} else {
fn_builder.writeln('\treturn a == b;')
}
@ -282,38 +285,52 @@ fn (mut g Gen) gen_array_equality_fn(left_type ast.Type) string {
mut fn_builder := strings.new_builder(512)
fn_builder.writeln('static bool ${ptr_styp}_arr_eq(${ptr_styp} a, ${ptr_styp} b) {')
fn_builder.writeln('\tif (a.len != b.len) {')
left_len := g.read_field(left_type, 'len', 'a')
right_len := g.read_field(left_type, 'len', 'b')
left_data := g.read_field(left_type, 'data', 'a')
right_data := g.read_field(left_type, 'data', 'b')
left_elem := g.read_field(left_type, 'element_size', 'a')
right_elem := g.read_field(left_type, 'element_size', 'b')
if left_type.has_flag(.option) {
fn_builder.writeln('\tif (a.state != b.state) return false;')
}
fn_builder.writeln('\tif (${left_len} != ${right_len}) {')
fn_builder.writeln('\t\treturn false;')
fn_builder.writeln('\t}')
fn_builder.writeln('\tfor (int i = 0; i < a.len; ++i) {')
fn_builder.writeln('\tfor (int i = 0; i < ${left_len}; ++i) {')
// compare every pair of elements of the two arrays
if elem.sym.kind == .string {
fn_builder.writeln('\t\tif (!string__eq(*((${ptr_elem_styp}*)((byte*)a.data+(i*a.element_size))), *((${ptr_elem_styp}*)((byte*)b.data+(i*b.element_size))))) {')
fn_builder.writeln('\t\tif (!string__eq(*((${ptr_elem_styp}*)((byte*)${left_data}+(i*${left_elem}))), *((${ptr_elem_styp}*)((byte*)${right_data}+(i*${right_elem}))))) {')
} else if elem.sym.kind == .sum_type && !elem.typ.is_ptr() {
eq_fn := g.gen_sumtype_equality_fn(elem.typ)
fn_builder.writeln('\t\tif (!${eq_fn}_sumtype_eq(((${ptr_elem_styp}*)a.data)[i], ((${ptr_elem_styp}*)b.data)[i])) {')
fn_builder.writeln('\t\tif (!${eq_fn}_sumtype_eq(((${ptr_elem_styp}*)${left_data})[i], ((${ptr_elem_styp}*)${right_data})[i])) {')
} else if elem.sym.kind == .struct_ && !elem.typ.is_ptr() {
eq_fn := g.gen_struct_equality_fn(elem.typ)
fn_builder.writeln('\t\tif (!${eq_fn}_struct_eq(((${ptr_elem_styp}*)a.data)[i], ((${ptr_elem_styp}*)b.data)[i])) {')
fn_builder.writeln('\t\tif (!${eq_fn}_struct_eq(((${ptr_elem_styp}*)${left_data})[i], ((${ptr_elem_styp}*)${right_data})[i])) {')
} else if elem.sym.kind == .interface_ && !elem.typ.is_ptr() {
eq_fn := g.gen_interface_equality_fn(elem.typ)
fn_builder.writeln('\t\tif (!${eq_fn}_interface_eq(((${ptr_elem_styp}*)a.data)[i], ((${ptr_elem_styp}*)b.data)[i])) {')
fn_builder.writeln('\t\tif (!${eq_fn}_interface_eq(((${ptr_elem_styp}*)${left_data})[i], ((${ptr_elem_styp}*)${right_data})[i])) {')
} else if elem.sym.kind == .array && !elem.typ.is_ptr() {
eq_fn := g.gen_array_equality_fn(elem.typ)
fn_builder.writeln('\t\tif (!${eq_fn}_arr_eq(((${ptr_elem_styp}*)a.data)[i], ((${ptr_elem_styp}*)b.data)[i])) {')
fn_builder.writeln('\t\tif (!${eq_fn}_arr_eq(((${ptr_elem_styp}*)${left_data})[i], ((${ptr_elem_styp}*)${right_data})[i])) {')
} else if elem.sym.kind == .array_fixed && !elem.typ.is_ptr() {
eq_fn := g.gen_fixed_array_equality_fn(elem.typ)
fn_builder.writeln('\t\tif (!${eq_fn}_arr_eq(((${ptr_elem_styp}*)a.data)[i], ((${ptr_elem_styp}*)b.data)[i])) {')
fn_builder.writeln('\t\tif (!${eq_fn}_arr_eq(((${ptr_elem_styp}*)${left_data})[i], ((${ptr_elem_styp}*)${right_data})[i])) {')
} else if elem.sym.kind == .map && !elem.typ.is_ptr() {
eq_fn := g.gen_map_equality_fn(elem.typ)
fn_builder.writeln('\t\tif (!${eq_fn}_map_eq(((${ptr_elem_styp}*)a.data)[i], ((${ptr_elem_styp}*)b.data)[i])) {')
fn_builder.writeln('\t\tif (!${eq_fn}_map_eq(((${ptr_elem_styp}*)${left_data})[i], ((${ptr_elem_styp}*)${right_data})[i])) {')
} else if elem.sym.kind == .alias && !elem.typ.is_ptr() {
eq_fn := g.gen_alias_equality_fn(elem.typ)
fn_builder.writeln('\t\tif (!${eq_fn}_alias_eq(((${ptr_elem_styp}*)a.data)[i], ((${ptr_elem_styp}*)b.data)[i])) {')
fn_builder.writeln('\t\tif (!${eq_fn}_alias_eq(((${ptr_elem_styp}*)${left_data})[i], ((${ptr_elem_styp}*)${right_data})[i])) {')
} else if elem.sym.kind == .function {
fn_builder.writeln('\t\tif (*((voidptr*)((byte*)a.data+(i*a.element_size))) != *((voidptr*)((byte*)b.data+(i*b.element_size)))) {')
fn_builder.writeln('\t\tif (*((voidptr*)((byte*)${left_data}+(i*${left_elem}))) != *((voidptr*)((byte*)${right_data}+(i*${right_elem})))) {')
} else {
fn_builder.writeln('\t\tif (*((${ptr_elem_styp}*)((byte*)a.data+(i*a.element_size))) != *((${ptr_elem_styp}*)((byte*)b.data+(i*b.element_size)))) {')
fn_builder.writeln('\t\tif (*((${ptr_elem_styp}*)((byte*)${left_data}+(i*${left_elem}))) != *((${ptr_elem_styp}*)((byte*)${right_data}+(i*${right_elem})))) {')
}
fn_builder.writeln('\t\t\treturn false;')
fn_builder.writeln('\t\t}')
@ -457,6 +474,7 @@ fn (mut g Gen) gen_map_equality_fn(left_type ast.Type) string {
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))
idx_fn := g.typ(left.typ.set_nr_muls(0).clear_flag(.option))
fn_name := ptr_styp.replace('interface ', '')
if left_type in g.generated_eq_fns {
return fn_name
@ -471,12 +489,12 @@ fn (mut g Gen) gen_interface_equality_fn(left_type ast.Type) string {
}
left_arg := g.read_field(left_type, '_typ', 'a')
right_arg := g.read_field(left_type, '_typ', 'a')
right_arg := g.read_field(left_type, '_typ', 'b')
fn_builder.writeln('static int v_typeof_interface_idx_${ptr_styp}(int sidx); // for auto eq method')
fn_builder.writeln('static int v_typeof_interface_idx_${idx_fn}(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 (${left_arg} == ${right_arg}) {')
fn_builder.writeln('\t\tint idx = v_typeof_interface_idx_${ptr_styp}(${left_arg});')
fn_builder.writeln('\t\tint idx = v_typeof_interface_idx_${idx_fn}(${left_arg});')
if info is ast.Interface {
for typ in info.types {
fn_builder.writeln('\t\tif (idx == ${typ.idx()}) {')
@ -484,30 +502,44 @@ fn (mut g Gen) gen_interface_equality_fn(left_type ast.Type) string {
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}))')
l_eqfn := g.read_field(left_type, '_${eq_fn}', 'a')
r_eqfn := g.read_field(left_type, '_${eq_fn}', 'b')
fn_builder.write_string('${eq_fn}_struct_eq(*(${l_eqfn}), *(${r_eqfn}))')
}
.string {
fn_builder.write_string('string__eq(*(a._string), *(b._string))')
l_str := g.read_field(left_type, '_string', 'a')
r_str := g.read_field(left_type, '_string', 'b')
fn_builder.write_string('string__eq(*(${l_str}), *(${r_str}))')
}
.sum_type {
eq_fn := g.gen_sumtype_equality_fn(typ)
fn_builder.write_string('${eq_fn}_sumtype_eq(*(a._${eq_fn}), *(b._${eq_fn}))')
l_eqfn := g.read_field(left_type, '_${eq_fn}', 'a')
r_eqfn := g.read_field(left_type, '_${eq_fn}', 'b')
fn_builder.write_string('${eq_fn}_sumtype_eq(*(${l_eqfn}), *(${r_eqfn}))')
}
.array {
eq_fn := g.gen_array_equality_fn(typ)
fn_builder.write_string('${eq_fn}_arr_eq(*(a._${eq_fn}), *(b._${eq_fn}))')
l_eqfn := g.read_field(left_type, '_${eq_fn}', 'a')
r_eqfn := g.read_field(left_type, '_${eq_fn}', 'b')
fn_builder.write_string('${eq_fn}_arr_eq(*(${l_eqfn}), *(${r_eqfn}))')
}
.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}))')
l_eqfn := g.read_field(left_type, '_${eq_fn}', 'a')
r_eqfn := g.read_field(left_type, '_${eq_fn}', 'b')
fn_builder.write_string('${eq_fn}_arr_eq(*(${l_eqfn}), *(${r_eqfn}))')
}
.map {
eq_fn := g.gen_map_equality_fn(typ)
fn_builder.write_string('${eq_fn}_map_eq(*(a._${eq_fn}), *(b._${eq_fn}))')
l_eqfn := g.read_field(left_type, '_${eq_fn}', 'a')
r_eqfn := g.read_field(left_type, '_${eq_fn}', 'b')
fn_builder.write_string('${eq_fn}_map_eq(*(${l_eqfn}), *(${r_eqfn}))')
}
.alias {
eq_fn := g.gen_alias_equality_fn(typ)
fn_builder.write_string('${eq_fn}_alias_eq(*(a._${eq_fn}), *(b._${eq_fn}))')
l_eqfn := g.read_field(left_type, '_${eq_fn}', 'a')
r_eqfn := g.read_field(left_type, '_${eq_fn}', 'b')
fn_builder.write_string('${eq_fn}_alias_eq(*(${l_eqfn}), *(${r_eqfn}))')
}
else {
fn_builder.write_string('true')

View File

@ -0,0 +1,88 @@
interface Interface {
a ?int
}
struct Test2 {
a ?int
}
type Alias = int
type AliasStruct = Test2
type AliasStruct2 = fn ()
type AliasStruct3 = []int
type SumType = Alias | AliasStruct2 | f64 | int
struct Test {
mut:
a ?int
b ?f64
c ?string
d ?[]int
e ?[]string
f ?[]f64
g ?fn ()
h ?Alias
i ?Interface = Test2{
a: -1
}
j ?AliasStruct
k ?AliasStruct2
l ?AliasStruct3
m ?SumType
n SumType
}
fn test_simple_compare() {
mut a := Test{}
mut b := Test{}
assert a == b
}
fn test_anon_compare() {
z := fn () {}
d := fn () {}
mut a := Test{}
mut b := Test{}
assert a == b
a.g = z
b.g = d
assert a != b
}
fn test_alias_compare() {
z := 1
d := 2
mut a := Test{}
mut b := Test{}
assert a == b
a.h = z
b.h = d
assert a != b
}
fn test_iface_compare() {
z := Test2{
a: -1
}
d := Test2{
a: 0
}
mut a := Test{
a: 0
}
mut b := Test{
a: 0
}
assert a == b
a.i = z
b.i = d
assert a != b
}