cgen: implement eq operator for interfaces (#12047)

pull/12051/head
05st 2021-10-03 01:04:05 -05:00 committed by GitHub
parent f282e64fe3
commit 129c81f34d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 110 additions and 1 deletions

View File

@ -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
}

View File

@ -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]

View File

@ -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'
})
}