From a0cc313156a0c9fa7591527d2b38a37ed0b8dfa8 Mon Sep 17 00:00:00 2001 From: Alexander Udalov Date: Wed, 29 Jul 2015 23:43:11 +0300 Subject: [PATCH] Support class reference expression for reified type parameters Also make KClass::java an intrinsic property. Based on the work by @dnpetrov #KT-6976 Fixed --- .../kotlin/codegen/ExpressionCodegen.java | 39 +++++++--- .../kotlin/codegen/JvmCodegenUtil.java | 8 ++ .../codegen/inline/ReifiedTypeInliner.kt | 69 +++++++++++++----- .../codegen/intrinsics/IntrinsicMethods.java | 1 + .../intrinsics/IntrinsicPropertyGetter.kt | 31 ++++++++ .../codegen/intrinsics/JavaClassProperty.kt | 9 ++- .../codegen/intrinsics/KClassJavaProperty.kt | 73 +++++++++++++++++++ .../BasicExpressionTypingVisitor.java | 20 +++-- .../classLiterals/reifiedTypeClassLiteral.kt | 29 ++++++++ .../javaExtensionPropertyIntrinsic.kt | 16 ++++ .../codegen/BytecodeTextTestGenerated.java | 6 ++ ...lackBoxWithStdlibCodegenTestGenerated.java | 21 ++++++ .../src/kotlin/reflect/jvm/mapping.kt | 2 + 13 files changed, 283 insertions(+), 41 deletions(-) create mode 100644 compiler/backend/src/org/jetbrains/kotlin/codegen/intrinsics/IntrinsicPropertyGetter.kt create mode 100644 compiler/backend/src/org/jetbrains/kotlin/codegen/intrinsics/KClassJavaProperty.kt create mode 100644 compiler/testData/codegen/boxWithStdlib/reflection/classLiterals/reifiedTypeClassLiteral.kt create mode 100644 compiler/testData/codegen/bytecodeText/javaExtensionPropertyIntrinsic.kt diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/ExpressionCodegen.java b/compiler/backend/src/org/jetbrains/kotlin/codegen/ExpressionCodegen.java index 6bb752c0ffb..9dacfd896b1 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/ExpressionCodegen.java +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/ExpressionCodegen.java @@ -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 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 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 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); } diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/JvmCodegenUtil.java b/compiler/backend/src/org/jetbrains/kotlin/codegen/JvmCodegenUtil.java index 925d3eb050c..1f3632968e4 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/JvmCodegenUtil.java +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/JvmCodegenUtil.java @@ -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); + } } diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/ReifiedTypeInliner.kt b/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/ReifiedTypeInliner.kt index 827fb144cd3..5541d35d1be 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/ReifiedTypeInliner.kt +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/ReifiedTypeInliner.kt @@ -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() - 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 = hashSetOf() diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/intrinsics/IntrinsicMethods.java b/compiler/backend/src/org/jetbrains/kotlin/codegen/intrinsics/IntrinsicMethods.java index fa44fb39ea3..910bc70f326 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/intrinsics/IntrinsicMethods.java +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/intrinsics/IntrinsicMethods.java @@ -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); diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/intrinsics/IntrinsicPropertyGetter.kt b/compiler/backend/src/org/jetbrains/kotlin/codegen/intrinsics/IntrinsicPropertyGetter.kt new file mode 100644 index 00000000000..fed6580a3e8 --- /dev/null +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/intrinsics/IntrinsicPropertyGetter.kt @@ -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? +} diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/intrinsics/JavaClassProperty.kt b/compiler/backend/src/org/jetbrains/kotlin/codegen/intrinsics/JavaClassProperty.kt index 9db6e9dc010..bcaf482c2b7 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/intrinsics/JavaClassProperty.kt +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/intrinsics/JavaClassProperty.kt @@ -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) diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/intrinsics/KClassJavaProperty.kt b/compiler/backend/src/org/jetbrains/kotlin/codegen/intrinsics/KClassJavaProperty.kt new file mode 100644 index 00000000000..dfd43fbf695 --- /dev/null +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/intrinsics/KClassJavaProperty.kt @@ -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) + } +} diff --git a/compiler/frontend/src/org/jetbrains/kotlin/types/expressions/BasicExpressionTypingVisitor.java b/compiler/frontend/src/org/jetbrains/kotlin/types/expressions/BasicExpressionTypingVisitor.java index dced3c69a77..b6cdd225a5e 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/types/expressions/BasicExpressionTypingVisitor.java +++ b/compiler/frontend/src/org/jetbrains/kotlin/types/expressions/BasicExpressionTypingVisitor.java @@ -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 parameters = typeConstructor.getParameters(); - if (parameters.size() != type.getArguments().size()) return false; + if (typeDeclarationDescriptor instanceof ClassDescriptor) { + List 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 diff --git a/compiler/testData/codegen/boxWithStdlib/reflection/classLiterals/reifiedTypeClassLiteral.kt b/compiler/testData/codegen/boxWithStdlib/reflection/classLiterals/reifiedTypeClassLiteral.kt new file mode 100644 index 00000000000..5e8d22cc6d6 --- /dev/null +++ b/compiler/testData/codegen/boxWithStdlib/reflection/classLiterals/reifiedTypeClassLiteral.kt @@ -0,0 +1,29 @@ +import kotlin.test.* +import kotlin.reflect.jvm.java + +class Klass +class Other + +inline fun simpleName(): String = + T::class.simpleName!! + +inline fun twoReifiedParams(): String = + "${T1::class.simpleName!!}, ${T2::class.simpleName!!}" + +inline fun myJavaClass(): Class = + T::class.java + +fun box(): String { + assertEquals("Klass", simpleName()) + assertEquals("Int", simpleName()) + assertEquals("Array", simpleName>()) + assertEquals("Error", simpleName()) + assertEquals("Klass, Other", twoReifiedParams()) + + assertEquals(javaClass(), myJavaClass()) + assertEquals(javaClass(), myJavaClass()) + assertEquals(javaClass(), myJavaClass()) + assertEquals(javaClass(), myJavaClass()) + + return "OK" +} diff --git a/compiler/testData/codegen/bytecodeText/javaExtensionPropertyIntrinsic.kt b/compiler/testData/codegen/bytecodeText/javaExtensionPropertyIntrinsic.kt new file mode 100644 index 00000000000..f61fc0dcc0d --- /dev/null +++ b/compiler/testData/codegen/bytecodeText/javaExtensionPropertyIntrinsic.kt @@ -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 diff --git a/compiler/tests/org/jetbrains/kotlin/codegen/BytecodeTextTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/codegen/BytecodeTextTestGenerated.java index d7b551fb128..e06e6b389d4 100644 --- a/compiler/tests/org/jetbrains/kotlin/codegen/BytecodeTextTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/codegen/BytecodeTextTestGenerated.java @@ -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"); diff --git a/compiler/tests/org/jetbrains/kotlin/codegen/generated/BlackBoxWithStdlibCodegenTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/codegen/generated/BlackBoxWithStdlibCodegenTestGenerated.java index 978716473f2..879ce52c054 100644 --- a/compiler/tests/org/jetbrains/kotlin/codegen/generated/BlackBoxWithStdlibCodegenTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/codegen/generated/BlackBoxWithStdlibCodegenTestGenerated.java @@ -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) diff --git a/core/reflection.jvm/src/kotlin/reflect/jvm/mapping.kt b/core/reflection.jvm/src/kotlin/reflect/jvm/mapping.kt index 75945d3bce1..9715c173e0d 100644 --- a/core/reflection.jvm/src/kotlin/reflect/jvm/mapping.kt +++ b/core/reflection.jvm/src/kotlin/reflect/jvm/mapping.kt @@ -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 KClass.java: Class get() = (this as KClassImpl).jClass