diff --git a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/JvmSymbols.kt b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/JvmSymbols.kt index a87688f999c..3b25af7f98b 100644 --- a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/JvmSymbols.kt +++ b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/JvmSymbols.kt @@ -7,6 +7,7 @@ package org.jetbrains.kotlin.backend.jvm import org.jetbrains.kotlin.backend.common.ir.Symbols import org.jetbrains.kotlin.backend.common.ir.createImplicitParameterDeclarationWithWrappedDescriptor +import org.jetbrains.kotlin.backend.jvm.intrinsics.KClassJavaProperty import org.jetbrains.kotlin.descriptors.ClassDescriptor import org.jetbrains.kotlin.descriptors.ClassKind import org.jetbrains.kotlin.descriptors.Modality @@ -18,6 +19,7 @@ import org.jetbrains.kotlin.ir.declarations.IrDeclarationOrigin import org.jetbrains.kotlin.ir.declarations.IrPackageFragment import org.jetbrains.kotlin.ir.declarations.impl.IrExternalPackageFragmentImpl import org.jetbrains.kotlin.ir.symbols.IrClassSymbol +import org.jetbrains.kotlin.ir.symbols.IrPropertySymbol import org.jetbrains.kotlin.ir.symbols.IrSimpleFunctionSymbol import org.jetbrains.kotlin.ir.symbols.impl.IrExternalPackageFragmentSymbolImpl import org.jetbrains.kotlin.ir.types.defaultType @@ -50,6 +52,7 @@ class JvmSymbols( private fun createPackage(fqName: FqName): IrPackageFragment = IrExternalPackageFragmentImpl(IrExternalPackageFragmentSymbolImpl(EmptyPackageFragmentDescriptor(context.state.module, fqName))) + private val kotlinJvmPackage: IrPackageFragment = createPackage(FqName("kotlin.jvm")) private val kotlinJvmInternalPackage: IrPackageFragment = createPackage(FqName("kotlin.jvm.internal")) private val kotlinJvmFunctionsPackage: IrPackageFragment = createPackage(FqName("kotlin.jvm.functions")) private val javaLangPackage: IrPackageFragment = createPackage(FqName("java.lang")) @@ -307,4 +310,15 @@ class JvmSymbols( val genericToArray: IrSimpleFunctionSymbol = collectionToArrayClass.functions.single { it.owner.name.asString() == "toArray" && it.owner.valueParameters.size == 2 } + + val kClassJava: IrPropertySymbol = + buildProperty { + name = Name.identifier("java") + }.apply { + parent = kotlinJvmPackage + addGetter().apply { + addExtensionReceiver(irBuiltIns.kClassClass.typeWith()) + returnType = javaLangClass.typeWith() + } + }.symbol } 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 87092beb185..099a32d351d 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 @@ -11,7 +11,6 @@ import org.jetbrains.kotlin.backend.jvm.JvmLoweredDeclarationOrigin import org.jetbrains.kotlin.backend.jvm.intrinsics.IrIntrinsicMethods import org.jetbrains.kotlin.backend.jvm.intrinsics.JavaClassProperty import org.jetbrains.kotlin.backend.jvm.intrinsics.Not -import org.jetbrains.kotlin.backend.jvm.lower.CrIrType import org.jetbrains.kotlin.backend.jvm.lower.constantValue import org.jetbrains.kotlin.backend.jvm.lower.inlineclasses.unboxInlineClass import org.jetbrains.kotlin.codegen.* @@ -1080,18 +1079,15 @@ class ExpressionCodegen( JavaClassProperty.invokeWith(classReference.argument.accept(this, data)) } else if (classReference is IrClassReference) { val classType = classReference.classType - if (classType is CrIrType) { - putJavaLangClassInstance(mv, classType.type, null, typeMapper.kotlinTypeMapper) - return classReference.onStack - } else { - val classifier = classType.classifierOrNull - if (classifier is IrTypeParameterSymbol) { - assert(classifier.owner.isReified) { "Non-reified type parameter under ::class should be rejected by type checker: ${classifier.owner.dump()}" } - putReifiedOperationMarkerIfTypeIsReifiedParameter(classType, ReifiedTypeInliner.OperationKind.JAVA_CLASS, mv, this) + val classifier = classType.classifierOrNull + if (classifier is IrTypeParameterSymbol) { + assert(classifier.owner.isReified) { + "Non-reified type parameter under ::class should be rejected by type checker: ${classifier.owner.dump()}" } - - putJavaLangClassInstance(mv, typeMapper.mapType(classType), classType.toKotlinType(), typeMapper.kotlinTypeMapper) + putReifiedOperationMarkerIfTypeIsReifiedParameter(classType, ReifiedTypeInliner.OperationKind.JAVA_CLASS, mv, this) } + + putJavaLangClassInstance(mv, typeMapper.mapType(classType), classType.toKotlinType(), typeMapper.kotlinTypeMapper) } else { throw AssertionError("not an IrGetClass or IrClassReference: ${classReference.dump()}") } 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 index 71abbb216cb..47934fa5ed6 100644 --- 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 @@ -51,18 +51,6 @@ 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.org.objectweb.asm.Type - -//Hack implementation to support CR java types in lower -class CrIrType(val type: Type) : IrType { - override val annotations: List = emptyList() - - override fun equals(other: Any?): Boolean = - other is CrIrType && type == other.type - - override fun hashCode(): Int = - type.hashCode() -} internal val callableReferencePhase = makeIrFilePhase( ::CallableReferenceLowering, @@ -410,42 +398,40 @@ internal class CallableReferenceLowering(val context: JvmBackendContext) : FileL } private fun createGetOwnerMethod(superFunction: IrSimpleFunction): IrSimpleFunction = buildOverride(superFunction).apply { - val globalContext = context - val state = globalContext.state - val irContainer = callee.parent + body = context.createIrBuilder(symbol, startOffset, endOffset).run { + irExprBody(calculateOwner(callee.parent, this@CallableReferenceLowering.context)) + } + } + } + + companion object { + internal fun IrBuilderWithScope.calculateOwner(irContainer: IrDeclarationParent, context: JvmBackendContext): IrExpression { + val symbols = context.ir.symbols val isContainerPackage = - ((irContainer as? IrClass)?.origin == IrDeclarationOrigin.FILE_CLASS) || irContainer is IrPackageFragment + (irContainer as? IrClass)?.origin == IrDeclarationOrigin.FILE_CLASS || irContainer is IrPackageFragment - val type = when (irContainer) { - // TODO: getDefaultType() here is wrong and won't work for arrays - is IrClass -> state.typeMapper.mapType(irContainer.defaultType.toKotlinType()) - else -> state.typeMapper.mapOwner(callee.descriptor) - } - - val clazz = globalContext.ir.symbols.javaLangClass val clazzRef = IrClassReferenceImpl( UNDEFINED_OFFSET, UNDEFINED_OFFSET, - clazz.typeWith(), - clazz, - CrIrType(type) + symbols.javaLangClass.typeWith(), + symbols.javaLangClass, + // For built-in members (i.e. top level `toString`) we don't know any meaningful container, so we're generating Any. + // The non-IR backend generates equally meaningless "kotlin/KotlinPackage" in this case (see KT-17151). + (irContainer as? IrClass)?.defaultType ?: context.irBuiltIns.anyNType ) - body = context.createIrBuilder(symbol, startOffset, endOffset).run { - irExprBody(if (isContainerPackage) { - irCall(globalContext.ir.symbols.getOrCreateKotlinPackage).apply { - putValueArgument(0, clazzRef) - // 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 - putValueArgument(1, irString(state.moduleName)) - } - } else { - irCall(globalContext.ir.symbols.getOrCreateKotlinClass).apply { - putValueArgument(0, clazzRef) - } - }) + if (!isContainerPackage) return clazzRef + + val jClass = irGet(symbols.javaLangClass.typeWith(), null, symbols.kClassJava.owner.getter!!.symbol).apply { + extensionReceiver = clazzRef + } + return irCall(symbols.getOrCreateKotlinPackage).apply { + putValueArgument(0, jClass) + // 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 + putValueArgument(1, irString(context.state.moduleName)) } } } diff --git a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/lower/PropertyReferenceLowering.kt b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/lower/PropertyReferenceLowering.kt index 53418bf55c4..5d76998e916 100644 --- a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/lower/PropertyReferenceLowering.kt +++ b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/lower/PropertyReferenceLowering.kt @@ -21,7 +21,6 @@ import org.jetbrains.kotlin.ir.builders.declarations.buildClass import org.jetbrains.kotlin.ir.builders.declarations.buildField import org.jetbrains.kotlin.ir.declarations.* import org.jetbrains.kotlin.ir.expressions.* -import org.jetbrains.kotlin.ir.expressions.impl.IrClassReferenceImpl import org.jetbrains.kotlin.ir.expressions.impl.IrVarargImpl import org.jetbrains.kotlin.ir.symbols.IrClassSymbol import org.jetbrains.kotlin.ir.symbols.IrFieldSymbol @@ -30,7 +29,6 @@ import org.jetbrains.kotlin.ir.symbols.IrSymbol import org.jetbrains.kotlin.ir.types.createType import org.jetbrains.kotlin.ir.types.impl.IrSimpleTypeImpl import org.jetbrains.kotlin.ir.types.impl.makeTypeProjection -import org.jetbrains.kotlin.ir.types.typeWith import org.jetbrains.kotlin.ir.util.* import org.jetbrains.kotlin.ir.visitors.transformChildrenVoid import org.jetbrains.kotlin.load.java.JvmAbi @@ -85,48 +83,18 @@ internal class PropertyReferenceLowering(val context: JvmBackendContext) : Class private val kPropertiesFieldType = context.ir.symbols.array.createType(false, listOf(makeTypeProjection(kPropertyStarType, Variance.OUT_VARIANCE))) - // Return some declaration the parent of which is the containing class/package for the referenced property. This is - // a bit of a hack, as the reason for not returning the container itself is the `mapImplementationOwner` call below. - // TODO: move after LocalDeclarationsLowering and always use the getter/field? Can't move below ConstLowering - // right now -- get() would not be optimized. - private val IrMemberAccessExpression.propertyContainerChild: IrDeclaration? + private val IrMemberAccessExpression.propertyContainer: IrDeclarationParent get() { - var current: IrDeclaration? = getter?.owner ?: field?.owner - while (current?.parent is IrFunction) + var current: IrDeclaration = getter?.owner ?: field?.owner ?: error("Property without getter or field: ${dump()}") + while (current.parent is IrFunction) current = current.parent as IrFunction // Local delegated property. - return current + return current.parent } - // TODO: remove code duplication with CallableReferenceLowering - private val IrMemberAccessExpression.parentJavaClassReference - get() = IrClassReferenceImpl( - startOffset, endOffset, - context.ir.symbols.javaLangClass.typeWith(), - context.ir.symbols.javaLangClass, - // TODO: when the parent is an interface, this should map to DefaultImpls. However, that requires - // moving this lowering below InterfaceLowering; see comment about the ordering above, though. - CrIrType(context.state.typeMapper.mapImplementationOwner(propertyContainerChild!!.descriptor)) - ) - - private fun IrBuilderWithScope.buildReflectedContainerReference(expression: IrMemberAccessExpression): IrExpression { - val parent = expression.propertyContainerChild?.parent - val context = this@PropertyReferenceLowering.context - return when { - // FileClassLowering creates a class to which all package-level declarations are moved. However, there - // can still be external declarations at the package level, which is why we check for both a file class - // and a package fragment. - parent is IrPackageFragment || (parent is IrClass && parent.origin == IrDeclarationOrigin.FILE_CLASS) -> - irCall(context.ir.symbols.getOrCreateKotlinPackage).apply { - putValueArgument(0, expression.parentJavaClassReference) - putValueArgument(1, irString(context.state.moduleName)) - } - parent is IrClass -> - irCall(context.ir.symbols.getOrCreateKotlinClass).apply { - putValueArgument(0, expression.parentJavaClassReference) - } - else -> throw AssertionError("referenced property not inside a class/package fragment") + private fun IrBuilderWithScope.buildReflectedContainerReference(expression: IrMemberAccessExpression): IrExpression = + with(CallableReferenceLowering) { + calculateOwner(expression.propertyContainer, this@PropertyReferenceLowering.context) } - } private fun IrClass.addOverride(method: IrSimpleFunction, buildBody: IrBuilderWithScope.(List) -> IrExpression) = addFunction { diff --git a/compiler/testData/codegen/box/reflection/call/inlineClasses/inlineClassConstructor.kt b/compiler/testData/codegen/box/reflection/call/inlineClasses/inlineClassConstructor.kt index ecc39d49f75..d133c22255b 100644 --- a/compiler/testData/codegen/box/reflection/call/inlineClasses/inlineClassConstructor.kt +++ b/compiler/testData/codegen/box/reflection/call/inlineClasses/inlineClassConstructor.kt @@ -1,5 +1,6 @@ -// IGNORE_BACKEND: JS_IR, JS, NATIVE, JVM_IR +// IGNORE_BACKEND: JS_IR, JS, NATIVE // WITH_REFLECT + import kotlin.reflect.KCallable import kotlin.test.assertEquals @@ -43,4 +44,4 @@ fun box(): String { assertEquals(Z2(Z(42)), ::Z2.call(Z(42))) return "OK" -} \ No newline at end of file +}