WSL overload resolution should not be cascading
authorfpizlo@apple.com <fpizlo@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Sun, 10 Sep 2017 21:49:13 +0000 (21:49 +0000)
committerfpizlo@apple.com <fpizlo@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Sun, 10 Sep 2017 21:49:13 +0000 (21:49 +0000)
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.

git-svn-id: https://svn.webkit.org/repository/webkit/trunk@221837 268f45cc-cd09-0410-ab3c-d52691b4dbfc

31 files changed:
Tools/ChangeLog
Tools/WebGPUShadingLanguageRI/All.js
Tools/WebGPUShadingLanguageRI/ArrayRefType.js
Tools/WebGPUShadingLanguageRI/CallExpression.js
Tools/WebGPUShadingLanguageRI/CastExpression.js [deleted file]
Tools/WebGPUShadingLanguageRI/Checker.js
Tools/WebGPUShadingLanguageRI/Evaluator.js
Tools/WebGPUShadingLanguageRI/Func.js
Tools/WebGPUShadingLanguageRI/FuncDef.js
Tools/WebGPUShadingLanguageRI/FuncInstantiator.js
Tools/WebGPUShadingLanguageRI/FunctionLikeBlock.js
Tools/WebGPUShadingLanguageRI/InferTypesForCall.js [new file with mode: 0644]
Tools/WebGPUShadingLanguageRI/Inline.js
Tools/WebGPUShadingLanguageRI/Lexer.js
Tools/WebGPUShadingLanguageRI/NameContext.js
Tools/WebGPUShadingLanguageRI/NameResolver.js
Tools/WebGPUShadingLanguageRI/NativeFunc.js
Tools/WebGPUShadingLanguageRI/Node.js
Tools/WebGPUShadingLanguageRI/Parse.js
Tools/WebGPUShadingLanguageRI/Prepare.js
Tools/WebGPUShadingLanguageRI/Program.js
Tools/WebGPUShadingLanguageRI/ProtocolDecl.js
Tools/WebGPUShadingLanguageRI/PtrType.js
Tools/WebGPUShadingLanguageRI/ResolveOverloadImpl.js
Tools/WebGPUShadingLanguageRI/Rewriter.js
Tools/WebGPUShadingLanguageRI/StandardLibrary.js [moved from Tools/WebGPUShadingLanguageRI/StandardLibraryPrologue.js with 92% similarity]
Tools/WebGPUShadingLanguageRI/StandardLibraryEpilogue.js [deleted file]
Tools/WebGPUShadingLanguageRI/Test.html
Tools/WebGPUShadingLanguageRI/Test.js
Tools/WebGPUShadingLanguageRI/TypeRef.js
Tools/WebGPUShadingLanguageRI/Visitor.js

index 4c271fe..36af21f 100644 (file)
@@ -1,3 +1,131 @@
+2017-09-07  Filip Pizlo  <fpizlo@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  <beidson@apple.com>
 
         Try to avoid creating the default WKWebsiteDataStore until its actually needed.
index 60b75fd..83c0cc6 100644 (file)
@@ -42,7 +42,6 @@ load("BoolLiteral.js");
 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("FuncInstantiator.js");
 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("ResolveTypeDefs.js");
 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");
index 5523b9c..02a501c 100644 (file)
 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")
index 8d02907..f51970d 100644 (file)
@@ -32,16 +32,20 @@ class CallExpression extends Expression {
         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 @@ class CallExpression extends Expression {
         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 + ")";
     }
 }
 
diff --git a/Tools/WebGPUShadingLanguageRI/CastExpression.js b/Tools/WebGPUShadingLanguageRI/CastExpression.js
deleted file mode 100644 (file)
index 372e0c5..0000000
+++ /dev/null
@@ -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 + ")";
-    }
-}
-
index b66d94c..8081b67 100644 (file)
@@ -246,7 +246,7 @@ class Checker extends Visitor {
         return result;
     }
 
