From db4a9d6b590b02a9d666acb0cae8c0009c385e5e Mon Sep 17 00:00:00 2001 From: Delyan Angelov Date: Sat, 4 Jul 2020 20:58:10 +0300 Subject: [PATCH] checker: stricter check for function type signatures --- vlib/v/checker/check_types.v | 54 ++++++++++++++++++++++++++---------- vlib/v/checker/checker.v | 1 + vlib/v/table/atypes.v | 5 +++- 3 files changed, 44 insertions(+), 16 deletions(-) diff --git a/vlib/v/checker/check_types.v b/vlib/v/checker/check_types.v index d63b48af09..3736530158 100644 --- a/vlib/v/checker/check_types.v +++ b/vlib/v/checker/check_types.v @@ -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,25 +120,43 @@ pub fn (c &Checker) check_basic(got, expected table.Type) bool { } // fn type if got_type_sym.kind == .function && exp_type_sym.kind == .function { - 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) { - 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 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 { + 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] fn (c &Checker) check_shift(left_type, right_type table.Type, left_pos, right_pos token.Position) table.Type { 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 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 { diff --git a/vlib/v/checker/checker.v b/vlib/v/checker/checker.v index e3b4cb6953..badcde628e 100644 --- a/vlib/v/checker/checker.v +++ b/vlib/v/checker/checker.v @@ -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') { diff --git a/vlib/v/table/atypes.v b/vlib/v/table/atypes.v index c186db3c53..00a615e593 100644 --- a/vlib/v/table/atypes.v +++ b/vlib/v/table/atypes.v @@ -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 }