vxx2 / vlib / v3 / tests / review_transform_regressions_test.v
304 lines · 270 sloc · 19.53 KB · 8739cbd7fc28231971854e7a7606cfeff0e26ea8
Raw
1import os
2
3const vexe = @VEXE
4const tests_dir = os.dir(@FILE)
5const v3_dir = os.dir(tests_dir)
6const vlib_dir = os.dir(v3_dir)
7const v3_src = os.join_path(v3_dir, 'v3.v')
8
9fn build_v3_review_transform() string {
10 v3_bin := os.join_path(os.temp_dir(), 'v3_review_transform_regressions_test')
11 build := os.execute('${vexe} -path "${vlib_dir}|@vlib|@vmodules" -o ${v3_bin} ${v3_src}')
12 assert build.exit_code == 0, build.output
13 return v3_bin
14}
15
16fn run_bad(v3_bin string, name string, src string, expected string) {
17 bad_src := os.join_path(os.temp_dir(), 'v3_${name}.v')
18 os.write_file(bad_src, src) or { panic(err) }
19 bad_bin := os.join_path(os.temp_dir(), 'v3_${name}')
20 result := os.execute('${v3_bin} ${bad_src} -b c -o ${bad_bin}')
21 assert result.exit_code != 0, '${name}: expected failure, got success\n${result.output}'
22 assert result.output.contains(expected), '${name}: expected `${expected}` in\n${result.output}'
23 assert !result.output.contains('C compilation failed'), '${name}: reached C compilation\n${result.output}'
24}
25
26fn run_good(v3_bin string, name string, src string) string {
27 good_src := os.join_path(os.temp_dir(), 'v3_${name}.v')
28 os.write_file(good_src, src) or { panic(err) }
29 good_bin := os.join_path(os.temp_dir(), 'v3_${name}')
30 compile := os.execute('${v3_bin} ${good_src} -b c -o ${good_bin}')
31 assert compile.exit_code == 0, '${name}: compile failed\n${compile.output}'
32 assert !compile.output.contains('C compilation failed'), '${name}: C compilation failed\n${compile.output}'
33 run := os.execute(good_bin)
34 assert run.exit_code == 0, '${name}: run failed\n${run.output}'
35 return run.output.trim_space()
36}
37
38fn write_project_file(root string, rel string, src string) {
39 path := os.join_path(root, rel)
40 os.mkdir_all(os.dir(path)) or { panic(err) }
41 os.write_file(path, src) or { panic(err) }
42}
43
44fn run_good_project(v3_bin string, name string, files map[string]string, input string) string {
45 root := os.join_path(os.temp_dir(), 'v3_${name}_project')
46 if os.exists(root) {
47 os.rmdir_all(root) or { panic(err) }
48 }
49 os.mkdir_all(root) or { panic(err) }
50 for rel, src in files {
51 write_project_file(root, rel, src)
52 }
53 input_path := if input.len == 0 { root } else { os.join_path(root, input) }
54 good_bin := os.join_path(os.temp_dir(), 'v3_${name}')
55 compile := os.execute('${v3_bin} ${input_path} -b c -o ${good_bin}')
56 assert compile.exit_code == 0, '${name}: compile failed\n${compile.output}'
57 assert !compile.output.contains('C compilation failed'), '${name}: C compilation failed\n${compile.output}'
58 run := os.execute(good_bin)
59 assert run.exit_code == 0, '${name}: run failed\n${run.output}'
60 return run.output.trim_space()
61}
62
63fn test_reject_dynamic_arrays_for_fixed_array_expectations() {
64 v3_bin := build_v3_review_transform()
65 run_bad(v3_bin, 'bad_fixed_array_literal_len',
66 'fn take3(a [3]int) int {\n\treturn a[0]\n}\nfn main() {\n\t_ := take3([1, 2])\n}\n',
67 'cannot use')
68 run_bad(v3_bin, 'bad_dynamic_array_for_fixed_array',
69 'fn take3(a [3]int) int {\n\treturn a[0]\n}\nfn main() {\n\txs := [1, 2, 3]\n\t_ := take3(xs)\n}\n',
70 'cannot use')
71 out := run_good(v3_bin, 'good_exact_fixed_array_literal',
72 'fn take3(a [3]int) int {\n\treturn a[0] + a[1] + a[2]\n}\nfn main() {\n\tprintln(int_str(take3([1, 2, 3])))\n}\n')
73 assert out == '6'
74 indexed := run_good(v3_bin, 'good_fixed_array_init_index',
75 'fn main() {\n\ta := [4]int{init: index * index}\n\tprintln(int_str(a[0]) + "," + int_str(a[1]) + "," + int_str(a[2]) + "," + int_str(a[3]))\n}\n')
76 assert indexed == '0,1,4,9'
77 const_indexed := run_good(v3_bin, 'good_fixed_array_const_init_index',
78 'const n = 4\n\nfn main() {\n\ta := [n]int{init: index * index}\n\tprintln(int_str(a[0]) + "," + int_str(a[1]) + "," + int_str(a[2]) + "," + int_str(a[3]))\n}\n')
79 assert const_indexed == '0,1,4,9'
80}
81
82fn test_array_equality_uses_semantic_element_comparison() {
83 v3_bin := build_v3_review_transform()
84 out := run_good(v3_bin, 'semantic_array_equality',
85 "struct Child {\n\tlabel string\n}\n\nstruct Item {\n\tname string\n\tparts []string\n\tnested [][]string\n\tchildren []Child\n}\n\nfn join(a string, b string) string {\n\treturn a + b\n}\n\nfn main() {\n\tleft := [Item{\n\t\tname: 'hi'.clone()\n\t\tparts: ['ab'.clone()]\n\t\tnested: [[join('n', 'est')]]\n\t\tchildren: [Child{\n\t\t\tlabel: 'kid'.clone()\n\t\t}]\n\t}]\n\tright := [Item{\n\t\tname: join('h', 'i')\n\t\tparts: [join('a', 'b')]\n\t\tnested: [['nest'.clone()]]\n\t\tchildren: [Child{\n\t\t\tlabel: join('k', 'id')\n\t\t}]\n\t}]\n\tmaps_left := [{\n\t\t'k': 'value'.clone()\n\t}]\n\tmaps_right := [{\n\t\t'k': join('val', 'ue')\n\t}]\n\tnested_left := [[join('y', 'o')]]\n\tnested_right := [['yo'.clone()]]\n\tchild_map_left := {\n\t\t'items': [Child{\n\t\t\tlabel: 'mapkid'.clone()\n\t\t}]\n\t}\n\tchild_map_right := {\n\t\t'items': [Child{\n\t\t\tlabel: join('map', 'kid')\n\t\t}]\n\t}\n\tneedle := Item{\n\t\tname: join('h', 'i')\n\t\tparts: [join('a', 'b')]\n\t\tnested: [['nest'.clone()]]\n\t\tchildren: [Child{\n\t\t\tlabel: join('k', 'id')\n\t\t}]\n\t}\n\tprintln(left == right)\n\tprintln(left.equals(right))\n\tprintln(maps_left == maps_right)\n\tprintln(nested_left == nested_right)\n\tprintln(child_map_left == child_map_right)\n\tprintln(needle in left)\n\tprintln(int_str(left.index(needle)))\n}\n")
86 assert out == 'true\ntrue\ntrue\ntrue\ntrue\ntrue\n0'
87}
88
89fn test_nested_map_equality_uses_declared_value_type() {
90 v3_bin := build_v3_review_transform()
91 out := run_good(v3_bin, 'nested_map_semantic_equality',
92 "struct Item {\n\tname string\n\tparts []string\n}\n\nstruct Holder {\n\titems map[string][]Item\n}\n\nfn join(a string, b string) string {\n\treturn a + b\n}\n\nfn main() {\n\tmut left_map := map[string][]Item{}\n\tleft_map['items'] = [Item{\n\t\tname: 'ab'.clone()\n\t\tparts: ['xy'.clone()]\n\t}]\n\tmut right_map := map[string][]Item{}\n\tright_map['items'] = [Item{\n\t\tname: join('a', 'b')\n\t\tparts: [join('x', 'y')]\n\t}]\n\tleft_arr := [left_map]\n\tright_arr := [right_map]\n\tleft_holder := Holder{\n\t\titems: left_map\n\t}\n\tright_holder := Holder{\n\t\titems: right_map\n\t}\n\tprintln(left_arr == right_arr)\n\tprintln(left_holder == right_holder)\n}\n")
93 assert out == 'true\ntrue'
94}
95
96fn test_pointer_array_equality_uses_pointer_identity() {
97 v3_bin := build_v3_review_transform()
98 out := run_good(v3_bin, 'pointer_array_equality',
99 'struct Node {\n\tvalue int\n}\n\nfn main() {\n\tleft_node := Node{\n\t\tvalue: 5\n\t}\n\tright_node := Node{\n\t\tvalue: 5\n\t}\n\tleft_ptr := &left_node\n\tright_ptr := &right_node\n\tleft := [left_ptr]\n\tright := [right_ptr]\n\tsame := [left_ptr]\n\tprintln(left == right)\n\tprintln(left != right)\n\tprintln(left == same)\n\tprintln(right_ptr in left)\n\tprintln(int_str(left.index(right_ptr)))\n}\n')
100 assert out == 'false\ntrue\ntrue\nfalse\n-1'
101}
102
103fn test_array_pointer_equality_uses_pointer_identity() {
104 v3_bin := build_v3_review_transform()
105 out := run_good(v3_bin, 'array_pointer_equality',
106 'fn main() {\n\tleft := [1, 2]\n\tright := [1, 2]\n\tleft_ptr := &left\n\tright_ptr := &right\n\tsame_ptr := left_ptr\n\tprintln(left_ptr == right_ptr)\n\tprintln(left_ptr != right_ptr)\n\tprintln(left_ptr == same_ptr)\n\tprintln(*left_ptr == *right_ptr)\n}\n')
107 assert out == 'false\ntrue\ntrue\ntrue'
108}
109
110fn test_map_pointer_equality_uses_pointer_identity() {
111 v3_bin := build_v3_review_transform()
112 out := run_good(v3_bin, 'map_pointer_equality',
113 "fn main() {\n\tleft := {\n\t\t'x': 1\n\t}\n\tright := {\n\t\t'x': 1\n\t}\n\tleft_ptr := &left\n\tright_ptr := &right\n\tsame_ptr := left_ptr\n\tprintln(left_ptr == right_ptr)\n\tprintln(left_ptr != right_ptr)\n\tprintln(left_ptr == same_ptr)\n\tprintln(*left_ptr == *right_ptr)\n}\n")
114 assert out == 'false\ntrue\ntrue\ntrue'
115}
116
117fn test_fixed_array_values_compare_semantically() {
118 v3_bin := build_v3_review_transform()
119 out := run_good(v3_bin, 'fixed_array_semantic_equality',
120 "fn join(a string, b string) string {\n\treturn a + b\n}\n\nfn main() {\n\tleft := [[1]string{init: 'ab'.clone()}]\n\tright := [[1]string{init: join('a', 'b')}]\n\tmut map_left := map[string][1]string{}\n\tmap_left['k'] = [1]string{init: 'cd'.clone()}\n\tmut map_right := map[string][1]string{}\n\tmap_right['k'] = [1]string{init: join('c', 'd')}\n\tmut ints_left := map[string][2]i64{}\n\tints_left['k'] = [i64(1), i64(0)]!\n\tmut ints_right := map[string][2]i64{}\n\tints_right['k'] = [i64(2), i64(0)]!\n\tprintln(left == right)\n\tprintln(left.equals(right))\n\tprintln(map_left == map_right)\n\tprintln(ints_left == ints_right)\n}\n")
121 assert out == 'true\ntrue\ntrue\nfalse'
122}
123
124fn test_const_length_fixed_array_map_values_compare_semantically() {
125 v3_bin := build_v3_review_transform()
126 out := run_good_project(v3_bin, 'const_len_fixed_array_map_equality', {
127 'main.v': 'module main\n\nimport store\n\nfn main() {\n\tprintln(store.check())\n}\n'
128 'store/store.v': "module store\n\nconst n = 2\n\nfn join(a string, b string) string {\n\treturn a + b\n}\n\npub fn check() bool {\n\tmut left := map[string][n]string{}\n\tleft['k'] = [n]string{init: 'ab'.clone()}\n\tmut right := map[string][n]string{}\n\tright['k'] = [n]string{init: join('a', 'b')}\n\treturn left == right\n}\n"
129 }, 'main.v')
130 assert out == 'true'
131}
132
133fn test_interface_array_repeat_evaluates_receiver_once() {
134 v3_bin := build_v3_review_transform()
135 out := run_good(v3_bin, 'interface_repeat_side_effects',
136 'interface Thing {\n\tvalue() int\n}\n\nstruct Item {\n\tn int\n}\n\nfn (i Item) value() int {\n\treturn i.n\n}\n\n__global calls int\n\nfn make_item() Thing {\n\tcalls++\n\treturn Item{\n\t\tn: calls\n\t}\n}\n\nfn main() {\n\titems := [make_item()].repeat(3)\n\tprintln(int_str(calls))\n\tprintln(int_str(items[0].value() + items[1].value() + items[2].value()))\n}\n')
137 assert out == '1\n3'
138}
139
140fn test_negative_is_return_smartcasts_following_statements() {
141 v3_bin := build_v3_review_transform()
142 out := run_good(v3_bin, 'negative_is_return_smartcast',
143 'struct MapKind {\n\tkey_type int\n\tvalue_type int\n}\nstruct OtherKind {}\ntype Kind = MapKind | OtherKind\n\nfn passthrough(k Kind) Kind {\n\treturn k\n}\n\nfn score(k Kind) int {\n\tclean := passthrough(k)\n\tif clean !is MapKind {\n\t\treturn 0\n\t}\n\treturn clean.key_type + clean.value_type\n}\n\nfn main() {\n\tprintln(int_str(score(Kind(MapKind{\n\t\tkey_type: 2\n\t\tvalue_type: 5\n\t}))))\n\tprintln(int_str(score(Kind(OtherKind{}))))\n}\n')
144 assert out == '7\n0'
145}
146
147fn test_comptime_type_conditions_handle_logical_ops() {
148 v3_bin := build_v3_review_transform()
149 out := run_good(v3_bin, 'comptime_type_condition_logical_ops',
150 "fn classify[T](x T) int {\n\t_ := x\n\t\$if T !is string && T !is \$int && T !is []u8 {\n\t\treturn 1\n\t} \$else {\n\t\treturn 2\n\t}\n\treturn 0\n}\n\nfn grouped[T](x T) int {\n\t_ := x\n\t\$if (T is int || T is string) && T is bool {\n\t\treturn 1\n\t} \$else {\n\t\treturn 2\n\t}\n\treturn 0\n}\n\nfn main() {\n\tprintln(int_str(classify('abc')))\n\tprintln(int_str(classify(3)))\n\tprintln(int_str(classify([u8(1)])))\n\tprintln(int_str(classify(1.5)))\n\tprintln(int_str(grouped(3)))\n\tprintln(int_str(grouped('abc')))\n}\n")
151 assert out == '2\n2\n2\n1\n2\n2'
152}
153
154fn test_comptime_type_conditions_keep_prefix_types_compact() {
155 v3_bin := build_v3_review_transform()
156 out := run_good(v3_bin, 'comptime_type_condition_prefix_types',
157 'struct Foo {}\n\nfn main() {\n\t\$if ?int is ?int {\n\t\tprintln("opt")\n\t} \$else {\n\t\tprintln("badopt")\n\t}\n\t\$if !Foo is !Foo {\n\t\tprintln("res")\n\t} \$else {\n\t\tprintln("badres")\n\t}\n}\n')
158 assert out == 'opt\nres'
159}
160
161fn test_comptime_type_conditions_qualify_module_aliases() {
162 v3_bin := build_v3_review_transform()
163 out := run_good_project(v3_bin, 'comptime_type_condition_module_alias', {
164 'main.v': 'module main\n\nimport foo\n\nfn main() {\n\tprintln(foo.check())\n}\n'
165 'foo/foo.v': "module foo\n\ntype ID = int\n\npub fn check() string {\n\t\$if ID is \$alias {\n\t\treturn 'alias'\n\t} \$else {\n\t\treturn 'not alias'\n\t}\n}\n"
166 }, 'main.v')
167 assert out == 'alias'
168}
169
170fn test_struct_equality_compares_pointer_fields_as_pointers() {
171 v3_bin := build_v3_review_transform()
172 out := run_good(v3_bin, 'struct_eq_pointer_field',
173 'struct Node {\n\tvalue int\n\tnext &Node\n}\n\nfn main() {\n\tleft := Node{\n\t\tvalue: 7\n\t\tnext: unsafe { nil }\n\t}\n\tright := Node{\n\t\tvalue: 7\n\t\tnext: unsafe { nil }\n\t}\n\tprintln([left] == [right])\n}\n')
174 assert out == 'true'
175}
176
177fn test_single_module_test_file_skips_premodule_attributes() {
178 v3_bin := build_v3_review_transform()
179 root := os.join_path(os.temp_dir(), 'v3_premodule_attr_module_test')
180 os.rmdir_all(root) or {}
181 os.mkdir_all(os.join_path(root, 'tar')) or { panic(err) }
182 os.write_file(os.join_path(root, 'v.mod'), 'Module { name: "premodule_attr_module_test" }\n') or {
183 panic(err)
184 }
185 os.write_file(os.join_path(root, 'tar', 'reader.v'),
186 'module tar /* implementation module */\n\nfn reader_value() string {\n\treturn "reader"\n}\n') or {
187 panic(err)
188 }
189 test_file := os.join_path(root, 'tar', 'reader_test.v')
190 os.write_file(test_file,
191 '@[has_globals]\n/* block comment before module */\nmodule tar // test module\n\nfn test_reader_value() {\n\tprintln(reader_value())\n}\n') or {
192 panic(err)
193 }
194 bin_path := os.join_path(root, 'reader_test_bin')
195 compile := os.execute('${v3_bin} ${test_file} -b c -o ${bin_path}')
196 assert compile.exit_code == 0, compile.output
197 run := os.execute(bin_path)
198 assert run.exit_code == 0, run.output
199 assert run.output.trim_space() == 'reader'
200}
201
202fn test_delete_last_empty_array_panics_before_tail_clear() {
203 v3_bin := build_v3_review_transform()
204 src := 'fn main() {\n\tmut values := []int{}\n\tvalues.delete_last()\n\tprintln("after")\n}\n'
205 good_src := os.join_path(os.temp_dir(), 'v3_delete_last_empty.v')
206 os.write_file(good_src, src) or { panic(err) }
207 good_bin := os.join_path(os.temp_dir(), 'v3_delete_last_empty')
208 compile := os.execute('${v3_bin} ${good_src} -b c -o ${good_bin}')
209 assert compile.exit_code == 0, compile.output
210 run := os.execute(good_bin)
211 assert run.exit_code != 0, run.output
212 assert run.output.contains('array.delete_last: array is empty'), run.output
213}
214
215fn test_delete_last_preserves_shared_slice_buffer() {
216 v3_bin := build_v3_review_transform()
217 out := run_good(v3_bin, 'delete_last_preserves_shared_slice_buffer',
218 "fn main() {\n\tmut a := [1, 2, 3, 4]\n\tb := unsafe { a[..a.len] }\n\told_data := a.data\n\ta.delete_last()\n\tassert a == [1, 2, 3]\n\tassert b == [1, 2, 3, 4]\n\tassert a.data != old_data\n\tprintln('ok')\n}\n")
219 assert out == 'ok'
220}
221
222fn test_slice_element_assignment_writes_through() {
223 v3_bin := build_v3_review_transform()
224 out := run_good(v3_bin, 'slice_element_assignment_writes_through',
225 "fn main() {\n\tmut a := [1, 2, 3, 4]\n\tmut s := unsafe { a[1..3] }\n\ts[0] = 42\n\ts[1] += 5\n\tassert a == [1, 42, 8, 4]\n\tassert s == [42, 8]\n\tprintln('ok')\n}\n")
226 assert out == 'ok'
227}
228
229fn test_string_pointer_comparisons_keep_pointer_semantics() {
230 v3_bin := build_v3_review_transform()
231 out := run_good(v3_bin, 'string_pointer_comparison',
232 "fn main() {\n\tleft := 'same'.clone()\n\tright := 'same'.clone()\n\tpleft := &left\n\tpright := &right\n\tprintln(pleft == pright)\n\tprintln(pleft != pright)\n\tprintln(*pleft == *pright)\n}\n")
233 assert out == 'false\ntrue\ntrue'
234}
235
236fn test_map_keys_and_values_lower_to_runtime_methods() {
237 v3_bin := build_v3_review_transform()
238 out := run_good(v3_bin, 'map_keys_values_lowering',
239 "fn make_lookup() map[string]int {\n\treturn {\n\t\t'one': 1\n\t\t'two': 2\n\t}\n}\n\nfn main() {\n\tlookup := make_lookup()\n\tkeys := lookup.keys()\n\tvalues := make_lookup().values()\n\tmut total := 0\n\tfor value in values {\n\t\ttotal += value\n\t}\n\tprintln(int_str(keys.len))\n\tprintln(int_str(values.len))\n\tprintln(int_str(total))\n}\n")
240 assert out == '2\n2\n3'
241}
242
243fn test_map_str_preserves_signed_wide_entries() {
244 v3_bin := build_v3_review_transform()
245 out := run_good(v3_bin, 'map_str_signed_wide_entries',
246 "fn main() {\n\tvalue_map := {\n\t\t'x': i64(5000000000)\n\t}\n\tkey_map := {\n\t\ti64(-5000000000): 'x'\n\t}\n\tprintln(value_map.str())\n\tprintln(key_map.str())\n}\n")
247 assert out == "{'x': 5000000000}\n{-5000000000: 'x'}"
248}
249
250fn test_map_str_normalizes_alias_key_and_value_types() {
251 v3_bin := build_v3_review_transform()
252 out := run_good(v3_bin, 'map_str_alias_kinds',
253 "type ID = int\n\ntype Amount = f64\n\nfn main() {\n\tids := {\n\t\tID(23): 'id'\n\t}\n\tamounts := {\n\t\t'price': Amount(1.25)\n\t}\n\tprintln('\${ids}')\n\tprintln('\${amounts}')\n}\n")
254 assert out == "{23: 'id'}\n{'price': 1.25}"
255}
256
257fn test_map_literal_stringification_evaluates_entries_once() {
258 v3_bin := build_v3_review_transform()
259 out := run_good(v3_bin, 'map_literal_str_side_effects',
260 "__global key_calls int\n__global val_calls int\n\nfn next_key() string {\n\tkey_calls++\n\treturn 'k' + int_str(key_calls)\n}\n\nfn next_val() int {\n\tval_calls++\n\treturn val_calls * 10\n}\n\nfn main() {\n\tprintln({\n\t\tnext_key(): next_val()\n\t})\n\tprintln(int_str(key_calls) + ',' + int_str(val_calls))\n}\n")
261 assert out == "{'k1': 10}\n1,1"
262}
263
264fn test_shadowed_minmaxof_calls_are_not_rewritten() {
265 v3_bin := build_v3_review_transform()
266 out := run_good_project(v3_bin, 'shadowed_minmaxof_calls', {
267 'main.v': 'module main\n\nimport shadow { maxof, minof }\n\nfn main() {\n\tprintln(int_str(maxof[int]()))\n\tprintln(int_str(minof[int]()))\n}\n'
268 'shadow/shadow.v': 'module shadow\n\npub fn maxof[T]() int {\n\treturn 7\n}\n\npub fn minof[T]() int {\n\treturn -7\n}\n'
269 }, 'main.v')
270 assert out == '7\n-7'
271}
272
273fn test_runes_iterator_index_is_loop_scoped() {
274 v3_bin := build_v3_review_transform()
275 out := run_good(v3_bin, 'runes_iterator_index_scope',
276 "fn main() {\n\tfor i, r in 'ab'.runes_iterator() {\n\t\t_ := r\n\t\tprintln(int_str(i))\n\t}\n\ti := 9\n\tprintln(int_str(i))\n}\n")
277 assert out == '0\n1\n9'
278}
279
280fn test_array_last_index_uses_element_width() {
281 v3_bin := build_v3_review_transform()
282 out := run_good(v3_bin, 'array_last_index_element_width',
283 'fn main() {\n\twide := [i64(1), i64(5000000000), i64(2), i64(5000000000)]\n\tfloats := [1.25, 2.5, 1.25]\n\tflags := [true, false, true]\n\tprintln(int_str(wide.last_index(i64(5000000000))))\n\tprintln(int_str(floats.last_index(1.25)))\n\tprintln(int_str(flags.last_index(true)))\n}\n')
284 assert out == '3\n2\n2'
285}
286
287fn test_array_last_index_uses_semantic_element_comparison() {
288 v3_bin := build_v3_review_transform()
289 out := run_good(v3_bin, 'array_last_index_semantic_equality',
290 "struct Item {\n\tname string\n\tparts []string\n}\n\nfn join(a string, b string) string {\n\treturn a + b\n}\n\nfn main() {\n\tnested := [['ab'.clone()], [join('x', 'y')], [join('a', 'b')]]\n\tnested_needle := ['ab'.clone()]\n\titems := [Item{\n\t\tname: 'ab'.clone()\n\t\tparts: ['xy'.clone()]\n\t}, Item{\n\t\tname: join('a', 'b')\n\t\tparts: [join('x', 'y')]\n\t}]\n\tneedle := Item{\n\t\tname: 'ab'.clone()\n\t\tparts: ['xy'.clone()]\n\t}\n\tprintln(int_str(nested.last_index(nested_needle)))\n\tprintln(int_str(items.last_index(needle)))\n}\n")
291 assert out == '2\n1'
292}
293
294fn test_hierarchical_import_runtime_inits_before_importer_init() {
295 v3_bin := build_v3_review_transform()
296 out := run_good_project(v3_bin, 'hierarchical_runtime_init_order', {
297 'main.v': 'module main\n\nimport foo.user\nimport bar as shortbar\n\nfn main() {\n\t_ := shortbar.value()\n\tprintln(int_str(user.value()))\n}\n'
298 'foo/user/user.v': 'module user\n\nimport foo.bar as foobar\n\n__global seen int\n\nfn init() {\n\tseen = foobar.value() + 1\n}\n\npub fn value() int {\n\treturn seen\n}\n'
299 'foo/bar/bar.v': 'module bar\n\n__global flag = make_flag()\n\nfn make_flag() int {\n\treturn 40\n}\n\npub fn value() int {\n\treturn flag\n}\n'
300 'bar/bar.v': 'module bar\n\n__global flag = make_flag()\n\nfn make_flag() int {\n\treturn 3\n}\n\npub fn value() int {\n\treturn flag\n}\n'
301 'unrelated/other.v': 'module other\n\npub fn value() int {\n\treturn 0\n}\n'
302 }, 'main.v')
303 assert out == '41'
304}
305