-    checkCastOrCallExpression(node, returnType)
+    visitCallExpression(node)
     {
         for (let typeArgument of node.typeArguments)
             typeArgument.visit(this);
@@ -257,8 +257,8 @@ class Checker extends Visitor {
             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,18 +271,23 @@ class Checker extends Visitor {
                 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);
             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 @@ class Checker extends Visitor {
         }
         return node.resolve(overload);
     }
-
-    visitCastExpression(node)
-    {
-        return this.checkCastOrCallExpression(node, node.returnType);
-    }
-    
-    visitCallExpression(node)
-    {
-        return this.checkCastOrCallExpression(node, undefined);
-    }
 }
 
index 77219e6..1e270e2 100644 (file)
@@ -148,7 +148,8 @@ class Evaluator extends Visitor {
 
     visitLogicalNot(node)
     {
-        return EPtr.box(!node.operand.visit(this).loadValue());
+        let result = !node.operand.visit(this).loadValue();
+        return EPtr.box(result);
     }
 
     visitIfStatement(node)
index e94ca6c..08d4d5b 100644 (file)
@@ -45,6 +45,7 @@ class Func extends Node {
     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; }
     
index 7be364d..f76e500 100644 (file)
@@ -29,6 +29,7 @@ class FuncDef extends Func {
     {
         super(origin, name, returnType, typeParameters, parameters, isCast);
         this._body = body;
+        this.isRestricted = false;
     }
 
     get body() { return this._body; }
index be63f51..6a4c739 100644 (file)
@@ -38,6 +38,14 @@ class FuncInstantiator {
     // 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 @@ class FuncInstantiator {
                 // 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);
index 120317f..0450054 100644 (file)
@@ -43,6 +43,6 @@ class FunctionLikeBlock extends Value {
     
     toString()
     {
-        return "([&] (" + this.parameters + ") -> " + this.returnType + " { " + this.block + " }(" + this.argumentList + "))";
+        return "([&] (" + this.parameters + ") -> " + this.returnType + " { " + this.body + " }(" + this.argumentList + "))";
     }
 }
diff --git a/Tools/WebGPUShadingLanguageRI/InferTypesForCall.js b/Tools/WebGPUShadingLanguageRI/InferTypesForCall.js
new file mode 100644 (file)
index 0000000..55feec7
--- /dev/null
@@ -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};
+}
+
index 623098c..fa4c87f 100644 (file)
@@ -57,7 +57,7 @@ function _inlineFunction(program, func, visiting)
 
 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)
index 94e0141..214b36a 100644 (file)
 "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 @@ class Lexer {
         
         // 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");
         }
 
