vxx2 / vlib / v3 / tests / transformer_parity_test.v
989 lines · 925 sloc · 24.59 KB · 42203d41d069b6736382ee1cc64a69e160c94b1c
Raw
1import os
2import v3.flat
3import v3.parser
4import v3.pref
5import v3.transform
6import v3.types
7
8// parse_transform_source reads parse transform source input for v3 tests.
9fn parse_transform_source(source string) &flat.FlatAst {
10 src := os.join_path(os.temp_dir(), 'v3_transformer_parity_test.v')
11 return parse_transform_file(src, source)
12}
13
14// parse_transform_file reads parse transform file input for v3 tests.
15fn parse_transform_file(src string, source string) &flat.FlatAst {
16 os.write_file(src, source) or { panic(err) }
17 prefs := pref.new_preferences()
18 mut p := parser.Parser.new(prefs)
19 mut a := p.parse_file(src)
20 mut tc := types.TypeChecker.new(a)
21 tc.collect(a)
22 tc.annotate_types()
23 transform.transform(mut a, &tc)
24 return a
25}
26
27// parse_checked_transform_source reads parse checked transform source input for v3 tests.
28fn parse_checked_transform_source(source string) &flat.FlatAst {
29 src := os.join_path(os.temp_dir(), 'v3_transformer_checked_parity_test.v')
30 os.write_file(src, source) or { panic(err) }
31 prefs := pref.new_preferences()
32 mut p := parser.Parser.new(prefs)
33 mut a := p.parse_file(src)
34 mut tc := types.TypeChecker.new(a)
35 tc.diagnose_unknown_calls = true
36 tc.collect(a)
37 tc.check_semantics()
38 assert tc.errors.len == 0, tc.errors.str()
39 transform.transform(mut a, &tc)
40 return a
41}
42
43// find_fn resolves find fn information for v3 tests.
44fn find_fn(a &flat.FlatAst, name string) flat.Node {
45 for node in a.nodes {
46 if node.kind == .fn_decl && node.value == name {
47 return node
48 }
49 }
50 assert false
51 return flat.Node{}
52}
53
54// first_decl_rhs returns first decl rhs data for v3 tests.
55fn first_decl_rhs(a &flat.FlatAst, fn_name string) flat.Node {
56 f := find_fn(a, fn_name)
57 for i in 0 .. f.children_count {
58 stmt := a.child_node(&f, i)
59 if stmt.kind == .decl_assign && stmt.children_count == 2 {
60 return *a.child_node(stmt, 1)
61 }
62 }
63 assert false
64 return flat.Node{}
65}
66
67// decl_rhs supports decl rhs handling for v3 tests.
68fn decl_rhs(a &flat.FlatAst, fn_name string, name string) flat.Node {
69 f := find_fn(a, fn_name)
70 for i in 0 .. f.children_count {
71 stmt := a.child_node(&f, i)
72 if stmt.kind == .decl_assign && stmt.children_count == 2 {
73 lhs := a.child_node(stmt, 0)
74 if lhs.kind == .ident && lhs.value == name {
75 return *a.child_node(stmt, 1)
76 }
77 }
78 }
79 assert false
80 return flat.Node{}
81}
82
83// first_return_expr returns first return expr data for v3 tests.
84fn first_return_expr(a &flat.FlatAst, fn_name string) flat.Node {
85 f := find_fn(a, fn_name)
86 for i in 0 .. f.children_count {
87 stmt := a.child_node(&f, i)
88 if stmt.kind == .return_stmt && stmt.children_count > 0 {
89 return *a.child_node(stmt, 0)
90 }
91 }
92 assert false
93 return flat.Node{}
94}
95
96// count_kind supports count kind handling for v3 tests.
97fn count_kind(a &flat.FlatAst, id flat.NodeId, kind flat.NodeKind) int {
98 if int(id) < 0 {
99 return 0
100 }
101 node := a.nodes[int(id)]
102 mut total := if node.kind == kind { 1 } else { 0 }
103 for i in 0 .. node.children_count {
104 total += count_kind(a, a.child(&node, i), kind)
105 }
106 return total
107}
108
109// count_call_name supports count call name handling for v3 tests.
110fn count_call_name(a &flat.FlatAst, id flat.NodeId, name string) int {
111 if int(id) < 0 {
112 return 0
113 }
114 node := a.nodes[int(id)]
115 mut total := 0
116 if node.kind == .call && node.children_count > 0 {
117 fn_node := a.child_node(&node, 0)
118 if fn_node.kind == .ident && fn_node.value == name {
119 total++
120 }
121 }
122 for i in 0 .. node.children_count {
123 total += count_call_name(a, a.child(&node, i), name)
124 }
125 return total
126}
127
128fn first_call_arg_opt(a &flat.FlatAst, id flat.NodeId, name string, arg_idx int) ?flat.Node {
129 if int(id) < 0 {
130 return none
131 }
132 node := a.nodes[int(id)]
133 if node.kind == .call && node.children_count > arg_idx + 1 {
134 fn_node := a.child_node(&node, 0)
135 if fn_node.kind == .ident && fn_node.value == name {
136 return *a.child_node(&node, arg_idx + 1)
137 }
138 }
139 for i in 0 .. node.children_count {
140 if found := first_call_arg_opt(a, a.child(&node, i), name, arg_idx) {
141 return found
142 }
143 }
144 return none
145}
146
147// count_infix_op supports count infix op handling for v3 tests.
148fn count_infix_op(a &flat.FlatAst, id flat.NodeId, op flat.Op) int {
149 if int(id) < 0 {
150 return 0
151 }
152 node := a.nodes[int(id)]
153 mut total := if node.kind == .infix && node.op == op { 1 } else { 0 }
154 for i in 0 .. node.children_count {
155 total += count_infix_op(a, a.child(&node, i), op)
156 }
157 return total
158}
159
160// count_wide_decl_assigns supports count wide decl assigns handling for v3 tests.
161fn count_wide_decl_assigns(a &flat.FlatAst, id flat.NodeId) int {
162 if int(id) < 0 {
163 return 0
164 }
165 node := a.nodes[int(id)]
166 mut total := if node.kind == .decl_assign && node.children_count > 2 { 1 } else { 0 }
167 for i in 0 .. node.children_count {
168 total += count_wide_decl_assigns(a, a.child(&node, i))
169 }
170 return total
171}
172
173// count_wide_assigns supports count wide assigns handling for v3 tests.
174fn count_wide_assigns(a &flat.FlatAst, id flat.NodeId) int {
175 if int(id) < 0 {
176 return 0
177 }
178 node := a.nodes[int(id)]
179 mut total := if node.kind == .assign && node.children_count > 2 { 1 } else { 0 }
180 for i in 0 .. node.children_count {
181 total += count_wide_assigns(a, a.child(&node, i))
182 }
183 return total
184}
185
186// count_selector_value supports count selector value handling for v3 tests.
187fn count_selector_value(a &flat.FlatAst, id flat.NodeId, value string) int {
188 if int(id) < 0 {
189 return 0
190 }
191 node := a.nodes[int(id)]
192 mut total := if node.kind == .selector && node.value == value { 1 } else { 0 }
193 for i in 0 .. node.children_count {
194 total += count_selector_value(a, a.child(&node, i), value)
195 }
196 return total
197}
198
199// test_typeof_expression_lowers_to_string_literal validates this v3 regression case.
200fn test_typeof_expression_lowers_to_string_literal() {
201 a := parse_transform_source('
202fn main() {
203 name := typeof(123)
204}
205')
206 main_fn := find_fn(a, 'main')
207 for i in 0 .. main_fn.children_count {
208 stmt := a.child_node(&main_fn, i)
209 if stmt.kind == .decl_assign && stmt.children_count == 2 {
210 rhs := a.child_node(stmt, 1)
211 assert rhs.kind == .string_literal
212 assert rhs.value == 'int literal'
213 return
214 }
215 }
216 assert false
217}
218
219// test_vmodroot_lowers_to_nearest_vmod_dir validates this v3 regression case.
220fn test_vmodroot_lowers_to_nearest_vmod_dir() {
221 root := os.join_path(os.temp_dir(), 'v3_vmodroot_transformer_parity')
222 os.mkdir_all(root) or { panic(err) }
223 os.write_file(os.join_path(root, 'v.mod'), 'Module { name: "parity" }') or { panic(err) }
224 src := os.join_path(root, 'main.v')
225 a := parse_transform_file(src, '
226fn main() {
227 root := @VMODROOT
228}
229')
230 rhs := first_decl_rhs(a, 'main')
231 assert rhs.kind == .string_literal
232 assert rhs.value == root
233}
234
235// test_return_match_lowers_to_explicit_branch_returns validates this v3 regression case.
236fn test_return_match_lowers_to_explicit_branch_returns() {
237 a := parse_transform_source('
238fn choose(x int) int {
239 return match x {
240 0 {
241 10
242 }
243 else {
244 20
245 }
246 }
247}
248')
249 choose_fn := find_fn(a, 'choose')
250 mut match_count := 0
251 mut return_count := 0
252 for i in 0 .. choose_fn.children_count {
253 child_id := a.child(&choose_fn, i)
254 match_count += count_kind(a, child_id, .match_stmt)
255 return_count += count_kind(a, child_id, .return_stmt)
256 }
257 assert match_count == 0
258 assert return_count == 2
259}
260
261// test_return_if_keeps_or_lowering_inside_branch validates this v3 regression case.
262fn test_return_if_keeps_or_lowering_inside_branch() {
263 a := parse_transform_source('
264fn maybe_int() ?int {
265 return 8
266}
267
268fn choose(flag bool) int {
269 return if flag {
270 maybe_int() or {
271 1
272 }
273 } else {
274 2
275 }
276}
277')
278 choose_fn := find_fn(a, 'choose')
279 mut body_ids := []flat.NodeId{}
280 for i in 0 .. choose_fn.children_count {
281 child_id := a.child(&choose_fn, i)
282 child := a.nodes[int(child_id)]
283 if child.kind != .param {
284 body_ids << child_id
285 }
286 }
287 assert body_ids.len == 1
288 assert a.nodes[int(body_ids[0])].kind == .if_expr
289}
290
291// test_if_expr_value_lowers_to_temp_and_branch_assigns validates this v3 regression case.
292fn test_if_expr_value_lowers_to_temp_and_branch_assigns() {
293 a := parse_transform_source('
294fn main() {
295 x := if true {
296 1
297 } else {
298 2
299 }
300}
301')
302 rhs := decl_rhs(a, 'main', 'x')
303 assert rhs.kind == .ident
304 assert rhs.value.starts_with('__if_val_')
305 main_fn := find_fn(a, 'main')
306 mut if_count := 0
307 mut assign_count := 0
308 for i in 0 .. main_fn.children_count {
309 child_id := a.child(&main_fn, i)
310 if_count += count_kind(a, child_id, .if_expr)
311 assign_count += count_kind(a, child_id, .assign)
312 }
313 assert if_count == 1
314 assert assign_count == 2
315}
316
317// test_if_expr_call_arg_lowers_before_call validates this v3 regression case.
318fn test_if_expr_call_arg_lowers_before_call() {
319 a := parse_transform_source('
320fn use(x int) int {
321 return x
322}
323
324fn main() {
325 x := use(if true { 1 } else { 2 })
326}
327')
328 rhs := decl_rhs(a, 'main', 'x')
329 assert rhs.kind == .call
330 assert rhs.children_count == 2
331 arg := a.child_node(&rhs, 1)
332 assert arg.kind == .ident
333 assert arg.value.starts_with('__if_val_')
334}
335
336// test_nested_if_expr_branch_lowers_to_outer_temp_assignment validates this v3 regression case.
337fn test_nested_if_expr_branch_lowers_to_outer_temp_assignment() {
338 a := parse_transform_source('
339fn main() {
340 x := if true {
341 if false {
342 1
343 } else {
344 2
345 }
346 } else {
347 3
348 }
349}
350')
351 rhs := decl_rhs(a, 'main', 'x')
352 assert rhs.kind == .ident
353 assert rhs.value.starts_with('__if_val_')
354 main_fn := find_fn(a, 'main')
355 mut if_count := 0
356 mut assign_count := 0
357 for i in 0 .. main_fn.children_count {
358 child_id := a.child(&main_fn, i)
359 if_count += count_kind(a, child_id, .if_expr)
360 assign_count += count_kind(a, child_id, .assign)
361 }
362 assert if_count == 2
363 assert assign_count == 4
364}
365
366// test_multi_return_decl_lowers_to_temp_field_decls validates this v3 regression case.
367fn test_multi_return_decl_lowers_to_temp_field_decls() {
368 a := parse_transform_source("
369fn pair() (int, string) {
370 return 1, 'ok'
371}
372
373fn main() {
374 a, b := pair()
375}
376")
377 main_fn := find_fn(a, 'main')
378 mut wide_decl_count := 0
379 for i in 0 .. main_fn.children_count {
380 wide_decl_count += count_wide_decl_assigns(a, a.child(&main_fn, i))
381 }
382 assert wide_decl_count == 0
383 a_rhs := decl_rhs(a, 'main', 'a')
384 b_rhs := decl_rhs(a, 'main', 'b')
385 assert a_rhs.kind == .selector
386 assert a_rhs.value == 'arg0'
387 assert b_rhs.kind == .selector
388 assert b_rhs.value == 'arg1'
389}
390
391// test_multi_return_assign_lowers_to_temp_field_assigns validates this v3 regression case.
392fn test_multi_return_assign_lowers_to_temp_field_assigns() {
393 a := parse_transform_source("
394fn pair() (int, string) {
395 return 1, 'ok'
396}
397
398fn main() {
399 mut a := 0
400 mut b := ''
401 a, b = pair()
402}
403")
404 main_fn := find_fn(a, 'main')
405 mut wide_assign_count := 0
406 mut arg0_count := 0
407 mut arg1_count := 0
408 for i in 0 .. main_fn.children_count {
409 child_id := a.child(&main_fn, i)
410 wide_assign_count += count_wide_assigns(a, child_id)
411 arg0_count += count_selector_value(a, child_id, 'arg0')
412 arg1_count += count_selector_value(a, child_id, 'arg1')
413 }
414 assert wide_assign_count == 0
415 assert arg0_count == 1
416 assert arg1_count == 1
417}
418
419// test_assoc_expr_lowers_to_temp_and_field_assigns validates this v3 regression case.
420fn test_assoc_expr_lowers_to_temp_and_field_assigns() {
421 a := parse_transform_source('
422struct Point {
423 x int
424 y int
425}
426
427fn main() {
428 p := Point{x: 1, y: 2}
429 q := Point{...p, y: 3}
430}
431')
432 rhs := decl_rhs(a, 'main', 'q')
433 assert rhs.kind == .ident
434 assert rhs.value.starts_with('__assoc_')
435 main_fn := find_fn(a, 'main')
436 mut assoc_count := 0
437 mut assign_count := 0
438 for i in 0 .. main_fn.children_count {
439 child_id := a.child(&main_fn, i)
440 assoc_count += count_kind(a, child_id, .assoc)
441 assign_count += count_kind(a, child_id, .assign)
442 }
443 assert assoc_count == 0
444 assert assign_count == 1
445}
446
447// test_return_assoc_expr_lowers_before_return validates this v3 regression case.
448fn test_return_assoc_expr_lowers_before_return() {
449 a := parse_transform_source('
450struct Point {
451 x int
452 y int
453}
454
455fn moved(p Point) Point {
456 return Point{...p, x: 4}
457}
458')
459 ret := first_return_expr(a, 'moved')
460 assert ret.kind == .ident
461 assert ret.value.starts_with('__assoc_')
462 moved_fn := find_fn(a, 'moved')
463 mut assoc_count := 0
464 for i in 0 .. moved_fn.children_count {
465 assoc_count += count_kind(a, a.child(&moved_fn, i), .assoc)
466 }
467 assert assoc_count == 0
468}
469
470// test_array_append_stmt_lowers_to_runtime_push validates this v3 regression case.
471fn test_array_append_stmt_lowers_to_runtime_push() {
472 a := parse_transform_source('
473fn main() {
474 mut xs := []int{}
475 xs << 3
476}
477')
478 main_fn := find_fn(a, 'main')
479 mut push_count := 0
480 mut left_shift_count := 0
481 for i in 0 .. main_fn.children_count {
482 child_id := a.child(&main_fn, i)
483 push_count += count_call_name(a, child_id, 'array_push')
484 left_shift_count += count_infix_op(a, child_id, .left_shift)
485 }
486 assert push_count == 1
487 assert left_shift_count == 0
488}
489
490// test_array_append_many_stmt_lowers_to_runtime_push_many validates this v3 regression case.
491fn test_array_append_many_stmt_lowers_to_runtime_push_many() {
492 a := parse_transform_source('
493fn main() {
494 mut xs := []int{}
495 ys := []int{}
496 xs << ys
497}
498')
499 main_fn := find_fn(a, 'main')
500 mut push_many_count := 0
501 mut left_shift_count := 0
502 for i in 0 .. main_fn.children_count {
503 child_id := a.child(&main_fn, i)
504 push_many_count += count_call_name(a, child_id, 'array__push_many')
505 left_shift_count += count_infix_op(a, child_id, .left_shift)
506 }
507 assert push_many_count == 1
508 assert left_shift_count == 0
509}
510
511fn test_array_push_many_method_lowers_to_runtime_ptr_call() {
512 a := parse_transform_source('
513fn main() {
514 mut xs := []u8{}
515 mut b := u8(7)
516 unsafe {
517 xs.push_many(&b, 1)
518 }
519}
520')
521 main_fn := find_fn(a, 'main')
522 mut push_many_ptr_count := 0
523 mut push_many_selector_count := 0
524 for i in 0 .. main_fn.children_count {
525 child_id := a.child(&main_fn, i)
526 push_many_ptr_count += count_call_name(a, child_id, 'array_push_many_ptr')
527 push_many_selector_count += count_selector_value(a, child_id, 'push_many')
528 }
529 assert push_many_ptr_count == 1
530 assert push_many_selector_count == 0
531}
532
533fn test_array_push_many_type_marker_lowers_to_runtime_ptr_call() {
534 a := parse_transform_source('
535struct PushManyItem {
536 value int
537}
538
539fn main() {
540 mut xs := []PushManyItem{}
541 item := PushManyItem{value: 7}
542 xs.push_many(item, PushManyItem)
543}
544')
545 main_fn := find_fn(a, 'main')
546 mut push_many_ptr_count := 0
547 mut push_many_selector_count := 0
548 for i in 0 .. main_fn.children_count {
549 child_id := a.child(&main_fn, i)
550 push_many_ptr_count += count_call_name(a, child_id, 'array_push_many_ptr')
551 push_many_selector_count += count_selector_value(a, child_id, 'push_many')
552 }
553 assert push_many_ptr_count == 1
554 assert push_many_selector_count == 0
555}
556
557fn test_sql_expr_lowers_to_success_result_default() {
558 a := parse_transform_source('
559struct User {
560 id int
561}
562
563fn main() {
564 db := 0
565 users := sql db {
566 select from User
567 }
568 count := sql db {
569 select count from User
570 }
571 created := sql db {
572 create table User
573 }
574}
575')
576 main_fn := find_fn(a, 'main')
577 mut sql_expr_count := 0
578 for i in 0 .. main_fn.children_count {
579 sql_expr_count += count_kind(a, a.child(&main_fn, i), .sql_expr)
580 }
581 assert sql_expr_count == 0
582 users := decl_rhs(a, 'main', 'users')
583 assert users.kind == .struct_init
584 assert users.value == '![]User'
585 count := decl_rhs(a, 'main', 'count')
586 assert count.kind == .struct_init
587 assert count.value == '!int'
588 created := decl_rhs(a, 'main', 'created')
589 assert created.kind == .struct_init
590 assert created.value == '!void'
591}
592
593// test_or_expr_lowers_to_temp_and_if validates this v3 regression case.
594fn test_or_expr_lowers_to_temp_and_if() {
595 a := parse_transform_source('
596fn maybe_int() ?int {
597 return 3
598}
599
600fn main() {
601 x := maybe_int() or {
602 7
603 }
604}
605')
606 main_fn := find_fn(a, 'main')
607 mut or_count := 0
608 mut if_count := 0
609 for i in 0 .. main_fn.children_count {
610 child_id := a.child(&main_fn, i)
611 or_count += count_kind(a, child_id, .or_expr)
612 if_count += count_kind(a, child_id, .if_expr)
613 }
614 assert or_count == 0
615 assert if_count == 1
616}
617
618// test_map_index_or_lowers_to_get_check validates this v3 regression case.
619fn test_map_index_or_lowers_to_get_check() {
620 a := parse_transform_source('
621fn main() {
622 mut m := map[string]int{}
623 x := m["a"] or {
624 7
625 }
626}
627')
628 main_fn := find_fn(a, 'main')
629 mut or_count := 0
630 mut get_check_count := 0
631 for i in 0 .. main_fn.children_count {
632 child_id := a.child(&main_fn, i)
633 or_count += count_kind(a, child_id, .or_expr)
634 get_check_count += count_call_name(a, child_id, 'map__get_check')
635 }
636 assert or_count == 0
637 assert get_check_count == 1
638}
639
640fn test_map_methods_lower_to_runtime_calls() {
641 a := parse_transform_source('
642fn main() {
643 mut m := map[string]int{}
644 m.delete("a")
645 m.clear()
646 m.free()
647}
648')
649 main_fn := find_fn(a, 'main')
650 mut delete_count := 0
651 mut clear_count := 0
652 mut free_count := 0
653 mut selector_count := 0
654 for i in 0 .. main_fn.children_count {
655 child_id := a.child(&main_fn, i)
656 delete_count += count_call_name(a, child_id, 'map__delete')
657 clear_count += count_call_name(a, child_id, 'map__clear')
658 free_count += count_call_name(a, child_id, 'map__free')
659 selector_count += count_selector_value(a, child_id, 'delete')
660 selector_count += count_selector_value(a, child_id, 'clear')
661 selector_count += count_selector_value(a, child_id, 'free')
662 }
663 assert delete_count == 1
664 assert clear_count == 1
665 assert free_count == 1
666 assert selector_count == 0
667}
668
669fn test_map_delete_fixed_array_key_uses_full_key_type() {
670 a := parse_transform_source('
671fn main() {
672 mut m := map[[2]string]int{}
673 key := ["foo", "bar"]!
674 m[key] = 5
675 m.delete(key)
676}
677')
678 main_fn := find_fn(a, 'main')
679 mut key_tmp := ''
680 mut delete_count := 0
681 for i in 0 .. main_fn.children_count {
682 child_id := a.child(&main_fn, i)
683 delete_count += count_call_name(a, child_id, 'map__delete')
684 if arg := first_call_arg_opt(a, child_id, 'map__delete', 1) {
685 assert arg.kind == .prefix
686 assert arg.op == .amp
687 ident := a.child_node(&arg, 0)
688 assert ident.kind == .ident
689 key_tmp = ident.value
690 }
691 }
692 assert delete_count == 1
693 assert key_tmp.len > 0
694 mut found_key_decl := false
695 for i in 0 .. main_fn.children_count {
696 stmt := a.child_node(&main_fn, i)
697 if stmt.kind == .decl_assign && stmt.children_count >= 2 {
698 lhs := a.child_node(stmt, 0)
699 if lhs.kind == .ident && lhs.value == key_tmp {
700 assert stmt.typ == '[2]string'
701 found_key_decl = true
702 }
703 }
704 }
705 assert found_key_decl
706}
707
708fn test_exact_map_receiver_method_wins_over_builtin_lowering() {
709 a := parse_checked_transform_source('
710fn (m map[string]int) keys() int {
711 return 7
712}
713
714fn main() {
715 mut m := map[string]int{}
716 n := m.keys()
717}
718')
719 main_fn := find_fn(a, 'main')
720 mut exact_count := 0
721 mut builtin_count := 0
722 for i in 0 .. main_fn.children_count {
723 child_id := a.child(&main_fn, i)
724 exact_count += count_call_name(a, child_id, 'map[string]int.keys')
725 exact_count += count_call_name(a, child_id, 'main.map[string]int.keys')
726 builtin_count += count_call_name(a, child_id, 'map__keys')
727 builtin_count += count_call_name(a, child_id, 'map.keys')
728 }
729 assert exact_count == 1
730 assert builtin_count == 0
731}
732
733fn test_channel_close_lowers_to_runtime_call() {
734 a := parse_transform_source('
735fn main() {
736 ch := chan bool{cap: 1}
737 ch.close()
738}
739')
740 main_fn := find_fn(a, 'main')
741 mut close_count := 0
742 mut selector_count := 0
743 for i in 0 .. main_fn.children_count {
744 child_id := a.child(&main_fn, i)
745 close_count += count_call_name(a, child_id, 'sync__Channel__close')
746 close_count += count_selector_value(a, child_id, 'sync__Channel__close')
747 selector_count += count_selector_value(a, child_id, 'close')
748 }
749 assert close_count == 1
750 assert selector_count == 0
751}
752
753fn test_static_assoc_call_lowers_to_direct_call() {
754 a := parse_checked_transform_source('
755struct Tool {}
756
757fn Tool.make(x int) int {
758 return x
759}
760
761fn main() {
762 n := Tool.make(7)
763}
764')
765 main_fn := find_fn(a, 'main')
766 mut direct_count := 0
767 mut selector_count := 0
768 for i in 0 .. main_fn.children_count {
769 child_id := a.child(&main_fn, i)
770 direct_count += count_call_name(a, child_id, 'Tool.make')
771 selector_count += count_selector_value(a, child_id, 'make')
772 }
773 assert direct_count == 1
774 assert selector_count == 0
775}
776
777fn test_array_builtin_method_fallback_lowers_to_direct_call() {
778 a := parse_checked_transform_source('
779@[unsafe]
780fn (a array) pointers() []voidptr {
781 return []voidptr{}
782}
783
784fn main() {
785 nums := [1, 2, 3]
786 unsafe {
787 ptrs := nums.pointers()
788 }
789}
790')
791 main_fn := find_fn(a, 'main')
792 mut direct_count := 0
793 mut selector_count := 0
794 for i in 0 .. main_fn.children_count {
795 child_id := a.child(&main_fn, i)
796 direct_count += count_call_name(a, child_id, 'array.pointers')
797 selector_count += count_selector_value(a, child_id, 'pointers')
798 }
799 assert direct_count == 1
800 assert selector_count == 0
801}
802
803fn test_array_reverse_pointer_receiver_derefs_before_runtime_call() {
804 a := parse_transform_source('
805fn main() {
806 mut nums := []int{}
807 nums << 1
808 p := &nums
809 rev := p.reverse()
810}
811')
812 main_fn := find_fn(a, 'main')
813 mut direct_count := 0
814 mut selector_count := 0
815 for i in 0 .. main_fn.children_count {
816 child_id := a.child(&main_fn, i)
817 direct_count += count_call_name(a, child_id, 'array__reverse')
818 selector_count += count_selector_value(a, child_id, 'reverse')
819 }
820 assert direct_count == 1
821 assert selector_count == 0
822 mut arg := flat.Node{}
823 mut found_arg := false
824 for i in 0 .. main_fn.children_count {
825 if candidate := first_call_arg_opt(a, a.child(&main_fn, i), 'array__reverse', 0) {
826 arg = candidate
827 found_arg = true
828 break
829 }
830 }
831 assert found_arg
832 assert arg.kind == .prefix
833 assert arg.op == .mul
834 assert arg.children_count == 1
835 ident := a.child_node(&arg, 0)
836 assert ident.kind == .ident
837 assert ident.value == 'p'
838}
839
840fn test_fixed_array_pointers_uses_intrinsic_without_copy() {
841 a := parse_checked_transform_source('
842@[unsafe]
843fn (a array) pointers() []voidptr {
844 return []voidptr{}
845}
846
847fn main() {
848 mut fixed := [3]int{}
849 unsafe {
850 ptrs := fixed.pointers()
851 }
852}
853')
854 main_fn := find_fn(a, 'main')
855 mut direct_count := 0
856 mut copy_count := 0
857 mut selector_count := 0
858 for i in 0 .. main_fn.children_count {
859 child_id := a.child(&main_fn, i)
860 direct_count += count_call_name(a, child_id, 'array.pointers')
861 copy_count += count_call_name(a, child_id, 'new_array_from_c_array')
862 selector_count += count_selector_value(a, child_id, 'pointers')
863 }
864 assert direct_count == 1
865 assert copy_count == 0
866 assert selector_count == 0
867}
868
869fn test_fixed_array_dynamic_receiver_method_wins_over_array_builtin() {
870 a := parse_checked_transform_source('
871@[unsafe]
872fn (a array) pointers() []voidptr {
873 return []voidptr{}
874}
875
876fn (a []int) pointers() int {
877 return 7
878}
879
880fn main() {
881 mut fixed := [3]int{}
882 n := fixed.pointers()
883}
884')
885 main_fn := find_fn(a, 'main')
886 mut dynamic_count := 0
887 mut builtin_count := 0
888 for i in 0 .. main_fn.children_count {
889 child_id := a.child(&main_fn, i)
890 dynamic_count += count_call_name(a, child_id, '[]int.pointers')
891 dynamic_count += count_call_name(a, child_id, 'main.[]int.pointers')
892 builtin_count += count_call_name(a, child_id, 'array.pointers')
893 }
894 assert dynamic_count == 1
895 assert builtin_count == 0
896}
897
898fn test_exact_array_receiver_method_wins_over_builtin_fallback() {
899 a := parse_checked_transform_source('
900@[unsafe]
901fn (a array) pointers() []voidptr {
902 return []voidptr{}
903}
904
905fn (a []int) pointers() []int {
906 return a
907}
908
909fn main() {
910 mut nums := []int{}
911 nums << 1
912 nums << 2
913 nums << 3
914 ptrs := nums.pointers()
915}
916')
917 main_fn := find_fn(a, 'main')
918 mut exact_count := 0
919 mut builtin_count := 0
920 for i in 0 .. main_fn.children_count {
921 child_id := a.child(&main_fn, i)
922 exact_count += count_call_name(a, child_id, '[]int.pointers')
923 exact_count += count_call_name(a, child_id, 'main.[]int.pointers')
924 builtin_count += count_call_name(a, child_id, 'array.pointers')
925 }
926 assert exact_count == 1
927 assert builtin_count == 0
928}
929
930fn test_pointer_rvalue_arg_lowers_to_temp_address() {
931 a := parse_checked_transform_source('
932fn make_int() int {
933 return 7
934}
935
936fn takes_ptr(x &int) int {
937 return *x
938}
939
940fn main() {
941 y := takes_ptr(make_int())
942}
943')
944 main_fn := find_fn(a, 'main')
945 mut call_count := 0
946 mut make_count := 0
947 for i in 0 .. main_fn.children_count {
948 child_id := a.child(&main_fn, i)
949 call_count += count_call_name(a, child_id, 'takes_ptr')
950 make_count += count_call_name(a, child_id, 'make_int')
951 }
952 assert call_count == 1
953 assert make_count == 1
954 mut arg := flat.Node{}
955 mut found_arg := false
956 for i in 0 .. main_fn.children_count {
957 if candidate := first_call_arg_opt(a, a.child(&main_fn, i), 'takes_ptr', 0) {
958 arg = candidate
959 found_arg = true
960 break
961 }
962 }
963 assert found_arg
964 assert arg.kind == .prefix
965 assert arg.op == .amp
966 assert arg.children_count == 1
967 ident := a.child_node(&arg, 0)
968 assert ident.kind == .ident
969 assert ident.value.starts_with('__ptr_arg_')
970}
971
972fn test_map_values_membership_lowers_without_type_annotation() {
973 a := parse_checked_transform_source('
974fn main() {
975 mut names := map[string]string{}
976 found := "alex" in names.values()
977}
978')
979 main_fn := find_fn(a, 'main')
980 mut in_count := 0
981 mut for_count := 0
982 for i in 0 .. main_fn.children_count {
983 child_id := a.child(&main_fn, i)
984 in_count += count_kind(a, child_id, .in_expr)
985 for_count += count_kind(a, child_id, .for_stmt)
986 }
987 assert in_count == 0
988 assert for_count == 1
989}
990