mirror of
https://github.com/fluencelabs/assemblyscript
synced 2025-06-21 18:51:43 +00:00
Binary expression operator overloads for +/==; Check allocation flow in ternary expressions; Cache empty array buffers; Sealed decorator for non-derivable internals
This commit is contained in:
@ -2672,7 +2672,18 @@ export class Compiler extends DiagnosticEmitter {
|
||||
expr = module.createBinary(BinaryOp.EqI32, leftExpr, rightExpr);
|
||||
break;
|
||||
}
|
||||
case TypeKind.USIZE: // TODO: check operator overload
|
||||
case TypeKind.USIZE: { // check operator overload
|
||||
if (this.currentType.is(TypeFlags.REFERENCE)) {
|
||||
let classInstance = assert(this.currentType.classReference);
|
||||
let operatorName = classInstance.prototype.fnEquals;
|
||||
if (operatorName != null) {
|
||||
expr = this.compileOperatorOverload(classInstance, operatorName, leftExpr, rightExpr);
|
||||
assert(this.currentType == Type.bool);
|
||||
break;
|
||||
}
|
||||
}
|
||||
// fall-through
|
||||
}
|
||||
case TypeKind.ISIZE: {
|
||||
expr = module.createBinary(
|
||||
this.options.isWasm64
|
||||
@ -2822,7 +2833,17 @@ export class Compiler extends DiagnosticEmitter {
|
||||
expr = module.createBinary(BinaryOp.AddI32, leftExpr, rightExpr);
|
||||
break;
|
||||
}
|
||||
case TypeKind.USIZE: // TODO: check operator overload
|
||||
case TypeKind.USIZE: { // check operator overload
|
||||
if (this.currentType.is(TypeFlags.REFERENCE)) {
|
||||
let classInstance = assert(this.currentType.classReference);
|
||||
let operatorName = classInstance.prototype.fnConcat;
|
||||
if (operatorName != null) {
|
||||
expr = this.compileOperatorOverload(classInstance, operatorName, leftExpr, rightExpr);
|
||||
break;
|
||||
}
|
||||
}
|
||||
// fall-through
|
||||
}
|
||||
case TypeKind.ISIZE: {
|
||||
expr = module.createBinary(
|
||||
this.options.isWasm64
|
||||
@ -3726,6 +3747,20 @@ export class Compiler extends DiagnosticEmitter {
|
||||
: expr;
|
||||
}
|
||||
|
||||
compileOperatorOverload(
|
||||
classInstance: Class,
|
||||
operatorName: string,
|
||||
leftExpr: ExpressionRef,
|
||||
rightExpr: ExpressionRef
|
||||
): ExpressionRef {
|
||||
var classPrototype = classInstance.prototype;
|
||||
var operatorPrototype = assert(assert(classPrototype.members).get(operatorName));
|
||||
assert(operatorPrototype.kind == ElementKind.FUNCTION_PROTOTYPE);
|
||||
var operatorInstance = (<FunctionPrototype>operatorPrototype).resolve();
|
||||
if (!operatorInstance) return this.module.createUnreachable();
|
||||
return this.makeCallDirect(operatorInstance, [ leftExpr, rightExpr ]);
|
||||
}
|
||||
|
||||
compileAssignment(expression: Expression, valueExpression: Expression, contextualType: Type): ExpressionRef {
|
||||
var currentFunction = this.currentFunction;
|
||||
var resolved = this.program.resolveExpression(expression, currentFunction); // reports
|
||||
@ -4526,7 +4561,6 @@ export class Compiler extends DiagnosticEmitter {
|
||||
assert(parent.kind == ElementKind.CLASS);
|
||||
let thisType = (<Class>parent).type;
|
||||
if (currentFunction.is(CommonFlags.CONSTRUCTOR)) {
|
||||
let nativeSizeType = this.options.nativeSizeType;
|
||||
let flow = currentFunction.flow;
|
||||
if (!flow.is(FlowFlags.ALLOCATES)) {
|
||||
flow.set(FlowFlags.ALLOCATES);
|
||||
@ -5152,8 +5186,36 @@ export class Compiler extends DiagnosticEmitter {
|
||||
: this.compileExpression(ifElse, contextualType);
|
||||
}
|
||||
|
||||
var ifThenExpr = this.compileExpression(ifThen, contextualType);
|
||||
var ifElseExpr = this.compileExpression(ifElse, contextualType);
|
||||
var currentFunction = this.currentFunction;
|
||||
var ifThenExpr: ExpressionRef;
|
||||
var ifElseExpr: ExpressionRef;
|
||||
|
||||
// if part of a constructor, keep track of memory allocations
|
||||
if (currentFunction.is(CommonFlags.CONSTRUCTOR)) {
|
||||
let flow = currentFunction.flow;
|
||||
|
||||
flow = flow.enterBranchOrScope();
|
||||
currentFunction.flow = flow;
|
||||
ifThenExpr = this.compileExpression(ifThen, contextualType);
|
||||
let ifThenAllocates = flow.is(FlowFlags.ALLOCATES);
|
||||
flow = flow.leaveBranchOrScope();
|
||||
currentFunction.flow = flow;
|
||||
|
||||
flow = flow.enterBranchOrScope();
|
||||
currentFunction.flow = flow;
|
||||
ifElseExpr = this.compileExpression(ifElse, contextualType);
|
||||
let ifElseAllocates = flow.is(FlowFlags.ALLOCATES);
|
||||
flow = flow.leaveBranchOrScope();
|
||||
currentFunction.flow = flow;
|
||||
|
||||
if (ifThenAllocates && ifElseAllocates) flow.set(FlowFlags.ALLOCATES);
|
||||
|
||||
// otherwise simplify
|
||||
} else {
|
||||
ifThenExpr = this.compileExpression(ifThen, contextualType);
|
||||
ifElseExpr = this.compileExpression(ifElse, contextualType);
|
||||
}
|
||||
|
||||
return this.module.createIf(condExpr, ifThenExpr, ifElseExpr);
|
||||
}
|
||||
|
||||
|
@ -20,6 +20,7 @@ export enum DiagnosticCode {
|
||||
Structs_cannot_implement_interfaces = 208,
|
||||
Invalid_regular_expression_flags = 209,
|
||||
Implementation_0_must_match_the_signature_1 = 210,
|
||||
Class_0_is_sealed_and_cannot_be_extended = 211,
|
||||
Unterminated_string_literal = 1002,
|
||||
Identifier_expected = 1003,
|
||||
_0_expected = 1005,
|
||||
@ -122,6 +123,7 @@ export function diagnosticCodeToString(code: DiagnosticCode): string {
|
||||
case 208: return "Structs cannot implement interfaces.";
|
||||
case 209: return "Invalid regular expression flags.";
|
||||
case 210: return "Implementation '{0}' must match the signature '{1}'.";
|
||||
case 211: return "Class '{0}' is sealed and cannot be extended.";
|
||||
case 1002: return "Unterminated string literal.";
|
||||
case 1003: return "Identifier expected.";
|
||||
case 1005: return "'{0}' expected.";
|
||||
|
@ -12,6 +12,7 @@
|
||||
"Structs cannot implement interfaces.": 208,
|
||||
"Invalid regular expression flags.": 209,
|
||||
"Implementation '{0}' must match the signature '{1}'.": 210,
|
||||
"Class '{0}' is sealed and cannot be extended.": 211,
|
||||
|
||||
"Unterminated string literal.": 1002,
|
||||
"Identifier expected.": 1003,
|
||||
|
@ -171,6 +171,10 @@ export class Parser extends DiagnosticEmitter {
|
||||
flags |= CommonFlags.UNMANAGED;
|
||||
continue;
|
||||
}
|
||||
if (text == "sealed") {
|
||||
flags |= CommonFlags.SEALED;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
if (!decorators) decorators = [];
|
||||
decorators.push(decorator);
|
||||
|
@ -2041,34 +2041,36 @@ export enum CommonFlags {
|
||||
BUILTIN = 1 << 14,
|
||||
/** Is unmanaged. */
|
||||
UNMANAGED = 1 << 15,
|
||||
/** Is sealed. */
|
||||
SEALED = 1 << 16,
|
||||
|
||||
// Extended modifiers usually derived from basic modifiers or internal decorators
|
||||
|
||||
/** Is ambient, that is either declared or nested in a declared element. */
|
||||
AMBIENT = 1 << 16,
|
||||
AMBIENT = 1 << 17,
|
||||
/** Is generic. */
|
||||
GENERIC = 1 << 17,
|
||||
GENERIC = 1 << 18,
|
||||
/** Is part of a generic context. */
|
||||
GENERIC_CONTEXT = 1 << 18,
|
||||
GENERIC_CONTEXT = 1 << 19,
|
||||
/** Is an instance member. */
|
||||
INSTANCE = 1 << 19,
|
||||
INSTANCE = 1 << 20,
|
||||
/** Is a constructor. */
|
||||
CONSTRUCTOR = 1 << 20,
|
||||
CONSTRUCTOR = 1 << 21,
|
||||
/** Is an arrow function. */
|
||||
ARROW = 1 << 21,
|
||||
ARROW = 1 << 22,
|
||||
/** Is a module export. */
|
||||
MODULE_EXPORT = 1 << 22,
|
||||
MODULE_EXPORT = 1 << 23,
|
||||
/** Is a module import. */
|
||||
MODULE_IMPORT = 1 << 23,
|
||||
MODULE_IMPORT = 1 << 24,
|
||||
|
||||
// Compilation states
|
||||
|
||||
/** Is compiled. */
|
||||
COMPILED = 1 << 24,
|
||||
COMPILED = 1 << 25,
|
||||
/** Has a constant value and is therefore inlined. */
|
||||
INLINED = 1 << 25,
|
||||
INLINED = 1 << 26,
|
||||
/** Is scoped. */
|
||||
SCOPED = 1 << 26
|
||||
SCOPED = 1 << 27
|
||||
}
|
||||
|
||||
/** Base class of all program elements. */
|
||||
@ -2873,6 +2875,13 @@ export class ClassPrototype extends Element {
|
||||
);
|
||||
return null;
|
||||
}
|
||||
if (baseClass.is(CommonFlags.SEALED)) {
|
||||
this.program.error(
|
||||
DiagnosticCode.Class_0_is_sealed_and_cannot_be_extended,
|
||||
declaration.extendsType.range, baseClass.internalName
|
||||
);
|
||||
return null;
|
||||
}
|
||||
if (baseClass.prototype.is(CommonFlags.UNMANAGED) != this.is(CommonFlags.UNMANAGED)) {
|
||||
this.program.error(
|
||||
DiagnosticCode.Structs_cannot_extend_classes_and_vice_versa,
|
||||
|
Reference in New Issue
Block a user