WSL IntLiteralType should become int32 if unified with a type variable
authorfpizlo@apple.com <fpizlo@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Thu, 14 Sep 2017 18:33:26 +0000 (18:33 +0000)
committerfpizlo@apple.com <fpizlo@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Thu, 14 Sep 2017 18:33:26 +0000 (18:33 +0000)
commitb77a2456ca1c3eaffd9556da4a3ef3df9173df44
tree59272f0c70fc32c4ae184d4ebc478845685b2e19
parentf46d442eb76fc2d4bb37e9f79f9bbd421b95b981
WSL IntLiteralType should become int32 if unified with a type variable
https://bugs.webkit.org/show_bug.cgi?id=176707

Reviewed by Myles Maxfield.

This makes it so that this works:

    T foo<T>(T x) { return x; }
    foo(42); // T becomes int32

Previously, it did not work because IntLiteralType did not recognize TypeVariable as a number. Also,
TypeVariable would try to evaluate protocol inheritance of IntLiteralType, which would not go well. One
of the tests that this patch adds didn't just fail; it gave such an absurd 7-line type error that I felt
like I was using SML.

This fixes the problem by introducing what I think is a super deterministic way of handling literals and
type variables:

Before verifying a unification context, we now give all literals a chance to perform an extra
unification step. This is a two-phase process. This ensures that the unification performed by one
literal does not throw off the logic of some other literal. For example, if we do:

    void foo<T>(T, T) { }
    foo(42, 42u);

Then we want to always fail to compile, rather than sometimes succeeding. So, we first ask each literal
if it thinks that it needs to do extra unification. Both of the literals will report that they want to
in this case, because they will notice that they got unified with either at type variable or a literal,
which isn't specific enough. Then after they all register to do extra unification, they will both try to
unify with their preferred types (int32 for 42, uint32 for 42u). The first one will succeed, and the
second will give an error.

Without the special two-phase arrangement, it was possible to either get a type error or not depending
on the order - for example foo(42, 42u) might fail while foo(42u, 42) succeeds. It was definitely not
decidable, at least not unless you mandate the unification order as part of the type system spec. I
think that would have been nuts.

Both IntLiteral and UintLiteral are now "flexible"; the uint one will reject non-int or signed int
types and will prefer uint, but otherwise it's the same logic. This means that this will be valid:

    uint8 x = 5u;

But this is still wrong:

    int x = 5u;

To make this easy, I turned IntLiteral and UintLiteral (and IntLiteralType and UintLiteralType) into
factory-built generic types (see createLiteral() and createLiteralType()). Because visitors use the
constructor's declared name (GenericLiteral and GenericLiteralType in this case), it means that we can
share a ton of code between the different literals. I love that ES6 lets you do that.

