JVM IR: remove CrIrType, use class container in callable reference lowerings

This is possible now because after 3a9b94235f, 0423d0f41e and
5341de253f, all top level functions/properties in sources and in
binaries have a corresponding containing facade class
This commit is contained in:
Alexander Udalov
2019-07-05 18:28:17 +02:00
parent a048a11074
commit 1f36f60f43
5 changed files with 57 additions and 92 deletions
@@ -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.Symbols
import org.jetbrains.kotlin.backend.common.ir.createImplicitParameterDeclarationWithWrappedDescriptor 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.ClassDescriptor
import org.jetbrains.kotlin.descriptors.ClassKind import org.jetbrains.kotlin.descriptors.ClassKind
import org.jetbrains.kotlin.descriptors.Modality 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.IrPackageFragment
import org.jetbrains.kotlin.ir.declarations.impl.IrExternalPackageFragmentImpl import org.jetbrains.kotlin.ir.declarations.impl.IrExternalPackageFragmentImpl
import org.jetbrains.kotlin.ir.symbols.IrClassSymbol 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.IrSimpleFunctionSymbol
import org.jetbrains.kotlin.ir.symbols.impl.IrExternalPackageFragmentSymbolImpl import org.jetbrains.kotlin.ir.symbols.impl.IrExternalPackageFragmentSymbolImpl
import org.jetbrains.kotlin.ir.types.defaultType import org.jetbrains.kotlin.ir.types.defaultType
@@ -50,6 +52,7 @@ class JvmSymbols(
private fun createPackage(fqName: FqName): IrPackageFragment = private fun createPackage(fqName: FqName): IrPackageFragment =
IrExternalPackageFragmentImpl(IrExternalPackageFragmentSymbolImpl(EmptyPackageFragmentDescriptor(context.state.module, fqName))) 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 kotlinJvmInternalPackage: IrPackageFragment = createPackage(FqName("kotlin.jvm.internal"))
private val kotlinJvmFunctionsPackage: IrPackageFragment = createPackage(FqName("kotlin.jvm.functions")) private val kotlinJvmFunctionsPackage: IrPackageFragment = createPackage(FqName("kotlin.jvm.functions"))
private val javaLangPackage: IrPackageFragment = createPackage(FqName("java.lang")) private val javaLangPackage: IrPackageFragment = createPackage(FqName("java.lang"))
@@ -307,4 +310,15 @@ class JvmSymbols(
val genericToArray: IrSimpleFunctionSymbol = val genericToArray: IrSimpleFunctionSymbol =
collectionToArrayClass.functions.single { it.owner.name.asString() == "toArray" && it.owner.valueParameters.size == 2 } 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
} }
@@ -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.IrIntrinsicMethods
import org.jetbrains.kotlin.backend.jvm.intrinsics.JavaClassProperty import org.jetbrains.kotlin.backend.jvm.intrinsics.JavaClassProperty
import org.jetbrains.kotlin.backend.jvm.intrinsics.Not 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.constantValue
import org.jetbrains.kotlin.backend.jvm.lower.inlineclasses.unboxInlineClass import org.jetbrains.kotlin.backend.jvm.lower.inlineclasses.unboxInlineClass
import org.jetbrains.kotlin.codegen.* import org.jetbrains.kotlin.codegen.*
@@ -1080,18 +1079,15 @@ class ExpressionCodegen(
JavaClassProperty.invokeWith(classReference.argument.accept(this, data)) JavaClassProperty.invokeWith(classReference.argument.accept(this, data))
} else if (classReference is IrClassReference) { } else if (classReference is IrClassReference) {
val classType = classReference.classType val classType = classReference.classType
if (classType is CrIrType) { val classifier = classType.classifierOrNull
putJavaLangClassInstance(mv, classType.type, null, typeMapper.kotlinTypeMapper) if (classifier is IrTypeParameterSymbol) {
return classReference.onStack assert(classifier.owner.isReified) {
} else { "Non-reified type parameter under ::class should be rejected by type checker: ${classifier.owner.dump()}"
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)
} }
putReifiedOperationMarkerIfTypeIsReifiedParameter(classType, ReifiedTypeInliner.OperationKind.JAVA_CLASS, mv, this)
putJavaLangClassInstance(mv, typeMapper.mapType(classType), classType.toKotlinType(), typeMapper.kotlinTypeMapper)
} }
putJavaLangClassInstance(mv, typeMapper.mapType(classType), classType.toKotlinType(), typeMapper.kotlinTypeMapper)
} else { } else {
throw AssertionError("not an IrGetClass or IrClassReference: ${classReference.dump()}") throw AssertionError("not an IrGetClass or IrClassReference: ${classReference.dump()}")
} }
@@ -51,18 +51,6 @@ import org.jetbrains.kotlin.ir.visitors.transformChildrenVoid
import org.jetbrains.kotlin.load.java.JavaVisibilities import org.jetbrains.kotlin.load.java.JavaVisibilities
import org.jetbrains.kotlin.name.FqName import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.name.Name 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( internal val callableReferencePhase = makeIrFilePhase(
::CallableReferenceLowering, ::CallableReferenceLowering,
@@ -410,42 +398,40 @@ internal class CallableReferenceLowering(val context: JvmBackendContext) : FileL
} }
private fun createGetOwnerMethod(superFunction: IrSimpleFunction): IrSimpleFunction = buildOverride(superFunction).apply { private fun createGetOwnerMethod(superFunction: IrSimpleFunction): IrSimpleFunction = buildOverride(superFunction).apply {
val globalContext = context body = context.createIrBuilder(symbol, startOffset, endOffset).run {
val state = globalContext.state irExprBody(calculateOwner(callee.parent, this@CallableReferenceLowering.context))
val irContainer = callee.parent }
}
}
companion object {
internal fun IrBuilderWithScope.calculateOwner(irContainer: IrDeclarationParent, context: JvmBackendContext): IrExpression {
val symbols = context.ir.symbols
val isContainerPackage = 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( val clazzRef = IrClassReferenceImpl(
UNDEFINED_OFFSET, UNDEFINED_OFFSET,
UNDEFINED_OFFSET, UNDEFINED_OFFSET,
clazz.typeWith(), symbols.javaLangClass.typeWith(),
clazz, symbols.javaLangClass,
CrIrType(type) // 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 { if (!isContainerPackage) return clazzRef
irExprBody(if (isContainerPackage) {
irCall(globalContext.ir.symbols.getOrCreateKotlinPackage).apply { val jClass = irGet(symbols.javaLangClass.typeWith(), null, symbols.kClassJava.owner.getter!!.symbol).apply {
putValueArgument(0, clazzRef) extensionReceiver = 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 return irCall(symbols.getOrCreateKotlinPackage).apply {
// TODO: write the referenced declaration's module name and use it in reflection putValueArgument(0, jClass)
putValueArgument(1, irString(state.moduleName)) // 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
} else { // TODO: write the referenced declaration's module name and use it in reflection
irCall(globalContext.ir.symbols.getOrCreateKotlinClass).apply { putValueArgument(1, irString(context.state.moduleName))
putValueArgument(0, clazzRef)
}
})
} }
} }
} }
@@ -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.builders.declarations.buildField
import org.jetbrains.kotlin.ir.declarations.* import org.jetbrains.kotlin.ir.declarations.*
import org.jetbrains.kotlin.ir.expressions.* 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.expressions.impl.IrVarargImpl
import org.jetbrains.kotlin.ir.symbols.IrClassSymbol import org.jetbrains.kotlin.ir.symbols.IrClassSymbol
import org.jetbrains.kotlin.ir.symbols.IrFieldSymbol 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.createType
import org.jetbrains.kotlin.ir.types.impl.IrSimpleTypeImpl import org.jetbrains.kotlin.ir.types.impl.IrSimpleTypeImpl
import org.jetbrains.kotlin.ir.types.impl.makeTypeProjection 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.util.*
import org.jetbrains.kotlin.ir.visitors.transformChildrenVoid import org.jetbrains.kotlin.ir.visitors.transformChildrenVoid
import org.jetbrains.kotlin.load.java.JvmAbi import org.jetbrains.kotlin.load.java.JvmAbi
@@ -85,48 +83,18 @@ internal class PropertyReferenceLowering(val context: JvmBackendContext) : Class
private val kPropertiesFieldType = private val kPropertiesFieldType =
context.ir.symbols.array.createType(false, listOf(makeTypeProjection(kPropertyStarType, Variance.OUT_VARIANCE))) 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 private val IrMemberAccessExpression.propertyContainer: IrDeclarationParent
// 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?
get() { get() {
var current: IrDeclaration? = getter?.owner ?: field?.owner var current: IrDeclaration = getter?.owner ?: field?.owner ?: error("Property without getter or field: ${dump()}")
while (current?.parent is IrFunction) while (current.parent is IrFunction)
current = current.parent as IrFunction // Local delegated property. current = current.parent as IrFunction // Local delegated property.
return current return current.parent
} }
// TODO: remove code duplication with CallableReferenceLowering private fun IrBuilderWithScope.buildReflectedContainerReference(expression: IrMemberAccessExpression): IrExpression =
private val IrMemberAccessExpression.parentJavaClassReference with(CallableReferenceLowering) {
get() = IrClassReferenceImpl( calculateOwner(expression.propertyContainer, this@PropertyReferenceLowering.context)
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 IrClass.addOverride(method: IrSimpleFunction, buildBody: IrBuilderWithScope.(List<IrValueParameter>) -> IrExpression) = private fun IrClass.addOverride(method: IrSimpleFunction, buildBody: IrBuilderWithScope.(List<IrValueParameter>) -> IrExpression) =
addFunction { addFunction {
@@ -1,5 +1,6 @@
// IGNORE_BACKEND: JS_IR, JS, NATIVE, JVM_IR // IGNORE_BACKEND: JS_IR, JS, NATIVE
// WITH_REFLECT // WITH_REFLECT
import kotlin.reflect.KCallable import kotlin.reflect.KCallable
import kotlin.test.assertEquals import kotlin.test.assertEquals
@@ -43,4 +44,4 @@ fun box(): String {
assertEquals(Z2(Z(42)), ::Z2.call(Z(42))) assertEquals(Z2(Z(42)), ::Z2.call(Z(42)))
return "OK" return "OK"
} }