| 1 | import os |
| 2 | |
| 3 | const vexe = @VEXE |
| 4 | const tests_dir = os.dir(@FILE) |
| 5 | const v3_dir = os.dir(tests_dir) |
| 6 | const vlib_dir = os.dir(v3_dir) |
| 7 | const v3_src = os.join_path(v3_dir, 'v3.v') |
| 8 | |
| 9 | fn 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 | |
| 16 | fn 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 | |
| 26 | fn 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 | |
| 38 | fn 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 | |
| 44 | fn 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 | |
| 63 | fn 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 | |
| 82 | fn 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 | |
| 89 | fn 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 | |
| 96 | fn 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 | |
| 103 | fn 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 | |
| 110 | fn 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 | |
| 117 | fn 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 | |
| 124 | fn 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 | |
| 133 | fn 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 | |
| 140 | fn 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 | |
| 147 | fn 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 | |
| 154 | fn 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 | |
| 161 | fn 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 | |
| 170 | fn 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 | |
| 177 | fn 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 | |
| 202 | fn 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 | |
| 215 | fn 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 | |
| 222 | fn 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 | |
| 229 | fn 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 | |
| 236 | fn 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 | |
| 243 | fn 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 | |
| 250 | fn 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 | |
| 257 | fn 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 | |
| 264 | fn 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 | |
| 273 | fn 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 | |
| 280 | fn 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 | |
| 287 | fn 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 | |
| 294 | fn 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 | |