cgen: fix codegen for generic interface with multi return generic type (fix #24838) (#24858)

This commit is contained in:
Felipe Pena 2025-07-07 11:51:48 -03:00 committed by GitHub
parent e62ed47812
commit 00e0eae98b
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 72 additions and 7 deletions

View File

@ -502,6 +502,7 @@ pub fn gen(files []&ast.File, mut table ast.Table, pref_ &pref.Preferences) GenO
global_g.gen_array_index_methods() global_g.gen_array_index_methods()
global_g.gen_equality_fns() global_g.gen_equality_fns()
global_g.gen_free_methods() global_g.gen_free_methods()
global_g.register_iface_return_types()
global_g.write_results() global_g.write_results()
global_g.write_options() global_g.write_options()
global_g.sort_globals_consts() global_g.sort_globals_consts()
@ -5807,7 +5808,7 @@ fn (mut g Gen) return_stmt(node ast.Return) {
exprs_len := node.exprs.len exprs_len := node.exprs.len
expr0 := if exprs_len > 0 { node.exprs[0] } else { ast.empty_expr } expr0 := if exprs_len > 0 { node.exprs[0] } else { ast.empty_expr }
type0 := if exprs_len > 0 { node.types[0] } else { ast.void_type } type0 := if exprs_len > 0 { g.unwrap_generic(node.types[0]) } else { ast.void_type }
if exprs_len > 0 { if exprs_len > 0 {
// skip `return $vweb.html()` // skip `return $vweb.html()`
@ -5819,15 +5820,15 @@ fn (mut g Gen) return_stmt(node ast.Return) {
return return
} }
} }
ret_type := g.fn_decl.return_type ret_type := g.unwrap_generic(g.fn_decl.return_type)
// got to do a correct check for multireturn // got to do a correct check for multireturn
sym := g.table.sym(g.unwrap_generic(ret_type)) sym := g.table.sym(ret_type)
mut fn_ret_type := ret_type mut fn_ret_type := ret_type
if sym.kind == .alias { if sym.kind == .alias {
unaliased_type := g.table.unaliased_type(fn_ret_type) unaliased_type := g.table.unaliased_type(fn_ret_type)
if unaliased_type.has_option_or_result() { if unaliased_type.has_option_or_result() {
fn_ret_type = unaliased_type fn_ret_type = g.unwrap_generic(unaliased_type)
} }
} }
fn_return_is_multi := sym.kind == .multi_return fn_return_is_multi := sym.kind == .multi_return
@ -5857,7 +5858,7 @@ fn (mut g Gen) return_stmt(node ast.Return) {
} }
tmpvar := g.new_tmp_var() tmpvar := g.new_tmp_var()
g.defer_return_tmp_var = tmpvar g.defer_return_tmp_var = tmpvar
ret_typ := g.ret_styp(g.unwrap_generic(fn_ret_type)) ret_typ := g.ret_styp(fn_ret_type)
// `return fn_call_opt()` // `return fn_call_opt()`
if exprs_len == 1 && (fn_return_is_option || fn_return_is_result) && expr0 is ast.CallExpr if exprs_len == 1 && (fn_return_is_option || fn_return_is_result) && expr0 is ast.CallExpr
@ -6077,7 +6078,7 @@ fn (mut g Gen) return_stmt(node ast.Return) {
node.pos) node.pos)
} }
// normal return // normal return
return_sym := g.table.final_sym(g.unwrap_generic(type0)) return_sym := g.table.final_sym(type0)
// `return opt_ok(expr)` for functions that expect an option // `return opt_ok(expr)` for functions that expect an option
expr_type_is_opt := match expr0 { expr_type_is_opt := match expr0 {
ast.CallExpr { ast.CallExpr {
@ -6114,7 +6115,7 @@ fn (mut g Gen) return_stmt(node ast.Return) {
g.writeln('${ret_typ} ${tmpvar};') g.writeln('${ret_typ} ${tmpvar};')
styp := g.base_type(fn_ret_type) styp := g.base_type(fn_ret_type)
g.write('_option_ok(&(${styp}[]) { ') g.write('_option_ok(&(${styp}[]) { ')
if !g.unwrap_generic(fn_ret_type).is_ptr() && type0.is_ptr() { if !fn_ret_type.is_ptr() && type0.is_ptr() {
if !(expr0 is ast.Ident && !g.is_amp) { if !(expr0 is ast.Ident && !g.is_amp) {
g.write('*') g.write('*')
} }
@ -7717,6 +7718,22 @@ fn (g &Gen) has_been_referenced(fn_name string) bool {
return referenced return referenced
} }
fn (mut g Gen) register_iface_return_types() {
interfaces := g.table.type_symbols.filter(it.kind == .interface && it.info is ast.Interface)
for isym in interfaces {
inter_info := isym.info as ast.Interface
if inter_info.is_generic {
continue
}
for _, method_name in inter_info.get_methods() {
method := isym.find_method_with_generic_parent(method_name) or { continue }
if method.return_type.has_flag(.result) {
g.register_result(method.return_type)
}
}
}
}
// Generates interface table and interface indexes // Generates interface table and interface indexes
fn (mut g Gen) interface_table() string { fn (mut g Gen) interface_table() string {
util.timing_start(@METHOD) util.timing_start(@METHOD)

View File

@ -0,0 +1,48 @@
import pool
pub struct DB {}
fn (mut d DB) validate() !bool {
return false
}
fn (mut d DB) close() ! {}
fn (mut d DB) reset() ! {}
pub interface DatabaseMysqlPool[T] {
mut:
acquire() !(T, &pool.ConnectionPoolable)
release(conn &pool.ConnectionPoolable) !
}
@[heap]
struct DatabasePoolImpl[T] {
mut:
inner &pool.ConnectionPool
}
pub fn new_mysql_pool[T]() !&DatabaseMysqlPool[T] {
create_conn := fn () !&pool.ConnectionPoolable {
return DB{}
}
pool_conf := pool.ConnectionPoolConfig{}
inner_pool := pool.new_connection_pool(create_conn, pool_conf)!
pool_instance := &DatabasePoolImpl[T]{
inner: inner_pool
}
return pool_instance
}
pub fn (mut p DatabasePoolImpl[T]) acquire() !(T, &pool.ConnectionPoolable) {
conn := p.inner.get()!
return conn as DB, conn
}
pub fn (mut p DatabasePoolImpl[T]) release(conn &pool.ConnectionPoolable) ! {
p.inner.put(conn)!
}
fn test_main() {
new_mysql_pool[DB]() or { assert err.str().contains('failed') }
}