diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/state/KotlinTypeMapper.kt b/compiler/backend/src/org/jetbrains/kotlin/codegen/state/KotlinTypeMapper.kt index 21505664194..8b449c7bbc8 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/state/KotlinTypeMapper.kt +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/state/KotlinTypeMapper.kt @@ -1313,7 +1313,7 @@ class KotlinTypeMapper @JvmOverloads constructor( 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? { val containingDeclaration = descriptor.containingDeclaration diff --git a/compiler/fir/fir2ir/tests/org/jetbrains/kotlin/codegen/ir/FirBlackBoxCodegenTestGenerated.java b/compiler/fir/fir2ir/tests/org/jetbrains/kotlin/codegen/ir/FirBlackBoxCodegenTestGenerated.java index e573ffa75e1..d3e182475a9 100644 --- a/compiler/fir/fir2ir/tests/org/jetbrains/kotlin/codegen/ir/FirBlackBoxCodegenTestGenerated.java +++ b/compiler/fir/fir2ir/tests/org/jetbrains/kotlin/codegen/ir/FirBlackBoxCodegenTestGenerated.java @@ -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); } + @TestMetadata("builtinFunctionReferenceOwner.kt") + public void testBuiltinFunctionReferenceOwner() throws Exception { + runTest("compiler/testData/codegen/box/callableReference/builtinFunctionReferenceOwner.kt"); + } + @TestMetadata("classesAreSynthetic.kt") public void testClassesAreSynthetic() throws Exception { runTest("compiler/testData/codegen/box/callableReference/classesAreSynthetic.kt"); diff --git a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/JvmSymbols.kt b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/JvmSymbols.kt index 859a58d37ff..cd687d1790c 100644 --- a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/JvmSymbols.kt +++ b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/JvmSymbols.kt @@ -19,9 +19,10 @@ import org.jetbrains.kotlin.descriptors.Modality import org.jetbrains.kotlin.descriptors.Visibilities import org.jetbrains.kotlin.descriptors.impl.EmptyPackageFragmentDescriptor 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.IrFunctionImpl import org.jetbrains.kotlin.ir.symbols.* import org.jetbrains.kotlin.ir.symbols.impl.IrExternalPackageFragmentSymbolImpl import org.jetbrains.kotlin.ir.types.* @@ -134,6 +135,13 @@ class JvmSymbols( addValueParameter("object", irBuiltIns.anyNType) } klass.addFunction("throwNpe", irBuiltIns.unitType, isStatic = true) + + klass.declarations.add(buildClass { + name = Name.identifier("Kotlin") + }.apply { + parent = klass + createImplicitParameterDeclarationWithWrappedDescriptor() + }) } val checkExpressionValueIsNotNull: IrSimpleFunctionSymbol = @@ -154,6 +162,9 @@ class JvmSymbols( val intrinsicStringPlus: IrFunctionSymbol = 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 -> klass.addConstructor() klass.addFunction("toString", irBuiltIns.stringType).apply { diff --git a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/lower/CallableReferenceLowering.kt b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/lower/CallableReferenceLowering.kt index 767549ee173..fbc75c3238b 100644 --- a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/lower/CallableReferenceLowering.kt +++ b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/lower/CallableReferenceLowering.kt @@ -370,9 +370,15 @@ internal class CallableReferenceLowering(private val context: JvmBackendContext) kClassToJavaClass(kClassReference(classType), context) 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. - // The non-IR backend generates equally meaningless "kotlin/KotlinPackage" in this case (see KT-17151). - val kClass = kClassReference((irContainer as? IrClass)?.defaultType ?: context.irBuiltIns.anyNType) + val classType = + if (irContainer is IrClass) irContainer.defaultType + 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) return kClass diff --git a/compiler/testData/codegen/box/callableReference/builtinFunctionReferenceOwner.kt b/compiler/testData/codegen/box/callableReference/builtinFunctionReferenceOwner.kt new file mode 100644 index 00000000000..98a81858b1d --- /dev/null +++ b/compiler/testData/codegen/box/callableReference/builtinFunctionReferenceOwner.kt @@ -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" +} diff --git a/compiler/tests/org/jetbrains/kotlin/codegen/BlackBoxCodegenTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/codegen/BlackBoxCodegenTestGenerated.java index 00711153317..9032db2a9ab 100644 --- a/compiler/tests/org/jetbrains/kotlin/codegen/BlackBoxCodegenTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/codegen/BlackBoxCodegenTestGenerated.java @@ -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); } + @TestMetadata("builtinFunctionReferenceOwner.kt") + public void testBuiltinFunctionReferenceOwner() throws Exception { + runTest("compiler/testData/codegen/box/callableReference/builtinFunctionReferenceOwner.kt"); + } + @TestMetadata("classesAreSynthetic.kt") public void testClassesAreSynthetic() throws Exception { runTest("compiler/testData/codegen/box/callableReference/classesAreSynthetic.kt"); diff --git a/compiler/tests/org/jetbrains/kotlin/codegen/LightAnalysisModeTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/codegen/LightAnalysisModeTestGenerated.java index 1a8e1241b70..b126726b505 100644 --- a/compiler/tests/org/jetbrains/kotlin/codegen/LightAnalysisModeTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/codegen/LightAnalysisModeTestGenerated.java @@ -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); } + @TestMetadata("builtinFunctionReferenceOwner.kt") + public void testBuiltinFunctionReferenceOwner() throws Exception { + runTest("compiler/testData/codegen/box/callableReference/builtinFunctionReferenceOwner.kt"); + } + @TestMetadata("classesAreSynthetic.kt") public void testClassesAreSynthetic() throws Exception { runTest("compiler/testData/codegen/box/callableReference/classesAreSynthetic.kt"); diff --git a/compiler/tests/org/jetbrains/kotlin/codegen/ir/IrBlackBoxCodegenTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/codegen/ir/IrBlackBoxCodegenTestGenerated.java index d145a999a78..330d7cf3f46 100644 --- a/compiler/tests/org/jetbrains/kotlin/codegen/ir/IrBlackBoxCodegenTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/codegen/ir/IrBlackBoxCodegenTestGenerated.java @@ -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); } + @TestMetadata("builtinFunctionReferenceOwner.kt") + public void testBuiltinFunctionReferenceOwner() throws Exception { + runTest("compiler/testData/codegen/box/callableReference/builtinFunctionReferenceOwner.kt"); + } + @TestMetadata("classesAreSynthetic.kt") public void testClassesAreSynthetic() throws Exception { runTest("compiler/testData/codegen/box/callableReference/classesAreSynthetic.kt"); diff --git a/libraries/stdlib/jvm/runtime/kotlin/jvm/internal/Intrinsics.java b/libraries/stdlib/jvm/runtime/kotlin/jvm/internal/Intrinsics.java index 10e03019324..86b996ada14 100644 --- a/libraries/stdlib/jvm/runtime/kotlin/jvm/internal/Intrinsics.java +++ b/libraries/stdlib/jvm/runtime/kotlin/jvm/internal/Intrinsics.java @@ -266,4 +266,11 @@ public class Intrinsics { throwable.setStackTrace(newStackTrace); 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() { + } + } } diff --git a/libraries/tools/binary-compatibility-validator/reference-public-api/kotlin-stdlib-runtime-merged.txt b/libraries/tools/binary-compatibility-validator/reference-public-api/kotlin-stdlib-runtime-merged.txt index edb749fc7e9..d7ab4c8aaa0 100644 --- a/libraries/tools/binary-compatibility-validator/reference-public-api/kotlin-stdlib-runtime-merged.txt +++ b/libraries/tools/binary-compatibility-validator/reference-public-api/kotlin-stdlib-runtime-merged.txt @@ -3437,6 +3437,9 @@ public class kotlin/jvm/internal/Intrinsics { 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 fun (I)V public fun getArity ()I