Title: [221837] trunk/Tools
Revision
221837
Author
fpi...@apple.com
Date
2017-09-10 14:49:13 -0700 (Sun, 10 Sep 2017)

Log Message

WSL overload resolution should not be cascading
https://bugs.webkit.org/show_bug.cgi?id=176333

Reviewed by Myles Maxfield.
        
This removes the cascading nature of overload resolution that WSL used to have, and replaces it with
something C++-like. If there are multiple overload candidates that match the callsite, then we resolve
them against each other. Anytime a function cannot be resolved onto another function, it is removed,
since this means that this function is in some way more general than the other one, and we are just
looking for the most specific function.
        
If this process ends with only one function being selected, then we succeed, else we fail.
        
Also changed the syntax for defining generic casts to:
        
operator<T> Thingy<T>(things)
        
Also fixed parsing of cast expressions. It's now possible to say a cast _expression_ in WSL.
        
The removal of cascading causes some problems. For example, the following two operators in our standard
library are ambiguous for bool(bool):
        
operator<T> T(T)
operator<T:Equatable> bool(T)
        
I think that what we really want is to say that the following operators are restricted to the standard
library:
        
operator<T> T()
operator<T> T(T)
        
It should not be possible to ever overload these.
        
These changes are mostly tested by existing tests and the changes in the standard library, which has to
be parsed for every test.

* WebGPUShadingLanguageRI/All.js:
* WebGPUShadingLanguageRI/ArrayRefType.js:
(ArrayRefType.prototype.unifyImpl):
* WebGPUShadingLanguageRI/CallExpression.js:
(CallExpression):
(CallExpression.prototype.get isCast):
(CallExpression.prototype.get returnType):
(CallExpression.prototype.resolve):
(CallExpression.prototype.becomeCast):
(CallExpression.prototype.setCastData):
(CallExpression.prototype.toString):
* WebGPUShadingLanguageRI/Checker.js:
* WebGPUShadingLanguageRI/Evaluator.js:
(Evaluator.prototype.visitLogicalNot):
* WebGPUShadingLanguageRI/Func.js:
(Func.prototype.get returnTypeForOverloadResolution):
* WebGPUShadingLanguageRI/FuncDef.js:
(FuncDef):
* WebGPUShadingLanguageRI/FuncInstantiator.js:
(FuncInstantiator.prototype.getUnique.FindTypeVariable.prototype.visitTypeVariable):
(FuncInstantiator.prototype.getUnique.FindTypeVariable):
(FuncInstantiator.prototype.getUnique.InstantiationSubstitution.prototype.visitCallExpression):
(FuncInstantiator.prototype.getUnique.InstantiationSubstitution):
* WebGPUShadingLanguageRI/FunctionLikeBlock.js:
(FunctionLikeBlock.prototype.toString):
(FunctionLikeBlock):
* WebGPUShadingLanguageRI/InferTypesForCall.js: Added.
(inferTypesForCall):
* WebGPUShadingLanguageRI/Inline.js:
(resolveInlinedFunction):
* WebGPUShadingLanguageRI/Lexer.js:
(Lexer):
(Lexer.prototype.next):
* WebGPUShadingLanguageRI/NameContext.js:
(NameContext):
(NameContext.prototype.mapFor):
(NameContext.prototype.add):
(NameContext.prototype.get let):
(NameContext.prototype.Symbol.iterator):
(NameContext.get currentStatement): Deleted.
* WebGPUShadingLanguageRI/NameResolver.js:
(NameResolver.prototype.visitProgram):
(NameResolver.prototype.determinePossibleOverloads):
(NameResolver.prototype.visitProtocolFuncDecl):
(NameResolver.prototype.visitCallExpression):
(NameResolver):
* WebGPUShadingLanguageRI/NativeFunc.js:
(NativeFunc):
* WebGPUShadingLanguageRI/Node.js:
(Node.prototype.visit):
* WebGPUShadingLanguageRI/Parse.js:
(parsePossiblePrefix):
(parseFuncDecl):
(parseNativeFunc):
(parseNative):
(parsePreferredFuncDef):
(parse):
* WebGPUShadingLanguageRI/Prepare.js:
(prepare):
* WebGPUShadingLanguageRI/Program.js:
(Program.prototype.resolveFuncOverload): Deleted.
(Program.prototype.get nameContext): Deleted.
* WebGPUShadingLanguageRI/ProtocolDecl.js:
(ProtocolDecl.prototype.inherits):
(ProtocolDecl.prototype.hasHeir):
* WebGPUShadingLanguageRI/PtrType.js:
(PtrType.prototype.unifyImpl):
* WebGPUShadingLanguageRI/ResolveOverloadImpl.js:
(resolveOverloadImpl):
* WebGPUShadingLanguageRI/Rewriter.js:
(Rewriter.prototype.visitProtocolFuncDecl):
(Rewriter.prototype.processDerivedCallData):
(Rewriter.prototype.visitCastExpression): Deleted.
* WebGPUShadingLanguageRI/StandardLibrary.js: Added.
(preferred.operator.T.T):
(operator.T.Equatable.bool):
* WebGPUShadingLanguageRI/StandardLibraryEpilogue.js: Removed.
* WebGPUShadingLanguageRI/StandardLibraryPrologue.js: Removed.
* WebGPUShadingLanguageRI/Test.html:
* WebGPUShadingLanguageRI/Test.js:
(doLex):
(checkUInt):
(checkBool):
* WebGPUShadingLanguageRI/TypeRef.js:
(TypeRef.prototype.toString):
(TypeRef):
* WebGPUShadingLanguageRI/Visitor.js:
(Visitor.prototype.visitCallExpression):
(Visitor.prototype.visitCastExpression): Deleted.

Modified Paths

Added Paths

Removed Paths

Diff

Modified: trunk/Tools/ChangeLog (221836 => 221837)


