Initial support of function callable references

This commit is contained in:
Mikhael Bogdanov
2018-08-08 12:13:45 +03:00
parent 06b16a6459
commit 813e1ffa39
8 changed files with 787 additions and 12 deletions
@@ -32,6 +32,7 @@ import org.jetbrains.kotlin.resolve.DescriptorFactory
import org.jetbrains.kotlin.resolve.DescriptorUtils
import org.jetbrains.kotlin.resolve.PropertyImportedFromObject
import org.jetbrains.kotlin.resolve.descriptorUtil.getSuperClassNotAny
import org.jetbrains.kotlin.resolve.jvm.AsmTypes
import org.jetbrains.kotlin.resolve.jvm.AsmTypes.*
import org.jetbrains.kotlin.resolve.jvm.diagnostics.JvmDeclarationOrigin
import org.jetbrains.kotlin.resolve.jvm.jvmSignature.JvmMethodSignature
@@ -195,6 +196,11 @@ class PropertyReferenceCodegen(
@JvmStatic
fun generateCallableReferenceSignature(iv: InstructionAdapter, callable: CallableDescriptor, state: GenerationState) {
iv.aconst(getSignatureString(callable, state))
}
@JvmStatic
fun getSignatureString(callable: CallableDescriptor, state: GenerationState): String {
if (callable is LocalVariableDescriptor) {
val asmType = state.bindingContext.get(CodegenBinding.DELEGATED_PROPERTY_METADATA_OWNER, callable)
?: throw AssertionError("No delegated property metadata owner for $callable")
@@ -203,8 +209,7 @@ class PropertyReferenceCodegen(
if (index < 0) {
throw AssertionError("Local delegated property is not found in $asmType: $callable")
}
iv.aconst("<v#$index>") // v = "variable"
return
return "<v#$index>"
}
val accessor = when (callable) {
@@ -218,7 +223,7 @@ class PropertyReferenceCodegen(
}
val declaration = DescriptorUtils.unwrapFakeOverride(accessor).original
val method = state.typeMapper.mapAsmMethod(declaration)
iv.aconst(method.name + method.descriptor)
return method.name + method.descriptor
}
@JvmStatic
@@ -87,6 +87,30 @@ fun ClassDescriptor.getFunction(name: String, types: List<KotlinType>): Function
.getContributedFunctions(Name.identifier(name), NoLookupLocation.FROM_BACKEND).single().substitute(typeSubstitutor)!!
}
fun ClassDescriptor.getStaticFunction(name: String, types: List<KotlinType>): FunctionDescriptor {
val typeSubstitutor = TypeSubstitutor.create(
declaredTypeParameters
.withIndex()
.associateBy({ it.value.typeConstructor }, { TypeProjectionImpl(types[it.index]) })
)
return staticScope
.getContributedFunctions(Name.identifier(name), NoLookupLocation.FROM_BACKEND).single().substitute(typeSubstitutor)!!
}
fun ClassDescriptor.getProperty(name: String, types: List<KotlinType>): PropertyDescriptor {
val typeSubstitutor = TypeSubstitutor.create(
declaredTypeParameters
.withIndex()
.associateBy({ it.value.typeConstructor }, { TypeProjectionImpl(types[it.index]) })
)
return unsubstitutedMemberScope
.getContributedVariables(
Name.identifier(name),
NoLookupLocation.FROM_BACKEND
).single().substitute(typeSubstitutor) as PropertyDescriptor
}
val KotlinType.isFunctionOrKFunctionType: Boolean
get() {
val kind = constructor.declarationDescriptor?.getFunctionalClassKind()
@@ -175,6 +175,8 @@ abstract class Symbols<out T : CommonBackendContext>(val context: T, private val
val kFunctionImpl = calc { symbolTable.referenceClass(context.reflectionTypes.kFunctionImpl) }
val functionReference = calc { symbolTable.referenceClass(context.getInternalClass("FunctionReference")) }
val kProperty0Impl = calc { symbolTable.referenceClass(context.reflectionTypes.kProperty0Impl) }
val kProperty1Impl = calc { symbolTable.referenceClass(context.reflectionTypes.kProperty1Impl) }
val kProperty2Impl = calc { symbolTable.referenceClass(context.reflectionTypes.kProperty2Impl) }
@@ -239,7 +239,7 @@ fun IrConstructor.callsSuper(): Boolean {
return callsSuper
}
fun ParameterDescriptor.copyAsValueParameter(newOwner: CallableDescriptor, index: Int) = when (this) {
fun ParameterDescriptor.copyAsValueParameter(newOwner: CallableDescriptor, index: Int, name: Name = this.name) = when (this) {
is ValueParameterDescriptor -> this.copy(newOwner, name, index)
is ReceiverParameterDescriptor -> ValueParameterDescriptorImpl(
containingDeclaration = newOwner,
@@ -57,6 +57,7 @@ class JvmLower(val context: JvmBackendContext) {
},
Visibilities.PUBLIC //TODO properly figure out visibility
).runOnFilePostfix(irFile)
CallableReferenceLowering(context).lower(irFile)
EnumClassLowering(context).runOnFilePostfix(irFile)
//Should be before SyntheticAccessorLowering cause of synthetic accessor for companion constructor
@@ -7,6 +7,7 @@ package org.jetbrains.kotlin.backend.jvm.codegen
import org.jetbrains.kotlin.backend.jvm.intrinsics.IrIntrinsicFunction
import org.jetbrains.kotlin.backend.jvm.intrinsics.IrIntrinsicMethods
import org.jetbrains.kotlin.backend.jvm.lower.CrIrType
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
import org.jetbrains.kotlin.codegen.*
import org.jetbrains.kotlin.codegen.AsmUtil.*
@@ -20,6 +21,7 @@ import org.jetbrains.kotlin.codegen.intrinsics.JavaClassProperty
import org.jetbrains.kotlin.codegen.pseudoInsns.fakeAlwaysFalseIfeq
import org.jetbrains.kotlin.codegen.pseudoInsns.fixStackAndJump
import org.jetbrains.kotlin.codegen.signature.BothSignatureWriter
import org.jetbrains.kotlin.codegen.state.GenerationState
import org.jetbrains.kotlin.descriptors.*
import org.jetbrains.kotlin.descriptors.impl.TypeAliasConstructorDescriptor
import org.jetbrains.kotlin.ir.IrElement
@@ -949,13 +951,19 @@ class ExpressionCodegen(
assert(classReference is IrGetClass)
JavaClassProperty.generateImpl(mv, gen((classReference as IrGetClass).argument, data))
} else {
val type = classReference.classType.toKotlinType()
if (TypeUtils.isTypeParameter(type)) {
assert(TypeUtils.isReifiedTypeParameter(type)) { "Non-reified type parameter under ::class should be rejected by type checker: " + type }
putReifiedOperationMarkerIfTypeIsReifiedParameter(type, ReifiedTypeInliner.OperationKind.JAVA_CLASS, mv, this)
}
val classType = classReference.classType
if (classType is CrIrType) {
putJavaLangClassInstance(mv, classType.type)
return
} else {
val type = classType.toKotlinType()
if (TypeUtils.isTypeParameter(type)) {
assert(TypeUtils.isReifiedTypeParameter(type)) { "Non-reified type parameter under ::class should be rejected by type checker: " + type }
putReifiedOperationMarkerIfTypeIsReifiedParameter(type, ReifiedTypeInliner.OperationKind.JAVA_CLASS, mv, this)
}
putJavaLangClassInstance(mv, typeMapper.mapType(type))
putJavaLangClassInstance(mv, typeMapper.mapType(type))
}
}
if (wrapIntoKClass) {
@@ -1025,7 +1033,7 @@ class ExpressionCodegen(
// We should inline callable containing reified type parameters even if inline is disabled
// because they may contain something to reify and straight call will probably fail at runtime
val isInline = (!state.isInlineDisabled || InlineUtil.containsReifiedTypeParameters(descriptor)) && (InlineUtil.isInline(descriptor) || InlineUtil.isArrayConstructorWithLambda(descriptor))
val isInline = descriptor.isInlineCall(state)
if (!isInline) return IrCallGenerator.DefaultCallGenerator
@@ -1130,3 +1138,7 @@ fun DefaultCallArgs.generateOnStackIfNeeded(callGenerator: IrCallGenerator, isCo
}
return toInts.isNotEmpty()
}
internal fun CallableDescriptor.isInlineCall(state: GenerationState) =
(!state.isInlineDisabled || InlineUtil.containsReifiedTypeParameters(this)) &&
(InlineUtil.isInline(this) || InlineUtil.isArrayConstructorWithLambda(this))
@@ -0,0 +1,728 @@
/*
* Copyright 2010-2017 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jetbrains.kotlin.backend.jvm.lower
import org.jetbrains.kotlin.backend.common.FileLoweringPass
import org.jetbrains.kotlin.backend.common.IrElementTransformerVoidWithContext
import org.jetbrains.kotlin.backend.common.descriptors.*
import org.jetbrains.kotlin.backend.common.ir.createFakeOverrideDescriptor
import org.jetbrains.kotlin.backend.common.lower.*
import org.jetbrains.kotlin.backend.jvm.JvmBackendContext
import org.jetbrains.kotlin.backend.jvm.codegen.isInlineCall
import org.jetbrains.kotlin.backend.jvm.codegen.isInlineIrExpression
import org.jetbrains.kotlin.backend.jvm.descriptors.JvmPropertyDescriptorImpl
import org.jetbrains.kotlin.codegen.PropertyReferenceCodegen
import org.jetbrains.kotlin.codegen.binding.CodegenBinding
import org.jetbrains.kotlin.descriptors.*
import org.jetbrains.kotlin.descriptors.SourceElement.NO_SOURCE
import org.jetbrains.kotlin.descriptors.annotations.Annotations
import org.jetbrains.kotlin.descriptors.impl.*
import org.jetbrains.kotlin.incremental.components.NoLookupLocation
import org.jetbrains.kotlin.ir.UNDEFINED_OFFSET
import org.jetbrains.kotlin.ir.builders.*
import org.jetbrains.kotlin.ir.declarations.*
import org.jetbrains.kotlin.ir.declarations.impl.*
import org.jetbrains.kotlin.ir.expressions.*
import org.jetbrains.kotlin.ir.expressions.impl.IrClassReferenceImpl
import org.jetbrains.kotlin.ir.expressions.impl.IrConstImpl
import org.jetbrains.kotlin.ir.expressions.impl.IrDelegatingConstructorCallImpl
import org.jetbrains.kotlin.ir.expressions.impl.IrInstanceInitializerCallImpl
import org.jetbrains.kotlin.ir.symbols.*
import org.jetbrains.kotlin.ir.symbols.impl.IrConstructorSymbolImpl
import org.jetbrains.kotlin.ir.symbols.impl.IrFieldSymbolImpl
import org.jetbrains.kotlin.ir.symbols.impl.IrSimpleFunctionSymbolImpl
import org.jetbrains.kotlin.ir.types.IrSimpleType
import org.jetbrains.kotlin.ir.types.IrType
import org.jetbrains.kotlin.ir.types.impl.IrSimpleTypeImpl
import org.jetbrains.kotlin.ir.types.impl.makeTypeProjection
import org.jetbrains.kotlin.ir.types.toIrType
import org.jetbrains.kotlin.ir.types.toKotlinType
import org.jetbrains.kotlin.ir.util.*
import org.jetbrains.kotlin.ir.visitors.transformChildrenVoid
import org.jetbrains.kotlin.load.java.JavaVisibilities
import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.resolve.DescriptorUtils
import org.jetbrains.kotlin.resolve.inline.InlineUtil
import org.jetbrains.kotlin.storage.LockBasedStorageManager
import org.jetbrains.kotlin.types.KotlinType
import org.jetbrains.kotlin.types.TypeUtils
import org.jetbrains.kotlin.types.Variance
import org.jetbrains.org.objectweb.asm.Opcodes
import org.jetbrains.org.objectweb.asm.Type
//Hack implementation to support CR java types in lower
class CrIrType(val type: Type) : IrType {
override val annotations = emptyList()
}
//Originally was copied from K/Native
class CallableReferenceLowering(val context: JvmBackendContext) : FileLoweringPass {
object DECLARATION_ORIGIN_FUNCTION_REFERENCE_IMPL : IrDeclarationOriginImpl("FUNCTION_REFERENCE_IMPL")
private var functionReferenceCount = 0
private val inlineLambdaReferences = mutableSetOf<IrFunctionReference>()
override fun lower(irFile: IrFile) {
irFile.transformChildrenVoid(object : IrElementTransformerVoidWithContext() {
override fun visitCall(expression: IrCall): IrExpression {
val descriptor = expression.descriptor
if (descriptor.isInlineCall(context.state)) {
//TODO: more wise filtering
descriptor.valueParameters.map { valueParameter ->
if (InlineUtil.isInlineParameter(valueParameter)) {
expression.getValueArgument(valueParameter.index)?.let {
if (isInlineIrExpression(it)) {
(it as IrBlock).statements.filterIsInstance<IrFunctionReference>().forEach { reference ->
inlineLambdaReferences.add(reference)
}
}
}
}
}
}
//TODO: clean
return super.visitCall(expression)
}
override fun visitFunctionReference(expression: IrFunctionReference): IrExpression {
expression.transformChildrenVoid(this)
if (!expression.type.toKotlinType().isFunctionOrKFunctionType || inlineLambdaReferences.contains(expression)) {
// Not a subject of this lowering.
return expression
}
val loweredFunctionReference = FunctionReferenceBuilder(currentScope!!.scope.scopeOwner, expression).build()
val irBuilder = context.createIrBuilder(currentScope!!.scope.scopeOwnerSymbol, expression.startOffset, expression.endOffset)
return irBuilder.irBlock(expression) {
+loweredFunctionReference.functionReferenceClass
+irCall(loweredFunctionReference.functionReferenceConstructor.symbol).apply {
expression.getArguments().forEachIndexed { index, argument ->
putValueArgument(index, argument.second)
}
}
}
}
})
}
private class BuiltFunctionReference(
val functionReferenceClass: IrClass,
val functionReferenceConstructor: IrConstructor
)
private val kotlinPackageScope = context.builtIns.builtInsPackageScope
private val continuationClassDescriptor = context.getClass(FqName("kotlin.coroutines.experimental.Continuation"))
//private val getContinuationSymbol = context.ir.symbols.getContinuation
private inner class FunctionReferenceBuilder(
val containingDeclaration: DeclarationDescriptor,
val irFunctionReference: IrFunctionReference
) {
private val functionDescriptor = irFunctionReference.descriptor
private val functionParameters = functionDescriptor.explicitParameters
private val boundFunctionParameters = irFunctionReference.getArguments().map { it.first }
private val unboundFunctionParameters = functionParameters - boundFunctionParameters
private lateinit var functionReferenceClassDescriptor: ClassDescriptorImpl
private lateinit var functionReferenceClass: IrClassImpl
private lateinit var functionReferenceThis: IrValueParameterSymbol
private lateinit var argumentToPropertiesMap: Map<ParameterDescriptor, IrFieldSymbol>
private val functionReference = context.ir.symbols.functionReference
fun build(): BuiltFunctionReference {
val startOffset = irFunctionReference.startOffset
val endOffset = irFunctionReference.endOffset
val returnType = functionDescriptor.returnType!!
val superTypes: MutableList<KotlinType> = mutableListOf(
functionReference.descriptor.defaultType
)
val numberOfParameters = unboundFunctionParameters.size
val functionClassDescriptor = context.getClass(FqName("kotlin.jvm.functions.Function$numberOfParameters"))
val functionParameterTypes = unboundFunctionParameters.map { it.type }
val functionClassTypeParameters = functionParameterTypes + returnType
superTypes += functionClassDescriptor.defaultType.replace(functionClassTypeParameters)
var suspendFunctionClassDescriptor: ClassDescriptor? = null
var suspendFunctionClassTypeParameters: List<KotlinType>? = null
val lastParameterType = unboundFunctionParameters.lastOrNull()?.type
if (lastParameterType != null && TypeUtils.getClassDescriptor(lastParameterType) == continuationClassDescriptor) {
// If the last parameter is Continuation<> inherit from SuspendFunction.
suspendFunctionClassDescriptor = kotlinPackageScope.getContributedClassifier(
Name.identifier("SuspendFunction${numberOfParameters - 1}"), NoLookupLocation.FROM_BACKEND
) as ClassDescriptor
suspendFunctionClassTypeParameters = functionParameterTypes.dropLast(1) + lastParameterType.arguments.single().type
superTypes += suspendFunctionClassDescriptor.defaultType.replace(suspendFunctionClassTypeParameters)
}
functionReferenceClassDescriptor = ClassDescriptorImpl(
/* containingDeclaration = */ containingDeclaration,
/* name = */ "${functionDescriptor.name}\$${functionReferenceCount++}".synthesizedName,
/* modality = */ Modality.FINAL,
/* kind = */ ClassKind.CLASS,
/* superTypes = */ superTypes,
/* source = */ /*TODO*/ (containingDeclaration as? DeclarationDescriptorWithSource)?.source ?: NO_SOURCE,
/* isExternal = */ false,
LockBasedStorageManager.NO_LOCKS
)
functionReferenceClass = IrClassImpl(
startOffset = startOffset,
endOffset = endOffset,
origin = DECLARATION_ORIGIN_FUNCTION_REFERENCE_IMPL,
descriptor = functionReferenceClassDescriptor
)
val contributedDescriptors = mutableListOf<DeclarationDescriptor>()
val constructorBuilder = createConstructorBuilder()
functionReferenceClassDescriptor.initialize(
SimpleMemberScope(contributedDescriptors), setOf(constructorBuilder.symbol.descriptor), null
)
functionReferenceClass.createParameterDeclarations()
functionReferenceThis = functionReferenceClass.thisReceiver!!.symbol
val invokeFunctionDescriptor = functionClassDescriptor.getFunction("invoke", functionClassTypeParameters)
val invokeMethodBuilder = createInvokeMethodBuilder(invokeFunctionDescriptor)
val getSignatureBuilder =
createGetSignatureMethodBuilder(functionReference.owner.descriptor.getFunction("getSignature", emptyList()))
val getNameBuilder = createGetNameMethodBuilder(functionReference.owner.descriptor.getProperty("name", emptyList()))
val getOwnerBuilder = createGetOwnerMethodBuilder(functionReference.owner.descriptor.getFunction("getOwner", emptyList()))
val suspendInvokeMethodBuilder =
if (suspendFunctionClassDescriptor != null) {
val suspendInvokeFunctionDescriptor =
suspendFunctionClassDescriptor.getFunction("invoke", suspendFunctionClassTypeParameters!!)
createInvokeMethodBuilder(suspendInvokeFunctionDescriptor)
} else null
val inheritedScope = functionReference.descriptor.unsubstitutedMemberScope
.getContributedDescriptors().mapNotNull { it.createFakeOverrideDescriptor(functionReferenceClassDescriptor) }
.filterNot { it.name.asString() == "getSignature" || it.name.asString() == "name" || it.name.asString() == "getOwner" }
contributedDescriptors.addAll(
(
inheritedScope + invokeMethodBuilder.symbol.descriptor +
suspendInvokeMethodBuilder?.symbol?.descriptor + getSignatureBuilder.symbol.descriptor
).filterNotNull()
)
constructorBuilder.initialize()
functionReferenceClass.declarations.add(constructorBuilder.ir)
invokeMethodBuilder.initialize()
functionReferenceClass.declarations.add(invokeMethodBuilder.ir)
getSignatureBuilder.initialize()
functionReferenceClass.declarations.add(getSignatureBuilder.ir)
getNameBuilder.initialize()
functionReferenceClass.declarations.add(getNameBuilder.ir)
getOwnerBuilder.initialize()
functionReferenceClass.declarations.add(getOwnerBuilder.ir)
suspendInvokeMethodBuilder?.let {
it.initialize()
functionReferenceClass.declarations.add(it.ir)
}
return BuiltFunctionReference(functionReferenceClass, constructorBuilder.ir)
}
private fun createConstructorBuilder() = object : SymbolWithIrBuilder<IrConstructorSymbol, IrConstructor>() {
private val kFunctionRefConstructorSymbol =
functionReference.constructors.filter { it.descriptor.valueParameters.size == 2 }.single()
override fun buildSymbol() = IrConstructorSymbolImpl(
ClassConstructorDescriptorImpl.create(
/* containingDeclaration = */ functionReferenceClassDescriptor,
/* annotations = */ Annotations.EMPTY,
/* isPrimary = */ false,
/* source = */ SourceElement.NO_SOURCE
)
)
override fun doInitialize() {
val descriptor = symbol.descriptor as ClassConstructorDescriptorImpl
val constructorParameters = boundFunctionParameters.mapIndexed { index, parameter ->
parameter.copyAsValueParameter(descriptor, index, parameter.name)
}
descriptor.initialize(constructorParameters, Visibilities.PUBLIC)
descriptor.returnType = functionReferenceClassDescriptor.defaultType
}
override fun buildIr(): IrConstructor {
argumentToPropertiesMap = boundFunctionParameters.associate {
it to buildPropertyWithBackingField(it.name.safeName(), it.type, false)
}
val startOffset = irFunctionReference.startOffset
val endOffset = irFunctionReference.endOffset
return IrConstructorImpl(
startOffset = startOffset,
endOffset = endOffset,
origin = DECLARATION_ORIGIN_FUNCTION_REFERENCE_IMPL,
symbol = symbol
).apply {
returnType = symbol.descriptor.returnType.toIrType()!!
val irBuilder = context.createIrBuilder(this.symbol, startOffset, endOffset)
createParameterDeclarations()
body = irBuilder.irBlockBody {
+IrDelegatingConstructorCallImpl(
startOffset, endOffset, context.irBuiltIns.unitType,
kFunctionRefConstructorSymbol, kFunctionRefConstructorSymbol.descriptor
).apply {
val const =
IrConstImpl.int(startOffset, endOffset, context.irBuiltIns.intType, unboundFunctionParameters.size)
putValueArgument(0, const)
val irReceiver = valueParameters.firstOrNull()
val receiver = boundFunctionParameters.singleOrNull()
val receiverValue = receiver?.let {
irGet(irReceiver!!.symbol.owner)
} ?: irNull()
putValueArgument(1, receiverValue)
//TODO use receiver from base class
receiver?.let {
+irSetField(irGet(functionReferenceThis.owner), argumentToPropertiesMap[it]!!.owner, receiverValue)
}
}
+IrInstanceInitializerCallImpl(startOffset, endOffset, functionReferenceClass.symbol, context.irBuiltIns.unitType)
// Save all arguments to fields.
}
}
}
}
private fun createInvokeMethodBuilder(superFunctionDescriptor: FunctionDescriptor) =
object : SymbolWithIrBuilder<IrSimpleFunctionSymbol, IrSimpleFunction>() {
override fun buildSymbol() = IrSimpleFunctionSymbolImpl(
SimpleFunctionDescriptorImpl.create(
/* containingDeclaration = */ functionReferenceClassDescriptor,
/* annotations = */ Annotations.EMPTY,
/* name = */ Name.identifier("invoke"),
/* kind = */ CallableMemberDescriptor.Kind.DECLARATION,
/* source = */ SourceElement.NO_SOURCE
)
)
override fun doInitialize() {
val descriptor = symbol.descriptor as SimpleFunctionDescriptorImpl
val valueParameters = superFunctionDescriptor.valueParameters
.map { it.copyAsValueParameter(descriptor, it.index) }
descriptor.initialize(
/* receiverParameterType = */ null,
/* dispatchReceiverParameter = */ functionReferenceClassDescriptor.thisAsReceiverParameter,
/* typeParameters = */ emptyList(),
/* unsubstitutedValueParameters = */ valueParameters,
/* unsubstitutedReturnType = */ superFunctionDescriptor.returnType,
/* modality = */ Modality.FINAL,
/* visibility = */ Visibilities.PUBLIC
).apply {
overriddenDescriptors += superFunctionDescriptor
isSuspend = superFunctionDescriptor.isSuspend
}
}
override fun buildIr(): IrSimpleFunction {
val startOffset = irFunctionReference.startOffset
val endOffset = irFunctionReference.endOffset
val ourSymbol = symbol
return IrFunctionImpl(
startOffset = startOffset,
endOffset = endOffset,
origin = DECLARATION_ORIGIN_FUNCTION_REFERENCE_IMPL,
symbol = ourSymbol
).apply {
val function = this
val irBuilder = context.createIrBuilder(function.symbol, startOffset, endOffset)
returnType = ourSymbol.descriptor.returnType!!.toIrType()!!
createParameterDeclarations()
body = irBuilder.irBlockBody(startOffset, endOffset) {
+irReturn(
irCall(irFunctionReference.symbol).apply {
var unboundIndex = 0
val unboundArgsSet = unboundFunctionParameters.toSet()
functionParameters.forEach {
val argument =
if (!unboundArgsSet.contains(it))
// Bound parameter - read from field.
irGetField(irGet(functionReferenceThis.owner), argumentToPropertiesMap[it]!!.owner)
else {
if (ourSymbol.descriptor.isSuspend && unboundIndex == valueParameters.size)
// For suspend functions the last argument is continuation and it is implicit.
TODO()
// irCall(getContinuationSymbol,
// listOf(ourSymbol.descriptor.returnType!!))
else
irGet(valueParameters[unboundIndex++])
}
when (it) {
functionDescriptor.dispatchReceiverParameter -> dispatchReceiver = argument
functionDescriptor.extensionReceiverParameter -> extensionReceiver = argument
else -> putValueArgument((it as ValueParameterDescriptor).index, argument)
}
}
assert(unboundIndex == valueParameters.size) { "Not all arguments of <invoke> are used" }
}
)
}
}
}
}
private fun buildPropertyWithBackingField(name: Name, type: KotlinType, isMutable: Boolean): IrFieldSymbol {
val fieldSymbol = IrFieldSymbolImpl(
JvmPropertyDescriptorImpl.createFinalField(
Name.identifier("this$0"), type, functionReferenceClassDescriptor,
Annotations.EMPTY, JavaVisibilities.PACKAGE_VISIBILITY, Opcodes.ACC_SYNTHETIC, SourceElement.NO_SOURCE
)
)
val field = IrFieldImpl(
irFunctionReference.startOffset,
irFunctionReference.endOffset,
DECLARATION_ORIGIN_FUNCTION_REFERENCE_IMPL,
fieldSymbol,
type.toIrType()!!
)
functionReferenceClass.declarations.add(field)
return fieldSymbol
}
private fun createGetNameMethodBuilder(superNameProperty: PropertyDescriptor) =
object : SymbolWithIrBuilder<IrSimpleFunctionSymbol, IrSimpleFunction>() {
override fun buildSymbol() = IrSimpleFunctionSymbolImpl(
PropertyDescriptorImpl.create(
/* containingDeclaration = */ functionReferenceClassDescriptor,
/* annotations = */ Annotations.EMPTY,
superNameProperty.modality,
superNameProperty.visibility,
false,
/* name = */ superNameProperty.name,
/* kind = */ CallableMemberDescriptor.Kind.DECLARATION,
/* source = */ SourceElement.NO_SOURCE,
false, false, false, false, false, false
).let { property ->
property.overriddenDescriptors += superNameProperty
PropertyGetterDescriptorImpl(
property,
Annotations.EMPTY,
Modality.OPEN,
Visibilities.PUBLIC,
false, false, false,
CallableMemberDescriptor.Kind.DECLARATION,
null,
SourceElement.NO_SOURCE
).also {
property.initialize(it, null)
property.setType(
/* outType = */ superNameProperty.type,
/* typeParameters = */ superNameProperty.typeParameters,
/* dispatchReceiverParameter = */ superNameProperty.dispatchReceiverParameter,
/* receiverType = */ superNameProperty.extensionReceiverParameter?.type
)
//overriddenDescriptors += superNameProperty.getter
}
}
)
override fun doInitialize() {
val descriptor = symbol.descriptor as PropertyGetterDescriptorImpl
descriptor.initialize(superNameProperty.type)
}
override fun buildIr(): IrSimpleFunction {
val startOffset = irFunctionReference.startOffset
val endOffset = irFunctionReference.endOffset
val ourSymbol = symbol
return IrFunctionImpl(
startOffset = startOffset,
endOffset = endOffset,
origin = DECLARATION_ORIGIN_FUNCTION_REFERENCE_IMPL,
symbol = ourSymbol
).apply {
val function = this
val irBuilder = context.createIrBuilder(function.symbol, startOffset, endOffset)
returnType = ourSymbol.descriptor.returnType!!.toIrType()!!
createParameterDeclarations()
body = irBuilder.irBlockBody(startOffset, endOffset) {
+irReturn(
IrConstImpl.string(-1, -1, context.irBuiltIns.stringType, functionDescriptor.name.asString())
)
}
}
}
}
private fun createGetSignatureMethodBuilder(superFunctionDescriptor: FunctionDescriptor) =
object : SymbolWithIrBuilder<IrSimpleFunctionSymbol, IrSimpleFunction>() {
override fun buildSymbol() = IrSimpleFunctionSymbolImpl(
SimpleFunctionDescriptorImpl.create(
/* containingDeclaration = */ functionReferenceClassDescriptor,
/* annotations = */ Annotations.EMPTY,
/* name = */ Name.identifier("getSignature"),
/* kind = */ CallableMemberDescriptor.Kind.DECLARATION,
/* source = */ SourceElement.NO_SOURCE
)
)
override fun doInitialize() {
val descriptor = symbol.descriptor as SimpleFunctionDescriptorImpl
val valueParameters = superFunctionDescriptor.valueParameters
.map { it.copyAsValueParameter(descriptor, it.index) }
descriptor.initialize(
/* receiverParameterType = */ null,
/* dispatchReceiverParameter = */ functionReferenceClassDescriptor.thisAsReceiverParameter,
/* typeParameters = */ emptyList(),
/* unsubstitutedValueParameters = */ valueParameters,
/* unsubstitutedReturnType = */ superFunctionDescriptor.returnType,
/* modality = */ Modality.FINAL,
/* visibility = */ Visibilities.PUBLIC
).apply {
overriddenDescriptors += superFunctionDescriptor
isSuspend = superFunctionDescriptor.isSuspend
}
}
override fun buildIr(): IrSimpleFunction {
val startOffset = irFunctionReference.startOffset
val endOffset = irFunctionReference.endOffset
val ourSymbol = symbol
return IrFunctionImpl(
startOffset = startOffset,
endOffset = endOffset,
origin = DECLARATION_ORIGIN_FUNCTION_REFERENCE_IMPL,
symbol = ourSymbol
).apply {
val function = this
val irBuilder = context.createIrBuilder(function.symbol, startOffset, endOffset)
returnType = ourSymbol.descriptor.returnType!!.toIrType()!!
createParameterDeclarations()
body = irBuilder.irBlockBody(startOffset, endOffset) {
+irReturn(
IrConstImpl.string(
-1, -1, context.irBuiltIns.stringType,
PropertyReferenceCodegen.getSignatureString(
irFunctionReference.symbol.descriptor, this@CallableReferenceLowering.context.state
)
)
)
}
}
}
}
private fun createGetOwnerMethodBuilder(superFunctionDescriptor: FunctionDescriptor) =
object : SymbolWithIrBuilder<IrSimpleFunctionSymbol, IrSimpleFunction>() {
override fun buildSymbol() = IrSimpleFunctionSymbolImpl(
SimpleFunctionDescriptorImpl.create(
/* containingDeclaration = */ functionReferenceClassDescriptor,
/* annotations = */ Annotations.EMPTY,
/* name = */ Name.identifier("getOwner"),
/* kind = */ CallableMemberDescriptor.Kind.DECLARATION,
/* source = */ SourceElement.NO_SOURCE
)
)
override fun doInitialize() {
val descriptor = symbol.descriptor as SimpleFunctionDescriptorImpl
val valueParameters = superFunctionDescriptor.valueParameters
.map { it.copyAsValueParameter(descriptor, it.index) }
descriptor.initialize(
/* receiverParameterType = */ null,
/* dispatchReceiverParameter = */ functionReferenceClassDescriptor.thisAsReceiverParameter,
/* typeParameters = */ emptyList(),
/* unsubstitutedValueParameters = */ valueParameters,
/* unsubstitutedReturnType = */ superFunctionDescriptor.returnType,
/* modality = */ Modality.FINAL,
/* visibility = */ Visibilities.PUBLIC
).apply {
overriddenDescriptors += superFunctionDescriptor
isSuspend = superFunctionDescriptor.isSuspend
}
}
override fun buildIr(): IrSimpleFunction {
val startOffset = irFunctionReference.startOffset
val endOffset = irFunctionReference.endOffset
val ourSymbol = symbol
return IrFunctionImpl(
startOffset = startOffset,
endOffset = endOffset,
origin = DECLARATION_ORIGIN_FUNCTION_REFERENCE_IMPL,
symbol = ourSymbol
).apply {
returnType = symbol.descriptor.returnType!!.toIrType()!!
val function = this
val irBuilder = context.createIrBuilder(function.symbol, startOffset, endOffset)
createParameterDeclarations()
body = irBuilder.irBlockBody(startOffset, endOffset) {
+irReturn(
generateCallableReferenceDeclarationContainer(irFunctionReference)
)
}
}
}
fun IrBuilderWithScope.generateCallableReferenceDeclarationContainer(
irFunctionReference: IrFunctionReference
): IrExpression {
val descriptor = irFunctionReference.symbol.descriptor
val globalContext = this@CallableReferenceLowering.context
val state = globalContext.state
val container = descriptor.containingDeclaration
val type =
when {
container is ClassDescriptor ->
// TODO: getDefaultType() here is wrong and won't work for arrays
state.typeMapper.mapType(container.defaultType)
container is PackageFragmentDescriptor ->
state.typeMapper.mapOwner(descriptor)
descriptor is VariableDescriptorWithAccessors ->
globalContext.state.bindingContext.get(
CodegenBinding.DELEGATED_PROPERTY_METADATA_OWNER, descriptor
)!!
else -> state.typeMapper.mapOwner(descriptor)
}
val clazzDescriptor = globalContext.getClass(FqName("java.lang.Class"))
val clazz = IrClassReferenceImpl(
UNDEFINED_OFFSET,
UNDEFINED_OFFSET,
clazzDescriptor.toIrType(),
clazzDescriptor,
CrIrType(type)
)
val isContainerPackage = if (descriptor is LocalVariableDescriptor)
DescriptorUtils.getParentOfType(descriptor, ClassDescriptor::class.java) == null
else
container is PackageFragmentDescriptor
val reflectionClass = globalContext.getClass(FqName("kotlin.jvm.internal.Reflection"))
return if (isContainerPackage) {
// Note that this name is not used in reflection. There should be the name of the referenced declaration's module instead,
// but there's no nice API to obtain that name here yet
// TODO: write the referenced declaration's module name and use it in reflection
val module = IrConstImpl.string(
-1, -1, globalContext.irBuiltIns.stringType,
state.moduleName
)
val function = reflectionClass.getStaticFunction("getOrCreateKotlinPackage", emptyList())
irCall(IrSimpleFunctionSymbolImpl(function), function.returnType!!.toIrType()!!).apply {
putValueArgument(0, clazz)
putValueArgument(1, module)
}
} else {
val function = reflectionClass.staticScope
.getContributedFunctions(Name.identifier("getOrCreateKotlinClass"), NoLookupLocation.FROM_BACKEND)
.single { it.valueParameters.size == 1 }
irCall(IrSimpleFunctionSymbolImpl(function), function.returnType!!.toIrType()!!).apply {
putValueArgument(0, clazz)
}
}
}
}
}
//TODO rewrite
private fun Name.safeName(): Name {
return if (isSpecial) {
val name = asString()
Name.identifier("$${name.substring(1, name.length - 1)}")
} else this
}
}
// Copied from K/Native IrUtils2.kt
// TODO move IrUtils2.kt to common
private fun IrClass.createParameterDeclarations() {
thisReceiver = IrValueParameterImpl(
startOffset, endOffset,
IrDeclarationOrigin.INSTANCE_RECEIVER,
descriptor.thisAsReceiverParameter,
this.symbol.typeWith(this.typeParameters.map { it.defaultType }),
null
).also { valueParameter ->
valueParameter.parent = this
}
assert(typeParameters.isEmpty())
assert(descriptor.declaredTypeParameters.isEmpty())
}
private val IrTypeParameter.defaultType: IrType get() = this.symbol.defaultType
private val IrTypeParameterSymbol.defaultType: IrType
get() = IrSimpleTypeImpl(
this,
false,
emptyList(),
emptyList()
)
private fun IrClassifierSymbol.typeWith(arguments: List<IrType>): IrSimpleType =
IrSimpleTypeImpl(
this,
false,
arguments.map { makeTypeProjection(it, Variance.INVARIANT) },
emptyList()
)
@@ -145,6 +145,9 @@ fun IrBuilderWithScope.irSetVar(variable: IrVariableSymbol, value: IrExpression)
fun IrBuilderWithScope.irGetField(receiver: IrExpression?, field: IrField) =
IrGetFieldImpl(startOffset, endOffset, field.symbol, field.type, receiver)
fun IrBuilderWithScope.irSetField(receiver: IrExpression?, field: IrField, value: IrExpression) =
IrSetFieldImpl(startOffset, endOffset, field.symbol, receiver, value, field.type)
fun IrBuilderWithScope.irGetObjectValue(type: IrType, classSymbol: IrClassSymbol) =
IrGetObjectValueImpl(startOffset, endOffset, type, classSymbol)
@@ -251,4 +254,4 @@ fun IrBuilderWithScope.irSetField(receiver: IrExpression, irField: IrField, valu
receiver = receiver,
value = value,
type = context.irBuiltIns.unitType
)
)