v4 / vlib / v3 / eval / eval_test.v
3832 lines · 3391 sloc · 56.63 KB · b217dae98822d39840ecdfca5ba314b2e651f280
Raw
1module eval
2
3import os
4import v3.parser
5
6const vexe = @VEXE
7const v3_dir = os.dir(os.dir(@FILE))
8const v3_src = os.join_path(v3_dir, 'v3.v')
9
10fn test_eval_function_call_and_for_range() {
11 mut e := create()
12 e.run_text('
13fn sum(n int) int {
14 mut acc := 0
15 for i in 0 .. n {
16 acc += i
17 }
18 return acc
19}
20
21fn main() {
22 println(sum(5))
23}
24') or {
25 panic(err)
26 }
27 assert e.stdout() == '10\n'
28}
29
30fn test_eval_registers_top_level_comptime_block_declarations() {
31 mut e := create()
32 e.run_text('
33 $if windows {
34 fn gated_message() string {
35 return "ok"
36 }
37} $else $if macos {
38 fn gated_message() string {
39 return "ok"
40 }
41} $else {
42 fn gated_message() string {
43 return "ok"
44 }
45}
46
47fn main() {
48 println(gated_message())
49}
50 ') or {
51 panic(err)
52 }
53 assert e.stdout() == 'ok\n'
54}
55
56fn test_eval_executes_implicit_main_top_level_statements() {
57 mut e := create()
58 e.run_text('
59 mut x := 1
60 x += 2
61 println(x)
62 ') or { panic(err) }
63 assert e.stdout() == '3\n'
64}
65
66fn test_eval_disabled_if_call_skips_arguments() {
67 mut e := create()
68 e.run_text('
69 __global hit int
70
71@[if trace ?]
72fn trace(x int) {}
73
74fn side_effect() int {
75 hit = 99
76 return 1
77}
78
79fn main() {
80 trace(side_effect())
81 println(int_str(hit))
82}
83 ') or {
84 panic(err)
85 }
86 assert e.stdout() == '0\n'
87}
88
89fn test_eval_labeled_for_in_flow_targets_named_loop() {
90 mut e := create()
91 e.run_text('
92fn main() {
93 mut out := ""
94 outer: for x in 0 .. 3 {
95 for y in 0 .. 3 {
96 if x == 1 && y == 0 {
97 continue outer
98 }
99 if x == 2 && y == 1 {
100 break outer
101 }
102 out += "\${x}:\${y};"
103 }
104 }
105 println(out)
106}
107') or {
108 panic(err)
109 }
110 assert e.stdout() == '0:0;0:1;0:2;2:0;\n'
111}
112
113fn test_eval_labeled_c_style_for_flow_targets_named_loop() {
114 mut e := create()
115 e.run_text('
116fn main() {
117 mut out := ""
118 outer: for x := 0; x < 3; x++ {
119 for y := 0; y < 3; y++ {
120 if x == 1 && y == 0 {
121 continue outer
122 }
123 if x == 2 && y == 1 {
124 break outer
125 }
126 out += "\${x}:\${y};"
127 }
128 }
129 println(out)
130}
131') or {
132 panic(err)
133 }
134 assert e.stdout() == '0:0;0:1;0:2;2:0;\n'
135}
136
137fn test_eval_if_expr_value() {
138 mut e := create()
139 e.run_text('
140fn main() {
141 x := if 3 > 2 {
142 41
143 } else {
144 0
145 }
146 println(x + 1)
147}
148') or {
149 panic(err)
150 }
151 assert e.stdout() == '42\n'
152}
153
154fn test_eval_char_literal_escapes() {
155 mut e := create()
156 e.run_text(r"
157fn main() {
158 println(int_str(`\0`))
159 println(int_str(`\\`))
160 println(int_str(`\'`))
161}
162 ") or {
163 panic(err)
164 }
165 assert e.stdout() == '0\n92\n39\n'
166}
167
168fn test_eval_match_statement_propagates_return() {
169 mut e := create()
170 e.run_text('
171fn choose(x int) int {
172 match x {
173 0 {
174 return 1
175 }
176 else {}
177 }
178 return 2
179}
180
181fn main() {
182 println(int_str(choose(0)))
183 println(int_str(choose(1)))
184}
185') or {
186 panic(err)
187 }
188 assert e.stdout() == '1\n2\n'
189}
190
191fn test_eval_match_condition_propagates_return() {
192 mut e := create()
193 e.run_text('
194fn maybe() ?int {
195 return none
196}
197
198fn run() int {
199 x := 1
200 match x {
201 maybe() or {
202 return 7
203 } {}
204 else {}
205 }
206 return 0
207}
208
209fn main() {
210 println(int_str(run()))
211}
212 ') or {
213 panic(err)
214 }
215 assert e.stdout() == '7\n'
216}
217
218fn test_eval_match_branch_shadows_outer_locals() {
219 mut e := create()
220 e.run_text('
221fn stmt_shadow(n int) int {
222 x := 1
223 match n {
224 0 {
225 x := 2
226 if x != 2 {
227 return 99
228 }
229 }
230 else {}
231 }
232 return x
233}
234
235fn value_shadow(n int) int {
236 x := 1
237 y := match n {
238 0 {
239 x := 2
240 x
241 }
242 else {
243 3
244 }
245 }
246 return x * 10 + y
247}
248
249fn main() {
250 println(int_str(stmt_shadow(0)))
251 println(int_str(stmt_shadow(1)))
252 println(int_str(value_shadow(0)))
253 println(int_str(value_shadow(1)))
254}
255 ') or {
256 panic(err)
257 }
258 assert e.stdout() == '1\n1\n12\n13\n'
259}
260
261fn test_eval_c_style_for_scopes_initializer_and_body() {
262 mut e := create()
263 e.run_text('
264fn main() {
265 i := 10
266 for i := 0; i < 1; i++ {}
267 println(int_str(i))
268
269 x := 1
270 for j := 0; j < 2; j++ {
271 x := j + 2
272 _ = x
273 }
274 println(int_str(x))
275}
276 ') or {
277 panic(err)
278 }
279 assert e.stdout() == '10\n1\n'
280}
281
282fn test_eval_array_append_and_string_interpolation() {
283 mut e := create()
284 e.run_text('
285fn main() {
286 mut arr := []int{}
287 arr << 7
288 arr << 9
289 println("\${arr[0]}:\${arr[1]}:\${arr.len}")
290}
291') or {
292 panic(err)
293 }
294 assert e.stdout() == '7:9:2\n'
295}
296
297fn test_eval_array_append_adapts_sum_elements() {
298 mut e := create()
299 e.run_text('
300type Any = int | string
301
302fn main() {
303 mut xs := []Any{}
304 xs << 1
305 xs << "s"
306 println(int_str(xs[0]._typ))
307 println(int_str(xs[1]._typ))
308}
309 ') or {
310 panic(err)
311 }
312 assert e.stdout() == '0\n1\n'
313}
314
315fn test_eval_array_append_keeps_nested_array_rhs_as_single_element() {
316 mut e := create()
317 e.run_text('
318 fn main() {
319 mut nested := [][]int{}
320 nested << [1, 2]
321 println(int_str(nested.len))
322 println(int_str(nested[0].len))
323 println(int_str(nested[0][1]))
324
325 mut flat := []int{}
326 flat << [3, 4]
327 println(int_str(flat.len))
328 println(int_str(flat[1]))
329}
330 ') or {
331 panic(err)
332 }
333 assert e.stdout() == '1\n2\n2\n2\n4\n'
334}
335
336fn test_eval_array_append_index_target_evaluates_once() {
337 mut e := create()
338 e.run_text('
339 fn next(mut i int) int {
340 old := i
341 i++
342 return old
343 }
344
345 fn main() {
346 mut xs := [][]int{}
347 xs << [1]
348 xs << [2]
349 mut i := 0
350 xs[next(mut i)] << 9
351 println(int_str(xs[0].len))
352 println(int_str(xs[0][1]))
353 println(int_str(xs[1].len))
354 println(int_str(i))
355 }
356 ') or {
357 panic(err)
358 }
359 assert e.stdout() == '2\n9\n1\n1\n'
360}
361
362fn test_eval_array_append_rhs_uses_element_enum_type() {
363 mut e := create()
364 e.run_text('
365 enum Color {
366 red = 10
367 }
368
369 enum Other {
370 red = 1
371 }
372
373 fn main() {
374 mut xs := []Color{}
375 xs << .red
376 println(xs[0] == Color.red)
377 }
378 ') or {
379 panic(err)
380 }
381 assert e.stdout() == 'true\n'
382}
383
384fn test_eval_value_blocks_execute_array_append_statements() {
385 mut e := create()
386 e.run_text('
387fn maybe() ?int {
388 return none
389}
390
391fn main() {
392 mut xs := []int{}
393 n := if true {
394 xs << 1
395 xs.len
396 } else {
397 0
398 }
399 m := maybe() or {
400 xs << 2
401 xs.len
402 }
403 println(int_str(n))
404 println(int_str(m))
405 println(int_str(xs.len))
406 println(int_str(xs[0]))
407 println(int_str(xs[1]))
408}
409 ') or {
410 panic(err)
411 }
412 assert e.stdout() == '1\n2\n2\n1\n2\n'
413}
414
415fn test_eval_match_value_branches_execute_array_append_statements() {
416 mut e := create()
417 e.run_text('
418fn main() {
419 mut xs := []int{}
420 n := match 0 {
421 0 {
422 xs << 1
423 xs.len
424 }
425 else {
426 0
427 }
428 }
429 m := match 1 {
430 0 {
431 0
432 }
433 else {
434 xs << 2
435 xs.len
436 }
437 }
438 println(int_str(n))
439 println(int_str(m))
440 println(int_str(xs.len))
441 println(int_str(xs[0]))
442 println(int_str(xs[1]))
443}
444 ') or {
445 panic(err)
446 }
447 assert e.stdout() == '1\n2\n2\n1\n2\n'
448}
449
450fn test_eval_or_block_return_propagates_from_array_append_rhs() {
451 mut e := create()
452 e.run_text('
453 fn maybe() ?int {
454 return none
455}
456
457fn run() int {
458 mut xs := []int{}
459 xs << (maybe() or {
460 return 7
461 })
462 return xs.len
463}
464
465fn main() {
466 println(int_str(run()))
467}
468 ') or {
469 panic(err)
470 }
471 assert e.stdout() == '7\n'
472}
473
474fn test_eval_for_mut_array_writes_back_elements() {
475 mut e := create()
476 e.run_text('
477struct Item {
478mut:
479 n int
480}
481
482fn main() {
483 mut xs := [Item{n: 1}, Item{n: 2}]
484 for mut item in xs {
485 item.n += 10
486 }
487 println(int_str(xs[0].n))
488 println(int_str(xs[1].n))
489}
490 ') or {
491 panic(err)
492 }
493 assert e.stdout() == '11\n12\n'
494}
495
496fn test_eval_for_mut_reuses_resolved_array_container() {
497 mut e := create()
498 e.run_text('
499fn next(mut i int) int {
500 old := i
501 i++
502 return old
503}
504
505fn main() {
506 mut buckets := [[1], [10]]
507 mut i := 0
508 for mut x in buckets[next(mut i)] {
509 x++
510 }
511 println(int_str(buckets[0][0]))
512 println(int_str(buckets[1][0]))
513 println(int_str(i))
514}
515 ') or {
516 panic(err)
517 }
518 assert e.stdout() == '2\n10\n1\n'
519}
520
521fn test_eval_array_init_preserves_cap() {
522 mut e := create()
523 e.run_text('
524 fn main() {
525 a := []int{cap: 4}
526 b := []int{len: 1, cap: 4}
527 println(int_str(a.len))
528 println(int_str(a.cap))
529 println(int_str(b.len))
530 println(int_str(b.cap))
531}
532 ') or {
533 panic(err)
534 }
535 assert e.stdout() == '0\n4\n1\n4\n'
536}
537
538fn test_eval_array_init_adapts_sum_elements() {
539 mut e := create()
540 e.run_text('
541type Any = int | string
542
543fn main() {
544 xs := []Any{1, "s"}
545 ys := []Any{len: 2, init: 1}
546 println(int_str(xs[0]._typ))
547 println(int_str(xs[1]._typ))
548 println(int_str(ys[1]._typ))
549}
550 ') or {
551 panic(err)
552 }
553 assert e.stdout() == '0\n1\n0\n'
554}
555
556fn test_eval_array_init_flow_propagates_return() {
557 mut e := create()
558 e.run_text('
559fn maybe() ?int {
560 return none
561}
562
563fn run() []int {
564 return []int{len: 1, init: maybe() or { return [7] }}
565}
566
567fn main() {
568 xs := run()
569 println(int_str(xs.len))
570 println(int_str(xs[0]))
571}
572 ') or {
573 panic(err)
574 }
575 assert e.stdout() == '1\n7\n'
576}
577
578fn test_eval_array_init_evaluates_init_for_each_index() {
579 mut e := create()
580 e.run_text('
581fn bump(mut calls int) int {
582 calls++
583 return calls
584}
585
586fn main() {
587 mut calls := 0
588 xs := []int{len: 3, init: index}
589 ys := []int{len: 3, init: index + bump(mut calls)}
590 fixed := [3]int{init: index}
591 println(int_str(xs[0]))
592 println(int_str(xs[2]))
593 println(int_str(ys[0]))
594 println(int_str(ys[2]))
595 println(int_str(calls))
596 println(int_str(fixed[2]))
597}
598 ') or {
599 panic(err)
600 }
601 assert e.stdout() == '0\n2\n1\n5\n3\n2\n'
602}
603
604fn test_eval_fixed_array_init_uses_declared_len() {
605 mut e := create()
606 e.run_text('
607fn main() {
608 a := [3]int{}
609 b := [3]int{init: 5}
610 nested := [2][2]int{}
611 dynamic := [][2]int{}
612 println(int_str(a.len))
613 println(int_str(a[2]))
614 println(int_str(b.len))
615 println(int_str(b[1]))
616 println(int_str(nested[1][1]))
617 println(int_str(dynamic.len))
618}
619 ') or {
620 panic(err)
621 }
622 assert e.stdout() == '3\n0\n3\n5\n0\n0\n'
623}
624
625fn test_eval_fixed_array_init_resolves_const_len() {
626 mut e := create()
627 e.run_text('
628const n = 3
629
630struct Box {
631 xs [n]int
632}
633
634fn main() {
635 a := [n]int{}
636 b := [n]int{init: index}
637 box := Box{}
638 println(int_str(a.len))
639 println(int_str(a[2]))
640 println(int_str(b.len))
641 println(int_str(b[2]))
642 println(int_str(box.xs.len))
643 println(int_str(box.xs[2]))
644}
645 ') or {
646 panic(err)
647 }
648 assert e.stdout() == '3\n0\n3\n2\n3\n0\n'
649}
650
651fn test_eval_right_shift_compound_assignment() {
652 mut e := create()
653 e.run_text('
654fn main() {
655 mut x := 8
656 x >>= 1
657 println(int_str(x))
658}
659') or { panic(err) }
660 assert e.stdout() == '4\n'
661}
662
663fn test_eval_unsigned_right_shift_and_compound_assignment() {
664 mut e := create()
665 e.run_text('
666fn main() {
667 println(int_str(i64(-5) >>> 1))
668 mut x := i64(-5)
669 x >>>= 1
670 println(int_str(x))
671}
672') or {
673 panic(err)
674 }
675 assert e.stdout() == '9223372036854775805\n9223372036854775805\n'
676}
677
678fn test_eval_compound_index_target_evaluates_once() {
679 mut e := create()
680 e.run_text('
681fn next(mut i int) int {
682 old := i
683 i++
684 return old
685}
686
687fn main() {
688 mut xs := [1, 2]
689 mut i := 0
690 xs[next(mut i)] += 10
691 println(int_str(xs[0]))
692 println(int_str(xs[1]))
693 println(int_str(i))
694}
695 ') or {
696 panic(err)
697 }
698 assert e.stdout() == '11\n2\n1\n'
699}
700
701fn test_eval_selector_index_receiver_evaluates_once_on_write() {
702 mut e := create()
703 e.run_text('
704struct Item {
705mut:
706 x int
707}
708
709fn next(mut i int) int {
710 old := i
711 i++
712 return old
713}
714
715fn main() {
716 mut xs := [Item{x: 1}, Item{x: 2}]
717 mut i := 0
718 xs[next(mut i)].x = 5
719 println(int_str(xs[0].x))
720 println(int_str(xs[1].x))
721 println(int_str(i))
722}
723 ') or {
724 panic(err)
725 }
726 assert e.stdout() == '5\n2\n1\n'
727}
728
729fn test_eval_struct_method_and_map_update() {
730 mut e := create()
731 e.run_text("
732struct Point {
733 x int
734 y int
735}
736
737fn (p Point) sum() int {
738 return p.x + p.y
739}
740
741fn main() {
742 p := Point{x: 2, y: 5}
743 mut m := map[string]int{}
744 m['a'] = p.sum()
745 m['b'] += 3
746 println(int_str(m['a'] + m['b']))
747}
748") or {
749 panic(err)
750 }
751 assert e.stdout() == '10\n'
752}
753
754fn test_eval_static_method_dispatches_from_type_value() {
755 mut e := create()
756 e.run_text('
757struct Foo {
758 n int
759}
760
761fn Foo.new(n int) Foo {
762 return Foo{n: n}
763}
764
765fn main() {
766 foo := Foo.new(7)
767 println(int_str(foo.n))
768}
769 ') or {
770 panic(err)
771 }
772 assert e.stdout() == '7\n'
773}
774
775fn test_eval_overloaded_plus_operator_dispatches_method() {
776 mut e := create()
777 e.run_text('
778struct Number {
779 value int
780}
781
782fn (a Number) + (b Number) Number {
783 return Number{value: a.value + b.value}
784}
785
786fn main() {
787 c := Number{value: 2} + Number{value: 5}
788 println(int_str(c.value))
789}
790 ') or {
791 panic(err)
792 }
793 assert e.stdout() == '7\n'
794}
795
796fn test_eval_alias_receiver_method_dispatches_by_static_type() {
797 mut e := create()
798 e.run_text('
799type UserId = int
800
801fn (id UserId) next() int {
802 return int(id) + 1
803}
804
805fn main() {
806 id := UserId(1)
807 println(int_str(id.next()))
808 println(int_str(UserId(2).next()))
809}
810') or {
811 panic(err)
812 }
813 assert e.stdout() == '2\n3\n'
814}
815
816fn test_eval_typeof_name_selector_returns_type_name() {
817 mut e := create()
818 e.run_text('
819fn main() {
820 println(typeof(1).name)
821 println(typeof("x").name)
822}
823 ') or {
824 panic(err)
825 }
826 assert e.stdout() == 'int\nstring\n'
827}
828
829fn test_eval_map_delete_mutates_receiver() {
830 mut e := create()
831 e.run_text("
832 fn main() {
833 mut m := map[string]int{}
834 m['a'] = 7
835 m.delete('a')
836 println(int_str(m.len))
837 println('a' in m)
838 println(int_str(m['a']))
839}
840") or {
841 panic(err)
842 }
843 assert e.stdout() == '0\nfalse\n0\n'
844}
845
846fn test_eval_map_delete_index_receiver_evaluates_once() {
847 mut e := create()
848 e.run_text("
849 fn next(mut i int) int {
850 old := i
851 i++
852 return old
853 }
854
855 fn main() {
856 mut maps := []map[string]int{}
857 maps << map[string]int{'a': 1}
858 maps << map[string]int{'a': 2}
859 mut i := 0
860 maps[next(mut i)].delete('a')
861 println('a' in maps[0])
862 println('a' in maps[1])
863 println(int_str(i))
864 }
865 ") or {
866 panic(err)
867 }
868 assert e.stdout() == 'false\ntrue\n1\n'
869}
870
871fn test_eval_map_literal_adapts_sum_values() {
872 mut e := create()
873 e.run_text('
874 type Any = int | string
875
876fn main() {
877 m := map[string]Any{"a": 1, "b": "s"}
878 println(int_str(m["a"]._typ))
879 println(int_str(m["b"]._typ))
880}
881 ') or {
882 panic(err)
883 }
884 assert e.stdout() == '0\n1\n'
885}
886
887fn test_eval_map_literal_keys_use_declared_enum_type() {
888 mut e := create()
889 e.run_text('
890enum Color {
891 red
892}
893
894enum Other {
895 red = 10
896}
897
898fn main() {
899 m := map[Color]int{.red: 7}
900 println(int_str(m[Color.red]))
901 println(int_str(m[.red] or { 0 }))
902}
903 ') or {
904 panic(err)
905 }
906 assert e.stdout() == '7\n7\n'
907}
908
909fn test_eval_container_methods_use_declared_enum_arg_type() {
910 mut e := create()
911 e.run_text('
912enum Color {
913 red
914 blue
915}
916
917enum Other {
918 red = 10
919}
920
921fn main() {
922 mut m := map[Color]int{.red: 1}
923 m.delete(.red)
924 println(int_str(m.len))
925 xs := [Color.red, Color.blue]
926 println(xs.contains(.red))
927 println(int_str(xs.index(.red)))
928}
929 ') or {
930 panic(err)
931 }
932 assert e.stdout() == '0\ntrue\n0\n'
933}
934
935fn test_eval_map_literal_value_flow_propagates_return() {
936 mut e := create()
937 e.run_text('
938fn maybe() ?int {
939 return none
940}
941
942fn run() map[string]int {
943 return {
944 "a": maybe() or {
945 return {
946 "b": 7
947 }
948 }
949 }
950}
951
952fn main() {
953 m := run()
954 println(int_str(m["b"]))
955 println(int_str(m["a"]))
956}
957 ') or {
958 panic(err)
959 }
960 assert e.stdout() == '7\n0\n'
961}
962
963fn test_eval_map_lookup_adapts_sum_keys() {
964 mut e := create()
965 e.run_text('
966type Any = int | string
967
968fn main() {
969 m := map[Any]int{1: 2, "s": 3}
970 println(int_str(m[1]))
971 println(int_str(m["s"]))
972}
973 ') or {
974 panic(err)
975 }
976 assert e.stdout() == '2\n3\n'
977}
978
979fn test_eval_indexed_writes_adapt_sum_values() {
980 mut e := create()
981 e.run_text('
982type Any = int | string
983
984fn main() {
985 mut xs := []Any{len: 2}
986 xs[0] = 1
987 xs[1] = "s"
988 println(int_str(xs[0]._typ))
989 println(int_str(xs[1]._typ))
990
991 mut m := map[string]Any{}
992 m["a"] = 1
993 m["b"] = "s"
994 println(int_str(m["a"]._typ))
995 println(int_str(m["b"]._typ))
996}
997 ') or {
998 panic(err)
999 }
1000 assert e.stdout() == '0\n1\n0\n1\n'
1001}
1002
1003fn test_eval_index_assignment_lhs_index_propagates_return() {
1004 mut e := create()
1005 e.run_text('
1006fn idx() ?int {
1007 return none
1008}
1009
1010fn run() int {
1011 mut xs := [0]
1012 xs[idx() or {
1013 return 7
1014 }] = 1
1015 return xs[0]
1016}
1017
1018fn main() {
1019 println(int_str(run()))
1020}
1021 ') or {
1022 panic(err)
1023 }
1024 assert e.stdout() == '7\n'
1025}
1026
1027fn test_eval_postfix_index_target_evaluates_once() {
1028 mut e := create()
1029 e.run_text('
1030fn next(mut i int) int {
1031 old := i
1032 i++
1033 return old
1034}
1035
1036fn main() {
1037 mut xs := [1, 2]
1038 mut i := 0
1039 old := xs[next(mut i)]++
1040 println(int_str(old))
1041 println(int_str(xs[0]))
1042 println(int_str(xs[1]))
1043 println(int_str(i))
1044}
1045 ') or {
1046 panic(err)
1047 }
1048 assert e.stdout() == '1\n2\n2\n1\n'
1049}
1050
1051fn test_eval_postfix_index_target_propagates_flow() {
1052 mut e := create()
1053 e.run_text('
1054fn idx() ?int {
1055 return none
1056}
1057
1058fn run() int {
1059 mut xs := [0]
1060 xs[idx() or {
1061 return 7
1062 }]++
1063 return xs[0]
1064}
1065
1066fn main() {
1067 println(int_str(run()))
1068}
1069 ') or {
1070 panic(err)
1071 }
1072 assert e.stdout() == '7\n'
1073}
1074
1075fn test_eval_array_literal_preserves_element_type_for_sum_checks() {
1076 mut e := create()
1077 e.run_text('
1078type Any = []int | string
1079
1080fn main() {
1081 x := Any([1, 2])
1082 println(x is []int)
1083}
1084 ') or {
1085 panic(err)
1086 }
1087 assert e.stdout() == 'true\n'
1088}
1089
1090fn test_eval_shorthand_map_literal_infers_key_value_types() {
1091 mut e := create()
1092 e.run_text('
1093fn main() {
1094 m := {"a": 1}
1095 println(int_str(m["a"]))
1096 println(int_str(m["missing"]))
1097}
1098 ') or {
1099 panic(err)
1100 }
1101 assert e.stdout() == '1\n0\n'
1102}
1103
1104fn test_eval_typed_map_target_adapts_entries() {
1105 mut e := create()
1106 e.run_text('
1107type Any = int | string
1108
1109struct S {
1110 m map[string]Any
1111}
1112
1113fn main() {
1114 s := S{
1115 m: {
1116 "a": 1
1117 "b": "s"
1118 }
1119 }
1120 println(int_str(s.m["a"]._typ))
1121 println(int_str(s.m["b"]._typ))
1122}
1123 ') or {
1124 panic(err)
1125 }
1126 assert e.stdout() == '0\n1\n'
1127}
1128
1129fn test_eval_mut_receiver_method_updates_original() {
1130 mut e := create()
1131 e.run_text('
1132struct Point {
1133mut:
1134 x int
1135}
1136
1137fn (mut p Point) inc() int {
1138 p.x += 1
1139 return p.x
1140}
1141
1142fn main() {
1143 mut p := Point{x: 1}
1144 println(int_str(p.inc()))
1145 println(int_str(p.x))
1146}
1147') or {
1148 panic(err)
1149 }
1150 assert e.stdout() == '2\n2\n'
1151}
1152
1153fn test_eval_mut_function_arg_updates_original() {
1154 mut e := create()
1155 e.run_text('
1156fn inc(mut x int) {
1157 x++
1158}
1159
1160fn main() {
1161 mut a := 1
1162 inc(mut a)
1163 println(int_str(a))
1164}
1165') or {
1166 panic(err)
1167 }
1168 assert e.stdout() == '2\n'
1169}
1170
1171fn test_eval_mut_index_argument_writes_back_once() {
1172 mut e := create()
1173 e.run_text('
1174fn next(mut i int) int {
1175 old := i
1176 i++
1177 return old
1178}
1179
1180fn inc(mut x int) {
1181 x++
1182}
1183
1184fn main() {
1185 mut xs := [1, 2]
1186 mut i := 0
1187 inc(mut xs[next(mut i)])
1188 println(int_str(xs[0]))
1189 println(int_str(xs[1]))
1190 println(int_str(i))
1191}
1192') or {
1193 panic(err)
1194 }
1195 assert e.stdout() == '2\n2\n1\n'
1196}
1197
1198fn test_eval_mut_function_literal_arg_updates_original() {
1199 mut e := create()
1200 e.run_text('
1201fn main() {
1202 f := fn (mut x int) {
1203 x++
1204 }
1205 mut a := 1
1206 f(mut a)
1207 println(int_str(a))
1208}
1209') or {
1210 panic(err)
1211 }
1212 assert e.stdout() == '2\n'
1213}
1214
1215fn test_eval_function_literal_arg_adapts_to_sum_param() {
1216 mut e := create()
1217 e.run_text('
1218type Any = int | string
1219
1220fn main() {
1221 f := fn (x Any) {
1222 println(int_str(x._typ))
1223 }
1224 f(1)
1225}
1226 ') or {
1227 panic(err)
1228 }
1229 assert e.stdout() == '0\n'
1230}
1231
1232fn test_eval_variadic_arguments_pack_into_array() {
1233 mut e := create()
1234 e.run_text('
1235fn count(xs ...int) int {
1236 return xs.len
1237}
1238
1239fn sum(seed int, xs ...int) int {
1240 mut total := seed
1241 for x in xs {
1242 total += x
1243 }
1244 return total
1245}
1246
1247fn main() {
1248 println(int_str(count()))
1249 println(int_str(count(1, 2)))
1250 println(int_str(sum(10, 1, 2, 3)))
1251 f := fn (xs ...int) int {
1252 return xs.len
1253 }
1254 println(int_str(f(4, 5, 6)))
1255}
1256 ') or {
1257 panic(err)
1258 }
1259 assert e.stdout() == '0\n2\n16\n3\n'
1260}
1261
1262fn test_eval_function_literal_captures_escaping_scope() {
1263 mut e := create()
1264 e.run_text('
1265fn make() fn () int {
1266 x := 7
1267 return fn [x] () int {
1268 return x
1269 }
1270}
1271
1272fn main() {
1273 f := make()
1274 println(int_str(f()))
1275}
1276 ') or {
1277 panic(err)
1278 }
1279 assert e.stdout() == '7\n'
1280}
1281
1282fn test_eval_mut_function_literal_capture_persists_between_calls() {
1283 mut e := create()
1284 e.run_text('
1285fn new_counter() fn () int {
1286 mut i := 0
1287 return fn [mut i] () int {
1288 i++
1289 return i
1290 }
1291}
1292
1293fn main() {
1294 counter := new_counter()
1295 println(int_str(counter()))
1296 println(int_str(counter()))
1297}
1298 ') or {
1299 panic(err)
1300 }
1301 assert e.stdout() == '1\n2\n'
1302}
1303
1304fn test_eval_mut_closure_param_preserves_capture_state() {
1305 mut e := create()
1306 e.run_text('
1307fn new_counter() fn () int {
1308 mut i := 0
1309 return fn [mut i] () int {
1310 i++
1311 return i
1312 }
1313}
1314
1315fn use(f fn () int) {
1316 println(int_str(f()))
1317 println(int_str(f()))
1318}
1319
1320fn main() {
1321 counter := new_counter()
1322 use(counter)
1323 println(int_str(counter()))
1324}
1325 ') or {
1326 panic(err)
1327 }
1328 assert e.stdout() == '1\n2\n3\n'
1329}
1330
1331fn test_eval_function_valued_selector_call_updates_captures() {
1332 mut e := create()
1333 e.run_text('
1334struct S {
1335 f fn () int
1336}
1337
1338fn new_counter() fn () int {
1339 mut i := 0
1340 return fn [mut i] () int {
1341 i++
1342 return i
1343 }
1344}
1345
1346fn main() {
1347 mut s := S{
1348 f: new_counter()
1349 }
1350 println(int_str(s.f()))
1351 println(int_str(s.f()))
1352}
1353 ') or {
1354 panic(err)
1355 }
1356 assert e.stdout() == '1\n2\n'
1357}
1358
1359fn test_eval_mut_method_arg_updates_original() {
1360 mut e := create()
1361 e.run_text('
1362struct S {}
1363
1364fn (s S) inc(mut x int) {
1365 x++
1366}
1367
1368fn main() {
1369 s := S{}
1370 mut a := 1
1371 s.inc(mut a)
1372 println(int_str(a))
1373}
1374') or {
1375 panic(err)
1376 }
1377 assert e.stdout() == '2\n'
1378}
1379
1380fn test_eval_multi_return_assignment_spreads_tuple() {
1381 mut e := create()
1382 e.run_text("
1383fn pair() (int, string) {
1384 return 2, 'ok'
1385}
1386
1387fn main() {
1388 a, b := pair()
1389 println(int_str(a))
1390 println(b)
1391}
1392") or {
1393 panic(err)
1394 }
1395 assert e.stdout() == '2\nok\n'
1396}
1397
1398fn test_eval_multi_return_assignment_spreads_three_value_tuple() {
1399 mut e := create()
1400 e.run_text("
1401fn triple() (int, string, int) {
1402 return 1, 'two', 3
1403}
1404
1405fn main() {
1406 a, b, c := triple()
1407 println(int_str(a))
1408 println(b)
1409 println(int_str(c))
1410}
1411") or {
1412 panic(err)
1413 }
1414 assert e.stdout() == '1\ntwo\n3\n'
1415}
1416
1417fn test_eval_multi_return_adapts_items_to_declared_types() {
1418 mut e := create()
1419 e.run_text('
1420type Any = int | string
1421
1422fn pair() (Any, Any) {
1423 return 1, "s"
1424}
1425
1426fn main() {
1427 a, b := pair()
1428 println(int_str(a._typ))
1429 println(int_str(b._typ))
1430}
1431 ') or {
1432 panic(err)
1433 }
1434 assert e.stdout() == '0\n1\n'
1435}
1436
1437fn test_eval_imported_return_adapts_in_callee_module() {
1438 dir := os.join_path(os.temp_dir(), 'v3_eval_import_return_${os.getpid()}')
1439 os.rmdir_all(dir) or {}
1440 os.mkdir_all(dir) or { panic(err) }
1441 defer {
1442 os.rmdir_all(dir) or {}
1443 }
1444 main_file := os.join_path(dir, 'main.v')
1445 mod_file := os.join_path(dir, 'm.v')
1446 os.write_file(mod_file, '
1447module m
1448
1449pub type Any = int | string
1450
1451pub fn make() Any {
1452 return 1
1453}
1454 ') or {
1455 panic(err)
1456 }
1457 os.write_file(main_file, '
1458module main
1459
1460import m
1461
1462fn main() {
1463 x := m.make()
1464 println(int_str(x._typ))
1465 if x is int {
1466 println("int")
1467 }
1468}
1469 ') or {
1470 panic(err)
1471 }
1472 mut e := create()
1473 mut p := parser.Parser.new(&e.prefs)
1474 p.parse_files([main_file, mod_file])
1475 e.run_files(p.a) or { panic(err) }
1476 assert e.stdout() == '0\nint\n'
1477}
1478
1479fn test_eval_imported_array_return_qualifies_element_type() {
1480 dir := os.join_path(os.temp_dir(), 'v3_eval_import_array_return_${os.getpid()}')
1481 os.rmdir_all(dir) or {}
1482 os.mkdir_all(dir) or { panic(err) }
1483 defer {
1484 os.rmdir_all(dir) or {}
1485 }
1486 main_file := os.join_path(dir, 'main.v')
1487 mod_file := os.join_path(dir, 'm.v')
1488 os.write_file(mod_file, '
1489module m
1490
1491pub struct Item {}
1492
1493pub fn items() []Item {
1494 return [Item{}]
1495}
1496 ') or {
1497 panic(err)
1498 }
1499 os.write_file(main_file, '
1500module main
1501
1502import m
1503
1504fn main() {
1505 mut xs := m.items()
1506 xs << [m.Item{}, m.Item{}]
1507 println(int_str(xs.len))
1508}
1509 ') or {
1510 panic(err)
1511 }
1512 mut e := create()
1513 mut p := parser.Parser.new(&e.prefs)
1514 p.parse_files([main_file, mod_file])
1515 e.run_files(p.a) or { panic(err) }
1516 assert e.stdout() == '3\n'
1517}
1518
1519fn test_eval_imported_struct_field_default_adapts_in_declaring_module() {
1520 dir := os.join_path(os.temp_dir(), 'v3_eval_import_field_default_${os.getpid()}')
1521 os.rmdir_all(dir) or {}
1522 os.mkdir_all(dir) or { panic(err) }
1523 defer {
1524 os.rmdir_all(dir) or {}
1525 }
1526 main_file := os.join_path(dir, 'main.v')
1527 mod_file := os.join_path(dir, 'm.v')
1528 os.write_file(mod_file, '
1529module m
1530
1531pub struct A {}
1532
1533pub type Any = A | string
1534
1535pub struct Box {
1536pub:
1537 x Any = A{}
1538}
1539 ') or {
1540 panic(err)
1541 }
1542 os.write_file(main_file, '
1543module main
1544
1545import m
1546
1547fn main() {
1548 box := m.Box{}
1549 println(int_str(box.x._typ))
1550 if box.x is m.A {
1551 println("a")
1552 }
1553}
1554 ') or {
1555 panic(err)
1556 }
1557 mut e := create()
1558 mut p := parser.Parser.new(&e.prefs)
1559 p.parse_files([main_file, mod_file])
1560 e.run_files(p.a) or { panic(err) }
1561 assert e.stdout() == '0\na\n'
1562}
1563
1564fn test_eval_imported_struct_field_container_type_uses_declaring_module() {
1565 dir := os.join_path(os.temp_dir(), 'v3_eval_import_field_container_${os.getpid()}')
1566 os.rmdir_all(dir) or {}
1567 os.mkdir_all(dir) or { panic(err) }
1568 defer {
1569 os.rmdir_all(dir) or {}
1570 }
1571 main_file := os.join_path(dir, 'main.v')
1572 mod_file := os.join_path(dir, 'm.v')
1573 os.write_file(mod_file, '
1574module m
1575
1576pub struct Item {}
1577
1578pub struct Box {
1579pub mut:
1580 xs []Item
1581}
1582 ') or {
1583 panic(err)
1584 }
1585 os.write_file(main_file, '
1586module main
1587
1588import m
1589
1590fn main() {
1591 box := m.Box{xs: [m.Item{}]}
1592 mut xs := box.xs
1593 xs << [m.Item{}, m.Item{}]
1594 println(int_str(xs.len))
1595}
1596 ') or {
1597 panic(err)
1598 }
1599 mut e := create()
1600 mut p := parser.Parser.new(&e.prefs)
1601 p.parse_files([main_file, mod_file])
1602 e.run_files(p.a) or { panic(err) }
1603 assert e.stdout() == '3\n'
1604}
1605
1606fn test_eval_value_block_preserves_multi_return_values() {
1607 mut e := create()
1608 e.run_text("
1609fn choose(ok bool) (int, string) {
1610 return if ok { 1, 'a' } else { 2, 'b' }
1611}
1612
1613fn main() {
1614 a, b := choose(true)
1615 c, d := choose(false)
1616 println('\${a}:\${b}:\${c}:\${d}')
1617}
1618") or {
1619 panic(err)
1620 }
1621 assert e.stdout() == '1:a:2:b\n'
1622}
1623
1624fn test_eval_value_block_uses_last_sequential_expression_value() {
1625 mut e := create()
1626 e.run_text('
1627 fn trace() int {
1628 return 1
1629 }
1630
1631 fn choose(ok bool) int {
1632 return if ok {
1633 trace()
1634 2
1635 } else {
1636 3
1637 }
1638}
1639
1640fn main() {
1641 println(int_str(choose(true)))
1642 println(int_str(choose(false)))
1643}
1644 ') or {
1645 panic(err)
1646 }
1647 assert e.stdout() == '2\n3\n'
1648}
1649
1650fn test_eval_multi_assign_preserves_rhs_values() {
1651 mut e := create()
1652 e.run_text('
1653fn main() {
1654 mut a := 1
1655 mut b := 2
1656 a, b = b, a
1657 println(int_str(a))
1658 println(int_str(b))
1659}
1660') or {
1661 panic(err)
1662 }
1663 assert e.stdout() == '2\n1\n'
1664}
1665
1666fn test_eval_multi_assign_propagates_rhs_flow() {
1667 mut e := create()
1668 e.run_text('
1669fn maybe_pair() ?(int, int) {
1670 return none
1671}
1672
1673fn run() int {
1674 a, b := maybe_pair() or {
1675 return 7
1676 }
1677 return a + b
1678}
1679
1680fn main() {
1681 println(int_str(run()))
1682}
1683 ') or {
1684 panic(err)
1685 }
1686 assert e.stdout() == '7\n'
1687}
1688
1689fn test_eval_struct_equality_compares_fields() {
1690 mut e := create()
1691 e.run_text('
1692struct Point {
1693 x int
1694}
1695
1696fn main() {
1697 a := Point{x: 1}
1698 b := Point{x: 2}
1699 c := Point{x: 1}
1700 println(a == b)
1701 println(a == c)
1702}
1703') or {
1704 panic(err)
1705 }
1706 assert e.stdout() == 'false\ntrue\n'
1707}
1708
1709fn test_eval_scopes_enum_constants_by_enum_type() {
1710 mut e := create()
1711 e.run_text('
1712enum A {
1713 x
1714}
1715
1716enum B {
1717 x = 10
1718}
1719
1720fn main() {
1721 println(int_str(A.x))
1722 println(int_str(B.x))
1723}
1724') or {
1725 panic(err)
1726 }
1727 assert e.stdout() == '0\n10\n'
1728}
1729
1730fn test_eval_enum_selector_preserves_sum_variant_type() {
1731 mut e := create()
1732 e.run_text('
1733enum Test {
1734 abc
1735}
1736
1737type SumTest = Test | u8
1738
1739fn main() {
1740 b := SumTest(Test.abc)
1741 println(b is Test)
1742 println(b is u8)
1743}
1744 ') or {
1745 panic(err)
1746 }
1747 assert e.stdout() == 'true\nfalse\n'
1748}
1749
1750fn test_eval_match_shorthand_enum_uses_target_enum_type() {
1751 mut e := create()
1752 e.run_text('
1753enum A {
1754 x
1755}
1756
1757enum B {
1758 x = 10
1759}
1760
1761fn main() {
1762 match A.x {
1763 .x {
1764 println("a")
1765 }
1766 else {
1767 println("bad")
1768 }
1769 }
1770}
1771') or {
1772 panic(err)
1773 }
1774 assert e.stdout() == 'a\n'
1775}
1776
1777fn test_eval_match_shorthand_enum_uses_tracked_var_type() {
1778 mut e := create()
1779 e.run_text('
1780enum A {
1781 x
1782}
1783
1784enum B {
1785 x = 10
1786}
1787
1788fn main() {
1789 a := A.x
1790 match a {
1791 .x {
1792 println("a")
1793 }
1794 else {
1795 println("bad")
1796 }
1797 }
1798}
1799') or {
1800 panic(err)
1801 }
1802 assert e.stdout() == 'a\n'
1803}
1804
1805fn test_eval_enum_zero_values_use_first_field() {
1806 mut e := create()
1807 e.run_text('
1808 enum Color {
1809 red
1810 blue
1811}
1812
1813struct S {
1814 c Color
1815}
1816
1817__global g Color
1818
1819fn main() {
1820 s := S{}
1821 arr := [2]Color{}
1822 m := map[string]Color{}
1823 println(s.c == Color.red)
1824 println(g == Color.red)
1825 println(arr[0] == Color.red)
1826 println(m["missing"] == Color.red)
1827}
1828 ') or {
1829 panic(err)
1830 }
1831 assert e.stdout() == 'true\ntrue\ntrue\ntrue\n'
1832}
1833
1834fn test_eval_enum_cast_preserves_enum_identity() {
1835 mut e := create()
1836 e.run_text('
1837 enum Color {
1838 red
1839 blue
1840 }
1841
1842 type Any = Color | int
1843
1844 fn main() {
1845 c := Color(1)
1846 x := Any(Color(1))
1847 println(c == Color.blue)
1848 println(c)
1849 println(x is Color)
1850 }
1851 ') or {
1852 panic(err)
1853 }
1854 assert e.stdout() == 'true\nblue\ntrue\n'
1855}
1856
1857fn test_eval_global_assignment_uses_declared_type() {
1858 mut e := create()
1859 e.run_text('
1860 enum State {
1861 idle
1862 busy
1863}
1864
1865__global state State
1866
1867fn main() {
1868 state = .busy
1869 println(state)
1870}
1871 ') or {
1872 panic(err)
1873 }
1874 assert e.stdout() == 'busy\n'
1875}
1876
1877fn test_eval_enum_shorthand_return_preserves_enum_type() {
1878 mut e := create()
1879 e.run_text('
1880enum Color {
1881 red
1882 blue
1883}
1884
1885type Any = Color | int
1886
1887fn color() Color {
1888 return .red
1889}
1890
1891fn main() {
1892 c := color()
1893 x := Any(c)
1894 println(c == Color.red)
1895 println(x is Color)
1896 println(int_str(x._typ))
1897}
1898 ') or {
1899 panic(err)
1900 }
1901 assert e.stdout() == 'true\ntrue\n0\n'
1902}
1903
1904fn test_eval_enum_shorthand_return_uses_expected_type_in_value_branches() {
1905 mut e := create()
1906 e.run_text('
1907enum Color {
1908 red = 10
1909 blue = 20
1910}
1911
1912enum Other {
1913 red = 1
1914 blue = 2
1915}
1916
1917fn pick_if(b bool) Color {
1918 return if b {
1919 .red
1920 } else {
1921 .blue
1922 }
1923}
1924
1925fn pick_match(n int) Color {
1926 return match n {
1927 0 {
1928 .red
1929 }
1930 else {
1931 .blue
1932 }
1933 }
1934}
1935
1936fn main() {
1937 println(pick_if(true) == Color.red)
1938 println(pick_if(false) == Color.blue)
1939 println(pick_match(0) == Color.red)
1940 println(pick_match(1) == Color.blue)
1941}
1942 ') or {
1943 panic(err)
1944 }
1945 assert e.stdout() == 'true\ntrue\ntrue\ntrue\n'
1946}
1947
1948fn test_eval_enum_shorthand_uses_typed_call_and_struct_contexts() {
1949 mut e := create()
1950 e.run_text('
1951enum A {
1952 x
1953}
1954
1955enum B {
1956 x = 10
1957}
1958
1959struct S {
1960 c A
1961}
1962
1963fn take_a(a A) int {
1964 return int(a)
1965}
1966
1967fn main() {
1968 s := S{c: .x}
1969 println(int_str(take_a(.x)))
1970 println(int_str(s.c))
1971}
1972 ') or {
1973 panic(err)
1974 }
1975 assert e.stdout() == '0\n0\n'
1976}
1977
1978fn test_eval_imported_function_param_hints_are_qualified() {
1979 dir := os.join_path(os.temp_dir(), 'v3_eval_import_param_hint_${os.getpid()}')
1980 os.rmdir_all(dir) or {}
1981 os.mkdir_all(dir) or { panic(err) }
1982 defer {
1983 os.rmdir_all(dir) or {}
1984 }
1985 main_file := os.join_path(dir, 'main.v')
1986 mod_file := os.join_path(dir, 'm.v')
1987 os.write_file(mod_file, '
1988module m
1989
1990pub enum Color {
1991 red
1992 blue
1993}
1994
1995pub fn take(c Color) string {
1996 if c == Color.red {
1997 return "m-red"
1998 }
1999 return "wrong"
2000}
2001 ') or {
2002 panic(err)
2003 }
2004 os.write_file(main_file, '
2005module main
2006
2007import m
2008
2009enum Other {
2010 red = 10
2011}
2012
2013fn main() {
2014 println(m.take(.red))
2015}
2016 ') or {
2017 panic(err)
2018 }
2019 mut e := create()
2020 mut p := parser.Parser.new(&e.prefs)
2021 p.parse_files([main_file, mod_file])
2022 e.run_files(p.a) or { panic(err) }
2023 assert e.stdout() == 'm-red\n'
2024}
2025
2026fn test_eval_imported_fn_value_param_hints_are_qualified() {
2027 dir := os.join_path(os.temp_dir(), 'v3_eval_import_fn_value_hint_${os.getpid()}')
2028 os.rmdir_all(dir) or {}
2029 os.mkdir_all(dir) or { panic(err) }
2030 defer {
2031 os.rmdir_all(dir) or {}
2032 }
2033 main_file := os.join_path(dir, 'main.v')
2034 mod_file := os.join_path(dir, 'm.v')
2035 os.write_file(mod_file, '
2036module m
2037
2038pub enum Color {
2039 red
2040 blue
2041}
2042
2043pub fn make_taker() fn (Color) string {
2044 return fn (c Color) string {
2045 if c == Color.red {
2046 return "m-red"
2047 }
2048 return "wrong"
2049 }
2050}
2051 ') or {
2052 panic(err)
2053 }
2054 os.write_file(main_file, '
2055module main
2056
2057import m
2058
2059enum Other {
2060 red = 10
2061}
2062
2063fn main() {
2064 f := m.make_taker()
2065 println(f(.red))
2066}
2067 ') or {
2068 panic(err)
2069 }
2070 mut e := create()
2071 mut p := parser.Parser.new(&e.prefs)
2072 p.parse_files([main_file, mod_file])
2073 e.run_files(p.a) or { panic(err) }
2074 assert e.stdout() == 'm-red\n'
2075}
2076
2077fn test_eval_match_range_patterns_are_inclusive() {
2078 mut e := create()
2079 e.run_text('
2080fn classify_stmt(n int) string {
2081 mut out := ""
2082 match n {
2083 1...3 {
2084 out = "range"
2085 }
2086 else {
2087 out = "other"
2088 }
2089 }
2090 return out
2091}
2092
2093fn classify_expr(n int) string {
2094 return match n {
2095 1...3 {
2096 "range"
2097 }
2098 else {
2099 "other"
2100 }
2101 }
2102}
2103
2104fn main() {
2105 println(classify_stmt(3))
2106 println(classify_expr(1))
2107 println(classify_expr(4))
2108}
2109 ') or {
2110 panic(err)
2111 }
2112 assert e.stdout() == 'range\nrange\nother\n'
2113}
2114
2115fn test_eval_match_primitive_sum_branches_are_type_patterns() {
2116 mut e := create()
2117 e.run_text('
2118 type Any = int | string
2119
2120fn classify(x Any) string {
2121 return match x {
2122 int {
2123 "int"
2124 }
2125 string {
2126 "string"
2127 }
2128 else {
2129 "other"
2130 }
2131 }
2132}
2133
2134fn main() {
2135 println(classify(1))
2136 println(classify("s"))
2137}
2138 ') or {
2139 panic(err)
2140 }
2141 assert e.stdout() == 'int\nstring\n'
2142}
2143
2144fn test_eval_match_value_pattern_is_not_type_pattern() {
2145 mut e := create()
2146 e.run_text('
2147 type Any = int | string
2148
2149 fn classify(x Any) string {
2150 return match x {
2151 "int" {
2152 "literal"
2153 }
2154 int {
2155 "type"
2156 }
2157 else {
2158 "other"
2159 }
2160 }
2161 }
2162
2163 fn main() {
2164 println(classify(1))
2165 }
2166 ') or {
2167 panic(err)
2168 }
2169 assert e.stdout() == 'type\n'
2170}
2171
2172fn test_eval_sum_smartcasts_bind_branch_payloads() {
2173 mut e := create()
2174 e.run_text('
2175 type Any = int | string
2176
2177fn if_cast(x Any) int {
2178 if x is int {
2179 return x + 1
2180 }
2181 return 0
2182}
2183
2184fn match_cast(x Any) int {
2185 return match x {
2186 int {
2187 x + 2
2188 }
2189 else {
2190 0
2191 }
2192 }
2193}
2194
2195fn main() {
2196 println(int_str(if_cast(1)))
2197 println(int_str(if_cast("s")))
2198 println(int_str(match_cast(1)))
2199 println(int_str(match_cast("s")))
2200}
2201 ') or {
2202 panic(err)
2203 }
2204 assert e.stdout() == '2\n0\n3\n0\n'
2205}
2206
2207fn test_eval_logical_and_rhs_uses_is_smartcast() {
2208 mut e := create()
2209 e.run_text('
2210type Any = int | string
2211
2212fn positive(x Any) bool {
2213 return x is int && x > 0
2214}
2215
2216fn main() {
2217 println(positive(2))
2218 println(positive(-1))
2219 println(positive("s"))
2220}
2221 ') or {
2222 panic(err)
2223 }
2224 assert e.stdout() == 'true\nfalse\nfalse\n'
2225}
2226
2227fn test_eval_calls_function_value_from_identifier() {
2228 mut e := create()
2229 e.run_text('
2230fn main() {
2231 f := fn () int {
2232 return 1
2233 }
2234 println(int_str(f()))
2235}
2236') or {
2237 panic(err)
2238 }
2239 assert e.stdout() == '1\n'
2240}
2241
2242fn test_eval_prefix_minus_preserves_float() {
2243 mut e := create()
2244 e.run_text('
2245fn main() {
2246 x := 1.5
2247 println(-1.5)
2248 println(-x)
2249}
2250 ') or { panic(err) }
2251 assert e.stdout() == '-1.5\n-1.5\n'
2252}
2253
2254fn test_eval_mixed_numeric_equality_compares_as_float() {
2255 mut e := create()
2256 e.run_text('
2257fn main() {
2258 println(1 == 1.5)
2259 println(1.5 == 1)
2260 println(1 == 1.0)
2261 println(1.0 == 1)
2262 println(1 != 1.5)
2263}
2264') or {
2265 panic(err)
2266 }
2267 assert e.stdout() == 'false\nfalse\ntrue\ntrue\ntrue\n'
2268}
2269
2270fn test_eval_number_literals_strip_separators() {
2271 mut e := create()
2272 e.run_text('
2273fn main() {
2274 println(int_str(1_234))
2275 println(int_str(0x1_f))
2276 println(1_234.5 == 1234.5)
2277}
2278 ') or {
2279 panic(err)
2280 }
2281 assert e.stdout() == '1234\n31\ntrue\n'
2282}
2283
2284fn test_eval_sum_numeric_as_cast_unwraps_payload() {
2285 mut e := create()
2286 e.run_text('
2287type Any = int | string
2288
2289fn main() {
2290 x := Any(7)
2291 println(int_str(x as int))
2292}
2293 ') or {
2294 panic(err)
2295 }
2296 assert e.stdout() == '7\n'
2297}
2298
2299fn test_eval_alias_field_zero_value_uses_underlying_type() {
2300 mut e := create()
2301 e.run_text('
2302type UserId = int
2303
2304struct S {
2305 id UserId
2306}
2307
2308fn main() {
2309 println(int_str(S{}.id))
2310}
2311 ') or {
2312 panic(err)
2313 }
2314 assert e.stdout() == '0\n'
2315}
2316
2317fn test_eval_alias_to_sum_param_adapts_argument() {
2318 mut e := create()
2319 e.run_text('
2320type Any = int | string
2321type Alias = Any
2322
2323fn variant(x Alias) int {
2324 return x._typ
2325}
2326
2327fn main() {
2328 println(int_str(variant(1)))
2329 println(int_str(variant("s")))
2330}
2331 ') or {
2332 panic(err)
2333 }
2334 assert e.stdout() == '0\n1\n'
2335}
2336
2337fn test_eval_struct_field_writes_adapt_sum_values() {
2338 mut e := create()
2339 e.run_text('
2340type Any = int | string
2341
2342struct S {
2343mut:
2344 a Any
2345}
2346
2347fn main() {
2348 mut s := S{}
2349 s.a = 1
2350 println(int_str(s.a._typ))
2351 s.a = "s"
2352 println(int_str(s.a._typ))
2353}
2354 ') or {
2355 panic(err)
2356 }
2357 assert e.stdout() == '0\n1\n'
2358}
2359
2360fn test_eval_struct_init_fields_adapt_sum_values() {
2361 mut e := create()
2362 e.run_text('
2363type Any = int | string
2364
2365struct S {
2366 a Any
2367 b Any
2368}
2369
2370fn main() {
2371 s := S{a: 1, b: "s"}
2372 println(int_str(s.a._typ))
2373 println(int_str(s.b._typ))
2374 t := S{
2375 ...s
2376 a: "x"
2377 }
2378 println(int_str(t.a._typ))
2379}
2380 ') or {
2381 panic(err)
2382 }
2383 assert e.stdout() == '0\n1\n1\n'
2384}
2385
2386fn test_eval_defer_runs_before_function_return() {
2387 mut e := create()
2388 e.run_text('
2389fn run() int {
2390 defer {
2391 println("first")
2392 }
2393 defer {
2394 println("second")
2395 }
2396 println("body")
2397 return 7
2398}
2399
2400fn main() {
2401 println(int_str(run()))
2402}
2403') or {
2404 panic(err)
2405 }
2406 assert e.stdout() == 'body\nsecond\nfirst\n7\n'
2407}
2408
2409fn test_eval_scoped_defers_run_at_scope_exit() {
2410 mut e := create()
2411 e.run_text('
2412fn main() {
2413 mut out := ""
2414 if true {
2415 defer {
2416 out += "d"
2417 }
2418 out += "b"
2419 }
2420 out += "a"
2421 for i in 0 .. 2 {
2422 defer {
2423 out += int_str(i)
2424 }
2425 out += "i"
2426 }
2427 println(out)
2428}
2429 ') or {
2430 panic(err)
2431 }
2432 assert e.stdout() == 'bdai0i1\n'
2433}
2434
2435fn test_eval_defer_fn_runs_at_function_exit() {
2436 mut e := create()
2437 e.run_text('
2438__global hit int
2439
2440fn run() {
2441 for _ in 0 .. 2 {
2442 defer(fn) {
2443 hit += 100
2444 }
2445 println(int_str(hit))
2446 hit++
2447 }
2448 println(int_str(hit))
2449}
2450
2451fn main() {
2452 run()
2453 println(int_str(hit))
2454}
2455 ') or {
2456 panic(err)
2457 }
2458 assert e.stdout() == '0\n1\n2\n202\n'
2459}
2460
2461fn test_eval_or_block_return_propagates() {
2462 mut e := create()
2463 e.run_text('
2464fn maybe() ?int {
2465 return none
2466}
2467
2468fn run() int {
2469 _ := maybe() or {
2470 return 1
2471 }
2472 return 2
2473}
2474
2475fn main() {
2476 println(int_str(run()))
2477}
2478') or {
2479 panic(err)
2480 }
2481 assert e.stdout() == '1\n'
2482}
2483
2484fn test_eval_optional_bool_return_wraps_false_payload() {
2485 mut e := create()
2486 e.run_text('
2487fn maybe() ?bool {
2488 return false
2489}
2490
2491fn run_or() bool {
2492 return maybe() or {
2493 return true
2494 }
2495}
2496
2497fn run_guard() string {
2498 if v := maybe() {
2499 if v {
2500 return "true"
2501 }
2502 return "false"
2503 }
2504 return "none"
2505}
2506
2507fn main() {
2508 println(run_or())
2509 println(run_guard())
2510}
2511 ') or {
2512 panic(err)
2513 }
2514 assert e.stdout() == 'false\nfalse\n'
2515}
2516
2517fn test_eval_optional_if_guard_binds_payload_type() {
2518 mut e := create()
2519 e.run_text('
2520fn maybe() ?int {
2521 return 41
2522}
2523
2524fn absent() ?int {
2525 return none
2526}
2527
2528fn main() {
2529 if x := maybe() {
2530 println(int_str(x + 1))
2531 } else {
2532 println("missing")
2533 }
2534 if x := absent() {
2535 println(int_str(x))
2536 } else {
2537 println("absent")
2538 }
2539}
2540 ') or {
2541 panic(err)
2542 }
2543 assert e.stdout() == '42\nabsent\n'
2544}
2545
2546fn test_eval_optional_sum_return_adapts_payload_before_wrapping() {
2547 mut e := create()
2548 e.run_text('
2549type Any = int | string
2550
2551fn maybe() ?Any {
2552 return 1
2553}
2554
2555fn main() {
2556 x := maybe() or {
2557 return
2558 }
2559 println(int_str(x._typ))
2560}
2561 ') or {
2562 panic(err)
2563 }
2564 assert e.stdout() == '0\n'
2565}
2566
2567fn test_eval_or_block_return_propagates_from_call_argument() {
2568 mut e := create()
2569 e.run_text('
2570fn maybe() ?int {
2571 return none
2572}
2573
2574fn run() int {
2575 println(int_str(maybe() or {
2576 return 1
2577 }))
2578 return 2
2579}
2580
2581fn main() {
2582 println(int_str(run()))
2583}
2584 ') or {
2585 panic(err)
2586 }
2587 assert e.stdout() == '1\n'
2588}
2589
2590fn test_eval_or_block_return_propagates_from_nested_infix() {
2591 mut e := create()
2592 e.run_text('
2593fn maybe() ?int {
2594 return none
2595}
2596
2597fn run() int {
2598 x := (maybe() or {
2599 return 12
2600 }) + 1
2601 return x
2602}
2603
2604fn main() {
2605 println(int_str(run()))
2606}
2607 ') or {
2608 panic(err)
2609 }
2610 assert e.stdout() == '12\n'
2611}
2612
2613fn test_eval_or_block_return_propagates_from_selector_receiver() {
2614 mut e := create()
2615 e.run_text('
2616fn maybe() ?string {
2617 return none
2618}
2619
2620fn run() string {
2621 n := (maybe() or {
2622 return "early"
2623 }).len
2624 return int_str(n)
2625}
2626
2627fn main() {
2628 println(run())
2629}
2630 ') or {
2631 panic(err)
2632 }
2633 assert e.stdout() == 'early\n'
2634}
2635
2636fn test_eval_or_block_return_propagates_from_method_receiver() {
2637 mut e := create()
2638 e.run_text('
2639fn maybe_arr() ?[]int {
2640 return none
2641}
2642
2643fn run() int {
2644 x := (maybe_arr() or {
2645 return 12
2646 }).first()
2647 return x
2648}
2649
2650fn main() {
2651 println(int_str(run()))
2652}
2653 ') or {
2654 panic(err)
2655 }
2656 assert e.stdout() == '12\n'
2657}
2658
2659fn test_eval_or_block_return_propagates_from_outer_or_left_operand() {
2660 mut e := create()
2661 e.run_text('
2662fn maybe() ?int {
2663 return none
2664}
2665
2666fn wrap(x int) ?int {
2667 return x
2668}
2669
2670fn run() int {
2671 _ := wrap(maybe() or {
2672 return 1
2673 }) or {
2674 return 2
2675 }
2676 return 3
2677}
2678
2679fn main() {
2680 println(int_str(run()))
2681}
2682 ') or {
2683 panic(err)
2684 }
2685 assert e.stdout() == '1\n'
2686}
2687
2688fn test_eval_or_block_return_propagates_from_match_subject() {
2689 mut e := create()
2690 e.run_text('
2691fn maybe() ?int {
2692 return none
2693}
2694
2695fn run() int {
2696 match (maybe() or {
2697 return 7
2698 }) {
2699 else {}
2700 }
2701 return 0
2702}
2703
2704fn main() {
2705 println(int_str(run()))
2706}
2707 ') or {
2708 panic(err)
2709 }
2710 assert e.stdout() == '7\n'
2711}
2712
2713fn test_eval_map_index_or_uses_lookup_presence() {
2714 mut e := create()
2715 e.run_text('
2716fn main() {
2717 mut m := map[string]int{}
2718 m["present"] = 0
2719 println(int_str(m["present"] or { 7 }))
2720 println(int_str(m["missing"] or { 7 }))
2721
2722 mut s := map[string]string{}
2723 s["empty"] = ""
2724 println(s["empty"] or { "fallback" })
2725 println(s["missing"] or { "fallback" })
2726}
2727 ') or {
2728 panic(err)
2729 }
2730 assert e.stdout() == '0\n7\n\nfallback\n'
2731}
2732
2733fn test_eval_map_index_if_guard_uses_lookup_presence() {
2734 mut e := create()
2735 e.run_text('
2736fn main() {
2737 mut m := map[string]int{}
2738 m["present"] = 0
2739 if v := m["present"] {
2740 println(int_str(v))
2741 } else {
2742 println("missing-present")
2743 }
2744 if v := m["missing"] {
2745 println(int_str(v))
2746 } else {
2747 println("missing")
2748 }
2749}
2750 ') or {
2751 panic(err)
2752 }
2753 assert e.stdout() == '0\nmissing\n'
2754}
2755
2756fn test_eval_postfix_option_propagates_failure() {
2757 mut e := create()
2758 e.run_text('
2759fn maybe() ?int {
2760 return none
2761}
2762
2763fn run() ?int {
2764 maybe()?
2765 println("after")
2766 return 1
2767}
2768
2769fn main() {
2770 run() or {
2771 println("none")
2772 return
2773 }
2774}
2775 ') or {
2776 panic(err)
2777 }
2778 assert e.stdout() == 'none\n'
2779}
2780
2781fn test_eval_or_block_binds_err() {
2782 mut e := create()
2783 e.run_text('
2784fn maybe() ?int {
2785 return none
2786}
2787
2788fn main() {
2789 maybe() or {
2790 _ := err
2791 println("handled")
2792 return
2793 }
2794}
2795 ') or {
2796 panic(err)
2797 }
2798 assert e.stdout() == 'handled\n'
2799}
2800
2801fn test_eval_or_block_return_propagates_from_for_in_header() {
2802 mut e := create()
2803 e.run_text('
2804fn maybe_arr() ?[]int {
2805 return none
2806}
2807
2808fn maybe_int() ?int {
2809 return none
2810}
2811
2812fn maybe_two() ?int {
2813 return 2
2814}
2815
2816fn iterable() int {
2817 for x in (maybe_arr() or {
2818 return 7
2819 }) {
2820 _ = x
2821 }
2822 return 0
2823}
2824
2825fn range_start() int {
2826 for i in (maybe_int() or {
2827 return 8
2828 }) .. 3 {
2829 _ = i
2830 }
2831 return 0
2832}
2833
2834fn range_end() int {
2835 for i in 0 .. (maybe_int() or {
2836 return 9
2837 }) {
2838 _ = i
2839 }
2840 return 0
2841}
2842
2843fn main() {
2844 println(int_str(iterable()))
2845 println(int_str(range_start()))
2846 println(int_str(range_end()))
2847}
2848 ') or {
2849 panic(err)
2850 }
2851 assert e.stdout() == '7\n8\n9\n'
2852}
2853
2854fn test_eval_or_block_return_propagates_from_flow_contexts() {
2855 mut e := create()
2856 e.run_text('
2857fn maybe_bool() ?bool {
2858 return none
2859}
2860
2861fn maybe_arr() ?[]int {
2862 return none
2863}
2864
2865fn maybe_int() ?int {
2866 return none
2867}
2868
2869fn maybe_two() ?int {
2870 return 2
2871}
2872
2873fn if_condition() int {
2874 if maybe_bool() or {
2875 return 1
2876 } {
2877 return 99
2878 }
2879 return 0
2880}
2881
2882fn assert_condition() bool {
2883 assert maybe_bool() or {
2884 return false
2885 }
2886 return true
2887}
2888
2889fn loop_condition() int {
2890 for maybe_bool() or {
2891 return 5
2892 } {
2893 return 99
2894 }
2895 return 0
2896}
2897
2898fn index_receiver() int {
2899 x := (maybe_arr() or {
2900 return 6
2901 })[0]
2902 return x
2903}
2904
2905fn index_value() int {
2906 arr := [10]
2907 x := arr[maybe_int() or {
2908 return 7
2909 }]
2910 return x
2911}
2912
2913fn if_expr_branch() int {
2914 x := if true {
2915 maybe_int() or {
2916 return 8
2917 }
2918 } else {
2919 0
2920 }
2921 return x
2922}
2923
2924fn if_guard_scope() int {
2925 x := 1
2926 if x := maybe_two() {
2927 if x != 2 {
2928 return 99
2929 }
2930 }
2931 return x
2932}
2933
2934fn main() {
2935 println(int_str(if_condition()))
2936 println(assert_condition())
2937 println(int_str(loop_condition()))
2938 println(int_str(index_receiver()))
2939 println(int_str(index_value()))
2940 println(int_str(if_expr_branch()))
2941 println(int_str(if_guard_scope()))
2942}
2943 ') or {
2944 panic(err)
2945 }
2946 assert e.stdout() == '1\nfalse\n5\n6\n7\n8\n1\n'
2947}
2948
2949fn test_eval_or_block_return_propagates_from_array_literal_element() {
2950 mut e := create()
2951 e.run_text('
2952fn maybe() ?int {
2953 return none
2954}
2955
2956fn run() []int {
2957 _ := [maybe() or {
2958 return [7]
2959 }]
2960 return [0]
2961}
2962
2963fn main() {
2964 println(int_str(run()[0]))
2965}
2966 ') or {
2967 panic(err)
2968 }
2969 assert e.stdout() == '7\n'
2970}
2971
2972fn test_eval_or_block_return_propagates_from_struct_init_field() {
2973 mut e := create()
2974 e.run_text('
2975struct S {
2976 n int
2977}
2978
2979fn maybe() ?int {
2980 return none
2981}
2982
2983fn run() S {
2984 return S{
2985 n: maybe() or {
2986 return S{
2987 n: 7
2988 }
2989 }
2990 }
2991}
2992
2993fn main() {
2994 println(int_str(run().n))
2995}
2996 ') or {
2997 panic(err)
2998 }
2999 assert e.stdout() == '7\n'
3000}
3001
3002fn test_eval_or_block_return_propagates_from_string_interpolation() {
3003 mut e := create()
3004 e.run_text('
3005fn maybe() ?int {
3006 return none
3007}
3008
3009fn run() int {
3010 _ := "\${maybe() or {
3011 return 7
3012 }}"
3013 return 9
3014}
3015
3016fn main() {
3017 println(int_str(run()))
3018}
3019 ') or {
3020 panic(err)
3021 }
3022 assert e.stdout() == '7\n'
3023}
3024
3025fn test_eval_match_expression_propagates_branch_return() {
3026 mut e := create()
3027 e.run_text('
3028fn run(n int) int {
3029 x := match n {
3030 0 {
3031 return 12
3032 }
3033 else {
3034 7
3035 }
3036 }
3037 return x + 1
3038}
3039
3040fn main() {
3041 println(int_str(run(0)))
3042 println(int_str(run(1)))
3043}
3044 ') or {
3045 panic(err)
3046 }
3047 assert e.stdout() == '12\n8\n'
3048}
3049
3050fn test_eval_module_const_uses_defining_module_context() {
3051 dir := os.join_path(os.temp_dir(), 'v3_eval_const_module_${os.getpid()}')
3052 os.rmdir_all(dir) or {}
3053 os.mkdir_all(dir) or { panic(err) }
3054 defer {
3055 os.rmdir_all(dir) or {}
3056 }
3057 mod_file := os.join_path(dir, 'm.v')
3058 main_file := os.join_path(dir, 'main.v')
3059 os.write_file(mod_file, '
3060module m
3061
3062const x = helper()
3063
3064fn helper() int {
3065 return 7
3066}
3067') or {
3068 panic(err)
3069 }
3070 os.write_file(main_file, '
3071module main
3072
3073import m
3074
3075fn helper() int {
3076 return 99
3077}
3078
3079fn main() {
3080 println(int_str(m.x))
3081}
3082') or {
3083 panic(err)
3084 }
3085 mut e := create()
3086 mut p := parser.Parser.new(&e.prefs)
3087 p.parse_files([mod_file, main_file])
3088 e.run_files(p.a) or { panic(err) }
3089 assert e.stdout() == '7\n'
3090}
3091
3092fn test_eval_enum_initializers_use_declaring_module_context() {
3093 dir := os.join_path(os.temp_dir(), 'v3_eval_enum_module_${os.getpid()}')
3094 os.rmdir_all(dir) or {}
3095 os.mkdir_all(dir) or { panic(err) }
3096 defer {
3097 os.rmdir_all(dir) or {}
3098 }
3099 mod_file := os.join_path(dir, 'm.v')
3100 main_file := os.join_path(dir, 'main.v')
3101 os.write_file(mod_file, '
3102module m
3103
3104const base = 2
3105
3106pub enum E {
3107 a = base
3108 b
3109}
3110
3111pub fn value() int {
3112 return int(E.a) * 10 + int(E.b)
3113}
3114') or {
3115 panic(err)
3116 }
3117 os.write_file(main_file, '
3118module main
3119
3120import m
3121
3122const base = 10
3123
3124fn main() {
3125 println(int_str(m.value()))
3126}
3127') or {
3128 panic(err)
3129 }
3130 mut e := create()
3131 mut p := parser.Parser.new(&e.prefs)
3132 p.parse_files([mod_file, main_file])
3133 e.run_files(p.a) or { panic(err) }
3134 assert e.stdout() == '23\n'
3135}
3136
3137fn test_eval_enum_initializers_use_file_import_aliases() {
3138 dir := os.join_path(os.temp_dir(), 'v3_eval_enum_alias_${os.getpid()}')
3139 os.rmdir_all(dir) or {}
3140 os.mkdir_all(dir) or { panic(err) }
3141 defer {
3142 os.rmdir_all(dir) or {}
3143 }
3144 dep_file := os.join_path(dir, 'dep.v')
3145 main_file := os.join_path(dir, 'main.v')
3146 os.write_file(dep_file, '
3147module dep
3148
3149pub const n = 7
3150 ') or { panic(err) }
3151 os.write_file(main_file, '
3152module main
3153
3154import dep as d
3155
3156enum E {
3157 a = d.n
3158}
3159
3160fn main() {
3161 println(int_str(int(E.a)))
3162}
3163 ') or {
3164 panic(err)
3165 }
3166 mut e := create()
3167 mut p := parser.Parser.new(&e.prefs)
3168 p.parse_files([main_file, dep_file])
3169 e.run_files(p.a) or { panic(err) }
3170 assert e.stdout() == '7\n'
3171}
3172
3173fn test_eval_global_initializers_run_after_registration_in_declaring_module() {
3174 dir := os.join_path(os.temp_dir(), 'v3_eval_global_init_${os.getpid()}')
3175 os.rmdir_all(dir) or {}
3176 os.mkdir_all(dir) or { panic(err) }
3177 defer {
3178 os.rmdir_all(dir) or {}
3179 }
3180 main_file := os.join_path(dir, 'main.v')
3181 mod_file := os.join_path(dir, 'm.v')
3182 os.write_file(mod_file, '
3183module m
3184
3185__global g = helper()
3186
3187fn helper() int {
3188 return 7
3189}
3190
3191pub fn value() int {
3192 return g
3193}
3194 ') or {
3195 panic(err)
3196 }
3197 os.write_file(main_file, '
3198module main
3199
3200import m
3201
3202fn helper() int {
3203 return 99
3204}
3205
3206__global main_g = helper()
3207
3208fn main() {
3209 println(int_str(main_g))
3210 println(int_str(m.value()))
3211}
3212 ') or {
3213 panic(err)
3214 }
3215 mut e := create()
3216 mut p := parser.Parser.new(&e.prefs)
3217 p.parse_files([main_file, mod_file])
3218 e.run_files(p.a) or { panic(err) }
3219 assert e.stdout() == '99\n7\n'
3220}
3221
3222fn test_eval_global_initializers_run_imports_before_main() {
3223 dir := os.join_path(os.temp_dir(), 'v3_eval_global_init_order_${os.getpid()}')
3224 os.rmdir_all(dir) or {}
3225 os.mkdir_all(dir) or { panic(err) }
3226 defer {
3227 os.rmdir_all(dir) or {}
3228 }
3229 main_file := os.join_path(dir, 'main.v')
3230 mod_file := os.join_path(dir, 'm.v')
3231 os.write_file(mod_file, '
3232module m
3233
3234__global g = 7
3235
3236pub fn value() int {
3237 return g
3238}
3239 ') or {
3240 panic(err)
3241 }
3242 os.write_file(main_file, '
3243module main
3244
3245import m
3246
3247__global x = m.value()
3248
3249fn main() {
3250 println(int_str(x))
3251}
3252 ') or {
3253 panic(err)
3254 }
3255 mut e := create()
3256 mut p := parser.Parser.new(&e.prefs)
3257 p.parse_files([main_file, mod_file])
3258 e.run_files(p.a) or { panic(err) }
3259 assert e.stdout() == '7\n'
3260}
3261
3262fn test_eval_module_inits_run_dependencies_first() {
3263 dir := os.join_path(os.temp_dir(), 'v3_eval_init_order_${os.getpid()}')
3264 os.rmdir_all(dir) or {}
3265 os.mkdir_all(dir) or { panic(err) }
3266 defer {
3267 os.rmdir_all(dir) or {}
3268 }
3269 main_file := os.join_path(dir, 'main.v')
3270 moda_file := os.join_path(dir, 'moda.v')
3271 modb_file := os.join_path(dir, 'modb.v')
3272 os.write_file(modb_file, '
3273module modb
3274
3275__global flag int
3276
3277fn init() {
3278 flag = 41
3279}
3280
3281pub fn value() int {
3282 return flag
3283}
3284 ') or {
3285 panic(err)
3286 }
3287 os.write_file(moda_file, '
3288module moda
3289
3290import modb
3291
3292__global seen int
3293
3294fn init() {
3295 seen = modb.value()
3296}
3297
3298pub fn value() int {
3299 return seen
3300}
3301 ') or {
3302 panic(err)
3303 }
3304 os.write_file(main_file, '
3305module main
3306
3307import moda
3308
3309fn main() {
3310 println(int_str(moda.value()))
3311}
3312 ') or {
3313 panic(err)
3314 }
3315 mut e := create()
3316 mut p := parser.Parser.new(&e.prefs)
3317 p.parse_files([main_file, moda_file, modb_file])
3318 e.run_files(p.a) or { panic(err) }
3319 assert e.stdout() == '41\n'
3320}
3321
3322fn test_eval_struct_metadata_uses_current_module() {
3323 dir := os.join_path(os.temp_dir(), 'v3_eval_struct_scope_${os.getpid()}')
3324 os.rmdir_all(dir) or {}
3325 os.mkdir_all(dir) or { panic(err) }
3326 defer {
3327 os.rmdir_all(dir) or {}
3328 }
3329 main_file := os.join_path(dir, 'main.v')
3330 mod_file := os.join_path(dir, 'm.v')
3331 os.write_file(main_file, '
3332module main
3333
3334import m
3335
3336struct Point {
3337 x int
3338}
3339
3340fn main() {
3341 p := Point{}
3342 println(int_str(p.x))
3343}
3344') or {
3345 panic(err)
3346 }
3347 os.write_file(mod_file, '
3348module m
3349
3350struct Point {
3351 y int
3352}
3353') or { panic(err) }
3354 mut e := create()
3355 mut p := parser.Parser.new(&e.prefs)
3356 p.parse_files([main_file, mod_file])
3357 e.run_files(p.a) or { panic(err) }
3358 assert e.stdout() == '0\n'
3359}
3360
3361fn test_eval_struct_field_defaults_use_declaring_module() {
3362 dir := os.join_path(os.temp_dir(), 'v3_eval_struct_field_module_${os.getpid()}')
3363 os.rmdir_all(dir) or {}
3364 os.mkdir_all(dir) or { panic(err) }
3365 defer {
3366 os.rmdir_all(dir) or {}
3367 }
3368 main_file := os.join_path(dir, 'main.v')
3369 mod_file := os.join_path(dir, 'm.v')
3370 os.write_file(mod_file, '
3371module m
3372
3373pub struct Inner {
3374 x int
3375}
3376
3377pub struct Outer {
3378 inner Inner
3379}
3380
3381pub fn outer_x(o Outer) int {
3382 return o.inner.x
3383}
3384') or {
3385 panic(err)
3386 }
3387 os.write_file(main_file, '
3388module main
3389
3390import m
3391
3392struct Inner {
3393 y int
3394}
3395
3396fn main() {
3397 outer := m.Outer{}
3398 println(int_str(m.outer_x(outer)))
3399}
3400') or {
3401 panic(err)
3402 }
3403 mut e := create()
3404 mut p := parser.Parser.new(&e.prefs)
3405 p.parse_files([main_file, mod_file])
3406 e.run_files(p.a) or { panic(err) }
3407 assert e.stdout() == '0\n'
3408}
3409
3410fn test_eval_struct_field_default_initializers_are_preserved() {
3411 dir := os.join_path(os.temp_dir(), 'v3_eval_struct_field_defaults_${os.getpid()}')
3412 os.rmdir_all(dir) or {}
3413 os.mkdir_all(dir) or { panic(err) }
3414 defer {
3415 os.rmdir_all(dir) or {}
3416 }
3417 main_file := os.join_path(dir, 'main.v')
3418 mod_file := os.join_path(dir, 'm.v')
3419 os.write_file(mod_file, '
3420module m
3421
3422pub struct S {
3423pub:
3424 n int = helper()
3425}
3426
3427fn helper() int {
3428 return 7
3429}
3430 ') or {
3431 panic(err)
3432 }
3433 os.write_file(main_file, '
3434module main
3435
3436import m
3437
3438struct S {
3439 n int = helper()
3440}
3441
3442fn helper() int {
3443 return 3
3444}
3445
3446fn main() {
3447 println(int_str(S{}.n))
3448 println(int_str(m.S{}.n))
3449}
3450 ') or {
3451 panic(err)
3452 }
3453 mut e := create()
3454 mut p := parser.Parser.new(&e.prefs)
3455 p.parse_files([main_file, mod_file])
3456 e.run_files(p.a) or { panic(err) }
3457 assert e.stdout() == '3\n7\n'
3458}
3459
3460fn test_eval_import_alias_struct_init_resolves_real_module() {
3461 dir := os.join_path(os.temp_dir(), 'v3_eval_import_alias_struct_${os.getpid()}')
3462 os.rmdir_all(dir) or {}
3463 os.mkdir_all(dir) or { panic(err) }
3464 defer {
3465 os.rmdir_all(dir) or {}
3466 }
3467 main_file := os.join_path(dir, 'main.v')
3468 mod_file := os.join_path(dir, 'm.v')
3469 os.write_file(mod_file, '
3470module m
3471
3472pub struct S {
3473pub:
3474 n int = 7
3475}
3476 ') or { panic(err) }
3477 os.write_file(main_file, '
3478module main
3479
3480import m as mm
3481
3482fn main() {
3483 println(int_str(mm.S{}.n))
3484}
3485 ') or {
3486 panic(err)
3487 }
3488 mut e := create()
3489 mut p := parser.Parser.new(&e.prefs)
3490 p.parse_files([main_file, mod_file])
3491 e.run_files(p.a) or { panic(err) }
3492 assert e.stdout() == '7\n'
3493}
3494
3495fn test_eval_zero_array_field_qualifies_imported_element_type() {
3496 dir := os.join_path(os.temp_dir(), 'v3_eval_import_array_elem_${os.getpid()}')
3497 os.rmdir_all(dir) or {}
3498 os.mkdir_all(dir) or { panic(err) }
3499 defer {
3500 os.rmdir_all(dir) or {}
3501 }
3502 main_file := os.join_path(dir, 'main.v')
3503 mod_file := os.join_path(dir, 'm.v')
3504 os.write_file(mod_file, '
3505module m
3506
3507pub struct Item {}
3508
3509pub struct Box {
3510pub mut:
3511 xs []Item
3512}
3513 ') or {
3514 panic(err)
3515 }
3516 os.write_file(main_file, '
3517module main
3518
3519import m
3520
3521fn main() {
3522 mut b := m.Box{}
3523 b.xs << [m.Item{}, m.Item{}]
3524 println(int_str(b.xs.len))
3525}
3526 ') or {
3527 panic(err)
3528 }
3529 mut e := create()
3530 mut p := parser.Parser.new(&e.prefs)
3531 p.parse_files([main_file, mod_file])
3532 e.run_files(p.a) or { panic(err) }
3533 assert e.stdout() == '2\n'
3534}
3535
3536fn test_eval_is_checks_keep_module_qualified_types_distinct() {
3537 dir := os.join_path(os.temp_dir(), 'v3_eval_type_scope_${os.getpid()}')
3538 os.rmdir_all(dir) or {}
3539 os.mkdir_all(dir) or { panic(err) }
3540 defer {
3541 os.rmdir_all(dir) or {}
3542 }
3543 main_file := os.join_path(dir, 'main.v')
3544 mod_file := os.join_path(dir, 'm.v')
3545 os.write_file(mod_file, '
3546module m
3547
3548pub struct Foo {}
3549') or { panic(err) }
3550 os.write_file(main_file, '
3551module main
3552
3553import m
3554
3555struct Foo {}
3556
3557type Any = Foo | m.Foo
3558
3559fn classify(x Any) string {
3560 if x is Foo {
3561 return "local"
3562 }
3563 if x is m.Foo {
3564 return "module"
3565 }
3566 return "none"
3567}
3568
3569fn main() {
3570 println(classify(m.Foo{}))
3571}
3572') or {
3573 panic(err)
3574 }
3575 mut e := create()
3576 mut p := parser.Parser.new(&e.prefs)
3577 p.parse_files([main_file, mod_file])
3578 e.run_files(p.a) or { panic(err) }
3579 assert e.stdout() == 'module\n'
3580}
3581
3582fn test_eval_module_sum_type_keeps_primitive_variants_unqualified() {
3583 dir := os.join_path(os.temp_dir(), 'v3_eval_primitive_type_scope_${os.getpid()}')
3584 os.rmdir_all(dir) or {}
3585 os.mkdir_all(dir) or { panic(err) }
3586 defer {
3587 os.rmdir_all(dir) or {}
3588 }
3589 main_file := os.join_path(dir, 'main.v')
3590 mod_file := os.join_path(dir, 'm.v')
3591 os.write_file(mod_file, '
3592module m
3593
3594pub type Any = u32 | string
3595
3596pub fn classify(x Any) string {
3597 if x is u32 {
3598 return "u32"
3599 }
3600 if x is string {
3601 return "string"
3602 }
3603 return "none"
3604}
3605 ') or {
3606 panic(err)
3607 }
3608 os.write_file(main_file, '
3609module main
3610
3611import m
3612
3613fn main() {
3614 println(m.classify(u32(7)))
3615 println(m.classify("ok"))
3616}
3617 ') or {
3618 panic(err)
3619 }
3620 mut e := create()
3621 mut p := parser.Parser.new(&e.prefs)
3622 p.parse_files([main_file, mod_file])
3623 e.run_files(p.a) or { panic(err) }
3624 assert e.stdout() == 'u32\nstring\n'
3625}
3626
3627fn test_eval_sum_tables_are_module_scoped_and_exact() {
3628 dir := os.join_path(os.temp_dir(), 'v3_eval_sum_scope_${os.getpid()}')
3629 os.rmdir_all(dir) or {}
3630 os.mkdir_all(dir) or { panic(err) }
3631 defer {
3632 os.rmdir_all(dir) or {}
3633 }
3634 main_file := os.join_path(dir, 'main.v')
3635 mod_file := os.join_path(dir, 'm.v')
3636 os.write_file(mod_file, '
3637module m
3638
3639pub struct Foo {}
3640
3641pub type Any = string | bool
3642
3643pub fn variant_index() int {
3644 x := Any("s")
3645 return x._typ
3646}
3647 ') or {
3648 panic(err)
3649 }
3650 os.write_file(main_file, '
3651module main
3652
3653import m
3654
3655struct Foo {}
3656
3657type Any = int | string
3658type Both = Foo | m.Foo
3659
3660fn local_variant_index() int {
3661 x := Any("s")
3662 return x._typ
3663}
3664
3665fn imported_variant_index() int {
3666 x := Both(m.Foo{})
3667 return x._typ
3668}
3669
3670fn main() {
3671 println(int_str(local_variant_index()))
3672 println(int_str(m.variant_index()))
3673 println(int_str(imported_variant_index()))
3674}
3675 ') or {
3676 panic(err)
3677 }
3678 mut e := create()
3679 mut p := parser.Parser.new(&e.prefs)
3680 p.parse_files([main_file, mod_file])
3681 e.run_files(p.a) or { panic(err) }
3682 assert e.stdout() == '1\n0\n1\n'
3683}
3684
3685fn test_eval_is_checks_respect_container_element_types() {
3686 mut e := create()
3687 e.run_text('
3688type Any = []int | []string | map[string]int | map[string]string
3689
3690fn classify(x Any) string {
3691 if x is []string {
3692 return "strings"
3693 }
3694 if x is []int {
3695 return "ints"
3696 }
3697 if x is map[string]string {
3698 return "string-map"
3699 }
3700 if x is map[string]int {
3701 return "int-map"
3702 }
3703 return "none"
3704}
3705
3706fn main() {
3707 println(classify([]int{len: 1, init: 1}))
3708 println(classify([]string{len: 1, init: "s"}))
3709 mut mi := map[string]int{}
3710 mi["a"] = 1
3711 println(classify(mi))
3712 mut ms := map[string]string{}
3713 ms["a"] = "s"
3714 println(classify(ms))
3715}
3716 ') or {
3717 panic(err)
3718 }
3719 assert e.stdout() == 'ints\nstrings\nint-map\nstring-map\n'
3720}
3721
3722fn test_eval_primitive_str_methods_are_direct() {
3723 mut e := create()
3724 e.run_text('
3725fn main() {
3726 total := 42
3727 println(total.str())
3728 println(true.str())
3729 f := 1.5
3730 println(f.str())
3731}
3732 ') or {
3733 panic(err)
3734 }
3735 assert e.stdout() == '42\ntrue\n1.5\n'
3736}
3737
3738fn test_eval_enum_stringification_uses_field_names() {
3739 mut e := create()
3740 e.run_text('
3741enum State {
3742 idle
3743 busy = 10
3744}
3745
3746fn main() {
3747 println(State.busy)
3748 println("\${State.idle}")
3749}
3750 ') or {
3751 panic(err)
3752 }
3753 assert e.stdout() == 'busy\nidle\n'
3754}
3755
3756fn test_eval_struct_stringification_matches_v_output() {
3757 mut e := create()
3758 e.run_text('
3759struct Point {
3760 x int
3761}
3762
3763struct User {
3764 name string
3765 age int
3766}
3767
3768struct Custom {
3769 n int
3770}
3771
3772fn (c Custom) str() string {
3773 return "custom " + int_str(c.n)
3774}
3775
3776fn main() {
3777 println(Point{x: 1})
3778 println(User{name: "Ada", age: 2})
3779 println(Custom{n: 3})
3780 println("\${Custom{n: 4}}")
3781}
3782 ') or {
3783 panic(err)
3784 }
3785 assert e.stdout() == "Point{
3786 x: 1
3787}
3788User{
3789 name: 'Ada'
3790 age: 2
3791}
3792custom 3
3793custom 4
3794"
3795}
3796
3797fn test_eval_os_join_path_delegates_to_os() {
3798 mut e := create()
3799 e.run_text('
3800import os
3801
3802fn main() {
3803 println(os.join_path("", "foo"))
3804 println(os.join_path("foo", ""))
3805}
3806 ') or {
3807 panic(err)
3808 }
3809 expected := os.join_path('', 'foo') + '\n' + os.join_path('foo', '') + '\n'
3810 assert e.stdout() == expected
3811}
3812
3813fn test_v3_eval_backend_cli() {
3814 v3_bin := os.join_path(os.temp_dir(), 'v3_eval_backend_test')
3815 build := os.execute('${vexe} -o ${v3_bin} ${v3_src}')
3816 assert build.exit_code == 0
3817 src := os.join_path(os.temp_dir(), 'v3_eval_backend_sample.v')
3818 os.write_file(src, '
3819fn main() {
3820 mut total := 0
3821 for i in 0 .. 7 {
3822 total += i
3823 }
3824 println(int_str(total))
3825}
3826') or {
3827 panic(err)
3828 }
3829 result := os.execute('${v3_bin} ${src} -b eval')
3830 assert result.exit_code == 0
3831 assert result.output.contains('21\n')
3832}
3833