JVM: use a safer version of fileParent for Java declarations

Java declarations do not have a file parent, their outer element is
IrExternalPackageFragment.

The test did not fail in K1 only by accident, because there's an extra
IrTypeOperatorCall on the property reference's dispatch receiver, which
automatically makes it non-inlinable. In K2, it's IrGetField, so we were
trying to compute if its dispatch receiver is inlinable and for that we
tried to get its fileParent, which resulted in exception if it comes
from Java.

Also refactor PropertyReferenceDelegationTransformer.canInline a bit.

 #KT-57955 Fixed
This commit is contained in:
Alexander Udalov
2023-05-09 15:12:23 +02:00
committed by Space Team
parent e2dafdb5b9
commit ff65324172
9 changed files with 84 additions and 16 deletions
@@ -15142,6 +15142,12 @@ public class FirLightTreeBlackBoxCodegenTestGenerated extends AbstractFirLightTr
runTest("compiler/testData/codegen/box/delegatedProperty/delegateToAnother/kt50019_noOptimizedCallableReferences.kt"); runTest("compiler/testData/codegen/box/delegatedProperty/delegateToAnother/kt50019_noOptimizedCallableReferences.kt");
} }
@Test
@TestMetadata("kt57955.kt")
public void testKt57955() throws Exception {
runTest("compiler/testData/codegen/box/delegatedProperty/delegateToAnother/kt57955.kt");
}
@Test @Test
@TestMetadata("mutable.kt") @TestMetadata("mutable.kt")
public void testMutable() throws Exception { public void testMutable() throws Exception {
@@ -15142,6 +15142,12 @@ public class FirPsiBlackBoxCodegenTestGenerated extends AbstractFirPsiBlackBoxCo
runTest("compiler/testData/codegen/box/delegatedProperty/delegateToAnother/kt50019_noOptimizedCallableReferences.kt"); runTest("compiler/testData/codegen/box/delegatedProperty/delegateToAnother/kt50019_noOptimizedCallableReferences.kt");
} }
@Test
@TestMetadata("kt57955.kt")
public void testKt57955() throws Exception {
runTest("compiler/testData/codegen/box/delegatedProperty/delegateToAnother/kt57955.kt");
}
@Test @Test
@TestMetadata("mutable.kt") @TestMetadata("mutable.kt")
public void testMutable() throws Exception { public void testMutable() throws Exception {
@@ -11,7 +11,7 @@ import org.jetbrains.kotlin.backend.common.lower.parents
import org.jetbrains.kotlin.backend.common.phaser.makeIrFilePhase import org.jetbrains.kotlin.backend.common.phaser.makeIrFilePhase
import org.jetbrains.kotlin.backend.jvm.JvmBackendContext import org.jetbrains.kotlin.backend.jvm.JvmBackendContext
import org.jetbrains.kotlin.backend.jvm.ir.createJvmIrBuilder import org.jetbrains.kotlin.backend.jvm.ir.createJvmIrBuilder
import org.jetbrains.kotlin.backend.jvm.ir.fileParent import org.jetbrains.kotlin.backend.jvm.ir.fileParentOrNull
import org.jetbrains.kotlin.backend.jvm.lower.JvmPropertiesLowering.Companion.createSyntheticMethodForPropertyDelegate import org.jetbrains.kotlin.backend.jvm.lower.JvmPropertiesLowering.Companion.createSyntheticMethodForPropertyDelegate
import org.jetbrains.kotlin.builtins.StandardNames import org.jetbrains.kotlin.builtins.StandardNames
import org.jetbrains.kotlin.descriptors.Modality import org.jetbrains.kotlin.descriptors.Modality
@@ -21,7 +21,8 @@ import org.jetbrains.kotlin.ir.builders.declarations.buildField
import org.jetbrains.kotlin.ir.builders.declarations.buildVariable import org.jetbrains.kotlin.ir.builders.declarations.buildVariable
import org.jetbrains.kotlin.ir.declarations.* import org.jetbrains.kotlin.ir.declarations.*
import org.jetbrains.kotlin.ir.expressions.* import org.jetbrains.kotlin.ir.expressions.*
import org.jetbrains.kotlin.ir.expressions.impl.* import org.jetbrains.kotlin.ir.expressions.impl.IrCompositeImpl
import org.jetbrains.kotlin.ir.expressions.impl.IrPropertyReferenceImpl
import org.jetbrains.kotlin.ir.symbols.impl.IrAnonymousInitializerSymbolImpl import org.jetbrains.kotlin.ir.symbols.impl.IrAnonymousInitializerSymbolImpl
import org.jetbrains.kotlin.ir.util.* import org.jetbrains.kotlin.ir.util.*
import org.jetbrains.kotlin.ir.visitors.IrElementTransformerVoid import org.jetbrains.kotlin.ir.visitors.IrElementTransformerVoid
@@ -89,15 +90,28 @@ private class PropertyReferenceDelegationTransformer(val context: JvmBackendCont
// Some receivers don't need to be stored in fields and can be reevaluated every time an accessor is called: // Some receivers don't need to be stored in fields and can be reevaluated every time an accessor is called:
private fun IrExpression.canInline(visibleScopes: Set<IrDeclarationParent>): Boolean = when (this) { private fun IrExpression.canInline(visibleScopes: Set<IrDeclarationParent>): Boolean = when (this) {
// Reads of immutable variables are stable, but value parameters of the constructor are not in scope: is IrGetValue -> {
is IrGetValue -> symbol.owner.let { !(it is IrVariable && it.isVar) && it.parent in visibleScopes } // Reads of immutable variables are stable, but value parameters of the constructor are not in scope:
// Reads of final fields of stable values are stable, but fields in other files can become non-final: val value = symbol.owner
is IrGetField -> symbol.owner.let { it.isFinal && it.fileParent in visibleScopes } && receiver?.canInline(visibleScopes) != false !(value is IrVariable && value.isVar) && value.parent in visibleScopes
// Same applies to reads of properties with default getters, but non-final properties may be overridden by `var`s: }
is IrCall -> symbol.owner.let { it.isFinalDefaultValGetter && it.fileParent in visibleScopes } && is IrGetField -> {
dispatchReceiver?.canInline(visibleScopes) != false && extensionReceiver?.canInline(visibleScopes) != false // Reads of final fields of stable values are stable, but fields in other files can become non-final:
// Constants and singleton object accesses are always stable: val field = symbol.owner
else -> isTrivial() field.isFinal && field.fileParentOrNull.let { it != null && it in visibleScopes }
&& receiver?.canInline(visibleScopes) != false
}
is IrCall -> {
// Same applies to reads of properties with default getters, but non-final properties may be overridden by `var`s:
val callee = symbol.owner
callee.isFinalDefaultValGetter && callee.fileParentOrNull.let { it != null && it in visibleScopes }
&& dispatchReceiver?.canInline(visibleScopes) != false
&& extensionReceiver?.canInline(visibleScopes) != false
}
else -> {
// Constants and singleton object accesses are always stable:
isTrivial()
}
} }
private val IrSimpleFunction.isFinalDefaultValGetter: Boolean private val IrSimpleFunction.isFinalDefaultValGetter: Boolean
@@ -441,11 +441,14 @@ fun IrMemberAccessExpression<*>.getBooleanConstArgument(i: Int): Boolean =
} ?: throw AssertionError("Value argument #$i should be a Boolean const: ${dump()}") } ?: throw AssertionError("Value argument #$i should be a Boolean const: ${dump()}")
val IrDeclaration.fileParent: IrFile val IrDeclaration.fileParent: IrFile
get() { get() = fileParentOrNull ?: error("No file parent: $this")
return when (val myParent = parent) {
is IrFile -> myParent @Suppress("RecursivePropertyAccessor")
else -> (myParent as IrDeclaration).fileParent val IrDeclaration.fileParentOrNull: IrFile?
} get() = when (val myParent = parent) {
is IrFile -> myParent
is IrDeclaration -> myParent.fileParentOrNull
else -> null
} }
private val RETENTION_PARAMETER_NAME = Name.identifier("value") private val RETENTION_PARAMETER_NAME = Name.identifier("value")
@@ -0,0 +1,16 @@
// TARGET_BACKEND: JVM
// WITH_STDLIB
// FILE: box.kt
class C {
val x: Int? by J().s::length
}
fun box(): String =
if (C().x == 0) "OK" else "Fail"
// FILE: J.java
public class J {
public final String s = "";
}
@@ -14806,6 +14806,12 @@ public class BlackBoxCodegenTestGenerated extends AbstractBlackBoxCodegenTest {
runTest("compiler/testData/codegen/box/delegatedProperty/delegateToAnother/kt50019_noOptimizedCallableReferences.kt"); runTest("compiler/testData/codegen/box/delegatedProperty/delegateToAnother/kt50019_noOptimizedCallableReferences.kt");
} }
@Test
@TestMetadata("kt57955.kt")
public void testKt57955() throws Exception {
runTest("compiler/testData/codegen/box/delegatedProperty/delegateToAnother/kt57955.kt");
}
@Test @Test
@TestMetadata("mutable.kt") @TestMetadata("mutable.kt")
public void testMutable() throws Exception { public void testMutable() throws Exception {
@@ -15142,6 +15142,12 @@ public class IrBlackBoxCodegenTestGenerated extends AbstractIrBlackBoxCodegenTes
runTest("compiler/testData/codegen/box/delegatedProperty/delegateToAnother/kt50019_noOptimizedCallableReferences.kt"); runTest("compiler/testData/codegen/box/delegatedProperty/delegateToAnother/kt50019_noOptimizedCallableReferences.kt");
} }
@Test
@TestMetadata("kt57955.kt")
public void testKt57955() throws Exception {
runTest("compiler/testData/codegen/box/delegatedProperty/delegateToAnother/kt57955.kt");
}
@Test @Test
@TestMetadata("mutable.kt") @TestMetadata("mutable.kt")
public void testMutable() throws Exception { public void testMutable() throws Exception {
@@ -15142,6 +15142,12 @@ public class IrBlackBoxCodegenWithIrInlinerTestGenerated extends AbstractIrBlack
runTest("compiler/testData/codegen/box/delegatedProperty/delegateToAnother/kt50019_noOptimizedCallableReferences.kt"); runTest("compiler/testData/codegen/box/delegatedProperty/delegateToAnother/kt50019_noOptimizedCallableReferences.kt");
} }
@Test
@TestMetadata("kt57955.kt")
public void testKt57955() throws Exception {
runTest("compiler/testData/codegen/box/delegatedProperty/delegateToAnother/kt57955.kt");
}
@Test @Test
@TestMetadata("mutable.kt") @TestMetadata("mutable.kt")
public void testMutable() throws Exception { public void testMutable() throws Exception {
@@ -12115,6 +12115,11 @@ public class LightAnalysisModeTestGenerated extends AbstractLightAnalysisModeTes
runTest("compiler/testData/codegen/box/delegatedProperty/delegateToAnother/kt50019_noOptimizedCallableReferences.kt"); runTest("compiler/testData/codegen/box/delegatedProperty/delegateToAnother/kt50019_noOptimizedCallableReferences.kt");
} }
@TestMetadata("kt57955.kt")
public void testKt57955() throws Exception {
runTest("compiler/testData/codegen/box/delegatedProperty/delegateToAnother/kt57955.kt");
}
@TestMetadata("mutable.kt") @TestMetadata("mutable.kt")
public void testMutable() throws Exception { public void testMutable() throws Exception {
runTest("compiler/testData/codegen/box/delegatedProperty/delegateToAnother/mutable.kt"); runTest("compiler/testData/codegen/box/delegatedProperty/delegateToAnother/mutable.kt");