gen: fix interface pointers

pull/4828/head
Enzo Baldisserri 2020-05-10 21:16:22 +02:00 committed by GitHub
parent 40aad27a67
commit b09fd66aa2
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 72 additions and 5 deletions

View File

@ -3660,6 +3660,14 @@ _Interface I_${cctype}_to_Interface_${interface_name}(${cctype}* x) {
._object = (void*) (x),
._interface_idx = ${interface_index_name}
};
}
_Interface* I_${cctype}_to_Interface_${interface_name}_ptr(${cctype}* x) {
/* TODO Remove memdup */
return (_Interface*) memdup(&(_Interface) {
._object = (void*) (x),
._interface_idx = ${interface_index_name}
}, sizeof(_Interface));
}')
methods_struct.writeln('\t{')
st_sym := g.table.get_type_symbol(st)
@ -3766,7 +3774,11 @@ fn (mut g Gen) array_init(it ast.ArrayInit) {
fn (g &Gen) interface_call(typ, interface_type table.Type) {
interface_styp := g.cc_type(interface_type)
styp := g.cc_type(typ)
g.write('/* $interface_styp */ I_${styp}_to_Interface_${interface_styp}(')
mut cast_fn_name := 'I_${styp}_to_Interface_${interface_styp}'
if interface_type.is_ptr() {
cast_fn_name += '_ptr'
}
g.write('${cast_fn_name}(')
if !typ.is_ptr() {
g.write('&')
}

View File

@ -298,9 +298,10 @@ fn (mut g Gen) method_call(node ast.CallExpr) {
// Speaker_name_table[s._interface_idx].speak(s._object)
g.write('${c_name(receiver_type_name)}_name_table[')
g.expr(node.left)
g.write('._interface_idx].${node.name}(')
dot := if node.left_type.is_ptr() { '->' } else { '.' }
g.write('${dot}_interface_idx].${node.name}(')
g.expr(node.left)
g.write('._object')
g.write('${dot}_object')
if node.args.len > 0 {
g.write(', ')
g.call_args(node.args, node.expected_arg_types)
@ -554,11 +555,14 @@ fn (mut g Gen) call_args(args []ast.CallArg, expected_types []table.Type) {
// styp := g.typ(arg.typ) // g.table.get_type_symbol(arg.typ)
if exp_sym.kind == .interface_ {
g.interface_call(arg.typ, expected_types[i])
// g.write('/*Z*/I_${styp}_to_${exp_styp}(')
is_interface = true
}
}
g.ref_or_deref_arg(arg, expected_types[i])
if is_interface {
g.expr(arg.expr)
} else {
g.ref_or_deref_arg(arg, expected_types[i])
}
} else {
g.expr(arg.expr)
}

View File

@ -3,6 +3,7 @@ struct Dog {
}
struct Cat {
mut:
breed string
}
@ -25,6 +26,10 @@ fn (c Cat) name_detailed(pet_name string) string {
return '$pet_name the ${typeof(c)}, breed:${c.breed}'
}
fn (c mut Cat) set_breed(new string) {
c.breed = new
}
// utility function to convert to string, as a sample
fn (c Cat) str() string {
return 'Cat: $c.breed'
@ -44,6 +49,10 @@ fn (d Dog) name_detailed(pet_name string) string {
return '$pet_name the ${typeof(d)}, breed:${d.breed}'
}
fn (d mut Dog) set_breed(new string) {
println('Nah')
}
// do not add to Dog the utility function 'str', as a sample
fn test_todo() {
if true {
@ -62,11 +71,23 @@ fn perform_speak(a Animal) {
println(a.name())
}
fn perform_speak_on_ptr(a &Animal) {
a.speak('Hi !')
assert true
name := a.name()
assert name == 'Dog' || name == 'Cat'
// if a is Dog {
// assert name == 'Dog'
// }
println(a.name())
}
fn test_perform_speak() {
dog := Dog{
breed: 'Labrador Retriever'
}
perform_speak(dog)
perform_speak_on_ptr(dog)
cat := Cat{
breed: 'Persian'
}
@ -74,6 +95,10 @@ fn test_perform_speak() {
perform_speak(Cat{
breed: 'Persian'
})
perform_speak_on_ptr(cat)
perform_speak_on_ptr(Cat{
breed: 'Persian'
})
handle_animals([dog, cat])
/*
f := Foo {
@ -82,6 +107,19 @@ fn test_perform_speak() {
*/
}
fn change_animal_breed(a &Animal, new string) {
a.set_breed(new)
}
fn test_interface_ptr_modification() {
mut cat := Cat{
breed: 'Persian'
}
// TODO Should fail and require `mut cat`
change_animal_breed(cat, 'Siamese')
assert cat.breed == 'Siamese'
}
fn perform_name_detailed(a Animal) {
name_full := a.name_detailed('MyPet')
println(name_full)
@ -142,6 +180,7 @@ interface Animal {
name() string
name_detailed(pet_name string) string
speak(s string)
set_breed(s string)
}
fn test_interface_array() {
@ -150,6 +189,7 @@ fn test_interface_array() {
animals = [Cat{}, Dog{
breed: 'Labrador Retriever'
}]
assert true
animals << Cat{}
assert true
// TODO .str() from the real types should be called
@ -157,3 +197,14 @@ fn test_interface_array() {
// println('Animals array contains: ${animals}') // implicit call to 'str' function
assert animals.len == 3
}
fn test_interface_ptr_array() {
mut animals := []&Animal{}
animals = [Cat{}, Dog{
breed: 'Labrador Retriever'
}]
assert true
animals << Cat{}
assert true
assert animals.len == 3
}