Skip to content

Commit f714afa

Browse files
authored
Implement explicit this type (AssemblyScript#373)
* Add backing classes for basic types (I32...) * Move standard numeric constants to backing classes
1 parent d5f72e3 commit f714afa

File tree

14 files changed

+8043
-1611
lines changed

14 files changed

+8043
-1611
lines changed

src/builtins.ts

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -153,7 +153,12 @@ export function compileCall(
153153
);
154154
return module.createUnreachable();
155155
}
156-
let element = compiler.resolver.resolveExpression(operands[0], compiler.currentFunction, ReportMode.SWALLOW);
156+
let element = compiler.resolver.resolveExpression(
157+
operands[0],
158+
compiler.currentFunction,
159+
Type.void,
160+
ReportMode.SWALLOW
161+
);
157162
return module.createI32(element ? 1 : 0);
158163
}
159164
case "isConstant": { // isConstant(expression) -> bool

src/compiler.ts

Lines changed: 26 additions & 105 deletions
Original file line numberDiff line numberDiff line change
@@ -5421,33 +5421,22 @@ export class Compiler extends DiagnosticEmitter {
54215421
if (thisArg) {
54225422
let parent = assert(instance.parent);
54235423
assert(parent.kind == ElementKind.CLASS);
5424-
if (getExpressionId(thisArg) == ExpressionId.GetLocal) {
5425-
flow.addScopedLocalAlias(
5426-
getGetLocalIndex(thisArg),
5427-
(<Class>parent).type,
5428-
"this"
5429-
);
5430-
let parentBase = (<Class>parent).base;
5431-
if (parentBase) {
5432-
flow.addScopedLocalAlias(
5433-
getGetLocalIndex(thisArg),
5434-
parentBase.type,
5435-
"super"
5436-
);
5437-
}
5438-
} else {
5439-
let thisLocal = flow.addScopedLocal((<Class>parent).type, "this", false);
5424+
let thisType = assert(instance.signature.thisType);
5425+
let classType = thisType.classReference;
5426+
let superType = classType
5427+
? classType.base
5428+
? classType.base.type
5429+
: null
5430+
: null;
5431+
if (getExpressionId(thisArg) == ExpressionId.GetLocal) { // reuse this var
5432+
flow.addScopedLocalAlias(getGetLocalIndex(thisArg), thisType, "this");
5433+
if (superType) flow.addScopedLocalAlias(getGetLocalIndex(thisArg), superType, "super");
5434+
} else { // use a temp var
5435+
let thisLocal = flow.addScopedLocal(thisType, "this", false);
54405436
body.push(
54415437
module.createSetLocal(thisLocal.index, thisArg)
54425438
);
5443-
let parentBase = (<Class>parent).base;
5444-
if (parentBase) {
5445-
flow.addScopedLocalAlias(
5446-
thisLocal.index,
5447-
parentBase.type,
5448-
"super"
5449-
);
5450-
}
5439+
if (superType) flow.addScopedLocalAlias(thisLocal.index, superType, "super");
54515440
}
54525441
}
54535442
var parameterTypes = signature.parameterTypes;
@@ -5895,7 +5884,7 @@ export class Compiler extends DiagnosticEmitter {
58955884
}
58965885

58975886
compileElementAccessExpression(expression: ElementAccessExpression, contextualType: Type): ExpressionRef {
5898-
var target = this.resolver.resolveElementAccess(expression, this.currentFunction); // reports
5887+
var target = this.resolver.resolveElementAccess(expression, this.currentFunction, contextualType); // reports
58995888
if (!target) return this.module.createUnreachable();
59005889
switch (target.kind) {
59015890
case ElementKind.CLASS: {
@@ -6003,7 +5992,7 @@ export class Compiler extends DiagnosticEmitter {
60035992
if (currentFunction.is(CommonFlags.INSTANCE)) {
60045993
let parent = assert(currentFunction.parent);
60055994
assert(parent.kind == ElementKind.CLASS);
6006-
let thisType = (<Class>parent).type;
5995+
let thisType = assert(currentFunction.signature.thisType);
60075996
if (currentFunction.is(CommonFlags.CONSTRUCTOR)) {
60085997
if (!flow.is(FlowFlags.ALLOCATES)) {
60095998
flow.set(FlowFlags.ALLOCATES);
@@ -6194,84 +6183,16 @@ export class Compiler extends DiagnosticEmitter {
61946183
intValue
61956184
);
61966185
}
6197-
switch (contextualType.kind) {
6198-
6199-
// compile to contextualType if matching
6200-
6201-
case TypeKind.I8: {
6202-
if (i64_is_i8(intValue)) return module.createI32(i64_low(intValue));
6203-
break;
6204-
}
6205-
case TypeKind.U8: {
6206-
if (i64_is_u8(intValue)) return module.createI32(i64_low(intValue));
6207-
break;
6208-
}
6209-
case TypeKind.I16: {
6210-
if (i64_is_i16(intValue)) return module.createI32(i64_low(intValue));
6211-
break;
6212-
}
6213-
case TypeKind.U16: {
6214-
if (i64_is_u16(intValue)) return module.createI32(i64_low(intValue));
6215-
break;
6216-
}
6217-
case TypeKind.I32: {
6218-
if (i64_is_i32(intValue)) return module.createI32(i64_low(intValue));
6219-
break;
6220-
}
6221-
case TypeKind.U32: {
6222-
if (i64_is_u32(intValue)) return module.createI32(i64_low(intValue));
6223-
break;
6224-
}
6225-
case TypeKind.BOOL: {
6226-
if (i64_is_bool(intValue)) return module.createI32(i64_low(intValue));
6227-
break;
6228-
}
6229-
case TypeKind.ISIZE: {
6230-
if (!this.options.isWasm64) {
6231-
if (i64_is_i32(intValue)) return module.createI32(i64_low(intValue));
6232-
break;
6233-
}
6234-
return module.createI64(i64_low(intValue), i64_high(intValue));
6235-
}
6236-
case TypeKind.USIZE: {
6237-
if (!this.options.isWasm64) {
6238-
if (i64_is_u32(intValue)) return module.createI32(i64_low(intValue));
6239-
break;
6240-
}
6241-
return module.createI64(i64_low(intValue), i64_high(intValue));
6242-
}
6243-
case TypeKind.I64:
6244-
case TypeKind.U64: {
6245-
return module.createI64(i64_low(intValue), i64_high(intValue));
6246-
}
6247-
case TypeKind.F32: {
6248-
if (i64_is_f32(intValue)) return module.createF32(i64_to_f32(intValue));
6249-
break;
6250-
}
6251-
case TypeKind.F64: {
6252-
if (i64_is_f64(intValue)) return module.createF64(i64_to_f64(intValue));
6253-
break;
6254-
}
6255-
case TypeKind.VOID: {
6256-
break; // compiles to best fitting type below, being dropped
6257-
}
6258-
default: {
6259-
assert(false);
6260-
return module.createUnreachable();
6261-
}
6262-
}
6263-
6264-
// otherwise compile to best fitting native type
6265-
6266-
if (i64_is_i32(intValue)) {
6267-
this.currentType = Type.i32;
6268-
return module.createI32(i64_low(intValue));
6269-
} else if (i64_is_u32(intValue)) {
6270-
this.currentType = Type.u32;
6271-
return module.createI32(i64_low(intValue));
6272-
} else {
6273-
this.currentType = Type.i64;
6274-
return module.createI64(i64_low(intValue), i64_high(intValue));
6186+
let type = this.resolver.determineIntegerLiteralType(intValue, contextualType);
6187+
this.currentType = type;
6188+
switch (type.kind) {
6189+
case TypeKind.ISIZE: if (!this.options.isWasm64) return module.createI32(i64_low(intValue));
6190+
case TypeKind.I64: return module.createI64(i64_low(intValue), i64_high(intValue));
6191+
case TypeKind.USIZE: if (!this.options.isWasm64) return module.createI32(i64_low(intValue));
6192+
case TypeKind.U64: return module.createI64(i64_low(intValue), i64_high(intValue));
6193+
case TypeKind.F32: return module.createF32(i64_to_f32(intValue));
6194+
case TypeKind.F64: return module.createF64(i64_to_f64(intValue));
6195+
default: return module.createI32(i64_low(intValue));
62756196
}
62766197
}
62776198
case LiteralKind.STRING: {
@@ -6749,7 +6670,7 @@ export class Compiler extends DiagnosticEmitter {
67496670
): ExpressionRef {
67506671
var module = this.module;
67516672

6752-
var target = this.resolver.resolvePropertyAccess(propertyAccess, this.currentFunction); // reports
6673+
var target = this.resolver.resolvePropertyAccess(propertyAccess, this.currentFunction, contextualType); // reports
67536674
if (!target) return module.createUnreachable();
67546675

67556676
switch (target.kind) {

src/program.ts

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -328,6 +328,8 @@ export class Program extends DiagnosticEmitter {
328328
fileLevelExports: Map<string,Element> = new Map();
329329
/** Module-level exports by exported name. */
330330
moduleLevelExports: Map<string,ModuleExport> = new Map();
331+
/** Classes backing basic types like `i32`. */
332+
basicClasses: Map<TypeKind,Class> = new Map();
331333

332334
/** ArrayBuffer instance reference. */
333335
arrayBufferInstance: Class | null = null;
@@ -641,6 +643,21 @@ export class Program extends DiagnosticEmitter {
641643
}
642644
}
643645

646+
// register classes backing basic types
647+
this.registerBasicClass(TypeKind.I8, "I8");
648+
this.registerBasicClass(TypeKind.I16, "I16");
649+
this.registerBasicClass(TypeKind.I32, "I32");
650+
this.registerBasicClass(TypeKind.I64, "I64");
651+
this.registerBasicClass(TypeKind.ISIZE, "Isize");
652+
this.registerBasicClass(TypeKind.U8, "U8");
653+
this.registerBasicClass(TypeKind.U16, "U16");
654+
this.registerBasicClass(TypeKind.U32, "U32");
655+
this.registerBasicClass(TypeKind.U64, "U64");
656+
this.registerBasicClass(TypeKind.USIZE, "Usize");
657+
this.registerBasicClass(TypeKind.BOOL, "Bool");
658+
this.registerBasicClass(TypeKind.F32, "F32");
659+
this.registerBasicClass(TypeKind.F64, "F64");
660+
644661
// register 'start'
645662
{
646663
let element = assert(this.elementsLookup.get("start"));
@@ -727,6 +744,15 @@ export class Program extends DiagnosticEmitter {
727744
}
728745
}
729746

747+
private registerBasicClass(typeKind: TypeKind, className: string): void {
748+
if (this.elementsLookup.has(className)) {
749+
let element = assert(this.elementsLookup.get(className));
750+
assert(element.kind == ElementKind.CLASS_PROTOTYPE);
751+
let classElement = this.resolver.resolveClass(<ClassPrototype>element, null);
752+
if (classElement) this.basicClasses.set(typeKind, classElement);
753+
}
754+
}
755+
730756
/** Sets a constant integer value. */
731757
setConstantInteger(globalName: string, type: Type, value: I64): void {
732758
assert(type.is(TypeFlags.INTEGER));

0 commit comments

Comments
 (0)