K2: Support callable references adaptation on top-level

^KT-45989 In progress
^KT-54709 Related
^KT-55217 Fixed
This commit is contained in:
Denis.Zharkov
2022-11-25 12:28:18 +01:00
committed by Space Team
parent 8f8ea8c57f
commit dcdc48a233
13 changed files with 118 additions and 31 deletions
@@ -3102,6 +3102,22 @@ public class DiagnosisCompilerTestFE10TestdataTestGenerated extends AbstractDiag
runTest("compiler/testData/diagnostics/tests/callableReference/withQuestionMarks.kt"); runTest("compiler/testData/diagnostics/tests/callableReference/withQuestionMarks.kt");
} }
@Nested
@TestMetadata("compiler/testData/diagnostics/tests/callableReference/adapted")
@TestDataPath("$PROJECT_ROOT")
public class Adapted {
@Test
public void testAllFilesPresentInAdapted() throws Exception {
KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/diagnostics/tests/callableReference/adapted"), Pattern.compile("^(.+)\\.kt$"), Pattern.compile("^(.+)\\.fir\\.kts?$"), true);
}
@Test
@TestMetadata("simpleAdaptationOutsideOfCall.kt")
public void testSimpleAdaptationOutsideOfCall() throws Exception {
runTest("compiler/testData/diagnostics/tests/callableReference/adapted/simpleAdaptationOutsideOfCall.kt");
}
}
@Nested @Nested
@TestMetadata("compiler/testData/diagnostics/tests/callableReference/bound") @TestMetadata("compiler/testData/diagnostics/tests/callableReference/bound")
@TestDataPath("$PROJECT_ROOT") @TestDataPath("$PROJECT_ROOT")
@@ -3108,6 +3108,22 @@ public class FirOldFrontendDiagnosticsTestGenerated extends AbstractFirDiagnosti
runTest("compiler/testData/diagnostics/tests/callableReference/withQuestionMarks.kt"); runTest("compiler/testData/diagnostics/tests/callableReference/withQuestionMarks.kt");
} }
@Nested
@TestMetadata("compiler/testData/diagnostics/tests/callableReference/adapted")
@TestDataPath("$PROJECT_ROOT")
public class Adapted {
@Test
public void testAllFilesPresentInAdapted() throws Exception {
KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/diagnostics/tests/callableReference/adapted"), Pattern.compile("^(.*)\\.kts?$"), Pattern.compile("^(.+)\\.fir\\.kts?$"), true);
}
@Test
@TestMetadata("simpleAdaptationOutsideOfCall.kt")
public void testSimpleAdaptationOutsideOfCall() throws Exception {
runTest("compiler/testData/diagnostics/tests/callableReference/adapted/simpleAdaptationOutsideOfCall.kt");
}
}
@Nested @Nested
@TestMetadata("compiler/testData/diagnostics/tests/callableReference/bound") @TestMetadata("compiler/testData/diagnostics/tests/callableReference/bound")
@TestDataPath("$PROJECT_ROOT") @TestDataPath("$PROJECT_ROOT")
@@ -3102,6 +3102,22 @@ public class FirOldFrontendDiagnosticsWithLightTreeTestGenerated extends Abstrac
runTest("compiler/testData/diagnostics/tests/callableReference/withQuestionMarks.kt"); runTest("compiler/testData/diagnostics/tests/callableReference/withQuestionMarks.kt");
} }
@Nested
@TestMetadata("compiler/testData/diagnostics/tests/callableReference/adapted")
@TestDataPath("$PROJECT_ROOT")
public class Adapted {
@Test
public void testAllFilesPresentInAdapted() throws Exception {
KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/diagnostics/tests/callableReference/adapted"), Pattern.compile("^(.+)\\.kt$"), Pattern.compile("^(.+)\\.fir\\.kts?$"), true);
}
@Test
@TestMetadata("simpleAdaptationOutsideOfCall.kt")
public void testSimpleAdaptationOutsideOfCall() throws Exception {
runTest("compiler/testData/diagnostics/tests/callableReference/adapted/simpleAdaptationOutsideOfCall.kt");
}
}
@Nested @Nested
@TestMetadata("compiler/testData/diagnostics/tests/callableReference/bound") @TestMetadata("compiler/testData/diagnostics/tests/callableReference/bound")
@TestDataPath("$PROJECT_ROOT") @TestDataPath("$PROJECT_ROOT")
@@ -34,4 +34,9 @@ object SyntheticCallableId {
syntheticPackageName, syntheticPackageName,
Name.identifier("ID_CALL") Name.identifier("ID_CALL")
) )
val ACCEPT_SPECIFIC_TYPE = CallableId(
syntheticPackageName,
Name.identifier("ACCEPT_SPECIFIC_TYPE_CALL")
)
} }
@@ -154,34 +154,36 @@ class FirSyntheticCallGenerator(
): FirCallableReferenceAccess? { ): FirCallableReferenceAccess? {
val argumentList = buildUnaryArgumentList(callableReferenceAccess) val argumentList = buildUnaryArgumentList(callableReferenceAccess)
val typeArguments = val parameterTypeRef =
when { when {
expectedTypeRef is FirResolvedTypeRef && !expectedTypeRef.coneType.isUnitOrFlexibleUnit -> listOf( expectedTypeRef is FirResolvedTypeRef && !expectedTypeRef.coneType.isUnitOrFlexibleUnit -> expectedTypeRef
buildTypeProjectionWithVariance { else -> context.session.builtinTypes.anyType
variance = Variance.INVARIANT
typeRef = expectedTypeRef
}
)
else -> emptyList()
} }
val callableId = SyntheticCallableId.ACCEPT_SPECIFIC_TYPE
val functionSymbol = FirSyntheticFunctionSymbol(callableId)
// fun accept(p: <parameterTypeRef>): Unit
val function =
generateMemberFunction(functionSymbol, callableId.callableName, returnType = context.session.builtinTypes.unitType).apply {
valueParameters += parameterTypeRef.toValueParameter("reference", functionSymbol, isVararg = false)
}.build()
val reference = val reference =
generateCalleeReferenceWithCandidate( generateCalleeReferenceWithCandidate(
callableReferenceAccess, callableReferenceAccess,
idFunction, function,
argumentList, argumentList,
SyntheticCallableId.ID.callableName, callableId.callableName,
CallKind.SyntheticIdForCallableReferencesResolution, CallKind.SyntheticIdForCallableReferencesResolution,
context, context,
typeArguments,
) )
val fakeCallElement = buildFunctionCall { val fakeCallElement = buildFunctionCall {
calleeReference = reference calleeReference = reference
this.argumentList = argumentList this.argumentList = argumentList
} }
val argument = components.callCompleter.completeCall(fakeCallElement, expectedTypeRef).result.argument val argument = components.callCompleter.completeCall(fakeCallElement, expectedTypeRef = null).result.argument
return ((argument as? FirVarargArgumentsExpression)?.arguments?.get(0) ?: argument) as FirCallableReferenceAccess? return argument as FirCallableReferenceAccess?
} }
private fun generateCalleeReferenceWithCandidate( private fun generateCalleeReferenceWithCandidate(
@@ -191,9 +193,8 @@ class FirSyntheticCallGenerator(
name: Name, name: Name,
callKind: CallKind = CallKind.SyntheticSelect, callKind: CallKind = CallKind.SyntheticSelect,
context: ResolutionContext, context: ResolutionContext,
typeArguments: List<FirTypeProjection> = emptyList()
): FirNamedReferenceWithCandidate { ): FirNamedReferenceWithCandidate {
val callInfo = generateCallInfo(callSite, name, argumentList, callKind, typeArguments) val callInfo = generateCallInfo(callSite, name, argumentList, callKind)
val candidate = generateCandidate(callInfo, function, context) val candidate = generateCandidate(callInfo, function, context)
val applicability = components.resolutionStageRunner.processCandidate(candidate, context) val applicability = components.resolutionStageRunner.processCandidate(candidate, context)
if (applicability <= CandidateApplicability.INAPPLICABLE) { if (applicability <= CandidateApplicability.INAPPLICABLE) {
@@ -224,7 +225,6 @@ class FirSyntheticCallGenerator(
name: Name, name: Name,
argumentList: FirArgumentList, argumentList: FirArgumentList,
callKind: CallKind, callKind: CallKind,
typeArguments: List<FirTypeProjection> = emptyList()
) = CallInfo( ) = CallInfo(
callSite = callSite, callSite = callSite,
callKind = callKind, callKind = callKind,
@@ -232,7 +232,7 @@ class FirSyntheticCallGenerator(
explicitReceiver = null, explicitReceiver = null,
argumentList = argumentList, argumentList = argumentList,
isImplicitInvoke = false, isImplicitInvoke = false,
typeArguments = typeArguments, typeArguments = emptyList(),
session = session, session = session,
containingFile = components.file, containingFile = components.file,
containingDeclarations = components.containingDeclarations containingDeclarations = components.containingDeclarations
@@ -0,0 +1,10 @@
// SKIP_TXT
fun baz(options: String = ""): String = ""
fun runForString(x: () -> String) {}
fun foo(dumpStrategy: String) {
val dump0: () -> String = ::baz
runForString(::baz)
}
@@ -0,0 +1,10 @@
// SKIP_TXT
fun baz(options: String = ""): String = ""
fun runForString(x: () -> String) {}
fun foo(dumpStrategy: String) {
val dump0: () -> String = <!TYPE_MISMATCH!>::<!TYPE_MISMATCH!>baz<!><!>
runForString(::baz)
}
@@ -5,5 +5,5 @@ fun foo(x: Any, y: Int) = y
fun main() { fun main() {
::<!OVERLOAD_RESOLUTION_AMBIGUITY!>foo<!> ::<!OVERLOAD_RESOLUTION_AMBIGUITY!>foo<!>
val fooRef: (Int, Any) -> Unit = ::<!UNRESOLVED_REFERENCE!>foo<!> val fooRef: (Int, Any) -> Unit = ::foo
} }
@@ -6,5 +6,5 @@ fun foo(i: Int) {}
val fn1: (Int) -> Unit = ::foo val fn1: (Int) -> Unit = ::foo
val fn2: (IntArray) -> Unit = ::foo val fn2: (IntArray) -> Unit = ::foo
val fn3: (Int, Int) -> Unit = ::<!UNRESOLVED_REFERENCE!>foo<!> val fn3: (Int, Int) -> Unit = ::foo
val fn4: (Array<String>) -> Unit = ::foo val fn4: (Array<String>) -> Unit = ::foo
@@ -4,8 +4,7 @@
fun main(b: Boolean) { fun main(b: Boolean) {
callWithLambda { callWithLambda {
// The only relevant case for KT-55729, Unit conversion should work, but doesn't in K1 1.8.0 // The only relevant case for KT-55729, Unit conversion should work, but doesn't in K1 1.8.0
// For K2, it still doesn't work (see KT-55936) ::test1
::<!UNRESOLVED_REFERENCE!>test1<!>
} }
callWithLambda { callWithLambda {
@@ -23,8 +22,8 @@ fun main(b: Boolean) {
} }
callWithLambda { callWithLambda {
// That hasn't been working ever in K1 nor K2 // Doesn't work in K1, but does in K2
(::<!UNRESOLVED_REFERENCE!>test1<!>) (::test1)
} }
} }
@@ -4,7 +4,6 @@
fun main(b: Boolean) { fun main(b: Boolean) {
callWithLambda { callWithLambda {
// The only relevant case for KT-55729, Unit conversion should work, but doesn't in K1 1.8.0 // The only relevant case for KT-55729, Unit conversion should work, but doesn't in K1 1.8.0
// For K2, it still doesn't work (see KT-55936)
::test1 ::test1
} }
@@ -23,7 +22,7 @@ fun main(b: Boolean) {
} }
callWithLambda { callWithLambda {
// That hasn't been working ever in K1 nor K2 // Doesn't work in K1, but does in K2
(<!TYPE_MISMATCH, TYPE_MISMATCH!>::<!TYPE_MISMATCH!>test1<!><!>) (<!TYPE_MISMATCH, TYPE_MISMATCH!>::<!TYPE_MISMATCH!>test1<!><!>)
} }
} }
@@ -3108,6 +3108,22 @@ public class DiagnosticTestGenerated extends AbstractDiagnosticTest {
runTest("compiler/testData/diagnostics/tests/callableReference/withQuestionMarks.kt"); runTest("compiler/testData/diagnostics/tests/callableReference/withQuestionMarks.kt");
} }
@Nested
@TestMetadata("compiler/testData/diagnostics/tests/callableReference/adapted")
@TestDataPath("$PROJECT_ROOT")
public class Adapted {
@Test
public void testAllFilesPresentInAdapted() throws Exception {
KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/diagnostics/tests/callableReference/adapted"), Pattern.compile("^(.*)\\.kts?$"), Pattern.compile("^(.+)\\.fir\\.kts?$"), true);
}
@Test
@TestMetadata("simpleAdaptationOutsideOfCall.kt")
public void testSimpleAdaptationOutsideOfCall() throws Exception {
runTest("compiler/testData/diagnostics/tests/callableReference/adapted/simpleAdaptationOutsideOfCall.kt");
}
}
@Nested @Nested
@TestMetadata("compiler/testData/diagnostics/tests/callableReference/bound") @TestMetadata("compiler/testData/diagnostics/tests/callableReference/bound")
@TestDataPath("$PROJECT_ROOT") @TestDataPath("$PROJECT_ROOT")
@@ -16,11 +16,11 @@ class Case1() {
} }
fun case1() { fun case1() {
val y0: (String)-> Case1 = ::<!UNRESOLVED_REFERENCE!>foo<!> val y0: (String)-> Case1 = ::foo
val y1: (String)-> Case1 = Case1.Companion::<!UNRESOLVED_REFERENCE!>foo<!> val y1: (String)-> Case1 = Case1.Companion::foo
val y2: (String)-> Case1 = (Case1)::<!UNRESOLVED_REFERENCE!>foo<!> val y2: (String)-> Case1 = (Case1)::foo
} }
fun case1_0() : (String)-> Case1 = ::<!UNRESOLVED_REFERENCE!>foo<!> fun case1_0() : (String)-> Case1 = ::foo
fun case1_1() : (String)-> Case1 = (Case1)::<!UNRESOLVED_REFERENCE!>foo<!> fun case1_1() : (String)-> Case1 = (Case1)::foo
fun case1_2(): (String)-> Case1 = Case1.Companion::<!UNRESOLVED_REFERENCE!>foo<!> fun case1_2(): (String)-> Case1 = Case1.Companion::foo