v: allow alias as fixed array on return (#18817)

This commit is contained in:
Felipe Pena 2023-07-13 05:58:49 -03:00 committed by GitHub
parent 029e8a815b
commit 413ffbfc3b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
13 changed files with 138 additions and 39 deletions

View File

@ -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

View File

@ -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 {

View File

@ -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
}
}

View File

@ -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 | }

View File

@ -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]!
}

View File

@ -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 {
g.write('${styp[3..]} ')
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} ')
}

View File

@ -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

View File

@ -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,14 +110,30 @@ 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 {
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 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_')
} 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 {
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}));')

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View 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]!
}