From 247efb220cbaf08e07b1810c0129eb9a5d76b384 Mon Sep 17 00:00:00 2001 From: Alexander Udalov Date: Mon, 8 Mar 2021 19:40:40 +0100 Subject: [PATCH] Do not require backing fields for extension properties This has no effect on correct code because extension properties cannot have a backing field anyway and that is checked separately. But this function is used in psi2ir to determine whether or not to create a backing field for a property, and in case the code where the property is declared is unreachable like in KT-44496 and has no explicit getter or setter, it would previously return true for extension properties, which on JVM would result in an actual field in the class file, which made no sense. After this change, the compiler will actually crash with an exception in the IR validaton step because the symbol for the field is unbound. That is a bit better than proceeding to generate potentially invalid bytecode, but of course a proper fix would be to report an error in the frontend. #KT-44496 --- .../src/org/jetbrains/kotlin/resolve/resolveUtil.kt | 1 + .../source.kt | 7 +++++++ .../source.kt | 8 ++++++++ .../compiler/CompileKotlinAgainstCustomBinariesTest.kt | 10 ++++++++++ 4 files changed, 26 insertions(+) create mode 100644 compiler/testData/compileKotlinAgainstCustomBinaries/unreachableExtensionValPropertyDeclaration/source.kt create mode 100644 compiler/testData/compileKotlinAgainstCustomBinaries/unreachableExtensionVarPropertyDeclaration/source.kt diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/resolveUtil.kt b/compiler/frontend/src/org/jetbrains/kotlin/resolve/resolveUtil.kt index a3662f9d578..ce92e779851 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/resolveUtil.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/resolveUtil.kt @@ -11,6 +11,7 @@ import org.jetbrains.kotlin.resolve.source.KotlinSourceElement fun PropertyDescriptor.hasBackingField(bindingContext: BindingContext?): Boolean = when { kind == CallableMemberDescriptor.Kind.FAKE_OVERRIDE -> overriddenDescriptors.any { it.hasBackingField(bindingContext) } + extensionReceiverParameter != null -> false source is KotlinSourceElement && bindingContext != null -> bindingContext.get(BindingContext.BACKING_FIELD_REQUIRED, this) ?: false compileTimeInitializer != null -> true // backingField != null -> true // TODO: in case of DeserializedPropetyDescriptor this function returns incorrect result for FO field diff --git a/compiler/testData/compileKotlinAgainstCustomBinaries/unreachableExtensionValPropertyDeclaration/source.kt b/compiler/testData/compileKotlinAgainstCustomBinaries/unreachableExtensionValPropertyDeclaration/source.kt new file mode 100644 index 00000000000..eb7ad43b6ad --- /dev/null +++ b/compiler/testData/compileKotlinAgainstCustomBinaries/unreachableExtensionValPropertyDeclaration/source.kt @@ -0,0 +1,7 @@ +// KT-44496 + +class C { + val todo: String = TODO() + + val String.noGetterExtensionProperty: Int +} diff --git a/compiler/testData/compileKotlinAgainstCustomBinaries/unreachableExtensionVarPropertyDeclaration/source.kt b/compiler/testData/compileKotlinAgainstCustomBinaries/unreachableExtensionVarPropertyDeclaration/source.kt new file mode 100644 index 00000000000..569482f6fb8 --- /dev/null +++ b/compiler/testData/compileKotlinAgainstCustomBinaries/unreachableExtensionVarPropertyDeclaration/source.kt @@ -0,0 +1,8 @@ +// KT-44496 + +class C { + val todo: String = TODO() + + var String.noSetterExtensionProperty: Int + get() = 42 +} diff --git a/compiler/tests/org/jetbrains/kotlin/jvm/compiler/CompileKotlinAgainstCustomBinariesTest.kt b/compiler/tests/org/jetbrains/kotlin/jvm/compiler/CompileKotlinAgainstCustomBinariesTest.kt index 20cd32ce46f..c417879f652 100644 --- a/compiler/tests/org/jetbrains/kotlin/jvm/compiler/CompileKotlinAgainstCustomBinariesTest.kt +++ b/compiler/tests/org/jetbrains/kotlin/jvm/compiler/CompileKotlinAgainstCustomBinariesTest.kt @@ -696,6 +696,16 @@ class CompileKotlinAgainstCustomBinariesTest : AbstractKotlinCompilerIntegration compileKotlin("main.kt", tmpdir, listOf(library), additionalOptions = features) } + fun testUnreachableExtensionVarPropertyDeclaration() { + val (output, exitCode) = compileKotlin("source.kt", tmpdir, expectedFileName = null) + assertEquals("Output:\n$output", ExitCode.INTERNAL_ERROR, exitCode) + } + + fun testUnreachableExtensionValPropertyDeclaration() { + val (output, exitCode) = compileKotlin("source.kt", tmpdir, expectedFileName = null) + assertEquals("Output:\n$output", ExitCode.INTERNAL_ERROR, exitCode) + } + // If this test fails, then bootstrap compiler most likely should be advanced fun testPreReleaseFlagIsConsistentBetweenBootstrapAndCurrentCompiler() { val bootstrapCompiler = JarFile(PathUtil.kotlinPathsForCompiler.compilerPath)