v2 / vlib / v / gen / c / fn.v
7447 lines · 7281 sloc · 252.82 KB · ba60fc20382bc75dcb22e8e9db12bb32e45afc56
Raw
1// Copyright (c) 2019-2024 Alexander Medvednikov. All rights reserved.
2// Use of this source code is governed by an MIT license
3// that can be found in the LICENSE file.
4module c
5
6import os
7import strings
8import v.ast
9import v.util
10
11// has[int]() => has_T_int()
12// has[int, string]() => has_T_int_string()
13const c_fn_name_escape_seq = ['[', '_T_', ', ', '_', ']', '']
14
15// c_manual_prelude_decl_names matches the C stdlib declarations emitted by `c_headers`.
16// When one of these symbols is declared in V as `fn C.name(...)`, cgen must not emit an
17// extra fallback prototype, or it can conflict with the prelude declaration.
18const c_manual_prelude_decl_names = [
19 'vfprintf',
20 'vsnprintf',
21 'fprintf',
22 'printf',
23 'snprintf',
24 'sprintf',
25 'sscanf',
26 'scanf',
27 'puts',
28 'perror',
29 'fputs',
30 'getchar',
31 'putchar',
32 'getc',
33 'fgetc',
34 'ungetc',
35 'fflush',
36 'feof',
37 'ferror',
38 'clearerr',
39 'setvbuf',
40 'ftell',
41 'rewind',
42 'fopen',
43 'fdopen',
44 'freopen',
45 'fileno',
46 'fread',
47 'fwrite',
48 'fgets',
49 'fclose',
50 'popen',
51 'pclose',
52 'malloc',
53 'calloc',
54 'realloc',
55 'aligned_alloc',
56 'free',
57 'rand',
58 'srand',
59 'atexit',
60 'exit',
61 'abs',
62 'atoi',
63 'atof',
64 'getenv',
65 'setenv',
66 'unsetenv',
67 'system',
68 'remove',
69 'rename',
70 'realpath',
71 'mkstemp',
72 'qsort',
73 'strcmp',
74 'strncmp',
75 'strdup',
76 'strcasecmp',
77 'strncasecmp',
78 'strlen',
79 'strerror',
80 'memcpy',
81 'memmove',
82 'memset',
83 'memcmp',
84 'memchr',
85 'strchr',
86 'strrchr',
87 'fseek',
88 'getline',
89 '__ctype_b_loc',
90]
91
92const vinix_c_linker_symbol_names = [
93 'text_start',
94 'text_end',
95 'rodata_start',
96 'rodata_end',
97 'data_start',
98 'data_end',
99 'interrupt_thunks',
100]
101
102const c_compiler_builtin_decl_names = [
103 '__builtin_return_address',
104]
105
106fn collect_function_defer_stmts(node &ast.FnDecl) []ast.DeferStmt {
107 mut defer_stmts := []ast.DeferStmt{cap: node.defer_stmts.len}
108 for defer_stmt in node.defer_stmts {
109 if defer_stmt.mode == .function {
110 defer_stmts << defer_stmt
111 }
112 }
113 return defer_stmts
114}
115
116fn (g &Gen) method_decl_fkey(method ast.Fn) string {
117 if method.source_fn != unsafe { nil } {
118 fndecl := unsafe { &ast.FnDecl(method.source_fn) }
119 return fndecl.fkey()
120 }
121 return method.fkey()
122}
123
124fn (g &Gen) generic_parent_method_fkey(sym ast.TypeSymbol, method_name string) string {
125 match sym.info {
126 ast.Struct, ast.Interface, ast.SumType {
127 if sym.info.parent_type.has_flag(.generic) {
128 parent_sym := g.table.sym(sym.info.parent_type)
129 if method := parent_sym.find_method(method_name) {
130 return g.method_decl_fkey(method)
131 }
132 }
133 }
134 ast.GenericInst {
135 if sym.info.parent_idx > 0 {
136 parent_sym := g.table.sym(ast.idx_to_type(sym.info.parent_idx))
137 if method := parent_sym.find_method(method_name) {
138 return g.method_decl_fkey(method)
139 }
140 }
141 }
142 else {}
143 }
144
145 return ''
146}
147
148fn (g &Gen) resolve_method_decl_fkey_for_type(typ ast.Type, method_name string) string {
149 mut candidate_types := []ast.Type{}
150 for candidate in [typ] {
151 if candidate == 0 {
152 continue
153 }
154 if candidate !in candidate_types {
155 candidate_types << candidate
156 }
157 unaliased := g.table.unaliased_type(candidate)
158 if unaliased != 0 && unaliased != candidate && unaliased !in candidate_types {
159 candidate_types << unaliased
160 }
161 if !candidate.is_ptr() {
162 ref_typ := candidate.ref()
163 if ref_typ != 0 && ref_typ !in candidate_types {
164 candidate_types << ref_typ
165 }
166 }
167 if candidate.is_ptr() {
168 deref_typ := candidate.deref()
169 if deref_typ != 0 && deref_typ !in candidate_types {
170 candidate_types << deref_typ
171 }
172 }
173 }
174 for candidate in candidate_types {
175 sym := g.table.sym(candidate)
176 parent_fkey := g.generic_parent_method_fkey(sym, method_name)
177 if parent_fkey != '' {
178 return parent_fkey
179 }
180 if method := sym.find_method_with_generic_parent(method_name) {
181 return g.method_decl_fkey(method)
182 }
183 if method := g.table.find_method(sym, method_name) {
184 return g.method_decl_fkey(method)
185 }
186 method, embed_types := g.table.find_method_from_embeds(g.table.final_sym(candidate),
187 method_name) or { ast.Fn{}, []ast.Type{} }
188 if embed_types.len != 0 {
189 return g.method_decl_fkey(method)
190 }
191 }
192 return ''
193}
194
195fn free_method_calls_free_on_receiver(method ast.Fn) bool {
196 if method.source_fn == unsafe { nil } {
197 return false
198 }
199 fn_decl := unsafe { &ast.FnDecl(method.source_fn) }
200 if fn_decl.receiver.name == '' {
201 return false
202 }
203 root := ast.Node(ast.Stmt(*fn_decl))
204 return free_method_calls_free_on_receiver_walk(root, fn_decl.receiver.name)
205}
206
207fn free_method_calls_free_on_receiver_walk(node ast.Node, receiver_name string) bool {
208 if node is ast.Expr {
209 match node {
210 ast.AnonFn, ast.LambdaExpr {
211 return false
212 }
213 ast.CallExpr {
214 if node.name == 'free' && node.args.len == 1
215 && free_method_matches_receiver_expr(node.args[0].expr, receiver_name) {
216 return true
217 }
218 }
219 else {}
220 }
221 }
222 for child in node.children() {
223 if free_method_calls_free_on_receiver_walk(child, receiver_name) {
224 return true
225 }
226 }
227 return false
228}
229
230fn free_method_matches_receiver_expr(expr ast.Expr, receiver_name string) bool {
231 return match expr {
232 ast.Ident { expr.name == receiver_name }
233 ast.CastExpr { free_method_matches_receiver_expr(expr.expr, receiver_name) }
234 ast.ParExpr { free_method_matches_receiver_expr(expr.expr, receiver_name) }
235 else { false }
236 }
237}
238
239fn (g &Gen) prefers_msvc_compatible_code() bool {
240 return g.is_cc_msvc || g.pref.os == .windows
241}
242
243fn (mut g Gen) node_decl_fkey(node ast.FnDecl) string {
244 if node.is_method && !node.name.contains('_T_') {
245 receiver_sym := g.table.sym(node.receiver.typ)
246 receiver_has_concrete_generics := match receiver_sym.info {
247 ast.Struct, ast.Interface, ast.SumType {
248 receiver_sym.info.concrete_types.len > 0 || receiver_sym.generic_types.len > 0
249 }
250 ast.GenericInst {
251 true
252 }
253 else {
254 false
255 }
256 }
257
258 needs_generic_method_fkey := node.generic_names.len > 0 || node.ninstances > 0
259 || node.receiver.typ.has_flag(.generic)
260 || g.type_has_unresolved_generic_parts(node.receiver.typ)
261 || receiver_has_concrete_generics
262 if !needs_generic_method_fkey {
263 return node.fkey()
264 }
265 resolved_fkey := g.resolve_method_decl_fkey_for_type(node.receiver.typ, node.name)
266 if resolved_fkey != '' {
267 $if trace_decl_fkey ? {
268 if node.name in ['call_generic_fn', 'collect', 'next', 'next1', 'next2', 'next3',
269 'method', 'another_method'] {
270 eprintln('>>> node_decl_fkey resolved: ${node.name} | receiver: ${g.table.type_to_str(node.receiver.typ)} | fkey: ${resolved_fkey}')
271 }
272 }
273 return resolved_fkey
274 }
275 if generic_method := g.matching_generic_file_method(node) {
276 $if trace_decl_fkey ? {
277 if node.name in ['call_generic_fn', 'collect', 'next', 'next1', 'next2', 'next3',
278 'method', 'another_method'] {
279 eprintln('>>> node_decl_fkey matched file generic: ${node.name} | receiver: ${g.table.type_to_str(node.receiver.typ)} | matched receiver: ${g.table.type_to_str(generic_method.receiver.typ)} | fkey: ${generic_method.fkey()}')
280 }
281 }
282 return generic_method.fkey()
283 }
284 }
285 return node.fkey()
286}
287
288fn (mut g Gen) method_receiver_signature(typ ast.Type) string {
289 if typ == 0 {
290 return ''
291 }
292 base_typ := g.table.unaliased_type(g.unwrap_generic(typ))
293 sym := g.table.final_sym(base_typ)
294 return '${sym.ngname}|${base_typ.nr_muls()}'
295}
296
297fn (mut g Gen) matching_generic_file_method(node ast.FnDecl) ?ast.FnDecl {
298 if !node.is_method {
299 return none
300 }
301 node_receiver_sig := g.method_receiver_signature(node.receiver.typ)
302 if node_receiver_sig == '' {
303 return none
304 }
305 for generic_fn in g.file.generic_fns {
306 if !generic_fn.is_method || generic_fn.name != node.name {
307 continue
308 }
309 $if trace_decl_fkey ? {
310 if node.name in ['call_generic_fn', 'collect', 'next', 'next1', 'next2', 'next3',
311 'method', 'another_method'] {
312 eprintln('>>> matching_generic_file_method: ${node.name} | node receiver: ${g.table.type_to_str(node.receiver.typ)} | node sig: ${node_receiver_sig} | generic receiver: ${g.table.type_to_str(generic_fn.receiver.typ)} | generic sig: ${g.method_receiver_signature(generic_fn.receiver.typ)} | generic fkey: ${generic_fn.fkey()}')
313 }
314 }
315 if g.method_receiver_signature(generic_fn.receiver.typ) == node_receiver_sig {
316 return ast.FnDecl{
317 ...*generic_fn
318 }
319 }
320 }
321 return none
322}
323
324fn (g &Gen) generic_file_fn_by_fkey(fkey string) ?ast.FnDecl {
325 for generic_fn in g.file.generic_fns {
326 if generic_fn.fkey() == fkey {
327 return ast.FnDecl{
328 ...*generic_fn
329 }
330 }
331 }
332 return none
333}
334
335// find_all_receiver_concrete_types finds all concrete type instantiations
336// of the receiver's generic type by looking up GenericInst types in the type table.
337// find_all_receiver_concrete_types finds all concrete type instantiations
338// of the receiver's generic type by examining registered concrete types of
339// sibling methods on the same receiver that have complete type sets.
340fn (g &Gen) find_all_receiver_concrete_types(node ast.FnDecl, receiver_generic_count int) [][]ast.Type {
341 receiver_typ_int := int(node.receiver.typ)
342 prefix := '${receiver_typ_int}.'
343 mut result := [][]ast.Type{}
344 mut seen := map[string]bool{}
345 // Look through all registered method generic types on this receiver
346 for fkey, type_sets in g.table.fn_generic_types {
347 if !fkey.starts_with(prefix) {
348 continue
349 }
350 for concrete_types in type_sets {
351 if concrete_types.any(it.has_flag(.generic)) {
352 continue
353 }
354 // We need sets that have both receiver + method generics
355 if concrete_types.len > receiver_generic_count {
356 receiver_part := concrete_types[..receiver_generic_count]
357 key := receiver_part.str()
358 if key !in seen {
359 seen[key] = true
360 result << receiver_part
361 }
362 }
363 }
364 }
365 // Fallback: if no sibling methods have complete type sets, look for
366 // concrete instantiations of the receiver type in the type table
367 // (GenericInst types whose parent matches the receiver).
368 if result.len == 0 {
369 receiver_parent := node.receiver.typ.set_nr_muls(0).set_flag(.generic)
370 receiver_parent_sym := g.table.sym(receiver_parent)
371 receiver_base_name := receiver_parent_sym.name.all_before('<')
372 for _, sym in g.table.type_symbols {
373 if sym.info is ast.Struct {
374 if sym.info.concrete_types.len == receiver_generic_count
375 && (sym.info.parent_type == receiver_parent
376 || (sym.info.parent_type != 0
377 && g.table.sym(sym.info.parent_type).name.all_before('<') == receiver_base_name)) {
378 cts := sym.info.concrete_types
379 if !cts.any(it.has_flag(.generic)) {
380 key := cts.str()
381 if key !in seen {
382 seen[key] = true
383 result << cts.clone()
384 }
385 }
386 }
387 }
388 }
389 }
390 return result
391}
392
393fn (mut g Gen) effective_fn_generic_names(node ast.FnDecl) []string {
394 if node.generic_names.len > 0 {
395 return node.generic_names.clone()
396 }
397 if !node.is_method {
398 return []string{}
399 }
400 resolved_fkey := g.node_decl_fkey(node)
401 if generic_method := g.generic_file_fn_by_fkey(resolved_fkey) {
402 if generic_method.generic_names.len > 0 {
403 $if trace_decl_fkey ? {
404 if node.name in ['call_generic_fn', 'collect', 'next', 'next1', 'next2', 'next3',
405 'method', 'another_method'] {
406 eprintln('>>> effective_fn_generic_names from file generic: ${node.name} | receiver: ${g.table.type_to_str(node.receiver.typ)} | generic_names: ${generic_method.generic_names}')
407 }
408 }
409 return generic_method.generic_names.clone()
410 }
411 receiver_generic_names := g.table.generic_type_names(generic_method.receiver.typ)
412 if receiver_generic_names.len > 0 {
413 $if trace_decl_fkey ? {
414 if node.name in ['call_generic_fn', 'collect', 'next', 'next1', 'next2', 'next3',
415 'method', 'another_method'] {
416 eprintln('>>> effective_fn_generic_names from generic receiver: ${node.name} | receiver: ${g.table.type_to_str(generic_method.receiver.typ)} | generic_names: ${receiver_generic_names}')
417 }
418 }
419 return receiver_generic_names
420 }
421 }
422 receiver_generic_names := g.table.generic_type_names(node.receiver.typ)
423 if receiver_generic_names.len == 0 {
424 return []string{}
425 }
426 if g.table.fn_generic_types[g.node_decl_fkey(node)].len > 0 {
427 return receiver_generic_names
428 }
429 return []string{}
430}
431
432// method_concrete_types_for_name returns the concrete types for the generic
433// name suffix in c_fn_name. For methods where cur_concrete_types includes
434// merged receiver + method types that were synthesized in gen_fn_decl
435// (because the checker only registered method-own types), strip the
436// receiver's types from the suffix since they're already encoded in the
437// receiver type name (e.g., Foo_T_string).
438fn (mut g Gen) method_concrete_types_for_name(node &ast.FnDecl) []ast.Type {
439 if !node.is_method || g.cur_concrete_types.len == 0 {
440 return g.cur_concrete_types
441 }
442 receiver_generic_names := g.table.generic_type_names(node.receiver.typ)
443 if receiver_generic_names.len == 0 || g.cur_concrete_types.len <= receiver_generic_names.len {
444 return g.cur_concrete_types
445 }
446 // Check if the checker registered incomplete types (method-only) or
447 // complete types (receiver + method). If the registered types are
448 // already complete, don't strip anything.
449 // Always use the full concrete types (receiver + method). The call site
450 // is responsible for generating matching names via method_name_concrete_types.
451 return g.cur_concrete_types
452}
453
454fn (mut g Gen) resolve_current_fn_generic_type(typ ast.Type) ast.Type {
455 if typ == 0 {
456 return 0
457 }
458 _, generic_names := g.current_fn_generic_params()
459 if generic_names.len == 0 || g.cur_concrete_types.len == 0 {
460 return g.unwrap_generic(typ)
461 }
462 mut muttable := unsafe { &ast.Table(g.table) }
463 if resolved := muttable.convert_generic_type(typ, generic_names, g.cur_concrete_types) {
464 return g.unwrap_generic(resolved)
465 }
466 return g.unwrap_generic(g.recheck_concrete_type(typ))
467}
468
469fn (mut g Gen) resolved_call_concrete_type(typ ast.Type) ast.Type {
470 return ast.mktyp(g.resolve_current_fn_generic_type(typ))
471}
472
473fn (mut g Gen) receiver_concrete_types_for_type(typ ast.Type) []ast.Type {
474 if typ == 0 {
475 return []ast.Type{}
476 }
477 sym := g.table.sym(typ)
478 match sym.info {
479 ast.Struct, ast.Interface, ast.SumType {
480 mut concrete_types := sym.info.concrete_types.clone()
481 if concrete_types.len == 0 && sym.generic_types.len == sym.info.generic_types.len
482 && sym.generic_types != sym.info.generic_types {
483 concrete_types = sym.generic_types.clone()
484 }
485 return concrete_types.map(g.unwrap_generic(it))
486 }
487 ast.GenericInst {
488 return sym.info.concrete_types.map(g.unwrap_generic(it))
489 }
490 else {
491 return []ast.Type{}
492 }
493 }
494}
495
496fn (mut g Gen) method_receiver_only_specialization_types(method ast.Fn, concrete_receiver_type ast.Type) []ast.Type {
497 mut receiver_concrete_types := g.receiver_concrete_types_for_type(concrete_receiver_type)
498 if receiver_concrete_types.len == 0 {
499 receiver_concrete_types =
500 g.receiver_concrete_types_for_type(g.recheck_concrete_type(concrete_receiver_type))
501 }
502 mut parent_method := ast.Fn{}
503 _, parent_method = g.receiver_generic_call_context(concrete_receiver_type, method.name)
504 if parent_method.params.len == 0 {
505 _, parent_method = g.receiver_generic_call_context(g.recheck_concrete_type(concrete_receiver_type),
506 method.name)
507 }
508 method_receiver_generic_names := if method.params.len > 0 {
509 g.table.generic_type_names(method.params[0].typ)
510 } else {
511 []string{}
512 }
513 parent_receiver_generic_names := if parent_method.params.len > 0 {
514 g.table.generic_type_names(parent_method.params[0].typ)
515 } else {
516 []string{}
517 }
518 full_method := if parent_method.generic_names.len > method.generic_names.len
519 || (method_receiver_generic_names.len == 0 && parent_receiver_generic_names.len > 0) {
520 parent_method
521 } else {
522 method
523 }
524 if receiver_concrete_types.len == 0 || full_method.params.len == 0 {
525 return []ast.Type{}
526 }
527 receiver_generic_names := g.table.generic_type_names(full_method.params[0].typ)
528 if receiver_generic_names.len == 0 {
529 if receiver_concrete_types.len > 0
530 && full_method.generic_names.len == receiver_concrete_types.len {
531 return receiver_concrete_types.clone()
532 }
533 return []ast.Type{}
534 }
535 if full_method.generic_names.len == 0
536 || (full_method.generic_names.len == receiver_generic_names.len
537 && full_method.generic_names == receiver_generic_names) {
538 return receiver_concrete_types.clone()
539 }
540 return []ast.Type{}
541}
542
543fn (mut g Gen) specialized_method_name_from_receiver(method ast.Fn, concrete_receiver_type ast.Type, base_name string) string {
544 specialization_types := g.method_receiver_only_specialization_types(method,
545 concrete_receiver_type)
546 if specialization_types.len == 0 {
547 return base_name
548 }
549 specialized_suffix := g.generic_fn_name(specialization_types, '')
550 if specialized_suffix != '' && base_name.ends_with(specialized_suffix) {
551 return base_name
552 }
553 return g.generic_fn_name(specialization_types, base_name)
554}
555
556fn (mut g Gen) specialized_method_name_from_receiver_context(method ast.Fn, receiver_concrete_types []ast.Type, parent_method ast.Fn, base_name string) string {
557 if receiver_concrete_types.len == 0 || method.params.len == 0 {
558 return base_name
559 }
560 method_receiver_generic_names := g.table.generic_type_names(method.params[0].typ)
561 parent_receiver_generic_names := if parent_method.params.len > 0 {
562 g.table.generic_type_names(parent_method.params[0].typ)
563 } else {
564 []string{}
565 }
566 full_method := if parent_method.generic_names.len > method.generic_names.len
567 || (method_receiver_generic_names.len == 0 && parent_receiver_generic_names.len > 0) {
568 parent_method
569 } else {
570 method
571 }
572 receiver_generic_names := g.table.generic_type_names(full_method.params[0].typ)
573 if receiver_generic_names.len == 0 {
574 if full_method.generic_names.len != receiver_concrete_types.len {
575 return base_name
576 }
577 } else if full_method.generic_names.len > 0
578 && (full_method.generic_names.len != receiver_generic_names.len
579 || full_method.generic_names != receiver_generic_names) {
580 return base_name
581 }
582 specialized_suffix := g.generic_fn_name(receiver_concrete_types, '')
583 if specialized_suffix != '' && base_name.ends_with(specialized_suffix) {
584 return base_name
585 }
586 return g.generic_fn_name(receiver_concrete_types, base_name)
587}
588
589fn (mut g Gen) recover_method_call_concrete_types_from_name(raw_method_name string, method_name string, receiver_type ast.Type, method_for_generics ast.Fn, parent_generic_method ast.Fn) []ast.Type {
590 if raw_method_name == '' || method_name == ''
591 || !raw_method_name.starts_with(method_name + '_T_') {
592 return []ast.Type{}
593 }
594 method_receiver_generic_names := if method_for_generics.params.len > 0 {
595 g.table.generic_type_names(method_for_generics.params[0].typ)
596 } else {
597 []string{}
598 }
599 parent_receiver_generic_names := if parent_generic_method.params.len > 0 {
600 g.table.generic_type_names(parent_generic_method.params[0].typ)
601 } else {
602 []string{}
603 }
604 full_method := if
605 parent_generic_method.generic_names.len > method_for_generics.generic_names.len
606 || (method_receiver_generic_names.len == 0 && parent_receiver_generic_names.len > 0) {
607 parent_generic_method
608 } else {
609 method_for_generics
610 }
611 mut full_fkey := g.resolve_method_decl_fkey_for_type(receiver_type, method_name)
612 if full_fkey == '' {
613 full_fkey = g.method_decl_fkey(full_method)
614 }
615 if full_fkey == '' {
616 return []ast.Type{}
617 }
618 for candidate in g.table.fn_generic_types[full_fkey] {
619 if candidate.any(it.has_flag(.generic) || g.type_has_unresolved_generic_parts(it)) {
620 continue
621 }
622 name_concrete_types := candidate.map(g.unwrap_generic(it))
623 if g.generic_fn_name(name_concrete_types, method_name) == raw_method_name {
624 return candidate.map(g.unwrap_generic(it))
625 }
626 }
627 return []ast.Type{}
628}
629
630fn (mut g Gen) method_name_concrete_types(full_fkey string, concrete_types []ast.Type, receiver_concrete_types []ast.Type) []ast.Type {
631 if full_fkey == '' || concrete_types.len == 0 {
632 return concrete_types.clone()
633 }
634 normalized_concrete_types := concrete_types.map(g.unwrap_generic(it))
635 normalized_receiver_types := receiver_concrete_types.map(g.unwrap_generic(it))
636 mut matching_partial_candidate := []ast.Type{}
637 for candidate in g.table.fn_generic_types[full_fkey] {
638 if candidate.any(it.has_flag(.generic) || g.type_has_unresolved_generic_parts(it)) {
639 continue
640 }
641 normalized_candidate := candidate.map(g.unwrap_generic(it))
642 if normalized_candidate == normalized_concrete_types {
643 return normalized_candidate
644 }
645 if normalized_receiver_types.len > 0
646 && normalized_candidate.len + normalized_receiver_types.len == normalized_concrete_types.len
647 && normalized_concrete_types[..normalized_receiver_types.len] == normalized_receiver_types
648 && normalized_concrete_types[normalized_receiver_types.len..] == normalized_candidate {
649 // Return the full types (receiver + method) to match the function
650 // definition which always uses complete types.
651 return normalized_concrete_types
652 }
653 if normalized_candidate.len > normalized_concrete_types.len
654 && normalized_candidate[..normalized_concrete_types.len] == normalized_concrete_types {
655 if matching_partial_candidate.len == 0 {
656 matching_partial_candidate = normalized_candidate.clone()
657 } else if matching_partial_candidate != normalized_candidate {
658 return normalized_concrete_types
659 }
660 }
661 }
662 if matching_partial_candidate.len > 0 {
663 return matching_partial_candidate
664 }
665 return normalized_concrete_types
666}
667
668fn (mut g Gen) raw_method_name_concrete_types(raw_method_name string, method_name string, raw_concrete_types []ast.Type, receiver_concrete_types []ast.Type) []ast.Type {
669 if raw_method_name == '' || method_name == '' || raw_concrete_types.len == 0
670 || !raw_method_name.starts_with(method_name + '_T_') {
671 return []ast.Type{}
672 }
673 mut resolved_raw_concrete_types := []ast.Type{}
674 for concrete_type in raw_concrete_types {
675 resolved_concrete_type := g.resolved_call_concrete_type(concrete_type)
676 if resolved_concrete_type == 0 || resolved_concrete_type.has_flag(.generic)
677 || g.type_has_unresolved_generic_parts(resolved_concrete_type) {
678 return []ast.Type{}
679 }
680 resolved_raw_concrete_types << resolved_concrete_type
681 }
682 if g.generic_fn_name(resolved_raw_concrete_types, method_name) == raw_method_name {
683 return resolved_raw_concrete_types
684 }
685 if receiver_concrete_types.len > 0
686 && resolved_raw_concrete_types.len > receiver_concrete_types.len {
687 method_only_types := resolved_raw_concrete_types[receiver_concrete_types.len..].clone()
688 if g.generic_fn_name(method_only_types, method_name) == raw_method_name {
689 return method_only_types
690 }
691 }
692 if raw_concrete_types.any(it.has_flag(.generic) || g.type_has_unresolved_generic_parts(it)) {
693 return resolved_raw_concrete_types
694 }
695 return []ast.Type{}
696}
697
698fn (g &Gen) raw_method_name_suffix(raw_method_name string, method_name string, generic_names []string) string {
699 if raw_method_name == '' || method_name == ''
700 || !raw_method_name.starts_with(method_name + '_T_') {
701 return ''
702 }
703 suffix_tokens := raw_method_name[method_name.len + 3..].split('_').filter(it.len > 0)
704 for suffix_token in suffix_tokens {
705 if suffix_token in generic_names {
706 return ''
707 }
708 }
709 return raw_method_name[method_name.len..]
710}
711
712fn (mut g Gen) is_used_by_main(node ast.FnDecl) bool {
713 $if trace_unused_by_main ? {
714 defer(fn) {
715 used_by_main := $res()
716 if !used_by_main {
717 fkey := node.fkey()
718 println('> trace_unused_by_main: mod: ${node.mod} | ${node.name} | fkey: ${fkey} | line_nr: ${node.pos.line_nr}')
719 }
720 }
721 }
722 if g.should_emit_c_fallback_decl(node) {
723 return true
724 }
725 if node.is_c_extern {
726 return true
727 }
728 if node.is_method && node.name in ['[]', '[]='] {
729 return true
730 }
731 if node.is_test && node.name.all_after_last('.') in ['before_each', 'after_each'] {
732 return true
733 }
734 if node.mod == 'builtin' && node.name in ['print', 'println', 'eprint', 'eprintln'] {
735 return true
736 }
737 mut is_used_by_main := true
738 if g.pref.skip_unused {
739 if node.is_markused {
740 // TODO for some reason markused walker doesn't set used_fns[key] true for
741 // [markused] fndecls
742 return true
743 }
744 fkey := g.node_decl_fkey(node)
745 is_used_by_main = g.table.used_features.used_fns[fkey]
746 if !is_used_by_main && g.effective_fn_generic_names(node).len > 0
747 && g.table.fn_generic_types[fkey].len > 0 {
748 is_used_by_main = true
749 }
750 if !is_used_by_main && node.generic_names.len == 0 {
751 recovered_generic_names, recovered_concrete_types :=
752 g.recover_specialized_generic_context_for(node.name)
753 if recovered_generic_names.len > 0
754 && recovered_generic_names.len == recovered_concrete_types.len {
755 for generic_fn in g.file.generic_fns {
756 if generic_fn.generic_names.len == 0 {
757 continue
758 }
759 for base_name in [generic_fn.name, generic_fn.fkey()] {
760 if g.generic_fn_name(recovered_concrete_types, base_name) == node.name {
761 is_used_by_main = g.table.used_features.used_fns[generic_fn.fkey()]
762 if is_used_by_main {
763 break
764 }
765 }
766 }
767 if is_used_by_main {
768 break
769 }
770 }
771 }
772 if !is_used_by_main && node.name.contains('_T_') {
773 is_used_by_main = true
774 }
775 }
776 $if trace_skip_unused_fns ? {
777 println('> is_used_by_main: ${is_used_by_main} | node.name: ${node.name} | fkey: ${fkey} | node.is_method: ${node.is_method}')
778 }
779 if !is_used_by_main && node.is_method {
780 receiver_type := g.table.final_type(node.receiver.typ.set_nr_muls(0))
781 for isym in g.table.type_symbols {
782 if isym.kind != .interface || isym.info !is ast.Interface {
783 continue
784 }
785 if isym.idx !in g.table.used_features.used_syms {
786 continue
787 }
788 inter_info := isym.info as ast.Interface
789 impl_types := inter_info.implementor_types(true)
790 if receiver_type !in impl_types {
791 continue
792 }
793 mut interface_requires_method := false
794 if interface_method := isym.find_method(node.name) {
795 interface_requires_method = interface_method.no_body
796 } else if interface_method := isym.find_method_with_generic_parent(node.name) {
797 interface_requires_method = interface_method.no_body
798 }
799 if interface_requires_method {
800 is_used_by_main = true
801 break
802 }
803 }
804 }
805 if !is_used_by_main {
806 $if trace_skip_unused_fns_in_c_code ? {
807 g.writeln('// trace_skip_unused_fns_in_c_code, ${node.name}, fkey: ${fkey}')
808 }
809 }
810 } else {
811 $if trace_skip_unused_fns_in_c_code ? {
812 g.writeln('// trace_skip_unused_fns_in_c_code, ${node.name}, fkey: ${node.fkey()}')
813 }
814 }
815 return is_used_by_main
816}
817
818fn file_has_c_includes(file &ast.File) bool {
819 if file == unsafe { nil } {
820 return false
821 }
822 for stmt in file.stmts {
823 if stmt is ast.HashStmt && stmt.kind in ['include', 'preinclude'] {
824 return true
825 }
826 }
827 return false
828}
829
830fn modules_with_c_includes(files []&ast.File) map[string]bool {
831 mut mods := map[string]bool{}
832 for file in files {
833 if file_has_c_includes(file) {
834 mods[file.mod.name] = true
835 if file.mod.name.ends_with('.c') {
836 mods[file.mod.name.all_before_last('.')] = true
837 }
838 }
839 }
840 return mods
841}
842
843fn file_imports_c_header_module(file &ast.File) bool {
844 if file == unsafe { nil } {
845 return false
846 }
847 for imp in file.imports {
848 if imp.source_name.ends_with('.c') {
849 return true
850 }
851 }
852 return false
853}
854
855fn (g &Gen) module_has_c_header_module(file &ast.File) bool {
856 if file_imports_c_header_module(file) {
857 return true
858 }
859 if file == unsafe { nil } || g.table == unsafe { nil } || file.path == '' {
860 return false
861 }
862 helper_dir := os.join_path(os.dir(file.path), 'c')
863 for path in g.table.filelist {
864 if path.starts_with(helper_dir + os.path_separator) {
865 return true
866 }
867 }
868 return false
869}
870
871fn (g &Gen) c_prelude_provides_decl(c_sym_name string) bool {
872 return !g.pref.no_preludes && !g.pref.is_bare && c_sym_name in c_manual_prelude_decl_names
873}
874
875fn (g &Gen) should_emit_c_fallback_decl(node ast.FnDecl) bool {
876 c_sym_name := node.name.all_after_first('C__').all_after_first('C.')
877 if c_sym_name in c_compiler_builtin_decl_names {
878 return false
879 }
880 if g.pref.os == .vinix && c_sym_name in vinix_c_linker_symbol_names {
881 return false
882 }
883 if node.language != .c || node.is_c_extern || file_has_c_includes(node.source_file)
884 || node.mod in g.mods_with_c_includes || g.module_has_c_header_module(node.source_file)
885 || g.c_prelude_provides_decl(c_sym_name) {
886 return false
887 }
888 if node.source_file == unsafe { nil } {
889 return true
890 }
891 if !node.source_file.path.starts_with(g.pref.vlib) {
892 return true
893 }
894 return node.mod == 'main' || node.source_file.is_test
895}
896
897fn (g &Gen) should_emit_c_signature_type_decls(node ast.FnDecl) bool {
898 return node.is_c_extern || g.should_emit_c_fallback_decl(node)
899 || (node.no_body && node.attrs.contains('c'))
900}
901
902fn (mut g Gen) ensure_c_extern_signature_type_decls(node ast.FnDecl) {
903 if !g.pref.skip_unused || !g.should_emit_c_signature_type_decls(node) {
904 return
905 }
906 g.ensure_c_extern_signature_type_decl(node.return_type)
907 for param in node.params {
908 g.ensure_c_extern_signature_type_decl(param.typ)
909 }
910}
911
912fn (mut g Gen) ensure_c_extern_signature_type_decl(typ_ ast.Type) {
913 if typ_ == 0 {
914 return
915 }
916 typ := typ_.clear_option_and_result().set_nr_muls(0).clear_flags(.generic, .variadic)
917 if typ == 0 {
918 return
919 }
920 sym := g.table.sym(typ)
921 if sym.is_builtin || sym.name in ['byte', 'i32', 'C.FILE'] {
922 return
923 }
924 if sym.idx in g.table.used_features.used_syms {
925 return
926 }
927 if sym.cname in g.c_extern_signature_types {
928 return
929 }
930 g.c_extern_signature_types[sym.cname] = true
931 match sym.info {
932 ast.Alias {
933 g.ensure_c_extern_signature_type_decl(sym.info.parent_type)
934 g.write_alias_typesymbol_declaration(sym)
935 }
936 ast.FnType {
937 for param in sym.info.func.params {
938 g.ensure_c_extern_signature_type_decl(param.typ)
939 }
940 g.ensure_c_extern_signature_type_decl(sym.info.func.return_type)
941 }
942 ast.Struct {
943 if sym.language == .c && sym.cname.starts_with('C__') && !sym.info.is_anon {
944 c_struct_name := sym.cname[3..]
945 if c_struct_name == 'va_list' {
946 // skip: already defined via __builtin_va_list in cheaders
947 } else if sym.info.is_typedef {
948 g.typedefs.writeln('typedef struct ${c_struct_name} ${c_struct_name};')
949 } else {
950 g.typedefs.writeln('struct ${c_struct_name};')
951 }
952 } else {
953 g.typedefs.writeln('typedef struct ${sym.cname} ${sym.cname};')
954 }
955 }
956 ast.Array {
957 g.ensure_c_extern_signature_type_decl(sym.info.elem_type)
958 }
959 ast.ArrayFixed {
960 g.ensure_c_extern_signature_type_decl(sym.info.elem_type)
961 }
962 else {}
963 }
964}
965
966fn (mut g Gen) fn_decl(node ast.FnDecl) {
967 $if trace_cgen_fn_decl ? {
968 eprintln('> g.tid: ${g.tid} | g.fid: ${g.fid:3} | g.file.path: ${g.file.path} | fn_decl: ${node.name}')
969 }
970 if node.should_be_skipped {
971 return
972 }
973 if node.is_test {
974 g.test_function_names << node.name
975 }
976 effective_generic_names := g.effective_fn_generic_names(node)
977 if node.ninstances == 0 && effective_generic_names.len > 0
978 && g.table.fn_generic_types[g.node_decl_fkey(node)].len == 0 {
979 $if trace_generics ? {
980 eprintln('skipping generic fn with no concrete instances: ${node.mod} ${node.name}')
981 }
982 return
983 }
984 if !g.is_used_by_main(node) {
985 return
986 }
987 g.ensure_c_extern_signature_type_decls(node)
988 if g.is_builtin_mod && g.pref.gc_mode == .boehm_leak && node.kind == .malloc {
989 g.definitions.write_string('#define builtin___v_malloc GC_MALLOC\n')
990 return
991 }
992
993 if g.pref.parallel_cc {
994 if node.is_anon {
995 // g.write('static ')
996 // g.definitions.write_string('static ')
997 }
998 if !node.is_anon {
999 g.out_fn_start_pos << g.out.len
1000 }
1001 }
1002 prev_is_direct_array_access := g.is_direct_array_access
1003 g.is_direct_array_access = node.is_direct_arr || g.pref.no_bounds_checking
1004 defer {
1005 g.is_direct_array_access = prev_is_direct_array_access
1006 }
1007
1008 // handle `@[ignore_overflow] fn abc() {}` and -check-overflow :
1009 prev_do_int_overflow_checks := g.do_int_overflow_checks
1010 g.do_int_overflow_checks = g.pref.is_check_overflow && !g.is_builtin_overflow_mod
1011 && !node.is_ignore_overflow
1012 defer {
1013 g.do_int_overflow_checks = prev_do_int_overflow_checks
1014 }
1015
1016 // Emit extern prototypes for headerless `fn C.some_name() int`
1017 // declarations. Header-backed C declarations keep relying on the included
1018 // prototypes to avoid redeclaration conflicts.
1019 old_inside_c_extern := g.inside_c_extern
1020 defer {
1021 g.inside_c_extern = old_inside_c_extern
1022 }
1023 if node.is_c_extern || g.should_emit_c_fallback_decl(node) {
1024 g.inside_c_extern = true
1025 }
1026
1027 g.gen_attrs(node.attrs)
1028 mut skip := false
1029 pos := g.out.len
1030 defs_pos := g.definitions.len
1031 should_bundle_module := util.should_bundle_module(node.mod)
1032 if g.pref.build_mode == .build_module {
1033 // TODO: true for not just "builtin"
1034 // TODO: clean this up
1035 mod := if g.is_builtin_mod { 'builtin' } else { node.name.all_before_last('.') }
1036 module_built_short := g.module_built.all_after_last('/').all_after_last('.')
1037 // for now dont skip generic functions as they are being marked as static
1038 // when -usecache is enabled, until a better solution is implemented.
1039 if ((mod != g.module_built && node.mod != g.module_built && node.mod != module_built_short)
1040 || should_bundle_module) && node.generic_names.len == 0 {
1041 // Skip functions that don't have to be generated for this module.
1042 // println('skip bm ${node.name} mod=${node.mod} module_built=${g.module_built}')
1043 skip = true
1044 }
1045 if g.is_builtin_mod && g.module_built == 'builtin' && node.mod == 'builtin' {
1046 skip = false
1047 }
1048 if !skip && g.pref.is_verbose {
1049 println('build module `${g.module_built}` fn `${node.name}`')
1050 }
1051 }
1052 if g.pref.use_cache {
1053 // We are using prebuilt modules, we do not need to generate
1054 // their functions in main.c.
1055 if node.mod != 'main' && node.mod != 'help' && !should_bundle_module && !g.pref.is_test
1056 && node.generic_names.len == 0 {
1057 skip = true
1058 }
1059 }
1060 keep_fn_decl := g.fn_decl
1061 unsafe {
1062 g.fn_decl = &node
1063 }
1064 if node.is_main {
1065 g.has_main = true
1066 }
1067 // TODO: PERF remove this from here
1068 is_backtrace := node.name.starts_with('backtrace')
1069 && node.name in ['backtrace_symbols', 'backtrace', 'backtrace_symbols_fd']
1070 if is_backtrace {
1071 g.write('\n#ifndef __cplusplus\n')
1072 }
1073 g.gen_fn_decl(node, skip)
1074 if is_backtrace {
1075 g.write('\n#endif\n')
1076 }
1077 g.fn_decl = keep_fn_decl
1078 if skip {
1079 g.go_back_to(pos)
1080 if g.pref.build_mode != .build_module && !g.pref.use_cache {
1081 g.definitions.go_back_to(defs_pos)
1082 }
1083 }
1084 if !g.pref.skip_unused {
1085 if node.language != .c {
1086 g.writeln('')
1087 }
1088 }
1089 // Write the next function into another parallel C file
1090 // g.out_idx++
1091 // if g.out_idx >= g.out_parallel.len {
1092 // g.out_idx = 0
1093 //}
1094}
1095
1096fn (mut g Gen) post_process_generic_fns_for_files(files []&ast.File) {
1097 old_file := g.file
1098 old_fid := g.fid
1099 old_cur_concrete_types := g.cur_concrete_types.clone()
1100 mut emitted_generic_specializations := map[string]bool{}
1101 for {
1102 mut emitted_this_round := false
1103 for fid, file in files {
1104 g.fid = fid
1105 g.file = file
1106 for generic_fn in file.generic_fns {
1107 if generic_fn.is_anon {
1108 continue
1109 }
1110 effective_generic_names := g.effective_fn_generic_names(*generic_fn)
1111 if effective_generic_names.len == 0 {
1112 continue
1113 }
1114 fkey := g.node_decl_fkey(*generic_fn)
1115 generic_types_by_fn := g.table.fn_generic_types[fkey].clone()
1116 if generic_types_by_fn.len == 0 {
1117 continue
1118 }
1119 mut receiver_generic_names := []string{}
1120 mut all_receiver_cts := [][]ast.Type{}
1121 if generic_fn.is_method {
1122 receiver_generic_names = g.table.generic_type_names(generic_fn.receiver.typ)
1123 if receiver_generic_names.len > 0
1124 && receiver_generic_names.len < effective_generic_names.len {
1125 all_receiver_cts = g.find_all_receiver_concrete_types(*generic_fn,
1126 receiver_generic_names.len)
1127 }
1128 }
1129 for concrete_types in generic_types_by_fn {
1130 if concrete_types.any(it.has_flag(.generic)
1131 || g.type_has_unresolved_generic_parts(it))
1132 {
1133 continue
1134 }
1135 mut pending_specializations := [][]ast.Type{}
1136 if concrete_types.len == effective_generic_names.len {
1137 pending_specializations << concrete_types.clone()
1138 } else if concrete_types.len < effective_generic_names.len
1139 && all_receiver_cts.len > 0
1140 && concrete_types.len + receiver_generic_names.len == effective_generic_names.len {
1141 for receiver_cts in all_receiver_cts {
1142 mut merged := receiver_cts.clone()
1143 merged << concrete_types
1144 pending_specializations << merged
1145 }
1146 }
1147 for concrete_specialization in pending_specializations {
1148 specialization_key := g.generic_fn_name(concrete_specialization, fkey)
1149 if specialization_key in emitted_generic_specializations {
1150 continue
1151 }
1152 emitted_generic_specializations[specialization_key] = true
1153 g.cur_concrete_types = concrete_specialization.clone()
1154 g.fn_decl(*generic_fn)
1155 emitted_this_round = true
1156 }
1157 }
1158 }
1159 }
1160 if !emitted_this_round {
1161 break
1162 }
1163 g.cur_concrete_types = []
1164 }
1165 g.cur_concrete_types = old_cur_concrete_types
1166 g.file = old_file
1167 g.fid = old_fid
1168}
1169
1170fn (mut g Gen) gen_fn_decl(node &ast.FnDecl, skip bool) {
1171 $if trace_cgen_gen_fn_decl ? {
1172 eprintln('> g.tid: ${g.tid} | g.fid: ${g.fid:3} | g.file.path: ${g.file.path} | gen_fn_decl: ${node.name} | skip: ${skip}')
1173 }
1174 // TODO: For some reason, build fails with autofree with this line
1175 // as it's only informative, comment it for now
1176 // g.gen_attrs(it.attrs)
1177 if node.language == .c && !g.inside_c_extern {
1178 return
1179 }
1180 c_sym_name := node.name.all_after_first('C__').all_after_first('C.')
1181 if node.language == .c && c_sym_name in ['va_start', 'va_arg', 'va_end', 'va_copy'] {
1182 return
1183 }
1184 old_is_vlines_enabled := g.is_vlines_enabled
1185 g.is_vlines_enabled = true
1186 defer {
1187 g.is_vlines_enabled = old_is_vlines_enabled
1188 }
1189 function_defer_stmts := collect_function_defer_stmts(node)
1190
1191 tmp_defer_vars := g.defer_vars // must be here because of workflow
1192 if g.anon_fn == unsafe { nil } {
1193 g.defer_vars = []string{}
1194 } else {
1195 if function_defer_stmts.len > 0 {
1196 g.defer_vars = []string{}
1197 defer(fn) {
1198 g.defer_vars = tmp_defer_vars
1199 }
1200 }
1201 }
1202 // Skip [if xxx] if xxx is not defined
1203 /*
1204 for attr in node.attrs {
1205 if !attr.is_comptime_define {
1206 continue
1207 }
1208 if attr.name !in g.pref.compile_defines_all {
1209 // println('skipping [if]')
1210 return
1211 }
1212 }
1213 */
1214
1215 g.returned_var_names.clear()
1216 old_g_autofree := g.is_autofree
1217 if node.is_manualfree {
1218 g.is_autofree = false
1219 }
1220 defer {
1221 g.is_autofree = old_g_autofree
1222 }
1223 effective_generic_names := g.effective_fn_generic_names(*node)
1224 if effective_generic_names.len > 0 && g.cur_concrete_types.len == 0 {
1225 return
1226 }
1227 // For methods with their own generics (e.g. fn (c Calc[S]) next[T](input T))
1228 // where cur_concrete_types only contains receiver generics (S=TypeA),
1229 // skip if cur_concrete_types doesn't match the expected number of generic names.
1230 if effective_generic_names.len > 0 && g.cur_concrete_types.len > 0
1231 && g.cur_concrete_types.len != effective_generic_names.len {
1232 return
1233 }
1234 cur_fn_save := g.cur_fn
1235 cur_concrete_types_save := g.cur_concrete_types.clone()
1236 defer {
1237 g.cur_fn = cur_fn_save
1238 g.cur_concrete_types = cur_concrete_types_save
1239 g.clear_type_resolution_caches()
1240 }
1241 mut effective_cur_fn := *node
1242 if g.cur_concrete_types.len > 0 && effective_generic_names.len == g.cur_concrete_types.len
1243 && effective_cur_fn.generic_names != effective_generic_names {
1244 effective_cur_fn = ast.FnDecl{
1245 ...effective_cur_fn
1246 generic_names: effective_generic_names.clone()
1247 }
1248 }
1249 if node.generic_names.len == 0 && g.cur_concrete_types.len == 0
1250 && (!node.is_method || node.receiver.typ.has_flag(.generic)
1251 || node.name.contains('_T_')) {
1252 recovered_generic_names, recovered_concrete_types :=
1253 g.recover_specialized_generic_context_for(node.name)
1254 if recovered_generic_names.len > 0
1255 && recovered_generic_names.len == recovered_concrete_types.len {
1256 effective_cur_fn = ast.FnDecl{
1257 ...*node
1258 generic_names: recovered_generic_names.clone()
1259 }
1260 g.cur_concrete_types = recovered_concrete_types.clone()
1261 }
1262 }
1263 unsafe {
1264 // TODO: remove unsafe
1265 g.cur_fn = &effective_cur_fn
1266 }
1267 g.clear_type_resolution_caches()
1268 g.refresh_current_generic_fn_scope_vars(g.cur_fn)
1269 fn_start_pos := g.out.len
1270 is_closure := node.scope.has_inherited_vars()
1271 mut cur_closure_ctx := ''
1272 if is_closure {
1273 cur_closure_ctx = g.closure_ctx(node)
1274 // declare the struct before its implementation
1275 g.definitions.write_string(cur_closure_ctx)
1276 g.definitions.writeln(';')
1277 }
1278
1279 g.write_v_source_line_info_stmt(node)
1280 fn_attrs := g.write_fn_attrs(node.attrs)
1281 // Live
1282 is_livefn := node.attrs.contains('live')
1283 is_livemain := g.pref.is_livemain && is_livefn
1284 is_liveshared := g.pref.is_liveshared && is_livefn
1285 is_livemode := g.pref.is_livemain || g.pref.is_liveshared
1286 is_live_wrap := is_livefn && is_livemode
1287 if is_livefn && !is_livemode {
1288 eprintln('INFO: compile with `v -live ${g.pref.path} `, if you want to use the @[live] function ${node.name} .')
1289 }
1290
1291 mut name := g.c_fn_name(node)
1292 type_name := g.ret_styp(g.unwrap_generic(node.return_type))
1293 // Live functions are protected by a mutex, because otherwise they
1294 // can be changed by the live reload thread, *while* they are
1295 // running, with unpredictable results (usually just crashing).
1296 // For this purpose, the actual body of the live function,
1297 // is put under a non publicly accessible function, that is prefixed
1298 // with 'impl_live_' .
1299 if is_livemode {
1300 if is_livefn {
1301 g.hotcode_fn_names << name
1302 }
1303 g.hotcode_fpaths << g.file.path
1304 }
1305 mut impl_fn_name := name
1306 if is_live_wrap {
1307 impl_fn_name = 'impl_live_${name}'
1308 }
1309 last_fn_c_name_save := g.last_fn_c_name
1310 defer {
1311 g.last_fn_c_name = last_fn_c_name_save
1312 }
1313 g.last_fn_c_name = impl_fn_name
1314
1315 if !g.inside_c_extern && node.trace_fns.len > 0 {
1316 for trace_fn, call_fn in node.trace_fns {
1317 if trace_fn in g.trace_fn_definitions {
1318 continue
1319 }
1320 trace_fn_ret_type := g.styp(call_fn.return_type)
1321
1322 g.write('VV_LOC ${trace_fn_ret_type} ${c_name(trace_fn)}(')
1323 g.definitions.write_string('VV_LOC ${trace_fn_ret_type} ${c_name(trace_fn)}(')
1324
1325 mut trace_call_args := []string{}
1326 if call_fn.is_fn_var {
1327 sig := g.fn_var_signature(ast.void_type, call_fn.func.return_type,
1328 call_fn.func.params.map(it.typ), call_fn.name)
1329 g.write(sig)
1330 g.definitions.write_string(sig)
1331 if call_fn.func.params.len > 0 {
1332 g.write(', ')
1333 g.definitions.write_string(', ')
1334 trace_call_args, _, _ = g.fn_decl_params(call_fn.func.params, unsafe { nil },
1335 call_fn.func.is_variadic, call_fn.func.is_c_variadic)
1336 }
1337 } else {
1338 trace_call_args, _, _ = g.fn_decl_params(call_fn.func.params, unsafe { nil },
1339 call_fn.func.is_variadic, call_fn.func.is_c_variadic)
1340 }
1341
1342 g.writeln(') {')
1343 g.definitions.write_string(');\n')
1344
1345 orig_fn_args := trace_call_args.join(', ')
1346 add_trace_hook := g.pref.is_trace
1347 && call_fn.name !in ['v.debug.add_after_call', 'v.debug.add_before_call', 'v.debug.remove_after_call', 'v.debug.remove_before_call']
1348 if g.pref.is_callstack {
1349 if g.cur_fn.is_method || g.cur_fn.is_static_type_method {
1350 g.writeln('\tbuiltin__array_push((array*)&g_callstack, _MOV((v__debug__FnTrace[]){ ((v__debug__FnTrace){.name = _S("${g.table.type_to_str(g.cur_fn.receiver.typ)}.${g.cur_fn.name.all_after_last('__static__')}"),.file = _S("${call_fn.file}"),.line = ${call_fn.line},}) }));')
1351 } else {
1352 g.writeln('\tbuiltin__array_push((array*)&g_callstack, _MOV((v__debug__FnTrace[]){ ((v__debug__FnTrace){.name = _S("${g.cur_fn.name}"),.file = _S("${call_fn.file}"),.line = ${call_fn.line},}) }));')
1353 }
1354 }
1355 mut method_name := c_name(call_fn.name)
1356 if call_fn.name.contains('_') {
1357 parts := call_fn.name.split('_')
1358 if parts.len >= 2 {
1359 receiver_type_name := parts[0]
1360 if resolved_sym := g.table.find_sym(receiver_type_name) {
1361 if resolved_sym.is_builtin() {
1362 method_name = 'builtin__${method_name}'
1363 }
1364 }
1365 }
1366 }
1367 if call_fn.return_type == 0 || call_fn.return_type == ast.void_type {
1368 if add_trace_hook {
1369 g.writeln('\tif (!g_trace.in_hook) {')
1370 g.writeln('\t\tv__debug__before_call_hook(_S("${call_fn.name}"));')
1371 g.writeln('\t}')
1372 }
1373 g.writeln('\t${method_name}(${orig_fn_args});')
1374 if add_trace_hook {
1375 g.writeln('\tif (!g_trace.in_hook) {')
1376 g.writeln('\t\tv__debug__after_call_hook(_S("${call_fn.name}"));')
1377 g.writeln('\t}')
1378 }
1379 if g.pref.is_callstack {
1380 g.writeln('\tbuiltin__array_pop((array*)&g_callstack);')
1381 }
1382 } else {
1383 if add_trace_hook {
1384 g.writeln('\tif (!g_trace.in_hook) {')
1385 g.writeln('\t\tv__debug__before_call_hook(_S("${call_fn.name}"));')
1386 g.writeln('\t}')
1387 }
1388 g.writeln('\t${g.styp(call_fn.return_type)} ret = ${method_name}(${orig_fn_args});')
1389 if g.pref.is_callstack {
1390 g.writeln('\tbuiltin__array_pop((array*)&g_callstack);')
1391 }
1392 if add_trace_hook {
1393 g.writeln('\tif (!g_trace.in_hook) {')
1394 g.writeln('\t\tv__debug__after_call_hook(_S("${call_fn.name}"));')
1395 g.writeln('\t}')
1396 }
1397 g.writeln('\treturn ret;')
1398 }
1399 g.writeln2('}', '')
1400 g.trace_fn_definitions << trace_fn
1401 }
1402 }
1403
1404 if is_live_wrap {
1405 if is_livemain {
1406 g.definitions.write_string('${type_name} (* ${impl_fn_name})(')
1407 g.write('${type_name} no_impl_${name}(')
1408 }
1409 if is_liveshared {
1410 if g.pref.os == .windows {
1411 g.export_funcs << impl_fn_name
1412 g.definitions.write_string('VV_EXP ${type_name} ${impl_fn_name}(')
1413 g.write('VV_EXP ${type_name} ${impl_fn_name}(')
1414 } else {
1415 g.definitions.write_string('${type_name} ${impl_fn_name}(')
1416 g.write('${type_name} ${impl_fn_name}(')
1417 }
1418 }
1419 } else if g.inside_c_extern {
1420 c_extern_fn_header := 'extern ${type_name} ${fn_attrs}${name.all_after_first('C__')}('
1421 g.definitions.write_string(c_extern_fn_header)
1422 } else {
1423 if !(node.is_pub || g.pref.is_debug) {
1424 // Private functions need to marked as static so that they are not exportable in the
1425 // binaries
1426 if g.pref.build_mode != .build_module && !g.pref.use_cache {
1427 // If we are building vlib/builtin, we need all private functions like array_get
1428 // to be public, so that all V programs can access them.
1429 if !(node.is_anon && g.pref.parallel_cc) {
1430 g.write('VV_LOC ')
1431 // g.definitions.write_string('${g.static_modifier} VV_LOC ')
1432 g.definitions.write_string('VV_LOC ')
1433 }
1434 }
1435 }
1436 // as a temp solution generic functions are marked static
1437 // when -usecache is enabled to fix duplicate symbols with clang
1438 // TODO: implement a better sulution
1439 needs_object_local_linkage := g.should_use_object_local_linkage(node.mod)
1440 && (node.is_pub || g.pref.is_debug)
1441 visibility_kw := if needs_object_local_linkage {
1442 'static '
1443 } else if g.cur_concrete_types.len > 0
1444 && (g.pref.build_mode == .build_module || g.pref.use_cache) {
1445 'static '
1446 } else {
1447 ''
1448 }
1449 fn_header := '${visibility_kw}${type_name} ${fn_attrs}${name}('
1450 g.definitions.write_string(fn_header)
1451 g.write(fn_header)
1452 }
1453 arg_start_pos := g.out.len
1454 is_c_variadic := node.is_c_variadic || (node.language == .c && node.is_variadic)
1455 fargs, fargtypes, heap_promoted := g.fn_decl_params(node.params, node.scope, node.is_variadic,
1456 is_c_variadic)
1457 if is_closure {
1458 g.nr_closures++
1459 if g.pref.no_closures {
1460 g.error('a closure was generated for function', node.pos)
1461 }
1462 }
1463 arg_str := g.out.after(arg_start_pos)
1464 if node.no_body || ((g.pref.use_cache && g.pref.build_mode != .build_module) && node.is_builtin
1465 && !g.pref.is_test) || skip {
1466 // Just a function header. Builtin function bodies are defined in builtin.o
1467 g.definitions.writeln(');') // NO BODY')
1468 if !g.inside_c_extern {
1469 g.writeln(');')
1470 }
1471 return
1472 }
1473 if node.params.len == 0 {
1474 g.definitions.write_string('void')
1475 }
1476 if attr := node.attrs.find_first('_linker_section') {
1477 g.definitions.writeln(') __attribute__ ((section ("${attr.arg}")));')
1478 } else {
1479 g.definitions.writeln(');')
1480 }
1481 g.writeln(') {')
1482 if is_closure {
1483 g.writeln('${cur_closure_ctx}* ${closure_ctx} = g_closure.closure_get_data();')
1484 }
1485 for i, is_promoted in heap_promoted {
1486 if is_promoted {
1487 g.writeln('${fargtypes[i]}* ${fargs[i]} = HEAP(${fargtypes[i]}, _v_toheap_${fargs[i]});')
1488 }
1489 }
1490 g.indent++
1491 for defer_stmt in function_defer_stmts {
1492 if defer_stmt.mode != .function {
1493 continue
1494 }
1495 g.writeln('bool ${g.defer_flag_var(defer_stmt)} = false;')
1496 for var in defer_stmt.defer_vars {
1497 if var.name in fargs || var.kind == .constant {
1498 continue
1499 }
1500 if var.kind == .variable {
1501 if var.name !in g.defer_vars {
1502 g.defer_vars << var.name
1503 mut deref := ''
1504 if v := var.scope.find_var(var.name) {
1505 if v.is_auto_heap {
1506 deref = '*'
1507 }
1508 }
1509 info := var.obj as ast.Var
1510 if g.table.sym(info.typ).kind != .function {
1511 if info.is_static {
1512 g.write('static ')
1513 }
1514 if info.is_volatile {
1515 g.write('volatile ')
1516 }
1517 decl_typ := if deref == '*' {
1518 info.typ.ref()
1519 } else {
1520 info.typ
1521 }
1522 default_expr := g.type_default(decl_typ)
1523 if g.type_default_vars.len > 0 {
1524 for decl in g.type_default_vars.str().trim_right('\n').split_into_lines() {
1525 g.writeln(decl)
1526 }
1527 g.type_default_vars.clear()
1528 }
1529 g.writeln('${g.styp(info.typ)}${deref} ${c_name(var.name)} = ${default_expr};')
1530 }
1531 }
1532 }
1533 }
1534 }
1535 g.indent--
1536 if is_live_wrap {
1537 // The live function just calls its implementation dual, while ensuring
1538 // that the call is wrapped by the mutex lock & unlock calls.
1539 // Adding the mutex lock/unlock inside the body of the implementation
1540 // function is not reliable, because the implementation function can do
1541 // an early exit, which will leave the mutex locked.
1542 live_mutex_ptr_type := if g.pref.os == .windows {
1543 'HANDLE*'
1544 } else {
1545 'pthread_mutex_t*'
1546 }
1547 mut fn_args_list := []string{}
1548 for ia, fa in fargs {
1549 fn_args_list << '${fargtypes[ia]} ${fa}'
1550 }
1551 mut live_fncall := '${impl_fn_name}(' + fargs.join(', ') + ');'
1552 mut live_fnreturn := ''
1553 if type_name != 'void' {
1554 live_fncall = '${type_name} res = ${live_fncall}'
1555 live_fnreturn = 'return res;'
1556 }
1557 if is_livemain {
1558 g.definitions.writeln('${type_name} no_impl_${name}(' + fn_args_list.join(', ') + ');')
1559 }
1560 g.definitions.writeln('${type_name} ${name}(' + fn_args_list.join(', ') + ');')
1561 g.hotcode_definitions.writeln('${type_name} ${name}(' + fn_args_list.join(', ') + '){')
1562 g.hotcode_definitions.writeln(' ${live_mutex_ptr_type} live_fn_mutex_ptr = v_live_fn_mutex_ptr();')
1563 g.hotcode_definitions.writeln(' pthread_mutex_lock(live_fn_mutex_ptr);')
1564 g.hotcode_definitions.writeln(' ${live_fncall}')
1565 g.hotcode_definitions.writeln(' pthread_mutex_unlock(live_fn_mutex_ptr);')
1566 g.hotcode_definitions.writeln(' ${live_fnreturn}')
1567 g.hotcode_definitions.writeln('}')
1568 }
1569 // Profiling mode? Start counting at the beginning of the function (save current time).
1570 if g.pref.is_prof && g.pref.build_mode != .build_module {
1571 g.profile_fn(node)
1572 }
1573 // we could be in an anon fn so save outer fn defer stmts
1574 prev_defer_stmts := g.defer_stmts
1575 g.defer_stmts = []
1576 ctmp := g.tmp_count
1577 g.tmp_count = 0
1578 defer {
1579 g.tmp_count = ctmp
1580 }
1581 prev_inside_ternary := g.inside_ternary
1582 g.inside_ternary = 0
1583 prev_indent := g.indent
1584 g.indent = 0
1585 defer {
1586 g.indent = prev_indent
1587 }
1588 g.stmts(node.stmts)
1589 g.inside_ternary = prev_inside_ternary
1590 if node.is_noreturn {
1591 g.writeln('\twhile(1);')
1592 }
1593 // clear g.fn_mut_arg_names
1594
1595 if !node.has_return {
1596 g.write_defer_stmts_when_needed(node.scope, false, node.name_pos)
1597 }
1598 if node.is_anon {
1599 g.defer_stmts = prev_defer_stmts
1600 } else {
1601 g.defer_stmts = []
1602 }
1603 if node.return_type != ast.void_type && node.stmts.len > 0 && node.stmts.last() !is ast.Return
1604 && !node.attrs.contains('_naked') {
1605 default_expr := g.type_default(node.return_type)
1606 // TODO: perf?
1607 if default_expr == '{0}' {
1608 g.writeln('\treturn (${type_name})${default_expr};')
1609 } else {
1610 g.writeln('\treturn ${default_expr};')
1611 }
1612 }
1613 g.writeln('}')
1614 if g.pref.printfn_list.len > 0 && g.last_fn_c_name in g.pref.printfn_list {
1615 println(g.out.after(fn_start_pos))
1616 }
1617 weak := if node.is_weak { 'VWEAK ' } else { '' }
1618 for attr in node.attrs {
1619 if attr.name == 'export' {
1620 g.writeln('// export alias: ${attr.arg} -> ${name}')
1621 g.export_funcs << attr.arg
1622 export_alias := '${weak}${type_name} ${fn_attrs}${attr.arg}(${arg_str})'
1623 g.definitions.writeln('VV_EXP ${export_alias}; // exported fn ${node.name}')
1624 g.writeln('${export_alias} {')
1625 if !g.pref.is_shared && 'no_main' in g.table.modules {
1626 g.writeln('\t_vno_main_init_caller();')
1627 }
1628 g.write2('\treturn ${name}(', fargs.join(', '))
1629 g.writeln2(');', '}')
1630 }
1631 }
1632}
1633
1634fn (mut g Gen) c_fn_name(node &ast.FnDecl) string {
1635 mut name := node.name
1636 if name in ['+', '-', '*', '**', '/', '%', '<', '==', '[]', '[]='] {
1637 name = util.replace_op(name)
1638 }
1639 if node.is_method {
1640 unwrapped_rec_typ := g.unwrap_generic(node.receiver.typ)
1641 name = g.cc_type(unwrapped_rec_typ, false) + '_' + name
1642 receiver_sym := g.table.sym(unwrapped_rec_typ)
1643 if receiver_sym.is_builtin() {
1644 name = 'builtin__${name}'
1645 }
1646 if receiver_sym.kind == .placeholder {
1647 name = name.replace_each(c_fn_name_escape_seq)
1648 }
1649 }
1650 if node.is_anon && g.anon_fn != unsafe { nil } && g.anon_fn.has_ct_var {
1651 name = '${name}_${g.comptime.comptime_loop_id}'
1652 }
1653 if node.language == .c {
1654 name = util.no_dots(name)
1655 } else {
1656 name = c_fn_name(name)
1657 }
1658 if !node.is_method && node.mod == 'builtin' && !name.starts_with('builtin__') {
1659 name = 'builtin__${name}'
1660 }
1661
1662 if node.generic_names.len > 0 {
1663 name = g.generic_fn_name(g.method_concrete_types_for_name(node), name)
1664 name = name.replace_each(c_fn_name_escape_seq)
1665 }
1666
1667 if g.pref.translated || g.file.is_translated || node.is_file_translated {
1668 if cattr := node.attrs.find_first('c') {
1669 // This fixes unknown symbols errors when building separate .c => .v files into .o files
1670 // example:
1671 // @[c: 'P_TryMove'] fn p_trymove(thing &Mobj_t, x int, y int) bool
1672 // translates to:
1673 // bool P_TryMove(main__Mobj_t* thing, int x, int y);
1674 // In fn_call every time `p_trymove` is called, `P_TryMove` will be generated instead.
1675 name = cattr.arg
1676 }
1677 }
1678 return name
1679}
1680
1681const closure_ctx = '_V_closure_ctx'
1682
1683fn (g &Gen) anon_fn_generic_names(generic_names []string) []string {
1684 if g.cur_fn == unsafe { nil } || g.cur_fn.generic_names.len == 0
1685 || g.cur_concrete_types.len == 0 {
1686 return generic_names.clone()
1687 }
1688 mut names := g.cur_fn.generic_names.clone()
1689 for generic_name in generic_names {
1690 if generic_name !in names {
1691 names << generic_name
1692 }
1693 }
1694 return names
1695}
1696
1697fn (mut g Gen) gen_closure_fn_name(node ast.AnonFn) string {
1698 mut fn_name := node.decl.name
1699 if g.anon_fn_generic_names(node.decl.generic_names).len > 0 {
1700 fn_name = g.generic_fn_name(g.cur_concrete_types, fn_name)
1701 }
1702 if node.has_ct_var {
1703 fn_name += '_${g.comptime.comptime_loop_id}'
1704 }
1705 return fn_name
1706}
1707
1708fn (mut g Gen) c_call_alias_signature(node ast.CallExpr, name string) string {
1709 ret_styp := g.styp(node.return_type)
1710 mut sig := '${ret_styp} (*${name})('
1711 if node.args.len == 0 {
1712 if !node.is_c_variadic {
1713 sig += 'void'
1714 }
1715 } else {
1716 for i, arg in node.args {
1717 arg_typ := if arg.typ != 0 {
1718 arg.typ
1719 } else if i < node.expected_arg_types.len {
1720 node.expected_arg_types[i]
1721 } else {
1722 ast.voidptr_type
1723 }
1724 sig += g.styp(arg_typ)
1725 if i < node.args.len - 1 || node.is_c_variadic {
1726 sig += ', '
1727 }
1728 }
1729 if node.is_c_variadic {
1730 sig += '...'
1731 }
1732 }
1733 sig += ')'
1734 return sig
1735}
1736
1737fn (mut g Gen) c_call_name(node ast.CallExpr, cname string) string {
1738 if node.scope == unsafe { nil } {
1739 return cname
1740 }
1741 if node.scope.find_var(cname) == none && node.scope.find_global(cname) == none {
1742 return cname
1743 }
1744 g.global_tmp_count++
1745 alias_name := '__v_c_fn_${g.global_tmp_count}_${cname}'
1746 alias_sig := g.c_call_alias_signature(node, alias_name)
1747 cast_sig := g.c_call_alias_signature(node, '')
1748 g.definitions.writeln('${g.static_non_parallel}${alias_sig} = (${cast_sig})${cname};')
1749 if g.pref.parallel_cc {
1750 g.extern_out.writeln('extern ${alias_sig};')
1751 }
1752 return alias_name
1753}
1754
1755fn (mut g Gen) closure_ctx(node ast.FnDecl) string {
1756 mut fn_name := node.name
1757 generic_names := if node.is_anon {
1758 g.anon_fn_generic_names(node.generic_names)
1759 } else {
1760 node.generic_names
1761 }
1762 if generic_names.len > 0 {
1763 fn_name = g.generic_fn_name(g.cur_concrete_types, fn_name)
1764 }
1765 return 'struct _V_${fn_name}_Ctx'
1766}
1767
1768fn (mut g Gen) is_mut_closure_fixed_array(var ast.Param) bool {
1769 resolved_typ := g.recheck_concrete_type(var.typ)
1770 return var.is_mut && g.table.final_sym(resolved_typ).kind == .array_fixed
1771}
1772
1773fn (mut g Gen) mut_closure_fixed_array_field_styp(var ast.Param) string {
1774 resolved_typ := g.recheck_concrete_type(var.typ)
1775 info := g.table.final_sym(resolved_typ).info as ast.ArrayFixed
1776 resolved_elem_type := g.recheck_concrete_type(info.elem_type)
1777 mut elem_styp := g.styp(resolved_elem_type.set_nr_muls(0))
1778 if resolved_elem_type.is_ptr() {
1779 elem_styp += '*'.repeat(resolved_elem_type.nr_muls())
1780 }
1781 return '${elem_styp}*'
1782}
1783
1784fn (mut g Gen) closure_inherited_var_type(node ast.AnonFn, var ast.Param) ast.Type {
1785 resolved := g.resolve_current_fn_generic_param_type(var.name)
1786 if resolved != 0 {
1787 return g.unwrap_generic(g.recheck_concrete_type(resolved))
1788 }
1789 if node.decl.scope != unsafe { nil } && node.decl.scope.parent != unsafe { nil } {
1790 if scope_var := node.decl.scope.parent.find_var(var.name) {
1791 // If the scope variable has smartcasts and is a sumtype, use the
1792 // smartcast variant type instead of the original sumtype.
1793 if scope_var.smartcasts.len > 0 && g.table.type_kind(scope_var.typ) == .sum_type {
1794 return g.unwrap_generic(g.recheck_concrete_type(scope_var.smartcasts.last()))
1795 }
1796 // Only use resolved_expr_type for generic type resolution.
1797 // For non-generic types, scope_var.typ is already correct and
1798 // resolved_expr_type can produce wrong pointer levels (e.g. adding
1799 // an extra ref() for &receiver expressions).
1800 if scope_var.typ.has_flag(.generic)
1801 || g.type_has_unresolved_generic_parts(scope_var.typ) {
1802 if scope_var.expr !is ast.EmptyExpr {
1803 resolved_expr_typ := g.resolved_expr_type(scope_var.expr, scope_var.typ)
1804 if resolved_expr_typ != 0 {
1805 return g.unwrap_generic(g.recheck_concrete_type(resolved_expr_typ))
1806 }
1807 }
1808 }
1809 if scope_var.typ != 0 {
1810 return g.unwrap_generic(g.recheck_concrete_type(scope_var.typ))
1811 }
1812 }
1813 }
1814 return g.unwrap_generic(g.recheck_concrete_type(var.typ))
1815}
1816
1817fn (g &Gen) variadic_voidptr_promoted_type(typ ast.Type) ast.Type {
1818 base_typ := g.table.unaliased_type(typ).clear_flags()
1819 if base_typ in ast.int_promoted_type_idxs || base_typ == ast.bool_type {
1820 return ast.int_type
1821 }
1822 if base_typ == ast.f32_type {
1823 return ast.f64_type
1824 }
1825 return ast.no_type
1826}
1827
1828fn (mut g Gen) gen_anon_fn(mut node ast.AnonFn) {
1829 is_amp := g.is_amp
1830 g.is_amp = false
1831 defer {
1832 g.is_amp = is_amp
1833 }
1834 g.gen_anon_fn_decl(mut node)
1835 fn_name := g.gen_closure_fn_name(node)
1836 if !node.decl.scope.has_inherited_vars() {
1837 g.write(fn_name)
1838 return
1839 }
1840 ctx_struct := g.closure_ctx(node.decl)
1841 // it may be possible to optimize `memdup` out if the closure never leaves current scope
1842 // TODO: in case of an assignment, this should only call "closure_set_data" and "closure_set_function" (and free the former data)
1843 g.write('builtin__closure__closure_create(${fn_name}, (${ctx_struct}*) builtin__memdup_uncollectable(&(${ctx_struct}){')
1844 g.indent++
1845 for var in node.inherited_vars {
1846 mut has_inherited := false
1847 mut is_ptr := false
1848 var_name := c_name(var.name)
1849 if g.is_mut_closure_fixed_array(var) {
1850 if obj := node.decl.scope.find_var(var.name) {
1851 if obj.has_inherited {
1852 has_inherited = true
1853 g.writeln('.${var_name} = ${closure_ctx}->${var_name},')
1854 }
1855 }
1856 if !has_inherited {
1857 g.writeln('.${var_name} = ${var_name},')
1858 }
1859 continue
1860 }
1861 if obj := node.decl.scope.find_var(var.name) {
1862 is_ptr = obj.typ.is_ptr()
1863 if obj.has_inherited {
1864 has_inherited = true
1865 resolved_var_typ := g.closure_inherited_var_type(node, var)
1866 var_sym := g.table.sym(resolved_var_typ)
1867 if var_sym.info is ast.ArrayFixed {
1868 g.write('.${var_name} = {')
1869 for i in 0 .. var_sym.info.size {
1870 g.write('${closure_ctx}->${var_name}[${i}],')
1871 }
1872 g.writeln('},')
1873 } else if g.resolved_ident_is_by_value_auto_deref_capture(ast.Ident{
1874 name: var.name
1875 scope: node.decl.scope
1876 })
1877 {
1878 g.writeln('.${var_name} = *${closure_ctx}->${var_name},')
1879 } else {
1880 g.writeln('.${var_name} = ${closure_ctx}->${var_name},')
1881 }
1882 }
1883 }
1884 if !has_inherited {
1885 resolved_var_typ := g.closure_inherited_var_type(node, var)
1886 var_sym := g.table.sym(resolved_var_typ)
1887 if var_sym.info is ast.ArrayFixed {
1888 g.write('.${var_name} = {')
1889 for i in 0 .. var_sym.info.size {
1890 g.write('${var_name}[${i}],')
1891 }
1892 g.writeln('},')
1893 } else if g.is_autofree && !var.is_mut && var_sym.info is ast.Array {
1894 g.writeln('.${var_name} = builtin__array_clone(&${var_name}),')
1895 } else if g.is_autofree && !var.is_mut && var_sym.kind == .string {
1896 g.writeln('.${var_name} = builtin__string_clone(${var_name}),')
1897 } else {
1898 mut is_auto_heap := false
1899 mut is_auto_deref_capture := false
1900 mut field_name := ''
1901 if obj := node.decl.scope.parent.find(var.name) {
1902 if obj is ast.Var {
1903 is_auto_heap = !obj.is_stack_obj && obj.is_auto_heap
1904 is_auto_deref_capture = obj.is_auto_deref && !var.is_mut
1905 && (is_ptr || obj.typ.is_ptr())
1906 if obj.smartcasts.len > 0 {
1907 if g.table.type_kind(obj.typ) == .sum_type {
1908 cast_sym := g.table.sym(obj.smartcasts.last())
1909 field_name += '._${cast_sym.cname}'
1910 }
1911 }
1912 }
1913 }
1914 if (is_auto_heap && !is_ptr) || is_auto_deref_capture || field_name != '' {
1915 g.writeln('.${var_name} = *${var_name}${field_name},')
1916 } else {
1917 g.writeln('.${var_name} = ${var_name},')
1918 }
1919 }
1920 }
1921 }
1922 g.indent--
1923 g.write('}, sizeof(${ctx_struct})))')
1924
1925 g.empty_line = false
1926}
1927
1928fn (mut g Gen) gen_anon_fn_decl(mut node ast.AnonFn) {
1929 mut fn_name := g.gen_closure_fn_name(node)
1930 if node.has_gen[fn_name] {
1931 return
1932 }
1933 mut builder := strings.new_builder(256)
1934 // Generate a closure struct
1935 if node.inherited_vars.len > 0 {
1936 ctx_struct := g.closure_ctx(node.decl)
1937 if ctx_struct !in g.closure_structs {
1938 g.closure_structs << ctx_struct
1939 g.definitions.writeln('${ctx_struct} {')
1940 for var in node.inherited_vars {
1941 mut resolved_var_typ := g.closure_inherited_var_type(node, var)
1942 // When the variable is auto-heap promoted, the closure struct
1943 // stores the dereferenced value (the init code does `*var`),
1944 // so strip one pointer level from the field type.
1945 // Similarly, when a `mut` parameter (is_auto_deref) is captured
1946 // without `mut`, the closure stores the dereferenced value.
1947 if node.decl.scope != unsafe { nil } && node.decl.scope.parent != unsafe { nil } {
1948 if scope_var := node.decl.scope.parent.find_var(var.name) {
1949 if scope_var.is_auto_heap && !scope_var.is_stack_obj
1950 && resolved_var_typ.is_ptr() {
1951 resolved_var_typ = resolved_var_typ.deref()
1952 } else if scope_var.is_auto_deref && !var.is_mut
1953 && resolved_var_typ.is_ptr() {
1954 resolved_var_typ = resolved_var_typ.deref()
1955 }
1956 }
1957 }
1958 var_sym := g.table.sym(resolved_var_typ)
1959 if g.is_mut_closure_fixed_array(var) {
1960 g.definitions.writeln('\t${g.mut_closure_fixed_array_field_styp(var)} ${c_name(var.name)};')
1961 } else if var_sym.info is ast.FnType {
1962 resolved_ret_type := g.recheck_concrete_type(var_sym.info.func.return_type)
1963 resolved_param_types :=
1964 var_sym.info.func.params.map(g.recheck_concrete_type(it.typ))
1965 mut sig := g.fn_var_signature(resolved_var_typ, resolved_ret_type,
1966 resolved_param_types, c_name(var.name))
1967 g.definitions.writeln('\t' + sig + ';')
1968 } else {
1969 styp := g.styp(resolved_var_typ)
1970 g.definitions.writeln('\t${styp} ${c_name(var.name)};')
1971 }
1972 }
1973 g.definitions.writeln('};\n')
1974 }
1975 }
1976 pos := g.out.len
1977 was_anon_fn := g.anon_fn
1978 prev_stmt_path_pos := g.stmt_path_pos.clone()
1979 prev_skip_stmt_pos := g.skip_stmt_pos
1980 decl := ast.FnDecl{
1981 ...node.decl
1982 generic_names: g.anon_fn_generic_names(node.decl.generic_names)
1983 }
1984 g.stmt_path_pos = []
1985 g.skip_stmt_pos = false
1986 g.anon_fn = node
1987 old_inside_return := g.inside_return
1988 old_inside_return_expr := g.inside_return_expr
1989 g.inside_return = false
1990 g.inside_return_expr = false
1991 g.fn_decl(decl)
1992 g.inside_return_expr = old_inside_return_expr
1993 g.inside_return = old_inside_return
1994 g.anon_fn = was_anon_fn
1995 g.skip_stmt_pos = prev_skip_stmt_pos
1996 g.stmt_path_pos = prev_stmt_path_pos
1997 builder.write_string(g.out.cut_to(pos))
1998 out := builder.str()
1999 if out.len == 0 {
2000 return
2001 }
2002 node.has_gen[fn_name] = true
2003 g.anon_fn_definitions << out
2004 if g.pref.parallel_cc {
2005 g.extern_out.writeln('extern ${out.all_before(' {')};')
2006 }
2007}
2008
2009fn (mut g Gen) fn_decl_params(params []ast.Param, scope &ast.Scope, is_variadic bool, is_c_variadic bool) ([]string, []string, []bool) {
2010 mut fparams := []string{}
2011 mut fparamtypes := []string{}
2012 mut heap_promoted := []bool{}
2013 param_count := if is_c_variadic && is_variadic && params.len > 0
2014 && params.last().typ.has_flag(.variadic) {
2015 params.len - 1
2016 } else {
2017 params.len
2018 }
2019 if param_count == 0 {
2020 // in C, `()` is untyped, unlike `(void)`
2021 if !g.inside_c_extern && !is_c_variadic {
2022 g.write('void')
2023 }
2024 }
2025 for i, param in params {
2026 if i >= param_count {
2027 break
2028 }
2029 mut typ := g.unwrap_generic(param.typ)
2030 if g.pref.translated && g.file.is_translated && param.typ.has_flag(.variadic) {
2031 typ = g.table.sym(typ).array_info().elem_type.set_flag(.variadic)
2032 }
2033 if param.is_mut && param.orig_typ != 0 && param.orig_typ.has_flag(.generic)
2034 && param.typ.has_flag(.generic) {
2035 mut surface_typ := g.unwrap_generic(param.orig_typ)
2036 // Only use ref() when the pointer comes from the generic type argument
2037 // (T=&int), not from the param signature (&T / ?&T).
2038 orig_was_ptr := param.orig_typ.nr_muls() > 0
2039 typ = if surface_typ.is_ptr() && !orig_was_ptr {
2040 surface_typ.ref()
2041 } else {
2042 surface_typ.set_nr_muls(1)
2043 }
2044 if typ.has_flag(.option) {
2045 typ = typ.set_flag(.option_mut_param_t)
2046 }
2047 }
2048 if param.is_mut && param.typ.has_flag(.generic) && typ.has_flag(.option) {
2049 typ = typ.set_flag(.option_mut_param_t).set_nr_muls(param.typ.nr_muls() - 1)
2050 }
2051 if param.is_mut && param.orig_typ != 0 && param.orig_typ.has_flag(.option)
2052 && typ.has_flag(.option_mut_param_t) && typ.nr_muls() == 1
2053 && !g.mut_option_param_assigned_directly(param.name) {
2054 typ = typ.ref()
2055 }
2056 param_type_sym := g.table.sym(typ)
2057 mut caname := if param.name in ['', '_'] {
2058 '_d${i + 1}'
2059 } else if param_type_sym.kind == .function && !typ.has_flag(.option) {
2060 c_fn_name(param.name)
2061 } else {
2062 c_name(param.name)
2063 }
2064 mut param_type_name := g.styp(typ)
2065 if param.typ.has_flag(.generic) {
2066 param_type_name = param_type_name.replace_each(c_fn_name_escape_seq)
2067 }
2068 if param_type_sym.kind == .function && !typ.has_flag(.option) {
2069 info := param_type_sym.info as ast.FnType
2070 func := info.func
2071 if !g.inside_c_extern {
2072 g.write('${g.ret_styp(func.return_type)} (*${caname})(')
2073 }
2074 g.definitions.write_string('${g.ret_styp(func.return_type)} (*${caname})(')
2075 g.fn_decl_params(func.params, unsafe { nil }, func.is_variadic, func.is_c_variadic)
2076 if !g.inside_c_extern {
2077 g.write(')')
2078 }
2079 g.definitions.write_string(')')
2080 fparams << caname
2081 fparamtypes << param_type_name
2082 heap_promoted << false
2083 } else {
2084 mut heap_prom := false
2085 if scope != unsafe { nil } {
2086 if param.name != '_' {
2087 if v := scope.find_var(param.name) {
2088 if !v.is_stack_obj && v.is_auto_heap {
2089 heap_prom = true
2090 }
2091 }
2092 }
2093 }
2094 var_name_prefix := if heap_prom { '_v_toheap_' } else { '' }
2095 const_prefix := if param.typ.is_any_kind_of_pointer() && !param.is_mut
2096 && param.name.starts_with('const_') {
2097 'const '
2098 } else {
2099 ''
2100 }
2101 const_param_type_name := if const_prefix != '' {
2102 g.const_pointer_param_type_name(typ, param_type_name)
2103 } else {
2104 param_type_name
2105 }
2106 s := '${const_prefix}${const_param_type_name} ${var_name_prefix}${caname}'
2107 if !g.inside_c_extern {
2108 g.write(s)
2109 }
2110 g.definitions.write_string(s)
2111 fparams << caname
2112 fparamtypes << param_type_name
2113 heap_promoted << heap_prom
2114 }
2115 if i < param_count - 1 {
2116 if !g.inside_c_extern {
2117 g.write(', ')
2118 }
2119 g.definitions.write_string(', ')
2120 }
2121 }
2122 if ((g.pref.translated && is_variadic) || is_c_variadic) && (!is_c_variadic || param_count > 0) {
2123 if param_count > 0 {
2124 if !g.inside_c_extern {
2125 g.write(', ')
2126 }
2127 g.definitions.write_string(', ')
2128 }
2129 if !g.inside_c_extern {
2130 g.write('... ')
2131 }
2132 g.definitions.write_string('... ')
2133 }
2134 return fparams, fparamtypes, heap_promoted
2135}
2136
2137fn (g &Gen) mut_option_param_assigned_directly(name string) bool {
2138 if g.cur_fn == unsafe { nil } {
2139 return false
2140 }
2141 for stmt in g.cur_fn.stmts {
2142 if stmt is ast.AssignStmt {
2143 for left in stmt.left {
2144 if left is ast.Ident && left.name == name {
2145 return true
2146 }
2147 }
2148 }
2149 }
2150 return false
2151}
2152
2153fn (mut g Gen) const_pointer_param_type_name(typ ast.Type, param_type_name string) string {
2154 unwrapped_typ := g.unwrap_generic(typ)
2155 return match unwrapped_typ {
2156 ast.voidptr_type { 'void*' }
2157 ast.byteptr_type { 'u8*' }
2158 ast.charptr_type { 'char*' }
2159 else { param_type_name }
2160 }
2161}
2162
2163fn (mut g Gen) get_anon_fn_type_name(mut node ast.AnonFn, var_name string) string {
2164 mut builder := strings.new_builder(64)
2165 return_styp := g.styp(node.decl.return_type)
2166 builder.write_string('${return_styp} (*${var_name}) (')
2167 if node.decl.params.len == 0 {
2168 builder.write_string('void)')
2169 } else {
2170 for i, param in node.decl.params {
2171 param_styp := g.styp(param.typ)
2172 builder.write_string('${param_styp} ${param.name}')
2173 if i != node.decl.params.len - 1 {
2174 builder.write_string(', ')
2175 }
2176 }
2177 builder.write_string(')')
2178 }
2179 return builder.str()
2180}
2181
2182fn (mut g Gen) call_expr(node ast.CallExpr) {
2183 if node.should_be_skipped {
2184 return
2185 }
2186 if node.is_c_type_cast {
2187 g.cast_expr(ast.CastExpr{
2188 typ: node.return_type
2189 typname: g.table.sym(g.unwrap_generic(node.return_type)).name
2190 expr: node.args[0].expr
2191 expr_type: node.args[0].typ
2192 pos: node.pos
2193 })
2194 return
2195 }
2196 is_shared := g.is_shared
2197 g.is_shared = false
2198 defer {
2199 g.is_shared = is_shared
2200 }
2201 // NOTE: everything could be done this way
2202 // see my comment in parser near anon_fn
2203 mut tmp_anon_fn_var := ''
2204 mut tmp_fn_result_var := ''
2205 mut needs_tmp_fn_result_cleanup := false
2206 if node.left is ast.AnonFn {
2207 if node.left.inherited_vars.len > 0 {
2208 tmp_anon_fn_var = g.new_tmp_var()
2209 fn_type := g.fn_var_signature(ast.void_type, node.left.decl.return_type,
2210 node.left.decl.params.map(it.typ), tmp_anon_fn_var)
2211 line := g.go_before_last_stmt().trim_space()
2212 g.empty_line = true
2213 g.write('${fn_type} = ')
2214 g.expr(ast.Expr(node.left))
2215 g.writeln(';')
2216 g.set_current_pos_as_last_stmt_pos()
2217 g.write(line)
2218 if node.or_block.kind == .absent {
2219 if g.out.last_n(1) != '\n' {
2220 g.writeln('')
2221 }
2222 g.write(tmp_anon_fn_var)
2223 }
2224 } else if node.or_block.kind == .absent {
2225 g.expr(ast.Expr(node.left))
2226 }
2227 } else if !g.inside_curry_call && node.left is ast.IndexExpr && node.name == '' {
2228 if node.or_block.kind == .absent {
2229 old_is_fn_index_call := g.is_fn_index_call
2230 g.is_fn_index_call = true
2231 g.expr(ast.Expr(node.left))
2232 g.is_fn_index_call = old_is_fn_index_call
2233 } else {
2234 // map1['key']() handling
2235 line := g.go_before_last_stmt()
2236 g.empty_line = true
2237
2238 // temp var for map1['key'] where value is a fn to be called
2239 left_typ := g.table.value_type(node.left.left_type)
2240 tmp_res := g.new_tmp_var()
2241 fn_sym := g.table.sym(left_typ).info as ast.FnType
2242 fn_type := g.fn_var_signature(ast.void_type, fn_sym.func.return_type,
2243 fn_sym.func.params.map(it.typ), tmp_res)
2244
2245 old_is_fn_index_call := g.is_fn_index_call
2246 g.is_fn_index_call = true
2247 g.write('${fn_type} = ')
2248 g.expr(ast.Expr(node.left))
2249 g.is_fn_index_call = old_is_fn_index_call
2250 g.writeln(';')
2251
2252 tmp_res2 := g.new_tmp_var()
2253 // uses the `tmp_res` as fn name (where it is a ptr to fn var)
2254 g.write('${g.styp(node.return_type)} ${tmp_res2} = ${tmp_res}')
2255 g.last_tmp_call_var << tmp_res2
2256 old_inside_curry_call := g.inside_curry_call
2257 g.inside_curry_call = true
2258 // map1['key']()() handling
2259 g.expr(node)
2260 g.inside_curry_call = old_inside_curry_call
2261 g.write2(line, '*(${g.base_type(node.return_type)}*)${tmp_res2}.data')
2262 return
2263 }
2264 } else if !g.inside_curry_call && node.left is ast.CallExpr && node.name == '' {
2265 if node.or_block.kind == .absent {
2266 left_return_typ := g.recheck_concrete_type(g.unwrap_generic(node.left.return_type))
2267 if g.table.used_features.anon_fn && g.table.final_sym(left_return_typ).kind == .function {
2268 tmp_fn_result_var = g.new_tmp_var()
2269 fn_sym := g.table.final_sym(left_return_typ).info as ast.FnType
2270 fn_type := g.fn_var_signature(ast.void_type, fn_sym.func.return_type,
2271 fn_sym.func.params.map(it.typ), tmp_fn_result_var)
2272 line := g.go_before_last_stmt().trim_space()
2273 g.empty_line = true
2274 g.write('${fn_type} = ')
2275 g.expr(ast.Expr(node.left))
2276 g.writeln(';')
2277 g.set_current_pos_as_last_stmt_pos()
2278 g.write(line)
2279 if g.out.last_n(1) != '\n' {
2280 g.writeln('')
2281 }
2282 g.write(tmp_fn_result_var)
2283 needs_tmp_fn_result_cleanup = true
2284 } else {
2285 g.expr(ast.Expr(node.left))
2286 }
2287 } else {
2288 ret_typ := node.return_type
2289
2290 line := g.go_before_last_stmt()
2291 g.empty_line = true
2292
2293 tmp_res := g.new_tmp_var()
2294 g.write('${g.styp(ret_typ)} ${tmp_res} = ')
2295
2296 g.last_tmp_call_var << tmp_res
2297 g.expr(ast.Expr(node.left))
2298
2299 old_inside_curry_call := g.inside_curry_call
2300 g.inside_curry_call = true
2301 g.expr(node)
2302 g.inside_curry_call = old_inside_curry_call
2303 g.write2(line, '*(${g.base_type(ret_typ)}*)${tmp_res}.data')
2304 return
2305 }
2306 } else if !g.inside_curry_call && node.left is ast.SelectorExpr && node.name == '' {
2307 if node.or_block.kind == .absent {
2308 g.expr(ast.Expr(node.left))
2309 } else {
2310 ret_typ := node.return_type
2311
2312 line := g.go_before_last_stmt()
2313 g.empty_line = true
2314
2315 tmp_res := g.new_tmp_var()
2316 g.write('${g.styp(ret_typ)} ${tmp_res} = ')
2317
2318 g.last_tmp_call_var << tmp_res
2319 g.expr(ast.Expr(node.left))
2320
2321 old_inside_curry_call := g.inside_curry_call
2322 g.inside_curry_call = true
2323 g.expr(node)
2324 g.inside_curry_call = old_inside_curry_call
2325 g.write2(line, '*(${g.base_type(ret_typ)}*)${tmp_res}.data')
2326 return
2327 }
2328 }
2329 old_inside_call := g.inside_call
2330 g.inside_call = true
2331 // Reset inside_selector_lhs so that receiver expressions inside method
2332 // calls generate proper auto-heap dereferences. Without this, when a
2333 // method call is nested inside a selector (e.g. exa.payload()!.len),
2334 // the selector's inside_selector_lhs flag would leak into the receiver
2335 // generation and suppress the (*(exa)) deref.
2336 old_inside_selector_lhs := g.inside_selector_lhs
2337 g.inside_selector_lhs = false
2338 defer {
2339 g.inside_call = old_inside_call
2340 g.inside_selector_lhs = old_inside_selector_lhs
2341 }
2342 gen_keep_alive := node.is_keep_alive && node.return_type != ast.void_type
2343 && g.pref.gc_mode in [.boehm_full, .boehm_incr, .boehm_full_opt, .boehm_incr_opt]
2344 gen_or := node.or_block.kind != .absent // && !g.is_autofree
2345 is_gen_or_and_assign_rhs := gen_or && !g.discard_or_result
2346 mut cur_line := if !g.inside_curry_call && (is_gen_or_and_assign_rhs || gen_keep_alive) { // && !g.is_autofree {
2347 // `x := foo() or { ...}`
2348 // cut everything that has been generated to prepend option variable creation
2349 line := g.go_before_last_stmt()
2350 g.out.write_string(util.tabs(g.indent))
2351 line
2352 } else {
2353 ''
2354 }
2355 // g.write('/*EE line="${cur_line}"*/')
2356 tmp_opt := if gen_or || gen_keep_alive {
2357 if g.inside_curry_call && g.last_tmp_call_var.len > 0 {
2358 g.last_tmp_call_var.pop()
2359 } else if !g.inside_or_block {
2360 new_tmp := g.new_tmp_var()
2361 g.last_tmp_call_var << new_tmp
2362 new_tmp
2363 } else {
2364 g.new_tmp_var()
2365 }
2366 } else {
2367 ''
2368 }
2369 mut tmp_fn_result_call_value := ''
2370 mut tmp_fn_result_call_line := ''
2371 if needs_tmp_fn_result_cleanup && !gen_or && !gen_keep_alive && !g.inside_curry_call
2372 && node.return_type != 0 && node.return_type != ast.void_type {
2373 tmp_fn_result_call_line = g.go_before_last_stmt()
2374 if tmp_fn_result_call_line.ends_with(tmp_fn_result_var) {
2375 tmp_fn_result_call_line = tmp_fn_result_call_line[..tmp_fn_result_call_line.len - tmp_fn_result_var.len]
2376 }
2377 g.empty_line = true
2378 tmp_fn_result_call_value = g.new_tmp_var()
2379 g.write('${g.styp(node.return_type)} ${tmp_fn_result_call_value} = ${tmp_fn_result_var}')
2380 }
2381 mut effective_return_type := node.return_type
2382 if (gen_or || gen_keep_alive) && node.return_type != 0 {
2383 mut ret_typ := effective_return_type
2384 resolved_ret_typ := g.resolve_return_type(node)
2385 if resolved_ret_typ != ast.void_type && !resolved_ret_typ.has_flag(.generic)
2386 && !g.type_has_unresolved_generic_parts(resolved_ret_typ) {
2387 if node.return_type.has_flag(.result) && !resolved_ret_typ.has_flag(.result) {
2388 ret_typ = resolved_ret_typ.set_flag(.result)
2389 } else if node.return_type.has_flag(.option) && !resolved_ret_typ.has_flag(.option) {
2390 ret_typ = resolved_ret_typ.set_flag(.option)
2391 } else {
2392 ret_typ = resolved_ret_typ
2393 }
2394 } else if g.table.sym(ret_typ).kind == .alias {
2395 unaliased_type := g.table.unaliased_type(ret_typ)
2396 if unaliased_type.has_option_or_result() {
2397 ret_typ = unaliased_type
2398 }
2399 } else if node.return_type_generic != 0 {
2400 unwrapped_ret_typ := g.unwrap_generic(node.return_type_generic)
2401 if !unwrapped_ret_typ.has_flag(.generic) {
2402 ret_sym := g.table.sym(unwrapped_ret_typ)
2403 if ret_sym.info is ast.Array && g.table.sym(node.return_type_generic).kind == .array {
2404 // Make []T returns T type when array was supplied to T
2405 if g.table.type_to_str(node.return_type_generic).count('[]') < g.table.type_to_str(unwrapped_ret_typ).count('[]') {
2406 ret_typ = g.unwrap_generic(ret_sym.info.elem_type).derive(unwrapped_ret_typ)
2407 }
2408 }
2409 } else if g.cur_fn != unsafe { nil } && g.cur_fn.is_method
2410 && g.cur_fn.receiver.typ.has_flag(.generic) && g.cur_concrete_types.len > 0 {
2411 // unwrap_generic failed because cur_fn.generic_names is empty
2412 // (generics come from the receiver, not the method itself).
2413 // Use the receiver's generic type names to resolve.
2414 receiver_generic_names := g.table.generic_type_names(g.cur_fn.receiver.typ)
2415 if receiver_generic_names.len == g.cur_concrete_types.len {
2416 if gen_type := g.table.convert_generic_type(node.return_type_generic,
2417 receiver_generic_names, g.cur_concrete_types)
2418 {
2419 if !gen_type.has_flag(.generic) {
2420 ret_typ = gen_type
2421 }
2422 }
2423 }
2424 }
2425 }
2426 effective_return_type = ret_typ
2427 mut styp := g.styp(ret_typ)
2428 if gen_or && !is_gen_or_and_assign_rhs {
2429 cur_line = g.go_before_last_stmt()
2430 }
2431 if gen_or && g.infix_left_var_name.len > 0 {
2432 g.writeln('${styp} ${tmp_opt};')
2433 g.writeln('if (${g.infix_left_var_name}) {')
2434 g.indent++
2435 g.write('${tmp_opt} = ')
2436 } else if !g.inside_curry_call {
2437 if g.assign_ct_type[node.pos.pos] != 0 && node.or_block.kind != .absent {
2438 styp = g.styp(g.assign_ct_type[node.pos.pos].derive(ret_typ))
2439 }
2440 g.write('${styp} ${tmp_opt} = ')
2441 if node.left is ast.AnonFn {
2442 if node.left.inherited_vars.len > 0 {
2443 g.write(tmp_anon_fn_var)
2444 } else {
2445 g.expr(ast.Expr(node.left))
2446 }
2447 }
2448 }
2449 }
2450 if node.is_method && !node.is_field {
2451 if g.pref.experimental && node.args.len > 0 && node.kind == .writeln
2452 && node.args[0].expr is ast.StringInterLiteral
2453 && g.table.sym(node.receiver_type).name == 'strings.Builder' {
2454 g.string_inter_literal_sb_optimized(node)
2455 } else {
2456 g.method_call(node)
2457 }
2458 } else {
2459 g.fn_call(node)
2460 }
2461 if needs_tmp_fn_result_cleanup && !gen_or && !gen_keep_alive && !g.inside_curry_call {
2462 if node.return_type == ast.void_type {
2463 g.writeln(';')
2464 g.write('builtin__closure__closure_try_destroy((voidptr)${tmp_fn_result_var})')
2465 g.set_current_pos_as_last_stmt_pos()
2466 } else if tmp_fn_result_call_value != '' {
2467 g.writeln(';')
2468 g.writeln('builtin__closure__closure_try_destroy((voidptr)${tmp_fn_result_var});')
2469 g.write2(tmp_fn_result_call_line, tmp_fn_result_call_value)
2470 }
2471 }
2472 if gen_or && node.return_type != 0 {
2473 g.or_block(tmp_opt, node.or_block, effective_return_type)
2474 mut unwrapped_typ := effective_return_type.clear_option_and_result()
2475 if g.table.sym(unwrapped_typ).kind == .alias {
2476 unaliased_type := g.table.unaliased_type(unwrapped_typ)
2477 if unaliased_type.has_option_or_result() {
2478 unwrapped_typ = unaliased_type.clear_option_and_result()
2479 }
2480 }
2481 mut unwrapped_styp := g.styp(unwrapped_typ)
2482 if g.infix_left_var_name.len > 0 {
2483 g.indent--
2484 g.writeln('}')
2485 g.set_current_pos_as_last_stmt_pos()
2486 }
2487 if unwrapped_typ == ast.void_type {
2488 g.write('\n ${cur_line}')
2489 } else if !g.inside_curry_call {
2490 if !g.inside_const_opt_or_res {
2491 if g.assign_ct_type[node.pos.pos] != 0 && node.or_block.kind != .absent {
2492 unwrapped_styp =
2493 g.styp(g.assign_ct_type[node.pos.pos].derive(effective_return_type).clear_option_and_result())
2494 }
2495 if g.table.sym(effective_return_type).kind == .array_fixed
2496 && unwrapped_styp.starts_with('_v_') {
2497 unwrapped_styp = unwrapped_styp[3..]
2498 }
2499 // Synthesized/transformed call nodes may lose `is_return_used`
2500 // even though the enclosing C generation path is still
2501 // emitting a value expression (struct fields, call args, etc).
2502 // In those cases `is_gen_or_and_assign_rhs` still tells us that
2503 // the unwrapped result is needed in the current expression.
2504 if node.is_return_used || is_gen_or_and_assign_rhs {
2505 is_fn := g.table.final_sym(unwrapped_typ).kind == .function
2506 // return value is used, so we need to write the unwrapped temporary var
2507 if is_fn && unwrapped_typ.nr_muls() > 0 {
2508 g.write('\n ${cur_line}((${unwrapped_styp}*)${tmp_opt}.data)')
2509 } else {
2510 g.write('\n ${cur_line}(*(${unwrapped_styp}*)${tmp_opt}.data)')
2511 }
2512 } else {
2513 g.write('\n ${cur_line}')
2514 }
2515 } else {
2516 if !g.inside_or_block && g.last_tmp_call_var.len > 0 && !cur_line.contains(' = ') {
2517 g.write('\n\t*(${unwrapped_styp}*)${g.last_tmp_call_var.pop()}.data = ${cur_line}(*(${unwrapped_styp}*)${tmp_opt}.data)')
2518 } else {
2519 g.write('\n ${cur_line}(*(${unwrapped_styp}*)${tmp_opt}.data)')
2520 }
2521 }
2522 }
2523 } else if gen_keep_alive && node.return_type != 0 {
2524 if node.return_type == ast.void_type {
2525 g.write('\n ${cur_line}')
2526 } else {
2527 g.write('\n ${cur_line} ${tmp_opt}')
2528 }
2529 }
2530 if node.is_noreturn {
2531 if g.inside_ternary == 0 {
2532 g.writeln(';')
2533 g.write('VUNREACHABLE()')
2534 } else {
2535 $if msvc {
2536 // MSVC has no support for the statement expressions used below
2537 } $else {
2538 g.write(', ({VUNREACHABLE();})')
2539 }
2540 }
2541 }
2542}
2543
2544fn (mut g Gen) conversion_function_call(prefix string, postfix string, node ast.CallExpr) {
2545 g.write('${prefix}( (')
2546 g.expr(node.left)
2547 dot := if node.left_type.is_ptr() { '->' } else { '.' }
2548 g.write(')${dot}_typ )${postfix}')
2549}
2550
2551@[inline]
2552fn (mut g Gen) write_raw_receiver_expr(node ast.Expr) {
2553 old_inside_selector_lhs := g.inside_selector_lhs
2554 g.inside_selector_lhs = true
2555 defer {
2556 g.inside_selector_lhs = old_inside_selector_lhs
2557 }
2558 g.expr(node)
2559}
2560
2561@[inline]
2562fn (mut g Gen) gen_arg_from_type(node_type ast.Type, node ast.Expr) {
2563 is_auto_heap_ident := node is ast.Ident && g.resolved_ident_is_auto_heap(node)
2564 if node_type.has_flag(.shared_f) {
2565 if node_type.is_ptr() || is_auto_heap_ident {
2566 g.write('&')
2567 }
2568 if is_auto_heap_ident {
2569 g.write_raw_receiver_expr(node)
2570 } else {
2571 g.expr(node)
2572 }
2573 g.write('->val')
2574 } else {
2575 if node_type.is_ptr() || is_auto_heap_ident {
2576 if is_auto_heap_ident {
2577 g.write_raw_receiver_expr(node)
2578 } else {
2579 g.expr(node)
2580 }
2581 } else if !node.is_lvalue()
2582 || (node is ast.Ident && g.table.is_interface_smartcast(node.obj)) {
2583 g.write('ADDR(${g.styp(node_type)}, ')
2584 g.expr(node)
2585 g.write(')')
2586 } else {
2587 g.write('&')
2588 g.expr(node)
2589 }
2590 }
2591}
2592
2593fn (mut g Gen) gen_map_method_call(node ast.CallExpr, left_type ast.Type, left_sym ast.TypeSymbol) bool {
2594 match node.kind {
2595 .reserve {
2596 g.write('builtin__map_reserve(')
2597 g.gen_arg_from_type(left_type, node.left)
2598 g.write(', ')
2599 g.expr(node.args[0].expr)
2600 g.write(')')
2601 }
2602 .delete {
2603 elem_type_str := if left_sym.info is ast.Map {
2604 g.styp(left_sym.info.key_type)
2605 } else {
2606 // In generic contexts, the left type may resolve to the base
2607 // `map` struct rather than a concrete `map[K]V`. Resolve the
2608 // key type from the argument expression instead.
2609 arg_type := g.unwrap_generic(g.resolved_expr_type(node.args[0].expr,
2610 node.args[0].typ))
2611 g.styp(arg_type)
2612 }
2613 g.write('builtin__map_delete(')
2614 g.gen_arg_from_type(left_type, node.left)
2615 g.write(', &(${elem_type_str}[]){')
2616 g.expr(node.args[0].expr)
2617 g.write('})')
2618 }
2619 .free, .clear, .keys, .values {
2620 g.write('builtin__map_${node.name}(')
2621 g.gen_arg_from_type(left_type, node.left)
2622 g.write(')')
2623 }
2624 else {
2625 return false
2626 }
2627 }
2628
2629 return true
2630}
2631
2632fn (mut g Gen) gen_array_method_call(node ast.CallExpr, left_type ast.Type, left_sym ast.TypeSymbol) bool {
2633 if node.name == 'get' {
2634 g.gen_array_get(node)
2635 return true
2636 }
2637 match node.kind {
2638 .filter {
2639 g.gen_array_filter(node)
2640 }
2641 .sort {
2642 g.gen_array_sort(node)
2643 }
2644 .sorted {
2645 g.gen_array_sorted(node)
2646 }
2647 .sort_with_compare {
2648 if !g.gen_array_sort_with_compare(node) {
2649 return false
2650 }
2651 }
2652 .sorted_with_compare {
2653 if !g.gen_array_sorted_with_compare(node) {
2654 return false
2655 }
2656 }
2657 .insert {
2658 g.gen_array_insert(node)
2659 }
2660 .map {
2661 g.gen_array_map(node)
2662 }
2663 .prepend {
2664 g.gen_array_prepend(node)
2665 }
2666 .contains {
2667 g.gen_array_contains(left_type, node.left, node.args[0].typ, node.args[0].expr)
2668 }
2669 .index {
2670 g.gen_array_index(node, false)
2671 }
2672 .last_index {
2673 g.gen_array_index(node, true)
2674 }
2675 .wait {
2676 g.gen_array_wait(node)
2677 }
2678 .any {
2679 g.gen_array_any(node)
2680 }
2681 .count {
2682 g.gen_array_count(node)
2683 }
2684 .all {
2685 g.gen_array_all(node)
2686 }
2687 .delete, .drop, .delete_last, .delete_many {
2688 g.write('builtin__array_${node.name}(')
2689 g.gen_arg_from_type(left_type, node.left)
2690 if node.kind != .delete_last {
2691 g.write(', ')
2692 g.expr(node.args[0].expr)
2693 if node.kind == .delete_many {
2694 g.write(', ')
2695 g.expr(node.args[1].expr)
2696 }
2697 }
2698 g.write(')')
2699 }
2700 .grow_cap, .grow_len {
2701 g.write('builtin__array_${node.name}(')
2702 g.gen_arg_from_type(left_type, node.left)
2703 g.write(', ')
2704 g.expr(node.args[0].expr)
2705 g.write(')')
2706 }
2707 .first, .last, .pop_left, .pop {
2708 mut noscan := ''
2709 array_info := left_sym.info as ast.Array
2710 if node.kind in [.pop_left, .pop] {
2711 noscan = g.check_noscan(array_info.elem_type)
2712 }
2713 return_type := g.resolved_array_builtin_method_return_type(node, left_type,
2714 node.return_type)
2715 return_type_str := g.styp(return_type)
2716 g.write('(*(${return_type_str}*)builtin__array_${node.name}${noscan}(')
2717 if node.kind in [.pop_left, .pop] {
2718 g.gen_arg_from_type(left_type, node.left)
2719 } else {
2720 if node.left_type.is_ptr() || node.left.is_auto_deref_var() {
2721 g.write('(*')
2722 g.expr(node.left)
2723 g.write(')')
2724 } else {
2725 g.expr(node.left)
2726 }
2727 if left_type.has_flag(.shared_f) {
2728 g.write('.val')
2729 }
2730 }
2731 g.write('))')
2732 }
2733 .clone, .repeat {
2734 array_info := left_sym.info as ast.Array
2735 elem_sym :=
2736 g.table.final_sym(g.table.unaliased_type(g.unwrap_generic(array_info.elem_type)))
2737 if node.kind == .repeat && elem_sym.kind == .interface {
2738 fn_name := g.register_array_interface_repeat_fn(g.resolve_return_type(node))
2739 g.write('${fn_name}(')
2740 if node.left_type.is_ptr() {
2741 g.write('*'.repeat(node.left_type.nr_muls()))
2742 }
2743 g.expr(ast.Expr(node.left))
2744 g.write(', ')
2745 g.expr(node.args[0].expr)
2746 g.write(')')
2747 return true
2748 }
2749 array_depth := g.get_array_depth(array_info.elem_type)
2750 to_depth := if array_depth >= 0 { '_to_depth' } else { '' }
2751 mut is_range_slice := false
2752 if node.left is ast.IndexExpr && node.left.index is ast.RangeExpr && node.kind == .clone {
2753 is_range_slice = true
2754 }
2755 to_static := if is_range_slice { '_static' } else { '' }
2756 g.write('builtin__array_${node.name}${to_static}${to_depth}(')
2757 if node.kind == .clone {
2758 if is_range_slice {
2759 if node.left_type.is_ptr() {
2760 g.write('*'.repeat(node.left_type.nr_muls()))
2761 }
2762 g.expr(node.left)
2763 } else {
2764 g.gen_arg_from_type(left_type, node.left)
2765 }
2766 } else {
2767 if node.left_type.is_ptr() {
2768 g.write('*'.repeat(node.left_type.nr_muls()))
2769 }
2770 g.expr(ast.Expr(node.left))
2771 }
2772 if node.kind == .repeat {
2773 g.write(', ')
2774 g.expr(node.args[0].expr)
2775 }
2776 if array_depth >= 0 {
2777 g.write(', ${array_depth}')
2778 }
2779 g.write(')')
2780 }
2781 else {
2782 return false
2783 }
2784 }
2785
2786 return true
2787}
2788
2789fn (mut g Gen) gen_fixed_array_method_call(node ast.CallExpr, left_type ast.Type) bool {
2790 match node.kind {
2791 .filter {
2792 g.gen_array_filter(node)
2793 }
2794 .index {
2795 g.gen_array_index(node, false)
2796 }
2797 .last_index {
2798 g.gen_array_index(node, true)
2799 }
2800 .contains {
2801 g.gen_array_contains(left_type, node.left, node.args[0].typ, node.args[0].expr)
2802 }
2803 .any {
2804 g.gen_array_any(node)
2805 }
2806 .count {
2807 g.gen_array_count(node)
2808 }
2809 .all {
2810 g.gen_array_all(node)
2811 }
2812 .map {
2813 g.gen_array_map(node)
2814 }
2815 .sort {
2816 g.gen_array_sort(node)
2817 }
2818 .sorted {
2819 g.gen_array_sorted(node)
2820 }
2821 .sort_with_compare {
2822 if !g.gen_array_sort_with_compare(node) {
2823 return false
2824 }
2825 }
2826 .sorted_with_compare {
2827 if !g.gen_array_sorted_with_compare(node) {
2828 return false
2829 }
2830 }
2831 .reverse {
2832 g.gen_fixed_array_reverse(node)
2833 }
2834 .reverse_in_place {
2835 g.gen_fixed_array_reverse_in_place(node)
2836 }
2837 else {
2838 return false
2839 }
2840 }
2841
2842 return true
2843}
2844
2845fn (mut g Gen) gen_to_str_method_call(node ast.CallExpr, unwrapped_rec_type ast.Type) bool {
2846 left_node := node.left
2847 mut rec_type := g.unwrap_generic(g.type_resolver.get_type_or_default(left_node,
2848 left_node.type()))
2849 if rec_type in [ast.void_type, ast.no_type] {
2850 rec_type = unwrapped_rec_type
2851 }
2852 if rec_type.has_flag(.shared_f) {
2853 rec_type = rec_type.clear_flag(.shared_f).set_nr_muls(0)
2854 }
2855 if left_node is ast.ComptimeSelector {
2856 if left_node.typ_key != '' {
2857 rec_type = g.type_resolver.get_ct_type_or_default(left_node.typ_key, rec_type)
2858 g.gen_expr_to_string(left_node, rec_type)
2859 return true
2860 }
2861 } else if left_node is ast.PostfixExpr {
2862 rec_type = g.type_resolver.get_type_or_default(left_node.expr, rec_type)
2863 if left_node.op == .question {
2864 rec_type = rec_type.clear_flag(.option)
2865 }
2866 g.gen_expr_to_string(left_node, rec_type)
2867 return true
2868 } else if left_node is ast.ComptimeCall {
2869 if left_node.kind == .method {
2870 sym := g.table.sym(g.unwrap_generic(left_node.left_type))
2871 if m := sym.find_method(g.comptime.comptime_for_method.name) {
2872 rec_type = m.return_type
2873 g.gen_expr_to_string(left_node, rec_type)
2874 return true
2875 }
2876 }
2877 } else if left_node is ast.Ident {
2878 if left_node.obj is ast.Var {
2879 if left_node.obj.ct_type_var != .no_comptime {
2880 rec_type = g.type_resolver.get_type(left_node)
2881 // In generic contexts, scope var types may be stale
2882 if g.cur_fn != unsafe { nil } && g.cur_concrete_types.len > 0
2883 && left_node.obj.ct_type_var == .generic_param {
2884 resolved := g.resolved_expr_type(left_node, rec_type)
2885 if resolved != 0 {
2886 rec_type = resolved
2887 }
2888 }
2889 g.gen_expr_to_string(left_node, rec_type)
2890 return true
2891 } else if left_node.obj.smartcasts.len > 0 {
2892 rec_type = g.unwrap_generic(left_node.obj.smartcasts.last())
2893 cast_sym := g.table.sym(rec_type)
2894 if cast_sym.info is ast.Aggregate {
2895 rec_type = cast_sym.info.types[g.aggregate_type_idx]
2896 }
2897 g.gen_expr_to_string(left_node, rec_type)
2898 return true
2899 } else if left_node.or_expr.kind == .propagate_option {
2900 g.gen_expr_to_string(left_node, g.unwrap_generic(node.left_type))
2901 return true
2902 }
2903 }
2904 } else if left_node is ast.None {
2905 g.gen_expr_to_string(left_node, ast.none_type)
2906 return true
2907 } else if node.left_type.has_flag(.option) {
2908 g.gen_expr_to_string(left_node, g.unwrap_generic(node.left_type))
2909 return true
2910 }
2911 if g.cur_fn != unsafe { nil } && g.cur_concrete_types.len > 0 {
2912 resolved_rec_type := g.resolved_expr_type(left_node, node.left_type)
2913 if resolved_rec_type != 0 && resolved_rec_type != ast.void_type {
2914 g.gen_expr_to_string(left_node,
2915 g.unwrap_generic(g.recheck_concrete_type(resolved_rec_type)))
2916 return true
2917 }
2918 }
2919 rec_sym := g.table.sym(rec_type)
2920 if g.alias_uses_parent_str(rec_sym) {
2921 rec_type = (rec_sym.info as ast.Alias).parent_type
2922 }
2923 g.get_str_fn(rec_type)
2924 return false
2925}
2926
2927fn (g &Gen) alias_uses_parent_str(sym ast.TypeSymbol) bool {
2928 if sym.info !is ast.Alias || sym.has_method('str') {
2929 return false
2930 }
2931 alias_info := sym.info as ast.Alias
2932 parent_sym := g.table.sym(alias_info.parent_type)
2933 return parent_sym.is_string() || parent_sym.is_number()
2934 || parent_sym.kind in [.bool, .char, .byteptr, .charptr, .voidptr, .map]
2935}
2936
2937fn (g &Gen) alias_keeps_parent_method_dispatch(sym ast.TypeSymbol, method_name string, kind ast.CallKind) bool {
2938 if sym.info !is ast.Alias || sym.has_method(method_name) {
2939 return false
2940 }
2941 return kind != .str || g.alias_uses_parent_str(sym)
2942}
2943
2944// resolve_return_type resolves the generic return type of CallExpr
2945fn (mut g Gen) resolve_return_type(node ast.CallExpr) ast.Type {
2946 if node.is_method {
2947 if node.kind == .map && node.return_type != 0 && !node.return_type.has_flag(.generic)
2948 && !g.type_has_unresolved_generic_parts(node.return_type)
2949 && !(g.cur_fn != unsafe { nil } && g.cur_concrete_types.len > 0) {
2950 return if node.or_block.kind == .absent {
2951 g.unwrap_generic(g.recheck_concrete_type(node.return_type))
2952 } else {
2953 g.unwrap_generic(g.recheck_concrete_type(node.return_type)).clear_option_and_result()
2954 }
2955 }
2956 mut left_type := g.resolved_expr_type(node.left, node.left_type)
2957 if left_type == 0 || left_type == ast.void_type {
2958 left_type = node.left_type
2959 }
2960 left_type = g.recheck_concrete_type(left_type)
2961 if left_type == 0 || left_type == ast.void_type {
2962 return ast.void_type
2963 }
2964 left_sym := g.table.sym(left_type)
2965 final_left_sym := g.table.final_sym(g.unwrap_generic(left_type))
2966 if final_left_sym.kind == .map && node.kind in [.keys, .values] {
2967 map_info := final_left_sym.info as ast.Map
2968 return_type := if node.kind == .keys {
2969 ast.idx_to_type(g.table.find_or_register_array(map_info.key_type))
2970 } else {
2971 ast.idx_to_type(g.table.find_or_register_array(map_info.value_type))
2972 }
2973 return if node.or_block.kind == .absent {
2974 return_type
2975 } else {
2976 return_type.clear_option_and_result()
2977 }
2978 }
2979 if final_left_sym.kind == .map && node.name in ['clone', 'move'] {
2980 return g.unwrap_generic(left_type)
2981 }
2982 if final_left_sym.kind in [.array, .array_fixed] && !(left_sym.has_method(node.name)
2983 || left_sym.has_method_with_generic_parent(node.name)) && (node.name == 'get'
2984 || node.kind in [.first, .last, .pop_left, .pop, .map, .filter, .reverse, .clone, .clone_to_depth, .repeat, .trim, .slice, .sorted, .sorted_with_compare]) {
2985 return_type := g.resolved_array_builtin_method_return_type(node, left_type,
2986 node.return_type)
2987 return if node.or_block.kind == .absent {
2988 return_type
2989 } else {
2990 return_type.clear_option_and_result()
2991 }
2992 }
2993 if node.is_field {
2994 selector := ast.SelectorExpr{
2995 expr: node.left
2996 expr_type: left_type
2997 field_name: node.name
2998 }
2999 fn_typ := g.resolved_selector_field_type(selector, left_type)
3000 if fn_typ != 0 {
3001 fn_sym := g.table.final_sym(fn_typ.clear_option_and_result())
3002 if fn_sym.info is ast.FnType {
3003 return_type :=
3004 g.unwrap_generic(g.recheck_concrete_type(fn_sym.info.func.return_type))
3005 if return_type != 0 {
3006 return if node.or_block.kind == .absent {
3007 return_type
3008 } else {
3009 return_type.clear_option_and_result()
3010 }
3011 }
3012 }
3013 }
3014 }
3015 func := left_sym.find_method_with_generic_parent(node.name) or {
3016 g.table.find_method(left_sym, node.name) or { return ast.void_type }
3017 }
3018 if func.return_type != 0 && !func.return_type.has_flag(.generic)
3019 && !g.type_has_unresolved_generic_parts(func.return_type) {
3020 return if node.or_block.kind == .absent {
3021 func.return_type
3022 } else {
3023 func.return_type.clear_option_and_result()
3024 }
3025 }
3026 receiver_concrete_types, parent_method := g.receiver_generic_call_context(left_type,
3027 node.name)
3028 if func.generic_names.len > 0 {
3029 mut concrete_types := if node.concrete_types.len == func.generic_names.len
3030 && node.concrete_types.all(it != 0 && !it.has_flag(.generic)
3031 && !g.type_has_unresolved_generic_parts(it)) {
3032 node.concrete_types.map(g.unwrap_generic(it))
3033 } else if node.raw_concrete_types.len > 0 {
3034 node.raw_concrete_types.map(g.unwrap_generic(it))
3035 } else {
3036 node.concrete_types.map(g.unwrap_generic(it))
3037 }
3038 if concrete_types.len == 0 && receiver_concrete_types.len > 0 {
3039 concrete_types = receiver_concrete_types.clone()
3040 } else if receiver_concrete_types.len > 0 && concrete_types.len < func.generic_names.len
3041 && receiver_concrete_types.len + concrete_types.len == func.generic_names.len {
3042 method_concrete_types := concrete_types.clone()
3043 concrete_types = receiver_concrete_types.clone()
3044 concrete_types << method_concrete_types
3045 }
3046 if receiver_concrete_types.len > 0 {
3047 for i, receiver_ct in receiver_concrete_types {
3048 if i < concrete_types.len {
3049 concrete_types[i] = receiver_ct
3050 }
3051 }
3052 }
3053 mut rec_len := 0
3054 if left_type.has_flag(.generic) {
3055 rec_sym := g.table.final_sym(g.unwrap_generic(left_type))
3056 match rec_sym.info {
3057 ast.Struct, ast.Interface, ast.SumType {
3058 rec_len += rec_sym.info.generic_types.len
3059 }
3060 else {}
3061 }
3062 }
3063 if g.cur_fn != unsafe { nil } && g.cur_concrete_types.len > 0 {
3064 offset := if func.is_method { 1 } else { 0 }
3065 receiver_param_type := if func.params.len > 0 {
3066 func.params[0].typ
3067 } else {
3068 ast.no_type
3069 }
3070 mut generic_arg_idx := 0
3071 for i, arg in node.args {
3072 param := if func.is_variadic && i >= func.params.len - (offset + 1) {
3073 func.params.last()
3074 } else {
3075 func.params[offset + i]
3076 }
3077 if !param.typ.has_flag(.generic) || param.typ == receiver_param_type {
3078 continue
3079 }
3080 slot := rec_len + generic_arg_idx
3081 generic_arg_idx++
3082 // Only override if the current concrete type is still unresolved.
3083 // The checker already resolves concrete types correctly (e.g. T=int for []T with []int arg),
3084 // so we should not overwrite already-resolved values with the full argument type
3085 // (which would turn T=int into T=[]int, causing []T to resolve to [][]int).
3086 if slot < concrete_types.len {
3087 current_type := concrete_types[slot]
3088 if current_type != 0 && current_type != ast.void_type
3089 && !current_type.has_flag(.generic)
3090 && !g.type_has_unresolved_generic_parts(current_type) {
3091 // When the arg is a generic_param variable, the checker's concrete type
3092 // may be stale (from a different instantiation). Re-resolve from
3093 // g.cur_concrete_types and override if different.
3094 if arg.expr is ast.Ident && arg.expr.obj is ast.Var
3095 && (arg.expr.obj as ast.Var).ct_type_var == .generic_param && g.table.sym(param.typ).name in func.generic_names {
3096 mut resolved :=
3097 g.resolve_current_fn_generic_param_type(arg.expr.name)
3098 if (arg.is_mut || (arg.expr.obj as ast.Var).is_mut)
3099 && resolved.is_ptr() {
3100 resolved = resolved.deref()
3101 }
3102 if resolved != 0 && resolved != ast.void_type
3103 && resolved != current_type {
3104 concrete_types[slot] = resolved
3105 }
3106 }
3107 continue
3108 }
3109 }
3110 mut resolved_arg_type := ast.void_type
3111 if arg.expr is ast.Ident && arg.expr.obj is ast.Var
3112 && (arg.expr.obj as ast.Var).ct_type_var == .generic_param {
3113 resolved_arg_type = g.resolve_current_fn_generic_param_type(arg.expr.name)
3114 if (arg.is_mut || (arg.expr.obj as ast.Var).is_mut)
3115 && resolved_arg_type.is_ptr() {
3116 resolved_arg_type = resolved_arg_type.deref()
3117 }
3118 }
3119 if resolved_arg_type == ast.void_type {
3120 resolved_arg_type = g.resolved_generic_call_arg_type(arg)
3121 }
3122 if arg.expr.is_auto_deref_var() && resolved_arg_type.is_ptr()
3123 && !param.typ.is_ptr() {
3124 resolved_arg_type = resolved_arg_type.deref()
3125 }
3126 if resolved_arg_type.clear_option_and_result() == ast.none_type {
3127 continue
3128 }
3129 if resolved_arg_type != 0 && resolved_arg_type != ast.void_type
3130 && !resolved_arg_type.has_flag(.generic)
3131 && !g.type_has_unresolved_generic_parts(resolved_arg_type)
3132 && slot < concrete_types.len {
3133 g.infer_generic_call_concrete_types_from_types(func.generic_names, mut
3134 concrete_types, arg, param.typ, resolved_arg_type)
3135 }
3136 }
3137 }
3138
3139 mut call_ := unsafe { node }
3140 comptime_args := g.type_resolver.resolve_args(g.cur_fn, func, mut call_, concrete_types)
3141 if concrete_types.len > 0 {
3142 for k, v in comptime_args {
3143 slot := rec_len + k
3144 if slot < concrete_types.len {
3145 current_type := concrete_types[slot]
3146 if current_type == ast.void_type || current_type.has_flag(.generic)
3147 || g.type_has_unresolved_generic_parts(current_type) {
3148 concrete_types[slot] = g.unwrap_generic(v)
3149 }
3150 }
3151 }
3152 }
3153 // Prefer the resolved method declaration over the cached call metadata here.
3154 // Generic rechecks can leave `node.return_type_generic` stale even when the
3155 // method's concrete type arguments have since been corrected.
3156 mut return_type_candidates := []ast.Type{}
3157 if func.return_type != 0 {
3158 return_type_candidates << func.return_type
3159 }
3160 if node.return_type_generic != ast.void_type && node.return_type_generic != 0
3161 && node.return_type_generic !in return_type_candidates {
3162 return_type_candidates << node.return_type_generic
3163 }
3164 if parent_method.params.len > 0 && parent_method.return_type != 0
3165 && parent_method.return_type !in return_type_candidates {
3166 return_type_candidates << parent_method.return_type
3167 }
3168 for return_type_generic in return_type_candidates {
3169 if gen_type := g.table.convert_generic_type(return_type_generic,
3170 func.generic_names, concrete_types)
3171 {
3172 if !gen_type.has_flag(.generic) {
3173 return if node.or_block.kind == .absent {
3174 gen_type
3175 } else {
3176 gen_type.clear_option_and_result()
3177 }
3178 }
3179 }
3180 }
3181 }
3182 if parent_method.params.len > 0 && receiver_concrete_types.len > 0 {
3183 parent_return_type_generic := if node.return_type_generic != ast.void_type
3184 && node.return_type_generic != 0 {
3185 node.return_type_generic
3186 } else {
3187 parent_method.return_type
3188 }
3189 receiver_generic_names := g.table.generic_type_names(parent_method.params[0].typ)
3190 if receiver_generic_names.len == receiver_concrete_types.len {
3191 if gen_type := g.table.convert_generic_type(parent_return_type_generic,
3192 receiver_generic_names, receiver_concrete_types)
3193 {
3194 if !gen_type.has_flag(.generic) {
3195 return if node.or_block.kind == .absent {
3196 gen_type
3197 } else {
3198 gen_type.clear_option_and_result()
3199 }
3200 }
3201 }
3202 }
3203 }
3204 } else if node.is_static_method {
3205 // For static method calls like T.from(s) or T.parse(mut p) in generic contexts,
3206 // node.return_type may be stale from a previous checker instantiation.
3207 // Resolve from left_type which retains the .generic flag.
3208 if node.left_type.has_flag(.generic) && g.cur_fn != unsafe { nil }
3209 && g.cur_concrete_types.len > 0 {
3210 resolved_left := g.unwrap_generic(g.recheck_concrete_type(node.left_type))
3211 if resolved_left != ast.void_type && resolved_left != 0 {
3212 mut ret := resolved_left
3213 if node.return_type.has_flag(.result) {
3214 ret = ret.set_flag(.result)
3215 } else if node.return_type.has_flag(.option) {
3216 ret = ret.set_flag(.option)
3217 }
3218 return if node.or_block.kind == .absent {
3219 ret
3220 } else {
3221 ret.clear_option_and_result()
3222 }
3223 }
3224 }
3225 ret_type := g.unwrap_generic(g.recheck_concrete_type(node.return_type))
3226 return if node.or_block.kind == .absent {
3227 ret_type
3228 } else {
3229 ret_type.clear_option_and_result()
3230 }
3231 } else {
3232 mut fn_var_type := ast.void_type
3233 lookup_name := if node.left is ast.Ident { node.left.name } else { node.name }
3234 resolved_current_type := g.resolve_current_fn_generic_param_type(lookup_name)
3235 if resolved_current_type != 0
3236 && g.table.final_sym(g.unwrap_generic(resolved_current_type)).kind == .function {
3237 fn_var_type = g.unwrap_generic(g.recheck_concrete_type(resolved_current_type))
3238 } else if node.is_fn_var {
3239 fn_var_type = g.unwrap_generic(g.recheck_concrete_type(node.fn_var_type))
3240 }
3241 if fn_var_type == 0 {
3242 if obj := node.scope.find_var(lookup_name) {
3243 if g.table.final_sym(g.unwrap_generic(obj.typ)).kind == .function {
3244 fn_var_type = g.unwrap_generic(g.recheck_concrete_type(obj.typ))
3245 }
3246 }
3247 }
3248 if fn_var_type != 0 {
3249 fn_sym := g.table.final_sym(fn_var_type)
3250 if fn_sym.info is ast.FnType {
3251 return_type :=
3252 g.unwrap_generic(g.recheck_concrete_type(fn_sym.info.func.return_type))
3253 if return_type != 0 {
3254 return if node.or_block.kind == .absent {
3255 return_type
3256 } else {
3257 return_type.clear_option_and_result()
3258 }
3259 }
3260 }
3261 }
3262 if func := g.table.find_fn(node.name) {
3263 if func.generic_names.len > 0 {
3264 mut concrete_types := g.generic_fn_call_concrete_types(func, node)
3265 mut call_ := unsafe { node }
3266 comptime_args := g.type_resolver.resolve_args(g.cur_fn, func, mut call_,
3267 concrete_types)
3268 if concrete_types.len > 0 {
3269 for k, v in comptime_args {
3270 if k < concrete_types.len {
3271 current_type := concrete_types[k]
3272 if current_type == ast.void_type || current_type.has_flag(.generic)
3273 || g.type_has_unresolved_generic_parts(current_type) {
3274 concrete_types[k] = g.unwrap_generic(v)
3275 }
3276 }
3277 }
3278 }
3279 return_type_generic := if node.return_type_generic != ast.void_type {
3280 node.return_type_generic
3281 } else {
3282 func.return_type
3283 }
3284 if gen_type := g.table.convert_generic_type(return_type_generic,
3285 func.generic_names, concrete_types)
3286 {
3287 if !gen_type.has_flag(.generic) {
3288 return if node.or_block.kind == .absent {
3289 gen_type
3290 } else {
3291 gen_type.clear_option_and_result()
3292 }
3293 }
3294 }
3295 }
3296 }
3297 }
3298 return ast.void_type
3299}
3300
3301fn (mut g Gen) resolved_array_builtin_method_return_type(node ast.CallExpr, left_type ast.Type, fallback ast.Type) ast.Type {
3302 mut return_type := g.unwrap_generic(g.recheck_concrete_type(fallback))
3303 resolved_left_type := g.recheck_concrete_type(g.resolved_expr_type(node.left, left_type))
3304 if resolved_left_type == 0 {
3305 return return_type
3306 }
3307 resolved_left_sym := g.table.final_sym(g.unwrap_generic(resolved_left_type))
3308 if resolved_left_sym.kind !in [.array, .array_fixed] {
3309 return return_type
3310 }
3311 if node.name == 'get' {
3312 elem_type := if resolved_left_sym.info is ast.Array {
3313 resolved_left_sym.info.elem_type
3314 } else if resolved_left_sym.info is ast.ArrayFixed {
3315 resolved_left_sym.info.elem_type
3316 } else {
3317 return return_type
3318 }
3319 if elem_type == 0 {
3320 return return_type
3321 }
3322 return g.unwrap_generic(g.recheck_concrete_type(elem_type.set_flag(.option)))
3323 }
3324 match node.kind {
3325 .map {
3326 if node.args.len == 0 {
3327 return return_type
3328 }
3329 arg := node.args[0]
3330 arg_type := g.unwrap_generic(g.recheck_concrete_type(g.resolved_expr_type(arg.expr,
3331 arg.typ)))
3332 if arg_type == 0 {
3333 return return_type
3334 }
3335 arg_sym := g.table.final_sym(g.unwrap_generic(arg_type))
3336 mapped_type := match arg_sym.info {
3337 ast.FnType {
3338 if arg.expr is ast.SelectorExpr {
3339 arg_type
3340 } else {
3341 arg_sym.info.func.return_type
3342 }
3343 }
3344 else {
3345 arg_type
3346 }
3347 }
3348
3349 resolved_mapped_type := g.unwrap_generic(g.recheck_concrete_type(mapped_type))
3350 if resolved_mapped_type == 0 {
3351 return return_type
3352 }
3353 return g.table.find_or_register_array(resolved_mapped_type)
3354 }
3355 .filter, .reverse, .clone, .clone_to_depth, .repeat, .trim, .slice, .sorted,
3356 .sorted_with_compare {
3357 // These methods return a new array by value, never a pointer.
3358 // Strip pointer flags from mut receivers.
3359 mut ret := g.unwrap_generic(resolved_left_type).set_nr_muls(0)
3360 // .filter on a fixed array returns a dynamic array since the
3361 // result size is determined at runtime.
3362 if node.kind == .filter && resolved_left_sym.kind == .array_fixed {
3363 info := resolved_left_sym.info as ast.ArrayFixed
3364 ret = ast.new_type(g.table.find_or_register_array(info.elem_type))
3365 }
3366 return ret
3367 }
3368 .first, .last, .pop_left, .pop {
3369 elem_type := if resolved_left_sym.info is ast.Array {
3370 resolved_left_sym.info.elem_type
3371 } else if resolved_left_sym.info is ast.ArrayFixed {
3372 resolved_left_sym.info.elem_type
3373 } else {
3374 return return_type
3375 }
3376 if elem_type == 0 {
3377 return return_type
3378 }
3379 return g.unwrap_generic(g.recheck_concrete_type(elem_type))
3380 }
3381 else {}
3382 }
3383
3384 return return_type
3385}
3386
3387fn (mut g Gen) resolve_receiver_name(node ast.CallExpr, unwrapped_rec_type ast.Type, final_left_sym ast.TypeSymbol,
3388 left_sym ast.TypeSymbol, typ_sym ast.TypeSymbol) string {
3389 mut receiver_type_name := util.no_dots(g.cc_type(unwrapped_rec_type, false))
3390 if final_left_sym.kind == .map && node.kind in [.clone, .move] {
3391 receiver_type_name = 'map'
3392 }
3393 if final_left_sym.kind == .array && !(left_sym.kind == .alias && left_sym.has_method(node.name))
3394 && node.kind in [.clear, .repeat, .sort_with_compare, .sorted_with_compare, .push_many, .trim, .first, .last, .pop_left, .pop, .clone, .clone_to_depth, .reverse, .slice, .pointers] {
3395 if !(left_sym.info is ast.Alias && typ_sym.has_method(node.name)) {
3396 // `array_Xyz_clone` => `builtin__array_clone`
3397 receiver_type_name = 'array'
3398 }
3399 }
3400 return receiver_type_name
3401}
3402
3403fn (mut g Gen) receiver_generic_call_context(left_type ast.Type, method_name string) ([]ast.Type, ast.Fn) {
3404 rec_sym := g.table.final_sym(left_type)
3405 mut receiver_concrete_types := []ast.Type{}
3406 mut parent_method := ast.Fn{}
3407 match rec_sym.info {
3408 ast.Struct, ast.Interface, ast.SumType {
3409 if rec_sym.info.concrete_types.len > 0 {
3410 receiver_concrete_types = rec_sym.info.concrete_types.map(g.unwrap_generic(it))
3411 } else if rec_sym.generic_types.len == rec_sym.info.generic_types.len
3412 && rec_sym.generic_types != rec_sym.info.generic_types {
3413 receiver_concrete_types = rec_sym.generic_types.map(g.unwrap_generic(it))
3414 }
3415 if rec_sym.info.parent_type.has_flag(.generic) {
3416 parent_sym := g.table.sym(rec_sym.info.parent_type)
3417 if m := parent_sym.find_method(method_name) {
3418 parent_method = m
3419 }
3420 }
3421 }
3422 ast.GenericInst {
3423 receiver_concrete_types = rec_sym.info.concrete_types.map(g.unwrap_generic(it))
3424 if rec_sym.info.parent_idx > 0 {
3425 parent_sym := g.table.sym(ast.idx_to_type(rec_sym.info.parent_idx))
3426 if m := parent_sym.find_method(method_name) {
3427 parent_method = m
3428 }
3429 }
3430 }
3431 else {}
3432 }
3433
3434 // For generic fn-type aliases (e.g. `type ParseFunction[T] = fn(string) !T`),
3435 // the concrete instantiation is stored as FnType with generic_types holding
3436 // the concrete types. Check generic_types on the sym and its parent.
3437 if receiver_concrete_types.len == 0 {
3438 non_final_sym := g.table.sym(left_type)
3439 if non_final_sym.info is ast.GenericInst {
3440 receiver_concrete_types = non_final_sym.info.concrete_types.map(g.unwrap_generic(it))
3441 if non_final_sym.info.parent_idx > 0 {
3442 parent_sym := g.table.sym(ast.idx_to_type(non_final_sym.info.parent_idx))
3443 if m := parent_sym.find_method(method_name) {
3444 parent_method = m
3445 }
3446 }
3447 } else if non_final_sym.generic_types.len > 0 && non_final_sym.parent_idx > 0
3448 && !non_final_sym.generic_types.any(it.has_flag(.generic)) {
3449 // Concrete generic instantiation (e.g. ParseFunction[string])
3450 // where generic_types holds the resolved concrete types.
3451 receiver_concrete_types = non_final_sym.generic_types.map(g.unwrap_generic(it))
3452 parent_sym := g.table.sym(ast.idx_to_type(non_final_sym.parent_idx))
3453 if m := parent_sym.find_method(method_name) {
3454 parent_method = m
3455 }
3456 }
3457 }
3458 return receiver_concrete_types, parent_method
3459}
3460
3461fn (mut g Gen) resolved_generic_call_arg_type(arg ast.CallArg) ast.Type {
3462 mut arg_type := g.resolved_expr_type(arg.expr, arg.typ)
3463 if arg.expr is ast.ComptimeCall && arg.expr.method_name == 'method'
3464 && g.comptime.comptime_for_method != unsafe { nil } {
3465 sym := g.table.sym(g.unwrap_generic(arg.expr.left_type))
3466 if m := sym.find_method(g.comptime.comptime_for_method.name) {
3467 return m.return_type
3468 }
3469 }
3470 mut has_current_generic_type := false
3471 mut resolved_current_type := ast.void_type
3472 if arg.expr is ast.Ident {
3473 // In comptime variant loops, a smartcast variable's type is dynamically
3474 // resolved per variant iteration. Don't override it with the generic param
3475 // resolution (which gives the sumtype, not the variant).
3476 is_comptime_smartcast := arg.expr.obj is ast.Var && arg.expr.obj.ct_type_var == .smartcast
3477 && g.comptime.comptime_for_variant_var.len > 0
3478 if !is_comptime_smartcast {
3479 resolved_current_type = g.resolve_current_fn_generic_param_type(arg.expr.name)
3480 }
3481 if resolved_current_type != 0 {
3482 has_current_generic_type = true
3483 is_mut_source_arg := arg.expr.obj is ast.Var && arg.expr.obj.is_arg
3484 && arg.expr.obj.is_mut
3485 arg_type = if (arg.is_mut || is_mut_source_arg) && resolved_current_type.is_ptr() {
3486 resolved_current_type.deref()
3487 } else {
3488 resolved_current_type
3489 }
3490 }
3491 if arg.expr.obj is ast.Var {
3492 scope_type := g.resolved_scope_var_type(arg.expr)
3493 keep_source_generic_type := has_current_generic_type && arg.expr.obj.is_arg
3494 && arg.expr.obj.is_mut && scope_type.is_ptr() && !arg_type.is_ptr()
3495 // When the generic param type was resolved from cur_concrete_types
3496 // and is fully concrete, trust it over potentially stale scope types.
3497 skip_scope_override := has_current_generic_type && arg_type != 0
3498 && !arg_type.has_flag(.generic) && !g.type_has_unresolved_generic_parts(arg_type)
3499 if scope_type != 0 && !keep_source_generic_type && !skip_scope_override
3500 && (arg_type == 0 || arg_type.has_flag(.generic)
3501 || g.type_has_unresolved_generic_parts(arg_type)
3502 || has_current_generic_type
3503 || g.unwrap_generic(arg_type) != g.unwrap_generic(scope_type)
3504 || arg_type == ast.usize_type
3505 || (arg.expr.obj as ast.Var).smartcasts.len > 0) {
3506 arg_type = scope_type
3507 }
3508 }
3509 }
3510 if !arg.is_mut && arg.expr.is_auto_deref_var() && arg_type.is_ptr() {
3511 arg_type = arg_type.deref()
3512 }
3513 return g.unwrap_generic(g.recheck_concrete_type(arg_type))
3514}
3515
3516fn (mut g Gen) generic_param_infer_type(param ast.Param) ast.Type {
3517 if param.orig_typ != 0 && (param.orig_typ.has_flag(.generic)
3518 || g.type_has_unresolved_generic_parts(param.orig_typ)) {
3519 return param.orig_typ
3520 }
3521 return param.typ
3522}
3523
3524fn (mut g Gen) infer_generic_call_concrete_types_from_types(generic_names []string, mut concrete_types []ast.Type, arg ast.CallArg, param_typ ast.Type, arg_typ ast.Type) {
3525 g.infer_generic_call_concrete_types_from_types_inner(generic_names, mut concrete_types, arg,
3526 param_typ, arg_typ, false)
3527}
3528
3529fn (mut g Gen) infer_generic_call_concrete_types_from_types_inner(generic_names []string, mut concrete_types []ast.Type, arg ast.CallArg, param_typ ast.Type, arg_typ ast.Type, from_composite bool) {
3530 if param_typ == 0 || arg_typ == 0 {
3531 return
3532 }
3533 param_sym := g.table.sym(param_typ)
3534 arg_sym := g.table.final_sym(g.unwrap_generic(arg_typ))
3535 if (param_typ.has_flag(.option) && arg_typ.has_flag(.option))
3536 || (param_typ.has_flag(.result) && arg_typ.has_flag(.result)) {
3537 param_inner := param_typ.clear_option_and_result()
3538 if param_inner.has_flag(.generic) {
3539 gt_name := g.table.sym(param_inner).name
3540 mut inferred_type := arg_typ.clear_option_and_result()
3541 if param_inner.nr_muls() > 0 && inferred_type.nr_muls() > 0 {
3542 inferred_type = inferred_type.set_nr_muls(0)
3543 }
3544 g.set_generic_call_concrete_type(generic_names, mut concrete_types, gt_name,
3545 inferred_type)
3546 }
3547 return
3548 }
3549 if param_typ.has_flag(.generic) && param_sym.name in generic_names {
3550 mut inferred_type := if arg_typ == ast.nil_type { ast.voidptr_type } else { arg_typ }
3551 mut strip_param_ptr_levels := true
3552 // `mut` lowers only the outer call argument to a pointer. Once inference
3553 // recurses through composite wrappers like `[]T`, nested generic types
3554 // should keep their original pointer indirection.
3555 if !from_composite && arg.is_mut && !param_typ.is_ptr() && inferred_type.is_ptr() {
3556 inferred_type = inferred_type.deref()
3557 }
3558 if arg.expr is ast.PrefixExpr && arg.expr.op == .amp && param_typ.nr_muls() > 0 {
3559 inner_type := g.resolved_expr_type(arg.expr.right, arg.expr.right_type)
3560 if inner_type != 0 {
3561 inferred_type = g.unwrap_generic(g.recheck_concrete_type(inner_type))
3562 if arg.expr.right.is_auto_deref_var() && inferred_type.is_ptr() {
3563 inferred_type = inferred_type.deref()
3564 }
3565 strip_param_ptr_levels = false
3566 }
3567 } else if arg.expr.is_auto_deref_var() && inferred_type.is_ptr() {
3568 inferred_type = inferred_type.deref()
3569 }
3570 if strip_param_ptr_levels && param_typ.nr_muls() > 0 && inferred_type.nr_muls() > 0 {
3571 param_muls := param_typ.nr_muls()
3572 arg_muls := inferred_type.nr_muls()