cgen: cache return_stmt()'s node.exprs[0] and node.types[0] (#23408)

This commit is contained in:
Felipe Pena 2025-01-08 15:41:36 -03:00 committed by GitHub
parent d1d47d6b8f
commit ca48d7da37
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194

View File

@ -5521,11 +5521,14 @@ fn (mut g Gen) return_stmt(node ast.Return) {
g.inside_return = old_inside_return g.inside_return = old_inside_return
} }
expr0 := if node.exprs.len > 0 { node.exprs[0] } else { ast.empty_expr }
type0 := if node.exprs.len > 0 { node.types[0] } else { ast.void_type }
if node.exprs.len > 0 { if node.exprs.len > 0 {
// skip `return $vweb.html()` // skip `return $vweb.html()`
if node.exprs[0] is ast.ComptimeCall && node.exprs[0].is_vweb { if expr0 is ast.ComptimeCall && expr0.is_vweb {
g.inside_return_tmpl = true g.inside_return_tmpl = true
g.expr(node.exprs[0]) g.expr(expr0)
g.inside_return_tmpl = false g.inside_return_tmpl = false
g.writeln(';') g.writeln(';')
return return
@ -5571,19 +5574,18 @@ fn (mut g Gen) return_stmt(node ast.Return) {
ret_typ := g.ret_styp(g.unwrap_generic(fn_ret_type)) ret_typ := g.ret_styp(g.unwrap_generic(fn_ret_type))
// `return fn_call_opt()` // `return fn_call_opt()`
if node.exprs.len == 1 && (fn_return_is_option || fn_return_is_result) if node.exprs.len == 1 && (fn_return_is_option || fn_return_is_result) && expr0 is ast.CallExpr
&& node.exprs[0] is ast.CallExpr && node.exprs[0].return_type == g.fn_decl.return_type && expr0.return_type == g.fn_decl.return_type && expr0.or_block.kind == .absent {
&& node.exprs[0].or_block.kind == .absent {
if g.defer_stmts.len > 0 { if g.defer_stmts.len > 0 {
g.write('${ret_typ} ${tmpvar} = ') g.write('${ret_typ} ${tmpvar} = ')
g.expr(node.exprs[0]) g.expr(expr0)
g.writeln(';') g.writeln(';')
g.write_defer_stmts_when_needed() g.write_defer_stmts_when_needed()
g.writeln('return ${tmpvar};') g.writeln('return ${tmpvar};')
} else { } else {
g.write_defer_stmts_when_needed() g.write_defer_stmts_when_needed()
g.write('return ') g.write('return ')
g.expr(node.exprs[0]) g.expr(expr0)
g.writeln(';') g.writeln(';')
} }
return return
@ -5595,14 +5597,14 @@ fn (mut g Gen) return_stmt(node ast.Return) {
|| (fn_return_is_multi && node.types.any(g.table.final_sym(it).kind == .array_fixed)) || (fn_return_is_multi && node.types.any(g.table.final_sym(it).kind == .array_fixed))
// handle promoting none/error/function returning _option' // handle promoting none/error/function returning _option'
if fn_return_is_option { if fn_return_is_option {
option_none := node.exprs[0] is ast.None option_none := expr0 is ast.None
ftyp := g.styp(node.types[0]) ftyp := g.styp(type0)
mut is_regular_option := ftyp == '_option' mut is_regular_option := ftyp == '_option'
if option_none || is_regular_option || node.types[0] == ast.error_type_idx { if option_none || is_regular_option || type0 == ast.error_type_idx {
if g.fn_decl != unsafe { nil } && g.fn_decl.is_test { if g.fn_decl != unsafe { nil } && g.fn_decl.is_test {
test_error_var := g.new_tmp_var() test_error_var := g.new_tmp_var()
g.write('${ret_typ} ${test_error_var} = ') g.write('${ret_typ} ${test_error_var} = ')
g.gen_option_error(fn_ret_type, node.exprs[0]) g.gen_option_error(fn_ret_type, expr0)
g.writeln(';') g.writeln(';')
g.write_defer_stmts_when_needed() g.write_defer_stmts_when_needed()
g.gen_failing_return_error_for_test_fn(node, test_error_var) g.gen_failing_return_error_for_test_fn(node, test_error_var)
@ -5613,7 +5615,7 @@ fn (mut g Gen) return_stmt(node ast.Return) {
} else { } else {
g.write('return ') g.write('return ')
} }
g.gen_option_error(fn_ret_type, node.exprs[0]) g.gen_option_error(fn_ret_type, expr0)
g.writeln(';') g.writeln(';')
if use_tmp_var { if use_tmp_var {
// handle options when returning `none` for `?(int, ?int)` // handle options when returning `none` for `?(int, ?int)`
@ -5635,13 +5637,13 @@ fn (mut g Gen) return_stmt(node ast.Return) {
} }
// handle promoting error/function returning result // handle promoting error/function returning result
if fn_return_is_result { if fn_return_is_result {
ftyp := g.styp(node.types[0]) ftyp := g.styp(type0)
mut is_regular_result := ftyp == result_name mut is_regular_result := ftyp == result_name
if is_regular_result || node.types[0] == ast.error_type_idx { if is_regular_result || type0 == ast.error_type_idx {
if g.fn_decl != unsafe { nil } && g.fn_decl.is_test { if g.fn_decl != unsafe { nil } && g.fn_decl.is_test {
test_error_var := g.new_tmp_var() test_error_var := g.new_tmp_var()
g.write('${ret_typ} ${test_error_var} = ') g.write('${ret_typ} ${test_error_var} = ')
g.gen_result_error(fn_ret_type, node.exprs[0]) g.gen_result_error(fn_ret_type, expr0)
g.writeln(';') g.writeln(';')
g.write_defer_stmts_when_needed() g.write_defer_stmts_when_needed()
g.gen_failing_return_error_for_test_fn(node, test_error_var) g.gen_failing_return_error_for_test_fn(node, test_error_var)
@ -5652,7 +5654,7 @@ fn (mut g Gen) return_stmt(node ast.Return) {
} else { } else {
g.write('return ') g.write('return ')
} }
g.gen_result_error(fn_ret_type, node.exprs[0]) g.gen_result_error(fn_ret_type, expr0)
g.writeln(';') g.writeln(';')
if use_tmp_var { if use_tmp_var {
g.write_defer_stmts_when_needed() g.write_defer_stmts_when_needed()
@ -5662,11 +5664,11 @@ fn (mut g Gen) return_stmt(node ast.Return) {
} }
} }
// regular cases // regular cases
if fn_return_is_multi && node.exprs.len > 0 && !g.expr_is_multi_return_call(node.exprs[0]) { if fn_return_is_multi && node.exprs.len > 0 && !g.expr_is_multi_return_call(expr0) {
if node.exprs.len == 1 && (node.exprs[0] is ast.IfExpr || node.exprs[0] is ast.MatchExpr) { if node.exprs.len == 1 && (expr0 is ast.IfExpr || expr0 is ast.MatchExpr) {
// use a temporary for `return if cond { x,y } else { a,b }` or `return match expr { abc { x, y } else { z, w } }` // use a temporary for `return if cond { x,y } else { a,b }` or `return match expr { abc { x, y } else { z, w } }`
g.write('${ret_typ} ${tmpvar} = ') g.write('${ret_typ} ${tmpvar} = ')
g.expr(node.exprs[0]) g.expr(expr0)
g.writeln(';') g.writeln(';')
g.write_defer_stmts_when_needed() g.write_defer_stmts_when_needed()
g.writeln('return ${tmpvar};') g.writeln('return ${tmpvar};')
@ -5786,30 +5788,29 @@ 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(node.types[0])) return_sym := g.table.final_sym(g.unwrap_generic(type0))
expr0 := node.exprs[0]
// `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 {
expr0.return_type.has_flag(.option) && expr0.or_block.kind == .absent expr0.return_type.has_flag(.option) && expr0.or_block.kind == .absent
} }
else { else {
node.types[0].has_flag(.option) type0.has_flag(.option)
} }
} }
if fn_return_is_option && !expr_type_is_opt && return_sym.name != option_name { if fn_return_is_option && !expr_type_is_opt && return_sym.name != option_name {
if fn_return_is_fixed_array && (expr0 in [ast.StructInit, ast.CallExpr, ast.CastExpr] if fn_return_is_fixed_array && (expr0 in [ast.StructInit, ast.CallExpr, ast.CastExpr]
|| (expr0 is ast.ArrayInit && expr0.has_callexpr)) || (expr0 is ast.ArrayInit && expr0.has_callexpr))
&& g.table.final_sym(node.types[0]).kind == .array_fixed { && g.table.final_sym(type0).kind == .array_fixed {
styp := g.styp(fn_ret_type.clear_option_and_result()) styp := g.styp(fn_ret_type.clear_option_and_result())
if expr0 is ast.CallExpr { if expr0 is ast.CallExpr {
tmp_var := g.expr_with_fixed_array(expr0, node.types[0], fn_ret_type) tmp_var := g.expr_with_fixed_array(expr0, type0, fn_ret_type)
g.writeln('${ret_typ} ${tmpvar} = ${tmp_var};') g.writeln('${ret_typ} ${tmpvar} = ${tmp_var};')
} else { } else {
g.writeln('${ret_typ} ${tmpvar} = (${ret_typ}){ .state=0, .err=_const_none__, .data={EMPTY_STRUCT_INITIALIZATION} };') g.writeln('${ret_typ} ${tmpvar} = (${ret_typ}){ .state=0, .err=_const_none__, .data={EMPTY_STRUCT_INITIALIZATION} };')
if expr0 is ast.StructInit { if expr0 is ast.StructInit {
g.write('memcpy(${tmpvar}.data, ') g.write('memcpy(${tmpvar}.data, ')
tmp_var := g.expr_with_opt(expr0, node.types[0], fn_ret_type) tmp_var := g.expr_with_opt(expr0, type0, fn_ret_type)
g.writeln('.data, sizeof(${styp}));') g.writeln('.data, sizeof(${styp}));')
if tmp_var != '' { if tmp_var != '' {
g.writeln('${tmpvar}.state = ${tmp_var}.state;') g.writeln('${tmpvar}.state = ${tmp_var}.state;')
@ -5824,8 +5825,8 @@ 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() && node.types[0].is_ptr() { if !g.unwrap_generic(fn_ret_type).is_ptr() && type0.is_ptr() {
if !(node.exprs[0] is ast.Ident && !g.is_amp) { if !(expr0 is ast.Ident && !g.is_amp) {
g.write('*') g.write('*')
} }
} }
@ -5834,7 +5835,7 @@ fn (mut g Gen) return_stmt(node ast.Return) {
g.fixed_array_var_init(g.expr_string(expr0), expr0.is_auto_deref_var(), g.fixed_array_var_init(g.expr_string(expr0), expr0.is_auto_deref_var(),
info.elem_type, info.size) info.elem_type, info.size)
} else { } else {
g.expr_with_cast(expr0, node.types[0], fn_ret_type.clear_option_and_result()) g.expr_with_cast(expr0, type0, fn_ret_type.clear_option_and_result())
} }
g.writeln(' }, (${option_name}*)(&${tmpvar}), sizeof(${styp}));') g.writeln(' }, (${option_name}*)(&${tmpvar}), sizeof(${styp}));')
} }
@ -5848,17 +5849,17 @@ fn (mut g Gen) return_stmt(node ast.Return) {
expr0.return_type.has_flag(.result) && expr0.or_block.kind == .absent expr0.return_type.has_flag(.result) && expr0.or_block.kind == .absent
} }
else { else {
node.types[0].has_flag(.result) type0.has_flag(.result)
} }
} }
if fn_return_is_result && !expr_type_is_result && return_sym.name != result_name { if fn_return_is_result && !expr_type_is_result && return_sym.name != result_name {
g.writeln('${ret_typ} ${tmpvar} = {0};') g.writeln('${ret_typ} ${tmpvar} = {0};')
if fn_return_is_fixed_array && expr0 !is ast.ArrayInit if fn_return_is_fixed_array && expr0 !is ast.ArrayInit
&& g.table.final_sym(node.types[0]).kind == .array_fixed { && g.table.final_sym(type0).kind == .array_fixed {
styp := g.styp(fn_ret_type.clear_option_and_result()) styp := g.styp(fn_ret_type.clear_option_and_result())
g.write('memcpy(${tmpvar}.data, ') g.write('memcpy(${tmpvar}.data, ')
if expr0 in [ast.CallExpr, ast.StructInit] { if expr0 in [ast.CallExpr, ast.StructInit] {
g.expr_with_opt(expr0, node.types[0], fn_ret_type) g.expr_with_opt(expr0, type0, fn_ret_type)
g.write('.data') g.write('.data')
} else { } else {
g.expr(expr0) g.expr(expr0)
@ -5867,19 +5868,19 @@ fn (mut g Gen) return_stmt(node ast.Return) {
} else { } else {
styp := g.base_type(fn_ret_type) styp := g.base_type(fn_ret_type)
g.write('_result_ok(&(${styp}[]) { ') g.write('_result_ok(&(${styp}[]) { ')
if !fn_ret_type.is_ptr() && node.types[0].is_ptr() { if !fn_ret_type.is_ptr() && type0.is_ptr() {
if !((node.exprs[0] is ast.Ident && !g.is_amp) || sym.kind == .interface) { if !((expr0 is ast.Ident && !g.is_amp) || sym.kind == .interface) {
g.write('*') g.write('*')
} }
} }
if fn_ret_type.has_flag(.option) { if fn_ret_type.has_flag(.option) {
g.expr_with_opt(expr0, node.types[0], fn_ret_type.clear_flag(.result)) g.expr_with_opt(expr0, type0, fn_ret_type.clear_flag(.result))
} else if return_sym.kind == .array_fixed && expr0 !is ast.ArrayInit { } else if return_sym.kind == .array_fixed && expr0 !is ast.ArrayInit {
info := return_sym.info as ast.ArrayFixed info := return_sym.info as ast.ArrayFixed
g.fixed_array_var_init(g.expr_string(expr0), expr0.is_auto_deref_var(), g.fixed_array_var_init(g.expr_string(expr0), expr0.is_auto_deref_var(),
info.elem_type, info.size) info.elem_type, info.size)
} else { } else {
g.expr_with_cast(expr0, node.types[0], fn_ret_type.clear_flag(.result)) g.expr_with_cast(expr0, type0, fn_ret_type.clear_flag(.result))
} }
g.writeln(' }, (${result_name}*)(&${tmpvar}), sizeof(${styp}));') g.writeln(' }, (${result_name}*)(&${tmpvar}), sizeof(${styp}));')
} }
@ -5892,12 +5893,11 @@ fn (mut g Gen) return_stmt(node ast.Return) {
// set free_parent_scopes to true, since all variables defined in parent // set free_parent_scopes to true, since all variables defined in parent
// scopes need to be freed before the return // scopes need to be freed before the return
if g.is_autofree { if g.is_autofree {
expr := node.exprs[0] if expr0 is ast.Ident {
if expr is ast.Ident { g.returned_var_name = expr0.name
g.returned_var_name = expr.name
} }
if !use_tmp_var && !g.is_builtin_mod { if !use_tmp_var && !g.is_builtin_mod {
use_tmp_var = expr is ast.CallExpr use_tmp_var = expr0 is ast.CallExpr
} }
} }
// Create a temporary variable for the return expression // Create a temporary variable for the return expression
@ -5926,68 +5926,67 @@ fn (mut g Gen) return_stmt(node ast.Return) {
var_str := g.expr_string(expr0) var_str := g.expr_string(expr0)
g.write(var_str.trim('&')) g.write(var_str.trim('&'))
} else if g.fn_decl.return_type.has_flag(.option) { } else if g.fn_decl.return_type.has_flag(.option) {
g.expr_with_opt(expr0, node.types[0], g.fn_decl.return_type) g.expr_with_opt(expr0, type0, g.fn_decl.return_type)
} else if g.table.sym(g.fn_decl.return_type).kind in [.sum_type, .interface] { } else if g.table.sym(g.fn_decl.return_type).kind in [.sum_type, .interface] {
g.expr_with_cast(expr0, node.types[0], g.fn_decl.return_type) g.expr_with_cast(expr0, type0, g.fn_decl.return_type)
} else { } else {
g.write('*') g.write('*')
g.expr(expr0) g.expr(expr0)
} }
} else { } else {
if g.fn_decl.return_type.has_flag(.option) { if g.fn_decl.return_type.has_flag(.option) {
expr0_is_alias_fn_ret := expr0 is ast.CallExpr && node.types[0].has_flag(.option) expr0_is_alias_fn_ret := expr0 is ast.CallExpr && type0.has_flag(.option)
&& g.table.type_kind(node.types[0]) in [.placeholder, .alias] && g.table.type_kind(type0) in [.placeholder, .alias]
// return foo() where foo() returns different option alias than current fn // return foo() where foo() returns different option alias than current fn
if expr0_is_alias_fn_ret { if expr0_is_alias_fn_ret {
g.expr_opt_with_cast(node.exprs[0], node.types[0], g.fn_decl.return_type) g.expr_opt_with_cast(expr0, type0, g.fn_decl.return_type)
} else { } else {
g.expr_with_opt(node.exprs[0], node.types[0], g.fn_decl.return_type) g.expr_with_opt(expr0, type0, g.fn_decl.return_type)
} }
} else { } else {
if fn_return_is_fixed_array && !node.types[0].has_option_or_result() { if fn_return_is_fixed_array && !type0.has_option_or_result() {
if node.exprs[0] is ast.Ident { if node.exprs[0] is ast.Ident {
g.writeln('{0};') g.writeln('{0};')
typ := if expr0.is_auto_deref_var() { typ := if node.exprs[0].is_auto_deref_var() {
node.types[0].deref() type0.deref()
} else { } else {
node.types[0] type0
} }
typ_sym := g.table.final_sym(typ) typ_sym := g.table.final_sym(typ)
if typ_sym.kind == .array_fixed if typ_sym.kind == .array_fixed
&& (typ_sym.info as ast.ArrayFixed).is_fn_ret { && (typ_sym.info as ast.ArrayFixed).is_fn_ret {
g.write('memcpy(${tmpvar}.ret_arr, ${g.expr_string(node.exprs[0])}.ret_arr, sizeof(${g.styp(typ)}))') g.write('memcpy(${tmpvar}.ret_arr, ${g.expr_string(expr0)}.ret_arr, sizeof(${g.styp(typ)}))')
} else { } else {
g.write('memcpy(${tmpvar}.ret_arr, ${g.expr_string(node.exprs[0])}, sizeof(${g.styp(typ)}))') g.write('memcpy(${tmpvar}.ret_arr, ${g.expr_string(expr0)}, sizeof(${g.styp(typ)}))')
} }
} else if node.exprs[0] in [ast.ArrayInit, ast.StructInit] { } else if expr0 in [ast.ArrayInit, ast.StructInit] {
if node.exprs[0] is ast.ArrayInit && node.exprs[0].is_fixed if expr0 is ast.ArrayInit && expr0.is_fixed && expr0.has_init {
&& node.exprs[0].has_init { if (expr0 as ast.ArrayInit).init_expr.is_literal() {
if (node.exprs[0] as ast.ArrayInit).init_expr.is_literal() {
g.write('{.ret_arr=') g.write('{.ret_arr=')
g.expr_with_cast(node.exprs[0], node.types[0], g.fn_decl.return_type) g.expr_with_cast(expr0, type0, g.fn_decl.return_type)
g.writeln('};') g.writeln('};')
} else { } else {
g.writeln('{0};') g.writeln('{0};')
g.write('memcpy(${tmpvar}.ret_arr, ') g.write('memcpy(${tmpvar}.ret_arr, ')
g.expr_with_cast(node.exprs[0], node.types[0], g.fn_decl.return_type) g.expr_with_cast(expr0, type0, g.fn_decl.return_type)
g.write(', sizeof(${g.styp(node.types[0])}))') g.write(', sizeof(${g.styp(type0)}))')
} }
} else { } else {
g.writeln('{0};') g.writeln('{0};')
tmpvar2 := g.new_tmp_var() tmpvar2 := g.new_tmp_var()
g.write('${g.styp(node.types[0])} ${tmpvar2} = ') g.write('${g.styp(type0)} ${tmpvar2} = ')
g.expr_with_cast(node.exprs[0], node.types[0], g.fn_decl.return_type) g.expr_with_cast(expr0, type0, g.fn_decl.return_type)
g.writeln(';') g.writeln(';')
g.write('memcpy(${tmpvar}.ret_arr, ${tmpvar2}, sizeof(${g.styp(node.types[0])}))') g.write('memcpy(${tmpvar}.ret_arr, ${tmpvar2}, sizeof(${g.styp(type0)}))')
} }
} else { } else {
g.writeln('{0};') g.writeln('{0};')
g.write('memcpy(${tmpvar}.ret_arr, ') g.write('memcpy(${tmpvar}.ret_arr, ')
g.expr_with_cast(node.exprs[0], node.types[0], g.fn_decl.return_type) g.expr_with_cast(expr0, type0, g.fn_decl.return_type)
g.write(', sizeof(${g.styp(node.types[0])}))') g.write(', sizeof(${g.styp(type0)}))')
} }
} else { } else {
g.expr_with_cast(node.exprs[0], node.types[0], g.fn_decl.return_type) g.expr_with_cast(expr0, type0, g.fn_decl.return_type)
} }
} }
} }