From 38ab6521aa698fa10f21334e6b6272b2dfdc2e2d Mon Sep 17 00:00:00 2001 From: Denis Zharkov Date: Fri, 18 Oct 2019 14:36:57 +0300 Subject: [PATCH] FIR: Support static methods in callable references ^KT-32725 In Progress --- .../jetbrains/kotlin/fir/FirCallResolver.kt | 31 +++++++++- .../kotlin/fir/resolve/calls/ResolverParts.kt | 11 ++-- .../callableReferences/companions.kt | 43 +++++++++++++ .../callableReferences/companions.txt | 62 +++++++++++++++++++ .../callableReferences/javaStatic.kt | 20 ++++++ .../callableReferences/javaStatic.txt | 14 +++++ .../fir/FirDiagnosticsTestGenerated.java | 10 +++ 7 files changed, 184 insertions(+), 7 deletions(-) create mode 100644 compiler/fir/resolve/testData/diagnostics/callableReferences/companions.kt create mode 100644 compiler/fir/resolve/testData/diagnostics/callableReferences/companions.txt create mode 100644 compiler/fir/resolve/testData/diagnostics/callableReferences/javaStatic.kt create mode 100644 compiler/fir/resolve/testData/diagnostics/callableReferences/javaStatic.txt diff --git a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/FirCallResolver.kt b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/FirCallResolver.kt index 3bd00ca1dcb..b7bbc5acd4a 100644 --- a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/FirCallResolver.kt +++ b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/FirCallResolver.kt @@ -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, diff --git a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/calls/ResolverParts.kt b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/calls/ResolverParts.kt index fcd9147ab2a..a2085a11929 100644 --- a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/calls/ResolverParts.kt +++ b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/calls/ResolverParts.kt @@ -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() ?: ConeKotlinErrorType("No type for parameter $it") } diff --git a/compiler/fir/resolve/testData/diagnostics/callableReferences/companions.kt b/compiler/fir/resolve/testData/diagnostics/callableReferences/companions.kt new file mode 100644 index 00000000000..1cb574eec49 --- /dev/null +++ b/compiler/fir/resolve/testData/diagnostics/callableReferences/companions.kt @@ -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) +} + diff --git a/compiler/fir/resolve/testData/diagnostics/callableReferences/companions.txt b/compiler/fir/resolve/testData/diagnostics/callableReferences/companions.txt new file mode 100644 index 00000000000..f80cf71ea3d --- /dev/null +++ b/compiler/fir/resolve/testData/diagnostics/callableReferences/companions.txt @@ -0,0 +1,62 @@ +FILE: main.kt + public final class KotlinClass : R|JavaClass| { + public constructor(): R|KotlinClass| { + super() + } + + 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() + } + + 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() + } + + 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() + } + + public final fun bar(x: R|kotlin/String|): R|kotlin/Int| { + ^bar Int(1) + } + + } + + } + public final fun foo1(x: R|kotlin/Function1|): R|kotlin/Unit| { + } + public final fun foo2(x: R|kotlin/Function2|): R|kotlin/Unit| { + } + public final fun foo3(x: R|kotlin/Function2|): R|kotlin/Unit| { + } + public final fun foo3(x: R|kotlin/Function1|): 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|) + #(Q|KotlinClass|::baz#) + R|/foo1|(Q|KotlinClass|::R|/JavaClass.bar|) + R|/foo2|(Q|KotlinClass|::R|/JavaClass.bar|) + #(Q|KotlinClass|::bar#) + R|/foo1|(Q|KotlinClass2|::R|/JavaClass.bar|) + #(Q|KotlinClass2|::bar#) + R|/foo3|(Q|KotlinClass2|::R|/JavaClass.bar|) + } diff --git a/compiler/fir/resolve/testData/diagnostics/callableReferences/javaStatic.kt b/compiler/fir/resolve/testData/diagnostics/callableReferences/javaStatic.kt new file mode 100644 index 00000000000..3d8cd7fb413 --- /dev/null +++ b/compiler/fir/resolve/testData/diagnostics/callableReferences/javaStatic.kt @@ -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) +} diff --git a/compiler/fir/resolve/testData/diagnostics/callableReferences/javaStatic.txt b/compiler/fir/resolve/testData/diagnostics/callableReferences/javaStatic.txt new file mode 100644 index 00000000000..b5783d084c1 --- /dev/null +++ b/compiler/fir/resolve/testData/diagnostics/callableReferences/javaStatic.txt @@ -0,0 +1,14 @@ +FILE: main.kt + public final fun foo1(x: R|kotlin/Function1|): R|kotlin/Unit| { + } + public final fun foo2(x: R|kotlin/Function2|): R|kotlin/Unit| { + } + public final fun foo3(x: R|kotlin/Function2|): R|kotlin/Unit| { + } + public final fun foo3(x: R|kotlin/Function1|): R|kotlin/Unit| { + } + public final fun main(): R|kotlin/Unit| { + R|/foo1|(Q|JavaClass|::R|/JavaClass.bar|) + R|/foo2|(Q|JavaClass|::R|/JavaClass.bar|) + #(Q|JavaClass|::bar#) + } diff --git a/compiler/fir/resolve/tests/org/jetbrains/kotlin/fir/FirDiagnosticsTestGenerated.java b/compiler/fir/resolve/tests/org/jetbrains/kotlin/fir/FirDiagnosticsTestGenerated.java index 1f9b736fd33..0011a02c334 100644 --- a/compiler/fir/resolve/tests/org/jetbrains/kotlin/fir/FirDiagnosticsTestGenerated.java +++ b/compiler/fir/resolve/tests/org/jetbrains/kotlin/fir/FirDiagnosticsTestGenerated.java @@ -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");