index 53735a2..6137961 100644 (file)
@@ -34,7 +34,6 @@ function isWildcardKind(kind)
 class NameContext {
     constructor(delegate)
     {
-        this._funcMap = new Map();
         this._map = new Map();
         this._set = new Set();
         this._defined = null;
@@ -51,9 +50,8 @@ class NameContext {
         case Value:
         case Type:
         case Protocol:
-            return this._map;
         case Func:
-            return this._funcMap;
+            return this._map;
         default:
             throw new Error("Bad kind: " + kind);
         }
@@ -72,9 +70,14 @@ class NameContext {
         
         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 @@ class NameContext {
         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 @@ class NameContext {
     
     *[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;
         }
     }
 }
index 116e318..d44c250 100644 (file)
@@ -50,6 +50,7 @@ class NameResolver extends Visitor {
         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 @@ class NameResolver extends Visitor {
         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 @@ class NameResolver extends Visitor {
     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);
     }
 }
index 46e6885..747aa3a 100644 (file)
@@ -28,6 +28,7 @@ class NativeFunc extends Func {
     constructor(origin, name, returnType, typeParameters, parameters, isCast)
     {
         super(origin, name, returnType, typeParameters, parameters, isCast);
+        this.isRestricted = false;
     }
     
     get isNative() { return true; }
index 04e3889..66750b6 100644 (file)
 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);
         let returnValue = visitFunc.call(visitor, this);
         if ("returnValue" in visitor)
             returnValue = visitor.returnValue;
-        memoTable.set(this, returnValue);
         return returnValue;
     }
     
index a61a48c..af6cc80 100644 (file)
@@ -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 @@ function parse(program, origin, lineNumberOffset, text)
             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 @@ function parse(program, origin, lineNumberOffset, text)
         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 @@ function parse(program, origin, lineNumberOffset, text)
         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 @@ function parse(program, origin, lineNumberOffset, text)
         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,9 +735,19 @@ function parse(program, origin, lineNumberOffset, text)
             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 (;;) {
@@ -739,8 +758,10 @@ function parse(program, origin, lineNumberOffset, text)
             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")
index 2bda925..a050b17 100644 (file)
@@ -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);
index 71e3eaf..4e6ca6a 100644 (file)
@@ -58,23 +58,6 @@ class Program extends Node {
         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)
index 8e336d0..863531d 100644 (file)
@@ -72,7 +72,7 @@ class ProtocolDecl extends Protocol {
             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 @@ class ProtocolDecl extends Protocol {
         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;
             
index 008af40..619cbd0 100644 (file)
@@ -31,6 +31,8 @@ class PtrType extends ReferenceType {
     {
         if (!(other instanceof PtrType))
             return false;
+        if (this.addressSpace != other.addressSpace)
+            return false;
         return this.elementType.unify(unificationContext, other.elementType);
     }
     
index 79314d5..2465314 100644 (file)
 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;
-        }
-        if (argumentTypes.length != func.parameters.length) {
-            failures.push(new OverloadResolutionFailure(func, "Wrong number of arguments (passed " + argumentTypes.length + ", require " + func.parameters.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;
         }
-        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]);
+    }
+    
+    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: failures};
+    return {failures: ambiguityList.map(overload => new OverloadResolutionFailure(overload.func, message))};
 }
index 95881ab..21d5a1a 100644 (file)
@@ -74,6 +74,7 @@ class Rewriter extends VisitorBase {
             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 @@ class Rewriter extends VisitorBase {
             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(
@@ -25,7 +25,7 @@
 "use strict";
 
 // NOTE: The next line is line 28, and we rely on this in Prepare.js.
-const standardLibraryPrologue = `
+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.
@@ -57,10 +57,22 @@ protocol Equatable {
     bool operator==(Equatable, Equatable);
 }
 
-operator T<><T>(T x) {
+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);
diff --git a/Tools/WebGPUShadingLanguageRI/StandardLibraryEpilogue.js b/Tools/WebGPUShadingLanguageRI/StandardLibraryEpilogue.js
deleted file mode 100644 (file)
index ca54a14..0000000
+++ /dev/null
@@ -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;
-}
-`;
index abff96a..2b41e28 100644 (file)
@@ -18,7 +18,6 @@
 <script src="CallAssignment.js"></script>
 <script src="CallExpression.js"></script>
 <script src="CallFunction.js"></script>
-<script src="CastExpression.js"></script>
 <script src="Check.js"></script>
 <script src="CheckLiteralTypes.js"></script>
 <script src="CheckRecursion.js"></script>
@@ -42,6 +41,7 @@
 <script src="FuncParameter.js"></script>
 <script src="FunctionLikeBlock.js"></script>
 <script src="IfStatement.js"></script>
+<script src="InferTypesForCall.js"></script>
 <script src="Inline.js"></script>
 <script src="Inliner.js"></script>
 <script src="InstantiateImmediates.js"></script>
@@ -77,8 +77,7 @@
 <script src="Return.js"></script>
 <script src="ReturnChecker.js"></script>
 <script src="ReturnException.js"></script>
-<script src="StandardLibraryEpilogue.js"></script>
-<script src="StandardLibraryPrologue.js"></script>
+<script src="StandardLibrary.js"></script>
 <script src="StructLayoutBuilder.js"></script>
 <script src="StructType.js"></script>
 <script src="Substitution.js"></script>
index 7af744f..a642c44 100644 (file)
@@ -41,7 +41,7 @@ function doPrep(code)
 
 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 checkInt(program, result, expected)
 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 @@ function TEST_protocolMonoPolySigDoublePolyDefExplicit()
         (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++) {
index 50dea1c..c62d75d 100644 (file)
@@ -116,6 +116,8 @@ class TypeRef extends Type {
     
     toString()
     {
+        if (!this.name)
+            return this.type.toString();
         if (!this.typeArguments.length)
             return this.name;
         return this.name + "<" + this.typeArguments + ">";
index d6e8669..95d15ce 100644 (file)
@@ -263,14 +263,10 @@ class Visitor extends VisitorBase {
             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);