--- trunk/Tools/ChangeLog	2017-09-10 19:00:03 UTC (rev 221836)
+++ trunk/Tools/ChangeLog	2017-09-10 21:49:13 UTC (rev 221837)
@@ -1,3 +1,131 @@
+2017-09-07  Filip Pizlo  <fpi...@apple.com>
+
+        WSL overload resolution should not be cascading
+        https://bugs.webkit.org/show_bug.cgi?id=176333
+
+        Reviewed by Myles Maxfield.
+        
+        This removes the cascading nature of overload resolution that WSL used to have, and replaces it with
+        something C++-like. If there are multiple overload candidates that match the callsite, then we resolve
+        them against each other. Anytime a function cannot be resolved onto another function, it is removed,
+        since this means that this function is in some way more general than the other one, and we are just
+        looking for the most specific function.
+        
+        If this process ends with only one function being selected, then we succeed, else we fail.
+        
+        Also changed the syntax for defining generic casts to:
+        
+        operator<T> Thingy<T>(things)
+        
+        Also fixed parsing of cast expressions. It's now possible to say a cast _expression_ in WSL.
+        
+        The removal of cascading causes some problems. For example, the following two operators in our standard
+        library are ambiguous for bool(bool):
+        
+        operator<T> T(T)
+        operator<T:Equatable> bool(T)
+        
+        I think that what we really want is to say that the following operators are restricted to the standard
+        library:
+        
+        operator<T> T()
+        operator<T> T(T)
+        
+        It should not be possible to ever overload these.
+        
+        These changes are mostly tested by existing tests and the changes in the standard library, which has to
+        be parsed for every test.
+
+        * WebGPUShadingLanguageRI/All.js:
+        * WebGPUShadingLanguageRI/ArrayRefType.js:
+        (ArrayRefType.prototype.unifyImpl):
+        * WebGPUShadingLanguageRI/CallExpression.js:
+        (CallExpression):
+        (CallExpression.prototype.get isCast):
+        (CallExpression.prototype.get returnType):
+        (CallExpression.prototype.resolve):
+        (CallExpression.prototype.becomeCast):
+        (CallExpression.prototype.setCastData):
+        (CallExpression.prototype.toString):
+        * WebGPUShadingLanguageRI/Checker.js:
+        * WebGPUShadingLanguageRI/Evaluator.js:
+        (Evaluator.prototype.visitLogicalNot):
+        * WebGPUShadingLanguageRI/Func.js:
+        (Func.prototype.get returnTypeForOverloadResolution):
+        * WebGPUShadingLanguageRI/FuncDef.js:
+        (FuncDef):
+        * WebGPUShadingLanguageRI/FuncInstantiator.js:
+        (FuncInstantiator.prototype.getUnique.FindTypeVariable.prototype.visitTypeVariable):
+        (FuncInstantiator.prototype.getUnique.FindTypeVariable):
+        (FuncInstantiator.prototype.getUnique.InstantiationSubstitution.prototype.visitCallExpression):
+        (FuncInstantiator.prototype.getUnique.InstantiationSubstitution):
+        * WebGPUShadingLanguageRI/FunctionLikeBlock.js:
+        (FunctionLikeBlock.prototype.toString):
+        (FunctionLikeBlock):
+        * WebGPUShadingLanguageRI/InferTypesForCall.js: Added.
+        (inferTypesForCall):
+        * WebGPUShadingLanguageRI/Inline.js:
+        (resolveInlinedFunction):
+        * WebGPUShadingLanguageRI/Lexer.js:
+        (Lexer):
+        (Lexer.prototype.next):
+        * WebGPUShadingLanguageRI/NameContext.js:
+        (NameContext):
+        (NameContext.prototype.mapFor):
+        (NameContext.prototype.add):
+        (NameContext.prototype.get let):
+        (NameContext.prototype.Symbol.iterator):
+        (NameContext.get currentStatement): Deleted.
+        * WebGPUShadingLanguageRI/NameResolver.js:
+        (NameResolver.prototype.visitProgram):
+        (NameResolver.prototype.determinePossibleOverloads):
+        (NameResolver.prototype.visitProtocolFuncDecl):
+        (NameResolver.prototype.visitCallExpression):
+        (NameResolver):
+        * WebGPUShadingLanguageRI/NativeFunc.js:
+        (NativeFunc):
+        * WebGPUShadingLanguageRI/Node.js:
+        (Node.prototype.visit):
+        * WebGPUShadingLanguageRI/Parse.js:
+        (parsePossiblePrefix):
+        (parseFuncDecl):
+        (parseNativeFunc):
+        (parseNative):
+        (parsePreferredFuncDef):
+        (parse):
+        * WebGPUShadingLanguageRI/Prepare.js:
+        (prepare):
+        * WebGPUShadingLanguageRI/Program.js:
+        (Program.prototype.resolveFuncOverload): Deleted.
+        (Program.prototype.get nameContext): Deleted.
+        * WebGPUShadingLanguageRI/ProtocolDecl.js:
+        (ProtocolDecl.prototype.inherits):
+        (ProtocolDecl.prototype.hasHeir):
+        * WebGPUShadingLanguageRI/PtrType.js:
+        (PtrType.prototype.unifyImpl):
+        * WebGPUShadingLanguageRI/ResolveOverloadImpl.js:
+        (resolveOverloadImpl):
+        * WebGPUShadingLanguageRI/Rewriter.js:
+        (Rewriter.prototype.visitProtocolFuncDecl):
+        (Rewriter.prototype.processDerivedCallData):
+        (Rewriter.prototype.visitCastExpression): Deleted.
+        * WebGPUShadingLanguageRI/StandardLibrary.js: Added.
+        (preferred.operator.T.T):
+        (operator.T.Equatable.bool):
+        * WebGPUShadingLanguageRI/StandardLibraryEpilogue.js: Removed.
+        * WebGPUShadingLanguageRI/StandardLibraryPrologue.js: Removed.
+        * WebGPUShadingLanguageRI/Test.html:
+        * WebGPUShadingLanguageRI/Test.js:
+        (doLex):
+        (checkUInt):
+        (checkBool):
+        * WebGPUShadingLanguageRI/TypeRef.js:
+        (TypeRef.prototype.toString):
+        (TypeRef):
+        * WebGPUShadingLanguageRI/Visitor.js:
+        (Visitor.prototype.visitCallExpression):
+        (Visitor.prototype.visitCastExpression): Deleted.
+
 2017-09-10  Brady Eidson  <beid...@apple.com>
 
         Try to avoid creating the default WKWebsiteDataStore until its actually needed.

Modified: trunk/Tools/WebGPUShadingLanguageRI/All.js (221836 => 221837)


--- trunk/Tools/WebGPUShadingLanguageRI/All.js	2017-09-10 19:00:03 UTC (rev 221836)
+++ trunk/Tools/WebGPUShadingLanguageRI/All.js	2017-09-10 21:49:13 UTC (rev 221837)
@@ -42,7 +42,6 @@
 load("CallAssignment.js");
 load("CallExpression.js");
 load("CallFunction.js");
-load("CastExpression.js");
 load("Check.js");
 load("CheckLiteralTypes.js");
 load("CheckRecursion.js");
@@ -66,6 +65,7 @@
 load("FuncParameter.js");
 load("FunctionLikeBlock.js");
 load("IfStatement.js");
+load("InferTypesForCall.js");
 load("Inline.js");
 load("Inliner.js");
 load("InstantiateImmediates.js");
@@ -101,8 +101,7 @@
 load("Return.js");
 load("ReturnChecker.js");
 load("ReturnException.js");
-load("StandardLibraryEpilogue.js");
-load("StandardLibraryPrologue.js");
+load("StandardLibrary.js");
 load("StructLayoutBuilder.js");
 load("StructType.js");
 load("Substitution.js");

Modified: trunk/Tools/WebGPUShadingLanguageRI/ArrayRefType.js (221836 => 221837)


