JVM IR: fix generation of equals/hashCode for fun interfaces over references

... in case `-Xno-optimized-callable-references` is enabled. Before this
change, the generated abstract equals/hashCode methods were considered
as accidental overrides because they did not have equals/hashCode from
the supertype in the overriddenSymbols list.

 #KT-43666 Fixed
This commit is contained in:
Alexander Udalov
2020-11-30 15:00:11 +01:00
parent 50ae360ff9
commit 606de26646
10 changed files with 63 additions and 2 deletions
@@ -12194,6 +12194,11 @@ public class FirBlackBoxCodegenTestGenerated extends AbstractFirBlackBoxCodegenT
runTest("compiler/testData/codegen/box/funInterface/multimodule.kt");
}
@TestMetadata("noOptimizedCallableReferences.kt")
public void testNoOptimizedCallableReferences() throws Exception {
runTest("compiler/testData/codegen/box/funInterface/noOptimizedCallableReferences.kt");
}
@TestMetadata("nonAbstractMethod.kt")
public void testNonAbstractMethod() throws Exception {
runTest("compiler/testData/codegen/box/funInterface/nonAbstractMethod.kt");
@@ -245,7 +245,7 @@ internal class FunctionReferenceLowering(private val context: JvmBackendContext)
if (!useOptimizedSuperClass) {
// This is the case of a fun interface wrapper over a (maybe adapted) function reference,
// with `-Xno-optimized-callable-referenced` enabled. We can't use constructors of FunctionReferenceImpl,
// with `-Xno-optimized-callable-references` enabled. We can't use constructors of FunctionReferenceImpl,
// so we'd need to basically generate a full class for a reference inheriting from FunctionReference,
// effectively disabling the optimization of fun interface wrappers over references.
// This scenario is probably not very popular because it involves using equals/hashCode on function references
@@ -254,8 +254,11 @@ internal class FunctionReferenceLowering(private val context: JvmBackendContext)
// TODO: generate getFunctionDelegate, equals and hashCode properly in this case
functionReferenceClass.addFunction("equals", backendContext.irBuiltIns.booleanType, Modality.ABSTRACT).apply {
addValueParameter("other", backendContext.irBuiltIns.anyNType)
overriddenSymbols = listOf(functionSuperClass.functions.single { isEqualsFromAny(it.owner) })
}
functionReferenceClass.addFunction("hashCode", backendContext.irBuiltIns.intType, Modality.ABSTRACT).apply {
overriddenSymbols = listOf(functionSuperClass.functions.single { isHashCodeFromAny(it.owner) })
}
functionReferenceClass.addFunction("hashCode", backendContext.irBuiltIns.intType, Modality.ABSTRACT)
return
}
@@ -274,6 +277,13 @@ internal class FunctionReferenceLowering(private val context: JvmBackendContext)
}.generate()
}
private fun isEqualsFromAny(f: IrSimpleFunction): Boolean =
f.name.asString() == "equals" && f.extensionReceiverParameter == null &&
f.valueParameters.singleOrNull()?.type?.isNullableAny() == true
private fun isHashCodeFromAny(f: IrSimpleFunction): Boolean =
f.name.asString() == "hashCode" && f.extensionReceiverParameter == null && f.valueParameters.isEmpty()
private fun createConstructor(): IrConstructor =
functionReferenceClass.addConstructor {
origin = JvmLoweredDeclarationOrigin.GENERATED_MEMBER_IN_CALLABLE_REFERENCE
@@ -0,0 +1,11 @@
// KOTLIN_CONFIGURATION_FLAGS: +JVM.NO_OPTIMIZED_CALLABLE_REFERENCES
fun interface P {
fun get(): String
}
class G(val p: P)
fun f(): String = "OK"
fun box(): String = G(::f).p.get()
@@ -13594,6 +13594,11 @@ public class BlackBoxCodegenTestGenerated extends AbstractBlackBoxCodegenTest {
runTest("compiler/testData/codegen/box/funInterface/multimodule.kt");
}
@TestMetadata("noOptimizedCallableReferences.kt")
public void testNoOptimizedCallableReferences() throws Exception {
runTest("compiler/testData/codegen/box/funInterface/noOptimizedCallableReferences.kt");
}
@TestMetadata("nonAbstractMethod.kt")
public void testNonAbstractMethod() throws Exception {
runTest("compiler/testData/codegen/box/funInterface/nonAbstractMethod.kt");
@@ -13594,6 +13594,11 @@ public class LightAnalysisModeTestGenerated extends AbstractLightAnalysisModeTes
runTest("compiler/testData/codegen/box/funInterface/multimodule.kt");
}
@TestMetadata("noOptimizedCallableReferences.kt")
public void testNoOptimizedCallableReferences() throws Exception {
runTest("compiler/testData/codegen/box/funInterface/noOptimizedCallableReferences.kt");
}
@TestMetadata("nonAbstractMethod.kt")
public void testNonAbstractMethod() throws Exception {
runTest("compiler/testData/codegen/box/funInterface/nonAbstractMethod.kt");
@@ -12194,6 +12194,11 @@ public class IrBlackBoxCodegenTestGenerated extends AbstractIrBlackBoxCodegenTes
runTest("compiler/testData/codegen/box/funInterface/multimodule.kt");
}
@TestMetadata("noOptimizedCallableReferences.kt")
public void testNoOptimizedCallableReferences() throws Exception {
runTest("compiler/testData/codegen/box/funInterface/noOptimizedCallableReferences.kt");
}
@TestMetadata("nonAbstractMethod.kt")
public void testNonAbstractMethod() throws Exception {
runTest("compiler/testData/codegen/box/funInterface/nonAbstractMethod.kt");
@@ -10434,6 +10434,11 @@ public class IrJsCodegenBoxES6TestGenerated extends AbstractIrJsCodegenBoxES6Tes
runTest("compiler/testData/codegen/box/funInterface/multimodule.kt");
}
@TestMetadata("noOptimizedCallableReferences.kt")
public void testNoOptimizedCallableReferences() throws Exception {
runTest("compiler/testData/codegen/box/funInterface/noOptimizedCallableReferences.kt");
}
@TestMetadata("nonAbstractMethod.kt")
public void testNonAbstractMethod() throws Exception {
runTest("compiler/testData/codegen/box/funInterface/nonAbstractMethod.kt");
@@ -10434,6 +10434,11 @@ public class IrJsCodegenBoxTestGenerated extends AbstractIrJsCodegenBoxTest {
runTest("compiler/testData/codegen/box/funInterface/multimodule.kt");
}
@TestMetadata("noOptimizedCallableReferences.kt")
public void testNoOptimizedCallableReferences() throws Exception {
runTest("compiler/testData/codegen/box/funInterface/noOptimizedCallableReferences.kt");
}
@TestMetadata("nonAbstractMethod.kt")
public void testNonAbstractMethod() throws Exception {
runTest("compiler/testData/codegen/box/funInterface/nonAbstractMethod.kt");
@@ -10434,6 +10434,11 @@ public class JsCodegenBoxTestGenerated extends AbstractJsCodegenBoxTest {
runTest("compiler/testData/codegen/box/funInterface/multimodule.kt");
}
@TestMetadata("noOptimizedCallableReferences.kt")
public void testNoOptimizedCallableReferences() throws Exception {
runTest("compiler/testData/codegen/box/funInterface/noOptimizedCallableReferences.kt");
}
@TestMetadata("nonAbstractMethod.kt")
public void testNonAbstractMethod() throws Exception {
runTest("compiler/testData/codegen/box/funInterface/nonAbstractMethod.kt");
@@ -5214,6 +5214,11 @@ public class IrCodegenBoxWasmTestGenerated extends AbstractIrCodegenBoxWasmTest
runTest("compiler/testData/codegen/box/funInterface/funConversionInVararg.kt");
}
@TestMetadata("noOptimizedCallableReferences.kt")
public void testNoOptimizedCallableReferences() throws Exception {
runTest("compiler/testData/codegen/box/funInterface/noOptimizedCallableReferences.kt");
}
@TestMetadata("partialSam.kt")
public void testPartialSam() throws Exception {
runTest("compiler/testData/codegen/box/funInterface/partialSam.kt");