Support class reference expression for reified type parameters

Also make KClass::java an intrinsic property.

Based on the work by @dnpetrov

 #KT-6976 Fixed
This commit is contained in:
Alexander Udalov
2015-07-29 23:43:11 +03:00
parent 628bb774fd
commit a0cc313156
13 changed files with 283 additions and 41 deletions
@@ -38,7 +38,7 @@ import org.jetbrains.kotlin.codegen.extensions.ExpressionCodegenExtension;
import org.jetbrains.kotlin.codegen.inline.*;
import org.jetbrains.kotlin.codegen.intrinsics.IntrinsicMethod;
import org.jetbrains.kotlin.codegen.intrinsics.IntrinsicMethods;
import org.jetbrains.kotlin.codegen.intrinsics.JavaClassProperty;
import org.jetbrains.kotlin.codegen.intrinsics.IntrinsicPropertyGetter;
import org.jetbrains.kotlin.codegen.pseudoInsns.PseudoInsnsPackage;
import org.jetbrains.kotlin.codegen.signature.BothSignatureWriter;
import org.jetbrains.kotlin.codegen.state.GenerationState;
@@ -53,7 +53,6 @@ import org.jetbrains.kotlin.jvm.RuntimeAssertionInfo;
import org.jetbrains.kotlin.jvm.bindingContextSlices.BindingContextSlicesPackage;
import org.jetbrains.kotlin.lexer.JetTokens;
import org.jetbrains.kotlin.load.java.JvmAbi;
import org.jetbrains.kotlin.load.java.descriptors.JavaClassDescriptor;
import org.jetbrains.kotlin.load.java.descriptors.SamConstructorDescriptor;
import org.jetbrains.kotlin.name.Name;
import org.jetbrains.kotlin.psi.*;
@@ -1981,10 +1980,11 @@ public class ExpressionCodegen extends JetVisitor<StackValue, StackValue> implem
CallableMemberDescriptor memberDescriptor = DescriptorUtils.unwrapFakeOverride((CallableMemberDescriptor) descriptor);
IntrinsicMethod intrinsic = state.getIntrinsics().getIntrinsic(memberDescriptor);
if (intrinsic instanceof JavaClassProperty) {
if (intrinsic instanceof IntrinsicPropertyGetter) {
//TODO: intrinsic properties (see intermediateValueForProperty)
Type returnType = typeMapper.mapType(memberDescriptor);
return ((JavaClassProperty) intrinsic).generate(returnType, receiver);
StackValue intrinsicResult = ((IntrinsicPropertyGetter) intrinsic).generate(resolvedCall, this, returnType, receiver);
if (intrinsicResult != null) return intrinsicResult;
}
}
@@ -2498,15 +2498,17 @@ public class ExpressionCodegen extends JetVisitor<StackValue, StackValue> implem
TypeParameterDescriptor key = entry.getKey();
if (!key.isReified()) continue;
TypeParameterDescriptor parameterDescriptor = TypeUtils.getTypeParameterDescriptorOrNull(entry.getValue());
JetType type = entry.getValue();
TypeParameterDescriptor parameterDescriptor = TypeUtils.getTypeParameterDescriptorOrNull(type);
if (parameterDescriptor == null) {
// type is not generic
BothSignatureWriter signatureWriter = new BothSignatureWriter(BothSignatureWriter.Mode.TYPE);
Type type = typeMapper.mapTypeParameter(entry.getValue(), signatureWriter);
Type asmType = typeMapper.mapTypeParameter(type, signatureWriter);
mappings.addParameterMappingToType(
key.getName().getIdentifier(),
type,
asmType,
signatureWriter.toString()
);
}
@@ -2813,12 +2815,25 @@ public class ExpressionCodegen extends JetVisitor<StackValue, StackValue> implem
public Unit invoke(InstructionAdapter v) {
Type classAsmType = typeMapper.mapType(type);
ClassifierDescriptor descriptor = type.getConstructor().getDeclarationDescriptor();
//noinspection ConstantConditions
ModuleDescriptor module = DescriptorUtils.getContainingModule(descriptor);
// Instantiate annotation classes as foreign due to bug in JDK 6 and 7:
// http://bugs.java.com/bugdatabase/view_bug.do?bug_id=6857918
if (descriptor instanceof JavaClassDescriptor || module == module.getBuiltIns().getBuiltInsModule() ||
DescriptorUtils.isAnnotationClass(descriptor)) {
if (descriptor instanceof TypeParameterDescriptor) {
TypeParameterDescriptor typeParameterDescriptor = (TypeParameterDescriptor) descriptor;
if (typeParameterDescriptor.isReified()) {
// Emit reified type parameters as Kotlin classes.
// ReifiedTypeInliner will rewrite the following GETSTATIC to proper bytecode instructions
// if the class literal for actual type should be emitted with wrapped Java class.
v.visitLdcInsn(typeParameterDescriptor.getName().asString());
v.invokestatic(
IntrinsicMethods.INTRINSICS_CLASS_NAME, ReifiedTypeInliner.CLASS_LITERAL_MARKER_METHOD_NAME,
Type.getMethodDescriptor(Type.VOID_TYPE, Type.getType(String.class)), false
);
v.getstatic(classAsmType.getInternalName(), JvmAbi.KOTLIN_CLASS_FIELD_NAME, K_CLASS_TYPE.getDescriptor());
}
else {
throw new AssertionError("Non-reified type parameter under ::class should be rejected by type checker: " +
typeParameterDescriptor.getName().asString());
}
}
else if (shouldUseJavaClassForClassLiteral(descriptor)) {
putJavaLangClassInstance(v, classAsmType);
wrapJavaClassIntoKClass(v);
}
@@ -30,6 +30,7 @@ import org.jetbrains.kotlin.codegen.context.MethodContext;
import org.jetbrains.kotlin.codegen.context.PackageContext;
import org.jetbrains.kotlin.codegen.state.JetTypeMapper;
import org.jetbrains.kotlin.descriptors.*;
import org.jetbrains.kotlin.load.java.descriptors.JavaClassDescriptor;
import org.jetbrains.kotlin.load.java.lazy.descriptors.LazyJavaPackageFragment;
import org.jetbrains.kotlin.load.kotlin.KotlinJvmBinaryClass;
import org.jetbrains.kotlin.load.kotlin.VirtualFileKotlinClass;
@@ -237,4 +238,11 @@ public class JvmCodegenUtil {
return InlineUtil.canBeInlineArgument(declaration) &&
InlineUtil.isInlinedArgument((JetFunction) declaration, bindingContext, false);
}
public static boolean shouldUseJavaClassForClassLiteral(@NotNull ClassifierDescriptor descriptor) {
ModuleDescriptor module = DescriptorUtils.getContainingModule(descriptor);
return descriptor instanceof JavaClassDescriptor ||
module == module.getBuiltIns().getBuiltInsModule() ||
DescriptorUtils.isAnnotationClass(descriptor);
}
}
@@ -16,21 +16,21 @@
package org.jetbrains.kotlin.codegen.inline
import org.jetbrains.org.objectweb.asm.Type
import org.jetbrains.org.objectweb.asm.tree.InsnList
import org.jetbrains.org.objectweb.asm.tree.MethodInsnNode
import org.jetbrains.org.objectweb.asm.tree.AbstractInsnNode
import org.jetbrains.org.objectweb.asm.Opcodes
import org.jetbrains.org.objectweb.asm.tree.TypeInsnNode
import com.google.common.collect.ImmutableSet
import org.jetbrains.kotlin.codegen.AsmUtil
import org.jetbrains.kotlin.codegen.JvmCodegenUtil
import org.jetbrains.kotlin.codegen.context.MethodContext
import org.jetbrains.kotlin.codegen.intrinsics.IntrinsicMethods
import kotlin.platform.platformStatic
import org.jetbrains.org.objectweb.asm.tree.LdcInsnNode
import org.jetbrains.kotlin.resolve.DescriptorUtils
import org.jetbrains.kotlin.resolve.jvm.AsmTypes
import org.jetbrains.kotlin.types.JetType
import org.jetbrains.org.objectweb.asm.MethodVisitor
import org.jetbrains.org.objectweb.asm.Opcodes
import org.jetbrains.org.objectweb.asm.Type
import org.jetbrains.org.objectweb.asm.signature.SignatureReader
import org.jetbrains.org.objectweb.asm.signature.SignatureWriter
import org.jetbrains.org.objectweb.asm.MethodVisitor
import com.google.common.collect.ImmutableSet
import org.jetbrains.kotlin.codegen.context.MethodContext
import org.jetbrains.kotlin.resolve.DescriptorUtils
import org.jetbrains.org.objectweb.asm.tree.*
import kotlin.platform.platformStatic
public class ReifiedTypeInliner(private val parametersMapping: ReifiedTypeParameterMappings?) {
@@ -39,11 +39,13 @@ public class ReifiedTypeInliner(private val parametersMapping: ReifiedTypeParame
public val CHECKCAST_MARKER_METHOD_NAME: String = "reifyCheckcast"
public val INSTANCEOF_MARKER_METHOD_NAME: String = "reifyInstanceof"
public val JAVA_CLASS_MARKER_METHOD_NAME: String = "reifyJavaClass"
public val CLASS_LITERAL_MARKER_METHOD_NAME: String = "reifyClassLiteral"
public val NEED_CLASS_REIFICATION_MARKER_METHOD_NAME: String = "needClassReification"
private val PARAMETRISED_MARKERS = ImmutableSet.of(
NEW_ARRAY_MARKER_METHOD_NAME, CHECKCAST_MARKER_METHOD_NAME,
INSTANCEOF_MARKER_METHOD_NAME, JAVA_CLASS_MARKER_METHOD_NAME
INSTANCEOF_MARKER_METHOD_NAME, JAVA_CLASS_MARKER_METHOD_NAME,
CLASS_LITERAL_MARKER_METHOD_NAME
)
private fun isParametrisedReifiedMarker(insn: AbstractInsnNode) =
@@ -139,6 +141,7 @@ public class ReifiedTypeInliner(private val parametersMapping: ReifiedTypeParame
CHECKCAST_MARKER_METHOD_NAME -> processCheckcast(insn, asmType)
INSTANCEOF_MARKER_METHOD_NAME -> processInstanceof(insn, asmType)
JAVA_CLASS_MARKER_METHOD_NAME -> processJavaClass(insn, asmType)
CLASS_LITERAL_MARKER_METHOD_NAME -> processClassLiteral(insn, asmType, instructions, mapping.type!!)
else -> false
}) {
instructions.remove(insn.getPrevious()!!)
@@ -153,13 +156,13 @@ public class ReifiedTypeInliner(private val parametersMapping: ReifiedTypeParame
}
private fun processNewArray(insn: MethodInsnNode, parameter: Type) =
processNextTypeInsn(insn, parameter, Opcodes.ANEWARRAY)
processNextTypeInsn(insn, parameter, Opcodes.ANEWARRAY)
private fun processCheckcast(insn: MethodInsnNode, parameter: Type) =
processNextTypeInsn(insn, parameter, Opcodes.CHECKCAST)
processNextTypeInsn(insn, parameter, Opcodes.CHECKCAST)
private fun processInstanceof(insn: MethodInsnNode, parameter: Type) =
processNextTypeInsn(insn, parameter, Opcodes.INSTANCEOF)
processNextTypeInsn(insn, parameter, Opcodes.INSTANCEOF)
private fun processNextTypeInsn(insn: MethodInsnNode, parameter: Type, expectedNextOpcode: Int): Boolean {
if (insn.getNext()?.getOpcode() != expectedNextOpcode) return false
@@ -174,6 +177,30 @@ public class ReifiedTypeInliner(private val parametersMapping: ReifiedTypeParame
return true
}
private fun processClassLiteral(insn: MethodInsnNode, parameter: Type, instructions: InsnList, type: JetType): Boolean {
val next = insn.next
if (next !is FieldInsnNode || next.opcode != Opcodes.GETSTATIC) return false
val descriptor = type.constructor.declarationDescriptor!!
if (JvmCodegenUtil.shouldUseJavaClassForClassLiteral(descriptor)) {
instructions.insertBefore(
next,
if (AsmUtil.isPrimitive(parameter))
FieldInsnNode(Opcodes.GETSTATIC, AsmUtil.boxType(parameter).internalName, "TYPE", "Ljava/lang/Class;")
else
LdcInsnNode(parameter)
)
val foreignKotlinClassDesc = Type.getMethodDescriptor(AsmTypes.K_CLASS_TYPE, AsmTypes.JAVA_CLASS_TYPE)
instructions.insertBefore(
next, MethodInsnNode(Opcodes.INVOKESTATIC, AsmTypes.REFLECTION, "foreignKotlinClass", foreignKotlinClassDesc, false)
)
instructions.remove(next)
}
else {
next.owner = AsmUtil.boxType(parameter).internalName
}
return true
}
private fun getParameterName(insn: MethodInsnNode): String? {
val prev = insn.getPrevious()!!
@@ -191,12 +218,12 @@ public class ReifiedTypeInliner(private val parametersMapping: ReifiedTypeParame
public class ReifiedTypeParameterMappings() {
private val mappingsByName = hashMapOf<String, ReifiedTypeParameterMapping>()
public fun addParameterMappingToType(name: String, asmType: Type, signature: String) {
mappingsByName[name] = ReifiedTypeParameterMapping(name, asmType, newName = null, signature = signature)
public fun addParameterMappingToType(name: String, type: JetType, asmType: Type, signature: String) {
mappingsByName[name] = ReifiedTypeParameterMapping(name, type, asmType, newName = null, signature = signature)
}
public fun addParameterMappingToNewParameter(name: String, newName: String) {
mappingsByName[name] = ReifiedTypeParameterMapping(name, asmType = null, newName = newName, signature = null)
mappingsByName[name] = ReifiedTypeParameterMapping(name, type = null, asmType = null, newName = newName, signature = null)
}
fun get(name: String): ReifiedTypeParameterMapping? {
@@ -204,7 +231,9 @@ public class ReifiedTypeParameterMappings() {
}
}
public class ReifiedTypeParameterMapping(val name: String, val asmType: Type?, val newName: String?, val signature: String?)
public class ReifiedTypeParameterMapping(
val name: String, val type: JetType?, val asmType: Type?, val newName: String?, val signature: String?
)
public class ReifiedTypeParametersUsages {
val usedTypeParameters: MutableSet<String> = hashSetOf()
@@ -62,6 +62,7 @@ public class IntrinsicMethods {
public IntrinsicMethods() {
namedMethods.put("kotlin.javaClass.function", new JavaClassFunction());
namedMethods.put("kotlin.javaClass.property", new JavaClassProperty());
namedMethods.put("kotlin.KClass.java.property", new KClassJavaProperty());
namedMethods.put("kotlin.arrays.array", new JavaClassArray());
namedMethods.put("kotlin.jvm.internal.unsafe.monitorEnter", MonitorInstruction.MONITOR_ENTER);
namedMethods.put("kotlin.jvm.internal.unsafe.monitorExit", MonitorInstruction.MONITOR_EXIT);
@@ -0,0 +1,31 @@
/*
* Copyright 2010-2015 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jetbrains.kotlin.codegen.intrinsics
import org.jetbrains.kotlin.codegen.ExpressionCodegen
import org.jetbrains.kotlin.codegen.StackValue
import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall
import org.jetbrains.org.objectweb.asm.Type
public abstract class IntrinsicPropertyGetter : IntrinsicMethod() {
public abstract fun generate(
resolvedCall: ResolvedCall<*>?,
codegen: ExpressionCodegen,
returnType: Type,
receiver: StackValue
): StackValue?
}
@@ -28,8 +28,13 @@ import org.jetbrains.kotlin.resolve.jvm.AsmTypes.getType
import org.jetbrains.org.objectweb.asm.Type
import org.jetbrains.org.objectweb.asm.commons.InstructionAdapter
public class JavaClassProperty : IntrinsicMethod() {
public fun generate(returnType: Type, receiver: StackValue): StackValue =
public class JavaClassProperty : IntrinsicPropertyGetter() {
public override fun generate(
resolvedCall: ResolvedCall<*>?,
codegen: ExpressionCodegen,
returnType: Type,
receiver: StackValue
): StackValue? =
StackValue.operation(returnType) {
val actualType = generateImpl(it, receiver)
StackValue.coerce(actualType, returnType, it)
@@ -0,0 +1,73 @@
/*
* Copyright 2010-2015 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jetbrains.kotlin.codegen.intrinsics
import org.jetbrains.kotlin.codegen.AsmUtil
import org.jetbrains.kotlin.codegen.ExpressionCodegen
import org.jetbrains.kotlin.codegen.StackValue
import org.jetbrains.kotlin.codegen.inline.ReifiedTypeInliner
import org.jetbrains.kotlin.descriptors.TypeParameterDescriptor
import org.jetbrains.kotlin.psi.JetClassLiteralExpression
import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall
import org.jetbrains.kotlin.resolve.jvm.AsmTypes
import org.jetbrains.kotlin.resolve.scopes.receivers.ExpressionReceiver
import org.jetbrains.kotlin.types.JetType
import org.jetbrains.org.objectweb.asm.Type
import org.jetbrains.org.objectweb.asm.commons.InstructionAdapter
public class KClassJavaProperty : IntrinsicPropertyGetter() {
override fun generate(resolvedCall: ResolvedCall<*>?, codegen: ExpressionCodegen, returnType: Type, receiver: StackValue): StackValue? {
val type = resolvedCall!!.extensionReceiver.type.arguments.single().type
val asmType = codegen.state.typeMapper.mapType(type)
return when {
isReifiedTypeParameter(type) -> {
StackValue.operation(returnType) { iv ->
codegen.putReifierMarkerIfTypeIsReifiedParameter(type, ReifiedTypeInliner.JAVA_CLASS_MARKER_METHOD_NAME)
AsmUtil.putJavaLangClassInstance(iv, asmType)
coerceToJavaLangClass(iv, returnType)
}
}
isWithClassLiteralArgument(resolvedCall) -> {
StackValue.operation(returnType) { iv ->
if (AsmUtil.isPrimitive(asmType)) {
iv.getstatic(AsmUtil.boxType(asmType).internalName, "TYPE", "Ljava/lang/Class;")
}
else {
iv.tconst(asmType)
}
coerceToJavaLangClass(iv, returnType)
}
}
else -> null
}
}
private fun isReifiedTypeParameter(type: JetType): Boolean {
val typeDescriptor = type.constructor.declarationDescriptor
return typeDescriptor is TypeParameterDescriptor && typeDescriptor.isReified
}
private fun isWithClassLiteralArgument(resolvedCall: ResolvedCall<*>): Boolean {
val extensionReceiver = resolvedCall.extensionReceiver
return extensionReceiver is ExpressionReceiver && extensionReceiver.expression is JetClassLiteralExpression
}
private fun coerceToJavaLangClass(iv: InstructionAdapter, returnType: Type) {
StackValue.coerce(AsmTypes.JAVA_CLASS_TYPE, returnType, iv)
}
}
@@ -31,7 +31,6 @@ import org.jetbrains.kotlin.builtins.KotlinBuiltIns;
import org.jetbrains.kotlin.descriptors.*;
import org.jetbrains.kotlin.descriptors.annotations.Annotations;
import org.jetbrains.kotlin.diagnostics.Diagnostic;
import org.jetbrains.kotlin.diagnostics.DiagnosticFactory;
import org.jetbrains.kotlin.lexer.JetTokens;
import org.jetbrains.kotlin.name.Name;
import org.jetbrains.kotlin.psi.*;
@@ -585,16 +584,23 @@ public class BasicExpressionTypingVisitor extends ExpressionTypingVisitor {
if (type.isMarkedNullable()) return false;
TypeConstructor typeConstructor = type.getConstructor();
if (!(typeConstructor.getDeclarationDescriptor() instanceof ClassDescriptor)) return false;
ClassifierDescriptor typeDeclarationDescriptor = typeConstructor.getDeclarationDescriptor();
List<TypeParameterDescriptor> parameters = typeConstructor.getParameters();
if (parameters.size() != type.getArguments().size()) return false;
if (typeDeclarationDescriptor instanceof ClassDescriptor) {
List<TypeParameterDescriptor> parameters = typeConstructor.getParameters();
if (parameters.size() != type.getArguments().size()) return false;
for (TypeParameterDescriptor parameter : parameters) {
if (!parameter.isReified()) return false;
for (TypeParameterDescriptor parameter : parameters) {
if (!parameter.isReified()) return false;
}
return true;
}
else if (typeDeclarationDescriptor instanceof TypeParameterDescriptor) {
return ((TypeParameterDescriptor) typeDeclarationDescriptor).isReified();
}
return true;
return false;
}
@Override
@@ -0,0 +1,29 @@
import kotlin.test.*
import kotlin.reflect.jvm.java
class Klass
class Other
inline fun <reified T> simpleName(): String =
T::class.simpleName!!
inline fun <reified T1, reified T2> twoReifiedParams(): String =
"${T1::class.simpleName!!}, ${T2::class.simpleName!!}"
inline fun <reified T> myJavaClass(): Class<T> =
T::class.java
fun box(): String {
assertEquals("Klass", simpleName<Klass>())
assertEquals("Int", simpleName<Int>())
assertEquals("Array", simpleName<Array<Int>>())
assertEquals("Error", simpleName<Error>())
assertEquals("Klass, Other", twoReifiedParams<Klass, Other>())
assertEquals(javaClass<String>(), myJavaClass<String>())
assertEquals(javaClass<IntArray>(), myJavaClass<IntArray>())
assertEquals(javaClass<Klass>(), myJavaClass<Klass>())
assertEquals(javaClass<Error>(), myJavaClass<Error>())
return "OK"
}
@@ -0,0 +1,16 @@
import kotlin.reflect.jvm.java
class Klass
fun foo() {
val c0 = (Klass::class).java // prevent intrinsic .java for class literal
val c1 = Klass::class.java
val c2 = Int::class.java
val c3 = Integer::class.java
}
// 2 LDC LKlass;.class
// 1 GETSTATIC java/lang/Integer.TYPE : Ljava/lang/Class;
// 1 INVOKESTATIC kotlin/reflect/jvm.*\.getJava
// 1 LDC Ljava/lang/Integer;.class
@@ -131,6 +131,12 @@ public class BytecodeTextTestGenerated extends AbstractBytecodeTextTest {
doTest(fileName);
}
@TestMetadata("javaExtensionPropertyIntrinsic.kt")
public void testJavaExtensionPropertyIntrinsic() throws Exception {
String fileName = JetTestUtils.navigationMetadata("compiler/testData/codegen/bytecodeText/javaExtensionPropertyIntrinsic.kt");
doTest(fileName);
}
@TestMetadata("kt2202.kt")
public void testKt2202() throws Exception {
String fileName = JetTestUtils.navigationMetadata("compiler/testData/codegen/bytecodeText/kt2202.kt");
@@ -2886,6 +2886,12 @@ public class BlackBoxWithStdlibCodegenTestGenerated extends AbstractBlackBoxCode
doTestWithStdlib(fileName);
}
@TestMetadata("reifiedTypeClassLiteral.kt")
public void testReifiedTypeClassLiteral() throws Exception {
String fileName = JetTestUtils.navigationMetadata("compiler/testData/codegen/boxWithStdlib/reflection/classLiterals/reifiedTypeClassLiteral.kt");
doTestWithStdlib(fileName);
}
@TestMetadata("simpleClassLiteral.kt")
public void testSimpleClassLiteral() throws Exception {
String fileName = JetTestUtils.navigationMetadata("compiler/testData/codegen/boxWithStdlib/reflection/classLiterals/simpleClassLiteral.kt");
@@ -3331,6 +3337,21 @@ public class BlackBoxWithStdlibCodegenTestGenerated extends AbstractBlackBoxCode
}
}
@TestMetadata("compiler/testData/codegen/boxWithStdlib/reflection/noKotlinReflect")
@TestDataPath("$PROJECT_ROOT")
@RunWith(JUnit3RunnerWithInners.class)
public static class NoKotlinReflect extends AbstractBlackBoxCodegenTest {
public void testAllFilesPresentInNoKotlinReflect() throws Exception {
JetTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/codegen/boxWithStdlib/reflection/noKotlinReflect"), Pattern.compile("^(.+)\\.kt$"), true);
}
@TestMetadata("simpleClassLiterals.kt")
public void testSimpleClassLiterals() throws Exception {
String fileName = JetTestUtils.navigationMetadata("compiler/testData/codegen/boxWithStdlib/reflection/noKotlinReflect/simpleClassLiterals.kt");
doTestWithStdlib(fileName);
}
}
@TestMetadata("compiler/testData/codegen/boxWithStdlib/reflection/packages")
@TestDataPath("$PROJECT_ROOT")
@RunWith(JUnit3RunnerWithInners.class)
@@ -20,6 +20,7 @@ import java.lang.reflect.Constructor
import java.lang.reflect.Field
import java.lang.reflect.Method
import java.lang.reflect.Modifier
import kotlin.jvm.internal.Intrinsic
import kotlin.reflect.*
import kotlin.reflect.jvm.internal.*
@@ -28,6 +29,7 @@ import kotlin.reflect.jvm.internal.*
/**
* Returns a Java [Class] instance corresponding to the given [KClass] instance.
*/
@Intrinsic("kotlin.KClass.java.property")
public val <T> KClass<T>.java: Class<T>
get() = (this as KClassImpl<T>).jClass