mirror of
https://github.com/vlang/v.git
synced 2023-08-10 21:13:21 +03:00
cgen: simplify fixed arr return (#18380)
This commit is contained in:
parent
1de6523da5
commit
7a25c03aa7
@ -2538,10 +2538,12 @@ pub fn (mut c Checker) expr(node_ ast.Expr) ast.Type {
|
||||
tsym := c.table.sym(unwrapped_expr_type)
|
||||
if tsym.kind == .array_fixed {
|
||||
info := tsym.info as ast.ArrayFixed
|
||||
// for dumping fixed array we must registed the fixed array struct to return from function
|
||||
if !info.is_fn_ret {
|
||||
// for dumping fixed array we must register the fixed array struct to return from function
|
||||
c.table.find_or_register_array_fixed(info.elem_type, info.size, info.size_expr,
|
||||
true)
|
||||
}
|
||||
}
|
||||
type_cname := if node.expr_type.has_flag(.option) {
|
||||
'_option_${tsym.cname}'
|
||||
} else {
|
||||
|
@ -636,13 +636,6 @@ fn (mut g Gen) assign_stmt(node_ ast.AssignStmt) {
|
||||
} else if is_fixed_array_var {
|
||||
// TODO Instead of the translated check, check if it's a pointer already
|
||||
// and don't generate memcpy &
|
||||
right_is_fixed_ret := !(val is ast.CallExpr
|
||||
&& (val as ast.CallExpr).or_block.kind == .propagate_option)
|
||||
&& ((right_sym.info is ast.ArrayFixed
|
||||
&& (right_sym.info as ast.ArrayFixed).is_fn_ret)
|
||||
|| (val is ast.DumpExpr && right_sym.info is ast.ArrayFixed)
|
||||
|| (val is ast.CallExpr
|
||||
&& g.table.sym(g.unwrap_generic((val as ast.CallExpr).return_type)).kind == .array_fixed))
|
||||
typ_str := g.typ(val_type).trim('*')
|
||||
final_typ_str := if is_fixed_array_var { '' } else { '(${typ_str}*)' }
|
||||
final_ref_str := if is_fixed_array_var {
|
||||
@ -661,9 +654,6 @@ fn (mut g Gen) assign_stmt(node_ ast.AssignStmt) {
|
||||
g.expr(left)
|
||||
g.write(', ${final_ref_str}')
|
||||
g.expr(val)
|
||||
if right_is_fixed_ret {
|
||||
g.write('.ret_arr')
|
||||
}
|
||||
g.write(', sizeof(${typ_str})) /*assign*/')
|
||||
}
|
||||
} else if is_decl {
|
||||
|
@ -649,15 +649,15 @@ fn (mut g Gen) gen_str_for_array_fixed(info ast.ArrayFixed, styp string, str_fn_
|
||||
is_elem_ptr := typ.is_ptr()
|
||||
sym_has_str_method, str_method_expects_ptr, _ := sym.str_method_info()
|
||||
elem_str_fn_name := g.get_str_fn(typ)
|
||||
def_arg := if info.is_fn_ret { '${g.typ(typ)} a[${info.size}]' } else { '${styp} a' }
|
||||
|
||||
g.definitions.writeln('static string ${str_fn_name}(${styp} a); // auto')
|
||||
g.auto_str_funcs.writeln('static string ${str_fn_name}(${styp} a) { return indent_${str_fn_name}(a, 0);}')
|
||||
g.definitions.writeln('static string indent_${str_fn_name}(${styp} a, int indent_count); // auto')
|
||||
g.auto_str_funcs.writeln('static string indent_${str_fn_name}(${styp} a, int indent_count) {')
|
||||
g.definitions.writeln('static string ${str_fn_name}(); // auto')
|
||||
g.auto_str_funcs.writeln('static string ${str_fn_name}(${def_arg}) { return indent_${str_fn_name}(a, 0);}')
|
||||
g.definitions.writeln('static string indent_${str_fn_name}(${def_arg}, int indent_count); // auto')
|
||||
g.auto_str_funcs.writeln('static string indent_${str_fn_name}(${def_arg}, int indent_count) {')
|
||||
g.auto_str_funcs.writeln('\tstrings__Builder sb = strings__new_builder(${info.size} * 10);')
|
||||
g.auto_str_funcs.writeln('\tstrings__Builder_write_string(&sb, _SLIT("["));')
|
||||
g.auto_str_funcs.writeln('\tfor (int i = 0; i < ${info.size}; ++i) {')
|
||||
suffix := if info.is_fn_ret { '.ret_arr' } else { '' }
|
||||
if sym.kind == .function {
|
||||
g.auto_str_funcs.writeln('\t\tstring x = ${elem_str_fn_name}();')
|
||||
g.auto_str_funcs.writeln('\t\tstrings__Builder_write_string(&sb, x);')
|
||||
@ -666,30 +666,30 @@ fn (mut g Gen) gen_str_for_array_fixed(info ast.ArrayFixed, styp string, str_fn_
|
||||
if should_use_indent_func(sym.kind) && !sym_has_str_method {
|
||||
if is_elem_ptr {
|
||||
g.auto_str_funcs.writeln('\t\tstrings__Builder_write_string(&sb, _SLIT("${deref_label}"));')
|
||||
g.auto_str_funcs.writeln('\t\tif ( 0 == a${suffix}[i] ) {')
|
||||
g.auto_str_funcs.writeln('\t\tif ( 0 == a[i] ) {')
|
||||
g.auto_str_funcs.writeln('\t\t\tstrings__Builder_write_string(&sb, _SLIT("0"));')
|
||||
g.auto_str_funcs.writeln('\t\t}else{')
|
||||
g.auto_str_funcs.writeln('\t\t\tstrings__Builder_write_string(&sb, ${elem_str_fn_name}( ${deref} a${suffix}[i]) );')
|
||||
g.auto_str_funcs.writeln('\t\t\tstrings__Builder_write_string(&sb, ${elem_str_fn_name}( ${deref} a[i]) );')
|
||||
g.auto_str_funcs.writeln('\t\t}')
|
||||
} else {
|
||||
g.auto_str_funcs.writeln('\t\tstrings__Builder_write_string(&sb, ${elem_str_fn_name}( ${deref} a${suffix}[i]) );')
|
||||
g.auto_str_funcs.writeln('\t\tstrings__Builder_write_string(&sb, ${elem_str_fn_name}( ${deref} a[i]) );')
|
||||
}
|
||||
} else if sym.kind in [.f32, .f64] {
|
||||
if sym.kind == .f32 {
|
||||
field_str := str_intp_g32('a${suffix}[i]')
|
||||
field_str := str_intp_g32('a[i]')
|
||||
g.auto_str_funcs.writeln('\t\tstrings__Builder_write_string(&sb, ${field_str} );')
|
||||
} else {
|
||||
field_str := str_intp_g64('a${suffix}[i]')
|
||||
field_str := str_intp_g64('a[i]')
|
||||
g.auto_str_funcs.writeln('\t\tstrings__Builder_write_string(&sb, ${field_str} );')
|
||||
}
|
||||
} else if sym.kind == .string {
|
||||
field_str := str_intp_sq('a${suffix}[i]')
|
||||
field_str := str_intp_sq('a[i]')
|
||||
g.auto_str_funcs.writeln('\t\tstrings__Builder_write_string(&sb, ${field_str});')
|
||||
} else if sym.kind == .rune {
|
||||
tmp_str := str_intp_rune('${elem_str_fn_name}( ${deref} a${suffix}[i])')
|
||||
tmp_str := str_intp_rune('${elem_str_fn_name}( ${deref} a[i])')
|
||||
g.auto_str_funcs.writeln('\t\tstrings__Builder_write_string(&sb, ${tmp_str});')
|
||||
} else {
|
||||
g.auto_str_funcs.writeln('\t\tstrings__Builder_write_string(&sb, ${elem_str_fn_name}( ${deref} a${suffix}[i]));')
|
||||
g.auto_str_funcs.writeln('\t\tstrings__Builder_write_string(&sb, ${elem_str_fn_name}( ${deref} a[i]));')
|
||||
}
|
||||
}
|
||||
g.auto_str_funcs.writeln('\t\tif (i < ${info.size - 1}) {')
|
||||
|
@ -138,6 +138,7 @@ mut:
|
||||
inside_or_block bool
|
||||
inside_call bool
|
||||
inside_curry_call bool // inside foo()()!, foo()()?, foo()()
|
||||
expected_fixed_arr bool
|
||||
inside_for_c_stmt bool
|
||||
inside_comptime_for_field bool
|
||||
inside_cast_in_heap int // inside cast to interface type in heap (resolve recursive calls)
|
||||
@ -2452,11 +2453,6 @@ fn (mut g Gen) expr_with_cast(expr ast.Expr, got_type_raw ast.Type, expected_typ
|
||||
}
|
||||
// no cast
|
||||
g.expr(expr)
|
||||
if expr is ast.CallExpr && !(expr as ast.CallExpr).is_fn_var && !expected_type.has_flag(.option)
|
||||
&& exp_sym.kind == .array_fixed {
|
||||
// it's non-option fixed array, requires accessing .ret_arr member to get the array
|
||||
g.write('.ret_arr')
|
||||
}
|
||||
}
|
||||
|
||||
fn write_octal_escape(mut b strings.Builder, c u8) {
|
||||
@ -4989,12 +4985,16 @@ fn (mut g Gen) return_stmt(node ast.Return) {
|
||||
g.writeln('{0};')
|
||||
if node.exprs[0] is ast.Ident {
|
||||
g.write('memcpy(${tmpvar}.ret_arr, ${g.expr_string(node.exprs[0])}, sizeof(${g.typ(node.types[0])})) /*ret*/')
|
||||
} else {
|
||||
} else if node.exprs[0] is ast.ArrayInit {
|
||||
tmpvar2 := g.new_tmp_var()
|
||||
g.write('${g.typ(node.types[0])} ${tmpvar2} = ')
|
||||
g.expr_with_cast(node.exprs[0], node.types[0], g.fn_decl.return_type)
|
||||
g.writeln(';')
|
||||
g.write('memcpy(${tmpvar}.ret_arr, ${tmpvar2}, sizeof(${g.typ(node.types[0])})) /*ret*/')
|
||||
} else {
|
||||
g.write('memcpy(${tmpvar}.ret_arr, ')
|
||||
g.expr_with_cast(node.exprs[0], node.types[0], g.fn_decl.return_type)
|
||||
g.write(', sizeof(${g.typ(node.types[0])})) /*ret*/')
|
||||
}
|
||||
} else {
|
||||
g.expr_with_cast(node.exprs[0], node.types[0], g.fn_decl.return_type)
|
||||
|
@ -67,6 +67,10 @@ fn (mut g Gen) dump_expr(node ast.DumpExpr) {
|
||||
g.inside_opt_or_res = old_inside_opt_or_res
|
||||
}
|
||||
g.write(')')
|
||||
if (g.inside_assign || g.expected_fixed_arr) && !expr_type.has_flag(.option)
|
||||
&& g.table.type_kind(expr_type) == .array_fixed {
|
||||
g.write('.ret_arr')
|
||||
}
|
||||
}
|
||||
|
||||
fn (mut g Gen) dump_expr_definitions() {
|
||||
@ -106,8 +110,13 @@ fn (mut g Gen) dump_expr_definitions() {
|
||||
dump_typedefs['typedef ${str_tdef};'] = true
|
||||
str_dumparg_ret_type = str_dumparg_type
|
||||
} else if !typ.has_flag(.option) && dump_sym.kind == .array_fixed {
|
||||
if (dump_sym.info as ast.ArrayFixed).is_fn_ret {
|
||||
str_dumparg_ret_type = str_dumparg_type
|
||||
str_dumparg_type = str_dumparg_type.trim_string_left('_v_')
|
||||
} else {
|
||||
// fixed array returned from function
|
||||
str_dumparg_ret_type = '_v_' + str_dumparg_type
|
||||
}
|
||||
} else {
|
||||
str_dumparg_ret_type = str_dumparg_type
|
||||
}
|
||||
|
@ -1474,6 +1474,11 @@ fn (mut g Gen) method_call(node ast.CallExpr) {
|
||||
g.write(', ${array_depth}')
|
||||
}
|
||||
g.write(')')
|
||||
if node.return_type != 0 && !node.return_type.has_flag(.option)
|
||||
&& g.table.sym(node.return_type).kind == .array_fixed {
|
||||
// it's non-option fixed array, requires accessing .ret_arr member to get the array
|
||||
g.write('.ret_arr')
|
||||
}
|
||||
}
|
||||
|
||||
fn (mut g Gen) fn_call(node ast.CallExpr) {
|
||||
@ -1776,6 +1781,11 @@ fn (mut g Gen) fn_call(node ast.CallExpr) {
|
||||
if name != '&' {
|
||||
g.write(')')
|
||||
}
|
||||
if node.return_type != 0 && !node.return_type.has_flag(.option)
|
||||
&& g.table.sym(node.return_type).kind == .array_fixed {
|
||||
// it's non-option fixed array, requires accessing .ret_arr member to get the array
|
||||
g.write('.ret_arr')
|
||||
}
|
||||
if tmp_cnt_save >= 0 {
|
||||
g.writeln(';')
|
||||
g.keep_alive_call_postgen(node, tmp_cnt_save)
|
||||
@ -1916,6 +1926,10 @@ fn (mut g Gen) autofree_call_postgen(node_pos int) {
|
||||
}
|
||||
|
||||
fn (mut g Gen) call_args(node ast.CallExpr) {
|
||||
g.expected_fixed_arr = true
|
||||
defer {
|
||||
g.expected_fixed_arr = false
|
||||
}
|
||||
args := if g.is_js_call {
|
||||
if node.args.len < 1 {
|
||||
g.error('node should have at least 1 arg', node.pos)
|
||||
|
@ -368,10 +368,6 @@ fn (mut g Gen) index_of_fixed_array(node ast.IndexExpr, sym ast.TypeSymbol) {
|
||||
} else {
|
||||
g.expr(node.left)
|
||||
}
|
||||
if node.left is ast.CallExpr && sym.kind == .array_fixed
|
||||
&& (sym.info as ast.ArrayFixed).is_fn_ret {
|
||||
g.write('.ret_arr')
|
||||
}
|
||||
}
|
||||
g.write('[')
|
||||
if g.is_direct_array_access || g.pref.translated || node.index is ast.IntegerLiteral {
|
||||
|
@ -8,6 +8,10 @@ import v.token
|
||||
import v.util
|
||||
|
||||
fn (mut g Gen) infix_expr(node ast.InfixExpr) {
|
||||
g.expected_fixed_arr = true
|
||||
defer {
|
||||
g.expected_fixed_arr = false
|
||||
}
|
||||
if node.auto_locked != '' {
|
||||
g.writeln('sync__RwMutex_lock(&${node.auto_locked}->mtx);')
|
||||
}
|
||||
|
@ -54,8 +54,10 @@ fn (mut g Gen) string_inter_literal_sb_optimized(call_expr ast.CallExpr) {
|
||||
fn (mut g Gen) gen_expr_to_string(expr ast.Expr, etype ast.Type) {
|
||||
old_inside_opt_or_res := g.inside_opt_or_res
|
||||
g.inside_opt_or_res = true
|
||||
g.expected_fixed_arr = true
|
||||
defer {
|
||||
g.inside_opt_or_res = old_inside_opt_or_res
|
||||
g.expected_fixed_arr = false
|
||||
}
|
||||
is_shared := etype.has_flag(.shared_f)
|
||||
mut typ := etype
|
||||
|
52
vlib/v/tests/fixed_array_2_test.v
Normal file
52
vlib/v/tests/fixed_array_2_test.v
Normal file
@ -0,0 +1,52 @@
|
||||
struct Test {}
|
||||
|
||||
fn (t Test) conversion_error(value u16) [4]u8 {
|
||||
return conversion_error(value)
|
||||
}
|
||||
|
||||
fn arr_opt() ?[2]int {
|
||||
return [1, 2]!
|
||||
}
|
||||
|
||||
fn conversion_error(value u16) [4]u8 {
|
||||
mut return_value := [4]u8{}
|
||||
for i := 0; i < 4; i++ {
|
||||
return_value[i] = u8(value)
|
||||
}
|
||||
return return_value
|
||||
}
|
||||
|
||||
fn test_assign() {
|
||||
// -- Block below works fine
|
||||
value := conversion_error(42)
|
||||
println(value)
|
||||
}
|
||||
|
||||
fn test_assign_method() {
|
||||
value2 := Test{}.conversion_error(42)
|
||||
println(value2)
|
||||
}
|
||||
|
||||
fn test_ret() {
|
||||
// -- Block above works fine
|
||||
println(conversion_error(42))
|
||||
println(Test{}.conversion_error(42))
|
||||
}
|
||||
|
||||
fn test_assign_dump() {
|
||||
y := dump(conversion_error(42))
|
||||
dump(y)
|
||||
y2 := dump(Test{}.conversion_error(42))
|
||||
dump(y2)
|
||||
}
|
||||
|
||||
fn test_assert() {
|
||||
a := [1, 2]!
|
||||
assert dump(a) == [1, 2]!
|
||||
}
|
||||
|
||||
fn test_call() {
|
||||
conversion_error(42)
|
||||
Test{}.conversion_error(42)
|
||||
dump(arr_opt())
|
||||
}
|
Loading…
Reference in New Issue
Block a user