@@ -1811,7 +1811,6 @@ export class Compiler extends DiagnosticEmitter {
1811
1811
}
1812
1812
}
1813
1813
if ( ! isInlined ) {
1814
- let flow = currentFunction . flow ;
1815
1814
if (
1816
1815
declaration . isAny ( CommonFlags . LET | CommonFlags . CONST ) ||
1817
1816
flow . is ( FlowFlags . INLINE_CONTEXT )
@@ -4404,55 +4403,131 @@ export class Compiler extends DiagnosticEmitter {
4404
4403
// direct call: concrete function
4405
4404
case ElementKind . FUNCTION_PROTOTYPE : {
4406
4405
let prototype = < FunctionPrototype > target ;
4406
+ let typeArguments = expression . typeArguments ;
4407
4407
4408
- // builtins are compiled on the fly
4408
+ // builtins handle present respectively omitted type arguments on their own
4409
4409
if ( prototype . is ( CommonFlags . AMBIENT | CommonFlags . BUILTIN ) ) {
4410
- let expr = compileBuiltinCall ( // reports
4411
- this ,
4412
- prototype ,
4413
- prototype . resolveBuiltinTypeArguments (
4414
- expression . typeArguments ,
4415
- currentFunction . flow . contextualTypeArguments
4416
- ) ,
4417
- expression . arguments ,
4418
- contextualType ,
4419
- expression
4420
- ) ;
4421
- if ( ! expr ) {
4410
+ return this . compileCallExpressionBuiltin ( prototype , expression , contextualType ) ;
4411
+ }
4412
+
4413
+ let instance : Function | null = null ;
4414
+
4415
+ // resolve generic call if type arguments have been provided
4416
+ if ( typeArguments ) {
4417
+ if ( ! prototype . is ( CommonFlags . GENERIC ) ) {
4422
4418
this . error (
4423
- DiagnosticCode . Operation_not_supported ,
4424
- expression . range
4419
+ DiagnosticCode . Type_0_is_not_generic ,
4420
+ expression . expression . range , prototype . internalName
4425
4421
) ;
4426
4422
return module . createUnreachable ( ) ;
4427
4423
}
4428
- return expr ;
4429
-
4430
- // otherwise compile to a call (and maybe inline)
4431
- } else {
4432
- let instance = prototype . resolveUsingTypeArguments ( // reports
4433
- expression . typeArguments ,
4434
- currentFunction . flow . contextualTypeArguments ,
4424
+ instance = prototype . resolveUsingTypeArguments ( // reports
4425
+ typeArguments ,
4426
+ this . currentFunction . flow . contextualTypeArguments ,
4435
4427
expression
4436
4428
) ;
4437
- if ( ! instance ) return module . createUnreachable ( ) ;
4438
- let thisExpr : ExpressionRef = 0 ;
4439
- if ( instance . is ( CommonFlags . INSTANCE ) ) {
4440
- thisExpr = this . compileExpressionRetainType (
4441
- assert ( this . program . resolvedThisExpression ) ,
4442
- this . options . usizeType
4443
- ) ;
4429
+
4430
+ // infer generic call if type arguments have been omitted
4431
+ } else if ( prototype . is ( CommonFlags . GENERIC ) ) {
4432
+ let inferredTypes = new Map < string , Type | null > ( ) ;
4433
+ let typeParameters = assert ( prototype . declaration . typeParameters ) ;
4434
+ let numTypeParameters = typeParameters . length ;
4435
+ for ( let i = 0 ; i < numTypeParameters ; ++ i ) {
4436
+ inferredTypes . set ( typeParameters [ i ] . name . text , null ) ;
4437
+ }
4438
+ // let numInferred = 0;
4439
+ let parameterTypes = prototype . declaration . signature . parameterTypes ;
4440
+ let numParameterTypes = parameterTypes . length ;
4441
+ let argumentExpressions = expression . arguments ;
4442
+ let numArguments = argumentExpressions . length ;
4443
+ let argumentExprs = new Array < ExpressionRef > ( numArguments ) ;
4444
+ for ( let i = 0 ; i < numParameterTypes ; ++ i ) {
4445
+ let typeNode = parameterTypes [ i ] . type ;
4446
+ let name = typeNode . kind == NodeKind . TYPE ? ( < TypeNode > typeNode ) . name . text : null ;
4447
+ let argumentExpression = i < numArguments
4448
+ ? argumentExpressions [ i ]
4449
+ : prototype . declaration . signature . parameterTypes [ i ] . initializer ;
4450
+ if ( ! argumentExpression ) { // missing initializer -> too few arguments
4451
+ this . error (
4452
+ DiagnosticCode . Expected_0_arguments_but_got_1 ,
4453
+ expression . range , numParameterTypes . toString ( 10 ) , numArguments . toString ( 10 )
4454
+ ) ;
4455
+ return module . createUnreachable ( ) ;
4456
+ }
4457
+ if ( name !== null && inferredTypes . has ( name ) ) {
4458
+ let inferredType = inferredTypes . get ( name ) ;
4459
+ if ( inferredType ) {
4460
+ argumentExprs [ i ] = this . compileExpressionRetainType ( argumentExpression , inferredType ) ;
4461
+ let commonType : Type | null ;
4462
+ if ( ! ( commonType = Type . commonCompatible ( inferredType , this . currentType , true ) ) ) {
4463
+ if ( ! ( commonType = Type . commonCompatible ( inferredType , this . currentType , false ) ) ) {
4464
+ this . error (
4465
+ DiagnosticCode . Type_0_is_not_assignable_to_type_1 ,
4466
+ parameterTypes [ i ] . type . range , this . currentType . toString ( ) , inferredType . toString ( )
4467
+ ) ;
4468
+ return module . createUnreachable ( ) ;
4469
+ }
4470
+ }
4471
+ inferredType = commonType ;
4472
+ } else {
4473
+ argumentExprs [ i ] = this . compileExpressionRetainType ( argumentExpression , Type . i32 ) ;
4474
+ inferredType = this . currentType ;
4475
+ // ++numInferred;
4476
+ }
4477
+ inferredTypes . set ( name , inferredType ) ;
4478
+ } else {
4479
+ let concreteType = this . program . resolveType (
4480
+ parameterTypes [ i ] . type ,
4481
+ this . currentFunction . flow . contextualTypeArguments ,
4482
+ true
4483
+ ) ;
4484
+ if ( ! concreteType ) return module . createUnreachable ( ) ;
4485
+ argumentExprs [ i ] = this . compileExpression ( argumentExpression , concreteType ) ;
4486
+ }
4444
4487
}
4445
- return this . compileCallDirect (
4446
- instance ,
4447
- expression . arguments ,
4448
- expression ,
4449
- thisExpr ,
4450
- instance . hasDecorator ( DecoratorFlags . INLINE )
4488
+ let resolvedTypeArguments = new Array < Type > ( numTypeParameters ) ;
4489
+ for ( let i = 0 ; i < numTypeParameters ; ++ i ) {
4490
+ let inferredType = assert ( inferredTypes . get ( typeParameters [ i ] . name . text ) ) ; // TODO
4491
+ resolvedTypeArguments [ i ] = inferredType ;
4492
+ }
4493
+ instance = prototype . resolve (
4494
+ resolvedTypeArguments ,
4495
+ this . currentFunction . flow . contextualTypeArguments
4496
+ ) ;
4497
+ if ( ! instance ) return this . module . createUnreachable ( ) ;
4498
+ return this . makeCallDirect ( instance , argumentExprs ) ;
4499
+ // TODO: this skips inlining because inlining requires compiling its temporary locals in
4500
+ // the scope of the inlined flow. might need another mechanism to lock temp. locals early,
4501
+ // so inlining can be performed in `makeCallDirect` instead?
4502
+
4503
+ // otherwise resolve the non-generic call as usual
4504
+ } else {
4505
+ instance = prototype . resolve (
4506
+ null ,
4507
+ this . currentFunction . flow . contextualTypeArguments
4508
+ ) ;
4509
+ }
4510
+ if ( ! instance ) return this . module . createUnreachable ( ) ;
4511
+
4512
+ // compile 'this' expression if an instance method
4513
+ let thisExpr : ExpressionRef = 0 ;
4514
+ if ( instance . is ( CommonFlags . INSTANCE ) ) {
4515
+ thisExpr = this . compileExpressionRetainType (
4516
+ assert ( this . program . resolvedThisExpression ) ,
4517
+ this . options . usizeType
4451
4518
) ;
4452
4519
}
4520
+
4521
+ return this . compileCallDirect (
4522
+ instance ,
4523
+ expression . arguments ,
4524
+ expression ,
4525
+ thisExpr ,
4526
+ instance . hasDecorator ( DecoratorFlags . INLINE )
4527
+ ) ;
4453
4528
}
4454
4529
4455
- // indirect call: index argument with signature
4530
+ // indirect call: index argument with signature (non-generic, can't be inlined)
4456
4531
case ElementKind . LOCAL : {
4457
4532
if ( signature = ( < Local > target ) . type . signatureReference ) {
4458
4533
indexArg = module . createGetLocal ( ( < Local > target ) . index , NativeType . I32 ) ;
@@ -4525,6 +4600,32 @@ export class Compiler extends DiagnosticEmitter {
4525
4600
) ;
4526
4601
}
4527
4602
4603
+ private compileCallExpressionBuiltin (
4604
+ prototype : FunctionPrototype ,
4605
+ expression : CallExpression ,
4606
+ contextualType : Type
4607
+ ) : ExpressionRef {
4608
+ var expr = compileBuiltinCall ( // reports
4609
+ this ,
4610
+ prototype ,
4611
+ prototype . resolveBuiltinTypeArguments (
4612
+ expression . typeArguments ,
4613
+ this . currentFunction . flow . contextualTypeArguments
4614
+ ) ,
4615
+ expression . arguments ,
4616
+ contextualType ,
4617
+ expression
4618
+ ) ;
4619
+ if ( ! expr ) {
4620
+ this . error (
4621
+ DiagnosticCode . Operation_not_supported ,
4622
+ expression . range
4623
+ ) ;
4624
+ return this . module . createUnreachable ( ) ;
4625
+ }
4626
+ return expr ;
4627
+ }
4628
+
4528
4629
/**
4529
4630
* Checks that a call with the given number as arguments can be performed according to the
4530
4631
* specified signature.
0 commit comments