JVM IR: remove CrIrType, use class container in callable reference lowerings
This is possible now because after3a9b94235f,0423d0f41eand5341de253f, all top level functions/properties in sources and in binaries have a corresponding containing facade class
This commit is contained in:
@@ -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
|
||||
}
|
||||
|
||||
+7
-11
@@ -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()}")
|
||||
}
|
||||
|
||||
+26
-40
@@ -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<IrConstructorCall> = 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))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+7
-39
@@ -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<IrValueParameter>) -> IrExpression) =
|
||||
addFunction {
|
||||
|
||||
+3
-2
@@ -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"
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user