checker: fix interface checking of array arguments; closes #2377

pull/7220/head^2
Delyan Angelov 2020-12-09 18:51:37 +02:00
parent 3b94a2b77a
commit 8caf3829d7
No known key found for this signature in database
GPG Key ID: 66886C0F12D595ED
5 changed files with 67 additions and 6 deletions

View File

@ -1575,12 +1575,6 @@ pub fn (mut c Checker) call_fn(mut call_expr ast.CallExpr) table.Type {
c.type_implements(typ, arg.typ, call_arg.expr.position())
continue
}
// Handle expected interface array
/*
if exp_type_sym.kind == .array && t.get_type_symbol(t.value_type(exp_idx)).kind == .interface_ {
return true
}
*/
c.check_expected(typ, arg.typ) or {
// str method, allow type with str method if fn arg is string
// Passing an int or a string array produces a c error here
@ -1631,6 +1625,9 @@ pub fn (mut c Checker) call_fn(mut call_expr ast.CallExpr) table.Type {
}
fn (mut c Checker) type_implements(typ table.Type, inter_typ table.Type, pos token.Position) bool {
$if debug_interface_type_implements ? {
eprintln('> type_implements typ: $typ.debug() | inter_typ: $inter_typ.debug()')
}
typ_sym := c.table.get_type_symbol(typ)
mut inter_sym := c.table.get_type_symbol(inter_typ)
styp := c.table.type_to_str(typ)
@ -2388,6 +2385,7 @@ pub fn (mut c Checker) array_init(mut array_init ast.ArrayInit) table.Type {
if i == 0 {
elem_type = expected_value_type
c.expected_type = elem_type
c.type_implements(typ, elem_type, expr.position())
}
continue
}

View File

@ -5638,6 +5638,10 @@ fn (mut g Gen) interface_table() string {
// cctype is the Cleaned Concrete Type name, *without ptr*,
// i.e. cctype is always just Cat, not Cat_ptr:
cctype := g.cc_type(st)
$if debug_interface_table ? {
eprintln('>> interface name: $ityp.name | concrete type: $st.debug() | st symname: ' +
g.table.get_type_symbol(st).name)
}
// Speaker_Cat_index = 0
interface_index_name := '_${interface_name}_${cctype}_index'
if already_generated_mwrappers[interface_index_name] > 0 {

View File

@ -324,6 +324,9 @@ fn (mut g Gen) method_call(node ast.CallExpr) {
mut receiver_type_name := util.no_dots(g.cc_type2(g.unwrap_generic(node.receiver_type)))
if typ_sym.kind == .interface_ {
// Speaker_name_table[s._interface_idx].speak(s._object)
$if debug_interface_method_call ? {
eprintln('>>> interface typ_sym.name: $typ_sym.name | receiver_type_name: $receiver_type_name')
}
g.write('${c_name(receiver_type_name)}_name_table[')
g.expr(node.left)
dot := if node.left_type.is_ptr() { '->' } else { '.' }

View File

@ -0,0 +1,28 @@
struct Dog {
breed string
}
fn (d Dog) name() string {
return 'Dog'
}
// Utility helper function, to force interface _name_table generation
fn get_name(s Speaker) {
}
//
fn test_an_array_of_interfaces_works() {
dog := Dog{}
// get_name(dog) // uncommenting this line fixes the example
get_names([dog, dog])
}
fn get_names(speakers []Speaker) {
for s in speakers {
println(s.name())
}
}
interface Speaker {
name() string
}

View File

@ -0,0 +1,28 @@
struct Dog {
breed string
}
fn (d Dog) name() string {
return 'Dog'
}
// Utility helper function, to force interface _name_table generation
fn get_name(s Speaker) {
}
//
fn test_an_array_of_interfaces_works() {
dog := Dog{}
get_name(dog) // NB: this line does nothing, but forces interface _name_table generation
get_names([dog, dog])
}
fn get_names(speakers []Speaker) {
for s in speakers {
println(s.name())
}
}
interface Speaker {
name() string
}