Fix contextual type argument propagation when calling function expressions; Implement indirect calls to concrete functions

This commit is contained in:
dcodeIO 2018-03-21 17:17:31 +01:00
parent 49f4d3dff1
commit 4687dc2572
9 changed files with 331 additions and 57 deletions

2
dist/asc.js vendored

File diff suppressed because one or more lines are too long

2
dist/asc.js.map vendored

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -4550,6 +4550,16 @@ export class Compiler extends DiagnosticEmitter {
}
return this.module.createGetGlobal((<EnumValue>element).internalName, NativeType.I32);
}
case ElementKind.FUNCTION_PROTOTYPE: {
let instance = (<FunctionPrototype>element).resolve(
null,
this.currentFunction.contextualTypeArguments
);
if (!(instance && this.compileFunction(instance))) return module.createUnreachable();
let index = this.ensureFunctionTableEntry(instance);
this.currentType = Type.u32.asFunction(instance.signature);
return this.module.createI32(index);
}
}
this.error(
DiagnosticCode.Operation_not_supported,

View File

@ -1892,7 +1892,7 @@ export class Program extends DiagnosticEmitter {
if (element && element.kind == ElementKind.FUNCTION_PROTOTYPE) {
let instance = (<FunctionPrototype>element).resolveUsingTypeArguments(
(<CallExpression>expression).typeArguments,
null,
contextualFunction.contextualTypeArguments,
expression
);
if (instance) {

View File

@ -1,70 +1,180 @@
(module
(type $i (func (result i32)))
(type $iii (func (param i32 i32) (result i32)))
(type $iiiiv (func (param i32 i32 i32 i32)))
(type $III (func (param i64 i64) (result i64)))
(type $FFF (func (param f64 f64) (result f64)))
(type $iiii (func (param i32 i32 i32) (result i32)))
(type $v (func))
(import "env" "abort" (func $abort (param i32 i32 i32 i32)))
(global $function-types/i32Adder (mut i32) (i32.const 0))
(global $function-types/i64Adder (mut i32) (i32.const 0))
(table 3 3 anyfunc)
(elem (i32.const 0) $function-types/makeAdder<i32>~anonymous|0 $function-types/makeAdder<i64>~anonymous|1 $function-types/makeAdder<f64>~anonymous|2)
(table 4 4 anyfunc)
(elem (i32.const 0) $function-types/makeAdder<i32>~anonymous|0 $function-types/makeAdder<i64>~anonymous|1 $function-types/makeAdder<f64>~anonymous|2 $function-types/makeAdder<i32>~anonymous|0)
(memory $0 1)
(data (i32.const 4) "\11\00\00\00f\00u\00n\00c\00t\00i\00o\00n\00-\00t\00y\00p\00e\00s\00.\00t\00s")
(export "memory" (memory $0))
(start $start)
(func $function-types/makeAdder<i32>~anonymous|0 (; 0 ;) (type $iii) (param $0 i32) (param $1 i32) (result i32)
(func $function-types/makeAdder<i32>~anonymous|0 (; 1 ;) (type $iii) (param $0 i32) (param $1 i32) (result i32)
(i32.add
(get_local $0)
(get_local $1)
)
)
(func $function-types/makeAdder<i32> (; 1 ;) (type $i) (result i32)
(func $function-types/makeAdder<i32> (; 2 ;) (type $i) (result i32)
(i32.const 0)
)
(func $function-types/makeAdder<i64>~anonymous|1 (; 2 ;) (type $III) (param $0 i64) (param $1 i64) (result i64)
(func $function-types/makeAdder<i64>~anonymous|1 (; 3 ;) (type $III) (param $0 i64) (param $1 i64) (result i64)
(i64.add
(get_local $0)
(get_local $1)
)
)
(func $function-types/makeAdder<i64> (; 3 ;) (type $i) (result i32)
(func $function-types/makeAdder<i64> (; 4 ;) (type $i) (result i32)
(i32.const 1)
)
(func $function-types/makeAdder<f64>~anonymous|2 (; 4 ;) (type $FFF) (param $0 f64) (param $1 f64) (result f64)
(func $function-types/makeAdder<f64>~anonymous|2 (; 5 ;) (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)
(func $function-types/makeAdder<f64> (; 6 ;) (type $i) (result i32)
(i32.const 2)
)
(func $start (; 6 ;) (type $v)
(func $function-types/doAddWithFn<i32> (; 7 ;) (type $iiii) (param $0 i32) (param $1 i32) (param $2 i32) (result i32)
(call_indirect (type $iii)
(get_local $0)
(get_local $1)
(get_local $2)
)
)
(func $function-types/doAdd<i32> (; 8 ;) (type $iii) (param $0 i32) (param $1 i32) (result i32)
(call_indirect (type $iii)
(get_local $0)
(get_local $1)
(call $function-types/makeAdder<i32>)
)
)
(func $start (; 9 ;) (type $v)
(set_global $function-types/i32Adder
(call $function-types/makeAdder<i32>)
)
(drop
(if
(i32.ne
(call_indirect (type $iii)
(i32.const 1)
(i32.const 2)
(get_global $function-types/i32Adder)
)
(i32.const 3)
)
(block
(call $abort
(i32.const 0)
(i32.const 4)
(i32.const 11)
(i32.const 0)
)
(unreachable)
)
)
(set_global $function-types/i64Adder
(call $function-types/makeAdder<i64>)
)
(drop
(if
(i64.ne
(call_indirect (type $III)
(i64.const 1)
(i64.const 2)
(i64.const 10)
(i64.const 20)
(get_global $function-types/i64Adder)
)
(i64.const 30)
)
(drop
(block
(call $abort
(i32.const 0)
(i32.const 4)
(i32.const 15)
(i32.const 0)
)
(unreachable)
)
)
(if
(f64.ne
(call_indirect (type $FFF)
(f64.const 1)
(f64.const 2)
(f64.const 1.5)
(f64.const 2.5)
(call $function-types/makeAdder<f64>)
)
(f64.const 4)
)
(block
(call $abort
(i32.const 0)
(i32.const 4)
(i32.const 17)
(i32.const 0)
)
(unreachable)
)
)
(if
(i32.ne
(call $function-types/doAddWithFn<i32>
(i32.const 2)
(i32.const 3)
(get_global $function-types/i32Adder)
)
(i32.const 5)
)
(block
(call $abort
(i32.const 0)
(i32.const 4)
(i32.const 23)
(i32.const 0)
)
(unreachable)
)
)
(if
(i32.ne
(call $function-types/doAdd<i32>
(i32.const 3)
(i32.const 4)
)
(i32.const 7)
)
(block
(call $abort
(i32.const 0)
(i32.const 4)
(i32.const 29)
(i32.const 0)
)
(unreachable)
)
)
(if
(i32.ne
(call $function-types/doAddWithFn<i32>
(i32.const 4)
(i32.const 5)
(i32.const 3)
)
(i32.const 9)
)
(block
(call $abort
(i32.const 0)
(i32.const 4)
(i32.const 35)
(i32.const 0)
)
(unreachable)
)
)
)
)

View File

@ -7,9 +7,29 @@ function makeAdder<T>(): Adder<T> {
}
var i32Adder = makeAdder<i32>();
i32Adder(1, 2);
assert(i32Adder(1, 2) == 3);
var i64Adder = makeAdder<i64>();
i64Adder(1, 2);
makeAdder<f64>()(1, 2);
assert(i64Adder(10, 20) == 30);
assert(makeAdder<f64>()(1.5, 2.5) == 4.0);
function doAddWithFn<T>(a: T, b: T, fn: (a: T, b: T) => T): T {
return fn(a, b);
}
assert(doAddWithFn<i32>(2, 3, i32Adder) == 5);
function doAdd<T>(a: T, b: T): T {
return makeAdder<T>()(a, b);
}
assert(doAdd<i32>(3, 4) == 7);
function addI32(a: i32, b: i32): i32 {
return a + b;
}
assert(doAddWithFn<i32>(4, 5, addI32) == 9);

View File

@ -1,18 +1,22 @@
(module
(type $i (func (result i32)))
(type $iii (func (param i32 i32) (result i32)))
(type $iiiiv (func (param i32 i32 i32 i32)))
(type $III (func (param i64 i64) (result i64)))
(type $FFF (func (param f64 f64) (result f64)))
(type $iiii (func (param i32 i32 i32) (result i32)))
(type $v (func))
(import "env" "abort" (func $abort (param i32 i32 i32 i32)))
(global $function-types/i32Adder (mut i32) (i32.const 0))
(global $function-types/i64Adder (mut i32) (i32.const 0))
(global $HEAP_BASE i32 (i32.const 4))
(table 3 3 anyfunc)
(elem (i32.const 0) $function-types/makeAdder<i32>~anonymous|0 $function-types/makeAdder<i64>~anonymous|1 $function-types/makeAdder<f64>~anonymous|2)
(global $HEAP_BASE i32 (i32.const 44))
(table 4 4 anyfunc)
(elem (i32.const 0) $function-types/makeAdder<i32>~anonymous|0 $function-types/makeAdder<i64>~anonymous|1 $function-types/makeAdder<f64>~anonymous|2 $function-types/addI32)
(memory $0 1)
(data (i32.const 4) "\11\00\00\00f\00u\00n\00c\00t\00i\00o\00n\00-\00t\00y\00p\00e\00s\00.\00t\00s\00")
(export "memory" (memory $0))
(start $start)
(func $function-types/makeAdder<i32>~anonymous|0 (; 0 ;) (type $iii) (param $0 i32) (param $1 i32) (result i32)
(func $function-types/makeAdder<i32>~anonymous|0 (; 1 ;) (type $iii) (param $0 i32) (param $1 i32) (result i32)
(return
(i32.add
(get_local $0)
@ -20,12 +24,12 @@
)
)
)
(func $function-types/makeAdder<i32> (; 1 ;) (type $i) (result i32)
(func $function-types/makeAdder<i32> (; 2 ;) (type $i) (result i32)
(return
(i32.const 0)
)
)
(func $function-types/makeAdder<i64>~anonymous|1 (; 2 ;) (type $III) (param $0 i64) (param $1 i64) (result i64)
(func $function-types/makeAdder<i64>~anonymous|1 (; 3 ;) (type $III) (param $0 i64) (param $1 i64) (result i64)
(return
(i64.add
(get_local $0)
@ -33,12 +37,12 @@
)
)
)
(func $function-types/makeAdder<i64> (; 3 ;) (type $i) (result i32)
(func $function-types/makeAdder<i64> (; 4 ;) (type $i) (result i32)
(return
(i32.const 1)
)
)
(func $function-types/makeAdder<f64>~anonymous|2 (; 4 ;) (type $FFF) (param $0 f64) (param $1 f64) (result f64)
(func $function-types/makeAdder<f64>~anonymous|2 (; 5 ;) (type $FFF) (param $0 f64) (param $1 f64) (result f64)
(return
(f64.add
(get_local $0)
@ -46,39 +50,169 @@
)
)
)
(func $function-types/makeAdder<f64> (; 5 ;) (type $i) (result i32)
(func $function-types/makeAdder<f64> (; 6 ;) (type $i) (result i32)
(return
(i32.const 2)
)
)
(func $start (; 6 ;) (type $v)
(func $function-types/doAddWithFn<i32> (; 7 ;) (type $iiii) (param $0 i32) (param $1 i32) (param $2 i32) (result i32)
(return
(call_indirect (type $iii)
(get_local $0)
(get_local $1)
(get_local $2)
)
)
)
(func $function-types/doAdd<i32> (; 8 ;) (type $iii) (param $0 i32) (param $1 i32) (result i32)
(return
(call_indirect (type $iii)
(get_local $0)
(get_local $1)
(call $function-types/makeAdder<i32>)
)
)
)
(func $function-types/addI32 (; 9 ;) (type $iii) (param $0 i32) (param $1 i32) (result i32)
(return
(i32.add
(get_local $0)
(get_local $1)
)
)
)
(func $start (; 10 ;) (type $v)
(nop)
(set_global $function-types/i32Adder
(call $function-types/makeAdder<i32>)
)
(drop
(if
(i32.eqz
(i32.eq
(call_indirect (type $iii)
(i32.const 1)
(i32.const 2)
(get_global $function-types/i32Adder)
)
(i32.const 3)
)
)
(block
(call $abort
(i32.const 0)
(i32.const 4)
(i32.const 11)
(i32.const 0)
)
(unreachable)
)
)
(set_global $function-types/i64Adder
(call $function-types/makeAdder<i64>)
)
(drop
(if
(i32.eqz
(i64.eq
(call_indirect (type $III)
(i64.const 1)
(i64.const 2)
(i64.const 10)
(i64.const 20)
(get_global $function-types/i64Adder)
)
(i64.const 30)
)
(drop
)
(block
(call $abort
(i32.const 0)
(i32.const 4)
(i32.const 15)
(i32.const 0)
)
(unreachable)
)
)
(if
(i32.eqz
(f64.eq
(call_indirect (type $FFF)
(f64.const 1)
(f64.const 2)
(f64.const 1.5)
(f64.const 2.5)
(call $function-types/makeAdder<f64>)
)
(f64.const 4)
)
)
(block
(call $abort
(i32.const 0)
(i32.const 4)
(i32.const 17)
(i32.const 0)
)
(unreachable)
)
)
(if
(i32.eqz
(i32.eq
(call $function-types/doAddWithFn<i32>
(i32.const 2)
(i32.const 3)
(get_global $function-types/i32Adder)
)
(i32.const 5)
)
)
(block
(call $abort
(i32.const 0)
(i32.const 4)
(i32.const 23)
(i32.const 0)
)
(unreachable)
)
)
(if
(i32.eqz
(i32.eq
(call $function-types/doAdd<i32>
(i32.const 3)
(i32.const 4)
)
(i32.const 7)
)
)
(block
(call $abort
(i32.const 0)
(i32.const 4)
(i32.const 29)
(i32.const 0)
)
(unreachable)
)
)
(if
(i32.eqz
(i32.eq
(call $function-types/doAddWithFn<i32>
(i32.const 4)
(i32.const 5)
(i32.const 3)
)
(i32.const 9)
)
)
(block
(call $abort
(i32.const 0)
(i32.const 4)
(i32.const 35)
(i32.const 0)
)
(unreachable)
)
)
)
)