checker: stricter check for function type signatures
parent
bb6ab185c3
commit
db4a9d6b59
|
@ -8,6 +8,9 @@ import v.token
|
||||||
import v.ast
|
import v.ast
|
||||||
|
|
||||||
pub fn (c &Checker) check_basic(got, expected table.Type) bool {
|
pub fn (c &Checker) check_basic(got, expected table.Type) bool {
|
||||||
|
if got == expected {
|
||||||
|
return true
|
||||||
|
}
|
||||||
t := c.table
|
t := c.table
|
||||||
got_idx := t.unalias_num_type(got).idx()
|
got_idx := t.unalias_num_type(got).idx()
|
||||||
exp_idx := t.unalias_num_type(expected).idx()
|
exp_idx := t.unalias_num_type(expected).idx()
|
||||||
|
@ -117,25 +120,43 @@ pub fn (c &Checker) check_basic(got, expected table.Type) bool {
|
||||||
}
|
}
|
||||||
// fn type
|
// fn type
|
||||||
if got_type_sym.kind == .function && exp_type_sym.kind == .function {
|
if got_type_sym.kind == .function && exp_type_sym.kind == .function {
|
||||||
got_info := got_type_sym.info as table.FnType
|
return c.check_matching_function_symbols(got_type_sym, exp_type_sym)
|
||||||
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) {
|
|
||||||
for i, got_arg in got_fn.args {
|
|
||||||
exp_arg := exp_fn.args[i]
|
|
||||||
if !c.check_basic(got_arg.typ, exp_arg.typ) {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return false
|
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 {
|
||||||
|
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
|
||||||
|
}
|
||||||
|
|
||||||
[inline]
|
[inline]
|
||||||
fn (c &Checker) check_shift(left_type, right_type table.Type, left_pos, right_pos token.Position) table.Type {
|
fn (c &Checker) check_shift(left_type, right_type table.Type, left_pos, right_pos token.Position) table.Type {
|
||||||
if !left_type.is_int() {
|
if !left_type.is_int() {
|
||||||
|
@ -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
|
// TODO: promote(), check_types(), symmetric_check() and check() overlap - should be rearranged
|
||||||
pub fn (c &Checker) check_types(got, expected table.Type) bool {
|
pub fn (c &Checker) check_types(got, expected table.Type) bool {
|
||||||
|
if got == expected {
|
||||||
|
return true
|
||||||
|
}
|
||||||
exp_idx := expected.idx()
|
exp_idx := expected.idx()
|
||||||
got_idx := got.idx()
|
got_idx := got.idx()
|
||||||
if exp_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
|
return true
|
||||||
}
|
}
|
||||||
*/
|
*/
|
||||||
|
|
||||||
if !c.check_types(typ, arg.typ) {
|
if !c.check_types(typ, arg.typ) {
|
||||||
// str method, allow type with str method if fn arg is string
|
// str method, allow type with str method if fn arg is string
|
||||||
if arg_typ_sym.kind == .string && typ_sym.has_method('str') {
|
if arg_typ_sym.kind == .string && typ_sym.has_method('str') {
|
||||||
|
|
|
@ -641,7 +641,10 @@ pub fn (k Kind) str() string {
|
||||||
.alias { 'alias' }
|
.alias { 'alias' }
|
||||||
.enum_ { 'enum' }
|
.enum_ { 'enum' }
|
||||||
.any { 'any' }
|
.any { 'any' }
|
||||||
else { 'unknown' }
|
.function { 'function' }
|
||||||
|
.interface_ { 'interface' }
|
||||||
|
.ustring { 'ustring' }
|
||||||
|
.generic_struct_inst { 'generic_struct_inst' }
|
||||||
}
|
}
|
||||||
return k_str
|
return k_str
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue