Fix compilation of immediate called function expressions

This commit is contained in:
dcodeIO 2018-03-12 22:34:40 +01:00
parent c93f0bb1fe
commit 7ee6e1cf7b
8 changed files with 92 additions and 19 deletions

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -31,6 +31,7 @@ import {
Field, Field,
FunctionPrototype, FunctionPrototype,
Function, Function,
FunctionTarget,
Global, Global,
Local, Local,
Namespace, Namespace,
@ -3876,8 +3877,9 @@ export class Compiler extends DiagnosticEmitter {
} }
} }
case ElementKind.FIELD: { case ElementKind.FIELD: {
if (signature = (<Field>element).type.functionType) { let type = (<Field>element).type;
let targetExpr = this.compileExpression(assert(resolved.targetExpression), Type.u32); if (signature = type.functionType) {
let targetExpr = this.compileExpression(assert(resolved.targetExpression), type);
indexArg = this.module.createLoad( indexArg = this.module.createLoad(
4, 4,
false, false,
@ -3894,9 +3896,12 @@ export class Compiler extends DiagnosticEmitter {
return this.module.createUnreachable(); return this.module.createUnreachable();
} }
} }
case ElementKind.PROPERTY: { case ElementKind.FUNCTION_TARGET: {
// TODO signature = (<FunctionTarget>element).signature;
indexArg = this.compileExpression(expression.expression, (<FunctionTarget>element).type);
break;
} }
case ElementKind.PROPERTY: // TODO
// not supported // not supported
default: { default: {

View File

@ -1774,10 +1774,15 @@ export class Program extends DiagnosticEmitter {
if (!resolvedElement) resolvedElement = new ResolvedElement(); if (!resolvedElement) resolvedElement = new ResolvedElement();
return resolvedElement.set(classType); return resolvedElement.set(classType);
} else { } else {
let functionType = returnType.functionType; let signature = returnType.functionType;
if (functionType) { if (signature) {
// TODO: Signatures aren't elements but probably should be let functionTarget = signature.cachedFunctionTarget;
throw new Error("not implemented"); if (!functionTarget) {
functionTarget = new FunctionTarget(this, signature);
signature.cachedFunctionTarget = functionTarget;
}
if (!resolvedElement) resolvedElement = new ResolvedElement();
return resolvedElement.set(functionTarget);
} }
} }
} }
@ -1846,6 +1851,8 @@ export enum ElementKind {
FUNCTION_PROTOTYPE, FUNCTION_PROTOTYPE,
/** A {@link Function}. */ /** A {@link Function}. */
FUNCTION, FUNCTION,
/** A {@link FunctionTarget}. */
FUNCTION_TARGET,
/** A {@link ClassPrototype}. */ /** A {@link ClassPrototype}. */
CLASS_PROTOTYPE, CLASS_PROTOTYPE,
/** A {@link Class}. */ /** A {@link Class}. */
@ -2671,6 +2678,27 @@ export class Function extends Element {
toString(): string { return this.prototype.simpleName; } toString(): string { return this.prototype.simpleName; }
} }
/** A resolved function table entry, that is an function called by an index and signature. */
export class FunctionTarget extends Element {
kind = ElementKind.FUNCTION_TARGET;
/** Underlying signature. */
signature: Signature;
/** Function type. */
type: Type;
/** Constructs a new function target. */
constructor(program: Program, signature: Signature) {
super(program, "", "");
var simpleName = signature.toSignatureString();
this.simpleName = simpleName;
this.internalName = simpleName;
this.signature = signature;
this.type = Type.u32.asFunction(signature);
}
}
/** A yet unresolved instance field prototype. */ /** A yet unresolved instance field prototype. */
export class FieldPrototype extends Element { export class FieldPrototype extends Element {

View File

@ -1,5 +1,6 @@
import { import {
Class Class,
FunctionTarget
} from "./program"; } from "./program";
import { import {
@ -452,6 +453,8 @@ export class Signature {
thisType: Type | null; thisType: Type | null;
/** Whether the last parameter is a rest parameter. */ /** Whether the last parameter is a rest parameter. */
hasRest: bool; hasRest: bool;
/** Cached {@link FunctionTarget}. */
cachedFunctionTarget: FunctionTarget | null = null;
constructor( constructor(
parameterTypes: Type[] | null = null, parameterTypes: Type[] | null = null,

View File

@ -2,11 +2,12 @@
(type $i (func (result i32))) (type $i (func (result i32)))
(type $iii (func (param i32 i32) (result i32))) (type $iii (func (param i32 i32) (result i32)))
(type $III (func (param i64 i64) (result i64))) (type $III (func (param i64 i64) (result i64)))
(type $FFF (func (param f64 f64) (result f64)))
(type $v (func)) (type $v (func))
(global $function-types/i32Adder (mut i32) (i32.const 0)) (global $function-types/i32Adder (mut i32) (i32.const 0))
(global $function-types/i64Adder (mut i32) (i32.const 0)) (global $function-types/i64Adder (mut i32) (i32.const 0))
(table 2 2 anyfunc) (table 3 3 anyfunc)
(elem (i32.const 0) $function-types/makeAdder<i32>~anonymous|0 $function-types/makeAdder<i64>~anonymous|1) (elem (i32.const 0) $function-types/makeAdder<i32>~anonymous|0 $function-types/makeAdder<i64>~anonymous|1 $function-types/makeAdder<f64>~anonymous|2)
(memory $0 1) (memory $0 1)
(export "memory" (memory $0)) (export "memory" (memory $0))
(start $start) (start $start)
@ -28,7 +29,16 @@
(func $function-types/makeAdder<i64> (; 3 ;) (type $i) (result i32) (func $function-types/makeAdder<i64> (; 3 ;) (type $i) (result i32)
(i32.const 1) (i32.const 1)
) )
(func $start (; 4 ;) (type $v) (func $function-types/makeAdder<f64>~anonymous|2 (; 4 ;) (type $FFF) (param $0 f64) (param $1 f64) (result f64)
(f64.add
(get_local $0)
(get_local $1)
)
)
(func $function-types/makeAdder<f64> (; 5 ;) (type $i) (result i32)
(i32.const 2)
)
(func $start (; 6 ;) (type $v)
(set_global $function-types/i32Adder (set_global $function-types/i32Adder
(call $function-types/makeAdder<i32>) (call $function-types/makeAdder<i32>)
) )
@ -49,5 +59,12 @@
(get_global $function-types/i64Adder) (get_global $function-types/i64Adder)
) )
) )
(drop
(call_indirect (type $FFF)
(f64.const 1)
(f64.const 2)
(call $function-types/makeAdder<f64>)
)
)
) )
) )

View File

@ -12,5 +12,4 @@ i32Adder(1, 2);
var i64Adder = makeAdder<i64>(); var i64Adder = makeAdder<i64>();
i64Adder(1, 2); i64Adder(1, 2);
// TODO: makeAdder<f64>()(1, 2);
// makeAdder<f64>()(1, 2);

View File

@ -2,12 +2,13 @@
(type $i (func (result i32))) (type $i (func (result i32)))
(type $iii (func (param i32 i32) (result i32))) (type $iii (func (param i32 i32) (result i32)))
(type $III (func (param i64 i64) (result i64))) (type $III (func (param i64 i64) (result i64)))
(type $FFF (func (param f64 f64) (result f64)))
(type $v (func)) (type $v (func))
(global $function-types/i32Adder (mut i32) (i32.const 0)) (global $function-types/i32Adder (mut i32) (i32.const 0))
(global $function-types/i64Adder (mut i32) (i32.const 0)) (global $function-types/i64Adder (mut i32) (i32.const 0))
(global $HEAP_BASE i32 (i32.const 4)) (global $HEAP_BASE i32 (i32.const 4))
(table 2 2 anyfunc) (table 3 3 anyfunc)
(elem (i32.const 0) $function-types/makeAdder<i32>~anonymous|0 $function-types/makeAdder<i64>~anonymous|1) (elem (i32.const 0) $function-types/makeAdder<i32>~anonymous|0 $function-types/makeAdder<i64>~anonymous|1 $function-types/makeAdder<f64>~anonymous|2)
(memory $0 1) (memory $0 1)
(export "memory" (memory $0)) (export "memory" (memory $0))
(start $start) (start $start)
@ -37,7 +38,20 @@
(i32.const 1) (i32.const 1)
) )
) )
(func $start (; 4 ;) (type $v) (func $function-types/makeAdder<f64>~anonymous|2 (; 4 ;) (type $FFF) (param $0 f64) (param $1 f64) (result f64)
(return
(f64.add
(get_local $0)
(get_local $1)
)
)
)
(func $function-types/makeAdder<f64> (; 5 ;) (type $i) (result i32)
(return
(i32.const 2)
)
)
(func $start (; 6 ;) (type $v)
(nop) (nop)
(set_global $function-types/i32Adder (set_global $function-types/i32Adder
(call $function-types/makeAdder<i32>) (call $function-types/makeAdder<i32>)
@ -59,5 +73,12 @@
(get_global $function-types/i64Adder) (get_global $function-types/i64Adder)
) )
) )
(drop
(call_indirect (type $FFF)
(f64.const 1)
(f64.const 2)
(call $function-types/makeAdder<f64>)
)
)
) )
) )