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:
Generated
+5
@@ -12194,6 +12194,11 @@ public class FirBlackBoxCodegenTestGenerated extends AbstractFirBlackBoxCodegenT
|
|||||||
runTest("compiler/testData/codegen/box/funInterface/multimodule.kt");
|
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")
|
@TestMetadata("nonAbstractMethod.kt")
|
||||||
public void testNonAbstractMethod() throws Exception {
|
public void testNonAbstractMethod() throws Exception {
|
||||||
runTest("compiler/testData/codegen/box/funInterface/nonAbstractMethod.kt");
|
runTest("compiler/testData/codegen/box/funInterface/nonAbstractMethod.kt");
|
||||||
|
|||||||
+12
-2
@@ -245,7 +245,7 @@ internal class FunctionReferenceLowering(private val context: JvmBackendContext)
|
|||||||
|
|
||||||
if (!useOptimizedSuperClass) {
|
if (!useOptimizedSuperClass) {
|
||||||
// This is the case of a fun interface wrapper over a (maybe adapted) function reference,
|
// 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,
|
// 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.
|
// 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
|
// 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
|
// TODO: generate getFunctionDelegate, equals and hashCode properly in this case
|
||||||
functionReferenceClass.addFunction("equals", backendContext.irBuiltIns.booleanType, Modality.ABSTRACT).apply {
|
functionReferenceClass.addFunction("equals", backendContext.irBuiltIns.booleanType, Modality.ABSTRACT).apply {
|
||||||
addValueParameter("other", backendContext.irBuiltIns.anyNType)
|
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
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -274,6 +277,13 @@ internal class FunctionReferenceLowering(private val context: JvmBackendContext)
|
|||||||
}.generate()
|
}.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 =
|
private fun createConstructor(): IrConstructor =
|
||||||
functionReferenceClass.addConstructor {
|
functionReferenceClass.addConstructor {
|
||||||
origin = JvmLoweredDeclarationOrigin.GENERATED_MEMBER_IN_CALLABLE_REFERENCE
|
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()
|
||||||
+5
@@ -13594,6 +13594,11 @@ public class BlackBoxCodegenTestGenerated extends AbstractBlackBoxCodegenTest {
|
|||||||
runTest("compiler/testData/codegen/box/funInterface/multimodule.kt");
|
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")
|
@TestMetadata("nonAbstractMethod.kt")
|
||||||
public void testNonAbstractMethod() throws Exception {
|
public void testNonAbstractMethod() throws Exception {
|
||||||
runTest("compiler/testData/codegen/box/funInterface/nonAbstractMethod.kt");
|
runTest("compiler/testData/codegen/box/funInterface/nonAbstractMethod.kt");
|
||||||
|
|||||||
+5
@@ -13594,6 +13594,11 @@ public class LightAnalysisModeTestGenerated extends AbstractLightAnalysisModeTes
|
|||||||
runTest("compiler/testData/codegen/box/funInterface/multimodule.kt");
|
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")
|
@TestMetadata("nonAbstractMethod.kt")
|
||||||
public void testNonAbstractMethod() throws Exception {
|
public void testNonAbstractMethod() throws Exception {
|
||||||
runTest("compiler/testData/codegen/box/funInterface/nonAbstractMethod.kt");
|
runTest("compiler/testData/codegen/box/funInterface/nonAbstractMethod.kt");
|
||||||
|
|||||||
+5
@@ -12194,6 +12194,11 @@ public class IrBlackBoxCodegenTestGenerated extends AbstractIrBlackBoxCodegenTes
|
|||||||
runTest("compiler/testData/codegen/box/funInterface/multimodule.kt");
|
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")
|
@TestMetadata("nonAbstractMethod.kt")
|
||||||
public void testNonAbstractMethod() throws Exception {
|
public void testNonAbstractMethod() throws Exception {
|
||||||
runTest("compiler/testData/codegen/box/funInterface/nonAbstractMethod.kt");
|
runTest("compiler/testData/codegen/box/funInterface/nonAbstractMethod.kt");
|
||||||
|
|||||||
Generated
+5
@@ -10434,6 +10434,11 @@ public class IrJsCodegenBoxES6TestGenerated extends AbstractIrJsCodegenBoxES6Tes
|
|||||||
runTest("compiler/testData/codegen/box/funInterface/multimodule.kt");
|
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")
|
@TestMetadata("nonAbstractMethod.kt")
|
||||||
public void testNonAbstractMethod() throws Exception {
|
public void testNonAbstractMethod() throws Exception {
|
||||||
runTest("compiler/testData/codegen/box/funInterface/nonAbstractMethod.kt");
|
runTest("compiler/testData/codegen/box/funInterface/nonAbstractMethod.kt");
|
||||||
|
|||||||
Generated
+5
@@ -10434,6 +10434,11 @@ public class IrJsCodegenBoxTestGenerated extends AbstractIrJsCodegenBoxTest {
|
|||||||
runTest("compiler/testData/codegen/box/funInterface/multimodule.kt");
|
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")
|
@TestMetadata("nonAbstractMethod.kt")
|
||||||
public void testNonAbstractMethod() throws Exception {
|
public void testNonAbstractMethod() throws Exception {
|
||||||
runTest("compiler/testData/codegen/box/funInterface/nonAbstractMethod.kt");
|
runTest("compiler/testData/codegen/box/funInterface/nonAbstractMethod.kt");
|
||||||
|
|||||||
Generated
+5
@@ -10434,6 +10434,11 @@ public class JsCodegenBoxTestGenerated extends AbstractJsCodegenBoxTest {
|
|||||||
runTest("compiler/testData/codegen/box/funInterface/multimodule.kt");
|
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")
|
@TestMetadata("nonAbstractMethod.kt")
|
||||||
public void testNonAbstractMethod() throws Exception {
|
public void testNonAbstractMethod() throws Exception {
|
||||||
runTest("compiler/testData/codegen/box/funInterface/nonAbstractMethod.kt");
|
runTest("compiler/testData/codegen/box/funInterface/nonAbstractMethod.kt");
|
||||||
|
|||||||
Generated
+5
@@ -5214,6 +5214,11 @@ public class IrCodegenBoxWasmTestGenerated extends AbstractIrCodegenBoxWasmTest
|
|||||||
runTest("compiler/testData/codegen/box/funInterface/funConversionInVararg.kt");
|
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")
|
@TestMetadata("partialSam.kt")
|
||||||
public void testPartialSam() throws Exception {
|
public void testPartialSam() throws Exception {
|
||||||
runTest("compiler/testData/codegen/box/funInterface/partialSam.kt");
|
runTest("compiler/testData/codegen/box/funInterface/partialSam.kt");
|
||||||
|
|||||||
Reference in New Issue
Block a user