Make JetStream 2
[WebKit-https.git] / PerformanceTests / JetStream2 / WSL / Test.js
1 /*
2  * Copyright (C) 2017 Apple Inc. All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
7  * 1. Redistributions of source code must retain the above copyright
8  *    notice, this list of conditions and the following disclaimer.
9  * 2. Redistributions in binary form must reproduce the above copyright
10  *    notice, this list of conditions and the following disclaimer in the
11  *    documentation and/or other materials provided with the distribution.
12  *
13  * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
14  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE INC. OR
17  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
18  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
19  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
20  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
21  * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
23  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
24  */
25 "use strict";
26
27 function doPrep(code)
28 {
29     return prepare("/internal/test", 0, code);
30 }
31
32 function doLex(code)
33 {
34     let lexer = new Lexer("/internal/test", "native", 0, code);
35     var result = [];
36     for (;;) {
37         let next = lexer.next();
38         if (!next)
39             return result;
40         result.push(next);
41     }
42     return result;
43 }
44
45 function makeInt(program, value)
46 {
47     return TypedValue.box(program.intrinsics.int32, value);
48 }
49
50 function makeUint(program, value)
51 {
52     return TypedValue.box(program.intrinsics.uint32, value);
53 }
54
55 function makeUint8(program, value)
56 {
57     return TypedValue.box(program.intrinsics.uint8, value);
58 }
59
60 function makeBool(program, value)
61 {
62     return TypedValue.box(program.intrinsics.bool, value);
63 }
64
65 function makeFloat(program, value)
66 {
67     return TypedValue.box(program.intrinsics.float, value);
68 }
69
70 function makeDouble(program, value)
71 {
72     return TypedValue.box(program.intrinsics.double, value);
73 }
74
75 function makeEnum(program, enumName, value)
76 {
77     let enumType = program.types.get(enumName);
78     if (!enumType)
79         throw new Error("No type named " + enumName);
80     let enumMember = enumType.memberByName(value);
81     if (!enumMember)
82         throw new Error("No member named " + enumMember + " in " + enumType);
83     return TypedValue.box(enumType, enumMember.value.unifyNode.valueForSelectedType);
84 }
85
86 function checkNumber(program, result, expected)
87 {
88     if (!result.type.unifyNode.isNumber)
89         throw new Error("Wrong result type; result: " + result);
90     if (result.value != expected)
91         throw new Error("Wrong result: " + result.value + " (expected " + expected + ")");
92 }
93
94 function checkInt(program, result, expected)
95 {
96     if (!result.type.equals(program.intrinsics.int32))
97         throw new Error("Wrong result type; result: " + result);
98     checkNumber(program, result, expected);
99 }
100
101 function checkEnum(program, result, expected)
102 {
103     if (!(result.type.unifyNode instanceof EnumType))
104         throw new Error("Wrong result type; result: " + result);
105     if (result.value != expected)
106         throw new Error("Wrong result: " + result.value + " (expected " + expected + ")");
107 }
108
109 function checkUint(program, result, expected)
110 {
111     if (!result.type.equals(program.intrinsics.uint32))
112         throw new Error("Wrong result type: " + result.type);
113     if (result.value != expected)
114         throw new Error("Wrong result: " + result.value + " (expected " + expected + ")");
115 }
116
117 function checkUint8(program, result, expected)
118 {
119     if (!result.type.equals(program.intrinsics.uint8))
120         throw new Error("Wrong result type: " + result.type);
121     if (result.value != expected)
122         throw new Error("Wrong result: " + result.value + " (expected " + expected + ")");
123 }
124
125 function checkBool(program, result, expected)
126 {
127     if (!result.type.equals(program.intrinsics.bool))
128         throw new Error("Wrong result type: " + result.type);
129     if (result.value != expected)
130         throw new Error("Wrong result: " + result.value + " (expected " + expected + ")");
131 }
132
133 function checkFloat(program, result, expected)
134 {
135     if (!result.type.equals(program.intrinsics.float))
136         throw new Error("Wrong result type: " + result.type);
137     if (result.value != expected)
138         throw new Error("Wrong result: " + result.value + " (expected " + expected + ")");
139 }
140
141 function checkDouble(program, result, expected)
142 {
143     if (!result.type.equals(program.intrinsics.double))
144         throw new Error("Wrong result type: " + result.type);
145     if (result.value != expected)
146         throw new Error("Wrong result: " + result.value + " (expected " + expected + ")");
147 }
148
149 function checkLexerToken(result, expectedIndex, expectedKind, expectedText)
150 {
151     if (result._index != expectedIndex)
152         throw new Error("Wrong lexer index; result: " + result._index + " (expected " + expectedIndex + ")");
153     if (result._kind != expectedKind)
154         throw new Error("Wrong lexer kind; result: " + result._kind + " (expected " + expectedKind + ")");
155     if (result._text != expectedText)
156         throw new Error("Wrong lexer text; result: " + result._text + " (expected " + expectedText + ")");
157 }
158
159 function checkFail(callback, predicate)
160 {
161     try {
162         callback();
163         throw new Error("Did not throw exception");
164     } catch (e) {
165         if (predicate(e)) {
166             return;
167         }
168         throw e;
169     }
170 }
171
172 let okToTest = false;
173
174 let tests = new Proxy({}, {
175     set(target, property, value, receiver)
176     {
177         if (property in target)
178             throw new Error("Trying to declare duplicate test: " + property);
179         target[property] = value;
180         return true;
181     }
182 });
183
184 tests.literalBool = function() {
185     let program = doPrep("bool foo() { return true; }");
186     checkBool(program, callFunction(program, "foo", [], []), true);
187 }
188
189 tests.identityBool = function() {
190     let program = doPrep("bool foo(bool x) { return x; }");
191     checkBool(program, callFunction(program, "foo", [], [makeBool(program, true)]), true);
192     checkBool(program, callFunction(program, "foo", [], [makeBool(program, false)]), false);
193 }
194
195 tests.intSimpleMath = function() {
196     let program = doPrep("int foo(int x, int y) { return x + y; }");
197     checkInt(program, callFunction(program, "foo", [], [makeInt(program, 7), makeInt(program, 5)]), 12);
198     program = doPrep("int foo(int x, int y) { return x - y; }");
199     checkInt(program, callFunction(program, "foo", [], [makeInt(program, 7), makeInt(program, 5)]), 2);
200     checkInt(program, callFunction(program, "foo", [], [makeInt(program, 5), makeInt(program, 7)]), -2);
201     program = doPrep("int foo(int x, int y) { return x * y; }");
202     checkInt(program, callFunction(program, "foo", [], [makeInt(program, 7), makeInt(program, 5)]), 35);
203     checkInt(program, callFunction(program, "foo", [], [makeInt(program, 7), makeInt(program, -5)]), -35);
204     program = doPrep("int foo(int x, int y) { return x / y; }");
205     checkInt(program, callFunction(program, "foo", [], [makeInt(program, 7), makeInt(program, 2)]), 3);
206     checkInt(program, callFunction(program, "foo", [], [makeInt(program, 7), makeInt(program, -2)]), -3);
207 }
208
209 tests.uintSimpleMath = function() {
210     let program = doPrep("uint foo(uint x, uint y) { return x + y; }");
211     checkUint(program, callFunction(program, "foo", [], [makeUint(program, 7), makeUint(program, 5)]), 12);
212     program = doPrep("uint foo(uint x, uint y) { return x - y; }");
213     checkUint(program, callFunction(program, "foo", [], [makeUint(program, 7), makeUint(program, 5)]), 2);
214     checkUint(program, callFunction(program, "foo", [], [makeUint(program, 5), makeUint(program, 7)]), 4294967294);
215     program = doPrep("uint foo(uint x, uint y) { return x * y; }");
216     checkUint(program, callFunction(program, "foo", [], [makeUint(program, 7), makeUint(program, 5)]), 35);
217     program = doPrep("uint foo(uint x, uint y) { return x / y; }");
218     checkUint(program, callFunction(program, "foo", [], [makeUint(program, 7), makeUint(program, 2)]), 3);
219 }
220
221 tests.uint8SimpleMath = function() {
222     let program = doPrep("uint8 foo(uint8 x, uint8 y) { return x + y; }");
223     checkUint8(program, callFunction(program, "foo", [], [makeUint8(program, 7), makeUint8(program, 5)]), 12);
224     program = doPrep("uint8 foo(uint8 x, uint8 y) { return x - y; }");
225     checkUint8(program, callFunction(program, "foo", [], [makeUint8(program, 7), makeUint8(program, 5)]), 2);
226     checkUint8(program, callFunction(program, "foo", [], [makeUint8(program, 5), makeUint8(program, 7)]), 254);
227     program = doPrep("uint8 foo(uint8 x, uint8 y) { return x * y; }");
228     checkUint8(program, callFunction(program, "foo", [], [makeUint8(program, 7), makeUint8(program, 5)]), 35);
229     program = doPrep("uint8 foo(uint8 x, uint8 y) { return x / y; }");
230     checkUint8(program, callFunction(program, "foo", [], [makeUint8(program, 7), makeUint8(program, 2)]), 3);
231 }
232
233 tests.equality = function() {
234     let program = doPrep("bool foo(uint x, uint y) { return x == y; }");
235     checkBool(program, callFunction(program, "foo", [], [makeUint(program, 7), makeUint(program, 5)]), false);
236     checkBool(program, callFunction(program, "foo", [], [makeUint(program, 7), makeUint(program, 7)]), true);
237     program = doPrep("bool foo(uint8 x, uint8 y) { return x == y; }");
238     checkBool(program, callFunction(program, "foo", [], [makeUint8(program, 7), makeUint8(program, 5)]), false);
239     checkBool(program, callFunction(program, "foo", [], [makeUint8(program, 7), makeUint8(program, 7)]), true);
240     program = doPrep("bool foo(int x, int y) { return x == y; }");
241     checkBool(program, callFunction(program, "foo", [], [makeInt(program, 7), makeInt(program, 5)]), false);
242     checkBool(program, callFunction(program, "foo", [], [makeInt(program, 7), makeInt(program, 7)]), true);
243     program = doPrep("bool foo(bool x, bool y) { return x == y; }");
244     checkBool(program, callFunction(program, "foo", [], [makeBool(program, false), makeBool(program, true)]), false);
245     checkBool(program, callFunction(program, "foo", [], [makeBool(program, true), makeBool(program, false)]), false);
246     checkBool(program, callFunction(program, "foo", [], [makeBool(program, false), makeBool(program, false)]), true);
247     checkBool(program, callFunction(program, "foo", [], [makeBool(program, true), makeBool(program, true)]), true);
248 }
249
250 tests.logicalNegation = function()
251 {
252     let program = doPrep("bool foo(bool x) { return !x; }");
253     checkBool(program, callFunction(program, "foo", [], [makeBool(program, true)]), false);
254     checkBool(program, callFunction(program, "foo", [], [makeBool(program, false)]), true);
255 }
256
257 tests.notEquality = function() {
258     let program = doPrep("bool foo(uint x, uint y) { return x != y; }");
259     checkBool(program, callFunction(program, "foo", [], [makeUint(program, 7), makeUint(program, 5)]), true);
260     checkBool(program, callFunction(program, "foo", [], [makeUint(program, 7), makeUint(program, 7)]), false);
261     program = doPrep("bool foo(uint8 x, uint8 y) { return x != y; }");
262     checkBool(program, callFunction(program, "foo", [], [makeUint8(program, 7), makeUint8(program, 5)]), true);
263     checkBool(program, callFunction(program, "foo", [], [makeUint8(program, 7), makeUint8(program, 7)]), false);
264     program = doPrep("bool foo(int x, int y) { return x != y; }");
265     checkBool(program, callFunction(program, "foo", [], [makeInt(program, 7), makeInt(program, 5)]), true);
266     checkBool(program, callFunction(program, "foo", [], [makeInt(program, 7), makeInt(program, 7)]), false);
267     program = doPrep("bool foo(bool x, bool y) { return x != y; }");
268     checkBool(program, callFunction(program, "foo", [], [makeBool(program, false), makeBool(program, true)]), true);
269     checkBool(program, callFunction(program, "foo", [], [makeBool(program, true), makeBool(program, false)]), true);
270     checkBool(program, callFunction(program, "foo", [], [makeBool(program, false), makeBool(program, false)]), false);
271     checkBool(program, callFunction(program, "foo", [], [makeBool(program, true), makeBool(program, true)]), false);
272 }
273
274 tests.equalityTypeFailure = function()
275 {
276     checkFail(
277         () => doPrep("bool foo(int x, uint y) { return x == y; }"),
278         (e) => e instanceof WTypeError && e.message.indexOf("/internal/test:1") != -1);
279 }
280
281 tests.generalNegation = function()
282 {
283     let program = doPrep("bool foo(int x) { return !x; }");
284     checkBool(program, callFunction(program, "foo", [], [makeInt(program, 7)]), false);
285     checkBool(program, callFunction(program, "foo", [], [makeInt(program, 0)]), true);
286 }
287
288 tests.add1 = function() {
289     let program = doPrep("int foo(int x) { return x + 1; }");
290     checkInt(program, callFunction(program, "foo", [], [makeInt(program, 42)]), 43);
291 }
292
293 tests.simpleGeneric = function() {
294     let program = doPrep(`
295         T id<T>(T x) { return x; }
296         int foo(int x) { return id(x) + 1; }
297     `);
298     checkInt(program, callFunction(program, "foo", [], [makeInt(program, 42)]), 43);
299 }
300
301 tests.nameResolutionFailure = function()
302 {
303     checkFail(
304         () => doPrep("int foo(int x) { return x + y; }"),
305         (e) => e instanceof WTypeError && e.message.indexOf("/internal/test:1") != -1);
306 }
307
308 tests.simpleVariable = function()
309 {
310     let program = doPrep(`
311         int foo(int p)
312         {
313             int result = p;
314             return result;
315         }
316     `);
317     checkInt(program, callFunction(program, "foo", [], [makeInt(program, 42)]), 42);
318 }
319
320 tests.simpleAssignment = function()
321 {
322     let program = doPrep(`
323         int foo(int p)
324         {
325             int result;
326             result = p;
327             return result;
328         }
329     `);
330     checkInt(program, callFunction(program, "foo", [], [makeInt(program, 42)]), 42);
331 }
332
333 tests.simpleDefault = function()
334 {
335     let program = doPrep(`
336         int foo()
337         {
338             int result;
339             return result;
340         }
341     `);
342     checkInt(program, callFunction(program, "foo", [], []), 0);
343 }
344
345 tests.simpleDereference = function()
346 {
347     let program = doPrep(`
348         int foo(device int* p)
349         {
350             return *p;
351         }
352     `);
353     let buffer = new EBuffer(1);
354     buffer.set(0, 13);
355     checkInt(program, callFunction(program, "foo", [], [TypedValue.box(new PtrType(externalOrigin, "device", program.intrinsics.int32), new EPtr(buffer, 0))]), 13);
356 }
357
358 tests.dereferenceStore = function()
359 {
360     let program = doPrep(`
361         void foo(device int* p)
362         {
363             *p = 52;
364         }
365     `);
366     let buffer = new EBuffer(1);
367     buffer.set(0, 13);
368     callFunction(program, "foo", [], [TypedValue.box(new PtrType(externalOrigin, "device", program.intrinsics.int32), new EPtr(buffer, 0))]);
369     if (buffer.get(0) != 52)
370         throw new Error("Expected buffer to contain 52 but it contains: " + buffer.get(0));
371 }
372
373 tests.simpleMakePtr = function()
374 {
375     let program = doPrep(`
376         thread int* foo()
377         {
378             int x = 42;
379             return &x;
380         }
381     `);
382     let result = callFunction(program, "foo", [], []);
383     if (!result.type.isPtr)
384         throw new Error("Return type is not a pointer: " + result.type);
385     if (!result.type.elementType.equals(program.intrinsics.int32))
386         throw new Error("Return type is not a pointer to an int: " + result.type);
387     if (!(result.value instanceof EPtr))
388         throw new Error("Return value is not an EPtr: " + result.value);
389     let value = result.value.loadValue();
390     if (value != 42)
391         throw new Error("Expected 42 but got: " + value);
392 }
393
394 tests.threadArrayLoad = function()
395 {
396     let program = doPrep(`
397         int foo(thread int[] array)
398         {
399             return array[0u];
400         }
401     `);
402     let buffer = new EBuffer(1);
403     buffer.set(0, 89);
404     let result = callFunction(program, "foo", [], [TypedValue.box(new ArrayRefType(externalOrigin, "thread", program.intrinsics.int32), new EArrayRef(new EPtr(buffer, 0), 1))]);
405     checkInt(program, result, 89);
406 }
407
408 tests.threadArrayLoadIntLiteral = function()
409 {
410     let program = doPrep(`
411         int foo(thread int[] array)
412         {
413             return array[0];
414         }
415     `);
416     let buffer = new EBuffer(1);
417     buffer.set(0, 89);
418     let result = callFunction(program, "foo", [], [TypedValue.box(new ArrayRefType(externalOrigin, "thread", program.intrinsics.int32), new EArrayRef(new EPtr(buffer, 0), 1))]);
419     checkInt(program, result, 89);
420 }
421
422 tests.deviceArrayLoad = function()
423 {
424     let program = doPrep(`
425         int foo(device int[] array)
426         {
427             return array[0u];
428         }
429     `);
430     let buffer = new EBuffer(1);
431     buffer.set(0, 89);
432     let result = callFunction(program, "foo", [], [TypedValue.box(new ArrayRefType(externalOrigin, "device", program.intrinsics.int32), new EArrayRef(new EPtr(buffer, 0), 1))]);
433     checkInt(program, result, 89);
434 }
435
436 tests.threadArrayStore = function()
437 {
438     let program = doPrep(`
439         void foo(thread int[] array, int value)
440         {
441             array[0u] = value;
442         }
443     `);
444     let buffer = new EBuffer(1);
445     buffer.set(0, 15);
446     let arrayRef = TypedValue.box(
447         new ArrayRefType(externalOrigin, "thread", program.intrinsics.int32),
448         new EArrayRef(new EPtr(buffer, 0), 1));
449     callFunction(program, "foo", [], [arrayRef, makeInt(program, 65)]);
450     if (buffer.get(0) != 65)
451         throw new Error("Bad value stored into buffer (expected 65): " + buffer.get(0));
452     callFunction(program, "foo", [], [arrayRef, makeInt(program, -111)]);
453     if (buffer.get(0) != -111)
454         throw new Error("Bad value stored into buffer (expected -111): " + buffer.get(0));
455 }
456
457 tests.deviceArrayStore = function()
458 {
459     let program = doPrep(`
460         void foo(device int[] array, int value)
461         {
462             array[0u] = value;
463         }
464     `);
465     let buffer = new EBuffer(1);
466     buffer.set(0, 15);
467     let arrayRef = TypedValue.box(
468         new ArrayRefType(externalOrigin, "device", program.intrinsics.int32),
469         new EArrayRef(new EPtr(buffer, 0), 1));
470     callFunction(program, "foo", [], [arrayRef, makeInt(program, 65)]);
471     if (buffer.get(0) != 65)
472         throw new Error("Bad value stored into buffer (expected 65): " + buffer.get(0));
473     callFunction(program, "foo", [], [arrayRef, makeInt(program, -111)]);
474     if (buffer.get(0) != -111)
475         throw new Error("Bad value stored into buffer (expected -111): " + buffer.get(0));
476 }
477
478 tests.deviceArrayStoreIntLiteral = function()
479 {
480     let program = doPrep(`
481         void foo(device int[] array, int value)
482         {
483             array[0] = value;
484         }
485     `);
486     let buffer = new EBuffer(1);
487     buffer.set(0, 15);
488     let arrayRef = TypedValue.box(
489         new ArrayRefType(externalOrigin, "device", program.intrinsics.int32),
490         new EArrayRef(new EPtr(buffer, 0), 1));
491     callFunction(program, "foo", [], [arrayRef, makeInt(program, 65)]);
492     if (buffer.get(0) != 65)
493         throw new Error("Bad value stored into buffer (expected 65): " + buffer.get(0));
494     callFunction(program, "foo", [], [arrayRef, makeInt(program, -111)]);
495     if (buffer.get(0) != -111)
496         throw new Error("Bad value stored into buffer (expected -111): " + buffer.get(0));
497 }
498
499 tests.simpleProtocol = function()
500 {
501     let program = doPrep(`
502         protocol MyAddable {
503             MyAddable operator+(MyAddable, MyAddable);
504         }
505         T add<T:MyAddable>(T a, T b)
506         {
507             return a + b;
508         }
509         int foo(int x)
510         {
511             return add(x, 73);
512         }
513     `);
514     checkInt(program, callFunction(program, "foo", [], [makeInt(program, 45)]), 45 + 73);
515 }
516
517 tests.typeMismatchReturn = function()
518 {
519     checkFail(
520         () => doPrep(`
521             int foo()
522             {
523                 return 0u;
524             }
525         `),
526         (e) => e instanceof WTypeError);
527 }
528
529 tests.typeMismatchVariableDecl = function()
530 {
531     checkFail(
532         () => doPrep(`
533             void foo(uint x)
534             {
535                 int y = x;
536             }
537         `),
538         (e) => e instanceof WTypeError);
539 }
540
541 tests.typeMismatchAssignment = function()
542 {
543     checkFail(
544         () => doPrep(`
545             void foo(uint x)
546             {
547                 int y;
548                 y = x;
549             }
550         `),
551         (e) => e instanceof WTypeError);
552 }
553
554 tests.typeMismatchReturnParam = function()
555 {
556     checkFail(
557         () => doPrep(`
558             int foo(uint x)
559             {
560                 return x;
561             }
562         `),
563         (e) => e instanceof WTypeError);
564 }
565
566 tests.badAdd = function()
567 {
568     checkFail(
569         () => doPrep(`
570             void bar<T>(T) { }
571             void foo(int x, uint y)
572             {
573                 bar(x + y);
574             }
575         `),
576         (e) => e instanceof WTypeError && e.message.indexOf("native int32 operator+<>(int32,int32)") != -1);
577 }
578
579 tests.lexerKeyword = function()
580 {
581     let result = doLex("ident for while 123 123u { } {asd asd{ 1a3 1.2 + 3.4 + 1. + .2 1.2d 0.d .3d && ||");
582     if (result.length != 25)
583         throw new Error("Lexer emitted an incorrect number of tokens (expected 23): " + result.length);
584     checkLexerToken(result[0],  0,  "identifier",    "ident");
585     checkLexerToken(result[1],  6,  "keyword",       "for");
586     checkLexerToken(result[2],  10, "keyword",       "while");
587     checkLexerToken(result[3],  16, "intLiteral",    "123");
588     checkLexerToken(result[4],  20, "uintLiteral",   "123u");
589     checkLexerToken(result[5],  25, "punctuation",   "{");
590     checkLexerToken(result[6],  27, "punctuation",   "}");
591     checkLexerToken(result[7],  29, "punctuation",   "{");
592     checkLexerToken(result[8],  30, "identifier",    "asd");
593     checkLexerToken(result[9],  34, "identifier",    "asd");
594     checkLexerToken(result[10], 37, "punctuation",   "{");
595     checkLexerToken(result[11], 39, "intLiteral",    "1");
596     checkLexerToken(result[12], 40, "identifier",    "a3");
597     checkLexerToken(result[13], 43, "floatLiteral",  "1.2");
598     checkLexerToken(result[14], 47, "punctuation",   "+");
599     checkLexerToken(result[15], 49, "floatLiteral",  "3.4");
600     checkLexerToken(result[16], 53, "punctuation",   "+");
601     checkLexerToken(result[17], 55, "floatLiteral",  "1.");
602     checkLexerToken(result[18], 58, "punctuation",   "+");
603     checkLexerToken(result[19], 60, "floatLiteral",  ".2");
604     checkLexerToken(result[20], 63, "floatLiteral",  "1.2d");
605     checkLexerToken(result[21], 68, "floatLiteral",  "0.d");
606     checkLexerToken(result[22], 72, "floatLiteral",  ".3d");
607     checkLexerToken(result[23], 76, "punctuation",   "&&");
608     checkLexerToken(result[24], 79, "punctuation",   "||");
609 }
610
611 tests.simpleNoReturn = function()
612 {
613     checkFail(
614         () => doPrep("int foo() { }"),
615         (e) => e instanceof WTypeError);
616 }
617
618 tests.simpleUnreachableCode = function()
619 {
620     checkFail(
621         () => doPrep(`
622             void foo()
623             {
624                 return;
625                 int x;
626             }
627         `),
628         (e) => e instanceof WTypeError);
629 }
630
631 tests.simpleStruct = function()
632 {
633     let program = doPrep(`
634         struct Foo {
635             int x;
636             int y;
637         }
638         Foo foo(Foo foo)
639         {
640             Foo result;
641             result.x = foo.y;
642             result.y = foo.x;
643             return result;
644         }
645     `);
646     let structType = program.types.get("Foo");
647     if (!structType)
648         throw new Error("Did not find Foo type");
649     let buffer = new EBuffer(2);
650     buffer.set(0, 62);
651     buffer.set(1, 24);
652     let result = callFunction(program, "foo", [], [new TypedValue(structType, new EPtr(buffer, 0))]);
653     if (!result.type.equals(structType))
654         throw new Error("Wrong result type: " + result.type);
655     let x = result.ePtr.get(0);
656     let y = result.ePtr.get(1);
657     if (x != 24)
658         throw new Error("Wrong result for x: " + x + " (y = " + y + ")");
659     if (y != 62)
660         throw new Error("Wrong result for y: " + y + " (x + " + x + ")");
661 }
662
663 tests.genericStructInstance = function()
664 {
665     let program = doPrep(`
666         struct Foo<T> {
667             T x;
668             T y;
669         }
670         Foo<int> foo(Foo<int> foo)
671         {
672             Foo<int> result;
673             result.x = foo.y;
674             result.y = foo.x;
675             return result;
676         }
677     `);
678     let structType = TypeRef.instantiate(program.types.get("Foo"), [program.intrinsics.int32]);
679     let buffer = new EBuffer(2);
680     buffer.set(0, 62);
681     buffer.set(1, 24);
682     let result = callFunction(program, "foo", [], [new TypedValue(structType, new EPtr(buffer, 0))]);
683     let x = result.ePtr.get(0);
684     let y = result.ePtr.get(1);
685     if (x != 24)
686         throw new Error("Wrong result for x: " + x + " (y = " + y + ")");
687     if (y != 62)
688         throw new Error("Wrong result for y: " + y + " (x + " + x + ")");
689 }
690
691 tests.doubleGenericCallsDoubleGeneric = function()
692 {
693     doPrep(`
694         void foo<T, U>(T, U) { }
695         void bar<V, W>(V x, W y) { foo(x, y); }
696     `);
697 }
698
699 tests.doubleGenericCallsSingleGeneric = function()
700 {
701     checkFail(
702         () => doPrep(`
703             void foo<T>(T, T) { }
704             void bar<V, W>(V x, W y) { foo(x, y); }
705         `),
706         (e) => e instanceof WTypeError);
707 }
708
709 tests.loadNull = function()
710 {
711     checkFail(
712         () => doPrep(`
713             void sink<T>(T) { }
714             void foo() { sink(*null); }
715         `),
716         (e) => e instanceof WTypeError && e.message.indexOf("Type passed to dereference is not a pointer: null") != -1);
717 }
718
719 tests.storeNull = function()
720 {
721     checkFail(
722         () => doPrep(`
723             void foo() { *null = 42; }
724         `),
725         (e) => e instanceof WTypeError && e.message.indexOf("Type passed to dereference is not a pointer: null") != -1);
726 }
727
728 tests.returnNull = function()
729 {
730     let program = doPrep(`
731         thread int* foo() { return null; }
732     `);
733     let result = callFunction(program, "foo", [], []);
734     if (!result.type.isPtr)
735         throw new Error("Return type is not a pointer: " + result.type);
736     if (!result.type.elementType.equals(program.intrinsics.int32))
737         throw new Error("Return type is not a pointer to an int: " + result.type);
738     if (result.value != null)
739         throw new Error("Return value is not null: " + result.value);
740 }
741
742 tests.dereferenceDefaultNull = function()
743 {
744     let program = doPrep(`
745         int foo()
746         {
747             thread int* p;
748             return *p;
749         }
750     `);
751     checkFail(
752         () => callFunction(program, "foo", [], []),
753         (e) => e instanceof WTrapError);
754 }
755
756 tests.defaultInitializedNull = function()
757 {
758     let program = doPrep(`
759         int foo()
760         {
761             thread int* p = null;;
762             return *p;
763         }
764     `);
765     checkFail(
766         () => callFunction(program, "foo", [], []),
767         (e) => e instanceof WTrapError);
768 }
769
770 tests.passNullToPtrMonomorphic = function()
771 {
772     let program = doPrep(`
773         int foo(thread int* ptr)
774         {
775             return *ptr;
776         }
777         int bar()
778         {
779             return foo(null);
780         }
781     `);
782     checkFail(
783         () => callFunction(program, "bar", [], []),
784         (e) => e instanceof WTrapError);
785 }
786
787 tests.passNullToPtrPolymorphic = function()
788 {
789     checkFail(
790         () => doPrep(`
791             T foo<T>(thread T* ptr)
792             {
793                 return *ptr;
794             }
795             int bar()
796             {
797                 return foo(null);
798             }
799         `),
800         (e) => e instanceof WTypeError);
801 }
802
803 tests.passNullToPolymorphic = function()
804 {
805     checkFail(
806         () => doPrep(`
807             T foo<T>(T ptr)
808             {
809                 return ptr;
810             }
811             int bar()
812             {
813                 return foo(null);
814             }
815         `),
816         (e) => e instanceof WTypeError);
817 }
818
819 tests.loadNullArrayRef = function()
820 {
821     checkFail(
822         () => doPrep(`
823             void sink<T>(T) { }
824             void foo() { sink(null[0u]); }
825         `),
826         (e) => e instanceof WTypeError && e.message.indexOf("Cannot resolve access") != -1);
827 }
828
829 tests.storeNullArrayRef = function()
830 {
831     checkFail(
832         () => doPrep(`
833             void foo() { null[0u] = 42; }
834         `),
835         (e) => e instanceof WTypeError && e.message.indexOf("Cannot resolve access") != -1);
836 }
837
838 tests.returnNullArrayRef = function()
839 {
840     let program = doPrep(`
841         thread int[] foo() { return null; }
842     `);
843     let result = callFunction(program, "foo", [], []);
844     if (!result.type.isArrayRef)
845         throw new Error("Return type is not an array reference: " + result.type);
846     if (!result.type.elementType.equals(program.intrinsics.int32))
847         throw new Error("Return type is not an int array reference: " + result.type);
848     if (result.value != null)
849         throw new Error("Return value is not null: " + result.value);
850 }
851
852 tests.dereferenceDefaultNullArrayRef = function()
853 {
854     let program = doPrep(`
855         int foo()
856         {
857             thread int[] p;
858             return p[0u];
859         }
860     `);
861     checkFail(
862         () => callFunction(program, "foo", [], []),
863         (e) => e instanceof WTrapError);
864 }
865
866 tests.defaultInitializedNullArrayRef = function()
867 {
868     let program = doPrep(`
869         int foo()
870         {
871             thread int[] p = null;
872             return p[0u];
873         }
874     `);
875     checkFail(
876         () => callFunction(program, "foo", [], []),
877         (e) => e instanceof WTrapError);
878 }
879
880 tests.defaultInitializedNullArrayRefIntLiteral = function()
881 {
882     let program = doPrep(`
883         int foo()
884         {
885             thread int[] p = null;
886             return p[0];
887         }
888     `);
889     checkFail(
890         () => callFunction(program, "foo", [], []),
891         (e) => e instanceof WTrapError);
892 }
893
894 tests.passNullToPtrMonomorphicArrayRef = function()
895 {
896     let program = doPrep(`
897         int foo(thread int[] ptr)
898         {
899             return ptr[0u];
900         }
901         int bar()
902         {
903             return foo(null);
904         }
905     `);
906     checkFail(
907         () => callFunction(program, "bar", [], []),
908         (e) => e instanceof WTrapError);
909 }
910
911 tests.passNullToPtrPolymorphicArrayRef = function()
912 {
913     checkFail(
914         () => doPrep(`
915             T foo<T>(thread T[] ptr)
916             {
917                 return ptr[0u];
918             }
919             int bar()
920             {
921                 return foo(null);
922             }
923         `),
924         (e) => e instanceof WTypeError);
925 }
926
927 tests.returnIntLiteralUint = function()
928 {
929     let program = doPrep("uint foo() { return 42; }");
930     checkNumber(program, callFunction(program, "foo", [], []), 42);
931 }
932
933 tests.returnIntLiteralDouble = function()
934 {
935     let program = doPrep("double foo() { return 42; }");
936     checkNumber(program, callFunction(program, "foo", [], []), 42);
937 }
938
939 tests.badIntLiteralForInt = function()
940 {
941     checkFail(
942         () => doPrep("void foo() { int x = 3000000000; }"),
943         (e) => e instanceof WSyntaxError);
944 }
945
946 tests.badIntLiteralForUint = function()
947 {
948     checkFail(
949         () => doPrep("void foo() { uint x = 5000000000; }"),
950         (e) => e instanceof WSyntaxError);
951 }
952
953 tests.badIntLiteralForDouble = function()
954 {
955     checkFail(
956         () => doPrep("void foo() { double x = 5000000000000000000000000000000000000; }"),
957         (e) => e instanceof WSyntaxError);
958 }
959
960 tests.passNullAndNotNull = function()
961 {
962     let program = doPrep(`
963         T bar<T>(device T* p, device T*)
964         {
965             return *p;
966         }
967         int foo(device int* p)
968         {
969             return bar(p, null);
970         }
971     `);
972     let buffer = new EBuffer(1);
973     buffer.set(0, 13);
974     checkInt(program, callFunction(program, "foo", [], [TypedValue.box(new PtrType(externalOrigin, "device", program.intrinsics.int32), new EPtr(buffer, 0))]), 13);
975 }
976
977 tests.passNullAndNotNullFullPoly = function()
978 {
979     let program = doPrep(`
980         T bar<T>(T p, T)
981         {
982             return p;
983         }
984         int foo(device int* p)
985         {
986             return *bar(p, null);
987         }
988     `);
989     let buffer = new EBuffer(1);
990     buffer.set(0, 13);
991     checkInt(program, callFunction(program, "foo", [], [TypedValue.box(new PtrType(externalOrigin, "device", program.intrinsics.int32), new EPtr(buffer, 0))]), 13);
992 }
993
994 tests.passNullAndNotNullFullPolyReverse = function()
995 {
996     let program = doPrep(`
997         T bar<T>(T, T p)
998         {
999             return p;
1000         }
1001         int foo(device int* p)
1002         {
1003             return *bar(null, p);
1004         }
1005     `);
1006     let buffer = new EBuffer(1);
1007     buffer.set(0, 13);
1008     checkInt(program, callFunction(program, "foo", [], [TypedValue.box(new PtrType(externalOrigin, "device", program.intrinsics.int32), new EPtr(buffer, 0))]), 13);
1009 }
1010
1011 tests.nullTypeVariableUnify = function()
1012 {
1013     let left = new NullType(externalOrigin);
1014     let right = new TypeVariable(externalOrigin, "T", null);
1015     if (left.equals(right))
1016         throw new Error("Should not be equal but are: " + left + " and " + right);
1017     if (right.equals(left))
1018         throw new Error("Should not be equal but are: " + left + " and " + right);
1019     
1020     function everyOrder(array, callback)
1021     {
1022         function recurse(array, callback, order)
1023         {
1024             if (!array.length)
1025                 return callback.call(null, order);
1026             
1027             for (let i = 0; i < array.length; ++i) {
1028                 let nextArray = array.concat();
1029                 nextArray.splice(i, 1);
1030                 recurse(nextArray, callback, order.concat([array[i]]));
1031             }
1032         }
1033         
1034         recurse(array, callback, []);
1035     }
1036     
1037     function everyPair(things)
1038     {
1039         let result = [];
1040         for (let i = 0; i < things.length; ++i) {
1041             for (let j = 0; j < things.length; ++j) {
1042                 if (i != j)
1043                     result.push([things[i], things[j]]);
1044             }
1045         }
1046         return result;
1047     }
1048     
1049     everyOrder(
1050         everyPair(["nullType", "variableType", "ptrType"]),
1051         order => {
1052             let types = {};
1053             types.nullType = new NullType(externalOrigin);
1054             types.variableType = new TypeVariable(externalOrigin, "T", null);
1055             types.ptrType = new PtrType(externalOrigin, "constant", new NativeType(externalOrigin, "foo_t", []));
1056             let unificationContext = new UnificationContext([types.variableType]);
1057             for (let [leftName, rightName] of order) {
1058                 let left = types[leftName];
1059                 let right = types[rightName];
1060                 let result = left.unify(unificationContext, right);
1061                 if (!result)
1062                     throw new Error("In order " + order + " cannot unify " + left + " with " + right);
1063             }
1064             if (!unificationContext.verify().result)
1065                 throw new Error("In order " + order.map(value => "(" + value + ")") + " cannot verify");
1066         });
1067 }
1068
1069 tests.doubleNot = function()
1070 {
1071     let program = doPrep(`
1072         bool foo(bool x)
1073         {
1074             return !!x;
1075         }
1076     `);
1077     checkBool(program, callFunction(program, "foo", [], [makeBool(program, true)]), true);
1078     checkBool(program, callFunction(program, "foo", [], [makeBool(program, false)]), false);
1079 }
1080
1081 tests.simpleRecursion = function()
1082 {
1083     checkFail(
1084         () => doPrep(`
1085             void foo<T>(T x)
1086             {
1087                 foo(&x);
1088             }
1089         `),
1090         (e) => e instanceof WTypeError);
1091 }
1092
1093 tests.protocolMonoSigPolyDef = function()
1094 {
1095     let program = doPrep(`
1096         struct IntAnd<T> {
1097             int first;
1098             T second;
1099         }
1100         IntAnd<T> intAnd<T>(int first, T second)
1101         {
1102             IntAnd<T> result;
1103             result.first = first;
1104             result.second = second;
1105             return result;
1106         }
1107         protocol IntAndable {
1108             IntAnd<int> intAnd(IntAndable, int);
1109         }
1110         int foo<T:IntAndable>(T first, int second)
1111         {
1112             IntAnd<int> result = intAnd(first, second);
1113             return result.first + result.second;
1114         }
1115     `);
1116     checkInt(program, callFunction(program, "foo", [], [makeInt(program, 54), makeInt(program, 12)]), 54 + 12);
1117 }
1118
1119 tests.protocolPolySigPolyDef = function()
1120 {
1121     let program = doPrep(`
1122         struct IntAnd<T> {
1123             int first;
1124             T second;
1125         }
1126         IntAnd<T> intAnd<T>(int first, T second)
1127         {
1128             IntAnd<T> result;
1129             result.first = first;
1130             result.second = second;
1131             return result;
1132         }
1133         protocol IntAndable {
1134             IntAnd<T> intAnd<T>(IntAndable, T);
1135         }
1136         int foo<T:IntAndable>(T first, int second)
1137         {
1138             IntAnd<int> result = intAnd(first, second);
1139             return result.first + result.second;
1140         }
1141     `);
1142     checkInt(program, callFunction(program, "foo", [], [makeInt(program, 54), makeInt(program, 12)]), 54 + 12);
1143 }
1144
1145 tests.protocolDoublePolySigDoublePolyDef = function()
1146 {
1147     let program = doPrep(`
1148         struct IntAnd<T, U> {
1149             int first;
1150             T second;
1151             U third;
1152         }
1153         IntAnd<T, U> intAnd<T, U>(int first, T second, U third)
1154         {
1155             IntAnd<T, U> result;
1156             result.first = first;
1157             result.second = second;
1158             result.third = third;
1159             return result;
1160         }
1161         protocol IntAndable {
1162             IntAnd<T, U> intAnd<T, U>(IntAndable, T, U);
1163         }
1164         int foo<T:IntAndable>(T first, int second, int third)
1165         {
1166             IntAnd<int, int> result = intAnd(first, second, third);
1167             return result.first + result.second + result.third;
1168         }
1169     `);
1170     checkInt(program, callFunction(program, "foo", [], [makeInt(program, 54), makeInt(program, 12), makeInt(program, 39)]), 54 + 12 + 39);
1171 }
1172
1173 tests.protocolDoublePolySigDoublePolyDefExplicit = function()
1174 {
1175     let program = doPrep(`
1176         struct IntAnd<T, U> {
1177             int first;
1178             T second;
1179             U third;
1180         }
1181         IntAnd<T, U> intAnd<T, U>(int first, T second, U third)
1182         {
1183             IntAnd<T, U> result;
1184             result.first = first;
1185             result.second = second;
1186             result.third = third;
1187             return result;
1188         }
1189         protocol IntAndable {
1190             IntAnd<T, U> intAnd<T, U>(IntAndable, T, U);
1191         }
1192         int foo<T:IntAndable>(T first, int second, int third)
1193         {
1194             IntAnd<int, int> result = intAnd<int, int>(first, second, third);
1195             return result.first + result.second + result.third;
1196         }
1197     `);
1198     checkInt(program, callFunction(program, "foo", [], [makeInt(program, 54), makeInt(program, 12), makeInt(program, 39)]), 54 + 12 + 39);
1199 }
1200
1201 tests.variableShadowing = function()
1202 {
1203     let program = doPrep(`
1204         int foo()
1205         {
1206             int y;
1207             int x = 7;
1208             {
1209                 int x = 8;
1210                 y = x;
1211             }
1212             return y;
1213         }
1214     `);
1215     checkInt(program, callFunction(program, "foo", [], []), 8);
1216     program = doPrep(`
1217         int foo()
1218         {
1219             int y;
1220             int x = 7;
1221             {
1222                 int x = 8;
1223             }
1224             y = x;
1225             return y;
1226         }
1227     `);
1228     checkInt(program, callFunction(program, "foo", [], []), 7);
1229 }
1230
1231 tests.ifStatement = function()
1232 {
1233     let program = doPrep(`
1234         int foo(int x)
1235         {
1236             int y = 6;
1237             if (x == 7) {
1238                 y = 8;
1239             }
1240             return y;
1241         }
1242     `);
1243     checkInt(program, callFunction(program, "foo", [], [makeInt(program, 3)]), 6);
1244     checkInt(program, callFunction(program, "foo", [], [makeInt(program, 4)]), 6);
1245     checkInt(program, callFunction(program, "foo", [], [makeInt(program, 5)]), 6);
1246     checkInt(program, callFunction(program, "foo", [], [makeInt(program, 6)]), 6);
1247     checkInt(program, callFunction(program, "foo", [], [makeInt(program, 7)]), 8);
1248     checkInt(program, callFunction(program, "foo", [], [makeInt(program, 8)]), 6);
1249     checkInt(program, callFunction(program, "foo", [], [makeInt(program, 9)]), 6);
1250 }
1251
1252 tests.ifElseStatement = function()
1253 {
1254     let program = doPrep(`
1255         int foo(int x)
1256         {
1257             int y = 6;
1258             if (x == 7) {
1259                 y = 8;
1260             } else {
1261                 y = 9;
1262             }
1263             return y;
1264         }
1265     `);
1266     checkInt(program, callFunction(program, "foo", [], [makeInt(program, 3)]), 9);
1267     checkInt(program, callFunction(program, "foo", [], [makeInt(program, 4)]), 9);
1268     checkInt(program, callFunction(program, "foo", [], [makeInt(program, 5)]), 9);
1269     checkInt(program, callFunction(program, "foo", [], [makeInt(program, 6)]), 9);
1270     checkInt(program, callFunction(program, "foo", [], [makeInt(program, 7)]), 8);
1271     checkInt(program, callFunction(program, "foo", [], [makeInt(program, 8)]), 9);
1272     checkInt(program, callFunction(program, "foo", [], [makeInt(program, 9)]), 9);
1273 }
1274
1275 tests.ifElseIfStatement = function()
1276 {
1277     let program = doPrep(`
1278         int foo(int x)
1279         {
1280             int y = 6;
1281             if (x == 7) {
1282                 y = 8;
1283             } else if (x == 8) {
1284                 y = 9;
1285             }
1286             return y;
1287         }
1288     `);
1289     checkInt(program, callFunction(program, "foo", [], [makeInt(program, 3)]), 6);
1290     checkInt(program, callFunction(program, "foo", [], [makeInt(program, 4)]), 6);
1291     checkInt(program, callFunction(program, "foo", [], [makeInt(program, 5)]), 6);
1292     checkInt(program, callFunction(program, "foo", [], [makeInt(program, 6)]), 6);
1293     checkInt(program, callFunction(program, "foo", [], [makeInt(program, 7)]), 8);
1294     checkInt(program, callFunction(program, "foo", [], [makeInt(program, 8)]), 9);
1295     checkInt(program, callFunction(program, "foo", [], [makeInt(program, 9)]), 6);
1296 }
1297
1298 tests.ifElseIfElseStatement = function()
1299 {
1300     let program = doPrep(`
1301         int foo(int x)
1302         {
1303             int y = 6;
1304             if (x == 7) {
1305                 y = 8;
1306             } else if (x == 8) {
1307                 y = 9;
1308             } else {
1309                 y = 10;
1310             }
1311             return y;
1312         }
1313     `);
1314     checkInt(program, callFunction(program, "foo", [], [makeInt(program, 3)]), 10);
1315     checkInt(program, callFunction(program, "foo", [], [makeInt(program, 4)]), 10);
1316     checkInt(program, callFunction(program, "foo", [], [makeInt(program, 5)]), 10);
1317     checkInt(program, callFunction(program, "foo", [], [makeInt(program, 6)]), 10);
1318     checkInt(program, callFunction(program, "foo", [], [makeInt(program, 7)]), 8);
1319     checkInt(program, callFunction(program, "foo", [], [makeInt(program, 8)]), 9);
1320     checkInt(program, callFunction(program, "foo", [], [makeInt(program, 9)]), 10);
1321 }
1322
1323 tests.returnIf = function()
1324 {
1325     checkFail(
1326         () => doPrep(`
1327             int foo(int x)
1328             {
1329                 int y = 6;
1330                 if (x == 7) {
1331                     return y;
1332                 }
1333             }
1334         `),
1335         (e) => e instanceof WTypeError);
1336     checkFail(
1337         () => doPrep(`
1338             int foo(int x)
1339             {
1340                 int y = 6;
1341                 if (x == 7) {
1342                     return y;
1343                 } else {
1344                     y = 8;
1345                 }
1346             }
1347         `),
1348         (e) => e instanceof WTypeError);
1349     checkFail(
1350         () => doPrep(`
1351             int foo(int x)
1352             {
1353                 int y = 6;
1354                 if (x == 7) {
1355                     y = 8;
1356                 } else {
1357                     return y;
1358                 }
1359             }
1360         `),
1361         (e) => e instanceof WTypeError);
1362     let program = doPrep(`
1363         int foo(int x)
1364         {
1365             int y = 6;
1366             if (x == 7) {
1367                 return 8;
1368             } else {
1369                 return 10;
1370             }
1371         }
1372     `);
1373     checkInt(program, callFunction(program, "foo", [], [makeInt(program, 3)]), 10);
1374     checkInt(program, callFunction(program, "foo", [], [makeInt(program, 4)]), 10);
1375     checkInt(program, callFunction(program, "foo", [], [makeInt(program, 5)]), 10);
1376     checkInt(program, callFunction(program, "foo", [], [makeInt(program, 6)]), 10);
1377     checkInt(program, callFunction(program, "foo", [], [makeInt(program, 7)]), 8);
1378     checkInt(program, callFunction(program, "foo", [], [makeInt(program, 8)]), 10);
1379     checkInt(program, callFunction(program, "foo", [], [makeInt(program, 9)]), 10);
1380     checkFail(
1381         () => doPrep(`
1382             int foo(int x)
1383             {
1384                 int y = 6;
1385                 if (x == 7) {
1386                     return 8;
1387                 } else if (x == 9) {
1388                     return 10;
1389                 }
1390             }
1391         `),
1392         (e) => e instanceof WTypeError);
1393     program = doPrep(`
1394         int foo(int x)
1395         {
1396             int y = 6;
1397             if (x == 7) {
1398                 return 8;
1399             } else {
1400                 y = 9;
1401             }
1402             return y;
1403         }
1404     `);
1405     checkInt(program, callFunction(program, "foo", [], [makeInt(program, 3)]), 9);
1406     checkInt(program, callFunction(program, "foo", [], [makeInt(program, 4)]), 9);
1407     checkInt(program, callFunction(program, "foo", [], [makeInt(program, 5)]), 9);
1408     checkInt(program, callFunction(program, "foo", [], [makeInt(program, 6)]), 9);
1409     checkInt(program, callFunction(program, "foo", [], [makeInt(program, 7)]), 8);
1410     checkInt(program, callFunction(program, "foo", [], [makeInt(program, 8)]), 9);
1411     checkInt(program, callFunction(program, "foo", [], [makeInt(program, 9)]), 9);
1412     checkFail(
1413         () => doPrep(`
1414             int foo(int x)
1415             {
1416                 int y = 6;
1417                 if (x == 7) {
1418                     return 8;
1419                 } else {
1420                     return 10;
1421                 }
1422                 return 11;
1423             }
1424         `),
1425         (e) => e instanceof WTypeError);
1426     program = doPrep(`
1427         int foo(int x)
1428         {
1429             int y = 6;
1430             if (x == 7)
1431                 int y = 8;
1432             return y;
1433         }
1434     `);
1435     checkInt(program, callFunction(program, "foo", [], [makeInt(program, 7)]), 6);
1436 }
1437
1438 tests.simpleWhile = function()
1439 {
1440     let program = doPrep(`
1441         int foo(int x)
1442         {
1443             while (x < 13)
1444                 x = x * 2;
1445             return x;
1446         }
1447     `);
1448     checkInt(program, callFunction(program, "foo", [], [makeInt(program, 1)]), 16);
1449 }
1450
1451 tests.protocolMonoPolySigDoublePolyDefExplicit = function()
1452 {
1453     checkFail(
1454         () => {
1455             let program = doPrep(`
1456                 struct IntAnd<T, U> {
1457                     int first;
1458                     T second;
1459                     U third;
1460                 }
1461                 IntAnd<T, U> intAnd<T, U>(int first, T second, U third)
1462                 {
1463                     IntAnd<T, U> result;
1464                     result.first = first;
1465                     result.second = second;
1466                     result.third = third;
1467                     return result;
1468                 }
1469                 protocol IntAndable {
1470                     IntAnd<T, int> intAnd<T>(IntAndable, T, int);
1471                 }
1472                 int foo<T:IntAndable>(T first, int second, int third)
1473                 {
1474                     IntAnd<int, int> result = intAnd<int>(first, second, third);
1475                     return result.first + result.second + result.third;
1476                 }
1477             `);
1478             callFunction(program, "foo", [], [makeInt(program, 54), makeInt(program, 12), makeInt(program, 39)]);
1479         },
1480         (e) => e instanceof WTypeError);
1481 }
1482
1483 tests.ambiguousOverloadSimple = function()
1484 {
1485     checkFail(
1486         () => doPrep(`
1487             void foo<T>(int, T) { }
1488             void foo<T>(T, int) { }
1489             void bar(int a, int b) { foo(a, b); }
1490         `),
1491         (e) => e instanceof WTypeError);
1492 }
1493
1494 tests.ambiguousOverloadOverlapping = function()
1495 {
1496     checkFail(
1497         () => doPrep(`
1498             void foo<T>(int, T) { }
1499             void foo<T>(T, T) { }
1500             void bar(int a, int b) { foo(a, b); }
1501         `),
1502         (e) => e instanceof WTypeError);
1503 }
1504
1505 tests.ambiguousOverloadTieBreak = function()
1506 {
1507     doPrep(`
1508         void foo<T>(int, T) { }
1509         void foo<T>(T, T) { }
1510         void foo(int, int) { }
1511         void bar(int a, int b) { foo(a, b); }
1512     `);
1513 }
1514
1515 tests.intOverloadResolution = function()
1516 {
1517     let program = doPrep(`
1518         int foo(int) { return 1; }
1519         int foo(uint) { return 2; }
1520         int foo(double) { return 3; }
1521         int bar() { return foo(42); }
1522     `);
1523     checkInt(program, callFunction(program, "bar", [], []), 1);
1524 }
1525
1526 tests.intOverloadResolutionReverseOrder = function()
1527 {
1528     let program = doPrep(`
1529         int foo(double) { return 3; }
1530         int foo(uint) { return 2; }
1531         int foo(int) { return 1; }
1532         int bar() { return foo(42); }
1533     `);
1534     checkInt(program, callFunction(program, "bar", [], []), 1);
1535 }
1536
1537 tests.intOverloadResolutionGeneric = function()
1538 {
1539     let program = doPrep(`
1540         int foo(int) { return 1; }
1541         int foo<T>(T) { return 2; }
1542         int bar() { return foo(42); }
1543     `);
1544     checkInt(program, callFunction(program, "bar", [], []), 1);
1545 }
1546
1547 tests.intLiteralGeneric = function()
1548 {
1549     let program = doPrep(`
1550         int foo<T>(T x) { return 3478; }
1551         int bar() { return foo(42); }
1552     `);
1553     checkInt(program, callFunction(program, "bar", [], []), 3478);
1554 }
1555
1556 tests.intLiteralGenericWithProtocols = function()
1557 {
1558     let program = doPrep(`
1559         protocol MyConvertibleToInt {
1560             operator int(MyConvertibleToInt);
1561         }
1562         int foo<T:MyConvertibleToInt>(T x) { return int(x); }
1563         int bar() { return foo(42); }
1564     `);
1565     checkInt(program, callFunction(program, "bar", [], []), 42);
1566 }
1567
1568 tests.uintLiteralGeneric = function()
1569 {
1570     let program = doPrep(`
1571         int foo<T>(T x) { return 3478; }
1572         int bar() { return foo(42u); }
1573     `);
1574     checkInt(program, callFunction(program, "bar", [], []), 3478);
1575 }
1576
1577 tests.uintLiteralGenericWithProtocols = function()
1578 {
1579     let program = doPrep(`
1580         protocol MyConvertibleToUint {
1581             operator uint(MyConvertibleToUint);
1582         }
1583         uint foo<T:MyConvertibleToUint>(T x) { return uint(x); }
1584         uint bar() { return foo(42u); }
1585     `);
1586     checkUint(program, callFunction(program, "bar", [], []), 42);
1587 }
1588
1589 tests.intLiteralGenericSpecific = function()
1590 {
1591     let program = doPrep(`
1592         T foo<T>(T x) { return x; }
1593         int bar() { return foo(int(42)); }
1594     `);
1595     checkInt(program, callFunction(program, "bar", [], []), 42);
1596 }
1597
1598 tests.simpleConstexpr = function()
1599 {
1600     let program = doPrep(`
1601         int foo<int a>(int b)
1602         {
1603             return a + b;
1604         }
1605         int bar(int b)
1606         {
1607             return foo<42>(b);
1608         }
1609     `);
1610     checkInt(program, callFunction(program, "bar", [], [makeInt(program, 58)]), 58 + 42);
1611 }
1612
1613 tests.break = function()
1614 {
1615     let program = doPrep(`
1616         int foo(int x)
1617         {
1618             while (true) {
1619                 x = x * 2;
1620                 if (x >= 7)
1621                     break;
1622             }
1623             return x;
1624         }
1625     `);
1626     checkInt(program, callFunction(program, "foo", [], [makeInt(program, 1)]), 8);
1627     checkInt(program, callFunction(program, "foo", [], [makeInt(program, 10)]), 20);
1628     program = doPrep(`
1629         int foo(int x)
1630         {
1631             while (true) {
1632                 while (true) {
1633                     x = x * 2;
1634                     if (x >= 7)
1635                         break;
1636                 }
1637                 x = x - 1;
1638                 break;
1639             }
1640             return x;
1641             
1642         }
1643     `);
1644     checkInt(program, callFunction(program, "foo", [], [makeInt(program, 1)]), 7);
1645     checkInt(program, callFunction(program, "foo", [], [makeInt(program, 10)]), 19);
1646     checkFail(
1647         () => doPrep(`
1648             int foo(int x)
1649             {
1650                 while (true) {
1651                     {
1652                         break;
1653                     }
1654                     x = x + 1;
1655                 }
1656                 return x;
1657             }
1658         `),
1659         (e) => e instanceof WTypeError);
1660     checkFail(
1661         () => doPrep(`
1662             int foo(int x)
1663             {
1664                 break;
1665                 return x;
1666             }
1667         `),
1668         (e) => e instanceof WTypeError);
1669     program = doPrep(`
1670             int foo(int x)
1671             {
1672                 while (true) {
1673                     if (x == 7) {
1674                         break;
1675                     }
1676                     x = x + 1;
1677                 }
1678                 return x;
1679             }
1680     `);
1681     checkInt(program, callFunction(program, "foo", [], [makeInt(program, 1)]), 7);
1682     program = doPrep(`
1683             int foo(int x)
1684             {
1685                 while (true) {
1686                     break;
1687                 }
1688                 return x;
1689             }
1690     `);
1691     checkInt(program, callFunction(program, "foo", [], [makeInt(program, 1)]), 1);
1692     program = doPrep(`
1693             int foo()
1694             {
1695                 while (true) {
1696                     return 7;
1697                 }
1698             }
1699     `);
1700     checkInt(program, callFunction(program, "foo", [], []), 7);
1701     checkFail(
1702         () => doPrep(`
1703             int foo(int x)
1704             {
1705                 while(true) {
1706                     break;
1707                     return 7;
1708                 }
1709             }
1710         `),
1711         (e) => e instanceof WTypeError);
1712 }
1713
1714 tests.continue = function()
1715 {
1716     let program = doPrep(`
1717         int foo(int x)
1718         {
1719             while (x < 10) {
1720                 if (x == 8) {
1721                     x = x + 1;
1722                     continue;
1723                 }
1724                 x = x * 2;
1725             }
1726             return x;
1727         }
1728     `);
1729     checkInt(program, callFunction(program, "foo", [], [makeInt(program, 1)]), 18);
1730     checkFail(
1731         () => doPrep(`
1732             int foo(int x)
1733             {
1734                 continue;
1735                 return x;
1736                 
1737             }
1738         `),
1739         (e) => e instanceof WTypeError);
1740 }
1741
1742 tests.doWhile = function()
1743 {
1744     let program = doPrep(`
1745         int foo(int x)
1746         {
1747             int y = 7;
1748             do {
1749                 y = 8;
1750                 break;
1751             } while (x < 10);
1752             return y;
1753         }
1754     `);
1755     checkInt(program, callFunction(program, "foo", [], [makeInt(program, 1)]), 8);
1756     checkInt(program, callFunction(program, "foo", [], [makeInt(program, 11)]), 8);
1757     program = doPrep(`
1758         int foo(int x)
1759         {
1760             int y = 7;
1761             do {
1762                 y = 8;
1763                 break;
1764             } while (y == 7);
1765             return y;
1766         }
1767     `);
1768     checkInt(program, callFunction(program, "foo", [], [makeInt(program, 1)]), 8);
1769     program = doPrep(`
1770         int foo(int x)
1771         {
1772             int sum = 0;
1773             do {
1774                 if (x == 11) {
1775                     x = 15;
1776                     continue;
1777                 }
1778                 sum = sum + x;
1779                 x = x + 1;
1780             } while (x < 13);
1781             return sum;
1782         }
1783     `);
1784     checkInt(program, callFunction(program, "foo", [], [makeInt(program, 9)]), 19);
1785 }
1786
1787 tests.forLoop = function()
1788 {
1789     let program = doPrep(`
1790         int foo(int x)
1791         {
1792             int sum = 0;
1793             int i;
1794             for (i = 0; i < x; i = i + 1) {
1795                 sum = sum + i;
1796             }
1797             return sum;
1798         }
1799     `);
1800     checkInt(program, callFunction(program, "foo", [], [makeInt(program, 3)]), 3);
1801     checkInt(program, callFunction(program, "foo", [], [makeInt(program, 4)]), 6);
1802     checkInt(program, callFunction(program, "foo", [], [makeInt(program, 5)]), 10);
1803     program = doPrep(`
1804         int foo(int x)
1805         {
1806             int sum = 0;
1807             for (int i = 0; i < x; i = i + 1) {
1808                 sum = sum + i;
1809             }
1810             return sum;
1811         }
1812     `);
1813     checkInt(program, callFunction(program, "foo", [], [makeInt(program, 3)]), 3);
1814     checkInt(program, callFunction(program, "foo", [], [makeInt(program, 4)]), 6);
1815     checkInt(program, callFunction(program, "foo", [], [makeInt(program, 5)]), 10);
1816     program = doPrep(`
1817         int foo(int x)
1818         {
1819             int sum = 0;
1820             int i = 100;
1821             for (int i = 0; i < x; i = i + 1) {
1822                 sum = sum + i;
1823             }
1824             return sum;
1825         }
1826     `);
1827     checkInt(program, callFunction(program, "foo", [], [makeInt(program, 3)]), 3);
1828     checkInt(program, callFunction(program, "foo", [], [makeInt(program, 4)]), 6);
1829     checkInt(program, callFunction(program, "foo", [], [makeInt(program, 5)]), 10);
1830     program = doPrep(`
1831         int foo(int x)
1832         {
1833             int sum = 0;
1834             for (int i = 0; i < x; i = i + 1) {
1835                 if (i == 4)
1836                     continue;
1837                 sum = sum + i;
1838             }
1839             return sum;
1840         }
1841     `);
1842     checkInt(program, callFunction(program, "foo", [], [makeInt(program, 3)]), 3);
1843     checkInt(program, callFunction(program, "foo", [], [makeInt(program, 4)]), 6);
1844     checkInt(program, callFunction(program, "foo", [], [makeInt(program, 5)]), 6);
1845     checkInt(program, callFunction(program, "foo", [], [makeInt(program, 6)]), 11);
1846     program = doPrep(`
1847         int foo(int x)
1848         {
1849             int sum = 0;
1850             for (int i = 0; i < x; i = i + 1) {
1851                 if (i == 5)
1852                     break;
1853                 sum = sum + i;
1854             }
1855             return sum;
1856         }
1857     `);
1858     checkInt(program, callFunction(program, "foo", [], [makeInt(program, 3)]), 3);
1859     checkInt(program, callFunction(program, "foo", [], [makeInt(program, 4)]), 6);
1860     checkInt(program, callFunction(program, "foo", [], [makeInt(program, 5)]), 10);
1861     checkInt(program, callFunction(program, "foo", [], [makeInt(program, 6)]), 10);
1862     checkInt(program, callFunction(program, "foo", [], [makeInt(program, 7)]), 10);
1863     program = doPrep(`
1864         int foo(int x)
1865         {
1866             int sum = 0;
1867             for (int i = 0; ; i = i + 1) {
1868                 if (i >= x)
1869                     break;
1870                 sum = sum + i;
1871             }
1872             return sum;
1873         }
1874     `);
1875     checkInt(program, callFunction(program, "foo", [], [makeInt(program, 3)]), 3);
1876     checkInt(program, callFunction(program, "foo", [], [makeInt(program, 4)]), 6);
1877     checkInt(program, callFunction(program, "foo", [], [makeInt(program, 5)]), 10);
1878     checkInt(program, callFunction(program, "foo", [], [makeInt(program, 6)]), 15);
1879     checkInt(program, callFunction(program, "foo", [], [makeInt(program, 7)]), 21);
1880     program = doPrep(`
1881         int foo(int x)
1882         {
1883             int sum = 0;
1884             int i = 0;
1885             for ( ; ; i = i + 1) {
1886                 if (i >= x)
1887                     break;
1888                 sum = sum + i;
1889             }
1890             return sum;
1891         }
1892     `);
1893     checkInt(program, callFunction(program, "foo", [], [makeInt(program, 3)]), 3);
1894     checkInt(program, callFunction(program, "foo", [], [makeInt(program, 4)]), 6);
1895     checkInt(program, callFunction(program, "foo", [], [makeInt(program, 5)]), 10);
1896     checkInt(program, callFunction(program, "foo", [], [makeInt(program, 6)]), 15);
1897     checkInt(program, callFunction(program, "foo", [], [makeInt(program, 7)]), 21);
1898     program = doPrep(`
1899         int foo(int x)
1900         {
1901             int sum = 0;
1902             int i = 0;
1903             for ( ; ; ) {
1904                 if (i >= x)
1905                     break;
1906                 sum = sum + i;
1907                 i = i + 1;
1908             }
1909             return sum;
1910         }
1911     `);
1912     checkInt(program, callFunction(program, "foo", [], [makeInt(program, 3)]), 3);
1913     checkInt(program, callFunction(program, "foo", [], [makeInt(program, 4)]), 6);
1914     checkInt(program, callFunction(program, "foo", [], [makeInt(program, 5)]), 10);
1915     checkInt(program, callFunction(program, "foo", [], [makeInt(program, 6)]), 15);
1916     checkInt(program, callFunction(program, "foo", [], [makeInt(program, 7)]), 21);
1917     checkFail(
1918         () => doPrep(`
1919             void foo(int x)
1920             {
1921                 for (int i = 0; ; i = i + 1) {
1922                     break;
1923                     x = i;
1924                 }
1925             }
1926         `),
1927         (e) => e instanceof WTypeError);
1928     program = doPrep(`
1929         int foo(int x)
1930         {
1931             for ( ; ; ) {
1932                 return 7;
1933             }
1934         }
1935     `);
1936     checkInt(program, callFunction(program, "foo", [], [makeInt(program, 3)]), 7);
1937     checkInt(program, callFunction(program, "foo", [], [makeInt(program, 4)]), 7);
1938     checkInt(program, callFunction(program, "foo", [], [makeInt(program, 5)]), 7);
1939     checkInt(program, callFunction(program, "foo", [], [makeInt(program, 6)]), 7);
1940     checkInt(program, callFunction(program, "foo", [], [makeInt(program, 7)]), 7);
1941     checkFail(
1942         () => doPrep(`
1943             int foo(int x)
1944             {
1945                 for ( ; x < 10; ) {
1946                     return 7;
1947                 }
1948             }
1949         `),
1950         (e) => e instanceof WTypeError);
1951     program = doPrep(`
1952         int foo(int x)
1953         {
1954             for ( ; true; ) {
1955                 return 7;
1956             }
1957         }
1958     `);
1959     checkInt(program, callFunction(program, "foo", [], [makeInt(program, 3)]), 7);
1960     checkInt(program, callFunction(program, "foo", [], [makeInt(program, 4)]), 7);
1961     checkInt(program, callFunction(program, "foo", [], [makeInt(program, 5)]), 7);
1962     checkInt(program, callFunction(program, "foo", [], [makeInt(program, 6)]), 7);
1963     checkInt(program, callFunction(program, "foo", [], [makeInt(program, 7)]), 7);
1964 }
1965
1966 tests.chainConstexpr = function()
1967 {
1968     let program = doPrep(`
1969         int foo<int a>(int b)
1970         {
1971             return a + b;
1972         }
1973         int bar<int a>(int b)
1974         {
1975             return foo<a>(b);
1976         }
1977         int baz(int b)
1978         {
1979             return bar<42>(b);
1980         }
1981     `);
1982     checkInt(program, callFunction(program, "baz", [], [makeInt(program, 58)]), 58 + 42);
1983 }
1984
1985 tests.chainGeneric = function()
1986 {
1987     let program = doPrep(`
1988         T foo<T>(T x)
1989         {
1990             return x;
1991         }
1992         T bar<T>(thread T* ptr)
1993         {
1994             return *foo(ptr);
1995         }
1996         int baz(int x)
1997         {
1998             return bar(&x);
1999         }
2000     `);
2001     checkInt(program, callFunction(program, "baz", [], [makeInt(program, 37)]), 37);
2002 }
2003
2004 tests.chainStruct = function()
2005 {
2006     let program = doPrep(`
2007         struct Foo<T> {
2008             T f;
2009         }
2010         struct Bar<T> {
2011             Foo<thread T*> f;
2012         }
2013         int foo(thread Bar<int>* x)
2014         {
2015             return *x->f.f;
2016         }
2017         int bar(int a)
2018         {
2019             Bar<int> x;
2020             x.f.f = &a;
2021             return foo(&x);
2022         }
2023     `);
2024     checkInt(program, callFunction(program, "bar", [], [makeInt(program, 4657)]), 4657);
2025 }
2026
2027 tests.chainStructNewlyValid = function()
2028 {
2029     let program = doPrep(`
2030         struct Foo<T> {
2031             T f;
2032         }
2033         struct Bar<T> {
2034             Foo<device T*> f;
2035         }
2036         int foo(thread Bar<int>* x)
2037         {
2038             return *x->f.f;
2039         }
2040         int bar(device int* a)
2041         {
2042             Bar<int> x;
2043             x.f.f = a;
2044             return foo(&x);
2045         }
2046     `);
2047     let buffer = new EBuffer(1);
2048     buffer.set(0, 78453);
2049     checkInt(program, callFunction(program, "bar", [], [TypedValue.box(new PtrType(externalOrigin, "device", program.intrinsics.int32), new EPtr(buffer, 0))]), 78453);
2050 }
2051
2052 tests.chainStructDevice = function()
2053 {
2054     let program = doPrep(`
2055         struct Foo<T> {
2056             T f;
2057         }
2058         struct Bar<T> {
2059             Foo<device T*> f;
2060         }
2061         int foo(thread Bar<int>* x)
2062         {
2063             return *x->f.f;
2064         }
2065         int bar(device int* a)
2066         {
2067             Bar<int> x;
2068             x.f.f = a;
2069             return foo(&x);
2070         }
2071     `);
2072     let buffer = new EBuffer(1);
2073     buffer.set(0, 79201);
2074     checkInt(program, callFunction(program, "bar", [], [TypedValue.box(new PtrType(externalOrigin, "device", program.intrinsics.int32), new EPtr(buffer, 0))]), 79201);
2075 }
2076
2077 tests.paramChainStructDevice = function()
2078 {
2079     let program = doPrep(`
2080         struct Foo<T> {
2081             T f;
2082         }
2083         struct Bar<T> {
2084             Foo<T> f;
2085         }
2086         int foo(thread Bar<device int*>* x)
2087         {
2088             return *x->f.f;
2089         }
2090         int bar(device int* a)
2091         {
2092             Bar<device int*> x;
2093             x.f.f = a;
2094             return foo(&x);
2095         }
2096     `);
2097     let buffer = new EBuffer(1);
2098     buffer.set(0, 79201);
2099     checkInt(program, callFunction(program, "bar", [], [TypedValue.box(new PtrType(externalOrigin, "device", program.intrinsics.int32), new EPtr(buffer, 0))]), 79201);
2100 }
2101
2102 tests.simpleProtocolExtends = function()
2103 {
2104     let program = doPrep(`
2105         protocol Foo {
2106             void foo(thread Foo*);
2107         }
2108         protocol Bar : Foo {
2109             void bar(thread Bar*);
2110         }
2111         void fuzz<T:Foo>(thread T* p)
2112         {
2113             foo(p);
2114         }
2115         void buzz<T:Bar>(thread T* p)
2116         {
2117             fuzz(p);
2118             bar(p);
2119         }
2120         void foo(thread int* p)
2121         {
2122             *p = *p + 743;
2123         }
2124         void bar(thread int* p)
2125         {
2126             *p = *p + 91;
2127         }
2128         int thingy(int a)
2129         {
2130             buzz(&a);
2131             return a;
2132         }
2133     `);
2134     checkInt(program, callFunction(program, "thingy", [], [makeInt(program, 642)]), 642 + 743 + 91);
2135 }
2136
2137 tests.protocolExtendsTwo = function()
2138 {
2139     let program = doPrep(`
2140         protocol Foo {
2141             void foo(thread Foo*);
2142         }
2143         protocol Bar {
2144             void bar(thread Bar*);
2145         }
2146         protocol Baz : Foo, Bar {
2147             void baz(thread Baz*);
2148         }
2149         void fuzz<T:Foo>(thread T* p)
2150         {
2151             foo(p);
2152         }
2153         void buzz<T:Bar>(thread T* p)
2154         {
2155             bar(p);
2156         }
2157         void xuzz<T:Baz>(thread T* p)
2158         {
2159             fuzz(p);
2160             buzz(p);
2161             baz(p);
2162         }
2163         void foo(thread int* p)
2164         {
2165             *p = *p + 743;
2166         }
2167         void bar(thread int* p)
2168         {
2169             *p = *p + 91;
2170         }
2171         void baz(thread int* p)
2172         {
2173             *p = *p + 39;
2174         }
2175         int thingy(int a)
2176         {
2177             xuzz(&a);
2178             return a;
2179         }
2180     `);
2181     checkInt(program, callFunction(program, "thingy", [], [makeInt(program, 642)]), 642 + 743 + 91 + 39);
2182 }
2183
2184 tests.prefixPlusPlus = function()
2185 {
2186     let program = doPrep(`
2187         int foo(int x)
2188         {
2189             ++x;
2190             return x;
2191         }
2192     `);
2193     checkInt(program, callFunction(program, "foo", [], [makeInt(program, 64)]), 65);
2194 }
2195
2196 tests.prefixPlusPlusResult = function()
2197 {
2198     let program = doPrep(`
2199         int foo(int x)
2200         {
2201             return ++x;
2202         }
2203     `);
2204     checkInt(program, callFunction(program, "foo", [], [makeInt(program, 64)]), 65);
2205 }
2206
2207 tests.postfixPlusPlus = function()
2208 {
2209     let program = doPrep(`
2210         int foo(int x)
2211         {
2212             x++;
2213             return x;
2214         }
2215     `);
2216     checkInt(program, callFunction(program, "foo", [], [makeInt(program, 64)]), 65);
2217 }
2218
2219 tests.postfixPlusPlusResult = function()
2220 {
2221     let program = doPrep(`
2222         int foo(int x)
2223         {
2224             return x++;
2225         }
2226     `);
2227     checkInt(program, callFunction(program, "foo", [], [makeInt(program, 64)]), 64);
2228 }
2229
2230 tests.prefixMinusMinus = function()
2231 {
2232     let program = doPrep(`
2233         int foo(int x)
2234         {
2235             --x;
2236             return x;
2237         }
2238     `);
2239     checkInt(program, callFunction(program, "foo", [], [makeInt(program, 64)]), 63);
2240 }
2241
2242 tests.prefixMinusMinusResult = function()
2243 {
2244     let program = doPrep(`
2245         int foo(int x)
2246         {
2247             return --x;
2248         }
2249     `);
2250     checkInt(program, callFunction(program, "foo", [], [makeInt(program, 64)]), 63);
2251 }
2252
2253 tests.postfixMinusMinus = function()
2254 {
2255     let program = doPrep(`
2256         int foo(int x)
2257         {
2258             x--;
2259             return x;
2260         }
2261     `);
2262     checkInt(program, callFunction(program, "foo", [], [makeInt(program, 64)]), 63);
2263 }
2264
2265 tests.postfixMinusMinusResult = function()
2266 {
2267     let program = doPrep(`
2268         int foo(int x)
2269         {
2270             return x--;
2271         }
2272     `);
2273     checkInt(program, callFunction(program, "foo", [], [makeInt(program, 64)]), 64);
2274 }
2275
2276 tests.plusEquals = function()
2277 {
2278     let program = doPrep(`
2279         int foo(int x)
2280         {
2281             x += 42;
2282             return x;
2283         }
2284     `);
2285     checkInt(program, callFunction(program, "foo", [], [makeInt(program, 385)]), 385 + 42);
2286 }
2287
2288 tests.plusEqualsResult = function()
2289 {
2290     let program = doPrep(`
2291         int foo(int x)
2292         {
2293             return x += 42;
2294         }
2295     `);
2296     checkInt(program, callFunction(program, "foo", [], [makeInt(program, 385)]), 385 + 42);
2297 }
2298
2299 tests.minusEquals = function()
2300 {
2301     let program = doPrep(`
2302         int foo(int x)
2303         {
2304             x -= 42;
2305             return x;
2306         }
2307     `);
2308     checkInt(program, callFunction(program, "foo", [], [makeInt(program, 385)]), 385 - 42);
2309 }
2310
2311 tests.minusEqualsResult = function()
2312 {
2313     let program = doPrep(`
2314         int foo(int x)
2315         {
2316             return x -= 42;
2317         }
2318     `);
2319     checkInt(program, callFunction(program, "foo", [], [makeInt(program, 385)]), 385 - 42);
2320 }
2321
2322 tests.timesEquals = function()
2323 {
2324     let program = doPrep(`
2325         int foo(int x)
2326         {
2327             x *= 42;
2328             return x;
2329         }
2330     `);
2331     checkInt(program, callFunction(program, "foo", [], [makeInt(program, 385)]), 385 * 42);
2332 }
2333
2334 tests.timesEqualsResult = function()
2335 {
2336     let program = doPrep(`
2337         int foo(int x)
2338         {
2339             return x *= 42;
2340         }
2341     `);
2342     checkInt(program, callFunction(program, "foo", [], [makeInt(program, 385)]), 385 * 42);
2343 }
2344
2345 tests.divideEquals = function()
2346 {
2347     let program = doPrep(`
2348         int foo(int x)
2349         {
2350             x /= 42;
2351             return x;
2352         }
2353     `);
2354     checkInt(program, callFunction(program, "foo", [], [makeInt(program, 385)]), (385 / 42) | 0);
2355 }
2356
2357 tests.divideEqualsResult = function()
2358 {
2359     let program = doPrep(`
2360         int foo(int x)
2361         {
2362             return x /= 42;
2363         }
2364     `);
2365     checkInt(program, callFunction(program, "foo", [], [makeInt(program, 385)]), (385 / 42) | 0);
2366 }
2367
2368 tests.twoIntLiterals = function()
2369 {
2370     let program = doPrep(`
2371         bool foo()
2372         {
2373             return 42 == 42;
2374         }
2375     `);
2376     checkBool(program, callFunction(program, "foo", [], []), true);
2377 }
2378
2379 tests.unifyDifferentLiterals = function()
2380 {
2381     checkFail(
2382         () => doPrep(`
2383             void bar<T>(T, T)
2384             {
2385             }
2386             void foo()
2387             {
2388                 bar(42, 42u);
2389             }
2390         `),
2391         (e) => e instanceof WTypeError);
2392 }
2393
2394 tests.unifyDifferentLiteralsBackwards = function()
2395 {
2396     checkFail(
2397         () => doPrep(`
2398             void bar<T>(T, T)
2399             {
2400             }
2401             void foo()
2402             {
2403                 bar(42u, 42);
2404             }
2405         `),
2406         (e) => e instanceof WTypeError);
2407 }
2408
2409 tests.unifyVeryDifferentLiterals = function()
2410 {
2411     checkFail(
2412         () => doPrep(`
2413             void bar<T>(T, T)
2414             {
2415             }
2416             void foo()
2417             {
2418                 bar(42, null);
2419             }
2420         `),
2421         (e) => e instanceof WTypeError);
2422 }
2423
2424 tests.unifyVeryDifferentLiteralsBackwards = function()
2425 {
2426     checkFail(
2427         () => doPrep(`
2428             void bar<T>(T, T)
2429             {
2430             }
2431             void foo()
2432             {
2433                 bar(null, 42);
2434             }
2435         `),
2436         (e) => e instanceof WTypeError);
2437 }
2438
2439 tests.assignUintToInt = function()
2440 {
2441     checkFail(
2442         () => doPrep(`
2443             void foo()
2444             {
2445                 int x = 42u;
2446             }
2447         `),
2448         (e) => e instanceof WTypeError && e.message.indexOf("Type mismatch in variable initialization") != -1);
2449 }
2450
2451 tests.buildArrayThenSumIt = function()
2452 {
2453     let program = doPrep(`
2454         int foo()
2455         {
2456             int[42] array;
2457             for (uint i = 0; i < 42; i = i + 1)
2458                 array[i] = int(i + 5);
2459             int result;
2460             for (uint i = 0; i < 42; i = i + 1)
2461                 result = result + array[i];
2462             return result;
2463         }
2464     `);
2465     checkInt(program, callFunction(program, "foo", [], []), 42 * 5 + 42 * 41 / 2);
2466 }
2467
2468 tests.buildArrayThenSumItUsingArrayReference = function()
2469 {
2470     let program = doPrep(`
2471         int bar(thread int[] array)
2472         {
2473             for (uint i = 0; i < 42; i = i + 1)
2474                 array[i] = int(i + 5);
2475             int result;
2476             for (uint i = 0; i < 42; i = i + 1)
2477                 result = result + array[i];
2478             return result;
2479         }
2480         int foo()
2481         {
2482             int[42] array;
2483             return bar(@array);
2484         }
2485     `);
2486     checkInt(program, callFunction(program, "foo", [], []), 42 * 5 + 42 * 41 / 2);
2487 }
2488
2489 tests.overrideSubscriptStruct = function()
2490 {
2491     let program = doPrep(`
2492         struct Foo {
2493             int x;
2494             int y;
2495         }
2496         thread int* operator&[](thread Foo* foo, uint index)
2497         {
2498             if (index == 0)
2499                 return &foo->x;
2500             if (index == 1)
2501                 return &foo->y;
2502             return null;
2503         }
2504         int foo()
2505         {
2506             Foo foo;
2507             foo.x = 498;
2508             foo.y = 19;
2509             return foo[0] + foo[1] * 3;
2510         }
2511     `);
2512     checkInt(program, callFunction(program, "foo", [], []), 498 + 19 * 3);
2513 }
2514
2515 tests.overrideSubscriptStructAndDoStores = function()
2516 {
2517     let program = doPrep(`
2518         struct Foo {
2519             int x;
2520             int y;
2521         }
2522         thread int* operator&[](thread Foo* foo, uint index)
2523         {
2524             if (index == 0)
2525                 return &foo->x;
2526             if (index == 1)
2527                 return &foo->y;
2528             return null;
2529         }
2530         int foo()
2531         {
2532             Foo foo;
2533             foo[0] = 498;
2534             foo[1] = 19;
2535             return foo.x + foo.y;
2536         }
2537     `);
2538     checkInt(program, callFunction(program, "foo", [], []), 498 + 19);
2539 }
2540
2541 tests.overrideSubscriptStructAndUsePointers = function()
2542 {
2543     let program = doPrep(`
2544         struct Foo {
2545             int x;
2546             int y;
2547         }
2548         thread int* operator&[](thread Foo* foo, uint index)
2549         {
2550             if (index == 0)
2551                 return &foo->x;
2552             if (index == 1)
2553                 return &foo->y;
2554             return null;
2555         }
2556         int bar(thread Foo* foo)
2557         {
2558             return (*foo)[0] + (*foo)[1];
2559         }
2560         int foo()
2561         {
2562             Foo foo;
2563             foo.x = 498;
2564             foo.y = 19;
2565             return bar(&foo);
2566         }
2567     `);
2568     checkInt(program, callFunction(program, "foo", [], []), 498 + 19);
2569 }
2570
2571 tests.overrideSubscriptStructAndUsePointersIncorrectly = function()
2572 {
2573     checkFail(
2574         () => doPrep(`
2575             struct Foo {
2576                 int x;
2577                 int y;
2578             }
2579             thread int* operator&[](thread Foo* foo, uint index)
2580             {
2581                 if (index == 0)
2582                     return &foo->x;
2583                 if (index == 1)
2584                     return &foo->y;
2585                 return null;
2586             }
2587             int bar(thread Foo* foo)
2588             {
2589                 return foo[0] + foo[1];
2590             }
2591             int foo()
2592             {
2593                 Foo foo;
2594                 foo.x = 498;
2595                 foo.y = 19;
2596                 return bar(&foo);
2597             }
2598         `),
2599         (e) => e instanceof WTypeError);
2600 }
2601
2602 tests.makeArrayRefFromLocal = function()
2603 {
2604     let program = doPrep(`
2605         int bar(thread int[] ref)
2606         {
2607             return ref[0];
2608         }
2609         int foo()
2610         {
2611             int x = 48;
2612             return bar(@x);
2613         }
2614     `);
2615     checkInt(program, callFunction(program, "foo", [], []), 48);
2616 }
2617
2618 tests.makeArrayRefFromPointer = function()
2619 {
2620     let program = doPrep(`
2621         int bar(thread int[] ref)
2622         {
2623             return ref[0];
2624         }
2625         int baz(thread int* ptr)
2626         {
2627             return bar(@ptr);
2628         }
2629         int foo()
2630         {
2631             int x = 48;
2632             return baz(&x);
2633         }
2634     `);
2635     checkInt(program, callFunction(program, "foo", [], []), 48);
2636 }
2637
2638 tests.makeArrayRefFromArrayRef = function()
2639 {
2640     checkFail(
2641         () => doPrep(`
2642             int bar(thread int[] ref)
2643             {
2644                 return ref[0];
2645             }
2646             int baz(thread int[] ptr)
2647             {
2648                 return bar(@ptr);
2649             }
2650             int foo()
2651             {
2652                 int x = 48;
2653                 return baz(@x);
2654             }
2655         `),
2656         (e) => e instanceof WTypeError);
2657 }
2658
2659 tests.simpleLength = function()
2660 {
2661     let program = doPrep(`
2662         uint foo()
2663         {
2664             double[754] array;
2665             return (@array).length;
2666         }
2667     `);
2668     checkUint(program, callFunction(program, "foo", [], []), 754);
2669 }
2670
2671 tests.nonArrayRefArrayLengthSucceed = function()
2672 {
2673     let program = doPrep(`
2674         uint foo()
2675         {
2676             double[754] array;
2677             return array.length;
2678         }
2679     `);
2680     checkUint(program, callFunction(program, "foo", [], []), 754);
2681 }
2682
2683 tests.nonArrayRefArrayLengthFail = function()
2684 {
2685     checkFail(
2686         () => doPrep(`
2687             thread uint* lengthPtr()
2688             {
2689                 int[42] array;
2690                 return &(array.length);
2691             }
2692         `),
2693         e => e instanceof WTypeError);
2694 }
2695
2696 tests.constexprIsNotLValuePtr = function()
2697 {
2698     checkFail(
2699         () => doPrep(`
2700             thread int* foo<int x>()
2701             {
2702                 return &x;
2703             }
2704         `),
2705         e => e instanceof WTypeError);
2706 }
2707
2708 tests.constexprIsNotLValueAssign = function()
2709 {
2710     checkFail(
2711         () => doPrep(`
2712             void foo<int x>()
2713             {
2714                 x = 42;
2715             }
2716         `),
2717         e => e instanceof WTypeError);
2718 }
2719
2720 tests.constexprIsNotLValueRMW = function()
2721 {
2722     checkFail(
2723         () => doPrep(`
2724             void foo<int x>()
2725             {
2726                 x += 42;
2727             }
2728         `),
2729         e => e instanceof WTypeError);
2730 }
2731
2732 tests.assignLength = function()
2733 {
2734     checkFail(
2735         () => doPrep(`
2736             void foo()
2737             {
2738                 double[754] array;
2739                 (@array).length = 42;
2740             }
2741         `),
2742         (e) => e instanceof WTypeError && e.message.indexOf("Have neither ander nor setter") != -1);
2743 }
2744
2745 tests.assignLengthHelper = function()
2746 {
2747     checkFail(
2748         () => doPrep(`
2749             void bar(thread double[] array)
2750             {
2751                 array.length = 42;
2752             }
2753             void foo()
2754             {
2755                 double[754] array;
2756                 bar(@array);
2757             }
2758         `),
2759         (e) => e instanceof WTypeError && e.message.indexOf("Have neither ander nor setter") != -1);
2760 }
2761
2762 tests.simpleGetter = function()
2763 {
2764     let program = doPrep(`
2765         struct Foo {
2766             int x;
2767         }
2768         int operator.y(Foo foo)
2769         {
2770             return foo.x;
2771         }
2772         int foo()
2773         {
2774             Foo foo;
2775             foo.x = 7804;
2776             return foo.y;
2777         }
2778     `);
2779     checkInt(program, callFunction(program, "foo", [], []), 7804);
2780 }
2781
2782 tests.simpleSetter = function()
2783 {
2784     let program = doPrep(`
2785         struct Foo {
2786             int x;
2787         }
2788         int operator.y(Foo foo)
2789         {
2790             return foo.x;
2791         }
2792         Foo operator.y=(Foo foo, int value)
2793         {
2794             foo.x = value;
2795             return foo;
2796         }
2797         int foo()
2798         {
2799             Foo foo;
2800             foo.y = 7804;
2801             return foo.x;
2802         }
2803     `);
2804     checkInt(program, callFunction(program, "foo", [], []), 7804);
2805 }
2806
2807 tests.genericAccessors = function()
2808 {
2809     let program = doPrep(`
2810         struct Foo<T> {
2811             T x;
2812             T[3] y;
2813         }
2814         struct Bar<T> {
2815             T x;
2816             T y;
2817         }
2818         Bar<T> operator.z<T>(Foo<T> foo)
2819         {
2820             Bar<T> result;
2821             result.x = foo.x;
2822             result.y = foo.y[1];
2823             return result;
2824         }
2825         Foo<T> operator.z=<T>(Foo<T> foo, Bar<T> bar)
2826         {
2827             foo.x = bar.x;
2828             foo.y[1] = bar.y;
2829             return foo;
2830         }
2831         T operator.sum<T:Addable>(Foo<T> foo)
2832         {
2833             return foo.x + foo.y[0] + foo.y[1] + foo.y[2];
2834         }
2835         T operator.sum<T:Addable>(Bar<T> bar)
2836         {
2837             return bar.x + bar.y;
2838         }
2839         operator<T> Bar<T>(T x, T y)
2840         {
2841             Bar<T> result;
2842             result.x = x;
2843             result.y = y;
2844             return result;
2845         }
2846         void setup(thread Foo<int>* foo)
2847         {
2848             foo->x = 1;
2849             foo->y[0] = 2;
2850             foo->y[1] = 3;
2851             foo->y[2] = 4;
2852         }
2853         int testSuperBasic()
2854         {
2855             Foo<int> foo;
2856             setup(&foo);
2857             return foo.sum;
2858         }
2859         int testZSetterDidSetY()
2860         {
2861             Foo<int> foo;
2862             foo.z = Bar<int>(53, 932);
2863             return foo.y[1];
2864         }
2865         int testZSetter()
2866         {
2867             Foo<int> foo;
2868             foo.z = Bar<int>(53, 932);
2869             return foo.sum;
2870         }
2871         int testZGetter()
2872         {
2873             Foo<int> foo;
2874             // This deliberately does not call setup() just so we test this syntax.
2875             foo.x = 1;
2876             foo.y[0] = 2;
2877             foo.y[1] = 3;
2878             foo.y[2] = 4;
2879             return foo.z.sum;
2880         }
2881         int testLValueEmulation()
2882         {
2883             Foo<int> foo;
2884             setup(&foo);
2885             foo.z.y *= 5;
2886             return foo.sum;
2887         }
2888     `);
2889     checkInt(program, callFunction(program, "testSuperBasic", [], []), 1 + 2 + 3 + 4);
2890     checkInt(program, callFunction(program, "testZSetterDidSetY", [], []), 932);
2891     checkInt(program, callFunction(program, "testZSetter", [], []), 53 + 932);
2892     checkInt(program, callFunction(program, "testZGetter", [], []), 1 + 3);
2893     checkInt(program, callFunction(program, "testLValueEmulation", [], []), 1 + 2 + 3 * 5 + 4);
2894 }
2895
2896 tests.bitSubscriptAccessor = function()
2897 {
2898     let program = doPrep(`
2899         protocol MyBitmaskable : Equatable {
2900             MyBitmaskable operator&(MyBitmaskable, MyBitmaskable);
2901             MyBitmaskable operator|(MyBitmaskable, MyBitmaskable);
2902             MyBitmaskable operator~(MyBitmaskable);
2903             MyBitmaskable operator<<(MyBitmaskable, uint);
2904             MyBitmaskable operator>>(MyBitmaskable, uint);
2905             operator MyBitmaskable(int);
2906         }
2907         T maskForBitIndex<T:MyBitmaskable>(uint index)
2908         {
2909             return T(1) << index;
2910         }
2911         bool operator[]<T:MyBitmaskable>(T value, uint index)
2912         {
2913             return bool(value & maskForBitIndex<T>(index));
2914         }
2915         T operator[]=<T:MyBitmaskable>(T value, uint index, bool bit)
2916         {
2917             T mask = maskForBitIndex<T>(index);
2918             if (bit)
2919                 value |= mask;
2920             else
2921                 value &= ~mask;
2922             return value;
2923         }
2924         uint operator.length(int)
2925         {
2926             return 32;
2927         }
2928         uint operator.length(uint)
2929         {
2930             return 32;
2931         }
2932         int testIntSetBit3()
2933         {
2934             int foo;
2935             foo[3] = true;
2936             return foo;
2937         }
2938         bool testIntSetGetBit5()
2939         {
2940             int foo;
2941             foo[5] = true;
2942             return foo[5];
2943         }
2944         bool testIntGetBit1()
2945         {
2946             int foo;
2947             return foo[1];
2948         }
2949         int testUintSumBits()
2950         {
2951             int foo = 42;
2952             int result;
2953             for (uint i = 0; i < foo.length; ++i) {
2954                 if (foo[i])
2955                     result++;
2956             }
2957             return result;
2958         }
2959         int testUintSwapBits()
2960         {
2961             int foo = 42;
2962             for (uint i = 0; i < foo.length / 2; ++i) {
2963                 bool tmp = foo[i];
2964                 foo[i] = foo[foo.length - i - 1];
2965                 foo[foo.length - i - 1] = tmp;
2966             }
2967             return foo;
2968         }
2969         struct Foo {
2970             uint f;
2971             uint g;
2972         }
2973         operator Foo(uint f, uint g)
2974         {
2975             Foo result;
2976             result.f = f;
2977             result.g = g;
2978             return result;
2979         }
2980         int operator.h(Foo foo)
2981         {
2982             return int((foo.f & 0xffff) | ((foo.g & 0xffff) << 16));
2983         }
2984         Foo operator.h=(Foo foo, int value)
2985         {
2986             foo.f &= ~0xffffu;
2987             foo.f |= uint(value) & 0xffff;
2988             foo.g &= ~0xffffu;
2989             foo.g |= (uint(value) >> 16) & 0xffff;
2990             return foo;
2991         }
2992         int testLValueEmulation()
2993         {
2994             Foo foo;
2995             foo.f = 42;
2996             foo.g = 37;
2997             for (uint i = 0; i < foo.h.length; ++i)
2998                 foo.h[i] ^= true;
2999             return int(foo.f + foo.g);
3000         }
3001         struct Bar {
3002             Foo a;
3003             Foo b;
3004         }
3005         Foo operator.c(Bar bar)
3006         {
3007             return Foo(uint(bar.a.h), uint(bar.b.h));
3008         }
3009         Bar operator.c=(Bar bar, Foo foo)
3010         {
3011             bar.a.h = int(foo.f);
3012             bar.b.h = int(foo.g);
3013             return bar;
3014         }
3015         int testCrazyLValueEmulation()
3016         {
3017             Bar bar;
3018             bar.a.f = 1;
3019             bar.a.g = 2;
3020             bar.b.f = 3;
3021             bar.b.g = 4;
3022             for (uint i = 0; i < bar.c.h.length; i += 2)
3023                 bar.c.h[i] ^= true;
3024             return int(bar.a.f + bar.a.g + bar.b.f + bar.b.g);
3025         }
3026     `);
3027     checkInt(program, callFunction(program, "testIntSetBit3", [], []), 8);
3028     checkBool(program, callFunction(program, "testIntSetGetBit5", [], []), true);
3029     checkBool(program, callFunction(program, "testIntGetBit1", [], []), false);
3030     checkInt(program, callFunction(program, "testUintSumBits", [], []), 3);
3031     checkInt(program, callFunction(program, "testUintSwapBits", [], []), 1409286144);
3032     checkInt(program, callFunction(program, "testLValueEmulation", [], []), 130991);
3033     checkInt(program, callFunction(program, "testCrazyLValueEmulation", [], []), 43696);
3034 }
3035
3036 tests.nestedSubscriptLValueEmulationSimple = function()
3037 {
3038     let program = doPrep(`
3039         struct Foo {
3040             int[7] array;
3041         }
3042         int operator[](Foo foo, uint index)
3043         {
3044             return foo.array[index];
3045         }
3046         Foo operator[]=(Foo foo, uint index, int value)
3047         {
3048             foo.array[index] = value;
3049             return foo;
3050         }
3051         uint operator.length(Foo foo)
3052         {
3053             return foo.array.length;
3054         }
3055         int sum(Foo foo)
3056         {
3057             int result = 0;
3058             for (uint i = foo.length; i--;)
3059                 result += foo[i];
3060             return result;
3061         }
3062         struct Bar {
3063             Foo[6] array;
3064         }
3065         uint operator.length(Bar bar)
3066         {
3067             return bar.array.length;
3068         }
3069         Foo operator[](Bar bar, uint index)
3070         {
3071             return bar.array[index];
3072         }
3073         Bar operator[]=(Bar bar, uint index, Foo value)
3074         {
3075             bar.array[index] = value;
3076             return bar;
3077         }
3078         int sum(Bar bar)
3079         {
3080             int result = 0;
3081             for (uint i = bar.length; i--;)
3082                 result += sum(bar[i]);
3083             return result;
3084         }
3085         struct Baz {
3086             Bar[5] array;
3087         }
3088         Bar operator[](Baz baz, uint index)
3089         {
3090             return baz.array[index];
3091         }
3092         Baz operator[]=(Baz baz, uint index, Bar value)
3093         {
3094             baz.array[index] = value;
3095             return baz;
3096         }
3097         uint operator.length(Baz baz)
3098         {
3099             return baz.array.length;
3100         }
3101         int sum(Baz baz)
3102         {
3103             int result = 0;
3104             for (uint i = baz.length; i--;)
3105                 result += sum(baz[i]);
3106             return result;
3107         }
3108         void setValues(thread Baz* baz)
3109         {
3110             for (uint i = baz->length; i--;) {
3111                 for (uint j = (*baz)[i].length; j--;) {
3112                     for (uint k = (*baz)[i][j].length; k--;)
3113                         (*baz)[i][j][k] = int(i + j + k);
3114                 }
3115             }
3116         }
3117         int testSetValuesAndSum()
3118         {
3119             Baz baz;
3120             setValues(&baz);
3121             return sum(baz);
3122         }
3123         int testSetValuesMutateValuesAndSum()
3124         {
3125             Baz baz;
3126             setValues(&baz);
3127             for (uint i = baz.length; i--;) {
3128                 for (uint j = baz[i].length; j--;) {
3129                     for (uint k = baz[i][j].length; k--;)
3130                         baz[i][j][k] *= int(k);
3131                 }
3132             }
3133             return sum(baz);
3134         }
3135     `);
3136     checkInt(program, callFunction(program, "testSetValuesAndSum", [], []), 1575);
3137     checkInt(program, callFunction(program, "testSetValuesMutateValuesAndSum", [], []), 5565);
3138 }
3139
3140 tests.nestedSubscriptLValueEmulationGeneric = function()
3141 {
3142     let program = doPrep(`
3143         struct Foo<T> {
3144             T[7] array;
3145         }
3146         T operator[]<T>(Foo<T> foo, uint index)
3147         {
3148             return foo.array[index];
3149         }
3150         Foo<T> operator[]=<T>(Foo<T> foo, uint index, T value)
3151         {
3152             foo.array[index] = value;
3153             return foo;
3154         }
3155         uint operator.length<T>(Foo<T> foo)
3156         {
3157             return foo.array.length;
3158         }
3159         protocol MyAddable {
3160             MyAddable operator+(MyAddable, MyAddable);
3161         }
3162         T sum<T:MyAddable>(Foo<T> foo)
3163         {
3164             T result;
3165             for (uint i = foo.length; i--;)
3166                 result += foo[i];
3167             return result;
3168         }
3169         struct Bar<T> {
3170             Foo<T>[6] array;
3171         }
3172         uint operator.length<T>(Bar<T> bar)
3173         {
3174             return bar.array.length;
3175         }
3176         Foo<T> operator[]<T>(Bar<T> bar, uint index)
3177         {
3178             return bar.array[index];
3179         }
3180         Bar<T> operator[]=<T>(Bar<T> bar, uint index, Foo<T> value)
3181         {
3182             bar.array[index] = value;
3183             return bar;
3184         }
3185         T sum<T:MyAddable>(Bar<T> bar)
3186         {
3187             T result;
3188             for (uint i = bar.length; i--;)
3189                 result += sum(bar[i]);
3190             return result;
3191         }
3192         struct Baz<T> {
3193             Bar<T>[5] array;
3194         }
3195         Bar<T> operator[]<T>(Baz<T> baz, uint index)
3196         {
3197             return baz.array[index];
3198         }
3199         Baz<T> operator[]=<T>(Baz<T> baz, uint index, Bar<T> value)
3200         {
3201             baz.array[index] = value;
3202             return baz;
3203         }
3204         uint operator.length<T>(Baz<T> baz)
3205         {
3206             return baz.array.length;
3207         }
3208         T sum<T:MyAddable>(Baz<T> baz)
3209         {
3210             T result;
3211             for (uint i = baz.length; i--;)
3212                 result += sum(baz[i]);
3213             return result;
3214         }
3215         protocol MyConvertibleFromUint {
3216             operator MyConvertibleFromUint(uint);
3217         }
3218         protocol SetValuable : MyAddable, MyConvertibleFromUint { }
3219         void setValues<T:SetValuable>(thread Baz<T>* baz)
3220         {
3221             for (uint i = baz->length; i--;) {
3222                 for (uint j = (*baz)[i].length; j--;) {
3223                     for (uint k = (*baz)[i][j].length; k--;)
3224                         (*baz)[i][j][k] = T(i + j + k);
3225                 }
3226             }
3227         }
3228         int testSetValuesAndSum()
3229         {
3230             Baz<int> baz;
3231             setValues(&baz);
3232             return sum(baz);
3233         }
3234         int testSetValuesMutateValuesAndSum()
3235         {
3236             Baz<int> baz;
3237             setValues(&baz);
3238             for (uint i = baz.length; i--;) {
3239                 for (uint j = baz[i].length; j--;) {
3240                     for (uint k = baz[i][j].length; k--;)
3241                         baz[i][j][k] *= int(k);
3242                 }
3243             }
3244             return sum(baz);
3245         }
3246     `);
3247     checkInt(program, callFunction(program, "testSetValuesAndSum", [], []), 1575);
3248     checkInt(program, callFunction(program, "testSetValuesMutateValuesAndSum", [], []), 5565);
3249 }
3250
3251 tests.boolBitAnd = function()
3252 {
3253     let program = doPrep(`
3254         bool foo(bool a, bool b)
3255         {
3256             return a & b;
3257         }
3258     `);
3259     checkBool(program, callFunction(program, "foo", [], [makeBool(program, false), makeBool(program, false)]), false);
3260     checkBool(program, callFunction(program, "foo", [], [makeBool(program, true), makeBool(program, false)]), false);
3261     checkBool(program, callFunction(program, "foo", [], [makeBool(program, false), makeBool(program, true)]), false);
3262     checkBool(program, callFunction(program, "foo", [], [makeBool(program, true), makeBool(program, true)]), true);
3263 }
3264
3265 tests.boolBitOr = function()
3266 {
3267     let program = doPrep(`
3268         bool foo(bool a, bool b)
3269         {
3270             return a | b;
3271         }
3272     `);
3273     checkBool(program, callFunction(program, "foo", [], [makeBool(program, false), makeBool(program, false)]), false);
3274     checkBool(program, callFunction(program, "foo", [], [makeBool(program, true), makeBool(program, false)]), true);
3275     checkBool(program, callFunction(program, "foo", [], [makeBool(program, false), makeBool(program, true)]), true);
3276     checkBool(program, callFunction(program, "foo", [], [makeBool(program, true), makeBool(program, true)]), true);
3277 }
3278
3279 tests.boolBitXor = function()
3280 {
3281     let program = doPrep(`
3282         bool foo(bool a, bool b)
3283         {
3284             return a ^ b;
3285         }
3286     `);
3287     checkBool(program, callFunction(program, "foo", [], [makeBool(program, false), makeBool(program, false)]), false);
3288     checkBool(program, callFunction(program, "foo", [], [makeBool(program, true), makeBool(program, false)]), true);
3289     checkBool(program, callFunction(program, "foo", [], [makeBool(program, false), makeBool(program, true)]), true);
3290     checkBool(program, callFunction(program, "foo", [], [makeBool(program, true), makeBool(program, true)]), false);
3291 }
3292
3293 tests.boolBitNot = function()
3294 {
3295     let program = doPrep(`
3296         bool foo(bool a)
3297         {
3298             return ~a;
3299         }
3300     `);
3301     checkBool(program, callFunction(program, "foo", [], [makeBool(program, false)]), true);
3302     checkBool(program, callFunction(program, "foo", [], [makeBool(program, true)]), false);
3303 }
3304
3305 tests.intBitAnd = function()
3306 {
3307     let program = doPrep(`
3308         int foo(int a, int b)
3309         {
3310             return a & b;
3311         }
3312     `);
3313     checkInt(program, callFunction(program, "foo", [], [makeInt(program, 1), makeInt(program, 7)]), 1);
3314     checkInt(program, callFunction(program, "foo", [], [makeInt(program, 65535), makeInt(program, 42)]), 42);
3315     checkInt(program, callFunction(program, "foo", [], [makeInt(program, -1), makeInt(program, -7)]), -7);
3316     checkInt(program, callFunction(program, "foo", [], [makeInt(program, 0), makeInt(program, 85732)]), 0);
3317 }
3318
3319 tests.intBitOr = function()
3320 {
3321     let program = doPrep(`
3322         int foo(int a, int b)
3323         {
3324             return a | b;
3325         }
3326     `);
3327     checkInt(program, callFunction(program, "foo", [], [makeInt(program, 1), makeInt(program, 7)]), 7);
3328     checkInt(program, callFunction(program, "foo", [], [makeInt(program, 65535), makeInt(program, 42)]), 65535);
3329     checkInt(program, callFunction(program, "foo", [], [makeInt(program, -1), makeInt(program, -7)]), -1);
3330     checkInt(program, callFunction(program, "foo", [], [makeInt(program, 0), makeInt(program, 85732)]), 85732);
3331 }
3332
3333 tests.intBitXor = function()
3334 {
3335     let program = doPrep(`
3336         int foo(int a, int b)
3337         {
3338             return a ^ b;
3339         }
3340     `);
3341     checkInt(program, callFunction(program, "foo", [], [makeInt(program, 1), makeInt(program, 7)]), 6);
3342     checkInt(program, callFunction(program, "foo", [], [makeInt(program, 65535), makeInt(program, 42)]), 65493);
3343     checkInt(program, callFunction(program, "foo", [], [makeInt(program, -1), makeInt(program, -7)]), 6);
3344     checkInt(program, callFunction(program, "foo", [], [makeInt(program, 0), makeInt(program, 85732)]), 85732);
3345 }
3346
3347 tests.intBitNot = function()
3348 {
3349     let program = doPrep(`
3350         int foo(int a)
3351         {
3352             return ~a;
3353         }
3354     `);
3355     checkInt(program, callFunction(program, "foo", [], [makeInt(program, 1)]), -2);
3356     checkInt(program, callFunction(program, "foo", [], [makeInt(program, 65535)]), -65536);
3357     checkInt(program, callFunction(program, "foo", [], [makeInt(program, -1)]), 0);
3358     checkInt(program, callFunction(program, "foo", [], [makeInt(program, 0)]), -1);
3359 }
3360
3361 tests.intLShift = function()
3362 {
3363     let program = doPrep(`
3364         int foo(int a, uint b)
3365         {
3366             return a << b;
3367         }
3368     `);
3369     checkInt(program, callFunction(program, "foo", [], [makeInt(program, 1), makeUint(program, 7)]), 128);
3370     checkInt(program, callFunction(program, "foo", [], [makeInt(program, 65535), makeUint(program, 2)]), 262140);
3371     checkInt(program, callFunction(program, "foo", [], [makeInt(program, -1), makeUint(program, 5)]), -32);
3372     checkInt(program, callFunction(program, "foo", [], [makeInt(program, 0), makeUint(program, 3)]), 0);
3373 }
3374
3375 tests.intRShift = function()
3376 {
3377     let program = doPrep(`
3378         int foo(int a, uint b)
3379         {
3380             return a >> b;
3381         }
3382     `);
3383     checkInt(program, callFunction(program, "foo", [], [makeInt(program, 1), makeUint(program, 7)]), 0);
3384     checkInt(program, callFunction(program, "foo", [], [makeInt(program, 65535), makeUint(program, 2)]), 16383);
3385     checkInt(program, callFunction(program, "foo", [], [makeInt(program, -1), makeUint(program, 5)]), -1);
3386     checkInt(program, callFunction(program, "foo", [], [makeInt(program, 0), makeUint(program, 3)]), 0);
3387 }
3388
3389 tests.uintBitAnd = function()
3390 {
3391     let program = doPrep(`
3392         uint foo(uint a, uint b)
3393         {
3394             return a & b;
3395         }
3396     `);
3397     checkUint(program, callFunction(program, "foo", [], [makeUint(program, 1), makeUint(program, 7)]), 1);
3398     checkUint(program, callFunction(program, "foo", [], [makeUint(program, 65535), makeUint(program, 42)]), 42);
3399     checkUint(program, callFunction(program, "foo", [], [makeUint(program, -1), makeUint(program, -7)]), 4294967289);
3400     checkUint(program, callFunction(program, "foo", [], [makeUint(program, 0), makeUint(program, 85732)]), 0);
3401 }
3402
3403 tests.uintBitOr = function()