Skip to content

Commit 4adb69f

Browse files
committed
Binary expression operator overloads for +/==; Check allocation flow in ternary expressions; Cache empty array buffers; Sealed decorator for non-derivable internals
1 parent 9cc0fcd commit 4adb69f

18 files changed

+5232
-425
lines changed

dist/asc.js

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

dist/asc.js.map

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

dist/assemblyscript.js

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

dist/assemblyscript.js.map

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/compiler.ts

Lines changed: 67 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2672,7 +2672,18 @@ export class Compiler extends DiagnosticEmitter {
26722672
expr = module.createBinary(BinaryOp.EqI32, leftExpr, rightExpr);
26732673
break;
26742674
}
2675-
case TypeKind.USIZE: // TODO: check operator overload
2675+
case TypeKind.USIZE: { // check operator overload
2676+
if (this.currentType.is(TypeFlags.REFERENCE)) {
2677+
let classInstance = assert(this.currentType.classReference);
2678+
let operatorName = classInstance.prototype.fnEquals;
2679+
if (operatorName != null) {
2680+
expr = this.compileOperatorOverload(classInstance, operatorName, leftExpr, rightExpr);
2681+
assert(this.currentType == Type.bool);
2682+
break;
2683+
}
2684+
}
2685+
// fall-through
2686+
}
26762687
case TypeKind.ISIZE: {
26772688
expr = module.createBinary(
26782689
this.options.isWasm64
@@ -2822,7 +2833,17 @@ export class Compiler extends DiagnosticEmitter {
28222833
expr = module.createBinary(BinaryOp.AddI32, leftExpr, rightExpr);
28232834
break;
28242835
}
2825-
case TypeKind.USIZE: // TODO: check operator overload
2836+
case TypeKind.USIZE: { // check operator overload
2837+
if (this.currentType.is(TypeFlags.REFERENCE)) {
2838+
let classInstance = assert(this.currentType.classReference);
2839+
let operatorName = classInstance.prototype.fnConcat;
2840+
if (operatorName != null) {
2841+
expr = this.compileOperatorOverload(classInstance, operatorName, leftExpr, rightExpr);
2842+
break;
2843+
}
2844+
}
2845+
// fall-through
2846+
}
28262847
case TypeKind.ISIZE: {
28272848
expr = module.createBinary(
28282849
this.options.isWasm64
@@ -3726,6 +3747,20 @@ export class Compiler extends DiagnosticEmitter {
37263747
: expr;
37273748
}
37283749

3750+
compileOperatorOverload(
3751+
classInstance: Class,
3752+
operatorName: string,
3753+
leftExpr: ExpressionRef,
3754+
rightExpr: ExpressionRef
3755+
): ExpressionRef {
3756+
var classPrototype = classInstance.prototype;
3757+
var operatorPrototype = assert(assert(classPrototype.members).get(operatorName));
3758+
assert(operatorPrototype.kind == ElementKind.FUNCTION_PROTOTYPE);
3759+
var operatorInstance = (<FunctionPrototype>operatorPrototype).resolve();
3760+
if (!operatorInstance) return this.module.createUnreachable();
3761+
return this.makeCallDirect(operatorInstance, [ leftExpr, rightExpr ]);
3762+
}
3763+
37293764
compileAssignment(expression: Expression, valueExpression: Expression, contextualType: Type): ExpressionRef {
37303765
var currentFunction = this.currentFunction;
37313766
var resolved = this.program.resolveExpression(expression, currentFunction); // reports
@@ -4526,7 +4561,6 @@ export class Compiler extends DiagnosticEmitter {
45264561
assert(parent.kind == ElementKind.CLASS);
45274562
let thisType = (<Class>parent).type;
45284563
if (currentFunction.is(CommonFlags.CONSTRUCTOR)) {
4529-
let nativeSizeType = this.options.nativeSizeType;
45304564
let flow = currentFunction.flow;
45314565
if (!flow.is(FlowFlags.ALLOCATES)) {
45324566
flow.set(FlowFlags.ALLOCATES);
@@ -5152,8 +5186,36 @@ export class Compiler extends DiagnosticEmitter {
51525186
: this.compileExpression(ifElse, contextualType);
51535187
}
51545188

5155-
var ifThenExpr = this.compileExpression(ifThen, contextualType);
5156-
var ifElseExpr = this.compileExpression(ifElse, contextualType);
5189+
var currentFunction = this.currentFunction;
5190+
var ifThenExpr: ExpressionRef;
5191+
var ifElseExpr: ExpressionRef;
5192+
5193+
// if part of a constructor, keep track of memory allocations
5194+
if (currentFunction.is(CommonFlags.CONSTRUCTOR)) {
5195+
let flow = currentFunction.flow;
5196+
5197+
flow = flow.enterBranchOrScope();
5198+
currentFunction.flow = flow;
5199+
ifThenExpr = this.compileExpression(ifThen, contextualType);
5200+
let ifThenAllocates = flow.is(FlowFlags.ALLOCATES);
5201+
flow = flow.leaveBranchOrScope();
5202+
currentFunction.flow = flow;
5203+
5204+
flow = flow.enterBranchOrScope();
5205+
currentFunction.flow = flow;
5206+
ifElseExpr = this.compileExpression(ifElse, contextualType);
5207+
let ifElseAllocates = flow.is(FlowFlags.ALLOCATES);
5208+
flow = flow.leaveBranchOrScope();
5209+
currentFunction.flow = flow;
5210+
5211+
if (ifThenAllocates && ifElseAllocates) flow.set(FlowFlags.ALLOCATES);
5212+
5213+
// otherwise simplify
5214+
} else {
5215+
ifThenExpr = this.compileExpression(ifThen, contextualType);
5216+
ifElseExpr = this.compileExpression(ifElse, contextualType);
5217+
}
5218+
51575219
return this.module.createIf(condExpr, ifThenExpr, ifElseExpr);
51585220
}
51595221

src/diagnosticMessages.generated.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ export enum DiagnosticCode {
2020
Structs_cannot_implement_interfaces = 208,
2121
Invalid_regular_expression_flags = 209,
2222
Implementation_0_must_match_the_signature_1 = 210,
23+
Class_0_is_sealed_and_cannot_be_extended = 211,
2324
Unterminated_string_literal = 1002,
2425
Identifier_expected = 1003,
2526
_0_expected = 1005,
@@ -122,6 +123,7 @@ export function diagnosticCodeToString(code: DiagnosticCode): string {
122123
case 208: return "Structs cannot implement interfaces.";
123124
case 209: return "Invalid regular expression flags.";
124125
case 210: return "Implementation '{0}' must match the signature '{1}'.";
126+
case 211: return "Class '{0}' is sealed and cannot be extended.";
125127
case 1002: return "Unterminated string literal.";
126128
case 1003: return "Identifier expected.";
127129
case 1005: return "'{0}' expected.";

src/diagnosticMessages.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
"Structs cannot implement interfaces.": 208,
1313
"Invalid regular expression flags.": 209,
1414
"Implementation '{0}' must match the signature '{1}'.": 210,
15+
"Class '{0}' is sealed and cannot be extended.": 211,
1516

1617
"Unterminated string literal.": 1002,
1718
"Identifier expected.": 1003,

src/parser.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -171,6 +171,10 @@ export class Parser extends DiagnosticEmitter {
171171
flags |= CommonFlags.UNMANAGED;
172172
continue;
173173
}
174+
if (text == "sealed") {
175+
flags |= CommonFlags.SEALED;
176+
continue;
177+
}
174178
}
175179
if (!decorators) decorators = [];
176180
decorators.push(decorator);

src/program.ts

Lines changed: 20 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -2041,34 +2041,36 @@ export enum CommonFlags {
20412041
BUILTIN = 1 << 14,
20422042
/** Is unmanaged. */
20432043
UNMANAGED = 1 << 15,
2044+
/** Is sealed. */
2045+
SEALED = 1 << 16,
20442046

20452047
// Extended modifiers usually derived from basic modifiers or internal decorators
20462048

20472049
/** Is ambient, that is either declared or nested in a declared element. */
2048-
AMBIENT = 1 << 16,
2050+
AMBIENT = 1 << 17,
20492051
/** Is generic. */
2050-
GENERIC = 1 << 17,
2052+
GENERIC = 1 << 18,
20512053
/** Is part of a generic context. */
2052-
GENERIC_CONTEXT = 1 << 18,
2054+
GENERIC_CONTEXT = 1 << 19,
20532055
/** Is an instance member. */
2054-
INSTANCE = 1 << 19,
2056+
INSTANCE = 1 << 20,
20552057
/** Is a constructor. */
2056-
CONSTRUCTOR = 1 << 20,
2058+
CONSTRUCTOR = 1 << 21,
20572059
/** Is an arrow function. */
2058-
ARROW = 1 << 21,
2060+
ARROW = 1 << 22,
20592061
/** Is a module export. */
2060-
MODULE_EXPORT = 1 << 22,
2062+
MODULE_EXPORT = 1 << 23,
20612063
/** Is a module import. */
2062-
MODULE_IMPORT = 1 << 23,
2064+
MODULE_IMPORT = 1 << 24,
20632065

20642066
// Compilation states
20652067

20662068
/** Is compiled. */
2067-
COMPILED = 1 << 24,
2069+
COMPILED = 1 << 25,
20682070
/** Has a constant value and is therefore inlined. */
2069-
INLINED = 1 << 25,
2071+
INLINED = 1 << 26,
20702072
/** Is scoped. */
2071-
SCOPED = 1 << 26
2073+
SCOPED = 1 << 27
20722074
}
20732075

20742076
/** Base class of all program elements. */
@@ -2873,6 +2875,13 @@ export class ClassPrototype extends Element {
28732875
);
28742876
return null;
28752877
}
2878+
if (baseClass.is(CommonFlags.SEALED)) {
2879+
this.program.error(
2880+
DiagnosticCode.Class_0_is_sealed_and_cannot_be_extended,
2881+
declaration.extendsType.range, baseClass.internalName
2882+
);
2883+
return null;
2884+
}
28762885
if (baseClass.prototype.is(CommonFlags.UNMANAGED) != this.is(CommonFlags.UNMANAGED)) {
28772886
this.program.error(
28782887
DiagnosticCode.Structs_cannot_extend_classes_and_vice_versa,

std/assembly.d.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -354,5 +354,8 @@ declare function operator(token: string): (target: any, propertyKey: string, des
354354
/** Annotates a class as being unmanaged with limited capabilities. */
355355
declare function unmanaged(target: Function): any;
356356

357+
/** Annotates a class as being sealed / non-derivable. */
358+
declare function sealed(target: Function): any;
359+
357360
/** Annotates a class field with an explicit offset. */
358361
declare function offset(offset: usize): any;

0 commit comments

Comments
 (0)