@@ -3429,7 +3429,7 @@ export class Compiler extends DiagnosticEmitter {
34293429 break ;
34303430 }
34313431 case NodeKind . FUNCTION : {
3432- expr = this . compileFunctionExpression ( < FunctionExpression > expression , contextualType . signatureReference , constraints ) ;
3432+ expr = this . compileFunctionExpression ( < FunctionExpression > expression , contextualType , constraints ) ;
34333433 break ;
34343434 }
34353435 case NodeKind . IDENTIFIER :
@@ -7311,26 +7311,30 @@ export class Compiler extends DiagnosticEmitter {
73117311
73127312 private compileFunctionExpression (
73137313 expression : FunctionExpression ,
7314- contextualSignature : Signature | null ,
7314+ contextualType : Type ,
73157315 constraints : Constraints
73167316 ) : ExpressionRef {
73177317 var declaration = expression . declaration . clone ( ) ; // generic contexts can have multiple
73187318 assert ( ! declaration . typeParameters ) ; // function expression cannot be generic
73197319 var flow = this . currentFlow ;
73207320 var actualFunction = flow . actualFunction ;
7321+ var isNamed = declaration . name . text . length > 0 ;
7322+ var isSemanticallyAnonymous = ! isNamed || contextualType != Type . void ;
73217323 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 ,
73257327 actualFunction ,
73267328 declaration ,
73277329 DecoratorFlags . NONE
73287330 ) ;
73297331 var instance : Function | null ;
73307332 var contextualTypeArguments = uniqueMap ( flow . contextualTypeArguments ) ;
7333+ var module = this . module ;
73317334
73327335 // compile according to context. this differs from a normal function in that omitted parameter
73337336 // and return types can be inferred and omitted arguments can be replaced with dummies.
7337+ var contextualSignature = contextualType . signatureReference ;
73347338 if ( contextualSignature ) {
73357339 let signatureNode = prototype . functionTypeNode ;
73367340 let parameterNodes = signatureNode . parameters ;
@@ -7344,7 +7348,7 @@ export class Compiler extends DiagnosticEmitter {
73447348 DiagnosticCode . Expected_0_arguments_but_got_1 ,
73457349 expression . range , numParameters . toString ( ) , numPresentParameters . toString ( )
73467350 ) ;
7347- return this . module . unreachable ( ) ;
7351+ return module . unreachable ( ) ;
73487352 }
73497353
73507354 // check non-omitted parameter types
@@ -7356,13 +7360,13 @@ export class Compiler extends DiagnosticEmitter {
73567360 actualFunction . parent ,
73577361 contextualTypeArguments
73587362 ) ;
7359- if ( ! resolvedType ) return this . module . unreachable ( ) ;
7363+ if ( ! resolvedType ) return module . unreachable ( ) ;
73607364 if ( ! parameterTypes [ i ] . isStrictlyAssignableTo ( resolvedType ) ) {
73617365 this . error (
73627366 DiagnosticCode . Type_0_is_not_assignable_to_type_1 ,
73637367 parameterNode . range , parameterTypes [ i ] . toString ( ) , resolvedType . toString ( )
73647368 ) ;
7365- return this . module . unreachable ( ) ;
7369+ return module . unreachable ( ) ;
73667370 }
73677371 }
73687372 // any unused parameters are inherited but ignored
@@ -7376,7 +7380,7 @@ export class Compiler extends DiagnosticEmitter {
73767380 actualFunction . parent ,
73777381 contextualTypeArguments
73787382 ) ;
7379- if ( ! resolvedType ) return this . module . unreachable ( ) ;
7383+ if ( ! resolvedType ) return module . unreachable ( ) ;
73807384 if (
73817385 returnType == Type . void
73827386 ? resolvedType != Type . void
@@ -7386,7 +7390,7 @@ export class Compiler extends DiagnosticEmitter {
73867390 DiagnosticCode . Type_0_is_not_assignable_to_type_1 ,
73877391 signatureNode . returnType . range , resolvedType . toString ( ) , returnType . toString ( )
73887392 ) ;
7389- return this . module . unreachable ( ) ;
7393+ return module . unreachable ( ) ;
73907394 }
73917395 }
73927396
@@ -7399,20 +7403,20 @@ export class Compiler extends DiagnosticEmitter {
73997403 DiagnosticCode . _this_cannot_be_referenced_in_current_location ,
74007404 thisTypeNode . range
74017405 ) ;
7402- return this . module . unreachable ( ) ;
7406+ return module . unreachable ( ) ;
74037407 }
74047408 let resolvedType = this . resolver . resolveType (
74057409 thisTypeNode ,
74067410 actualFunction . parent ,
74077411 contextualTypeArguments
74087412 ) ;
7409- if ( ! resolvedType ) return this . module . unreachable ( ) ;
7413+ if ( ! resolvedType ) return module . unreachable ( ) ;
74107414 if ( ! thisType . isStrictlyAssignableTo ( resolvedType ) ) {
74117415 this . error (
74127416 DiagnosticCode . Type_0_is_not_assignable_to_type_1 ,
74137417 thisTypeNode . range , thisType . toString ( ) , resolvedType . toString ( )
74147418 ) ;
7415- return this . module . unreachable ( ) ;
7419+ return module . unreachable ( ) ;
74167420 }
74177421 }
74187422
@@ -7428,7 +7432,7 @@ export class Compiler extends DiagnosticEmitter {
74287432 instance . flow . outer = flow ;
74297433 let worked = this . compileFunction ( instance ) ;
74307434 this . currentType = contextualSignature . type ;
7431- if ( ! worked ) return this . module . unreachable ( ) ;
7435+ if ( ! worked ) return module . unreachable ( ) ;
74327436
74337437 // otherwise compile like a normal function
74347438 } else {
@@ -7437,13 +7441,41 @@ export class Compiler extends DiagnosticEmitter {
74377441 instance . flow . outer = flow ;
74387442 let worked = this . compileFunction ( instance ) ;
74397443 this . currentType = instance . signature . type ;
7440- if ( ! worked ) return this . module . unreachable ( ) ;
7444+ if ( ! worked ) return module . unreachable ( ) ;
74417445 }
74427446
74437447 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 ;
74477479 }
74487480
74497481 /** Makes sure the enclosing source file of the specified expression has been compiled. */
0 commit comments