[WHLSL] Allow native types to have type arguments (like "vector<float, 4>")
authormmaxfield@apple.com <mmaxfield@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Thu, 23 Aug 2018 19:52:16 +0000 (19:52 +0000)
committermmaxfield@apple.com <mmaxfield@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Thu, 23 Aug 2018 19:52:16 +0000 (19:52 +0000)
https://bugs.webkit.org/show_bug.cgi?id=188773

Reviewed by Filip Pizlo.

Before this patch, it was impossible to represent "native typedef vector<float, 4>" because NativeTypes couldn't have
typeArguments.

Previously, the way to identify a type was strictly by name, which was represented by a string. Therefore, when something like
"vector<int, 3>" was parsed, it would produce a TypeRef with the name "vector" and typeArguments [TypeRef, IntLiteral]. Then,
there was a pass to convert the TypeRef to have the name "int3" and no typeArguments. After this transformation, each type could
be uniquely identified by name. That name was then matched to the string-only NativeType name.

This is okay for vectors and matrices, but it is unfortunate for textures (e.g. Texture2D<float4>) because they don't have any
natural string-only name. In addition, the canonicalization would have to be made aware of the fact that Texture2D<float4> is
the same as Texture2D<vector<float, 4>>. Similarly, an author may wish to typedef float4 to a different name.

It would be possible to mangle the names of the texture types to something unique, but then we lose information about the inner
type. For example, if we did this, Visitor wouldn't recurse into the float4 when encountering Texture2D<float4> because that
information would be lost. This could potentially make operations like programWithUnnecessaryThingsRemoved() more difficult to
implement in the future.

So, it would be better to have each type uniquely identified by (name, typeArguments). TypeRef will therefore also have
typeArguments which are used to determine which type it is referencing. After this analysis is done to determine what each
TypeRef is referencing, subsequent passes shouldn't care about the typeArguments and should only care about the .type field
which had been set - this was true even before this patch.

This means that NameContext has to aggregate types that accept typeArguments into arrays, where each array holds all the Types
that have the same name but different typeArguments. Then, when we need to match a TypeRef with a Type, we can ask the
NameContext for the appropriate array. This is the same way that function resolution works.

We can use Node.unify() to determine whether a TypeRef matches a NativeType. Eventually, this will go away, but for now, this is
an okay start. This works just about the same way that function overload resolution works.

* WebGPUShadingLanguageRI/All.js:
* WebGPUShadingLanguageRI/CallExpression.js:
(CallExpression.prototype.resolve):
* WebGPUShadingLanguageRI/CheckTypesWithArguments.js: Copied from Tools/WebGPUShadingLanguageRI/ResolveTypeDefs.js. After types
have been resolved, there should be no TypeRefs with name "vector" that don't have type arguments. This is just a sanity check.
(checkTypesWithArguments.TypeWithArgumentsChecker.prototype.visitTypeRef):
(checkTypesWithArguments.TypeWithArgumentsChecker):
(checkTypesWithArguments):
* WebGPUShadingLanguageRI/Checker.js:
(Checker.prototype.visitProgram): Program.types mirrors NameContext: it's a Map that maps strings to types. Because types with
typeArguments share names, this has to be updated to map strings to arrays for these types.
(Checker.prototype.visitTypeRef):
* WebGPUShadingLanguageRI/InferTypesForCall.js:
(inferTypesForCall): Don't know why this was here.
(inferTypesForTypeArguments): Same as inferTypesForCall, but this one is for matching type arguments.
* WebGPUShadingLanguageRI/Intrinsics.js: Adding the types. This patch also adds some scalar types like half, char, etc, but they
don't have any functions which accept them. Those will be tested in my next patch which adds math functions for these types. This
moves in the direction of matching the standard library in the spec.
(Intrinsics.cast):
(Intrinsics.bitwiseCast):
(Intrinsics.castToHalf):
(Intrinsics.):
(Intrinsics):
* WebGPUShadingLanguageRI/NameContext.js: Aggregate types with typeArguments into arrays.
(NameContext.prototype.add):
(NameContext.prototype.get let):
(NameContext.underlyingThings.prototype.else):
(NameContext.prototype.Symbol.iterator):
(NameContext):
* WebGPUShadingLanguageRI/NameResolver.js:
(NameResolver.prototype.visitTypeRef): Call TypeRef.resolve().
(NameResolver.prototype.visitCallExpression):
(NameResolver):
(NameResolver.prototype.visitVectorType): Deleted.
* WebGPUShadingLanguageRI/NativeType.js: NativeTypes can have type arguments now.
(NativeType):
(NativeType.prototype.get typeArguments):
(NativeType.prototype.toString):
(NativeType.create):
* WebGPUShadingLanguageRI/Prepare.js:
(let.prepare):
* WebGPUShadingLanguageRI/Program.js: Update to work with types aggregated into arrays.
(Program.prototype.add):
(Program.prototype.toString):
(Program):
* WebGPUShadingLanguageRI/RemoveTypeArguments.js: Removed.
* WebGPUShadingLanguageRI/ResolveNames.js: Update to work with types aggregated into arrays.
(resolveNamesInTypes):
* WebGPUShadingLanguageRI/ResolveOverloadImpl.js: Resolve the type overload for types with typeArguments.
* WebGPUShadingLanguageRI/ResolveTypeDefs.js: Update to work with types aggregated into arrays.
(resolveTypeDefsInTypes):
* WebGPUShadingLanguageRI/Rewriter.js: TypeRefs and Native/Vector types can have typeArguments.
(Rewriter.prototype.visitTypeRef):
(Rewriter.prototype.visitVectorType):
(Rewriter):
* WebGPUShadingLanguageRI/SPIRV.html:
* WebGPUShadingLanguageRI/StandardLibrary.js: Matches Intrinsics.
(bool.operator):
* WebGPUShadingLanguageRI/StatementCloner.js: Native types can have typeArguments.
(StatementCloner.prototype.visitNativeType):
* WebGPUShadingLanguageRI/SynthesizeDefaultConstructorOperator.js: Vector types need constructors too.
(synthesizeDefaultConstructorOperator.FindAllTypes.prototype.visitVectorType):
(synthesizeDefaultConstructorOperator.FindAllTypes):
(synthesizeDefaultConstructorOperator):
* WebGPUShadingLanguageRI/SynthesizeStructAccessors.js: No reason to distinguish between wrapping and instantiating a TypeRef.
(synthesizeStructAccessors.createTypeRef):
* WebGPUShadingLanguageRI/Test.html:
* WebGPUShadingLanguageRI/Test.js:
* WebGPUShadingLanguageRI/TypeOverloadResolutionFailure.js: Copied from Tools/WebGPUShadingLanguageRI/ResolveTypeDefs.js.
(TypeOverloadResolutionFailure):
(TypeOverloadResolutionFailure.prototype.get type):
(TypeOverloadResolutionFailure.prototype.get reason):
(TypeOverloadResolutionFailure.prototype.toString):
* WebGPUShadingLanguageRI/TypeRef.js:
(TypeRef.wrap):
(TypeRef.prototype.resolve): Figure out which item in the possibleOverloads array matches this.
(TypeRef.prototype.toString):
(TypeRef):
(TypeRef.instantiate): Deleted.
* WebGPUShadingLanguageRI/UnificationContext.js: We need to give literals a chance to assume their preferred type. This
adds this facility back into the compiler (it was previously deleted).
(UnificationContext.prototype.verify):
* WebGPUShadingLanguageRI/VectorType.js: Vector types have type arguments.
(VectorType):
(VectorType.prototype.get elementType):
(VectorType.prototype.get numElements):
(VectorType.prototype.get numElementsValue):
(VectorType.prototype.toString):
* WebGPUShadingLanguageRI/Visitor.js: Iterate over the typeArguments.
(Visitor.prototype.visitTypeRef):
(Visitor.prototype.visitNativeType):
(Visitor.prototype.visitVectorType):
(Visitor):
* WebGPUShadingLanguageRI/index.html:

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

30 files changed:
Tools/ChangeLog
Tools/WebGPUShadingLanguageRI/All.js
Tools/WebGPUShadingLanguageRI/CallExpression.js
Tools/WebGPUShadingLanguageRI/CheckTypesWithArguments.js [new file with mode: 0644]
Tools/WebGPUShadingLanguageRI/Checker.js
Tools/WebGPUShadingLanguageRI/InferTypesForCall.js
Tools/WebGPUShadingLanguageRI/Intrinsics.js
Tools/WebGPUShadingLanguageRI/NameContext.js
Tools/WebGPUShadingLanguageRI/NameResolver.js
Tools/WebGPUShadingLanguageRI/NativeType.js
Tools/WebGPUShadingLanguageRI/Prepare.js
Tools/WebGPUShadingLanguageRI/Program.js
Tools/WebGPUShadingLanguageRI/RemoveTypeArguments.js [deleted file]
Tools/WebGPUShadingLanguageRI/ResolveNames.js
Tools/WebGPUShadingLanguageRI/ResolveOverloadImpl.js
Tools/WebGPUShadingLanguageRI/ResolveTypeDefs.js
Tools/WebGPUShadingLanguageRI/Rewriter.js
Tools/WebGPUShadingLanguageRI/SPIRV.html
Tools/WebGPUShadingLanguageRI/StandardLibrary.js
Tools/WebGPUShadingLanguageRI/StatementCloner.js
Tools/WebGPUShadingLanguageRI/SynthesizeDefaultConstructorOperator.js
Tools/WebGPUShadingLanguageRI/SynthesizeStructAccessors.js
Tools/WebGPUShadingLanguageRI/Test.html
Tools/WebGPUShadingLanguageRI/Test.js
Tools/WebGPUShadingLanguageRI/TypeOverloadResolutionFailure.js [new file with mode: 0644]
Tools/WebGPUShadingLanguageRI/TypeRef.js
Tools/WebGPUShadingLanguageRI/UnificationContext.js
Tools/WebGPUShadingLanguageRI/VectorType.js
Tools/WebGPUShadingLanguageRI/Visitor.js
Tools/WebGPUShadingLanguageRI/index.html

