mirror of
https://github.com/vlang/v.git
synced 2023-08-10 21:13:21 +03:00
This commit is contained in:
@ -168,6 +168,22 @@ pub fn (mut c Checker) check_types(got ast.Type, expected ast.Type) bool {
|
||||
return true
|
||||
}
|
||||
|
||||
fn (c Checker) check_multiple_ptr_match(got ast.Type, expected ast.Type, param ast.Param, arg ast.CallArg) bool {
|
||||
param_nr_muls := if param.is_mut && !expected.is_ptr() { 1 } else { expected.nr_muls() }
|
||||
if got.is_ptr() && got.nr_muls() > 1 && got.nr_muls() != param_nr_muls {
|
||||
if arg.expr is ast.PrefixExpr && (arg.expr as ast.PrefixExpr).op == .amp {
|
||||
return false
|
||||
}
|
||||
if arg.expr is ast.UnsafeExpr {
|
||||
expr := (arg.expr as ast.UnsafeExpr).expr
|
||||
if expr is ast.PrefixExpr && (expr as ast.PrefixExpr).op == .amp {
|
||||
return false
|
||||
}
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
pub fn (mut c Checker) check_expected_call_arg(got ast.Type, expected_ ast.Type, language ast.Language, arg ast.CallArg) ? {
|
||||
if got == 0 {
|
||||
return error('unexpected 0 type')
|
||||
|
@ -1047,6 +1047,13 @@ pub fn (mut c Checker) fn_call(mut node ast.CallExpr, mut continue_check &bool)
|
||||
c.mark_as_referenced(mut &call_arg.expr, true)
|
||||
}
|
||||
}
|
||||
|
||||
if arg_typ !in [ast.voidptr_type, ast.nil_type]
|
||||
&& !c.check_multiple_ptr_match(arg_typ, param.typ, param, call_arg) {
|
||||
got_typ_str, expected_typ_str := c.get_string_names_of(arg_typ, param.typ)
|
||||
c.error('cannot use `$got_typ_str` as `$expected_typ_str` in argument ${i + 1} to `$fn_name`',
|
||||
call_arg.pos)
|
||||
}
|
||||
continue
|
||||
}
|
||||
if param.typ.is_ptr() && !param.is_mut && !call_arg.typ.is_real_pointer()
|
||||
@ -1150,6 +1157,12 @@ pub fn (mut c Checker) fn_call(mut node ast.CallExpr, mut continue_check &bool)
|
||||
}
|
||||
c.error('$err.msg() in argument ${i + 1} to `$fn_name`', call_arg.pos)
|
||||
}
|
||||
if final_param_sym.kind == .struct_ && arg_typ !in [ast.voidptr_type, ast.nil_type]
|
||||
&& !c.check_multiple_ptr_match(arg_typ, param.typ, param, call_arg) {
|
||||
got_typ_str, expected_typ_str := c.get_string_names_of(arg_typ, param.typ)
|
||||
c.error('cannot use `$got_typ_str` as `$expected_typ_str` in argument ${i + 1} to `$fn_name`',
|
||||
call_arg.pos)
|
||||
}
|
||||
// Warn about automatic (de)referencing, which will be removed soon.
|
||||
if func.language != .c && !c.inside_unsafe && arg_typ.nr_muls() != param.typ.nr_muls()
|
||||
&& !(call_arg.is_mut && param.is_mut) && !(!call_arg.is_mut && !param.is_mut)
|
||||
@ -1665,6 +1678,14 @@ pub fn (mut c Checker) method_call(mut node ast.CallExpr) ast.Type {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if got_arg_typ !in [ast.voidptr_type, ast.nil_type]
|
||||
&& !c.check_multiple_ptr_match(got_arg_typ, param.typ, param, arg) {
|
||||
got_typ_str, expected_typ_str := c.get_string_names_of(got_arg_typ,
|
||||
param.typ)
|
||||
c.error('cannot use `$got_typ_str` as `$expected_typ_str` in argument ${i + 1} to `$method_name`',
|
||||
arg.pos)
|
||||
}
|
||||
continue
|
||||
}
|
||||
if param.typ.is_ptr() && !arg.typ.is_real_pointer() && arg.expr.is_literal()
|
||||
@ -1693,6 +1714,13 @@ pub fn (mut c Checker) method_call(mut node ast.CallExpr) ast.Type {
|
||||
c.error('$err.msg() in argument ${i + 1} to `${left_sym.name}.$method_name`',
|
||||
arg.pos)
|
||||
}
|
||||
param_typ_sym := c.table.sym(exp_arg_typ)
|
||||
if param_typ_sym.kind == .struct_ && got_arg_typ !in [ast.voidptr_type, ast.nil_type]
|
||||
&& !c.check_multiple_ptr_match(got_arg_typ, param.typ, param, arg) {
|
||||
got_typ_str, expected_typ_str := c.get_string_names_of(got_arg_typ, param.typ)
|
||||
c.error('cannot use `$got_typ_str` as `$expected_typ_str` in argument ${i + 1} to `$method_name`',
|
||||
arg.pos)
|
||||
}
|
||||
}
|
||||
if method.is_unsafe && !c.inside_unsafe {
|
||||
c.warn('method `${left_sym.name}.$method_name` must be called from an `unsafe` block',
|
||||
|
20
vlib/v/checker/tests/fn_call_arg_ptr_mismatch_err.out
Normal file
20
vlib/v/checker/tests/fn_call_arg_ptr_mismatch_err.out
Normal file
@ -0,0 +1,20 @@
|
||||
vlib/v/checker/tests/fn_call_arg_ptr_mismatch_err.vv:31:29: error: cannot use `&&SomethingImplemented` as `&ISomething` in argument 1 to `get_value_implemented`
|
||||
29 | }
|
||||
30 | // fn call
|
||||
31 | _ := get_value_implemented(&s1)
|
||||
| ~~~
|
||||
32 | // method call
|
||||
33 | _ := s1.get_value_implemented(&s1)
|
||||
vlib/v/checker/tests/fn_call_arg_ptr_mismatch_err.vv:33:32: error: cannot use `&&SomethingImplemented` as `&ISomething` in argument 1 to `get_value_implemented`
|
||||
31 | _ := get_value_implemented(&s1)
|
||||
32 | // method call
|
||||
33 | _ := s1.get_value_implemented(&s1)
|
||||
| ~~~
|
||||
34 |
|
||||
35 | s2 := &SomethingNotImplemented{
|
||||
vlib/v/checker/tests/fn_call_arg_ptr_mismatch_err.vv:39:33: error: cannot use `&&SomethingNotImplemented` as `&SomethingNotImplemented` in argument 1 to `get_value_not_implemented`
|
||||
37 | }
|
||||
38 | // fn call
|
||||
39 | _ := get_value_not_implemented(&s2)
|
||||
| ~~~
|
||||
40 | }
|
40
vlib/v/checker/tests/fn_call_arg_ptr_mismatch_err.vv
Normal file
40
vlib/v/checker/tests/fn_call_arg_ptr_mismatch_err.vv
Normal file
@ -0,0 +1,40 @@
|
||||
interface ISomething {
|
||||
value int
|
||||
get_value_implemented(s &ISomething) int
|
||||
}
|
||||
|
||||
struct SomethingImplemented {
|
||||
value int
|
||||
}
|
||||
|
||||
fn (s SomethingImplemented) get_value_implemented(s_ &ISomething) int {
|
||||
return s.value
|
||||
}
|
||||
|
||||
fn get_value_implemented(s &ISomething) int {
|
||||
return s.value
|
||||
}
|
||||
|
||||
struct SomethingNotImplemented {
|
||||
value int
|
||||
}
|
||||
|
||||
fn get_value_not_implemented(s &SomethingNotImplemented) int {
|
||||
return s.value
|
||||
}
|
||||
|
||||
fn main() {
|
||||
s1 := &SomethingImplemented{
|
||||
value: 1
|
||||
}
|
||||
// fn call
|
||||
_ := get_value_implemented(&s1)
|
||||
// method call
|
||||
_ := s1.get_value_implemented(&s1)
|
||||
|
||||
s2 := &SomethingNotImplemented{
|
||||
value: 1
|
||||
}
|
||||
// fn call
|
||||
_ := get_value_not_implemented(&s2)
|
||||
}
|
Reference in New Issue
Block a user