Skip to content

Commit 1149abf

Browse files
committed
Add 'instantiate<T>' builtin (like 'new' but from a type), see #349
1 parent 1d93877 commit 1149abf

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
@@ -2322,6 +2322,25 @@ export function compileCall(
23222322
// thus must be used with care. it exists because it *might* be useful in specific scenarios.
23232323
return module.createCallIndirect(arg0, operandExprs, typeName);
23242324
}
2325+
case "instantiate": {
2326+
if (!(typeArguments && typeArguments.length == 1)) {
2327+
if (typeArguments && typeArguments.length) compiler.currentType = typeArguments[0];
2328+
compiler.error(
2329+
DiagnosticCode.Expected_0_type_arguments_but_got_1,
2330+
reportNode.range, "1", typeArguments ? typeArguments.length.toString(10) : "0"
2331+
);
2332+
return module.createUnreachable();
2333+
}
2334+
let classInstance = typeArguments[0].classReference;
2335+
if (!classInstance) {
2336+
compiler.error(
2337+
DiagnosticCode.Operation_not_supported,
2338+
reportNode.range
2339+
);
2340+
return module.createUnreachable();
2341+
}
2342+
return compiler.compileInstantiate(classInstance, operands, reportNode);
2343+
}
23252344

23262345
// user-defined diagnostic macros
23272346

src/compiler.ts

Lines changed: 13 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -6651,9 +6651,10 @@ export class Compiler extends DiagnosticEmitter {
66516651
);
66526652
}
66536653
if (!classInstance) return module.createUnreachable();
6654+
return this.compileInstantiate(classInstance, expression.arguments, expression);
6655+
}
66546656

6655-
var expr: ExpressionRef;
6656-
6657+
compileInstantiate(classInstance: Class, argumentExpressions: Expression[], reportNode: Node): ExpressionRef {
66576658
// traverse to the top-most visible constructor
66586659
var currentClassInstance: Class | null = classInstance;
66596660
var constructorInstance: Function | null = null;
@@ -6663,14 +6664,21 @@ export class Compiler extends DiagnosticEmitter {
66636664
} while (currentClassInstance = currentClassInstance.base);
66646665

66656666
// if a constructor is present, call it with a zero `this`
6667+
var expr: ExpressionRef;
66666668
if (constructorInstance) {
6667-
expr = this.compileCallDirect(constructorInstance, expression.arguments, expression,
6668-
options.usizeType.toNativeZero(module)
6669+
expr = this.compileCallDirect(constructorInstance, argumentExpressions, reportNode,
6670+
this.options.usizeType.toNativeZero(this.module)
66696671
);
66706672

66716673
// otherwise simply allocate a new instance and initialize its fields
66726674
} else {
6673-
expr = this.makeAllocate(classInstance, expression);
6675+
if (argumentExpressions.length) {
6676+
this.error(
6677+
DiagnosticCode.Expected_0_arguments_but_got_1,
6678+
reportNode.range, "0", argumentExpressions.length.toString(10)
6679+
);
6680+
}
6681+
expr = this.makeAllocate(classInstance, reportNode);
66746682
}
66756683

66766684
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
@builtin export declare function i8(value: void): i8;
4647
export namespace i8 {

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)