index 19e66f3..f038e38 100644 (file)
@@ -1,3 +1,134 @@
+2018-08-23  Myles C. Maxfield  <mmaxfield@apple.com>
+
+        [WHLSL] Allow native types to have type arguments (like "vector<float, 4>")
+        https://bugs.webkit.org/show_bug.cgi?id=188773
+
+        Reviewed by Filip Pizlo.
+
+        Before this patch, it was impossible to represent "native typedef vector<float, 4>" because NativeTypes couldn't have
+        typeArguments.
+
+        Previously, the way to identify a type was strictly by name, which was represented by a string. Therefore, when something like
+        "vector<int, 3>" was parsed, it would produce a TypeRef with the name "vector" and typeArguments [TypeRef, IntLiteral]. Then,
+        there was a pass to convert the TypeRef to have the name "int3" and no typeArguments. After this transformation, each type could
+        be uniquely identified by name. That name was then matched to the string-only NativeType name.
+
+        This is okay for vectors and matrices, but it is unfortunate for textures (e.g. Texture2D<float4>) because they don't have any
+        natural string-only name. In addition, the canonicalization would have to be made aware of the fact that Texture2D<float4> is
+        the same as Texture2D<vector<float, 4>>. Similarly, an author may wish to typedef float4 to a different name.
+
+        It would be possible to mangle the names of the texture types to something unique, but then we lose information about the inner
+        type. For example, if we did this, Visitor wouldn't recurse into the float4 when encountering Texture2D<float4> because that
+        information would be lost. This could potentially make operations like programWithUnnecessaryThingsRemoved() more difficult to
+        implement in the future.
+
+        So, it would be better to have each type uniquely identified by (name, typeArguments). TypeRef will therefore also have
+        typeArguments which are used to determine which type it is referencing. After this analysis is done to determine what each
+        TypeRef is referencing, subsequent passes shouldn't care about the typeArguments and should only care about the .type field
+        which had been set - this was true even before this patch.
+
+        This means that NameContext has to aggregate types that accept typeArguments into arrays, where each array holds all the Types
+        that have the same name but different typeArguments. Then, when we need to match a TypeRef with a Type, we can ask the
+        NameContext for the appropriate array. This is the same way that function resolution works.
+
+        We can use Node.unify() to determine whether a TypeRef matches a NativeType. Eventually, this will go away, but for now, this is
+        an okay start. This works just about the same way that function overload resolution works. 
+
+        * WebGPUShadingLanguageRI/All.js:
+        * WebGPUShadingLanguageRI/CallExpression.js:
+        (CallExpression.prototype.resolve):
+        * WebGPUShadingLanguageRI/CheckTypesWithArguments.js: Copied from Tools/WebGPUShadingLanguageRI/ResolveTypeDefs.js. After types
+        have been resolved, there should be no TypeRefs with name "vector" that don't have type arguments. This is just a sanity check.
+        (checkTypesWithArguments.TypeWithArgumentsChecker.prototype.visitTypeRef):
+        (checkTypesWithArguments.TypeWithArgumentsChecker):
+        (checkTypesWithArguments):
+        * WebGPUShadingLanguageRI/Checker.js:
+        (Checker.prototype.visitProgram): Program.types mirrors NameContext: it's a Map that maps strings to types. Because types with
+        typeArguments share names, this has to be updated to map strings to arrays for these types.
+        (Checker.prototype.visitTypeRef):
+        * WebGPUShadingLanguageRI/InferTypesForCall.js:
+        (inferTypesForCall): Don't know why this was here.
+        (inferTypesForTypeArguments): Same as inferTypesForCall, but this one is for matching type arguments.
+        * WebGPUShadingLanguageRI/Intrinsics.js: Adding the types. This patch also adds some scalar types like half, char, etc, but they
+        don't have any functions which accept them. Those will be tested in my next patch which adds math functions for these types. This
+        moves in the direction of matching the standard library in the spec.
+        (Intrinsics.cast):
+        (Intrinsics.bitwiseCast):
+        (Intrinsics.castToHalf):
+        (Intrinsics.):
+        (Intrinsics):
+        * WebGPUShadingLanguageRI/NameContext.js: Aggregate types with typeArguments into arrays.
+        (NameContext.prototype.add):
+        (NameContext.prototype.get let):
+        (NameContext.underlyingThings.prototype.else):
+        (NameContext.prototype.Symbol.iterator):
+        (NameContext):
+        * WebGPUShadingLanguageRI/NameResolver.js:
+        (NameResolver.prototype.visitTypeRef): Call TypeRef.resolve().
+        (NameResolver.prototype.visitCallExpression):
+        (NameResolver):
+        (NameResolver.prototype.visitVectorType): Deleted.
+        * WebGPUShadingLanguageRI/NativeType.js: NativeTypes can have type arguments now.
+        (NativeType):
+        (NativeType.prototype.get typeArguments):
+        (NativeType.prototype.toString):
+        (NativeType.create):
+        * WebGPUShadingLanguageRI/Prepare.js:
+        (let.prepare):
+        * WebGPUShadingLanguageRI/Program.js: Update to work with types aggregated into arrays.
+        (Program.prototype.add):
+        (Program.prototype.toString):
+        (Program):
+        * WebGPUShadingLanguageRI/RemoveTypeArguments.js: Removed.
+        * WebGPUShadingLanguageRI/ResolveNames.js: Update to work with types aggregated into arrays.
+        (resolveNamesInTypes):
+        * WebGPUShadingLanguageRI/ResolveOverloadImpl.js: Resolve the type overload for types with typeArguments.
+        * WebGPUShadingLanguageRI/ResolveTypeDefs.js: Update to work with types aggregated into arrays.
+        (resolveTypeDefsInTypes):
+        * WebGPUShadingLanguageRI/Rewriter.js: TypeRefs and Native/Vector types can have typeArguments.
+        (Rewriter.prototype.visitTypeRef):
+        (Rewriter.prototype.visitVectorType):
+        (Rewriter):
+        * WebGPUShadingLanguageRI/SPIRV.html:
+        * WebGPUShadingLanguageRI/StandardLibrary.js: Matches Intrinsics.
+        (bool.operator):
+        * WebGPUShadingLanguageRI/StatementCloner.js: Native types can have typeArguments.
+        (StatementCloner.prototype.visitNativeType):
+        * WebGPUShadingLanguageRI/SynthesizeDefaultConstructorOperator.js: Vector types need constructors too.
+        (synthesizeDefaultConstructorOperator.FindAllTypes.prototype.visitVectorType):
+        (synthesizeDefaultConstructorOperator.FindAllTypes):
+        (synthesizeDefaultConstructorOperator):
+        * WebGPUShadingLanguageRI/SynthesizeStructAccessors.js: No reason to distinguish between wrapping and instantiating a TypeRef.
+        (synthesizeStructAccessors.createTypeRef):
+        * WebGPUShadingLanguageRI/Test.html:
+        * WebGPUShadingLanguageRI/Test.js:
+        * WebGPUShadingLanguageRI/TypeOverloadResolutionFailure.js: Copied from Tools/WebGPUShadingLanguageRI/ResolveTypeDefs.js.
+        (TypeOverloadResolutionFailure):
+        (TypeOverloadResolutionFailure.prototype.get type):
+        (TypeOverloadResolutionFailure.prototype.get reason):
+        (TypeOverloadResolutionFailure.prototype.toString):
+        * WebGPUShadingLanguageRI/TypeRef.js:
+        (TypeRef.wrap):
+        (TypeRef.prototype.resolve): Figure out which item in the possibleOverloads array matches this.
+        (TypeRef.prototype.toString):
+        (TypeRef):
+        (TypeRef.instantiate): Deleted.
+        * WebGPUShadingLanguageRI/UnificationContext.js: We need to give literals a chance to assume their preferred type. This
+        adds this facility back into the compiler (it was previously deleted).
+        (UnificationContext.prototype.verify):
+        * WebGPUShadingLanguageRI/VectorType.js: Vector types have type arguments.
+        (VectorType):
+        (VectorType.prototype.get elementType):
+        (VectorType.prototype.get numElements):
+        (VectorType.prototype.get numElementsValue):
+        (VectorType.prototype.toString):
+        * WebGPUShadingLanguageRI/Visitor.js: Iterate over the typeArguments.
+        (Visitor.prototype.visitTypeRef):
+        (Visitor.prototype.visitNativeType):
+        (Visitor.prototype.visitVectorType):
+        (Visitor):
+        * WebGPUShadingLanguageRI/index.html:
+
 2018-08-23  Wenson Hsieh  <wenson_hsieh@apple.com>
 
         [Attachment Support] Attachment elements don't appear in drag images on macOS
