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), ._object = (void*) (x),
._interface_idx = ${interface_index_name} ._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{') methods_struct.writeln('\t{')
st_sym := g.table.get_type_symbol(st) 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) { fn (g &Gen) interface_call(typ, interface_type table.Type) {
interface_styp := g.cc_type(interface_type) interface_styp := g.cc_type(interface_type)
styp := g.cc_type(typ) 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() { if !typ.is_ptr() {
g.write('&') 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) // Speaker_name_table[s._interface_idx].speak(s._object)
g.write('${c_name(receiver_type_name)}_name_table[') g.write('${c_name(receiver_type_name)}_name_table[')
g.expr(node.left) 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.expr(node.left)
g.write('._object') g.write('${dot}_object')
if node.args.len > 0 { if node.args.len > 0 {
g.write(', ') g.write(', ')
g.call_args(node.args, node.expected_arg_types) 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) // styp := g.typ(arg.typ) // g.table.get_type_symbol(arg.typ)
if exp_sym.kind == .interface_ { if exp_sym.kind == .interface_ {
g.interface_call(arg.typ, expected_types[i]) g.interface_call(arg.typ, expected_types[i])
// g.write('/*Z*/I_${styp}_to_${exp_styp}(')
is_interface = true is_interface = true
} }
} }
if is_interface {
g.expr(arg.expr)
} else {
g.ref_or_deref_arg(arg, expected_types[i]) g.ref_or_deref_arg(arg, expected_types[i])
}
} else { } else {
g.expr(arg.expr) g.expr(arg.expr)
} }

View File

@ -3,6 +3,7 @@ struct Dog {
} }
struct Cat { struct Cat {
mut:
breed string breed string
} }
@ -25,6 +26,10 @@ fn (c Cat) name_detailed(pet_name string) string {
return '$pet_name the ${typeof(c)}, breed:${c.breed}' 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 // utility function to convert to string, as a sample
fn (c Cat) str() string { fn (c Cat) str() string {
return 'Cat: $c.breed' 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}' 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 // do not add to Dog the utility function 'str', as a sample
fn test_todo() { fn test_todo() {
if true { if true {
@ -62,11 +71,23 @@ fn perform_speak(a Animal) {
println(a.name()) 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() { fn test_perform_speak() {
dog := Dog{ dog := Dog{
breed: 'Labrador Retriever' breed: 'Labrador Retriever'
} }
perform_speak(dog) perform_speak(dog)
perform_speak_on_ptr(dog)
cat := Cat{ cat := Cat{
breed: 'Persian' breed: 'Persian'
} }
@ -74,6 +95,10 @@ fn test_perform_speak() {
perform_speak(Cat{ perform_speak(Cat{
breed: 'Persian' breed: 'Persian'
}) })
perform_speak_on_ptr(cat)
perform_speak_on_ptr(Cat{
breed: 'Persian'
})
handle_animals([dog, cat]) handle_animals([dog, cat])
/* /*
f := Foo { 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) { fn perform_name_detailed(a Animal) {
name_full := a.name_detailed('MyPet') name_full := a.name_detailed('MyPet')
println(name_full) println(name_full)
@ -142,6 +180,7 @@ interface Animal {
name() string name() string
name_detailed(pet_name string) string name_detailed(pet_name string) string
speak(s string) speak(s string)
set_breed(s string)
} }
fn test_interface_array() { fn test_interface_array() {
@ -150,6 +189,7 @@ fn test_interface_array() {
animals = [Cat{}, Dog{ animals = [Cat{}, Dog{
breed: 'Labrador Retriever' breed: 'Labrador Retriever'
}] }]
assert true
animals << Cat{} animals << Cat{}
assert true assert true
// TODO .str() from the real types should be called // 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 // println('Animals array contains: ${animals}') // implicit call to 'str' function
assert animals.len == 3 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
}