[JS IR BE] Implement property reference

Add cache for direct (which has no closured parameters) KCallable references
Refactor FunctionReferenceLowering
 * Rename FunctionReferenceLowering -> CallableReferenceLowering
 * Add util method to create value parameters
This commit is contained in:
Roman Artemev
2018-05-14 18:50:57 +03:00
committed by Roman Artemev
parent fb1fbf1473
commit 261edd5f4c
17 changed files with 546 additions and 257 deletions
@@ -18,12 +18,12 @@ package org.jetbrains.kotlin.backend.js
import org.jetbrains.kotlin.backend.common.descriptors.DescriptorsFactory
import org.jetbrains.kotlin.builtins.CompanionObjectMapping.isMappedIntrinsicCompanionObject
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
import org.jetbrains.kotlin.descriptors.*
import org.jetbrains.kotlin.descriptors.annotations.Annotations
import org.jetbrains.kotlin.descriptors.impl.ClassConstructorDescriptorImpl
import org.jetbrains.kotlin.descriptors.impl.PropertyDescriptorImpl
import org.jetbrains.kotlin.descriptors.impl.ValueParameterDescriptorImpl
import org.jetbrains.kotlin.ir.backend.js.utils.Namer
import org.jetbrains.kotlin.ir.backend.js.utils.createValueParameter
import org.jetbrains.kotlin.ir.declarations.IrClass
import org.jetbrains.kotlin.ir.declarations.IrConstructor
import org.jetbrains.kotlin.ir.symbols.*
@@ -34,9 +34,7 @@ import org.jetbrains.kotlin.ir.util.dump
import org.jetbrains.kotlin.name.Name
import java.util.*
class JsDescriptorsFactory(
private val builtIns: KotlinBuiltIns
) : DescriptorsFactory {
class JsDescriptorsFactory : DescriptorsFactory {
private val singletonFieldDescriptors = HashMap<IrBindableSymbol<*, *>, IrFieldSymbol>()
private val outerThisFieldSymbols = HashMap<IrClass, IrFieldSymbol>()
private val innerClassConstructors = HashMap<IrConstructorSymbol, IrConstructorSymbol>()
@@ -93,19 +91,7 @@ class JsDescriptorsFactory(
classDescriptor, oldDescriptor.annotations, oldDescriptor.isPrimary, oldDescriptor.source
)
val outerThisValueParameter = ValueParameterDescriptorImpl(
newDescriptor,
null,
0,
Annotations.EMPTY,
Name.identifier("\$outer"),
outerThisType,
false,
false,
false,
null,
SourceElement.NO_SOURCE
)
val outerThisValueParameter = createValueParameter(newDescriptor, 0, Namer.OUTER_NAME, outerThisType)
val newValueParameters =
listOf(outerThisValueParameter) +
@@ -9,6 +9,7 @@ import org.jetbrains.kotlin.descriptors.*
import org.jetbrains.kotlin.descriptors.annotations.Annotations
import org.jetbrains.kotlin.descriptors.impl.SimpleFunctionDescriptorImpl
import org.jetbrains.kotlin.descriptors.impl.TypeParameterDescriptorImpl
import org.jetbrains.kotlin.ir.backend.js.utils.createValueParameter
import org.jetbrains.kotlin.ir.backend.js.utils.getFunctions
import org.jetbrains.kotlin.ir.declarations.IrSimpleFunction
import org.jetbrains.kotlin.ir.descriptors.IrBuiltIns
@@ -74,11 +75,19 @@ class JsIntrinsics(private val module: ModuleDescriptor, private val irBuiltIns:
val jsBitShiftL = binOpInt("jsBitShiftL")
// KFunction operations:
val jsName = unOp("kCallableName", irBuiltIns.string)
val jsPropertyGet = binOp("kPropertyGet")
val jsPropertySet = tripleOp("kPropertySet", irBuiltIns.unit)
// Other:
val jsInstanceOf = binOpBool("jsInstanceOf")
val jsObjectCreate: IrSimpleFunction = defineObjectCreateIntrinsic()
val jsObjectCreate = defineObjectCreateIntrinsic()
val jsSetJSField = defineSetJSPropertyIntrinsic()
val jsCode = module.getFunctions(FqName("kotlin.js.js")).singleOrNull()?.let { symbolTable.referenceFunction(it) }
@@ -112,6 +121,26 @@ class JsIntrinsics(private val module: ModuleDescriptor, private val irBuiltIns:
return stubBuilder.generateFunctionStub(desc)
}
private fun defineSetJSPropertyIntrinsic(): IrSimpleFunction {
val returnType = irBuiltIns.unit
val desc = SimpleFunctionDescriptorImpl.create(
module,
Annotations.EMPTY,
Name.identifier("\$setJSProperty\$"),
CallableMemberDescriptor.Kind.SYNTHESIZED,
SourceElement.NO_SOURCE
).apply {
val parameterDescriptors = listOf("receiver", "fieldName", "fieldValue")
.mapIndexed { i, name -> createValueParameter(this, i, name, irBuiltIns.any) }
initialize(null, null, emptyList(), parameterDescriptors, returnType, Modality.FINAL, Visibilities.PUBLIC)
}
return stubBuilder.generateFunctionStub(desc)
}
private fun unOp(name: String, returnType: KotlinType = irBuiltIns.anyN) =
irBuiltIns.run { defineOperator(name, returnType, listOf(anyN)) }
@@ -121,6 +150,9 @@ class JsIntrinsics(private val module: ModuleDescriptor, private val irBuiltIns:
private fun binOp(name: String, returnType: KotlinType = irBuiltIns.anyN) =
irBuiltIns.run { defineOperator(name, returnType, listOf(anyN, anyN)) }
private fun tripleOp(name: String, returnType: KotlinType = irBuiltIns.anyN) =
irBuiltIns.run { defineOperator(name, returnType, listOf(anyN, anyN, anyN)) }
private fun binOpBool(name: String) = binOp(name, irBuiltIns.bool)
private fun binOpInt(name: String) = binOp(name, irBuiltIns.int)
}
@@ -40,7 +40,7 @@ class JsIrBackendContext(
override val builtIns = module.builtIns
override val sharedVariablesManager =
JsSharedVariablesManager(builtIns, KnownPackageFragmentDescriptor(builtIns.builtInsModule, FqName("kotlin.js.internal")))
override val descriptorsFactory = JsDescriptorsFactory(builtIns)
override val descriptorsFactory = JsDescriptorsFactory()
override val reflectionTypes: ReflectionTypes by lazy(LazyThreadSafetyMode.PUBLICATION) {
// TODO
@@ -13,8 +13,7 @@ import org.jetbrains.kotlin.descriptors.annotations.Annotations
import org.jetbrains.kotlin.descriptors.impl.ClassConstructorDescriptorImpl
import org.jetbrains.kotlin.descriptors.impl.LocalVariableDescriptor
import org.jetbrains.kotlin.descriptors.impl.PropertyDescriptorImpl
import org.jetbrains.kotlin.descriptors.impl.ValueParameterDescriptorImpl
import org.jetbrains.kotlin.ir.IrStatement
import org.jetbrains.kotlin.ir.backend.js.utils.createValueParameter
import org.jetbrains.kotlin.ir.declarations.IrVariable
import org.jetbrains.kotlin.ir.declarations.impl.IrVariableImpl
import org.jetbrains.kotlin.ir.expressions.IrExpression
@@ -136,19 +135,7 @@ class JsSharedVariablesManager(val builtIns: KotlinBuiltIns, val jsInterinalPack
listOf(), true
)
val paramDesc = ValueParameterDescriptorImpl(
this,
null,
0,
Annotations.EMPTY,
Name.identifier("v"),
parameterType,
false,
false,
false,
null,
SourceElement.NO_SOURCE
)
val paramDesc = createValueParameter(this, 0, "v", parameterType)
initialize(listOf(paramDesc), Visibilities.PUBLIC)
returnType = KotlinTypeFactory.simpleNotNullType(
@@ -10,7 +10,7 @@ import org.jetbrains.kotlin.backend.common.lower.*
import org.jetbrains.kotlin.backend.common.runOnFilePostfix
import org.jetbrains.kotlin.config.CompilerConfiguration
import org.jetbrains.kotlin.ir.backend.js.lower.BlockDecomposerLowering
import org.jetbrains.kotlin.ir.backend.js.lower.FunctionReferenceLowering
import org.jetbrains.kotlin.ir.backend.js.lower.CallableReferenceLowering
import org.jetbrains.kotlin.ir.backend.js.lower.IntrinsicifyCallsLowering
import org.jetbrains.kotlin.ir.backend.js.lower.SecondaryCtorLowering
import org.jetbrains.kotlin.ir.backend.js.transformers.irToJs.IrModuleToJsTransformer
@@ -67,6 +67,6 @@ fun JsIrBackendContext.lower(file: IrFile) {
InitializersLowering(this, JsLoweredDeclarationOrigin.CLASS_STATIC_INITIALIZER, false).runOnFilePostfix(file)
BlockDecomposerLowering(this).runOnFilePostfix(file)
SecondaryCtorLowering(this).runOnFilePostfix(file)
CallableReferenceLowering(this).lower(file)
IntrinsicifyCallsLowering(this).lower(file)
FunctionReferenceLowering(this).lower(file)
}
@@ -11,7 +11,7 @@ import org.jetbrains.kotlin.descriptors.annotations.Annotations
import org.jetbrains.kotlin.descriptors.impl.FunctionDescriptorImpl
import org.jetbrains.kotlin.descriptors.impl.LocalVariableDescriptor
import org.jetbrains.kotlin.descriptors.impl.SimpleFunctionDescriptorImpl
import org.jetbrains.kotlin.descriptors.impl.ValueParameterDescriptorImpl
import org.jetbrains.kotlin.ir.backend.js.utils.createValueParameter
import org.jetbrains.kotlin.ir.descriptors.IrTemporaryVariableDescriptorImpl
import org.jetbrains.kotlin.ir.symbols.IrFunctionSymbol
import org.jetbrains.kotlin.ir.symbols.IrSimpleFunctionSymbol
@@ -23,28 +23,8 @@ import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.types.KotlinType
object JsSymbolBuilder {
fun buildValueParameter(
containingSymbol: IrSimpleFunctionSymbol,
index: Int,
type: KotlinType,
name: String? = null,
hasDefault: Boolean = false
) =
IrValueParameterSymbolImpl(
ValueParameterDescriptorImpl(
containingSymbol.descriptor,
null,
index,
Annotations.EMPTY,
Name.identifier(name ?: "param$index"),
type,
hasDefault,
false,
false,
null,
SourceElement.NO_SOURCE
)
)
fun buildValueParameter(containingSymbol: IrSimpleFunctionSymbol, index: Int, type: KotlinType, name: String? = null) =
IrValueParameterSymbolImpl(createValueParameter(containingSymbol.descriptor, index, name ?: "param$index", type))
fun buildSimpleFunction(
containingDeclaration: DeclarationDescriptor,
@@ -78,4 +78,5 @@ object JsIrBuilder {
fun buildNull(type: KotlinType) = IrConstImpl.constNull(UNDEFINED_OFFSET, UNDEFINED_OFFSET, type)
fun buildBoolean(type: KotlinType, v: Boolean) = IrConstImpl.boolean(UNDEFINED_OFFSET, UNDEFINED_OFFSET, type, v)
fun buildString(type: KotlinType, s: String) = IrConstImpl.string(UNDEFINED_OFFSET, UNDEFINED_OFFSET, type, s)
}
@@ -10,9 +10,9 @@ import org.jetbrains.kotlin.builtins.KotlinBuiltIns
import org.jetbrains.kotlin.ir.IrElement
import org.jetbrains.kotlin.ir.IrStatement
import org.jetbrains.kotlin.ir.backend.js.JsIrBackendContext
import org.jetbrains.kotlin.ir.backend.js.descriptors.JsSymbolBuilder
import org.jetbrains.kotlin.ir.backend.js.descriptors.initialize
import org.jetbrains.kotlin.ir.backend.js.ir.JsIrBuilder
import org.jetbrains.kotlin.ir.backend.js.symbols.JsSymbolBuilder
import org.jetbrains.kotlin.ir.backend.js.symbols.initialize
import org.jetbrains.kotlin.ir.backend.js.utils.Namer
import org.jetbrains.kotlin.ir.declarations.IrField
import org.jetbrains.kotlin.ir.declarations.IrFunction
@@ -393,16 +393,16 @@ class BlockDecomposerLowering(val context: JsIrBackendContext) : FunctionLowerin
collectingList += tempResult.runIfChangedOrDefault(listOf(statement)) { statements }
}
if (lastStatement != null) {
return if (lastStatement != null) {
val result = lastStatement.accept(expressionVisitor, data).runIfChangedOrDefault(lastStatement as IrExpression) {
collectingList += statements
resultValue
}
collectingList += JsIrBuilder.buildSetVariable(variable, result)
return DecomposedResult(mutableListOf(varDeclaration, body), JsIrBuilder.buildGetValue(variable))
DecomposedResult(mutableListOf(varDeclaration, body), JsIrBuilder.buildGetValue(variable))
} else {
// do not allow variable to be uninitialized
return DecomposedResult(mutableListOf(), unitValue)
DecomposedResult(mutableListOf(), unitValue)
}
}
@@ -562,7 +562,8 @@ class BlockDecomposerLowering(val context: JsIrBackendContext) : FunctionLowerin
expression.endOffset,
expression.type,
expression.varargElementType,
newArguments)
newArguments
)
return DecomposedResult(newStatements, newExpression)
}
@@ -0,0 +1,353 @@
/*
* Copyright 2010-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license
* that can be found in the license/LICENSE.txt file.
*/
package org.jetbrains.kotlin.ir.backend.js.lower
import org.jetbrains.kotlin.backend.common.DeclarationContainerLoweringPass
import org.jetbrains.kotlin.backend.common.FileLoweringPass
import org.jetbrains.kotlin.backend.common.lower.copyAsValueParameter
import org.jetbrains.kotlin.backend.common.runOnFilePostfix
import org.jetbrains.kotlin.descriptors.CallableDescriptor
import org.jetbrains.kotlin.descriptors.ClassConstructorDescriptor
import org.jetbrains.kotlin.descriptors.ValueParameterDescriptor
import org.jetbrains.kotlin.ir.IrElement
import org.jetbrains.kotlin.ir.IrStatement
import org.jetbrains.kotlin.ir.backend.js.JsIrBackendContext
import org.jetbrains.kotlin.ir.backend.js.ir.JsIrBuilder
import org.jetbrains.kotlin.ir.backend.js.utils.Namer
import org.jetbrains.kotlin.ir.declarations.*
import org.jetbrains.kotlin.ir.declarations.impl.IrValueParameterImpl
import org.jetbrains.kotlin.ir.expressions.*
import org.jetbrains.kotlin.ir.expressions.impl.IrCallImpl
import org.jetbrains.kotlin.ir.symbols.IrFunctionSymbol
import org.jetbrains.kotlin.ir.symbols.IrSimpleFunctionSymbol
import org.jetbrains.kotlin.ir.symbols.IrValueParameterSymbol
import org.jetbrains.kotlin.ir.symbols.IrValueSymbol
import org.jetbrains.kotlin.ir.util.transformFlat
import org.jetbrains.kotlin.ir.visitors.*
import org.jetbrains.kotlin.resolve.descriptorUtil.fqNameSafe
import org.jetbrains.kotlin.types.KotlinType
class CallableReferenceLowering(val context: JsIrBackendContext) : FileLoweringPass, DeclarationContainerLoweringPass {
private val callableToGetterFunction = mutableMapOf<CallableDescriptor, IrFunction>()
// TODO: replace descriptor usage with symbol instead
private val collectedReferenceMap = mutableMapOf<IrDeclaration, IrCallableReference>()
private val callableNameConst = JsIrBuilder.buildString(context.irBuiltIns.string, Namer.KCALLABLE_NAME)
private val getterConst = JsIrBuilder.buildString(context.irBuiltIns.string, Namer.KPROPERTY_GET)
private val setterConst = JsIrBuilder.buildString(context.irBuiltIns.string, Namer.KPROPERTY_SET)
override fun lower(irFile: IrFile) {
irFile.acceptVoid(CallableReferenceCollector())
runOnFilePostfix(irFile)
irFile.transformChildrenVoid(CallableReferenceTransformer())
}
inner class CallableReferenceCollector : IrElementVisitorVoid {
override fun visitFunctionReference(expression: IrFunctionReference) {
collectedReferenceMap[expression.symbol.owner] = expression
}
override fun visitPropertyReference(expression: IrPropertyReference) {
//Note: The getter is taken because the `invoke()` function of the resulted reference has to be corresponding getter call
collectedReferenceMap[expression.getter!!.owner] = expression
}
override fun visitElement(element: IrElement) {
element.acceptChildrenVoid(this)
}
}
override fun lower(irDeclarationContainer: IrDeclarationContainer) {
irDeclarationContainer.declarations.transformFlat { d ->
collectedReferenceMap[d]?.accept(object : IrElementVisitor<List<IrDeclaration>, IrFunction> {
override fun visitElement(element: IrElement, data: IrFunction) = error("Unreachable execution")
override fun visitFunctionReference(expression: IrFunctionReference, data: IrFunction) =
lowerKFunctionReference(data, expression)
override fun visitPropertyReference(expression: IrPropertyReference, data: IrFunction) =
lowerKPropertyReference(data, expression)
}, d as IrFunction)
}
}
inner class CallableReferenceTransformer : IrElementTransformerVoid() {
override fun visitCallableReference(expression: IrCallableReference) = callableToGetterFunction[expression.descriptor]?.let {
redirectToFunction(expression, it)
} ?: expression
private fun redirectToFunction(callable: IrCallableReference, newTarget: IrFunction) =
IrCallImpl(callable.startOffset, callable.endOffset, newTarget.symbol, callable.origin).apply {
copyTypeArgumentsFrom(callable)
var index = 0
for (i in 0 until callable.valueArgumentsCount) {
val arg = callable.getValueArgument(i)
if (arg != null) {
putValueArgument(index++, arg)
}
}
}
}
private fun createClosureGetterName(descriptor: CallableDescriptor) = createHelperFunctionName(descriptor, "KReferenceGet")
private fun createPropertyClosureGetterName(descriptor: CallableDescriptor) = createHelperFunctionName(descriptor, "KPropertyGet")
private fun createClosureInstanceName(descriptor: CallableDescriptor) = createHelperFunctionName(descriptor, "KReferenceClosure")
private fun createHelperFunctionName(descriptor: CallableDescriptor, suffix: String): String {
val nameBuilder = StringBuilder()
if (descriptor is ClassConstructorDescriptor) {
nameBuilder.append(descriptor.constructedClass.fqNameSafe)
nameBuilder.append('_')
}
nameBuilder.append(descriptor.name)
nameBuilder.append('_')
nameBuilder.append(suffix)
return nameBuilder.toString()
}
private fun getReferenceName(descriptor: CallableDescriptor): String {
if (descriptor is ClassConstructorDescriptor) {
return descriptor.constructedClass.name.identifier
}
return descriptor.name.identifier
}
private fun lowerKFunctionReference(declaration: IrFunction, functionReference: IrFunctionReference): List<IrDeclaration> {
// transform
// x = Foo::bar ->
// x = Foo_bar_KreferenceGet(c1: closure$C1, c2: closure$C2) : KFunctionN<Foo, T2, ..., TN, TReturn> {
// [ if ($cache$ == null) { ] // in case reference has no closure param cache it
// val x = fun Foo_bar_KreferenceClosure(p0: Foo, p1: T2, p2: T3): TReturn {
// return p0.bar(c1, c2, p1, p2)
// }
// x.callableName = "bar"
// [ $cache$ = x } ]
// return {$cache$|x}
// }
// KFunctionN<Foo, T2, ..., TN, TReturn>, arguments.size = N + 1
val refGetFunction = buildGetFunction(declaration, functionReference.type, createClosureGetterName(declaration.descriptor))
val refClosureFunction = buildClosureFunction(declaration, refGetFunction)
val additionalDeclarations = generateGetterBodyWithGuard(refGetFunction) {
val irClosureReference = JsIrBuilder.buildFunctionReference(functionReference.type, refClosureFunction.symbol)
val irVarSymbol = JsSymbolBuilder.buildTempVar(refGetFunction.symbol, irClosureReference.type)
val irVar = JsIrBuilder.buildVar(irVarSymbol, irClosureReference)
// TODO: fill other fields of callable reference (returnType, parameters, isFinal, etc.)
val irSetName = JsIrBuilder.buildCall(context.intrinsics.jsSetJSField.symbol).apply {
putValueArgument(0, JsIrBuilder.buildGetValue(irVarSymbol))
putValueArgument(1, callableNameConst)
putValueArgument(2, JsIrBuilder.buildString(context.irBuiltIns.string, getReferenceName(declaration.descriptor)))
}
Pair(listOf(irVar, irSetName), irVarSymbol)
}
callableToGetterFunction[functionReference.descriptor] = refGetFunction
return additionalDeclarations + listOf(declaration, refGetFunction)
}
private fun lowerKPropertyReference(getterDeclaration: IrFunction, propertyReference: IrPropertyReference): List<IrDeclaration> {
// transform
// x = Foo::bar ->
// x = Foo_bar_KreferenceGet() : KPropertyN<Foo, PType> {
// if ($cache$ == null) { // very likely property reference is going to be cached
// val x = fun Foo_bar_KreferenceClosure_get(r: Foo): PType {
// return r.<get>()
// }
// x.get = x
// x.callableName = "bar"
// if (mutable) {
// x.set = fun Foo_bar_KreferenceClosure_set(r: Foo, v: PType>) {
// r.<set>(v)
// }
// }
// $cache$ = x
// }
// return $cache$
// }
val getterName = createPropertyClosureGetterName(propertyReference.descriptor)
val refGetFunction = buildGetFunction(propertyReference.getter!!.owner, propertyReference.type, getterName)
val getterFunction = propertyReference.getter?.let { buildClosureFunction(it.owner, refGetFunction) }!!
val setterFunction = propertyReference.setter?.let { buildClosureFunction(it.owner, refGetFunction) }
val additionalDeclarations = generateGetterBodyWithGuard(refGetFunction) {
val statements = mutableListOf<IrStatement>()
val getterFunctionType = context.builtIns.getFunction(getterFunction.valueParameters.size + 1)
val irGetReference = JsIrBuilder.buildFunctionReference(getterFunctionType.defaultType, getterFunction.symbol)
val irVarSymbol = JsSymbolBuilder.buildTempVar(refGetFunction.symbol, getterFunctionType.defaultType)
statements += JsIrBuilder.buildVar(irVarSymbol, irGetReference)
JsIrBuilder.buildCall(context.intrinsics.jsSetJSField.symbol).run {
putValueArgument(0, JsIrBuilder.buildGetValue(irVarSymbol))
putValueArgument(1, getterConst)
putValueArgument(2, JsIrBuilder.buildGetValue(irVarSymbol))
statements += this
}
if (setterFunction != null) {
val setterFunctionType = context.builtIns.getFunction(setterFunction.valueParameters.size + 1)
val irSetReference = JsIrBuilder.buildFunctionReference(setterFunctionType.defaultType, setterFunction.symbol)
JsIrBuilder.buildCall(context.intrinsics.jsSetJSField.symbol).run {
putValueArgument(0, JsIrBuilder.buildGetValue(irVarSymbol))
putValueArgument(1, setterConst)
putValueArgument(2, irSetReference)
statements += this
}
}
// TODO: fill other fields of callable reference (returnType, parameters, isFinal, etc.)
JsIrBuilder.buildCall(context.intrinsics.jsSetJSField.symbol).run {
putValueArgument(0, JsIrBuilder.buildGetValue(irVarSymbol))
putValueArgument(1, callableNameConst)
putValueArgument(2, JsIrBuilder.buildString(context.irBuiltIns.string, getReferenceName(propertyReference.descriptor)))
statements += this
}
Pair(statements, irVarSymbol)
}
callableToGetterFunction[propertyReference.descriptor] = refGetFunction
return additionalDeclarations + listOf(getterDeclaration, refGetFunction)
}
private fun generateGetterBodyWithGuard(
getterFunction: IrSimpleFunction,
builder: () -> Pair<List<IrStatement>, IrValueSymbol>
): List<IrDeclaration> {
val (bodyStatements, varSymbol) = builder()
val statements = mutableListOf<IrStatement>()
val returnValue: IrExpression
val returnStatements: List<IrDeclaration>
if (getterFunction.valueParameters.isEmpty()) {
// compose cache for 'direct' closure
// if ($cache$ === null) {
// $cache$ = <body>
// }
//
val cacheName = "${getterFunction.name}_${Namer.KCALLABLE_CACHE_SUFFIX}"
val cacheVarSymbol =
JsSymbolBuilder.buildVar(getterFunction.descriptor.containingDeclaration, getterFunction.returnType, cacheName, true)
val irCacheNull = JsIrBuilder.buildNull(cacheVarSymbol.descriptor.type)
val irCacheDeclaration = JsIrBuilder.buildVar(cacheVarSymbol, irCacheNull)
val irCacheValue = JsIrBuilder.buildGetValue(cacheVarSymbol)
val irIfCondition = JsIrBuilder.buildCall(context.irBuiltIns.eqeqeqSymbol).apply {
putValueArgument(0, irCacheValue)
putValueArgument(1, irCacheNull)
}
val irSetCache = JsIrBuilder.buildSetVariable(cacheVarSymbol, JsIrBuilder.buildGetValue(varSymbol))
val thenStatements = mutableListOf<IrStatement>().apply {
addAll(bodyStatements)
add(irSetCache)
}
val irThenBranch = JsIrBuilder.buildBlock(context.irBuiltIns.unit, thenStatements)
val irIfNode = JsIrBuilder.buildIfElse(context.irBuiltIns.unit, irIfCondition, irThenBranch)
statements += irIfNode
returnValue = irCacheValue
returnStatements = listOf(irCacheDeclaration)
} else {
statements += bodyStatements
returnValue = JsIrBuilder.buildGetValue(varSymbol)
returnStatements = emptyList()
}
statements += JsIrBuilder.buildReturn(getterFunction.symbol, returnValue)
getterFunction.body = JsIrBuilder.buildBlockBody(statements)
return returnStatements
}
private fun generateSignatureForClosure(
callable: IrFunctionSymbol,
getter: IrSimpleFunctionSymbol,
closure: IrSimpleFunctionSymbol
): List<IrValueParameterSymbol> {
val result = mutableListOf<IrValueParameterSymbol>()
callable.owner.dispatchReceiverParameter?.run { result.add(JsSymbolBuilder.buildValueParameter(closure, result.size, type)) }
callable.owner.extensionReceiverParameter?.run { result.add(JsSymbolBuilder.buildValueParameter(closure, result.size, type)) }
for (i in getter.owner.valueParameters.size until callable.owner.valueParameters.size) {
val param = callable.owner.valueParameters[i]
val paramName = param.name.run { if (!isSpecial) identifier else null }
result += JsSymbolBuilder.buildValueParameter(closure, result.size, param.type, paramName)
}
return result
}
private fun buildGetFunction(declaration: IrFunction, callableType: KotlinType, getterName: String): IrSimpleFunction {
val closureParams = callableType.arguments.dropLast(1) // drop return type
var kFunctionValueParamsCount = closureParams.size
if (declaration.dispatchReceiverParameter != null) kFunctionValueParamsCount--
if (declaration.extensionReceiverParameter != null) kFunctionValueParamsCount--
assert(kFunctionValueParamsCount >= 0)
// The `getter` function takes only closure parameters
val getterValueParameters = declaration.valueParameters.dropLast(kFunctionValueParamsCount)
val refGetSymbol = JsSymbolBuilder.buildSimpleFunction(declaration.descriptor.containingDeclaration, getterName).apply {
initialize(
valueParameters = getterValueParameters.mapIndexed { i, p -> p.descriptor.copyAsValueParameter(descriptor, i) },
type = callableType
)
}
return JsIrBuilder.buildFunction(refGetSymbol).apply {
for (i in 0 until getterValueParameters.size) {
val p = getterValueParameters[i]
valueParameters += IrValueParameterImpl(p.startOffset, p.endOffset, p.origin, refGetSymbol.descriptor.valueParameters[i])
}
}
}
private fun buildClosureFunction(declaration: IrFunction, refGetFunction: IrSimpleFunction): IrFunction {
val closureName = createClosureInstanceName(declaration.descriptor)
val refClosureSymbol = JsSymbolBuilder.buildSimpleFunction(refGetFunction.descriptor, closureName)
// the params which are passed to closure
val closureParamSymbols = generateSignatureForClosure(declaration.symbol, refGetFunction.symbol, refClosureSymbol)
val closureParamDescriptors = closureParamSymbols.map { it.descriptor as ValueParameterDescriptor }
refClosureSymbol.initialize(valueParameters = closureParamDescriptors, type = declaration.returnType)
return JsIrBuilder.buildFunction(refClosureSymbol).apply {
for (it in closureParamSymbols) {
valueParameters += JsIrBuilder.buildValueParameter(it)
}
val irCall = JsIrBuilder.buildCall(declaration.symbol)
var p = 0
declaration.dispatchReceiverParameter?.run { irCall.dispatchReceiver = JsIrBuilder.buildGetValue(closureParamSymbols[p++]) }
declaration.extensionReceiverParameter?.run { irCall.extensionReceiver = JsIrBuilder.buildGetValue(closureParamSymbols[p++]) }
var j = 0
for (v in refGetFunction.valueParameters) {
irCall.putValueArgument(j++, JsIrBuilder.buildGetValue(v.symbol))
}
for (i in p until closureParamSymbols.size) {
irCall.putValueArgument(j++, JsIrBuilder.buildGetValue(closureParamSymbols[i]))
}
val irClosureReturn = JsIrBuilder.buildReturn(symbol, irCall)
body = JsIrBuilder.buildBlockBody(listOf(irClosureReturn))
}
}
}
@@ -1,183 +0,0 @@
/*
* Copyright 2010-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license
* that can be found in the license/LICENSE.txt file.
*/
package org.jetbrains.kotlin.ir.backend.js.lower
import org.jetbrains.kotlin.backend.common.DeclarationContainerLoweringPass
import org.jetbrains.kotlin.backend.common.FileLoweringPass
import org.jetbrains.kotlin.backend.common.lower.copyAsValueParameter
import org.jetbrains.kotlin.backend.common.runOnFilePostfix
import org.jetbrains.kotlin.descriptors.ValueParameterDescriptor
import org.jetbrains.kotlin.ir.IrElement
import org.jetbrains.kotlin.ir.backend.js.JsIrBackendContext
import org.jetbrains.kotlin.ir.backend.js.descriptors.JsSymbolBuilder
import org.jetbrains.kotlin.ir.backend.js.descriptors.initialize
import org.jetbrains.kotlin.ir.backend.js.ir.JsIrBuilder
import org.jetbrains.kotlin.ir.declarations.*
import org.jetbrains.kotlin.ir.declarations.impl.IrValueParameterImpl
import org.jetbrains.kotlin.ir.expressions.IrExpression
import org.jetbrains.kotlin.ir.expressions.IrFunctionReference
import org.jetbrains.kotlin.ir.expressions.copyTypeArgumentsFrom
import org.jetbrains.kotlin.ir.expressions.impl.IrCallImpl
import org.jetbrains.kotlin.ir.symbols.IrFunctionSymbol
import org.jetbrains.kotlin.ir.util.transformFlat
import org.jetbrains.kotlin.ir.visitors.*
import org.jetbrains.kotlin.resolve.descriptorUtil.fqNameSafe
import org.jetbrains.kotlin.types.KotlinType
// TODO replace with DeclarationContainerLowerPass && do flatTransform
class FunctionReferenceLowering(val context: JsIrBackendContext) : FileLoweringPass, DeclarationContainerLoweringPass {
private val lambdas = mutableMapOf<IrDeclaration, KotlinType>()
private val oldToNewDeclarationMap = mutableMapOf<IrFunctionSymbol, IrFunction>()
override fun lower(irFile: IrFile) {
irFile.acceptVoid(FunctionReferenceCollector())
runOnFilePostfix(irFile)
irFile.transformChildrenVoid(FunctionReferenceVisitor())
}
inner class FunctionReferenceCollector : IrElementVisitorVoid {
override fun visitFunctionReference(expression: IrFunctionReference) {
lambdas[expression.symbol.owner as IrFunction] = expression.type
}
override fun visitElement(element: IrElement) {
element.acceptChildrenVoid(this)
}
}
override fun lower(irDeclarationContainer: IrDeclarationContainer) {
irDeclarationContainer.declarations.transformFlat { d ->
if (d is IrFunction) {
lambdas[d]?.let {
lowerKFunctionReference(d, it)
}
} else null
}
}
inner class FunctionReferenceVisitor : IrElementTransformerVoid() {
override fun visitFunctionReference(expression: IrFunctionReference): IrExpression {
val newTarget = oldToNewDeclarationMap[expression.symbol]
return if (newTarget != null) IrCallImpl(expression.startOffset, expression.endOffset, newTarget.symbol, expression.origin).apply {
copyTypeArgumentsFrom(expression)
var index = 0
for (i in 0 until expression.valueArgumentsCount) {
val arg = expression.getValueArgument(i)
if (arg != null) {
putValueArgument(index++, arg)
}
}
} else expression
}
}
private fun createClosureGetterName(declaration: IrFunction) = createHelperFunctionName(declaration, "KreferenceGet")
private fun createClosureInstanceName(declaration: IrFunction) = createHelperFunctionName(declaration, "KreferenceClosure")
private fun createHelperFunctionName(declaration: IrFunction, suffix: String): String {
val nameBuilder = StringBuilder()
if (declaration is IrConstructor) {
nameBuilder.append(declaration.descriptor.constructedClass.fqNameSafe)
nameBuilder.append('_')
}
nameBuilder.append(declaration.descriptor.name)
nameBuilder.append('_')
nameBuilder.append(suffix)
return nameBuilder.toString()
}
private fun lowerKFunctionReference(declaration: IrFunction, functionType: KotlinType): List<IrFunction> {
// TODO: property reference
// transform
// x = Foo::bar ->
// x = Foo_bar_KreferenceGet(c1: closure$C1, c2: closure$C2) : KFunctionN<Foo, T2, ..., TN, TReturn> {
// return fun Foo_bar_KreferenceClosure(p0: Foo, p1: T2, p2: T3): TReturn {
// return p0.bar(c1, c2, p1, p2)
// }
// }
// KFunctionN<Foo, T2, ..., TN, TReturn>, arguments.size = N + 1
val closureParams = functionType.arguments.dropLast(1) // drop return type
var kFunctionValueParamsCount = closureParams.size
if (declaration.dispatchReceiverParameter != null) kFunctionValueParamsCount--
if (declaration.extensionReceiverParameter != null) kFunctionValueParamsCount--
assert(kFunctionValueParamsCount >= 0)
// The `getter` function takes only parameters which have to be closured
val getterValueParameters = declaration.valueParameters.dropLast(kFunctionValueParamsCount)
val getterName = createClosureGetterName(declaration)
val refGetSymbol =
JsSymbolBuilder.buildSimpleFunction(declaration.descriptor.containingDeclaration, getterName).apply {
initialize(
valueParameters = getterValueParameters.mapIndexed { i, p -> p.descriptor.copyAsValueParameter(this.descriptor, i) },
type = functionType
)
}
val refGetFunction = JsIrBuilder.buildFunction(refGetSymbol).apply {
getterValueParameters.mapIndexed { i, p ->
valueParameters += IrValueParameterImpl(p.startOffset, p.endOffset, p.origin, refGetSymbol.descriptor.valueParameters[i])
}
}
val closureName = createClosureInstanceName(declaration)
val refClosureSymbol = JsSymbolBuilder.buildSimpleFunction(refGetSymbol.descriptor, closureName)
// the params which are passed to closure
val closureParamSymbols = closureParams.mapIndexed { index, p ->
// TODO: re-use original parameter names
JsSymbolBuilder.buildValueParameter(refClosureSymbol, index, p.type)
}
val closureParamDescriptors = closureParamSymbols.map { it.descriptor as ValueParameterDescriptor }
refClosureSymbol.initialize(valueParameters = closureParamDescriptors, type = declaration.returnType)
JsIrBuilder.buildFunction(refClosureSymbol).apply {
closureParamSymbols.forEach { valueParameters += JsIrBuilder.buildValueParameter(it) }
val irClosureCall = JsIrBuilder.buildCall(declaration.symbol).apply {
var p = 0
if (declaration.dispatchReceiverParameter != null) {
dispatchReceiver = JsIrBuilder.buildGetValue(closureParamSymbols[p++])
}
if (declaration.extensionReceiverParameter != null) {
extensionReceiver = JsIrBuilder.buildGetValue(closureParamSymbols[p++])
}
var j = 0
refGetFunction.valueParameters.forEach { v ->
putValueArgument(j++, JsIrBuilder.buildGetValue(v.symbol))
}
closureParamSymbols.drop(p).forEach { v ->
putValueArgument(j++, JsIrBuilder.buildGetValue(v))
}
}
val irClosureReturn = JsIrBuilder.buildReturn(refClosureSymbol, irClosureCall)
body = JsIrBuilder.buildBlockBody(listOf(irClosureReturn))
}
refGetFunction.apply {
val irClosureReference = JsIrBuilder.buildFunctionReference(functionType, refClosureSymbol)
val irGetterReturn = JsIrBuilder.buildReturn(refGetSymbol, irClosureReference)
body = JsIrBuilder.buildBlockBody(listOf(irGetterReturn))
}
oldToNewDeclarationMap[declaration.symbol] = refGetFunction
return listOf(declaration, refGetFunction)
}
}
@@ -6,8 +6,10 @@
package org.jetbrains.kotlin.ir.backend.js.lower
import org.jetbrains.kotlin.backend.common.FileLoweringPass
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
import org.jetbrains.kotlin.ir.UNDEFINED_OFFSET
import org.jetbrains.kotlin.ir.backend.js.JsIrBackendContext
import org.jetbrains.kotlin.ir.backend.js.utils.Namer
import org.jetbrains.kotlin.ir.declarations.IrFile
import org.jetbrains.kotlin.ir.declarations.IrFunction
import org.jetbrains.kotlin.ir.declarations.IrSimpleFunction
@@ -20,6 +22,7 @@ import org.jetbrains.kotlin.ir.expressions.impl.IrConstImpl
import org.jetbrains.kotlin.ir.symbols.IrFunctionSymbol
import org.jetbrains.kotlin.ir.visitors.IrElementTransformerVoid
import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.resolve.DescriptorUtils
import org.jetbrains.kotlin.types.KotlinType
import org.jetbrains.kotlin.types.SimpleType
import org.jetbrains.kotlin.util.OperatorNameConventions
@@ -30,11 +33,16 @@ class IntrinsicifyCallsLowering(private val context: JsIrBackendContext) : FileL
private val memberToTransformer: Map<SimpleMemberKey, (IrCall) -> IrCall>
private val memberToIrFunction: Map<SimpleMemberKey, IrSimpleFunction>
private val symbolToIrFunction: Map<IrFunctionSymbol, IrSimpleFunction>
private val nameToIrTransformer: Map<Name, (IrCall) -> IrCall>
val kCallable = context.builtIns.getBuiltInClassByFqName(KotlinBuiltIns.FQ_NAMES.kCallable.toSafe())
val kProperty = context.builtIns.getBuiltInClassByFqName(KotlinBuiltIns.FQ_NAMES.kProperty.asSingleFqName())
init {
memberToIrFunction = mutableMapOf()
symbolToIrFunction = mutableMapOf()
memberToTransformer = mutableMapOf()
nameToIrTransformer = mutableMapOf()
val primitiveNumbers = context.irBuiltIns.run { listOf(int, short, byte, float, double) }
@@ -103,6 +111,25 @@ class IntrinsicifyCallsLowering(private val context: JsIrBackendContext) : FileL
}
}
}
nameToIrTransformer.run {
addWithPredicate(
Name.special(Namer.KCALLABLE_GET_NAME),
{ call -> call.symbol.owner.dispatchReceiverParameter?.run { DescriptorUtils.isSubtypeOfClass(type, kCallable) } ?: false },
{ call -> irCall(call, context.intrinsics.jsName.symbol, dispatchReceiverAsFirstArgument = true) })
addWithPredicate(
Name.identifier(Namer.KPROPERTY_GET),
{ call -> call.symbol.owner.dispatchReceiverParameter?.run { DescriptorUtils.isSubtypeOfClass(type, kProperty) } ?: false },
{ call -> irCall(call, context.intrinsics.jsPropertyGet.symbol, dispatchReceiverAsFirstArgument = true)}
)
addWithPredicate(
Name.identifier(Namer.KPROPERTY_SET),
{ call -> call.symbol.owner.dispatchReceiverParameter?.run { DescriptorUtils.isSubtypeOfClass(type, kProperty) } ?: false},
{ call -> irCall(call, context.intrinsics.jsPropertySet.symbol, dispatchReceiverAsFirstArgument = true)}
)
}
}
override fun lower(irFile: IrFile) {
@@ -132,7 +159,12 @@ class IntrinsicifyCallsLowering(private val context: JsIrBackendContext) : FileL
return it(call)
}
}
nameToIrTransformer[symbol.owner.name]?.let {
return it(call)
}
}
}
return call
@@ -196,4 +228,10 @@ private fun <V> MutableMap<IrFunctionSymbol, V>.add(from: IrFunctionSymbol, to:
put(from, to)
}
private fun <K> MutableMap<K, (IrCall) -> IrCall>.addWithPredicate(from: K, predicate: (IrCall) -> Boolean, action: (IrCall) -> IrCall) {
put(from) { call: IrCall -> select({ predicate(call) }, { action(call) }, { call }) }
}
private inline fun <T> select(crossinline predicate: () -> Boolean, crossinline ifTrue: () -> T, crossinline ifFalse: () -> T): T = if (predicate()) ifTrue() else ifFalse()
private data class SimpleMemberKey(val klass: KotlinType, val name: Name)
@@ -6,10 +6,7 @@
package org.jetbrains.kotlin.ir.backend.js.transformers.irToJs
import org.jetbrains.kotlin.ir.backend.js.utils.JsGenerationContext
import org.jetbrains.kotlin.ir.declarations.IrClass
import org.jetbrains.kotlin.ir.declarations.IrConstructor
import org.jetbrains.kotlin.ir.declarations.IrField
import org.jetbrains.kotlin.ir.declarations.IrSimpleFunction
import org.jetbrains.kotlin.ir.declarations.*
import org.jetbrains.kotlin.js.backend.ast.*
class IrDeclarationToJsTransformer : BaseIrElementToJsNodeTransformer<JsStatement, JsGenerationContext> {
@@ -35,4 +32,8 @@ class IrDeclarationToJsTransformer : BaseIrElementToJsNodeTransformer<JsStatemen
)
return jsAssignment(JsNameRef(fieldName, JsThisRef()), initExpression).makeStmt()
}
override fun visitVariable(declaration: IrVariable, context: JsGenerationContext): JsStatement {
return declaration.accept(IrElementToJsStatementTransformer(), context)
}
}
@@ -15,6 +15,7 @@ import org.jetbrains.kotlin.ir.backend.js.utils.isAny
import org.jetbrains.kotlin.ir.declarations.IrClass
import org.jetbrains.kotlin.ir.declarations.IrConstructor
import org.jetbrains.kotlin.ir.declarations.IrSimpleFunction
import org.jetbrains.kotlin.ir.declarations.IrVariable
import org.jetbrains.kotlin.ir.symbols.impl.IrClassSymbolImpl
import org.jetbrains.kotlin.ir.util.isInterface
import org.jetbrains.kotlin.ir.util.isReal
@@ -34,12 +35,12 @@ class JsClassGenerator(private val irClass: IrClass, val context: JsGenerationCo
fun generate(): JsStatement {
maybeGeneratePrimaryConstructor()
val transformer = IrFunctionToJsTransformer()
val transformer = IrDeclarationToJsTransformer()
for (declaration in irClass.declarations) {
when (declaration) {
is IrConstructor -> {
classBlock.statements += declaration.accept(transformer, context).makeStmt()
classBlock.statements += declaration.accept(transformer, context)
classBlock.statements += generateInheritanceCode()
}
is IrSimpleFunction -> {
@@ -48,6 +49,9 @@ class JsClassGenerator(private val irClass: IrClass, val context: JsGenerationCo
is IrClass -> {
classBlock.statements += JsClassGenerator(declaration, context).generate()
}
is IrVariable -> {
classBlock.statements += declaration.accept(transformer, context)
}
else -> {
}
}
@@ -70,6 +70,17 @@ class JsIntrinsicTransformers(backendContext: JsIrBackendContext) {
JsInvocation(Namer.JS_OBJECT_CREATE_FUNCTION, prototype)
}
add(intrinsics.jsSetJSField) { call, context ->
val args = translateCallArguments(call, context)
val receiver = args[0]
val fieldName = args[1] as JsStringLiteral
val fieldValue = args[2]
val fieldNameLiteral = fieldName.value!!
jsAssignment(JsNameRef(fieldNameLiteral, receiver), fieldValue)
}
add(backendContext.sharedVariablesManager.closureBoxConstructorTypeSymbol) { call, context ->
val args = translateCallArguments(call, context)
val initializer = args[0]
@@ -86,6 +97,27 @@ class JsIntrinsicTransformers(backendContext: JsIrBackendContext) {
else -> JsInvocation(JsFunction(context.currentScope, jsCode as? JsBlock ?: JsBlock(jsCode as JsStatement), ""))
}
}
add(intrinsics.jsName) { call: IrCall, context ->
val args = translateCallArguments(call, context)
val receiver = args[0]
JsNameRef(Namer.KCALLABLE_NAME, receiver)
}
add(intrinsics.jsPropertyGet) { call: IrCall, context ->
val args = translateCallArguments(call, context)
val reference = args[0]
val receiver = args[1]
JsInvocation(JsNameRef(Namer.KPROPERTY_GET, reference), listOf(receiver))
}
add(intrinsics.jsPropertySet) { call: IrCall, context ->
val args = translateCallArguments(call, context)
val reference = args[0]
val receiver = args[1]
val value = args[2]
JsInvocation(JsNameRef(Namer.KPROPERTY_SET, reference), listOf(receiver, value))
}
}
}
@@ -37,6 +37,7 @@ object Namer {
val SLICE_FUNCTION = "slice"
val CONCAT_FUNCTION = "concat"
val OUTER_NAME = "\$outer"
val UNREACHABLE_NAME = "\$unreachable"
val OUTER_FIELD_NAME = "\$outer"
@@ -85,6 +86,12 @@ object Namer {
val GETTER_PREFIX = "get_"
val SETTER_PREFIX = "set_"
val KCALLABLE_GET_NAME = "<get-name>"
val KCALLABLE_NAME = "callableName"
val KPROPERTY_GET = "get"
val KPROPERTY_SET = "set"
val KCALLABLE_CACHE_SUFFIX = "\$cache"
val SETTER_ARGUMENT = "\$setValue"
val THIS_SPECIAL_NAME = "<this>"
@@ -6,13 +6,15 @@
package org.jetbrains.kotlin.ir.backend.js.utils
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
import org.jetbrains.kotlin.descriptors.FunctionDescriptor
import org.jetbrains.kotlin.descriptors.ModuleDescriptor
import org.jetbrains.kotlin.descriptors.*
import org.jetbrains.kotlin.descriptors.annotations.Annotations
import org.jetbrains.kotlin.descriptors.impl.ValueParameterDescriptorImpl
import org.jetbrains.kotlin.incremental.components.NoLookupLocation
import org.jetbrains.kotlin.ir.symbols.IrClassSymbol
import org.jetbrains.kotlin.ir.symbols.IrConstructorSymbol
import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.types.KotlinType
val IrConstructorSymbol.constructedClass get() = descriptor.constructedClass
@@ -25,3 +27,27 @@ fun ModuleDescriptor.getFunctions(fqName: FqName): List<FunctionDescriptor> {
fun ModuleDescriptor.getFunctions(packageFqName: FqName, name: Name): List<FunctionDescriptor> {
return getPackage(packageFqName).memberScope.getContributedFunctions(name, NoLookupLocation.FROM_BACKEND).toList()
}
fun ModuleDescriptor.getClassifier(fqName: FqName): ClassifierDescriptor? {
return getClassifier(fqName.parent(), fqName.shortName())
}
fun ModuleDescriptor.getClassifier(packageFqName: FqName, name: Name): ClassifierDescriptor? {
return getPackage(packageFqName).memberScope.getContributedClassifier(name, NoLookupLocation.FROM_BACKEND)
}
fun createValueParameter(containingDeclaration: CallableDescriptor, index: Int, name: String, type: KotlinType): ValueParameterDescriptor {
return ValueParameterDescriptorImpl(
containingDeclaration = containingDeclaration,
original = null,
index = index,
annotations = Annotations.EMPTY,
name = Name.identifier(name),
outType = type,
declaresDefaultValue = false,
isCrossinline = false,
isNoinline = false,
varargElementType = null,
source = SourceElement.NO_SOURCE
)
}
@@ -0,0 +1,24 @@
// EXPECTED_REACHABLE_NODES: 1109
// This test was adapted from compiler/testData/codegen/box/callableReference/function/local/.
package foo
import kotlin.reflect.KFunction
fun foo0() = "OK"
fun foo1(a: String) = "O" + a
fun foo2(a: String, b: String) = a + b
fun refName0(ref: KFunction<String>) = ref.name
//fun refName1(ref: KFunction1<String, String>) = ref.name
//fun refName2(ref: KFunction2<String, String, String>) = ref.name
fun box(): String {
val name = refName0(::foo0)
val f1 = ::foo1
val f2 = ::foo2
if (name != "foo0") return "Fail: " + name
if (f1.name != "foo1") return "Fail: " + f1.name
if (f2.name != "foo2") return "Fail: " + f2.name
return "OK"
}