Generate reference to existing class for builtin function references
Instead of non-existing `kotlin.KotlinPackage`, which led to NoClassDefFoundError as soon as reflection tried to call getOwner on a builtin callable reference, use a reference to a new physical class `kotlin.jvm.internal.Intrinsics$Kotlin`. This will allow to support KT-17151. Note that for API version less than 1.4, this will still lead to NoClassDefFoundError, but this is not worse than the current situation where it happens anyway.
This commit is contained in:
@@ -1313,7 +1313,7 @@ class KotlinTypeMapper @JvmOverloads constructor(
|
|||||||
return JvmClassName.byClassId(ownerClassId).internalName
|
return JvmClassName.byClassId(ownerClassId).internalName
|
||||||
}
|
}
|
||||||
|
|
||||||
private val FAKE_CLASS_ID_FOR_BUILTINS = ClassId.topLevel(FqName("kotlin.KotlinPackage"))
|
private val FAKE_CLASS_ID_FOR_BUILTINS = ClassId(FqName("kotlin.jvm.internal"), FqName("Intrinsics.Kotlin"), false)
|
||||||
|
|
||||||
private fun getPackageMemberContainingClassesInfo(descriptor: DescriptorWithContainerSource): ContainingClassesInfo? {
|
private fun getPackageMemberContainingClassesInfo(descriptor: DescriptorWithContainerSource): ContainingClassesInfo? {
|
||||||
val containingDeclaration = descriptor.containingDeclaration
|
val containingDeclaration = descriptor.containingDeclaration
|
||||||
|
|||||||
Generated
+5
@@ -1963,6 +1963,11 @@ public class FirBlackBoxCodegenTestGenerated extends AbstractFirBlackBoxCodegenT
|
|||||||
KotlinTestUtils.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/codegen/box/callableReference"), Pattern.compile("^(.+)\\.kt$"), null, TargetBackend.JVM_IR, true);
|
KotlinTestUtils.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/codegen/box/callableReference"), Pattern.compile("^(.+)\\.kt$"), null, TargetBackend.JVM_IR, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@TestMetadata("builtinFunctionReferenceOwner.kt")
|
||||||
|
public void testBuiltinFunctionReferenceOwner() throws Exception {
|
||||||
|
runTest("compiler/testData/codegen/box/callableReference/builtinFunctionReferenceOwner.kt");
|
||||||
|
}
|
||||||
|
|
||||||
@TestMetadata("classesAreSynthetic.kt")
|
@TestMetadata("classesAreSynthetic.kt")
|
||||||
public void testClassesAreSynthetic() throws Exception {
|
public void testClassesAreSynthetic() throws Exception {
|
||||||
runTest("compiler/testData/codegen/box/callableReference/classesAreSynthetic.kt");
|
runTest("compiler/testData/codegen/box/callableReference/classesAreSynthetic.kt");
|
||||||
|
|||||||
@@ -19,9 +19,10 @@ import org.jetbrains.kotlin.descriptors.Modality
|
|||||||
import org.jetbrains.kotlin.descriptors.Visibilities
|
import org.jetbrains.kotlin.descriptors.Visibilities
|
||||||
import org.jetbrains.kotlin.descriptors.impl.EmptyPackageFragmentDescriptor
|
import org.jetbrains.kotlin.descriptors.impl.EmptyPackageFragmentDescriptor
|
||||||
import org.jetbrains.kotlin.ir.builders.declarations.*
|
import org.jetbrains.kotlin.ir.builders.declarations.*
|
||||||
import org.jetbrains.kotlin.ir.declarations.*
|
import org.jetbrains.kotlin.ir.declarations.IrClass
|
||||||
|
import org.jetbrains.kotlin.ir.declarations.IrDeclarationOrigin
|
||||||
|
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.declarations.impl.IrFunctionImpl
|
|
||||||
import org.jetbrains.kotlin.ir.symbols.*
|
import org.jetbrains.kotlin.ir.symbols.*
|
||||||
import org.jetbrains.kotlin.ir.symbols.impl.IrExternalPackageFragmentSymbolImpl
|
import org.jetbrains.kotlin.ir.symbols.impl.IrExternalPackageFragmentSymbolImpl
|
||||||
import org.jetbrains.kotlin.ir.types.*
|
import org.jetbrains.kotlin.ir.types.*
|
||||||
@@ -134,6 +135,13 @@ class JvmSymbols(
|
|||||||
addValueParameter("object", irBuiltIns.anyNType)
|
addValueParameter("object", irBuiltIns.anyNType)
|
||||||
}
|
}
|
||||||
klass.addFunction("throwNpe", irBuiltIns.unitType, isStatic = true)
|
klass.addFunction("throwNpe", irBuiltIns.unitType, isStatic = true)
|
||||||
|
|
||||||
|
klass.declarations.add(buildClass {
|
||||||
|
name = Name.identifier("Kotlin")
|
||||||
|
}.apply {
|
||||||
|
parent = klass
|
||||||
|
createImplicitParameterDeclarationWithWrappedDescriptor()
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
val checkExpressionValueIsNotNull: IrSimpleFunctionSymbol =
|
val checkExpressionValueIsNotNull: IrSimpleFunctionSymbol =
|
||||||
@@ -154,6 +162,9 @@ class JvmSymbols(
|
|||||||
val intrinsicStringPlus: IrFunctionSymbol =
|
val intrinsicStringPlus: IrFunctionSymbol =
|
||||||
intrinsicsClass.functions.single { it.owner.name.asString() == "stringPlus" }
|
intrinsicsClass.functions.single { it.owner.name.asString() == "stringPlus" }
|
||||||
|
|
||||||
|
val intrinsicsKotlinClass: IrClassSymbol =
|
||||||
|
(intrinsicsClass.owner.declarations.single { it is IrClass && it.name.asString() == "Kotlin" } as IrClass).symbol
|
||||||
|
|
||||||
override val stringBuilder: IrClassSymbol = createClass(FqName("java.lang.StringBuilder")) { klass ->
|
override val stringBuilder: IrClassSymbol = createClass(FqName("java.lang.StringBuilder")) { klass ->
|
||||||
klass.addConstructor()
|
klass.addConstructor()
|
||||||
klass.addFunction("toString", irBuiltIns.stringType).apply {
|
klass.addFunction("toString", irBuiltIns.stringType).apply {
|
||||||
|
|||||||
+9
-3
@@ -370,9 +370,15 @@ internal class CallableReferenceLowering(private val context: JvmBackendContext)
|
|||||||
kClassToJavaClass(kClassReference(classType), context)
|
kClassToJavaClass(kClassReference(classType), context)
|
||||||
|
|
||||||
internal fun IrBuilderWithScope.calculateOwner(irContainer: IrDeclarationParent, context: JvmBackendContext): IrExpression {
|
internal fun IrBuilderWithScope.calculateOwner(irContainer: IrDeclarationParent, context: JvmBackendContext): IrExpression {
|
||||||
// For built-in members (i.e. top level `toString`) we don't know any meaningful container, so we're generating Any.
|
val classType =
|
||||||
// The non-IR backend generates equally meaningless "kotlin/KotlinPackage" in this case (see KT-17151).
|
if (irContainer is IrClass) irContainer.defaultType
|
||||||
val kClass = kClassReference((irContainer as? IrClass)?.defaultType ?: context.irBuiltIns.anyNType)
|
else {
|
||||||
|
// For built-in members (i.e. top level `toString`) we generate reference to an internal class for an owner.
|
||||||
|
// This allows kotlin-reflect to understand that this is a built-in intrinsic which has no real declaration,
|
||||||
|
// and construct a special KCallable object.
|
||||||
|
context.ir.symbols.intrinsicsKotlinClass.defaultType
|
||||||
|
}
|
||||||
|
val kClass = kClassReference(classType)
|
||||||
|
|
||||||
if ((irContainer as? IrClass)?.isFileClass != true && irContainer !is IrPackageFragment)
|
if ((irContainer as? IrClass)?.isFileClass != true && irContainer !is IrPackageFragment)
|
||||||
return kClass
|
return kClass
|
||||||
|
|||||||
+12
@@ -0,0 +1,12 @@
|
|||||||
|
// TARGET_BACKEND: JVM
|
||||||
|
// IGNORE_BACKEND_FIR: JVM_IR
|
||||||
|
// WITH_RUNTIME
|
||||||
|
|
||||||
|
fun box(): String {
|
||||||
|
val f = Any?::toString
|
||||||
|
|
||||||
|
val owner = (f as kotlin.jvm.internal.CallableReference).owner as kotlin.jvm.internal.PackageReference
|
||||||
|
if (owner.jClass.name != "kotlin.jvm.internal.Intrinsics\$Kotlin") return "Fail: $owner"
|
||||||
|
|
||||||
|
return "OK"
|
||||||
|
}
|
||||||
+5
@@ -1983,6 +1983,11 @@ public class BlackBoxCodegenTestGenerated extends AbstractBlackBoxCodegenTest {
|
|||||||
KotlinTestUtils.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/codegen/box/callableReference"), Pattern.compile("^(.+)\\.kt$"), null, TargetBackend.JVM, true);
|
KotlinTestUtils.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/codegen/box/callableReference"), Pattern.compile("^(.+)\\.kt$"), null, TargetBackend.JVM, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@TestMetadata("builtinFunctionReferenceOwner.kt")
|
||||||
|
public void testBuiltinFunctionReferenceOwner() throws Exception {
|
||||||
|
runTest("compiler/testData/codegen/box/callableReference/builtinFunctionReferenceOwner.kt");
|
||||||
|
}
|
||||||
|
|
||||||
@TestMetadata("classesAreSynthetic.kt")
|
@TestMetadata("classesAreSynthetic.kt")
|
||||||
public void testClassesAreSynthetic() throws Exception {
|
public void testClassesAreSynthetic() throws Exception {
|
||||||
runTest("compiler/testData/codegen/box/callableReference/classesAreSynthetic.kt");
|
runTest("compiler/testData/codegen/box/callableReference/classesAreSynthetic.kt");
|
||||||
|
|||||||
+5
@@ -1983,6 +1983,11 @@ public class LightAnalysisModeTestGenerated extends AbstractLightAnalysisModeTes
|
|||||||
KotlinTestUtils.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/codegen/box/callableReference"), Pattern.compile("^(.+)\\.kt$"), null, TargetBackend.JVM, true);
|
KotlinTestUtils.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/codegen/box/callableReference"), Pattern.compile("^(.+)\\.kt$"), null, TargetBackend.JVM, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@TestMetadata("builtinFunctionReferenceOwner.kt")
|
||||||
|
public void testBuiltinFunctionReferenceOwner() throws Exception {
|
||||||
|
runTest("compiler/testData/codegen/box/callableReference/builtinFunctionReferenceOwner.kt");
|
||||||
|
}
|
||||||
|
|
||||||
@TestMetadata("classesAreSynthetic.kt")
|
@TestMetadata("classesAreSynthetic.kt")
|
||||||
public void testClassesAreSynthetic() throws Exception {
|
public void testClassesAreSynthetic() throws Exception {
|
||||||
runTest("compiler/testData/codegen/box/callableReference/classesAreSynthetic.kt");
|
runTest("compiler/testData/codegen/box/callableReference/classesAreSynthetic.kt");
|
||||||
|
|||||||
+5
@@ -1963,6 +1963,11 @@ public class IrBlackBoxCodegenTestGenerated extends AbstractIrBlackBoxCodegenTes
|
|||||||
KotlinTestUtils.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/codegen/box/callableReference"), Pattern.compile("^(.+)\\.kt$"), null, TargetBackend.JVM_IR, true);
|
KotlinTestUtils.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/codegen/box/callableReference"), Pattern.compile("^(.+)\\.kt$"), null, TargetBackend.JVM_IR, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@TestMetadata("builtinFunctionReferenceOwner.kt")
|
||||||
|
public void testBuiltinFunctionReferenceOwner() throws Exception {
|
||||||
|
runTest("compiler/testData/codegen/box/callableReference/builtinFunctionReferenceOwner.kt");
|
||||||
|
}
|
||||||
|
|
||||||
@TestMetadata("classesAreSynthetic.kt")
|
@TestMetadata("classesAreSynthetic.kt")
|
||||||
public void testClassesAreSynthetic() throws Exception {
|
public void testClassesAreSynthetic() throws Exception {
|
||||||
runTest("compiler/testData/codegen/box/callableReference/classesAreSynthetic.kt");
|
runTest("compiler/testData/codegen/box/callableReference/classesAreSynthetic.kt");
|
||||||
|
|||||||
@@ -266,4 +266,11 @@ public class Intrinsics {
|
|||||||
throwable.setStackTrace(newStackTrace);
|
throwable.setStackTrace(newStackTrace);
|
||||||
return throwable;
|
return throwable;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Stub class which is used as an owner of callable references for built-ins declared in package "kotlin".
|
||||||
|
@SinceKotlin(version = "1.4")
|
||||||
|
public static class Kotlin {
|
||||||
|
private Kotlin() {
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+3
@@ -3437,6 +3437,9 @@ public class kotlin/jvm/internal/Intrinsics {
|
|||||||
public static fun throwUninitializedPropertyAccessException (Ljava/lang/String;)V
|
public static fun throwUninitializedPropertyAccessException (Ljava/lang/String;)V
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public class kotlin/jvm/internal/Intrinsics$Kotlin {
|
||||||
|
}
|
||||||
|
|
||||||
public abstract class kotlin/jvm/internal/Lambda : java/io/Serializable, kotlin/jvm/internal/FunctionBase {
|
public abstract class kotlin/jvm/internal/Lambda : java/io/Serializable, kotlin/jvm/internal/FunctionBase {
|
||||||
public fun <init> (I)V
|
public fun <init> (I)V
|
||||||
public fun getArity ()I
|
public fun getArity ()I
|
||||||
|
|||||||
Reference in New Issue
Block a user