1 /// Copyright: Copyright (c) 2017-2020 Andrey Penechko.
2 /// License: $(WEB boost.org/LICENSE_1_0.txt, Boost License 1.0).
3 /// Authors: Andrey Penechko.
4 module tests.passing;
5 
6 import core.stdc.stdlib : malloc, free;
7 import std.stdio;
8 import tester;
9 
10 Test[] passingTests() { return collectTests!(tests.passing)(); }
11 
12 /// Used to force correct type of float literal, like `42.54f.force`
13 /// Without it, 42.54f will be store as dobule by the compiler
14 T force(T)(T t) { return t; }
15 
16 extern(C) void external_print_i32_func(int par1) {
17 	formattedWrite(testSink, "%s ", par1);
18 }
19 extern(C) void external_print_i64_func(long par1) {
20 	formattedWrite(testSink, "%s ", par1);
21 }
22 extern(C) void external_print_string(Slice!char param) {
23 	char[] slice = *cast(char[]*)&param;
24 	testSink.put(slice);
25 }
26 
27 @TestInfo(&tester7)
28 immutable test7 = q{--- test7
29 	i32 fib(i32 number) {
30 		if (number < 1) return 0;
31 		if (number < 3) return 1;
32 		return fib(number-1) + fib(number-2);
33 	}
34 };
35 void tester7(ref TestContext ctx) {
36 	auto fib = ctx.getFunctionPtr!(int, int)("fib");
37 	immutable int[] results = [1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144, 233,
38 	377, 610, 987, 1597, 2584, 4181, 6765];
39 	foreach(size_t i, int expected; results)
40 	{
41 		int res = fib(cast(int)i+1);
42 		assert(res == expected, format("%s != %s", res, expected));
43 	}
44 }
45 
46 
47 @TestInfo()
48 immutable test9 = q{--- test9
49 	i32 test(i32 number) {
50 		i32 result;
51 		if (1 == 1)
52 		{
53 			result = 1;
54 		}
55 		else
56 		{
57 			result = 0;
58 		}
59 		return result;
60 	}
61 };
62 
63 
64 @TestInfo(&tester8)
65 immutable test8 = q{--- test8
66 	i32 sign(i32 number) {
67 		i32 result;
68 		if (number < 0) result = 0-1;
69 		else if (number > 0) result = 1;
70 		else result = 0;
71 		return result;
72 	}
73 };
74 
75 
76 @TestInfo(&tester8)
77 immutable test8_1 = q{--- test8_1
78 	i32 sign(i32 number) {
79 		if (number < 0) return 0-1;
80 		else if (number > 0) return 1;
81 		else return 0;
82 	}
83 };
84 
85 void tester8(ref TestContext ctx) {
86 	auto sign = ctx.getFunctionPtr!(int, int)("sign");
87 	int res1 = sign(10);
88 	int res2 = sign(0);
89 	int res3 = sign(-10);
90 	//writefln("sign(10) -> %s", res1);
91 	//writefln("sign(0) -> %s", res2);
92 	//writefln("sign(-10) -> %s", res3);
93 	assert(res1 == 1);
94 	assert(res2 == 0);
95 	assert(res3 == -1);
96 }
97 
98 
99 @TestInfo(&tester10)
100 immutable test10 = q{--- test10
101 	// Test reading pointer at zero index
102 	i32 run(i32* array) {
103 		return array[0];
104 	}
105 };
106 void tester10(ref TestContext ctx) {
107 	auto run = ctx.getFunctionPtr!(int, int*)("run");
108 	int val = 42;
109 	int res = run(&val);
110 	//writefln("test(&42) -> %s", res);
111 	assert(res == 42);
112 }
113 
114 
115 @TestInfo(&tester11)
116 immutable test11 = q{--- test11
117 	// Test reading pointer at constant non-zero index
118 	i32 run(i32* array) {
119 		return array[1];
120 	}
121 };
122 void tester11(ref TestContext ctx) {
123 	auto run = ctx.getFunctionPtr!(int, int*)("run");
124 	int[2] val = [42, 56];
125 	int res = run(val.ptr);
126 	//writefln("test([42, 56].ptr) -> %s", res);
127 	assert(res == 56);
128 }
129 
130 
131 @TestInfo(&tester12)
132 immutable test12 = q{--- test12
133 	// Test reading pointer at variable index
134 	i32 run(i32* array, i32 index) {
135 		return array[index];
136 	}
137 };
138 void tester12(ref TestContext ctx) {
139 	auto run = ctx.getFunctionPtr!(int, int*, int)("run");
140 	int[2] val = [42, 56];
141 	int res0 = run(val.ptr, 0);
142 	int res1 = run(val.ptr, 1);
143 	//writefln("test([42, 56].ptr, 1) -> %s", res);
144 	assert(res0 == 42);
145 	assert(res1 == 56);
146 }
147 
148 
149 @TestInfo(&tester13)
150 immutable test13 = q{--- test13
151 	// Test pointer index assign
152 	void run(i32* array, i32 index, i32 value) {
153 		array[index] = value;
154 	}
155 };
156 void tester13(ref TestContext ctx) {
157 	auto run = ctx.getFunctionPtr!(void, int*, int, int)("run");
158 	int[4] val = [42, 56, 96, 102];
159 	int[4] expected = [42, 20, 96, 102];
160 	run(val.ptr, 1, 20);
161 	//writefln("test([42, 56].ptr, 1, 20) -> %s", val);
162 	assert(val == expected, format("%s != %s", val, expected));
163 }
164 
165 
166 @TestInfo(&tester14)
167 immutable test14 = q{--- test14
168 	// Test pointer index assign
169 	void run(i32* array, i32 index, i32 value, i32 value2, i32 value3) {
170 		array[index] = value + value2 + value3;
171 	}
172 };
173 void tester14(ref TestContext ctx) {
174 	auto run = ctx.getFunctionPtr!(void, int*, int, int, int, int)("run");
175 	int[2] val = [42, 56];
176 	run(val.ptr, 1, 10, 6, 4);
177 	//writefln("test([42, 56].ptr, 1, 10, 6, 4) -> %s", val);
178 	assert(val[1] == 20);
179 }
180 
181 
182 @TestInfo(&tester15, [HostSymbol("external", cast(void*)&test15_external_func)])
183 immutable test15 = q{--- test15
184 	// Test 3 inputs no parameters pushed to the stack
185 	i32 run(i32 par) {
186 		return external(par, 10, 20);
187 	}
188 	@extern(module, "host")
189 	i32 external(i32, i32, i32);
190 };
191 extern(C) int test15_external_func(int par1, int par2, int par3) {
192 	return par1 + par2 + par3;
193 }
194 void tester15(ref TestContext ctx) {
195 	auto run = ctx.getFunctionPtr!(int, int)("run");
196 	int result = run(10);
197 	//writefln("fun(10) -> %s", result);
198 	assert(result == 40);
199 }
200 
201 
202 @TestInfo(&tester16, [HostSymbol("external", cast(void*)&test16_external_func)])
203 immutable test16 = q{--- test16
204 	// Test more than 4 inputs (5-th parameter pushed to the stack, extra alignment needed)
205 	i32 run(i32 par) {
206 		return external(par, 10, 20, 30, 40);
207 	}
208 	@extern(module, "host")
209 	i32 external(i32, i32, i32, i32, i32);
210 };
211 extern(C) int test16_external_func(int par1, int par2, int par3, int par4, int par5) {
212 	return par1 + par2 + par3 + par4 + par5;
213 }
214 void tester16(ref TestContext ctx) {
215 	auto run = ctx.getFunctionPtr!(int, int)("run");
216 	int result = run(10);
217 	//writefln("fun(10) -> %s", result);
218 	assert(result == 110);
219 }
220 
221 
222 @TestInfo(&tester17, [HostSymbol("external", cast(void*)&test17_external_func)])
223 immutable test17 = q{--- test17
224 	// Test 6 inputs (5-th and 6-th parameters pushed to the stack, no extra alignment needed)
225 	i32 run(i32 par) {
226 		return external(par, 10, 20, 30, 40, 50);
227 	}
228 	@extern(module, "host")
229 	i32 external(i32, i32, i32, i32, i32, i32);
230 };
231 extern(C) int test17_external_func(int par1, int par2, int par3, int par4, int par5, int par6) {
232 	return par1 + par2 + par3 + par4 + par5 + par6;
233 }
234 void tester17(ref TestContext ctx) {
235 	auto run = ctx.getFunctionPtr!(int, int)("run");
236 	int result = run(10);
237 	//writefln("fun(10) -> %s", result);
238 	assert(result == 160);
239 }
240 
241 void testerRunVoid(ref TestContext ctx) {
242 	auto run = ctx.getFunctionPtr!(void)("run");
243 	run();
244 }
245 
246 
247 @TestInfo(&testerRunVoid)
248 immutable test18 = q{--- test18
249 	// test empty void function
250 	void run() {}
251 };
252 
253 
254 @TestInfo(&testerRunVoid)
255 immutable test19 = q{--- test19
256 	// test empty void function with return
257 	void run() { return; }
258 };
259 
260 
261 @TestInfo(&tester20)
262 immutable test20 = q{--- test20
263 	// test empty i32 function without return and with control flow
264 	void run(i32 i) { if(i){}else{} }
265 };
266 void tester20(ref TestContext ctx) {
267 	auto run = ctx.getFunctionPtr!(void, int)("run");
268 	run(1);
269 }
270 
271 
272 void tester21(ref TestContext ctx) {
273 	auto fibonacci = ctx.getFunctionPtr!(void)("fibonacci");
274 	fibonacci();
275 	assert(testSink.text == "1 1 2 3 5 8 13 21 34 55 89 144 233 377 610 987 1597 2584 4181 6765");
276 }
277 
278 
279 @TestInfo(&tester21, [HostSymbol("print", cast(void*)&external_print_i32_func)])
280 immutable test21 = q{--- test21
281 	// test fibonacci. while loop. func call
282 	@extern(module, "host")
283 	void print(i32); // external
284 	void fibonacci() {
285 		i32 lo = 0;
286 		i32 hi = 1;
287 		while (hi < 10000) {
288 			hi = hi + lo;
289 			lo = hi - lo;
290 			print(lo);
291 		}
292 	}
293 };
294 
295 
296 @TestInfo(&tester21, [HostSymbol("print", cast(void*)&external_print_i32_func)])
297 immutable test21_2 = q{--- test21_2
298 	// Causes other order of phi functions, which requires correct move sequence to resolve
299 	// Tests phi resolution after register allocation
300 	@extern(module, "host")
301 	void print(i32); // external
302 	void fibonacci() {
303 		i32 lo = 0;
304 		i32 hi = 1;
305 		while (hi < 10000) {
306 			i32 tmp = hi;
307 			hi = hi + lo;
308 			lo = tmp;
309 			print(lo);
310 		}
311 	}
312 };
313 
314 
315 @TestInfo(&tester22)
316 immutable test22 = q{--- test22
317 	// test phi resolution with critical edge and test break;
318 	i32 run() {
319 		i32 counter = 10;
320 		i32 counter2 = 0;
321 		while (counter > 0)
322 		{
323 			counter = counter - 1;
324 			counter2 = counter2 + 1;
325 			if (counter2 == 5) break;
326 		}
327 		return counter;
328 	}
329 };
330 void tester22(ref TestContext ctx) {
331 	auto run = ctx.getFunctionPtr!(int)("run");
332 	int res = run();
333 	assert(res == 5);
334 }
335 
336 
337 @TestInfo(&tester23)
338 immutable test23 = q{--- test23
339 	// test continue
340 	i32 run() {
341 		i32 counter = 10;
342 		i32 counter2 = 2;
343 		while (counter > 0) {
344 			counter = counter - 1;
345 			if (counter < 5) continue;
346 			counter2 = counter2 + 1;
347 		}
348 		return counter2;
349 	}
350 };
351 void tester23(ref TestContext ctx) {
352 	auto run = ctx.getFunctionPtr!(int)("run");
353 	int res = run();
354 	assert(res == 7);
355 }
356 
357 
358 @TestInfo(&tester24, [HostSymbol("print", cast(void*)&test24_external_print)])
359 immutable test24 = q{--- test24
360 	// test string literal as u8* param
361 	@extern(module, "host")
362 	void print(u8*);
363 	void run(){ print("Hello"); }
364 };
365 extern(C) void test24_external_print(ubyte* param) {
366 	testSink.put(cast(char[])param[0..5]); // Hello
367 }
368 void tester24(ref TestContext ctx) {
369 	auto run = ctx.getFunctionPtr!(void)("run");
370 	run();
371 	assert(testSink.text == "Hello");
372 }
373 
374 
375 @TestInfo(&tester25, [HostSymbol("print", cast(void*)&external_print_string)])
376 immutable test25 = q{--- test25
377 	// test struct creation, member set, stack struct as func argument
378 	struct string { u64 length; u8* ptr; }
379 	@extern(module, "host")
380 	void print(string);
381 	void run(){
382 		string str;
383 		str.ptr = "Hello";
384 		str.length = 5;
385 		print(str);
386 	}
387 };
388 void tester25(ref TestContext ctx) {
389 	auto run = ctx.getFunctionPtr!(void)("run");
390 	run();
391 	//writefln("run() == '%s'", testSink.text);
392 	assert(testSink.text == "Hello");
393 }
394 
395 
396 @TestInfo(&tester25, [HostSymbol("print", cast(void*)&external_print_string)])
397 immutable test26 = q{--- test26
398 	// test global parameter, assignment
399 	struct string { u64 length; u8* ptr; }
400 	@extern(module, "host")
401 	void print(string);
402 	string str;
403 	void run(){
404 		str.ptr = "Hello";
405 		str.length = 5;
406 		print(str);
407 	}
408 };
409 
410 
411 @TestInfo(&tester27, [HostSymbol("print", cast(void*)&external_print_string)])
412 immutable test27 = q{--- test27
413 	// test slices
414 	@extern(module, "host")
415 	void print(u8[]);
416 	void run() {
417 		u8[] array;
418 		array.length = 9;
419 		// Assign string literal to ptr
420 		array.ptr = "AssignPtr";
421 		print(array);
422 
423 		// Assign string literal to slice
424 		array = "AssignSlice";
425 		print(array);
426 	}
427 };
428 void tester27(ref TestContext ctx) {
429 	auto run = ctx.getFunctionPtr!(void)("run");
430 	run();
431 	//writefln("run() == '%s'", testSink.text);
432 	assert(testSink.text == "AssignPtrAssignSlice");
433 }
434 
435 
436 @TestInfo(&tester31, [HostSymbol("print_num", cast(void*)&test31_external_print_num)])
437 immutable test31 = q{--- test31
438 	// test enums
439 	//enum i32 e2; // manifest constant, invalid, need initializer
440 	enum e3 = 3; // manifest constant
441 	enum i32 e4 = 4; // manifest constant
442 
443 	enum { e5 = 5 } // anon type
444 	enum : i32 { e6 = 6 } // anon type
445 
446 	enum e1; // type
447 	enum e7 : i32 { e7 = 7 } // type
448 	enum e8 : i32; // type, body omitted
449 	enum e9 { e9 = 9 } // type
450 
451 	@extern(module, "host")
452 	void print_num(i64 val);
453 	e9 ret_enum(){ return e9.e9; }
454 	void accept_enum(e9 e){print_num(e);}
455 	void run() {
456 		print_num(e3);
457 		print_num(e4);
458 		print_num(e5);
459 		print_num(e6);
460 		// enum implicitly casts to base
461 		print_num(e7.e7);
462 		print_num(e9.e9);
463 		accept_enum(e9.e9);
464 		// explicit cast of int to enum
465 		accept_enum(cast(e9)42);
466 		// makes sure that e9.e9 is of type e9 and that e9 is implicitly castable to i32
467 		print_num(ret_enum());
468 	}
469 };
470 extern(C) void test31_external_print_num(long param) {
471 	testSink.putf("%s", param);
472 }
473 void tester31(ref TestContext ctx) {
474 	auto run = ctx.getFunctionPtr!(void)("run");
475 	run();
476 	//writefln("run() == '%s'", testSink.text);
477 	assert(testSink.text == "3456799429");
478 }
479 
480 
481 @TestInfo(&tester21, [HostSymbol("print", cast(void*)&external_print_i32_func)])
482 immutable test32 = q{--- test32
483 	// Test reg alloc xchg generation
484 	@extern(module, "host")
485 	void print(i32); // external
486 	void fibonacci() {
487 		i32 lo = 0;
488 		i32 hi = 1;
489 		while (hi < 10000) {
490 			i32 tmp = hi;
491 			hi = hi + lo;
492 			lo = tmp;
493 			print(lo);
494 		}
495 		while (hi < 10000) {
496 			i32 tmp = hi;
497 			hi = hi + lo;
498 			lo = tmp;
499 			print(lo);
500 		}
501 		while (hi < 10000) {
502 			i32 tmp = hi;
503 			hi = hi + lo;
504 			lo = tmp;
505 			print(lo);
506 		}
507 		while (hi < 10000) {
508 			i32 tmp = hi;
509 			hi = hi + lo;
510 			lo = tmp;
511 			print(lo);
512 		}
513 	}
514 };
515 
516 
517 @TestInfo(&tester21, [HostSymbol("print", cast(void*)&external_print_i32_func)])
518 immutable test33 = q{
519 --- test33_1
520 	// test multifile compilation
521 	@extern(module, "host")
522 	void print(i32); // external
523 --- test33_2
524 	import test33_1;
525 	void fibonacci() {
526 		i32 lo = 0;
527 		i32 hi = 1;
528 		while (hi < 10000) {
529 			hi = hi + lo;
530 			lo = hi - lo;
531 			print(lo);
532 		}
533 	}
534 };
535 
536 @TestInfo(&tester34)
537 immutable test34 = q{--- test34
538 	i32 getElement(i32[] items, i32 index) { return items[index]; }
539 };
540 void tester34(ref TestContext ctx) {
541 	auto getElement = ctx.getFunctionPtr!(int, Slice!int, int)("getElement");
542 	int[2] val = [42, 56];
543 	Slice!int slice = Slice!int(val);
544 	int res0 = getElement(slice, 0);
545 	int res1 = getElement(slice, 1);
546 	assert(res0 == 42);
547 	assert(res1 == 56);
548 }
549 
550 
551 @TestInfo(&tester35)
552 immutable test35 = q{--- test35
553 	void setElement(i32[] items, i32 index, i32 value) { items[index] = value; }
554 };
555 void tester35(ref TestContext ctx) {
556 	auto setElement = ctx.getFunctionPtr!(void, Slice!int, int, int)("setElement");
557 	int[2] val = [42, 56];
558 	Slice!int slice = Slice!int(val);
559 	setElement(slice, 0, 88);
560 	assert(val == [88, 56]);
561 	setElement(slice, 1, 96);
562 	assert(val == [88, 96]);
563 }
564 
565 
566 @TestInfo()
567 immutable test36 = q{--- test36
568 	// Test null literal implicit conversion to pointer types
569 	void test() {
570 		callee1(null);
571 		callee2(null);
572 	}
573 	void callee1(void*) {}
574 	void callee2(u8*) {}
575 };
576 
577 
578 @TestInfo()
579 immutable test37 = q{--- test37
580 	// Test negative int literal
581 	void test() {
582 		callee1(-1);
583 	}
584 	void callee1(i32) {}
585 };
586 
587 
588 @TestInfo()
589 immutable test38 = q{--- test38
590 	// Test empty struct
591 	struct A {}
592 };
593 
594 
595 @TestInfo(&tester39)
596 immutable test39 = q{--- test39
597 	// Test shifts
598 	i32 shl(i32 a, i32 b) {
599 		return a << b;
600 	}
601 	i32 shr(i32 a, i32 b) {
602 		return a >> b;
603 	}
604 	i32 sar(i32 a, i32 b) {
605 		return a >>> b;
606 	}
607 };
608 void tester39(ref TestContext ctx) {
609 	auto shl = ctx.getFunctionPtr!(int, int, int)("shl");
610 	auto shr = ctx.getFunctionPtr!(int, int, int)("shr");
611 	auto sar = ctx.getFunctionPtr!(int, int, int)("sar");
612 	foreach(i; 0..33) {
613 		int res = shl(1, i);
614 		assert(res == 1 << i);
615 		//writefln("1 << %s == %b", i, res);
616 
617 		enum HIGH_BIT = 1 << 31;
618 		int res2 = shr(HIGH_BIT, i);
619 		//writefln("%032b >> %s == %032b", HIGH_BIT, i, res2);
620 		assert(res2 == HIGH_BIT >> i);
621 
622 		int res3 = sar(HIGH_BIT, i);
623 		assert(res3 == HIGH_BIT >>> i);
624 		//writefln("%032b >>> %s == %032b", HIGH_BIT, i, res3);
625 	}
626 }
627 
628 
629 @TestInfo(&tester40)
630 immutable test40 = q{--- test40
631 	// Test left shift by a constant
632 	i32 shl(i32 a) {
633 		i32 res1 = a << 1;
634 		i32 res2 = 4 << a;
635 		i32 res3 = a << 3;
636 		i32 res4 = a << 31;
637 		i32 res5 = 1 << 31;
638 		return res1 + res2 + res3 + res4 + res5;
639 	}
640 };
641 void tester40(ref TestContext ctx) {
642 	auto shl = ctx.getFunctionPtr!(int, int)("shl");
643 	int res = shl(1);
644 	//writefln("%b", res);
645 	assert(res == (1 << 1) + (4 << 1) + (1 << 3) + (1 << 31) + (1 << 31));
646 }
647 
648 
649 @TestInfo(&tester41)
650 immutable test41 = q{--- test41
651 	// Test division, multiplication, remainder
652 	i32 idiv(i32 a, i32 b) {
653 		return a / b;
654 	}
655 	u32 div(u32 a, u32 b) {
656 		return a / b;
657 	}
658 	i32 imul(i32 a, i32 b) {
659 		return a * b;
660 	}
661 	u32 mul(u32 a, u32 b) {
662 		return a * b;
663 	}
664 	i32 irem(i32 a, i32 b) {
665 		return a % b;
666 	}
667 	u32 rem(u32 a, u32 b) {
668 		return a % b;
669 	}
670 };
671 void tester41(ref TestContext ctx) {
672 	auto div = ctx.getFunctionPtr!(int, int, int)("div");
673 	auto idiv = ctx.getFunctionPtr!(int, int, int)("idiv");
674 	auto rem = ctx.getFunctionPtr!(int, int, int)("rem");
675 	auto irem = ctx.getFunctionPtr!(int, int, int)("irem");
676 	auto mul = ctx.getFunctionPtr!(int, int, int)("mul");
677 	auto imul = ctx.getFunctionPtr!(int, int, int)("imul");
678 	int resDiv = div(10, 5);
679 	//writefln("10 / 5 == %s", resDiv);
680 	assert(resDiv == 10 / 5);
681 	int resIdiv = idiv(-10, 5);
682 	//writefln("-10 / 5 == %s %s", resIdiv, -10 / 5);
683 	assert(resIdiv == -10 / 5);
684 	int resRem = rem(10, 4);
685 	//writefln("10 %% 4 == %s", resRem);
686 	assert(resRem == 10 % 4);
687 	int resIrem = irem(-10, 4);
688 	//writefln("-10 %% 4 == %s %s", resIrem, -10 % 4);
689 	assert(resIrem == -10 % 4);
690 	int resMul = mul(-10, 4);
691 	//writefln("-10 * 4 == %s %s", resMul, -10 * 4);
692 	assert(resMul == -10 * 4);
693 	int resImul = imul(-10, 4);
694 	//writefln("-10 * 4 == %s %s", resImul, -10 * 4);
695 	assert(resImul == -10 * 4);
696 }
697 
698 
699 @TestInfo(&tester42)
700 immutable test42 = q{--- test42
701 	// Test bit-wise negation, unary minus, xor, or, and operators
702 	i32 not(i32 a) {
703 		return ~a;
704 	}
705 	i32 neg(i32 a) {
706 		return -a;
707 	}
708 	i32 xor(i32 a, i32 b) {
709 		return a ^ b;
710 	}
711 	i32 or(i32 a, i32 b) {
712 		return a | b;
713 	}
714 	i32 and(i32 a, i32 b) {
715 		return a & b;
716 	}
717 };
718 void tester42(ref TestContext ctx) {
719 	auto not = ctx.getFunctionPtr!(int, int)("not");
720 	auto neg = ctx.getFunctionPtr!(int, int)("neg");
721 	auto xor = ctx.getFunctionPtr!(int, int, int)("xor");
722 	auto or  = ctx.getFunctionPtr!(int, int, int)("or");
723 	auto and = ctx.getFunctionPtr!(int, int, int)("and");
724 
725 	int res_not = not(0b01);
726 	//writefln("~0b01 == %02b", res_not);
727 	assert(res_not == ~0b01);
728 
729 	int res_neg = neg(1);
730 	//writefln("-1 == %s", res_neg);
731 	assert(res_neg == -1);
732 
733 	int res_xor = xor(0b0011, 0b0101);
734 	//writefln("0b0011 ^ 0b0101 == %04b", res_xor);
735 	assert(res_xor == (0b0011 ^ 0b0101));
736 
737 	int res_or = or(0b0011, 0b0101);
738 	//writefln("0b0011 | 0b0101 == %04b", res_or);
739 	assert(res_or == (0b0011 | 0b0101));
740 
741 	int res_and = and(0b0011, 0b0101);
742 	//writefln("0b0011 & 0b0101 == %04b", res_and);
743 	assert(res_and == (0b0011 & 0b0101));
744 }
745 
746 
747 @TestInfo(&tester43)
748 immutable test43 = q{--- test43
749 	// Test op=
750 	i32 add(i32 a, i32 b) { a += b; return a; }
751 	i32 sub(i32 a, i32 b) { a -= b; return a; }
752 	i32 mul(i32 a, i32 b) { a *= b; return a; }
753 	i32 div(i32 a, i32 b) { a /= b; return a; }
754 	i32 rem(i32 a, i32 b) { a %= b; return a; }
755 	i32 shl(i32 a, i32 b) { a <<= b; return a; }
756 	i32 shr(i32 a, i32 b) { a >>>= b; return a; }
757 	i32 sar(i32 a, i32 b) { a >>= b; return a; }
758 	i32 or (i32 a, i32 b) { a |= b; return a; }
759 	i32 xor(i32 a, i32 b) { a ^= b; return a; }
760 	i32 and(i32 a, i32 b) { a &= b; return a; }
761 };
762 void tester43(ref TestContext ctx) {
763 	auto add = ctx.getFunctionPtr!(int, int, int)("add");
764 	auto sub = ctx.getFunctionPtr!(int, int, int)("sub");
765 	auto mul = ctx.getFunctionPtr!(int, int, int)("mul");
766 	auto div = ctx.getFunctionPtr!(int, int, int)("div");
767 	auto rem = ctx.getFunctionPtr!(int, int, int)("rem");
768 	auto shl = ctx.getFunctionPtr!(int, int, int)("shl");
769 	auto shr = ctx.getFunctionPtr!(int, int, int)("shr");
770 	auto sar = ctx.getFunctionPtr!(int, int, int)("sar");
771 	auto or  = ctx.getFunctionPtr!(int, int, int)("or");
772 	auto xor = ctx.getFunctionPtr!(int, int, int)("xor");
773 	auto and = ctx.getFunctionPtr!(int, int, int)("and");
774 
775 	assert(add(1, 3) == 4);
776 	assert(sub(3, 1) == 2);
777 	assert(mul(3, 2) == 6);
778 	assert(div(7, 2) == 3);
779 	assert(rem(7, 2) == 1);
780 	assert(shl(1, 2) == 4);
781 	assert(shr(int.min, 2) == (int.min >>> 2));
782 	assert(sar(int.min, 2) == (int.min >> 2));
783 	assert(or(0b0011, 0b0101) == 0b0111);
784 	assert(xor(0b0011, 0b0101) == 0b0110);
785 	assert(and(0b0011, 0b0101) == 0b0001);
786 }
787 
788 
789 @TestInfo(&tester44)
790 immutable test44 = q{--- test44
791 	// Test --a, ++a
792 	i32 preInc(i32 a) { return ++a + ++a; }
793 	i32 postInc(i32 a) { return a++ + a++; }
794 	i32 preDec(i32 a) { return --a + --a; }
795 	i32 postDec(i32 a) { return a-- + a--; }
796 
797 	i32* preIncPtr(i32* a) { return ++a; }
798 	i32* postIncPtr(i32* a) { return a++; }
799 	i32* preDecPtr(i32* a) { return --a; }
800 	i32* postDecPtr(i32* a) { return a--; }
801 };
802 void tester44(ref TestContext ctx) {
803 	auto preInc = ctx.getFunctionPtr!(int, int)("preInc");
804 	auto postInc = ctx.getFunctionPtr!(int, int)("postInc");
805 	auto preDec = ctx.getFunctionPtr!(int, int)("preDec");
806 	auto postDec = ctx.getFunctionPtr!(int, int)("postDec");
807 
808 	assert(preInc(10) == 23);
809 	assert(postInc(10) == 21);
810 	assert(preDec(3) == 3);
811 	assert(postDec(3) == 5);
812 
813 	auto preIncPtr = ctx.getFunctionPtr!(int*, int*)("preIncPtr");
814 	auto postIncPtr = ctx.getFunctionPtr!(int*, int*)("postIncPtr");
815 	auto preDecPtr = ctx.getFunctionPtr!(int*, int*)("preDecPtr");
816 	auto postDecPtr = ctx.getFunctionPtr!(int*, int*)("postDecPtr");
817 
818 	int[4] arr;
819 	assert(preIncPtr(&arr[1]) == &arr[2]);
820 	assert(postIncPtr(&arr[1]) == &arr[1]);
821 	assert(preDecPtr(&arr[1]) == &arr[0]);
822 	assert(postDecPtr(&arr[1]) == &arr[1]);
823 }
824 
825 
826 @TestInfo(&tester45)
827 immutable test45 = q{--- test45
828 	void incArray(i32* arr, i32 length) {
829 		i32 i = 0;
830 		while(i < length) {
831 			++arr[i++];
832 		}
833 	}
834 };
835 void tester45(ref TestContext ctx) {
836 	int[4] arr = [1, 2, 3, 4];
837 	auto incArray = ctx.getFunctionPtr!(void, int*, int)("incArray");
838 	incArray(arr.ptr, arr.length);
839 	assert(arr == [2, 3, 4, 5]);
840 }
841 
842 
843 @TestInfo(&tester46)
844 immutable test46 = q{--- test46
845 	void incArray(i32* begin, i32* end) {
846 		while(begin < end) {
847 			++(*begin++);
848 		}
849 	}
850 };
851 void tester46(ref TestContext ctx) {
852 	int[4] arr = [1, 2, 3, 4];
853 	auto incArray = ctx.getFunctionPtr!(void, int*, int*)("incArray");
854 	incArray(arr.ptr, arr.ptr + arr.length);
855 	assert(arr == [2, 3, 4, 5]);
856 }
857 
858 
859 @TestInfo(&tester47)
860 immutable test47 = q{--- test47
861 	// test logical not, or, and
862 	i32 selectNot(i32 selector, i32 a, i32 b) {
863 		if (!selector)
864 			return a;
865 		else return b;
866 	}
867 	i32 selectOr(i32 selectorA, i32 selectorB, i32 a, i32 b) {
868 		if (selectorA || selectorB)
869 			return a;
870 		else return b;
871 	}
872 	i32 selectAnd(i32 selectorA, i32 selectorB, i32 a, i32 b) {
873 		if (selectorA && selectorB)
874 			return a;
875 		else return b;
876 	}
877 };
878 void tester47(ref TestContext ctx) {
879 	auto selectNot = ctx.getFunctionPtr!(int, int, int, int)("selectNot");
880 	assert(selectNot(0, 1, 2) == 1);
881 	assert(selectNot(1, 1, 2) == 2);
882 	auto selectOr = ctx.getFunctionPtr!(int, int, int, int, int)("selectOr");
883 	assert(selectOr(0, 0, 1, 0) == 0);
884 	assert(selectOr(0, 1, 1, 0) == 1);
885 	assert(selectOr(1, 0, 1, 0) == 1);
886 	assert(selectOr(1, 1, 1, 0) == 1);
887 	auto selectAnd = ctx.getFunctionPtr!(int, int, int, int, int)("selectAnd");
888 	assert(selectAnd(0, 0, 1, 0) == 0);
889 	assert(selectAnd(0, 1, 1, 0) == 0);
890 	assert(selectAnd(1, 0, 1, 0) == 0);
891 	assert(selectAnd(1, 1, 1, 0) == 1);
892 }
893 
894 
895 @TestInfo(&tester48)
896 immutable test48 = q{--- test48
897 	// bool values
898 	bool getFalse() { return false; }
899 	bool getTrue() { return true; }
900 	bool getBool(i32 selectorA) {
901 		return selectorA;
902 	}
903 	bool getNot(i32 selectorA) {
904 		return !selectorA;
905 	}
906 	bool getOr(i32 selectorA, i32 selectorB) {
907 		return selectorA || selectorB;
908 	}
909 	bool getAnd(i32 selectorA, i32 selectorB) {
910 		return selectorA && selectorB;
911 	}
912 };
913 void tester48(ref TestContext ctx) {
914 	auto getFalse = ctx.getFunctionPtr!(bool)("getFalse");
915 	assert(getFalse() == false);
916 	auto getTrue = ctx.getFunctionPtr!(bool)("getTrue");
917 	assert(getTrue() == true);
918 	auto getBool = ctx.getFunctionPtr!(bool, int)("getBool");
919 	assert(getBool(0) == false);
920 	assert(getBool(1) == true);
921 	auto getNot = ctx.getFunctionPtr!(bool, int)("getNot");
922 	assert(getNot(0) == true);
923 	assert(getNot(1) == false);
924 	auto getOr = ctx.getFunctionPtr!(bool, int, int)("getOr");
925 	assert(getOr(0, 0) == false);
926 	assert(getOr(0, 1) == true);
927 	assert(getOr(1, 0) == true);
928 	assert(getOr(1, 1) == true);
929 	auto getAnd = ctx.getFunctionPtr!(bool, int, int)("getAnd");
930 	assert(getAnd(0, 0) == false);
931 	assert(getAnd(0, 1) == false);
932 	assert(getAnd(1, 0) == false);
933 	assert(getAnd(1, 1) == true);
934 }
935 
936 
937 @TestInfo(&tester49)
938 immutable test49 = q{--- test49
939 	// Test full suite of pointer arithmetic operations
940 	void preIncrement(i32* arr, i32 length) {
941 		(++arr)[-1] = 10; // arr[0] = 10, negative index
942 		*arr        = 15; // arr[1] = 15, deref pointer
943 	}
944 	void preDecrement(i32* arr, i32 length) {
945 		(--arr)[1] = 20; // arr[0] = 20
946 		arr[2]  = 25; // arr[1] = 25
947 	}
948 	void postIncrement(i32* arr, i32 length) {
949 		(arr++)[0] = 30; // arr[0] = 30
950 		arr[0]  = 35; // arr[1] = 35
951 	}
952 	void postDecrement(i32* arr, i32 length) {
953 		(arr--)[0] = 40; // arr[0] = 40
954 		arr[2]  = 45; // arr[1] = 45
955 	}
956 	void addInt(i32* arr, i32 length) {
957 		*(arr + 3) = 50; // arr[3] = 50
958 	}
959 	void subInt(i32* arr, i32 length) {
960 		*(arr - 3) = 60; // arr[-4] = 60
961 	}
962 	void diff(i32* arr, i32 length) {
963 		i32* last = arr + length; // last = &arr[4];
964 		// sub two pointers
965 		i64 diff = last - arr;
966 		arr[length - 3] = cast(i32)diff; // ar[1] = 4
967 	}
968 	void plusEqual(i32* arr, i32 length) {
969 		arr += 3;
970 		arr[0] = 90; // arr[3] = 90
971 	}
972 	void minusEqual(i32* arr, i32 length) {
973 		arr -= 3;
974 		arr[3] = 100; // arr[0] = 100
975 	}
976 };
977 void tester49(ref TestContext ctx) {
978 	int[2] arr;
979 	auto preIncrement = ctx.getFunctionPtr!(void, int*, int)("preIncrement");
980 	preIncrement(arr.ptr, arr.length);
981 	assert(arr == [10, 15]);
982 
983 	auto preDecrement = ctx.getFunctionPtr!(void, int*, int)("preDecrement");
984 	preDecrement(arr.ptr, arr.length);
985 	assert(arr == [20, 25]);
986 
987 	auto postIncrement = ctx.getFunctionPtr!(void, int*, int)("postIncrement");
988 	postIncrement(arr.ptr, arr.length);
989 	assert(arr == [30, 35]);
990 
991 	auto postDecrement = ctx.getFunctionPtr!(void, int*, int)("postDecrement");
992 	postDecrement(arr.ptr, arr.length);
993 	assert(arr == [40, 45]);
994 
995 	int[4] arr2;
996 
997 	auto addInt = ctx.getFunctionPtr!(void, int*, int)("addInt");
998 	addInt(arr2.ptr, arr2.length);
999 	assert(arr2 == [0, 0, 0, 50]);
1000 
1001 	auto subInt = ctx.getFunctionPtr!(void, int*, int)("subInt");
1002 	subInt(arr2.ptr+3, arr2.length);
1003 	assert(arr2 == [60, 0, 0, 50]);
1004 
1005 	auto diff = ctx.getFunctionPtr!(void, int*, int)("diff");
1006 	diff(arr2.ptr, arr2.length);
1007 	assert(arr2 == [60, 4, 0, 50]);
1008 
1009 	auto plusEqual = ctx.getFunctionPtr!(void, int*, int)("plusEqual");
1010 	plusEqual(arr2.ptr, arr2.length);
1011 	assert(arr2 == [60, 4, 0, 90]);
1012 
1013 	auto minusEqual = ctx.getFunctionPtr!(void, int*, int)("minusEqual");
1014 	minusEqual(arr2.ptr, arr2.length);
1015 	assert(arr2 == [100, 4, 0, 90]);
1016 }
1017 
1018 @TestInfo(&tester50)
1019 immutable test50 = q{--- test50
1020 	// test ptr cmp with null
1021 	// test unary branch on byte value
1022 	u64 cstrlen(u8* str) {
1023 		if (str == null) return 0;
1024 
1025 		u8* start = str;
1026 		while(*str)
1027 		{
1028 			++str;
1029 		}
1030 		return cast(u64)(str - start);
1031 	}
1032 };
1033 void tester50(ref TestContext ctx) {
1034 	auto cstrlen = ctx.getFunctionPtr!(ulong, const(char)*)("cstrlen");
1035 	string str = "test";
1036 	ulong length = cstrlen(str.ptr);
1037 	assert(length == str.length);
1038 }
1039 
1040 @TestInfo(&tester51)
1041 immutable test51 = q{--- test51
1042 	// test null assign, compare
1043 	u8* assignNull() {
1044 		u8* ptr = null;
1045 		return ptr;
1046 	}
1047 	bool testNull(u8* ptr) {
1048 		return ptr == null;
1049 	}
1050 };
1051 void tester51(ref TestContext ctx) {
1052 	auto assignNull = ctx.getFunctionPtr!(ubyte*)("assignNull");
1053 	ubyte* val = assignNull();
1054 	assert(val == null);
1055 
1056 	auto testNull = ctx.getFunctionPtr!(bool, ubyte*)("testNull");
1057 	bool resNull = testNull(val);
1058 	assert(resNull == true);
1059 
1060 	ubyte value;
1061 	bool resNotNull = testNull(&value);
1062 	assert(resNotNull == false);
1063 }
1064 
1065 @TestInfo(&tester52)
1066 immutable test52 = q{--- test52
1067 	// test integer comparison
1068 	bool cmp8(i8 a, i8 b) { return a == b; }
1069 	bool cmp16(i16 a, i16 b) { return a == b; }
1070 	bool cmp32(i32 a, i32 b) { return a == b; }
1071 	bool cmp64(i64 a, i64 b) { return a == b; }
1072 
1073 	bool br8(i8 a, i8 b) { bool result; if (a == b) result = true; else result = false; return result; }
1074 	bool br16(i16 a, i16 b) { bool result; if (a == b) result = true; else result = false; return result; }
1075 	bool br32(i32 a, i32 b) { bool result; if (a == b) result = true; else result = false; return result; }
1076 	bool br64(i64 a, i64 b) { bool result; if (a == b) result = true; else result = false; return result; }
1077 };
1078 void tester52(ref TestContext ctx) {
1079 	// pass 64bit values, to check that only lower bits are compared
1080 	void test(string funcName, ulong a, ulong b)
1081 	{
1082 		auto cmp = ctx.getFunctionPtr!(bool, ulong, ulong)(funcName);
1083 		bool res = cmp(a, b);
1084 		assert(res == true);
1085 	}
1086 	test("cmp8", 0xF0_F0_F0_F0_F0_F0_F0_FF, 0x0F_0F_0F_0F_0F_0F_0F_FF);
1087 	test("br8", 0xF0_F0_F0_F0_F0_F0_F0_FF, 0x0F_0F_0F_0F_0F_0F_0F_FF);
1088 
1089 	test("cmp16", 0xF0_F0_F0_F0_F0_F0_FF_FF, 0x0F_0F_0F_0F_0F_0F_FF_FF);
1090 	test("br16", 0xF0_F0_F0_F0_F0_F0_FF_FF, 0x0F_0F_0F_0F_0F_0F_FF_FF);
1091 
1092 	test("cmp32", 0xF0_F0_F0_F0_FF_FF_FF_FF, 0x0F_0F_0F_0F_FF_FF_FF_FF);
1093 	test("br32", 0xF0_F0_F0_F0_FF_FF_FF_FF, 0x0F_0F_0F_0F_FF_FF_FF_FF);
1094 
1095 	test("cmp64", 0xFF_FF_FF_FF_FF_FF_FF_FF, 0xFF_FF_FF_FF_FF_FF_FF_FF);
1096 	test("br64", 0xFF_FF_FF_FF_FF_FF_FF_FF, 0xFF_FF_FF_FF_FF_FF_FF_FF);
1097 }
1098 
1099 @TestInfo(&tester53)
1100 immutable test53 = q{--- test53
1101 	// Test constant folding
1102 	i32 add() { return 1 + 3; }
1103 	i32 sub() { return 3 - 1; }
1104 	i32 mul() { return 3 * 2; }
1105 	i32 div() { return 7 / 2; }
1106 	i32 rem() { return 7 % 2; }
1107 	i32 shl() { return 1 << 2; }
1108 	i32 shr() { return i32.min >>> 2; }
1109 	i32 sar() { return i32.min >> 2; }
1110 	i32 or () { return 0b0011 | 0b0101; }
1111 	i32 xor() { return 0b0011 ^ 0b0101; }
1112 	i32 and() { return 0b0011 & 0b0101; }
1113 };
1114 void tester53(ref TestContext ctx) {
1115 	auto add = ctx.getFunctionPtr!(int)("add");
1116 	auto sub = ctx.getFunctionPtr!(int)("sub");
1117 	auto mul = ctx.getFunctionPtr!(int)("mul");
1118 	auto div = ctx.getFunctionPtr!(int)("div");
1119 	auto rem = ctx.getFunctionPtr!(int)("rem");
1120 	auto shl = ctx.getFunctionPtr!(int)("shl");
1121 	auto shr = ctx.getFunctionPtr!(int)("shr");
1122 	auto sar = ctx.getFunctionPtr!(int)("sar");
1123 	auto or  = ctx.getFunctionPtr!(int)("or");
1124 	auto xor = ctx.getFunctionPtr!(int)("xor");
1125 	auto and = ctx.getFunctionPtr!(int)("and");
1126 
1127 	assert(add() == 4);
1128 	assert(sub() == 2);
1129 	assert(mul() == 6);
1130 	assert(div() == 3);
1131 	assert(rem() == 1);
1132 	assert(shl() == 4);
1133 	assert(shr() == (int.min >>> 2));
1134 	assert(sar() == (int.min >> 2));
1135 	assert(or() == 0b0111);
1136 	assert(xor() == 0b0110);
1137 	assert(and() == 0b0001);
1138 }
1139 
1140 @TestInfo()
1141 immutable test54 = q{--- test54
1142 	// Test bool literal branching
1143 	void run() {
1144 		while(true) {
1145 			break;
1146 		}
1147 		while(false) {
1148 
1149 		}
1150 		while(true) {
1151 
1152 		}
1153 		if (true){}
1154 		if (false){}
1155 	}
1156 };
1157 
1158 
1159 @TestInfo(&tester55, [HostSymbol("print", cast(void*)&external_print_string)])
1160 immutable test55 = q{--- test55
1161 	// test slice forwarding
1162 	@extern(module, "host")
1163 	void print(u8[] str);
1164 	void forward(u8[] str) {
1165 		print(str);
1166 	}
1167 };
1168 void tester55(ref TestContext ctx) {
1169 	auto forward = ctx.getFunctionPtr!(void, Slice!(immutable(char)))("forward");
1170 	forward(Slice!(immutable(char))("testString"));
1171 	assert(testSink.text == "testString");
1172 }
1173 
1174 
1175 @TestInfo()
1176 immutable test56 = q{--- test56
1177 	// test using bool variable for branching
1178 	void branch() {
1179 		bool run = true;
1180 		while (run) {}
1181 	}
1182 };
1183 
1184 @TestInfo()
1185 immutable test57 = q{--- test57
1186 	// test using bool variable for branching
1187 	void use(bool){}
1188 	void branch() {
1189 		bool run = true;
1190 		while (run) {}
1191 		use(run);
1192 	}
1193 };
1194 
1195 @TestInfo()
1196 immutable test58 = q{--- test58
1197 	// Test declaration statement that declares pointer var
1198 	struct SDL_Event {
1199 		u32 type;
1200 	}
1201 	void run() {
1202 		SDL_Event* key;
1203 	}
1204 };
1205 
1206 @TestInfo()
1207 immutable test59 = q{--- test59
1208 	// Test dot operator on dereference and member expressions
1209 	struct SDL_KeyboardEvent {
1210 		u32 type;
1211 		u32 timestamp;
1212 		SDL_Keysym keysym;
1213 	}
1214 	struct SDL_Keysym {
1215 		u32 scancode;
1216 		u32 sym;
1217 	}
1218 	void run(SDL_KeyboardEvent* key) {
1219 		if ((*key).keysym.scancode == 1) {
1220 			(*key).keysym.sym = 42;
1221 		}
1222 	}
1223 };
1224 
1225 @TestInfo()
1226 immutable test60 = q{--- test60
1227 	// Test dot operator on pointer type
1228 	struct SDL_KeyboardEvent {
1229 		u32 type;
1230 		u32 timestamp;
1231 		SDL_Keysym keysym;
1232 	}
1233 	struct SDL_Keysym {
1234 		u32 scancode;
1235 		u32 sym;
1236 	}
1237 	void run(SDL_KeyboardEvent* key) {
1238 		if (key.keysym.scancode == 1) {
1239 			key.keysym.sym = 42;
1240 		}
1241 	}
1242 };
1243 
1244 @TestInfo()
1245 immutable test61 = q{--- test61
1246 	// Test pointer to pointer cast
1247 	struct SDL_Event {
1248 		u32 type;
1249 		u8[52] padding;
1250 	}
1251 	struct SDL_KeyboardEvent {
1252 		u32 type;
1253 		u32 timestamp;
1254 		SDL_Keysym keysym;
1255 	}
1256 	struct SDL_Keysym {
1257 		u32 scancode;
1258 		u32 sym;
1259 	}
1260 	void run(SDL_KeyboardEvent* key) {
1261 		SDL_Event e;
1262 		SDL_KeyboardEvent* key = cast(SDL_KeyboardEvent*)&e;
1263 	}
1264 };
1265 
1266 @TestInfo()
1267 immutable test62 = q{--- test62
1268 	// Bug. Infinite loop in trivial phi removal
1269 	struct SDL_Event {
1270 		u32 type;
1271 		u8[52] padding;
1272 	}
1273 	struct SDL_KeyboardEvent {
1274 		u32 type;
1275 		u32 timestamp;
1276 		u32 keysym;
1277 	}
1278 	i32 SDL_PollEvent(SDL_Event*){return 0;}
1279 	i32 player_x;
1280 	void run(SDL_KeyboardEvent* key) {
1281 		bool run = true;
1282 		SDL_Event e;
1283 
1284 		while (run)
1285 		{
1286 			if (e.type == 1)
1287 			{
1288 				SDL_KeyboardEvent* key = cast(SDL_KeyboardEvent*)&e;
1289 				if ((*key).keysym == 1)
1290 				{
1291 					++player_x;
1292 				}
1293 			}
1294 		}
1295 	}
1296 };
1297 
1298 @TestInfo()
1299 immutable test63 = q{--- test63
1300 	// Store const into stack
1301 	void usePtru8(u8*){}
1302 	void usePtru16(u16*){}
1303 	void usePtru32(u32*){}
1304 	void usePtru64(u64*){}
1305 	void run() {
1306 		u8 num8 = 10;
1307 		u16 num16 = 10;
1308 		u32 num32 = 10;
1309 		u64 num64 = 10;
1310 		usePtru8(&num8);
1311 		usePtru16(&num16);
1312 		usePtru32(&num32);
1313 		usePtru64(&num64);
1314 	}
1315 };
1316 
1317 
1318 @TestInfo(&tester65, [HostSymbol("print", cast(void*)&external_print_string)])
1319 immutable test65 = q{--- test65
1320 	// Test string literals
1321 	@extern(module, "host")
1322 	void print(u8[]); // external
1323 	u8[] returnStringLiteral() {
1324 		return "testString";
1325 	}
1326 	void passStringLiteralArgument() {
1327 		print("testString");
1328 	}
1329 };
1330 void tester65(ref TestContext ctx) {
1331 	auto returnStringLiteral = ctx.getFunctionPtr!(Slice!char)("returnStringLiteral");
1332 	assert(returnStringLiteral() == "testString");
1333 
1334 	auto passStringLiteralArgument = ctx.getFunctionPtr!(void)("passStringLiteralArgument");
1335 	passStringLiteralArgument();
1336 	assert(testSink.text == "testString");
1337 }
1338 
1339 @TestInfo(&tester66)
1340 immutable test66 = q{--- test66
1341 	// Test char literals
1342 	u8 getChar() { return '\n'; }
1343 };
1344 void tester66(ref TestContext ctx) {
1345 	auto getChar = ctx.getFunctionPtr!(char)("getChar");
1346 	assert(getChar() == '\n');
1347 }
1348 
1349 @TestInfo(&tester67)
1350 immutable test67 = q{--- test67
1351 	// Test static arrays
1352 	u8* getPtr(u8[21]* arrPtr) { return (*arrPtr).ptr; }
1353 	u64 getLength(u8[21]* arrPtr) { return (*arrPtr).length; }
1354 	u8 getElement(u8[21]* arrPtr, i64 index) { return (*arrPtr)[index]; }
1355 	void arrayToSlice(u8[21]* arrPtr) { receiveSlice(*arrPtr); }
1356 	void receiveSlice(u8[] arr) {}
1357 	struct Color {
1358 		u8 r;
1359 		u8 g;
1360 		u8 b;
1361 		u8 a;
1362 	}
1363 	Color[2] colors;
1364 	void fun() {
1365 		Color[2] colors_static_local;
1366 		Color[] colors_local;
1367 	}
1368 };
1369 void tester67(ref TestContext ctx) {
1370 	ubyte[21] array;
1371 	foreach(i, ref elem; array) elem = cast(ubyte)i;
1372 
1373 	auto getPtr = ctx.getFunctionPtr!(ubyte*, ubyte[21]*)("getPtr");
1374 	assert(getPtr(&array) == array.ptr);
1375 
1376 	auto getLength = ctx.getFunctionPtr!(ulong, ubyte[21]*)("getLength");
1377 	assert(getLength(&array) == array.length);
1378 
1379 	auto getElement = ctx.getFunctionPtr!(ubyte, ubyte[21]*, ulong)("getElement");
1380 	foreach(i, elem; array)
1381 		assert(getElement(&array, i) == elem);
1382 
1383 	auto arrayToSlice = ctx.getFunctionPtr!(void, ubyte[21]*)("arrayToSlice");
1384 	arrayToSlice(&array);
1385 }
1386 
1387 @TestInfo()
1388 immutable test68 = q{--- test68
1389 	// Test enum inside struct
1390 	struct Struct {
1391 		u8 a;
1392 		enum someVal = 42;
1393 	}
1394 	void run() {
1395 		i64 var = Struct.someVal;
1396 		Struct s;
1397 		i64 var2 = s.someVal;
1398 	}
1399 };
1400 
1401 @TestInfo()
1402 immutable test69 = q{--- test69
1403 	// Bug. Multiple users of trivial phis do not get
1404 	// all users added when replacing phi result by singular phi argument
1405 	struct GameMap {
1406 		bool blocked;
1407 		bool block_sight;
1408 	}
1409 	void initialize_tiles(GameMap* map)
1410 	{
1411 		i32 x = 0;
1412 		while(x < 20) {
1413 			map.blocked = false;
1414 			map.block_sight = false;
1415 		}
1416 	}
1417 };
1418 
1419 @TestInfo()
1420 immutable test70 = q{--- test70
1421 	// usage of member expr in condition
1422 	struct GameMap {
1423 		bool blocked;
1424 		bool block_sight;
1425 	}
1426 	void initialize_tiles(GameMap* map)
1427 	{
1428 		if (map.blocked) {
1429 			map.block_sight = true;
1430 		}
1431 	}
1432 };
1433 
1434 @TestInfo()
1435 immutable test71 = q{--- test71
1436 	// Take address of array index
1437 	u8* getFirst(u8[2]* array)
1438 	{
1439 		return &(*array)[0];
1440 	}
1441 };
1442 
1443 @TestInfo()
1444 immutable test72 = q{--- test72
1445 	// Use call result as condition
1446 	i32 run()
1447 	{
1448 		i32 val;
1449 		if (getBool()) {
1450 			val = 42;
1451 		} else {
1452 			val = 21;
1453 		}
1454 		return val;
1455 	}
1456 	bool getBool() { return true; }
1457 };
1458 
1459 @TestInfo()
1460 immutable test73 = q{--- test73
1461 	// General instruction const handling
1462 	void run()
1463 	{
1464 		i8 val8;
1465 		i16 val16;
1466 		i32 val32;
1467 		i64 val64;
1468 		val8 += 8;
1469 		val16 += 8;
1470 		val16 += 500;
1471 		val32 += 8;
1472 		val32 += 500;
1473 		val32 += 70000;
1474 		val64 += 8;
1475 		val64 += 500;
1476 		val64 += 70000;
1477 		val64 += 0x8_0000_0000;
1478 	}
1479 };
1480 
1481 
1482 @TestInfo(&tester74)
1483 immutable test74 = q{--- test74
1484 	// Test nested call expression
1485 	struct GameMap;
1486 	GameMap* pass_ptr_and_struct(GameMap* map) {
1487 		return create_room(map, Rect(1,1,5,5));
1488 	}
1489 
1490 	struct Rect {
1491 		i32 x1;
1492 		i32 y1;
1493 		i32 x2;
1494 		i32 y2;
1495 	}
1496 
1497 	GameMap* create_room(GameMap* map, Rect room) {
1498 		return map;
1499 	}
1500 };
1501 void tester74(ref TestContext ctx) {
1502 	ubyte b;
1503 	auto pass_ptr_and_struct = ctx.getFunctionPtr!(ubyte*, ubyte*)("pass_ptr_and_struct");
1504 	assert(pass_ptr_and_struct(&b) == &b);
1505 }
1506 
1507 
1508 @TestInfo(&tester75)
1509 immutable test75 = q{--- test75
1510 	// Test for loop
1511 	i32 sum(i32[] numbers) {
1512 		i32 sum = 0;
1513 		for (u32 i = 0; i < numbers.length; ++i)
1514 		{
1515 			sum += numbers[i];
1516 		}
1517 		return sum;
1518 	}
1519 	void loops1() {
1520 		i32 outer1;
1521 		i32 outer2;
1522 		for (;;) break;
1523 		for (i32 i;;) break;
1524 		for (i32 i, i32 j, i32 k = 8;;) break;
1525 		for (;outer1 == 0;) break;
1526 		for (;;outer1 = 0, outer2 = 10) break;
1527 	}
1528 };
1529 void tester75(ref TestContext ctx) {
1530 	int[10] nums = [1,2,3,4,5,6,7,8,9,10];
1531 	auto sum = ctx.getFunctionPtr!(int, Slice!int)("sum");
1532 	assert(sum(Slice!int(nums[])) == 55);
1533 }
1534 
1535 
1536 @TestInfo(&tester76)
1537 immutable test76 = q{--- test76
1538 	// Test for loop break avoiding increments block
1539 	i32 test_for() {
1540 		i32 outer;
1541 		for (;;outer = 10) break;
1542 		return outer; // must return 0, not 10
1543 	}
1544 };
1545 void tester76(ref TestContext ctx) {
1546 	auto test_for = ctx.getFunctionPtr!(int)("test_for");
1547 	assert(test_for() == 0);
1548 }
1549 
1550 @TestInfo()
1551 immutable test77 = q{--- test77
1552 	//
1553 	struct Tile {
1554 		bool blocked;
1555 		bool block_sight;
1556 	}
1557 
1558 	struct GameMap {
1559 		enum map_width = 40;
1560 		enum map_height = 40;
1561 		Tile[40][40] tiles;
1562 	}
1563 
1564 	void initialize_tiles(GameMap* map) {
1565 		for (i32 y = 0; y < map.map_height; ++y) {
1566 			for (i32 x = 0; x < map.map_width; ++x) {
1567 				map.tiles[y][x].blocked = true;
1568 				map.tiles[y][x].block_sight = true;
1569 			}
1570 		}
1571 	}
1572 };
1573 
1574 @TestInfo(&tester78)
1575 immutable test78 = q{--- test78
1576 	// Bug: division by small constant generated BYTE idiv, instead of DWORD
1577 	i64 test_div(i64 i, u8[] res) {
1578 		res[0] = cast(u8)(i % 10);
1579 		i /= 10;
1580 		res[1] = cast(u8)(i % 10);
1581 		return i;
1582 	}
1583 };
1584 void tester78(ref TestContext ctx) {
1585 	auto test_div = ctx.getFunctionPtr!(long, long, Slice!ubyte)("test_div");
1586 	ubyte[2] buf;
1587 	assert(test_div(97, Slice!ubyte(buf[])) == 9);
1588 	assert(buf[] == [7, 9]);
1589 }
1590 
1591 @TestInfo(&tester79)
1592 immutable test79 = q{--- test79
1593 	// test null to slice conversion
1594 	void receive(u8[]) {}
1595 	u8[] make() {
1596 		receive(null);
1597 		return null;
1598 	}
1599 };
1600 void tester79(ref TestContext ctx) {
1601 	auto make = ctx.getFunctionPtr!(Slice!ubyte)("make");
1602 	assert(make() == null);
1603 }
1604 
1605 @TestInfo(&tester80)
1606 immutable test80 = q{--- test80
1607 	// integer types .min, .max properties
1608 	u8 u8min() {  return u8.min; }
1609 	u16 u16min() { return u16.min; }
1610 	u32 u32min() { return u32.min; }
1611 	u64 u64min() { return u64.min; }
1612 	u8 u8max() {  return u8.max; }
1613 	u16 u16max() { return u16.max; }
1614 	u32 u32max() { return u32.max; }
1615 	u64 u64max() { return u64.max; }
1616 	i8 i8min() {  return i8.min; }
1617 	i16 i16min() { return i16.min; }
1618 	i32 i32min() { return i32.min; }
1619 	i64 i64min() { return i64.min; }
1620 	i8 i8max() {  return i8.max; }
1621 	i16 i16max() { return i16.max; }
1622 	i32 i32max() { return i32.max; }
1623 	i64 i64max() { return i64.max; }
1624 };
1625 void tester80(ref TestContext ctx) {
1626 	assert(ctx.getFunctionPtr!(ubyte)("u8min")()  == ubyte.min);
1627 	assert(ctx.getFunctionPtr!(ushort)("u16min")() == ushort.min);
1628 	assert(ctx.getFunctionPtr!(uint)("u32min")() == uint.min);
1629 	assert(ctx.getFunctionPtr!(ulong)("u64min")() == ulong.min);
1630 	assert(ctx.getFunctionPtr!(ubyte)("u8max")()  == ubyte.max);
1631 	assert(ctx.getFunctionPtr!(ushort)("u16max")() == ushort.max);
1632 	assert(ctx.getFunctionPtr!(uint)("u32max")() == uint.max);
1633 	assert(ctx.getFunctionPtr!(ulong)("u64max")() == ulong.max);
1634 	assert(ctx.getFunctionPtr!(byte)("i8min")()  == byte.min);
1635 	assert(ctx.getFunctionPtr!(short)("i16min")() == short.min);
1636 	assert(ctx.getFunctionPtr!(int)("i32min")() == int.min);
1637 	assert(ctx.getFunctionPtr!(long)("i64min")() == long.min);
1638 	assert(ctx.getFunctionPtr!(byte)("i8max")()  == byte.max);
1639 	assert(ctx.getFunctionPtr!(short)("i16max")() == short.max);
1640 	assert(ctx.getFunctionPtr!(int)("i32max")() == int.max);
1641 	assert(ctx.getFunctionPtr!(long)("i64max")() == long.max);
1642 }
1643 
1644 
1645 @TestInfo(&tester81)
1646 immutable test81 = q{--- test81
1647 	// Test mov of 64bit constant into memory
1648 	void run(i64* ptr) { *ptr = i64.max; }
1649 };
1650 void tester81(ref TestContext ctx) {
1651 	long val = 0;
1652 	ctx.getFunctionPtr!(void, long*)("run")(&val);
1653 	assert(val == long.max);
1654 }
1655 
1656 
1657 @TestInfo()
1658 immutable test82 = q{--- test82
1659 	// Bug
1660 	void test()
1661 	{
1662 		for (u32 roomIndex = 0; roomIndex < 20; ++roomIndex)
1663 		{
1664 			for (u32 otherRoom = 0; otherRoom < roomIndex; ++otherRoom)
1665 			{
1666 				if (otherRoom < roomIndex) {
1667 					break;
1668 				}
1669 			}
1670 		}
1671 	}
1672 };
1673 
1674 @TestInfo(&tester83)
1675 immutable test83 = q{--- test83
1676 	// using enum as array size
1677 	// constant folding in static expressions
1678 	// test forward references too
1679 
1680 	// use static array length in constant folded expression
1681 	enum combined_enums = cast(u64)arr_size3 + arrBackref.length;
1682 	i32[combined_enums] arrBackrefX;
1683 	u64 combinedEnums() { return arrBackrefX.length; } // 16
1684 
1685 	enum arr_size = 4;
1686 	i32[arr_size] arrBackref;
1687 	u64 getSize1() { return arrBackref.length; } // 4
1688 
1689 	u64 testBackref() {
1690 		i32[arr_size] local_arr;
1691 		return local_arr.length; // 4
1692 	}
1693 
1694 	i32[arr_size2] arrForwardref;
1695 	u64 getSize2() { return arrForwardref.length; } // 7
1696 
1697 	u64 testForwardref() {
1698 		i32[arr_size2] local_arr;
1699 		return local_arr.length; // 7
1700 	}
1701 
1702 	enum arr_size2 = 7;
1703 
1704 	i32[arr_size3 + 4] arrForwardref2;
1705 	u64 getSize3() { return arrForwardref2.length; } // 16
1706 
1707 	u64 testForwardref2() {
1708 		i32[arr_size3 + 10] local_arr;
1709 		return local_arr.length; // 22
1710 	}
1711 
1712 	enum arr_size3 = 12;
1713 };
1714 void tester83(ref TestContext ctx) {
1715 	assert(ctx.getFunctionPtr!ulong("combinedEnums")() == 16);
1716 	assert(ctx.getFunctionPtr!ulong("getSize1")() == 4);
1717 	assert(ctx.getFunctionPtr!ulong("testBackref")() == 4);
1718 	assert(ctx.getFunctionPtr!ulong("getSize2")() == 7);
1719 	assert(ctx.getFunctionPtr!ulong("testForwardref")() == 7);
1720 	assert(ctx.getFunctionPtr!ulong("getSize3")() == 16);
1721 	assert(ctx.getFunctionPtr!ulong("testForwardref2")() == 22);
1722 }
1723 
1724 @TestInfo(&tester84)
1725 immutable test84 = q{--- test84
1726 	// check nested array length is set correctly
1727 	i32[40][30] arr;
1728 	u64 nestedArrLen() { return arr[0].length; } // 40
1729 };
1730 void tester84(ref TestContext ctx) {
1731 	assert(ctx.getFunctionPtr!ulong("nestedArrLen")() == 40);
1732 }
1733 
1734 @TestInfo(&tester85)
1735 immutable test85 = q{--- test85
1736 	// UFCS without parenthesis
1737 	i32 static_func0() { return 42; }
1738 	void static_func_void() {}
1739 	i32 static_func1(i32 num) { return num; }
1740 	i32 static_func2(i32 num, i32 num2) { return num + num2; }
1741 	i32 test0() {
1742 		static_func_void;
1743 		return static_func0;
1744 	}
1745 	i32 test1(i32 num) {
1746 		return num.static_func1;
1747 	}
1748 	i32 test2(i32 num, i32 num2) {
1749 		return num.static_func2(num2);
1750 	}
1751 };
1752 void tester85(ref TestContext ctx) {
1753 	assert(ctx.getFunctionPtr!(int)("test0")() == 42);
1754 	assert(ctx.getFunctionPtr!(int, int)("test1")(42) == 42);
1755 	assert(ctx.getFunctionPtr!(int, int, int)("test2")(42, 24) == 66);
1756 }
1757 
1758 @TestInfo()
1759 immutable test86 = q{--- test86
1760 	// alias type
1761 	alias T = i32;
1762 	T num = 2;
1763 	T test(T t) { return t; }
1764 
1765 	struct S { i32 member; }
1766 	alias U = S;
1767 	void test2() {
1768 		U s;
1769 		s.member = 10;
1770 	}
1771 
1772 	alias funcAlias = test; // function alias
1773 	T test3() { return funcAlias(30); }
1774 
1775 	alias varAlias = num; // variable alias
1776 	T test4() { return varAlias; }
1777 
1778 	alias aliasOfAlias = varAlias; // alias of alias
1779 	T test5() { return aliasOfAlias; }
1780 
1781 	enum enumVal = 42;
1782 	alias enumAlias = enumVal; // enum alias
1783 	T test6() { return enumAlias; }
1784 
1785 	alias Ptr = i32*;
1786 	alias HANDLE = void*;
1787 	alias alias_bool = bool;
1788 	enum ptrsize = i32*.sizeof;
1789 	enum u8min = u8.max;
1790 	u8[u8min] arr;
1791 	u8[ptrsize] arr2;
1792 };
1793 
1794 @TestInfo(&tester87)
1795 immutable test87 = q{--- test87
1796 	// pointer type expr parsing
1797 	enum ptrsize = i32*.sizeof;
1798 	enum ptrsize2 = i32**.sizeof;
1799 	enum arrsize = i32[4].sizeof;
1800 	struct S { i64 var; } // 8
1801 	enum S_ptrsize = S*.sizeof;
1802 	enum S_ptrsize2 = S**.sizeof;
1803 	enum S_arrsize = S[4].sizeof; // 32
1804 	S[S_arrsize] arr; // 256
1805 	u64 S_sizeof() { return S.sizeof; } // 8
1806 	u64 arr_sizeof() { return arr.sizeof; } // 256
1807 };
1808 
1809 void tester87(ref TestContext ctx) {
1810 	assert(ctx.getFunctionPtr!(ulong)("S_sizeof")() == 8);
1811 	assert(ctx.getFunctionPtr!(ulong)("arr_sizeof")() == 256);
1812 }
1813 
1814 @TestInfo(&tester88)
1815 immutable test88 = q{--- test88
1816 	// function pointer
1817 	alias i32_funType = i32 function();
1818 	alias i32ptr_funType = i32* function();
1819 	enum i32_funType funPtrEnum = &i32Fun;
1820 	enum i32 function() inlinefunPtrEnum = &i32Fun;
1821 	// i32_funType funPtrGlobal = &i32Fun; // TODO: globals are uninitialized now
1822 	// i32 function() inlinefunPtrGlobal = &i32Fun; // TODO: globals are uninitialized now
1823 	i32 i32Fun() {
1824 		return 42;
1825 	}
1826 	i32_funType retFuncPtr() {
1827 		return &i32Fun;
1828 	}
1829 	i32 test() {
1830 		i32_funType funPtr = retFuncPtr(); // call by ptr (may be optimized to direct call later)
1831 		i32 function() inlinefunPtr = &i32Fun; // direct call
1832 		return funPtr() + inlinefunPtr();
1833 	}
1834 	i32 test2() {
1835 		return funPtrEnum() + inlinefunPtrEnum(); // direct call is performed
1836 	}
1837 	i32 sum(i32 a, i32 b) { return a + b; }
1838 	// pass ptr to function with parameters
1839 	i32 callFunc(i32 function(i32, i32) func, i32 a, i32 b) {
1840 		return func(a, b);
1841 	}
1842 	i32 test3() {
1843 		return callFunc(&sum, 10, 40);
1844 	}
1845 	i32 callFunc2(i32 a1, i32 a2, i32 a3, i32 a4, i32 a5, i32 a6, i32 function(i32, i32) func) {
1846 		return func(a1, a2);
1847 	}
1848 	// test push function address
1849 	i32 test4() {
1850 		return callFunc2(1, 2, 3, 4, 5, 6, &sum);
1851 	}
1852 };
1853 void tester88(ref TestContext ctx) {
1854 	assert(ctx.getFunctionPtr!(int)("test")() == 84);
1855 	assert(ctx.getFunctionPtr!(int)("test2")() == 84);
1856 	assert(ctx.getFunctionPtr!(int)("test3")() == 50);
1857 	assert(ctx.getFunctionPtr!(int)("test4")() == 3);
1858 }
1859 
1860 @TestInfo()
1861 immutable test89 = q{--- test89
1862 	// function pointer as parameter
1863 	void tran_thong(i32 xstart, i32 ystart, i32 xend, i32 yend, void function(void*, i32, i32) callback)
1864 	{}
1865 };
1866 
1867 @TestInfo(&tester90)
1868 immutable test90 = q{--- test90
1869 	void setRangeu8(u8* slice, u64 from, u64 to, u8 value) {
1870 		while(from < to) {
1871 			slice[from] = value;
1872 			++from;
1873 		}
1874 	}
1875 	void formatInt(i64 i, u8[21]* output, u32 minSize, u8[]* result)
1876 	{
1877 		u32 numDigits = 0;
1878 		if (i == 0)
1879 		{
1880 			if (minSize == 0)
1881 				minSize = 1;
1882 			setRangeu8((*output).ptr, 21 - minSize, 21, '0');
1883 			(*output)[20] = '0';
1884 			numDigits = minSize;
1885 		}
1886 		else
1887 		{
1888 			bool neg = i < 0;
1889 			if (neg) {
1890 				i = -i;
1891 			}
1892 			bool overflow = i < 0;
1893 			if (overflow)
1894 				i = i64.max;
1895 
1896 			while (i)
1897 			{
1898 				u8 c = cast(u8)('0' + i % 10);
1899 				(*output)[21 - ++numDigits] = c;
1900 				i /= 10;
1901 			}
1902 
1903 			while (numDigits < minSize) {
1904 				(*output)[21 - ++numDigits] = '0';
1905 			}
1906 
1907 			if (neg) {
1908 				(*output)[21 - ++numDigits] = '-';
1909 			}
1910 			if (overflow) {
1911 				++(*output)[20];
1912 			}
1913 		}
1914 		(*result).ptr = (*output).ptr + (21 - numDigits);
1915 		(*result).length = numDigits;
1916 	}
1917 };
1918 void tester90(ref TestContext ctx) {
1919 	auto setRangeu8 = ctx.getFunctionPtr!(void, char*, ulong, ulong, char)("setRangeu8");
1920 
1921 	char[23] buf;
1922 	buf[] = 'z';
1923 
1924 	setRangeu8(&buf[1], 0, 21, 'x');
1925 	setRangeu8(&buf[1], 0, 1, '0');
1926 	setRangeu8(&buf[1], 20, 21, '1');
1927 	assert(buf == "z0xxxxxxxxxxxxxxxxxxx1z");
1928 
1929 	auto formatInt = ctx.getFunctionPtr!(void, long, char*, uint, Slice!char*)("formatInt");
1930 
1931 	void testFormatInt(long num, string expectedBuf, string expectedResult) {
1932 		buf[] = 'x';
1933 		Slice!char result;
1934 		formatInt(num, &buf[1], 0, &result);
1935 		//writefln("buf ptr %s len %s ptr %s %s", buf.ptr, result.length, result.ptr, buf);
1936 		assert(buf == expectedBuf);
1937 		assert(result.slice == expectedResult);
1938 	}
1939 
1940 	testFormatInt(  0,      "xxxxxxxxxxxxxxxxxxxxx0x", "0");
1941 	testFormatInt(  1,      "xxxxxxxxxxxxxxxxxxxxx1x", "1");
1942 	testFormatInt( 10,      "xxxxxxxxxxxxxxxxxxxx10x", "10");
1943 	testFormatInt(-10,      "xxxxxxxxxxxxxxxxxxx-10x", "-10");
1944 	testFormatInt(long.min, "xx-9223372036854775808x", "-9223372036854775808");
1945 	testFormatInt(long.max, "xxx9223372036854775807x", "9223372036854775807");
1946 }
1947 
1948 
1949 @TestInfo(&tester91)
1950 immutable test91 = q{--- test91
1951 	// splitting and spilling
1952 	void tran_thong(i32 xstart, i32 ystart, i32 xend, i32 yend, void function(void*, i32, i32) callback, void* userData)
1953 	{
1954 		i32 x = xstart;
1955 		i32 y = ystart;
1956 
1957 		i32 deltax;
1958 		i32 signdx;
1959 		if (xend >= xstart) {
1960 			deltax = xend - xstart;
1961 			signdx = 1;
1962 		} else {
1963 			deltax = xstart - xend;
1964 			signdx = -1;
1965 		}
1966 
1967 		i32 deltay;
1968 		i32 signdy;
1969 		if (yend >= ystart) {
1970 			deltay = yend - ystart;
1971 			signdy = 1;
1972 		} else {
1973 			deltay = ystart - yend;
1974 			signdy = -1;
1975 		}
1976 
1977 		callback(userData, x, y);
1978 
1979 		i32 test;
1980 		if (signdy == -1)
1981 			test = -1;
1982 		else
1983 			test = 0;
1984 
1985 		if (deltax >= deltay) {
1986 			test = (deltax + test) >> 1;
1987 			for (i32 i = 1; i < deltax; ++i) {
1988 				test -= deltay;
1989 				x += signdx;
1990 				if (test < 0) {
1991 					y += signdy;
1992 					test += deltax;
1993 				}
1994 				callback(userData, x, y);
1995 			}
1996 		} else {
1997 			test = (deltay + test) >> 1;
1998 			for (i32 i = 1; i < deltay; ++i) {
1999 				test -= deltax;
2000 				y += signdy;
2001 				if (test < 0) {
2002 					x += signdx;
2003 					test += deltay;
2004 				}
2005 				callback(userData, x, y);
2006 			}
2007 		}
2008 		callback(userData, xend, yend);
2009 	}
2010 };
2011 void tester91(ref TestContext ctx) {
2012 	static struct test91_user_data {
2013 		string text;
2014 		size_t i;
2015 	}
2016 	static extern(C) void external_print_coords_func(void* userData, int x, int y) {
2017 		auto data = cast(test91_user_data*)userData;
2018 		if (data.i > 0) testSink.put(", ");
2019 		formattedWrite(testSink, "(%s %s %s)", data.text, x, y);
2020 		++data.i;
2021 	}
2022 	alias func_T = extern(C) void function(void*, int, int);
2023 	auto tran_thong = ctx.getFunctionPtr!(void, int, int, int, int, func_T, void*)("tran_thong");
2024 
2025 	test91_user_data data = {
2026 		text : "hi"
2027 	};
2028 
2029 	tran_thong(0, 0, 2, 2, &external_print_coords_func, &data);
2030 
2031 	//writefln("%s", testSink.text);
2032 	assert(testSink.text == "(hi 0 0), (hi 1 1), (hi 2 2)");
2033 }
2034 
2035 @TestInfo(&tester92)
2036 immutable test92 = q{--- test92
2037 	// struct methods
2038 	struct Struct {
2039 		i32 member;
2040 		void set42() {
2041 			this.member += 42;
2042 			member = 42;
2043 		}
2044 		void set(i32 par) {
2045 			member = par;
2046 			this.member = par;
2047 		}
2048 		void set2() {
2049 			set42(); // pass this
2050 		}
2051 		void set3() {
2052 			set42; // pass this
2053 		}
2054 		void set4() {
2055 			this.set42; // explicit this
2056 		}
2057 		void set5() {
2058 			this.set42(); // explicit this
2059 		}
2060 		void set6() {
2061 			set(42); // pass this
2062 		}
2063 	}
2064 	i32 testMethod1() {
2065 		Struct s;
2066 		s.set42(); // take address
2067 		return s.member;
2068 	}
2069 	i32 testMethod2(i32 val) {
2070 		Struct s;
2071 		s.set(val); // take address
2072 		return s.member;
2073 	}
2074 	i32 testMethod3() {
2075 		Struct s;
2076 		s.set42; // take address
2077 		return s.member;
2078 	}
2079 	i32 testMethod4() {
2080 		Struct s;
2081 		Struct* sptr = &s;
2082 		sptr.set42; // call method on pointer
2083 		return sptr.member;
2084 	}
2085 	i32 testMethod5() {
2086 		Struct[1] s;
2087 		s[0].set42; // call method on index expr
2088 		s[0].set42();
2089 		s[0].set(42);
2090 		return s[0].member;
2091 	}
2092 	i32 testMethodToMethod2() {
2093 		Struct s = Struct(10); // reset stack value for future tests
2094 		s.set2;
2095 		return s.member;
2096 	}
2097 	i32 testMethodToMethod3() {
2098 		Struct s = Struct(10); // reset stack value for future tests
2099 		s.set3;
2100 		return s.member;
2101 	}
2102 	i32 testMethodToMethod4() {
2103 		Struct s = Struct(10); // reset stack value for future tests
2104 		s.set4;
2105 		return s.member;
2106 	}
2107 	i32 testMethodToMethod5() {
2108 		Struct s = Struct(10); // reset stack value for future tests
2109 		s.set5;
2110 		return s.member;
2111 	}
2112 	i32 testMethodToMethod6() {
2113 		Struct s = Struct(10); // reset stack value for future tests
2114 		s.set6;
2115 		return s.member;
2116 	}
2117 };
2118 void tester92(ref TestContext ctx) {
2119 	assert(ctx.getFunctionPtr!(int)("testMethod1")() == 42);
2120 	assert(ctx.getFunctionPtr!(int, int)("testMethod2")(60) == 60);
2121 	assert(ctx.getFunctionPtr!(int)("testMethod3")() == 42);
2122 	assert(ctx.getFunctionPtr!(int)("testMethod4")() == 42);
2123 	assert(ctx.getFunctionPtr!(int)("testMethod5")() == 42);
2124 	assert(ctx.getFunctionPtr!(int)("testMethodToMethod2")() == 42);
2125 	assert(ctx.getFunctionPtr!(int)("testMethodToMethod3")() == 42);
2126 	assert(ctx.getFunctionPtr!(int)("testMethodToMethod4")() == 42);
2127 	assert(ctx.getFunctionPtr!(int)("testMethodToMethod5")() == 42);
2128 	assert(ctx.getFunctionPtr!(int)("testMethodToMethod6")() == 42);
2129 }
2130 
2131 @TestInfo()
2132 immutable test93 = q{--- test93
2133 	// empty string literal
2134 	void print(u8[]){}
2135 	void run(){
2136 		print("");
2137 	}
2138 };
2139 
2140 @TestInfo(&tester94)
2141 immutable test94 = q{--- test94
2142 	// return small struct
2143 	struct Small {
2144 		i32 a;
2145 		i32 b;
2146 	}
2147 	Small glue(i32 a, i32 b)
2148 	{
2149 		return Small(a, b);
2150 	}
2151 };
2152 void tester94(ref TestContext ctx) {
2153 	static struct Small {
2154 		int a;
2155 		int b;
2156 	}
2157 	assert(ctx.getFunctionPtr!(Small, int, int)("glue")(42, 100) == Small(42, 100));
2158 }
2159 
2160 
2161 @TestInfo(&tester95)
2162 immutable test95 = q{--- test95
2163 	// if callback returns true the traversal stops
2164 	void tran_thong(i32 xstart, i32 ystart, i32 xend, i32 yend, bool function(void*, i32, i32) callback, void* userData)
2165 	{
2166 		i32 x = xstart;
2167 		i32 y = ystart;
2168 
2169 		if (callback(userData, x, y)) return;
2170 
2171 		i32 deltax;
2172 		i32 signdx;
2173 		if (xend >= xstart) {
2174 			deltax = xend - xstart;
2175 			signdx = 1;
2176 		} else {
2177 			deltax = xstart - xend;
2178 			signdx = -1;
2179 		}
2180 
2181 		i32 deltay;
2182 		i32 signdy;
2183 		if (yend >= ystart) {
2184 			deltay = yend - ystart;
2185 			signdy = 1;
2186 		} else {
2187 			deltay = ystart - yend;
2188 			signdy = -1;
2189 		}
2190 
2191 		i32 test;
2192 		if (signdy == -1)
2193 			test = -1;
2194 		else
2195 			test = 0;
2196 
2197 		if (deltax >= deltay) {
2198 			test = (deltax + test) >> 1;
2199 			for (i32 i = 1; i < deltax; ++i) {
2200 				test -= deltay;
2201 				x += signdx;
2202 				if (test < 0) {
2203 					y += signdy;
2204 					test += deltax;
2205 				}
2206 				if (callback(userData, x, y)) return;
2207 			}
2208 		} else {
2209 			test = (deltay + test) >> 1;
2210 			for (i32 i = 1; i < deltay; ++i) {
2211 				test -= deltax;
2212 				y += signdy;
2213 				if (test < 0) {
2214 					x += signdx;
2215 					test += deltay;
2216 				}
2217 				if (callback(userData, x, y)) return;
2218 			}
2219 		}
2220 		if (callback(userData, xend, yend)) return;
2221 	}
2222 };
2223 void tester95(ref TestContext ctx) {
2224 	static struct test95_user_data {
2225 		string text;
2226 		size_t i;
2227 		size_t breakIndex;
2228 	}
2229 	static extern(C) bool external_print_coords_func(void* userData, int x, int y) {
2230 		auto data = cast(test95_user_data*)userData;
2231 		if (data.i > 0) testSink.put(", ");
2232 		formattedWrite(testSink, "(%s %s %s)", data.text, x, y);
2233 		if (data.breakIndex == data.i) return true;
2234 		++data.i;
2235 		return false;
2236 	}
2237 
2238 	alias func_T = extern(C) bool function(void*, int, int);
2239 	auto tran_thong = ctx.getFunctionPtr!(void, int, int, int, int, func_T, void*)("tran_thong");
2240 
2241 	void runTest(size_t breakIndex, string expectedString)
2242 	{
2243 		test95_user_data data;
2244 		data = test95_user_data("hi", 0, breakIndex);
2245 		tran_thong(0, 0, 3, 3, &external_print_coords_func, &data);
2246 		//writefln("%s", testSink.text);
2247 		assert(testSink.text == expectedString);
2248 		testSink.clear;
2249 	}
2250 
2251 	runTest(0, "(hi 0 0)");
2252 	runTest(1, "(hi 0 0), (hi 1 1)");
2253 	runTest(2, "(hi 0 0), (hi 1 1), (hi 2 2)");
2254 	runTest(3, "(hi 0 0), (hi 1 1), (hi 2 2), (hi 3 3)");
2255 	runTest(4, "(hi 0 0), (hi 1 1), (hi 2 2), (hi 3 3)");
2256 }
2257 
2258 @TestInfo(&tester96)
2259 immutable test96 = q{--- test96
2260 	// splitting and spilling
2261 	void tran_thong(i32 xstart, i32 ystart, i32 xend, i32 yend, void function(void*, i32, i32) callback, void* userData)
2262 	{
2263 		i32 x = xstart;
2264 		i32 y = ystart;
2265 
2266 		i32 deltax;
2267 		i32 signdx;
2268 		if (xend >= xstart) {
2269 			deltax = xend - xstart;
2270 			signdx = 1;
2271 		} else {
2272 			deltax = xstart - xend;
2273 			signdx = -1;
2274 		}
2275 
2276 		i32 deltay;
2277 		i32 signdy;
2278 		if (yend >= ystart) {
2279 			deltay = yend - ystart;
2280 			signdy = 1;
2281 		} else {
2282 			deltay = ystart - yend;
2283 			signdy = -1;
2284 		}
2285 
2286 		i32 test;
2287 		if (signdy == -1)
2288 			test = -1;
2289 		else
2290 			test = 0;
2291 
2292 		if (deltax >= deltay) {
2293 			test = (deltax + test) >> 1;
2294 			for (i32 i = 1; i < deltax; ++i) {
2295 				test -= deltay;
2296 				x += signdx;
2297 				if (test < 0) {
2298 					y += signdy;
2299 					test += deltax;
2300 				}
2301 				callback(userData, x, y);
2302 			}
2303 		} else {
2304 			test = (deltay + test) >> 1;
2305 			for (i32 i = 1; i < deltay; ++i) {
2306 				test -= deltax;
2307 				y += signdy;
2308 				if (test < 0) {
2309 					x += signdx;
2310 					test += deltay;
2311 				}
2312 				callback(userData, x, y);
2313 			}
2314 		}
2315 	}
2316 };
2317 void tester96(ref TestContext ctx) {
2318 	static struct test96_user_data {
2319 		string text;
2320 		size_t i;
2321 	}
2322 	static extern(C) void external_print_coords_func(void* userData, int x, int y) {
2323 		auto data = cast(test96_user_data*)userData;
2324 		if (data.i > 0) testSink.put(", ");
2325 		formattedWrite(testSink, "(%s %s %s)", data.text, x, y);
2326 		++data.i;
2327 	}
2328 	alias func_T = extern(C) void function(void*, int, int);
2329 	auto tran_thong = ctx.getFunctionPtr!(void, int, int, int, int, func_T, void*)("tran_thong");
2330 
2331 	test96_user_data data = {
2332 		text : "hi"
2333 	};
2334 
2335 	tran_thong(0, 0, 2, 2, &external_print_coords_func, &data);
2336 
2337 	//writefln("%s", testSink.text);
2338 	assert(testSink.text == "(hi 1 1)");
2339 }
2340 
2341 @TestInfo(&tester97)
2342 immutable test97 = q{--- test97
2343 	// test proper GEP lowering for stack allocated data
2344 	// stack argument of add instruction should be detected and lea instruction must be produced
2345 	i32 index_array(i32 index)
2346 	{
2347 		i32[10] array;
2348 		array[index] = 42;
2349 		return array[index];
2350 	}
2351 };
2352 void tester97(ref TestContext ctx) {
2353 	auto index_array = ctx.getFunctionPtr!(int, int)("index_array");
2354 
2355 	assert(index_array(0) == 42);
2356 	assert(index_array(9) == 42);
2357 }
2358 
2359 @TestInfo()
2360 immutable test98 = q{--- folder/test98.vx
2361 	import dep98;
2362 	// test module name creation. Folders must be stripped
2363 	void test()
2364 	{
2365 		libfunc();
2366 	}
2367 --- folder/dep98.vx
2368 	void libfunc(){}
2369 };
2370 
2371 @TestInfo(&tester99)
2372 immutable test99 = `--- test99
2373 	// test #if
2374 	enum valTrue = true;
2375 	enum valFalse = false;
2376 
2377 	// global scope
2378 	#if(valTrue)
2379 		i32 foo() { return 42; } // no else
2380 
2381 	#if(valFalse)
2382 		i32 foo() { return 42; } // no items to insert
2383 
2384 	#if(valTrue){} // empty
2385 
2386 	// curly braces
2387 	#if(valFalse)
2388 	{
2389 		i32 bar() { return 42; }
2390 	}
2391 	else // insert more than 1 item
2392 	{
2393 		i32 bar() { return 100; }
2394 		i32 bar2() { return 200; }
2395 	}
2396 
2397 	// function scope
2398 	i32 funcTrue() {
2399 		#if(valTrue)
2400 			return 42;
2401 		else
2402 			return 100;
2403 	}
2404 
2405 	i32 funcFalse() {
2406 		#if(valFalse)
2407 			return 42;
2408 		else
2409 			return 100;
2410 	}
2411 `;
2412 void tester99(ref TestContext ctx) {
2413 	auto foo = ctx.getFunctionPtr!(int)("foo");
2414 	auto bar = ctx.getFunctionPtr!(int)("bar");
2415 	auto bar2 = ctx.getFunctionPtr!(int)("bar2");
2416 	auto funcTrue = ctx.getFunctionPtr!(int)("funcTrue");
2417 	auto funcFalse = ctx.getFunctionPtr!(int)("funcFalse");
2418 
2419 	assert(foo() == 42);
2420 	assert(bar() == 100);
2421 	assert(bar2() == 200);
2422 	assert(funcTrue() == 42);
2423 	assert(funcFalse() == 100);
2424 }
2425 
2426 @TestInfo()
2427 immutable test100 = `--- test100
2428 	enum a = true;
2429 	#if (a)
2430 		enum b = true;
2431 
2432 	void main()
2433 	{
2434 		#if (b) enum c = 42; // requires #if (a) to be evalauated first
2435 	}
2436 `;
2437 
2438 @TestInfo()
2439 immutable test101 = `--- test101
2440 	enum a = true;
2441 	enum b = true;
2442 	#if (a)
2443 	{
2444 		#if (b) enum c = true;
2445 	}
2446 
2447 	void main()
2448 	{
2449 		#if (c) enum d = 42; // requires #if (b) to be evalauated first
2450 	}
2451 `;
2452 
2453 @TestInfo()
2454 immutable test102 = q{--- test102
2455 	// test taking address of members
2456 	struct S {
2457 		u64 member;
2458 		void method() {
2459 			func(&member);
2460 		}
2461 	}
2462 	void func(u64* ptr) {}
2463 };
2464 
2465 @TestInfo()
2466 immutable test103 = q{--- test103
2467 	// test loading of pointers in member chains
2468 	struct A {
2469 		u64 member;
2470 	}
2471 	struct S {
2472 		A* a;
2473 	}
2474 	void func() {
2475 		S s;
2476 		s.a.member = 42;
2477 	}
2478 };
2479 
2480 @TestInfo(&tester104)
2481 immutable test104 = q{--- test104
2482 	// cast int to int
2483 	i16 fold__i8_to_i16_sext() { return cast(i16)cast( i8)-1; } // sext   i8 -> i16
2484 	i32 fold__i8_to_i32_sext() { return cast(i32)cast( i8)-1; } // sext   i8 -> i32
2485 	i32 fold_i16_to_i32_sext() { return cast(i32)cast(i16)-1; } // sext  i16 -> i32
2486 	i64 fold__i8_to_i64_sext() { return cast(i64)cast( i8)-1; } // sext   i8 -> i64
2487 	i64 fold_i16_to_i64_sext() { return cast(i64)cast(i16)-1; } // sext  i16 -> i64
2488 	i64 fold_i32_to_i64_sext() { return cast(i64)cast(i32)-1; } // sext  i32 -> i64
2489 
2490 	i16 fold__u8_to_i16_zext() { return cast(i16)cast( u8)u8.max;  } // zext   u8 -> i16
2491 	i32 fold__u8_to_i32_zext() { return cast(i32)cast( u8)u8.max;  } // zext   u8 -> i32
2492 	i32 fold_u16_to_i32_zext() { return cast(i32)cast(u16)u16.max; } // zext  u16 -> i32
2493 	i64 fold__u8_to_i64_zext() { return cast(i64)cast( u8)u8.max;  } // zext   u8 -> i64
2494 	i64 fold_u16_to_i64_zext() { return cast(i64)cast(u16)u16.max; } // zext  u16 -> i64
2495 	i64 fold_u32_to_i64_zext() { return cast(i64)cast(u32)u32.max; } // zext  u32 -> i64
2496 
2497 	u16 fold__u8_to_u16_zext() { return cast(u16)cast( u8)u8.max;  } // zext   u8 -> u16
2498 	u32 fold__u8_to_u32_zext() { return cast(u32)cast( u8)u8.max;  } // zext   u8 -> u32
2499 	u32 fold_u16_to_u32_zext() { return cast(u32)cast(u16)u16.max; } // zext  u16 -> u32
2500 	u64 fold__u8_to_u64_zext() { return cast(u64)cast( u8)u8.max;  } // zext   u8 -> u64
2501 	u64 fold_u16_to_u64_zext() { return cast(u64)cast(u16)u16.max; } // zext  u16 -> u64
2502 	u64 fold_u32_to_u64_zext() { return cast(u64)cast(u32)u32.max; } // zext  u32 -> u64
2503 
2504 	u16 fold__i8_to_u16_zext() { return cast(u16)i8.min;  } // zext   i8 -> u16 TODO: these should error without cast
2505 	u32 fold__i8_to_u32_zext() { return cast(u32)i8.min;  } // zext   i8 -> u32 TODO: these should error without cast
2506 	u32 fold_i16_to_u32_zext() { return cast(u32)i16.min; } // zext  i16 -> u32 TODO: these should error without cast
2507 	u64 fold__i8_to_u64_zext() { return cast(u64)i8.min;  } // zext   i8 -> u64 TODO: these should error without cast
2508 	u64 fold_i16_to_u64_zext() { return cast(u64)i16.min; } // zext  i16 -> u64 TODO: these should error without cast
2509 	u64 fold_i32_to_u64_zext() { return cast(u64)i32.min; } // zext  i32 -> u64 TODO: these should error without cast
2510 
2511 
2512 	i16 func__i8_to_i16( i8 a) { return a; } // sext   i8 -> i16
2513 	i32 func__i8_to_i32( i8 a) { return a; } // sext   i8 -> i32
2514 	i32 func_i16_to_i32(i16 a) { return a; } // sext  i16 -> i32
2515 	i64 func__i8_to_i64( i8 a) { return a; } // sext   i8 -> i64
2516 	i64 func_i16_to_i64(i16 a) { return a; } // sext  i16 -> i64
2517 	i64 func_i32_to_i64(i32 a) { return a; } // sext  i32 -> i64
2518 
2519 	i16 func__u8_to_i16( u8 a) { return a; } // zext   u8 -> i16
2520 	i32 func__u8_to_i32( u8 a) { return a; } // zext   u8 -> i32
2521 	i32 func_u16_to_i32(u16 a) { return a; } // zext  u16 -> i32
2522 	i64 func__u8_to_i64( u8 a) { return a; } // zext   u8 -> i64
2523 	i64 func_u16_to_i64(u16 a) { return a; } // zext  u16 -> i64
2524 	i64 func_u32_to_i64(u32 a) { return a; } // zext  u32 -> i64
2525 
2526 	u16 func__u8_to_u16( u8 a) { return a; } // zext   u8 -> u16
2527 	u32 func__u8_to_u32( u8 a) { return a; } // zext   u8 -> u32
2528 	u32 func_u16_to_u32(u16 a) { return a; } // zext  u16 -> u32
2529 	u64 func__u8_to_u64( u8 a) { return a; } // zext   u8 -> u64
2530 	u64 func_u16_to_u64(u16 a) { return a; } // zext  u16 -> u64
2531 	u64 func_u32_to_u64(u32 a) { return a; } // zext  u32 -> u64
2532 
2533 	u16 func__i8_to_u16( i8 a) { return cast(u16)a; } // zext   i8 -> u16 TODO: these should error without cast
2534 	u32 func__i8_to_u32( i8 a) { return cast(u32)a; } // zext   i8 -> u32 TODO: these should error without cast
2535 	u32 func_i16_to_u32(i16 a) { return cast(u32)a; } // zext  i16 -> u32 TODO: these should error without cast
2536 	u64 func__i8_to_u64( i8 a) { return cast(u64)a; } // zext   i8 -> u64 TODO: these should error without cast
2537 	u64 func_i16_to_u64(i16 a) { return cast(u64)a; } // zext  i16 -> u64 TODO: these should error without cast
2538 	u64 func_i32_to_u64(i32 a) { return cast(u64)a; } // zext  i32 -> u64 TODO: these should error without cast
2539 };
2540 void tester104(ref TestContext ctx) {
2541 	assert(ctx.getFunctionPtr!(short)("fold__i8_to_i16_sext")() == short(-1));
2542 	assert(ctx.getFunctionPtr!(  int)("fold__i8_to_i32_sext")() ==   int(-1));
2543 	assert(ctx.getFunctionPtr!(  int)("fold_i16_to_i32_sext")() ==   int(-1));
2544 	assert(ctx.getFunctionPtr!( long)("fold__i8_to_i64_sext")() ==  long(-1));
2545 	assert(ctx.getFunctionPtr!( long)("fold_i16_to_i64_sext")() ==  long(-1));
2546 	assert(ctx.getFunctionPtr!( long)("fold_i32_to_i64_sext")() ==  long(-1));
2547 
2548 	assert(ctx.getFunctionPtr!(short)("fold__u8_to_i16_zext")() ==  ubyte.max);
2549 	assert(ctx.getFunctionPtr!(  int)("fold__u8_to_i32_zext")() ==  ubyte.max);
2550 	assert(ctx.getFunctionPtr!(  int)("fold_u16_to_i32_zext")() == ushort.max);
2551 	assert(ctx.getFunctionPtr!( long)("fold__u8_to_i64_zext")() ==  ubyte.max);
2552 	assert(ctx.getFunctionPtr!( long)("fold_u16_to_i64_zext")() == ushort.max);
2553 	assert(ctx.getFunctionPtr!( long)("fold_u32_to_i64_zext")() ==   uint.max);
2554 
2555 	assert(ctx.getFunctionPtr!(ushort)("fold__u8_to_u16_zext")() ==  ubyte.max);
2556 	assert(ctx.getFunctionPtr!(  uint)("fold__u8_to_u32_zext")() ==  ubyte.max);
2557 	assert(ctx.getFunctionPtr!(  uint)("fold_u16_to_u32_zext")() == ushort.max);
2558 	assert(ctx.getFunctionPtr!( ulong)("fold__u8_to_u64_zext")() ==  ubyte.max);
2559 	assert(ctx.getFunctionPtr!( ulong)("fold_u16_to_u64_zext")() == ushort.max);
2560 	assert(ctx.getFunctionPtr!( ulong)("fold_u32_to_u64_zext")() ==   uint.max);
2561 
2562 	//writefln("%08X", ctx.getFunctionPtr!(ushort)("fold__i8_to_u16_zext")());
2563 	assert(ctx.getFunctionPtr!(ushort)("fold__i8_to_u16_zext")() ==  ubyte(0x0000_0080));
2564 	assert(ctx.getFunctionPtr!(  uint)("fold__i8_to_u32_zext")() ==  ubyte(0x0000_0080));
2565 	assert(ctx.getFunctionPtr!(  uint)("fold_i16_to_u32_zext")() == ushort(0x0000_8000));
2566 	assert(ctx.getFunctionPtr!( ulong)("fold__i8_to_u64_zext")() ==  ubyte(0x0000_0080));
2567 	assert(ctx.getFunctionPtr!( ulong)("fold_i16_to_u64_zext")() == ushort(0x0000_8000));
2568 	assert(ctx.getFunctionPtr!( ulong)("fold_i32_to_u64_zext")() ==   uint(0x8000_0000));
2569 
2570 
2571 	assert(ctx.getFunctionPtr!(short,   byte)("func__i8_to_i16")(  byte(-1)) == short(-1));
2572 	assert(ctx.getFunctionPtr!(  int,   byte)("func__i8_to_i32")(  byte(-1)) ==   int(-1));
2573 	assert(ctx.getFunctionPtr!(  int,  short)("func_i16_to_i32")( short(-1)) ==   int(-1));
2574 	assert(ctx.getFunctionPtr!( long,   byte)("func__i8_to_i64")(  byte(-1)) ==  long(-1));
2575 	assert(ctx.getFunctionPtr!( long,  short)("func_i16_to_i64")( short(-1)) ==  long(-1));
2576 	assert(ctx.getFunctionPtr!( long,    int)("func_i32_to_i64")(   int(-1)) ==  long(-1));
2577 
2578 	assert(ctx.getFunctionPtr!(short,  ubyte)("func__u8_to_i16")( ubyte.max) ==  ubyte.max);
2579 	assert(ctx.getFunctionPtr!(  int,  ubyte)("func__u8_to_i32")( ubyte.max) ==  ubyte.max);
2580 	assert(ctx.getFunctionPtr!(  int, ushort)("func_u16_to_i32")(ushort.max) == ushort.max);
2581 	assert(ctx.getFunctionPtr!( long,  ubyte)("func__u8_to_i64")( ubyte.max) ==  ubyte.max);
2582 	assert(ctx.getFunctionPtr!( long, ushort)("func_u16_to_i64")(ushort.max) == ushort.max);
2583 	assert(ctx.getFunctionPtr!( long,   uint)("func_u32_to_i64")(  uint.max) ==   uint.max);
2584 
2585 	assert(ctx.getFunctionPtr!(ushort,  ubyte)("func__u8_to_u16")( ubyte.max) ==  ubyte.max);
2586 	assert(ctx.getFunctionPtr!(  uint,  ubyte)("func__u8_to_u32")( ubyte.max) ==  ubyte.max);
2587 	assert(ctx.getFunctionPtr!(  uint, ushort)("func_u16_to_u32")(ushort.max) == ushort.max);
2588 	assert(ctx.getFunctionPtr!( ulong,  ubyte)("func__u8_to_u64")( ubyte.max) ==  ubyte.max);
2589 	assert(ctx.getFunctionPtr!( ulong, ushort)("func_u16_to_u64")(ushort.max) == ushort.max);
2590 	assert(ctx.getFunctionPtr!( ulong,   uint)("func_u32_to_u64")(  uint.max) ==   uint.max);
2591 
2592 	//writefln("%08X", ctx.getFunctionPtr!(ushort,   byte)("func__i8_to_u16")(  byte.min));
2593 	assert(ctx.getFunctionPtr!(ushort,   byte)("func__i8_to_u16")(  byte.min) ==  ubyte(0x0000_0080));
2594 	assert(ctx.getFunctionPtr!(  uint,   byte)("func__i8_to_u32")(  byte.min) ==  ubyte(0x0000_0080));
2595 	assert(ctx.getFunctionPtr!(  uint,  short)("func_i16_to_u32")( short.min) == ushort(0x0000_8000));
2596 	assert(ctx.getFunctionPtr!( ulong,   byte)("func__i8_to_u64")(  byte.min) ==  ubyte(0x0000_0080));
2597 	assert(ctx.getFunctionPtr!( ulong,  short)("func_i16_to_u64")( short.min) == ushort(0x0000_8000));
2598 	assert(ctx.getFunctionPtr!( ulong,    int)("func_i32_to_u64")(   int.min) ==   uint(0x8000_0000));
2599 }
2600 
2601 @TestInfo(&tester105)
2602 immutable test105 = q{--- test105
2603 	// test struct constructor with default initialization
2604 	struct Struct
2605 	{
2606 		i32 var = 42;
2607 		void fun(){}
2608 		i32 var2;
2609 	}
2610 	Struct get_struct()
2611 	{
2612 		Struct s = Struct();
2613 		return s;
2614 	}
2615 	// test struct constructor with nested struct initialization
2616 	struct Struct2
2617 	{
2618 		u8[] str;
2619 	}
2620 	Struct2 get_struct2(u8[] str)
2621 	{
2622 		return Struct2(str);
2623 	}
2624 };
2625 void tester105(ref TestContext ctx) {
2626 	struct Struct { int a; int b; }
2627 	auto get_struct = ctx.getFunctionPtr!(Struct)("get_struct");
2628 	assert(get_struct() == Struct(42, 0));
2629 
2630 	struct Struct2 { const(char)[] str; }
2631 	auto get_struct2 = ctx.getFunctionPtr!(Struct2, SliceString)("get_struct2");
2632 	assert(get_struct2(SliceString("test")) == Struct2("test"));
2633 }
2634 
2635 
2636 @TestInfo(&tester106, [HostSymbol("fun2", cast(void*)&external_tester106)])
2637 immutable test106 = q{--- test106
2638 	// Test structs passed as pointer on the stack (win64 abi) (name parameter)
2639 	// big struct on stack (sysv64)
2640 	void fun(i32, i32, i32, u8, u8, u8, u8[] name, bool){
2641 		fun2(name);
2642 	}
2643 	@extern(module, "host")
2644 	void fun2(u8[]);
2645 	void run()
2646 	{
2647 		fun(50, 50, 32, 0, 255, 0, "Player", true);
2648 	}
2649 };
2650 extern(C) void external_tester106(Slice!char str) {
2651 	assert(str == "Player");
2652 }
2653 void tester106(ref TestContext ctx) {
2654 	auto run = ctx.getFunctionPtr!(void)("run");
2655 	run();
2656 }
2657 
2658 
2659 @TestInfo(&tester107)
2660 immutable test107 = q{--- test107
2661 	// Test slicing
2662 	i32[] slice_ptr1(i32* ptr)
2663 	{
2664 		return ptr[0..10];
2665 	}
2666 	i32[] slice_ptr2(i32* ptr, u64 from, u64 to)
2667 	{
2668 		return ptr[from..to];
2669 	}
2670 	i32[] slice_array1(i32[10]* ptr)
2671 	{
2672 		return (*ptr)[0..10];
2673 	}
2674 	i32[] slice_array2(i32[10]* ptr, u64 from, u64 to)
2675 	{
2676 		return (*ptr)[from..to];
2677 	}
2678 	i32[] slice_slice1(i32[] ptr)
2679 	{
2680 		return ptr[0..10];
2681 	}
2682 	i32[] slice_slice2(i32[] ptr, u64 from, u64 to)
2683 	{
2684 		return ptr[from..to];
2685 	}
2686 	void test()
2687 	{
2688 		u8[2] array;
2689 		u8[] slice = array[0..1];
2690 		u8_user(array[0..1]);
2691 	}
2692 	void u8_user(u8[]){}
2693 };
2694 void tester107(ref TestContext ctx) {
2695 	int[10] array = [0,1,2,3,4,5,6,7,8,9];
2696 
2697 	auto slice_ptr1 = ctx.getFunctionPtr!(Slice!int, int*)("slice_ptr1");
2698 	assert(slice_ptr1(array.ptr) == array[]);
2699 	auto slice_ptr2 = ctx.getFunctionPtr!(Slice!int, int*, ulong, ulong)("slice_ptr2");
2700 	assert(slice_ptr2(array.ptr, 0, 10) == array[]);
2701 	assert(slice_ptr2(array.ptr, 5, 7) == array[5..7]);
2702 
2703 	auto slice_array1 = ctx.getFunctionPtr!(Slice!int, int[10]*)("slice_array1");
2704 	assert(slice_array1(&array) == array[]);
2705 	auto slice_array2 = ctx.getFunctionPtr!(Slice!int, int[10]*, ulong, ulong)("slice_array2");
2706 	assert(slice_array2(&array, 0, 10) == array[]);
2707 	assert(slice_array2(&array, 5, 7) == array[5..7]);
2708 
2709 	auto slice_slice1 = ctx.getFunctionPtr!(Slice!int, Slice!int)("slice_slice1");
2710 	assert(slice_slice1(Slice!int(array[])) == array[]);
2711 	auto slice_slice2 = ctx.getFunctionPtr!(Slice!int, Slice!int, ulong, ulong)("slice_slice2");
2712 	assert(slice_slice2(Slice!int(array[]), 0, 10) == array[]);
2713 	assert(slice_slice2(Slice!int(array[]), 5, 7) == array[5..7]);
2714 }
2715 
2716 
2717 @TestInfo(&tester108)
2718 immutable test108 = q{--- test108
2719 	// Test function templates
2720 	T min[T](T a, T b) {
2721 		if (a < b) return a;
2722 		return b;
2723 	}
2724 	i8 test_i8(i8 a, i8 b) {
2725 		return min[i8](a, b) + min[i8](a, b); // test double instantiation
2726 	}
2727 	i16 test_i16(i16 a, i16 b) {
2728 		return min[i16](a, b) + min[i16](a, b); // test multiple instances
2729 	}
2730 	i32 test_i32(i32 a, i32 b) {
2731 		return min[i32](a, b) + min[i32](a, b);
2732 	}
2733 	i64 test_i64(i64 a, i64 b) {
2734 		return min[i64](a, b) + min[i64](a, b);
2735 	}
2736 };
2737 void tester108(ref TestContext ctx) {
2738 	auto test_i8 = ctx.getFunctionPtr!(byte, byte, byte)("test_i8");
2739 	auto test_i16 = ctx.getFunctionPtr!(short, short, short)("test_i16");
2740 	auto test_i32 = ctx.getFunctionPtr!(int, int, int)("test_i32");
2741 	auto test_i64 = ctx.getFunctionPtr!(long, long, long)("test_i64");
2742 	assert(test_i8(42, 120) == 42 * 2);
2743 	assert(test_i16(420, 1200) == 420 * 2);
2744 	assert(test_i32(-10_000, 10_000) == -10_000 * 2);
2745 	assert(test_i64(-10_000, 10_000) == -10_000 * 2);
2746 }
2747 
2748 @TestInfo()
2749 immutable test109 = q{--- test109
2750 	// Test all type kinds
2751 	struct S {
2752 		i32 n;
2753 	}
2754 	T pass[T](T a) {
2755 		return a;
2756 	}
2757 	i8 test_basic(i8 a) {
2758 		return pass[i8](a);
2759 	}
2760 	u8* test_ptr(u8* ptr) {
2761 		return pass[u8*](ptr);
2762 	}
2763 	S test_struct(S s) {
2764 		return pass[S](s);
2765 	}
2766 	u8[] test_i64(u8[] slice) {
2767 		return pass[u8[]](slice);
2768 	}
2769 };
2770 
2771 @TestInfo(&tester110)
2772 immutable test110 = q{--- test110
2773 	// Test struct templates
2774 	struct Array[T] {
2775 		T item;
2776 	}
2777 	T fun[T](T arg) { return arg; }
2778 	Array[i32] test(Array[i32] array) {
2779 		return fun[Array[i32]](array);
2780 	}
2781 };
2782 void tester110(ref TestContext ctx) {
2783 	assert(ctx.getFunctionPtr!(int, int)("test")(42) == 42);
2784 }
2785 
2786 
2787 @TestInfo(&tester111)
2788 immutable test111 = q{--- test111
2789 	// Test string escapes
2790 	u8[] test() {
2791 		return "\'\"\?\\\0\a\b\f\n\r\t\v\xAA\uAAAA\U0000AAAA";
2792 	}
2793 };
2794 void tester111(ref TestContext ctx) {
2795 	assert(ctx.getFunctionPtr!(Slice!char)("test")() == "\'\"\?\\\0\a\b\f\n\r\t\v\xAA\uAAAA\U0000AAAA");
2796 }
2797 
2798 @TestInfo(&tester112)
2799 immutable test112 = q{--- test112
2800 	// Test int <--> ptr conversions
2801 	u64 ptr_to_int(u8* ptr) {
2802 		return cast(u64)ptr;
2803 	}
2804 	u8* int_to_ptr(u64 i) {
2805 		return cast(u8*)i;
2806 	}
2807 };
2808 void tester112(ref TestContext ctx) {
2809 	assert(ctx.getFunctionPtr!(ulong, ubyte*)("ptr_to_int")(cast(ubyte*)0xFFFF_FFFF_FFFF_FFFF) == 0xFFFF_FFFF_FFFF_FFFF);
2810 	assert(ctx.getFunctionPtr!(ubyte*, ulong)("int_to_ptr")(0xFFFF_FFFF_FFFF_FFFF) == cast(ubyte*)0xFFFF_FFFF_FFFF_FFFF);
2811 }
2812 
2813 
2814 @TestInfo(&tester113)
2815 immutable test113 = q{--- test113
2816 	// default initialization of variables
2817 	struct S
2818 	{
2819 		i32 integer;
2820 		u8[] slice;
2821 	}
2822 	void fun()
2823 	{
2824 		S s;
2825 		i32 integer;
2826 		u8[] slice;
2827 	}
2828 };
2829 void tester113(ref TestContext ctx) {
2830 }
2831 
2832 
2833 @TestInfo(&tester114)
2834 immutable test114 = q{--- test114
2835 	// test ptr slice correctenss
2836 	struct Array
2837 	{
2838 		i32* bufPtr;
2839 		u32 length;
2840 		u32 capacity;
2841 
2842 		i32[] data()
2843 		{
2844 			return bufPtr[0..length];
2845 		}
2846 	}
2847 
2848 	i32[] test(Array* array)
2849 	{
2850 		return array.data;
2851 	}
2852 };
2853 void tester114(ref TestContext ctx) {
2854 	static struct Array {
2855 		int* ptr;
2856 		uint length;
2857 		uint capacity;
2858 	}
2859 	int[2] buffer = [42, 0];
2860 	Array array = Array(buffer.ptr, 1, 2);
2861 	int[] data = ctx.getFunctionPtr!(Slice!int, Array*)("test")(&array).slice;
2862 	assert(data.ptr == buffer.ptr);
2863 	assert(data.length == 1);
2864 }
2865 
2866 
2867 @TestInfo(&tester115)
2868 immutable test115 = q{--- test115
2869 	// Test recursive templates
2870 	T test[T](T arg) {
2871 		if (arg == 0)
2872 			return 42;
2873 		return test[T](arg-1);
2874 	}
2875 	i32 test_i32() {
2876 		return test[i32](42);
2877 	}
2878 };
2879 void tester115(ref TestContext ctx) {
2880 	assert(ctx.getFunctionPtr!(int)("test_i32")() == 42);
2881 }
2882 
2883 
2884 @TestInfo(&tester116)
2885 immutable test116 = q{--- test116
2886 	// Test default arguments
2887 	struct S { i32 a; i32 b; }
2888 	i32 func_i32(i32 arg = 42) { return arg; }
2889 	u8[] func_string(u8[] arg = "Hello") { return arg; }
2890 	//S func_struct(S arg = S(1, 2)) { return arg; } // TODO
2891 
2892 	i32 test_i32() { return func_i32; }
2893 	u8[] test_string() { return func_string; }
2894 	//S test_struct() { return func_struct; }
2895 };
2896 void tester116(ref TestContext ctx) {
2897 	assert(ctx.getFunctionPtr!(int)("test_i32")() == 42);
2898 	assert(ctx.getFunctionPtr!SliceString("test_string")().slice == "Hello");
2899 }
2900 
2901 
2902 @TestInfo(&tester117)
2903 immutable test117 = q{--- test117
2904 	// BUG: passing small constant (u8) as big (u32) argument causes u8 <- u8 mov instead of u32 <- u32
2905 	u32 pass(u32 param) {
2906 		return param;
2907 	}
2908 	u64 test() {
2909 		u64 val = pass(0xFFFF_FFFF); // fill register with garbage
2910 		val += pass(0); // BUG: sets only the lowest byte, passing 0xFFFF_FF00 as an argument
2911 		return val;
2912 	}
2913 };
2914 void tester117(ref TestContext ctx) {
2915 	assert(ctx.getFunctionPtr!(ulong)("test")() == 0xFFFF_FFFF);
2916 }
2917 
2918 
2919 @TestInfo(&tester118)
2920 immutable test118 = q{--- test118
2921 	// Test global ptr deref assign
2922 	u32* glob_ptr;
2923 	u32** get_ptr() { return &glob_ptr; }
2924 	void set_value(u32 val) { *glob_ptr = val; }
2925 };
2926 void tester118(ref TestContext ctx) {
2927 	auto get_ptr = ctx.getFunctionPtr!(uint**)("get_ptr");
2928 	auto set_value = ctx.getFunctionPtr!(void, uint)("set_value");
2929 	uint val;
2930 	(*get_ptr()) = &val;
2931 	set_value(100);
2932 	assert(val == 100);
2933 }
2934 
2935 
2936 @TestInfo(&tester119)
2937 immutable test119 = q{--- test119
2938 	// Test global scalar initialization
2939 	u32 glob = 42;
2940 	u32 read_global() { return glob; }
2941 	void set_global(u32 val) { glob = val; }
2942 };
2943 void tester119(ref TestContext ctx) {
2944 	auto read_global = ctx.getFunctionPtr!(uint)("read_global");
2945 	auto set_global = ctx.getFunctionPtr!(void, uint)("set_global");
2946 	assert(read_global() == 42);
2947 	set_global(100);
2948 	assert(read_global() == 100);
2949 }
2950 
2951 
2952 @TestInfo(&tester120)
2953 immutable test120 = q{--- test120
2954 	// Test global struct initialization
2955 	struct S {
2956 		u32 a;
2957 		u32 b;
2958 		u32 c;
2959 		u32 d;
2960 	}
2961 	S glob = S(1, 2, 3, 4);
2962 	S read_global() { return glob; }
2963 	void set_global(S val) { glob = val; }
2964 };
2965 void tester120(ref TestContext ctx) {
2966 	struct S {
2967 		uint a;
2968 		uint b;
2969 		uint c;
2970 		uint d;
2971 	}
2972 	auto read_global = ctx.getFunctionPtr!(S)("read_global");
2973 	auto set_global = ctx.getFunctionPtr!(void, S)("set_global");
2974 	assert(read_global() == S(1, 2, 3, 4));
2975 	set_global(S(10, 20, 30, 40));
2976 	assert(read_global() == S(10, 20, 30, 40));
2977 }
2978 
2979 
2980 @TestInfo(&tester121)
2981 immutable test121 = q{--- test121
2982 	// Test global struct initialization with pointers
2983 	u32 a = 1;
2984 	u32 b = 2;
2985 	u32 c = 3;
2986 	u32 d = 4;
2987 	struct S {
2988 		u32* a;
2989 		u32* b;
2990 		u32* c;
2991 		u32* d;
2992 	}
2993 	S glob = S(&a, &b, &c, &d);
2994 	S read_global() { return glob; }
2995 };
2996 void tester121(ref TestContext ctx) {
2997 	struct S {
2998 		uint* a;
2999 		uint* b;
3000 		uint* c;
3001 		uint* d;
3002 	}
3003 	auto read_global = ctx.getFunctionPtr!(S)("read_global");
3004 	//import utils : printHex;
3005 	//printHex(ctx.driver.context.staticDataBuffer.data, 16);
3006 	S s = read_global();
3007 	assert(*s.a == 1);
3008 	assert(*s.b == 2);
3009 	assert(*s.c == 3);
3010 	assert(*s.d == 4);
3011 }
3012 
3013 
3014 @TestInfo(&tester122)
3015 immutable test122 = q{--- test122
3016 	// Test global pointer initialization
3017 	u32 glob = 42;
3018 	u32* glob_ptr = &glob;
3019 	u32* get_ptr() { return glob_ptr; }
3020 	u32 read_global() { return *glob_ptr; }
3021 	void set_global(u32 val) { *glob_ptr = val; }
3022 };
3023 void tester122(ref TestContext ctx) {
3024 	auto get_ptr = ctx.getFunctionPtr!(uint*)("get_ptr");
3025 	auto read_global = ctx.getFunctionPtr!(uint)("read_global");
3026 	auto set_global = ctx.getFunctionPtr!(void, uint)("set_global");
3027 	//writefln("%X %s", get_ptr(), *get_ptr());
3028 	//writefln("%s", read_global());
3029 	assert(read_global() == 42);
3030 	set_global(100);
3031 	//writefln("%X %s", get_ptr(), *get_ptr());
3032 	//writefln("%s", read_global());
3033 	assert(read_global() == 100);
3034 }
3035 
3036 
3037 @TestInfo(&tester123)
3038 immutable test123 = q{--- test123
3039 	// Test switch
3040 	i32 fun(i32 val) {
3041 		switch (val) {
3042 			0 { return 40; }
3043 			1 { return 10; }
3044 			2 { return 15; }
3045 			else { return 0; }
3046 		}
3047 	}
3048 };
3049 void tester123(ref TestContext ctx) {
3050 	auto fun = ctx.getFunctionPtr!(int, int)("fun");
3051 	assert(fun(0) == 40);
3052 	assert(fun(1) == 10);
3053 	assert(fun(2) == 15);
3054 	assert(fun(100) == 0);
3055 	assert(fun(200) == 0);
3056 	assert(fun(-200) == 0);
3057 }
3058 
3059 @TestInfo(&tester124)
3060 immutable test124 = q{--- test124
3061 	// Test global in separate module
3062 	import file2;
3063 	i64 read_global() { return noop(glob); }
3064 	i64 noop(i64 val) { return val; }
3065 --- file2
3066 	i64 glob = 42;
3067 };
3068 void tester124(ref TestContext ctx) {
3069 	auto read_global = ctx.getFunctionPtr!(uint)("read_global");
3070 	assert(read_global() == 42);
3071 }
3072 
3073 
3074 @TestInfo()
3075 immutable test125 = q{--- test125
3076 	// Index expression over template should copy isType of template body
3077 	void freeArray[T](T[] array) {}
3078 
3079 	struct Array[T]
3080 	{
3081 		T* bufPtr;
3082 		u32 length;
3083 		u32 capacity;
3084 
3085 		void free()
3086 		{
3087 			freeArray[T](bufPtr[0..length]);
3088 		}
3089 	}
3090 	alias int_array = Array[i32];
3091 };
3092 
3093 @TestInfo()
3094 immutable test126 = q{--- test126
3095 	// Template bug. .ptr PtrTypeNode was not marked as type checked
3096 	void run() {
3097 		i32[] slice;
3098 		freeArray[i32](slice);
3099 	}
3100 
3101 	void freeArray[T](T[] array)
3102 	{
3103 		if (array.ptr == null) return;
3104 	}
3105 };
3106 
3107 @TestInfo(&tester127)
3108 immutable test127 = q{--- test127
3109 	// Small struct store
3110 	void put(Point* bufPtr, Point item) {
3111 		bufPtr[0] = item;
3112 	}
3113 	struct Point { i32 x; i32 y; }
3114 };
3115 void tester127(ref TestContext ctx) {
3116 	static struct Point { int x; int y; }
3117 	auto put = ctx.getFunctionPtr!(void, Point*, Point)("put");
3118 	Point point;
3119 	put(&point, Point(42, 90));
3120 	assert(point == Point(42, 90));
3121 }
3122 
3123 
3124 @TestInfo()
3125 immutable test128 = q{--- test128
3126 	// Test member access on null constant
3127 	struct Tile {
3128 		u16 a;
3129 		u16 b;
3130 	}
3131 	void run() {
3132 		Tile* t;
3133 		t.b = 42; // member of null pointer
3134 	}
3135 };
3136 
3137 
3138 @TestInfo()
3139 immutable test129 = `--- test129
3140 	// Test inlining a recursive function inside non-recursive caller
3141 	i32 caller(i32 param) {
3142 		return callee(param) + 10;
3143 	}
3144 
3145 	i32 callee(i32 param) #inline {
3146 		if (param == 0) return 42;
3147 		return callee(param - 1);
3148 	}
3149 `;
3150 
3151 @TestInfo()
3152 immutable test130 = `--- test130
3153 	// Test inlining with phi function
3154 	// Test inlining with array used
3155 	i32 caller(i32 param) {
3156 		return sign(param);
3157 	}
3158 
3159 	i32 sign(i32 number) #inline {
3160 		if (number < 0) return 0-1;
3161 		else if (number > 0) return 1;
3162 		else return 0;
3163 	}
3164 `;
3165 
3166 
3167 @TestInfo(null, [HostSymbol("log", cast(void*)&external_print_i64_func)])
3168 immutable test131 = q{--- test131
3169 	i64 fac(i64 x) {
3170 		if (x < 2) {
3171 			return 1;
3172 		} else {
3173 			return fac(x - 1) * x;
3174 		}
3175 	}
3176 	@extern(module, "host")
3177 	void log(i64);
3178 	void run() {
3179 		log(fac(5));
3180 	}
3181 };
3182 
3183 
3184 @TestInfo()
3185 immutable test132 = q{--- test132
3186 	#assert(true, "Assert test");
3187 };
3188 
3189 
3190 @TestInfo()
3191 immutable test133 = q{--- test133
3192 	#assert(false, "Assert test");
3193 --- <error>
3194 test133:1:2: Error: #assert: "Assert test"
3195 };
3196 
3197 
3198 @TestInfo()
3199 immutable test134 = q{--- test134
3200 	$alias func() {
3201 		return func; // return alias to itself
3202 	}
3203 };
3204 
3205 @TestInfo()
3206 immutable test135 = q{--- test135
3207 	$alias func() {
3208 		return func; // return alias to itself
3209 	}
3210 };
3211 
3212 @TestInfo(&tester136)
3213 immutable test136 = q{--- test136
3214 	// Various meta types tests
3215 	i32 func() { return 42; }
3216 	$alias metaFun1() { return func; } // return $alias of func
3217 	$alias metaFun2() { return u8; } // return $alias of built-in
3218 	$type  metaFun3() { return u8; } // return $type
3219 	enum bool res1 = metaFun1() == u8; // false
3220 	enum bool res2 = metaFun2() == u8; // true
3221 	enum bool res3 = metaFun3() == u8; // true
3222 
3223 	enum $alias a = func;
3224 	//enum $type t = i32;
3225 	i32 run() { return a(); }
3226 	bool run1() { return res1; }
3227 	bool run2() { return res2; }
3228 	bool run3() { return res3; }
3229 
3230 	bool isInteger($type type) {
3231 		return type == u8
3232 			|| type == i8
3233 			|| type == u16
3234 			|| type == i16
3235 			|| type == u32
3236 			|| type == i32
3237 			|| type == u64
3238 			|| type == i64;
3239 	}
3240 	enum bool res4 =
3241 		isInteger(u8) &&
3242 		isInteger(i8) &&
3243 		isInteger(u16) &&
3244 		isInteger(i16) &&
3245 		isInteger(u32) &&
3246 		isInteger(i32) &&
3247 		isInteger(u64) &&
3248 		isInteger(i64);
3249 	bool run4() { return res4; }
3250 };
3251 void tester136(ref TestContext ctx) {
3252 	auto run = ctx.getFunctionPtr!(int)("run");
3253 	auto run1 = ctx.getFunctionPtr!(bool)("run1");
3254 	auto run2 = ctx.getFunctionPtr!(bool)("run2");
3255 	auto run3 = ctx.getFunctionPtr!(bool)("run3");
3256 	auto run4 = ctx.getFunctionPtr!(bool)("run4");
3257 	assert(run() == 42);
3258 	assert(run1() == false);
3259 	assert(run2() == true);
3260 	assert(run3() == true);
3261 	assert(run4() == true);
3262 }
3263 
3264 
3265 @TestInfo()
3266 immutable test137 = q{--- test137
3267 	// ctfe only structs
3268 	struct S1 {
3269 		$alias ctfeVar;
3270 	}
3271 	struct S2 {
3272 		$alias ctfeFun(){ return S1; }
3273 	}
3274 };
3275 
3276 
3277 @TestInfo(null, [HostSymbol("crash", cast(void*)&external_noop)])
3278 immutable test138 = q{--- test138
3279 	// noreturn
3280 	@extern(module, "host")
3281 	noreturn crash();
3282 	void run1() {
3283 		crash();
3284 	}
3285 	noreturn run2() {
3286 		crash();
3287 	}
3288 	// should not complain about missing return
3289 	i32 run3() {
3290 		crash();
3291 	}
3292 };
3293 
3294 
3295 @TestInfo()
3296 immutable test139 = q{--- test139
3297 	// builtin functions
3298 	bool run() {
3299 		return val;
3300 	}
3301 	enum val = $compileError("CTFE error");
3302 --- <error>
3303 test139:5:26: Error: CTFE error
3304 };
3305 
3306 
3307 @TestInfo()
3308 immutable test140 = q{--- test140
3309 	// CTFE in type check pass
3310 	#assert(callee1, "test");
3311 	bool callee1() {
3312 		return callee2();
3313 	}
3314 	bool callee2() {
3315 		return false;
3316 	}
3317 --- <error>
3318 test140:2:2: Error: #assert: "test"
3319 };
3320 
3321 
3322 // TODO: no file/line number in the error
3323 @TestInfo()
3324 immutable test141 = q{--- test141
3325 	// builtin functions
3326 	#assert(callee1, "test");
3327 	bool callee1() {
3328 		return callee2();
3329 	}
3330 
3331 	bool callee2() {
3332 		$compileError("CTFE error");
3333 	}
3334 --- <error>
3335 : Error: CTFE error
3336 };
3337 
3338 
3339 @TestInfo(&tester142)
3340 immutable test142 = q{--- test142
3341 	// Store $alias and $type in alias
3342 	alias type1 = getType1();
3343 	$alias getType1() { return u8; }
3344 	type1 run1() {
3345 		 return 42;
3346 	}
3347 	alias type2 = getType2();
3348 	$type getType2() { return u8; }
3349 	type2 run2() {
3350 		 return 42;
3351 	}
3352 };
3353 void tester142(ref TestContext ctx) {
3354 	auto run1 = ctx.getFunctionPtr!(ubyte)("run1");
3355 	auto run2 = ctx.getFunctionPtr!(ubyte)("run2");
3356 	assert(run1() == 42);
3357 	assert(run2() == 42);
3358 }
3359 
3360 
3361 @TestInfo(&tester143)
3362 immutable test143 = q{--- test143
3363 	// bool $isSlice($type type)
3364 	bool run1() {
3365 		enum bool val = $isSlice(u8[]);
3366 		return val; // true
3367 	}
3368 	bool run2() {
3369 		enum bool val = $isSlice(u8);
3370 		return val; // false
3371 	}
3372 };
3373 void tester143(ref TestContext ctx) {
3374 	auto run1 = ctx.getFunctionPtr!(bool)("run1");
3375 	auto run2 = ctx.getFunctionPtr!(bool)("run2");
3376 	assert(run1() == true);
3377 	assert(run2() == false);
3378 }
3379 
3380 
3381 @TestInfo(&tester144, [
3382 	HostSymbol("printStr", cast(void*)&external_print_string),
3383 	HostSymbol("printInt", cast(void*)&external_print_i64_func)])
3384 immutable test144 = q{--- test144
3385 	// select function
3386 	@extern(module, "host")
3387 	void printStr(u8[]);
3388 	@extern(module, "host")
3389 	void printInt(i64 i);
3390 	bool isInteger($type type) {
3391 		return type == u8
3392 			|| type == i8
3393 			|| type == u16
3394 			|| type == i16
3395 			|| type == u32
3396 			|| type == i32
3397 			|| type == u64
3398 			|| type == i64;
3399 	}
3400 	$alias selectPrintFunc($type T) {
3401 		if (isInteger(T))
3402 			return printInt;
3403 		if ($isSlice(T))
3404 			return printStr;
3405 		$compileError("Invalid type");
3406 	}
3407 	void run() {
3408 		alias func1 = selectPrintFunc(u8[]);
3409 		func1("Hello");
3410 		alias func2 = selectPrintFunc(i32);
3411 		func2(42);
3412 	}
3413 };
3414 void tester144(ref TestContext ctx) {
3415 	auto run = ctx.getFunctionPtr!(void)("run");
3416 	run();
3417 	assert(testSink.text == "Hello42");
3418 }
3419 
3420 
3421 @TestInfo()
3422 immutable test145 = q{--- test145
3423 	// Test implicit function template instantiation (0 args)
3424 	void fun[]() {}
3425 	void run(){ fun(); }
3426 };
3427 
3428 
3429 @TestInfo()
3430 immutable test146 = q{--- test146
3431 	// Test implicit function template instantiation (1 arg)
3432 	void fun[T](T param) {}
3433 	void run(){ fun(42); }
3434 };
3435 
3436 
3437 @TestInfo()
3438 immutable test147 = q{--- test147
3439 	// Test implicit function template instantiation (2 equivalent types on single arg)
3440 	void fun[T](T param1, T param2) {}
3441 	void run(){ fun(42, 42); }
3442 };
3443 
3444 
3445 @TestInfo(&tester148)
3446 immutable test148 = q{--- test148
3447 	// Test implicit function template instantiation
3448 	T min[T](T a, T b) {
3449 		if (a < b) return a;
3450 		return b;
3451 	}
3452 	i8 test_i8(i8 a, i8 b) {
3453 		return min(a, b) + min(a, b);
3454 	}
3455 	i16 test_i16(i16 a, i16 b) {
3456 		return min(a, b) + min(a, b);
3457 	}
3458 	i32 test_i32(i32 a, i32 b) {
3459 		return min(a, b) + min(a, b);
3460 	}
3461 	i64 test_i64(i64 a, i64 b) {
3462 		return min(a, b) + min(a, b);
3463 	}
3464 };
3465 void tester148(ref TestContext ctx) {
3466 	auto test_i8 = ctx.getFunctionPtr!(byte, byte, byte)("test_i8");
3467 	auto test_i16 = ctx.getFunctionPtr!(short, short, short)("test_i16");
3468 	auto test_i32 = ctx.getFunctionPtr!(int, int, int)("test_i32");
3469 	auto test_i64 = ctx.getFunctionPtr!(long, long, long)("test_i64");
3470 	assert(test_i8(42, 120) == 42 * 2);
3471 	assert(test_i16(420, 1200) == 420 * 2);
3472 	assert(test_i32(-10_000, 10_000) == -10_000 * 2);
3473 	assert(test_i64(-10_000, 10_000) == -10_000 * 2);
3474 }
3475 
3476 
3477 @TestInfo()
3478 immutable test149 = q{--- test149
3479 	// Test implicit function template instantiation (2 different types that have common type)
3480 	void fun[T](T param1, T param2) {}
3481 	void run(){ fun(42, 500); }
3482 };
3483 
3484 
3485 @TestInfo(&tester150, [
3486 	HostSymbol("printStr", cast(void*)&external_print_string),
3487 	HostSymbol("printInt", cast(void*)&external_print_i64_func)])
3488 immutable test150 = q{--- test150
3489 	// $isInteger + IFTI
3490 	@extern(module, "host")
3491 	void printStr(u8[]);
3492 	@extern(module, "host")
3493 	void printInt(i64 i);
3494 	$alias selectPrintFunc($type T) {
3495 		if ($isInteger(T))
3496 			return printInt;
3497 		if ($isSlice(T))
3498 			return printStr;
3499 		$compileError("Invalid type");
3500 	}
3501 	void write[T](T val) {
3502 		alias func = selectPrintFunc(T);
3503 		func(val);
3504 	}
3505 	void run() {
3506 		write("Hello");
3507 		write(42);
3508 	}
3509 };
3510 void tester150(ref TestContext ctx) {
3511 	auto run = ctx.getFunctionPtr!(void)("run");
3512 	run();
3513 	assert(testSink.text == "Hello42");
3514 }
3515 
3516 
3517 @TestInfo()
3518 immutable test151 = q{--- test151
3519 	// Variadic template arg (0 uses, 0 args)
3520 	void fun[Args...]() {
3521 		#assert(Args.length == 0);
3522 	}
3523 	void run(){ fun(); }
3524 };
3525 
3526 
3527 @TestInfo()
3528 immutable test152 = q{
3529 --- test152
3530 	// Variadic template arg (0 uses, 0 args, 2 variadics)
3531 	void fun[Args1..., Args2...]() {}
3532 	void run(){ fun(); }
3533 --- <error>
3534 test152:2:21: Error: Only single variadic template parameter allowed
3535 };
3536 
3537 
3538 @TestInfo()
3539 immutable test153 = q{
3540 --- test153
3541 	// Variadic template arg (0 uses, 0 args, 1 variadic, 1 param after variadic)
3542 	void fun[Args..., T]() {}
3543 	void run(){ fun(); }
3544 --- <error>
3545 test153:2:20: Error: Cannot have template parameters after variadic parameter (WIP)
3546 };
3547 
3548 
3549 @TestInfo()
3550 immutable test154 = q{--- test154
3551 	// Variadic template arg (0 args)
3552 	void fun[Args...](Args... args) {
3553 		#assert(Args.length == 0);
3554 	}
3555 	void run(){ fun(); }
3556 };
3557 
3558 
3559 @TestInfo()
3560 immutable test155 = q{--- test155
3561 	// Variadic template arg (1 arg)
3562 	void fun[Args...](Args... args) {
3563 		#assert(Args.length == 1);
3564 	}
3565 	void run(){ fun(42); }
3566 };
3567 
3568 
3569 @TestInfo()
3570 immutable test156 = q{--- test156
3571 	// Variadic template arg (2 args)
3572 	void fun[Args...](Args... args) {
3573 		#assert(Args.length == 2);
3574 	}
3575 	void run(){ fun(42, 4096); }
3576 };
3577 
3578 
3579 @TestInfo()
3580 immutable test157 = q{--- test157
3581 	// Variadic template arg (3 args)
3582 	void fun[Args...](Args... args) {
3583 		#assert(Args.length == 3);
3584 	}
3585 	void run(){ fun(42, 4096, 200000); }
3586 };
3587 
3588 
3589 @TestInfo()
3590 immutable test158 = q{--- test158
3591 	// Variadic template arg, same instance (2 args)
3592 	void fun[Args...](Args... args) {
3593 		#assert(Args.length == 3);
3594 	}
3595 	void run(){
3596 		fun(42, 4096, 200000);
3597 		fun(50, 3000, 300000);
3598 	}
3599 };
3600 
3601 
3602 @TestInfo()
3603 immutable test159 = q{--- test159
3604 	// Variadic template arg, 2 different instances (2 args)
3605 	void fun[Args...](Args... args) {}
3606 	void run(){
3607 		fun(42, 4096);
3608 		fun(50, 3000, 300000);
3609 	}
3610 };
3611 
3612 
3613 @TestInfo()
3614 immutable test160 = q{--- test160
3615 	// Non-variadic + Variadic template arg
3616 	void fun[Args...](u8 par, Args... args) {
3617 		#assert(Args.length == 1);
3618 	}
3619 	void run(){ fun(42, 4096); }
3620 };
3621 
3622 
3623 @TestInfo()
3624 immutable test161 = q{--- test161
3625 	// Non-variadic + 0 Variadic template args
3626 	void fun[Args...](u8 par, Args... args) {
3627 		#assert(Args.length == 0);
3628 	}
3629 	void run(){ fun(42); }
3630 };
3631 
3632 
3633 @TestInfo()
3634 immutable test162 = q{--- test162
3635 	// Non-variadic + 0 Variadic template args
3636 	void fun[Args...](u8 par) {
3637 		#assert(Args.length == 0);
3638 	}
3639 	void run(){ fun(42); }
3640 };
3641 
3642 
3643 @TestInfo()
3644 immutable test163 = q{--- test163
3645 	// Non-variadic + 0 Variadic template args + default RT params
3646 	void fun[Args...](u8 par1, Args... args, u8 par2 = 50) {
3647 		#assert(Args.length == 0);
3648 	}
3649 	void run(){ fun(42); }
3650 };
3651 
3652 
3653 @TestInfo()
3654 immutable test164 = q{--- test164
3655 	// Non-variadic + 0 Variadic template args + non-default RT param
3656 	void fun[Args...](u8 par1, Args... args, u8 par2) {
3657 		#assert(Args.length == 0);
3658 	}
3659 	void run(){ fun(42, 50); }
3660 };
3661 
3662 
3663 @TestInfo()
3664 immutable test165 = q{--- test165
3665 	// Non-variadic + 1 Variadic template args + non-default RT param
3666 	void fun[Args...](u8 par1, Args... args, u8 par2) {
3667 		#assert(Args.length == 1);
3668 	}
3669 	void run(){ fun(42, 50, 60); }
3670 };
3671 
3672 
3673 @TestInfo()
3674 immutable test166 = q{--- test166
3675 	// Access variadic variable
3676 	i32 fun[Args...](Args... args) {
3677 		return args[0];
3678 	}
3679 	#assert(fun(42) == 42);
3680 };
3681 
3682 
3683 @TestInfo()
3684 immutable test167 = q{--- test167
3685 	// Access variadic variable
3686 	i32 fun[Args...](Args... args) {
3687 		alias arg0 = args[0];
3688 		alias T0 = Args[0];
3689 		T0 result = arg0;
3690 		return result;
3691 	}
3692 	#assert(fun(42) == 42);
3693 };
3694 
3695 
3696 @TestInfo()
3697 immutable test168 = q{--- test168
3698 	// #foreach
3699 	i64 fun[Args...](Args... args) {
3700 		i64 sum = 0;
3701 		#foreach(i, arg; args) {
3702 			sum += arg;
3703 		}
3704 		return sum;
3705 	}
3706 	#assert(fun(1, 2, 3) == 6);
3707 };
3708 
3709 
3710 @TestInfo(&tester169, [
3711 	HostSymbol("printStr", cast(void*)&external_print_string),
3712 	HostSymbol("printInt", cast(void*)&external_print_i64_func)])
3713 immutable test169 = q{--- test169
3714 	// #foreach with multiple statements
3715 	@extern(module, "host")
3716 	void printStr(u8[]);
3717 	@extern(module, "host")
3718 	void printInt(i64 i);
3719 	$alias selectPrintFunc($type T) {
3720 		if ($isInteger(T))
3721 			return printInt;
3722 		if ($isSlice(T))
3723 			return printStr;
3724 		$compileError("Invalid type");
3725 	}
3726 	void write[Args...](Args... args) {
3727 		#foreach(i, arg; args) {
3728 			alias func = selectPrintFunc(Args[i]);
3729 			func(arg);
3730 		}
3731 	}
3732 	void run() {
3733 		write("Hello", 42);
3734 	}
3735 };
3736 void tester169(ref TestContext ctx) {
3737 	auto run = ctx.getFunctionPtr!(void)("run");
3738 	run();
3739 	assert(testSink.text == "Hello42");
3740 }
3741 
3742 
3743 @TestInfo()
3744 immutable test170 = q{
3745 --- test170_1
3746 	// Use name from other module in func signature
3747 	import test170_2;
3748 	void fun(Struct s){}
3749 --- test170_2
3750 	struct Struct {}
3751 };
3752 
3753 
3754 @TestInfo()
3755 immutable test171 = q{
3756 --- test171
3757 	// Variadic function parameter (2 expanded parameters)
3758 	void fun[Args...](Args... args, Args... args2) {
3759 		#assert(Args.length == 1);
3760 	}
3761 	void run(){ fun(42); }
3762 --- <error>
3763 test171:2:38: Error: Cannot have two expanded parameters
3764 };
3765 
3766 
3767 //@TestInfo()
3768 //immutable test172 = q{--- test172
3769 //	// No parenths variadic call
3770 //	i64 fun[Args...](Args... args) {
3771 //		return 0;
3772 //	}
3773 //	#assert(fun == 0);
3774 //};
3775 
3776 
3777 @TestInfo()
3778 @(TargetOs.linux)
3779 immutable test173 = q{--- test173
3780 	// Extern attribute
3781 	@extern(syscall, 60)
3782 	void exit();
3783 	void run() {
3784 		exit();
3785 	}
3786 };
3787 
3788 
3789 @TestInfo()
3790 @(TargetOs.linux)
3791 immutable test174 = q{--- test174
3792 	// 2 Extern attributes
3793 	@extern(syscall, 60)
3794 	void exit();
3795 
3796 	// var attributes
3797 	@extern(syscall, 42)
3798 	u8 var;
3799 
3800 	// struct attribute
3801 	@extern(syscall, 1)
3802 	struct A {
3803 		// member var attribute
3804 		@extern(syscall, 2)
3805 		u8 var;
3806 
3807 		// member func attribute
3808 		@extern(syscall, 3)
3809 		void foo();
3810 	}
3811 };
3812 
3813 
3814 @TestInfo(&tester_float_1)
3815 immutable test_float_1 = q{--- test_float_1.vx
3816 	// floats negation
3817 	f32 neg_f32(f32 n) { return -n; }
3818 	f64 neg_f64(f64 n) { return -n; }
3819 };
3820 void tester_float_1(ref TestContext ctx) {
3821 	assert(ctx.getFunctionPtr!(float, float)("neg_f32")(2) == -2);
3822 	assert(ctx.getFunctionPtr!(double, double)("neg_f64")(2) == -2);
3823 }
3824 
3825 
3826 @TestInfo(&tester_float_2)
3827 immutable test_float_2 = q{--- test_float_2
3828 	// floats: arithmetics and comparisons
3829 	f32 f32_add(f32 a, f32 b) { return a + b; }
3830 	f64 f64_add(f64 a, f64 b) { return a + b; }
3831 	f32 f32_sub(f32 a, f32 b) { return a - b; }
3832 	f64 f64_sub(f64 a, f64 b) { return a - b; }
3833 	f32 f32_mul(f32 a, f32 b) { return a * b; }
3834 	f64 f64_mul(f64 a, f64 b) { return a * b; }
3835 	f32 f32_div(f32 a, f32 b) { return a / b; }
3836 	f64 f64_div(f64 a, f64 b) { return a / b; }
3837 	bool f32_lt(f32 a, f32 b) { return a < b; }
3838 	bool f64_lt(f64 a, f64 b) { return a < b; }
3839 	bool f32_le(f32 a, f32 b) { return a <= b; }
3840 	bool f64_le(f64 a, f64 b) { return a <= b; }
3841 	bool f32_eq(f32 a, f32 b) { return a == b; }
3842 	bool f64_eq(f64 a, f64 b) { return a == b; }
3843 	bool f32_ne(f32 a, f32 b) { return a != b; }
3844 	bool f64_ne(f64 a, f64 b) { return a != b; }
3845 	bool f32_gt(f32 a, f32 b) { return a > b; }
3846 	bool f64_gt(f64 a, f64 b) { return a > b; }
3847 	bool f32_ge(f32 a, f32 b) { return a >= b; }
3848 	bool f64_ge(f64 a, f64 b) { return a >= b; }
3849 };
3850 void tester_float_2(ref TestContext ctx) {
3851 	auto f32_add = ctx.getFunctionPtr!(float, float, float)("f32_add");
3852 	assert(f32_add(42, 100) == 42f + 100f);
3853 	auto f64_add = ctx.getFunctionPtr!(double, double, double)("f64_add");
3854 	assert(f64_add(42, 100) == 42.0 + 100.0);
3855 
3856 	auto f32_sub = ctx.getFunctionPtr!(float, float, float)("f32_sub");
3857 	assert(f32_sub(42, 100) == 42f - 100f);
3858 	auto f64_sub = ctx.getFunctionPtr!(double, double, double)("f64_sub");
3859 	assert(f64_sub(42, 100) == 42.0 - 100.0);
3860 
3861 	auto f32_mul = ctx.getFunctionPtr!(float, float, float)("f32_mul");
3862 	assert(f32_mul(42, 100) == 42f * 100f);
3863 	auto f64_mul = ctx.getFunctionPtr!(double, double, double)("f64_mul");
3864 	assert(f64_mul(42, 100) == 42.0 * 100.0);
3865 
3866 	auto f32_div = ctx.getFunctionPtr!(float, float, float)("f32_div");
3867 	assert(f32_div(42, 100) == 42f / 100f);
3868 	auto f64_div = ctx.getFunctionPtr!(double, double, double)("f64_div");
3869 	assert(f64_div(42, 100) == 42.0 / 100.0);
3870 
3871 	auto f32_lt = ctx.getFunctionPtr!(bool, float, float)("f32_lt");
3872 	assert(f32_lt(42, 42) == (42f < 42f));
3873 	assert(f32_lt(42, 100) == (42f < 100f));
3874 	assert(f32_lt(100, 42) == (100f < 42f));
3875 	assert(f32_lt(-100, -42) == (-100f < -42f));
3876 	auto f64_lt = ctx.getFunctionPtr!(bool, double, double)("f64_lt");
3877 	assert(f64_lt(42, 42) == (42.0 < 42.0));
3878 	assert(f64_lt(42, 100) == (42.0 < 100.0));
3879 	assert(f64_lt(100, 42) == (100.0 < 42.0));
3880 	assert(f64_lt(-100, -42) == (-100.0 < -42.0));
3881 
3882 	auto f32_le = ctx.getFunctionPtr!(bool, float, float)("f32_le");
3883 	assert(f32_le(42, 42) == (42f <= 42f));
3884 	assert(f32_le(42, 100) == (42f <= 100f));
3885 	assert(f32_le(100, 42) == (100f <= 42f));
3886 	assert(f32_le(-100, -42) == (-100f <= -42f));
3887 	auto f64_le = ctx.getFunctionPtr!(bool, double, double)("f64_le");
3888 	assert(f64_le(42, 42) == (42.0 <= 42.0));
3889 	assert(f64_le(42, 100) == (42.0 <= 100.0));
3890 	assert(f64_le(100, 42) == (100.0 <= 42.0));
3891 	assert(f64_le(-100, -42) == (-100.0 <= -42.0));
3892 
3893 	auto f32_eq = ctx.getFunctionPtr!(bool, float, float)("f32_eq");
3894 	assert(f32_eq(42, 42) == (42f == 42f));
3895 	assert(f32_eq(42, 100) == (42f == 100f));
3896 	assert(f32_eq(100, 42) == (100f == 42f));
3897 	assert(f32_eq(-100, -42) == (-100f == -42f));
3898 	auto f64_eq = ctx.getFunctionPtr!(bool, double, double)("f64_eq");
3899 	assert(f64_eq(42, 42) == (42.0 == 42.0));
3900 	assert(f64_eq(42, 100) == (42.0 == 100.0));
3901 	assert(f64_eq(100, 42) == (100.0 == 42.0));
3902 	assert(f64_eq(-100, -42) == (-100.0 == -42.0));
3903 
3904 	auto f32_ne = ctx.getFunctionPtr!(bool, float, float)("f32_ne");
3905 	assert(f32_ne(42, 42) == (42f != 42f));
3906 	assert(f32_ne(42, 100) == (42f != 100f));
3907 	assert(f32_ne(100, 42) == (100f != 42f));
3908 	assert(f32_ne(-100, -42) == (-100f != -42f));
3909 	auto f64_ne = ctx.getFunctionPtr!(bool, double, double)("f64_ne");
3910 	assert(f64_ne(42, 42) == (42.0 != 42.0));
3911 	assert(f64_ne(42, 100) == (42.0 != 100.0));
3912 	assert(f64_ne(100, 42) == (100.0 != 42.0));
3913 	assert(f64_ne(-100, -42) == (-100.0 != -42.0));
3914 
3915 	auto f32_gt = ctx.getFunctionPtr!(bool, float, float)("f32_gt");
3916 	assert(f32_gt(42, 42) == (42f > 42f));
3917 	assert(f32_gt(42, 100) == (42f > 100f));
3918 	assert(f32_gt(100, 42) == (100f > 42f));
3919 	assert(f32_gt(-100, -42) == (-100f > -42f));
3920 	auto f64_gt = ctx.getFunctionPtr!(bool, double, double)("f64_gt");
3921 	assert(f64_gt(42, 42) == (42.0 > 42.0));
3922 	assert(f64_gt(42, 100) == (42.0 > 100.0));
3923 	assert(f64_gt(100, 42) == (100.0 > 42.0));
3924 	assert(f64_gt(-100, -42) == (-100.0 > -42.0));
3925 
3926 	auto f32_ge = ctx.getFunctionPtr!(bool, float, float)("f32_ge");
3927 	assert(f32_ge(42, 42) == (42f >= 42f));
3928 	assert(f32_ge(42, 100) == (42f >= 100f));
3929 	assert(f32_ge(100, 42) == (100f >= 42f));
3930 	assert(f32_ge(-100, -42) == (-100f >= -42f));
3931 	auto f64_ge = ctx.getFunctionPtr!(bool, double, double)("f64_ge");
3932 	assert(f64_ge(42, 42) == (42.0 >= 42.0));
3933 	assert(f64_ge(42, 100) == (42.0 >= 100.0));
3934 	assert(f64_ge(100, 42) == (100.0 >= 42.0));
3935 	assert(f64_ge(-100, -42) == (-100.0 >= -42.0));
3936 }
3937 
3938 /*
3939 @TestInfo(&tester_float_3)
3940 immutable test_float_3 = q{--- test_float_3.vx
3941 	// floats compare with literal
3942 	bool f32_lt_l(f32 b) { return 0  < b; }
3943 	bool f64_lt_l(f64 b) { return 0  < b; }
3944 	bool f32_le_l(f32 b) { return 0 <= b; }
3945 	bool f64_le_l(f64 b) { return 0 <= b; }
3946 	bool f32_eq_l(f32 b) { return 0 == b; }
3947 	bool f64_eq_l(f64 b) { return 0 == b; }
3948 	bool f32_ne_l(f32 b) { return 0 != b; }
3949 	bool f64_ne_l(f64 b) { return 0 != b; }
3950 	bool f32_gt_l(f32 b) { return 0  > b; }
3951 	bool f64_gt_l(f64 b) { return 0  > b; }
3952 	bool f32_ge_l(f32 b) { return 0 >= b; }
3953 	bool f64_ge_l(f64 b) { return 0 >= b; }
3954 
3955 	bool f32_lt_r(f32 a) { return a  < 0; }
3956 	bool f64_lt_r(f64 a) { return a  < 0; }
3957 	bool f32_le_r(f32 a) { return a <= 0; }
3958 	bool f64_le_r(f64 a) { return a <= 0; }
3959 	bool f32_eq_r(f32 a) { return a == 0; }
3960 	bool f64_eq_r(f64 a) { return a == 0; }
3961 	bool f32_ne_r(f32 a) { return a != 0; }
3962 	bool f64_ne_r(f64 a) { return a != 0; }
3963 	bool f32_gt_r(f32 a) { return a  > 0; }
3964 	bool f64_gt_r(f64 a) { return a  > 0; }
3965 	bool f32_ge_r(f32 a) { return a >= 0; }
3966 	bool f64_ge_r(f64 a) { return a >= 0; }
3967 };
3968 void tester_float_3(ref TestContext ctx) {
3969 
3970 }*/
3971 
3972 
3973 @TestInfo(&tester_float_4)
3974 immutable test_float_4 = q{--- test_float_4
3975 	// floats: argument passing via stack and registers
3976 	f32 f32_add(f32 p1, f32 p2, f32 p3, f32 p4, f32 p5, f32 p6, f32 p7, f32 p8, f32 p9) {
3977 		return p1 + p2 + p3 + p4 + p5 + p6 + p7 + p8 + p9;
3978 	}
3979 	f64 f64_add(f64 p1, f64 p2, f64 p3, f64 p4, f64 p5, f64 p6, f64 p7, f64 p8, f64 p9) {
3980 		return p1 + p2 + p3 + p4 + p5 + p6 + p7 + p8 + p9;
3981 	}
3982 	f32 f32_call(f32 p1, f32 p2, f32 p3, f32 p4, f32 p5, f32 p6, f32 p7, f32 p8, f32 p9) {
3983 		return f32_add(p1, p2, p3, p4, p5, p6, p7, p8, p9);
3984 	}
3985 	f64 f64_call(f64 p1, f64 p2, f64 p3, f64 p4, f64 p5, f64 p6, f64 p7, f64 p8, f64 p9) {
3986 		return f64_add(p1, p2, p3, p4, p5, p6, p7, p8, p9);
3987 	}
3988 };
3989 void tester_float_4(ref TestContext ctx) {
3990 	auto f32_add = ctx.getFunctionPtr!(float, float, float, float, float, float, float, float, float, float)("f32_add");
3991 	assert(f32_add(1, 2, 3, 4, 5, 6, 7, 8, 9) == 1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9);
3992 	auto f64_add = ctx.getFunctionPtr!(double, double, double, double, double, double, double, double, double, double)("f64_add");
3993 	assert(f64_add(1, 2, 3, 4, 5, 6, 7, 8, 9) == 1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9);
3994 	auto f32_call = ctx.getFunctionPtr!(float, float, float, float, float, float, float, float, float, float)("f32_call");
3995 	assert(f32_call(1, 2, 3, 4, 5, 6, 7, 8, 9) == 1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9);
3996 	auto f64_call = ctx.getFunctionPtr!(double, double, double, double, double, double, double, double, double, double)("f64_call");
3997 	assert(f64_call(1, 2, 3, 4, 5, 6, 7, 8, 9) == 1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9);
3998 }
3999 
4000 
4001 @TestInfo(&tester177)
4002 immutable test177 = q{--- test177
4003 	f64 func_f32_to_f64(f32 a) { return a; } // f32 -> f64
4004 	f32 func_f64_to_f32(f64 a) { return cast(f32)a; } // f64 -> f32
4005 
4006 	f32 func_f32_zero1() { return 0; }
4007 	f64 func_f64_zero1() { return 0; }
4008 	f32 func_f32_zero2() { return 0.0; }
4009 	f64 func_f64_zero2() { return 0.0; }
4010 	f32 func_f32_const() { return 0.5; }
4011 	f64 func_f64_const() { return 0.5; }
4012 
4013 	f32 func_f32_const_mult(f32 a) { return a * cast(f32)0.5; }
4014 	f64 func_f64_const_mult(f64 a) { return a * 0.5; }
4015 
4016 	f32 func_const_f32_mult(f32 a) { return cast(f32)0.5 * a; }
4017 	f64 func_const_f64_mult(f64 a) { return 0.5 * a; }
4018 
4019 	 i8 func_f32_to__i8(f32 a) { return a; } // f32 ->  i8
4020 	i16 func_f32_to_i16(f32 a) { return a; } // f32 -> i16
4021 	i32 func_f32_to_i32(f32 a) { return a; } // f32 -> i32
4022 	i64 func_f32_to_i64(f32 a) { return a; } // f32 -> i64
4023 
4024 	 u8 func_f32_to__u8(f32 a) { return a; } // f32 ->  u8
4025 	u16 func_f32_to_u16(f32 a) { return a; } // f32 -> u16
4026 	u32 func_f32_to_u32(f32 a) { return a; } // f32 -> u32
4027 	u64 func_f32_to_u64(f32 a) { return a; } // f32 -> u64 // TODO: more precise conversion
4028 
4029 	 i8 func_f64_to__i8(f64 a) { return a; } // f64 ->  i8
4030 	i16 func_f64_to_i16(f64 a) { return a; } // f64 -> i16
4031 	i32 func_f64_to_i32(f64 a) { return a; } // f64 -> i32
4032 	i64 func_f64_to_i64(f64 a) { return a; } // f64 -> i64
4033 
4034 	 u8 func_f64_to__u8(f64 a) { return a; } // f64 ->  u8
4035 	u16 func_f64_to_u16(f64 a) { return a; } // f64 -> u16
4036 	u32 func_f64_to_u32(f64 a) { return a; } // f64 -> u32
4037 	u64 func_f64_to_u64(f64 a) { return a; } // f64 -> u64 // TODO: more precise conversion
4038 
4039 	f32 func__i8_to_f32( i8 a) { return a; } //  i8 -> f32
4040 	f32 func_i16_to_f32(i16 a) { return a; } // i16 -> f32
4041 	f32 func_i32_to_f32(i32 a) { return a; } // i32 -> f32
4042 	f32 func_i64_to_f32(i64 a) { return a; } // i64 -> f32
4043 
4044 	f32 func__u8_to_f32( u8 a) { return a; } //  u8 -> f32
4045 	f32 func_u16_to_f32(u16 a) { return a; } // u16 -> f32
4046 	f32 func_u32_to_f32(u32 a) { return a; } // u32 -> f32
4047 	f32 func_u64_to_f32(u64 a) { return a; } // u64 -> f32 // TODO: more precise conversion
4048 
4049 	f64 func__i8_to_f64( i8 a) { return a; } //  i8 -> f64
4050 	f64 func_i16_to_f64(i16 a) { return a; } // i16 -> f64
4051 	f64 func_i32_to_f64(i32 a) { return a; } // i32 -> f64
4052 	f64 func_i64_to_f64(i64 a) { return a; } // i64 -> f64
4053 
4054 	f64 func__u8_to_f64( u8 a) { return a; } //  u8 -> f64
4055 	f64 func_u16_to_f64(u16 a) { return a; } // u16 -> f64
4056 	f64 func_u32_to_f64(u32 a) { return a; } // u32 -> f64
4057 	f64 func_u64_to_f64(u64 a) { return a; } // u64 -> f64 // TODO: more precise conversion
4058 };
4059 void tester177(ref TestContext ctx) {
4060 	assert(ctx.getFunctionPtr!(double,  float)("func_f32_to_f64")(42.54f) == 42.54f.force);
4061 	assert(ctx.getFunctionPtr!(float,  double)("func_f64_to_f32")(42.54) == 42.54f.force);
4062 
4063 	assert(ctx.getFunctionPtr!(float)("func_f32_zero1")() == 0f.force);
4064 	assert(ctx.getFunctionPtr!(double)("func_f64_zero1")() == 0);
4065 	assert(ctx.getFunctionPtr!(float)("func_f32_zero2")() == 0f.force);
4066 	assert(ctx.getFunctionPtr!(double)("func_f64_zero2")() == 0);
4067 	assert(ctx.getFunctionPtr!(float)("func_f32_const")() == 0.5f.force);
4068 	assert(ctx.getFunctionPtr!(double)("func_f64_const")() == 0.5);
4069 
4070 	assert(ctx.getFunctionPtr!(float, float)("func_f32_const_mult")(1) == 0.5f.force);
4071 	assert(ctx.getFunctionPtr!(double, double)("func_f64_const_mult")(1) == 0.5);
4072 
4073 	assert(ctx.getFunctionPtr!(float, float)("func_const_f32_mult")(1) == 0.5f.force);
4074 	assert(ctx.getFunctionPtr!(double, double)("func_const_f64_mult")(1) == 0.5);
4075 
4076 	assert(ctx.getFunctionPtr!(  byte,  float)("func_f32_to__i8")(-127.6f.force) == -127);
4077 	assert(ctx.getFunctionPtr!( short,  float)("func_f32_to_i16")(-127.6f.force) == -127);
4078 	assert(ctx.getFunctionPtr!(   int,  float)("func_f32_to_i32")(-127.6f.force) == -127);
4079 	assert(ctx.getFunctionPtr!(  long,  float)("func_f32_to_i64")(-127.6f.force) == -127);
4080 	assert(ctx.getFunctionPtr!( ubyte,  float)("func_f32_to__u8")(255.6f.force) == 255);
4081 	assert(ctx.getFunctionPtr!(ushort,  float)("func_f32_to_u16")(255.6f.force) == 255);
4082 	assert(ctx.getFunctionPtr!(  uint,  float)("func_f32_to_u32")(255.6f.force) == 255);
4083 	assert(ctx.getFunctionPtr!( ulong,  float)("func_f32_to_u64")(255.6f.force) == 255);
4084 
4085 	assert(ctx.getFunctionPtr!(  byte, double)("func_f64_to__i8")(-127.6.force) == -127);
4086 	assert(ctx.getFunctionPtr!( short, double)("func_f64_to_i16")(-127.6.force) == -127);
4087 	assert(ctx.getFunctionPtr!(   int, double)("func_f64_to_i32")(-127.6.force) == -127);
4088 	assert(ctx.getFunctionPtr!(  long, double)("func_f64_to_i64")(-127.6.force) == -127);
4089 	assert(ctx.getFunctionPtr!( ubyte, double)("func_f64_to__u8")(255.6.force) == 255);
4090 	assert(ctx.getFunctionPtr!(ushort, double)("func_f64_to_u16")(255.6.force) == 255);
4091 	assert(ctx.getFunctionPtr!(  uint, double)("func_f64_to_u32")(255.6.force) == 255);
4092 	assert(ctx.getFunctionPtr!( ulong, double)("func_f64_to_u64")(255.6.force) == 255);
4093 
4094 	assert(ctx.getFunctionPtr!( float,   byte)("func__i8_to_f32")(-127) == -127.0f.force);
4095 	assert(ctx.getFunctionPtr!( float,  short)("func_i16_to_f32")(-127) == -127.0f.force);
4096 	assert(ctx.getFunctionPtr!( float,    int)("func_i32_to_f32")(-127) == -127.0f.force);
4097 	assert(ctx.getFunctionPtr!( float,   long)("func_i64_to_f32")(-127) == -127.0f.force);
4098 	assert(ctx.getFunctionPtr!( float,  ubyte)("func__u8_to_f32")(127) == 127.0f.force);
4099 	assert(ctx.getFunctionPtr!( float, ushort)("func_u16_to_f32")(127) == 127.0f.force);
4100 	assert(ctx.getFunctionPtr!( float,   uint)("func_u32_to_f32")(127) == 127.0f.force);
4101 	assert(ctx.getFunctionPtr!( float,  ulong)("func_u64_to_f32")(127) == 127.0f.force);
4102 
4103 	assert(ctx.getFunctionPtr!(double,   byte)("func__i8_to_f64")(-127) == -127.0);
4104 	assert(ctx.getFunctionPtr!(double,  short)("func_i16_to_f64")(-127) == -127.0);
4105 	assert(ctx.getFunctionPtr!(double,    int)("func_i32_to_f64")(-127) == -127.0);
4106 	assert(ctx.getFunctionPtr!(double,   long)("func_i64_to_f64")(-127) == -127.0);
4107 	assert(ctx.getFunctionPtr!(double,  ubyte)("func__u8_to_f64")(127) == 127.0);
4108 	assert(ctx.getFunctionPtr!(double, ushort)("func_u16_to_f64")(127) == 127.0);
4109 	assert(ctx.getFunctionPtr!(double,   uint)("func_u32_to_f64")(127) == 127.0);
4110 	assert(ctx.getFunctionPtr!(double,  ulong)("func_u64_to_f64")(127) == 127.0);
4111 }
4112 
4113 
4114 @TestInfo(&tester178)
4115 immutable test178 = q{--- test178
4116 	struct Result { i32 sum; i32 maxflips; }
4117 	// https://benchmarksgame-team.pages.debian.net/benchmarksgame/description/fannkuchredux.html
4118 	Result fannkuch(i32 n) {
4119 		i32 signx;
4120 		i32 maxflips;
4121 		i32 sum;
4122 		i32 i;
4123 		i32 j;
4124 		i32 k;
4125 		i32 q1;
4126 		i32 flips;
4127 		i32 qq;
4128 		i32 t;
4129 		i32 sx;
4130 		i32 tt;
4131 		i32[100] p;
4132 		i32[100] q;
4133 		i32[100] s;
4134 
4135 		signx = 1;
4136 		maxflips = 0;
4137 		sum = 0;
4138 		for (i=1; i<=n; ++i) {
4139 			p[i-1] = i;
4140 			q[i-1] = i;
4141 			s[i-1] = i;
4142 		}
4143 		while (true) {
4144 			q1 = p[1-1];
4145 			if (q1 != 1) {
4146 				for (i=2; i<=n; ++i) {
4147 					q[i-1] = p[i-1];
4148 				}
4149 				flips = 1;
4150 				while (true) {
4151 					qq = q[q1-1];
4152 					if (qq == 1) {
4153 						sum += signx*flips;
4154 						if (flips > maxflips) {
4155 							maxflips = flips;
4156 						}
4157 						break;
4158 					}
4159 					q[q1-1] = q1;
4160 					if (q1 >= 4) {
4161 						i = 2;
4162 						j = q1-1;
4163 						while (true) {
4164 							{
4165 								i32 temp = q[i-1];
4166 								q[i-1] = q[j-1];
4167 								q[j-1] = temp;
4168 							}
4169 							++i;
4170 							--j;
4171 							if (i >= j) break;
4172 						}
4173 					}
4174 					q1 = qq;
4175 					++flips;
4176 				}
4177 			}
4178 			if (signx == 1) {
4179 				{
4180 					i32 temp = p[2-1];
4181 					p[2-1] = p[1-1];
4182 					p[1-1] = temp;
4183 				}
4184 				signx = -1;
4185 			}
4186 			else {
4187 				{
4188 					i32 temp = p[2-1];
4189 					p[2-1] = p[3-1];
4190 					p[3-1] = temp;
4191 				}
4192 				signx = 1;
4193 				for (i=3; i<=n; ++i) {
4194 					sx = s[i-1];
4195 					if (sx != 1) {
4196 						s[i-1] = sx-1;
4197 						break;
4198 					}
4199 					if (i == n) {
4200 						return Result(sum, maxflips);
4201 					}
4202 					s[i-1] = i;
4203 					tt = p[1-1];
4204 					for (j=1; j<=i; ++j) {
4205 						p[j-1] = p[j+1-1];
4206 					}
4207 					p[i+1-1] = tt;
4208 				}
4209 			}
4210 		}
4211 	}
4212 };
4213 void tester178(ref TestContext ctx) {
4214 	static struct Result { int sum; int maxflips; }
4215 	auto fannkuch = ctx.getFunctionPtr!(Result, int)("fannkuch");
4216 	assert(fannkuch(3) == Result(2, 2));
4217 	//assert(fannkuch(11) == Result(556355, 51)); // slow: ~2s
4218 }
4219 
4220 /*
4221 // aggregate lowering bug
4222 @TestInfo(&tester179)
4223 immutable test179 = q{--- test179
4224 	void use(i64, i64){}
4225 	// floats: argument passing via stack and registers
4226 	u8[] decompress(i32 res, u8[] data, u8[] outBuffer)
4227 	{
4228 		//i32 res = LZ4_decompress_safe(data.ptr, outBuffer.ptr, cast(i32)data.length, cast(i32)outBuffer.length);
4229 		if (res < 0)
4230 		{
4231 			use(cast(i64)data.length, cast(i64)outBuffer.length);
4232 			return null;
4233 		}
4234 		return outBuffer[0..res];
4235 	}
4236 };
4237 void tester179(ref TestContext ctx) {
4238 }
4239 */
4240 
4241 @TestInfo()
4242 // empty source
4243 immutable test180 = q{--- test180};
4244 
4245 
4246 @TestInfo()
4247 immutable test181 = q{--- test181
4248 	// alias as enum type
4249 	alias ENetSocketType = i32;
4250 	enum : ENetSocketType
4251 	{
4252 		ENET_SOCKET_TYPE_STREAM   = 1,
4253 		ENET_SOCKET_TYPE_DATAGRAM = 2,
4254 	}
4255 };
4256 
4257 
4258 @TestInfo()
4259 immutable test182 = q{--- test182
4260 	// store {{}*, i8}* s0, {{}*, i8} {zeroinit, 1}
4261 	// isSameType gets to compare pointers to different structs, with different number of members
4262 	Struct run1() {
4263 		return Struct();
4264 	}
4265 	void run2() {
4266 		Struct s;
4267 	}
4268 	struct GLFWwindow;
4269 	struct Struct {
4270 		GLFWwindow* window;
4271 		bool isRunning = true;
4272 	}
4273 };
4274 
4275 
4276 @TestInfo(&tester183)
4277 immutable test183 = q{--- test183
4278 	// operations on enum types
4279 	enum F : u32 {
4280 		f1 = 0b01,
4281 		f2 = 0b10,
4282 	}
4283 	u32 run1() {
4284 		return F.f1 | F.f2;
4285 	}
4286 	F run2() {
4287 		return F.f1 | F.f2;
4288 	}
4289 	F run3(F a, F b) {
4290 		return a | b;
4291 	}
4292 	F run4(F a) {
4293 		return ~a;
4294 	}
4295 };
4296 void tester183(ref TestContext ctx) {
4297 	assert(ctx.getFunctionPtr!(uint)("run1")() == 3);
4298 	assert(ctx.getFunctionPtr!(uint)("run2")() == 3);
4299 	assert(ctx.getFunctionPtr!(uint, uint, uint)("run3")(1, 2) == 3);
4300 	assert(ctx.getFunctionPtr!(uint, uint)("run4")(1) == ~1);
4301 }
4302 
4303 
4304 // packages
4305 @TestInfo()
4306 immutable test184 = q{--- test184/mod1.vx
4307 	module test184.mod1;
4308 --- test184/mod2.vx
4309 	module test184.mod2;
4310 };
4311 
4312 
4313 @TestInfo()
4314 immutable test185 = q{--- test185/mod1.vx
4315 	module test185.mod1;
4316 --- test185/mod2.vx
4317 	module mod2;
4318 };
4319 
4320 
4321 @TestInfo(&tester186)
4322 immutable test186 = q{--- test186/mod1.vx
4323 	module test186.mod1;
4324 	i32 test() { return 42; }
4325 --- test186/mod2.vx
4326 	module test186.mod2;
4327 	import test186.mod1;
4328 	i32 run() { return test(); }
4329 };
4330 void tester186(ref TestContext ctx) {
4331 	assert(ctx.getFunctionPtr!(uint)("run")() == 42);
4332 }
4333 
4334 @TestInfo()
4335 immutable test187 = q{--- test187
4336 	// lexer bug with leading underscore
4337 	i32 _import;
4338 	i32 _module;
4339 };
4340 
4341 
4342 @TestInfo()
4343 immutable test188 = q{--- test188
4344 	// Union
4345 	union VkClearColorValue {
4346 		f32[4]  float32;
4347 		i32[4]  int32;
4348 		u32[4]  uint32;
4349 	}
4350 	VkClearColorValue getf32(f32[4] val) {
4351 		VkClearColorValue result;
4352 		result.float32 = val;
4353 		return result;
4354 	}
4355 	VkClearColorValue geti32(i32[4] val) {
4356 		VkClearColorValue result;
4357 		result.int32 = val;
4358 		return result;
4359 	}
4360 	VkClearColorValue getu32(u32[4] val) {
4361 		VkClearColorValue result;
4362 		result.uint32 = val;
4363 		return result;
4364 	}
4365 };
4366 
4367 
4368 @TestInfo(&tester189)
4369 immutable test189 = q{--- test189
4370 	// Call function pointer in member variable
4371 	i32 get42(){ return 42; }
4372 	struct DispatchDevice {
4373 		i32 DestroyDevice() { return vkDestroyDevice(); }
4374 		i32 function() vkDestroyDevice = &get42;
4375 	}
4376 	i32 run() {
4377 		DispatchDevice dev;
4378 		return dev.DestroyDevice();
4379 	}
4380 };
4381 void tester189(ref TestContext ctx) {
4382 	assert(ctx.getFunctionPtr!(int)("run")() == 42);
4383 }
4384 
4385 
4386 @TestInfo()
4387 immutable test190 = q{--- test190
4388 	// Null enum initializer
4389 	enum VK_NULL_HANDLE = null;
4390 	void* run() { return VK_NULL_HANDLE; }
4391 };
4392 
4393 
4394 @TestInfo()
4395 immutable test191 = q{--- test191
4396 	// Unary op eval
4397 	enum VK_ATTACHMENT_UNUSED = (~0);
4398 };
4399 
4400 
4401 @TestInfo(&tester192)
4402 immutable test192 = q{--- test192
4403 	// Default value of enum
4404 	enum VkStructureType {
4405 		VK_STRUCTURE_TYPE_APPLICATION_INFO     = 0,
4406 		VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO = 1,
4407 	}
4408 	struct VkBaseInStructure {
4409 		VkStructureType     sType; // enum default value is needed
4410 		VkBaseInStructure*  pNext; // recursive type
4411 	}
4412 	VkStructureType run() {
4413 		VkBaseInStructure s;
4414 		return s.sType;
4415 	}
4416 };
4417 void tester192(ref TestContext ctx) {
4418 	enum VkStructureType {
4419 		VK_STRUCTURE_TYPE_APPLICATION_INFO     = 0,
4420 		VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO = 1,
4421 	}
4422 	assert(ctx.getFunctionPtr!(VkStructureType)("run")() == VkStructureType.VK_STRUCTURE_TYPE_APPLICATION_INFO);
4423 }
4424 
4425 @TestInfo()
4426 immutable test193 = q{--- test193
4427 	// circular dependency on enum type
4428 	VkStructureType sType = VkStructureType.VK_STRUCTURE_TYPE_APPLICATION_INFO;
4429 	enum VkStructureType {
4430 		VK_STRUCTURE_TYPE_APPLICATION_INFO = 0,
4431 	}
4432 };
4433 
4434 
4435 @TestInfo(&tester194)
4436 immutable test194 = q{--- test194
4437 	// #version
4438 	#version(windows) {
4439 		i32 run() { return 1; }
4440 	}
4441 	else #version(linux) {
4442 		i32 run() { return 2; }
4443 	}
4444 	else #version(macos) {
4445 		i32 run() { return 3; }
4446 	}
4447 	else #assert(false, "Unsupported OS");
4448 };
4449 void tester194(ref TestContext ctx) {
4450 	     version(Windows) int result = 1;
4451 	else version(linux)   int result = 2;
4452 	else version(OSX)     int result = 3;
4453 	assert(ctx.getFunctionPtr!int("run")() == result);
4454 }
4455 
4456 
4457 @TestInfo()
4458 immutable test195 = q{--- test195
4459 	// Circular deps on enum type
4460 	bool run() {
4461 		VkResult result;
4462 		return result != VkResult.VK_SUCCESS;
4463 	}
4464 	enum VkResult {
4465 		VK_SUCCESS = 0
4466 	}
4467 };
4468 
4469 
4470 @TestInfo()
4471 immutable test196 = q{--- test196
4472 	u8*[] var;
4473 };
4474 
4475 
4476 @TestInfo()
4477 immutable test197 = q{--- test197
4478 	void run() {
4479 		u8* ptr;
4480 		foo(ptr);
4481 	}
4482 	void foo(void*){}
4483 };
4484 
4485 /*
4486 @TestInfo()
4487 immutable test198 = q{--- test198
4488 	// TODO: Need to either deduplicate types, or special code for == on types, or $sameType
4489 	bool isU8Ptr($type type) {
4490 		return type == u8*;
4491 	}
4492 	#assert(isU8Ptr(u8*));
4493 };
4494 */
4495 
4496 @TestInfo(&tester199)
4497 immutable test199 = q{--- test199
4498 	alias i32_funType = i32 function();
4499 	enum i32_funType funPtrEnum = &i32Fun;
4500 	i32 i32Fun() { return 42; }
4501 	i32 test2() {
4502 		return funPtrEnum();
4503 	}
4504 };
4505 void tester199(ref TestContext ctx) {
4506 	assert(ctx.getFunctionPtr!(int)("test2")() == 42);
4507 }
4508 
4509 
4510 @TestInfo()
4511 immutable test200 = q{--- test200
4512 	// Common type between enum and u32
4513 	enum MDBX_env_flags_t : u32 {
4514 		MDBX_SAFE_NOSYNC = 0x10000,
4515 		MDBX_MAPASYNC = MDBX_SAFE_NOSYNC,
4516 		MDBX_UTTERLY_NOSYNC = MDBX_SAFE_NOSYNC | 0x100000,
4517 	}
4518 };
4519 
4520 
4521 @TestInfo()
4522 immutable test201 = q{--- test201
4523 	// Enum of structs
4524 	enum Colors : Color {
4525 		UNEXPLORED = Color(0, 0, 0),
4526 		DARK_WALL = Color(0, 0, 100),
4527 	}
4528 	struct Color {
4529 		u8 r;
4530 		u8 g;
4531 		u8 b;
4532 	}
4533 	// Cast from enum to base struct
4534 	Color color = Colors.DARK_WALL;
4535 };
4536 
4537 
4538 @TestInfo()
4539 immutable test202 = q{--- test202
4540 	// aggregate lowering with phi function (two paths that return a big struct) and phi has constant argument
4541 	u8[] fromStringz(u8* cString, u64 len) {
4542 		if (cString == null) return null;
4543 		return cString[0..len];
4544 	}
4545 };
4546 
4547 
4548 @TestInfo()
4549 immutable test203 = q{--- test203
4550 	// String literal to u8* in ctfe
4551 	u8* ptr = "hello";
4552 	struct TracyLoc {
4553 		u8* name;
4554 		u8* func;
4555 		u8* file;
4556 		u32 line;
4557 		u32 color;
4558 	}
4559 	TracyLoc zone_loc = TracyLoc("Zonename", "update", "main.vx", 81, 0xFF00FF);
4560 };
4561 
4562 
4563 @TestInfo()
4564 immutable test204 = q{--- test204
4565 	// aggregate lowering
4566 	struct A {
4567 		i32 val1;
4568 		i32 val2;
4569 	}
4570 	A run(A res, bool cond, i32 val) {
4571 		if (cond) res.val1 = val;
4572 		return res;
4573 	}
4574 };
4575 
4576 
4577 @TestInfo(&tester205)
4578 immutable test205 = q{--- test205
4579 	// aggregate lowering
4580 	struct Struct {
4581 		i32 member;
4582 		void set42() {
4583 			this.member += 42;
4584 			member = 42;
4585 		}
4586 	}
4587 	i32 testMethod5() {
4588 		Struct[1] s;
4589 		s[0].set42;
4590 		return s[0].member;
4591 	}
4592 };
4593 void tester205(ref TestContext ctx) {
4594 	assert(ctx.getFunctionPtr!(int)("testMethod5")() == 42);
4595 }
4596 
4597 
4598 @TestInfo()
4599 immutable test206 = q{--- test206
4600 	//
4601 	struct Tile {
4602 		bool blocked;
4603 		bool block_sight;
4604 	}
4605 
4606 	struct GameMap {
4607 		enum map_width = 40;
4608 		enum map_height = 40;
4609 		Tile[40] tiles;
4610 	}
4611 
4612 	void initialize_tiles(Tile[40]* map, i32 x) {
4613 		(*map)[x].block_sight = true;
4614 	}
4615 	void initialize_tiles2(i32 x) {
4616 		Tile[40] map;
4617 		map[x].block_sight = true;
4618 	}
4619 };
4620 
4621 
4622 @TestInfo(&tester207)
4623 immutable test207 = q{--- test207
4624 	// aggregate lowering
4625 	u8[] fromStringz(u8* cString) {
4626 		if (cString == null) return null;
4627 		u8* cursor = cString;
4628 		while(*cursor) ++cursor;
4629 		u64 length = cast(u64)(cursor - cString);
4630 		return cString[0..length];
4631 	}
4632 };
4633 void tester207(ref TestContext ctx) {
4634 	assert(ctx.getFunctionPtr!(Slice!(const(char)), const(char)*)("fromStringz")("test") == "test");
4635 }
4636 
4637 
4638 @TestInfo(&tester208, [HostSymbol("print", cast(void*)&test208_print)])
4639 immutable test208 = q{--- test208
4640 	// bug. Could not encode 32-bit offset because static data sections were too big.
4641 	void run() {
4642 		print("0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000");
4643 		print("1111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111");
4644 		print("2222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222");
4645 		print("3333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333");
4646 		print("4444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444");
4647 		print("5555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555");
4648 		print("6666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666");
4649 		print("7777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777");
4650 		print("8888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888");
4651 		print("9999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999");
4652 		print("AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA");
4653 		print("BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB");
4654 		print("CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC");
4655 		print("DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD");
4656 		print("EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE");
4657 		print("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF");
4658 	}
4659 	@extern(module, "host")
4660 	void print(u8[]);
4661 };
4662 extern(C) void test208_print(SliceString str) {
4663 	testSink.put(str.slice);
4664 }
4665 void tester208(ref TestContext ctx) {
4666 	ctx.getFunctionPtr!(void)("run")();
4667 	assert(testSink.text ==
4668 		"0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"~
4669 		"1111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111"~
4670 		"2222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222"~
4671 		"3333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333"~
4672 		"4444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444"~
4673 		"5555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555"~
4674 		"6666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666"~
4675 		"7777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777"~
4676 		"8888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888"~
4677 		"9999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999"~
4678 		"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"~
4679 		"BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB"~
4680 		"CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC"~
4681 		"DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD"~
4682 		"EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE"~
4683 		"FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF");
4684 }
4685 
4686 
4687 @TestInfo()
4688 immutable test209 = q{--- test209
4689 	//
4690 	$alias selectPrintFunc($type T) {
4691 		return printInt;
4692 	}
4693 	void printInt() {
4694 		print("res");
4695 	}
4696 	void print[Args...](Args... args) {
4697 		alias func = selectPrintFunc(u8[]);
4698 		func();
4699 	}
4700 };
4701 
4702 
4703 @TestInfo(&tester210)
4704 immutable test210 = q{--- test210
4705 	// struct size with forward reference
4706 	u64 run() { return VkExtensionProperties.sizeof; } // 260
4707 
4708 	VkExtensionProperties[11] extensions;
4709 	struct VkExtensionProperties {
4710 		u8[256] extensionName;
4711 		u32 specVersion;
4712 	}
4713 };
4714 void tester210(ref TestContext ctx) {
4715 	assert(ctx.getFunctionPtr!(ulong)("run")() == 260);
4716 }
4717 
4718 
4719 @TestInfo(&tester211)
4720 immutable test211 = q{--- test211
4721 	// code gen of `add reg global`
4722 	VkExtensionProperties[11] extensions;
4723 	struct VkExtensionProperties {
4724 		u8[256] extensionName;
4725 	}
4726 	u8* get(i32 i) {
4727 		return extensions[i].extensionName.ptr;
4728 	}
4729 };
4730 void tester211(ref TestContext ctx) {
4731 	auto get = ctx.getFunctionPtr!(ubyte*, int)("get");
4732 	void* arenaPtr = ctx.driver.context.staticDataBuffer.bufPtr;
4733 	assert(get(1) - get(0) == 256);
4734 	assert(get(0) == arenaPtr);
4735 	assert(get(1) == arenaPtr + 256);
4736 }
4737 
4738 
4739 @TestInfo()
4740 immutable test212 = q{--- test212
4741 	// Forward reference for variable init value -> enum init value -> enum member init value
4742 	VkQueryType queryType;
4743 	enum VkQueryType {
4744 		VK_QUERY_TYPE_OCCLUSION = 0,
4745 	}
4746 };
4747 
4748 
4749 /*@TestInfo()
4750 immutable test213 = q{--- test213
4751 	// Recursive type
4752 	struct Qq
4753 	{
4754 		i32[Qq.sizeof]* a;
4755 	}
4756 };*/
4757 
4758 
4759 @TestInfo(&tester214)
4760 immutable test214 = q{--- test214
4761 	// code gen of add rax, imm32 generated add eax, imm32
4762 	VkExtensionProperties[11] extensions;
4763 	struct VkExtensionProperties {
4764 		u8[256] extensionName;
4765 		u32 specVersion;
4766 	}
4767 	void* get(i32 i) {
4768 		return &extensions[i].specVersion;
4769 	}
4770 };
4771 void tester214(ref TestContext ctx) {
4772 	auto get = ctx.getFunctionPtr!(void*, int)("get");
4773 	void* arenaPtr = ctx.driver.context.staticDataBuffer.bufPtr;
4774 	void* ptr = get(0);
4775 
4776 	assert(ptr == arenaPtr + 256);
4777 	assert(get(1) - get(0) == 260);
4778 }
4779 
4780 
4781 @TestInfo()
4782 immutable test215 = q{--- test215
4783 	// UFCS for ptr type
4784 	VkExtensionProperties[11] extensions;
4785 	struct VkExtensionProperties {
4786 		u8[256] extensionName;
4787 		u32 specVersion;
4788 	}
4789 	void run() {
4790 		extensions[0].extensionName.ptr.fromStringz;
4791 	}
4792 	void fromStringz(u8*){}
4793 };
4794 
4795 
4796 @TestInfo()
4797 immutable test216 = q{--- test216
4798 	// $baseOf
4799 	#assert($baseOf(u8[]) == u8);
4800 	#assert($baseOf(u8*) == u8);
4801 	#assert($baseOf(u8[10]) == u8);
4802 	#assert($baseOf(u16[10]) != u8);
4803 };
4804 
4805 
4806 @TestInfo()
4807 immutable test217 = q{--- test217
4808 	// doIfti missing ref on AstNodes, causing UFCS call that replaced node to use stale array
4809 	struct VkLayerProperties {
4810 		u8[1] description;
4811 	}
4812 	u8[] fromStringz(u8* cString) { return null; }
4813 	void println[Args...](Args... args) {}
4814 	void run() {
4815 		VkLayerProperties layer;
4816 		println(layer.description.ptr.fromStringz);
4817 		println("", layer.description.ptr.fromStringz);
4818 	}
4819 };
4820 
4821 @TestInfo(&tester218)
4822 immutable test218 = q{--- test218
4823 	// indexing of call
4824 	struct App {
4825 		u8*[1] validationLayers;
4826 		void init() {
4827 			validationLayers[0] = "VK_LAYER_KHRONOS_validation";
4828 		}
4829 		u8** get() {
4830 			return validationLayers.ptr;
4831 		}
4832 	}
4833 	u8* run() {
4834 		App app;
4835 		app.init;
4836 		return app.get()[0];
4837 	}
4838 };
4839 void tester218(ref TestContext ctx) {
4840 	import std.string : fromStringz;
4841 	auto run = ctx.getFunctionPtr!(char*)("run");
4842 	assert(run().fromStringz == "VK_LAYER_KHRONOS_validation");
4843 }
4844 
4845 @TestInfo(&tester219)
4846 immutable test219 = q{--- test219
4847 	// Assigning struct member array
4848 	struct S {
4849 		u8** ptr;
4850 	}
4851 	struct App {
4852 		u8*[1] validationLayers;
4853 		void init() {
4854 			validationLayers[0] = "VK_LAYER_KHRONOS_validation"; // here
4855 		}
4856 		S get() {
4857 			return S(validationLayers.ptr); // also test access via .ptr
4858 		}
4859 	}
4860 	S run() {
4861 		App app;
4862 		app.init;
4863 		return app.get();
4864 	}
4865 };
4866 void tester219(ref TestContext ctx) {
4867 	import std.string : fromStringz;
4868 	auto run = ctx.getFunctionPtr!(char**)("run");
4869 	assert((*run()).fromStringz == "VK_LAYER_KHRONOS_validation");
4870 }
4871 
4872 
4873 @TestInfo(&tester220)
4874 immutable test220 = q{--- test220
4875 	// slicing of static array bug
4876 	struct App {
4877 		u8*[1] validationLayers;
4878 		void init() {
4879 			validationLayers[0] = "VK_LAYER_KHRONOS_validation";
4880 		}
4881 		u8* get() {
4882 			return accessor(validationLayers); // here
4883 		}
4884 	}
4885 	u8* accessor(u8*[] layers) { return layers[0]; }
4886 	u8* run() {
4887 		App app;
4888 		app.init;
4889 		return app.get();
4890 	}
4891 };
4892 void tester220(ref TestContext ctx) {
4893 	import std.string : fromStringz;
4894 	auto run = ctx.getFunctionPtr!(char*)("run");
4895 	assert(run().fromStringz == "VK_LAYER_KHRONOS_validation");
4896 }
4897 
4898 
4899 @TestInfo()
4900 immutable test221 = q{--- test221
4901 	// store function pointer into struct member
4902 	// `debugCallback` IR type was not generated because it is located after `run`
4903 	struct S {
4904 		void function() funcPtr;
4905 	}
4906 	void run() {
4907 		S createInfo;
4908 		createInfo.funcPtr = &debugCallback;
4909 	}
4910 	void debugCallback() {}
4911 };
4912 
4913 
4914 @TestInfo(null, [HostSymbol("ExitProcess", cast(void*)&external_noop)])
4915 immutable test222 = q{--- test222
4916 	/// @extern(module)
4917 	@extern(module, "host")
4918 	noreturn ExitProcess(u32 uExitCode);
4919 };
4920 
4921 
4922 @TestInfo(null, [HostSymbol("ExitProcess", cast(void*)&external_noop)])
4923 immutable test223 = q{
4924 	/// Issue #16. `TypeCheckState.curFunc` was used in func signature, while it pointed to the caller function.
4925 	void main() {
4926 		ExitProcess(0);
4927 	}
4928 	@extern(module, "host")
4929 	noreturn ExitProcess(u32 uExitCode);
4930 };
4931 
4932 
4933 @TestInfo()
4934 immutable test224 = q{--- test224
4935 	/// Bug with circular dependency
4936 	void main() {
4937 		Client client;
4938 		client.run(); // 1 call
4939 	}
4940 	struct Client { // 4 Client
4941 		void run() {} // 2 func signature, 3 Client* this, 5 run function, 6 func signature
4942 	}
4943 };
4944 
4945 
4946 @TestInfo()
4947 immutable test225 = q{--- test225
4948 	/// Feature: `@attr:`
4949 	/// Should not give an error if function with the body has broadcasted @extern attribute
4950 	@extern(module, "modA"): // both are broadcasted
4951 	@extern(module, "modB"): // each attribute with its own :
4952 	void withAttrib(){}
4953 };
4954 
4955 
4956 @TestInfo()
4957 immutable test226 = q{--- test226
4958 	/// Feature: `@attr:`
4959 	@extern(module, "modA")  // both are broadcasted
4960 	@extern(module, "modB"): // with single :
4961 	void withAttrib(){}
4962 };
4963 
4964 
4965 @TestInfo(null, [HostSymbol("withAttribA", cast(void*)&external_noop), HostSymbol("withAttribB", cast(void*)&external_noop)])
4966 immutable test227 = q{--- test227
4967 	/// Feature: `@attr:`
4968 	/// Multiple functions with the same attribute
4969 	@extern(module, "host"):
4970 	void withAttribA();
4971 	void withAttribB();
4972 };
4973 
4974 
4975 @TestInfo()
4976 immutable test227_1 = q{--- test227_1
4977 	/// No definitions after @:
4978 	@extern(module, "modB"):
4979 };
4980 
4981 
4982 /* // TODO:
4983 immutable
4984 	/// Feature: `@attr:`
4985 	/// Overriding with later attribute
4986 	@extern(module, "host1"):
4987 	void withAttribA();
4988 	@extern(module, "host2"):
4989 	void withAttribB();
4990 };
4991 immutable
4992 	/// Feature: `@attr:`
4993 	/// Overriding with later attribute
4994 	@extern(module, "host1"):
4995 	void withAttribA();
4996 	@extern(module, "host2")
4997 	void withAttribB();
4998 };
4999 */
5000 
5001 
5002 @TestInfo()
5003 immutable test228 = q{--- test228
5004 	/// Take alias of global var
5005 	u32 hey;
5006 	$alias getHey() {
5007 		return hey;
5008 	}
5009 
5010 	void run() {
5011 		alias u = getHey();
5012 		foo(u);
5013 	}
5014 
5015 	void foo(u32 a){}
5016 };
5017 
5018 
5019 @TestInfo()
5020 immutable test229 = q{--- test229
5021 	/// Attribute scope
5022 	@extern(module, "host") {
5023 		void foo(u32 a){}
5024 	}
5025 	// shouldn't get the attribute. TODO: need ability to assert that.
5026 	void bar(u32 a){}
5027 };
5028 
5029 
5030 @TestInfo()
5031 immutable test230 = q{--- test230
5032 	/// All call variants
5033 	struct S {
5034 		void methodCaller() {
5035 			method;
5036 			method();
5037 
5038 			methodT;
5039 			methodT();
5040 
5041 			methodT[];
5042 			methodT[]();
5043 		}
5044 		void method() {}
5045 		void methodT[]() {}
5046 	}
5047 
5048 	void funcCaller() {
5049 		S s;
5050 
5051 		s.method;
5052 		s.method();
5053 
5054 		s.methodT;
5055 		s.methodT();
5056 
5057 		s.methodT[];
5058 		s.methodT[]();
5059 
5060 		func;
5061 		func();
5062 
5063 		funcT;
5064 		funcT();
5065 
5066 		funcT[];
5067 		funcT[]();
5068 
5069 		// s.funcT; // TODO
5070 		// s.funcT(); // TODO
5071 		// s.funcT[](); // TODO
5072 	}
5073 
5074 	void func() {}
5075 	void funcT[]() {}
5076 
5077 	// TODO:
5078 	// UFCS
5079 	// call func ptr variable
5080 	// call through alias
5081 	// call member functions through pointer
5082 };
5083 
5084 
5085 @TestInfo(&tester231)
5086 immutable test231 = q{--- test231
5087 	/// sign extension of 64-bit constants
5088 	i64 run() {
5089 		return -1;
5090 	}
5091 };
5092 void tester231(ref TestContext ctx) {
5093 	auto run = ctx.getFunctionPtr!(long)("run");
5094 	assert(run() == -1);
5095 }
5096 
5097 
5098 /*@TestInfo()
5099 immutable test232 = q{--- test232
5100 	/// TODO
5101 	/// Semantic ordering bug. Trying to access NUM's type before it was computed
5102 	void run() {
5103 		for(u32 i = 0; i < S.NUM; ++i) {
5104 		}
5105 	}
5106 	struct S {
5107 		enum NUM = 2;
5108 	}
5109 };*/
5110 
5111 
5112 /* @TestInfo()
5113 immutable test233 = q{--- test233
5114 	/// TODO
5115 	/// Semantic ordering bug
5116 	void run() {
5117 		A a;
5118 		a.b.foo();
5119 	}
5120 	struct A {
5121 		B[] b;
5122 	}
5123 	struct B[] {
5124 		void foo(){}
5125 	}
5126 };*/
5127 
5128 
5129 @TestInfo()
5130 immutable test234 = q{--- test234
5131 	/// IR gen bug. Address of `arr` must be taken and passed as first parameter of `data`. Instead it is passed by value.
5132 	struct Array
5133 	{
5134 		u64* ptr;
5135 		u64 length;
5136 		u64[] data() { return ptr[0..length]; }
5137 	}
5138 	u64 get(Array arr) {
5139 		return arr.data[0];
5140 	}
5141 };
5142 
5143 
5144 @TestInfo()
5145 immutable test235 = q{--- test235
5146 	/// Address of this parameter is taken, which forces it to be allocated on the stack
5147 	/// Then member assignment doesn't load the stored pointer
5148 	/// lowerToMember missed `memberNode.flags |= MemberExprFlags.needsDeref;` line
5149 	/// Without it no deref node was generated
5150 	struct S {
5151 		bool b;
5152 		void method() {
5153 			b = false;
5154 			receive(&this);
5155 		}
5156 	}
5157 	void receive(S**){}
5158 };
5159 
5160 
5161 @TestInfo()
5162 immutable test236 = q{--- test236
5163 	// Bug #27. be.reg_alloc.move_solver(82): ICE: Assertion failure: Second write to rax detected
5164 
5165 	// First DCE removes some instructions. This leads to some phi functions not having any users.
5166 	// This makes liveness analysis emit empty range for those vregs ([102; 102) and [144; 144) for example).
5167 	// Then register allocator allocates two intervals to the same register, because
5168 	// overlap of [144; 144) and [144; 148) is not detected and they are both allocated to eax.
5169 	// Then move solver sees 2 writes to the same register and reports an error.
5170 
5171 	f64 to_f64(u8* s) {
5172 		f64 a = 0.0;
5173 		i32 c;
5174 		i32 e = 0;
5175 		c = *s++; // This expression will give use the "illegal hardware instruction" issue if I un-comment it
5176 		while (c != '\0' && is_digit(c)) {
5177 			a = a * 10.0 + (c - '0');
5178 		}
5179 
5180 		if (c == '.') {
5181 			c = *s++; // However, the same expression doesn't give the error here
5182 			while (c != '\0' && is_digit(c)) {
5183 				a = a * 10.0 + (c - '0');
5184 				e = e - 1;
5185 				c = *s++; // And here too!
5186 			}
5187 		}
5188 
5189 		if (c == 'e' || c == 'E') {
5190 			i32 sign = 1;
5191 			i32 i = 0;
5192 			c = *s++;
5193 			if (c == '+') c = *s++;
5194 			else if (c == '-') {
5195 				c = *s++;
5196 				sign = -1;
5197 			}
5198 
5199 			while (is_digit(c)) {
5200 				i = i * 10 + (c - '0');
5201 				c = *s++;
5202 			}
5203 			e += i*sign;
5204 		}
5205 		return a;
5206 	}
5207 
5208 	bool is_digit(i32 c) {
5209 		return c >= '0' && c <= '9';
5210 	}
5211 };
5212 
5213 
5214 @TestInfo()
5215 immutable test237 = q{--- test237
5216 	// Bug #27. be.emit_mc_amd64(257): ICE: Assertion failure: reg size mismatch 2 != 3
5217 	f64 to_f64(u8* s) {
5218 		f64 a = 0.0;
5219 		i32 c;
5220 		i32 e = 0;
5221 
5222 		c = *s++; // This expression will give use the "illegal hardware instruction" issue if I un-comment it
5223 		while (c != '\0' && is_digit(c)) {
5224 			a = a * 10.0 + (c - '0');
5225 		}
5226 
5227 		if (c == '.') {
5228 			c = *s++; // However, the same expression doesn't give the error here
5229 			while (c != '\0' && is_digit(c)) {
5230 				a = a * 10.0 + (c - '0');
5231 				e = e - 1;
5232 				c = *s++; // And here too!
5233 			}
5234 		}
5235 
5236 		if (c == 'e' || c == 'E') {
5237 			i32 sign = 1;
5238 			i32 i = 0;
5239 			c = *s++;
5240 			if (c == '+') c = *s++;
5241 			else if (c == '-') {
5242 				c = *s++;
5243 				sign = -1;
5244 			}
5245 
5246 			while (is_digit(c)) {
5247 			  i = i * 10 + (c - '0');
5248 			  c = *s++;
5249 			}
5250 			e += i*sign;
5251 		}
5252 
5253 		while (e > 0) {
5254 			a *= 10.0;
5255 			e--;
5256 		}
5257 
5258 		while (e < 0) {
5259 			a *= 0.1;
5260 			e++;
5261 		}
5262 
5263 		return a;
5264 	}
5265 
5266 	bool is_digit(i32 c) {
5267 		return c >= '0' && c <= '9';
5268 	}
5269 };
5270 
5271 
5272 @TestInfo()
5273 immutable test238 = q{--- test238
5274 	/// Bug #28. Missing handling of globals, functions in move solver
5275 	u8* retGlobal(i32 num) {
5276 		if (num == 0) return "0";
5277 		return "1";
5278 	}
5279 	void function() regFunc(i32 num) {
5280 		if (num == 0) return &fun1;
5281 		return &fun2;
5282 	}
5283 	void fun1(){}
5284 	void fun2(){}
5285 };
5286 
5287 
5288 @TestInfo()
5289 immutable test239 = q{--- test239
5290 	// circular dependency on enum type
5291 	VkSharingMode mode = VkSharingMode.VK_SHARING_MODE_CONCURRENT;
5292 	enum VkSharingMode {
5293 		VK_SHARING_MODE_CONCURRENT = 1,
5294 		VK_SHARING_MODE_END_RANGE  = VK_SHARING_MODE_CONCURRENT,
5295 	}
5296 };
5297 
5298 
5299 @TestInfo()
5300 immutable test240 = q{--- test240
5301 	// Recursive type
5302 	struct S {
5303 		S[] nested1;
5304 		S* nested2;
5305 	}
5306 };
5307 
5308 
5309 @TestInfo(&tester241)
5310 immutable test241 = q{--- test241
5311 	// Compile-time int <-> float
5312 	f32  i8_to_f32() { return cast(f32)cast( i8)-100; }
5313 	f32 i16_to_f32() { return cast(f32)cast(i16)-100; }
5314 	f32 i32_to_f32() { return cast(f32)cast(i32)-100; }
5315 	f32 i64_to_f32() { return cast(f32)cast(i64)-100; }
5316 
5317 	f32  u8_to_f32() { return cast(f32)cast( u8)100; }
5318 	f32 u16_to_f32() { return cast(f32)cast(u16)100; }
5319 	f32 u32_to_f32() { return cast(f32)cast(u32)100; }
5320 	f32 u64_to_f32() { return cast(f32)cast(u64)100; }
5321 
5322 	f64  i8_to_f64() { return cast(f64)cast( i8)-100; }
5323 	f64 i16_to_f64() { return cast(f64)cast(i16)-100; }
5324 	f64 i32_to_f64() { return cast(f64)cast(i32)-100; }
5325 	f64 i64_to_f64() { return cast(f64)cast(i64)-100; }
5326 
5327 	f64  u8_to_f64() { return cast(f64)cast( u8)100; }
5328 	f64 u16_to_f64() { return cast(f64)cast(u16)100; }
5329 	f64 u32_to_f64() { return cast(f64)cast(u32)100; }
5330 	f64 u64_to_f64() { return cast(f64)cast(u64)100; }
5331 
5332 
5333 	 i8 f32_to__i8() { return cast( i8)cast(f32)-100.5; }
5334 	i16 f32_to_i16() { return cast(i16)cast(f32)-100.5; }
5335 	i32 f32_to_i32() { return cast(i32)cast(f32)-100.5; }
5336 	i64 f32_to_i64() { return cast(i64)cast(f32)-100.5; }
5337 
5338 	 u8 f32_to__u8() { return cast( u8)cast(f32)100.5; }
5339 	u16 f32_to_u16() { return cast(u16)cast(f32)100.5; }
5340 	u32 f32_to_u32() { return cast(u32)cast(f32)100.5; }
5341 	u64 f32_to_u64() { return cast(u64)cast(f32)100.5; }
5342 
5343 	 i8 f64_to__i8() { return cast( i8)cast(f64)-100.5; }
5344 	i16 f64_to_i16() { return cast(i16)cast(f64)-100.5; }
5345 	i32 f64_to_i32() { return cast(i32)cast(f64)-100.5; }
5346 	i64 f64_to_i64() { return cast(i64)cast(f64)-100.5; }
5347 
5348 	 u8 f64_to__u8() { return cast( u8)cast(f64)100.5; }
5349 	u16 f64_to_u16() { return cast(u16)cast(f64)100.5; }
5350 	u32 f64_to_u32() { return cast(u32)cast(f64)100.5; }
5351 	u64 f64_to_u64() { return cast(u64)cast(f64)100.5; }
5352 };
5353 void tester241(ref TestContext ctx) {
5354 	assert(ctx.getFunctionPtr!( float)( "i8_to_f32")() == -100);
5355 	assert(ctx.getFunctionPtr!( float)("i16_to_f32")() == -100);
5356 	assert(ctx.getFunctionPtr!( float)("i32_to_f32")() == -100);
5357 	assert(ctx.getFunctionPtr!( float)("i64_to_f32")() == -100);
5358 
5359 	assert(ctx.getFunctionPtr!( float)( "u8_to_f32")() == 100);
5360 	assert(ctx.getFunctionPtr!( float)("u16_to_f32")() == 100);
5361 	assert(ctx.getFunctionPtr!( float)("u32_to_f32")() == 100);
5362 	assert(ctx.getFunctionPtr!( float)("u64_to_f32")() == 100);
5363 
5364 	assert(ctx.getFunctionPtr!(double)( "i8_to_f64")() == -100);
5365 	assert(ctx.getFunctionPtr!(double)("i16_to_f64")() == -100);
5366 	assert(ctx.getFunctionPtr!(double)("i32_to_f64")() == -100);
5367 	assert(ctx.getFunctionPtr!(double)("i64_to_f64")() == -100);
5368 
5369 	assert(ctx.getFunctionPtr!(double)( "u8_to_f64")() == 100);
5370 	assert(ctx.getFunctionPtr!(double)("u16_to_f64")() == 100);
5371 	assert(ctx.getFunctionPtr!(double)("u32_to_f64")() == 100);
5372 	assert(ctx.getFunctionPtr!(double)("u64_to_f64")() == 100);
5373 
5374 	assert(ctx.getFunctionPtr!(  byte)("f32_to__i8")() == -100);
5375 	assert(ctx.getFunctionPtr!( short)("f32_to_i16")() == -100);
5376 	assert(ctx.getFunctionPtr!(   int)("f32_to_i32")() == -100);
5377 	assert(ctx.getFunctionPtr!(  long)("f32_to_i64")() == -100);
5378 
5379 	assert(ctx.getFunctionPtr!( ubyte)("f32_to__u8")() == 100);
5380 	assert(ctx.getFunctionPtr!(ushort)("f32_to_u16")() == 100);
5381 	assert(ctx.getFunctionPtr!(  uint)("f32_to_u32")() == 100);
5382 	assert(ctx.getFunctionPtr!( ulong)("f32_to_u64")() == 100);
5383 
5384 	assert(ctx.getFunctionPtr!(  byte)("f64_to__i8")() == -100);
5385 	assert(ctx.getFunctionPtr!( short)("f64_to_i16")() == -100);
5386 	assert(ctx.getFunctionPtr!(   int)("f64_to_i32")() == -100);
5387 	assert(ctx.getFunctionPtr!(  long)("f64_to_i64")() == -100);
5388 
5389 	assert(ctx.getFunctionPtr!( ubyte)("f64_to__u8")() == 100);
5390 	assert(ctx.getFunctionPtr!(ushort)("f64_to_u16")() == 100);
5391 	assert(ctx.getFunctionPtr!(  uint)("f64_to_u32")() == 100);
5392 	assert(ctx.getFunctionPtr!( ulong)("f64_to_u64")() == 100);
5393 }
5394 
5395 
5396 @TestInfo(&tester242)
5397 immutable test242 = q{--- test242
5398 	// Compile-time binary float ops
5399 	bool f32_gt()  { return cast(f32)100.0 >  cast(f32)50.0; }
5400 	bool f32_ge()  { return cast(f32)100.0 >= cast(f32)50.0; }
5401 	bool f32_lt()  { return cast(f32)100.0 <  cast(f32)50.0; }
5402 	bool f32_le()  { return cast(f32)100.0 <= cast(f32)50.0; }
5403 
5404 	f32 f32_add() { return cast(f32)100.0 + cast(f32)100.0; }
5405 	f32 f32_sub() { return cast(f32)100.0 - cast(f32)100.0; }
5406 	f32 f32_mul() { return cast(f32)100.0 * cast(f32)100.0; }
5407 	f32 f32_div() { return cast(f32)100.0 / cast(f32)100.0; }
5408 
5409 	bool f64_gt()  { return cast(f64)100.0 >  cast(f64)50.0; }
5410 	bool f64_ge()  { return cast(f64)100.0 >= cast(f64)50.0; }
5411 	bool f64_lt()  { return cast(f64)100.0 <  cast(f64)50.0; }
5412 	bool f64_le()  { return cast(f64)100.0 <= cast(f64)50.0; }
5413 
5414 	f64 f64_add() { return cast(f64)100.0 + cast(f64)100.0; }
5415 	f64 f64_sub() { return cast(f64)100.0 - cast(f64)100.0; }
5416 	f64 f64_mul() { return cast(f64)100.0 * cast(f64)100.0; }
5417 	f64 f64_div() { return cast(f64)100.0 / cast(f64)100.0; }
5418 };
5419 void tester242(ref TestContext ctx) {
5420 	assert(ctx.getFunctionPtr!(bool)("f32_gt")() == true);
5421 	assert(ctx.getFunctionPtr!(bool)("f32_ge")() == true);
5422 	assert(ctx.getFunctionPtr!(bool)("f32_lt")() == false);
5423 	assert(ctx.getFunctionPtr!(bool)("f32_le")() == false);
5424 
5425 	assert(ctx.getFunctionPtr!(float)("f32_add")() == 100 + 100);
5426 	assert(ctx.getFunctionPtr!(float)("f32_sub")() == 100 - 100);
5427 	assert(ctx.getFunctionPtr!(float)("f32_mul")() == 100 * 100);
5428 	assert(ctx.getFunctionPtr!(float)("f32_div")() == 100 / 100);
5429 
5430 	assert(ctx.getFunctionPtr!(bool)("f64_gt")() == true);
5431 	assert(ctx.getFunctionPtr!(bool)("f64_ge")() == true);
5432 	assert(ctx.getFunctionPtr!(bool)("f64_lt")() == false);
5433 	assert(ctx.getFunctionPtr!(bool)("f64_le")() == false);
5434 
5435 	assert(ctx.getFunctionPtr!(double)("f64_add")() == 100 + 100);
5436 	assert(ctx.getFunctionPtr!(double)("f64_sub")() == 100 - 100);
5437 	assert(ctx.getFunctionPtr!(double)("f64_mul")() == 100 * 100);
5438 	assert(ctx.getFunctionPtr!(double)("f64_div")() == 100 / 100);
5439 }
5440 
5441 
5442 @TestInfo(&tester243)
5443 immutable test243 = q{--- test243
5444 	// remainder
5445 	i8  rem_i8__fold() { return cast(i8) -32 % 10; }
5446 	i16 rem_i16_fold() { return cast(i16)-32 % 10; }
5447 	i32 rem_i32_fold() { return cast(i32)-32 % 10; }
5448 	i64 rem_i64_fold() { return cast(i64)-32 % 10; }
5449 
5450 	u8  rem_u8__fold() { return cast(u8) 32 % 10; }
5451 	u16 rem_u16_fold() { return cast(u16)32 % 10; }
5452 	u32 rem_u32_fold() { return cast(u32)32 % 10; }
5453 	u64 rem_u64_fold() { return cast(u64)32 % 10; }
5454 
5455 	i8  rem_i8__con(i8  a) { return a % 10; }
5456 	i16 rem_i16_con(i16 a) { return a % 10; }
5457 	i32 rem_i32_con(i32 a) { return a % 10; }
5458 	i64 rem_i64_con(i64 a) { return a % 10; }
5459 
5460 	u8  rem_u8__con(u8  a) { return a % 10; }
5461 	u16 rem_u16_con(u16 a) { return a % 10; }
5462 	u32 rem_u32_con(u32 a) { return a % 10; }
5463 	u64 rem_u64_con(u64 a) { return a % 10; }
5464 
5465 	i8  rem_i8__var(i8  a, i8  b) { return a % b; }
5466 	i16 rem_i16_var(i16 a, i16 b) { return a % b; }
5467 	i32 rem_i32_var(i32 a, i32 b) { return a % b; }
5468 	i64 rem_i64_var(i64 a, i64 b) { return a % b; }
5469 
5470 	u8  rem_u8__var(u8  a, u8  b) { return a % b; }
5471 	u16 rem_u16_var(u16 a, u16 b) { return a % b; }
5472 	u32 rem_u32_var(u32 a, u32 b) { return a % b; }
5473 	u64 rem_u64_var(u64 a, u64 b) { return a % b; }
5474 };
5475 void tester243(ref TestContext ctx) {
5476 	assert(ctx.getFunctionPtr!(  byte)("rem_i8__fold")() == -32 % 10);
5477 	assert(ctx.getFunctionPtr!( short)("rem_i16_fold")() == -32 % 10);
5478 	assert(ctx.getFunctionPtr!(   int)("rem_i32_fold")() == -32 % 10);
5479 	assert(ctx.getFunctionPtr!(  long)("rem_i64_fold")() == -32 % 10);
5480 
5481 	assert(ctx.getFunctionPtr!( ubyte)("rem_u8__fold")() == 32 % 10);
5482 	assert(ctx.getFunctionPtr!(ushort)("rem_u16_fold")() == 32 % 10);
5483 	assert(ctx.getFunctionPtr!(  uint)("rem_u32_fold")() == 32 % 10);
5484 	assert(ctx.getFunctionPtr!( ulong)("rem_u64_fold")() == 32 % 10);
5485 
5486 	assert(ctx.getFunctionPtr!(  byte,  byte)("rem_i8__con")(-32) == -32 % 10);
5487 	assert(ctx.getFunctionPtr!( short, short)("rem_i16_con")(-32) == -32 % 10);
5488 	assert(ctx.getFunctionPtr!(   int,   int)("rem_i32_con")(-32) == -32 % 10);
5489 	assert(ctx.getFunctionPtr!(  long,  long)("rem_i64_con")(-32) == -32 % 10);
5490 
5491 	assert(ctx.getFunctionPtr!( ubyte, ubyte)("rem_u8__con")(32) == 32 % 10);
5492 	assert(ctx.getFunctionPtr!(ushort,ushort)("rem_u16_con")(32) == 32 % 10);
5493 	assert(ctx.getFunctionPtr!(  uint,  uint)("rem_u32_con")(32) == 32 % 10);
5494 	assert(ctx.getFunctionPtr!( ulong, ulong)("rem_u64_con")(32) == 32 % 10);
5495 
5496 	assert(ctx.getFunctionPtr!(  byte,  byte,  byte)("rem_i8__var")(-32, 10) == -32 % 10);
5497 	assert(ctx.getFunctionPtr!( short, short, short)("rem_i16_var")(-32, 10) == -32 % 10);
5498 	assert(ctx.getFunctionPtr!(   int,   int,   int)("rem_i32_var")(-32, 10) == -32 % 10);
5499 	assert(ctx.getFunctionPtr!(  long,  long,  long)("rem_i64_var")(-32, 10) == -32 % 10);
5500 
5501 	assert(ctx.getFunctionPtr!( ubyte, ubyte, ubyte)("rem_u8__var")(32, 10) == 32 % 10);
5502 	assert(ctx.getFunctionPtr!(ushort,ushort,ushort)("rem_u16_var")(32, 10) == 32 % 10);
5503 	assert(ctx.getFunctionPtr!(  uint,  uint,  uint)("rem_u32_var")(32, 10) == 32 % 10);
5504 	assert(ctx.getFunctionPtr!( ulong, ulong, ulong)("rem_u64_var")(32, 10) == 32 % 10);
5505 }
5506 
5507 
5508 @TestInfo()
5509 immutable test244 = q{--- test244
5510 	// small int literals are implicitly i32
5511 	// but they should auto-cast if necessary
5512 
5513 	i8  lit_i8()  { return 1; }
5514 	i16 lit_i16() { return 1; }
5515 	i32 lit_i32() { return 1; }
5516 	i64 lit_i64() { return 1; }
5517 
5518 	u8  lit_u8()  { return 1; }
5519 	u16 lit_u16() { return 1; }
5520 	u32 lit_u32() { return 1; }
5521 	u64 lit_u64() { return 1; }
5522 };
5523 
5524 
5525 @TestInfo()
5526 immutable test245 = r"--- test245
5527 	// literal type suffix
5528 
5529 	f32 lit_f32a() { return 1f32; }
5530 	f64 lit_f64a() { return 1f64; }
5531 	f32 lit_f32b() { return 1.0f32; }
5532 	f64 lit_f64b() { return 1.0f64; }
5533 
5534 	i8  lit_i8_() { return 1i8; }
5535 	i16 lit_i16() { return 1i16; }
5536 	i32 lit_i32() { return 1i32; }
5537 	i64 lit_i64() { return 1i64; }
5538 
5539 	u8  lit_u8_() { return 1u8; }
5540 	u16 lit_u16() { return 1u16; }
5541 	u32 lit_u32() { return 1u32; }
5542 	u64 lit_u64() { return 1u64; }
5543 
5544 	i8  lit_i8_b() { return 0b1i8; }
5545 	i16 lit_i16b() { return 0b1i16; }
5546 	i32 lit_i32b() { return 0b1i32; }
5547 	i64 lit_i64b() { return 0b1i64; }
5548 
5549 	u8  lit_u8_b() { return 0b1u8; }
5550 	u16 lit_u16b() { return 0b1u16; }
5551 	u32 lit_u32b() { return 0b1u32; }
5552 	u64 lit_u64b() { return 0b1u64; }
5553 
5554 	i8  lit_i8_x() { return 0x1i8; }
5555 	i16 lit_i16x() { return 0x1i16; }
5556 	i32 lit_i32x() { return 0x1i32; }
5557 	i64 lit_i64x() { return 0x1i64; }
5558 
5559 	u8  lit_u8_x() { return 0x1u8; }
5560 	u16 lit_u16x() { return 0x1u16; }
5561 	u32 lit_u32x() { return 0x1u32; }
5562 	u64 lit_u64x() { return 0x1u64; }
5563 ";
5564 
5565 
5566 @TestInfo(&tester246)
5567 immutable test246 = q{--- test246
5568 	struct MonoTime {
5569 		i64 ticks;
5570 		Duration sub(MonoTime other) {
5571 			return Duration(ticks - other.ticks);
5572 		}
5573 	}
5574 	struct Duration {
5575 		i64 ticks;
5576 	}
5577 	i64 run(i64 a, i64 b) {
5578 		MonoTime ma = MonoTime(a);
5579 		MonoTime mb = MonoTime(b);
5580 		return ma.sub(mb).ticks;
5581 	}
5582 };
5583 void tester246(ref TestContext ctx) {
5584 	assert(ctx.getFunctionPtr!(long, long, long)("run")(100, 40) == 60);
5585 }
5586 
5587 /*
5588 @TestInfo(&tester247)
5589 immutable test247 = q{--- test247
5590 	struct MonoTime {
5591 		i64 ticks;
5592 		Duration sub(MonoTime other) {
5593 			return Duration(ticks - other.ticks);
5594 		}
5595 	}
5596 	struct Duration {
5597 		i64 ticks;
5598 	}
5599 	i64 run(i64 a, i64 b) {
5600 		return MonoTime(a).sub(MonoTime(b)).ticks;
5601 	}
5602 };
5603 void tester247(ref TestContext ctx) {
5604 	assert(ctx.getFunctionPtr!(long, long, long)("run")(100, 40) == 60);
5605 }*/
5606 
5607 
5608 @TestInfo(&tester248)
5609 immutable test248 = q{--- test248.vx
5610 	// special keywords
5611 	u64 getLine() { return __LINE__; }
5612 	u8[] getFile() { return __FILE__; }
5613 	u8[] getFunctionName() { return __FUNCTION_NAME__; }
5614 	u8[] getModuleName() { return __MODULE_NAME__; }
5615 };
5616 void tester248(ref TestContext ctx) {
5617 	assert(ctx.getFunctionPtr!(ulong)("getLine")() == 2);
5618 	assert(ctx.getFunctionPtr!(SliceString)("getFile")() == "test248.vx");
5619 	assert(ctx.getFunctionPtr!(SliceString)("getFunctionName")() == "getFunctionName");
5620 	assert(ctx.getFunctionPtr!(SliceString)("getModuleName")() == "test248");
5621 }
5622 
5623 
5624 @TestInfo(&tester249)
5625 immutable test249 = q{
5626 --- test249_1.vx
5627 	// special keywords as a default argument
5628 	u64  funLine(u64 line = __LINE__) { return line; }
5629 	u8[] funFile(u8[] file = __FILE__) { return file; }
5630 	u8[] funFunctionName(u8[] func = __FUNCTION_NAME__) { return func; }
5631 	u8[] funModuleName(u8[] mod = __MODULE_NAME__) { return mod; }
5632 --- test249_2.vx
5633 	import test249_1;
5634 
5635 	u64 getLine() { return funLine; }
5636 	u8[] getFile() { return funFile; }
5637 	u8[] getFunctionName() { return funFunctionName; }
5638 	u8[] getModuleName() { return funModuleName; }
5639 };
5640 void tester249(ref TestContext ctx) {
5641 	assert(ctx.getFunctionPtr!(ulong)("getLine")() == 3);
5642 	assert(ctx.getFunctionPtr!(SliceString)("getFile")() == "test249_2.vx");
5643 	assert(ctx.getFunctionPtr!(SliceString)("getFunctionName")() == "getFunctionName");
5644 	assert(ctx.getFunctionPtr!(SliceString)("getModuleName")() == "test249_2");
5645 }
5646 
5647 
5648 @TestInfo(&tester250)
5649 immutable test250 = q{--- test250.vx
5650 	// @static variables inside functions and structs
5651 	u64 incAndReturn1() {
5652 		@static u64 var = 42;
5653 		++var;
5654 		return var;
5655 	}
5656 	// broadcasted variant
5657 	u64 incAndReturn2() {
5658 		@static:
5659 		u64 var1 = 10;
5660 		u64 var2 = 42;
5661 		++var1;
5662 		++var2;
5663 		return var1 + var2;
5664 	}
5665 
5666 	struct S {
5667 		@static u64 structVar = 50;
5668 		u64 incAndReturn1() {
5669 			++structVar;
5670 			return structVar;
5671 		}
5672 		u64 incAndReturn2() {
5673 			++this.structVar;
5674 			return this.structVar;
5675 		}
5676 	}
5677 	// @static struct member
5678 	u64 incAndReturn3() {
5679 		++S.structVar;
5680 		return S.structVar;
5681 	}
5682 	// through variable
5683 	u64 incAndReturn4() {
5684 		S s;
5685 		++s.structVar;
5686 		return s.structVar;
5687 	}
5688 	// through method of instance
5689 	u64 incAndReturn5() {
5690 		S s;
5691 		return s.incAndReturn1();
5692 	}
5693 	// through method of instance through this
5694 	u64 incAndReturn6() {
5695 		S s;
5696 		return s.incAndReturn2();
5697 	}
5698 };
5699 void tester250(ref TestContext ctx) {
5700 	assert(ctx.getFunctionPtr!(ulong)("incAndReturn1")() == 43);
5701 	assert(ctx.getFunctionPtr!(ulong)("incAndReturn1")() == 44);
5702 
5703 	assert(ctx.getFunctionPtr!(ulong)("incAndReturn2")() == 11 + 43);
5704 	assert(ctx.getFunctionPtr!(ulong)("incAndReturn2")() == 12 + 44);
5705 
5706 	assert(ctx.getFunctionPtr!(ulong)("incAndReturn3")() == 51);
5707 	assert(ctx.getFunctionPtr!(ulong)("incAndReturn3")() == 52);
5708 
5709 	assert(ctx.getFunctionPtr!(ulong)("incAndReturn4")() == 53);
5710 	assert(ctx.getFunctionPtr!(ulong)("incAndReturn4")() == 54);
5711 
5712 	assert(ctx.getFunctionPtr!(ulong)("incAndReturn5")() == 55);
5713 	assert(ctx.getFunctionPtr!(ulong)("incAndReturn5")() == 56);
5714 
5715 	assert(ctx.getFunctionPtr!(ulong)("incAndReturn6")() == 57);
5716 	assert(ctx.getFunctionPtr!(ulong)("incAndReturn6")() == 58);
5717 }
5718 
5719 
5720 @TestInfo()
5721 immutable test251 = q{--- test251.vx
5722 	// Forbid @static on parameters
5723 	void fun(@static u64 param) {}
5724 --- <error>
5725 test251.vx:2:23: Error: Parameters cannot be @static
5726 };
5727 
5728 
5729 @TestInfo(&tester252)
5730 immutable test252 = q{--- test252.vx
5731 	// @static methods
5732 	struct S {
5733 		@static u64 structVar = 50;
5734 		@static u64 incAndReturnStatic() {
5735 			++structVar;
5736 			return structVar;
5737 		}
5738 	}
5739 	// through static method
5740 	u64 incAndReturn1() {
5741 		return S.incAndReturnStatic();
5742 	}
5743 	// through static method via instance
5744 	u64 incAndReturn2() {
5745 		S s;
5746 		return s.incAndReturnStatic();
5747 	}
5748 	// check that access to non-static members from static method is forbidden
5749 };
5750 void tester252(ref TestContext ctx) {
5751 	assert(ctx.getFunctionPtr!(ulong)("incAndReturn1")() == 51);
5752 	assert(ctx.getFunctionPtr!(ulong)("incAndReturn1")() == 52);
5753 
5754 	assert(ctx.getFunctionPtr!(ulong)("incAndReturn2")() == 53);
5755 	assert(ctx.getFunctionPtr!(ulong)("incAndReturn2")() == 54);
5756 }
5757 
5758 
5759 @TestInfo()
5760 immutable test253 = q{--- test253.vx
5761 	// Forbid access to non-@static member from @static method
5762 	// @static methods
5763 	struct S {
5764 		u64 structVar = 50;
5765 		@static void useNonstatic() {
5766 			++structVar;
5767 		}
5768 	}
5769 --- <error>
5770 test253.vx:6:6: Error: undefined identifier `this`
5771 };
5772 
5773 
5774 @TestInfo()
5775 immutable test254 = q{--- test254.vx
5776 	alias PFN_vkAllocationFunction = void* function(void* pUserData);
5777 };
5778 
5779 
5780 @TestInfo()
5781 immutable test255 = q{--- test255.vx
5782 	// Issue 40
5783 	// Incorrect aggregate lowering
5784 	// Was checking for isConstant, which ignored zero constants
5785 	struct Color { u8 r; u8 g; u8 b; u8 a; }
5786 
5787 	void draw() {
5788 		for(u64 i = 0; i < 4; i++){
5789 			u8 a = cast(u8) i;
5790 			Color c = Color(255, 0, 0, a);
5791 		}
5792 	}
5793 };
5794 
5795 
5796 @TestInfo()
5797 immutable test256 = `--- test256.vx
5798 	// Logical not CTFE
5799 	enum VAL = true;
5800 
5801 	#if(!VAL) struct A {}
5802 `;
5803 
5804 @TestInfo(&tester257)
5805 immutable test257 = q{--- test257.vx
5806 	// offsetof
5807 	struct Color { u8 r; u8 g; u8 b; u8 a; }
5808 
5809 	u64 offsetof_r() { return Color.r.offsetof; }
5810 	u64 offsetof_g() { return Color.g.offsetof; }
5811 	u64 offsetof_b() { return Color.b.offsetof; }
5812 	u64 offsetof_a() { return Color.a.offsetof; }
5813 };
5814 void tester257(ref TestContext ctx) {
5815 	assert(ctx.getFunctionPtr!(ulong)("offsetof_r")() == 0);
5816 	assert(ctx.getFunctionPtr!(ulong)("offsetof_g")() == 1);
5817 	assert(ctx.getFunctionPtr!(ulong)("offsetof_b")() == 2);
5818 	assert(ctx.getFunctionPtr!(ulong)("offsetof_a")() == 3);
5819 }
5820 
5821 
5822 @TestInfo()
5823 immutable test258 = q{--- test258.vx
5824 	// offsetof only applies to `type.member`, not `instance.member`
5825 	struct Color { u8 r; u8 g; u8 b; u8 a; }
5826 
5827 	u64 offsetof_a(Color c) { return c.offsetof; }
5828 --- <error>
5829 test258.vx:4:36: Error: `Color` has no member `offsetof`
5830 };
5831 
5832 
5833 @TestInfo()
5834 immutable test259 = q{--- test259.vx
5835 	// offsetof should not work on non-struct types
5836 	enum a;
5837 	enum b {m}
5838 	enum test_1 = a.offsetof;
5839 	enum test_2 = u8.offsetof;
5840 	enum test_3 = b.m.offsetof;
5841 --- <error>
5842 test259.vx:4:17: Error: `a` has no member `offsetof`
5843 test259.vx:5:18: Error: `u8` has no member `offsetof`
5844 test259.vx:6:19: Error: `b` has no member `offsetof`
5845 };
5846 
5847 
5848 @TestInfo(&tester260)
5849 immutable test260 = q{--- test260.vx
5850 	// offsetof with non-static members
5851 	struct Color {
5852 		u8 r;
5853 		enum e;
5854 		u8 g;
5855 		alias e1 = e;
5856 		u8 b;
5857 		u8 a;
5858 	}
5859 
5860 	u64 offsetof_r() { return Color.r.offsetof; }
5861 	u64 offsetof_g() { return Color.g.offsetof; }
5862 	u64 offsetof_b() { return Color.b.offsetof; }
5863 	u64 offsetof_a() { return Color.a.offsetof; }
5864 	//u64 offsetof_e() { return Color.e.offsetof; }
5865 };
5866 void tester260(ref TestContext ctx) {
5867 	assert(ctx.getFunctionPtr!(ulong)("offsetof_r")() == 0);
5868 	assert(ctx.getFunctionPtr!(ulong)("offsetof_g")() == 1);
5869 	assert(ctx.getFunctionPtr!(ulong)("offsetof_b")() == 2);
5870 	assert(ctx.getFunctionPtr!(ulong)("offsetof_a")() == 3);
5871 }
5872 
5873 
5874 @TestInfo()
5875 immutable test261 = q{--- test261.vx
5876 	// offsetof only applies to non-static memebers
5877 	struct Color { enum e; alias e1 = e; @static u8 g; }
5878 
5879 	u64 offsetof_e() { return Color.e.offsetof; }
5880 	u64 offsetof_e1() { return Color.e1.offsetof; }
5881 	u64 offsetof_g() { return Color.g.offsetof; }
5882 --- <error>
5883 test261.vx:4:35: Error: `e` has no member `offsetof`
5884 test261.vx:5:37: Error: `e` has no member `offsetof`
5885 test261.vx:6:35: Error: `u8` has no member `offsetof`
5886 };
5887 
5888 
5889 @TestInfo()
5890 immutable test262 = q{--- test262.vx
5891 	// bug Type [2 x {i32, i32, i32, i32}] of size 32 cannot be stored in a register
5892 	// caused by generating load instead of load_aggregate for arrays
5893 	struct Color { i32 r; i32 g; i32 b; i32 a; }
5894 	Color[2] get() { Color[2] c; return c; }
5895 };
5896 
5897 
5898 @TestInfo(&tester266)
5899 immutable test266 = q{--- test266.vx
5900 	// using int literals to initialize floats
5901 	f32 get_f32() {
5902 		f32 val = 1;
5903 		return val;
5904 	}
5905 	f64 get_f64() {
5906 		f64 val = 1;
5907 		return val;
5908 	}
5909 };
5910 void tester266(ref TestContext ctx) {
5911 	assert(ctx.getFunctionPtr!(float)("get_f32")() == 1.0f);
5912 	assert(ctx.getFunctionPtr!(double)("get_f64")() == 1.0);
5913 }
5914 
5915 
5916 @TestInfo(&tester267)
5917 immutable test267 = q{--- test267.vx
5918 	// implicit conversion of pointer to bool
5919 	bool null_to_bool() {
5920 		return null;
5921 	}
5922 	bool ptr_to_bool(void* ptr) {
5923 		return ptr;
5924 	}
5925 	bool u8_ptr_to_bool(u8* ptr) {
5926 		return ptr;
5927 	}
5928 	struct Handle_dummy; alias Handle = Handle_dummy*;
5929 	bool struct_ptr_to_bool(Handle ptr) {
5930 		return ptr;
5931 	}
5932 	u8 null_branch() {
5933 		if(null) return 42;
5934 		return 12;
5935 	}
5936 	u8 ptr_branch(void* ptr) {
5937 		if(ptr) return 42;
5938 		return 12;
5939 	}
5940 	u8 u8_ptr_branch(u8* ptr) {
5941 		if(ptr) return 42;
5942 		return 12;
5943 	}
5944 	u8 struct_ptr_branch(Handle ptr) {
5945 		if(ptr) return 42;
5946 		return 12;
5947 	}
5948 };
5949 void tester267(ref TestContext ctx) {
5950 	ubyte var;
5951 	assert(ctx.getFunctionPtr!(bool)("null_to_bool")() == false);
5952 	assert(ctx.getFunctionPtr!(bool, void*)("ptr_to_bool")(null) == false);
5953 	assert(ctx.getFunctionPtr!(bool, void*)("ptr_to_bool")(&var) == true);
5954 	assert(ctx.getFunctionPtr!(bool, void*)("u8_ptr_to_bool")(null) == false);
5955 	assert(ctx.getFunctionPtr!(bool, void*)("u8_ptr_to_bool")(&var) == true);
5956 	assert(ctx.getFunctionPtr!(bool, void*)("struct_ptr_to_bool")(null) == false);
5957 	assert(ctx.getFunctionPtr!(bool, void*)("struct_ptr_to_bool")(&var) == true);
5958 	assert(ctx.getFunctionPtr!(ubyte)("null_branch")() == 12);
5959 	assert(ctx.getFunctionPtr!(ubyte, void*)("ptr_branch")(null) == 12);
5960 	assert(ctx.getFunctionPtr!(ubyte, void*)("ptr_branch")(&var) == 42);
5961 	assert(ctx.getFunctionPtr!(ubyte, void*)("u8_ptr_branch")(null) == 12);
5962 	assert(ctx.getFunctionPtr!(ubyte, void*)("u8_ptr_branch")(&var) == 42);
5963 	assert(ctx.getFunctionPtr!(ubyte, void*)("struct_ptr_branch")(null) == 12);
5964 	assert(ctx.getFunctionPtr!(ubyte, void*)("struct_ptr_branch")(&var) == 42);
5965 }
5966 
5967 
5968 @TestInfo()
5969 immutable test268 = `--- test268.vx
5970 	// auto for variable declarations in function body
5971 	struct S {}
5972 	enum E { e = 1 }
5973 	void fun() {
5974 		auto val_i8  = 1_i8;
5975 		auto val_i16 = 1_i16;
5976 		auto val_i32 = 1_i32;
5977 		auto val_i64 = 1_i64;
5978 		auto val_u8  = 1_u8;
5979 		auto val_u16 = 1_u16;
5980 		auto val_u32 = 1_u32;
5981 		auto val_u64 = 1_u64;
5982 		auto val_f32 = 1_f32;
5983 		auto val_f64 = 1_f64;
5984 		auto val_bool = true;
5985 		auto val_null = null;
5986 		auto val_S = S();
5987 		auto val_E = E.e;
5988 		auto val_type = u8;
5989 	}
5990 	auto val_i8  = 1_i8;
5991 	auto val_i16 = 1_i16;
5992 	auto val_i32 = 1_i32;
5993 	auto val_i64 = 1_i64;
5994 	auto val_u8  = 1_u8;
5995 	auto val_u16 = 1_u16;
5996 	auto val_u32 = 1_u32;
5997 	auto val_u64 = 1_u64;
5998 	auto val_f32 = 1_f32;
5999 	auto val_f64 = 1_f64;
6000 	auto val_bool = true;
6001 	auto val_null = null;
6002 	auto val_S = S();
6003 	auto val_E = E.e;
6004 	auto val_type = u8;
6005 `;
6006 
6007 
6008 @TestInfo()
6009 immutable test269 = q{--- test269.vx
6010 	// functions returning auto
6011 	auto fun() {}
6012 --- <error>
6013 test269.vx:2:7: Error: functions cannot return `auto`
6014 };
6015 
6016 
6017 @TestInfo()
6018 immutable test270 = q{--- test270.vx
6019 	// functions returning auto
6020 	auto fun[T]() {}
6021 --- <error>
6022 test270.vx:2:7: Error: functions cannot return `auto`
6023 };
6024 
6025 
6026 @TestInfo()
6027 immutable test271 = q{--- test271.vx
6028 	// auto variables requiring initializer
6029 	auto var;
6030 --- <error>
6031 test271.vx:2:7: Error: variables declared as `auto` must have an initializer
6032 };
6033 
6034 
6035 @TestInfo(&tester272)
6036 immutable test272 = q{--- test272.vx
6037 	// named arguments
6038 	i32 func(i32 param1, i32 param2, i32 param3) { return param1 * 40 + param2 * 20 + param3; }
6039 	i32 call_0() { return func(1, 2, 3); }
6040 	i32 call_1() { return func(param1: 1, 2, 3); }
6041 	i32 call_2() { return func(1, param2: 2, 3); }
6042 	i32 call_3() { return func(1, 2, param3: 3); }
6043 	i32 call_4() { return func(param1: 1, param2: 2, 3); }
6044 	i32 call_5() { return func(param2: 2, 3, param1: 1, ); }
6045 	i32 call_6() { return func(param1: 1, 2, param3: 3); }
6046 	i32 call_7() { return func(param3: 3, param1: 1, 2); }
6047 	i32 call_8() { return func(1, param2: 2, param3: 3); }
6048 	i32 call_9() { return func(1, param3: 3, param2: 2); }
6049 	i32 call10() { return func(param1: 1, param2: 2, param3: 3); }
6050 	i32 call11() { return func(param1: 1, param3: 3, param2: 2); }
6051 	i32 call12() { return func(param2: 2, param1: 1, param3: 3); }
6052 	i32 call13() { return func(param2: 2, param3: 3, param1: 1); }
6053 	i32 call14() { return func(param3: 3, param1: 1, param2: 2); }
6054 	i32 call15() { return func(param3: 3, param2: 2, param1: 1); }
6055 };
6056 void tester272(ref TestContext ctx) {
6057 	assert(ctx.getFunctionPtr!(int)("call_0")() == 83);
6058 	assert(ctx.getFunctionPtr!(int)("call_1")() == 83);
6059 	assert(ctx.getFunctionPtr!(int)("call_2")() == 83);
6060 	assert(ctx.getFunctionPtr!(int)("call_3")() == 83);
6061 	assert(ctx.getFunctionPtr!(int)("call_4")() == 83);
6062 	assert(ctx.getFunctionPtr!(int)("call_5")() == 83);
6063 	assert(ctx.getFunctionPtr!(int)("call_6")() == 83);
6064 	assert(ctx.getFunctionPtr!(int)("call_7")() == 83);
6065 	assert(ctx.getFunctionPtr!(int)("call_8")() == 83);
6066 	assert(ctx.getFunctionPtr!(int)("call_9")() == 83);
6067 	assert(ctx.getFunctionPtr!(int)("call10")() == 83);
6068 	assert(ctx.getFunctionPtr!(int)("call11")() == 83);
6069 	assert(ctx.getFunctionPtr!(int)("call12")() == 83);
6070 	assert(ctx.getFunctionPtr!(int)("call13")() == 83);
6071 	assert(ctx.getFunctionPtr!(int)("call14")() == 83);
6072 }
6073 
6074 @TestInfo()
6075 immutable test273 = q{--- test273.vx
6076 	// named arguments, error cases
6077 	i32 func(i32 param1, i32 param2, i32 param3) { return param1 * 40 + param2 * 20 + param3; }
6078 	i32 call_1() { return func(param4: 4, 1, 2); } // nonexisting named parameter
6079 	i32 call_2() { return func(param2: 2, 1, 3); } // setting parameter 4, param1 not set
6080 	i32 call_3() { return func(param3: 3, 1, 2); } // setting parameter 4 and 5, params 1 and 2 not set
6081 	i32 call_4() { return func(param1: 1, param1: 1, 2); } // setting parameter 1 twice
6082 --- <error>
6083 test273.vx:3:29: Error: Function `func` has no parameter named `param4`
6084 test273.vx:3:28: Error: Missing argument for parameter 1: `param1`
6085 test273.vx:3:28: Error: Missing argument for parameter 2: `param2`
6086 test273.vx:3:28: Error: Missing argument for parameter 3: `param3`
6087 test273.vx:4:43: Error: Trying to provide parameter 4, while `func` has 3 parameters
6088 test273.vx:4:28: Error: Missing argument for parameter 1: `param1`
6089 test273.vx:5:40: Error: Trying to provide parameter 4, while `func` has 3 parameters
6090 test273.vx:5:43: Error: Trying to provide parameter 5, while `func` has 3 parameters
6091 test273.vx:5:28: Error: Missing argument for parameter 1: `param1`
6092 test273.vx:5:28: Error: Missing argument for parameter 2: `param2`
6093 test273.vx:6:40: Error: Parameter `param1` provided several times
6094 test273.vx:6:28: Error: Missing argument for parameter 3: `param3`
6095 };
6096 
6097 
6098 @TestInfo(&tester274)
6099 immutable test274 = q{--- test274.vx
6100 	// named arguments with default arguments
6101 	i32 func(i32 param1, i32 param2, i32 param3 = 3) { return param1 * 40 + param2 * 20 + param3; }
6102 	i32 call_0() { return func(1, 2); }
6103 	i32 call_1() { return func(1, 2, 3); }
6104 	i32 call_2() { return func(param1: 1, 2); }
6105 	i32 call_3() { return func(1, param2: 2); }
6106 	i32 call_4() { return func(param1: 1, param2: 2); }
6107 	i32 call_5() { return func(param2: 2, param1: 1); }
6108 };
6109 void tester274(ref TestContext ctx) {
6110 	assert(ctx.getFunctionPtr!(int)("call_0")() == 83);
6111 	assert(ctx.getFunctionPtr!(int)("call_1")() == 83);
6112 	assert(ctx.getFunctionPtr!(int)("call_2")() == 83);
6113 	assert(ctx.getFunctionPtr!(int)("call_3")() == 83);
6114 	assert(ctx.getFunctionPtr!(int)("call_4")() == 83);
6115 	assert(ctx.getFunctionPtr!(int)("call_5")() == 83);
6116 }
6117 
6118 
6119 @TestInfo()
6120 immutable test275 = q{--- test275.vx
6121 	// named arguments, anonymous parameters
6122 	void func(i32) {}
6123 	void call() { return func(__param_0: 1); }
6124 --- <error>
6125 test275.vx:3:28: Error: Function `func` has no parameter named `__param_0`
6126 test275.vx:3:27: Error: Missing argument for anonymous parameter 1
6127 };
6128 
6129 
6130 @TestInfo(&tester276)
6131 immutable test276 = q{--- test276.vx
6132 	// return void typed expression from void function
6133 	void func() {}
6134 	void call() { return func(); }
6135 };
6136 void tester276(ref TestContext ctx) {
6137 	ctx.getFunctionPtr!(void)("call")();
6138 }
6139 
6140 
6141 @TestInfo(&tester277)
6142 immutable test277 = q{--- test277.vx
6143 	// named arguments for structs (named cannot be mixed with positional)
6144 	struct Color { u8 r = 1; u8 g = 2; u8 b = 3; u8 a; }
6145 	Color make_0() { return Color(r: 1, g: 2, b: 3, a: 4); }
6146 	Color make_1() { return Color(r: 1); }
6147 	Color make_2() { return Color(r: 1, a: 4); }
6148 	Color make_3() { return Color(a: 4, b: 3, g: 2, r: 1); }
6149 	//union Union { u32 u; bool b; f32 f; }
6150 	//Union make_4() { return Union(u: 100); }
6151 	//Union make_5() { return Union(b: true); }
6152 	//Union make_6() { return Union(f: 10); }
6153 };
6154 void tester277(ref TestContext ctx) {
6155 	static struct Color { ubyte r; ubyte g; ubyte b; ubyte a; }
6156 	static struct Union {
6157 		this(uint u){ this.u = u; }
6158 		this(bool b){ this.b = b; }
6159 		this(float f){ this.f = f; }
6160 		uint u;
6161 		bool b;
6162 		float f;
6163 	}
6164 	assert(ctx.getFunctionPtr!(Color)("make_0")() == Color(1, 2, 3, 4));
6165 	assert(ctx.getFunctionPtr!(Color)("make_1")() == Color(1, 2, 3, 0));
6166 	assert(ctx.getFunctionPtr!(Color)("make_2")() == Color(1, 2, 3, 4));
6167 	assert(ctx.getFunctionPtr!(Color)("make_3")() == Color(1, 2, 3, 4));
6168 	//assert(ctx.getFunctionPtr!(Union)("make_4")() == Union(100));
6169 }
6170 
6171 
6172 @TestInfo()
6173 immutable test278 = q{--- test278.vx
6174 	// nnamed arguments for structs, errors
6175 	struct Color { u8 r = 1; u8 g = 2; u8 b = 3; u8 a; }
6176 	struct ColorStatic { @static u8 r = 1; u8 g = 2; u8 b = 3; u8 a; }
6177 	union U { u8 b; f32 f; }
6178 	Color make_1() { return Color(r: 1, g: 2, b: 3, w: 4); }
6179 	ColorStatic make_2() { return ColorStatic(r: 1); }
6180 	Color make_3() { return Color(1, 2, 3, 4, 5); }
6181 	Color make_4() { return Color(r: 1, 2, 3, 4, 5); }
6182 	U make_5() { return U(b: 1, f: 1.0); }
6183 --- <error>
6184 test278.vx:5:50: Error: struct `Color` has no member named `w`
6185 test278.vx:6:44: Error: cannot initialize variable `r` of struct `ColorStatic`
6186 test278.vx:7:31: Error: cannot initialize struct `Color` with 5 arguments, it has 4 members
6187 test278.vx:8:31: Error: cannot initialize struct `Color` with 5 arguments, it has 4 members
6188 test278.vx:8:38: Error: named and positional arguments cannot be mixed in struct constructor
6189 test278.vx:9:23: Error: union constructor must have a single argument, not 2
6190 };
6191 
6192 
6193 @TestInfo()
6194 immutable test279 = q{--- test279.vx
6195 	// issue 42. Call expression of index expression didn't account for different template kinds and always assumed function template
6196 	struct Vector[T] {
6197 		T* ptr;
6198 		u64 capacity;
6199 		u64 length;
6200 	}
6201 
6202 	void main() {
6203 		Vector[i32] numbers = Vector[i32](null, 10, 0);
6204 	}
6205 };
6206 
6207 
6208 @TestInfo()
6209 immutable test280 = q{--- test280.vx
6210 	// issue 43. Missing check for expand operator on non-templated function
6211 	void printa(u8[]... data) {}
6212 --- <error>
6213 test280.vx:2:22: Error: Variadic arrays are not yet implemented
6214 };
6215 
6216 
6217 @TestInfo()
6218 immutable test281 = q{--- test281.vx
6219 	// issue 44. Missing check for expand operator on templated function without variadic parameter
6220 	void print[Args](Args... data) {}
6221 	void run() {
6222 		print("Hello", ", ", "world!\n");
6223 	}
6224 --- <error>
6225 test281.vx:2:27: Error: Variadic parameters are not implemented
6226 };
6227 
6228 
6229 @TestInfo()
6230 immutable test282 = q{--- test282.vx
6231 	// issue 44
6232 	void print[Args](Args data) {}
6233 	void run() {
6234 		print("Hello", ", ", "world!\n");
6235 	}
6236 --- <error>
6237 test282.vx:4:8: Error: Cannot infer template parameters. Number of runtime arguments (3) does not match number of function parameters (1)
6238 };
6239 
6240 
6241 @TestInfo()
6242 immutable test283 = q{--- test283.vx
6243 	// Templated method with IFTI
6244 	struct S {
6245 		void methodCaller() {
6246 			methodT(42);
6247 			methodT[](42);
6248 		}
6249 		void method(i32 arg) {}
6250 		void methodT[](i32 arg) {}
6251 	}
6252 };
6253 
6254 
6255 @TestInfo()
6256 immutable test284 = q{--- test284.vx
6257 	// Check for expand on incorrect template parameter
6258 	void print[T, Args...](T... data) {}
6259 	void run() {
6260 		print("Hello", ", ", "world!\n");
6261 	}
6262 --- <error>
6263 test284.vx:2:30: Error: Should be `Args... data`
6264 test284.vx:2:30: Error: Cannot expand non-variadic template parameter T
6265 };
6266 
6267 
6268 @TestInfo()
6269 immutable test285 = q{--- test285.vx
6270 	// Use of non-expanded variadic type
6271 	void print[Args...](Args data) {}
6272 	void run() {
6273 		print("Hello", ", ", "world!\n");
6274 	}
6275 --- <error>
6276 test285.vx:2:22: Error: Should be `Args... data`
6277 test285.vx:4:8: Error: Cannot infer template parameters. Number of runtime arguments (3) does not match number of function parameters (1)
6278 };
6279 
6280 
6281 
6282 @TestInfo()
6283 immutable test286 = q{--- test286.vx
6284 	// Report error on out-of-bound access to array
6285 	void sys_write(void* ptr){}
6286 	void printa[Args...](Args... data) {
6287 		sys_write(data[3].ptr);
6288 	}
6289 	void main() {
6290 		printa("Hello", ", ", "world!\n");
6291 	}
6292 --- <error>
6293 test286.vx:4:17: Error: Accessing index 3 of array of length 3
6294 };
6295 
6296 
6297 @TestInfo()
6298 immutable test287 = q{--- test287.vx
6299 	// Forward reference bug. Type of `b` was not type checked
6300 	struct Array[T] {}
6301 	struct Ctx {
6302 		S a;
6303 	}
6304 	struct S {
6305 		Array[i32] b;
6306 	}
6307 };
6308 
6309 
6310 @TestInfo(&tester288)
6311 immutable test288 = q{--- test288.vx
6312 	// Aggregate lowering bug with constant aggregate nested inside non-constant one
6313 	struct vec3 { f32 x; f32 y; f32 z; }
6314 	struct Vertex {
6315 		f32 pos;
6316 		vec3 color;
6317 	}
6318 	Vertex putQuadAt(f32 pos) {
6319 		return Vertex(pos, vec3(1, 0, 0));
6320 	}
6321 };
6322 void tester288(ref TestContext ctx) {
6323 	static struct vec3 { float x; float y; float z; }
6324 	static struct Vertex { float pos; vec3 color; }
6325 	assert(ctx.getFunctionPtr!(Vertex, float)("putQuadAt")(56.0f) == Vertex(56.0f, vec3(1, 0, 0)));
6326 }
6327 
6328 
6329 /*
6330 TODO
6331 @TestInfo(&tester289)
6332 immutable test289 = q{--- test289.vx
6333 	// Aggregate of float type
6334 	struct vec2 { f32 x; f32 y; }
6335 	vec2 make(f32 x, f32 y) {
6336 		return vec2(x, y);
6337 	}
6338 };
6339 void tester289(ref TestContext ctx) {
6340 	static struct vec2 { float x; float y; }
6341 	assert(ctx.getFunctionPtr!(vec2, float, float)("make")(56.0f, 30.0f) == vec2(56.0f, 30.0f));
6342 }*/
6343 
6344 
6345 @TestInfo(&tester290, [HostSymbol("noop", cast(void*)&external_noop)])
6346 immutable test290 = q{--- test290.vx
6347 	// Taking address of the external symbol
6348 	@extern(module, "host") void noop();
6349 	void* run() {
6350 		return &noop;
6351 	}
6352 };
6353 void tester290(ref TestContext ctx) {
6354 	assert(ctx.getFunctionPtr!(void*)("run")() == &external_noop);
6355 }