index 8152527..f9a1d99 100644 (file)
@@ -60,6 +60,7 @@ load("CheckLoops.js");
 load("CheckRecursion.js");
 load("CheckRecursiveTypes.js");
 load("CheckReturns.js");
+load("CheckTypesWithArguments.js");
 load("CheckUnreachableCode.js");
 load("CheckWrapped.js");
 load("Checker.js");
@@ -133,7 +134,6 @@ load("PtrType.js");
 load("ReadModifyWriteExpression.js");
 load("RecursionChecker.js");
 load("RecursiveTypeChecker.js");
-load("RemoveTypeArguments.js");
 load("ResolveNames.js");
 load("ResolveOverloadImpl.js");
 load("ResolveProperties.js");
@@ -157,6 +157,7 @@ load("TrapStatement.js");
 load("TypeDef.js");
 load("TypeDefResolver.js");
 load("TypeRef.js");
+load("TypeOverloadResolutionFailure.js");
 load("TypedValue.js");
 load("UintLiteral.js");
 load("UintLiteralType.js");
@@ -170,4 +171,4 @@ load("WSyntaxError.js");
 load("WTrapError.js");
 load("WTypeError.js");
 load("WhileLoop.js");
-load("WrapChecker.js");
\ No newline at end of file
+load("WrapChecker.js");
index b25398f..3b15455 100644 (file)
@@ -64,7 +64,6 @@ class CallExpression extends Expression {
                 overload.func = func;
         }
 
