|
|
|
@ -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(<BlockStatement>statement, contextualFlags);
|
|
|
|
|
stmt = this.compileBlockStatement(<BlockStatement>statement);
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
case NodeKind.BREAK: {
|
|
|
|
|
stmt = this.compileBreakStatement(<BreakStatement>statement, contextualFlags);
|
|
|
|
|
stmt = this.compileBreakStatement(<BreakStatement>statement);
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
case NodeKind.CONTINUE: {
|
|
|
|
|
stmt = this.compileContinueStatement(<ContinueStatement>statement, contextualFlags);
|
|
|
|
|
stmt = this.compileContinueStatement(<ContinueStatement>statement);
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
case NodeKind.DO: {
|
|
|
|
|
stmt = this.compileDoStatement(<DoStatement>statement, contextualFlags);
|
|
|
|
|
stmt = this.compileDoStatement(<DoStatement>statement);
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
case NodeKind.EMPTY: {
|
|
|
|
|
stmt = this.compileEmptyStatement(<EmptyStatement>statement, contextualFlags);
|
|
|
|
|
stmt = this.compileEmptyStatement(<EmptyStatement>statement);
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
case NodeKind.EXPRESSION: {
|
|
|
|
|
stmt = this.compileExpressionStatement(<ExpressionStatement>statement, contextualFlags);
|
|
|
|
|
stmt = this.compileExpressionStatement(<ExpressionStatement>statement);
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
case NodeKind.FOR: {
|
|
|
|
|
stmt = this.compileForStatement(<ForStatement>statement, contextualFlags);
|
|
|
|
|
stmt = this.compileForStatement(<ForStatement>statement);
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
case NodeKind.IF: {
|
|
|
|
|
stmt = this.compileIfStatement(<IfStatement>statement, contextualFlags);
|
|
|
|
|
stmt = this.compileIfStatement(<IfStatement>statement);
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
case NodeKind.RETURN: {
|
|
|
|
|
stmt = this.compileReturnStatement(<ReturnStatement>statement, contextualFlags);
|
|
|
|
|
stmt = this.compileReturnStatement(<ReturnStatement>statement, isLastInBody);
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
case NodeKind.SWITCH: {
|
|
|
|
|
stmt = this.compileSwitchStatement(<SwitchStatement>statement, contextualFlags);
|
|
|
|
|
stmt = this.compileSwitchStatement(<SwitchStatement>statement);
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
case NodeKind.THROW: {
|
|
|
|
|
stmt = this.compileThrowStatement(<ThrowStatement>statement, contextualFlags);
|
|
|
|
|
stmt = this.compileThrowStatement(<ThrowStatement>statement);
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
case NodeKind.TRY: {
|
|
|
|
|
stmt = this.compileTryStatement(<TryStatement>statement, contextualFlags);
|
|
|
|
|
stmt = this.compileTryStatement(<TryStatement>statement);
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
case NodeKind.VARIABLE: {
|
|
|
|
|
stmt = this.compileVariableStatement(<VariableStatement>statement, contextualFlags);
|
|
|
|
|
stmt = this.compileVariableStatement(<VariableStatement>statement);
|
|
|
|
|
if (!stmt) stmt = module.nop();
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
case NodeKind.VOID: {
|
|
|
|
|
stmt = this.compileVoidStatement(<VoidStatement>statement, contextualFlags);
|
|
|
|
|
stmt = this.compileVoidStatement(<VoidStatement>statement);
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
case NodeKind.WHILE: {
|
|
|
|
|
stmt = this.compileWhileStatement(<WhileStatement>statement, contextualFlags);
|
|
|
|
|
stmt = this.compileWhileStatement(<WhileStatement>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(<Expression>statement.condition, Type.bool),
|
|
|
|
|
this.compileExpression(<Expression>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(<Field>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((<Property>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 = (<Class>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 = (<Field>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((<Property>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((<Field>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 = (<Field>target).type;
|
|
|
|
|
return module.load(
|
|
|
|
|
(<Field>target).type.byteSize,
|
|
|
|
@ -8010,10 +7964,7 @@ export class Compiler extends DiagnosticEmitter {
|
|
|
|
|
case ElementKind.PROPERTY: { // instance property
|
|
|
|
|
let getterInstance = assert((<Property>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
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|