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