-
         if (!overload.func) {
             failures.push(...overload.failures);
             let message = "Did not find function named " + this.name + " for call with ";
diff --git a/Tools/WebGPUShadingLanguageRI/CheckTypesWithArguments.js b/Tools/WebGPUShadingLanguageRI/CheckTypesWithArguments.js
new file mode 100644 (file)
index 0000000..bb6b2bd
--- /dev/null
@@ -0,0 +1,38 @@
+/*
+ * Copyright (C) 2018 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 checkTypesWithArguments(program)
+{
+    class TypeWithArgumentsChecker extends Visitor {
+        visitTypeRef(node)
+        {
+            if (node.name == "vector" && node.typeArguments.length == 0)
+                throw new Error("Builtin type ${node.name} should always have type arguments.");
+        }
+    }
+    program.visit(new TypeWithArgumentsChecker());
+}
+
index 1a14c86..4fb7ade 100644 (file)
@@ -41,8 +41,13 @@ class Checker extends Visitor {
             statement.visit(this);
         }
         
-        for (let type of node.types.values())
-            doStatement(type);
+        for (let type of node.types.values()) {
+            if (type instanceof Array) {
+                for (let constituentType of type)
+                    doStatement(constituentType);
+            } else
+                doStatement(type);
+        }
         for (let funcs of node.functions.values()) {
             for (let func of funcs) {
                 this.visitFunc(func);
@@ -247,6 +252,10 @@ class Checker extends Visitor {
     {
         if (!node.type)
             throw new Error("Type reference without a type in checker: " + node + " at " + node.origin);
+        // All the structs will be visited by visitProgram() iterating through each top-level type.
+        // We don't want to recurse here because the contents of structs can refer to themselves (e.g. a linked list),
+        // and this would can an infinite loop.
+        // Typedefs can't refer to themselves because we check that in TypeDefResolver.
         if (!(node.type instanceof StructType))
             node.type.visit(this);
     }
index 5f32ed1..bcfeb98 100644 (file)
@@ -36,12 +36,8 @@ function inferTypesForCall(func, argumentTypes, returnType)
         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)) {
-        if (func.returnType.toString() == "vector") {
-            returnType.unify(unificationContext, func.returnType)
-        }
+    if (returnType && !returnType.unify(unificationContext, func.returnType))
         return {failure: new OverloadResolutionFailure(func, "Return type " + func.returnType + " does not match " + returnType)};
-    }
     let verificationResult = unificationContext.verify();
     if (!verificationResult.result)
         return {failure: new OverloadResolutionFailure(func, verificationResult.reason)};
@@ -49,3 +45,21 @@ function inferTypesForCall(func, argumentTypes, returnType)
     return {func, unificationContext};
 }
 
+function inferTypesForTypeArguments(type, typeArguments)
+{
+    if (typeArguments.length != type.typeArguments.length)
+        return {failure: new TypeOverloadResolutionFailure(type, "Wrong number of arguments (passed " + typeArguments.length + ", require " + type.typeArguments.length + ")")};
+    let unificationContext = new UnificationContext();
+
+    for (let i = 0; i < typeArguments.length; ++i) {
+        if (!typeArguments[i])
+            throw new Error("Null type argument at i = " + i);
+        if (!typeArguments[i].unify(unificationContext, type.typeArguments[i]))
+            return {failure: new TypeOverloadResolutionFailure(type, "Argument #" + (i + 1) + " " + (type.typeArguments[i].name ? "for parameter " + type.typeArguments[i].name + " " : "") + "does not match (passed " + typeArguments[i] + ", require " + type.typeArguments[i].type + ")")};
+    }
+    let verificationResult = unificationContext.verify();
+    if (!verificationResult.result)
+        return {failure: new TypeOverloadResolutionFailure(type, verificationResult.reason)};
+
+    return {type, unificationContext};
+}
index 50d40c0..e9c3d1b 100644 (file)
@@ -33,15 +33,7 @@ class Intrinsics {
         // to catch the intrinsics must be based on the type names that StandardLibrary.js uses.
         // For example, if a native function is declared using "int" rather than "int", then we must
         // use "int" here, since we don't yet know that they are the same type.
-        
-        this._map.set(
-            "native typedef void",
-            type => {
-                this.void = type;
-                type.size = 0;
-                type.populateDefaultValue = () => { };
-            });
-        
+
         function isBitwiseEquivalent(left, right)
         {
             let doubleArray = new Float64Array(1);
@@ -56,58 +48,83 @@ class Intrinsics {
             return true;
         }
 
+        function cast(typedArrayConstructor, number)
+        {
+            var array = new typedArrayConstructor(1);
+            array[0] = number;
+            return array[0];
+        }
+
+        function bitwiseCast(typedArrayConstructor1, typedArrayConstructor2, value)
+        {
+            let typedArray1 = new typedArrayConstructor1(1);
+            let typedArray2 = new typedArrayConstructor2(typedArray1.buffer);
+            typedArray1[0] = value;
+            return typedArray2[0];
+        }
+
+        function castToHalf(number)
+        {
+            // FIXME: Make this math obey IEEE 754.
+            if (Number.isNaN(number))
+               return number
+            if (number > 65504)
+                return Number.POSITIVE_INFINITY;
+            if (number < -65504)
+                return Number.NEGATIVE_INFINITY;
+            if (number > 0 && number < Math.pow(2, -24))
+                return 0;
+            if (number < 0 && number > -Math.pow(2, -24))
+                return -0;
+            let doubleArray = new Float64Array(1);
+            let uintArray = new Uint8Array(doubleArray.buffer);
+            doubleArray[0] = number;
+            let sign = uintArray[7] & 0x80;
+            let exponent = ((uintArray[7] & 0x7f) << 4) | ((uintArray[6] & 0xf0) >>> 4);
+            let significand = ((uintArray[6] & 0x0f) << 6) | ((uintArray[5] & 0xfc) >>> 2);
+
+            if ((exponent - 1023) < -14) {
+                exponent = 0;
+                significand = (Math.abs(number) * Math.pow(2, 24)) >>> 0;
+                let value = Math.pow(2, -14) * significand / 1024;
+                if (sign != 0)
+                    value *= -1;
+                return value;
+            }
+
+            doubleArray[0] = 0;
+
+            uintArray[7] |= sign;
+            uintArray[7] |= (exponent >>> 4);
+            uintArray[6] |= ((exponent << 4) & 0xf0);
+            uintArray[6] |= (significand >>> 6);
+            uintArray[5] |= ((significand << 2) & 0xfc);
+
+            return doubleArray[0];
+        }
+
         this._map.set(
-            "native typedef int",
+            "native typedef void",
             type => {
-                this.int = type;
-                type.isPrimitive = true;
-                type.isInt = true;
-                type.isNumber = true;
-                type.isSigned = true;
-                type.canRepresent = value => isBitwiseEquivalent(value | 0, value);
-                type.size = 1;
-                type.defaultValue = 0;
-                type.createLiteral = (origin, value) => IntLiteral.withType(origin, value | 0, type);
-                type.successorValue = value => (value + 1) | 0;
-                type.valuesEqual = (a, b) => a === b;
-                type.populateDefaultValue = (buffer, offset) => buffer.set(offset, 0);
-                type.formatValueFromIntLiteral = value => value | 0;
-                type.formatValueFromUintLiteral = value => value | 0;
-                type.allValues = function*() { 
-                    for (let i = 0; i <= 0xffffffff; ++i) {
-                        let value = i | 0;
-                        yield {value: value, name: value};
-                    }
-                };
+                this.void = type;
+                type.size = 0;
+                type.populateDefaultValue = () => { };
             });
 
         this._map.set(
-            "native typedef uint",
+            "native typedef bool",
             type => {
-                this.uint = type;
+                this.bool = type;
                 type.isPrimitive = true;
-                type.isInt = true;
-                type.isNumber = true;
-                type.isSigned = false;
-                type.canRepresent = value => isBitwiseEquivalent(value >>> 0, value);
                 type.size = 1;
-                type.defaultValue = 0;
-                type.createLiteral = (origin, value) => IntLiteral.withType(origin, value >>> 0, type);
-                type.successorValue = value => (value + 1) >>> 0;
-                type.valuesEqual = (a, b) => a === b;
-                type.populateDefaultValue = (buffer, offset) => buffer.set(offset, 0);
-                type.formatValueFromIntLiteral = value => value >>> 0;
-                type.formatValueFromUintLiteral = value => value >>> 0;
-                type.allValues = function*() { 
-                    for (let i = 0; i <= 0xffffffff; ++i)
-                        yield {value: i, name: i};
-                };
+                type.populateDefaultValue = (buffer, offset) => buffer.set(offset, false);
             });
 
         this._map.set(
             "native typedef uchar",
             type => {
                 this.uchar = type;
+                type.isPrimitive = true;
                 type.isInt = true;
                 type.isNumber = true;
                 type.isSigned = false;
@@ -126,149 +143,292 @@ class Intrinsics {
                 };
             });
 
+
+            this._map.set(
+             "native typedef ushort",
+             type => {
+                 this.ushort = type;
+                 type.isPrimitive = true;
+                 type.isInt = true;
+                 type.isNumber = true;
+                 type.isSigned = false;
+                 type.canRepresent = value => isBitwiseEquivalent(value & 0xffff, value);
+                 type.size = 1;
+                 type.defaultValue = 0;
+                 type.createLiteral = (origin, value) => IntLiteral.withType(origin, value & 0xffff, type);
+                 type.successorValue = value => (value + 1) & 0xffff;
+                 type.valuesEqual = (a, b) => a === b;
+                 type.populateDefaultValue = (buffer, offset) => buffer.set(offset, 0);
+                 type.formatValueFromIntLiteral = value => value & 0xffff;
+                 type.formatValueFromUintLiteral = value => value & 0xffff;
+                 type.allValues = function*() {
+                     for (let i = 0; i <= 0xffff; ++i)
+                         yield {value: i, name: i};
+                 };
+             });
+
         this._map.set(
-            "native typedef float",
-            type => {
-                this.float = type;
-                type.isPrimitive = true;
-                type.size = 1;
-                type.isFloating = true;
-                type.isNumber = true;
-                type.canRepresent = value => isBitwiseEquivalent(Math.fround(value), value);
-                type.populateDefaultValue = (buffer, offset) => buffer.set(offset, 0);
-                type.formatValueFromIntLiteral = value => value;
-                type.formatValueFromUintLiteral = value => value;
-                type.formatValueFromFloatLiteral = value => Math.fround(value);
-            });
+             "native typedef uint",
+             type => {
+                 this.uint = type;
+                 type.isPrimitive = true;
+                 type.isInt = true;
+                 type.isNumber = true;
+                 type.isSigned = false;
+                 type.canRepresent = value => isBitwiseEquivalent(value >>> 0, value);
+                 type.size = 1;
+                 type.defaultValue = 0;
+                 type.createLiteral = (origin, value) => IntLiteral.withType(origin, value >>> 0, type);
+                 type.successorValue = value => (value + 1) >>> 0;
+                 type.valuesEqual = (a, b) => a === b;
+                 type.populateDefaultValue = (buffer, offset) => buffer.set(offset, 0);
+                 type.formatValueFromIntLiteral = value => value >>> 0;
+                 type.formatValueFromUintLiteral = value => value >>> 0;
+                 type.allValues = function*() {
+                     for (let i = 0; i <= 0xffffffff; ++i)
+                         yield {value: i, name: i};
+                 };
+             });
 
         this._map.set(
-            "native typedef bool",
-            type => {
-                this.bool = type;
-                type.isPrimitive = true;
-                type.size = 1;
-                type.populateDefaultValue = (buffer, offset) => buffer.set(offset, false);
-            });
+             "native typedef char",
+             type => {
+                 this.char = type;
+                 type.isPrimitive = true;
+                 type.isInt = true;
+                 type.isNumber = true;
+                 type.isSigned = true;
+                 type.canRepresent = value => isBitwiseEquivalent(cast(Int8Array, value), value);
+                 type.size = 1;
+                 type.defaultValue = 0;
+                 type.createLiteral = (origin, value) => IntLiteral.withType(origin, cast(Int8Array, value), type);
+                 type.successorValue = value => cast(Int8Array, value + 1);
+                 type.valuesEqual = (a, b) => a === b;
+                 type.populateDefaultValue = (buffer, offset) => buffer.set(offset, 0);
+                 type.formatValueFromIntLiteral = value => cast(Int8Array, value);
+                 type.formatValueFromUintLiteral = value => cast(Int8Array, value);
+                 type.allValues = function*() {
+                     for (let i = 0; i <= 0xff; ++i) {
+                         let value = cast(Int8Array, i);
+                         yield {value: value, name: value};
+                     }
+                 };
+             });
+
+        this._map.set(
+             "native typedef short",
+             type => {
+                 this.short = type;
+                 type.isPrimitive = true;
+                 type.isInt = true;
+                 type.isNumber = true;
+                 type.isSigned = true;
+                 type.canRepresent = value => isBitwiseEquivalent(cast(Int16Array, value), value);
+                 type.size = 1;
+                 type.defaultValue = 0;
+                 type.createLiteral = (origin, value) => IntLiteral.withType(origin, cast(Int16Array, value), type);
+                 type.successorValue = value => cast(Int16Array, value + 1);
+                 type.valuesEqual = (a, b) => a === b;
+                 type.populateDefaultValue = (buffer, offset) => buffer.set(offset, 0);
+                 type.formatValueFromIntLiteral = value => cast(Int16Array, value);
+                 type.formatValueFromUintLiteral = value => cast(Int16Array, value);
+                 type.allValues = function*() {
+                     for (let i = 0; i <= 0xffff; ++i) {
+                         let value = cast(Int16Array, i);
+                         yield {value: value, name: value};
+                     }
+                 };
+             });
+
+        this._map.set(
+             "native typedef int",
+             type => {
+                 this.int = type;
+                 type.isPrimitive = true;
+                 type.isInt = true;
+                 type.isNumber = true;
+                 type.isSigned = true;
+                 type.canRepresent = value => isBitwiseEquivalent(value | 0, value);
+                 type.size = 1;
+                 type.defaultValue = 0;
+                 type.createLiteral = (origin, value) => IntLiteral.withType(origin, value | 0, type);
+                 type.successorValue = value => (value + 1) | 0;
+                 type.valuesEqual = (a, b) => a === b;
+                 type.populateDefaultValue = (buffer, offset) => buffer.set(offset, 0);
+                 type.formatValueFromIntLiteral = value => value | 0;
+                 type.formatValueFromUintLiteral = value => value | 0;
+                 type.allValues = function*() {
+                     for (let i = 0; i <= 0xffffffff; ++i) {
+                         let value = i | 0;
+                         yield {value: value, name: value};
+                     }
+                 };
+             });
+
+         this._map.set(
+             "native typedef half",
+             type => {
+                 this.half = type;
+                 type.isPrimitive = true;
+                 type.size = 1;
+                 type.isFloating = true;
+                 type.isNumber = true;
+                 type.canRepresent = value => isBitwiseEquivalent(castToHalf(value), value);
+                 type.populateDefaultValue = (buffer, offset) => buffer.set(offset, 0);
+                 type.formatValueFromIntLiteral = value => value;
+                 type.formatValueFromUintLiteral = value => value;
+                 type.formatValueFromFloatLiteral = value => castToHalf(value);
+             });
+
+         this._map.set(
+             "native typedef float",
+             type => {
+                 this.float = type;
+                 type.isPrimitive = true;
+                 type.size = 1;
+                 type.isFloating = true;
+                 type.isNumber = true;
+                 type.canRepresent = value => isBitwiseEquivalent(Math.fround(value), value);
+                 type.populateDefaultValue = (buffer, offset) => buffer.set(offset, 0);
+                 type.formatValueFromIntLiteral = value => value;
+                 type.formatValueFromUintLiteral = value => value;
+                 type.formatValueFromFloatLiteral = value => Math.fround(value);
+             });
+
+        this._map.set(
+             "native typedef atomic_int",
+             type => {
+                 this.atomic_int = type;
+             });
+
+        this._map.set(
+             "native typedef atomic_uint",
+             type => {
+                 this.atomic_uint = type;
+             });
 
         for (let vectorType of VectorElementTypes) {
-            for (let vectorSize of VectorElementSizes)
-                this._map.set(`native typedef vector<${vectorType}, ${vectorSize}>`, type => {});
+            for (let vectorSize of VectorElementSizes) {
+                this._map.set(`native typedef vector<${vectorType}, ${vectorSize}>`, type => {
+                    this[`vector<${vectorType}, ${vectorSize}>`] = type;
+                });
+            }
         }
-        
+
         this._map.set(
             "native operator int(uint)",
             func => {
                 func.implementation = ([value]) => EPtr.box(value.loadValue() | 0);
             });
-        
+
         this._map.set(
             "native operator int(uchar)",
             func => {
                 func.implementation = ([value]) => EPtr.box(value.loadValue() | 0);
             });
-        
+
         this._map.set(
             "native operator int(float)",
             func => {
                 func.implementation = ([value]) => EPtr.box(value.loadValue() | 0);
             });
-        
+
         this._map.set(
             "native operator uint(int)",
             func => {
                 func.implementation = ([value]) => EPtr.box(value.loadValue() >>> 0);
             });
-        
+
         this._map.set(
             "native operator uint(uchar)",
             func => {
                 func.implementation = ([value]) => EPtr.box(value.loadValue() >>> 0);
             });
-        
+
         this._map.set(
             "native operator uint(float)",
             func => {
                 func.implementation = ([value]) => EPtr.box(value.loadValue() >>> 0);
             });
-        
+
         this._map.set(
             "native operator uchar(int)",
             func => {
                 func.implementation = ([value]) => EPtr.box(value.loadValue() & 0xff);
             });
-        
+
         this._map.set(
             "native operator uchar(uint)",
             func => {
                 func.implementation = ([value]) => EPtr.box(value.loadValue() & 0xff);
             });
-        
+
         this._map.set(
             "native operator uchar(float)",
             func => {
                 func.implementation = ([value]) => EPtr.box(value.loadValue() & 0xff);
             });
-        
+
         this._map.set(
             "native operator float(int)",
             func => {
                 func.implementation = ([value]) => EPtr.box(Math.fround(value.loadValue()));
             });
-        
+
         this._map.set(
             "native operator float(uint)",
             func => {
                 func.implementation = ([value]) => EPtr.box(Math.fround(value.loadValue()));
             });
-        
+
         this._map.set(
             "native operator float(uchar)",
             func => {
                 func.implementation = ([value]) => EPtr.box(Math.fround(value.loadValue()));
             });
-        
+
         this._map.set(
             "native int operator+(int,int)",
             func => {
                 func.implementation = ([left, right]) =>
                     EPtr.box((left.loadValue() + right.loadValue()) | 0);
             });
-        
+
         this._map.set(
             "native uint operator+(uint,uint)",
             func => {
                 func.implementation = ([left, right]) =>
                     EPtr.box((left.loadValue() + right.loadValue()) >>> 0);
             });
-        
+
         this._map.set(
             "native float operator+(float,float)",
             func => {
                 func.implementation = ([left, right]) =>
                     EPtr.box(Math.fround(left.loadValue() + right.loadValue()));
             });
-        
+
         this._map.set(
             "native int operator-(int,int)",
             func => {
                 func.implementation = ([left, right]) =>
                     EPtr.box((left.loadValue() - right.loadValue()) | 0);
             });
-        
+
         this._map.set(
             "native uint operator-(uint,uint)",
             func => {
                 func.implementation = ([left, right]) =>
                     EPtr.box((left.loadValue() - right.loadValue()) >>> 0);
             });
-        
+
         this._map.set(
             "native float operator-(float,float)",
             func => {
                 func.implementation = ([left, right]) =>
                     EPtr.box(Math.fround(left.loadValue() - right.loadValue()));
             });
-        
+
         this._map.set(
             "native int operator*(int,int)",
             func => {
@@ -276,229 +436,229 @@ class Intrinsics {
                     return EPtr.box((left.loadValue() * right.loadValue()) | 0);
                 };
             });
-        
+
         this._map.set(
             "native uint operator*(uint,uint)",
             func => {
                 func.implementation = ([left, right]) =>
                     EPtr.box((left.loadValue() * right.loadValue()) >>> 0);
             });
-        
+
         this._map.set(
             "native float operator*(float,float)",
             func => {
                 func.implementation = ([left, right]) =>
                     EPtr.box(Math.fround(left.loadValue() * right.loadValue()));
             });
-        
+
         this._map.set(
             "native int operator/(int,int)",
             func => {
                 func.implementation = ([left, right]) =>
                     EPtr.box((left.loadValue() / right.loadValue()) | 0);
             });
-        
+
         this._map.set(
             "native uint operator/(uint,uint)",
             func => {
                 func.implementation = ([left, right]) =>
                     EPtr.box((left.loadValue() / right.loadValue()) >>> 0);
             });
-        
+
         this._map.set(
             "native int operator&(int,int)",
             func => {
                 func.implementation = ([left, right]) =>
                     EPtr.box(left.loadValue() & right.loadValue());
             });
-        
+
         this._map.set(
             "native uint operator&(uint,uint)",
             func => {
                 func.implementation = ([left, right]) =>
                     EPtr.box((left.loadValue() & right.loadValue()) >>> 0);
             });
-        
+
         this._map.set(
             "native int operator|(int,int)",
             func => {
                 func.implementation = ([left, right]) =>
                     EPtr.box(left.loadValue() | right.loadValue());
             });
-        
+
         this._map.set(
             "native uint operator|(uint,uint)",
             func => {
                 func.implementation = ([left, right]) =>
                     EPtr.box((left.loadValue() | right.loadValue()) >>> 0);
             });
-        
+
         this._map.set(
             "native int operator^(int,int)",
             func => {
                 func.implementation = ([left, right]) =>
                     EPtr.box(left.loadValue() ^ right.loadValue());
             });
-        
+
         this._map.set(
             "native uint operator^(uint,uint)",
             func => {
                 func.implementation = ([left, right]) =>
                     EPtr.box((left.loadValue() ^ right.loadValue()) >>> 0);
             });
-        
+
         this._map.set(
             "native int operator<<(int,uint)",
             func => {
                 func.implementation = ([left, right]) =>
                     EPtr.box(left.loadValue() << right.loadValue());
             });
-        
+
         this._map.set(
             "native uint operator<<(uint,uint)",
             func => {
                 func.implementation = ([left, right]) =>
                     EPtr.box((left.loadValue() << right.loadValue()) >>> 0);
             });
-        
+
         this._map.set(
             "native int operator>>(int,uint)",
             func => {
                 func.implementation = ([left, right]) =>
                     EPtr.box(left.loadValue() >> right.loadValue());
             });
-        
+
         this._map.set(
             "native uint operator>>(uint,uint)",
             func => {
                 func.implementation = ([left, right]) =>
                     EPtr.box(left.loadValue() >>> right.loadValue());
             });
-        
+
         this._map.set(
             "native int operator~(int)",
             func => {
                 func.implementation = ([value]) => EPtr.box(~value.loadValue());
             });
-        
+
         this._map.set(
             "native uint operator~(uint)",
             func => {
                 func.implementation = ([value]) => EPtr.box((~value.loadValue()) >>> 0);
             });
-        
+
         this._map.set(
             "native float operator/(float,float)",
             func => {
                 func.implementation = ([left, right]) =>
                     EPtr.box(Math.fround(left.loadValue() / right.loadValue()));
             });
-        
+
         this._map.set(
             "native bool operator==(int,int)",
             func => {
                 func.implementation = ([left, right]) =>
                     EPtr.box(left.loadValue() == right.loadValue());
             });
-        
+
         this._map.set(
             "native bool operator==(uint,uint)",
             func => {
                 func.implementation = ([left, right]) =>
                     EPtr.box(left.loadValue() == right.loadValue());
             });
-        
+
         this._map.set(
             "native bool operator==(bool,bool)",
             func => {
                 func.implementation = ([left, right]) =>
                     EPtr.box(left.loadValue() == right.loadValue());
             });
-        
+
         this._map.set(
             "native bool operator==(float,float)",
             func => {
                 func.implementation = ([left, right]) =>
                     EPtr.box(left.loadValue() == right.loadValue());
             });
-        
+
         this._map.set(
             "native bool operator<(int,int)",
             func => {
                 func.implementation = ([left, right]) =>
                     EPtr.box(left.loadValue() < right.loadValue());
             });
-        
+
         this._map.set(
             "native bool operator<(uint,uint)",
             func => {
                 func.implementation = ([left, right]) =>
                     EPtr.box(left.loadValue() < right.loadValue());
             });
-        
+
         this._map.set(
             "native bool operator<(float,float)",
             func => {
                 func.implementation = ([left, right]) =>
                     EPtr.box(left.loadValue() < right.loadValue());
             });
-        
+
         this._map.set(
             "native bool operator<=(int,int)",
             func => {
                 func.implementation = ([left, right]) =>
                     EPtr.box(left.loadValue() <= right.loadValue());
             });
-        
+
         this._map.set(
             "native bool operator<=(uint,uint)",
             func => {
                 func.implementation = ([left, right]) =>
                     EPtr.box(left.loadValue() <= right.loadValue());
             });
-        
+
         this._map.set(
             "native bool operator<=(float,float)",
             func => {
                 func.implementation = ([left, right]) =>
                     EPtr.box(left.loadValue() <= right.loadValue());
             });
-        
+
         this._map.set(
             "native bool operator>(int,int)",
             func => {
                 func.implementation = ([left, right]) =>
                     EPtr.box(left.loadValue() > right.loadValue());
             });
-        
+
         this._map.set(
             "native bool operator>(uint,uint)",
             func => {
                 func.implementation = ([left, right]) =>
                     EPtr.box(left.loadValue() > right.loadValue());
             });
-        
+
         this._map.set(
             "native bool operator>(float,float)",
             func => {
                 func.implementation = ([left, right]) =>
                     EPtr.box(left.loadValue() > right.loadValue());
             });
-        
+
         this._map.set(
             "native bool operator>=(int,int)",
             func => {
                 func.implementation = ([left, right]) =>
                     EPtr.box(left.loadValue() >= right.loadValue());
             });
-        
+
         this._map.set(
             "native bool operator>=(uint,uint)",
             func => {
                 func.implementation = ([left, right]) =>
                     EPtr.box(left.loadValue() >= right.loadValue());
             });
-        
+
         this._map.set(
             "native bool operator>=(float,float)",
             func => {
@@ -538,7 +698,7 @@ class Intrinsics {
         for (let setter of BuiltinVectorSetter.functions())
             this._map.set(setter.toString(), func => setter.instantiateImplementation(func));
     }
-    
+
     add(thing)
     {
         let intrinsic = this._map.get(thing.toString());
index 1bab3fc..dc68578 100644 (file)
@@ -69,11 +69,33 @@ class NameContext {
             return;
         }
 
+        if (thing.kind == Type) {
+            this._set.add(thing);
+            if (thing.name == "vector") {
+                let array = this._map.get(thing.name);
+                if (!array) {
+                    array = [];
+                    array.kind = Type;
+                    this._map.set(thing.name, array);
+                }
+                if (array.kind != Type)
+                    throw new WTypeError(thing.origin.originString, "Cannot reuse type name for function: " + thing.name);
+                array.push(thing);
+                return;
+            } else {
+                if (this._map.has(thing.name))
+                    throw new WTypeError(thing.origin.originString, "Duplicate name: " + thing.name);
+                this._map.set(thing.name, thing);
+            }
+            return;
+        }
+        
         if (this._map.has(thing.name))
             throw new WTypeError(thing.origin.originString, "Duplicate name: " + thing.name);
 
         this._set.add(thing);
         this._map.set(thing.name, thing);
+
     }
     
     get(kind, name)
@@ -102,6 +124,10 @@ class NameContext {
             for (let func of thing)
                 yield func;
             return;
+        } else if (thing.kind === Type && (thing instanceof Array)) {
+            for (let type of thing)
+                yield type;
+            return;
         }
         yield thing;
     }
@@ -163,8 +189,8 @@ class NameContext {
     {
         for (let value of this._map.values()) {
             if (value instanceof Array) {
-                for (let func of value)
-                    yield func;
+                for (let thing of value)
+                    yield thing;
                 continue;
             }
             yield value;
index f615a2f..9a099f4 100644 (file)
@@ -120,12 +120,19 @@ class NameResolver extends Visitor {
     
     visitTypeRef(node)
     {
+        super.visitTypeRef(node);
         let type = node.type;
         if (!type) {
             type = this._nameContext.get(Type, node.name);
             if (!type)
                 throw new WTypeError(node.origin.originString, "Could not find type named " + node.name);
-            node.type = type;
+            if (type instanceof Array) {
+                // Type unification requires the .type value to be set already, so we can eagerly set it now.
+                for (let overload of type)
+                    Node.visit(overload, this);
+                node.resolve(type);
+            } else
+                node.type = type;
         }
     }
     
@@ -208,9 +215,4 @@ class NameResolver extends Visitor {
         
         super.visitCallExpression(node);
     }
-
-    visitVectorType(node)
-    {
-        node.elementType.visit(this);
-    }
 }
index e2d851c..2381b5a 100644 (file)
 "use strict";
 
 class NativeType extends Type {
-    constructor(origin, name)
+    constructor(origin, name, typeArguments)
     {
+        if (!(typeArguments instanceof Array))
+            throw new Error("type parameters not array: " + typeArguments);
         super();
         this._origin = origin;
         this._name = name;
+        this._typeArguments = typeArguments;
         this._isNumber = false;
         this._isInt = false;
         this._isFloating = false;
@@ -38,6 +41,7 @@ class NativeType extends Type {
     
     get origin() { return this._origin; }
     get name() { return this._name; }
+    get typeArguments() { return this._typeArguments; }
     get isNative() { return true; }
     
     // We let Intrinsics.js set these as it likes.
@@ -52,19 +56,18 @@ class NativeType extends Type {
     
     toString()
     {
-        return `native typedef ${this.name}`;
+        let result = `native typedef ${this.name}`;
+        if (this.typeArguments.length)
+            result += "<" + this.typeArguments.join(",") + ">";
+        return result;
     }
     
     static create(origin, name, typeArguments)
     {
-        // FIXME: For native types like Texture1D this should resolve the type to something concrete by changing the type name.
-        if (typeArguments.length)
-            throw new WTypeError(origin.originString, `${name}<${typeArguments.join(",")}>: Support for native types with type arguments is currently unimplemented.`);
+        if (name == "vector")
+            return new VectorType(origin, name, typeArguments);
 
-        if (allVectorTypeNames().indexOf(name) > -1)
-            return new VectorType(origin, name);
-
-        return new NativeType(origin, name);
+        return new NativeType(origin, name, typeArguments);
     }
 }
 
index 7b16139..9faca86 100644 (file)
@@ -40,7 +40,6 @@ let prepare = (() => {
         }
         
         foldConstexprs(program);
-        removeTypeArguments(program);
 
         let nameResolver = createNameResolver(program);
         resolveNamesInTypes(program, nameResolver);
@@ -54,6 +53,7 @@ let prepare = (() => {
         synthesizeDefaultConstructorOperator(program);
         resolveNamesInFunctions(program, nameResolver);
         resolveTypeDefsInFunctions(program);
+        checkTypesWithArguments(program);
         
         check(program);
         checkLiteralTypes(program);
@@ -66,6 +66,7 @@ let prepare = (() => {
         checkLoops(program);
         checkRecursion(program);
         checkProgramWrapped(program);
+        checkTypesWithArguments(program);
         findHighZombies(program);
         program.visit(new StructLayoutBuilder());
         inline(program);
index 06625d9..1116c4f 100644 (file)
@@ -48,19 +48,25 @@ class Program extends Node {
         if (statement instanceof Func) {
             let array = this._functions.get(statement.name);
             if (!array)
-                this._functions.set(statement.name, array = []);
+                this.functions.set(statement.name, array = []);
             array.push(statement);
-        } else if (statement instanceof Type)
-            this._types.set(statement.name, statement);
-        else
+        } else if (statement instanceof Type) {
+            if (statement.isNative && statement.name == "vector") {
+                let array = this.types.get(statement.name);
+                if (!array)
+                    this.types.set(statement.name, array = []);
+                array.push(statement);
+            } else
+                this.types.set(statement.name, statement);
+        } else
             throw new Error("Statement is not a function or type: " + statement);
-        this._topLevelStatements.push(statement);
-        this._globalNameContext.add(statement);
+        this.topLevelStatements.push(statement);
+        this.globalNameContext.add(statement);
     }
     
     toString()
     {
-        if (!this._topLevelStatements.length)
+        if (!this.topLevelStatements.length)
             return "";
         return this._topLevelStatements.join(";") + ";";
     }
diff --git a/Tools/WebGPUShadingLanguageRI/RemoveTypeArguments.js b/Tools/WebGPUShadingLanguageRI/RemoveTypeArguments.js
deleted file mode 100644 (file)
index 93db9e6..0000000
+++ /dev/null
@@ -1,65 +0,0 @@
-/*
- * Copyright (C) 2018 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 removeTypeArguments(program)
-{
-    class RemoveTypeArguments extends Visitor {
-        static resolveNameAndArguments(node)
-        {
-            if (!node.typeArguments)
-                return node.name;
-
-            switch (node.name) {
-            case "vector":
-                if (node.typeArguments.length != 2)
-                    throw new WSyntaxError(node.originString, `${node.name} should have 2 type arguments, got ${node.typeArguments.length}.`);
-
-                const elementTypeName = node.typeArguments[0].name;
-                const lengthValue = node.typeArguments[1].value;
-
-                if (VectorElementTypes.indexOf(elementTypeName) < 0)
-                    throw new WSyntaxError(node.originString, `${elementTypeName} is not a valid vector element type.`);
-                if (VectorElementSizes.indexOf(lengthValue) < 0)
-                    throw new WSyntaxError(node.originString, `${lengthValue} is not a valid size for vectors with element type ${elementTypeName}.`);
-
-                return `${elementTypeName}${lengthValue}`;
-            // FIXME: Further cases for matrices, textures, etc.
-            default:
-                if (node.typeArguments.length)
-                    throw new WSyntaxError(`${node.name}${arguments.join(", ")} is not a permitted generic type or function`);
-                return node.name;
-            }
-        }
-
-        visitTypeRef(node)
-        {
-            node._name = RemoveTypeArguments.resolveNameAndArguments(node);
-            node._typeArguments = null;
-        }
-    }
-
-    program.visit(new RemoveTypeArguments());
-}
index 2e402c8..b8b5334 100644 (file)
@@ -31,8 +31,13 @@ function createNameResolver(program)
 
 function resolveNamesInTypes(program, nameResolver)
 {
-    for (let type of program.types.values())
-        nameResolver.doStatement(type);
+    for (let type of program.types.values()) {
+        if (type instanceof Array) {
+            for (let constituentType of type)
+                nameResolver.doStatement(constituentType);
+        } else
+            nameResolver.doStatement(type);
+    }
 }
 
 function resolveNamesInFunctions(program, nameResolver)
index d0f1e34..7a097bc 100644 (file)
@@ -100,3 +100,28 @@ function resolveOverloadImpl(functions, argumentTypes, returnType, allowEntryPoi
     
     return {failures: ambiguityList.map(overload => new OverloadResolutionFailure(overload.func, message))};
 }
+
+function resolveTypeOverloadImpl(types, typeArguments)
+{
+    if (!types)
+        throw new Error("Null types; that should have been caught by the caller.");
+
+    let failures = [];
+    let successes = [];
+    for (let type of types) {
+        let overload = inferTypesForTypeArguments(type, typeArguments);
+        if (overload.failure)
+            failures.push(overload.failure);
+        else
+            successes.push(overload);
+    }
+    
+    if (!successes.length)
+        return {failures: failures};
+    
+    if (successes.length == 1)
+        return successes[0];
+    
+    let message = "Ambiguous overload - types mutually applicable";
+    return {failures: successes.map(overload => new TypeOverloadResolutionFailure(overload.type, message))};
+}
index 9143f8e..0574bec 100644 (file)
 function resolveTypeDefsInTypes(program)
 {
     let resolver = new TypeDefResolver();
-    for (let type of program.types.values())
-        type.visit(resolver);
+    for (let type of program.types.values()) {
+        if (type instanceof Array) {
+            for (let constituentType of type)
+                constituentType.visit(resolver);
+        } else
+            type.visit(resolver);
+    }
 }
 
 function resolveTypeDefsInFunctions(program)
index d547d20..2901dd5 100644 (file)
@@ -97,7 +97,7 @@ class Rewriter {
     
     visitTypeRef(node)
     {
-        let result = new TypeRef(node.origin, node.name);
+        let result = new TypeRef(node.origin, node.name, node.typeArguments.map(argument => argument.visit(this)));
         if (node.type)
             result.type = Node.visit(node.type, this);
         return result;
@@ -382,7 +382,7 @@ class Rewriter {
 
     visitVectorType(node)
     {
-        const vecType = new VectorType(node.origin, node.name);
+        const vecType = new VectorType(node.origin, node.name, node.typeArguments.map(argument => argument.visit(this)));
         vecType._elementType = node.elementType.visit(this);
         return vecType;
     }
index c7b3940..20be7c8 100644 (file)
@@ -43,6 +43,7 @@ td {
     <script src="CheckRecursion.js"></script>
     <script src="CheckRecursiveTypes.js"></script>
     <script src="CheckReturns.js"></script>
+    <script src="CheckTypesWithArguments.js"></script>
     <script src="CheckUnreachableCode.js"></script>
     <script src="CheckWrapped.js"></script>
     <script src="Checker.js"></script>
@@ -116,7 +117,6 @@ td {
     <script src="ReadModifyWriteExpression.js"></script>
     <script src="RecursionChecker.js"></script>
     <script src="RecursiveTypeChecker.js"></script>
-    <script src="RemoveTypeArguments.js"></script>
     <script src="ResolveNames.js"></script>
     <script src="ResolveOverloadImpl.js"></script>
     <script src="ResolveProperties.js"></script>
@@ -140,6 +140,7 @@ td {
     <script src="TypeDef.js"></script>
     <script src="TypeDefResolver.js"></script>
     <script src="TypeRef.js"></script>
+    <script src="TypeOverloadResolutionFailure.js"></script>
     <script src="TypedValue.js"></script>
     <script src="UintLiteral.js"></script>
     <script src="UintLiteralType.js"></script>
index 06b251c..8190a43 100644 (file)
@@ -33,17 +33,70 @@ let standardLibrary = `
 native typedef void;
 native typedef bool;
 native typedef uchar;
+native typedef ushort;
 native typedef uint;
+native typedef char;
+native typedef short;
 native typedef int;
+native typedef half;
 native typedef float;
-
-// FIXME: Add support for these types to Intrinsics.js
-// native typedef ushort;
-// native typedef char;
-// native typedef short;
-// native typedef half;
-// native typedef atomic_int;
-// native typedef atomic_uint;
+native typedef atomic_int;
+native typedef atomic_uint;
+
+native typedef vector<bool, 2>;
+typedef bool2 = vector<bool, 2>;
+native typedef vector<bool, 3>;
+typedef bool3 = vector<bool, 3>;
+native typedef vector<bool, 4>;
+typedef bool4 = vector<bool, 4>;
+native typedef vector<uchar, 2>;
+typedef uchar2 = vector<uchar, 2>;
+native typedef vector<uchar, 3>;
+typedef uchar3 = vector<uchar, 3>;
+native typedef vector<uchar, 4>;
+typedef uchar4 = vector<uchar, 4>;
+native typedef vector<ushort, 2>;
+typedef ushort2 = vector<ushort, 2>;
+native typedef vector<ushort, 3>;
+typedef ushort3 = vector<ushort, 3>;
+native typedef vector<ushort, 4>;
+typedef ushort4 = vector<ushort, 4>;
+native typedef vector<uint, 2>;
+typedef uint2 = vector<uint, 2>;
+native typedef vector<uint, 3>;
+typedef uint3 = vector<uint, 3>;
+native typedef vector<uint, 4>;
+typedef uint4 = vector<uint, 4>;
+native typedef vector<char, 2>;
+typedef char2 = vector<char, 2>;
+native typedef vector<char, 3>;
+typedef char3 = vector<char, 3>;
+native typedef vector<char, 4>;
+typedef char4 = vector<char, 4>;
+native typedef vector<short, 2>;
+typedef short2 = vector<short, 2>;
+native typedef vector<short, 3>;
+typedef short3 = vector<short, 3>;
+native typedef vector<short, 4>;
+typedef short4 = vector<short, 4>;
+native typedef vector<int, 2>;
+typedef int2 = vector<int, 2>;
+native typedef vector<int, 3>;
+typedef int3 = vector<int, 3>;
+native typedef vector<int, 4>;
+typedef int4 = vector<int, 4>;
+native typedef vector<half, 2>;
+typedef half2 = vector<half, 2>;
+native typedef vector<half, 3>;
+typedef half3 = vector<half, 3>;
+native typedef vector<half, 4>;
+typedef half4 = vector<half, 4>;
+native typedef vector<float, 2>;
+typedef float2 = vector<float, 2>;
+native typedef vector<float, 3>;
+typedef float3 = vector<float, 3>;
+native typedef vector<float, 4>;
+typedef float4 = vector<float, 4>;
 
 native operator int(uint);
 native operator int(uchar);
@@ -147,28 +200,12 @@ bool operator~(bool value)
 {
     return !value;
 }
-
-native typedef uchar2;
-native typedef uchar3;
-native typedef uchar4;
-
-native typedef uint2;
-native typedef uint3;
-native typedef uint4;
-
-native typedef int2;
-native typedef int3;
-native typedef int4;
-
-native typedef float2;
-native typedef float3;
-native typedef float4;
 `;
 
 // FIXME: Once the standard library has been replaced with a new version, this comments should be removed.
 // This list is used to restrict the availability of vector types available in the langauge.
 // Permissible vector element types must appear in this list and in the standard library
-const VectorElementTypes = [ /*"bool",*/ "uchar", /*"char", "ushort", "short",*/ "uint", "int", /* "half", */"float" ];
+const VectorElementTypes = [ "bool", "uchar", "char", "ushort", "short", "uint", "int", "half", "float" ];
 const VectorElementSizes = [ 2, 3, 4 ];
 
 function allVectorTypeNames()