--- trunk/Tools/WebGPUShadingLanguageRI/ArrayRefType.js	2017-09-10 19:00:03 UTC (rev 221836)
+++ trunk/Tools/WebGPUShadingLanguageRI/ArrayRefType.js	2017-09-10 21:49:13 UTC (rev 221837)
@@ -29,7 +29,10 @@
 class ArrayRefType extends ReferenceType {
     unifyImpl(unificationContext, other)
     {
-        if (!(other instanceof ArrayRefType)) {
+        if (other instanceof ArrayRefType) {
+            if (this.addressSpace != other.addressSpace)
+                return false;
+        } else {
             if (!(other instanceof ArrayType))
                 return false;
             if (this.addressSpace != "thread")

Modified: trunk/Tools/WebGPUShadingLanguageRI/CallExpression.js (221836 => 221837)


--- trunk/Tools/WebGPUShadingLanguageRI/CallExpression.js	2017-09-10 19:00:03 UTC (rev 221836)
+++ trunk/Tools/WebGPUShadingLanguageRI/CallExpression.js	2017-09-10 21:49:13 UTC (rev 221837)
@@ -32,16 +32,20 @@
         this._typeArguments = typeArguments;
         this._argumentList = argumentList;
         this.func = null;
+        this._isCast = false;
+        this._returnType = null;
     }
     
     get name() { return this._name; }
     get typeArguments() { return this._typeArguments; }
     get argumentList() { return this._argumentList; }
+    get isCast() { return this._isCast; }
+    get returnType() { return this._returnType; }
     
     resolve(overload)
     {
         this.func = overload.func;
-        this.actualTypeArguments = overload.typeArguments;
+        this.actualTypeArguments = overload.typeArguments.map(TypeRef.wrap);
         let result = overload.func.returnType.substituteToUnification(
             overload.func.typeParameters, overload.unificationContext);
         if (!result)
@@ -49,9 +53,27 @@
         return result;
     }
     
+    becomeCast(returnType)
+    {
+        this._returnType = new TypeRef(this.origin, this.name, this._typeArguments);
+        this._returnType.type = returnType;
+        this._name = "operator cast";
+        this._isCast = true;
+        this._typeArguments = [];
+    }
+    
+    setCastData(returnType)
+    {
+        this._returnType = returnType;
+        this._isCast = true;
+    }
+    
     toString()
     {
-        return this.name + "<" + this.typeArguments + ">(" + this.argumentList + ")";
+        return (this.isCast ? "operator " + this.returnType : this.name) +
+            "<" + this.typeArguments + ">" +
+            (this.actualTypeArguments ? "<<" + this.actualTypeArguments + ">>" : "") +
+            "(" + this.argumentList + ")";
     }
 }
 

Deleted: trunk/Tools/WebGPUShadingLanguageRI/CastExpression.js (221836 => 221837)


--- trunk/Tools/WebGPUShadingLanguageRI/CastExpression.js	2017-09-10 19:00:03 UTC (rev 221836)
+++ trunk/Tools/WebGPUShadingLanguageRI/CastExpression.js	2017-09-10 21:49:13 UTC (rev 221837)
@@ -1,46 +0,0 @@
-/*
- * 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";
-
-// This is a bit of a misnomer, as this represents casts as well as constructors.
-// Syntactically they are identical; a cast just takes one argument whereas a
-// constructor takes 0-n.
-class CastExpression extends CallExpression {
-    constructor(origin, returnType, typeArguments, argumentList)
-    {
-        super(origin, CastExpression.functionName, typeArguments, argumentList);
-        this._returnType = returnType;
-    }
-
-    static get functionName() { return "operator cast"; }
-    
-    get returnType() { return this._returnType; }
-    
-    toString()
-    {
-        return this.returnType + "<" + this.typeArguments + ">(" + this.argumentList + ")";
-    }
-}
-

Modified: trunk/Tools/WebGPUShadingLanguageRI/Checker.js (221836 => 221837)


--- trunk/Tools/WebGPUShadingLanguageRI/Checker.js	2017-09-10 19:00:03 UTC (rev 221836)
+++ trunk/Tools/WebGPUShadingLanguageRI/Checker.js	2017-09-10 21:49:13 UTC (rev 221837)
@@ -246,7 +246,7 @@
         return result;
     }
 
-    checkCastOrCallExpression(node, returnType)
+    visitCallExpression(node)
     {
         for (let typeArgument of node.typeArguments)
             typeArgument.visit(this);
@@ -257,8 +257,8 @@
             return TypeRef.wrap(newArgument);
         });
         node.argumentTypes = argumentTypes;
-        if (returnType)
-            returnType.visit(this);
+        if (node.returnType)
+            node.returnType.visit(this);
         
         let overload = null;
         let failures = [];
@@ -271,7 +271,7 @@
                 typeParameter.protocol.protocolDecl.signaturesByNameWithTypeVariable(node.name, typeParameter);
             if (!signatures)
                 continue;
-            overload = resolveOverloadImpl(signatures, node.typeArguments, argumentTypes, returnType);
+            overload = resolveOverloadImpl(signatures, node.typeArguments, argumentTypes, node.returnType);
             if (overload.func)
                 break;
             failures.push(...overload.failures);
@@ -278,11 +278,16 @@
             overload = null;
         }
         if (!overload) {
-            overload = this._program.resolveFuncOverload(
-                node.name, node.typeArguments, argumentTypes, returnType);
+            overload = resolveOverloadImpl(
+                node.possibleOverloads, node.typeArguments, argumentTypes, node.returnType);
             if (!overload.func) {
                 failures.push(...overload.failures);
-                let message = "Did not find function for call";
+                let message = "Did not find function for call with ";
+                if (node.typeArguments.length)
+                    message += "type arguments <" + node.typeArguments + "> and ";
+                message += "argument types (" + argumentTypes + ")";
+                if (node.returnType)
+                    message +=" and return type " + node.returnType;
                 if (failures.length)
                     message += ", but considered:\n" + failures.join("\n")
                 throw new WTypeError(node.origin.originString, message);
@@ -298,15 +303,5 @@
         }
         return node.resolve(overload);
     }
-
-    visitCastExpression(node)
-    {
-        return this.checkCastOrCallExpression(node, node.returnType);
-    }
-    
-    visitCallExpression(node)
-    {
-        return this.checkCastOrCallExpression(node, undefined);
-    }
 }
 

Modified: trunk/Tools/WebGPUShadingLanguageRI/Evaluator.js (221836 => 221837)


--- trunk/Tools/WebGPUShadingLanguageRI/Evaluator.js	2017-09-10 19:00:03 UTC (rev 221836)
+++ trunk/Tools/WebGPUShadingLanguageRI/Evaluator.js	2017-09-10 21:49:13 UTC (rev 221837)
@@ -148,7 +148,8 @@
 
     visitLogicalNot(node)
     {
-        return EPtr.box(!node.operand.visit(this).loadValue());
+        let result = !node.operand.visit(this).loadValue();
+        return EPtr.box(result);
     }
 
     visitIfStatement(node)

Modified: trunk/Tools/WebGPUShadingLanguageRI/Func.js (221836 => 221837)


--- trunk/Tools/WebGPUShadingLanguageRI/Func.js	2017-09-10 19:00:03 UTC (rev 221836)
+++ trunk/Tools/WebGPUShadingLanguageRI/Func.js	2017-09-10 21:49:13 UTC (rev 221837)
@@ -45,6 +45,7 @@
     get parameters() { return this._parameters; }
     get parameterTypes() { return this.parameters.map(parameter => parameter.type); }
     get isCast() { return this._isCast; }
+    get returnTypeForOverloadResolution() { return this.isCast ? this.returnType : null; }
     
     get kind() { return Func; }
     

Modified: trunk/Tools/WebGPUShadingLanguageRI/FuncDef.js (221836 => 221837)


--- trunk/Tools/WebGPUShadingLanguageRI/FuncDef.js	2017-09-10 19:00:03 UTC (rev 221836)
+++ trunk/Tools/WebGPUShadingLanguageRI/FuncDef.js	2017-09-10 21:49:13 UTC (rev 221837)
@@ -29,6 +29,7 @@
     {
         super(origin, name, returnType, typeParameters, parameters, isCast);
         this._body = body;
+        this.isRestricted = false;
     }
 
     get body() { return this._body; }

Modified: trunk/Tools/WebGPUShadingLanguageRI/FuncInstantiator.js (221836 => 221837)


--- trunk/Tools/WebGPUShadingLanguageRI/FuncInstantiator.js	2017-09-10 19:00:03 UTC (rev 221836)
+++ trunk/Tools/WebGPUShadingLanguageRI/FuncInstantiator.js	2017-09-10 21:49:13 UTC (rev 221837)
@@ -38,6 +38,14 @@
     // resolutions on the original Program.
     getUnique(func, typeArguments)
     {
+        class FindTypeVariable extends Visitor {
+            visitTypeVariable(node) {
+                throw new Error("Unexpected type variable: " + node);
+            }
+        }
+        for (let typeArgument of typeArguments)
+            typeArgument.visit(new FindTypeVariable());
+        
         let instances = this._instances.get(func);
         if (!instances)
             this._instances.set(func, instances = []);
@@ -64,7 +72,7 @@
                 // We may have to re-resolve the function call, if it was a call to a protocol
                 // signature.
                 if (result.func instanceof ProtocolFuncDecl) {
-                    let overload = thisInstantiator._program.resolveFuncOverload(result.name, result.typeArguments, result.argumentTypes);
+                    let overload = resolveOverloadImpl(result.possibleOverloads, result.typeArguments, result.argumentTypes, result.returnTypeForOverloadResolution);
                     if (!overload.func)
                         throw new Error("Could not resolve protocol signature function call during instantiation: " + result.func + (overload.failures.length ? "; tried:\n" + overload.failures.join("\n") : ""));
                     result.resolve(overload);

Modified: trunk/Tools/WebGPUShadingLanguageRI/FunctionLikeBlock.js (221836 => 221837)


--- trunk/Tools/WebGPUShadingLanguageRI/FunctionLikeBlock.js	2017-09-10 19:00:03 UTC (rev 221836)
+++ trunk/Tools/WebGPUShadingLanguageRI/FunctionLikeBlock.js	2017-09-10 21:49:13 UTC (rev 221837)
@@ -43,6 +43,6 @@
     
     toString()
     {
-        return "([&] (" + this.parameters + ") -> " + this.returnType + " { " + this.block + " }(" + this.argumentList + "))";
+        return "([&] (" + this.parameters + ") -> " + this.returnType + " { " + this.body + " }(" + this.argumentList + "))";
     }
 }

Added: trunk/Tools/WebGPUShadingLanguageRI/InferTypesForCall.js (0 => 221837)


--- trunk/Tools/WebGPUShadingLanguageRI/InferTypesForCall.js	                        (rev 0)
+++ trunk/Tools/WebGPUShadingLanguageRI/InferTypesForCall.js	2017-09-10 21:49:13 UTC (rev 221837)
@@ -0,0 +1,62 @@
+/*
+ * 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 inferTypesForCall(func, typeArguments, argumentTypes, returnType)
+{
+    if (typeArguments.length && typeArguments.length != func.typeParameters.length)
+        return {failure: new OverloadResolutionFailure(func, "Wrong number of type arguments (passed " + typeArguments.length + ", require " + func.typeParameters.length + ")")};
+    if (argumentTypes.length != func.parameters.length)
+        return {failure: new OverloadResolutionFailure(func, "Wrong number of arguments (passed " + argumentTypes.length + ", require " + func.parameters.length + ")")};
+    let unificationContext = new UnificationContext(func.typeParameters);
+    for (let i = 0; i < typeArguments.length; ++i) {
+        let argument = typeArguments[i];
+        let parameter = func.typeParameters[i];
+        if (!argument.unify(unificationContext, parameter))
+            return {failure: new OverloadResolutionFailure(func, "Type argument #" + (i + 1) + " for parameter " + parameter.name + " does not match (passed " + argument + ", require " + parameter + ")")};
+    }
+    for (let i = 0; i < argumentTypes.length; ++i) {
+        if (!argumentTypes[i])
+            throw new Error("Null argument type at i = " + i);
+        if (!argumentTypes[i].unify(unificationContext, func.parameters[i].type))
+            return {failure: new OverloadResolutionFailure(func, "Argument #" + (i + 1) + " " + (func.parameters[i].name ? "for parameter " + func.parameters[i].name : "") + " does not match (passed " + argumentTypes[i] + ", require " + func.parameters[i].type + ")")};
+    }
+    if (returnType && !returnType.unify(unificationContext, func.returnType))
+        return {failure: new OverloadResolutionFailure(func, "Return type " + func.returnType + " does not match " + returnType)};
+    if (!unificationContext.verify())
+        return {failure: new OverloadResolutionFailure(func, "Violates type variable constraints")};
+    let shouldBuildTypeArguments = !typeArguments.length;
+    if (shouldBuildTypeArguments)
+        typeArguments = [];
+    for (let typeParameter of func.typeParameters) {
+        let typeArgument = unificationContext.find(typeParameter);
+        if (typeArgument == typeParameter)
+            return {failure: new OverloadResolutionFailure(func, "Type parameter " + typeParameter + " did not get assigned a type")};
+        if (shouldBuildTypeArguments)
+            typeArguments.push(typeArgument);
+    }
+    return {func, unificationContext, typeArguments};
+}
+

Modified: trunk/Tools/WebGPUShadingLanguageRI/Inline.js (221836 => 221837)


--- trunk/Tools/WebGPUShadingLanguageRI/Inline.js	2017-09-10 19:00:03 UTC (rev 221836)
+++ trunk/Tools/WebGPUShadingLanguageRI/Inline.js	2017-09-10 21:49:13 UTC (rev 221837)
@@ -57,7 +57,7 @@
 
 function resolveInlinedFunction(program, name, typeArguments, argumentTypes)
 {
-    let overload = program.resolveFuncOverload(name, typeArguments, argumentTypes);
+    let overload = program.globalNameContext.resolveFuncOverload(name, typeArguments, argumentTypes);
     if (!overload.func)
         return overload.failures;
     if (!overload.func.typeParameters)

Modified: trunk/Tools/WebGPUShadingLanguageRI/Lexer.js (221836 => 221837)


--- trunk/Tools/WebGPUShadingLanguageRI/Lexer.js	2017-09-10 19:00:03 UTC (rev 221836)
+++ trunk/Tools/WebGPUShadingLanguageRI/Lexer.js	2017-09-10 21:49:13 UTC (rev 221837)
@@ -25,9 +25,10 @@
 "use strict";
 
 class Lexer {
-    constructor(origin, lineNumberOffset, text)
+    constructor(origin, originKind, lineNumberOffset, text)
     {
         this._origin = origin;
+        this._originKind = originKind;
         this._lineNumberOffset = lineNumberOffset;
         this._text = text;
         this._index = 0;
@@ -103,8 +104,12 @@
         
         // FIXME: Make this do Unicode.
         if (/^[^\d\W]\w*/.test(relevantText)) {
-            if (["struct", "protocol", "typedef", "if", "else", "enum", "continue", "break", "switch", "case", "default", "for", "while", "do", "return", "sizeof", "constant", "device", "threadgroup", "thread", "operator", "null", "true", "false"].includes(RegExp.lastMatch))
+            if (/^(struct|protocol|typedef|if|else|enum|continue|break|switch|case|default|for|while|do|return|constant|device|threadgroup|thread|operator|null|true|false)$/.test(RegExp.lastMatch))
                 return result("keyword");
+            
+            if (this._originKind == "native" && /^(native|restricted)$/.test(RegExp.lastMatch))
+                return result("keyword");
+            
             return result("identifier");
         }
 

Modified: trunk/Tools/WebGPUShadingLanguageRI/NameContext.js (221836 => 221837)


--- trunk/Tools/WebGPUShadingLanguageRI/NameContext.js	2017-09-10 19:00:03 UTC (rev 221836)
+++ trunk/Tools/WebGPUShadingLanguageRI/NameContext.js	2017-09-10 21:49:13 UTC (rev 221837)
@@ -34,7 +34,6 @@
 class NameContext {
     constructor(delegate)
     {
-        this._funcMap = new Map();
         this._map = new Map();
         this._set = new Set();
         this._defined = null;
@@ -51,9 +50,8 @@
         case Value:
         case Type:
         case Protocol:
+        case Func:
             return this._map;
-        case Func:
-            return this._funcMap;
         default:
             throw new Error("Bad kind: " + kind);
         }
@@ -72,9 +70,14 @@
         
         if (thing.kind == Func) {
             this._set.add(thing);
-            let array = this._funcMap.get(thing.name);
-            if (!array)
-                this._funcMap.set(thing.name, array = []);
+            let array = this._map.get(thing.name);
+            if (!array) {
+                array = [];
+                array.kind = Func;
+                this._map.set(thing.name, array);
+            }
+            if (array.kind != Func)
+                throw new WTypeError(thing.origin.originString, "Cannot reuse type name for function: " + thing.name);
             array.push(thing);
             return;
         }
@@ -94,6 +97,15 @@
         return result;
     }
     
+    resolveFuncOverload(name, typeArguments, argumentTypes, returnType)
+    {
+        let functions = this.get(Func, name);
+        if (!functions)
+            return {failures: []};
+        
+        return resolveOverloadImpl(functions, typeArguments, argumentTypes, returnType);
+    }
+    
     get currentStatement()
     {
         if (this._currentStatement)
@@ -165,11 +177,13 @@
     
     *[Symbol.iterator]()
     {
-        for (let value of this._map.values())
+        for (let value of this._map.values()) {
+            if (value instanceof Array) {
+                for (let func of value)
+                    yield func;
+                continue;
+            }
             yield value;
-        for (let funcs of this._funcMap.values()) {
-            for (let func of funcs)
-                yield func;
         }
     }
 }

Modified: trunk/Tools/WebGPUShadingLanguageRI/NameResolver.js (221836 => 221837)


--- trunk/Tools/WebGPUShadingLanguageRI/NameResolver.js	2017-09-10 19:00:03 UTC (rev 221836)
+++ trunk/Tools/WebGPUShadingLanguageRI/NameResolver.js	2017-09-10 21:49:13 UTC (rev 221837)
@@ -50,6 +50,7 @@
         let checker = new NameResolver(nameContext);
         for (let statement of node.topLevelStatements)
             nameContext.doStatement(statement, () => statement.visit(checker));
+        node.globalNameContext = nameContext;
     }
     
     _visitTypeParametersAndBuildNameContext(node)
@@ -117,6 +118,15 @@
         node.protocolDecl = result;
     }
     
