mirror of
https://github.com/vlang/v.git
synced 2023-08-10 21:13:21 +03:00
all: allow fixed array returns (#17931)
This commit is contained in:
parent
c8d2098a14
commit
9d9785cc05
@ -1061,14 +1061,15 @@ pub fn (mut t Table) find_or_register_array_with_dims(elem_type Type, nr_dims in
|
||||
return t.find_or_register_array(t.find_or_register_array_with_dims(elem_type, nr_dims - 1))
|
||||
}
|
||||
|
||||
pub fn (mut t Table) find_or_register_array_fixed(elem_type Type, size int, size_expr Expr) int {
|
||||
name := t.array_fixed_name(elem_type, size, size_expr)
|
||||
pub fn (mut t Table) find_or_register_array_fixed(elem_type Type, size int, size_expr Expr, is_fn_ret bool) int {
|
||||
prefix := if is_fn_ret { '_v_' } else { '' }
|
||||
name := prefix + t.array_fixed_name(elem_type, size, size_expr)
|
||||
// existing
|
||||
existing_idx := t.type_idxs[name]
|
||||
if existing_idx > 0 {
|
||||
return existing_idx
|
||||
}
|
||||
cname := t.array_fixed_cname(elem_type, size)
|
||||
cname := prefix + t.array_fixed_cname(elem_type, size)
|
||||
// register
|
||||
array_fixed_type := TypeSymbol{
|
||||
kind: .array_fixed
|
||||
@ -1078,6 +1079,7 @@ pub fn (mut t Table) find_or_register_array_fixed(elem_type Type, size int, size
|
||||
elem_type: elem_type
|
||||
size: size
|
||||
size_expr: size_expr
|
||||
is_fn_ret: is_fn_ret
|
||||
}
|
||||
}
|
||||
return t.register_sym(array_fixed_type)
|
||||
@ -1381,7 +1383,8 @@ pub fn (mut t Table) bitsize_to_type(bit_size int) Type {
|
||||
if bit_size % 8 != 0 { // there is no way to do `i2131(32)` so this should never be reached
|
||||
t.panic('compiler bug: bitsizes must be multiples of 8')
|
||||
}
|
||||
return new_type(t.find_or_register_array_fixed(u8_type, bit_size / 8, empty_expr))
|
||||
return new_type(t.find_or_register_array_fixed(u8_type, bit_size / 8, empty_expr,
|
||||
false))
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1511,7 +1514,7 @@ pub fn (mut t Table) resolve_generic_to_concrete(generic_type Type, generic_name
|
||||
if typ := t.resolve_generic_to_concrete(sym.info.elem_type, generic_names,
|
||||
concrete_types)
|
||||
{
|
||||
idx := t.find_or_register_array_fixed(typ, sym.info.size, None{})
|
||||
idx := t.find_or_register_array_fixed(typ, sym.info.size, None{}, false)
|
||||
if typ.has_flag(.generic) {
|
||||
return new_type(idx).derive_add_muls(generic_type).set_flag(.generic)
|
||||
} else {
|
||||
@ -1779,7 +1782,7 @@ pub fn (mut t Table) unwrap_generic_type(typ Type, generic_names []string, concr
|
||||
}
|
||||
ArrayFixed {
|
||||
unwrap_typ := t.unwrap_generic_type(ts.info.elem_type, generic_names, concrete_types)
|
||||
idx := t.find_or_register_array_fixed(unwrap_typ, ts.info.size, None{})
|
||||
idx := t.find_or_register_array_fixed(unwrap_typ, ts.info.size, None{}, false)
|
||||
return new_type(idx).derive_add_muls(typ).clear_flag(.generic)
|
||||
}
|
||||
Chan {
|
||||
|
@ -226,6 +226,7 @@ pub:
|
||||
size_expr Expr // used by fmt for e.g. ´[my_const]u8´
|
||||
pub mut:
|
||||
elem_type Type
|
||||
is_fn_ret bool
|
||||
}
|
||||
|
||||
pub struct Chan {
|
||||
|
@ -233,7 +233,8 @@ fn (mut c Checker) array_init(mut node ast.ArrayInit) ast.Type {
|
||||
}
|
||||
}
|
||||
if node.is_fixed {
|
||||
idx := c.table.find_or_register_array_fixed(elem_type, node.exprs.len, ast.empty_expr)
|
||||
idx := c.table.find_or_register_array_fixed(elem_type, node.exprs.len, ast.empty_expr,
|
||||
false)
|
||||
if elem_type.has_flag(.generic) {
|
||||
node.typ = ast.new_type(idx).set_flag(.generic)
|
||||
} else {
|
||||
@ -281,7 +282,8 @@ fn (mut c Checker) array_init(mut node ast.ArrayInit) ast.Type {
|
||||
c.error('fixed size cannot be zero or negative (fixed_size: ${fixed_size})',
|
||||
init_expr.pos())
|
||||
}
|
||||
idx := c.table.find_or_register_array_fixed(node.elem_type, int(fixed_size), init_expr)
|
||||
idx := c.table.find_or_register_array_fixed(node.elem_type, int(fixed_size), init_expr,
|
||||
false)
|
||||
if node.elem_type.has_flag(.generic) {
|
||||
node.typ = ast.new_type(idx).set_flag(.generic)
|
||||
} else {
|
||||
|
@ -120,19 +120,16 @@ fn (mut c Checker) fn_decl(mut node ast.FnDecl) {
|
||||
return_sym := c.table.final_sym(node.return_type)
|
||||
if return_sym.info is ast.MultiReturn {
|
||||
for multi_type in return_sym.info.types {
|
||||
multi_sym := c.table.sym(multi_type)
|
||||
if multi_type == ast.error_type {
|
||||
c.error('type `IError` cannot be used in multi-return, return an Option instead',
|
||||
node.return_type_pos)
|
||||
} else if multi_type.has_flag(.result) {
|
||||
c.error('result cannot be used in multi-return, return a Result instead',
|
||||
node.return_type_pos)
|
||||
} else if multi_sym.kind == .array_fixed {
|
||||
c.error('fixed array cannot be used in multi-return', node.return_type_pos)
|
||||
}
|
||||
}
|
||||
} else if return_sym.kind == .array_fixed {
|
||||
c.error('fixed array cannot be returned by function', node.return_type_pos)
|
||||
} else if c.table.sym(node.return_type).kind == .alias && return_sym.kind == .array_fixed {
|
||||
c.error('fixed array cannot be returned by function using alias', node.return_type_pos)
|
||||
}
|
||||
// Ensure each generic type of the parameter was declared in the function's definition
|
||||
if node.return_type.has_flag(.generic) {
|
||||
|
@ -202,6 +202,11 @@ fn (mut c Checker) return_stmt(mut node ast.Return) {
|
||||
}
|
||||
continue
|
||||
}
|
||||
if exp_type_sym.kind == .array_fixed && got_type_sym.kind == .array_fixed {
|
||||
if (exp_type_sym.info as ast.ArrayFixed).size == (got_type_sym.info as ast.ArrayFixed).size && (exp_type_sym.info as ast.ArrayFixed).elem_type == (got_type_sym.info as ast.ArrayFixed).elem_type {
|
||||
continue
|
||||
}
|
||||
}
|
||||
// `fn foo() !int { return Err{} }`
|
||||
if got_type_sym.kind == .struct_
|
||||
&& c.type_implements(got_type, ast.error_type, node.pos) {
|
||||
|
@ -1,11 +1,11 @@
|
||||
vlib/v/checker/tests/return_aliases_of_fixed_array.vv:8:18: error: fixed array cannot be returned by function
|
||||
vlib/v/checker/tests/return_aliases_of_fixed_array.vv:8:18: error: fixed array cannot be returned by function using alias
|
||||
6 | }
|
||||
7 |
|
||||
8 | fn (v Mat) foo() Mat {
|
||||
| ~~~
|
||||
9 | return v
|
||||
10 | }
|
||||
vlib/v/checker/tests/return_aliases_of_fixed_array.vv:12:10: error: fixed array cannot be returned by function
|
||||
vlib/v/checker/tests/return_aliases_of_fixed_array.vv:12:10: error: fixed array cannot be returned by function using alias
|
||||
10 | }
|
||||
11 |
|
||||
12 | fn bar() Mat {
|
||||
|
@ -1,12 +1,7 @@
|
||||
vlib/v/checker/tests/return_fixed_array.vv:1:25: error: fixed array cannot be returned by function
|
||||
1 | fn return_fixed_array() [3]int {
|
||||
| ~~~~~~
|
||||
2 | return [1, 2, 3]!
|
||||
3 | }
|
||||
vlib/v/checker/tests/return_fixed_array.vv:5:41: error: fixed array cannot be used in multi-return
|
||||
3 | }
|
||||
4 |
|
||||
5 | fn return_fixed_array_in_multi_return() ([3]int, [3]int) {
|
||||
| ~~~~~~~~~~~~~~~~
|
||||
6 | return [1, 2, 3]!, [4, 5, 6]!
|
||||
7 | }
|
||||
vlib/v/checker/tests/return_fixed_array.vv:11:25: error: fixed array cannot be returned by function using alias
|
||||
9 | }
|
||||
10 |
|
||||
11 | fn return_fixed_array() Abc {
|
||||
| ~~~
|
||||
12 | return [1, 2, 3]!
|
||||
13 | }
|
||||
|
@ -1,3 +1,5 @@
|
||||
type Abc = [3]int
|
||||
|
||||
fn return_fixed_array() [3]int {
|
||||
return [1, 2, 3]!
|
||||
}
|
||||
@ -5,3 +7,7 @@ fn return_fixed_array() [3]int {
|
||||
fn return_fixed_array_in_multi_return() ([3]int, [3]int) {
|
||||
return [1, 2, 3]!, [4, 5, 6]!
|
||||
}
|
||||
|
||||
fn return_fixed_array() Abc {
|
||||
return [1, 2, 3]!
|
||||
}
|
@ -553,7 +553,12 @@ fn (mut g Gen) assign_stmt(node_ ast.AssignStmt) {
|
||||
}
|
||||
}
|
||||
if !is_used_var_styp {
|
||||
g.write('${styp} ')
|
||||
if !val_type.has_flag(.option) && left_sym.info is ast.ArrayFixed
|
||||
&& (left_sym.info as ast.ArrayFixed).is_fn_ret {
|
||||
g.write('${styp[3..]} ')
|
||||
} else {
|
||||
g.write('${styp} ')
|
||||
}
|
||||
}
|
||||
if is_auto_heap {
|
||||
g.write('*')
|
||||
@ -613,6 +618,12 @@ 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.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 {
|
||||
@ -631,7 +642,10 @@ fn (mut g Gen) assign_stmt(node_ ast.AssignStmt) {
|
||||
g.expr(left)
|
||||
g.write(', ${final_ref_str}')
|
||||
g.expr(val)
|
||||
g.write(', sizeof(${typ_str}))')
|
||||
if right_is_fixed_ret {
|
||||
g.write('.ret_arr')
|
||||
}
|
||||
g.write(', sizeof(${typ_str})) /*assign*/')
|
||||
}
|
||||
} else if is_decl {
|
||||
g.is_shared = var_type.has_flag(.shared_f)
|
||||
@ -755,21 +769,27 @@ fn (mut g Gen) gen_multi_return_assign(node &ast.AssignStmt, return_type ast.Typ
|
||||
}
|
||||
} else {
|
||||
g.expr(lx)
|
||||
if g.is_arraymap_set {
|
||||
if is_auto_heap {
|
||||
g.writeln('HEAP${noscan}(${styp}, ${mr_var_name}.arg${i}) });')
|
||||
} else if is_option {
|
||||
g.writeln('(*((${g.base_type(return_type)}*)${mr_var_name}.data)).arg${i} });')
|
||||
} else {
|
||||
g.writeln('${mr_var_name}.arg${i} });')
|
||||
}
|
||||
sym := g.table.sym(node.left_types[i])
|
||||
if sym.kind == .array_fixed {
|
||||
g.writeln(';')
|
||||
g.writeln('memcpy(&${g.expr_string(lx)}, &${mr_var_name}.arg${i}, sizeof(${styp}));')
|
||||
} else {
|
||||
if is_auto_heap {
|
||||
g.writeln(' = HEAP${noscan}(${styp}, ${mr_var_name}.arg${i});')
|
||||
} else if is_option {
|
||||
g.writeln(' = (*((${g.base_type(return_type)}*)${mr_var_name}.data)).arg${i};')
|
||||
if g.is_arraymap_set {
|
||||
if is_auto_heap {
|
||||
g.writeln('HEAP${noscan}(${styp}, ${mr_var_name}.arg${i}) });')
|
||||
} else if is_option {
|
||||
g.writeln('(*((${g.base_type(return_type)}*)${mr_var_name}.data)).arg${i} });')
|
||||
} else {
|
||||
g.writeln('${mr_var_name}.arg${i} });')
|
||||
}
|
||||
} else {
|
||||
g.writeln(' = ${mr_var_name}.arg${i};')
|
||||
if is_auto_heap {
|
||||
g.writeln(' = HEAP${noscan}(${styp}, ${mr_var_name}.arg${i});')
|
||||
} else if is_option {
|
||||
g.writeln(' = (*((${g.base_type(return_type)}*)${mr_var_name}.data)).arg${i};')
|
||||
} else {
|
||||
g.writeln(' = ${mr_var_name}.arg${i};')
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -657,6 +657,7 @@ fn (mut g Gen) gen_str_for_array_fixed(info ast.ArrayFixed, styp string, str_fn_
|
||||
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);')
|
||||
@ -665,27 +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[i] ) {')
|
||||
g.auto_str_funcs.writeln('\t\tif ( 0 == a${suffix}[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[i]) );')
|
||||
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}')
|
||||
} else {
|
||||
g.auto_str_funcs.writeln('\t\tstrings__Builder_write_string(&sb, ${elem_str_fn_name}( ${deref} a[i]) );')
|
||||
g.auto_str_funcs.writeln('\t\tstrings__Builder_write_string(&sb, ${elem_str_fn_name}( ${deref} a${suffix}[i]) );')
|
||||
}
|
||||
} else if sym.kind in [.f32, .f64] {
|
||||
if sym.kind == .f32 {
|
||||
g.auto_str_funcs.writeln('\t\tstrings__Builder_write_string(&sb, ${str_intp_g32('a[i]')} );')
|
||||
field_str := str_intp_g32('a${suffix}[i]')
|
||||
g.auto_str_funcs.writeln('\t\tstrings__Builder_write_string(&sb, ${field_str} );')
|
||||
} else {
|
||||
g.auto_str_funcs.writeln('\t\tstrings__Builder_write_string(&sb, ${str_intp_g64('a[i]')} );')
|
||||
field_str := str_intp_g64('a${suffix}[i]')
|
||||
g.auto_str_funcs.writeln('\t\tstrings__Builder_write_string(&sb, ${field_str} );')
|
||||
}
|
||||
} else if sym.kind == .string {
|
||||
g.auto_str_funcs.writeln('\t\tstrings__Builder_write_string(&sb, ${str_intp_sq('a[i]')});')
|
||||
field_str := str_intp_sq('a${suffix}[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[i])')
|
||||
tmp_str := str_intp_rune('${elem_str_fn_name}( ${deref} a${suffix}[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[i]));')
|
||||
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\tif (i < ${info.size - 1}) {')
|
||||
|
@ -799,6 +799,7 @@ pub fn (mut g Gen) init() {
|
||||
g.write_typedef_types()
|
||||
g.write_typeof_functions()
|
||||
g.write_sorted_types()
|
||||
g.write_array_fixed_return_types()
|
||||
g.write_multi_return_types()
|
||||
g.definitions.writeln('// end of definitions #endif')
|
||||
if g.pref.compile_defines_all.len > 0 {
|
||||
@ -1390,7 +1391,7 @@ pub fn (mut g Gen) write_typedef_types() {
|
||||
mut def_str := 'typedef ${fixed};'
|
||||
def_str = def_str.replace_once('(*)', '(*${styp}[${len}])')
|
||||
g.type_definitions.writeln(def_str)
|
||||
} else {
|
||||
} else if !info.is_fn_ret {
|
||||
g.type_definitions.writeln('typedef ${fixed} ${styp} [${len}];')
|
||||
base := g.typ(info.elem_type.clear_flags(.option, .result))
|
||||
if info.elem_type.has_flag(.option) && base !in g.options_forward {
|
||||
@ -1573,6 +1574,30 @@ pub fn (mut g Gen) write_fn_typesymbol_declaration(sym ast.TypeSymbol) {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn (mut g Gen) write_array_fixed_return_types() {
|
||||
g.typedefs.writeln('\n// BEGIN_array_fixed_return_typedefs')
|
||||
g.type_definitions.writeln('\n// BEGIN_array_fixed_return_structs')
|
||||
|
||||
for sym in g.table.type_symbols {
|
||||
if sym.kind != .array_fixed || (sym.info as ast.ArrayFixed).elem_type.has_flag(.generic)
|
||||
|| !(sym.info as ast.ArrayFixed).is_fn_ret {
|
||||
continue
|
||||
}
|
||||
info := sym.info as ast.ArrayFixed
|
||||
mut fixed_elem_name := g.typ(info.elem_type.set_nr_muls(0))
|
||||
if info.elem_type.is_ptr() {
|
||||
fixed_elem_name += '*'.repeat(info.elem_type.nr_muls())
|
||||
}
|
||||
g.typedefs.writeln('typedef struct ${sym.cname} ${sym.cname};')
|
||||
g.type_definitions.writeln('struct ${sym.cname} {')
|
||||
g.type_definitions.writeln('\t${fixed_elem_name} ret_arr[${info.size}];')
|
||||
g.type_definitions.writeln('};')
|
||||
}
|
||||
|
||||
g.typedefs.writeln('// END_array_fixed_return_typedefs\n')
|
||||
g.type_definitions.writeln('// END_array_fixed_return_structs\n')
|
||||
}
|
||||
|
||||
pub fn (mut g Gen) write_multi_return_types() {
|
||||
start_pos := g.type_definitions.len
|
||||
g.typedefs.writeln('\n// BEGIN_multi_return_typedefs')
|
||||
@ -4564,6 +4589,7 @@ fn (mut g Gen) return_stmt(node ast.Return) {
|
||||
fn_return_is_multi := sym.kind == .multi_return
|
||||
fn_return_is_option := fn_ret_type.has_flag(.option)
|
||||
fn_return_is_result := fn_ret_type.has_flag(.result)
|
||||
fn_return_is_fixed_array := sym.kind == .array_fixed && !fn_ret_type.has_flag(.option)
|
||||
|
||||
mut has_semicolon := false
|
||||
if node.exprs.len == 0 {
|
||||
@ -4581,10 +4607,14 @@ fn (mut g Gen) return_stmt(node ast.Return) {
|
||||
return
|
||||
}
|
||||
tmpvar := g.new_tmp_var()
|
||||
ret_typ := g.typ(g.unwrap_generic(fn_ret_type))
|
||||
mut ret_typ := g.typ(g.unwrap_generic(fn_ret_type))
|
||||
if fn_ret_type.has_flag(.generic) && fn_return_is_fixed_array {
|
||||
ret_typ = '_v_${ret_typ}'
|
||||
}
|
||||
mut use_tmp_var := g.defer_stmts.len > 0 || g.defer_profile_code.len > 0
|
||||
|| g.cur_lock.lockeds.len > 0
|
||||
|| (fn_return_is_multi && node.exprs.len >= 1 && fn_return_is_option)
|
||||
|| fn_return_is_fixed_array
|
||||
// handle promoting none/error/function returning _option'
|
||||
if fn_return_is_option {
|
||||
option_none := node.exprs[0] is ast.None
|
||||
@ -4879,7 +4909,20 @@ fn (mut g Gen) return_stmt(node ast.Return) {
|
||||
if g.fn_decl.return_type.has_flag(.option) {
|
||||
g.expr_with_opt(node.exprs[0], node.types[0], g.fn_decl.return_type)
|
||||
} else {
|
||||
g.expr_with_cast(node.exprs[0], node.types[0], g.fn_decl.return_type)
|
||||
if fn_return_is_fixed_array && !node.types[0].has_flag(.option) {
|
||||
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 {
|
||||
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.expr_with_cast(node.exprs[0], node.types[0], g.fn_decl.return_type)
|
||||
}
|
||||
}
|
||||
}
|
||||
if use_tmp_var {
|
||||
@ -5638,7 +5681,8 @@ fn (mut g Gen) write_types(symbols []&ast.TypeSymbol) {
|
||||
}
|
||||
ast.ArrayFixed {
|
||||
elem_sym := g.table.sym(sym.info.elem_type)
|
||||
if !elem_sym.is_builtin() && !sym.info.elem_type.has_flag(.generic) {
|
||||
if !elem_sym.is_builtin() && !sym.info.elem_type.has_flag(.generic)
|
||||
&& !sym.info.is_fn_ret {
|
||||
// .array_fixed {
|
||||
styp := sym.cname
|
||||
// array_fixed_char_300 => char x[300]
|
||||
|
@ -225,6 +225,10 @@ fn (mut g Gen) gen_fn_decl(node &ast.FnDecl, skip bool) {
|
||||
mut name := g.c_fn_name(node) or { return }
|
||||
mut type_name := g.typ(g.unwrap_generic(node.return_type))
|
||||
|
||||
if node.return_type.has_flag(.generic) && g.table.sym(node.return_type).kind == .array_fixed {
|
||||
type_name = '_v_${type_name}'
|
||||
}
|
||||
|
||||
if g.pref.obfuscate && g.cur_mod.name == 'main' && name.starts_with('main__') && !node.is_main
|
||||
&& node.name != 'str' {
|
||||
mut key := node.name
|
||||
|
@ -368,6 +368,10 @@ 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 {
|
||||
|
@ -266,7 +266,7 @@ fn (mut p Parser) comptime_for() ast.ComptimeFor {
|
||||
p.check(.key_in)
|
||||
mut typ_pos := p.tok.pos()
|
||||
lang := p.parse_language()
|
||||
typ := p.parse_any_type(lang, false, false)
|
||||
typ := p.parse_any_type(lang, false, false, false)
|
||||
typ_pos = typ_pos.extend(p.prev_tok.pos())
|
||||
p.check(.dot)
|
||||
for_val := p.check_name()
|
||||
|
@ -10,7 +10,7 @@ import v.token
|
||||
|
||||
const maximum_inline_sum_type_variants = 3
|
||||
|
||||
pub fn (mut p Parser) parse_array_type(expecting token.Kind) ast.Type {
|
||||
pub fn (mut p Parser) parse_array_type(expecting token.Kind, is_option bool) ast.Type {
|
||||
p.check(expecting)
|
||||
// fixed array
|
||||
if p.tok.kind in [.number, .name] {
|
||||
@ -72,7 +72,8 @@ pub fn (mut p Parser) parse_array_type(expecting token.Kind) ast.Type {
|
||||
if fixed_size <= 0 {
|
||||
p.error_with_pos('fixed size cannot be zero or negative', size_expr.pos())
|
||||
}
|
||||
idx := p.table.find_or_register_array_fixed(elem_type, fixed_size, size_expr)
|
||||
idx := p.table.find_or_register_array_fixed(elem_type, fixed_size, size_expr,
|
||||
!is_option && p.inside_fn_return)
|
||||
if elem_type.has_flag(.generic) {
|
||||
return ast.new_type(idx).set_flag(.generic)
|
||||
}
|
||||
@ -462,7 +463,7 @@ pub fn (mut p Parser) parse_type() ast.Type {
|
||||
is_array := p.tok.kind == .lsbr
|
||||
pos := p.tok.pos()
|
||||
if p.tok.kind != .lcbr {
|
||||
typ = p.parse_any_type(language, nr_muls > 0, true)
|
||||
typ = p.parse_any_type(language, nr_muls > 0, true, is_option)
|
||||
if typ.idx() == 0 {
|
||||
// error is set in parse_type
|
||||
return 0
|
||||
@ -501,7 +502,7 @@ If you need to modify an array in a function, use a mutable argument instead: `f
|
||||
return typ
|
||||
}
|
||||
|
||||
pub fn (mut p Parser) parse_any_type(language ast.Language, is_ptr bool, check_dot bool) ast.Type {
|
||||
pub fn (mut p Parser) parse_any_type(language ast.Language, is_ptr bool, check_dot bool, is_option bool) ast.Type {
|
||||
mut name := p.tok.lit
|
||||
if language == .c {
|
||||
name = 'C.${name}'
|
||||
@ -555,7 +556,7 @@ pub fn (mut p Parser) parse_any_type(language ast.Language, is_ptr bool, check_d
|
||||
}
|
||||
.lsbr, .nilsbr {
|
||||
// array
|
||||
return p.parse_array_type(p.tok.kind)
|
||||
return p.parse_array_type(p.tok.kind, is_option)
|
||||
}
|
||||
else {
|
||||
if p.tok.kind == .lpar {
|
||||
|
90
vlib/v/tests/fn_fixed_array_ret_test.v
Normal file
90
vlib/v/tests/fn_fixed_array_ret_test.v
Normal file
@ -0,0 +1,90 @@
|
||||
fn fixed() [4]int {
|
||||
return [1, 2, 3, 4]!
|
||||
}
|
||||
|
||||
fn fixed_opt() ?[4]int {
|
||||
return [1, 2, 3, 4]!
|
||||
}
|
||||
|
||||
fn multi_ret() ([4]int, bool) {
|
||||
return [1, 2, 3, 4]!, true
|
||||
}
|
||||
|
||||
fn multi_ret_opt() (?[4]int, bool) {
|
||||
return [1, 2, 3, 4]!, true
|
||||
}
|
||||
|
||||
fn multi_ret_opt_none() (?[4]int, bool) {
|
||||
return none, true
|
||||
}
|
||||
|
||||
fn test_simple() {
|
||||
a := fixed()
|
||||
assert a.len == 4
|
||||
}
|
||||
|
||||
fn test_simple_option() {
|
||||
b := fixed_opt()
|
||||
assert b?.len == 4
|
||||
}
|
||||
|
||||
fn test_mr_fixed() {
|
||||
w, y := multi_ret()
|
||||
assert w.len == 4
|
||||
assert y == true
|
||||
}
|
||||
|
||||
fn test_mr_fixed_opt() {
|
||||
w1, y1 := multi_ret_opt()
|
||||
assert w1?.len == 4
|
||||
assert y1 == true
|
||||
}
|
||||
|
||||
fn test_mr_fixed_opt_none() {
|
||||
w2, y2 := multi_ret_opt_none()
|
||||
assert w2 == none
|
||||
assert y2 == true
|
||||
}
|
||||
|
||||
fn four(a [4]int) [4]int {
|
||||
assert a.len == 4
|
||||
return a
|
||||
}
|
||||
|
||||
fn test_passing_arg() {
|
||||
a := [1, 2, 3, 4]!
|
||||
b := four(a)
|
||||
assert b.len == 4
|
||||
c := four(b)
|
||||
assert c.len == 4
|
||||
}
|
||||
|
||||
fn test_passing_opt_arg() {
|
||||
a := fixed_opt()
|
||||
four(a?)
|
||||
}
|
||||
|
||||
fn test_assign() {
|
||||
mut a := [1, 2, 3, 4]!
|
||||
a = four(a)
|
||||
assert a.len == 4
|
||||
a = fixed_opt()?
|
||||
assert a.len == 4
|
||||
b := a
|
||||
assert b.len == 4
|
||||
}
|
||||
|
||||
fn gn_fixed[T](a [4]T) [4]T {
|
||||
return a
|
||||
}
|
||||
|
||||
fn test_generic() {
|
||||
b := [1, 2, 3, 4]!
|
||||
a := gn_fixed(b)
|
||||
c := gn_fixed(a)
|
||||
}
|
||||
|
||||
fn test_inline() {
|
||||
mut a := [1, 2, 3, 4]!
|
||||
assert four(a)[1] == 2
|
||||
}
|
Loading…
Reference in New Issue
Block a user