Diff
Modified: trunk/Tools/ChangeLog (222037 => 222038)
--- trunk/Tools/ChangeLog 2017-09-14 18:20:09 UTC (rev 222037)
+++ trunk/Tools/ChangeLog 2017-09-14 18:33:26 UTC (rev 222038)
@@ -1,3 +1,152 @@
+2017-09-14 Filip Pizlo <fpi...@apple.com>
+
+ WSL IntLiteralType should become int32 if unified with a type variable
+ https://bugs.webkit.org/show_bug.cgi?id=176707
+
+ Reviewed by Myles Maxfield.
+
+ This makes it so that this works:
+
+ T foo<T>(T x) { return x; }
+ foo(42); // T becomes int32
+
+ Previously, it did not work because IntLiteralType did not recognize TypeVariable as a number. Also,
+ TypeVariable would try to evaluate protocol inheritance of IntLiteralType, which would not go well. One
+ of the tests that this patch adds didn't just fail; it gave such an absurd 7-line type error that I felt
+ like I was using SML.
+
+ This fixes the problem by introducing what I think is a super deterministic way of handling literals and
+ type variables:
+
+ Before verifying a unification context, we now give all literals a chance to perform an extra
+ unification step. This is a two-phase process. This ensures that the unification performed by one
+ literal does not throw off the logic of some other literal. For example, if we do:
+
+ void foo<T>(T, T) { }
+ foo(42, 42u);
+
+ Then we want to always fail to compile, rather than sometimes succeeding. So, we first ask each literal
+ if it thinks that it needs to do extra unification. Both of the literals will report that they want to
+ in this case, because they will notice that they got unified with either at type variable or a literal,
+ which isn't specific enough. Then after they all register to do extra unification, they will both try to
+ unify with their preferred types (int32 for 42, uint32 for 42u). The first one will succeed, and the
+ second will give an error.
+
+ Without the special two-phase arrangement, it was possible to either get a type error or not depending
+ on the order - for example foo(42, 42u) might fail while foo(42u, 42) succeeds. It was definitely not
+ decidable, at least not unless you mandate the unification order as part of the type system spec. I
+ think that would have been nuts.
+
+ Both IntLiteral and UintLiteral are now "flexible"; the uint one will reject non-int or signed int
+ types and will prefer uint, but otherwise it's the same logic. This means that this will be valid:
+
+ uint8 x = 5u;
+
+ But this is still wrong:
+
+ int x = 5u;
+
+ To make this easy, I turned IntLiteral and UintLiteral (and IntLiteralType and UintLiteralType) into
+ factory-built generic types (see createLiteral() and createLiteralType()). Because visitors use the
+ constructor's declared name (GenericLiteral and GenericLiteralType in this case), it means that we can
+ share a ton of code between the different literals. I love that ES6 lets you do that.
+
+ * WebGPUShadingLanguageRI/All.js:
+ * WebGPUShadingLanguageRI/Checker.js:
+ * WebGPUShadingLanguageRI/CreateLiteral.js: Added.
+ (createLiteral.GenericLiteral):
+ (createLiteral.GenericLiteral.prototype.get value):
+ (createLiteral.GenericLiteral.prototype.get isConstexpr):
+ (createLiteral.GenericLiteral.prototype.toString):
+ (createLiteral):
+ * WebGPUShadingLanguageRI/CreateLiteralType.js: Added.
+ (createLiteralType.GenericLiteralType):
+ (createLiteralType.GenericLiteralType.prototype.get origin):
+ (createLiteralType.GenericLiteralType.prototype.get value):
+ (createLiteralType.GenericLiteralType.prototype.get isPrimitive):
+ (createLiteralType.GenericLiteralType.prototype.get isUnifiable):
+ (createLiteralType.GenericLiteralType.prototype.get isLiteral):
+ (createLiteralType.GenericLiteralType.prototype.typeVariableUnify):
+ (createLiteralType.GenericLiteralType.prototype.unifyImpl):
+ (createLiteralType.GenericLiteralType.prototype.prepareToVerify):
+ (createLiteralType.GenericLiteralType.prototype.verifyAsArgument):
+ (createLiteralType.GenericLiteralType.prototype.verifyAsParameter):
+ (createLiteralType.GenericLiteralType.prototype.conversionCost):
+ (createLiteralType.GenericLiteralType.prototype.commitUnification):
+ (createLiteralType.GenericLiteralType.prototype.toString):
+ (createLiteralType):
+ * WebGPUShadingLanguageRI/Evaluator.js:
+ (Evaluator.prototype.visitIntLiteral): Deleted.
+ (Evaluator.prototype.visitUintLiteral): Deleted.
+ * WebGPUShadingLanguageRI/IntLiteral.js:
+ (let.IntLiteral.createLiteral.createType):
+ (IntLiteral): Deleted.
+ (IntLiteral.prototype.get value): Deleted.
+ (IntLiteral.prototype.get isConstexpr): Deleted.
+ (IntLiteral.prototype.toString): Deleted.
+ * WebGPUShadingLanguageRI/IntLiteralType.js:
+ (IntLiteralType): Deleted.
+ (IntLiteralType.prototype.get origin): Deleted.
+ (IntLiteralType.prototype.get value): Deleted.
+ (IntLiteralType.prototype.get isPrimitive): Deleted.
+ (IntLiteralType.prototype.get isUnifiable): Deleted.
+ (IntLiteralType.prototype.typeVariableUnify): Deleted.
+ (IntLiteralType.prototype.unifyImpl): Deleted.
+ (IntLiteralType.prototype.verifyAsArgument): Deleted.
+ (IntLiteralType.prototype.verifyAsParameter): Deleted.
+ (IntLiteralType.prototype.conversionCost): Deleted.
+ (IntLiteralType.prototype.commitUnification): Deleted.
+ (IntLiteralType.prototype.toString): Deleted.
+ * WebGPUShadingLanguageRI/Intrinsics.js:
+ (Intrinsics):
+ * WebGPUShadingLanguageRI/LiteralTypeChecker.js:
+ (LiteralTypeChecker.prototype.visitIntLiteralType): Deleted.
+ * WebGPUShadingLanguageRI/Node.js:
+ (Node.prototype.prepareToVerify):
+ (Node.prototype.commitUnification):
+ (Node.prototype.get isLiteral):
+ * WebGPUShadingLanguageRI/NullType.js:
+ (NullType.prototype.get isLiteral):
+ (NullType.prototype.toString):
+ (NullType):
+ * WebGPUShadingLanguageRI/Parse.js:
+ (parseTerm):
+ * WebGPUShadingLanguageRI/Rewriter.js:
+ (Rewriter.prototype.visitGenericLiteralType):
+ (Rewriter.prototype.visitIntLiteral): Deleted.
+ (Rewriter.prototype.visitIntLiteralType): Deleted.
+ (Rewriter.prototype.visitUintLiteral): Deleted.
+ (Rewriter.prototype.visitBoolLiteral): Deleted.
+ * WebGPUShadingLanguageRI/Test.html:
+ * WebGPUShadingLanguageRI/Test.js:
+ (makeUint):
+ (checkUint):
+ (TEST_uintSimpleMath):
+ (TEST_equality):
+ (TEST_notEquality):
+ (TEST_intLiteralGeneric):
+ (TEST_intLiteralGenericWithProtocols):
+ (TEST_uintLiteralGeneric):
+ (TEST_uintLiteralGenericWithProtocols):
+ (TEST_intLiteralGenericSpecific):
+ (TEST_twoIntLiterals):
+ (TEST_unifyDifferentLiterals):
+ (makeUInt): Deleted.
+ (checkUInt): Deleted.
+ * WebGPUShadingLanguageRI/Type.js:
+ * WebGPUShadingLanguageRI/UintLiteral.js:
+ (let.UintLiteral.createLiteral.createType):
+ (UintLiteral): Deleted.
+ (UintLiteral.prototype.get value): Deleted.
+ (UintLiteral.prototype.get isConstexpr): Deleted.
+ (UintLiteral.prototype.toString): Deleted.
+ * WebGPUShadingLanguageRI/UintLiteralType.js: Added.
+ (let.UintLiteralType.createLiteralType.verifyAsArgument):
+ * WebGPUShadingLanguageRI/UnificationContext.js:
+ (UnificationContext.prototype.verify):
+ * WebGPUShadingLanguageRI/Visitor.js:
+ (Visitor.prototype.visitProtocolDecl):
+
2017-09-14 Ryan Haddad <ryanhad...@apple.com>
Unreviewed, rolling out r221868.
Modified: trunk/Tools/WebGPUShadingLanguageRI/All.js (222037 => 222038)
--- trunk/Tools/WebGPUShadingLanguageRI/All.js 2017-09-14 18:20:09 UTC (rev 222037)
+++ trunk/Tools/WebGPUShadingLanguageRI/All.js 2017-09-14 18:33:26 UTC (rev 222038)
@@ -32,6 +32,8 @@
load("VisitorBase.js");
load("Rewriter.js");
load("Visitor.js");
+load("CreateLiteral.js");
+load("CreateLiteralType.js");
load("AddressSpace.js");
load("ArrayRefType.js");
@@ -123,6 +125,7 @@
load("TypeVariable.js");
load("TypedValue.js");
load("UintLiteral.js");
+load("UintLiteralType.js");
load("UnificationContext.js");
load("UnreachableCodeChecker.js");
load("VariableDecl.js");
Modified: trunk/Tools/WebGPUShadingLanguageRI/Checker.js (222037 => 222038)
--- trunk/Tools/WebGPUShadingLanguageRI/Checker.js 2017-09-14 18:20:09 UTC (rev 222037)
+++ trunk/Tools/WebGPUShadingLanguageRI/Checker.js 2017-09-14 18:33:26 UTC (rev 222038)
@@ -197,16 +197,11 @@
throw new WTypeError(node.origin.originString, "Non-void function must return a value");
}
- visitIntLiteral(node)
+ visitGenericLiteral(node)
{
return node.type;
}
- visitUintLiteral(node)
- {
- return this._program.intrinsics.uint32;
- }
-
visitNullLiteral(node)
{
return node.type;
Added: trunk/Tools/WebGPUShadingLanguageRI/CreateLiteral.js (0 => 222038)
--- trunk/Tools/WebGPUShadingLanguageRI/CreateLiteral.js (rev 0)
+++ trunk/Tools/WebGPUShadingLanguageRI/CreateLiteral.js 2017-09-14 18:33:26 UTC (rev 222038)
@@ -0,0 +1,48 @@
+/*
+ * 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 createLiteral(config)
+{
+ class GenericLiteral extends _expression_ {
+ constructor(origin, value)
+ {
+ super(origin);
+ this._value = value;
+ this.type = config.createType.call(this, origin, value);
+ }
+
+ get value() { return this._value; }
+ get isConstexpr() { return true; }
+
+ toString()
+ {
+ return config.preferredTypeName + "Literal<" + this.value + ">";
+ }
+ }
+
+ return GenericLiteral;
+}
+
Added: trunk/Tools/WebGPUShadingLanguageRI/CreateLiteralType.js (0 => 222038)
--- trunk/Tools/WebGPUShadingLanguageRI/CreateLiteralType.js (rev 0)
+++ trunk/Tools/WebGPUShadingLanguageRI/CreateLiteralType.js 2017-09-14 18:33:26 UTC (rev 222038)
@@ -0,0 +1,101 @@
+/*
+ * 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 createLiteralType(config)
+{
+ class GenericLiteralType extends Type {
+ constructor(origin, value)
+ {
+ super();
+ this._origin = origin;
+ this._value = value;
+ this.preferredType = new TypeRef(origin, config.preferredTypeName, []);
+ }
+
+ get origin() { return this._origin; }
+ get value() { return this._value; }
+
+ get isPrimitive() { return true; }
+ get isUnifiable() { return true; }
+ get isLiteral() { return true; }
+
+ typeVariableUnify(unificationContext, other)
+ {
+ if (!(other instanceof Type))
+ return false;
+
+ return this._typeVariableUnifyImpl(unificationContext, other);
+ }
+
+ unifyImpl(unificationContext, other)
+ {
+ return this.typeVariableUnify(unificationContext, other);
+ }
+
+ prepareToVerify(unificationContext)
+ {
+ let realThis = unificationContext.find(this);
+ if (realThis instanceof TypeVariable || realThis.isLiteral) {
+ return () => {
+ if (realThis.unify(unificationContext, this.preferredType))
+ return {result: true};
+ return {result: false, reason: "Type mismatch between " + unificationContext.find(realThis) + " and " + this.preferredType};
+ };
+ }
+ }
+
+ verifyAsArgument(unificationContext)
+ {
+ return config.verifyAsArgument.call(this, unificationContext);
+ }
+
+ verifyAsParameter(unificationContext)
+ {
+ throw new Error("GenericLiteralType should never be used as a type parameter");
+ }
+
+ conversionCost(unificationContext)
+ {
+ let realThis = unificationContext.find(this);
+ if (realThis.equals(this.preferredType))
+ return 0;
+ return 1;
+ }
+
+ commitUnification(unificationContext)
+ {
+ this.type = TypeRef.wrap(unificationContext.find(this));
+ }
+
+ toString()
+ {
+ return config.preferredTypeName + "LiteralType<" + this.value + ">";
+ }
+ }
+
+ return GenericLiteralType;
+}
+
Modified: trunk/Tools/WebGPUShadingLanguageRI/Evaluator.js (222037 => 222038)
--- trunk/Tools/WebGPUShadingLanguageRI/Evaluator.js 2017-09-14 18:20:09 UTC (rev 222037)
+++ trunk/Tools/WebGPUShadingLanguageRI/Evaluator.js 2017-09-14 18:33:26 UTC (rev 222038)
@@ -126,16 +126,11 @@
return node.variable.ePtr;
}
- visitIntLiteral(node)
+ visitGenericLiteral(node)
{
return EPtr.box(node.value);
}
- visitUintLiteral(node)
- {
- return EPtr.box(node.value);
- }
-
visitNullLiteral(node)
{
return EPtr.box(null);
Modified: trunk/Tools/WebGPUShadingLanguageRI/IntLiteral.js (222037 => 222038)
--- trunk/Tools/WebGPUShadingLanguageRI/IntLiteral.js 2017-09-14 18:20:09 UTC (rev 222037)
+++ trunk/Tools/WebGPUShadingLanguageRI/IntLiteral.js 2017-09-14 18:33:26 UTC (rev 222038)
@@ -24,20 +24,12 @@
*/
"use strict";
-class IntLiteral extends _expression_ {
- constructor(origin, value)
- {
- super(origin);
- this._value = value;
- this.type = new IntLiteralType(origin, value);
- }
+let IntLiteral = createLiteral({
+ preferredTypeName: "int",
- get value() { return this._value; }
- get isConstexpr() { return true; }
-
- toString()
+ createType(origin, value)
{
- return "" + this.value;
+ return new IntLiteralType(origin, value);
}
-}
+});
Modified: trunk/Tools/WebGPUShadingLanguageRI/IntLiteralType.js (222037 => 222038)
--- trunk/Tools/WebGPUShadingLanguageRI/IntLiteralType.js 2017-09-14 18:20:09 UTC (rev 222037)
+++ trunk/Tools/WebGPUShadingLanguageRI/IntLiteralType.js 2017-09-14 18:33:26 UTC (rev 222038)
@@ -24,34 +24,9 @@
*/
"use strict";
-class IntLiteralType extends Type {
- constructor(origin, value)
- {
- super();
- this._origin = origin;
- this._value = value;
- this.intType = new TypeRef(origin, "int", []);
- }
+let IntLiteralType = createLiteralType({
+ preferredTypeName: "int",
- get origin() { return this._origin; }
- get value() { return this._value; }
-
- get isPrimitive() { return true; }
- get isUnifiable() { return true; }
-
- typeVariableUnify(unificationContext, other)
- {
- if (!(other instanceof Type))
- return false;
-
- return this._typeVariableUnifyImpl(unificationContext, other);
- }
-
- unifyImpl(unificationContext, other)
- {
- return this.typeVariableUnify(unificationContext, other);
- }
-
verifyAsArgument(unificationContext)
{
let realThis = unificationContext.find(this);
@@ -61,28 +36,4 @@
return {result: false, reason: "Int literal " + this.value + " too large to be represented by type " + realThis};
return {result: true};
}
-
- verifyAsParameter(unificationContext)
- {
- throw new Error("IntLiteralType should never be used as a type parameter");
- }
-
- conversionCost(unificationContext)
- {
- let realThis = unificationContext.find(this);
- if (realThis.equals(this.intType))
- return 0;
- return 1;
- }
-
- commitUnification(unificationContext)
- {
- this.type = TypeRef.wrap(unificationContext.find(this));
- }
-
- toString()
- {
- return "intLiteralType<" + this.value + ">";
- }
-}
-
+});
Modified: trunk/Tools/WebGPUShadingLanguageRI/Intrinsics.js (222037 => 222038)
--- trunk/Tools/WebGPUShadingLanguageRI/Intrinsics.js 2017-09-14 18:20:09 UTC (rev 222037)
+++ trunk/Tools/WebGPUShadingLanguageRI/Intrinsics.js 2017-09-14 18:33:26 UTC (rev 222038)
@@ -66,6 +66,7 @@
this.int32 = type;
type.isInt = true;
type.isNumber = true;
+ type.isSigned = true;
type.canRepresent = value => isBitwiseEquivalent(value | 0, value);
type.size = 1;
type.populateDefaultValue = (buffer, offset) => buffer.set(offset, 0);
@@ -77,6 +78,7 @@
this.uint32 = type;
type.isInt = true;
type.isNumber = true;
+ type.isSigned = false;
type.canRepresent = value => isBitwiseEquivalent(value >>> 0, value);
type.size = 1;
type.populateDefaultValue = (buffer, offset) => buffer.set(offset, 0);
Modified: trunk/Tools/WebGPUShadingLanguageRI/LiteralTypeChecker.js (222037 => 222038)
--- trunk/Tools/WebGPUShadingLanguageRI/LiteralTypeChecker.js 2017-09-14 18:20:09 UTC (rev 222037)
+++ trunk/Tools/WebGPUShadingLanguageRI/LiteralTypeChecker.js 2017-09-14 18:33:26 UTC (rev 222038)
@@ -39,7 +39,7 @@
throw new Error("Null at " + node.origin.originString + " does not have type");
}
- visitIntLiteralType(node)
+ visitGenericLiteralType(node)
{
if (!node.type)
throw new Error(node + " at " + node.origin.originString + " does not have type");
Modified: trunk/Tools/WebGPUShadingLanguageRI/Node.js (222037 => 222038)
--- trunk/Tools/WebGPUShadingLanguageRI/Node.js 2017-09-14 18:20:09 UTC (rev 222037)
+++ trunk/Tools/WebGPUShadingLanguageRI/Node.js 2017-09-14 18:33:26 UTC (rev 222038)
@@ -72,10 +72,12 @@
}
// Most type variables don't care about this.
- commitUnification(unificatoinContext) { }
+ prepareToVerify(unificationContext) { }
+ commitUnification(unificationContext) { }
get unifyNode() { return this; }
get isUnifiable() { return false; }
+ get isLiteral() { return false; }
get isNative() { return false; }
Modified: trunk/Tools/WebGPUShadingLanguageRI/NullType.js (222037 => 222038)
--- trunk/Tools/WebGPUShadingLanguageRI/NullType.js 2017-09-14 18:20:09 UTC (rev 222037)
+++ trunk/Tools/WebGPUShadingLanguageRI/NullType.js 2017-09-14 18:33:26 UTC (rev 222038)
@@ -39,6 +39,7 @@
get isPrimitive() { return true; }
get isUnifiable() { return true; }
+ get isLiteral() { return true; }
typeVariableUnify(unificationContext, other)
{
@@ -73,7 +74,7 @@
toString()
{
- return "null";
+ return "nullType";
}
}
Modified: trunk/Tools/WebGPUShadingLanguageRI/Parse.js (222037 => 222038)
--- trunk/Tools/WebGPUShadingLanguageRI/Parse.js 2017-09-14 18:20:09 UTC (rev 222037)
+++ trunk/Tools/WebGPUShadingLanguageRI/Parse.js 2017-09-14 18:33:26 UTC (rev 222038)
@@ -178,7 +178,7 @@
return new IntLiteral(token, intVersion);
}
if (token = tryConsumeKind("uintLiteral")) {
- let uintVersion = token.text >>> 0;
+ let uintVersion = token.text.substr(0, token.text.length - 1) >>> 0;
if (uintVersion + "u" !== token.text)
lexer.fail("Integer literal is not 32-bit unsigned integer");
return new UintLiteral(token, uintVersion);
Modified: trunk/Tools/WebGPUShadingLanguageRI/Rewriter.js (222037 => 222038)
--- trunk/Tools/WebGPUShadingLanguageRI/Rewriter.js 2017-09-14 18:20:09 UTC (rev 222037)
+++ trunk/Tools/WebGPUShadingLanguageRI/Rewriter.js 2017-09-14 18:33:26 UTC (rev 222038)
@@ -211,7 +211,7 @@
return new Break(node.origin);
}
- visitIntLiteral(node)
+ visitGenericLiteral(node)
{
let result = new IntLiteral(node.origin, node.value);
result.type = node.type.visit(this);
@@ -218,19 +218,14 @@
return result;
}
- visitIntLiteralType(node)
+ visitGenericLiteralType(node)
{
- let result = new IntLiteralType(node.origin, node.value);
+ let result = new node.constructor(node.origin, node.value);
result.type = node.type ? node.type.visit(this) : null;
- result.intType = node.intType.visit(this);
+ result.preferredType = node.preferredType.visit(this);
return result;
}
- visitUintLiteral(node)
- {
- return node;
- }
-
visitBoolLiteral(node)
{
return node;
Modified: trunk/Tools/WebGPUShadingLanguageRI/Test.html (222037 => 222038)
--- trunk/Tools/WebGPUShadingLanguageRI/Test.html 2017-09-14 18:20:09 UTC (rev 222037)
+++ trunk/Tools/WebGPUShadingLanguageRI/Test.html 2017-09-14 18:33:26 UTC (rev 222038)
@@ -9,6 +9,9 @@
<script src=""
<script src=""
<script src=""
+<script src=""
+<script src=""
+
<script src=""
<script src=""
<script src=""
@@ -99,6 +102,7 @@
<script src=""
<script src=""
<script src=""
+<script src=""
<script src=""
<script src=""
<script src=""
Modified: trunk/Tools/WebGPUShadingLanguageRI/Test.js (222037 => 222038)
--- trunk/Tools/WebGPUShadingLanguageRI/Test.js 2017-09-14 18:20:09 UTC (rev 222037)
+++ trunk/Tools/WebGPUShadingLanguageRI/Test.js 2017-09-14 18:33:26 UTC (rev 222038)
@@ -65,7 +65,7 @@
throw new Error("Wrong result: " + result + " (expected " + expected + ")");
}
-function makeUInt(program, value)
+function makeUint(program, value)
{
return TypedValue.box(program.intrinsics.uint32, value);
}
@@ -82,7 +82,7 @@
checkNumber(program, result, expected);
}
-function checkUInt(program, result, expected)
+function checkUint(program, result, expected)
{
if (!result.type.equals(program.intrinsics.uint32))
throw new Error("Wrong result type: " + result.type);
@@ -149,20 +149,20 @@
function TEST_uintSimpleMath() {
let program = doPrep("uint foo(uint x, uint y) { return x + y; }");
- checkUInt(program, callFunction(program, "foo", [], [makeUInt(program, 7), makeUInt(program, 5)]), 12);
+ 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);
+ 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);
+ 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);
+ checkUint(program, callFunction(program, "foo", [], [makeUint(program, 7), makeUint(program, 2)]), 3);
}
function TEST_equality() {
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);
+ 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(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);
@@ -182,8 +182,8 @@
function TEST_notEquality() {
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);
+ 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(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);
@@ -1457,14 +1457,46 @@
function TEST_intLiteralGeneric()
{
- checkFail(
- () => doPrep(`
- int foo<T>(T) { return 1; }
- int bar() { return foo(42); }
- `),
- (e) => e instanceof WTypeError);
+ let program = doPrep(`
+ int foo<T>(T x) { return 3478; }
+ int bar() { return foo(42); }
+ `);
+ checkInt(program, callFunction(program, "bar", [], []), 3478);
}
+function TEST_intLiteralGenericWithProtocols()
+{
+ let program = doPrep(`
+ protocol ConvertibleToInt {
+ operator int(ConvertibleToInt);
+ }
+ int foo<T:ConvertibleToInt>(T x) { return int(x); }
+ int bar() { return foo(42); }
+ `);
+ checkInt(program, callFunction(program, "bar", [], []), 42);
+}
+
+function TEST_uintLiteralGeneric()
+{
+ let program = doPrep(`
+ int foo<T>(T x) { return 3478; }
+ int bar() { return foo(42u); }
+ `);
+ checkInt(program, callFunction(program, "bar", [], []), 3478);
+}
+
+function TEST_uintLiteralGenericWithProtocols()
+{
+ let program = doPrep(`
+ protocol ConvertibleToUint {
+ operator uint(ConvertibleToUint);
+ }
+ uint foo<T:ConvertibleToUint>(T x) { return uint(x); }
+ uint bar() { return foo(42u); }
+ `);
+ checkUint(program, callFunction(program, "bar", [], []), 42);
+}
+
function TEST_intLiteralGenericSpecific()
{
let program = doPrep(`
@@ -2059,6 +2091,89 @@
checkInt(program, callFunction(program, "thingy", [], [makeInt(program, 642)]), 642 + 743 + 91 + 39);
}
+function TEST_twoIntLiterals()
+{
+ let program = doPrep(`
+ bool foo()
+ {
+ return 42 == 42;
+ }
+ `);
+ checkBool(program, callFunction(program, "foo", [], []), true);
+}
+
+function TEST_unifyDifferentLiterals()
+{
+ checkFail(
+ () => doPrep(`
+ void bar<T>(T, T)
+ {
+ }
+ void foo()
+ {
+ bar(42, 42u);
+ }
+ `),
+ (e) => e instanceof WTypeError);
+}
+
+function TEST_unifyDifferentLiteralsBackwards()
+{
+ checkFail(
+ () => doPrep(`
+ void bar<T>(T, T)
+ {
+ }
+ void foo()
+ {
+ bar(42u, 42);
+ }
+ `),
+ (e) => e instanceof WTypeError);
+}
+
+function TEST_unifyVeryDifferentLiterals()
+{
+ checkFail(
+ () => doPrep(`
+ void bar<T>(T, T)
+ {
+ }
+ void foo()
+ {
+ bar(42, null);
+ }
+ `),
+ (e) => e instanceof WTypeError);
+}
+
+function TEST_unifyVeryDifferentLiteralsBackwards()
+{
+ checkFail(
+ () => doPrep(`
+ void bar<T>(T, T)
+ {
+ }
+ void foo()
+ {
+ bar(null, 42);
+ }
+ `),
+ (e) => e instanceof WTypeError);
+}
+
+function TEST_assignUintToInt()
+{
+ checkFail(
+ () => doPrep(`
+ void foo()
+ {
+ int x = 42u;
+ }
+ `),
+ (e) => e instanceof WTypeError && e.message.indexOf("Type mismatch in variable initialization") != -1);
+}
+
let filter = /.*/; // run everything by default
if (this["arguments"]) {
for (let i = 0; i < arguments.length; i++) {
Modified: trunk/Tools/WebGPUShadingLanguageRI/UintLiteral.js (222037 => 222038)
--- trunk/Tools/WebGPUShadingLanguageRI/UintLiteral.js 2017-09-14 18:20:09 UTC (rev 222037)
+++ trunk/Tools/WebGPUShadingLanguageRI/UintLiteral.js 2017-09-14 18:33:26 UTC (rev 222038)
@@ -24,19 +24,12 @@
*/
"use strict";
-class UintLiteral extends _expression_ {
- constructor(origin, value)
- {
- super(origin);
- this._value = value;
- }
+let UintLiteral = createLiteral({
+ preferredTypeName: "uint",
- get value() { return this._value; }
- get isConstexpr() { return true; }
-
- toString()
+ createType(origin, value)
{
- return "" + this._value + "u";
+ return new UintLiteralType(origin, value);
}
-}
+});
Added: trunk/Tools/WebGPUShadingLanguageRI/UintLiteralType.js (0 => 222038)
--- trunk/Tools/WebGPUShadingLanguageRI/UintLiteralType.js (rev 0)
+++ trunk/Tools/WebGPUShadingLanguageRI/UintLiteralType.js 2017-09-14 18:33:26 UTC (rev 222038)
@@ -0,0 +1,41 @@
+/*
+ * 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";
+
+let UintLiteralType = createLiteralType({
+ preferredTypeName: "uint",
+
+ verifyAsArgument(unificationContext)
+ {
+ let realThis = unificationContext.find(this);
+ if (!realThis.isInt)
+ return {result: false, reason: "Cannot use uint literal with non-integer type " + realThis};
+ if (realThis.isSigned)
+ return {result: false, reason: "Cannot use uint literal with signed type " + realThis};
+ if (!realThis.canRepresent(this.value))
+ return {result: false, reason: "Uint literal " + this.value + " too large to be represented by type " + realThis};
+ return {result: true};
+ }
+});
Modified: trunk/Tools/WebGPUShadingLanguageRI/UnificationContext.js (222037 => 222038)
--- trunk/Tools/WebGPUShadingLanguageRI/UnificationContext.js 2017-09-14 18:20:09 UTC (rev 222037)
+++ trunk/Tools/WebGPUShadingLanguageRI/UnificationContext.js 2017-09-14 18:33:26 UTC (rev 222038)
@@ -91,6 +91,19 @@
verify()
{
+ // We do a two-phase pre-verification. This gives literals a chance to select a more specific type.
+ let preparations = [];
+ for (let node of this.nodes) {
+ let preparation = node.prepareToVerify(this);
+ if (preparation)
+ preparations.push(preparation);
+ }
+ for (let preparation of preparations) {
+ let result = preparation();
+ if (!result.result)
+ return result;
+ }
+
for (let typeParameter of this._typeParameters) {
let result = typeParameter.verifyAsParameter(this);
if (!result.result)
@@ -102,12 +115,14 @@
let result = typeArgument.verifyAsArgument(this);
if (!result.result)
return result;
+ if (typeArgument.isLiteral)
+ continue;
argumentSet.add(this.find(typeArgument));
numTypeVariableArguments++;
}
if (argumentSet.size == numTypeVariableArguments)
return {result: true};
- return {result: false, reason: "Type variables used as arguments got unified"};
+ return {result: false, reason: "Type variables used as arguments got unified with each other"};
}
get conversionCost()
Modified: trunk/Tools/WebGPUShadingLanguageRI/Visitor.js (222037 => 222038)
--- trunk/Tools/WebGPUShadingLanguageRI/Visitor.js 2017-09-14 18:20:09 UTC (rev 222037)
+++ trunk/Tools/WebGPUShadingLanguageRI/Visitor.js 2017-09-14 18:33:26 UTC (rev 222038)
@@ -255,22 +255,18 @@
{
}
- visitIntLiteral(node)
+ visitGenericLiteral(node)
{
node.type.visit(this);
}
- visitIntLiteralType(node)
+ visitGenericLiteralType(node)
{
if (node.type)
node.type.visit(this);
- node.intType.visit(this);
+ node.preferredType.visit(this);
}
- visitUintLiteral(node)
- {
- }
-
visitNullLiteral(node)
{
node.type.visit(this);