* WebGPUShadingLanguageRI/All.js:
* WebGPUShadingLanguageRI/Checker.js:
* WebGPUShadingLanguageRI/CreateLiteral.js: Added.
(createLiteral.GenericLiteral):
(createLiteral.GenericLiteral.prototype.get value):
(createLiteral.GenericLiteral.prototype.get isConstexpr):
(createLiteral.GenericLiteral.prototype.toString):
(createLiteral):
* WebGPUShadingLanguageRI/CreateLiteralType.js: Added.
(createLiteralType.GenericLiteralType):
(createLiteralType.GenericLiteralType.prototype.get origin):
(createLiteralType.GenericLiteralType.prototype.get value):
(createLiteralType.GenericLiteralType.prototype.get isPrimitive):
(createLiteralType.GenericLiteralType.prototype.get isUnifiable):
(createLiteralType.GenericLiteralType.prototype.get isLiteral):
(createLiteralType.GenericLiteralType.prototype.typeVariableUnify):
(createLiteralType.GenericLiteralType.prototype.unifyImpl):
(createLiteralType.GenericLiteralType.prototype.prepareToVerify):
(createLiteralType.GenericLiteralType.prototype.verifyAsArgument):
(createLiteralType.GenericLiteralType.prototype.verifyAsParameter):
(createLiteralType.GenericLiteralType.prototype.conversionCost):
(createLiteralType.GenericLiteralType.prototype.commitUnification):
(createLiteralType.GenericLiteralType.prototype.toString):
(createLiteralType):
* WebGPUShadingLanguageRI/Evaluator.js:
(Evaluator.prototype.visitIntLiteral): Deleted.
(Evaluator.prototype.visitUintLiteral): Deleted.
* WebGPUShadingLanguageRI/IntLiteral.js:
(let.IntLiteral.createLiteral.createType):
(IntLiteral): Deleted.
(IntLiteral.prototype.get value): Deleted.
(IntLiteral.prototype.get isConstexpr): Deleted.
(IntLiteral.prototype.toString): Deleted.
* WebGPUShadingLanguageRI/IntLiteralType.js:
(IntLiteralType): Deleted.
(IntLiteralType.prototype.get origin): Deleted.
(IntLiteralType.prototype.get value): Deleted.
(IntLiteralType.prototype.get isPrimitive): Deleted.
(IntLiteralType.prototype.get isUnifiable): Deleted.
(IntLiteralType.prototype.typeVariableUnify): Deleted.
(IntLiteralType.prototype.unifyImpl): Deleted.
(IntLiteralType.prototype.verifyAsArgument): Deleted.
(IntLiteralType.prototype.verifyAsParameter): Deleted.
(IntLiteralType.prototype.conversionCost): Deleted.
(IntLiteralType.prototype.commitUnification): Deleted.
(IntLiteralType.prototype.toString): Deleted.
* WebGPUShadingLanguageRI/Intrinsics.js:
(Intrinsics):
* WebGPUShadingLanguageRI/LiteralTypeChecker.js:
(LiteralTypeChecker.prototype.visitIntLiteralType): Deleted.
* WebGPUShadingLanguageRI/Node.js:
(Node.prototype.prepareToVerify):
(Node.prototype.commitUnification):
(Node.prototype.get isLiteral):
* WebGPUShadingLanguageRI/NullType.js:
(NullType.prototype.get isLiteral):
(NullType.prototype.toString):
(NullType):
* WebGPUShadingLanguageRI/Parse.js:
(parseTerm):
* WebGPUShadingLanguageRI/Rewriter.js:
(Rewriter.prototype.visitGenericLiteralType):
(Rewriter.prototype.visitIntLiteral): Deleted.
(Rewriter.prototype.visitIntLiteralType): Deleted.
(Rewriter.prototype.visitUintLiteral): Deleted.
(Rewriter.prototype.visitBoolLiteral): Deleted.
* WebGPUShadingLanguageRI/Test.html:
* WebGPUShadingLanguageRI/Test.js:
(makeUint):
(checkUint):
(TEST_uintSimpleMath):
(TEST_equality):
(TEST_notEquality):
(TEST_intLiteralGeneric):
(TEST_intLiteralGenericWithProtocols):
(TEST_uintLiteralGeneric):
(TEST_uintLiteralGenericWithProtocols):
(TEST_intLiteralGenericSpecific):
(TEST_twoIntLiterals):
(TEST_unifyDifferentLiterals):
(makeUInt): Deleted.
(checkUInt): Deleted.
* WebGPUShadingLanguageRI/Type.js:
* WebGPUShadingLanguageRI/UintLiteral.js:
(let.UintLiteral.createLiteral.createType):
(UintLiteral): Deleted.
(UintLiteral.prototype.get value): Deleted.
(UintLiteral.prototype.get isConstexpr): Deleted.
(UintLiteral.prototype.toString): Deleted.
* WebGPUShadingLanguageRI/UintLiteralType.js: Added.
(let.UintLiteralType.createLiteralType.verifyAsArgument):
* WebGPUShadingLanguageRI/UnificationContext.js:
(UnificationContext.prototype.verify):
* WebGPUShadingLanguageRI/Visitor.js:
(Visitor.prototype.visitProtocolDecl):

git-svn-id: https://svn.webkit.org/repository/webkit/trunk@222038 268f45cc-cd09-0410-ab3c-d52691b4dbfc
20 files changed:
Tools/ChangeLog
Tools/WebGPUShadingLanguageRI/All.js
Tools/WebGPUShadingLanguageRI/Checker.js
Tools/WebGPUShadingLanguageRI/CreateLiteral.js [new file with mode: 0644]
Tools/WebGPUShadingLanguageRI/CreateLiteralType.js [new file with mode: 0644]
Tools/WebGPUShadingLanguageRI/Evaluator.js
Tools/WebGPUShadingLanguageRI/IntLiteral.js
Tools/WebGPUShadingLanguageRI/IntLiteralType.js
Tools/WebGPUShadingLanguageRI/Intrinsics.js
Tools/WebGPUShadingLanguageRI/LiteralTypeChecker.js
Tools/WebGPUShadingLanguageRI/Node.js
Tools/WebGPUShadingLanguageRI/NullType.js
Tools/WebGPUShadingLanguageRI/Parse.js
Tools/WebGPUShadingLanguageRI/Rewriter.js
Tools/WebGPUShadingLanguageRI/Test.html
Tools/WebGPUShadingLanguageRI/Test.js
Tools/WebGPUShadingLanguageRI/UintLiteral.js
Tools/WebGPUShadingLanguageRI/UintLiteralType.js [new file with mode: 0644]
Tools/WebGPUShadingLanguageRI/UnificationContext.js
Tools/WebGPUShadingLanguageRI/Visitor.js