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:
parent
0a8a0fdb0e
commit
24cc5920e6
@ -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')
|
||||
|
88
vlib/v/tests/option_struct_compare_test.v
Normal file
88
vlib/v/tests/option_struct_compare_test.v
Normal 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
|
||||
}
|
Loading…
Reference in New Issue
Block a user