diff --git a/src/ast.ts b/src/ast.ts index 23ffaca27f..9ac9fde6aa 100644 --- a/src/ast.ts +++ b/src/ast.ts @@ -111,17 +111,6 @@ export enum NodeKind { COMMENT } -/** Checks if a node represents a constant value. */ -export function nodeIsConstantValue(kind: NodeKind): bool { - switch (kind) { - case NodeKind.LITERAL: - case NodeKind.NULL: - case NodeKind.TRUE: - case NodeKind.FALSE: return true; - } - return false; -} - /** Base class of all nodes. */ export abstract class Node { /** Node kind indicator. */ @@ -1141,6 +1130,41 @@ export abstract class Node { node.statement = statement; return node; } + + /** Tests if this node is a literal of the specified kind. */ + isLiteralKind(literalKind: LiteralKind): bool { + return this.kind == NodeKind.LITERAL + && (changetype(this)).literalKind == literalKind; // TS + } + + /** Tests if this node is a literal of a numeric kind (float or integer). */ + get isNumericLiteral(): bool { + if (this.kind == NodeKind.LITERAL) { + switch ((changetype(this)).literalKind) { // TS + case LiteralKind.FLOAT: + case LiteralKind.INTEGER: return true; + } + } + return false; + } + + /** Tests whether this node is guaranteed to compile to a constant value. */ + get compilesToConst(): bool { + switch (this.kind) { + case NodeKind.LITERAL: { + switch ((changetype(this)).literalKind) { // TS + case LiteralKind.FLOAT: + case LiteralKind.INTEGER: + case LiteralKind.STRING: return true; + } + break; + } + case NodeKind.NULL: + case NodeKind.TRUE: + case NodeKind.FALSE: return true; + } + return false; + } } // types @@ -1153,28 +1177,29 @@ export abstract class TypeNode extends Node { /** Tests if this type has a generic component matching one of the given type parameters. */ hasGenericComponent(typeParameterNodes: TypeParameterNode[]): bool { - var self = this; // TS otherwise complains if (this.kind == NodeKind.NAMEDTYPE) { - if (!(self).name.next) { - let typeArgumentNodes = (self).typeArguments; + let namedTypeNode = changetype(this); // TS + if (!namedTypeNode.name.next) { + let typeArgumentNodes = namedTypeNode.typeArguments; if (typeArgumentNodes !== null && typeArgumentNodes.length > 0) { for (let i = 0, k = typeArgumentNodes.length; i < k; ++i) { if (typeArgumentNodes[i].hasGenericComponent(typeParameterNodes)) return true; } } else { - let name = (self).name.identifier.text; + let name = namedTypeNode.name.identifier.text; for (let i = 0, k = typeParameterNodes.length; i < k; ++i) { if (typeParameterNodes[i].name.text == name) return true; } } } } else if (this.kind == NodeKind.FUNCTIONTYPE) { - let parameterNodes = (self).parameters; + let functionTypeNode = changetype(this); // TS + let parameterNodes = functionTypeNode.parameters; for (let i = 0, k = parameterNodes.length; i < k; ++i) { if (parameterNodes[i].type.hasGenericComponent(typeParameterNodes)) return true; } - if ((self).returnType.hasGenericComponent(typeParameterNodes)) return true; - let explicitThisType = (self).explicitThisType; + if (functionTypeNode.returnType.hasGenericComponent(typeParameterNodes)) return true; + let explicitThisType = functionTypeNode.explicitThisType; if (explicitThisType !== null && explicitThisType.hasGenericComponent(typeParameterNodes)) return true; } else { assert(false); @@ -1319,25 +1344,26 @@ export namespace DecoratorKind { break; } } - } else if ( - nameNode.kind == NodeKind.PROPERTYACCESS && - (nameNode).expression.kind == NodeKind.IDENTIFIER - ) { - let nameStr = ((nameNode).expression).text; - assert(nameStr.length); - let propStr = (nameNode).property.text; - assert(propStr.length); - // @operator.binary, @operator.prefix, @operator.postfix - if (nameStr == "operator") { - switch (propStr.charCodeAt(0)) { - case CharCode.b: { - if (propStr == "binary") return DecoratorKind.OPERATOR_BINARY; - break; - } - case CharCode.p: { - if (propStr == "prefix") return DecoratorKind.OPERATOR_PREFIX; - if (propStr == "postfix") return DecoratorKind.OPERATOR_POSTFIX; - break; + } else if (nameNode.kind == NodeKind.PROPERTYACCESS) { + let propertyAccessNode = nameNode; + let expression = propertyAccessNode.expression; + if (expression.kind == NodeKind.IDENTIFIER) { + let nameStr = (expression).text; + assert(nameStr.length); + let propStr = propertyAccessNode.property.text; + assert(propStr.length); + // @operator.binary, @operator.prefix, @operator.postfix + if (nameStr == "operator") { + switch (propStr.charCodeAt(0)) { + case CharCode.b: { + if (propStr == "binary") return DecoratorKind.OPERATOR_BINARY; + break; + } + case CharCode.p: { + if (propStr == "prefix") return DecoratorKind.OPERATOR_PREFIX; + if (propStr == "postfix") return DecoratorKind.OPERATOR_POSTFIX; + break; + } } } } @@ -1397,17 +1423,6 @@ export enum LiteralKind { OBJECT } -/** Checks if the given node represents a numeric (float or integer) literal. */ -export function isNumericLiteral(node: Expression): bool { - if (node.kind == NodeKind.LITERAL) { - switch ((node).literalKind) { - case LiteralKind.FLOAT: - case LiteralKind.INTEGER: return true; - } - } - return false; -} - /** Base class of all literal expressions. */ export abstract class LiteralExpression extends Expression { /** Specific literal kind. */ diff --git a/src/builtins.ts b/src/builtins.ts index 7be453c14d..a32cd9a359 100644 --- a/src/builtins.ts +++ b/src/builtins.ts @@ -35,13 +35,10 @@ import { } from "./diagnostics"; import { - NodeKind, Expression, LiteralKind, - LiteralExpression, StringLiteralExpression, - CallExpression, - isNumericLiteral + CallExpression } from "./ast"; import { @@ -889,17 +886,15 @@ function builtin_offsetof(ctx: BuiltinContext): ExpressionRef { return module.unreachable(); } if (operands.length) { - if ( - operands[0].kind != NodeKind.LITERAL || - (operands[0]).literalKind != LiteralKind.STRING - ) { + let firstOperand = operands[0]; + if (!firstOperand.isLiteralKind(LiteralKind.STRING)) { compiler.error( DiagnosticCode.String_literal_expected, operands[0].range ); return module.unreachable(); } - let fieldName = (operands[0]).value; + let fieldName = (firstOperand).value; let classMembers = classType.members; if (classMembers !== null && classMembers.has(fieldName)) { let member = assert(classMembers.get(fieldName)); @@ -909,7 +904,7 @@ function builtin_offsetof(ctx: BuiltinContext): ExpressionRef { } compiler.error( DiagnosticCode.Type_0_has_no_property_1, - operands[0].range, classType.internalName, fieldName + firstOperand.range, classType.internalName, fieldName ); return module.unreachable(); } @@ -1346,7 +1341,7 @@ function builtin_max(ctx: BuiltinContext): ExpressionRef { var type = compiler.currentType; if (!type.is(TypeFlags.REFERENCE)) { let arg1: ExpressionRef; - if (!typeArguments && isNumericLiteral(left)) { // prefer right type + if (!typeArguments && left.isNumericLiteral) { // prefer right type arg1 = compiler.compileExpression(operands[1], type, Constraints.MUST_WRAP); if (compiler.currentType != type) { arg0 = compiler.compileExpression(left, type = compiler.currentType, Constraints.CONV_IMPLICIT | Constraints.MUST_WRAP); @@ -1425,7 +1420,7 @@ function builtin_min(ctx: BuiltinContext): ExpressionRef { var type = compiler.currentType; if (!type.is(TypeFlags.REFERENCE)) { let arg1: ExpressionRef; - if (!typeArguments && isNumericLiteral(left)) { // prefer right type + if (!typeArguments && left.isNumericLiteral) { // prefer right type arg1 = compiler.compileExpression(operands[1], type, Constraints.MUST_WRAP); if (compiler.currentType != type) { arg0 = compiler.compileExpression(left, type = compiler.currentType, Constraints.CONV_IMPLICIT | Constraints.MUST_WRAP); diff --git a/src/compiler.ts b/src/compiler.ts index 278199c01b..4ab8d792fe 100644 --- a/src/compiler.ts +++ b/src/compiler.ts @@ -166,7 +166,6 @@ import { NamedTypeNode, - nodeIsConstantValue, findDecorator, isTypeOmitted } from "./ast"; @@ -623,10 +622,10 @@ export class Compiler extends DiagnosticEmitter { // traverse instances case ElementKind.FUNCTION_PROTOTYPE: { - let instances = (element).instances; - if (instances) { + let functionInstances = (element).instances; + if (functionInstances) { // TODO: for (let instance of instances.values()) { - for (let _values = Map_values(instances), i = 0, k = _values.length; i < k; ++i) { + for (let _values = Map_values(functionInstances), i = 0, k = _values.length; i < k; ++i) { let instance = unchecked(_values[i]); let instanceName = name; if (instance.is(CommonFlags.GENERIC)) { @@ -639,10 +638,10 @@ export class Compiler extends DiagnosticEmitter { break; } case ElementKind.CLASS_PROTOTYPE: { - let instances = (element).instances; - if (instances) { + let classInstances = (element).instances; + if (classInstances) { // TODO: for (let instance of instances.values()) { - for (let _values = Map_values(instances), i = 0, k = _values.length; i < k; ++i) { + for (let _values = Map_values(classInstances), i = 0, k = _values.length; i < k; ++i) { let instance = unchecked(_values[i]); let instanceName = name; if (instance.is(CommonFlags.GENERIC)) { @@ -655,21 +654,22 @@ export class Compiler extends DiagnosticEmitter { break; } case ElementKind.PROPERTY_PROTOTYPE: { - let prototype = element; - let getter = prototype.getterPrototype; - if (getter) this.ensureModuleExport(GETTER_PREFIX + name, getter, prefix); - let setter = prototype.setterPrototype; - if (setter) this.ensureModuleExport(SETTER_PREFIX + name, setter, prefix); + let propertyPrototype = element; + let getterPrototype = propertyPrototype.getterPrototype; + if (getterPrototype) this.ensureModuleExport(GETTER_PREFIX + name, getterPrototype, prefix); + let setterPrototype = propertyPrototype.setterPrototype; + if (setterPrototype) this.ensureModuleExport(SETTER_PREFIX + name, setterPrototype, prefix); break; } // export concrete elements case ElementKind.GLOBAL: { - let isConst = element.is(CommonFlags.CONST) || element.is(CommonFlags.STATIC | CommonFlags.READONLY); + let global = element; + let isConst = global.is(CommonFlags.CONST) || global.is(CommonFlags.STATIC | CommonFlags.READONLY); if (!isConst && !this.options.hasFeature(Feature.MUTABLE_GLOBALS)) { this.error( DiagnosticCode.Cannot_export_a_mutable_global, - (element).identifierNode.range + global.identifierNode.range ); } else { this.module.addGlobalExport(element.internalName, prefix + name); @@ -689,42 +689,42 @@ export class Compiler extends DiagnosticEmitter { break; } case ElementKind.FUNCTION: { - let instance = element; - let signature = instance.signature; + let functionInstance = element; + let signature = functionInstance.signature; if (signature.requiredParameters < signature.parameterTypes.length) { // utilize trampoline to fill in omitted arguments - instance = this.ensureTrampoline(instance); + functionInstance = this.ensureTrampoline(functionInstance); this.ensureBuiltinArgumentsLength(); } - if (instance.is(CommonFlags.COMPILED)) this.module.addFunctionExport(instance.internalName, prefix + name); + if (functionInstance.is(CommonFlags.COMPILED)) this.module.addFunctionExport(functionInstance.internalName, prefix + name); break; } case ElementKind.PROPERTY: { - let instance = element; - let getter = instance.getterInstance; + let propertyInstance = element; + let getter = propertyInstance.getterInstance; if (getter) this.ensureModuleExport(GETTER_PREFIX + name, getter, prefix); - let setter = instance.setterInstance; + let setter = propertyInstance.setterInstance; if (setter) this.ensureModuleExport(SETTER_PREFIX + name, setter, prefix); break; } case ElementKind.FIELD: { - let instance = element; + let fieldInstance = element; if (element.is(CommonFlags.COMPILED)) { let module = this.module; - module.addFunctionExport(instance.internalGetterName, prefix + GETTER_PREFIX + name); + module.addFunctionExport(fieldInstance.internalGetterName, prefix + GETTER_PREFIX + name); if (!element.is(CommonFlags.READONLY)) { - module.addFunctionExport(instance.internalSetterName, prefix + SETTER_PREFIX + name); + module.addFunctionExport(fieldInstance.internalSetterName, prefix + SETTER_PREFIX + name); } } break; } case ElementKind.CLASS: { - let instance = element; + let classInstance = element; // make the class name itself represent its runtime id - if (!instance.type.isUnmanaged) { + if (!classInstance.type.isUnmanaged) { let module = this.module; - let internalName = instance.internalName; - module.addGlobal(internalName, NativeType.I32, false, module.i32(instance.id)); + let internalName = classInstance.internalName; + module.addGlobal(internalName, NativeType.I32, false, module.i32(classInstance.id)); module.addGlobalExport(internalName, prefix + name); } break; @@ -797,13 +797,14 @@ export class Compiler extends DiagnosticEmitter { break; } case ElementKind.PROPERTY_PROTOTYPE: { - let getterPrototype = (element).getterPrototype; + let propertyPrototype = element; + let getterPrototype = propertyPrototype.getterPrototype; if (getterPrototype) { assert(!getterPrototype.is(CommonFlags.GENERIC)); let instance = this.resolver.resolveFunction(getterPrototype, null); if (instance) this.compileFunction(instance); } - let setterPrototype = (element).setterPrototype; + let setterPrototype = propertyPrototype.setterPrototype; if (setterPrototype) { assert(!setterPrototype.is(CommonFlags.GENERIC)); let instance = this.resolver.resolveFunction(setterPrototype, null); @@ -1143,9 +1144,9 @@ export class Compiler extends DiagnosticEmitter { let member = unchecked(_values[i]); if (member.kind != ElementKind.ENUMVALUE) continue; // happens if an enum is also a namespace let initInStart = false; - let val = member; - let valueNode = val.valueNode; - val.set(CommonFlags.COMPILED); + let enumValue = member; + let valueNode = enumValue.valueNode; + enumValue.set(CommonFlags.COMPILED); let previousFlow = this.currentFlow; if (element.hasDecorator(DecoratorFlags.LAZY)) { this.currentFlow = element.file.startFunction.flow; @@ -1173,7 +1174,7 @@ export class Compiler extends DiagnosticEmitter { if (previousValueIsMut) { this.error( DiagnosticCode.Enum_member_must_have_initializer, - (member).identifierNode.range.atEnd + enumValue.identifierNode.range.atEnd ); } if (isInline) { @@ -1199,24 +1200,24 @@ export class Compiler extends DiagnosticEmitter { } this.currentFlow = previousFlow; if (initInStart) { - module.addGlobal(val.internalName, NativeType.I32, true, module.i32(0)); + module.addGlobal(enumValue.internalName, NativeType.I32, true, module.i32(0)); this.currentBody.push( - this.makeGlobalAssignment(val, initExpr, false) + this.makeGlobalAssignment(enumValue, initExpr, false) ); previousValueIsMut = true; } else { if (isInline) { - val.setConstantIntegerValue(i64_new(getConstValueI32(initExpr)), Type.i32); - if (val.is(CommonFlags.MODULE_EXPORT)) { - module.addGlobal(val.internalName, NativeType.I32, false, initExpr); + enumValue.setConstantIntegerValue(i64_new(getConstValueI32(initExpr)), Type.i32); + if (enumValue.is(CommonFlags.MODULE_EXPORT)) { + module.addGlobal(enumValue.internalName, NativeType.I32, false, initExpr); } } else { - module.addGlobal(val.internalName, NativeType.I32, false, initExpr); + module.addGlobal(enumValue.internalName, NativeType.I32, false, initExpr); } - val.isImmutable = true; + enumValue.isImmutable = true; previousValueIsMut = false; } - previousValue = val; + previousValue = enumValue; } } this.currentParent = previousParent; @@ -1482,19 +1483,20 @@ export class Compiler extends DiagnosticEmitter { } case ElementKind.FUNCTION_PROTOTYPE: { if (!element.is(CommonFlags.GENERIC)) { - let instance = this.resolver.resolveFunction(element, null); - if (instance) this.compileFunction(instance); + let functionInstance = this.resolver.resolveFunction(element, null); + if (functionInstance) this.compileFunction(functionInstance); } break; } case ElementKind.PROPERTY_PROTOTYPE: { - let getterPrototype = (element).getterPrototype; + let propertyPrototype = element; + let getterPrototype = propertyPrototype.getterPrototype; if (getterPrototype) { assert(!getterPrototype.is(CommonFlags.GENERIC)); let instance = this.resolver.resolveFunction(getterPrototype, null); if (instance) this.compileFunction(instance); } - let setterPrototype = (element).setterPrototype; + let setterPrototype = propertyPrototype.setterPrototype; if (setterPrototype) { assert(!setterPrototype.is(CommonFlags.GENERIC)); let instance = this.resolver.resolveFunction(setterPrototype, null); @@ -1514,8 +1516,8 @@ export class Compiler extends DiagnosticEmitter { switch (element.kind) { case ElementKind.FUNCTION_PROTOTYPE: { if (!element.is(CommonFlags.GENERIC)) { - let instance = this.resolver.resolveFunction(element, null); - if (instance) this.compileFunction(instance); + let functionInstance = this.resolver.resolveFunction(element, null); + if (functionInstance) this.compileFunction(functionInstance); } break; } @@ -1831,12 +1833,13 @@ export class Compiler extends DiagnosticEmitter { break; } case NodeKind.NAMESPACEDECLARATION: { - let element = this.program.getElementByDeclaration(statement); + let declaration = statement; + let element = this.program.getElementByDeclaration(declaration); if (element) { // any potentiall merged element let previousParent = this.currentParent; this.currentParent = element; - let memberStatements = (statement).members; + let memberStatements = declaration.members; for (let i = 0, k = memberStatements.length; i < k; ++i) { this.compileTopLevelStatement(memberStatements[i], body); } @@ -1866,11 +1869,10 @@ export class Compiler extends DiagnosticEmitter { break; } case NodeKind.EXPORT: { - if ((statement).internalPath != null) { - this.compileFileByPath( - (statement).internalPath, - (statement).path - ); + let exportStatement = statement; + let internalPath = exportStatement.internalPath; + if (internalPath !== null) { + this.compileFileByPath(internalPath, assert(exportStatement.path)); } break; } @@ -1879,10 +1881,8 @@ export class Compiler extends DiagnosticEmitter { break; } case NodeKind.IMPORT: { - this.compileFileByPath( - (statement).internalPath, - (statement).path - ); + let importStatement = statement; + this.compileFileByPath(importStatement.internalPath, importStatement.path); break; } case NodeKind.FUNCTIONDECLARATION: @@ -5782,11 +5782,12 @@ export class Compiler extends DiagnosticEmitter { break; } case ElementKind.PROPERTY_PROTOTYPE: { // static property - let setterPrototype = (target).setterPrototype; + let propertyPrototype = target; + let setterPrototype = propertyPrototype.setterPrototype; if (!setterPrototype) { this.error( DiagnosticCode.Cannot_assign_to_0_because_it_is_a_constant_or_a_read_only_property, - expression.range, (target).internalName + expression.range, propertyPrototype.internalName ); return this.module.unreachable(); } @@ -5798,11 +5799,12 @@ export class Compiler extends DiagnosticEmitter { break; } case ElementKind.PROPERTY: { // instance property - let setterInstance = (target).setterInstance; + let propertyInstance = target; + let setterInstance = propertyInstance.setterInstance; if (!setterInstance) { this.error( DiagnosticCode.Cannot_assign_to_0_because_it_is_a_constant_or_a_read_only_property, - expression.range, (target).internalName + expression.range, propertyInstance.internalName ); return this.module.unreachable(); } @@ -5814,19 +5816,20 @@ export class Compiler extends DiagnosticEmitter { case ElementKind.INDEXSIGNATURE: { let parent = (target).parent; assert(parent.kind == ElementKind.CLASS); + let classInstance = parent; let isUnchecked = flow.is(FlowFlags.UNCHECKED_CONTEXT); - let indexedSet = (parent).lookupOverload(OperatorKind.INDEXED_SET, isUnchecked); + let indexedSet = classInstance.lookupOverload(OperatorKind.INDEXED_SET, isUnchecked); if (!indexedSet) { - let indexedGet = (parent).lookupOverload(OperatorKind.INDEXED_GET, isUnchecked); + let indexedGet = classInstance.lookupOverload(OperatorKind.INDEXED_GET, isUnchecked); if (!indexedGet) { this.error( DiagnosticCode.Index_signature_is_missing_in_type_0, - expression.range, (parent).internalName + expression.range, classInstance.internalName ); } else { this.error( DiagnosticCode.Index_signature_in_type_0_only_permits_reading, - expression.range, (parent).internalName + expression.range, classInstance.internalName ); } return this.module.unreachable(); @@ -5891,33 +5894,36 @@ export class Compiler extends DiagnosticEmitter { switch (target.kind) { case ElementKind.LOCAL: { - if (flow.isLocalFlag((target).index, LocalFlags.CONSTANT, true)) { + let local = target; + if (flow.isLocalFlag(local.index, LocalFlags.CONSTANT, true)) { this.error( DiagnosticCode.Cannot_assign_to_0_because_it_is_a_constant_or_a_read_only_property, valueExpression.range, target.internalName ); - this.currentType = tee ? (target).type : Type.void; + this.currentType = tee ? local.type : Type.void; return module.unreachable(); } - return this.makeLocalAssignment(target, valueExpr, valueType, tee); + return this.makeLocalAssignment(local, valueExpr, valueType, tee); } case ElementKind.GLOBAL: { - if (!this.compileGlobal(target)) return module.unreachable(); + let global = target; + if (!this.compileGlobal(global)) return module.unreachable(); if (target.isAny(CommonFlags.CONST | CommonFlags.READONLY)) { this.error( DiagnosticCode.Cannot_assign_to_0_because_it_is_a_constant_or_a_read_only_property, valueExpression.range, target.internalName ); - this.currentType = tee ? (target).type : Type.void; + this.currentType = tee ? global.type : Type.void; return module.unreachable(); } - return this.makeGlobalAssignment(target, valueExpr, tee); + return this.makeGlobalAssignment(global, valueExpr, tee); } case ElementKind.FIELD: { - let initializerNode = (target).initializerNode; + let fieldInstance = target; + let initializerNode = fieldInstance.initializerNode; if ( - (target).is(CommonFlags.READONLY) && + fieldInstance.is(CommonFlags.READONLY) && !( flow.actualFunction.is(CommonFlags.CONSTRUCTOR) || initializerNode !== null @@ -5925,11 +5931,11 @@ export class Compiler extends DiagnosticEmitter { ) { this.error( DiagnosticCode.Cannot_assign_to_0_because_it_is_a_constant_or_a_read_only_property, - valueExpression.range, (target).internalName + valueExpression.range, fieldInstance.internalName ); return module.unreachable(); } - return this.makeFieldAssignment(target, + return this.makeFieldAssignment(fieldInstance, valueExpr, // FIXME: explicit type (currently fails due to missing null checking) this.compileExpression(assert(thisExpression), this.options.usizeType), @@ -5937,7 +5943,8 @@ export class Compiler extends DiagnosticEmitter { ); } case ElementKind.PROPERTY_PROTOTYPE: { // static property - let setterPrototype = (target).setterPrototype; + let propertyPrototype = target; + let setterPrototype = propertyPrototype.setterPrototype; if (!setterPrototype) { this.error( DiagnosticCode.Cannot_assign_to_0_because_it_is_a_constant_or_a_read_only_property, @@ -5953,7 +5960,7 @@ export class Compiler extends DiagnosticEmitter { // call just the setter if the return value isn't of interest if (!tee) return this.makeCallDirect(setterInstance, [ valueExpr ], valueExpression); // otherwise call the setter first, then the getter - let getterPrototype = assert((target).getterPrototype); // must be present + let getterPrototype = assert(propertyPrototype.getterPrototype); // must be present let getterInstance = this.resolver.resolveFunction(getterPrototype, null, makeMap(), ReportMode.REPORT); if (!getterInstance) return module.unreachable(); let returnType = getterInstance.signature.returnType; @@ -5965,9 +5972,11 @@ export class Compiler extends DiagnosticEmitter { ], nativeReturnType); } case ElementKind.PROPERTY: { // instance property - let instance = (target).parent; - assert(instance.kind == ElementKind.CLASS); - let setterInstance = (target).setterInstance; + let propertyInstance = target; + assert(propertyInstance.parent.kind == ElementKind.CLASS); + let classInstance = propertyInstance.parent; + assert(classInstance.kind == ElementKind.CLASS); + let setterInstance = propertyInstance.setterInstance; if (!setterInstance) { this.error( DiagnosticCode.Cannot_assign_to_0_because_it_is_a_constant_or_a_read_only_property, @@ -5980,7 +5989,7 @@ export class Compiler extends DiagnosticEmitter { if (this.skippedAutoreleases.has(valueExpr)) valueExpr = this.makeAutorelease(valueExpr, valueType, flow); // (*) // call just the setter if the return value isn't of interest if (!tee) { - let thisExpr = this.compileExpression(assert(thisExpression), instance.type); + let thisExpr = this.compileExpression(assert(thisExpression), classInstance.type); return this.makeCallDirect(setterInstance, [ thisExpr, valueExpr ], valueExpression); } // otherwise call the setter first, then the getter @@ -6002,43 +6011,46 @@ export class Compiler extends DiagnosticEmitter { return ret; } case ElementKind.INDEXSIGNATURE: { - let instance = (target).parent; - assert(instance.kind == ElementKind.CLASS); + let indexSignature = target; + let parent = indexSignature.parent; + assert(parent.kind == ElementKind.CLASS); + let classInstance = parent; + assert(classInstance.kind == ElementKind.CLASS); let isUnchecked = flow.is(FlowFlags.UNCHECKED_CONTEXT); - let indexedGet = instance.lookupOverload(OperatorKind.INDEXED_GET, isUnchecked); - if (!indexedGet) { + let getterInstance = classInstance.lookupOverload(OperatorKind.INDEXED_GET, isUnchecked); + if (!getterInstance) { this.error( DiagnosticCode.Index_signature_is_missing_in_type_0, - valueExpression.range, instance.internalName + valueExpression.range, classInstance.internalName ); return module.unreachable(); } - let indexedSet = instance.lookupOverload(OperatorKind.INDEXED_SET, isUnchecked); - if (!indexedSet) { + let setterInstance = classInstance.lookupOverload(OperatorKind.INDEXED_SET, isUnchecked); + if (!setterInstance) { this.error( DiagnosticCode.Index_signature_in_type_0_only_permits_reading, - valueExpression.range, instance.internalName + valueExpression.range, classInstance.internalName ); - this.currentType = tee ? indexedGet.signature.returnType : Type.void; + this.currentType = tee ? getterInstance.signature.returnType : Type.void; return module.unreachable(); } - assert(indexedSet.signature.parameterTypes.length == 2); - let valueType = indexedSet.signature.parameterTypes[1]; + assert(setterInstance.signature.parameterTypes.length == 2); + let valueType = setterInstance.signature.parameterTypes[1]; if (this.skippedAutoreleases.has(valueExpr)) valueExpr = this.makeAutorelease(valueExpr, valueType, flow); // (*) - let thisExpr = this.compileExpression(assert(thisExpression), instance.type); + let thisExpr = this.compileExpression(assert(thisExpression), classInstance.type); let elementExpr = this.compileExpression(assert(indexExpression), Type.i32, Constraints.CONV_IMPLICIT); if (tee) { - let tempTarget = flow.getTempLocal(instance.type); + let tempTarget = flow.getTempLocal(classInstance.type); let tempElement = flow.getTempLocal(this.currentType); - let returnType = indexedGet.signature.returnType; + let returnType = getterInstance.signature.returnType; flow.freeTempLocal(tempTarget); let ret = module.block(null, [ - this.makeCallDirect(indexedSet, [ + this.makeCallDirect(setterInstance, [ module.local_tee(tempTarget.index, thisExpr), module.local_tee(tempElement.index, elementExpr), valueExpr ], valueExpression), - this.makeCallDirect(indexedGet, [ + this.makeCallDirect(getterInstance, [ module.local_get(tempTarget.index, tempTarget.type.toNativeType()), module.local_get(tempElement.index, tempElement.type.toNativeType()) ], valueExpression) @@ -6047,7 +6059,7 @@ export class Compiler extends DiagnosticEmitter { flow.freeTempLocal(tempTarget); return ret; } else { - return this.makeCallDirect(indexedSet, [ + return this.makeCallDirect(setterInstance, [ thisExpr, elementExpr, valueExpr @@ -6348,21 +6360,21 @@ export class Compiler extends DiagnosticEmitter { // direct call: concrete function case ElementKind.FUNCTION_PROTOTYPE: { - let prototype = target; + let functionPrototype = target; // builtins handle present respectively omitted type arguments on their own - if (prototype.hasDecorator(DecoratorFlags.BUILTIN)) { - return this.compileCallExpressionBuiltin(prototype, expression, contextualType); + if (functionPrototype.hasDecorator(DecoratorFlags.BUILTIN)) { + return this.compileCallExpressionBuiltin(functionPrototype, expression, contextualType); } let thisExpression = this.resolver.currentThisExpression; // compileCallDirect may reset - let instance = this.resolver.maybeInferCall(expression, prototype, flow); - if (!instance) return this.module.unreachable(); + let functionInstance = this.resolver.maybeInferCall(expression, functionPrototype, flow); + if (!functionInstance) return this.module.unreachable(); return this.compileCallDirect( - instance, + functionInstance, expression.arguments, expression, - instance.is(CommonFlags.INSTANCE) + functionInstance.is(CommonFlags.INSTANCE) ? this.compileExpression(assert(thisExpression), this.options.usizeType) : 0, constraints @@ -6371,36 +6383,39 @@ export class Compiler extends DiagnosticEmitter { // indirect call: index argument with signature (non-generic, can't be inlined) case ElementKind.LOCAL: { - signature = (target).type.signatureReference; + let local = target; + signature = local.type.signatureReference; if (signature) { - if ((target).is(CommonFlags.INLINED)) { - indexArg = module.i32(i64_low((target).constantIntegerValue)); + if (local.is(CommonFlags.INLINED)) { + indexArg = module.i32(i64_low(local.constantIntegerValue)); } else { - indexArg = module.local_get((target).index, NativeType.I32); + indexArg = module.local_get(local.index, NativeType.I32); } break; } this.error( DiagnosticCode.Cannot_invoke_an_expression_whose_type_lacks_a_call_signature_Type_0_has_no_compatible_call_signatures, - expression.range, (target).type.toString() + expression.range, local.type.toString() ); return module.unreachable(); } case ElementKind.GLOBAL: { - signature = (target).type.signatureReference; + let global = target; + signature = global.type.signatureReference; if (signature) { - indexArg = module.global_get((target).internalName, (target).type.toNativeType()); + indexArg = module.global_get(global.internalName, global.type.toNativeType()); break; } this.error( DiagnosticCode.Cannot_invoke_an_expression_whose_type_lacks_a_call_signature_Type_0_has_no_compatible_call_signatures, - expression.range, (target).type.toString() + expression.range, global.type.toString() ); return module.unreachable(); } case ElementKind.FIELD: { - let type = (target).type; - signature = type.signatureReference; + let fieldInstance = target; + let fieldType = fieldInstance.type; + signature = fieldType.signatureReference; if (signature) { let thisExpression = assert(this.resolver.currentThisExpression); let thisExpr = this.compileExpression(thisExpression, this.options.usizeType); @@ -6409,25 +6424,27 @@ export class Compiler extends DiagnosticEmitter { false, thisExpr, NativeType.I32, - (target).memoryOffset + fieldInstance.memoryOffset ); break; } else { this.error( DiagnosticCode.Cannot_invoke_an_expression_whose_type_lacks_a_call_signature_Type_0_has_no_compatible_call_signatures, - expression.range, type.toString() + expression.range, fieldType.toString() ); return module.unreachable(); } } case ElementKind.FUNCTION_TARGET: { - signature = (target).signature; - indexArg = this.compileExpression(expression.expression, (target).type, Constraints.CONV_IMPLICIT); + let functionTarget = target; + signature = functionTarget.signature; + indexArg = this.compileExpression(expression.expression, functionTarget.type, Constraints.CONV_IMPLICIT); break; } case ElementKind.PROPERTY_PROTOTYPE: { // static property - let getterPrototype = assert((target).getterPrototype); + let propertyPrototype = target; + let getterPrototype = assert(propertyPrototype.getterPrototype); let getterInstance = this.resolver.resolveFunction(getterPrototype, null); if (!getterInstance) return module.unreachable(); indexArg = this.compileCallDirect(getterInstance, [], expression.expression); @@ -6442,7 +6459,8 @@ export class Compiler extends DiagnosticEmitter { break; } case ElementKind.PROPERTY: { // instance property - let getterInstance = assert((target).getterInstance); + let propertyInstance = target; + let getterInstance = assert(propertyInstance.getterInstance); indexArg = this.compileCallDirect(getterInstance, [], expression.expression, this.compileExpression(assert(this.resolver.currentThisExpression), this.options.usizeType) ); @@ -6733,15 +6751,17 @@ export class Compiler extends DiagnosticEmitter { ); } if (thisArg) { - let classInstance = assert(instance.parent); assert(classInstance.kind == ElementKind.CLASS); + let parent = assert(instance.parent); + assert(parent.kind == ElementKind.CLASS); + let classInstance = parent; let thisType = assert(instance.signature.thisType); let thisLocal = flow.addScopedLocal(CommonNames.this_, thisType, usedLocals); // No need to retain `this` as it can't be reassigned and thus can't become prematurely released body.unshift( module.local_set(thisLocal.index, thisArg) ); - let baseInstance = (classInstance).base; - if (baseInstance) flow.addScopedAlias(CommonNames.super_, baseInstance.type, thisLocal.index); + let base = classInstance.base; + if (base) flow.addScopedAlias(CommonNames.super_, base.type, thisLocal.index); } else { assert(!instance.signature.thisType); } @@ -7318,9 +7338,9 @@ export class Compiler extends DiagnosticEmitter { for (let i = numArguments; i < maxArguments; ++i) { let initializer = parameterNodes[i].initializer; if (initializer) { - if (nodeIsConstantValue(initializer.kind)) { + if (initializer.compilesToConst) { operands.push(this.compileExpression( - parameterNodes[i].initializer, + initializer, parameterTypes[i], Constraints.CONV_IMPLICIT )); @@ -7740,7 +7760,9 @@ export class Compiler extends DiagnosticEmitter { case NodeKind.THIS: { if (actualFunction.is(CommonFlags.INSTANCE)) { let thisLocal = assert(flow.lookupLocal(CommonNames.this_)); - let classInstance = assert(actualFunction.parent); assert(classInstance.kind == ElementKind.CLASS); + let parent = assert(actualFunction.parent); + assert(parent.kind == ElementKind.CLASS); + let classInstance = parent; let nativeSizeType = this.options.nativeSizeType; if (actualFunction.is(CommonFlags.CONSTRUCTOR)) { if (!flow.is(FlowFlags.ALLOCATES)) { @@ -7758,12 +7780,12 @@ export class Compiler extends DiagnosticEmitter { ), module.local_set(thisLocal.index, this.makeRetain( - this.makeAllocation(classInstance) + this.makeAllocation(classInstance) ) ) ) ]; - this.makeFieldInitializationInConstructor(classInstance, stmts); + this.makeFieldInitializationInConstructor(classInstance, stmts); stmts.push( module.local_get(thisLocal.index, nativeSizeType) ); @@ -7807,8 +7829,10 @@ export class Compiler extends DiagnosticEmitter { } } if (actualFunction.is(CommonFlags.INSTANCE)) { - let classInstance = assert(actualFunction.parent); assert(classInstance.kind == ElementKind.CLASS); - let baseClassInstance = (classInstance).base; + let parent = assert(actualFunction.parent); + assert(parent.kind == ElementKind.CLASS); + let classInstance = parent; + let baseClassInstance = classInstance.base; if (baseClassInstance) { let superType = baseClassInstance.type; this.currentType = superType; @@ -7842,17 +7866,18 @@ export class Compiler extends DiagnosticEmitter { switch (target.kind) { case ElementKind.LOCAL: { - let type = (target).type; - assert(type != Type.void); - if ((target).is(CommonFlags.INLINED)) { - return this.compileInlineConstant(target, contextualType, constraints); + let local = target; + let localType = local.type; + assert(localType != Type.void); + if (local.is(CommonFlags.INLINED)) { + return this.compileInlineConstant(local, contextualType, constraints); } - let localIndex = (target).index; + let localIndex = local.index; assert(localIndex >= 0); - if (type.is(TypeFlags.NULLABLE) && flow.isLocalFlag(localIndex, LocalFlags.NONNULL, false)) { - type = type.nonNullableType; + if (localType.is(TypeFlags.NULLABLE) && flow.isLocalFlag(localIndex, LocalFlags.NONNULL, false)) { + localType = localType.nonNullableType; } - this.currentType = type; + this.currentType = localType; if (target.parent != flow.parentFunction) { // TODO: closures @@ -7862,21 +7887,23 @@ export class Compiler extends DiagnosticEmitter { ); return module.unreachable(); } - return module.local_get(localIndex, type.toNativeType()); + return module.local_get(localIndex, localType.toNativeType()); } case ElementKind.GLOBAL: { - if (!this.compileGlobal(target)) { // reports; not yet compiled if a static field + let global = target; + if (!this.compileGlobal(global)) { // reports; not yet compiled if a static field return module.unreachable(); } - let type = (target).type; - assert(type != Type.void); - if ((target).is(CommonFlags.INLINED)) { - return this.compileInlineConstant(target, contextualType, constraints); + let globalType = global.type; + assert(globalType != Type.void); + if (global.is(CommonFlags.INLINED)) { + return this.compileInlineConstant(global, contextualType, constraints); } - this.currentType = type; - return module.global_get((target).internalName, type.toNativeType()); + this.currentType = globalType; + return module.global_get(global.internalName, globalType.toNativeType()); } case ElementKind.ENUMVALUE: { // here: if referenced from within the same enum + let enumValue = target; if (!target.is(CommonFlags.COMPILED)) { this.error( DiagnosticCode.A_member_initializer_in_a_enum_declaration_cannot_reference_members_declared_after_it_including_members_defined_in_other_enums, @@ -7886,25 +7913,26 @@ export class Compiler extends DiagnosticEmitter { return module.unreachable(); } this.currentType = Type.i32; - if ((target).is(CommonFlags.INLINED)) { - assert((target).constantValueKind == ConstantValueKind.INTEGER); - return module.i32(i64_low((target).constantIntegerValue)); + if (enumValue.is(CommonFlags.INLINED)) { + assert(enumValue.constantValueKind == ConstantValueKind.INTEGER); + return module.i32(i64_low(enumValue.constantIntegerValue)); } - return module.global_get((target).internalName, NativeType.I32); + return module.global_get(enumValue.internalName, NativeType.I32); } case ElementKind.FUNCTION_PROTOTYPE: { - let instance = this.resolver.resolveFunction( - target, + let functionPrototype = target; + let functionInstance = this.resolver.resolveFunction( + functionPrototype, null, makeMap(flow.contextualTypeArguments) ); - if (!instance || !this.compileFunction(instance)) return module.unreachable(); + if (!functionInstance || !this.compileFunction(functionInstance)) return module.unreachable(); if (contextualType.is(TypeFlags.HOST | TypeFlags.REFERENCE)) { this.currentType = Type.anyref; - return module.ref_func(instance.internalName); + return module.ref_func(functionInstance.internalName); } - let index = this.ensureFunctionTableEntry(instance); - this.currentType = instance.signature.type; + let index = this.ensureFunctionTableEntry(functionInstance); + this.currentType = functionInstance.signature.type; return module.i32(index); } } @@ -8283,7 +8311,7 @@ export class Compiler extends DiagnosticEmitter { program.options.isWasm64 ? module.i64(elementType.alignLog2) : module.i32(elementType.alignLog2), - module.i32((arrayInstance).id), + module.i32(arrayInstance.id), program.options.isWasm64 ? module.i64(i64_low(bufferAddress), i64_high(bufferAddress)) : module.i32(i64_low(bufferAddress)) @@ -8302,7 +8330,7 @@ export class Compiler extends DiagnosticEmitter { } // otherwise compile an explicit instantiation with indexed sets - var setter = (arrayInstance).lookupOverload(OperatorKind.INDEXED_SET, true); + var setter = arrayInstance.lookupOverload(OperatorKind.INDEXED_SET, true); if (!setter) { flow.freeTempLocal(tempThis); flow.freeTempLocal(tempDataStart); @@ -8325,7 +8353,7 @@ export class Compiler extends DiagnosticEmitter { program.options.isWasm64 ? module.i64(elementType.alignLog2) : module.i32(elementType.alignLog2), - module.i32((arrayInstance).id), + module.i32(arrayInstance.id), program.options.isWasm64 ? module.i64(0) : module.i32(0) @@ -8334,14 +8362,14 @@ export class Compiler extends DiagnosticEmitter { ) ); // tempData = tempThis.dataStart - var dataStart = assert(arrayInstance.lookupInSelf("dataStart")); - assert(dataStart.kind == ElementKind.FIELD); + var dataStartMember = assert(arrayInstance.lookupInSelf("dataStart")); + assert(dataStartMember.kind == ElementKind.FIELD); stmts.push( module.local_set(tempDataStart.index, module.load(arrayType.byteSize, false, module.local_get(tempThis.index, nativeArrayType), nativeArrayType, - (dataStart).memoryOffset + (dataStartMember).memoryOffset ) ) ); @@ -8412,7 +8440,7 @@ export class Compiler extends DiagnosticEmitter { let expr: ExpressionRef; if (expression) { expr = module.precomputeExpression( - this.compileExpression(expression, elementType, + this.compileExpression(expression, elementType, Constraints.CONV_IMPLICIT | Constraints.WILL_RETAIN ) ); @@ -8602,13 +8630,14 @@ export class Compiler extends DiagnosticEmitter { hasErrors = true; continue; } - let type = (member).type; + let fieldInstance = member; + let fieldType = fieldInstance.type; exprs[i + 1] = this.module.store( // TODO: handle setters as well - type.byteSize, + fieldType.byteSize, this.module.local_get(tempLocal.index, this.options.nativeSizeType), - this.compileExpression(values[i], (member).type, Constraints.CONV_IMPLICIT), - type.toNativeType(), - (member).memoryOffset + this.compileExpression(values[i], fieldInstance.type, Constraints.CONV_IMPLICIT), + fieldType.toNativeType(), + fieldInstance.memoryOffset ); } this.currentType = classReference.type.nonNullableType; @@ -8826,31 +8855,37 @@ export class Compiler extends DiagnosticEmitter { switch (target.kind) { case ElementKind.GLOBAL: { // static field - if (!this.compileGlobal(target)) return module.unreachable(); // reports - let globalType = (target).type; + let global = target; + if (!this.compileGlobal(global)) return module.unreachable(); // reports + let globalType = global.type; assert(globalType != Type.void); - if ((target).is(CommonFlags.INLINED)) { - return this.compileInlineConstant(target, ctxType, constraints); + if (global.is(CommonFlags.INLINED)) { + return this.compileInlineConstant(global, ctxType, constraints); } this.currentType = globalType; - return module.global_get((target).internalName, globalType.toNativeType()); + return module.global_get(global.internalName, globalType.toNativeType()); } case ElementKind.ENUMVALUE: { // enum value - let theEnum = assert((target).parent); assert(theEnum.kind == ElementKind.ENUM); - if (!this.compileEnum(theEnum)) { + let enumValue = target; + let parent = assert(enumValue.parent); + assert(parent.kind == ElementKind.ENUM); + let parentEnum = parent; + if (!this.compileEnum(parentEnum)) { this.currentType = Type.i32; return this.module.unreachable(); } this.currentType = Type.i32; - if ((target).is(CommonFlags.INLINED)) { - assert((target).constantValueKind == ConstantValueKind.INTEGER); - return this.compileInlineConstant(target, ctxType, constraints); + if (enumValue.is(CommonFlags.INLINED)) { + assert(enumValue.constantValueKind == ConstantValueKind.INTEGER); + return this.compileInlineConstant(enumValue, ctxType, constraints); } - assert((target).type == Type.i32); - return module.global_get((target).internalName, NativeType.I32); + assert(enumValue.type == Type.i32); + return module.global_get(enumValue.internalName, NativeType.I32); } case ElementKind.FIELD: { // instance field - assert((target).memoryOffset >= 0); + let fieldInstance = target; + let fieldType = fieldInstance.type; + assert(fieldInstance.memoryOffset >= 0); let thisExpression = assert(this.resolver.currentThisExpression); let thisExpr = this.compileExpression(thisExpression, this.options.usizeType); let thisType = this.currentType; @@ -8862,17 +8897,18 @@ export class Compiler extends DiagnosticEmitter { ); } } - this.currentType = (target).type; + this.currentType = fieldType; return module.load( - (target).type.byteSize, - (target).type.is(TypeFlags.SIGNED | TypeFlags.INTEGER), + fieldType.byteSize, + fieldType.is(TypeFlags.SIGNED | TypeFlags.INTEGER), thisExpr, - (target).type.toNativeType(), - (target).memoryOffset + fieldType.toNativeType(), + fieldInstance.memoryOffset ); } case ElementKind.PROPERTY_PROTOTYPE: {// static property - let getterPrototype = (target).getterPrototype; + let propertyPrototype = target; + let getterPrototype = propertyPrototype.getterPrototype; if (getterPrototype) { let getter = this.resolver.resolveFunction(getterPrototype, null); if (getter) return this.compileCallDirect(getter, [], expression, 0); @@ -8880,25 +8916,24 @@ export class Compiler extends DiagnosticEmitter { return module.unreachable(); } case ElementKind.PROPERTY: { // instance property - let getterInstance = assert((target).getterInstance); + let propertyInstance = target; + let getterInstance = assert(propertyInstance.getterInstance); return this.compileCallDirect(getterInstance, [], expression, this.compileExpression(assert(this.resolver.currentThisExpression), this.options.usizeType) ); } case ElementKind.FUNCTION_PROTOTYPE: { - let prototype = target; - - if (prototype.is(CommonFlags.STATIC)) { - let instance = this.resolver.resolveFunction(prototype, null); - if (!instance) return module.unreachable(); - if (!this.compileFunction(instance)) return module.unreachable(); - this.currentType = instance.type; - return module.i32(this.ensureFunctionTableEntry(instance)); + let functionPrototype = target; + if (functionPrototype.is(CommonFlags.STATIC)) { + let functionInstance = this.resolver.resolveFunction(functionPrototype, null); + if (!functionInstance) return module.unreachable(); + if (!this.compileFunction(functionInstance)) return module.unreachable(); + this.currentType = functionInstance.type; + return module.i32(this.ensureFunctionTableEntry(functionInstance)); } - this.error( DiagnosticCode.Cannot_access_method_0_without_calling_it_as_it_requires_this_to_be_set, - expression.range, prototype.name + expression.range, functionPrototype.name ); return module.unreachable(); } @@ -9300,12 +9335,10 @@ export class Compiler extends DiagnosticEmitter { break; } case Token.MINUS: { - if (expression.operand.kind == NodeKind.LITERAL && ( - (expression.operand).literalKind == LiteralKind.INTEGER || - (expression.operand).literalKind == LiteralKind.FLOAT - )) { + let operand = expression.operand; + if (operand.isNumericLiteral) { // implicitly negate integer and float literals. also enables proper checking of literal ranges. - expr = this.compileLiteralExpression(expression.operand, contextualType, Constraints.NONE, true); + expr = this.compileLiteralExpression(operand, contextualType, Constraints.NONE, true); // compileExpression normally does this: if (this.options.sourceMap) this.addDebugLocation(expr, expression.range); break; @@ -10129,11 +10162,11 @@ function mangleImportName( let arg = args[0]; // if one argument is given, override just the element name // if two arguments are given, override both module and element name - if (arg.kind == NodeKind.LITERAL && (arg).literalKind == LiteralKind.STRING) { + if (arg.isLiteralKind(LiteralKind.STRING)) { mangleImportName_elementName = (arg).value; if (args.length >= 2) { arg = args[1]; - if (arg.kind == NodeKind.LITERAL && (arg).literalKind == LiteralKind.STRING) { + if (arg.isLiteralKind(LiteralKind.STRING)) { mangleImportName_moduleName = mangleImportName_elementName; mangleImportName_elementName = (arg).value; if (args.length > 2) { diff --git a/src/definitions.ts b/src/definitions.ts index 95236a9b14..c9834c174d 100644 --- a/src/definitions.ts +++ b/src/definitions.ts @@ -93,8 +93,8 @@ export abstract class ExportsWalker { visitElement(name: string, element: Element): void { if (element.is(CommonFlags.PRIVATE) && !this.includePrivate) return; var seen = this.seen; - if (seen.has(element) && !element.is(CommonFlags.INSTANCE)) { - this.visitAlias(name, element, seen.get(element)); + if (!element.is(CommonFlags.INSTANCE) && seen.has(element)) { + this.visitAlias(name, element, assert(seen.get(element))); return; } seen.set(element, name); @@ -117,7 +117,8 @@ export abstract class ExportsWalker { break; } case ElementKind.FIELD: { - if ((element).is(CommonFlags.COMPILED)) this.visitField(name, element); + let fieldInstance = element; + if (fieldInstance.is(CommonFlags.COMPILED)) this.visitField(name, fieldInstance); break; } case ElementKind.PROPERTY_PROTOTYPE: { @@ -125,11 +126,11 @@ export abstract class ExportsWalker { break; } case ElementKind.PROPERTY: { - let prop = element; - let getter = prop.getterInstance; - if (getter) this.visitFunction(name, getter); - let setter = prop.setterInstance; - if (setter) this.visitFunction(name, setter); + let propertyInstance = element; + let getterInstance = propertyInstance.getterInstance; + if (getterInstance) this.visitFunction(name, getterInstance); + let setterInstance = propertyInstance.setterInstance; + if (setterInstance) this.visitFunction(name, setterInstance); break; } case ElementKind.NAMESPACE: { @@ -167,7 +168,7 @@ export abstract class ExportsWalker { // var instances = element.instances; // if (instances) { // for (let instance of instances.values()) { - // if (instance.is(CommonFlags.COMPILED)) this.visitProperty(instance); + // if (instance.is(CommonFlags.COMPILED)) this.visitProperty(instance); // } // } assert(false); @@ -238,8 +239,8 @@ export class IDLBuilder extends ExportsWalker { let memberName = unchecked(_keys[i]); let member = assert(members.get(memberName)); if (member.kind == ElementKind.ENUMVALUE) { - let value = member; - let isConst = value.is(CommonFlags.INLINED); + let enumValue = member; + let isConst = enumValue.is(CommonFlags.INLINED); indent(sb, this.indentLevel); if (isConst) sb.push("const "); else sb.push("readonly "); @@ -247,8 +248,8 @@ export class IDLBuilder extends ExportsWalker { sb.push(memberName); if (isConst) { sb.push(" = "); - assert(value.constantValueKind == ConstantValueKind.INTEGER); - sb.push(i64_low(value.constantIntegerValue).toString()); + assert(enumValue.constantValueKind == ConstantValueKind.INTEGER); + sb.push(i64_low(enumValue.constantIntegerValue).toString()); } sb.push(";\n"); } @@ -385,7 +386,6 @@ export class TSDBuilder extends ExportsWalker { private sb: string[] = []; private indentLevel: i32 = 0; - private unknown: Set = new Set(); /** Constructs a new WebIDL builder. */ constructor(program: Program, includePrivate: bool = false) { @@ -427,13 +427,13 @@ export class TSDBuilder extends ExportsWalker { let memberName = unchecked(_keys[i]); let member = assert(members.get(memberName)); if (member.kind == ElementKind.ENUMVALUE) { - let value = member; + let enumValue = member; indent(sb, this.indentLevel); sb.push(memberName); if (member.is(CommonFlags.INLINED)) { sb.push(" = "); - assert(value.constantValueKind == ConstantValueKind.INTEGER); - sb.push(i64_low(value.constantIntegerValue).toString()); + assert(enumValue.constantValueKind == ConstantValueKind.INTEGER); + sb.push(i64_low(enumValue.constantIntegerValue).toString()); } sb.push(",\n"); --remainingMembers; diff --git a/src/extra/ast.ts b/src/extra/ast.ts index 7266545123..ad37ee5269 100644 --- a/src/extra/ast.ts +++ b/src/extra/ast.ts @@ -471,10 +471,12 @@ export class ASTBuilder { var elements = node.elementExpressions; var numElements = elements.length; if (numElements) { - if (elements[0]) this.visitNode(elements[0]); + let element = elements[0]; + if (element) this.visitNode(element); for (let i = 1; i < numElements; ++i) { + element = elements[i]; sb.push(", "); - if (elements[i]) this.visitNode(elements[i]); + if (element) this.visitNode(element); } } sb.push("]"); diff --git a/src/flow.ts b/src/flow.ts index ef330117a1..6296c8078f 100644 --- a/src/flow.ts +++ b/src/flow.ts @@ -1110,7 +1110,7 @@ export class Flow { // TODO: this is inefficient because it has to read a string let global = assert(this.parentFunction.program.elementsByName.get(assert(getGlobalGetName(expr)))); assert(global.kind == ElementKind.GLOBAL); - return canConversionOverflow(assert((global).type), type); + return canConversionOverflow((global).type, type); } case ExpressionId.Binary: { @@ -1316,8 +1316,9 @@ export class Flow { if (instancesByName.has(instanceName)) { let instance = assert(instancesByName.get(instanceName)); assert(instance.kind == ElementKind.FUNCTION); - let returnType = (instance).signature.returnType; - return !(instance).flow.is(FlowFlags.RETURNS_WRAPPED) + let functionInstance = instance; + let returnType = functionInstance.signature.returnType; + return !functionInstance.flow.is(FlowFlags.RETURNS_WRAPPED) || canConversionOverflow(returnType, type); } return false; // assume no overflow for builtins diff --git a/src/parser.ts b/src/parser.ts index ad0f8ac617..fbd248a347 100644 --- a/src/parser.ts +++ b/src/parser.ts @@ -862,7 +862,7 @@ export class Parser extends DiagnosticEmitter { do { let member = this.parseVariableDeclaration(tn, flags, decorators, isFor); if (!member) return null; - members.push(member); + members.push(member); } while (tn.skip(Token.COMMA)); var ret = Node.createVariableStatement(members, decorators, tn.range(startPos, tn.pos)); @@ -972,7 +972,7 @@ export class Parser extends DiagnosticEmitter { while (!tn.skip(Token.CLOSEBRACE)) { let member = this.parseEnumValue(tn, CommonFlags.NONE); if (!member) return null; - members.push(member); + members.push(member); if (!tn.skip(Token.COMMA)) { if (tn.skip(Token.CLOSEBRACE)) { break; @@ -1325,7 +1325,7 @@ export class Parser extends DiagnosticEmitter { : isOptional ? ParameterKind.OPTIONAL : ParameterKind.DEFAULT, - Range.join(startRange, tn.range()) + Range.join(assert(startRange), tn.range()) ); param.flags |= accessFlags; return param; @@ -1644,9 +1644,16 @@ export class Parser extends DiagnosticEmitter { do { let type = this.parseType(tn); if (!type) return null; + if (type.kind != NodeKind.NAMEDTYPE) { + this.error( + DiagnosticCode.Identifier_expected, + type.range + ); + return null; + } if (!isInterface) { - if (!implementsTypes) implementsTypes = [type]; - else implementsTypes.push(type); + if (!implementsTypes) implementsTypes = []; + implementsTypes.push(type); } } while (tn.skip(Token.COMMA)); } @@ -1687,7 +1694,7 @@ export class Parser extends DiagnosticEmitter { if (!tn.skip(Token.CLOSEBRACE)) { do { let member = this.parseClassMember(tn, declaration); - if (member) members.push(member); + if (member) members.push(member); else { this.skipStatement(tn); if (tn.skip(Token.ENDOFFILE)) { @@ -1739,7 +1746,7 @@ export class Parser extends DiagnosticEmitter { if (!tn.skip(Token.CLOSEBRACE)) { do { let member = this.parseClassMember(tn, declaration); - if (member) members.push(member); + if (member) members.push(member); else { this.skipStatement(tn); if (tn.skip(Token.ENDOFFILE)) { @@ -1776,8 +1783,8 @@ export class Parser extends DiagnosticEmitter { do { let decorator = this.parseDecorator(tn); if (!decorator) break; - if (!decorators) decorators = [decorator]; - else decorators.push(decorator); + if (!decorators) decorators = new Array(); + decorators.push(decorator); } while (tn.skip(Token.AT)); if (decorators !== null && isInterface) { this.error( @@ -2242,6 +2249,13 @@ export class Parser extends DiagnosticEmitter { if (tn.skip(Token.COLON)) { let valueType = this.parseType(tn); if (!valueType) return null; + if (valueType.kind != NodeKind.NAMEDTYPE) { + this.error( + DiagnosticCode.Identifier_expected, + valueType.range + ); + return null; + } return Node.createIndexSignatureDeclaration(keyType, valueType, flags, tn.range(start, tn.pos)); } else { this.error( @@ -2831,7 +2845,7 @@ export class Parser extends DiagnosticEmitter { if (!condition) return null; if (tn.skip(Token.CLOSEPAREN)) { - let ret = Node.createDoStatement(statement, condition, tn.range(startPos, tn.pos)); + let ret = Node.createDoStatement(statement, condition, tn.range(startPos, tn.pos)); tn.skip(Token.SEMICOLON); return ret; } else { @@ -3084,13 +3098,13 @@ export class Parser extends DiagnosticEmitter { if (!condition) return null; if (tn.skip(Token.CLOSEPAREN)) { if (tn.skip(Token.OPENBRACE)) { - let cases = new Array(); + let switchCases = new Array(); while (!tn.skip(Token.CLOSEBRACE)) { - let case_ = this.parseSwitchCase(tn); - if (!case_) return null; - cases.push(case_); + let switchCase = this.parseSwitchCase(tn); + if (!switchCase) return null; + switchCases.push(switchCase); } - let ret = Node.createSwitchStatement(condition, cases, tn.range(startPos, tn.pos)); + let ret = Node.createSwitchStatement(condition, switchCases, tn.range(startPos, tn.pos)); tn.skip(Token.SEMICOLON); return ret; } else { @@ -3177,7 +3191,7 @@ export class Parser extends DiagnosticEmitter { var startPos = tn.tokenPos; var expression = this.parseExpression(tn); if (!expression) return null; - var ret = Node.createThrowStatement(expression, tn.range(startPos, tn.pos)); + var ret = Node.createThrowStatement(expression, tn.range(startPos, tn.pos)); tn.skip(Token.SEMICOLON); return ret; } @@ -3198,7 +3212,7 @@ export class Parser extends DiagnosticEmitter { while (!tn.skip(Token.CLOSEBRACE)) { stmt = this.parseStatement(tn); if (!stmt) return null; - statements.push(stmt); + statements.push(stmt); } let catchVariable: IdentifierExpression | null = null; let catchStatements: Statement[] | null = null; @@ -3237,7 +3251,7 @@ export class Parser extends DiagnosticEmitter { while (!tn.skip(Token.CLOSEBRACE)) { stmt = this.parseStatement(tn); if (!stmt) return null; - catchStatements.push(stmt); + catchStatements.push(stmt); } } if (tn.skip(Token.FINALLY)) { @@ -3252,7 +3266,7 @@ export class Parser extends DiagnosticEmitter { while (!tn.skip(Token.CLOSEBRACE)) { stmt = this.parseStatement(tn); if (!stmt) return null; - finallyStatements.push(stmt); + finallyStatements.push(stmt); } } if (!(catchStatements || finallyStatements)) { @@ -3922,7 +3936,7 @@ export class Parser extends DiagnosticEmitter { let next = Node.createIdentifierExpression(tn.readIdentifier(), tn.range()); expr = Node.createPropertyAccessExpression( expr, - next, + next, tn.range(startPos, tn.pos) ); } else { diff --git a/src/program.ts b/src/program.ts index 37d4632fc3..ca70cf3ce8 100644 --- a/src/program.ts +++ b/src/program.ts @@ -16,6 +16,27 @@ * @license Apache-2.0 */ +// Element Base class of all elements +// ├─DeclaredElement Base class of elements with a declaration +// │ ├─TypedElement Base class of elements resolving to a type +// │ │ ├─TypeDefinition Type alias declaration +// │ │ ├─VariableLikeElement Base class of all variable-like elements +// │ │ │ ├─EnumValue Enum value +// │ │ │ ├─Global File global +// │ │ │ ├─Local Function local +// │ │ │ ├─Field Class field (instance only) +// │ │ │ └─Property Class property +// │ │ ├─IndexSignature Class index signature +// │ │ ├─Function Concrete function instance +// │ │ └─Class Concrete class instance +// │ ├─Namespace Namespace with static members +// │ ├─FunctionPrototype Prototype of concrete function instances +// │ ├─FieldPrototype Prototype of concrete field instances +// │ ├─PropertyPrototype Prototype of concrete property instances +// │ └─ClassPrototype Prototype of concrete classe instances +// ├─File File, analogous to Source in the AST +// └─FunctionTarget Indirectly called function helper (typed) + import { CommonFlags, PATH_DELIMITER, @@ -68,7 +89,6 @@ import { Expression, IdentifierExpression, - LiteralExpression, LiteralKind, StringLiteralExpression, @@ -954,7 +974,7 @@ export class Program extends DiagnosticEmitter { if (basePrototype.hasDecorator(DecoratorFlags.SEALED)) { this.error( DiagnosticCode.Class_0_is_sealed_and_cannot_be_extended, - extendsNode.range, (baseElement).identifierNode.text + extendsNode.range, basePrototype.identifierNode.text ); } if ( @@ -1053,8 +1073,8 @@ export class Program extends DiagnosticEmitter { /** Requires that a global function is present and returns it. */ private requireFunction(name: string, typeArguments: Type[] | null = null): Function { - var prototype = this.require(name, ElementKind.FUNCTION_PROTOTYPE); - var resolved = this.resolver.resolveFunction(prototype, typeArguments); + var prototype = this.require(name, ElementKind.FUNCTION_PROTOTYPE); + var resolved = this.resolver.resolveFunction(prototype, typeArguments); if (!resolved) throw new Error("invalid " + name); return resolved; } @@ -1093,9 +1113,10 @@ export class Program extends DiagnosticEmitter { break; } case ElementKind.PROPERTY_PROTOTYPE: { - let getterPrototype = (element).getterPrototype; + let propertyPrototype = element; + let getterPrototype = propertyPrototype.getterPrototype; if (getterPrototype) this.markModuleExport(getterPrototype); - let setterPrototype = (element).setterPrototype; + let setterPrototype = propertyPrototype.setterPrototype; if (setterPrototype) this.markModuleExport(setterPrototype); break; } @@ -1374,10 +1395,11 @@ export class Program extends DiagnosticEmitter { break; } case NodeKind.METHODDECLARATION: { + let methodDeclaration = memberDeclaration; if (memberDeclaration.isAny(CommonFlags.GET | CommonFlags.SET)) { - this.initializeProperty(memberDeclaration, element); + this.initializeProperty(methodDeclaration, element); } else { - this.initializeMethod(memberDeclaration, element); + this.initializeMethod(methodDeclaration, element); } break; } @@ -1481,10 +1503,7 @@ export class Program extends DiagnosticEmitter { let numArgs = args ? args.length : 0; if (numArgs == 1) { let firstArg = (decorator.arguments)[0]; - if ( - firstArg.kind == NodeKind.LITERAL && - (firstArg).literalKind == LiteralKind.STRING - ) { + if (firstArg.isLiteralKind(LiteralKind.STRING)) { let text = (firstArg).value; let kind = OperatorKind.fromDecorator(decorator.decoratorKind, text); if (kind == OperatorKind.INVALID) { @@ -1919,10 +1938,11 @@ export class Program extends DiagnosticEmitter { break; } case NodeKind.METHODDECLARATION: { + let methodDeclaration = memberDeclaration; if (memberDeclaration.isAny(CommonFlags.GET | CommonFlags.SET)) { - this.initializeProperty(memberDeclaration, element); + this.initializeProperty(methodDeclaration, element); } else { - this.initializeMethod(memberDeclaration, element); + this.initializeMethod(methodDeclaration, element); } break; } @@ -2865,7 +2885,8 @@ export class FunctionPrototype extends DeclaredElement { var boundPrototypes = this.boundPrototypes; if (!boundPrototypes) this.boundPrototypes = boundPrototypes = new Map(); else if (boundPrototypes.has(classInstance)) return assert(boundPrototypes.get(classInstance)); - var declaration = this.declaration; assert(declaration.kind == NodeKind.METHODDECLARATION); + var declaration = this.declaration; + assert(declaration.kind == NodeKind.METHODDECLARATION); var bound = new FunctionPrototype( this.name, classInstance, // ! @@ -2882,7 +2903,7 @@ export class FunctionPrototype extends DeclaredElement { /** Gets the resolved instance for the specified instance key, if already resolved. */ getResolvedInstance(instanceKey: string): Function | null { var instances = this.instances; - if (instances !== null && instances.has(instanceKey)) return instances.get(instanceKey); + if (instances !== null && instances.has(instanceKey)) return assert(instances.get(instanceKey)); return null; } @@ -3260,15 +3281,22 @@ export class Property extends VariableLikeElement { } } -/** An resolved index signature. */ -export class IndexSignature extends VariableLikeElement { +/** A resolved index signature. */ +export class IndexSignature extends TypedElement { /** Constructs a new index prototype. */ constructor( /** Parent class. */ parent: Class ) { - super(ElementKind.INDEXSIGNATURE, parent.internalName + "[]", parent); + super( + ElementKind.INDEXSIGNATURE, + "[]", + parent.internalName + "[]", + parent.program, + parent, + parent.program.makeNativeVariableDeclaration("[]") // is fine + ); } /** Obtains the getter instance. */ @@ -3626,10 +3654,11 @@ export class Class extends TypedElement { /** Writes a field value to a buffer and returns the number of bytes written. */ writeField(name: string, value: T, buffer: Uint8Array, baseOffset: i32): i32 { - var field = this.lookupInSelf(name); - if (field !== null && field.kind == ElementKind.FIELD) { - let offset = baseOffset + (field).memoryOffset; - switch ((field).type.kind) { + var element = this.lookupInSelf(name); + if (element !== null && element.kind == ElementKind.FIELD) { + let fieldInstance = element; + let offset = baseOffset + fieldInstance.memoryOffset; + switch (fieldInstance.type.kind) { case TypeKind.I8: case TypeKind.U8: { writeI8(i32(value), buffer, offset); diff --git a/src/resolver.ts b/src/resolver.ts index 7084d50493..f7868164e5 100644 --- a/src/resolver.ts +++ b/src/resolver.ts @@ -260,6 +260,7 @@ export class Resolver extends DiagnosticEmitter { // Handle type definitions if (element.kind == ElementKind.TYPEDEFINITION) { + let typeDefinition = element; // Shortcut already resolved (mostly builtins) if (element.is(CommonFlags.RESOLVED)) { @@ -271,7 +272,7 @@ export class Resolver extends DiagnosticEmitter { ); } } - let type = (element).type; + let type = typeDefinition.type; if (node.isNullable) { if (!type.is(TypeFlags.REFERENCE)) { if (reportMode == ReportMode.REPORT) { @@ -297,7 +298,7 @@ export class Resolver extends DiagnosticEmitter { } // Resolve normally - let typeParameterNodes = (element).typeParameterNodes; + let typeParameterNodes = typeDefinition.typeParameterNodes; let typeArguments: Type[] | null = null; if (typeParameterNodes) { typeArguments = this.resolveTypeArguments( @@ -316,7 +317,7 @@ export class Resolver extends DiagnosticEmitter { ); } let type = this.resolveType( - (element).typeNode, + typeDefinition.typeNode, element, ctxTypes, reportMode @@ -826,11 +827,12 @@ export class Resolver extends DiagnosticEmitter { typeParameterNames: Set ): void { if (node.kind == NodeKind.NAMEDTYPE) { - let typeArgumentNodes = (node).typeArguments; + let namedTypeNode = node; + let typeArgumentNodes = namedTypeNode.typeArguments; if (typeArgumentNodes !== null && typeArgumentNodes.length > 0) { // foo(bar: Array) let classReference = type.classReference; if (classReference) { - let classPrototype = this.resolveTypeName((node).name, ctxFlow.actualFunction); + let classPrototype = this.resolveTypeName(namedTypeNode.name, ctxFlow.actualFunction); if (!classPrototype || classPrototype.kind != ElementKind.CLASS_PROTOTYPE) return; if (classReference.prototype == classPrototype) { let typeArguments = classReference.typeArguments; @@ -843,7 +845,7 @@ export class Resolver extends DiagnosticEmitter { } } } else { // foo(bar: T) - let name = (node).name.identifier.text; + let name = namedTypeNode.name.identifier.text; if (ctxTypes.has(name)) { let currentType = assert(ctxTypes.get(name)); if (currentType == Type.auto || (typeParameterNames.has(name) && currentType.isAssignableTo(type))) { @@ -852,18 +854,19 @@ export class Resolver extends DiagnosticEmitter { } } } else if (node.kind == NodeKind.FUNCTIONTYPE) { // foo(bar: (baz: T) => i32)) - let parameterNodes = (node).parameters; + let functionTypeNode = node; + let parameterNodes = functionTypeNode.parameters; if (parameterNodes !== null && parameterNodes.length > 0) { let signatureReference = type.signatureReference; if (signatureReference) { let parameterTypes = signatureReference.parameterTypes; let thisType = signatureReference.thisType; - if (parameterTypes.length == parameterNodes.length && !thisType == !(node).explicitThisType) { + if (parameterTypes.length == parameterNodes.length && !thisType == !functionTypeNode.explicitThisType) { for (let i = 0, k = parameterTypes.length; i < k; ++i) { this.propagateInferredGenericTypes(parameterNodes[i].type, parameterTypes[i], ctxFlow, ctxTypes, typeParameterNames); } - this.propagateInferredGenericTypes((node).returnType, signatureReference.returnType, ctxFlow, ctxTypes, typeParameterNames); - if (thisType) this.propagateInferredGenericTypes((node).explicitThisType!, thisType, ctxFlow, ctxTypes, typeParameterNames); + this.propagateInferredGenericTypes(functionTypeNode.returnType, signatureReference.returnType, ctxFlow, ctxTypes, typeParameterNames); + if (thisType) this.propagateInferredGenericTypes(functionTypeNode.explicitThisType!, thisType, ctxFlow, ctxTypes, typeParameterNames); return; } } @@ -887,7 +890,9 @@ export class Resolver extends DiagnosticEmitter { } return type; } - if (kind == ElementKind.FUNCTION_TARGET) return (element).type; + if (kind == ElementKind.FUNCTION_TARGET) { + return (element).type; + } return null; } @@ -1280,7 +1285,9 @@ export class Resolver extends DiagnosticEmitter { case ElementKind.ENUMVALUE: case ElementKind.LOCAL: case ElementKind.FIELD: { // someVar.prop - let type = (target).type; assert(type != Type.void); + let variableLikeElement = target; + let type = variableLikeElement.type; + assert(type != Type.void); let classReference = type.classReference; if (!classReference) { let wrapperClasses = this.program.wrapperClasses; @@ -1290,7 +1297,7 @@ export class Resolver extends DiagnosticEmitter { if (reportMode == ReportMode.REPORT) { this.error( DiagnosticCode.Property_0_does_not_exist_on_type_1, - node.property.range, propertyName, (target).type.toString() + node.property.range, propertyName, variableLikeElement.type.toString() ); } return null; @@ -1300,8 +1307,9 @@ export class Resolver extends DiagnosticEmitter { break; } case ElementKind.PROPERTY_PROTOTYPE: { // SomeClass.prop + let propertyPrototype = target; let getterInstance = this.resolveFunction( // reports - assert((target).getterPrototype), // must have a getter + assert(propertyPrototype.getterPrototype), // must have a getter null, makeMap(), reportMode @@ -1327,7 +1335,8 @@ export class Resolver extends DiagnosticEmitter { break; } case ElementKind.PROPERTY: { // someInstance.prop - let getterInstance = assert((target).getterInstance); // must have a getter + let propertyInstance = target; + let getterInstance = assert(propertyInstance.getterInstance); // must have a getter let type = getterInstance.signature.returnType; let classReference = type.classReference; if (!classReference) { @@ -1348,10 +1357,12 @@ export class Resolver extends DiagnosticEmitter { break; } case ElementKind.INDEXSIGNATURE: { // someInstance[x].prop - let elementExpression = assert(this.currentElementExpression); - let parent = (target).parent; + let indexSignature = target; + let parent = indexSignature.parent; assert(parent.kind == ElementKind.CLASS); - let indexedGet = (parent).lookupOverload(OperatorKind.INDEXED_GET); + let classInstance = parent; + let elementExpression = assert(this.currentElementExpression); + let indexedGet = classInstance.lookupOverload(OperatorKind.INDEXED_GET); if (!indexedGet) { if (reportMode == ReportMode.REPORT) { this.error( @@ -1407,15 +1418,19 @@ export class Resolver extends DiagnosticEmitter { } // traverse inherited static members on the base prototype if target is a class prototype if (target.kind == ElementKind.CLASS_PROTOTYPE) { - if ((target).basePrototype) { - target = (target).basePrototype; + let classPrototype = target; + let basePrototype = classPrototype.basePrototype; + if (basePrototype) { + target = basePrototype; } else { break; } // traverse inherited instance members on the base class if target is a class instance } else if (target.kind == ElementKind.CLASS) { - if ((target).base) { - target = (target).base; + let classInstance = target; + let baseInstance = classInstance.base; + if (baseInstance) { + target = baseInstance; } else { break; } @@ -1734,7 +1749,7 @@ export class Resolver extends DiagnosticEmitter { switch (operator) { case Token.MINUS: { // implicitly negate if an integer literal to distinguish between i32/u32/i64 - if (operand.kind == NodeKind.LITERAL && (operand).literalKind == LiteralKind.INTEGER) { + if (operand.isLiteralKind(LiteralKind.INTEGER)) { return this.determineIntegerLiteralType(i64_sub(i64_zero, (operand).value), ctxType); } // fall-through @@ -2377,18 +2392,21 @@ export class Resolver extends DiagnosticEmitter { if (!target) return null; switch (target.kind) { case ElementKind.FUNCTION_PROTOTYPE: { + let functionPrototype = target; // `unchecked` behaves like parenthesized if ( - (target).internalName == BuiltinNames.unchecked && + functionPrototype.internalName == BuiltinNames.unchecked && node.arguments.length > 0 ) { return this.resolveExpression(node.arguments[0], ctxFlow, ctxType, reportMode); } - let instance = this.maybeInferCall(node, target, ctxFlow, reportMode); + let instance = this.maybeInferCall(node, functionPrototype, ctxFlow, reportMode); if (!instance) return null; return instance.signature.returnType; } - case ElementKind.FUNCTION_TARGET: return (target).signature.returnType; + case ElementKind.FUNCTION_TARGET: { + return (target).signature.returnType; + } } if (reportMode == ReportMode.REPORT) { this.error( @@ -2791,9 +2809,10 @@ export class Resolver extends DiagnosticEmitter { // If this is an instance method, first apply the class's type arguments if (prototype.is(CommonFlags.INSTANCE)) { assert(actualParent.kind == ElementKind.CLASS); - let classTypeArguments = (actualParent).typeArguments; + let classInstance = actualParent; + let classTypeArguments = classInstance.typeArguments; if (classTypeArguments) { - let typeParameterNodes = assert((actualParent).prototype.typeParameterNodes); + let typeParameterNodes = assert(classInstance.prototype.typeParameterNodes); let numClassTypeArguments = classTypeArguments.length; assert(numClassTypeArguments == typeParameterNodes.length); for (let i = 0; i < numClassTypeArguments; ++i) { @@ -2959,14 +2978,15 @@ export class Resolver extends DiagnosticEmitter { switch (member.kind) { case ElementKind.FIELD_PROTOTYPE: { - let fieldTypeNode = (member).typeNode; + let fieldPrototype = member; + let fieldTypeNode = fieldPrototype.typeNode; let fieldType: Type | null = null; // TODO: handle duplicate non-private fields specifically? if (!fieldTypeNode) { if (base) { let baseMembers = base.members; - if (baseMembers !== null && baseMembers.has((member).name)) { - let baseField = assert(baseMembers.get((member).name)); + if (baseMembers !== null && baseMembers.has(fieldPrototype.name)) { + let baseField = assert(baseMembers.get(fieldPrototype.name)); if (!baseField.is(CommonFlags.PRIVATE)) { assert(baseField.kind == ElementKind.FIELD); fieldType = (baseField).type; @@ -2977,7 +2997,7 @@ export class Resolver extends DiagnosticEmitter { if (reportMode == ReportMode.REPORT) { this.error( DiagnosticCode.Type_expected, - (member).identifierNode.range.atEnd + fieldPrototype.identifierNode.range.atEnd ); } } @@ -2990,13 +3010,13 @@ export class Resolver extends DiagnosticEmitter { ); } if (!fieldType) break; // did report above - let field = new Field(member, instance, fieldType); + let fieldInstance = new Field(fieldPrototype, instance, fieldType); assert(isPowerOf2(fieldType.byteSize)); let mask = fieldType.byteSize - 1; if (memoryOffset & mask) memoryOffset = (memoryOffset | mask) + 1; - field.memoryOffset = memoryOffset; + fieldInstance.memoryOffset = memoryOffset; memoryOffset += fieldType.byteSize; - instance.add(member.name, field); // reports + instance.add(member.name, fieldInstance); // reports break; } case ElementKind.FUNCTION_PROTOTYPE: { @@ -3005,8 +3025,9 @@ export class Resolver extends DiagnosticEmitter { break; } case ElementKind.PROPERTY_PROTOTYPE: { - let propertyInstance = new Property(member, instance); - let getterPrototype = (member).getterPrototype; + let propertyPrototype = member; + let propertyInstance = new Property(propertyPrototype, instance); + let getterPrototype = propertyPrototype.getterPrototype; if (getterPrototype) { let getterInstance = this.resolveFunction( getterPrototype.toBound(instance), @@ -3019,7 +3040,7 @@ export class Resolver extends DiagnosticEmitter { propertyInstance.setType(getterInstance.signature.returnType); } } - let setterPrototype = (member).setterPrototype; + let setterPrototype = propertyPrototype.setterPrototype; if (setterPrototype) { let setterInstance = this.resolveFunction( setterPrototype.toBound(instance), diff --git a/tests/bootstrap/index.ts b/tests/bootstrap/index.ts index 673bc0a358..60828f9610 100644 --- a/tests/bootstrap/index.ts +++ b/tests/bootstrap/index.ts @@ -1,12 +1,13 @@ import * as fs from "fs"; import * as binaryen from "binaryen"; +import * as util from "util"; import * as loader from "../../lib/loader"; import AssemblyScript from "../../out/assemblyscript"; async function test(build: string): Promise { await binaryen.ready; const assemblyscript = await loader.instantiate(fs.promises.readFile(__dirname + "/../../out/assemblyscript." + build + ".wasm"), { binaryen }); - console.log(assemblyscript); + console.log(util.inspect(assemblyscript, true)); const optionsPtr = assemblyscript.newOptions(); const programPtr = assemblyscript.newProgram(optionsPtr); const textPtr = assemblyscript.__allocString("export function add(a: i32, b: i32): i32 { return a + b; }\n");