+    visitProtocolFuncDecl(node)
+    {
+        this.visitFunc(node);
+        let funcs = this._nameContext.get(Func, node.name);
+        if (!funcs)
+            throw new WTypeError(node.origin.originString, "Cannot find any functions named " + node.na,e);
+        node.possibleOverloads = funcs;
+    }
+    
     visitTypeDef(node)
     {
         let nameContext = new NameContext(this._nameContext);
@@ -218,6 +228,20 @@
     visitCallExpression(node)
     {
         this._resolveTypeArguments(node.typeArguments);
+        
+        let funcs = this._nameContext.get(Func, node.name);
+        if (funcs)
+            node.possibleOverloads = funcs;
+        else {
+            let type = this._nameContext.get(Type, node.name);
+            if (!type)
+                throw new WTypeError(node.origin.originString, "Cannot find any function or type named " + node.name);
+            node.becomeCast(type);
+            node.possibleOverloads = this._nameContext.get(Func, "operator cast");
+            if (!node.possibleOverloads)
+                throw new WTypeError(node.origin.originString, "Cannot find any operator cast implementations in cast to " + type);
+        }
+        
         super.visitCallExpression(node);
     }
 }

Modified: trunk/Tools/WebGPUShadingLanguageRI/NativeFunc.js (221836 => 221837)


