| /* | |
| * Copyright (C) 2017 Apple Inc. All rights reserved. | |
| * | |
| * Redistribution and use in source and binary forms, with or without | |
| * modification, are permitted provided that the following conditions | |
| * are met: | |
| * 1. Redistributions of source code must retain the above copyright | |
| * notice, this list of conditions and the following disclaimer. | |
| * 2. Redistributions in binary form must reproduce the above copyright | |
| * notice, this list of conditions and the following disclaimer in the | |
| * documentation and/or other materials provided with the distribution. | |
| * | |
| * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY | |
| * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | |
| * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR | |
| * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR | |
| * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, | |
| * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, | |
| * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR | |
| * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY | |
| * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | |
| * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | |
| * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | |
| */ | |
| "use strict"; | |
| function doPrep(code) | |
| { | |
| return prepare("/internal/test", 0, code); | |
| } | |
| function doLex(code) | |
| { | |
| let lexer = new Lexer("/internal/test", "native", 0, code); | |
| var result = []; | |
| for (;;) { | |
| let next = lexer.next(); | |
| if (!next) | |
| return result; | |
| result.push(next); | |
| } | |
| return result; | |
| } | |
| function makeInt(program, value) | |
| { | |
| return TypedValue.box(program.intrinsics.int32, value); | |
| } | |
| function makeUint(program, value) | |
| { | |
| return TypedValue.box(program.intrinsics.uint32, value); | |
| } | |
| function makeUint8(program, value) | |
| { | |
| return TypedValue.box(program.intrinsics.uint8, value); | |
| } | |
| function makeBool(program, value) | |
| { | |
| return TypedValue.box(program.intrinsics.bool, value); | |
| } | |
| function makeFloat(program, value) | |
| { | |
| return TypedValue.box(program.intrinsics.float, value); | |
| } | |
| function makeDouble(program, value) | |
| { | |
| return TypedValue.box(program.intrinsics.double, value); | |
| } | |
| function makeEnum(program, enumName, value) | |
| { | |
| let enumType = program.types.get(enumName); | |
| if (!enumType) | |
| throw new Error("No type named " + enumName); | |
| let enumMember = enumType.memberByName(value); | |
| if (!enumMember) | |
| throw new Error("No member named " + enumMember + " in " + enumType); | |
| return TypedValue.box(enumType, enumMember.value.unifyNode.valueForSelectedType); | |
| } | |
| function checkNumber(program, result, expected) | |
| { | |
| if (!result.type.unifyNode.isNumber) | |
| throw new Error("Wrong result type; result: " + result); | |
| if (result.value != expected) | |
| throw new Error("Wrong result: " + result.value + " (expected " + expected + ")"); | |
| } | |
| function checkInt(program, result, expected) | |
| { | |
| if (!result.type.equals(program.intrinsics.int32)) | |
| throw new Error("Wrong result type; result: " + result); | |
| checkNumber(program, result, expected); | |
| } | |
| function checkEnum(program, result, expected) | |
| { | |
| if (!(result.type.unifyNode instanceof EnumType)) | |
| throw new Error("Wrong result type; result: " + result); | |
| if (result.value != expected) | |
| throw new Error("Wrong result: " + result.value + " (expected " + expected + ")"); | |
| } | |
| function checkUint(program, result, expected) | |
| { | |
| if (!result.type.equals(program.intrinsics.uint32)) | |
| throw new Error("Wrong result type: " + result.type); | |
| if (result.value != expected) | |
| throw new Error("Wrong result: " + result.value + " (expected " + expected + ")"); | |
| } | |
| function checkUint8(program, result, expected) | |
| { | |
| if (!result.type.equals(program.intrinsics.uint8)) | |
| throw new Error("Wrong result type: " + result.type); | |
| if (result.value != expected) | |
| throw new Error("Wrong result: " + result.value + " (expected " + expected + ")"); | |
| } | |
| function checkBool(program, result, expected) | |
| { | |
| if (!result.type.equals(program.intrinsics.bool)) | |
| throw new Error("Wrong result type: " + result.type); | |
| if (result.value != expected) | |
| throw new Error("Wrong result: " + result.value + " (expected " + expected + ")"); | |
| } | |
| function checkFloat(program, result, expected) | |
| { | |
| if (!result.type.equals(program.intrinsics.float)) | |
| throw new Error("Wrong result type: " + result.type); | |
| if (result.value != expected) | |
| throw new Error("Wrong result: " + result.value + " (expected " + expected + ")"); | |
| } | |
| function checkDouble(program, result, expected) | |
| { | |
| if (!result.type.equals(program.intrinsics.double)) | |
| throw new Error("Wrong result type: " + result.type); | |
| if (result.value != expected) | |
| throw new Error("Wrong result: " + result.value + " (expected " + expected + ")"); | |
| } | |
| function checkLexerToken(result, expectedIndex, expectedKind, expectedText) | |
| { | |
| if (result._index != expectedIndex) | |
| throw new Error("Wrong lexer index; result: " + result._index + " (expected " + expectedIndex + ")"); | |
| if (result._kind != expectedKind) | |
| throw new Error("Wrong lexer kind; result: " + result._kind + " (expected " + expectedKind + ")"); | |
| if (result._text != expectedText) | |
| throw new Error("Wrong lexer text; result: " + result._text + " (expected " + expectedText + ")"); | |
| } | |
| function checkFail(callback, predicate) | |
| { | |
| try { | |
| callback(); | |
| throw new Error("Did not throw exception"); | |
| } catch (e) { | |
| if (predicate(e)) { | |
| return; | |
| } | |
| throw e; | |
| } | |
| } | |
| let okToTest = false; | |
| let tests = new Proxy({}, { | |
| set(target, property, value, receiver) | |
| { | |
| if (property in target) | |
| throw new Error("Trying to declare duplicate test: " + property); | |
| target[property] = value; | |
| return true; | |
| } | |
| }); | |
| tests.literalBool = function() { | |
| let program = doPrep("bool foo() { return true; }"); | |
| checkBool(program, callFunction(program, "foo", [], []), true); | |
| } | |
| tests.identityBool = function() { | |
| let program = doPrep("bool foo(bool x) { return x; }"); | |
| checkBool(program, callFunction(program, "foo", [], [makeBool(program, true)]), true); | |
| checkBool(program, callFunction(program, "foo", [], [makeBool(program, false)]), false); | |
| } | |
| tests.intSimpleMath = function() { | |
| let program = doPrep("int foo(int x, int y) { return x + y; }"); | |
| checkInt(program, callFunction(program, "foo", [], [makeInt(program, 7), makeInt(program, 5)]), 12); | |
| program = doPrep("int foo(int x, int y) { return x - y; }"); | |
| checkInt(program, callFunction(program, "foo", [], [makeInt(program, 7), makeInt(program, 5)]), 2); | |
| checkInt(program, callFunction(program, "foo", [], [makeInt(program, 5), makeInt(program, 7)]), -2); | |
| program = doPrep("int foo(int x, int y) { return x * y; }"); | |
| checkInt(program, callFunction(program, "foo", [], [makeInt(program, 7), makeInt(program, 5)]), 35); | |
| checkInt(program, callFunction(program, "foo", [], [makeInt(program, 7), makeInt(program, -5)]), -35); | |
| program = doPrep("int foo(int x, int y) { return x / y; }"); | |
| checkInt(program, callFunction(program, "foo", [], [makeInt(program, 7), makeInt(program, 2)]), 3); | |
| checkInt(program, callFunction(program, "foo", [], [makeInt(program, 7), makeInt(program, -2)]), -3); | |
| } | |
| tests.uintSimpleMath = function() { | |
| let program = doPrep("uint foo(uint x, uint y) { return x + y; }"); | |
| checkUint(program, callFunction(program, "foo", [], [makeUint(program, 7), makeUint(program, 5)]), 12); | |
| program = doPrep("uint foo(uint x, uint y) { return x - y; }"); | |
| checkUint(program, callFunction(program, "foo", [], [makeUint(program, 7), makeUint(program, 5)]), 2); | |
| checkUint(program, callFunction(program, "foo", [], [makeUint(program, 5), makeUint(program, 7)]), 4294967294); | |
| program = doPrep("uint foo(uint x, uint y) { return x * y; }"); | |
| checkUint(program, callFunction(program, "foo", [], [makeUint(program, 7), makeUint(program, 5)]), 35); | |
| program = doPrep("uint foo(uint x, uint y) { return x / y; }"); | |
| checkUint(program, callFunction(program, "foo", [], [makeUint(program, 7), makeUint(program, 2)]), 3); | |
| } | |
| tests.uint8SimpleMath = function() { | |
| let program = doPrep("uint8 foo(uint8 x, uint8 y) { return x + y; }"); | |
| checkUint8(program, callFunction(program, "foo", [], [makeUint8(program, 7), makeUint8(program, 5)]), 12); | |
| program = doPrep("uint8 foo(uint8 x, uint8 y) { return x - y; }"); | |
| checkUint8(program, callFunction(program, "foo", [], [makeUint8(program, 7), makeUint8(program, 5)]), 2); | |
| checkUint8(program, callFunction(program, "foo", [], [makeUint8(program, 5), makeUint8(program, 7)]), 254); | |
| program = doPrep("uint8 foo(uint8 x, uint8 y) { return x * y; }"); | |
| checkUint8(program, callFunction(program, "foo", [], [makeUint8(program, 7), makeUint8(program, 5)]), 35); | |
| program = doPrep("uint8 foo(uint8 x, uint8 y) { return x / y; }"); | |
| checkUint8(program, callFunction(program, "foo", [], [makeUint8(program, 7), makeUint8(program, 2)]), 3); | |
| } | |
| tests.equality = function() { | |
| let program = doPrep("bool foo(uint x, uint y) { return x == y; }"); | |
| checkBool(program, callFunction(program, "foo", [], [makeUint(program, 7), makeUint(program, 5)]), false); | |
| checkBool(program, callFunction(program, "foo", [], [makeUint(program, 7), makeUint(program, 7)]), true); | |
| program = doPrep("bool foo(uint8 x, uint8 y) { return x == y; }"); | |
| checkBool(program, callFunction(program, "foo", [], [makeUint8(program, 7), makeUint8(program, 5)]), false); | |
| checkBool(program, callFunction(program, "foo", [], [makeUint8(program, 7), makeUint8(program, 7)]), true); | |
| program = doPrep("bool foo(int x, int y) { return x == y; }"); | |
| checkBool(program, callFunction(program, "foo", [], [makeInt(program, 7), makeInt(program, 5)]), false); | |
| checkBool(program, callFunction(program, "foo", [], [makeInt(program, 7), makeInt(program, 7)]), true); | |
| program = doPrep("bool foo(bool x, bool y) { return x == y; }"); | |
| checkBool(program, callFunction(program, "foo", [], [makeBool(program, false), makeBool(program, true)]), false); | |
| checkBool(program, callFunction(program, "foo", [], [makeBool(program, true), makeBool(program, false)]), false); | |
| checkBool(program, callFunction(program, "foo", [], [makeBool(program, false), makeBool(program, false)]), true); | |
| checkBool(program, callFunction(program, "foo", [], [makeBool(program, true), makeBool(program, true)]), true); | |
| } | |
| tests.logicalNegation = function() | |
| { | |
| let program = doPrep("bool foo(bool x) { return !x; }"); | |
| checkBool(program, callFunction(program, "foo", [], [makeBool(program, true)]), false); | |
| checkBool(program, callFunction(program, "foo", [], [makeBool(program, false)]), true); | |
| } | |
| tests.notEquality = function() { | |
| let program = doPrep("bool foo(uint x, uint y) { return x != y; }"); | |
| checkBool(program, callFunction(program, "foo", [], [makeUint(program, 7), makeUint(program, 5)]), true); | |
| checkBool(program, callFunction(program, "foo", [], [makeUint(program, 7), makeUint(program, 7)]), false); | |
| program = doPrep("bool foo(uint8 x, uint8 y) { return x != y; }"); | |
| checkBool(program, callFunction(program, "foo", [], [makeUint8(program, 7), makeUint8(program, 5)]), true); | |
| checkBool(program, callFunction(program, "foo", [], [makeUint8(program, 7), makeUint8(program, 7)]), false); | |
| program = doPrep("bool foo(int x, int y) { return x != y; }"); | |
| checkBool(program, callFunction(program, "foo", [], [makeInt(program, 7), makeInt(program, 5)]), true); | |
| checkBool(program, callFunction(program, "foo", [], [makeInt(program, 7), makeInt(program, 7)]), false); | |
| program = doPrep("bool foo(bool x, bool y) { return x != y; }"); | |
| checkBool(program, callFunction(program, "foo", [], [makeBool(program, false), makeBool(program, true)]), true); | |
| checkBool(program, callFunction(program, "foo", [], [makeBool(program, true), makeBool(program, false)]), true); | |
| checkBool(program, callFunction(program, "foo", [], [makeBool(program, false), makeBool(program, false)]), false); | |
| checkBool(program, callFunction(program, "foo", [], [makeBool(program, true), makeBool(program, true)]), false); | |
| } | |
| tests.equalityTypeFailure = function() | |
| { | |
| checkFail( | |
| () => doPrep("bool foo(int x, uint y) { return x == y; }"), | |
| (e) => e instanceof WTypeError && e.message.indexOf("/internal/test:1") != -1); | |
| } | |
| tests.generalNegation = function() | |
| { | |
| let program = doPrep("bool foo(int x) { return !x; }"); | |
| checkBool(program, callFunction(program, "foo", [], [makeInt(program, 7)]), false); | |
| checkBool(program, callFunction(program, "foo", [], [makeInt(program, 0)]), true); | |
| } | |
| tests.add1 = function() { | |
| let program = doPrep("int foo(int x) { return x + 1; }"); | |
| checkInt(program, callFunction(program, "foo", [], [makeInt(program, 42)]), 43); | |
| } | |
| tests.simpleGeneric = function() { | |
| let program = doPrep(` | |
| T id<T>(T x) { return x; } | |
| int foo(int x) { return id(x) + 1; } | |
| `); | |
| checkInt(program, callFunction(program, "foo", [], [makeInt(program, 42)]), 43); | |
| } | |
| tests.nameResolutionFailure = function() | |
| { | |
| checkFail( | |
| () => doPrep("int foo(int x) { return x + y; }"), | |
| (e) => e instanceof WTypeError && e.message.indexOf("/internal/test:1") != -1); | |
| } | |
| tests.simpleVariable = function() | |
| { | |
| let program = doPrep(` | |
| int foo(int p) | |
| { | |
| int result = p; | |
| return result; | |
| } | |
| `); | |
| checkInt(program, callFunction(program, "foo", [], [makeInt(program, 42)]), 42); | |
| } | |
| tests.simpleAssignment = function() | |
| { | |
| let program = doPrep(` | |
| int foo(int p) | |
| { | |
| int result; | |
| result = p; | |
| return result; | |
| } | |
| `); | |
| checkInt(program, callFunction(program, "foo", [], [makeInt(program, 42)]), 42); | |
| } | |
| tests.simpleDefault = function() | |
| { | |
| let program = doPrep(` | |
| int foo() | |
| { | |
| int result; | |
| return result; | |
| } | |
| `); | |
| checkInt(program, callFunction(program, "foo", [], []), 0); | |
| } | |
| tests.simpleDereference = function() | |
| { | |
| let program = doPrep(` | |
| int foo(device int* p) | |
| { | |
| return *p; | |
| } | |
| `); | |
| let buffer = new EBuffer(1); | |
| buffer.set(0, 13); | |
| checkInt(program, callFunction(program, "foo", [], [TypedValue.box(new PtrType(externalOrigin, "device", program.intrinsics.int32), new EPtr(buffer, 0))]), 13); | |
| } | |
| tests.dereferenceStore = function() | |
| { | |
| let program = doPrep(` | |
| void foo(device int* p) | |
| { | |
| *p = 52; | |
| } | |
| `); | |
| let buffer = new EBuffer(1); | |
| buffer.set(0, 13); | |
| callFunction(program, "foo", [], [TypedValue.box(new PtrType(externalOrigin, "device", program.intrinsics.int32), new EPtr(buffer, 0))]); | |
| if (buffer.get(0) != 52) | |
| throw new Error("Expected buffer to contain 52 but it contains: " + buffer.get(0)); | |
| } | |
| tests.simpleMakePtr = function() | |
| { | |
| let program = doPrep(` | |
| thread int* foo() | |
| { | |
| int x = 42; | |
| return &x; | |
| } | |
| `); | |
| let result = callFunction(program, "foo", [], []); | |
| if (!result.type.isPtr) | |
| throw new Error("Return type is not a pointer: " + result.type); | |
| if (!result.type.elementType.equals(program.intrinsics.int32)) | |
| throw new Error("Return type is not a pointer to an int: " + result.type); | |
| if (!(result.value instanceof EPtr)) | |
| throw new Error("Return value is not an EPtr: " + result.value); | |
| let value = result.value.loadValue(); | |
| if (value != 42) | |
| throw new Error("Expected 42 but got: " + value); | |
| } | |
| tests.threadArrayLoad = function() | |
| { | |
| let program = doPrep(` | |
| int foo(thread int[] array) | |
| { | |
| return array[0u]; | |
| } | |
| `); | |
| let buffer = new EBuffer(1); | |
| buffer.set(0, 89); | |
| let result = callFunction(program, "foo", [], [TypedValue.box(new ArrayRefType(externalOrigin, "thread", program.intrinsics.int32), new EArrayRef(new EPtr(buffer, 0), 1))]); | |
| checkInt(program, result, 89); | |
| } | |
| tests.threadArrayLoadIntLiteral = function() | |
| { | |
| let program = doPrep(` | |
| int foo(thread int[] array) | |
| { | |
| return array[0]; | |
| } | |
| `); | |
| let buffer = new EBuffer(1); | |
| buffer.set(0, 89); | |
| let result = callFunction(program, "foo", [], [TypedValue.box(new ArrayRefType(externalOrigin, "thread", program.intrinsics.int32), new EArrayRef(new EPtr(buffer, 0), 1))]); | |
| checkInt(program, result, 89); | |
| } | |
| tests.deviceArrayLoad = function() | |
| { | |
| let program = doPrep(` | |
| int foo(device int[] array) | |
| { | |
| return array[0u]; | |
| } | |
| `); | |
| let buffer = new EBuffer(1); | |
| buffer.set(0, 89); | |
| let result = callFunction(program, "foo", [], [TypedValue.box(new ArrayRefType(externalOrigin, "device", program.intrinsics.int32), new EArrayRef(new EPtr(buffer, 0), 1))]); | |
| checkInt(program, result, 89); | |
| } | |
| tests.threadArrayStore = function() | |
| { | |
| let program = doPrep(` | |
| void foo(thread int[] array, int value) | |
| { | |
| array[0u] = value; | |
| } | |
| `); | |
| let buffer = new EBuffer(1); | |
| buffer.set(0, 15); | |
| let arrayRef = TypedValue.box( | |
| new ArrayRefType(externalOrigin, "thread", program.intrinsics.int32), | |
| new EArrayRef(new EPtr(buffer, 0), 1)); | |
| callFunction(program, "foo", [], [arrayRef, makeInt(program, 65)]); | |
| if (buffer.get(0) != 65) | |
| throw new Error("Bad value stored into buffer (expected 65): " + buffer.get(0)); | |
| callFunction(program, "foo", [], [arrayRef, makeInt(program, -111)]); | |
| if (buffer.get(0) != -111) | |
| throw new Error("Bad value stored into buffer (expected -111): " + buffer.get(0)); | |
| } | |
| tests.deviceArrayStore = function() | |
| { | |
| let program = doPrep(` | |
| void foo(device int[] array, int value) | |
| { | |
| array[0u] = value; | |
| } | |
| `); | |
| let buffer = new EBuffer(1); | |
| buffer.set(0, 15); | |
| let arrayRef = TypedValue.box( | |
| new ArrayRefType(externalOrigin, "device", program.intrinsics.int32), | |
| new EArrayRef(new EPtr(buffer, 0), 1)); | |
| callFunction(program, "foo", [], [arrayRef, makeInt(program, 65)]); | |
| if (buffer.get(0) != 65) | |
| throw new Error("Bad value stored into buffer (expected 65): " + buffer.get(0)); | |
| callFunction(program, "foo", [], [arrayRef, makeInt(program, -111)]); | |
| if (buffer.get(0) != -111) | |
| throw new Error("Bad value stored into buffer (expected -111): " + buffer.get(0)); | |
| } | |
| tests.deviceArrayStoreIntLiteral = function() | |
| { | |
| let program = doPrep(` | |
| void foo(device int[] array, int value) | |
| { | |
| array[0] = value; | |
| } | |
| `); | |
| let buffer = new EBuffer(1); | |
| buffer.set(0, 15); | |
| let arrayRef = TypedValue.box( | |
| new ArrayRefType(externalOrigin, "device", program.intrinsics.int32), | |
| new EArrayRef(new EPtr(buffer, 0), 1)); | |
| callFunction(program, "foo", [], [arrayRef, makeInt(program, 65)]); | |
| if (buffer.get(0) != 65) | |
| throw new Error("Bad value stored into buffer (expected 65): " + buffer.get(0)); | |
| callFunction(program, "foo", [], [arrayRef, makeInt(program, -111)]); | |
| if (buffer.get(0) != -111) | |
| throw new Error("Bad value stored into buffer (expected -111): " + buffer.get(0)); | |
| } | |
| tests.simpleProtocol = function() | |
| { | |
| let program = doPrep(` | |
| protocol MyAddable { | |
| MyAddable operator+(MyAddable, MyAddable); | |
| } | |
| T add<T:MyAddable>(T a, T b) | |
| { | |
| return a + b; | |
| } | |
| int foo(int x) | |
| { | |
| return add(x, 73); | |
| } | |
| `); | |
| checkInt(program, callFunction(program, "foo", [], [makeInt(program, 45)]), 45 + 73); | |
| } | |
| tests.typeMismatchReturn = function() | |
| { | |
| checkFail( | |
| () => doPrep(` | |
| int foo() | |
| { | |
| return 0u; | |
| } | |
| `), | |
| (e) => e instanceof WTypeError); | |
| } | |
| tests.typeMismatchVariableDecl = function() | |
| { | |
| checkFail( | |
| () => doPrep(` | |
| void foo(uint x) | |
| { | |
| int y = x; | |
| } | |
| `), | |
| (e) => e instanceof WTypeError); | |
| } | |
| tests.typeMismatchAssignment = function() | |
| { | |
| checkFail( | |
| () => doPrep(` | |
| void foo(uint x) | |
| { | |
| int y; | |
| y = x; | |
| } | |
| `), | |
| (e) => e instanceof WTypeError); | |
| } | |
| tests.typeMismatchReturnParam = function() | |
| { | |
| checkFail( | |
| () => doPrep(` | |
| int foo(uint x) | |
| { | |
| return x; | |
| } | |
| `), | |
| (e) => e instanceof WTypeError); | |
| } | |
| tests.badAdd = function() | |
| { | |
| checkFail( | |
| () => doPrep(` | |
| void bar<T>(T) { } | |
| void foo(int x, uint y) | |
| { | |
| bar(x + y); | |
| } | |
| `), | |
| (e) => e instanceof WTypeError && e.message.indexOf("native int32 operator+<>(int32,int32)") != -1); | |
| } | |
| tests.lexerKeyword = function() | |
| { | |
| let result = doLex("ident for while 123 123u { } {asd asd{ 1a3 1.2 + 3.4 + 1. + .2 1.2d 0.d .3d && ||"); | |
| if (result.length != 25) | |
| throw new Error("Lexer emitted an incorrect number of tokens (expected 23): " + result.length); | |
| checkLexerToken(result[0], 0, "identifier", "ident"); | |
| checkLexerToken(result[1], 6, "keyword", "for"); | |
| checkLexerToken(result[2], 10, "keyword", "while"); | |
| checkLexerToken(result[3], 16, "intLiteral", "123"); | |
| checkLexerToken(result[4], 20, "uintLiteral", "123u"); | |
| checkLexerToken(result[5], 25, "punctuation", "{"); | |
| checkLexerToken(result[6], 27, "punctuation", "}"); | |
| checkLexerToken(result[7], 29, "punctuation", "{"); | |
| checkLexerToken(result[8], 30, "identifier", "asd"); | |
| checkLexerToken(result[9], 34, "identifier", "asd"); | |
| checkLexerToken(result[10], 37, "punctuation", "{"); | |
| checkLexerToken(result[11], 39, "intLiteral", "1"); | |
| checkLexerToken(result[12], 40, "identifier", "a3"); | |
| checkLexerToken(result[13], 43, "floatLiteral", "1.2"); | |
| checkLexerToken(result[14], 47, "punctuation", "+"); | |
| checkLexerToken(result[15], 49, "floatLiteral", "3.4"); | |
| checkLexerToken(result[16], 53, "punctuation", "+"); | |
| checkLexerToken(result[17], 55, "floatLiteral", "1."); | |
| checkLexerToken(result[18], 58, "punctuation", "+"); | |
| checkLexerToken(result[19], 60, "floatLiteral", ".2"); | |
| checkLexerToken(result[20], 63, "floatLiteral", "1.2d"); | |
| checkLexerToken(result[21], 68, "floatLiteral", "0.d"); | |
| checkLexerToken(result[22], 72, "floatLiteral", ".3d"); | |
| checkLexerToken(result[23], 76, "punctuation", "&&"); | |
| checkLexerToken(result[24], 79, "punctuation", "||"); | |
| } | |
| tests.simpleNoReturn = function() | |
| { | |
| checkFail( | |
| () => doPrep("int foo() { }"), | |
| (e) => e instanceof WTypeError); | |
| } | |
| tests.simpleUnreachableCode = function() | |
| { | |
| checkFail( | |
| () => doPrep(` | |
| void foo() | |
| { | |
| return; | |
| int x; | |
| } | |
| `), | |
| (e) => e instanceof WTypeError); | |
| } | |
| tests.simpleStruct = function() | |
| { | |
| let program = doPrep(` | |
| struct Foo { | |
| int x; | |
| int y; | |
| } | |
| Foo foo(Foo foo) | |
| { | |
| Foo result; | |
| result.x = foo.y; | |
| result.y = foo.x; | |
| return result; | |
| } | |
| `); | |
| let structType = program.types.get("Foo"); | |
| if (!structType) | |
| throw new Error("Did not find Foo type"); | |
| let buffer = new EBuffer(2); | |
| buffer.set(0, 62); | |
| buffer.set(1, 24); | |
| let result = callFunction(program, "foo", [], [new TypedValue(structType, new EPtr(buffer, 0))]); | |
| if (!result.type.equals(structType)) | |
| throw new Error("Wrong result type: " + result.type); | |
| let x = result.ePtr.get(0); | |
| let y = result.ePtr.get(1); | |
| if (x != 24) | |
| throw new Error("Wrong result for x: " + x + " (y = " + y + ")"); | |
| if (y != 62) | |
| throw new Error("Wrong result for y: " + y + " (x + " + x + ")"); | |
| } | |
| tests.genericStructInstance = function() | |
| { | |
| let program = doPrep(` | |
| struct Foo<T> { | |
| T x; | |
| T y; | |
| } | |
| Foo<int> foo(Foo<int> foo) | |
| { | |
| Foo<int> result; | |
| result.x = foo.y; | |
| result.y = foo.x; | |
| return result; | |
| } | |
| `); | |
| let structType = TypeRef.instantiate(program.types.get("Foo"), [program.intrinsics.int32]); | |
| let buffer = new EBuffer(2); | |
| buffer.set(0, 62); | |
| buffer.set(1, 24); | |
| let result = callFunction(program, "foo", [], [new TypedValue(structType, new EPtr(buffer, 0))]); | |
| let x = result.ePtr.get(0); | |
| let y = result.ePtr.get(1); | |
| if (x != 24) | |
| throw new Error("Wrong result for x: " + x + " (y = " + y + ")"); | |
| if (y != 62) | |
| throw new Error("Wrong result for y: " + y + " (x + " + x + ")"); | |
| } | |
| tests.doubleGenericCallsDoubleGeneric = function() | |
| { | |
| doPrep(` | |
| void foo<T, U>(T, U) { } | |
| void bar<V, W>(V x, W y) { foo(x, y); } | |
| `); | |
| } | |
| tests.doubleGenericCallsSingleGeneric = function() | |
| { | |
| checkFail( | |
| () => doPrep(` | |
| void foo<T>(T, T) { } | |
| void bar<V, W>(V x, W y) { foo(x, y); } | |
| `), | |
| (e) => e instanceof WTypeError); | |
| } | |
| tests.loadNull = function() | |
| { | |
| checkFail( | |
| () => doPrep(` | |
| void sink<T>(T) { } | |
| void foo() { sink(*null); } | |
| `), | |
| (e) => e instanceof WTypeError && e.message.indexOf("Type passed to dereference is not a pointer: null") != -1); | |
| } | |
| tests.storeNull = function() | |
| { | |
| checkFail( | |
| () => doPrep(` | |
| void foo() { *null = 42; } | |
| `), | |
| (e) => e instanceof WTypeError && e.message.indexOf("Type passed to dereference is not a pointer: null") != -1); | |
| } | |
| tests.returnNull = function() | |
| { | |
| let program = doPrep(` | |
| thread int* foo() { return null; } | |
| `); | |
| let result = callFunction(program, "foo", [], []); | |
| if (!result.type.isPtr) | |
| throw new Error("Return type is not a pointer: " + result.type); | |
| if (!result.type.elementType.equals(program.intrinsics.int32)) | |
| throw new Error("Return type is not a pointer to an int: " + result.type); | |
| if (result.value != null) | |
| throw new Error("Return value is not null: " + result.value); | |
| } | |
| tests.dereferenceDefaultNull = function() | |
| { | |
| let program = doPrep(` | |
| int foo() | |
| { | |
| thread int* p; | |
| return *p; | |
| } | |
| `); | |
| checkFail( | |
| () => callFunction(program, "foo", [], []), | |
| (e) => e instanceof WTrapError); | |
| } | |
| tests.defaultInitializedNull = function() | |
| { | |
| let program = doPrep(` | |
| int foo() | |
| { | |
| thread int* p = null;; | |
| return *p; | |
| } | |
| `); | |
| checkFail( | |
| () => callFunction(program, "foo", [], []), | |
| (e) => e instanceof WTrapError); | |
| } | |
| tests.passNullToPtrMonomorphic = function() | |
| { | |
| let program = doPrep(` | |
| int foo(thread int* ptr) | |
| { | |
| return *ptr; | |
| } | |
| int bar() | |
| { | |
| return foo(null); | |
| } | |
| `); | |
| checkFail( | |
| () => callFunction(program, "bar", [], []), | |
| (e) => e instanceof WTrapError); | |
| } | |
| tests.passNullToPtrPolymorphic = function() | |
| { | |
| checkFail( | |
| () => doPrep(` | |
| T foo<T>(thread T* ptr) | |
| { | |
| return *ptr; | |
| } | |
| int bar() | |
| { | |
| return foo(null); | |
| } | |
| `), | |
| (e) => e instanceof WTypeError); | |
| } | |
| tests.passNullToPolymorphic = function() | |
| { | |
| checkFail( | |
| () => doPrep(` | |
| T foo<T>(T ptr) | |
| { | |
| return ptr; | |
| } | |
| int bar() | |
| { | |
| return foo(null); | |
| } | |
| `), | |
| (e) => e instanceof WTypeError); | |
| } | |
| tests.loadNullArrayRef = function() | |
| { | |
| checkFail( | |
| () => doPrep(` | |
| void sink<T>(T) { } | |
| void foo() { sink(null[0u]); } | |
| `), | |
| (e) => e instanceof WTypeError && e.message.indexOf("Cannot resolve access") != -1); | |
| } | |
| tests.storeNullArrayRef = function() | |
| { | |
| checkFail( | |
| () => doPrep(` | |
| void foo() { null[0u] = 42; } | |
| `), | |
| (e) => e instanceof WTypeError && e.message.indexOf("Cannot resolve access") != -1); | |
| } | |
| tests.returnNullArrayRef = function() | |
| { | |
| let program = doPrep(` | |
| thread int[] foo() { return null; } | |
| `); | |
| let result = callFunction(program, "foo", [], []); | |
| if (!result.type.isArrayRef) | |
| throw new Error("Return type is not an array reference: " + result.type); | |
| if (!result.type.elementType.equals(program.intrinsics.int32)) | |
| throw new Error("Return type is not an int array reference: " + result.type); | |
| if (result.value != null) | |
| throw new Error("Return value is not null: " + result.value); | |
| } | |
| tests.dereferenceDefaultNullArrayRef = function() | |
| { | |
| let program = doPrep(` | |
| int foo() | |
| { | |
| thread int[] p; | |
| return p[0u]; | |
| } | |
| `); | |
| checkFail( | |
| () => callFunction(program, "foo", [], []), | |
| (e) => e instanceof WTrapError); | |
| } | |
| tests.defaultInitializedNullArrayRef = function() | |
| { | |
| let program = doPrep(` | |
| int foo() | |
| { | |
| thread int[] p = null; | |
| return p[0u]; | |
| } | |
| `); | |
| checkFail( | |
| () => callFunction(program, "foo", [], []), | |
| (e) => e instanceof WTrapError); | |
| } | |
| tests.defaultInitializedNullArrayRefIntLiteral = function() | |
| { | |
| let program = doPrep(` | |
| int foo() | |
| { | |
| thread int[] p = null; | |
| return p[0]; | |
| } | |
| `); | |
| checkFail( | |
| () => callFunction(program, "foo", [], []), | |
| (e) => e instanceof WTrapError); | |
| } | |
| tests.passNullToPtrMonomorphicArrayRef = function() | |
| { | |
| let program = doPrep(` | |
| int foo(thread int[] ptr) | |
| { | |
| return ptr[0u]; | |
| } | |
| int bar() | |
| { | |
| return foo(null); | |
| } | |
| `); | |
| checkFail( | |
| () => callFunction(program, "bar", [], []), | |
| (e) => e instanceof WTrapError); | |
| } | |
| tests.passNullToPtrPolymorphicArrayRef = function() | |
| { | |
| checkFail( | |
| () => doPrep(` | |
| T foo<T>(thread T[] ptr) | |
| { | |
| return ptr[0u]; | |
| } | |
| int bar() | |
| { | |
| return foo(null); | |
| } | |
| `), | |
| (e) => e instanceof WTypeError); | |
| } | |
| tests.returnIntLiteralUint = function() | |
| { | |
| let program = doPrep("uint foo() { return 42; }"); | |
| checkNumber(program, callFunction(program, "foo", [], []), 42); | |
| } | |
| tests.returnIntLiteralDouble = function() | |
| { | |
| let program = doPrep("double foo() { return 42; }"); | |
| checkNumber(program, callFunction(program, "foo", [], []), 42); | |
| } | |
| tests.badIntLiteralForInt = function() | |
| { | |
| checkFail( | |
| () => doPrep("void foo() { int x = 3000000000; }"), | |
| (e) => e instanceof WSyntaxError); | |
| } | |
| tests.badIntLiteralForUint = function() | |
| { | |
| checkFail( | |
| () => doPrep("void foo() { uint x = 5000000000; }"), | |
| (e) => e instanceof WSyntaxError); | |
| } | |
| tests.badIntLiteralForDouble = function() | |
| { | |
| checkFail( | |
| () => doPrep("void foo() { double x = 5000000000000000000000000000000000000; }"), | |
| (e) => e instanceof WSyntaxError); | |
| } | |
| tests.passNullAndNotNull = function() | |
| { | |
| let program = doPrep(` | |
| T bar<T>(device T* p, device T*) | |
| { | |
| return *p; | |
| } | |
| int foo(device int* p) | |
| { | |
| return bar(p, null); | |
| } | |
| `); | |
| let buffer = new EBuffer(1); | |
| buffer.set(0, 13); | |
| checkInt(program, callFunction(program, "foo", [], [TypedValue.box(new PtrType(externalOrigin, "device", program.intrinsics.int32), new EPtr(buffer, 0))]), 13); | |
| } | |
| tests.passNullAndNotNullFullPoly = function() | |
| { | |
| let program = doPrep(` | |
| T bar<T>(T p, T) | |
| { | |
| return p; | |
| } | |
| int foo(device int* p) | |
| { | |
| return *bar(p, null); | |
| } | |
| `); | |
| let buffer = new EBuffer(1); | |
| buffer.set(0, 13); | |
| checkInt(program, callFunction(program, "foo", [], [TypedValue.box(new PtrType(externalOrigin, "device", program.intrinsics.int32), new EPtr(buffer, 0))]), 13); | |
| } | |
| tests.passNullAndNotNullFullPolyReverse = function() | |
| { | |
| let program = doPrep(` | |
| T bar<T>(T, T p) | |
| { | |
| return p; | |
| } | |
| int foo(device int* p) | |
| { | |
| return *bar(null, p); | |
| } | |
| `); | |
| let buffer = new EBuffer(1); | |
| buffer.set(0, 13); | |
| checkInt(program, callFunction(program, "foo", [], [TypedValue.box(new PtrType(externalOrigin, "device", program.intrinsics.int32), new EPtr(buffer, 0))]), 13); | |
| } | |
| tests.nullTypeVariableUnify = function() | |
| { | |
| let left = new NullType(externalOrigin); | |
| let right = new TypeVariable(externalOrigin, "T", null); | |
| if (left.equals(right)) | |
| throw new Error("Should not be equal but are: " + left + " and " + right); | |
| if (right.equals(left)) | |
| throw new Error("Should not be equal but are: " + left + " and " + right); | |
| function everyOrder(array, callback) | |
| { | |
| function recurse(array, callback, order) | |
| { | |
| if (!array.length) | |
| return callback.call(null, order); | |
| for (let i = 0; i < array.length; ++i) { | |
| let nextArray = array.concat(); | |
| nextArray.splice(i, 1); | |
| recurse(nextArray, callback, order.concat([array[i]])); | |
| } | |
| } | |
| recurse(array, callback, []); | |
| } | |
| function everyPair(things) | |
| { | |
| let result = []; | |
| for (let i = 0; i < things.length; ++i) { | |
| for (let j = 0; j < things.length; ++j) { | |
| if (i != j) | |
| result.push([things[i], things[j]]); | |
| } | |
| } | |
| return result; | |
| } | |
| everyOrder( | |
| everyPair(["nullType", "variableType", "ptrType"]), | |
| order => { | |
| let types = {}; | |
| types.nullType = new NullType(externalOrigin); | |
| types.variableType = new TypeVariable(externalOrigin, "T", null); | |
| types.ptrType = new PtrType(externalOrigin, "constant", new NativeType(externalOrigin, "foo_t", [])); | |
| let unificationContext = new UnificationContext([types.variableType]); | |
| for (let [leftName, rightName] of order) { | |
| let left = types[leftName]; | |
| let right = types[rightName]; | |
| let result = left.unify(unificationContext, right); | |
| if (!result) | |
| throw new Error("In order " + order + " cannot unify " + left + " with " + right); | |
| } | |
| if (!unificationContext.verify().result) | |
| throw new Error("In order " + order.map(value => "(" + value + ")") + " cannot verify"); | |
| }); | |
| } | |
| tests.doubleNot = function() | |
| { | |
| let program = doPrep(` | |
| bool foo(bool x) | |
| { | |
| return !!x; | |
| } | |
| `); | |
| checkBool(program, callFunction(program, "foo", [], [makeBool(program, true)]), true); | |
| checkBool(program, callFunction(program, "foo", [], [makeBool(program, false)]), false); | |
| } | |
| tests.simpleRecursion = function() | |
| { | |
| checkFail( | |
| () => doPrep(` | |
| void foo<T>(T x) | |
| { | |
| foo(&x); | |
| } | |
| `), | |
| (e) => e instanceof WTypeError); | |
| } | |
| tests.protocolMonoSigPolyDef = function() | |
| { | |
| let program = doPrep(` | |
| struct IntAnd<T> { | |
| int first; | |
| T second; | |
| } | |
| IntAnd<T> intAnd<T>(int first, T second) | |
| { | |
| IntAnd<T> result; | |
| result.first = first; | |
| result.second = second; | |
| return result; | |
| } | |
| protocol IntAndable { | |
| IntAnd<int> intAnd(IntAndable, int); | |
| } | |
| int foo<T:IntAndable>(T first, int second) | |
| { | |
| IntAnd<int> result = intAnd(first, second); | |
| return result.first + result.second; | |
| } | |
| `); | |
| checkInt(program, callFunction(program, "foo", [], [makeInt(program, 54), makeInt(program, 12)]), 54 + 12); | |
| } | |
| tests.protocolPolySigPolyDef = function() | |
| { | |
| let program = doPrep(` | |
| struct IntAnd<T> { | |
| int first; | |
| T second; | |
| } | |
| IntAnd<T> intAnd<T>(int first, T second) | |
| { | |
| IntAnd<T> result; | |
| result.first = first; | |
| result.second = second; | |
| return result; | |
| } | |
| protocol IntAndable { | |
| IntAnd<T> intAnd<T>(IntAndable, T); | |
| } | |
| int foo<T:IntAndable>(T first, int second) | |
| { | |
| IntAnd<int> result = intAnd(first, second); | |
| return result.first + result.second; | |
| } | |
| `); | |
| checkInt(program, callFunction(program, "foo", [], [makeInt(program, 54), makeInt(program, 12)]), 54 + 12); | |
| } | |
| tests.protocolDoublePolySigDoublePolyDef = function() | |
| { | |
| let program = doPrep(` | |
| struct IntAnd<T, U> { | |
| int first; | |
| T second; | |
| U third; | |
| } | |
| IntAnd<T, U> intAnd<T, U>(int first, T second, U third) | |
| { | |
| IntAnd<T, U> result; | |
| result.first = first; | |
| result.second = second; | |
| result.third = third; | |
| return result; | |
| } | |
| protocol IntAndable { | |
| IntAnd<T, U> intAnd<T, U>(IntAndable, T, U); | |
| } | |
| int foo<T:IntAndable>(T first, int second, int third) | |
| { | |
| IntAnd<int, int> result = intAnd(first, second, third); | |
| return result.first + result.second + result.third; | |
| } | |
| `); | |
| checkInt(program, callFunction(program, "foo", [], [makeInt(program, 54), makeInt(program, 12), makeInt(program, 39)]), 54 + 12 + 39); | |
| } | |
| tests.protocolDoublePolySigDoublePolyDefExplicit = function() | |
| { | |
| let program = doPrep(` | |
| struct IntAnd<T, U> { | |
| int first; | |
| T second; | |
| U third; | |
| } | |
| IntAnd<T, U> intAnd<T, U>(int first, T second, U third) | |
| { | |
| IntAnd<T, U> result; | |
| result.first = first; | |
| result.second = second; | |
| result.third = third; | |
| return result; | |
| } | |
| protocol IntAndable { | |
| IntAnd<T, U> intAnd<T, U>(IntAndable, T, U); | |
| } | |
| int foo<T:IntAndable>(T first, int second, int third) | |
| { | |
| IntAnd<int, int> result = intAnd<int, int>(first, second, third); | |
| return result.first + result.second + result.third; | |
| } | |
| `); | |
| checkInt(program, callFunction(program, "foo", [], [makeInt(program, 54), makeInt(program, 12), makeInt(program, 39)]), 54 + 12 + 39); | |
| } | |
| tests.variableShadowing = function() | |
| { | |
| let program = doPrep(` | |
| int foo() | |
| { | |
| int y; | |
| int x = 7; | |
| { | |
| int x = 8; | |
| y = x; | |
| } | |
| return y; | |
| } | |
| `); | |
| checkInt(program, callFunction(program, "foo", [], []), 8); | |
| program = doPrep(` | |
| int foo() | |
| { | |
| int y; | |
| int x = 7; | |
| { | |
| int x = 8; | |
| } | |
| y = x; | |
| return y; | |
| } | |
| `); | |
| checkInt(program, callFunction(program, "foo", [], []), 7); | |
| } | |
| tests.ifStatement = function() | |
| { | |
| let program = doPrep(` | |
| int foo(int x) | |
| { | |
| int y = 6; | |
| if (x == 7) { | |
| y = 8; | |
| } | |
| return y; | |
| } | |
| `); | |
| checkInt(program, callFunction(program, "foo", [], [makeInt(program, 3)]), 6); | |
| checkInt(program, callFunction(program, "foo", [], [makeInt(program, 4)]), 6); | |
| checkInt(program, callFunction(program, "foo", [], [makeInt(program, 5)]), 6); | |
| checkInt(program, callFunction(program, "foo", [], [makeInt(program, 6)]), 6); | |
| checkInt(program, callFunction(program, "foo", [], [makeInt(program, 7)]), 8); | |
| checkInt(program, callFunction(program, "foo", [], [makeInt(program, 8)]), 6); | |
| checkInt(program, callFunction(program, "foo", [], [makeInt(program, 9)]), 6); | |
| } | |
| tests.ifElseStatement = function() | |
| { | |
| let program = doPrep(` | |
| int foo(int x) | |
| { | |
| int y = 6; | |
| if (x == 7) { | |
| y = 8; | |
| } else { | |
| y = 9; | |
| } | |
| return y; | |
| } | |
| `); | |
| checkInt(program, callFunction(program, "foo", [], [makeInt(program, 3)]), 9); | |
| checkInt(program, callFunction(program, "foo", [], [makeInt(program, 4)]), 9); | |
| checkInt(program, callFunction(program, "foo", [], [makeInt(program, 5)]), 9); | |
| checkInt(program, callFunction(program, "foo", [], [makeInt(program, 6)]), 9); | |
| checkInt(program, callFunction(program, "foo", [], [makeInt(program, 7)]), 8); | |
| checkInt(program, callFunction(program, "foo", [], [makeInt(program, 8)]), 9); | |
| checkInt(program, callFunction(program, "foo", [], [makeInt(program, 9)]), 9); | |
| } | |
| tests.ifElseIfStatement = function() | |
| { | |
| let program = doPrep(` | |
| int foo(int x) | |
| { | |
| int y = 6; | |
| if (x == 7) { | |
| y = 8; | |
| } else if (x == 8) { | |
| y = 9; | |
| } | |
| return y; | |
| } | |
| `); | |
| checkInt(program, callFunction(program, "foo", [], [makeInt(program, 3)]), 6); | |
| checkInt(program, callFunction(program, "foo", [], [makeInt(program, 4)]), 6); | |
| checkInt(program, callFunction(program, "foo", [], [makeInt(program, 5)]), 6); | |
| checkInt(program, callFunction(program, "foo", [], [makeInt(program, 6)]), 6); | |
| checkInt(program, callFunction(program, "foo", [], [makeInt(program, 7)]), 8); | |
| checkInt(program, callFunction(program, "foo", [], [makeInt(program, 8)]), 9); | |
| checkInt(program, callFunction(program, "foo", [], [makeInt(program, 9)]), 6); | |
| } | |
| tests.ifElseIfElseStatement = function() | |
| { | |
| let program = doPrep(` | |
| int foo(int x) | |
| { | |
| int y = 6; | |
| if (x == 7) { | |
| y = 8; | |
| } else if (x == 8) { | |
| y = 9; | |
| } else { | |
| y = 10; | |
| } | |
| return y; | |
| } | |
| `); | |
| checkInt(program, callFunction(program, "foo", [], [makeInt(program, 3)]), 10); | |
| checkInt(program, callFunction(program, "foo", [], [makeInt(program, 4)]), 10); | |
| checkInt(program, callFunction(program, "foo", [], [makeInt(program, 5)]), 10); | |
| checkInt(program, callFunction(program, "foo", [], [makeInt(program, 6)]), 10); | |
| checkInt(program, callFunction(program, "foo", [], [makeInt(program, 7)]), 8); | |
| checkInt(program, callFunction(program, "foo", [], [makeInt(program, 8)]), 9); | |
| checkInt(program, callFunction(program, "foo", [], [makeInt(program, 9)]), 10); | |
| } | |
| tests.returnIf = function() | |
| { | |
| checkFail( | |
| () => doPrep(` | |
| int foo(int x) | |
| { | |
| int y = 6; | |
| if (x == 7) { | |
| return y; | |
| } | |
| } | |
| `), | |
| (e) => e instanceof WTypeError); | |
| checkFail( | |
| () => doPrep(` | |
| int foo(int x) | |
| { | |
| int y = 6; | |
| if (x == 7) { | |
| return y; | |
| } else { | |
| y = 8; | |
| } | |
| } | |
| `), | |
| (e) => e instanceof WTypeError); | |
| checkFail( | |
| () => doPrep(` | |
| int foo(int x) | |
| { | |
| int y = 6; | |
| if (x == 7) { | |
| y = 8; | |
| } else { | |
| return y; | |
| } | |
| } | |
| `), | |
| (e) => e instanceof WTypeError); | |
| let program = doPrep(` | |
| int foo(int x) | |
| { | |
| int y = 6; | |
| if (x == 7) { | |
| return 8; | |
| } else { | |
| return 10; | |
| } | |
| } | |
| `); | |
| checkInt(program, callFunction(program, "foo", [], [makeInt(program, 3)]), 10); | |
| checkInt(program, callFunction(program, "foo", [], [makeInt(program, 4)]), 10); | |
| checkInt(program, callFunction(program, "foo", [], [makeInt(program, 5)]), 10); | |
| checkInt(program, callFunction(program, "foo", [], [makeInt(program, 6)]), 10); | |
| checkInt(program, callFunction(program, "foo", [], [makeInt(program, 7)]), 8); | |
| checkInt(program, callFunction(program, "foo", [], [makeInt(program, 8)]), 10); | |
| checkInt(program, callFunction(program, "foo", [], [makeInt(program, 9)]), 10); | |
| checkFail( | |
| () => doPrep(` | |
| int foo(int x) | |
| { | |
| int y = 6; | |
| if (x == 7) { | |
| return 8; | |
| } else if (x == 9) { | |
| return 10; | |
| } | |
| } | |
| `), | |
| (e) => e instanceof WTypeError); | |
| program = doPrep(` | |
| int foo(int x) | |
| { | |
| int y = 6; | |
| if (x == 7) { | |
| return 8; | |
| } else { | |
| y = 9; | |
| } | |
| return y; | |
| } | |
| `); | |
| checkInt(program, callFunction(program, "foo", [], [makeInt(program, 3)]), 9); | |
| checkInt(program, callFunction(program, "foo", [], [makeInt(program, 4)]), 9); | |
| checkInt(program, callFunction(program, "foo", [], [makeInt(program, 5)]), 9); | |
| checkInt(program, callFunction(program, "foo", [], [makeInt(program, 6)]), 9); | |
| checkInt(program, callFunction(program, "foo", [], [makeInt(program, 7)]), 8); | |
| checkInt(program, callFunction(program, "foo", [], [makeInt(program, 8)]), 9); | |
| checkInt(program, callFunction(program, "foo", [], [makeInt(program, 9)]), 9); | |
| checkFail( | |
| () => doPrep(` | |
| int foo(int x) | |
| { | |
| int y = 6; | |
| if (x == 7) { | |
| return 8; | |
| } else { | |
| return 10; | |
| } | |
| return 11; | |
| } | |
| `), | |
| (e) => e instanceof WTypeError); | |
| program = doPrep(` | |
| int foo(int x) | |
| { | |
| int y = 6; | |
| if (x == 7) | |
| int y = 8; | |
| return y; | |
| } | |
| `); | |
| checkInt(program, callFunction(program, "foo", [], [makeInt(program, 7)]), 6); | |
| } | |
| tests.simpleWhile = function() | |
| { | |
| let program = doPrep(` | |
| int foo(int x) | |
| { | |
| while (x < 13) | |
| x = x * 2; | |
| return x; | |
| } | |
| `); | |
| checkInt(program, callFunction(program, "foo", [], [makeInt(program, 1)]), 16); | |
| } | |
| tests.protocolMonoPolySigDoublePolyDefExplicit = function() | |
| { | |
| checkFail( | |
| () => { | |
| let program = doPrep(` | |
| struct IntAnd<T, U> { | |
| int first; | |
| T second; | |
| U third; | |
| } | |
| IntAnd<T, U> intAnd<T, U>(int first, T second, U third) | |
| { | |
| IntAnd<T, U> result; | |
| result.first = first; | |
| result.second = second; | |
| result.third = third; | |
| return result; | |
| } | |
| protocol IntAndable { | |
| IntAnd<T, int> intAnd<T>(IntAndable, T, int); | |
| } | |
| int foo<T:IntAndable>(T first, int second, int third) | |
| { | |
| IntAnd<int, int> result = intAnd<int>(first, second, third); | |
| return result.first + result.second + result.third; | |
| } | |
| `); | |
| callFunction(program, "foo", [], [makeInt(program, 54), makeInt(program, 12), makeInt(program, 39)]); | |
| }, | |
| (e) => e instanceof WTypeError); | |
| } | |
| tests.ambiguousOverloadSimple = function() | |
| { | |
| checkFail( | |
| () => doPrep(` | |
| void foo<T>(int, T) { } | |
| void foo<T>(T, int) { } | |
| void bar(int a, int b) { foo(a, b); } | |
| `), | |
| (e) => e instanceof WTypeError); | |
| } | |
| tests.ambiguousOverloadOverlapping = function() | |
| { | |
| checkFail( | |
| () => doPrep(` | |
| void foo<T>(int, T) { } | |
| void foo<T>(T, T) { } | |
| void bar(int a, int b) { foo(a, b); } | |
| `), | |
| (e) => e instanceof WTypeError); | |
| } | |
| tests.ambiguousOverloadTieBreak = function() | |
| { | |
| doPrep(` | |
| void foo<T>(int, T) { } | |
| void foo<T>(T, T) { } | |
| void foo(int, int) { } | |
| void bar(int a, int b) { foo(a, b); } | |
| `); | |
| } | |
| tests.intOverloadResolution = function() | |
| { | |
| let program = doPrep(` | |
| int foo(int) { return 1; } | |
| int foo(uint) { return 2; } | |
| int foo(double) { return 3; } | |
| int bar() { return foo(42); } | |
| `); | |
| checkInt(program, callFunction(program, "bar", [], []), 1); | |
| } | |
| tests.intOverloadResolutionReverseOrder = function() | |
| { | |
| let program = doPrep(` | |
| int foo(double) { return 3; } | |
| int foo(uint) { return 2; } | |
| int foo(int) { return 1; } | |
| int bar() { return foo(42); } | |
| `); | |
| checkInt(program, callFunction(program, "bar", [], []), 1); | |
| } | |
| tests.intOverloadResolutionGeneric = function() | |
| { | |
| let program = doPrep(` | |
| int foo(int) { return 1; } | |
| int foo<T>(T) { return 2; } | |
| int bar() { return foo(42); } | |
| `); | |
| checkInt(program, callFunction(program, "bar", [], []), 1); | |
| } | |
| tests.intLiteralGeneric = function() | |
| { | |
| let program = doPrep(` | |
| int foo<T>(T x) { return 3478; } | |
| int bar() { return foo(42); } | |
| `); | |
| checkInt(program, callFunction(program, "bar", [], []), 3478); | |
| } | |
| tests.intLiteralGenericWithProtocols = function() | |
| { | |
| let program = doPrep(` | |
| protocol MyConvertibleToInt { | |
| operator int(MyConvertibleToInt); | |
| } | |
| int foo<T:MyConvertibleToInt>(T x) { return int(x); } | |
| int bar() { return foo(42); } | |
| `); | |
| checkInt(program, callFunction(program, "bar", [], []), 42); | |
| } | |
| tests.uintLiteralGeneric = function() | |
| { | |
| let program = doPrep(` | |
| int foo<T>(T x) { return 3478; } | |
| int bar() { return foo(42u); } | |
| `); | |
| checkInt(program, callFunction(program, "bar", [], []), 3478); | |
| } | |
| tests.uintLiteralGenericWithProtocols = function() | |
| { | |
| let program = doPrep(` | |
| protocol MyConvertibleToUint { | |
| operator uint(MyConvertibleToUint); | |
| } | |
| uint foo<T:MyConvertibleToUint>(T x) { return uint(x); } | |
| uint bar() { return foo(42u); } | |
| `); | |
| checkUint(program, callFunction(program, "bar", [], []), 42); | |
| } | |
| tests.intLiteralGenericSpecific = function() | |
| { | |
| let program = doPrep(` | |
| T foo<T>(T x) { return x; } | |
| int bar() { return foo(int(42)); } | |
| `); | |
| checkInt(program, callFunction(program, "bar", [], []), 42); | |
| } | |
| tests.simpleConstexpr = function() | |
| { | |
| let program = doPrep(` | |
| int foo<int a>(int b) | |
| { | |
| return a + b; | |
| } | |
| int bar(int b) | |
| { | |
| return foo<42>(b); | |
| } | |
| `); | |
| checkInt(program, callFunction(program, "bar", [], [makeInt(program, 58)]), 58 + 42); | |
| } | |
| tests.break = function() | |
| { | |
| let program = doPrep(` | |
| int foo(int x) | |
| { | |
| while (true) { | |
| x = x * 2; | |
| if (x >= 7) | |
| break; | |
| } | |
| return x; | |
| } | |
| `); | |
| checkInt(program, callFunction(program, "foo", [], [makeInt(program, 1)]), 8); | |
| checkInt(program, callFunction(program, "foo", [], [makeInt(program, 10)]), 20); | |
| program = doPrep(` | |
| int foo(int x) | |
| { | |
| while (true) { | |
| while (true) { | |
| x = x * 2; | |
| if (x >= 7) | |
| break; | |
| } | |
| x = x - 1; | |
| break; | |
| } | |
| return x; | |
| } | |
| `); | |
| checkInt(program, callFunction(program, "foo", [], [makeInt(program, 1)]), 7); | |
| checkInt(program, callFunction(program, "foo", [], [makeInt(program, 10)]), 19); | |
| checkFail( | |
| () => doPrep(` | |
| int foo(int x) | |
| { | |
| while (true) { | |
| { | |
| break; | |
| } | |
| x = x + 1; | |
| } | |
| return x; | |
| } | |
| `), | |
| (e) => e instanceof WTypeError); | |
| checkFail( | |
| () => doPrep(` | |
| int foo(int x) | |
| { | |
| break; | |
| return x; | |
| } | |
| `), | |
| (e) => e instanceof WTypeError); | |
| program = doPrep(` | |
| int foo(int x) | |
| { | |
| while (true) { | |
| if (x == 7) { | |
| break; | |
| } | |
| x = x + 1; | |
| } | |
| return x; | |
| } | |
| `); | |
| checkInt(program, callFunction(program, "foo", [], [makeInt(program, 1)]), 7); | |
| program = doPrep(` | |
| int foo(int x) | |
| { | |
| while (true) { | |
| break; | |
| } | |
| return x; | |
| } | |
| `); | |
| checkInt(program, callFunction(program, "foo", [], [makeInt(program, 1)]), 1); | |
| program = doPrep(` | |
| int foo() | |
| { | |
| while (true) { | |
| return 7; | |
| } | |
| } | |
| `); | |
| checkInt(program, callFunction(program, "foo", [], []), 7); | |
| checkFail( | |
| () => doPrep(` | |
| int foo(int x) | |
| { | |
| while(true) { | |
| break; | |
| return 7; | |
| } | |
| } | |
| `), | |
| (e) => e instanceof WTypeError); | |
| } | |
| tests.continue = function() | |
| { | |
| let program = doPrep(` | |
| int foo(int x) | |
| { | |
| while (x < 10) { | |
| if (x == 8) { | |
| x = x + 1; | |
| continue; | |
| } | |
| x = x * 2; | |
| } | |
| return x; | |
| } | |
| `); | |
| checkInt(program, callFunction(program, "foo", [], [makeInt(program, 1)]), 18); | |
| checkFail( | |
| () => doPrep(` | |
| int foo(int x) | |
| { | |
| continue; | |
| return x; | |
| } | |
| `), | |
| (e) => e instanceof WTypeError); | |
| } | |
| tests.doWhile = function() | |
| { | |
| let program = doPrep(` | |
| int foo(int x) | |
| { | |
| int y = 7; | |
| do { | |
| y = 8; | |
| break; | |
| } while (x < 10); | |
| return y; | |
| } | |
| `); | |
| checkInt(program, callFunction(program, "foo", [], [makeInt(program, 1)]), 8); | |
| checkInt(program, callFunction(program, "foo", [], [makeInt(program, 11)]), 8); | |
| program = doPrep(` | |
| int foo(int x) | |
| { | |
| int y = 7; | |
| do { | |
| y = 8; | |
| break; | |
| } while (y == 7); | |
| return y; | |
| } | |
| `); | |
| checkInt(program, callFunction(program, "foo", [], [makeInt(program, 1)]), 8); | |
| program = doPrep(` | |
| int foo(int x) | |
| { | |
| int sum = 0; | |
| do { | |
| if (x == 11) { | |
| x = 15; | |
| continue; | |
| } | |
| sum = sum + x; | |
| x = x + 1; | |
| } while (x < 13); | |
| return sum; | |
| } | |
| `); | |
| checkInt(program, callFunction(program, "foo", [], [makeInt(program, 9)]), 19); | |
| } | |
| tests.forLoop = function() | |
| { | |
| let program = doPrep(` | |
| int foo(int x) | |
| { | |
| int sum = 0; | |
| int i; | |
| for (i = 0; i < x; i = i + 1) { | |
| sum = sum + i; | |
| } | |
| return sum; | |
| } | |
| `); | |
| checkInt(program, callFunction(program, "foo", [], [makeInt(program, 3)]), 3); | |
| checkInt(program, callFunction(program, "foo", [], [makeInt(program, 4)]), 6); | |
| checkInt(program, callFunction(program, "foo", [], [makeInt(program, 5)]), 10); | |
| program = doPrep(` | |
| int foo(int x) | |
| { | |
| int sum = 0; | |
| for (int i = 0; i < x; i = i + 1) { | |
| sum = sum + i; | |
| } | |
| return sum; | |
| } | |
| `); | |
| checkInt(program, callFunction(program, "foo", [], [makeInt(program, 3)]), 3); | |
| checkInt(program, callFunction(program, "foo", [], [makeInt(program, 4)]), 6); | |
| checkInt(program, callFunction(program, "foo", [], [makeInt(program, 5)]), 10); | |
| program = doPrep(` | |
| int foo(int x) | |
| { | |
| int sum = 0; | |
| int i = 100; | |
| for (int i = 0; i < x; i = i + 1) { | |
| sum = sum + i; | |
| } | |
| return sum; | |
| } | |
| `); | |
| checkInt(program, callFunction(program, "foo", [], [makeInt(program, 3)]), 3); | |
| checkInt(program, callFunction(program, "foo", [], [makeInt(program, 4)]), 6); | |
| checkInt(program, callFunction(program, "foo", [], [makeInt(program, 5)]), 10); | |
| program = doPrep(` | |
| int foo(int x) | |
| { | |
| int sum = 0; | |
| for (int i = 0; i < x; i = i + 1) { | |
| if (i == 4) | |
| continue; | |
| sum = sum + i; | |
| } | |
| return sum; | |
| } | |
| `); | |
| checkInt(program, callFunction(program, "foo", [], [makeInt(program, 3)]), 3); | |
| checkInt(program, callFunction(program, "foo", [], [makeInt(program, 4)]), 6); | |
| checkInt(program, callFunction(program, "foo", [], [makeInt(program, 5)]), 6); | |
| checkInt(program, callFunction(program, "foo", [], [makeInt(program, 6)]), 11); | |
| program = doPrep(` | |
| int foo(int x) | |
| { | |
| int sum = 0; | |
| for (int i = 0; i < x; i = i + 1) { | |
| if (i == 5) | |
| break; | |
| sum = sum + i; | |
| } | |
| return sum; | |
| } | |
| `); | |
| checkInt(program, callFunction(program, "foo", [], [makeInt(program, 3)]), 3); | |
| checkInt(program, callFunction(program, "foo", [], [makeInt(program, 4)]), 6); | |
| checkInt(program, callFunction(program, "foo", [], [makeInt(program, 5)]), 10); | |
| checkInt(program, callFunction(program, "foo", [], [makeInt(program, 6)]), 10); | |
| checkInt(program, callFunction(program, "foo", [], [makeInt(program, 7)]), 10); | |
| program = doPrep(` | |
| int foo(int x) | |
| { | |
| int sum = 0; | |
| for (int i = 0; ; i = i + 1) { | |
| if (i >= x) | |
| break; | |
| sum = sum + i; | |
| } | |
| return sum; | |
| } | |
| `); | |
| checkInt(program, callFunction(program, "foo", [], [makeInt(program, 3)]), 3); | |
| checkInt(program, callFunction(program, "foo", [], [makeInt(program, 4)]), 6); | |
| checkInt(program, callFunction(program, "foo", [], [makeInt(program, 5)]), 10); | |
| checkInt(program, callFunction(program, "foo", [], [makeInt(program, 6)]), 15); | |
| checkInt(program, callFunction(program, "foo", [], [makeInt(program, 7)]), 21); | |
| program = doPrep(` | |
| int foo(int x) | |
| { | |
| int sum = 0; | |
| int i = 0; | |
| for ( ; ; i = i + 1) { | |
| if (i >= x) | |
| break; | |
| sum = sum + i; | |
| } | |
| return sum; | |
| } | |
| `); | |
| checkInt(program, callFunction(program, "foo", [], [makeInt(program, 3)]), 3); | |
| checkInt(program, callFunction(program, "foo", [], [makeInt(program, 4)]), 6); | |
| checkInt(program, callFunction(program, "foo", [], [makeInt(program, 5)]), 10); | |
| checkInt(program, callFunction(program, "foo", [], [makeInt(program, 6)]), 15); | |
| checkInt(program, callFunction(program, "foo", [], [makeInt(program, 7)]), 21); | |
| program = doPrep(` | |
| int foo(int x) | |
| { | |
| int sum = 0; | |
| int i = 0; | |
| for ( ; ; ) { | |
| if (i >= x) | |
| break; | |
| sum = sum + i; | |
| i = i + 1; | |
| } | |
| return sum; | |
| } | |
| `); | |
| checkInt(program, callFunction(program, "foo", [], [makeInt(program, 3)]), 3); | |
| checkInt(program, callFunction(program, "foo", [], [makeInt(program, 4)]), 6); | |
| checkInt(program, callFunction(program, "foo", [], [makeInt(program, 5)]), 10); | |
| checkInt(program, callFunction(program, "foo", [], [makeInt(program, 6)]), 15); | |
| checkInt(program, callFunction(program, "foo", [], [makeInt(program, 7)]), 21); | |
| checkFail( | |
| () => doPrep(` | |
| void foo(int x) | |
| { | |
| for (int i = 0; ; i = i + 1) { | |
| break; | |
| x = i; | |
| } | |
| } | |
| `), | |
| (e) => e instanceof WTypeError); | |
| program = doPrep(` | |
| int foo(int x) | |
| { | |
| for ( ; ; ) { | |
| return 7; | |
| } | |
| } | |
| `); | |
| checkInt(program, callFunction(program, "foo", [], [makeInt(program, 3)]), 7); | |
| checkInt(program, callFunction(program, "foo", [], [makeInt(program, 4)]), 7); | |
| checkInt(program, callFunction(program, "foo", [], [makeInt(program, 5)]), 7); | |
| checkInt(program, callFunction(program, "foo", [], [makeInt(program, 6)]), 7); | |
| checkInt(program, callFunction(program, "foo", [], [makeInt(program, 7)]), 7); | |
| checkFail( | |
| () => doPrep(` | |
| int foo(int x) | |
| { | |
| for ( ; x < 10; ) { | |
| return 7; | |
| } | |
| } | |
| `), | |
| (e) => e instanceof WTypeError); | |
| program = doPrep(` | |
| int foo(int x) | |
| { | |
| for ( ; true; ) { | |
| return 7; | |
| } | |
| } | |
| `); | |
| checkInt(program, callFunction(program, "foo", [], [makeInt(program, 3)]), 7); | |
| checkInt(program, callFunction(program, "foo", [], [makeInt(program, 4)]), 7); | |
| checkInt(program, callFunction(program, "foo", [], [makeInt(program, 5)]), 7); | |
| checkInt(program, callFunction(program, "foo", [], [makeInt(program, 6)]), 7); | |
| checkInt(program, callFunction(program, "foo", [], [makeInt(program, 7)]), 7); | |
| } | |
| tests.chainConstexpr = function() | |
| { | |
| let program = doPrep(` | |
| int foo<int a>(int b) | |
| { | |
| return a + b; | |
| } | |
| int bar<int a>(int b) | |
| { | |
| return foo<a>(b); | |
| } | |
| int baz(int b) | |
| { | |
| return bar<42>(b); | |
| } | |
| `); | |
| checkInt(program, callFunction(program, "baz", [], [makeInt(program, 58)]), 58 + 42); | |
| } | |
| tests.chainGeneric = function() | |
| { | |
| let program = doPrep(` | |
| T foo<T>(T x) | |
| { | |
| return x; | |
| } | |
| T bar<T>(thread T* ptr) | |
| { | |
| return *foo(ptr); | |
| } | |
| int baz(int x) | |
| { | |
| return bar(&x); | |
| } | |
| `); | |
| checkInt(program, callFunction(program, "baz", [], [makeInt(program, 37)]), 37); | |
| } | |
| tests.chainStruct = function() | |
| { | |
| let program = doPrep(` | |
| struct Foo<T> { | |
| T f; | |
| } | |
| struct Bar<T> { | |
| Foo<thread T*> f; | |
| } | |
| int foo(thread Bar<int>* x) | |
| { | |
| return *x->f.f; | |
| } | |
| int bar(int a) | |
| { | |
| Bar<int> x; | |
| x.f.f = &a; | |
| return foo(&x); | |
| } | |
| `); | |
| checkInt(program, callFunction(program, "bar", [], [makeInt(program, 4657)]), 4657); | |
| } | |
| tests.chainStructNewlyValid = function() | |
| { | |
| let program = doPrep(` | |
| struct Foo<T> { | |
| T f; | |
| } | |
| struct Bar<T> { | |
| Foo<device T*> f; | |
| } | |
| int foo(thread Bar<int>* x) | |
| { | |
| return *x->f.f; | |
| } | |
| int bar(device int* a) | |
| { | |
| Bar<int> x; | |
| x.f.f = a; | |
| return foo(&x); | |
| } | |
| `); | |
| let buffer = new EBuffer(1); | |
| buffer.set(0, 78453); | |
| checkInt(program, callFunction(program, "bar", [], [TypedValue.box(new PtrType(externalOrigin, "device", program.intrinsics.int32), new EPtr(buffer, 0))]), 78453); | |
| } | |
| tests.chainStructDevice = function() | |
| { | |
| let program = doPrep(` | |
| struct Foo<T> { | |
| T f; | |
| } | |
| struct Bar<T> { | |
| Foo<device T*> f; | |
| } | |
| int foo(thread Bar<int>* x) | |
| { | |
| return *x->f.f; | |
| } | |
| int bar(device int* a) | |
| { | |
| Bar<int> x; | |
| x.f.f = a; | |
| return foo(&x); | |
| } | |
| `); | |
| let buffer = new EBuffer(1); | |
| buffer.set(0, 79201); | |
| checkInt(program, callFunction(program, "bar", [], [TypedValue.box(new PtrType(externalOrigin, "device", program.intrinsics.int32), new EPtr(buffer, 0))]), 79201); | |
| } | |
| tests.paramChainStructDevice = function() | |
| { | |
| let program = doPrep(` | |
| struct Foo<T> { | |
| T f; | |
| } | |
| struct Bar<T> { | |
| Foo<T> f; | |
| } | |
| int foo(thread Bar<device int*>* x) | |
| { | |
| return *x->f.f; | |
| } | |
| int bar(device int* a) | |
| { | |
| Bar<device int*> x; | |
| x.f.f = a; | |
| return foo(&x); | |
| } | |
| `); | |
| let buffer = new EBuffer(1); | |
| buffer.set(0, 79201); | |
| checkInt(program, callFunction(program, "bar", [], [TypedValue.box(new PtrType(externalOrigin, "device", program.intrinsics.int32), new EPtr(buffer, 0))]), 79201); | |
| } | |
| tests.simpleProtocolExtends = function() | |
| { | |
| let program = doPrep(` | |
| protocol Foo { | |
| void foo(thread Foo*); | |
| } | |
| protocol Bar : Foo { | |
| void bar(thread Bar*); | |
| } | |
| void fuzz<T:Foo>(thread T* p) | |
| { | |
| foo(p); | |
| } | |
| void buzz<T:Bar>(thread T* p) | |
| { | |
| fuzz(p); | |
| bar(p); | |
| } | |
| void foo(thread int* p) | |
| { | |
| *p = *p + 743; | |
| } | |
| void bar(thread int* p) | |
| { | |
| *p = *p + 91; | |
| } | |
| int thingy(int a) | |
| { | |
| buzz(&a); | |
| return a; | |
| } | |
| `); | |
| checkInt(program, callFunction(program, "thingy", [], [makeInt(program, 642)]), 642 + 743 + 91); | |
| } | |
| tests.protocolExtendsTwo = function() | |
| { | |
| let program = doPrep(` | |
| protocol Foo { | |
| void foo(thread Foo*); | |
| } | |
| protocol Bar { | |
| void bar(thread Bar*); | |
| } | |
| protocol Baz : Foo, Bar { | |
| void baz(thread Baz*); | |
| } | |
| void fuzz<T:Foo>(thread T* p) | |
| { | |
| foo(p); | |
| } | |
| void buzz<T:Bar>(thread T* p) | |
| { | |
| bar(p); | |
| } | |
| void xuzz<T:Baz>(thread T* p) | |
| { | |
| fuzz(p); | |
| buzz(p); | |
| baz(p); | |
| } | |
| void foo(thread int* p) | |
| { | |
| *p = *p + 743; | |
| } | |
| void bar(thread int* p) | |
| { | |
| *p = *p + 91; | |
| } | |
| void baz(thread int* p) | |
| { | |
| *p = *p + 39; | |
| } | |
| int thingy(int a) | |
| { | |
| xuzz(&a); | |
| return a; | |
| } | |
| `); | |
| checkInt(program, callFunction(program, "thingy", [], [makeInt(program, 642)]), 642 + 743 + 91 + 39); | |
| } | |
| tests.prefixPlusPlus = function() | |
| { | |
| let program = doPrep(` | |
| int foo(int x) | |
| { | |
| ++x; | |
| return x; | |
| } | |
| `); | |
| checkInt(program, callFunction(program, "foo", [], [makeInt(program, 64)]), 65); | |
| } | |
| tests.prefixPlusPlusResult = function() | |
| { | |
| let program = doPrep(` | |
| int foo(int x) | |
| { | |
| return ++x; | |
| } | |
| `); | |
| checkInt(program, callFunction(program, "foo", [], [makeInt(program, 64)]), 65); | |
| } | |
| tests.postfixPlusPlus = function() | |
| { | |
| let program = doPrep(` | |
| int foo(int x) | |
| { | |
| x++; | |
| return x; | |
| } | |
| `); | |
| checkInt(program, callFunction(program, "foo", [], [makeInt(program, 64)]), 65); | |
| } | |
| tests.postfixPlusPlusResult = function() | |
| { | |
| let program = doPrep(` | |
| int foo(int x) | |
| { | |
| return x++; | |
| } | |
| `); | |
| checkInt(program, callFunction(program, "foo", [], [makeInt(program, 64)]), 64); | |
| } | |
| tests.prefixMinusMinus = function() | |
| { | |
| let program = doPrep(` | |
| int foo(int x) | |
| { | |
| --x; | |
| return x; | |
| } | |
| `); | |
| checkInt(program, callFunction(program, "foo", [], [makeInt(program, 64)]), 63); | |
| } | |
| tests.prefixMinusMinusResult = function() | |
| { | |
| let program = doPrep(` | |
| int foo(int x) | |
| { | |
| return --x; | |
| } | |
| `); | |
| checkInt(program, callFunction(program, "foo", [], [makeInt(program, 64)]), 63); | |
| } | |
| tests.postfixMinusMinus = function() | |
| { | |
| let program = doPrep(` | |
| int foo(int x) | |
| { | |
| x--; | |
| return x; | |
| } | |
| `); | |
| checkInt(program, callFunction(program, "foo", [], [makeInt(program, 64)]), 63); | |
| } | |
| tests.postfixMinusMinusResult = function() | |
| { | |
| let program = doPrep(` | |
| int foo(int x) | |
| { | |
| return x--; | |
| } | |
| `); | |
| checkInt(program, callFunction(program, "foo", [], [makeInt(program, 64)]), 64); | |
| } | |
| tests.plusEquals = function() | |
| { | |
| let program = doPrep(` | |
| int foo(int x) | |
| { | |
| x += 42; | |
| return x; | |
| } | |
| `); | |
| checkInt(program, callFunction(program, "foo", [], [makeInt(program, 385)]), 385 + 42); | |
| } | |
| tests.plusEqualsResult = function() | |
| { | |
| let program = doPrep(` | |
| int foo(int x) | |
| { | |
| return x += 42; | |
| } | |
| `); | |
| checkInt(program, callFunction(program, "foo", [], [makeInt(program, 385)]), 385 + 42); | |
| } | |
| tests.minusEquals = function() | |
| { | |
| let program = doPrep(` | |
| int foo(int x) | |
| { | |
| x -= 42; | |
| return x; | |
| } | |
| `); | |
| checkInt(program, callFunction(program, "foo", [], [makeInt(program, 385)]), 385 - 42); | |
| } | |
| tests.minusEqualsResult = function() | |
| { | |
| let program = doPrep(` | |
| int foo(int x) | |
| { | |
| return x -= 42; | |
| } | |
| `); | |
| checkInt(program, callFunction(program, "foo", [], [makeInt(program, 385)]), 385 - 42); | |
| } | |
| tests.timesEquals = function() | |
| { | |
| let program = doPrep(` | |
| int foo(int x) | |
| { | |
| x *= 42; | |
| return x; | |
| } | |
| `); | |
| checkInt(program, callFunction(program, "foo", [], [makeInt(program, 385)]), 385 * 42); | |
| } | |
| tests.timesEqualsResult = function() | |
| { | |
| let program = doPrep(` | |
| int foo(int x) | |
| { | |
| return x *= 42; | |
| } | |
| `); | |
| checkInt(program, callFunction(program, "foo", [], [makeInt(program, 385)]), 385 * 42); | |
| } | |
| tests.divideEquals = function() | |
| { | |
| let program = doPrep(` | |
| int foo(int x) | |
| { | |
| x /= 42; | |
| return x; | |
| } | |
| `); | |
| checkInt(program, callFunction(program, "foo", [], [makeInt(program, 385)]), (385 / 42) | 0); | |
| } | |
| tests.divideEqualsResult = function() | |
| { | |
| let program = doPrep(` | |
| int foo(int x) | |
| { | |
| return x /= 42; | |
| } | |
| `); | |
| checkInt(program, callFunction(program, "foo", [], [makeInt(program, 385)]), (385 / 42) | 0); | |
| } | |
| tests.twoIntLiterals = function() | |
| { | |
| let program = doPrep(` | |
| bool foo() | |
| { | |
| return 42 == 42; | |
| } | |
| `); | |
| checkBool(program, callFunction(program, "foo", [], []), true); | |
| } | |
| tests.unifyDifferentLiterals = function() | |
| { | |
| checkFail( | |
| () => doPrep(` | |
| void bar<T>(T, T) | |
| { | |
| } | |
| void foo() | |
| { | |
| bar(42, 42u); | |
| } | |
| `), | |
| (e) => e instanceof WTypeError); | |
| } | |
| tests.unifyDifferentLiteralsBackwards = function() | |
| { | |
| checkFail( | |
| () => doPrep(` | |
| void bar<T>(T, T) | |
| { | |
| } | |
| void foo() | |
| { | |
| bar(42u, 42); | |
| } | |
| `), | |
| (e) => e instanceof WTypeError); | |
| } | |
| tests.unifyVeryDifferentLiterals = function() | |
| { | |
| checkFail( | |
| () => doPrep(` | |
| void bar<T>(T, T) | |
| { | |
| } | |
| void foo() | |
| { | |
| bar(42, null); | |
| } | |
| `), | |
| (e) => e instanceof WTypeError); | |
| } | |
| tests.unifyVeryDifferentLiteralsBackwards = function() | |
| { | |
| checkFail( | |
| () => doPrep(` | |
| void bar<T>(T, T) | |
| { | |
| } | |
| void foo() | |
| { | |
| bar(null, 42); | |
| } | |
| `), | |
| (e) => e instanceof WTypeError); | |
| } | |
| tests.assignUintToInt = function() | |
| { | |
| checkFail( | |
| () => doPrep(` | |
| void foo() | |
| { | |
| int x = 42u; | |
| } | |
| `), | |
| (e) => e instanceof WTypeError && e.message.indexOf("Type mismatch in variable initialization") != -1); | |
| } | |
| tests.buildArrayThenSumIt = function() | |
| { | |
| let program = doPrep(` | |
| int foo() | |
| { | |
| int[42] array; | |
| for (uint i = 0; i < 42; i = i + 1) | |
| array[i] = int(i + 5); | |
| int result; | |
| for (uint i = 0; i < 42; i = i + 1) | |
| result = result + array[i]; | |
| return result; | |
| } | |
| `); | |
| checkInt(program, callFunction(program, "foo", [], []), 42 * 5 + 42 * 41 / 2); | |
| } | |
| tests.buildArrayThenSumItUsingArrayReference = function() | |
| { | |
| let program = doPrep(` | |
| int bar(thread int[] array) | |
| { | |
| for (uint i = 0; i < 42; i = i + 1) | |
| array[i] = int(i + 5); | |
| int result; | |
| for (uint i = 0; i < 42; i = i + 1) | |
| result = result + array[i]; | |
| return result; | |
| } | |
| int foo() | |
| { | |
| int[42] array; | |
| return bar(@array); | |
| } | |
| `); | |
| checkInt(program, callFunction(program, "foo", [], []), 42 * 5 + 42 * 41 / 2); | |
| } | |
| tests.overrideSubscriptStruct = function() | |
| { | |
| let program = doPrep(` | |
| struct Foo { | |
| int x; | |
| int y; | |
| } | |
| thread int* operator&[](thread Foo* foo, uint index) | |
| { | |
| if (index == 0) | |
| return &foo->x; | |
| if (index == 1) | |
| return &foo->y; | |
| return null; | |
| } | |
| int foo() | |
| { | |
| Foo foo; | |
| foo.x = 498; | |
| foo.y = 19; | |
| return foo[0] + foo[1] * 3; | |
| } | |
| `); | |
| checkInt(program, callFunction(program, "foo", [], []), 498 + 19 * 3); | |
| } | |
| tests.overrideSubscriptStructAndDoStores = function() | |
| { | |
| let program = doPrep(` | |
| struct Foo { | |
| int x; | |
| int y; | |
| } | |
| thread int* operator&[](thread Foo* foo, uint index) | |
| { | |
| if (index == 0) | |
| return &foo->x; | |
| if (index == 1) | |
| return &foo->y; | |
| return null; | |
| } | |
| int foo() | |
| { | |
| Foo foo; | |
| foo[0] = 498; | |
| foo[1] = 19; | |
| return foo.x + foo.y; | |
| } | |
| `); | |
| checkInt(program, callFunction(program, "foo", [], []), 498 + 19); | |
| } | |
| tests.overrideSubscriptStructAndUsePointers = function() | |
| { | |
| let program = doPrep(` | |
| struct Foo { | |
| int x; | |
| int y; | |
| } | |
| thread int* operator&[](thread Foo* foo, uint index) | |
| { | |
| if (index == 0) | |
| return &foo->x; | |
| if (index == 1) | |
| return &foo->y; | |
| return null; | |
| } | |
| int bar(thread Foo* foo) | |
| { | |
| return (*foo)[0] + (*foo)[1]; | |
| } | |
| int foo() | |
| { | |
| Foo foo; | |
| foo.x = 498; | |
| foo.y = 19; | |
| return bar(&foo); | |
| } | |
| `); | |
| checkInt(program, callFunction(program, "foo", [], []), 498 + 19); | |
| } | |
| tests.overrideSubscriptStructAndUsePointersIncorrectly = function() | |
| { | |
| checkFail( | |
| () => doPrep(` | |
| struct Foo { | |
| int x; | |
| int y; | |
| } | |
| thread int* operator&[](thread Foo* foo, uint index) | |
| { | |
| if (index == 0) | |
| return &foo->x; | |
| if (index == 1) | |
| return &foo->y; | |
| return null; | |
| } | |
| int bar(thread Foo* foo) | |
| { | |
| return foo[0] + foo[1]; | |
| } | |
| int foo() | |
| { | |
| Foo foo; | |
| foo.x = 498; | |
| foo.y = 19; | |
| return bar(&foo); | |
| } | |
| `), | |
| (e) => e instanceof WTypeError); | |
| } | |
| tests.makeArrayRefFromLocal = function() | |
| { | |
| let program = doPrep(` | |
| int bar(thread int[] ref) | |
| { | |
| return ref[0]; | |
| } | |
| int foo() | |
| { | |
| int x = 48; | |
| return bar(@x); | |
| } | |
| `); | |
| checkInt(program, callFunction(program, "foo", [], []), 48); | |
| } | |
| tests.makeArrayRefFromPointer = function() | |
| { | |
| let program = doPrep(` | |
| int bar(thread int[] ref) | |
| { | |
| return ref[0]; | |
| } | |
| int baz(thread int* ptr) | |
| { | |
| return bar(@ptr); | |
| } | |
| int foo() | |
| { | |
| int x = 48; | |
| return baz(&x); | |
| } | |
| `); | |
| checkInt(program, callFunction(program, "foo", [], []), 48); | |
| } | |
| tests.makeArrayRefFromArrayRef = function() | |
| { | |
| checkFail( | |
| () => doPrep(` | |
| int bar(thread int[] ref) | |
| { | |
| return ref[0]; | |
| } | |
| int baz(thread int[] ptr) | |
| { | |
| return bar(@ptr); | |
| } | |
| int foo() | |
| { | |
| int x = 48; | |
| return baz(@x); | |
| } | |
| `), | |
| (e) => e instanceof WTypeError); | |
| } | |
| tests.simpleLength = function() | |
| { | |
| let program = doPrep(` | |
| uint foo() | |
| { | |
| double[754] array; | |
| return (@array).length; | |
| } | |
| `); | |
| checkUint(program, callFunction(program, "foo", [], []), 754); | |
| } | |
| tests.nonArrayRefArrayLengthSucceed = function() | |
| { | |
| let program = doPrep(` | |
| uint foo() | |
| { | |
| double[754] array; | |
| return array.length; | |
| } | |
| `); | |
| checkUint(program, callFunction(program, "foo", [], []), 754); | |
| } | |
| tests.nonArrayRefArrayLengthFail = function() | |
| { | |
| checkFail( | |
| () => doPrep(` | |
| thread uint* lengthPtr() | |
| { | |
| int[42] array; | |
| return &(array.length); | |
| } | |
| `), | |
| e => e instanceof WTypeError); | |
| } | |
| tests.constexprIsNotLValuePtr = function() | |
| { | |
| checkFail( | |
| () => doPrep(` | |
| thread int* foo<int x>() | |
| { | |
| return &x; | |
| } | |
| `), | |
| e => e instanceof WTypeError); | |
| } | |
| tests.constexprIsNotLValueAssign = function() | |
| { | |
| checkFail( | |
| () => doPrep(` | |
| void foo<int x>() | |
| { | |
| x = 42; | |
| } | |
| `), | |
| e => e instanceof WTypeError); | |
| } | |
| tests.constexprIsNotLValueRMW = function() | |
| { | |
| checkFail( | |
| () => doPrep(` | |
| void foo<int x>() | |
| { | |
| x += 42; | |
| } | |
| `), | |
| e => e instanceof WTypeError); | |
| } | |
| tests.assignLength = function() | |
| { | |
| checkFail( | |
| () => doPrep(` | |
| void foo() | |
| { | |
| double[754] array; | |
| (@array).length = 42; | |
| } | |
| `), | |
| (e) => e instanceof WTypeError && e.message.indexOf("Have neither ander nor setter") != -1); | |
| } | |
| tests.assignLengthHelper = function() | |
| { | |
| checkFail( | |
| () => doPrep(` | |
| void bar(thread double[] array) | |
| { | |
| array.length = 42; | |
| } | |
| void foo() | |
| { | |
| double[754] array; | |
| bar(@array); | |
| } | |
| `), | |
| (e) => e instanceof WTypeError && e.message.indexOf("Have neither ander nor setter") != -1); | |
| } | |
| tests.simpleGetter = function() | |
| { | |
| let program = doPrep(` | |
| struct Foo { | |
| int x; | |
| } | |
| int operator.y(Foo foo) | |
| { | |
| return foo.x; | |
| } | |
| int foo() | |
| { | |
| Foo foo; | |
| foo.x = 7804; | |
| return foo.y; | |
| } | |
| `); | |
| checkInt(program, callFunction(program, "foo", [], []), 7804); | |
| } | |
| tests.simpleSetter = function() | |
| { | |
| let program = doPrep(` | |
| struct Foo { | |
| int x; | |
| } | |
| int operator.y(Foo foo) | |
| { | |
| return foo.x; | |
| } | |
| Foo operator.y=(Foo foo, int value) | |
| { | |
| foo.x = value; | |
| return foo; | |
| } | |
| int foo() | |
| { | |
| Foo foo; | |
| foo.y = 7804; | |
| return foo.x; | |
| } | |
| `); | |
| checkInt(program, callFunction(program, "foo", [], []), 7804); | |
| } | |
| tests.genericAccessors = function() | |
| { | |
| let program = doPrep(` | |
| struct Foo<T> { | |
| T x; | |
| T[3] y; | |
| } | |
| struct Bar<T> { | |
| T x; | |
| T y; | |
| } | |
| Bar<T> operator.z<T>(Foo<T> foo) | |
| { | |
| Bar<T> result; | |
| result.x = foo.x; | |
| result.y = foo.y[1]; | |
| return result; | |
| } | |
| Foo<T> operator.z=<T>(Foo<T> foo, Bar<T> bar) | |
| { | |
| foo.x = bar.x; | |
| foo.y[1] = bar.y; | |
| return foo; | |
| } | |
| T operator.sum<T:Addable>(Foo<T> foo) | |
| { | |
| return foo.x + foo.y[0] + foo.y[1] + foo.y[2]; | |
| } | |
| T operator.sum<T:Addable>(Bar<T> bar) | |
| { | |
| return bar.x + bar.y; | |
| } | |
| operator<T> Bar<T>(T x, T y) | |
| { | |
| Bar<T> result; | |
| result.x = x; | |
| result.y = y; | |
| return result; | |
| } | |
| void setup(thread Foo<int>* foo) | |
| { | |
| foo->x = 1; | |
| foo->y[0] = 2; | |
| foo->y[1] = 3; | |
| foo->y[2] = 4; | |
| } | |
| int testSuperBasic() | |
| { | |
| Foo<int> foo; | |
| setup(&foo); | |
| return foo.sum; | |
| } | |
| int testZSetterDidSetY() | |
| { | |
| Foo<int> foo; | |
| foo.z = Bar<int>(53, 932); | |
| return foo.y[1]; | |
| } | |
| int testZSetter() | |
| { | |
| Foo<int> foo; | |
| foo.z = Bar<int>(53, 932); | |
| return foo.sum; | |
| } | |
| int testZGetter() | |
| { | |
| Foo<int> foo; | |
| // This deliberately does not call setup() just so we test this syntax. | |
| foo.x = 1; | |
| foo.y[0] = 2; | |
| foo.y[1] = 3; | |
| foo.y[2] = 4; | |
| return foo.z.sum; | |
| } | |
| int testLValueEmulation() | |
| { | |
| Foo<int> foo; | |
| setup(&foo); | |
| foo.z.y *= 5; | |
| return foo.sum; | |
| } | |
| `); | |
| checkInt(program, callFunction(program, "testSuperBasic", [], []), 1 + 2 + 3 + 4); | |
| checkInt(program, callFunction(program, "testZSetterDidSetY", [], []), 932); | |
| checkInt(program, callFunction(program, "testZSetter", [], []), 53 + 932); | |
| checkInt(program, callFunction(program, "testZGetter", [], []), 1 + 3); | |
| checkInt(program, callFunction(program, "testLValueEmulation", [], []), 1 + 2 + 3 * 5 + 4); | |
| } | |
| tests.bitSubscriptAccessor = function() | |
| { | |
| let program = doPrep(` | |
| protocol MyBitmaskable : Equatable { | |
| MyBitmaskable operator&(MyBitmaskable, MyBitmaskable); | |
| MyBitmaskable operator|(MyBitmaskable, MyBitmaskable); | |
| MyBitmaskable operator~(MyBitmaskable); | |
| MyBitmaskable operator<<(MyBitmaskable, uint); | |
| MyBitmaskable operator>>(MyBitmaskable, uint); | |
| operator MyBitmaskable(int); | |
| } | |
| T maskForBitIndex<T:MyBitmaskable>(uint index) | |
| { | |
| return T(1) << index; | |
| } | |
| bool operator[]<T:MyBitmaskable>(T value, uint index) | |
| { | |
| return bool(value & maskForBitIndex<T>(index)); | |
| } | |
| T operator[]=<T:MyBitmaskable>(T value, uint index, bool bit) | |
| { | |
| T mask = maskForBitIndex<T>(index); | |
| if (bit) | |
| value |= mask; | |
| else | |
| value &= ~mask; | |
| return value; | |
| } | |
| uint operator.length(int) | |
| { | |
| return 32; | |
| } | |
| uint operator.length(uint) | |
| { | |
| return 32; | |
| } | |
| int testIntSetBit3() | |
| { | |
| int foo; | |
| foo[3] = true; | |
| return foo; | |
| } | |
| bool testIntSetGetBit5() | |
| { | |
| int foo; | |
| foo[5] = true; | |
| return foo[5]; | |
| } | |
| bool testIntGetBit1() | |
| { | |
| int foo; | |
| return foo[1]; | |
| } | |
| int testUintSumBits() | |
| { | |
| int foo = 42; | |
| int result; | |
| for (uint i = 0; i < foo.length; ++i) { | |
| if (foo[i]) | |
| result++; | |
| } | |
| return result; | |
| } | |
| int testUintSwapBits() | |
| { | |
| int foo = 42; | |
| for (uint i = 0; i < foo.length / 2; ++i) { | |
| bool tmp = foo[i]; | |
| foo[i] = foo[foo.length - i - 1]; | |
| foo[foo.length - i - 1] = tmp; | |
| } | |
| return foo; | |
| } | |
| struct Foo { | |
| uint f; | |
| uint g; | |
| } | |
| operator Foo(uint f, uint g) | |
| { | |
| Foo result; | |
| result.f = f; | |
| result.g = g; | |
| return result; | |
| } | |
| int operator.h(Foo foo) | |
| { | |
| return int((foo.f & 0xffff) | ((foo.g & 0xffff) << 16)); | |
| } | |
| Foo operator.h=(Foo foo, int value) | |
| { | |
| foo.f &= ~0xffffu; | |
| foo.f |= uint(value) & 0xffff; | |
| foo.g &= ~0xffffu; | |
| foo.g |= (uint(value) >> 16) & 0xffff; | |
| return foo; | |
| } | |
| int testLValueEmulation() | |
| { | |
| Foo foo; | |
| foo.f = 42; | |
| foo.g = 37; | |
| for (uint i = 0; i < foo.h.length; ++i) | |
| foo.h[i] ^= true; | |
| return int(foo.f + foo.g); | |
| } | |
| struct Bar { | |
| Foo a; | |
| Foo b; | |
| } | |
| Foo operator.c(Bar bar) | |
| { | |
| return Foo(uint(bar.a.h), uint(bar.b.h)); | |
| } | |
| Bar operator.c=(Bar bar, Foo foo) | |
| { | |
| bar.a.h = int(foo.f); | |
| bar.b.h = int(foo.g); | |
| return bar; | |
| } | |
| int testCrazyLValueEmulation() | |
| { | |
| Bar bar; | |
| bar.a.f = 1; | |
| bar.a.g = 2; | |
| bar.b.f = 3; | |
| bar.b.g = 4; | |
| for (uint i = 0; i < bar.c.h.length; i += 2) | |
| bar.c.h[i] ^= true; | |
| return int(bar.a.f + bar.a.g + bar.b.f + bar.b.g); | |
| } | |
| `); | |
| checkInt(program, callFunction(program, "testIntSetBit3", [], []), 8); | |
| checkBool(program, callFunction(program, "testIntSetGetBit5", [], []), true); | |
| checkBool(program, callFunction(program, "testIntGetBit1", [], []), false); | |
| checkInt(program, callFunction(program, "testUintSumBits", [], []), 3); | |
| checkInt(program, callFunction(program, "testUintSwapBits", [], []), 1409286144); | |
| checkInt(program, callFunction(program, "testLValueEmulation", [], []), 130991); | |
| checkInt(program, callFunction(program, "testCrazyLValueEmulation", [], []), 43696); | |
| } | |
| tests.nestedSubscriptLValueEmulationSimple = function() | |
| { | |
| let program = doPrep(` | |
| struct Foo { | |
| int[7] array; | |
| } | |
| int operator[](Foo foo, uint index) | |
| { | |
| return foo.array[index]; | |
| } | |
| Foo operator[]=(Foo foo, uint index, int value) | |
| { | |
| foo.array[index] = value; | |
| return foo; | |
| } | |
| uint operator.length(Foo foo) | |
| { | |
| return foo.array.length; | |
| } | |
| int sum(Foo foo) | |
| { | |
| int result = 0; | |
| for (uint i = foo.length; i--;) | |
| result += foo[i]; | |
| return result; | |
| } | |
| struct Bar { | |
| Foo[6] array; | |
| } | |
| uint operator.length(Bar bar) | |
| { | |
| return bar.array.length; | |
| } | |
| Foo operator[](Bar bar, uint index) | |
| { | |
| return bar.array[index]; | |
| } | |
| Bar operator[]=(Bar bar, uint index, Foo value) | |
| { | |
| bar.array[index] = value; | |
| return bar; | |
| } | |
| int sum(Bar bar) | |
| { | |
| int result = 0; | |
| for (uint i = bar.length; i--;) | |
| result += sum(bar[i]); | |
| return result; | |
| } | |
| struct Baz { | |
| Bar[5] array; | |
| } | |
| Bar operator[](Baz baz, uint index) | |
| { | |
| return baz.array[index]; | |
| } | |
| Baz operator[]=(Baz baz, uint index, Bar value) | |
| { | |
| baz.array[index] = value; | |
| return baz; | |
| } | |
| uint operator.length(Baz baz) | |
| { | |
| return baz.array.length; | |
| } | |
| int sum(Baz baz) | |
| { | |
| int result = 0; | |
| for (uint i = baz.length; i--;) | |
| result += sum(baz[i]); | |
| return result; | |
| } | |
| void setValues(thread Baz* baz) | |
| { | |
| for (uint i = baz->length; i--;) { | |
| for (uint j = (*baz)[i].length; j--;) { | |
| for (uint k = (*baz)[i][j].length; k--;) | |
| (*baz)[i][j][k] = int(i + j + k); | |
| } | |
| } | |
| } | |
| int testSetValuesAndSum() | |
| { | |
| Baz baz; | |
| setValues(&baz); | |
| return sum(baz); | |
| } | |
| int testSetValuesMutateValuesAndSum() | |
| { | |
| Baz baz; | |
| setValues(&baz); | |
| for (uint i = baz.length; i--;) { | |
| for (uint j = baz[i].length; j--;) { | |
| for (uint k = baz[i][j].length; k--;) | |
| baz[i][j][k] *= int(k); | |
| } | |
| } | |
| return sum(baz); | |
| } | |
| `); | |
| checkInt(program, callFunction(program, "testSetValuesAndSum", [], []), 1575); | |
| checkInt(program, callFunction(program, "testSetValuesMutateValuesAndSum", [], []), 5565); | |
| } | |
| tests.nestedSubscriptLValueEmulationGeneric = function() | |
| { | |
| let program = doPrep(` | |
| struct Foo<T> { | |
| T[7] array; | |
| } | |
| T operator[]<T>(Foo<T> foo, uint index) | |
| { | |
| return foo.array[index]; | |
| } | |
| Foo<T> operator[]=<T>(Foo<T> foo, uint index, T value) | |
| { | |
| foo.array[index] = value; | |
| return foo; | |
| } | |
| uint operator.length<T>(Foo<T> foo) | |
| { | |
| return foo.array.length; | |
| } | |
| protocol MyAddable { | |
| MyAddable operator+(MyAddable, MyAddable); | |
| } | |
| T sum<T:MyAddable>(Foo<T> foo) | |
| { | |
| T result; | |
| for (uint i = foo.length; i--;) | |
| result += foo[i]; | |
| return result; | |
| } | |
| struct Bar<T> { | |
| Foo<T>[6] array; | |
| } | |
| uint operator.length<T>(Bar<T> bar) | |
| { | |
| return bar.array.length; | |
| } | |
| Foo<T> operator[]<T>(Bar<T> bar, uint index) | |
| { | |
| return bar.array[index]; | |
| } | |
| Bar<T> operator[]=<T>(Bar<T> bar, uint index, Foo<T> value) | |
| { | |
| bar.array[index] = value; | |
| return bar; | |
| } | |
| T sum<T:MyAddable>(Bar<T> bar) | |
| { | |
| T result; | |
| for (uint i = bar.length; i--;) | |
| result += sum(bar[i]); | |
| return result; | |
| } | |
| struct Baz<T> { | |
| Bar<T>[5] array; | |
| } | |
| Bar<T> operator[]<T>(Baz<T> baz, uint index) | |
| { | |
| return baz.array[index]; | |
| } | |
| Baz<T> operator[]=<T>(Baz<T> baz, uint index, Bar<T> value) | |
| { | |
| baz.array[index] = value; | |
| return baz; | |
| } | |
| uint operator.length<T>(Baz<T> baz) | |
| { | |
| return baz.array.length; | |
| } | |
| T sum<T:MyAddable>(Baz<T> baz) | |
| { | |
| T result; | |
| for (uint i = baz.length; i--;) | |
| result += sum(baz[i]); | |
| return result; | |
| } | |
| protocol MyConvertibleFromUint { | |
| operator MyConvertibleFromUint(uint); | |
| } | |
| protocol SetValuable : MyAddable, MyConvertibleFromUint { } | |
| void setValues<T:SetValuable>(thread Baz<T>* baz) | |
| { | |
| for (uint i = baz->length; i--;) { | |
| for (uint j = (*baz)[i].length; j--;) { | |
| for (uint k = (*baz)[i][j].length; k--;) | |
| (*baz)[i][j][k] = T(i + j + k); | |
| } | |
| } | |
| } | |
| int testSetValuesAndSum() | |
| { | |
| Baz<int> baz; | |
| setValues(&baz); | |
| return sum(baz); | |
| } | |
| int testSetValuesMutateValuesAndSum() | |
| { | |
| Baz<int> baz; | |
| setValues(&baz); | |
| for (uint i = baz.length; i--;) { | |
| for (uint j = baz[i].length; j--;) { | |
| for (uint k = baz[i][j].length; k--;) | |
| baz[i][j][k] *= int(k); | |
| } | |
| } | |
| return sum(baz); | |
| } | |
| `); | |
| checkInt(program, callFunction(program, "testSetValuesAndSum", [], []), 1575); | |
| checkInt(program, callFunction(program, "testSetValuesMutateValuesAndSum", [], []), 5565); | |
| } | |
| tests.boolBitAnd = function() | |
| { | |
| let program = doPrep(` | |
| bool foo(bool a, bool b) | |
| { | |
| return a & b; | |
| } | |
| `); | |
| checkBool(program, callFunction(program, "foo", [], [makeBool(program, false), makeBool(program, false)]), false); | |
| checkBool(program, callFunction(program, "foo", [], [makeBool(program, true), makeBool(program, false)]), false); | |
| checkBool(program, callFunction(program, "foo", [], [makeBool(program, false), makeBool(program, true)]), false); | |
| checkBool(program, callFunction(program, "foo", [], [makeBool(program, true), makeBool(program, true)]), true); | |
| } | |
| tests.boolBitOr = function() | |
| { | |
| let program = doPrep(` | |
| bool foo(bool a, bool b) | |
| { | |
| return a | b; | |
| } | |
| `); | |
| checkBool(program, callFunction(program, "foo", [], [makeBool(program, false), makeBool(program, false)]), false); | |
| checkBool(program, callFunction(program, "foo", [], [makeBool(program, true), makeBool(program, false)]), true); | |
| checkBool(program, callFunction(program, "foo", [], [makeBool(program, false), makeBool(program, true)]), true); | |
| checkBool(program, callFunction(program, "foo", [], [makeBool(program, true), makeBool(program, true)]), true); | |
| } | |
| tests.boolBitXor = function() | |
| { | |
| let program = doPrep(` | |
| bool foo(bool a, bool b) | |
| { | |
| return a ^ b; | |
| } | |
| `); | |
| checkBool(program, callFunction(program, "foo", [], [makeBool(program, false), makeBool(program, false)]), false); | |
| checkBool(program, callFunction(program, "foo", [], [makeBool(program, true), makeBool(program, false)]), true); | |
| checkBool(program, callFunction(program, "foo", [], [makeBool(program, false), makeBool(program, true)]), true); | |
| checkBool(program, callFunction(program, "foo", [], [makeBool(program, true), makeBool(program, true)]), false); | |
| } | |
| tests.boolBitNot = function() | |
| { | |
| let program = doPrep(` | |
| bool foo(bool a) | |
| { | |
| return ~a; | |
| } | |
| `); | |
| checkBool(program, callFunction(program, "foo", [], [makeBool(program, false)]), true); | |
| checkBool(program, callFunction(program, "foo", [], [makeBool(program, true)]), false); | |
| } | |
| tests.intBitAnd = function() | |
| { | |
| let program = doPrep(` | |
| int foo(int a, int b) | |
| { | |
| return a & b; | |
| } | |
| `); | |
| checkInt(program, callFunction(program, "foo", [], [makeInt(program, 1), makeInt(program, 7)]), 1); | |
| checkInt(program, callFunction(program, "foo", [], [makeInt(program, 65535), makeInt(program, 42)]), 42); | |
| checkInt(program, callFunction(program, "foo", [], [makeInt(program, -1), makeInt(program, -7)]), -7); | |
| checkInt(program, callFunction(program, "foo", [], [makeInt(program, 0), makeInt(program, 85732)]), 0); | |
| } | |
| tests.intBitOr = function() | |
| { | |
| let program = doPrep(` | |
| int foo(int a, int b) | |
| { | |
| return a | b; | |
| } | |
| `); | |
| checkInt(program, callFunction(program, "foo", [], [makeInt(program, 1), makeInt(program, 7)]), 7); | |
| checkInt(program, callFunction(program, "foo", [], [makeInt(program, 65535), makeInt(program, 42)]), 65535); | |
| checkInt(program, callFunction(program, "foo", [], [makeInt(program, -1), makeInt(program, -7)]), -1); | |
| checkInt(program, callFunction(program, "foo", [], [makeInt(program, 0), makeInt(program, 85732)]), 85732); | |
| } | |
| tests.intBitXor = function() | |
| { | |
| let program = doPrep(` | |
| int foo(int a, int b) | |
| { | |
| return a ^ b; | |
| } | |
| `); | |
| checkInt(program, callFunction(program, "foo", [], [makeInt(program, 1), makeInt(program, 7)]), 6); | |
| checkInt(program, callFunction(program, "foo", [], [makeInt(program, 65535), makeInt(program, 42)]), 65493); | |
| checkInt(program, callFunction(program, "foo", [], [makeInt(program, -1), makeInt(program, -7)]), 6); | |
| checkInt(program, callFunction(program, "foo", [], [makeInt(program, 0), makeInt(program, 85732)]), 85732); | |
| } | |
| tests.intBitNot = function() | |
| { | |
| let program = doPrep(` | |
| int foo(int a) | |
| { | |
| return ~a; | |
| } | |
| `); | |
| checkInt(program, callFunction(program, "foo", [], [makeInt(program, 1)]), -2); | |
| checkInt(program, callFunction(program, "foo", [], [makeInt(program, 65535)]), -65536); | |
| checkInt(program, callFunction(program, "foo", [], [makeInt(program, -1)]), 0); | |
| checkInt(program, callFunction(program, "foo", [], [makeInt(program, 0)]), -1); | |
| } | |
| tests.intLShift = function() | |
| { | |
| let program = doPrep(` | |
| int foo(int a, uint b) | |
| { | |
| return a << b; | |
| } | |
| `); | |
| checkInt(program, callFunction(program, "foo", [], [makeInt(program, 1), makeUint(program, 7)]), 128); | |
| checkInt(program, callFunction(program, "foo", [], [makeInt(program, 65535), makeUint(program, 2)]), 262140); | |
| checkInt(program, callFunction(program, "foo", [], [makeInt(program, -1), makeUint(program, 5)]), -32); | |
| checkInt(program, callFunction(program, "foo", [], [makeInt(program, 0), makeUint(program, 3)]), 0); | |
| } | |
| tests.intRShift = function() | |
| { | |
| let program = doPrep(` | |
| int foo(int a, uint b) | |
| { | |
| return a >> b; | |
| } | |
| `); | |
| checkInt(program, callFunction(program, "foo", [], [makeInt(program, 1), makeUint(program, 7)]), 0); | |
| checkInt(program, callFunction(program, "foo", [], [makeInt(program, 65535), makeUint(program, 2)]), 16383); | |
| checkInt(program, callFunction(program, "foo", [], [makeInt(program, -1), makeUint(program, 5)]), -1); | |
| checkInt(program, callFunction(program, "foo", [], [makeInt(program, 0), makeUint(program, 3)]), 0); | |
| } | |
| tests.uintBitAnd = function() | |
| { | |
| let program = doPrep(` | |
| uint foo(uint a, uint b) | |
| { | |
| return a & b; | |
| } | |
| `); | |
| checkUint(program, callFunction(program, "foo", [], [makeUint(program, 1), makeUint(program, 7)]), 1); | |
| checkUint(program, callFunction(program, "foo", [], [makeUint(program, 65535), makeUint(program, 42)]), 42); | |
| checkUint(program, callFunction(program, "foo", [], [makeUint(program, -1), makeUint(program, -7)]), 4294967289); | |
| checkUint(program, callFunction(program, "foo", [], [makeUint(program, 0), makeUint(program, 85732)]), 0); | |
| } | |
| tests.uintBitOr = function() | |
| { | |
| let program = doPrep(` | |
| uint foo(uint a, uint b) | |
| { | |
| return a | b; | |
| } | |
| `); | |
| checkUint(program, callFunction(program, "foo", [], [makeUint(program, 1), makeUint(program, 7)]), 7); | |
| checkUint(program, callFunction(program, "foo", [], [makeUint(program, 65535), makeUint(program, 42)]), 65535); | |
| checkUint(program, callFunction(program, "foo", [], [makeUint(program, -1), makeUint(program, -7)]), 4294967295); | |
| checkUint(program, callFunction(program, "foo", [], [makeUint(program, 0), makeUint(program, 85732)]), 85732); | |
| } | |
| tests.uintBitXor = function() | |
| { | |
| let program = doPrep(` | |
| uint foo(uint a, uint b) | |
| { | |
| return a ^ b; | |
| } | |
| `); | |
| checkUint(program, callFunction(program, "foo", [], [makeUint(program, 1), makeUint(program, 7)]), 6); | |
| checkUint(program, callFunction(program, "foo", [], [makeUint(program, 65535), makeUint(program, 42)]), 65493); | |
| checkUint(program, callFunction(program, "foo", [], [makeUint(program, -1), makeUint(program, -7)]), 6); | |
| checkUint(program, callFunction(program, "foo", [], [makeUint(program, 0), makeUint(program, 85732)]), 85732); | |
| } | |
| tests.uintBitNot = function() | |
| { | |
| let program = doPrep(` | |
| uint foo(uint a) | |
| { | |
| return ~a; | |
| } | |
| `); | |
| checkUint(program, callFunction(program, "foo", [], [makeUint(program, 1)]), 4294967294); | |
| checkUint(program, callFunction(program, "foo", [], [makeUint(program, 65535)]), 4294901760); | |
| checkUint(program, callFunction(program, "foo", [], [makeUint(program, -1)]), 0); | |
| checkUint(program, callFunction(program, "foo", [], [makeUint(program, 0)]), 4294967295); | |
| } | |
| tests.uintLShift = function() | |
| { | |
| let program = doPrep(` | |
| uint foo(uint a, uint b) | |
| { | |
| return a << b; | |
| } | |
| `); | |
| checkUint(program, callFunction(program, "foo", [], [makeUint(program, 1), makeUint(program, 7)]), 128); | |
| checkUint(program, callFunction(program, "foo", [], [makeUint(program, 65535), makeUint(program, 2)]), 262140); | |
| checkUint(program, callFunction(program, "foo", [], [makeUint(program, -1), makeUint(program, 5)]), 4294967264); | |
| checkUint(program, callFunction(program, "foo", [], [makeUint(program, 0), makeUint(program, 3)]), 0); | |
| } | |
| tests.uintRShift = function() | |
| { | |
| let program = doPrep(` | |
| uint foo(uint a, uint b) | |
| { | |
| return a >> b; | |
| } | |
| `); | |
| checkUint(program, callFunction(program, "foo", [], [makeUint(program, 1), makeUint(program, 7)]), 0); | |
| checkUint(program, callFunction(program, "foo", [], [makeUint(program, 65535), makeUint(program, 2)]), 16383); | |
| checkUint(program, callFunction(program, "foo", [], [makeUint(program, -1), makeUint(program, 5)]), 134217727); | |
| checkUint(program, callFunction(program, "foo", [], [makeUint(program, 0), makeUint(program, 3)]), 0); | |
| } | |
| tests.uint8BitAnd = function() | |
| { | |
| let program = doPrep(` | |
| uint8 foo(uint8 a, uint8 b) | |
| { | |
| return a & b; | |
| } | |
| `); | |
| checkUint8(program, callFunction(program, "foo", [], [makeUint8(program, 1), makeUint8(program, 7)]), 1); | |
| checkUint8(program, callFunction(program, "foo", [], [makeUint8(program, 65535), makeUint8(program, 42)]), 42); | |
| checkUint8(program, callFunction(program, "foo", [], [makeUint8(program, -1), makeUint8(program, -7)]), 249); | |
| checkUint8(program, callFunction(program, "foo", [], [makeUint8(program, 0), makeUint8(program, 85732)]), 0); | |
| } | |
| tests.uint8BitOr = function() | |
| { | |
| let program = doPrep(` | |
| uint8 foo(uint8 a, uint8 b) | |
| { | |
| return a | b; | |
| } | |
| `); | |
| checkUint8(program, callFunction(program, "foo", [], [makeUint8(program, 1), makeUint8(program, 7)]), 7); | |
| checkUint8(program, callFunction(program, "foo", [], [makeUint8(program, 65535), makeUint8(program, 42)]), 255); | |
| checkUint8(program, callFunction(program, "foo", [], [makeUint8(program, -1), makeUint8(program, -7)]), 255); | |
| checkUint8(program, callFunction(program, "foo", [], [makeUint8(program, 0), makeUint8(program, 85732)]), 228); | |
| } | |
| tests.uint8BitXor = function() | |
| { | |
| let program = doPrep(` | |
| uint8 foo(uint8 a, uint8 b) | |
| { | |
| return a ^ b; | |
| } | |
| `); | |
| checkUint8(program, callFunction(program, "foo", [], [makeUint8(program, 1), makeUint8(program, 7)]), 6); | |
| checkUint8(program, callFunction(program, "foo", [], [makeUint8(program, 65535), makeUint8(program, 42)]), 213); | |
| checkUint8(program, callFunction(program, "foo", [], [makeUint8(program, -1), makeUint8(program, -7)]), 6); | |
| checkUint8(program, callFunction(program, "foo", [], [makeUint8(program, 0), makeUint8(program, 85732)]), 228); | |
| } | |
| tests.uint8BitNot = function() | |
| { | |
| let program = doPrep(` | |
| uint8 foo(uint8 a) | |
| { | |
| return ~a; | |
| } | |
| `); | |
| checkUint8(program, callFunction(program, "foo", [], [makeUint8(program, 1)]), 254); | |
| checkUint8(program, callFunction(program, "foo", [], [makeUint8(program, 65535)]), 0); | |
| checkUint8(program, callFunction(program, "foo", [], [makeUint8(program, -1)]), 0); | |
| checkUint8(program, callFunction(program, "foo", [], [makeUint8(program, 0)]), 255); | |
| } | |
| tests.uint8LShift = function() | |
| { | |
| let program = doPrep(` | |
| uint8 foo(uint8 a, uint b) | |
| { | |
| return a << b; | |
| } | |
| `); | |
| checkUint8(program, callFunction(program, "foo", [], [makeUint8(program, 1), makeUint(program, 7)]), 128); | |
| checkUint8(program, callFunction(program, "foo", [], [makeUint8(program, 65535), makeUint(program, 2)]), 252); | |
| checkUint8(program, callFunction(program, "foo", [], [makeUint8(program, -1), makeUint(program, 5)]), 224); | |
| checkUint8(program, callFunction(program, "foo", [], [makeUint8(program, 0), makeUint(program, 3)]), 0); | |
| } | |
| tests.uint8RShift = function() | |
| { | |
| let program = doPrep(` | |
| uint8 foo(uint8 a, uint b) | |
| { | |
| return a >> b; | |
| } | |
| `); | |
| checkUint8(program, callFunction(program, "foo", [], [makeUint8(program, 1), makeUint(program, 7)]), 0); | |
| checkUint8(program, callFunction(program, "foo", [], [makeUint8(program, 65535), makeUint(program, 2)]), 255); | |
| checkUint8(program, callFunction(program, "foo", [], [makeUint8(program, -1), makeUint(program, 5)]), 255); | |
| checkUint8(program, callFunction(program, "foo", [], [makeUint8(program, 0), makeUint(program, 3)]), 0); | |
| } | |
| tests.floatMath = function() | |
| { | |
| let program = doPrep(` | |
| bool foo() | |
| { | |
| return 42.5 == 42.5; | |
| } | |
| bool foo2() | |
| { | |
| return 42.5f == 42.5; | |
| } | |
| bool foo3() | |
| { | |
| return 42.5 == 42.5f; | |
| } | |
| bool foo4() | |
| { | |
| return 42.5f == 42.5f; | |
| } | |
| bool foo5() | |
| { | |
| return 42.5d == 42.5d; | |
| } | |
| float bar(float x) | |
| { | |
| return x; | |
| } | |
| float foo6() | |
| { | |
| return bar(7.5); | |
| } | |
| float foo7() | |
| { | |
| return bar(7.5f); | |
| } | |
| float foo8() | |
| { | |
| return bar(7.5d); | |
| } | |
| float foo9() | |
| { | |
| return float(7.5); | |
| } | |
| float foo10() | |
| { | |
| return float(7.5f); | |
| } | |
| float foo11() | |
| { | |
| return float(7.5d); | |
| } | |
| float foo12() | |
| { | |
| return float(7); | |
| } | |
| float foo13() | |
| { | |
| double x = 7.5d; | |
| return float(x); | |
| } | |
| double foo14() | |
| { | |
| double x = 7.5f; | |
| return double(x); | |
| } | |
| `); | |
| checkBool(program, callFunction(program, "foo", [], []), true); | |
| checkBool(program, callFunction(program, "foo2", [], []), true); | |
| checkBool(program, callFunction(program, "foo3", [], []), true); | |
| checkBool(program, callFunction(program, "foo4", [], []), true); | |
| checkBool(program, callFunction(program, "foo5", [], []), true); | |
| checkFloat(program, callFunction(program, "foo6", [], []), 7.5); | |
| checkFloat(program, callFunction(program, "foo7", [], []), 7.5); | |
| checkFloat(program, callFunction(program, "foo8", [], []), 7.5); | |
| checkFloat(program, callFunction(program, "foo9", [], []), 7.5); | |
| checkFloat(program, callFunction(program, "foo10", [], []), 7.5); | |
| checkFloat(program, callFunction(program, "foo11", [], []), 7.5); | |
| checkFloat(program, callFunction(program, "foo12", [], []), 7); | |
| checkFloat(program, callFunction(program, "foo13", [], []), 7.5); | |
| checkDouble(program, callFunction(program, "foo14", [], []), 7.5); | |
| checkFail( | |
| () => doPrep(` | |
| int bar(int x) | |
| { | |
| return x; | |
| } | |
| int foo() | |
| { | |
| bar(4.); | |
| } | |
| `), | |
| (e) => e instanceof WTypeError); | |
| checkFail( | |
| () => doPrep(` | |
| int bar(int x) | |
| { | |
| return x; | |
| } | |
| int foo() | |
| { | |
| bar(4.d); | |
| } | |
| `), | |
| (e) => e instanceof WTypeError); | |
| checkFail( | |
| () => doPrep(` | |
| int bar(int x) | |
| { | |
| return x; | |
| } | |
| int foo() | |
| { | |
| bar(4.f); | |
| } | |
| `), | |
| (e) => e instanceof WTypeError); | |
| checkFail( | |
| () => doPrep(` | |
| uint bar(uint x) | |
| { | |
| return x; | |
| } | |
| int foo() | |
| { | |
| bar(4.); | |
| } | |
| `), | |
| (e) => e instanceof WTypeError); | |
| checkFail( | |
| () => doPrep(` | |
| uint bar(uint x) | |
| { | |
| return x; | |
| } | |
| int foo() | |
| { | |
| bar(4.d); | |
| } | |
| `), | |
| (e) => e instanceof WTypeError); | |
| checkFail( | |
| () => doPrep(` | |
| uint bar(uint x) | |
| { | |
| return x; | |
| } | |
| int foo() | |
| { | |
| bar(4.f); | |
| } | |
| `), | |
| (e) => e instanceof WTypeError); | |
| checkFail( | |
| () => doPrep(` | |
| float bar(float x) | |
| { | |
| return x; | |
| } | |
| void foo() | |
| { | |
| bar(16777217.d); | |
| } | |
| `), | |
| (e) => e instanceof WTypeError); | |
| checkFail( | |
| () => doPrep(` | |
| float bar(float x) | |
| { | |
| return x; | |
| } | |
| float foo() | |
| { | |
| double x = 7.; | |
| return bar(x); | |
| } | |
| `), | |
| (e) => e instanceof WTypeError); | |
| checkFail( | |
| () => doPrep(` | |
| float foo() | |
| { | |
| double x = 7.; | |
| return x; | |
| } | |
| `), | |
| (e) => e instanceof WTypeError); | |
| } | |
| tests.genericCastInfer = function() | |
| { | |
| let program = doPrep(` | |
| struct Complex<T> { | |
| T real; | |
| T imag; | |
| } | |
| operator<T> Complex<T>(T real, T imag) | |
| { | |
| Complex<T> result; | |
| result.real = real; | |
| result.imag = imag; | |
| return result; | |
| } | |
| int foo() | |
| { | |
| Complex<int> x = Complex<int>(1, 2); | |
| return x.real + x.imag; | |
| } | |
| `); | |
| checkInt(program, callFunction(program, "foo", [], []), 3); | |
| } | |
| tests.booleanMath = function() | |
| { | |
| let program = doPrep(` | |
| bool foo() | |
| { | |
| return true && true; | |
| } | |
| bool foo2() | |
| { | |
| return true && false; | |
| } | |
| bool foo3() | |
| { | |
| return false && true; | |
| } | |
| bool foo4() | |
| { | |
| return false && false; | |
| } | |
| bool foo5() | |
| { | |
| return true || true; | |
| } | |
| bool foo6() | |
| { | |
| return true || false; | |
| } | |
| bool foo7() | |
| { | |
| return false || true; | |
| } | |
| bool foo8() | |
| { | |
| return false || false; | |
| } | |
| `); | |
| checkBool(program, callFunction(program, "foo", [], []), true); | |
| checkBool(program, callFunction(program, "foo2", [], []), false); | |
| checkBool(program, callFunction(program, "foo3", [], []), false); | |
| checkBool(program, callFunction(program, "foo4", [], []), false); | |
| checkBool(program, callFunction(program, "foo5", [], []), true); | |
| checkBool(program, callFunction(program, "foo6", [], []), true); | |
| checkBool(program, callFunction(program, "foo7", [], []), true); | |
| checkBool(program, callFunction(program, "foo8", [], []), false); | |
| } | |
| tests.typedefArray = function() | |
| { | |
| let program = doPrep(` | |
| typedef ArrayTypedef = int[2]; | |
| int foo() | |
| { | |
| ArrayTypedef arrayTypedef; | |
| return arrayTypedef[0]; | |
| } | |
| `); | |
| checkInt(program, callFunction(program, "foo", [], []), 0); | |
| } | |
| tests.shaderTypes = function() | |
| { | |
| checkFail( | |
| () => doPrep(` | |
| struct Foo { | |
| float4 x; | |
| } | |
| vertex Foo bar() | |
| { | |
| Foo result; | |
| result.x = float4(); | |
| return result; | |
| } | |
| Foo foo() { | |
| return bar(); | |
| } | |
| `), | |
| (e) => e instanceof WTypeError); | |
| checkFail( | |
| () => doPrep(` | |
| vertex float bar() | |
| { | |
| return 4.; | |
| } | |
| `), | |
| (e) => e instanceof WTypeError); | |
| checkFail( | |
| () => doPrep(` | |
| struct Foo { | |
| float4 x; | |
| } | |
| vertex Foo bar(device Foo* x) | |
| { | |
| return Foo(); | |
| } | |
| `), | |
| (e) => e instanceof WTypeError); | |
| checkFail( | |
| () => doPrep(` | |
| struct Boo { | |
| float4 x; | |
| } | |
| struct Foo { | |
| float4 x; | |
| device Boo* y; | |
| } | |
| vertex Foo bar() | |
| { | |
| return Foo(); | |
| } | |
| `), | |
| (e) => e instanceof WTypeError); | |
| checkFail( | |
| () => doPrep(` | |
| struct Foo { | |
| float4 x; | |
| } | |
| struct Boo { | |
| device Foo* y; | |
| } | |
| vertex Foo bar(Boo b) | |
| { | |
| return Foo(); | |
| } | |
| `), | |
| (e) => e instanceof WTypeError); | |
| checkFail( | |
| () => doPrep(` | |
| struct Foo { | |
| float4 x; | |
| } | |
| vertex Foo bar(device Foo* x) | |
| { | |
| return Foo(); | |
| } | |
| `), | |
| (e) => e instanceof WTypeError); | |
| checkFail( | |
| () => doPrep(` | |
| struct Foo { | |
| float4 x; | |
| } | |
| fragment Foo bar(Foo foo) | |
| { | |
| return Foo(); | |
| } | |
| `), | |
| (e) => e instanceof WTypeError); | |
| checkFail( | |
| () => doPrep(` | |
| struct Foo { | |
| float4 x; | |
| } | |
| fragment Foo bar(device Foo* stageIn) | |
| { | |
| return Foo(); | |
| } | |
| `), | |
| (e) => e instanceof WTypeError); | |
| checkFail( | |
| () => doPrep(` | |
| struct Boo { | |
| float4 x; | |
| } | |
| struct Foo { | |
| float4 x; | |
| device Boo* y; | |
| } | |
| fragment Boo bar(Foo stageIn) | |
| { | |
| return boo(); | |
| } | |
| `), | |
| (e) => e instanceof WTypeError); | |
| checkFail( | |
| () => doPrep(` | |
| struct Boo { | |
| float4 x; | |
| } | |
| struct Foo { | |
| float4 x; | |
| device Boo* y; | |
| } | |
| fragment Foo bar(Boo stageIn) | |
| { | |
| return Foo(); | |
| } | |
| `), | |
| (e) => e instanceof WTypeError); | |
| } | |
| tests.builtinVectors = function() | |
| { | |
| let program = doPrep(` | |
| int foo() | |
| { | |
| int2 a = int2(3, 4); | |
| return a[0]; | |
| } | |
| int foo2() | |
| { | |
| int2 a = int2(3, 4); | |
| int3 b = int3(a, 5); | |
| return b[1]; | |
| } | |
| int foo3() | |
| { | |
| int3 a = int3(3, 4, 5); | |
| int4 b = int4(6, a); | |
| return b[1]; | |
| } | |
| int foo4() | |
| { | |
| int2 a = int2(3, 4); | |
| int2 b = int2(5, 6); | |
| int4 c = int4(a, b); | |
| return c[2]; | |
| } | |
| bool foo5() | |
| { | |
| int4 a = int4(3, 4, 5, 6); | |
| int2 b = int2(4, 5); | |
| int4 c = int4(3, b, 6); | |
| return a == c; | |
| } | |
| bool foo6() | |
| { | |
| int2 a = int2(4, 5); | |
| int3 b = int3(3, a); | |
| int3 c = int3(3, 4, 6); | |
| return b == c; | |
| } | |
| uint foou() | |
| { | |
| uint2 a = uint2(3, 4); | |
| return a[0]; | |
| } | |
| uint foou2() | |
| { | |
| uint2 a = uint2(3, 4); | |
| uint3 b = uint3(a, 5); | |
| return b[1]; | |
| } | |
| uint foou3() | |
| { | |
| uint3 a = uint3(3, 4, 5); | |
| uint4 b = uint4(6, a); | |
| return b[1]; | |
| } | |
| uint foou4() | |
| { | |
| uint2 a = uint2(3, 4); | |
| uint2 b = uint2(5, 6); | |
| uint4 c = uint4(a, b); | |
| return c[2]; | |
| } | |
| bool foou5() | |
| { | |
| uint4 a = uint4(3, 4, 5, 6); | |
| uint2 b = uint2(4, 5); | |
| uint4 c = uint4(3, b, 6); | |
| return a == c; | |
| } | |
| bool foou6() | |
| { | |
| uint2 a = uint2(4, 5); | |
| uint3 b = uint3(3, a); | |
| uint3 c = uint3(3, 4, 6); | |
| return b == c; | |
| } | |
| float foof() | |
| { | |
| float2 a = float2(3., 4.); | |
| return a[0]; | |
| } | |
| float foof2() | |
| { | |
| float2 a = float2(3., 4.); | |
| float3 b = float3(a, 5.); | |
| return b[1]; | |
| } | |
| float foof3() | |
| { | |
| float3 a = float3(3., 4., 5.); | |
| float4 b = float4(6., a); | |
| return b[1]; | |
| } | |
| float foof4() | |
| { | |
| float2 a = float2(3., 4.); | |
| float2 b = float2(5., 6.); | |
| float4 c = float4(a, b); | |
| return c[2]; | |
| } | |
| bool foof5() | |
| { | |
| float4 a = float4(3., 4., 5., 6.); | |
| float2 b = float2(4., 5.); | |
| float4 c = float4(3., b, 6.); | |
| return a == c; | |
| } | |
| bool foof6() | |
| { | |
| float2 a = float2(4., 5.); | |
| float3 b = float3(3., a); | |
| float3 c = float3(3., 4., 6.); | |
| return b == c; | |
| } | |
| double food() | |
| { | |
| double2 a = double2(3., 4.); | |
| return a[0]; | |
| } | |
| double food2() | |
| { | |
| double2 a = double2(3., 4.); | |
| double3 b = double3(a, 5.); | |
| return b[1]; | |
| } | |
| double food3() | |
| { | |
| double3 a = double3(3., 4., 5.); | |
| double4 b = double4(6., a); | |
| return b[1]; | |
| } | |
| double food4() | |
| { | |
| double2 a = double2(3., 4.); | |
| double2 b = double2(5., 6.); | |
| double4 c = double4(a, b); | |
| return c[2]; | |
| } | |
| bool food5() | |
| { | |
| double4 a = double4(3., 4., 5., 6.); | |
| double2 b = double2(4., 5.); | |
| double4 c = double4(3., b, 6.); | |
| return a == c; | |
| } | |
| bool food6() | |
| { | |
| double2 a = double2(4., 5.); | |
| double3 b = double3(3., a); | |
| double3 c = double3(3., 4., 6.); | |
| return b == c; | |
| } | |
| `); | |
| checkInt(program, callFunction(program, "foo", [], []), 3); | |
| checkInt(program, callFunction(program, "foo2", [], []), 4); | |
| checkInt(program, callFunction(program, "foo3", [], []), 3); | |
| checkInt(program, callFunction(program, "foo4", [], []), 5); | |
| checkBool(program, callFunction(program, "foo5", [], []), true); | |
| checkBool(program, callFunction(program, "foo6", [], []), false); | |
| checkUint(program, callFunction(program, "foou", [], []), 3); | |
| checkUint(program, callFunction(program, "foou2", [], []), 4); | |
| checkUint(program, callFunction(program, "foou3", [], []), 3); | |
| checkUint(program, callFunction(program, "foou4", [], []), 5); | |
| checkBool(program, callFunction(program, "foou5", [], []), true); | |
| checkBool(program, callFunction(program, "foou6", [], []), false); | |
| checkFloat(program, callFunction(program, "foof", [], []), 3); | |
| checkFloat(program, callFunction(program, "foof2", [], []), 4); | |
| checkFloat(program, callFunction(program, "foof3", [], []), 3); | |
| checkFloat(program, callFunction(program, "foof4", [], []), 5); | |
| checkBool(program, callFunction(program, "foof5", [], []), true); | |
| checkBool(program, callFunction(program, "foof6", [], []), false); | |
| checkDouble(program, callFunction(program, "food", [], []), 3); | |
| checkDouble(program, callFunction(program, "food2", [], []), 4); | |
| checkDouble(program, callFunction(program, "food3", [], []), 3); | |
| checkDouble(program, callFunction(program, "food4", [], []), 5); | |
| checkBool(program, callFunction(program, "food5", [], []), true); | |
| checkBool(program, callFunction(program, "food6", [], []), false); | |
| } | |
| tests.instantiateStructInStruct = function() | |
| { | |
| let program = doPrep(` | |
| struct Bar<T> { | |
| T x; | |
| } | |
| struct Foo { | |
| Bar<int> x; | |
| } | |
| int foo() | |
| { | |
| Foo x; | |
| x.x.x = 42; | |
| x.x.x++; | |
| return x.x.x; | |
| } | |
| `); | |
| checkInt(program, callFunction(program, "foo", [], []), 43); | |
| } | |
| tests.instantiateStructInStructWithInt2 = function() | |
| { | |
| let program = doPrep(` | |
| struct Foo { | |
| int2 x; | |
| } | |
| int foo() | |
| { | |
| Foo x; | |
| x.x.x = 42; | |
| x.x.x++; | |
| return x.x.x; | |
| } | |
| `); | |
| checkInt(program, callFunction(program, "foo", [], []), 43); | |
| } | |
| tests.simpleEnum = function() | |
| { | |
| let program = doPrep(` | |
| enum Foo { | |
| War, | |
| Famine, | |
| Pestilence, | |
| Death | |
| } | |
| Foo war() | |
| { | |
| return Foo.War; | |
| } | |
| Foo famine() | |
| { | |
| return Foo.Famine; | |
| } | |
| Foo pestilence() | |
| { | |
| return Foo.Pestilence; | |
| } | |
| Foo death() | |
| { | |
| return Foo.Death; | |
| } | |
| bool equals(Foo a, Foo b) | |
| { | |
| return a == b; | |
| } | |
| bool notEquals(Foo a, Foo b) | |
| { | |
| return a != b; | |
| } | |
| bool testSimpleEqual() | |
| { | |
| return equals(Foo.War, Foo.War); | |
| } | |
| bool testAnotherEqual() | |
| { | |
| return equals(Foo.Pestilence, Foo.Pestilence); | |
| } | |
| bool testNotEqual() | |
| { | |
| return equals(Foo.Famine, Foo.Death); | |
| } | |
| bool testSimpleNotEqual() | |
| { | |
| return notEquals(Foo.War, Foo.War); | |
| } | |
| bool testAnotherNotEqual() | |
| { | |
| return notEquals(Foo.Pestilence, Foo.Pestilence); | |
| } | |
| bool testNotNotEqual() | |
| { | |
| return notEquals(Foo.Famine, Foo.Death); | |
| } | |
| int intWar() | |
| { | |
| return int(war()); | |
| } | |
| int intFamine() | |
| { | |
| return int(famine()); | |
| } | |
| int intPestilence() | |
| { | |
| return int(pestilence()); | |
| } | |
| int intDeath() | |
| { | |
| return int(death()); | |
| } | |
| int warValue() | |
| { | |
| return war().value; | |
| } | |
| int famineValue() | |
| { | |
| return famine().value; | |
| } | |
| int pestilenceValue() | |
| { | |
| return pestilence().value; | |
| } | |
| int deathValue() | |
| { | |
| return death().value; | |
| } | |
| int warValueLiteral() | |
| { | |
| return Foo.War.value; | |
| } | |
| int famineValueLiteral() | |
| { | |
| return Foo.Famine.value; | |
| } | |
| int pestilenceValueLiteral() | |
| { | |
| return Foo.Pestilence.value; | |
| } | |
| int deathValueLiteral() | |
| { | |
| return Foo.Death.value; | |
| } | |
| Foo intWarBackwards() | |
| { | |
| return Foo(intWar()); | |
| } | |
| Foo intFamineBackwards() | |
| { | |
| return Foo(intFamine()); | |
| } | |
| Foo intPestilenceBackwards() | |
| { | |
| return Foo(intPestilence()); | |
| } | |
| Foo intDeathBackwards() | |
| { | |
| return Foo(intDeath()); | |
| } | |
| `); | |
| checkEnum(program, callFunction(program, "war", [], []), 0); | |
| checkEnum(program, callFunction(program, "famine", [], []), 1); | |
| checkEnum(program, callFunction(program, "pestilence", [], []), 2); | |
| checkEnum(program, callFunction(program, "death", [], []), 3); | |
| checkBool(program, callFunction(program, "testSimpleEqual", [], []), true); | |
| checkBool(program, callFunction(program, "testAnotherEqual", [], []), true); | |
| checkBool(program, callFunction(program, "testNotEqual", [], []), false); | |
| checkBool(program, callFunction(program, "testSimpleNotEqual", [], []), false); | |
| checkBool(program, callFunction(program, "testAnotherNotEqual", [], []), false); | |
| checkBool(program, callFunction(program, "testNotNotEqual", [], []), true); | |
| checkInt(program, callFunction(program, "intWar", [], []), 0); | |
| checkInt(program, callFunction(program, "intFamine", [], []), 1); | |
| checkInt(program, callFunction(program, "intPestilence", [], []), 2); | |
| checkInt(program, callFunction(program, "intDeath", [], []), 3); | |
| checkInt(program, callFunction(program, "warValue", [], []), 0); | |
| checkInt(program, callFunction(program, "famineValue", [], []), 1); | |
| checkInt(program, callFunction(program, "pestilenceValue", [], []), 2); | |
| checkInt(program, callFunction(program, "deathValue", [], []), 3); | |
| checkInt(program, callFunction(program, "warValueLiteral", [], []), 0); | |
| checkInt(program, callFunction(program, "famineValueLiteral", [], []), 1); | |
| checkInt(program, callFunction(program, "pestilenceValueLiteral", [], []), 2); | |
| checkInt(program, callFunction(program, "deathValueLiteral", [], []), 3); | |
| checkEnum(program, callFunction(program, "intWarBackwards", [], []), 0); | |
| checkEnum(program, callFunction(program, "intFamineBackwards", [], []), 1); | |
| checkEnum(program, callFunction(program, "intPestilenceBackwards", [], []), 2); | |
| checkEnum(program, callFunction(program, "intDeathBackwards", [], []), 3); | |
| } | |
| tests.enumWithManualValues = function() | |
| { | |
| let program = doPrep(` | |
| enum Foo { | |
| War = 72, | |
| Famine = 0, | |
| Pestilence = 23, | |
| Death = -42 | |
| } | |
| Foo war() | |
| { | |
| return Foo.War; | |
| } | |
| Foo famine() | |
| { | |
| return Foo.Famine; | |
| } | |
| Foo pestilence() | |
| { | |
| return Foo.Pestilence; | |
| } | |
| Foo death() | |
| { | |
| return Foo.Death; | |
| } | |
| `); | |
| checkEnum(program, callFunction(program, "war", [], []), 72); | |
| checkEnum(program, callFunction(program, "famine", [], []), 0); | |
| checkEnum(program, callFunction(program, "pestilence", [], []), 23); | |
| checkEnum(program, callFunction(program, "death", [], []), -42); | |
| } | |
| tests.enumWithoutZero = function() | |
| { | |
| checkFail( | |
| () => doPrep(` | |
| enum Foo { | |
| War = 72, | |
| Famine = 64, | |
| Pestilence = 23, | |
| Death = -42 | |
| } | |
| `), | |
| e => e instanceof WTypeError); | |
| } | |
| tests.enumDuplicates = function() | |
| { | |
| checkFail( | |
| () => doPrep(` | |
| enum Foo { | |
| War = -42, | |
| Famine = 0, | |
| Pestilence = 23, | |
| Death = -42 | |
| } | |
| `), | |
| e => e instanceof WTypeError); | |
| } | |
| tests.enumWithSomeManualValues = function() | |
| { | |
| let program = doPrep(` | |
| enum Foo { | |
| War = 72, | |
| Famine, | |
| Pestilence = 0, | |
| Death | |
| } | |
| Foo war() | |
| { | |
| return Foo.War; | |
| } | |
| Foo famine() | |
| { | |
| return Foo.Famine; | |
| } | |
| Foo pestilence() | |
| { | |
| return Foo.Pestilence; | |
| } | |
| Foo death() | |
| { | |
| return Foo.Death; | |
| } | |
| `); | |
| checkEnum(program, callFunction(program, "war", [], []), 72); | |
| checkEnum(program, callFunction(program, "famine", [], []), 73); | |
| checkEnum(program, callFunction(program, "pestilence", [], []), 0); | |
| checkEnum(program, callFunction(program, "death", [], []), 1); | |
| } | |
| tests.enumConstexprGenericFunction = function() | |
| { | |
| let program = doPrep(` | |
| enum Axis { X, Y } | |
| int foo<Axis axis>() { return int(axis); } | |
| int testX() { return foo<Axis.X>(); } | |
| int testY() { return foo<Axis.Y>(); } | |
| `); | |
| checkInt(program, callFunction(program, "testX", [], []), 0); | |
| checkInt(program, callFunction(program, "testY", [], []), 1); | |
| } | |
| tests.enumConstexprGenericStruct = function() | |
| { | |
| let program = doPrep(` | |
| enum Axis { X, Y } | |
| struct Foo<Axis axis> { } | |
| int foo<Axis axis>(Foo<axis>) { return int(axis); } | |
| int testX() | |
| { | |
| Foo<Axis.X> f; | |
| return foo(f); | |
| } | |
| int testY() | |
| { | |
| Foo<Axis.Y> f; | |
| return foo(f); | |
| } | |
| `); | |
| checkInt(program, callFunction(program, "testX", [], []), 0); | |
| checkInt(program, callFunction(program, "testY", [], []), 1); | |
| } | |
| tests.trap = function() | |
| { | |
| let program = doPrep(` | |
| int foo() | |
| { | |
| trap; | |
| } | |
| int foo2(int x) | |
| { | |
| if (x == 3) | |
| trap; | |
| return 4; | |
| } | |
| struct Bar { | |
| int3 x; | |
| float y; | |
| } | |
| Bar foo3() | |
| { | |
| trap; | |
| } | |
| `); | |
| checkFail( | |
| () => callFunction(program, "foo", [], []), | |
| e => e instanceof WTrapError); | |
| checkInt(program, callFunction(program, "foo2", [], [makeInt(program, 1)]), 4); | |
| checkFail( | |
| () => callFunction(program, "foo2", [], [makeInt(program, 3)]), | |
| e => e instanceof WTrapError); | |
| checkFail( | |
| () => callFunction(program, "foo3", [], []), | |
| e => e instanceof WTrapError); | |
| } | |
| tests.swizzle = function() | |
| { | |
| let program = doPrep(` | |
| float foo() { | |
| float4 bar = float4(3., 4., 5., 6.); | |
| float3 baz = bar.zzx; | |
| return baz.z; | |
| } | |
| float foo2() { | |
| float4 bar = float4(3., 4., 5., 6.); | |
| float3 baz = bar.wyz; | |
| return baz.x; | |
| } | |
| float foo3() { | |
| float3 bar = float3(3., 4., 5.); | |
| float2 baz = bar.yz; | |
| float4 quix = baz.yyxx; | |
| return quix.z; | |
| } | |
| `); | |
| checkFloat(program, callFunction(program, "foo", [], []), 3); | |
| checkFloat(program, callFunction(program, "foo2", [], []), 6); | |
| checkFloat(program, callFunction(program, "foo3", [], []), 4); | |
| } | |
| tests.enumWithExplicitIntBase = function() | |
| { | |
| let program = doPrep(` | |
| enum Foo : int { | |
| War, | |
| Famine, | |
| Pestilence, | |
| Death | |
| } | |
| Foo war() | |
| { | |
| return Foo.War; | |
| } | |
| Foo famine() | |
| { | |
| return Foo.Famine; | |
| } | |
| Foo pestilence() | |
| { | |
| return Foo.Pestilence; | |
| } | |
| Foo death() | |
| { | |
| return Foo.Death; | |
| } | |
| bool equals(Foo a, Foo b) | |
| { | |
| return a == b; | |
| } | |
| bool notEquals(Foo a, Foo b) | |
| { | |
| return a != b; | |
| } | |
| bool testSimpleEqual() | |
| { | |
| return equals(Foo.War, Foo.War); | |
| } | |
| bool testAnotherEqual() | |
| { | |
| return equals(Foo.Pestilence, Foo.Pestilence); | |
| } | |
| bool testNotEqual() | |
| { | |
| return equals(Foo.Famine, Foo.Death); | |
| } | |
| bool testSimpleNotEqual() | |
| { | |
| return notEquals(Foo.War, Foo.War); | |
| } | |
| bool testAnotherNotEqual() | |
| { | |
| return notEquals(Foo.Pestilence, Foo.Pestilence); | |
| } | |
| bool testNotNotEqual() | |
| { | |
| return notEquals(Foo.Famine, Foo.Death); | |
| } | |
| int intWar() | |
| { | |
| return int(war()); | |
| } | |
| int intFamine() | |
| { | |
| return int(famine()); | |
| } | |
| int intPestilence() | |
| { | |
| return int(pestilence()); | |
| } | |
| int intDeath() | |
| { | |
| return int(death()); | |
| } | |
| int warValue() | |
| { | |
| return war().value; | |
| } | |
| int famineValue() | |
| { | |
| return famine().value; | |
| } | |
| int pestilenceValue() | |
| { | |
| return pestilence().value; | |
| } | |
| int deathValue() | |
| { | |
| return death().value; | |
| } | |
| int warValueLiteral() | |
| { | |
| return Foo.War.value; | |
| } | |
| int famineValueLiteral() | |
| { | |
| return Foo.Famine.value; | |
| } | |
| int pestilenceValueLiteral() | |
| { | |
| return Foo.Pestilence.value; | |
| } | |
| int deathValueLiteral() | |
| { | |
| return Foo.Death.value; | |
| } | |
| Foo intWarBackwards() | |
| { | |
| return Foo(intWar()); | |
| } | |
| Foo intFamineBackwards() | |
| { | |
| return Foo(intFamine()); | |
| } | |
| Foo intPestilenceBackwards() | |
| { | |
| return Foo(intPestilence()); | |
| } | |
| Foo intDeathBackwards() | |
| { | |
| return Foo(intDeath()); | |
| } | |
| `); | |
| checkEnum(program, callFunction(program, "war", [], []), 0); | |
| checkEnum(program, callFunction(program, "famine", [], []), 1); | |
| checkEnum(program, callFunction(program, "pestilence", [], []), 2); | |
| checkEnum(program, callFunction(program, "death", [], []), 3); | |
| checkBool(program, callFunction(program, "testSimpleEqual", [], []), true); | |
| checkBool(program, callFunction(program, "testAnotherEqual", [], []), true); | |
| checkBool(program, callFunction(program, "testNotEqual", [], []), false); | |
| checkBool(program, callFunction(program, "testSimpleNotEqual", [], []), false); | |
| checkBool(program, callFunction(program, "testAnotherNotEqual", [], []), false); | |
| checkBool(program, callFunction(program, "testNotNotEqual", [], []), true); | |
| checkInt(program, callFunction(program, "intWar", [], []), 0); | |
| checkInt(program, callFunction(program, "intFamine", [], []), 1); | |
| checkInt(program, callFunction(program, "intPestilence", [], []), 2); | |
| checkInt(program, callFunction(program, "intDeath", [], []), 3); | |
| checkInt(program, callFunction(program, "warValue", [], []), 0); | |
| checkInt(program, callFunction(program, "famineValue", [], []), 1); | |
| checkInt(program, callFunction(program, "pestilenceValue", [], []), 2); | |
| checkInt(program, callFunction(program, "deathValue", [], []), 3); | |
| checkInt(program, callFunction(program, "warValueLiteral", [], []), 0); | |
| checkInt(program, callFunction(program, "famineValueLiteral", [], []), 1); | |
| checkInt(program, callFunction(program, "pestilenceValueLiteral", [], []), 2); | |
| checkInt(program, callFunction(program, "deathValueLiteral", [], []), 3); | |
| checkEnum(program, callFunction(program, "intWarBackwards", [], []), 0); | |
| checkEnum(program, callFunction(program, "intFamineBackwards", [], []), 1); | |
| checkEnum(program, callFunction(program, "intPestilenceBackwards", [], []), 2); | |
| checkEnum(program, callFunction(program, "intDeathBackwards", [], []), 3); | |
| } | |
| tests.enumWithUintBase = function() | |
| { | |
| let program = doPrep(` | |
| enum Foo : uint { | |
| War, | |
| Famine, | |
| Pestilence, | |
| Death | |
| } | |
| Foo war() | |
| { | |
| return Foo.War; | |
| } | |
| Foo famine() | |
| { | |
| return Foo.Famine; | |
| } | |
| Foo pestilence() | |
| { | |
| return Foo.Pestilence; | |
| } | |
| Foo death() | |
| { | |
| return Foo.Death; | |
| } | |
| bool equals(Foo a, Foo b) | |
| { | |
| return a == b; | |
| } | |
| bool notEquals(Foo a, Foo b) | |
| { | |
| return a != b; | |
| } | |
| bool testSimpleEqual() | |
| { | |
| return equals(Foo.War, Foo.War); | |
| } | |
| bool testAnotherEqual() | |
| { | |
| return equals(Foo.Pestilence, Foo.Pestilence); | |
| } | |
| bool testNotEqual() | |
| { | |
| return equals(Foo.Famine, Foo.Death); | |
| } | |
| bool testSimpleNotEqual() | |
| { | |
| return notEquals(Foo.War, Foo.War); | |
| } | |
| bool testAnotherNotEqual() | |
| { | |
| return notEquals(Foo.Pestilence, Foo.Pestilence); | |
| } | |
| bool testNotNotEqual() | |
| { | |
| return notEquals(Foo.Famine, Foo.Death); | |
| } | |
| uint uintWar() | |
| { | |
| return uint(war()); | |
| } | |
| uint uintFamine() | |
| { | |
| return uint(famine()); | |
| } | |
| uint uintPestilence() | |
| { | |
| return uint(pestilence()); | |
| } | |
| uint uintDeath() | |
| { | |
| return uint(death()); | |
| } | |
| uint warValue() | |
| { | |
| return war().value; | |
| } | |
| uint famineValue() | |
| { | |
| return famine().value; | |
| } | |
| uint pestilenceValue() | |
| { | |
| return pestilence().value; | |
| } | |
| uint deathValue() | |
| { | |
| return death().value; | |
| } | |
| uint warValueLiteral() | |
| { | |
| return Foo.War.value; | |
| } | |
| uint famineValueLiteral() | |
| { | |
| return Foo.Famine.value; | |
| } | |
| uint pestilenceValueLiteral() | |
| { | |
| return Foo.Pestilence.value; | |
| } | |
| uint deathValueLiteral() | |
| { | |
| return Foo.Death.value; | |
| } | |
| Foo uintWarBackwards() | |
| { | |
| return Foo(uintWar()); | |
| } | |
| Foo uintFamineBackwards() | |
| { | |
| return Foo(uintFamine()); | |
| } | |
| Foo uintPestilenceBackwards() | |
| { | |
| return Foo(uintPestilence()); | |
| } | |
| Foo uintDeathBackwards() | |
| { | |
| return Foo(uintDeath()); | |
| } | |
| `); | |
| checkEnum(program, callFunction(program, "war", [], []), 0); | |
| checkEnum(program, callFunction(program, "famine", [], []), 1); | |
| checkEnum(program, callFunction(program, "pestilence", [], []), 2); | |
| checkEnum(program, callFunction(program, "death", [], []), 3); | |
| checkBool(program, callFunction(program, "testSimpleEqual", [], []), true); | |
| checkBool(program, callFunction(program, "testAnotherEqual", [], []), true); | |
| checkBool(program, callFunction(program, "testNotEqual", [], []), false); | |
| checkBool(program, callFunction(program, "testSimpleNotEqual", [], []), false); | |
| checkBool(program, callFunction(program, "testAnotherNotEqual", [], []), false); | |
| checkBool(program, callFunction(program, "testNotNotEqual", [], []), true); | |
| checkUint(program, callFunction(program, "uintWar", [], []), 0); | |
| checkUint(program, callFunction(program, "uintFamine", [], []), 1); | |
| checkUint(program, callFunction(program, "uintPestilence", [], []), 2); | |
| checkUint(program, callFunction(program, "uintDeath", [], []), 3); | |
| checkUint(program, callFunction(program, "warValue", [], []), 0); | |
| checkUint(program, callFunction(program, "famineValue", [], []), 1); | |
| checkUint(program, callFunction(program, "pestilenceValue", [], []), 2); | |
| checkUint(program, callFunction(program, "deathValue", [], []), 3); | |
| checkUint(program, callFunction(program, "warValueLiteral", [], []), 0); | |
| checkUint(program, callFunction(program, "famineValueLiteral", [], []), 1); | |
| checkUint(program, callFunction(program, "pestilenceValueLiteral", [], []), 2); | |
| checkUint(program, callFunction(program, "deathValueLiteral", [], []), 3); | |
| checkEnum(program, callFunction(program, "uintWarBackwards", [], []), 0); | |
| checkEnum(program, callFunction(program, "uintFamineBackwards", [], []), 1); | |
| checkEnum(program, callFunction(program, "uintPestilenceBackwards", [], []), 2); | |
| checkEnum(program, callFunction(program, "uintDeathBackwards", [], []), 3); | |
| } | |
| tests.enumFloatBase = function() | |
| { | |
| checkFail( | |
| () => doPrep(` | |
| enum Foo : float { | |
| Bar | |
| } | |
| `), | |
| e => e instanceof WTypeError); | |
| } | |
| tests.enumPtrBase = function() | |
| { | |
| checkFail( | |
| () => doPrep(` | |
| enum Foo : thread int* { | |
| Bar | |
| } | |
| `), | |
| e => e instanceof WTypeError); | |
| } | |
| tests.enumArrayRefBase = function() | |
| { | |
| checkFail( | |
| () => doPrep(` | |
| enum Foo : thread int[] { | |
| Bar | |
| } | |
| `), | |
| e => e instanceof WTypeError); | |
| } | |
| tests.emptyStruct = function() | |
| { | |
| let program = doPrep(` | |
| struct Thingy { } | |
| int foo() | |
| { | |
| Thingy thingy; | |
| return 46; | |
| } | |
| `); | |
| checkInt(program, callFunction(program, "foo", [], []), 46); | |
| } | |
| tests.enumStructBase = function() | |
| { | |
| checkFail( | |
| () => doPrep(` | |
| struct Thingy { } | |
| enum Foo : Thingy { | |
| Bar | |
| } | |
| `), | |
| e => e instanceof WTypeError); | |
| } | |
| tests.enumNoMembers = function() | |
| { | |
| checkFail( | |
| () => doPrep(` | |
| enum Foo { } | |
| `), | |
| e => e instanceof WTypeError); | |
| } | |
| tests.simpleSwitch = function() | |
| { | |
| let program = doPrep(` | |
| int foo(int x) | |
| { | |
| switch (x) { | |
| case 767: | |
| return 27; | |
| case 69: | |
| return 7624; | |
| default: | |
| return 49; | |
| } | |
| } | |
| `); | |
| checkInt(program, callFunction(program, "foo", [], [makeInt(program, 767)]), 27); | |
| checkInt(program, callFunction(program, "foo", [], [makeInt(program, 69)]), 7624); | |
| checkInt(program, callFunction(program, "foo", [], [makeInt(program, 0)]), 49); | |
| } | |
| tests.exhaustiveUint8Switch = function() | |
| { | |
| let text = "double foo(uint8 x) { switch (uint8(x)) {" | |
| for (let i = 0; i <= 0xff; ++i) | |
| text += "case " + i + ": return " + i * 1.5 + ";"; | |
| text += "} }"; | |
| let program = doPrep(text); | |
| for (let i = 0; i < 0xff; ++i) | |
| checkDouble(program, callFunction(program, "foo", [], [makeUint8(program, i)]), i * 1.5); | |
| } | |
| tests.notQuiteExhaustiveUint8Switch = function() | |
| { | |
| let text = "double foo(uint8 x) { switch (uint8(x)) {" | |
| for (let i = 0; i <= 0xfe; ++i) | |
| text += "case " + i + ": return " + i * 1.5 + ";"; | |
| text += "} }"; | |
| checkFail(() => doPrep(text), e => e instanceof WTypeError); | |
| } | |
| tests.notQuiteExhaustiveUint8SwitchWithDefault = function() | |
| { | |
| let text = "double foo(uint8 x) { switch (uint8(x)) {" | |
| for (let i = 0; i <= 0xfe; ++i) | |
| text += "case " + i + ": return " + i * 1.5 + ";"; | |
| text += "default: return " + 0xff * 1.5 + ";"; | |
| text += "} }"; | |
| let program = doPrep(text); | |
| for (let i = 0; i < 0xff; ++i) | |
| checkDouble(program, callFunction(program, "foo", [], [makeUint8(program, i)]), i * 1.5); | |
| } | |
| tests.switchFallThrough = function() | |
| { | |
| // FIXME: This might become an error in future versions. | |
| // https://bugs.webkit.org/show_bug.cgi?id=177172 | |
| let program = doPrep(` | |
| int foo(int x) | |
| { | |
| int result = 0; | |
| switch (x) { | |
| case 767: | |
| result += 27; | |
| case 69: | |
| result += 7624; | |
| default: | |
| result += 49; | |
| } | |
| return result; | |
| } | |
| `); | |
| checkInt(program, callFunction(program, "foo", [], [makeInt(program, 767)]), 27 + 7624 + 49); | |
| checkInt(program, callFunction(program, "foo", [], [makeInt(program, 69)]), 7624 + 49); | |
| checkInt(program, callFunction(program, "foo", [], [makeInt(program, 0)]), 49); | |
| } | |
| tests.switchBreak = function() | |
| { | |
| let program = doPrep(` | |
| int foo(int x) | |
| { | |
| int result = 0; | |
| switch (x) { | |
| case 767: | |
| result += 27; | |
| break; | |
| case 69: | |
| result += 7624; | |
| break; | |
| default: | |
| result += 49; | |
| break; | |
| } | |
| return result; | |
| } | |
| `); | |
| checkInt(program, callFunction(program, "foo", [], [makeInt(program, 767)]), 27); | |
| checkInt(program, callFunction(program, "foo", [], [makeInt(program, 69)]), 7624); | |
| checkInt(program, callFunction(program, "foo", [], [makeInt(program, 0)]), 49); | |
| } | |
| tests.enumSwitchBreakExhaustive = function() | |
| { | |
| let program = doPrep(` | |
| enum Foo { | |
| A, B, C | |
| } | |
| int foo(Foo x) | |
| { | |
| int result = 0; | |
| switch (x) { | |
| case Foo.A: | |
| result += 27; | |
| break; | |
| case Foo.B: | |
| result += 7624; | |
| break; | |
| case Foo.C: | |
| result += 49; | |
| break; | |
| } | |
| return result; | |
| } | |
| `); | |
| checkInt(program, callFunction(program, "foo", [], [makeEnum(program, "Foo", "A")]), 27); | |
| checkInt(program, callFunction(program, "foo", [], [makeEnum(program, "Foo", "B")]), 7624); | |
| checkInt(program, callFunction(program, "foo", [], [makeEnum(program, "Foo", "C")]), 49); | |
| } | |
| tests.enumSwitchBreakNotQuiteExhaustive = function() | |
| { | |
| checkFail( | |
| () => doPrep(` | |
| enum Foo { | |
| A, B, C, D | |
| } | |
| int foo(Foo x) | |
| { | |
| int result = 0; | |
| switch (x) { | |
| case Foo.A: | |
| result += 27; | |
| break; | |
| case Foo.B: | |
| result += 7624; | |
| break; | |
| case Foo.C: | |
| result += 49; | |
| break; | |
| } | |
| return result; | |
| } | |
| `), | |
| e => e instanceof WTypeError); | |
| } | |
| tests.enumSwitchBreakNotQuiteExhaustiveWithDefault = function() | |
| { | |
| let program = doPrep(` | |
| enum Foo { | |
| A, B, C | |
| } | |
| int foo(Foo x) | |
| { | |
| int result = 0; | |
| switch (x) { | |
| case Foo.A: | |
| result += 27; | |
| break; | |
| case Foo.B: | |
| result += 7624; | |
| break; | |
| default: | |
| result += 49; | |
| break; | |
| } | |
| return result; | |
| } | |
| `); | |
| checkInt(program, callFunction(program, "foo", [], [makeEnum(program, "Foo", "A")]), 27); | |
| checkInt(program, callFunction(program, "foo", [], [makeEnum(program, "Foo", "B")]), 7624); | |
| checkInt(program, callFunction(program, "foo", [], [makeEnum(program, "Foo", "C")]), 49); | |
| } | |
| tests.simpleRecursiveStruct = function() | |
| { | |
| checkFail( | |
| () => doPrep(` | |
| struct Foo { | |
| Foo foo; | |
| } | |
| `), | |
| e => e instanceof WTypeError); | |
| } | |
| tests.mutuallyRecursiveStruct = function() | |
| { | |
| checkFail( | |
| () => doPrep(` | |
| struct Foo { | |
| Bar bar; | |
| } | |
| struct Bar { | |
| Foo foo; | |
| } | |
| `), | |
| e => e instanceof WTypeError); | |
| } | |
| tests.mutuallyRecursiveStructWithPointersBroken = function() | |
| { | |
| let program = doPrep(` | |
| struct Foo { | |
| thread Bar* bar; | |
| int foo; | |
| } | |
| struct Bar { | |
| thread Foo* foo; | |
| int bar; | |
| } | |
| int foo() | |
| { | |
| Foo foo; | |
| Bar bar; | |
| foo.foo = 564; | |
| bar.bar = 53; | |
| return foo.bar->bar - bar.foo->foo; | |
| } | |
| `); | |
| checkFail( | |
| () => checkInt(program, callFunction(program, "foo", [], []), -511), | |
| e => e instanceof WTrapError); | |
| } | |
| tests.mutuallyRecursiveStructWithPointers = function() | |
| { | |
| let program = doPrep(` | |
| struct Foo { | |
| thread Bar* bar; | |
| int foo; | |
| } | |
| struct Bar { | |
| thread Foo* foo; | |
| int bar; | |
| } | |
| int foo() | |
| { | |
| Foo foo; | |
| Bar bar; | |
| foo.bar = &bar; | |
| bar.foo = &foo; | |
| foo.foo = 564; | |
| bar.bar = 53; | |
| return foo.bar->bar - bar.foo->foo; | |
| } | |
| `); | |
| checkInt(program, callFunction(program, "foo", [], []), -511); | |
| } | |
| tests.linkedList = function() | |
| { | |
| let program = doPrep(` | |
| struct Node { | |
| thread Node* next; | |
| int value; | |
| } | |
| int foo() | |
| { | |
| Node x, y, z; | |
| x.next = &y; | |
| y.next = &z; | |
| x.value = 1; | |
| y.value = 2; | |
| z.value = 3; | |
| return x.next->next->value; | |
| } | |
| `); | |
| checkInt(program, callFunction(program, "foo", [], []), 3); | |
| } | |
| tests.pointerToPointer = function() | |
| { | |
| let program = doPrep(` | |
| int foo() | |
| { | |
| int x; | |
| thread int* p = &x; | |
| thread int** pp = &p; | |
| int*thread*thread qq = pp; | |
| int result = 0; | |
| x = 42; | |
| *p = 76; | |
| result += x; | |
| **pp = 39; | |
| result += x; | |
| **qq = 83; | |
| result += x; | |
| return result; | |
| } | |
| `); | |
| checkInt(program, callFunction(program, "foo", [], []), 76 + 39 + 83); | |
| } | |
| tests.arrayRefToArrayRef = function() | |
| { | |
| let program = doPrep(` | |
| int foo() | |
| { | |
| int x; | |
| thread int[] p = @x; | |
| thread int[][] pp = @p; | |
| int[]thread[]thread qq = pp; | |
| int result = 0; | |
| x = 42; | |
| p[0] = 76; | |
| result += x; | |
| pp[0][0] = 39; | |
| result += x; | |
| qq[0][0] = 83; | |
| result += x; | |
| return result; | |
| } | |
| `); | |
| checkInt(program, callFunction(program, "foo", [], []), 76 + 39 + 83); | |
| } | |
| tests.pointerGetter = function() | |
| { | |
| checkFail( | |
| () => doPrep(` | |
| int operator.foo(device int*) | |
| { | |
| return 543; | |
| } | |
| `), | |
| e => e instanceof WTypeError); | |
| checkFail( | |
| () => doPrep(` | |
| int operator.foo(thread int*) | |
| { | |
| return 543; | |
| } | |
| `), | |
| e => e instanceof WTypeError); | |
| checkFail( | |
| () => doPrep(` | |
| int operator.foo(threadgroup int*) | |
| { | |
| return 543; | |
| } | |
| `), | |
| e => e instanceof WTypeError); | |
| checkFail( | |
| () => doPrep(` | |
| int operator.foo(constant int*) | |
| { | |
| return 543; | |
| } | |
| `), | |
| e => e instanceof WTypeError); | |
| } | |
| tests.loneSetter = function() | |
| { | |
| checkFail( | |
| () => doPrep(` | |
| int operator.foo=(int, int) | |
| { | |
| return 543; | |
| } | |
| `), | |
| e => e instanceof WTypeError); | |
| } | |
| tests.setterWithMismatchedType = function() | |
| { | |
| checkFail( | |
| () => doPrep(` | |
| double operator.foo(int) | |
| { | |
| return 5.43; | |
| } | |
| int operator.foo=(int, int) | |
| { | |
| return 543; | |
| } | |
| `), | |
| e => e instanceof WTypeError); | |
| } | |
| tests.setterWithMatchedType = function() | |
| { | |
| doPrep(` | |
| int operator.foo(int) | |
| { | |
| return 5; | |
| } | |
| int operator.foo=(int, int) | |
| { | |
| return 543; | |
| } | |
| `); | |
| } | |
| tests.operatorWithUninferrableTypeVariable = function() | |
| { | |
| checkFail( | |
| () => doPrep(` | |
| struct Foo { | |
| int x; | |
| } | |
| Foo operator+<T>(Foo a, Foo b) | |
| { | |
| Foo result; | |
| result.x = a.x + b.x; | |
| return result; | |
| } | |
| `), | |
| e => e instanceof WTypeError); | |
| } | |
| tests.operatorWithoutUninferrableTypeVariable = function() | |
| { | |
| let program = doPrep(` | |
| struct Foo { | |
| int x; | |
| } | |
| Foo operator+(Foo a, Foo b) | |
| { | |
| Foo result; | |
| result.x = a.x + b.x; | |
| return result; | |
| } | |
| int foo() | |
| { | |
| Foo a; | |
| a.x = 645; | |
| Foo b; | |
| b.x = -35; | |
| return (a + b).x; | |
| } | |
| `); | |
| checkInt(program, callFunction(program, "foo", [], []), 645 - 35); | |
| } | |
| tests.operatorCastWithUninferrableTypeVariable = function() | |
| { | |
| checkFail( | |
| () => doPrep(` | |
| struct Foo { | |
| int x; | |
| } | |
| operator<T> Foo(int x) | |
| { | |
| Foo result; | |
| result.x = x; | |
| return result; | |
| } | |
| `), | |
| e => e instanceof WTypeError); | |
| } | |
| tests.operatorCastWithTypeVariableInferredFromReturnType = function() | |
| { | |
| let program = doPrep(` | |
| struct Foo { | |
| int x; | |
| } | |
| protocol Barable { | |
| void bar(thread Barable*, int); | |
| } | |
| void bar(thread double* result, int value) | |
| { | |
| *result = double(value); | |
| } | |
| operator<T:Barable> T(Foo foo) | |
| { | |
| T result; | |
| bar(&result, foo.x); | |
| return result; | |
| } | |
| int foo() | |
| { | |
| Foo foo; | |
| foo.x = 75; | |
| double x = double(foo); | |
| return int(x * 1.5); | |
| } | |
| `); | |
| checkInt(program, callFunction(program, "foo", [], []), 112); | |
| } | |
| tests.incWrongArgumentLength = function() | |
| { | |
| checkFail( | |
| () => doPrep(` | |
| int operator++() { return 32; } | |
| `), | |
| e => e instanceof WTypeError); | |
| checkFail( | |
| () => doPrep(` | |
| int operator++(int, int) { return 76; } | |
| `), | |
| e => e instanceof WTypeError); | |
| } | |
| tests.decWrongArgumentLength = function() | |
| { | |
| checkFail( | |
| () => doPrep(` | |
| int operator--() { return 32; } | |
| `), | |
| e => e instanceof WTypeError); | |
| checkFail( | |
| () => doPrep(` | |
| int operator--(int, int) { return 76; } | |
| `), | |
| e => e instanceof WTypeError); | |
| } | |
| tests.incWrongTypes = function() | |
| { | |
| checkFail( | |
| () => doPrep(` | |
| int operator++(double) { return 32; } | |
| `), | |
| e => e instanceof WTypeError); | |
| } | |
| tests.decWrongTypes = function() | |
| { | |
| checkFail( | |
| () => doPrep(` | |
| int operator--(double) { return 32; } | |
| `), | |
| e => e instanceof WTypeError); | |
| } | |
| tests.plusWrongArgumentLength = function() | |
| { | |
| checkFail( | |
| () => doPrep(` | |
| int operator+() { return 32; } | |
| `), | |
| e => e instanceof WTypeError); | |
| checkFail( | |
| () => doPrep(` | |
| int operator+(int, int, int) { return 76; } | |
| `), | |
| e => e instanceof WTypeError); | |
| } | |
| tests.minusWrongArgumentLength = function() | |
| { | |
| checkFail( | |
| () => doPrep(` | |
| int operator-() { return 32; } | |
| `), | |
| e => e instanceof WTypeError); | |
| checkFail( | |
| () => doPrep(` | |
| int operator-(int, int, int) { return 76; } | |
| `), | |
| e => e instanceof WTypeError); | |
| } | |
| tests.timesWrongArgumentLength = function() | |
| { | |
| checkFail( | |
| () => doPrep(` | |
| int operator*() { return 32; } | |
| `), | |
| e => e instanceof WTypeError); | |
| checkFail( | |
| () => doPrep(` | |
| int operator*(int) { return 534; } | |
| `), | |
| e => e instanceof WTypeError); | |
| checkFail( | |
| () => doPrep(` | |
| int operator*(int, int, int) { return 76; } | |
| `), | |
| e => e instanceof WTypeError); | |
| } | |
| tests.divideWrongArgumentLength = function() | |
| { | |
| checkFail( | |
| () => doPrep(` | |
| int operator/() { return 32; } | |
| `), | |
| e => e instanceof WTypeError); | |
| checkFail( | |
| () => doPrep(` | |
| int operator/(int) { return 534; } | |
| `), | |
| e => e instanceof WTypeError); | |
| checkFail( | |
| () => doPrep(` | |
| int operator/(int, int, int) { return 76; } | |
| `), | |
| e => e instanceof WTypeError); | |
| } | |
| tests.moduloWrongArgumentLength = function() | |
| { | |
| checkFail( | |
| () => doPrep(` | |
| int operator%() { return 32; } | |
| `), | |
| e => e instanceof WTypeError); | |
| checkFail( | |
| () => doPrep(` | |
| int operator%(int) { return 534; } | |
| `), | |
| e => e instanceof WTypeError); | |
| checkFail( | |
| () => doPrep(` | |
| int operator%(int, int, int) { return 76; } | |
| `), | |
| e => e instanceof WTypeError); | |
| } | |
| tests.bitAndWrongArgumentLength = function() | |
| { | |
| checkFail( | |
| () => doPrep(` | |
| int operator&() { return 32; } | |
| `), | |
| e => e instanceof WTypeError); | |
| checkFail( | |
| () => doPrep(` | |
| int operator&(int) { return 534; } | |
| `), | |
| e => e instanceof WTypeError); | |
| checkFail( | |
| () => doPrep(` | |
| int operator&(int, int, int) { return 76; } | |
| `), | |
| e => e instanceof WTypeError); | |
| } | |
| tests.bitOrWrongArgumentLength = function() | |
| { | |
| checkFail( | |
| () => doPrep(` | |
| int operator|() { return 32; } | |
| `), | |
| e => e instanceof WTypeError); | |
| checkFail( | |
| () => doPrep(` | |
| int operator|(int) { return 534; } | |
| `), | |
| e => e instanceof WTypeError); | |
| checkFail( | |
| () => doPrep(` | |
| int operator|(int, int, int) { return 76; } | |
| `), | |
| e => e instanceof WTypeError); | |
| } | |
| tests.bitXorWrongArgumentLength = function() | |
| { | |
| checkFail( | |
| () => doPrep(` | |
| int operator^() { return 32; } | |
| `), | |
| e => e instanceof WTypeError); | |
| checkFail( | |
| () => doPrep(` | |
| int operator^(int) { return 534; } | |
| `), | |
| e => e instanceof WTypeError); | |
| checkFail( | |
| () => doPrep(` | |
| int operator^(int, int, int) { return 76; } | |
| `), | |
| e => e instanceof WTypeError); | |
| } | |
| tests.lShiftWrongArgumentLength = function() | |
| { | |
| checkFail( | |
| () => doPrep(` | |
| int operator<<() { return 32; } | |
| `), | |
| e => e instanceof WTypeError); | |
| checkFail( | |
| () => doPrep(` | |
| int operator<<(int) { return 534; } | |
| `), | |
| e => e instanceof WTypeError); | |
| checkFail( | |
| () => doPrep(` | |
| int operator<<(int, int, int) { return 76; } | |
| `), | |
| e => e instanceof WTypeError); | |
| } | |
| tests.rShiftWrongArgumentLength = function() | |
| { | |
| checkFail( | |
| () => doPrep(` | |
| int operator>>() { return 32; } | |
| `), | |
| e => e instanceof WTypeError); | |
| checkFail( | |
| () => doPrep(` | |
| int operator>>(int) { return 534; } | |
| `), | |
| e => e instanceof WTypeError); | |
| checkFail( | |
| () => doPrep(` | |
| int operator>>(int, int, int) { return 76; } | |
| `), | |
| e => e instanceof WTypeError); | |
| } | |
| tests.bitNotWrongArgumentLength = function() | |
| { | |
| checkFail( | |
| () => doPrep(` | |
| int operator~() { return 32; } | |
| `), | |
| e => e instanceof WTypeError); | |
| checkFail( | |
| () => doPrep(` | |
| int operator~(int, int) { return 534; } | |
| `), | |
| e => e instanceof WTypeError); | |
| } | |
| tests.equalsWrongArgumentLength = function() | |
| { | |
| checkFail( | |
| () => doPrep(` | |
| bool operator==() { return true; } | |
| `), | |
| e => e instanceof WTypeError); | |
| checkFail( | |
| () => doPrep(` | |
| bool operator==(int) { return true; } | |
| `), | |
| e => e instanceof WTypeError); | |
| checkFail( | |
| () => doPrep(` | |
| bool operator==(int, int, int) { return true; } | |
| `), | |
| e => e instanceof WTypeError); | |
| } | |
| tests.lessThanWrongArgumentLength = function() | |
| { | |
| checkFail( | |
| () => doPrep(` | |
| bool operator<() { return true; } | |
| `), | |
| e => e instanceof WTypeError); | |
| checkFail( | |
| () => doPrep(` | |
| bool operator<(int) { return true; } | |
| `), | |
| e => e instanceof WTypeError); | |
| checkFail( | |
| () => doPrep(` | |
| bool operator<(int, int, int) { return true; } | |
| `), | |
| e => e instanceof WTypeError); | |
| } | |
| tests.lessEqualWrongArgumentLength = function() | |
| { | |
| checkFail( | |
| () => doPrep(` | |
| bool operator<=() { return true; } | |
| `), | |
| e => e instanceof WTypeError); | |
| checkFail( | |
| () => doPrep(` | |
| bool operator<=(int) { return true; } | |
| `), | |
| e => e instanceof WTypeError); | |
| checkFail( | |
| () => doPrep(` | |
| bool operator<=(int, int, int) { return true; } | |
| `), | |
| e => e instanceof WTypeError); | |
| } | |
| tests.greaterWrongArgumentLength = function() | |
| { | |
| checkFail( | |
| () => doPrep(` | |
| bool operator>() { return true; } | |
| `), | |
| e => e instanceof WTypeError); | |
| checkFail( | |
| () => doPrep(` | |
| bool operator>(int) { return true; } | |
| `), | |
| e => e instanceof WTypeError); | |
| checkFail( | |
| () => doPrep(` | |
| bool operator>(int, int, int) { return true; } | |
| `), | |
| e => e instanceof WTypeError); | |
| } | |
| tests.greaterEqualWrongArgumentLength = function() | |
| { | |
| checkFail( | |
| () => doPrep(` | |
| bool operator>=() { return true; } | |
| `), | |
| e => e instanceof WTypeError); | |
| checkFail( | |
| () => doPrep(` | |
| bool operator>=(int) { return true; } | |
| `), | |
| e => e instanceof WTypeError); | |
| checkFail( | |
| () => doPrep(` | |
| bool operator>=(int, int, int) { return true; } | |
| `), | |
| e => e instanceof WTypeError); | |
| } | |
| tests.equalsWrongReturnType = function() | |
| { | |
| checkFail( | |
| () => doPrep(` | |
| int operator==(int a, int b) { return a + b; } | |
| `), | |
| e => e instanceof WTypeError); | |
| } | |
| tests.notEqualsOverload = function() | |
| { | |
| checkFail( | |
| () => doPrep(` | |
| struct Foo { } | |
| bool operator!=(Foo, Foo) { return true; } | |
| `), | |
| e => e instanceof WSyntaxError); | |
| } | |
| tests.lessThanWrongReturnType = function() | |
| { | |
| checkFail( | |
| () => doPrep(` | |
| int operator<(int a, int b) { return a + b; } | |
| `), | |
| e => e instanceof WTypeError); | |
| } | |
| tests.lessEqualWrongReturnType = function() | |
| { | |
| checkFail( | |
| () => doPrep(` | |
| int operator<=(int a, int b) { return a + b; } | |
| `), | |
| e => e instanceof WTypeError); | |
| } | |
| tests.greaterThanWrongReturnType = function() | |
| { | |
| checkFail( | |
| () => doPrep(` | |
| int operator>(int a, int b) { return a + b; } | |
| `), | |
| e => e instanceof WTypeError); | |
| } | |
| tests.greaterEqualWrongReturnType = function() | |
| { | |
| checkFail( | |
| () => doPrep(` | |
| int operator>=(int a, int b) { return a + b; } | |
| `), | |
| e => e instanceof WTypeError); | |
| } | |
| tests.dotOperatorWrongArgumentLength = function() | |
| { | |
| checkFail( | |
| () => doPrep(` | |
| int operator.foo() { return 42; } | |
| `), | |
| e => e instanceof WTypeError); | |
| checkFail( | |
| () => doPrep(` | |
| struct Foo { } | |
| int operator.foo(Foo, int) { return 42; } | |
| `), | |
| e => e instanceof WTypeError); | |
| } | |
| tests.dotOperatorSetterWrongArgumentLength = function() | |
| { | |
| checkFail( | |
| () => doPrep(` | |
| struct Foo { } | |
| Foo operator.foo=() { return 42; } | |
| `), | |
| e => e instanceof WTypeError); | |
| checkFail( | |
| () => doPrep(` | |
| struct Foo { } | |
| Foo operator.foo=(Foo) { return 42; } | |
| `), | |
| e => e instanceof WTypeError); | |
| checkFail( | |
| () => doPrep(` | |
| struct Foo { } | |
| Foo operator.foo=(Foo, int, int) { return 42; } | |
| `), | |
| e => e instanceof WTypeError); | |
| } | |
| tests.loneSetterPointer = function() | |
| { | |
| checkFail( | |
| () => doPrep(` | |
| thread int* operator.foo=(thread int* ptr, int) | |
| { | |
| return ptr; | |
| } | |
| `), | |
| e => e instanceof WTypeError); | |
| } | |
| tests.setterWithNoGetterOverload = function() | |
| { | |
| checkFail( | |
| () => doPrep(` | |
| struct Foo { } | |
| struct Bar { } | |
| int operator.foo(Foo) | |
| { | |
| return 534; | |
| } | |
| Bar operator.foo=(Bar, int) | |
| { | |
| return Bar(); | |
| } | |
| `), | |
| e => e instanceof WTypeError); | |
| } | |
| tests.setterWithNoGetterOverloadFixed = function() | |
| { | |
| doPrep(` | |
| struct Bar { } | |
| int operator.foo(Bar) | |
| { | |
| return 534; | |
| } | |
| Bar operator.foo=(Bar, int) | |
| { | |
| return Bar(); | |
| } | |
| `); | |
| } | |
| tests.anderWithNothingWrong = function() | |
| { | |
| let program = doPrep(` | |
| struct Foo { | |
| int x; | |
| } | |
| thread int* operator&.foo(thread Foo* foo) | |
| { | |
| return &foo->x; | |
| } | |
| int foo() | |
| { | |
| Foo x; | |
| x.x = 13; | |
| return x.foo; | |
| } | |
| `); | |
| checkInt(program, callFunction(program, "foo", [], []), 13); | |
| } | |
| tests.anderWithWrongNumberOfArguments = function() | |
| { | |
| checkFail( | |
| () => doPrep(` | |
| thread int* operator&.foo() | |
| { | |
| int x; | |
| return &x; | |
| } | |
| `), | |
| e => e instanceof WTypeError); | |
| checkFail( | |
| () => doPrep(` | |
| struct Foo { | |
| int x; | |
| } | |
| thread int* operator&.foo(thread Foo* foo, int blah) | |
| { | |
| return &foo->x; | |
| } | |
| `), | |
| e => e instanceof WTypeError); | |
| } | |
| tests.anderDoesntReturnPointer = function() | |
| { | |
| checkFail( | |
| () => doPrep(` | |
| struct Foo { | |
| int x; | |
| } | |
| int operator&.foo(thread Foo* foo) | |
| { | |
| return foo->x; | |
| } | |
| `), | |
| e => e instanceof WTypeError); | |
| } | |
| tests.anderDoesntTakeReference = function() | |
| { | |
| checkFail( | |
| () => doPrep(` | |
| struct Foo { | |
| int x; | |
| } | |
| thread int* operator&.foo(Foo foo) | |
| { | |
| return &foo.x; | |
| } | |
| `), | |
| e => e instanceof WTypeError); | |
| } | |
| tests.anderWithArrayRef = function() | |
| { | |
| let program = doPrep(` | |
| struct Foo { | |
| int x; | |
| } | |
| thread int* operator&.foo(thread Foo[] foo) | |
| { | |
| return &foo[0].x; | |
| } | |
| int foo() | |
| { | |
| Foo x; | |
| x.x = 13; | |
| return (@x).foo; | |
| } | |
| `); | |
| checkInt(program, callFunction(program, "foo", [], []), 13); | |
| } | |
| tests.pointerIndexGetter = function() | |
| { | |
| checkFail( | |
| () => doPrep(` | |
| int operator[](device int*, uint) | |
| { | |
| return 543; | |
| } | |
| `), | |
| e => e instanceof WTypeError); | |
| checkFail( | |
| () => doPrep(` | |
| int operator[](thread int*, uint) | |
| { | |
| return 543; | |
| } | |
| `), | |
| e => e instanceof WTypeError); | |
| checkFail( | |
| () => doPrep(` | |
| int operator[](threadgroup int*, uint) | |
| { | |
| return 543; | |
| } | |
| `), | |
| e => e instanceof WTypeError); | |
| checkFail( | |
| () => doPrep(` | |
| int operator[](constant int*, uint) | |
| { | |
| return 543; | |
| } | |
| `), | |
| e => e instanceof WTypeError); | |
| } | |
| tests.loneIndexSetter = function() | |
| { | |
| checkFail( | |
| () => doPrep(` | |
| int operator[]=(int, uint, int) | |
| { | |
| return 543; | |
| } | |
| `), | |
| e => e instanceof WTypeError); | |
| } | |
| tests.notLoneIndexSetter = function() | |
| { | |
| doPrep(` | |
| int operator[](int, uint) | |
| { | |
| return 65; | |
| } | |
| int operator[]=(int, uint, int) | |
| { | |
| return 543; | |
| } | |
| `); | |
| } | |
| tests.indexSetterWithMismatchedType = function() | |
| { | |
| checkFail( | |
| () => doPrep(` | |
| double operator[](int, uint) | |
| { | |
| return 5.43; | |
| } | |
| int operator[]=(int, uint, int) | |
| { | |
| return 543; | |
| } | |
| `), | |
| e => e instanceof WTypeError && e.message.indexOf("Setter and getter must agree on value type") != -1); | |
| } | |
| tests.indexOperatorWrongArgumentLength = function() | |
| { | |
| checkFail( | |
| () => doPrep(` | |
| int operator[]() { return 42; } | |
| `), | |
| e => e instanceof WTypeError); | |
| checkFail( | |
| () => doPrep(` | |
| int operator[](int) { return 42; } | |
| `), | |
| e => e instanceof WTypeError); | |
| checkFail( | |
| () => doPrep(` | |
| int operator[](int, int, int) { return 42; } | |
| `), | |
| e => e instanceof WTypeError); | |
| } | |
| tests.indexOperatorSetterWrongArgumentLength = function() | |
| { | |
| checkFail( | |
| () => doPrep(` | |
| int operator[]=() { return 42; } | |
| `), | |
| e => e instanceof WTypeError); | |
| checkFail( | |
| () => doPrep(` | |
| int operator[]=(int) { return 42; } | |
| `), | |
| e => e instanceof WTypeError); | |
| checkFail( | |
| () => doPrep(` | |
| int operator[]=(int, int) { return 42; } | |
| `), | |
| e => e instanceof WTypeError); | |
| checkFail( | |
| () => doPrep(` | |
| int operator[]=(int, int, int, int) { return 42; } | |
| `), | |
| e => e instanceof WTypeError); | |
| } | |
| tests.loneIndexSetterPointer = function() | |
| { | |
| checkFail( | |
| () => doPrep(` | |
| thread int* operator[]=(thread int* ptr, uint, int) | |
| { | |
| return ptr; | |
| } | |
| `), | |
| e => e instanceof WTypeError); | |
| } | |
| tests.indexSetterWithNoGetterOverload = function() | |
| { | |
| checkFail( | |
| () => doPrep(` | |
| struct Foo { } | |
| struct Bar { } | |
| int operator[](Foo, uint) | |
| { | |
| return 534; | |
| } | |
| Bar operator[]=(Bar, uint, int) | |
| { | |
| return Bar(); | |
| } | |
| `), | |
| e => e instanceof WTypeError); | |
| } | |
| tests.indexSetterWithNoGetterOverloadFixed = function() | |
| { | |
| doPrep(` | |
| struct Bar { } | |
| int operator[](Bar, uint) | |
| { | |
| return 534; | |
| } | |
| Bar operator[]=(Bar, uint, int) | |
| { | |
| return Bar(); | |
| } | |
| `); | |
| } | |
| tests.indexAnderWithNothingWrong = function() | |
| { | |
| let program = doPrep(` | |
| struct Foo { | |
| int x; | |
| } | |
| thread int* operator&[](thread Foo* foo, uint) | |
| { | |
| return &foo->x; | |
| } | |
| int foo() | |
| { | |
| Foo x; | |
| x.x = 13; | |
| return x[666]; | |
| } | |
| `); | |
| checkInt(program, callFunction(program, "foo", [], []), 13); | |
| } | |
| tests.indexAnderWithWrongNumberOfArguments = function() | |
| { | |
| checkFail( | |
| () => doPrep(` | |
| thread int* operator&[]() | |
| { | |
| int x; | |
| return &x; | |
| } | |
| `), | |
| e => e instanceof WTypeError); | |
| checkFail( | |
| () => doPrep(` | |
| struct Foo { | |
| int x; | |
| } | |
| thread int* operator&[](thread Foo* foo) | |
| { | |
| return &foo->x; | |
| } | |
| `), | |
| e => e instanceof WTypeError); | |
| checkFail( | |
| () => doPrep(` | |
| struct Foo { | |
| int x; | |
| } | |
| thread int* operator&[](thread Foo* foo, uint, uint) | |
| { | |
| return &foo->x; | |
| } | |
| `), | |
| e => e instanceof WTypeError); | |
| } | |
| tests.indexAnderDoesntReturnPointer = function() | |
| { | |
| checkFail( | |
| () => doPrep(` | |
| struct Foo { | |
| int x; | |
| } | |
| int operator&[](thread Foo* foo, uint) | |
| { | |
| return foo->x; | |
| } | |
| `), | |
| e => e instanceof WTypeError && e.message.indexOf("Return type of ander is not a pointer") != -1); | |
| } | |
| tests.indexAnderDoesntTakeReference = function() | |
| { | |
| checkFail( | |
| () => doPrep(` | |
| struct Foo { | |
| int x; | |
| } | |
| thread int* operator&[](Foo foo, uint) | |
| { | |
| return &foo.x; | |
| } | |
| `), | |
| e => e instanceof WTypeError && e.message.indexOf("Parameter to ander is not a reference") != -1); | |
| } | |
| tests.indexAnderWithArrayRef = function() | |
| { | |
| let program = doPrep(` | |
| struct Foo { | |
| int x; | |
| } | |
| thread int* operator&[](thread Foo[] array, double index) | |
| { | |
| return &array[uint(index + 1)].x; | |
| } | |
| int foo() | |
| { | |
| Foo x; | |
| x.x = 13; | |
| return (@x)[double(-1)]; | |
| } | |
| `); | |
| checkInt(program, callFunction(program, "foo", [], []), 13); | |
| } | |
| tests.devicePtrPtr = function() | |
| { | |
| checkFail( | |
| () => doPrep(` | |
| void foo() | |
| { | |
| device int** p; | |
| } | |
| `), | |
| e => e instanceof WTypeError && e.message.indexOf("Illegal pointer to non-primitive type: int32* device* device") != -1); | |
| } | |
| tests.threadgroupPtrPtr = function() | |
| { | |
| checkFail( | |
| () => doPrep(` | |
| void foo() | |
| { | |
| threadgroup int** p; | |
| } | |
| `), | |
| e => e instanceof WTypeError && e.message.indexOf("Illegal pointer to non-primitive type: int32* threadgroup* threadgroup") != -1); | |
| } | |
| tests.constantPtrPtr = function() | |
| { | |
| checkFail( | |
| () => doPrep(` | |
| void foo() | |
| { | |
| constant int** p; | |
| } | |
| `), | |
| e => e instanceof WTypeError && e.message.indexOf("Illegal pointer to non-primitive type: int32* constant* constant") != -1); | |
| } | |
| tests.pointerIndexGetterInProtocol = function() | |
| { | |
| for (let addressSpace of addressSpaces) { | |
| checkFail( | |
| () => doPrep(` | |
| protocol Foo { | |
| int operator[](${addressSpace} Foo*, uint); | |
| } | |
| struct Bar { } | |
| int operator[](Bar, uint) { return 42; } | |
| `), | |
| e => e instanceof WTypeError && e.message.indexOf("Cannot have getter for pointer type") != -1); | |
| } | |
| } | |
| tests.loneIndexSetterInProtocol = function() | |
| { | |
| checkFail( | |
| () => doPrep(` | |
| protocol Foo { | |
| Foo operator[]=(Foo, uint, int); | |
| } | |
| struct Bar { } | |
| int operator[](Bar, uint) { return 42; } | |
| Bar operator[]=(Bar, uint, int) { return Bar(); } | |
| `), | |
| e => e instanceof WTypeError && e.message.indexOf("Every setter must have a matching getter") != -1); | |
| } | |
| tests.notLoneIndexSetterInProtocol = function() | |
| { | |
| doPrep(` | |
| protocol Foo { | |
| int operator[](Foo, uint); | |
| Foo operator[]=(Foo, uint, int); | |
| } | |
| struct Bar { } | |
| int operator[](Bar, uint) { return 42; } | |
| Bar operator[]=(Bar, uint, int) { return Bar(); } | |
| `); | |
| } | |
| tests.indexSetterWithMismatchedTypeInProtocol = function() | |
| { | |
| checkFail( | |
| () => doPrep(` | |
| protocol Foo { | |
| double operator[](Foo, uint); | |
| Foo operator[]=(Foo, uint, int); | |
| } | |
| struct Bar { } | |
| int operator[](Bar, uint) { return 42; } | |
| Bar operator[]=(Bar, uint, int) { return Bar(); } | |
| `), | |
| e => e instanceof WTypeError && e.message.indexOf("Setter and getter must agree on value type") != -1); | |
| } | |
| tests.indexOperatorWrongArgumentLengthInProtocol = function() | |
| { | |
| checkFail( | |
| () => doPrep(` | |
| protocol Foo { | |
| int operator[](); | |
| } | |
| struct Bar { } | |
| int operator[](Bar, uint) { return 42; } | |
| `), | |
| e => e instanceof WTypeError && e.message.indexOf("Protocol's type variable (Foo) not mentioned in signature") != -1); | |
| checkFail( | |
| () => doPrep(` | |
| protocol Foo { | |
| int operator[](Foo); | |
| } | |
| struct Bar { } | |
| int operator[](Bar, uint) { return 42; } | |
| `), | |
| e => e instanceof WTypeError && e.message.indexOf("Incorrect number of parameters") != -1); | |
| checkFail( | |
| () => doPrep(` | |
| protocol Foo { | |
| int operator[](Foo, int, int); | |
| } | |
| struct Bar { } | |
| int operator[](Bar, uint) { return 42; } | |
| `), | |
| e => e instanceof WTypeError && e.message.indexOf("Incorrect number of parameters") != -1); | |
| } | |
| tests.indexOperatorSetterWrongArgumentLengthInProtocol = function() | |
| { | |
| checkFail( | |
| () => doPrep(` | |
| protocol Foo { | |
| int operator[]=(); | |
| } | |
| struct Bar { } | |
| int operator[](Bar, uint) { return 42; } | |
| Bar operator[]=(Bar, uint, int) { return Bar(); } | |
| `), | |
| e => e instanceof WTypeError && e.message.indexOf("Protocol's type variable (Foo) not mentioned in signature") != -1); | |
| checkFail( | |
| () => doPrep(` | |
| protocol Foo { | |
| int operator[]=(Foo); | |
| } | |
| struct Bar { } | |
| int operator[](Bar, uint) { return 42; } | |
| Bar operator[]=(Bar, uint, int) { return Bar(); } | |
| `), | |
| e => e instanceof WTypeError && e.message.indexOf("Incorrect number of parameters") != -1); | |
| checkFail( | |
| () => doPrep(` | |
| protocol Foo { | |
| int operator[]=(Foo, int); | |
| } | |
| struct Bar { } | |
| int operator[](Bar, uint) { return 42; } | |
| Bar operator[]=(Bar, uint, int) { return Bar(); } | |
| `), | |
| e => e instanceof WTypeError && e.message.indexOf("Incorrect number of parameters") != -1); | |
| checkFail( | |
| () => doPrep(` | |
| protocol Foo { | |
| int operator[]=(Foo, int, int, int); | |
| } | |
| struct Bar { } | |
| int operator[](Bar, uint) { return 42; } | |
| Bar operator[]=(Bar, uint, int) { return Bar(); } | |
| `), | |
| e => e instanceof WTypeError && e.message.indexOf("Incorrect number of parameters") != -1); | |
| } | |
| tests.loneIndexSetterPointerInProtocol = function() | |
| { | |
| checkFail( | |
| () => doPrep(` | |
| protocol Foo { | |
| thread int* operator[]=(thread Foo* ptr, uint, int); | |
| } | |
| struct Bar { } | |
| int operator[](Bar, uint) { return 42; } | |
| Bar operator[]=(Bar, uint, int) { return Bar(); } | |
| `), | |
| e => e instanceof WTypeError && e.message.indexOf("Cannot have setter for pointer type") != -1); | |
| } | |
| tests.indexSetterWithNoGetterOverloadInProtocol = function() | |
| { | |
| checkFail( | |
| () => doPrep(` | |
| protocol Foo { | |
| int operator[](int, Foo); | |
| Foo operator[]=(Foo, uint, int); | |
| } | |
| struct Bar { } | |
| int operator[](Bar, uint) { return 42; } | |
| Bar operator[]=(Bar, uint, int) { return Bar(); } | |
| `), | |
| e => e instanceof WTypeError && e.message.indexOf("Did not find function named operator[]= with arguments Foo,uint32") != -1); | |
| } | |
| tests.indexSetterWithNoGetterOverloadFixedInProtocol = function() | |
| { | |
| doPrep(` | |
| protocol Foo { | |
| int operator[](Foo, uint); | |
| Foo operator[]=(Foo, uint, int); | |
| } | |
| struct Bar { } | |
| int operator[](Bar, uint) { return 42; } | |
| Bar operator[]=(Bar, uint, int) { return Bar(); } | |
| `); | |
| } | |
| tests.indexAnderWithNothingWrongInProtocol = function() | |
| { | |
| let program = doPrep(` | |
| protocol Foo { | |
| thread int* operator&[](thread Foo* foo, uint); | |
| } | |
| int bar<T:Foo>(T x) | |
| { | |
| return x[42]; | |
| } | |
| struct Bar { } | |
| thread int* operator&[](thread Bar*, uint) | |
| { | |
| int result = 1234; | |
| return &result; | |
| } | |
| int foo() | |
| { | |
| return bar(Bar()); | |
| } | |
| `); | |
| checkInt(program, callFunction(program, "foo", [], []), 1234); | |
| } | |
| tests.indexAnderWithWrongNumberOfArgumentsInProtocol = function() | |
| { | |
| checkFail( | |
| () => doPrep(` | |
| protocol Foo { | |
| thread int* operator&[](); | |
| } | |
| struct Bar { } | |
| thread int* operator&[](thread Bar*, uint) | |
| { | |
| int result = 1234; | |
| return &result; | |
| } | |
| `), | |
| e => e instanceof WTypeError && e.message.indexOf("Protocol's type variable (Foo) not mentioned in signature") != -1); | |
| checkFail( | |
| () => doPrep(` | |
| protocol Foo { | |
| thread int* operator&[](thread Foo* foo); | |
| } | |
| struct Bar { } | |
| thread int* operator&[](thread Bar*, uint) | |
| { | |
| int result = 1234; | |
| return &result; | |
| } | |
| `), | |
| e => e instanceof WTypeError && e.message.indexOf("Incorrect number of parameters for operator&[]") != -1); | |
| checkFail( | |
| () => doPrep(` | |
| protocol Foo { | |
| thread int* operator&[](thread Foo* foo, uint, uint); | |
| } | |
| struct Bar { } | |
| thread int* operator&[](thread Bar*, uint) | |
| { | |
| int result = 1234; | |
| return &result; | |
| } | |
| `), | |
| e => e instanceof WTypeError && e.message.indexOf("Incorrect number of parameters for operator&[]") != -1); | |
| } | |
| tests.indexAnderDoesntReturnPointerInProtocol = function() | |
| { | |
| checkFail( | |
| () => doPrep(` | |
| protocol Foo { | |
| int operator&[](thread Foo* foo, uint); | |
| } | |
| struct Bar { } | |
| thread int* operator&[](thread Bar*, uint) | |
| { | |
| int result = 1234; | |
| return &result; | |
| } | |
| `), | |
| e => e instanceof WTypeError && e.message.indexOf("Return type of ander is not a pointer") != -1); | |
| } | |
| tests.indexAnderDoesntTakeReferenceInProtocol = function() | |
| { | |
| checkFail( | |
| () => doPrep(` | |
| protocol Foo { | |
| thread int* operator&[](Foo foo, uint); | |
| } | |
| struct Bar { } | |
| thread int* operator&[](thread Bar*, uint) | |
| { | |
| int result = 1234; | |
| return &result; | |
| } | |
| `), | |
| e => e instanceof WTypeError && e.message.indexOf("Parameter to ander is not a reference") != -1); | |
| } | |
| tests.indexAnderWithArrayRefInProtocol = function() | |
| { | |
| let program = doPrep(` | |
| protocol Foo { | |
| thread int* operator&[](thread Foo[] array, double index); | |
| } | |
| int bar<T:Foo>(thread T[] x) | |
| { | |
| return x[1.5]; | |
| } | |
| struct Bar { } | |
| thread int* operator&[](thread Bar[], double) | |
| { | |
| int result = 1234; | |
| return &result; | |
| } | |
| int foo() | |
| { | |
| Bar x; | |
| return bar(@x); | |
| } | |
| `); | |
| checkInt(program, callFunction(program, "foo", [], []), 1234); | |
| } | |
| tests.andReturnedArrayRef = function() | |
| { | |
| let program = doPrep(` | |
| thread int[] getArray() | |
| { | |
| int[10] x; | |
| x[5] = 354; | |
| return @x; | |
| } | |
| int foo() | |
| { | |
| thread int* ptr = &getArray()[5]; | |
| return *ptr; | |
| } | |
| `); | |
| checkInt(program, callFunction(program, "foo", [], []), 354); | |
| } | |
| okToTest = true; | |
| function doTest() | |
| { | |
| if (!okToTest) | |
| throw new Error("Test setup is incomplete."); | |
| let names = []; | |
| for (let s in tests) | |
| names.push(s); | |
| names.sort(); | |
| for (let s of names) { | |
| tests[s](); | |
| } | |
| } | |
| class Benchmark { | |
| buildStdlib() { | |
| prepare(); | |
| } | |
| run() { | |
| doTest() | |
| } | |
| } |