FIR: Support SAM conversion for interfaces containing Object methods

This commit is contained in:
Denis Zharkov
2019-11-26 19:29:56 +03:00
parent 7cd55c85e6
commit bf68e85a5c
6 changed files with 29 additions and 13 deletions
@@ -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<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)
}
)
}
@@ -2,14 +2,10 @@ fun test_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>) {
comparator.compare(1, 2)
}
fun test_4(comparator: Comparator<Int>) {
comparator.compare(1, 2)
}
}
@@ -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| {
R|<local>/comparator|.R|FakeOverride<java/util/Comparator.compare: R|kotlin/Int|>|(Int(1), Int(2))
}
@@ -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");