vxx / vlib / v3 / transform / monomorphize.v
3101 lines · 2969 sloc · 90.2 KB · 2b81918e62db9ab38787518603a7f93bee80868c
Raw
1module transform
2
3import v3.flat
4import v3.types
5
6struct GenericStructDecl {
7 id flat.NodeId
8 node flat.Node
9 file string
10 module string
11 key string
12}
13
14fn (mut t Transformer) is_generic_fn(name string) bool {
15 decls := t.cached_generic_fn_decls()
16 return name in decls || transform_qualified_fn_name(t.cur_module, name) in decls
17}
18
19fn (mut t Transformer) is_generic_struct(name string) bool {
20 base, _, ok := generic_app_parts(name)
21 if ok {
22 return base in t.structs
23 }
24 if info := t.lookup_struct_info(name) {
25 return info.name.contains('[')
26 }
27 return false
28}
29
30fn (mut t Transformer) monomorphize_pass() []string {
31 decls := t.cached_generic_fn_decls()
32 if decls.len == 0 {
33 return []string{}
34 }
35 struct_decls := t.collect_generic_struct_decls()
36 template_nodes := t.generic_decl_template_nodes(decls)
37 mut emitted := map[string]bool{}
38 mut generated := []string{}
39 mut changed := true
40 for changed {
41 changed = false
42 t.ensure_node_module_map()
43 mut cur_module := ''
44 node_count := t.a.nodes.len
45 for i in 0 .. node_count {
46 if template_nodes[i] {
47 continue
48 }
49 node := t.a.nodes[i]
50 match node.kind {
51 .module_decl {
52 cur_module = node.value
53 }
54 .call {
55 // An infix operator on a generic instance was already lowered to a
56 // direct call (`Vec_int__plus(a, b)`) before this pass. Record the
57 // callee so `specialize_generic_struct_methods` emits an operator
58 // overload only for instances whose operator is actually called.
59 t.record_called_fn_name(node)
60 call_module := t.node_module_map_cache[i] or { cur_module }
61 decl_key, args := t.generic_call_specialization(flat.NodeId(i), node,
62 call_module, decls) or { continue }
63 decl := decls[decl_key] or { continue }
64 if !t.call_has_source_generic_args(node)
65 && t.generic_args_contain_alias(args, decl.module) {
66 t.a.nodes[i].value = args.join(', ')
67 }
68 spec_key := generic_fn_spec_key(decl_key, args)
69 if emitted[spec_key] {
70 continue
71 }
72 generated << t.generated_fn_used_names(decl,
73 t.emit_generic_fn_specialization(decl, args), args)
74 emitted[spec_key] = true
75 changed = true
76 }
77 else {}
78 }
79 }
80 // Specialize methods of instantiated generic structs that are never reached
81 // through an explicit call node — notably operator overloads (`a + b`), which
82 // are infix expressions lowered to method calls only later in the pipeline.
83 if t.specialize_generic_struct_methods(struct_decls, decls, mut emitted, mut generated) {
84 changed = true
85 }
86 }
87 t.rewrite_generic_calls(decls, template_nodes)
88 t.erase_generic_fn_decls(decls)
89 return generated
90}
91
92// is_operator_method_name reports whether a method-name part is an overloaded
93// operator symbol (`+`, `-`, `*`, `/`, `%`, `==`, `<`, `>`, `<=`, `>=`).
94fn is_operator_method_name(name string) bool {
95 return name in ['+', '-', '*', '/', '%', '==', '!=', '<', '>', '<=', '>=']
96}
97
98// record_called_fn_name records the callee name of a direct call so operator overloads
99// (lowered to direct calls before this pass) can be specialized only when actually
100// called. Operator method names are mangled (`Vec_int__plus`), matching the name
101// `specialize_generic_struct_methods` would emit for that instance and operator.
102fn (mut t Transformer) record_called_fn_name(node flat.Node) {
103 if node.children_count < 1 {
104 return
105 }
106 fn_node := t.a.child_node(&node, 0)
107 if fn_node.kind == .ident && fn_node.value.len > 0 {
108 t.used_struct_operator_fns[fn_node.value] = true
109 }
110}
111
112// specialize_generic_struct_methods specializes every generic method of each
113// instantiated generic struct (e.g. for `Vec4[f32]`, generate `vec__Vec4_f32__plus`,
114// `vec__Vec4_f32__one`, ...). It only handles methods whose generic parameters are
115// exactly the struct's parameters (no extra method-level `[U]`); those are left to
116// the call-driven path. Returns whether any new specialization was emitted.
117fn (mut t Transformer) specialize_generic_struct_methods(struct_decls map[string]GenericStructDecl, decls map[string]GenericFnDecl, mut emitted map[string]bool, mut generated []string) bool {
118 mut specs := map[string]string{}
119 t.collect_generic_struct_specs(struct_decls, mut specs)
120 mut any := false
121 for spec, base in specs {
122 _, args, ok := generic_app_parts(spec)
123 if !ok || args.len == 0 {
124 continue
125 }
126 for decl_key, decl in decls {
127 if !decl_key.contains('.') || decl_key.all_before_last('.') != base {
128 continue
129 }
130 // Only operator overloads need struct-instantiation-driven specialization:
131 // they are reached through infix expressions, not call nodes. Regular
132 // methods are specialized on demand by the call-driven path, so emitting
133 // every method here would generate unused (and possibly unresolved) bodies.
134 // The exception is a method used as a *value* (`b.method`): it has no call
135 // node to drive specialization, so specialize the ones the checker recorded.
136 method := decl_key.all_after_last('.')
137 if is_operator_method_name(method) {
138 // Specialize an operator overload only for an instance whose operator is
139 // actually applied somewhere (recorded by record_used_struct_operator).
140 // Otherwise a stored-but-never-operated instance whose type argument does
141 // not support the operation would emit a body that fails C compilation.
142 if c_name('${spec}.${method}') !in t.used_struct_operator_fns {
143 continue
144 }
145 } else {
146 mvkey := '${spec}.${method}'
147 if isnil(t.tc) || mvkey !in t.tc.generic_method_value_info {
148 continue
149 }
150 // Only specialize a method value the checker recorded inside a *reachable*
151 // function: markused seeds the concrete instance key (`Box[int].report`) into
152 // `used_fns` per reachable function, so one used only in dead code is skipped —
153 // its body may be invalid for that type argument and would fail C compilation.
154 if t.used_fns.len > 0 && mvkey !in t.used_fns && c_name(mvkey) !in t.used_fns {
155 continue
156 }
157 }
158 if decl.node.generic_params.len != 0 {
159 // Method has its own generic parameters beyond the struct's; leave it
160 // to the call-driven specialization which can infer them.
161 continue
162 }
163 spec_key := generic_fn_spec_key(decl_key, args)
164 if emitted[spec_key] {
165 continue
166 }
167 generated << t.generated_fn_used_names(decl,
168 t.emit_generic_fn_specialization(decl, args), args)
169 emitted[spec_key] = true
170 any = true
171 }
172 }
173 return any
174}
175
176fn (mut t Transformer) materialize_generic_structs() {
177 if isnil(t.tc) {
178 return
179 }
180 decls := t.collect_generic_struct_decls()
181 if decls.len == 0 {
182 return
183 }
184 mut specs := map[string]string{}
185 t.collect_generic_struct_specs(decls, mut specs)
186 for _ in 0 .. 20 {
187 before := specs.len
188 current := specs.clone()
189 for spec, base in current {
190 decl := decls[base] or { continue }
191 _, args, ok := generic_app_parts(spec)
192 if !ok {
193 continue
194 }
195 for i in 0 .. decl.node.children_count {
196 field := t.a.child_node(&decl.node, i)
197 if field.kind != .field_decl {
198 continue
199 }
200 field_type := substitute_generic_type_text_with_params(field.typ, args,
201 decl.node.generic_params)
202 t.collect_generic_struct_spec_from_type(field_type, decl.module, decl.file, decls, mut
203 specs)
204 }
205 }
206 if specs.len == before {
207 break
208 }
209 }
210 for spec, base in specs {
211 decl := decls[base] or { continue }
212 t.materialize_generic_struct_spec(spec, decl)
213 }
214 for _, decl in decls {
215 t.tc.structs.delete(decl.key)
216 t.tc.unions.delete(decl.key)
217 t.tc.params_structs.delete(decl.key)
218 }
219}
220
221fn (mut t Transformer) collect_generic_struct_decls() map[string]GenericStructDecl {
222 mut decls := map[string]GenericStructDecl{}
223 t.ensure_node_module_map()
224 mut cur_file := ''
225 mut cur_module := ''
226 for i, node in t.a.nodes {
227 match node.kind {
228 .file {
229 cur_file = node.value
230 }
231 .module_decl {
232 cur_module = node.value
233 }
234 .struct_decl {
235 if node.generic_params.len == 0 && !node.typ.contains('generic') {
236 continue
237 }
238 module_name := t.node_module_map_cache[i] or { cur_module }
239 key := generic_struct_decl_key(node.value, module_name)
240 decls[key] = GenericStructDecl{
241 id: flat.NodeId(i)
242 node: node
243 file: cur_file
244 module: module_name
245 key: key
246 }
247 }
248 else {}
249 }
250 }
251 return decls
252}
253
254fn generic_struct_decl_key(name string, module_name string) string {
255 if name.contains('.') || module_name.len == 0 || module_name == 'main'
256 || module_name == 'builtin' {
257 return name
258 }
259 return '${module_name}.${name}'
260}
261
262fn (mut t Transformer) collect_generic_struct_specs(decls map[string]GenericStructDecl, mut specs map[string]string) {
263 for _, target in t.tc.type_aliases {
264 t.collect_generic_struct_spec_from_type(target, '', '', decls, mut specs)
265 }
266 mut file_name := ''
267 mut module_name := ''
268 for node in t.a.nodes {
269 match node.kind {
270 .file {
271 file_name = node.value
272 module_name = ''
273 }
274 .module_decl {
275 module_name = node.value
276 }
277 else {}
278 }
279
280 if node.typ.len > 0 {
281 t.collect_generic_struct_spec_from_type(node.typ, module_name, file_name, decls, mut
282 specs)
283 }
284 match node.kind {
285 .struct_init, .array_init, .cast_expr, .as_expr, .sizeof_expr, .typeof_expr, .is_expr {
286 t.collect_generic_struct_spec_from_type(node.value, module_name, file_name, decls, mut
287 specs)
288 }
289 else {}
290 }
291 }
292}
293
294fn (mut t Transformer) collect_generic_struct_spec_from_type(typ string, module_name string, file_name string, decls map[string]GenericStructDecl, mut specs map[string]string) {
295 clean := typ.trim_space()
296 if clean.len == 0 {
297 return
298 }
299 if clean.starts_with('&') {
300 t.collect_generic_struct_spec_from_type(clean[1..], module_name, file_name, decls, mut
301 specs)
302 return
303 }
304 if clean.starts_with('mut ') {
305 t.collect_generic_struct_spec_from_type(clean[4..], module_name, file_name, decls, mut
306 specs)
307 return
308 }
309 if clean.starts_with('?') || clean.starts_with('!') {
310 t.collect_generic_struct_spec_from_type(clean[1..], module_name, file_name, decls, mut
311 specs)
312 return
313 }
314 if clean.starts_with('...') {
315 t.collect_generic_struct_spec_from_type(clean[3..], module_name, file_name, decls, mut
316 specs)
317 return
318 }
319 if clean.starts_with('[]') {
320 t.collect_generic_struct_spec_from_type(clean[2..], module_name, file_name, decls, mut
321 specs)
322 return
323 }
324 if clean.starts_with('map[') {
325 bracket_end := generic_matching_bracket(clean, 3)
326 if bracket_end < clean.len {
327 t.collect_generic_struct_spec_from_type(clean[4..bracket_end], module_name, file_name,
328 decls, mut specs)
329 t.collect_generic_struct_spec_from_type(clean[bracket_end + 1..], module_name,
330 file_name, decls, mut specs)
331 }
332 return
333 }
334 if clean.starts_with('[') {
335 bracket_end := generic_matching_bracket(clean, 0)
336 if bracket_end < clean.len {
337 t.collect_generic_struct_spec_from_type(clean[bracket_end + 1..], module_name,
338 file_name, decls, mut specs)
339 }
340 return
341 }
342 base, args, ok := generic_app_parts(clean)
343 if !ok {
344 return
345 }
346 for arg in args {
347 t.collect_generic_struct_spec_from_type(arg, module_name, file_name, decls, mut specs)
348 }
349 if t.generic_args_have_placeholders(args) {
350 return
351 }
352 spec_base := t.generic_struct_spec_base_name(base, module_name, file_name, decls) or { return }
353 spec_name := '${spec_base}[${args.join(', ')}]'
354 specs[spec_name] = spec_base
355}
356
357fn (t &Transformer) generic_struct_spec_base_name(base string, module_name string, file_name string, decls map[string]GenericStructDecl) ?string {
358 if base in decls {
359 return base
360 }
361 if base.contains('.') {
362 return none
363 }
364 if module_name.len > 0 && module_name != 'main' && module_name != 'builtin' {
365 qbase := '${module_name}.${base}'
366 if qbase in decls {
367 return qbase
368 }
369 }
370 if resolved := t.selective_import_generic_struct_base(base, file_name, decls) {
371 return resolved
372 }
373 mut found := ''
374 for key, _ in decls {
375 if key.all_after_last('.') == base {
376 if found.len > 0 && found != key {
377 return none
378 }
379 found = key
380 }
381 }
382 if found.len > 0 {
383 return found
384 }
385 return none
386}
387
388fn (t &Transformer) selective_import_generic_struct_base(base string, file_name string, decls map[string]GenericStructDecl) ?string {
389 if isnil(t.tc) || base.contains('.') || file_name.len == 0 {
390 return none
391 }
392 candidates := t.tc.file_selective_imports[file_import_key(file_name, base)] or { return none }
393 for candidate in candidates {
394 if candidate in decls {
395 return candidate
396 }
397 }
398 return none
399}
400
401fn (mut t Transformer) materialize_generic_struct_spec(spec_name string, decl GenericStructDecl) {
402 _, args, ok := generic_app_parts(spec_name)
403 if !ok || args.len == 0 {
404 return
405 }
406 old_module := t.cur_module
407 old_file := t.cur_file
408 old_tc_module := t.tc.cur_module
409 old_tc_file := t.tc.cur_file
410 t.cur_module = decl.module
411 t.cur_file = decl.file
412 t.tc.cur_module = decl.module
413 t.tc.cur_file = decl.file
414 mut fields := []types.StructField{}
415 for i in 0 .. decl.node.children_count {
416 field := t.a.child_node(&decl.node, i)
417 if field.kind != .field_decl {
418 continue
419 }
420 field_type := substitute_generic_type_text_with_params(field.typ, args,
421 decl.node.generic_params)
422 fields << types.StructField{
423 name: field.value
424 typ: t.tc.parse_type(field_type)
425 }
426 }
427 t.tc.structs[spec_name] = fields
428 if decl.key in t.tc.unions {
429 t.tc.unions[spec_name] = true
430 }
431 if decl.key in t.tc.params_structs {
432 t.tc.params_structs[spec_name] = true
433 }
434 t.cur_module = old_module
435 t.cur_file = old_file
436 t.tc.cur_module = old_tc_module
437 t.tc.cur_file = old_tc_file
438}
439
440fn (mut t Transformer) collect_generic_fn_decls() map[string]GenericFnDecl {
441 mut decls := map[string]GenericFnDecl{}
442 t.ensure_node_module_map()
443 mut cur_file := ''
444 mut cur_module := ''
445 for i, node in t.a.nodes {
446 match node.kind {
447 .file {
448 cur_file = node.value
449 }
450 .module_decl {
451 cur_module = node.value
452 }
453 .fn_decl {
454 fn_module := t.node_module_map_cache[i] or { cur_module }
455 if !t.fn_decl_has_unresolved_generics(node, fn_module) {
456 continue
457 }
458 key := t.generic_fn_decl_key(node, fn_module)
459 decls[key] = GenericFnDecl{
460 id: flat.NodeId(i)
461 node: node
462 file: cur_file
463 module: fn_module
464 key: key
465 }
466 }
467 else {}
468 }
469 }
470 return decls
471}
472
473fn (mut t Transformer) generic_decl_template_nodes(decls map[string]GenericFnDecl) map[int]bool {
474 mut nodes := map[int]bool{}
475 for _, decl in decls {
476 t.collect_node_subtree_ids(decl.id, mut nodes)
477 }
478 return nodes
479}
480
481fn (mut t Transformer) ensure_node_module_map() {
482 if t.node_module_map_nodes == t.a.nodes.len {
483 return
484 }
485 mut modules := map[int]string{}
486 mut cur_module := ''
487 for i, node in t.a.nodes {
488 match node.kind {
489 .module_decl {
490 cur_module = node.value
491 }
492 .fn_decl, .const_decl, .global_decl, .struct_decl, .type_decl, .enum_decl,
493 .interface_decl {
494 t.mark_node_module(flat.NodeId(i), cur_module, mut modules)
495 }
496 else {}
497 }
498 }
499 t.node_module_map_cache = modules.move()
500 t.node_module_map_nodes = t.a.nodes.len
501}
502
503fn (mut t Transformer) mark_node_module(id flat.NodeId, module_name string, mut modules map[int]string) {
504 idx := int(id)
505 if idx < 0 || idx >= t.a.nodes.len || idx in modules {
506 return
507 }
508 modules[idx] = module_name
509 node := t.a.nodes[idx]
510 for i in 0 .. node.children_count {
511 t.mark_node_module(t.a.child(&node, i), module_name, mut modules)
512 }
513}
514
515fn (mut t Transformer) collect_node_subtree_ids(id flat.NodeId, mut nodes map[int]bool) {
516 if int(id) < 0 || int(id) >= t.a.nodes.len || nodes[int(id)] {
517 return
518 }
519 nodes[int(id)] = true
520 node := t.a.nodes[int(id)]
521 for i in 0 .. node.children_count {
522 t.collect_node_subtree_ids(t.a.child(&node, i), mut nodes)
523 }
524}
525
526fn (mut t Transformer) emit_generic_fn_specialization(decl GenericFnDecl, args []string) flat.NodeId {
527 old_module := t.cur_module
528 old_file := t.cur_file
529 old_tc_module := if isnil(t.tc) { '' } else { t.tc.cur_module }
530 old_tc_file := if isnil(t.tc) { '' } else { t.tc.cur_file }
531 t.cur_module = decl.module
532 t.cur_file = decl.file
533 if !isnil(t.tc) {
534 t.tc.cur_module = decl.module
535 t.tc.cur_file = decl.file
536 }
537 if decl.module.len > 0 {
538 t.a.add_node(flat.Node{
539 kind: .module_decl
540 value: decl.module
541 })
542 }
543 old_params := t.active_generic_params
544 t.active_generic_params = t.generic_fn_param_names(decl.node, decl.module)
545 clone_id := t.clone_generic_fn_node(decl.node, args)
546 t.specialize_cloned_fn_signature(clone_id, decl, args)
547 clone := t.a.nodes[int(clone_id)]
548 t.register_specialized_fn_signature(decl, clone, args)
549 t.active_generic_params = old_params
550 t.transform_specialized_fn_body(clone_id, decl.module, decl.file)
551 t.cur_module = old_module
552 t.cur_file = old_file
553 if !isnil(t.tc) {
554 t.tc.cur_module = old_tc_module
555 t.tc.cur_file = old_tc_file
556 }
557 return clone_id
558}
559
560fn (mut t Transformer) transform_specialized_fn_body(clone_id flat.NodeId, module_name string, file_name string) {
561 if int(clone_id) < 0 || int(clone_id) >= t.a.nodes.len {
562 return
563 }
564 old_module := t.cur_module
565 old_file := t.cur_file
566 old_tc_file := if isnil(t.tc) { '' } else { t.tc.cur_file }
567 old_fn_name := t.cur_fn_name
568 old_ret_type := t.cur_fn_ret_type
569 old_var_types := t.var_types.clone()
570 old_is_generic := t.cur_fn_is_generic
571 t.cur_module = module_name
572 t.cur_file = file_name
573 if !isnil(t.tc) {
574 t.tc.cur_file = file_name
575 }
576 t.transform_fn_body(int(clone_id))
577 t.cur_module = old_module
578 t.cur_file = old_file
579 if !isnil(t.tc) {
580 t.tc.cur_file = old_tc_file
581 }
582 t.cur_fn_name = old_fn_name
583 t.cur_fn_ret_type = old_ret_type
584 t.var_types = old_var_types
585 t.cur_fn_is_generic = old_is_generic
586}
587
588fn (mut t Transformer) generated_fn_used_names(decl GenericFnDecl, clone_id flat.NodeId, args []string) []string {
589 if int(clone_id) < 0 || int(clone_id) >= t.a.nodes.len {
590 return []string{}
591 }
592 clone := t.a.nodes[int(clone_id)]
593 qname := transform_qualified_fn_name(decl.module, clone.value)
594 mut names := [clone.value, qname, c_name(clone.value), c_name(qname)]
595 names << specialized_generic_fn_signature_aliases(decl, args)
596 return names
597}
598
599fn (mut t Transformer) specialize_cloned_fn_signature(clone_id flat.NodeId, decl GenericFnDecl, args []string) {
600 if int(clone_id) < 0 || int(clone_id) >= t.a.nodes.len {
601 return
602 }
603 params := t.generic_fn_param_names(decl.node, decl.module)
604 t.a.nodes[int(clone_id)].typ = t.specialized_signature_type_text(decl, decl.node.typ, args,
605 params)
606 t.a.nodes[int(clone_id)].generic_params = []string{}
607 mut dst_params := []flat.NodeId{}
608 clone := t.a.nodes[int(clone_id)]
609 for i in 0 .. clone.children_count {
610 dst_id := t.a.child(&clone, i)
611 if t.a.nodes[int(dst_id)].kind == .param {
612 dst_params << dst_id
613 }
614 }
615 mut param_idx := 0
616 for i in 0 .. decl.node.children_count {
617 src := t.a.child_node(&decl.node, i)
618 if src.kind != .param {
619 continue
620 }
621 if param_idx >= dst_params.len {
622 continue
623 }
624 dst_id := dst_params[param_idx]
625 t.a.nodes[int(dst_id)].typ = t.specialized_signature_type_text(decl, src.typ, args, params)
626 param_idx++
627 }
628}
629
630fn (mut t Transformer) register_specialized_fn_signature(decl GenericFnDecl, clone flat.Node, args []string) {
631 old_module := t.cur_module
632 old_file := t.cur_file
633 old_tc_module := if isnil(t.tc) { '' } else { t.tc.cur_module }
634 old_tc_file := if isnil(t.tc) { '' } else { t.tc.cur_file }
635 t.cur_module = decl.module
636 t.cur_file = decl.file
637 if !isnil(t.tc) {
638 t.tc.cur_module = decl.module
639 t.tc.cur_file = decl.file
640 }
641 generic_params := t.generic_fn_param_names(decl.node, decl.module)
642 ret_name := t.specialized_signature_type_text(decl, decl.node.typ, args, generic_params)
643 ret := if !isnil(t.tc) { t.tc.parse_type(ret_name) } else { types.Type(types.void_) }
644 mut params := []types.Type{}
645 mut variadic := false
646 for i in 0 .. decl.node.children_count {
647 child := t.a.child_node(&decl.node, i)
648 if child.kind != .param {
649 continue
650 }
651 param_type := t.specialized_signature_type_text(decl, child.typ, args, generic_params)
652 if param_type.starts_with('...') {
653 variadic = true
654 }
655 if !isnil(t.tc) {
656 params << t.tc.parse_type(param_type)
657 }
658 }
659 qname := transform_qualified_fn_name(decl.module, clone.value)
660 t.fn_ret_types[clone.value] = ret_name
661 t.fn_ret_types[qname] = ret_name
662 if !isnil(t.tc) {
663 mut names := [clone.value, qname, c_name(clone.value),
664 c_name(qname)]
665 names << specialized_generic_fn_signature_aliases(decl, args)
666 for name in names {
667 t.tc.fn_ret_types[name] = ret
668 t.tc.fn_param_types[name] = params.clone()
669 t.tc.fn_variadic[name] = variadic
670 }
671 t.tc.cur_module = old_tc_module
672 t.tc.cur_file = old_tc_file
673 }
674 t.cur_module = old_module
675 t.cur_file = old_file
676}
677
678fn (mut t Transformer) specialized_fn_return_type_text(decl GenericFnDecl, args []string) string {
679 return t.specialized_signature_type_text(decl, decl.node.typ, args, t.generic_fn_param_names(decl.node,
680 decl.module))
681}
682
683fn (mut t Transformer) specialized_signature_type_text(decl GenericFnDecl, typ string, args []string, params []string) string {
684 substituted := substitute_generic_type_text_with_params(typ, args, params)
685 qualified := t.qualify_specialized_signature_type_text(substituted, decl)
686 if isnil(t.tc) {
687 return qualified
688 }
689 old_module := t.cur_module
690 old_file := t.cur_file
691 old_tc_module := t.tc.cur_module
692 old_tc_file := t.tc.cur_file
693 t.cur_module = decl.module
694 t.cur_file = decl.file
695 t.tc.cur_module = decl.module
696 t.tc.cur_file = decl.file
697 parsed := t.tc.parse_type(qualified)
698 t.cur_module = old_module
699 t.cur_file = old_file
700 t.tc.cur_module = old_tc_module
701 t.tc.cur_file = old_tc_file
702 if parsed is types.Unknown {
703 return qualified
704 }
705 return parsed.name()
706}
707
708fn (t &Transformer) qualify_specialized_signature_type_text(typ string, decl GenericFnDecl) string {
709 clean := typ.trim_space()
710 if clean.len == 0 || isnil(t.tc) {
711 return typ
712 }
713 if clean.starts_with('&') {
714 return '&' + t.qualify_specialized_signature_type_text(clean[1..], decl)
715 }
716 if clean.starts_with('mut ') {
717 inner := t.qualify_specialized_signature_type_text(clean[4..], decl)
718 if inner.starts_with('&') {
719 return inner
720 }
721 return '&' + inner
722 }
723 if clean.starts_with('?') {
724 return '?' + t.qualify_specialized_signature_type_text(clean[1..], decl)
725 }
726 if clean.starts_with('!') {
727 return '!' + t.qualify_specialized_signature_type_text(clean[1..], decl)
728 }
729 if clean.starts_with('...') {
730 return '...' + t.qualify_specialized_signature_type_text(clean[3..], decl)
731 }
732 if clean.starts_with('[]') {
733 return '[]' + t.qualify_specialized_signature_type_text(clean[2..], decl)
734 }
735 if clean.starts_with('map[') {
736 bracket_end := generic_matching_bracket(clean, 3)
737 if bracket_end < clean.len {
738 key := t.qualify_specialized_signature_type_text(clean[4..bracket_end], decl)
739 val := t.qualify_specialized_signature_type_text(clean[bracket_end + 1..], decl)
740 return 'map[${key}]${val}'
741 }
742 }
743 if clean.starts_with('[') {
744 bracket_end := generic_matching_bracket(clean, 0)
745 if bracket_end < clean.len {
746 return clean[..bracket_end + 1] +
747 t.qualify_specialized_signature_type_text(clean[bracket_end + 1..], decl)
748 }
749 }
750 if clean.starts_with('(') && clean.ends_with(')') && clean.contains(',') {
751 mut parts := []string{}
752 for part in split_generic_args(clean[1..clean.len - 1]) {
753 parts << t.qualify_specialized_signature_type_text(part, decl)
754 }
755 return '(' + parts.join(', ') + ')'
756 }
757 bracket := clean.index_u8(`[`)
758 if bracket > 0 {
759 bracket_end := generic_matching_bracket(clean, bracket)
760 if bracket_end < clean.len {
761 mut parts := []string{}
762 for part in split_generic_args(clean[bracket + 1..bracket_end]) {
763 parts << t.qualify_specialized_signature_type_text(part, decl)
764 }
765 base := t.qualify_specialized_signature_type_text(clean[..bracket], decl)
766 return base + '[' + parts.join(', ') + ']' + clean[bracket_end + 1..]
767 }
768 }
769 if clean.contains('.') || types.is_builtin_type_name(clean)
770 || clean in ['void', 'none', 'nil', 'C', 'JS'] {
771 return clean
772 }
773 return t.selective_signature_type_symbol(decl.file, clean) or { clean }
774}
775
776fn (t &Transformer) selective_signature_type_symbol(file string, name string) ?string {
777 if isnil(t.tc) || file.len == 0 || name.contains('.') {
778 return none
779 }
780 candidates := t.tc.file_selective_imports[file_import_key(file, name)] or { return none }
781 for candidate in candidates {
782 if candidate in t.tc.type_aliases || candidate in t.tc.structs
783 || candidate in t.tc.interface_names || candidate in t.tc.flag_enums
784 || candidate in t.tc.enum_names || candidate in t.tc.sum_types {
785 return candidate
786 }
787 }
788 return none
789}
790
791fn specialized_generic_fn_signature_aliases(decl GenericFnDecl, args []string) []string {
792 if !decl.node.value.contains('.') {
793 return []string{}
794 }
795 receiver := generic_fn_decl_base_value(decl.node.value).all_before_last('.')
796 method := decl.node.value.all_after_last('.')
797 if receiver.len == 0 || method.len == 0 {
798 return []string{}
799 }
800 flat_receiver := '${receiver}_${generic_type_suffixes(args)}'
801 qflat_receiver := transform_qualified_fn_name(decl.module, flat_receiver)
802 return [
803 '${flat_receiver}.${method}',
804 '${qflat_receiver}.${method}',
805 c_name('${flat_receiver}.${method}'),
806 c_name('${qflat_receiver}.${method}'),
807 '${c_name(flat_receiver)}__${c_name(method)}',
808 c_name('${decl.module}.${flat_receiver}.${method}'),
809 ]
810}
811
812fn (mut t Transformer) rewrite_generic_calls(decls map[string]GenericFnDecl, template_nodes map[int]bool) {
813 t.ensure_node_module_map()
814 mut cur_module := ''
815 for i in 0 .. t.a.nodes.len {
816 if template_nodes[i] {
817 continue
818 }
819 node := t.a.nodes[i]
820 match node.kind {
821 .module_decl {
822 cur_module = node.value
823 }
824 .call {
825 call_module := t.node_module_map_cache[i] or { cur_module }
826 decl_key, args := t.generic_call_specialization(flat.NodeId(i), node, call_module,
827 decls) or { continue }
828 decl := decls[decl_key] or { continue }
829 if !t.call_has_source_generic_args(node)
830 && t.generic_args_contain_alias(args, decl.module) {
831 t.a.nodes[i].value = args.join(', ')
832 }
833 if t.generic_decl_is_receiver_method(decl.node) {
834 t.rewrite_generic_method_call(flat.NodeId(i), node, decl, args)
835 } else {
836 t.rewrite_generic_plain_call(flat.NodeId(i), node, decl, args)
837 }
838 }
839 else {}
840 }
841 }
842}
843
844fn (mut t Transformer) concrete_generic_call_return_type(id flat.NodeId, node flat.Node) string {
845 if node.kind != .call || node.children_count == 0 {
846 return ''
847 }
848 decls := t.cached_generic_fn_decls()
849 if decls.len == 0 {
850 return ''
851 }
852 decl_key := t.generic_call_decl_key(id, node, t.cur_module, decls) or { return '' }
853 decl := decls[decl_key] or { return '' }
854 if t.should_skip_generic_call_specialization(decl_key) {
855 return ''
856 }
857 mut args := []string{}
858 if explicit := t.explicit_generic_call_args(node, t.cur_module) {
859 args = explicit.clone()
860 } else {
861 args = t.infer_generic_call_args_from_params(decl, node) or { return '' }
862 }
863 if args.len == 0 || t.generic_args_have_placeholders(args) {
864 return ''
865 }
866 ret := t.specialized_fn_return_type_text(decl, args)
867 if ret.len == 0 || t.generic_arg_is_unresolved(ret) {
868 return ''
869 }
870 return t.normalize_type_alias(ret)
871}
872
873fn (mut t Transformer) concrete_generic_call_param_types(id flat.NodeId, node flat.Node) ?[]types.Type {
874 if node.kind != .call || node.children_count == 0 || isnil(t.tc) {
875 return none
876 }
877 decls := t.cached_generic_fn_decls()
878 if decls.len == 0 {
879 return none
880 }
881 decl_key := t.generic_call_decl_key(id, node, t.cur_module, decls) or { return none }
882 decl := decls[decl_key] or { return none }
883 if t.should_skip_generic_call_specialization(decl_key) {
884 return none
885 }
886 mut args := []string{}
887 if explicit := t.explicit_generic_call_args(node, t.cur_module) {
888 args = explicit.clone()
889 } else {
890 args = t.infer_generic_call_args_from_params(decl, node) or { return none }
891 }
892 if args.len == 0 || t.generic_args_have_placeholders(args) {
893 return none
894 }
895 params := t.generic_fn_param_names(decl.node, decl.module)
896 mut result := []types.Type{}
897 for i in 0 .. decl.node.children_count {
898 child := t.a.child_node(&decl.node, i)
899 if child.kind != .param {
900 continue
901 }
902 param_type := t.specialized_signature_type_text(decl, child.typ, args, params)
903 result << t.tc.parse_type(param_type)
904 }
905 if result.len == 0 {
906 return none
907 }
908 return result
909}
910
911fn (mut t Transformer) cached_generic_fn_decls() map[string]GenericFnDecl {
912 if !t.generic_fn_decls_ready {
913 t.generic_fn_decls_cache = t.collect_generic_fn_decls()
914 t.generic_fn_decls_ready = true
915 }
916 return t.generic_fn_decls_cache
917}
918
919fn (mut t Transformer) infer_generic_call_args_from_params(decl GenericFnDecl, node flat.Node) ?[]string {
920 param_names := t.generic_fn_param_names(decl.node, decl.module)
921 if param_names.len == 0 {
922 return none
923 }
924 is_receiver := t.generic_decl_is_receiver_method(decl.node)
925 mut inferred := map[string]string{}
926 mut param_idx := 0
927 for i in 0 .. decl.node.children_count {
928 child := t.a.child_node(&decl.node, i)
929 if child.kind != .param {
930 continue
931 }
932 is_recv_param := is_receiver && param_idx == 0
933 arg_id := t.generic_call_arg_id_for_param(node, param_idx, is_receiver) or {
934 param_idx++
935 continue
936 }
937 arg_type := t.generic_call_arg_type_for_inference(arg_id)
938 if arg_type.len > 0 {
939 infer_generic_type_args(child.typ, arg_type, mut inferred)
940 if is_recv_param {
941 t.infer_generic_receiver_suffix_args(child.typ, arg_type, mut inferred)
942 t.infer_generic_embedded_receiver_args(child.typ, arg_type, mut inferred)
943 }
944 }
945 param_idx++
946 }
947 mut args := []string{cap: param_names.len}
948 for name in param_names {
949 arg := inferred[name] or { return none }
950 args << t.generic_arg_for_decl_module(arg, decl.module)
951 }
952 return args
953}
954
955fn (mut t Transformer) rewrite_generic_plain_call(id flat.NodeId, node flat.Node, decl GenericFnDecl, args []string) {
956 spec_value := specialized_generic_fn_value(decl.node.value, args)
957 spec_name := transform_qualified_fn_name(decl.module, spec_value)
958 ret_typ := t.specialized_fn_return_type_text(decl, args)
959 param_types := t.specialized_generic_call_param_type_texts(decl, args)
960 mut children := []flat.NodeId{cap: int(node.children_count)}
961 children << t.make_ident(spec_name)
962 for i in 1 .. node.children_count {
963 arg_id := t.a.child(&node, i)
964 param_idx := i - 1
965 param_type := if param_idx < param_types.len { param_types[param_idx] } else { '' }
966 children << t.retype_generic_call_literal_arg(arg_id, param_type)
967 }
968 start := t.a.children.len
969 for child in children {
970 t.a.children << child
971 }
972 t.a.nodes[int(id)] = flat.Node{
973 kind: .call
974 op: node.op
975 children_start: start
976 children_count: flat.child_count(children.len)
977 pos: node.pos
978 value: ''
979 typ: ret_typ
980 }
981 t.clear_resolved_call(id)
982}
983
984fn (mut t Transformer) specialized_generic_call_param_type_texts(decl GenericFnDecl, args []string) []string {
985 params := t.generic_fn_param_names(decl.node, decl.module)
986 mut result := []string{}
987 for i in 0 .. decl.node.children_count {
988 child := t.a.child_node(&decl.node, i)
989 if child.kind != .param {
990 continue
991 }
992 result << t.specialized_call_target_type_text(decl, child.typ, args, params)
993 }
994 return result
995}
996
997fn (mut t Transformer) specialized_call_target_type_text(decl GenericFnDecl, typ string, args []string, params []string) string {
998 substituted := substitute_generic_type_text_with_params(typ, args, params)
999 return t.qualify_specialized_signature_type_text(substituted, decl)
1000}
1001
1002fn (mut t Transformer) retype_generic_call_literal_arg(arg_id flat.NodeId, param_type string) flat.NodeId {
1003 if int(arg_id) < 0 || param_type.len == 0 {
1004 return arg_id
1005 }
1006 node := t.a.nodes[int(arg_id)]
1007 if node.kind == .array_literal
1008 && t.generic_call_array_literal_can_retype_inline(node, param_type) {
1009 return t.transform_expr_for_type(arg_id, param_type)
1010 }
1011 if node.kind == .ident && node.value.contains('arr_lit') && node.typ.starts_with('[]')
1012 && param_type.starts_with('[]') && node.typ != param_type {
1013 if t.retype_lowered_array_literal_temp(node.value, param_type) {
1014 t.a.nodes[int(arg_id)].typ = param_type
1015 t.set_var_type(node.value, param_type)
1016 }
1017 }
1018 return arg_id
1019}
1020
1021fn (t &Transformer) generic_call_array_literal_can_retype_inline(node flat.Node, param_type string) bool {
1022 if !param_type.starts_with('[]') {
1023 return false
1024 }
1025 for i in 0 .. node.children_count {
1026 child := t.a.child_node(&node, i)
1027 if child.kind !in [.int_literal, .float_literal, .bool_literal, .char_literal,
1028 .string_literal, .cast_expr, .as_expr] {
1029 return false
1030 }
1031 }
1032 return true
1033}
1034
1035fn (mut t Transformer) retype_lowered_array_literal_temp(name string, array_type string) bool {
1036 if !array_type.starts_with('[]') {
1037 return false
1038 }
1039 elem_type := array_type[2..]
1040 mut changed := false
1041 for i in 0 .. t.a.nodes.len {
1042 node := t.a.nodes[i]
1043 if node.kind == .decl_assign && node.children_count >= 2 {
1044 lhs_id := t.a.child(&node, 0)
1045 lhs := t.a.nodes[int(lhs_id)]
1046 if lhs.kind == .ident && lhs.value == name {
1047 rhs_id := t.a.child(&node, 1)
1048 t.a.nodes[i].typ = array_type
1049 t.a.nodes[int(lhs_id)].typ = array_type
1050 t.set_var_type(name, array_type)
1051 t.retype_array_new_call(rhs_id, elem_type, array_type)
1052 changed = true
1053 }
1054 }
1055 if node.kind == .call && t.call_is_array_push_to_name(node, name) {
1056 value_name := t.array_push_value_name(node) or { continue }
1057 if t.retype_decl_assign_name(value_name, elem_type) {
1058 changed = true
1059 }
1060 }
1061 }
1062 return changed
1063}
1064
1065fn (mut t Transformer) retype_array_new_call(call_id flat.NodeId, elem_type string, array_type string) {
1066 if int(call_id) < 0 || int(call_id) >= t.a.nodes.len {
1067 return
1068 }
1069 call := t.a.nodes[int(call_id)]
1070 if call.kind != .call || call.children_count < 2 {
1071 return
1072 }
1073 callee := t.a.child_node(&call, 0)
1074 if callee.kind != .ident || callee.value != 'array_new' {
1075 return
1076 }
1077 sizeof_id := t.a.child(&call, 1)
1078 if int(sizeof_id) >= 0 && int(sizeof_id) < t.a.nodes.len {
1079 if t.a.nodes[int(sizeof_id)].kind == .sizeof_expr {
1080 t.a.nodes[int(sizeof_id)].value = elem_type
1081 }
1082 }
1083 t.a.nodes[int(call_id)].typ = array_type
1084}
1085
1086fn (t &Transformer) call_is_array_push_to_name(node flat.Node, name string) bool {
1087 if node.children_count < 3 {
1088 return false
1089 }
1090 callee := t.a.child_node(&node, 0)
1091 if callee.kind != .ident || callee.value != 'array_push' {
1092 return false
1093 }
1094 arg := t.a.child_node(&node, 1)
1095 if arg.kind != .prefix || arg.children_count == 0 {
1096 return false
1097 }
1098 base := t.a.child_node(arg, 0)
1099 return base.kind == .ident && base.value == name
1100}
1101
1102fn (t &Transformer) array_push_value_name(node flat.Node) ?string {
1103 if node.children_count < 3 {
1104 return none
1105 }
1106 arg := t.a.child_node(&node, 2)
1107 if arg.kind != .prefix || arg.children_count == 0 {
1108 return none
1109 }
1110 base := t.a.child_node(arg, 0)
1111 if base.kind != .ident || base.value.len == 0 {
1112 return none
1113 }
1114 return base.value
1115}
1116
1117fn (mut t Transformer) retype_decl_assign_name(name string, typ string) bool {
1118 mut changed := false
1119 for i in 0 .. t.a.nodes.len {
1120 node := t.a.nodes[i]
1121 if node.kind != .decl_assign || node.children_count < 1 {
1122 continue
1123 }
1124 lhs_id := t.a.child(&node, 0)
1125 lhs := t.a.nodes[int(lhs_id)]
1126 if lhs.kind != .ident || lhs.value != name {
1127 continue
1128 }
1129 t.a.nodes[i].typ = typ
1130 t.a.nodes[int(lhs_id)].typ = typ
1131 t.set_var_type(name, typ)
1132 changed = true
1133 }
1134 return changed
1135}
1136
1137// call_is_selector_form reports whether a call node embeds its receiver inside the
1138// callee (`recv.method(args)`) rather than passing it as an explicit child
1139// (`Type.method(recv, args)`, the ident-lowered form).
1140fn (t &Transformer) call_is_selector_form(node flat.Node) bool {
1141 if node.children_count == 0 {
1142 return false
1143 }
1144 mut callee := t.a.nodes[int(t.a.child(&node, 0))]
1145 if callee.kind == .index && callee.children_count > 0 {
1146 callee = t.a.nodes[int(t.a.child(&callee, 0))]
1147 }
1148 return callee.kind == .selector
1149}
1150
1151fn (mut t Transformer) rewrite_generic_method_call(id flat.NodeId, node flat.Node, decl GenericFnDecl, args []string) {
1152 if node.children_count == 0 {
1153 return
1154 }
1155 // Method-level generics (`method[U](...)`) cannot be resolved from the receiver
1156 // type alone — the receiver carries no `_U` suffix — so the call must name the
1157 // specialized function explicitly, passing the receiver as the first argument
1158 // (exactly like a plain generic call). Pure struct-generic methods keep the
1159 // selector callee, which cgen resolves via the already-monomorphized receiver.
1160 if t.generic_decl_has_method_level_params(decl) {
1161 t.rewrite_method_level_generic_call(id, node, decl, args)
1162 return
1163 }
1164 fn_id := t.a.child(&node, 0)
1165 if int(fn_id) < 0 {
1166 return
1167 }
1168 fn_node := t.a.nodes[int(fn_id)]
1169 if fn_node.kind != .index && fn_node.kind != .selector {
1170 return
1171 }
1172 mut callee_id := fn_id
1173 if fn_node.kind == .index && fn_node.children_count > 0 {
1174 callee_id = t.a.child(&fn_node, 0)
1175 }
1176 ret_typ := t.specialized_fn_return_type_text(decl, args)
1177 mut children := []flat.NodeId{cap: int(node.children_count)}
1178 children << callee_id
1179 for i in 1 .. node.children_count {
1180 children << t.a.child(&node, i)
1181 }
1182 start := t.a.children.len
1183 for child in children {
1184 t.a.children << child
1185 }
1186 t.a.nodes[int(id)] = flat.Node{
1187 kind: .call
1188 op: node.op
1189 children_start: start
1190 children_count: flat.child_count(children.len)
1191 pos: node.pos
1192 value: ''
1193 typ: ret_typ
1194 }
1195 t.clear_resolved_call(id)
1196}
1197
1198// rewrite_method_level_generic_call rewrites a call to a method-level generic into
1199// an explicit call of the specialized function: `SpecName(receiver, args...)`. It
1200// handles both the selector form (receiver inside the callee) and the
1201// ident-lowered form (receiver already an explicit child).
1202fn (mut t Transformer) rewrite_method_level_generic_call(id flat.NodeId, node flat.Node, decl GenericFnDecl, args []string) {
1203 old_params := t.active_generic_params
1204 t.active_generic_params = t.generic_fn_param_names(decl.node, decl.module)
1205 spec_value := specialized_generic_fn_value(decl.node.value, args)
1206 spec_name := transform_qualified_fn_name(decl.module, spec_value)
1207 ret_typ := t.specialized_signature_type_text(decl, decl.node.typ, args, t.active_generic_params)
1208 t.active_generic_params = old_params
1209
1210 mut children := []flat.NodeId{cap: int(node.children_count) + 1}
1211 children << t.make_ident(spec_name)
1212 if t.call_is_selector_form(node) {
1213 // Receiver is embedded in the selector callee; explicit args are children 1..n.
1214 if recv_id := t.generic_call_receiver_id(node) {
1215 children << recv_id
1216 }
1217 for i in 1 .. node.children_count {
1218 children << t.a.child(&node, i)
1219 }
1220 } else {
1221 // Ident-lowered form: receiver and args are already explicit children 1..n.
1222 for i in 1 .. node.children_count {
1223 children << t.a.child(&node, i)
1224 }
1225 }
1226 start := t.a.children.len
1227 for child in children {
1228 t.a.children << child
1229 }
1230 t.a.nodes[int(id)] = flat.Node{
1231 kind: .call
1232 op: node.op
1233 children_start: start
1234 children_count: flat.child_count(children.len)
1235 pos: node.pos
1236 value: ''
1237 typ: ret_typ
1238 }
1239 t.clear_resolved_call(id)
1240}
1241
1242fn (mut t Transformer) clear_resolved_call(id flat.NodeId) {
1243 if isnil(t.tc) {
1244 return
1245 }
1246 idx := int(id)
1247 if idx >= 0 && idx < t.tc.resolved_call_names.len {
1248 t.tc.resolved_call_names[idx] = ''
1249 t.tc.resolved_call_set[idx] = false
1250 }
1251}
1252
1253fn (mut t Transformer) erase_generic_fn_decls(decls map[string]GenericFnDecl) {
1254 for _, decl in decls {
1255 t.unregister_generic_fn_signature(decl)
1256 if int(decl.id) < 0 || int(decl.id) >= t.a.nodes.len {
1257 continue
1258 }
1259 t.a.nodes[int(decl.id)] = flat.Node{
1260 kind: .empty
1261 pos: decl.node.pos
1262 }
1263 }
1264}
1265
1266fn (mut t Transformer) unregister_generic_fn_signature(decl GenericFnDecl) {
1267 if isnil(t.tc) {
1268 return
1269 }
1270 mut names := [decl.node.value, decl.key, c_name(decl.node.value),
1271 c_name(decl.key)]
1272 if decl.module.len > 0 && decl.module != 'main' && decl.module != 'builtin' {
1273 qname := transform_qualified_fn_name(decl.module, decl.node.value)
1274 names << qname
1275 names << c_name(qname)
1276 }
1277 for name in names {
1278 t.tc.fn_ret_types.delete(name)
1279 t.tc.fn_param_types.delete(name)
1280 t.tc.fn_variadic.delete(name)
1281 }
1282}
1283
1284fn (mut t Transformer) generic_call_specialization(id flat.NodeId, node flat.Node, module_name string, decls map[string]GenericFnDecl) ?(string, []string) {
1285 if node.children_count == 0 {
1286 return none
1287 }
1288 decl_key := t.generic_call_decl_key(id, node, module_name, decls) or { return none }
1289 decl := decls[decl_key] or { return none }
1290 if t.should_skip_generic_call_specialization(decl_key) {
1291 return none
1292 }
1293 if t.call_has_source_generic_args(node) {
1294 if args := t.explicit_generic_call_args(node, module_name) {
1295 if args.len > 0 && !t.generic_args_have_placeholders(args) {
1296 return decl_key, args
1297 }
1298 }
1299 } else if args := t.explicit_generic_call_args(node, module_name) {
1300 if args.len > 0 && !t.generic_args_have_placeholders(args)
1301 && t.generic_args_contain_alias(args, module_name) {
1302 return decl_key, args
1303 }
1304 }
1305 if args := t.infer_generic_call_args(decl, id, node) {
1306 if args.len > 0 && !t.generic_args_have_placeholders(args) {
1307 return decl_key, args
1308 }
1309 }
1310 if args := t.explicit_generic_call_args(node, module_name) {
1311 if args.len > 0 && !t.generic_args_have_placeholders(args) {
1312 return decl_key, args
1313 }
1314 }
1315 return none
1316}
1317
1318fn (t &Transformer) call_has_source_generic_args(node flat.Node) bool {
1319 if node.children_count == 0 {
1320 return false
1321 }
1322 fn_node := t.a.child_node(&node, 0)
1323 return fn_node.kind == .index && fn_node.children_count >= 2 && fn_node.value != 'range'
1324}
1325
1326fn (t &Transformer) should_skip_generic_call_specialization(decl_key string) bool {
1327 return decl_key in ['json.decode', 'json2.decode', 'x.json2.decode', 'json.encode',
1328 'json2.encode', 'x.json2.encode', 'veb.run_at', 'veb.run_new']
1329}
1330
1331fn (mut t Transformer) generic_call_decl_key(id flat.NodeId, node flat.Node, module_name string, decls map[string]GenericFnDecl) ?string {
1332 if node.children_count == 0 {
1333 return none
1334 }
1335 mut callee_id := t.a.child(&node, 0)
1336 mut callee := t.a.nodes[int(callee_id)]
1337 if callee.kind == .index && callee.children_count > 0 && callee.value != 'range' {
1338 callee_id = t.a.child(&callee, 0)
1339 callee = t.a.nodes[int(callee_id)]
1340 }
1341 if !isnil(t.tc) {
1342 if resolved := t.tc.resolved_call_name(id) {
1343 key := t.generic_resolved_call_decl_key(resolved, callee, module_name, decls) or {
1344 return none
1345 }
1346 if decl := decls[key] {
1347 if !t.generic_call_arg_count_matches_decl(node, decl) {
1348 return none
1349 }
1350 return key
1351 }
1352 return none
1353 }
1354 }
1355 if callee.kind == .ident {
1356 if t.local_concrete_fn_shadows_generic(callee.value, module_name, decls) {
1357 return none
1358 }
1359 for candidate in t.generic_plain_call_candidates(callee.value, module_name) {
1360 key := generic_fn_decl_base_value(candidate)
1361 if decl := decls[key] {
1362 if !t.generic_call_arg_count_matches_decl(node, decl) {
1363 continue
1364 }
1365 return key
1366 }
1367 }
1368 } else if callee.kind == .selector && callee.children_count > 0 {
1369 base_id := t.a.child(&callee, 0)
1370 base := t.a.nodes[int(base_id)]
1371 if base.kind == .ident && t.ident_is_import_alias(base.value) {
1372 mod_name := t.import_alias_module(base.value)
1373 for candidate in ['${mod_name}.${callee.value}', '${base.value}.${callee.value}'] {
1374 key := generic_fn_decl_base_value(candidate)
1375 if decl := decls[key] {
1376 if !t.generic_call_arg_count_matches_decl(node, decl) {
1377 continue
1378 }
1379 return key
1380 }
1381 }
1382 }
1383 mut base_type := t.node_type(base_id)
1384 if base_type.starts_with('&') {
1385 base_type = base_type[1..]
1386 }
1387 base_name, _, ok := generic_app_parts(base_type)
1388 if ok {
1389 key := t.generic_receiver_decl_key(base_name, callee.value, decls)
1390 if decl := decls[key] {
1391 if !t.generic_call_arg_count_matches_decl(node, decl) {
1392 return none
1393 }
1394 return key
1395 }
1396 }
1397 for key, _ in decls {
1398 if key.all_after_last('.') == callee.value {
1399 decl := decls[key]
1400 if t.generic_decl_is_receiver_method(decl.node) {
1401 if !t.generic_call_arg_count_matches_decl(node, decl) {
1402 continue
1403 }
1404 return key
1405 }
1406 }
1407 }
1408 }
1409 return none
1410}
1411
1412fn (t &Transformer) generic_resolved_call_decl_key(resolved string, callee flat.Node, module_name string, decls map[string]GenericFnDecl) ?string {
1413 key := generic_fn_decl_base_value(resolved)
1414 if key in decls {
1415 return key
1416 }
1417 resolved_mod := if key.contains('.') { key.all_before_last('.') } else { module_name }
1418 short := key.all_after_last('.')
1419 if resolved_mod.len > 0 {
1420 qshort := '${resolved_mod}.${short}'
1421 if qshort in decls {
1422 return qshort
1423 }
1424 }
1425 if decl := decls[short] {
1426 if decl.module == resolved_mod || decl.module == module_name {
1427 return short
1428 }
1429 }
1430 if callee.kind == .ident
1431 && !t.local_concrete_fn_shadows_generic(callee.value, module_name, decls) {
1432 for candidate in t.generic_plain_call_candidates(callee.value, module_name) {
1433 candidate_key := generic_fn_decl_base_value(candidate)
1434 if candidate_key in decls {
1435 return candidate_key
1436 }
1437 }
1438 }
1439 return none
1440}
1441
1442fn (t &Transformer) generic_call_arg_count_matches_decl(node flat.Node, decl GenericFnDecl) bool {
1443 mut param_count := 0
1444 mut is_variadic := false
1445 for i in 0 .. decl.node.children_count {
1446 child := t.a.child_node(&decl.node, i)
1447 if child.kind != .param {
1448 continue
1449 }
1450 param_count++
1451 if child.typ.starts_with('...') {
1452 is_variadic = true
1453 }
1454 }
1455 // param_count includes the receiver for methods. The call's child count
1456 // depends on form: the selector form (`recv.method(args)`) keeps the receiver
1457 // inside the callee child, so children = [callee, args...] and the callee child
1458 // offsets the receiver param (actual == children_count). The ident-lowered form
1459 // (`Type.method(recv, args)`) carries the receiver as a real child, so
1460 // children = [callee, recv, args...] and actual == children_count - 1.
1461 is_receiver := decl.node.value.contains('.')
1462 actual_args := t.generic_call_effective_arg_count(node)
1463 actual := if is_receiver && t.call_is_selector_form(node) {
1464 actual_args + 1
1465 } else {
1466 actual_args
1467 }
1468 if is_variadic {
1469 return actual >= param_count - 1
1470 }
1471 return actual == param_count
1472}
1473
1474fn (t &Transformer) generic_call_effective_arg_count(node flat.Node) int {
1475 if node.children_count <= 1 {
1476 return 0
1477 }
1478 mut count := 0
1479 mut i := 1
1480 for i < node.children_count {
1481 arg := t.a.child_node(&node, i)
1482 if arg.kind == .field_init {
1483 count++
1484 for i < node.children_count {
1485 field := t.a.child_node(&node, i)
1486 if field.kind != .field_init {
1487 break
1488 }
1489 i++
1490 }
1491 continue
1492 }
1493 count++
1494 i++
1495 }
1496 return count
1497}
1498
1499fn (t &Transformer) local_concrete_fn_shadows_generic(name string, module_name string, decls map[string]GenericFnDecl) bool {
1500 qname := transform_qualified_fn_name(module_name, name)
1501 if name in decls || qname in decls {
1502 return false
1503 }
1504 if qname in t.fn_ret_types {
1505 return true
1506 }
1507 if isnil(t.tc) {
1508 return false
1509 }
1510 return qname in t.tc.fn_param_types || qname in t.tc.fn_ret_types
1511}
1512
1513fn (t &Transformer) generic_plain_call_candidates(name string, module_name string) []string {
1514 mut candidates := []string{}
1515 candidates << name
1516 if module_name.len > 0 && module_name != 'main' && module_name != 'builtin' {
1517 candidates << '${module_name}.${name}'
1518 }
1519 if !isnil(t.tc) {
1520 qname := t.tc.qualify_fn_name(name)
1521 candidates << qname
1522 }
1523 return candidates
1524}
1525
1526fn (t &Transformer) generic_receiver_decl_key(base_name string, method string, decls map[string]GenericFnDecl) string {
1527 direct := '${base_name}.${method}'
1528 if direct in decls {
1529 return direct
1530 }
1531 short := base_name.all_after_last('.')
1532 for key, _ in decls {
1533 if key == '${short}.${method}' || key.ends_with('.${short}.${method}') {
1534 return key
1535 }
1536 }
1537 return direct
1538}
1539
1540fn (t &Transformer) explicit_generic_call_args(node flat.Node, module_name string) ?[]string {
1541 if node.value.len > 0 {
1542 return normalize_generic_args(split_generic_args(node.value), module_name)
1543 }
1544 if node.children_count == 0 {
1545 return none
1546 }
1547 fn_node := t.a.child_node(&node, 0)
1548 if fn_node.kind != .index || fn_node.children_count < 2 || fn_node.value == 'range' {
1549 return none
1550 }
1551 type_arg := t.generic_call_type_args_name(fn_node)
1552 if type_arg.len == 0 {
1553 return none
1554 }
1555 return normalize_generic_args(split_generic_args(type_arg), module_name)
1556}
1557
1558fn (t &Transformer) generic_call_arg_id_for_param(node flat.Node, param_idx int, is_receiver bool) ?flat.NodeId {
1559 is_recv_param := is_receiver && param_idx == 0
1560 selector_form := is_receiver && t.call_is_selector_form(node)
1561 if is_recv_param {
1562 if selector_form {
1563 return t.generic_call_receiver_id(node)
1564 }
1565 if int(node.children_count) <= 1 {
1566 return none
1567 }
1568 return t.a.child(&node, 1)
1569 }
1570 arg_idx := if selector_form { param_idx } else { param_idx + 1 }
1571 if arg_idx >= int(node.children_count) {
1572 return none
1573 }
1574 return t.a.child(&node, arg_idx)
1575}
1576
1577fn (mut t Transformer) infer_generic_call_args(decl GenericFnDecl, _id flat.NodeId, node flat.Node) ?[]string {
1578 param_names := t.generic_fn_param_names(decl.node, decl.module)
1579 if param_names.len == 0 {
1580 return none
1581 }
1582 is_receiver := t.generic_decl_is_receiver_method(decl.node)
1583 mut inferred := map[string]string{}
1584 mut param_idx := 0
1585 for i in 0 .. decl.node.children_count {
1586 child := t.a.child_node(&decl.node, i)
1587 if child.kind != .param {
1588 continue
1589 }
1590 is_recv_param := is_receiver && param_idx == 0
1591 arg_id := t.generic_call_arg_id_for_param(node, param_idx, is_receiver) or {
1592 param_idx++
1593 continue
1594 }
1595 arg_type := t.generic_call_arg_type_for_inference(arg_id)
1596 if arg_type.len > 0 {
1597 infer_generic_type_args(child.typ, arg_type, mut inferred)
1598 if is_recv_param {
1599 t.infer_generic_receiver_suffix_args(child.typ, arg_type, mut inferred)
1600 t.infer_generic_embedded_receiver_args(child.typ, arg_type, mut inferred)
1601 }
1602 }
1603 param_idx++
1604 }
1605 ret := t.node_type(_id)
1606 if ret.len > 0 {
1607 infer_generic_type_args(decl.node.typ, ret, mut inferred)
1608 }
1609 mut args := []string{cap: param_names.len}
1610 for name in param_names {
1611 arg := inferred[name] or { return none }
1612 args << t.generic_arg_for_decl_module(arg, decl.module)
1613 }
1614 return args
1615}
1616
1617fn (t &Transformer) generic_arg_for_decl_module(arg string, module_name string) string {
1618 if t.generic_arg_is_alias_name(arg, module_name) {
1619 return t.qualify_generic_arg_for_decl_module(arg, module_name)
1620 }
1621 normalized := t.normalize_type_in_module(arg, module_name)
1622 qualified := t.qualify_generic_arg_for_decl_module(normalized, module_name)
1623 if qualified != normalized {
1624 return qualified
1625 }
1626 if module_name.len > 0 && normalized.starts_with('${module_name}.') {
1627 return normalized.all_after_last('.')
1628 }
1629 return normalized
1630}
1631
1632fn (t &Transformer) generic_arg_is_alias_name(arg string, module_name string) bool {
1633 clean := arg.trim_space()
1634 if clean.len == 0 || isnil(t.tc) {
1635 return false
1636 }
1637 if clean in t.tc.type_aliases {
1638 return true
1639 }
1640 if module_name.len > 0 && module_name != 'main' && module_name != 'builtin' {
1641 if '${module_name}.${clean}' in t.tc.type_aliases {
1642 return true
1643 }
1644 }
1645 for alias, _ in t.tc.type_aliases {
1646 if alias.all_after_last('.') == clean {
1647 return true
1648 }
1649 }
1650 return false
1651}
1652
1653fn (t &Transformer) generic_args_contain_alias(args []string, module_name string) bool {
1654 for arg in args {
1655 if t.generic_arg_is_alias_name(arg, module_name) {
1656 return true
1657 }
1658 }
1659 return false
1660}
1661
1662fn (t &Transformer) qualify_generic_arg_for_decl_module(arg string, module_name string) string {
1663 clean := arg.trim_space()
1664 if clean.len == 0 {
1665 return clean
1666 }
1667 if clean.starts_with('&') {
1668 return '&' + t.qualify_generic_arg_for_decl_module(clean[1..], module_name)
1669 }
1670 if clean.starts_with('mut ') {
1671 return 'mut ' + t.qualify_generic_arg_for_decl_module(clean[4..], module_name)
1672 }
1673 if clean.starts_with('?') || clean.starts_with('!') {
1674 return clean[..1] + t.qualify_generic_arg_for_decl_module(clean[1..], module_name)
1675 }
1676 if clean.starts_with('...') {
1677 return '...' + t.qualify_generic_arg_for_decl_module(clean[3..], module_name)
1678 }
1679 if clean.starts_with('[]') {
1680 return '[]' + t.qualify_generic_arg_for_decl_module(clean[2..], module_name)
1681 }
1682 if clean.starts_with('map[') {
1683 bracket_end := generic_matching_bracket(clean, 3)
1684 if bracket_end < clean.len {
1685 key := t.qualify_generic_arg_for_decl_module(clean[4..bracket_end], module_name)
1686 val := t.qualify_generic_arg_for_decl_module(clean[bracket_end + 1..], module_name)
1687 return 'map[${key}]${val}'
1688 }
1689 }
1690 if clean.starts_with('[') {
1691 bracket_end := generic_matching_bracket(clean, 0)
1692 if bracket_end < clean.len {
1693 return clean[..bracket_end + 1] +
1694 t.qualify_generic_arg_for_decl_module(clean[bracket_end + 1..], module_name)
1695 }
1696 }
1697 if clean.contains('.') || types.is_builtin_type_name(clean) {
1698 return clean
1699 }
1700 if t.generic_arg_module_owns_type(clean, module_name) {
1701 return clean
1702 }
1703 if qualified := t.qualified_types[clean] {
1704 return qualified
1705 }
1706 return clean
1707}
1708
1709fn (t &Transformer) generic_arg_module_owns_type(name string, module_name string) bool {
1710 if module_name.len == 0 || module_name == 'main' || module_name == 'builtin' {
1711 return false
1712 }
1713 qname := '${module_name}.${name}'
1714 if qname in t.structs || qname in t.sum_types || qname in t.enum_types {
1715 return true
1716 }
1717 if !isnil(t.tc) {
1718 return qname in t.tc.type_aliases || qname in t.tc.structs || qname in t.tc.sum_types
1719 || qname in t.tc.enum_names || qname in t.tc.interface_names
1720 }
1721 return false
1722}
1723
1724fn (t &Transformer) generic_arg_expr_type(id flat.NodeId) string {
1725 if int(id) < 0 || int(id) >= t.a.nodes.len {
1726 return ''
1727 }
1728 node := t.a.nodes[int(id)]
1729 match node.kind {
1730 .array_literal {
1731 if node.children_count > 0 {
1732 child_id := t.a.child(&node, 0)
1733 mut elem_type := t.generic_arg_expr_type(child_id)
1734 if elem_type.len == 0 {
1735 elem_type = t.node_type(child_id)
1736 }
1737 if elem_type.len > 0 {
1738 return '[]${elem_type}'
1739 }
1740 }
1741 if node.typ.len > 0 {
1742 return t.normalize_type_alias(node.typ)
1743 }
1744 }
1745 .fn_literal, .lambda_expr {
1746 if fn_type := t.fn_value_type_name(id) {
1747 return fn_type
1748 }
1749 }
1750 .cast_expr, .as_expr {
1751 if node.value.len > 0 {
1752 return node.value
1753 }
1754 }
1755 .infix {
1756 if node.children_count >= 2 {
1757 left_type := t.node_type(t.a.child(&node, 0))
1758 if left_type.len > 0 {
1759 return left_type
1760 }
1761 right_type := t.node_type(t.a.child(&node, 1))
1762 if right_type.len > 0 {
1763 return right_type
1764 }
1765 }
1766 }
1767 .prefix, .paren {
1768 if node.children_count > 0 {
1769 return t.node_type(t.a.child(&node, 0))
1770 }
1771 }
1772 .index {
1773 if node.children_count > 0 {
1774 base_type := t.normalize_type_alias(t.node_type(t.a.child(&node, 0)))
1775 if base_type.starts_with('[]') {
1776 return base_type[2..]
1777 }
1778 if base_type.starts_with('map[') {
1779 bracket_end := generic_matching_bracket(base_type, 3)
1780 if bracket_end < base_type.len {
1781 return base_type[bracket_end + 1..]
1782 }
1783 }
1784 if base_type.starts_with('[') {
1785 bracket_end := generic_matching_bracket(base_type, 0)
1786 if bracket_end < base_type.len {
1787 return base_type[bracket_end + 1..]
1788 }
1789 }
1790 }
1791 }
1792 else {}
1793 }
1794
1795 return t.node_type(id)
1796}
1797
1798fn (t &Transformer) generic_call_arg_type_for_inference(id flat.NodeId) string {
1799 if int(id) < 0 || int(id) >= t.a.nodes.len {
1800 return ''
1801 }
1802 node := t.a.nodes[int(id)]
1803 if node.kind in [.array_literal, .fn_literal, .lambda_expr] {
1804 typ := t.generic_arg_expr_type(id)
1805 if typ.len > 0 {
1806 return typ
1807 }
1808 }
1809 if node.typ.len > 0 {
1810 typ := t.normalize_type_alias(node.typ)
1811 if typ.len > 0 && !t.generic_arg_is_unresolved(typ) {
1812 return typ
1813 }
1814 }
1815 mut typ := t.node_type(id)
1816 if typ.len == 0 {
1817 typ = t.generic_arg_expr_type(id)
1818 }
1819 return typ
1820}
1821
1822fn (t &Transformer) infer_generic_receiver_suffix_args(param_type string, arg_type string, mut inferred map[string]string) {
1823 param := param_type.trim_space().trim_left('&')
1824 arg := arg_type.trim_space().trim_left('&')
1825 base, param_args, ok := generic_app_parts(param)
1826 if !ok || param_args.len == 0 || arg.len == 0 {
1827 return
1828 }
1829 mut suffix := ''
1830 for prefix in [base, c_name(base)] {
1831 if arg.starts_with('${prefix}_') {
1832 suffix = arg[prefix.len + 1..]
1833 break
1834 }
1835 }
1836 if suffix.len == 0 {
1837 short := base.all_after_last('.')
1838 arg_short := if arg.contains('.') { arg.all_after_last('.') } else { arg }
1839 for candidate in [arg, arg_short, c_name(arg), c_name(arg_short)] {
1840 for prefix in [short, c_name(short)] {
1841 if candidate.starts_with('${prefix}_') {
1842 suffix = candidate[prefix.len + 1..]
1843 break
1844 }
1845 }
1846 if suffix.len > 0 {
1847 break
1848 }
1849 }
1850 }
1851 if suffix.len == 0 {
1852 return
1853 }
1854 for i, param_arg in param_args {
1855 if !is_generic_fn_placeholder_name(param_arg) || param_arg in inferred {
1856 continue
1857 }
1858 decoded := generic_type_arg_from_suffix(suffix)
1859 if decoded.len == 0 {
1860 continue
1861 }
1862 if i == 0 {
1863 inferred[param_arg] = decoded
1864 }
1865 }
1866}
1867
1868fn (t &Transformer) infer_generic_embedded_receiver_args(param_type string, arg_type string, mut inferred map[string]string) {
1869 param := param_type.trim_space().trim_left('&')
1870 base, _, ok := generic_app_parts(param)
1871 if !ok || base.len == 0 {
1872 return
1873 }
1874 mut receiver_type := arg_type.trim_space().trim_left('&')
1875 receiver_base, _, receiver_is_generic := generic_app_parts(receiver_type)
1876 if receiver_is_generic {
1877 receiver_type = receiver_base
1878 }
1879 info := t.structs[receiver_type] or {
1880 short := if receiver_type.contains('.') {
1881 receiver_type.all_after_last('.')
1882 } else {
1883 receiver_type
1884 }
1885 t.structs[short] or { return }
1886 }
1887 for field in info.fields {
1888 field_type := field.typ.trim_space().trim_left('&')
1889 field_base, _, field_is_generic := generic_app_parts(field_type)
1890 if !field_is_generic {
1891 continue
1892 }
1893 if field_base == base || field_base.all_after_last('.') == base.all_after_last('.') {
1894 infer_generic_type_args(param, field_type, mut inferred)
1895 return
1896 }
1897 }
1898}
1899
1900fn (t &Transformer) generic_call_receiver_id(node flat.Node) ?flat.NodeId {
1901 if node.children_count == 0 {
1902 return none
1903 }
1904 mut callee_id := t.a.child(&node, 0)
1905 mut callee := t.a.nodes[int(callee_id)]
1906 if callee.kind == .index && callee.children_count > 0 {
1907 callee_id = t.a.child(&callee, 0)
1908 callee = t.a.nodes[int(callee_id)]
1909 }
1910 if callee.kind != .selector || callee.children_count == 0 {
1911 return none
1912 }
1913 return t.a.child(&callee, 0)
1914}
1915
1916fn infer_generic_type_args(param_type string, arg_type string, mut inferred map[string]string) {
1917 param := param_type.trim_space()
1918 arg := arg_type.trim_space()
1919 if param.len == 0 || arg.len == 0 {
1920 return
1921 }
1922 if arg == 'unknown' || arg == 'generic' {
1923 return
1924 }
1925 if is_generic_fn_placeholder_name(param) {
1926 if param !in inferred {
1927 inferred[param] = arg
1928 }
1929 return
1930 }
1931 if param.starts_with('&') {
1932 // A `&T` / `mut T` parameter binds to a by-value argument too (the arg type
1933 // carries no `&`), so strip the reference from the parameter regardless of
1934 // whether the argument is itself a reference.
1935 infer_generic_type_args(param[1..], arg.trim_left('&'), mut inferred)
1936 return
1937 }
1938 if param.starts_with('mut ') {
1939 infer_generic_type_args(param[4..], arg.trim_left('&'), mut inferred)
1940 return
1941 }
1942 if param.starts_with('...') {
1943 infer_generic_type_args(param[3..], arg.trim_left('[]'), mut inferred)
1944 return
1945 }
1946 if param.starts_with('[]') && arg.starts_with('[]') {
1947 infer_generic_type_args(param[2..], arg[2..], mut inferred)
1948 return
1949 }
1950 if param.starts_with('?') && arg.starts_with('?') {
1951 infer_generic_type_args(param[1..], arg[1..], mut inferred)
1952 return
1953 }
1954 if param.starts_with('!') && arg.starts_with('!') {
1955 infer_generic_type_args(param[1..], arg[1..], mut inferred)
1956 return
1957 }
1958 if param.starts_with('fn') && arg.starts_with('fn') {
1959 infer_generic_fn_type_args(param, arg, mut inferred)
1960 return
1961 }
1962 if param.starts_with('map[') && arg.starts_with('map[') {
1963 p_end := generic_matching_bracket(param, 3)
1964 a_end := generic_matching_bracket(arg, 3)
1965 if p_end < param.len && a_end < arg.len {
1966 infer_generic_type_args(param[4..p_end], arg[4..a_end], mut inferred)
1967 infer_generic_type_args(param[p_end + 1..], arg[a_end + 1..], mut inferred)
1968 }
1969 return
1970 }
1971 p_base, p_args, p_ok := generic_app_parts(param)
1972 if p_ok {
1973 a_base, a_args, a_ok := generic_app_parts(arg)
1974 if p_ok && a_ok && p_base.all_after_last('.') == a_base.all_after_last('.') {
1975 for i, p_arg in p_args {
1976 if i < a_args.len {
1977 infer_generic_type_args(p_arg, a_args[i], mut inferred)
1978 }
1979 }
1980 }
1981 }
1982}
1983
1984fn infer_generic_fn_type_args(param string, arg string, mut inferred map[string]string) {
1985 p_params, p_ret := fn_type_text_parts(param) or { return }
1986 a_params, a_ret := fn_type_text_parts(arg) or { return }
1987 for i, p_param in p_params {
1988 if i >= a_params.len {
1989 break
1990 }
1991 infer_generic_type_args(generic_fn_type_param_payload(p_param),
1992 generic_fn_type_param_payload(a_params[i]), mut inferred)
1993 }
1994 if p_ret.len > 0 && a_ret.len > 0 {
1995 infer_generic_type_args(p_ret, a_ret, mut inferred)
1996 }
1997}
1998
1999fn fn_type_text_parts(typ string) ?([]string, string) {
2000 clean := typ.trim_space()
2001 open := clean.index_u8(`(`)
2002 if open < 0 {
2003 return none
2004 }
2005 mut depth := 1
2006 mut close := open + 1
2007 for close < clean.len {
2008 if clean[close] == `(` {
2009 depth++
2010 } else if clean[close] == `)` {
2011 depth--
2012 if depth == 0 {
2013 break
2014 }
2015 }
2016 close++
2017 }
2018 if close >= clean.len {
2019 return none
2020 }
2021 params_text := clean[open + 1..close]
2022 params := split_fn_type_params(params_text)
2023 ret := clean[close + 1..].trim_space()
2024 return params, ret
2025}
2026
2027fn split_fn_type_params(s string) []string {
2028 mut parts := []string{}
2029 mut depth := 0
2030 mut start := 0
2031 for i := 0; i < s.len; i++ {
2032 c := s[i]
2033 if c == `(` || c == `[` {
2034 depth++
2035 } else if c == `)` || c == `]` {
2036 depth--
2037 } else if c == `,` && depth == 0 {
2038 part := s[start..i].trim_space()
2039 if part.len > 0 {
2040 parts << part
2041 }
2042 start = i + 1
2043 }
2044 }
2045 tail := s[start..].trim_space()
2046 if tail.len > 0 {
2047 parts << tail
2048 }
2049 return parts
2050}
2051
2052fn generic_fn_type_param_payload(param string) string {
2053 mut text := param.trim_space()
2054 if text.starts_with('mut ') {
2055 text = text[4..].trim_space()
2056 }
2057 space := generic_top_level_space_index(text)
2058 if space > 0 {
2059 head := text[..space].trim_space()
2060 tail := text[space + 1..].trim_space()
2061 if generic_fn_type_param_head_is_name(head, tail) {
2062 return tail
2063 }
2064 }
2065 return text
2066}
2067
2068fn (mut t Transformer) clone_generic_fn_node(node flat.Node, args []string) flat.NodeId {
2069 return t.clone_generic_node_from(node, args, true)
2070}
2071
2072fn (mut t Transformer) clone_generic_node(id flat.NodeId, args []string) flat.NodeId {
2073 if int(id) < 0 || int(id) >= t.a.nodes.len {
2074 return id
2075 }
2076 node := t.a.nodes[int(id)]
2077 clone_id := t.clone_generic_node_from(node, args, false)
2078 t.copy_cloned_resolution(id, clone_id)
2079 return clone_id
2080}
2081
2082fn (mut t Transformer) clone_generic_node_from(node flat.Node, args []string, is_root bool) flat.NodeId {
2083 if node.kind == .selector && node.value == 'name' && node.children_count > 0 {
2084 base := t.a.child_node(&node, 0)
2085 if base.kind == .ident && is_generic_fn_placeholder_name(base.value) {
2086 idx := t.active_generic_param_index(base.value)
2087 if idx < args.len {
2088 return t.make_string_literal(args[idx])
2089 }
2090 }
2091 }
2092 mut children := []flat.NodeId{cap: int(node.children_count)}
2093 for i in 0 .. node.children_count {
2094 children << t.clone_generic_node(t.a.child(&node, i), args)
2095 }
2096 cloned_typ := t.subst_type(node.typ, args)
2097 t.retarget_cloned_new_map_call(node, mut children, cloned_typ)
2098 start := t.a.children.len
2099 for child in children {
2100 t.a.children << child
2101 }
2102 cloned_value := if is_root {
2103 specialized_generic_fn_value(node.value, args)
2104 } else {
2105 t.subst_node_value(node, args)
2106 }
2107 return t.a.add_node(flat.Node{
2108 kind: node.kind
2109 kind_id: node.kind_id
2110 op: node.op
2111 pos: node.pos
2112 children_start: start
2113 children_count: flat.child_count(children.len)
2114 typ: cloned_typ
2115 value: cloned_value
2116 })
2117}
2118
2119fn (mut t Transformer) retarget_cloned_new_map_call(node flat.Node, mut children []flat.NodeId, map_type string) {
2120 if node.kind != .call || children.len < 7 || !map_type.starts_with('map[') {
2121 return
2122 }
2123 callee := t.a.nodes[int(children[0])]
2124 if callee.kind != .ident || callee.value != 'new_map' {
2125 return
2126 }
2127 key_type, _ := t.map_type_parts(map_type)
2128 if key_type.len == 0 {
2129 return
2130 }
2131 hash_fn, eq_fn, clone_fn, free_fn := map_callback_names(key_type)
2132 children[3] = t.make_ident(hash_fn)
2133 children[4] = t.make_ident(eq_fn)
2134 children[5] = t.make_ident(clone_fn)
2135 children[6] = t.make_ident(free_fn)
2136}
2137
2138fn (mut t Transformer) copy_cloned_resolution(src_id flat.NodeId, dst_id flat.NodeId) {
2139 if isnil(t.tc) {
2140 return
2141 }
2142 src_idx := int(src_id)
2143 dst_idx := int(dst_id)
2144 if src_idx < 0 || dst_idx < 0 {
2145 return
2146 }
2147 if src_idx < t.tc.resolved_call_set.len && t.tc.resolved_call_set[src_idx]
2148 && !t.resolved_call_is_generic_fn(t.tc.resolved_call_names[src_idx]) {
2149 for t.tc.resolved_call_names.len <= dst_idx {
2150 t.tc.resolved_call_names << ''
2151 t.tc.resolved_call_set << false
2152 }
2153 t.tc.resolved_call_names[dst_idx] = t.tc.resolved_call_names[src_idx]
2154 t.tc.resolved_call_set[dst_idx] = true
2155 }
2156 if src_idx < t.tc.resolved_fn_value_set.len && t.tc.resolved_fn_value_set[src_idx] {
2157 for t.tc.resolved_fn_value_names.len <= dst_idx {
2158 t.tc.resolved_fn_value_names << ''
2159 t.tc.resolved_fn_value_set << false
2160 }
2161 t.tc.resolved_fn_value_names[dst_idx] = t.tc.resolved_fn_value_names[src_idx]
2162 t.tc.resolved_fn_value_set[dst_idx] = true
2163 }
2164}
2165
2166fn (t &Transformer) resolved_call_is_generic_fn(name string) bool {
2167 if name.len == 0 || isnil(t.tc) {
2168 return false
2169 }
2170 if name in t.tc.fn_generic_params {
2171 return true
2172 }
2173 base := generic_fn_decl_base_value(name)
2174 if base in t.tc.fn_generic_params {
2175 return true
2176 }
2177 if name.contains('.') {
2178 short := name.all_after_last('.')
2179 if short in t.tc.fn_generic_params {
2180 return true
2181 }
2182 }
2183 return false
2184}
2185
2186fn substitute_generic_node_value(node flat.Node, args []string) string {
2187 match node.kind {
2188 .call, .array_init, .struct_init, .cast_expr, .as_expr, .sizeof_expr, .typeof_expr,
2189 .is_expr, .type_decl, .field_decl, .param {
2190 return substitute_generic_type_text(node.value, args)
2191 }
2192 else {
2193 return node.value
2194 }
2195 }
2196}
2197
2198fn (mut t Transformer) fn_decl_has_unresolved_generics(node flat.Node, module_name string) bool {
2199 if node.generic_params.len > 0 {
2200 return true
2201 }
2202 if t.type_text_has_generic_placeholder(node.typ, module_name)
2203 || t.type_text_has_generic_placeholder(node.value, module_name) {
2204 return true
2205 }
2206 for i in 0 .. node.children_count {
2207 child := t.a.child_node(&node, i)
2208 if child.kind == .param && t.type_text_has_generic_placeholder(child.typ, module_name) {
2209 return true
2210 }
2211 }
2212 return false
2213}
2214
2215fn (mut t Transformer) node_subtree_has_generic_placeholder(id flat.NodeId, module_name string) bool {
2216 if int(id) < 0 || int(id) >= t.a.nodes.len {
2217 return false
2218 }
2219 node := t.a.nodes[int(id)]
2220 if t.type_text_has_generic_placeholder(node.typ, module_name)
2221 || t.type_text_has_generic_placeholder(node.value, module_name) {
2222 return true
2223 }
2224 for i in 0 .. node.children_count {
2225 if t.node_subtree_has_generic_placeholder(t.a.child(&node, i), module_name) {
2226 return true
2227 }
2228 }
2229 return false
2230}
2231
2232fn (mut t Transformer) type_text_has_generic_placeholder(typ string, module_name string) bool {
2233 clean := typ.trim_space()
2234 if clean.len == 0 {
2235 return false
2236 }
2237 if clean == 'generic' {
2238 return true
2239 }
2240 if is_generic_fn_placeholder_name(clean) && !t.concrete_type_name_known(clean, module_name) {
2241 return true
2242 }
2243 if clean.starts_with('&') {
2244 return t.type_text_has_generic_placeholder(clean[1..], module_name)
2245 }
2246 if clean.starts_with('mut ') {
2247 return t.type_text_has_generic_placeholder(clean[4..], module_name)
2248 }
2249 if clean.starts_with('?') || clean.starts_with('!') {
2250 return t.type_text_has_generic_placeholder(clean[1..], module_name)
2251 }
2252 if clean.starts_with('...') {
2253 return t.type_text_has_generic_placeholder(clean[3..], module_name)
2254 }
2255 if clean.starts_with('[]') {
2256 return t.type_text_has_generic_placeholder(clean[2..], module_name)
2257 }
2258 if clean.starts_with('map[') {
2259 bracket_end := generic_matching_bracket(clean, 3)
2260 if bracket_end < clean.len {
2261 return t.type_text_has_generic_placeholder(clean[4..bracket_end], module_name)
2262 || t.type_text_has_generic_placeholder(clean[bracket_end + 1..], module_name)
2263 }
2264 }
2265 if clean.starts_with('[') {
2266 bracket_end := generic_matching_bracket(clean, 0)
2267 if bracket_end < clean.len {
2268 return t.type_text_has_generic_placeholder(clean[bracket_end + 1..], module_name)
2269 }
2270 }
2271 _, args, ok := generic_app_parts(clean)
2272 if ok {
2273 for arg in args {
2274 if t.type_text_has_generic_placeholder(arg, module_name) {
2275 return true
2276 }
2277 }
2278 }
2279 return false
2280}
2281
2282fn (mut t Transformer) concrete_type_name_known(name string, module_name string) bool {
2283 if types.is_builtin_type_name(name) || name in ['C', 'JS'] {
2284 return true
2285 }
2286 qname := if name.contains('.') || module_name.len == 0 || module_name == 'main'
2287 || module_name == 'builtin' {
2288 name
2289 } else {
2290 '${module_name}.${name}'
2291 }
2292 return name in t.structs || qname in t.structs || name in t.sum_types
2293 || qname in t.sum_types || name in t.enum_types || qname in t.enum_types
2294 || (!isnil(t.tc) && (name in t.tc.type_aliases || qname in t.tc.type_aliases
2295 || name in t.tc.structs || qname in t.tc.structs || name in t.tc.sum_types
2296 || qname in t.tc.sum_types || name in t.tc.enum_names
2297 || qname in t.tc.enum_names || name in t.tc.interface_names
2298 || qname in t.tc.interface_names))
2299}
2300
2301fn (mut t Transformer) generic_fn_decl_key(node flat.Node, module_name string) string {
2302 base_value := generic_fn_decl_base_value(node.value)
2303 if module_name.len > 0 && module_name != 'main' && module_name != 'builtin' {
2304 return '${module_name}.${base_value}'
2305 }
2306 return base_value
2307}
2308
2309fn generic_fn_decl_base_value(value string) string {
2310 if !value.contains('.') {
2311 return value
2312 }
2313 receiver := value.all_before_last('.')
2314 method := value.all_after_last('.')
2315 base, _, ok := generic_app_parts(receiver)
2316 if ok {
2317 return '${base}.${method}'
2318 }
2319 return value
2320}
2321
2322fn (t &Transformer) generic_decl_is_receiver_method(node flat.Node) bool {
2323 return node.value.contains('.')
2324}
2325
2326fn (mut t Transformer) generic_decl_has_method_level_params(decl GenericFnDecl) bool {
2327 all_params := t.generic_fn_param_names(decl.node, decl.module)
2328 if all_params.len == 0 {
2329 return false
2330 }
2331 mut receiver_params := []string{}
2332 if decl.node.value.contains('.') {
2333 receiver := decl.node.value.all_before_last('.')
2334 t.collect_generic_param_names_from_type(receiver, decl.module, mut receiver_params)
2335 }
2336 for i in 0 .. decl.node.children_count {
2337 child := t.a.child_node(&decl.node, i)
2338 if child.kind == .param {
2339 t.collect_generic_param_names_from_type(child.typ, decl.module, mut receiver_params)
2340 break
2341 }
2342 }
2343 for param in all_params {
2344 if param !in receiver_params {
2345 return true
2346 }
2347 }
2348 return false
2349}
2350
2351fn (mut t Transformer) generic_fn_param_names(node flat.Node, module_name string) []string {
2352 mut names := []string{}
2353 for param in node.generic_params {
2354 if param !in names {
2355 names << param
2356 }
2357 }
2358 t.collect_generic_param_names_from_type(node.value, module_name, mut names)
2359 t.collect_generic_param_names_from_type(node.typ, module_name, mut names)
2360 for i in 0 .. node.children_count {
2361 child := t.a.child_node(&node, i)
2362 if child.kind == .param {
2363 t.collect_generic_param_names_from_type(child.typ, module_name, mut names)
2364 }
2365 }
2366 return names
2367}
2368
2369fn (mut t Transformer) collect_generic_param_names_from_node(id flat.NodeId, module_name string, mut names []string) {
2370 if int(id) < 0 || int(id) >= t.a.nodes.len {
2371 return
2372 }
2373 node := t.a.nodes[int(id)]
2374 t.collect_generic_param_names_from_type(node.typ, module_name, mut names)
2375 t.collect_generic_param_names_from_type(node.value, module_name, mut names)
2376 for i in 0 .. node.children_count {
2377 t.collect_generic_param_names_from_node(t.a.child(&node, i), module_name, mut names)
2378 }
2379}
2380
2381fn (mut t Transformer) collect_generic_param_names_from_type(typ string, module_name string, mut names []string) {
2382 clean := typ.trim_space()
2383 if clean.len == 0 {
2384 return
2385 }
2386 if is_generic_fn_placeholder_name(clean) && !t.concrete_type_name_known(clean, module_name) {
2387 if clean !in names {
2388 names << clean
2389 }
2390 return
2391 }
2392 if clean.starts_with('&') {
2393 t.collect_generic_param_names_from_type(clean[1..], module_name, mut names)
2394 return
2395 }
2396 if clean.starts_with('mut ') {
2397 t.collect_generic_param_names_from_type(clean[4..], module_name, mut names)
2398 return
2399 }
2400 if clean.starts_with('?') || clean.starts_with('!') {
2401 t.collect_generic_param_names_from_type(clean[1..], module_name, mut names)
2402 return
2403 }
2404 if clean.starts_with('...') {
2405 t.collect_generic_param_names_from_type(clean[3..], module_name, mut names)
2406 return
2407 }
2408 if clean.starts_with('[]') {
2409 t.collect_generic_param_names_from_type(clean[2..], module_name, mut names)
2410 return
2411 }
2412 if clean.starts_with('map[') {
2413 bracket_end := generic_matching_bracket(clean, 3)
2414 if bracket_end < clean.len {
2415 t.collect_generic_param_names_from_type(clean[4..bracket_end], module_name, mut names)
2416 t.collect_generic_param_names_from_type(clean[bracket_end + 1..], module_name, mut
2417 names)
2418 }
2419 return
2420 }
2421 _, args, ok := generic_app_parts(clean)
2422 if ok {
2423 for arg in args {
2424 t.collect_generic_param_names_from_type(arg, module_name, mut names)
2425 }
2426 return
2427 }
2428 bracket := clean.index_u8(`[`)
2429 if bracket > 0 {
2430 bracket_end := generic_matching_bracket(clean, bracket)
2431 if bracket_end > bracket && bracket_end < clean.len {
2432 for arg in split_generic_args(clean[bracket + 1..bracket_end]) {
2433 t.collect_generic_param_names_from_type(arg, module_name, mut names)
2434 }
2435 }
2436 }
2437}
2438
2439fn generic_app_parts(typ string) (string, []string, bool) {
2440 if typ.starts_with('fn(') || typ.starts_with('fn (') {
2441 return '', []string{}, false
2442 }
2443 bracket := typ.index_u8(`[`)
2444 if bracket <= 0 {
2445 return '', []string{}, false
2446 }
2447 bracket_end := generic_matching_bracket(typ, bracket)
2448 if bracket_end <= bracket || bracket_end >= typ.len {
2449 return '', []string{}, false
2450 }
2451 return typ[..bracket], split_generic_args(typ[bracket + 1..bracket_end]), true
2452}
2453
2454fn generic_matching_bracket(s string, start int) int {
2455 mut depth := 0
2456 for i in start .. s.len {
2457 if s[i] == `[` {
2458 depth++
2459 } else if s[i] == `]` {
2460 depth--
2461 if depth == 0 {
2462 return i
2463 }
2464 }
2465 }
2466 return s.len
2467}
2468
2469fn split_generic_args(s string) []string {
2470 mut parts := []string{}
2471 mut depth := 0
2472 mut start := 0
2473 for i in 0 .. s.len {
2474 match s[i] {
2475 `[` {
2476 depth++
2477 }
2478 `]` {
2479 depth--
2480 }
2481 `,` {
2482 if depth == 0 {
2483 parts << s[start..i].trim_space()
2484 start = i + 1
2485 }
2486 }
2487 else {}
2488 }
2489 }
2490 parts << s[start..].trim_space()
2491 return parts
2492}
2493
2494fn normalize_generic_args(args []string, module_name string) []string {
2495 mut result := []string{cap: args.len}
2496 for arg in args {
2497 result << normalize_generic_arg(arg, module_name)
2498 }
2499 return result
2500}
2501
2502fn normalize_generic_arg(arg string, module_name string) string {
2503 clean := arg.trim_space()
2504 if clean.len == 0 {
2505 return clean
2506 }
2507 if clean.starts_with('&') {
2508 return '&' + normalize_generic_arg(clean[1..], module_name)
2509 }
2510 if clean.starts_with('[]') {
2511 return '[]' + normalize_generic_arg(clean[2..], module_name)
2512 }
2513 if clean.starts_with('?') || clean.starts_with('!') {
2514 return clean[..1] + normalize_generic_arg(clean[1..], module_name)
2515 }
2516 if clean.starts_with('map[') {
2517 bracket_end := generic_matching_bracket(clean, 3)
2518 if bracket_end < clean.len {
2519 key := normalize_generic_arg(clean[4..bracket_end], module_name)
2520 val := normalize_generic_arg(clean[bracket_end + 1..], module_name)
2521 return 'map[${key}]${val}'
2522 }
2523 }
2524 if clean.contains('.') || module_name.len == 0 || module_name == 'main'
2525 || module_name == 'builtin' || types.is_builtin_type_name(clean) {
2526 return clean
2527 }
2528 return clean
2529}
2530
2531fn substitute_generic_type_text(typ string, args []string) string {
2532 clean := typ.trim_space()
2533 if clean.len == 0 || args.len == 0 {
2534 return typ
2535 }
2536 if is_generic_fn_placeholder_name(clean) {
2537 idx := generic_param_index(clean)
2538 if idx < args.len {
2539 return args[idx]
2540 }
2541 return clean
2542 }
2543 if clean.starts_with('&') {
2544 return '&' + substitute_generic_type_text(clean[1..], args)
2545 }
2546 if clean.starts_with('mut ') {
2547 return 'mut ' + substitute_generic_type_text(clean[4..], args)
2548 }
2549 if clean.starts_with('?') {
2550 return '?' + substitute_generic_type_text(clean[1..], args)
2551 }
2552 if clean.starts_with('!') {
2553 return '!' + substitute_generic_type_text(clean[1..], args)
2554 }
2555 if clean.starts_with('...') {
2556 return '...' + substitute_generic_type_text(clean[3..], args)
2557 }
2558 if clean.starts_with('[]') {
2559 return '[]' + substitute_generic_type_text(clean[2..], args)
2560 }
2561 if clean.starts_with('map[') {
2562 bracket_end := generic_matching_bracket(clean, 3)
2563 if bracket_end < clean.len {
2564 key := substitute_generic_type_text(clean[4..bracket_end], args)
2565 val := substitute_generic_type_text(clean[bracket_end + 1..], args)
2566 return 'map[${key}]${val}'
2567 }
2568 }
2569 if clean.starts_with('[') {
2570 bracket_end := generic_matching_bracket(clean, 0)
2571 if bracket_end < clean.len {
2572 return clean[..bracket_end + 1] + substitute_generic_type_text(clean[bracket_end +
2573 1..], args)
2574 }
2575 }
2576 if clean.starts_with('(') && clean.ends_with(')') && clean.contains(',') {
2577 mut parts := []string{}
2578 for part in split_generic_args(clean[1..clean.len - 1]) {
2579 parts << substitute_generic_type_text(part, args)
2580 }
2581 return '(' + parts.join(', ') + ')'
2582 }
2583 base, nested_args, ok := generic_app_parts(clean)
2584 if ok {
2585 mut resolved_args := []string{}
2586 for arg in nested_args {
2587 resolved_args << substitute_generic_type_text(arg, args)
2588 }
2589 return '${base}[${resolved_args.join(', ')}]'
2590 }
2591 return clean
2592}
2593
2594fn substitute_generic_type_text_with_params(typ string, args []string, params []string) string {
2595 clean := typ.trim_space()
2596 if clean.len == 0 || args.len == 0 {
2597 return typ
2598 }
2599 for i, param in params {
2600 if clean == param {
2601 if i < args.len {
2602 return args[i]
2603 }
2604 return clean
2605 }
2606 }
2607 if params.len == 0 && is_generic_fn_placeholder_name(clean) {
2608 idx := generic_param_index(clean)
2609 if idx < args.len {
2610 return args[idx]
2611 }
2612 return clean
2613 }
2614 if clean.starts_with('&') {
2615 return '&' + substitute_generic_type_text_with_params(clean[1..], args, params)
2616 }
2617 if clean.starts_with('mut ') {
2618 return 'mut ' + substitute_generic_type_text_with_params(clean[4..], args, params)
2619 }
2620 if clean.starts_with('?') {
2621 return '?' + substitute_generic_type_text_with_params(clean[1..], args, params)
2622 }
2623 if clean.starts_with('!') {
2624 return '!' + substitute_generic_type_text_with_params(clean[1..], args, params)
2625 }
2626 if clean.starts_with('...') {
2627 return '...' + substitute_generic_type_text_with_params(clean[3..], args, params)
2628 }
2629 if clean.starts_with('[]') {
2630 return '[]' + substitute_generic_type_text_with_params(clean[2..], args, params)
2631 }
2632 if clean.starts_with('map[') {
2633 bracket_end := generic_matching_bracket(clean, 3)
2634 if bracket_end < clean.len {
2635 key := substitute_generic_type_text_with_params(clean[4..bracket_end], args, params)
2636 val := substitute_generic_type_text_with_params(clean[bracket_end + 1..], args, params)
2637 return 'map[${key}]${val}'
2638 }
2639 }
2640 if clean.starts_with('[') {
2641 bracket_end := generic_matching_bracket(clean, 0)
2642 if bracket_end < clean.len {
2643 return clean[..bracket_end + 1] +
2644 substitute_generic_type_text_with_params(clean[bracket_end + 1..], args, params)
2645 }
2646 }
2647 if clean.starts_with('(') && clean.ends_with(')') && clean.contains(',') {
2648 mut parts := []string{}
2649 for part in split_generic_args(clean[1..clean.len - 1]) {
2650 parts << substitute_generic_type_text_with_params(part, args, params)
2651 }
2652 return '(' + parts.join(', ') + ')'
2653 }
2654 if clean.starts_with('fn(') || clean.starts_with('fn (') {
2655 // Substitute the generic params inside a function-type parameter so a specialized
2656 // method body emits e.g. `fn (string) int`, not the placeholder `fn (T) int` (which
2657 // cgen would otherwise render as `fn (int) int`).
2658 if sub := subst_generic_fn_type_text(clean, args, params) {
2659 return sub
2660 }
2661 }
2662 base, nested_args, ok := generic_app_parts(clean)
2663 if ok {
2664 mut resolved_args := []string{}
2665 for arg in nested_args {
2666 resolved_args << substitute_generic_type_text_with_params(arg, args, params)
2667 }
2668 return '${base}[${resolved_args.join(', ')}]'
2669 }
2670 return clean
2671}
2672
2673// subst_generic_fn_type_text substitutes generic params inside a `fn (...) ...` type text,
2674// recursing into each parameter type and the return type. Returns none when the signature
2675// is malformed (unbalanced parens).
2676fn subst_generic_fn_type_text(clean string, args []string, params []string) ?string {
2677 params_start := clean.index_u8(`(`) + 1
2678 mut depth := 1
2679 mut params_end := params_start
2680 for params_end < clean.len {
2681 if clean[params_end] == `(` {
2682 depth++
2683 } else if clean[params_end] == `)` {
2684 depth--
2685 if depth == 0 {
2686 break
2687 }
2688 }
2689 params_end++
2690 }
2691 if params_end >= clean.len {
2692 return none
2693 }
2694 params_str := clean[params_start..params_end]
2695 mut fn_parts := []string{}
2696 if params_str.trim_space().len > 0 {
2697 mut pdepth := 0
2698 mut start := 0
2699 for i := 0; i < params_str.len; i++ {
2700 c := params_str[i]
2701 if c == `(` || c == `[` {
2702 pdepth++
2703 } else if c == `)` || c == `]` {
2704 pdepth--
2705 } else if c == `,` && pdepth == 0 {
2706 fn_parts << subst_generic_fn_type_param_text(params_str[start..i], args, params)
2707 start = i + 1
2708 }
2709 }
2710 fn_parts << subst_generic_fn_type_param_text(params_str[start..], args, params)
2711 }
2712 ret_str := clean[params_end + 1..].trim_space()
2713 if ret_str.len > 0 {
2714 return 'fn(${fn_parts.join(', ')}) ${substitute_generic_type_text_with_params(ret_str,
2715 args, params)}'
2716 }
2717 return 'fn(${fn_parts.join(', ')})'
2718}
2719
2720fn subst_generic_fn_type_param_text(param string, args []string, params []string) string {
2721 mut text := param.trim_space()
2722 mut is_mut := false
2723 if text.starts_with('mut ') {
2724 is_mut = true
2725 text = text[4..].trim_space()
2726 }
2727 space := generic_top_level_space_index(text)
2728 if space > 0 {
2729 head := text[..space].trim_space()
2730 tail := text[space + 1..].trim_space()
2731 if generic_fn_type_param_head_is_name(head, tail) {
2732 sub := substitute_generic_type_text_with_params(tail, args, params)
2733 if is_mut && sub.len > 0 && !sub.starts_with('&') {
2734 return '${head} &${sub}'
2735 }
2736 return '${head} ${sub}'
2737 }
2738 }
2739 sub := substitute_generic_type_text_with_params(text, args, params)
2740 if is_mut && sub.len > 0 && !sub.starts_with('&') {
2741 return '&${sub}'
2742 }
2743 return sub
2744}
2745
2746fn generic_top_level_space_index(s string) int {
2747 mut depth := 0
2748 for i := 0; i < s.len; i++ {
2749 match s[i] {
2750 `(`, `[` {
2751 depth++
2752 }
2753 `)`, `]` {
2754 depth--
2755 }
2756 ` ` {
2757 if depth == 0 {
2758 return i
2759 }
2760 }
2761 else {}
2762 }
2763 }
2764 return -1
2765}
2766
2767fn generic_fn_type_param_head_is_name(head string, tail string) bool {
2768 if head.len == 0 || tail.len == 0 {
2769 return false
2770 }
2771 if head.starts_with('fn') || head.starts_with('&') || head.starts_with('[') {
2772 return false
2773 }
2774 if head in ['shared', 'atomic', 'chan', 'thread', 'map'] || head.contains('.') {
2775 return false
2776 }
2777 if types.is_builtin_type_name(head) {
2778 return false
2779 }
2780 return (head[0] >= `a` && head[0] <= `z`) || head[0] == `_`
2781}
2782
2783// subst_type substitutes generic placeholders in a type-text using the currently
2784// active generic parameter names (so non-canonical params resolve by name). Falls
2785// back to positional substitution when no params are active.
2786fn (t &Transformer) subst_type(typ string, args []string) string {
2787 return substitute_generic_type_text_with_params(typ, args, t.active_generic_params)
2788}
2789
2790// subst_node_value is the param-aware counterpart of substitute_generic_node_value.
2791fn (t &Transformer) subst_node_value(node flat.Node, args []string) string {
2792 match node.kind {
2793 .call, .array_init, .struct_init, .cast_expr, .as_expr, .sizeof_expr, .typeof_expr,
2794 .is_expr, .type_decl, .field_decl, .param {
2795 return t.subst_type(node.value, args)
2796 }
2797 .comptime_if {
2798 return t.subst_comptime_type_condition(node.value, args)
2799 }
2800 else {
2801 return node.value
2802 }
2803 }
2804}
2805
2806fn (t &Transformer) subst_comptime_type_condition(cond string, args []string) string {
2807 clean := cond.trim_space()
2808 if clean.starts_with('(') {
2809 end := comptime_condition_matching_paren(clean, 0)
2810 if end == clean.len - 1 {
2811 inner := t.subst_comptime_type_condition(clean[1..clean.len - 1], args)
2812 return '(${inner})'
2813 }
2814 }
2815 or_idx := comptime_condition_top_level_index(clean, '||')
2816 if or_idx >= 0 {
2817 left := t.subst_comptime_type_condition(clean[..or_idx], args)
2818 right := t.subst_comptime_type_condition(clean[or_idx + 2..], args)
2819 return '${left} || ${right}'
2820 }
2821 and_idx := comptime_condition_top_level_index(clean, '&&')
2822 if and_idx >= 0 {
2823 left := t.subst_comptime_type_condition(clean[..and_idx], args)
2824 right := t.subst_comptime_type_condition(clean[and_idx + 2..], args)
2825 return '${left} && ${right}'
2826 }
2827 for op in [' !is ', ' is '] {
2828 op_idx := comptime_condition_top_level_index(clean, op)
2829 if op_idx >= 0 {
2830 left := clean[..op_idx].trim_space()
2831 right := clean[op_idx + op.len..].trim_space()
2832 return '${t.subst_type(left, args)}${op}${t.subst_type(right, args)}'
2833 }
2834 }
2835 if clean.starts_with('!') {
2836 inner_raw := clean[1..].trim_space()
2837 inner := t.subst_comptime_type_condition(inner_raw, args)
2838 if inner_raw.starts_with('(') {
2839 return '!(${inner})'
2840 }
2841 return '!${inner}'
2842 }
2843 return clean
2844}
2845
2846// active_generic_param_index returns the position of a placeholder name within the
2847// active generic params, or the positional fallback when none are active.
2848fn (t &Transformer) active_generic_param_index(name string) int {
2849 for i, p in t.active_generic_params {
2850 if p == name {
2851 return i
2852 }
2853 }
2854 return generic_param_index(name)
2855}
2856
2857fn specialized_generic_fn_value(value string, args []string) string {
2858 if value.contains('.') {
2859 receiver := value.all_before_last('.')
2860 method := value.all_after_last('.')
2861 base, _, ok := generic_app_parts(receiver)
2862 if ok {
2863 return '${base}[${generic_type_args_short(args)}].${method}'
2864 }
2865 return '${receiver}[${generic_type_args_short(args)}].${method}'
2866 }
2867 return '${value}_T_${generic_type_suffixes(args)}'
2868}
2869
2870fn generic_type_args_short(args []string) string {
2871 mut parts := []string{cap: args.len}
2872 for arg in args {
2873 parts << generic_type_arg_short(arg)
2874 }
2875 return parts.join(', ')
2876}
2877
2878fn generic_type_arg_short(type_arg string) string {
2879 clean := type_arg.trim_space()
2880 // Function-type args (`fn (A, B) R`) and other compound types cannot appear
2881 // verbatim in a C identifier and must not be naively shortened by the last
2882 // `.` (which would truncate `fn(...) mod.R` to `R)`). Reduce them to a
2883 // deterministic sanitized fragment instead.
2884 if clean.contains('(') || clean.contains(' ') {
2885 return sanitize_type_name_fragment(clean)
2886 }
2887 if clean.contains('.') {
2888 return clean.all_after_last('.')
2889 }
2890 return clean
2891}
2892
2893// sanitize_type_name_fragment reduces an arbitrary type text (notably a function
2894// type) to a deterministic fragment that is a valid C identifier piece: module
2895// qualifiers are dropped, `[]`/`&` become readable prefixes, and every other run
2896// of non-identifier characters collapses to a single underscore.
2897fn sanitize_type_name_fragment(typ string) string {
2898 mut out := []u8{}
2899 mut prev_us := false
2900 mut i := 0
2901 for i < typ.len {
2902 c := typ[i]
2903 if (c >= `A` && c <= `Z`) || (c >= `a` && c <= `z`) || (c >= `0` && c <= `9`) {
2904 out << c
2905 prev_us = false
2906 i++
2907 } else if c == `[` && i + 1 < typ.len && typ[i + 1] == `]` {
2908 for ch in 'Array_'.bytes() {
2909 out << ch
2910 }
2911 prev_us = false
2912 i += 2
2913 } else if c == `&` {
2914 for ch in 'ptr_'.bytes() {
2915 out << ch
2916 }
2917 prev_us = false
2918 i++
2919 } else if c == `.` {
2920 // Drop the preceding module qualifier (everything emitted since the
2921 // last separator), keeping only the unqualified name.
2922 for out.len > 0 {
2923 last := out[out.len - 1]
2924 if (last >= `A` && last <= `Z`) || (last >= `a` && last <= `z`)
2925 || (last >= `0` && last <= `9`) {
2926 out.delete_last()
2927 } else {
2928 break
2929 }
2930 }
2931 i++
2932 } else {
2933 if !prev_us {
2934 out << `_`
2935 prev_us = true
2936 }
2937 i++
2938 }
2939 }
2940 mut s := out.bytestr()
2941 for s.starts_with('_') {
2942 s = s[1..]
2943 }
2944 for s.ends_with('_') {
2945 s = s[..s.len - 1]
2946 }
2947 return s
2948}
2949
2950fn generic_type_suffixes(args []string) string {
2951 mut parts := []string{cap: args.len}
2952 for arg in args {
2953 parts << c_name(generic_type_arg_short(arg).replace('[]', 'Array_').replace('&', 'ptr_'))
2954 }
2955 return parts.join('_')
2956}
2957
2958fn generic_param_index(name string) int {
2959 return match name {
2960 'T', 'A', 'K', 'X' { 0 }
2961 'U', 'B', 'V', 'Y' { 1 }
2962 'C', 'W', 'Z' { 2 }
2963 else { 0 }
2964 }
2965}
2966
2967fn is_generic_fn_placeholder_name(typ string) bool {
2968 clean := typ.trim_space()
2969 if clean.contains('.') {
2970 return is_generic_fn_placeholder_name(clean.all_after_last('.'))
2971 }
2972 return clean.len == 1 && clean[0] >= `A` && clean[0] <= `Z`
2973}
2974
2975fn (t &Transformer) generic_args_have_placeholders(args []string) bool {
2976 for arg in args {
2977 if t.generic_arg_is_unresolved(arg) {
2978 return true
2979 }
2980 }
2981 return false
2982}
2983
2984fn (t &Transformer) generic_arg_is_unresolved(arg string) bool {
2985 clean := arg.trim_space()
2986 if clean.len == 0 || clean in ['unknown', 'void', 'generic'] {
2987 return true
2988 }
2989 if is_generic_fn_placeholder_name(clean) {
2990 // A one-letter uppercase name is only an unresolved generic placeholder
2991 // when it does not name a real declared concrete type. `Box[A]` where
2992 // `struct A` exists is a concrete instantiation that must be materialized.
2993 return !t.is_known_concrete_type_name(clean)
2994 }
2995 if clean.starts_with('&') {
2996 return t.generic_arg_is_unresolved(clean[1..])
2997 }
2998 if clean.starts_with('?') || clean.starts_with('!') {
2999 return t.generic_arg_is_unresolved(clean[1..])
3000 }
3001 if clean.starts_with('...') {
3002 return t.generic_arg_is_unresolved(clean[3..])
3003 }
3004 if clean.starts_with('[]') {
3005 return t.generic_arg_is_unresolved(clean[2..])
3006 }
3007 if clean.starts_with('map[') {
3008 bracket_end := generic_matching_bracket(clean, 3)
3009 if bracket_end < clean.len {
3010 return t.generic_arg_is_unresolved(clean[4..bracket_end])
3011 || t.generic_arg_is_unresolved(clean[bracket_end + 1..])
3012 }
3013 }
3014 _, nested_args, ok := generic_app_parts(clean)
3015 if ok {
3016 for nested in nested_args {
3017 if t.generic_arg_is_unresolved(nested) {
3018 return true
3019 }
3020 }
3021 }
3022 return false
3023}
3024
3025// is_known_concrete_type_name reports whether `name` refers to an already
3026// declared concrete type (struct, sum type, enum, interface or alias), so that
3027// one-letter type names like `A` are not mistaken for generic placeholders.
3028fn (t &Transformer) is_known_concrete_type_name(name string) bool {
3029 if t.type_name_is_declared(name) {
3030 return true
3031 }
3032 if !name.contains('.') {
3033 if t.cur_module.len > 0 && t.cur_module != 'main' && t.cur_module != 'builtin'
3034 && t.type_name_is_declared('${t.cur_module}.${name}') {
3035 return true
3036 }
3037 if t.type_name_is_declared('main.${name}') {
3038 return true
3039 }
3040 }
3041 return false
3042}
3043
3044fn (t &Transformer) type_name_is_declared(name string) bool {
3045 if name in t.structs || name in t.sum_types || name in t.enum_types {
3046 return true
3047 }
3048 if !isnil(t.tc) {
3049 if name in t.tc.structs || name in t.tc.sum_types || name in t.tc.enum_names
3050 || name in t.tc.interface_names || name in t.tc.type_aliases {
3051 return true
3052 }
3053 }
3054 return false
3055}
3056
3057fn generic_type_arg_from_suffix(suffix string) string {
3058 if suffix.len == 0 {
3059 return ''
3060 }
3061 return match suffix {
3062 'v_int' { 'int' }
3063 'v_u8' { 'u8' }
3064 'v_u16' { 'u16' }
3065 'v_u32' { 'u32' }
3066 'v_u64' { 'u64' }
3067 'v_i8' { 'i8' }
3068 'v_i16' { 'i16' }
3069 'v_i32' { 'i32' }
3070 'v_i64' { 'i64' }
3071 'v_f32' { 'f32' }
3072 'v_f64' { 'f64' }
3073 'Array_u8' { '[]u8' }
3074 else { suffix.replace('__', '.') }
3075 }
3076}
3077
3078fn generic_fn_spec_key(decl_key string, args []string) string {
3079 return '${decl_key}[${args.join(', ')}]'
3080}
3081
3082fn (t &Transformer) ident_is_import_alias(name string) bool {
3083 if isnil(t.tc) {
3084 return false
3085 }
3086 return name in t.tc.imports || file_import_key(t.tc.cur_file, name) in t.tc.file_imports
3087}
3088
3089fn (t &Transformer) import_alias_module(name string) string {
3090 if isnil(t.tc) {
3091 return name
3092 }
3093 if mod := t.tc.file_imports[file_import_key(t.tc.cur_file, name)] {
3094 return mod
3095 }
3096 return t.tc.imports[name] or { name }
3097}
3098
3099fn file_import_key(file string, alias string) string {
3100 return '${file}\n${alias}'
3101}
3102