cgen: fix lambda inferring generic type on method call (fix #23221) (#23234)

This commit is contained in:
Felipe Pena 2024-12-22 08:58:45 -03:00 committed by GitHub
parent b58937c9cf
commit 24eac4d74d
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
3 changed files with 55 additions and 10 deletions

View File

@ -1125,7 +1125,11 @@ fn (mut c Checker) infer_fn_generic_types(func &ast.Fn, mut node ast.CallExpr) {
if typ.has_flag(.generic) {
lambda_ret_gt_name := c.table.type_to_str(typ)
idx := func.generic_names.index(lambda_ret_gt_name)
typ = node.concrete_types[idx]
if idx < node.concrete_types.len {
typ = node.concrete_types[idx]
} else {
typ = ast.void_type
}
}
}
}

View File

@ -1806,15 +1806,7 @@ fn (mut c Checker) fn_call(mut node ast.CallExpr, mut continue_check &bool) ast.
}
if mut call_arg.expr is ast.LambdaExpr {
// Calling fn is generic and lambda arg also is generic
if node.concrete_types.len > 0 && call_arg.expr.func != unsafe { nil }
&& call_arg.expr.func.decl.generic_names.len > 0 {
call_arg.expr.call_ctx = unsafe { node }
if c.table.register_fn_concrete_types(call_arg.expr.func.decl.fkey(),
node.concrete_types)
{
call_arg.expr.func.decl.ninstances++
}
}
c.handle_generic_lambda_arg(node, mut call_arg.expr)
continue
}
c.error('${err.msg()} in argument ${i + 1} to `${fn_name}`', call_arg.pos)
@ -2793,6 +2785,10 @@ fn (mut c Checker) method_call(mut node ast.CallExpr, mut continue_check &bool)
c.error('${err.msg()} in argument ${i + 1} to `${left_sym.name}.${method_name}`',
arg.pos)
}
if mut arg.expr is ast.LambdaExpr {
// Calling fn is generic and lambda arg also is generic
c.handle_generic_lambda_arg(node, mut arg.expr)
}
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) {
@ -2871,6 +2867,17 @@ fn (mut c Checker) method_call(mut node ast.CallExpr, mut continue_check &bool)
return node.return_type
}
fn (mut c Checker) handle_generic_lambda_arg(node &ast.CallExpr, mut lambda ast.LambdaExpr) {
// Calling fn is generic and lambda arg also is generic
if node.concrete_types.len > 0 && lambda.func != unsafe { nil }
&& lambda.func.decl.generic_names.len > 0 {
lambda.call_ctx = unsafe { node }
if c.table.register_fn_concrete_types(lambda.func.decl.fkey(), node.concrete_types) {
lambda.func.decl.ninstances++
}
}
}
fn (mut c Checker) spawn_expr(mut node ast.SpawnExpr) ast.Type {
ret_type := c.call_expr(mut node.call_expr)
if node.call_expr.or_block.kind != .absent {

View File

@ -0,0 +1,34 @@
module main
fn test_main() {
my := MyError{
path: 'err msg'
}
p := my.to[string](|m| m.path)
p2 := my.to_str(|m| m.path)
println(p)
println(p2)
assert p == p2
}
struct MyError {
pub:
path string
}
fn (e &MyError) msg() string {
return e.path
}
fn (e &MyError) code() int {
return 1
}
fn (e &MyError) to[T](func fn (MyError) T) T {
return func(e)
}
fn (e &MyError) to_str(func fn (MyError) string) string {
return func(e)
}