KClassJavaProperty support
This commit is contained in:
committed by
Dmitry Petrov
parent
5ee2f87c4a
commit
b72d7557d1
+29
@@ -22,6 +22,7 @@ import org.jetbrains.kotlin.builtins.KotlinBuiltIns
|
||||
import org.jetbrains.kotlin.codegen.*
|
||||
import org.jetbrains.kotlin.codegen.AsmUtil.*
|
||||
import org.jetbrains.kotlin.codegen.StackValue.*
|
||||
import org.jetbrains.kotlin.codegen.intrinsics.JavaClassProperty
|
||||
import org.jetbrains.kotlin.codegen.pseudoInsns.fixStackAndJump
|
||||
import org.jetbrains.kotlin.descriptors.*
|
||||
import org.jetbrains.kotlin.descriptors.impl.TypeAliasConstructorDescriptor
|
||||
@@ -819,6 +820,34 @@ class ExpressionCodegen(
|
||||
return expression.onStack
|
||||
}
|
||||
|
||||
override fun visitClassReference(expression: IrClassReference, data: BlockInfo): StackValue {
|
||||
generateClassLiteralReference(expression, true, data)
|
||||
return expression.onStack
|
||||
}
|
||||
|
||||
fun generateClassLiteralReference(
|
||||
receiverExpression: IrExpression,
|
||||
wrapIntoKClass: Boolean,
|
||||
data: BlockInfo
|
||||
) {
|
||||
if (receiverExpression !is IrClassReference /* && DescriptorUtils.isObject(receiverExpression.descriptor)*/) {
|
||||
JavaClassProperty.generateImpl(mv, gen(receiverExpression, data))
|
||||
}
|
||||
else {
|
||||
// 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)
|
||||
// }
|
||||
|
||||
putJavaLangClassInstance(mv, typeMapper.mapType(receiverExpression.descriptor.defaultType))
|
||||
}
|
||||
|
||||
if (wrapIntoKClass) {
|
||||
wrapJavaClassIntoKClass(mv)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private fun coerceNotToUnit(fromType: Type, toType: Type) {
|
||||
if (toType != AsmTypes.UNIT_TYPE) {
|
||||
coerce(fromType, toType, mv)
|
||||
|
||||
+12
-40
@@ -18,57 +18,29 @@ package org.jetbrains.kotlin.backend.jvm.intrinsics
|
||||
|
||||
import org.jetbrains.kotlin.backend.jvm.JvmBackendContext
|
||||
import org.jetbrains.kotlin.backend.jvm.codegen.BlockInfo
|
||||
import org.jetbrains.kotlin.codegen.AsmUtil.putJavaLangClassInstance
|
||||
import org.jetbrains.kotlin.codegen.AsmUtil.wrapJavaClassIntoKClass
|
||||
import org.jetbrains.kotlin.codegen.ExpressionCodegen
|
||||
import org.jetbrains.kotlin.codegen.StackValue
|
||||
import org.jetbrains.kotlin.descriptors.FunctionDescriptor
|
||||
import org.jetbrains.kotlin.ir.expressions.IrClassReference
|
||||
import org.jetbrains.kotlin.ir.expressions.IrGetClass
|
||||
import org.jetbrains.kotlin.ir.expressions.IrMemberAccessExpression
|
||||
import org.jetbrains.kotlin.psi.KtClassLiteralExpression
|
||||
import org.jetbrains.kotlin.resolve.BindingContext.DOUBLE_COLON_LHS
|
||||
import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall
|
||||
import org.jetbrains.kotlin.resolve.jvm.jvmSignature.JvmMethodSignature
|
||||
import org.jetbrains.kotlin.resolve.scopes.receivers.ExpressionReceiver
|
||||
import org.jetbrains.org.objectweb.asm.Type
|
||||
import org.jetbrains.org.objectweb.asm.commons.InstructionAdapter
|
||||
|
||||
class KClassJavaProperty : IntrinsicMethod() {
|
||||
override fun toCallable(expression: IrMemberAccessExpression, signature: JvmMethodSignature, context: JvmBackendContext): IrIntrinsicFunction {
|
||||
return object: IrIntrinsicFunction(expression, signature, context) {
|
||||
override fun invoke(v: InstructionAdapter, codegen: org.jetbrains.kotlin.backend.jvm.codegen.ExpressionCodegen, data: BlockInfo): StackValue {
|
||||
putJavaLangClassInstance(v, signature.returnType)
|
||||
wrapJavaClassIntoKClass(v)
|
||||
val extensionReceiver = expression.extensionReceiver
|
||||
if (extensionReceiver is IrClassReference || extensionReceiver is IrGetClass) {
|
||||
codegen.generateClassLiteralReference(extensionReceiver, false, data)
|
||||
}
|
||||
else {
|
||||
codegen.gen(extensionReceiver!!, data)
|
||||
val mapToCallableMethod = context.state.typeMapper.mapToCallableMethod(expression.descriptor as FunctionDescriptor, false)
|
||||
mapToCallableMethod.genInvokeInstruction(codegen.mv)
|
||||
}
|
||||
return StackValue.onStack(signature.returnType)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// val type = lhs.type
|
||||
// if (lhs is DoubleColonLHS.Expression && !(lhs as DoubleColonLHS.Expression).isObject) {
|
||||
// JavaClassProperty.generateImpl(v, gen(receiverExpression))
|
||||
// }
|
||||
// else {
|
||||
// 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)
|
||||
// }
|
||||
|
||||
// putJavaLangClassInstance(v, typeMapper.mapType(type))
|
||||
// }
|
||||
|
||||
// if (wrapIntoKClass) {
|
||||
// wrapJavaClassIntoKClass(v)
|
||||
// }
|
||||
|
||||
// return Unit
|
||||
}
|
||||
|
||||
|
||||
fun generate(resolvedCall: ResolvedCall<*>?, codegen: ExpressionCodegen, returnType: Type, receiver: StackValue): StackValue? {
|
||||
val receiverValue = resolvedCall!!.extensionReceiver as? ExpressionReceiver ?: return null
|
||||
val classLiteralExpression = receiverValue.expression as? KtClassLiteralExpression ?: return null
|
||||
val receiverExpression = classLiteralExpression.receiverExpression ?: return null
|
||||
val lhs = codegen.bindingContext.get(DOUBLE_COLON_LHS, receiverExpression) ?: return null
|
||||
val value = codegen.generateClassLiteralReference(lhs, receiverExpression, /* wrapIntoKClass = */ false)
|
||||
return StackValue.coercion(value, returnType)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,10 @@
|
||||
//WITH_RUNTIME
|
||||
class A
|
||||
|
||||
fun test() {
|
||||
A::class
|
||||
A()::class
|
||||
|
||||
A::class.java
|
||||
A()::class.java
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
FILE /classReference.kt
|
||||
CLASS CLASS A
|
||||
CONSTRUCTOR public constructor A()
|
||||
BLOCK_BODY
|
||||
DELEGATING_CONSTRUCTOR_CALL 'constructor Any()'
|
||||
INSTANCE_INITIALIZER_CALL classDescriptor='A'
|
||||
FUN public fun test(): kotlin.Unit
|
||||
BLOCK_BODY
|
||||
TYPE_OP origin=IMPLICIT_COERCION_TO_UNIT typeOperand=kotlin.Unit
|
||||
CLASS_REFERENCE 'A' type=kotlin.reflect.KClass<A>
|
||||
TYPE_OP origin=IMPLICIT_COERCION_TO_UNIT typeOperand=kotlin.Unit
|
||||
GET_CLASS type=kotlin.reflect.KClass<A>
|
||||
CALL 'constructor A()' type=A origin=null
|
||||
TYPE_OP origin=IMPLICIT_COERCION_TO_UNIT typeOperand=kotlin.Unit
|
||||
CALL '<get-java>() on KClass<A>: Class<A>' type=java.lang.Class<A> origin=GET_PROPERTY
|
||||
$receiver: CLASS_REFERENCE 'A' type=kotlin.reflect.KClass<A>
|
||||
TYPE_OP origin=IMPLICIT_COERCION_TO_UNIT typeOperand=kotlin.Unit
|
||||
CALL '<get-java>() on KClass<A>: Class<A>' type=java.lang.Class<A> origin=GET_PROPERTY
|
||||
$receiver: GET_CLASS type=kotlin.reflect.KClass<A>
|
||||
CALL 'constructor A()' type=A origin=null
|
||||
@@ -0,0 +1,7 @@
|
||||
//WITH_RUNTIME
|
||||
object A
|
||||
|
||||
fun test() {
|
||||
A::class
|
||||
A::class.java
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
FILE /objectClassReference.kt
|
||||
CLASS OBJECT A
|
||||
CONSTRUCTOR private constructor A()
|
||||
BLOCK_BODY
|
||||
DELEGATING_CONSTRUCTOR_CALL 'constructor Any()'
|
||||
INSTANCE_INITIALIZER_CALL classDescriptor='A'
|
||||
FUN public fun test(): kotlin.Unit
|
||||
BLOCK_BODY
|
||||
TYPE_OP origin=IMPLICIT_COERCION_TO_UNIT typeOperand=kotlin.Unit
|
||||
CLASS_REFERENCE 'A' type=kotlin.reflect.KClass<A>
|
||||
TYPE_OP origin=IMPLICIT_COERCION_TO_UNIT typeOperand=kotlin.Unit
|
||||
CALL '<get-java>() on KClass<A>: Class<A>' type=java.lang.Class<A> origin=GET_PROPERTY
|
||||
$receiver: CLASS_REFERENCE 'A' type=kotlin.reflect.KClass<A>
|
||||
@@ -400,6 +400,12 @@ public class IrTextTestCaseGenerated extends AbstractIrTextTestCase {
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("classReference.kt")
|
||||
public void testClassReference() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/ir/irText/expressions/classReference.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("coercionToUnit.kt")
|
||||
public void testCoercionToUnit() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/ir/irText/expressions/coercionToUnit.kt");
|
||||
@@ -520,6 +526,12 @@ public class IrTextTestCaseGenerated extends AbstractIrTextTestCase {
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("objectClassReference.kt")
|
||||
public void testObjectClassReference() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/ir/irText/expressions/objectClassReference.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("primitiveComparisons.kt")
|
||||
public void testPrimitiveComparisons() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/ir/irText/expressions/primitiveComparisons.kt");
|
||||
|
||||
Reference in New Issue
Block a user