FIR: Support static methods in callable references
^KT-32725 In Progress
This commit is contained in:
@@ -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#)
|
||||
}
|
||||
+10
@@ -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");
|
||||
|
||||
Reference in New Issue
Block a user