[JS IR] Use context-dependent names for lambdas
Partially fix KT-46525
Now the code like
```
fun foo(a: () -> Unit) {}
interface A {
fun run()
}
fun main() {
foo {
println()
}
val a = object : A {
override fun run() {
TODO()
}
}
}
```
is being compiled into
```
function foo(a) {
}
function A() {
}
A.$metadata$ = {
simpleName: 'A',
kind: 'interface',
interfaces: []
};
function main() {
foo(main$lambda());
var a = new _no_name_provided_();
}
function main$lambda() {
return function () {
println();
};
}
// TODO
function _no_name_provided_() {
}
_no_name_provided_.$metadata$ = {
kind: 'class',
interfaces: [A]
};
```
This commit is contained in:
committed by
TeamCityServer
parent
76e08356d8
commit
fe4a25eba1
+36
-1
@@ -123,6 +123,41 @@ class CallableReferenceLowering(private val context: CommonBackendContext) : Bod
|
||||
private val superFunctionInterface = reference.type.classOrNull?.owner ?: error("Expected functional type")
|
||||
private val isKReference = superFunctionInterface.name.identifier[0] == 'K'
|
||||
|
||||
private fun StringBuilder.collectNamesForLambda(d: IrDeclarationWithName) {
|
||||
val parent = d.parent
|
||||
|
||||
if (parent is IrPackageFragment) {
|
||||
append(d.name.asString())
|
||||
return
|
||||
}
|
||||
|
||||
collectNamesForLambda(parent as IrDeclarationWithName)
|
||||
|
||||
if (d is IrAnonymousInitializer) return
|
||||
|
||||
fun IrDeclaration.isLambdaFun(): Boolean = origin == IrDeclarationOrigin.LOCAL_FUNCTION_FOR_LAMBDA
|
||||
|
||||
when {
|
||||
d.isLambdaFun() -> {
|
||||
append('$')
|
||||
if (d is IrSimpleFunction && d.isSuspend) append('s')
|
||||
append("lambda")
|
||||
}
|
||||
d.name == SpecialNames.NO_NAME_PROVIDED -> append("\$o")
|
||||
else -> {
|
||||
append('$')
|
||||
append(d.name.asString())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun makeContextDependentName(): Name {
|
||||
val sb = StringBuilder()
|
||||
sb.collectNamesForLambda(function)
|
||||
if (!isLambda) sb.append("\$ref")
|
||||
return Name.identifier(sb.toString())
|
||||
}
|
||||
|
||||
private fun buildReferenceClass(): IrClass {
|
||||
return context.irFactory.buildClass {
|
||||
setSourceRange(reference)
|
||||
@@ -130,7 +165,7 @@ class CallableReferenceLowering(private val context: CommonBackendContext) : Bod
|
||||
// A callable reference results in a synthetic class, while a lambda is not synthetic.
|
||||
// We don't produce GENERATED_SAM_IMPLEMENTATION, which is always synthetic.
|
||||
origin = if (isKReference || !isLambda) FUNCTION_REFERENCE_IMPL else LAMBDA_IMPL
|
||||
name = SpecialNames.NO_NAME_PROVIDED
|
||||
name = makeContextDependentName()
|
||||
}.apply {
|
||||
superTypes = listOf(superClass, reference.type)
|
||||
// if (samSuperType == null)
|
||||
|
||||
+1
-3
@@ -323,14 +323,12 @@ class InteropCallableReferenceLowering(val context: JsIrBackendContext) : BodyLo
|
||||
val newDeclarations = mutableListOf<IrDeclaration>()
|
||||
val constructor = lambdaClass.declarations.single { it is IrConstructor } as IrConstructor
|
||||
|
||||
val factoryName = Name.identifier("${lambdaClass.name.asString()}\$factory")
|
||||
|
||||
val factoryDeclaration = context.irFactory.buildFun {
|
||||
startOffset = lambdaClass.startOffset
|
||||
endOffset = lambdaClass.endOffset
|
||||
visibility = lambdaClass.visibility
|
||||
returnType = lambdaClass.defaultType
|
||||
name = factoryName
|
||||
name = lambdaClass.name
|
||||
origin = JsStatementOrigins.FACTORY_ORIGIN
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user