mirror of
https://github.com/vlang/v.git
synced 2023-08-10 21:13:21 +03:00
checker, native: Check arguments of native builtin functions (#15952)
This commit is contained in:
parent
c655847dfb
commit
5b59171a00
@ -487,6 +487,38 @@ pub fn (mut c Checker) call_expr(mut node ast.CallExpr) ast.Type {
|
|||||||
return typ
|
return typ
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn (mut c Checker) builtin_args(mut node ast.CallExpr, fn_name string, func ast.Fn) {
|
||||||
|
c.inside_println_arg = true
|
||||||
|
c.expected_type = ast.string_type
|
||||||
|
node.args[0].typ = c.expr(node.args[0].expr)
|
||||||
|
arg := node.args[0]
|
||||||
|
c.check_expr_opt_call(arg.expr, arg.typ)
|
||||||
|
if arg.typ.is_void() {
|
||||||
|
c.error('`$fn_name` can not print void expressions', node.pos)
|
||||||
|
} else if arg.typ == ast.char_type && arg.typ.nr_muls() == 0 {
|
||||||
|
c.error('`$fn_name` cannot print type `char` directly, print its address or cast it to an integer instead',
|
||||||
|
node.pos)
|
||||||
|
}
|
||||||
|
c.fail_if_unreadable(arg.expr, arg.typ, 'argument to print')
|
||||||
|
c.inside_println_arg = false
|
||||||
|
node.return_type = ast.void_type
|
||||||
|
c.set_node_expected_arg_types(mut node, func)
|
||||||
|
|
||||||
|
/*
|
||||||
|
// TODO: optimize `struct T{} fn (t &T) str() string {return 'abc'} mut a := []&T{} a << &T{} println(a[0])`
|
||||||
|
// It currently generates:
|
||||||
|
// `println(T_str_no_ptr(*(*(T**)array_get(a, 0))));`
|
||||||
|
// ... which works, but could be just:
|
||||||
|
// `println(T_str(*(T**)array_get(a, 0)));`
|
||||||
|
prexpr := node.args[0].expr
|
||||||
|
prtyp := node.args[0].typ
|
||||||
|
prtyp_sym := c.table.sym(prtyp)
|
||||||
|
prtyp_is_ptr := prtyp.is_ptr()
|
||||||
|
prhas_str, prexpects_ptr, prnr_args := prtyp_sym.str_method_info()
|
||||||
|
eprintln('>>> println hack typ: ${prtyp} | sym.name: ${prtyp_sym.name} | is_ptr: $prtyp_is_ptr | has_str: $prhas_str | expects_ptr: $prexpects_ptr | nr_args: $prnr_args | expr: ${prexpr.str()} ')
|
||||||
|
*/
|
||||||
|
}
|
||||||
|
|
||||||
pub fn (mut c Checker) fn_call(mut node ast.CallExpr, mut continue_check &bool) ast.Type {
|
pub fn (mut c Checker) fn_call(mut node ast.CallExpr, mut continue_check &bool) ast.Type {
|
||||||
fn_name := node.name
|
fn_name := node.name
|
||||||
if fn_name == 'main' {
|
if fn_name == 'main' {
|
||||||
@ -713,6 +745,10 @@ pub fn (mut c Checker) fn_call(mut node ast.CallExpr, mut continue_check &bool)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if is_native_builtin {
|
if is_native_builtin {
|
||||||
|
if node.args.len > 0 && fn_name in ['println', 'print', 'eprintln', 'eprint', 'panic'] {
|
||||||
|
c.builtin_args(mut node, fn_name, func)
|
||||||
|
return func.return_type
|
||||||
|
}
|
||||||
return ast.void_type
|
return ast.void_type
|
||||||
}
|
}
|
||||||
// check for arg (var) of fn type
|
// check for arg (var) of fn type
|
||||||
@ -841,34 +877,7 @@ pub fn (mut c Checker) fn_call(mut node ast.CallExpr, mut continue_check &bool)
|
|||||||
}
|
}
|
||||||
// println / eprintln / panic can print anything
|
// println / eprintln / panic can print anything
|
||||||
if node.args.len > 0 && fn_name in ['println', 'print', 'eprintln', 'eprint', 'panic'] {
|
if node.args.len > 0 && fn_name in ['println', 'print', 'eprintln', 'eprint', 'panic'] {
|
||||||
c.inside_println_arg = true
|
c.builtin_args(mut node, fn_name, func)
|
||||||
c.expected_type = ast.string_type
|
|
||||||
node.args[0].typ = c.expr(node.args[0].expr)
|
|
||||||
arg := node.args[0]
|
|
||||||
c.check_expr_opt_call(arg.expr, arg.typ)
|
|
||||||
if arg.typ.is_void() {
|
|
||||||
c.error('`$fn_name` can not print void expressions', node.pos)
|
|
||||||
} else if arg.typ == ast.char_type && arg.typ.nr_muls() == 0 {
|
|
||||||
c.error('`$fn_name` cannot print type `char` directly, print its address or cast it to an integer instead',
|
|
||||||
node.pos)
|
|
||||||
}
|
|
||||||
c.fail_if_unreadable(arg.expr, arg.typ, 'argument to print')
|
|
||||||
c.inside_println_arg = false
|
|
||||||
node.return_type = ast.void_type
|
|
||||||
c.set_node_expected_arg_types(mut node, func)
|
|
||||||
/*
|
|
||||||
// TODO: optimize `struct T{} fn (t &T) str() string {return 'abc'} mut a := []&T{} a << &T{} println(a[0])`
|
|
||||||
// It currently generates:
|
|
||||||
// `println(T_str_no_ptr(*(*(T**)array_get(a, 0))));`
|
|
||||||
// ... which works, but could be just:
|
|
||||||
// `println(T_str(*(T**)array_get(a, 0)));`
|
|
||||||
prexpr := node.args[0].expr
|
|
||||||
prtyp := node.args[0].typ
|
|
||||||
prtyp_sym := c.table.sym(prtyp)
|
|
||||||
prtyp_is_ptr := prtyp.is_ptr()
|
|
||||||
prhas_str, prexpects_ptr, prnr_args := prtyp_sym.str_method_info()
|
|
||||||
eprintln('>>> println hack typ: ${prtyp} | sym.name: ${prtyp_sym.name} | is_ptr: $prtyp_is_ptr | has_str: $prhas_str | expects_ptr: $prexpects_ptr | nr_args: $prnr_args | expr: ${prexpr.str()} ')
|
|
||||||
*/
|
|
||||||
return func.return_type
|
return func.return_type
|
||||||
}
|
}
|
||||||
// `return error(err)` -> `return err`
|
// `return error(err)` -> `return err`
|
||||||
|
@ -8,6 +8,14 @@ fn abc() {
|
|||||||
println(c)
|
println(c)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn abc_direct() {
|
||||||
|
// print at-exprs directly instead of using variables
|
||||||
|
println(@LINE)
|
||||||
|
println(@FILE_LINE)
|
||||||
|
println(@FN)
|
||||||
|
}
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
abc()
|
abc()
|
||||||
|
abc_direct()
|
||||||
}
|
}
|
||||||
|
@ -1,3 +1,6 @@
|
|||||||
3
|
3
|
||||||
atexpr.vv:4
|
atexpr.vv:4
|
||||||
abc
|
abc
|
||||||
|
13
|
||||||
|
atexpr.vv:14
|
||||||
|
abc_direct
|
||||||
|
Loading…
x
Reference in New Issue
Block a user