Title: [222038] trunk/Tools
Revision
222038
Author
fpi...@apple.com
Date
2017-09-14 11:33:26 -0700 (Thu, 14 Sep 2017)

Log Message

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):

Modified Paths

Added Paths

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);
_______________________________________________
webkit-changes mailing list
webkit-changes@lists.webkit.org
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to