checker: check mut interface arguments (#13479)
parent
5a14748e7c
commit
f8b8950b96
|
@ -1255,18 +1255,6 @@ pub fn (mut c Checker) method_call(mut node ast.CallExpr) ast.Type {
|
||||||
final_arg_typ = exp_arg_sym.array_info().elem_type
|
final_arg_typ = exp_arg_sym.array_info().elem_type
|
||||||
final_arg_sym = c.table.sym(final_arg_typ)
|
final_arg_sym = c.table.sym(final_arg_typ)
|
||||||
}
|
}
|
||||||
// Handle expected interface
|
|
||||||
if final_arg_sym.kind == .interface_ {
|
|
||||||
if c.type_implements(got_arg_typ, final_arg_typ, arg.expr.pos()) {
|
|
||||||
if !got_arg_typ.is_ptr() && !got_arg_typ.is_pointer() && !c.inside_unsafe {
|
|
||||||
got_arg_typ_sym := c.table.sym(got_arg_typ)
|
|
||||||
if got_arg_typ_sym.kind != .interface_ {
|
|
||||||
c.mark_as_referenced(mut &arg.expr, true)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
if exp_arg_typ.has_flag(.generic) {
|
if exp_arg_typ.has_flag(.generic) {
|
||||||
if concrete_types.len == 0 {
|
if concrete_types.len == 0 {
|
||||||
continue
|
continue
|
||||||
|
@ -1290,18 +1278,6 @@ pub fn (mut c Checker) method_call(mut node ast.CallExpr) ast.Type {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
c.check_expected_call_arg(got_arg_typ, exp_arg_typ, node.language, arg) or {
|
|
||||||
// str method, allow type with str method if fn arg is string
|
|
||||||
// Passing an int or a string array produces a c error here
|
|
||||||
// Deleting this condition results in propper V error messages
|
|
||||||
// if arg_typ_sym.kind == .string && typ_sym.has_method('str') {
|
|
||||||
// continue
|
|
||||||
// }
|
|
||||||
if got_arg_typ != ast.void_type {
|
|
||||||
c.error('$err.msg() in argument ${i + 1} to `${left_sym.name}.$method_name`',
|
|
||||||
arg.pos)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
param := if method.is_variadic && i >= method.params.len - 1 {
|
param := if method.is_variadic && i >= method.params.len - 1 {
|
||||||
method.params[method.params.len - 1]
|
method.params[method.params.len - 1]
|
||||||
} else {
|
} else {
|
||||||
|
@ -1337,6 +1313,30 @@ pub fn (mut c Checker) method_call(mut node ast.CallExpr) ast.Type {
|
||||||
c.fail_if_unreadable(arg.expr, got_arg_typ, 'argument')
|
c.fail_if_unreadable(arg.expr, got_arg_typ, 'argument')
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
// Handle expected interface
|
||||||
|
if final_arg_sym.kind == .interface_ {
|
||||||
|
if c.type_implements(got_arg_typ, final_arg_typ, arg.expr.pos()) {
|
||||||
|
if !got_arg_typ.is_ptr() && !got_arg_typ.is_pointer() && !c.inside_unsafe {
|
||||||
|
got_arg_typ_sym := c.table.sym(got_arg_typ)
|
||||||
|
if got_arg_typ_sym.kind != .interface_ {
|
||||||
|
c.mark_as_referenced(mut &arg.expr, true)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
c.check_expected_call_arg(got_arg_typ, exp_arg_typ, node.language, arg) or {
|
||||||
|
// str method, allow type with str method if fn arg is string
|
||||||
|
// Passing an int or a string array produces a c error here
|
||||||
|
// Deleting this condition results in propper V error messages
|
||||||
|
// if arg_typ_sym.kind == .string && typ_sym.has_method('str') {
|
||||||
|
// continue
|
||||||
|
// }
|
||||||
|
if got_arg_typ != ast.void_type {
|
||||||
|
c.error('$err.msg() in argument ${i + 1} to `${left_sym.name}.$method_name`',
|
||||||
|
arg.pos)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if method.is_unsafe && !c.inside_unsafe {
|
if method.is_unsafe && !c.inside_unsafe {
|
||||||
c.warn('method `${left_sym.name}.$method_name` must be called from an `unsafe` block',
|
c.warn('method `${left_sym.name}.$method_name` must be called from an `unsafe` block',
|
||||||
|
|
|
@ -0,0 +1,6 @@
|
||||||
|
vlib/v/checker/tests/mut_interface_param_err.vv:19:10: error: `add` parameter `widget` is `mut`, you need to provide `mut` e.g. `mut arg1`
|
||||||
|
17 | mut win := Window{}
|
||||||
|
18 | mut btn := Button{}
|
||||||
|
19 | win.add(btn) // should be an error here
|
||||||
|
| ~~~
|
||||||
|
20 | }
|
|
@ -0,0 +1,20 @@
|
||||||
|
interface Widget{
|
||||||
|
mut:
|
||||||
|
init()
|
||||||
|
}
|
||||||
|
|
||||||
|
struct Button{}
|
||||||
|
fn (mut b Button) init(){}
|
||||||
|
|
||||||
|
struct Window{
|
||||||
|
mut:
|
||||||
|
widgets []Widget
|
||||||
|
}
|
||||||
|
|
||||||
|
fn (mut w Window) add(mut widget Widget){}
|
||||||
|
|
||||||
|
fn main(){
|
||||||
|
mut win := Window{}
|
||||||
|
mut btn := Button{}
|
||||||
|
win.add(btn) // should be an error here
|
||||||
|
}
|
Loading…
Reference in New Issue