v2 / vlib / v / ast / table.v
4837 lines · 4634 sloc · 143.42 KB · 2efab47ee393d97eb0faf8d75e7f11796310aad6
Raw
1// Copyright (c) 2019-2024 Alexander Medvednikov. All rights reserved.
2// Use of this source code is governed by an MIT license
3// that can be found in the LICENSE file.
4@[has_globals]
5module ast
6
7import v.cflag
8import v.util
9import v.token
10
11@[heap; minify]
12pub struct UsedFeatures {
13pub mut:
14 dump bool // filled in by markused
15 anon_fn bool // fn () { }
16 auto_str bool // auto str fns
17 auto_str_ptr bool // auto str fns for ptr type
18 auto_str_arr bool // auto str fns for array
19 arr_prepend bool // arr.prepend()
20 arr_insert bool // arr.insert()
21 arr_first bool // arr.first()
22 arr_last bool // arr.last()
23 arr_pop_left bool // arr.pop_left()
24 arr_pop bool // arr.pop()
25 arr_delete bool // arr.delete()
26 arr_reverse bool // arr.reverse()
27 arr_map bool // []map[key]value
28 print_options bool // print option type
29 safe_int bool // needs safe int comparison
30 print_types map[int]bool // print() idx types
31 used_fns map[string]bool // filled in by markused
32 used_consts map[string]bool // filled in by markused
33 used_globals map[string]bool // filled in by markused
34 used_syms map[int]bool // filled in by markused
35 referenced_fns map[string]bool // filled in by the checker
36 referenced_consts map[string]bool // filled in by the checker
37 used_veb_types []Type // veb context types, filled in by checker
38 used_maps int // how many times maps were used, filled in by markused
39 used_none int // how many times `none` was used, filled in by markused
40 used_closures int // number of used closures, either directly with `fn [state] () {}`, or indirectly (though `instance.method` promotions)
41 // json bool // json is imported
42 comptime_calls map[string]bool // resolved name to call on comptime
43 comptime_syms map[Type]bool // resolved syms (generic)
44 //
45 used_attr_noreturn bool // @[noreturn]
46 used_attr_hidden bool // @[hidden]
47 used_attr_weak bool // @[weak]
48}
49
50@[unsafe]
51pub fn (mut uf UsedFeatures) free() {
52 unsafe {
53 uf.print_types.free()
54 uf.used_fns.free()
55 uf.used_consts.free()
56 uf.used_globals.free()
57 uf.referenced_fns.free()
58 uf.referenced_consts.free()
59 uf.used_veb_types.free()
60 }
61}
62
63@[heap; minify]
64pub struct Table {
65mut:
66 parsing_type string // name of the type to enable recursive type parsing
67pub mut:
68 type_symbols []&TypeSymbol
69 type_idxs map[string]int
70 fns map[string]Fn
71 iface_types map[string][]Type
72 dumps map[int]string // needed for efficiently generating all _v_dump_expr_TNAME() functions
73 imports []string // List of all imports
74 modules []string // Topologically sorted list of all modules registered by the application
75 global_scope &Scope = unsafe { nil }
76 cflags []cflag.CFlag
77 redefined_fns []string
78 fn_generic_types map[string][][]Type // for generic functions
79 interfaces map[int]InterfaceDecl
80 sumtypes map[int]SumTypeDecl
81 cmod_prefix string // needed for ast.type_to_str(Type) while vfmt; contains `os.`
82 is_fmt bool
83 used_features &UsedFeatures = &UsedFeatures{} // filled in by the builder via markused module, when pref.skip_unused = true;
84 veb_res_idx_cache int // Cache of `veb.Result` type
85 veb_ctx_idx_cache int // Cache of `veb.Context` type
86 panic_handler FnPanicHandler = default_table_panic_handler
87 panic_userdata voidptr = unsafe { nil } // can be used to pass arbitrary data to panic_handler;
88 panic_npanics int
89 cur_fn &FnDecl = unsafe { nil } // previously stored in Checker.cur_fn and Gen.cur_fn
90 cur_lambda &LambdaExpr = unsafe { nil } // current lambda node
91 cur_concrete_types []Type // current concrete types, e.g. [int, string]
92 gostmts int // how many `go` statements there were in the parsed files.
93 // When table.gostmts > 0, __VTHREADS__ is defined, which can be checked with `$if threads {`
94 enum_decls map[string]EnumDecl
95 vls_info map[string]VlsInfo
96 module_deprecated map[string]bool
97 module_attrs map[string][]Attr // module attributes
98 builtin_pub_fns map[string]bool
99 pointer_size int
100 // cache for type_to_str_using_aliases
101 cached_type_to_str shared map[u64]string
102 // counters and maps for anon structs and unions, to avoid name conflicts.
103 anon_struct_names map[string]int // anon struct name -> struct sym idx
104 anon_struct_counter int
105 anon_union_names map[string]int // anon union name -> union sym idx
106 anon_union_counter int
107 comptime_is_true map[string]ComptTimeCondResult // The evaluate cond results for different generic types combination, such as `comptime_is_true['T=int,X=string|main.v|pos ...'] = {true, '!DEFINED(WINDOWS)'}`
108 new_int bool // use 64bit/32bit platform dependent `int`
109 new_int_fmt_fix bool // vfmt will fix `int` to `i32`
110 export_names map[string]string // @[export] names
111 filelist []string // all files list
112}
113
114pub struct ComptTimeCondResult {
115pub mut:
116 val bool
117 c_str string
118}
119
120pub struct VlsInfo {
121pub mut:
122 pos token.Pos
123 doc string // documentation
124}
125
126// used by vls to avoid leaks
127// TODO: remove manual memory management
128@[unsafe]
129pub fn (mut t Table) free() {
130 unsafe {
131 for s in t.type_symbols {
132 s.free()
133 }
134 t.type_symbols.free()
135 t.type_idxs.free()
136 t.fns.free()
137 t.dumps.free()
138 t.imports.free()
139 t.modules.free()
140 t.cflags.free()
141 t.redefined_fns.free()
142 t.fn_generic_types.free()
143 t.cmod_prefix.free()
144 t.used_features.free()
145 }
146}
147
148pub const fn_type_escape_seq = ['...', 'variadic_', '&', 'ref_', '[', '_T_', ']', '', ', ', '_',
149 ',', '_', '(', '_', ')', '', ' ', '_', '?', 'option_', '!', 'result_', '|', '_or_', '<', '_',
150 '>', '']
151pub const map_cname_escape_seq = ['[', '_T_', ', ', '_', ']', '']
152
153pub type FnPanicHandler = fn (&Table, string)
154
155fn default_table_panic_handler(_t &Table, message string) {
156 panic(message)
157}
158
159pub fn (t &Table) panic(message string) {
160 mut mt := unsafe { &Table(t) }
161 mt.panic_npanics++
162 t.panic_handler(t, message)
163}
164
165pub fn new_table() &Table {
166 mut t := &Table{
167 global_scope: &Scope{
168 parent: unsafe { nil }
169 }
170 cur_fn: unsafe { nil }
171 }
172 t.register_builtin_type_symbols()
173 t.is_fmt = true
174 global_table = t
175 return t
176}
177
178__global global_table = &Table(unsafe { nil })
179
180// used to compare fn's & for naming anon fn's
181pub fn (t &Table) fn_type_signature(f &Fn) string {
182 mut sig := ''
183 for i, arg in f.params {
184 sig += t.fn_type_signature_part(f, i, arg)
185 if i < f.params.len - 1 {
186 sig += '_'
187 }
188 }
189 if f.is_c_variadic {
190 if sig.len > 0 {
191 sig += '_'
192 }
193 sig += 'c_variadic'
194 }
195 if f.return_type != 0 && f.return_type != void_type {
196 sig += '__${util.no_dots(t.type_to_str(f.return_type)).replace_each(fn_type_escape_seq)}'
197 }
198 return sig
199}
200
201fn (t &Table) fn_type_signature_part(f &Fn, i int, arg Param) string {
202 mut typ := arg.typ
203 mut sig := ''
204 if arg.is_mut {
205 if typ.is_ptr() {
206 typ = typ.deref()
207 }
208 sig += 'mut '
209 }
210 if i == f.params.len - 1 && f.is_variadic && !f.is_c_variadic {
211 sig += '...'
212 }
213 sig += t.type_to_str(typ)
214 return util.no_dots(sig).replace_each(fn_type_escape_seq)
215}
216
217// fn_type_source_signature generates the signature of a function which looks like in the V source
218pub fn (t &Table) fn_type_source_signature(f &Fn) string {
219 import_aliases := map[string]string{}
220 mut sig := '('
221 for i, arg in f.params {
222 mut typ := arg.typ
223 if arg.is_mut {
224 if typ.is_ptr() {
225 typ = typ.deref()
226 }
227 sig += 'mut '
228 }
229 // Note: arg name is only added for fmt, else it would causes errors with generics
230 if t.is_fmt && arg.name != '' {
231 sig += '${arg.name} '
232 }
233 if i == f.params.len - 1 && f.is_variadic && !f.is_c_variadic {
234 sig += '...'
235 }
236 sig += t.type_to_str_using_aliases(typ, import_aliases)
237 if i < f.params.len - 1 {
238 sig += ', '
239 }
240 }
241 if f.is_c_variadic {
242 if f.params.len > 0 {
243 sig += ', '
244 }
245 sig += '...'
246 }
247 sig += ')'
248 if f.return_type == ovoid_type {
249 sig += ' ?'
250 } else if f.return_type == rvoid_type {
251 sig += ' !'
252 } else if f.return_type != void_type && f.return_type != 0 {
253 sig += ' ${t.type_to_str_using_aliases(f.return_type, import_aliases)}'
254 }
255 return sig
256}
257
258pub fn (t &Table) is_same_method(f &Fn, func &Fn) string {
259 if f.return_type != func.return_type {
260 s := t.type_to_str(f.return_type)
261 return 'expected return type `${s}`'
262 }
263 if f.params.len != func.params.len {
264 return 'expected ${f.params.len} parameter(s), not ${func.params.len}'
265 }
266
267 // interface name() other mut name() : error
268
269 for i in 0 .. f.params.len {
270 // don't check receiver for `.typ`
271 has_unexpected_type := i > 0
272 && t.unaliased_type(f.params[i].typ) != t.unaliased_type(func.params[i].typ)
273 // temporary hack for JS ifaces
274 lsym := t.sym(f.params[i].typ)
275 rsym := t.sym(func.params[i].typ)
276 if lsym.language == .js && rsym.language == .js {
277 return ''
278 }
279 has_unexpected_sharetype := f.params[i].is_shared != func.params[i].is_shared
280 || f.params[i].is_atomic != func.params[i].is_atomic
281 has_unexpected_mutability := !f.params[i].is_mut && func.params[i].is_mut
282
283 if has_unexpected_type || has_unexpected_sharetype || has_unexpected_mutability {
284 exps := t.type_to_str(f.params[i].typ)
285 gots := t.type_to_str(func.params[i].typ)
286 if has_unexpected_type {
287 return 'expected `${exps}`, not `${gots}` for parameter ${i}'
288 } else if has_unexpected_sharetype {
289 return 'expected `${t.param_type_with_specifier(f.params[i], i == 0)}`, not `${t.param_type_with_specifier(func.params[i],
290 i == 0)}` for parameter ${i}'
291 } else {
292 return 'expected `${exps}` which is immutable, not `mut ${gots}`'
293 }
294 }
295 }
296 return ''
297}
298
299fn (t &Table) param_type_with_specifier(p Param, is_receiver bool) string {
300 mut parts := []string{}
301 if p.is_mut {
302 parts << 'mut'
303 }
304 if p.is_shared {
305 parts << 'shared'
306 }
307 if p.is_atomic {
308 parts << 'atomic'
309 }
310 mut ptyp := p.typ.clear_flags(.shared_f, .atomic_f)
311 if is_receiver && ptyp.is_ptr() {
312 ptyp = ptyp.deref()
313 }
314 parts << t.type_to_str(ptyp)
315 return parts.join(' ')
316}
317
318// is_compatible_auto_str_method returns true when `method` matches the compiler-generated
319// `str() string` signature.
320pub fn (t &Table) is_compatible_auto_str_method(method &Fn) bool {
321 return method.name == 'str' && method.return_type == string_type && method.params.len == 1
322 && !method.params[0].is_mut
323}
324
325// type_has_implicit_str_method returns true when `typ` can satisfy `method`
326// through the compiler-generated `str() string`.
327pub fn (t &Table) type_has_implicit_str_method(typ Type, method &Fn) bool {
328 if !t.is_compatible_auto_str_method(method) {
329 return false
330 }
331 if typ.has_option_or_result() {
332 return false
333 }
334 sym := t.sym(typ.clear_flag(.variadic))
335 if sym.has_method_with_generic_parent('str') {
336 return false
337 }
338 if sym.kind == .char && typ.nr_muls() == 0 {
339 return false
340 }
341 if sym.kind == .function {
342 return false
343 }
344 if typ.is_any_kind_of_pointer() || typ in voidptr_types || typ in byteptr_types
345 || typ in charptr_types || typ == nil_type {
346 return true
347 }
348 match sym.info {
349 Alias, Array, ArrayFixed, Enum, FnType, Struct, Map, MultiReturn, SumType, Chan, Thread {
350 return sym.name != 'nil'
351 }
352 else {
353 return sym.kind in [.i8, .i16, .i32, .int, .i64, .isize, .u8, .u16, .u32, .u64, .usize,
354 .f32, .f64, .rune, .bool, .string, .generic_inst]
355 }
356 }
357}
358
359pub fn (t &Table) find_fn(name string) ?Fn {
360 if f := t.fns[name] {
361 return f
362 }
363 return none
364}
365
366pub fn (t &Table) known_fn(name string) bool {
367 t.find_fn(name) or { return false }
368 return true
369}
370
371pub fn (mut t Table) register_fn(new_fn Fn) {
372 t.fns[new_fn.name] = new_fn
373 if new_fn.is_pub && new_fn.mod == 'builtin' {
374 t.builtin_pub_fns[new_fn.name] = true
375 }
376}
377
378pub fn (mut t Table) register_interface(idecl InterfaceDecl) {
379 t.interfaces[idecl.typ] = idecl
380}
381
382pub fn (mut t Table) register_sumtype(sumtyp SumTypeDecl) {
383 t.sumtypes[sumtyp.typ] = sumtyp
384}
385
386pub fn (mut t TypeSymbol) register_method(new_fn Fn) int {
387 // returns a method index, stored in the ast.FnDecl
388 // for faster lookup in the checker's fn_decl method
389 t.methods << new_fn
390 return t.methods.len - 1
391}
392
393pub fn (mut t TypeSymbol) update_method(f Fn) int {
394 for i, m in t.methods {
395 if m.name == f.name {
396 t.methods[i] = f
397 return i
398 }
399 }
400 return -1
401}
402
403pub fn (t &Table) register_aggregate_method(mut sym TypeSymbol, name string) !Fn {
404 if sym.kind != .aggregate {
405 t.panic('table.register_aggregate_method: sym.name: ${sym.name}, sym.kind: ${sym.kind} is not an aggregate, name: ${name}')
406 }
407 agg_info := sym.info as Aggregate
408 // an aggregate always has at least 2 types
409 mut found_once := false
410 mut new_fn := Fn{}
411 for typ in agg_info.types {
412 ts := t.sym(typ)
413 if type_method := ts.find_method(name) {
414 if !found_once {
415 found_once = true
416 new_fn = type_method
417 } else if !new_fn.method_equals(type_method) {
418 return error('method `${t.type_to_str(typ)}.${name}` signature is different')
419 }
420 } else {
421 return error('unknown method: `${t.type_to_str(typ)}.${name}`')
422 }
423 }
424 // register the method in the aggregate, so lookup is faster next time
425 sym.register_method(new_fn)
426 return new_fn
427}
428
429pub fn (t &Table) has_method(s &TypeSymbol, name string) bool {
430 t.find_method(s, name) or { return false }
431 return true
432}
433
434// get_type_methods returns methods available on `typ`.
435// For aliases, it includes alias-defined methods first, then inherited parent methods.
436pub fn (t &Table) get_type_methods(typ Type) []Fn {
437 mut ts := t.sym(typ)
438 mut methods := ts.get_methods()
439 if ts.kind != .alias {
440 return methods
441 }
442 mut seen_method_names := map[string]bool{}
443 for method in methods {
444 seen_method_names[method.name] = true
445 }
446 for ts.parent_idx != 0 {
447 ts = t.type_symbols[ts.parent_idx]
448 for method in ts.get_methods() {
449 if method.name !in seen_method_names {
450 methods << method
451 seen_method_names[method.name] = true
452 }
453 }
454 }
455 return methods
456}
457
458// find_method searches from current type up through each parent looking for method
459pub fn (t &Table) find_method(s &TypeSymbol, name string) !Fn {
460 mut ts := unsafe { s }
461 for {
462 if method := ts.find_method(name) {
463 return method
464 }
465 if ts.kind == .generic_inst {
466 parent_sym := t.sym(new_type((ts.info as GenericInst).parent_idx))
467 if method := parent_sym.find_method_with_generic_parent(name) {
468 return method
469 }
470 return error('unknown method')
471 }
472 if ts.kind == .aggregate {
473 if method := t.register_aggregate_method(mut ts, name) {
474 return method
475 } else {
476 return err
477 }
478 }
479 if ts.parent_idx == 0 {
480 // Also try Struct/Interface/SumType parent_type for generic concrete types
481 // whose parent_idx is 0 but have parent_type set.
482 has_parent_type := (ts.kind == .struct && (ts.info as Struct).parent_type != 0)
483 || (ts.kind == .interface && (ts.info as Interface).parent_type != 0)
484 || (ts.kind == .sum_type && (ts.info as SumType).parent_type != 0)
485 if has_parent_type {
486 if method := ts.find_method_with_generic_parent(name) {
487 return method
488 }
489 }
490 break
491 }
492 ts = t.type_symbols[ts.parent_idx]
493 }
494 return error('unknown method')
495}
496
497@[params]
498pub struct GetEmbedsOptions {
499pub:
500 preceding []Type
501}
502
503// get_embeds returns all nested embedded structs
504// the hierarchy of embeds is returned as a list
505pub fn (t &Table) get_embeds(sym &TypeSymbol, options GetEmbedsOptions) [][]Type {
506 mut embeds := [][]Type{}
507 unalias_sym := if sym.info is Alias { t.sym(sym.info.parent_type) } else { sym }
508 if unalias_sym.info is Struct {
509 for embed in unalias_sym.info.embeds {
510 embed_sym := t.sym(embed)
511 mut preceding := options.preceding.clone()
512 preceding << embed
513 embeds << t.get_embeds(embed_sym, preceding: preceding)
514 }
515 if unalias_sym.info.embeds.len == 0 && options.preceding.len > 0 {
516 embeds << options.preceding
517 }
518 }
519 return embeds
520}
521
522pub fn (t &Table) find_method_from_embeds(sym &TypeSymbol, method_name string) !(Fn, []Type) {
523 if sym.info is Struct {
524 mut found_methods := []Fn{}
525 mut embed_of_found_methods := []Type{}
526 for embed in sym.info.embeds {
527 embed_sym := t.sym(embed)
528 if m := embed_sym.find_method_with_generic_parent(method_name) {
529 found_methods << m
530 embed_of_found_methods << embed
531 } else {
532 method, types := t.find_method_from_embeds(embed_sym, method_name) or { continue }
533 found_methods << method
534 embed_of_found_methods << embed
535 embed_of_found_methods << types
536 }
537 }
538 if found_methods.len == 1 {
539 return found_methods[0], embed_of_found_methods
540 } else if found_methods.len > 1 {
541 return error('ambiguous method `${method_name}`')
542 }
543 } else if sym.info is Interface {
544 mut found_methods := []Fn{}
545 mut embed_of_found_methods := []Type{}
546 for embed in sym.info.embeds {
547 embed_sym := t.sym(embed)
548 if m := embed_sym.find_method_with_generic_parent(method_name) {
549 found_methods << m
550 embed_of_found_methods << embed
551 } else {
552 method, types := t.find_method_from_embeds(embed_sym, method_name) or { continue }
553 found_methods << method
554 embed_of_found_methods << embed
555 embed_of_found_methods << types
556 }
557 }
558 if found_methods.len == 1 {
559 return found_methods[0], embed_of_found_methods
560 } else if found_methods.len > 1 {
561 return error('ambiguous method `${method_name}`')
562 }
563 } else if sym.info is Aggregate {
564 for typ in sym.info.types {
565 agg_sym := t.sym(typ)
566 method, embed_types := t.find_method_from_embeds(agg_sym, method_name) or { continue }
567 if embed_types.len != 0 {
568 return method, embed_types
569 }
570 }
571 }
572 return error('')
573}
574
575// find_method_with_embeds searches for a given method, also looking through embedded fields
576pub fn (t &Table) find_method_with_embeds(sym &TypeSymbol, method_name string) !Fn {
577 if func := t.find_method(sym, method_name) {
578 return func
579 } else {
580 // look for embedded field
581 func, _ := t.find_method_from_embeds(sym, method_name) or { return err }
582 return func
583 }
584}
585
586// find_enum_field_val finds the possible int value from the enum name and enum field
587// (returns `none` if the value cannot be resolved at compile time)
588pub fn (t &Table) find_enum_field_val(name string, field_ string) ?i64 {
589 mut val := i64(0)
590 enum_decl := t.enum_decls[name]
591 mut enum_vals := []i64{}
592 for field in enum_decl.fields {
593 if field.name == field_ {
594 if field.has_expr {
595 if field.expr is IntegerLiteral {
596 val = field.expr.val.i64()
597 break
598 }
599 return none
600 } else {
601 if enum_vals.len > 0 {
602 val = enum_vals.last() + 1
603 } else {
604 val = 0
605 }
606 break
607 }
608 } else {
609 if field.has_expr {
610 if field.expr is IntegerLiteral {
611 enum_vals << field.expr.val.i64()
612 } else {
613 return none
614 }
615 } else {
616 if enum_vals.len > 0 {
617 enum_vals << enum_vals.last() + 1
618 } else {
619 enum_vals << 0
620 }
621 }
622 }
623 }
624 return if enum_decl.is_flag { i64(u64(1) << u64(val)) } else { val }
625}
626
627pub fn (t &Table) get_enum_field_names(name string) []string {
628 enum_decl := t.enum_decls[name]
629 mut field_names := []string{}
630 for field in enum_decl.fields {
631 field_names << field.name
632 }
633 return field_names
634}
635
636pub fn (t &Table) get_enum_field_vals(name string) []i64 {
637 enum_decl := t.enum_decls[name]
638 mut enum_vals := []i64{}
639 mut last_val := i64(0)
640 for field in enum_decl.fields {
641 if field.has_expr {
642 if field.expr is IntegerLiteral {
643 enum_vals << field.expr.val.i64()
644 last_val = field.expr.val.i64()
645 }
646 } else {
647 if enum_vals.len > 0 {
648 enum_vals << last_val + 1
649 last_val++
650 } else {
651 enum_vals << 0
652 }
653 }
654 }
655 return enum_vals
656}
657
658pub fn (t &Table) get_embed_methods(sym &TypeSymbol) []Fn {
659 mut methods := []Fn{}
660 if sym.info is Struct {
661 for embed in sym.info.embeds {
662 embed_sym := t.sym(embed)
663 methods << embed_sym.methods
664 methods << t.get_embed_methods(embed_sym)
665 }
666 }
667 return methods
668}
669
670fn (t &Table) register_aggregate_field(mut sym TypeSymbol, name string) !StructField {
671 if sym.kind != .aggregate {
672 t.panic('table.register_aggregate_field: sym.name: ${sym.name}, sym.kind: ${sym.kind} is not an aggregate, name: ${name}')
673 }
674 mut agg_info := sym.info as Aggregate
675 // an aggregate always has at least 2 types
676 mut found_once := false
677 mut new_field := StructField{}
678 for typ in agg_info.types {
679 ts := t.sym(typ)
680 if type_field := t.find_field(ts, name) {
681 if !found_once {
682 found_once = true
683 new_field = type_field
684 } else if new_field.typ != type_field.typ {
685 return error('field `${t.type_to_str(typ)}.${name}` type is different')
686 }
687 new_field = StructField{
688 ...new_field
689 is_mut: new_field.is_mut && type_field.is_mut
690 is_pub: new_field.is_pub && type_field.is_pub
691 }
692 } else {
693 return error('type `${t.type_to_str(typ)}` has no field or method `${name}`')
694 }
695 }
696 agg_info.fields << new_field
697 return new_field
698}
699
700pub fn (t &Table) struct_has_field(struct_ &TypeSymbol, name string) bool {
701 t.find_field(struct_, name) or { return false }
702 return true
703}
704
705// struct_fields returns all fields including fields from embeds
706// use this instead symbol.info.fields to get all fields
707pub fn (t &Table) struct_fields(sym &TypeSymbol) []StructField {
708 mut fields := []StructField{}
709 if sym.info is Struct {
710 fields << sym.info.fields
711 for embed in sym.info.embeds {
712 embed_sym := t.sym(embed)
713 fields << t.struct_fields(embed_sym)
714 }
715 }
716 return fields
717}
718
719// search from current type up through each parent looking for field
720pub fn (t &Table) find_field(s &TypeSymbol, name string) !StructField {
721 mut ts := unsafe { s }
722 for {
723 match mut ts.info {
724 Struct {
725 if field := ts.info.find_field(name) {
726 return field
727 }
728 }
729 Aggregate {
730 if field := ts.info.find_field(name) {
731 return field
732 }
733 field := t.register_aggregate_field(mut ts, name) or { return err }
734 return field
735 }
736 Interface {
737 if field := ts.info.find_field(name) {
738 return field
739 }
740 }
741 GenericInst {
742 parent_sym := t.sym(new_type(ts.info.parent_idx))
743 if field := t.find_field(parent_sym, name) {
744 match parent_sym.info {
745 Struct, Interface, SumType {
746 mut table := global_table
747 generic_names := parent_sym.info.generic_types.map(t.sym(it).name)
748 if generic_names.len == ts.info.concrete_types.len {
749 mut resolved_field := field
750 if ft := table.convert_generic_type(field.typ, generic_names,
751 ts.info.concrete_types)
752 {
753 resolved_field.typ = ft
754 }
755 if fut := table.convert_generic_type(field.unaliased_typ,
756 generic_names, ts.info.concrete_types)
757 {
758 resolved_field.unaliased_typ = fut
759 }
760 return resolved_field
761 }
762 }
763 else {}
764 }
765
766 return field
767 }
768 }
769 SumType {
770 t.resolve_common_sumtype_fields(mut ts)
771 if field := ts.info.find_sum_type_field(name) {
772 return field
773 }
774 missing_variants := t.find_missing_variants(ts.info, name)
775 return error('field `${name}` does not exist or have the same type in these sumtype `${ts.name}` variants: ${missing_variants}')
776 }
777 else {}
778 }
779
780 if ts.parent_idx == 0 {
781 break
782 }
783 ts = t.type_symbols[ts.parent_idx]
784 }
785 return error('')
786}
787
788// find_field_from_embeds tries to find a field in the nested embeds
789pub fn (t &Table) find_field_from_embeds(sym &TypeSymbol, field_name string) !(StructField, []Type) {
790 if sym.info is Struct {
791 mut found_fields := []StructField{}
792 mut embeds_of_found_fields := []Type{}
793 for embed in sym.info.embeds {
794 embed_sym := t.sym(embed)
795 if field := t.find_field(embed_sym, field_name) {
796 found_fields << field
797 embeds_of_found_fields << embed
798 } else {
799 field, types := t.find_field_from_embeds(embed_sym, field_name) or { continue }
800 found_fields << field
801 embeds_of_found_fields << embed
802 embeds_of_found_fields << types
803 }
804 }
805 if found_fields.len == 1 {
806 return found_fields[0], embeds_of_found_fields
807 } else if found_fields.len > 1 {
808 return error('ambiguous field `${field_name}`')
809 }
810 } else if sym.info is Aggregate {
811 for typ in sym.info.types {
812 agg_sym := t.sym(typ)
813 field, embed_types := t.find_field_from_embeds(agg_sym, field_name) or { continue }
814 if embed_types.len > 0 {
815 return field, embed_types
816 }
817 }
818 } else if sym.info is Alias {
819 unalias_sym := t.sym(sym.info.parent_type)
820 return t.find_field_from_embeds(unalias_sym, field_name)
821 }
822 return error('')
823}
824
825// find_field_with_embeds searches for a given field, also looking through embedded fields
826pub fn (t &Table) find_field_with_embeds(sym &TypeSymbol, field_name string) !StructField {
827 if field := t.find_field(sym, field_name) {
828 return field
829 } else {
830 // look for embedded field
831 first_err := err
832 field, _ := t.find_field_from_embeds(sym, field_name) or { return first_err }
833 return field
834 }
835}
836
837pub fn (t &Table) resolve_common_sumtype_fields(mut sym TypeSymbol) {
838 mut info := sym.info as SumType
839 if info.found_fields {
840 return
841 }
842 mut field_map := map[string]StructField{}
843 mut field_usages := map[string]int{}
844 for variant in info.variants {
845 mut v_sym := t.final_sym(variant)
846 fields := match mut v_sym.info {
847 Struct {
848 t.struct_fields(v_sym)
849 }
850 SumType {
851 t.resolve_common_sumtype_fields(mut v_sym)
852 v_sym.info.fields
853 }
854 else {
855 []StructField{}
856 }
857 }
858
859 for field in fields {
860 if field.name !in field_map {
861 field_map[field.name] = field
862 field_usages[field.name]++
863 } else if field.equals(field_map[field.name]) {
864 field_usages[field.name]++
865 }
866 }
867 }
868 for field, nr_definitions in field_usages {
869 if nr_definitions == info.variants.len {
870 info.fields << field_map[field]
871 }
872 }
873 info.found_fields = true
874 sym.info = info
875 if sym.idx > 0 {
876 mut mut_table := unsafe { &Table(t) }
877 mut_table.type_symbols[sym.idx].info = info
878 }
879}
880
881// find_single_field_variant returns a field that exists in exactly one aggregate or sumtype variant.
882pub fn (t &Table) find_single_field_variant(sym &TypeSymbol, field_name string) !(Type, StructField, []Type) {
883 variants := match sym.info {
884 Aggregate { sym.info.types }
885 SumType { sym.info.variants }
886 else { []Type{} }
887 }
888
889 if variants.len == 0 {
890 return error('')
891 }
892 mut found_variant := Type(0)
893 mut found_field := StructField{}
894 mut found_embed_types := []Type{}
895 for variant in variants {
896 variant_sym := t.final_sym(variant)
897 mut field := StructField{}
898 mut embed_types := []Type{}
899 if f := t.find_field(variant_sym, field_name) {
900 field = f
901 } else {
902 field, embed_types = t.find_field_from_embeds(variant_sym, field_name) or { continue }
903 }
904 if found_variant != 0 {
905 return error('')
906 }
907 found_variant = variant
908 found_field = field
909 found_embed_types = embed_types.clone()
910 }
911 if found_variant == 0 {
912 return error('')
913 }
914 return found_variant, found_field, found_embed_types
915}
916
917@[inline]
918pub fn (t &Table) find_type(name string) Type {
919 return idx_to_type(t.type_idxs[name])
920}
921
922@[inline]
923pub fn (t &Table) find_type_idx(name string) int {
924 return t.type_idxs[name]
925}
926
927@[inline]
928pub fn (t &Table) find_type_idx_fn_scoped(name string, scope &Scope) int {
929 if scope != unsafe { nil } {
930 idx := t.type_idxs['_${name}_${scope.start_pos}']
931 if idx != 0 {
932 return idx
933 }
934 }
935 return t.type_idxs[name]
936}
937
938@[inline]
939pub fn (t &Table) find_sym(name string) ?&TypeSymbol {
940 idx := t.type_idxs[name]
941 if idx > 0 {
942 return t.type_symbols[idx]
943 }
944 return none
945}
946
947@[inline]
948pub fn (t &Table) find_sym_and_type_idx(name string) (&TypeSymbol, int) {
949 idx := t.type_idxs[name]
950 if idx > 0 {
951 return t.type_symbols[idx], idx
952 }
953 return invalid_type_symbol, idx
954}
955
956pub const invalid_type_symbol = &TypeSymbol{
957 idx: invalid_type_idx
958 parent_idx: invalid_type_idx
959 language: .v
960 mod: 'builtin'
961 kind: .placeholder
962 name: 'InvalidType'
963 cname: 'InvalidType'
964 is_builtin: false
965}
966
967@[inline]
968pub fn (t &Table) sym_by_idx(idx int) &TypeSymbol {
969 return t.type_symbols[idx]
970}
971
972@[direct_array_access]
973pub fn (t &Table) sym(typ Type) &TypeSymbol {
974 idx := typ.idx()
975 if idx > 0 && idx < t.type_symbols.len {
976 return t.type_symbols[idx]
977 }
978 if idx == 0 || idx == 65535 || typ == invalid_type {
979 // invalid_type and idx=0 are used as sentinels during generic type resolution;
980 // return a safe placeholder instead of panicking.
981 return invalid_type_symbol
982 }
983 // this should never happen
984 t.panic('table.sym: invalid type (typ=${typ} idx=${idx}). Compiler bug. This should never happen. Please report the bug using `v bug file.v`.
985')
986 return invalid_type_symbol
987}
988
989// final_sym follows aliases until it gets to a "real" Type
990@[direct_array_access]
991pub fn (t &Table) final_sym(typ Type) &TypeSymbol {
992 mut idx := typ.idx()
993 if idx > 0 && idx < t.type_symbols.len {
994 cur_sym := t.type_symbols[idx]
995 if cur_sym.info is Alias {
996 idx = cur_sym.info.parent_type.idx()
997 }
998 return t.type_symbols[idx]
999 }
1000 if idx == 0 {
1001 return invalid_type_symbol
1002 }
1003 // this should never happen
1004 t.panic('table.final_sym: invalid type (typ=${typ} idx=${idx}). Compiler bug. This should never happen. Please report the bug using `v bug file.v`.')
1005 return invalid_type_symbol
1006}
1007
1008// final_type returns the underlying type, if the final type is an Enum it returns the enum defined type (int one) otherwise the aliased/real type is returned
1009pub fn (t &Table) final_type(typ Type) Type {
1010 mut idx := typ.idx()
1011 if idx > 0 && idx < t.type_symbols.len {
1012 cur_sym := t.type_symbols[idx]
1013 if cur_sym.info is Alias {
1014 idx = cur_sym.info.parent_type.idx()
1015 aliased_sym := t.type_symbols[idx]
1016 if aliased_sym.info is Enum {
1017 return aliased_sym.info.typ
1018 }
1019 return cur_sym.info.parent_type
1020 } else if cur_sym.info is Enum {
1021 return cur_sym.info.typ
1022 }
1023 }
1024 return typ
1025}
1026
1027@[inline]
1028pub fn (t &Table) get_type_name(typ Type) string {
1029 return t.sym(typ).name
1030}
1031
1032@[inline]
1033pub fn (t &Table) get_final_type_name(typ Type) string {
1034 return t.final_sym(typ).name
1035}
1036
1037@[inline]
1038pub fn (t &Table) unalias_num_type(typ Type) Type {
1039 sym := t.sym(typ)
1040 if sym.info is Alias {
1041 if sym.info.parent_type <= char_type && sym.info.parent_type >= void_type {
1042 return sym.info.parent_type
1043 }
1044 }
1045 return typ
1046}
1047
1048@[inline]
1049pub fn (t &Table) unaliased_type(typ Type) Type {
1050 sym := t.sym(typ)
1051 if sym.info is Alias {
1052 return sym.info.parent_type
1053 }
1054 return typ
1055}
1056
1057// fully_unaliased_type unwraps alias chains while preserving pointer indirections and flags.
1058@[inline]
1059pub fn (t &Table) fully_unaliased_type(typ Type) Type {
1060 mut unaliased := typ
1061 mut extra_flags := u32(typ) & 0xff00_0000
1062 for {
1063 sym := t.sym(unaliased)
1064 if sym.info is Alias {
1065 parent_typ := sym.info.parent_type
1066 unaliased = Type(u32(parent_typ.set_nr_muls(parent_typ.nr_muls() + unaliased.nr_muls())) | extra_flags)
1067 extra_flags |= u32(unaliased) & 0xff00_0000
1068 continue
1069 }
1070 return unaliased
1071 }
1072 return unaliased
1073}
1074
1075// update_sym_by_idx replaces the symbol on the `existing_idx`, with the new `sym`
1076pub fn (mut t Table) update_sym_by_idx(existing_idx int, sym &TypeSymbol) {
1077 t.delete_cached_type_to_str(idx_to_type(existing_idx), 0)
1078 t.type_symbols[existing_idx] = &TypeSymbol{
1079 ...sym
1080 idx: existing_idx
1081 size: -1 // enforce recalculation of the size, for future t.type_size(idx) calls
1082 align: -1
1083 }
1084 for mut esym in t.type_symbols {
1085 if esym.size != -1 && esym.info is Alias && esym.info.parent_type == existing_idx {
1086 // make sure to force recalculation, if t.type_size(idx) on an already existing alias is called again:
1087 esym.size = -1
1088 esym.align = -1
1089 }
1090 }
1091}
1092
1093fn (mut t Table) promote_placeholder_generic_children(parent_idx int, sym TypeSymbol) {
1094 parent_generic_types := match sym.info {
1095 Struct { sym.info.generic_types }
1096 Interface { sym.info.generic_types }
1097 SumType { sym.info.generic_types }
1098 else { []Type{} }
1099 }
1100
1101 for i, child in t.type_symbols {
1102 if child.kind != .placeholder || child.parent_idx != parent_idx
1103 || child.generic_types.len == 0 {
1104 continue
1105 }
1106 if child.generic_types == parent_generic_types {
1107 // The placeholder child uses the same generic types as the parent struct
1108 // (e.g. Iter<T> where Iter[T] uses the same T). Redirect it to the parent
1109 // rather than creating a redundant promoted type.
1110 t.type_symbols[i] = t.type_symbols[parent_idx]
1111 continue
1112 }
1113 t.update_sym_by_idx(i, &TypeSymbol{
1114 ...sym
1115 name: child.name
1116 cname: child.cname
1117 ngname: child.ngname
1118 rname: if child.rname == '' { sym.name } else { child.rname }
1119 parent_idx: parent_idx
1120 methods: child.methods
1121 generic_types: child.generic_types.clone()
1122 })
1123 }
1124}
1125
1126fn (mut t Table) rewrite_already_registered_symbol(typ TypeSymbol, existing_idx int) int {
1127 existing_symbol := t.type_symbols[existing_idx]
1128 $if trace_rewrite_already_registered_symbol ? {
1129 eprintln('>> rewrite_already_registered_symbol sym: ${typ.name} | existing_idx: ${existing_idx} | existing_symbol: ${existing_symbol.name}')
1130 }
1131 if existing_symbol.kind == .placeholder {
1132 // override placeholder
1133 ngname := if typ.ngname != '' { typ.ngname } else { strip_generic_params(typ.name) }
1134 t.type_symbols[existing_idx] = &TypeSymbol{
1135 ...typ
1136 ngname: ngname
1137 methods: existing_symbol.methods
1138 idx: existing_idx
1139 is_builtin: existing_symbol.is_builtin
1140 }
1141 t.promote_placeholder_generic_children(existing_idx, typ)
1142 return existing_idx
1143 }
1144 // Allow overwriting a generic_inst with a more complete concrete type definition
1145 // (struct, interface, sumtype). This happens when unwrap_generic_type creates a
1146 // placeholder that gets prematurely converted to generic_inst by
1147 // find_or_register_generic_inst during method resolution, before the full type
1148 // can be registered.
1149 if existing_symbol.kind == .generic_inst && typ.kind in [.struct, .interface, .sum_type] {
1150 ngname := if typ.ngname != '' { typ.ngname } else { strip_generic_params(typ.name) }
1151 t.type_symbols[existing_idx] = &TypeSymbol{
1152 ...typ
1153 ngname: ngname
1154 methods: existing_symbol.methods
1155 idx: existing_idx
1156 is_builtin: existing_symbol.is_builtin
1157 }
1158 return existing_idx
1159 }
1160 // Allow C type aliases to override existing C types (e.g. `type C.WCHAR = u16`
1161 // on Windows where WCHAR is already registered from system headers).
1162 // Detect C aliases by the `C.` name prefix, since alias TypeSymbols
1163 // themselves don't carry .language == .c (only Alias.info.language does):
1164 if typ.kind == .alias && typ.name.starts_with('C.') && existing_symbol.name.starts_with('C.') {
1165 t.type_symbols[existing_idx] = &TypeSymbol{
1166 ...typ
1167 idx: existing_idx
1168 is_builtin: existing_symbol.is_builtin
1169 }
1170 return existing_idx
1171 }
1172 // Keep concrete C type re-declarations so later modules can resolve their own
1173 // symbol instead of inheriting the first module's private metadata.
1174 if existing_symbol.language == .c && typ.language == .c {
1175 return -2
1176 }
1177 // Override the already registered builtin types with the actual
1178 // v struct declarations in the vlib/builtin module sources:
1179 if (existing_idx >= string_type_idx && existing_idx <= map_type_idx)
1180 || existing_idx == error_type_idx {
1181 if existing_idx == string_type_idx {
1182 // existing_type := t.type_symbols[existing_idx]
1183 unsafe {
1184 *existing_symbol = TypeSymbol{
1185 ...typ
1186 kind: existing_symbol.kind
1187 idx: existing_idx
1188 is_builtin: existing_symbol.is_builtin
1189 }
1190 }
1191 } else {
1192 t.type_symbols[existing_idx] = &TypeSymbol{
1193 ...typ
1194 idx: existing_idx
1195 is_builtin: existing_symbol.is_builtin
1196 }
1197 }
1198 return existing_idx
1199 }
1200 return invalid_type_idx
1201}
1202
1203@[inline]
1204pub fn (mut t Table) register_sym(sym TypeSymbol) int {
1205 mut idx := -2
1206 $if trace_register_sym ? {
1207 defer(fn) {
1208 eprintln('>> register_sym: ${sym.name:-60} | idx: ${idx}')
1209 }
1210 }
1211 sym_name := if sym.info is Struct && sym.info.scoped_name != '' {
1212 sym.info.scoped_name
1213 } else {
1214 sym.name
1215 }
1216 mut existing_idx := t.type_idxs[sym_name]
1217 if existing_idx > 0 {
1218 idx = t.rewrite_already_registered_symbol(sym, existing_idx)
1219 if idx != -2 {
1220 return idx
1221 }
1222 }
1223 if sym.mod == 'main' {
1224 existing_idx = t.type_idxs[sym_name.trim_string_left('main.')]
1225 if existing_idx > 0 {
1226 idx = t.rewrite_already_registered_symbol(sym, existing_idx)
1227 if idx != -2 {
1228 return idx
1229 }
1230 }
1231 }
1232 idx = t.type_symbols.len
1233 t.type_symbols << &TypeSymbol{
1234 ...sym
1235 }
1236 t.type_symbols[idx].idx = idx
1237 if t.type_symbols[idx].ngname == '' {
1238 t.type_symbols[idx].ngname = strip_generic_params(sym.name)
1239 }
1240 t.type_idxs[sym_name] = idx
1241 return idx
1242}
1243
1244@[inline]
1245pub fn (mut t Table) register_enum_decl(enum_decl EnumDecl) {
1246 t.enum_decls[enum_decl.name] = enum_decl
1247}
1248
1249@[inline]
1250pub fn (mut t Table) register_anon_struct(name string, sym_idx int) {
1251 t.anon_struct_names[name] = sym_idx
1252}
1253
1254@[inline]
1255pub fn (mut t Table) register_anon_union(name string, sym_idx int) {
1256 t.anon_union_names[name] = sym_idx
1257}
1258
1259pub fn (t &Table) known_type(name string) bool {
1260 return t.type_idxs[name] != 0 || t.parsing_type == name || name in ['i32', 'byte']
1261}
1262
1263@[inline]
1264pub fn strip_generic_params(name string) string {
1265 return name.all_before('[')
1266}
1267
1268pub fn split_generic_args(args string) []string {
1269 if args.len == 0 {
1270 return []string{}
1271 }
1272 mut parts := []string{}
1273 mut start := 0
1274 mut square_depth := 0
1275 mut paren_depth := 0
1276 mut brace_depth := 0
1277 for i, ch in args {
1278 match ch {
1279 `[` {
1280 square_depth++
1281 }
1282 `]` {
1283 if square_depth > 0 {
1284 square_depth--
1285 }
1286 }
1287 `(` {
1288 paren_depth++
1289 }
1290 `)` {
1291 if paren_depth > 0 {
1292 paren_depth--
1293 }
1294 }
1295 `{` {
1296 brace_depth++
1297 }
1298 `}` {
1299 if brace_depth > 0 {
1300 brace_depth--
1301 }
1302 }
1303 `,` {
1304 if square_depth == 0 && paren_depth == 0 && brace_depth == 0 {
1305 parts << args[start..i].trim_space()
1306 start = i + 1
1307 }
1308 }
1309 else {}
1310 }
1311 }
1312 parts << args[start..].trim_space()
1313 return parts.filter(it.len > 0)
1314}
1315
1316// start_parsing_type open the scope during the parsing of a type
1317// where the type name must include the module prefix
1318pub fn (mut t Table) start_parsing_type(type_name string) {
1319 t.parsing_type = type_name
1320}
1321
1322pub fn (mut t Table) reset_parsing_type() {
1323 t.parsing_type = ''
1324}
1325
1326pub fn (t &Table) known_type_idx(typ Type) bool {
1327 if typ == 0 {
1328 return false
1329 }
1330 sym := t.sym(typ)
1331 match sym.kind {
1332 .placeholder {
1333 return sym.language != .v || sym.name.starts_with('C.')
1334 }
1335 .array {
1336 if sym.info is Array {
1337 return t.known_type_idx(sym.info.elem_type)
1338 }
1339 return false
1340 }
1341 .array_fixed {
1342 if sym.info is ArrayFixed {
1343 return t.known_type_idx(sym.info.elem_type)
1344 }
1345 return false
1346 }
1347 .map {
1348 if sym.info is Map {
1349 return t.known_type_idx(sym.info.key_type) && t.known_type_idx(sym.info.value_type)
1350 }
1351 return false
1352 }
1353 else {}
1354 }
1355
1356 return true
1357}
1358
1359// supports_map_key_type returns true when C codegen can hash and compare the map key type.
1360pub fn (t &Table) supports_map_key_type(typ Type) bool {
1361 if typ == 0 || typ.has_flag(.generic) {
1362 return true
1363 }
1364 mut seen := map[int]bool{}
1365 return t.supports_map_key_type_in_type(typ.clear_flags(), mut seen)
1366}
1367
1368fn (t &Table) supports_map_key_type_in_type(typ Type, mut seen map[int]bool) bool {
1369 current_typ := typ.clear_flags()
1370 if current_typ.nr_muls() > 0 {
1371 return false
1372 }
1373 type_idx := current_typ.idx()
1374 if seen[type_idx] {
1375 return true
1376 }
1377 seen[type_idx] = true
1378 sym := t.sym(current_typ)
1379 match sym.kind {
1380 .alias {
1381 return t.supports_map_key_type_in_type((sym.info as Alias).parent_type, mut seen)
1382 }
1383 .array_fixed {
1384 return t.supports_map_key_type_in_type((sym.info as ArrayFixed).elem_type, mut seen)
1385 }
1386 .u8, .i8, .char, .i16, .u16, .enum, .int, .i32, .u32, .rune, .f32, .voidptr, .u64, .i64,
1387 .f64, .string {
1388 return true
1389 }
1390 else {
1391 return false
1392 }
1393 }
1394}
1395
1396// array_source_name generates the original name for the v source.
1397// e. g. []int
1398@[inline]
1399pub fn (t &Table) array_name(elem_type Type) string {
1400 elem_type_sym := t.sym(elem_type)
1401 ptr := if elem_type.is_ptr() { '&'.repeat(elem_type.nr_muls()) } else { '' }
1402 opt := if elem_type.has_flag(.option) { '?' } else { '' }
1403 res := if elem_type.has_flag(.result) { '!' } else { '' }
1404 name := if elem_type_sym.info is Struct && elem_type_sym.info.scoped_name != '' {
1405 elem_type_sym.info.scoped_name
1406 } else {
1407 elem_type_sym.name
1408 }
1409 return '[]${opt}${res}${ptr}${name}'
1410}
1411
1412@[inline]
1413pub fn (t &Table) array_cname(elem_type Type) string {
1414 elem_type_sym := t.sym(elem_type)
1415 suffix := if elem_type.is_ptr() { '_ptr'.repeat(elem_type.nr_muls()) } else { '' }
1416 opt := if elem_type.has_flag(.option) { '_option_' } else { '' }
1417 res := if elem_type.has_flag(.result) { '_result_' } else { '' }
1418 cname := elem_type_sym.scoped_cname()
1419 if elem_type_sym.cname.contains('[') {
1420 type_name := cname.replace_each(map_cname_escape_seq)
1421 return 'Array_${opt}${res}${type_name}${suffix}'
1422 } else {
1423 return 'Array_${opt}${res}${cname}${suffix}'
1424 }
1425}
1426
1427// array_fixed_source_name generates the original name for the v source.
1428// e. g. [16][8]int
1429@[inline]
1430pub fn (t &Table) array_fixed_name(elem_type Type, size int, size_expr Expr) string {
1431 elem_type_sym := t.sym(elem_type)
1432 ptr := if elem_type.is_ptr() { '&'.repeat(elem_type.nr_muls()) } else { '' }
1433 opt := if elem_type.has_flag(.option) { '?' } else { '' }
1434 res := if elem_type.has_flag(.result) { '!' } else { '' }
1435 size_str := if size_expr is EmptyExpr || size !in [0, 987654321] {
1436 size.str()
1437 } else {
1438 size_expr.str()
1439 }
1440 name := if elem_type_sym.info is Struct && elem_type_sym.info.scoped_name != '' {
1441 elem_type_sym.info.scoped_name
1442 } else {
1443 elem_type_sym.name
1444 }
1445 return '[${size_str}]${opt}${res}${ptr}${name}'
1446}
1447
1448@[inline]
1449pub fn (t &Table) array_fixed_cname(elem_type Type, size int) string {
1450 elem_type_sym := t.sym(elem_type)
1451 suffix := if elem_type.is_ptr() { '_ptr${elem_type.nr_muls()}' } else { '' }
1452 opt := if elem_type.has_flag(.option) { '_option_' } else { '' }
1453 res := if elem_type.has_flag(.result) { '_result_' } else { '' }
1454 mut cname := elem_type_sym.scoped_cname()
1455 if elem_type_sym.cname.contains('[') {
1456 type_name := cname.replace_each(map_cname_escape_seq)
1457 return 'Array_fixed_${opt}${res}${type_name}${suffix}_${size}'
1458 } else {
1459 return 'Array_fixed_${opt}${res}${cname}${suffix}_${size}'
1460 }
1461}
1462
1463@[inline]
1464pub fn (t &Table) chan_name(elem_type Type, is_mut bool) string {
1465 elem_type_sym := t.sym(elem_type)
1466 mut ptr := ''
1467 if is_mut {
1468 ptr = 'mut '
1469 } else if elem_type.is_ptr() {
1470 ptr = '&'
1471 }
1472 return 'chan ${ptr}${elem_type_sym.name}'
1473}
1474
1475@[inline]
1476pub fn (t &Table) chan_cname(elem_type Type, is_mut bool) string {
1477 elem_type_sym := t.sym(elem_type)
1478 mut suffix := ''
1479 if is_mut {
1480 suffix = '_mut'
1481 } else if elem_type.is_ptr() {
1482 suffix = '_ptr'
1483 }
1484 type_name := if elem_type_sym.cname.contains('[') {
1485 elem_type_sym.cname.replace_each(map_cname_escape_seq)
1486 } else {
1487 elem_type_sym.cname
1488 }
1489 return 'chan_${type_name}' + suffix
1490}
1491
1492@[inline]
1493pub fn (t &Table) promise_name(return_type Type) string {
1494 if return_type.idx() == void_type_idx {
1495 return 'Promise[JS.Any, JS.Any]'
1496 }
1497
1498 return_type_sym := t.sym(return_type)
1499 return 'Promise[${return_type_sym.name}, JS.Any]'
1500}
1501
1502@[inline]
1503pub fn (t &Table) promise_cname(return_type Type) string {
1504 if return_type == void_type {
1505 return 'Promise_Any_Any'
1506 }
1507
1508 return_type_sym := t.sym(return_type)
1509 return 'Promise_${return_type_sym.name}_Any'
1510}
1511
1512@[inline]
1513pub fn (t &Table) thread_name(return_type Type) string {
1514 if return_type.idx() == void_type_idx {
1515 if return_type.has_flag(.option) {
1516 return 'thread ?'
1517 } else if return_type.has_flag(.result) {
1518 return 'thread !'
1519 } else {
1520 return 'thread'
1521 }
1522 }
1523 return_type_sym := t.sym(return_type)
1524 ptr := if return_type.is_ptr() { '&' } else { '' }
1525 opt := if return_type.has_flag(.option) { '?' } else { '' }
1526 res := if return_type.has_flag(.result) { '!' } else { '' }
1527 return 'thread ${opt}${res}${ptr}${return_type_sym.name}'
1528}
1529
1530@[inline]
1531pub fn (t &Table) thread_cname(return_type Type) string {
1532 if return_type == void_type {
1533 if return_type.has_flag(.option) {
1534 return '__v_thread_Option_void'
1535 } else if return_type.has_flag(.result) {
1536 return '__v_thread_Result_void'
1537 } else {
1538 return '__v_thread'
1539 }
1540 }
1541 return_type_sym := t.sym(return_type)
1542 suffix := if return_type.is_ptr() { '_ptr' } else { '' }
1543 opt := if return_type.has_flag(.option) { '_option_' } else { '' }
1544 res := if return_type.has_flag(.result) { '_result_' } else { '' }
1545 return '__v_thread_${opt}${res}${return_type_sym.cname}${suffix}'
1546}
1547
1548// map_source_name generates the original name for the v source.
1549// e. g. map[string]int
1550@[inline]
1551pub fn (t &Table) map_name(key_type Type, value_type Type) string {
1552 key_type_sym := t.sym(key_type)
1553 value_type_sym := t.sym(value_type)
1554 ptr := if value_type.is_ptr() { '&'.repeat(value_type.nr_muls()) } else { '' }
1555 opt := if value_type.has_flag(.option) { '?' } else { '' }
1556 res := if value_type.has_flag(.result) { '!' } else { '' }
1557 return 'map[${key_type_sym.name}]${opt}${res}${ptr}${value_type_sym.name}'
1558}
1559
1560@[inline]
1561pub fn (t &Table) map_cname(key_type Type, value_type Type) string {
1562 key_type_sym := t.sym(key_type)
1563 value_type_sym := t.sym(value_type)
1564 suffix := if value_type.is_ptr() { '_ptr'.repeat(value_type.nr_muls()) } else { '' }
1565 opt := if value_type.has_flag(.option) { '_option_' } else { '' }
1566 res := if value_type.has_flag(.result) { '_result_' } else { '' }
1567 if value_type_sym.cname.contains('[') {
1568 type_name := value_type_sym.cname.replace_each(map_cname_escape_seq)
1569 return 'Map_${key_type_sym.cname}_${opt}${res}${type_name}${suffix}'
1570 } else {
1571 return 'Map_${key_type_sym.cname}_${opt}${res}${value_type_sym.cname}${suffix}'
1572 }
1573}
1574
1575pub fn (mut t Table) find_or_register_chan(elem_type Type, is_mut bool) int {
1576 name := t.chan_name(elem_type, is_mut)
1577 cname := t.chan_cname(elem_type, is_mut)
1578 // existing
1579 existing_idx := t.type_idxs[name]
1580 if existing_idx > 0 {
1581 return existing_idx
1582 }
1583 chan_sym := TypeSymbol{
1584 parent_idx: chan_type_idx
1585 kind: .chan
1586 name: name
1587 cname: cname
1588 ngname: strip_generic_params(name)
1589 info: Chan{
1590 elem_type: elem_type
1591 is_mut: is_mut
1592 }
1593 }
1594 return t.register_sym(chan_sym)
1595}
1596
1597pub fn (mut t Table) find_or_register_map(key_type Type, value_type Type) int {
1598 name := t.map_name(key_type, value_type)
1599 cname := t.map_cname(key_type, value_type)
1600 // existing
1601 existing_idx := t.type_idxs[name]
1602 if existing_idx > 0 {
1603 return existing_idx
1604 }
1605 map_sym := TypeSymbol{
1606 parent_idx: map_type_idx
1607 kind: .map
1608 name: name
1609 cname: cname
1610 ngname: strip_generic_params(name)
1611 info: Map{
1612 key_type: key_type
1613 value_type: value_type
1614 }
1615 }
1616 return t.register_sym(map_sym)
1617}
1618
1619pub fn (mut t Table) find_or_register_thread(return_type Type) int {
1620 name := t.thread_name(return_type)
1621 cname := t.thread_cname(return_type)
1622 // existing
1623 existing_idx := t.type_idxs[name]
1624 if existing_idx > 0 {
1625 return existing_idx
1626 }
1627 thread_sym := TypeSymbol{
1628 parent_idx: thread_type_idx
1629 kind: .thread
1630 name: name
1631 cname: cname
1632 ngname: strip_generic_params(name)
1633 info: Thread{
1634 return_type: return_type
1635 }
1636 }
1637 return t.register_sym(thread_sym)
1638}
1639
1640pub fn (mut t Table) find_or_register_promise(return_type Type) int {
1641 name := t.promise_name(return_type)
1642
1643 cname := t.promise_cname(return_type)
1644 // existing
1645 existing_idx := t.type_idxs[name]
1646 if existing_idx > 0 {
1647 return existing_idx
1648 }
1649
1650 promise_type := TypeSymbol{
1651 parent_idx: t.type_idxs['Promise']
1652 kind: .struct
1653 name: name
1654 cname: cname
1655 ngname: strip_generic_params(name)
1656 info: Struct{
1657 concrete_types: [return_type, t.type_idxs['JS.Any']]
1658 }
1659 }
1660
1661 // register
1662 return t.register_sym(promise_type)
1663}
1664
1665pub fn (mut t Table) find_or_register_array(elem_type Type) int {
1666 name := t.array_name(elem_type)
1667 // existing
1668 existing_idx := t.type_idxs[name]
1669 if existing_idx > 0 {
1670 return existing_idx
1671 }
1672 cname := t.array_cname(elem_type)
1673 // register
1674 array_type_ := TypeSymbol{
1675 parent_idx: array_type_idx
1676 kind: .array
1677 name: name
1678 cname: cname
1679 ngname: strip_generic_params(name)
1680 info: Array{
1681 nr_dims: 1
1682 elem_type: elem_type
1683 }
1684 }
1685 return t.register_sym(array_type_)
1686}
1687
1688pub fn (mut t Table) find_or_register_array_with_dims(elem_type Type, nr_dims int) int {
1689 if nr_dims == 1 {
1690 return t.find_or_register_array(elem_type)
1691 }
1692 return t.find_or_register_array(idx_to_type(t.find_or_register_array_with_dims(elem_type,
1693 nr_dims - 1)))
1694}
1695
1696pub fn (mut t Table) find_or_register_array_fixed(elem_type Type, size int, size_expr Expr, is_fn_ret bool) int {
1697 prefix := if is_fn_ret { '_v_' } else { '' }
1698 name := prefix + t.array_fixed_name(elem_type, size, size_expr)
1699 // existing
1700 existing_idx := t.type_idxs[name]
1701 if existing_idx > 0 {
1702 return existing_idx
1703 }
1704 cname := prefix + t.array_fixed_cname(elem_type, size)
1705 // register
1706 array_fixed_type := TypeSymbol{
1707 kind: .array_fixed
1708 name: name
1709 cname: cname
1710 ngname: strip_generic_params(name)
1711 info: ArrayFixed{
1712 elem_type: elem_type
1713 size: size
1714 size_expr: size_expr
1715 is_fn_ret: is_fn_ret
1716 }
1717 }
1718 return t.register_sym(array_fixed_type)
1719}
1720
1721pub fn (mut t Table) find_or_register_multi_return(mr_typs []Type) int {
1722 mut name := '('
1723 mut cname := 'multi_return'
1724 for i, mr_typ in mr_typs {
1725 mr_type_sym := t.sym(mktyp(mr_typ))
1726 ref, cref := if mr_typ.is_ptr() { '&', 'ref_' } else { '', '' }
1727 name += if mr_typ.has_flag(.option) { '?' } else { '' }
1728 name += if mr_typ.has_flag(.result) { '!' } else { '' }
1729 name += '${ref}${mr_type_sym.name}'
1730 cname += if mr_typ.has_flag(.option) { '_option' } else { '' }
1731 cname += if mr_typ.has_flag(.result) { '_result' } else { '' }
1732 cname += '_${cref}${mr_type_sym.cname}'
1733 if i < mr_typs.len - 1 {
1734 name += ', '
1735 }
1736 }
1737 name += ')'
1738 // existing
1739 existing_idx := t.type_idxs[name]
1740 if existing_idx > 0 {
1741 return existing_idx
1742 }
1743 multireg_sym := TypeSymbol{
1744 kind: .multi_return
1745 name: name
1746 cname: cname
1747 ngname: strip_generic_params(name)
1748 info: MultiReturn{
1749 types: mr_typs
1750 }
1751 }
1752 return t.register_sym(multireg_sym)
1753}
1754
1755pub fn (mut t Table) find_or_register_fn_type(f Fn, is_anon bool, has_decl bool) int {
1756 name := if f.name == '' { 'fn ${t.fn_type_source_signature(f)}' } else { f.name.clone() }
1757 cname := if f.name == '' {
1758 'anon_fn_${t.fn_type_signature(f)}'
1759 } else {
1760 util.no_dots(f.name.clone()).replace_each(fn_type_escape_seq)
1761 }
1762 anon := f.name == '' || is_anon
1763 existing_idx := t.type_idxs[name]
1764 if existing_idx > 0 {
1765 mut existing_sym := t.type_symbols[existing_idx]
1766 if existing_sym.kind != .placeholder {
1767 if mut existing_sym.info is FnType && !has_decl {
1768 existing_sym.info.has_decl = has_decl
1769 }
1770 return existing_idx
1771 }
1772 }
1773 return t.register_sym(
1774 kind: .function
1775 name: name
1776 cname: cname
1777 ngname: strip_generic_params(name)
1778 mod: f.mod
1779 info: FnType{
1780 is_anon: anon
1781 has_decl: has_decl
1782 func: f
1783 }
1784 )
1785}
1786
1787pub fn (mut t Table) find_or_register_generic_inst(parent_typ Type, concrete_types []Type) int {
1788 parent_sym := t.sym(parent_typ)
1789 expected_generic_types := match parent_sym.info {
1790 Struct { parent_sym.info.generic_types.len }
1791 Interface { parent_sym.info.generic_types.len }
1792 SumType { parent_sym.info.generic_types.len }
1793 FnType { parent_sym.info.func.generic_names.len }
1794 else { 0 }
1795 }
1796
1797 if expected_generic_types == 0 || concrete_types.len != expected_generic_types {
1798 return 0
1799 }
1800 base_name := if parent_sym.ngname != '' {
1801 parent_sym.ngname
1802 } else {
1803 strip_generic_params(parent_sym.name)
1804 }
1805 mut inst_name := base_name + '['
1806 mut inst_cname := parent_sym.cname + '_T_'
1807 for i, ct in concrete_types {
1808 ct_sym := t.sym(ct)
1809 if ct.nr_muls() > 0 {
1810 inst_name += '&'.repeat(ct.nr_muls())
1811 inst_cname += '__ptr__'.repeat(ct.nr_muls())
1812 }
1813 inst_name += ct_sym.name
1814 inst_cname += ct_sym.scoped_cname()
1815 if i < concrete_types.len - 1 {
1816 inst_name += ', '
1817 inst_cname += '_T_'
1818 }
1819 }
1820 inst_name += ']'
1821 existing_idx := t.type_idxs[inst_name]
1822 if existing_idx > 0 {
1823 if t.type_symbols[existing_idx].kind == .placeholder {
1824 t.type_symbols[existing_idx].kind = .generic_inst
1825 t.type_symbols[existing_idx].ngname = parent_sym.ngname
1826 t.type_symbols[existing_idx].mod = parent_sym.mod
1827 t.type_symbols[existing_idx].info = GenericInst{
1828 parent_idx: parent_typ.idx()
1829 concrete_types: concrete_types
1830 }
1831 }
1832 return existing_idx
1833 }
1834 return t.register_sym(
1835 kind: .generic_inst
1836 name: inst_name
1837 cname: inst_cname
1838 ngname: parent_sym.ngname
1839 mod: parent_sym.mod
1840 is_pub: parent_sym.is_pub
1841 info: GenericInst{
1842 parent_idx: parent_typ.idx()
1843 concrete_types: concrete_types
1844 }
1845 )
1846}
1847
1848fn (t &Table) generic_fn_inst_name(sym &TypeSymbol, concrete_types []Type) string {
1849 mut name := sym.name + '['
1850 for i, concrete_type in concrete_types {
1851 concrete_sym := t.sym(concrete_type)
1852 if concrete_type.is_ptr() {
1853 name += '&'.repeat(concrete_type.nr_muls())
1854 }
1855 name += concrete_sym.name
1856 if i < concrete_types.len - 1 {
1857 name += ', '
1858 }
1859 }
1860 name += ']'
1861 return name
1862}
1863
1864pub fn (mut t Table) add_placeholder_type(name string, cname string, language Language) int {
1865 mut modname := ''
1866 if name.contains('.') {
1867 modname = name.all_before_last('.')
1868 }
1869 placeholder_sym := TypeSymbol{
1870 kind: .placeholder
1871 name: name
1872 cname: util.no_dots(cname).replace_each(['&', ''])
1873 ngname: strip_generic_params(name)
1874 language: language
1875 mod: modname
1876 is_pub: true
1877 is_builtin: name in builtins
1878 }
1879 return t.register_sym(placeholder_sym)
1880}
1881
1882@[inline]
1883pub fn (t &Table) value_type(typ Type) Type {
1884 sym := t.final_sym(typ)
1885 if typ.has_flag(.variadic) {
1886 // ...string => string
1887 // return typ.clear_flag(.variadic)
1888 array_info := sym.info as Array
1889 return array_info.elem_type
1890 }
1891 if sym.kind == .array {
1892 // Check index type
1893 info := sym.info as Array
1894 return info.elem_type
1895 }
1896 if sym.kind == .array_fixed {
1897 info := sym.info as ArrayFixed
1898 return info.elem_type
1899 }
1900 if sym.kind == .map {
1901 info := sym.info as Map
1902 return info.value_type
1903 }
1904 if sym.kind == .string && typ.is_ptr() {
1905 // (&string)[i] => string
1906 return string_type
1907 }
1908 if sym.kind in [.byteptr, .string] {
1909 return u8_type
1910 }
1911 if typ.is_ptr() {
1912 // byte* => byte
1913 // bytes[0] is a byte, not byte*
1914 return typ.deref()
1915 }
1916 return void_type
1917}
1918
1919pub fn (mut t Table) register_fn_generic_types(fn_name string) {
1920 t.fn_generic_types[fn_name] = [][]Type{}
1921}
1922
1923pub fn (mut t Table) register_fn_concrete_types(fn_name string, types []Type) bool {
1924 if types.len == 0 {
1925 return false
1926 }
1927 mut a := t.fn_generic_types[fn_name] or { return false }
1928 if types in a {
1929 return false
1930 }
1931 a << types
1932 t.fn_generic_types[fn_name] = a
1933 return true
1934}
1935
1936// TODO: there is a bug when casting sumtype the other way if its pointer
1937// so until fixed at least show v (not C) error `x(variant) = y(SumType*)`
1938pub fn (t &Table) sumtype_has_variant(parent Type, variant Type, is_as bool) bool {
1939 parent_sym := t.sym(parent)
1940 if parent_sym.kind == .sum_type {
1941 parent_info := parent_sym.info as SumType
1942 var_sym := t.sym(variant)
1943 match var_sym.kind {
1944 .aggregate {
1945 return t.sumtype_check_aggregate_variant(parent, variant, is_as)
1946 }
1947 .alias {
1948 return t.sumtype_check_alias_variant(parent, variant, is_as)
1949 }
1950 .function {
1951 return t.sumtype_check_function_variant(parent_info, variant, is_as)
1952 }
1953 else {
1954 return t.sumtype_check_variant_in_type(parent_info, variant, is_as)
1955 }
1956 }
1957 }
1958 return false
1959}
1960
1961pub fn (t &Table) sumtype_has_variant_recursive(parent Type, variant Type, is_as bool) bool {
1962 if t.sumtype_has_variant(parent, variant, is_as) {
1963 return true
1964 }
1965 parent_sym := t.sym(parent)
1966 if parent_sym.kind != .sum_type || parent_sym.info !is SumType {
1967 return false
1968 }
1969 parent_info := parent_sym.info as SumType
1970 for parent_variant in parent_info.variants {
1971 if nested_sumtype := t.sumtype_nested_variant_type(parent_variant) {
1972 if t.sumtype_has_variant_recursive(nested_sumtype, variant, is_as) {
1973 return true
1974 }
1975 }
1976 }
1977 return false
1978}
1979
1980pub fn (t &Table) sumtype_matchable_variants(parent Type) []Type {
1981 mut variants := []Type{}
1982 mut seen := map[u32]bool{}
1983 t.collect_sumtype_matchable_variants(parent, mut seen, mut variants)
1984 return variants
1985}
1986
1987pub fn (t &Table) sumtype_missing_variants(parent Type, handled []Type) []Type {
1988 mut missing := []Type{}
1989 mut seen := map[u32]bool{}
1990 t.collect_sumtype_missing_variants(parent, handled, mut seen, mut missing)
1991 return missing
1992}
1993
1994fn (t &Table) collect_sumtype_matchable_variants(parent Type, mut seen map[u32]bool, mut variants []Type) {
1995 parent_sym := t.sym(parent)
1996 if parent_sym.kind != .sum_type || parent_sym.info !is SumType {
1997 return
1998 }
1999 parent_info := parent_sym.info as SumType
2000 for variant in parent_info.variants {
2001 if u32(variant) !in seen {
2002 seen[u32(variant)] = true
2003 variants << variant
2004 }
2005 if nested_sumtype := t.sumtype_nested_variant_type(variant) {
2006 t.collect_sumtype_matchable_variants(nested_sumtype, mut seen, mut variants)
2007 }
2008 }
2009}
2010
2011fn (t &Table) collect_sumtype_missing_variants(parent Type, handled []Type, mut seen map[u32]bool, mut missing []Type) {
2012 if t.sumtype_variant_is_handled(parent, handled) {
2013 return
2014 }
2015 if nested_sumtype := t.sumtype_nested_variant_type(parent) {
2016 nested_sym := t.sym(nested_sumtype)
2017 if nested_sym.kind == .sum_type && nested_sym.info is SumType {
2018 nested_info := nested_sym.info as SumType
2019 for variant in nested_info.variants {
2020 if t.sumtype_variant_is_handled(variant, handled) {
2021 continue
2022 }
2023 if nested_variant := t.sumtype_nested_variant_type(variant) {
2024 t.collect_sumtype_missing_variants(nested_variant, handled, mut seen, mut
2025 missing)
2026 } else if u32(variant) !in seen {
2027 seen[u32(variant)] = true
2028 missing << variant
2029 }
2030 }
2031 return
2032 }
2033 }
2034 if u32(parent) !in seen {
2035 seen[u32(parent)] = true
2036 missing << parent
2037 }
2038}
2039
2040fn (t &Table) sumtype_variant_is_handled(variant Type, handled []Type) bool {
2041 for handled_variant in handled {
2042 if t.same_sumtype_variant(variant, handled_variant, true) {
2043 return true
2044 }
2045 }
2046 return false
2047}
2048
2049fn (t &Table) same_sumtype_variant(expected Type, got Type, is_as bool) bool {
2050 return expected.idx() == got.idx() && expected.has_flag(.option) == got.has_flag(.option)
2051 && (!is_as || expected.nr_muls() == got.nr_muls())
2052}
2053
2054fn (t &Table) sumtype_nested_variant_type(variant Type) ?Type {
2055 nested_sumtype := t.fully_unaliased_type(variant)
2056 if t.sym(nested_sumtype).kind == .sum_type {
2057 return nested_sumtype
2058 }
2059 return none
2060}
2061
2062fn (t &Table) sumtype_check_function_variant(parent_info SumType, variant Type, is_as bool) bool {
2063 variant_fn := (t.sym(variant).info as FnType).func
2064 variant_fn_sig := t.fn_type_source_signature(variant_fn)
2065
2066 for v in parent_info.variants {
2067 v_sym := t.sym(v)
2068 if v_sym.info is FnType {
2069 if t.fn_type_source_signature(v_sym.info.func) == variant_fn_sig
2070 && (!is_as || v.nr_muls() == variant.nr_muls()) {
2071 return true
2072 }
2073 }
2074 }
2075 return false
2076}
2077
2078fn (t &Table) sumtype_check_variant_in_type(parent_info SumType, variant Type, is_as bool) bool {
2079 for v in parent_info.variants {
2080 if t.same_sumtype_variant(v, variant, is_as) {
2081 return true
2082 }
2083 }
2084 if !is_as {
2085 for v in parent_info.variants {
2086 if t.can_implicit_array_cast(variant, v) {
2087 return true
2088 }
2089 }
2090 }
2091 return false
2092}
2093
2094fn (t &Table) sumtype_check_aggregate_variant(parent_type Type, aggregate_type &Type, is_as bool) bool {
2095 aggregate_sym := t.sym(aggregate_type).info as Aggregate
2096 for var_type in aggregate_sym.types {
2097 if !t.sumtype_has_variant(parent_type, var_type, is_as) {
2098 return false
2099 }
2100 }
2101 return true
2102}
2103
2104fn (t &Table) sumtype_check_alias_variant(parent_type Type, alias_type Type, is_as bool) bool {
2105 parent_sym := t.sym(parent_type).info as SumType
2106 if !t.sumtype_check_variant_in_type(parent_sym, alias_type, is_as) {
2107 alias_info := t.sym(alias_type).info as Alias
2108 // The alias is an alias or of the same sumtype parent, or one
2109 // of the SumType variant. e.g: alias of another sum type.
2110 // https://github.com/vlang/v/issues/14029
2111 return parent_type == alias_info.parent_type
2112 || t.sumtype_has_variant(parent_type, alias_info.parent_type, is_as)
2113 }
2114 // the alias_type is inside one of the variant of the sum type
2115 return true
2116}
2117
2118pub fn (t &Table) is_sumtype_or_in_variant(parent Type, typ Type) bool {
2119 if typ == 0 {
2120 return false
2121 }
2122 if t.sym(typ).kind == .sum_type && parent.idx() == typ.idx()
2123 && parent.nr_muls() == typ.nr_muls() {
2124 return true
2125 }
2126 return t.sumtype_has_variant(parent, typ, false)
2127}
2128
2129// can_implicit_array_cast reports whether `got` can be converted to `expected`
2130// by boxing each array element into the expected interface or sum type.
2131pub fn (t &Table) can_implicit_array_cast(got Type, expected Type) bool {
2132 if got == 0 || expected == 0 || got == expected {
2133 return false
2134 }
2135 got_idx := got.idx()
2136 expected_idx := expected.idx()
2137 if got_idx == expected_idx {
2138 return false
2139 }
2140 if got_idx > 0 && got_idx < t.type_symbols.len && expected_idx > 0
2141 && expected_idx < t.type_symbols.len {
2142 got_kind := t.type_symbols[got_idx].kind
2143 expected_kind := t.type_symbols[expected_idx].kind
2144 if (got_kind != .array && got_kind != .alias)
2145 || (expected_kind != .array && expected_kind != .alias) {
2146 return false
2147 }
2148 }
2149 got_unaliased := t.unaliased_type(got)
2150 expected_unaliased := t.unaliased_type(expected)
2151 got_sym := t.final_sym(got_unaliased)
2152 expected_sym := t.final_sym(expected_unaliased)
2153 if got_sym.kind != .array || expected_sym.kind != .array {
2154 return false
2155 }
2156 got_info := got_sym.info as Array
2157 expected_info := expected_sym.info as Array
2158 if got_info.nr_dims != expected_info.nr_dims {
2159 return false
2160 }
2161 got_elem_type := t.unaliased_type(got_info.elem_type)
2162 expected_elem_type := t.unaliased_type(expected_info.elem_type)
2163 if got_elem_type == expected_elem_type {
2164 return false
2165 }
2166 match t.final_sym(expected_elem_type).kind {
2167 .sum_type {
2168 return t.is_sumtype_or_in_variant(expected_elem_type, mktyp(got_elem_type))
2169 }
2170 .interface {
2171 return t.does_type_implement_interface(got_elem_type, expected_elem_type)
2172 }
2173 else {
2174 return false
2175 }
2176 }
2177}
2178
2179@[inline]
2180pub fn (t &Table) is_interface_var(var ScopeObject) bool {
2181 return var is Var && var.orig_type != 0 && t.sym(var.orig_type).kind == .interface
2182 && t.sym(var.smartcasts.last()).kind != .interface
2183}
2184
2185@[inline]
2186pub fn (t &Table) is_interface_smartcast(var ScopeObject) bool {
2187 return var is Var && var.orig_type != 0 && t.sym(var.orig_type).kind == .interface
2188 && var.smartcasts.len > 0
2189}
2190
2191// only used for debugging V compiler type bugs
2192pub fn (t &Table) known_type_names() []string {
2193 mut res := []string{cap: t.type_idxs.len}
2194 for _, idx in t.type_idxs {
2195 typ := idx_to_type(idx)
2196 // Skip `int_literal_type_idx` and `float_literal_type_idx` because they shouldn't be visible to the User.
2197 if idx !in [0, int_literal_type_idx, float_literal_type_idx] && t.known_type_idx(typ) {
2198 tsym := t.sym(typ)
2199 if tsym.kind !in [.function, .chan] {
2200 res << t.type_to_str(typ)
2201 } else if tsym.info is Chan && t.sym(tsym.info.elem_type).kind != .placeholder {
2202 res << t.type_to_str(tsym.info.elem_type)
2203 }
2204 }
2205 }
2206 return res
2207}
2208
2209// has_deep_child_no_ref returns true if type is struct and has any child or nested child with the type of the given name.
2210// The given name consists of module and name (`mod.Name`).
2211// It ignores children that are references, including aliases to references.
2212pub fn (t &Table) has_deep_child_no_ref(ts &TypeSymbol, name string) bool {
2213 mut seen := map[string]bool{}
2214 return t.has_deep_child_no_ref_in_sym(ts, name, mut seen)
2215}
2216
2217fn (t &Table) has_deep_child_no_ref_in_sym(ts &TypeSymbol, name string, mut seen map[string]bool) bool {
2218 if ts.kind == .placeholder || ts.name in seen {
2219 return false
2220 }
2221 seen[ts.name] = true
2222 match ts.info {
2223 Struct {
2224 for field in ts.info.fields {
2225 sym := t.sym(field.typ)
2226 if !field.typ.is_ptr() && !field.typ.has_flag(.option) && (sym.name == name
2227 || (sym.info is Struct && t.has_deep_child_no_ref_in_sym(sym, name, mut seen))) {
2228 return true
2229 }
2230 }
2231 for embed in ts.info.embeds {
2232 if t.has_deep_child_no_ref_in_embed(embed, name, mut seen) {
2233 return true
2234 }
2235 }
2236 }
2237 else {}
2238 }
2239
2240 return false
2241}
2242
2243fn (t &Table) has_deep_child_no_ref_in_embed(typ Type, name string, mut seen map[string]bool) bool {
2244 unaliased_typ := t.unaliased_type(typ)
2245 if unaliased_typ.is_ptr() || unaliased_typ.has_flag(.option) {
2246 return false
2247 }
2248 sym := t.sym(unaliased_typ)
2249 if sym.name == name {
2250 return true
2251 }
2252 return t.has_deep_child_no_ref_in_sym(sym, name, mut seen)
2253}
2254
2255// complete_interface_check does a MxN check for all M interfaces vs all N types, to determine what types implement what interfaces.
2256// It short circuits most checks when an interface can not possibly be implemented by a type.
2257pub fn (mut t Table) complete_interface_check() {
2258 util.timing_start(@METHOD)
2259 defer {
2260 util.timing_measure(@METHOD)
2261 }
2262 for tk, mut tsym in t.type_symbols {
2263 tk_typ := idx_to_type(tk)
2264 if tsym.kind != .struct {
2265 continue
2266 }
2267 for _, mut idecl in t.interfaces {
2268 if idecl.typ == 0 {
2269 continue
2270 }
2271 // empty interface only generate type cast functions of the current module
2272 if idecl.methods.len == 0 && idecl.fields.len == 0 && tsym.mod != t.sym(idecl.typ).mod {
2273 continue
2274 }
2275 if t.does_type_implement_interface(tk_typ, idecl.typ) {
2276 $if trace_types_implementing_each_interface ? {
2277 eprintln('>>> tsym.mod: ${tsym.mod} | tsym.name: ${tsym.name} | tk: ${tk} | idecl.name: ${idecl.name} | idecl.typ: ${idecl.typ}')
2278 }
2279 if idecl.name !in t.iface_types {
2280 t.iface_types[idecl.name] = []Type{}
2281 }
2282 t.iface_types[idecl.name] << tk_typ
2283 }
2284 }
2285 }
2286 // For empty interfaces, propagate concrete types from all other interfaces
2287 // into the empty interface's variant list. Empty interfaces can be assigned
2288 // from any interface (e.g. `IError` -> `EmptyIface{}`); at runtime the empty
2289 // interface will hold the source interface's dynamic type, so the empty
2290 // interface must have cast functions for each possible concrete variant.
2291 mut empty_iface_typs := []Type{}
2292 for _, idecl in t.interfaces {
2293 if idecl.typ == 0 {
2294 continue
2295 }
2296 if idecl.methods.len == 0 && idecl.fields.len == 0 {
2297 empty_iface_typs << idecl.typ
2298 }
2299 }
2300 for iface_typ in empty_iface_typs {
2301 mut iface_sym := t.sym(iface_typ)
2302 if iface_sym.info !is Interface {
2303 continue
2304 }
2305 mut iface_info := iface_sym.info as Interface
2306 mut collected_types := []Type{}
2307 mut seen_cnames := map[string]bool{}
2308 for existing in iface_info.types {
2309 existing_sym := t.sym(mktyp(existing))
2310 seen_cnames[existing_sym.cname] = true
2311 }
2312 for _, other_sym in t.type_symbols {
2313 if other_sym.kind != .interface || other_sym.idx == iface_sym.idx {
2314 continue
2315 }
2316 if other_sym.info !is Interface {
2317 continue
2318 }
2319 other_info := other_sym.info as Interface
2320 for variant in other_info.types {
2321 mk_variant := mktyp(variant)
2322 variant_sym := t.sym(mk_variant)
2323 if variant_sym.kind != .struct {
2324 continue
2325 }
2326 if variant_sym.cname in seen_cnames {
2327 continue
2328 }
2329 seen_cnames[variant_sym.cname] = true
2330 collected_types << mk_variant
2331 }
2332 }
2333 if collected_types.len > 0 {
2334 iface_info.types << collected_types
2335 iface_sym.info = iface_info
2336 if iface_sym.name !in t.iface_types {
2337 t.iface_types[iface_sym.name] = []Type{}
2338 }
2339 mut target_variants := t.iface_types[iface_sym.name].clone()
2340 for variant in collected_types {
2341 if variant !in target_variants {
2342 target_variants << variant
2343 }
2344 }
2345 t.iface_types[iface_sym.name] = target_variants
2346 }
2347 }
2348}
2349
2350// bitsize_to_type returns a type corresponding to the bit_size
2351// Examples:
2352//
2353// `8 > i8`
2354//
2355// `32 > int`
2356//
2357// `123 > panic()`
2358//
2359// `128 > [16]u8`
2360//
2361// `608 > [76]u8`
2362pub fn (mut t Table) bitsize_to_type(bit_size int) Type {
2363 match bit_size {
2364 8 {
2365 return i8_type
2366 }
2367 16 {
2368 return i16_type
2369 }
2370 32 {
2371 return i32_type
2372 }
2373 64 {
2374 return i64_type
2375 }
2376 else {
2377 if bit_size % 8 != 0 { // there is no way to do `i2131(32)` so this should never be reached
2378 t.panic('table.bitsize_to_type: compiler bug: bitsizes must be multiples of 8, but passed bit_size is ${bit_size}')
2379 }
2380 return new_type(t.find_or_register_array_fixed(u8_type, bit_size / 8, empty_expr, false))
2381 }
2382 }
2383}
2384
2385pub fn (t &Table) interface_inherits_interface(typ Type, inter_typ Type) bool {
2386 if typ.idx() == inter_typ.idx() {
2387 return true
2388 }
2389 sym := t.sym(typ)
2390 if sym.kind != .interface || sym.info !is Interface {
2391 return false
2392 }
2393 info := sym.info as Interface
2394 for embed in info.embeds {
2395 if embed.idx() == inter_typ.idx() || t.interface_inherits_interface(embed, inter_typ) {
2396 return true
2397 }
2398 }
2399 if info.parent_type != 0 && info.parent_type.idx() != 0 && info.parent_type != typ {
2400 parent_sym := t.sym(info.parent_type)
2401 if parent_sym.kind == .interface
2402 && t.interface_inherits_interface(info.parent_type, inter_typ) {
2403 return true
2404 }
2405 }
2406 return false
2407}
2408
2409pub fn (t &Table) does_type_implement_interface(typ Type, inter_typ Type) bool {
2410 if typ.idx() == inter_typ.idx() {
2411 // same type -> already casted to the interface
2412 return true
2413 }
2414 if inter_typ.idx() == error_type_idx && typ.idx() == none_type_idx {
2415 // `none` "implements" the Error interface
2416 return true
2417 }
2418 sym := t.sym(typ)
2419 if sym.language != .v {
2420 return false
2421 }
2422 // generic struct don't generate cast interface fn
2423 if sym.info is Struct {
2424 if sym.info.is_generic {
2425 return false
2426 }
2427 }
2428 mut inter_sym := t.sym(inter_typ)
2429 if sym.kind == .interface && inter_sym.kind == .interface {
2430 inter_info := inter_sym.info as Interface
2431 if inter_info.methods.len == 0 && inter_info.fields.len == 0 && inter_info.embeds.len == 0 {
2432 return true
2433 }
2434 if !t.interface_inherits_interface(typ, inter_typ) {
2435 return false
2436 }
2437 }
2438 if mut inter_sym.info is Interface {
2439 attrs := unsafe { t.interfaces[inter_typ].attrs }
2440 for attr in attrs {
2441 if attr.name == 'single_impl' {
2442 return false
2443 }
2444 }
2445 // do not check the same type more than once
2446 for tt in inter_sym.info.types {
2447 if tt.idx() == typ.idx() {
2448 return true
2449 }
2450 }
2451 // verify methods
2452 for imethod in inter_sym.info.methods {
2453 if t.is_compatible_auto_str_method(imethod) && typ.nr_muls() == 0 && sym.kind == .char {
2454 return false
2455 }
2456 if method := t.find_method_with_embeds(sym, imethod.name) {
2457 msg := t.is_same_method(imethod, method)
2458 if msg.len > 0 {
2459 return false
2460 }
2461 continue
2462 }
2463 match sym.info {
2464 SumType, Struct, Interface {
2465 if method := sym.find_method_with_generic_parent(imethod.name) {
2466 msg := t.is_same_method(imethod, method)
2467 if msg.len > 0 {
2468 return false
2469 }
2470 continue
2471 }
2472 }
2473 else {}
2474 }
2475
2476 if t.type_has_implicit_str_method(typ, imethod) {
2477 continue
2478 }
2479 return false
2480 }
2481 // verify fields
2482 for ifield in inter_sym.info.fields {
2483 if ifield.typ == voidptr_type || ifield.typ == nil_type {
2484 // Allow `voidptr` fields in interfaces for now. (for example
2485 // to enable .db check in veb)
2486 if t.struct_has_field(sym, ifield.name) {
2487 continue
2488 } else {
2489 return false
2490 }
2491 }
2492 if field := t.find_field_with_embeds(sym, ifield.name) {
2493 if ifield.typ != field.typ {
2494 return false
2495 } else if ifield.is_mut && !(field.is_mut || field.is_global) {
2496 return false
2497 }
2498 continue
2499 }
2500 return false
2501 }
2502 if sym.kind !in [.interface, .aggregate] && typ != voidptr_type && typ != nil_type
2503 && typ != none_type && !inter_sym.info.types.contains(typ) {
2504 inter_sym.info.types << typ
2505 }
2506 if !inter_sym.info.types.contains(voidptr_type) {
2507 inter_sym.info.types << voidptr_type
2508 }
2509 return true
2510 }
2511 return false
2512}
2513
2514pub fn (mut t Table) convert_generic_static_type_name(fn_name string, generic_names []string, concrete_types []Type) (Type, string) {
2515 if index := fn_name.index('__static__') {
2516 if index > 0 {
2517 generic_name := fn_name[0..index]
2518 valid_generic := util.is_generic_type_name(generic_name)
2519 && generic_name in generic_names
2520 if valid_generic {
2521 name_type := t.find_type(generic_name).set_flag(.generic)
2522 if typ := t.convert_generic_type(name_type, generic_names, concrete_types) {
2523 return name_type, '${t.type_to_str(typ)}${fn_name[index..]}'
2524 }
2525 }
2526 }
2527 }
2528 return void_type, fn_name
2529}
2530
2531// convert_generic_type convert generics to real types (T => int) or other generics type.
2532pub fn (mut t Table) convert_generic_type(generic_type Type, generic_names []string, to_types []Type) ?Type {
2533 if generic_names.len != to_types.len {
2534 return none
2535 }
2536 type_idx := generic_type.idx()
2537 if type_idx == 0 || type_idx >= t.type_symbols.len {
2538 return none
2539 }
2540 mut sym := t.sym(generic_type)
2541 if sym.name in generic_names {
2542 index := generic_names.index(sym.name)
2543 if index >= to_types.len {
2544 return none
2545 }
2546 typ := to_types[index]
2547 if typ == 0 || typ.idx() >= t.type_symbols.len {
2548 return none
2549 }
2550 mut rtyp := typ.derive_add_muls(generic_type)
2551 if typ.has_flag(.generic) {
2552 rtyp = rtyp.set_flag(.generic)
2553 } else {
2554 rtyp = rtyp.clear_flag(.generic)
2555 }
2556 if !generic_type.has_flag(.result) && typ.has_flag(.option) {
2557 rtyp = rtyp.set_flag(.option)
2558 if generic_type.is_ptr() {
2559 rtyp = rtyp.set_flag(.option_mut_param_t)
2560 }
2561 }
2562 resolved_typ_sym := t.sym(t.fully_unaliased_type(typ))
2563 if resolved_typ_sym.info is FnType && typ.has_flag(.shared_f) {
2564 rtyp = rtyp.set_flag(.shared_f)
2565 }
2566 if resolved_typ_sym.info is FnType && typ.has_flag(.atomic_f) {
2567 rtyp = rtyp.set_flag(.atomic_f)
2568 }
2569 return rtyp
2570 }
2571 match mut sym.info {
2572 Array {
2573 dims, elem_type := t.get_array_dims(sym.info)
2574 if typ := t.convert_generic_type(elem_type, generic_names, to_types) {
2575 idx := t.find_or_register_array_with_dims(typ, dims)
2576 if typ.has_flag(.generic) {
2577 return new_type(idx).derive_add_muls(generic_type).set_flag(.generic)
2578 } else {
2579 return new_type(idx).derive_add_muls(generic_type).clear_flag(.generic)
2580 }
2581 }
2582 }
2583 ArrayFixed {
2584 if typ := t.convert_generic_type(sym.info.elem_type, generic_names, to_types) {
2585 idx := t.find_or_register_array_fixed(typ, sym.info.size, None{}, false)
2586 if typ.has_flag(.generic) {
2587 return new_type(idx).derive_add_muls(generic_type).set_flag(.generic)
2588 } else {
2589 return new_type(idx).derive_add_muls(generic_type).clear_flag(.generic)
2590 }
2591 }
2592 }
2593 Chan {
2594 if typ := t.convert_generic_type(sym.info.elem_type, generic_names, to_types) {
2595 idx := t.find_or_register_chan(typ, typ.nr_muls() > 0)
2596 if typ.has_flag(.generic) {
2597 return new_type(idx).derive_add_muls(generic_type).set_flag(.generic)
2598 } else {
2599 return new_type(idx).derive_add_muls(generic_type).clear_flag(.generic)
2600 }
2601 }
2602 }
2603 Thread {
2604 if typ := t.convert_generic_type(sym.info.return_type, generic_names, to_types) {
2605 idx := t.find_or_register_thread(typ)
2606 if typ.has_flag(.generic) {
2607 return new_type(idx).derive_add_muls(generic_type).set_flag(.generic)
2608 } else {
2609 return new_type(idx).derive_add_muls(generic_type).clear_flag(.generic)
2610 }
2611 }
2612 }
2613 FnType {
2614 mut func := sym.info.func
2615 mut has_generic := false
2616 return_type_sym := t.sym(func.return_type)
2617 if func.return_type.has_flag(.generic)
2618 || t.generic_type_names(func.return_type).len > 0
2619 || (return_type_sym.kind == .generic_inst
2620 && (return_type_sym.info as GenericInst).concrete_types.any(it.has_flag(.generic))) {
2621 if typ := t.convert_generic_type(func.return_type, generic_names, to_types) {
2622 func.return_type = typ
2623 } else {
2624 func.return_type = t.unwrap_generic_type_ex(func.return_type, generic_names,
2625 to_types, true)
2626 }
2627 if func.return_type.has_flag(.generic)
2628 || t.generic_type_names(func.return_type).len > 0 {
2629 has_generic = true
2630 }
2631 }
2632 func.params = func.params.clone()
2633 for mut param in func.params {
2634 orig_param_type := param.typ
2635 if typ := t.convert_generic_param_type(param, generic_names, to_types) {
2636 param.typ = typ
2637 }
2638 if t.sym(param.typ).kind == .placeholder {
2639 param.typ =
2640 t.unwrap_generic_type_ex(orig_param_type, generic_names, to_types, true)
2641 }
2642 if param.typ.has_flag(.generic) || t.generic_type_names(param.typ).len > 0 {
2643 has_generic = true
2644 }
2645 if param.orig_typ.has_flag(.generic) || t.generic_type_names(param.orig_typ).len > 0 {
2646 if otyp := t.convert_generic_type(param.orig_typ, generic_names, to_types) {
2647 param.orig_typ = otyp
2648 } else {
2649 param.orig_typ = t.unwrap_generic_type_ex(param.orig_typ, generic_names,
2650 to_types, true)
2651 }
2652 }
2653 }
2654 if !sym.info.is_anon && !has_generic {
2655 inst_name := t.generic_fn_inst_name(sym, to_types)
2656 idx := t.find_type_idx(inst_name)
2657 if idx > 0 {
2658 return new_type(idx).derive_add_muls(generic_type).clear_flag(.generic)
2659 }
2660 }
2661 func.name = ''
2662 func.generic_names = []
2663 idx := t.find_or_register_fn_type(func, true, false)
2664 if has_generic {
2665 return new_type(idx).derive_add_muls(generic_type).set_flag(.generic)
2666 } else {
2667 return new_type(idx).derive_add_muls(generic_type).clear_flag(.generic)
2668 }
2669 }
2670 GenericInst {
2671 mut concrete_types := sym.info.concrete_types.clone()
2672 mut type_changed := false
2673 for i, concrete_type in concrete_types {
2674 if typ := t.convert_generic_type(concrete_type, generic_names, to_types) {
2675 concrete_types[i] = typ
2676 type_changed = true
2677 }
2678 }
2679 if type_changed {
2680 idx := t.find_or_register_generic_inst(new_type(sym.info.parent_idx),
2681 concrete_types)
2682 if idx > 0 {
2683 return new_type(idx).derive_add_muls(generic_type).clear_flag(.generic)
2684 }
2685 }
2686 }
2687 MultiReturn {
2688 mut types := []Type{}
2689 mut type_changed := false
2690 for ret_type in sym.info.types {
2691 if typ := t.convert_generic_type(ret_type, generic_names, to_types) {
2692 types << typ
2693 type_changed = true
2694 } else {
2695 types << ret_type
2696 }
2697 }
2698 if type_changed {
2699 idx := t.find_or_register_multi_return(types)
2700 if types.any(it.has_flag(.generic)) {
2701 return new_type(idx).derive_add_muls(generic_type).set_flag(.generic)
2702 } else {
2703 return new_type(idx).derive_add_muls(generic_type).clear_flag(.generic)
2704 }
2705 }
2706 }
2707 Map {
2708 mut type_changed := false
2709 mut unwrapped_key_type := sym.info.key_type
2710 mut unwrapped_value_type := sym.info.value_type
2711 if typ := t.convert_generic_type(sym.info.key_type, generic_names, to_types) {
2712 unwrapped_key_type = typ
2713 type_changed = true
2714 }
2715 if typ := t.convert_generic_type(sym.info.value_type, generic_names, to_types) {
2716 unwrapped_value_type = typ
2717 type_changed = true
2718 }
2719 if type_changed {
2720 // map[Type]T where T is an alias to map type
2721 if to_types.len == 1 && sym.info.value_type.has_flag(.generic)
2722 && t.type_kind(to_types[0]) == .alias && t.final_sym(to_types[0]).kind == .map {
2723 return unwrapped_value_type
2724 }
2725 idx := t.find_or_register_map(unwrapped_key_type, unwrapped_value_type)
2726 if unwrapped_key_type.has_flag(.generic) || unwrapped_value_type.has_flag(.generic) {
2727 return new_type(idx).derive_add_muls(generic_type).set_flag(.generic)
2728 } else {
2729 return new_type(idx).derive_add_muls(generic_type).clear_flag(.generic)
2730 }
2731 }
2732 }
2733 Struct, Interface, SumType {
2734 if sym.info.is_generic {
2735 mut nrt := '${sym.name}['
2736 mut rnrt := '${sym.rname}['
2737 mut cnrt := '${sym.cname}_T_'
2738 mut converted_types := []Type{}
2739 mut t_generic_names := generic_names.clone()
2740 mut t_to_types := to_types.clone()
2741 mut has_unresolved_generic := false
2742 mut type_changed := false
2743 if sym.generic_types.len > 0 && sym.generic_types.len == sym.info.generic_types.len
2744 && sym.generic_types != sym.info.generic_types {
2745 t_generic_names = sym.info.generic_types.map(t.sym(it).name)
2746 t_to_types = []
2747 for t_typ in sym.generic_types {
2748 if !t_typ.has_flag(.generic) {
2749 t_to_types << t_typ
2750 } else {
2751 if tt := t.convert_generic_type(t_typ, generic_names, to_types) {
2752 t_to_types << tt
2753 }
2754 }
2755 }
2756 }
2757 for i in 0 .. sym.info.generic_types.len {
2758 if ct := t.convert_generic_type(sym.info.generic_types[i], t_generic_names,
2759 t_to_types)
2760 {
2761 converted_types << ct
2762 gts := t.sym(ct)
2763 if ct != sym.info.generic_types[i] {
2764 type_changed = true
2765 }
2766 if ct.is_ptr() {
2767 nrt += '&'.repeat(ct.nr_muls())
2768 cnrt += '__ptr__'.repeat(ct.nr_muls())
2769 }
2770 nrt += gts.name
2771 rnrt += gts.name
2772 cnrt += gts.scoped_cname()
2773 if i != sym.info.generic_types.len - 1 {
2774 nrt += ', '
2775 rnrt += ', '
2776 cnrt += '_T_'
2777 }
2778 if ct.has_flag(.generic) {
2779 has_unresolved_generic = true
2780 }
2781 } else {
2782 return none
2783 }
2784 }
2785 if type_changed && converted_types.len == sym.info.generic_types.len {
2786 idx := t.find_or_register_generic_inst(new_type(type_idx), converted_types)
2787 if idx > 0 {
2788 return if has_unresolved_generic {
2789 new_type(idx).derive_add_muls(generic_type).set_flag(.generic)
2790 } else {
2791 new_type(idx).derive_add_muls(generic_type).clear_flag(.generic)
2792 }
2793 }
2794 }
2795 nrt += ']'
2796 rnrt += ']'
2797 mut idx := t.type_idxs[nrt]
2798 if idx == 0 {
2799 idx = t.type_idxs[rnrt]
2800 if idx == 0 {
2801 idx = t.add_placeholder_type(nrt, cnrt, .v)
2802 }
2803 }
2804 return if has_unresolved_generic {
2805 new_type(idx).derive_add_muls(generic_type).set_flag(.generic)
2806 } else {
2807 new_type(idx).derive_add_muls(generic_type).clear_flag(.generic)
2808 }
2809 }
2810 }
2811 UnknownTypeInfo {
2812 if sym.name.contains('[') && sym.name.contains(']') {
2813 base_name := sym.name.all_before_last('[')
2814 generic_part := sym.name.all_after_last('[').trim_right(']')
2815 mut converted_args := []string{}
2816 mut has_generic := false
2817 mut changed := false
2818 args := split_generic_args(generic_part)
2819 for arg in args {
2820 if arg in generic_names {
2821 idx := generic_names.index(arg)
2822 if idx < to_types.len {
2823 converted_type := to_types[idx]
2824 converted_type_str := t.type_to_str(converted_type)
2825 if converted_type_str != arg {
2826 converted_args << converted_type_str
2827 changed = true
2828 if converted_type.has_flag(.generic) {
2829 has_generic = true
2830 }
2831 } else {
2832 converted_args << arg
2833 }
2834 } else {
2835 converted_args << arg
2836 }
2837 } else {
2838 converted_args << arg
2839 }
2840 }
2841 if changed {
2842 new_name := base_name + '[' + converted_args.join(', ') + ']'
2843 mut new_idx := t.type_idxs[new_name]
2844 if new_idx == 0 {
2845 new_idx = t.add_placeholder_type(new_name, util.no_dots(new_name).replace_each([
2846 '[',
2847 '_T_',
2848 ']',
2849 '',
2850 ', ',
2851 '_T_',
2852 ',',
2853 '_T_',
2854 ' ',
2855 '',
2856 ]), sym.language)
2857 }
2858 return if has_generic {
2859 new_type(new_idx).derive_add_muls(generic_type).set_flag(.generic)
2860 } else {
2861 new_type(new_idx).derive_add_muls(generic_type).clear_flag(.generic)
2862 }
2863 }
2864 }
2865 }
2866 else {}
2867 }
2868
2869 return none
2870}
2871
2872fn (mut t Table) lower_mut_param_type(typ Type, orig_typ ...Type) Type {
2873 // When the pointer came from the generic type argument itself (T=&int),
2874 // not from the param signature (&T), we need ref() to add one more level.
2875 orig_was_ptr := orig_typ.len > 0 && orig_typ[0].nr_muls() > 0
2876 mut lowered := if typ.is_ptr() && !orig_was_ptr {
2877 typ.ref()
2878 } else {
2879 typ.set_nr_muls(1)
2880 }
2881 if lowered.has_flag(.option) {
2882 lowered = lowered.set_flag(.option_mut_param_t)
2883 }
2884 return lowered
2885}
2886
2887pub fn (mut t Table) convert_generic_param_type(param Param, generic_names []string, to_types []Type) ?Type {
2888 if param.is_mut && param.orig_typ != 0 && param.orig_typ.has_flag(.generic)
2889 && to_types.all(!it.has_flag(.generic)) {
2890 if typ := t.convert_generic_type(param.orig_typ, generic_names, to_types) {
2891 return t.lower_mut_param_type(typ, param.orig_typ)
2892 }
2893 }
2894 return t.convert_generic_type(param.typ, generic_names, to_types)
2895}
2896
2897// type_contains_placeholder returns true if the given type or any of its inner
2898// generic types resolves to a placeholder (i.e., an undefined/unknown type).
2899pub fn (t &Table) type_contains_placeholder(typ Type) bool {
2900 sym := t.sym(typ)
2901 if sym.kind == .placeholder {
2902 return true
2903 }
2904 return match sym.info {
2905 Array {
2906 t.type_contains_placeholder(sym.info.elem_type)
2907 }
2908 ArrayFixed {
2909 t.type_contains_placeholder(sym.info.elem_type)
2910 }
2911 Map {
2912 t.type_contains_placeholder(sym.info.key_type)
2913 || t.type_contains_placeholder(sym.info.value_type)
2914 }
2915 SumType {
2916 sym.info.concrete_types.any(t.type_contains_placeholder(it))
2917 }
2918 Struct {
2919 sym.info.concrete_types.any(t.type_contains_placeholder(it))
2920 }
2921 else {
2922 false
2923 }
2924 }
2925}
2926
2927pub fn (mut t Table) unwrap_generic_param_type(param Param, generic_names []string, concrete_types []Type) Type {
2928 if param.is_mut && param.orig_typ != 0 && param.orig_typ.has_flag(.generic)
2929 && concrete_types.all(!it.has_flag(.generic)) {
2930 return t.lower_mut_param_type(t.unwrap_generic_type(param.orig_typ, generic_names,
2931 concrete_types))
2932 }
2933 return t.unwrap_generic_type(param.typ, generic_names, concrete_types)
2934}
2935
2936// convert_generic_expr_type resolves generic placeholders stored inside expression metadata.
2937// Some synthesized concrete types use default expressions directly from type symbols, so these
2938// types need to be specialized eagerly instead of relying on a later checker pass.
2939fn (mut t Table) convert_generic_expr_type(typ Type, generic_names []string, concrete_types []Type) Type {
2940 if typ == 0 {
2941 return typ
2942 }
2943 return t.convert_generic_type(typ, generic_names, concrete_types) or { typ }
2944}
2945
2946fn (mut t Table) convert_generic_expr_types(types []Type, generic_names []string, concrete_types []Type) []Type {
2947 if types.len == 0 {
2948 return types
2949 }
2950 mut resolved := []Type{len: types.len}
2951 for i, typ in types {
2952 resolved[i] = t.convert_generic_expr_type(typ, generic_names, concrete_types)
2953 }
2954 return resolved
2955}
2956
2957fn (mut t Table) convert_generic_nested_expr_types(types [][]Type, generic_names []string, concrete_types []Type) [][]Type {
2958 if types.len == 0 {
2959 return types
2960 }
2961 mut resolved := [][]Type{len: types.len}
2962 for i, inner in types {
2963 resolved[i] = t.convert_generic_expr_types(inner, generic_names, concrete_types)
2964 }
2965 return resolved
2966}
2967
2968fn (mut t Table) convert_generic_call_args(args []CallArg, generic_names []string, concrete_types []Type) []CallArg {
2969 if args.len == 0 {
2970 return args
2971 }
2972 mut resolved := []CallArg{len: args.len}
2973 for i, arg in args {
2974 resolved[i] = CallArg{
2975 ...arg
2976 expr: t.convert_generic_default_expr(arg.expr, generic_names, concrete_types)
2977 typ: t.convert_generic_expr_type(arg.typ, generic_names, concrete_types)
2978 }
2979 }
2980 return resolved
2981}
2982
2983fn (mut t Table) convert_generic_struct_init_fields(fields []StructInitField, generic_names []string, concrete_types []Type) []StructInitField {
2984 if fields.len == 0 {
2985 return fields
2986 }
2987 mut resolved := []StructInitField{len: fields.len}
2988 for i, field in fields {
2989 resolved[i] = StructInitField{
2990 ...field
2991 expr: t.convert_generic_default_expr(field.expr, generic_names, concrete_types)
2992 typ: t.convert_generic_expr_type(field.typ, generic_names, concrete_types)
2993 expected_type: t.convert_generic_expr_type(field.expected_type, generic_names,
2994 concrete_types)
2995 parent_type: t.convert_generic_expr_type(field.parent_type, generic_names,
2996 concrete_types)
2997 }
2998 }
2999 return resolved
3000}
3001
3002fn (mut t Table) convert_generic_default_expr(expr Expr, generic_names []string, concrete_types []Type) Expr {
3003 match expr {
3004 ArrayDecompose {
3005 return Expr(ArrayDecompose{
3006 ...expr
3007 expr: t.convert_generic_default_expr(expr.expr, generic_names, concrete_types)
3008 expr_type: t.convert_generic_expr_type(expr.expr_type, generic_names,
3009 concrete_types)
3010 arg_type: t.convert_generic_expr_type(expr.arg_type, generic_names, concrete_types)
3011 })
3012 }
3013 ArrayInit {
3014 mut exprs := []Expr{cap: expr.exprs.len}
3015 for node in expr.exprs {
3016 exprs << t.convert_generic_default_expr(node, generic_names, concrete_types)
3017 }
3018 return Expr(ArrayInit{
3019 ...expr
3020 exprs: exprs
3021 len_expr: t.convert_generic_default_expr(expr.len_expr, generic_names,
3022 concrete_types)
3023 cap_expr: t.convert_generic_default_expr(expr.cap_expr, generic_names,
3024 concrete_types)
3025 init_expr: t.convert_generic_default_expr(expr.init_expr, generic_names,
3026 concrete_types)
3027 expr_types: t.convert_generic_expr_types(expr.expr_types, generic_names,
3028 concrete_types)
3029 elem_type: t.convert_generic_expr_type(expr.elem_type, generic_names,
3030 concrete_types)
3031 init_type: t.convert_generic_expr_type(expr.init_type, generic_names,
3032 concrete_types)
3033 typ: t.convert_generic_expr_type(expr.typ, generic_names, concrete_types)
3034 alias_type: t.convert_generic_expr_type(expr.alias_type, generic_names,
3035 concrete_types)
3036 })
3037 }
3038 AsCast {
3039 return Expr(AsCast{
3040 ...expr
3041 typ: t.convert_generic_expr_type(expr.typ, generic_names, concrete_types)
3042 expr: t.convert_generic_default_expr(expr.expr, generic_names, concrete_types)
3043 expr_type: t.convert_generic_expr_type(expr.expr_type, generic_names,
3044 concrete_types)
3045 })
3046 }
3047 CallExpr {
3048 mut resolved_concrete_types := t.convert_generic_expr_types(expr.concrete_types,
3049 generic_names, concrete_types)
3050 mut name := expr.name
3051 if !expr.is_method {
3052 if func := t.find_fn_in_mod(expr.name, expr.mod) {
3053 name = func.name
3054 if func.generic_names.len > 0 && resolved_concrete_types.len == 0 {
3055 for fn_generic_name in func.generic_names {
3056 idx := generic_names.index(fn_generic_name)
3057 if idx >= 0 && idx < concrete_types.len {
3058 resolved_concrete_types << concrete_types[idx]
3059 }
3060 }
3061 }
3062 if resolved_concrete_types.len == func.generic_names.len
3063 && resolved_concrete_types.all(!it.has_flag(.generic)) {
3064 t.register_fn_concrete_types(func.fkey(), resolved_concrete_types)
3065 }
3066 }
3067 }
3068 return Expr(CallExpr{
3069 ...expr
3070 name: name
3071 args: t.convert_generic_call_args(expr.args, generic_names,
3072 concrete_types)
3073 expected_arg_types: t.convert_generic_expr_types(expr.expected_arg_types,
3074 generic_names, concrete_types)
3075 left: t.convert_generic_default_expr(expr.left, generic_names,
3076 concrete_types)
3077 left_type: t.convert_generic_expr_type(expr.left_type, generic_names,
3078 concrete_types)
3079 receiver_type: t.convert_generic_expr_type(expr.receiver_type,
3080 generic_names, concrete_types)
3081 receiver_concrete_type: t.convert_generic_expr_type(expr.receiver_concrete_type,
3082 generic_names, concrete_types)
3083 return_type: t.convert_generic_expr_type(expr.return_type,
3084 generic_names, concrete_types)
3085 return_type_generic: t.convert_generic_expr_type(expr.return_type_generic,
3086 generic_names, concrete_types)
3087 fn_var_type: t.convert_generic_expr_type(expr.fn_var_type,
3088 generic_names, concrete_types)
3089 concrete_types: resolved_concrete_types
3090 raw_concrete_types: if expr.raw_concrete_types.len > 0 {
3091 t.convert_generic_expr_types(expr.raw_concrete_types, generic_names,
3092 concrete_types)
3093 } else {
3094 resolved_concrete_types
3095 }
3096 from_embed_types: t.convert_generic_expr_types(expr.from_embed_types,
3097 generic_names, concrete_types)
3098 })
3099 }
3100 CastExpr {
3101 return Expr(CastExpr{
3102 ...expr
3103 arg: t.convert_generic_default_expr(expr.arg, generic_names, concrete_types)
3104 typ: t.convert_generic_expr_type(expr.typ, generic_names, concrete_types)
3105 expr: t.convert_generic_default_expr(expr.expr, generic_names, concrete_types)
3106 expr_type: t.convert_generic_expr_type(expr.expr_type, generic_names,
3107 concrete_types)
3108 })
3109 }
3110 ChanInit {
3111 return Expr(ChanInit{
3112 ...expr
3113 cap_expr: t.convert_generic_default_expr(expr.cap_expr, generic_names,
3114 concrete_types)
3115 typ: t.convert_generic_expr_type(expr.typ, generic_names, concrete_types)
3116 elem_type: t.convert_generic_expr_type(expr.elem_type, generic_names,
3117 concrete_types)
3118 })
3119 }
3120 ConcatExpr {
3121 mut vals := []Expr{cap: expr.vals.len}
3122 for node in expr.vals {
3123 vals << t.convert_generic_default_expr(node, generic_names, concrete_types)
3124 }
3125 return Expr(ConcatExpr{
3126 ...expr
3127 vals: vals
3128 return_type: t.convert_generic_expr_type(expr.return_type, generic_names,
3129 concrete_types)
3130 })
3131 }
3132 DumpExpr {
3133 return Expr(DumpExpr{
3134 ...expr
3135 expr: t.convert_generic_default_expr(expr.expr, generic_names, concrete_types)
3136 expr_type: t.convert_generic_expr_type(expr.expr_type, generic_names,
3137 concrete_types)
3138 })
3139 }
3140 Ident {
3141 mut resolved_concrete_types := t.convert_generic_expr_types(expr.concrete_types,
3142 generic_names, concrete_types)
3143 mut info := expr.info
3144 mut kind := expr.kind
3145 mut name := expr.name
3146 match mut info {
3147 IdentFn {
3148 info.typ = t.convert_generic_expr_type(info.typ, generic_names, concrete_types)
3149 }
3150 IdentVar {
3151 info.typ = t.convert_generic_expr_type(info.typ, generic_names, concrete_types)
3152 }
3153 }
3154
3155 mut obj := expr.obj
3156 match mut obj {
3157 AsmRegister {
3158 obj.typ = t.convert_generic_expr_type(obj.typ, generic_names, concrete_types)
3159 }
3160 ConstField {
3161 obj.typ = t.convert_generic_expr_type(obj.typ, generic_names, concrete_types)
3162 }
3163 EmptyScopeObject {
3164 obj.typ = t.convert_generic_expr_type(obj.typ, generic_names, concrete_types)
3165 }
3166 GlobalField {
3167 obj.typ = t.convert_generic_expr_type(obj.typ, generic_names, concrete_types)
3168 }
3169 Var {
3170 obj.typ = t.convert_generic_expr_type(obj.typ, generic_names, concrete_types)
3171 obj.orig_type = t.convert_generic_expr_type(obj.orig_type, generic_names,
3172 concrete_types)
3173 obj.smartcasts = t.convert_generic_expr_types(obj.smartcasts, generic_names,
3174 concrete_types)
3175 }
3176 }
3177
3178 if func := t.find_fn_in_mod(expr.name, expr.mod) {
3179 name = func.name
3180 mut fn_type := t.find_or_register_fn_type(func, false, true)
3181 if fn_type < 0 {
3182 mut f := Fn{
3183 ...func
3184 }
3185 f.name = ''
3186 fn_type = t.find_or_register_fn_type(f, false, true)
3187 }
3188 if func.generic_names.len > 0 && resolved_concrete_types.len == 0 {
3189 for fn_generic_name in func.generic_names {
3190 idx := generic_names.index(fn_generic_name)
3191 if idx >= 0 && idx < concrete_types.len {
3192 resolved_concrete_types << concrete_types[idx]
3193 }
3194 }
3195 }
3196 if func.generic_names.len > 0 {
3197 if typ_ := t.convert_generic_type(fn_type, func.generic_names,
3198 resolved_concrete_types)
3199 {
3200 fn_type = typ_
3201 }
3202 }
3203 if fn_type > 0 {
3204 kind = .function
3205 info = IdentFn{
3206 typ: fn_type
3207 }
3208 }
3209 if resolved_concrete_types.len == func.generic_names.len
3210 && resolved_concrete_types.all(!it.has_flag(.generic)) {
3211 t.register_fn_concrete_types(func.fkey(), resolved_concrete_types)
3212 }
3213 }
3214 return Expr(Ident{
3215 ...expr
3216 name: name
3217 obj: obj
3218 info: info
3219 kind: kind
3220 concrete_types: resolved_concrete_types
3221 })
3222 }
3223 IfGuardExpr {
3224 return Expr(IfGuardExpr{
3225 ...expr
3226 expr: t.convert_generic_default_expr(expr.expr, generic_names, concrete_types)
3227 expr_type: t.convert_generic_expr_type(expr.expr_type, generic_names,
3228 concrete_types)
3229 })
3230 }
3231 IndexExpr {
3232 return Expr(IndexExpr{
3233 ...expr
3234 index: t.convert_generic_default_expr(expr.index, generic_names,
3235 concrete_types)
3236 left: t.convert_generic_default_expr(expr.left, generic_names,
3237 concrete_types)
3238 left_type: t.convert_generic_expr_type(expr.left_type, generic_names,
3239 concrete_types)
3240 index_type: t.convert_generic_expr_type(expr.index_type, generic_names,
3241 concrete_types)
3242 setter_arg_type: t.convert_generic_expr_type(expr.setter_arg_type, generic_names,
3243 concrete_types)
3244 typ: t.convert_generic_expr_type(expr.typ, generic_names,
3245 concrete_types)
3246 })
3247 }
3248 InfixExpr {
3249 return Expr(InfixExpr{
3250 ...expr
3251 left: t.convert_generic_default_expr(expr.left, generic_names,
3252 concrete_types)
3253 right: t.convert_generic_default_expr(expr.right, generic_names,
3254 concrete_types)
3255 left_type: t.convert_generic_expr_type(expr.left_type, generic_names,
3256 concrete_types)
3257 right_type: t.convert_generic_expr_type(expr.right_type, generic_names,
3258 concrete_types)
3259 promoted_type: t.convert_generic_expr_type(expr.promoted_type, generic_names,
3260 concrete_types)
3261 })
3262 }
3263 IsRefType {
3264 return Expr(IsRefType{
3265 ...expr
3266 expr: t.convert_generic_default_expr(expr.expr, generic_names, concrete_types)
3267 typ: t.convert_generic_expr_type(expr.typ, generic_names, concrete_types)
3268 })
3269 }
3270 Likely {
3271 return Expr(Likely{
3272 ...expr
3273 expr: t.convert_generic_default_expr(expr.expr, generic_names, concrete_types)
3274 })
3275 }
3276 MapInit {
3277 mut keys := []Expr{cap: expr.keys.len}
3278 for node in expr.keys {
3279 keys << t.convert_generic_default_expr(node, generic_names, concrete_types)
3280 }
3281 mut vals := []Expr{cap: expr.vals.len}
3282 for node in expr.vals {
3283 vals << t.convert_generic_default_expr(node, generic_names, concrete_types)
3284 }
3285 return Expr(MapInit{
3286 ...expr
3287 keys: keys
3288 vals: vals
3289 val_types: t.convert_generic_expr_types(expr.val_types, generic_names,
3290 concrete_types)
3291 typ: t.convert_generic_expr_type(expr.typ, generic_names, concrete_types)
3292 key_type: t.convert_generic_expr_type(expr.key_type, generic_names,
3293 concrete_types)
3294 value_type: t.convert_generic_expr_type(expr.value_type, generic_names,
3295 concrete_types)
3296 update_expr: t.convert_generic_default_expr(expr.update_expr, generic_names,
3297 concrete_types)
3298 })
3299 }
3300 OffsetOf {
3301 return Expr(OffsetOf{
3302 ...expr
3303 struct_type: t.convert_generic_expr_type(expr.struct_type, generic_names,
3304 concrete_types)
3305 })
3306 }
3307 ParExpr {
3308 return Expr(ParExpr{
3309 ...expr
3310 expr: t.convert_generic_default_expr(expr.expr, generic_names, concrete_types)
3311 })
3312 }
3313 PostfixExpr {
3314 return Expr(PostfixExpr{
3315 ...expr
3316 expr: t.convert_generic_default_expr(expr.expr, generic_names, concrete_types)
3317 typ: t.convert_generic_expr_type(expr.typ, generic_names, concrete_types)
3318 })
3319 }
3320 PrefixExpr {
3321 return Expr(PrefixExpr{
3322 ...expr
3323 right_type: t.convert_generic_expr_type(expr.right_type, generic_names,
3324 concrete_types)
3325 right: t.convert_generic_default_expr(expr.right, generic_names,
3326 concrete_types)
3327 })
3328 }
3329 RangeExpr {
3330 return Expr(RangeExpr{
3331 ...expr
3332 low: t.convert_generic_default_expr(expr.low, generic_names, concrete_types)
3333 high: t.convert_generic_default_expr(expr.high, generic_names, concrete_types)
3334 typ: t.convert_generic_expr_type(expr.typ, generic_names, concrete_types)
3335 })
3336 }
3337 SelectorExpr {
3338 return Expr(SelectorExpr{
3339 ...expr
3340 expr: t.convert_generic_default_expr(expr.expr, generic_names,
3341 concrete_types)
3342 expr_type: t.convert_generic_expr_type(expr.expr_type,
3343 generic_names, concrete_types)
3344 typ: t.convert_generic_expr_type(expr.typ, generic_names,
3345 concrete_types)
3346 name_type: t.convert_generic_expr_type(expr.name_type,
3347 generic_names, concrete_types)
3348 from_embed_types: t.convert_generic_expr_types(expr.from_embed_types,
3349 generic_names, concrete_types)
3350 generic_from_embed_types: t.convert_generic_nested_expr_types(expr.generic_from_embed_types,
3351 generic_names, concrete_types)
3352 })
3353 }
3354 SizeOf {
3355 return Expr(SizeOf{
3356 ...expr
3357 expr: t.convert_generic_default_expr(expr.expr, generic_names, concrete_types)
3358 typ: t.convert_generic_expr_type(expr.typ, generic_names, concrete_types)
3359 })
3360 }
3361 StringInterLiteral {
3362 mut exprs := []Expr{cap: expr.exprs.len}
3363 for node in expr.exprs {
3364 exprs << t.convert_generic_default_expr(node, generic_names, concrete_types)
3365 }
3366 return Expr(StringInterLiteral{
3367 ...expr
3368 exprs: exprs
3369 expr_types: t.convert_generic_expr_types(expr.expr_types, generic_names,
3370 concrete_types)
3371 })
3372 }
3373 StructInit {
3374 return Expr(StructInit{
3375 ...expr
3376 generic_typ: t.convert_generic_expr_type(expr.generic_typ, generic_names,
3377 concrete_types)
3378 typ: t.convert_generic_expr_type(expr.typ, generic_names,
3379 concrete_types)
3380 update_expr: t.convert_generic_default_expr(expr.update_expr, generic_names,
3381 concrete_types)
3382 update_expr_type: t.convert_generic_expr_type(expr.update_expr_type, generic_names,
3383 concrete_types)
3384 init_fields: t.convert_generic_struct_init_fields(expr.init_fields,
3385 generic_names, concrete_types)
3386 generic_types: t.convert_generic_expr_types(expr.generic_types, generic_names,
3387 concrete_types)
3388 })
3389 }
3390 TypeNode {
3391 return Expr(TypeNode{
3392 ...expr
3393 typ: t.convert_generic_expr_type(expr.typ, generic_names, concrete_types)
3394 })
3395 }
3396 TypeOf {
3397 return Expr(TypeOf{
3398 ...expr
3399 expr: t.convert_generic_default_expr(expr.expr, generic_names, concrete_types)
3400 typ: t.convert_generic_expr_type(expr.typ, generic_names, concrete_types)
3401 })
3402 }
3403 UnsafeExpr {
3404 return Expr(UnsafeExpr{
3405 ...expr
3406 expr: t.convert_generic_default_expr(expr.expr, generic_names, concrete_types)
3407 })
3408 }
3409 else {}
3410 }
3411
3412 return expr
3413}
3414
3415fn generic_names_push_with_filter(mut to_names []string, from_names []string) {
3416 for name in from_names {
3417 if name !in to_names {
3418 to_names << name
3419 }
3420 }
3421}
3422
3423fn (ts &TypeSymbol) has_generic_type_info() bool {
3424 return match ts.info {
3425 Struct, Interface, SumType { ts.info.is_generic }
3426 else { false }
3427 }
3428}
3429
3430fn (t &Table) find_fn_in_mod(name string, mod string) ?Fn {
3431 if func := t.find_fn(name) {
3432 return func
3433 }
3434 if mod != '' && !name.contains('.') {
3435 if func := t.find_fn('${mod}.${name}') {
3436 return func
3437 }
3438 }
3439 return none
3440}
3441
3442pub fn (mut t Table) generic_type_names(generic_type Type) []string {
3443 mut names := []string{}
3444 idx := generic_type.idx()
3445 if idx == 0 || idx >= t.type_symbols.len {
3446 return names
3447 }
3448 mut sym := t.sym(generic_type)
3449 if sym.name.len == 1 && sym.name[0].is_capital() {
3450 names << sym.name
3451 return names
3452 }
3453 match mut sym.info {
3454 Array {
3455 _, elem_type := t.get_array_dims(sym.info)
3456 names << t.generic_type_names(elem_type)
3457 }
3458 ArrayFixed {
3459 names << t.generic_type_names(sym.info.elem_type)
3460 }
3461 Chan {
3462 names << t.generic_type_names(sym.info.elem_type)
3463 }
3464 FnType {
3465 for param in sym.info.func.params {
3466 generic_names_push_with_filter(mut names, t.generic_type_names(param.typ))
3467 if param.orig_typ != 0 {
3468 generic_names_push_with_filter(mut names, t.generic_type_names(param.orig_typ))
3469 }
3470 }
3471 generic_names_push_with_filter(mut names,
3472 t.generic_type_names(sym.info.func.return_type))
3473 if names.len == 0 {
3474 generic_names_push_with_filter(mut names, sym.info.func.generic_names)
3475 }
3476 }
3477 MultiReturn {
3478 for ret_type in sym.info.types {
3479 generic_names_push_with_filter(mut names, t.generic_type_names(ret_type))
3480 }
3481 }
3482 Map {
3483 names << t.generic_type_names(sym.info.key_type)
3484 generic_names_push_with_filter(mut names, t.generic_type_names(sym.info.value_type))
3485 }
3486 Struct, Interface, SumType {
3487 if sym.info.is_generic {
3488 if sym.generic_types.len > 0 {
3489 // Foo[U] (declaration: Foo[T])
3490 for typ in sym.generic_types {
3491 if typ.has_flag(.generic) && t.sym(typ).kind == .any {
3492 names << t.sym(typ).name
3493 }
3494 }
3495 } else {
3496 names << sym.info.generic_types.map(t.sym(it).name)
3497 }
3498 }
3499 }
3500 else {
3501 // For placeholder types (forward-declared generic structs),
3502 // check generic_types on the symbol itself
3503 if sym.generic_types.len > 0 {
3504 for typ in sym.generic_types {
3505 if typ.has_flag(.generic) && t.sym(typ).kind == .any {
3506 names << t.sym(typ).name
3507 }
3508 }
3509 }
3510 }
3511 }
3512
3513 return names
3514}
3515
3516// unwrap_generic_type resolves generic symbols to their concrete types.
3517pub fn (mut t Table) unwrap_generic_type(typ Type, generic_names []string, concrete_types []Type) Type {
3518 return t.unwrap_generic_type_ex(typ, generic_names, concrete_types, false)
3519}
3520
3521// unwrap_generic_type_ex resolves generic symbols to concrete types and can recheck nested concrete fields.
3522pub fn (mut t Table) unwrap_generic_type_ex(typ Type, generic_names []string, concrete_types []Type, recheck_concrete_types bool) Type {
3523 return t.unwrap_generic_type_ex_with_depth(typ, generic_names, concrete_types,
3524 recheck_concrete_types, []string{})
3525}
3526
3527fn (mut t Table) unwrap_generic_type_ex_with_depth(typ Type, generic_names []string, concrete_types []Type, recheck_concrete_types bool, depth_guard []string) Type {
3528 mut final_concrete_types := []Type{}
3529 mut fields := []StructField{}
3530 mut nrt := ''
3531 mut c_nrt := ''
3532 mut new_depth_guard := []string{}
3533 type_idx := typ.idx()
3534 if type_idx == 0 || type_idx >= t.type_symbols.len {
3535 return typ
3536 }
3537 for ct in concrete_types {
3538 if ct.idx() == 0 || ct.idx() >= t.type_symbols.len {
3539 return typ
3540 }
3541 }
3542 ts := t.type_symbols[type_idx]
3543 match ts.info {
3544 Array {
3545 dims, elem_type := t.get_array_dims(ts.info)
3546 unwrap_typ := t.unwrap_generic_type_ex_with_depth(elem_type, generic_names,
3547 concrete_types, recheck_concrete_types, depth_guard)
3548 idx := t.find_or_register_array_with_dims(unwrap_typ, dims)
3549 if idx <= 0 {
3550 return typ
3551 }
3552 return new_type(idx).derive_add_muls(typ).clear_flag(.generic)
3553 }
3554 ArrayFixed {
3555 unwrap_typ := t.unwrap_generic_type_ex_with_depth(ts.info.elem_type, generic_names,
3556 concrete_types, recheck_concrete_types, depth_guard)
3557 idx := t.find_or_register_array_fixed(unwrap_typ, ts.info.size, None{}, false)
3558 if idx <= 0 {
3559 return typ
3560 }
3561 return new_type(idx).derive_add_muls(typ).clear_flag(.generic)
3562 }
3563 Chan {
3564 unwrap_typ := t.unwrap_generic_type(ts.info.elem_type, generic_names, concrete_types)
3565 idx := t.find_or_register_chan(unwrap_typ, unwrap_typ.nr_muls() > 0)
3566 if idx <= 0 {
3567 return typ
3568 }
3569 return new_type(idx).derive_add_muls(typ).clear_flag(.generic)
3570 }
3571 Thread {
3572 unwrap_typ := t.unwrap_generic_type_ex_with_depth(ts.info.return_type, generic_names,
3573 concrete_types, recheck_concrete_types, depth_guard)
3574 idx := t.find_or_register_thread(unwrap_typ)
3575 if idx <= 0 {
3576 return typ
3577 }
3578 return new_type(idx).derive_add_muls(typ).clear_flag(.generic)
3579 }
3580 Map {
3581 unwrap_key_type := t.unwrap_generic_type_ex_with_depth(ts.info.key_type, generic_names,
3582 concrete_types, recheck_concrete_types, depth_guard)
3583 unwrap_value_type := t.unwrap_generic_type_ex_with_depth(ts.info.value_type,
3584 generic_names, concrete_types, recheck_concrete_types, depth_guard)
3585 idx := t.find_or_register_map(unwrap_key_type, unwrap_value_type)
3586 if idx <= 0 {
3587 return typ
3588 }
3589 return new_type(idx).derive_add_muls(typ).clear_flag(.generic)
3590 }
3591 FnType {
3592 mut unwrapped_fn := ts.info.func
3593 unwrapped_fn.params = unwrapped_fn.params.clone()
3594 mut has_generic := false
3595 for i, param in unwrapped_fn.params {
3596 if param.typ.has_flag(.generic) || t.generic_type_names(param.typ).len > 0 {
3597 unwrapped_fn.params[i].typ = t.unwrap_generic_param_type(param, generic_names,
3598 concrete_types)
3599 has_generic = true
3600 }
3601 if param.orig_typ.has_flag(.generic) || t.generic_type_names(param.orig_typ).len > 0 {
3602 unwrapped_fn.params[i].orig_typ = t.unwrap_generic_type(param.orig_typ,
3603 generic_names, concrete_types)
3604 }
3605 }
3606 if unwrapped_fn.return_type.has_flag(.generic)
3607 || t.generic_type_names(unwrapped_fn.return_type).len > 0
3608 || (unwrapped_fn.return_type.idx() > 0 && unwrapped_fn.return_type.idx() < t.type_symbols.len
3609 && t.sym(unwrapped_fn.return_type).kind == .generic_inst&& (t.sym(unwrapped_fn.return_type).info as GenericInst).concrete_types.any(it.has_flag(.generic))) {
3610 unwrapped_fn.return_type = t.unwrap_generic_type_ex_with_depth(unwrapped_fn.return_type,
3611 generic_names, concrete_types, recheck_concrete_types, depth_guard)
3612 has_generic = true
3613 }
3614 if has_generic {
3615 if !ts.info.is_anon {
3616 inst_name := t.generic_fn_inst_name(ts, concrete_types)
3617 idx := t.find_type_idx(inst_name)
3618 if idx > 0 {
3619 return new_type(idx).derive_add_muls(typ).clear_flag(.generic)
3620 }
3621 }
3622 // Clear the name so find_or_register_fn_type registers a new anonymous fn
3623 // type with the resolved concrete param/return types, instead of returning
3624 // the existing generic fn type entry (matched by name).
3625 unwrapped_fn.name = ''
3626 unwrapped_fn.generic_names = []
3627 idx := t.find_or_register_fn_type(unwrapped_fn, true, false)
3628 if idx <= 0 {
3629 return typ
3630 }
3631 return new_type(idx).derive_add_muls(typ).clear_flag(.generic)
3632 }
3633 return typ
3634 }
3635 Struct, Interface, SumType {
3636 if !ts.info.is_generic {
3637 return typ
3638 }
3639 mut t_generic_names := generic_names.clone()
3640 mut t_concrete_types := concrete_types.clone()
3641 if ts.generic_types.len > 0 && ts.generic_types.len == ts.info.generic_types.len
3642 && ts.generic_types != ts.info.generic_types {
3643 t_generic_names = ts.info.generic_types.map(t.sym(it).name)
3644 t_concrete_types = []
3645 for t_typ in ts.generic_types {
3646 if !t_typ.has_flag(.generic) {
3647 t_concrete_types << t_typ
3648 } else {
3649 t_concrete_types << t.unwrap_generic_type(t_typ, generic_names,
3650 concrete_types)
3651 }
3652 }
3653 }
3654 base_name := if ts.ngname == '' { ts.name } else { ts.ngname }
3655 nrt = '${base_name}['
3656 c_nrt = '${ts.cname}_T_'
3657 for i in 0 .. ts.info.generic_types.len {
3658 if ct := t.convert_generic_type(ts.info.generic_types[i], t_generic_names,
3659 t_concrete_types)
3660 {
3661 gts := t.sym(ct)
3662 if ct.is_ptr() {
3663 nrt += '&'.repeat(ct.nr_muls())
3664 c_nrt += '__ptr__'.repeat(ct.nr_muls())
3665 }
3666 nrt += gts.name
3667 c_nrt += gts.scoped_cname()
3668 if i != ts.info.generic_types.len - 1 {
3669 nrt += ', '
3670 c_nrt += '_T_'
3671 }
3672 } else {
3673 return typ
3674 }
3675 }
3676 nrt += ']'
3677 mut idx := t.type_idxs[nrt]
3678 if idx != 0 && t.type_symbols[idx].kind != .placeholder {
3679 if recheck_concrete_types {
3680 // Rechecking an already-registered concrete generic can revisit the same
3681 // self-referential type through one of its fields.
3682 if nrt in depth_guard {
3683 if idx <= 0 {
3684 return typ
3685 }
3686 return new_type(idx).derive(typ).clear_flag(.generic)
3687 }
3688 new_depth_guard = []string{cap: depth_guard.len + 1}
3689 new_depth_guard << depth_guard
3690 new_depth_guard << nrt
3691 fields = ts.info.fields.clone()
3692 for i in 0 .. fields.len {
3693 resolved_field_typ := t.unwrap_generic_type_ex_with_depth(fields[i].typ,
3694 t_generic_names, t_concrete_types, recheck_concrete_types,
3695 new_depth_guard)
3696 if resolved_field_typ != fields[i].typ {
3697 fields[i].typ = resolved_field_typ
3698 }
3699 }
3700 // update concrete types
3701 for i in 0 .. ts.info.generic_types.len {
3702 if t_typ := t.convert_generic_type(ts.info.generic_types[i],
3703 t_generic_names, t_concrete_types)
3704 {
3705 final_concrete_types << t_typ
3706 }
3707 }
3708 if final_concrete_types.len > 0 {
3709 t.unwrap_method_types(ts, generic_names, concrete_types)
3710 }
3711 }
3712 if idx <= 0 {
3713 return typ
3714 }
3715 return new_type(idx).derive(typ).clear_flag(.generic)
3716 }
3717 if idx == 0 {
3718 idx = t.add_placeholder_type(nrt, c_nrt, .v)
3719 }
3720 if nrt in depth_guard {
3721 // The concrete type is currently being built higher in the stack.
3722 // Reuse its placeholder to avoid recursive generic unwrapping loops.
3723 if idx <= 0 {
3724 return typ
3725 }
3726 return new_type(idx).derive(typ).clear_flag(.generic)
3727 }
3728 new_depth_guard = []string{cap: depth_guard.len + 1}
3729 new_depth_guard << depth_guard
3730 new_depth_guard << nrt
3731 // fields type translate to concrete type
3732 fields = ts.info.fields.clone()
3733 for i in 0 .. fields.len {
3734 orig_type := fields[i].typ
3735 resolved_field_typ := t.unwrap_generic_type_ex_with_depth(orig_type,
3736 t_generic_names, t_concrete_types, recheck_concrete_types, new_depth_guard)
3737 if resolved_field_typ != orig_type {
3738 fields[i].typ = resolved_field_typ
3739 // Update type in `info.embeds`, if it's embed
3740 if fields[i].is_embed {
3741 mut parent_sym := t.sym(typ)
3742 mut parent_info := parent_sym.info
3743 if mut parent_info is Struct {
3744 for mut embed in parent_info.embeds {
3745 if embed == orig_type {
3746 embed = fields[i].typ
3747 break
3748 }
3749 }
3750 }
3751 }
3752 }
3753 if fields[i].has_default_expr {
3754 if fields[i].default_expr_typ != 0 && fields[i].default_expr_typ != nil_type {
3755 fields[i].default_expr_typ = t.convert_generic_expr_type(fields[i].default_expr_typ,
3756 t_generic_names, t_concrete_types)
3757 fields[i].default_expr = t.convert_generic_default_expr(fields[i].default_expr,
3758 t_generic_names, t_concrete_types)
3759 } else if fields[i].default_expr_typ == 0
3760 || fields[i].default_expr_typ == nil_type {
3761 if fields[i].default_expr.is_nil() && fields[i].typ.is_any_kind_of_pointer() {
3762 fields[i].default_expr_typ = fields[i].typ
3763 }
3764 }
3765 }
3766 }
3767 // update concrete types
3768 for i in 0 .. ts.info.generic_types.len {
3769 if t_typ := t.convert_generic_type(ts.info.generic_types[i], t_generic_names,
3770 t_concrete_types)
3771 {
3772 final_concrete_types << t_typ
3773 }
3774 }
3775 // If concrete types still contain generic parameters (e.g. Vec3[U] where U
3776 // is unresolved), don't create a partially-resolved struct entry. The struct
3777 // will be properly instantiated when all type parameters are known.
3778 //
3779 // Structural check via generic_type_names catches entries like `[]T`
3780 // whose `.generic` Type-flag has been cleared but whose type structure
3781 // still references an unresolved generic parameter. Without this check,
3782 // such entries reach register_sym below and leak into codegen as
3783 // `Array_T` / placeholder-typed struct fields.
3784 if final_concrete_types.any(it.has_flag(.generic))
3785 || final_concrete_types.any(t.generic_type_names(it).len > 0) {
3786 return typ
3787 }
3788 }
3789 GenericInst {
3790 // Resolve GenericInst concrete_types that still contain generic parameters.
3791 // E.g. CacheStore[K, &CacheItem[K, V]] with K=string, V=int becomes
3792 // CacheStore[string, &CacheItem[string, int]].
3793 mut resolved_cts := ts.info.concrete_types.clone()
3794 mut changed := false
3795 for i in 0 .. resolved_cts.len {
3796 if resolved_cts[i].has_flag(.generic) {
3797 new_ct := t.unwrap_generic_type_ex_with_depth(resolved_cts[i], generic_names,
3798 concrete_types, recheck_concrete_types, depth_guard)
3799 if new_ct != resolved_cts[i] {
3800 resolved_cts[i] = new_ct
3801 changed = true
3802 }
3803 }
3804 }
3805 if changed {
3806 parent_typ := new_type(ts.info.parent_idx)
3807 idx := t.find_or_register_generic_inst(parent_typ, resolved_cts)
3808 if idx > 0 {
3809 return new_type(idx).derive_add_muls(typ).clear_flag(.generic)
3810 }
3811 }
3812 return typ
3813 }
3814 else {}
3815 }
3816
3817 match ts.info {
3818 Struct {
3819 mut info := ts.info
3820 info.is_generic = false
3821 info.concrete_types = final_concrete_types
3822 info.parent_type = typ.set_flag(.generic)
3823 info.fields = fields
3824 new_idx := t.register_sym(
3825 kind: .struct
3826 name: nrt
3827 cname: util.no_dots(c_nrt)
3828 parent_idx: typ.idx()
3829 mod: ts.mod
3830 info: info
3831 is_pub: ts.is_pub
3832 )
3833 if final_concrete_types.len > 0 {
3834 t.unwrap_method_types(ts, generic_names, concrete_types)
3835 }
3836 if new_idx <= 0 {
3837 existing := t.type_idxs[nrt]
3838 if existing > 0 {
3839 return new_type(existing).derive(typ).clear_flag(.generic)
3840 }
3841 return typ
3842 }
3843 return new_type(new_idx).derive(typ).clear_flag(.generic)
3844 }
3845 SumType {
3846 mut variants := ts.info.variants.clone()
3847 gn_names := ts.info.generic_types.map(t.sym(it).name)
3848 for i in 0 .. variants.len {
3849 sym := t.sym(variants[i])
3850 if variants[i].has_flag(.generic) || sym.kind == .generic_inst
3851 || (sym.kind in [.struct, .sum_type, .interface] && sym.has_generic_type_info()) {
3852 if sym.kind in [.struct, .sum_type, .interface] {
3853 variants[i] = t.unwrap_generic_type_ex_with_depth(variants[i], gn_names,
3854 final_concrete_types, false, new_depth_guard)
3855 } else {
3856 if t_typ := t.convert_generic_type(variants[i], gn_names,
3857 final_concrete_types)
3858 {
3859 variants[i] = t_typ
3860 }
3861 }
3862 }
3863 }
3864 mut info := ts.info
3865 info.is_generic = false
3866 info.concrete_types = final_concrete_types
3867 info.parent_type = typ.set_flag(.generic)
3868 info.fields = fields
3869 info.variants = variants
3870 new_idx := t.register_sym(
3871 kind: .sum_type
3872 name: nrt
3873 cname: util.no_dots(c_nrt)
3874 parent_idx: typ.idx()
3875 mod: ts.mod
3876 info: info
3877 is_pub: ts.is_pub
3878 )
3879 if final_concrete_types.len > 0 {
3880 t.unwrap_method_types(ts, generic_names, concrete_types)
3881 }
3882 if new_idx <= 0 {
3883 existing := t.type_idxs[nrt]
3884 if existing > 0 {
3885 return new_type(existing).derive(typ).clear_flag(.generic)
3886 }
3887 return typ
3888 }
3889 return new_type(new_idx).derive(typ).clear_flag(.generic)
3890 }
3891 Interface {
3892 // resolve generic types inside methods
3893 mut imethods := ts.info.methods.clone()
3894 gn_names := t.get_real_generic_names(typ, generic_names)
3895 // Use final_concrete_types (the interface's own resolved concrete types)
3896 // instead of concrete_types (the outer struct's types) so that nested
3897 // generic type arguments like CacheStore[K, &CacheItem[K, V]] resolve
3898 // V to &CacheItem[string, int] rather than plain int.
3899 iface_concrete := if final_concrete_types.len == gn_names.len {
3900 final_concrete_types
3901 } else {
3902 concrete_types[..gn_names.len]
3903 }
3904 for mut method in imethods {
3905 if unwrap_typ := t.convert_generic_type(method.return_type, gn_names,
3906 iface_concrete)
3907 {
3908 method.return_type = unwrap_typ
3909 }
3910 for mut param in method.params {
3911 if unwrap_typ := t.convert_generic_param_type(param, gn_names, iface_concrete) {
3912 param.typ = unwrap_typ
3913 }
3914 }
3915 }
3916 mut all_methods := ts.methods.clone()
3917 for imethod in imethods {
3918 for mut method in all_methods {
3919 if imethod.name == method.name {
3920 method = imethod
3921 }
3922 }
3923 }
3924 mut info := ts.info
3925 info.is_generic = false
3926 info.concrete_types = final_concrete_types
3927 info.parent_type = typ.set_flag(.generic)
3928 info.fields = fields
3929 info.methods = imethods
3930 new_idx := t.register_sym(
3931 kind: .interface
3932 name: nrt
3933 cname: util.no_dots(c_nrt)
3934 parent_idx: typ.idx()
3935 mod: ts.mod
3936 info: info
3937 is_pub: ts.is_pub
3938 )
3939 if new_idx > 0 {
3940 mut ts_copy := t.sym(idx_to_type(new_idx))
3941 for method in all_methods {
3942 ts_copy.register_method(method)
3943 }
3944 }
3945 if final_concrete_types.len > 0 {
3946 t.unwrap_method_types(ts, generic_names, concrete_types)
3947 }
3948 if new_idx <= 0 {
3949 // register_sym can fail when convert_generic_type (used above to
3950 // resolve method parameter types) calls find_or_register_generic_inst,
3951 // which converts the placeholder we created earlier into a generic_inst.
3952 // In that case, look up the existing entry and use it — the
3953 // generic_insts_to_concrete pass will resolve it later.
3954 existing := t.type_idxs[nrt]
3955 if existing > 0 {
3956 return new_type(existing).derive(typ).clear_flag(.generic)
3957 }
3958 return typ
3959 }
3960 return new_type(new_idx).derive(typ).clear_flag(.generic)
3961 }
3962 else {
3963 if typ.has_flag(.generic) {
3964 if converted := t.convert_generic_type(typ, generic_names, concrete_types) {
3965 return converted
3966 }
3967 }
3968 }
3969 }
3970
3971 return typ
3972}
3973
3974fn concrete_type_lists_match(a []Type, b []Type) bool {
3975 if a.len != b.len {
3976 return false
3977 }
3978 for i, typ in a {
3979 if typ != b[i] {
3980 return false
3981 }
3982 }
3983 return true
3984}
3985
3986fn (t &Table) type_contains_transformed_parent_inst(typ Type, parent_idx int, concrete_types []Type) bool {
3987 if typ == 0 {
3988 return false
3989 }
3990 sym := t.sym(typ)
3991 match sym.info {
3992 Array {
3993 return t.type_contains_transformed_parent_inst(sym.info.elem_type, parent_idx,
3994 concrete_types)
3995 }
3996 ArrayFixed {
3997 return t.type_contains_transformed_parent_inst(sym.info.elem_type, parent_idx,
3998 concrete_types)
3999 }
4000 Chan {
4001 return t.type_contains_transformed_parent_inst(sym.info.elem_type, parent_idx,
4002 concrete_types)
4003 }
4004 Thread {
4005 return t.type_contains_transformed_parent_inst(sym.info.return_type, parent_idx,
4006 concrete_types)
4007 }
4008 Map {
4009 return
4010 t.type_contains_transformed_parent_inst(sym.info.key_type, parent_idx, concrete_types)
4011 || t.type_contains_transformed_parent_inst(sym.info.value_type, parent_idx, concrete_types)
4012 }
4013 FnType {
4014 if t.type_contains_transformed_parent_inst(sym.info.func.return_type, parent_idx,
4015 concrete_types)
4016 {
4017 return true
4018 }
4019 for param in sym.info.func.params {
4020 if t.type_contains_transformed_parent_inst(param.typ, parent_idx, concrete_types)
4021 || t.type_contains_transformed_parent_inst(param.orig_typ, parent_idx, concrete_types) {
4022 return true
4023 }
4024 }
4025 }
4026 GenericInst {
4027 if sym.info.parent_idx == parent_idx
4028 && !concrete_type_lists_match(sym.info.concrete_types, concrete_types) {
4029 return true
4030 }
4031 for ct in sym.info.concrete_types {
4032 if t.type_contains_transformed_parent_inst(ct, parent_idx, concrete_types) {
4033 return true
4034 }
4035 }
4036 }
4037 Struct {
4038 if sym.parent_idx == parent_idx
4039 && !concrete_type_lists_match(sym.info.concrete_types, concrete_types) {
4040 return true
4041 }
4042 for ct in sym.info.concrete_types {
4043 if t.type_contains_transformed_parent_inst(ct, parent_idx, concrete_types) {
4044 return true
4045 }
4046 }
4047 }
4048 Interface {
4049 if sym.parent_idx == parent_idx
4050 && !concrete_type_lists_match(sym.info.concrete_types, concrete_types) {
4051 return true
4052 }
4053 for ct in sym.info.concrete_types {
4054 if t.type_contains_transformed_parent_inst(ct, parent_idx, concrete_types) {
4055 return true
4056 }
4057 }
4058 }
4059 SumType {
4060 if sym.parent_idx == parent_idx
4061 && !concrete_type_lists_match(sym.info.concrete_types, concrete_types) {
4062 return true
4063 }
4064 for ct in sym.info.concrete_types {
4065 if t.type_contains_transformed_parent_inst(ct, parent_idx, concrete_types) {
4066 return true
4067 }
4068 }
4069 }
4070 MultiReturn {
4071 for mr_typ in sym.info.types {
4072 if t.type_contains_transformed_parent_inst(mr_typ, parent_idx, concrete_types) {
4073 return true
4074 }
4075 }
4076 }
4077 else {}
4078 }
4079
4080 return false
4081}
4082
4083fn (mut t Table) should_auto_register_concrete_method(method Fn, parent_type Type, concrete_types []Type) bool {
4084 parent_idx := parent_type.clear_flag(.generic).idx()
4085 if parent_idx == 0 || method.generic_names.len != concrete_types.len {
4086 return false
4087 }
4088 for i in 1 .. method.params.len {
4089 param := method.params[i]
4090 mut param_typ := param.typ
4091 if param.typ.has_flag(.generic) || t.generic_type_names(param.typ).len > 0 {
4092 if pt := t.convert_generic_param_type(param, method.generic_names, concrete_types) {
4093 param_typ = pt
4094 } else {
4095 param_typ = t.unwrap_generic_type_ex(param.typ, method.generic_names,
4096 concrete_types, true)
4097 }
4098 }
4099 if t.type_contains_transformed_parent_inst(param_typ, parent_idx, concrete_types) {
4100 return false
4101 }
4102 }
4103 mut return_type := method.return_type
4104 if method.return_type.has_flag(.generic) || t.generic_type_names(method.return_type).len > 0 {
4105 if rt := t.convert_generic_type(method.return_type, method.generic_names, concrete_types) {
4106 return_type = rt
4107 } else {
4108 return_type = t.unwrap_generic_type_ex(method.return_type, method.generic_names,
4109 concrete_types, true)
4110 }
4111 }
4112 return !t.type_contains_transformed_parent_inst(return_type, parent_idx, concrete_types)
4113}
4114
4115fn (mut t Table) unwrap_method_types(ts &TypeSymbol, generic_names []string, concrete_types []Type) {
4116 mut needs_unwrap_types := []Type{}
4117 for method in ts.get_methods() {
4118 for i in 1 .. method.params.len {
4119 if method.params[i].typ.has_flag(.generic)
4120 && method.params[i].typ != method.params[0].typ {
4121 if method.params[i].typ !in needs_unwrap_types {
4122 needs_unwrap_types << method.params[i].typ
4123 }
4124 }
4125 }
4126 // Check return type outside the parameter loop so methods with no
4127 // non-receiver params (e.g. `magnitude()`) are also covered.
4128 if method.return_type.has_flag(.generic) && method.return_type != method.params[0].typ {
4129 if method.return_type !in needs_unwrap_types {
4130 needs_unwrap_types << method.return_type
4131 }
4132 }
4133 }
4134 for typ_ in needs_unwrap_types {
4135 t.unwrap_generic_type(typ_, generic_names, concrete_types)
4136 }
4137}
4138
4139fn (mut t Table) specialize_generic_fn_method_type(typ Type, parent_type Type, concrete_type Type, generic_names []string, concrete_types []Type) Type {
4140 if typ.clear_flag(.generic).idx() == parent_type.clear_flag(.generic).idx() {
4141 return concrete_type.derive(typ).clear_flag(.generic)
4142 }
4143 sym := t.sym(typ)
4144 match sym.info {
4145 Array {
4146 dims, elem_type := t.get_array_dims(sym.info)
4147 elem_typ := t.specialize_generic_fn_method_type(elem_type, parent_type, concrete_type,
4148 generic_names, concrete_types)
4149 if elem_typ != elem_type {
4150 idx := t.find_or_register_array_with_dims(elem_typ, dims)
4151 if elem_typ.has_flag(.generic) {
4152 return new_type(idx).derive_add_muls(typ).set_flag(.generic)
4153 }
4154 return new_type(idx).derive_add_muls(typ).clear_flag(.generic)
4155 }
4156 }
4157 ArrayFixed {
4158 elem_typ := t.specialize_generic_fn_method_type(sym.info.elem_type, parent_type,
4159 concrete_type, generic_names, concrete_types)
4160 if elem_typ != sym.info.elem_type {
4161 idx := t.find_or_register_array_fixed(elem_typ, sym.info.size, None{}, false)
4162 if elem_typ.has_flag(.generic) {
4163 return new_type(idx).derive_add_muls(typ).set_flag(.generic)
4164 }
4165 return new_type(idx).derive_add_muls(typ).clear_flag(.generic)
4166 }
4167 }
4168 Chan {
4169 elem_typ := t.specialize_generic_fn_method_type(sym.info.elem_type, parent_type,
4170 concrete_type, generic_names, concrete_types)
4171 if elem_typ != sym.info.elem_type {
4172 idx := t.find_or_register_chan(elem_typ, elem_typ.nr_muls() > 0)
4173 if elem_typ.has_flag(.generic) {
4174 return new_type(idx).derive_add_muls(typ).set_flag(.generic)
4175 }
4176 return new_type(idx).derive_add_muls(typ).clear_flag(.generic)
4177 }
4178 }
4179 Thread {
4180 ret_typ := t.specialize_generic_fn_method_type(sym.info.return_type, parent_type,
4181 concrete_type, generic_names, concrete_types)
4182 if ret_typ != sym.info.return_type {
4183 idx := t.find_or_register_thread(ret_typ)
4184 if ret_typ.has_flag(.generic) {
4185 return new_type(idx).derive_add_muls(typ).set_flag(.generic)
4186 }
4187 return new_type(idx).derive_add_muls(typ).clear_flag(.generic)
4188 }
4189 }
4190 MultiReturn {
4191 mut resolved_types := []Type{cap: sym.info.types.len}
4192 mut type_changed := false
4193 for ret_typ in sym.info.types {
4194 resolved_typ := t.specialize_generic_fn_method_type(ret_typ, parent_type,
4195 concrete_type, generic_names, concrete_types)
4196 if resolved_typ != ret_typ {
4197 type_changed = true
4198 }
4199 resolved_types << resolved_typ
4200 }
4201 if type_changed {
4202 idx := t.find_or_register_multi_return(resolved_types)
4203 if resolved_types.any(it.has_flag(.generic)) {
4204 return new_type(idx).derive_add_muls(typ).set_flag(.generic)
4205 }
4206 return new_type(idx).derive_add_muls(typ).clear_flag(.generic)
4207 }
4208 }
4209 Map {
4210 key_typ := t.specialize_generic_fn_method_type(sym.info.key_type, parent_type,
4211 concrete_type, generic_names, concrete_types)
4212 value_typ := t.specialize_generic_fn_method_type(sym.info.value_type, parent_type,
4213 concrete_type, generic_names, concrete_types)
4214 if key_typ != sym.info.key_type || value_typ != sym.info.value_type {
4215 idx := t.find_or_register_map(key_typ, value_typ)
4216 if key_typ.has_flag(.generic) || value_typ.has_flag(.generic) {
4217 return new_type(idx).derive_add_muls(typ).set_flag(.generic)
4218 }
4219 return new_type(idx).derive_add_muls(typ).clear_flag(.generic)
4220 }
4221 }
4222 else {}
4223 }
4224
4225 if typ.has_flag(.generic) {
4226 if resolved_typ := t.convert_generic_type(typ, generic_names, concrete_types) {
4227 return resolved_typ
4228 }
4229 }
4230 return typ
4231}
4232
4233fn (mut t Table) specialize_generic_fn_type_methods(parent_type Type, mut concrete_sym TypeSymbol, generic_names []string, concrete_types []Type) {
4234 parent_sym := t.sym(parent_type)
4235 if parent_sym.info !is FnType || parent_sym.methods.len == 0 {
4236 return
4237 }
4238 concrete_type := idx_to_type(concrete_sym.idx)
4239 concrete_sym.methods = []Fn{}
4240 for method in parent_sym.methods {
4241 mut concrete_method := method.new_method_with_receiver_type(concrete_type)
4242 concrete_method.generic_names = method.generic_names.clone()
4243 concrete_method.return_type = t.specialize_generic_fn_method_type(method.return_type,
4244 parent_type, concrete_type, generic_names, concrete_types)
4245 for i in 1 .. concrete_method.params.len {
4246 concrete_method.params[i].typ = t.specialize_generic_fn_method_type(method.params[i].typ,
4247 parent_type, concrete_type, generic_names, concrete_types)
4248 }
4249 concrete_method.receiver_type = concrete_method.params[0].typ
4250 concrete_sym.register_method(concrete_method)
4251 }
4252}
4253
4254// generic struct instantiations to concrete types
4255pub fn (mut t Table) generic_insts_to_concrete() {
4256 for mut sym in t.type_symbols {
4257 if sym.kind == .generic_inst {
4258 info := sym.info as GenericInst
4259 if info.parent_idx <= 0 || info.parent_idx >= t.type_symbols.len {
4260 continue
4261 }
4262 parent := t.type_symbols[info.parent_idx]
4263 if info.concrete_types.any(it.has_flag(.generic))
4264 && (parent.info is Struct || parent.info is Interface || parent.info is SumType) {
4265 continue
4266 }
4267 if parent.kind == .placeholder {
4268 sym.kind = .placeholder
4269 continue
4270 }
4271 match parent.info {
4272 Struct {
4273 mut parent_info := parent.info as Struct
4274 if !parent_info.is_generic {
4275 util.verror('generic error',
4276 'struct `${parent.name}` is not a generic struct, cannot instantiate to the concrete types')
4277 continue
4278 }
4279 mut fields := parent_info.fields.clone()
4280 if parent_info.generic_types.len == info.concrete_types.len {
4281 generic_names := t.get_generic_names(parent_info.generic_types)
4282 for i in 0 .. fields.len {
4283 if fields[i].typ.has_flag(.generic) {
4284 orig_type := fields[i].typ
4285 if fields[i].typ.idx() != info.parent_idx {
4286 fields[i].typ = t.unwrap_generic_type(fields[i].typ,
4287 generic_names, info.concrete_types)
4288 }
4289
4290 if t_typ := t.convert_generic_type(fields[i].typ, generic_names,
4291 info.concrete_types)
4292 {
4293 fields[i].typ = t_typ
4294 }
4295 // Update type in `info.embeds`, if it's embed
4296 if fields[i].is_embed {
4297 for mut embed in parent_info.embeds {
4298 if embed == orig_type {
4299 embed = fields[i].typ
4300 break
4301 }
4302 }
4303 }
4304 }
4305 if fields[i].has_default_expr {
4306 if fields[i].default_expr_typ != 0
4307 && fields[i].default_expr_typ != nil_type {
4308 fields[i].default_expr_typ = t.convert_generic_expr_type(fields[i].default_expr_typ,
4309 generic_names, info.concrete_types)
4310 }
4311 fields[i].default_expr = t.convert_generic_default_expr(fields[i].default_expr,
4312 generic_names, info.concrete_types)
4313 }
4314 }
4315 parent_info.is_generic = false
4316 parent_info.concrete_types = info.concrete_types.clone()
4317 parent_info.fields = fields
4318 parent_info.parent_type = new_type(info.parent_idx).set_flag(.generic)
4319 sym.info = Struct{
4320 ...parent_info
4321 is_generic: false
4322 concrete_types: info.concrete_types.clone()
4323 scoped_name: sym.name
4324 }
4325 sym.is_pub = true
4326 sym.kind = parent.kind
4327
4328 parent_sym := t.sym(parent_info.parent_type)
4329 for method in parent_sym.methods {
4330 if method.generic_names.len == info.concrete_types.len
4331 && t.should_auto_register_concrete_method(method, parent_info.parent_type, info.concrete_types) {
4332 t.register_fn_concrete_types(method.fkey(), info.concrete_types)
4333 }
4334 }
4335 } else {
4336 util.verror('generic error',
4337 'the number of generic types of struct `${parent.name}` is inconsistent with the concrete types')
4338 }
4339 }
4340 Interface {
4341 mut parent_info := parent.info as Interface
4342 if !parent_info.is_generic {
4343 util.verror('generic error',
4344 'interface `${parent.name}` is not a generic interface, cannot instantiate to the concrete types')
4345 continue
4346 }
4347 if parent_info.generic_types.len == info.concrete_types.len {
4348 mut fields := parent_info.fields.clone()
4349 generic_names := t.get_generic_names(parent_info.generic_types)
4350 for i in 0 .. fields.len {
4351 if t_typ := t.convert_generic_type(fields[i].typ, generic_names,
4352 info.concrete_types)
4353 {
4354 fields[i].typ = t_typ
4355 }
4356 }
4357 mut imethods := parent_info.methods.clone()
4358 for mut method in imethods {
4359 method.generic_names.clear()
4360 if pt := t.convert_generic_type(method.return_type, generic_names,
4361 info.concrete_types)
4362 {
4363 method.return_type = pt
4364 }
4365 method.params = method.params.clone()
4366 for mut param in method.params {
4367 if pt := t.convert_generic_param_type(param, generic_names,
4368 info.concrete_types)
4369 {
4370 param.typ = pt
4371 }
4372 }
4373 sym.register_method(method)
4374 }
4375 mut all_methods := parent.methods.clone()
4376 for imethod in imethods {
4377 for mut method in all_methods {
4378 if imethod.name == method.name {
4379 method = imethod
4380 }
4381 }
4382 }
4383 sym.info = Interface{
4384 ...parent_info
4385 is_generic: false
4386 concrete_types: info.concrete_types.clone()
4387 fields: fields
4388 methods: imethods
4389 parent_type: new_type(info.parent_idx).set_flag(.generic)
4390 }
4391 sym.is_pub = true
4392 sym.kind = parent.kind
4393 sym.methods = all_methods
4394 } else {
4395 util.verror('generic error',
4396 'the number of generic types of interface `${parent.name}` is inconsistent with the concrete types')
4397 }
4398 }
4399 SumType {
4400 mut parent_info := parent.info as SumType
4401 if !parent_info.is_generic {
4402 util.verror('generic error',
4403 'sumtype `${parent.name}` is not a generic sumtype, cannot instantiate to the concrete types')
4404 continue
4405 }
4406 if parent_info.generic_types.len == info.concrete_types.len {
4407 mut fields := parent_info.fields.clone()
4408 mut variants := parent_info.variants.clone()
4409 generic_names := t.get_generic_names(parent_info.generic_types)
4410 for i in 0 .. fields.len {
4411 if t_typ := t.convert_generic_type(fields[i].typ, generic_names,
4412 info.concrete_types)
4413 {
4414 fields[i].typ = t_typ
4415 }
4416 }
4417 for i in 0 .. variants.len {
4418 t_sym := t.sym(variants[i])
4419 if variants[i].has_flag(.generic)
4420 || t_sym.kind == .generic_inst
4421 || (t_sym.kind in [.struct, .sum_type, .interface]
4422 && t_sym.has_generic_type_info()) {
4423 if t_sym.kind == .struct && variants[i].idx() != info.parent_idx {
4424 variants[i] = t.unwrap_generic_type(variants[i], generic_names,
4425 info.concrete_types)
4426 } else {
4427 if t_typ := t.convert_generic_type(variants[i], generic_names,
4428 info.concrete_types)
4429 {
4430 variants[i] = t_typ
4431 }
4432 }
4433 }
4434 }
4435 sym.info = SumType{
4436 ...parent_info
4437 is_generic: false
4438 concrete_types: info.concrete_types.clone()
4439 fields: fields
4440 variants: variants
4441 parent_type: new_type(info.parent_idx).set_flag(.generic)
4442 }
4443 sym.is_pub = true
4444 sym.kind = parent.kind
4445 } else {
4446 util.verror('generic error',
4447 'the number of generic types of sumtype `${parent.name}` is inconsistent with the concrete types')
4448 }
4449 }
4450 FnType {
4451 mut parent_info := parent.info as FnType
4452 mut function := parent_info.func
4453 function.params = function.params.clone()
4454 for mut param in function.params {
4455 if param.typ.has_flag(.generic) || t.generic_type_names(param.typ).len > 0 {
4456 if t_typ := t.convert_generic_param_type(param, function.generic_names,
4457 info.concrete_types)
4458 {
4459 param.typ = t_typ
4460 } else {
4461 param.typ = t.unwrap_generic_type_ex(param.typ,
4462 function.generic_names, info.concrete_types, true)
4463 }
4464 }
4465 if param.orig_typ.has_flag(.generic)
4466 || t.generic_type_names(param.orig_typ).len > 0 {
4467 if t_typ := t.convert_generic_type(param.orig_typ,
4468 function.generic_names, info.concrete_types)
4469 {
4470 param.orig_typ = t_typ
4471 } else {
4472 param.orig_typ = t.unwrap_generic_type_ex(param.orig_typ,
4473 function.generic_names, info.concrete_types, true)
4474 }
4475 }
4476 }
4477 return_type_sym := t.sym(function.return_type)
4478 if function.return_type.has_flag(.generic)
4479 || t.generic_type_names(function.return_type).len > 0
4480 || (return_type_sym.kind == .generic_inst&& (return_type_sym.info as GenericInst).concrete_types.any(it.has_flag(.generic))) {
4481 if t_typ := t.convert_generic_type(function.return_type,
4482 function.generic_names, info.concrete_types)
4483 {
4484 function.return_type = t_typ
4485 } else {
4486 function.return_type = t.unwrap_generic_type_ex(function.return_type,
4487 function.generic_names, info.concrete_types, true)
4488 }
4489 }
4490 function.generic_names = []
4491 sym.info = FnType{
4492 ...parent_info
4493 func: function
4494 }
4495 sym.parent_idx = info.parent_idx
4496 sym.is_pub = true
4497 sym.kind = parent.kind
4498 sym.generic_types = info.concrete_types.clone()
4499 for method in parent.methods {
4500 if method.generic_names.len == info.concrete_types.len
4501 && t.should_auto_register_concrete_method(method, new_type(info.parent_idx).set_flag(.generic), info.concrete_types) {
4502 t.register_fn_concrete_types(method.fkey(), info.concrete_types)
4503 }
4504 }
4505 t.specialize_generic_fn_type_methods(new_type(info.parent_idx).set_flag(.generic), mut
4506 sym, parent_info.func.generic_names, info.concrete_types)
4507 }
4508 else {}
4509 }
4510
4511 if sym.kind != .generic_inst && sym.language == .v && sym.name.contains('[') {
4512 sym.cname = sym.name.replace('.', '__').replace_each([
4513 '[',
4514 '_T_',
4515 ']',
4516 '',
4517 ', ',
4518 '_T_',
4519 ',',
4520 '_T_',
4521 ' ',
4522 '',
4523 '&',
4524 '__ptr__',
4525 '(',
4526 '_',
4527 ')',
4528 '_',
4529 ])
4530 }
4531 }
4532 }
4533 // Second pass: register method concrete types for Struct types that were
4534 // already converted from GenericInst (e.g. by unwrap_generic_type_ex)
4535 // but whose methods haven't been registered yet.
4536 for sym in t.type_symbols {
4537 if sym.kind != .struct {
4538 continue
4539 }
4540 if sym.info is Struct {
4541 if sym.info.concrete_types.len > 0 && sym.info.parent_type.has_flag(.generic)
4542 && !sym.info.concrete_types.any(it.has_flag(.generic))
4543 && !sym.info.concrete_types.any(t.generic_type_names(it).len > 0) {
4544 parent_sym := t.sym(sym.info.parent_type)
4545 for method in parent_sym.methods {
4546 if method.generic_names.len == sym.info.concrete_types.len
4547 && t.should_auto_register_concrete_method(method, sym.info.parent_type, sym.info.concrete_types) {
4548 t.register_fn_concrete_types(method.fkey(), sym.info.concrete_types)
4549 }
4550 }
4551 }
4552 }
4553 }
4554}
4555
4556// Extracts all generic names from Type<A>[B] => B when <A>[B] is present
4557// otherwise generic_names is returned
4558pub fn (t &Table) get_real_generic_names(typ Type, generic_names []string) []string {
4559 if typ.has_flag(.generic) {
4560 typ_name := t.type_to_str(typ)
4561 if typ_name.contains('>[') {
4562 return typ_name.split('>[')[1].all_before_last(']').split(',')
4563 }
4564 }
4565 return generic_names
4566}
4567
4568// Extracts all type names from given types, notice that MultiReturn will be decompose
4569// and will not included in returned string
4570pub fn (t &Table) get_generic_names(generic_types []Type) []string {
4571 mut generic_names := []string{cap: generic_types.len}
4572 for typ in generic_types {
4573 if !typ.has_flag(.generic) {
4574 continue
4575 }
4576
4577 sym := t.sym(typ)
4578 info := sym.info
4579
4580 match info {
4581 MultiReturn {
4582 generic_names << t.get_generic_names(info.types)
4583 }
4584 else {
4585 generic_names << sym.name
4586 }
4587 }
4588 }
4589 return generic_names
4590}
4591
4592// check_if_elements_need_unwrap checks if the elements of a container (arrays, maps) need to be unwrapped to a concrete type
4593pub fn (mut t Table) check_if_elements_need_unwrap(root_typ Type, typ Type) bool {
4594 sym := t.sym(typ)
4595 if sym.kind !in [.array, .array_fixed, .map] {
4596 return false
4597 }
4598
4599 mut typs := []Type{}
4600 match sym.info {
4601 Array {
4602 typs << (sym.info as Array).elem_type
4603 }
4604 ArrayFixed {
4605 typs << (sym.info as ArrayFixed).elem_type
4606 }
4607 Map {
4608 typs << (sym.info as Map).key_type
4609 typs << (sym.info as Map).value_type
4610 }
4611 else {}
4612 }
4613
4614 for typ_ in typs {
4615 if typ_.has_flag(.generic) {
4616 t_sym := t.sym(typ_)
4617 match t_sym.info {
4618 Struct, Interface, SumType {
4619 if t_sym.info.is_generic && t_sym.info.generic_types.len > 0
4620 && t_sym.info.concrete_types.len == 0 && typ_.idx() != root_typ.idx() {
4621 return true
4622 }
4623 }
4624 else {}
4625 }
4626 }
4627 if t.check_if_elements_need_unwrap(root_typ, typ_) {
4628 return true
4629 }
4630 }
4631 return false
4632}
4633
4634pub fn (t &Table) dependent_names_in_expr(expr Expr) []string {
4635 mut names := []string{}
4636 match expr {
4637 ArrayInit {
4638 for elem_expr in expr.exprs {
4639 names << t.dependent_names_in_expr(elem_expr)
4640 }
4641 if expr.has_len {
4642 names << t.dependent_names_in_expr(expr.len_expr)
4643 }
4644 if expr.has_cap {
4645 names << t.dependent_names_in_expr(expr.cap_expr)
4646 }
4647 if expr.has_init {
4648 names << t.dependent_names_in_expr(expr.init_expr)
4649 }
4650 }
4651 CallExpr {
4652 if expr.is_method {
4653 names << t.dependent_names_in_expr(expr.left)
4654 }
4655 for arg in expr.args {
4656 names << t.dependent_names_in_expr(arg.expr)
4657 }
4658 if func := t.find_fn(expr.name) {
4659 names << func.dep_names
4660 }
4661 }
4662 CastExpr {
4663 names << t.dependent_names_in_expr(expr.expr)
4664 names << t.dependent_names_in_expr(expr.arg)
4665 }
4666 Ident {
4667 if expr.kind in [.global, .constant] {
4668 names << util.no_dots(expr.name)
4669 }
4670 }
4671 IndexExpr {
4672 names << t.dependent_names_in_expr(expr.left)
4673 }
4674 IfExpr {
4675 for branch in expr.branches {
4676 names << t.dependent_names_in_expr(branch.cond)
4677 for stmt in branch.stmts {
4678 names << t.dependent_names_in_stmt(stmt)
4679 }
4680 }
4681 }
4682 InfixExpr {
4683 names << t.dependent_names_in_expr(expr.left)
4684 names << t.dependent_names_in_expr(expr.right)
4685 }
4686 MapInit {
4687 for key in expr.keys {
4688 names << t.dependent_names_in_expr(key)
4689 }
4690 for val in expr.vals {
4691 names << t.dependent_names_in_expr(val)
4692 }
4693 }
4694 MatchExpr {
4695 names << t.dependent_names_in_expr(expr.cond)
4696 for branch in expr.branches {
4697 for stmt in branch.stmts {
4698 names << t.dependent_names_in_stmt(stmt)
4699 }
4700 }
4701 }
4702 ParExpr {
4703 names << t.dependent_names_in_expr(expr.expr)
4704 }
4705 PostfixExpr {
4706 names << t.dependent_names_in_expr(expr.expr)
4707 }
4708 PrefixExpr {
4709 names << t.dependent_names_in_expr(expr.right)
4710 }
4711 StringInterLiteral {
4712 for inter_expr in expr.exprs {
4713 names << t.dependent_names_in_expr(inter_expr)
4714 }
4715 }
4716 SelectorExpr {
4717 names << t.dependent_names_in_expr(expr.expr)
4718 }
4719 StructInit {
4720 if expr.has_update_expr {
4721 names << t.dependent_names_in_expr(expr.update_expr)
4722 }
4723 for field in expr.init_fields {
4724 names << t.dependent_names_in_expr(field.expr)
4725 }
4726 }
4727 else {}
4728 }
4729
4730 return names
4731}
4732
4733pub fn (t &Table) dependent_names_in_stmt(stmt Stmt) []string {
4734 mut names := []string{}
4735 match stmt {
4736 AssignStmt {
4737 for expr in stmt.left {
4738 names << t.dependent_names_in_expr(expr)
4739 }
4740 for expr in stmt.right {
4741 names << t.dependent_names_in_expr(expr)
4742 }
4743 }
4744 ExprStmt {
4745 names << t.dependent_names_in_expr(stmt.expr)
4746 }
4747 ForInStmt {
4748 names << t.dependent_names_in_expr(stmt.cond)
4749 for stmt_ in stmt.stmts {
4750 names << t.dependent_names_in_stmt(stmt_)
4751 }
4752 }
4753 ForStmt {
4754 for stmt_ in stmt.stmts {
4755 names << t.dependent_names_in_stmt(stmt_)
4756 }
4757 }
4758 ForCStmt {
4759 names << t.dependent_names_in_stmt(stmt.init)
4760 names << t.dependent_names_in_expr(stmt.cond)
4761 names << t.dependent_names_in_stmt(stmt.inc)
4762 for stmt_ in stmt.stmts {
4763 names << t.dependent_names_in_stmt(stmt_)
4764 }
4765 }
4766 Return {
4767 for expr in stmt.exprs {
4768 names << t.dependent_names_in_expr(expr)
4769 }
4770 }
4771 else {}
4772 }
4773
4774 return names
4775}
4776
4777pub fn (t &Table) get_array_dims(arr Array) (int, Type) {
4778 mut dims := 1
4779 mut elem_type := arr.elem_type
4780 mut elem_sym := t.sym(elem_type)
4781 for mut elem_sym.info is Array {
4782 dims++
4783 elem_type = elem_sym.info.elem_type
4784 elem_sym = t.sym(elem_type)
4785 }
4786 return dims, elem_type
4787}
4788
4789pub fn (t &Table) get_trace_fn_name(cur_fn FnDecl, node CallExpr) (string, string) {
4790 generic_name := node.concrete_types.map(t.type_to_str(it)).join('_')
4791 hash_fn := '_v__trace__${cur_fn.name}_${node.name}_${generic_name}_${node.pos.line_nr}'
4792 fn_name := if node.concrete_types.len > 0 { '${node.name}_T_${generic_name}' } else { node.name }
4793 return hash_fn, fn_name
4794}
4795
4796// get_attrs retrieve the attribrutes from the type symbol
4797pub fn (t &Table) get_attrs(sym TypeSymbol) []Attr {
4798 match sym.info {
4799 Enum {
4800 return t.enum_decls[sym.name].attrs
4801 }
4802 Struct {
4803 return sym.info.attrs
4804 }
4805 FnType {
4806 return sym.info.func.attrs
4807 }
4808 Interface {
4809 return unsafe { t.interfaces[sym.idx].attrs }
4810 }
4811 SumType {
4812 return unsafe { t.sumtypes[sym.idx].attrs }
4813 }
4814 else {
4815 return []
4816 }
4817 }
4818}
4819
4820pub fn (mut t Table) get_veb_result_type_idx() int {
4821 if t.veb_res_idx_cache > 0 {
4822 return t.veb_res_idx_cache
4823 }
4824
4825 t.veb_res_idx_cache = t.find_type('veb.Result')
4826 return t.veb_res_idx_cache
4827}
4828
4829@[inline]
4830pub fn (mut t Table) register_vls_info(key string, val VlsInfo) {
4831 t.vls_info[key] = val
4832}
4833
4834pub fn (t &Table) unwrap(typ Type) Type {
4835 ts := t.sym(typ)
4836 return if ts.info is Alias { t.unwrap(ts.info.parent_type) } else { typ }
4837}
4838