Skip to content

Commit 0c40d2f

Browse files
dcodeIOWillem Wyndham
authored and
Willem Wyndham
committed
Add 'instantiate<T>' builtin (like 'new' but from a type), see AssemblyScript#349
1 parent 7a002d2 commit 0c40d2f

File tree

4 files changed

+35
-5
lines changed

4 files changed

+35
-5
lines changed

src/builtins.ts

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2734,6 +2734,25 @@ export function compileCall(
27342734
// thus must be used with care. it exists because it *might* be useful in specific scenarios.
27352735
return module.createCallIndirect(arg0, operandExprs, typeName);
27362736
}
2737+
case "instantiate": {
2738+
if (!(typeArguments && typeArguments.length == 1)) {
2739+
if (typeArguments && typeArguments.length) compiler.currentType = typeArguments[0];
2740+
compiler.error(
2741+
DiagnosticCode.Expected_0_type_arguments_but_got_1,
2742+
reportNode.range, "1", typeArguments ? typeArguments.length.toString(10) : "0"
2743+
);
2744+
return module.createUnreachable();
2745+
}
2746+
let classInstance = typeArguments[0].classReference;
2747+
if (!classInstance) {
2748+
compiler.error(
2749+
DiagnosticCode.Operation_not_supported,
2750+
reportNode.range
2751+
);
2752+
return module.createUnreachable();
2753+
}
2754+
return compiler.compileInstantiate(classInstance, operands, reportNode);
2755+
}
27372756

27382757
// user-defined diagnostic macros
27392758

src/compiler.ts

Lines changed: 13 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -6656,9 +6656,10 @@ export class Compiler extends DiagnosticEmitter {
66566656
);
66576657
}
66586658
if (!classInstance) return module.createUnreachable();
6659+
return this.compileInstantiate(classInstance, expression.arguments, expression);
6660+
}
66596661

6660-
var expr: ExpressionRef;
6661-
6662+
compileInstantiate(classInstance: Class, argumentExpressions: Expression[], reportNode: Node): ExpressionRef {
66626663
// traverse to the top-most visible constructor
66636664
var currentClassInstance: Class | null = classInstance;
66646665
var constructorInstance: Function | null = null;
@@ -6668,14 +6669,21 @@ export class Compiler extends DiagnosticEmitter {
66686669
} while (currentClassInstance = currentClassInstance.base);
66696670

66706671
// if a constructor is present, call it with a zero `this`
6672+
var expr: ExpressionRef;
66716673
if (constructorInstance) {
6672-
expr = this.compileCallDirect(constructorInstance, expression.arguments, expression,
6673-
options.usizeType.toNativeZero(module)
6674+
expr = this.compileCallDirect(constructorInstance, argumentExpressions, reportNode,
6675+
this.options.usizeType.toNativeZero(this.module)
66746676
);
66756677

66766678
// otherwise simply allocate a new instance and initialize its fields
66776679
} else {
6678-
expr = this.makeAllocate(classInstance, expression);
6680+
if (argumentExpressions.length) {
6681+
this.error(
6682+
DiagnosticCode.Expected_0_arguments_but_got_1,
6683+
reportNode.range, "0", argumentExpressions.length.toString(10)
6684+
);
6685+
}
6686+
expr = this.makeAllocate(classInstance, reportNode);
66796687
}
66806688

66816689
this.currentType = classInstance.type;

std/assembly/builtins.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@
4141
@builtin export declare function assert<T>(isTrueish: T, message?: string): T;
4242
@builtin export declare function unchecked<T>(expr: T): T;
4343
@builtin export declare function call_indirect<T>(target: void, ...args: void[]): T;
44+
@builtin export declare function instantiate<T>(...args: void[]): T;
4445

4546
export namespace Atomic {
4647
@builtin export declare function load<T>(offset: usize, constantOffset?: usize): T;

std/assembly/index.d.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -112,6 +112,8 @@ declare function changetype<T>(value: any): T;
112112
declare function unchecked<T>(value: T): T;
113113
/** Emits a `call_indirect` instruction, calling the specified function in the function table by index with the specified arguments. Does result in a runtime error if the arguments do not match the called function. */
114114
declare function call_indirect<T>(target: Function | u32, ...args: any[]): T;
115+
/** Instantiates a new instance of `T` using the specified constructor arguments. */
116+
declare function instantiate<T>(...args: any[]): T;
115117
/** Tests if a 32-bit or 64-bit float is `NaN`. */
116118
declare function isNaN<T = f32 | f64>(value: T): bool;
117119
/** Tests if a 32-bit or 64-bit float is finite, that is not `NaN` or +/-`Infinity`. */

0 commit comments

Comments
 (0)