index b3948c4..0d0715a 100644 (file)
@@ -50,7 +50,7 @@ class StatementCloner extends Rewriter {
     
     visitNativeType(node)
     {
-        return new NativeType(node.origin, node.name);
+        return new NativeType(node.origin, node.name, node.typeArguments.map(argument => argument.visit(this)));
     }
     
     visitTypeDef(node)
index fefe9c0..3a3f767 100644 (file)
@@ -45,6 +45,12 @@ function synthesizeDefaultConstructorOperator(program)
             types.add(node);
             super.visitElementalType(node);
         }
+
+        visitVectorType(node)
+        {
+            types.add(node);
+            super.visitVectorType(node);
+        }
     }
 
     program.visit(new FindAllTypes());
index bfe6044..a018146 100644 (file)
@@ -51,7 +51,7 @@ function synthesizeStructAccessors(program)
             
             function createTypeRef()
             {
-                return TypeRef.instantiate(type);
+                return TypeRef.wrap(type);
             }
             
             let isCast = false;
index 13f3582..0de6941 100644 (file)
@@ -37,6 +37,7 @@
 <script src="CheckRecursion.js"></script>
 <script src="CheckRecursiveTypes.js"></script>
 <script src="CheckReturns.js"></script>
+<script src="CheckTypesWithArguments.js"></script>
 <script src="CheckUnreachableCode.js"></script>
 <script src="CheckWrapped.js"></script>
 <script src="Checker.js"></script>
 <script src="ReadModifyWriteExpression.js"></script>
 <script src="RecursionChecker.js"></script>
 <script src="RecursiveTypeChecker.js"></script>
