@@ -3429,7 +3429,7 @@ export class Compiler extends DiagnosticEmitter {
3429
3429
break ;
3430
3430
}
3431
3431
case NodeKind . FUNCTION : {
3432
- expr = this . compileFunctionExpression ( < FunctionExpression > expression , contextualType . signatureReference , constraints ) ;
3432
+ expr = this . compileFunctionExpression ( < FunctionExpression > expression , contextualType , constraints ) ;
3433
3433
break ;
3434
3434
}
3435
3435
case NodeKind . IDENTIFIER :
@@ -7311,26 +7311,30 @@ export class Compiler extends DiagnosticEmitter {
7311
7311
7312
7312
private compileFunctionExpression (
7313
7313
expression : FunctionExpression ,
7314
- contextualSignature : Signature | null ,
7314
+ contextualType : Type ,
7315
7315
constraints : Constraints
7316
7316
) : ExpressionRef {
7317
7317
var declaration = expression . declaration . clone ( ) ; // generic contexts can have multiple
7318
7318
assert ( ! declaration . typeParameters ) ; // function expression cannot be generic
7319
7319
var flow = this . currentFlow ;
7320
7320
var actualFunction = flow . actualFunction ;
7321
+ var isNamed = declaration . name . text . length > 0 ;
7322
+ var isSemanticallyAnonymous = ! isNamed || contextualType != Type . void ;
7321
7323
var prototype = new FunctionPrototype (
7322
- declaration . name . text . length
7323
- ? declaration . name . text
7324
- : "anonymous|" + ( actualFunction . nextAnonymousId ++ ) . toString ( ) ,
7324
+ isSemanticallyAnonymous
7325
+ ? ( isNamed ? declaration . name . text + "|" : "anonymous|" ) + ( actualFunction . nextAnonymousId ++ ) . toString ( )
7326
+ : declaration . name . text ,
7325
7327
actualFunction ,
7326
7328
declaration ,
7327
7329
DecoratorFlags . NONE
7328
7330
) ;
7329
7331
var instance : Function | null ;
7330
7332
var contextualTypeArguments = uniqueMap ( flow . contextualTypeArguments ) ;
7333
+ var module = this . module ;
7331
7334
7332
7335
// compile according to context. this differs from a normal function in that omitted parameter
7333
7336
// and return types can be inferred and omitted arguments can be replaced with dummies.
7337
+ var contextualSignature = contextualType . signatureReference ;
7334
7338
if ( contextualSignature ) {
7335
7339
let signatureNode = prototype . functionTypeNode ;
7336
7340
let parameterNodes = signatureNode . parameters ;
@@ -7344,7 +7348,7 @@ export class Compiler extends DiagnosticEmitter {
7344
7348
DiagnosticCode . Expected_0_arguments_but_got_1 ,
7345
7349
expression . range , numParameters . toString ( ) , numPresentParameters . toString ( )
7346
7350
) ;
7347
- return this . module . unreachable ( ) ;
7351
+ return module . unreachable ( ) ;
7348
7352
}
7349
7353
7350
7354
// check non-omitted parameter types
@@ -7356,13 +7360,13 @@ export class Compiler extends DiagnosticEmitter {
7356
7360
actualFunction . parent ,
7357
7361
contextualTypeArguments
7358
7362
) ;
7359
- if ( ! resolvedType ) return this . module . unreachable ( ) ;
7363
+ if ( ! resolvedType ) return module . unreachable ( ) ;
7360
7364
if ( ! parameterTypes [ i ] . isStrictlyAssignableTo ( resolvedType ) ) {
7361
7365
this . error (
7362
7366
DiagnosticCode . Type_0_is_not_assignable_to_type_1 ,
7363
7367
parameterNode . range , parameterTypes [ i ] . toString ( ) , resolvedType . toString ( )
7364
7368
) ;
7365
- return this . module . unreachable ( ) ;
7369
+ return module . unreachable ( ) ;
7366
7370
}
7367
7371
}
7368
7372
// any unused parameters are inherited but ignored
@@ -7376,7 +7380,7 @@ export class Compiler extends DiagnosticEmitter {
7376
7380
actualFunction . parent ,
7377
7381
contextualTypeArguments
7378
7382
) ;
7379
- if ( ! resolvedType ) return this . module . unreachable ( ) ;
7383
+ if ( ! resolvedType ) return module . unreachable ( ) ;
7380
7384
if (
7381
7385
returnType == Type . void
7382
7386
? resolvedType != Type . void
@@ -7386,7 +7390,7 @@ export class Compiler extends DiagnosticEmitter {
7386
7390
DiagnosticCode . Type_0_is_not_assignable_to_type_1 ,
7387
7391
signatureNode . returnType . range , resolvedType . toString ( ) , returnType . toString ( )
7388
7392
) ;
7389
- return this . module . unreachable ( ) ;
7393
+ return module . unreachable ( ) ;
7390
7394
}
7391
7395
}
7392
7396
@@ -7399,20 +7403,20 @@ export class Compiler extends DiagnosticEmitter {
7399
7403
DiagnosticCode . _this_cannot_be_referenced_in_current_location ,
7400
7404
thisTypeNode . range
7401
7405
) ;
7402
- return this . module . unreachable ( ) ;
7406
+ return module . unreachable ( ) ;
7403
7407
}
7404
7408
let resolvedType = this . resolver . resolveType (
7405
7409
thisTypeNode ,
7406
7410
actualFunction . parent ,
7407
7411
contextualTypeArguments
7408
7412
) ;
7409
- if ( ! resolvedType ) return this . module . unreachable ( ) ;
7413
+ if ( ! resolvedType ) return module . unreachable ( ) ;
7410
7414
if ( ! thisType . isStrictlyAssignableTo ( resolvedType ) ) {
7411
7415
this . error (
7412
7416
DiagnosticCode . Type_0_is_not_assignable_to_type_1 ,
7413
7417
thisTypeNode . range , thisType . toString ( ) , resolvedType . toString ( )
7414
7418
) ;
7415
- return this . module . unreachable ( ) ;
7419
+ return module . unreachable ( ) ;
7416
7420
}
7417
7421
}
7418
7422
@@ -7428,7 +7432,7 @@ export class Compiler extends DiagnosticEmitter {
7428
7432
instance . flow . outer = flow ;
7429
7433
let worked = this . compileFunction ( instance ) ;
7430
7434
this . currentType = contextualSignature . type ;
7431
- if ( ! worked ) return this . module . unreachable ( ) ;
7435
+ if ( ! worked ) return module . unreachable ( ) ;
7432
7436
7433
7437
// otherwise compile like a normal function
7434
7438
} else {
@@ -7437,13 +7441,41 @@ export class Compiler extends DiagnosticEmitter {
7437
7441
instance . flow . outer = flow ;
7438
7442
let worked = this . compileFunction ( instance ) ;
7439
7443
this . currentType = instance . signature . type ;
7440
- if ( ! worked ) return this . module . unreachable ( ) ;
7444
+ if ( ! worked ) return module . unreachable ( ) ;
7441
7445
}
7442
7446
7443
7447
var offset = this . ensureRuntimeFunction ( instance ) ; // reports
7444
- return this . options . isWasm64
7445
- ? this . module . i64 ( i64_low ( offset ) , i64_high ( offset ) )
7446
- : this . module . i32 ( i64_low ( offset ) ) ;
7448
+ var expr = this . options . isWasm64
7449
+ ? module . i64 ( i64_low ( offset ) , i64_high ( offset ) )
7450
+ : module . i32 ( i64_low ( offset ) ) ;
7451
+
7452
+ // add a constant local referring to the function if applicable
7453
+ if ( ! isSemanticallyAnonymous ) {
7454
+ let fname = instance . name ;
7455
+ let existingLocal = flow . getScopedLocal ( fname ) ;
7456
+ if ( existingLocal ) {
7457
+ if ( ! existingLocal . declaration . range . source . isNative ) {
7458
+ this . errorRelated (
7459
+ DiagnosticCode . Duplicate_identifier_0 ,
7460
+ declaration . name . range ,
7461
+ existingLocal . declaration . name . range ,
7462
+ fname
7463
+ ) ;
7464
+ } else { // scoped locals are shared temps that don't track declarations
7465
+ this . error (
7466
+ DiagnosticCode . Duplicate_identifier_0 ,
7467
+ declaration . name . range , fname
7468
+ ) ;
7469
+ }
7470
+ } else {
7471
+ let ftype = instance . type ;
7472
+ let local = flow . addScopedLocal ( instance . name , ftype ) ;
7473
+ flow . setLocalFlag ( local . index , LocalFlags . CONSTANT ) ;
7474
+ expr = module . local_tee ( local . index , expr , ftype . isManaged ) ;
7475
+ }
7476
+ }
7477
+
7478
+ return expr ;
7447
7479
}
7448
7480
7449
7481
/** Makes sure the enclosing source file of the specified expression has been compiled. */
0 commit comments