diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/PropertyReferenceCodegen.kt b/compiler/backend/src/org/jetbrains/kotlin/codegen/PropertyReferenceCodegen.kt index 5931513a31b..46deae70101 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/PropertyReferenceCodegen.kt +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/PropertyReferenceCodegen.kt @@ -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 = "variable" - return + return "" } 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 diff --git a/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/descriptors/DescriptorUtils.kt b/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/descriptors/DescriptorUtils.kt index ba40b8a7369..1f913064518 100644 --- a/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/descriptors/DescriptorUtils.kt +++ b/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/descriptors/DescriptorUtils.kt @@ -87,6 +87,30 @@ fun ClassDescriptor.getFunction(name: String, types: List): Function .getContributedFunctions(Name.identifier(name), NoLookupLocation.FROM_BACKEND).single().substitute(typeSubstitutor)!! } +fun ClassDescriptor.getStaticFunction(name: String, types: List): 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): 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() diff --git a/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/ir/Ir.kt b/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/ir/Ir.kt index c032d33f113..8a115696f5e 100644 --- a/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/ir/Ir.kt +++ b/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/ir/Ir.kt @@ -175,6 +175,8 @@ abstract class Symbols(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) } diff --git a/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/lower/LowerUtils.kt b/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/lower/LowerUtils.kt index 5cceb311f03..0a916b1d850 100644 --- a/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/lower/LowerUtils.kt +++ b/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/lower/LowerUtils.kt @@ -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, diff --git a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/JvmLower.kt b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/JvmLower.kt index 4008a220829..edea722b1ba 100644 --- a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/JvmLower.kt +++ b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/JvmLower.kt @@ -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 diff --git a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/codegen/ExpressionCodegen.kt b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/codegen/ExpressionCodegen.kt index 5e66f0b682e..b3b5da9a260 100644 --- a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/codegen/ExpressionCodegen.kt +++ b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/codegen/ExpressionCodegen.kt @@ -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)) \ No newline at end of file diff --git a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/lower/CallableReferenceLowering.kt b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/lower/CallableReferenceLowering.kt new file mode 100644 index 00000000000..21155701f9b --- /dev/null +++ b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/lower/CallableReferenceLowering.kt @@ -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() + + 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().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 + + 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 = 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? = 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() + 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() { + + 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() { + + 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 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() { + + 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() { + + 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() { + + 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): IrSimpleType = + IrSimpleTypeImpl( + this, + false, + arguments.map { makeTypeProjection(it, Variance.INVARIANT) }, + emptyList() + ) diff --git a/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/builders/ExpressionHelpers.kt b/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/builders/ExpressionHelpers.kt index e46e7c7fede..abbe3550c2b 100644 --- a/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/builders/ExpressionHelpers.kt +++ b/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/builders/ExpressionHelpers.kt @@ -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 - ) \ No newline at end of file + )