mirror of
https://github.com/vlang/v.git
synced 2025-09-18 11:56:57 -04:00
checker: fix validation of lambda params and returns in generic function calls (#22387)
This commit is contained in:
parent
f24d239199
commit
1a11056419
@ -37,7 +37,8 @@ pub mut:
|
|||||||
panic_handler FnPanicHandler = default_table_panic_handler
|
panic_handler FnPanicHandler = default_table_panic_handler
|
||||||
panic_userdata voidptr = unsafe { nil } // can be used to pass arbitrary data to panic_handler;
|
panic_userdata voidptr = unsafe { nil } // can be used to pass arbitrary data to panic_handler;
|
||||||
panic_npanics int
|
panic_npanics int
|
||||||
cur_fn &FnDecl = unsafe { nil } // previously stored in Checker.cur_fn and Gen.cur_fn
|
cur_fn &FnDecl = unsafe { nil } // previously stored in Checker.cur_fn and Gen.cur_fn
|
||||||
|
cur_lambda &LambdaExpr = unsafe { nil } // current lambda node
|
||||||
cur_concrete_types []Type // current concrete types, e.g. <int, string>
|
cur_concrete_types []Type // current concrete types, e.g. <int, string>
|
||||||
gostmts int // how many `go` statements there were in the parsed files.
|
gostmts int // how many `go` statements there were in the parsed files.
|
||||||
// When table.gostmts > 0, __VTHREADS__ is defined, which can be checked with `$if threads {`
|
// When table.gostmts > 0, __VTHREADS__ is defined, which can be checked with `$if threads {`
|
||||||
|
@ -2735,6 +2735,13 @@ fn (mut c Checker) unwrap_generic(typ ast.Type) ast.Type {
|
|||||||
{
|
{
|
||||||
return t_typ
|
return t_typ
|
||||||
}
|
}
|
||||||
|
if c.inside_lambda && c.table.cur_lambda.call_ctx != unsafe { nil } {
|
||||||
|
if t_typ := c.table.resolve_generic_to_concrete(typ, c.table.cur_lambda.func.decl.generic_names,
|
||||||
|
c.table.cur_lambda.call_ctx.concrete_types)
|
||||||
|
{
|
||||||
|
return t_typ
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return typ
|
return typ
|
||||||
@ -2971,8 +2978,10 @@ pub fn (mut c Checker) expr(mut node ast.Expr) ast.Type {
|
|||||||
}
|
}
|
||||||
ast.LambdaExpr {
|
ast.LambdaExpr {
|
||||||
c.inside_lambda = true
|
c.inside_lambda = true
|
||||||
|
c.table.cur_lambda = unsafe { &node }
|
||||||
defer {
|
defer {
|
||||||
c.inside_lambda = false
|
c.inside_lambda = false
|
||||||
|
c.table.cur_lambda = unsafe { nil }
|
||||||
}
|
}
|
||||||
return c.lambda_expr(mut node, c.expected_type)
|
return c.lambda_expr(mut node, c.expected_type)
|
||||||
}
|
}
|
||||||
|
@ -1234,6 +1234,10 @@ fn (mut c Checker) fn_call(mut node ast.CallExpr, mut continue_check &bool) ast.
|
|||||||
for i, mut call_arg in node.args {
|
for i, mut call_arg in node.args {
|
||||||
if call_arg.expr is ast.CallExpr {
|
if call_arg.expr is ast.CallExpr {
|
||||||
node.args[i].typ = c.expr(mut call_arg.expr)
|
node.args[i].typ = c.expr(mut call_arg.expr)
|
||||||
|
} else if mut call_arg.expr is ast.LambdaExpr {
|
||||||
|
if node.concrete_types.len > 0 {
|
||||||
|
call_arg.expr.call_ctx = unsafe { node }
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
c.check_expected_arg_count(mut node, func) or { return func.return_type }
|
c.check_expected_arg_count(mut node, func) or { return func.return_type }
|
||||||
@ -1608,7 +1612,7 @@ fn (mut c Checker) fn_call(mut node ast.CallExpr, mut continue_check &bool) ast.
|
|||||||
}
|
}
|
||||||
if mut call_arg.expr is ast.LambdaExpr {
|
if mut call_arg.expr is ast.LambdaExpr {
|
||||||
// Calling fn is generic and lambda arg also is generic
|
// Calling fn is generic and lambda arg also is generic
|
||||||
if node.concrete_types.len > 0
|
if node.concrete_types.len > 0 && call_arg.expr.func != unsafe { nil }
|
||||||
&& call_arg.expr.func.decl.generic_names.len > 0 {
|
&& call_arg.expr.func.decl.generic_names.len > 0 {
|
||||||
call_arg.expr.call_ctx = unsafe { node }
|
call_arg.expr.call_ctx = unsafe { node }
|
||||||
if c.table.register_fn_concrete_types(call_arg.expr.func.decl.fkey(),
|
if c.table.register_fn_concrete_types(call_arg.expr.func.decl.fkey(),
|
||||||
|
@ -261,9 +261,8 @@ fn (mut c Checker) return_stmt(mut node ast.Return) {
|
|||||||
} else {
|
} else {
|
||||||
got_type_sym.name
|
got_type_sym.name
|
||||||
}
|
}
|
||||||
// ignore generic casting expr on lambda in this phase
|
// ignore generic lambda return in this phase
|
||||||
if c.inside_lambda && exp_type.has_flag(.generic)
|
if c.inside_lambda && exp_type.has_flag(.generic) {
|
||||||
&& node.exprs[expr_idxs[i]] is ast.CastExpr {
|
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
c.error('cannot use `${got_type_name}` as ${c.error_type_name(exp_type)} in return argument',
|
c.error('cannot use `${got_type_name}` as ${c.error_type_name(exp_type)} in return argument',
|
||||||
|
7
vlib/v/tests/generics/lamda_param_and_ret_test.v
Normal file
7
vlib/v/tests/generics/lamda_param_and_ret_test.v
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
import arrays
|
||||||
|
|
||||||
|
fn test_main() {
|
||||||
|
items := ['item1', 'item2', 'item3']
|
||||||
|
list := arrays.map_indexed[string, string](items, |i, item| '${i}. ${item}')
|
||||||
|
assert list == ['0. item1', '1. item2', '2. item3']
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user