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 8371e775160..11723ee88a8 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 @@ -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) diff --git a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/intrinsics/KClassJavaProperty.kt b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/intrinsics/KClassJavaProperty.kt index a9a4403027c..bf545c06fb4 100644 --- a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/intrinsics/KClassJavaProperty.kt +++ b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/intrinsics/KClassJavaProperty.kt @@ -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) } } diff --git a/compiler/testData/ir/irText/expressions/classReference.kt b/compiler/testData/ir/irText/expressions/classReference.kt new file mode 100644 index 00000000000..4ba32de63e2 --- /dev/null +++ b/compiler/testData/ir/irText/expressions/classReference.kt @@ -0,0 +1,10 @@ +//WITH_RUNTIME +class A + +fun test() { + A::class + A()::class + + A::class.java + A()::class.java +} \ No newline at end of file diff --git a/compiler/testData/ir/irText/expressions/classReference.txt b/compiler/testData/ir/irText/expressions/classReference.txt new file mode 100644 index 00000000000..de35b64ab18 --- /dev/null +++ b/compiler/testData/ir/irText/expressions/classReference.txt @@ -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 + TYPE_OP origin=IMPLICIT_COERCION_TO_UNIT typeOperand=kotlin.Unit + GET_CLASS type=kotlin.reflect.KClass + CALL 'constructor A()' type=A origin=null + TYPE_OP origin=IMPLICIT_COERCION_TO_UNIT typeOperand=kotlin.Unit + CALL '() on KClass: Class' type=java.lang.Class origin=GET_PROPERTY + $receiver: CLASS_REFERENCE 'A' type=kotlin.reflect.KClass + TYPE_OP origin=IMPLICIT_COERCION_TO_UNIT typeOperand=kotlin.Unit + CALL '() on KClass: Class' type=java.lang.Class origin=GET_PROPERTY + $receiver: GET_CLASS type=kotlin.reflect.KClass + CALL 'constructor A()' type=A origin=null diff --git a/compiler/testData/ir/irText/expressions/objectClassReference.kt b/compiler/testData/ir/irText/expressions/objectClassReference.kt new file mode 100644 index 00000000000..c0d3efd9519 --- /dev/null +++ b/compiler/testData/ir/irText/expressions/objectClassReference.kt @@ -0,0 +1,7 @@ +//WITH_RUNTIME +object A + +fun test() { + A::class + A::class.java +} \ No newline at end of file diff --git a/compiler/testData/ir/irText/expressions/objectClassReference.txt b/compiler/testData/ir/irText/expressions/objectClassReference.txt new file mode 100644 index 00000000000..ba6bc0771be --- /dev/null +++ b/compiler/testData/ir/irText/expressions/objectClassReference.txt @@ -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 + TYPE_OP origin=IMPLICIT_COERCION_TO_UNIT typeOperand=kotlin.Unit + CALL '() on KClass: Class' type=java.lang.Class origin=GET_PROPERTY + $receiver: CLASS_REFERENCE 'A' type=kotlin.reflect.KClass diff --git a/compiler/tests/org/jetbrains/kotlin/ir/IrTextTestCaseGenerated.java b/compiler/tests/org/jetbrains/kotlin/ir/IrTextTestCaseGenerated.java index 46b99cd2060..33dd216478c 100644 --- a/compiler/tests/org/jetbrains/kotlin/ir/IrTextTestCaseGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/ir/IrTextTestCaseGenerated.java @@ -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");