v4 / vlib / v3 / transform / sum.v
550 lines · 528 sloc · 16.59 KB · 7a89e581dace12716ed47d2e665fd337d9820870
Raw
1module transform
2
3import v3.flat
4
5// trim_pointer_type transforms trim pointer type data for transform.
6fn (t &Transformer) trim_pointer_type(typ string) string {
7 if typ.starts_with('&') {
8 return typ[1..]
9 }
10 return typ
11}
12
13// resolve_variant resolves resolve variant information for transform.
14fn (t &Transformer) resolve_variant(sum_name string, variant string) string {
15 if variant.contains('.') {
16 return variant
17 }
18 resolved_sum := t.resolve_sum_name(sum_name)
19 if resolved_variant := t.sum_variant_name(resolved_sum, variant) {
20 return resolved_variant
21 }
22 if resolved_sum.contains('.') {
23 return '${resolved_sum.all_before_last('.')}.${variant}'
24 }
25 if sum_name.contains('.') {
26 return '${sum_name.all_before_last('.')}.${variant}'
27 }
28 return variant
29}
30
31// resolve_sum_name resolves resolve sum name information for transform.
32fn (t &Transformer) resolve_sum_name(sum_name string) string {
33 if sum_name.len == 0 {
34 return sum_name
35 }
36 if isnil(t.sum_cache) {
37 return t.resolve_sum_name_uncached(sum_name)
38 }
39 mut c := t.sum_cache
40 if c.module != t.cur_module {
41 c.module = t.cur_module
42 c.entries.clear()
43 }
44 if cached := c.entries[sum_name] {
45 return cached
46 }
47 result := t.resolve_sum_name_uncached(sum_name)
48 c.entries[sum_name] = result
49 return result
50}
51
52// resolve_sum_name_uncached resolves resolve sum name uncached information for transform.
53fn (t &Transformer) resolve_sum_name_uncached(sum_name string) string {
54 if sum_name in t.sum_types {
55 return sum_name
56 }
57 if sum_name.contains('.') {
58 short_sum := sum_name.all_after_last('.')
59 if short_sum in t.sum_types {
60 return short_sum
61 }
62 }
63 if !sum_name.contains('.') && t.cur_module.len > 0 && t.cur_module != 'main'
64 && t.cur_module != 'builtin' {
65 qsum := '${t.cur_module}.${sum_name}'
66 if qsum in t.sum_types {
67 return qsum
68 }
69 }
70 if !sum_name.contains('.') {
71 mut found := ''
72 for key, _ in t.sum_types {
73 if key.contains('.') && key.all_after_last('.') == sum_name {
74 if found.len > 0 && found != key {
75 found = ''
76 break
77 }
78 found = key
79 }
80 }
81 if found.len > 0 {
82 return found
83 }
84 }
85 if !isnil(t.tc) {
86 if sum_name in t.tc.sum_types {
87 return sum_name
88 }
89 if sum_name.contains('.') {
90 short_sum := sum_name.all_after_last('.')
91 if short_sum in t.tc.sum_types {
92 return short_sum
93 }
94 }
95 if !sum_name.contains('.') && t.cur_module.len > 0 && t.cur_module != 'main'
96 && t.cur_module != 'builtin' {
97 qsum := '${t.cur_module}.${sum_name}'
98 if qsum in t.tc.sum_types {
99 return qsum
100 }
101 }
102 if !sum_name.contains('.') {
103 mut found := ''
104 for key, _ in t.tc.sum_types {
105 if key.contains('.') && key.all_after_last('.') == sum_name {
106 if found.len > 0 && found != key {
107 found = ''
108 break
109 }
110 found = key
111 }
112 }
113 if found.len > 0 {
114 return found
115 }
116 }
117 }
118 return sum_name
119}
120
121// is_sum_type_name reports whether is sum type name applies in transform.
122fn (t &Transformer) is_sum_type_name(name string) bool {
123 if name.len == 0 {
124 return false
125 }
126 resolved := t.resolve_sum_name(name)
127 return resolved in t.sum_types
128}
129
130// is_interface_type_name reports whether is interface type name applies in transform.
131fn (t &Transformer) is_interface_type_name(name string) bool {
132 if name.len == 0 || isnil(t.tc) {
133 return false
134 }
135 clean := t.trim_pointer_type(t.normalize_type_alias(name))
136 if clean == 'IError' || clean in t.tc.interface_names {
137 return true
138 }
139 if !clean.contains('.') && t.cur_module.len > 0 && t.cur_module != 'main'
140 && t.cur_module != 'builtin' {
141 return '${t.cur_module}.${clean}' in t.tc.interface_names
142 }
143 return false
144}
145
146// interface_variant_type supports interface variant type handling for Transformer.
147fn (t &Transformer) interface_variant_type(variant string) string {
148 if variant.contains('.') {
149 return variant
150 }
151 if variant in t.structs {
152 return variant
153 }
154 if t.cur_module.len > 0 && t.cur_module != 'main' && t.cur_module != 'builtin' {
155 qvariant := '${t.cur_module}.${variant}'
156 if qvariant in t.structs {
157 return qvariant
158 }
159 }
160 for name, _ in t.structs {
161 if name.contains('.') && name.all_after_last('.') == variant {
162 return name
163 }
164 }
165 return variant
166}
167
168// smartcast_target_type supports smartcast target type handling for Transformer.
169fn (t &Transformer) smartcast_target_type(sc SmartcastContext) string {
170 if t.is_interface_type_name(sc.sum_type_name) {
171 return t.interface_variant_type(sc.variant_name)
172 }
173 return t.resolve_variant(sc.sum_type_name, sc.variant_name)
174}
175
176// sum_type_index supports sum type index handling for Transformer.
177fn (t &Transformer) sum_type_index(sum_name string, variant string) int {
178 resolved_sum := t.resolve_sum_name(sum_name)
179 variants := t.sum_types[resolved_sum] or {
180 if !isnil(t.tc) {
181 tc_variants := t.tc.sum_types[resolved_sum] or { return 0 }
182 return sum_type_index_in_variants(tc_variants, variant)
183 }
184 return 0
185 }
186 return sum_type_index_in_variants(variants, variant)
187}
188
189// sum_type_index_in_variants supports sum type index in variants handling for transform.
190fn sum_type_index_in_variants(variants []string, variant string) int {
191 short_variant := variant_short_name_text(variant)
192 for i, v in variants {
193 short_v := variant_short_name_text(v)
194 if v == variant || short_v == short_variant {
195 return i + 1
196 }
197 }
198 return 0
199}
200
201// transform_is_expr transforms transform is expr data for transform.
202fn (mut t Transformer) transform_is_expr(id flat.NodeId, node flat.Node) flat.NodeId {
203 if node.children_count == 0 {
204 return id
205 }
206 expr_id := t.a.child(&node, 0)
207 expr_type := t.node_type(expr_id)
208 clean_type0 := t.trim_pointer_type(expr_type)
209 clean_type := if clean_type0 in t.sum_types {
210 clean_type0
211 } else {
212 t.find_sum_type_for_variant(node.value)
213 }
214 if t.is_interface_type_name(clean_type0) {
215 new_expr := t.transform_expr(expr_id)
216 object := t.make_selector_op(new_expr, '_object', 'voidptr', if expr_type.starts_with('&') {
217 .arrow
218 } else {
219 .dot
220 })
221 return t.make_infix(.ne, object, t.a.add(.nil_literal))
222 }
223 if clean_type.len == 0 || clean_type !in t.sum_types {
224 return t.make_bool_literal(true)
225 }
226 new_expr := t.transform_expr(expr_id)
227 if check := t.make_sum_type_pattern_check(new_expr, expr_type, clean_type, node.value) {
228 return check
229 }
230 return t.make_bool_literal(true)
231}
232
233// make_sum_is_check builds make sum is check data for transform.
234fn (mut t Transformer) make_sum_is_check(expr flat.NodeId, expr_type string, sum_name string, variant string) flat.NodeId {
235 tag := t.make_selector_op(expr, 'typ', 'int', if expr_type.starts_with('&') {
236 .arrow
237 } else {
238 .dot
239 })
240 idx := t.make_int_literal(t.sum_type_index(sum_name, variant))
241 return t.make_infix(.eq, tag, idx)
242}
243
244// sum_variant_path supports sum variant path handling for Transformer.
245fn (t &Transformer) sum_variant_path(sum_name string, variant string) []string {
246 mut visited := map[string]bool{}
247 return t.sum_variant_path_inner(sum_name, variant, mut visited)
248}
249
250// sum_variant_path_inner supports sum variant path inner handling for Transformer.
251fn (t &Transformer) sum_variant_path_inner(sum_name string, variant string, mut visited map[string]bool) []string {
252 resolved_sum := t.resolve_sum_name(t.trim_pointer_type(sum_name))
253 if resolved_sum.len == 0 || resolved_sum in visited {
254 return []string{}
255 }
256 visited[resolved_sum] = true
257 if direct := t.sum_variant_name(resolved_sum, variant) {
258 return [direct]
259 }
260 variants := t.sum_types[resolved_sum] or { return []string{} }
261 for direct in variants {
262 direct_sum := t.resolve_sum_name(t.trim_pointer_type(direct))
263 if direct_sum == resolved_sum || direct_sum !in t.sum_types {
264 continue
265 }
266 nested := t.sum_variant_path_inner(direct_sum, variant, mut visited)
267 if nested.len == 0 {
268 continue
269 }
270 mut path := []string{cap: nested.len + 1}
271 path << direct
272 path << nested
273 return path
274 }
275 return []string{}
276}
277
278// make_sum_type_pattern_check builds make sum type pattern check data for transform.
279fn (mut t Transformer) make_sum_type_pattern_check(expr flat.NodeId, expr_type string, sum_name string, variant string) ?flat.NodeId {
280 resolved_sum := t.resolve_sum_name(t.trim_pointer_type(sum_name))
281 path := t.sum_variant_path(resolved_sum, variant)
282 if path.len == 0 {
283 return none
284 }
285 mut current := expr
286 mut current_type := expr_type
287 mut current_sum := resolved_sum
288 mut chain := flat.empty_node
289 for i, path_variant in path {
290 cmp := t.make_sum_is_check(current, current_type, current_sum, path_variant)
291 if int(chain) < 0 {
292 chain = cmp
293 } else {
294 chain = t.make_infix(.logical_and, chain, cmp)
295 }
296 if i == path.len - 1 {
297 break
298 }
299 qv := t.resolve_variant(current_sum, path_variant)
300 use_ptr := t.variant_references_sum(qv, current_sum)
301 field_type := if use_ptr { '&${qv}' } else { qv }
302 current = t.make_selector_op(current, t.sum_field_name(qv), field_type, if current_type.starts_with('&') {
303 .arrow
304 } else {
305 .dot
306 })
307 current_type = field_type
308 current_sum = t.resolve_sum_name(t.trim_pointer_type(qv))
309 }
310 return chain
311}
312
313// transform_as_expr converts transform as expr data for transform.
314fn (mut t Transformer) transform_as_expr(id flat.NodeId, node flat.Node) flat.NodeId {
315 if node.children_count == 0 {
316 return id
317 }
318 expr_id := t.a.child(&node, 0)
319 expr_type := t.node_type(expr_id)
320 clean_type0 := t.trim_pointer_type(expr_type)
321 clean_type := if clean_type0 in t.sum_types {
322 clean_type0
323 } else {
324 t.find_sum_type_for_variant(node.value)
325 }
326 if clean_type.len == 0 || clean_type !in t.sum_types {
327 return t.transform_expr(expr_id)
328 }
329 qv := t.resolve_variant(clean_type, node.value)
330 if qv.len > 0 && t.normalize_type_alias(clean_type0) == t.normalize_type_alias(qv) {
331 return t.transform_expr(expr_id)
332 }
333 sc_key := t.expr_key(expr_id)
334 if sc_key.len > 0 {
335 contexts := t.smartcasts_for(sc_key)
336 mut matched_contexts := []SmartcastContext{}
337 for i, sc in contexts {
338 mut sc_variant := sc.variant_name
339 if sc.variant_name.contains('.') {
340 sc_variant = sc.variant_name.all_after_last('.')
341 }
342 mut target_variant := node.value
343 if node.value.contains('.') {
344 target_variant = node.value.all_after_last('.')
345 }
346 if sc_variant == target_variant {
347 end := i + 1
348 matched_contexts = contexts[..end].clone()
349 }
350 }
351 if matched_contexts.len > 0 {
352 base := t.make_plain_expr_for_smartcast(expr_id)
353 return t.apply_smartcast_contexts(base, t.original_expr_type(expr_id), matched_contexts)
354 }
355 }
356 field := t.sum_field_name(qv)
357 new_expr := t.transform_expr(expr_id)
358 use_ptr := t.variant_references_sum(qv, clean_type)
359 field_typ := if use_ptr { '&${qv}' } else { qv }
360 field_sel := t.make_selector_op(new_expr, field, field_typ, if expr_type.starts_with('&') {
361 .arrow
362 } else {
363 .dot
364 })
365 if use_ptr {
366 return t.make_prefix(.mul, field_sel)
367 }
368 return field_sel
369}
370
371// wrap_sum_return_expr transforms wrap sum return expr data for transform.
372fn (mut t Transformer) wrap_sum_return_expr(expr_id flat.NodeId) flat.NodeId {
373 was_return_expr := t.in_return_expr
374 t.in_return_expr = true
375 result := if t.cur_fn_ret_type.len == 0 || t.cur_fn_ret_type !in t.sum_types {
376 t.transform_expr(expr_id)
377 } else {
378 t.wrap_sum_value(expr_id, t.cur_fn_ret_type)
379 }
380 t.in_return_expr = was_return_expr
381 return result
382}
383
384// wrap_sum_value transforms wrap sum value data for transform.
385fn (mut t Transformer) wrap_sum_value(expr_id flat.NodeId, target_sum string) flat.NodeId {
386 resolved_sum := t.resolve_sum_name(target_sum)
387 if resolved_sum.len == 0 || resolved_sum !in t.sum_types {
388 return t.transform_expr(expr_id)
389 }
390 expr := t.a.nodes[int(expr_id)]
391 if expr.kind == .if_expr {
392 branch_type := t.if_expr_branch_result_type(expr)
393 if t.if_expr_branch_overrides_sum_target(branch_type, resolved_sum) {
394 return t.transform_expr(expr_id)
395 }
396 if lowered := t.try_expand_if_expr_value_for_type(expr_id, expr, resolved_sum) {
397 return lowered
398 }
399 }
400 expr_type := t.node_type(expr_id)
401 mut variant := expr_type
402 mut expr_smartcast := SmartcastContext{}
403 key := t.expr_key(expr_id)
404 if key.len > 0 {
405 if sc := t.find_smartcast(key) {
406 expr_smartcast = sc
407 }
408 }
409 has_expr_smartcast := expr_smartcast.expr_name.len > 0
410 if has_expr_smartcast && t.resolve_sum_name(expr_smartcast.sum_type_name) == resolved_sum {
411 variant = t.resolve_variant(expr_smartcast.sum_type_name, expr_smartcast.variant_name)
412 }
413 if expr.kind == .prefix && expr.op == .mul && expr.children_count > 0 {
414 inner_type := t.node_type(t.a.child(&expr, 0))
415 if inner_type.starts_with('&') {
416 variant = inner_type[1..]
417 }
418 }
419 if expr.kind == .struct_init || expr.kind == .cast_expr {
420 variant = expr.value
421 } else if expr.kind == .as_expr && expr.value.len > 0 {
422 variant = expr.value
423 } else if expr.kind == .assoc && expr.value.len > 0 {
424 variant = expr.value
425 } else if expr.kind == .assoc && expr.children_count > 0 {
426 variant = t.node_type(t.a.child(&expr, 0))
427 }
428 if expr.kind !in [.assoc, .as_expr, .prefix] && !has_expr_smartcast
429 && t.resolve_sum_name(expr_type) == resolved_sum {
430 return t.transform_expr(expr_id)
431 }
432 if expr_type.starts_with('&') && t.resolve_sum_name(expr_type[1..]) == resolved_sum {
433 inner := t.transform_expr(expr_id)
434 deref := t.make_prefix(.mul, inner)
435 t.a.nodes[int(deref)].typ = resolved_sum
436 return deref
437 }
438 if variant.len == 0 {
439 return t.transform_expr(expr_id)
440 }
441 mut clean_variant := if variant.starts_with('&') { variant[1..] } else { variant }
442 if clean_variant.starts_with('ptr') && clean_variant.len > 3 && clean_variant[3..].contains('.') {
443 clean_variant = clean_variant[3..]
444 }
445 if clean_variant.starts_with('ptr') && clean_variant.len > 3
446 && clean_variant[3..].contains('__') {
447 clean_variant = clean_variant[3..].replace('__', '.')
448 }
449 short_variant := t.variant_short_name(clean_variant)
450 mut matches := false
451 mut matched_variant := clean_variant
452 for v in t.sum_types[resolved_sum] {
453 short_v := t.variant_short_name(v)
454 if v == clean_variant || short_v == short_variant {
455 matches = true
456 matched_variant = v
457 break
458 }
459 }
460 if !matches {
461 return t.transform_expr(expr_id)
462 }
463 ref_variant := t.variant_references_sum(matched_variant, resolved_sum)
464 mut pointer_variant_child := flat.empty_node
465 if expr.kind == .prefix && expr.op == .mul && expr.children_count > 0 {
466 pointer_variant_child = t.a.child(&expr, 0)
467 }
468 inner := if int(pointer_variant_child) >= 0 && ref_variant {
469 t.transform_expr(pointer_variant_child)
470 } else {
471 t.transform_expr(expr_id)
472 }
473 if expr_type.starts_with('&') {
474 return t.make_sum_literal(resolved_sum, matched_variant, inner)
475 }
476 if int(pointer_variant_child) >= 0 && ref_variant {
477 return t.make_sum_literal(resolved_sum, matched_variant, inner)
478 }
479 if ref_variant {
480 return t.make_sum_literal(resolved_sum, matched_variant, inner)
481 }
482 start := t.a.children.len
483 t.a.children << inner
484 return t.a.add_node(flat.Node{
485 kind: .cast_expr
486 value: resolved_sum
487 children_start: start
488 children_count: 1
489 typ: resolved_sum
490 })
491}
492
493// ensure_sum_variant_ref supports ensure sum variant ref handling for Transformer.
494fn (mut t Transformer) ensure_sum_variant_ref(value flat.NodeId, variant string) flat.NodeId {
495 mut value_type := t.node_type(value)
496 if value_type.starts_with('&') {
497 return value
498 }
499 clean_variant := if variant.starts_with('&') { variant[1..] } else { variant }
500 if value_type.len == 0 {
501 value_type = clean_variant
502 }
503 if t.expr_can_take_address(value) || t.a.nodes[int(value)].kind == .struct_init {
504 ref := t.make_prefix(.amp, value)
505 t.a.nodes[int(ref)].typ = '&${clean_variant}'
506 return ref
507 }
508 tmp_name := t.new_temp('sum_val')
509 t.pending_stmts << t.make_decl_assign_typed(tmp_name, value, value_type)
510 ref := t.make_prefix(.amp, t.make_ident(tmp_name))
511 t.a.nodes[int(ref)].typ = '&${clean_variant}'
512 return ref
513}
514
515// make_sum_literal builds make sum literal data for transform.
516fn (mut t Transformer) make_sum_literal(sum_name string, variant string, value flat.NodeId) flat.NodeId {
517 qvariant := t.resolve_variant(sum_name, variant)
518 typ_field := t.make_sum_literal_field('typ', t.make_int_literal(t.sum_type_index(sum_name,
519 qvariant)), 'int')
520 raw_value_type := t.node_type(value)
521 value_type := if raw_value_type.starts_with('&') {
522 raw_value_type
523 } else {
524 qvariant
525 }
526 value_field := t.make_sum_literal_field(t.sum_field_name(qvariant), value, value_type)
527 start := t.a.children.len
528 t.a.children << typ_field
529 t.a.children << value_field
530 return t.a.add_node(flat.Node{
531 kind: .struct_init
532 children_start: start
533 children_count: 2
534 value: sum_name
535 typ: sum_name
536 })
537}
538
539// make_sum_literal_field builds make sum literal field data for transform.
540fn (mut t Transformer) make_sum_literal_field(name string, value flat.NodeId, typ string) flat.NodeId {
541 start := t.a.children.len
542 t.a.children << value
543 return t.a.add_node(flat.Node{
544 kind: .field_init
545 children_start: start
546 children_count: 1
547 value: name
548 typ: typ
549 })
550}
551