Diff
Modified: trunk/Tools/ChangeLog (221433 => 221434)
--- trunk/Tools/ChangeLog 2017-08-31 19:20:36 UTC (rev 221433)
+++ trunk/Tools/ChangeLog 2017-08-31 19:33:35 UTC (rev 221434)
@@ -1,3 +1,75 @@
+2017-08-30 Filip Pizlo <fpi...@apple.com>
+
+ WSL should be able to run a program that uses generics
+ https://bugs.webkit.org/show_bug.cgi?id=176152
+
+ Reviewed by Keith Miller.
+
+ This fixes the WSL parser and type checker to the point that we can:
+
+ - Parse a function call!
+ - Type check a generic function call with an inferred type parameter.
+ - Instantiate a generic function.
+ - Inline a function call.
+ - Evaluate an inlined function call.
+
+ This also changes the test suite so that it's a little nicer to add new tests. Functions whose
+ names start with "TEST_" are tests.
+
+ * WebGPUShadingLanguageRI/Checker.js:
+ (Checker.prototype.visitProtocolDecl.set throw):
+ * WebGPUShadingLanguageRI/EBufferBuilder.js:
+ (EBufferBuilder.prototype.visitFuncParameter):
+ (EBufferBuilder):
+ * WebGPUShadingLanguageRI/Evaluator.js:
+ (Evaluator.prototype.visitFunctionLikeBlock):
+ * WebGPUShadingLanguageRI/FuncDef.js:
+ (FuncDef.prototype.toString):
+ (FuncDef):
+ * WebGPUShadingLanguageRI/FuncInstantiator.js:
+ (FuncInstantiator.prototype.getUnique):
+ (FuncInstantiator):
+ * WebGPUShadingLanguageRI/Inliner.js:
+ (Inliner.prototype.visitCallExpression):
+ (Inliner):
+ * WebGPUShadingLanguageRI/Lexer.js:
+ (Lexer):
+ * WebGPUShadingLanguageRI/NameContext.js:
+ (NameContext):
+ (NameContext.prototype.add):
+ (NameContext.prototype.get let):
+ (NameContext.prototype.defineAll):
+ (NameContext.get intrinsics): Deleted.
+ (NameContext.set program): Deleted.
+ (NameContext.get program): Deleted.
+ * WebGPUShadingLanguageRI/NameResolver.js:
+ (NameResolver.prototype.visitProgram):
+ * WebGPUShadingLanguageRI/Parse.js:
+ (parseTerm):
+ (parsePossibleSuffix):
+ (genericParseCommaExpression):
+ (parseReturn):
+ * WebGPUShadingLanguageRI/Program.js:
+ (Program.prototype.resolveFuncOverload):
+ * WebGPUShadingLanguageRI/ProtocolDecl.js:
+ (ProtocolDecl.prototype.inherits):
+ * WebGPUShadingLanguageRI/ResolveOverloadImpl.js:
+ (resolveOverloadImpl):
+ * WebGPUShadingLanguageRI/Rewriter.js:
+ (Rewriter.prototype.visitFuncParameter):
+ (Rewriter.prototype.visitCallExpression):
+ (Rewriter.prototype._map): Deleted.
+ * WebGPUShadingLanguageRI/Test.js:
+ (checkInt):
+ (TEST_add1):
+ (TEST_simpleGeneric):
+ (let.s.in.this.s.startsWith):
+ (load): Deleted.
+ * WebGPUShadingLanguageRI/TypeVariable.js:
+ (TypeVariable.prototype.typeVariableUnify):
+ * WebGPUShadingLanguageRI/UnificationContext.js:
+ (UnificationContext.prototype.union):
+
2017-08-30 Alex Christensen <achristen...@webkit.org>
Add WKUIDelegatePrivate equivalent of WKPageUIClient's didClickAutoFillButton
Modified: trunk/Tools/WebGPUShadingLanguageRI/Checker.js (221433 => 221434)
--- trunk/Tools/WebGPUShadingLanguageRI/Checker.js 2017-08-31 19:20:36 UTC (rev 221433)
+++ trunk/Tools/WebGPUShadingLanguageRI/Checker.js 2017-08-31 19:33:35 UTC (rev 221434)
@@ -165,6 +165,7 @@
});
let overload = null;
+ let failures = [];
for (let typeParameter of this._currentStatement.typeParameters) {
if (!(typeParameter instanceof TypeVariable))
continue;
@@ -175,15 +176,25 @@
if (!signatures)
continue;
overload = resolveOverloadImpl(signatures, node.typeArguments, argumentTypes);
- if (overload)
+ if (overload.func)
break;
+ failures.push(...overload.failures);
+ overload = null;
}
if (!overload) {
overload = this._program.resolveFuncOverload(
node.name, node.typeArguments, argumentTypes);
+ if (!overload.func) {
+ failures.push(...overload.failures);
+ let message = "Did not find function for call";
+ if (failures.length) {
+ let stringifyFailure =
+ failure => failure.func + " did not match because: " + failure.reason;
+ message += ", but considered:\n" + failures.map(stringifyFailure).join("\n")
+ }
+ throw new WTypeError(node.origin.originString, message);
+ }
}
- if (!overload)
- throw new WTypeError(node.origin.originString, "Did not find function for call");
node.func = overload.func;
node.actualTypeArguments = overload.typeArguments.map(TypeRef.wrap);
let result = overload.func.returnType.substituteToUnification(
Modified: trunk/Tools/WebGPUShadingLanguageRI/EBufferBuilder.js (221433 => 221434)
--- trunk/Tools/WebGPUShadingLanguageRI/EBufferBuilder.js 2017-08-31 19:20:36 UTC (rev 221433)
+++ trunk/Tools/WebGPUShadingLanguageRI/EBufferBuilder.js 2017-08-31 19:33:35 UTC (rev 221434)
@@ -41,6 +41,8 @@
visitFuncParameter(node)
{
+ if (!node.type)
+ throw new Error("Func parameter has no type: " + node);
node.ePtr = this._createEPtr(node.type);
}
}
Modified: trunk/Tools/WebGPUShadingLanguageRI/Evaluator.js (221433 => 221434)
--- trunk/Tools/WebGPUShadingLanguageRI/Evaluator.js 2017-08-31 19:20:36 UTC (rev 221433)
+++ trunk/Tools/WebGPUShadingLanguageRI/Evaluator.js 2017-08-31 19:33:35 UTC (rev 221434)
@@ -51,8 +51,8 @@
visitFunctionLikeBlock(node)
{
for (let i = 0; i < node.argumentList.length; ++i)
- node.parameters[i].lValue.value = node.argumentList[i].visit(this);
- return visitFunctionBody(node.block);
+ node.parameters[i].ePtr.copyFrom(node.argumentList[i].visit(this));
+ return this.visitFunctionBody(node.body);
}
visitReturn(node)
Modified: trunk/Tools/WebGPUShadingLanguageRI/FuncDef.js (221433 => 221434)
--- trunk/Tools/WebGPUShadingLanguageRI/FuncDef.js 2017-08-31 19:20:36 UTC (rev 221433)
+++ trunk/Tools/WebGPUShadingLanguageRI/FuncDef.js 2017-08-31 19:33:35 UTC (rev 221434)
@@ -36,7 +36,7 @@
toString()
{
- return super.toString() + " { " + this.body + " }";
+ return super.toString() + " " + this.body;
}
}
Modified: trunk/Tools/WebGPUShadingLanguageRI/FuncInstantiator.js (221433 => 221434)
--- trunk/Tools/WebGPUShadingLanguageRI/FuncInstantiator.js 2017-08-31 19:20:36 UTC (rev 221433)
+++ trunk/Tools/WebGPUShadingLanguageRI/FuncInstantiator.js 2017-08-31 19:33:35 UTC (rev 221434)
@@ -37,8 +37,8 @@
return func;
let instances = this._instances.get(func);
- if (!functions)
- this._functions.set(func, functions = []);
+ if (!instances)
+ this._instances.set(func, instances = []);
for (let instance of instances) {
let ok = true;
@@ -62,7 +62,7 @@
func.body.visit(substitution));
let instance = {func: resultingFunc, typeArguments};
instances.push(instance);
- return func;
+ return resultingFunc;
}
}
Modified: trunk/Tools/WebGPUShadingLanguageRI/Inliner.js (221433 => 221434)
--- trunk/Tools/WebGPUShadingLanguageRI/Inliner.js 2017-08-31 19:20:36 UTC (rev 221433)
+++ trunk/Tools/WebGPUShadingLanguageRI/Inliner.js 2017-08-31 19:33:35 UTC (rev 221434)
@@ -35,7 +35,7 @@
visitCallExpression(node)
{
if (node.func.isNative)
- return node;
+ return super.visitCallExpression(node);
return this._visiting.doVisit(node.func, () => {
let func = this._program.funcInstantiator.getUnique(node.func, node.actualTypeArguments);
_inlineFunction(this._program, func, this._visiting);
Modified: trunk/Tools/WebGPUShadingLanguageRI/Lexer.js (221433 => 221434)
--- trunk/Tools/WebGPUShadingLanguageRI/Lexer.js 2017-08-31 19:20:36 UTC (rev 221433)
+++ trunk/Tools/WebGPUShadingLanguageRI/Lexer.js 2017-08-31 19:33:35 UTC (rev 221434)
@@ -154,4 +154,19 @@
throw e;
}
}
+
+ testScope(callback)
+ {
+ let state = this.state;
+ try {
+ callback();
+ return true;
+ } catch (e) {
+ if (e instanceof WSyntaxError)
+ return false;
+ throw e;
+ } finally {
+ this.state = state;
+ }
+ }
}
Modified: trunk/Tools/WebGPUShadingLanguageRI/NameContext.js (221433 => 221434)
--- trunk/Tools/WebGPUShadingLanguageRI/NameContext.js 2017-08-31 19:20:36 UTC (rev 221433)
+++ trunk/Tools/WebGPUShadingLanguageRI/NameContext.js 2017-08-31 19:33:35 UTC (rev 221434)
@@ -36,7 +36,8 @@
{
this._funcMap = new Map();
this._map = new Map();
- this._defined = new Set();
+ this._set = new Set();
+ this._defined = null;
this._currentStatement = null;
this._delegate = delegate;
this._intrinsics = null;
@@ -70,6 +71,7 @@
}
if (thing.kind == Func) {
+ this._set.add(thing);
let array = this._funcMap.get(thing.name);
if (!array)
this._funcMap.set(thing.name, array = []);
@@ -78,6 +80,7 @@
}
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);
}
@@ -100,10 +103,18 @@
return null;
}
+ handleDefining()
+ {
+ this._defined = new Set();
+ }
+
isDefined(thing)
{
- return this._defined.has(thing)
- || (this._delegate && this._delegate.isDefined(thing));
+ if (this._set.has(thing)) {
+ return !this._defined
+ || this._defined.has(thing);
+ }
+ return this._delegate && this._delegate.isDefined(thing);
}
define(thing)
@@ -113,8 +124,7 @@
defineAll()
{
- for (let thing of this)
- this.define(thing);
+ this._defined = null;
}
doStatement(statement, callback)
Modified: trunk/Tools/WebGPUShadingLanguageRI/NameResolver.js (221433 => 221434)
--- trunk/Tools/WebGPUShadingLanguageRI/NameResolver.js 2017-08-31 19:20:36 UTC (rev 221433)
+++ trunk/Tools/WebGPUShadingLanguageRI/NameResolver.js 2017-08-31 19:33:35 UTC (rev 221434)
@@ -43,6 +43,7 @@
let nameContext = new NameContext(this._nameContext);
nameContext.program = node;
nameContext.recognizeIntrinsics();
+ nameContext.handleDefining();
node.intrinsics = nameContext.intrinsics;
for (let statement of node.topLevelStatements)
nameContext.add(statement);
Modified: trunk/Tools/WebGPUShadingLanguageRI/Parse.js (221433 => 221434)
--- trunk/Tools/WebGPUShadingLanguageRI/Parse.js 2017-08-31 19:20:36 UTC (rev 221433)
+++ trunk/Tools/WebGPUShadingLanguageRI/Parse.js 2017-08-31 19:33:35 UTC (rev 221434)
@@ -177,9 +177,15 @@
lexer.fail("Integer literal is not 32-bit integer");
return new IntLiteral(token.origin, intVersion);
}
+ if (token = tryConsumeKind("doubleLiteral")) {
+ token = consumeKind("doubleLiteral");
+ return new DoubleLiteral(token.origin, +token.text);
+ }
// FIXME: Need support for float literals and probably other literals too.
- token = consumeKind("doubleLiteral");
- return new DoubleLiteral(token.origin, +token.text);
+ consume("(");
+ let result = parseExpression();
+ consume(")");
+ return result;
}
function parseConstexpr()
@@ -336,42 +342,46 @@
break;
}
consume(")");
- return new CallExpression(name.origin, name, typeArguments, argumentList);
+ return new CallExpression(name.origin, name.text, typeArguments, argumentList);
}
function parsePossibleSuffix()
{
- let simpleCase = lexer.backtrackingScope(() => {
- let left = parseTerm();
- let token;
- while (token = tryConsume("++", "--", ".", "->", "[")) {
- switch (token.text) {
- case "++":
- case "--":
- left = new SuffixCallAssignment(token.origin, "operator" + token.text, left);
- break;
- case ".":
- case "->":
- if (token.text == "->")
- left = new DereferenceExpression(token.origin, left);
- left = new DotExpression(token.origin, left, consumeKind("identifier"));
- break;
- case "[": {
- let index = parseExpression();
- consume("]");
- left = new IndexExpression(token.origin, left, index);
- break;
- }
- default:
- throw new Error("Bad token: " + token);
- }
- }
- return left;
+ // First check if this is a call _expression_.
+ let isCallExpression = lexer.testScope(() => {
+ consumeKind("identifier");
+ parseTypeArguments();
+ consume("(");
});
- if (simpleCase)
- return simpleCase;
- return parseCallExpression();
+ if (isCallExpression)
+ return parseCallExpression();
+
+ let left = parseTerm();
+ let token;
+ while (token = tryConsume("++", "--", ".", "->", "[")) {
+ switch (token.text) {
+ case "++":
+ case "--":
+ left = new SuffixCallAssignment(token.origin, "operator" + token.text, left);
+ break;
+ case ".":
+ case "->":
+ if (token.text == "->")
+ left = new DereferenceExpression(token.origin, left);
+ left = new DotExpression(token.origin, left, consumeKind("identifier"));
+ break;
+ case "[": {
+ let index = parseExpression();
+ consume("]");
+ left = new IndexExpression(token.origin, left, index);
+ break;
+ }
+ default:
+ throw new Error("Bad token: " + token);
+ }
+ }
+ return left;
}
function parsePossiblePrefix()
@@ -497,7 +507,10 @@
lexer.fail("Unexpected end of file");
origin = origin.origin;
for (;;) {
- let effectfulExpression = lexer.backtrackingScope(parseEffectfulExpression);
+ let effectfulExpression = lexer.backtrackingScope(() => {
+ parseEffectfulExpression();
+ consume(",");
+ });
if (!effectfulExpression) {
let final = finalExpressionParser();
list.push(final);
@@ -504,8 +517,6 @@
break;
}
list.push(effectfulExpression);
- if (!tryConsume(","))
- break;
}
return new CommaExpression(origin, list);
}
@@ -530,7 +541,9 @@
function parseReturn()
{
let origin = consume("return").origin;
- return new Return(origin, parseExpression());
+ let _expression_ = parseExpression();
+ consume(";");
+ return new Return(origin, _expression_);
}
function parseVariableDecls()
Modified: trunk/Tools/WebGPUShadingLanguageRI/Program.js (221433 => 221434)
--- trunk/Tools/WebGPUShadingLanguageRI/Program.js 2017-08-31 19:20:36 UTC (rev 221433)
+++ trunk/Tools/WebGPUShadingLanguageRI/Program.js 2017-08-31 19:33:35 UTC (rev 221434)
@@ -58,7 +58,7 @@
{
let functions = this.functions.get(name);
if (!functions)
- return null;
+ return {failures: []};
return resolveOverloadImpl(functions, typeArguments, argumentTypes);
}
Modified: trunk/Tools/WebGPUShadingLanguageRI/ProtocolDecl.js (221433 => 221434)
--- trunk/Tools/WebGPUShadingLanguageRI/ProtocolDecl.js 2017-08-31 19:20:36 UTC (rev 221433)
+++ trunk/Tools/WebGPUShadingLanguageRI/ProtocolDecl.js 2017-08-31 19:33:35 UTC (rev 221434)
@@ -68,7 +68,7 @@
if (!signatures)
return false;
let overload = resolveOverloadImpl(signatures, [], otherSignature.parameterTypes);
- if (!overload)
+ if (!overload.func)
return false;
let substitutedReturnType =
overload.func.returnType.substituteToUnification(
Modified: trunk/Tools/WebGPUShadingLanguageRI/ResolveOverloadImpl.js (221433 => 221434)
--- trunk/Tools/WebGPUShadingLanguageRI/ResolveOverloadImpl.js 2017-08-31 19:20:36 UTC (rev 221433)
+++ trunk/Tools/WebGPUShadingLanguageRI/ResolveOverloadImpl.js 2017-08-31 19:33:35 UTC (rev 221434)
@@ -26,11 +26,16 @@
function resolveOverloadImpl(functions, typeArguments, argumentTypes)
{
+ let failures = [];
for (let func of functions) {
- if (typeArguments.length && typeArguments.length != func.typeParameters.length)
+ if (typeArguments.length && typeArguments.length != func.typeParameters.length) {
+ failures.push({func, reason: "Wrong number of type arguments (passed " + typeArguments.length + ", require " + func.typeParameters.length + ")"});
continue;
- if (argumentTypes.length != func.parameters.length)
+ }
+ if (argumentTypes.length != func.parameters.length) {
+ failures.push({func, reason: "Wrong number of arguments (passed " + argumentTypes.length + ", require " + func.parameters.length + ")"});
continue;
+ }
let unificationContext = new UnificationContext(func.typeParameters);
let ok = true;
for (let i = 0; i < typeArguments.length; ++i) {
@@ -37,6 +42,7 @@
let argument = typeArguments[i];
let parameter = func.typeParameters[i];
if (!argument.unify(unificationContext, parameter)) {
+ failures.push({func, reason: "Type argument #" + (i + 1) + " for parameter " + func.typeParameters.name + " does not match (passed " + argument + ", require " + parameter + ")"});
ok = false;
break;
}
@@ -47,6 +53,7 @@
if (!argumentTypes[i])
throw new Error("Null argument type at i = " + i);
if (!argumentTypes[i].unify(unificationContext, func.parameters[i].type)) {
+ failures.push({func, reason: "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;
}
@@ -53,8 +60,10 @@
}
if (!ok)
continue;
- if (!unificationContext.verify())
+ if (!unificationContext.verify()) {
+ failures.push({func, reason: "Violates type variable constraints"});
continue;
+ }
let shouldBuildTypeArguments = !typeArguments.length;
if (shouldBuildTypeArguments)
typeArguments = [];
@@ -61,6 +70,7 @@
for (let typeParameter of func.typeParameters) {
let typeArgument = unificationContext.find(typeParameter);
if (typeArgument == typeParameter) {
+ failures.push({func, reason: "Type parameter " + typeParameter + " did not get assigned a type"});
ok = false;
break;
}
@@ -72,5 +82,5 @@
return {func, unificationContext, typeArguments};
}
- return null;
+ return {failures: failures};
}
Modified: trunk/Tools/WebGPUShadingLanguageRI/Rewriter.js (221433 => 221434)
--- trunk/Tools/WebGPUShadingLanguageRI/Rewriter.js 2017-08-31 19:20:36 UTC (rev 221433)
+++ trunk/Tools/WebGPUShadingLanguageRI/Rewriter.js 2017-08-31 19:33:35 UTC (rev 221434)
@@ -30,7 +30,7 @@
this._mapping = new Map();
}
- _map(oldItem, newItem)
+ _mapNode(oldItem, newItem)
{
this._mapping.set(oldItem, newItem);
return newItem;
@@ -54,8 +54,8 @@
visitFuncParameter(node)
{
- let result = new FuncParameter(node.name, node.type.visit(this));
- this._map(node, result);
+ let result = new FuncParameter(node.origin, node.name, node.type.visit(this));
+ this._mapNode(node, result);
result.lValue = node.lValue;
return result;
}
@@ -151,12 +151,13 @@
let result = new CallExpression(
node.origin, node.name,
node.typeArguments.map(typeArgument => typeArgument.visit(this)),
- node.argumentlist.map(argument => argument.visit(this)));
+ node.argumentList.map(argument => argument.visit(this)));
let actualTypeArguments = node.actualTypeArguments;
if (actualTypeArguments) {
result.actualTypeArguments =
actualTypeArguments.map(actualTypeArgument => actualTypeArgument.visit(this));
}
+ result.func = node.func;
return result;
}
Modified: trunk/Tools/WebGPUShadingLanguageRI/Test.js (221433 => 221434)
--- trunk/Tools/WebGPUShadingLanguageRI/Test.js 2017-08-31 19:20:36 UTC (rev 221433)
+++ trunk/Tools/WebGPUShadingLanguageRI/Test.js 2017-08-31 19:33:35 UTC (rev 221434)
@@ -26,12 +26,37 @@
load("All.js");
+function checkInt(result, expected)
{
- let program = prepare("<test>", 0, "int foo(int x) { return x + 1; }");
- let result = callFunction(program, "foo", [], [new EInt(program.intrinsics.int32, 42)]);
if (!(result instanceof EInt))
throw new Error("Wrong result type; result: " + result);
- if (result.value != 43)
- throw new Error("Wrong result: " + result);
+ if (result.value != expected)
+ throw new Error("Wrong result: " + result + " (expected " + expected + ")");
}
+function TEST_add1() {
+ let program = prepare("<test>", 0, "int foo(int x) { return x + 1; }");
+ checkInt(callFunction(program, "foo", [], [new EInt(program.intrinsics.int32, 42)]), 43);
+}
+
+function TEST_simpleGeneric() {
+ let program = prepare(
+ "<test>", 0,
+ `T id<T>(T x) { return x; }
+ int foo(int x) { return id(x) + 1; }`);
+ checkInt(callFunction(program, "foo", [], [new EInt(program.intrinsics.int32, 42)]), 43);
+}
+
+let before = preciseTime();
+
+for (let s in this) {
+ if (s.startsWith("TEST_")) {
+ print(s + "...");
+ this[s]();
+ print(" OK!");
+ }
+}
+
+let after = preciseTime();
+
+print("That took " + (after - before) * 1000 + " ms.");
Modified: trunk/Tools/WebGPUShadingLanguageRI/TypeVariable.js (221433 => 221434)
--- trunk/Tools/WebGPUShadingLanguageRI/TypeVariable.js 2017-08-31 19:20:36 UTC (rev 221433)
+++ trunk/Tools/WebGPUShadingLanguageRI/TypeVariable.js 2017-08-31 19:33:35 UTC (rev 221434)
@@ -60,7 +60,7 @@
if (realThis != this)
return realThis.unify(unificationContext, other);
- unificationContext.unify(this, other);
+ unificationContext.union(this, other);
return true;
}
Modified: trunk/Tools/WebGPUShadingLanguageRI/UnificationContext.js (221433 => 221434)
--- trunk/Tools/WebGPUShadingLanguageRI/UnificationContext.js 2017-08-31 19:20:36 UTC (rev 221433)
+++ trunk/Tools/WebGPUShadingLanguageRI/UnificationContext.js 2017-08-31 19:33:35 UTC (rev 221434)
@@ -33,20 +33,21 @@
union(a, b)
{
- a = find(a);
- b = find(b);
+ a = this.find(a);
+ b = this.find(b);
if (a == b)
return;
- if (!b.isUnifiable)
+ if (!a.isUnifiable) {
[a, b] = [b, a];
- if (!a.isUnifiable)
- throw new Error("Cannot unify non-unifiable things " + a + " and " + b);
+ if (!a.isUnifiable)
+ throw new Error("Cannot unify non-unifiable things " + a + " and " + b);
+ }
// Make sure that type parameters don't end up being roots.
if (a.isUnifiable && b.isUnifiable && this._typeParameters.has(b))
[a, b] = [b, a];
-
+
this._nextMap.set(a, b);
}