Skip to content

Commit a71f649

Browse files
authored
fix: Simplify compileCallExpression (#2558)
1 parent a150a49 commit a71f649

File tree

8 files changed

+376
-208
lines changed

8 files changed

+376
-208
lines changed

src/compiler.ts

Lines changed: 26 additions & 122 deletions
Original file line numberDiff line numberDiff line change
@@ -5990,11 +5990,8 @@ export class Compiler extends DiagnosticEmitter {
59905990
if (!target) return module.unreachable();
59915991
let thisExpression = this.resolver.currentThisExpression;
59925992

5993-
let signature: Signature | null;
5994-
let functionArg: ExpressionRef;
5993+
// handle direct call
59955994
switch (target.kind) {
5996-
5997-
// direct call: concrete function
59985995
case ElementKind.FunctionPrototype: {
59995996
let functionPrototype = <FunctionPrototype>target;
60005997
if (functionPrototype.hasDecorator(DecoratorFlags.Builtin)) {
@@ -6024,128 +6021,35 @@ export class Compiler extends DiagnosticEmitter {
60246021
constraints
60256022
);
60266023
}
6024+
}
60276025

6028-
// indirect call: first-class function (non-generic, can't be inlined)
6029-
case ElementKind.Local: {
6030-
let local = <Local>target;
6031-
signature = local.type.signatureReference;
6032-
if (signature) {
6033-
if (local.parent != flow.targetFunction) {
6034-
// TODO: closures
6035-
this.error(
6036-
DiagnosticCode.Not_implemented_0,
6037-
expression.range,
6038-
"Closures"
6039-
);
6040-
return module.unreachable();
6041-
}
6042-
if (local.is(CommonFlags.Inlined)) {
6043-
let inlinedValue = local.constantIntegerValue;
6044-
if (this.options.isWasm64) {
6045-
functionArg = module.i64(i64_low(inlinedValue), i64_high(inlinedValue));
6046-
} else {
6047-
assert(!i64_high(inlinedValue));
6048-
functionArg = module.i32(i64_low(inlinedValue));
6049-
}
6050-
} else {
6051-
functionArg = module.local_get(local.index, this.options.sizeTypeRef);
6052-
}
6053-
break;
6054-
}
6055-
this.error(
6056-
DiagnosticCode.Cannot_invoke_an_expression_whose_type_lacks_a_call_signature_Type_0_has_no_compatible_call_signatures,
6057-
expression.range, local.type.toString()
6058-
);
6059-
return module.unreachable();
6060-
}
6061-
case ElementKind.Global: {
6062-
let global = <Global>target;
6063-
signature = global.type.signatureReference;
6064-
if (signature) {
6065-
functionArg = module.global_get(global.internalName, global.type.toRef());
6066-
break;
6067-
}
6068-
this.error(
6069-
DiagnosticCode.Cannot_invoke_an_expression_whose_type_lacks_a_call_signature_Type_0_has_no_compatible_call_signatures,
6070-
expression.range, global.type.toString()
6026+
// handle indirect call
6027+
let functionArg = this.compileExpression(expression.expression, Type.auto);
6028+
let signature = this.currentType.getSignature();
6029+
if (signature) {
6030+
return this.compileCallIndirect(
6031+
signature,
6032+
functionArg,
6033+
expression.args,
6034+
expression,
6035+
0,
6036+
contextualType == Type.void
6037+
);
6038+
}
6039+
this.error(
6040+
DiagnosticCode.Cannot_invoke_an_expression_whose_type_lacks_a_call_signature_Type_0_has_no_compatible_call_signatures,
6041+
expression.range, this.currentType.toString()
6042+
);
6043+
if (target.kind == ElementKind.PropertyPrototype) {
6044+
let getterPrototype = (<PropertyPrototype>target).getterPrototype;
6045+
if (getterPrototype) {
6046+
this.infoRelated(
6047+
DiagnosticCode.This_expression_is_not_callable_because_it_is_a_get_accessor_Did_you_mean_to_use_it_without,
6048+
expression.range, getterPrototype.identifierNode.range
60716049
);
6072-
return module.unreachable();
6073-
}
6074-
case ElementKind.PropertyPrototype: {
6075-
let propertyInstance = this.resolver.resolveProperty(<PropertyPrototype>target);
6076-
if (!propertyInstance) return module.unreachable();
6077-
target = propertyInstance;
6078-
// fall-through
6079-
}
6080-
case ElementKind.Property: {
6081-
let propertyInstance = <Property>target;
6082-
let getterInstance = propertyInstance.getterInstance;
6083-
let type = assert(this.resolver.getTypeOfElement(target));
6084-
6085-
if (!getterInstance) {
6086-
this.error(
6087-
DiagnosticCode.Cannot_invoke_an_expression_whose_type_lacks_a_call_signature_Type_0_has_no_compatible_call_signatures,
6088-
expression.range, type.toString()
6089-
);
6090-
return module.unreachable();
6091-
}
6092-
6093-
let thisArg: ExpressionRef = 0;
6094-
if (propertyInstance.is(CommonFlags.Instance)) {
6095-
thisArg = this.compileExpression(
6096-
assert(thisExpression),
6097-
assert(getterInstance.signature.thisType),
6098-
Constraints.ConvImplicit | Constraints.IsThis
6099-
);
6100-
}
6101-
functionArg = this.compileCallDirect(getterInstance, [], expression.expression, thisArg);
6102-
signature = this.currentType.signatureReference;
6103-
if (!signature) {
6104-
this.error(
6105-
DiagnosticCode.Cannot_invoke_an_expression_whose_type_lacks_a_call_signature_Type_0_has_no_compatible_call_signatures,
6106-
expression.range, this.currentType.toString()
6107-
);
6108-
return module.unreachable();
6109-
}
6110-
break;
6111-
}
6112-
case ElementKind.Class: {
6113-
let classInstance = <Class>target;
6114-
let typeArguments = classInstance.getTypeArgumentsTo(this.program.functionPrototype);
6115-
if (typeArguments && typeArguments.length > 0) {
6116-
let ftype = typeArguments[0];
6117-
signature = ftype.getSignature();
6118-
functionArg = this.compileExpression(expression.expression, ftype, Constraints.ConvImplicit);
6119-
break;
6120-
}
6121-
// fall-through
6122-
}
6123-
6124-
// not supported
6125-
default: {
6126-
let type = this.resolver.getTypeOfElement(target);
6127-
if (type) {
6128-
this.error(
6129-
DiagnosticCode.Type_0_has_no_call_signatures,
6130-
expression.range, type.toString()
6131-
);
6132-
} else {
6133-
this.error(
6134-
DiagnosticCode.Expression_cannot_be_represented_by_a_type,
6135-
expression.range
6136-
);
6137-
}
6138-
return module.unreachable();
61396050
}
61406051
}
6141-
return this.compileCallIndirect(
6142-
assert(signature), // FIXME: bootstrap can't see this yet
6143-
functionArg,
6144-
expression.args,
6145-
expression,
6146-
0,
6147-
contextualType == Type.void
6148-
);
6052+
return module.unreachable();
61496053
}
61506054

61516055
/** Compiles the given arguments like a call expression according to the specified context. */

src/diagnosticMessages.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -199,6 +199,7 @@
199199
"File '{0}' not found.": 6054,
200200
"Numeric separators are not allowed here.": 6188,
201201
"Multiple consecutive numeric separators are not permitted.": 6189,
202+
"This expression is not callable because it is a 'get' accessor. Did you mean to use it without '()'?": 6234,
202203
"'super' must be called before accessing 'this' in the constructor of a derived class.": 17009,
203204
"'super' must be called before accessing a property of 'super' in the constructor of a derived class.": 17011
204205
}

src/resolver.ts

Lines changed: 15 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -2441,35 +2441,32 @@ export class Resolver extends DiagnosticEmitter {
24412441
) {
24422442
return this.resolveExpression(node.args[0], ctxFlow, ctxType, reportMode);
24432443
}
2444-
let instance = this.maybeInferCall(node, functionPrototype, ctxFlow, reportMode);
2445-
if (!instance) return null;
2446-
return instance.signature.returnType;
2444+
let functionInstance = this.maybeInferCall(node, functionPrototype, ctxFlow, reportMode);
2445+
if (!functionInstance) return null;
2446+
target = functionInstance;
2447+
// fall-through
2448+
}
2449+
case ElementKind.Function: {
2450+
return (<Function>target).signature.returnType;
24472451
}
24482452
case ElementKind.PropertyPrototype: {
24492453
let propertyInstance = this.resolveProperty(<PropertyPrototype>target, reportMode);
24502454
if (!propertyInstance) return null;
24512455
target = propertyInstance;
24522456
// fall-through
24532457
}
2454-
case ElementKind.Global:
2455-
case ElementKind.Local:
2456-
case ElementKind.Property: {
2457-
let varType = (<VariableLikeElement>target).type;
2458-
let varElement = this.getElementOfType(varType);
2459-
if (!varElement || varElement.kind != ElementKind.Class) {
2460-
break;
2461-
}
2462-
target = varElement;
2458+
default: {
2459+
if (!isTypedElement(target.kind)) break;
2460+
let targetElement = this.getElementOfType((<TypedElement>target).type);
2461+
if (!targetElement || targetElement.kind != ElementKind.Class) break;
2462+
target = targetElement;
24632463
// fall-through
24642464
}
24652465
case ElementKind.Class: {
24662466
let typeArguments = (<Class>target).getTypeArgumentsTo(this.program.functionPrototype);
2467-
if (typeArguments && typeArguments.length > 0) {
2468-
let ftype = typeArguments[0];
2469-
let signatureReference = assert(ftype.signatureReference);
2470-
return signatureReference.returnType;
2471-
}
2472-
break;
2467+
if (!(typeArguments && typeArguments.length)) break;
2468+
let signature = assert(typeArguments[0].getSignature());
2469+
return signature.returnType;
24732470
}
24742471
}
24752472
if (reportMode == ReportMode.Report) {

tests/compiler/assert-nonnull.debug.wat

Lines changed: 86 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -69,24 +69,28 @@
6969
i32.load $0 offset=4
7070
)
7171
(func $assert-nonnull/testFn (type $i32_=>_i32) (param $fn i32) (result i32)
72+
(local $1 i32)
7273
i32.const 0
7374
global.set $~argumentsLength
7475
local.get $fn
76+
local.tee $1
77+
if (result i32)
78+
local.get $1
79+
else
80+
i32.const 32
81+
i32.const 96
82+
i32.const 35
83+
i32.const 10
84+
call $~lib/builtins/abort
85+
unreachable
86+
end
7587
i32.load $0
7688
call_indirect $0 (type $none_=>_i32)
7789
)
7890
(func $assert-nonnull/Foo#get:baz (type $i32_=>_i32) (param $this i32) (result i32)
7991
local.get $this
8092
i32.load $0 offset=4
8193
)
82-
(func $assert-nonnull/testObjFn (type $i32_=>_i32) (param $foo i32) (result i32)
83-
i32.const 0
84-
global.set $~argumentsLength
85-
local.get $foo
86-
call $assert-nonnull/Foo#get:baz
87-
i32.load $0
88-
call_indirect $0 (type $none_=>_i32)
89-
)
9094
(func $~stack_check (type $none_=>_none)
9195
global.get $~lib/memory/__stack_pointer
9296
global.get $~lib/memory/__data_end
@@ -538,6 +542,7 @@
538542
(func $assert-nonnull/testRet (type $i32_=>_i32) (param $fn i32) (result i32)
539543
(local $1 i32)
540544
(local $2 i32)
545+
(local $3 i32)
541546
global.get $~lib/memory/__stack_pointer
542547
i32.const 4
543548
i32.sub
@@ -550,8 +555,55 @@
550555
i32.const 0
551556
global.set $~argumentsLength
552557
local.get $fn
558+
local.tee $1
559+
if (result i32)
560+
local.get $1
561+
else
562+
i32.const 32
563+
i32.const 96
564+
i32.const 44
565+
i32.const 10
566+
call $~lib/builtins/abort
567+
unreachable
568+
end
553569
i32.load $0
554570
call_indirect $0 (type $none_=>_i32)
571+
local.tee $2
572+
i32.store $0
573+
local.get $2
574+
if (result i32)
575+
local.get $2
576+
else
577+
i32.const 32
578+
i32.const 96
579+
i32.const 44
580+
i32.const 10
581+
call $~lib/builtins/abort
582+
unreachable
583+
end
584+
local.set $3
585+
global.get $~lib/memory/__stack_pointer
586+
i32.const 4
587+
i32.add
588+
global.set $~lib/memory/__stack_pointer
589+
local.get $3
590+
)
591+
(func $assert-nonnull/testObjFn (type $i32_=>_i32) (param $foo i32) (result i32)
592+
(local $1 i32)
593+
(local $2 i32)
594+
global.get $~lib/memory/__stack_pointer
595+
i32.const 4
596+
i32.sub
597+
global.set $~lib/memory/__stack_pointer
598+
call $~stack_check
599+
global.get $~lib/memory/__stack_pointer
600+
i32.const 0
601+
i32.store $0
602+
i32.const 0
603+
global.set $~argumentsLength
604+
global.get $~lib/memory/__stack_pointer
605+
local.get $foo
606+
call $assert-nonnull/Foo#get:baz
555607
local.tee $1
556608
i32.store $0
557609
local.get $1
@@ -560,11 +612,13 @@
560612
else
561613
i32.const 32
562614
i32.const 96
563-
i32.const 44
615+
i32.const 48
564616
i32.const 10
565617
call $~lib/builtins/abort
566618
unreachable
567619
end
620+
i32.load $0
621+
call_indirect $0 (type $none_=>_i32)
568622
local.set $2
569623
global.get $~lib/memory/__stack_pointer
570624
i32.const 4
@@ -575,21 +629,21 @@
575629
(func $assert-nonnull/testObjRet (type $i32_=>_i32) (param $foo i32) (result i32)
576630
(local $1 i32)
577631
(local $2 i32)
632+
(local $3 i32)
578633
global.get $~lib/memory/__stack_pointer
579-
i32.const 4
634+
i32.const 8
580635
i32.sub
581636
global.set $~lib/memory/__stack_pointer
582637
call $~stack_check
583638
global.get $~lib/memory/__stack_pointer
584-
i32.const 0
585-
i32.store $0
639+
i64.const 0
640+
i64.store $0
586641
global.get $~lib/memory/__stack_pointer
587642
i32.const 0
588643
global.set $~argumentsLength
644+
global.get $~lib/memory/__stack_pointer
589645
local.get $foo
590646
call $assert-nonnull/Foo#get:baz
591-
i32.load $0
592-
call_indirect $0 (type $none_=>_i32)
593647
local.tee $1
594648
i32.store $0
595649
local.get $1
@@ -603,12 +657,27 @@
603657
call $~lib/builtins/abort
604658
unreachable
605659
end
606-
local.set $2
660+
i32.load $0
661+
call_indirect $0 (type $none_=>_i32)
662+
local.tee $2
663+
i32.store $0 offset=4
664+
local.get $2
665+
if (result i32)
666+
local.get $2
667+
else
668+
i32.const 32
669+
i32.const 96
670+
i32.const 52
671+
i32.const 10
672+
call $~lib/builtins/abort
673+
unreachable
674+
end
675+
local.set $3
607676
global.get $~lib/memory/__stack_pointer
608-
i32.const 4
677+
i32.const 8
609678
i32.add
610679
global.set $~lib/memory/__stack_pointer
611-
local.get $2
680+
local.get $3
612681
)
613682
(func $export:assert-nonnull/testVar (type $i32_=>_i32) (param $0 i32) (result i32)
614683
(local $1 i32)

0 commit comments

Comments
 (0)