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