diff --git a/src/builtins.ts b/src/builtins.ts index 7bd978ce..d163e1b8 100644 --- a/src/builtins.ts +++ b/src/builtins.ts @@ -648,7 +648,7 @@ export function compileCall( checkTypeAbsent(typeArguments, reportNode, prototype) | checkArgsRequired(operands, 1, reportNode, compiler) ) return module.unreachable(); - let expr = compiler.compileExpressionRetainType(operands[0], Type.i32); + let expr = compiler.compileExpression(operands[0], Type.auto); compiler.currentType = Type.bool; return module.i32(getExpressionId(expr) == ExpressionId.Const ? 1 : 0); } @@ -1555,6 +1555,7 @@ export function compileCall( ) return module.unreachable(); let type = typeArguments![0]; let outType = ( + contextualType != Type.auto && type.is(TypeFlags.INTEGER) && contextualType.is(TypeFlags.INTEGER) && contextualType.size > type.size @@ -1965,7 +1966,7 @@ export function compileCall( ) return module.unreachable(); let arg0 = typeArguments ? compiler.compileExpression(operands[0], typeArguments[0], ContextualFlags.IMPLICIT) - : compiler.compileExpressionRetainType(operands[0], Type.i32); + : compiler.compileExpression(operands[0], Type.auto); let type = compiler.currentType; if (!type.isAny(TypeFlags.VALUE | TypeFlags.REFERENCE)) { compiler.error( @@ -1976,7 +1977,7 @@ export function compileCall( } let arg1 = compiler.compileExpression(operands[1], type, ContextualFlags.IMPLICIT); let arg2 = compiler.makeIsTrueish( - compiler.compileExpressionRetainType(operands[2], Type.bool), + compiler.compileExpression(operands[2], Type.bool), compiler.currentType // ^ ); compiler.currentType = type; @@ -2060,7 +2061,7 @@ export function compileCall( checkArgsRequired(operands, 1, reportNode, compiler) ) return module.unreachable(); let toType = typeArguments![0]; - let arg0 = compiler.compileExpressionRetainType(operands[0], toType); + let arg0 = compiler.compileExpression(operands[0], toType); let fromType = compiler.currentType; compiler.currentType = toType; if (fromType.size != toType.size) { @@ -2085,7 +2086,7 @@ export function compileCall( } let arg0 = typeArguments ? compiler.compileExpression(operands[0], typeArguments[0], ContextualFlags.IMPLICIT | ContextualFlags.WRAP) - : compiler.compileExpressionRetainType(operands[0], Type.bool, ContextualFlags.WRAP); + : compiler.compileExpression(operands[0], Type.bool, ContextualFlags.WRAP); let type = compiler.currentType; compiler.currentType = type.nonNullableType; @@ -2272,7 +2273,7 @@ export function compileCall( checkArgsOptional(operands, 1, i32.MAX_VALUE, reportNode, compiler) ) return module.unreachable(); let returnType = typeArguments ? typeArguments[0] : contextualType; - let arg0 = compiler.compileExpressionRetainType(operands[0], Type.u32); + let arg0 = compiler.compileExpression(operands[0], Type.u32); let arg0Type = compiler.currentType; if (!( arg0Type == Type.u32 || // either plain index @@ -2290,7 +2291,7 @@ export function compileCall( let parameterTypes = new Array(numOperands); let nativeParamTypes = new Array(numOperands); for (let i = 0; i < numOperands; ++i) { - operandExprs[i] = compiler.compileExpressionRetainType(operands[1 + i], Type.i32); + operandExprs[i] = compiler.compileExpression(operands[1 + i], Type.i32); let operandType = compiler.currentType; parameterTypes[i] = operandType; nativeParamTypes[i] = operandType.toNativeType(); @@ -4232,21 +4233,17 @@ function evaluateConstantType( return typeArguments[0]; } if (operands.length == 1) { // optional type argument - if (typeArguments) { - if (typeArguments.length == 1) { - compiler.compileExpression(operands[0], typeArguments[0], ContextualFlags.IMPLICIT); - } else { - if (typeArguments.length) { - compiler.error( - DiagnosticCode.Expected_0_type_arguments_but_got_1, - reportNode.typeArgumentsRange, "1", typeArguments.length.toString(10) - ); - return null; - } - compiler.compileExpressionRetainType(operands[0], Type.i32); + if (typeArguments !== null && typeArguments.length) { + if (typeArguments.length > 1) { + compiler.error( + DiagnosticCode.Expected_0_type_arguments_but_got_1, + reportNode.typeArgumentsRange, "1", typeArguments.length.toString(10) + ); + return null; } + compiler.compileExpression(operands[0], typeArguments[0], ContextualFlags.IMPLICIT); } else { - compiler.compileExpressionRetainType(operands[0], Type.i32); + compiler.compileExpression(operands[0], Type.auto); } return compiler.currentType; } diff --git a/src/compiler.ts b/src/compiler.ts index c55b6cf4..a4352acb 100644 --- a/src/compiler.ts +++ b/src/compiler.ts @@ -248,10 +248,8 @@ export const enum ContextualFlags { WILL_DROP = 1 << 3, /** Value is known to be immediately assigned to a retaining target. */ SKIP_AUTORELEASE = 1 << 4, - /** Is the last statement in a function body. */ - LAST_IN_BODY = 1 << 5, /** Data can be compiled statically. */ - STATIC_CAPABLE = 1 << 6 + STATIC_CAPABLE = 1 << 5 } /** Runtime features to be activated by the compiler. */ @@ -814,7 +812,7 @@ export class Compiler extends DiagnosticEmitter { if (global.hasDecorator(DecoratorFlags.LAZY)) { this.currentFlow = global.file.startFunction.flow; } - initExpr = this.compileExpression(initializerNode, Type.i32, // reports + initExpr = this.compileExpression(initializerNode, Type.auto, // reports ContextualFlags.WRAP | ContextualFlags.SKIP_AUTORELEASE ); if (this.skippedAutoreleases.has(initExpr)) initAutoreleaseSkipped = true; @@ -1686,70 +1684,70 @@ export class Compiler extends DiagnosticEmitter { compileStatement( statement: Statement, - contextualFlags: ContextualFlags = ContextualFlags.NONE + isLastInBody: bool = false ): ExpressionRef { var module = this.module; var stmt: ExpressionRef; switch (statement.kind) { case NodeKind.BLOCK: { - stmt = this.compileBlockStatement(statement, contextualFlags); + stmt = this.compileBlockStatement(statement); break; } case NodeKind.BREAK: { - stmt = this.compileBreakStatement(statement, contextualFlags); + stmt = this.compileBreakStatement(statement); break; } case NodeKind.CONTINUE: { - stmt = this.compileContinueStatement(statement, contextualFlags); + stmt = this.compileContinueStatement(statement); break; } case NodeKind.DO: { - stmt = this.compileDoStatement(statement, contextualFlags); + stmt = this.compileDoStatement(statement); break; } case NodeKind.EMPTY: { - stmt = this.compileEmptyStatement(statement, contextualFlags); + stmt = this.compileEmptyStatement(statement); break; } case NodeKind.EXPRESSION: { - stmt = this.compileExpressionStatement(statement, contextualFlags); + stmt = this.compileExpressionStatement(statement); break; } case NodeKind.FOR: { - stmt = this.compileForStatement(statement, contextualFlags); + stmt = this.compileForStatement(statement); break; } case NodeKind.IF: { - stmt = this.compileIfStatement(statement, contextualFlags); + stmt = this.compileIfStatement(statement); break; } case NodeKind.RETURN: { - stmt = this.compileReturnStatement(statement, contextualFlags); + stmt = this.compileReturnStatement(statement, isLastInBody); break; } case NodeKind.SWITCH: { - stmt = this.compileSwitchStatement(statement, contextualFlags); + stmt = this.compileSwitchStatement(statement); break; } case NodeKind.THROW: { - stmt = this.compileThrowStatement(statement, contextualFlags); + stmt = this.compileThrowStatement(statement); break; } case NodeKind.TRY: { - stmt = this.compileTryStatement(statement, contextualFlags); + stmt = this.compileTryStatement(statement); break; } case NodeKind.VARIABLE: { - stmt = this.compileVariableStatement(statement, contextualFlags); + stmt = this.compileVariableStatement(statement); if (!stmt) stmt = module.nop(); break; } case NodeKind.VOID: { - stmt = this.compileVoidStatement(statement, contextualFlags); + stmt = this.compileVoidStatement(statement); break; } case NodeKind.WHILE: { - stmt = this.compileWhileStatement(statement, contextualFlags); + stmt = this.compileWhileStatement(statement); break; } case NodeKind.TYPEDECLARATION: { @@ -1783,11 +1781,7 @@ export class Compiler extends DiagnosticEmitter { var module = this.module; var flow = this.currentFlow; for (let i = 0; i < numStatements; ++i) { - let stmt = this.compileStatement(statements[i], - isBody && i == numStatements - 1 - ? ContextualFlags.LAST_IN_BODY - : ContextualFlags.NONE - ); + let stmt = this.compileStatement(statements[i], isBody && i == numStatements - 1); switch (getExpressionId(stmt)) { case ExpressionId.Block: { if (!getBlockName(stmt)) { @@ -1808,8 +1802,7 @@ export class Compiler extends DiagnosticEmitter { } compileBlockStatement( - statement: BlockStatement, - contextualFlags: ContextualFlags + statement: BlockStatement ): ExpressionRef { var statements = statement.statements; var outerFlow = this.currentFlow; @@ -1825,8 +1818,7 @@ export class Compiler extends DiagnosticEmitter { } compileBreakStatement( - statement: BreakStatement, - contextualFlags: ContextualFlags + statement: BreakStatement ): ExpressionRef { var module = this.module; if (statement.label) { @@ -1859,8 +1851,7 @@ export class Compiler extends DiagnosticEmitter { } compileContinueStatement( - statement: ContinueStatement, - contextualFlags: ContextualFlags + statement: ContinueStatement ): ExpressionRef { var module = this.module; var label = statement.label; @@ -1895,8 +1886,7 @@ export class Compiler extends DiagnosticEmitter { } compileDoStatement( - statement: DoStatement, - contextualFlags: ContextualFlags + statement: DoStatement ): ExpressionRef { var module = this.module; @@ -1967,24 +1957,19 @@ export class Compiler extends DiagnosticEmitter { } compileEmptyStatement( - statement: EmptyStatement, - contextualFlags: ContextualFlags + statement: EmptyStatement ): ExpressionRef { return this.module.nop(); } compileExpressionStatement( - statement: ExpressionStatement, - contextualFlags: ContextualFlags, + statement: ExpressionStatement ): ExpressionRef { - return this.compileExpression(statement.expression, Type.void, - contextualFlags | ContextualFlags.EXPLICIT | ContextualFlags.WILL_DROP - ); + return this.compileExpression(statement.expression, Type.void, ContextualFlags.IMPLICIT); } compileForStatement( - statement: ForStatement, - contextualFlags: ContextualFlags + statement: ForStatement ): ExpressionRef { var module = this.module; @@ -2005,7 +1990,7 @@ export class Compiler extends DiagnosticEmitter { if (statement.condition) { condExpr = module.precomputeExpression( this.makeIsTrueish( - this.compileExpressionRetainType(statement.condition, Type.bool), + this.compileExpression(statement.condition, Type.bool), this.currentType ) ); @@ -2113,8 +2098,7 @@ export class Compiler extends DiagnosticEmitter { } compileIfStatement( - statement: IfStatement, - contextualFlags: ContextualFlags + statement: IfStatement ): ExpressionRef { var module = this.module; var ifTrue = statement.ifTrue; @@ -2124,7 +2108,7 @@ export class Compiler extends DiagnosticEmitter { // The condition doesn't initiate a branch yet var condExpr = module.precomputeExpression( this.makeIsTrueish( - this.compileExpressionRetainType(statement.condition, Type.bool), + this.compileExpression(statement.condition, Type.bool), this.currentType ) ); @@ -2189,7 +2173,7 @@ export class Compiler extends DiagnosticEmitter { compileReturnStatement( statement: ReturnStatement, - contextualFlags: ContextualFlags + isLastInBody: bool ): ExpressionRef { var module = this.module; var expr: ExpressionRef = 0; @@ -2256,7 +2240,7 @@ export class Compiler extends DiagnosticEmitter { flow.freeScopedLocals(); // If the last statement anyway, make it the block's return value - if ((contextualFlags & ContextualFlags.LAST_IN_BODY) != 0 && expr && returnType != Type.void) { + if (isLastInBody && expr && returnType != Type.void) { if (!stmts.length) return expr; stmts.push(expr); return module.block(null, stmts, returnType.toNativeType()); @@ -2276,7 +2260,9 @@ export class Compiler extends DiagnosticEmitter { return module.block(null, stmts); } - compileSwitchStatement(statement: SwitchStatement, contextualFlags: ContextualFlags): ExpressionRef { + compileSwitchStatement( + statement: SwitchStatement + ): ExpressionRef { var module = this.module; var cases = statement.cases; @@ -2389,8 +2375,7 @@ export class Compiler extends DiagnosticEmitter { } compileThrowStatement( - statement: ThrowStatement, - contextualFlags: ContextualFlags + statement: ThrowStatement ): ExpressionRef { var flow = this.currentFlow; @@ -2413,8 +2398,7 @@ export class Compiler extends DiagnosticEmitter { } compileTryStatement( - statement: TryStatement, - contextualFlags: ContextualFlags + statement: TryStatement ): ExpressionRef { // TODO: can't yet support something like: try { return ... } finally { ... } // worthwhile to investigate lowering returns to block results (here)? @@ -2426,7 +2410,9 @@ export class Compiler extends DiagnosticEmitter { } /** Compiles a variable statement. Returns `0` if an initializer is not necessary. */ - compileVariableStatement(statement: VariableStatement, contextualFlags: ContextualFlags): ExpressionRef { + compileVariableStatement( + statement: VariableStatement + ): ExpressionRef { var module = this.module; var declarations = statement.declarations; var numDeclarations = declarations.length; @@ -2458,7 +2444,7 @@ export class Compiler extends DiagnosticEmitter { // Otherwise infer type from initializer } else if (declaration.initializer) { - initExpr = this.compileExpressionRetainType(declaration.initializer, Type.void, + initExpr = this.compileExpression(declaration.initializer, Type.auto, ContextualFlags.SKIP_AUTORELEASE ); // reports initAutoreleaseSkipped = this.skippedAutoreleases.has(initExpr); @@ -2617,20 +2603,24 @@ export class Compiler extends DiagnosticEmitter { : flatten(module, initializers, NativeType.None); } - compileVoidStatement(statement: VoidStatement, contextualFlags: ContextualFlags): ExpressionRef { + compileVoidStatement( + statement: VoidStatement + ): ExpressionRef { return this.compileExpression(statement.expression, Type.void, ContextualFlags.EXPLICIT | ContextualFlags.WILL_DROP ); } - compileWhileStatement(statement: WhileStatement, contextualFlags: ContextualFlags): ExpressionRef { + compileWhileStatement( + statement: WhileStatement + ): ExpressionRef { var module = this.module; var outerFlow = this.currentFlow; // Compile condition var condExpr = module.precomputeExpression( this.makeIsTrueish( - this.compileExpressionRetainType(statement.condition, Type.bool), + this.compileExpression(statement.condition, Type.bool), this.currentType ) ); @@ -2885,20 +2875,6 @@ export class Compiler extends DiagnosticEmitter { return expr; } - /** Compiles an expression while retaining the type, that is not void, it ultimately compiles to. */ - compileExpressionRetainType( - expression: Expression, - contextualType: Type, - contextualFlags: ContextualFlags = ContextualFlags.NONE - ): ExpressionRef { - return this.compileExpression(expression, - contextualType == Type.void - ? Type.i32 // default to i32 - : contextualType, - (contextualFlags & ~(ContextualFlags.IMPLICIT | ContextualFlags.EXPLICIT)) - ); - } - /** Compiles and precomputes an expression, possibly yielding a costant value. */ precomputeExpression( expression: Expression, @@ -3108,6 +3084,7 @@ export class Compiler extends DiagnosticEmitter { contextualType: Type, contextualFlags: ContextualFlags ): ExpressionRef { + var inheritedFlags = contextualFlags & ~(ContextualFlags.IMPLICIT | ContextualFlags.EXPLICIT); switch (expression.assertionKind) { case AssertionKind.PREFIX: case AssertionKind.AS: { @@ -3118,13 +3095,11 @@ export class Compiler extends DiagnosticEmitter { flow.contextualTypeArguments ); if (!toType) return this.module.unreachable(); - return this.compileExpression(expression.expression, toType, - contextualFlags | ContextualFlags.EXPLICIT - ); + return this.compileExpression(expression.expression, toType, inheritedFlags | ContextualFlags.EXPLICIT); } case AssertionKind.NONNULL: { assert(!expression.toType); - let expr = this.compileExpressionRetainType(expression.expression, contextualType); + let expr = this.compileExpression(expression.expression, contextualType.exceptVoid, inheritedFlags); let type = this.currentType; if (this.currentFlow.isNonnull(expr, type)) { this.info( @@ -3177,7 +3152,7 @@ export class Compiler extends DiagnosticEmitter { var operator = expression.operator; switch (operator) { case Token.LESSTHAN: { - leftExpr = this.compileExpressionRetainType(left, contextualType); + leftExpr = this.compileExpression(left, contextualType); leftType = this.currentType; // check operator overload @@ -3197,7 +3172,7 @@ export class Compiler extends DiagnosticEmitter { return this.module.unreachable(); } - rightExpr = this.compileExpressionRetainType(right, leftType); + rightExpr = this.compileExpression(right, leftType); rightType = this.currentType; if (commonType = Type.commonDenominator(leftType, rightType, true)) { leftExpr = this.convertExpression(leftExpr, @@ -3277,7 +3252,7 @@ export class Compiler extends DiagnosticEmitter { break; } case Token.GREATERTHAN: { - leftExpr = this.compileExpressionRetainType(left, contextualType); + leftExpr = this.compileExpression(left, contextualType); leftType = this.currentType; // check operator overload @@ -3297,7 +3272,7 @@ export class Compiler extends DiagnosticEmitter { return this.module.unreachable(); } - rightExpr = this.compileExpressionRetainType(right, leftType); + rightExpr = this.compileExpression(right, leftType); rightType = this.currentType; if (commonType = Type.commonDenominator(leftType, rightType, true)) { leftExpr = this.convertExpression(leftExpr, @@ -3377,7 +3352,7 @@ export class Compiler extends DiagnosticEmitter { break; } case Token.LESSTHAN_EQUALS: { - leftExpr = this.compileExpressionRetainType(left, contextualType); + leftExpr = this.compileExpression(left, contextualType); leftType = this.currentType; // check operator overload @@ -3397,7 +3372,7 @@ export class Compiler extends DiagnosticEmitter { return this.module.unreachable(); } - rightExpr = this.compileExpressionRetainType(right, leftType); + rightExpr = this.compileExpression(right, leftType); rightType = this.currentType; if (commonType = Type.commonDenominator(leftType, rightType, true)) { leftExpr = this.convertExpression(leftExpr, @@ -3477,7 +3452,7 @@ export class Compiler extends DiagnosticEmitter { break; } case Token.GREATERTHAN_EQUALS: { - leftExpr = this.compileExpressionRetainType(left, contextualType); + leftExpr = this.compileExpression(left, contextualType); leftType = this.currentType; // check operator overload @@ -3497,7 +3472,7 @@ export class Compiler extends DiagnosticEmitter { return this.module.unreachable(); } - rightExpr = this.compileExpressionRetainType(right, leftType); + rightExpr = this.compileExpression(right, leftType); rightType = this.currentType; if (commonType = Type.commonDenominator(leftType, rightType, true)) { leftExpr = this.convertExpression(leftExpr, @@ -3584,7 +3559,7 @@ export class Compiler extends DiagnosticEmitter { // checking for a possible use of unary EQZ. while the most classic of all optimizations, // that's not what the source told us to do. for reference, `!left` emits unary EQZ. - leftExpr = this.compileExpressionRetainType(left, contextualType); + leftExpr = this.compileExpression(left, contextualType); leftType = this.currentType; // check operator overload @@ -3600,7 +3575,7 @@ export class Compiler extends DiagnosticEmitter { // still allow '==' with references } - rightExpr = this.compileExpressionRetainType(right, leftType); + rightExpr = this.compileExpression(right, leftType); rightType = this.currentType; if (commonType = Type.commonDenominator(leftType, rightType, false)) { leftExpr = this.convertExpression(leftExpr, @@ -3672,7 +3647,7 @@ export class Compiler extends DiagnosticEmitter { } case Token.EXCLAMATION_EQUALS_EQUALS: case Token.EXCLAMATION_EQUALS: { - leftExpr = this.compileExpressionRetainType(left, contextualType); + leftExpr = this.compileExpression(left, contextualType); leftType = this.currentType; // check operator overload @@ -3688,7 +3663,7 @@ export class Compiler extends DiagnosticEmitter { // still allow '!=' with references } - rightExpr = this.compileExpressionRetainType(right, leftType); + rightExpr = this.compileExpression(right, leftType); rightType = this.currentType; if (commonType = Type.commonDenominator(leftType, rightType, false)) { leftExpr = this.convertExpression(leftExpr, @@ -3763,7 +3738,7 @@ export class Compiler extends DiagnosticEmitter { } case Token.PLUS_EQUALS: compound = true; case Token.PLUS: { - leftExpr = this.compileExpressionRetainType(left, contextualType); + leftExpr = this.compileExpression(left, contextualType); leftType = this.currentType; // check operator overload @@ -3786,7 +3761,7 @@ export class Compiler extends DiagnosticEmitter { if (compound) { rightExpr = this.compileExpression(right, leftType, ContextualFlags.IMPLICIT); } else { - rightExpr = this.compileExpressionRetainType(right, leftType); + rightExpr = this.compileExpression(right, leftType); rightType = this.currentType; if (commonType = Type.commonDenominator(leftType, rightType, false)) { leftExpr = this.convertExpression(leftExpr, @@ -3852,7 +3827,7 @@ export class Compiler extends DiagnosticEmitter { } case Token.MINUS_EQUALS: compound = true; case Token.MINUS: { - leftExpr = this.compileExpressionRetainType(left, contextualType); + leftExpr = this.compileExpression(left, contextualType); leftType = this.currentType; // check operator overload @@ -3876,7 +3851,7 @@ export class Compiler extends DiagnosticEmitter { rightExpr = this.compileExpression(right, leftType, ContextualFlags.IMPLICIT); rightType = this.currentType; } else { - rightExpr = this.compileExpressionRetainType(right, leftType); + rightExpr = this.compileExpression(right, leftType); rightType = this.currentType; if (commonType = Type.commonDenominator(leftType, rightType, false)) { leftExpr = this.convertExpression(leftExpr, @@ -3942,7 +3917,7 @@ export class Compiler extends DiagnosticEmitter { } case Token.ASTERISK_EQUALS: compound = true; case Token.ASTERISK: { - leftExpr = this.compileExpressionRetainType(left, contextualType); + leftExpr = this.compileExpression(left, contextualType); leftType = this.currentType; // check operator overload @@ -3966,7 +3941,7 @@ export class Compiler extends DiagnosticEmitter { leftExpr = this.ensureSmallIntegerWrap(leftExpr, leftType); rightExpr = this.compileExpression(right, leftType, ContextualFlags.IMPLICIT); } else { - rightExpr = this.compileExpressionRetainType(right, leftType); + rightExpr = this.compileExpression(right, leftType); rightType = this.currentType; if (commonType = Type.commonDenominator(leftType, rightType, false)) { leftExpr = this.convertExpression(leftExpr, @@ -4032,7 +4007,7 @@ export class Compiler extends DiagnosticEmitter { } case Token.ASTERISK_ASTERISK_EQUALS: compound = true; case Token.ASTERISK_ASTERISK: { - leftExpr = this.compileExpressionRetainType(left, contextualType); + leftExpr = this.compileExpression(left, contextualType); leftType = this.currentType; // check operator overload @@ -4124,7 +4099,7 @@ export class Compiler extends DiagnosticEmitter { } case Token.SLASH_EQUALS: compound = true; case Token.SLASH: { - leftExpr = this.compileExpressionRetainType(left, contextualType); + leftExpr = this.compileExpression(left, contextualType); leftType = this.currentType; // check operator overload @@ -4149,7 +4124,7 @@ export class Compiler extends DiagnosticEmitter { rightExpr = this.compileExpression(right, leftType, ContextualFlags.IMPLICIT); rightType = this.currentType; } else { - rightExpr = this.compileExpressionRetainType(right, leftType); + rightExpr = this.compileExpression(right, leftType); rightType = this.currentType; if (commonType = Type.commonDenominator(leftType, rightType, false)) { leftExpr = this.convertExpression(leftExpr, @@ -4233,7 +4208,7 @@ export class Compiler extends DiagnosticEmitter { } case Token.PERCENT_EQUALS: compound = true; case Token.PERCENT: { - leftExpr = this.compileExpressionRetainType(left, contextualType); + leftExpr = this.compileExpression(left, contextualType); leftType = this.currentType; // check operator overload @@ -4258,7 +4233,7 @@ export class Compiler extends DiagnosticEmitter { rightExpr = this.compileExpression(right, leftType, ContextualFlags.IMPLICIT); rightType = this.currentType; } else { - rightExpr = this.compileExpressionRetainType(right, leftType); + rightExpr = this.compileExpression(right, leftType); rightType = this.currentType; if (commonType = Type.commonDenominator(leftType, rightType, false)) { leftExpr = this.convertExpression(leftExpr, @@ -4399,7 +4374,7 @@ export class Compiler extends DiagnosticEmitter { } case Token.LESSTHAN_LESSTHAN_EQUALS: compound = true; case Token.LESSTHAN_LESSTHAN: { - leftExpr = this.compileExpressionRetainType(left, contextualType.intType); + leftExpr = this.compileExpression(left, contextualType.intType); leftType = this.currentType; // check operator overload @@ -4465,7 +4440,7 @@ export class Compiler extends DiagnosticEmitter { } case Token.GREATERTHAN_GREATERTHAN_EQUALS: compound = true; case Token.GREATERTHAN_GREATERTHAN: { - leftExpr = this.compileExpressionRetainType(left, contextualType.intType); + leftExpr = this.compileExpression(left, contextualType.intType); leftType = this.currentType; // check operator overload @@ -4553,7 +4528,7 @@ export class Compiler extends DiagnosticEmitter { } case Token.GREATERTHAN_GREATERTHAN_GREATERTHAN_EQUALS: compound = true; case Token.GREATERTHAN_GREATERTHAN_GREATERTHAN: { - leftExpr = this.compileExpressionRetainType(left, contextualType.intType); + leftExpr = this.compileExpression(left, contextualType.intType); leftType = this.currentType; // check operator overload @@ -4622,7 +4597,7 @@ export class Compiler extends DiagnosticEmitter { } case Token.AMPERSAND_EQUALS: compound = true; case Token.AMPERSAND: { - leftExpr = this.compileExpressionRetainType(left, contextualType.intType); + leftExpr = this.compileExpression(left, contextualType.intType); leftType = this.currentType; // check operator overloadd @@ -4646,7 +4621,7 @@ export class Compiler extends DiagnosticEmitter { rightExpr = this.compileExpression(right, leftType, ContextualFlags.IMPLICIT); rightType = this.currentType; } else { - rightExpr = this.compileExpressionRetainType(right, leftType); + rightExpr = this.compileExpression(right, leftType); rightType = this.currentType; if (commonType = Type.commonDenominator(leftType, rightType, false)) { leftExpr = this.convertExpression(leftExpr, @@ -4712,7 +4687,7 @@ export class Compiler extends DiagnosticEmitter { } case Token.BAR_EQUALS: compound = true; case Token.BAR: { - leftExpr = this.compileExpressionRetainType(left, contextualType.intType); + leftExpr = this.compileExpression(left, contextualType.intType); leftType = this.currentType; // check operator overload @@ -4736,7 +4711,7 @@ export class Compiler extends DiagnosticEmitter { rightExpr = this.compileExpression(right, leftType, ContextualFlags.IMPLICIT); rightType = this.currentType; } else { - rightExpr = this.compileExpressionRetainType(right, leftType); + rightExpr = this.compileExpression(right, leftType); rightType = this.currentType; if (commonType = Type.commonDenominator(leftType, rightType, false)) { leftExpr = this.convertExpression(leftExpr, @@ -4805,7 +4780,7 @@ export class Compiler extends DiagnosticEmitter { } case Token.CARET_EQUALS: compound = true; case Token.CARET: { - leftExpr = this.compileExpressionRetainType(left, contextualType.intType); + leftExpr = this.compileExpression(left, contextualType.intType); leftType = this.currentType; // check operator overload @@ -4829,7 +4804,7 @@ export class Compiler extends DiagnosticEmitter { rightExpr = this.compileExpression(right, leftType, ContextualFlags.IMPLICIT); rightType = this.currentType; } else { - rightExpr = this.compileExpressionRetainType(right, leftType); + rightExpr = this.compileExpression(right, leftType); rightType = this.currentType; if (commonType = Type.commonDenominator(leftType, rightType, false)) { leftExpr = this.convertExpression(leftExpr, @@ -4901,13 +4876,14 @@ export class Compiler extends DiagnosticEmitter { case Token.AMPERSAND_AMPERSAND: { // left && right -> (t = left) ? right : t let flow = this.currentFlow; - leftExpr = this.compileExpressionRetainType(left, contextualType, contextualFlags); + let inheritedFlags = contextualFlags & (ContextualFlags.SKIP_AUTORELEASE | ContextualFlags.WRAP); + leftExpr = this.compileExpression(left, contextualType.exceptVoid, inheritedFlags); leftType = this.currentType; let rightFlow = flow.fork(); this.currentFlow = rightFlow; rightFlow.inheritNonnullIfTrue(leftExpr); - rightExpr = this.compileExpression(right, leftType, ContextualFlags.IMPLICIT | (contextualFlags & ~ContextualFlags.WILL_DROP)); + rightExpr = this.compileExpression(right, leftType, inheritedFlags | ContextualFlags.IMPLICIT); rightType = leftType; // simplify if only interested in true or false @@ -4998,13 +4974,14 @@ export class Compiler extends DiagnosticEmitter { } case Token.BAR_BAR: { // left || right -> ((t = left) ? t : right) let flow = this.currentFlow; - leftExpr = this.compileExpressionRetainType(left, contextualType, contextualFlags); + let inheritedFlags = contextualFlags & (ContextualFlags.SKIP_AUTORELEASE | ContextualFlags.WRAP); + leftExpr = this.compileExpression(left, contextualType.exceptVoid, inheritedFlags); leftType = this.currentType; let rightFlow = flow.fork(); this.currentFlow = rightFlow; rightFlow.inheritNonnullIfFalse(leftExpr); - rightExpr = this.compileExpression(right, leftType, ContextualFlags.IMPLICIT | contextualFlags); + rightExpr = this.compileExpression(right, leftType, inheritedFlags | ContextualFlags.IMPLICIT); rightType = leftType; // simplify if only interested in true or false @@ -5326,11 +5303,8 @@ export class Compiler extends DiagnosticEmitter { } return this.makeFieldAssignment(target, valueExpr, - this.compileExpressionRetainType( - assert(thisExpression), - // FIXME: explicit type (currently fails due to missing null checking) - this.options.usizeType - ), + // FIXME: explicit type (currently fails due to missing null checking) + this.compileExpression(assert(thisExpression), this.options.usizeType), tee ); } @@ -5371,20 +5345,14 @@ export class Compiler extends DiagnosticEmitter { } // call just the setter if the return value isn't of interest if (!tee) { - let thisExpr = this.compileExpressionRetainType( - assert(thisExpression), - this.options.usizeType - ); + let thisExpr = this.compileExpression(assert(thisExpression), this.options.usizeType); return this.makeCallDirect(setterInstance, [ thisExpr, valueExpr ], valueExpression); } // otherwise call the setter first, then the getter let getterInstance = assert((target).getterInstance); // must be present let returnType = getterInstance.signature.returnType; let nativeReturnType = returnType.toNativeType(); - let thisExpr = this.compileExpressionRetainType( - assert(thisExpression), - this.options.usizeType - ); + let thisExpr = this.compileExpression(assert(thisExpression), this.options.usizeType); let tempLocal = flow.getAndFreeTempLocal(returnType); let tempLocalIndex = tempLocal.index; return module.block(null, [ @@ -5419,10 +5387,7 @@ export class Compiler extends DiagnosticEmitter { return module.unreachable(); } let targetType = (target).type; - let thisExpr = this.compileExpressionRetainType( - assert(thisExpression), - this.options.usizeType - ); + let thisExpr = this.compileExpression(assert(thisExpression), this.options.usizeType); let elementExpr = this.compileExpression(indexExpression, Type.i32, ContextualFlags.IMPLICIT); if (tee) { let tempLocalTarget = flow.getTempLocal(targetType); @@ -5868,7 +5833,7 @@ export class Compiler extends DiagnosticEmitter { if (templateName !== null && inferredTypes.has(templateName)) { let inferredType = inferredTypes.get(templateName); if (inferredType) { - argumentExprs[i] = this.compileExpressionRetainType(argumentExpression, inferredType); + argumentExprs[i] = this.compileExpression(argumentExpression, inferredType); let commonType: Type | null; if (!(commonType = Type.commonDenominator(inferredType, this.currentType, true))) { if (!(commonType = Type.commonDenominator(inferredType, this.currentType, false))) { @@ -5881,7 +5846,7 @@ export class Compiler extends DiagnosticEmitter { } inferredType = commonType; } else { - argumentExprs[i] = this.compileExpressionRetainType(argumentExpression, Type.i32); + argumentExprs[i] = this.compileExpression(argumentExpression, Type.auto); inferredType = this.currentType; // ++numInferred; } @@ -5921,10 +5886,7 @@ export class Compiler extends DiagnosticEmitter { // compile 'this' expression if an instance method let thisExpr: ExpressionRef = 0; if (instance.is(CommonFlags.INSTANCE)) { - thisExpr = this.compileExpressionRetainType( - assert(this.resolver.currentThisExpression), - this.options.usizeType - ); + thisExpr = this.compileExpression(assert(this.resolver.currentThisExpression), this.options.usizeType); } return this.compileCallDirect( @@ -5969,10 +5931,7 @@ export class Compiler extends DiagnosticEmitter { let type = (target).type; if (signature = type.signatureReference) { let thisExpression = assert(this.resolver.currentThisExpression); - let thisExpr = this.compileExpressionRetainType( - thisExpression, - this.options.usizeType - ); + let thisExpr = this.compileExpression(thisExpression, this.options.usizeType); indexArg = module.load( 4, false, @@ -6013,10 +5972,7 @@ export class Compiler extends DiagnosticEmitter { case ElementKind.PROPERTY: { // instance property let getterInstance = assert((target).getterInstance); indexArg = this.compileCallDirect(getterInstance, [], expression.expression, - this.compileExpressionRetainType( - assert(this.resolver.currentThisExpression), - this.options.usizeType - ) + this.compileExpression(assert(this.resolver.currentThisExpression), this.options.usizeType) ); signature = this.currentType.signatureReference; if (!signature) { @@ -6579,6 +6535,7 @@ export class Compiler extends DiagnosticEmitter { /** Makes an automatic release call at the end of the current flow. */ makeAutorelease(expr: ExpressionRef, flow: Flow = this.currentFlow): ExpressionRef { + // FIXME: loses track of nonNull state? return this.module.local_tee(flow.getAutoreleaseLocal(this.options.usizeType).index, expr); } @@ -7325,7 +7282,7 @@ export class Compiler extends DiagnosticEmitter { // time of implementation, this seemed more useful because dynamic rhs expressions are not // possible in AS anyway. also note that the code generated below must preserve side-effects of // the LHS expression even when the result is a constant, i.e. return a block dropping `expr`. - var expr = this.compileExpressionRetainType(expression.expression, this.options.usizeType); + var expr = this.compileExpression(expression.expression, this.options.usizeType); var actualType = this.currentType; var expectedType = this.resolver.resolveType(expression.isType, this.currentFlow.actualFunction); this.currentType = Type.bool; @@ -7986,10 +7943,7 @@ export class Compiler extends DiagnosticEmitter { } case ElementKind.FIELD: { // instance field assert((target).memoryOffset >= 0); - let thisExpr = this.compileExpressionRetainType( - assert(this.resolver.currentThisExpression), - this.options.usizeType - ); + let thisExpr = this.compileExpression(assert(this.resolver.currentThisExpression), this.options.usizeType); this.currentType = (target).type; return module.load( (target).type.byteSize, @@ -8010,10 +7964,7 @@ export class Compiler extends DiagnosticEmitter { case ElementKind.PROPERTY: { // instance property let getterInstance = assert((target).getterInstance); return this.compileCallDirect(getterInstance, [], propertyAccess, - this.compileExpressionRetainType( - assert(this.resolver.currentThisExpression), - this.options.usizeType - ) + this.compileExpression(assert(this.resolver.currentThisExpression), this.options.usizeType) ); } case ElementKind.FUNCTION_PROTOTYPE: { @@ -8042,7 +7993,7 @@ export class Compiler extends DiagnosticEmitter { var condExpr = this.module.precomputeExpression( this.makeIsTrueish( - this.compileExpressionRetainType(expression.condition, Type.bool), + this.compileExpression(expression.condition, Type.bool), this.currentType ) ); @@ -8053,19 +8004,19 @@ export class Compiler extends DiagnosticEmitter { getExpressionType(condExpr) == NativeType.I32 ) { return getConstValueI32(condExpr) - ? this.compileExpressionRetainType(ifThen, contextualType) - : this.compileExpressionRetainType(ifElse, contextualType); + ? this.compileExpression(ifThen, contextualType) + : this.compileExpression(ifElse, contextualType); } var ifThenFlow = outerFlow.fork(); this.currentFlow = ifThenFlow; - var ifThenExpr = this.compileExpressionRetainType(ifThen, contextualType, contextualFlags & ContextualFlags.SKIP_AUTORELEASE); + var ifThenExpr = this.compileExpression(ifThen, contextualType, contextualFlags & ContextualFlags.SKIP_AUTORELEASE); var ifThenType = this.currentType; var IfThenAutoreleaseSkipped = this.skippedAutoreleases.has(ifThenExpr); var ifElseFlow = outerFlow.fork(); this.currentFlow = ifElseFlow; - var ifElseExpr = this.compileExpressionRetainType(ifElse, contextualType, contextualFlags & ContextualFlags.SKIP_AUTORELEASE); + var ifElseExpr = this.compileExpression(ifElse, contextualType, contextualFlags & ContextualFlags.SKIP_AUTORELEASE); var ifElseType = this.currentType; var ifElseAutoreleaseSkipped = this.skippedAutoreleases.has(ifElseExpr); @@ -8133,9 +8084,7 @@ export class Compiler extends DiagnosticEmitter { // make a getter for the expression (also obtains the type) var getValue = this.compileExpression( // reports expression.operand, - contextualType == Type.void - ? Type.i32 - : contextualType, + contextualType.exceptVoid, ContextualFlags.NONE ); @@ -8367,9 +8316,7 @@ export class Compiler extends DiagnosticEmitter { case Token.PLUS: { expr = this.compileExpression( expression.operand, - contextualType == Type.void - ? Type.i32 - : contextualType, + contextualType.exceptVoid, ContextualFlags.NONE ); @@ -8407,9 +8354,7 @@ export class Compiler extends DiagnosticEmitter { expr = this.compileExpression( expression.operand, - contextualType == Type.void - ? Type.i32 - : contextualType, + contextualType.exceptVoid, ContextualFlags.NONE ); @@ -8476,9 +8421,7 @@ export class Compiler extends DiagnosticEmitter { compound = true; expr = this.compileExpression( expression.operand, - contextualType == Type.void - ? Type.i32 - : contextualType, + contextualType.exceptVoid, ContextualFlags.NONE ); @@ -8545,9 +8488,7 @@ export class Compiler extends DiagnosticEmitter { compound = true; expr = this.compileExpression( expression.operand, - contextualType == Type.void - ? Type.i32 - : contextualType, + contextualType.exceptVoid, ContextualFlags.NONE ); @@ -8613,9 +8554,7 @@ export class Compiler extends DiagnosticEmitter { case Token.EXCLAMATION: { expr = this.compileExpression( expression.operand, - contextualType == Type.void - ? Type.i32 - : contextualType, + contextualType.exceptVoid, ContextualFlags.NONE ); diff --git a/src/diagnostics.ts b/src/diagnostics.ts index 9368bf94..2eff86a3 100644 --- a/src/diagnostics.ts +++ b/src/diagnostics.ts @@ -280,8 +280,8 @@ export abstract class DiagnosticEmitter { var message = DiagnosticMessage.create(code, category, arg0, arg1, arg2).withRange(range); if (relatedRange) message.relatedRange = relatedRange; this.diagnostics.push(message); - // console.log(formatDiagnosticMessage(message, true, true) + "\n"); // temporary - // console.log(new Error("stack").stack); + console.log(formatDiagnosticMessage(message, true, true) + "\n"); // temporary + console.log(new Error("stack").stack); } /** Emits an informatory diagnostic message. */ diff --git a/src/types.ts b/src/types.ts index 166584c3..37a4ff9b 100644 --- a/src/types.ts +++ b/src/types.ts @@ -145,6 +145,12 @@ export class Type { } } + /** Substitutes this type with the auto type if this type is void. */ + get exceptVoid(): Type { + if (this.kind == TypeKind.VOID) return Type.auto; + return this; + } + /** Gets this type's logarithmic alignment in memory. */ get alignLog2(): i32 { return 31 - clz(this.byteSize); @@ -526,6 +532,9 @@ export class Type { /** No return type. */ static readonly void: Type = new Type(TypeKind.VOID, TypeFlags.NONE, 0); + + /** Alias of i32 indicating type inference of locals and globals with just an initializer. */ + static readonly auto: Type = new Type(Type.i32.kind, Type.i32.flags, Type.i32.size); } /** Converts an array of types to an array of native types. */ diff --git a/tests/compiler/assert-nonnull.optimized.wat b/tests/compiler/assert-nonnull.optimized.wat index 34da49a3..e9f76b90 100644 --- a/tests/compiler/assert-nonnull.optimized.wat +++ b/tests/compiler/assert-nonnull.optimized.wat @@ -116,6 +116,12 @@ (func $assert-nonnull/testElem (; 8 ;) (type $FUNCSIG$ii) (param $0 i32) (result i32) local.get $0 call $~lib/array/Array#__get + local.tee $0 + i32.eqz + if + unreachable + end + local.get $0 ) (func $assert-nonnull/testAll (; 9 ;) (type $FUNCSIG$ii) (param $0 i32) (result i32) local.get $0 diff --git a/tests/compiler/assert-nonnull.untouched.wat b/tests/compiler/assert-nonnull.untouched.wat index 99aed7ec..ac6d6e1f 100644 --- a/tests/compiler/assert-nonnull.untouched.wat +++ b/tests/compiler/assert-nonnull.untouched.wat @@ -179,7 +179,6 @@ ) (func $assert-nonnull/testElem (; 11 ;) (type $FUNCSIG$ii) (param $0 i32) (result i32) (local $1 i32) - (local $2 i32) local.get $0 call $~lib/rt/stub/__retain drop @@ -187,13 +186,16 @@ i32.const 0 call $~lib/array/Array#__get local.tee $1 + if (result i32) + local.get $1 + else + unreachable + end call $~lib/rt/stub/__retain - local.set $2 - local.get $1 - call $~lib/rt/stub/__release + local.set $1 local.get $0 call $~lib/rt/stub/__release - local.get $2 + local.get $1 ) (func $assert-nonnull/testAll (; 12 ;) (type $FUNCSIG$ii) (param $0 i32) (result i32) (local $1 i32) diff --git a/tests/compiler/retain-i32.optimized.wat b/tests/compiler/retain-i32.optimized.wat index 6cfabbee..431e76c8 100644 --- a/tests/compiler/retain-i32.optimized.wat +++ b/tests/compiler/retain-i32.optimized.wat @@ -6,6 +6,7 @@ (data (i32.const 8) "\1a\00\00\00\01\00\00\00\01\00\00\00\1a\00\00\00r\00e\00t\00a\00i\00n\00-\00i\003\002\00.\00t\00s") (global $retain-i32/si (mut i32) (i32.const 0)) (global $retain-i32/ui (mut i32) (i32.const 0)) + (global $retain-i32/ri (mut i32) (i32.const 0)) (export "memory" (memory $0)) (start $start) (func $start:retain-i32 (; 1 ;) (type $FUNCSIG$v) @@ -254,6 +255,12 @@ call $~lib/builtins/abort unreachable end + i32.const 0 + i32.load8_s + global.set $retain-i32/ri + i32.const 0 + i32.load8_s + drop ) (func $start (; 2 ;) (type $FUNCSIG$v) call $start:retain-i32 diff --git a/tests/compiler/retain-i32.ts b/tests/compiler/retain-i32.ts index 769b684f..5484c06c 100644 --- a/tests/compiler/retain-i32.ts +++ b/tests/compiler/retain-i32.ts @@ -129,3 +129,14 @@ assert(ui == 1); ui = 255 % 255; assert(ui == 0); + +// inferring global type from load should still retain T +var ri = load(0); +assert(ri instanceof i8); + +// inferring local type from load should still retain T +function testLocalRetain(): void { + var ri = load(0); + assert(ri instanceof i8); +} +testLocalRetain(); diff --git a/tests/compiler/retain-i32.untouched.wat b/tests/compiler/retain-i32.untouched.wat index fdad18d4..fa6fcdc4 100644 --- a/tests/compiler/retain-i32.untouched.wat +++ b/tests/compiler/retain-i32.untouched.wat @@ -18,6 +18,7 @@ (global $~lib/builtins/u32.MAX_VALUE i32 (i32.const -1)) (global $retain-i32/si (mut i32) (i32.const 0)) (global $retain-i32/ui (mut i32) (i32.const 0)) + (global $retain-i32/ri (mut i32) (i32.const 0)) (export "memory" (memory $0)) (start $start) (func $retain-i32/test (; 1 ;) (type $FUNCSIG$vii) (param $0 i32) (param $1 i32) @@ -330,7 +331,25 @@ unreachable end ) - (func $start:retain-i32 (; 2 ;) (type $FUNCSIG$v) + (func $retain-i32/testLocalRetain (; 2 ;) (type $FUNCSIG$v) + (local $0 i32) + i32.const 0 + i32.load8_s + local.set $0 + local.get $0 + drop + i32.const 1 + i32.eqz + if + i32.const 0 + i32.const 24 + i32.const 140 + i32.const 2 + call $~lib/builtins/abort + unreachable + end + ) + (func $start:retain-i32 (; 3 ;) (type $FUNCSIG$v) (local $0 i32) i32.const 0 global.get $~lib/builtins/i8.MAX_VALUE @@ -786,10 +805,26 @@ call $~lib/builtins/abort unreachable end + i32.const 0 + i32.load8_s + global.set $retain-i32/ri + global.get $retain-i32/ri + drop + i32.const 1 + i32.eqz + if + i32.const 0 + i32.const 24 + i32.const 135 + i32.const 0 + call $~lib/builtins/abort + unreachable + end + call $retain-i32/testLocalRetain ) - (func $start (; 3 ;) (type $FUNCSIG$v) + (func $start (; 4 ;) (type $FUNCSIG$v) call $start:retain-i32 ) - (func $null (; 4 ;) (type $FUNCSIG$v) + (func $null (; 5 ;) (type $FUNCSIG$v) ) ) diff --git a/tests/compiler/std/symbol.optimized.wat b/tests/compiler/std/symbol.optimized.wat index 4f375618..837accea 100644 --- a/tests/compiler/std/symbol.optimized.wat +++ b/tests/compiler/std/symbol.optimized.wat @@ -1475,6 +1475,7 @@ call $~lib/string/String.__concat ) (func $start:std/symbol (; 27 ;) (type $FUNCSIG$v) + (local $0 i32) i32.const 24 call $~lib/symbol/Symbol global.set $std/symbol/sym1 @@ -1537,9 +1538,21 @@ end global.get $std/symbol/sym3 call $~lib/symbol/_Symbol.keyFor + local.tee $0 + i32.eqz + if + unreachable + end + local.get $0 global.set $std/symbol/key3 global.get $std/symbol/sym4 call $~lib/symbol/_Symbol.keyFor + local.tee $0 + i32.eqz + if + unreachable + end + local.get $0 global.set $std/symbol/key4 global.get $std/symbol/key3 i32.const 24 diff --git a/tests/compiler/std/symbol.untouched.wat b/tests/compiler/std/symbol.untouched.wat index d5956daa..42fda050 100644 --- a/tests/compiler/std/symbol.untouched.wat +++ b/tests/compiler/std/symbol.untouched.wat @@ -3342,8 +3342,6 @@ (local $1 i32) (local $2 i32) (local $3 i32) - (local $4 i32) - (local $5 i32) i32.const 24 call $~lib/symbol/Symbol global.set $std/symbol/sym1 @@ -3423,11 +3421,21 @@ global.get $std/symbol/sym3 call $~lib/symbol/_Symbol.keyFor local.tee $0 + if (result i32) + local.get $0 + else + unreachable + end call $~lib/rt/stub/__retain global.set $std/symbol/key3 global.get $std/symbol/sym4 call $~lib/symbol/_Symbol.keyFor - local.tee $1 + local.tee $0 + if (result i32) + local.get $0 + else + unreachable + end call $~lib/rt/stub/__retain global.set $std/symbol/key4 global.get $std/symbol/key3 @@ -3457,7 +3465,7 @@ i32.const 0 call $~lib/symbol/Symbol call $~lib/symbol/_Symbol#toString - local.tee $2 + local.tee $0 i32.const 704 call $~lib/string/String.__eq i32.eqz @@ -3471,7 +3479,7 @@ end global.get $std/symbol/sym3 call $~lib/symbol/_Symbol#toString - local.tee $3 + local.tee $1 i32.const 736 call $~lib/string/String.__eq i32.eqz @@ -3489,7 +3497,7 @@ global.set $std/symbol/isConcatSpreadable global.get $std/symbol/hasInstance call $~lib/symbol/_Symbol#toString - local.tee $4 + local.tee $2 i32.const 776 call $~lib/string/String.__eq i32.eqz @@ -3503,7 +3511,7 @@ end global.get $std/symbol/isConcatSpreadable call $~lib/symbol/_Symbol#toString - local.tee $5 + local.tee $3 i32.const 832 call $~lib/string/String.__eq i32.eqz @@ -3527,10 +3535,6 @@ call $~lib/rt/stub/__release local.get $3 call $~lib/rt/stub/__release - local.get $4 - call $~lib/rt/stub/__release - local.get $5 - call $~lib/rt/stub/__release ) (func $start (; 34 ;) (type $FUNCSIG$v) call $start:std/symbol