v / vlib / v / ast / table.v
5105 lines · 4897 sloc · 151.58 KB
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 structured_receiver_methods map[string][]Fn
80 interfaces map[int]InterfaceDecl
81 sumtypes map[int]SumTypeDecl
82 cmod_prefix string // needed for ast.type_to_str(Type) while vfmt; contains `os.`
83 is_fmt bool
84 used_features &UsedFeatures = &UsedFeatures{} // filled in by the builder via markused module, when pref.skip_unused = true;
85 veb_res_idx_cache int // Cache of `veb.Result` type
86 veb_ctx_idx_cache int // Cache of `veb.Context` type
87 panic_handler FnPanicHandler = default_table_panic_handler
88 panic_userdata voidptr = unsafe { nil } // can be used to pass arbitrary data to panic_handler;
89 panic_npanics int
90 cur_fn &FnDecl = unsafe { nil } // previously stored in Checker.cur_fn and Gen.cur_fn
91 cur_lambda &LambdaExpr = unsafe { nil } // current lambda node
92 cur_concrete_types []Type // current concrete types, e.g. [int, string]
93 gostmts int // how many `go` statements there were in the parsed files.
94 // When table.gostmts > 0, __VTHREADS__ is defined, which can be checked with `$if threads {`
95 enum_decls map[string]EnumDecl
96 vls_info map[string]VlsInfo
97 module_deprecated map[string]bool
98 module_attrs map[string][]Attr // module attributes
99 builtin_pub_fns map[string]bool
100 pointer_size int
101 // cache for type_to_str_using_aliases
102 cached_type_to_str shared map[u64]string
103 // counters and maps for anon structs and unions, to avoid name conflicts.
104 anon_struct_names map[string]int // anon struct name -> struct sym idx
105 anon_struct_counter int
106 anon_union_names map[string]int // anon union name -> union sym idx
107 anon_union_counter int
108 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)'}`
109 new_int bool // use 64bit/32bit platform dependent `int`
110 new_int_fmt_fix bool // vfmt will fix `int` to `i32`
111 export_names map[string]string // @[export] names
112 filelist []string // all files list
113}
114
115pub struct ComptTimeCondResult {
116pub mut:
117 val bool
118 c_str string
119}
120
121pub struct VlsInfo {
122pub mut:
123 pos token.Pos
124 doc string // documentation
125}
126
127// used by vls to avoid leaks
128// TODO: remove manual memory management
129@[unsafe]
130pub fn (mut t Table) free() {
131 unsafe {
132 for s in t.type_symbols {
133 s.free()
134 }
135 t.type_symbols.free()
136 t.type_idxs.free()
137 t.fns.free()
138 t.dumps.free()
139 t.imports.free()
140 t.modules.free()
141 t.cflags.free()
142 t.redefined_fns.free()
143 t.fn_generic_types.free()
144 t.cmod_prefix.free()
145 t.used_features.free()
146 }
147}
148
149pub const fn_type_escape_seq = ['...', 'variadic_', '&', 'ref_', '[', '_T_', ']', '', ', ', '_',
150 ',', '_', '(', '_', ')', '', ' ', '_', '?', 'option_', '!', 'result_', '|', '_or_', '<', '_',
151 '>', '']
152pub const map_cname_escape_seq = ['[', '_T_', ', ', '_', ']', '']
153
154pub type FnPanicHandler = fn (&Table, string)
155
156fn default_table_panic_handler(_t &Table, message string) {
157 panic(message)
158}
159
160pub fn (t &Table) panic(message string) {
161 mut mt := unsafe { &Table(t) }
162 mt.panic_npanics++
163 t.panic_handler(t, message)
164}
165
166pub fn new_table() &Table {
167 mut t := &Table{
168 global_scope: &Scope{
169 parent: unsafe { nil }
170 }
171 cur_fn: unsafe { nil }
172 }
173 t.register_builtin_type_symbols()
174 t.is_fmt = true
175 global_table = t
176 return t
177}
178
179__global global_table = &Table(unsafe { nil })
180
181// used to compare fn's & for naming anon fn's
182pub fn (t &Table) fn_type_signature(f &Fn) string {
183 mut sig := ''
184 for i, arg in f.params {
185 sig += t.fn_type_signature_part(f, i, arg)
186 if i < f.params.len - 1 {
187 sig += '_'
188 }
189 }
190 if f.is_c_variadic {
191 if sig.len > 0 {
192 sig += '_'
193 }
194 sig += 'c_variadic'
195 }
196 if f.return_type != 0 && f.return_type != void_type {
197 sig += '__${util.no_dots(t.type_to_str(f.return_type)).replace_each(fn_type_escape_seq)}'
198 }
199 return sig
200}
201
202fn (t &Table) fn_type_signature_part(f &Fn, i int, arg Param) string {
203 mut typ := arg.typ
204 mut sig := ''
205 if arg.is_mut {
206 if typ.is_ptr() {
207 typ = typ.deref()
208 }
209 sig += 'mut '
210 }
211 if i == f.params.len - 1 && f.is_variadic && !f.is_c_variadic {
212 sig += '...'
213 }
214 sig += t.type_to_str(typ)
215 return util.no_dots(sig).replace_each(fn_type_escape_seq)
216}
217
218// fn_type_source_signature generates the signature of a function which looks like in the V source
219pub fn (t &Table) fn_type_source_signature(f &Fn) string {
220 import_aliases := map[string]string{}
221 mut sig := '('
222 for i, arg in f.params {
223 mut typ := arg.typ
224 if arg.is_mut {
225 if typ.is_ptr() {
226 typ = typ.deref()
227 }
228 sig += 'mut '
229 }
230 // Note: arg name is only added for fmt, else it would causes errors with generics
231 if t.is_fmt && arg.name != '' {
232 sig += '${arg.name} '
233 }
234 if i == f.params.len - 1 && f.is_variadic && !f.is_c_variadic {
235 sig += '...'
236 }
237 sig += t.type_to_str_using_aliases(typ, import_aliases)
238 if i < f.params.len - 1 {
239 sig += ', '
240 }
241 }
242 if f.is_c_variadic {
243 if f.params.len > 0 {
244 sig += ', '
245 }
246 sig += '...'
247 }
248 sig += ')'
249 if f.return_type == ovoid_type {
250 sig += ' ?'
251 } else if f.return_type == rvoid_type {
252 sig += ' !'
253 } else if f.return_type != void_type && f.return_type != 0 {
254 sig += ' ${t.type_to_str_using_aliases(f.return_type, import_aliases)}'
255 }
256 return sig
257}
258
259pub fn (t &Table) is_same_method(f &Fn, func &Fn) string {
260 if f.return_type != func.return_type {
261 s := t.type_to_str(f.return_type)
262 return 'expected return type `${s}`'
263 }
264 if f.params.len != func.params.len {
265 return 'expected ${f.params.len} parameter(s), not ${func.params.len}'
266 }
267
268 // interface name() other mut name() : error
269
270 for i in 0 .. f.params.len {
271 // don't check receiver for `.typ`
272 has_unexpected_type := i > 0
273 && t.unaliased_type(f.params[i].typ) != t.unaliased_type(func.params[i].typ)
274 // temporary hack for JS ifaces
275 lsym := t.sym(f.params[i].typ)
276 rsym := t.sym(func.params[i].typ)
277 if lsym.language == .js && rsym.language == .js {
278 return ''
279 }
280 has_unexpected_sharetype := f.params[i].is_shared != func.params[i].is_shared
281 || f.params[i].is_atomic != func.params[i].is_atomic
282 has_unexpected_mutability := !f.params[i].is_mut && func.params[i].is_mut
283
284 if has_unexpected_type || has_unexpected_sharetype || has_unexpected_mutability {
285 exps := t.type_to_str(f.params[i].typ)
286 gots := t.type_to_str(func.params[i].typ)
287 if has_unexpected_type {
288 return 'expected `${exps}`, not `${gots}` for parameter ${i}'
289 } else if has_unexpected_sharetype {
290 return 'expected `${t.param_type_with_specifier(f.params[i], i == 0)}`, not `${t.param_type_with_specifier(func.params[i],
291 i == 0)}` for parameter ${i}'
292 } else {
293 return 'expected `${exps}` which is immutable, not `mut ${gots}`'
294 }
295 }
296 }
297 return ''
298}
299
300fn (t &Table) param_type_with_specifier(p Param, is_receiver bool) string {
301 mut parts := []string{}
302 if p.is_mut {
303 parts << 'mut'
304 }
305 if p.is_shared {
306 parts << 'shared'
307 }
308 if p.is_atomic {
309 parts << 'atomic'
310 }
311 mut ptyp := p.typ.clear_flags(.shared_f, .atomic_f)
312 if is_receiver && ptyp.is_ptr() {
313 ptyp = ptyp.deref()
314 }
315 parts << t.type_to_str(ptyp)
316 return parts.join(' ')
317}
318
319// is_compatible_auto_str_method returns true when `method` matches the compiler-generated
320// `str() string` signature.
321pub fn (t &Table) is_compatible_auto_str_method(method &Fn) bool {
322 return method.name == 'str' && method.return_type == string_type && method.params.len == 1
323 && !method.params[0].is_mut
324}
325
326// type_has_implicit_str_method returns true when `typ` can satisfy `method`
327// through the compiler-generated `str() string`.
328pub fn (t &Table) type_has_implicit_str_method(typ Type, method &Fn) bool {
329 if !t.is_compatible_auto_str_method(method) {
330 return false
331 }
332 if typ.has_option_or_result() {
333 return false
334 }
335 sym := t.sym(typ.clear_flag(.variadic))
336 if sym.has_method_with_generic_parent('str') {
337 return false
338 }
339 if sym.kind == .char && typ.nr_muls() == 0 {
340 return false
341 }
342 if sym.kind == .function {
343 return false
344 }
345 if typ.is_any_kind_of_pointer() || typ in voidptr_types || typ in byteptr_types
346 || typ in charptr_types || typ == nil_type {
347 return true
348 }
349 match sym.info {
350 Alias, Array, ArrayFixed, Enum, FnType, Struct, Map, MultiReturn, SumType, Chan, Thread {
351 return sym.name != 'nil'
352 }
353 else {
354 return sym.kind in [.i8, .i16, .i32, .int, .i64, .isize, .u8, .u16, .u32, .u64, .usize,
355 .f32, .f64, .rune, .bool, .string, .generic_inst]
356 }
357 }
358}
359
360pub fn (t &Table) find_fn(name string) ?Fn {
361 if f := t.fns[name] {
362 return f
363 }
364 return none
365}
366
367pub fn (t &Table) known_fn(name string) bool {
368 t.find_fn(name) or { return false }
369 return true
370}
371
372pub fn (mut t Table) register_fn(new_fn Fn) {
373 t.fns[new_fn.name] = new_fn
374 if new_fn.is_pub && new_fn.mod == 'builtin' {
375 t.builtin_pub_fns[new_fn.name] = true
376 }
377}
378
379pub fn (mut t Table) register_interface(idecl InterfaceDecl) {
380 t.interfaces[idecl.typ] = idecl
381}
382
383pub fn (mut t Table) register_sumtype(sumtyp SumTypeDecl) {
384 t.sumtypes[sumtyp.typ] = sumtyp
385}
386
387pub fn (mut t TypeSymbol) register_method(new_fn Fn) int {
388 // returns a method index, stored in the ast.FnDecl
389 // for faster lookup in the checker's fn_decl method
390 t.methods << new_fn
391 return t.methods.len - 1
392}
393
394fn receiver_pattern_method_key(parent_idx int, name string) string {
395 return '${parent_idx}.${name}'
396}
397
398pub fn (mut t Table) register_structured_receiver_method(new_fn Fn) {
399 if !t.receiver_type_is_structured_generic_pattern(new_fn.receiver_type) {
400 return
401 }
402 receiver := t.receiver_generic_types(new_fn.receiver_type) or { return }
403 key := receiver_pattern_method_key(receiver.parent_idx, new_fn.name)
404 mut methods := t.structured_receiver_methods[key] or { []Fn{} }
405 methods << new_fn
406 t.structured_receiver_methods[key] = methods
407}
408
409pub fn (mut t TypeSymbol) update_method(f Fn) int {
410 for i, m in t.methods {
411 if m.name == f.name {
412 t.methods[i] = f
413 return i
414 }
415 }
416 return -1
417}
418
419pub fn (t &Table) register_aggregate_method(mut sym TypeSymbol, name string) !Fn {
420 if sym.kind != .aggregate {
421 t.panic('table.register_aggregate_method: sym.name: ${sym.name}, sym.kind: ${sym.kind} is not an aggregate, name: ${name}')
422 }
423 agg_info := sym.info as Aggregate
424 // an aggregate always has at least 2 types
425 mut found_once := false
426 mut new_fn := Fn{}
427 for typ in agg_info.types {
428 ts := t.sym(typ)
429 if type_method := ts.find_method(name) {
430 if !found_once {
431 found_once = true
432 new_fn = type_method
433 } else if !new_fn.method_equals(type_method) {
434 return error('method `${t.type_to_str(typ)}.${name}` signature is different')
435 }
436 } else {
437 return error('unknown method: `${t.type_to_str(typ)}.${name}`')
438 }
439 }
440 // register the method in the aggregate, so lookup is faster next time
441 sym.register_method(new_fn)
442 return new_fn
443}
444
445pub fn (t &Table) has_method(s &TypeSymbol, name string) bool {
446 t.find_method(s, name) or { return false }
447 return true
448}
449
450// get_type_methods returns methods available on `typ`.
451// For aliases, it includes alias-defined methods first, then inherited parent methods.
452pub fn (t &Table) get_type_methods(typ Type) []Fn {
453 mut ts := t.sym(typ)
454 mut methods := ts.get_methods()
455 if ts.kind != .alias {
456 return methods
457 }
458 mut seen_method_names := map[string]bool{}
459 for method in methods {
460 seen_method_names[method.name] = true
461 }
462 for ts.parent_idx != 0 {
463 ts = t.type_symbols[ts.parent_idx]
464 for method in ts.get_methods() {
465 if method.name !in seen_method_names {
466 methods << method
467 seen_method_names[method.name] = true
468 }
469 }
470 }
471 return methods
472}
473
474// find_method searches from current type up through each parent looking for method
475pub fn (t &Table) find_method(s &TypeSymbol, name string) !Fn {
476 mut ts := unsafe { s }
477 for {
478 if method := ts.find_method(name) {
479 return method
480 }
481 if ts.kind == .generic_inst {
482 parent_sym := t.sym(new_type((ts.info as GenericInst).parent_idx))
483 if method := parent_sym.find_method_with_generic_parent(name) {
484 return method
485 }
486 return error('unknown method')
487 }
488 if ts.kind == .aggregate {
489 if method := t.register_aggregate_method(mut ts, name) {
490 return method
491 } else {
492 return err
493 }
494 }
495 if ts.parent_idx == 0 {
496 // Also try Struct/Interface/SumType parent_type for generic concrete types
497 // whose parent_idx is 0 but have parent_type set.
498 has_parent_type := (ts.kind == .struct && (ts.info as Struct).parent_type != 0)
499 || (ts.kind == .interface && (ts.info as Interface).parent_type != 0)
500 || (ts.kind == .sum_type && (ts.info as SumType).parent_type != 0)
501 if has_parent_type {
502 if method := ts.find_method_with_generic_parent(name) {
503 return method
504 }
505 }
506 break
507 }
508 ts = t.type_symbols[ts.parent_idx]
509 }
510 return error('unknown method')
511}
512
513@[params]
514pub struct GetEmbedsOptions {
515pub:
516 preceding []Type
517}
518
519// get_embeds returns all nested embedded structs
520// the hierarchy of embeds is returned as a list
521pub fn (t &Table) get_embeds(sym &TypeSymbol, options GetEmbedsOptions) [][]Type {
522 mut embeds := [][]Type{}
523 unalias_sym := if sym.info is Alias { t.sym(sym.info.parent_type) } else { sym }
524 if unalias_sym.info is Struct {
525 for embed in unalias_sym.info.embeds {
526 embed_sym := t.sym(embed)
527 mut preceding := options.preceding.clone()
528 preceding << embed
529 embeds << t.get_embeds(embed_sym, preceding: preceding)
530 }
531 if unalias_sym.info.embeds.len == 0 && options.preceding.len > 0 {
532 embeds << options.preceding
533 }
534 }
535 return embeds
536}
537
538pub fn (t &Table) find_method_from_embeds(sym &TypeSymbol, method_name string) !(Fn, []Type) {
539 if sym.info is Struct {
540 mut found_methods := []Fn{}
541 mut embed_of_found_methods := []Type{}
542 for embed in sym.info.embeds {
543 embed_sym := t.sym(embed)
544 if m := embed_sym.find_method_with_generic_parent(method_name) {
545 found_methods << m
546 embed_of_found_methods << embed
547 } else {
548 method, types := t.find_method_from_embeds(embed_sym, method_name) or { continue }
549 found_methods << method
550 embed_of_found_methods << embed
551 embed_of_found_methods << types
552 }
553 }
554 if found_methods.len == 1 {
555 return found_methods[0], embed_of_found_methods
556 } else if found_methods.len > 1 {
557 return error('ambiguous method `${method_name}`')
558 }
559 } else if sym.info is Interface {
560 mut found_methods := []Fn{}
561 mut embed_of_found_methods := []Type{}
562 for embed in sym.info.embeds {
563 embed_sym := t.sym(embed)
564 if m := embed_sym.find_method_with_generic_parent(method_name) {
565 found_methods << m
566 embed_of_found_methods << embed
567 } else {
568 method, types := t.find_method_from_embeds(embed_sym, method_name) or { continue }
569 found_methods << method
570 embed_of_found_methods << embed
571 embed_of_found_methods << types
572 }
573 }
574 if found_methods.len == 1 {
575 return found_methods[0], embed_of_found_methods
576 } else if found_methods.len > 1 {
577 return error('ambiguous method `${method_name}`')
578 }
579 } else if sym.info is Aggregate {
580 for typ in sym.info.types {
581 agg_sym := t.sym(typ)
582 method, embed_types := t.find_method_from_embeds(agg_sym, method_name) or { continue }
583 if embed_types.len != 0 {
584 return method, embed_types
585 }
586 }
587 }
588 return error('')
589}
590
591// find_method_with_embeds searches for a given method, also looking through embedded fields
592pub fn (t &Table) find_method_with_embeds(sym &TypeSymbol, method_name string) !Fn {
593 if func := t.find_method(sym, method_name) {
594 return func
595 } else {
596 // look for embedded field
597 func, _ := t.find_method_from_embeds(sym, method_name) or { return err }
598 return func
599 }
600}
601
602// find_enum_field_val finds the possible int value from the enum name and enum field
603// (returns `none` if the value cannot be resolved at compile time)
604pub fn (t &Table) find_enum_field_val(name string, field_ string) ?i64 {
605 mut val := i64(0)
606 enum_decl := t.enum_decls[name]
607 mut enum_vals := []i64{}
608 for field in enum_decl.fields {
609 if field.name == field_ {
610 if field.has_expr {
611 if field.expr is IntegerLiteral {
612 val = field.expr.val.i64()
613 break
614 }
615 return none
616 } else {
617 if enum_vals.len > 0 {
618 val = enum_vals.last() + 1
619 } else {
620 val = 0
621 }
622 break
623 }
624 } else {
625 if field.has_expr {
626 if field.expr is IntegerLiteral {
627 enum_vals << field.expr.val.i64()
628 } else {
629 return none
630 }
631 } else {
632 if enum_vals.len > 0 {
633 enum_vals << enum_vals.last() + 1
634 } else {
635 enum_vals << 0
636 }
637 }
638 }
639 }
640 return if enum_decl.is_flag { i64(u64(1) << u64(val)) } else { val }
641}
642
643pub fn (t &Table) get_enum_field_names(name string) []string {
644 enum_decl := t.enum_decls[name]
645 mut field_names := []string{}
646 for field in enum_decl.fields {
647 field_names << field.name
648 }
649 return field_names
650}
651
652pub fn (t &Table) get_enum_field_vals(name string) []i64 {
653 enum_decl := t.enum_decls[name]
654 mut enum_vals := []i64{}
655 mut last_val := i64(0)
656 for field in enum_decl.fields {
657 if field.has_expr {
658 if field.expr is IntegerLiteral {
659 enum_vals << field.expr.val.i64()
660 last_val = field.expr.val.i64()
661 }
662 } else {
663 if enum_vals.len > 0 {
664 enum_vals << last_val + 1
665 last_val++
666 } else {
667 enum_vals << 0
668 }
669 }
670 }
671 return enum_vals
672}
673
674pub fn (t &Table) get_embed_methods(sym &TypeSymbol) []Fn {
675 mut methods := []Fn{}
676 if sym.info is Struct {
677 for embed in sym.info.embeds {
678 embed_sym := t.sym(embed)
679 methods << embed_sym.methods
680 methods << t.get_embed_methods(embed_sym)
681 }
682 }
683 return methods
684}
685
686fn (t &Table) register_aggregate_field(mut sym TypeSymbol, name string) !StructField {
687 if sym.kind != .aggregate {
688 t.panic('table.register_aggregate_field: sym.name: ${sym.name}, sym.kind: ${sym.kind} is not an aggregate, name: ${name}')
689 }
690 mut agg_info := sym.info as Aggregate
691 // an aggregate always has at least 2 types
692 mut found_once := false
693 mut new_field := StructField{}
694 for typ in agg_info.types {
695 ts := t.sym(typ)
696 if type_field := t.find_field(ts, name) {
697 if !found_once {
698 found_once = true
699 new_field = type_field
700 } else if new_field.typ != type_field.typ {
701 return error('field `${t.type_to_str(typ)}.${name}` type is different')
702 }
703 new_field = StructField{
704 ...new_field
705 is_mut: new_field.is_mut && type_field.is_mut
706 is_pub: new_field.is_pub && type_field.is_pub
707 }
708 } else {
709 return error('type `${t.type_to_str(typ)}` has no field or method `${name}`')
710 }
711 }
712 agg_info.fields << new_field
713 return new_field
714}
715
716pub fn (t &Table) struct_has_field(struct_ &TypeSymbol, name string) bool {
717 t.find_field(struct_, name) or { return false }
718 return true
719}
720
721// struct_fields returns all fields including fields from embeds
722// use this instead symbol.info.fields to get all fields
723pub fn (t &Table) struct_fields(sym &TypeSymbol) []StructField {
724 mut fields := []StructField{}
725 if sym.info is Struct {
726 fields << sym.info.fields
727 for embed in sym.info.embeds {
728 embed_sym := t.sym(embed)
729 fields << t.struct_fields(embed_sym)
730 }
731 }
732 return fields
733}
734
735// search from current type up through each parent looking for field
736pub fn (t &Table) find_field(s &TypeSymbol, name string) !StructField {
737 mut ts := unsafe { s }
738 for {
739 match mut ts.info {
740 Struct {
741 if field := ts.info.find_field(name) {
742 return field
743 }
744 }
745 Aggregate {
746 if field := ts.info.find_field(name) {
747 return field
748 }
749 field := t.register_aggregate_field(mut ts, name) or { return err }
750 return field
751 }
752 Interface {
753 if field := ts.info.find_field(name) {
754 return field
755 }
756 }
757 GenericInst {
758 parent_sym := t.sym(new_type(ts.info.parent_idx))
759 if field := t.find_field(parent_sym, name) {
760 match parent_sym.info {
761 Struct, Interface, SumType {
762 mut table := global_table
763 generic_names := parent_sym.info.generic_types.map(t.sym(it).name)
764 if generic_names.len == ts.info.concrete_types.len {
765 mut resolved_field := field
766 if ft := table.convert_generic_type(field.typ, generic_names,
767 ts.info.concrete_types)
768 {
769 resolved_field.typ = ft
770 }
771 if fut := table.convert_generic_type(field.unaliased_typ,
772 generic_names, ts.info.concrete_types)
773 {
774 resolved_field.unaliased_typ = fut
775 }
776 return resolved_field
777 }
778 }
779 else {}
780 }
781
782 return field
783 }
784 }
785 SumType {
786 t.resolve_common_sumtype_fields(mut ts)
787 if field := ts.info.find_sum_type_field(name) {
788 return field
789 }
790 missing_variants := t.find_missing_variants(ts.info, name)
791 return error('field `${name}` does not exist or have the same type in these sumtype `${ts.name}` variants: ${missing_variants}')
792 }
793 else {}
794 }
795
796 if ts.parent_idx == 0 {
797 break
798 }
799 ts = t.type_symbols[ts.parent_idx]
800 }
801 return error('')
802}
803
804// find_field_from_embeds tries to find a field in the nested embeds
805pub fn (t &Table) find_field_from_embeds(sym &TypeSymbol, field_name string) !(StructField, []Type) {
806 if sym.info is Struct {
807 mut found_fields := []StructField{}
808 mut embeds_of_found_fields := []Type{}
809 for embed in sym.info.embeds {
810 embed_sym := t.sym(embed)
811 if field := t.find_field(embed_sym, field_name) {
812 found_fields << field
813 embeds_of_found_fields << embed
814 } else {
815 field, types := t.find_field_from_embeds(embed_sym, field_name) or { continue }
816 found_fields << field
817 embeds_of_found_fields << embed
818 embeds_of_found_fields << types
819 }
820 }
821 if found_fields.len == 1 {
822 return found_fields[0], embeds_of_found_fields
823 } else if found_fields.len > 1 {
824 return error('ambiguous field `${field_name}`')
825 }
826 } else if sym.info is Aggregate {
827 mut found_once := false
828 mut new_field := StructField{}
829 mut found_embed_types := []Type{}
830 for typ in sym.info.types {
831 agg_sym := t.sym(typ)
832 mut field := StructField{}
833 mut embed_types := []Type{}
834 if type_field := t.find_field(agg_sym, field_name) {
835 field = type_field
836 } else {
837 field, embed_types = t.find_field_from_embeds(agg_sym, field_name) or {
838 return error('type `${t.type_to_str(typ)}` has no field or method `${field_name}`')
839 }
840 if found_embed_types.len == 0 {
841 found_embed_types = embed_types.clone()
842 }
843 }
844 if !found_once {
845 found_once = true
846 new_field = field
847 } else if new_field.typ != field.typ {
848 return error('field `${t.type_to_str(typ)}.${field_name}` type is different')
849 }
850 new_field = StructField{
851 ...new_field
852 is_mut: new_field.is_mut && field.is_mut
853 is_pub: new_field.is_pub && field.is_pub
854 }
855 }
856 if found_once {
857 return new_field, found_embed_types
858 }
859 } else if sym.info is Alias {
860 unalias_sym := t.sym(sym.info.parent_type)
861 return t.find_field_from_embeds(unalias_sym, field_name)
862 }
863 return error('')
864}
865
866// find_field_with_embeds searches for a given field, also looking through embedded fields
867pub fn (t &Table) find_field_with_embeds(sym &TypeSymbol, field_name string) !StructField {
868 if field := t.find_field(sym, field_name) {
869 return field
870 } else {
871 // look for embedded field
872 first_err := err
873 field, _ := t.find_field_from_embeds(sym, field_name) or { return first_err }
874 return field
875 }
876}
877
878pub fn (t &Table) resolve_common_sumtype_fields(mut sym TypeSymbol) {
879 mut info := sym.info as SumType
880 if info.found_fields {
881 return
882 }
883 mut field_map := map[string]StructField{}
884 mut field_usages := map[string]int{}
885 for variant in info.variants {
886 mut v_sym := t.final_sym(variant)
887 fields := match mut v_sym.info {
888 Struct {
889 t.struct_fields(v_sym)
890 }
891 SumType {
892 t.resolve_common_sumtype_fields(mut v_sym)
893 v_sym.info.fields
894 }
895 else {
896 []StructField{}
897 }
898 }
899
900 mut counted_field_names := map[string]bool{}
901 for field in fields {
902 if field.name in counted_field_names {
903 continue
904 }
905 counted_field_names[field.name] = true
906 if field.name !in field_map {
907 field_map[field.name] = field
908 field_usages[field.name]++
909 } else if field.equals(field_map[field.name]) {
910 field_usages[field.name]++
911 }
912 }
913 }
914 for field, nr_definitions in field_usages {
915 if nr_definitions == info.variants.len {
916 info.fields << field_map[field]
917 }
918 }
919 info.found_fields = true
920 sym.info = info
921 if sym.idx > 0 {
922 mut mut_table := unsafe { &Table(t) }
923 mut_table.type_symbols[sym.idx].info = info
924 }
925}
926
927// find_single_field_variant returns a field that exists in exactly one aggregate or sumtype variant.
928pub fn (t &Table) find_single_field_variant(sym &TypeSymbol, field_name string) !(Type, StructField, []Type) {
929 variants := match sym.info {
930 Aggregate { sym.info.types }
931 SumType { sym.info.variants }
932 else { []Type{} }
933 }
934
935 if variants.len == 0 {
936 return error('')
937 }
938 mut found_variant := Type(0)
939 mut found_field := StructField{}
940 mut found_embed_types := []Type{}
941 for variant in variants {
942 variant_sym := t.final_sym(variant)
943 mut field := StructField{}
944 mut embed_types := []Type{}
945 if f := t.find_field(variant_sym, field_name) {
946 field = f
947 } else {
948 field, embed_types = t.find_field_from_embeds(variant_sym, field_name) or { continue }
949 }
950 if found_variant != 0 {
951 return error('')
952 }
953 found_variant = variant
954 found_field = field
955 found_embed_types = embed_types.clone()
956 }
957 if found_variant == 0 {
958 return error('')
959 }
960 return found_variant, found_field, found_embed_types
961}
962
963@[inline]
964pub fn (t &Table) find_type(name string) Type {
965 return idx_to_type(t.type_idxs[name])
966}
967
968@[inline]
969pub fn (t &Table) find_type_idx(name string) int {
970 return t.type_idxs[name]
971}
972
973@[inline]
974pub fn (t &Table) find_type_idx_fn_scoped(name string, scope &Scope) int {
975 if scope != unsafe { nil } {
976 idx := t.type_idxs['_${name}_${scope.start_pos}']
977 if idx != 0 {
978 return idx
979 }
980 }
981 return t.type_idxs[name]
982}
983
984@[inline]
985pub fn (t &Table) find_sym(name string) ?&TypeSymbol {
986 idx := t.type_idxs[name]
987 if idx > 0 {
988 return t.type_symbols[idx]
989 }
990 return none
991}
992
993@[inline]
994pub fn (t &Table) find_sym_and_type_idx(name string) (&TypeSymbol, int) {
995 idx := t.type_idxs[name]
996 if idx > 0 {
997 return t.type_symbols[idx], idx
998 }
999 return invalid_type_symbol, idx
1000}
1001
1002pub const invalid_type_symbol = &TypeSymbol{
1003 idx: invalid_type_idx
1004 parent_idx: invalid_type_idx
1005 language: .v
1006 mod: 'builtin'
1007 kind: .placeholder
1008 name: 'InvalidType'
1009 cname: 'InvalidType'
1010 is_builtin: false
1011}
1012
1013@[inline]
1014pub fn (t &Table) sym_by_idx(idx int) &TypeSymbol {
1015 return t.type_symbols[idx]
1016}
1017
1018@[direct_array_access]
1019pub fn (t &Table) sym(typ Type) &TypeSymbol {
1020 idx := typ.idx()
1021 if idx > 0 && idx < t.type_symbols.len {
1022 return t.type_symbols[idx]
1023 }
1024 if idx == 0 || idx == 65535 || typ == invalid_type {
1025 // invalid_type and idx=0 are used as sentinels during generic type resolution;
1026 // return a safe placeholder instead of panicking.
1027 return invalid_type_symbol
1028 }
1029 // this should never happen
1030 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`.
1031')
1032 return invalid_type_symbol
1033}
1034
1035// max_alias_chain_depth caps the recursive walk through chained aliases
1036// (#27055) so a malformed input — e.g. mutual aliases formed via placeholder
1037// rewriting — can't hang the compiler in the type-resolution helpers below.
1038const max_alias_chain_depth = 64
1039
1040// final_sym follows aliases until it gets to a "real" Type. Chained aliases
1041// (`type B = A` where `A` is itself an alias, #27055) are walked recursively;
1042// a depth cap guards against pathological inputs where mutual aliases slip
1043// past the checker's cycle rejection.
1044@[direct_array_access]
1045pub fn (t &Table) final_sym(typ Type) &TypeSymbol {
1046 mut idx := typ.idx()
1047 if idx > 0 && idx < t.type_symbols.len {
1048 mut cur_sym := t.type_symbols[idx]
1049 for _ in 0 .. max_alias_chain_depth {
1050 if cur_sym.info !is Alias {
1051 break
1052 }
1053 idx = (cur_sym.info as Alias).parent_type.idx()
1054 if idx <= 0 || idx >= t.type_symbols.len {
1055 break
1056 }
1057 cur_sym = t.type_symbols[idx]
1058 }
1059 return cur_sym
1060 }
1061 if idx == 0 {
1062 return invalid_type_symbol
1063 }
1064 // this should never happen
1065 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`.')
1066 return invalid_type_symbol
1067}
1068
1069// 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
1070pub fn (t &Table) final_type(typ Type) Type {
1071 mut idx := typ.idx()
1072 if idx > 0 && idx < t.type_symbols.len {
1073 mut cur_sym := t.type_symbols[idx]
1074 mut last_alias_parent := Type(0)
1075 for _ in 0 .. max_alias_chain_depth {
1076 if cur_sym.info !is Alias {
1077 break
1078 }
1079 last_alias_parent = (cur_sym.info as Alias).parent_type
1080 idx = last_alias_parent.idx()
1081 if idx <= 0 || idx >= t.type_symbols.len {
1082 break
1083 }
1084 cur_sym = t.type_symbols[idx]
1085 }
1086 if last_alias_parent != 0 {
1087 if cur_sym.info is Enum {
1088 return cur_sym.info.typ
1089 }
1090 return last_alias_parent
1091 }
1092 if cur_sym.info is Enum {
1093 return cur_sym.info.typ
1094 }
1095 }
1096 return typ
1097}
1098
1099@[inline]
1100pub fn (t &Table) get_type_name(typ Type) string {
1101 return t.sym(typ).name
1102}
1103
1104@[inline]
1105pub fn (t &Table) get_final_type_name(typ Type) string {
1106 return t.final_sym(typ).name
1107}
1108
1109@[inline]
1110pub fn (t &Table) unalias_num_type(typ Type) Type {
1111 sym := t.sym(typ)
1112 if sym.info is Alias {
1113 if sym.info.parent_type <= char_type && sym.info.parent_type >= void_type {
1114 return sym.info.parent_type
1115 }
1116 }
1117 return typ
1118}
1119
1120@[inline]
1121pub fn (t &Table) unaliased_type(typ Type) Type {
1122 sym := t.sym(typ)
1123 if sym.info is Alias {
1124 return sym.info.parent_type
1125 }
1126 return typ
1127}
1128
1129// are_payloads_alias_compatible reports whether two types describe the same
1130// in-memory payload after fully unaliasing both sides, including recursively
1131// through arrays/fixed arrays/maps. It does NOT permit numeric promotions
1132// or any other shape change — meant for checks that need true layout
1133// equivalence (e.g. gating result/option memcpy-based clones, or checking
1134// that `!Alias <- !T` is valid when `type Alias = T`).
1135pub fn (t &Table) are_payloads_alias_compatible(a Type, b Type) bool {
1136 if a == b {
1137 return true
1138 }
1139 a_unaliased := t.fully_unaliased_type(a)
1140 b_unaliased := t.fully_unaliased_type(b)
1141 // `?T`/`!T` lower to a distinct `_option_T`/`_result_T` C struct per
1142 // element type, so `?Alias` and `?T` (or container elements wrapping the
1143 // same) are not layout-equivalent even if `Alias = T`. The top-level
1144 // conversion in return.v / cgen.v (#27264) clears these flags before
1145 // recursing — if they remain after unaliasing (including the case where
1146 // the alias's parent carries the flag), reject (#27278 review).
1147 if a_unaliased.has_option_or_result() || b_unaliased.has_option_or_result() {
1148 return false
1149 }
1150 if a_unaliased == b_unaliased {
1151 return true
1152 }
1153 // `sym()` looks up by idx and drops `nr_muls()`, so without this guard a
1154 // pointer like `&[]Token` would be reported as payload-compatible with
1155 // `Tokens` (#27278 review).
1156 if a_unaliased.nr_muls() != b_unaliased.nr_muls() {
1157 return false
1158 }
1159 a_sym := t.sym(a_unaliased)
1160 b_sym := t.sym(b_unaliased)
1161 if a_sym.kind != b_sym.kind {
1162 return false
1163 }
1164 if a_sym.info is Array && b_sym.info is Array {
1165 return a_sym.info.nr_dims == b_sym.info.nr_dims
1166 && t.are_payloads_alias_compatible(a_sym.info.elem_type, b_sym.info.elem_type)
1167 }
1168 if a_sym.info is ArrayFixed && b_sym.info is ArrayFixed {
1169 return a_sym.info.size == b_sym.info.size
1170 && t.are_payloads_alias_compatible(a_sym.info.elem_type, b_sym.info.elem_type)
1171 }
1172 if a_sym.info is Map && b_sym.info is Map {
1173 return t.are_payloads_alias_compatible(a_sym.info.key_type, b_sym.info.key_type)
1174 && t.are_payloads_alias_compatible(a_sym.info.value_type, b_sym.info.value_type)
1175 }
1176 return false
1177}
1178
1179// fully_unaliased_type unwraps alias chains while preserving pointer indirections and flags.
1180@[inline]
1181pub fn (t &Table) fully_unaliased_type(typ Type) Type {
1182 mut unaliased := typ
1183 mut extra_flags := u32(typ) & 0xff00_0000
1184 for {
1185 sym := t.sym(unaliased)
1186 if sym.info is Alias {
1187 parent_typ := sym.info.parent_type
1188 unaliased = Type(u32(parent_typ.set_nr_muls(parent_typ.nr_muls() + unaliased.nr_muls())) | extra_flags)
1189 extra_flags |= u32(unaliased) & 0xff00_0000
1190 continue
1191 }
1192 return unaliased
1193 }
1194 return unaliased
1195}
1196
1197// update_sym_by_idx replaces the symbol on the `existing_idx`, with the new `sym`
1198pub fn (mut t Table) update_sym_by_idx(existing_idx int, sym &TypeSymbol) {
1199 t.delete_cached_type_to_str(idx_to_type(existing_idx), 0)
1200 t.type_symbols[existing_idx] = &TypeSymbol{
1201 ...sym
1202 idx: existing_idx
1203 size: -1 // enforce recalculation of the size, for future t.type_size(idx) calls
1204 align: -1
1205 }
1206 for mut esym in t.type_symbols {
1207 if esym.size != -1 && esym.info is Alias && esym.info.parent_type == existing_idx {
1208 // make sure to force recalculation, if t.type_size(idx) on an already existing alias is called again:
1209 esym.size = -1
1210 esym.align = -1
1211 }
1212 }
1213}
1214
1215fn (mut t Table) promote_placeholder_generic_children(parent_idx int, sym TypeSymbol) {
1216 parent_generic_types := match sym.info {
1217 Struct { sym.info.generic_types }
1218 Interface { sym.info.generic_types }
1219 SumType { sym.info.generic_types }
1220 else { []Type{} }
1221 }
1222
1223 for i, child in t.type_symbols {
1224 if child.kind != .placeholder || child.parent_idx != parent_idx
1225 || child.generic_types.len == 0 {
1226 continue
1227 }
1228 if child.generic_types == parent_generic_types {
1229 // The placeholder child uses the same generic types as the parent struct
1230 // (e.g. Iter<T> where Iter[T] uses the same T). Redirect it to the parent
1231 // rather than creating a redundant promoted type.
1232 t.type_symbols[i] = t.type_symbols[parent_idx]
1233 continue
1234 }
1235 t.update_sym_by_idx(i, &TypeSymbol{
1236 ...sym
1237 name: child.name
1238 cname: child.cname
1239 ngname: child.ngname
1240 rname: if child.rname == '' { sym.name } else { child.rname }
1241 parent_idx: parent_idx
1242 methods: child.methods
1243 generic_types: child.generic_types.clone()
1244 })
1245 }
1246}
1247
1248fn (mut t Table) rewrite_already_registered_symbol(typ TypeSymbol, existing_idx int) int {
1249 existing_symbol := t.type_symbols[existing_idx]
1250 $if trace_rewrite_already_registered_symbol ? {
1251 eprintln('>> rewrite_already_registered_symbol sym: ${typ.name} | existing_idx: ${existing_idx} | existing_symbol: ${existing_symbol.name}')
1252 }
1253 if existing_symbol.kind == .placeholder {
1254 // override placeholder
1255 ngname := if typ.ngname != '' { typ.ngname } else { strip_generic_params(typ.name) }
1256 t.type_symbols[existing_idx] = &TypeSymbol{
1257 ...typ
1258 ngname: ngname
1259 methods: existing_symbol.methods
1260 idx: existing_idx
1261 is_builtin: existing_symbol.is_builtin
1262 }
1263 t.promote_placeholder_generic_children(existing_idx, typ)
1264 return existing_idx
1265 }
1266 // Allow overwriting a generic_inst with a more complete concrete type definition
1267 // (struct, interface, sumtype). This happens when unwrap_generic_type creates a
1268 // placeholder that gets prematurely converted to generic_inst by
1269 // find_or_register_generic_inst during method resolution, before the full type
1270 // can be registered.
1271 if existing_symbol.kind == .generic_inst && typ.kind in [.struct, .interface, .sum_type] {
1272 ngname := if typ.ngname != '' { typ.ngname } else { strip_generic_params(typ.name) }
1273 t.type_symbols[existing_idx] = &TypeSymbol{
1274 ...typ
1275 ngname: ngname
1276 methods: existing_symbol.methods
1277 idx: existing_idx
1278 is_builtin: existing_symbol.is_builtin
1279 }
1280 return existing_idx
1281 }
1282 // Allow C type aliases to override existing C types (e.g. `type C.WCHAR = u16`
1283 // on Windows where WCHAR is already registered from system headers).
1284 // Detect C aliases by the `C.` name prefix, since alias TypeSymbols
1285 // themselves don't carry .language == .c (only Alias.info.language does):
1286 if typ.kind == .alias && typ.name.starts_with('C.') && existing_symbol.name.starts_with('C.') {
1287 t.type_symbols[existing_idx] = &TypeSymbol{
1288 ...typ
1289 idx: existing_idx
1290 is_builtin: existing_symbol.is_builtin
1291 }
1292 return existing_idx
1293 }
1294 // Keep concrete C type re-declarations so later modules can resolve their own
1295 // symbol instead of inheriting the first module's private metadata.
1296 if existing_symbol.language == .c && typ.language == .c {
1297 return -2
1298 }
1299 // Override the already registered builtin types with the actual
1300 // v struct declarations in the vlib/builtin module sources:
1301 if (existing_idx >= string_type_idx && existing_idx <= map_type_idx)
1302 || existing_idx == error_type_idx {
1303 if existing_idx == string_type_idx {
1304 // existing_type := t.type_symbols[existing_idx]
1305 unsafe {
1306 *existing_symbol = TypeSymbol{
1307 ...typ
1308 kind: existing_symbol.kind
1309 idx: existing_idx
1310 is_builtin: existing_symbol.is_builtin
1311 }
1312 }
1313 } else {
1314 t.type_symbols[existing_idx] = &TypeSymbol{
1315 ...typ
1316 idx: existing_idx
1317 is_builtin: existing_symbol.is_builtin
1318 }
1319 }
1320 return existing_idx
1321 }
1322 return invalid_type_idx
1323}
1324
1325@[inline]
1326pub fn (mut t Table) register_sym(sym TypeSymbol) int {
1327 mut idx := -2
1328 $if trace_register_sym ? {
1329 defer(fn) {
1330 eprintln('>> register_sym: ${sym.name:-60} | idx: ${idx}')
1331 }
1332 }
1333 sym_name := if sym.info is Struct && sym.info.scoped_name != '' {
1334 sym.info.scoped_name
1335 } else {
1336 sym.name
1337 }
1338 mut existing_idx := t.type_idxs[sym_name]
1339 if existing_idx > 0 {
1340 idx = t.rewrite_already_registered_symbol(sym, existing_idx)
1341 if idx != -2 {
1342 return idx
1343 }
1344 }
1345 if sym.mod == 'main' {
1346 existing_idx = t.type_idxs[sym_name.trim_string_left('main.')]
1347 if existing_idx > 0 {
1348 idx = t.rewrite_already_registered_symbol(sym, existing_idx)
1349 if idx != -2 {
1350 return idx
1351 }
1352 }
1353 }
1354 idx = t.type_symbols.len
1355 t.type_symbols << &TypeSymbol{
1356 ...sym
1357 }
1358 t.type_symbols[idx].idx = idx
1359 if t.type_symbols[idx].ngname == '' {
1360 t.type_symbols[idx].ngname = strip_generic_params(sym.name)
1361 }
1362 t.type_idxs[sym_name] = idx
1363 return idx
1364}
1365
1366@[inline]
1367pub fn (mut t Table) register_enum_decl(enum_decl EnumDecl) {
1368 t.enum_decls[enum_decl.name] = enum_decl
1369}
1370
1371@[inline]
1372pub fn (mut t Table) register_anon_struct(name string, sym_idx int) {
1373 t.anon_struct_names[name] = sym_idx
1374}
1375
1376@[inline]
1377pub fn (mut t Table) register_anon_union(name string, sym_idx int) {
1378 t.anon_union_names[name] = sym_idx
1379}
1380
1381pub fn (t &Table) known_type(name string) bool {
1382 return t.type_idxs[name] != 0 || t.parsing_type == name || name in ['i32', 'byte']
1383}
1384
1385@[inline]
1386pub fn strip_generic_params(name string) string {
1387 return name.all_before('[')
1388}
1389
1390pub fn split_generic_args(args string) []string {
1391 if args.len == 0 {
1392 return []string{}
1393 }
1394 mut parts := []string{}
1395 mut start := 0
1396 mut square_depth := 0
1397 mut paren_depth := 0
1398 mut brace_depth := 0
1399 for i, ch in args {
1400 match ch {
1401 `[` {
1402 square_depth++
1403 }
1404 `]` {
1405 if square_depth > 0 {
1406 square_depth--
1407 }
1408 }
1409 `(` {
1410 paren_depth++
1411 }
1412 `)` {
1413 if paren_depth > 0 {
1414 paren_depth--
1415 }
1416 }
1417 `{` {
1418 brace_depth++
1419 }
1420 `}` {
1421 if brace_depth > 0 {
1422 brace_depth--
1423 }
1424 }
1425 `,` {
1426 if square_depth == 0 && paren_depth == 0 && brace_depth == 0 {
1427 parts << args[start..i].trim_space()
1428 start = i + 1
1429 }
1430 }
1431 else {}
1432 }
1433 }
1434 parts << args[start..].trim_space()
1435 return parts.filter(it.len > 0)
1436}
1437
1438// start_parsing_type open the scope during the parsing of a type
1439// where the type name must include the module prefix
1440pub fn (mut t Table) start_parsing_type(type_name string) {
1441 t.parsing_type = type_name
1442}
1443
1444pub fn (mut t Table) reset_parsing_type() {
1445 t.parsing_type = ''
1446}
1447
1448pub fn (t &Table) known_type_idx(typ Type) bool {
1449 if typ == 0 {
1450 return false
1451 }
1452 sym := t.sym(typ)
1453 match sym.kind {
1454 .placeholder {
1455 return sym.language != .v || sym.name.starts_with('C.')
1456 }
1457 .array {
1458 if sym.info is Array {
1459 return t.known_type_idx(sym.info.elem_type)
1460 }
1461 return false
1462 }
1463 .array_fixed {
1464 if sym.info is ArrayFixed {
1465 return t.known_type_idx(sym.info.elem_type)
1466 }
1467 return false
1468 }
1469 .map {
1470 if sym.info is Map {
1471 return t.known_type_idx(sym.info.key_type) && t.known_type_idx(sym.info.value_type)
1472 }
1473 return false
1474 }
1475 else {}
1476 }
1477
1478 return true
1479}
1480
1481// supports_map_key_type returns true when C codegen can hash and compare the map key type.
1482pub fn (t &Table) supports_map_key_type(typ Type) bool {
1483 if typ == 0 || typ.has_flag(.generic) {
1484 return true
1485 }
1486 mut seen := map[int]bool{}
1487 return t.supports_map_key_type_in_type(typ.clear_flags(), mut seen)
1488}
1489
1490fn (t &Table) supports_map_key_type_in_type(typ Type, mut seen map[int]bool) bool {
1491 current_typ := typ.clear_flags()
1492 if current_typ.nr_muls() > 0 {
1493 return false
1494 }
1495 type_idx := current_typ.idx()
1496 if seen[type_idx] {
1497 return true
1498 }
1499 seen[type_idx] = true
1500 sym := t.sym(current_typ)
1501 match sym.kind {
1502 .alias {
1503 return t.supports_map_key_type_in_type((sym.info as Alias).parent_type, mut seen)
1504 }
1505 .array_fixed {
1506 return t.supports_map_key_type_in_type((sym.info as ArrayFixed).elem_type, mut seen)
1507 }
1508 .u8, .i8, .char, .i16, .u16, .enum, .int, .i32, .u32, .rune, .f32, .voidptr, .u64, .i64,
1509 .f64, .string {
1510 return true
1511 }
1512 else {
1513 return false
1514 }
1515 }
1516}
1517
1518// array_source_name generates the original name for the v source.
1519// e. g. []int
1520@[inline]
1521pub fn (t &Table) array_name(elem_type Type) string {
1522 elem_type_sym := t.sym(elem_type)
1523 ptr := if elem_type.is_ptr() { '&'.repeat(elem_type.nr_muls()) } else { '' }
1524 opt := if elem_type.has_flag(.option) { '?' } else { '' }
1525 res := if elem_type.has_flag(.result) { '!' } else { '' }
1526 name := if elem_type_sym.info is Struct && elem_type_sym.info.scoped_name != '' {
1527 elem_type_sym.info.scoped_name
1528 } else {
1529 elem_type_sym.name
1530 }
1531 return '[]${opt}${res}${ptr}${name}'
1532}
1533
1534@[inline]
1535pub fn (t &Table) array_cname(elem_type Type) string {
1536 elem_type_sym := t.sym(elem_type)
1537 suffix := if elem_type.is_ptr() { '_ptr'.repeat(elem_type.nr_muls()) } else { '' }
1538 opt := if elem_type.has_flag(.option) { '_option_' } else { '' }
1539 res := if elem_type.has_flag(.result) { '_result_' } else { '' }
1540 cname := elem_type_sym.scoped_cname()
1541 if elem_type_sym.cname.contains('[') {
1542 type_name := cname.replace_each(map_cname_escape_seq)
1543 return 'Array_${opt}${res}${type_name}${suffix}'
1544 } else {
1545 return 'Array_${opt}${res}${cname}${suffix}'
1546 }
1547}
1548
1549// array_fixed_source_name generates the original name for the v source.
1550// e. g. [16][8]int
1551@[inline]
1552pub fn (t &Table) array_fixed_name(elem_type Type, size int, size_expr Expr) string {
1553 elem_type_sym := t.sym(elem_type)
1554 ptr := if elem_type.is_ptr() { '&'.repeat(elem_type.nr_muls()) } else { '' }
1555 opt := if elem_type.has_flag(.option) { '?' } else { '' }
1556 res := if elem_type.has_flag(.result) { '!' } else { '' }
1557 size_str := if size_expr is EmptyExpr || size !in [0, 987654321] {
1558 size.str()
1559 } else {
1560 size_expr.str()
1561 }
1562 name := if elem_type_sym.info is Struct && elem_type_sym.info.scoped_name != '' {
1563 elem_type_sym.info.scoped_name
1564 } else {
1565 elem_type_sym.name
1566 }
1567 return '[${size_str}]${opt}${res}${ptr}${name}'
1568}
1569
1570@[inline]
1571pub fn (t &Table) array_fixed_cname(elem_type Type, size int) string {
1572 elem_type_sym := t.sym(elem_type)
1573 suffix := if elem_type.is_ptr() { '_ptr${elem_type.nr_muls()}' } else { '' }
1574 opt := if elem_type.has_flag(.option) { '_option_' } else { '' }
1575 res := if elem_type.has_flag(.result) { '_result_' } else { '' }
1576 mut cname := elem_type_sym.scoped_cname()
1577 if elem_type_sym.cname.contains('[') {
1578 type_name := cname.replace_each(map_cname_escape_seq)
1579 return 'Array_fixed_${opt}${res}${type_name}${suffix}_${size}'
1580 } else {
1581 return 'Array_fixed_${opt}${res}${cname}${suffix}_${size}'
1582 }
1583}
1584
1585@[inline]
1586pub fn (t &Table) chan_name(elem_type Type, is_mut bool) string {
1587 elem_type_sym := t.sym(elem_type)
1588 mut ptr := ''
1589 if is_mut {
1590 ptr = 'mut '
1591 } else if elem_type.is_ptr() {
1592 ptr = '&'
1593 }
1594 return 'chan ${ptr}${elem_type_sym.name}'
1595}
1596
1597@[inline]
1598pub fn (t &Table) chan_cname(elem_type Type, is_mut bool) string {
1599 elem_type_sym := t.sym(elem_type)
1600 mut suffix := ''
1601 if is_mut {
1602 suffix = '_mut'
1603 } else if elem_type.is_ptr() {
1604 suffix = '_ptr'
1605 }
1606 type_name := if elem_type_sym.cname.contains('[') {
1607 elem_type_sym.cname.replace_each(map_cname_escape_seq)
1608 } else {
1609 elem_type_sym.cname
1610 }
1611 return 'chan_${type_name}' + suffix
1612}
1613
1614@[inline]
1615pub fn (t &Table) promise_name(return_type Type) string {
1616 if return_type.idx() == void_type_idx {
1617 return 'Promise[JS.Any, JS.Any]'
1618 }
1619
1620 return_type_sym := t.sym(return_type)
1621 return 'Promise[${return_type_sym.name}, JS.Any]'
1622}
1623
1624@[inline]
1625pub fn (t &Table) promise_cname(return_type Type) string {
1626 if return_type == void_type {
1627 return 'Promise_Any_Any'
1628 }
1629
1630 return_type_sym := t.sym(return_type)
1631 return 'Promise_${return_type_sym.name}_Any'
1632}
1633
1634@[inline]
1635pub fn (t &Table) thread_name(return_type Type) string {
1636 if return_type.idx() == void_type_idx {
1637 if return_type.has_flag(.option) {
1638 return 'thread ?'
1639 } else if return_type.has_flag(.result) {
1640 return 'thread !'
1641 } else {
1642 return 'thread'
1643 }
1644 }
1645 return_type_sym := t.sym(return_type)
1646 ptr := if return_type.is_ptr() { '&' } else { '' }
1647 opt := if return_type.has_flag(.option) { '?' } else { '' }
1648 res := if return_type.has_flag(.result) { '!' } else { '' }
1649 return 'thread ${opt}${res}${ptr}${return_type_sym.name}'
1650}
1651
1652@[inline]
1653pub fn (t &Table) thread_cname(return_type Type) string {
1654 if return_type == void_type {
1655 if return_type.has_flag(.option) {
1656 return '__v_thread_Option_void'
1657 } else if return_type.has_flag(.result) {
1658 return '__v_thread_Result_void'
1659 } else {
1660 return '__v_thread'
1661 }
1662 }
1663 return_type_sym := t.sym(return_type)
1664 suffix := if return_type.is_ptr() { '_ptr' } else { '' }
1665 opt := if return_type.has_flag(.option) { '_option_' } else { '' }
1666 res := if return_type.has_flag(.result) { '_result_' } else { '' }
1667 return '__v_thread_${opt}${res}${return_type_sym.cname}${suffix}'
1668}
1669
1670// map_source_name generates the original name for the v source.
1671// e. g. map[string]int
1672@[inline]
1673pub fn (t &Table) map_name(key_type Type, value_type Type) string {
1674 key_type_sym := t.sym(key_type)
1675 value_type_sym := t.sym(value_type)
1676 ptr := if value_type.is_ptr() { '&'.repeat(value_type.nr_muls()) } else { '' }
1677 opt := if value_type.has_flag(.option) { '?' } else { '' }
1678 res := if value_type.has_flag(.result) { '!' } else { '' }
1679 return 'map[${key_type_sym.name}]${opt}${res}${ptr}${value_type_sym.name}'
1680}
1681
1682@[inline]
1683pub fn (t &Table) map_cname(key_type Type, value_type Type) string {
1684 key_type_sym := t.sym(key_type)
1685 value_type_sym := t.sym(value_type)
1686 suffix := if value_type.is_ptr() { '_ptr'.repeat(value_type.nr_muls()) } else { '' }
1687 opt := if value_type.has_flag(.option) { '_option_' } else { '' }
1688 res := if value_type.has_flag(.result) { '_result_' } else { '' }
1689 if value_type_sym.cname.contains('[') {
1690 type_name := value_type_sym.cname.replace_each(map_cname_escape_seq)
1691 return 'Map_${key_type_sym.cname}_${opt}${res}${type_name}${suffix}'
1692 } else {
1693 return 'Map_${key_type_sym.cname}_${opt}${res}${value_type_sym.cname}${suffix}'
1694 }
1695}
1696
1697pub fn (mut t Table) find_or_register_chan(elem_type Type, is_mut bool) int {
1698 name := t.chan_name(elem_type, is_mut)
1699 cname := t.chan_cname(elem_type, is_mut)
1700 // existing
1701 existing_idx := t.type_idxs[name]
1702 if existing_idx > 0 {
1703 return existing_idx
1704 }
1705 chan_sym := TypeSymbol{
1706 parent_idx: chan_type_idx
1707 kind: .chan
1708 name: name
1709 cname: cname
1710 ngname: strip_generic_params(name)
1711 info: Chan{
1712 elem_type: elem_type
1713 is_mut: is_mut
1714 }
1715 }
1716 return t.register_sym(chan_sym)
1717}
1718
1719pub fn (mut t Table) find_or_register_map(key_type Type, value_type Type) int {
1720 name := t.map_name(key_type, value_type)
1721 cname := t.map_cname(key_type, value_type)
1722 // existing
1723 existing_idx := t.type_idxs[name]
1724 if existing_idx > 0 {
1725 return existing_idx
1726 }
1727 map_sym := TypeSymbol{
1728 parent_idx: map_type_idx
1729 kind: .map
1730 name: name
1731 cname: cname
1732 ngname: strip_generic_params(name)
1733 info: Map{
1734 key_type: key_type
1735 value_type: value_type
1736 }
1737 }
1738 return t.register_sym(map_sym)
1739}
1740
1741pub fn (mut t Table) find_or_register_thread(return_type Type) int {
1742 name := t.thread_name(return_type)
1743 cname := t.thread_cname(return_type)
1744 // existing
1745 existing_idx := t.type_idxs[name]
1746 if existing_idx > 0 {
1747 return existing_idx
1748 }
1749 thread_sym := TypeSymbol{
1750 parent_idx: thread_type_idx
1751 kind: .thread
1752 name: name
1753 cname: cname
1754 ngname: strip_generic_params(name)
1755 info: Thread{
1756 return_type: return_type
1757 }
1758 }
1759 return t.register_sym(thread_sym)
1760}
1761
1762pub fn (mut t Table) find_or_register_promise(return_type Type) int {
1763 name := t.promise_name(return_type)
1764
1765 cname := t.promise_cname(return_type)
1766 // existing
1767 existing_idx := t.type_idxs[name]
1768 if existing_idx > 0 {
1769 return existing_idx
1770 }
1771
1772 promise_type := TypeSymbol{
1773 parent_idx: t.type_idxs['Promise']
1774 kind: .struct
1775 name: name
1776 cname: cname
1777 ngname: strip_generic_params(name)
1778 info: Struct{
1779 concrete_types: [return_type, t.type_idxs['JS.Any']]
1780 }
1781 }
1782
1783 // register
1784 return t.register_sym(promise_type)
1785}
1786
1787pub fn (mut t Table) find_or_register_array(elem_type Type) int {
1788 name := t.array_name(elem_type)
1789 // existing
1790 existing_idx := t.type_idxs[name]
1791 if existing_idx > 0 {
1792 return existing_idx
1793 }
1794 cname := t.array_cname(elem_type)
1795 // register
1796 array_type_ := TypeSymbol{
1797 parent_idx: array_type_idx
1798 kind: .array
1799 name: name
1800 cname: cname
1801 ngname: strip_generic_params(name)
1802 info: Array{
1803 nr_dims: 1
1804 elem_type: elem_type
1805 }
1806 }
1807 return t.register_sym(array_type_)
1808}
1809
1810pub fn (mut t Table) find_or_register_array_with_dims(elem_type Type, nr_dims int) int {
1811 if nr_dims == 1 {
1812 return t.find_or_register_array(elem_type)
1813 }
1814 return t.find_or_register_array(idx_to_type(t.find_or_register_array_with_dims(elem_type,
1815 nr_dims - 1)))
1816}
1817
1818pub fn (mut t Table) find_or_register_array_fixed(elem_type Type, size int, size_expr Expr, is_fn_ret bool) int {
1819 prefix := if is_fn_ret { '_v_' } else { '' }
1820 name := prefix + t.array_fixed_name(elem_type, size, size_expr)
1821 // existing
1822 existing_idx := t.type_idxs[name]
1823 if existing_idx > 0 {
1824 return existing_idx
1825 }
1826 cname := prefix + t.array_fixed_cname(elem_type, size)
1827 // register
1828 array_fixed_type := TypeSymbol{
1829 kind: .array_fixed
1830 name: name
1831 cname: cname
1832 ngname: strip_generic_params(name)
1833 info: ArrayFixed{
1834 elem_type: elem_type
1835 size: size
1836 size_expr: size_expr
1837 is_fn_ret: is_fn_ret
1838 }
1839 }
1840 return t.register_sym(array_fixed_type)
1841}
1842
1843pub fn (mut t Table) find_or_register_multi_return(mr_typs []Type) int {
1844 mut name := '('
1845 mut cname := 'multi_return'
1846 for i, mr_typ in mr_typs {
1847 mr_type_sym := t.sym(mktyp(mr_typ))
1848 ref, cref := if mr_typ.is_ptr() { '&', 'ref_' } else { '', '' }
1849 name += if mr_typ.has_flag(.option) { '?' } else { '' }
1850 name += if mr_typ.has_flag(.result) { '!' } else { '' }
1851 name += '${ref}${mr_type_sym.name}'
1852 cname += if mr_typ.has_flag(.option) { '_option' } else { '' }
1853 cname += if mr_typ.has_flag(.result) { '_result' } else { '' }
1854 cname += '_${cref}${mr_type_sym.cname}'
1855 if i < mr_typs.len - 1 {
1856 name += ', '
1857 }
1858 }
1859 name += ')'
1860 // existing
1861 existing_idx := t.type_idxs[name]
1862 if existing_idx > 0 {
1863 return existing_idx
1864 }
1865 multireg_sym := TypeSymbol{
1866 kind: .multi_return
1867 name: name
1868 cname: cname
1869 ngname: strip_generic_params(name)
1870 info: MultiReturn{
1871 types: mr_typs
1872 }
1873 }
1874 return t.register_sym(multireg_sym)
1875}
1876
1877pub fn (mut t Table) find_or_register_fn_type(f Fn, is_anon bool, has_decl bool) int {
1878 name := if f.name == '' { 'fn ${t.fn_type_source_signature(f)}' } else { f.name.clone() }
1879 cname := if f.name == '' {
1880 'anon_fn_${t.fn_type_signature(f)}'
1881 } else {
1882 util.no_dots(f.name.clone()).replace_each(fn_type_escape_seq)
1883 }
1884 anon := f.name == '' || is_anon
1885 existing_idx := t.type_idxs[name]
1886 if existing_idx > 0 {
1887 mut existing_sym := t.type_symbols[existing_idx]
1888 if existing_sym.kind != .placeholder {
1889 if mut existing_sym.info is FnType && !has_decl {
1890 existing_sym.info.has_decl = has_decl
1891 }
1892 return existing_idx
1893 }
1894 }
1895 return t.register_sym(
1896 kind: .function
1897 name: name
1898 cname: cname
1899 ngname: strip_generic_params(name)
1900 mod: f.mod
1901 info: FnType{
1902 is_anon: anon
1903 has_decl: has_decl
1904 func: f
1905 }
1906 )
1907}
1908
1909pub fn (mut t Table) find_or_register_generic_inst(parent_typ Type, concrete_types []Type) int {
1910 parent_sym := t.sym(parent_typ)
1911 expected_generic_types := match parent_sym.info {
1912 Struct { parent_sym.info.generic_types.len }
1913 Interface { parent_sym.info.generic_types.len }
1914 SumType { parent_sym.info.generic_types.len }
1915 FnType { parent_sym.info.func.generic_names.len }
1916 else { 0 }
1917 }
1918
1919 if expected_generic_types == 0 || concrete_types.len != expected_generic_types {
1920 return 0
1921 }
1922 base_name := if parent_sym.ngname != '' {
1923 parent_sym.ngname
1924 } else {
1925 strip_generic_params(parent_sym.name)
1926 }
1927 mut inst_name := base_name + '['
1928 mut inst_cname := parent_sym.cname + '_T_'
1929 for i, ct in concrete_types {
1930 ct_sym := t.sym(ct)
1931 if ct.nr_muls() > 0 {
1932 inst_name += '&'.repeat(ct.nr_muls())
1933 inst_cname += '__ptr__'.repeat(ct.nr_muls())
1934 }
1935 inst_name += ct_sym.name
1936 inst_cname += ct_sym.scoped_cname()
1937 if i < concrete_types.len - 1 {
1938 inst_name += ', '
1939 inst_cname += '_T_'
1940 }
1941 }
1942 inst_name += ']'
1943 existing_idx := t.type_idxs[inst_name]
1944 if existing_idx > 0 {
1945 if t.type_symbols[existing_idx].kind == .placeholder {
1946 t.type_symbols[existing_idx].kind = .generic_inst
1947 t.type_symbols[existing_idx].ngname = parent_sym.ngname
1948 t.type_symbols[existing_idx].mod = parent_sym.mod
1949 t.type_symbols[existing_idx].info = GenericInst{
1950 parent_idx: parent_typ.idx()
1951 concrete_types: concrete_types
1952 }
1953 }
1954 return existing_idx
1955 }
1956 return t.register_sym(
1957 kind: .generic_inst
1958 name: inst_name
1959 cname: inst_cname
1960 ngname: parent_sym.ngname
1961 mod: parent_sym.mod
1962 is_pub: parent_sym.is_pub
1963 info: GenericInst{
1964 parent_idx: parent_typ.idx()
1965 concrete_types: concrete_types
1966 }
1967 )
1968}
1969
1970fn (t &Table) generic_fn_inst_name(sym &TypeSymbol, concrete_types []Type) string {
1971 mut name := sym.name + '['
1972 for i, concrete_type in concrete_types {
1973 concrete_sym := t.sym(concrete_type)
1974 if concrete_type.is_ptr() {
1975 name += '&'.repeat(concrete_type.nr_muls())
1976 }
1977 name += concrete_sym.name
1978 if i < concrete_types.len - 1 {
1979 name += ', '
1980 }
1981 }
1982 name += ']'
1983 return name
1984}
1985
1986pub fn (mut t Table) add_placeholder_type(name string, cname string, language Language) int {
1987 mut modname := ''
1988 if name.contains('.') {
1989 modname = name.all_before_last('.')
1990 }
1991 placeholder_sym := TypeSymbol{
1992 kind: .placeholder
1993 name: name
1994 cname: util.no_dots(cname).replace_each(['&', ''])
1995 ngname: strip_generic_params(name)
1996 language: language
1997 mod: modname
1998 is_pub: true
1999 is_builtin: name in builtins
2000 }
2001 return t.register_sym(placeholder_sym)
2002}
2003
2004@[inline]
2005pub fn (t &Table) value_type(typ Type) Type {
2006 sym := t.final_sym(typ)
2007 if typ.has_flag(.variadic) {
2008 // ...string => string
2009 // return typ.clear_flag(.variadic)
2010 array_info := sym.info as Array
2011 return array_info.elem_type
2012 }
2013 if sym.kind == .array {
2014 // Check index type
2015 info := sym.info as Array
2016 return info.elem_type
2017 }
2018 if sym.kind == .array_fixed {
2019 info := sym.info as ArrayFixed
2020 return info.elem_type
2021 }
2022 if sym.kind == .map {
2023 info := sym.info as Map
2024 return info.value_type
2025 }
2026 if sym.kind == .string && typ.is_ptr() {
2027 // (&string)[i] => string
2028 return string_type
2029 }
2030 if sym.kind in [.byteptr, .string] {
2031 return u8_type
2032 }
2033 if typ.is_ptr() {
2034 // byte* => byte
2035 // bytes[0] is a byte, not byte*
2036 return typ.deref()
2037 }
2038 return void_type
2039}
2040
2041pub fn (mut t Table) register_fn_generic_types(fn_name string) {
2042 t.fn_generic_types[fn_name] = [][]Type{}
2043}
2044
2045pub fn (mut t Table) register_fn_concrete_types(fn_name string, types []Type) bool {
2046 if types.len == 0 {
2047 return false
2048 }
2049 mut a := t.fn_generic_types[fn_name] or { return false }
2050 if types in a {
2051 return false
2052 }
2053 a << types
2054 t.fn_generic_types[fn_name] = a
2055 return true
2056}
2057
2058// TODO: there is a bug when casting sumtype the other way if its pointer
2059// so until fixed at least show v (not C) error `x(variant) = y(SumType*)`
2060pub fn (t &Table) sumtype_has_variant(parent Type, variant Type, is_as bool) bool {
2061 parent_sym := t.sym(parent)
2062 if parent_sym.kind == .sum_type {
2063 parent_info := parent_sym.info as SumType
2064 var_sym := t.sym(variant)
2065 match var_sym.kind {
2066 .aggregate {
2067 return t.sumtype_check_aggregate_variant(parent, variant, is_as)
2068 }
2069 .alias {
2070 return t.sumtype_check_alias_variant(parent, variant, is_as)
2071 }
2072 .function {
2073 return t.sumtype_check_function_variant(parent_info, variant, is_as)
2074 }
2075 else {
2076 return t.sumtype_check_variant_in_type(parent_info, variant, is_as)
2077 }
2078 }
2079 }
2080 return false
2081}
2082
2083pub fn (t &Table) sumtype_has_variant_recursive(parent Type, variant Type, is_as bool) bool {
2084 if t.sumtype_has_variant(parent, variant, is_as) {
2085 return true
2086 }
2087 parent_sym := t.sym(parent)
2088 if parent_sym.kind != .sum_type || parent_sym.info !is SumType {
2089 return false
2090 }
2091 parent_info := parent_sym.info as SumType
2092 for parent_variant in parent_info.variants {
2093 if nested_sumtype := t.sumtype_nested_variant_type(parent_variant) {
2094 if t.sumtype_has_variant_recursive(nested_sumtype, variant, is_as) {
2095 return true
2096 }
2097 }
2098 }
2099 return false
2100}
2101
2102pub fn (t &Table) sumtype_matchable_variants(parent Type) []Type {
2103 mut variants := []Type{}
2104 mut seen := map[u32]bool{}
2105 t.collect_sumtype_matchable_variants(parent, mut seen, mut variants)
2106 return variants
2107}
2108
2109pub fn (t &Table) sumtype_missing_variants(parent Type, handled []Type) []Type {
2110 mut missing := []Type{}
2111 mut seen := map[u32]bool{}
2112 t.collect_sumtype_missing_variants(parent, handled, mut seen, mut missing)
2113 return missing
2114}
2115
2116fn (t &Table) collect_sumtype_matchable_variants(parent Type, mut seen map[u32]bool, mut variants []Type) {
2117 parent_sym := t.sym(parent)
2118 if parent_sym.kind != .sum_type || parent_sym.info !is SumType {
2119 return
2120 }
2121 parent_info := parent_sym.info as SumType
2122 for variant in parent_info.variants {
2123 if u32(variant) !in seen {
2124 seen[u32(variant)] = true
2125 variants << variant
2126 }
2127 if nested_sumtype := t.sumtype_nested_variant_type(variant) {
2128 t.collect_sumtype_matchable_variants(nested_sumtype, mut seen, mut variants)
2129 }
2130 }
2131}
2132
2133fn (t &Table) collect_sumtype_missing_variants(parent Type, handled []Type, mut seen map[u32]bool, mut missing []Type) {
2134 if t.sumtype_variant_is_handled(parent, handled) {
2135 return
2136 }
2137 if nested_sumtype := t.sumtype_nested_variant_type(parent) {
2138 nested_sym := t.sym(nested_sumtype)
2139 if nested_sym.kind == .sum_type && nested_sym.info is SumType {
2140 nested_info := nested_sym.info as SumType
2141 for variant in nested_info.variants {
2142 if t.sumtype_variant_is_handled(variant, handled) {
2143 continue
2144 }
2145 if nested_variant := t.sumtype_nested_variant_type(variant) {
2146 t.collect_sumtype_missing_variants(nested_variant, handled, mut seen, mut
2147 missing)
2148 } else if u32(variant) !in seen {
2149 seen[u32(variant)] = true
2150 missing << variant
2151 }
2152 }
2153 return
2154 }
2155 }
2156 if u32(parent) !in seen {
2157 seen[u32(parent)] = true
2158 missing << parent
2159 }
2160}
2161
2162fn (t &Table) sumtype_variant_is_handled(variant Type, handled []Type) bool {
2163 for handled_variant in handled {
2164 if t.same_sumtype_variant(variant, handled_variant, true) {
2165 return true
2166 }
2167 }
2168 return false
2169}
2170
2171fn (t &Table) same_sumtype_variant(expected Type, got Type, is_as bool) bool {
2172 return expected.idx() == got.idx() && expected.has_flag(.option) == got.has_flag(.option)
2173 && (!is_as || expected.nr_muls() == got.nr_muls())
2174}
2175
2176fn (t &Table) sumtype_nested_variant_type(variant Type) ?Type {
2177 nested_sumtype := t.fully_unaliased_type(variant)
2178 if t.sym(nested_sumtype).kind == .sum_type {
2179 return nested_sumtype
2180 }
2181 return none
2182}
2183
2184fn (t &Table) sumtype_check_function_variant(parent_info SumType, variant Type, is_as bool) bool {
2185 variant_fn := (t.sym(variant).info as FnType).func
2186 variant_fn_sig := t.fn_type_source_signature(variant_fn)
2187
2188 for v in parent_info.variants {
2189 v_sym := t.sym(v)
2190 if v_sym.info is FnType {
2191 if t.fn_type_source_signature(v_sym.info.func) == variant_fn_sig
2192 && (!is_as || v.nr_muls() == variant.nr_muls()) {
2193 return true
2194 }
2195 }
2196 }
2197 return false
2198}
2199
2200fn (t &Table) sumtype_check_variant_in_type(parent_info SumType, variant Type, is_as bool) bool {
2201 for v in parent_info.variants {
2202 if t.same_sumtype_variant(v, variant, is_as) {
2203 return true
2204 }
2205 }
2206 if !is_as {
2207 for v in parent_info.variants {
2208 if t.can_implicit_array_cast(variant, v) {
2209 return true
2210 }
2211 }
2212 }
2213 return false
2214}
2215
2216fn (t &Table) sumtype_check_aggregate_variant(parent_type Type, aggregate_type &Type, is_as bool) bool {
2217 aggregate_sym := t.sym(aggregate_type).info as Aggregate
2218 for var_type in aggregate_sym.types {
2219 if !t.sumtype_has_variant(parent_type, var_type, is_as) {
2220 return false
2221 }
2222 }
2223 return true
2224}
2225
2226fn (t &Table) sumtype_check_alias_variant(parent_type Type, alias_type Type, is_as bool) bool {
2227 parent_sym := t.sym(parent_type).info as SumType
2228 if !t.sumtype_check_variant_in_type(parent_sym, alias_type, is_as) {
2229 alias_info := t.sym(alias_type).info as Alias
2230 // The alias is an alias or of the same sumtype parent, or one
2231 // of the SumType variant. e.g: alias of another sum type.
2232 // https://github.com/vlang/v/issues/14029
2233 return parent_type == alias_info.parent_type
2234 || t.sumtype_has_variant(parent_type, alias_info.parent_type, is_as)
2235 }
2236 // the alias_type is inside one of the variant of the sum type
2237 return true
2238}
2239
2240pub fn (t &Table) is_sumtype_or_in_variant(parent Type, typ Type) bool {
2241 if typ == 0 {
2242 return false
2243 }
2244 if t.sym(typ).kind == .sum_type && parent.idx() == typ.idx()
2245 && parent.nr_muls() == typ.nr_muls() {
2246 return true
2247 }
2248 return t.sumtype_has_variant(parent, typ, false)
2249}
2250
2251// can_implicit_array_cast reports whether `got` can be converted to `expected`
2252// by boxing each array element into the expected interface or sum type.
2253pub fn (t &Table) can_implicit_array_cast(got Type, expected Type) bool {
2254 if got == 0 || expected == 0 || got == expected {
2255 return false
2256 }
2257 got_idx := got.idx()
2258 expected_idx := expected.idx()
2259 if got_idx == expected_idx {
2260 return false
2261 }
2262 if got_idx > 0 && got_idx < t.type_symbols.len && expected_idx > 0
2263 && expected_idx < t.type_symbols.len {
2264 got_kind := t.type_symbols[got_idx].kind
2265 expected_kind := t.type_symbols[expected_idx].kind
2266 if (got_kind != .array && got_kind != .alias)
2267 || (expected_kind != .array && expected_kind != .alias) {
2268 return false
2269 }
2270 }
2271 got_unaliased := t.unaliased_type(got)
2272 expected_unaliased := t.unaliased_type(expected)
2273 got_sym := t.final_sym(got_unaliased)
2274 expected_sym := t.final_sym(expected_unaliased)
2275 if got_sym.kind != .array || expected_sym.kind != .array {
2276 return false
2277 }
2278 got_info := got_sym.info as Array
2279 expected_info := expected_sym.info as Array
2280 if got_info.nr_dims != expected_info.nr_dims {
2281 return false
2282 }
2283 got_elem_type := t.unaliased_type(got_info.elem_type)
2284 expected_elem_type := t.unaliased_type(expected_info.elem_type)
2285 if got_elem_type == expected_elem_type {
2286 return false
2287 }
2288 match t.final_sym(expected_elem_type).kind {
2289 .sum_type {
2290 return t.is_sumtype_or_in_variant(expected_elem_type, mktyp(got_elem_type))
2291 }
2292 .interface {
2293 return t.does_type_implement_interface(got_elem_type, expected_elem_type)
2294 }
2295 else {
2296 return false
2297 }
2298 }
2299}
2300
2301@[inline]
2302pub fn (t &Table) is_interface_var(var ScopeObject) bool {
2303 return var is Var && var.orig_type != 0 && t.sym(var.orig_type).kind == .interface
2304 && t.sym(var.smartcasts.last()).kind != .interface
2305}
2306
2307@[inline]
2308pub fn (t &Table) is_interface_smartcast(var ScopeObject) bool {
2309 return var is Var && var.orig_type != 0 && t.sym(var.orig_type).kind == .interface
2310 && var.smartcasts.len > 0
2311}
2312
2313// only used for debugging V compiler type bugs
2314pub fn (t &Table) known_type_names() []string {
2315 mut res := []string{cap: t.type_idxs.len}
2316 for _, idx in t.type_idxs {
2317 typ := idx_to_type(idx)
2318 // Skip `int_literal_type_idx` and `float_literal_type_idx` because they shouldn't be visible to the User.
2319 if idx !in [0, int_literal_type_idx, float_literal_type_idx] && t.known_type_idx(typ) {
2320 tsym := t.sym(typ)
2321 if tsym.kind !in [.function, .chan] {
2322 res << t.type_to_str(typ)
2323 } else if tsym.info is Chan && t.sym(tsym.info.elem_type).kind != .placeholder {
2324 res << t.type_to_str(tsym.info.elem_type)
2325 }
2326 }
2327 }
2328 return res
2329}
2330
2331// 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.
2332// The given name consists of module and name (`mod.Name`).
2333// It ignores children that are references, including aliases to references.
2334pub fn (t &Table) has_deep_child_no_ref(ts &TypeSymbol, name string) bool {
2335 mut seen := map[string]bool{}
2336 return t.has_deep_child_no_ref_in_sym(ts, name, mut seen)
2337}
2338
2339fn (t &Table) has_deep_child_no_ref_in_sym(ts &TypeSymbol, name string, mut seen map[string]bool) bool {
2340 if ts.kind == .placeholder || ts.name in seen {
2341 return false
2342 }
2343 seen[ts.name] = true
2344 match ts.info {
2345 Struct {
2346 for field in ts.info.fields {
2347 sym := t.sym(field.typ)
2348 if !field.typ.is_ptr() && !field.typ.has_flag(.option) && (sym.name == name
2349 || (sym.info is Struct && t.has_deep_child_no_ref_in_sym(sym, name, mut seen))) {
2350 return true
2351 }
2352 }
2353 for embed in ts.info.embeds {
2354 if t.has_deep_child_no_ref_in_embed(embed, name, mut seen) {
2355 return true
2356 }
2357 }
2358 }
2359 else {}
2360 }
2361
2362 return false
2363}
2364
2365fn (t &Table) has_deep_child_no_ref_in_embed(typ Type, name string, mut seen map[string]bool) bool {
2366 unaliased_typ := t.unaliased_type(typ)
2367 if unaliased_typ.is_ptr() || unaliased_typ.has_flag(.option) {
2368 return false
2369 }
2370 sym := t.sym(unaliased_typ)
2371 if sym.name == name {
2372 return true
2373 }
2374 return t.has_deep_child_no_ref_in_sym(sym, name, mut seen)
2375}
2376
2377// complete_interface_check does a MxN check for all M interfaces vs all N types, to determine what types implement what interfaces.
2378// It short circuits most checks when an interface can not possibly be implemented by a type.
2379pub fn (mut t Table) complete_interface_check() {
2380 util.timing_start(@METHOD)
2381 defer {
2382 util.timing_measure(@METHOD)
2383 }
2384 for tk, mut tsym in t.type_symbols {
2385 tk_typ := idx_to_type(tk)
2386 if tsym.kind != .struct {
2387 continue
2388 }
2389 for _, mut idecl in t.interfaces {
2390 if idecl.typ == 0 {
2391 continue
2392 }
2393 // empty interface only generate type cast functions of the current module
2394 if idecl.methods.len == 0 && idecl.fields.len == 0 && tsym.mod != t.sym(idecl.typ).mod {
2395 continue
2396 }
2397 if t.does_type_implement_interface(tk_typ, idecl.typ) {
2398 $if trace_types_implementing_each_interface ? {
2399 eprintln('>>> tsym.mod: ${tsym.mod} | tsym.name: ${tsym.name} | tk: ${tk} | idecl.name: ${idecl.name} | idecl.typ: ${idecl.typ}')
2400 }
2401 if idecl.name !in t.iface_types {
2402 t.iface_types[idecl.name] = []Type{}
2403 }
2404 t.iface_types[idecl.name] << tk_typ
2405 }
2406 }
2407 }
2408 // For empty interfaces, propagate concrete types from all other interfaces
2409 // into the empty interface's variant list. Empty interfaces can be assigned
2410 // from any interface (e.g. `IError` -> `EmptyIface{}`); at runtime the empty
2411 // interface will hold the source interface's dynamic type, so the empty
2412 // interface must have cast functions for each possible concrete variant.
2413 mut empty_iface_typs := []Type{}
2414 for _, idecl in t.interfaces {
2415 if idecl.typ == 0 {
2416 continue
2417 }
2418 if idecl.methods.len == 0 && idecl.fields.len == 0 {
2419 empty_iface_typs << idecl.typ
2420 }
2421 }
2422 for iface_typ in empty_iface_typs {
2423 mut iface_sym := t.sym(iface_typ)
2424 if iface_sym.info !is Interface {
2425 continue
2426 }
2427 mut iface_info := iface_sym.info as Interface
2428 mut collected_types := []Type{}
2429 mut seen_cnames := map[string]bool{}
2430 for existing in iface_info.types {
2431 existing_sym := t.sym(mktyp(existing))
2432 seen_cnames[existing_sym.cname] = true
2433 }
2434 for _, other_sym in t.type_symbols {
2435 if other_sym.kind != .interface || other_sym.idx == iface_sym.idx {
2436 continue
2437 }
2438 if other_sym.info !is Interface {
2439 continue
2440 }
2441 other_info := other_sym.info as Interface
2442 for variant in other_info.types {
2443 mk_variant := mktyp(variant)
2444 variant_sym := t.sym(mk_variant)
2445 if variant_sym.kind != .struct {
2446 continue
2447 }
2448 if variant_sym.cname in seen_cnames {
2449 continue
2450 }
2451 seen_cnames[variant_sym.cname] = true
2452 collected_types << mk_variant
2453 }
2454 }
2455 if collected_types.len > 0 {
2456 iface_info.types << collected_types
2457 iface_sym.info = iface_info
2458 if iface_sym.name !in t.iface_types {
2459 t.iface_types[iface_sym.name] = []Type{}
2460 }
2461 mut target_variants := t.iface_types[iface_sym.name].clone()
2462 for variant in collected_types {
2463 if variant !in target_variants {
2464 target_variants << variant
2465 }
2466 }
2467 t.iface_types[iface_sym.name] = target_variants
2468 }
2469 }
2470}
2471
2472// bitsize_to_type returns a type corresponding to the bit_size
2473// Examples:
2474//
2475// `8 > i8`
2476//
2477// `32 > int`
2478//
2479// `123 > panic()`
2480//
2481// `128 > [16]u8`
2482//
2483// `608 > [76]u8`
2484pub fn (mut t Table) bitsize_to_type(bit_size int) Type {
2485 match bit_size {
2486 8 {
2487 return i8_type
2488 }
2489 16 {
2490 return i16_type
2491 }
2492 32 {
2493 return i32_type
2494 }
2495 64 {
2496 return i64_type
2497 }
2498 else {
2499 if bit_size % 8 != 0 { // there is no way to do `i2131(32)` so this should never be reached
2500 t.panic('table.bitsize_to_type: compiler bug: bitsizes must be multiples of 8, but passed bit_size is ${bit_size}')
2501 }
2502 return new_type(t.find_or_register_array_fixed(u8_type, bit_size / 8, empty_expr, false))
2503 }
2504 }
2505}
2506
2507pub fn (t &Table) interface_inherits_interface(typ Type, inter_typ Type) bool {
2508 if typ.idx() == inter_typ.idx() {
2509 return true
2510 }
2511 sym := t.sym(typ)
2512 if sym.kind != .interface || sym.info !is Interface {
2513 return false
2514 }
2515 info := sym.info as Interface
2516 for embed in info.embeds {
2517 if embed.idx() == inter_typ.idx() || t.interface_inherits_interface(embed, inter_typ) {
2518 return true
2519 }
2520 }
2521 if info.parent_type != 0 && info.parent_type.idx() != 0 && info.parent_type != typ {
2522 parent_sym := t.sym(info.parent_type)
2523 if parent_sym.kind == .interface
2524 && t.interface_inherits_interface(info.parent_type, inter_typ) {
2525 return true
2526 }
2527 }
2528 return false
2529}
2530
2531pub fn (t &Table) does_type_implement_interface(typ Type, inter_typ Type) bool {
2532 if typ.idx() == inter_typ.idx() {
2533 // same type -> already casted to the interface
2534 return true
2535 }
2536 if inter_typ.idx() == error_type_idx && typ.idx() == none_type_idx {
2537 // `none` "implements" the Error interface
2538 return true
2539 }
2540 sym := t.sym(typ)
2541 if sym.language != .v {
2542 return false
2543 }
2544 // generic struct don't generate cast interface fn
2545 if sym.info is Struct {
2546 if sym.info.is_generic {
2547 return false
2548 }
2549 }
2550 mut inter_sym := t.sym(inter_typ)
2551 if sym.kind == .interface && inter_sym.kind == .interface {
2552 inter_info := inter_sym.info as Interface
2553 if inter_info.methods.len == 0 && inter_info.fields.len == 0 && inter_info.embeds.len == 0 {
2554 return true
2555 }
2556 if !t.interface_inherits_interface(typ, inter_typ) {
2557 return false
2558 }
2559 }
2560 if mut inter_sym.info is Interface {
2561 attrs := unsafe { t.interfaces[inter_typ].attrs }
2562 for attr in attrs {
2563 if attr.name == 'single_impl' {
2564 return false
2565 }
2566 }
2567 // do not check the same type more than once
2568 for tt in inter_sym.info.types {
2569 if tt.idx() == typ.idx() {
2570 return true
2571 }
2572 }
2573 // verify methods
2574 for imethod in inter_sym.info.methods {
2575 if t.is_compatible_auto_str_method(imethod) && typ.nr_muls() == 0 && sym.kind == .char {
2576 return false
2577 }
2578 if method := t.find_method_with_embeds(sym, imethod.name) {
2579 msg := t.is_same_method(imethod, method)
2580 if msg.len > 0 {
2581 return false
2582 }
2583 continue
2584 }
2585 match sym.info {
2586 SumType, Struct, Interface {
2587 if method := sym.find_method_with_generic_parent(imethod.name) {
2588 msg := t.is_same_method(imethod, method)
2589 if msg.len > 0 {
2590 return false
2591 }
2592 continue
2593 }
2594 }
2595 else {}
2596 }
2597
2598 if t.type_has_implicit_str_method(typ, imethod) {
2599 continue
2600 }
2601 return false
2602 }
2603 // verify fields
2604 for ifield in inter_sym.info.fields {
2605 if ifield.typ == voidptr_type || ifield.typ == nil_type {
2606 // Allow `voidptr` fields in interfaces for now. (for example
2607 // to enable .db check in veb)
2608 if t.struct_has_field(sym, ifield.name) {
2609 continue
2610 } else {
2611 return false
2612 }
2613 }
2614 if field := t.find_field_with_embeds(sym, ifield.name) {
2615 if ifield.typ != field.typ {
2616 return false
2617 } else if ifield.is_mut && !(field.is_mut || field.is_global) {
2618 return false
2619 }
2620 continue
2621 }
2622 return false
2623 }
2624 if sym.kind !in [.interface, .aggregate] && typ != voidptr_type && typ != nil_type
2625 && typ != none_type && !inter_sym.info.types.contains(typ) {
2626 inter_sym.info.types << typ
2627 }
2628 if !inter_sym.info.types.contains(voidptr_type) {
2629 inter_sym.info.types << voidptr_type
2630 }
2631 return true
2632 }
2633 return false
2634}
2635
2636pub fn (mut t Table) convert_generic_static_type_name(fn_name string, generic_names []string, concrete_types []Type) (Type, string) {
2637 if index := fn_name.index('__static__') {
2638 if index > 0 {
2639 generic_name := fn_name[0..index]
2640 valid_generic := util.is_generic_type_name(generic_name)
2641 && generic_name in generic_names
2642 if valid_generic {
2643 name_type := t.find_type(generic_name).set_flag(.generic)
2644 if typ := t.convert_generic_type(name_type, generic_names, concrete_types) {
2645 return name_type, '${t.type_to_str(typ)}${fn_name[index..]}'
2646 }
2647 }
2648 }
2649 }
2650 return void_type, fn_name
2651}
2652
2653// convert_generic_type convert generics to real types (T => int) or other generics type.
2654pub fn (mut t Table) convert_generic_type(generic_type Type, generic_names []string, to_types []Type) ?Type {
2655 if generic_names.len != to_types.len {
2656 return none
2657 }
2658 type_idx := generic_type.idx()
2659 if type_idx == 0 || type_idx >= t.type_symbols.len {
2660 return none
2661 }
2662 mut sym := t.sym(generic_type)
2663 if sym.name in generic_names {
2664 index := generic_names.index(sym.name)
2665 if index >= to_types.len {
2666 return none
2667 }
2668 typ := to_types[index]
2669 if typ == 0 || typ.idx() >= t.type_symbols.len {
2670 return none
2671 }
2672 mut rtyp := typ.derive_add_muls(generic_type)
2673 if typ.has_flag(.generic) {
2674 rtyp = rtyp.set_flag(.generic)
2675 } else {
2676 rtyp = rtyp.clear_flag(.generic)
2677 }
2678 if !generic_type.has_flag(.result) && typ.has_flag(.option) {
2679 rtyp = rtyp.set_flag(.option)
2680 if generic_type.is_ptr() {
2681 rtyp = rtyp.set_flag(.option_mut_param_t)
2682 }
2683 }
2684 resolved_typ_sym := t.sym(t.fully_unaliased_type(typ))
2685 if resolved_typ_sym.info is FnType && typ.has_flag(.shared_f) {
2686 rtyp = rtyp.set_flag(.shared_f)
2687 }
2688 if resolved_typ_sym.info is FnType && typ.has_flag(.atomic_f) {
2689 rtyp = rtyp.set_flag(.atomic_f)
2690 }
2691 return rtyp
2692 }
2693 match mut sym.info {
2694 Array {
2695 dims, elem_type := t.get_array_dims(sym.info)
2696 if typ := t.convert_generic_type(elem_type, generic_names, to_types) {
2697 idx := t.find_or_register_array_with_dims(typ, dims)
2698 if typ.has_flag(.generic) {
2699 return new_type(idx).derive_add_muls(generic_type).set_flag(.generic)
2700 } else {
2701 return new_type(idx).derive_add_muls(generic_type).clear_flag(.generic)
2702 }
2703 }
2704 }
2705 ArrayFixed {
2706 if typ := t.convert_generic_type(sym.info.elem_type, generic_names, to_types) {
2707 idx := t.find_or_register_array_fixed(typ, sym.info.size, None{}, false)
2708 if typ.has_flag(.generic) {
2709 return new_type(idx).derive_add_muls(generic_type).set_flag(.generic)
2710 } else {
2711 return new_type(idx).derive_add_muls(generic_type).clear_flag(.generic)
2712 }
2713 }
2714 }
2715 Chan {
2716 if typ := t.convert_generic_type(sym.info.elem_type, generic_names, to_types) {
2717 idx := t.find_or_register_chan(typ, typ.nr_muls() > 0)
2718 if typ.has_flag(.generic) {
2719 return new_type(idx).derive_add_muls(generic_type).set_flag(.generic)
2720 } else {
2721 return new_type(idx).derive_add_muls(generic_type).clear_flag(.generic)
2722 }
2723 }
2724 }
2725 Thread {
2726 if typ := t.convert_generic_type(sym.info.return_type, generic_names, to_types) {
2727 idx := t.find_or_register_thread(typ)
2728 if typ.has_flag(.generic) {
2729 return new_type(idx).derive_add_muls(generic_type).set_flag(.generic)
2730 } else {
2731 return new_type(idx).derive_add_muls(generic_type).clear_flag(.generic)
2732 }
2733 }
2734 }
2735 FnType {
2736 mut func := sym.info.func
2737 mut has_generic := false
2738 return_type_sym := t.sym(func.return_type)
2739 if func.return_type.has_flag(.generic)
2740 || t.generic_type_names(func.return_type).len > 0
2741 || (return_type_sym.kind == .generic_inst
2742 && (return_type_sym.info as GenericInst).concrete_types.any(it.has_flag(.generic))) {
2743 if typ := t.convert_generic_type(func.return_type, generic_names, to_types) {
2744 func.return_type = typ
2745 } else {
2746 func.return_type = t.unwrap_generic_type_ex(func.return_type, generic_names,
2747 to_types, true)
2748 }
2749 if func.return_type.has_flag(.generic)
2750 || t.generic_type_names(func.return_type).len > 0 {
2751 has_generic = true
2752 }
2753 }
2754 func.params = func.params.clone()
2755 for mut param in func.params {
2756 orig_param_type := param.typ
2757 if typ := t.convert_generic_param_type(param, generic_names, to_types) {
2758 param.typ = typ
2759 }
2760 if t.sym(param.typ).kind == .placeholder {
2761 param.typ =
2762 t.unwrap_generic_type_ex(orig_param_type, generic_names, to_types, true)
2763 }
2764 if param.typ.has_flag(.generic) || t.generic_type_names(param.typ).len > 0 {
2765 has_generic = true
2766 }
2767 if param.orig_typ.has_flag(.generic) || t.generic_type_names(param.orig_typ).len > 0 {
2768 if otyp := t.convert_generic_type(param.orig_typ, generic_names, to_types) {
2769 param.orig_typ = otyp
2770 } else {
2771 param.orig_typ = t.unwrap_generic_type_ex(param.orig_typ, generic_names,
2772 to_types, true)
2773 }
2774 }
2775 }
2776 if !sym.info.is_anon && !has_generic {
2777 inst_name := t.generic_fn_inst_name(sym, to_types)
2778 idx := t.find_type_idx(inst_name)
2779 if idx > 0 {
2780 return new_type(idx).derive_add_muls(generic_type).clear_flag(.generic)
2781 }
2782 }
2783 func.name = ''
2784 func.generic_names = []
2785 idx := t.find_or_register_fn_type(func, true, false)
2786 if has_generic {
2787 return new_type(idx).derive_add_muls(generic_type).set_flag(.generic)
2788 } else {
2789 return new_type(idx).derive_add_muls(generic_type).clear_flag(.generic)
2790 }
2791 }
2792 GenericInst {
2793 mut concrete_types := sym.info.concrete_types.clone()
2794 mut type_changed := false
2795 for i, concrete_type in concrete_types {
2796 if typ := t.convert_generic_type(concrete_type, generic_names, to_types) {
2797 concrete_types[i] = typ
2798 type_changed = true
2799 }
2800 }
2801 if type_changed {
2802 idx := t.find_or_register_generic_inst(new_type(sym.info.parent_idx),
2803 concrete_types)
2804 if idx > 0 {
2805 return new_type(idx).derive_add_muls(generic_type).clear_flag(.generic)
2806 }
2807 }
2808 }
2809 MultiReturn {
2810 mut types := []Type{}
2811 mut type_changed := false
2812 for ret_type in sym.info.types {
2813 if typ := t.convert_generic_type(ret_type, generic_names, to_types) {
2814 types << typ
2815 type_changed = true
2816 } else {
2817 types << ret_type
2818 }
2819 }
2820 if type_changed {
2821 idx := t.find_or_register_multi_return(types)
2822 if types.any(it.has_flag(.generic)) {
2823 return new_type(idx).derive_add_muls(generic_type).set_flag(.generic)
2824 } else {
2825 return new_type(idx).derive_add_muls(generic_type).clear_flag(.generic)
2826 }
2827 }
2828 }
2829 Map {
2830 mut type_changed := false
2831 mut unwrapped_key_type := sym.info.key_type
2832 mut unwrapped_value_type := sym.info.value_type
2833 if typ := t.convert_generic_type(sym.info.key_type, generic_names, to_types) {
2834 unwrapped_key_type = typ
2835 type_changed = true
2836 }
2837 if typ := t.convert_generic_type(sym.info.value_type, generic_names, to_types) {
2838 unwrapped_value_type = typ
2839 type_changed = true
2840 }
2841 if type_changed {
2842 // map[Type]T where T is an alias to map type
2843 if to_types.len == 1 && sym.info.value_type.has_flag(.generic)
2844 && t.type_kind(to_types[0]) == .alias && t.final_sym(to_types[0]).kind == .map {
2845 return unwrapped_value_type
2846 }
2847 idx := t.find_or_register_map(unwrapped_key_type, unwrapped_value_type)
2848 if unwrapped_key_type.has_flag(.generic) || unwrapped_value_type.has_flag(.generic) {
2849 return new_type(idx).derive_add_muls(generic_type).set_flag(.generic)
2850 } else {
2851 return new_type(idx).derive_add_muls(generic_type).clear_flag(.generic)
2852 }
2853 }
2854 }
2855 Struct, Interface, SumType {
2856 if sym.info.is_generic {
2857 mut nrt := '${sym.name}['
2858 mut rnrt := '${sym.rname}['
2859 mut cnrt := '${sym.cname}_T_'
2860 mut converted_types := []Type{}
2861 mut t_generic_names := generic_names.clone()
2862 mut t_to_types := to_types.clone()
2863 mut has_unresolved_generic := false
2864 mut type_changed := false
2865 if sym.generic_types.len > 0 && sym.generic_types.len == sym.info.generic_types.len
2866 && sym.generic_types != sym.info.generic_types {
2867 t_generic_names = sym.info.generic_types.map(t.sym(it).name)
2868 t_to_types = []
2869 for t_typ in sym.generic_types {
2870 if !t_typ.has_flag(.generic) {
2871 t_to_types << t_typ
2872 } else {
2873 if tt := t.convert_generic_type(t_typ, generic_names, to_types) {
2874 t_to_types << tt
2875 }
2876 }
2877 }
2878 }
2879 for i in 0 .. sym.info.generic_types.len {
2880 if ct := t.convert_generic_type(sym.info.generic_types[i], t_generic_names,
2881 t_to_types)
2882 {
2883 converted_types << ct
2884 gts := t.sym(ct)
2885 if ct != sym.info.generic_types[i] {
2886 type_changed = true
2887 }
2888 if ct.is_ptr() {
2889 nrt += '&'.repeat(ct.nr_muls())
2890 cnrt += '__ptr__'.repeat(ct.nr_muls())
2891 }
2892 nrt += gts.name
2893 rnrt += gts.name
2894 cnrt += gts.scoped_cname()
2895 if i != sym.info.generic_types.len - 1 {
2896 nrt += ', '
2897 rnrt += ', '
2898 cnrt += '_T_'
2899 }
2900 if ct.has_flag(.generic) {
2901 has_unresolved_generic = true
2902 }
2903 } else {
2904 return none
2905 }
2906 }
2907 if type_changed && converted_types.len == sym.info.generic_types.len {
2908 idx := t.find_or_register_generic_inst(new_type(type_idx), converted_types)
2909 if idx > 0 {
2910 return if has_unresolved_generic {
2911 new_type(idx).derive_add_muls(generic_type).set_flag(.generic)
2912 } else {
2913 new_type(idx).derive_add_muls(generic_type).clear_flag(.generic)
2914 }
2915 }
2916 }
2917 nrt += ']'
2918 rnrt += ']'
2919 mut idx := t.type_idxs[nrt]
2920 if idx == 0 {
2921 idx = t.type_idxs[rnrt]
2922 if idx == 0 {
2923 idx = t.add_placeholder_type(nrt, cnrt, .v)
2924 }
2925 }
2926 return if has_unresolved_generic {
2927 new_type(idx).derive_add_muls(generic_type).set_flag(.generic)
2928 } else {
2929 new_type(idx).derive_add_muls(generic_type).clear_flag(.generic)
2930 }
2931 }
2932 }
2933 UnknownTypeInfo {
2934 if sym.name.contains('[') && sym.name.contains(']') {
2935 base_name := sym.name.all_before_last('[')
2936 generic_part := sym.name.all_after_last('[').trim_right(']')
2937 mut converted_args := []string{}
2938 mut has_generic := false
2939 mut changed := false
2940 args := split_generic_args(generic_part)
2941 for arg in args {
2942 if arg in generic_names {
2943 idx := generic_names.index(arg)
2944 if idx < to_types.len {
2945 converted_type := to_types[idx]
2946 converted_type_str := t.type_to_str(converted_type)
2947 if converted_type_str != arg {
2948 converted_args << converted_type_str
2949 changed = true
2950 if converted_type.has_flag(.generic) {
2951 has_generic = true
2952 }
2953 } else {
2954 converted_args << arg
2955 }
2956 } else {
2957 converted_args << arg
2958 }
2959 } else {
2960 converted_args << arg
2961 }
2962 }
2963 if changed {
2964 new_name := base_name + '[' + converted_args.join(', ') + ']'
2965 mut new_idx := t.type_idxs[new_name]
2966 if new_idx == 0 {
2967 new_idx = t.add_placeholder_type(new_name, util.no_dots(new_name).replace_each([
2968 '[',
2969 '_T_',
2970 ']',
2971 '',
2972 ', ',
2973 '_T_',
2974 ',',
2975 '_T_',
2976 ' ',
2977 '',
2978 ]), sym.language)
2979 }
2980 return if has_generic {
2981 new_type(new_idx).derive_add_muls(generic_type).set_flag(.generic)
2982 } else {
2983 new_type(new_idx).derive_add_muls(generic_type).clear_flag(.generic)
2984 }
2985 }
2986 }
2987 }
2988 else {}
2989 }
2990
2991 return none
2992}
2993
2994fn (mut t Table) lower_mut_param_type(typ Type, orig_typ ...Type) Type {
2995 // When the pointer came from the generic type argument itself (T=&int),
2996 // not from the param signature (&T), we need ref() to add one more level.
2997 orig_was_ptr := orig_typ.len > 0 && orig_typ[0].nr_muls() > 0
2998 mut lowered := if typ.is_ptr() && !orig_was_ptr {
2999 typ.ref()
3000 } else {
3001 typ.set_nr_muls(1)
3002 }
3003 if lowered.has_flag(.option) {
3004 lowered = lowered.set_flag(.option_mut_param_t)
3005 }
3006 return lowered
3007}
3008
3009pub fn (mut t Table) convert_generic_param_type(param Param, generic_names []string, to_types []Type) ?Type {
3010 if param.is_mut && param.orig_typ != 0 && param.orig_typ.has_flag(.generic)
3011 && to_types.all(!it.has_flag(.generic)) {
3012 if typ := t.convert_generic_type(param.orig_typ, generic_names, to_types) {
3013 return t.lower_mut_param_type(typ, param.orig_typ)
3014 }
3015 }
3016 return t.convert_generic_type(param.typ, generic_names, to_types)
3017}
3018
3019// type_contains_placeholder returns true if the given type or any of its inner
3020// generic types resolves to a placeholder (i.e., an undefined/unknown type).
3021pub fn (t &Table) type_contains_placeholder(typ Type) bool {
3022 sym := t.sym(typ)
3023 if sym.kind == .placeholder {
3024 return true
3025 }
3026 return match sym.info {
3027 Array {
3028 t.type_contains_placeholder(sym.info.elem_type)
3029 }
3030 ArrayFixed {
3031 t.type_contains_placeholder(sym.info.elem_type)
3032 }
3033 Map {
3034 t.type_contains_placeholder(sym.info.key_type)
3035 || t.type_contains_placeholder(sym.info.value_type)
3036 }
3037 SumType {
3038 sym.info.concrete_types.any(t.type_contains_placeholder(it))
3039 }
3040 Struct {
3041 sym.info.concrete_types.any(t.type_contains_placeholder(it))
3042 }
3043 else {
3044 false
3045 }
3046 }
3047}
3048
3049pub fn (mut t Table) unwrap_generic_param_type(param Param, generic_names []string, concrete_types []Type) Type {
3050 if param.is_mut && param.orig_typ != 0 && param.orig_typ.has_flag(.generic)
3051 && concrete_types.all(!it.has_flag(.generic)) {
3052 return t.lower_mut_param_type(t.unwrap_generic_type(param.orig_typ, generic_names,
3053 concrete_types))
3054 }
3055 return t.unwrap_generic_type(param.typ, generic_names, concrete_types)
3056}
3057
3058// convert_generic_expr_type resolves generic placeholders stored inside expression metadata.
3059// Some synthesized concrete types use default expressions directly from type symbols, so these
3060// types need to be specialized eagerly instead of relying on a later checker pass.
3061fn (mut t Table) convert_generic_expr_type(typ Type, generic_names []string, concrete_types []Type) Type {
3062 if typ == 0 {
3063 return typ
3064 }
3065 return t.convert_generic_type(typ, generic_names, concrete_types) or { typ }
3066}
3067
3068fn (mut t Table) convert_generic_expr_types(types []Type, generic_names []string, concrete_types []Type) []Type {
3069 if types.len == 0 {
3070 return types
3071 }
3072 mut resolved := []Type{len: types.len}
3073 for i, typ in types {
3074 resolved[i] = t.convert_generic_expr_type(typ, generic_names, concrete_types)
3075 }
3076 return resolved
3077}
3078
3079fn (mut t Table) convert_generic_nested_expr_types(types [][]Type, generic_names []string, concrete_types []Type) [][]Type {
3080 if types.len == 0 {
3081 return types
3082 }
3083 mut resolved := [][]Type{len: types.len}
3084 for i, inner in types {
3085 resolved[i] = t.convert_generic_expr_types(inner, generic_names, concrete_types)
3086 }
3087 return resolved
3088}
3089
3090fn (mut t Table) convert_generic_call_args(args []CallArg, generic_names []string, concrete_types []Type) []CallArg {
3091 if args.len == 0 {
3092 return args
3093 }
3094 mut resolved := []CallArg{len: args.len}
3095 for i, arg in args {
3096 resolved[i] = CallArg{
3097 ...arg
3098 expr: t.convert_generic_default_expr(arg.expr, generic_names, concrete_types)
3099 typ: t.convert_generic_expr_type(arg.typ, generic_names, concrete_types)
3100 }
3101 }
3102 return resolved
3103}
3104
3105fn (mut t Table) convert_generic_struct_init_fields(fields []StructInitField, generic_names []string, concrete_types []Type) []StructInitField {
3106 if fields.len == 0 {
3107 return fields
3108 }
3109 mut resolved := []StructInitField{len: fields.len}
3110 for i, field in fields {
3111 resolved[i] = StructInitField{
3112 ...field
3113 expr: t.convert_generic_default_expr(field.expr, generic_names, concrete_types)
3114 typ: t.convert_generic_expr_type(field.typ, generic_names, concrete_types)
3115 expected_type: t.convert_generic_expr_type(field.expected_type, generic_names,
3116 concrete_types)
3117 parent_type: t.convert_generic_expr_type(field.parent_type, generic_names,
3118 concrete_types)
3119 }
3120 }
3121 return resolved
3122}
3123
3124fn (mut t Table) convert_generic_default_expr(expr Expr, generic_names []string, concrete_types []Type) Expr {
3125 match expr {
3126 ArrayDecompose {
3127 return Expr(ArrayDecompose{
3128 ...expr
3129 expr: t.convert_generic_default_expr(expr.expr, generic_names, concrete_types)
3130 expr_type: t.convert_generic_expr_type(expr.expr_type, generic_names,
3131 concrete_types)
3132 arg_type: t.convert_generic_expr_type(expr.arg_type, generic_names, concrete_types)
3133 })
3134 }
3135 ArrayInit {
3136 mut exprs := []Expr{cap: expr.exprs.len}
3137 for node in expr.exprs {
3138 exprs << t.convert_generic_default_expr(node, generic_names, concrete_types)
3139 }
3140 return Expr(ArrayInit{
3141 ...expr
3142 exprs: exprs
3143 len_expr: t.convert_generic_default_expr(expr.len_expr, generic_names,
3144 concrete_types)
3145 cap_expr: t.convert_generic_default_expr(expr.cap_expr, generic_names,
3146 concrete_types)
3147 init_expr: t.convert_generic_default_expr(expr.init_expr, generic_names,
3148 concrete_types)
3149 expr_types: t.convert_generic_expr_types(expr.expr_types, generic_names,
3150 concrete_types)
3151 elem_type: t.convert_generic_expr_type(expr.elem_type, generic_names,
3152 concrete_types)
3153 init_type: t.convert_generic_expr_type(expr.init_type, generic_names,
3154 concrete_types)
3155 typ: t.convert_generic_expr_type(expr.typ, generic_names, concrete_types)
3156 alias_type: t.convert_generic_expr_type(expr.alias_type, generic_names,
3157 concrete_types)
3158 })
3159 }
3160 AsCast {
3161 return Expr(AsCast{
3162 ...expr
3163 typ: t.convert_generic_expr_type(expr.typ, generic_names, concrete_types)
3164 expr: t.convert_generic_default_expr(expr.expr, generic_names, concrete_types)
3165 expr_type: t.convert_generic_expr_type(expr.expr_type, generic_names,
3166 concrete_types)
3167 })
3168 }
3169 CallExpr {
3170 mut resolved_concrete_types := t.convert_generic_expr_types(expr.concrete_types,
3171 generic_names, concrete_types)
3172 mut name := expr.name
3173 if !expr.is_method {
3174 if func := t.find_fn_in_mod(expr.name, expr.mod) {
3175 name = func.name
3176 if func.generic_names.len > 0 && resolved_concrete_types.len == 0 {
3177 for fn_generic_name in func.generic_names {
3178 idx := generic_names.index(fn_generic_name)
3179 if idx >= 0 && idx < concrete_types.len {
3180 resolved_concrete_types << concrete_types[idx]
3181 }
3182 }
3183 }
3184 if resolved_concrete_types.len == func.generic_names.len
3185 && resolved_concrete_types.all(!it.has_flag(.generic)) {
3186 t.register_fn_concrete_types(func.fkey(), resolved_concrete_types)
3187 }
3188 }
3189 }
3190 return Expr(CallExpr{
3191 ...expr
3192 name: name
3193 args: t.convert_generic_call_args(expr.args, generic_names,
3194 concrete_types)
3195 expected_arg_types: t.convert_generic_expr_types(expr.expected_arg_types,
3196 generic_names, concrete_types)
3197 left: t.convert_generic_default_expr(expr.left, generic_names,
3198 concrete_types)
3199 left_type: t.convert_generic_expr_type(expr.left_type, generic_names,
3200 concrete_types)
3201 receiver_type: t.convert_generic_expr_type(expr.receiver_type,
3202 generic_names, concrete_types)
3203 receiver_concrete_type: t.convert_generic_expr_type(expr.receiver_concrete_type,
3204 generic_names, concrete_types)
3205 return_type: t.convert_generic_expr_type(expr.return_type,
3206 generic_names, concrete_types)
3207 return_type_generic: t.convert_generic_expr_type(expr.return_type_generic,
3208 generic_names, concrete_types)
3209 fn_var_type: t.convert_generic_expr_type(expr.fn_var_type,
3210 generic_names, concrete_types)
3211 concrete_types: resolved_concrete_types
3212 raw_concrete_types: if expr.raw_concrete_types.len > 0 {
3213 t.convert_generic_expr_types(expr.raw_concrete_types, generic_names,
3214 concrete_types)
3215 } else {
3216 resolved_concrete_types
3217 }
3218 from_embed_types: t.convert_generic_expr_types(expr.from_embed_types,
3219 generic_names, concrete_types)
3220 })
3221 }
3222 CastExpr {
3223 return Expr(CastExpr{
3224 ...expr
3225 arg: t.convert_generic_default_expr(expr.arg, generic_names, concrete_types)
3226 typ: t.convert_generic_expr_type(expr.typ, generic_names, concrete_types)
3227 expr: t.convert_generic_default_expr(expr.expr, generic_names, concrete_types)
3228 expr_type: t.convert_generic_expr_type(expr.expr_type, generic_names,
3229 concrete_types)
3230 })
3231 }
3232 ChanInit {
3233 return Expr(ChanInit{
3234 ...expr
3235 cap_expr: t.convert_generic_default_expr(expr.cap_expr, generic_names,
3236 concrete_types)
3237 typ: t.convert_generic_expr_type(expr.typ, generic_names, concrete_types)
3238 elem_type: t.convert_generic_expr_type(expr.elem_type, generic_names,
3239 concrete_types)
3240 })
3241 }
3242 ConcatExpr {
3243 mut vals := []Expr{cap: expr.vals.len}
3244 for node in expr.vals {
3245 vals << t.convert_generic_default_expr(node, generic_names, concrete_types)
3246 }
3247 return Expr(ConcatExpr{
3248 ...expr
3249 vals: vals
3250 return_type: t.convert_generic_expr_type(expr.return_type, generic_names,
3251 concrete_types)
3252 })
3253 }
3254 DumpExpr {
3255 return Expr(DumpExpr{
3256 ...expr
3257 expr: t.convert_generic_default_expr(expr.expr, generic_names, concrete_types)
3258 expr_type: t.convert_generic_expr_type(expr.expr_type, generic_names,
3259 concrete_types)
3260 })
3261 }
3262 Ident {
3263 mut resolved_concrete_types := t.convert_generic_expr_types(expr.concrete_types,
3264 generic_names, concrete_types)
3265 mut info := expr.info
3266 mut kind := expr.kind
3267 mut name := expr.name
3268 match mut info {
3269 IdentFn {
3270 info.typ = t.convert_generic_expr_type(info.typ, generic_names, concrete_types)
3271 }
3272 IdentVar {
3273 info.typ = t.convert_generic_expr_type(info.typ, generic_names, concrete_types)
3274 }
3275 }
3276
3277 mut obj := expr.obj
3278 match mut obj {
3279 AsmRegister {
3280 obj.typ = t.convert_generic_expr_type(obj.typ, generic_names, concrete_types)
3281 }
3282 ConstField {
3283 obj.typ = t.convert_generic_expr_type(obj.typ, generic_names, concrete_types)
3284 }
3285 EmptyScopeObject {
3286 obj.typ = t.convert_generic_expr_type(obj.typ, generic_names, concrete_types)
3287 }
3288 GlobalField {
3289 obj.typ = t.convert_generic_expr_type(obj.typ, generic_names, concrete_types)
3290 }
3291 Var {
3292 obj.typ = t.convert_generic_expr_type(obj.typ, generic_names, concrete_types)
3293 obj.orig_type = t.convert_generic_expr_type(obj.orig_type, generic_names,
3294 concrete_types)
3295 obj.smartcasts = t.convert_generic_expr_types(obj.smartcasts, generic_names,
3296 concrete_types)
3297 }
3298 }
3299
3300 if func := t.find_fn_in_mod(expr.name, expr.mod) {
3301 name = func.name
3302 mut fn_type := t.find_or_register_fn_type(func, false, true)
3303 if fn_type < 0 {
3304 mut f := Fn{
3305 ...func
3306 }
3307 f.name = ''
3308 fn_type = t.find_or_register_fn_type(f, false, true)
3309 }
3310 if func.generic_names.len > 0 && resolved_concrete_types.len == 0 {
3311 for fn_generic_name in func.generic_names {
3312 idx := generic_names.index(fn_generic_name)
3313 if idx >= 0 && idx < concrete_types.len {
3314 resolved_concrete_types << concrete_types[idx]
3315 }
3316 }
3317 }
3318 if func.generic_names.len > 0 {
3319 if typ_ := t.convert_generic_type(fn_type, func.generic_names,
3320 resolved_concrete_types)
3321 {
3322 fn_type = typ_
3323 }
3324 }
3325 if fn_type > 0 {
3326 kind = .function
3327 info = IdentFn{
3328 typ: fn_type
3329 }
3330 }
3331 if resolved_concrete_types.len == func.generic_names.len
3332 && resolved_concrete_types.all(!it.has_flag(.generic)) {
3333 t.register_fn_concrete_types(func.fkey(), resolved_concrete_types)
3334 }
3335 }
3336 return Expr(Ident{
3337 ...expr
3338 name: name
3339 obj: obj
3340 info: info
3341 kind: kind
3342 concrete_types: resolved_concrete_types
3343 })
3344 }
3345 IfGuardExpr {
3346 return Expr(IfGuardExpr{
3347 ...expr
3348 expr: t.convert_generic_default_expr(expr.expr, generic_names, concrete_types)
3349 expr_type: t.convert_generic_expr_type(expr.expr_type, generic_names,
3350 concrete_types)
3351 })
3352 }
3353 IndexExpr {
3354 return Expr(IndexExpr{
3355 ...expr
3356 index: t.convert_generic_default_expr(expr.index, generic_names,
3357 concrete_types)
3358 left: t.convert_generic_default_expr(expr.left, generic_names,
3359 concrete_types)
3360 left_type: t.convert_generic_expr_type(expr.left_type, generic_names,
3361 concrete_types)
3362 index_type: t.convert_generic_expr_type(expr.index_type, generic_names,
3363 concrete_types)
3364 setter_arg_type: t.convert_generic_expr_type(expr.setter_arg_type, generic_names,
3365 concrete_types)
3366 typ: t.convert_generic_expr_type(expr.typ, generic_names,
3367 concrete_types)
3368 })
3369 }
3370 InfixExpr {
3371 return Expr(InfixExpr{
3372 ...expr
3373 left: t.convert_generic_default_expr(expr.left, generic_names,
3374 concrete_types)
3375 right: t.convert_generic_default_expr(expr.right, generic_names,
3376 concrete_types)
3377 left_type: t.convert_generic_expr_type(expr.left_type, generic_names,
3378 concrete_types)
3379 right_type: t.convert_generic_expr_type(expr.right_type, generic_names,
3380 concrete_types)
3381 promoted_type: t.convert_generic_expr_type(expr.promoted_type, generic_names,
3382 concrete_types)
3383 })
3384 }
3385 IsRefType {
3386 return Expr(IsRefType{
3387 ...expr
3388 expr: t.convert_generic_default_expr(expr.expr, generic_names, concrete_types)
3389 typ: t.convert_generic_expr_type(expr.typ, generic_names, concrete_types)
3390 })
3391 }
3392 Likely {
3393 return Expr(Likely{
3394 ...expr
3395 expr: t.convert_generic_default_expr(expr.expr, generic_names, concrete_types)
3396 })
3397 }
3398 MapInit {
3399 mut keys := []Expr{cap: expr.keys.len}
3400 for node in expr.keys {
3401 keys << t.convert_generic_default_expr(node, generic_names, concrete_types)
3402 }
3403 mut vals := []Expr{cap: expr.vals.len}
3404 for node in expr.vals {
3405 vals << t.convert_generic_default_expr(node, generic_names, concrete_types)
3406 }
3407 return Expr(MapInit{
3408 ...expr
3409 keys: keys
3410 vals: vals
3411 val_types: t.convert_generic_expr_types(expr.val_types, generic_names,
3412 concrete_types)
3413 typ: t.convert_generic_expr_type(expr.typ, generic_names, concrete_types)
3414 key_type: t.convert_generic_expr_type(expr.key_type, generic_names,
3415 concrete_types)
3416 value_type: t.convert_generic_expr_type(expr.value_type, generic_names,
3417 concrete_types)
3418 update_expr: t.convert_generic_default_expr(expr.update_expr, generic_names,
3419 concrete_types)
3420 })
3421 }
3422 OffsetOf {
3423 return Expr(OffsetOf{
3424 ...expr
3425 struct_type: t.convert_generic_expr_type(expr.struct_type, generic_names,
3426 concrete_types)
3427 })
3428 }
3429 ParExpr {
3430 return Expr(ParExpr{
3431 ...expr
3432 expr: t.convert_generic_default_expr(expr.expr, generic_names, concrete_types)
3433 })
3434 }
3435 PostfixExpr {
3436 return Expr(PostfixExpr{
3437 ...expr
3438 expr: t.convert_generic_default_expr(expr.expr, generic_names, concrete_types)
3439 typ: t.convert_generic_expr_type(expr.typ, generic_names, concrete_types)
3440 })
3441 }
3442 PrefixExpr {
3443 return Expr(PrefixExpr{
3444 ...expr
3445 right_type: t.convert_generic_expr_type(expr.right_type, generic_names,
3446 concrete_types)
3447 right: t.convert_generic_default_expr(expr.right, generic_names,
3448 concrete_types)
3449 })
3450 }
3451 RangeExpr {
3452 return Expr(RangeExpr{
3453 ...expr
3454 low: t.convert_generic_default_expr(expr.low, generic_names, concrete_types)
3455 high: t.convert_generic_default_expr(expr.high, generic_names, concrete_types)
3456 typ: t.convert_generic_expr_type(expr.typ, generic_names, concrete_types)
3457 })
3458 }
3459 SelectorExpr {
3460 return Expr(SelectorExpr{
3461 ...expr
3462 expr: t.convert_generic_default_expr(expr.expr, generic_names,
3463 concrete_types)
3464 expr_type: t.convert_generic_expr_type(expr.expr_type,
3465 generic_names, concrete_types)
3466 typ: t.convert_generic_expr_type(expr.typ, generic_names,
3467 concrete_types)
3468 name_type: t.convert_generic_expr_type(expr.name_type,
3469 generic_names, concrete_types)
3470 from_embed_types: t.convert_generic_expr_types(expr.from_embed_types,
3471 generic_names, concrete_types)
3472 generic_from_embed_types: t.convert_generic_nested_expr_types(expr.generic_from_embed_types,
3473 generic_names, concrete_types)
3474 })
3475 }
3476 SizeOf {
3477 return Expr(SizeOf{
3478 ...expr
3479 expr: t.convert_generic_default_expr(expr.expr, generic_names, concrete_types)
3480 typ: t.convert_generic_expr_type(expr.typ, generic_names, concrete_types)
3481 })
3482 }
3483 StringInterLiteral {
3484 mut exprs := []Expr{cap: expr.exprs.len}
3485 for node in expr.exprs {
3486 exprs << t.convert_generic_default_expr(node, generic_names, concrete_types)
3487 }
3488 return Expr(StringInterLiteral{
3489 ...expr
3490 exprs: exprs
3491 expr_types: t.convert_generic_expr_types(expr.expr_types, generic_names,
3492 concrete_types)
3493 })
3494 }
3495 StructInit {
3496 return Expr(StructInit{
3497 ...expr
3498 generic_typ: t.convert_generic_expr_type(expr.generic_typ, generic_names,
3499 concrete_types)
3500 typ: t.convert_generic_expr_type(expr.typ, generic_names,
3501 concrete_types)
3502 update_expr: t.convert_generic_default_expr(expr.update_expr, generic_names,
3503 concrete_types)
3504 update_expr_type: t.convert_generic_expr_type(expr.update_expr_type, generic_names,
3505 concrete_types)
3506 init_fields: t.convert_generic_struct_init_fields(expr.init_fields,
3507 generic_names, concrete_types)
3508 generic_types: t.convert_generic_expr_types(expr.generic_types, generic_names,
3509 concrete_types)
3510 })
3511 }
3512 TypeNode {
3513 return Expr(TypeNode{
3514 ...expr
3515 typ: t.convert_generic_expr_type(expr.typ, generic_names, concrete_types)
3516 })
3517 }
3518 TypeOf {
3519 return Expr(TypeOf{
3520 ...expr
3521 expr: t.convert_generic_default_expr(expr.expr, generic_names, concrete_types)
3522 typ: t.convert_generic_expr_type(expr.typ, generic_names, concrete_types)
3523 })
3524 }
3525 UnsafeExpr {
3526 return Expr(UnsafeExpr{
3527 ...expr
3528 expr: t.convert_generic_default_expr(expr.expr, generic_names, concrete_types)
3529 })
3530 }
3531 else {}
3532 }
3533
3534 return expr
3535}
3536
3537fn generic_names_push_with_filter(mut to_names []string, from_names []string) {
3538 for name in from_names {
3539 if name !in to_names {
3540 to_names << name
3541 }
3542 }
3543}
3544
3545fn (ts &TypeSymbol) has_generic_type_info() bool {
3546 return match ts.info {
3547 Struct, Interface, SumType { ts.info.is_generic }
3548 else { false }
3549 }
3550}
3551
3552fn (t &Table) find_fn_in_mod(name string, mod string) ?Fn {
3553 if func := t.find_fn(name) {
3554 return func
3555 }
3556 if mod != '' && !name.contains('.') {
3557 if func := t.find_fn('${mod}.${name}') {
3558 return func
3559 }
3560 }
3561 return none
3562}
3563
3564pub fn (mut t Table) generic_type_names(generic_type Type) []string {
3565 mut names := []string{}
3566 idx := generic_type.idx()
3567 if idx == 0 || idx >= t.type_symbols.len {
3568 return names
3569 }
3570 mut sym := t.sym(generic_type)
3571 if sym.name.len == 1 && sym.name[0].is_capital() {
3572 names << sym.name
3573 return names
3574 }
3575 match mut sym.info {
3576 Array {
3577 _, elem_type := t.get_array_dims(sym.info)
3578 names << t.generic_type_names(elem_type)
3579 }
3580 ArrayFixed {
3581 names << t.generic_type_names(sym.info.elem_type)
3582 }
3583 Chan {
3584 names << t.generic_type_names(sym.info.elem_type)
3585 }
3586 FnType {
3587 for param in sym.info.func.params {
3588 generic_names_push_with_filter(mut names, t.generic_type_names(param.typ))
3589 if param.orig_typ != 0 {
3590 generic_names_push_with_filter(mut names, t.generic_type_names(param.orig_typ))
3591 }
3592 }
3593 generic_names_push_with_filter(mut names,
3594 t.generic_type_names(sym.info.func.return_type))
3595 if names.len == 0 {
3596 generic_names_push_with_filter(mut names, sym.info.func.generic_names)
3597 }
3598 }
3599 MultiReturn {
3600 for ret_type in sym.info.types {
3601 generic_names_push_with_filter(mut names, t.generic_type_names(ret_type))
3602 }
3603 }
3604 Map {
3605 names << t.generic_type_names(sym.info.key_type)
3606 generic_names_push_with_filter(mut names, t.generic_type_names(sym.info.value_type))
3607 }
3608 Struct, Interface, SumType {
3609 if sym.info.is_generic {
3610 if sym.generic_types.len > 0 {
3611 // Foo[U] (declaration: Foo[T])
3612 for typ in sym.generic_types {
3613 if typ.has_flag(.generic) && t.sym(typ).kind == .any {
3614 names << t.sym(typ).name
3615 }
3616 }
3617 } else {
3618 names << sym.info.generic_types.map(t.sym(it).name)
3619 }
3620 }
3621 }
3622 else {
3623 // For placeholder types (forward-declared generic structs),
3624 // check generic_types on the symbol itself
3625 if sym.generic_types.len > 0 {
3626 for typ in sym.generic_types {
3627 if typ.has_flag(.generic) && t.sym(typ).kind == .any {
3628 names << t.sym(typ).name
3629 }
3630 }
3631 }
3632 }
3633 }
3634
3635 return names
3636}
3637
3638// unwrap_generic_type resolves generic symbols to their concrete types.
3639pub fn (mut t Table) unwrap_generic_type(typ Type, generic_names []string, concrete_types []Type) Type {
3640 return t.unwrap_generic_type_ex(typ, generic_names, concrete_types, false)
3641}
3642
3643// unwrap_generic_type_ex resolves generic symbols to concrete types and can recheck nested concrete fields.
3644pub fn (mut t Table) unwrap_generic_type_ex(typ Type, generic_names []string, concrete_types []Type, recheck_concrete_types bool) Type {
3645 return t.unwrap_generic_type_ex_with_depth(typ, generic_names, concrete_types,
3646 recheck_concrete_types, []string{})
3647}
3648
3649fn (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 {
3650 mut final_concrete_types := []Type{}
3651 mut fields := []StructField{}
3652 mut nrt := ''
3653 mut c_nrt := ''
3654 mut new_depth_guard := []string{}
3655 type_idx := typ.idx()
3656 if type_idx == 0 || type_idx >= t.type_symbols.len {
3657 return typ
3658 }
3659 for ct in concrete_types {
3660 if ct.idx() == 0 || ct.idx() >= t.type_symbols.len {
3661 return typ
3662 }
3663 }
3664 ts := t.type_symbols[type_idx]
3665 match ts.info {
3666 Array {
3667 dims, elem_type := t.get_array_dims(ts.info)
3668 unwrap_typ := t.unwrap_generic_type_ex_with_depth(elem_type, generic_names,
3669 concrete_types, recheck_concrete_types, depth_guard)
3670 idx := t.find_or_register_array_with_dims(unwrap_typ, dims)
3671 if idx <= 0 {
3672 return typ
3673 }
3674 return new_type(idx).derive_add_muls(typ).clear_flag(.generic)
3675 }
3676 ArrayFixed {
3677 unwrap_typ := t.unwrap_generic_type_ex_with_depth(ts.info.elem_type, generic_names,
3678 concrete_types, recheck_concrete_types, depth_guard)
3679 idx := t.find_or_register_array_fixed(unwrap_typ, ts.info.size, None{}, false)
3680 if idx <= 0 {
3681 return typ
3682 }
3683 return new_type(idx).derive_add_muls(typ).clear_flag(.generic)
3684 }
3685 Chan {
3686 unwrap_typ := t.unwrap_generic_type(ts.info.elem_type, generic_names, concrete_types)
3687 idx := t.find_or_register_chan(unwrap_typ, unwrap_typ.nr_muls() > 0)
3688 if idx <= 0 {
3689 return typ
3690 }
3691 return new_type(idx).derive_add_muls(typ).clear_flag(.generic)
3692 }
3693 Thread {
3694 unwrap_typ := t.unwrap_generic_type_ex_with_depth(ts.info.return_type, generic_names,
3695 concrete_types, recheck_concrete_types, depth_guard)
3696 idx := t.find_or_register_thread(unwrap_typ)
3697 if idx <= 0 {
3698 return typ
3699 }
3700 return new_type(idx).derive_add_muls(typ).clear_flag(.generic)
3701 }
3702 Map {
3703 unwrap_key_type := t.unwrap_generic_type_ex_with_depth(ts.info.key_type, generic_names,
3704 concrete_types, recheck_concrete_types, depth_guard)
3705 unwrap_value_type := t.unwrap_generic_type_ex_with_depth(ts.info.value_type,
3706 generic_names, concrete_types, recheck_concrete_types, depth_guard)
3707 idx := t.find_or_register_map(unwrap_key_type, unwrap_value_type)
3708 if idx <= 0 {
3709 return typ
3710 }
3711 return new_type(idx).derive_add_muls(typ).clear_flag(.generic)
3712 }
3713 FnType {
3714 mut unwrapped_fn := ts.info.func
3715 unwrapped_fn.params = unwrapped_fn.params.clone()
3716 mut has_generic := false
3717 for i, param in unwrapped_fn.params {
3718 if param.typ.has_flag(.generic) || t.generic_type_names(param.typ).len > 0 {
3719 unwrapped_fn.params[i].typ = t.unwrap_generic_param_type(param, generic_names,
3720 concrete_types)
3721 has_generic = true
3722 }
3723 if param.orig_typ.has_flag(.generic) || t.generic_type_names(param.orig_typ).len > 0 {
3724 unwrapped_fn.params[i].orig_typ = t.unwrap_generic_type(param.orig_typ,
3725 generic_names, concrete_types)
3726 }
3727 }
3728 if unwrapped_fn.return_type.has_flag(.generic)
3729 || t.generic_type_names(unwrapped_fn.return_type).len > 0
3730 || (unwrapped_fn.return_type.idx() > 0 && unwrapped_fn.return_type.idx() < t.type_symbols.len
3731 && 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))) {
3732 unwrapped_fn.return_type = t.unwrap_generic_type_ex_with_depth(unwrapped_fn.return_type,
3733 generic_names, concrete_types, recheck_concrete_types, depth_guard)
3734 has_generic = true
3735 }
3736 if has_generic {
3737 if !ts.info.is_anon {
3738 inst_name := t.generic_fn_inst_name(ts, concrete_types)
3739 idx := t.find_type_idx(inst_name)
3740 if idx > 0 {
3741 return new_type(idx).derive_add_muls(typ).clear_flag(.generic)
3742 }
3743 }
3744 // Clear the name so find_or_register_fn_type registers a new anonymous fn
3745 // type with the resolved concrete param/return types, instead of returning
3746 // the existing generic fn type entry (matched by name).
3747 unwrapped_fn.name = ''
3748 unwrapped_fn.generic_names = []
3749 idx := t.find_or_register_fn_type(unwrapped_fn, true, false)
3750 if idx <= 0 {
3751 return typ
3752 }
3753 return new_type(idx).derive_add_muls(typ).clear_flag(.generic)
3754 }
3755 return typ
3756 }
3757 Struct, Interface, SumType {
3758 if !ts.info.is_generic {
3759 return typ
3760 }
3761 mut t_generic_names := generic_names.clone()
3762 mut t_concrete_types := concrete_types.clone()
3763 if ts.generic_types.len > 0 && ts.generic_types.len == ts.info.generic_types.len
3764 && ts.generic_types != ts.info.generic_types {
3765 t_generic_names = ts.info.generic_types.map(t.sym(it).name)
3766 t_concrete_types = []
3767 for t_typ in ts.generic_types {
3768 if !t_typ.has_flag(.generic) {
3769 t_concrete_types << t_typ
3770 } else {
3771 t_concrete_types << t.unwrap_generic_ty