mirror of
https://github.com/vlang/v.git
synced 2023-08-10 21:13:21 +03:00
v: allow alias as fixed array on return (#18817)
This commit is contained in:
parent
029e8a815b
commit
413ffbfc3b
@ -887,6 +887,30 @@ pub fn (t &TypeSymbol) is_heap() bool {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn (t &ArrayFixed) is_compatible(t2 ArrayFixed) bool {
|
||||
return t.size == t2.size && t.elem_type == t2.elem_type
|
||||
}
|
||||
|
||||
pub fn (t &TypeSymbol) is_array_fixed() bool {
|
||||
if t.info is ArrayFixed {
|
||||
return true
|
||||
} else if t.info is Alias {
|
||||
return global_table.final_sym(t.info.parent_type).is_array_fixed()
|
||||
} else {
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
pub fn (t &TypeSymbol) is_array_fixed_ret() bool {
|
||||
if t.info is ArrayFixed {
|
||||
return t.info.is_fn_ret
|
||||
} else if t.info is Alias {
|
||||
return global_table.final_sym(t.info.parent_type).is_array_fixed_ret()
|
||||
} else {
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
pub fn (mut t Table) register_builtin_type_symbols() {
|
||||
// reserve index 0 so nothing can go there
|
||||
// save index check, 0 will mean not found
|
||||
|
@ -129,8 +129,6 @@ fn (mut c Checker) fn_decl(mut node ast.FnDecl) {
|
||||
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) {
|
||||
@ -1521,6 +1519,16 @@ fn (mut c Checker) cast_fixed_array_ret(typ ast.Type, sym ast.TypeSymbol) ast.Ty
|
||||
return typ
|
||||
}
|
||||
|
||||
// cast_to_fixed_array_ret casts a ArrayFixed type created to do not return to a returning one
|
||||
fn (mut c Checker) cast_to_fixed_array_ret(typ ast.Type, sym ast.TypeSymbol) ast.Type {
|
||||
if sym.kind == .array_fixed && !(sym.info as ast.ArrayFixed).is_fn_ret {
|
||||
info := sym.info as ast.ArrayFixed
|
||||
return c.table.find_or_register_array_fixed(info.elem_type, info.size, info.size_expr,
|
||||
true)
|
||||
}
|
||||
return typ
|
||||
}
|
||||
|
||||
fn (mut c Checker) method_call(mut node ast.CallExpr) ast.Type {
|
||||
left_type := c.expr(mut node.left)
|
||||
if left_type == ast.void_type {
|
||||
|
@ -208,8 +208,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 {
|
||||
exp_final_sym := c.table.final_sym(exp_type)
|
||||
got_final_sym := c.table.final_sym(got_type)
|
||||
if exp_final_sym.kind == .array_fixed && got_final_sym.kind == .array_fixed {
|
||||
got_arr_sym := c.table.sym(c.cast_to_fixed_array_ret(got_type, got_final_sym))
|
||||
if (exp_final_sym.info as ast.ArrayFixed).is_compatible(got_arr_sym.info as ast.ArrayFixed) {
|
||||
continue
|
||||
}
|
||||
}
|
||||
|
@ -1,7 +0,0 @@
|
||||
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,13 +0,0 @@
|
||||
type Abc = [3]int
|
||||
|
||||
fn return_fixed_array() [3]int {
|
||||
return [1, 2, 3]!
|
||||
}
|
||||
|
||||
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]!
|
||||
}
|
@ -578,9 +578,22 @@ fn (mut g Gen) assign_stmt(node_ ast.AssignStmt) {
|
||||
}
|
||||
}
|
||||
if !is_used_var_styp {
|
||||
if !val_type.has_flag(.option) && left_sym.info is ast.ArrayFixed
|
||||
&& left_sym.info.is_fn_ret {
|
||||
if !val_type.has_flag(.option) && left_sym.is_array_fixed() {
|
||||
if left_sym.kind == .alias {
|
||||
parent_sym := g.table.final_sym((left_sym.info as ast.Alias).parent_type)
|
||||
styp = g.typ((left_sym.info as ast.Alias).parent_type)
|
||||
if !parent_sym.is_array_fixed_ret() {
|
||||
g.write('${styp} ')
|
||||
} else {
|
||||
g.write('${styp[3..]} ')
|
||||
}
|
||||
} else {
|
||||
if !left_sym.is_array_fixed_ret() {
|
||||
g.write('${styp} ')
|
||||
} else {
|
||||
g.write('${styp[3..]} ')
|
||||
}
|
||||
}
|
||||
} else {
|
||||
g.write('${styp} ')
|
||||
}
|
||||
|
@ -4760,7 +4760,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)
|
||||
fn_return_is_fixed_array := sym.is_array_fixed() && !fn_ret_type.has_flag(.option)
|
||||
|
||||
mut has_semicolon := false
|
||||
if node.exprs.len == 0 {
|
||||
@ -4782,6 +4782,8 @@ fn (mut g Gen) return_stmt(node ast.Return) {
|
||||
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}'
|
||||
} else if sym.kind == .alias && fn_return_is_fixed_array {
|
||||
ret_typ = '_v_' + g.typ((sym.info as ast.Alias).parent_type)
|
||||
}
|
||||
mut use_tmp_var := g.defer_stmts.len > 0 || g.defer_profile_code.len > 0
|
||||
|| g.cur_lock.lockeds.len > 0
|
||||
|
@ -100,6 +100,7 @@ fn (mut g Gen) dump_expr_definitions() {
|
||||
}
|
||||
str_dumparg_type += g.cc_type(dump_type, true) + ptr_asterisk
|
||||
}
|
||||
mut is_fixed_arr_ret := false
|
||||
if dump_sym.kind == .function {
|
||||
fninfo := dump_sym.info as ast.FnType
|
||||
str_dumparg_type = 'DumpFNType_${name}'
|
||||
@ -109,7 +110,9 @@ fn (mut g Gen) dump_expr_definitions() {
|
||||
g.go_back(str_tdef.len)
|
||||
dump_typedefs['typedef ${str_tdef};'] = true
|
||||
str_dumparg_ret_type = str_dumparg_type
|
||||
} else if !typ.has_flag(.option) && dump_sym.kind == .array_fixed {
|
||||
} else if !typ.has_flag(.option) && dump_sym.is_array_fixed() {
|
||||
match 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_')
|
||||
@ -117,6 +120,20 @@ fn (mut g Gen) dump_expr_definitions() {
|
||||
// fixed array returned from function
|
||||
str_dumparg_ret_type = '_v_' + str_dumparg_type
|
||||
}
|
||||
}
|
||||
.alias {
|
||||
parent_sym := g.table.sym((dump_sym.info as ast.Alias).parent_type)
|
||||
if parent_sym.kind == .array_fixed {
|
||||
str_dumparg_ret_type =
|
||||
if (parent_sym.info as ast.ArrayFixed).is_fn_ret { '' } else { '_v_' } +
|
||||
g.cc_type((dump_sym.info as ast.Alias).parent_type, true)
|
||||
str_dumparg_type = str_dumparg_ret_type.trim_string_left('_v_')
|
||||
is_fixed_arr_ret = true
|
||||
}
|
||||
}
|
||||
else {}
|
||||
}
|
||||
is_fixed_arr_ret = true
|
||||
} else {
|
||||
str_dumparg_ret_type = str_dumparg_type
|
||||
}
|
||||
@ -173,7 +190,7 @@ fn (mut g Gen) dump_expr_definitions() {
|
||||
dump_fns.writeln('\tstrings__Builder_write_string(&sb, value);')
|
||||
dump_fns.writeln("\tstrings__Builder_write_rune(&sb, '\\n');")
|
||||
surrounder.builder_write_afters(mut dump_fns)
|
||||
if !typ.has_flag(.option) && dump_sym.kind == .array_fixed {
|
||||
if is_fixed_arr_ret {
|
||||
tmp_var := g.new_tmp_var()
|
||||
dump_fns.writeln('\t${str_dumparg_ret_type} ${tmp_var} = {0};')
|
||||
dump_fns.writeln('\tmemcpy(${tmp_var}.ret_arr, dump_arg, sizeof(${str_dumparg_type}));')
|
||||
|
@ -225,8 +225,16 @@ fn (mut g Gen) gen_fn_decl(node &ast.FnDecl, skip bool) {
|
||||
mut name := g.c_fn_name(node)
|
||||
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 {
|
||||
ret_sym := g.table.sym(node.return_type)
|
||||
if node.return_type.has_flag(.generic) && ret_sym.kind == .array_fixed {
|
||||
type_name = '_v_${type_name}'
|
||||
} else if ret_sym.kind == .alias && !node.return_type.has_flag(.option) {
|
||||
unalias_typ := g.table.unaliased_type(node.return_type)
|
||||
unalias_sym := g.table.sym(unalias_typ)
|
||||
if unalias_sym.kind == .array_fixed {
|
||||
type_name = if !(unalias_sym.info as ast.ArrayFixed).is_fn_ret { '_v_' } else { '' } +
|
||||
g.typ(unalias_typ)
|
||||
}
|
||||
}
|
||||
|
||||
if g.pref.obfuscate && g.cur_mod.name == 'main' && name.starts_with('main__') && !node.is_main
|
||||
|
@ -64,6 +64,10 @@ fn (mut p Parser) parse_array_type(expecting token.Kind, is_option bool) ast.Typ
|
||||
}
|
||||
}
|
||||
p.check(.rsbr)
|
||||
p.fixed_array_dim++
|
||||
defer {
|
||||
p.fixed_array_dim--
|
||||
}
|
||||
elem_type := p.parse_type()
|
||||
if elem_type.idx() == 0 {
|
||||
// error is handled by parse_type
|
||||
@ -73,7 +77,7 @@ fn (mut p Parser) parse_array_type(expecting token.Kind, is_option bool) ast.Typ
|
||||
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,
|
||||
!is_option && p.inside_fn_return)
|
||||
p.fixed_array_dim == 1 && !is_option && p.inside_fn_return)
|
||||
if elem_type.has_flag(.generic) {
|
||||
return ast.new_type(idx).set_flag(.generic)
|
||||
}
|
||||
@ -705,6 +709,16 @@ fn (mut p Parser) find_type_or_add_placeholder(name string, language ast.Languag
|
||||
typ = ast.new_type(idx)
|
||||
}
|
||||
}
|
||||
ast.Alias {
|
||||
if p.inside_fn_return {
|
||||
parent_sym := p.table.sym(sym.info.parent_type)
|
||||
if parent_sym.kind == .array_fixed {
|
||||
info := parent_sym.array_fixed_info()
|
||||
typ = p.table.find_or_register_array_fixed(info.elem_type, info.size,
|
||||
info.size_expr, p.inside_fn_return)
|
||||
}
|
||||
}
|
||||
}
|
||||
else {}
|
||||
}
|
||||
return typ
|
||||
|
@ -65,6 +65,7 @@ mut:
|
||||
inside_map_init bool
|
||||
inside_orm bool
|
||||
inside_chan_decl bool
|
||||
fixed_array_dim int // fixed array dim parsing level
|
||||
or_is_handled bool // ignore `or` in this expression
|
||||
builtin_mod bool // are we in the `builtin` module?
|
||||
mod string // current module name
|
||||
|
@ -1,10 +1,13 @@
|
||||
type Mat = [2][2]int
|
||||
|
||||
fn main() {
|
||||
fn test_main() {
|
||||
a := Mat([[1, 2]!, [3, 4]!]!)
|
||||
println(a.foo())
|
||||
z := a.foo()
|
||||
assert z == [[1, 2]!, [3, 4]!]!
|
||||
}
|
||||
|
||||
// vfmt off
|
||||
fn (v Mat) foo() Mat {
|
||||
return v
|
||||
}
|
||||
@ -12,3 +15,4 @@ fn (v Mat) foo() Mat {
|
||||
fn bar() Mat {
|
||||
return Mat([[1, 2]!, [3, 4]!]!)
|
||||
}
|
||||
// vfmt on
|
25
vlib/v/tests/return_fixed_array_test.v
Normal file
25
vlib/v/tests/return_fixed_array_test.v
Normal file
@ -0,0 +1,25 @@
|
||||
type Abc = [3]int
|
||||
|
||||
fn return_fixed_array() [3]int {
|
||||
return [1, 2, 3]!
|
||||
}
|
||||
|
||||
fn return_fixed_array_in_multi_return() ([3]int, [3]int) {
|
||||
return [1, 2, 3]!, [4, 5, 6]!
|
||||
}
|
||||
|
||||
// vfmt off
|
||||
fn return_fixed_array_with_alias() Abc {
|
||||
return [1, 2, 3]!
|
||||
}
|
||||
// vfmt on
|
||||
|
||||
fn test_with_alias() {
|
||||
a := return_fixed_array_with_alias()
|
||||
assert a == [1, 2, 3]!
|
||||
}
|
||||
|
||||
fn test_without_alias() {
|
||||
a := return_fixed_array()
|
||||
assert a == [1, 2, 3]!
|
||||
}
|
Loading…
Reference in New Issue
Block a user