From ea22f4b681ed70be9963c8de47d1711b12030797 Mon Sep 17 00:00:00 2001 From: Alexander Udalov Date: Fri, 9 Apr 2021 21:53:06 +0200 Subject: [PATCH] IR: check absence of extension receiver in isMethodOfAny Otherwise extension methods named toString/equals/hashCode were generated incorrectly on JVM IR, which could result in AbstractMethodError at runtime. #KT-45963 Fixed --- .../FirBlackBoxCodegenTestGenerated.java | 6 ++++++ .../kotlin/backend/common/ir/IrUtils.kt | 10 +++++++--- ...ensionEqualsHashCodeToStringInInterface.kt | 19 +++++++++++++++++++ .../codegen/BlackBoxCodegenTestGenerated.java | 6 ++++++ .../IrBlackBoxCodegenTestGenerated.java | 6 ++++++ .../LightAnalysisModeTestGenerated.java | 5 +++++ .../IrJsCodegenBoxES6TestGenerated.java | 5 +++++ .../IrJsCodegenBoxTestGenerated.java | 5 +++++ .../semantics/JsCodegenBoxTestGenerated.java | 5 +++++ .../IrCodegenBoxWasmTestGenerated.java | 5 +++++ 10 files changed, 69 insertions(+), 3 deletions(-) create mode 100644 compiler/testData/codegen/box/extensionFunctions/memberExtensionEqualsHashCodeToStringInInterface.kt diff --git a/compiler/fir/fir2ir/tests-gen/org/jetbrains/kotlin/test/runners/codegen/FirBlackBoxCodegenTestGenerated.java b/compiler/fir/fir2ir/tests-gen/org/jetbrains/kotlin/test/runners/codegen/FirBlackBoxCodegenTestGenerated.java index f0a09ea2790..7cd417d08f8 100644 --- a/compiler/fir/fir2ir/tests-gen/org/jetbrains/kotlin/test/runners/codegen/FirBlackBoxCodegenTestGenerated.java +++ b/compiler/fir/fir2ir/tests-gen/org/jetbrains/kotlin/test/runners/codegen/FirBlackBoxCodegenTestGenerated.java @@ -14738,6 +14738,12 @@ public class FirBlackBoxCodegenTestGenerated extends AbstractFirBlackBoxCodegenT runTest("compiler/testData/codegen/box/extensionFunctions/kt865.kt"); } + @Test + @TestMetadata("memberExtensionEqualsHashCodeToStringInInterface.kt") + public void testMemberExtensionEqualsHashCodeToStringInInterface() throws Exception { + runTest("compiler/testData/codegen/box/extensionFunctions/memberExtensionEqualsHashCodeToStringInInterface.kt"); + } + @Test @TestMetadata("nested2.kt") public void testNested2() throws Exception { diff --git a/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/ir/IrUtils.kt b/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/ir/IrUtils.kt index 938e05b278f..74e1a012eaa 100644 --- a/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/ir/IrUtils.kt +++ b/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/ir/IrUtils.kt @@ -394,9 +394,13 @@ fun IrClass.createImplicitParameterDeclarationWithWrappedDescriptor() { @Suppress("UNCHECKED_CAST") fun isElseBranch(branch: IrBranch) = branch is IrElseBranch || ((branch.condition as? IrConst)?.value == true) -fun IrFunction.isMethodOfAny() = - ((valueParameters.size == 0 && name.asString().let { it == "hashCode" || it == "toString" }) || - (valueParameters.size == 1 && name.asString() == "equals" && valueParameters[0].type.isNullableAny())) +fun IrFunction.isMethodOfAny(): Boolean = + extensionReceiverParameter == null && dispatchReceiverParameter != null && + when (name.asString()) { + "hashCode", "toString" -> valueParameters.isEmpty() + "equals" -> valueParameters.singleOrNull()?.type?.isNullableAny() == true + else -> false + } fun IrClass.simpleFunctions() = declarations.flatMap { when (it) { diff --git a/compiler/testData/codegen/box/extensionFunctions/memberExtensionEqualsHashCodeToStringInInterface.kt b/compiler/testData/codegen/box/extensionFunctions/memberExtensionEqualsHashCodeToStringInInterface.kt new file mode 100644 index 00000000000..e305518cfcb --- /dev/null +++ b/compiler/testData/codegen/box/extensionFunctions/memberExtensionEqualsHashCodeToStringInInterface.kt @@ -0,0 +1,19 @@ +interface AssertDSL { + infix fun Any?.equals(other: Any?) { + if (this != other) throw AssertionError("$this != $other") + } + + fun Any?.toString(): String = "" + fun Any?.hashCode(): Int = 0 +} + +class C(val x: Int) : AssertDSL + +fun C.test(): String { + x equals 42 + null.toString() + null.hashCode() + return "OK" +} + +fun box(): String = C(42).test() diff --git a/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/codegen/BlackBoxCodegenTestGenerated.java b/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/codegen/BlackBoxCodegenTestGenerated.java index 40b8fb25194..4551efdd9b8 100644 --- a/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/codegen/BlackBoxCodegenTestGenerated.java +++ b/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/codegen/BlackBoxCodegenTestGenerated.java @@ -14738,6 +14738,12 @@ public class BlackBoxCodegenTestGenerated extends AbstractBlackBoxCodegenTest { runTest("compiler/testData/codegen/box/extensionFunctions/kt865.kt"); } + @Test + @TestMetadata("memberExtensionEqualsHashCodeToStringInInterface.kt") + public void testMemberExtensionEqualsHashCodeToStringInInterface() throws Exception { + runTest("compiler/testData/codegen/box/extensionFunctions/memberExtensionEqualsHashCodeToStringInInterface.kt"); + } + @Test @TestMetadata("nested2.kt") public void testNested2() throws Exception { diff --git a/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/codegen/IrBlackBoxCodegenTestGenerated.java b/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/codegen/IrBlackBoxCodegenTestGenerated.java index 1d88ec1791d..84a2a9e54e1 100644 --- a/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/codegen/IrBlackBoxCodegenTestGenerated.java +++ b/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/codegen/IrBlackBoxCodegenTestGenerated.java @@ -14738,6 +14738,12 @@ public class IrBlackBoxCodegenTestGenerated extends AbstractIrBlackBoxCodegenTes runTest("compiler/testData/codegen/box/extensionFunctions/kt865.kt"); } + @Test + @TestMetadata("memberExtensionEqualsHashCodeToStringInInterface.kt") + public void testMemberExtensionEqualsHashCodeToStringInInterface() throws Exception { + runTest("compiler/testData/codegen/box/extensionFunctions/memberExtensionEqualsHashCodeToStringInInterface.kt"); + } + @Test @TestMetadata("nested2.kt") public void testNested2() throws Exception { diff --git a/compiler/tests-gen/org/jetbrains/kotlin/codegen/LightAnalysisModeTestGenerated.java b/compiler/tests-gen/org/jetbrains/kotlin/codegen/LightAnalysisModeTestGenerated.java index 8806f058617..a3b2796d96d 100644 --- a/compiler/tests-gen/org/jetbrains/kotlin/codegen/LightAnalysisModeTestGenerated.java +++ b/compiler/tests-gen/org/jetbrains/kotlin/codegen/LightAnalysisModeTestGenerated.java @@ -12095,6 +12095,11 @@ public class LightAnalysisModeTestGenerated extends AbstractLightAnalysisModeTes runTest("compiler/testData/codegen/box/extensionFunctions/kt865.kt"); } + @TestMetadata("memberExtensionEqualsHashCodeToStringInInterface.kt") + public void testMemberExtensionEqualsHashCodeToStringInInterface() throws Exception { + runTest("compiler/testData/codegen/box/extensionFunctions/memberExtensionEqualsHashCodeToStringInInterface.kt"); + } + @TestMetadata("nested2.kt") public void testNested2() throws Exception { runTest("compiler/testData/codegen/box/extensionFunctions/nested2.kt"); diff --git a/js/js.tests/tests-gen/org/jetbrains/kotlin/js/test/es6/semantics/IrJsCodegenBoxES6TestGenerated.java b/js/js.tests/tests-gen/org/jetbrains/kotlin/js/test/es6/semantics/IrJsCodegenBoxES6TestGenerated.java index 38c9e79057d..9cd15441a24 100644 --- a/js/js.tests/tests-gen/org/jetbrains/kotlin/js/test/es6/semantics/IrJsCodegenBoxES6TestGenerated.java +++ b/js/js.tests/tests-gen/org/jetbrains/kotlin/js/test/es6/semantics/IrJsCodegenBoxES6TestGenerated.java @@ -10764,6 +10764,11 @@ public class IrJsCodegenBoxES6TestGenerated extends AbstractIrJsCodegenBoxES6Tes runTest("compiler/testData/codegen/box/extensionFunctions/kt865.kt"); } + @TestMetadata("memberExtensionEqualsHashCodeToStringInInterface.kt") + public void testMemberExtensionEqualsHashCodeToStringInInterface() throws Exception { + runTest("compiler/testData/codegen/box/extensionFunctions/memberExtensionEqualsHashCodeToStringInInterface.kt"); + } + @TestMetadata("nested2.kt") public void testNested2() throws Exception { runTest("compiler/testData/codegen/box/extensionFunctions/nested2.kt"); diff --git a/js/js.tests/tests-gen/org/jetbrains/kotlin/js/test/ir/semantics/IrJsCodegenBoxTestGenerated.java b/js/js.tests/tests-gen/org/jetbrains/kotlin/js/test/ir/semantics/IrJsCodegenBoxTestGenerated.java index 52180ad6c30..37a94dc2b67 100644 --- a/js/js.tests/tests-gen/org/jetbrains/kotlin/js/test/ir/semantics/IrJsCodegenBoxTestGenerated.java +++ b/js/js.tests/tests-gen/org/jetbrains/kotlin/js/test/ir/semantics/IrJsCodegenBoxTestGenerated.java @@ -10185,6 +10185,11 @@ public class IrJsCodegenBoxTestGenerated extends AbstractIrJsCodegenBoxTest { runTest("compiler/testData/codegen/box/extensionFunctions/kt865.kt"); } + @TestMetadata("memberExtensionEqualsHashCodeToStringInInterface.kt") + public void testMemberExtensionEqualsHashCodeToStringInInterface() throws Exception { + runTest("compiler/testData/codegen/box/extensionFunctions/memberExtensionEqualsHashCodeToStringInInterface.kt"); + } + @TestMetadata("nested2.kt") public void testNested2() throws Exception { runTest("compiler/testData/codegen/box/extensionFunctions/nested2.kt"); diff --git a/js/js.tests/tests-gen/org/jetbrains/kotlin/js/test/semantics/JsCodegenBoxTestGenerated.java b/js/js.tests/tests-gen/org/jetbrains/kotlin/js/test/semantics/JsCodegenBoxTestGenerated.java index cee96591873..45419099388 100644 --- a/js/js.tests/tests-gen/org/jetbrains/kotlin/js/test/semantics/JsCodegenBoxTestGenerated.java +++ b/js/js.tests/tests-gen/org/jetbrains/kotlin/js/test/semantics/JsCodegenBoxTestGenerated.java @@ -10185,6 +10185,11 @@ public class JsCodegenBoxTestGenerated extends AbstractJsCodegenBoxTest { runTest("compiler/testData/codegen/box/extensionFunctions/kt865.kt"); } + @TestMetadata("memberExtensionEqualsHashCodeToStringInInterface.kt") + public void testMemberExtensionEqualsHashCodeToStringInInterface() throws Exception { + runTest("compiler/testData/codegen/box/extensionFunctions/memberExtensionEqualsHashCodeToStringInInterface.kt"); + } + @TestMetadata("nested2.kt") public void testNested2() throws Exception { runTest("compiler/testData/codegen/box/extensionFunctions/nested2.kt"); diff --git a/js/js.tests/tests-gen/org/jetbrains/kotlin/js/test/wasm/semantics/IrCodegenBoxWasmTestGenerated.java b/js/js.tests/tests-gen/org/jetbrains/kotlin/js/test/wasm/semantics/IrCodegenBoxWasmTestGenerated.java index 4efa7c317ac..868b61a8b1b 100644 --- a/js/js.tests/tests-gen/org/jetbrains/kotlin/js/test/wasm/semantics/IrCodegenBoxWasmTestGenerated.java +++ b/js/js.tests/tests-gen/org/jetbrains/kotlin/js/test/wasm/semantics/IrCodegenBoxWasmTestGenerated.java @@ -5089,6 +5089,11 @@ public class IrCodegenBoxWasmTestGenerated extends AbstractIrCodegenBoxWasmTest runTest("compiler/testData/codegen/box/extensionFunctions/kt5467.kt"); } + @TestMetadata("memberExtensionEqualsHashCodeToStringInInterface.kt") + public void testMemberExtensionEqualsHashCodeToStringInInterface() throws Exception { + runTest("compiler/testData/codegen/box/extensionFunctions/memberExtensionEqualsHashCodeToStringInInterface.kt"); + } + @TestMetadata("nested2.kt") public void testNested2() throws Exception { runTest("compiler/testData/codegen/box/extensionFunctions/nested2.kt");