checker: fix "unregistered" variadic interface call arguments (#12525)

pull/12529/head
Ned 2021-11-21 00:15:20 +08:00 committed by GitHub
parent 90ba856107
commit 82010e729d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 28 additions and 4 deletions

View File

@ -2173,12 +2173,14 @@ pub fn (mut c Checker) method_call(mut node ast.CallExpr) ast.Type {
arg.pos) arg.pos)
} }
mut final_arg_sym := exp_arg_sym mut final_arg_sym := exp_arg_sym
mut final_arg_typ := exp_arg_typ
if method.is_variadic && exp_arg_sym.info is ast.Array { if method.is_variadic && exp_arg_sym.info is ast.Array {
final_arg_sym = c.table.get_type_symbol(exp_arg_sym.array_info().elem_type) final_arg_typ = exp_arg_sym.array_info().elem_type
final_arg_sym = c.table.get_type_symbol(final_arg_typ)
} }
// Handle expected interface // Handle expected interface
if final_arg_sym.kind == .interface_ { if final_arg_sym.kind == .interface_ {
if c.type_implements(got_arg_typ, exp_arg_typ, arg.expr.position()) { if c.type_implements(got_arg_typ, final_arg_typ, arg.expr.position()) {
if !got_arg_typ.is_ptr() && !got_arg_typ.is_pointer() && !c.inside_unsafe { if !got_arg_typ.is_ptr() && !got_arg_typ.is_pointer() && !c.inside_unsafe {
got_arg_typ_sym := c.table.get_type_symbol(got_arg_typ) got_arg_typ_sym := c.table.get_type_symbol(got_arg_typ)
if got_arg_typ_sym.kind != .interface_ { if got_arg_typ_sym.kind != .interface_ {
@ -2849,8 +2851,10 @@ pub fn (mut c Checker) fn_call(mut node ast.CallExpr, mut continue_check &bool)
} }
} }
mut final_param_sym := param_typ_sym mut final_param_sym := param_typ_sym
mut final_param_typ := param.typ
if func.is_variadic && param_typ_sym.info is ast.Array { if func.is_variadic && param_typ_sym.info is ast.Array {
final_param_sym = c.table.get_type_symbol(param_typ_sym.array_info().elem_type) final_param_typ = param_typ_sym.array_info().elem_type
final_param_sym = c.table.get_type_symbol(final_param_typ)
} }
// NB: Casting to voidptr is used as an escape mechanism, so: // NB: Casting to voidptr is used as an escape mechanism, so:
// 1. allow passing *explicit* voidptr (native or through cast) to functions // 1. allow passing *explicit* voidptr (native or through cast) to functions
@ -2867,7 +2871,7 @@ pub fn (mut c Checker) fn_call(mut node ast.CallExpr, mut continue_check &bool)
} }
// Handle expected interface // Handle expected interface
if final_param_sym.kind == .interface_ { if final_param_sym.kind == .interface_ {
if c.type_implements(typ, param.typ, call_arg.expr.position()) { if c.type_implements(typ, final_param_typ, call_arg.expr.position()) {
if !typ.is_ptr() && !typ.is_pointer() && !c.inside_unsafe if !typ.is_ptr() && !typ.is_pointer() && !c.inside_unsafe
&& typ_sym.kind != .interface_ { && typ_sym.kind != .interface_ {
c.mark_as_referenced(mut &call_arg.expr, true) c.mark_as_referenced(mut &call_arg.expr, true)

View File

@ -366,3 +366,23 @@ fn main() {
println(dog.name) println(dog.name)
println(get_animal_name(mut dog)) println(get_animal_name(mut dog))
} }
type Text = string
fn (t Text) display() string {
return t
}
interface Displayable {
display() string
}
fn print_displayable(ds ...Displayable) {
for d in ds {
println(d.display())
}
}
fn test_variadic_interface() {
print_displayable(Text('test'), Text('hehe'))
}