Skip to content

Commit

Permalink
cgen, checker: fix array fixed return type for interface methods (#22320
Browse files Browse the repository at this point in the history
)
  • Loading branch information
felipensp committed Sep 26, 2024
1 parent 861bbe6 commit 1cac0c3
Show file tree
Hide file tree
Showing 4 changed files with 52 additions and 23 deletions.
10 changes: 10 additions & 0 deletions vlib/v/checker/interface.v
Original file line number Diff line number Diff line change
Expand Up @@ -141,6 +141,16 @@ fn (mut c Checker) interface_decl(mut node ast.InterfaceDecl) {
}
}
}
} else if !method.return_type.has_option_or_result() {
ret_sym := c.table.sym(method.return_type)
if ret_sym.info is ast.ArrayFixed && !ret_sym.info.is_fn_ret {
c.cast_to_fixed_array_ret(method.return_type, ret_sym)
} else if ret_sym.info is ast.Alias {
parent_sym := c.table.sym(ret_sym.info.parent_type)
if parent_sym.info is ast.ArrayFixed && !parent_sym.info.is_fn_ret {
c.cast_to_fixed_array_ret(ret_sym.info.parent_type, parent_sym)
}
}
}
for j, param in method.params {
if j == 0 && is_js {
Expand Down
28 changes: 20 additions & 8 deletions vlib/v/gen/c/cgen.v
Original file line number Diff line number Diff line change
Expand Up @@ -5473,12 +5473,7 @@ fn (mut g Gen) return_stmt(node ast.Return) {
}
tmpvar := g.new_tmp_var()
g.defer_return_tmp_var = tmpvar
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)
}
ret_typ := g.ret_typ(g.unwrap_generic(fn_ret_type))
if node.exprs.len == 1 {
// `return fn_call_opt()`
if (fn_return_is_option || fn_return_is_result) && node.exprs[0] is ast.CallExpr
Expand Down Expand Up @@ -7661,7 +7656,7 @@ fn (mut g Gen) interface_table() string {
for k, method_name in inter_methods {
method := isym.find_method_with_generic_parent(method_name) or { continue }
methodidx[method.name] = k
ret_styp := g.typ(method.return_type)
ret_styp := g.ret_typ(method.return_type)
methods_struct_def.write_string('\t${ret_styp} (*_method_${c_fn_name(method.name)})(void* _')
// the first param is the receiver, it's handled by `void*` above
for i in 1 .. method.params.len {
Expand Down Expand Up @@ -7847,7 +7842,7 @@ static inline __shared__${interface_name} ${shared_fn_name}(__shared__${cctype}*
method_call = '${cctype}_${name}'
// inline void Cat_speak_Interface_Animal_method_wrapper(Cat c) { return Cat_speak(*c); }
iwpostfix := '_Interface_${interface_name}_method_wrapper'
methods_wrapper.write_string('static inline ${g.typ(method.return_type)} ${cctype}_${name}${iwpostfix}(')
methods_wrapper.write_string('static inline ${g.ret_typ(method.return_type)} ${cctype}_${name}${iwpostfix}(')
params_start_pos := g.out.len
mut params := method.params.clone()
// hack to mutate typ
Expand Down Expand Up @@ -8036,6 +8031,23 @@ fn (mut g Gen) trace_last_lines(fbase string, params TraceLastLinesParams) {
println('`'.repeat(80))
}

// ret_type generates proper type name for return type context
pub fn (mut g Gen) ret_typ(typ ast.Type) string {
mut ret_styp := g.typ(typ)
if !typ.has_option_or_result() {
ret_sym := g.table.sym(typ)
if ret_sym.info is ast.ArrayFixed && !ret_sym.info.is_fn_ret {
ret_styp = '_v_${ret_styp}'
} else if ret_sym.info is ast.Alias {
unalias_sym := g.table.sym(ret_sym.info.parent_type)
if unalias_sym.info is ast.ArrayFixed && !unalias_sym.info.is_fn_ret {
ret_styp = '_v_${g.typ(ret_sym.info.parent_type)}'
}
}
}
return ret_styp
}

pub fn (mut g Gen) get_array_depth(el_typ ast.Type) int {
typ := g.unwrap_generic(el_typ)
sym := g.table.final_sym(typ)
Expand Down
16 changes: 1 addition & 15 deletions vlib/v/gen/c/fn.v
Original file line number Diff line number Diff line change
Expand Up @@ -225,21 +225,7 @@ 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))

ret_sym := g.table.sym(g.unwrap_generic(node.return_type))
if node.return_type.has_flag(.generic) && !node.return_type.has_option_or_result()
&& ret_sym.kind == .array_fixed {
type_name = '_v_${type_name}'
} else if ret_sym.kind == .alias && !node.return_type.has_option_or_result() {
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)
}
}

type_name := g.ret_typ(g.unwrap_generic(node.return_type))
if g.pref.obfuscate && g.cur_mod.name == 'main' && name.starts_with('main__') && !node.is_main
&& node.name != 'str' {
mut key := node.name
Expand Down
21 changes: 21 additions & 0 deletions vlib/v/tests/fns/interface_methods_fixed_arr_test.v
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
module main

pub type Mat4 = [16]f32

interface IGameObject {
world_transform() Mat4
}

struct Foo implements IGameObject {
}

fn (f Foo) world_transform() Mat4 {
return Mat4{}
}

fn test_main() {
t := Foo{}
a := t.world_transform()
b := Mat4{}
assert a == b
}

0 comments on commit 1cac0c3

Please sign in to comment.