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() {
|
pub fn (mut t Table) register_builtin_type_symbols() {
|
||||||
// reserve index 0 so nothing can go there
|
// reserve index 0 so nothing can go there
|
||||||
// save index check, 0 will mean not found
|
// 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)
|
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
|
// Ensure each generic type of the parameter was declared in the function's definition
|
||||||
if node.return_type.has_flag(.generic) {
|
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
|
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 {
|
fn (mut c Checker) method_call(mut node ast.CallExpr) ast.Type {
|
||||||
left_type := c.expr(mut node.left)
|
left_type := c.expr(mut node.left)
|
||||||
if left_type == ast.void_type {
|
if left_type == ast.void_type {
|
||||||
|
@ -208,8 +208,11 @@ fn (mut c Checker) return_stmt(mut node ast.Return) {
|
|||||||
}
|
}
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
if exp_type_sym.kind == .array_fixed && got_type_sym.kind == .array_fixed {
|
exp_final_sym := c.table.final_sym(exp_type)
|
||||||
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 {
|
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
|
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 !is_used_var_styp {
|
||||||
if !val_type.has_flag(.option) && left_sym.info is ast.ArrayFixed
|
if !val_type.has_flag(.option) && left_sym.is_array_fixed() {
|
||||||
&& left_sym.info.is_fn_ret {
|
if left_sym.kind == .alias {
|
||||||
g.write('${styp[3..]} ')
|
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 {
|
} else {
|
||||||
g.write('${styp} ')
|
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_multi := sym.kind == .multi_return
|
||||||
fn_return_is_option := fn_ret_type.has_flag(.option)
|
fn_return_is_option := fn_ret_type.has_flag(.option)
|
||||||
fn_return_is_result := fn_ret_type.has_flag(.result)
|
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
|
mut has_semicolon := false
|
||||||
if node.exprs.len == 0 {
|
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))
|
mut ret_typ := g.typ(g.unwrap_generic(fn_ret_type))
|
||||||
if fn_ret_type.has_flag(.generic) && fn_return_is_fixed_array {
|
if fn_ret_type.has_flag(.generic) && fn_return_is_fixed_array {
|
||||||
ret_typ = '_v_${ret_typ}'
|
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
|
mut use_tmp_var := g.defer_stmts.len > 0 || g.defer_profile_code.len > 0
|
||||||
|| g.cur_lock.lockeds.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
|
str_dumparg_type += g.cc_type(dump_type, true) + ptr_asterisk
|
||||||
}
|
}
|
||||||
|
mut is_fixed_arr_ret := false
|
||||||
if dump_sym.kind == .function {
|
if dump_sym.kind == .function {
|
||||||
fninfo := dump_sym.info as ast.FnType
|
fninfo := dump_sym.info as ast.FnType
|
||||||
str_dumparg_type = 'DumpFNType_${name}'
|
str_dumparg_type = 'DumpFNType_${name}'
|
||||||
@ -109,14 +110,30 @@ fn (mut g Gen) dump_expr_definitions() {
|
|||||||
g.go_back(str_tdef.len)
|
g.go_back(str_tdef.len)
|
||||||
dump_typedefs['typedef ${str_tdef};'] = true
|
dump_typedefs['typedef ${str_tdef};'] = true
|
||||||
str_dumparg_ret_type = str_dumparg_type
|
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() {
|
||||||
if (dump_sym.info as ast.ArrayFixed).is_fn_ret {
|
match dump_sym.kind {
|
||||||
str_dumparg_ret_type = str_dumparg_type
|
.array_fixed {
|
||||||
str_dumparg_type = str_dumparg_type.trim_string_left('_v_')
|
if (dump_sym.info as ast.ArrayFixed).is_fn_ret {
|
||||||
} else {
|
str_dumparg_ret_type = str_dumparg_type
|
||||||
// fixed array returned from function
|
str_dumparg_type = str_dumparg_type.trim_string_left('_v_')
|
||||||
str_dumparg_ret_type = '_v_' + str_dumparg_type
|
} else {
|
||||||
|
// 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 {
|
} else {
|
||||||
str_dumparg_ret_type = str_dumparg_type
|
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_string(&sb, value);')
|
||||||
dump_fns.writeln("\tstrings__Builder_write_rune(&sb, '\\n');")
|
dump_fns.writeln("\tstrings__Builder_write_rune(&sb, '\\n');")
|
||||||
surrounder.builder_write_afters(mut dump_fns)
|
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()
|
tmp_var := g.new_tmp_var()
|
||||||
dump_fns.writeln('\t${str_dumparg_ret_type} ${tmp_var} = {0};')
|
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}));')
|
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 name := g.c_fn_name(node)
|
||||||
mut type_name := g.typ(g.unwrap_generic(node.return_type))
|
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}'
|
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
|
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.check(.rsbr)
|
||||||
|
p.fixed_array_dim++
|
||||||
|
defer {
|
||||||
|
p.fixed_array_dim--
|
||||||
|
}
|
||||||
elem_type := p.parse_type()
|
elem_type := p.parse_type()
|
||||||
if elem_type.idx() == 0 {
|
if elem_type.idx() == 0 {
|
||||||
// error is handled by parse_type
|
// 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())
|
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)
|
p.fixed_array_dim == 1 && !is_option && p.inside_fn_return)
|
||||||
if elem_type.has_flag(.generic) {
|
if elem_type.has_flag(.generic) {
|
||||||
return ast.new_type(idx).set_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)
|
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 {}
|
else {}
|
||||||
}
|
}
|
||||||
return typ
|
return typ
|
||||||
|
@ -65,6 +65,7 @@ mut:
|
|||||||
inside_map_init bool
|
inside_map_init bool
|
||||||
inside_orm bool
|
inside_orm bool
|
||||||
inside_chan_decl bool
|
inside_chan_decl bool
|
||||||
|
fixed_array_dim int // fixed array dim parsing level
|
||||||
or_is_handled bool // ignore `or` in this expression
|
or_is_handled bool // ignore `or` in this expression
|
||||||
builtin_mod bool // are we in the `builtin` module?
|
builtin_mod bool // are we in the `builtin` module?
|
||||||
mod string // current module name
|
mod string // current module name
|
||||||
|
@ -1,10 +1,13 @@
|
|||||||
type Mat = [2][2]int
|
type Mat = [2][2]int
|
||||||
|
|
||||||
fn main() {
|
fn test_main() {
|
||||||
a := Mat([[1, 2]!, [3, 4]!]!)
|
a := Mat([[1, 2]!, [3, 4]!]!)
|
||||||
println(a.foo())
|
println(a.foo())
|
||||||
|
z := a.foo()
|
||||||
|
assert z == [[1, 2]!, [3, 4]!]!
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// vfmt off
|
||||||
fn (v Mat) foo() Mat {
|
fn (v Mat) foo() Mat {
|
||||||
return v
|
return v
|
||||||
}
|
}
|
||||||
@ -12,3 +15,4 @@ fn (v Mat) foo() Mat {
|
|||||||
fn bar() Mat {
|
fn bar() Mat {
|
||||||
return Mat([[1, 2]!, [3, 4]!]!)
|
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