FIR: Support static methods in callable references

^KT-32725 In Progress
This commit is contained in:
Denis Zharkov
2019-10-18 14:36:57 +03:00
parent 937ea3d8a0
commit 38ab6521aa
7 changed files with 184 additions and 7 deletions
@@ -284,17 +284,42 @@ class FirCallResolver(
name, resultCollector, callableReferenceAccess.explicitReceiver, expectedType, outerConstraintSystemBuilder,
lhs
)
is DoubleColonLHS.Type -> createCallableReferencesConsumerForReceiver(
is DoubleColonLHS.Type -> createCallableReferencesConsumerForReceivers(
name,
resultCollector,
FirExpressionStub(callableReferenceAccess.psi).apply { replaceTypeRef(FirResolvedTypeRefImpl(null, lhs.type)) },
expectedType,
outerConstraintSystemBuilder,
lhs
lhs,
FirExpressionStub(callableReferenceAccess.psi).apply { replaceTypeRef(FirResolvedTypeRefImpl(null, lhs.type)) },
callableReferenceAccess.explicitReceiver
)
}
}
private fun createCallableReferencesConsumerForReceivers(
name: Name,
resultCollector: CandidateCollector,
expectedType: ConeKotlinType?,
outerConstraintSystemBuilder: ConstraintSystemBuilder?,
lhs: DoubleColonLHS?,
vararg receivers: FirExpression?
): TowerDataConsumer {
if (receivers.size == 1) {
return createCallableReferencesConsumerForReceiver(
name, resultCollector, receivers[0], expectedType, outerConstraintSystemBuilder, lhs
)
}
return PrioritizedTowerDataConsumer(
resultCollector,
*Array(receivers.size) { index ->
createCallableReferencesConsumerForReceiver(
name, resultCollector, receivers[index], expectedType, outerConstraintSystemBuilder, lhs
)
}
)
}
private fun createCallableReferencesConsumerForReceiver(
name: Name,
resultCollector: CandidateCollector,
@@ -177,10 +177,14 @@ internal object CheckCallableReferenceExpectedType : CheckerStage() {
override suspend fun check(candidate: Candidate, sink: CheckerSink, callInfo: CallInfo) {
val outerCsBuilder = callInfo.outerCSBuilder ?: return
val expectedType = callInfo.expectedType ?: return
val lhs = callInfo.lhs
val resultingReceiverType = when (callInfo.lhs) {
is DoubleColonLHS.Type -> callInfo.lhs.type.takeIf { callInfo.explicitReceiver !is FirResolvedQualifier }
else -> null
}
val resultingType: ConeKotlinType = when (val fir = candidate.symbol.fir) {
is FirSimpleFunction -> createKFunctionType(fir, lhs)
is FirSimpleFunction -> createKFunctionType(fir, resultingReceiverType)
is FirProperty -> createKPropertyType(fir)
else -> ConeKotlinErrorType("Unknown callable kind: ${fir::class}")
}.let(candidate.substitutor::substituteOrSelf)
@@ -212,9 +216,8 @@ private fun createKPropertyType(fir: FirProperty): ConeKotlinType {
private fun createKFunctionType(
function: FirSimpleFunction,
lhs: DoubleColonLHS?
receiverType: ConeKotlinType?
): ConeKotlinType {
val receiverType = (lhs as? DoubleColonLHS.Type)?.type
val parameterTypes = function.valueParameters.map {
it.returnTypeRef.coneTypeSafe<ConeKotlinType>() ?: ConeKotlinErrorType("No type for parameter $it")
}
@@ -0,0 +1,43 @@
// FILE: JavaClass.java
public class JavaClass {
public static int bar(String x) { return 0; }
public int bar(CharSequence x) { return 0; }
}
// FILE: main.kt
class KotlinClass : JavaClass() {
fun baz(x: CharSequence): Int = 1
companion object {
fun baz(x: String): Int = 1
}
}
class KotlinClass2 : JavaClass() {
override fun bar(x: CharSequence): Int = 1
companion object {
fun bar(x: String): Int = 1
}
}
fun foo1(x: (String) -> Int) {}
fun foo2(x: (KotlinClass, CharSequence) -> Int) {}
fun foo3(x: (KotlinClass, CharSequence) -> Int) {}
fun foo3(x: (String) -> Int) {}
fun main() {
foo1(KotlinClass::baz)
foo2(KotlinClass::baz)
foo3(KotlinClass::baz)
foo1(KotlinClass::bar)
foo2(KotlinClass::bar)
foo3(KotlinClass::bar)
foo1(KotlinClass2::bar)
foo2(KotlinClass2::bar)
foo3(KotlinClass2::bar)
}
@@ -0,0 +1,62 @@
FILE: main.kt
public final class KotlinClass : R|JavaClass| {
public constructor(): R|KotlinClass| {
super<R|JavaClass|>()
}
public final fun baz(x: R|kotlin/CharSequence|): R|kotlin/Int| {
^baz Int(1)
}
public final companion object Companion : R|kotlin/Any| {
private constructor(): R|KotlinClass.Companion| {
super<R|kotlin/Any|>()
}
public final fun baz(x: R|kotlin/String|): R|kotlin/Int| {
^baz Int(1)
}
}
}
public final class KotlinClass2 : R|JavaClass| {
public constructor(): R|KotlinClass2| {
super<R|JavaClass|>()
}
public final override fun bar(x: R|kotlin/CharSequence|): R|kotlin/Int| {
^bar Int(1)
}
public final companion object Companion : R|kotlin/Any| {
private constructor(): R|KotlinClass2.Companion| {
super<R|kotlin/Any|>()
}
public final fun bar(x: R|kotlin/String|): R|kotlin/Int| {
^bar Int(1)
}
}
}
public final fun foo1(x: R|kotlin/Function1<kotlin/String, kotlin/Int>|): R|kotlin/Unit| {
}
public final fun foo2(x: R|kotlin/Function2<KotlinClass, kotlin/CharSequence, kotlin/Int>|): R|kotlin/Unit| {
}
public final fun foo3(x: R|kotlin/Function2<KotlinClass, kotlin/CharSequence, kotlin/Int>|): R|kotlin/Unit| {
}
public final fun foo3(x: R|kotlin/Function1<kotlin/String, kotlin/Int>|): R|kotlin/Unit| {
}
public final fun main(): R|kotlin/Unit| {
R|/foo1|(Q|KotlinClass|::R|/KotlinClass.Companion.baz|)
R|/foo2|(Q|KotlinClass|::R|/KotlinClass.baz|)
<Ambiguity: foo3, [/foo3, /foo3]>#(Q|KotlinClass|::baz#)
R|/foo1|(Q|KotlinClass|::R|/JavaClass.bar|)
R|/foo2|(Q|KotlinClass|::R|/JavaClass.bar|)
<Ambiguity: foo3, [/foo3, /foo3]>#(Q|KotlinClass|::bar#)
R|/foo1|(Q|KotlinClass2|::R|/JavaClass.bar|)
<Inapplicable(INAPPLICABLE): [/foo2]>#(Q|KotlinClass2|::bar#)
R|/foo3|(Q|KotlinClass2|::R|/JavaClass.bar|)
}
@@ -0,0 +1,20 @@
// FILE: JavaClass.java
public class JavaClass {
public static int bar(String x) { return 0; }
public int bar(CharSequence x) { return 0; }
}
// FILE: main.kt
fun foo1(x: (String) -> Int) {}
fun foo2(x: (JavaClass, CharSequence) -> Int) {}
fun foo3(x: (JavaClass, CharSequence) -> Int) {}
fun foo3(x: (String) -> Int) {}
fun main() {
foo1(JavaClass::bar)
foo2(JavaClass::bar)
foo3(JavaClass::bar)
}
@@ -0,0 +1,14 @@
FILE: main.kt
public final fun foo1(x: R|kotlin/Function1<kotlin/String, kotlin/Int>|): R|kotlin/Unit| {
}
public final fun foo2(x: R|kotlin/Function2<JavaClass, kotlin/CharSequence, kotlin/Int>|): R|kotlin/Unit| {
}
public final fun foo3(x: R|kotlin/Function2<JavaClass, kotlin/CharSequence, kotlin/Int>|): R|kotlin/Unit| {
}
public final fun foo3(x: R|kotlin/Function1<kotlin/String, kotlin/Int>|): R|kotlin/Unit| {
}
public final fun main(): R|kotlin/Unit| {
R|/foo1|(Q|JavaClass|::R|/JavaClass.bar|)
R|/foo2|(Q|JavaClass|::R|/JavaClass.bar|)
<Ambiguity: foo3, [/foo3, /foo3]>#(Q|JavaClass|::bar#)
}
@@ -40,6 +40,11 @@ public class FirDiagnosticsTestGenerated extends AbstractFirDiagnosticsTest {
KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/fir/resolve/testData/diagnostics/callableReferences"), Pattern.compile("^(.+)\\.kt$"), true);
}
@TestMetadata("companions.kt")
public void testCompanions() throws Exception {
runTest("compiler/fir/resolve/testData/diagnostics/callableReferences/companions.kt");
}
@TestMetadata("differentLevels.kt")
public void testDifferentLevels() throws Exception {
runTest("compiler/fir/resolve/testData/diagnostics/callableReferences/differentLevels.kt");
@@ -55,6 +60,11 @@ public class FirDiagnosticsTestGenerated extends AbstractFirDiagnosticsTest {
runTest("compiler/fir/resolve/testData/diagnostics/callableReferences/inferenceFromExpectedType.kt");
}
@TestMetadata("javaStatic.kt")
public void testJavaStatic() throws Exception {
runTest("compiler/fir/resolve/testData/diagnostics/callableReferences/javaStatic.kt");
}
@TestMetadata("manyCandidatesInference.kt")
public void testManyCandidatesInference() throws Exception {
runTest("compiler/fir/resolve/testData/diagnostics/callableReferences/manyCandidatesInference.kt");