--- trunk/Tools/WebGPUShadingLanguageRI/NativeFunc.js	2017-09-10 19:00:03 UTC (rev 221836)
+++ trunk/Tools/WebGPUShadingLanguageRI/NativeFunc.js	2017-09-10 21:49:13 UTC (rev 221837)
@@ -28,6 +28,7 @@
     constructor(origin, name, returnType, typeParameters, parameters, isCast)
     {
         super(origin, name, returnType, typeParameters, parameters, isCast);
+        this.isRestricted = false;
     }
     
     get isNative() { return true; }

Modified: trunk/Tools/WebGPUShadingLanguageRI/Node.js (221836 => 221837)


--- trunk/Tools/WebGPUShadingLanguageRI/Node.js	2017-09-10 19:00:03 UTC (rev 221836)
+++ trunk/Tools/WebGPUShadingLanguageRI/Node.js	2017-09-10 21:49:13 UTC (rev 221837)
@@ -27,10 +27,6 @@
 class Node {
     visit(visitor)
     {
-        let memoTable = visitor._memoTable;
-        if (memoTable.has(this))
-            return memoTable.get(this);
-        
         let visitFunc = visitor["visit" + this.constructor.name];
         if (!visitFunc)
             throw new Error("No visit function for " + this.constructor.name + " in " + visitor.constructor.name);
@@ -37,7 +33,6 @@
         let returnValue = visitFunc.call(visitor, this);
         if ("returnValue" in visitor)
             returnValue = visitor.returnValue;
-        memoTable.set(this, returnValue);
         return returnValue;
     }
     

Modified: trunk/Tools/WebGPUShadingLanguageRI/Parse.js (221836 => 221837)


--- trunk/Tools/WebGPUShadingLanguageRI/Parse.js	2017-09-10 19:00:03 UTC (rev 221836)
+++ trunk/Tools/WebGPUShadingLanguageRI/Parse.js	2017-09-10 21:49:13 UTC (rev 221837)
@@ -24,9 +24,9 @@
  */
 "use strict";
 
-function parse(program, origin, lineNumberOffset, text)
+function parse(program, origin, originKind, lineNumberOffset, text)
 {
-    let lexer = new Lexer(origin, lineNumberOffset, text);
+    let lexer = new Lexer(origin, originKind, lineNumberOffset, text);
     
     // The hardest part of dealing with C-like languages is parsing variable declaration statements.
     // Let's consider if this happens in WSL. Here are the valid statements in WSL that being with an
@@ -382,7 +382,7 @@
             return new MakeArrayRefExpression(token, parsePossiblePrefix());
         if (token = tryConsume("!")) {
             let remainder = parsePossiblePrefix();
-            return new LogicalNot(token, new CastExpression(remainder.origin, new TypeRef(remainder.origin, "bool", []), [], [remainder]));
+            return new LogicalNot(token, new CallExpression(remainder.origin, "bool", [], [remainder]));
         }
         return parsePossibleSuffix();
     }
@@ -546,7 +546,7 @@
         let elseBody;
         if (tryConsume("else"))
             elseBody = parseStatement();
-        return new IfStatement(origin, new CastExpression(conditional.origin, new TypeRef(conditional.origin, "bool", []), [], [conditional]), body, elseBody);
+        return new IfStatement(origin, new CallExpression(conditional.origin, "bool", [], [conditional]), body, elseBody);
     }
     
     function parseVariableDecls()
