Initial support of function callable references
This commit is contained in:
@@ -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
|
||||
|
||||
+24
@@ -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) }
|
||||
|
||||
+1
-1
@@ -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
|
||||
|
||||
+19
-7
@@ -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))
|
||||
+728
@@ -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
|
||||
)
|
||||
)
|
||||
|
||||
Reference in New Issue
Block a user