| 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() string { |
| 10 | v3_bin := os.join_path(os.temp_dir(), 'v3_fn_nil_context_test') |
| 11 | build := |
| 12 | os.execute('${vexe} -gc none -path "${vlib_dir}|@vlib|@vmodules" -o ${v3_bin} ${v3_src}') |
| 13 | assert build.exit_code == 0, build.output |
| 14 | return v3_bin |
| 15 | } |
| 16 | |
| 17 | fn run_good(v3_bin string, name string, src string) string { |
| 18 | good_src := os.join_path(os.temp_dir(), 'v3_${name}.v') |
| 19 | os.write_file(good_src, src) or { panic(err) } |
| 20 | good_bin := os.join_path(os.temp_dir(), 'v3_${name}') |
| 21 | compile := os.execute('${v3_bin} ${good_src} -b c -o ${good_bin}') |
| 22 | assert compile.exit_code == 0, '${name}: compile failed: ${compile.output}' |
| 23 | assert !compile.output.contains('C compilation failed'), '${name}: C compilation failed: ${compile.output}' |
| 24 | run := os.execute(good_bin) |
| 25 | assert run.exit_code == 0, '${name}: run failed: ${run.output}' |
| 26 | return run.output.trim_space() |
| 27 | } |
| 28 | |
| 29 | fn run_bad(v3_bin string, name string, src string, expected string) { |
| 30 | bad_src := os.join_path(os.temp_dir(), 'v3_${name}.v') |
| 31 | os.write_file(bad_src, src) or { panic(err) } |
| 32 | bad_bin := os.join_path(os.temp_dir(), 'v3_${name}') |
| 33 | result := os.execute('${v3_bin} ${bad_src} -b c -o ${bad_bin}') |
| 34 | assert result.exit_code != 0 |
| 35 | assert result.output.contains(expected), '${name}: missing `${expected}` in ${result.output}' |
| 36 | assert !result.output.contains('C compilation failed') |
| 37 | } |
| 38 | |
| 39 | fn test_unsafe_nil_contextually_matches_fn_fields() { |
| 40 | v3_bin := build_v3() |
| 41 | default_out := run_good(v3_bin, 'fn_nil_default', 'struct S { |
| 42 | f fn (int) ! = unsafe { nil } |
| 43 | } |
| 44 | |
| 45 | fn main() { |
| 46 | _ := S{} |
| 47 | println(int_str(1)) |
| 48 | } |
| 49 | ') |
| 50 | assert default_out == '1' |
| 51 | alias_out := run_good(v3_bin, 'fn_alias_nil_field_init', 'type Callback = fn (data voidptr) |
| 52 | |
| 53 | struct S { |
| 54 | f Callback |
| 55 | } |
| 56 | |
| 57 | fn main() { |
| 58 | _ := S{ |
| 59 | f: unsafe { nil } |
| 60 | } |
| 61 | println(int_str(2)) |
| 62 | } |
| 63 | ') |
| 64 | assert alias_out == '2' |
| 65 | run_bad(v3_bin, 'fn_field_rejects_voidptr_variable', 'struct S { |
| 66 | f fn (int) ! |
| 67 | } |
| 68 | |
| 69 | fn main() { |
| 70 | v := unsafe { nil } |
| 71 | _ := S{ |
| 72 | f: v |
| 73 | } |
| 74 | } |
| 75 | ', |
| 76 | 'cannot initialize field `f` with `&void`; expected `fn(int) !void`') |
| 77 | run_bad(v3_bin, 'fn_field_rejects_non_nil_unsafe_pointer', 'struct S { |
| 78 | f fn (int) ! |
| 79 | } |
| 80 | |
| 81 | fn main() { |
| 82 | _ := S{ |
| 83 | f: unsafe { &int(0) } |
| 84 | } |
| 85 | } |
| 86 | ', |
| 87 | 'cannot initialize field `f` with `&int`; expected `fn(int) !void`') |
| 88 | run_bad(v3_bin, 'fn_field_rejects_voidptr_zero', 'struct S { |
| 89 | f fn (int) ! |
| 90 | } |
| 91 | |
| 92 | fn main() { |
| 93 | _ := S{ |
| 94 | f: voidptr(0) |
| 95 | } |
| 96 | } |
| 97 | ', |
| 98 | 'cannot initialize field `f` with `&void`; expected `fn(int) !void`') |
| 99 | run_bad(v3_bin, 'fn_field_rejects_integer_zero', 'struct S { |
| 100 | f fn (int) ! |
| 101 | } |
| 102 | |
| 103 | fn main() { |
| 104 | _ := S{ |
| 105 | f: 0 |
| 106 | } |
| 107 | } |
| 108 | ', |
| 109 | 'cannot initialize field `f` with `int`; expected `fn(int) !void`') |
| 110 | run_bad(v3_bin, 'fn_field_rejects_wrong_arity', 'fn no_args() ! { |
| 111 | return |
| 112 | } |
| 113 | |
| 114 | struct S { |
| 115 | f fn (int) ! |
| 116 | } |
| 117 | |
| 118 | fn main() { |
| 119 | _ := S{ |
| 120 | f: no_args |
| 121 | } |
| 122 | } |
| 123 | ', |
| 124 | 'cannot initialize field `f` with `fn() !void`; expected `fn(int) !void`') |
| 125 | run_bad(v3_bin, 'fn_field_rejects_wrong_return', 'fn returns_int(i int) !int { |
| 126 | return i |
| 127 | } |
| 128 | |
| 129 | struct S { |
| 130 | f fn (int) ! |
| 131 | } |
| 132 | |
| 133 | fn main() { |
| 134 | _ := S{ |
| 135 | f: returns_int |
| 136 | } |
| 137 | } |
| 138 | ', |
| 139 | 'cannot initialize field `f` with `fn(int) !int`; expected `fn(int) !void`') |
| 140 | run_bad(v3_bin, 'fn_alias_field_rejects_wrong_arity', 'type Callback = fn (int) ! |
| 141 | |
| 142 | fn no_args() ! { |
| 143 | return |
| 144 | } |
| 145 | |
| 146 | struct S { |
| 147 | f Callback |
| 148 | } |
| 149 | |
| 150 | fn main() { |
| 151 | _ := S{ |
| 152 | f: no_args |
| 153 | } |
| 154 | } |
| 155 | ', |
| 156 | 'cannot initialize field `f` with `fn() !void`; expected `Callback`') |
| 157 | } |
| 158 | |