Skip to content

Commit 2abf5fc

Browse files
committed
v3: address generic review follow-ups
1 parent c1b7736 commit 2abf5fc

8 files changed

Lines changed: 602 additions & 14 deletions

File tree

vlib/v3/gen/c/fn.v

Lines changed: 118 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -927,7 +927,7 @@ fn (mut g FlatGen) gen_fn_in_module(node flat.Node, module_name string) {
927927
g.writeln('\t_vinit();')
928928
}
929929
} else {
930-
ret_type := g.tc.parse_type(node.typ)
930+
ret_type := g.fn_node_return_type(node, module_name)
931931
g.set_cur_fn_ret(ret_type)
932932
g.write(g.fn_return_type_name(ret_type))
933933
g.write(' ')
@@ -969,7 +969,7 @@ fn (mut g FlatGen) gen_fn_in_module(node flat.Node, module_name string) {
969969
fn (mut g FlatGen) gen_export_wrapper_for_fn(node flat.Node, module_name string) {
970970
export_name := g.export_fn_name_in_module(module_name, node.value) or { return }
971971
canonical_name := g.fn_c_name_in_module(module_name, node.value)
972-
ret_type := g.tc.parse_type(node.typ)
972+
ret_type := g.fn_node_return_type(node, module_name)
973973
ret_ct := g.fn_return_type_name(ret_type)
974974
g.write(ret_ct)
975975
g.write(' ')
@@ -1192,13 +1192,19 @@ fn (g &FlatGen) collect_test_harness_decl_ids(node flat.Node, mut ids []flat.Nod
11921192
}
11931193

11941194
fn (g &FlatGen) is_supported_test_fn_decl(node flat.Node) bool {
1195+
if node.generic_params.len > 0 {
1196+
return false
1197+
}
11951198
if g.test_fn_param_count(node) != 0 {
11961199
return false
11971200
}
11981201
return test_harness_fn_return_supported(g.tc.parse_type(node.typ))
11991202
}
12001203

12011204
fn (g &FlatGen) is_supported_test_hook_decl(node flat.Node) bool {
1205+
if node.generic_params.len > 0 {
1206+
return false
1207+
}
12021208
return g.test_fn_param_count(node) == 0 && g.tc.parse_type(node.typ) is types.Void
12031209
}
12041210

@@ -3734,7 +3740,7 @@ fn (mut g FlatGen) forward_decls() {
37343740
forwarded[qfn] = true
37353741
g.tc.cur_file = cur_file
37363742
g.tc.cur_module = cur_module
3737-
ret_type := g.tc.parse_type(node.typ)
3743+
ret_type := g.fn_node_return_type(node, cur_module)
37383744
g.write(g.fn_return_type_name(ret_type))
37393745
g.write(' ')
37403746
g.write(qfn)
@@ -3906,6 +3912,80 @@ fn (mut g FlatGen) implicit_veb_ctx_type() types.Type {
39063912
return g.tc.parse_type('mut Context')
39073913
}
39083914

3915+
fn (mut g FlatGen) fn_node_return_type(node flat.Node, module_name string) types.Type {
3916+
for candidate in g.fn_node_signature_names(node, module_name) {
3917+
if rt := g.tc.fn_ret_types[candidate] {
3918+
return rt
3919+
}
3920+
}
3921+
if info := g.generic_receiver_method_call_info(node.value) {
3922+
return info.return_type
3923+
}
3924+
return g.tc.parse_type(node.typ)
3925+
}
3926+
3927+
fn (mut g FlatGen) fn_node_param_types(node flat.Node, module_name string) []types.Type {
3928+
if g.fn_needs_implicit_veb_ctx(node) {
3929+
return []types.Type{}
3930+
}
3931+
mut explicit_params := 0
3932+
for i in 0 .. node.children_count {
3933+
if g.a.child_node(&node, i).kind == .param {
3934+
explicit_params++
3935+
}
3936+
}
3937+
for candidate in g.fn_node_signature_names(node, module_name) {
3938+
if params := g.tc.fn_param_types[candidate] {
3939+
if params.len == explicit_params {
3940+
return params
3941+
}
3942+
}
3943+
}
3944+
if info := g.generic_receiver_method_call_info(node.value) {
3945+
if info.params.len == explicit_params {
3946+
return info.params.clone()
3947+
}
3948+
}
3949+
return []types.Type{}
3950+
}
3951+
3952+
fn (g &FlatGen) generic_receiver_method_call_info(name string) ?types.CallInfo {
3953+
if !name.contains('.') {
3954+
return none
3955+
}
3956+
receiver := name.all_before_last('.')
3957+
if !receiver.contains('[') || !receiver.contains(']') {
3958+
return none
3959+
}
3960+
return g.tc.resolve_generic_struct_method(receiver, name.all_after_last('.'))
3961+
}
3962+
3963+
fn (mut g FlatGen) fn_node_signature_names(node flat.Node, module_name string) []string {
3964+
dotted_name := qualify_name_in_module(module_name, node.value)
3965+
cname := g.fn_c_name_in_module(module_name, node.value)
3966+
mut names := []string{}
3967+
if module_name.len > 0 && module_name != 'main' && module_name != 'builtin' {
3968+
names << dotted_name
3969+
names << c_name(dotted_name)
3970+
names << cname
3971+
names << node.value
3972+
names << c_name(node.value)
3973+
} else {
3974+
names << node.value
3975+
names << c_name(node.value)
3976+
names << dotted_name
3977+
names << c_name(dotted_name)
3978+
names << cname
3979+
}
3980+
mut deduped := []string{cap: names.len}
3981+
for name in names {
3982+
if name.len > 0 && name !in deduped {
3983+
deduped << name
3984+
}
3985+
}
3986+
return deduped
3987+
}
3988+
39093989
// write_fn_node_params writes fn node params output for c.
39103990
fn (mut g FlatGen) write_fn_node_params(node flat.Node) {
39113991
mut params_len := 0
@@ -3923,16 +4003,26 @@ fn (mut g FlatGen) write_fn_node_params(node flat.Node) {
39234003
return
39244004
}
39254005
mut written := 0
4006+
mut param_idx := 0
39264007
mut implicit_ctx_written := false
39274008
insert_implicit_ctx_after_first := needs_implicit_ctx && g.fn_has_receiver_param(node)
4009+
typed_params := g.fn_node_param_types(node, g.tc.cur_module)
4010+
concrete_optional_params := g.is_specialized_generic_fn_node(node)
39284011
for i in 0 .. node.children_count {
39294012
param_id := g.a.child(&node, i)
39304013
p := g.a.node(param_id)
39314014
if p.kind != .param {
39324015
continue
39334016
}
3934-
pt := g.tc.parse_type(p.typ)
3935-
ct := if pt is types.ArrayFixed {
4017+
pt := if param_idx < typed_params.len {
4018+
typed_params[param_idx]
4019+
} else {
4020+
g.tc.parse_type(p.typ)
4021+
}
4022+
param_idx++
4023+
ct := if concrete_optional_params && (pt is types.OptionType || pt is types.ResultType) {
4024+
g.concrete_optional_type_name(pt)
4025+
} else if pt is types.ArrayFixed {
39364026
'${g.tc.c_type(pt.elem_type)}*'
39374027
} else if pt is types.OptionType || pt is types.ResultType {
39384028
g.optional_type_name(pt)
@@ -3967,6 +4057,29 @@ fn (mut g FlatGen) write_fn_node_params(node flat.Node) {
39674057
}
39684058
}
39694059

4060+
fn (g &FlatGen) is_specialized_generic_fn_node(node flat.Node) bool {
4061+
return node.value.contains('[') || node.value.contains('_T_')
4062+
}
4063+
4064+
fn (mut g FlatGen) concrete_optional_type_name(t types.Type) string {
4065+
mut base_type := types.Type(types.void_)
4066+
if t is types.OptionType {
4067+
base_type = t.base_type
4068+
} else if t is types.ResultType {
4069+
base_type = t.base_type
4070+
} else {
4071+
return g.tc.c_type(t)
4072+
}
4073+
mut inner_ct := g.tc.c_type(base_type)
4074+
if inner_ct.starts_with('fn_ptr:') {
4075+
inner_ct = g.resolve_fn_ptr_type(inner_ct)
4076+
}
4077+
safe_name := inner_ct.replace('*', 'ptr').replace(' ', '_')
4078+
opt_name := 'Optional_${safe_name}'
4079+
g.needed_optional_types[opt_name] = inner_ct
4080+
return opt_name
4081+
}
4082+
39704083
fn (mut g FlatGen) write_implicit_veb_ctx_param() {
39714084
pt := g.implicit_veb_ctx_type()
39724085
g.write(g.tc.c_type(pt))

vlib/v3/gen/c/fn_d_parallel.v

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -434,9 +434,13 @@ fn (g &FlatGen) clone_parallel_type_checker() &types.TypeChecker {
434434
a: unsafe { g.tc.a }
435435
fn_ret_types: g.tc.fn_ret_types
436436
fn_param_types: g.tc.fn_param_types
437+
fn_ret_type_texts: g.tc.fn_ret_type_texts
438+
fn_param_type_texts: g.tc.fn_param_type_texts
437439
fn_variadic: g.tc.fn_variadic
440+
fn_implicit_veb_ctx: g.tc.fn_implicit_veb_ctx
438441
c_variadic_fns: g.tc.c_variadic_fns
439442
structs: g.tc.structs
443+
struct_generic_params: g.tc.struct_generic_params
440444
struct_field_c_abi_fns: g.tc.struct_field_c_abi_fns
441445
unions: g.tc.unions
442446
type_aliases: g.tc.type_aliases

vlib/v3/tests/parallel_cgen_test.v

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -161,6 +161,65 @@ fn test_parallel_cgen_worker_keeps_test_user_main_renamed() {
161161
assert c_code.contains('main__user_main();'), c_code
162162
}
163163

164+
fn write_parallel_generic_struct_method_project(name string) string {
165+
project_dir := os.join_path(os.temp_dir(), 'v3_${name}')
166+
os.rmdir_all(project_dir) or {}
167+
os.mkdir_all(project_dir) or { panic(err) }
168+
169+
mut main_src := strings.new_builder(96_000)
170+
main_src.writeln('module main')
171+
main_src.writeln('')
172+
main_src.writeln('struct Box[T] {')
173+
main_src.writeln(' value T')
174+
main_src.writeln('}')
175+
main_src.writeln('')
176+
main_src.writeln('fn (b Box[T]) accept(x ?T) T {')
177+
main_src.writeln(' value := x or {')
178+
main_src.writeln(' return b.value')
179+
main_src.writeln(' }')
180+
main_src.writeln(' return value')
181+
main_src.writeln('}')
182+
main_src.writeln('')
183+
main_src.writeln('fn use_box_accept() int {')
184+
main_src.writeln(' b := Box[int]{')
185+
main_src.writeln(' value: 5')
186+
main_src.writeln(' }')
187+
main_src.writeln(' return b.accept(7) + b.accept(8)')
188+
main_src.writeln('}')
189+
main_src.writeln('')
190+
for i in 0 .. 1050 {
191+
main_src.writeln('fn helper_${i}() int {')
192+
main_src.writeln('\treturn ${i}')
193+
main_src.writeln('}')
194+
main_src.writeln('')
195+
}
196+
main_src.writeln('fn main() {')
197+
main_src.writeln('\tmut total := use_box_accept()')
198+
for i in 0 .. 1050 {
199+
main_src.writeln('\ttotal += helper_${i}()')
200+
}
201+
main_src.writeln('\tprintln(int_str(total))')
202+
main_src.writeln('}')
203+
os.write_file(os.join_path(project_dir, 'main.v'), main_src.str()) or { panic(err) }
204+
return os.join_path(project_dir, 'main.v')
205+
}
206+
207+
fn test_parallel_cgen_worker_resolves_generic_struct_method_signature() {
208+
v3_bin := build_parallel_v3()
209+
main_path := write_parallel_generic_struct_method_project('parallel_generic_struct_method')
210+
bin_out := os.join_path(os.temp_dir(), 'v3_parallel_generic_struct_method_out')
211+
compile := os.execute('VJOBS=2 ${v3_bin} ${main_path} -b c -o ${bin_out}')
212+
assert compile.exit_code == 0, compile.output
213+
assert compile.output.contains('cgen (parallel)'), compile.output
214+
run := os.execute(bin_out)
215+
assert run.exit_code == 0, run.output
216+
assert run.output.trim_space() == '550740'
217+
c_code := os.read_file(bin_out + '.c') or { panic(err) }
218+
assert c_code.contains('Box_int__accept'), c_code
219+
assert c_code.contains('Optional_int x'), c_code
220+
assert !c_code.contains('?T'), c_code
221+
}
222+
164223
fn write_parallel_top_level_no_main_project(name string) string {
165224
project_dir := os.join_path(os.temp_dir(), 'v3_${name}')
166225
os.rmdir_all(project_dir) or {}

0 commit comments

Comments
 (0)