checker: stricter check for function type signatures
parent
bb6ab185c3
commit
db4a9d6b59
|
@ -8,6 +8,9 @@ import v.token
|
|||
import v.ast
|
||||
|
||||
pub fn (c &Checker) check_basic(got, expected table.Type) bool {
|
||||
if got == expected {
|
||||
return true
|
||||
}
|
||||
t := c.table
|
||||
got_idx := t.unalias_num_type(got).idx()
|
||||
exp_idx := t.unalias_num_type(expected).idx()
|
||||
|
@ -117,24 +120,42 @@ pub fn (c &Checker) check_basic(got, expected table.Type) bool {
|
|||
}
|
||||
// fn type
|
||||
if got_type_sym.kind == .function && exp_type_sym.kind == .function {
|
||||
return c.check_matching_function_symbols(got_type_sym, exp_type_sym)
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
pub fn (c &Checker) check_matching_function_symbols(got_type_sym &table.TypeSymbol, exp_type_sym &table.TypeSymbol) bool {
|
||||
got_info := got_type_sym.info as table.FnType
|
||||
exp_info := exp_type_sym.info as table.FnType
|
||||
got_fn := got_info.func
|
||||
exp_fn := exp_info.func
|
||||
// we are using check() to compare return type & args as they might include
|
||||
// functions themselves. TODO: optimize, only use check() when needed
|
||||
if got_fn.args.len == exp_fn.args.len && c.check_basic(got_fn.return_type, exp_fn.return_type) {
|
||||
if got_fn.args.len != exp_fn.args.len {
|
||||
return false
|
||||
}
|
||||
if !c.check_basic(got_fn.return_type, exp_fn.return_type) {
|
||||
return false
|
||||
}
|
||||
for i, got_arg in got_fn.args {
|
||||
exp_arg := exp_fn.args[i]
|
||||
exp_arg_is_ptr := exp_arg.typ.is_ptr() || exp_arg.typ.is_pointer()
|
||||
got_arg_is_ptr := got_arg.typ.is_ptr() || got_arg.typ.is_pointer()
|
||||
if exp_arg_is_ptr != got_arg_is_ptr {
|
||||
$if debug_matching_function_symbols ? {
|
||||
exp_arg_pointedness := if exp_arg_is_ptr { 'a pointer' } else { 'NOT a pointer' }
|
||||
got_arg_pointedness := if got_arg_is_ptr { 'a pointer' } else { 'NOT a pointer' }
|
||||
eprintln('`$exp_fn.name` expected fn argument: `$exp_arg.name` is $exp_arg_pointedness, but `$got_fn.name` actual fn argument: `$got_arg.name` is $got_arg_pointedness')
|
||||
}
|
||||
return false
|
||||
}
|
||||
if !c.check_basic(got_arg.typ, exp_arg.typ) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
[inline]
|
||||
fn (c &Checker) check_shift(left_type, right_type table.Type, left_pos, right_pos token.Position) table.Type {
|
||||
|
@ -215,6 +236,9 @@ fn (c &Checker) promote_num(left_type, right_type table.Type) table.Type {
|
|||
|
||||
// TODO: promote(), check_types(), symmetric_check() and check() overlap - should be rearranged
|
||||
pub fn (c &Checker) check_types(got, expected table.Type) bool {
|
||||
if got == expected {
|
||||
return true
|
||||
}
|
||||
exp_idx := expected.idx()
|
||||
got_idx := got.idx()
|
||||
if exp_idx == got_idx {
|
||||
|
|
|
@ -1180,6 +1180,7 @@ pub fn (mut c Checker) call_fn(mut call_expr ast.CallExpr) table.Type {
|
|||
return true
|
||||
}
|
||||
*/
|
||||
|
||||
if !c.check_types(typ, arg.typ) {
|
||||
// str method, allow type with str method if fn arg is string
|
||||
if arg_typ_sym.kind == .string && typ_sym.has_method('str') {
|
||||
|
|
|
@ -641,7 +641,10 @@ pub fn (k Kind) str() string {
|
|||
.alias { 'alias' }
|
||||
.enum_ { 'enum' }
|
||||
.any { 'any' }
|
||||
else { 'unknown' }
|
||||
.function { 'function' }
|
||||
.interface_ { 'interface' }
|
||||
.ustring { 'ustring' }
|
||||
.generic_struct_inst { 'generic_struct_inst' }
|
||||
}
|
||||
return k_str
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue