From b6c4e884629258d079cb5d104bdcd44c60dafc49 Mon Sep 17 00:00:00 2001 From: yuyi Date: Wed, 8 Mar 2023 04:49:53 +0800 Subject: [PATCH] checker: check error of casting to interface (fix #17522) (#17531) --- vlib/v/checker/checker.v | 9 ++++++-- .../v/checker/tests/cast_to_interface_err.out | 12 +++++++++++ vlib/v/checker/tests/cast_to_interface_err.vv | 21 +++++++++++++++++++ ...x_is_notis_interface_unimplemented_err.out | 16 +++++++++++++- .../tests/mut_receiver_wrong_return_type.out | 13 ++++++++++++ 5 files changed, 68 insertions(+), 3 deletions(-) create mode 100644 vlib/v/checker/tests/cast_to_interface_err.out create mode 100644 vlib/v/checker/tests/cast_to_interface_err.vv diff --git a/vlib/v/checker/checker.v b/vlib/v/checker/checker.v index 1c5ca957c..9bd36b90d 100644 --- a/vlib/v/checker/checker.v +++ b/vlib/v/checker/checker.v @@ -913,8 +913,8 @@ fn (mut c Checker) type_implements(typ ast.Type, interface_type ast.Type, pos to // TODO: remove once deprecation period for `IError` methods has ended if inter_sym.idx == ast.error_type_idx && (imethod.name == 'msg' || imethod.name == 'code') { - // c.note("`$styp` doesn't implement method `$imethod.name` of interface `$inter_sym.name`. The usage of fields is being deprecated in favor of methods.", - // pos) + c.note("`${styp}` doesn't implement method `${imethod.name}` of interface `${inter_sym.name}`. The usage of fields is being deprecated in favor of methods.", + pos) return false } // << @@ -2828,6 +2828,11 @@ fn (mut c Checker) cast_expr(mut node ast.CastExpr) ast.Type { final_to_sym = c.table.final_sym(to_type) } } + } else { + ft := c.table.type_to_str(from_type) + tt := c.table.type_to_str(to_type) + c.error('`${ft}` does not implement interface `${tt}`, cannot cast `${ft}` to interface `${tt}`', + node.pos) } } else if to_type == ast.bool_type && from_type != ast.bool_type && !c.inside_unsafe && !c.pref.translated && !c.file.is_translated { diff --git a/vlib/v/checker/tests/cast_to_interface_err.out b/vlib/v/checker/tests/cast_to_interface_err.out new file mode 100644 index 000000000..b0bae1f83 --- /dev/null +++ b/vlib/v/checker/tests/cast_to_interface_err.out @@ -0,0 +1,12 @@ +vlib/v/checker/tests/cast_to_interface_err.vv:20:9: notice: `CustomError` doesn't implement method `msg` of interface `IError`. The usage of fields is being deprecated in favor of methods. + 18 | + 19 | fn my_error() IError { + 20 | return IError(CustomError{}) + | ~~~~~~~~~~~~~~~~~~~~~ + 21 | } +vlib/v/checker/tests/cast_to_interface_err.vv:20:9: error: `CustomError` does not implement interface `IError`, cannot cast `CustomError` to interface `IError` + 18 | + 19 | fn my_error() IError { + 20 | return IError(CustomError{}) + | ~~~~~~~~~~~~~~~~~~~~~ + 21 | } diff --git a/vlib/v/checker/tests/cast_to_interface_err.vv b/vlib/v/checker/tests/cast_to_interface_err.vv new file mode 100644 index 000000000..0bd92d710 --- /dev/null +++ b/vlib/v/checker/tests/cast_to_interface_err.vv @@ -0,0 +1,21 @@ +fn main() { + dump(foo()!) +} + +fn foo() !int { + // do something + if true { + return 1 + } + return my_error() +} + +struct CustomError { +pub: + msg string + code int +} + +fn my_error() IError { + return IError(CustomError{}) +} diff --git a/vlib/v/checker/tests/infix_is_notis_interface_unimplemented_err.out b/vlib/v/checker/tests/infix_is_notis_interface_unimplemented_err.out index 02ef679ca..950a38f8d 100644 --- a/vlib/v/checker/tests/infix_is_notis_interface_unimplemented_err.out +++ b/vlib/v/checker/tests/infix_is_notis_interface_unimplemented_err.out @@ -1,3 +1,17 @@ +vlib/v/checker/tests/infix_is_notis_interface_unimplemented_err.vv:8:14: notice: `int` doesn't implement method `msg` of interface `IError`. The usage of fields is being deprecated in favor of methods. + 6 | if _ := f() { + 7 | } else { + 8 | _ = err is int + | ~~~ + 9 | } + 10 | +vlib/v/checker/tests/infix_is_notis_interface_unimplemented_err.vv:12:14: notice: `int` doesn't implement method `msg` of interface `IError`. The usage of fields is being deprecated in favor of methods. + 10 | + 11 | _ = f() or { + 12 | _ = err is int + | ~~~ + 13 | 0 + 14 | } vlib/v/checker/tests/infix_is_notis_interface_unimplemented_err.vv:8:14: error: `int` doesn't implement interface `IError` 6 | if _ := f() { 7 | } else { @@ -6,7 +20,7 @@ vlib/v/checker/tests/infix_is_notis_interface_unimplemented_err.vv:8:14: error: 9 | } 10 | vlib/v/checker/tests/infix_is_notis_interface_unimplemented_err.vv:12:14: error: `int` doesn't implement interface `IError` - 10 | + 10 | 11 | _ = f() or { 12 | _ = err is int | ~~~ diff --git a/vlib/v/checker/tests/mut_receiver_wrong_return_type.out b/vlib/v/checker/tests/mut_receiver_wrong_return_type.out index 3524822d3..38a2793fb 100644 --- a/vlib/v/checker/tests/mut_receiver_wrong_return_type.out +++ b/vlib/v/checker/tests/mut_receiver_wrong_return_type.out @@ -1,3 +1,16 @@ +vlib/v/checker/tests/mut_receiver_wrong_return_type.vv:4:2: notice: `&Test` doesn't implement method `msg` of interface `IError`. The usage of fields is being deprecated in favor of methods. + 2 | + 3 | fn (mut test Test) test() ?int { + 4 | return test + | ~~~~~~~~~~~ + 5 | } + 6 | +vlib/v/checker/tests/mut_receiver_wrong_return_type.vv:8:2: notice: `&Test` doesn't implement method `msg` of interface `IError`. The usage of fields is being deprecated in favor of methods. + 6 | + 7 | fn (mut test Test) test2() int { + 8 | return test + | ~~~~~~~~~~~ + 9 | } vlib/v/checker/tests/mut_receiver_wrong_return_type.vv:4:9: error: cannot use `Test` as type `?int` in return argument 2 | 3 | fn (mut test Test) test() ?int { -- 2.39.5