mirror of
https://github.com/fluencelabs/assemblyscript
synced 2025-04-25 07:02:13 +00:00
Support calling the result of a getter (#252)
This commit is contained in:
parent
c27b6e8951
commit
3605630747
@ -5152,7 +5152,7 @@ export class Compiler extends DiagnosticEmitter {
|
||||
} else {
|
||||
this.error(
|
||||
DiagnosticCode.Cannot_invoke_an_expression_whose_type_lacks_a_call_signature_Type_0_has_no_compatible_call_signatures,
|
||||
expression.range, (<Field>target).type.toString()
|
||||
expression.range, type.toString()
|
||||
);
|
||||
return module.createUnreachable();
|
||||
}
|
||||
@ -5167,7 +5167,20 @@ export class Compiler extends DiagnosticEmitter {
|
||||
);
|
||||
break;
|
||||
}
|
||||
case ElementKind.PROPERTY: // TODO
|
||||
|
||||
case ElementKind.PROPERTY: {
|
||||
indexArg = this.compileGetter(<Property>target, expression.expression);
|
||||
let type = this.currentType;
|
||||
signature = type.signatureReference;
|
||||
if (!signature) {
|
||||
this.error(
|
||||
DiagnosticCode.Cannot_invoke_an_expression_whose_type_lacks_a_call_signature_Type_0_has_no_compatible_call_signatures,
|
||||
expression.range, type.toString()
|
||||
);
|
||||
return module.createUnreachable();
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
// not supported
|
||||
default: {
|
||||
@ -6711,43 +6724,8 @@ export class Compiler extends DiagnosticEmitter {
|
||||
(<Field>target).memoryOffset
|
||||
);
|
||||
}
|
||||
case ElementKind.PROPERTY: { // instance property (here: getter)
|
||||
let prototype = (<Property>target).getterPrototype;
|
||||
if (prototype) {
|
||||
let instance = this.resolver.resolveFunction(prototype, null);
|
||||
if (!instance) return module.createUnreachable();
|
||||
let signature = instance.signature;
|
||||
if (!this.checkCallSignature( // reports
|
||||
signature,
|
||||
0,
|
||||
instance.is(CommonFlags.INSTANCE),
|
||||
propertyAccess
|
||||
)) {
|
||||
return module.createUnreachable();
|
||||
}
|
||||
let inline = (instance.decoratorFlags & DecoratorFlags.INLINE) != 0;
|
||||
if (instance.is(CommonFlags.INSTANCE)) {
|
||||
let parent = assert(instance.parent);
|
||||
assert(parent.kind == ElementKind.CLASS);
|
||||
let thisExpression = assert(this.resolver.currentThisExpression);
|
||||
let thisExpr = this.compileExpressionRetainType(
|
||||
thisExpression,
|
||||
this.options.usizeType,
|
||||
WrapMode.NONE
|
||||
);
|
||||
this.currentType = signature.returnType;
|
||||
return this.compileCallDirect(instance, [], propertyAccess, thisExpr, inline);
|
||||
} else {
|
||||
this.currentType = signature.returnType;
|
||||
return this.compileCallDirect(instance, [], propertyAccess, 0, inline);
|
||||
}
|
||||
} else {
|
||||
this.error(
|
||||
DiagnosticCode.Property_0_does_not_exist_on_type_1,
|
||||
propertyAccess.range, (<Property>target).simpleName, (<Property>target).parent.toString()
|
||||
);
|
||||
return module.createUnreachable();
|
||||
}
|
||||
case ElementKind.PROPERTY: {// instance property (here: getter)
|
||||
return this.compileGetter(<Property>target, propertyAccess);
|
||||
}
|
||||
}
|
||||
this.error(
|
||||
@ -6757,6 +6735,45 @@ export class Compiler extends DiagnosticEmitter {
|
||||
return module.createUnreachable();
|
||||
}
|
||||
|
||||
private compileGetter(target: Property, reportNode: Node): ExpressionRef {
|
||||
var prototype = target.getterPrototype;
|
||||
if (prototype) {
|
||||
let instance = this.resolver.resolveFunction(prototype, null);
|
||||
if (!instance) return this.module.createUnreachable();
|
||||
let signature = instance.signature;
|
||||
if (!this.checkCallSignature( // reports
|
||||
signature,
|
||||
0,
|
||||
instance.is(CommonFlags.INSTANCE),
|
||||
reportNode
|
||||
)) {
|
||||
return this.module.createUnreachable();
|
||||
}
|
||||
let inline = (instance.decoratorFlags & DecoratorFlags.INLINE) != 0;
|
||||
if (instance.is(CommonFlags.INSTANCE)) {
|
||||
let parent = assert(instance.parent);
|
||||
assert(parent.kind == ElementKind.CLASS);
|
||||
let thisExpression = assert(this.resolver.currentThisExpression); //!!!
|
||||
let thisExpr = this.compileExpressionRetainType(
|
||||
thisExpression,
|
||||
this.options.usizeType,
|
||||
WrapMode.NONE
|
||||
);
|
||||
this.currentType = signature.returnType;
|
||||
return this.compileCallDirect(instance, [], reportNode, thisExpr, inline);
|
||||
} else {
|
||||
this.currentType = signature.returnType;
|
||||
return this.compileCallDirect(instance, [], reportNode, 0, inline);
|
||||
}
|
||||
} else {
|
||||
this.error(
|
||||
DiagnosticCode.Property_0_does_not_exist_on_type_1,
|
||||
reportNode.range, (<Property>target).simpleName, (<Property>target).parent.toString()
|
||||
);
|
||||
return this.module.createUnreachable();
|
||||
}
|
||||
}
|
||||
|
||||
compileTernaryExpression(expression: TernaryExpression, contextualType: Type): ExpressionRef {
|
||||
var ifThen = expression.ifThen;
|
||||
var ifElse = expression.ifElse;
|
||||
|
13
tests/compiler/getter-call.ts
Normal file
13
tests/compiler/getter-call.ts
Normal file
@ -0,0 +1,13 @@
|
||||
import "allocator/arena";
|
||||
|
||||
class C {
|
||||
get x(): () => i32 {
|
||||
return (): i32 => 42;
|
||||
}
|
||||
}
|
||||
|
||||
export function test(): i32 {
|
||||
// TODO: GH#251 return new C().x();
|
||||
let c = new C();
|
||||
return c.x();
|
||||
}
|
182
tests/compiler/getter-call.untouched.wat
Normal file
182
tests/compiler/getter-call.untouched.wat
Normal file
@ -0,0 +1,182 @@
|
||||
(module
|
||||
(type $i (func (result i32)))
|
||||
(type $ii (func (param i32) (result i32)))
|
||||
(type $v (func))
|
||||
(global $~lib/internal/allocator/AL_BITS i32 (i32.const 3))
|
||||
(global $~lib/internal/allocator/AL_SIZE i32 (i32.const 8))
|
||||
(global $~lib/internal/allocator/AL_MASK i32 (i32.const 7))
|
||||
(global $~lib/internal/allocator/MAX_SIZE_32 i32 (i32.const 1073741824))
|
||||
(global $~lib/allocator/arena/startOffset (mut i32) (i32.const 0))
|
||||
(global $~lib/allocator/arena/offset (mut i32) (i32.const 0))
|
||||
(global $~argc (mut i32) (i32.const 0))
|
||||
(global $HEAP_BASE i32 (i32.const 8))
|
||||
(table 1 1 anyfunc)
|
||||
(elem (i32.const 0) $getter-call/C#get:x~anonymous|0)
|
||||
(memory $0 0)
|
||||
(export "memory" (memory $0))
|
||||
(export "table" (table $0))
|
||||
(export "test" (func $getter-call/test))
|
||||
(start $start)
|
||||
(func $~lib/allocator/arena/__memory_allocate (; 0 ;) (type $ii) (param $0 i32) (result i32)
|
||||
(local $1 i32)
|
||||
(local $2 i32)
|
||||
(local $3 i32)
|
||||
(local $4 i32)
|
||||
(local $5 i32)
|
||||
(local $6 i32)
|
||||
(if
|
||||
(i32.gt_u
|
||||
(get_local $0)
|
||||
(get_global $~lib/internal/allocator/MAX_SIZE_32)
|
||||
)
|
||||
(unreachable)
|
||||
)
|
||||
(set_local $1
|
||||
(get_global $~lib/allocator/arena/offset)
|
||||
)
|
||||
(set_local $4
|
||||
(i32.and
|
||||
(i32.add
|
||||
(i32.add
|
||||
(get_local $1)
|
||||
(select
|
||||
(tee_local $2
|
||||
(get_local $0)
|
||||
)
|
||||
(tee_local $3
|
||||
(i32.const 1)
|
||||
)
|
||||
(i32.gt_u
|
||||
(get_local $2)
|
||||
(get_local $3)
|
||||
)
|
||||
)
|
||||
)
|
||||
(get_global $~lib/internal/allocator/AL_MASK)
|
||||
)
|
||||
(i32.xor
|
||||
(get_global $~lib/internal/allocator/AL_MASK)
|
||||
(i32.const -1)
|
||||
)
|
||||
)
|
||||
)
|
||||
(set_local $5
|
||||
(current_memory)
|
||||
)
|
||||
(if
|
||||
(i32.gt_u
|
||||
(get_local $4)
|
||||
(i32.shl
|
||||
(get_local $5)
|
||||
(i32.const 16)
|
||||
)
|
||||
)
|
||||
(block
|
||||
(set_local $2
|
||||
(i32.shr_u
|
||||
(i32.and
|
||||
(i32.add
|
||||
(i32.sub
|
||||
(get_local $4)
|
||||
(get_local $1)
|
||||
)
|
||||
(i32.const 65535)
|
||||
)
|
||||
(i32.xor
|
||||
(i32.const 65535)
|
||||
(i32.const -1)
|
||||
)
|
||||
)
|
||||
(i32.const 16)
|
||||
)
|
||||
)
|
||||
(set_local $3
|
||||
(select
|
||||
(tee_local $3
|
||||
(get_local $5)
|
||||
)
|
||||
(tee_local $6
|
||||
(get_local $2)
|
||||
)
|
||||
(i32.gt_s
|
||||
(get_local $3)
|
||||
(get_local $6)
|
||||
)
|
||||
)
|
||||
)
|
||||
(if
|
||||
(i32.lt_s
|
||||
(grow_memory
|
||||
(get_local $3)
|
||||
)
|
||||
(i32.const 0)
|
||||
)
|
||||
(if
|
||||
(i32.lt_s
|
||||
(grow_memory
|
||||
(get_local $2)
|
||||
)
|
||||
(i32.const 0)
|
||||
)
|
||||
(unreachable)
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
(set_global $~lib/allocator/arena/offset
|
||||
(get_local $4)
|
||||
)
|
||||
(get_local $1)
|
||||
)
|
||||
(func $~lib/memory/memory.allocate (; 1 ;) (type $ii) (param $0 i32) (result i32)
|
||||
(return
|
||||
(call $~lib/allocator/arena/__memory_allocate
|
||||
(get_local $0)
|
||||
)
|
||||
)
|
||||
)
|
||||
(func $getter-call/C#get:x~anonymous|0 (; 2 ;) (type $i) (result i32)
|
||||
(i32.const 42)
|
||||
)
|
||||
(func $getter-call/C#get:x (; 3 ;) (type $ii) (param $0 i32) (result i32)
|
||||
(i32.const 0)
|
||||
)
|
||||
(func $getter-call/test (; 4 ;) (type $i) (result i32)
|
||||
(local $0 i32)
|
||||
(set_local $0
|
||||
(block (result i32)
|
||||
(set_local $0
|
||||
(call $~lib/memory/memory.allocate
|
||||
(i32.const 0)
|
||||
)
|
||||
)
|
||||
(get_local $0)
|
||||
)
|
||||
)
|
||||
(set_global $~argc
|
||||
(i32.const 0)
|
||||
)
|
||||
(call_indirect (type $i)
|
||||
(call $getter-call/C#get:x
|
||||
(get_local $0)
|
||||
)
|
||||
)
|
||||
)
|
||||
(func $start (; 5 ;) (type $v)
|
||||
(set_global $~lib/allocator/arena/startOffset
|
||||
(i32.and
|
||||
(i32.add
|
||||
(get_global $HEAP_BASE)
|
||||
(get_global $~lib/internal/allocator/AL_MASK)
|
||||
)
|
||||
(i32.xor
|
||||
(get_global $~lib/internal/allocator/AL_MASK)
|
||||
(i32.const -1)
|
||||
)
|
||||
)
|
||||
)
|
||||
(set_global $~lib/allocator/arena/offset
|
||||
(get_global $~lib/allocator/arena/startOffset)
|
||||
)
|
||||
)
|
||||
)
|
Loading…
x
Reference in New Issue
Block a user