-<script src="RemoveTypeArguments.js"></script>
 <script src="ResolveNames.js"></script>
 <script src="ResolveOverloadImpl.js"></script>
 <script src="ResolveProperties.js"></script>
 <script src="TypeDef.js"></script>
 <script src="TypeDefResolver.js"></script>
 <script src="TypeRef.js"></script>
+<script src="TypeOverloadResolutionFailure.js"></script>
 <script src="TypedValue.js"></script>
 <script src="UintLiteral.js"></script>
 <script src="UintLiteralType.js"></script>
index df417da..bffbcf0 100644 (file)
@@ -2881,7 +2881,7 @@ tests.shaderTypes = function()
             }
             fragment Boo bar(Foo stageIn)
             {
-                return boo();
+                return Boo();
             }
         `),
         (e) => e instanceof WTypeError);
@@ -2904,7 +2904,7 @@ tests.shaderTypes = function()
 
 tests.vectorTypeSyntax = function()
 {
-    const program = doPrep(`
+    let program = doPrep(`
         int foo2()
         {
             int2 x;
@@ -2939,7 +2939,26 @@ tests.vectorTypeSyntax = function()
     checkInt(program, callFunction(program, "foo2", []), 4);
     checkInt(program, callFunction(program, "foo3", []), 5);
     checkInt(program, callFunction(program, "foo4", []), 6);
+    checkBool(program, callFunction(program, "vec2OperatorCast", []), true);
+
+    program = doPrep(`
+        typedef i = int;
+        int foo2()
+        {
+            int2 x;
+            vector<i, 2> z = int2(3, 4);
+            x = z;
+            return x.y;
+        }
+
+        bool vec2OperatorCast()
+        {
+            int2 x = vector<i,2>(1, 2);
+            vector<i, 2> y = int2(1, 2);
+            return x == y && x.x == 1 && x.y == 2 && y.x == 1 && y.y == 2;
+        }`);
 
+    checkInt(program, callFunction(program, "foo2", []), 4);
     checkBool(program, callFunction(program, "vec2OperatorCast", []), true);
 }
 
diff --git a/Tools/WebGPUShadingLanguageRI/TypeOverloadResolutionFailure.js b/Tools/WebGPUShadingLanguageRI/TypeOverloadResolutionFailure.js
new file mode 100644 (file)
index 0000000..d5cb3f7
--- /dev/null
@@ -0,0 +1,42 @@
+/*
+ * Copyright (C) 2018 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";
+
+class TypeOverloadResolutionFailure {
+    constructor(type, reason)
+    {
+        this._type = type;
+        this._reason = reason;
+    }
+    
+    get type() { return this._type; }
+    get reason() { return this._reason; }
+    
+    toString()
+    {
+        return this.type.toString() + " did not match because: " + this.reason;
+    }
+}
+
index b5f3c0b..acda706 100644 (file)
@@ -25,7 +25,7 @@
 "use strict";
 
 class TypeRef extends Type {
-    constructor(origin, name, typeArguments = null)
+    constructor(origin, name, typeArguments = [])
     {
         super();
         this._origin = origin;
@@ -38,14 +38,11 @@ class TypeRef extends Type {
     {
         if (type instanceof TypeRef)
             return type;
-        let result = new TypeRef(type.origin, type.name);
-        result.type = type;
-        return result;
-    }
-    
-    static instantiate(type)
-    {
-        let result = new TypeRef(type.origin, type.name);
+        let result;
+        if (type instanceof NativeType)
+            result = new TypeRef(type.origin, type.name, type.typeArguments);
+        else
+            result = new TypeRef(type.orgin, type.name);
         result.type = type;
         return result;
     }
@@ -64,6 +61,39 @@ class TypeRef extends Type {
         this._type = newType;
     }
 
+    resolve(possibleOverloads)
+    {
+        if (!possibleOverloads)
+            throw new WTypeError(this.origin.originString, "Did not find any types named " + this.name);
+
+        let failures = [];
+        let overload = resolveTypeOverloadImpl(possibleOverloads, this.typeArguments);
+
+        if (!overload.type) {
+            failures.push(...overload.failures);
+            let message = "Did not find type named " + this.name + " for type arguments ";
+            message += "(" + this.typeArguments + ")";
+            if (failures.length)
+                message += ", but considered:\n" + failures.join("\n")
+            throw new WTypeError(this.origin.originString, message);
+        }
+
+        for (let i = 0; i < this.typeArguments.length; ++i) {
+            let typeArgument = this.typeArguments[i];
+            let resolvedTypeArgument = overload.type.typeArguments[i];
+            let result = typeArgument.equalsWithCommit(resolvedTypeArgument);
+            if (!result)
+                throw new Error("At " + this.origin.originString + " argument types for Type and TypeRef not equal: argument type = " + typeArgument + ", resolved type argument = " + resolvedTypeArgument);
+            if (resolvedTypeArgument.constructor.name == "GenericLiteral") {
+                result = typeArgument.type.equalsWithCommit(resolvedTypeArgument.type);
+                if (!result)
+                    throw new Error("At " + this.origin.originString + " argument types for Type and TypeRef not equal: argument type = " + typeArgument + ", resolved type argument = " + resolvedTypeArgument);
+            }
+                
+        }
+        this.type = overload.type;
+    }
+
     get unifyNode()
     {
         if (!this.type)
@@ -99,7 +129,10 @@ class TypeRef extends Type {
     {
         if (!this.name)
             return this.type.toString();
-        return this.name;
+        let result = this.name;
+        if (this.typeArguments.length > 0)
+            result += "<" + this.typeArguments.map(argument => argument.toString()).join(",") + ">";
+        return result;
     }
 }
 
index 2f71547..3819169 100644 (file)
@@ -92,6 +92,19 @@ class UnificationContext {
     
     verify()
     {
+        // We do a two-phase pre-verification. This gives literals a chance to select a more specific type.
+        let preparations = [];
+        for (let node of this.nodes) {
+            let preparation = node.prepareToVerify(this);
+            if (preparation)
+                preparations.push(preparation);
+        }
+        for (let preparation of preparations) {
+            let result = preparation();
+            if (!result.result)
+                return result;
+        }
+
         for (let typeArgument of this.typeArguments()) {
             let result = typeArgument.verifyAsArgument(this);
             if (!result.result)
index 5014c67..df0cbc2 100644 (file)
 "use strict";
 
 class VectorType extends NativeType {
-    constructor(origin, name)
+    constructor(origin, name, typeArguments)
     {
-        super(origin, name);
-        const match = /^([A-z]+)([0-9])$/.exec(name);
-        if (!match)
-            throw new WTypeError(origin.originString, `${name} doesn't match the format for vector type names.'`);
-
-        this._elementType = new TypeRef(origin, match[1]);
-        this._numElementsValue = parseInt(match[2]);
+        super(origin, name, typeArguments);
     }
 
-    get elementType() { return this._elementType; }
-    get numElementsValue() { return this._numElementsValue; }
+    get elementType() { return this.typeArguments[0]; }
+    get numElements() { return this.typeArguments[1]; }
+    get numElementsValue() { return this.numElements.value; }
     get size() { return this.elementType.size * this.numElementsValue; }
 
     unifyImpl(unificationContext, other)
@@ -59,7 +54,7 @@ class VectorType extends NativeType {
 
     toString()
     {
-        return `native typedef ${this.elementType}${this.numElementsValue}`;
+        return `native typedef vector<${this.elementType}, ${this.numElementsValue}>`;
     }
 }
 
index 7d387b2..60dfceb 100644 (file)
@@ -68,10 +68,14 @@ class Visitor {
     
     visitTypeRef(node)
     {
+        for (let typeArgument of node.typeArguments)
+            typeArgument.visit(this);
     }
     
     visitNativeType(node)
     {
+        for (let typeArgument of node.typeArguments)
+            typeArgument.visit(this);
     }
     
     visitTypeDef(node)
@@ -327,6 +331,7 @@ class Visitor {
     visitVectorType(node)
     {
         node.elementType.visit(this);
+        node.numElements.visit(this);
     }
 }
 
index 4c93a33..9c31ce9 100644 (file)
@@ -38,6 +38,7 @@
 <script src="CheckRecursiveTypes.js"></script>
 <script src="CheckReturns.js"></script>
 <script src="CheckUnreachableCode.js"></script>
+<script src="CheckTypesWithArguments.js"></script>
 <script src="CheckWrapped.js"></script>
 <script src="Checker.js"></script>
 <script src="CloneProgram.js"></script>
 <script src="ReadModifyWriteExpression.js"></script>
 <script src="RecursionChecker.js"></script>
 <script src="RecursiveTypeChecker.js"></script>
-<script src="RemoveTypeArguments.js"></script>
 <script src="ResolveNames.js"></script>
 <script src="ResolveOverloadImpl.js"></script>
 <script src="ResolveProperties.js"></script>
 <script src="TypeDef.js"></script>
 <script src="TypeDefResolver.js"></script>
 <script src="TypeRef.js"></script>
+<script src="TypeOverloadResolutionFailure.js"></script>
 <script src="TypedValue.js"></script>
 <script src="UintLiteral.js"></script>
 <script src="UintLiteralType.js"></script>