2 * Copyright (C) 2018 Apple Inc. All rights reserved.
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
7 * 1. Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * 2. Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
13 * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
14 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
17 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
18 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
19 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
20 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
21 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
23 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 class Checker extends Visitor {
31 this._program = program;
32 this._currentStatement = null;
33 this._vertexEntryPoints = new Set();
34 this._fragmentEntryPoints = new Set();
35 this._computeEntryPoints = new Set();
40 let doStatement = statement => {
41 this._currentStatement = statement;
42 statement.visit(this);
45 for (let type of node.types.values()) {
46 if (type instanceof Array) {
47 for (let constituentType of type)
48 doStatement(constituentType);
52 for (let funcs of node.functions.values()) {
53 for (let func of funcs) {
57 for (let funcs of node.functions.values()) {
58 for (let func of funcs)
66 constructor(type, semantic)
68 if (node.shaderType != "test" && !semantic)
69 throw new WTypeError(node.origin.originString, "An entry-point input/output exists which doesn't have a semantic");
71 this._semantic = semantic;
74 get type() { return this._type; }
75 get semantic() { return this._semantic; }
78 let program = this._program;
79 class Gatherer extends Visitor {
80 constructor(currentSemantic = null)
83 this._currentSemantic = currentSemantic;
87 reset(currentSemantic = null)
89 this.currentSemantic = currentSemantic;
92 set currentSemantic(value) { this._currentSemantic = value; }
93 get currentSemantic() { return this._currentSemantic; }
94 get result() { return this._result; }
98 this.result.push(new Item(node, this.currentSemantic));
101 visitVectorType(node)
103 this.result.push(new Item(node, this.currentSemantic));
106 visitMatrixType(node)
108 this.result.push(new Item(node, this.currentSemantic));
111 visitNativeType(node)
113 if (program.intrinsics.void.equals(node)) {
114 if (this.currentSemantic)
115 throw new WTypeError(node.origin.originString, "Void can't have a semantic");
117 this.result.push(new Item(node, this.currentSemantic));
120 visitStructType(node)
122 if (this.currentSemantic != null)
123 throw new WTypeError(node.origin.originString, "Structs inside entry point signatures can't have semantics.");
124 for (let field of node.fields) {
125 this.currentSemantic = field.semantic;
126 field.type.visit(this);
132 node.type.visit(this);
137 this.result.push(new Item(node, this.currentSemantic));
140 visitArrayRefType(node)
142 this.result.push(new Item(node, this.currentSemantic));
147 this.result.push(new Item(node, this.currentSemantic));
150 visitFuncParameter(node)
152 this._currentSemantic = node.semantic;
153 node.type.visit(this);
157 let inputGatherer = new Gatherer();
158 for (let parameter of node.parameters) {
159 inputGatherer.reset();
160 parameter.visit(inputGatherer);
162 let outputGatherer = new Gatherer(node.semantic);
163 node.returnType.visit(outputGatherer);
165 function checkDuplicateSemantics(items) {
166 // FIXME: Make this faster than O(n^2)
167 for (let i = 0; i < items.length; ++i) {
168 for (let j = i + 1; j < items.length; ++j) {
169 if (items[i].semantic && items[i].semantic.equalToOtherSemantic(items[j].semantic))
170 throw new WTypeError(node.origin.originString, `Duplicate semantic found in entry point: ${items[i].semantic}`);
174 checkDuplicateSemantics(inputGatherer.result);
175 checkDuplicateSemantics(outputGatherer.result);
177 function checkSemanticTypes(items) {
178 for (let item of items) {
179 if (item.semantic && !item.semantic.isAcceptableType(item.type, program))
180 throw new WTypeError(node.origin.originString, `Semantic ${item.semantic} is unnacceptable type ${item.type}`);
183 checkSemanticTypes(inputGatherer.result);
184 checkSemanticTypes(outputGatherer.result);
186 function checkSemanticForShaderType(items, direction) {
187 for (let item of items) {
188 if (item.semantic && !item.semantic.isAcceptableForShaderType(direction, node.shaderType))
189 throw new WTypeError(node.origin.originString, `Semantic ${item.semantic} is unnacceptable as an ${direction} of shader type ${node.shaderType}`);
192 checkSemanticForShaderType(inputGatherer.result, "input");
193 checkSemanticForShaderType(outputGatherer.result, "output");
195 class PODChecker extends Visitor {
203 return node.elementType.visit(this);
206 visitVectorType(node)
211 visitMatrixType(node)
216 visitNativeType(node)
218 return node.isNumber;
226 visitArrayRefType(node)
231 visitStructType(node)
234 for (let field of node.fields)
235 result = result && field.visit(this);
241 return node.type.visit(this);
244 function checkPODData(items) {
245 for (let item of items) {
246 if ((item.type instanceof PtrType) || (item.type instanceof ArrayRefType) || (item.type instanceof ArrayType)) {
247 if (!item.type.elementType.visit(new PODChecker()))
248 throw new WTypeError(node.origin.originString, "Buffer attached to entry point needs to only contain POD types");
252 checkPODData(inputGatherer.result);
253 checkPODData(outputGatherer.result);
256 _checkShaderType(node)
258 switch (node.shaderType) {
260 if (this._vertexEntryPoints.has(node.name))
261 throw new WTypeError(node.origin.originString, "Duplicate vertex entry point name " + node.name);
262 this._vertexEntryPoints.add(node.name);
265 if (this._fragmentEntryPoints.has(node.name))
266 throw new WTypeError(node.origin.originString, "Duplicate fragment entry point name " + node.name);
267 this._fragmentEntryPoints.add(node.name);
270 if (this._computeEntryPoints.has(node.name))
271 throw new WTypeError(node.origin.originString, "Duplicate compute entry point name " + node.name);
272 this._computeEntryPoints.add(node.name);
277 throw new Error("Bad shader type: " + node.shaderType);
281 _checkOperatorOverload(func, resolveFuncs)
283 if (Lexer.textIsIdentifier(func.name))
284 return; // Not operator!
286 if (!func.name.startsWith("operator"))
287 throw new Error("Bad operator overload name: " + func.name);
289 let checkGetter = (kind) => {
290 let numExpectedParameters = kind == "index" ? 2 : 1;
291 if (func.parameters.length != numExpectedParameters)
292 throw new WTypeError(func.origin.originString, "Incorrect number of parameters for " + func.name + " (expected " + numExpectedParameters + ", got " + func.parameters.length + ")");
293 if (func.parameterTypes[0].unifyNode.isPtr)
294 throw new WTypeError(func.origin.originString, "Cannot have getter for pointer type: " + func.parameterTypes[0]);
297 let checkSetter = (kind) => {
298 let numExpectedParameters = kind == "index" ? 3 : 2;
299 if (func.parameters.length != numExpectedParameters)
300 throw new WTypeError(func.origin.originString, "Incorrect number of parameters for " + func.name + " (expected " + numExpectedParameters + ", got " + func.parameters.length + ")");
301 if (func.parameterTypes[0].unifyNode.isPtr)
302 throw new WTypeError(func.origin.originString, "Cannot have setter for pointer type: " + func.parameterTypes[0]);
303 if (!func.returnType.equals(func.parameterTypes[0]))
304 throw new WTypeError(func.origin.originString, "First parameter type and return type of setter must match (parameter was " + func.parameterTypes[0] + " but return was " + func.returnType + ")");
305 let valueType = func.parameterTypes[numExpectedParameters - 1];
306 let getterName = func.name.substr(0, func.name.length - 1);
307 let getterFuncs = resolveFuncs(getterName);
309 throw new WTypeError(func.origin.originString, "Every setter must have a matching getter, but did not find any function named " + getterName + " to match " + func.name);
310 let argumentTypes = func.parameterTypes.slice(0, numExpectedParameters - 1);
311 let overload = resolveOverloadImpl(getterFuncs, argumentTypes, null);
313 throw new WTypeError(func.origin.originString, "Did not find function named " + func.name + " with arguments " + argumentTypes + (overload.failures.length ? "; tried:\n" + overload.failures.join("\n") : ""));
314 let resultType = overload.func.returnType;
315 if (!resultType.equals(valueType))
316 throw new WTypeError(func.origin.originString, "Setter and getter must agree on value type (getter at " + overload.func.origin.originString + " says " + resultType + " while this setter says " + valueType + ")");
319 let checkAnder = (kind) => {
320 let numExpectedParameters = kind == "index" ? 2 : 1;
321 if (func.parameters.length != numExpectedParameters)
322 throw new WTypeError(func.origin.originString, "Incorrect number of parameters for " + func.name + " (expected " + numExpectedParameters + ", got " + func.parameters.length + ")");
323 if (!func.returnType.unifyNode.isPtr)
324 throw new WTypeError(func.origin.originString, "Return type of ander is not a pointer: " + func.returnType);
325 if (!func.parameterTypes[0].unifyNode.isRef)
326 throw new WTypeError(func.origin.originString, "Parameter to ander is not a reference: " + func.parameterTypes[0]);
330 case "operator cast":
334 if (func.parameters.length != 1)
335 throw new WTypeError(func.origin.originString, "Incorrect number of parameters for " + func.name + " (expected 1, got " + func.parameters.length + ")");
336 if (!func.parameterTypes[0].equals(func.returnType))
337 throw new WTypeError(func.origin.originString, "Parameter type and return type must match for " + func.name + " (parameter is " + func.parameterTypes[0] + " while return is " + func.returnType + ")");
341 if (func.parameters.length != 1 && func.parameters.length != 2)
342 throw new WTypeError(func.origin.originString, "Incorrect number of parameters for " + func.name + " (expected 1 or 2, got " + func.parameters.length + ")");
352 if (func.parameters.length != 2)
353 throw new WTypeError(func.origin.originString, "Incorrect number of parameters for " + func.name + " (expected 2, got " + func.parameters.length + ")");
356 if (func.parameters.length != 1)
357 throw new WTypeError(func.origin.originString, "Incorrect number of parameters for " + func.name + " (expected 1, got " + func.parameters.length + ")");
364 if (func.parameters.length != 2)
365 throw new WTypeError(func.origin.originString, "Incorrect number of parameters for " + func.name + " (expected 2, got " + func.parameters.length + ")");
366 if (!func.returnType.equals(this._program.intrinsics.bool))
367 throw new WTypeError(func.origin.originString, "Return type of " + func.name + " must be bool but was " + func.returnType);
370 checkGetter("index");
373 checkSetter("index");
379 if (func.name.startsWith("operator.")) {
380 if (func.name.endsWith("="))
386 if (func.name.startsWith("operator&.")) {
390 throw new Error("Parser accepted unrecognized operator: " + func.name);
396 if (node.shaderType) {
397 this._checkShaderType(node);
398 this._checkSemantics(node);
400 this._checkOperatorOverload(node, name => this._program.functions.get(name));
401 node.body.visit(this);
406 node.baseType.visit(this);
408 let baseType = node.baseType.unifyNode;
411 throw new WTypeError(node.origin.originString, "Base type of enum is not an integer: " + node.baseType);
413 for (let member of node.members) {
417 let memberType = member.value.visit(this);
418 if (!baseType.equalsWithCommit(memberType))
419 throw new WTypeError(member.origin.originString, "Type of enum member " + member.value.name + " does not patch enum base type (member type is " + memberType + ", enum base type is " + node.baseType + ")");
422 let nextValue = baseType.defaultValue;
423 for (let member of node.members) {
425 nextValue = baseType.successorValue(member.value.unifyNode.valueForSelectedType);
429 member.value = baseType.createLiteral(member.origin, nextValue);
430 nextValue = baseType.successorValue(nextValue);
433 let memberArray = Array.from(node.members);
434 for (let i = 0; i < memberArray.length; ++i) {
435 let member = memberArray[i];
436 for (let j = i + 1; j < memberArray.length; ++j) {
437 let otherMember = memberArray[j];
438 if (baseType.valuesEqual(member.value.unifyNode.valueForSelectedType, otherMember.value.unifyNode.valueForSelectedType))
439 throw new WTypeError(otherMember.origin.originString, "Duplicate enum member value (" + member.name + " has " + member.value + " while " + otherMember.name + " has " + otherMember.value + ")");
443 let foundZero = false;
444 for (let member of node.members) {
445 if (baseType.valuesEqual(member.value.unifyNode.valueForSelectedType, baseType.defaultValue)) {
451 throw new WTypeError(node.origin.originString, "Enum does not have a member with the value zero");
457 throw new Error("Type reference without a type in checker: " + node + " at " + node.origin);
458 // All the structs will be visited by visitProgram() iterating through each top-level type.
459 // We don't want to recurse here because the contents of structs can refer to themselves (e.g. a linked list),
460 // and this would can an infinite loop.
461 // Typedefs can't refer to themselves because we check that in TypeDefResolver.
462 if (!(node.type instanceof StructType))
463 node.type.visit(this);
466 visitVectorType(node)
468 node.elementType.visit(this);
469 node.numElements.visit(this);
471 let isKnownAllowedVectorElementType = false;
472 for (let vectorElementTypeName of VectorElementTypes) {
473 const vectorElementType = this._program.globalNameContext.get(Type, vectorElementTypeName);
474 if (!vectorElementType)
475 throw new WTypeError(`${vectorElementType} is listed in VectorElementTypes, but it is not a known native type in the standard library or intrinsics.`);
476 if (vectorElementType.equals(node.elementType)) {
477 isKnownAllowedVectorElementType = true;
482 if (!isKnownAllowedVectorElementType)
483 throw new WTypeError(`${node.elementType} is not a permitted vector element type.`);
484 if (node.numElementsValue != 2 && node.numElementsValue != 3 && node.numElementsValue != 4)
485 throw new WTypeError(`${node.toString()}: ${node.numElementsValue} is not 2, 3, or 4.`);
488 visitMatrixType(node)
490 node.elementType.visit(this);
491 node.numRows.visit(this);
492 node.numColumns.visit(this);
494 let isKnownAllowedVectorElementType = false;
495 for (let elementTypeName of ["half", "float"]) {
496 const elementType = this._program.globalNameContext.get(Type, elementTypeName);
498 throw new WTypeError(`${elementTypeName} is not a known native type in the standard library or intrinsics.`);
499 if (elementType.equals(node.elementType)) {
500 isKnownAllowedVectorElementType = true;
505 if (!isKnownAllowedVectorElementType)
506 throw new WTypeError(`${node.elementType} is not a permitted vector element type.`);
507 if (node.numRowsValue != 2 && node.numRowsValue != 3 && node.numRowsValue != 4)
508 throw new WTypeError(`${node.toString()}: ${node.numRowsValue} is not 2, 3, or 4.`);
509 if (node.numColumnsValue != 2 && node.numColumnsValue != 3 && node.numColumnsValue != 4)
510 throw new WTypeError(`${node.toString()}: ${node.numColumnsValue} is not 2, 3, or 4.`);
515 node.elementType.visit(this);
517 if (!node.numElements.isConstexpr)
518 throw new WTypeError(node.origin.originString, "Array length must be constexpr");
520 let type = node.numElements.visit(this);
522 if (!type.equalsWithCommit(this._program.intrinsics.uint))
523 throw new WTypeError(node.origin.originString, "Array length must be a uint");
526 visitVariableDecl(node)
528 node.type.visit(this);
529 if (node.initializer) {
530 let lhsType = node.type;
531 let rhsType = node.initializer.visit(this);
532 if (!lhsType.equalsWithCommit(rhsType))
533 throw new WTypeError(node.origin.originString, "Type mismatch in variable initialization: " + lhsType + " versus " + rhsType);
537 visitAssignment(node)
539 let lhsType = node.lhs.visit(this);
540 if (!node.lhs.isLValue)
541 throw new WTypeError(node.origin.originString, "LHS of assignment is not an LValue: " + node.lhs + node.lhs.notLValueReasonString);
542 if (!isAddressSpace(node.lhs.addressSpace))
543 throw new Error(`${node.origin.originString}: Unknown address space in node ${node.lhs}`);
544 if (node.lhs.addressSpace == "constant")
545 throw new WTypeError(node.origin.originString, "Cannot assign to variable in the constant address space.");
546 let rhsType = node.rhs.visit(this);
547 if (!lhsType.equalsWithCommit(rhsType))
548 throw new WTypeError(node.origin.originString, "Type mismatch in assignment: " + lhsType + " versus " + rhsType);
553 visitIdentityExpression(node)
555 return node.target.visit(this);
558 visitReadModifyWriteExpression(node)
560 let lhsType = node.lValue.visit(this);
561 if (!node.lValue.isLValue)
562 throw new WTypeError(node.origin.originString, "LHS of read-modify-write is not an LValue: " + node.lValue + node.lValue.notLValueReasonString);
563 node.oldValueVar.type = lhsType;
564 node.newValueVar.type = lhsType;
565 node.oldValueVar.visit(this);
566 node.newValueVar.visit(this);
567 let newValueType = node.newValueExp.visit(this);
568 if (!lhsType.equalsWithCommit(newValueType))
569 return new WTypeError(node.origin.originString, "Type mismatch in read-modify-write: " + lhsType + " versus " + newValueType);
570 return node.resultExp.visit(this);
573 visitAnonymousVariable(node)
576 throw new Error("Anonymous variable must know type before first appearance");
579 visitDereferenceExpression(node)
581 let type = node.ptr.visit(this).unifyNode;
583 throw new WTypeError(node.origin.originString, "Type passed to dereference is not a pointer: " + type);
584 node.type = type.elementType;
585 node.addressSpace = type.addressSpace;
586 if (!node.addressSpace)
587 throw new Error("Null address space in type: " + type);
591 visitMakePtrExpression(node)
593 let elementType = node.lValue.visit(this).unifyNode;
594 if (!node.lValue.isLValue)
595 throw new WTypeError(node.origin.originString, "Operand to & is not an LValue: " + node.lValue + node.lValue.notLValueReasonString);
597 return new PtrType(node.origin, node.lValue.addressSpace, elementType);
600 visitMakeArrayRefExpression(node)
602 let elementType = node.lValue.visit(this).unifyNode;
603 if (elementType.isPtr) {
604 node.become(new ConvertPtrToArrayRefExpression(node.origin, node.lValue));
605 return new ArrayRefType(node.origin, elementType.addressSpace, elementType.elementType);
608 if (!node.lValue.isLValue)
609 throw new WTypeError(node.origin.originString, "Operand to @ is not an LValue: " + node.lValue + node.lValue.notLValueReasonString);
611 if (elementType.isArray) {
612 node.numElements = elementType.numElements;
613 elementType = elementType.elementType;
615 node.numElements = UintLiteral.withType(node.origin, 1, this._program.intrinsics.uint);
617 return new ArrayRefType(node.origin, node.lValue.addressSpace, elementType);
620 visitConvertToArrayRefExpression(node)
622 throw new Error("Should not exist yet.");
625 _finishVisitingPropertyAccess(node, baseType, extraArgs, extraArgTypes)
627 baseType = baseType.visit(new AutoWrapper())
628 node.baseType = baseType;
630 // Such a type must exist. This may throw if it doesn't.
631 let typeForAnd = baseType.argumentTypeForAndOverload(node.origin);
633 throw new Error("Cannot get typeForAnd");
639 let result = CallExpression.resolve(
640 node.origin, node.possibleGetOverloads,
641 node.getFuncName, [node.base, ...extraArgs], [baseType, ...extraArgTypes], null, this._program);
642 node.callForGet = result.call;
643 node.resultTypeForGet = result.resultType;
645 if (!(e instanceof WTypeError))
651 let baseForAnd = baseType.argumentForAndOverload(node.origin, node.base);
653 let result = CallExpression.resolve(
654 node.origin, node.possibleAndOverloads,
655 node.andFuncName, [baseForAnd, ...extraArgs], [typeForAnd, ...extraArgTypes],
656 null, this._program);
657 node.callForAnd = result.call;
658 node.resultTypeForAnd = result.resultType.unifyNode.returnTypeFromAndOverload(node.origin);
660 if (!(e instanceof WTypeError))
665 if (!node.resultTypeForGet && !node.resultTypeForAnd) {
666 throw new WTypeError(
667 node.origin.originString,
668 "Cannot resolve access; tried by-value:\n" +
669 errorForGet.typeErrorMessage + "\n" +
670 "and tried by-pointer:\n" +
671 errorForAnd.typeErrorMessage);
674 if (node.resultTypeForGet && node.resultTypeForAnd
675 && !node.resultTypeForGet.equals(node.resultTypeForAnd))
676 throw new WTypeError(node.origin.originString, "Result type resolved by-value (" + node.resultTypeForGet + ") does not match result type resolved by-pointer (" + node.resultTypeForAnd + ")");
679 let result = CallExpression.resolve(
680 node.origin, node.possibleSetOverloads,
681 node.setFuncName, [node.base, ...extraArgs, null], [baseType, ...extraArgTypes, node.resultType], null, this._program);
682 node.callForSet = result.call;
683 if (!result.resultType.equals(baseType))
684 throw new WTypeError(node.origin.originString, "Result type of setter " + result.call.func + " is not the base type " + baseType);
686 if (!(e instanceof WTypeError))
688 node.errorForSet = e;
691 // OK, now we need to determine if we are an lvalue. We are an lvalue if we can be assigned to. We can
692 // be assigned to if we have an ander or setter. But it's weirder than that. We also need the base to be
693 // an lvalue, except unless the base is an array reference.
694 if (!node.callForAnd && !node.callForSet) {
695 node.isLValue = false;
696 node.notLValueReason =
697 "Have neither ander nor setter. Tried setter:\n" +
698 node.errorForSet.typeErrorMessage + "\n" +
699 "and tried ander:\n" +
700 errorForAnd.typeErrorMessage;
701 } else if (!node.base.isLValue && !baseType.isArrayRef) {
702 node.isLValue = false;
703 node.notLValueReason = "Base of property access is neither a lvalue nor an array reference";
705 node.isLValue = true;
706 node.addressSpace = baseType.addressSpace ? baseType.addressSpace : node.base.addressSpace;
709 return node.resultType;
712 visitDotExpression(node)
714 let structType = node.struct.visit(this).unifyNode;
715 return this._finishVisitingPropertyAccess(node, structType, [], []);
718 visitIndexExpression(node)
720 let arrayType = node.array.visit(this).unifyNode;
721 let indexType = node.index.visit(this);
723 return this._finishVisitingPropertyAccess(node, arrayType, [node.index], [indexType]);
726 visitVariableRef(node)
728 if (!node.variable.type)
729 throw new Error("Variable has no type: " + node.variable);
730 return node.variable.type;
736 let resultType = node.value.visit(this);
738 throw new Error("Null result type from " + node.value);
739 if (!node.func.returnType.equalsWithCommit(resultType))
740 throw new WTypeError(node.origin.originString, "Trying to return " + resultType + " in a function that returns " + node.func.returnType);
744 if (!node.func.returnType.equalsWithCommit(this._program.intrinsics.void))
745 throw new WTypeError(node.origin.originString, "Non-void function must return a value");
748 visitGenericLiteral(node)
753 visitNullLiteral(node)
758 visitBoolLiteral(node)
760 return this._program.intrinsics.bool;
763 visitEnumLiteral(node)
765 return node.member.enumType;
768 _requireBool(expression)
770 let type = expression.visit(this);
772 throw new Error("Expression has no type, but should be bool: " + expression);
773 if (!type.equals(this._program.intrinsics.bool))
774 throw new WTypeError("Expression isn't a bool: " + expression);
777 visitLogicalNot(node)
779 this._requireBool(node.operand);
780 return this._program.intrinsics.bool;
783 visitLogicalExpression(node)
785 this._requireBool(node.left);
786 this._requireBool(node.right);
787 return this._program.intrinsics.bool;
790 visitIfStatement(node)
792 this._requireBool(node.conditional);
793 node.body.visit(this);
795 node.elseBody.visit(this);
800 this._requireBool(node.conditional);
801 node.body.visit(this);
804 visitDoWhileLoop(node)
806 node.body.visit(this);
807 this._requireBool(node.conditional);
812 if (node.initialization)
813 node.initialization.visit(this);
815 this._requireBool(node.condition);
817 node.increment.visit(this);
818 node.body.visit(this);
821 visitSwitchStatement(node)
823 let type = node.value.visit(this).commit();
825 if (!type.unifyNode.isInt && !(type.unifyNode instanceof EnumType))
826 throw new WTypeError(node.origin.originString, "Cannot switch on non-integer/non-enum type: " + type);
830 let hasDefault = false;
832 for (let switchCase of node.switchCases) {
833 switchCase.body.visit(this);
835 if (switchCase.isDefault) {
840 if (!switchCase.value.isConstexpr)
841 throw new WTypeError(switchCase.origin.originString, "Switch case not constexpr: " + switchCase.value);
843 let caseType = switchCase.value.visit(this);
844 if (!type.equalsWithCommit(caseType))
845 throw new WTypeError(switchCase.origin.originString, "Switch case type does not match switch value type (case type is " + caseType + " but switch value type is " + type + ")");
848 for (let i = 0; i < node.switchCases.length; ++i) {
849 let firstCase = node.switchCases[i];
850 for (let j = i + 1; j < node.switchCases.length; ++j) {
851 let secondCase = node.switchCases[j];
853 if (firstCase.isDefault != secondCase.isDefault)
856 if (firstCase.isDefault)
857 throw new WTypeError(secondCase.origin.originString, "Duplicate default case in switch statement");
859 let valuesEqual = type.unifyNode.valuesEqual(
860 firstCase.value.unifyNode.valueForSelectedType,
861 secondCase.value.unifyNode.valueForSelectedType);
863 throw new WTypeError(secondCase.origin.originString, "Duplicate case in switch statement for value " + firstCase.value.unifyNode.valueForSelectedType);
868 let includedValues = new Set();
869 for (let switchCase of node.switchCases)
870 includedValues.add(switchCase.value.unifyNode.valueForSelectedType);
872 for (let {value, name} of type.unifyNode.allValues()) {
873 if (!includedValues.has(value))
874 throw new WTypeError(node.origin.originString, "Value not handled by switch statement: " + name);
879 visitCommaExpression(node)
882 for (let expression of node.list)
883 result = expression.visit(this);
887 visitTernaryExpression(node)
889 this._requireBool(node.predicate);
890 let bodyType = node.bodyExpression.visit(this);
891 let elseType = node.elseExpression.visit(this);
893 throw new Error("Ternary expression body has no type: " + node.bodyExpression);
895 throw new Error("Ternary expression else has no type: " + node.elseExpression);
896 if (!bodyType.equalsWithCommit(elseType))
897 throw new WTypeError(node.origin.originString, "Body and else clause of ternary statement don't have the same type: " + node);
901 visitCallExpression(node)
903 let argumentTypes = node.argumentList.map(argument => {
904 let newArgument = argument.visit(this);
906 throw new Error("visitor returned null for " + argument);
907 return newArgument.visit(new AutoWrapper());
910 node.argumentTypes = argumentTypes;
912 node.returnType.visit(this);
914 let result = node.resolve(node.possibleOverloads, this._program);