@@ -644,20 +644,22 @@
         let origin;
         let returnType;
         let name;
+        let typeParameters;
         let isCast;
         let operatorToken = tryConsume("operator");
         if (operatorToken) {
             origin = operatorToken;
+            typeParameters = parseTypeParameters();
             returnType = parseType();
-            name = CastExpression.functionName;
+            name = "operator cast";
             isCast = true;
         } else {
             returnType = parseType();
             origin = returnType.origin;
             name = parseFuncName();
+            typeParameters = parseTypeParameters();
             isCast = false;
         }
-        let typeParameters = parseTypeParameters();
         let parameters = parseParameters();
         return new Func(origin, name, returnType, typeParameters, parameters, isCast);
     }
@@ -710,6 +712,13 @@
         return result;
     }
     
+    function parseNativeFunc()
+    {
+        let func = parseFuncDecl();
+        consume(";");
+        return new NativeFunc(func.origin, func.name, func.returnType, func.typeParameters, func.parameters, func.isCast);
+    }
+    
     function parseNative()
     {
         let origin = consume("native");
@@ -726,11 +735,21 @@
             consume(";");
             return new NativeType(origin, name.text, isType == "primitive", parameters);
         }
-        let func = parseFuncDecl();
-        consume(";");
-        return new NativeFunc(func.origin, func.name, func.returnType, func.typeParameters, func.parameters, func.isCast);
+        return parseNativeFunc();
     }
     
