diff --git a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/SamResolution.kt b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/SamResolution.kt index fe5ad5e3afb..277b9591173 100644 --- a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/SamResolution.kt +++ b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/SamResolution.kt @@ -265,7 +265,7 @@ private fun FirRegularClass.findSingleAbstractMethodByNames( "${functionSymbol.callableId.callableName} is expected to be _root_ide_package_.org.jetbrains.kotlin.fir.declarations.FirSimpleFunction, but ${functionSymbol::class} was found" } - if (firFunction.modality != Modality.ABSTRACT) return@processFunctionsByName ProcessorAction.NEXT + if (firFunction.modality != Modality.ABSTRACT || firFunction.isPublicInObject()) return@processFunctionsByName ProcessorAction.NEXT if (resultMethod != null) { metIncorrectMember = true @@ -286,7 +286,7 @@ private fun FirRegularClass.hasMoreThenOneAbstractFunctionOrHasAbstractProperty( var wasAbstractFunction = false for (declaration in declarations) { if (declaration is FirProperty && declaration.modality == Modality.ABSTRACT) return true - if (declaration is FirSimpleFunction && declaration.modality == Modality.ABSTRACT) { + if (declaration is FirSimpleFunction && declaration.modality == Modality.ABSTRACT && !declaration.isPublicInObject()) { if (wasAbstractFunction) return true wasAbstractFunction = true } @@ -295,6 +295,17 @@ private fun FirRegularClass.hasMoreThenOneAbstractFunctionOrHasAbstractProperty( return false } +// From the definition of function interfaces in the Java specification (pt. 9.8): +// "methods that are members of I that do not have the same signature as any public instance method of the class Object" +// It means that if an interface declares `int hashCode()` then the method won't be taken into account when +// checking if the interface is SAM. +private fun FirSimpleFunction.isPublicInObject(): Boolean { + // TODO: We make here a conservative check just filtering out methods by name, check the signature as well + return name.asString() in PUBLIC_METHOD_NAMES_IN_OBJECT +} + +private val PUBLIC_METHOD_NAMES_IN_OBJECT = setOf("equals", "hashCode", "getClass", "wait", "notify", "notifyAll", "toString") + private fun FirSimpleFunction.getFunctionTypeForAbstractMethod(): ConeLookupTagBasedType { val parameterTypes = valueParameters.map { it.returnTypeRef.coneTypeSafe() ?: ConeKotlinErrorType("No type for parameter $it") diff --git a/compiler/fir/resolve/testData/resolve/stdlib/javaLangComparator.kt b/compiler/fir/resolve/testData/resolve/stdlib/javaLangComparator.kt new file mode 100644 index 00000000000..0b982d1668a --- /dev/null +++ b/compiler/fir/resolve/testData/resolve/stdlib/javaLangComparator.kt @@ -0,0 +1,3 @@ +fun test_2(list: List) { + val comp = java.util.Comparator { x, y -> 1 } +} diff --git a/compiler/fir/resolve/testData/resolve/stdlib/javaLangComparator.txt b/compiler/fir/resolve/testData/resolve/stdlib/javaLangComparator.txt new file mode 100644 index 00000000000..4e9670c1ece --- /dev/null +++ b/compiler/fir/resolve/testData/resolve/stdlib/javaLangComparator.txt @@ -0,0 +1,7 @@ +FILE: javaLangComparator.kt + public final fun test_2(list: R|kotlin/collections/List|): R|kotlin/Unit| { + lval comp: R|java/util/Comparator| = Q|java/util|.R|java/util/Comparator|( = Comparator@fun (x: R|kotlin/Int|, y: R|kotlin/Int|): R|kotlin/Int| { + Int(1) + } + ) + } diff --git a/compiler/fir/resolve/testData/resolve/stdlib/problems/unresolvedComparator.kt b/compiler/fir/resolve/testData/resolve/stdlib/problems/unresolvedComparator.kt index d1760f718e1..53a1806444b 100644 --- a/compiler/fir/resolve/testData/resolve/stdlib/problems/unresolvedComparator.kt +++ b/compiler/fir/resolve/testData/resolve/stdlib/problems/unresolvedComparator.kt @@ -2,14 +2,10 @@ fun test_1() { val comp = Comparator { x, y -> 1 } } -fun test_2(list: List) { - val comp = java.util.Comparator { x, y -> 1 } -} - fun test_3(comparator: java.util.Comparator) { comparator.compare(1, 2) } fun test_4(comparator: Comparator) { comparator.compare(1, 2) -} \ No newline at end of file +} diff --git a/compiler/fir/resolve/testData/resolve/stdlib/problems/unresolvedComparator.txt b/compiler/fir/resolve/testData/resolve/stdlib/problems/unresolvedComparator.txt index c8f3395249e..e47af829aea 100644 --- a/compiler/fir/resolve/testData/resolve/stdlib/problems/unresolvedComparator.txt +++ b/compiler/fir/resolve/testData/resolve/stdlib/problems/unresolvedComparator.txt @@ -5,12 +5,6 @@ FILE: unresolvedComparator.kt } ) } - public final fun test_2(list: R|kotlin/collections/List|): R|kotlin/Unit| { - lval comp: = Q|java/util|.#( = Comparator@fun (x: R|class error: No type for parameter|, y: R|class error: No type for parameter|): R|kotlin/Int| { - Int(1) - } - ) - } public final fun test_3(comparator: R|java/util/Comparator|): R|kotlin/Unit| { R|/comparator|.R|FakeOverride|(Int(1), Int(2)) } diff --git a/compiler/fir/resolve/tests/org/jetbrains/kotlin/fir/FirDiagnosticsWithStdlibTestGenerated.java b/compiler/fir/resolve/tests/org/jetbrains/kotlin/fir/FirDiagnosticsWithStdlibTestGenerated.java index 1524e97e256..134a8d340d1 100644 --- a/compiler/fir/resolve/tests/org/jetbrains/kotlin/fir/FirDiagnosticsWithStdlibTestGenerated.java +++ b/compiler/fir/resolve/tests/org/jetbrains/kotlin/fir/FirDiagnosticsWithStdlibTestGenerated.java @@ -118,6 +118,11 @@ public class FirDiagnosticsWithStdlibTestGenerated extends AbstractFirDiagnostic runTest("compiler/fir/resolve/testData/resolve/stdlib/javaEnumSynthetic.kt"); } + @TestMetadata("javaLangComparator.kt") + public void testJavaLangComparator() throws Exception { + runTest("compiler/fir/resolve/testData/resolve/stdlib/javaLangComparator.kt"); + } + @TestMetadata("listPlusAssign.kt") public void testListPlusAssign() throws Exception { runTest("compiler/fir/resolve/testData/resolve/stdlib/listPlusAssign.kt");