FIR: Support SAM conversion for interfaces containing Object methods
This commit is contained in:
@@ -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"
|
"${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) {
|
if (resultMethod != null) {
|
||||||
metIncorrectMember = true
|
metIncorrectMember = true
|
||||||
@@ -286,7 +286,7 @@ private fun FirRegularClass.hasMoreThenOneAbstractFunctionOrHasAbstractProperty(
|
|||||||
var wasAbstractFunction = false
|
var wasAbstractFunction = false
|
||||||
for (declaration in declarations) {
|
for (declaration in declarations) {
|
||||||
if (declaration is FirProperty && declaration.modality == Modality.ABSTRACT) return true
|
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
|
if (wasAbstractFunction) return true
|
||||||
wasAbstractFunction = true
|
wasAbstractFunction = true
|
||||||
}
|
}
|
||||||
@@ -295,6 +295,17 @@ private fun FirRegularClass.hasMoreThenOneAbstractFunctionOrHasAbstractProperty(
|
|||||||
return false
|
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 {
|
private fun FirSimpleFunction.getFunctionTypeForAbstractMethod(): ConeLookupTagBasedType {
|
||||||
val parameterTypes = valueParameters.map {
|
val parameterTypes = valueParameters.map {
|
||||||
it.returnTypeRef.coneTypeSafe<ConeKotlinType>() ?: ConeKotlinErrorType("No type for parameter $it")
|
it.returnTypeRef.coneTypeSafe<ConeKotlinType>() ?: ConeKotlinErrorType("No type for parameter $it")
|
||||||
|
|||||||
@@ -0,0 +1,3 @@
|
|||||||
|
fun test_2(list: List<Int>) {
|
||||||
|
val comp = java.util.Comparator<Int> { x, y -> 1 }
|
||||||
|
}
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
FILE: javaLangComparator.kt
|
||||||
|
public final fun test_2(list: R|kotlin/collections/List<kotlin/Int>|): R|kotlin/Unit| {
|
||||||
|
lval comp: R|java/util/Comparator<kotlin/Int>| = Q|java/util|.R|java/util/Comparator|<R|kotlin/Int|>(<L> = Comparator@fun <anonymous>(x: R|kotlin/Int|, y: R|kotlin/Int|): R|kotlin/Int| {
|
||||||
|
Int(1)
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
+1
-5
@@ -2,14 +2,10 @@ fun test_1() {
|
|||||||
val comp = <!UNRESOLVED_REFERENCE!>Comparator<!><Int> { x, y -> 1 }
|
val comp = <!UNRESOLVED_REFERENCE!>Comparator<!><Int> { x, y -> 1 }
|
||||||
}
|
}
|
||||||
|
|
||||||
fun test_2(list: List<Int>) {
|
|
||||||
val comp = java.util.<!UNRESOLVED_REFERENCE!>Comparator<!><Int> { x, y -> 1 }
|
|
||||||
}
|
|
||||||
|
|
||||||
fun test_3(comparator: java.util.Comparator<Int>) {
|
fun test_3(comparator: java.util.Comparator<Int>) {
|
||||||
comparator.compare(1, 2)
|
comparator.compare(1, 2)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun test_4(comparator: Comparator<Int>) {
|
fun test_4(comparator: Comparator<Int>) {
|
||||||
comparator.compare(1, 2)
|
comparator.compare(1, 2)
|
||||||
}
|
}
|
||||||
|
|||||||
-6
@@ -5,12 +5,6 @@ FILE: unresolvedComparator.kt
|
|||||||
}
|
}
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
public final fun test_2(list: R|kotlin/collections/List<kotlin/Int>|): R|kotlin/Unit| {
|
|
||||||
lval comp: <ERROR TYPE REF: Unresolved name: Comparator> = Q|java/util|.<Unresolved name: Comparator>#<R|kotlin/Int|>(<L> = Comparator@fun <anonymous>(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<kotlin/Int>|): R|kotlin/Unit| {
|
public final fun test_3(comparator: R|java/util/Comparator<kotlin/Int>|): R|kotlin/Unit| {
|
||||||
R|<local>/comparator|.R|FakeOverride<java/util/Comparator.compare: R|kotlin/Int|>|(Int(1), Int(2))
|
R|<local>/comparator|.R|FakeOverride<java/util/Comparator.compare: R|kotlin/Int|>|(Int(1), Int(2))
|
||||||
}
|
}
|
||||||
|
|||||||
Generated
+5
@@ -118,6 +118,11 @@ public class FirDiagnosticsWithStdlibTestGenerated extends AbstractFirDiagnostic
|
|||||||
runTest("compiler/fir/resolve/testData/resolve/stdlib/javaEnumSynthetic.kt");
|
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")
|
@TestMetadata("listPlusAssign.kt")
|
||||||
public void testListPlusAssign() throws Exception {
|
public void testListPlusAssign() throws Exception {
|
||||||
runTest("compiler/fir/resolve/testData/resolve/stdlib/listPlusAssign.kt");
|
runTest("compiler/fir/resolve/testData/resolve/stdlib/listPlusAssign.kt");
|
||||||
|
|||||||
Reference in New Issue
Block a user