From b83638245708e426a8d48a1d80797d58b567d48f Mon Sep 17 00:00:00 2001 From: dcode Date: Tue, 9 Jun 2020 23:39:32 +0200 Subject: [PATCH] Implicitly resolve to callables when resolving call expressions --- src/resolver.ts | 11 + .../function-expression.optimized.wat | 111 +++++++ tests/compiler/function-expression.ts | 39 +++ .../function-expression.untouched.wat | 274 +++++++++++++++++- 4 files changed, 431 insertions(+), 4 deletions(-) diff --git a/src/resolver.ts b/src/resolver.ts index 551e893c23..3cef9ca2c1 100644 --- a/src/resolver.ts +++ b/src/resolver.ts @@ -2384,6 +2384,17 @@ export class Resolver extends DiagnosticEmitter { if (!instance) return null; return instance.signature.returnType; } + case ElementKind.GLOBAL: + case ElementKind.LOCAL: + case ElementKind.FIELD: { + let varType = (target).type; + let varElement = this.getElementOfType(varType); + if (!varElement || varElement.kind != ElementKind.FUNCTION_TARGET) { + break; + } + target = varElement; + // fall-through + } case ElementKind.FUNCTION_TARGET: { return (target).signature.returnType; } diff --git a/tests/compiler/function-expression.optimized.wat b/tests/compiler/function-expression.optimized.wat index a0f1087d58..7d019dffa1 100644 --- a/tests/compiler/function-expression.optimized.wat +++ b/tests/compiler/function-expression.optimized.wat @@ -1,5 +1,116 @@ (module + (type $none_=>_i32 (func (result i32))) + (type $i32_=>_i32 (func (param i32) (result i32))) + (type $i32_i32_=>_i32 (func (param i32 i32) (result i32))) + (type $none_=>_none (func)) + (type $i32_i32_i32_i32_=>_none (func (param i32 i32 i32 i32))) + (import "env" "abort" (func $~lib/builtins/abort (param i32 i32 i32 i32))) (memory $0 1) (data (i32.const 1024) ",\00\00\00\01\00\00\00\01\00\00\00,\00\00\00f\00u\00n\00c\00t\00i\00o\00n\00-\00e\00x\00p\00r\00e\00s\00s\00i\00o\00n\00.\00t\00s") + (table $0 18 funcref) + (elem (i32.const 1) $start:function-expression~anonymous|0 $start:function-expression~anonymous|0 $start:function-expression~someName $start:function-expression~anonymous|2 $start:function-expression~anonymous|3 $start:function-expression~anonymous|4 $start:function-expression~anonymous|5 $start:function-expression~anonymous|3 $start:function-expression~anonymous|4 $start:function-expression~anonymous|5 $start:function-expression~anonymous|2 $function-expression/testGlobal~anonymous|0~anonymous|0 $function-expression/testGlobal~anonymous|0 $function-expression/testGlobal~anonymous|0~anonymous|0 $function-expression/testLocal~anonymous|0 $function-expression/testGlobal~anonymous|0~anonymous|0 $function-expression/testField~anonymous|0) (export "memory" (memory $0)) + (start $~start) + (func $start:function-expression~anonymous|0 (param $0 i32) (result i32) + local.get $0 + ) + (func $start:function-expression~someName + nop + ) + (func $start:function-expression~anonymous|2 (result i32) + i32.const 1 + ) + (func $start:function-expression~anonymous|3 (param $0 i32) (param $1 i32) (result i32) + local.get $0 + local.get $1 + i32.add + ) + (func $start:function-expression~anonymous|4 (param $0 i32) (param $1 i32) (result i32) + local.get $0 + ) + (func $start:function-expression~anonymous|5 (param $0 i32) (param $1 i32) (result i32) + i32.const 42 + ) + (func $function-expression/testGlobal~anonymous|0~anonymous|0 (param $0 i32) (result i32) + local.get $0 + i32.const 24 + i32.add + ) + (func $function-expression/testGlobal~anonymous|0 (result i32) + i32.const 12 + ) + (func $function-expression/testLocal~anonymous|0 (result i32) + i32.const 14 + ) + (func $function-expression/testField~anonymous|0 (result i32) + i32.const 16 + ) + (func $~start + (local $0 i32) + (local $1 i32) + i32.const 1120 + memory.size + local.tee $1 + i32.const 16 + i32.shl + local.tee $0 + i32.gt_u + if + local.get $1 + i32.const 66655 + local.get $0 + i32.sub + i32.const -65536 + i32.and + i32.const 16 + i32.shr_u + local.tee $0 + local.get $1 + local.get $0 + i32.gt_s + select + memory.grow + i32.const 0 + i32.lt_s + if + local.get $0 + memory.grow + i32.const 0 + i32.lt_s + if + unreachable + end + end + end + i32.const 1088 + i32.const 16 + i32.store + i32.const 1092 + i32.const 1 + i32.store + i32.const 1096 + i32.const 3 + i32.store + i32.const 1100 + i32.const 4 + i32.store + i32.const 1104 + i32.const 17 + i32.store + i32.const 1 + i32.const 1104 + i32.load + call_indirect (type $none_=>_i32) + call_indirect (type $i32_=>_i32) + i32.const 25 + i32.ne + if + i32.const 0 + i32.const 1040 + i32.const 82 + i32.const 3 + call $~lib/builtins/abort + unreachable + end + ) ) diff --git a/tests/compiler/function-expression.ts b/tests/compiler/function-expression.ts index 294eaee7bf..8fe0fdbf2e 100644 --- a/tests/compiler/function-expression.ts +++ b/tests/compiler/function-expression.ts @@ -43,3 +43,42 @@ function testNullable(b: boolean): (() => i32) | null { } } assert(testNullable(false) == null); + +// see: https://github.com/AssemblyScript/assemblyscript/issues/1289 + +var globalFunc: () => (x: i32) => i32; +function testGlobal(): void { + globalFunc = (): (x:i32) => i32 => { + let myFunc = (x: i32): i32 => { + return 24 + x; + }; + return myFunc; + }; + assert(globalFunc()(1) == 25); +} +testGlobal(); + +function testLocal(): void { + let localFunc = (): (x:i32) => i32 => { + let myFunc = (x: i32): i32 => { + return 24 + x; + }; + return myFunc; + }; + assert(localFunc()(1) == 25); +} +testLocal(); + +class FieldClass { + constructor(public fieldFunc: () => (x: i32) => i32) {} +} +function testField(): void { + let fieldInst = new FieldClass((): (x:i32) => i32 => { + let myFunc = (x: i32): i32 => { + return 24 + x; + }; + return myFunc; + }); + assert(fieldInst.fieldFunc()(1) == 25); +} +testField(); diff --git a/tests/compiler/function-expression.untouched.wat b/tests/compiler/function-expression.untouched.wat index 32a6e38e23..4e8ee52c68 100644 --- a/tests/compiler/function-expression.untouched.wat +++ b/tests/compiler/function-expression.untouched.wat @@ -1,19 +1,24 @@ (module - (type $i32_i32_=>_i32 (func (param i32 i32) (result i32))) - (type $none_=>_i32 (func (result i32))) (type $i32_=>_i32 (func (param i32) (result i32))) + (type $none_=>_i32 (func (result i32))) + (type $i32_i32_=>_i32 (func (param i32 i32) (result i32))) (type $none_=>_none (func)) + (type $i32_=>_none (func (param i32))) (type $i32_i32_i32_i32_=>_none (func (param i32 i32 i32 i32))) (import "env" "abort" (func $~lib/builtins/abort (param i32 i32 i32 i32))) (memory $0 1) (data (i32.const 16) ",\00\00\00\01\00\00\00\01\00\00\00,\00\00\00f\00u\00n\00c\00t\00i\00o\00n\00-\00e\00x\00p\00r\00e\00s\00s\00i\00o\00n\00.\00t\00s\00") - (table $0 12 funcref) - (elem (i32.const 1) $start:function-expression~anonymous|0 $start:function-expression~anonymous|1 $start:function-expression~someName $start:function-expression~anonymous|2 $start:function-expression~anonymous|3 $start:function-expression~anonymous|4 $start:function-expression~anonymous|5 $function-expression/testOmittedReturn1~anonymous|0 $function-expression/testOmittedReturn2~anonymous|0 $function-expression/testOmittedReturn3~anonymous|0 $function-expression/testNullable~anonymous|0) + (table $0 18 funcref) + (elem (i32.const 1) $start:function-expression~anonymous|0 $start:function-expression~anonymous|1 $start:function-expression~someName $start:function-expression~anonymous|2 $start:function-expression~anonymous|3 $start:function-expression~anonymous|4 $start:function-expression~anonymous|5 $function-expression/testOmittedReturn1~anonymous|0 $function-expression/testOmittedReturn2~anonymous|0 $function-expression/testOmittedReturn3~anonymous|0 $function-expression/testNullable~anonymous|0 $function-expression/testGlobal~anonymous|0~anonymous|0 $function-expression/testGlobal~anonymous|0 $function-expression/testLocal~anonymous|0~anonymous|0 $function-expression/testLocal~anonymous|0 $function-expression/testField~anonymous|0~anonymous|0 $function-expression/testField~anonymous|0) (global $function-expression/f1 (mut i32) (i32.const 1)) (global $~argumentsLength (mut i32) (i32.const 0)) (global $function-expression/f2 (mut i32) (i32.const 2)) (global $function-expression/f3 (mut i32) (i32.const 3)) (global $function-expression/f4 (mut i32) (i32.const 4)) + (global $function-expression/globalFunc (mut i32) (i32.const 0)) + (global $~lib/rt/stub/startOffset (mut i32) (i32.const 0)) + (global $~lib/rt/stub/offset (mut i32) (i32.const 0)) + (global $~lib/heap/__heap_base i32 (i32.const 76)) (export "memory" (memory $0)) (start $~start) (func $start:function-expression~anonymous|0 (param $0 i32) (result i32) @@ -81,6 +86,254 @@ end unreachable ) + (func $function-expression/testGlobal~anonymous|0~anonymous|0 (param $0 i32) (result i32) + i32.const 24 + local.get $0 + i32.add + ) + (func $function-expression/testGlobal~anonymous|0 (result i32) + (local $0 i32) + i32.const 12 + local.set $0 + local.get $0 + ) + (func $function-expression/testGlobal + (local $0 i32) + i32.const 13 + global.set $function-expression/globalFunc + i32.const 1 + i32.const 0 + global.set $~argumentsLength + global.get $function-expression/globalFunc + call_indirect (type $none_=>_i32) + local.set $0 + i32.const 1 + global.set $~argumentsLength + local.get $0 + call_indirect (type $i32_=>_i32) + i32.const 25 + i32.eq + i32.eqz + if + i32.const 0 + i32.const 32 + i32.const 57 + i32.const 3 + call $~lib/builtins/abort + unreachable + end + ) + (func $function-expression/testLocal~anonymous|0~anonymous|0 (param $0 i32) (result i32) + i32.const 24 + local.get $0 + i32.add + ) + (func $function-expression/testLocal~anonymous|0 (result i32) + (local $0 i32) + i32.const 14 + local.set $0 + local.get $0 + ) + (func $function-expression/testLocal + (local $0 i32) + (local $1 i32) + i32.const 15 + local.set $0 + i32.const 1 + i32.const 0 + global.set $~argumentsLength + local.get $0 + call_indirect (type $none_=>_i32) + local.set $1 + i32.const 1 + global.set $~argumentsLength + local.get $1 + call_indirect (type $i32_=>_i32) + i32.const 25 + i32.eq + i32.eqz + if + i32.const 0 + i32.const 32 + i32.const 68 + i32.const 3 + call $~lib/builtins/abort + unreachable + end + ) + (func $~lib/rt/stub/maybeGrowMemory (param $0 i32) + (local $1 i32) + (local $2 i32) + (local $3 i32) + (local $4 i32) + (local $5 i32) + memory.size + local.set $1 + local.get $1 + i32.const 16 + i32.shl + local.set $2 + local.get $0 + local.get $2 + i32.gt_u + if + local.get $0 + local.get $2 + i32.sub + i32.const 65535 + i32.add + i32.const 65535 + i32.const -1 + i32.xor + i32.and + i32.const 16 + i32.shr_u + local.set $3 + local.get $1 + local.tee $4 + local.get $3 + local.tee $5 + local.get $4 + local.get $5 + i32.gt_s + select + local.set $4 + local.get $4 + memory.grow + i32.const 0 + i32.lt_s + if + local.get $3 + memory.grow + i32.const 0 + i32.lt_s + if + unreachable + end + end + end + local.get $0 + global.set $~lib/rt/stub/offset + ) + (func $~lib/rt/stub/__alloc (param $0 i32) (param $1 i32) (result i32) + (local $2 i32) + (local $3 i32) + (local $4 i32) + (local $5 i32) + (local $6 i32) + local.get $0 + i32.const 1073741808 + i32.gt_u + if + unreachable + end + global.get $~lib/rt/stub/offset + i32.const 16 + i32.add + local.set $2 + local.get $0 + i32.const 15 + i32.add + i32.const 15 + i32.const -1 + i32.xor + i32.and + local.tee $3 + i32.const 16 + local.tee $4 + local.get $3 + local.get $4 + i32.gt_u + select + local.set $5 + local.get $2 + local.get $5 + i32.add + call $~lib/rt/stub/maybeGrowMemory + local.get $2 + i32.const 16 + i32.sub + local.set $6 + local.get $6 + local.get $5 + i32.store + i32.const 1 + drop + local.get $6 + i32.const 1 + i32.store offset=4 + local.get $6 + local.get $1 + i32.store offset=8 + local.get $6 + local.get $0 + i32.store offset=12 + local.get $2 + ) + (func $~lib/rt/stub/__retain (param $0 i32) (result i32) + local.get $0 + ) + (func $function-expression/FieldClass#constructor (param $0 i32) (param $1 i32) (result i32) + local.get $0 + i32.eqz + if + i32.const 4 + i32.const 3 + call $~lib/rt/stub/__alloc + call $~lib/rt/stub/__retain + local.set $0 + end + local.get $0 + local.get $1 + i32.store + local.get $0 + ) + (func $function-expression/testField~anonymous|0~anonymous|0 (param $0 i32) (result i32) + i32.const 24 + local.get $0 + i32.add + ) + (func $function-expression/testField~anonymous|0 (result i32) + (local $0 i32) + i32.const 16 + local.set $0 + local.get $0 + ) + (func $~lib/rt/stub/__release (param $0 i32) + nop + ) + (func $function-expression/testField + (local $0 i32) + (local $1 i32) + i32.const 0 + i32.const 17 + call $function-expression/FieldClass#constructor + local.set $0 + i32.const 1 + i32.const 0 + global.set $~argumentsLength + local.get $0 + i32.load + call_indirect (type $none_=>_i32) + local.set $1 + i32.const 1 + global.set $~argumentsLength + local.get $1 + call_indirect (type $i32_=>_i32) + i32.const 25 + i32.eq + i32.eqz + if + i32.const 0 + i32.const 32 + i32.const 82 + i32.const 3 + call $~lib/builtins/abort + unreachable + end + local.get $0 + call $~lib/rt/stub/__release + ) (func $start:function-expression i32.const 1 i32.const 1 @@ -236,6 +489,19 @@ call $~lib/builtins/abort unreachable end + call $function-expression/testGlobal + call $function-expression/testLocal + global.get $~lib/heap/__heap_base + i32.const 15 + i32.add + i32.const 15 + i32.const -1 + i32.xor + i32.and + global.set $~lib/rt/stub/startOffset + global.get $~lib/rt/stub/startOffset + global.set $~lib/rt/stub/offset + call $function-expression/testField ) (func $~start call $start:function-expression