+    function parseRestrictedFuncDef()
+    {
+        consume("restricted");
+        let result;
+        if (tryConsume("native"))
+            result = parseNativeFunc();
+        else
+            result = parseFuncDef();
+        result.isRestricted = true;
+        return result;
+    }
+    
     for (;;) {
         let token = lexer.peek();
         if (!token)
@@ -739,8 +758,10 @@
             lexer.next();
         else if (token.text == "typedef")
             program.add(parseTypeDef());
-        else if (token.text == "native")
+        else if (originKind == "native" && token.text == "native")
             program.add(parseNative());
+        else if (originKind == "native" && token.text == "restricted")
+            program.add(parseRestrictedFuncDef());
         else if (token.text == "struct")
             program.add(parseStructType());
         else if (token.text == "enum")

Modified: trunk/Tools/WebGPUShadingLanguageRI/Prepare.js (221836 => 221837)


--- trunk/Tools/WebGPUShadingLanguageRI/Prepare.js	2017-09-10 19:00:03 UTC (rev 221836)
+++ trunk/Tools/WebGPUShadingLanguageRI/Prepare.js	2017-09-10 21:49:13 UTC (rev 221837)
@@ -27,9 +27,8 @@
 function prepare(origin, lineNumberOffset, text)
 {
     let program = new Program();
-    parse(program, "/internal/stdlib/prologue", 28, standardLibraryPrologue);
-    parse(program, origin, lineNumberOffset, text);
-    parse(program, "/internal/stdlib/epilogue", 28, standardLibraryEpilogue);
+    parse(program, "/internal/stdlib", "native", 27, standardLibrary);
+    parse(program, origin, "user", lineNumberOffset, text);
     resolveNames(program);
     resolveTypeDefs(program);
     check(program);

Modified: trunk/Tools/WebGPUShadingLanguageRI/Program.js (221836 => 221837)


--- trunk/Tools/WebGPUShadingLanguageRI/Program.js	2017-09-10 19:00:03 UTC (rev 221836)
+++ trunk/Tools/WebGPUShadingLanguageRI/Program.js	2017-09-10 21:49:13 UTC (rev 221837)
@@ -58,23 +58,6 @@
         this._topLevelStatements.push(statement);
     }
     
-    resolveFuncOverload(name, typeArguments, argumentTypes, returnType)
-    {
-        let functions = this.functions.get(name);
-        if (!functions)
-            return {failures: []};
-        
-        return resolveOverloadImpl(functions, typeArguments, argumentTypes, returnType);
-    }
-    
-    get nameContext()
-    {
-        let result = new NameContext();
-        for (let statement of this.topLevelStatements)
-            result.add(statement);
-        return result;
-    }
-    
     toString()
     {
         if (!this._topLevelStatements.length)

Modified: trunk/Tools/WebGPUShadingLanguageRI/ProtocolDecl.js (221836 => 221837)


--- trunk/Tools/WebGPUShadingLanguageRI/ProtocolDecl.js	2017-09-10 19:00:03 UTC (rev 221836)
+++ trunk/Tools/WebGPUShadingLanguageRI/ProtocolDecl.js	2017-09-10 21:49:13 UTC (rev 221837)
@@ -72,7 +72,7 @@
             let signatures = this.signaturesByName(otherSignature.name);
             if (!signatures)
                 return false;
-            let overload = resolveOverloadImpl(signatures, [], otherSignature.parameterTypes);
+            let overload = resolveOverloadImpl(signatures, [], otherSignature.parameterTypes, otherSignature.returnTypeForOverloadResolution);
             if (!overload.func)
                 return false;
             let substitutedReturnType =
@@ -90,7 +90,7 @@
         let signatures = this.signatures;
         for (let signature of signatures) {
             signature = signature.visit(substitution);
-            let overload = this.program.resolveFuncOverload(signature.name, signature.typeParameters, signature.parameterTypes);
+            let overload = resolveOverloadImpl(signature.possibleOverloads, signature.typeParameters, signature.parameterTypes, signature.returnTyupeForOverloadResolution);
             if (!overload.func)
                 return false;
             

Modified: trunk/Tools/WebGPUShadingLanguageRI/PtrType.js (221836 => 221837)


--- trunk/Tools/WebGPUShadingLanguageRI/PtrType.js	2017-09-10 19:00:03 UTC (rev 221836)
+++ trunk/Tools/WebGPUShadingLanguageRI/PtrType.js	2017-09-10 21:49:13 UTC (rev 221837)
@@ -31,6 +31,8 @@
     {
         if (!(other instanceof PtrType))
             return false;
+        if (this.addressSpace != other.addressSpace)
+            return false;
         return this.elementType.unify(unificationContext, other.elementType);
     }
     

Modified: trunk/Tools/WebGPUShadingLanguageRI/ResolveOverloadImpl.js (221836 => 221837)


--- trunk/Tools/WebGPUShadingLanguageRI/ResolveOverloadImpl.js	2017-09-10 19:00:03 UTC (rev 221836)
+++ trunk/Tools/WebGPUShadingLanguageRI/ResolveOverloadImpl.js	2017-09-10 21:49:13 UTC (rev 221837)
@@ -27,66 +27,69 @@
 function resolveOverloadImpl(functions, typeArguments, argumentTypes, returnType)
 {
     let failures = [];
+    let successes = [];
     for (let func of functions) {
-        if (typeArguments.length && typeArguments.length != func.typeParameters.length) {
-            failures.push(new OverloadResolutionFailure(func, "Wrong number of type arguments (passed " + typeArguments.length + ", require " + func.typeParameters.length + ")"));
-            continue;
+        let overload = inferTypesForCall(func, typeArguments, argumentTypes, returnType);
+        if (overload.failure)
+            failures.push(overload.failure);
+        else
+            successes.push(overload);
+    }
+    
+    if (!successes.length)
+        return {failures: failures};
+    
+    // If any of the signatures are restricted then we consider those first. This is an escape mechanism for
+    // built-in things.
+    // FIXME: It should be an error to declare a function that is at least as specific as a restricted function.
+    // https://bugs.webkit.org/show_bug.cgi?id=176580
+    let hasRestricted = false;
+    for (let overload of successes) {
+        if (overload.func.isRestricted) {
+            hasRestricted = true;
+            break;
         }
-        if (argumentTypes.length != func.parameters.length) {
-            failures.push(new OverloadResolutionFailure(func, "Wrong number of arguments (passed " + argumentTypes.length + ", require " + func.parameters.length + ")"));
-            continue;
-        }
-        let unificationContext = new UnificationContext(func.typeParameters);
+    }
+    
+    if (hasRestricted)
+        successes = successes.filter(overload => overload.func.isRestricted);
+    
+    // We are only interested in functions that are at least as specific as all of the others. This means
+    // that they can be "turned around" and applied onto all of the other functions in the list.
+    let prunedSuccesses = [];
+    for (let i = 0; i < successes.length; ++i) {
         let ok = true;
-        for (let i = 0; i < typeArguments.length; ++i) {
-            let argument = typeArguments[i];
-            let parameter = func.typeParameters[i];
-            if (!argument.unify(unificationContext, parameter)) {
-                failures.push(new OverloadResolutionFailure(func, "Type argument #" + (i + 1) + " for parameter " + parameter.name + " does not match (passed " + argument + ", require " + parameter + ")"));
-                ok = false;
-                break;
-            }
-        }
-        if (!ok)
-            continue;
-        for (let i = 0; i < argumentTypes.length; ++i) {
-            if (!argumentTypes[i])
-                throw new Error("Null argument type at i = " + i);
-            if (!argumentTypes[i].unify(unificationContext, func.parameters[i].type)) {
-                failures.push(new OverloadResolutionFailure(func, "Argument #" + (i + 1) + " " + (func.parameters[i].name ? "for parameter " + func.parameters[i].name : "") + " does not match (passed " + argumentTypes[i] + ", require " + func.parameters[i].type + ")"));
-                ok = false;
-                break;
-            }
-        }
-        if (!ok)
-            continue;
-        if (returnType) {
-            if (!returnType.unify(unificationContext, func.returnType)) {
-                failures.push(new OverloadResolutionFailure(func, "Return type " + func.returnType + " does not match " + returnType));
+        let argumentFunc = successes[i].func;
+        for (let j = 0; j < successes.length; ++j) {
+            if (i == j)
                 continue;
-            }
-        }
-        if (!unificationContext.verify()) {
-            failures.push(new OverloadResolutionFailure(func, "Violates type variable constraints"));
-            continue;
-        }
-        let shouldBuildTypeArguments = !typeArguments.length;
-        if (shouldBuildTypeArguments)
-            typeArguments = [];
-        for (let typeParameter of func.typeParameters) {
-            let typeArgument = unificationContext.find(typeParameter);
-            if (typeArgument == typeParameter) {
-                failures.push(new OverloadResolutionFailure(func, "Type parameter " + typeParameter + " did not get assigned a type"));
+            let parameterFunc = successes[j].func;
+            let overload = inferTypesForCall(
+                parameterFunc,
+                typeArguments.length ? argumentFunc.typeParameters : [],
+                argumentFunc.parameterTypes,
+                argumentFunc.returnTypeForOverloadResolution);
+            if (!overload.func) {
                 ok = false;
                 break;
             }
-            if (shouldBuildTypeArguments)
-                typeArguments.push(typeArgument);
         }
-        if (!ok)
-            continue;
-        return {func, unificationContext, typeArguments};
+        if (ok)
+            prunedSuccesses.push(successes[i]);
     }
     
-    return {failures: failures};
+    if (prunedSuccesses.length == 1)
+        return prunedSuccesses[0];
+    
+    let ambiguityList;
+    let message;
+    if (prunedSuccesses.length == 0) {
+        ambiguityList = successes;
+        message = "Ambiguous overload - no function can be applied to all others";
+    } else {
+        ambiguityList = prunedSuccesses;
+        message = "Ambiguous overload - functions mutually applicable";
+    }
+    
+    return {failures: ambiguityList.map(overload => new OverloadResolutionFailure(overload.func, message))};
 }

Modified: trunk/Tools/WebGPUShadingLanguageRI/Rewriter.js (221836 => 221837)


--- trunk/Tools/WebGPUShadingLanguageRI/Rewriter.js	2017-09-10 19:00:03 UTC (rev 221836)
+++ trunk/Tools/WebGPUShadingLanguageRI/Rewriter.js	2017-09-10 21:49:13 UTC (rev 221837)
@@ -74,6 +74,7 @@
             node.typeParameters.map(parameter => parameter.visit(this)),
             node.parameters.map(parameter => parameter.visit(this)));
         result.protocolDecl = node.protocolDecl;
+        result.possibleOverloads = node.possibleOverloads;
         return result;
     }
     
@@ -249,18 +250,12 @@
             result.argumentTypes = argumentTypes.map(argumentType => argumentType.visit(this));
         result.func = node.func;
         result.nativeFuncInstance = node.nativeFuncInstance;
+        result.possibleOverloads = node.possibleOverloads;
+        if (node.isCast)
+            result.setCastData(node.returnType.visit(this));
         return result;
     }
 
-    visitCastExpression(node)
-    {
-        let result = new CastExpression(
-            node.origin, node.returnType.visit(this),
-            node.typeArguments.map(typeArgument => typeArgument.visit(this)),
-            node.argumentList.map(argument => argument.visit(this)));
-        return this.processDerivedCallData(node, result);
-    }
-    
     visitCallExpression(node)
     {
         let result = new CallExpression(

Added: trunk/Tools/WebGPUShadingLanguageRI/StandardLibrary.js (0 => 221837)


--- trunk/Tools/WebGPUShadingLanguageRI/StandardLibrary.js	                        (rev 0)
+++ trunk/Tools/WebGPUShadingLanguageRI/StandardLibrary.js	2017-09-10 21:49:13 UTC (rev 221837)
@@ -0,0 +1,80 @@
+/*
+ * 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";
+
+// NOTE: The next line is line 28, and we rely on this in Prepare.js.
+const standardLibrary = `
+// This is the WSL standard library. Implementations of all of these things are in
+// Intrinsics.js. The only thing that gets defined before we get here is the primitive
+// protocol.
+
+// Need to bootstrap void first.
+native primitive typedef void;
+
+native primitive typedef int32;
+native primitive typedef uint32;
+native primitive typedef bool;
+typedef int = int32;
+typedef uint = uint32;
+
+native primitive typedef double;
+
+native int operator+(int, int);
+native uint operator+(uint, uint);
+native int operator-(int, int);
+native uint operator-(uint, uint);
+native int operator*(int, int);
+native uint operator*(uint, uint);
+native int operator/(int, int);
+native uint operator/(uint, uint);
+native bool operator==(int, int);
+native bool operator==(uint, uint);
+native bool operator==(bool, bool);
+
+protocol Equatable {
+    bool operator==(Equatable, Equatable);
+}
+
+restricted operator<T> T()
+{
+    T defaultValue;
+    return defaultValue;
+}
+
+restricted operator<T> T(T x)
+{
+    return x;
+}
+
+operator<T:Equatable> bool(T x)
+{
+    return x != T();
+}
+
+native thread T^ operator&[]<T>(thread T[], uint);
+native threadgroup T^ operator&[]<T:primitive>(threadgroup T[], uint);
+native device T^ operator&[]<T:primitive>(device T[], uint);
+native constant T^ operator&[]<T:primitive>(constant T[], uint);
+`;

Deleted: trunk/Tools/WebGPUShadingLanguageRI/StandardLibraryEpilogue.js (221836 => 221837)


--- trunk/Tools/WebGPUShadingLanguageRI/StandardLibraryEpilogue.js	2017-09-10 19:00:03 UTC (rev 221836)
+++ trunk/Tools/WebGPUShadingLanguageRI/StandardLibraryEpilogue.js	2017-09-10 21:49:13 UTC (rev 221837)
@@ -1,33 +0,0 @@
-/*
- * 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";
-
-// NOTE: The next line is line 28, and we rely on this in Prepare.js.
-const standardLibraryEpilogue = `
-operator bool<><T:Equatable>(T x) {
-    T defaultValue;
-    return x != defaultValue;
-}
-`;

Deleted: trunk/Tools/WebGPUShadingLanguageRI/StandardLibraryPrologue.js (221836 => 221837)


--- trunk/Tools/WebGPUShadingLanguageRI/StandardLibraryPrologue.js	2017-09-10 19:00:03 UTC (rev 221836)
+++ trunk/Tools/WebGPUShadingLanguageRI/StandardLibraryPrologue.js	2017-09-10 21:49:13 UTC (rev 221837)
@@ -1,68 +0,0 @@
-/*
- * 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";
-
-// NOTE: The next line is line 28, and we rely on this in Prepare.js.
-const standardLibraryPrologue = `
-// This is the WSL standard library. Implementations of all of these things are in
-// Intrinsics.js. The only thing that gets defined before we get here is the primitive
-// protocol.
-
-// Need to bootstrap void first.
-native primitive typedef void;
-
-native primitive typedef int32;
-native primitive typedef uint32;
-native primitive typedef bool;
-typedef int = int32;
-typedef uint = uint32;
-
-native primitive typedef double;
-
-native int operator+(int, int);
-native uint operator+(uint, uint);
-native int operator-(int, int);
-native uint operator-(uint, uint);
-native int operator*(int, int);
-native uint operator*(uint, uint);
-native int operator/(int, int);
-native uint operator/(uint, uint);
-native bool operator==(int, int);
-native bool operator==(uint, uint);
-native bool operator==(bool, bool);
-
-protocol Equatable {
-    bool operator==(Equatable, Equatable);
-}
-
-operator T<><T>(T x) {
-    return x;
-}
-
-native thread T^ operator&[]<T>(thread T[], uint);
-native threadgroup T^ operator&[]<T:primitive>(threadgroup T[], uint);
-native device T^ operator&[]<T:primitive>(device T[], uint);
-native constant T^ operator&[]<T:primitive>(constant T[], uint);
-`;

Modified: trunk/Tools/WebGPUShadingLanguageRI/Test.html (221836 => 221837)


--- trunk/Tools/WebGPUShadingLanguageRI/Test.html	2017-09-10 19:00:03 UTC (rev 221836)
+++ trunk/Tools/WebGPUShadingLanguageRI/Test.html	2017-09-10 21:49:13 UTC (rev 221837)
@@ -18,7 +18,6 @@
 <script src=""
 <script src=""
 <script src=""
-<script src=""
 <script src=""
 <script src=""
 <script src=""
@@ -42,6 +41,7 @@
 <script src=""
 <script src=""
 <script src=""
+<script src=""
 <script src=""
 <script src=""
 <script src=""
@@ -77,8 +77,7 @@
 <script src=""
 <script src=""
 <script src=""
-<script src=""
-<script src=""
+<script src=""
 <script src=""
 <script src=""
 <script src=""

Modified: trunk/Tools/WebGPUShadingLanguageRI/Test.js (221836 => 221837)


--- trunk/Tools/WebGPUShadingLanguageRI/Test.js	2017-09-10 19:00:03 UTC (rev 221836)
+++ trunk/Tools/WebGPUShadingLanguageRI/Test.js	2017-09-10 21:49:13 UTC (rev 221837)
@@ -41,7 +41,7 @@
 
 function doLex(code)
 {
-    let lexer = new Lexer("/internal/test", 0, code);
+    let lexer = new Lexer("/internal/test", "native", 0, code);
     var result = [];
     for (;;) {
         let next = lexer.next();
@@ -85,17 +85,17 @@
 function checkUInt(program, result, expected)
 {
     if (!result.type.equals(program.intrinsics.uint32))
-        throw new Error("Wrong result type; result: " + result);
+        throw new Error("Wrong result type: " + result.type);
     if (result.value != expected)
-        throw new Error("Wrong result: " + result + " (expected " + 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: " + result);
+        throw new Error("Wrong result type: " + result.type);
     if (result.value != expected)
-        throw new Error("Wrong result: " + result + " (expected " + expected + ")");
+        throw new Error("Wrong result: " + result.value + " (expected " + expected + ")");
 }
 
 function checkLexerToken(result, expectedIndex, expectedKind, expectedText)
@@ -1368,6 +1368,38 @@
         (e) => e instanceof WTypeError);
 }
 
+function TEST_ambiguousOverloadSimple()
+{
+    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);
+}
+
+function TEST_ambiguousOverloadOverlapping()
+{
+    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);
+}
+
+function TEST_ambiguousOverloadTieBreak()
+{
+    doPrep(`
+        void foo<T>(int, T) { }
+        void foo<T>(T, T) { }
+        void foo(int, int) { }
+        void bar(int a, int b) { foo(a, b); }
+    `);
+}
+
 let filter = /.*/; // run everything by default
 if (this["arguments"]) {
     for (let i = 0; i < arguments.length; i++) {

Modified: trunk/Tools/WebGPUShadingLanguageRI/TypeRef.js (221836 => 221837)


--- trunk/Tools/WebGPUShadingLanguageRI/TypeRef.js	2017-09-10 19:00:03 UTC (rev 221836)
+++ trunk/Tools/WebGPUShadingLanguageRI/TypeRef.js	2017-09-10 21:49:13 UTC (rev 221837)
@@ -116,6 +116,8 @@
     
     toString()
     {
+        if (!this.name)
+            return this.type.toString();
         if (!this.typeArguments.length)
             return this.name;
         return this.name + "<" + this.typeArguments + ">";

Modified: trunk/Tools/WebGPUShadingLanguageRI/Visitor.js (221836 => 221837)


--- trunk/Tools/WebGPUShadingLanguageRI/Visitor.js	2017-09-10 19:00:03 UTC (rev 221836)
+++ trunk/Tools/WebGPUShadingLanguageRI/Visitor.js	2017-09-10 21:49:13 UTC (rev 221837)
@@ -263,14 +263,10 @@
             for (let argument of actualTypeArguments)
                 argument.visit(this);
         }
+        if (node.returnType)
+            node.returnType.visit(this);
     }
     
-    visitCastExpression(node)
-    {
-        this.visitCallExpression(node);
-        node.returnType.visit(this);
-    }
-
     visitLogicalNot(node)
     {
         node.operand.visit(this);
_______________________________________________
webkit-changes mailing list
webkit-changes@lists.webkit.org
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to